DO NOT MERGE Remove window obscurement information. am: 5508ca2c19 am: 3847972ad2 am: cd71708eca am: 88855f8de7
am: 41f75ecb79  -s ours

Change-Id: Id698475c3c67bbacecdb92b6d5de50e62ecd135c
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..03af56d
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,13 @@
+BasedOnStyle: Google
+
+AccessModifierOffset: -4
+AlignOperands: false
+AllowShortFunctionsOnASingleLine: Inline
+AlwaysBreakBeforeMultilineStrings: false
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+ConstructorInitializerIndentWidth: 6
+ContinuationIndentWidth: 8
+IndentWidth: 4
+PenaltyBreakBeforeFirstCallParameter: 100000
+SpacesBeforeTrailingComments: 1
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..cd05b21
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,15 @@
+ndk_headers {
+    name: "libandroid_headers",
+    from: "include/android",
+    to: "android",
+    srcs: ["include/android/**/*.h"],
+    license: "NOTICE",
+}
+
+subdirs = [
+    "cmds/*",
+    "libs/*",
+    "opengl",
+    "services/*",
+    "vulkan",
+]
diff --git a/aidl/gui/android/view/Surface.aidl b/aidl/gui/android/view/Surface.aidl
index 674c163..7e89220 100644
--- a/aidl/gui/android/view/Surface.aidl
+++ b/aidl/gui/android/view/Surface.aidl
@@ -17,4 +17,4 @@
 
 package android.view;
 
-parcelable Surface cpp_header "gui/Surface.h";
+parcelable Surface cpp_header "gui/view/Surface.h";
diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp
new file mode 100644
index 0000000..6c5869a
--- /dev/null
+++ b/cmds/atrace/Android.bp
@@ -0,0 +1,27 @@
+// Copyright 2012 The Android Open Source Project
+
+cc_binary {
+    name: "atrace",
+    srcs: ["atrace.cpp"],
+
+    shared_libs: [
+        "libbinder",
+        "libhwbinder",
+        "android.hidl.manager@1.0",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libcutils",
+        "libutils",
+        "libz",
+        "libbase",
+    ],
+
+    init_rc: ["atrace.rc"],
+
+    product_variables: {
+        debuggable: {
+            init_rc: ["atrace_userdebug.rc"],
+        },
+    },
+}
diff --git a/cmds/atrace/Android.mk b/cmds/atrace/Android.mk
deleted file mode 100644
index a787e95..0000000
--- a/cmds/atrace/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright 2012 The Android Open Source Project
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= atrace.cpp
-
-LOCAL_C_INCLUDES += external/zlib
-
-LOCAL_MODULE:= atrace
-
-LOCAL_MODULE_TAGS:= optional
-
-LOCAL_SHARED_LIBRARIES := \
-    libbinder \
-    libcutils \
-    libutils \
-    libz \
-
-LOCAL_INIT_RC := atrace.rc
-
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 5885738..47e04e7 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
- #define LOG_TAG "atrace"
+#define LOG_TAG "atrace"
 
 #include <errno.h>
 #include <fcntl.h>
@@ -31,19 +31,26 @@
 #include <unistd.h>
 #include <zlib.h>
 
+#include <fstream>
+#include <memory>
+
 #include <binder/IBinder.h>
 #include <binder/IServiceManager.h>
 #include <binder/Parcel.h>
 
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <hidl/ServiceManagement.h>
 #include <cutils/properties.h>
 
 #include <utils/String8.h>
 #include <utils/Timers.h>
 #include <utils/Tokenizer.h>
 #include <utils/Trace.h>
+#include <android-base/file.h>
 
 using namespace android;
 
+using std::string;
 #define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
 
 #define MAX_SYS_FILES 10
@@ -103,72 +110,85 @@
     { "ss",         "System Server",    ATRACE_TAG_SYSTEM_SERVER, { } },
     { "database",   "Database",         ATRACE_TAG_DATABASE, { } },
     { "network",    "Network",          ATRACE_TAG_NETWORK, { } },
+    { "adb",        "ADB",              ATRACE_TAG_ADB, { } },
     { k_coreServiceCategory, "Core services", 0, { } },
     { "sched",      "CPU Scheduling",   0, {
-        { REQ,      "/sys/kernel/debug/tracing/events/sched/sched_switch/enable" },
-        { REQ,      "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable" },
-        { OPT,      "/sys/kernel/debug/tracing/events/sched/sched_blocked_reason/enable" },
-        { OPT,      "/sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable" },
+        { REQ,      "events/sched/sched_switch/enable" },
+        { REQ,      "events/sched/sched_wakeup/enable" },
+        { OPT,      "events/sched/sched_waking/enable" },
+        { OPT,      "events/sched/sched_blocked_reason/enable" },
+        { OPT,      "events/sched/sched_cpu_hotplug/enable" },
     } },
     { "irq",        "IRQ Events",   0, {
-        { REQ,      "/sys/kernel/debug/tracing/events/irq/enable" },
-        { OPT,      "/sys/kernel/debug/tracing/events/ipi/enable" },
+        { REQ,      "events/irq/enable" },
+        { OPT,      "events/ipi/enable" },
+    } },
+    { "i2c",        "I2C Events",   0, {
+        { REQ,      "events/i2c/enable" },
+        { REQ,      "events/i2c/i2c_read/enable" },
+        { REQ,      "events/i2c/i2c_write/enable" },
+        { REQ,      "events/i2c/i2c_result/enable" },
+        { REQ,      "events/i2c/i2c_reply/enable" },
+        { OPT,      "events/i2c/smbus_read/enable" },
+        { OPT,      "events/i2c/smbus_write/enable" },
+        { OPT,      "events/i2c/smbus_result/enable" },
+        { OPT,      "events/i2c/smbus_reply/enable" },
     } },
     { "freq",       "CPU Frequency",    0, {
-        { REQ,      "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable" },
-        { OPT,      "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable" },
-        { OPT,      "/sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable" },
+        { REQ,      "events/power/cpu_frequency/enable" },
+        { OPT,      "events/power/clock_set_rate/enable" },
+        { OPT,      "events/power/cpu_frequency_limits/enable" },
     } },
     { "membus",     "Memory Bus Utilization", 0, {
-        { REQ,      "/sys/kernel/debug/tracing/events/memory_bus/enable" },
+        { REQ,      "events/memory_bus/enable" },
     } },
     { "idle",       "CPU Idle",         0, {
-        { REQ,      "/sys/kernel/debug/tracing/events/power/cpu_idle/enable" },
+        { REQ,      "events/power/cpu_idle/enable" },
     } },
     { "disk",       "Disk I/O",         0, {
-        { OPT,      "/sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable" },
-        { OPT,      "/sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit/enable" },
-        { OPT,      "/sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin/enable" },
-        { OPT,      "/sys/kernel/debug/tracing/events/f2fs/f2fs_write_end/enable" },
-        { OPT,      "/sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable" },
-        { OPT,      "/sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable" },
-        { OPT,      "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable" },
-        { OPT,      "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable" },
-        { REQ,      "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable" },
-        { REQ,      "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable" },
+        { OPT,      "events/f2fs/f2fs_sync_file_enter/enable" },
+        { OPT,      "events/f2fs/f2fs_sync_file_exit/enable" },
+        { OPT,      "events/f2fs/f2fs_write_begin/enable" },
+        { OPT,      "events/f2fs/f2fs_write_end/enable" },
+        { OPT,      "events/ext4/ext4_da_write_begin/enable" },
+        { OPT,      "events/ext4/ext4_da_write_end/enable" },
+        { OPT,      "events/ext4/ext4_sync_file_enter/enable" },
+        { OPT,      "events/ext4/ext4_sync_file_exit/enable" },
+        { REQ,      "events/block/block_rq_issue/enable" },
+        { REQ,      "events/block/block_rq_complete/enable" },
     } },
     { "mmc",        "eMMC commands",    0, {
-        { REQ,      "/sys/kernel/debug/tracing/events/mmc/enable" },
+        { REQ,      "events/mmc/enable" },
     } },
     { "load",       "CPU Load",         0, {
-        { REQ,      "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable" },
+        { REQ,      "events/cpufreq_interactive/enable" },
     } },
     { "sync",       "Synchronization",  0, {
-        { REQ,      "/sys/kernel/debug/tracing/events/sync/enable" },
+        { REQ,      "events/sync/enable" },
     } },
     { "workq",      "Kernel Workqueues", 0, {
-        { REQ,      "/sys/kernel/debug/tracing/events/workqueue/enable" },
+        { REQ,      "events/workqueue/enable" },
     } },
     { "memreclaim", "Kernel Memory Reclaim", 0, {
-        { REQ,      "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable" },
-        { REQ,      "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable" },
-        { REQ,      "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable" },
-        { REQ,      "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable" },
+        { REQ,      "events/vmscan/mm_vmscan_direct_reclaim_begin/enable" },
+        { REQ,      "events/vmscan/mm_vmscan_direct_reclaim_end/enable" },
+        { REQ,      "events/vmscan/mm_vmscan_kswapd_wake/enable" },
+        { REQ,      "events/vmscan/mm_vmscan_kswapd_sleep/enable" },
     } },
     { "regulators",  "Voltage and Current Regulators", 0, {
-        { REQ,      "/sys/kernel/debug/tracing/events/regulator/enable" },
+        { REQ,      "events/regulator/enable" },
     } },
     { "binder_driver", "Binder Kernel driver", 0, {
-        { REQ,      "/sys/kernel/debug/tracing/events/binder/binder_transaction/enable" },
-        { REQ,      "/sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable" },
+        { REQ,      "events/binder/binder_transaction/enable" },
+        { REQ,      "events/binder/binder_transaction_received/enable" },
     } },
     { "binder_lock", "Binder global lock trace", 0, {
-        { REQ,      "/sys/kernel/debug/tracing/events/binder/binder_lock/enable" },
-        { REQ,      "/sys/kernel/debug/tracing/events/binder/binder_locked/enable" },
-        { REQ,      "/sys/kernel/debug/tracing/events/binder/binder_unlock/enable" },
+        { REQ,      "events/binder/binder_lock/enable" },
+        { REQ,      "events/binder/binder_locked/enable" },
+        { REQ,      "events/binder/binder_unlock/enable" },
     } },
     { "pagecache",  "Page cache", 0, {
-        { REQ,      "/sys/kernel/debug/tracing/events/filemap/enable" },
+        { REQ,      "events/filemap/enable" },
     } },
 };
 
@@ -187,61 +207,65 @@
 /* Global state */
 static bool g_traceAborted = false;
 static bool g_categoryEnables[NELEM(k_categories)] = {};
+static std::string g_traceFolder;
 
 /* Sys file paths */
 static const char* k_traceClockPath =
-    "/sys/kernel/debug/tracing/trace_clock";
+    "trace_clock";
 
 static const char* k_traceBufferSizePath =
-    "/sys/kernel/debug/tracing/buffer_size_kb";
+    "buffer_size_kb";
+
+static const char* k_traceCmdlineSizePath =
+    "saved_cmdlines_size";
 
 static const char* k_tracingOverwriteEnablePath =
-    "/sys/kernel/debug/tracing/options/overwrite";
+    "options/overwrite";
 
 static const char* k_currentTracerPath =
-    "/sys/kernel/debug/tracing/current_tracer";
+    "current_tracer";
 
 static const char* k_printTgidPath =
-    "/sys/kernel/debug/tracing/options/print-tgid";
+    "options/print-tgid";
 
 static const char* k_funcgraphAbsTimePath =
-    "/sys/kernel/debug/tracing/options/funcgraph-abstime";
+    "options/funcgraph-abstime";
 
 static const char* k_funcgraphCpuPath =
-    "/sys/kernel/debug/tracing/options/funcgraph-cpu";
+    "options/funcgraph-cpu";
 
 static const char* k_funcgraphProcPath =
-    "/sys/kernel/debug/tracing/options/funcgraph-proc";
+    "options/funcgraph-proc";
 
 static const char* k_funcgraphFlatPath =
-    "/sys/kernel/debug/tracing/options/funcgraph-flat";
+    "options/funcgraph-flat";
 
 static const char* k_funcgraphDurationPath =
-    "/sys/kernel/debug/tracing/options/funcgraph-duration";
+    "options/funcgraph-duration";
 
 static const char* k_ftraceFilterPath =
-    "/sys/kernel/debug/tracing/set_ftrace_filter";
+    "set_ftrace_filter";
 
 static const char* k_tracingOnPath =
-    "/sys/kernel/debug/tracing/tracing_on";
+    "tracing_on";
 
 static const char* k_tracePath =
-    "/sys/kernel/debug/tracing/trace";
+    "trace";
 
 static const char* k_traceStreamPath =
-    "/sys/kernel/debug/tracing/trace_pipe";
+    "trace_pipe";
 
 static const char* k_traceMarkerPath =
-    "/sys/kernel/debug/tracing/trace_marker";
+    "trace_marker";
 
 // Check whether a file exists.
 static bool fileExists(const char* filename) {
-    return access(filename, F_OK) != -1;
+    return access((g_traceFolder + filename).c_str(), F_OK) != -1;
 }
 
 // Check whether a file is writable.
 static bool fileIsWritable(const char* filename) {
-    return access(filename, W_OK) != -1;
+    return access((g_traceFolder + filename).c_str(), W_OK) != -1;
 }
 
 // Truncate a file.
@@ -250,9 +274,9 @@
     // This uses creat rather than truncate because some of the debug kernel
     // device nodes (e.g. k_ftraceFilterPath) currently aren't changed by
     // calls to truncate, but they are cleared by calls to creat.
-    int traceFD = creat(path, 0);
+    int traceFD = creat((g_traceFolder + path).c_str(), 0);
     if (traceFD == -1) {
-        fprintf(stderr, "error truncating %s: %s (%d)\n", path,
+        fprintf(stderr, "error truncating %s: %s (%d)\n", (g_traceFolder + path).c_str(),
             strerror(errno), errno);
         return false;
     }
@@ -264,9 +288,10 @@
 
 static bool _writeStr(const char* filename, const char* str, int flags)
 {
-    int fd = open(filename, flags);
+    std::string fullFilename = g_traceFolder + filename;
+    int fd = open(fullFilename.c_str(), flags);
     if (fd == -1) {
-        fprintf(stderr, "error opening %s: %s (%d)\n", filename,
+        fprintf(stderr, "error opening %s: %s (%d)\n", fullFilename.c_str(),
                 strerror(errno), errno);
         return false;
     }
@@ -274,7 +299,7 @@
     bool ok = true;
     ssize_t len = strlen(str);
     if (write(fd, str, len) != len) {
-        fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
+        fprintf(stderr, "error writing to %s: %s (%d)\n", fullFilename.c_str(),
                 strerror(errno), errno);
         ok = false;
     }
@@ -300,7 +325,7 @@
 {
   char buffer[128];
   int len = 0;
-  int fd = open(k_traceMarkerPath, O_WRONLY);
+  int fd = open((g_traceFolder + k_traceMarkerPath).c_str(), O_WRONLY);
   if (fd == -1) {
       fprintf(stderr, "error opening %s: %s (%d)\n", k_traceMarkerPath,
               strerror(errno), errno);
@@ -363,7 +388,7 @@
 // Check whether the category would be supported on the device if the user
 // were root.  This function assumes that root is able to write to any file
 // that exists.  It performs the same logic as isCategorySupported, but it
-// uses file existance rather than writability in the /sys/ file checks.
+// uses file existence rather than writability in the /sys/ file checks.
 static bool isCategorySupportedForRoot(const TracingCategory& category)
 {
     bool ok = category.tags != 0;
@@ -416,56 +441,40 @@
     return writeStr(k_traceBufferSizePath, str);
 }
 
-// Read the trace_clock sysfs file and return true if it matches the requested
-// value.  The trace_clock file format is:
-// local [global] counter uptime perf
-static bool isTraceClock(const char *mode)
+// Set the default size of cmdline hashtable
+static bool setCmdlineSize()
 {
-    int fd = open(k_traceClockPath, O_RDONLY);
-    if (fd == -1) {
-        fprintf(stderr, "error opening %s: %s (%d)\n", k_traceClockPath,
-            strerror(errno), errno);
-        return false;
+    if (fileExists(k_traceCmdlineSizePath)) {
+        return writeStr(k_traceCmdlineSizePath, "8192");
     }
-
-    char buf[4097];
-    ssize_t n = read(fd, buf, 4096);
-    close(fd);
-    if (n == -1) {
-        fprintf(stderr, "error reading %s: %s (%d)\n", k_traceClockPath,
-            strerror(errno), errno);
-        return false;
-    }
-    buf[n] = '\0';
-
-    char *start = strchr(buf, '[');
-    if (start == NULL) {
-        return false;
-    }
-    start++;
-
-    char *end = strchr(start, ']');
-    if (end == NULL) {
-        return false;
-    }
-    *end = '\0';
-
-    return strcmp(mode, start) == 0;
+    return true;
 }
 
-// Enable or disable the kernel's use of the global clock.  Disabling the global
-// clock will result in the kernel using a per-CPU local clock.
+// Set the clock to the best available option while tracing. Use 'boot' if it's
+// available; otherwise, use 'mono'. If neither are available use 'global'.
 // Any write to the trace_clock sysfs file will reset the buffer, so only
 // update it if the requested value is not the current value.
-static bool setGlobalClockEnable(bool enable)
+static bool setClock()
 {
-    const char *clock = enable ? "global" : "local";
+    std::ifstream clockFile((g_traceFolder + k_traceClockPath).c_str(), O_RDONLY);
+    std::string clockStr((std::istreambuf_iterator<char>(clockFile)),
+        std::istreambuf_iterator<char>());
 
-    if (isTraceClock(clock)) {
-        return true;
+    std::string newClock;
+    if (clockStr.find("boot") != std::string::npos) {
+        newClock = "boot";
+    } else if (clockStr.find("mono") != std::string::npos) {
+        newClock = "mono";
+    } else {
+        newClock = "global";
     }
 
-    return writeStr(k_traceClockPath, clock);
+    size_t begin = clockStr.find("[") + 1;
+    size_t end = clockStr.find("]");
+    if (newClock.compare(0, std::string::npos, clockStr, begin, end-begin) == 0) {
+        return true;
+    }
+    return writeStr(k_traceClockPath, newClock.c_str());
 }
 
 static bool setPrintTgidEnableIfPresent(bool enable)
@@ -503,6 +512,54 @@
     return true;
 }
 
+// Poke all the HAL processes in the system to get them to re-read
+// their system properties.
+static void pokeHalServices()
+{
+    using ::android::hidl::base::V1_0::IBase;
+    using ::android::hidl::manager::V1_0::IServiceManager;
+    using ::android::hardware::hidl_string;
+    using ::android::hardware::Return;
+
+    sp<IServiceManager> sm = ::android::hardware::defaultServiceManager();
+
+    if (sm == nullptr) {
+        fprintf(stderr, "failed to get IServiceManager to poke hal services\n");
+        return;
+    }
+
+    auto listRet = sm->list([&](const auto &interfaces) {
+        for (size_t i = 0; i < interfaces.size(); i++) {
+            string fqInstanceName = interfaces[i];
+            string::size_type n = fqInstanceName.find("/");
+            if (n == std::string::npos || interfaces[i].size() == n+1)
+                continue;
+            hidl_string fqInterfaceName = fqInstanceName.substr(0, n);
+            hidl_string instanceName = fqInstanceName.substr(n+1, std::string::npos);
+            Return<sp<IBase>> interfaceRet = sm->get(fqInterfaceName, instanceName);
+            if (!interfaceRet.isOk()) {
+                // ignore
+                continue;
+            }
+
+            sp<IBase> interface = interfaceRet;
+            if (interface == nullptr) {
+                // ignore
+                continue;
+            }
+
+            auto notifyRet = interface->notifySyspropsChanged();
+            if (!notifyRet.isOk()) {
+                // ignore
+            }
+        }
+    });
+    if (!listRet.isOk()) {
+        // TODO(b/34242478) fix this when we determine the correct ACL
+        //fprintf(stderr, "failed to list services: %s\n", listRet.description().c_str());
+    }
+}
+
 // Set the trace tags that userland tracing uses, and poke the running
 // processes to pick up the new value.
 static bool setTagsProperty(uint64_t tags)
@@ -533,11 +590,11 @@
 
 // Set the system property that indicates which apps should perform
 // application-level tracing.
-static bool setAppCmdlineProperty(const char* cmdline)
+static bool setAppCmdlineProperty(char* cmdline)
 {
     char buf[PROPERTY_KEY_MAX];
     int i = 0;
-    const char* start = cmdline;
+    char* start = cmdline;
     while (start != NULL) {
         if (i == MAX_PACKAGES) {
             fprintf(stderr, "error: only 16 packages could be traced at once\n");
@@ -587,24 +644,14 @@
 // kernel.
 static bool verifyKernelTraceFuncs(const char* funcs)
 {
-    int fd = open(k_ftraceFilterPath, O_RDONLY);
-    if (fd == -1) {
-        fprintf(stderr, "error opening %s: %s (%d)\n", k_ftraceFilterPath,
+    std::string buf;
+    if (!android::base::ReadFileToString(g_traceFolder + k_ftraceFilterPath, &buf)) {
+         fprintf(stderr, "error opening %s: %s (%d)\n", k_ftraceFilterPath,
             strerror(errno), errno);
-        return false;
+         return false;
     }
 
-    char buf[4097];
-    ssize_t n = read(fd, buf, 4096);
-    close(fd);
-    if (n == -1) {
-        fprintf(stderr, "error reading %s: %s (%d)\n", k_ftraceFilterPath,
-            strerror(errno), errno);
-        return false;
-    }
-
-    buf[n] = '\0';
-    String8 funcList = String8::format("\n%s", buf);
+    String8 funcList = String8::format("\n%s",buf.c_str());
 
     // Make sure that every function listed in funcs is in the list we just
     // read from the kernel, except for wildcard inputs.
@@ -624,7 +671,6 @@
         func = strtok(NULL, ",");
     }
     free(myFuncs);
-
     return ok;
 }
 
@@ -724,7 +770,9 @@
     ok &= setCategoriesEnableFromFile(g_categoriesFile);
     ok &= setTraceOverwriteEnable(g_traceOverwrite);
     ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
-    ok &= setGlobalClockEnable(true);
+    // TODO: Re-enable after stabilization
+    //ok &= setCmdlineSize();
+    ok &= setClock();
     ok &= setPrintTgidEnableIfPresent(true);
     ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
 
@@ -754,8 +802,9 @@
         }
         packageList += value;
     }
-    ok &= setAppCmdlineProperty(packageList.data());
+    ok &= setAppCmdlineProperty(&packageList[0]);
     ok &= pokeBinderServices();
+    pokeHalServices();
 
     // Disable all the sysfs enables.  This is done as a separate loop from
     // the enables to allow the same enable to exist in multiple categories.
@@ -797,7 +846,6 @@
     // Set the options back to their defaults.
     setTraceOverwriteEnable(true);
     setTraceBufferSizeKB(1);
-    setGlobalClockEnable(false);
     setPrintTgidEnableIfPresent(false);
     setKernelTraceFuncs(NULL);
 }
@@ -819,7 +867,7 @@
 static void streamTrace()
 {
     char trace_data[4096];
-    int traceFD = open(k_traceStreamPath, O_RDWR);
+    int traceFD = open((g_traceFolder + k_traceStreamPath).c_str(), O_RDWR);
     if (traceFD == -1) {
         fprintf(stderr, "error opening %s: %s (%d)\n", k_traceStreamPath,
                 strerror(errno), errno);
@@ -844,7 +892,7 @@
 static void dumpTrace(int outFd)
 {
     ALOGI("Dumping trace");
-    int traceFD = open(k_tracePath, O_RDWR);
+    int traceFD = open((g_traceFolder + k_tracePath).c_str(), O_RDWR);
     if (traceFD == -1) {
         fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
                 strerror(errno), errno);
@@ -853,30 +901,34 @@
 
     if (g_compress) {
         z_stream zs;
-        uint8_t *in, *out;
-        int result, flush;
-
         memset(&zs, 0, sizeof(zs));
-        result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
+
+        int result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
         if (result != Z_OK) {
             fprintf(stderr, "error initializing zlib: %d\n", result);
             close(traceFD);
             return;
         }
 
-        const size_t bufSize = 64*1024;
-        in = (uint8_t*)malloc(bufSize);
-        out = (uint8_t*)malloc(bufSize);
-        flush = Z_NO_FLUSH;
+        constexpr size_t bufSize = 64*1024;
+        std::unique_ptr<uint8_t> in(new uint8_t[bufSize]);
+        std::unique_ptr<uint8_t> out(new uint8_t[bufSize]);
+        if (!in || !out) {
+            fprintf(stderr, "couldn't allocate buffers\n");
+            close(traceFD);
+            return;
+        }
 
-        zs.next_out = out;
+        int flush = Z_NO_FLUSH;
+
+        zs.next_out = reinterpret_cast<Bytef*>(out.get());
         zs.avail_out = bufSize;
 
         do {
 
             if (zs.avail_in == 0) {
                 // More input is needed.
-                result = read(traceFD, in, bufSize);
+                result = read(traceFD, in.get(), bufSize);
                 if (result < 0) {
                     fprintf(stderr, "error reading trace: %s (%d)\n",
                             strerror(errno), errno);
@@ -885,14 +937,14 @@
                 } else if (result == 0) {
                     flush = Z_FINISH;
                 } else {
-                    zs.next_in = in;
+                    zs.next_in = reinterpret_cast<Bytef*>(in.get());
                     zs.avail_in = result;
                 }
             }
 
             if (zs.avail_out == 0) {
                 // Need to write the output.
-                result = write(outFd, out, bufSize);
+                result = write(outFd, out.get(), bufSize);
                 if ((size_t)result < bufSize) {
                     fprintf(stderr, "error writing deflated trace: %s (%d)\n",
                             strerror(errno), errno);
@@ -900,7 +952,7 @@
                     zs.avail_out = bufSize; // skip the final write
                     break;
                 }
-                zs.next_out = out;
+                zs.next_out = reinterpret_cast<Bytef*>(out.get());
                 zs.avail_out = bufSize;
             }
 
@@ -912,7 +964,7 @@
 
         if (zs.avail_out < bufSize) {
             size_t bytes = bufSize - zs.avail_out;
-            result = write(outFd, out, bytes);
+            result = write(outFd, out.get(), bytes);
             if ((size_t)result < bytes) {
                 fprintf(stderr, "error writing deflated trace: %s (%d)\n",
                         strerror(errno), errno);
@@ -923,9 +975,6 @@
         if (result != Z_OK) {
             fprintf(stderr, "error cleaning up zlib: %d\n", result);
         }
-
-        free(in);
-        free(out);
     } else {
         ssize_t sent = 0;
         while ((sent = sendfile(outFd, traceFD, NULL, 64*1024*1024)) > 0);
@@ -981,9 +1030,9 @@
                     "  -k fname,...    trace the listed kernel functions\n"
                     "  -n              ignore signals\n"
                     "  -s N            sleep for N seconds before tracing [default 0]\n"
-                    "  -t N            trace for N seconds [defualt 5]\n"
+                    "  -t N            trace for N seconds [default 5]\n"
                     "  -z              compress the trace dump\n"
-                    "  --async_start   start circular trace and return immediatly\n"
+                    "  --async_start   start circular trace and return immediately\n"
                     "  --async_dump    dump the current contents of circular trace buffer\n"
                     "  --async_stop    stop tracing and dump the current contents of circular\n"
                     "                    trace buffer\n"
@@ -998,6 +1047,29 @@
             );
 }
 
+bool findTraceFiles()
+{
+    static const std::string debugfs_path = "/sys/kernel/debug/tracing/";
+    static const std::string tracefs_path = "/sys/kernel/tracing/";
+    static const std::string trace_file = "trace_marker";
+
+    bool tracefs = access((tracefs_path + trace_file).c_str(), F_OK) != -1;
+    bool debugfs = access((debugfs_path + trace_file).c_str(), F_OK) != -1;
+
+    if (!tracefs && !debugfs) {
+        fprintf(stderr, "Error: Did not find trace folder\n");
+        return false;
+    }
+
+    if (tracefs) {
+        g_traceFolder = tracefs_path;
+    } else {
+        g_traceFolder = debugfs_path;
+    }
+
+    return true;
+}
+
 int main(int argc, char **argv)
 {
     bool async = false;
@@ -1011,6 +1083,11 @@
         exit(0);
     }
 
+    if (!findTraceFiles()) {
+        fprintf(stderr, "No trace folder found\n");
+        exit(-1);
+    }
+
     for (;;) {
         int ret;
         int option_index = 0;
@@ -1158,7 +1235,7 @@
             fflush(stdout);
             int outFd = STDOUT_FILENO;
             if (g_outputFile) {
-                outFd = open(g_outputFile, O_WRONLY | O_CREAT);
+                outFd = open(g_outputFile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
             }
             if (outFd == -1) {
                 printf("Failed to open '%s', err=%d", g_outputFile, errno);
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 747cc69..d538145 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -4,63 +4,135 @@
 
 # Allow writing to the kernel trace log.
     chmod 0222 /sys/kernel/debug/tracing/trace_marker
+    chmod 0222 /sys/kernel/tracing/trace_marker
 
 # Allow the shell group to enable (some) kernel tracing.
     chown root shell /sys/kernel/debug/tracing/trace_clock
+    chown root shell /sys/kernel/tracing/trace_clock
     chown root shell /sys/kernel/debug/tracing/buffer_size_kb
+    chown root shell /sys/kernel/tracing/buffer_size_kb
     chown root shell /sys/kernel/debug/tracing/options/overwrite
+    chown root shell /sys/kernel/tracing/options/overwrite
     chown root shell /sys/kernel/debug/tracing/options/print-tgid
+    chown root shell /sys/kernel/tracing/options/print-tgid
+    chown root shell /sys/kernel/debug/tracing/saved_cmdlines_size
+    chown root shell /sys/kernel/tracing/saved_cmdlines_size
     chown root shell /sys/kernel/debug/tracing/events/sched/sched_switch/enable
+    chown root shell /sys/kernel/tracing/events/sched/sched_switch/enable
     chown root shell /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
+    chown root shell /sys/kernel/tracing/events/sched/sched_wakeup/enable
     chown root shell /sys/kernel/debug/tracing/events/sched/sched_blocked_reason/enable
+    chown root shell /sys/kernel/tracing/events/sched/sched_blocked_reason/enable
     chown root shell /sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable
+    chown root shell /sys/kernel/tracing/events/sched/sched_cpu_hotplug/enable
     chown root shell /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
+    chown root shell /sys/kernel/tracing/events/power/cpu_frequency/enable
     chown root shell /sys/kernel/debug/tracing/events/power/cpu_idle/enable
+    chown root shell /sys/kernel/tracing/events/power/cpu_idle/enable
     chown root shell /sys/kernel/debug/tracing/events/power/clock_set_rate/enable
+    chown root shell /sys/kernel/tracing/events/power/clock_set_rate/enable
     chown root shell /sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable
+    chown root shell /sys/kernel/tracing/events/power/cpu_frequency_limits/enable
     chown root shell /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
+    chown root shell /sys/kernel/tracing/events/cpufreq_interactive/enable
     chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
+    chown root shell /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
     chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
+    chown root shell /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
     chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
+    chown root shell /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
     chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
+    chown root shell /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
     chown root shell /sys/kernel/debug/tracing/events/binder/binder_transaction/enable
+    chown root shell /sys/kernel/tracing/events/binder/binder_transaction/enable
     chown root shell /sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable
+    chown root shell /sys/kernel/tracing/events/binder/binder_transaction_received/enable
     chown root shell /sys/kernel/debug/tracing/events/binder/binder_lock/enable
+    chown root shell /sys/kernel/tracing/events/binder/binder_lock/enable
     chown root shell /sys/kernel/debug/tracing/events/binder/binder_locked/enable
+    chown root shell /sys/kernel/tracing/events/binder/binder_locked/enable
     chown root shell /sys/kernel/debug/tracing/events/binder/binder_unlock/enable
+    chown root shell /sys/kernel/tracing/events/binder/binder_unlock/enable
 
     chown root shell /sys/kernel/debug/tracing/tracing_on
+    chown root shell /sys/kernel/tracing/tracing_on
 
     chmod 0664 /sys/kernel/debug/tracing/trace_clock
+    chmod 0664 /sys/kernel/tracing/trace_clock
     chmod 0664 /sys/kernel/debug/tracing/buffer_size_kb
+    chmod 0664 /sys/kernel/tracing/buffer_size_kb
     chmod 0664 /sys/kernel/debug/tracing/options/overwrite
+    chmod 0664 /sys/kernel/tracing/options/overwrite
     chmod 0664 /sys/kernel/debug/tracing/options/print-tgid
+    chmod 0664 /sys/kernel/tracing/options/print-tgid
+    chmod 0664 /sys/kernel/debug/tracing/saved_cmdlines_size
+    chmod 0664 /sys/kernel/tracing/saved_cmdlines_size
     chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_switch/enable
+    chmod 0664 /sys/kernel/tracing/events/sched/sched_switch/enable
     chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
+    chmod 0664 /sys/kernel/tracing/events/sched/sched_wakeup/enable
     chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_blocked_reason/enable
+    chmod 0664 /sys/kernel/tracing/events/sched/sched_blocked_reason/enable
     chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable
+    chmod 0664 /sys/kernel/tracing/events/sched/sched_cpu_hotplug/enable
     chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
+    chmod 0664 /sys/kernel/tracing/events/power/cpu_frequency/enable
     chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_idle/enable
+    chmod 0664 /sys/kernel/tracing/events/power/cpu_idle/enable
     chmod 0664 /sys/kernel/debug/tracing/events/power/clock_set_rate/enable
+    chmod 0664 /sys/kernel/tracing/events/power/clock_set_rate/enable
     chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable
+    chmod 0664 /sys/kernel/tracing/events/power/cpu_frequency_limits/enable
     chmod 0664 /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
+    chmod 0664 /sys/kernel/tracing/events/cpufreq_interactive/enable
     chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
+    chmod 0664 /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
     chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
+    chmod 0664 /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
     chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
+    chmod 0664 /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
     chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
+    chmod 0664 /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
     chmod 0664 /sys/kernel/debug/tracing/tracing_on
+    chmod 0664 /sys/kernel/tracing/tracing_on
     chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_transaction/enable
+    chmod 0664 /sys/kernel/tracing/events/binder/binder_transaction/enable
     chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable
+    chmod 0664 /sys/kernel/tracing/events/binder/binder_transaction_received/enable
     chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_lock/enable
+    chmod 0664 /sys/kernel/tracing/events/binder/binder_lock/enable
     chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_locked/enable
+    chmod 0664 /sys/kernel/tracing/events/binder/binder_locked/enable
     chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_unlock/enable
+    chmod 0664 /sys/kernel/tracing/events/binder/binder_unlock/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/i2c/enable
+    chmod 0664 /sys/kernel/tracing/events/i2c/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/i2c/i2c_read/enable
+    chmod 0664 /sys/kernel/tracing/events/i2c/i2c_read/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/i2c/i2c_write/enable
+    chmod 0664 /sys/kernel/tracing/events/i2c/i2c_write/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/i2c/i2c_result/enable
+    chmod 0664 /sys/kernel/tracing/events/i2c/i2c_result/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/i2c/i2c_reply/enable
+    chmod 0664 /sys/kernel/tracing/events/i2c/i2c_reply/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/i2c/smbus_read/enable
+    chmod 0664 /sys/kernel/tracing/events/i2c/smbus_read/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/i2c/smbus_write/enable
+    chmod 0664 /sys/kernel/tracing/events/i2c/smbus_write/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/i2c/smbus_result/enable
+    chmod 0664 /sys/kernel/tracing/events/i2c/smbus_result/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/i2c/smbus_reply/enable
+    chmod 0664 /sys/kernel/tracing/events/i2c/smbus_reply/enable
 
     # Tracing disabled by default
     write /sys/kernel/debug/tracing/tracing_on 0
+    write /sys/kernel/tracing/tracing_on 0
 
 # Allow only the shell group to read and truncate the kernel trace.
     chown root shell /sys/kernel/debug/tracing/trace
+    chown root shell /sys/kernel/tracing/trace
     chmod 0660 /sys/kernel/debug/tracing/trace
+    chmod 0660 /sys/kernel/tracing/trace
 
 on property:persist.debug.atrace.boottrace=1
     start boottrace
diff --git a/cmds/atrace/atrace_userdebug.rc b/cmds/atrace/atrace_userdebug.rc
new file mode 100644
index 0000000..5fd28e2
--- /dev/null
+++ b/cmds/atrace/atrace_userdebug.rc
@@ -0,0 +1,47 @@
+## Permissions to allow additional system-wide tracing to the kernel trace buffer.
+## The default list of permissions is set in frameworks/native/cmds/atrace/atrace.rc
+
+# Allow the shell group to enable kernel tracepoints:
+
+on post-fs
+    chown root shell /sys/kernel/debug/tracing/events/sync/enable
+    chown root shell /sys/kernel/debug/tracing/events/workqueue/enable
+    chown root shell /sys/kernel/debug/tracing/events/regulator/enable
+    chown root shell /sys/kernel/debug/tracing/events/pagecache/enable
+
+    # irq
+    chown root shell /sys/kernel/debug/tracing/events/irq/enable
+    chown root shell /sys/kernel/debug/tracing/events/ipi/enable
+
+    # disk
+    chown root shell /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable
+    chown root shell /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit/enable
+    chown root shell /sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin/enable
+    chown root shell /sys/kernel/debug/tracing/events/f2fs/f2fs_write_end/enable
+    chown root shell /sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable
+    chown root shell /sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable
+    chown root shell /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable
+    chown root shell /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable
+    chown root shell /sys/kernel/debug/tracing/events/block/block_rq_issue/enable
+    chown root shell /sys/kernel/debug/tracing/events/block/block_rq_complete/enable
+
+    chmod 0664 /sys/kernel/debug/tracing/events/sync/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/workqueue/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/regulator/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/pagecache/enable
+
+    # irq
+    chmod 0664 /sys/kernel/debug/tracing/events/irq/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/ipi/enable
+
+    # disk
+    chmod 0664 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_end/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/block/block_rq_issue/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/block/block_rq_complete/enable
diff --git a/cmds/bugreport/Android.bp b/cmds/bugreport/Android.bp
new file mode 100644
index 0000000..139e4b2
--- /dev/null
+++ b/cmds/bugreport/Android.bp
@@ -0,0 +1,6 @@
+cc_binary {
+    name: "bugreport",
+    srcs: ["bugreport.cpp"],
+    cflags: ["-Wall"],
+    shared_libs: ["libcutils"],
+}
diff --git a/cmds/bugreport/Android.mk b/cmds/bugreport/Android.mk
deleted file mode 100644
index ced5d30..0000000
--- a/cmds/bugreport/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= bugreport.cpp
-
-LOCAL_MODULE:= bugreport
-
-LOCAL_CFLAGS := -Wall
-
-LOCAL_SHARED_LIBRARIES := libcutils
-
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/bugreportz/readme.md b/cmds/bugreportz/readme.md
index 2697f09..eb0d898 100644
--- a/cmds/bugreportz/readme.md
+++ b/cmds/bugreportz/readme.md
@@ -17,3 +17,4 @@
 
 - `OK:<path_to_bugreport_file>` in case of success.
 - `FAIL:<error message>` in case of failure.
+
diff --git a/cmds/cmd/Android.mk b/cmds/cmd/Android.mk
index ac2f4c0..d565e57 100644
--- a/cmds/cmd/Android.mk
+++ b/cmds/cmd/Android.mk
@@ -7,8 +7,11 @@
 LOCAL_SHARED_LIBRARIES := \
 	libutils \
 	liblog \
+    libselinux \
 	libbinder
-	
+
+LOCAL_C_INCLUDES += \
+    $(JNI_H_INCLUDE)
 
 ifeq ($(TARGET_OS),linux)
 	LOCAL_CFLAGS += -DXP_UNIX
diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp
index ed740d3..7e05d72 100644
--- a/cmds/cmd/cmd.cpp
+++ b/cmds/cmd/cmd.cpp
@@ -21,7 +21,10 @@
 #include <binder/ProcessState.h>
 #include <binder/IResultReceiver.h>
 #include <binder/IServiceManager.h>
+#include <binder/IShellCallback.h>
 #include <binder/TextOutput.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
 #include <utils/Vector.h>
 
 #include <getopt.h>
@@ -29,7 +32,16 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <fcntl.h>
 #include <sys/time.h>
+#include <errno.h>
+
+#include "selinux/selinux.h"
+#include "selinux/android.h"
+
+#include <UniquePtr.h>
+
+#define DEBUG 0
 
 using namespace android;
 
@@ -38,10 +50,72 @@
     return lhs->compare(*rhs);
 }
 
+struct SecurityContext_Delete {
+    void operator()(security_context_t p) const {
+        freecon(p);
+    }
+};
+typedef UniquePtr<char[], SecurityContext_Delete> Unique_SecurityContext;
+
+class MyShellCallback : public BnShellCallback
+{
+public:
+    bool mActive = true;
+
+    virtual int openOutputFile(const String16& path, const String16& seLinuxContext) {
+        String8 path8(path);
+        char cwd[256];
+        getcwd(cwd, 256);
+        String8 fullPath(cwd);
+        fullPath.appendPath(path8);
+        if (!mActive) {
+            aerr << "Open attempt after active for: " << fullPath << endl;
+            return -EPERM;
+        }
+        int fd = open(fullPath.string(), O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU|S_IRWXG);
+        if (fd < 0) {
+            return fd;
+        }
+        if (is_selinux_enabled() && seLinuxContext.size() > 0) {
+            String8 seLinuxContext8(seLinuxContext);
+            security_context_t tmp = NULL;
+            int ret = getfilecon(fullPath.string(), &tmp);
+            Unique_SecurityContext context(tmp);
+            int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(),
+                    "file", "write", NULL);
+            if (accessGranted != 0) {
+                close(fd);
+                aerr << "System server has no access to file context " << context.get()
+                        << " (from path " << fullPath.string() << ", context "
+                        << seLinuxContext8.string() << ")" << endl;
+                return -EPERM;
+            }
+        }
+        return fd;
+    }
+};
+
 class MyResultReceiver : public BnResultReceiver
 {
 public:
-    virtual void send(int32_t /*resultCode*/) {
+    Mutex mMutex;
+    Condition mCondition;
+    bool mHaveResult = false;
+    int32_t mResult = 0;
+
+    virtual void send(int32_t resultCode) {
+        AutoMutex _l(mMutex);
+        mResult = resultCode;
+        mHaveResult = true;
+        mCondition.signal();
+    }
+
+    int32_t waitForResult() {
+        AutoMutex _l(mMutex);
+        while (!mHaveResult) {
+            mCondition.wait(mMutex);
+        }
+        return mResult;
     }
 };
 
@@ -49,18 +123,25 @@
 {
     signal(SIGPIPE, SIG_IGN);
     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();
 
     sp<IServiceManager> sm = defaultServiceManager();
     fflush(stdout);
     if (sm == NULL) {
-        ALOGE("Unable to get default service manager!");
+        ALOGW("Unable to get default service manager!");
         aerr << "cmd: Unable to get default service manager!" << endl;
         return 20;
     }
 
     if (argc == 1) {
-        aout << "cmd: no service specified; use -l to list all services" << endl;
+        aerr << "cmd: No service specified; use -l to list all services" << endl;
         return 20;
     }
 
@@ -85,12 +166,41 @@
     String16 cmd = String16(argv[1]);
     sp<IBinder> service = sm->checkService(cmd);
     if (service == NULL) {
-        aerr << "Can't find service: " << argv[1] << endl;
+        ALOGW("Can't find service %s", argv[1]);
+        aerr << "cmd: Can't find service: " << argv[1] << endl;
         return 20;
     }
 
+    sp<MyShellCallback> cb = new MyShellCallback();
+    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);
+#endif
+
     // TODO: block until a result is returned to MyResultReceiver.
-    IBinder::shellCommand(service, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, args,
-            new MyResultReceiver());
-    return 0;
+    status_t err = IBinder::shellCommand(service, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, args,
+            cb, result);
+    if (err < 0) {
+        const char* errstr;
+        switch (err) {
+            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;
+        }
+        ALOGW("Failure calling service %s: %s (%d)", argv[1], errstr, -err);
+        aout << "cmd: Failure calling service " << argv[1] << ": " << errstr << " ("
+                << (-err) << ")" << endl;
+        return err;
+    }
+
+    cb->mActive = false;
+    status_t res = result->waitForResult();
+#if DEBUG
+    ALOGD("result=%d", (int)res);
+#endif
+    return res;
 }
diff --git a/cmds/dumpstate/.clang-format b/cmds/dumpstate/.clang-format
new file mode 100644
index 0000000..fc4eb1b
--- /dev/null
+++ b/cmds/dumpstate/.clang-format
@@ -0,0 +1,13 @@
+BasedOnStyle: Google
+AllowShortBlocksOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+
+AccessModifierOffset: -2
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
+UseTab: Never
+PenaltyExcessCharacter: 32
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
index 791a7c4..a407ea2 100644
--- a/cmds/dumpstate/Android.mk
+++ b/cmds/dumpstate/Android.mk
@@ -1,24 +1,178 @@
 LOCAL_PATH:= $(call my-dir)
+
+# ================#
+# Common settings #
+# ================#
+# ZipArchive support, the order matters here to get all symbols.
+COMMON_ZIP_LIBRARIES := libziparchive libz libcrypto
+
+# TODO: ideally the tests should depend on a shared dumpstate library, but currently libdumpstate
+# is used to define the device-specific HAL library. Instead, both dumpstate and dumpstate_test
+# shares a lot of common settings
+COMMON_LOCAL_CFLAGS := \
+       -Wall -Werror -Wno-missing-field-initializers -Wno-unused-variable -Wunused-parameter
+COMMON_SRC_FILES := \
+        DumpstateInternal.cpp \
+        utils.cpp
+COMMON_SHARED_LIBRARIES := \
+        android.hardware.dumpstate@1.0 \
+        android.hidl.manager@1.0 \
+        libhidlbase \
+        libbase \
+        libbinder \
+        libcutils \
+        libdebuggerd_client \
+        libdumpstateaidl \
+        libdumpstateutil \
+        liblog \
+        libselinux \
+        libutils \
+        $(COMMON_ZIP_LIBRARIES)
+
+# ====================#
+# libdumpstateutil #
+# ====================#
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES := libdumpstate_default.cpp
-LOCAL_MODULE := libdumpstate.default
+
+LOCAL_MODULE := libdumpstateutil
+
+LOCAL_CFLAGS := $(COMMON_LOCAL_CFLAGS)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+LOCAL_SRC_FILES := \
+        DumpstateInternal.cpp \
+        DumpstateUtil.cpp
+LOCAL_SHARED_LIBRARIES := \
+        libbase \
+        liblog \
+
+include $(BUILD_SHARED_LIBRARY)
+
+# ====================#
+# libdumpstateheaders #
+# ====================#
+# TODO: this module is necessary so the device-specific libdumpstate implementations do not
+# need to add any other dependency (like libbase). Should go away once dumpstate HAL changes.
+include $(CLEAR_VARS)
+
+LOCAL_EXPORT_C_INCLUDE_DIRS = $(LOCAL_PATH)
+LOCAL_MODULE := libdumpstateheaders
+LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \
+        $(COMMON_SHARED_LIBRARIES)
+LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := \
+        $(COMMON_STATIC_LIBRARIES)
+# Soong requires that whats is on LOCAL_EXPORTED_ is also on LOCAL_
+LOCAL_SHARED_LIBRARIES := $(LOCAL_EXPORT_SHARED_LIBRARY_HEADERS)
+LOCAL_STATIC_LIBRARIES := $(LOCAL_EXPORT_STATIC_LIBRARY_HEADERS)
+
 include $(BUILD_STATIC_LIBRARY)
 
+# ================ #
+# libdumpstateaidl #
+# =================#
 include $(CLEAR_VARS)
 
-ifdef BOARD_WLAN_DEVICE
-LOCAL_CFLAGS := -DFWDUMP_$(BOARD_WLAN_DEVICE)
-endif
+LOCAL_MODULE := libdumpstateaidl
 
-LOCAL_SRC_FILES := dumpstate.cpp utils.cpp
+LOCAL_CFLAGS := $(COMMON_LOCAL_CFLAGS)
+
+LOCAL_SHARED_LIBRARIES := \
+        libbinder \
+        libutils
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/binder
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/binder
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/binder
+LOCAL_SRC_FILES := \
+        binder/android/os/IDumpstate.aidl \
+        binder/android/os/IDumpstateListener.aidl \
+        binder/android/os/IDumpstateToken.aidl
+
+include $(BUILD_SHARED_LIBRARY)
+
+# ==========#
+# dumpstate #
+# ==========#
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(COMMON_SRC_FILES) \
+        DumpstateService.cpp \
+        dumpstate.cpp
 
 LOCAL_MODULE := dumpstate
 
-LOCAL_SHARED_LIBRARIES := libcutils liblog libselinux libbase
-# ZipArchive support, the order matters here to get all symbols.
-LOCAL_STATIC_LIBRARIES := libziparchive libz libmincrypt
-LOCAL_HAL_STATIC_LIBRARIES := libdumpstate
-LOCAL_CFLAGS += -Wall -Werror -Wno-unused-parameter
+LOCAL_SHARED_LIBRARIES := $(COMMON_SHARED_LIBRARIES)
+
+LOCAL_STATIC_LIBRARIES := $(COMMON_STATIC_LIBRARIES)
+
+LOCAL_CFLAGS += $(COMMON_LOCAL_CFLAGS)
+
 LOCAL_INIT_RC := dumpstate.rc
 
 include $(BUILD_EXECUTABLE)
+
+# ===============#
+# dumpstate_test #
+# ===============#
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := dumpstate_test
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_CFLAGS := $(COMMON_LOCAL_CFLAGS)
+
+LOCAL_SRC_FILES := $(COMMON_SRC_FILES) \
+        DumpstateService.cpp \
+        tests/dumpstate_test.cpp
+
+LOCAL_STATIC_LIBRARIES := $(COMMON_STATIC_LIBRARIES) \
+        libgmock
+
+LOCAL_SHARED_LIBRARIES := $(COMMON_SHARED_LIBRARIES)
+
+include $(BUILD_NATIVE_TEST)
+
+# =======================#
+# dumpstate_test_fixture #
+# =======================#
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := dumpstate_test_fixture
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_CFLAGS := $(COMMON_LOCAL_CFLAGS)
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
+LOCAL_SRC_FILES := \
+        tests/dumpstate_test_fixture.cpp
+
+LOCAL_MODULE_CLASS := NATIVE_TESTS
+
+dumpstate_tests_intermediates := $(local-intermediates-dir)/DATA
+dumpstate_tests_subpath_from_data := nativetest/dumpstate_test_fixture
+dumpstate_tests_root_in_device := /data/$(dumpstate_tests_subpath_from_data)
+dumpstate_tests_root_for_test_zip := $(dumpstate_tests_intermediates)/$(dumpstate_tests_subpath_from_data)
+testdata_files := $(call find-subdir-files, testdata/*)
+
+# Copy test data files to intermediates/DATA for use with LOCAL_PICKUP_FILES
+GEN := $(addprefix $(dumpstate_tests_root_for_test_zip)/, $(testdata_files))
+$(GEN): PRIVATE_PATH := $(LOCAL_PATH)
+$(GEN): PRIVATE_CUSTOM_TOOL = cp $< $@
+$(GEN): $(dumpstate_tests_root_for_test_zip)/testdata/% : $(LOCAL_PATH)/testdata/%
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+# Copy test data files again to $OUT/data so the tests can be run with adb sync
+# TODO: the build system should do this automatically
+GEN := $(addprefix $(TARGET_OUT_DATA)/$(dumpstate_tests_subpath_from_data)/, $(testdata_files))
+$(GEN): PRIVATE_PATH := $(LOCAL_PATH)
+$(GEN): PRIVATE_CUSTOM_TOOL = cp $< $@
+$(GEN): $(TARGET_OUT_DATA)/$(dumpstate_tests_subpath_from_data)/testdata/% : $(LOCAL_PATH)/testdata/%
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+LOCAL_PICKUP_FILES := $(dumpstate_tests_intermediates)
+
+include $(BUILD_NATIVE_TEST)
diff --git a/cmds/dumpstate/DumpstateInternal.cpp b/cmds/dumpstate/DumpstateInternal.cpp
new file mode 100644
index 0000000..0343277
--- /dev/null
+++ b/cmds/dumpstate/DumpstateInternal.cpp
@@ -0,0 +1,160 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "dumpstate"
+
+#include "DumpstateInternal.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <cutils/log.h>
+#include <private/android_filesystem_config.h>
+
+uint64_t Nanotime() {
+    timespec ts;
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+    return static_cast<uint64_t>(ts.tv_sec * NANOS_PER_SEC + ts.tv_nsec);
+}
+
+// Switches to non-root user and group.
+bool DropRootUser() {
+    if (getgid() == AID_SHELL && getuid() == AID_SHELL) {
+        MYLOGD("drop_root_user(): already running as Shell\n");
+        return true;
+    }
+    /* ensure we will keep capabilities when we drop root */
+    if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
+        MYLOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno));
+        return false;
+    }
+
+    gid_t groups[] = {AID_LOG,  AID_SDCARD_R,     AID_SDCARD_RW, AID_MOUNT,
+                      AID_INET, AID_NET_BW_STATS, AID_READPROC,  AID_BLUETOOTH};
+    if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) != 0) {
+        MYLOGE("Unable to setgroups, aborting: %s\n", strerror(errno));
+        return false;
+    }
+    if (setgid(AID_SHELL) != 0) {
+        MYLOGE("Unable to setgid, aborting: %s\n", strerror(errno));
+        return false;
+    }
+    if (setuid(AID_SHELL) != 0) {
+        MYLOGE("Unable to setuid, aborting: %s\n", strerror(errno));
+        return false;
+    }
+
+    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;
+    capheader.pid = 0;
+
+    capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG);
+    capdata[CAP_TO_INDEX(CAP_SYSLOG)].effective = CAP_TO_MASK(CAP_SYSLOG);
+    capdata[0].inheritable = 0;
+    capdata[1].inheritable = 0;
+
+    if (capset(&capheader, &capdata[0]) < 0) {
+        MYLOGE("capset failed: %s\n", strerror(errno));
+        return false;
+    }
+
+    return true;
+}
+
+int DumpFileFromFdToFd(const std::string& title, const std::string& path_string, int fd, int out_fd,
+                       bool dry_run) {
+    const char* path = path_string.c_str();
+    if (!title.empty()) {
+        dprintf(out_fd, "------ %s (%s", title.c_str(), path);
+
+        struct stat st;
+        // Only show the modification time of non-device files.
+        size_t path_len = strlen(path);
+        if ((path_len < 6 || memcmp(path, "/proc/", 6)) &&
+            (path_len < 5 || memcmp(path, "/sys/", 5)) &&
+            (path_len < 3 || memcmp(path, "/d/", 3)) && !fstat(fd, &st)) {
+            char stamp[80];
+            time_t mtime = st.st_mtime;
+            strftime(stamp, sizeof(stamp), "%Y-%m-%d %H:%M:%S", localtime(&mtime));
+            dprintf(out_fd, ": %s", stamp);
+        }
+        dprintf(out_fd, ") ------\n");
+        fsync(out_fd);
+    }
+    if (dry_run) {
+        if (out_fd != STDOUT_FILENO) {
+            // There is no title, but we should still print a dry-run message
+            dprintf(out_fd, "%s: skipped on dry run\n", path);
+        } else if (!title.empty()) {
+            dprintf(out_fd, "\t(skipped on dry run)\n");
+        }
+        fsync(out_fd);
+        return 0;
+    }
+    bool newline = false;
+    fd_set read_set;
+    timeval tm;
+    while (true) {
+        FD_ZERO(&read_set);
+        FD_SET(fd, &read_set);
+        /* Timeout if no data is read for 30 seconds. */
+        tm.tv_sec = 30;
+        tm.tv_usec = 0;
+        uint64_t elapsed = Nanotime();
+        int ret = TEMP_FAILURE_RETRY(select(fd + 1, &read_set, nullptr, nullptr, &tm));
+        if (ret == -1) {
+            dprintf(out_fd, "*** %s: select failed: %s\n", path, strerror(errno));
+            newline = true;
+            break;
+        } else if (ret == 0) {
+            elapsed = Nanotime() - elapsed;
+            dprintf(out_fd, "*** %s: Timed out after %.3fs\n", path, (float)elapsed / NANOS_PER_SEC);
+            newline = true;
+            break;
+        } else {
+            char buffer[65536];
+            ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
+            if (bytes_read > 0) {
+                android::base::WriteFully(out_fd, buffer, bytes_read);
+                newline = (buffer[bytes_read - 1] == '\n');
+            } else {
+                if (bytes_read == -1) {
+                    dprintf(out_fd, "*** %s: Failed to read from fd: %s", path, strerror(errno));
+                    newline = true;
+                }
+                break;
+            }
+        }
+    }
+    close(fd);
+
+    if (!newline) dprintf(out_fd, "\n");
+    if (!title.empty()) dprintf(out_fd, "\n");
+    return 0;
+}
diff --git a/cmds/dumpstate/DumpstateInternal.h b/cmds/dumpstate/DumpstateInternal.h
new file mode 100644
index 0000000..2f7704d
--- /dev/null
+++ b/cmds/dumpstate/DumpstateInternal.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+#ifndef FRAMEWORK_NATIVE_CMD_DUMPSTATE_INTERNAL_H_
+#define FRAMEWORK_NATIVE_CMD_DUMPSTATE_INTERNAL_H_
+
+#include <cstdint>
+#include <string>
+
+// TODO: rename macros to DUMPSTATE_LOGXXX
+#ifndef MYLOGD
+#define MYLOGD(...)               \
+    fprintf(stderr, __VA_ARGS__); \
+    ALOGD(__VA_ARGS__);
+#endif
+
+#ifndef MYLOGI
+#define MYLOGI(...)               \
+    fprintf(stderr, __VA_ARGS__); \
+    ALOGI(__VA_ARGS__);
+#endif
+
+#ifndef MYLOGE
+#define MYLOGE(...)               \
+    fprintf(stderr, __VA_ARGS__); \
+    ALOGE(__VA_ARGS__);
+#endif
+
+// Internal functions used by .cpp files on multiple build targets.
+// TODO: move to android::os::dumpstate::internal namespace
+
+// TODO: use functions from <chrono> instead
+const uint64_t NANOS_PER_SEC = 1000000000;
+uint64_t Nanotime();
+
+// Switches to non-root user and group.
+bool DropRootUser();
+
+// TODO: move to .cpp as static once is not used by utils.cpp anymore.
+int DumpFileFromFdToFd(const std::string& title, const std::string& path_string, int fd, int out_fd,
+                       bool dry_run = false);
+
+#endif  // FRAMEWORK_NATIVE_CMD_DUMPSTATE_INTERNAL_H_
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
new file mode 100644
index 0000000..efe0466
--- /dev/null
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -0,0 +1,106 @@
+/**
+ * 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.
+ */
+
+#define LOG_TAG "dumpstate"
+
+#include "DumpstateService.h"
+
+#include <android-base/stringprintf.h>
+
+#include "android/os/BnDumpstate.h"
+
+#include "DumpstateInternal.h"
+
+namespace android {
+namespace os {
+
+namespace {
+class DumpstateToken : public BnDumpstateToken {};
+}
+
+DumpstateService::DumpstateService() : ds_(Dumpstate::GetInstance()) {
+}
+
+char const* DumpstateService::getServiceName() {
+    return "dumpstate";
+}
+
+status_t DumpstateService::Start() {
+    IPCThreadState::self()->disableBackgroundScheduling(true);
+    status_t ret = BinderService<DumpstateService>::publish();
+    if (ret != android::OK) {
+        return ret;
+    }
+    sp<ProcessState> ps(ProcessState::self());
+    ps->startThreadPool();
+    ps->giveThreadPoolName();
+    return android::OK;
+}
+
+binder::Status DumpstateService::setListener(const std::string& name,
+                                             const sp<IDumpstateListener>& listener,
+                                             sp<IDumpstateToken>* returned_token) {
+    *returned_token = nullptr;
+    if (name.empty()) {
+        MYLOGE("setListener(): name not set\n");
+        return binder::Status::ok();
+    }
+    if (listener == nullptr) {
+        MYLOGE("setListener(): listener not set\n");
+        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());
+        return binder::Status::ok();
+    }
+
+    ds_.listener_name_ = name;
+    ds_.listener_ = listener;
+    *returned_token = new DumpstateToken();
+
+    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_);
+    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());
+
+    return NO_ERROR;
+}
+}  // namespace os
+}  // namespace android
diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h
new file mode 100644
index 0000000..4352d3d
--- /dev/null
+++ b/cmds/dumpstate/DumpstateService.h
@@ -0,0 +1,51 @@
+/**
+ * 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.
+ */
+
+#ifndef ANDROID_OS_DUMPSTATE_H_
+#define ANDROID_OS_DUMPSTATE_H_
+
+#include <mutex>
+#include <vector>
+
+#include <binder/BinderService.h>
+
+#include "android/os/BnDumpstate.h"
+#include "android/os/BnDumpstateToken.h"
+#include "dumpstate.h"
+
+namespace android {
+namespace os {
+
+class DumpstateService : public BinderService<DumpstateService>, public BnDumpstate {
+  public:
+    DumpstateService();
+
+    static status_t Start();
+    static char const* getServiceName();
+
+    status_t dump(int fd, const Vector<String16>& args) override;
+    binder::Status setListener(const std::string& name, const sp<IDumpstateListener>& listener,
+                               sp<IDumpstateToken>* returned_token) override;
+
+  private:
+    Dumpstate& ds_;
+    std::mutex lock_;
+};
+
+}  // namespace os
+}  // namespace android
+
+#endif  // ANDROID_OS_DUMPSTATE_H_
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp
new file mode 100644
index 0000000..26702c4
--- /dev/null
+++ b/cmds/dumpstate/DumpstateUtil.cpp
@@ -0,0 +1,384 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "dumpstate"
+
+#include "DumpstateUtil.h"
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <cutils/log.h>
+
+#include "DumpstateInternal.h"
+
+namespace android {
+namespace os {
+namespace dumpstate {
+
+namespace {
+
+static constexpr const char* kSuPath = "/system/xbin/su";
+
+static bool waitpid_with_timeout(pid_t pid, int timeout_seconds, int* status) {
+    sigset_t child_mask, old_mask;
+    sigemptyset(&child_mask);
+    sigaddset(&child_mask, SIGCHLD);
+
+    if (sigprocmask(SIG_BLOCK, &child_mask, &old_mask) == -1) {
+        printf("*** sigprocmask failed: %s\n", strerror(errno));
+        return false;
+    }
+
+    timespec ts;
+    ts.tv_sec = timeout_seconds;
+    ts.tv_nsec = 0;
+    int ret = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, NULL, &ts));
+    int saved_errno = errno;
+    // Set the signals back the way they were.
+    if (sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1) {
+        printf("*** sigprocmask failed: %s\n", strerror(errno));
+        if (ret == 0) {
+            return false;
+        }
+    }
+    if (ret == -1) {
+        errno = saved_errno;
+        if (errno == EAGAIN) {
+            errno = ETIMEDOUT;
+        } else {
+            printf("*** sigtimedwait failed: %s\n", strerror(errno));
+        }
+        return false;
+    }
+
+    pid_t child_pid = waitpid(pid, status, WNOHANG);
+    if (child_pid != pid) {
+        if (child_pid != -1) {
+            printf("*** Waiting for pid %d, got pid %d instead\n", pid, child_pid);
+        } else {
+            printf("*** waitpid failed: %s\n", strerror(errno));
+        }
+        return false;
+    }
+    return true;
+}
+}  // unnamed namespace
+
+CommandOptions CommandOptions::DEFAULT = CommandOptions::WithTimeout(10).Build();
+CommandOptions CommandOptions::AS_ROOT = CommandOptions::WithTimeout(10).AsRoot().Build();
+
+CommandOptions::CommandOptionsBuilder::CommandOptionsBuilder(int64_t timeout) : values(timeout) {
+}
+
+CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::Always() {
+    values.always_ = true;
+    return *this;
+}
+
+CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::AsRoot() {
+    values.account_mode_ = SU_ROOT;
+    return *this;
+}
+
+CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::DropRoot() {
+    values.account_mode_ = DROP_ROOT;
+    return *this;
+}
+
+CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::RedirectStderr() {
+    values.output_mode_ = REDIRECT_TO_STDERR;
+    return *this;
+}
+
+CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::Log(
+    const std::string& message) {
+    values.logging_message_ = message;
+    return *this;
+}
+
+CommandOptions CommandOptions::CommandOptionsBuilder::Build() {
+    return CommandOptions(values);
+}
+
+CommandOptions::CommandOptionsValues::CommandOptionsValues(int64_t timeout)
+    : timeout_(timeout),
+      always_(false),
+      account_mode_(DONT_DROP_ROOT),
+      output_mode_(NORMAL_OUTPUT),
+      logging_message_("") {
+}
+
+CommandOptions::CommandOptions(const CommandOptionsValues& values) : values(values) {
+}
+
+int64_t CommandOptions::Timeout() const {
+    return values.timeout_;
+}
+
+bool CommandOptions::Always() const {
+    return values.always_;
+}
+
+PrivilegeMode CommandOptions::PrivilegeMode() const {
+    return values.account_mode_;
+}
+
+OutputMode CommandOptions::OutputMode() const {
+    return values.output_mode_;
+}
+
+std::string CommandOptions::LoggingMessage() const {
+    return values.logging_message_;
+}
+
+CommandOptions::CommandOptionsBuilder CommandOptions::WithTimeout(int64_t timeout) {
+    return CommandOptions::CommandOptionsBuilder(timeout);
+}
+
+std::string PropertiesHelper::build_type_ = "";
+int PropertiesHelper::dry_run_ = -1;
+
+bool PropertiesHelper::IsUserBuild() {
+    if (build_type_.empty()) {
+        build_type_ = android::base::GetProperty("ro.build.type", "user");
+    }
+    return "user" == build_type_;
+}
+
+bool PropertiesHelper::IsDryRun() {
+    if (dry_run_ == -1) {
+        dry_run_ = android::base::GetBoolProperty("dumpstate.dry_run", false) ? 1 : 0;
+    }
+    return dry_run_ == 1;
+}
+
+int DumpFileToFd(int out_fd, const std::string& title, const std::string& path) {
+    int fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC));
+    if (fd < 0) {
+        int err = errno;
+        if (title.empty()) {
+            dprintf(out_fd, "*** Error dumping %s: %s\n", path.c_str(), strerror(err));
+        } else {
+            dprintf(out_fd, "*** Error dumping %s (%s): %s\n", path.c_str(), title.c_str(),
+                    strerror(err));
+        }
+        fsync(out_fd);
+        return -1;
+    }
+    return DumpFileFromFdToFd(title, path, fd, out_fd, PropertiesHelper::IsDryRun());
+}
+
+int RunCommandToFd(int fd, const std::string& title, const std::vector<std::string>& full_command,
+                   const CommandOptions& options) {
+    if (full_command.empty()) {
+        MYLOGE("No arguments on RunCommandToFd(%s)\n", title.c_str());
+        return -1;
+    }
+
+    int size = full_command.size() + 1;  // null terminated
+    int starting_index = 0;
+    if (options.PrivilegeMode() == SU_ROOT) {
+        starting_index = 2;  // "su" "root"
+        size += starting_index;
+    }
+
+    std::vector<const char*> args;
+    args.resize(size);
+
+    std::string command_string;
+    if (options.PrivilegeMode() == SU_ROOT) {
+        args[0] = kSuPath;
+        command_string += kSuPath;
+        args[1] = "root";
+        command_string += " root ";
+    }
+    for (size_t i = 0; i < full_command.size(); i++) {
+        args[i + starting_index] = full_command[i].data();
+        command_string += args[i + starting_index];
+        if (i != full_command.size() - 1) {
+            command_string += " ";
+        }
+    }
+    args[size - 1] = nullptr;
+
+    const char* command = command_string.c_str();
+
+    if (options.PrivilegeMode() == SU_ROOT && PropertiesHelper::IsUserBuild()) {
+        dprintf(fd, "Skipping '%s' on user build.\n", command);
+        return 0;
+    }
+
+    if (!title.empty()) {
+        dprintf(fd, "------ %s (%s) ------\n", title.c_str(), command);
+        fsync(fd);
+    }
+
+    const std::string& logging_message = options.LoggingMessage();
+    if (!logging_message.empty()) {
+        MYLOGI(logging_message.c_str(), command_string.c_str());
+    }
+
+    bool silent = (options.OutputMode() == REDIRECT_TO_STDERR);
+    bool redirecting_to_fd = STDOUT_FILENO != fd;
+
+    if (PropertiesHelper::IsDryRun() && !options.Always()) {
+        if (!title.empty()) {
+            dprintf(fd, "\t(skipped on dry run)\n");
+        } else if (redirecting_to_fd) {
+            // There is no title, but we should still print a dry-run message
+            dprintf(fd, "%s: skipped on dry run\n", command_string.c_str());
+        }
+        fsync(fd);
+        return 0;
+    }
+
+    const char* path = args[0];
+
+    uint64_t start = Nanotime();
+    pid_t pid = fork();
+
+    /* handle error case */
+    if (pid < 0) {
+        if (!silent) dprintf(fd, "*** fork: %s\n", strerror(errno));
+        MYLOGE("*** fork: %s\n", strerror(errno));
+        return pid;
+    }
+
+    /* handle child case */
+    if (pid == 0) {
+        if (options.PrivilegeMode() == DROP_ROOT && !DropRootUser()) {
+            if (!silent) {
+                dprintf(fd, "*** failed to drop root before running %s: %s\n", command,
+                        strerror(errno));
+            }
+            MYLOGE("*** could not drop root before running %s: %s\n", command, strerror(errno));
+            return -1;
+        }
+
+        if (silent) {
+            // Redirects stdout to stderr
+            TEMP_FAILURE_RETRY(dup2(STDERR_FILENO, STDOUT_FILENO));
+        } else if (redirecting_to_fd) {
+            // Redirect stdout to fd
+            TEMP_FAILURE_RETRY(dup2(fd, STDOUT_FILENO));
+            close(fd);
+        }
+
+        /* make sure the child dies when dumpstate dies */
+        prctl(PR_SET_PDEATHSIG, SIGKILL);
+
+        /* just ignore SIGPIPE, will go down with parent's */
+        struct sigaction sigact;
+        memset(&sigact, 0, sizeof(sigact));
+        sigact.sa_handler = SIG_IGN;
+        sigaction(SIGPIPE, &sigact, NULL);
+
+        execvp(path, (char**)args.data());
+        // execvp's result will be handled after waitpid_with_timeout() below, but
+        // if it failed, it's safer to exit dumpstate.
+        MYLOGD("execvp on command '%s' failed (error: %s)\n", command, strerror(errno));
+        // Must call _exit (instead of exit), otherwise it will corrupt the zip
+        // file.
+        _exit(EXIT_FAILURE);
+    }
+
+    /* handle parent case */
+    int status;
+    bool ret = waitpid_with_timeout(pid, options.Timeout(), &status);
+    fsync(fd);
+
+    uint64_t elapsed = Nanotime() - start;
+    if (!ret) {
+        if (errno == ETIMEDOUT) {
+            if (!silent)
+                dprintf(fd, "*** command '%s' timed out after %.3fs (killing pid %d)\n", command,
+                        static_cast<float>(elapsed) / NANOS_PER_SEC, pid);
+            MYLOGE("*** command '%s' timed out after %.3fs (killing pid %d)\n", command,
+                   static_cast<float>(elapsed) / NANOS_PER_SEC, pid);
+        } else {
+            if (!silent)
+                dprintf(fd, "*** command '%s': Error after %.4fs (killing pid %d)\n", command,
+                        static_cast<float>(elapsed) / NANOS_PER_SEC, pid);
+            MYLOGE("command '%s': Error after %.4fs (killing pid %d)\n", command,
+                   static_cast<float>(elapsed) / NANOS_PER_SEC, pid);
+        }
+        kill(pid, SIGTERM);
+        if (!waitpid_with_timeout(pid, 5, nullptr)) {
+            kill(pid, SIGKILL);
+            if (!waitpid_with_timeout(pid, 5, nullptr)) {
+                if (!silent)
+                    dprintf(fd, "could not kill command '%s' (pid %d) even with SIGKILL.\n",
+                            command, pid);
+                MYLOGE("could not kill command '%s' (pid %d) even with SIGKILL.\n", command, pid);
+            }
+        }
+        return -1;
+    }
+
+    if (WIFSIGNALED(status)) {
+        if (!silent)
+            dprintf(fd, "*** command '%s' failed: killed by signal %d\n", command, WTERMSIG(status));
+        MYLOGE("*** command '%s' failed: killed by signal %d\n", command, WTERMSIG(status));
+    } else if (WIFEXITED(status) && WEXITSTATUS(status) > 0) {
+        status = WEXITSTATUS(status);
+        if (!silent) dprintf(fd, "*** command '%s' failed: exit code %d\n", command, status);
+        MYLOGE("*** command '%s' failed: exit code %d\n", command, status);
+    }
+
+    return status;
+}
+
+int GetPidByName(const std::string& ps_name) {
+    DIR* proc_dir;
+    struct dirent* ps;
+    unsigned int pid;
+    std::string cmdline;
+
+    if (!(proc_dir = opendir("/proc"))) {
+        MYLOGE("Can't open /proc\n");
+        return -1;
+    }
+
+    while ((ps = readdir(proc_dir))) {
+        if (!(pid = atoi(ps->d_name))) {
+            continue;
+        }
+        android::base::ReadFileToString("/proc/" + std::string(ps->d_name) + "/cmdline", &cmdline);
+        if (cmdline.find(ps_name) == std::string::npos) {
+            continue;
+        } else {
+            closedir(proc_dir);
+            return pid;
+        }
+    }
+    MYLOGE("can't find the pid\n");
+    closedir(proc_dir);
+    return -1;
+}
+
+}  // namespace dumpstate
+}  // namespace os
+}  // namespace android
diff --git a/cmds/dumpstate/DumpstateUtil.h b/cmds/dumpstate/DumpstateUtil.h
new file mode 100644
index 0000000..5a8ce5b
--- /dev/null
+++ b/cmds/dumpstate/DumpstateUtil.h
@@ -0,0 +1,186 @@
+/*
+ * 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.
+ */
+#ifndef ANDROID_OS_DUMPSTATE_UTIL_H_
+#define ANDROID_OS_DUMPSTATE_UTIL_H_
+
+#include <cstdint>
+#include <string>
+
+namespace android {
+namespace os {
+namespace dumpstate {
+
+/*
+ * Defines the Linux account that should be executing a command.
+ */
+enum PrivilegeMode {
+    /* Explicitly change the `uid` and `gid` to be `shell`.*/
+    DROP_ROOT,
+    /* Don't change the `uid` and `gid`. */
+    DONT_DROP_ROOT,
+    /* Prefix the command with `/PATH/TO/su root`. Won't work non user builds. */
+    SU_ROOT
+};
+
+/*
+ * Defines what should happen with the main output stream (`stdout` or fd) of a command.
+ */
+enum OutputMode {
+    /* Don't change main output. */
+    NORMAL_OUTPUT,
+    /* Redirect main output to `stderr`. */
+    REDIRECT_TO_STDERR
+};
+
+/*
+ * Value object used to set command options.
+ *
+ * Typically constructed using a builder with chained setters. Examples:
+ *
+ *  CommandOptions::WithTimeout(20).AsRoot().Build();
+ *  CommandOptions::WithTimeout(10).Always().RedirectStderr().Build();
+ *
+ * Although the builder could be used to dynamically set values. Example:
+ *
+ *  CommandOptions::CommandOptionsBuilder options =
+ *  CommandOptions::WithTimeout(10);
+ *  if (!is_user_build()) {
+ *    options.AsRoot();
+ *  }
+ *  RunCommand("command", {"args"}, options.Build());
+ */
+class CommandOptions {
+  private:
+    class CommandOptionsValues {
+      private:
+        CommandOptionsValues(int64_t timeout);
+
+        int64_t timeout_;
+        bool always_;
+        PrivilegeMode account_mode_;
+        OutputMode output_mode_;
+        std::string logging_message_;
+
+        friend class CommandOptions;
+        friend class CommandOptionsBuilder;
+    };
+
+    CommandOptions(const CommandOptionsValues& values);
+
+    const CommandOptionsValues values;
+
+  public:
+    class CommandOptionsBuilder {
+      public:
+        /* Sets the command to always run, even on `dry-run` mode. */
+        CommandOptionsBuilder& Always();
+        /* Sets the command's PrivilegeMode as `SU_ROOT` */
+        CommandOptionsBuilder& AsRoot();
+        /* Sets the command's PrivilegeMode as `DROP_ROOT` */
+        CommandOptionsBuilder& DropRoot();
+        /* Sets the command's OutputMode as `REDIRECT_TO_STDERR` */
+        CommandOptionsBuilder& RedirectStderr();
+        /* When not empty, logs a message before executing the command.
+         * Must contain a `%s`, which will be replaced by the full command line, and end on `\n`. */
+        CommandOptionsBuilder& Log(const std::string& message);
+        /* Builds the command options. */
+        CommandOptions Build();
+
+      private:
+        CommandOptionsBuilder(int64_t timeout);
+        CommandOptionsValues values;
+        friend class CommandOptions;
+    };
+
+    /** Gets the command timeout, in seconds. */
+    int64_t Timeout() const;
+    /* Checks whether the command should always be run, even on dry-run mode. */
+    bool Always() const;
+    /** Gets the PrivilegeMode of the command. */
+    PrivilegeMode PrivilegeMode() const;
+    /** Gets the OutputMode of the command. */
+    OutputMode OutputMode() const;
+    /** Gets the logging message header, it any. */
+    std::string LoggingMessage() const;
+
+    /** Creates a builder with the requied timeout. */
+    static CommandOptionsBuilder WithTimeout(int64_t timeout);
+
+    // Common options.
+    static CommandOptions DEFAULT;
+    static CommandOptions AS_ROOT;
+};
+
+/*
+ * System properties helper.
+ */
+class PropertiesHelper {
+    friend class DumpstateBaseTest;
+
+  public:
+    /*
+     * Gets whether device is running a `user` build.
+     */
+    static bool IsUserBuild();
+
+    /*
+     * When running in dry-run mode, skips the real dumps and just print the section headers.
+     *
+     * Useful when debugging dumpstate or other bugreport-related activities.
+     *
+     * Dry-run mode is enabled by setting the system property `dumpstate.dry_run` to true.
+     */
+    static bool IsDryRun();
+
+  private:
+    static std::string build_type_;
+    static int dry_run_;
+};
+
+/*
+ * Forks a command, waits for it to finish, and returns its status.
+ *
+ * |fd| file descriptor that receives the command's 'stdout'.
+ * |title| description of the command printed on `stdout` (or empty to skip
+ * description).
+ * |full_command| array containing the command (first entry) and its arguments.
+ *                Must contain at least one element.
+ * |options| optional argument defining the command's behavior.
+ */
+int RunCommandToFd(int fd, const std::string& title, const std::vector<std::string>& full_command,
+                   const CommandOptions& options = CommandOptions::DEFAULT);
+
+/*
+ * Dumps the contents of a file into a file descriptor.
+ *
+ * |fd| file descriptor where the file is dumped into.
+ * |title| description of the command printed on `stdout` (or empty to skip
+ * description).
+ * |path| location of the file to be dumped.
+ */
+int DumpFileToFd(int fd, const std::string& title, const std::string& path);
+
+/*
+ * Finds the process id by process name.
+ * |ps_name| the process name we want to search for
+ */
+int GetPidByName(const std::string& ps_name);
+
+}  // namespace dumpstate
+}  // namespace os
+}  // namespace android
+
+#endif  // ANDROID_OS_DUMPSTATE_UTIL_H_
diff --git a/cmds/dumpstate/README.md b/cmds/dumpstate/README.md
new file mode 100644
index 0000000..0302ea5
--- /dev/null
+++ b/cmds/dumpstate/README.md
@@ -0,0 +1,103 @@
+# `dumpstate` development tips
+
+## To build `dumpstate`
+
+Do a full build first:
+
+```
+m -j dumpstate
+```
+
+Then incremental ones:
+
+```
+mmm -j frameworks/native/cmds/dumpstate
+```
+
+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
+```
+
+## 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
+```
+
+## To build, deploy, and run unit tests
+
+First create `/data/nativetest`:
+
+```
+adb shell mkdir /data/nativetest
+```
+
+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
+```
+
+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
+```
+
+## To take quick bugreports
+
+```
+adb shell setprop dumpstate.dry_run true
+```
+
+## To change the `dumpstate` version
+
+```
+adb shell setprop dumpstate.version VERSION_NAME
+```
+
+Example:
+
+```
+adb shell setprop dumpstate.version split-dumpsys && adb shell dumpstate -v
+```
+
+
+Then to restore the default version:
+
+```
+adb shell setprop dumpstate.version default
+```
+
+## 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`:
+
+```
+git clang-format --style=file HEAD~
+```
+
+## Useful Bash tricks
+
+```
+export BR_DIR=/bugreports
+
+alias br='adb shell cmd activity bug-report'
+alias ls_bugs='adb shell ls -l ${BR_DIR}/'
+
+unzip_bug() {
+  adb pull ${BR_DIR}/$1 && emacs $1 && mv $1 /tmp
+}
+
+less_bug() {
+  adb pull ${BR_DIR}/$1 && less $1 && mv $1 /tmp
+}
+
+rm_bugs() {
+ if [ -z "${BR_DIR}" ] ; then echo "Variable BR_DIR not set"; else adb shell rm -rf ${BR_DIR}/*; fi
+}
+
+```
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
new file mode 100644
index 0000000..4becccf
--- /dev/null
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -0,0 +1,35 @@
+/**
+ * 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.
+ */
+
+package android.os;
+
+import android.os.IDumpstateListener;
+import android.os.IDumpstateToken;
+
+/**
+  * Binder interface for the currently running dumpstate process.
+  * {@hide}
+  */
+interface IDumpstate {
+
+    /*
+     * Sets the listener for this dumpstate progress.
+     *
+     * Returns a token used to monitor dumpstate death, or `nullptr` if the listener was already
+     * set (the listener behaves like a Highlander: There Can be Only One).
+     */
+    IDumpstateToken setListener(@utf8InCpp String name, IDumpstateListener listener);
+}
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
new file mode 100644
index 0000000..32717f4
--- /dev/null
+++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
@@ -0,0 +1,27 @@
+/**
+ * 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.
+ */
+
+package android.os;
+
+/**
+  * Listener for dumpstate events.
+  *
+  * {@hide}
+  */
+interface IDumpstateListener {
+    void onProgressUpdated(int progress);
+    void onMaxProgressUpdated(int maxProgress);
+}
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateToken.aidl b/cmds/dumpstate/binder/android/os/IDumpstateToken.aidl
new file mode 100644
index 0000000..7f74ceb
--- /dev/null
+++ b/cmds/dumpstate/binder/android/os/IDumpstateToken.aidl
@@ -0,0 +1,24 @@
+/**
+ * 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.
+ */
+
+package android.os;
+
+/**
+  * Token used by the IDumpstateListener to watch for dumpstate death.
+  * {@hide}
+  */
+interface IDumpstateToken {
+}
diff --git a/cmds/dumpstate/bugreport-format.md b/cmds/dumpstate/bugreport-format.md
index ca7d574..b995b80 100644
--- a/cmds/dumpstate/bugreport-format.md
+++ b/cmds/dumpstate/bugreport-format.md
@@ -22,7 +22,7 @@
 file as the `ACTION_SEND_MULTIPLE` attachment.
 
 ## Version 1.0 (Android N)
-On _Android N (TBD)_, `dumpstate` generates a zip file directly (unless there
+On _Android N (Nougat)_, `dumpstate` generates a zip file directly (unless there
 is a failure, in which case it reverts to the flat file that is zipped by
 **Shell** and hence the end result is the _v0_ format).
 
@@ -55,6 +55,10 @@
 - `title.txt`: whose value is a single-line summary of the problem.
 - `description.txt`: whose value is a multi-line, detailed description of the problem.
 
+## Android O versions
+On _Android O (OhMightyAndroidWhatsYourNextReleaseName?)_, the following changes were made:
+- The ANR traces are added to the `FS` folder, typically under `FS/data/anr` (version `2.0-dev-1`).
+
 ## Intermediate versions
 During development, the versions will be suffixed with _-devX_ or
 _-devX-EXPERIMENTAL_FEATURE_, where _X_ is a number that increases as the
@@ -63,8 +67,8 @@
 For example, the initial version during _Android N_ development was
 **1.0-dev1**. When `dumpsys` was split in 2 sections but not all tools were
 ready to parse that format, the version was named **1.0-dev2**,
-which had to be passed do `dumpsys` explicitly (i.e., trhough a
-`-V 1.0-dev2` argument). Once that format became stable and tools
+which had to be passed to `dumpsys` explicitly (by setting the `dumpstate.version` system property).
+Once that format became stable and tools
 knew how to parse it, the default version became **1.0-dev2**.
 
 Similarly, if changes in the file format are made after the initial release of
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 0929d9b..f84d86d 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "dumpstate"
+
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -35,38 +37,37 @@
 #include <unistd.h>
 
 #include <android-base/file.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
+#include <cutils/native_handle.h>
 #include <cutils/properties.h>
+#include <openssl/sha.h>
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
 
-#include "private/android_filesystem_config.h"
-
-#define LOG_TAG "dumpstate"
-#include <cutils/log.h>
-
+#include "DumpstateInternal.h"
+#include "DumpstateService.h"
 #include "dumpstate.h"
-#include "ScopedFd.h"
-#include "ziparchive/zip_writer.h"
 
-#include "mincrypt/sha256.h"
+using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
 
-using android::base::StringPrintf;
+// TODO: remove once moved to namespace
+using android::os::dumpstate::CommandOptions;
+using android::os::dumpstate::DumpFileToFd;
+using android::os::dumpstate::PropertiesHelper;
+using android::os::dumpstate::GetPidByName;
 
 /* read before root is shed */
 static char cmdline_buf[16384] = "(unknown)";
 static const char *dump_traces_path = NULL;
 
-// TODO: variables below should be part of dumpstate object
-static unsigned long id;
-static char build_type[PROPERTY_VALUE_MAX];
-static time_t now;
-static std::unique_ptr<ZipWriter> zip_writer;
+// TODO: variables and functions below should be part of dumpstate object
+
 static std::set<std::string> mount_points;
 void add_mountinfo();
-int control_socket_fd = -1;
-/* suffix of the bugreport files - it's typically the date (when invoked with -d),
- * although it could be changed by the user using a system property */
-static std::string suffix;
 
 #define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
 #define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
@@ -91,41 +92,57 @@
 
 static tombstone_data_t tombstone_data[NUM_TOMBSTONES];
 
-const std::string ZIP_ROOT_DIR = "FS";
-std::string bugreport_dir;
-
-/*
- * List of supported zip format versions.
- *
- * See bugreport-format.txt for more info.
- */
-static std::string VERSION_DEFAULT = "1.0";
-
-bool is_user_build() {
-    return 0 == strncmp(build_type, "user", PROPERTY_VALUE_MAX - 1);
+// TODO: temporary variables and functions used during C++ refactoring
+static Dumpstate& ds = Dumpstate::GetInstance();
+static int RunCommand(const std::string& title, const std::vector<std::string>& fullCommand,
+                      const CommandOptions& options = CommandOptions::DEFAULT) {
+    return ds.RunCommand(title, fullCommand, options);
+}
+static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
+                       const CommandOptions& options = Dumpstate::DEFAULT_DUMPSYS,
+                       long dumpsysTimeout = 0) {
+    return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeout);
+}
+static int DumpFile(const std::string& title, const std::string& path) {
+    return ds.DumpFile(title, path);
 }
 
-/* gets the tombstone data, according to the bugreport type: if zipped gets all tombstones,
- * otherwise gets just those modified in the last half an hour. */
+// 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/dumpstate_board.txt";
+static const std::string kLsHalDebugPath = "/bugreports/dumpstate_lshal.txt";
+
+static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
+static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
+static constexpr char PROPERTY_VERSION[] = "dumpstate.version";
+static constexpr char PROPERTY_EXTRA_TITLE[] = "dumpstate.options.title";
+static constexpr char PROPERTY_EXTRA_DESCRIPTION[] = "dumpstate.options.description";
+
+static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
+
+/* gets the tombstone data, according to the bugreport type: if zipped, gets all tombstones;
+ * otherwise, gets just those modified in the last half an hour. */
 static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
-    time_t thirty_minutes_ago = now - 60*30;
+    time_t thirty_minutes_ago = ds.now_ - 60 * 30;
     for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
         snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
         int fd = TEMP_FAILURE_RETRY(open(data[i].name,
                                          O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
         struct stat st;
-        if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) &&
-            (zip_writer || (time_t) st.st_mtime >= thirty_minutes_ago)) {
-        data[i].fd = fd;
+        if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) && st.st_size > 0 &&
+            (ds.IsZipping() || st.st_mtime >= thirty_minutes_ago)) {
+            data[i].fd = fd;
         } else {
-        close(fd);
+            close(fd);
             data[i].fd = -1;
         }
     }
 }
 
 // for_each_pid() callback to get mount info about a process.
-void do_mountinfo(int pid, const char *name) {
+void do_mountinfo(int pid, const char* name __attribute__((unused))) {
     char path[PATH_MAX];
 
     // Gets the the content of the /proc/PID/ns/mnt link, so only unique mount points
@@ -142,7 +159,7 @@
     if (mount_points.find(linkname) == mount_points.end()) {
         // First time this mount point was found: add it
         snprintf(path, sizeof(path), "/proc/%d/mountinfo", pid);
-        if (add_zip_entry(ZIP_ROOT_DIR + path, path)) {
+        if (ds.AddZipEntry(ZIP_ROOT_DIR + path, path)) {
             mount_points.insert(linkname);
         } else {
             MYLOGE("Unable to add mountinfo %s to zip file\n", path);
@@ -151,12 +168,12 @@
 }
 
 void add_mountinfo() {
-    if (!is_zipping()) return;
-    const char *title = "MOUNT INFO";
+    if (!ds.IsZipping()) return;
+    std::string title = "MOUNT INFO";
     mount_points.clear();
-    DurationReporter duration_reporter(title, NULL);
-    for_each_pid(do_mountinfo, NULL);
-    MYLOGD("%s: %d entries added to zip file\n", title, (int) mount_points.size());
+    DurationReporter duration_reporter(title, true);
+    for_each_pid(do_mountinfo, nullptr);
+    MYLOGD("%s: %d entries added to zip file\n", title.c_str(), (int)mount_points.size());
 }
 
 static void dump_dev_files(const char *title, const char *driverpath, const char *filename)
@@ -175,40 +192,13 @@
             continue;
         }
         snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename);
-        dump_file(title, path);
+        DumpFile(title, path);
     }
 
     closedir(d);
 }
 
-// return pid of a userspace process. If not found or error, return 0.
-static unsigned int pid_of_process(const char* ps_name) {
-    DIR *proc_dir;
-    struct dirent *ps;
-    unsigned int pid;
-    std::string cmdline;
 
-    if (!(proc_dir = opendir("/proc"))) {
-        MYLOGE("Can't open /proc\n");
-        return 0;
-    }
-
-    while ((ps = readdir(proc_dir))) {
-        if (!(pid = atoi(ps->d_name))) {
-            continue;
-        }
-        android::base::ReadFileToString("/proc/"
-                + std::string(ps->d_name) + "/cmdline", &cmdline);
-        if (cmdline.find(ps_name) == std::string::npos) {
-            continue;
-        } else {
-            closedir(proc_dir);
-            return pid;
-        }
-    }
-    closedir(proc_dir);
-    return 0;
-}
 
 // dump anrd's trace and add to the zip file.
 // 1. check if anrd is running on this device.
@@ -225,13 +215,13 @@
     long long cur_size = 0;
     const char *trace_path = "/data/misc/anrd/";
 
-    if (!zip_writer) {
-        MYLOGE("Not dumping anrd trace because zip_writer is not set\n");
+    if (!ds.IsZipping()) {
+        MYLOGE("Not dumping anrd trace because it's not a zipped bugreport\n");
         return false;
     }
 
     // find anrd's pid if it is running.
-    pid = pid_of_process("/system/xbin/anrd");
+    pid = GetPidByName("/system/xbin/anrd");
 
     if (pid > 0) {
         if (stat(trace_path, &st) == 0) {
@@ -243,7 +233,8 @@
 
         // send SIGUSR1 to the anrd to generate a trace.
         sprintf(buf, "%u", pid);
-        if (run_command("ANRD_DUMP", 1, "kill", "-SIGUSR1", buf, NULL)) {
+        if (RunCommand("ANRD_DUMP", {"kill", "-SIGUSR1", buf},
+                       CommandOptions::WithTimeout(1).Build())) {
             MYLOGE("anrd signal timed out. Please manually collect trace\n");
             return false;
         }
@@ -296,7 +287,7 @@
                 }
             }
             // Add to the zip file.
-            if (!add_zip_entry("anrd_trace.txt", path)) {
+            if (!ds.AddZipEntry("anrd_trace.txt", path)) {
                 MYLOGE("Unable to add anrd_trace file %s to zip file\n", path);
             } else {
                 if (remove(path)) {
@@ -312,11 +303,11 @@
 }
 
 static void dump_systrace() {
-    if (!is_zipping()) {
-        MYLOGD("Not dumping systrace because dumpstate is not zipping\n");
+    if (!ds.IsZipping()) {
+        MYLOGD("Not dumping systrace because it's not a zipped bugreport\n");
         return;
     }
-    std::string systrace_path = bugreport_dir + "/systrace-" + suffix + ".txt";
+    std::string systrace_path = ds.GetPath("-systrace.txt");
     if (systrace_path.empty()) {
         MYLOGE("Not dumping systrace because path is empty\n");
         return;
@@ -333,17 +324,17 @@
 
     MYLOGD("Running '/system/bin/atrace --async_dump -o %s', which can take several minutes",
             systrace_path.c_str());
-    if (run_command("SYSTRACE", 120, "/system/bin/atrace", "--async_dump", "-o",
-            systrace_path.c_str(), NULL)) {
+    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: run_command 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 (run_command("SYSTRACE", 10, "/system/bin/atrace", "--kill", NULL)) {
-        //            MYLOGE("could not stop systrace ");
-        //        }
+        // 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 (!add_zip_entry("systrace.txt", systrace_path)) {
+    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())) {
@@ -353,13 +344,13 @@
 }
 
 static void dump_raft() {
-    if (is_user_build()) {
+    if (PropertiesHelper::IsUserBuild()) {
         return;
     }
 
-    std::string raft_log_path = bugreport_dir + "/raft_log.txt";
-    if (raft_log_path.empty()) {
-        MYLOGD("raft_log_path is empty\n");
+    std::string raft_path = ds.GetPath("-raft_log.txt");
+    if (raft_path.empty()) {
+        MYLOGD("raft_path is empty\n");
         return;
     }
 
@@ -369,29 +360,30 @@
         return;
     }
 
-    if (!is_zipping()) {
-        // Write compressed and encoded raft logs to stdout if not zip_writer.
-        run_command("RAFT LOGS", 600, "logcompressor", "-r", RAFT_DIR, NULL);
+    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;
     }
 
-    run_command("RAFT LOGS", 600, "logcompressor", "-n", "-r", RAFT_DIR,
-            "-o", raft_log_path.c_str(), NULL);
-    if (!add_zip_entry("raft_log.txt", raft_log_path)) {
-        MYLOGE("Unable to add raft log %s to zip file\n", raft_log_path.c_str());
+    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_log_path.c_str())) {
-            MYLOGE("Error removing raft file %s: %s\n", raft_log_path.c_str(), strerror(errno));
+        if (remove(raft_path.c_str())) {
+            MYLOGE("Error removing raft file %s: %s\n", raft_path.c_str(), strerror(errno));
         }
     }
 }
 
 /**
- * Finds the last modified file in the directory dir whose name starts with file_prefix
+ * Finds the last modified file in the directory dir whose name starts with file_prefix.
+ *
  * Function returns empty string when it does not find a file
  */
-static std::string get_last_modified_file_matching_prefix(const std::string& dir,
-                                                          const std::string& file_prefix) {
+static std::string GetLastModifiedFileWithPrefix(const std::string& dir,
+                                                 const std::string& file_prefix) {
     std::unique_ptr<DIR, decltype(&closedir)> d(opendir(dir.c_str()), closedir);
     if (d == nullptr) {
         MYLOGD("Error %d opening %s\n", errno, dir.c_str());
@@ -400,7 +392,7 @@
 
     // Find the newest file matching the file_prefix in dir
     struct dirent *de;
-    time_t last_modified = 0;
+    time_t last_modified_time = 0;
     std::string last_modified_file = "";
     struct stat s;
 
@@ -412,39 +404,43 @@
         file = dir + "/" + file;
         int ret = stat(file.c_str(), &s);
 
-        if ((ret == 0) && (s.st_mtime > last_modified)) {
+        if ((ret == 0) && (s.st_mtime > last_modified_time)) {
             last_modified_file = file;
-            last_modified = s.st_mtime;
+            last_modified_time = s.st_mtime;
         }
     }
 
     return last_modified_file;
 }
 
-void dump_modem_logs() {
-    DurationReporter duration_reporter("dump_modem_logs");
-    if (is_user_build()) {
+static void DumpModemLogs() {
+    DurationReporter durationReporter("DUMP MODEM LOGS");
+    if (PropertiesHelper::IsUserBuild()) {
         return;
     }
 
-    if (!is_zipping()) {
+    if (!ds.IsZipping()) {
         MYLOGD("Not dumping modem logs. dumpstate is not generating a zipping bugreport\n");
         return;
     }
 
-    char property[PROPERTY_VALUE_MAX];
-    property_get("ro.radio.log_prefix", property, "");
-    std::string file_prefix = std::string(property);
+    std::string file_prefix = android::base::GetProperty("ro.radio.log_prefix", "");
+
     if(file_prefix.empty()) {
         MYLOGD("No modem log : file_prefix is empty\n");
         return;
     }
 
-    MYLOGD("dump_modem_logs: directory is %s and file_prefix is %s\n",
-           bugreport_dir.c_str(), file_prefix.c_str());
+    // TODO: b/33820081 we need to provide a right way to dump modem logs.
+    std::string radio_bugreport_dir = android::base::GetProperty("ro.radio.log_loc", "");
+    if (radio_bugreport_dir.empty()) {
+        radio_bugreport_dir = dirname(ds.GetPath("").c_str());
+    }
 
-    std::string modem_log_file =
-        get_last_modified_file_matching_prefix(bugreport_dir, file_prefix);
+    MYLOGD("DumpModemLogs: directory is %s and file_prefix is %s\n",
+           radio_bugreport_dir.c_str(), file_prefix.c_str());
+
+    std::string modem_log_file = GetLastModifiedFileWithPrefix(radio_bugreport_dir, file_prefix);
 
     struct stat s;
     if (modem_log_file.empty() || stat(modem_log_file.c_str(), &s) != 0) {
@@ -453,7 +449,7 @@
     }
 
     std::string filename = basename(modem_log_file.c_str());
-    if (!add_zip_entry(filename, modem_log_file)) {
+    if (!ds.AddZipEntry(filename, modem_log_file)) {
         MYLOGE("Unable to add modem log %s to zip file\n", modem_log_file.c_str());
     } else {
         MYLOGD("Modem Log %s is added to zip\n", modem_log_file.c_str());
@@ -472,7 +468,7 @@
     return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
 }
 
-static bool skip_none(const char *path) {
+static bool skip_none(const char* path __attribute__((unused))) {
     return false;
 }
 
@@ -631,11 +627,10 @@
                                  / fields[__STAT_IO_TICKS];
 
         if (!write_perf && !write_ios) {
-            printf("%s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n",
-                   path, read_perf, read_ios, queue);
+            printf("%s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n", path, read_perf, read_ios, queue);
         } else {
-            printf("%s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n",
-                   path, read_perf, read_ios, write_perf, write_ios, queue);
+            printf("%s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n", path, read_perf,
+                   read_ios, write_perf, write_ios, queue);
         }
 
         /* bugreport timeout factor adjustment */
@@ -646,132 +641,43 @@
     return 0;
 }
 
-/* Copied policy from system/core/logd/LogBuffer.cpp */
-
-#define LOG_BUFFER_SIZE (256 * 1024)
-#define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
-#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
-
-static bool valid_size(unsigned long value) {
-    if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
-        return false;
-    }
-
-    long pages = sysconf(_SC_PHYS_PAGES);
-    if (pages < 1) {
-        return true;
-    }
-
-    long pagesize = sysconf(_SC_PAGESIZE);
-    if (pagesize <= 1) {
-        pagesize = PAGE_SIZE;
-    }
-
-    // maximum memory impact a somewhat arbitrary ~3%
-    pages = (pages + 31) / 32;
-    unsigned long maximum = pages * pagesize;
-
-    if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
-        return true;
-    }
-
-    return value <= maximum;
-}
-
-static unsigned long property_get_size(const char *key) {
-    unsigned long value;
-    char *cp, property[PROPERTY_VALUE_MAX];
-
-    property_get(key, property, "");
-    value = strtoul(property, &cp, 10);
-
-    switch(*cp) {
-    case 'm':
-    case 'M':
-        value *= 1024;
-    /* FALLTHRU */
-    case 'k':
-    case 'K':
-        value *= 1024;
-    /* FALLTHRU */
-    case '\0':
-        break;
-
-    default:
-        value = 0;
-    }
-
-    if (!valid_size(value)) {
-        value = 0;
-    }
-
-    return value;
-}
-
 /* timeout in ms */
 static unsigned long logcat_timeout(const char *name) {
-    static const char global_tuneable[] = "persist.logd.size"; // Settings App
-    static const char global_default[] = "ro.logd.size";       // BoardConfig.mk
-    char key[PROP_NAME_MAX];
-    unsigned long property_size, default_size;
-
-    default_size = property_get_size(global_tuneable);
-    if (!default_size) {
-        default_size = property_get_size(global_default);
-    }
-
-    snprintf(key, sizeof(key), "%s.%s", global_tuneable, name);
-    property_size = property_get_size(key);
-
-    if (!property_size) {
-        snprintf(key, sizeof(key), "%s.%s", global_default, name);
-        property_size = property_get_size(key);
-    }
-
-    if (!property_size) {
-        property_size = default_size;
-    }
-
-    if (!property_size) {
-        property_size = LOG_BUFFER_SIZE;
-    }
-
+    log_id_t id = android_name_to_log_id(name);
+    unsigned long property_size = __android_logger_get_buffer_size(id);
     /* Engineering margin is ten-fold our guess */
     return 10 * (property_size + worst_write_perf) / worst_write_perf;
 }
 
-/* End copy from system/core/logd/LogBuffer.cpp */
+void Dumpstate::PrintHeader() const {
+    std::string build, fingerprint, radio, bootloader, network;
+    char date[80];
 
-/* dumps the current system state to stdout */
-static void print_header(std::string version) {
-    char build[PROPERTY_VALUE_MAX], fingerprint[PROPERTY_VALUE_MAX];
-    char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX];
-    char network[PROPERTY_VALUE_MAX], date[80];
-
-    property_get("ro.build.display.id", build, "(unknown)");
-    property_get("ro.build.fingerprint", fingerprint, "(unknown)");
-    property_get("ro.build.type", build_type, "(unknown)");
-    property_get("gsm.version.baseband", radio, "(unknown)");
-    property_get("ro.bootloader", bootloader, "(unknown)");
-    property_get("gsm.operator.alpha", network, "(unknown)");
-    strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now));
+    build = android::base::GetProperty("ro.build.display.id", "(unknown)");
+    fingerprint = android::base::GetProperty("ro.build.fingerprint", "(unknown)");
+    radio = android::base::GetProperty("gsm.version.baseband", "(unknown)");
+    bootloader = android::base::GetProperty("ro.bootloader", "(unknown)");
+    network = android::base::GetProperty("gsm.operator.alpha", "(unknown)");
+    strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now_));
 
     printf("========================================================\n");
     printf("== dumpstate: %s\n", date);
     printf("========================================================\n");
 
     printf("\n");
-    printf("Build: %s\n", build);
-    printf("Build fingerprint: '%s'\n", fingerprint); /* format is important for other tools */
-    printf("Bootloader: %s\n", bootloader);
-    printf("Radio: %s\n", radio);
-    printf("Network: %s\n", network);
+    printf("Build: %s\n", build.c_str());
+    // NOTE: fingerprint entry format is important for other tools.
+    printf("Build fingerprint: '%s'\n", fingerprint.c_str());
+    printf("Bootloader: %s\n", bootloader.c_str());
+    printf("Radio: %s\n", radio.c_str());
+    printf("Network: %s\n", network.c_str());
 
     printf("Kernel: ");
-    dump_file(NULL, "/proc/version");
+    DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
     printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
-    printf("Bugreport format version: %s\n", version.c_str());
-    printf("Dumpstate info: id=%lu pid=%d\n", id, getpid());
+    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());
     printf("\n");
 }
 
@@ -783,10 +689,10 @@
       ".shb", ".sys", ".vb",  ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
 };
 
-bool add_zip_entry_from_fd(const std::string& entry_name, int fd) {
-    if (!is_zipping()) {
-        MYLOGD("Not adding entry %s from fd because dumpstate is not zipping\n",
-                entry_name.c_str());
+bool Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd) {
+    if (!IsZipping()) {
+        MYLOGD("Not adding zip entry %s from fd because it's not a zipped bugreport\n",
+               entry_name.c_str());
         return false;
     }
     std::string valid_name = entry_name;
@@ -804,250 +710,305 @@
 
     // Logging statement  below is useful to time how long each entry takes, but it's too verbose.
     // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
-    int32_t err = zip_writer->StartEntryWithTime(valid_name.c_str(),
-            ZipWriter::kCompress, get_mtime(fd, now));
-    if (err) {
-        MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
-                ZipWriter::ErrorCodeString(err));
+    int32_t err = zip_writer_->StartEntryWithTime(valid_name.c_str(), ZipWriter::kCompress,
+                                                  get_mtime(fd, ds.now_));
+    if (err != 0) {
+        MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
+               ZipWriter::ErrorCodeString(err));
         return false;
     }
 
     std::vector<uint8_t> buffer(65536);
     while (1) {
-        ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), sizeof(buffer)));
+        ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), buffer.size()));
         if (bytes_read == 0) {
             break;
         } else if (bytes_read == -1) {
             MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
             return false;
         }
-        err = zip_writer->WriteBytes(buffer.data(), bytes_read);
+        err = zip_writer_->WriteBytes(buffer.data(), bytes_read);
         if (err) {
-            MYLOGE("zip_writer->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
+            MYLOGE("zip_writer_->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
             return false;
         }
     }
 
-    err = zip_writer->FinishEntry();
-    if (err) {
-        MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
+    err = zip_writer_->FinishEntry();
+    if (err != 0) {
+        MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
         return false;
     }
 
     return true;
 }
 
-bool add_zip_entry(const std::string& entry_name, const std::string& entry_path) {
-    ScopedFd fd(TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
-    if (fd.get() == -1) {
+bool Dumpstate::AddZipEntry(const std::string& entry_name, const std::string& entry_path) {
+    android::base::unique_fd fd(
+        TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
+    if (fd == -1) {
         MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
         return false;
     }
 
-    return add_zip_entry_from_fd(entry_name, fd.get());
+    return AddZipEntryFromFd(entry_name, fd.get());
 }
 
 /* adds a file to the existing zipped bugreport */
-static int _add_file_from_fd(const char *title, const char *path, int fd) {
-    return add_zip_entry_from_fd(ZIP_ROOT_DIR + path, fd) ? 0 : 1;
+static int _add_file_from_fd(const char* title __attribute__((unused)), const char* path, int fd) {
+    return ds.AddZipEntryFromFd(ZIP_ROOT_DIR + path, fd) ? 0 : 1;
 }
 
-// TODO: move to util.cpp
-void add_dir(const char *dir, bool recursive) {
-    if (!is_zipping()) {
-        MYLOGD("Not adding dir %s because dumpstate is not zipping\n", dir);
+void Dumpstate::AddDir(const std::string& dir, bool recursive) {
+    if (!IsZipping()) {
+        MYLOGD("Not adding dir %s because it's not a zipped bugreport\n", dir.c_str());
         return;
     }
-    MYLOGD("Adding dir %s (recursive: %d)\n", dir, recursive);
-    DurationReporter duration_reporter(dir, NULL);
-    dump_files(NULL, dir, recursive ? skip_none : is_dir, _add_file_from_fd);
+    MYLOGD("Adding dir %s (recursive: %d)\n", dir.c_str(), recursive);
+    DurationReporter duration_reporter(dir, true);
+    dump_files("", dir.c_str(), recursive ? skip_none : is_dir, _add_file_from_fd);
 }
 
-bool is_zipping() {
-    return zip_writer != nullptr;
-}
-
-/* adds a text entry entry to the existing zip file. */
-static bool add_text_zip_entry(const std::string& entry_name, const std::string& content) {
-    if (!is_zipping()) {
-        MYLOGD("Not adding text entry %s because dumpstate is not zipping\n", entry_name.c_str());
+bool Dumpstate::AddTextZipEntry(const std::string& entry_name, const std::string& content) {
+    if (!IsZipping()) {
+        MYLOGD("Not adding text zip entry %s because it's not a zipped bugreport\n",
+               entry_name.c_str());
         return false;
     }
     MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
-    int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, now);
-    if (err) {
-        MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
-                ZipWriter::ErrorCodeString(err));
+    int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_);
+    if (err != 0) {
+        MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
+               ZipWriter::ErrorCodeString(err));
         return false;
     }
 
-    err = zip_writer->WriteBytes(content.c_str(), content.length());
-    if (err) {
-        MYLOGE("zip_writer->WriteBytes(%s): %s\n", entry_name.c_str(),
-                ZipWriter::ErrorCodeString(err));
+    err = zip_writer_->WriteBytes(content.c_str(), content.length());
+    if (err != 0) {
+        MYLOGE("zip_writer_->WriteBytes(%s): %s\n", entry_name.c_str(),
+               ZipWriter::ErrorCodeString(err));
         return false;
     }
 
-    err = zip_writer->FinishEntry();
-    if (err) {
-        MYLOGE("zip_writer->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
+    err = zip_writer_->FinishEntry();
+    if (err != 0) {
+        MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
         return false;
     }
 
     return true;
 }
 
-static void dump_iptables() {
-    run_command("IPTABLES", 10, "iptables", "-L", "-nvx", NULL);
-    run_command("IP6TABLES", 10, "ip6tables", "-L", "-nvx", NULL);
-    run_command("IPTABLES NAT", 10, "iptables", "-t", "nat", "-L", "-nvx", NULL);
-    /* no ip6 nat */
-    run_command("IPTABLES MANGLE", 10, "iptables", "-t", "mangle", "-L", "-nvx", NULL);
-    run_command("IP6TABLES MANGLE", 10, "ip6tables", "-t", "mangle", "-L", "-nvx", NULL);
-    run_command("IPTABLES RAW", 10, "iptables", "-t", "raw", "-L", "-nvx", NULL);
-    run_command("IP6TABLES RAW", 10, "ip6tables", "-t", "raw", "-L", "-nvx", NULL);
-}
-
-static void do_kmsg() {
+static void DoKmsg() {
     struct stat st;
     if (!stat(PSTORE_LAST_KMSG, &st)) {
         /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
-        dump_file("LAST KMSG", PSTORE_LAST_KMSG);
+        DumpFile("LAST KMSG", PSTORE_LAST_KMSG);
     } else if (!stat(ALT_PSTORE_LAST_KMSG, &st)) {
-        dump_file("LAST KMSG", ALT_PSTORE_LAST_KMSG);
+        DumpFile("LAST KMSG", ALT_PSTORE_LAST_KMSG);
     } else {
         /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */
-        dump_file("LAST KMSG", "/proc/last_kmsg");
+        DumpFile("LAST KMSG", "/proc/last_kmsg");
     }
 }
 
-static void do_logcat() {
+static void DoLogcat() {
     unsigned long timeout;
-    // dump_file("EVENT LOG TAGS", "/etc/event-log-tags");
+    // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
     // calculate timeout
     timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");
     if (timeout < 20000) {
         timeout = 20000;
     }
-    run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime",
-                                                        "-v", "printable",
-                                                        "-d",
-                                                        "*:v", NULL);
+    RunCommand("SYSTEM LOG",
+               {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid",
+                        "-d", "*:v"},
+               CommandOptions::WithTimeout(timeout / 1000).Build());
     timeout = logcat_timeout("events");
     if (timeout < 20000) {
         timeout = 20000;
     }
-    run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events",
-                                                       "-v", "threadtime",
-                                                       "-v", "printable",
-                                                       "-d",
-                                                       "*:v", NULL);
+    RunCommand("EVENT LOG",
+               {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid",
+                        "-d", "*:v"},
+               CommandOptions::WithTimeout(timeout / 1000).Build());
     timeout = logcat_timeout("radio");
     if (timeout < 20000) {
         timeout = 20000;
     }
-    run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio",
-                                                       "-v", "threadtime",
-                                                       "-v", "printable",
-                                                       "-d",
-                                                       "*:v", NULL);
+    RunCommand("RADIO LOG",
+               {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid",
+                        "-d", "*:v"},
+               CommandOptions::WithTimeout(timeout / 1000).Build());
 
-    run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL);
+    RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
 
     /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
-    run_command("LAST LOGCAT", 10, "logcat", "-L",
-                                             "-b", "all",
-                                             "-v", "threadtime",
-                                             "-v", "printable",
-                                             "-d",
-                                             "*:v", NULL);
+    RunCommand("LAST LOGCAT",
+                {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable", "-v", "uid",
+                        "-d", "*:v"});
 }
 
-static void dumpstate(const std::string& screenshot_path, const std::string& version) {
+static void DumpIpTables() {
+    RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
+    RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
+    RunCommand("IPTABLES NAT", {"iptables", "-t", "nat", "-L", "-nvx"});
+    /* no ip6 nat */
+    RunCommand("IPTABLES MANGLE", {"iptables", "-t", "mangle", "-L", "-nvx"});
+    RunCommand("IP6TABLES MANGLE", {"ip6tables", "-t", "mangle", "-L", "-nvx"});
+    RunCommand("IPTABLES RAW", {"iptables", "-t", "raw", "-L", "-nvx"});
+    RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
+}
+
+static void AddAnrTraceFiles() {
+    bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
+    std::string dump_traces_dir;
+
+    /* show the traces we collected in main(), if that was done */
+    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);
+        }
+    }
+
+    std::string anr_traces_path = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
+    std::string anr_traces_dir = dirname(anr_traces_path.c_str());
+
+    // 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("AddAnrTraceFiles(): dump_traces_dir=%s, anr_traces_dir=%s, already_dumped=%d\n",
+           dump_traces_dir.c_str(), anr_traces_dir.c_str(), already_dumped);
+
+    if (anr_traces_path.empty()) {
+        printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
+    } else {
+        int fd = TEMP_FAILURE_RETRY(
+            open(anr_traces_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
+        if (fd < 0) {
+            printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path.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);
+                    already_dumped = true;
+                }
+            } else {
+                MYLOGD("Dumping last ANR traces (%s) to the main bugreport entry\n",
+                       anr_traces_path.c_str());
+                dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path.c_str(), fd);
+            }
+        }
+    }
+
+    if (add_to_zip && already_dumped) {
+        MYLOGD("Already dumped directory %s to the zip file\n", anr_traces_dir.c_str());
+        return;
+    }
+
+    /* slow traces for slow operations */
+    struct stat st;
+    if (!anr_traces_path.empty()) {
+        int tail = anr_traces_path.size() - 1;
+        while (tail > 0 && anr_traces_path.at(tail) != '/') {
+            tail--;
+        }
+        int i = 0;
+        while (1) {
+            anr_traces_path = anr_traces_path.substr(0, tail + 1) +
+                              android::base::StringPrintf("slow%02d.txt", i);
+            if (stat(anr_traces_path.c_str(), &st)) {
+                // No traces file at this index, done with the files.
+                break;
+            }
+            ds.DumpFile("VM TRACES WHEN SLOW", anr_traces_path.c_str());
+            i++;
+        }
+    }
+}
+
+static void dumpstate() {
     DurationReporter duration_reporter("DUMPSTATE");
 
     dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
-    run_command("UPTIME", 10, "uptime", NULL);
+    RunCommand("UPTIME", {"uptime"});
     dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
     dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
-    dump_file("MEMORY INFO", "/proc/meminfo");
-    run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-H", NULL);
-    run_command("PROCRANK", 20, SU_PATH, "root", "procrank", NULL);
-    dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat");
-    dump_file("VMALLOC INFO", "/proc/vmallocinfo");
-    dump_file("SLAB INFO", "/proc/slabinfo");
-    dump_file("ZONEINFO", "/proc/zoneinfo");
-    dump_file("PAGETYPEINFO", "/proc/pagetypeinfo");
-    dump_file("BUDDYINFO", "/proc/buddyinfo");
-    dump_file("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
+    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);
+    DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat");
+    DumpFile("VMALLOC INFO", "/proc/vmallocinfo");
+    DumpFile("SLAB INFO", "/proc/slabinfo");
+    DumpFile("ZONEINFO", "/proc/zoneinfo");
+    DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo");
+    DumpFile("BUDDYINFO", "/proc/buddyinfo");
+    DumpFile("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
 
-    dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources");
-    dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
-    dump_file("KERNEL SYNC", "/d/sync");
+    DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
+    DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
+    DumpFile("KERNEL SYNC", "/d/sync");
 
-    run_command("PROCESSES AND THREADS", 10, "ps", "-Z", "-t", "-p", "-P", NULL);
-    run_command("LIBRANK", 10, SU_PATH, "root", "librank", NULL);
+    RunCommand("PROCESSES AND THREADS",
+               {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy"});
+    RunCommand("LIBRANK", {"librank"}, CommandOptions::AS_ROOT);
 
-    run_command("PRINTENV", 10, "printenv", NULL);
-    run_command("NETSTAT", 10, "netstat", "-n", NULL);
-    run_command("LSMOD", 10, "lsmod", NULL);
+    if (ds.IsZipping()) {
+        RunCommand(
+                "HARDWARE HALS",
+                {"lshal", std::string("--debug=") + kLsHalDebugPath},
+                CommandOptions::AS_ROOT);
+
+        ds.AddZipEntry("lshal-debug.txt", kLsHalDebugPath);
+
+        unlink(kLsHalDebugPath.c_str());
+    } else {
+        RunCommand(
+                "HARDWARE HALS", {"lshal", "--debug"}, CommandOptions::AS_ROOT);
+    }
+
+    RunCommand("PRINTENV", {"printenv"});
+    RunCommand("NETSTAT", {"netstat", "-nW"});
+    struct stat s;
+    if (stat("/proc/modules", &s) != 0) {
+        MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
+    } else {
+        RunCommand("LSMOD", {"lsmod"});
+    }
 
     do_dmesg();
 
-    run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL);
+    RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
     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)");
 
     /* Dump Bluetooth HCI logs */
-    add_dir("/data/misc/bluetooth/logs", true);
+    ds.AddDir("/data/misc/bluetooth/logs", true);
 
-    if (!screenshot_path.empty()) {
+    if (!ds.do_early_screenshot_) {
         MYLOGI("taking late screenshot\n");
-        take_screenshot(screenshot_path);
-        MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
+        ds.TakeScreenshot();
     }
 
-    do_logcat();
+    DoLogcat();
 
-    /* show the traces we collected in main(), if that was done */
-    if (dump_traces_path != NULL) {
-        dump_file("VM TRACES JUST NOW", dump_traces_path);
-    }
-
-    /* only show ANR traces if they're less than 15 minutes old */
-    struct stat st;
-    char anr_traces_path[PATH_MAX];
-    property_get("dalvik.vm.stack-trace-file", anr_traces_path, "");
-    if (!anr_traces_path[0]) {
-        printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
-    } else {
-      int fd = TEMP_FAILURE_RETRY(open(anr_traces_path,
-                                       O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
-      if (fd < 0) {
-          printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
-      } else {
-          dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path, fd);
-      }
-    }
-
-    /* slow traces for slow operations */
-    if (anr_traces_path[0] != 0) {
-        int tail = strlen(anr_traces_path)-1;
-        while (tail > 0 && anr_traces_path[tail] != '/') {
-            tail--;
-        }
-        int i = 0;
-        while (1) {
-            sprintf(anr_traces_path+tail+1, "slow%02d.txt", i);
-            if (stat(anr_traces_path, &st)) {
-                // No traces file at this index, done with the files.
-                break;
-            }
-            dump_file("VM TRACES WHEN SLOW", anr_traces_path);
-            i++;
-        }
-    }
+    AddAnrTraceFiles();
 
     int dumped = 0;
     for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
@@ -1055,8 +1016,8 @@
             const char *name = tombstone_data[i].name;
             int fd = tombstone_data[i].fd;
             dumped = 1;
-            if (zip_writer) {
-                if (!add_zip_entry_from_fd(ZIP_ROOT_DIR + name, fd)) {
+            if (ds.IsZipping()) {
+                if (!ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd)) {
                     MYLOGE("Unable to add tombstone %s to zip file\n", name);
                 }
             } else {
@@ -1070,229 +1031,294 @@
         printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
     }
 
-    dump_file("NETWORK DEV INFO", "/proc/net/dev");
-    dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
-    dump_file("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
-    dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
-    dump_file("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
+    DumpFile("NETWORK DEV INFO", "/proc/net/dev");
+    DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
+    DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
+    DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
+    DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
 
-    do_kmsg();
+    DoKmsg();
 
     /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
 
-    run_command("NETWORK INTERFACES", 10, "ip", "link", NULL);
+    RunCommand("NETWORK INTERFACES", {"ip", "link"});
 
-    run_command("IPv4 ADDRESSES", 10, "ip", "-4", "addr", "show", NULL);
-    run_command("IPv6 ADDRESSES", 10, "ip", "-6", "addr", "show", NULL);
+    RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
+    RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
 
-    run_command("IP RULES", 10, "ip", "rule", "show", NULL);
-    run_command("IP RULES v6", 10, "ip", "-6", "rule", "show", NULL);
+    RunCommand("IP RULES", {"ip", "rule", "show"});
+    RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
 
     dump_route_tables();
 
-    run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL);
-    run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL);
-    run_command("MULTICAST ADDRESSES", 10, "ip", "maddr", NULL);
-    run_command("WIFI NETWORKS", 20, "wpa_cli", "IFNAME=wlan0", "list_networks", NULL);
+    RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
+    RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
+    RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
+    RunCommand("WIFI NETWORKS", {"wpa_cli", "IFNAME=wlan0", "list_networks"},
+               CommandOptions::WithTimeout(20).Build());
 
-#ifdef FWDUMP_bcmdhd
-    run_command("ND OFFLOAD TABLE", 5,
-            SU_PATH, "root", WLUTIL, "nd_hostip", NULL);
+    RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
+               CommandOptions::WithTimeout(10).Build());
 
-    run_command("DUMP WIFI INTERNAL COUNTERS (1)", 20,
-            SU_PATH, "root", WLUTIL, "counters", NULL);
+    RunCommand("SYSTEM PROPERTIES", {"getprop"});
 
-    run_command("ND OFFLOAD STATUS (1)", 5,
-            SU_PATH, "root", WLUTIL, "nd_status", NULL);
+    RunCommand("VOLD DUMP", {"vdc", "dump"});
+    RunCommand("SECURE CONTAINERS", {"vdc", "asec", "list"});
 
-#endif
-    dump_file("INTERRUPTS (1)", "/proc/interrupts");
+    RunCommand("STORAGED TASKIOINFO", {"storaged", "-u"}, CommandOptions::WithTimeout(10).Build());
 
-    run_command("NETWORK DIAGNOSTICS", 10, "dumpsys", "-t", "10", "connectivity", "--diag", NULL);
+    RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
 
-#ifdef FWDUMP_bcmdhd
-    run_command("DUMP WIFI STATUS", 20,
-            SU_PATH, "root", "dhdutil", "-i", "wlan0", "dump", NULL);
-
-    run_command("DUMP WIFI INTERNAL COUNTERS (2)", 20,
-            SU_PATH, "root", WLUTIL, "counters", NULL);
-
-    run_command("ND OFFLOAD STATUS (2)", 5,
-            SU_PATH, "root", WLUTIL, "nd_status", NULL);
-#endif
-    dump_file("INTERRUPTS (2)", "/proc/interrupts");
-
-    print_properties();
-
-    run_command("VOLD DUMP", 10, "vdc", "dump", NULL);
-    run_command("SECURE CONTAINERS", 10, "vdc", "asec", "list", NULL);
-
-    run_command("FILESYSTEMS & FREE SPACE", 10, "df", NULL);
-
-    run_command("LAST RADIO LOG", 10, "parse_radio_log", "/proc/last_radio_log", NULL);
+    RunCommand("LAST RADIO LOG", {"parse_radio_log", "/proc/last_radio_log"});
 
     printf("------ BACKLIGHTS ------\n");
     printf("LCD brightness=");
-    dump_file(NULL, "/sys/class/leds/lcd-backlight/brightness");
+    DumpFile("", "/sys/class/leds/lcd-backlight/brightness");
     printf("Button brightness=");
-    dump_file(NULL, "/sys/class/leds/button-backlight/brightness");
+    DumpFile("", "/sys/class/leds/button-backlight/brightness");
     printf("Keyboard brightness=");
-    dump_file(NULL, "/sys/class/leds/keyboard-backlight/brightness");
+    DumpFile("", "/sys/class/leds/keyboard-backlight/brightness");
     printf("ALS mode=");
-    dump_file(NULL, "/sys/class/leds/lcd-backlight/als");
+    DumpFile("", "/sys/class/leds/lcd-backlight/als");
     printf("LCD driver registers:\n");
-    dump_file(NULL, "/sys/class/leds/lcd-backlight/registers");
+    DumpFile("", "/sys/class/leds/lcd-backlight/registers");
     printf("\n");
 
     /* Binder state is expensive to look at as it uses a lot of memory. */
-    dump_file("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
-    dump_file("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
-    dump_file("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
-    dump_file("BINDER STATS", "/sys/kernel/debug/binder/stats");
-    dump_file("BINDER STATE", "/sys/kernel/debug/binder/state");
+    DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
+    DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
+    DumpFile("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
+    DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
+    DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
 
-    printf("========================================================\n");
-    printf("== Board\n");
-    printf("========================================================\n");
+    ds.DumpstateBoard();
 
-    dumpstate_board();
-    printf("\n");
-
-    /* Migrate the ril_dumpstate to a dumpstate_board()? */
-    char ril_dumpstate_timeout[PROPERTY_VALUE_MAX] = {0};
-    property_get("ril.dumpstate.timeout", ril_dumpstate_timeout, "30");
-    if (strnlen(ril_dumpstate_timeout, PROPERTY_VALUE_MAX - 1) > 0) {
-        if (is_user_build()) {
-            // su does not exist on user builds, so try running without it.
-            // This way any implementations of vril-dump that do not require
-            // root can run on user builds.
-            run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
-                    "vril-dump", NULL);
-        } else {
-            run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
-                    SU_PATH, "root", "vril-dump", NULL);
+    /* Migrate the ril_dumpstate to a device specific dumpstate? */
+    int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
+    if (rilDumpstateTimeout > 0) {
+        // su does not exist on user builds, so try running without it.
+        // This way any implementations of vril-dump that do not require
+        // root can run on user builds.
+        CommandOptions::CommandOptionsBuilder options =
+            CommandOptions::WithTimeout(rilDumpstateTimeout);
+        if (!PropertiesHelper::IsUserBuild()) {
+            options.AsRoot();
         }
+        RunCommand("DUMP VENDOR RIL LOGS", {"vril-dump"}, options.Build());
     }
 
     printf("========================================================\n");
     printf("== Android Framework Services\n");
     printf("========================================================\n");
 
-    run_command("DUMPSYS", 60, "dumpsys", "-t", "60", "--skip", "meminfo", "cpuinfo", NULL);
+    RunDumpsys("DUMPSYS", {"--skip", "meminfo", "cpuinfo"}, CommandOptions::WithTimeout(90).Build(),
+               10);
 
     printf("========================================================\n");
     printf("== Checkins\n");
     printf("========================================================\n");
 
-    run_command("CHECKIN BATTERYSTATS", 30, "dumpsys", "-t", "30", "batterystats", "-c", NULL);
-    run_command("CHECKIN MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "--checkin", NULL);
-    run_command("CHECKIN NETSTATS", 30, "dumpsys", "-t", "30", "netstats", "--checkin", NULL);
-    run_command("CHECKIN PROCSTATS", 30, "dumpsys", "-t", "30", "procstats", "-c", NULL);
-    run_command("CHECKIN USAGESTATS", 30, "dumpsys", "-t", "30", "usagestats", "-c", NULL);
-    run_command("CHECKIN PACKAGE", 30, "dumpsys", "-t", "30", "package", "--checkin", NULL);
+    RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
+    RunDumpsys("CHECKIN MEMINFO", {"meminfo", "--checkin"});
+    RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
+    RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
+    RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
+    RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"});
 
     printf("========================================================\n");
     printf("== Running Application Activities\n");
     printf("========================================================\n");
 
-    run_command("APP ACTIVITIES", 30, "dumpsys", "-t", "30", "activity", "all", NULL);
+    RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"});
 
     printf("========================================================\n");
     printf("== Running Application Services\n");
     printf("========================================================\n");
 
-    run_command("APP SERVICES", 30, "dumpsys", "-t", "30", "activity", "service", "all", NULL);
+    RunDumpsys("APP SERVICES", {"activity", "service", "all"});
 
     printf("========================================================\n");
     printf("== Running Application Providers\n");
     printf("========================================================\n");
 
-    run_command("APP PROVIDERS", 30, "dumpsys", "-t", "30", "activity", "provider", "all", NULL);
+    RunDumpsys("APP PROVIDERS", {"activity", "provider", "all"});
 
-    // dump_modem_logs adds the modem logs if available to the bugreport.
+    printf("========================================================\n");
+    printf("== Dropbox crashes\n");
+    printf("========================================================\n");
+
+    RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
+    RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});
+
+    // DumpModemLogs adds the modem logs if available to the bugreport.
     // Do this at the end to allow for sufficient time for the modem logs to be
     // collected.
-    dump_modem_logs();
+    DumpModemLogs();
 
     printf("========================================================\n");
-    printf("== Final progress (pid %d): %d/%d (originally %d)\n",
-            getpid(), progress, weight_total, WEIGHT_TOTAL);
+    printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
+           ds.progress_->GetMax(), ds.progress_->GetInitialMax());
     printf("========================================================\n");
-    printf("== dumpstate: done\n");
+    printf("== dumpstate: done (id %d)\n", ds.id_);
     printf("========================================================\n");
 }
 
-static void usage() {
-  fprintf(stderr,
-          "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file [-d] [-p] [-t]"
-          "[-z] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
-          "  -h: display this help message\n"
-          "  -b: play sound file instead of vibrate, at beginning of job\n"
-          "  -e: play sound file instead of vibrate, at end of job\n"
-          "  -o: write to file (instead of stdout)\n"
-          "  -d: append date to filename (requires -o)\n"
-          "  -p: capture screenshot to filename.png (requires -o)\n"
-          "  -t: only captures telephony sections\n"
-          "  -z: generate zipped file (requires -o)\n"
-          "  -s: write output to control socket (for init)\n"
-          "  -S: write file location to control socket (for init; requires -o and -z)"
-          "  -q: disable vibrate\n"
-          "  -B: send broadcast when finished (requires -o)\n"
-          "  -P: send broadcast when started and update system properties on "
-          "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"
-          "  -V: sets the bugreport format version (valid values: %s)\n",
-          VERSION_DEFAULT.c_str());
+void Dumpstate::DumpstateBoard() {
+    DurationReporter duration_reporter("dumpstate_board()");
+    printf("========================================================\n");
+    printf("== Board\n");
+    printf("========================================================\n");
+
+    ::android::sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
+    if (dumpstate_device == nullptr) {
+        MYLOGE("No IDumpstateDevice implementation\n");
+        return;
+    }
+
+    if (!IsZipping()) {
+        MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
+        return;
+    }
+
+    std::string path = kDumpstateBoardPath;
+    MYLOGI("Calling IDumpstateDevice implementation using path %s\n", path.c_str());
+
+    int fd =
+        TEMP_FAILURE_RETRY(open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+                                S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
+    if (fd < 0) {
+        MYLOGE("Could not open file %s: %s\n", path.c_str(), strerror(errno));
+        return;
+    }
+
+    native_handle_t* handle = native_handle_create(1, 0);
+    if (handle == nullptr) {
+        MYLOGE("Could not create native_handle\n");
+        return;
+    }
+    handle->data[0] = fd;
+
+    // TODO: need a timeout mechanism so dumpstate does not hang on device implementation call.
+    android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle);
+    if (!status.isOk()) {
+        MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
+        native_handle_close(handle);
+        native_handle_delete(handle);
+        return;
+    }
+
+    AddZipEntry("dumpstate-board.txt", path);
+    printf("*** See dumpstate-board.txt entry ***\n");
+
+    native_handle_close(handle);
+    native_handle_delete(handle);
+
+    if (remove(path.c_str()) != 0) {
+        MYLOGE("Could not remove(%s): %s\n", path.c_str(), strerror(errno));
+    }
 }
 
-static void sigpipe_handler(int n) {
-    // don't complain to stderr or stdout
+static void ShowUsageAndExit(int exitCode = 1) {
+    fprintf(stderr,
+            "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file] [-d] [-p] "
+            "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
+            "  -h: display this help message\n"
+            "  -b: play sound file instead of vibrate, at beginning of job\n"
+            "  -e: play sound file instead of vibrate, at end of job\n"
+            "  -o: write to file (instead of stdout)\n"
+            "  -d: append date to filename (requires -o)\n"
+            "  -p: capture screenshot to filename.png (requires -o)\n"
+            "  -z: generate zipped file (requires -o)\n"
+            "  -s: write output to control socket (for init)\n"
+            "  -S: write file location to control socket (for init; requires -o and -z)"
+            "  -q: disable vibrate\n"
+            "  -B: send broadcast when finished (requires -o)\n"
+            "  -P: send broadcast when started and update system properties on "
+            "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"
+            "  -v: prints the dumpstate header and exit\n");
+    exit(exitCode);
+}
+
+static void ExitOnInvalidArgs() {
+    fprintf(stderr, "invalid combination of args\n");
+    ShowUsageAndExit();
+}
+
+static void sig_handler(int) {
     _exit(EXIT_FAILURE);
 }
 
-/* adds the temporary report to the existing .zip file, closes the .zip file, and removes the
-   temporary file.
- */
-static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path,
-        time_t now) {
-    if (!add_zip_entry(bugreport_name, bugreport_path)) {
+static void register_sig_handler() {
+    struct sigaction sa;
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    sa.sa_handler = sig_handler;
+    sigaction(SIGPIPE, &sa, NULL); // broken pipe
+    sigaction(SIGSEGV, &sa, NULL); // segment fault
+    sigaction(SIGINT, &sa, NULL); // ctrl-c
+    sigaction(SIGTERM, &sa, NULL); // killed
+    sigaction(SIGQUIT, &sa, NULL); // quit
+}
+
+bool Dumpstate::FinishZipFile() {
+    std::string entry_name = base_name_ + "-" + name_ + ".txt";
+    MYLOGD("Adding main entry (%s) from %s to .zip bugreport\n", entry_name.c_str(),
+           tmp_path_.c_str());
+    // Final timestamp
+    char date[80];
+    time_t the_real_now_please_stand_up = time(nullptr);
+    strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up));
+    MYLOGD("dumpstate id %d finished around %s (%ld s)\n", ds.id_, date,
+           the_real_now_please_stand_up - ds.now_);
+
+    if (!ds.AddZipEntry(entry_name, tmp_path_)) {
         MYLOGE("Failed to add text entry to .zip file\n");
         return false;
     }
-    if (!add_text_zip_entry("main_entry.txt", bugreport_name)) {
+    if (!AddTextZipEntry("main_entry.txt", entry_name)) {
         MYLOGE("Failed to add main_entry.txt to .zip file\n");
         return false;
     }
 
-    int32_t err = zip_writer->Finish();
-    if (err) {
-        MYLOGE("zip_writer->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
+    // Add log file (which contains stderr output) to zip...
+    fprintf(stderr, "dumpstate_log.txt entry on zip file logged up to here\n");
+    if (!ds.AddZipEntry("dumpstate_log.txt", ds.log_path_.c_str())) {
+        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()));
+    fprintf(stderr, "\n");
+
+    int32_t err = zip_writer_->Finish();
+    if (err != 0) {
+        MYLOGE("zip_writer_->Finish(): %s\n", ZipWriter::ErrorCodeString(err));
         return false;
     }
 
-    if (is_user_build()) {
-        MYLOGD("Removing temporary file %s\n", bugreport_path.c_str())
-        if (remove(bugreport_path.c_str())) {
-            ALOGW("remove(%s): %s\n", bugreport_path.c_str(), strerror(errno));
-        }
-    } else {
-        MYLOGD("Keeping temporary file %s on non-user build\n", bugreport_path.c_str())
+    // TODO: remove once FinishZipFile() is automatically handled by Dumpstate's destructor.
+    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));
     }
 
     return true;
 }
 
 static std::string SHA256_file_hash(std::string filepath) {
-    ScopedFd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC
-            | O_NOFOLLOW)));
-    if (fd.get() == -1) {
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
+            | O_CLOEXEC | O_NOFOLLOW)));
+    if (fd == -1) {
         MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
         return NULL;
     }
 
     SHA256_CTX ctx;
-    SHA256_init(&ctx);
+    SHA256_Init(&ctx);
 
     std::vector<uint8_t> buffer(65536);
     while (1) {
@@ -1304,21 +1330,48 @@
             return NULL;
         }
 
-        SHA256_update(&ctx, buffer.data(), bytes_read);
+        SHA256_Update(&ctx, buffer.data(), bytes_read);
     }
 
-    uint8_t hash[SHA256_DIGEST_SIZE];
-    memcpy(hash, SHA256_final(&ctx), SHA256_DIGEST_SIZE);
-    char hash_buffer[SHA256_DIGEST_SIZE * 2 + 1];
-    for(size_t i = 0; i < SHA256_DIGEST_SIZE; i++) {
+    uint8_t hash[SHA256_DIGEST_LENGTH];
+    SHA256_Final(hash, &ctx);
+
+    char hash_buffer[SHA256_DIGEST_LENGTH * 2 + 1];
+    for(size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
         sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
     }
     hash_buffer[sizeof(hash_buffer) - 1] = 0;
     return std::string(hash_buffer);
 }
 
+static void SendBroadcast(const std::string& action, const std::vector<std::string>& args) {
+    // clang-format off
+    std::vector<std::string> am = {"/system/bin/cmd", "activity", "broadcast", "--user", "0",
+                    "--receiver-foreground", "--receiver-include-background", "-a", action};
+    // clang-format on
+
+    am.insert(am.end(), args.begin(), args.end());
+
+    RunCommand("", am,
+               CommandOptions::WithTimeout(20)
+                   .Log("Sending broadcast: '%s'\n")
+                   .Always()
+                   .DropRoot()
+                   .RedirectStderr()
+                   .Build());
+}
+
+static void Vibrate(int duration_ms) {
+    // clang-format off
+    RunCommand("", {"cmd", "vibrator", "vibrate", std::to_string(duration_ms), "dumpstate"},
+               CommandOptions::WithTimeout(10)
+                   .Log("Vibrate: '%s'\n")
+                   .Always()
+                   .Build());
+    // clang-format on
+}
+
 int main(int argc, char *argv[]) {
-    struct sigaction sigact;
     int do_add_date = 0;
     int do_zip_file = 0;
     int do_vibrate = 1;
@@ -1327,33 +1380,15 @@
     int use_control_socket = 0;
     int do_fb = 0;
     int do_broadcast = 0;
-    int do_early_screenshot = 0;
     int is_remote_mode = 0;
+    bool show_header_only = false;
+    bool do_start_service = false;
     bool telephony_only = false;
 
-    std::string version = VERSION_DEFAULT;
-
-    now = time(NULL);
-
-    MYLOGI("begin\n");
-
-    /* gets the sequential id */
-    char last_id[PROPERTY_VALUE_MAX];
-    property_get("dumpstate.last_id", last_id, "0");
-    id = strtoul(last_id, NULL, 10) + 1;
-    snprintf(last_id, sizeof(last_id), "%lu", id);
-    property_set("dumpstate.last_id", last_id);
-    MYLOGI("dumpstate id: %lu\n", id);
-
-    /* clear SIGPIPE handler */
-    memset(&sigact, 0, sizeof(sigact));
-    sigact.sa_handler = sigpipe_handler;
-    sigaction(SIGPIPE, &sigact, NULL);
-
     /* set as high priority, and protect from OOM killer */
     setpriority(PRIO_PROCESS, 0, -20);
 
-    FILE *oom_adj = fopen("/proc/self/oom_score_adj", "we");
+    FILE* oom_adj = fopen("/proc/self/oom_score_adj", "we");
     if (oom_adj) {
         fputs("-1000", oom_adj);
         fclose(oom_adj);
@@ -1367,60 +1402,146 @@
     }
 
     /* parse arguments */
-    std::string args;
-    format_args(argc, const_cast<const char **>(argv), &args);
-    MYLOGD("Dumpstate command line: %s\n", args.c_str());
     int c;
-    while ((c = getopt(argc, argv, "dho:svqzptPBRSV:")) != -1) {
+    while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
         switch (c) {
-            case 'd': do_add_date = 1;          break;
-            case 't': telephony_only = true;    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': break;  // compatibility no-op
-            case 'q': do_vibrate = 0;           break;
-            case 'p': do_fb = 1;                break;
-            case 'P': do_update_progress = 1;   break;
-            case 'R': is_remote_mode = 1;       break;
-            case 'B': do_broadcast = 1;         break;
-            case 'V': version = optarg;         break;
-            case '?': printf("\n");
+            // 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':
-                usage();
-                exit(1);
+                ShowUsageAndExit(0);
+                break;
+            default:
+                fprintf(stderr, "Invalid option: %c\n", c);
+                ShowUsageAndExit();
+                // clang-format on
         }
     }
 
-    if ((do_zip_file || do_add_date || do_update_progress || do_broadcast) && !use_outfile) {
-        usage();
-        exit(1);
+    // 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") {
+            ds.update_progress_ = true;
+        } else if (ds.extra_options_ == "bugreporttelephony") {
+            telephony_only = true;
+        } 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) {
-        usage();
+        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) {
+        MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
+               ds.version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
+               VERSION_SPLIT_ANR.c_str());
         exit(1);
     }
 
-    if (do_update_progress && !do_broadcast) {
-        usage();
-        exit(1);
+    if (show_header_only) {
+        ds.PrintHeader();
+        exit(0);
     }
 
-    if (is_remote_mode && (do_update_progress || !do_broadcast || !do_zip_file || !do_add_date)) {
-        usage();
-        exit(1);
+    /* redirect output if needed */
+    bool is_redirecting = !use_socket && use_outfile;
+
+    // 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));
+
+    /* gets the sequential id */
+    uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
+    ds.id_ = ++last_id;
+    android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
+
+    MYLOGI("begin\n");
+
+    register_sig_handler();
+
+    if (do_start_service) {
+        MYLOGI("Starting 'dumpstate' service\n");
+        android::status_t ret;
+        if ((ret = android::os::DumpstateService::Start()) != android::OK) {
+            MYLOGE("Unable to start DumpstateService: %d\n", ret);
+        }
     }
 
-    if (version != VERSION_DEFAULT) {
-      usage();
-      exit(1);
+    if (PropertiesHelper::IsDryRun()) {
+        MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
     }
 
-    MYLOGI("bugreport format version: %s\n", version.c_str());
+    MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", ds.id_, ds.args_.c_str(),
+           ds.extra_options_.c_str());
 
-    do_early_screenshot = do_update_progress;
+    MYLOGI("bugreport format version: %s\n", ds.version_.c_str());
+
+    ds.do_early_screenshot_ = ds.update_progress_;
 
     // If we are going to use a socket, do it as early as possible
     // to avoid timeouts from bugreport.
@@ -1430,98 +1551,74 @@
 
     if (use_control_socket) {
         MYLOGD("Opening control socket\n");
-        control_socket_fd = open_socket("dumpstate");
-        do_update_progress = 1;
+        ds.control_socket_fd_ = open_socket("dumpstate");
+        ds.update_progress_ = 1;
     }
 
-    /* full path of the temporary file containing the bugreport */
-    std::string tmp_path;
-
-    /* full path of the file containing the dumpstate logs*/
-    std::string log_path;
-
-    /* full path of the systrace file, when enabled */
-    std::string systrace_path;
-
-    /* full path of the temporary file containing the screenshot (when requested) */
-    std::string screenshot_path;
-
-    /* base name (without suffix or extensions) of the bugreport files */
-    std::string base_name;
-
-    /* pointer to the actual path, be it zip or text */
-    std::string path;
-
-    /* pointer to the zipped file */
-    std::unique_ptr<FILE, int(*)(FILE*)> zip_file(NULL, fclose);
-
-    /* redirect output if needed */
-    bool is_redirecting = !use_socket && use_outfile;
-
     if (is_redirecting) {
-        bugreport_dir = dirname(use_outfile);
-        base_name = basename(use_outfile);
+        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(&now));
-            suffix = date;
+            strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
+            ds.name_ = date;
         } else {
-            suffix = "undated";
+            ds.name_ = "undated";
         }
-        char build_id[PROPERTY_VALUE_MAX];
-        property_get("ro.build.id", build_id, "UNKNOWN_BUILD");
-        base_name = base_name + "-" + build_id;
-        if (telephony_only) {
-            base_name = base_name + "-telephony";
-        }
-        if (do_fb) {
-            // TODO: if dumpstate was an object, the paths could be internal variables and then
-            // we could have a function to calculate the derived values, such as:
-            //     screenshot_path = GetPath(".png");
-            screenshot_path = bugreport_dir + "/" + base_name + "-" + suffix + ".png";
-        }
-        tmp_path = bugreport_dir + "/" + base_name + "-" + suffix + ".tmp";
-        log_path = bugreport_dir + "/dumpstate_log-" + suffix + "-"
-                + std::to_string(getpid()) + ".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",
-                bugreport_dir.c_str(), base_name.c_str(), suffix.c_str(),
-                log_path.c_str(), tmp_path.c_str(), screenshot_path.c_str());
+        if (telephony_only) {
+            ds.base_name_ += "-telephony";
+        }
+
+        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) {
-            path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
-            MYLOGD("Creating initial .zip file (%s)\n", path.c_str());
-            create_parent_dirs(path.c_str());
-            zip_file.reset(fopen(path.c_str(), "wb"));
-            if (!zip_file) {
-                MYLOGE("fopen(%s, 'wb'): %s\n", path.c_str(), strerror(errno));
+            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 {
-                zip_writer.reset(new ZipWriter(zip_file.get()));
+                ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
             }
-            add_text_zip_entry("version.txt", version);
+            ds.AddTextZipEntry("version.txt", ds.version_);
         }
 
-        if (do_update_progress) {
+        if (ds.update_progress_) {
             if (do_broadcast) {
                 // clang-format off
+
                 std::vector<std::string> am_args = {
-                     "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
-                     "--es", "android.intent.extra.NAME", suffix,
-                     "--ei", "android.intent.extra.ID", std::to_string(id),
-                     "--ei", "android.intent.extra.PID", std::to_string(getpid()),
-                     "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL),
+                     "--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()),
                 };
                 // clang-format on
-                send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args);
+                SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
             }
             if (use_control_socket) {
-                dprintf(control_socket_fd, "BEGIN:%s\n", path.c_str());
+                dprintf(ds.control_socket_fd_, "BEGIN:%s\n", ds.path_.c_str());
             }
         }
     }
@@ -1533,66 +1630,61 @@
         fclose(cmdline);
     }
 
-    /* open the vibrator before dropping root */
-    std::unique_ptr<FILE, int(*)(FILE*)> vibrator(NULL, fclose);
     if (do_vibrate) {
-        vibrator.reset(fopen("/sys/class/timed_output/vibrator/enable", "we"));
-        if (vibrator) {
-            vibrate(vibrator.get(), 150);
-        }
+        Vibrate(150);
     }
 
-    if (do_fb && do_early_screenshot) {
-        if (screenshot_path.empty()) {
+    if (do_fb && ds.do_early_screenshot_) {
+        if (ds.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");
-            take_screenshot(screenshot_path);
-            MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
-            if (chown(screenshot_path.c_str(), AID_SHELL, AID_SHELL)) {
-                MYLOGE("Unable to change ownership of screenshot file %s: %s\n",
-                        screenshot_path.c_str(), strerror(errno));
-            }
+            ds.TakeScreenshot();
         }
     }
 
     if (do_zip_file) {
-        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));
+        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(),
+                   strerror(errno));
         }
     }
 
     if (is_redirecting) {
-        redirect_to_file(stderr, const_cast<char*>(log_path.c_str()));
-        if (chown(log_path.c_str(), AID_SHELL, AID_SHELL)) {
+        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",
-                    log_path.c_str(), strerror(errno));
+                   ds.log_path_.c_str(), strerror(errno));
         }
         /* 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*>(tmp_path.c_str()));
-        if (chown(tmp_path.c_str(), AID_SHELL, AID_SHELL)) {
+        redirect_to_file(stdout, const_cast<char*>(ds.tmp_path_.c_str()));
+        if (chown(ds.tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
             MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
-                    tmp_path.c_str(), strerror(errno));
+                   ds.tmp_path_.c_str(), strerror(errno));
         }
     }
+
+    // Don't buffer stdout
+    setvbuf(stdout, nullptr, _IONBF, 0);
+
     // 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.
-    print_header(version);
+    ds.PrintHeader();
 
     if (telephony_only) {
-        dump_iptables();
-        if (!drop_root_user()) {
+        DumpIpTables();
+        if (!DropRootUser()) {
             return -1;
         }
         do_dmesg();
-        do_logcat();
-        do_kmsg();
-        dumpstate_board();
-        dump_modem_logs();
+        DoLogcat();
+        DoKmsg();
+        ds.DumpstateBoard();
+        DumpModemLogs();
     } 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
@@ -1601,40 +1693,44 @@
             dump_systrace();
         }
 
-        // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
-        dump_raft();
-
         // Invoking the following dumpsys calls before dump_traces() to try and
         // keep the system stats as close to its initial state as possible.
-        run_command_as_shell("DUMPSYS MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "-a", NULL);
-        run_command_as_shell("DUMPSYS CPUINFO", 10, "dumpsys", "-t", "10", "cpuinfo", "-a", NULL);
+        RunDumpsys("DUMPSYS MEMINFO", {"meminfo", "-a"},
+                   CommandOptions::WithTimeout(90).DropRoot().Build());
+        RunDumpsys("DUMPSYS CPUINFO", {"cpuinfo", "-a"},
+                   CommandOptions::WithTimeout(10).DropRoot().Build());
+
+        // 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. */
         get_tombstone_fds(tombstone_data);
-        add_dir(RECOVERY_DIR, true);
-        add_dir(RECOVERY_DATA_DIR, true);
-        add_dir(LOGPERSIST_DATA_DIR, false);
-        if (!is_user_build()) {
-            add_dir(PROFILE_DATA_DIR_CUR, true);
-            add_dir(PROFILE_DATA_DIR_REF, true);
+        ds.AddDir(RECOVERY_DIR, true);
+        ds.AddDir(RECOVERY_DATA_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();
-        dump_iptables();
+        DumpIpTables();
 
         // Capture any IPSec policies in play.  No keys are exposed here.
-        run_command("IP XFRM POLICY", 10, "ip", "xfrm", "policy", nullptr);
+        RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"},
+                   CommandOptions::WithTimeout(10).Build());
 
         // Run ss as root so we can see socket marks.
-        run_command("DETAILED SOCKET STATE", 10, "ss", "-eionptu", NULL);
+        RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"},
+                   CommandOptions::WithTimeout(10).Build());
 
-        if (!drop_root_user()) {
+        if (!DropRootUser()) {
             return -1;
         }
 
-        dumpstate(do_early_screenshot ? "": screenshot_path, version);
+        dumpstate();
     }
 
     /* close output if needed */
@@ -1646,125 +1742,136 @@
     if (use_outfile) {
 
         /* check if user changed the suffix using system properties */
-        char key[PROPERTY_KEY_MAX];
-        char value[PROPERTY_VALUE_MAX];
-        snprintf(key, sizeof(key), "dumpstate.%d.name", getpid());
-        property_get(key, value, "");
+        std::string name = android::base::GetProperty(
+            android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
         bool change_suffix= false;
-        if (value[0]) {
+        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(value, valid_regex)) {
+            if (std::regex_match(name.c_str(), valid_regex)) {
                 change_suffix = true;
             } else {
-                MYLOGE("invalid suffix provided by user: %s\n", value);
+                MYLOGE("invalid suffix provided by user: %s\n", name.c_str());
             }
         }
         if (change_suffix) {
-            MYLOGI("changing suffix from %s to %s\n", suffix.c_str(), value);
-            suffix = value;
-            if (!screenshot_path.empty()) {
-                std::string new_screenshot_path =
-                        bugreport_dir + "/" + base_name + "-" + suffix + ".png";
-                if (rename(screenshot_path.c_str(), new_screenshot_path.c_str())) {
-                    MYLOGE("rename(%s, %s): %s\n", screenshot_path.c_str(),
-                            new_screenshot_path.c_str(), strerror(errno));
+            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 {
-                    screenshot_path = new_screenshot_path;
+                    ds.screenshot_path_ = new_screenshot_path;
                 }
             }
         }
 
         bool do_text_file = true;
         if (do_zip_file) {
-            std::string entry_name = base_name + "-" + suffix + ".txt";
-            MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str());
-            if (!finish_zip_file(entry_name, tmp_path, now)) {
+            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 = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
-                if (path != new_path) {
-                    MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str());
-                    if (rename(path.c_str(), new_path.c_str())) {
-                        MYLOGE("rename(%s, %s): %s\n", path.c_str(),
-                                new_path.c_str(), strerror(errno));
+                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 {
-                        path = new_path;
+                        ds.path_ = new_path;
                     }
                 }
             }
         }
         if (do_text_file) {
-            path = bugreport_dir + "/" + base_name + "-" + suffix + ".txt";
-            MYLOGD("Generating .txt bugreport at %s from %s\n", path.c_str(), tmp_path.c_str());
-            if (rename(tmp_path.c_str(), path.c_str())) {
-                MYLOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno));
-                path.clear();
+            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(control_socket_fd, "FAIL:could not create zip file, check %s "
-                        "for more details\n", log_path.c_str());
+                dprintf(ds.control_socket_fd_,
+                        "FAIL:could not create zip file, check %s "
+                        "for more details\n",
+                        ds.log_path_.c_str());
             } else {
-                dprintf(control_socket_fd, "OK:%s\n", path.c_str());
+                dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str());
             }
         }
     }
 
     /* vibrate a few but shortly times to let user know it's finished */
-    if (vibrator) {
-        for (int i = 0; i < 3; i++) {
-            vibrate(vibrator.get(), 75);
-            usleep((75 + 50) * 1000);
-        }
+    for (int i = 0; i < 3; i++) {
+        Vibrate(75);
+        usleep((75 + 50) * 1000);
     }
 
     /* tell activity manager we're done */
     if (do_broadcast) {
-        if (!path.empty()) {
-            MYLOGI("Final bugreport path: %s\n", path.c_str());
+        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", "--receiver-foreground",
-                 "--ei", "android.intent.extra.ID", std::to_string(id),
-                 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
-                 "--ei", "android.intent.extra.MAX", std::to_string(weight_total),
-                 "--es", "android.intent.extra.BUGREPORT", path,
-                 "--es", "android.intent.extra.DUMPSTATE_LOG", log_path
+                 "--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(screenshot_path);
+                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(path));
-                send_broadcast("android.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
+                am_args.push_back(SHA256_file_hash(ds.path_));
+                SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED",
+                              am_args);
             } else {
-                send_broadcast("android.intent.action.BUGREPORT_FINISHED", am_args);
+                SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
             }
         } else {
             MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
         }
     }
 
-    MYLOGD("Final progress: %d/%d (originally %d)\n", progress, weight_total, WEIGHT_TOTAL);
-    MYLOGI("done\n");
+    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_);
 
     if (is_redirecting) {
         fclose(stderr);
     }
 
-    if (use_control_socket && control_socket_fd != -1) {
-      MYLOGD("Closing control socket\n");
-      close(control_socket_fd);
+    if (use_control_socket && ds.control_socket_fd_ != -1) {
+        MYLOGD("Closing control socket\n");
+        close(ds.control_socket_fd_);
     }
 
     return 0;
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 514af59..f02303b 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -14,93 +14,341 @@
  * limitations under the License.
  */
 
-#ifndef _DUMPSTATE_H_
-#define _DUMPSTATE_H_
-
-/* When defined, skips the real dumps and just print the section headers.
-   Useful when debugging dumpstate itself. */
-//#define _DUMPSTATE_DRY_RUN_
-
-#ifdef _DUMPSTATE_DRY_RUN_
-#define ON_DRY_RUN_RETURN(X) return X
-#define ON_DRY_RUN(code) code
-#else
-#define ON_DRY_RUN_RETURN(X)
-#define ON_DRY_RUN(code)
-#endif
-
-#ifndef MYLOGD
-#define MYLOGD(...) fprintf(stderr, __VA_ARGS__); ALOGD(__VA_ARGS__);
-#endif
-
-#ifndef MYLOGI
-#define MYLOGI(...) fprintf(stderr, __VA_ARGS__); ALOGI(__VA_ARGS__);
-#endif
-
-#ifndef MYLOGE
-#define MYLOGE(...) fprintf(stderr, __VA_ARGS__); ALOGE(__VA_ARGS__);
-#endif
+#ifndef FRAMEWORK_NATIVE_CMD_DUMPSTATE_H_
+#define FRAMEWORK_NATIVE_CMD_DUMPSTATE_H_
 
 #include <time.h>
 #include <unistd.h>
 #include <stdbool.h>
 #include <stdio.h>
+
+#include <string>
 #include <vector>
 
-#define SU_PATH "/system/xbin/su"
+#include <android-base/macros.h>
+#include <ziparchive/zip_writer.h>
 
+#include "DumpstateUtil.h"
+#include "android/os/BnDumpstate.h"
+
+// Workaround for const char *args[MAX_ARGS_ARRAY_SIZE] variables until they're converted to
+// std::vector<std::string>
+// TODO: remove once not used
+#define MAX_ARGS_ARRAY_SIZE 1000
+
+// TODO: move everything under this namespace
+// TODO: and then remove explicitly android::os::dumpstate:: prefixes
+namespace android {
+namespace os {
+namespace dumpstate {
+
+class DumpstateTest;
+class ProgressTest;
+
+}  // namespace dumpstate
+}  // namespace os
+}  // namespace android
+
+// TODO: remove once moved to HAL
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-typedef void (for_each_pid_func)(int, const char *);
-typedef void (for_each_tid_func)(int, int, const char *);
-
-/* Estimated total weight of bugreport generation.
+/*
+ * Helper class used to report how long it takes for a section to finish.
  *
- * Each section contributes to the total weight by an individual weight, so the overall progress
- * can be calculated by dividing the all completed weight by the total weight.
+ * Typical usage:
  *
- * This value is defined empirically and it need to be adjusted as more sections are added.
+ *    DurationReporter duration_reporter(title);
  *
- * It does not need to match the exact sum of all sections, but ideally it should to be slight more
- * than such sum: a value too high will cause the bugreport to finish before the user expected (for
- * example, jumping from 70% to 100%), while a value too low will cause the progress to get stuck
- * at an almost-finished value (like 99%) for a while.
  */
-static const int WEIGHT_TOTAL = 6500;
+class DurationReporter {
+  public:
+    DurationReporter(const std::string& title, bool log_only = false);
 
-/* Most simple commands have 10 as timeout, so 5 is a good estimate */
-static const int WEIGHT_FILE = 5;
+    ~DurationReporter();
+
+  private:
+    std::string title_;
+    bool log_only_;
+    uint64_t started_;
+
+    DISALLOW_COPY_AND_ASSIGN(DurationReporter);
+};
 
 /*
- * TODO: the dumpstate internal state is getting fragile; for example, this variable is defined
- * here, declared at utils.cpp, and used on utils.cpp and dumpstate.cpp.
- * It would be better to take advantage of the C++ migration and encapsulate the state in an object,
- * but that will be better handled in a major C++ refactoring, which would also get rid of other C
- * idioms (like using std::string instead of char*, removing varargs, etc...) */
-extern int do_update_progress, progress, weight_total, control_socket_fd;
+ * Keeps track of current progress and estimated max, saving stats on file to tune up future runs.
+ *
+ * Each `dumpstate` section contributes to the total weight by an individual weight, so the overall
+ * progress can be calculated by dividing the estimate max progress by the current progress.
+ *
+ * The estimated max progress is initially set to a value (`kDefaultMax) defined empirically, but
+ * it's adjusted after each dumpstate run by storing the average duration in a file.
+ *
+ */
+class Progress {
+    friend class android::os::dumpstate::ProgressTest;
+    friend class android::os::dumpstate::DumpstateTest;
 
-/* full path of the directory where the bugreport files will be written */
-extern std::string bugreport_dir;
+  public:
+    /*
+     * Default estimation of the max duration of a bugreport generation.
+     *
+     * It does not need to match the exact sum of all sections, but ideally it should to be slight
+     * more than such sum: a value too high will cause the bugreport to finish before the user
+     * expected (for example, jumping from 70% to 100%), while a value too low will cause the
+     * progress to get stuck at an almost-finished value (like 99%) for a while.
+     *
+     * This constant is only used when the average duration from previous runs cannot be used.
+     */
+    static const int kDefaultMax;
 
-/* root dir for all files copied as-is into the bugreport. */
-extern const std::string ZIP_ROOT_DIR;
+    Progress(const std::string& path = "");
 
-/* Checkes whether dumpstate is generating a zipped bugreport. */
-bool is_zipping();
+    // Gets the current progress.
+    int32_t Get() const;
 
-/* adds a new entry to the existing zip file. */
-bool add_zip_entry(const std::string& entry_name, const std::string& entry_path);
+    // Gets the current estimated max progress.
+    int32_t GetMax() const;
 
-/* adds a new entry to the existing zip file. */
-bool add_zip_entry_from_fd(const std::string& entry_name, int fd);
+    // Gets the initial estimated max progress.
+    int32_t GetInitialMax() const;
 
-/* adds all files from a directory to the zipped bugreport file */
-void add_dir(const char *dir, bool recursive);
+    // Increments progress (ignored if not positive).
+    // Returns `true` if the max progress increased as well.
+    bool Inc(int32_t delta);
 
-/* prints the contents of a file */
-int dump_file(const char *title, const char *path);
+    // Persist the stats.
+    void Save();
+
+    void Dump(int fd, const std::string& prefix) const;
+
+  private:
+    Progress(int32_t initial_max, float growth_factor,
+             const std::string& path = "");                                // Used by test cases.
+    Progress(int32_t initial_max, int32_t progress, float growth_factor);  // Used by test cases.
+    void Load();
+    int32_t initial_max_;
+    int32_t progress_;
+    int32_t max_;
+    float growth_factor_;
+    int32_t n_runs_;
+    int32_t average_max_;
+    const std::string& path_;
+};
+
+/*
+ * List of supported zip format versions.
+ *
+ * See bugreport-format.md for more info.
+ */
+static std::string VERSION_CURRENT = "1.0";
+
+/*
+ * Temporary version that adds a anr-traces.txt entry. Once tools support it, the current version
+ * will be bumped to 2.0-dev-1.
+ */
+static std::string VERSION_SPLIT_ANR = "2.0-dev-1";
+
+/*
+ * "Alias" for the current version.
+ */
+static std::string VERSION_DEFAULT = "default";
+
+/*
+ * Main class driving a bugreport generation.
+ *
+ * Currently, it only contains variables that are accessed externally, but gradually the functions
+ * that are spread accross utils.cpp and dumpstate.cpp will be moved to it.
+ */
+class Dumpstate {
+    friend class DumpstateTest;
+
+  public:
+    static android::os::dumpstate::CommandOptions DEFAULT_DUMPSYS;
+
+    static Dumpstate& GetInstance();
+
+    /* Checkes whether dumpstate is generating a zipped bugreport. */
+    bool IsZipping() const;
+
+    /*
+     * Forks a command, waits for it to finish, and returns its status.
+     *
+     * |title| description of the command printed on `stdout` (or empty to skip
+     * description).
+     * |full_command| array containing the command (first entry) and its arguments.
+     * Must contain at least one element.
+     * |options| optional argument defining the command's behavior.
+     */
+    int RunCommand(const std::string& title, const std::vector<std::string>& fullCommand,
+                   const android::os::dumpstate::CommandOptions& options =
+                       android::os::dumpstate::CommandOptions::DEFAULT);
+
+    /*
+     * Runs `dumpsys` with the given arguments, automatically setting its timeout
+     * (`-t` argument)
+     * according to the command options.
+     *
+     * |title| description of the command printed on `stdout` (or empty to skip
+     * description).
+     * |dumpsys_args| `dumpsys` arguments (except `-t`).
+     * |options| optional argument defining the command's behavior.
+     * |dumpsys_timeout| when > 0, defines the value passed to `dumpsys -t` (otherwise it uses the
+     * timeout from `options`)
+     */
+    void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
+                    const android::os::dumpstate::CommandOptions& options = DEFAULT_DUMPSYS,
+                    long dumpsys_timeout = 0);
+
+    /*
+     * Prints the contents of a file.
+     *
+     * |title| description of the command printed on `stdout` (or empty to skip
+     * description).
+     * |path| location of the file to be dumped.
+     */
+    int DumpFile(const std::string& title, const std::string& path);
+
+    /*
+     * Adds a new entry to the existing zip file.
+     * */
+    bool AddZipEntry(const std::string& entry_name, const std::string& entry_path);
+
+    /*
+     * Adds a new entry to the existing zip file.
+     */
+    bool AddZipEntryFromFd(const std::string& entry_name, int fd);
+
+    /*
+     * Adds a text entry entry to the existing zip file.
+     */
+    bool AddTextZipEntry(const std::string& entry_name, const std::string& content);
+
+    /*
+     * Adds all files from a directory to the zipped bugreport file.
+     */
+    void AddDir(const std::string& dir, bool recursive);
+
+    /*
+     * Takes a screenshot and save it to the given `path`.
+     *
+     * If `path` is empty, uses a standard path based on the bugreport name.
+     */
+    void TakeScreenshot(const std::string& path = "");
+
+    /////////////////////////////////////////////////////////////////////
+    // TODO: members below should be private once refactor is finished //
+    /////////////////////////////////////////////////////////////////////
+
+    // TODO: temporary method until Dumpstate object is properly set
+    void SetProgress(std::unique_ptr<Progress> progress);
+
+    void DumpstateBoard();
+
+    /*
+     * Updates the overall progress of the bugreport generation by the given weight increment.
+     */
+    void UpdateProgress(int32_t delta);
+
+    /* Prints the dumpstate header on `stdout`. */
+    void PrintHeader() const;
+
+    /*
+     * Adds the temporary report to the existing .zip file, closes the .zip file, and removes the
+     * temporary file.
+     */
+    bool FinishZipFile();
+
+    /* Gets the path of a bugreport file with the given suffix. */
+    std::string GetPath(const std::string& suffix) const;
+
+    // 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;
+
+    // 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.
+    int32_t update_progress_threshold_ = 100;
+
+    // Last progress that triggered a listener updated
+    int32_t last_updated_progress_;
+
+    // Whether it should take an screenshot earlier in the process.
+    bool do_early_screenshot_ = false;
+
+    std::unique_ptr<Progress> progress_;
+
+    // When set, defines a socket file-descriptor use to report progress to bugreportz.
+    int control_socket_fd_ = -1;
+
+    // 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
+    // `bugreport-BUILD_ID`.
+    std::string base_name_;
+
+    // Name is the suffix part of the bugreport files - it's typically the date (when invoked with
+    // `-d`), but it could be changed by the user..
+    std::string name_;
+
+    // Full path of the temporary file containing the bugreport.
+    std::string tmp_path_;
+
+    // Full path of the file containing the dumpstate logs.
+    std::string log_path_;
+
+    // Pointer to the actual path, be it zip or text.
+    std::string path_;
+
+    // Pointer to the zipped file.
+    std::unique_ptr<FILE, int (*)(FILE*)> zip_file{nullptr, fclose};
+
+    // Pointer to the zip structure.
+    std::unique_ptr<ZipWriter> zip_writer_;
+
+    // Binder object listing to progress.
+    android::sp<android::os::IDumpstateListener> listener_;
+    std::string listener_name_;
+
+    // Notification title and description
+    std::string notification_title;
+    std::string notification_description;
+
+  private:
+    // Used by GetInstance() only.
+    Dumpstate(const std::string& version = VERSION_CURRENT);
+
+    DISALLOW_COPY_AND_ASSIGN(Dumpstate);
+};
+
+// for_each_pid_func = void (*)(int, const char*);
+// for_each_tid_func = void (*)(int, int, const char*);
+
+typedef void(for_each_pid_func)(int, const char*);
+typedef void(for_each_tid_func)(int, int, const char*);
 
 /* saves the the contents of a file as a long */
 int read_file_as_long(const char *path, long int *output);
@@ -116,37 +364,8 @@
  * to false when set to NULL. dump_from_fd will always be
  * called with title NULL.
  */
-int dump_files(const char *title, const char *dir,
-        bool (*skip)(const char *path),
-        int (*dump_from_fd)(const char *title, const char *path, int fd));
-
-// TODO: need to refactor all those run_command variations; there shold be just one, receiving an
-// optional CommandOptions objects with values such as run_always, drop_root, etc...
-
-/* forks a command and waits for it to finish -- terminate args with NULL */
-int run_command_as_shell(const char *title, int timeout_seconds, const char *command, ...);
-int run_command(const char *title, int timeout_seconds, const char *command, ...);
-
-enum RootMode { DROP_ROOT, DONT_DROP_ROOT };
-enum StdoutMode { NORMAL_STDOUT, REDIRECT_TO_STDERR };
-
-/* forks a command and waits for it to finish
-   first element of args is the command, and last must be NULL.
-   command is always ran, even when _DUMPSTATE_DRY_RUN_ is defined. */
-int run_command_always(const char *title, RootMode root_mode, StdoutMode stdout_mode,
-        int timeout_seconds, const char *args[]);
-
-/* switch to non-root user and group */
-bool drop_root_user();
-
-/* sends a broadcast using Activity Manager */
-void send_broadcast(const std::string& action, const std::vector<std::string>& args);
-
-/* updates the overall progress of dumpstate by the given weight increment */
-void update_progress(int weight);
-
-/* prints all the system properties */
-void print_properties();
+int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path),
+               int (*dump_from_fd)(const char* title, const char* path, int fd));
 
 /** opens a socket and returns its file descriptor */
 int open_socket(const char *service);
@@ -154,9 +373,12 @@
 /* redirect output to a service control socket */
 void redirect_to_socket(FILE *redirect, const char *service);
 
-/* redirect output to a file */
+/* redirect output to a new file */
 void redirect_to_file(FILE *redirect, char *path);
 
+/* redirect output to an existing file */
+void redirect_to_existing_file(FILE *redirect, char *path);
+
 /* create leading directories, if necessary */
 void create_parent_dirs(const char *path);
 
@@ -187,15 +409,6 @@
 /* Play a sound via Stagefright */
 void play_sound(const char *path);
 
-/* Implemented by libdumpstate_board to dump board-specific info */
-void dumpstate_board();
-
-/* Takes a screenshot and save it to the given file */
-void take_screenshot(const std::string& path);
-
-/* Vibrates for a given durating (in milliseconds). */
-void vibrate(FILE* vibrator, int ms);
-
 /* Checks if a given path is a directory. */
 bool is_dir(const char* pathname);
 
@@ -208,34 +421,8 @@
 /** Gets command-line arguments. */
 void format_args(int argc, const char *argv[], std::string *args);
 
-/** Tells if the device is running a user build. */
-bool is_user_build();
-
-/*
- * Helper class used to report how long it takes for a section to finish.
- *
- * Typical usage:
- *
- *    DurationReporter duration_reporter(title);
- *
- */
-class DurationReporter {
-public:
-    DurationReporter(const char *title);
-    DurationReporter(const char *title, FILE* out);
-
-    ~DurationReporter();
-
-    static uint64_t nanotime();
-
-private:
-    const char* title_;
-    FILE* out_;
-    uint64_t started_;
-};
-
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* _DUMPSTATE_H_ */
+#endif /* FRAMEWORK_NATIVE_CMD_DUMPSTATE_H_ */
diff --git a/cmds/dumpstate/dumpstate.rc b/cmds/dumpstate/dumpstate.rc
index 336db9f..2e72574 100644
--- a/cmds/dumpstate/dumpstate.rc
+++ b/cmds/dumpstate/dumpstate.rc
@@ -17,40 +17,3 @@
     class main
     disabled
     oneshot
-
-# bugreportplus is an enhanced version of bugreport that provides a better
-# user interface (like displaying progress and allowing user to enter details).
-# It's typically triggered by the power button or developer settings.
-service bugreportplus /system/bin/dumpstate -d -B -P -z \
-        -o /data/user_de/0/com.android.shell/files/bugreports/bugreport
-    class main
-    disabled
-    oneshot
-
-# bugreportremote is an altered version of bugreport that is supposed to be
-# called not by human user of the device, but by DevicePolicyManagerService only when the
-# Device Owner explicitly requests it, and shared with the Device Policy Controller (DPC) app only
-# if the user consents
-# it will disable vibrations, screenshot taking and will not track progress or
-# allow user to enter any details
-service bugreportremote /system/bin/dumpstate -d -q -B -R -z \
-        -o /data/user_de/0/com.android.shell/files/bugreports/remote/bugreport
-    class main
-    disabled
-    oneshot
-
-# bugreportwear is a wearable version of bugreport that displays progress and takes early
-# screenshot.
-service bugreportwear /system/bin/dumpstate -d -B -P -p -z \
-        -o /data/user_de/0/com.android.shell/files/bugreports/bugreport
-    class main
-    disabled
-    oneshot
-
-# bugreportelefony is a lightweight version of bugreport that only includes a few, urgent
-# sections used to report telephony bugs.
-service bugreportelefony /system/bin/dumpstate -t -d -B -z \
-        -o /data/user_de/0/com.android.shell/files/bugreports/bugreport
-    class main
-    disabled
-    oneshot
diff --git a/cmds/dumpstate/libdumpstate_default.cpp b/cmds/dumpstate/libdumpstate_default.cpp
deleted file mode 100644
index fd840df..0000000
--- a/cmds/dumpstate/libdumpstate_default.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 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 "dumpstate.h"
-
-void dumpstate_board(void)
-{
-}
-
diff --git a/cmds/dumpstate/testdata/empty-file.txt b/cmds/dumpstate/testdata/empty-file.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cmds/dumpstate/testdata/empty-file.txt
diff --git a/cmds/dumpstate/testdata/multiple-lines-with-newline.txt b/cmds/dumpstate/testdata/multiple-lines-with-newline.txt
new file mode 100644
index 0000000..7b7a187
--- /dev/null
+++ b/cmds/dumpstate/testdata/multiple-lines-with-newline.txt
@@ -0,0 +1,3 @@
+I AM LINE1
+I AM LINE2
+I AM LINE3
diff --git a/cmds/dumpstate/testdata/multiple-lines.txt b/cmds/dumpstate/testdata/multiple-lines.txt
new file mode 100644
index 0000000..bead103
--- /dev/null
+++ b/cmds/dumpstate/testdata/multiple-lines.txt
@@ -0,0 +1,3 @@
+I AM LINE1
+I AM LINE2
+I AM LINE3
\ No newline at end of file
diff --git a/cmds/dumpstate/testdata/single-line-with-newline.txt b/cmds/dumpstate/testdata/single-line-with-newline.txt
new file mode 100644
index 0000000..cb48c82
--- /dev/null
+++ b/cmds/dumpstate/testdata/single-line-with-newline.txt
@@ -0,0 +1 @@
+I AM LINE1
diff --git a/cmds/dumpstate/testdata/single-line.txt b/cmds/dumpstate/testdata/single-line.txt
new file mode 100644
index 0000000..2f64046
--- /dev/null
+++ b/cmds/dumpstate/testdata/single-line.txt
@@ -0,0 +1 @@
+I AM LINE1
\ No newline at end of file
diff --git a/cmds/dumpstate/testdata/stats-invalid-1st-NAN.txt b/cmds/dumpstate/testdata/stats-invalid-1st-NAN.txt
new file mode 100644
index 0000000..dad9fe8
--- /dev/null
+++ b/cmds/dumpstate/testdata/stats-invalid-1st-NAN.txt
@@ -0,0 +1 @@
+SIX_SIX_SIX 42
diff --git a/cmds/dumpstate/testdata/stats-invalid-1st-negative.txt b/cmds/dumpstate/testdata/stats-invalid-1st-negative.txt
new file mode 100644
index 0000000..4facef9
--- /dev/null
+++ b/cmds/dumpstate/testdata/stats-invalid-1st-negative.txt
@@ -0,0 +1 @@
+-666 42
diff --git a/cmds/dumpstate/testdata/stats-invalid-1st-too-big.txt b/cmds/dumpstate/testdata/stats-invalid-1st-too-big.txt
new file mode 100644
index 0000000..42508f1
--- /dev/null
+++ b/cmds/dumpstate/testdata/stats-invalid-1st-too-big.txt
@@ -0,0 +1 @@
+4815162342 42
diff --git a/cmds/dumpstate/testdata/stats-invalid-2nd-NAN.txt b/cmds/dumpstate/testdata/stats-invalid-2nd-NAN.txt
new file mode 100644
index 0000000..a23ba2c
--- /dev/null
+++ b/cmds/dumpstate/testdata/stats-invalid-2nd-NAN.txt
@@ -0,0 +1 @@
+666 FORTY_TWO
diff --git a/cmds/dumpstate/testdata/stats-invalid-2nd-negative.txt b/cmds/dumpstate/testdata/stats-invalid-2nd-negative.txt
new file mode 100644
index 0000000..dd529b4
--- /dev/null
+++ b/cmds/dumpstate/testdata/stats-invalid-2nd-negative.txt
@@ -0,0 +1 @@
+666 -42
diff --git a/cmds/dumpstate/testdata/stats-invalid-2nd-too-big.txt b/cmds/dumpstate/testdata/stats-invalid-2nd-too-big.txt
new file mode 100644
index 0000000..b148b46
--- /dev/null
+++ b/cmds/dumpstate/testdata/stats-invalid-2nd-too-big.txt
@@ -0,0 +1 @@
+666 4815162342
diff --git a/cmds/dumpstate/testdata/stats-invalid-both-NAN.txt b/cmds/dumpstate/testdata/stats-invalid-both-NAN.txt
new file mode 100644
index 0000000..4a9466d
--- /dev/null
+++ b/cmds/dumpstate/testdata/stats-invalid-both-NAN.txt
@@ -0,0 +1 @@
+N_RUNS AVERAGE
\ No newline at end of file
diff --git a/cmds/dumpstate/testdata/stats-one-run-no-newline.txt b/cmds/dumpstate/testdata/stats-one-run-no-newline.txt
new file mode 100644
index 0000000..0aef60c
--- /dev/null
+++ b/cmds/dumpstate/testdata/stats-one-run-no-newline.txt
@@ -0,0 +1 @@
+1 10
\ No newline at end of file
diff --git a/cmds/dumpstate/testdata/stats-two-runs.txt b/cmds/dumpstate/testdata/stats-two-runs.txt
new file mode 100644
index 0000000..9af1233
--- /dev/null
+++ b/cmds/dumpstate/testdata/stats-two-runs.txt
@@ -0,0 +1 @@
+2 15
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
new file mode 100644
index 0000000..1c19268
--- /dev/null
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -0,0 +1,1157 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "dumpstate"
+#include <cutils/log.h>
+
+#include "DumpstateInternal.h"
+#include "DumpstateService.h"
+#include "android/os/BnDumpstate.h"
+#include "dumpstate.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <fcntl.h>
+#include <libgen.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <thread>
+
+#include <android-base/file.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+namespace android {
+namespace os {
+namespace dumpstate {
+
+using ::testing::EndsWith;
+using ::testing::HasSubstr;
+using ::testing::IsNull;
+using ::testing::IsEmpty;
+using ::testing::NotNull;
+using ::testing::StrEq;
+using ::testing::StartsWith;
+using ::testing::Test;
+using ::testing::internal::CaptureStderr;
+using ::testing::internal::CaptureStdout;
+using ::testing::internal::GetCapturedStderr;
+using ::testing::internal::GetCapturedStdout;
+
+class DumpstateListenerMock : public IDumpstateListener {
+  public:
+    MOCK_METHOD1(onProgressUpdated, binder::Status(int32_t progress));
+    MOCK_METHOD1(onMaxProgressUpdated, binder::Status(int32_t max_progress));
+
+  protected:
+    MOCK_METHOD0(onAsBinder, IBinder*());
+};
+
+static int calls_;
+
+// Base class for all tests in this file
+class DumpstateBaseTest : public Test {
+  public:
+    virtual void SetUp() override {
+        calls_++;
+        SetDryRun(false);
+    }
+
+    void SetDryRun(bool dry_run) const {
+        PropertiesHelper::dry_run_ = dry_run;
+    }
+
+    void SetBuildType(const std::string& build_type) const {
+        PropertiesHelper::build_type_ = build_type;
+    }
+
+    bool IsStandalone() const {
+        return calls_ == 1;
+    }
+
+    void DropRoot() const {
+        DropRootUser();
+        uid_t uid = getuid();
+        ASSERT_EQ(2000, (int)uid);
+    }
+
+  protected:
+    const std::string kTestPath = dirname(android::base::GetExecutablePath().c_str());
+    const std::string kFixturesPath = kTestPath + "/../dumpstate_test_fixture/";
+    const std::string kTestDataPath = kFixturesPath + "/testdata/";
+    const std::string kSimpleCommand = kFixturesPath + "dumpstate_test_fixture";
+    const std::string kEchoCommand = "/system/bin/echo";
+
+    /*
+     * Copies a text file fixture to a temporary file, returning it's path.
+     *
+     * Useful in cases where the test case changes the content of the tile.
+     */
+    std::string CopyTextFileFixture(const std::string& relative_name) {
+        std::string from = kTestDataPath + relative_name;
+        // Not using TemporaryFile because it's deleted at the end, and it's useful to keep it
+        // around for poking when the test fails.
+        std::string to = kTestDataPath + relative_name + ".tmp";
+        ALOGD("CopyTextFileFixture: from %s to %s\n", from.c_str(), to.c_str());
+        android::base::RemoveFileIfExists(to);
+        CopyTextFile(from, to);
+        return to.c_str();
+    }
+
+    // Need functions that returns void to use assertions -
+    // https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md#assertion-placement
+    void ReadFileToString(const std::string& path, std::string* content) {
+        ASSERT_TRUE(android::base::ReadFileToString(path, content))
+            << "could not read contents from " << path;
+    }
+    void WriteStringToFile(const std::string& content, const std::string& path) {
+        ASSERT_TRUE(android::base::WriteStringToFile(content, path))
+            << "could not write contents to " << path;
+    }
+
+  private:
+    void CopyTextFile(const std::string& from, const std::string& to) {
+        std::string content;
+        ReadFileToString(from, &content);
+        WriteStringToFile(content, to);
+    }
+};
+
+class DumpstateTest : public DumpstateBaseTest {
+  public:
+    void SetUp() {
+        DumpstateBaseTest::SetUp();
+        SetDryRun(false);
+        SetBuildType(android::base::GetProperty("ro.build.type", "(unknown)"));
+        ds.progress_.reset(new Progress());
+        ds.update_progress_ = false;
+        ds.update_progress_threshold_ = 0;
+    }
+
+    // Runs a command and capture `stdout` and `stderr`.
+    int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
+                   const CommandOptions& options = CommandOptions::DEFAULT) {
+        CaptureStdout();
+        CaptureStderr();
+        int status = ds.RunCommand(title, full_command, options);
+        out = GetCapturedStdout();
+        err = GetCapturedStderr();
+        return status;
+    }
+
+    // Dumps a file and capture `stdout` and `stderr`.
+    int DumpFile(const std::string& title, const std::string& path) {
+        CaptureStdout();
+        CaptureStderr();
+        int status = ds.DumpFile(title, path);
+        out = GetCapturedStdout();
+        err = GetCapturedStderr();
+        return status;
+    }
+
+    void SetProgress(long progress, long initial_max, long threshold = 0) {
+        ds.update_progress_ = true;
+        ds.update_progress_threshold_ = threshold;
+        ds.last_updated_progress_ = 0;
+        ds.progress_.reset(new Progress(initial_max, progress, 1.2));
+    }
+
+    std::string GetProgressMessage(const std::string& listener_name, int progress, int max,
+                                   int old_max = 0, bool update_progress = true) {
+        EXPECT_EQ(progress, ds.progress_->Get()) << "invalid progress";
+        EXPECT_EQ(max, ds.progress_->GetMax()) << "invalid max";
+
+        bool max_increased = old_max > 0;
+
+        std::string message = "";
+        if (max_increased) {
+            message =
+                android::base::StringPrintf("Adjusting max progress from %d to %d\n", old_max, max);
+        }
+
+        if (update_progress) {
+            message += android::base::StringPrintf("Setting progress (%s): %d/%d\n",
+                                                   listener_name.c_str(), progress, max);
+        }
+
+        return message;
+    }
+
+    // `stdout` and `stderr` from the last command ran.
+    std::string out, err;
+
+    Dumpstate& ds = Dumpstate::GetInstance();
+};
+
+TEST_F(DumpstateTest, RunCommandNoArgs) {
+    EXPECT_EQ(-1, RunCommand("", {}));
+}
+
+TEST_F(DumpstateTest, RunCommandNoTitle) {
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand}));
+    EXPECT_THAT(out, StrEq("stdout\n"));
+    EXPECT_THAT(err, StrEq("stderr\n"));
+}
+
+TEST_F(DumpstateTest, RunCommandWithTitle) {
+    EXPECT_EQ(0, RunCommand("I AM GROOT", {kSimpleCommand}));
+    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"));
+}
+
+TEST_F(DumpstateTest, RunCommandWithLoggingMessage) {
+    EXPECT_EQ(
+        0, RunCommand("", {kSimpleCommand},
+                      CommandOptions::WithTimeout(10).Log("COMMAND, Y U NO LOG FIRST?").Build()));
+    EXPECT_THAT(out, StrEq("stdout\n"));
+    EXPECT_THAT(err, StrEq("COMMAND, Y U NO LOG FIRST?stderr\n"));
+}
+
+TEST_F(DumpstateTest, RunCommandRedirectStderr) {
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand},
+                            CommandOptions::WithTimeout(10).RedirectStderr().Build()));
+    EXPECT_THAT(out, IsEmpty());
+    EXPECT_THAT(err, StrEq("stdout\nstderr\n"));
+}
+
+TEST_F(DumpstateTest, RunCommandWithOneArg) {
+    EXPECT_EQ(0, RunCommand("", {kEchoCommand, "one"}));
+    EXPECT_THAT(err, IsEmpty());
+    EXPECT_THAT(out, StrEq("one\n"));
+}
+
+TEST_F(DumpstateTest, RunCommandWithMultipleArgs) {
+    EXPECT_EQ(0, RunCommand("", {kEchoCommand, "one", "is", "the", "loniest", "number"}));
+    EXPECT_THAT(err, IsEmpty());
+    EXPECT_THAT(out, StrEq("one is the loniest number\n"));
+}
+
+TEST_F(DumpstateTest, RunCommandDryRun) {
+    SetDryRun(true);
+    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"));
+    EXPECT_THAT(err, IsEmpty());
+}
+
+TEST_F(DumpstateTest, RunCommandDryRunNoTitle) {
+    SetDryRun(true);
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand}));
+    EXPECT_THAT(out, IsEmpty());
+    EXPECT_THAT(err, IsEmpty());
+}
+
+TEST_F(DumpstateTest, RunCommandDryRunAlways) {
+    SetDryRun(true);
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(10).Always().Build()));
+    EXPECT_THAT(out, StrEq("stdout\n"));
+    EXPECT_THAT(err, StrEq("stderr\n"));
+}
+
+TEST_F(DumpstateTest, RunCommandNotFound) {
+    EXPECT_NE(0, RunCommand("", {"/there/cannot/be/such/command"}));
+    EXPECT_THAT(out, StartsWith("*** command '/there/cannot/be/such/command' failed: exit code"));
+    EXPECT_THAT(err, StartsWith("execvp on command '/there/cannot/be/such/command' failed"));
+}
+
+TEST_F(DumpstateTest, RunCommandFails) {
+    EXPECT_EQ(42, RunCommand("", {kSimpleCommand, "--exit", "42"}));
+    EXPECT_THAT(out, StrEq("stdout\n*** command '" + kSimpleCommand +
+                           " --exit 42' failed: exit code 42\n"));
+    EXPECT_THAT(err, StrEq("stderr\n*** command '" + kSimpleCommand +
+                           " --exit 42' failed: exit code 42\n"));
+}
+
+TEST_F(DumpstateTest, RunCommandCrashes) {
+    EXPECT_NE(0, RunCommand("", {kSimpleCommand, "--crash"}));
+    // We don't know the exit code, so check just the prefix.
+    EXPECT_THAT(
+        out, StartsWith("stdout\n*** command '" + kSimpleCommand + " --crash' failed: exit code"));
+    EXPECT_THAT(
+        err, StartsWith("stderr\n*** command '" + kSimpleCommand + " --crash' failed: exit code"));
+}
+
+TEST_F(DumpstateTest, RunCommandTimesout) {
+    EXPECT_EQ(-1, RunCommand("", {kSimpleCommand, "--sleep", "2"},
+                             CommandOptions::WithTimeout(1).Build()));
+    EXPECT_THAT(out, StartsWith("stdout line1\n*** command '" + kSimpleCommand +
+                                " --sleep 2' timed out after 1"));
+    EXPECT_THAT(err, StartsWith("sleeping for 2s\n*** command '" + kSimpleCommand +
+                                " --sleep 2' timed out after 1"));
+}
+
+TEST_F(DumpstateTest, RunCommandIsKilled) {
+    CaptureStdout();
+    CaptureStderr();
+
+    std::thread t([=]() {
+        EXPECT_EQ(SIGTERM, ds.RunCommand("", {kSimpleCommand, "--pid", "--sleep", "20"},
+                                         CommandOptions::WithTimeout(100).Always().Build()));
+    });
+
+    // Capture pid and pre-sleep output.
+    sleep(1);  // Wait a little bit to make sure pid and 1st line were printed.
+    std::string err = GetCapturedStderr();
+    EXPECT_THAT(err, StrEq("sleeping for 20s\n"));
+
+    std::string out = GetCapturedStdout();
+    std::vector<std::string> lines = android::base::Split(out, "\n");
+    ASSERT_EQ(3, (int)lines.size()) << "Invalid lines before sleep: " << out;
+
+    int pid = atoi(lines[0].c_str());
+    EXPECT_THAT(lines[1], StrEq("stdout line1"));
+    EXPECT_THAT(lines[2], IsEmpty());  // \n
+
+    // Then kill the process.
+    CaptureStdout();
+    CaptureStderr();
+    ASSERT_EQ(0, kill(pid, SIGTERM)) << "failed to kill pid " << pid;
+    t.join();
+
+    // Finally, check output after murder.
+    out = GetCapturedStdout();
+    err = GetCapturedStderr();
+
+    EXPECT_THAT(out, StrEq("*** command '" + kSimpleCommand +
+                           " --pid --sleep 20' failed: killed by signal 15\n"));
+    EXPECT_THAT(err, StrEq("*** command '" + kSimpleCommand +
+                           " --pid --sleep 20' failed: killed by signal 15\n"));
+}
+
+TEST_F(DumpstateTest, RunCommandProgress) {
+    sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
+    ds.listener_ = listener;
+    ds.listener_name_ = "FoxMulder";
+    SetProgress(0, 30);
+
+    EXPECT_CALL(*listener, onProgressUpdated(20));
+    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_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(10).Build()));
+    progress_message = GetProgressMessage(ds.listener_name_, 30, 30);
+    EXPECT_THAT(out, StrEq("stdout\n"));
+    EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
+
+    // Run a command that will increase maximum timeout.
+    EXPECT_CALL(*listener, onProgressUpdated(31));
+    EXPECT_CALL(*listener, onMaxProgressUpdated(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"));
+    EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
+
+    // Make sure command ran while in dry_run is counted.
+    SetDryRun(true);
+    EXPECT_CALL(*listener, onProgressUpdated(35));
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
+    progress_message = GetProgressMessage(ds.listener_name_, 35, 37);
+    EXPECT_THAT(out, IsEmpty());
+    EXPECT_THAT(err, StrEq(progress_message));
+
+    ds.listener_.clear();
+}
+
+TEST_F(DumpstateTest, RunCommandProgressIgnoreThreshold) {
+    sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
+    ds.listener_ = listener;
+    ds.listener_name_ = "FoxMulder";
+    SetProgress(0, 8, 5);  // 8 max, 5 threshold
+
+    // First update should always be sent.
+    EXPECT_CALL(*listener, onProgressUpdated(1));
+    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"));
+    EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
+
+    // Fourth update should be ignored because it's between the threshold (5 -1 = 4 < 5).
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
+    EXPECT_THAT(out, StrEq("stdout\n"));
+    EXPECT_THAT(err, StrEq("stderr\n"));
+
+    // Third update should be sent because it reaches threshold (6 - 1 = 5).
+    EXPECT_CALL(*listener, onProgressUpdated(6));
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
+    progress_message = GetProgressMessage(ds.listener_name_, 6, 8);
+    EXPECT_THAT(out, StrEq("stdout\n"));
+    EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
+
+    // Fourth update should be ignored because it's between the threshold (9 - 6 = 3 < 5).
+    // But max update should be sent.
+    EXPECT_CALL(*listener, onMaxProgressUpdated(10));  // 9 * 120% = 10.8 = 10
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(3).Build()));
+    progress_message = GetProgressMessage(ds.listener_name_, 9, 10, 8, false);
+    EXPECT_THAT(out, StrEq("stdout\n"));
+    EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
+
+    ds.listener_.clear();
+}
+
+TEST_F(DumpstateTest, RunCommandDropRoot) {
+    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.RunCommandDropRoot() on test suite\n")
+        return;
+    }
+    // First check root case - only available when running with 'adb root'.
+    uid_t uid = getuid();
+    if (uid == 0) {
+        EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"}));
+        EXPECT_THAT(out, StrEq("0\nstdout\n"));
+        EXPECT_THAT(err, StrEq("stderr\n"));
+        return;
+    }
+    // Then run dropping root.
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+                            CommandOptions::WithTimeout(1).DropRoot().Build()));
+    EXPECT_THAT(out, StrEq("2000\nstdout\n"));
+    EXPECT_THAT(err, StrEq("drop_root_user(): already running as Shell\nstderr\n"));
+}
+
+TEST_F(DumpstateTest, RunCommandAsRootUserBuild) {
+    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.RunCommandAsRootUserBuild() on test suite\n")
+        return;
+    }
+    if (!PropertiesHelper::IsUserBuild()) {
+        // Emulates user build if necessarily.
+        SetBuildType("user");
+    }
+
+    DropRoot();
+
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).AsRoot().Build()));
+
+    // We don't know the exact path of su, so we just check for the 'root ...' commands
+    EXPECT_THAT(out, StartsWith("Skipping"));
+    EXPECT_THAT(out, EndsWith("root " + kSimpleCommand + "' on user build.\n"));
+    EXPECT_THAT(err, IsEmpty());
+}
+
+TEST_F(DumpstateTest, RunCommandAsRootNonUserBuild) {
+    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() on test suite\n")
+        return;
+    }
+    if (PropertiesHelper::IsUserBuild()) {
+        ALOGI("Skipping RunCommandAsRootNonUserBuild on user builds\n");
+        return;
+    }
+
+    DropRoot();
+
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+                            CommandOptions::WithTimeout(1).AsRoot().Build()));
+
+    EXPECT_THAT(out, StrEq("0\nstdout\n"));
+    EXPECT_THAT(err, StrEq("stderr\n"));
+}
+
+TEST_F(DumpstateTest, DumpFileNotFoundNoTitle) {
+    EXPECT_EQ(-1, DumpFile("", "/I/cant/believe/I/exist"));
+    EXPECT_THAT(out,
+                StrEq("*** Error dumping /I/cant/believe/I/exist: No such file or directory\n"));
+    EXPECT_THAT(err, IsEmpty());
+}
+
+TEST_F(DumpstateTest, DumpFileNotFoundWithTitle) {
+    EXPECT_EQ(-1, DumpFile("Y U NO EXIST?", "/I/cant/believe/I/exist"));
+    EXPECT_THAT(err, IsEmpty());
+    // 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) {
+    EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
+    EXPECT_THAT(err, IsEmpty());
+    EXPECT_THAT(out, StrEq("I AM LINE1\n"));  // dumpstate adds missing newline
+}
+
+TEST_F(DumpstateTest, DumpFileSingleLineWithNewLine) {
+    EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line-with-newline.txt"));
+    EXPECT_THAT(err, IsEmpty());
+    EXPECT_THAT(out, StrEq("I AM LINE1\n"));
+}
+
+TEST_F(DumpstateTest, DumpFileMultipleLines) {
+    EXPECT_EQ(0, DumpFile("", kTestDataPath + "multiple-lines.txt"));
+    EXPECT_THAT(err, IsEmpty());
+    EXPECT_THAT(out, StrEq("I AM LINE1\nI AM LINE2\nI AM LINE3\n"));
+}
+
+TEST_F(DumpstateTest, DumpFileMultipleLinesWithNewLine) {
+    EXPECT_EQ(0, DumpFile("", kTestDataPath + "multiple-lines-with-newline.txt"));
+    EXPECT_THAT(err, IsEmpty());
+    EXPECT_THAT(out, StrEq("I AM LINE1\nI AM LINE2\nI AM LINE3\n"));
+}
+
+TEST_F(DumpstateTest, DumpFileOnDryRunNoTitle) {
+    SetDryRun(true);
+    EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
+    EXPECT_THAT(err, IsEmpty());
+    EXPECT_THAT(out, IsEmpty());
+}
+
+TEST_F(DumpstateTest, DumpFileOnDryRun) {
+    SetDryRun(true);
+    EXPECT_EQ(0, DumpFile("Might as well dump. Dump!", kTestDataPath + "single-line.txt"));
+    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"));
+}
+
+TEST_F(DumpstateTest, DumpFileUpdateProgress) {
+    sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
+    ds.listener_ = listener;
+    ds.listener_name_ = "FoxMulder";
+    SetProgress(0, 30);
+
+    EXPECT_CALL(*listener, onProgressUpdated(5));
+    EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
+
+    std::string progress_message =
+        GetProgressMessage(ds.listener_name_, 5, 30);  // TODO: unhardcode WEIGHT_FILE (5)?
+    EXPECT_THAT(err, StrEq(progress_message));
+    EXPECT_THAT(out, StrEq("I AM LINE1\n"));  // dumpstate adds missing newline
+
+    ds.listener_.clear();
+}
+
+class DumpstateServiceTest : public DumpstateBaseTest {
+  public:
+    DumpstateService dss;
+};
+
+TEST_F(DumpstateServiceTest, SetListenerNoName) {
+    sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
+    sp<IDumpstateToken> token;
+    EXPECT_TRUE(dss.setListener("", listener, &token).isOk());
+    ASSERT_THAT(token, IsNull());
+}
+
+TEST_F(DumpstateServiceTest, SetListenerNoPointer) {
+    sp<IDumpstateToken> token;
+    EXPECT_TRUE(dss.setListener("whatever", nullptr, &token).isOk());
+    ASSERT_THAT(token, IsNull());
+}
+
+TEST_F(DumpstateServiceTest, SetListenerTwice) {
+    sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
+    sp<IDumpstateToken> token;
+    EXPECT_TRUE(dss.setListener("whatever", listener, &token).isOk());
+    ASSERT_THAT(token, NotNull());
+    EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever"));
+
+    token.clear();
+    EXPECT_TRUE(dss.setListener("whatsoever", listener, &token).isOk());
+    ASSERT_THAT(token, IsNull());
+    EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever"));
+}
+
+class ProgressTest : public DumpstateBaseTest {
+  public:
+    Progress GetInstance(int32_t max, double growth_factor, const std::string& path = "") {
+        return Progress(max, growth_factor, path);
+    }
+
+    void AssertStats(const std::string& path, int32_t expected_runs, int32_t expected_average) {
+        std::string expected_content =
+            android::base::StringPrintf("%d %d\n", expected_runs, expected_average);
+        std::string actual_content;
+        ReadFileToString(path, &actual_content);
+        ASSERT_THAT(actual_content, StrEq(expected_content)) << "invalid stats on " << path;
+    }
+};
+
+TEST_F(ProgressTest, SimpleTest) {
+    Progress progress;
+    EXPECT_EQ(0, progress.Get());
+    EXPECT_EQ(Progress::kDefaultMax, progress.GetInitialMax());
+    EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+
+    bool max_increased = progress.Inc(1);
+    EXPECT_EQ(1, progress.Get());
+    EXPECT_EQ(Progress::kDefaultMax, progress.GetInitialMax());
+    EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+    EXPECT_FALSE(max_increased);
+
+    // Ignore negative increase.
+    max_increased = progress.Inc(-1);
+    EXPECT_EQ(1, progress.Get());
+    EXPECT_EQ(Progress::kDefaultMax, progress.GetInitialMax());
+    EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+    EXPECT_FALSE(max_increased);
+}
+
+TEST_F(ProgressTest, MaxGrowsInsideNewRange) {
+    Progress progress = GetInstance(10, 1.2);  // 20% growth factor
+    EXPECT_EQ(0, progress.Get());
+    EXPECT_EQ(10, progress.GetInitialMax());
+    EXPECT_EQ(10, progress.GetMax());
+
+    // No increase
+    bool max_increased = progress.Inc(10);
+    EXPECT_EQ(10, progress.Get());
+    EXPECT_EQ(10, progress.GetMax());
+    EXPECT_FALSE(max_increased);
+
+    // Increase, with new value < max*20%
+    max_increased = progress.Inc(1);
+    EXPECT_EQ(11, progress.Get());
+    EXPECT_EQ(13, progress.GetMax());  // 11 average * 20% growth = 13.2 = 13
+    EXPECT_TRUE(max_increased);
+}
+
+TEST_F(ProgressTest, MaxGrowsOutsideNewRange) {
+    Progress progress = GetInstance(10, 1.2);  // 20% growth factor
+    EXPECT_EQ(0, progress.Get());
+    EXPECT_EQ(10, progress.GetInitialMax());
+    EXPECT_EQ(10, progress.GetMax());
+
+    // No increase
+    bool max_increased = progress.Inc(10);
+    EXPECT_EQ(10, progress.Get());
+    EXPECT_EQ(10, progress.GetMax());
+    EXPECT_FALSE(max_increased);
+
+    // Increase, with new value > max*20%
+    max_increased = progress.Inc(5);
+    EXPECT_EQ(15, progress.Get());
+    EXPECT_EQ(18, progress.GetMax());  // 15 average * 20% growth = 18
+    EXPECT_TRUE(max_increased);
+}
+
+TEST_F(ProgressTest, InvalidPath) {
+    Progress progress("/devil/null");
+    EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+}
+
+TEST_F(ProgressTest, EmptyFile) {
+    Progress progress(CopyTextFileFixture("empty-file.txt"));
+    EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+}
+
+TEST_F(ProgressTest, InvalidLine1stEntryNAN) {
+    Progress progress(CopyTextFileFixture("stats-invalid-1st-NAN.txt"));
+    EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+}
+
+TEST_F(ProgressTest, InvalidLine2ndEntryNAN) {
+    Progress progress(CopyTextFileFixture("stats-invalid-2nd-NAN.txt"));
+    EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+}
+
+TEST_F(ProgressTest, InvalidLineBothNAN) {
+    Progress progress(CopyTextFileFixture("stats-invalid-both-NAN.txt"));
+    EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+}
+
+TEST_F(ProgressTest, InvalidLine1stEntryNegative) {
+    Progress progress(CopyTextFileFixture("stats-invalid-1st-negative.txt"));
+    EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+}
+
+TEST_F(ProgressTest, InvalidLine2ndEntryNegative) {
+    Progress progress(CopyTextFileFixture("stats-invalid-2nd-negative.txt"));
+    EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+}
+
+TEST_F(ProgressTest, InvalidLine1stEntryTooBig) {
+    Progress progress(CopyTextFileFixture("stats-invalid-1st-too-big.txt"));
+    EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+}
+
+TEST_F(ProgressTest, InvalidLine2ndEntryTooBig) {
+    Progress progress(CopyTextFileFixture("stats-invalid-2nd-too-big.txt"));
+    EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
+}
+
+// Tests stats are properly saved when the file does not exists.
+TEST_F(ProgressTest, FirstTime) {
+    if (!IsStandalone()) {
+        // TODO: temporarily disabled because it's failing when running as suite
+        MYLOGE("Skipping ProgressTest.FirstTime() on test suite\n")
+        return;
+    }
+
+    std::string path = kTestDataPath + "FirstTime.txt";
+    android::base::RemoveFileIfExists(path);
+
+    Progress run1(path);
+    EXPECT_EQ(0, run1.Get());
+    EXPECT_EQ(Progress::kDefaultMax, run1.GetInitialMax());
+    EXPECT_EQ(Progress::kDefaultMax, run1.GetMax());
+
+    bool max_increased = run1.Inc(20);
+    EXPECT_EQ(20, run1.Get());
+    EXPECT_EQ(Progress::kDefaultMax, run1.GetMax());
+    EXPECT_FALSE(max_increased);
+
+    run1.Save();
+    AssertStats(path, 1, 20);
+}
+
+// Tests what happens when the persistent settings contains the average duration of 1 run.
+// Data on file is 1 run and 109 average.
+TEST_F(ProgressTest, SecondTime) {
+    std::string path = CopyTextFileFixture("stats-one-run-no-newline.txt");
+
+    Progress run1 = GetInstance(-42, 1.2, path);
+    EXPECT_EQ(0, run1.Get());
+    EXPECT_EQ(10, run1.GetInitialMax());
+    EXPECT_EQ(10, run1.GetMax());
+
+    bool max_increased = run1.Inc(20);
+    EXPECT_EQ(20, run1.Get());
+    EXPECT_EQ(24, run1.GetMax());
+    EXPECT_TRUE(max_increased);
+
+    // Average now is 2 runs and (10 + 20)/ 2 = 15
+    run1.Save();
+    AssertStats(path, 2, 15);
+
+    Progress run2 = GetInstance(-42, 1.2, path);
+    EXPECT_EQ(0, run2.Get());
+    EXPECT_EQ(15, run2.GetInitialMax());
+    EXPECT_EQ(15, run2.GetMax());
+
+    max_increased = run2.Inc(25);
+    EXPECT_EQ(25, run2.Get());
+    EXPECT_EQ(30, run2.GetMax());
+    EXPECT_TRUE(max_increased);
+
+    // Average now is 3 runs and (15 * 2 + 25)/ 3 = 18.33 = 18
+    run2.Save();
+    AssertStats(path, 3, 18);
+
+    Progress run3 = GetInstance(-42, 1.2, path);
+    EXPECT_EQ(0, run3.Get());
+    EXPECT_EQ(18, run3.GetInitialMax());
+    EXPECT_EQ(18, run3.GetMax());
+
+    // Make sure average decreases as well
+    max_increased = run3.Inc(5);
+    EXPECT_EQ(5, run3.Get());
+    EXPECT_EQ(18, run3.GetMax());
+    EXPECT_FALSE(max_increased);
+
+    // Average now is 4 runs and (18 * 3 + 5)/ 4 = 14.75 = 14
+    run3.Save();
+    AssertStats(path, 4, 14);
+}
+
+// Tests what happens when the persistent settings contains the average duration of 2 runs.
+// Data on file is 2 runs and 15 average.
+TEST_F(ProgressTest, ThirdTime) {
+    std::string path = CopyTextFileFixture("stats-two-runs.txt");
+    AssertStats(path, 2, 15);  // Sanity check
+
+    Progress run1 = GetInstance(-42, 1.2, path);
+    EXPECT_EQ(0, run1.Get());
+    EXPECT_EQ(15, run1.GetInitialMax());
+    EXPECT_EQ(15, run1.GetMax());
+
+    bool max_increased = run1.Inc(20);
+    EXPECT_EQ(20, run1.Get());
+    EXPECT_EQ(24, run1.GetMax());
+    EXPECT_TRUE(max_increased);
+
+    // Average now is 3 runs and (15 * 2 + 20)/ 3 = 16.66 = 16
+    run1.Save();
+    AssertStats(path, 3, 16);
+}
+
+class DumpstateUtilTest : public DumpstateBaseTest {
+  public:
+    void SetUp() {
+        DumpstateBaseTest::SetUp();
+        SetDryRun(false);
+    }
+
+    void CaptureFdOut() {
+        ReadFileToString(path_, &out);
+    }
+
+    void CreateFd(const std::string& name) {
+        path_ = kTestDataPath + name;
+        MYLOGD("Creating fd for file %s\n", path_.c_str());
+
+        fd = TEMP_FAILURE_RETRY(open(path_.c_str(),
+                                     O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+                                     S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
+        ASSERT_GE(fd, 0) << "could not create FD for path " << path_;
+    }
+
+    // Runs a command into the `fd` and capture `stderr`.
+    int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
+                   const CommandOptions& options = CommandOptions::DEFAULT) {
+        CaptureStderr();
+        int status = RunCommandToFd(fd, title, full_command, options);
+        close(fd);
+
+        CaptureFdOut();
+        err = GetCapturedStderr();
+        return status;
+    }
+
+    // Dumps a file and into the `fd` and `stderr`.
+    int DumpFile(const std::string& title, const std::string& path) {
+        CaptureStderr();
+        int status = DumpFileToFd(fd, title, path);
+        close(fd);
+
+        CaptureFdOut();
+        err = GetCapturedStderr();
+        return status;
+    }
+
+    // Find out the pid of the process_name
+    int FindPidOfProcess(const std::string& process_name) {
+        CaptureStderr();
+        int status = GetPidByName(process_name);
+        err = GetCapturedStderr();
+        return status;
+    }
+
+    int fd;
+
+    // 'fd` output and `stderr` from the last command ran.
+    std::string out, err;
+
+  private:
+    std::string path_;
+};
+
+TEST_F(DumpstateUtilTest, RunCommandNoArgs) {
+    CreateFd("RunCommandNoArgs.txt");
+    EXPECT_EQ(-1, RunCommand("", {}));
+}
+
+TEST_F(DumpstateUtilTest, RunCommandNoTitle) {
+    CreateFd("RunCommandWithNoArgs.txt");
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand}));
+    EXPECT_THAT(out, StrEq("stdout\n"));
+    EXPECT_THAT(err, StrEq("stderr\n"));
+}
+
+TEST_F(DumpstateUtilTest, RunCommandWithTitle) {
+    CreateFd("RunCommandWithNoArgs.txt");
+    EXPECT_EQ(0, RunCommand("I AM GROOT", {kSimpleCommand}));
+    EXPECT_THAT(out, StrEq("------ I AM GROOT (" + kSimpleCommand + ") ------\nstdout\n"));
+    EXPECT_THAT(err, StrEq("stderr\n"));
+}
+
+TEST_F(DumpstateUtilTest, RunCommandWithOneArg) {
+    CreateFd("RunCommandWithOneArg.txt");
+    EXPECT_EQ(0, RunCommand("", {kEchoCommand, "one"}));
+    EXPECT_THAT(err, IsEmpty());
+    EXPECT_THAT(out, StrEq("one\n"));
+}
+
+TEST_F(DumpstateUtilTest, RunCommandWithMultipleArgs) {
+    CreateFd("RunCommandWithMultipleArgs.txt");
+    EXPECT_EQ(0, RunCommand("", {kEchoCommand, "one", "is", "the", "loniest", "number"}));
+    EXPECT_THAT(err, IsEmpty());
+    EXPECT_THAT(out, StrEq("one is the loniest number\n"));
+}
+
+TEST_F(DumpstateUtilTest, RunCommandWithLoggingMessage) {
+    CreateFd("RunCommandWithLoggingMessage.txt");
+    EXPECT_EQ(
+        0, RunCommand("", {kSimpleCommand},
+                      CommandOptions::WithTimeout(10).Log("COMMAND, Y U NO LOG FIRST?").Build()));
+    EXPECT_THAT(out, StrEq("stdout\n"));
+    EXPECT_THAT(err, StrEq("COMMAND, Y U NO LOG FIRST?stderr\n"));
+}
+
+TEST_F(DumpstateUtilTest, RunCommandRedirectStderr) {
+    CreateFd("RunCommandRedirectStderr.txt");
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand},
+                            CommandOptions::WithTimeout(10).RedirectStderr().Build()));
+    EXPECT_THAT(out, IsEmpty());
+    EXPECT_THAT(err, StrEq("stdout\nstderr\n"));
+}
+
+TEST_F(DumpstateUtilTest, RunCommandDryRun) {
+    CreateFd("RunCommandDryRun.txt");
+    SetDryRun(true);
+    EXPECT_EQ(0, RunCommand("I AM GROOT", {kSimpleCommand}));
+    EXPECT_THAT(out, StrEq(android::base::StringPrintf(
+                         "------ I AM GROOT (%s) ------\n\t(skipped on dry run)\n",
+                         kSimpleCommand.c_str())));
+    EXPECT_THAT(err, IsEmpty());
+}
+
+TEST_F(DumpstateUtilTest, RunCommandDryRunNoTitle) {
+    CreateFd("RunCommandDryRun.txt");
+    SetDryRun(true);
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand}));
+    EXPECT_THAT(
+        out, StrEq(android::base::StringPrintf("%s: skipped on dry run\n", kSimpleCommand.c_str())));
+    EXPECT_THAT(err, IsEmpty());
+}
+
+TEST_F(DumpstateUtilTest, RunCommandDryRunAlways) {
+    CreateFd("RunCommandDryRunAlways.txt");
+    SetDryRun(true);
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(10).Always().Build()));
+    EXPECT_THAT(out, StrEq("stdout\n"));
+    EXPECT_THAT(err, StrEq("stderr\n"));
+}
+
+TEST_F(DumpstateUtilTest, RunCommandNotFound) {
+    CreateFd("RunCommandNotFound.txt");
+    EXPECT_NE(0, RunCommand("", {"/there/cannot/be/such/command"}));
+    EXPECT_THAT(out, StartsWith("*** command '/there/cannot/be/such/command' failed: exit code"));
+    EXPECT_THAT(err, StartsWith("execvp on command '/there/cannot/be/such/command' failed"));
+}
+
+TEST_F(DumpstateUtilTest, RunCommandFails) {
+    CreateFd("RunCommandFails.txt");
+    EXPECT_EQ(42, RunCommand("", {kSimpleCommand, "--exit", "42"}));
+    EXPECT_THAT(out, StrEq("stdout\n*** command '" + kSimpleCommand +
+                           " --exit 42' failed: exit code 42\n"));
+    EXPECT_THAT(err, StrEq("stderr\n*** command '" + kSimpleCommand +
+                           " --exit 42' failed: exit code 42\n"));
+}
+
+TEST_F(DumpstateUtilTest, RunCommandCrashes) {
+    CreateFd("RunCommandCrashes.txt");
+    EXPECT_NE(0, RunCommand("", {kSimpleCommand, "--crash"}));
+    // We don't know the exit code, so check just the prefix.
+    EXPECT_THAT(
+        out, StartsWith("stdout\n*** command '" + kSimpleCommand + " --crash' failed: exit code"));
+    EXPECT_THAT(
+        err, StartsWith("stderr\n*** command '" + kSimpleCommand + " --crash' failed: exit code"));
+}
+
+TEST_F(DumpstateUtilTest, RunCommandTimesout) {
+    CreateFd("RunCommandTimesout.txt");
+    EXPECT_EQ(-1, RunCommand("", {kSimpleCommand, "--sleep", "2"},
+                             CommandOptions::WithTimeout(1).Build()));
+    EXPECT_THAT(out, StartsWith("stdout line1\n*** command '" + kSimpleCommand +
+                                " --sleep 2' timed out after 1"));
+    EXPECT_THAT(err, StartsWith("sleeping for 2s\n*** command '" + kSimpleCommand +
+                                " --sleep 2' timed out after 1"));
+}
+
+TEST_F(DumpstateUtilTest, RunCommandIsKilled) {
+    CreateFd("RunCommandIsKilled.txt");
+    CaptureStderr();
+
+    std::thread t([=]() {
+        EXPECT_EQ(SIGTERM, RunCommandToFd(fd, "", {kSimpleCommand, "--pid", "--sleep", "20"},
+                                          CommandOptions::WithTimeout(100).Always().Build()));
+    });
+
+    // Capture pid and pre-sleep output.
+    sleep(1);  // Wait a little bit to make sure pid and 1st line were printed.
+    std::string err = GetCapturedStderr();
+    EXPECT_THAT(err, StrEq("sleeping for 20s\n"));
+
+    CaptureFdOut();
+    std::vector<std::string> lines = android::base::Split(out, "\n");
+    ASSERT_EQ(3, (int)lines.size()) << "Invalid lines before sleep: " << out;
+
+    int pid = atoi(lines[0].c_str());
+    EXPECT_THAT(lines[1], StrEq("stdout line1"));
+    EXPECT_THAT(lines[2], IsEmpty());  // \n
+
+    // Then kill the process.
+    CaptureFdOut();
+    CaptureStderr();
+    ASSERT_EQ(0, kill(pid, SIGTERM)) << "failed to kill pid " << pid;
+    t.join();
+
+    // Finally, check output after murder.
+    CaptureFdOut();
+    err = GetCapturedStderr();
+
+    // out starts with the pid, which is an unknown
+    EXPECT_THAT(out, EndsWith("stdout line1\n*** command '" + kSimpleCommand +
+                              " --pid --sleep 20' failed: killed by signal 15\n"));
+    EXPECT_THAT(err, StrEq("*** command '" + kSimpleCommand +
+                           " --pid --sleep 20' failed: killed by signal 15\n"));
+}
+
+TEST_F(DumpstateUtilTest, RunCommandAsRootUserBuild) {
+    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 DumpstateUtilTest.RunCommandAsRootUserBuild() on test suite\n")
+        return;
+    }
+    CreateFd("RunCommandAsRootUserBuild.txt");
+    if (!PropertiesHelper::IsUserBuild()) {
+        // Emulates user build if necessarily.
+        SetBuildType("user");
+    }
+
+    DropRoot();
+
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).AsRoot().Build()));
+
+    // We don't know the exact path of su, so we just check for the 'root ...' commands
+    EXPECT_THAT(out, StartsWith("Skipping"));
+    EXPECT_THAT(out, EndsWith("root " + kSimpleCommand + "' on user build.\n"));
+    EXPECT_THAT(err, IsEmpty());
+}
+
+TEST_F(DumpstateUtilTest, RunCommandAsRootNonUserBuild) {
+    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 DumpstateUtilTest.RunCommandAsRootNonUserBuild() on test suite\n")
+        return;
+    }
+    CreateFd("RunCommandAsRootNonUserBuild.txt");
+    if (PropertiesHelper::IsUserBuild()) {
+        ALOGI("Skipping RunCommandAsRootNonUserBuild on user builds\n");
+        return;
+    }
+
+    DropRoot();
+
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+                            CommandOptions::WithTimeout(1).AsRoot().Build()));
+
+    EXPECT_THAT(out, StrEq("0\nstdout\n"));
+    EXPECT_THAT(err, StrEq("stderr\n"));
+}
+
+TEST_F(DumpstateUtilTest, RunCommandDropRoot) {
+    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 DumpstateUtilTest.RunCommandDropRoot() on test suite\n")
+        return;
+    }
+    CreateFd("RunCommandDropRoot.txt");
+    // First check root case - only available when running with 'adb root'.
+    uid_t uid = getuid();
+    if (uid == 0) {
+        EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"}));
+        EXPECT_THAT(out, StrEq("0\nstdout\n"));
+        EXPECT_THAT(err, StrEq("stderr\n"));
+        return;
+    }
+    // Then run dropping root.
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+                            CommandOptions::WithTimeout(1).DropRoot().Build()));
+    EXPECT_THAT(out, StrEq("2000\nstdout\n"));
+    EXPECT_THAT(err, StrEq("drop_root_user(): already running as Shell\nstderr\n"));
+}
+
+TEST_F(DumpstateUtilTest, DumpFileNotFoundNoTitle) {
+    CreateFd("DumpFileNotFound.txt");
+    EXPECT_EQ(-1, DumpFile("", "/I/cant/believe/I/exist"));
+    EXPECT_THAT(out,
+                StrEq("*** Error dumping /I/cant/believe/I/exist: No such file or directory\n"));
+    EXPECT_THAT(err, IsEmpty());
+}
+
+TEST_F(DumpstateUtilTest, DumpFileNotFoundWithTitle) {
+    CreateFd("DumpFileNotFound.txt");
+    EXPECT_EQ(-1, DumpFile("Y U NO EXIST?", "/I/cant/believe/I/exist"));
+    EXPECT_THAT(out, StrEq("*** Error dumping /I/cant/believe/I/exist (Y U NO EXIST?): No such "
+                           "file or directory\n"));
+    EXPECT_THAT(err, IsEmpty());
+}
+
+TEST_F(DumpstateUtilTest, DumpFileSingleLine) {
+    CreateFd("DumpFileSingleLine.txt");
+    EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
+    EXPECT_THAT(err, IsEmpty());
+    EXPECT_THAT(out, StrEq("I AM LINE1\n"));  // dumpstate adds missing newline
+}
+
+TEST_F(DumpstateUtilTest, DumpFileSingleLineWithNewLine) {
+    CreateFd("DumpFileSingleLineWithNewLine.txt");
+    EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line-with-newline.txt"));
+    EXPECT_THAT(err, IsEmpty());
+    EXPECT_THAT(out, StrEq("I AM LINE1\n"));
+}
+
+TEST_F(DumpstateUtilTest, DumpFileMultipleLines) {
+    CreateFd("DumpFileMultipleLines.txt");
+    EXPECT_EQ(0, DumpFile("", kTestDataPath + "multiple-lines.txt"));
+    EXPECT_THAT(err, IsEmpty());
+    EXPECT_THAT(out, StrEq("I AM LINE1\nI AM LINE2\nI AM LINE3\n"));
+}
+
+TEST_F(DumpstateUtilTest, DumpFileMultipleLinesWithNewLine) {
+    CreateFd("DumpFileMultipleLinesWithNewLine.txt");
+    EXPECT_EQ(0, DumpFile("", kTestDataPath + "multiple-lines-with-newline.txt"));
+    EXPECT_THAT(err, IsEmpty());
+    EXPECT_THAT(out, StrEq("I AM LINE1\nI AM LINE2\nI AM LINE3\n"));
+}
+
+TEST_F(DumpstateUtilTest, DumpFileOnDryRunNoTitle) {
+    CreateFd("DumpFileOnDryRun.txt");
+    SetDryRun(true);
+    std::string path = kTestDataPath + "single-line.txt";
+    EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
+    EXPECT_THAT(err, IsEmpty());
+    EXPECT_THAT(out, StrEq(path + ": skipped on dry run\n"));
+}
+
+TEST_F(DumpstateUtilTest, DumpFileOnDryRun) {
+    CreateFd("DumpFileOnDryRun.txt");
+    SetDryRun(true);
+    std::string path = kTestDataPath + "single-line.txt";
+    EXPECT_EQ(0, DumpFile("Might as well dump. Dump!", kTestDataPath + "single-line.txt"));
+    EXPECT_THAT(err, IsEmpty());
+    EXPECT_THAT(
+        out, StartsWith("------ Might as well dump. Dump! (" + kTestDataPath + "single-line.txt:"));
+    EXPECT_THAT(out, EndsWith("skipped on dry run\n"));
+}
+
+TEST_F(DumpstateUtilTest, FindingPidWithExistingProcess) {
+    // init process always has pid 1.
+    EXPECT_EQ(1, FindPidOfProcess("init"));
+    EXPECT_THAT(err, IsEmpty());
+}
+
+TEST_F(DumpstateUtilTest, FindingPidWithNotExistingProcess) {
+    // find the process with abnormal name.
+    EXPECT_EQ(-1, FindPidOfProcess("abcdef12345-543"));
+    EXPECT_THAT(err, StrEq("can't find the pid\n"));
+}
+
+}  // namespace dumpstate
+}  // namespace os
+}  // namespace android
diff --git a/cmds/dumpstate/tests/dumpstate_test_fixture.cpp b/cmds/dumpstate/tests/dumpstate_test_fixture.cpp
new file mode 100644
index 0000000..5be4719
--- /dev/null
+++ b/cmds/dumpstate/tests/dumpstate_test_fixture.cpp
@@ -0,0 +1,107 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define LOG_TAG "dumpstate"
+#include <cutils/log.h>
+
+void PrintDefaultOutput() {
+    fprintf(stdout, "stdout\n");
+    fflush(stdout);
+    fprintf(stderr, "stderr\n");
+    fflush(stderr);
+}
+
+/*
+ * Binary used to on RunCommand tests.
+ *
+ * Usage:
+ *
+ * - Unless stated otherwise this command:
+ *
+ *   1.Prints `stdout\n` on `stdout` and flushes it.
+ *   2.Prints `stderr\n` on `stderr` and flushes it.
+ *   3.Exit with status 0.
+ *
+ * - If 1st argument is '--pid', it first prints its pid on `stdout`.
+ *
+ * - If 1st argument is '--uid', it first prints its uid on `stdout`.
+ *
+ * - If 1st argument is '--crash', it uses ALOGF to crash and returns 666.
+ *
+ * - With argument '--exit' 'CODE', returns CODE;
+ *
+ * - With argument '--sleep 'TIME':
+ *
+ *   1.Prints `stdout line1\n` on `stdout` and `sleeping TIME s\n` on `stderr`
+ *   2.Sleeps for TIME s
+ *   3.Prints `stdout line2\n` on `stdout` and `woke up\n` on `stderr`
+ */
+int main(int argc, char* const argv[]) {
+    if (argc == 2) {
+        if (strcmp(argv[1], "--crash") == 0) {
+            PrintDefaultOutput();
+            LOG_FATAL("D'OH\n");
+            return 666;
+        }
+    }
+    if (argc == 3) {
+        if (strcmp(argv[1], "--exit") == 0) {
+            PrintDefaultOutput();
+            return atoi(argv[2]);
+        }
+    }
+
+    if (argc > 1) {
+        int index = 1;
+
+        // First check arguments that can shift the index.
+        if (strcmp(argv[1], "--pid") == 0) {
+            index++;
+            fprintf(stdout, "%d\n", getpid());
+            fflush(stdout);
+        } else if (strcmp(argv[1], "--uid") == 0) {
+            index++;
+            fprintf(stdout, "%d\n", getuid());
+            fflush(stdout);
+        }
+
+        // Then the "common" arguments, if any.
+        if (argc > index + 1) {
+            if (strcmp(argv[index], "--sleep") == 0) {
+                int napTime = atoi(argv[index + 1]);
+                fprintf(stdout, "stdout line1\n");
+                fflush(stdout);
+                fprintf(stderr, "sleeping for %ds\n", napTime);
+                fflush(stderr);
+                sleep(napTime);
+                fprintf(stdout, "stdout line2\n");
+                fflush(stdout);
+                fprintf(stderr, "woke up\n");
+                fflush(stderr);
+                return 0;
+            }
+        }
+    }
+
+    PrintDefaultOutput();
+    return 0;
+}
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index af6c666..eefdcbd 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -14,43 +14,65 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "dumpstate"
+
+#include "dumpstate.h"
+
 #include <dirent.h>
-#include <errno.h>
 #include <fcntl.h>
-#include <limits.h>
+#include <libgen.h>
+#include <math.h>
 #include <poll.h>
 #include <signal.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <string>
 #include <string.h>
 #include <sys/capability.h>
 #include <sys/inotify.h>
+#include <sys/klog.h>
+#include <sys/prctl.h>
 #include <sys/stat.h>
-#include <sys/sysconf.h>
 #include <sys/time.h>
 #include <sys/wait.h>
-#include <sys/klog.h>
 #include <time.h>
 #include <unistd.h>
-#include <vector>
-#include <sys/prctl.h>
 
-#define LOG_TAG "dumpstate"
+#include <set>
+#include <string>
+#include <vector>
 
 #include <android-base/file.h>
-#include <cutils/debugger.h>
-#include <cutils/log.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
 #include <cutils/properties.h>
 #include <cutils/sockets.h>
+#include <debuggerd/client.h>
+#include <log/log.h>
 #include <private/android_filesystem_config.h>
 
-#include <selinux/android.h>
+#include "DumpstateInternal.h"
 
-#include "dumpstate.h"
+// TODO: remove once moved to namespace
+using android::os::dumpstate::CommandOptions;
+using android::os::dumpstate::DumpFileToFd;
+using android::os::dumpstate::PropertiesHelper;
 
-static const int64_t NANOS_PER_SEC = 1000000000;
+// Keep in sync with
+// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
+static const int TRACE_DUMP_TIMEOUT_MS = 10000; // 10 seconds
+
+/* Most simple commands have 10 as timeout, so 5 is a good estimate */
+static const int32_t WEIGHT_FILE = 5;
+
+// TODO: temporary variables and functions used during C++ refactoring
+static Dumpstate& ds = Dumpstate::GetInstance();
+static int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
+                      const CommandOptions& options = CommandOptions::DEFAULT) {
+    return ds.RunCommand(title, full_command, options);
+}
 
 /* list of native processes to include in the native dumps */
 // This matches the /proc/pid/exe link instead of /proc/pid/cmdline.
@@ -58,47 +80,190 @@
         "/system/bin/audioserver",
         "/system/bin/cameraserver",
         "/system/bin/drmserver",
-        "/system/bin/mediacodec",     // media.codec
         "/system/bin/mediadrmserver",
         "/system/bin/mediaextractor", // media.extractor
         "/system/bin/mediaserver",
         "/system/bin/sdcard",
         "/system/bin/surfaceflinger",
         "/system/bin/vehicle_network_service",
+        "/vendor/bin/hw/android.hardware.media.omx@1.0-service", // media.codec
         NULL,
 };
 
-DurationReporter::DurationReporter(const char *title) : DurationReporter(title, stdout) {}
+/* list of hal interface to dump containing process during native dumps */
+static const char* hal_interfaces_to_dump[] {
+        "android.hardware.audio@2.0::IDevicesFactory",
+        "android.hardware.bluetooth@1.0::IBluetoothHci",
+        "android.hardware.camera.provider@2.4::ICameraProvider",
+        "android.hardware.graphics.composer@2.1::IComposer",
+        "android.hardware.vr@1.0::IVr",
+        "android.hardware.media.omx@1.0::IOmx",
+        NULL,
+};
 
-DurationReporter::DurationReporter(const char *title, FILE *out) {
-    title_ = title;
-    if (title) {
-        started_ = DurationReporter::nanotime();
+// Reasonable value for max stats.
+static const int STATS_MAX_N_RUNS = 1000;
+static const long STATS_MAX_AVERAGE = 100000;
+
+CommandOptions Dumpstate::DEFAULT_DUMPSYS = CommandOptions::WithTimeout(30).Build();
+
+Dumpstate::Dumpstate(const std::string& version)
+    : pid_(getpid()), version_(version), now_(time(nullptr)) {
+}
+
+Dumpstate& Dumpstate::GetInstance() {
+    static Dumpstate singleton_(android::base::GetProperty("dumpstate.version", VERSION_CURRENT));
+    return singleton_;
+}
+
+DurationReporter::DurationReporter(const std::string& title, bool log_only)
+    : title_(title), log_only_(log_only) {
+    if (!title_.empty()) {
+        started_ = Nanotime();
     }
-    out_ = out;
 }
 
 DurationReporter::~DurationReporter() {
-    if (title_) {
-        uint64_t elapsed = DurationReporter::nanotime() - started_;
-        // Use "Yoda grammar" to make it easier to grep|sort sections.
-        if (out_) {
-            fprintf(out_, "------ %.3fs was the duration of '%s' ------\n",
-                   (float) elapsed / NANOS_PER_SEC, title_);
+    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 {
-            MYLOGD("Duration of '%s': %.3fs\n", title_, (float) elapsed / NANOS_PER_SEC);
+            // 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());
         }
     }
 }
 
-uint64_t DurationReporter::DurationReporter::nanotime() {
-    struct timespec ts;
-    clock_gettime(CLOCK_MONOTONIC, &ts);
-    return (uint64_t) ts.tv_sec * NANOS_PER_SEC + ts.tv_nsec;
+const int32_t Progress::kDefaultMax = 5000;
+
+Progress::Progress(const std::string& path) : Progress(Progress::kDefaultMax, 1.1, path) {
+}
+
+Progress::Progress(int32_t initial_max, int32_t progress, float growth_factor)
+    : Progress(initial_max, growth_factor, "") {
+    progress_ = progress;
+}
+
+Progress::Progress(int32_t initial_max, float growth_factor, const std::string& path)
+    : initial_max_(initial_max),
+      progress_(0),
+      max_(initial_max),
+      growth_factor_(growth_factor),
+      n_runs_(0),
+      average_max_(0),
+      path_(path) {
+    if (!path_.empty()) {
+        Load();
+    }
+}
+
+void Progress::Load() {
+    MYLOGD("Loading stats from %s\n", path_.c_str());
+    std::string content;
+    if (!android::base::ReadFileToString(path_, &content)) {
+        MYLOGI("Could not read stats from %s; using max of %d\n", path_.c_str(), max_);
+        return;
+    }
+    if (content.empty()) {
+        MYLOGE("No stats (empty file) on %s; using max of %d\n", path_.c_str(), max_);
+        return;
+    }
+    std::vector<std::string> lines = android::base::Split(content, "\n");
+
+    if (lines.size() < 1) {
+        MYLOGE("Invalid stats on file %s: not enough lines (%d). Using max of %d\n", path_.c_str(),
+               (int)lines.size(), max_);
+        return;
+    }
+    char* ptr;
+    n_runs_ = strtol(lines[0].c_str(), &ptr, 10);
+    average_max_ = strtol(ptr, nullptr, 10);
+    if (n_runs_ <= 0 || average_max_ <= 0 || n_runs_ > STATS_MAX_N_RUNS ||
+        average_max_ > STATS_MAX_AVERAGE) {
+        MYLOGE("Invalid stats line on file %s: %s\n", path_.c_str(), lines[0].c_str());
+        initial_max_ = Progress::kDefaultMax;
+    } else {
+        initial_max_ = average_max_;
+    }
+    max_ = initial_max_;
+
+    MYLOGI("Average max progress: %d in %d runs; estimated max: %d\n", average_max_, n_runs_, max_);
+}
+
+void Progress::Save() {
+    int32_t total = n_runs_ * average_max_ + progress_;
+    int32_t runs = n_runs_ + 1;
+    int32_t average = floor(((float)total) / runs);
+    MYLOGI("Saving stats (total=%d, runs=%d, average=%d) on %s\n", total, runs, average,
+           path_.c_str());
+    if (path_.empty()) {
+        return;
+    }
+
+    std::string content = android::base::StringPrintf("%d %d\n", runs, average);
+    if (!android::base::WriteStringToFile(content, path_)) {
+        MYLOGE("Could not save stats on %s\n", path_.c_str());
+    }
+}
+
+int32_t Progress::Get() const {
+    return progress_;
+}
+
+bool Progress::Inc(int32_t delta) {
+    bool changed = false;
+    if (delta >= 0) {
+        progress_ += delta;
+        if (progress_ > max_) {
+            int32_t old_max = max_;
+            max_ = floor((float)progress_ * growth_factor_);
+            MYLOGD("Adjusting max progress from %d to %d\n", old_max, max_);
+            changed = true;
+        }
+    }
+    return changed;
+}
+
+int32_t Progress::GetMax() const {
+    return max_;
+}
+
+int32_t Progress::GetInitialMax() const {
+    return initial_max_;
+}
+
+void Progress::Dump(int fd, const std::string& prefix) const {
+    const char* pr = prefix.c_str();
+    dprintf(fd, "%sprogress: %d\n", pr, progress_);
+    dprintf(fd, "%smax: %d\n", pr, max_);
+    dprintf(fd, "%sinitial_max: %d\n", pr, initial_max_);
+    dprintf(fd, "%sgrowth_factor: %0.2f\n", pr, growth_factor_);
+    dprintf(fd, "%spath: %s\n", pr, path_.c_str());
+    dprintf(fd, "%sn_runs: %d\n", pr, n_runs_);
+    dprintf(fd, "%saverage_max: %d\n", pr, average_max_);
+}
+
+bool Dumpstate::IsZipping() const {
+    return zip_writer_ != nullptr;
+}
+
+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(),
+                                       name_.c_str(), suffix.c_str());
+}
+
+void Dumpstate::SetProgress(std::unique_ptr<Progress> progress) {
+    progress_ = std::move(progress);
 }
 
 void for_each_userid(void (*func)(int), const char *header) {
-    ON_DRY_RUN_RETURN();
+    std::string title = header == nullptr ? "for_each_userid" : android::base::StringPrintf(
+                                                                    "for_each_userid(%s)", header);
+    DurationReporter duration_reporter(title);
+    if (PropertiesHelper::IsDryRun()) return;
+
     DIR *d;
     struct dirent *de;
 
@@ -180,8 +345,12 @@
 }
 
 void for_each_pid(for_each_pid_func func, const char *header) {
-    ON_DRY_RUN_RETURN();
-  __for_each_pid(for_each_pid_helper, header, (void *)func);
+    std::string title = header == nullptr ? "for_each_pid"
+                                          : android::base::StringPrintf("for_each_pid(%s)", header);
+    DurationReporter duration_reporter(title);
+    if (PropertiesHelper::IsDryRun()) return;
+
+    __for_each_pid(for_each_pid_helper, header, (void *) func);
 }
 
 static void for_each_tid_helper(int pid, const char *cmdline, void *arg) {
@@ -233,12 +402,18 @@
 }
 
 void for_each_tid(for_each_tid_func func, const char *header) {
-    ON_DRY_RUN_RETURN();
+    std::string title = header == nullptr ? "for_each_tid"
+                                          : android::base::StringPrintf("for_each_tid(%s)", header);
+    DurationReporter duration_reporter(title);
+
+    if (PropertiesHelper::IsDryRun()) return;
+
     __for_each_pid(for_each_tid_helper, header, (void *) func);
 }
 
 void show_wchan(int pid, int tid, const char *name) {
-    ON_DRY_RUN_RETURN();
+    if (PropertiesHelper::IsDryRun()) return;
+
     char path[255];
     char buffer[255];
     int fd, ret, save_errno;
@@ -304,7 +479,8 @@
 }
 
 void show_showtime(int pid, const char *name) {
-    ON_DRY_RUN_RETURN();
+    if (PropertiesHelper::IsDryRun()) return;
+
     char path[255];
     char buffer[1023];
     int fd, ret, save_errno;
@@ -361,7 +537,7 @@
     if (iotime) {
         snprdec(buffer, sizeof(buffer), 79, permille);
     }
-    puts(buffer); // adds a trailing newline
+    puts(buffer);  // adds a trailing newline
 
     return;
 }
@@ -371,7 +547,8 @@
     DurationReporter duration_reporter(title);
     printf("------ %s ------\n", title);
 
-    ON_DRY_RUN_RETURN();
+    if (PropertiesHelper::IsDryRun()) return;
+
     /* Get size of kernel buffer */
     int size = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
     if (size <= 0) {
@@ -401,84 +578,17 @@
 
     snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name);
     snprintf(arg, sizeof(arg), "%d", pid);
-    run_command(title, 10, SU_PATH, "root", "showmap", "-q", arg, NULL);
+    RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT);
 }
 
-static int _dump_file_from_fd(const char *title, const char *path, int fd) {
-    if (title) {
-        printf("------ %s (%s", title, path);
-
-        struct stat st;
-        // Only show the modification time of non-device files.
-        size_t path_len = strlen(path);
-        if ((path_len < 6 || memcmp(path, "/proc/", 6)) &&
-                (path_len < 5 || memcmp(path, "/sys/", 5)) &&
-                (path_len < 3 || memcmp(path, "/d/", 3)) &&
-                !fstat(fd, &st)) {
-            char stamp[80];
-            time_t mtime = st.st_mtime;
-            strftime(stamp, sizeof(stamp), "%Y-%m-%d %H:%M:%S", localtime(&mtime));
-            printf(": %s", stamp);
-        }
-        printf(") ------\n");
-    }
-    ON_DRY_RUN({ update_progress(WEIGHT_FILE); close(fd); return 0; });
-
-    bool newline = false;
-    fd_set read_set;
-    struct timeval tm;
-    while (1) {
-        FD_ZERO(&read_set);
-        FD_SET(fd, &read_set);
-        /* Timeout if no data is read for 30 seconds. */
-        tm.tv_sec = 30;
-        tm.tv_usec = 0;
-        uint64_t elapsed = DurationReporter::nanotime();
-        int ret = TEMP_FAILURE_RETRY(select(fd + 1, &read_set, NULL, NULL, &tm));
-        if (ret == -1) {
-            printf("*** %s: select failed: %s\n", path, strerror(errno));
-            newline = true;
-            break;
-        } else if (ret == 0) {
-            elapsed = DurationReporter::nanotime() - elapsed;
-            printf("*** %s: Timed out after %.3fs\n", path,
-                   (float) elapsed / NANOS_PER_SEC);
-            newline = true;
-            break;
-        } else {
-            char buffer[65536];
-            ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
-            if (bytes_read > 0) {
-                fwrite(buffer, bytes_read, 1, stdout);
-                newline = (buffer[bytes_read-1] == '\n');
-            } else {
-                if (bytes_read == -1) {
-                    printf("*** %s: Failed to read from fd: %s", path, strerror(errno));
-                    newline = true;
-                }
-                break;
-            }
-        }
-    }
-    update_progress(WEIGHT_FILE);
-    close(fd);
-
-    if (!newline) printf("\n");
-    if (title) printf("\n");
-    return 0;
-}
-
-/* prints the contents of a file */
-int dump_file(const char *title, const char *path) {
+int Dumpstate::DumpFile(const std::string& title, const std::string& path) {
     DurationReporter duration_reporter(title);
-    int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
-    if (fd < 0) {
-        int err = errno;
-        printf("*** %s: %s\n", path, strerror(err));
-        if (title) printf("\n");
-        return -1;
-    }
-    return _dump_file_from_fd(title, path, fd);
+
+    int status = DumpFileToFd(STDOUT_FILENO, title, path);
+
+    UpdateProgress(WEIGHT_FILE);
+
+    return status;
 }
 
 int read_file_as_long(const char *path, long int *output) {
@@ -508,9 +618,8 @@
  * to false when set to NULL. dump_from_fd will always be
  * called with title NULL.
  */
-int dump_files(const char *title, const char *dir,
-        bool (*skip)(const char *path),
-        int (*dump_from_fd)(const char *title, const char *path, int fd)) {
+int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path),
+               int (*dump_from_fd)(const char* title, const char* path, int fd)) {
     DurationReporter duration_reporter(title);
     DIR *dirp;
     struct dirent *d;
@@ -518,10 +627,10 @@
     const char *slash = "/";
     int fd, retval = 0;
 
-    if (title) {
-        printf("------ %s (%s) ------\n", title, dir);
+    if (!title.empty()) {
+        printf("------ %s (%s) ------\n", title.c_str(), dir);
     }
-    ON_DRY_RUN_RETURN(0);
+    if (PropertiesHelper::IsDryRun()) return 0;
 
     if (dir[strlen(dir) - 1] == '/') {
         ++slash;
@@ -552,7 +661,7 @@
             continue;
         }
         if (d->d_type == DT_DIR) {
-            int ret = dump_files(NULL, newpath, skip, dump_from_fd);
+            int ret = dump_files("", newpath, skip, dump_from_fd);
             if (ret < 0) {
                 retval = ret;
             }
@@ -567,7 +676,7 @@
         (*dump_from_fd)(NULL, newpath, fd);
     }
     closedir(dirp);
-    if (title) {
+    if (!title.empty()) {
         printf("\n");
     }
     return retval;
@@ -578,6 +687,8 @@
  * stuck.
  */
 int dump_file_from_fd(const char *title, const char *path, int fd) {
+    if (PropertiesHelper::IsDryRun()) return 0;
+
     int flags = fcntl(fd, F_GETFL);
     if (flags == -1) {
         printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
@@ -588,332 +699,30 @@
         close(fd);
         return -1;
     }
-    return _dump_file_from_fd(title, path, fd);
+    return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun());
 }
 
-bool waitpid_with_timeout(pid_t pid, int timeout_seconds, int* status) {
-    sigset_t child_mask, old_mask;
-    sigemptyset(&child_mask);
-    sigaddset(&child_mask, SIGCHLD);
-
-    if (sigprocmask(SIG_BLOCK, &child_mask, &old_mask) == -1) {
-        printf("*** sigprocmask failed: %s\n", strerror(errno));
-        return false;
-    }
-
-    struct timespec ts;
-    ts.tv_sec = timeout_seconds;
-    ts.tv_nsec = 0;
-    int ret = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, NULL, &ts));
-    int saved_errno = errno;
-    // Set the signals back the way they were.
-    if (sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1) {
-        printf("*** sigprocmask failed: %s\n", strerror(errno));
-        if (ret == 0) {
-            return false;
-        }
-    }
-    if (ret == -1) {
-        errno = saved_errno;
-        if (errno == EAGAIN) {
-            errno = ETIMEDOUT;
-        } else {
-            printf("*** sigtimedwait failed: %s\n", strerror(errno));
-        }
-        return false;
-    }
-
-    pid_t child_pid = waitpid(pid, status, WNOHANG);
-    if (child_pid != pid) {
-        if (child_pid != -1) {
-            printf("*** Waiting for pid %d, got pid %d instead\n", pid, child_pid);
-        } else {
-            printf("*** waitpid failed: %s\n", strerror(errno));
-        }
-        return false;
-    }
-    return true;
-}
-
-// TODO: refactor all those commands that convert args
-void format_args(const char* command, const char *args[], std::string *string);
-
-int run_command(const char *title, int timeout_seconds, const char *command, ...) {
+int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command,
+                          const CommandOptions& options) {
     DurationReporter duration_reporter(title);
-    fflush(stdout);
 
-    const char *args[1024] = {command};
-    size_t arg;
-    va_list ap;
-    va_start(ap, command);
-    if (title) printf("------ %s (%s", title, command);
-    bool null_terminated = false;
-    for (arg = 1; arg < sizeof(args) / sizeof(args[0]); ++arg) {
-        args[arg] = va_arg(ap, const char *);
-        if (args[arg] == nullptr) {
-            null_terminated = true;
-            break;
-        }
-        // TODO: null_terminated check is not really working; line below would crash dumpstate if
-        // nullptr is missing
-        if (title) printf(" %s", args[arg]);
-    }
-    if (title) printf(") ------\n");
-    fflush(stdout);
-    if (!null_terminated) {
-        // Fail now, otherwise execvp() call on run_command_always() might hang.
-        std::string cmd;
-        format_args(command, args, &cmd);
-        MYLOGE("skipping command %s because its args were not NULL-terminated", cmd.c_str());
-        return -1;
-    }
+    int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options);
 
-    ON_DRY_RUN({ update_progress(timeout_seconds); va_end(ap); return 0; });
+    /* TODO: for now we're simplifying the progress calculation by using the
+     * timeout as the weight. It's a good approximation for most cases, except when calling dumpsys,
+     * where its weight should be much higher proportionally to its timeout.
+     * Ideally, it should use a options.EstimatedDuration() instead...*/
+    UpdateProgress(options.Timeout());
 
-    int status = run_command_always(title, DONT_DROP_ROOT, NORMAL_STDOUT, timeout_seconds, args);
-    va_end(ap);
     return status;
 }
 
-int run_command_as_shell(const char *title, int timeout_seconds, const char *command, ...) {
-    DurationReporter duration_reporter(title);
-    fflush(stdout);
-
-    const char *args[1024] = {command};
-    size_t arg;
-    va_list ap;
-    va_start(ap, command);
-    if (title) printf("------ %s (%s", title, command);
-    bool null_terminated = false;
-    for (arg = 1; arg < sizeof(args) / sizeof(args[0]); ++arg) {
-        args[arg] = va_arg(ap, const char *);
-        if (args[arg] == nullptr) {
-            null_terminated = true;
-            break;
-        }
-        // TODO: null_terminated check is not really working; line below would crash dumpstate if
-        // nullptr is missing
-        if (title) printf(" %s", args[arg]);
-    }
-    if (title) printf(") ------\n");
-    fflush(stdout);
-    if (!null_terminated) {
-        // Fail now, otherwise execvp() call on run_command_always() might hang.
-        std::string cmd;
-        format_args(command, args, &cmd);
-        MYLOGE("skipping command %s because its args were not NULL-terminated", cmd.c_str());
-        return -1;
-    }
-
-    ON_DRY_RUN({ update_progress(timeout_seconds); va_end(ap); return 0; });
-
-    int status = run_command_always(title, DROP_ROOT, NORMAL_STDOUT, timeout_seconds, args);
-    va_end(ap);
-    return status;
-}
-
-/* forks a command and waits for it to finish */
-int run_command_always(const char *title, RootMode root_mode, StdoutMode stdout_mode,
-        int timeout_seconds, const char *args[]) {
-    bool silent = (stdout_mode == REDIRECT_TO_STDERR);
-    // TODO: need to check if args is null-terminated, otherwise execvp will crash dumpstate
-
-    /* TODO: for now we're simplifying the progress calculation by using the timeout as the weight.
-     * It's a good approximation for most cases, except when calling dumpsys, where its weight
-     * should be much higher proportionally to its timeout. */
-    int weight = timeout_seconds;
-
-    const char *command = args[0];
-    uint64_t start = DurationReporter::nanotime();
-    pid_t pid = fork();
-
-    /* handle error case */
-    if (pid < 0) {
-        if (!silent) printf("*** fork: %s\n", strerror(errno));
-        MYLOGE("*** fork: %s\n", strerror(errno));
-        return pid;
-    }
-
-    /* handle child case */
-    if (pid == 0) {
-        if (root_mode == DROP_ROOT && !drop_root_user()) {
-        if (!silent) printf("*** fail todrop root before running %s: %s\n", command,
-                strerror(errno));
-            MYLOGE("*** could not drop root before running %s: %s\n", command, strerror(errno));
-            return -1;
-        }
-
-        if (silent) {
-            // Redirect stderr to stdout
-            dup2(STDERR_FILENO, STDOUT_FILENO);
-        }
-
-        /* make sure the child dies when dumpstate dies */
-        prctl(PR_SET_PDEATHSIG, SIGKILL);
-
-        /* just ignore SIGPIPE, will go down with parent's */
-        struct sigaction sigact;
-        memset(&sigact, 0, sizeof(sigact));
-        sigact.sa_handler = SIG_IGN;
-        sigaction(SIGPIPE, &sigact, NULL);
-
-        execvp(command, (char**) args);
-        // execvp's result will be handled after waitpid_with_timeout() below, but if it failed,
-        // it's safer to exit dumpstate.
-        MYLOGD("execvp on command '%s' failed (error: %s)", command, strerror(errno));
-        fflush(stdout);
-        // Must call _exit (instead of exit), otherwise it will corrupt the zip file.
-        _exit(EXIT_FAILURE);
-    }
-
-    /* handle parent case */
-    int status;
-    bool ret = waitpid_with_timeout(pid, timeout_seconds, &status);
-    uint64_t elapsed = DurationReporter::nanotime() - start;
-    std::string cmd; // used to log command and its args
-    if (!ret) {
-        if (errno == ETIMEDOUT) {
-            format_args(command, args, &cmd);
-            if (!silent) printf("*** command '%s' timed out after %.3fs (killing pid %d)\n",
-            cmd.c_str(), (float) elapsed / NANOS_PER_SEC, pid);
-            MYLOGE("command '%s' timed out after %.3fs (killing pid %d)\n", cmd.c_str(),
-                   (float) elapsed / NANOS_PER_SEC, pid);
-        } else {
-            format_args(command, args, &cmd);
-            if (!silent) printf("*** command '%s': Error after %.4fs (killing pid %d)\n",
-            cmd.c_str(), (float) elapsed / NANOS_PER_SEC, pid);
-            MYLOGE("command '%s': Error after %.4fs (killing pid %d)\n", cmd.c_str(),
-                   (float) elapsed / NANOS_PER_SEC, pid);
-        }
-        kill(pid, SIGTERM);
-        if (!waitpid_with_timeout(pid, 5, NULL)) {
-            kill(pid, SIGKILL);
-            if (!waitpid_with_timeout(pid, 5, NULL)) {
-                if (!silent) printf("could not kill command '%s' (pid %d) even with SIGKILL.\n",
-                        command, pid);
-                MYLOGE("could not kill command '%s' (pid %d) even with SIGKILL.\n", command, pid);
-            }
-        }
-        return -1;
-    } else if (status) {
-        format_args(command, args, &cmd);
-        if (!silent) printf("*** command '%s' failed: %s\n", cmd.c_str(), strerror(errno));
-        MYLOGE("command '%s' failed: %s\n", cmd.c_str(), strerror(errno));
-        return -2;
-    }
-
-    if (WIFSIGNALED(status)) {
-        if (!silent) printf("*** %s: Killed by signal %d\n", command, WTERMSIG(status));
-        MYLOGE("*** %s: Killed by signal %d\n", command, WTERMSIG(status));
-    } else if (WIFEXITED(status) && WEXITSTATUS(status) > 0) {
-        if (!silent) printf("*** %s: Exit code %d\n", command, WEXITSTATUS(status));
-        MYLOGE("*** %s: Exit code %d\n", command, WEXITSTATUS(status));
-    }
-
-    if (weight > 0) {
-        update_progress(weight);
-    }
-    return status;
-}
-
-bool drop_root_user() {
-    if (getgid() == AID_SHELL && getuid() == AID_SHELL) {
-        MYLOGD("drop_root_user(): already running as Shell");
-        return true;
-    }
-    /* ensure we will keep capabilities when we drop root */
-    if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
-        MYLOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno));
-        return false;
-    }
-
-    gid_t groups[] = { AID_LOG, AID_SDCARD_R, AID_SDCARD_RW,
-            AID_MOUNT, AID_INET, AID_NET_BW_STATS, AID_READPROC,
-            AID_BLUETOOTH };
-    if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
-        MYLOGE("Unable to setgroups, aborting: %s\n", strerror(errno));
-        return false;
-    }
-    if (setgid(AID_SHELL) != 0) {
-        MYLOGE("Unable to setgid, aborting: %s\n", strerror(errno));
-        return false;
-    }
-    if (setuid(AID_SHELL) != 0) {
-        MYLOGE("Unable to setuid, aborting: %s\n", strerror(errno));
-        return false;
-    }
-
-    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;
-    capheader.pid = 0;
-
-    capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG);
-    capdata[CAP_TO_INDEX(CAP_SYSLOG)].effective = CAP_TO_MASK(CAP_SYSLOG);
-    capdata[0].inheritable = 0;
-    capdata[1].inheritable = 0;
-
-    if (capset(&capheader, &capdata[0]) < 0) {
-        MYLOGE("capset failed: %s\n", strerror(errno));
-        return false;
-    }
-
-    return true;
-}
-
-void send_broadcast(const std::string& action, const std::vector<std::string>& args) {
-    if (args.size() > 1000) {
-        MYLOGE("send_broadcast: too many arguments (%d)\n", (int) args.size());
-        return;
-    }
-    const char *am_args[1024] = { "/system/bin/am", "broadcast", "--user", "0", "-a",
-                                  action.c_str() };
-    size_t am_index = 5; // Starts at the index of last initial value above.
-    for (const std::string& arg : args) {
-        am_args[++am_index] = arg.c_str();
-    }
-    // Always terminate with NULL.
-    am_args[am_index + 1] = NULL;
-    std::string args_string;
-    format_args(am_index + 1, am_args, &args_string);
-    MYLOGD("send_broadcast command: %s\n", args_string.c_str());
-    run_command_always(NULL, DROP_ROOT, REDIRECT_TO_STDERR, 20, am_args);
-}
-
-size_t num_props = 0;
-static char* props[2000];
-
-static void print_prop(const char *key, const char *name, void *user) {
-    (void) user;
-    if (num_props < sizeof(props) / sizeof(props[0])) {
-        char buf[PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX + 10];
-        snprintf(buf, sizeof(buf), "[%s]: [%s]\n", key, name);
-        props[num_props++] = strdup(buf);
-    }
-}
-
-static int compare_prop(const void *a, const void *b) {
-    return strcmp(*(char * const *) a, *(char * const *) b);
-}
-
-/* prints all the system properties */
-void print_properties() {
-    const char* title = "SYSTEM PROPERTIES";
-    DurationReporter duration_reporter(title);
-    printf("------ %s ------\n", title);
-    ON_DRY_RUN_RETURN();
-    size_t i;
-    num_props = 0;
-    property_list(print_prop, NULL);
-    qsort(&props, num_props, sizeof(props[0]), compare_prop);
-
-    for (i = 0; i < num_props; ++i) {
-        fputs(props[i], stdout);
-        free(props[i]);
-    }
-    printf("\n");
+void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
+                           const CommandOptions& options, long dumpsysTimeout) {
+    long timeout = dumpsysTimeout > 0 ? dumpsysTimeout : options.Timeout();
+    std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-t", std::to_string(timeout)};
+    dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end());
+    RunCommand(title, dumpsys, options);
 }
 
 int open_socket(const char *service) {
@@ -974,11 +783,11 @@
     }
 }
 
-/* redirect output to a file */
-void redirect_to_file(FILE *redirect, char *path) {
+void _redirect_to_file(FILE *redirect, char *path, int truncate_flag) {
     create_parent_dirs(path);
 
-    int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+    int fd = TEMP_FAILURE_RETRY(open(path,
+                                     O_WRONLY | O_CREAT | truncate_flag | O_CLOEXEC | O_NOFOLLOW,
                                      S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
     if (fd < 0) {
         MYLOGE("%s: %s\n", path, strerror(errno));
@@ -989,6 +798,23 @@
     close(fd);
 }
 
+void redirect_to_file(FILE *redirect, char *path) {
+    _redirect_to_file(redirect, path, O_TRUNC);
+}
+
+void redirect_to_existing_file(FILE *redirect, char *path) {
+    _redirect_to_file(redirect, path, O_APPEND);
+}
+
+static bool should_dump_hal_interface(const char* interface) {
+    for (const char** i = hal_interfaces_to_dump; *i; i++) {
+        if (!strcmp(*i, interface)) {
+            return true;
+        }
+    }
+    return false;
+}
+
 static bool should_dump_native_traces(const char* path) {
     for (const char** p = native_processes_to_dump; *p; p++) {
         if (!strcmp(*p, path)) {
@@ -998,42 +824,70 @@
     return false;
 }
 
+std::set<int> get_interesting_hal_pids() {
+    using android::hidl::manager::V1_0::IServiceManager;
+    using android::sp;
+    using android::hardware::Return;
+
+    sp<IServiceManager> manager = IServiceManager::getService();
+    std::set<int> pids;
+
+    Return<void> ret = manager->debugDump([&](auto& hals) {
+        for (const auto &info : hals) {
+            if (info.pid == static_cast<int>(IServiceManager::PidConstant::NO_PID)) {
+                continue;
+            }
+
+            if (!should_dump_hal_interface(info.interfaceName.c_str())) {
+                continue;
+            }
+
+            pids.insert(info.pid);
+        }
+    });
+
+    if (!ret.isOk()) {
+        MYLOGE("Could not get list of HAL PIDs: %s\n", ret.description().c_str());
+    }
+
+    return pids; // whether it was okay or not
+}
+
 /* dump Dalvik and native stack traces, return the trace file location (NULL if none) */
 const char *dump_traces() {
-    DurationReporter duration_reporter("DUMP TRACES", NULL);
-    ON_DRY_RUN_RETURN(NULL);
-    const char* result = NULL;
+    DurationReporter duration_reporter("DUMP TRACES");
 
-    char traces_path[PROPERTY_VALUE_MAX] = "";
-    property_get("dalvik.vm.stack-trace-file", traces_path, "");
-    if (!traces_path[0]) return NULL;
+    const char* result = nullptr;
+
+    std::string traces_path = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
+    if (traces_path.empty()) return nullptr;
 
     /* move the old traces.txt (if any) out of the way temporarily */
-    char anr_traces_path[PATH_MAX];
-    strlcpy(anr_traces_path, traces_path, sizeof(anr_traces_path));
-    strlcat(anr_traces_path, ".anr", sizeof(anr_traces_path));
-    if (rename(traces_path, anr_traces_path) && errno != ENOENT) {
-        MYLOGE("rename(%s, %s): %s\n", traces_path, anr_traces_path, strerror(errno));
-        return NULL;  // Can't rename old traces.txt -- no permission? -- leave it alone instead
+    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, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW | O_CLOEXEC,
-                                     0666));  /* -rw-rw-rw- */
+    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, strerror(errno));
-        return NULL;
+        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, strerror(errno));
+        MYLOGE("fchmod on %s failed: %s\n", traces_path.c_str(), strerror(errno));
         close(fd);
-        return NULL;
+        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");
@@ -1049,9 +903,9 @@
         goto error_close_fd;
     }
 
-    wfd = inotify_add_watch(ifd, traces_path, IN_CLOSE_WRITE);
+    wfd = inotify_add_watch(ifd, traces_path.c_str(), IN_CLOSE_WRITE);
     if (wfd < 0) {
-        MYLOGE("inotify_add_watch(%s): %s\n", traces_path, strerror(errno));
+        MYLOGE("inotify_add_watch(%s): %s\n", traces_path.c_str(), strerror(errno));
         goto error_close_ifd;
     }
 
@@ -1084,7 +938,7 @@
             }
 
             ++dalvik_found;
-            uint64_t start = DurationReporter::nanotime();
+            uint64_t start = Nanotime();
             if (kill(pid, SIGQUIT)) {
                 MYLOGE("kill(%d, SIGQUIT): %s\n", pid, strerror(errno));
                 continue;
@@ -1092,7 +946,7 @@
 
             /* wait for the writable-close notification from inotify */
             struct pollfd pfd = { ifd, POLLIN, 0 };
-            int ret = poll(&pfd, 1, 5000);  /* 5 sec timeout */
+            int ret = poll(&pfd, 1, TRACE_DUMP_TIMEOUT_MS);
             if (ret < 0) {
                 MYLOGE("poll: %s\n", strerror(errno));
             } else if (ret == 0) {
@@ -1105,16 +959,17 @@
             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)(DurationReporter::nanotime() - start) / NANOS_PER_SEC);
+                dprintf(fd, "[dump dalvik stack %d: %.3fs elapsed]\n", pid,
+                        (float)(Nanotime() - start) / NANOS_PER_SEC);
             }
-        } else if (should_dump_native_traces(data)) {
+        } 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 = DurationReporter::nanotime();
+                uint64_t start = Nanotime();
 
                 /* If 3 backtrace dumps fail in a row, consider debuggerd dead. */
                 if (timeout_failures == 3) {
@@ -1125,8 +980,8 @@
                 } else {
                     timeout_failures = 0;
                 }
-                dprintf(fd, "[dump native stack %d: %.3fs elapsed]\n",
-                        pid, (float)(DurationReporter::nanotime() - start) / NANOS_PER_SEC);
+                dprintf(fd, "[dump native stack %d: %.3fs elapsed]\n", pid,
+                        (float)(Nanotime() - start) / NANOS_PER_SEC);
             }
         }
     }
@@ -1135,17 +990,17 @@
         MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
     }
 
-    static char dump_traces_path[PATH_MAX];
-    strlcpy(dump_traces_path, traces_path, sizeof(dump_traces_path));
-    strlcat(dump_traces_path, ".bugreport", sizeof(dump_traces_path));
-    if (rename(traces_path, dump_traces_path)) {
-        MYLOGE("rename(%s, %s): %s\n", traces_path, dump_traces_path, strerror(errno));
+    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 = dump_traces_path;
+    result = dumptraces_path.c_str();
 
     /* replace the saved [ANR] traces.txt file */
-    rename(anr_traces_path, traces_path);
+    rename(anrtraces_path.c_str(), traces_path.c_str());
 
 error_close_ifd:
     close(ifd);
@@ -1156,9 +1011,9 @@
 
 void dump_route_tables() {
     DurationReporter duration_reporter("DUMP ROUTE TABLES");
-    ON_DRY_RUN_RETURN();
+    if (PropertiesHelper::IsDryRun()) return;
     const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
-    dump_file("RT_TABLES", RT_TABLES_PATH);
+    ds.DumpFile("RT_TABLES", RT_TABLES_PATH);
     FILE* fp = fopen(RT_TABLES_PATH, "re");
     if (!fp) {
         printf("*** %s: %s\n", RT_TABLES_PATH, strerror(errno));
@@ -1169,72 +1024,67 @@
     // need the table number. It's a 32-bit unsigned number, so max 10 chars. Skip the table name.
     // Add a fixed max limit so this doesn't go awry.
     for (int i = 0; i < 64 && fscanf(fp, " %10s %*s", table) == 1; ++i) {
-        run_command("ROUTE TABLE IPv4", 10, "ip", "-4", "route", "show", "table", table, NULL);
-        run_command("ROUTE TABLE IPv6", 10, "ip", "-6", "route", "show", "table", table, NULL);
+        RunCommand("ROUTE TABLE IPv4", {"ip", "-4", "route", "show", "table", table});
+        RunCommand("ROUTE TABLE IPv6", {"ip", "-6", "route", "show", "table", table});
     }
     fclose(fp);
 }
 
-/* overall progress */
-int progress = 0;
-int do_update_progress = 0; // Set by dumpstate.cpp
-int weight_total = WEIGHT_TOTAL;
-
 // TODO: make this function thread safe if sections are generated in parallel.
-void update_progress(int delta) {
-    if (!do_update_progress) return;
+void Dumpstate::UpdateProgress(int32_t delta) {
+    if (progress_ == nullptr) {
+        MYLOGE("UpdateProgress: progress_ not set\n");
+        return;
+    }
 
-    progress += delta;
+    // Always update progess so stats can be tuned...
+    bool max_changed = progress_->Inc(delta);
 
-    char key[PROPERTY_KEY_MAX];
-    char value[PROPERTY_VALUE_MAX];
+    // ...but only notifiy listeners when necessary.
+    if (!update_progress_) return;
+
+    int progress = progress_->Get();
+    int max = progress_->GetMax();
 
     // adjusts max on the fly
-    if (progress > weight_total) {
-        int new_total = weight_total * 1.2;
-        MYLOGD("Adjusting total weight from %d to %d\n", weight_total, new_total);
-        weight_total = new_total;
-        snprintf(key, sizeof(key), "dumpstate.%d.max", getpid());
-        snprintf(value, sizeof(value), "%d", weight_total);
-        int status = property_set(key, value);
-        if (status) {
-            MYLOGE("Could not update max weight by setting system property %s to %s: %d\n",
-                    key, value, status);
+    if (max_changed && listener_ != nullptr) {
+        listener_->onMaxProgressUpdated(max);
+    }
+
+    int32_t last_update_delta = progress - last_updated_progress_;
+    if (last_updated_progress_ > 0 && last_update_delta < update_progress_threshold_) {
+        return;
+    }
+    last_updated_progress_ = progress;
+
+    if (control_socket_fd_ >= 0) {
+        dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max);
+        fsync(control_socket_fd_);
+    }
+
+    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);
+        } 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);
         }
+        listener_->onProgressUpdated(progress);
     }
+}
 
-    snprintf(key, sizeof(key), "dumpstate.%d.progress", getpid());
-    snprintf(value, sizeof(value), "%d", progress);
-
-    if (progress % 100 == 0) {
-        // We don't want to spam logcat, so only log multiples of 100.
-        MYLOGD("Setting progress (%s): %s/%d\n", key, value, weight_total);
+void Dumpstate::TakeScreenshot(const std::string& path) {
+    const std::string& real_path = path.empty() ? screenshot_path_ : path;
+    int status =
+        RunCommand("", {"/system/bin/screencap", "-p", real_path},
+                   CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
+    if (status == 0) {
+        MYLOGD("Screenshot saved on %s\n", real_path.c_str());
     } else {
-        // stderr is ignored on normal invocations, but useful when calling /system/bin/dumpstate
-        // directly for debuggging.
-        fprintf(stderr, "Setting progress (%s): %s/%d\n", key, value, weight_total);
+        MYLOGE("Failed to take screenshot on %s\n", real_path.c_str());
     }
-
-    if (control_socket_fd >= 0) {
-        dprintf(control_socket_fd, "PROGRESS:%d/%d\n", progress, weight_total);
-        fsync(control_socket_fd);
-    }
-
-    int status = property_set(key, value);
-    if (status) {
-        MYLOGE("Could not update progress by setting system property %s to %s: %d\n",
-                key, value, status);
-    }
-}
-
-void take_screenshot(const std::string& path) {
-    const char *args[] = { "/system/bin/screencap", "-p", path.c_str(), NULL };
-    run_command_always(NULL, DONT_DROP_ROOT, REDIRECT_TO_STDERR, 10, args);
-}
-
-void vibrate(FILE* vibrator, int ms) {
-    fprintf(vibrator, "%d\n", ms);
-    fflush(vibrator);
 }
 
 bool is_dir(const char* pathname) {
@@ -1278,19 +1128,16 @@
     int ext_csd_rev = 0;
     std::string sub = buffer.substr(EXT_CSD_REV, sizeof(hex));
     if (sscanf(sub.c_str(), "%2x", &ext_csd_rev) != 1) {
-        printf("*** %s: EXT_CSD_REV parse error \"%s\"\n\n",
-               ext_csd_path, sub.c_str());
+        printf("*** %s: EXT_CSD_REV parse error \"%s\"\n\n", ext_csd_path, sub.c_str());
         return;
     }
 
     static const char *ver_str[] = {
         "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0"
     };
-    printf("rev 1.%d (MMC %s)\n",
-           ext_csd_rev,
-           (ext_csd_rev < (int)(sizeof(ver_str) / sizeof(ver_str[0]))) ?
-               ver_str[ext_csd_rev] :
-               "Unknown");
+    printf("rev 1.%d (MMC %s)\n", ext_csd_rev,
+           (ext_csd_rev < (int)(sizeof(ver_str) / sizeof(ver_str[0]))) ? ver_str[ext_csd_rev]
+                                                                       : "Unknown");
     if (ext_csd_rev < 7) {
         printf("\n");
         return;
@@ -1304,8 +1151,7 @@
     int ext_pre_eol_info = 0;
     sub = buffer.substr(EXT_PRE_EOL_INFO, sizeof(hex));
     if (sscanf(sub.c_str(), "%2x", &ext_pre_eol_info) != 1) {
-        printf("*** %s: PRE_EOL_INFO parse error \"%s\"\n\n",
-               ext_csd_path, sub.c_str());
+        printf("*** %s: PRE_EOL_INFO parse error \"%s\"\n\n", ext_csd_path, sub.c_str());
         return;
     }
 
@@ -1315,11 +1161,10 @@
         "Warning (consumed 80% of reserve)",
         "Urgent (consumed 90% of reserve)"
     };
-    printf("PRE_EOL_INFO %d (MMC %s)\n",
-           ext_pre_eol_info,
-           eol_str[(ext_pre_eol_info < (int)
-                       (sizeof(eol_str) / sizeof(eol_str[0]))) ?
-                           ext_pre_eol_info : 0]);
+    printf(
+        "PRE_EOL_INFO %d (MMC %s)\n", ext_pre_eol_info,
+        eol_str[(ext_pre_eol_info < (int)(sizeof(eol_str) / sizeof(eol_str[0]))) ? ext_pre_eol_info
+                                                                                 : 0]);
 
     for (size_t lifetime = EXT_DEVICE_LIFE_TIME_EST_TYP_A;
             lifetime <= EXT_DEVICE_LIFE_TIME_EST_TYP_B;
@@ -1348,48 +1193,18 @@
         ext_device_life_time_est = 0;
         sub = buffer.substr(lifetime, sizeof(hex));
         if (sscanf(sub.c_str(), "%2x", &ext_device_life_time_est) != 1) {
-            printf("*** %s: DEVICE_LIFE_TIME_EST_TYP_%c parse error \"%s\"\n",
-                   ext_csd_path,
-                   (unsigned)((lifetime - EXT_DEVICE_LIFE_TIME_EST_TYP_A) /
-                              sizeof(hex)) + 'A',
+            printf("*** %s: DEVICE_LIFE_TIME_EST_TYP_%c parse error \"%s\"\n", ext_csd_path,
+                   (unsigned)((lifetime - EXT_DEVICE_LIFE_TIME_EST_TYP_A) / sizeof(hex)) + 'A',
                    sub.c_str());
             continue;
         }
         printf("DEVICE_LIFE_TIME_EST_TYP_%c %d (MMC %s)\n",
-               (unsigned)((lifetime - EXT_DEVICE_LIFE_TIME_EST_TYP_A) /
-                          sizeof(hex)) + 'A',
+               (unsigned)((lifetime - EXT_DEVICE_LIFE_TIME_EST_TYP_A) / sizeof(hex)) + 'A',
                ext_device_life_time_est,
-               est_str[(ext_device_life_time_est < (int)
-                           (sizeof(est_str) / sizeof(est_str[0]))) ?
-                               ext_device_life_time_est : 0]);
+               est_str[(ext_device_life_time_est < (int)(sizeof(est_str) / sizeof(est_str[0])))
+                           ? ext_device_life_time_est
+                           : 0]);
     }
 
     printf("\n");
 }
-
-// TODO: refactor all those commands that convert args
-void format_args(int argc, const char *argv[], std::string *args) {
-    LOG_ALWAYS_FATAL_IF(args == nullptr);
-    for (int i = 0; i < argc; i++) {
-        args->append(argv[i]);
-        if (i < argc -1) {
-          args->append(" ");
-        }
-    }
-}
-void format_args(const char* command, const char *args[], std::string *string) {
-    LOG_ALWAYS_FATAL_IF(args == nullptr || command == nullptr);
-    string->append(command);
-    if (args[0] == nullptr) return;
-    string->append(" ");
-
-    for (int arg = 1; arg <= 1000; ++arg) {
-        if (args[arg] == nullptr) return;
-        string->append(args[arg]);
-        if (args[arg+1] != nullptr) {
-            string->append(" ");
-        }
-    }
-    // TODO: not really working: if NULL is missing, it will crash dumpstate.
-    MYLOGE("internal error: missing NULL entry on %s", string->c_str());
-}
diff --git a/cmds/dumpsys/.clang-format b/cmds/dumpsys/.clang-format
new file mode 100644
index 0000000..fc4eb1b
--- /dev/null
+++ b/cmds/dumpsys/.clang-format
@@ -0,0 +1,13 @@
+BasedOnStyle: Google
+AllowShortBlocksOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+
+AccessModifierOffset: -2
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
+UseTab: Never
+PenaltyExcessCharacter: 32
diff --git a/cmds/dumpsys/Android.bp b/cmds/dumpsys/Android.bp
new file mode 100644
index 0000000..3476964
--- /dev/null
+++ b/cmds/dumpsys/Android.bp
@@ -0,0 +1,50 @@
+cc_defaults {
+    name: "dumpsys_defaults",
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    srcs: [
+        "dumpsys.cpp",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "libutils",
+        "liblog",
+        "libbinder",
+    ],
+
+    clang: true,
+}
+
+//
+// Static library used in testing and executable
+//
+
+cc_library_static {
+    name: "libdumpsys",
+
+    defaults: ["dumpsys_defaults"],
+
+    export_include_dirs: ["."],
+}
+
+
+//
+// Executable
+//
+
+cc_binary {
+    name: "dumpsys",
+
+    defaults: ["dumpsys_defaults"],
+
+    srcs: [
+        "main.cpp",
+    ],
+}
+
+subdirs = ["tests"]
diff --git a/cmds/dumpsys/Android.mk b/cmds/dumpsys/Android.mk
deleted file mode 100644
index 8335c14..0000000
--- a/cmds/dumpsys/Android.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	dumpsys.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libbase \
-	libutils \
-	liblog \
-	libbinder
-
-
-ifeq ($(TARGET_OS),linux)
-	LOCAL_CFLAGS += -DXP_UNIX
-	#LOCAL_SHARED_LIBRARIES += librt
-endif
-
-LOCAL_MODULE:= dumpsys
-
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index d19e98a..f0e7200 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -1,10 +1,19 @@
 /*
- * Command that dumps interesting system state to the log.
+ * Copyright (C) 2009 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 "dumpsys"
-
 #include <algorithm>
 #include <chrono>
 #include <thread>
@@ -12,7 +21,6 @@
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
 #include <android-base/unique_fd.h>
-#include <binder/IServiceManager.h>
 #include <binder/Parcel.h>
 #include <binder/ProcessState.h>
 #include <binder/TextOutput.h>
@@ -30,6 +38,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include "dumpsys.h"
+
 using namespace android;
 using android::base::StringPrintf;
 using android::base::unique_fd;
@@ -53,7 +63,7 @@
             "         SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
 }
 
-bool IsSkipped(const Vector<String16>& skipped, const String16& service) {
+static bool IsSkipped(const Vector<String16>& skipped, const String16& service) {
     for (const auto& candidate : skipped) {
         if (candidate == service) {
             return true;
@@ -62,17 +72,7 @@
     return false;
 }
 
-int main(int argc, char* const argv[])
-{
-    signal(SIGPIPE, SIG_IGN);
-    sp<IServiceManager> sm = defaultServiceManager();
-    fflush(stdout);
-    if (sm == NULL) {
-        ALOGE("Unable to get default service manager!");
-        aerr << "dumpsys: Unable to get default service manager!" << endl;
-        return 20;
-    }
-
+int Dumpsys::main(int argc, char* const argv[]) {
     Vector<String16> services;
     Vector<String16> args;
     Vector<String16> skippedServices;
@@ -85,6 +85,9 @@
         {     0,           0, 0,  0 }
     };
 
+    // Must reset optind, otherwise subsequent calls will fail (wouldn't happen on main.cpp, but
+    // happens on test cases).
+    optind = 1;
     while (1) {
         int c;
         int optionIndex = 0;
@@ -147,7 +150,7 @@
 
     if (services.empty() || showListOnly) {
         // gets all services
-        services = sm->listServices();
+        services = sm_->listServices();
         services.sort(sort_func);
         args.add(String16("-a"));
     }
@@ -159,8 +162,9 @@
         aout << "Currently running services:" << endl;
 
         for (size_t i=0; i<N; i++) {
-            sp<IBinder> service = sm->checkService(services[i]);
-            if (service != NULL) {
+            sp<IBinder> service = sm_->checkService(services[i]);
+
+            if (service != nullptr) {
                 bool skipped = IsSkipped(skippedServices, services[i]);
                 aout << "  " << services[i] << (skipped ? " (skipped)" : "") << endl;
             }
@@ -175,8 +179,8 @@
         String16 service_name = std::move(services[i]);
         if (IsSkipped(skippedServices, service_name)) continue;
 
-        sp<IBinder> service = sm->checkService(service_name);
-        if (service != NULL) {
+        sp<IBinder> service = sm_->checkService(service_name);
+        if (service != nullptr) {
             int sfd[2];
 
             if (pipe(sfd) != 0) {
@@ -203,7 +207,7 @@
                 // call returns, to terminate our reads if the other end closes their copy of the
                 // file descriptor, but then hangs for some reason. There doesn't seem to be a good
                 // way to do this, though.
-                remote_end.clear();
+                remote_end.reset();
 
                 if (err != 0) {
                     aerr << "Error dumping service info: (" << strerror(err) << ") " << service_name
@@ -262,7 +266,10 @@
             }
 
             if (timed_out) {
-                aout << endl << "*** SERVICE DUMP TIMEOUT EXPIRED ***" << endl << endl;
+                aout << endl
+                     << "*** SERVICE '" << service_name << "' DUMP TIMEOUT (" << timeoutArg
+                     << "s) EXPIRED ***" << endl
+                     << endl;
             }
 
             if (timed_out || error) {
diff --git a/cmds/dumpsys/dumpsys.h b/cmds/dumpsys/dumpsys.h
new file mode 100644
index 0000000..2534dde
--- /dev/null
+++ b/cmds/dumpsys/dumpsys.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#ifndef FRAMEWORK_NATIVE_CMD_DUMPSYS_H_
+#define FRAMEWORK_NATIVE_CMD_DUMPSYS_H_
+
+#include <binder/IServiceManager.h>
+
+namespace android {
+
+class Dumpsys {
+  public:
+    Dumpsys(android::IServiceManager* sm) : sm_(sm) {
+    }
+    int main(int argc, char* const argv[]);
+
+  private:
+    android::IServiceManager* sm_;
+};
+}
+
+#endif  // FRAMEWORK_NATIVE_CMD_DUMPSYS_H_
diff --git a/cmds/dumpsys/main.cpp b/cmds/dumpsys/main.cpp
new file mode 100644
index 0000000..8ba0eba
--- /dev/null
+++ b/cmds/dumpsys/main.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+/*
+ * Command that dumps interesting system state to the log.
+ */
+
+#include "dumpsys.h"
+
+#include <binder/IServiceManager.h>
+#include <binder/TextOutput.h>
+
+#include <signal.h>
+#include <stdio.h>
+
+using namespace android;
+
+int main(int argc, char* const argv[]) {
+    signal(SIGPIPE, SIG_IGN);
+    sp<IServiceManager> sm = defaultServiceManager();
+    fflush(stdout);
+    if (sm == nullptr) {
+        ALOGE("Unable to get default service manager!");
+        aerr << "dumpsys: Unable to get default service manager!" << endl;
+        return 20;
+    }
+
+    Dumpsys dumpsys(sm.get());
+    return dumpsys.main(argc, argv);
+}
diff --git a/cmds/dumpsys/tests/Android.bp b/cmds/dumpsys/tests/Android.bp
new file mode 100644
index 0000000..7698ed5
--- /dev/null
+++ b/cmds/dumpsys/tests/Android.bp
@@ -0,0 +1,19 @@
+// Build the unit tests for dumpsys
+cc_test {
+    name: "dumpsys_test",
+
+    srcs: ["dumpsys_test.cpp"],
+
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libutils",
+    ],
+
+    static_libs: [
+        "libdumpsys",
+        "libgmock",
+    ],
+
+    clang: true,
+}
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
new file mode 100644
index 0000000..66beb6d
--- /dev/null
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -0,0 +1,300 @@
+/*
+ * 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 "../dumpsys.h"
+
+#include <vector>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <android-base/file.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+using namespace android;
+
+using ::testing::_;
+using ::testing::Action;
+using ::testing::ActionInterface;
+using ::testing::DoAll;
+using ::testing::Eq;
+using ::testing::HasSubstr;
+using ::testing::MakeAction;
+using ::testing::Not;
+using ::testing::Return;
+using ::testing::StrEq;
+using ::testing::Test;
+using ::testing::WithArg;
+using ::testing::internal::CaptureStderr;
+using ::testing::internal::CaptureStdout;
+using ::testing::internal::GetCapturedStderr;
+using ::testing::internal::GetCapturedStdout;
+
+class ServiceManagerMock : public IServiceManager {
+  public:
+    MOCK_CONST_METHOD1(getService, sp<IBinder>(const String16&));
+    MOCK_CONST_METHOD1(checkService, sp<IBinder>(const String16&));
+    MOCK_METHOD3(addService, status_t(const String16&, const sp<IBinder>&, bool));
+    MOCK_METHOD0(listServices, Vector<String16>());
+
+  protected:
+    MOCK_METHOD0(onAsBinder, IBinder*());
+};
+
+class BinderMock : public BBinder {
+  public:
+    BinderMock() {
+    }
+
+    MOCK_METHOD2(dump, status_t(int, const Vector<String16>&));
+};
+
+// gmock black magic to provide a WithArg<0>(WriteOnFd(output)) matcher
+typedef void WriteOnFdFunction(int);
+
+class WriteOnFdAction : public ActionInterface<WriteOnFdFunction> {
+  public:
+    explicit WriteOnFdAction(const std::string& output) : output_(output) {
+    }
+    virtual Result Perform(const ArgumentTuple& args) {
+        int fd = ::std::tr1::get<0>(args);
+        android::base::WriteStringToFd(output_, fd);
+    }
+
+  private:
+    std::string output_;
+};
+
+// Matcher used to emulate dump() by writing on its file descriptor.
+Action<WriteOnFdFunction> WriteOnFd(const std::string& output) {
+    return MakeAction(new WriteOnFdAction(output));
+}
+
+// Matcher for args using Android's Vector<String16> format
+// TODO: move it to some common testing library
+MATCHER_P(AndroidElementsAre, expected, "") {
+    std::ostringstream errors;
+    if (arg.size() != expected.size()) {
+        errors << " sizes do not match (expected " << expected.size() << ", got " << arg.size()
+               << ")\n";
+    }
+    int i = 0;
+    std::ostringstream actual_stream, expected_stream;
+    for (String16 actual : arg) {
+        std::string actual_str = String8(actual).c_str();
+        std::string expected_str = expected[i];
+        actual_stream << "'" << actual_str << "' ";
+        expected_stream << "'" << expected_str << "' ";
+        if (actual_str != expected_str) {
+            errors << " element mismatch at index " << i << "\n";
+        }
+        i++;
+    }
+
+    if (!errors.str().empty()) {
+        errors << "\nExpected args: " << expected_stream.str()
+               << "\nActual args: " << actual_stream.str();
+        *result_listener << errors.str();
+        return false;
+    }
+    return true;
+}
+
+// Custom action to sleep for timeout seconds
+ACTION_P(Sleep, timeout) {
+    sleep(timeout);
+}
+
+class DumpsysTest : public Test {
+  public:
+    DumpsysTest() : sm_(), dump_(&sm_), stdout_(), stderr_() {
+    }
+
+    void ExpectListServices(std::vector<std::string> services) {
+        Vector<String16> services16;
+        for (auto& service : services) {
+            services16.add(String16(service.c_str()));
+        }
+        EXPECT_CALL(sm_, listServices()).WillRepeatedly(Return(services16));
+    }
+
+    sp<BinderMock> ExpectCheckService(const char* name, bool running = true) {
+        sp<BinderMock> binder_mock;
+        if (running) {
+            binder_mock = new BinderMock;
+        }
+        EXPECT_CALL(sm_, checkService(String16(name))).WillRepeatedly(Return(binder_mock));
+        return binder_mock;
+    }
+
+    void ExpectDump(const char* name, const std::string& output) {
+        sp<BinderMock> binder_mock = ExpectCheckService(name);
+        EXPECT_CALL(*binder_mock, dump(_, _))
+            .WillRepeatedly(DoAll(WithArg<0>(WriteOnFd(output)), Return(0)));
+    }
+
+    void ExpectDumpWithArgs(const char* name, std::vector<std::string> args,
+                            const std::string& output) {
+        sp<BinderMock> binder_mock = ExpectCheckService(name);
+        EXPECT_CALL(*binder_mock, dump(_, AndroidElementsAre(args)))
+            .WillRepeatedly(DoAll(WithArg<0>(WriteOnFd(output)), Return(0)));
+    }
+
+    void ExpectDumpAndHang(const char* name, int timeout_s, const std::string& output) {
+        sp<BinderMock> binder_mock = ExpectCheckService(name);
+        EXPECT_CALL(*binder_mock, dump(_, _))
+            .WillRepeatedly(DoAll(Sleep(timeout_s), WithArg<0>(WriteOnFd(output)), Return(0)));
+    }
+
+    void CallMain(const std::vector<std::string>& args) {
+        const char* argv[1024] = {"/some/virtual/dir/dumpsys"};
+        int argc = (int)args.size() + 1;
+        int i = 1;
+        for (const std::string& arg : args) {
+            argv[i++] = arg.c_str();
+        }
+        CaptureStdout();
+        CaptureStderr();
+        int status = dump_.main(argc, const_cast<char**>(argv));
+        stdout_ = GetCapturedStdout();
+        stderr_ = GetCapturedStderr();
+        EXPECT_THAT(status, Eq(0));
+    }
+
+    void AssertRunningServices(const std::vector<std::string>& services) {
+        std::string expected("Currently running services:\n");
+        for (const std::string& service : services) {
+            expected.append("  ").append(service).append("\n");
+        }
+        EXPECT_THAT(stdout_, HasSubstr(expected));
+    }
+
+    void AssertOutput(const std::string& expected) {
+        EXPECT_THAT(stdout_, StrEq(expected));
+    }
+
+    void AssertOutputContains(const std::string& expected) {
+        EXPECT_THAT(stdout_, HasSubstr(expected));
+    }
+
+    void AssertDumped(const std::string& service, const std::string& dump) {
+        EXPECT_THAT(stdout_, HasSubstr("DUMP OF SERVICE " + service + ":\n" + dump));
+    }
+
+    void AssertNotDumped(const std::string& dump) {
+        EXPECT_THAT(stdout_, Not(HasSubstr(dump)));
+    }
+
+    void AssertStopped(const std::string& service) {
+        EXPECT_THAT(stderr_, HasSubstr("Can't find service: " + service + "\n"));
+    }
+
+    ServiceManagerMock sm_;
+    Dumpsys dump_;
+
+  private:
+    std::string stdout_, stderr_;
+};
+
+// Tests 'dumpsys -l' when all services are running
+TEST_F(DumpsysTest, ListAllServices) {
+    ExpectListServices({"Locksmith", "Valet"});
+    ExpectCheckService("Locksmith");
+    ExpectCheckService("Valet");
+
+    CallMain({"-l"});
+
+    AssertRunningServices({"Locksmith", "Valet"});
+}
+
+// Tests 'dumpsys -l' when a service is not running
+TEST_F(DumpsysTest, ListRunningServices) {
+    ExpectListServices({"Locksmith", "Valet"});
+    ExpectCheckService("Locksmith");
+    ExpectCheckService("Valet", false);
+
+    CallMain({"-l"});
+
+    AssertRunningServices({"Locksmith"});
+    AssertNotDumped({"Valet"});
+}
+
+// Tests 'dumpsys service_name' on a service is running
+TEST_F(DumpsysTest, DumpRunningService) {
+    ExpectDump("Valet", "Here's your car");
+
+    CallMain({"Valet"});
+
+    AssertOutput("Here's your car");
+}
+
+// Tests 'dumpsys -t 1 service_name' on a service that times out after 2s
+TEST_F(DumpsysTest, DumpRunningServiceTimeout) {
+    ExpectDumpAndHang("Valet", 2, "Here's your car");
+
+    CallMain({"-t", "1", "Valet"});
+
+    AssertOutputContains("SERVICE 'Valet' DUMP TIMEOUT (1s) EXPIRED");
+    AssertNotDumped("Here's your car");
+
+    // Must wait so binder mock is deleted, otherwise test will fail with a leaked object
+    sleep(1);
+}
+
+// Tests 'dumpsys service_name Y U NO HAVE ARGS' on a service that is running
+TEST_F(DumpsysTest, DumpWithArgsRunningService) {
+    ExpectDumpWithArgs("SERVICE", {"Y", "U", "NO", "HANDLE", "ARGS"}, "I DO!");
+
+    CallMain({"SERVICE", "Y", "U", "NO", "HANDLE", "ARGS"});
+
+    AssertOutput("I DO!");
+}
+
+// Tests 'dumpsys' with no arguments
+TEST_F(DumpsysTest, DumpMultipleServices) {
+    ExpectListServices({"running1", "stopped2", "running3"});
+    ExpectDump("running1", "dump1");
+    ExpectCheckService("stopped2", false);
+    ExpectDump("running3", "dump3");
+
+    CallMain({});
+
+    AssertRunningServices({"running1", "running3"});
+    AssertDumped("running1", "dump1");
+    AssertStopped("stopped2");
+    AssertDumped("running3", "dump3");
+}
+
+// Tests 'dumpsys --skip skipped3 skipped5', which should skip these services
+TEST_F(DumpsysTest, DumpWithSkip) {
+    ExpectListServices({"running1", "stopped2", "skipped3", "running4", "skipped5"});
+    ExpectDump("running1", "dump1");
+    ExpectCheckService("stopped2", false);
+    ExpectDump("skipped3", "dump3");
+    ExpectDump("running4", "dump4");
+    ExpectDump("skipped5", "dump5");
+
+    CallMain({"--skip", "skipped3", "skipped5"});
+
+    AssertRunningServices({"running1", "running4", "skipped3 (skipped)", "skipped5 (skipped)"});
+    AssertDumped("running1", "dump1");
+    AssertDumped("running4", "dump4");
+    AssertStopped("stopped2");
+    AssertNotDumped("dump3");
+    AssertNotDumped("dump5");
+}
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index ddf3aa8..dfc3e58 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -25,7 +25,6 @@
  namespace android {
 
 GLHelper::GLHelper() :
-    mGraphicBufferAlloc(new GraphicBufferAlloc()),
     mDisplay(EGL_NO_DISPLAY),
     mContext(EGL_NO_CONTEXT),
     mDummySurface(EGL_NO_SURFACE),
@@ -203,7 +202,7 @@
         sp<GLConsumer>* glConsumer, EGLSurface* surface) {
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
-    BufferQueue::createBufferQueue(&producer, &consumer, mGraphicBufferAlloc);
+    BufferQueue::createBufferQueue(&producer, &consumer);
     sp<GLConsumer> glc = new GLConsumer(consumer, name,
             GL_TEXTURE_EXTERNAL_OES, false, true);
     glc->setDefaultBufferSize(w, h);
@@ -365,6 +364,7 @@
     if (!result) {
         fprintf(stderr, "Shader source:\n");
         printShaderSource(lines);
+        delete[] src;
         return false;
     }
     delete[] src;
diff --git a/cmds/flatland/GLHelper.h b/cmds/flatland/GLHelper.h
index 7a9e9e3..d09463a 100644
--- a/cmds/flatland/GLHelper.h
+++ b/cmds/flatland/GLHelper.h
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <gui/GraphicBufferAlloc.h>
 #include <gui/GLConsumer.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceControl.h>
@@ -75,8 +74,6 @@
 
     bool setUpShaders(const ShaderDesc* shaderDescs, size_t numShaders);
 
-    sp<GraphicBufferAlloc> mGraphicBufferAlloc;
-
     EGLDisplay mDisplay;
     EGLContext mContext;
     EGLSurface mDummySurface;
diff --git a/cmds/flatland/Main.cpp b/cmds/flatland/Main.cpp
index c47b0c8..ec1e543 100644
--- a/cmds/flatland/Main.cpp
+++ b/cmds/flatland/Main.cpp
@@ -16,7 +16,6 @@
 
 #define ATRACE_TAG ATRACE_TAG_ALWAYS
 
-#include <gui/GraphicBufferAlloc.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceControl.h>
 #include <gui/GLConsumer.h>
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
new file mode 100644
index 0000000..33db6db
--- /dev/null
+++ b/cmds/installd/Android.bp
@@ -0,0 +1,75 @@
+cc_defaults {
+    name: "installd_defaults",
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    srcs: [
+        "CacheItem.cpp",
+        "CacheTracker.cpp",
+        "InstalldNativeService.cpp",
+        "dexopt.cpp",
+        "globals.cpp",
+        "utils.cpp",
+        "binder/android/os/IInstalld.aidl",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "liblog",
+        "liblogwrap",
+        "libselinux",
+        "libutils",
+    ],
+
+    clang: true,
+}
+
+//
+// Static library used in testing and executable
+//
+
+cc_library_static {
+    name: "libinstalld",
+    defaults: ["installd_defaults"],
+
+    export_include_dirs: ["."],
+    aidl: {
+        export_aidl_headers: true,
+    },
+}
+
+//
+// Executable
+//
+
+cc_binary {
+    name: "installd",
+    defaults: ["installd_defaults"],
+    srcs: ["installd.cpp"],
+
+    static_libs: ["libdiskusage"],
+
+    init_rc: ["installd.rc"],
+}
+
+// OTA chroot tool
+
+cc_binary {
+    name: "otapreopt_chroot",
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    clang: true,
+
+    srcs: ["otapreopt_chroot.cpp"],
+    shared_libs: [
+        "libbase",
+        "liblog",
+    ],
+}
+
+subdirs = ["tests"]
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
index 86df596..1d21b3c 100644
--- a/cmds/installd/Android.mk
+++ b/cmds/installd/Android.mk
@@ -1,56 +1,12 @@
 LOCAL_PATH := $(call my-dir)
 
-common_src_files := commands.cpp globals.cpp utils.cpp
-common_cflags := -Wall -Werror
-
-#
-# Static library used in testing and executable
-#
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libinstalld
-LOCAL_MODULE_TAGS := eng tests
-LOCAL_SRC_FILES := $(common_src_files)
-LOCAL_CFLAGS := $(common_cflags)
-LOCAL_SHARED_LIBRARIES := \
-    libbase \
-    liblogwrap \
-    libselinux \
-
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-LOCAL_CLANG := true
-include $(BUILD_STATIC_LIBRARY)
-
-#
-# Executable
-#
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := installd
-LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := $(common_cflags)
-LOCAL_SRC_FILES := installd.cpp $(common_src_files)
-LOCAL_SHARED_LIBRARIES := \
-    libbase \
-    libcutils \
-    liblog \
-    liblogwrap \
-    libselinux \
-
-LOCAL_STATIC_LIBRARIES := libdiskusage
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-LOCAL_INIT_RC := installd.rc
-LOCAL_CLANG := true
-include $(BUILD_EXECUTABLE)
-
 #
 # OTA Executable
 #
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := otapreopt
-LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := $(common_cflags)
+LOCAL_CFLAGS := -Wall -Werror
 
 # Base & ASLR boundaries for boot image creation.
 ifndef LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA
@@ -67,32 +23,17 @@
 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 $(common_src_files)
+LOCAL_SRC_FILES := otapreopt.cpp globals.cpp utils.cpp dexopt.cpp
+LOCAL_HEADER_LIBRARIES := dex2oat_headers
 LOCAL_SHARED_LIBRARIES := \
     libbase \
     libcutils \
     liblog \
     liblogwrap \
     libselinux \
+    libutils \
 
 LOCAL_STATIC_LIBRARIES := libdiskusage
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-LOCAL_CLANG := true
-include $(BUILD_EXECUTABLE)
-
-# OTA chroot tool
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := otapreopt_chroot
-LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := $(common_cflags)
-
-LOCAL_SRC_FILES := otapreopt_chroot.cpp
-LOCAL_SHARED_LIBRARIES := \
-    libbase \
-    liblog \
-
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 LOCAL_CLANG := true
 include $(BUILD_EXECUTABLE)
 
@@ -120,7 +61,3 @@
 LOCAL_REQUIRED_MODULES := otapreopt otapreopt_chroot otapreopt_slot
 
 include $(BUILD_PREBUILT)
-
-# Tests.
-
-include $(LOCAL_PATH)/tests/Android.mk
\ No newline at end of file
diff --git a/cmds/installd/CacheItem.cpp b/cmds/installd/CacheItem.cpp
new file mode 100644
index 0000000..515f915
--- /dev/null
+++ b/cmds/installd/CacheItem.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CacheItem.h"
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <sys/xattr.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+#include "utils.h"
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+CacheItem::CacheItem(FTSENT* p) {
+    level = p->fts_level;
+    directory = S_ISDIR(p->fts_statp->st_mode);
+    size = p->fts_statp->st_blocks * 512;
+    modified = p->fts_statp->st_mtime;
+
+    mParent = static_cast<CacheItem*>(p->fts_parent->fts_pointer);
+    if (mParent) {
+        group = mParent->group;
+        tombstone = mParent->tombstone;
+        mName = p->fts_name;
+        mName.insert(0, "/");
+    } else {
+        group = false;
+        tombstone = false;
+        mName = p->fts_path;
+    }
+}
+
+CacheItem::~CacheItem() {
+}
+
+std::string CacheItem::toString() {
+    return StringPrintf("%s size=%" PRId64 " mod=%ld", buildPath().c_str(), size, modified);
+}
+
+std::string CacheItem::buildPath() {
+    std::string res = mName;
+    CacheItem* parent = mParent;
+    while (parent) {
+        res.insert(0, parent->mName);
+        parent = parent->mParent;
+    }
+    return res;
+}
+
+int CacheItem::purge() {
+    int res = 0;
+    auto path = buildPath();
+    if (directory) {
+        FTS *fts;
+        FTSENT *p;
+        char *argv[] = { (char*) path.c_str(), nullptr };
+        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+            PLOG(WARNING) << "Failed to fts_open " << path;
+            return -1;
+        }
+        while ((p = fts_read(fts)) != nullptr) {
+            switch (p->fts_info) {
+            case FTS_D:
+                if (p->fts_level == 0) {
+                    p->fts_number = tombstone;
+                } else {
+                    p->fts_number = p->fts_parent->fts_number
+                            | (getxattr(p->fts_path, kXattrCacheTombstone, nullptr, 0) >= 0);
+                }
+                break;
+            case FTS_F:
+                if (p->fts_parent->fts_number) {
+                    if (truncate(p->fts_path, 0) != 0) {
+                        PLOG(WARNING) << "Failed to truncate " << p->fts_path;
+                        res = -1;
+                    }
+                } else {
+                    if (unlink(p->fts_path) != 0) {
+                        PLOG(WARNING) << "Failed to unlink " << p->fts_path;
+                        res = -1;
+                    }
+                }
+                break;
+            case FTS_DEFAULT:
+            case FTS_SL:
+            case FTS_SLNONE:
+                if (unlink(p->fts_path) != 0) {
+                    PLOG(WARNING) << "Failed to unlink " << p->fts_path;
+                    res = -1;
+                }
+                break;
+            case FTS_DP:
+                if (rmdir(p->fts_path) != 0) {
+                    PLOG(WARNING) << "Failed to rmdir " << p->fts_path;
+                    res = -1;
+                }
+                break;
+            }
+        }
+    } else {
+        if (tombstone) {
+            if (truncate(path.c_str(), 0) != 0) {
+                PLOG(WARNING) << "Failed to truncate " << path;
+                res = -1;
+            }
+        } else {
+            if (unlink(path.c_str()) != 0) {
+                PLOG(WARNING) << "Failed to unlink " << path;
+                res = -1;
+            }
+        }
+    }
+    return res;
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/CacheItem.h b/cmds/installd/CacheItem.h
new file mode 100644
index 0000000..84b77aa
--- /dev/null
+++ b/cmds/installd/CacheItem.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_INSTALLD_CACHE_ITEM_H
+#define ANDROID_INSTALLD_CACHE_ITEM_H
+
+#include <memory>
+#include <string>
+
+#include <fts.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <android-base/macros.h>
+
+namespace android {
+namespace installd {
+
+/**
+ * Single cache item that can be purged to free up space. This may be an
+ * isolated file, or an entire directory tree that should be deleted as a
+ * group.
+ */
+class CacheItem {
+public:
+    CacheItem(FTSENT* p);
+    ~CacheItem();
+
+    std::string toString();
+    std::string buildPath();
+
+    int purge();
+
+    short level;
+    bool directory;
+    bool group;
+    bool tombstone;
+    int64_t size;
+    time_t modified;
+
+private:
+    CacheItem* mParent;
+    std::string mName;
+
+    DISALLOW_COPY_AND_ASSIGN(CacheItem);
+};
+
+}  // namespace installd
+}  // namespace android
+
+#endif  // ANDROID_INSTALLD_CACHE_ITEM_H
diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp
new file mode 100644
index 0000000..e293948
--- /dev/null
+++ b/cmds/installd/CacheTracker.cpp
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
+
+#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 "utils.h"
+
+using android::base::StringPrintf;
+
+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() {
+}
+
+std::string CacheTracker::toString() {
+    return StringPrintf("UID=%d used=%" PRId64 " quota=%" PRId64 " ratio=%d",
+            multiuser_get_uid(mUserId, mAppId), cacheUsed, cacheQuota, getCacheRatio());
+}
+
+void CacheTracker::addDataPath(const std::string& dataPath) {
+    mDataPaths.push_back(dataPath);
+}
+
+void CacheTracker::loadStats() {
+    ATRACE_BEGIN("loadStats quota");
+    cacheUsed = 0;
+    if (loadQuotaStats()) {
+        return;
+    }
+    ATRACE_END();
+
+    ATRACE_BEGIN("loadStats tree");
+    cacheUsed = 0;
+    for (auto path : mDataPaths) {
+        auto cachePath = read_path_inode(path, "cache", kXattrInodeCache);
+        auto codeCachePath = read_path_inode(path, "code_cache", kXattrInodeCodeCache);
+        calculate_tree_size(cachePath, &cacheUsed);
+        calculate_tree_size(codeCachePath, &cacheUsed);
+    }
+    ATRACE_END();
+}
+
+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;
+        } else {
+            cacheUsed += dq.dqb_curspace;
+        }
+
+        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;
+        } else {
+            cacheUsed += dq.dqb_curspace;
+        }
+        return true;
+    } else {
+        return false;
+    }
+}
+
+void CacheTracker::loadItemsFrom(const std::string& path) {
+    FTS *fts;
+    FTSENT *p;
+    char *argv[] = { (char*) path.c_str(), nullptr };
+    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+        PLOG(WARNING) << "Failed to fts_open " << path;
+        return;
+    }
+    while ((p = fts_read(fts)) != nullptr) {
+        if (p->fts_level == 0) continue;
+
+        // Create tracking nodes for everything we encounter
+        switch (p->fts_info) {
+        case FTS_D:
+        case FTS_DEFAULT:
+        case FTS_F:
+        case FTS_SL:
+        case FTS_SLNONE: {
+            auto item = std::shared_ptr<CacheItem>(new CacheItem(p));
+            p->fts_pointer = static_cast<void*>(item.get());
+            items.push_back(item);
+        }
+        }
+
+        switch (p->fts_info) {
+        case FTS_D: {
+            auto item = static_cast<CacheItem*>(p->fts_pointer);
+            item->group |= (getxattr(p->fts_path, kXattrCacheGroup, nullptr, 0) >= 0);
+            item->tombstone |= (getxattr(p->fts_path, kXattrCacheTombstone, nullptr, 0) >= 0);
+
+            // When group, immediately collect all files under tree
+            if (item->group) {
+                while ((p = fts_read(fts)) != nullptr) {
+                    if (p->fts_info == FTS_DP && p->fts_level == item->level) break;
+                    switch (p->fts_info) {
+                    case FTS_D:
+                    case FTS_DEFAULT:
+                    case FTS_F:
+                    case FTS_SL:
+                    case FTS_SLNONE:
+                        item->size += p->fts_statp->st_blocks * 512;
+                        item->modified = std::max(item->modified, p->fts_statp->st_mtime);
+                    }
+                }
+            }
+        }
+        }
+
+        // Bubble up modified time to parent
+        switch (p->fts_info) {
+        case FTS_DP:
+        case FTS_DEFAULT:
+        case FTS_F:
+        case FTS_SL:
+        case FTS_SLNONE: {
+            auto item = static_cast<CacheItem*>(p->fts_pointer);
+            auto parent = static_cast<CacheItem*>(p->fts_parent->fts_pointer);
+            if (parent) {
+                parent->modified = std::max(parent->modified, item->modified);
+            }
+        }
+        }
+    }
+    fts_close(fts);
+}
+
+void CacheTracker::loadItems() {
+    items.clear();
+
+    ATRACE_BEGIN("loadItems");
+    for (auto path : mDataPaths) {
+        loadItemsFrom(read_path_inode(path, "cache", kXattrInodeCache));
+        loadItemsFrom(read_path_inode(path, "code_cache", kXattrInodeCodeCache));
+    }
+    ATRACE_END();
+
+    ATRACE_BEGIN("sortItems");
+    auto cmp = [](std::shared_ptr<CacheItem> left, std::shared_ptr<CacheItem> right) {
+        // TODO: sort dotfiles last
+        // TODO: sort code_cache last
+        if (left->modified != right->modified) {
+            return (left->modified > right->modified);
+        }
+        if (left->level != right->level) {
+            return (left->level < right->level);
+        }
+        return left->directory;
+    };
+    std::stable_sort(items.begin(), items.end(), cmp);
+    ATRACE_END();
+}
+
+void CacheTracker::ensureItems() {
+    if (mItemsLoaded) {
+        return;
+    } else {
+        loadItems();
+        mItemsLoaded = true;
+    }
+}
+
+int CacheTracker::getCacheRatio() {
+    if (cacheQuota == 0) {
+        return 0;
+    } else {
+        return (cacheUsed * 10000) / cacheQuota;
+    }
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/CacheTracker.h b/cmds/installd/CacheTracker.h
new file mode 100644
index 0000000..44359b4
--- /dev/null
+++ b/cmds/installd/CacheTracker.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_INSTALLD_CACHE_TRACKER_H
+#define ANDROID_INSTALLD_CACHE_TRACKER_H
+
+#include <memory>
+#include <string>
+#include <queue>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <android-base/macros.h>
+#include <cutils/multiuser.h>
+
+#include "CacheItem.h"
+
+namespace android {
+namespace installd {
+
+/**
+ * Cache tracker for a single UID. Each tracker is used in two modes: first
+ * for loading lightweight "stats", and then by loading detailed "items"
+ * which can then be purged to free up space.
+ */
+class CacheTracker {
+public:
+    CacheTracker(userid_t userId, appid_t appId, const std::string& quotaDevice);
+    ~CacheTracker();
+
+    std::string toString();
+
+    void addDataPath(const std::string& dataPath);
+
+    void loadStats();
+    void loadItems();
+
+    void ensureItems();
+
+    int getCacheRatio();
+
+    int64_t cacheUsed;
+    int64_t cacheQuota;
+
+    std::vector<std::shared_ptr<CacheItem>> items;
+
+private:
+    userid_t mUserId;
+    appid_t mAppId;
+    std::string mQuotaDevice;
+    bool mItemsLoaded;
+
+    std::vector<std::string> mDataPaths;
+
+    bool loadQuotaStats();
+    void loadItemsFrom(const std::string& path);
+
+    DISALLOW_COPY_AND_ASSIGN(CacheTracker);
+};
+
+}  // namespace installd
+}  // namespace android
+
+#endif  // ANDROID_INSTALLD_CACHE_TRACKER_H
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
new file mode 100644
index 0000000..60c89a9
--- /dev/null
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -0,0 +1,2357 @@
+/*
+** Copyright 2008, 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 "InstalldNativeService.h"
+
+#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
+
+#include <errno.h>
+#include <inttypes.h>
+#include <fstream>
+#include <fts.h>
+#include <regex>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/capability.h>
+#include <sys/file.h>
+#include <sys/resource.h>
+#include <sys/quota.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/xattr.h>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <cutils/fs.h>
+#include <cutils/properties.h>
+#include <cutils/sched_policy.h>
+#include <log/log.h>               // TODO: Move everything to base/logging.
+#include <logwrap/logwrap.h>
+#include <private/android_filesystem_config.h>
+#include <selinux/android.h>
+#include <system/thread_defs.h>
+#include <utils/Trace.h>
+
+#include "dexopt.h"
+#include "globals.h"
+#include "installd_deps.h"
+#include "otapreopt_utils.h"
+#include "utils.h"
+
+#include "CacheTracker.h"
+#include "MatchExtensionGen.h"
+
+#ifndef LOG_TAG
+#define LOG_TAG "installd"
+#endif
+
+using android::base::StringPrintf;
+using std::endl;
+
+namespace android {
+namespace installd {
+
+static constexpr const char* kCpPath = "/system/bin/cp";
+static constexpr const char* kXattrDefault = "user.default";
+
+static constexpr const int MIN_RESTRICTED_HOME_SDK_VERSION = 24; // > M
+
+static constexpr const char* PKG_LIB_POSTFIX = "/lib";
+static constexpr const char* CACHE_DIR_POSTFIX = "/cache";
+static constexpr const char* CODE_CACHE_DIR_POSTFIX = "/code_cache";
+
+static constexpr const char *kIdMapPath = "/system/bin/idmap";
+static constexpr const char* IDMAP_PREFIX = "/data/resource-cache/";
+static constexpr const char* IDMAP_SUFFIX = "@idmap";
+
+// 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";
+
+static binder::Status ok() {
+    return binder::Status::ok();
+}
+
+static binder::Status exception(uint32_t code, const std::string& msg) {
+    return binder::Status::fromExceptionCode(code, String8(msg.c_str()));
+}
+
+static binder::Status error() {
+    return binder::Status::fromServiceSpecificError(errno);
+}
+
+static binder::Status error(const std::string& msg) {
+    PLOG(ERROR) << msg;
+    return binder::Status::fromServiceSpecificError(errno, String8(msg.c_str()));
+}
+
+static binder::Status error(uint32_t code, const std::string& msg) {
+    LOG(ERROR) << msg << " (" << code << ")";
+    return binder::Status::fromServiceSpecificError(code, String8(msg.c_str()));
+}
+
+binder::Status checkPermission(const char* permission) {
+    pid_t pid;
+    uid_t uid;
+
+    if (checkCallingPermission(String16(permission), reinterpret_cast<int32_t*>(&pid),
+            reinterpret_cast<int32_t*>(&uid))) {
+        return ok();
+    } else {
+        return exception(binder::Status::EX_SECURITY,
+                StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, permission));
+    }
+}
+
+binder::Status checkUid(uid_t expectedUid) {
+    uid_t uid = IPCThreadState::self()->getCallingUid();
+    if (uid == expectedUid || uid == AID_ROOT) {
+        return ok();
+    } else {
+        return exception(binder::Status::EX_SECURITY,
+                StringPrintf("UID %d is not expected UID %d", uid, expectedUid));
+    }
+}
+
+binder::Status checkArgumentUuid(const std::unique_ptr<std::string>& uuid) {
+    if (!uuid || is_valid_filename(*uuid)) {
+        return ok();
+    } else {
+        return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+                StringPrintf("UUID %s is malformed", uuid->c_str()));
+    }
+}
+
+binder::Status checkArgumentPackageName(const std::string& packageName) {
+    if (is_valid_package_name(packageName.c_str())) {
+        return ok();
+    } else {
+        return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+                StringPrintf("Package name %s is malformed", packageName.c_str()));
+    }
+}
+
+#define ENFORCE_UID(uid) {                                  \
+    binder::Status status = checkUid((uid));                \
+    if (!status.isOk()) {                                   \
+        return status;                                      \
+    }                                                       \
+}
+
+#define CHECK_ARGUMENT_UUID(uuid) {                         \
+    binder::Status status = checkArgumentUuid((uuid));      \
+    if (!status.isOk()) {                                   \
+        return status;                                      \
+    }                                                       \
+}
+
+#define CHECK_ARGUMENT_PACKAGE_NAME(packageName) {          \
+    binder::Status status =                                 \
+            checkArgumentPackageName((packageName));        \
+    if (!status.isOk()) {                                   \
+        return status;                                      \
+    }                                                       \
+}
+
+}  // namespace
+
+status_t InstalldNativeService::start() {
+    IPCThreadState::self()->disableBackgroundScheduling(true);
+    status_t ret = BinderService<InstalldNativeService>::publish();
+    if (ret != android::OK) {
+        return ret;
+    }
+    sp<ProcessState> ps(ProcessState::self());
+    ps->startThreadPool();
+    ps->giveThreadPoolName();
+    return android::OK;
+}
+
+status_t InstalldNativeService::dump(int fd, const Vector<String16> & /* args */) {
+    auto out = std::fstream(StringPrintf("/proc/self/fd/%d", fd));
+    const binder::Status dump_permission = checkPermission(kDump);
+    if (!dump_permission.isOk()) {
+        out << dump_permission.toString8() << endl;
+        return PERMISSION_DENIED;
+    }
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    out << "installd is happy!" << endl;
+
+    {
+        std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+        out << endl << "Storage mounts:" << endl;
+        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;
+        }
+    }
+
+    {
+        std::lock_guard<std::recursive_mutex> lock(mQuotasLock);
+        out << endl << "Per-UID cache quotas:" << endl;
+        for (const auto& n : mCacheQuotas) {
+            out << "    " << n.first << " = " << n.second << endl;
+        }
+    }
+
+    out << endl;
+    out.flush();
+
+    return NO_ERROR;
+}
+
+/**
+ * Perform restorecon of the given path, but only perform recursive restorecon
+ * if the label of that top-level file actually changed.  This can save us
+ * significant time by avoiding no-op traversals of large filesystem trees.
+ */
+static int restorecon_app_data_lazy(const std::string& path, const std::string& seInfo, uid_t uid,
+        bool existing) {
+    int res = 0;
+    char* before = nullptr;
+    char* after = nullptr;
+
+    // Note that SELINUX_ANDROID_RESTORECON_DATADATA flag is set by
+    // libselinux. Not needed here.
+
+    if (lgetfilecon(path.c_str(), &before) < 0) {
+        PLOG(ERROR) << "Failed before getfilecon for " << path;
+        goto fail;
+    }
+    if (selinux_android_restorecon_pkgdir(path.c_str(), seInfo.c_str(), uid, 0) < 0) {
+        PLOG(ERROR) << "Failed top-level restorecon for " << path;
+        goto fail;
+    }
+    if (lgetfilecon(path.c_str(), &after) < 0) {
+        PLOG(ERROR) << "Failed after getfilecon for " << path;
+        goto fail;
+    }
+
+    // If the initial top-level restorecon above changed the label, then go
+    // back and restorecon everything recursively
+    if (strcmp(before, after)) {
+        if (existing) {
+            LOG(DEBUG) << "Detected label change from " << before << " to " << after << " at "
+                    << path << "; running recursive restorecon";
+        }
+        if (selinux_android_restorecon_pkgdir(path.c_str(), seInfo.c_str(), uid,
+                SELINUX_ANDROID_RESTORECON_RECURSE) < 0) {
+            PLOG(ERROR) << "Failed recursive restorecon for " << path;
+            goto fail;
+        }
+    }
+
+    goto done;
+fail:
+    res = -1;
+done:
+    free(before);
+    free(after);
+    return res;
+}
+
+static int restorecon_app_data_lazy(const std::string& parent, const char* name,
+        const std::string& seInfo, uid_t uid, bool existing) {
+    return restorecon_app_data_lazy(StringPrintf("%s/%s", parent.c_str(), name), seInfo, uid,
+            existing);
+}
+
+static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid) {
+    if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, uid) != 0) {
+        PLOG(ERROR) << "Failed to prepare " << path;
+        return -1;
+    }
+    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, const std::string& device,
+        uid_t uid) {
+    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 ((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 = (((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;
+    }
+}
+
+binder::Status InstalldNativeService::createAppData(const std::unique_ptr<std::string>& uuid,
+        const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
+        const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(uuid);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+    const char* pkgname = packageName.c_str();
+
+    // Assume invalid inode unless filled in below
+    if (_aidl_return != nullptr) *_aidl_return = -1;
+
+    int32_t uid = multiuser_get_uid(userId, appId);
+    int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
+    mode_t targetMode = targetSdkVersion >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751;
+
+    // If UID doesn't have a specific cache GID, use UID value
+    if (cacheGid == -1) {
+        cacheGid = uid;
+    }
+
+    if (flags & FLAG_STORAGE_CE) {
+        auto path = create_data_user_ce_package_path(uuid_, userId, pkgname);
+        bool existing = (access(path.c_str(), F_OK) == 0);
+
+        if (prepare_app_dir(path, targetMode, uid) ||
+                prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
+                prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
+            return error("Failed to prepare " + path);
+        }
+
+        // Consider restorecon over contents if label changed
+        if (restorecon_app_data_lazy(path, seInfo, uid, existing) ||
+                restorecon_app_data_lazy(path, "cache", seInfo, uid, existing) ||
+                restorecon_app_data_lazy(path, "code_cache", seInfo, uid, existing)) {
+            return error("Failed to restorecon " + path);
+        }
+
+        // Remember inode numbers of cache directories so that we can clear
+        // contents while CE storage is locked
+        if (write_path_inode(path, "cache", kXattrInodeCache) ||
+                write_path_inode(path, "code_cache", kXattrInodeCodeCache)) {
+            return error("Failed to write_path_inode for " + path);
+        }
+
+        // And return the CE inode of the top-level data directory so we can
+        // clear contents while CE storage is locked
+        if ((_aidl_return != nullptr)
+                && get_path_inode(path, reinterpret_cast<ino_t*>(_aidl_return)) != 0) {
+            return error("Failed to get_path_inode for " + path);
+        }
+    }
+    if (flags & FLAG_STORAGE_DE) {
+        auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
+        bool existing = (access(path.c_str(), F_OK) == 0);
+
+        if (prepare_app_dir(path, targetMode, uid) ||
+                prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
+                prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
+            return error("Failed to prepare " + path);
+        }
+
+        // Consider restorecon over contents if label changed
+        if (restorecon_app_data_lazy(path, seInfo, uid, existing) ||
+                restorecon_app_data_lazy(path, "cache", seInfo, uid, existing) ||
+                restorecon_app_data_lazy(path, "code_cache", seInfo, uid, existing)) {
+            return error("Failed to restorecon " + path);
+        }
+
+        if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid), uid)) {
+            return error("Failed to set hard quota " + path);
+        }
+
+        if (property_get_bool("dalvik.vm.usejitprofiles", false)) {
+            const std::string profile_dir =
+                    create_primary_current_profile_package_dir_path(userId, pkgname);
+            // read-write-execute only for the app user.
+            if (fs_prepare_dir_strict(profile_dir.c_str(), 0700, uid, uid) != 0) {
+                return error("Failed to prepare " + profile_dir);
+            }
+            const std::string profile_file = create_current_profile_path(userId, pkgname,
+                    /*is_secondary_dex*/false);
+            // read-write only for the app user.
+            if (fs_prepare_file_strict(profile_file.c_str(), 0600, uid, uid) != 0) {
+                return error("Failed to prepare " + profile_file);
+            }
+            const std::string ref_profile_path =
+                    create_primary_reference_profile_package_dir_path(pkgname);
+            // dex2oat/profman runs under the shared app gid and it needs to read/write reference
+            // profiles.
+            int shared_app_gid = multiuser_get_shared_gid(0, appId);
+            if ((shared_app_gid != -1) && fs_prepare_dir_strict(
+                    ref_profile_path.c_str(), 0700, shared_app_gid, shared_app_gid) != 0) {
+                return error("Failed to prepare " + ref_profile_path);
+            }
+        }
+    }
+    return ok();
+}
+
+binder::Status InstalldNativeService::migrateAppData(const std::unique_ptr<std::string>& uuid,
+        const std::string& packageName, int32_t userId, int32_t flags) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(uuid);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+    const char* pkgname = packageName.c_str();
+
+    // This method only exists to upgrade system apps that have requested
+    // forceDeviceEncrypted, so their default storage always lives in a
+    // consistent location.  This only works on non-FBE devices, since we
+    // never want to risk exposing data on a device with real CE/DE storage.
+
+    auto ce_path = create_data_user_ce_package_path(uuid_, userId, pkgname);
+    auto de_path = create_data_user_de_package_path(uuid_, userId, pkgname);
+
+    // If neither directory is marked as default, assume CE is default
+    if (getxattr(ce_path.c_str(), kXattrDefault, nullptr, 0) == -1
+            && getxattr(de_path.c_str(), kXattrDefault, nullptr, 0) == -1) {
+        if (setxattr(ce_path.c_str(), kXattrDefault, nullptr, 0, 0) != 0) {
+            return error("Failed to mark default storage " + ce_path);
+        }
+    }
+
+    // Migrate default data location if needed
+    auto target = (flags & FLAG_STORAGE_DE) ? de_path : ce_path;
+    auto source = (flags & FLAG_STORAGE_DE) ? ce_path : de_path;
+
+    if (getxattr(target.c_str(), kXattrDefault, nullptr, 0) == -1) {
+        LOG(WARNING) << "Requested default storage " << target
+                << " is not active; migrating from " << source;
+        if (delete_dir_contents_and_dir(target) != 0) {
+            return error("Failed to delete " + target);
+        }
+        if (rename(source.c_str(), target.c_str()) != 0) {
+            return error("Failed to rename " + source + " to " + target);
+        }
+    }
+
+    return ok();
+}
+
+
+binder::Status InstalldNativeService::clearAppProfiles(const std::string& packageName) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    binder::Status res = ok();
+    if (!clear_primary_reference_profile(packageName)) {
+        res = error("Failed to clear reference profile for " + packageName);
+    }
+    if (!clear_primary_current_profiles(packageName)) {
+        res = error("Failed to clear current profiles for " + packageName);
+    }
+    return res;
+}
+
+binder::Status InstalldNativeService::clearAppData(const std::unique_ptr<std::string>& uuid,
+        const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(uuid);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+    const char* pkgname = packageName.c_str();
+
+    binder::Status res = ok();
+    if (flags & FLAG_STORAGE_CE) {
+        auto path = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInode);
+        if (flags & FLAG_CLEAR_CACHE_ONLY) {
+            path = read_path_inode(path, "cache", kXattrInodeCache);
+        } else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) {
+            path = read_path_inode(path, "code_cache", kXattrInodeCodeCache);
+        }
+        if (access(path.c_str(), F_OK) == 0) {
+            if (delete_dir_contents(path) != 0) {
+                res = error("Failed to delete contents of " + path);
+            }
+        }
+    }
+    if (flags & FLAG_STORAGE_DE) {
+        std::string suffix = "";
+        bool only_cache = false;
+        if (flags & FLAG_CLEAR_CACHE_ONLY) {
+            suffix = CACHE_DIR_POSTFIX;
+            only_cache = true;
+        } else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) {
+            suffix = CODE_CACHE_DIR_POSTFIX;
+            only_cache = true;
+        }
+
+        auto path = create_data_user_de_package_path(uuid_, userId, pkgname) + suffix;
+        if (access(path.c_str(), F_OK) == 0) {
+            if (delete_dir_contents(path) != 0) {
+                res = error("Failed to delete contents of " + path);
+            }
+        }
+        if (!only_cache) {
+            if (!clear_primary_current_profile(packageName, userId)) {
+                res = error("Failed to clear current profile for " + packageName);
+            }
+        }
+    }
+    return res;
+}
+
+static int destroy_app_reference_profile(const std::string& pkgname) {
+    return delete_dir_contents_and_dir(
+        create_primary_reference_profile_package_dir_path(pkgname),
+        /*ignore_if_missing*/ true);
+}
+
+static int destroy_app_current_profiles(const std::string& pkgname, userid_t userid) {
+    return delete_dir_contents_and_dir(
+        create_primary_current_profile_package_dir_path(userid, pkgname),
+        /*ignore_if_missing*/ true);
+}
+
+binder::Status InstalldNativeService::destroyAppProfiles(const std::string& packageName) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    binder::Status res = ok();
+    std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
+    for (auto user : users) {
+        if (destroy_app_current_profiles(packageName, user) != 0) {
+            res = error("Failed to destroy current profiles for " + packageName);
+        }
+    }
+    if (destroy_app_reference_profile(packageName) != 0) {
+        res = error("Failed to destroy reference profile for " + packageName);
+    }
+    return res;
+}
+
+binder::Status InstalldNativeService::destroyAppData(const std::unique_ptr<std::string>& uuid,
+        const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(uuid);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+    const char* pkgname = packageName.c_str();
+
+    binder::Status res = ok();
+    if (flags & FLAG_STORAGE_CE) {
+        auto path = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInode);
+        if (delete_dir_contents_and_dir(path) != 0) {
+            res = error("Failed to delete " + path);
+        }
+    }
+    if (flags & FLAG_STORAGE_DE) {
+        auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
+        if (delete_dir_contents_and_dir(path) != 0) {
+            res = error("Failed to delete " + path);
+        }
+        destroy_app_current_profiles(packageName, userId);
+        // TODO(calin): If the package is still installed by other users it's probably
+        // beneficial to keep the reference profile around.
+        // Verify if it's ok to do that.
+        destroy_app_reference_profile(packageName);
+    }
+    return res;
+}
+
+static gid_t get_cache_gid(uid_t uid) {
+    int32_t gid = multiuser_get_cache_gid(multiuser_get_user_id(uid), multiuser_get_app_id(uid));
+    return (gid != -1) ? gid : uid;
+}
+
+binder::Status InstalldNativeService::fixupAppData(const std::unique_ptr<std::string>& uuid,
+        int32_t flags) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(uuid);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+    for (auto user : get_known_users(uuid_)) {
+        ATRACE_BEGIN("fixup user");
+        FTS* fts;
+        FTSENT* p;
+        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))) {
+            return error("Failed to fts_open");
+        }
+        while ((p = fts_read(fts)) != nullptr) {
+            if (p->fts_info == FTS_D && p->fts_level == 1) {
+                // Track down inodes of cache directories
+                uint64_t raw = 0;
+                ino_t inode_cache = 0;
+                ino_t inode_code_cache = 0;
+                if (getxattr(p->fts_path, kXattrInodeCache, &raw, sizeof(raw)) == sizeof(raw)) {
+                    inode_cache = raw;
+                }
+                if (getxattr(p->fts_path, kXattrInodeCodeCache, &raw, sizeof(raw)) == sizeof(raw)) {
+                    inode_code_cache = raw;
+                }
+
+                // Figure out expected GID of each child
+                FTSENT* child = fts_children(fts, 0);
+                while (child != nullptr) {
+                    if ((child->fts_statp->st_ino == inode_cache)
+                            || (child->fts_statp->st_ino == inode_code_cache)
+                            || !strcmp(child->fts_name, "cache")
+                            || !strcmp(child->fts_name, "code_cache")) {
+                        child->fts_number = get_cache_gid(p->fts_statp->st_uid);
+                    } else {
+                        child->fts_number = p->fts_statp->st_uid;
+                    }
+                    child = child->fts_link;
+                }
+            } else if (p->fts_level >= 2) {
+                if (p->fts_level > 2) {
+                    // Inherit GID from parent once we're deeper into tree
+                    p->fts_number = p->fts_parent->fts_number;
+                }
+
+                uid_t uid = p->fts_parent->fts_statp->st_uid;
+                gid_t cache_gid = get_cache_gid(uid);
+                gid_t expected = p->fts_number;
+                gid_t actual = p->fts_statp->st_gid;
+                if (actual == expected) {
+#if FIXUP_DEBUG
+                    LOG(DEBUG) << "Ignoring " << p->fts_path << " with expected GID " << expected;
+#endif
+                    if (!(flags & FLAG_FORCE)) {
+                        fts_set(fts, p, FTS_SKIP);
+                    }
+                } else if ((actual == uid) || (actual == cache_gid)) {
+                    // Only consider fixing up when current GID belongs to app
+                    if (p->fts_info != FTS_D) {
+                        LOG(INFO) << "Fixing " << p->fts_path << " with unexpected GID " << actual
+                                << " instead of " << expected;
+                    }
+                    switch (p->fts_info) {
+                    case FTS_DP:
+                        // If we're moving towards cache GID, we need to set S_ISGID
+                        if (expected == cache_gid) {
+                            if (chmod(p->fts_path, 02771) != 0) {
+                                PLOG(WARNING) << "Failed to chmod " << p->fts_path;
+                            }
+                        }
+                        // Intentional fall through to also set GID
+                    case FTS_F:
+                        if (chown(p->fts_path, -1, expected) != 0) {
+                            PLOG(WARNING) << "Failed to chown " << p->fts_path;
+                        }
+                        break;
+                    case FTS_SL:
+                    case FTS_SLNONE:
+                        if (lchown(p->fts_path, -1, expected) != 0) {
+                            PLOG(WARNING) << "Failed to chown " << p->fts_path;
+                        }
+                        break;
+                    }
+                } else {
+                    // Ignore all other GID transitions, since they're kinda shady
+                    LOG(WARNING) << "Ignoring " << p->fts_path << " with unexpected GID " << actual
+                            << " instead of " << expected;
+                }
+            }
+        }
+        fts_close(fts);
+        ATRACE_END();
+    }
+    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,
+        int32_t targetSdkVersion) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(fromUuid);
+    CHECK_ARGUMENT_UUID(toUuid);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* from_uuid = fromUuid ? fromUuid->c_str() : nullptr;
+    const char* to_uuid = toUuid ? toUuid->c_str() : nullptr;
+    const char* package_name = packageName.c_str();
+    const char* data_app_name = dataAppName.c_str();
+
+    binder::Status res = ok();
+    std::vector<userid_t> users = get_known_users(from_uuid);
+
+    // Copy app
+    {
+        auto from = create_data_app_package_path(from_uuid, data_app_name);
+        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);
+        if (rc != 0) {
+            res = error(rc, "Failed copying " + from + " to " + to);
+            goto fail;
+        }
+
+        if (selinux_android_restorecon(to.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
+            res = error("Failed to restorecon " + to);
+            goto fail;
+        }
+    }
+
+    // Copy private data for all known users
+    for (auto user : users) {
+
+        // Data source may not exist for all users; that's okay
+        auto from_ce = create_data_user_ce_package_path(from_uuid, user, package_name);
+        if (access(from_ce.c_str(), F_OK) != 0) {
+            LOG(INFO) << "Missing source " << from_ce;
+            continue;
+        }
+
+        if (!createAppData(toUuid, packageName, user, FLAG_STORAGE_CE | FLAG_STORAGE_DE, appId,
+                seInfo, targetSdkVersion, nullptr).isOk()) {
+            res = error("Failed to create package target");
+            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);
+            if (rc != 0) {
+                res = error(rc, "Failed copying " + from + " to " + to);
+                goto fail;
+            }
+        }
+        {
+            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);
+            if (rc != 0) {
+                res = error(rc, "Failed copying " + from + " to " + to);
+                goto fail;
+            }
+        }
+
+        if (!restoreconAppData(toUuid, packageName, user, FLAG_STORAGE_CE | FLAG_STORAGE_DE,
+                appId, seInfo).isOk()) {
+            res = error("Failed to restorecon");
+            goto fail;
+        }
+    }
+
+    // We let the framework scan the new location and persist that before
+    // deleting the data in the old location; this ordering ensures that
+    // we can recover from things like battery pulls.
+    return ok();
+
+fail:
+    // 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) {
+            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) {
+                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) {
+                LOG(WARNING) << "Failed to rollback " << to;
+            }
+        }
+    }
+    return res;
+}
+
+binder::Status InstalldNativeService::createUserData(const std::unique_ptr<std::string>& uuid,
+        int32_t userId, int32_t userSerial ATTRIBUTE_UNUSED, int32_t flags) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(uuid);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+    if (flags & FLAG_STORAGE_DE) {
+        if (uuid_ == nullptr) {
+            if (ensure_config_user_dirs(userId) != 0) {
+                return error(StringPrintf("Failed to ensure dirs for %d", userId));
+            }
+        }
+    }
+
+    // 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();
+}
+
+binder::Status InstalldNativeService::destroyUserData(const std::unique_ptr<std::string>& uuid,
+        int32_t userId, int32_t flags) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(uuid);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+    binder::Status res = ok();
+    if (flags & FLAG_STORAGE_DE) {
+        auto path = create_data_user_de_path(uuid_, userId);
+        if (delete_dir_contents_and_dir(path, true) != 0) {
+            res = error("Failed to delete " + path);
+        }
+        if (uuid_ == nullptr) {
+            path = create_data_misc_legacy_path(userId);
+            if (delete_dir_contents_and_dir(path, true) != 0) {
+                res = error("Failed to delete " + path);
+            }
+            path = create_primary_cur_profile_dir_path(userId);
+            if (delete_dir_contents_and_dir(path, true) != 0) {
+                res = error("Failed to delete " + path);
+            }
+        }
+    }
+    if (flags & FLAG_STORAGE_CE) {
+        auto path = create_data_user_ce_path(uuid_, userId);
+        if (delete_dir_contents_and_dir(path, true) != 0) {
+            res = error("Failed to delete " + path);
+        }
+        path = findDataMediaPath(uuid, userId);
+        if (delete_dir_contents_and_dir(path, true) != 0) {
+            res = error("Failed to delete " + path);
+        }
+    }
+    return res;
+}
+
+binder::Status InstalldNativeService::freeCache(const std::unique_ptr<std::string>& uuid,
+        int64_t targetFreeBytes, int64_t cacheReservedBytes, int32_t flags) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(uuid);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    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);
+    if (free < 0) {
+        return error("Failed to determine free space for " + data_path);
+    }
+
+    int64_t cleared = 0;
+    int64_t needed = targetFreeBytes - free;
+    LOG(DEBUG) << "Device " << data_path << " has " << free << " free; requested "
+            << targetFreeBytes << "; needed " << needed;
+
+    if (free >= targetFreeBytes) {
+        return ok();
+    }
+
+    if (flags & FLAG_FREE_CACHE_V2) {
+        // This new cache strategy fairly removes files from UIDs by deleting
+        // files from the UIDs which are most over their allocated quota
+
+        // 1. Create trackers for every known UID
+        ATRACE_BEGIN("create");
+        std::unordered_map<uid_t, std::shared_ptr<CacheTracker>> trackers;
+        for (auto user : get_known_users(uuid_)) {
+            FTS *fts;
+            FTSENT *p;
+            auto ce_path = create_data_user_ce_path(uuid_, user);
+            auto de_path = create_data_user_de_path(uuid_, user);
+            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))) {
+                return error("Failed to fts_open");
+            }
+            while ((p = fts_read(fts)) != NULL) {
+                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) {
+                        uid = (multiuser_get_app_id(p->fts_statp->st_gid) - AID_EXT_GID_START)
+                                + AID_APP_START;
+                    }
+                    auto search = trackers.find(uid);
+                    if (search != trackers.end()) {
+                        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));
+                        tracker->addDataPath(p->fts_path);
+                        {
+                            std::lock_guard<std::recursive_mutex> lock(mQuotasLock);
+                            tracker->cacheQuota = mCacheQuotas[uid];
+                        }
+                        if (tracker->cacheQuota == 0) {
+#if MEASURE_DEBUG
+                            LOG(WARNING) << "UID " << uid << " has no cache quota; assuming 64MB";
+#endif
+                            tracker->cacheQuota = 67108864;
+                        }
+                        trackers[uid] = tracker;
+                    }
+                    fts_set(fts, p, FTS_SKIP);
+                }
+            }
+            fts_close(fts);
+        }
+        ATRACE_END();
+
+        // 2. Populate tracker stats and insert into priority queue
+        ATRACE_BEGIN("populate");
+        int64_t cacheTotal = 0;
+        auto cmp = [](std::shared_ptr<CacheTracker> left, std::shared_ptr<CacheTracker> right) {
+            return (left->getCacheRatio() < right->getCacheRatio());
+        };
+        std::priority_queue<std::shared_ptr<CacheTracker>,
+                std::vector<std::shared_ptr<CacheTracker>>, decltype(cmp)> queue(cmp);
+        for (const auto& it : trackers) {
+            it.second->loadStats();
+            queue.push(it.second);
+            cacheTotal += it.second->cacheUsed;
+        }
+        ATRACE_END();
+
+        // 3. Bounce across the queue, freeing items from whichever tracker is
+        // the most over their assigned quota
+        ATRACE_BEGIN("bounce");
+        std::shared_ptr<CacheTracker> active;
+        while (active || !queue.empty()) {
+            // Only look at apps under quota when explicitly requested
+            if (active && (active->getCacheRatio() < 10000)
+                    && !(flags & FLAG_FREE_CACHE_V2_DEFY_QUOTA)) {
+                LOG(DEBUG) << "Active ratio " << active->getCacheRatio()
+                        << " isn't over quota, and defy not requested";
+                break;
+            }
+
+            // Only keep clearing when we haven't pushed into reserved area
+            if (cacheReservedBytes > 0 && cleared >= (cacheTotal - cacheReservedBytes)) {
+                LOG(DEBUG) << "Refusing to clear cached data in reserved space";
+                break;
+            }
+
+            // Find the best tracker to work with; this might involve swapping
+            // if the active tracker is no longer the most over quota
+            bool nextBetter = active && !queue.empty()
+                    && active->getCacheRatio() < queue.top()->getCacheRatio();
+            if (!active || nextBetter) {
+                if (active) {
+                    // Current tracker still has items, so we'll consider it
+                    // again later once it bubbles up to surface
+                    queue.push(active);
+                }
+                active = queue.top(); queue.pop();
+                active->ensureItems();
+                continue;
+            }
+
+            // If no items remain, go find another tracker
+            if (active->items.empty()) {
+                active = nullptr;
+                continue;
+            } else {
+                auto item = active->items.back();
+                active->items.pop_back();
+
+                LOG(DEBUG) << "Purging " << item->toString() << " from " << active->toString();
+                if (!noop) {
+                    item->purge();
+                }
+                active->cacheUsed -= item->size;
+                needed -= item->size;
+                cleared += item->size;
+            }
+
+            // Verify that we're actually done before bailing, since sneaky
+            // apps might be using hardlinks
+            if (needed <= 0) {
+                free = data_disk_free(data_path);
+                needed = targetFreeBytes - free;
+                if (needed <= 0) {
+                    break;
+                } else {
+                    LOG(WARNING) << "Expected to be done but still need " << needed;
+                }
+            }
+        }
+        ATRACE_END();
+
+    } else {
+        return error("Legacy cache logic no longer supported");
+    }
+
+    free = data_disk_free(data_path);
+    if (free >= targetFreeBytes) {
+        return ok();
+    } else {
+        return error(StringPrintf("Failed to free up %" PRId64 " on %s; final free space %" PRId64,
+                targetFreeBytes, data_path.c_str(), free));
+    }
+}
+
+binder::Status InstalldNativeService::rmdex(const std::string& codePath,
+        const std::string& instructionSet) {
+    ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    char dex_path[PKG_PATH_MAX];
+
+    const char* path = codePath.c_str();
+    const char* instruction_set = instructionSet.c_str();
+
+    if (validate_apk_path(path) && validate_system_app_path(path)) {
+        return error("Invalid path " + codePath);
+    }
+
+    if (!create_cache_path(dex_path, path, instruction_set)) {
+        return error("Failed to create cache path for " + codePath);
+    }
+
+    ALOGV("unlink %s\n", dex_path);
+    if (unlink(dex_path) < 0) {
+        // It's ok if we don't have a dalvik cache path. Report error only when the path exists
+        // but could not be unlinked.
+        if (errno != ENOENT) {
+            return error(StringPrintf("Failed to unlink %s", dex_path));
+        }
+    }
+    return ok();
+}
+
+struct stats {
+    int64_t codeSize;
+    int64_t dataSize;
+    int64_t cacheSize;
+};
+
+#if MEASURE_DEBUG
+static std::string toString(std::vector<int64_t> values) {
+    std::stringstream res;
+    res << "[";
+    for (size_t i = 0; i < values.size(); i++) {
+        res << values[i];
+        if (i < values.size() - 1) {
+            res << ",";
+        }
+    }
+    res << "]";
+    return res.str();
+}
+#endif
+
+static void collectQuotaStats(const std::string& device, int32_t userId,
+        int32_t appId, struct stats* stats, struct stats* extStats) {
+    if (device.empty()) return;
+
+    struct dqblk dq;
+
+    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;
+        }
+
+        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;
+            }
+        }
+
+        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 (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;
+            }
+        }
+
+        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;
+            }
+        }
+    }
+}
+
+static void collectManualStats(const std::string& path, struct stats* stats) {
+    DIR *d;
+    int dfd;
+    struct dirent *de;
+    struct stat s;
+
+    d = opendir(path.c_str());
+    if (d == nullptr) {
+        if (errno != ENOENT) {
+            PLOG(WARNING) << "Failed to open " << path;
+        }
+        return;
+    }
+    dfd = dirfd(d);
+    while ((de = readdir(d))) {
+        const char *name = de->d_name;
+
+        int64_t size = 0;
+        if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
+            size = s.st_blocks * 512;
+        }
+
+        if (de->d_type == DT_DIR) {
+            if (!strcmp(name, ".")) {
+                // Don't recurse, but still count node size
+            } else if (!strcmp(name, "..")) {
+                // Don't recurse or count node size
+                continue;
+            } else {
+                // Measure all children nodes
+                size = 0;
+                calculate_tree_size(StringPrintf("%s/%s", path.c_str(), name), &size);
+            }
+
+            if (!strcmp(name, "cache") || !strcmp(name, "code_cache")) {
+                stats->cacheSize += size;
+            }
+        }
+
+        // Legacy symlink isn't owned by app
+        if (de->d_type == DT_LNK && !strcmp(name, "lib")) {
+            continue;
+        }
+
+        // Everything found inside is considered data
+        stats->dataSize += size;
+    }
+    closedir(d);
+}
+
+static void collectManualStatsForUser(const std::string& path, struct stats* stats,
+        bool exclude_apps = false) {
+    DIR *d;
+    int dfd;
+    struct dirent *de;
+    struct stat s;
+
+    d = opendir(path.c_str());
+    if (d == nullptr) {
+        if (errno != ENOENT) {
+            PLOG(WARNING) << "Failed to open " << path;
+        }
+        return;
+    }
+    dfd = dirfd(d);
+    while ((de = readdir(d))) {
+        if (de->d_type == DT_DIR) {
+            const char *name = de->d_name;
+            if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) != 0) {
+                continue;
+            }
+            int32_t user_uid = multiuser_get_app_id(s.st_uid);
+            if (!strcmp(name, ".") || !strcmp(name, "..")) {
+                continue;
+            } else if (exclude_apps && (user_uid >= AID_APP_START && user_uid <= AID_APP_END)) {
+                continue;
+            } else {
+                collectManualStats(StringPrintf("%s/%s", path.c_str(), name), stats);
+            }
+        }
+    }
+    closedir(d);
+}
+
+static void collectManualExternalStatsForUser(const std::string& path, struct stats* stats) {
+    FTS *fts;
+    FTSENT *p;
+    char *argv[] = { (char*) path.c_str(), nullptr };
+    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+        PLOG(ERROR) << "Failed to fts_open " << path;
+        return;
+    }
+    while ((p = fts_read(fts)) != NULL) {
+        p->fts_number = p->fts_parent->fts_number;
+        switch (p->fts_info) {
+        case FTS_D:
+            if (p->fts_level == 4
+                    && !strcmp(p->fts_name, "cache")
+                    && !strcmp(p->fts_parent->fts_parent->fts_name, "data")
+                    && !strcmp(p->fts_parent->fts_parent->fts_parent->fts_name, "Android")) {
+                p->fts_number = 1;
+            }
+            // Fall through to count the directory
+        case FTS_DEFAULT:
+        case FTS_F:
+        case FTS_SL:
+        case FTS_SLNONE:
+            int64_t size = (p->fts_statp->st_blocks * 512);
+            if (p->fts_number == 1) {
+                stats->cacheSize += size;
+            }
+            stats->dataSize += size;
+            break;
+        }
+    }
+    fts_close(fts);
+}
+
+binder::Status InstalldNativeService::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,
+        const std::vector<std::string>& codePaths, std::vector<int64_t>* _aidl_return) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(uuid);
+    for (auto packageName : packageNames) {
+        CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    }
+    // NOTE: Locking is relaxed on this method, since it's limited to
+    // read-only measurements without mutation.
+
+    // When modifying this logic, always verify using tests:
+    // runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetAppSize
+
+#if MEASURE_DEBUG
+    LOG(INFO) << "Measuring user " << userId << " app " << appId;
+#endif
+
+    // Here's a summary of the common storage locations across the platform,
+    // and how they're each tagged:
+    //
+    // /data/app/com.example                           UID system
+    // /data/app/com.example/oat                       UID system
+    // /data/user/0/com.example                        UID u0_a10      GID u0_a10
+    // /data/user/0/com.example/cache                  UID u0_a10      GID u0_a10_cache
+    // /data/media/0/foo.txt                           UID u0_media_rw
+    // /data/media/0/bar.jpg                           UID u0_media_rw GID u0_media_image
+    // /data/media/0/Android/data/com.example          UID u0_media_rw GID u0_a10_ext
+    // /data/media/0/Android/data/com.example/cache    UID u0_media_rw GID u0_a10_ext_cache
+    // /data/media/obb/com.example                     UID system
+
+    struct stats stats;
+    struct stats extStats;
+    memset(&stats, 0, sizeof(stats));
+    memset(&extStats, 0, sizeof(extStats));
+
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+
+    auto device = findQuotaDeviceForUuid(uuid);
+    if (device.empty()) {
+        flags &= ~FLAG_USE_QUOTA;
+    }
+
+    ATRACE_BEGIN("obb");
+    for (auto packageName : packageNames) {
+        auto obbCodePath = create_data_media_obb_path(uuid_, packageName.c_str());
+        calculate_tree_size(obbCodePath, &extStats.codeSize);
+    }
+    ATRACE_END();
+
+    if (flags & FLAG_USE_QUOTA && appId >= AID_APP_START) {
+        ATRACE_BEGIN("code");
+        for (auto codePath : codePaths) {
+            calculate_tree_size(codePath, &stats.codeSize, -1,
+                    multiuser_get_shared_gid(0, appId));
+        }
+        ATRACE_END();
+
+        ATRACE_BEGIN("quota");
+        collectQuotaStats(device, userId, appId, &stats, &extStats);
+        ATRACE_END();
+    } else {
+        ATRACE_BEGIN("code");
+        for (auto codePath : codePaths) {
+            calculate_tree_size(codePath, &stats.codeSize);
+        }
+        ATRACE_END();
+
+        for (size_t i = 0; i < packageNames.size(); i++) {
+            const char* pkgname = packageNames[i].c_str();
+
+            ATRACE_BEGIN("data");
+            auto cePath = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInodes[i]);
+            collectManualStats(cePath, &stats);
+            auto dePath = create_data_user_de_package_path(uuid_, userId, pkgname);
+            collectManualStats(dePath, &stats);
+            ATRACE_END();
+
+            if (!uuid) {
+                ATRACE_BEGIN("profiles");
+                calculate_tree_size(
+                        create_primary_current_profile_package_dir_path(userId, pkgname),
+                        &stats.dataSize);
+                calculate_tree_size(
+                        create_primary_reference_profile_package_dir_path(pkgname),
+                        &stats.codeSize);
+                ATRACE_END();
+            }
+
+            ATRACE_BEGIN("external");
+            auto extPath = create_data_media_package_path(uuid_, userId, "data", pkgname);
+            collectManualStats(extPath, &extStats);
+            auto mediaPath = create_data_media_package_path(uuid_, userId, "media", pkgname);
+            calculate_tree_size(mediaPath, &extStats.dataSize);
+            ATRACE_END();
+        }
+
+        if (!uuid) {
+            ATRACE_BEGIN("dalvik");
+            int32_t sharedGid = multiuser_get_shared_gid(0, appId);
+            if (sharedGid != -1) {
+                calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
+                        sharedGid, -1);
+            }
+            ATRACE_END();
+        }
+    }
+
+    std::vector<int64_t> ret;
+    ret.push_back(stats.codeSize);
+    ret.push_back(stats.dataSize);
+    ret.push_back(stats.cacheSize);
+    ret.push_back(extStats.codeSize);
+    ret.push_back(extStats.dataSize);
+    ret.push_back(extStats.cacheSize);
+#if MEASURE_DEBUG
+    LOG(DEBUG) << "Final result " << toString(ret);
+#endif
+    *_aidl_return = ret;
+    return ok();
+}
+
+binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::string>& uuid,
+        int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
+        std::vector<int64_t>* _aidl_return) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(uuid);
+    // NOTE: Locking is relaxed on this method, since it's limited to
+    // read-only measurements without mutation.
+
+    // When modifying this logic, always verify using tests:
+    // runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetUserSize
+
+#if MEASURE_DEBUG
+    LOG(INFO) << "Measuring user " << userId;
+#endif
+
+    struct stats stats;
+    struct stats extStats;
+    memset(&stats, 0, sizeof(stats));
+    memset(&extStats, 0, sizeof(extStats));
+
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+
+    auto device = findQuotaDeviceForUuid(uuid);
+    if (device.empty()) {
+        flags &= ~FLAG_USE_QUOTA;
+    }
+
+    if (flags & FLAG_USE_QUOTA) {
+        struct dqblk dq;
+
+        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;
+        }
+        ATRACE_END();
+
+        ATRACE_BEGIN("code");
+        calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize, -1, -1, true);
+        ATRACE_END();
+
+        ATRACE_BEGIN("data");
+        auto cePath = create_data_user_ce_path(uuid_, userId);
+        collectManualStatsForUser(cePath, &stats, true);
+        auto dePath = create_data_user_de_path(uuid_, userId);
+        collectManualStatsForUser(dePath, &stats, true);
+        ATRACE_END();
+
+        if (!uuid) {
+            ATRACE_BEGIN("profile");
+            auto userProfilePath = create_primary_cur_profile_dir_path(userId);
+            calculate_tree_size(userProfilePath, &stats.dataSize, -1, -1, true);
+            auto refProfilePath = create_primary_ref_profile_dir_path();
+            calculate_tree_size(refProfilePath, &stats.codeSize, -1, -1, true);
+            ATRACE_END();
+        }
+
+        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;
+        }
+        ATRACE_END();
+
+        if (!uuid) {
+            ATRACE_BEGIN("dalvik");
+            calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
+                    -1, -1, true);
+            calculate_tree_size(create_primary_cur_profile_dir_path(userId), &stats.dataSize,
+                    -1, -1, true);
+            ATRACE_END();
+        }
+
+        ATRACE_BEGIN("quota");
+        int64_t dataSize = extStats.dataSize;
+        for (auto appId : appIds) {
+            if (appId >= AID_APP_START) {
+                collectQuotaStats(device, userId, appId, &stats, &extStats);
+
+#if MEASURE_DEBUG
+                // Sleep to make sure we don't lose logs
+                usleep(1);
+#endif
+            }
+        }
+        extStats.dataSize = dataSize;
+        ATRACE_END();
+    } else {
+        ATRACE_BEGIN("obb");
+        auto obbPath = create_data_path(uuid_) + "/media/obb";
+        calculate_tree_size(obbPath, &extStats.codeSize);
+        ATRACE_END();
+
+        ATRACE_BEGIN("code");
+        calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize);
+        ATRACE_END();
+
+        ATRACE_BEGIN("data");
+        auto cePath = create_data_user_ce_path(uuid_, userId);
+        collectManualStatsForUser(cePath, &stats);
+        auto dePath = create_data_user_de_path(uuid_, userId);
+        collectManualStatsForUser(dePath, &stats);
+        ATRACE_END();
+
+        if (!uuid) {
+            ATRACE_BEGIN("profile");
+            auto userProfilePath = create_primary_cur_profile_dir_path(userId);
+            calculate_tree_size(userProfilePath, &stats.dataSize);
+            auto refProfilePath = create_primary_ref_profile_dir_path();
+            calculate_tree_size(refProfilePath, &stats.codeSize);
+            ATRACE_END();
+        }
+
+        ATRACE_BEGIN("external");
+        auto dataMediaPath = create_data_media_path(uuid_, userId);
+        collectManualExternalStatsForUser(dataMediaPath, &extStats);
+#if MEASURE_DEBUG
+        LOG(DEBUG) << "Measured external data " << extStats.dataSize << " cache "
+                << extStats.cacheSize;
+#endif
+        ATRACE_END();
+
+        if (!uuid) {
+            ATRACE_BEGIN("dalvik");
+            calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize);
+            calculate_tree_size(create_primary_cur_profile_dir_path(userId), &stats.dataSize);
+            ATRACE_END();
+        }
+    }
+
+    std::vector<int64_t> ret;
+    ret.push_back(stats.codeSize);
+    ret.push_back(stats.dataSize);
+    ret.push_back(stats.cacheSize);
+    ret.push_back(extStats.codeSize);
+    ret.push_back(extStats.dataSize);
+    ret.push_back(extStats.cacheSize);
+#if MEASURE_DEBUG
+    LOG(DEBUG) << "Final result " << toString(ret);
+#endif
+    *_aidl_return = ret;
+    return ok();
+}
+
+binder::Status InstalldNativeService::getExternalSize(const std::unique_ptr<std::string>& uuid,
+        int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
+        std::vector<int64_t>* _aidl_return) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(uuid);
+    // NOTE: Locking is relaxed on this method, since it's limited to
+    // read-only measurements without mutation.
+
+    // When modifying this logic, always verify using tests:
+    // runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetExternalSize
+
+#if MEASURE_DEBUG
+    LOG(INFO) << "Measuring external " << userId;
+#endif
+
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+
+    int64_t totalSize = 0;
+    int64_t audioSize = 0;
+    int64_t videoSize = 0;
+    int64_t imageSize = 0;
+    int64_t appSize = 0;
+
+    auto device = findQuotaDeviceForUuid(uuid);
+    if (device.empty()) {
+        flags &= ~FLAG_USE_QUOTA;
+    }
+
+    if (flags & FLAG_USE_QUOTA) {
+        struct dqblk dq;
+
+        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;
+        }
+
+        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;
+        }
+        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;
+        }
+        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;
+        }
+        ATRACE_END();
+
+        ATRACE_BEGIN("apps");
+        struct stats extStats;
+        memset(&extStats, 0, sizeof(extStats));
+        for (auto appId : appIds) {
+            if (appId >= AID_APP_START) {
+                collectQuotaStats(device, userId, appId, nullptr, &extStats);
+            }
+        }
+        appSize = extStats.dataSize;
+        ATRACE_END();
+    } else {
+        ATRACE_BEGIN("manual");
+        FTS *fts;
+        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))) {
+            return error("Failed to fts_open " + path);
+        }
+        while ((p = fts_read(fts)) != NULL) {
+            char* ext;
+            int64_t size = (p->fts_statp->st_blocks * 512);
+            switch (p->fts_info) {
+            case FTS_F:
+                // Only categorize files not belonging to apps
+                if (p->fts_parent->fts_number == 0) {
+                    ext = strrchr(p->fts_name, '.');
+                    if (ext != nullptr) {
+                        switch (MatchExtension(++ext)) {
+                        case AID_MEDIA_AUDIO: audioSize += size; break;
+                        case AID_MEDIA_VIDEO: videoSize += size; break;
+                        case AID_MEDIA_IMAGE: imageSize += size; break;
+                        }
+                    }
+                }
+                // Fall through to 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;
+                }
+            case FTS_DEFAULT:
+            case FTS_SL:
+            case FTS_SLNONE:
+                if (p->fts_parent->fts_number == 1) {
+                    appSize += size;
+                }
+                totalSize += size;
+                break;
+            }
+        }
+        fts_close(fts);
+        ATRACE_END();
+    }
+
+    std::vector<int64_t> ret;
+    ret.push_back(totalSize);
+    ret.push_back(audioSize);
+    ret.push_back(videoSize);
+    ret.push_back(imageSize);
+    ret.push_back(appSize);
+#if MEASURE_DEBUG
+    LOG(DEBUG) << "Final result " << toString(ret);
+#endif
+    *_aidl_return = ret;
+    return ok();
+}
+
+binder::Status InstalldNativeService::setAppQuota(const std::unique_ptr<std::string>& uuid,
+        int32_t userId, int32_t appId, int64_t cacheQuota) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(uuid);
+    std::lock_guard<std::recursive_mutex> lock(mQuotasLock);
+
+    int32_t uid = multiuser_get_uid(userId, appId);
+    mCacheQuotas[uid] = cacheQuota;
+
+    return ok();
+}
+
+// Dumps the contents of a profile file, using pkgname's dex files for pretty
+// printing the result.
+binder::Status InstalldNativeService::dumpProfiles(int32_t uid, const std::string& packageName,
+        const std::string& codePaths, bool* _aidl_return) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* pkgname = packageName.c_str();
+    const char* code_paths = codePaths.c_str();
+
+    *_aidl_return = dump_profiles(uid, pkgname, code_paths);
+    return ok();
+}
+
+// TODO: Consider returning error codes.
+binder::Status InstalldNativeService::mergeProfiles(int32_t uid, const std::string& packageName,
+        bool* _aidl_return) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    *_aidl_return = analyze_primary_profiles(uid, packageName);
+    return ok();
+}
+
+binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t uid,
+        const std::unique_ptr<std::string>& packageName, const std::string& instructionSet,
+        int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
+        const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
+        const std::unique_ptr<std::string>& sharedLibraries,
+        const std::unique_ptr<std::string>& seInfo) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(uuid);
+    if (packageName && *packageName != "*") {
+        CHECK_ARGUMENT_PACKAGE_NAME(*packageName);
+    }
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* apk_path = apkPath.c_str();
+    const char* pkgname = packageName ? packageName->c_str() : "*";
+    const char* instruction_set = instructionSet.c_str();
+    const char* oat_dir = outputPath ? outputPath->c_str() : nullptr;
+    const char* compiler_filter = compilerFilter.c_str();
+    const char* volume_uuid = uuid ? uuid->c_str() : nullptr;
+    const char* shared_libraries = sharedLibraries ? sharedLibraries->c_str() : nullptr;
+    const char* se_info = seInfo ? seInfo->c_str() : nullptr;
+    int res = android::installd::dexopt(apk_path, uid, pkgname, instruction_set, dexoptNeeded,
+            oat_dir, dexFlags, compiler_filter, volume_uuid, shared_libraries, se_info);
+    return res ? error(res, "Failed to dexopt") : ok();
+}
+
+binder::Status InstalldNativeService::markBootComplete(const std::string& instructionSet) {
+    ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* instruction_set = instructionSet.c_str();
+
+    char boot_marker_path[PKG_PATH_MAX];
+    sprintf(boot_marker_path,
+          "%s/%s/%s/.booting",
+          android_data_dir.path,
+          DALVIK_CACHE,
+          instruction_set);
+
+    ALOGV("mark_boot_complete : %s", boot_marker_path);
+    if (unlink(boot_marker_path) != 0) {
+        return error(StringPrintf("Failed to unlink %s", boot_marker_path));
+    }
+    return ok();
+}
+
+void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid,
+        struct stat* statbuf)
+{
+    while (path[basepos] != 0) {
+        if (path[basepos] == '/') {
+            path[basepos] = 0;
+            if (lstat(path, statbuf) < 0) {
+                ALOGV("Making directory: %s\n", path);
+                if (mkdir(path, mode) == 0) {
+                    chown(path, uid, gid);
+                } else {
+                    ALOGW("Unable to make directory %s: %s\n", path, strerror(errno));
+                }
+            }
+            path[basepos] = '/';
+            basepos++;
+        }
+        basepos++;
+    }
+}
+
+binder::Status InstalldNativeService::linkNativeLibraryDirectory(
+        const std::unique_ptr<std::string>& uuid, const std::string& packageName,
+        const std::string& nativeLibPath32, int32_t userId) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(uuid);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+    const char* pkgname = packageName.c_str();
+    const char* asecLibDir = nativeLibPath32.c_str();
+    struct stat s, libStat;
+    binder::Status res = ok();
+
+    auto _pkgdir = create_data_user_ce_package_path(uuid_, userId, pkgname);
+    auto _libsymlink = _pkgdir + PKG_LIB_POSTFIX;
+
+    const char* pkgdir = _pkgdir.c_str();
+    const char* libsymlink = _libsymlink.c_str();
+
+    if (stat(pkgdir, &s) < 0) {
+        return error("Failed to stat " + _pkgdir);
+    }
+
+    if (chown(pkgdir, AID_INSTALL, AID_INSTALL) < 0) {
+        return error("Failed to chown " + _pkgdir);
+    }
+
+    if (chmod(pkgdir, 0700) < 0) {
+        res = error("Failed to chmod " + _pkgdir);
+        goto out;
+    }
+
+    if (lstat(libsymlink, &libStat) < 0) {
+        if (errno != ENOENT) {
+            res = error("Failed to stat " + _libsymlink);
+            goto out;
+        }
+    } else {
+        if (S_ISDIR(libStat.st_mode)) {
+            if (delete_dir_contents(libsymlink, 1, NULL) < 0) {
+                res = error("Failed to delete " + _libsymlink);
+                goto out;
+            }
+        } else if (S_ISLNK(libStat.st_mode)) {
+            if (unlink(libsymlink) < 0) {
+                res = error("Failed to unlink " + _libsymlink);
+                goto out;
+            }
+        }
+    }
+
+    if (symlink(asecLibDir, libsymlink) < 0) {
+        res = error("Failed to symlink " + _libsymlink + " to " + nativeLibPath32);
+        goto out;
+    }
+
+out:
+    if (chmod(pkgdir, s.st_mode) < 0) {
+        auto msg = "Failed to cleanup chmod " + _pkgdir;
+        if (res.isOk()) {
+            res = error(msg);
+        } else {
+            PLOG(ERROR) << msg;
+        }
+    }
+
+    if (chown(pkgdir, s.st_uid, s.st_gid) < 0) {
+        auto msg = "Failed to cleanup chown " + _pkgdir;
+        if (res.isOk()) {
+            res = error(msg);
+        } else {
+            PLOG(ERROR) << msg;
+        }
+    }
+
+    return res;
+}
+
+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);
+    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);
+    PLOG(ERROR) << "execl (" << kIdMapPath << ") failed";
+}
+
+static bool delete_stale_idmap(const char* target_apk, const char* overlay_apk,
+        const char* idmap_path, int32_t uid) {
+    int idmap_fd = open(idmap_path, O_RDWR);
+    if (idmap_fd < 0) {
+        PLOG(ERROR) << "idmap open failed: " << idmap_path;
+        unlink(idmap_path);
+        return true;
+    }
+
+    pid_t pid;
+    pid = fork();
+    if (pid == 0) {
+        /* child -- drop privileges before continuing */
+        if (setgid(uid) != 0) {
+            LOG(ERROR) << "setgid(" << uid << ") failed during idmap";
+            exit(1);
+        }
+        if (setuid(uid) != 0) {
+            LOG(ERROR) << "setuid(" << uid << ") failed during idmap";
+            exit(1);
+        }
+        if (flock(idmap_fd, LOCK_EX | LOCK_NB) != 0) {
+            PLOG(ERROR) << "flock(" << idmap_path << ") failed during idmap";
+            exit(1);
+        }
+
+        run_verify_idmap(target_apk, overlay_apk, idmap_fd);
+        exit(1); /* only if exec call to deleting stale idmap failed */
+    } else {
+        int status = wait_child(pid);
+        close(idmap_fd);
+
+        if (status != 0) {
+            // Failed on verifying if idmap is made from target_apk and overlay_apk.
+            LOG(DEBUG) << "delete stale idmap: " << idmap_path;
+            unlink(idmap_path);
+            return true;
+        }
+    }
+    return false;
+}
+
+// Transform string /a/b/c.apk to (prefix)/a@b@c.apk@(suffix)
+// eg /a/b/c.apk to /data/resource-cache/a@b@c.apk@idmap
+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) {
+        return -1;
+    }
+    const size_t len_overlay_path = strlen(overlay_path);
+    // will access overlay_path + 1 further below; requires absolute path
+    if (len_overlay_path < 2 || *overlay_path != '/') {
+        return -1;
+    }
+    const size_t len_idmap_root = strlen(prefix);
+    const size_t len_suffix = strlen(suffix);
+    if (SIZE_MAX - len_idmap_root < len_overlay_path ||
+            SIZE_MAX - (len_idmap_root + len_overlay_path) < len_suffix) {
+        // additions below would cause overflow
+        return -1;
+    }
+    if (N < len_idmap_root + len_overlay_path + len_suffix) {
+        return -1;
+    }
+    memset(idmap_path, 0, N);
+    snprintf(idmap_path, N, "%s%s%s", prefix, overlay_path + 1, suffix);
+    char *ch = idmap_path + len_idmap_root;
+    while (*ch != '\0') {
+        if (*ch == '/') {
+            *ch = '@';
+        }
+        ++ch;
+    }
+    return 0;
+}
+
+binder::Status InstalldNativeService::idmap(const std::string& targetApkPath,
+        const std::string& overlayApkPath, int32_t uid) {
+    ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* target_apk = targetApkPath.c_str();
+    const char* overlay_apk = overlayApkPath.c_str();
+    ALOGV("idmap target_apk=%s overlay_apk=%s uid=%d\n", target_apk, overlay_apk, uid);
+
+    int idmap_fd = -1;
+    char idmap_path[PATH_MAX];
+    struct stat idmap_stat;
+    bool outdated = false;
+
+    if (flatten_path(IDMAP_PREFIX, IDMAP_SUFFIX, overlay_apk,
+                idmap_path, sizeof(idmap_path)) == -1) {
+        ALOGE("idmap cannot generate idmap path for overlay %s\n", overlay_apk);
+        goto fail;
+    }
+
+    if (stat(idmap_path, &idmap_stat) < 0) {
+        outdated = true;
+    } else {
+        outdated = delete_stale_idmap(target_apk, overlay_apk, idmap_path, uid);
+    }
+
+    if (outdated) {
+        idmap_fd = open(idmap_path, O_RDWR | O_CREAT | O_EXCL, 0644);
+    } else {
+        idmap_fd = open(idmap_path, O_RDWR);
+    }
+
+    if (idmap_fd < 0) {
+        ALOGE("idmap cannot open '%s' for output: %s\n", idmap_path, strerror(errno));
+        goto fail;
+    }
+    if (fchown(idmap_fd, AID_SYSTEM, uid) < 0) {
+        ALOGE("idmap cannot chown '%s'\n", idmap_path);
+        goto fail;
+    }
+    if (fchmod(idmap_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) {
+        ALOGE("idmap cannot chmod '%s'\n", idmap_path);
+        goto fail;
+    }
+
+    if (!outdated) {
+        close(idmap_fd);
+        return ok();
+    }
+
+    pid_t pid;
+    pid = fork();
+    if (pid == 0) {
+        /* child -- drop privileges before continuing */
+        if (setgid(uid) != 0) {
+            ALOGE("setgid(%d) failed during idmap\n", uid);
+            exit(1);
+        }
+        if (setuid(uid) != 0) {
+            ALOGE("setuid(%d) failed during idmap\n", uid);
+            exit(1);
+        }
+        if (flock(idmap_fd, LOCK_EX | LOCK_NB) != 0) {
+            ALOGE("flock(%s) failed during idmap: %s\n", idmap_path, strerror(errno));
+            exit(1);
+        }
+
+        run_idmap(target_apk, overlay_apk, idmap_fd);
+        exit(1); /* only if exec call to idmap failed */
+    } else {
+        int status = wait_child(pid);
+        if (status != 0) {
+            ALOGE("idmap failed, status=0x%04x\n", status);
+            goto fail;
+        }
+    }
+
+    close(idmap_fd);
+    return ok();
+fail:
+    if (idmap_fd >= 0) {
+        close(idmap_fd);
+        unlink(idmap_path);
+    }
+    return error();
+}
+
+binder::Status InstalldNativeService::removeIdmap(const std::string& overlayApkPath) {
+    const char* overlay_apk = overlayApkPath.c_str();
+    char idmap_path[PATH_MAX];
+
+    if (flatten_path(IDMAP_PREFIX, IDMAP_SUFFIX, overlay_apk,
+                idmap_path, sizeof(idmap_path)) == -1) {
+        ALOGE("idmap cannot generate idmap path for overlay %s\n", overlay_apk);
+        return error();
+    }
+    if (unlink(idmap_path) < 0) {
+        ALOGE("couldn't unlink idmap file %s\n", idmap_path);
+        return error();
+    }
+    return ok();
+}
+
+binder::Status InstalldNativeService::restoreconAppData(const std::unique_ptr<std::string>& uuid,
+        const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
+        const std::string& seInfo) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(uuid);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    binder::Status res = ok();
+
+    // SELINUX_ANDROID_RESTORECON_DATADATA flag is set by libselinux. Not needed here.
+    unsigned int seflags = SELINUX_ANDROID_RESTORECON_RECURSE;
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+    const char* pkgName = packageName.c_str();
+    const char* seinfo = seInfo.c_str();
+
+    uid_t uid = multiuser_get_uid(userId, appId);
+    if (flags & FLAG_STORAGE_CE) {
+        auto path = create_data_user_ce_package_path(uuid_, userId, pkgName);
+        if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, seflags) < 0) {
+            res = error("restorecon failed for " + path);
+        }
+    }
+    if (flags & FLAG_STORAGE_DE) {
+        auto path = create_data_user_de_package_path(uuid_, userId, pkgName);
+        if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, seflags) < 0) {
+            res = error("restorecon failed for " + path);
+        }
+    }
+    return res;
+}
+
+binder::Status InstalldNativeService::createOatDir(const std::string& oatDir,
+        const std::string& instructionSet) {
+    ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* oat_dir = oatDir.c_str();
+    const char* instruction_set = instructionSet.c_str();
+    char oat_instr_dir[PKG_PATH_MAX];
+
+    if (validate_apk_path(oat_dir)) {
+        return error("Invalid path " + oatDir);
+    }
+    if (fs_prepare_dir(oat_dir, S_IRWXU | S_IRWXG | S_IXOTH, AID_SYSTEM, AID_INSTALL)) {
+        return error("Failed to prepare " + oatDir);
+    }
+    if (selinux_android_restorecon(oat_dir, 0)) {
+        return error("Failed to restorecon " + oatDir);
+    }
+    snprintf(oat_instr_dir, PKG_PATH_MAX, "%s/%s", oat_dir, instruction_set);
+    if (fs_prepare_dir(oat_instr_dir, S_IRWXU | S_IRWXG | S_IXOTH, AID_SYSTEM, AID_INSTALL)) {
+        return error(StringPrintf("Failed to prepare %s", oat_instr_dir));
+    }
+    return ok();
+}
+
+binder::Status InstalldNativeService::rmPackageDir(const std::string& packageDir) {
+    ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    if (validate_apk_path(packageDir.c_str())) {
+        return error("Invalid path " + packageDir);
+    }
+    if (delete_dir_contents_and_dir(packageDir) != 0) {
+        return error("Failed to delete " + packageDir);
+    }
+    return ok();
+}
+
+binder::Status InstalldNativeService::linkFile(const std::string& relativePath,
+        const std::string& fromBase, const std::string& toBase) {
+    ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* relative_path = relativePath.c_str();
+    const char* from_base = fromBase.c_str();
+    const char* to_base = toBase.c_str();
+    char from_path[PKG_PATH_MAX];
+    char to_path[PKG_PATH_MAX];
+    snprintf(from_path, PKG_PATH_MAX, "%s/%s", from_base, relative_path);
+    snprintf(to_path, PKG_PATH_MAX, "%s/%s", to_base, relative_path);
+
+    if (validate_apk_path_subdirs(from_path)) {
+        return error(StringPrintf("Invalid from path %s", from_path));
+    }
+
+    if (validate_apk_path_subdirs(to_path)) {
+        return error(StringPrintf("Invalid to path %s", to_path));
+    }
+
+    if (link(from_path, to_path) < 0) {
+        return error(StringPrintf("Failed to link from %s to %s", from_path, to_path));
+    }
+
+    return ok();
+}
+
+binder::Status InstalldNativeService::moveAb(const std::string& apkPath,
+        const std::string& instructionSet, const std::string& outputPath) {
+    ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* apk_path = apkPath.c_str();
+    const char* instruction_set = instructionSet.c_str();
+    const char* oat_dir = outputPath.c_str();
+
+    bool success = move_ab(apk_path, instruction_set, oat_dir);
+    return success ? ok() : error();
+}
+
+binder::Status InstalldNativeService::deleteOdex(const std::string& apkPath,
+        const std::string& instructionSet, const std::unique_ptr<std::string>& outputPath) {
+    ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* apk_path = apkPath.c_str();
+    const char* instruction_set = instructionSet.c_str();
+    const char* oat_dir = outputPath ? outputPath->c_str() : nullptr;
+
+    bool res = delete_odex(apk_path, instruction_set, oat_dir);
+    return res ? ok() : error();
+}
+
+binder::Status InstalldNativeService::reconcileSecondaryDexFile(
+        const std::string& dexPath, const std::string& packageName, int32_t uid,
+        const std::vector<std::string>& isas, const std::unique_ptr<std::string>& volumeUuid,
+        int32_t storage_flag, bool* _aidl_return) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(volumeUuid);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+    bool result = android::installd::reconcile_secondary_dex_file(
+            dexPath, packageName, uid, isas, volumeUuid, storage_flag, _aidl_return);
+    return result ? ok() : error();
+}
+
+binder::Status InstalldNativeService::invalidateMounts() {
+    ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+
+    mStorageMounts.clear();
+    mQuotaReverseMounts.clear();
+
+    std::ifstream in("/proc/mounts");
+    if (!in.is_open()) {
+        return error("Failed to read mounts");
+    }
+
+    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 !BYPASS_SDCARDFS
+        if (target.compare(0, 21, "/mnt/runtime/default/") == 0) {
+            LOG(DEBUG) << "Found storage mount " << source << " at " << target;
+            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.
+                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();
+}
+
+std::string InstalldNativeService::findDataMediaPath(
+        const std::unique_ptr<std::string>& uuid, userid_t userid) {
+    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+    auto path = StringPrintf("%s/media", create_data_path(uuid_).c_str());
+    auto resolved = mStorageMounts[path];
+    if (resolved.empty()) {
+        LOG(WARNING) << "Failed to find storage mount for " << path;
+        resolved = path;
+    }
+    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();
+    return ok();
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
new file mode 100644
index 0000000..4011315
--- /dev/null
+++ b/cmds/installd/InstalldNativeService.h
@@ -0,0 +1,142 @@
+/*
+**
+** Copyright 2008, 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 COMMANDS_H_
+#define COMMANDS_H_
+
+#include <inttypes.h>
+#include <unistd.h>
+
+#include <vector>
+#include <unordered_map>
+
+#include <android-base/macros.h>
+#include <binder/BinderService.h>
+#include <cutils/multiuser.h>
+
+#include "android/os/BnInstalld.h"
+#include "installd_constants.h"
+
+namespace android {
+namespace installd {
+
+class InstalldNativeService : public BinderService<InstalldNativeService>, public os::BnInstalld {
+public:
+    static status_t start();
+    static char const* getServiceName() { return "installd"; }
+    virtual status_t dump(int fd, const Vector<String16> &args) override;
+
+    binder::Status createUserData(const std::unique_ptr<std::string>& uuid, int32_t userId,
+            int32_t userSerial, int32_t flags);
+    binder::Status destroyUserData(const std::unique_ptr<std::string>& uuid, int32_t userId,
+            int32_t flags);
+
+    binder::Status createAppData(const std::unique_ptr<std::string>& uuid,
+            const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
+            const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return);
+    binder::Status restoreconAppData(const std::unique_ptr<std::string>& uuid,
+            const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
+            const std::string& seInfo);
+    binder::Status migrateAppData(const std::unique_ptr<std::string>& uuid,
+            const std::string& packageName, int32_t userId, int32_t flags);
+    binder::Status clearAppData(const std::unique_ptr<std::string>& uuid,
+            const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode);
+    binder::Status destroyAppData(const std::unique_ptr<std::string>& uuid,
+            const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode);
+
+    binder::Status fixupAppData(const std::unique_ptr<std::string>& uuid, int32_t flags);
+
+    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,
+            const std::vector<std::string>& codePaths, std::vector<int64_t>* _aidl_return);
+    binder::Status getUserSize(const std::unique_ptr<std::string>& uuid,
+            int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
+            std::vector<int64_t>* _aidl_return);
+    binder::Status getExternalSize(const std::unique_ptr<std::string>& uuid,
+            int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
+            std::vector<int64_t>* _aidl_return);
+
+    binder::Status setAppQuota(const std::unique_ptr<std::string>& uuid,
+            int32_t userId, int32_t appId, int64_t cacheQuota);
+
+    binder::Status 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,
+            int32_t targetSdkVersion);
+
+    binder::Status dexopt(const std::string& apkPath, int32_t uid,
+            const std::unique_ptr<std::string>& packageName, const std::string& instructionSet,
+            int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
+            const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
+            const std::unique_ptr<std::string>& sharedLibraries,
+            const std::unique_ptr<std::string>& seInfo);
+
+    binder::Status rmdex(const std::string& codePath, const std::string& instructionSet);
+
+    binder::Status mergeProfiles(int32_t uid, const std::string& packageName, bool* _aidl_return);
+    binder::Status dumpProfiles(int32_t uid, const std::string& packageName,
+            const std::string& codePaths, bool* _aidl_return);
+    binder::Status clearAppProfiles(const std::string& packageName);
+    binder::Status destroyAppProfiles(const std::string& packageName);
+
+    binder::Status idmap(const std::string& targetApkPath, const std::string& overlayApkPath,
+            int32_t uid);
+    binder::Status removeIdmap(const std::string& overlayApkPath);
+    binder::Status rmPackageDir(const std::string& packageDir);
+    binder::Status markBootComplete(const std::string& instructionSet);
+    binder::Status freeCache(const std::unique_ptr<std::string>& uuid, int64_t targetFreeBytes,
+            int64_t cacheReservedBytes, int32_t flags);
+    binder::Status linkNativeLibraryDirectory(const std::unique_ptr<std::string>& uuid,
+            const std::string& packageName, const std::string& nativeLibPath32, int32_t userId);
+    binder::Status createOatDir(const std::string& oatDir, const std::string& instructionSet);
+    binder::Status linkFile(const std::string& relativePath, const std::string& fromBase,
+            const std::string& toBase);
+    binder::Status moveAb(const std::string& apkPath, const std::string& instructionSet,
+            const std::string& outputPath);
+    binder::Status deleteOdex(const std::string& apkPath, const std::string& instructionSet,
+            const std::unique_ptr<std::string>& outputPath);
+    binder::Status reconcileSecondaryDexFile(const std::string& dexPath,
+        const std::string& packageName, int32_t uid, const std::vector<std::string>& isa,
+        const std::unique_ptr<std::string>& volumeUuid, int32_t storage_flag, bool* _aidl_return);
+
+    binder::Status invalidateMounts();
+    binder::Status isQuotaSupported(const std::unique_ptr<std::string>& volumeUuid,
+            bool* _aidl_return);
+
+private:
+    std::recursive_mutex mLock;
+
+    std::recursive_mutex mMountsLock;
+    std::recursive_mutex mQuotasLock;
+
+    /* 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
+}  // namespace android
+
+#endif  // COMMANDS_H_
diff --git a/cmds/installd/MatchExtensionGen.h b/cmds/installd/MatchExtensionGen.h
new file mode 100644
index 0000000..fded6b7
--- /dev/null
+++ b/cmds/installd/MatchExtensionGen.h
@@ -0,0 +1,628 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/******************************************************************
+ * THIS CODE WAS GENERATED BY matchgen.py, DO NOT MODIFY DIRECTLY *
+ ******************************************************************/
+
+#include <private/android_filesystem_config.h>
+
+int MatchExtension(const char* ext) {
+
+    switch (ext[0]) {
+    case '3':
+        switch (ext[1]) {
+        case 'g': case 'G':
+            switch (ext[2]) {
+            case '2':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_VIDEO;
+                }
+            case 'p': case 'P':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_VIDEO;
+                case 'p': case 'P':
+                    switch (ext[4]) {
+                    case '\0': return AID_MEDIA_VIDEO;
+                    case '2':
+                        switch (ext[5]) {
+                        case '\0': return AID_MEDIA_VIDEO;
+                        }
+                    }
+                }
+            }
+        }
+    case 'a': case 'A':
+        switch (ext[1]) {
+        case 'a': case 'A':
+            switch (ext[2]) {
+            case 'c': case 'C':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_AUDIO;
+                }
+            }
+        case 'i': case 'I':
+            switch (ext[2]) {
+            case 'f': case 'F':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_AUDIO;
+                case 'c': case 'C':
+                    switch (ext[4]) {
+                    case '\0': return AID_MEDIA_AUDIO;
+                    }
+                case 'f': case 'F':
+                    switch (ext[4]) {
+                    case '\0': return AID_MEDIA_AUDIO;
+                    }
+                }
+            }
+        case 'm': case 'M':
+            switch (ext[2]) {
+            case 'r': case 'R':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_AUDIO;
+                }
+            }
+        case 'r': case 'R':
+            switch (ext[2]) {
+            case 't': case 'T':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            case 'w': case 'W':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        case 's': case 'S':
+            switch (ext[2]) {
+            case 'f': case 'F':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_VIDEO;
+                }
+            case 'x': case 'X':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_VIDEO;
+                }
+            }
+        case 'v': case 'V':
+            switch (ext[2]) {
+            case 'i': case 'I':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_VIDEO;
+                }
+            }
+        case 'w': case 'W':
+            switch (ext[2]) {
+            case 'b': case 'B':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_AUDIO;
+                }
+            }
+        }
+    case 'b': case 'B':
+        switch (ext[1]) {
+        case 'm': case 'M':
+            switch (ext[2]) {
+            case 'p': case 'P':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        }
+    case 'c': case 'C':
+        switch (ext[1]) {
+        case 'r': case 'R':
+            switch (ext[2]) {
+            case '2':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        }
+    case 'd': case 'D':
+        switch (ext[1]) {
+        case 'i': case 'I':
+            switch (ext[2]) {
+            case 'f': case 'F':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_VIDEO;
+                }
+            }
+        case 'l': case 'L':
+            switch (ext[2]) {
+            case '\0': return AID_MEDIA_VIDEO;
+            }
+        case 'n': case 'N':
+            switch (ext[2]) {
+            case 'g': case 'G':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        case 'v': case 'V':
+            switch (ext[2]) {
+            case '\0': return AID_MEDIA_VIDEO;
+            }
+        }
+    case 'f': case 'F':
+        switch (ext[1]) {
+        case 'l': case 'L':
+            switch (ext[2]) {
+            case 'a': case 'A':
+                switch (ext[3]) {
+                case 'c': case 'C':
+                    switch (ext[4]) {
+                    case '\0': return AID_MEDIA_AUDIO;
+                    }
+                }
+            case 'i': case 'I':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_VIDEO;
+                }
+            }
+        }
+    case 'g': case 'G':
+        switch (ext[1]) {
+        case 'i': case 'I':
+            switch (ext[2]) {
+            case 'f': case 'F':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        case 's': case 'S':
+            switch (ext[2]) {
+            case 'm': case 'M':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_AUDIO;
+                }
+            }
+        }
+    case 'j': case 'J':
+        switch (ext[1]) {
+        case 'n': case 'N':
+            switch (ext[2]) {
+            case 'g': case 'G':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        case 'p': case 'P':
+            switch (ext[2]) {
+            case 'e': case 'E':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                case 'g': case 'G':
+                    switch (ext[4]) {
+                    case '\0': return AID_MEDIA_IMAGE;
+                    }
+                }
+            case 'g': case 'G':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        }
+    case 'l': case 'L':
+        switch (ext[1]) {
+        case 's': case 'S':
+            switch (ext[2]) {
+            case 'f': case 'F':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_VIDEO;
+                }
+            case 'x': case 'X':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_VIDEO;
+                }
+            }
+        }
+    case 'm': case 'M':
+        switch (ext[1]) {
+        case '3':
+            switch (ext[2]) {
+            case 'u': case 'U':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_AUDIO;
+                }
+            }
+        case '4':
+            switch (ext[2]) {
+            case 'a': case 'A':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_AUDIO;
+                }
+            case 'v': case 'V':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_VIDEO;
+                }
+            }
+        case 'k': case 'K':
+            switch (ext[2]) {
+            case 'a': case 'A':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_AUDIO;
+                }
+            case 'v': case 'V':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_VIDEO;
+                }
+            }
+        case 'n': case 'N':
+            switch (ext[2]) {
+            case 'g': case 'G':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_VIDEO;
+                }
+            }
+        case 'o': case 'O':
+            switch (ext[2]) {
+            case 'v': case 'V':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_VIDEO;
+                case 'i': case 'I':
+                    switch (ext[4]) {
+                    case 'e': case 'E':
+                        switch (ext[5]) {
+                        case '\0': return AID_MEDIA_VIDEO;
+                        }
+                    }
+                }
+            }
+        case 'p': case 'P':
+            switch (ext[2]) {
+            case '2':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_AUDIO;
+                }
+            case '3':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_AUDIO;
+                }
+            case '4':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_VIDEO;
+                }
+            case 'e': case 'E':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_VIDEO;
+                case 'g': case 'G':
+                    switch (ext[4]) {
+                    case '\0': return AID_MEDIA_VIDEO;
+                    case 'a': case 'A':
+                        switch (ext[5]) {
+                        case '\0': return AID_MEDIA_AUDIO;
+                        }
+                    }
+                }
+            case 'g': case 'G':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_VIDEO;
+                case 'a': case 'A':
+                    switch (ext[4]) {
+                    case '\0': return AID_MEDIA_AUDIO;
+                    }
+                }
+            }
+        case 'x': case 'X':
+            switch (ext[2]) {
+            case 'u': case 'U':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_VIDEO;
+                }
+            }
+        }
+    case 'n': case 'N':
+        switch (ext[1]) {
+        case 'e': case 'E':
+            switch (ext[2]) {
+            case 'f': case 'F':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        case 'r': case 'R':
+            switch (ext[2]) {
+            case 'w': case 'W':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        }
+    case 'o': case 'O':
+        switch (ext[1]) {
+        case 'g': case 'G':
+            switch (ext[2]) {
+            case 'a': case 'A':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_AUDIO;
+                }
+            case 'g': case 'G':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_AUDIO;
+                }
+            }
+        case 'r': case 'R':
+            switch (ext[2]) {
+            case 'f': case 'F':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        }
+    case 'p': case 'P':
+        switch (ext[1]) {
+        case 'b': case 'B':
+            switch (ext[2]) {
+            case 'm': case 'M':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        case 'c': case 'C':
+            switch (ext[2]) {
+            case 'x': case 'X':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        case 'e': case 'E':
+            switch (ext[2]) {
+            case 'f': case 'F':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        case 'g': case 'G':
+            switch (ext[2]) {
+            case 'm': case 'M':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        case 'l': case 'L':
+            switch (ext[2]) {
+            case 's': case 'S':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_AUDIO;
+                }
+            }
+        case 'n': case 'N':
+            switch (ext[2]) {
+            case 'g': case 'G':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            case 'm': case 'M':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        case 'p': case 'P':
+            switch (ext[2]) {
+            case 'm': case 'M':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        case 's': case 'S':
+            switch (ext[2]) {
+            case 'd': case 'D':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        }
+    case 'q': case 'Q':
+        switch (ext[1]) {
+        case 't': case 'T':
+            switch (ext[2]) {
+            case '\0': return AID_MEDIA_VIDEO;
+            }
+        }
+    case 'r': case 'R':
+        switch (ext[1]) {
+        case 'a': case 'A':
+            switch (ext[2]) {
+            case '\0': return AID_MEDIA_AUDIO;
+            case 'm': case 'M':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_AUDIO;
+                }
+            case 's': case 'S':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        case 'g': case 'G':
+            switch (ext[2]) {
+            case 'b': case 'B':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        case 'm': case 'M':
+            switch (ext[2]) {
+            case '\0': return AID_MEDIA_AUDIO;
+            }
+        case 'w': case 'W':
+            switch (ext[2]) {
+            case '2':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        }
+    case 's': case 'S':
+        switch (ext[1]) {
+        case 'd': case 'D':
+            switch (ext[2]) {
+            case '2':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_AUDIO;
+                }
+            }
+        case 'n': case 'N':
+            switch (ext[2]) {
+            case 'd': case 'D':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_AUDIO;
+                }
+            }
+        case 'r': case 'R':
+            switch (ext[2]) {
+            case 'w': case 'W':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        case 'v': case 'V':
+            switch (ext[2]) {
+            case 'g': case 'G':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                case 'z': case 'Z':
+                    switch (ext[4]) {
+                    case '\0': return AID_MEDIA_IMAGE;
+                    }
+                }
+            }
+        }
+    case 't': case 'T':
+        switch (ext[1]) {
+        case 'i': case 'I':
+            switch (ext[2]) {
+            case 'f': case 'F':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                case 'f': case 'F':
+                    switch (ext[4]) {
+                    case '\0': return AID_MEDIA_IMAGE;
+                    }
+                }
+            }
+        case 's': case 'S':
+            switch (ext[2]) {
+            case '\0': return AID_MEDIA_VIDEO;
+            }
+        }
+    case 'v': case 'V':
+        switch (ext[1]) {
+        case 'o': case 'O':
+            switch (ext[2]) {
+            case 'b': case 'B':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_VIDEO;
+                }
+            }
+        }
+    case 'w': case 'W':
+        switch (ext[1]) {
+        case 'a': case 'A':
+            switch (ext[2]) {
+            case 'v': case 'V':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_AUDIO;
+                }
+            case 'x': case 'X':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_AUDIO;
+                }
+            }
+        case 'b': case 'B':
+            switch (ext[2]) {
+            case 'm': case 'M':
+                switch (ext[3]) {
+                case 'p': case 'P':
+                    switch (ext[4]) {
+                    case '\0': return AID_MEDIA_IMAGE;
+                    }
+                }
+            }
+        case 'e': case 'E':
+            switch (ext[2]) {
+            case 'b': case 'B':
+                switch (ext[3]) {
+                case 'm': case 'M':
+                    switch (ext[4]) {
+                    case '\0': return AID_MEDIA_VIDEO;
+                    }
+                case 'p': case 'P':
+                    switch (ext[4]) {
+                    case '\0': return AID_MEDIA_IMAGE;
+                    }
+                }
+            }
+        case 'm': case 'M':
+            switch (ext[2]) {
+            case '\0': return AID_MEDIA_VIDEO;
+            case 'a': case 'A':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_AUDIO;
+                }
+            case 'v': case 'V':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_VIDEO;
+                }
+            case 'x': case 'X':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_VIDEO;
+                }
+            }
+        case 'r': case 'R':
+            switch (ext[2]) {
+            case 'f': case 'F':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_VIDEO;
+                }
+            }
+        case 'v': case 'V':
+            switch (ext[2]) {
+            case 'x': case 'X':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_VIDEO;
+                }
+            }
+        }
+    case 'x': case 'X':
+        switch (ext[1]) {
+        case 'b': case 'B':
+            switch (ext[2]) {
+            case 'm': case 'M':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        case 'p': case 'P':
+            switch (ext[2]) {
+            case 'm': case 'M':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        case 'w': case 'W':
+            switch (ext[2]) {
+            case 'd': case 'D':
+                switch (ext[3]) {
+                case '\0': return AID_MEDIA_IMAGE;
+                }
+            }
+        }
+    }
+
+    return 0;
+}
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
new file mode 100644
index 0000000..f09a397
--- /dev/null
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+package android.os;
+
+/** {@hide} */
+interface IInstalld {
+    void createUserData(@nullable @utf8InCpp String uuid, int userId, int userSerial, int flags);
+    void destroyUserData(@nullable @utf8InCpp String uuid, int userId, int flags);
+
+    long createAppData(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
+            int userId, int flags, int appId, in @utf8InCpp String seInfo, int targetSdkVersion);
+    void restoreconAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
+            int userId, int flags, int appId, @utf8InCpp String seInfo);
+    void migrateAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
+            int userId, int flags);
+    void clearAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
+            int userId, int flags, long ceDataInode);
+    void destroyAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
+            int userId, int flags, long ceDataInode);
+
+    void fixupAppData(@nullable @utf8InCpp String uuid, int flags);
+
+    long[] getAppSize(@nullable @utf8InCpp String uuid, in @utf8InCpp String[] packageNames,
+            int userId, int flags, int appId, in long[] ceDataInodes,
+            in @utf8InCpp String[] codePaths);
+    long[] getUserSize(@nullable @utf8InCpp String uuid, int userId, int flags, in int[] appIds);
+    long[] getExternalSize(@nullable @utf8InCpp String uuid, int userId, int flags, in int[] appIds);
+
+    void setAppQuota(@nullable @utf8InCpp String uuid, int userId, int appId, long cacheQuota);
+
+    void moveCompleteApp(@nullable @utf8InCpp String fromUuid, @nullable @utf8InCpp String toUuid,
+            @utf8InCpp String packageName, @utf8InCpp String dataAppName, int appId,
+            @utf8InCpp String seInfo, int targetSdkVersion);
+
+    void dexopt(@utf8InCpp String apkPath, int uid, @nullable @utf8InCpp String packageName,
+            @utf8InCpp String instructionSet, int dexoptNeeded,
+            @nullable @utf8InCpp String outputPath, int dexFlags,
+            @utf8InCpp String compilerFilter, @nullable @utf8InCpp String uuid,
+            @nullable @utf8InCpp String sharedLibraries,
+            @nullable @utf8InCpp String seInfo);
+
+    void rmdex(@utf8InCpp String codePath, @utf8InCpp String instructionSet);
+
+    boolean mergeProfiles(int uid, @utf8InCpp String packageName);
+    boolean dumpProfiles(int uid, @utf8InCpp String packageName, @utf8InCpp String codePaths);
+    void clearAppProfiles(@utf8InCpp String packageName);
+    void destroyAppProfiles(@utf8InCpp String packageName);
+
+    void idmap(@utf8InCpp String targetApkPath, @utf8InCpp String overlayApkPath, int uid);
+    void removeIdmap(@utf8InCpp String overlayApkPath);
+    void rmPackageDir(@utf8InCpp String packageDir);
+    void markBootComplete(@utf8InCpp String instructionSet);
+    void freeCache(@nullable @utf8InCpp String uuid, long targetFreeBytes,
+            long cacheReservedBytes, int flags);
+    void linkNativeLibraryDirectory(@nullable @utf8InCpp String uuid,
+            @utf8InCpp String packageName, @utf8InCpp String nativeLibPath32, int userId);
+    void createOatDir(@utf8InCpp String oatDir, @utf8InCpp String instructionSet);
+    void linkFile(@utf8InCpp String relativePath, @utf8InCpp String fromBase,
+            @utf8InCpp String toBase);
+    void moveAb(@utf8InCpp String apkPath, @utf8InCpp String instructionSet,
+            @utf8InCpp String outputPath);
+    void deleteOdex(@utf8InCpp String apkPath, @utf8InCpp String instructionSet,
+            @nullable @utf8InCpp String outputPath);
+
+    boolean reconcileSecondaryDexFile(@utf8InCpp String dexPath, @utf8InCpp String pkgName,
+        int uid, in @utf8InCpp String[] isas, @nullable @utf8InCpp String volume_uuid,
+        int storage_flag);
+
+    void invalidateMounts();
+    boolean isQuotaSupported(@nullable @utf8InCpp String uuid);
+}
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
deleted file mode 100644
index 271c75b..0000000
--- a/cmds/installd/commands.cpp
+++ /dev/null
@@ -1,2294 +0,0 @@
-/*
-** Copyright 2008, 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 "commands.h"
-
-#include <errno.h>
-#include <inttypes.h>
-#include <regex>
-#include <stdlib.h>
-#include <sys/capability.h>
-#include <sys/file.h>
-#include <sys/resource.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/xattr.h>
-#include <unistd.h>
-
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
-#include <cutils/fs.h>
-#include <cutils/log.h>               // TODO: Move everything to base/logging.
-#include <cutils/sched_policy.h>
-#include <diskusage/dirsize.h>
-#include <logwrap/logwrap.h>
-#include <private/android_filesystem_config.h>
-#include <selinux/android.h>
-#include <system/thread_defs.h>
-
-#include <globals.h>
-#include <installd_deps.h>
-#include <otapreopt_utils.h>
-#include <utils.h>
-
-#ifndef LOG_TAG
-#define LOG_TAG "installd"
-#endif
-
-using android::base::EndsWith;
-using android::base::StringPrintf;
-
-namespace android {
-namespace installd {
-
-static constexpr const char* kCpPath = "/system/bin/cp";
-static constexpr const char* kXattrDefault = "user.default";
-
-static constexpr const char* PKG_LIB_POSTFIX = "/lib";
-static constexpr const char* CACHE_DIR_POSTFIX = "/cache";
-static constexpr const char* CODE_CACHE_DIR_POSTFIX = "/code_cache";
-
-static constexpr const char* IDMAP_PREFIX = "/data/resource-cache/";
-static constexpr const char* IDMAP_SUFFIX = "@idmap";
-
-// NOTE: keep in sync with StorageManager
-static constexpr int FLAG_STORAGE_DE = 1 << 0;
-static constexpr int FLAG_STORAGE_CE = 1 << 1;
-
-// 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;
-
-/* dexopt needed flags matching those in dalvik.system.DexFile */
-static constexpr int DEXOPT_DEX2OAT_NEEDED       = 1;
-static constexpr int DEXOPT_PATCHOAT_NEEDED      = 2;
-static constexpr int DEXOPT_SELF_PATCHOAT_NEEDED = 3;
-
-#define MIN_RESTRICTED_HOME_SDK_VERSION 24 // > M
-
-typedef int fd_t;
-
-static bool property_get_bool(const char* property_name, bool default_value = false) {
-    char tmp_property_value[kPropertyValueMax];
-    bool have_property = get_property(property_name, tmp_property_value, nullptr) > 0;
-    if (!have_property) {
-        return default_value;
-    }
-    return strcmp(tmp_property_value, "true") == 0;
-}
-
-// Keep profile paths in sync with ActivityThread.
-constexpr const char* PRIMARY_PROFILE_NAME = "primary.prof";
-static std::string create_primary_profile(const std::string& profile_dir) {
-    return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME);
-}
-
-/**
- * Perform restorecon of the given path, but only perform recursive restorecon
- * if the label of that top-level file actually changed.  This can save us
- * significant time by avoiding no-op traversals of large filesystem trees.
- */
-static int restorecon_app_data_lazy(const std::string& path, const char* seinfo, uid_t uid) {
-    int res = 0;
-    char* before = nullptr;
-    char* after = nullptr;
-
-    // Note that SELINUX_ANDROID_RESTORECON_DATADATA flag is set by
-    // libselinux. Not needed here.
-
-    if (lgetfilecon(path.c_str(), &before) < 0) {
-        PLOG(ERROR) << "Failed before getfilecon for " << path;
-        goto fail;
-    }
-    if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, 0) < 0) {
-        PLOG(ERROR) << "Failed top-level restorecon for " << path;
-        goto fail;
-    }
-    if (lgetfilecon(path.c_str(), &after) < 0) {
-        PLOG(ERROR) << "Failed after getfilecon for " << path;
-        goto fail;
-    }
-
-    // If the initial top-level restorecon above changed the label, then go
-    // back and restorecon everything recursively
-    if (strcmp(before, after)) {
-        LOG(DEBUG) << "Detected label change from " << before << " to " << after << " at " << path
-                << "; running recursive restorecon";
-        if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid,
-                SELINUX_ANDROID_RESTORECON_RECURSE) < 0) {
-            PLOG(ERROR) << "Failed recursive restorecon for " << path;
-            goto fail;
-        }
-    }
-
-    goto done;
-fail:
-    res = -1;
-done:
-    free(before);
-    free(after);
-    return res;
-}
-
-static int restorecon_app_data_lazy(const std::string& parent, const char* name, const char* seinfo,
-        uid_t uid) {
-    return restorecon_app_data_lazy(StringPrintf("%s/%s", parent.c_str(), name), seinfo, uid);
-}
-
-static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid) {
-    if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, uid) != 0) {
-        PLOG(ERROR) << "Failed to prepare " << path;
-        return -1;
-    }
-    return 0;
-}
-
-static int prepare_app_dir(const std::string& parent, const char* name, mode_t target_mode,
-        uid_t uid) {
-    return prepare_app_dir(StringPrintf("%s/%s", parent.c_str(), name), target_mode, uid);
-}
-
-int create_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags,
-        appid_t appid, const char* seinfo, int target_sdk_version) {
-    uid_t uid = multiuser_get_uid(userid, appid);
-    mode_t target_mode = target_sdk_version >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751;
-    if (flags & FLAG_STORAGE_CE) {
-        auto path = create_data_user_ce_package_path(uuid, userid, pkgname);
-        if (prepare_app_dir(path, target_mode, uid) ||
-                prepare_app_dir(path, "cache", 0771, uid) ||
-                prepare_app_dir(path, "code_cache", 0771, uid)) {
-            return -1;
-        }
-
-        // Consider restorecon over contents if label changed
-        if (restorecon_app_data_lazy(path, seinfo, uid) ||
-                restorecon_app_data_lazy(path, "cache", seinfo, uid) ||
-                restorecon_app_data_lazy(path, "code_cache", seinfo, uid)) {
-            return -1;
-        }
-
-        // Remember inode numbers of cache directories so that we can clear
-        // contents while CE storage is locked
-        if (write_path_inode(path, "cache", kXattrInodeCache) ||
-                write_path_inode(path, "code_cache", kXattrInodeCodeCache)) {
-            return -1;
-        }
-    }
-    if (flags & FLAG_STORAGE_DE) {
-        auto path = create_data_user_de_package_path(uuid, userid, pkgname);
-        if (prepare_app_dir(path, target_mode, uid)) {
-            // TODO: include result once 25796509 is fixed
-            return 0;
-        }
-
-        // Consider restorecon over contents if label changed
-        if (restorecon_app_data_lazy(path, seinfo, uid)) {
-            return -1;
-        }
-
-        if (property_get_bool("dalvik.vm.usejitprofiles")) {
-            const std::string profile_path = create_data_user_profile_package_path(userid, pkgname);
-            // read-write-execute only for the app user.
-            if (fs_prepare_dir_strict(profile_path.c_str(), 0700, uid, uid) != 0) {
-                PLOG(ERROR) << "Failed to prepare " << profile_path;
-                return -1;
-            }
-            std::string profile_file = create_primary_profile(profile_path);
-            // read-write only for the app user.
-            if (fs_prepare_file_strict(profile_file.c_str(), 0600, uid, uid) != 0) {
-                PLOG(ERROR) << "Failed to prepare " << profile_path;
-                return -1;
-            }
-            const std::string ref_profile_path = create_data_ref_profile_package_path(pkgname);
-            // dex2oat/profman runs under the shared app gid and it needs to read/write reference
-            // profiles.
-            appid_t shared_app_gid = multiuser_get_shared_app_gid(uid);
-            if (fs_prepare_dir_strict(
-                    ref_profile_path.c_str(), 0700, shared_app_gid, shared_app_gid) != 0) {
-                PLOG(ERROR) << "Failed to prepare " << ref_profile_path;
-                return -1;
-            }
-        }
-    }
-    return 0;
-}
-
-int migrate_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags) {
-    // This method only exists to upgrade system apps that have requested
-    // forceDeviceEncrypted, so their default storage always lives in a
-    // consistent location.  This only works on non-FBE devices, since we
-    // never want to risk exposing data on a device with real CE/DE storage.
-
-    auto ce_path = create_data_user_ce_package_path(uuid, userid, pkgname);
-    auto de_path = create_data_user_de_package_path(uuid, userid, pkgname);
-
-    // If neither directory is marked as default, assume CE is default
-    if (getxattr(ce_path.c_str(), kXattrDefault, nullptr, 0) == -1
-            && getxattr(de_path.c_str(), kXattrDefault, nullptr, 0) == -1) {
-        if (setxattr(ce_path.c_str(), kXattrDefault, nullptr, 0, 0) != 0) {
-            PLOG(ERROR) << "Failed to mark default storage " << ce_path;
-            return -1;
-        }
-    }
-
-    // Migrate default data location if needed
-    auto target = (flags & FLAG_STORAGE_DE) ? de_path : ce_path;
-    auto source = (flags & FLAG_STORAGE_DE) ? ce_path : de_path;
-
-    if (getxattr(target.c_str(), kXattrDefault, nullptr, 0) == -1) {
-        LOG(WARNING) << "Requested default storage " << target
-                << " is not active; migrating from " << source;
-        if (delete_dir_contents_and_dir(target) != 0) {
-            PLOG(ERROR) << "Failed to delete";
-            return -1;
-        }
-        if (rename(source.c_str(), target.c_str()) != 0) {
-            PLOG(ERROR) << "Failed to rename";
-            return -1;
-        }
-    }
-
-    return 0;
-}
-
-static bool clear_profile(const std::string& profile) {
-    base::unique_fd ufd(open(profile.c_str(), O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
-    if (ufd.get() < 0) {
-        if (errno != ENOENT) {
-            PLOG(WARNING) << "Could not open profile " << profile;
-            return false;
-        } else {
-            // Nothing to clear. That's ok.
-            return true;
-        }
-    }
-
-    if (flock(ufd.get(), LOCK_EX | LOCK_NB) != 0) {
-        if (errno != EWOULDBLOCK) {
-            PLOG(WARNING) << "Error locking profile " << profile;
-        }
-        // This implies that the app owning this profile is running
-        // (and has acquired the lock).
-        //
-        // If we can't acquire the lock bail out since clearing is useless anyway
-        // (the app will write again to the profile).
-        //
-        // Note:
-        // This does not impact the this is not an issue for the profiling correctness.
-        // In case this is needed because of an app upgrade, profiles will still be
-        // eventually cleared by the app itself due to checksum mismatch.
-        // If this is needed because profman advised, then keeping the data around
-        // until the next run is again not an issue.
-        //
-        // If the app attempts to acquire a lock while we've held one here,
-        // it will simply skip the current write cycle.
-        return false;
-    }
-
-    bool truncated = ftruncate(ufd.get(), 0) == 0;
-    if (!truncated) {
-        PLOG(WARNING) << "Could not truncate " << profile;
-    }
-    if (flock(ufd.get(), LOCK_UN) != 0) {
-        PLOG(WARNING) << "Error unlocking profile " << profile;
-    }
-    return truncated;
-}
-
-static bool clear_reference_profile(const char* pkgname) {
-    std::string reference_profile_dir = create_data_ref_profile_package_path(pkgname);
-    std::string reference_profile = create_primary_profile(reference_profile_dir);
-    return clear_profile(reference_profile);
-}
-
-static bool clear_current_profile(const char* pkgname, userid_t user) {
-    std::string profile_dir = create_data_user_profile_package_path(user, pkgname);
-    std::string profile = create_primary_profile(profile_dir);
-    return clear_profile(profile);
-}
-
-static bool clear_current_profiles(const char* pkgname) {
-    bool success = true;
-    std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
-    for (auto user : users) {
-        success &= clear_current_profile(pkgname, user);
-    }
-    return success;
-}
-
-int clear_app_profiles(const char* pkgname) {
-    bool success = true;
-    success &= clear_reference_profile(pkgname);
-    success &= clear_current_profiles(pkgname);
-    return success ? 0 : -1;
-}
-
-int clear_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags,
-        ino_t ce_data_inode) {
-    int res = 0;
-    if (flags & FLAG_STORAGE_CE) {
-        auto path = create_data_user_ce_package_path(uuid, userid, pkgname, ce_data_inode);
-        if (flags & FLAG_CLEAR_CACHE_ONLY) {
-            path = read_path_inode(path, "cache", kXattrInodeCache);
-        } else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) {
-            path = read_path_inode(path, "code_cache", kXattrInodeCodeCache);
-        }
-        if (access(path.c_str(), F_OK) == 0) {
-            res |= delete_dir_contents(path);
-        }
-    }
-    if (flags & FLAG_STORAGE_DE) {
-        std::string suffix = "";
-        bool only_cache = false;
-        if (flags & FLAG_CLEAR_CACHE_ONLY) {
-            suffix = CACHE_DIR_POSTFIX;
-            only_cache = true;
-        } else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) {
-            suffix = CODE_CACHE_DIR_POSTFIX;
-            only_cache = true;
-        }
-
-        auto path = create_data_user_de_package_path(uuid, userid, pkgname) + suffix;
-        if (access(path.c_str(), F_OK) == 0) {
-            // TODO: include result once 25796509 is fixed
-            delete_dir_contents(path);
-        }
-        if (!only_cache) {
-            if (!clear_current_profile(pkgname, userid)) {
-                res |= -1;
-            }
-        }
-    }
-    return res;
-}
-
-static int destroy_app_reference_profile(const char *pkgname) {
-    return delete_dir_contents_and_dir(
-        create_data_ref_profile_package_path(pkgname),
-        /*ignore_if_missing*/ true);
-}
-
-static int destroy_app_current_profiles(const char *pkgname, userid_t userid) {
-    return delete_dir_contents_and_dir(
-        create_data_user_profile_package_path(userid, pkgname),
-        /*ignore_if_missing*/ true);
-}
-
-int destroy_app_profiles(const char *pkgname) {
-    int result = 0;
-    std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
-    for (auto user : users) {
-        result |= destroy_app_current_profiles(pkgname, user);
-    }
-    result |= destroy_app_reference_profile(pkgname);
-    return result;
-}
-
-int destroy_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags,
-        ino_t ce_data_inode) {
-    int res = 0;
-    if (flags & FLAG_STORAGE_CE) {
-        res |= delete_dir_contents_and_dir(
-                create_data_user_ce_package_path(uuid, userid, pkgname, ce_data_inode));
-    }
-    if (flags & FLAG_STORAGE_DE) {
-        res |= delete_dir_contents_and_dir(
-                create_data_user_de_package_path(uuid, userid, pkgname));
-        destroy_app_current_profiles(pkgname, userid);
-        // TODO(calin): If the package is still installed by other users it's probably
-        // beneficial to keep the reference profile around.
-        // Verify if it's ok to do that.
-        destroy_app_reference_profile(pkgname);
-    }
-    return res;
-}
-
-int move_complete_app(const char *from_uuid, const char *to_uuid, const char *package_name,
-        const char *data_app_name, appid_t appid, const char* seinfo, int target_sdk_version) {
-    std::vector<userid_t> users = get_known_users(from_uuid);
-
-    // Copy app
-    {
-        auto from = create_data_app_package_path(from_uuid, data_app_name);
-        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);
-
-        if (rc != 0) {
-            LOG(ERROR) << "Failed copying " << from << " to " << to
-                    << ": status " << rc;
-            goto fail;
-        }
-
-        if (selinux_android_restorecon(to.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
-            LOG(ERROR) << "Failed to restorecon " << to;
-            goto fail;
-        }
-    }
-
-    // Copy private data for all known users
-    for (auto user : users) {
-
-        // Data source may not exist for all users; that's okay
-        auto from_ce = create_data_user_ce_package_path(from_uuid, user, package_name);
-        if (access(from_ce.c_str(), F_OK) != 0) {
-            LOG(INFO) << "Missing source " << from_ce;
-            continue;
-        }
-
-        if (create_app_data(to_uuid, package_name, user, FLAG_STORAGE_CE | FLAG_STORAGE_DE,
-                appid, seinfo, target_sdk_version) != 0) {
-            LOG(ERROR) << "Failed to create package target on " << to_uuid;
-            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);
-            if (rc != 0) {
-                LOG(ERROR) << "Failed copying " << from << " to " << to << " with status " << rc;
-                goto fail;
-            }
-        }
-        {
-            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);
-            if (rc != 0) {
-                LOG(ERROR) << "Failed copying " << from << " to " << to << " with status " << rc;
-                goto fail;
-            }
-        }
-
-        if (restorecon_app_data(to_uuid, package_name, user, FLAG_STORAGE_CE | FLAG_STORAGE_DE,
-                appid, seinfo) != 0) {
-            LOG(ERROR) << "Failed to restorecon";
-            goto fail;
-        }
-    }
-
-    // We let the framework scan the new location and persist that before
-    // deleting the data in the old location; this ordering ensures that
-    // we can recover from things like battery pulls.
-    return 0;
-
-fail:
-    // 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) {
-            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) {
-                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) {
-                LOG(WARNING) << "Failed to rollback " << to;
-            }
-        }
-    }
-    return -1;
-}
-
-int create_user_data(const char *uuid, userid_t userid, int user_serial ATTRIBUTE_UNUSED,
-        int flags) {
-    if (flags & FLAG_STORAGE_DE) {
-        if (uuid == nullptr) {
-            return ensure_config_user_dirs(userid);
-        }
-    }
-    return 0;
-}
-
-int destroy_user_data(const char *uuid, userid_t userid, int flags) {
-    int res = 0;
-    if (flags & FLAG_STORAGE_DE) {
-        res |= delete_dir_contents_and_dir(create_data_user_de_path(uuid, userid), true);
-        if (uuid == nullptr) {
-            res |= delete_dir_contents_and_dir(create_data_misc_legacy_path(userid), true);
-            res |= delete_dir_contents_and_dir(create_data_user_profiles_path(userid), true);
-        }
-    }
-    if (flags & FLAG_STORAGE_CE) {
-        res |= delete_dir_contents_and_dir(create_data_user_ce_path(uuid, userid), true);
-        res |= delete_dir_contents_and_dir(create_data_media_path(uuid, userid), true);
-    }
-    return res;
-}
-
-/* Try to ensure free_size bytes of storage are available.
- * Returns 0 on success.
- * This is rather simple-minded because doing a full LRU would
- * be potentially memory-intensive, and without atime it would
- * also require that apps constantly modify file metadata even
- * when just reading from the cache, which is pretty awful.
- */
-int free_cache(const char *uuid, int64_t free_size) {
-    cache_t* cache;
-    int64_t avail;
-
-    auto data_path = create_data_path(uuid);
-
-    avail = data_disk_free(data_path);
-    if (avail < 0) return -1;
-
-    ALOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail);
-    if (avail >= free_size) return 0;
-
-    cache = start_cache_collection();
-
-    auto users = get_known_users(uuid);
-    for (auto user : users) {
-        add_cache_files(cache, create_data_user_ce_path(uuid, user));
-        add_cache_files(cache, create_data_user_de_path(uuid, user));
-        add_cache_files(cache,
-                StringPrintf("%s/Android/data", create_data_media_path(uuid, user).c_str()));
-    }
-
-    clear_cache_files(data_path, cache, free_size);
-    finish_cache_collection(cache);
-
-    return data_disk_free(data_path) >= free_size ? 0 : -1;
-}
-
-int rm_dex(const char *path, const char *instruction_set)
-{
-    char dex_path[PKG_PATH_MAX];
-
-    if (validate_apk_path(path) && validate_system_app_path(path)) {
-        ALOGE("invalid apk path '%s' (bad prefix)\n", path);
-        return -1;
-    }
-
-    if (!create_cache_path(dex_path, path, instruction_set)) return -1;
-
-    ALOGV("unlink %s\n", dex_path);
-    if (unlink(dex_path) < 0) {
-        if (errno != ENOENT) {
-            ALOGE("Couldn't unlink %s: %s\n", dex_path, strerror(errno));
-        }
-        return -1;
-    } else {
-        return 0;
-    }
-}
-
-static void add_app_data_size(std::string& path, int64_t *codesize, int64_t *datasize,
-        int64_t *cachesize) {
-    DIR *d;
-    int dfd;
-    struct dirent *de;
-    struct stat s;
-
-    d = opendir(path.c_str());
-    if (d == nullptr) {
-        PLOG(WARNING) << "Failed to open " << path;
-        return;
-    }
-    dfd = dirfd(d);
-    while ((de = readdir(d))) {
-        const char *name = de->d_name;
-
-        int64_t statsize = 0;
-        if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
-            statsize = stat_size(&s);
-        }
-
-        if (de->d_type == DT_DIR) {
-            int subfd;
-            int64_t dirsize = 0;
-            /* always skip "." and ".." */
-            if (name[0] == '.') {
-                if (name[1] == 0) continue;
-                if ((name[1] == '.') && (name[2] == 0)) continue;
-            }
-            subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
-            if (subfd >= 0) {
-                dirsize = calculate_dir_size(subfd);
-                close(subfd);
-            }
-            // TODO: check xattrs!
-            if (!strcmp(name, "cache") || !strcmp(name, "code_cache")) {
-                *datasize += statsize;
-                *cachesize += dirsize;
-            } else {
-                *datasize += dirsize + statsize;
-            }
-        } else if (de->d_type == DT_LNK && !strcmp(name, "lib")) {
-            *codesize += statsize;
-        } else {
-            *datasize += statsize;
-        }
-    }
-    closedir(d);
-}
-
-int get_app_size(const char *uuid, const char *pkgname, int userid, int flags, ino_t ce_data_inode,
-        const char *code_path, int64_t *codesize, int64_t *datasize, int64_t *cachesize,
-        int64_t* asecsize) {
-    DIR *d;
-    int dfd;
-
-    d = opendir(code_path);
-    if (d != nullptr) {
-        dfd = dirfd(d);
-        *codesize += calculate_dir_size(dfd);
-        closedir(d);
-    }
-
-    if (flags & FLAG_STORAGE_CE) {
-        auto path = create_data_user_ce_package_path(uuid, userid, pkgname, ce_data_inode);
-        add_app_data_size(path, codesize, datasize, cachesize);
-    }
-    if (flags & FLAG_STORAGE_DE) {
-        auto path = create_data_user_de_package_path(uuid, userid, pkgname);
-        add_app_data_size(path, codesize, datasize, cachesize);
-    }
-
-    *asecsize = 0;
-
-    return 0;
-}
-
-int get_app_data_inode(const char *uuid, const char *pkgname, int userid, int flags, ino_t *inode) {
-    if (flags & FLAG_STORAGE_CE) {
-        auto path = create_data_user_ce_package_path(uuid, userid, pkgname);
-        return get_path_inode(path, inode);
-    }
-    return -1;
-}
-
-static int split_count(const char *str)
-{
-  char *ctx;
-  int count = 0;
-  char buf[kPropertyValueMax];
-
-  strncpy(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 void run_patchoat(int input_fd, int oat_fd, const char* input_file_name,
-    const char* output_file_name, const char *pkgname ATTRIBUTE_UNUSED, const char *instruction_set)
-{
-    static const int MAX_INT_LEN = 12;      // '-'+10dig+'\0' -OR- 0x+8dig
-    static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
-
-    static const char* PATCHOAT_BIN = "/system/bin/patchoat";
-    if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
-        ALOGE("Instruction set %s longer than max length of %d",
-              instruction_set, MAX_INSTRUCTION_SET_LEN);
-        return;
-    }
-
-    /* input_file_name/input_fd should be the .odex/.oat file that is precompiled. I think*/
-    char instruction_set_arg[strlen("--instruction-set=") + MAX_INSTRUCTION_SET_LEN];
-    char output_oat_fd_arg[strlen("--output-oat-fd=") + MAX_INT_LEN];
-    char input_oat_fd_arg[strlen("--input-oat-fd=") + MAX_INT_LEN];
-    const char* patched_image_location_arg = "--patched-image-location=/system/framework/boot.art";
-    // The caller has already gotten all the locks we need.
-    const char* no_lock_arg = "--no-lock-output";
-    sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set);
-    sprintf(output_oat_fd_arg, "--output-oat-fd=%d", oat_fd);
-    sprintf(input_oat_fd_arg, "--input-oat-fd=%d", input_fd);
-    ALOGV("Running %s isa=%s in-fd=%d (%s) out-fd=%d (%s)\n",
-          PATCHOAT_BIN, instruction_set, input_fd, input_file_name, oat_fd, output_file_name);
-
-    /* patchoat, patched-image-location, no-lock, isa, input-fd, output-fd */
-    char* argv[7];
-    argv[0] = (char*) PATCHOAT_BIN;
-    argv[1] = (char*) patched_image_location_arg;
-    argv[2] = (char*) no_lock_arg;
-    argv[3] = instruction_set_arg;
-    argv[4] = output_oat_fd_arg;
-    argv[5] = input_oat_fd_arg;
-    argv[6] = NULL;
-
-    execv(PATCHOAT_BIN, (char* const *)argv);
-    ALOGE("execv(%s) failed: %s\n", PATCHOAT_BIN, strerror(errno));
-}
-
-static void run_dex2oat(int zip_fd, int oat_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 vm_safe_mode, bool debuggable, bool post_bootcomplete,
-        int profile_fd, const char* shared_libraries) {
-    static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
-
-    if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
-        ALOGE("Instruction set %s longer than max length of %d",
-              instruction_set, MAX_INSTRUCTION_SET_LEN);
-        return;
-    }
-
-    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);
-    }
-
-    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 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");
-
-    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);
-    }
-
-    static const char* DEX2OAT_BIN = "/system/bin/dex2oat";
-
-    static const char* RUNTIME_ARG = "--runtime-arg";
-
-    static const int MAX_INT_LEN = 12;      // '-'+10dig+'\0' -OR- 0x+8dig
-
-    char zip_fd_arg[strlen("--zip-fd=") + MAX_INT_LEN];
-    char zip_location_arg[strlen("--zip-location=") + PKG_PATH_MAX];
-    char oat_fd_arg[strlen("--oat-fd=") + MAX_INT_LEN];
-    char oat_location_arg[strlen("--oat-location=") + PKG_PATH_MAX];
-    char instruction_set_arg[strlen("--instruction-set=") + MAX_INSTRUCTION_SET_LEN];
-    char instruction_set_variant_arg[strlen("--instruction-set-variant=") + kPropertyValueMax];
-    char instruction_set_features_arg[strlen("--instruction-set-features=") + kPropertyValueMax];
-    char dex2oat_Xms_arg[strlen("-Xms") + kPropertyValueMax];
-    char dex2oat_Xmx_arg[strlen("-Xmx") + kPropertyValueMax];
-    char dex2oat_compiler_filter_arg[strlen("--compiler-filter=") + kPropertyValueMax];
-    bool have_dex2oat_swap_fd = false;
-    char dex2oat_swap_fd[strlen("--swap-fd=") + MAX_INT_LEN];
-    bool have_dex2oat_image_fd = false;
-    char dex2oat_image_fd[strlen("--app-image-fd=") + MAX_INT_LEN];
-
-    sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd);
-    sprintf(zip_location_arg, "--zip-location=%s", input_file_name);
-    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);
-    }
-
-    // Compute compiler filter.
-
-    bool have_dex2oat_compiler_filter_flag;
-    if (skip_compilation) {
-        strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=verify-none");
-        have_dex2oat_compiler_filter_flag = true;
-        have_dex2oat_relocation_skip_flag = true;
-    } else if (vm_safe_mode) {
-        strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=interpret-only");
-        have_dex2oat_compiler_filter_flag = true;
-    } else if (compiler_filter != nullptr &&
-            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 {
-        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);
-        }
-    }
-
-    // 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);
-    }
-
-
-    ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, input_file_name, output_file_name);
-
-    const char* argv[7  // 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)
-                     + (shared_libraries != nullptr ? 4 : 0)
-                     + (have_dex2oat_large_app_threshold ? 1 : 0)];
-    int i = 0;
-    argv[i++] = DEX2OAT_BIN;
-    argv[i++] = zip_fd_arg;
-    argv[i++] = zip_location_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 (shared_libraries != nullptr) {
-        argv[i++] = RUNTIME_ARG;
-        argv[i++] = "-classpath";
-        argv[i++] = RUNTIME_ARG;
-        argv[i++] = shared_libraries;
-    }
-    // Do not add after dex2oat_flags, they should override others for debugging.
-    argv[i] = NULL;
-
-    execv(DEX2OAT_BIN, (char * const *)argv);
-    ALOGE("execv(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno));
-}
-
-/*
- * Whether dexopt should use a swap file when compiling an APK.
- *
- * If kAlwaysProvideSwapFile, do this on all devices (dex2oat will make a more informed decision
- * itself, anyways).
- *
- * Otherwise, read "dalvik.vm.dex2oat-swap". If the property exists, return whether it is "true".
- *
- * Otherwise, return true if this is a low-mem device.
- *
- * Otherwise, return default value.
- */
-static bool kAlwaysProvideSwapFile = false;
-static bool kDefaultProvideSwapFile = true;
-
-static bool ShouldUseSwapFileForDexopt() {
-    if (kAlwaysProvideSwapFile) {
-        return true;
-    }
-
-    // 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;
-        }
-    }
-
-    // Shortcut for default value. This is an implementation optimization for the process sketched
-    // above. If the default value is true, we can avoid to check whether this is a low-mem device,
-    // as low-mem is never returning false. The compiler will optimize this away if it can.
-    if (kDefaultProvideSwapFile) {
-        return true;
-    }
-
-    bool is_low_mem = property_get_bool("ro.config.low_ram");
-    if (is_low_mem) {
-        return true;
-    }
-
-    // Default value must be false here.
-    return kDefaultProvideSwapFile;
-}
-
-static void SetDex2OatAndPatchOatScheduling(bool set_to_bg) {
-    if (set_to_bg) {
-        if (set_sched_policy(0, SP_BACKGROUND) < 0) {
-            ALOGE("set_sched_policy failed: %s\n", strerror(errno));
-            exit(70);
-        }
-        if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
-            ALOGE("setpriority failed: %s\n", strerror(errno));
-            exit(71);
-        }
-    }
-}
-
-static void close_all_fds(const std::vector<fd_t>& fds, const char* description) {
-    for (size_t i = 0; i < fds.size(); i++) {
-        if (close(fds[i]) != 0) {
-            PLOG(WARNING) << "Failed to close fd for " << description << " at index " << i;
-        }
-    }
-}
-
-static fd_t open_profile_dir(const std::string& profile_dir) {
-    fd_t profile_dir_fd = TEMP_FAILURE_RETRY(open(profile_dir.c_str(),
-            O_PATH | O_CLOEXEC | O_DIRECTORY | O_NOFOLLOW));
-    if (profile_dir_fd < 0) {
-        // In a multi-user environment, these directories can be created at
-        // different points and it's possible we'll attempt to open a profile
-        // dir before it exists.
-        if (errno != ENOENT) {
-            PLOG(ERROR) << "Failed to open profile_dir: " << profile_dir;
-        }
-    }
-    return profile_dir_fd;
-}
-
-static fd_t open_primary_profile_file_from_dir(const std::string& profile_dir, mode_t open_mode) {
-    fd_t profile_dir_fd  = open_profile_dir(profile_dir);
-    if (profile_dir_fd < 0) {
-        return -1;
-    }
-
-    fd_t profile_fd = -1;
-    std::string profile_file = create_primary_profile(profile_dir);
-
-    profile_fd = TEMP_FAILURE_RETRY(open(profile_file.c_str(), open_mode | O_NOFOLLOW));
-    if (profile_fd == -1) {
-        // It's not an error if the profile file does not exist.
-        if (errno != ENOENT) {
-            PLOG(ERROR) << "Failed to lstat profile_dir: " << profile_dir;
-        }
-    }
-    // TODO(calin): use AutoCloseFD instead of closing the fd manually.
-    if (close(profile_dir_fd) != 0) {
-        PLOG(WARNING) << "Could not close profile dir " << profile_dir;
-    }
-    return profile_fd;
-}
-
-static fd_t open_primary_profile_file(userid_t user, const char* pkgname) {
-    std::string profile_dir = create_data_user_profile_package_path(user, pkgname);
-    return open_primary_profile_file_from_dir(profile_dir, O_RDONLY);
-}
-
-static fd_t open_reference_profile(uid_t uid, const char* pkgname, bool read_write) {
-    std::string reference_profile_dir = create_data_ref_profile_package_path(pkgname);
-    int flags = read_write ? O_RDWR | O_CREAT : O_RDONLY;
-    fd_t fd = open_primary_profile_file_from_dir(reference_profile_dir, flags);
-    if (fd < 0) {
-        return -1;
-    }
-    if (read_write) {
-        // Fix the owner.
-        if (fchown(fd, uid, uid) < 0) {
-            close(fd);
-            return -1;
-        }
-    }
-    return fd;
-}
-
-static void open_profile_files(uid_t uid, const char* pkgname,
-            /*out*/ std::vector<fd_t>* profiles_fd, /*out*/ fd_t* reference_profile_fd) {
-    // Open the reference profile in read-write mode as profman might need to save the merge.
-    *reference_profile_fd = open_reference_profile(uid, pkgname, /*read_write*/ true);
-    if (*reference_profile_fd < 0) {
-        // We can't access the reference profile file.
-        return;
-    }
-
-    std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
-    for (auto user : users) {
-        fd_t profile_fd = open_primary_profile_file(user, pkgname);
-        // Add to the lists only if both fds are valid.
-        if (profile_fd >= 0) {
-            profiles_fd->push_back(profile_fd);
-        }
-    }
-}
-
-static void drop_capabilities(uid_t uid) {
-    if (setgid(uid) != 0) {
-        ALOGE("setgid(%d) failed in installd during dexopt\n", uid);
-        exit(64);
-    }
-    if (setuid(uid) != 0) {
-        ALOGE("setuid(%d) failed in installd during dexopt\n", uid);
-        exit(65);
-    }
-    // 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) {
-        ALOGE("capset failed: %s\n", strerror(errno));
-        exit(66);
-    }
-}
-
-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;
-
-static void run_profman_merge(const std::vector<fd_t>& profiles_fd, fd_t reference_profile_fd) {
-    static const size_t MAX_INT_LEN = 32;
-    static const char* PROFMAN_BIN = "/system/bin/profman";
-
-    std::vector<std::string> profile_args(profiles_fd.size());
-    char profile_buf[strlen("--profile-file-fd=") + MAX_INT_LEN];
-    for (size_t k = 0; k < profiles_fd.size(); k++) {
-        sprintf(profile_buf, "--profile-file-fd=%d", profiles_fd[k]);
-        profile_args[k].assign(profile_buf);
-    }
-    char reference_profile_arg[strlen("--reference-profile-file-fd=") + MAX_INT_LEN];
-    sprintf(reference_profile_arg, "--reference-profile-file-fd=%d", reference_profile_fd);
-
-    // program name, reference profile fd, the final NULL and the profile fds
-    const char* argv[3 + profiles_fd.size()];
-    int i = 0;
-    argv[i++] = PROFMAN_BIN;
-    argv[i++] = reference_profile_arg;
-    for (size_t k = 0; k < profile_args.size(); k++) {
-        argv[i++] = profile_args[k].c_str();
-    }
-    // Do not add after dex2oat_flags, they should override others for debugging.
-    argv[i] = NULL;
-
-    execv(PROFMAN_BIN, (char * const *)argv);
-    ALOGE("execv(%s) failed: %s\n", PROFMAN_BIN, strerror(errno));
-    exit(68);   /* only get here on exec failure */
-}
-
-// Decides if profile guided compilation is needed or not based on existing profiles.
-// Returns true if there is enough information in the current profiles that worth
-// a re-compilation of the package.
-// If the return value is true all the current profiles would have been merged into
-// the reference profiles accessible with open_reference_profile().
-static bool analyse_profiles(uid_t uid, const char* pkgname) {
-    std::vector<fd_t> profiles_fd;
-    fd_t reference_profile_fd = -1;
-    open_profile_files(uid, pkgname, &profiles_fd, &reference_profile_fd);
-    if (profiles_fd.empty() || (reference_profile_fd == -1)) {
-        // Skip profile guided compilation because no profiles were found.
-        // Or if the reference profile info couldn't be opened.
-        close_all_fds(profiles_fd, "profiles_fd");
-        if ((reference_profile_fd != - 1) && (close(reference_profile_fd) != 0)) {
-            PLOG(WARNING) << "Failed to close fd for reference profile";
-        }
-        return false;
-    }
-
-    ALOGV("PROFMAN (MERGE): --- BEGIN '%s' ---\n", pkgname);
-
-    pid_t pid = fork();
-    if (pid == 0) {
-        /* child -- drop privileges before continuing */
-        drop_capabilities(uid);
-        run_profman_merge(profiles_fd, reference_profile_fd);
-        exit(68);   /* only get here on exec failure */
-    }
-    /* parent */
-    int return_code = wait_child(pid);
-    bool need_to_compile = false;
-    bool should_clear_current_profiles = false;
-    bool should_clear_reference_profile = false;
-    if (!WIFEXITED(return_code)) {
-        LOG(WARNING) << "profman failed for package " << pkgname << ": " << return_code;
-    } else {
-        return_code = WEXITSTATUS(return_code);
-        switch (return_code) {
-            case PROFMAN_BIN_RETURN_CODE_COMPILE:
-                need_to_compile = true;
-                should_clear_current_profiles = true;
-                should_clear_reference_profile = false;
-                break;
-            case PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION:
-                need_to_compile = false;
-                should_clear_current_profiles = false;
-                should_clear_reference_profile = false;
-                break;
-            case PROFMAN_BIN_RETURN_CODE_BAD_PROFILES:
-                LOG(WARNING) << "Bad profiles for package " << pkgname;
-                need_to_compile = false;
-                should_clear_current_profiles = true;
-                should_clear_reference_profile = true;
-                break;
-            case PROFMAN_BIN_RETURN_CODE_ERROR_IO:  // fall-through
-            case PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING:
-                // Temporary IO problem (e.g. locking). Ignore but log a warning.
-                LOG(WARNING) << "IO error while reading profiles for package " << pkgname;
-                need_to_compile = false;
-                should_clear_current_profiles = false;
-                should_clear_reference_profile = false;
-                break;
-           default:
-                // Unknown return code or error. Unlink profiles.
-                LOG(WARNING) << "Unknown error code while processing profiles for package " << pkgname
-                        << ": " << return_code;
-                need_to_compile = false;
-                should_clear_current_profiles = true;
-                should_clear_reference_profile = true;
-                break;
-        }
-    }
-    close_all_fds(profiles_fd, "profiles_fd");
-    if (close(reference_profile_fd) != 0) {
-        PLOG(WARNING) << "Failed to close fd for reference profile";
-    }
-    if (should_clear_current_profiles) {
-        clear_current_profiles(pkgname);
-    }
-    if (should_clear_reference_profile) {
-        clear_reference_profile(pkgname);
-    }
-    return need_to_compile;
-}
-
-static void run_profman_dump(const std::vector<fd_t>& profile_fds,
-                             fd_t reference_profile_fd,
-                             const std::vector<std::string>& dex_locations,
-                             const std::vector<fd_t>& apk_fds,
-                             fd_t 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));
-    if (reference_profile_fd != -1) {
-        profman_args.push_back(StringPrintf("--reference-profile-file-fd=%d",
-                                            reference_profile_fd));
-    }
-    for (fd_t profile_fd : profile_fds) {
-        profman_args.push_back(StringPrintf("--profile-file-fd=%d", profile_fd));
-    }
-    for (const std::string& dex_location : dex_locations) {
-        profman_args.push_back(StringPrintf("--dex-location=%s", dex_location.c_str()));
-    }
-    for (fd_t apk_fd : apk_fds) {
-        profman_args.push_back(StringPrintf("--apk-fd=%d", apk_fd));
-    }
-    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);
-    ALOGE("execv(%s) failed: %s\n", PROFMAN_BIN, strerror(errno));
-    exit(68);   /* only get here on exec failure */
-}
-
-static const char* get_location_from_path(const char* path) {
-    static constexpr char kLocationSeparator = '/';
-    const char *location = strrchr(path, kLocationSeparator);
-    if (location == NULL) {
-        return path;
-    } else {
-        // Skip the separator character.
-        return location + 1;
-    }
-}
-
-// Dumps the contents of a profile file, using pkgname's dex files for pretty
-// printing the result.
-bool dump_profile(uid_t uid, const char* pkgname, const char* code_path_string) {
-    std::vector<fd_t> profile_fds;
-    fd_t reference_profile_fd = -1;
-    std::string out_file_name = StringPrintf("/data/misc/profman/%s.txt", pkgname);
-
-    ALOGV("PROFMAN (DUMP): --- BEGIN '%s' ---\n", pkgname);
-
-    open_profile_files(uid, pkgname, &profile_fds, &reference_profile_fd);
-
-    const bool has_reference_profile = (reference_profile_fd != -1);
-    const bool has_profiles = !profile_fds.empty();
-
-    if (!has_reference_profile && !has_profiles) {
-        ALOGE("profman dump: no profiles to dump for '%s'", pkgname);
-        return false;
-    }
-
-    fd_t output_fd = open(out_file_name.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW);
-    if (fchmod(output_fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
-        ALOGE("installd cannot chmod '%s' dump_profile\n", out_file_name.c_str());
-        return false;
-    }
-    std::vector<std::string> code_full_paths = base::Split(code_path_string, ";");
-    std::vector<std::string> dex_locations;
-    std::vector<fd_t> apk_fds;
-    for (const std::string& code_full_path : code_full_paths) {
-        const char* full_path = code_full_path.c_str();
-        fd_t apk_fd = open(full_path, O_RDONLY | O_NOFOLLOW);
-        if (apk_fd == -1) {
-            ALOGE("installd cannot open '%s'\n", full_path);
-            return false;
-        }
-        dex_locations.push_back(get_location_from_path(full_path));
-        apk_fds.push_back(apk_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);
-        exit(68);   /* only get here on exec failure */
-    }
-    /* parent */
-    close_all_fds(apk_fds, "apk_fds");
-    close_all_fds(profile_fds, "profile_fds");
-    if (close(reference_profile_fd) != 0) {
-        PLOG(WARNING) << "Failed to close fd for reference profile";
-    }
-    int return_code = wait_child(pid);
-    if (!WIFEXITED(return_code)) {
-        LOG(WARNING) << "profman failed for package " << pkgname << ": "
-                << return_code;
-        return false;
-    }
-    return true;
-}
-
-// Translate the given oat path to an art (app image) path. An empty string
-// denotes an error.
-static std::string create_image_filename(const std::string& oat_path) {
-  // A standard dalvik-cache entry. Replace ".dex" with ".art."
-  if (EndsWith(oat_path, ".dex")) {
-    std::string art_path = oat_path;
-    art_path.replace(art_path.length() - strlen("dex"), strlen("dex"), "art");
-    CHECK(EndsWith(art_path, ".art"));
-    return art_path;
-  }
-
-  // An odex entry. Not that this may not be an extension, e.g., in the OTA
-  // case (where the base name will have an extension for the B artifact).
-  size_t odex_pos = oat_path.rfind(".odex");
-  if (odex_pos != std::string::npos) {
-    std::string art_path = oat_path;
-    art_path.replace(odex_pos, strlen(".odex"), ".art");
-    CHECK_NE(art_path.find(".art"), std::string::npos);
-    return art_path;
-  }
-
-  // Don't know how to handle this.
-  return "";
-}
-
-static bool add_extension_to_file_name(char* file_name, const char* extension) {
-    if (strlen(file_name) + strlen(extension) + 1 > PKG_PATH_MAX) {
-        return false;
-    }
-    strcat(file_name, extension);
-    return true;
-}
-
-static int open_output_file(const char* file_name, bool recreate, int permissions) {
-    int flags = O_RDWR | O_CREAT;
-    if (recreate) {
-        if (unlink(file_name) < 0) {
-            if (errno != ENOENT) {
-                PLOG(ERROR) << "open_output_file: Couldn't unlink " << file_name;
-            }
-        }
-        flags |= O_EXCL;
-    }
-    return open(file_name, flags, permissions);
-}
-
-static bool set_permissions_and_ownership(int fd, bool is_public, int uid, const char* path) {
-    if (fchmod(fd,
-               S_IRUSR|S_IWUSR|S_IRGRP |
-               (is_public ? S_IROTH : 0)) < 0) {
-        ALOGE("installd cannot chmod '%s' during dexopt\n", path);
-        return false;
-    } else if (fchown(fd, AID_SYSTEM, uid) < 0) {
-        ALOGE("installd cannot chown '%s' during dexopt\n", path);
-        return false;
-    }
-    return true;
-}
-
-static bool create_oat_out_path(const char* apk_path, const char* instruction_set,
-            const char* oat_dir, /*out*/ char* out_path) {
-    // Early best-effort check whether we can fit the the path into our buffers.
-    // Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run
-    // without a swap file, if necessary. Reference profiles file also add an extra ".prof"
-    // extension to the cache path (5 bytes).
-    if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
-        ALOGE("apk_path too long '%s'\n", apk_path);
-        return false;
-    }
-
-    if (oat_dir != NULL && oat_dir[0] != '!') {
-        if (validate_apk_path(oat_dir)) {
-            ALOGE("invalid oat_dir '%s'\n", oat_dir);
-            return false;
-        }
-        if (!calculate_oat_file_path(out_path, oat_dir, apk_path, instruction_set)) {
-            return false;
-        }
-    } else {
-        if (!create_cache_path(out_path, apk_path, instruction_set)) {
-            return false;
-        }
-    }
-    return true;
-}
-
-// TODO: Consider returning error codes.
-bool merge_profiles(uid_t uid, const char *pkgname) {
-    return analyse_profiles(uid, pkgname);
-}
-
-static const char* parse_null(const char* arg) {
-    if (strcmp(arg, "!") == 0) {
-        return nullptr;
-    } else {
-        return arg;
-    }
-}
-
-int dexopt(const char* const params[DEXOPT_PARAM_COUNT]) {
-    return dexopt(params[0],                    // apk_path
-                  atoi(params[1]),              // uid
-                  params[2],                    // pkgname
-                  params[3],                    // instruction_set
-                  atoi(params[4]),              // dexopt_needed
-                  params[5],                    // oat_dir
-                  atoi(params[6]),              // dexopt_flags
-                  params[7],                    // compiler_filter
-                  parse_null(params[8]),        // volume_uuid
-                  parse_null(params[9]));       // shared_libraries
-    static_assert(DEXOPT_PARAM_COUNT == 10U, "Unexpected dexopt param count");
-}
-
-// Helper for fd management. This is similar to a unique_fd in that it closes the file descriptor
-// on destruction. It will also run the given cleanup (unless told not to) after closing.
-//
-// Usage example:
-//
-//   Dex2oatFileWrapper<std::function<void ()>> file(open(...),
-//                                                   [name]() {
-//                                                       unlink(name.c_str());
-//                                                   });
-//   // Note: care needs to be taken about name, as it needs to have a lifetime longer than the
-//            wrapper if captured as a reference.
-//
-//   if (file.get() == -1) {
-//       // Error opening...
-//   }
-//
-//   ...
-//   if (error) {
-//       // At this point, when the Dex2oatFileWrapper is destructed, the cleanup function will run
-//       // and delete the file (after the fd is closed).
-//       return -1;
-//   }
-//
-//   (Success case)
-//   file.SetCleanup(false);
-//   // At this point, when the Dex2oatFileWrapper is destructed, the cleanup function will not run
-//   // (leaving the file around; after the fd is closed).
-//
-template <typename Cleanup>
-class Dex2oatFileWrapper {
- public:
-    Dex2oatFileWrapper() : value_(-1), cleanup_(), do_cleanup_(true) {
-    }
-
-    Dex2oatFileWrapper(int value, Cleanup cleanup)
-            : value_(value), cleanup_(cleanup), do_cleanup_(true) {}
-
-    ~Dex2oatFileWrapper() {
-        reset(-1);
-    }
-
-    int get() {
-        return value_;
-    }
-
-    void SetCleanup(bool cleanup) {
-        do_cleanup_ = cleanup;
-    }
-
-    void reset(int new_value) {
-        if (value_ >= 0) {
-            close(value_);
-        }
-        if (do_cleanup_ && cleanup_ != nullptr) {
-            cleanup_();
-        }
-
-        value_ = new_value;
-    }
-
-    void reset(int new_value, Cleanup new_cleanup) {
-        if (value_ >= 0) {
-            close(value_);
-        }
-        if (do_cleanup_ && cleanup_ != nullptr) {
-            cleanup_();
-        }
-
-        value_ = new_value;
-        cleanup_ = new_cleanup;
-    }
-
- private:
-    int value_;
-    Cleanup cleanup_;
-    bool do_cleanup_;
-};
-
-int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* instruction_set,
-           int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
-           const char* volume_uuid ATTRIBUTE_UNUSED, const char* shared_libraries)
-{
-    bool is_public = ((dexopt_flags & DEXOPT_PUBLIC) != 0);
-    bool vm_safe_mode = (dexopt_flags & DEXOPT_SAFEMODE) != 0;
-    bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0;
-    bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0;
-    bool profile_guided = (dexopt_flags & DEXOPT_PROFILE_GUIDED) != 0;
-
-    // Don't use profile for vm_safe_mode. b/30688277
-    profile_guided = profile_guided && !vm_safe_mode;
-
-    CHECK(pkgname != nullptr);
-    CHECK(pkgname[0] != 0);
-
-    // Public apps should not be compiled with profile information ever. Same goes for the special
-    // package '*' used for the system server.
-    Dex2oatFileWrapper<std::function<void ()>> reference_profile_fd;
-    if (!is_public && pkgname[0] != '*') {
-        // Open reference profile in read only mode as dex2oat does not get write permissions.
-        const std::string pkgname_str(pkgname);
-        reference_profile_fd.reset(open_reference_profile(uid, pkgname, /*read_write*/ false),
-                                   [pkgname_str]() {
-                                       clear_reference_profile(pkgname_str.c_str());
-                                   });
-        // Note: it's OK to not find a profile here.
-    }
-
-    if ((dexopt_flags & ~DEXOPT_MASK) != 0) {
-        LOG_FATAL("dexopt flags contains unknown fields\n");
-    }
-
-    char out_path[PKG_PATH_MAX];
-    if (!create_oat_out_path(apk_path, instruction_set, oat_dir, out_path)) {
-        return false;
-    }
-
-    const char *input_file;
-    char in_odex_path[PKG_PATH_MAX];
-    switch (dexopt_needed) {
-        case DEXOPT_DEX2OAT_NEEDED:
-            input_file = apk_path;
-            break;
-
-        case DEXOPT_PATCHOAT_NEEDED:
-            if (!calculate_odex_file_path(in_odex_path, apk_path, instruction_set)) {
-                return -1;
-            }
-            input_file = in_odex_path;
-            break;
-
-        case DEXOPT_SELF_PATCHOAT_NEEDED:
-            input_file = out_path;
-            break;
-
-        default:
-            ALOGE("Invalid dexopt needed: %d\n", dexopt_needed);
-            return 72;
-    }
-
-    struct stat input_stat;
-    memset(&input_stat, 0, sizeof(input_stat));
-    stat(input_file, &input_stat);
-
-    base::unique_fd input_fd(open(input_file, O_RDONLY, 0));
-    if (input_fd.get() < 0) {
-        ALOGE("installd cannot open '%s' for input during dexopt\n", input_file);
-        return -1;
-    }
-
-    const std::string out_path_str(out_path);
-    Dex2oatFileWrapper<std::function<void ()>> out_fd(
-            open_output_file(out_path, /*recreate*/true, /*permissions*/0644),
-            [out_path_str]() { unlink(out_path_str.c_str()); });
-    if (out_fd.get() < 0) {
-        ALOGE("installd cannot open '%s' for output during dexopt\n", out_path);
-        return -1;
-    }
-    if (!set_permissions_and_ownership(out_fd.get(), is_public, uid, out_path)) {
-        return -1;
-    }
-
-    // Create a swap file if necessary.
-    base::unique_fd swap_fd;
-    if (ShouldUseSwapFileForDexopt()) {
-        // Make sure there really is enough space.
-        char swap_file_name[PKG_PATH_MAX];
-        strcpy(swap_file_name, out_path);
-        if (add_extension_to_file_name(swap_file_name, ".swap")) {
-            swap_fd.reset(open_output_file(swap_file_name, /*recreate*/true, /*permissions*/0600));
-        }
-        if (swap_fd.get() < 0) {
-            // Could not create swap file. Optimistically go on and hope that we can compile
-            // without it.
-            ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name);
-        } else {
-            // Immediately unlink. We don't really want to hit flash.
-            if (unlink(swap_file_name) < 0) {
-                PLOG(ERROR) << "Couldn't unlink swap file " << swap_file_name;
-            }
-        }
-    }
-
-    // Avoid generating an app image for extract only since it will not contain any classes.
-    Dex2oatFileWrapper<std::function<void ()>> image_fd;
-    const std::string image_path = create_image_filename(out_path);
-    if (!image_path.empty()) {
-        char app_image_format[kPropertyValueMax];
-        bool have_app_image_format =
-                get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
-        // Use app images only if it is enabled (by a set image format) and we are compiling
-        // profile-guided (so the app image doesn't conservatively contain all classes).
-        if (profile_guided && have_app_image_format) {
-            // Recreate is true since we do not want to modify a mapped image. If the app is
-            // already running and we modify the image file, it can cause crashes (b/27493510).
-            image_fd.reset(open_output_file(image_path.c_str(),
-                                            true /*recreate*/,
-                                            0600 /*permissions*/),
-                           [image_path]() { unlink(image_path.c_str()); }
-                           );
-            if (image_fd.get() < 0) {
-                // Could not create application image file. Go on since we can compile without
-                // it.
-                LOG(ERROR) << "installd could not create '"
-                        << image_path
-                        << "' for image file during dexopt";
-            } else if (!set_permissions_and_ownership(image_fd.get(),
-                                                      is_public,
-                                                      uid,
-                                                      image_path.c_str())) {
-                image_fd.reset(-1);
-            }
-        }
-        // If we have a valid image file path but no image fd, explicitly erase the image file.
-        if (image_fd.get() < 0) {
-            if (unlink(image_path.c_str()) < 0) {
-                if (errno != ENOENT) {
-                    PLOG(ERROR) << "Couldn't unlink image file " << image_path;
-                }
-            }
-        }
-    }
-
-    ALOGV("DexInv: --- BEGIN '%s' ---\n", input_file);
-
-    pid_t pid = fork();
-    if (pid == 0) {
-        /* child -- drop privileges before continuing */
-        drop_capabilities(uid);
-
-        SetDex2OatAndPatchOatScheduling(boot_complete);
-        if (flock(out_fd.get(), LOCK_EX | LOCK_NB) != 0) {
-            ALOGE("flock(%s) failed: %s\n", out_path, strerror(errno));
-            _exit(67);
-        }
-
-        if (dexopt_needed == DEXOPT_PATCHOAT_NEEDED
-            || dexopt_needed == DEXOPT_SELF_PATCHOAT_NEEDED) {
-            run_patchoat(input_fd.get(),
-                         out_fd.get(),
-                         input_file,
-                         out_path,
-                         pkgname,
-                         instruction_set);
-        } else if (dexopt_needed == DEXOPT_DEX2OAT_NEEDED) {
-            // Pass dex2oat the relative path to the input file.
-            const char *input_file_name = get_location_from_path(input_file);
-            run_dex2oat(input_fd.get(),
-                        out_fd.get(),
-                        image_fd.get(),
-                        input_file_name,
-                        out_path,
-                        swap_fd.get(),
-                        instruction_set,
-                        compiler_filter,
-                        vm_safe_mode,
-                        debuggable,
-                        boot_complete,
-                        reference_profile_fd.get(),
-                        shared_libraries);
-        } else {
-            ALOGE("Invalid dexopt needed: %d\n", dexopt_needed);
-            _exit(73);
-        }
-        _exit(68);   /* only get here on exec failure */
-    } else {
-        int res = wait_child(pid);
-        if (res == 0) {
-            ALOGV("DexInv: --- END '%s' (success) ---\n", input_file);
-        } else {
-            ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", input_file, res);
-            return -1;
-        }
-    }
-
-    struct utimbuf ut;
-    ut.actime = input_stat.st_atime;
-    ut.modtime = input_stat.st_mtime;
-    utime(out_path, &ut);
-
-    // We've been successful, don't delete output.
-    out_fd.SetCleanup(false);
-    image_fd.SetCleanup(false);
-    reference_profile_fd.SetCleanup(false);
-
-    return 0;
-}
-
-int mark_boot_complete(const char* instruction_set)
-{
-  char boot_marker_path[PKG_PATH_MAX];
-  sprintf(boot_marker_path,
-          "%s/%s/%s/.booting",
-          android_data_dir.path,
-          DALVIK_CACHE,
-          instruction_set);
-
-  ALOGV("mark_boot_complete : %s", boot_marker_path);
-  if (unlink(boot_marker_path) != 0) {
-      ALOGE("Unable to unlink boot marker at %s, error=%s", boot_marker_path,
-            strerror(errno));
-      return -1;
-  }
-
-  return 0;
-}
-
-void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid,
-        struct stat* statbuf)
-{
-    while (path[basepos] != 0) {
-        if (path[basepos] == '/') {
-            path[basepos] = 0;
-            if (lstat(path, statbuf) < 0) {
-                ALOGV("Making directory: %s\n", path);
-                if (mkdir(path, mode) == 0) {
-                    chown(path, uid, gid);
-                } else {
-                    ALOGW("Unable to make directory %s: %s\n", path, strerror(errno));
-                }
-            }
-            path[basepos] = '/';
-            basepos++;
-        }
-        basepos++;
-    }
-}
-
-int linklib(const char* uuid, const char* pkgname, const char* asecLibDir, int userId)
-{
-    struct stat s, libStat;
-    int rc = 0;
-
-    std::string _pkgdir(create_data_user_ce_package_path(uuid, userId, pkgname));
-    std::string _libsymlink(_pkgdir + PKG_LIB_POSTFIX);
-
-    const char* pkgdir = _pkgdir.c_str();
-    const char* libsymlink = _libsymlink.c_str();
-
-    if (stat(pkgdir, &s) < 0) return -1;
-
-    if (chown(pkgdir, AID_INSTALL, AID_INSTALL) < 0) {
-        ALOGE("failed to chown '%s': %s\n", pkgdir, strerror(errno));
-        return -1;
-    }
-
-    if (chmod(pkgdir, 0700) < 0) {
-        ALOGE("linklib() 1: failed to chmod '%s': %s\n", pkgdir, strerror(errno));
-        rc = -1;
-        goto out;
-    }
-
-    if (lstat(libsymlink, &libStat) < 0) {
-        if (errno != ENOENT) {
-            ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
-            rc = -1;
-            goto out;
-        }
-    } else {
-        if (S_ISDIR(libStat.st_mode)) {
-            if (delete_dir_contents(libsymlink, 1, NULL) < 0) {
-                rc = -1;
-                goto out;
-            }
-        } else if (S_ISLNK(libStat.st_mode)) {
-            if (unlink(libsymlink) < 0) {
-                ALOGE("couldn't unlink lib dir: %s\n", strerror(errno));
-                rc = -1;
-                goto out;
-            }
-        }
-    }
-
-    if (symlink(asecLibDir, libsymlink) < 0) {
-        ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libsymlink, asecLibDir,
-                strerror(errno));
-        rc = -errno;
-        goto out;
-    }
-
-out:
-    if (chmod(pkgdir, s.st_mode) < 0) {
-        ALOGE("linklib() 2: failed to chmod '%s': %s\n", pkgdir, strerror(errno));
-        rc = -errno;
-    }
-
-    if (chown(pkgdir, s.st_uid, s.st_gid) < 0) {
-        ALOGE("failed to chown '%s' : %s\n", pkgdir, strerror(errno));
-        return -errno;
-    }
-
-    return rc;
-}
-
-static void run_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd)
-{
-    static const char *IDMAP_BIN = "/system/bin/idmap";
-    static const size_t MAX_INT_LEN = 32;
-    char idmap_str[MAX_INT_LEN];
-
-    snprintf(idmap_str, sizeof(idmap_str), "%d", idmap_fd);
-
-    execl(IDMAP_BIN, IDMAP_BIN, "--fd", target_apk, overlay_apk, idmap_str, (char*)NULL);
-    ALOGE("execl(%s) failed: %s\n", IDMAP_BIN, strerror(errno));
-}
-
-// Transform string /a/b/c.apk to (prefix)/a@b@c.apk@(suffix)
-// eg /a/b/c.apk to /data/resource-cache/a@b@c.apk@idmap
-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) {
-        return -1;
-    }
-    const size_t len_overlay_path = strlen(overlay_path);
-    // will access overlay_path + 1 further below; requires absolute path
-    if (len_overlay_path < 2 || *overlay_path != '/') {
-        return -1;
-    }
-    const size_t len_idmap_root = strlen(prefix);
-    const size_t len_suffix = strlen(suffix);
-    if (SIZE_MAX - len_idmap_root < len_overlay_path ||
-            SIZE_MAX - (len_idmap_root + len_overlay_path) < len_suffix) {
-        // additions below would cause overflow
-        return -1;
-    }
-    if (N < len_idmap_root + len_overlay_path + len_suffix) {
-        return -1;
-    }
-    memset(idmap_path, 0, N);
-    snprintf(idmap_path, N, "%s%s%s", prefix, overlay_path + 1, suffix);
-    char *ch = idmap_path + len_idmap_root;
-    while (*ch != '\0') {
-        if (*ch == '/') {
-            *ch = '@';
-        }
-        ++ch;
-    }
-    return 0;
-}
-
-int idmap(const char *target_apk, const char *overlay_apk, uid_t uid)
-{
-    ALOGV("idmap target_apk=%s overlay_apk=%s uid=%d\n", target_apk, overlay_apk, uid);
-
-    int idmap_fd = -1;
-    char idmap_path[PATH_MAX];
-
-    if (flatten_path(IDMAP_PREFIX, IDMAP_SUFFIX, overlay_apk,
-                idmap_path, sizeof(idmap_path)) == -1) {
-        ALOGE("idmap cannot generate idmap path for overlay %s\n", overlay_apk);
-        goto fail;
-    }
-
-    unlink(idmap_path);
-    idmap_fd = open(idmap_path, O_RDWR | O_CREAT | O_EXCL, 0644);
-    if (idmap_fd < 0) {
-        ALOGE("idmap cannot open '%s' for output: %s\n", idmap_path, strerror(errno));
-        goto fail;
-    }
-    if (fchown(idmap_fd, AID_SYSTEM, uid) < 0) {
-        ALOGE("idmap cannot chown '%s'\n", idmap_path);
-        goto fail;
-    }
-    if (fchmod(idmap_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) {
-        ALOGE("idmap cannot chmod '%s'\n", idmap_path);
-        goto fail;
-    }
-
-    pid_t pid;
-    pid = fork();
-    if (pid == 0) {
-        /* child -- drop privileges before continuing */
-        if (setgid(uid) != 0) {
-            ALOGE("setgid(%d) failed during idmap\n", uid);
-            exit(1);
-        }
-        if (setuid(uid) != 0) {
-            ALOGE("setuid(%d) failed during idmap\n", uid);
-            exit(1);
-        }
-        if (flock(idmap_fd, LOCK_EX | LOCK_NB) != 0) {
-            ALOGE("flock(%s) failed during idmap: %s\n", idmap_path, strerror(errno));
-            exit(1);
-        }
-
-        run_idmap(target_apk, overlay_apk, idmap_fd);
-        exit(1); /* only if exec call to idmap failed */
-    } else {
-        int status = wait_child(pid);
-        if (status != 0) {
-            ALOGE("idmap failed, status=0x%04x\n", status);
-            goto fail;
-        }
-    }
-
-    close(idmap_fd);
-    return 0;
-fail:
-    if (idmap_fd >= 0) {
-        close(idmap_fd);
-        unlink(idmap_path);
-    }
-    return -1;
-}
-
-int restorecon_app_data(const char* uuid, const char* pkgName, userid_t userid, int flags,
-        appid_t appid, const char* seinfo) {
-    int res = 0;
-
-    // SELINUX_ANDROID_RESTORECON_DATADATA flag is set by libselinux. Not needed here.
-    unsigned int seflags = SELINUX_ANDROID_RESTORECON_RECURSE;
-
-    if (!pkgName || !seinfo) {
-        ALOGE("Package name or seinfo tag is null when trying to restorecon.");
-        return -1;
-    }
-
-    uid_t uid = multiuser_get_uid(userid, appid);
-    if (flags & FLAG_STORAGE_CE) {
-        auto path = create_data_user_ce_package_path(uuid, userid, pkgName);
-        if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, seflags) < 0) {
-            PLOG(ERROR) << "restorecon failed for " << path;
-            res = -1;
-        }
-    }
-    if (flags & FLAG_STORAGE_DE) {
-        auto path = create_data_user_de_package_path(uuid, userid, pkgName);
-        if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, seflags) < 0) {
-            PLOG(ERROR) << "restorecon failed for " << path;
-            // TODO: include result once 25796509 is fixed
-        }
-    }
-
-    return res;
-}
-
-int create_oat_dir(const char* oat_dir, const char* instruction_set)
-{
-    char oat_instr_dir[PKG_PATH_MAX];
-
-    if (validate_apk_path(oat_dir)) {
-        ALOGE("invalid apk path '%s' (bad prefix)\n", oat_dir);
-        return -1;
-    }
-    if (fs_prepare_dir(oat_dir, S_IRWXU | S_IRWXG | S_IXOTH, AID_SYSTEM, AID_INSTALL)) {
-        return -1;
-    }
-    if (selinux_android_restorecon(oat_dir, 0)) {
-        ALOGE("cannot restorecon dir '%s': %s\n", oat_dir, strerror(errno));
-        return -1;
-    }
-    snprintf(oat_instr_dir, PKG_PATH_MAX, "%s/%s", oat_dir, instruction_set);
-    if (fs_prepare_dir(oat_instr_dir, S_IRWXU | S_IRWXG | S_IXOTH, AID_SYSTEM, AID_INSTALL)) {
-        return -1;
-    }
-    return 0;
-}
-
-int rm_package_dir(const char* apk_path)
-{
-    if (validate_apk_path(apk_path)) {
-        ALOGE("invalid apk path '%s' (bad prefix)\n", apk_path);
-        return -1;
-    }
-    return delete_dir_contents(apk_path, 1 /* also_delete_dir */ , NULL /* exclusion_predicate */);
-}
-
-int link_file(const char* relative_path, const char* from_base, const char* to_base) {
-    char from_path[PKG_PATH_MAX];
-    char to_path[PKG_PATH_MAX];
-    snprintf(from_path, PKG_PATH_MAX, "%s/%s", from_base, relative_path);
-    snprintf(to_path, PKG_PATH_MAX, "%s/%s", to_base, relative_path);
-
-    if (validate_apk_path_subdirs(from_path)) {
-        ALOGE("invalid app data sub-path '%s' (bad prefix)\n", from_path);
-        return -1;
-    }
-
-    if (validate_apk_path_subdirs(to_path)) {
-        ALOGE("invalid app data sub-path '%s' (bad prefix)\n", to_path);
-        return -1;
-    }
-
-    const int ret = link(from_path, to_path);
-    if (ret < 0) {
-        ALOGE("link(%s, %s) failed : %s", from_path, to_path, strerror(errno));
-        return -1;
-    }
-
-    return 0;
-}
-
-// Helper for move_ab, so that we can have common failure-case cleanup.
-static bool unlink_and_rename(const char* from, const char* to) {
-    // Check whether "from" exists, and if so whether it's regular. If it is, unlink. Otherwise,
-    // return a failure.
-    struct stat s;
-    if (stat(to, &s) == 0) {
-        if (!S_ISREG(s.st_mode)) {
-            LOG(ERROR) << from << " is not a regular file to replace for A/B.";
-            return false;
-        }
-        if (unlink(to) != 0) {
-            LOG(ERROR) << "Could not unlink " << to << " to move A/B.";
-            return false;
-        }
-    } else {
-        // This may be a permission problem. We could investigate the error code, but we'll just
-        // let the rename failure do the work for us.
-    }
-
-    // Try to rename "to" to "from."
-    if (rename(from, to) != 0) {
-        PLOG(ERROR) << "Could not rename " << from << " to " << to;
-        return false;
-    }
-
-    return true;
-}
-
-// Move/rename a B artifact (from) to an A artifact (to).
-static bool move_ab_path(const std::string& b_path, const std::string& a_path) {
-    // Check whether B exists.
-    {
-        struct stat s;
-        if (stat(b_path.c_str(), &s) != 0) {
-            // Silently ignore for now. The service calling this isn't smart enough to understand
-            // lack of artifacts at the moment.
-            return false;
-        }
-        if (!S_ISREG(s.st_mode)) {
-            LOG(ERROR) << "A/B artifact " << b_path << " is not a regular file.";
-            // Try to unlink, but swallow errors.
-            unlink(b_path.c_str());
-            return false;
-        }
-    }
-
-    // Rename B to A.
-    if (!unlink_and_rename(b_path.c_str(), a_path.c_str())) {
-        // Delete the b_path so we don't try again (or fail earlier).
-        if (unlink(b_path.c_str()) != 0) {
-            PLOG(ERROR) << "Could not unlink " << b_path;
-        }
-
-        return false;
-    }
-
-    return true;
-}
-
-int move_ab(const char* apk_path, const char* instruction_set, const char* oat_dir) {
-    if (apk_path == nullptr || instruction_set == nullptr || oat_dir == nullptr) {
-        LOG(ERROR) << "Cannot move_ab with null input";
-        return -1;
-    }
-
-    // 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 -1;
-        }
-        slot_suffix = buf;
-
-        if (!ValidateTargetSlotSuffix(slot_suffix)) {
-            LOG(ERROR) << "Target slot suffix not legal: " << slot_suffix;
-            return -1;
-        }
-    }
-
-    // Validate other inputs.
-    if (validate_apk_path(apk_path) != 0) {
-        LOG(ERROR) << "invalid apk_path " << apk_path;
-        return -1;
-    }
-    if (validate_apk_path(oat_dir) != 0) {
-        LOG(ERROR) << "invalid oat_dir " << oat_dir;
-        return -1;
-    }
-
-    char a_path[PKG_PATH_MAX];
-    if (!calculate_oat_file_path(a_path, oat_dir, apk_path, instruction_set)) {
-        return -1;
-    }
-    const std::string a_image_path = create_image_filename(a_path);
-
-    // B path = A path + slot suffix.
-    const std::string b_path = StringPrintf("%s.%s", a_path, slot_suffix.c_str());
-    const std::string b_image_path = StringPrintf("%s.%s",
-                                                  a_image_path.c_str(),
-                                                  slot_suffix.c_str());
-
-    bool oat_success = move_ab_path(b_path, a_path);
-    bool success;
-
-    if (oat_success) {
-        // Note: we can live without an app image. As such, ignore failure to move the image file.
-        //       If we decide to require the app image, or the app image being moved correctly,
-        //       then change accordingly.
-        constexpr bool kIgnoreAppImageFailure = true;
-
-        bool art_success = true;
-        if (!a_image_path.empty()) {
-            art_success = move_ab_path(b_image_path, a_image_path);
-            if (!art_success) {
-                unlink(a_image_path.c_str());
-            }
-        }
-
-        success = art_success || kIgnoreAppImageFailure;
-    } else {
-        // Cleanup: delete B image, ignore errors.
-        unlink(b_image_path.c_str());
-
-        success = false;
-    }
-
-    return success ? 0 : -1;
-}
-
-bool delete_odex(const char *apk_path, const char *instruction_set, const char *oat_dir) {
-    // Delete the oat/odex file.
-    char out_path[PKG_PATH_MAX];
-    if (!create_oat_out_path(apk_path, instruction_set, oat_dir, out_path)) {
-        return false;
-    }
-
-    // In case of a permission failure report the issue. Otherwise just print a warning.
-    auto unlink_and_check = [](const char* path) -> bool {
-        int result = unlink(path);
-        if (result != 0) {
-            if (errno == EACCES || errno == EPERM) {
-                PLOG(ERROR) << "Could not unlink " << path;
-                return false;
-            }
-            PLOG(WARNING) << "Could not unlink " << path;
-        }
-        return true;
-    };
-
-    // Delete the oat/odex file.
-    bool return_value_oat = unlink_and_check(out_path);
-
-    // Derive and delete the app image.
-    bool return_value_art = unlink_and_check(create_image_filename(out_path).c_str());
-
-    // Report success.
-    return return_value_oat && return_value_art;
-}
-
-}  // namespace installd
-}  // namespace android
diff --git a/cmds/installd/commands.h b/cmds/installd/commands.h
deleted file mode 100644
index ba27517..0000000
--- a/cmds/installd/commands.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
-**
-** Copyright 2008, 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 COMMANDS_H_
-#define COMMANDS_H_
-
-#include <inttypes.h>
-#include <unistd.h>
-
-#include <cutils/multiuser.h>
-
-#include <installd_constants.h>
-
-namespace android {
-namespace installd {
-
-static constexpr size_t DEXOPT_PARAM_COUNT = 10U;
-
-int create_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags,
-        appid_t appid, const char* seinfo, int target_sdk_version);
-int restorecon_app_data(const char* uuid, const char* pkgName, userid_t userid, int flags,
-        appid_t appid, const char* seinfo);
-int migrate_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags);
-int clear_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags,
-        ino_t ce_data_inode);
-int destroy_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags,
-        ino_t ce_data_inode);
-
-int move_complete_app(const char* from_uuid, const char *to_uuid, const char *package_name,
-        const char *data_app_name, appid_t appid, const char* seinfo, int target_sdk_version);
-
-int get_app_size(const char *uuid, const char *pkgname, int userid, int flags, ino_t ce_data_inode,
-        const char* code_path, int64_t *codesize, int64_t *datasize, int64_t *cachesize,
-        int64_t *asecsize);
-int get_app_data_inode(const char *uuid, const char *pkgname, int userid, int flags, ino_t *inode);
-
-int create_user_data(const char *uuid, userid_t userid, int user_serial, int flags);
-int destroy_user_data(const char *uuid, userid_t userid, int flags);
-
-int rm_dex(const char *path, const char *instruction_set);
-int free_cache(const char *uuid, int64_t free_size);
-
-bool merge_profiles(uid_t uid, const char *pkgname);
-
-bool dump_profile(uid_t uid, const char *pkgname, const char *dex_files);
-
-int dexopt(const char *apk_path,
-           uid_t uid,
-           const char *pkgName,
-           const char *instruction_set,
-           int dexopt_needed,
-           const char* oat_dir,
-           int dexopt_flags,
-           const char* compiler_filter,
-           const char* volume_uuid,
-           const char* shared_libraries);
-static_assert(DEXOPT_PARAM_COUNT == 10U, "Unexpected dexopt param size");
-
-// Helper for the above, converting arguments.
-int dexopt(const char* const params[DEXOPT_PARAM_COUNT]);
-
-int mark_boot_complete(const char *instruction_set);
-int linklib(const char* uuid, const char* pkgname, const char* asecLibDir, int userId);
-int idmap(const char *target_path, const char *overlay_path, uid_t uid);
-int create_oat_dir(const char* oat_dir, const char *instruction_set);
-int rm_package_dir(const char* apk_path);
-int clear_app_profiles(const char* pkgname);
-int destroy_app_profiles(const char* pkgname);
-int link_file(const char *relative_path, const char *from_base, const char *to_base);
-
-// Move a B version over to the A location. Only works for oat_dir != nullptr.
-int move_ab(const char *apk_path, const char *instruction_set, const char* oat_dir);
-
-// Delete odex files generated by dexopt.
-bool delete_odex(const char *apk_path, const char *instruction_set, const char *oat_dir);
-
-}  // namespace installd
-}  // namespace android
-
-#endif  // COMMANDS_H_
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
new file mode 100644
index 0000000..70cf35c
--- /dev/null
+++ b/cmds/installd/dexopt.cpp
@@ -0,0 +1,1905 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "installed"
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/capability.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <cutils/fs.h>
+#include <cutils/properties.h>
+#include <cutils/sched_policy.h>
+#include <log/log.h>               // TODO: Move everything to base/logging.
+#include <private/android_filesystem_config.h>
+#include <selinux/android.h>
+#include <system/thread_defs.h>
+
+#include "dexopt.h"
+#include "installd_deps.h"
+#include "otapreopt_utils.h"
+#include "utils.h"
+
+using android::base::StringPrintf;
+using android::base::EndsWith;
+using android::base::unique_fd;
+
+namespace android {
+namespace installd {
+
+// Deleter using free() for use with std::unique_ptr<>. See also UniqueCPtr<> below.
+struct FreeDelete {
+  // NOTE: Deleting a const object is valid but free() takes a non-const pointer.
+  void operator()(const void* ptr) const {
+    free(const_cast<void*>(ptr));
+  }
+};
+
+// Alias for std::unique_ptr<> that uses the C function free() to delete objects.
+template <typename T>
+using UniqueCPtr = std::unique_ptr<T, FreeDelete>;
+
+static unique_fd invalid_unique_fd() {
+    return unique_fd(-1);
+}
+
+static bool clear_profile(const std::string& profile) {
+    unique_fd ufd(open(profile.c_str(), O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
+    if (ufd.get() < 0) {
+        if (errno != ENOENT) {
+            PLOG(WARNING) << "Could not open profile " << profile;
+            return false;
+        } else {
+            // Nothing to clear. That's ok.
+            return true;
+        }
+    }
+
+    if (flock(ufd.get(), LOCK_EX | LOCK_NB) != 0) {
+        if (errno != EWOULDBLOCK) {
+            PLOG(WARNING) << "Error locking profile " << profile;
+        }
+        // This implies that the app owning this profile is running
+        // (and has acquired the lock).
+        //
+        // If we can't acquire the lock bail out since clearing is useless anyway
+        // (the app will write again to the profile).
+        //
+        // Note:
+        // This does not impact the this is not an issue for the profiling correctness.
+        // In case this is needed because of an app upgrade, profiles will still be
+        // eventually cleared by the app itself due to checksum mismatch.
+        // If this is needed because profman advised, then keeping the data around
+        // until the next run is again not an issue.
+        //
+        // If the app attempts to acquire a lock while we've held one here,
+        // it will simply skip the current write cycle.
+        return false;
+    }
+
+    bool truncated = ftruncate(ufd.get(), 0) == 0;
+    if (!truncated) {
+        PLOG(WARNING) << "Could not truncate " << profile;
+    }
+    if (flock(ufd.get(), LOCK_UN) != 0) {
+        PLOG(WARNING) << "Error unlocking profile " << profile;
+    }
+    return truncated;
+}
+
+// Clear the reference profile for the given location.
+// The location is the package name for primary apks or the dex path for secondary dex files.
+static bool clear_reference_profile(const std::string& location, bool is_secondary_dex) {
+    return clear_profile(create_reference_profile_path(location, is_secondary_dex));
+}
+
+// Clear the reference profile for the given location.
+// The location is the package name for primary apks or the dex path for secondary dex files.
+static bool clear_current_profile(const std::string& pkgname, userid_t user,
+        bool is_secondary_dex) {
+    return clear_profile(create_current_profile_path(user, pkgname, is_secondary_dex));
+}
+
+// Clear the reference profile for the primary apk of the given package.
+bool clear_primary_reference_profile(const std::string& pkgname) {
+    return clear_reference_profile(pkgname, /*is_secondary_dex*/false);
+}
+
+// Clear all current profile for the primary apk of the given package.
+bool clear_primary_current_profiles(const std::string& pkgname) {
+    bool success = true;
+    // For secondary dex files, we don't really need the user but we use it for sanity checks.
+    std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
+    for (auto user : users) {
+        success &= clear_current_profile(pkgname, user, /*is_secondary_dex*/false);
+    }
+    return success;
+}
+
+// Clear the current profile for the primary apk of the given package and user.
+bool clear_primary_current_profile(const std::string& pkgname, userid_t user) {
+    return clear_current_profile(pkgname, user, /*is_secondary_dex*/false);
+}
+
+static int split_count(const char *str)
+{
+  char *ctx;
+  int count = 0;
+  char buf[kPropertyValueMax];
+
+  strncpy(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 const char* get_location_from_path(const char* path) {
+    static constexpr char kLocationSeparator = '/';
+    const char *location = strrchr(path, kLocationSeparator);
+    if (location == NULL) {
+        return path;
+    } else {
+        // Skip the separator character.
+        return location + 1;
+    }
+}
+
+static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vdex_fd, int image_fd,
+        const char* input_file_name, const char* output_file_name, int swap_fd,
+        const char* instruction_set, const char* compiler_filter,
+        bool debuggable, bool post_bootcomplete, int profile_fd, const char* shared_libraries) {
+    static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
+
+    if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
+        ALOGE("Instruction set %s longer than max length of %d",
+              instruction_set, MAX_INSTRUCTION_SET_LEN);
+        return;
+    }
+
+    // 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);
+    }
+
+    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);
+    }
+
+    static const char* DEX2OAT_BIN = "/system/bin/dex2oat";
+
+    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];
+
+    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);
+    }
+
+    // Compute compiler filter.
+
+    bool have_dex2oat_compiler_filter_flag = false;
+    if (skip_compilation) {
+        strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=extract");
+        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);
+        }
+    }
+
+    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);
+        }
+    }
+
+    // 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);
+    }
+
+    // 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());
+    }
+
+
+    ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, relative_input_file_name, output_file_name);
+
+    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)
+                     + (shared_libraries != nullptr ? 4 : 0)
+                     + (has_base_dir ? 1 : 0)
+                     + (have_dex2oat_large_app_threshold ? 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 (shared_libraries != nullptr) {
+        argv[i++] = RUNTIME_ARG;
+        argv[i++] = "-classpath";
+        argv[i++] = RUNTIME_ARG;
+        argv[i++] = shared_libraries;
+    }
+    if (has_base_dir) {
+        argv[i++] = base_dir;
+    }
+    // Do not add after dex2oat_flags, they should override others for debugging.
+    argv[i] = NULL;
+
+    execv(DEX2OAT_BIN, (char * const *)argv);
+    ALOGE("execv(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno));
+}
+
+/*
+ * Whether dexopt should use a swap file when compiling an APK.
+ *
+ * If kAlwaysProvideSwapFile, do this on all devices (dex2oat will make a more informed decision
+ * itself, anyways).
+ *
+ * Otherwise, read "dalvik.vm.dex2oat-swap". If the property exists, return whether it is "true".
+ *
+ * Otherwise, return true if this is a low-mem device.
+ *
+ * Otherwise, return default value.
+ */
+static bool kAlwaysProvideSwapFile = false;
+static bool kDefaultProvideSwapFile = true;
+
+static bool ShouldUseSwapFileForDexopt() {
+    if (kAlwaysProvideSwapFile) {
+        return true;
+    }
+
+    // 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;
+        }
+    }
+
+    // Shortcut for default value. This is an implementation optimization for the process sketched
+    // above. If the default value is true, we can avoid to check whether this is a low-mem device,
+    // as low-mem is never returning false. The compiler will optimize this away if it can.
+    if (kDefaultProvideSwapFile) {
+        return true;
+    }
+
+    bool is_low_mem = property_get_bool("ro.config.low_ram", false);
+    if (is_low_mem) {
+        return true;
+    }
+
+    // Default value must be false here.
+    return kDefaultProvideSwapFile;
+}
+
+static void SetDex2OatScheduling(bool set_to_bg) {
+    if (set_to_bg) {
+        if (set_sched_policy(0, SP_BACKGROUND) < 0) {
+            ALOGE("set_sched_policy failed: %s\n", strerror(errno));
+            exit(70);
+        }
+        if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
+            ALOGE("setpriority failed: %s\n", strerror(errno));
+            exit(71);
+        }
+    }
+}
+
+static bool create_profile(int uid, const std::string& profile) {
+    unique_fd fd(TEMP_FAILURE_RETRY(open(profile.c_str(), O_CREAT | O_NOFOLLOW, 0600)));
+    if (fd.get() < 0) {
+        if (errno == EEXIST) {
+            return true;
+        } else {
+            PLOG(ERROR) << "Failed to create profile " << profile;
+            return false;
+        }
+    }
+    // Profiles should belong to the app; make sure of that by giving ownership to
+    // 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;
+        return false;
+    }
+    return true;
+}
+
+static unique_fd open_profile(int uid, const std::string& profile, bool read_write) {
+    // Check if we need to open the profile for a read-write operation. If so, we
+    // might need to create the profile since the file might not be there. Reference
+    // profiles are created on the fly so they might not exist beforehand.
+    if (read_write) {
+        if (!create_profile(uid, profile)) {
+            return invalid_unique_fd();
+        }
+    }
+    int flags = read_write ? O_RDWR : O_RDONLY;
+    // Do not follow symlinks when opening a profile:
+    //   - primary profiles should not contain symlinks in their paths
+    //   - secondary dex paths should have been already resolved and validated
+    flags |= O_NOFOLLOW;
+
+    unique_fd fd(TEMP_FAILURE_RETRY(open(profile.c_str(), flags)));
+    if (fd.get() < 0) {
+        if (errno != ENOENT) {
+            // Profiles might be missing for various reasons. For example, in a
+            // multi-user environment, the profile directory for one user can be created
+            // after we start a merge. In this case the current profile for that user
+            // will not be found.
+            // Also, the secondary dex profiles might be deleted by the app at any time,
+            // so we can't we need to prepare if they are missing.
+            PLOG(ERROR) << "Failed to open profile " << profile;
+        }
+        return invalid_unique_fd();
+    }
+
+    return fd;
+}
+
+static unique_fd open_current_profile(uid_t uid, userid_t user, const std::string& location,
+        bool is_secondary_dex) {
+    std::string profile = create_current_profile_path(user, location, is_secondary_dex);
+    return open_profile(uid, profile, /*read_write*/false);
+}
+
+static unique_fd open_reference_profile(uid_t uid, const std::string& location, bool read_write,
+        bool is_secondary_dex) {
+    std::string profile = create_reference_profile_path(location, is_secondary_dex);
+    return open_profile(uid, profile, read_write);
+}
+
+static void open_profile_files(uid_t uid, const std::string& location, bool is_secondary_dex,
+            /*out*/ std::vector<unique_fd>* profiles_fd, /*out*/ unique_fd* reference_profile_fd) {
+    // Open the reference profile in read-write mode as profman might need to save the merge.
+    *reference_profile_fd = open_reference_profile(uid, location, /*read_write*/ true,
+            is_secondary_dex);
+
+    // For secondary dex files, we don't really need the user but we use it for sanity checks.
+    // Note: the user owning the dex file should be the current user.
+    std::vector<userid_t> users;
+    if (is_secondary_dex){
+        users.push_back(multiuser_get_user_id(uid));
+    } else {
+        users = get_known_users(/*volume_uuid*/ nullptr);
+    }
+    for (auto user : users) {
+        unique_fd profile_fd = open_current_profile(uid, user, location, is_secondary_dex);
+        // Add to the lists only if both fds are valid.
+        if (profile_fd.get() >= 0) {
+            profiles_fd->push_back(std::move(profile_fd));
+        }
+    }
+}
+
+static void drop_capabilities(uid_t uid) {
+    if (setgid(uid) != 0) {
+        ALOGE("setgid(%d) failed in installd during dexopt\n", uid);
+        exit(64);
+    }
+    if (setuid(uid) != 0) {
+        ALOGE("setuid(%d) failed in installd during dexopt\n", uid);
+        exit(65);
+    }
+    // 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) {
+        ALOGE("capset failed: %s\n", strerror(errno));
+        exit(66);
+    }
+}
+
+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;
+
+static void run_profman_merge(const std::vector<unique_fd>& profiles_fd,
+        const unique_fd& reference_profile_fd) {
+    static const size_t MAX_INT_LEN = 32;
+    static const char* PROFMAN_BIN = "/system/bin/profman";
+
+    std::vector<std::string> profile_args(profiles_fd.size());
+    char profile_buf[strlen("--profile-file-fd=") + MAX_INT_LEN];
+    for (size_t k = 0; k < profiles_fd.size(); k++) {
+        sprintf(profile_buf, "--profile-file-fd=%d", profiles_fd[k].get());
+        profile_args[k].assign(profile_buf);
+    }
+    char reference_profile_arg[strlen("--reference-profile-file-fd=") + MAX_INT_LEN];
+    sprintf(reference_profile_arg, "--reference-profile-file-fd=%d", reference_profile_fd.get());
+
+    // program name, reference profile fd, the final NULL and the profile fds
+    const char* argv[3 + profiles_fd.size()];
+    int i = 0;
+    argv[i++] = PROFMAN_BIN;
+    argv[i++] = reference_profile_arg;
+    for (size_t k = 0; k < profile_args.size(); k++) {
+        argv[i++] = profile_args[k].c_str();
+    }
+    // Do not add after dex2oat_flags, they should override others for debugging.
+    argv[i] = NULL;
+
+    execv(PROFMAN_BIN, (char * const *)argv);
+    ALOGE("execv(%s) failed: %s\n", PROFMAN_BIN, strerror(errno));
+    exit(68);   /* only get here on exec failure */
+}
+
+// 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.
+// Returns true if there is enough information in the current profiles that makes it
+// worth to recompile the given location.
+// If the return value is true all the current profiles would have been merged into
+// the reference profiles accessible with open_reference_profile().
+static bool analyze_profiles(uid_t uid, const std::string& location, bool is_secondary_dex) {
+    std::vector<unique_fd> profiles_fd;
+    unique_fd reference_profile_fd;
+    open_profile_files(uid, location, is_secondary_dex, &profiles_fd, &reference_profile_fd);
+    if (profiles_fd.empty() || (reference_profile_fd.get() < 0)) {
+        // Skip profile guided compilation because no profiles were found.
+        // Or if the reference profile info couldn't be opened.
+        return false;
+    }
+
+    pid_t pid = fork();
+    if (pid == 0) {
+        /* child -- drop privileges before continuing */
+        drop_capabilities(uid);
+        run_profman_merge(profiles_fd, reference_profile_fd);
+        exit(68);   /* only get here on exec failure */
+    }
+    /* parent */
+    int return_code = wait_child(pid);
+    bool need_to_compile = false;
+    bool should_clear_current_profiles = false;
+    bool should_clear_reference_profile = false;
+    if (!WIFEXITED(return_code)) {
+        LOG(WARNING) << "profman failed for location " << location << ": " << return_code;
+    } else {
+        return_code = WEXITSTATUS(return_code);
+        switch (return_code) {
+            case PROFMAN_BIN_RETURN_CODE_COMPILE:
+                need_to_compile = true;
+                should_clear_current_profiles = true;
+                should_clear_reference_profile = false;
+                break;
+            case PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION:
+                need_to_compile = false;
+                should_clear_current_profiles = false;
+                should_clear_reference_profile = false;
+                break;
+            case PROFMAN_BIN_RETURN_CODE_BAD_PROFILES:
+                LOG(WARNING) << "Bad profiles for location " << location;
+                need_to_compile = false;
+                should_clear_current_profiles = true;
+                should_clear_reference_profile = true;
+                break;
+            case PROFMAN_BIN_RETURN_CODE_ERROR_IO:  // fall-through
+            case PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING:
+                // Temporary IO problem (e.g. locking). Ignore but log a warning.
+                LOG(WARNING) << "IO error while reading profiles for location " << location;
+                need_to_compile = false;
+                should_clear_current_profiles = false;
+                should_clear_reference_profile = false;
+                break;
+           default:
+                // Unknown return code or error. Unlink profiles.
+                LOG(WARNING) << "Unknown error code while processing profiles for location "
+                        << location << ": " << return_code;
+                need_to_compile = false;
+                should_clear_current_profiles = true;
+                should_clear_reference_profile = true;
+                break;
+        }
+    }
+
+    if (should_clear_current_profiles) {
+        if (is_secondary_dex) {
+            // For secondary dex files, the owning user is the current user.
+            clear_current_profile(location, multiuser_get_user_id(uid), is_secondary_dex);
+        } else  {
+            clear_primary_current_profiles(location);
+        }
+    }
+    if (should_clear_reference_profile) {
+        clear_reference_profile(location, is_secondary_dex);
+    }
+    return need_to_compile;
+}
+
+// Decides if profile guided compilation is needed or not based on existing profiles.
+// The analysis is done for the primary apks of the given package.
+// Returns true if there is enough information in the current profiles that makes it
+// worth to recompile the package.
+// If the return value is true all the current profiles would have been merged into
+// the reference profiles accessible with open_reference_profile().
+bool analyze_primary_profiles(uid_t uid, const std::string& pkgname) {
+    return analyze_profiles(uid, pkgname, /*is_secondary_dex*/false);
+}
+
+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);
+    ALOGE("execv(%s) failed: %s\n", PROFMAN_BIN, strerror(errno));
+    exit(68);   /* only get here on exec failure */
+}
+
+bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_paths) {
+    std::vector<unique_fd> profile_fds;
+    unique_fd reference_profile_fd;
+    std::string out_file_name = StringPrintf("/data/misc/profman/%s.txt", pkgname.c_str());
+
+    open_profile_files(uid, pkgname, /*is_secondary_dex*/false,
+            &profile_fds, &reference_profile_fd);
+
+    const bool has_reference_profile = (reference_profile_fd.get() != -1);
+    const bool has_profiles = !profile_fds.empty();
+
+    if (!has_reference_profile && !has_profiles) {
+        LOG(ERROR)  << "profman dump: no profiles to dump for " << pkgname;
+        return false;
+    }
+
+    unique_fd output_fd(open(out_file_name.c_str(),
+            O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0644));
+    if (fchmod(output_fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
+        ALOGE("installd cannot chmod '%s' dump_profile\n", out_file_name.c_str());
+        return false;
+    }
+    std::vector<std::string> code_full_paths = base::Split(code_paths, ";");
+    std::vector<std::string> dex_locations;
+    std::vector<unique_fd> apk_fds;
+    for (const std::string& code_full_path : code_full_paths) {
+        const char* full_path = code_full_path.c_str();
+        unique_fd apk_fd(open(full_path, O_RDONLY | O_NOFOLLOW));
+        if (apk_fd == -1) {
+            ALOGE("installd cannot open '%s'\n", full_path);
+            return false;
+        }
+        dex_locations.push_back(get_location_from_path(full_path));
+        apk_fds.push_back(std::move(apk_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);
+        exit(68);   /* only get here on exec failure */
+    }
+    /* parent */
+    int return_code = wait_child(pid);
+    if (!WIFEXITED(return_code)) {
+        LOG(WARNING) << "profman failed for package " << pkgname << ": "
+                << return_code;
+        return false;
+    }
+    return true;
+}
+
+static std::string replace_file_extension(const std::string& oat_path, const std::string& new_ext) {
+  // A standard dalvik-cache entry. Replace ".dex" with `new_ext`.
+  if (EndsWith(oat_path, ".dex")) {
+    std::string new_path = oat_path;
+    new_path.replace(new_path.length() - strlen(".dex"), strlen(".dex"), new_ext);
+    CHECK(EndsWith(new_path, new_ext.c_str()));
+    return new_path;
+  }
+
+  // An odex entry. Not that this may not be an extension, e.g., in the OTA
+  // case (where the base name will have an extension for the B artifact).
+  size_t odex_pos = oat_path.rfind(".odex");
+  if (odex_pos != std::string::npos) {
+    std::string new_path = oat_path;
+    new_path.replace(odex_pos, strlen(".odex"), new_ext);
+    CHECK_NE(new_path.find(new_ext), std::string::npos);
+    return new_path;
+  }
+
+  // Don't know how to handle this.
+  return "";
+}
+
+// Translate the given oat path to an art (app image) path. An empty string
+// denotes an error.
+static std::string create_image_filename(const std::string& oat_path) {
+    return replace_file_extension(oat_path, ".art");
+}
+
+// Translate the given oat path to a vdex path. An empty string denotes an error.
+static std::string create_vdex_filename(const std::string& oat_path) {
+    return replace_file_extension(oat_path, ".vdex");
+}
+
+static bool add_extension_to_file_name(char* file_name, const char* extension) {
+    if (strlen(file_name) + strlen(extension) + 1 > PKG_PATH_MAX) {
+        return false;
+    }
+    strcat(file_name, extension);
+    return true;
+}
+
+static int open_output_file(const char* file_name, bool recreate, int permissions) {
+    int flags = O_RDWR | O_CREAT;
+    if (recreate) {
+        if (unlink(file_name) < 0) {
+            if (errno != ENOENT) {
+                PLOG(ERROR) << "open_output_file: Couldn't unlink " << file_name;
+            }
+        }
+        flags |= O_EXCL;
+    }
+    return open(file_name, flags, permissions);
+}
+
+static bool set_permissions_and_ownership(
+        int fd, bool is_public, int uid, const char* path, bool is_secondary_dex) {
+    // Primary apks are owned by the system. Secondary dex files are owned by the app.
+    int owning_uid = is_secondary_dex ? uid : AID_SYSTEM;
+    if (fchmod(fd,
+               S_IRUSR|S_IWUSR|S_IRGRP |
+               (is_public ? S_IROTH : 0)) < 0) {
+        ALOGE("installd cannot chmod '%s' during dexopt\n", path);
+        return false;
+    } else if (fchown(fd, owning_uid, uid) < 0) {
+        ALOGE("installd cannot chown '%s' during dexopt\n", path);
+        return false;
+    }
+    return true;
+}
+
+static bool IsOutputDalvikCache(const char* oat_dir) {
+  // InstallerConnection.java (which invokes installd) transforms Java null arguments
+  // into '!'. Play it safe by handling it both.
+  // TODO: ensure we never get null.
+  // TODO: pass a flag instead of inferring if the output is dalvik cache.
+  return oat_dir == nullptr || oat_dir[0] == '!';
+}
+
+static bool create_oat_out_path(const char* apk_path, const char* instruction_set,
+            const char* oat_dir, bool is_secondary_dex, /*out*/ char* out_oat_path) {
+    // Early best-effort check whether we can fit the the path into our buffers.
+    // Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run
+    // without a swap file, if necessary. Reference profiles file also add an extra ".prof"
+    // extension to the cache path (5 bytes).
+    if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
+        ALOGE("apk_path too long '%s'\n", apk_path);
+        return false;
+    }
+
+    if (!IsOutputDalvikCache(oat_dir)) {
+        // Oat dirs for secondary dex files are already validated.
+        if (!is_secondary_dex && validate_apk_path(oat_dir)) {
+            ALOGE("cannot validate apk path with oat_dir '%s'\n", oat_dir);
+            return false;
+        }
+        if (!calculate_oat_file_path(out_oat_path, oat_dir, apk_path, instruction_set)) {
+            return false;
+        }
+    } else {
+        if (!create_cache_path(out_oat_path, apk_path, instruction_set)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+// Helper for fd management. This is similar to a unique_fd in that it closes the file descriptor
+// on destruction. It will also run the given cleanup (unless told not to) after closing.
+//
+// Usage example:
+//
+//   Dex2oatFileWrapper file(open(...),
+//                                                   [name]() {
+//                                                       unlink(name.c_str());
+//                                                   });
+//   // Note: care needs to be taken about name, as it needs to have a lifetime longer than the
+//            wrapper if captured as a reference.
+//
+//   if (file.get() == -1) {
+//       // Error opening...
+//   }
+//
+//   ...
+//   if (error) {
+//       // At this point, when the Dex2oatFileWrapper is destructed, the cleanup function will run
+//       // and delete the file (after the fd is closed).
+//       return -1;
+//   }
+//
+//   (Success case)
+//   file.SetCleanup(false);
+//   // At this point, when the Dex2oatFileWrapper is destructed, the cleanup function will not run
+//   // (leaving the file around; after the fd is closed).
+//
+class Dex2oatFileWrapper {
+ public:
+    Dex2oatFileWrapper() : value_(-1), cleanup_(), do_cleanup_(true), auto_close_(true) {
+    }
+
+    Dex2oatFileWrapper(int value, std::function<void ()> cleanup)
+            : value_(value), cleanup_(cleanup), do_cleanup_(true), auto_close_(true) {}
+
+    Dex2oatFileWrapper(Dex2oatFileWrapper&& other) {
+        value_ = other.value_;
+        cleanup_ = other.cleanup_;
+        do_cleanup_ = other.do_cleanup_;
+        auto_close_ = other.auto_close_;
+        other.release();
+    }
+
+    Dex2oatFileWrapper& operator=(Dex2oatFileWrapper&& other) {
+        value_ = other.value_;
+        cleanup_ = other.cleanup_;
+        do_cleanup_ = other.do_cleanup_;
+        auto_close_ = other.auto_close_;
+        other.release();
+        return *this;
+    }
+
+    ~Dex2oatFileWrapper() {
+        reset(-1);
+    }
+
+    int get() {
+        return value_;
+    }
+
+    void SetCleanup(bool cleanup) {
+        do_cleanup_ = cleanup;
+    }
+
+    void reset(int new_value) {
+        if (auto_close_ && value_ >= 0) {
+            close(value_);
+        }
+        if (do_cleanup_ && cleanup_ != nullptr) {
+            cleanup_();
+        }
+
+        value_ = new_value;
+    }
+
+    void reset(int new_value, std::function<void ()> new_cleanup) {
+        if (auto_close_ && value_ >= 0) {
+            close(value_);
+        }
+        if (do_cleanup_ && cleanup_ != nullptr) {
+            cleanup_();
+        }
+
+        value_ = new_value;
+        cleanup_ = new_cleanup;
+    }
+
+    void DisableAutoClose() {
+        auto_close_ = false;
+    }
+
+ private:
+    void release() {
+        value_ = -1;
+        do_cleanup_ = false;
+        cleanup_ = nullptr;
+    }
+    int value_;
+    std::function<void ()> cleanup_;
+    bool do_cleanup_;
+    bool auto_close_;
+};
+
+// (re)Creates the app image if needed.
+Dex2oatFileWrapper maybe_open_app_image(const char* out_oat_path, bool profile_guided,
+        bool is_public, int uid, bool is_secondary_dex) {
+    // Use app images only if it is enabled (by a set image format) and we are compiling
+    // profile-guided (so the app image doesn't conservatively contain all classes).
+    // Note that we don't create an image for secondary dex files.
+    if (is_secondary_dex || !profile_guided) {
+        return Dex2oatFileWrapper();
+    }
+
+    const std::string image_path = create_image_filename(out_oat_path);
+    if (image_path.empty()) {
+        // Happens when the out_oat_path has an unknown extension.
+        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) {
+        return Dex2oatFileWrapper();
+    }
+    // Recreate is true since we do not want to modify a mapped image. If the app is
+    // already running and we modify the image file, it can cause crashes (b/27493510).
+    Dex2oatFileWrapper wrapper_fd(
+            open_output_file(image_path.c_str(), true /*recreate*/, 0600 /*permissions*/),
+            [image_path]() { unlink(image_path.c_str()); });
+    if (wrapper_fd.get() < 0) {
+        // Could not create application image file. Go on since we can compile without it.
+        LOG(ERROR) << "installd could not create '" << image_path
+                << "' for image file during dexopt";
+         // If we have a valid image file path but no image fd, explicitly erase the image file.
+        if (unlink(image_path.c_str()) < 0) {
+            if (errno != ENOENT) {
+                PLOG(ERROR) << "Couldn't unlink image file " << image_path;
+            }
+        }
+    } else if (!set_permissions_and_ownership(
+                wrapper_fd.get(), is_public, uid, image_path.c_str(), is_secondary_dex)) {
+        ALOGE("installd cannot set owner '%s' for image during dexopt\n", image_path.c_str());
+        wrapper_fd.reset(-1);
+    }
+
+    return wrapper_fd;
+}
+
+// Creates the dexopt swap file if necessary and return its fd.
+// Returns -1 if there's no need for a swap or in case of errors.
+unique_fd maybe_open_dexopt_swap_file(const char* out_oat_path) {
+    if (!ShouldUseSwapFileForDexopt()) {
+        return invalid_unique_fd();
+    }
+    // Make sure there really is enough space.
+    char swap_file_name[PKG_PATH_MAX];
+    strcpy(swap_file_name, out_oat_path);
+    if (!add_extension_to_file_name(swap_file_name, ".swap")) {
+        return invalid_unique_fd();
+    }
+    unique_fd swap_fd(open_output_file(
+            swap_file_name, /*recreate*/true, /*permissions*/0600));
+    if (swap_fd.get() < 0) {
+        // Could not create swap file. Optimistically go on and hope that we can compile
+        // without it.
+        ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name);
+    } else {
+        // Immediately unlink. We don't really want to hit flash.
+        if (unlink(swap_file_name) < 0) {
+            PLOG(ERROR) << "Couldn't unlink swap file " << swap_file_name;
+        }
+    }
+    return swap_fd;
+}
+
+// Opens the reference profiles if needed.
+// Note that the reference profile might not exist so it's OK if the fd will be -1.
+Dex2oatFileWrapper maybe_open_reference_profile(const std::string& pkgname,
+        const std::string& dex_path, bool profile_guided, bool is_public, int uid,
+        bool is_secondary_dex) {
+    // Public apps should not be compiled with profile information ever. Same goes for the special
+    // package '*' used for the system server.
+    if (!profile_guided || is_public || (pkgname[0] == '*')) {
+        return Dex2oatFileWrapper();
+    }
+
+    // Open reference profile in read only mode as dex2oat does not get write permissions.
+    const std::string location = is_secondary_dex ? dex_path : pkgname;
+    unique_fd ufd = open_reference_profile(uid, location, /*read_write*/false, is_secondary_dex);
+    const auto& cleanup = [location, is_secondary_dex]() {
+        clear_reference_profile(location.c_str(), is_secondary_dex);
+    };
+    return Dex2oatFileWrapper(ufd.release(), cleanup);
+}
+
+// Opens the vdex files and assigns the input fd to in_vdex_wrapper_fd and the output fd to
+// out_vdex_wrapper_fd. Returns true for success or false in case of errors.
+bool open_vdex_files(const char* apk_path, const char* out_oat_path, int dexopt_needed,
+        const char* instruction_set, bool is_public, int uid, bool is_secondary_dex,
+        bool profile_guided, Dex2oatFileWrapper* in_vdex_wrapper_fd,
+        Dex2oatFileWrapper* out_vdex_wrapper_fd) {
+    CHECK(in_vdex_wrapper_fd != nullptr);
+    CHECK(out_vdex_wrapper_fd != nullptr);
+    // Open the existing VDEX. We do this before creating the new output VDEX, which will
+    // unlink the old one.
+    char in_odex_path[PKG_PATH_MAX];
+    int dexopt_action = abs(dexopt_needed);
+    bool is_odex_location = dexopt_needed < 0;
+    std::string in_vdex_path_str;
+
+    // Infer the name of the output VDEX.
+    const std::string out_vdex_path_str = create_vdex_filename(out_oat_path);
+    if (out_vdex_path_str.empty()) {
+        return false;
+    }
+
+    bool update_vdex_in_place = false;
+    if (dexopt_action != DEX2OAT_FROM_SCRATCH) {
+        // Open the possibly existing vdex. If none exist, we pass -1 to dex2oat for input-vdex-fd.
+        const char* path = nullptr;
+        if (is_odex_location) {
+            if (calculate_odex_file_path(in_odex_path, apk_path, instruction_set)) {
+                path = in_odex_path;
+            } else {
+                ALOGE("installd cannot compute input vdex location for '%s'\n", apk_path);
+                return false;
+            }
+        } else {
+            path = out_oat_path;
+        }
+        in_vdex_path_str = create_vdex_filename(path);
+        if (in_vdex_path_str.empty()) {
+            ALOGE("installd cannot compute input vdex location for '%s'\n", path);
+            return false;
+        }
+        // We can update in place when all these conditions are met:
+        // 1) The vdex location to write to is the same as the vdex location to read (vdex files
+        //    on /system typically cannot be updated in place).
+        // 2) We dex2oat due to boot image change, because we then know the existing vdex file
+        //    cannot be currently used by a running process.
+        // 3) We are not doing a profile guided compilation, because dexlayout requires two
+        //    different vdex files to operate.
+        update_vdex_in_place =
+            (in_vdex_path_str == out_vdex_path_str) &&
+            (dexopt_action == DEX2OAT_FOR_BOOT_IMAGE) &&
+            !profile_guided;
+        if (update_vdex_in_place) {
+            // Open the file read-write to be able to update it.
+            in_vdex_wrapper_fd->reset(open(in_vdex_path_str.c_str(), O_RDWR, 0));
+            if (in_vdex_wrapper_fd->get() == -1) {
+                // If we failed to open the file, we cannot update it in place.
+                update_vdex_in_place = false;
+            }
+        } else {
+            in_vdex_wrapper_fd->reset(open(in_vdex_path_str.c_str(), O_RDONLY, 0));
+        }
+    }
+
+    // If we are updating the vdex in place, we do not need to recreate a vdex,
+    // and can use the same existing one.
+    if (update_vdex_in_place) {
+        // We unlink the file in case the invocation of dex2oat fails, to ensure we don't
+        // have bogus stale vdex files.
+        out_vdex_wrapper_fd->reset(
+              in_vdex_wrapper_fd->get(),
+              [out_vdex_path_str]() { unlink(out_vdex_path_str.c_str()); });
+        // Disable auto close for the in wrapper fd (it will be done when destructing the out
+        // wrapper).
+        in_vdex_wrapper_fd->DisableAutoClose();
+    } else {
+        out_vdex_wrapper_fd->reset(
+              open_output_file(out_vdex_path_str.c_str(), /*recreate*/true, /*permissions*/0644),
+              [out_vdex_path_str]() { unlink(out_vdex_path_str.c_str()); });
+        if (out_vdex_wrapper_fd->get() < 0) {
+            ALOGE("installd cannot open vdex'%s' during dexopt\n", out_vdex_path_str.c_str());
+            return false;
+        }
+    }
+    if (!set_permissions_and_ownership(out_vdex_wrapper_fd->get(), is_public, uid,
+            out_vdex_path_str.c_str(), is_secondary_dex)) {
+        ALOGE("installd cannot set owner '%s' for vdex during dexopt\n", out_vdex_path_str.c_str());
+        return false;
+    }
+
+    // If we got here we successfully opened the vdex files.
+    return true;
+}
+
+// Opens the output oat file for the given apk.
+// If successful it stores the output path into out_oat_path and returns true.
+Dex2oatFileWrapper open_oat_out_file(const char* apk_path, const char* oat_dir,
+        bool is_public, int uid, const char* instruction_set, bool is_secondary_dex,
+        char* out_oat_path) {
+    if (!create_oat_out_path(apk_path, instruction_set, oat_dir, is_secondary_dex, out_oat_path)) {
+        return Dex2oatFileWrapper();
+    }
+    const std::string out_oat_path_str(out_oat_path);
+    Dex2oatFileWrapper wrapper_fd(
+            open_output_file(out_oat_path, /*recreate*/true, /*permissions*/0644),
+            [out_oat_path_str]() { unlink(out_oat_path_str.c_str()); });
+    if (wrapper_fd.get() < 0) {
+        PLOG(ERROR) << "installd cannot open output during dexopt" <<  out_oat_path;
+    } else if (!set_permissions_and_ownership(
+                wrapper_fd.get(), is_public, uid, out_oat_path, is_secondary_dex)) {
+        ALOGE("installd cannot set owner '%s' for output during dexopt\n", out_oat_path);
+        wrapper_fd.reset(-1);
+    }
+    return wrapper_fd;
+}
+
+// Updates the access times of out_oat_path based on those from apk_path.
+void update_out_oat_access_times(const char* apk_path, const char* out_oat_path) {
+    struct stat input_stat;
+    memset(&input_stat, 0, sizeof(input_stat));
+    if (stat(apk_path, &input_stat) != 0) {
+        PLOG(ERROR) << "Could not stat " << apk_path << " during dexopt";
+        return;
+    }
+
+    struct utimbuf ut;
+    ut.actime = input_stat.st_atime;
+    ut.modtime = input_stat.st_mtime;
+    if (utime(out_oat_path, &ut) != 0) {
+        PLOG(WARNING) << "Could not update access times for " << apk_path << " during dexopt";
+    }
+}
+
+// Runs (execv) dexoptanalyzer on the given arguments.
+// 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, const char* instruction_set,
+        const char* compiler_filter, bool profile_was_updated) {
+    static const char* DEXOPTANALYZER_BIN = "/system/bin/dexoptanalyzer";
+    static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
+
+    if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
+        ALOGE("Instruction set %s longer than max length of %d",
+              instruction_set, MAX_INSTRUCTION_SET_LEN);
+        return;
+    }
+
+    char dex_file_arg[strlen("--dex-file=") + PKG_PATH_MAX];
+    char isa_arg[strlen("--isa=") + MAX_INSTRUCTION_SET_LEN];
+    char compiler_filter_arg[strlen("--compiler-filter=") + kPropertyValueMax];
+    const char* assume_profile_changed = "--assume-profile-changed";
+
+    sprintf(dex_file_arg, "--dex-file=%s", dex_file.c_str());
+    sprintf(isa_arg, "--isa=%s", instruction_set);
+    sprintf(compiler_filter_arg, "--compiler-filter=%s", compiler_filter);
+
+    // program name, dex file, isa, filter, the final NULL
+    const char* argv[5 + (profile_was_updated ? 1 : 0)];
+    int i = 0;
+    argv[i++] = DEXOPTANALYZER_BIN;
+    argv[i++] = dex_file_arg;
+    argv[i++] = isa_arg;
+    argv[i++] = compiler_filter_arg;
+    if (profile_was_updated) {
+        argv[i++] = assume_profile_changed;
+    }
+    argv[i] = NULL;
+
+    execv(DEXOPTANALYZER_BIN, (char * const *)argv);
+    ALOGE("execv(%s) failed: %s\n", DEXOPTANALYZER_BIN, strerror(errno));
+}
+
+// Prepares the oat dir for the secondary dex files.
+static bool prepare_secondary_dex_oat_dir(const std::string& dex_path, int uid,
+        const char* instruction_set, std::string* oat_dir_out) {
+    unsigned long dirIndex = dex_path.rfind('/');
+    if (dirIndex == std::string::npos) {
+        LOG(ERROR ) << "Unexpected dir structure for secondary dex " << dex_path;
+        return false;
+    }
+    std::string dex_dir = dex_path.substr(0, dirIndex);
+
+    // Create oat file output directory.
+    mode_t oat_dir_mode = S_IRWXU | S_IRWXG | S_IXOTH;
+    if (prepare_app_cache_dir(dex_dir, "oat", oat_dir_mode, uid, uid) != 0) {
+        LOG(ERROR) << "Could not prepare oat dir for secondary dex: " << dex_path;
+        return false;
+    }
+
+    char oat_dir[PKG_PATH_MAX];
+    snprintf(oat_dir, PKG_PATH_MAX, "%s/oat", dex_dir.c_str());
+    oat_dir_out->assign(oat_dir);
+
+    // Create oat/isa output directory.
+    if (prepare_app_cache_dir(*oat_dir_out, instruction_set, oat_dir_mode, uid, uid) != 0) {
+        LOG(ERROR) << "Could not prepare oat/isa dir for secondary dex: " << dex_path;
+        return false;
+    }
+
+    return true;
+}
+
+static int constexpr DEXOPTANALYZER_BIN_EXEC_ERROR = 200;
+
+// Verifies the result of dexoptanalyzer executed for the apk_path.
+// If the result is valid returns true and sets dexopt_needed_out to a valid value.
+// Returns false for errors or unexpected result values.
+static bool process_dexoptanalyzer_result(const std::string& dex_path, int result,
+            int* dexopt_needed_out) {
+    // The result values are defined in dexoptanalyzer.
+    switch (result) {
+        case 0:  // no_dexopt_needed
+            *dexopt_needed_out = NO_DEXOPT_NEEDED; return true;
+        case 1:  // dex2oat_from_scratch
+            *dexopt_needed_out = DEX2OAT_FROM_SCRATCH; return true;
+        case 5:  // dex2oat_for_bootimage_odex
+            *dexopt_needed_out = -DEX2OAT_FOR_BOOT_IMAGE; return true;
+        case 6:  // dex2oat_for_filter_odex
+            *dexopt_needed_out = -DEX2OAT_FOR_FILTER; return true;
+        case 7:  // dex2oat_for_relocation_odex
+            *dexopt_needed_out = -DEX2OAT_FOR_RELOCATION; return true;
+        case 2:  // dex2oat_for_bootimage_oat
+        case 3:  // dex2oat_for_filter_oat
+        case 4:  // dex2oat_for_relocation_oat
+            LOG(ERROR) << "Dexoptnalyzer return the status of an oat file."
+                    << " Expected odex file status for secondary dex " << dex_path
+                    << " : dexoptanalyzer result=" << result;
+            return false;
+        default:
+            LOG(ERROR) << "Unexpected result for dexoptanalyzer " << dex_path
+                    << " exec_dexoptanalyzer result=" << result;
+            return false;
+    }
+}
+
+// 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.
+// When returning true, the output parameters will be:
+//   - is_public_out: whether or not the oat file should not be made public
+//   - dexopt_needed_out: valid OatFileAsssitant::DexOptNeeded
+//   - oat_dir_out: the oat dir path where the oat file should be stored
+//   - dex_path_out: the real path of the dex file
+static bool process_secondary_dex_dexopt(const char* original_dex_path, const char* pkgname,
+        int dexopt_flags, const char* volume_uuid, int uid, const char* instruction_set,
+        const char* compiler_filter, bool* is_public_out, int* dexopt_needed_out,
+        std::string* oat_dir_out, std::string* dex_path_out) {
+    int storage_flag;
+
+    if ((dexopt_flags & DEXOPT_STORAGE_CE) != 0) {
+        storage_flag = FLAG_STORAGE_CE;
+        if ((dexopt_flags & DEXOPT_STORAGE_DE) != 0) {
+            LOG(ERROR) << "Ambiguous secondary dex storage flag. Both, CE and DE, flags are set";
+            return false;
+        }
+    } else if ((dexopt_flags & DEXOPT_STORAGE_DE) != 0) {
+        storage_flag = FLAG_STORAGE_DE;
+    } else {
+        LOG(ERROR) << "Secondary dex storage flag must be set";
+        return false;
+    }
+
+    {
+        // As opposed to the primary apk, secondary dex files might contain symlinks.
+        // Resolve the path before passing it to the validate method to
+        // make sure the verification is done on the real location.
+        UniqueCPtr<char> dex_real_path_cstr(realpath(original_dex_path, nullptr));
+        if (dex_real_path_cstr == nullptr) {
+            PLOG(ERROR) << "Could not get the real path of the secondary dex file "
+                    << original_dex_path;
+            return false;
+        } else {
+            dex_path_out->assign(dex_real_path_cstr.get());
+        }
+    }
+    const std::string& dex_path = *dex_path_out;
+    if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid, uid, storage_flag)) {
+        LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
+        return false;
+    }
+
+    // Check if the path exist. If not, there's nothing to do.
+    struct stat dex_path_stat;
+    if (stat(dex_path.c_str(), &dex_path_stat) != 0) {
+        if (errno == ENOENT) {
+            // Secondary dex files might be deleted any time by the app.
+            // Nothing to do if that's the case
+            ALOGV("Secondary dex does not exist %s", dex_path.c_str());
+            return NO_DEXOPT_NEEDED;
+        } else {
+            PLOG(ERROR) << "Could not access secondary dex " << dex_path;
+        }
+    }
+
+    // Check if we should make the oat file public.
+    // Note that if the dex file is not public the compiled code cannot be made public.
+    *is_public_out = ((dexopt_flags & DEXOPT_PUBLIC) != 0) &&
+            ((dex_path_stat.st_mode & S_IROTH) != 0);
+
+    // Prepare the oat directories.
+    if (!prepare_secondary_dex_oat_dir(dex_path, uid, instruction_set, oat_dir_out)) {
+        return false;
+    }
+
+    // Analyze profiles.
+    bool profile_was_updated = analyze_profiles(uid, dex_path, /*is_secondary_dex*/true);
+
+    pid_t pid = fork();
+    if (pid == 0) {
+        // child -- drop privileges before continuing.
+        drop_capabilities(uid);
+        // Run dexoptanalyzer to get dexopt_needed code.
+        exec_dexoptanalyzer(dex_path, instruction_set, compiler_filter, profile_was_updated);
+        exit(DEXOPTANALYZER_BIN_EXEC_ERROR);
+    }
+
+    /* parent */
+
+    int result = wait_child(pid);
+    if (!WIFEXITED(result)) {
+        LOG(ERROR) << "dexoptanalyzer failed for path " << dex_path << ": " << result;
+        return false;
+    }
+    result = WEXITSTATUS(result);
+    bool success = process_dexoptanalyzer_result(dex_path, result, dexopt_needed_out);
+    // Run dexopt only if needed or forced.
+    // Note that dexoptanalyzer is executed even if force compilation is enabled.
+    // We ignore its valid dexopNeeded result, but still check (in process_dexoptanalyzer_result)
+    // that we only get results for odex files (apk_dir/oat/isa/code.odex) and not
+    // for oat files from dalvik-cache.
+    if (success && ((dexopt_flags & DEXOPT_FORCE) != 0)) {
+        *dexopt_needed_out = DEX2OAT_FROM_SCRATCH;
+    }
+
+    return success;
+}
+
+int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* instruction_set,
+        int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
+        const char* volume_uuid, const char* shared_libraries, const char* se_info) {
+    CHECK(pkgname != nullptr);
+    CHECK(pkgname[0] != 0);
+    if ((dexopt_flags & ~DEXOPT_MASK) != 0) {
+        LOG_FATAL("dexopt flags contains unknown fields\n");
+    }
+
+    bool is_public = (dexopt_flags & DEXOPT_PUBLIC) != 0;
+    bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0;
+    bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0;
+    bool profile_guided = (dexopt_flags & DEXOPT_PROFILE_GUIDED) != 0;
+    bool is_secondary_dex = (dexopt_flags & DEXOPT_SECONDARY_DEX) != 0;
+
+    // Check if we're dealing with a secondary dex file and if we need to compile it.
+    std::string oat_dir_str;
+    std::string dex_real_path;
+    if (is_secondary_dex) {
+        if (process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid,
+                instruction_set, compiler_filter, &is_public, &dexopt_needed, &oat_dir_str,
+                &dex_real_path)) {
+            oat_dir = oat_dir_str.c_str();
+            dex_path = dex_real_path.c_str();
+            if (dexopt_needed == NO_DEXOPT_NEEDED) {
+                return 0;  // Nothing to do, report success.
+            }
+        } else {
+            return -1;  // We had an error, logged in the process method.
+        }
+    } else {
+        // Currently these flags are only use 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);
+    }
+
+    // Open the input file.
+    unique_fd input_fd(open(dex_path, O_RDONLY, 0));
+    if (input_fd.get() < 0) {
+        ALOGE("installd cannot open '%s' for input during dexopt\n", dex_path);
+        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,
+            instruction_set, is_secondary_dex, out_oat_path);
+    if (out_oat_fd.get() < 0) {
+        return -1;
+    }
+
+    // Open vdex files.
+    Dex2oatFileWrapper in_vdex_fd;
+    Dex2oatFileWrapper out_vdex_fd;
+    if (!open_vdex_files(dex_path, out_oat_path, dexopt_needed, instruction_set, is_public, uid,
+            is_secondary_dex, profile_guided, &in_vdex_fd, &out_vdex_fd)) {
+        return -1;
+    }
+
+    // Ensure that the oat dir and the compiler artifacts of secondary dex files have the correct
+    // selinux context (we generate them on the fly during the dexopt invocation and they don't
+    // fully inherit their parent context).
+    // Note that for primary apk the oat files are created before, in a separate installd
+    // call which also does the restorecon. TODO(calin): unify the paths.
+    if (is_secondary_dex) {
+        if (selinux_android_restorecon_pkgdir(oat_dir, se_info, uid,
+                SELINUX_ANDROID_RESTORECON_RECURSE)) {
+            LOG(ERROR) << "Failed to restorecon " << oat_dir;
+            return -1;
+        }
+    }
+
+    // Create a swap file if necessary.
+    unique_fd swap_fd = maybe_open_dexopt_swap_file(out_oat_path);
+
+    // Create the app image file if needed.
+    Dex2oatFileWrapper image_fd =
+            maybe_open_app_image(out_oat_path, profile_guided, is_public, uid, is_secondary_dex);
+
+    // Open the reference profile if needed.
+    Dex2oatFileWrapper reference_profile_fd = maybe_open_reference_profile(
+            pkgname, dex_path, profile_guided, is_public, uid, is_secondary_dex);
+
+    ALOGV("DexInv: --- BEGIN '%s' ---\n", dex_path);
+
+    pid_t pid = fork();
+    if (pid == 0) {
+        /* child -- drop privileges before continuing */
+        drop_capabilities(uid);
+
+        SetDex2OatScheduling(boot_complete);
+        if (flock(out_oat_fd.get(), LOCK_EX | LOCK_NB) != 0) {
+            ALOGE("flock(%s) failed: %s\n", out_oat_path, strerror(errno));
+            _exit(67);
+        }
+
+        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,
+                    reference_profile_fd.get(),
+                    shared_libraries);
+        _exit(68);   /* only get here on exec failure */
+    } else {
+        int res = wait_child(pid);
+        if (res == 0) {
+            ALOGV("DexInv: --- END '%s' (success) ---\n", dex_path);
+        } else {
+            ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", dex_path, res);
+            return res;
+        }
+    }
+
+    update_out_oat_access_times(dex_path, out_oat_path);
+
+    // We've been successful, don't delete output.
+    out_oat_fd.SetCleanup(false);
+    out_vdex_fd.SetCleanup(false);
+    image_fd.SetCleanup(false);
+    reference_profile_fd.SetCleanup(false);
+
+    return 0;
+}
+
+// Try to remove the given directory. Log an error if the directory exists
+// and is empty but could not be removed.
+static bool rmdir_if_empty(const char* dir) {
+    if (rmdir(dir) == 0) {
+        return true;
+    }
+    if (errno == ENOENT || errno == ENOTEMPTY) {
+        return true;
+    }
+    PLOG(ERROR) << "Failed to remove dir: " << dir;
+    return false;
+}
+
+// Try to unlink the given file. Log an error if the file exists and could not
+// be unlinked.
+static bool unlink_if_exists(const std::string& file) {
+    if (unlink(file.c_str()) == 0) {
+        return true;
+    }
+    if (errno == ENOENT) {
+        return true;
+
+    }
+    PLOG(ERROR) << "Could not unlink: " << file;
+    return false;
+}
+
+// Create the oat file structure for the secondary dex 'dex_path' and assign
+// the individual path component to the 'out_' parameters.
+static bool create_secondary_dex_oat_layout(const std::string& dex_path, const std::string& isa,
+        /*out*/char* out_oat_dir, /*out*/char* out_oat_isa_dir, /*out*/char* out_oat_path) {
+    size_t dirIndex = dex_path.rfind('/');
+    if (dirIndex == std::string::npos) {
+        LOG(ERROR) << "Unexpected dir structure for dex file " << dex_path;
+        return false;
+    }
+    // TODO(calin): we have similar computations in at lest 3 other places
+    // (InstalldNativeService, otapropt and dexopt). Unify them and get rid of snprintf by
+    // use string append.
+    std::string apk_dir = dex_path.substr(0, dirIndex);
+    snprintf(out_oat_dir, PKG_PATH_MAX, "%s/oat", apk_dir.c_str());
+    snprintf(out_oat_isa_dir, PKG_PATH_MAX, "%s/%s", out_oat_dir, isa.c_str());
+
+    if (!create_oat_out_path(dex_path.c_str(), isa.c_str(), out_oat_dir,
+            /*is_secondary_dex*/true, out_oat_path)) {
+        LOG(ERROR) << "Could not create oat path for secondary dex " << dex_path;
+        return false;
+    }
+    return true;
+}
+
+// Reconcile the secondary dex 'dex_path' and its generated oat files.
+// Return true if all the parameters are valid and the secondary dex file was
+//   processed successfully (i.e. the dex_path either exists, or if not, its corresponding
+//   oat/vdex/art files where deleted successfully). In this case, out_secondary_dex_exists
+//   will be true if the secondary dex file still exists. If the secondary dex file does not exist,
+//   the method cleans up any previously generated compiler artifacts (oat, vdex, art).
+// Return false if there were errors during processing. In this case
+//   out_secondary_dex_exists will be set to false.
+bool reconcile_secondary_dex_file(const std::string& dex_path,
+        const std::string& pkgname, int uid, const std::vector<std::string>& isas,
+        const std::unique_ptr<std::string>& volume_uuid, int storage_flag,
+        /*out*/bool* out_secondary_dex_exists) {
+    // Set out to false to start with, just in case we have validation errors.
+    *out_secondary_dex_exists = false;
+    if (isas.size() == 0) {
+        LOG(ERROR) << "reconcile_secondary_dex_file called with empty isas vector";
+        return false;
+    }
+
+    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,
+            uid, storage_flag)) {
+        LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
+        return false;
+    }
+
+    if (access(dex_path.c_str(), F_OK) == 0) {
+        // The path exists, nothing to do. The odex files (if any) will be left untouched.
+        *out_secondary_dex_exists = true;
+        return true;
+    } else if (errno != ENOENT) {
+        PLOG(ERROR) << "Failed to check access to secondary dex " << dex_path;
+        return false;
+    }
+
+    // The secondary dex does not exist anymore. Clear any generated files.
+    char oat_path[PKG_PATH_MAX];
+    char oat_dir[PKG_PATH_MAX];
+    char oat_isa_dir[PKG_PATH_MAX];
+    bool result = true;
+    for (size_t i = 0; i < isas.size(); i++) {
+        if (!create_secondary_dex_oat_layout(dex_path, isas[i], oat_dir, oat_isa_dir, oat_path)) {
+            LOG(ERROR) << "Could not create secondary odex layout: " << dex_path;
+            result = false;
+            continue;
+        }
+
+        // Delete oat/vdex/art files.
+        result = unlink_if_exists(oat_path) && result;
+        result = unlink_if_exists(create_vdex_filename(oat_path)) && result;
+        result = unlink_if_exists(create_image_filename(oat_path)) && result;
+
+        // Delete profiles.
+        std::string current_profile = create_current_profile_path(
+                multiuser_get_user_id(uid), dex_path, /*is_secondary*/true);
+        std::string reference_profile = create_reference_profile_path(
+                dex_path, /*is_secondary*/true);
+        result = unlink_if_exists(current_profile) && result;
+        result = unlink_if_exists(reference_profile) && result;
+
+        // Try removing the directories as well, they might be empty.
+        result = rmdir_if_empty(oat_isa_dir) && result;
+        result = rmdir_if_empty(oat_dir) && result;
+    }
+
+    return result;
+}
+
+// Helper for move_ab, so that we can have common failure-case cleanup.
+static bool unlink_and_rename(const char* from, const char* to) {
+    // Check whether "from" exists, and if so whether it's regular. If it is, unlink. Otherwise,
+    // return a failure.
+    struct stat s;
+    if (stat(to, &s) == 0) {
+        if (!S_ISREG(s.st_mode)) {
+            LOG(ERROR) << from << " is not a regular file to replace for A/B.";
+            return false;
+        }
+        if (unlink(to) != 0) {
+            LOG(ERROR) << "Could not unlink " << to << " to move A/B.";
+            return false;
+        }
+    } else {
+        // This may be a permission problem. We could investigate the error code, but we'll just
+        // let the rename failure do the work for us.
+    }
+
+    // Try to rename "to" to "from."
+    if (rename(from, to) != 0) {
+        PLOG(ERROR) << "Could not rename " << from << " to " << to;
+        return false;
+    }
+    return true;
+}
+
+// Move/rename a B artifact (from) to an A artifact (to).
+static bool move_ab_path(const std::string& b_path, const std::string& a_path) {
+    // Check whether B exists.
+    {
+        struct stat s;
+        if (stat(b_path.c_str(), &s) != 0) {
+            // Silently ignore for now. The service calling this isn't smart enough to understand
+            // lack of artifacts at the moment.
+            return false;
+        }
+        if (!S_ISREG(s.st_mode)) {
+            LOG(ERROR) << "A/B artifact " << b_path << " is not a regular file.";
+            // Try to unlink, but swallow errors.
+            unlink(b_path.c_str());
+            return false;
+        }
+    }
+
+    // Rename B to A.
+    if (!unlink_and_rename(b_path.c_str(), a_path.c_str())) {
+        // Delete the b_path so we don't try again (or fail earlier).
+        if (unlink(b_path.c_str()) != 0) {
+            PLOG(ERROR) << "Could not unlink " << b_path;
+        }
+
+        return false;
+    }
+
+    return true;
+}
+
+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;
+
+        if (!ValidateTargetSlotSuffix(slot_suffix)) {
+            LOG(ERROR) << "Target slot suffix not legal: " << slot_suffix;
+            return false;
+        }
+    }
+
+    // Validate other inputs.
+    if (validate_apk_path(apk_path) != 0) {
+        LOG(ERROR) << "Invalid apk_path: " << apk_path;
+        return false;
+    }
+    if (validate_apk_path(oat_dir) != 0) {
+        LOG(ERROR) << "Invalid oat_dir: " << oat_dir;
+        return false;
+    }
+
+    char a_path[PKG_PATH_MAX];
+    if (!calculate_oat_file_path(a_path, oat_dir, apk_path, instruction_set)) {
+        return false;
+    }
+    const std::string a_vdex_path = create_vdex_filename(a_path);
+    const std::string a_image_path = create_image_filename(a_path);
+
+    // B path = A path + slot suffix.
+    const std::string b_path = StringPrintf("%s.%s", a_path, slot_suffix.c_str());
+    const std::string b_vdex_path = StringPrintf("%s.%s", a_vdex_path.c_str(), slot_suffix.c_str());
+    const std::string b_image_path = StringPrintf("%s.%s",
+                                                  a_image_path.c_str(),
+                                                  slot_suffix.c_str());
+
+    bool success = true;
+    if (move_ab_path(b_path, a_path)) {
+        if (move_ab_path(b_vdex_path, a_vdex_path)) {
+            // Note: we can live without an app image. As such, ignore failure to move the image file.
+            //       If we decide to require the app image, or the app image being moved correctly,
+            //       then change accordingly.
+            constexpr bool kIgnoreAppImageFailure = true;
+
+            if (!a_image_path.empty()) {
+                if (!move_ab_path(b_image_path, a_image_path)) {
+                    unlink(a_image_path.c_str());
+                    if (!kIgnoreAppImageFailure) {
+                        success = false;
+                    }
+                }
+            }
+        } else {
+            // Cleanup: delete B image, ignore errors.
+            unlink(b_image_path.c_str());
+            success = false;
+        }
+    } else {
+        // Cleanup: delete B image, ignore errors.
+        unlink(b_vdex_path.c_str());
+        unlink(b_image_path.c_str());
+        success = false;
+    }
+    return success;
+}
+
+bool delete_odex(const char* apk_path, const char* instruction_set, const char* oat_dir) {
+    // Delete the oat/odex file.
+    char out_path[PKG_PATH_MAX];
+    if (!create_oat_out_path(apk_path, instruction_set, oat_dir,
+            /*is_secondary_dex*/false, out_path)) {
+        return false;
+    }
+
+    // In case of a permission failure report the issue. Otherwise just print a warning.
+    auto unlink_and_check = [](const char* path) -> bool {
+        int result = unlink(path);
+        if (result != 0) {
+            if (errno == EACCES || errno == EPERM) {
+                PLOG(ERROR) << "Could not unlink " << path;
+                return false;
+            }
+            PLOG(WARNING) << "Could not unlink " << path;
+        }
+        return true;
+    };
+
+    // Delete the oat/odex file.
+    bool return_value_oat = unlink_and_check(out_path);
+
+    // Derive and delete the app image.
+    bool return_value_art = unlink_and_check(create_image_filename(out_path).c_str());
+
+    // Derive and delete the vdex file.
+    bool return_value_vdex = unlink_and_check(create_vdex_filename(out_path).c_str());
+
+    // Report success.
+    return return_value_oat && return_value_art && return_value_vdex;
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
new file mode 100644
index 0000000..355adb1
--- /dev/null
+++ b/cmds/installd/dexopt.h
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+#ifndef DEXOPT_H_
+#define DEXOPT_H_
+
+#include <sys/types.h>
+
+#include <cutils/multiuser.h>
+
+namespace android {
+namespace installd {
+
+/* dexopt needed flags matching those in dalvik.system.DexFile */
+static constexpr int NO_DEXOPT_NEEDED            = 0;
+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;
+static constexpr int PATCHOAT_FOR_RELOCATION     = 5;
+
+// Clear the reference profile for the primary apk of the given package.
+bool clear_primary_reference_profile(const std::string& pkgname);
+// Clear the current profile for the primary apk of the given package and user.
+bool clear_primary_current_profile(const std::string& pkgname, userid_t user);
+// Clear all current profile for the primary apk of the given package.
+bool clear_primary_current_profiles(const std::string& pkgname);
+
+bool move_ab(const char* apk_path, const char* instruction_set, const char* output_path);
+
+// Decide if profile guided compilation is needed or not based on existing profiles.
+// The analysis is done for the primary apks (base + splits) of the given package.
+// Returns true if there is enough information in the current profiles that makes it
+// worth to recompile the package.
+// If the return value is true all the current profiles would have been merged into
+// the reference profiles accessible with open_reference_profile().
+bool analyze_primary_profiles(uid_t uid, const std::string& pkgname);
+
+bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_paths);
+
+bool delete_odex(const char* apk_path, const char* instruction_set, const char* output_path);
+
+bool reconcile_secondary_dex_file(const std::string& dex_path,
+        const std::string& pkgname, int uid, const std::vector<std::string>& isas,
+        const std::unique_ptr<std::string>& volumeUuid, int storage_flag,
+        /*out*/bool* out_secondary_dex_exists);
+
+int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set,
+        int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
+        const char* volume_uuid, const char* shared_libraries, const char* se_info);
+
+}  // namespace installd
+}  // namespace android
+
+#endif  // DEXOPT_H_
diff --git a/cmds/installd/globals.cpp b/cmds/installd/globals.cpp
index 93e1ce5..edcdb6a 100644
--- a/cmds/installd/globals.cpp
+++ b/cmds/installd/globals.cpp
@@ -14,19 +14,17 @@
 ** limitations under the License.
 */
 
+#define LOG_TAG "installd"
+
 #include <stdlib.h>
 #include <string.h>
 
-#include <cutils/log.h>               // TODO: Move everything to base::logging.
+#include <log/log.h>              // TODO: Move everything to base::logging.
 
 #include <globals.h>
 #include <installd_constants.h>
 #include <utils.h>
 
-#ifndef LOG_TAG
-#define LOG_TAG "installd"
-#endif
-
 namespace android {
 namespace installd {
 
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index 8f883db..35936a2 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -13,6 +13,7 @@
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
+#define LOG_TAG "installd"
 
 #include <fcntl.h>
 #include <selinux/android.h>
@@ -20,30 +21,19 @@
 #include <sys/capability.h>
 #include <sys/fsuid.h>
 #include <sys/prctl.h>
-#include <sys/socket.h>
 #include <sys/stat.h>
 
 #include <android-base/logging.h>
 #include <cutils/fs.h>
-#include <cutils/log.h>               // TODO: Move everything to base::logging.
 #include <cutils/properties.h>
-#include <cutils/sockets.h>
+#include <log/log.h>              // TODO: Move everything to base::logging.
 #include <private/android_filesystem_config.h>
 
-#include <commands.h>
-#include <globals.h>
-#include <installd_constants.h>
-#include <installd_deps.h>  // Need to fill in requirements of commands.
-#include <utils.h>
-
-#ifndef LOG_TAG
-#define LOG_TAG "installd"
-#endif
-#define SOCKET_PATH "installd"
-
-#define BUFFER_MAX    1024  /* input buffer for commands */
-#define TOKEN_MAX     16    /* max number of arguments in buffer */
-#define REPLY_MAX     256   /* largest reply allowed */
+#include "InstalldNativeService.h"
+#include "globals.h"
+#include "installd_constants.h"
+#include "installd_deps.h"  // Need to fill in requirements of commands.
+#include "utils.h"
 
 namespace android {
 namespace installd {
@@ -65,17 +55,17 @@
                              const char *oat_dir,
                              const char *apk_path,
                              const char *instruction_set) {
-    char *file_name_start;
-    char *file_name_end;
+    const char *file_name_start;
+    const char *file_name_end;
 
     file_name_start = strrchr(apk_path, '/');
     if (file_name_start == NULL) {
-        ALOGE("apk_path '%s' has no '/'s in it\n", apk_path);
+        SLOGE("apk_path '%s' has no '/'s in it\n", apk_path);
         return false;
     }
     file_name_end = strrchr(apk_path, '.');
     if (file_name_end < file_name_start) {
-        ALOGE("apk_path '%s' has no extension\n", apk_path);
+        SLOGE("apk_path '%s' has no extension\n", apk_path);
         return false;
     }
 
@@ -101,14 +91,14 @@
                               const char *instruction_set) {
     if (strlen(apk_path) + strlen("oat/") + strlen(instruction_set)
             + strlen("/") + strlen("odex") + 1 > PKG_PATH_MAX) {
-        ALOGE("apk_path '%s' may be too long to form odex file path.\n", apk_path);
+        SLOGE("apk_path '%s' may be too long to form odex file path.\n", apk_path);
         return false;
     }
 
     strcpy(path, apk_path);
     char *end = strrchr(path, '/');
     if (end == NULL) {
-        ALOGE("apk_path '%s' has no '/'s in it?!\n", apk_path);
+        SLOGE("apk_path '%s' has no '/'s in it?!\n", apk_path);
         return false;
     }
     const char *apk_end = apk_path + (end - path); // strrchr(apk_path, '/');
@@ -118,7 +108,7 @@
     strcat(path, apk_end);         // path = /system/framework/oat/<isa>/whatever.jar\0
     end = strrchr(path, '.');
     if (end == NULL) {
-        ALOGE("apk_path '%s' has no extension.\n", apk_path);
+        SLOGE("apk_path '%s' has no extension.\n", apk_path);
         return false;
     }
     strcpy(end + 1, "odex");
@@ -151,12 +141,11 @@
         return false;
     }
 
-    sprintf(path,"%s%s/%s/%s%s",
+    sprintf(path,"%s%s/%s/%s",
             android_data_dir.path,
             DALVIK_CACHE,
             instruction_set,
-            src + 1, /* skip the leading / */
-            DALVIK_CACHE_POSTFIX);
+            src + 1 /* skip the leading / */);
 
     char* tmp =
             path +
@@ -171,407 +160,19 @@
         }
     }
 
+    strcat(path, DALVIK_CACHE_POSTFIX);
     return true;
 }
 
-
-static char* parse_null(char* arg) {
-    if (strcmp(arg, "!") == 0) {
-        return nullptr;
-    } else {
-        return arg;
-    }
-}
-
-static int do_ping(char **arg ATTRIBUTE_UNUSED, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
-    return 0;
-}
-
-static int do_create_app_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
-    /* const char *uuid, const char *pkgname, userid_t userid, int flags,
-            appid_t appid, const char* seinfo, int target_sdk_version */
-    return create_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]),
-                           atoi(arg[4]), arg[5], atoi(arg[6]));
-}
-
-static int do_restorecon_app_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
-    /* const char* uuid, const char* pkgName, userid_t userid, int flags,
-            appid_t appid, const char* seinfo */
-    return restorecon_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), atoi(arg[4]), arg[5]);
-}
-
-static int do_migrate_app_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
-    /* const char *uuid, const char *pkgname, userid_t userid, int flags */
-    return migrate_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]));
-}
-
-static int do_clear_app_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
-    /* const char *uuid, const char *pkgname, userid_t userid, int flags, ino_t ce_data_inode */
-    return clear_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), atol(arg[4]));
-}
-
-static int do_destroy_app_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
-    /* const char *uuid, const char *pkgname, userid_t userid, int flags, ino_t ce_data_inode */
-    return destroy_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), atol(arg[4]));
-}
-
-// We use otapreopt_chroot to get into the chroot.
-static constexpr const char* kOtaPreopt = "/system/bin/otapreopt_chroot";
-
-static int do_ota_dexopt(const char* args[DEXOPT_PARAM_COUNT],
-                         char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
-    // Time to fork and run otapreopt.
-
-    // Check that the tool exists.
-    struct stat s;
-    if (stat(kOtaPreopt, &s) != 0) {
-        LOG(ERROR) << "Otapreopt chroot tool not found.";
-        return -1;
-    }
-
-    pid_t pid = fork();
-    if (pid == 0) {
-        const char* argv[1 + DEXOPT_PARAM_COUNT + 1];
-        argv[0] = kOtaPreopt;
-
-        for (size_t i = 0; i < DEXOPT_PARAM_COUNT; ++i) {
-            argv[i + 1] = args[i];
-        }
-
-        argv[DEXOPT_PARAM_COUNT + 1] = nullptr;
-
-        execv(argv[0], (char * const *)argv);
-        PLOG(ERROR) << "execv(OTAPREOPT_CHROOT) failed";
-        exit(99);
-    } else {
-        int res = wait_child(pid);
-        if (res == 0) {
-            ALOGV("DexInv: --- END OTAPREOPT (success) ---\n");
-        } else {
-            ALOGE("DexInv: --- END OTAPREOPT --- status=0x%04x, process failed\n", res);
-        }
-        return res;
-    }
-}
-
-static int do_regular_dexopt(const char* args[DEXOPT_PARAM_COUNT],
-                             char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
-    return dexopt(args);
-}
-
-using DexoptFn = int (*)(const char* args[DEXOPT_PARAM_COUNT],
-                         char reply[REPLY_MAX]);
-
-static int do_dexopt(char **arg, char reply[REPLY_MAX])
-{
-    const char* args[DEXOPT_PARAM_COUNT];
-    for (size_t i = 0; i < DEXOPT_PARAM_COUNT; ++i) {
-        CHECK(arg[i] != nullptr);
-        args[i] = arg[i];
-    }
-
-    int dexopt_flags = atoi(arg[6]);
-    DexoptFn dexopt_fn;
-    if ((dexopt_flags & DEXOPT_OTA) != 0) {
-        dexopt_fn = do_ota_dexopt;
-    } else {
-        dexopt_fn = do_regular_dexopt;
-    }
-    return dexopt_fn(args, reply);
-}
-
-static int do_merge_profiles(char **arg, char reply[REPLY_MAX])
-{
-    uid_t uid = static_cast<uid_t>(atoi(arg[0]));
-    const char* pkgname = arg[1];
-    if (merge_profiles(uid, pkgname)) {
-        strncpy(reply, "true", REPLY_MAX);
-    } else {
-        strncpy(reply, "false", REPLY_MAX);
-    }
-    return 0;
-}
-
-static int do_dump_profiles(char **arg, char reply[REPLY_MAX])
-{
-    uid_t uid = static_cast<uid_t>(atoi(arg[0]));
-    const char* pkgname = arg[1];
-    const char* dex_files = arg[2];
-    if (dump_profile(uid, pkgname, dex_files)) {
-        strncpy(reply, "true", REPLY_MAX);
-    } else {
-        strncpy(reply, "false", REPLY_MAX);
-    }
-    return 0;
-}
-
-static int do_mark_boot_complete(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
-    return mark_boot_complete(arg[0] /* instruction set */);
-}
-
-static int do_rm_dex(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
-    return rm_dex(arg[0], arg[1]); /* pkgname, instruction_set */
-}
-
-static int do_free_cache(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) /* TODO int:free_size */
-{
-    return free_cache(parse_null(arg[0]), (int64_t)atoll(arg[1])); /* uuid, free_size */
-}
-
-static int do_get_app_size(char **arg, char reply[REPLY_MAX]) {
-    int64_t codesize = 0;
-    int64_t datasize = 0;
-    int64_t cachesize = 0;
-    int64_t asecsize = 0;
-    int res = 0;
-
-    /* const char *uuid, const char *pkgname, int userid, int flags, ino_t ce_data_inode,
-            const char* code_path */
-    res = get_app_size(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), atol(arg[4]),
-            arg[5], &codesize, &datasize, &cachesize, &asecsize);
-
-    /*
-     * Each int64_t can take up 22 characters printed out. Make sure it
-     * doesn't go over REPLY_MAX in the future.
-     */
-    snprintf(reply, REPLY_MAX, "%" PRId64 " %" PRId64 " %" PRId64 " %" PRId64,
-            codesize, datasize, cachesize, asecsize);
-    return res;
-}
-
-static int do_get_app_data_inode(char **arg, char reply[REPLY_MAX]) {
-    ino_t inode = 0;
-    int res = 0;
-
-    /* const char *uuid, const char *pkgname, int userid, int flags */
-    res = get_app_data_inode(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), &inode);
-
-    snprintf(reply, REPLY_MAX, "%" PRId64, (int64_t) inode);
-    return res;
-}
-
-static int do_move_complete_app(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
-    /* const char* from_uuid, const char *to_uuid, const char *package_name,
-            const char *data_app_name, appid_t appid, const char* seinfo,
-            int target_sdk_version */
-    return move_complete_app(parse_null(arg[0]), parse_null(arg[1]), arg[2], arg[3],
-                             atoi(arg[4]), arg[5], atoi(arg[6]));
-}
-
-static int do_create_user_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
-    /* const char *uuid, userid_t userid, int user_serial, int flags */
-    return create_user_data(parse_null(arg[0]), atoi(arg[1]), atoi(arg[2]), atoi(arg[3]));
-}
-
-static int do_destroy_user_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
-    /* const char *uuid, userid_t userid, int flags */
-    return destroy_user_data(parse_null(arg[0]), atoi(arg[1]), atoi(arg[2]));
-}
-
-static int do_linklib(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
-    return linklib(parse_null(arg[0]), arg[1], arg[2], atoi(arg[3]));
-}
-
-static int do_idmap(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
-    return idmap(arg[0], arg[1], atoi(arg[2]));
-}
-
-static int do_create_oat_dir(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
-    /* oat_dir, instruction_set */
-    return create_oat_dir(arg[0], arg[1]);
-}
-
-static int do_rm_package_dir(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
-    /* oat_dir */
-    return rm_package_dir(arg[0]);
-}
-
-static int do_clear_app_profiles(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
-    /* package_name */
-    return clear_app_profiles(arg[0]);
-}
-
-static int do_destroy_app_profiles(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
-    /* package_name */
-    return destroy_app_profiles(arg[0]);
-}
-
-static int do_link_file(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
-    /* relative_path, from_base, to_base */
-    return link_file(arg[0], arg[1], arg[2]);
-}
-
-static int do_move_ab(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
-    // apk_path, instruction_set, oat_dir
-    return move_ab(arg[0], arg[1], arg[2]);
-}
-
-static int do_delete_odex(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
-    // apk_path, instruction_set, oat_dir
-    return delete_odex(arg[0], arg[1], arg[2]) ? 0 : -1;
-}
-
-struct cmdinfo {
-    const char *name;
-    unsigned numargs;
-    int (*func)(char **arg, char reply[REPLY_MAX]);
-};
-
-struct cmdinfo cmds[] = {
-    { "ping",                 0, do_ping },
-
-    { "create_app_data",      7, do_create_app_data },
-    { "restorecon_app_data",  6, do_restorecon_app_data },
-    { "migrate_app_data",     4, do_migrate_app_data },
-    { "clear_app_data",       5, do_clear_app_data },
-    { "destroy_app_data",     5, do_destroy_app_data },
-    { "move_complete_app",    7, do_move_complete_app },
-    { "get_app_size",         6, do_get_app_size },
-    { "get_app_data_inode",   4, do_get_app_data_inode },
-
-    { "create_user_data",     4, do_create_user_data },
-    { "destroy_user_data",    3, do_destroy_user_data },
-
-    { "dexopt",              10, do_dexopt },
-    { "markbootcomplete",     1, do_mark_boot_complete },
-    { "rmdex",                2, do_rm_dex },
-    { "freecache",            2, do_free_cache },
-    { "linklib",              4, do_linklib },
-    { "idmap",                3, do_idmap },
-    { "createoatdir",         2, do_create_oat_dir },
-    { "rmpackagedir",         1, do_rm_package_dir },
-    { "clear_app_profiles",   1, do_clear_app_profiles },
-    { "destroy_app_profiles", 1, do_destroy_app_profiles },
-    { "linkfile",             3, do_link_file },
-    { "move_ab",              3, do_move_ab },
-    { "merge_profiles",       2, do_merge_profiles },
-    { "dump_profiles",        3, do_dump_profiles },
-    { "delete_odex",          3, do_delete_odex },
-};
-
-static int readx(int s, void *_buf, int count)
-{
-    char *buf = (char *) _buf;
-    int n = 0, r;
-    if (count < 0) return -1;
-    while (n < count) {
-        r = read(s, buf + n, count - n);
-        if (r < 0) {
-            if (errno == EINTR) continue;
-            ALOGE("read error: %s\n", strerror(errno));
-            return -1;
-        }
-        if (r == 0) {
-            ALOGE("eof\n");
-            return -1; /* EOF */
-        }
-        n += r;
-    }
-    return 0;
-}
-
-static int writex(int s, const void *_buf, int count)
-{
-    const char *buf = (const char *) _buf;
-    int n = 0, r;
-    if (count < 0) return -1;
-    while (n < count) {
-        r = write(s, buf + n, count - n);
-        if (r < 0) {
-            if (errno == EINTR) continue;
-            ALOGE("write error: %s\n", strerror(errno));
-            return -1;
-        }
-        n += r;
-    }
-    return 0;
-}
-
-
-/* Tokenize the command buffer, locate a matching command,
- * ensure that the required number of arguments are provided,
- * call the function(), return the result.
- */
-static int execute(int s, char cmd[BUFFER_MAX])
-{
-    char reply[REPLY_MAX];
-    char *arg[TOKEN_MAX+1];
-    unsigned i;
-    unsigned n = 0;
-    unsigned short count;
-    int ret = -1;
-
-    // ALOGI("execute('%s')\n", cmd);
-
-        /* default reply is "" */
-    reply[0] = 0;
-
-        /* n is number of args (not counting arg[0]) */
-    arg[0] = cmd;
-    while (*cmd) {
-        if (isspace(*cmd)) {
-            *cmd++ = 0;
-            n++;
-            arg[n] = cmd;
-            if (n == TOKEN_MAX) {
-                ALOGE("too many arguments\n");
-                goto done;
-            }
-        }
-        if (*cmd) {
-          cmd++;
-        }
-    }
-
-    for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) {
-        if (!strcmp(cmds[i].name,arg[0])) {
-            if (n != cmds[i].numargs) {
-                ALOGE("%s requires %d arguments (%d given)\n",
-                     cmds[i].name, cmds[i].numargs, n);
-            } else {
-                ret = cmds[i].func(arg + 1, reply);
-            }
-            goto done;
-        }
-    }
-    ALOGE("unsupported command '%s'\n", arg[0]);
-
-done:
-    if (reply[0]) {
-        n = snprintf(cmd, BUFFER_MAX, "%d %s", ret, reply);
-    } else {
-        n = snprintf(cmd, BUFFER_MAX, "%d", ret);
-    }
-    if (n > BUFFER_MAX) n = BUFFER_MAX;
-    count = n;
-
-    // ALOGI("reply: '%s'\n", cmd);
-    if (writex(s, &count, sizeof(count))) return -1;
-    if (writex(s, cmd, count)) return -1;
-    return 0;
-}
-
 static bool initialize_globals() {
     const char* data_path = getenv("ANDROID_DATA");
     if (data_path == nullptr) {
-        ALOGE("Could not find ANDROID_DATA");
+        SLOGE("Could not find ANDROID_DATA");
         return false;
     }
     const char* root_path = getenv("ANDROID_ROOT");
     if (root_path == nullptr) {
-        ALOGE("Could not find ANDROID_ROOT");
+        SLOGE("Could not find ANDROID_ROOT");
         return false;
     }
 
@@ -597,12 +198,12 @@
     }
 
     if (ensure_config_user_dirs(0) == -1) {
-        ALOGE("Failed to setup misc for user 0");
+        SLOGE("Failed to setup misc for user 0");
         goto fail;
     }
 
     if (version == 2) {
-        ALOGD("Upgrading to /data/misc/user directories");
+        SLOGD("Upgrading to /data/misc/user directories");
 
         char misc_dir[PATH_MAX];
         snprintf(misc_dir, PATH_MAX, "%smisc", android_data_dir.path);
@@ -643,12 +244,12 @@
                 gid_t gid = uid;
                 if (access(keychain_added_dir, F_OK) == 0) {
                     if (copy_dir_files(keychain_added_dir, misc_added_dir, uid, gid) != 0) {
-                        ALOGE("Some files failed to copy");
+                        SLOGE("Some files failed to copy");
                     }
                 }
                 if (access(keychain_removed_dir, F_OK) == 0) {
                     if (copy_dir_files(keychain_removed_dir, misc_removed_dir, uid, gid) != 0) {
-                        ALOGE("Some files failed to copy");
+                        SLOGE("Some files failed to copy");
                     }
                 }
             }
@@ -668,7 +269,7 @@
     // Persist layout version if changed
     if (version != oldVersion) {
         if (fs_write_atomic_int(version_path, version) == -1) {
-            ALOGE("Failed to save version to %s: %s", version_path, strerror(errno));
+            SLOGE("Failed to save version to %s: %s", version_path, strerror(errno));
             goto fail;
         }
     }
@@ -702,80 +303,41 @@
 }
 
 static int installd_main(const int argc ATTRIBUTE_UNUSED, char *argv[]) {
-    char buf[BUFFER_MAX];
-    struct sockaddr addr;
-    socklen_t alen;
-    int lsocket, s;
+    int ret;
     int selinux_enabled = (is_selinux_enabled() > 0);
 
     setenv("ANDROID_LOG_TAGS", "*:v", 1);
     android::base::InitLogging(argv);
 
-    ALOGI("installd firing up\n");
+    SLOGI("installd firing up");
 
     union selinux_callback cb;
     cb.func_log = log_callback;
     selinux_set_callback(SELINUX_CB_LOG, cb);
 
     if (!initialize_globals()) {
-        ALOGE("Could not initialize globals; exiting.\n");
+        SLOGE("Could not initialize globals; exiting.\n");
         exit(1);
     }
 
     if (initialize_directories() < 0) {
-        ALOGE("Could not create directories; exiting.\n");
+        SLOGE("Could not create directories; exiting.\n");
         exit(1);
     }
 
     if (selinux_enabled && selinux_status_open(true) < 0) {
-        ALOGE("Could not open selinux status; exiting.\n");
+        SLOGE("Could not open selinux status; exiting.\n");
         exit(1);
     }
 
-    lsocket = android_get_control_socket(SOCKET_PATH);
-    if (lsocket < 0) {
-        ALOGE("Failed to get socket from environment: %s\n", strerror(errno));
+    if ((ret = InstalldNativeService::start()) != android::OK) {
+        SLOGE("Unable to start InstalldNativeService: %d", ret);
         exit(1);
     }
-    if (listen(lsocket, 5)) {
-        ALOGE("Listen on socket failed: %s\n", strerror(errno));
-        exit(1);
-    }
-    fcntl(lsocket, F_SETFD, FD_CLOEXEC);
 
-    for (;;) {
-        alen = sizeof(addr);
-        s = accept(lsocket, &addr, &alen);
-        if (s < 0) {
-            ALOGE("Accept failed: %s\n", strerror(errno));
-            continue;
-        }
-        fcntl(s, F_SETFD, FD_CLOEXEC);
+    IPCThreadState::self()->joinThreadPool();
 
-        ALOGI("new connection\n");
-        for (;;) {
-            unsigned short count;
-            if (readx(s, &count, sizeof(count))) {
-                ALOGE("failed to read size\n");
-                break;
-            }
-            if ((count < 1) || (count >= BUFFER_MAX)) {
-                ALOGE("invalid size %d\n", count);
-                break;
-            }
-            if (readx(s, buf, count)) {
-                ALOGE("failed to read command\n");
-                break;
-            }
-            buf[count] = 0;
-            if (selinux_enabled && selinux_status_updated() > 0) {
-                selinux_android_seapp_context_reload();
-            }
-            if (execute(s, buf)) break;
-        }
-        ALOGI("closing connection\n");
-        close(s);
-    }
+    LOG(INFO) << "installd shutting down";
 
     return 0;
 }
diff --git a/cmds/installd/installd.rc b/cmds/installd/installd.rc
index 5e4c925..240aa49 100644
--- a/cmds/installd/installd.rc
+++ b/cmds/installd/installd.rc
@@ -1,3 +1,103 @@
+
 service installd /system/bin/installd
     class main
-    socket installd stream 600 system system
+
+on early-boot
+    mkdir /config/sdcardfs/extensions/1055
+    mkdir /config/sdcardfs/extensions/1056
+    mkdir /config/sdcardfs/extensions/1057
+    mkdir /config/sdcardfs/extensions/1056/3gpp
+    mkdir /config/sdcardfs/extensions/1056/3gp
+    mkdir /config/sdcardfs/extensions/1056/3gpp2
+    mkdir /config/sdcardfs/extensions/1056/3g2
+    mkdir /config/sdcardfs/extensions/1056/avi
+    mkdir /config/sdcardfs/extensions/1056/dl
+    mkdir /config/sdcardfs/extensions/1056/dif
+    mkdir /config/sdcardfs/extensions/1056/dv
+    mkdir /config/sdcardfs/extensions/1056/fli
+    mkdir /config/sdcardfs/extensions/1056/m4v
+    mkdir /config/sdcardfs/extensions/1056/ts
+    mkdir /config/sdcardfs/extensions/1056/mpeg
+    mkdir /config/sdcardfs/extensions/1056/mpg
+    mkdir /config/sdcardfs/extensions/1056/mpe
+    mkdir /config/sdcardfs/extensions/1056/mp4
+    mkdir /config/sdcardfs/extensions/1056/vob
+    mkdir /config/sdcardfs/extensions/1056/qt
+    mkdir /config/sdcardfs/extensions/1056/mov
+    mkdir /config/sdcardfs/extensions/1056/mxu
+    mkdir /config/sdcardfs/extensions/1056/webm
+    mkdir /config/sdcardfs/extensions/1056/lsf
+    mkdir /config/sdcardfs/extensions/1056/lsx
+    mkdir /config/sdcardfs/extensions/1056/mkv
+    mkdir /config/sdcardfs/extensions/1056/mng
+    mkdir /config/sdcardfs/extensions/1056/asf
+    mkdir /config/sdcardfs/extensions/1056/asx
+    mkdir /config/sdcardfs/extensions/1056/wm
+    mkdir /config/sdcardfs/extensions/1056/wmv
+    mkdir /config/sdcardfs/extensions/1056/wmx
+    mkdir /config/sdcardfs/extensions/1056/wvx
+    mkdir /config/sdcardfs/extensions/1056/movie
+    mkdir /config/sdcardfs/extensions/1056/wrf
+    mkdir /config/sdcardfs/extensions/1057/bmp
+    mkdir /config/sdcardfs/extensions/1057/gif
+    mkdir /config/sdcardfs/extensions/1057/jpg
+    mkdir /config/sdcardfs/extensions/1057/jpeg
+    mkdir /config/sdcardfs/extensions/1057/jpe
+    mkdir /config/sdcardfs/extensions/1057/pcx
+    mkdir /config/sdcardfs/extensions/1057/png
+    mkdir /config/sdcardfs/extensions/1057/svg
+    mkdir /config/sdcardfs/extensions/1057/svgz
+    mkdir /config/sdcardfs/extensions/1057/tiff
+    mkdir /config/sdcardfs/extensions/1057/tif
+    mkdir /config/sdcardfs/extensions/1057/wbmp
+    mkdir /config/sdcardfs/extensions/1057/webp
+    mkdir /config/sdcardfs/extensions/1057/dng
+    mkdir /config/sdcardfs/extensions/1057/cr2
+    mkdir /config/sdcardfs/extensions/1057/ras
+    mkdir /config/sdcardfs/extensions/1057/art
+    mkdir /config/sdcardfs/extensions/1057/jng
+    mkdir /config/sdcardfs/extensions/1057/nef
+    mkdir /config/sdcardfs/extensions/1057/nrw
+    mkdir /config/sdcardfs/extensions/1057/orf
+    mkdir /config/sdcardfs/extensions/1057/rw2
+    mkdir /config/sdcardfs/extensions/1057/pef
+    mkdir /config/sdcardfs/extensions/1057/psd
+    mkdir /config/sdcardfs/extensions/1057/pnm
+    mkdir /config/sdcardfs/extensions/1057/pbm
+    mkdir /config/sdcardfs/extensions/1057/pgm
+    mkdir /config/sdcardfs/extensions/1057/ppm
+    mkdir /config/sdcardfs/extensions/1057/srw
+    mkdir /config/sdcardfs/extensions/1057/arw
+    mkdir /config/sdcardfs/extensions/1057/rgb
+    mkdir /config/sdcardfs/extensions/1057/xbm
+    mkdir /config/sdcardfs/extensions/1057/xpm
+    mkdir /config/sdcardfs/extensions/1057/xwd
+    mkdir /config/sdcardfs/extensions/1055/aac
+    mkdir /config/sdcardfs/extensions/1055/aac
+    mkdir /config/sdcardfs/extensions/1055/amr
+    mkdir /config/sdcardfs/extensions/1055/awb
+    mkdir /config/sdcardfs/extensions/1055/snd
+    mkdir /config/sdcardfs/extensions/1055/flac
+    mkdir /config/sdcardfs/extensions/1055/flac
+    mkdir /config/sdcardfs/extensions/1055/mp3
+    mkdir /config/sdcardfs/extensions/1055/mpga
+    mkdir /config/sdcardfs/extensions/1055/mpega
+    mkdir /config/sdcardfs/extensions/1055/mp2
+    mkdir /config/sdcardfs/extensions/1055/m4a
+    mkdir /config/sdcardfs/extensions/1055/aif
+    mkdir /config/sdcardfs/extensions/1055/aiff
+    mkdir /config/sdcardfs/extensions/1055/aifc
+    mkdir /config/sdcardfs/extensions/1055/gsm
+    mkdir /config/sdcardfs/extensions/1055/mka
+    mkdir /config/sdcardfs/extensions/1055/m3u
+    mkdir /config/sdcardfs/extensions/1055/wma
+    mkdir /config/sdcardfs/extensions/1055/wax
+    mkdir /config/sdcardfs/extensions/1055/ra
+    mkdir /config/sdcardfs/extensions/1055/rm
+    mkdir /config/sdcardfs/extensions/1055/ram
+    mkdir /config/sdcardfs/extensions/1055/ra
+    mkdir /config/sdcardfs/extensions/1055/pls
+    mkdir /config/sdcardfs/extensions/1055/sd2
+    mkdir /config/sdcardfs/extensions/1055/wav
+    mkdir /config/sdcardfs/extensions/1055/ogg
+    mkdir /config/sdcardfs/extensions/1055/oga
diff --git a/cmds/installd/installd_constants.h b/cmds/installd/installd_constants.h
index 41732cc..6a81cfc 100644
--- a/cmds/installd/installd_constants.h
+++ b/cmds/installd/installd_constants.h
@@ -28,8 +28,7 @@
 
 // This is used as a string literal, can't be constants. TODO: std::string...
 #define DALVIK_CACHE "dalvik-cache"
-constexpr const char* DALVIK_CACHE_POSTFIX = "/classes.dex";
-constexpr const char* DALVIK_CACHE_POSTFIX2 = "@classes.dex";
+constexpr const char* DALVIK_CACHE_POSTFIX = "@classes.dex";
 
 constexpr size_t PKG_NAME_MAX = 128u;   /* largest allowed package name */
 constexpr size_t PKG_PATH_MAX = 256u;   /* max size of any path we use */
@@ -39,20 +38,32 @@
  * frameworks/base/services/core/java/com/android/server/pm/Installer.java
  ***************************************************************************/
 constexpr int DEXOPT_PUBLIC         = 1 << 1;
-constexpr int DEXOPT_SAFEMODE       = 1 << 2;
-constexpr int DEXOPT_DEBUGGABLE     = 1 << 3;
-constexpr int DEXOPT_BOOTCOMPLETE   = 1 << 4;
-constexpr int DEXOPT_PROFILE_GUIDED = 1 << 5;
-constexpr int DEXOPT_OTA            = 1 << 6;
+constexpr int DEXOPT_DEBUGGABLE     = 1 << 2;
+constexpr int DEXOPT_BOOTCOMPLETE   = 1 << 3;
+constexpr int DEXOPT_PROFILE_GUIDED = 1 << 4;
+constexpr int DEXOPT_SECONDARY_DEX  = 1 << 5;
+// DEXOPT_FORCE, DEXOPT_STORAGE_CE, DEXOPT_STORAGE_DE are exposed for secondary
+// dex files only. Primary apks are analyzed in PackageManager and installd
+// does not need to know if the compilation is forced or on what kind of storage
+// the dex files are.
+constexpr int DEXOPT_FORCE          = 1 << 6;
+constexpr int DEXOPT_STORAGE_CE     = 1 << 7;
+constexpr int DEXOPT_STORAGE_DE     = 1 << 8;
 
 /* all known values for dexopt flags */
 constexpr int DEXOPT_MASK =
     DEXOPT_PUBLIC
-    | DEXOPT_SAFEMODE
     | DEXOPT_DEBUGGABLE
     | DEXOPT_BOOTCOMPLETE
     | DEXOPT_PROFILE_GUIDED
-    | DEXOPT_OTA;
+    | DEXOPT_SECONDARY_DEX
+    | DEXOPT_FORCE
+    | DEXOPT_STORAGE_CE
+    | DEXOPT_STORAGE_DE;
+
+// NOTE: keep in sync with StorageManager
+constexpr int FLAG_STORAGE_DE = 1 << 0;
+constexpr int FLAG_STORAGE_CE = 1 << 1;
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 
diff --git a/cmds/installd/matchgen.py b/cmds/installd/matchgen.py
new file mode 100644
index 0000000..131487d
--- /dev/null
+++ b/cmds/installd/matchgen.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python
+
+# 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.
+
+import collections, sys
+
+TYPES = {
+    "AID_MEDIA_AUDIO": ["aac","aac","amr","awb","snd","flac","flac","mp3","mpga","mpega","mp2","m4a","aif","aiff","aifc","gsm","mka","m3u","wma","wax","ra","rm","ram","ra","pls","sd2","wav","ogg","oga"],
+    "AID_MEDIA_VIDEO": ["3gpp","3gp","3gpp2","3g2","avi","dl","dif","dv","fli","m4v","ts","mpeg","mpg","mpe","mp4","vob","qt","mov","mxu","webm","lsf","lsx","mkv","mng","asf","asx","wm","wmv","wmx","wvx","movie","wrf"],
+    "AID_MEDIA_IMAGE": ["bmp","gif","jpg","jpeg","jpe","pcx","png","svg","svgz","tiff","tif","wbmp","webp","dng","cr2","ras","art","jng","nef","nrw","orf","rw2","pef","psd","pnm","pbm","pgm","ppm","srw","arw","rgb","xbm","xpm","xwd"]
+}
+
+if "--rc" in sys.argv:
+    print "on early-boot"
+    print "    mkdir /config/sdcardfs/extensions/1055"
+    print "    mkdir /config/sdcardfs/extensions/1056"
+    print "    mkdir /config/sdcardfs/extensions/1057"
+    for gid, exts in TYPES.iteritems():
+        if gid is "AID_MEDIA_AUDIO": gid = "1055"
+        if gid is "AID_MEDIA_VIDEO": gid = "1056"
+        if gid is "AID_MEDIA_IMAGE": gid = "1057"
+        for ext in exts:
+            print "    mkdir /config/sdcardfs/extensions/%s/%s" % (gid, ext)
+    exit()
+
+print """/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/******************************************************************
+ * THIS CODE WAS GENERATED BY matchgen.py, DO NOT MODIFY DIRECTLY *
+ ******************************************************************/
+
+#include <private/android_filesystem_config.h>
+
+int MatchExtension(const char* ext) {
+"""
+
+trie = collections.defaultdict(lambda: collections.defaultdict(lambda: collections.defaultdict(lambda: collections.defaultdict(lambda: collections.defaultdict(lambda: collections.defaultdict(lambda: ""))))))
+
+for t in TYPES:
+    for v in TYPES[t]:
+        v = v.lower()
+        target = trie
+        for c in v:
+            target = target[c]
+        target["\0"] = t
+
+def dump(target, index):
+    prefix = "    " * (index + 1)
+    print "%sswitch (ext[%d]) {" % (prefix, index)
+    for k in sorted(target.keys()):
+        if k == "\0":
+            print "%scase '\\0': return %s;" % (prefix, target[k])
+        else:
+            upper = k.upper()
+            if k != upper:
+                print "%scase '%s': case '%s':" % (prefix, k, upper)
+            else:
+                print "%scase '%s':" % (prefix, k)
+            dump(target[k], index + 1)
+    print "%s}" % (prefix)
+
+dump(trie, 0)
+
+print """
+    return 0;
+}
+"""
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 5fa972a..68cb0d7 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -16,6 +16,7 @@
 
 #include <algorithm>
 #include <inttypes.h>
+#include <limits>
 #include <random>
 #include <regex>
 #include <selinux/android.h>
@@ -32,17 +33,19 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <cutils/fs.h>
-#include <cutils/log.h>
 #include <cutils/properties.h>
+#include <dex2oat_return_codes.h>
+#include <log/log.h>
 #include <private/android_filesystem_config.h>
 
-#include <commands.h>
-#include <file_parsing.h>
-#include <globals.h>
-#include <installd_deps.h>  // Need to fill in requirements of commands.
-#include <otapreopt_utils.h>
-#include <system_properties.h>
-#include <utils.h>
+#include "dexopt.h"
+#include "file_parsing.h"
+#include "globals.h"
+#include "installd_constants.h"
+#include "installd_deps.h"  // Need to fill in requirements of commands.
+#include "otapreopt_utils.h"
+#include "system_properties.h"
+#include "utils.h"
 
 #ifndef LOG_TAG
 #define LOG_TAG "otapreopt"
@@ -61,6 +64,25 @@
 namespace android {
 namespace installd {
 
+// Check expected values for dexopt flags. If you need to change this:
+//
+//   RUN AN A/B OTA TO MAKE SURE THINGS STILL WORK!
+//
+// You most likely need to increase the protocol version and all that entails!
+
+static_assert(DEXOPT_PUBLIC         == 1 << 1, "DEXOPT_PUBLIC unexpected.");
+static_assert(DEXOPT_DEBUGGABLE     == 1 << 2, "DEXOPT_DEBUGGABLE unexpected.");
+static_assert(DEXOPT_BOOTCOMPLETE   == 1 << 3, "DEXOPT_BOOTCOMPLETE unexpected.");
+static_assert(DEXOPT_PROFILE_GUIDED == 1 << 4, "DEXOPT_PROFILE_GUIDED unexpected.");
+static_assert(DEXOPT_SECONDARY_DEX  == 1 << 5, "DEXOPT_SECONDARY_DEX unexpected.");
+static_assert(DEXOPT_FORCE          == 1 << 6, "DEXOPT_FORCE unexpected.");
+static_assert(DEXOPT_STORAGE_CE     == 1 << 7, "DEXOPT_STORAGE_CE unexpected.");
+static_assert(DEXOPT_STORAGE_DE     == 1 << 8, "DEXOPT_STORAGE_DE unexpected.");
+
+static_assert(DEXOPT_MASK           == 0x1fe, "DEXOPT_MASK unexpected.");
+
+
+
 template<typename T>
 static constexpr T RoundDown(T x, typename std::decay<T>::type n) {
     return DCHECK_CONSTEXPR(IsPowerOfTwo(n), , T(0))(x & -n);
@@ -144,6 +166,20 @@
 
 private:
 
+    struct Parameters {
+        const char *apk_path;
+        uid_t uid;
+        const char *pkgName;
+        const char *instruction_set;
+        int dexopt_needed;
+        const char* oat_dir;
+        int dexopt_flags;
+        const char* compiler_filter;
+        const char* volume_uuid;
+        const char* shared_libraries;
+        const char* se_info;
+    };
+
     bool ReadSystemProperties() {
         static constexpr const char* kPropertyFiles[] = {
                 "/default.prop", "/system/build.prop"
@@ -245,15 +281,23 @@
         return true;
     }
 
-    bool ReadArguments(int argc ATTRIBUTE_UNUSED, char** argv) {
-        // Expected command line:
-        //   target-slot dexopt {DEXOPT_PARAMETERS}
-        // The DEXOPT_PARAMETERS are passed on to dexopt(), so we expect DEXOPT_PARAM_COUNT
-        // of them. We store them in package_parameters_ (size checks are done when
-        // parsing the special parameters and when copying into package_parameters_.
+    bool ParseUInt(const char* in, uint32_t* out) {
+        char* end;
+        long long int result = strtoll(in, &end, 0);
+        if (in == end || *end != '\0') {
+            return false;
+        }
+        if (result < std::numeric_limits<uint32_t>::min() ||
+                std::numeric_limits<uint32_t>::max() < result) {
+            return false;
+        }
+        *out = static_cast<uint32_t>(result);
+        return true;
+    }
 
-        static_assert(DEXOPT_PARAM_COUNT == ARRAY_SIZE(package_parameters_),
-                      "Unexpected dexopt param count");
+    bool ReadArguments(int argc, char** argv) {
+        // Expected command line:
+        //   target-slot [version] dexopt {DEXOPT_PARAMETERS}
 
         const char* target_slot_arg = argv[1];
         if (target_slot_arg == nullptr) {
@@ -267,28 +311,229 @@
             return false;
         }
 
-        // Check for "dexopt" next.
+        // Check for version or "dexopt" next.
+        if (argv[2] == nullptr) {
+            LOG(ERROR) << "Missing parameters";
+            return false;
+        }
+
+        if (std::string("dexopt").compare(argv[2]) == 0) {
+            // This is version 1 (N) or pre-versioning version 2.
+            constexpr int kV2ArgCount =   1   // "otapreopt"
+                                        + 1   // slot
+                                        + 1   // "dexopt"
+                                        + 1   // apk_path
+                                        + 1   // uid
+                                        + 1   // pkg
+                                        + 1   // isa
+                                        + 1   // dexopt_needed
+                                        + 1   // oat_dir
+                                        + 1   // dexopt_flags
+                                        + 1   // filter
+                                        + 1   // volume
+                                        + 1   // libs
+                                        + 1;  // seinfo
+            if (argc == kV2ArgCount) {
+                return ReadArgumentsV2(argc, argv, false);
+            } else {
+                return ReadArgumentsV1(argc, argv);
+            }
+        }
+
+        uint32_t version;
+        if (!ParseUInt(argv[2], &version)) {
+            LOG(ERROR) << "Could not parse version: " << argv[2];
+            return false;
+        }
+
+        switch (version) {
+            case 2:
+                return ReadArgumentsV2(argc, argv, true);
+
+            default:
+                LOG(ERROR) << "Unsupported version " << version;
+                return false;
+        }
+    }
+
+    bool ReadArgumentsV2(int argc ATTRIBUTE_UNUSED, char** argv, bool versioned) {
+        size_t dexopt_index = versioned ? 3 : 2;
+
+        // Check for "dexopt".
+        if (argv[dexopt_index] == nullptr) {
+            LOG(ERROR) << "Missing parameters";
+            return false;
+        }
+        if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
+            LOG(ERROR) << "Expected \"dexopt\"";
+            return false;
+        }
+
+        size_t param_index = 0;
+        for (;; ++param_index) {
+            const char* param = argv[dexopt_index + 1 + param_index];
+            if (param == nullptr) {
+                break;
+            }
+
+            switch (param_index) {
+                case 0:
+                    package_parameters_.apk_path = param;
+                    break;
+
+                case 1:
+                    package_parameters_.uid = atoi(param);
+                    break;
+
+                case 2:
+                    package_parameters_.pkgName = param;
+                    break;
+
+                case 3:
+                    package_parameters_.instruction_set = param;
+                    break;
+
+                case 4:
+                    package_parameters_.dexopt_needed = atoi(param);
+                    break;
+
+                case 5:
+                    package_parameters_.oat_dir = param;
+                    break;
+
+                case 6:
+                    package_parameters_.dexopt_flags = atoi(param);
+                    break;
+
+                case 7:
+                    package_parameters_.compiler_filter = param;
+                    break;
+
+                case 8:
+                    package_parameters_.volume_uuid = ParseNull(param);
+                    break;
+
+                case 9:
+                    package_parameters_.shared_libraries = ParseNull(param);
+                    break;
+
+                case 10:
+                    package_parameters_.se_info = ParseNull(param);
+                    break;
+
+                default:
+                    LOG(ERROR) << "Too many arguments, got " << param;
+                    return false;
+            }
+        }
+
+        if (param_index != 11) {
+            LOG(ERROR) << "Not enough parameters";
+            return false;
+        }
+
+        return true;
+    }
+
+    static int ReplaceMask(int input, int old_mask, int new_mask) {
+        return (input & old_mask) != 0 ? new_mask : 0;
+    }
+
+    bool ReadArgumentsV1(int argc ATTRIBUTE_UNUSED, char** argv) {
+        // Check for "dexopt".
         if (argv[2] == nullptr) {
             LOG(ERROR) << "Missing parameters";
             return false;
         }
         if (std::string("dexopt").compare(argv[2]) != 0) {
-            LOG(ERROR) << "Second parameter not dexopt: " << argv[2];
+            LOG(ERROR) << "Expected \"dexopt\"";
             return false;
         }
 
-        // Copy the rest into package_parameters_, but be careful about over- and underflow.
-        size_t index = 0;
-        while (index < DEXOPT_PARAM_COUNT &&
-                argv[index + 3] != nullptr) {
-            package_parameters_[index] = argv[index + 3];
-            index++;
+        size_t param_index = 0;
+        for (;; ++param_index) {
+            const char* param = argv[3 + param_index];
+            if (param == nullptr) {
+                break;
+            }
+
+            switch (param_index) {
+                case 0:
+                    package_parameters_.apk_path = param;
+                    break;
+
+                case 1:
+                    package_parameters_.uid = atoi(param);
+                    break;
+
+                case 2:
+                    package_parameters_.pkgName = param;
+                    break;
+
+                case 3:
+                    package_parameters_.instruction_set = param;
+                    break;
+
+                case 4: {
+                    // Version 1 had:
+                    //   DEXOPT_DEX2OAT_NEEDED       = 1
+                    //   DEXOPT_PATCHOAT_NEEDED      = 2
+                    //   DEXOPT_SELF_PATCHOAT_NEEDED = 3
+                    // We will simply use DEX2OAT_FROM_SCRATCH.
+                    package_parameters_.dexopt_needed = DEX2OAT_FROM_SCRATCH;
+                    break;
+                }
+
+                case 5:
+                    package_parameters_.oat_dir = param;
+                    break;
+
+                case 6: {
+                    // Version 1 had:
+                    constexpr int OLD_DEXOPT_PUBLIC         = 1 << 1;
+                    // Note: DEXOPT_SAFEMODE has been removed.
+                    // constexpr int OLD_DEXOPT_SAFEMODE       = 1 << 2;
+                    constexpr int OLD_DEXOPT_DEBUGGABLE     = 1 << 3;
+                    constexpr int OLD_DEXOPT_BOOTCOMPLETE   = 1 << 4;
+                    constexpr int OLD_DEXOPT_PROFILE_GUIDED = 1 << 5;
+                    constexpr int OLD_DEXOPT_OTA            = 1 << 6;
+                    int input = atoi(param);
+                    package_parameters_.dexopt_flags =
+                            ReplaceMask(input, OLD_DEXOPT_PUBLIC, DEXOPT_PUBLIC) |
+                            ReplaceMask(input, OLD_DEXOPT_DEBUGGABLE, DEXOPT_DEBUGGABLE) |
+                            ReplaceMask(input, OLD_DEXOPT_BOOTCOMPLETE, DEXOPT_BOOTCOMPLETE) |
+                            ReplaceMask(input, OLD_DEXOPT_PROFILE_GUIDED, DEXOPT_PROFILE_GUIDED) |
+                            ReplaceMask(input, OLD_DEXOPT_OTA, 0);
+                    break;
+                }
+
+                case 7:
+                    package_parameters_.compiler_filter = param;
+                    break;
+
+                case 8:
+                    package_parameters_.volume_uuid = ParseNull(param);
+                    break;
+
+                case 9:
+                    package_parameters_.shared_libraries = ParseNull(param);
+                    break;
+
+                default:
+                    LOG(ERROR) << "Too many arguments, got " << param;
+                    return false;
+            }
         }
-        if (index != ARRAY_SIZE(package_parameters_) || argv[index + 3] != nullptr) {
-            LOG(ERROR) << "Wrong number of parameters";
+
+        if (param_index != 10) {
+            LOG(ERROR) << "Not enough parameters";
             return false;
         }
 
+        // Set se_info to null. It is only relevant for secondary dex files, which we won't
+        // receive from a v1 A side.
+        package_parameters_.se_info = nullptr;
+
         return true;
     }
 
@@ -305,11 +550,11 @@
     // Ensure that we have the right boot image. The first time any app is
     // compiled, we'll try to generate it.
     bool PrepareBootImage(bool force) const {
-        if (package_parameters_[kISAIndex] == nullptr) {
+        if (package_parameters_.instruction_set == nullptr) {
             LOG(ERROR) << "Instruction set missing.";
             return false;
         }
-        const char* isa = package_parameters_[kISAIndex];
+        const char* isa = package_parameters_.instruction_set;
 
         // Check whether the file exists where expected.
         std::string dalvik_cache = GetOTADataDirectory() + "/" + DALVIK_CACHE;
@@ -508,6 +753,10 @@
     }
 
     static const char* ParseNull(const char* arg) {
+        // b/38186355. Revert soon.
+        if (strcmp(arg, "!null") == 0) {
+            return nullptr;
+        }
         return (strcmp(arg, "!") == 0) ? nullptr : arg;
     }
 
@@ -535,14 +784,12 @@
         //       (This is ugly as it's the only thing where we need to understand the contents
         //        of package_parameters_, but it beats postponing the decision or using the call-
         //        backs to do weird things.)
-        constexpr size_t kApkPathIndex = 0;
-        CHECK_GT(DEXOPT_PARAM_COUNT, kApkPathIndex);
-        CHECK(package_parameters_[kApkPathIndex] != nullptr);
-        if (StartsWith(package_parameters_[kApkPathIndex], android_root_.c_str())) {
-            const char* last_slash = strrchr(package_parameters_[kApkPathIndex], '/');
+        const char* apk_path = package_parameters_.apk_path;
+        CHECK(apk_path != nullptr);
+        if (StartsWith(apk_path, android_root_.c_str())) {
+            const char* last_slash = strrchr(apk_path, '/');
             if (last_slash != nullptr) {
-                std::string path(package_parameters_[kApkPathIndex],
-                                 last_slash - package_parameters_[kApkPathIndex] + 1);
+                std::string path(apk_path, last_slash - apk_path + 1);
                 CHECK(EndsWith(path, "/"));
                 path = path + "oat";
                 if (access(path.c_str(), F_OK) == 0) {
@@ -556,36 +803,64 @@
         // partition will not be available and fail to build. This is problematic, as
         // this tool will wipe the OTA artifact cache and try again (for robustness after
         // a failed OTA with remaining cache artifacts).
-        if (access(package_parameters_[kApkPathIndex], F_OK) != 0) {
-            LOG(WARNING) << "Skipping preopt of non-existing package "
-                         << package_parameters_[kApkPathIndex];
+        if (access(apk_path, F_OK) != 0) {
+            LOG(WARNING) << "Skipping preopt of non-existing package " << apk_path;
             return true;
         }
 
         return false;
     }
 
+    // Run dexopt with the parameters of package_parameters_.
+    int Dexopt() {
+        return dexopt(package_parameters_.apk_path,
+                      package_parameters_.uid,
+                      package_parameters_.pkgName,
+                      package_parameters_.instruction_set,
+                      package_parameters_.dexopt_needed,
+                      package_parameters_.oat_dir,
+                      package_parameters_.dexopt_flags,
+                      package_parameters_.compiler_filter,
+                      package_parameters_.volume_uuid,
+                      package_parameters_.shared_libraries,
+                      package_parameters_.se_info);
+    }
+
     int RunPreopt() {
         if (ShouldSkipPreopt()) {
             return 0;
         }
 
-        int dexopt_result = dexopt(package_parameters_);
+        int dexopt_result = Dexopt();
         if (dexopt_result == 0) {
             return 0;
         }
 
         // If the dexopt failed, we may have a stale boot image from a previous OTA run.
-        // Try to delete and retry.
+        // Then regenerate and retry.
+        if (WEXITSTATUS(dexopt_result) ==
+                static_cast<int>(art::dex2oat::ReturnCode::kCreateRuntime)) {
+            if (!PrepareBootImage(/* force */ true)) {
+                LOG(ERROR) << "Forced boot image creating failed. Original error return was "
+                        << dexopt_result;
+                return dexopt_result;
+            }
 
-        if (!PrepareBootImage(/* force */ true)) {
-            LOG(ERROR) << "Forced boot image creating failed. Original error return was "
-                         << dexopt_result;
+            int dexopt_result_boot_image_retry = Dexopt();
+            if (dexopt_result_boot_image_retry == 0) {
+                return 0;
+            }
+        }
+
+        // If this was a profile-guided run, we may have profile version issues. Try to downgrade,
+        // if possible.
+        if ((package_parameters_.dexopt_flags & DEXOPT_PROFILE_GUIDED) == 0) {
             return dexopt_result;
         }
 
-        LOG(WARNING) << "Original dexopt failed, re-trying after boot image was regenerated.";
-        return dexopt(package_parameters_);
+        LOG(WARNING) << "Downgrading compiler filter in an attempt to progress compilation";
+        package_parameters_.dexopt_flags &= ~DEXOPT_PROFILE_GUIDED;
+        return Dexopt();
     }
 
     ////////////////////////////////////
@@ -715,7 +990,7 @@
     std::string boot_classpath_;
     std::string asec_mountpoint_;
 
-    const char* package_parameters_[DEXOPT_PARAM_COUNT];
+    Parameters package_parameters_;
 
     // Store environment values we need to set.
     std::vector<std::string> environ_;
@@ -823,7 +1098,7 @@
                                               DALVIK_CACHE,
                                               instruction_set,
                                               from_src.c_str(),
-                                              DALVIK_CACHE_POSTFIX2);
+                                              DALVIK_CACHE_POSTFIX);
 
     if (assembled_path.length() + 1 > PKG_PATH_MAX) {
         return false;
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index 5ea89e6..2030997 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -25,8 +25,8 @@
 #include <android-base/macros.h>
 #include <android-base/stringprintf.h>
 
-#include <commands.h>
-#include <otapreopt_utils.h>
+#include "installd_constants.h"
+#include "otapreopt_utils.h"
 
 #ifndef LOG_TAG
 #define LOG_TAG "otapreopt"
@@ -136,44 +136,18 @@
 
     // Now go on and run otapreopt.
 
-    // Incoming:  cmd + status-fd + target-slot + "dexopt" + dexopt-params + null
-    // Outgoing:  cmd             + target-slot + "dexopt" + dexopt-params + null
-    constexpr size_t kInArguments =   1                       // Binary name.
-                                    + 1                       // status file descriptor.
-                                    + 1                       // target-slot.
-                                    + 1                       // "dexopt."
-                                    + DEXOPT_PARAM_COUNT      // dexopt parameters.
-                                    + 1;                      // null termination.
-    constexpr size_t kOutArguments =   1                       // Binary name.
-                                     + 1                       // target-slot.
-                                     + 1                       // "dexopt."
-                                     + DEXOPT_PARAM_COUNT      // dexopt parameters.
-                                     + 1;                      // null termination.
-    const char* argv[kOutArguments];
-    if (static_cast<size_t>(argc) !=  kInArguments - 1 /* null termination */) {
-        LOG(ERROR) << "Unexpected argument size "
-                   << argc
-                   << " vs "
-                   << (kInArguments - 1);
-        for (size_t i = 0; i < static_cast<size_t>(argc); ++i) {
-            if (arg[i] == nullptr) {
-                LOG(ERROR) << "(null)";
-            } else {
-                LOG(ERROR) << "\"" << arg[i] << "\"";
-            }
-        }
-        exit(206);
-    }
+    // 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";
 
     // The first parameter is the status file descriptor, skip.
-
-    for (size_t i = 1; i <= kOutArguments - 2 /* cmd + null */; ++i) {
-        argv[i] = arg[i + 1];
+    for (size_t i = 2; i <= static_cast<size_t>(argc); ++i) {
+        argv[i - 1] = arg[i];
     }
-    argv[kOutArguments - 1] = nullptr;
 
-    execv(argv[0], (char * const *)argv);
+    execv(argv[0], static_cast<char * const *>(const_cast<char**>(argv)));
     PLOG(ERROR) << "execv(OTAPREOPT) failed.";
     exit(99);
 }
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
new file mode 100644
index 0000000..630c1f3
--- /dev/null
+++ b/cmds/installd/tests/Android.bp
@@ -0,0 +1,54 @@
+// Build the unit tests for installd
+cc_test {
+    name: "installd_utils_test",
+    clang: true,
+    srcs: ["installd_utils_test.cpp"],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libutils",
+        "libcutils",
+    ],
+    static_libs: [
+        "libinstalld",
+        "libdiskusage",
+    ],
+}
+
+cc_test {
+    name: "installd_cache_test",
+    clang: true,
+    srcs: ["installd_cache_test.cpp"],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "liblog",
+        "liblogwrap",
+        "libselinux",
+        "libutils",
+    ],
+    static_libs: [
+        "libinstalld",
+        "libdiskusage",
+    ],
+}
+
+cc_test {
+    name: "installd_service_test",
+    clang: true,
+    srcs: ["installd_service_test.cpp"],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "liblog",
+        "liblogwrap",
+        "libselinux",
+        "libutils",
+    ],
+    static_libs: [
+        "libinstalld",
+        "libdiskusage",
+    ],
+}
diff --git a/cmds/installd/tests/Android.mk b/cmds/installd/tests/Android.mk
deleted file mode 100644
index 38a9f69..0000000
--- a/cmds/installd/tests/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Build the unit tests for installd
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-# Build the unit tests.
-test_src_files := \
-    installd_utils_test.cpp
-
-shared_libraries := \
-    libbase \
-    libutils \
-    libcutils \
-
-static_libraries := \
-    libinstalld \
-    libdiskusage \
-
-c_includes := \
-    frameworks/native/cmds/installd
-
-$(foreach file,$(test_src_files), \
-    $(eval include $(CLEAR_VARS)) \
-    $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
-    $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
-    $(eval LOCAL_SRC_FILES := $(file)) \
-    $(eval LOCAL_C_INCLUDES := $(c_includes)) \
-    $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
-    $(eval LOCAL_CLANG := true) \
-    $(eval include $(BUILD_NATIVE_TEST)) \
-)
diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp
new file mode 100644
index 0000000..aed068c
--- /dev/null
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/statvfs.h>
+#include <sys/xattr.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <cutils/properties.h>
+#include <gtest/gtest.h>
+
+#include "InstalldNativeService.h"
+#include "globals.h"
+#include "utils.h"
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+constexpr const char* kTestUuid = "TEST";
+
+constexpr int64_t kKbInBytes = 1024;
+constexpr int64_t kMbInBytes = 1024 * kKbInBytes;
+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;
+
+int get_property(const char *key, char *value, const char *default_value) {
+    return property_get(key, value, default_value);
+}
+
+bool calculate_oat_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
+        const char *oat_dir ATTRIBUTE_UNUSED,
+        const char *apk_path ATTRIBUTE_UNUSED,
+        const char *instruction_set ATTRIBUTE_UNUSED) {
+    return false;
+}
+
+bool calculate_odex_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
+        const char *apk_path ATTRIBUTE_UNUSED,
+        const char *instruction_set ATTRIBUTE_UNUSED) {
+    return false;
+}
+
+bool create_cache_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
+        const char *src ATTRIBUTE_UNUSED,
+        const char *instruction_set ATTRIBUTE_UNUSED) {
+    return false;
+}
+
+static void mkdir(const char* path) {
+    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
+    ::mkdir(fullPath, 0755);
+}
+
+static void touch(const char* path, int len, int time) {
+    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
+    int fd = ::open(fullPath, O_RDWR | O_CREAT, 0644);
+    ::fallocate(fd, 0, 0, len);
+    ::close(fd);
+    struct utimbuf times;
+    times.actime = times.modtime = std::time(0) + time;
+    ::utime(fullPath, &times);
+}
+
+static int exists(const char* path) {
+    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
+    return ::access(fullPath, F_OK);
+}
+
+static int64_t size(const char* path) {
+    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
+    struct stat buf;
+    if (!stat(fullPath, &buf)) {
+        return buf.st_size;
+    } else {
+        return -1;
+    }
+}
+
+static int64_t free() {
+    struct statvfs buf;
+    if (!statvfs("/data/local/tmp", &buf)) {
+        return buf.f_bavail * buf.f_frsize;
+    } else {
+        PLOG(ERROR) << "Failed to statvfs";
+        return -1;
+    }
+}
+
+static void setxattr(const char* path, const char* key) {
+    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
+    ::setxattr(fullPath, key, "", 0, 0);
+}
+
+class CacheTest : public testing::Test {
+protected:
+    InstalldNativeService* service;
+    std::unique_ptr<std::string> testUuid;
+
+    virtual void SetUp() {
+        setenv("ANDROID_LOG_TAGS", "*:v", 1);
+        android::base::InitLogging(nullptr);
+
+        service = new InstalldNativeService();
+        testUuid = std::make_unique<std::string>();
+        *testUuid = std::string(kTestUuid);
+        system("mkdir -p /data/local/tmp/user/0");
+    }
+
+    virtual void TearDown() {
+        delete service;
+        system("rm -rf /data/local/tmp/user");
+    }
+};
+
+TEST_F(CacheTest, FreeCache_All) {
+    LOG(INFO) << "FreeCache_All";
+
+    mkdir("com.example");
+    touch("com.example/normal", 1 * kMbInBytes, 60);
+    mkdir("com.example/cache");
+    mkdir("com.example/cache/foo");
+    touch("com.example/cache/foo/one", 1 * kMbInBytes, 60);
+    touch("com.example/cache/foo/two", 2 * kMbInBytes, 120);
+
+    EXPECT_EQ(0, exists("com.example/normal"));
+    EXPECT_EQ(0, exists("com.example/cache/foo/one"));
+    EXPECT_EQ(0, exists("com.example/cache/foo/two"));
+
+    service->freeCache(testUuid, kTbInBytes, 0,
+            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+    EXPECT_EQ(0, exists("com.example/normal"));
+    EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
+    EXPECT_EQ(-1, exists("com.example/cache/foo/two"));
+}
+
+TEST_F(CacheTest, FreeCache_Age) {
+    LOG(INFO) << "FreeCache_Age";
+
+    mkdir("com.example");
+    mkdir("com.example/cache");
+    mkdir("com.example/cache/foo");
+    touch("com.example/cache/foo/one", kMbInBytes, 60);
+    touch("com.example/cache/foo/two", kMbInBytes, 120);
+
+    service->freeCache(testUuid, free() + kKbInBytes, 0,
+            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+    EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
+    EXPECT_EQ(0, exists("com.example/cache/foo/two"));
+
+    service->freeCache(testUuid, free() + kKbInBytes, 0,
+            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+    EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
+    EXPECT_EQ(-1, exists("com.example/cache/foo/two"));
+}
+
+TEST_F(CacheTest, FreeCache_Tombstone) {
+    LOG(INFO) << "FreeCache_Tombstone";
+
+    mkdir("com.example");
+    mkdir("com.example/cache");
+    mkdir("com.example/cache/foo");
+    touch("com.example/cache/foo/foo1", 1 * kMbInBytes, 60);
+    touch("com.example/cache/foo/foo2", 1 * kMbInBytes, 60);
+    mkdir("com.example/cache/bar");
+    touch("com.example/cache/bar/bar1", 2 * kMbInBytes, 120);
+    touch("com.example/cache/bar/bar2", 2 * kMbInBytes, 120);
+
+    setxattr("com.example/cache/bar", "user.cache_tombstone");
+
+    EXPECT_EQ(0, exists("com.example/cache/foo/foo1"));
+    EXPECT_EQ(0, exists("com.example/cache/foo/foo2"));
+    EXPECT_EQ(0, exists("com.example/cache/bar/bar1"));
+    EXPECT_EQ(0, exists("com.example/cache/bar/bar2"));
+    EXPECT_EQ(2 * kMbInBytes, size("com.example/cache/bar/bar1"));
+    EXPECT_EQ(2 * kMbInBytes, size("com.example/cache/bar/bar2"));
+
+    service->freeCache(testUuid, kTbInBytes, 0,
+            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+    EXPECT_EQ(-1, exists("com.example/cache/foo/foo1"));
+    EXPECT_EQ(-1, exists("com.example/cache/foo/foo2"));
+    EXPECT_EQ(0, exists("com.example/cache/bar/bar1"));
+    EXPECT_EQ(0, exists("com.example/cache/bar/bar2"));
+    EXPECT_EQ(0, size("com.example/cache/bar/bar1"));
+    EXPECT_EQ(0, size("com.example/cache/bar/bar2"));
+}
+
+TEST_F(CacheTest, FreeCache_Group) {
+    LOG(INFO) << "FreeCache_Group";
+
+    mkdir("com.example");
+    mkdir("com.example/cache");
+    mkdir("com.example/cache/foo");
+    touch("com.example/cache/foo/foo1", 1 * kMbInBytes, 60);
+    touch("com.example/cache/foo/foo2", 1 * kMbInBytes, 120);
+
+    setxattr("com.example/cache/foo", "user.cache_group");
+
+    service->freeCache(testUuid, free() + kKbInBytes, 0,
+            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+    EXPECT_EQ(-1, exists("com.example/cache/foo/foo1"));
+    EXPECT_EQ(-1, exists("com.example/cache/foo/foo2"));
+}
+
+TEST_F(CacheTest, FreeCache_GroupTombstone) {
+    LOG(INFO) << "FreeCache_GroupTombstone";
+
+    mkdir("com.example");
+    mkdir("com.example/cache");
+
+    // this dir must look really old for some reason?
+    mkdir("com.example/cache/group");
+    touch("com.example/cache/group/file1", kMbInBytes, 120);
+    touch("com.example/cache/group/file2", kMbInBytes, 120);
+    mkdir("com.example/cache/group/dir");
+    touch("com.example/cache/group/dir/file1", kMbInBytes, 120);
+    touch("com.example/cache/group/dir/file2", kMbInBytes, 120);
+    mkdir("com.example/cache/group/tomb");
+    touch("com.example/cache/group/tomb/file1", kMbInBytes, 120);
+    touch("com.example/cache/group/tomb/file2", kMbInBytes, 120);
+    mkdir("com.example/cache/group/tomb/dir");
+    touch("com.example/cache/group/tomb/dir/file1", kMbInBytes, 120);
+    touch("com.example/cache/group/tomb/dir/file2", kMbInBytes, 120);
+
+    mkdir("com.example/cache/tomb");
+    touch("com.example/cache/tomb/file1", kMbInBytes, 240);
+    touch("com.example/cache/tomb/file2", kMbInBytes, 240);
+    mkdir("com.example/cache/tomb/dir");
+    touch("com.example/cache/tomb/dir/file1", kMbInBytes, 240);
+    touch("com.example/cache/tomb/dir/file2", kMbInBytes, 240);
+    mkdir("com.example/cache/tomb/group");
+    touch("com.example/cache/tomb/group/file1", kMbInBytes, 60);
+    touch("com.example/cache/tomb/group/file2", kMbInBytes, 60);
+    mkdir("com.example/cache/tomb/group/dir");
+    touch("com.example/cache/tomb/group/dir/file1", kMbInBytes, 60);
+    touch("com.example/cache/tomb/group/dir/file2", kMbInBytes, 60);
+
+    setxattr("com.example/cache/group", "user.cache_group");
+    setxattr("com.example/cache/group/tomb", "user.cache_tombstone");
+    setxattr("com.example/cache/tomb", "user.cache_tombstone");
+    setxattr("com.example/cache/tomb/group", "user.cache_group");
+
+    service->freeCache(testUuid, free() + kKbInBytes, 0,
+            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/file2"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/dir/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/dir/file2"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/file2"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/dir/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/dir/file2"));
+
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file2"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2"));
+
+    service->freeCache(testUuid, free() + kKbInBytes, 0,
+            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+    EXPECT_EQ(-1, size("com.example/cache/group/file1"));
+    EXPECT_EQ(-1, size("com.example/cache/group/file2"));
+    EXPECT_EQ(-1, size("com.example/cache/group/dir/file1"));
+    EXPECT_EQ(-1, size("com.example/cache/group/dir/file2"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/file1"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/file2"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file1"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file2"));
+
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file2"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2"));
+
+    service->freeCache(testUuid, kTbInBytes, 0,
+            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+    EXPECT_EQ(-1, size("com.example/cache/group/file1"));
+    EXPECT_EQ(-1, size("com.example/cache/group/file2"));
+    EXPECT_EQ(-1, size("com.example/cache/group/dir/file1"));
+    EXPECT_EQ(-1, size("com.example/cache/group/dir/file2"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/file1"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/file2"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file1"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file2"));
+
+    EXPECT_EQ(0, size("com.example/cache/tomb/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/dir/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/dir/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2"));
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
new file mode 100644
index 0000000..34818f6
--- /dev/null
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/statvfs.h>
+#include <sys/xattr.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <cutils/properties.h>
+#include <gtest/gtest.h>
+
+#include "InstalldNativeService.h"
+#include "globals.h"
+#include "utils.h"
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+constexpr const char* kTestUuid = "TEST";
+
+static constexpr int FLAG_FORCE = 1 << 16;
+
+int get_property(const char *key, char *value, const char *default_value) {
+    return property_get(key, value, default_value);
+}
+
+bool calculate_oat_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
+        const char *oat_dir ATTRIBUTE_UNUSED,
+        const char *apk_path ATTRIBUTE_UNUSED,
+        const char *instruction_set ATTRIBUTE_UNUSED) {
+    return false;
+}
+
+bool calculate_odex_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
+        const char *apk_path ATTRIBUTE_UNUSED,
+        const char *instruction_set ATTRIBUTE_UNUSED) {
+    return false;
+}
+
+bool create_cache_path(char path[PKG_PATH_MAX],
+        const char *src,
+        const char *instruction_set) {
+    // Not really a valid path but it's good enough for testing.
+    sprintf(path,"/data/dalvik-cache/%s/%s", instruction_set, src);
+    return true;
+}
+
+static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) {
+    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
+    ::mkdir(fullPath, mode);
+    ::chown(fullPath, owner, group);
+    ::chmod(fullPath, mode);
+}
+
+static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) {
+    int fd = ::open(StringPrintf("/data/local/tmp/user/0/%s", path).c_str(),
+            O_RDWR | O_CREAT, mode);
+    ::fchown(fd, owner, group);
+    ::fchmod(fd, mode);
+    ::close(fd);
+}
+
+static int stat_gid(const char* path) {
+    struct stat buf;
+    ::stat(StringPrintf("/data/local/tmp/user/0/%s", path).c_str(), &buf);
+    return buf.st_gid;
+}
+
+static int stat_mode(const char* path) {
+    struct stat buf;
+    ::stat(StringPrintf("/data/local/tmp/user/0/%s", path).c_str(), &buf);
+    return buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID);
+}
+
+class ServiceTest : public testing::Test {
+protected:
+    InstalldNativeService* service;
+    std::unique_ptr<std::string> testUuid;
+
+    virtual void SetUp() {
+        setenv("ANDROID_LOG_TAGS", "*:v", 1);
+        android::base::InitLogging(nullptr);
+
+        service = new InstalldNativeService();
+        testUuid = std::make_unique<std::string>();
+        *testUuid = std::string(kTestUuid);
+        system("mkdir -p /data/local/tmp/user/0");
+    }
+
+    virtual void TearDown() {
+        delete service;
+        system("rm -rf /data/local/tmp/user");
+    }
+};
+
+TEST_F(ServiceTest, FixupAppData_Upgrade) {
+    LOG(INFO) << "FixupAppData_Upgrade";
+
+    mkdir("com.example", 10000, 10000, 0700);
+    mkdir("com.example/normal", 10000, 10000, 0700);
+    mkdir("com.example/cache", 10000, 10000, 0700);
+    touch("com.example/cache/file", 10000, 10000, 0700);
+
+    service->fixupAppData(testUuid, 0);
+
+    EXPECT_EQ(10000, stat_gid("com.example/normal"));
+    EXPECT_EQ(20000, stat_gid("com.example/cache"));
+    EXPECT_EQ(20000, stat_gid("com.example/cache/file"));
+
+    EXPECT_EQ(0700, stat_mode("com.example/normal"));
+    EXPECT_EQ(02771, stat_mode("com.example/cache"));
+    EXPECT_EQ(0700, stat_mode("com.example/cache/file"));
+}
+
+TEST_F(ServiceTest, FixupAppData_Moved) {
+    LOG(INFO) << "FixupAppData_Moved";
+
+    mkdir("com.example", 10000, 10000, 0700);
+    mkdir("com.example/foo", 10000, 10000, 0700);
+    touch("com.example/foo/file", 10000, 20000, 0700);
+    mkdir("com.example/bar", 10000, 20000, 0700);
+    touch("com.example/bar/file", 10000, 20000, 0700);
+
+    service->fixupAppData(testUuid, 0);
+
+    EXPECT_EQ(10000, stat_gid("com.example/foo"));
+    EXPECT_EQ(20000, stat_gid("com.example/foo/file"));
+    EXPECT_EQ(10000, stat_gid("com.example/bar"));
+    EXPECT_EQ(10000, stat_gid("com.example/bar/file"));
+
+    service->fixupAppData(testUuid, FLAG_FORCE);
+
+    EXPECT_EQ(10000, stat_gid("com.example/foo"));
+    EXPECT_EQ(10000, stat_gid("com.example/foo/file"));
+    EXPECT_EQ(10000, stat_gid("com.example/bar"));
+    EXPECT_EQ(10000, stat_gid("com.example/bar/file"));
+}
+
+TEST_F(ServiceTest, RmDexNoDalvikCache) {
+    LOG(INFO) << "RmDexNoDalvikCache";
+
+    // Try to remove a non existing dalvik cache dex. The call should be
+    // successful because there's nothing to remove.
+    EXPECT_TRUE(service->rmdex("com.example", "arm").isOk());
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 9b2de88..dab3236 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -19,9 +19,9 @@
 
 #include <gtest/gtest.h>
 
-#include <commands.h>
-#include <globals.h>
-#include <utils.h>
+#include "InstalldNativeService.h"
+#include "globals.h"
+#include "utils.h"
 
 #undef LOG_TAG
 #define LOG_TAG "utils_test"
@@ -29,12 +29,15 @@
 #define TEST_DATA_DIR "/data/"
 #define TEST_APP_DIR "/data/app/"
 #define TEST_APP_PRIVATE_DIR "/data/app-private/"
+#define TEST_APP_EPHEMERAL_DIR "/data/app-ephemeral/"
 #define TEST_ASEC_DIR "/mnt/asec/"
 #define TEST_EXPAND_DIR "/mnt/expand/"
 
 #define TEST_SYSTEM_DIR1 "/system/app/"
 #define TEST_SYSTEM_DIR2 "/vendor/app/"
 
+#define TEST_PROFILE_DIR "/data/misc/profiles"
+
 #define REALLY_LONG_APP_NAME "com.example." \
         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \
         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \
@@ -57,6 +60,9 @@
         android_app_private_dir.path = (char*) TEST_APP_PRIVATE_DIR;
         android_app_private_dir.len = strlen(TEST_APP_PRIVATE_DIR);
 
+        android_app_ephemeral_dir.path = (char*) TEST_APP_EPHEMERAL_DIR;
+        android_app_ephemeral_dir.len = strlen(TEST_APP_EPHEMERAL_DIR);
+
         android_data_dir.path = (char*) TEST_DATA_DIR;
         android_data_dir.len = strlen(TEST_DATA_DIR);
 
@@ -74,6 +80,9 @@
 
         android_system_dirs.dirs[1].path = (char*) TEST_SYSTEM_DIR2;
         android_system_dirs.dirs[1].len = strlen(TEST_SYSTEM_DIR2);
+
+        android_profiles_dir.path = (char*) TEST_PROFILE_DIR;
+        android_profiles_dir.len = strlen(TEST_PROFILE_DIR);
     }
 
     virtual void TearDown() {
@@ -85,19 +94,19 @@
     // Bad prefixes directories
     const char *badprefix1 = "/etc/passwd";
     EXPECT_EQ(-1, validate_apk_path(badprefix1))
-            << badprefix1 << " should be allowed as a valid path";
+            << badprefix1 << " should not be allowed as a valid path";
 
     const char *badprefix2 = "../.." TEST_APP_DIR "../../../blah";
     EXPECT_EQ(-1, validate_apk_path(badprefix2))
-            << badprefix2 << " should be allowed as a valid path";
+            << badprefix2 << " should not be allowed as a valid path";
 
     const char *badprefix3 = "init.rc";
     EXPECT_EQ(-1, validate_apk_path(badprefix3))
-            << badprefix3 << " should be allowed as a valid path";
+            << badprefix3 << " should not be allowed as a valid path";
 
     const char *badprefix4 = "/init.rc";
     EXPECT_EQ(-1, validate_apk_path(badprefix4))
-            << badprefix4 << " should be allowed as a valid path";
+            << badprefix4 << " should not be allowed as a valid path";
 }
 
 TEST_F(UtilsTest, IsValidApkPath_Internal) {
@@ -317,6 +326,7 @@
     size_t pkgnameSize = PKG_NAME_MAX;
     char pkgname[pkgnameSize + 1];
     memset(pkgname, 'a', pkgnameSize);
+    pkgname[1] = '.';
     pkgname[pkgnameSize] = '\0';
 
     EXPECT_EQ(0, create_pkg_path(path, pkgname, "", 0))
@@ -329,19 +339,6 @@
              << "Package path should be a really long string of a's";
 }
 
-TEST_F(UtilsTest, CreatePkgPath_LongPkgNameFail) {
-    char path[PKG_PATH_MAX];
-
-    // Create long packagename of "aaaaa..."
-    size_t pkgnameSize = PKG_NAME_MAX + 1;
-    char pkgname[pkgnameSize + 1];
-    memset(pkgname, 'a', pkgnameSize);
-    pkgname[pkgnameSize] = '\0';
-
-    EXPECT_EQ(-1, create_pkg_path(path, pkgname, "", 0))
-            << "Should return error because package name is too long.";
-}
-
 TEST_F(UtilsTest, CreatePkgPath_LongPostfixFail) {
     char path[PKG_PATH_MAX];
 
@@ -508,5 +505,71 @@
             create_data_user_ce_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 10, "com.example"));
 }
 
+TEST_F(UtilsTest, IsValidPackageName) {
+    EXPECT_EQ(true, is_valid_package_name("android"));
+    EXPECT_EQ(true, is_valid_package_name("com.example"));
+    EXPECT_EQ(true, is_valid_package_name("com.example-1"));
+    EXPECT_EQ(true, is_valid_package_name("com.example-1024"));
+    EXPECT_EQ(true, is_valid_package_name("com.example.foo---KiJFj4a_tePVw95pSrjg=="));
+    EXPECT_EQ(true, is_valid_package_name("really_LONG.a1234.package_name"));
+
+    EXPECT_EQ(false, is_valid_package_name("1234.package"));
+    EXPECT_EQ(false, is_valid_package_name("com.1234.package"));
+    EXPECT_EQ(false, is_valid_package_name(""));
+    EXPECT_EQ(false, is_valid_package_name("."));
+    EXPECT_EQ(false, is_valid_package_name(".."));
+    EXPECT_EQ(false, is_valid_package_name("../"));
+    EXPECT_EQ(false, is_valid_package_name("com.example/../com.evil/"));
+    EXPECT_EQ(false, is_valid_package_name("com.example-1/../com.evil/"));
+    EXPECT_EQ(false, is_valid_package_name("/com.evil"));
+}
+
+TEST_F(UtilsTest, CreateDataUserProfilePath) {
+    EXPECT_EQ("/data/misc/profiles/cur/0", create_primary_cur_profile_dir_path(0));
+    EXPECT_EQ("/data/misc/profiles/cur/1", create_primary_cur_profile_dir_path(1));
+}
+
+TEST_F(UtilsTest, CreateDataUserProfilePackagePath) {
+    EXPECT_EQ("/data/misc/profiles/cur/0/com.example",
+            create_primary_current_profile_package_dir_path(0, "com.example"));
+    EXPECT_EQ("/data/misc/profiles/cur/1/com.example",
+            create_primary_current_profile_package_dir_path(1, "com.example"));
+}
+
+TEST_F(UtilsTest, CreateDataRefProfilePath) {
+    EXPECT_EQ("/data/misc/profiles/ref", create_primary_ref_profile_dir_path());
+}
+
+TEST_F(UtilsTest, CreateDataRefProfilePackagePath) {
+    EXPECT_EQ("/data/misc/profiles/ref/com.example",
+        create_primary_reference_profile_package_dir_path("com.example"));
+}
+
+TEST_F(UtilsTest, CreatePrimaryCurrentProfile) {
+    std::string expected =
+        create_primary_current_profile_package_dir_path(0, "com.example") + "/primary.prof";
+    EXPECT_EQ(expected,
+            create_current_profile_path(/*user*/0, "com.example", /*is_secondary*/false));
+}
+
+TEST_F(UtilsTest, CreatePrimaryReferenceProfile) {
+    std::string expected =
+        create_primary_reference_profile_package_dir_path("com.example") + "/primary.prof";
+    EXPECT_EQ(expected,
+            create_reference_profile_path("com.example", /*is_secondary*/false));
+}
+
+TEST_F(UtilsTest, CreateSecondaryCurrentProfile) {
+    EXPECT_EQ("/data/user/0/com.example/secondary.dex.prof",
+            create_current_profile_path(/*user*/0,
+                    "/data/user/0/com.example/secondary.dex", /*is_secondary*/true));
+}
+
+TEST_F(UtilsTest, CreateSecondaryReferenceProfile) {
+    EXPECT_EQ("/data/user/0/com.example/oat/secondary.dex.prof",
+            create_reference_profile_path(
+                    "/data/user/0/com.example/secondary.dex", /*is_secondary*/true));
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 674f760..c792082 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -18,21 +18,18 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <fts.h>
 #include <stdlib.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <sys/xattr.h>
-
-#if defined(__APPLE__)
-#include <sys/mount.h>
-#else
-#include <sys/statfs.h>
-#endif
+#include <sys/statvfs.h>
 
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <cutils/fs.h>
-#include <cutils/log.h>
+#include <cutils/properties.h>
+#include <log/log.h>
 #include <private/android_filesystem_config.h>
 
 #include "globals.h"  // extern variables.
@@ -41,7 +38,6 @@
 #define LOG_TAG "installd"
 #endif
 
-#define CACHE_NOISY(x) //x
 #define DEBUG_XATTRS 0
 
 using android::base::StringPrintf;
@@ -53,7 +49,7 @@
  * Check that given string is valid filename, and that it attempts no
  * parent or child directory traversal.
  */
-static bool is_valid_filename(const std::string& name) {
+bool is_valid_filename(const std::string& name) {
     if (name.empty() || (name == ".") || (name == "..")
             || (name.find('/') != std::string::npos)) {
         return false;
@@ -64,7 +60,7 @@
 
 static void check_package_name(const char* package_name) {
     CHECK(is_valid_filename(package_name));
-    CHECK(is_valid_package_name(package_name) == 0);
+    CHECK(is_valid_package_name(package_name));
 }
 
 /**
@@ -135,7 +131,7 @@
 
 int create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname,
         const char *postfix, userid_t userid) {
-    if (is_valid_package_name(pkgname) != 0) {
+    if (!is_valid_package_name(pkgname)) {
         path[0] = '\0';
         return -1;
     }
@@ -154,6 +150,9 @@
 std::string create_data_path(const char* volume_uuid) {
     if (volume_uuid == nullptr) {
         return "/data";
+    } else if (!strcmp(volume_uuid, "TEST")) {
+        CHECK(property_get_bool("ro.debuggable", false));
+        return "/data/local/tmp";
     } else {
         CHECK(is_valid_filename(volume_uuid));
         return StringPrintf("/mnt/expand/%s", volume_uuid);
@@ -198,22 +197,76 @@
     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(),
+            data_type, package_name);
+}
+
 std::string create_data_misc_legacy_path(userid_t userid) {
     return StringPrintf("%s/misc/user/%u", create_data_path(nullptr).c_str(), userid);
 }
 
-std::string create_data_user_profiles_path(userid_t userid) {
+std::string create_primary_cur_profile_dir_path(userid_t userid) {
     return StringPrintf("%s/cur/%u", android_profiles_dir.path, userid);
 }
 
-std::string create_data_user_profile_package_path(userid_t user, const char* package_name) {
-    check_package_name(package_name);
-    return StringPrintf("%s/%s",create_data_user_profiles_path(user).c_str(), package_name);
+std::string create_primary_current_profile_package_dir_path(userid_t user,
+        const std::string& package_name) {
+    check_package_name(package_name.c_str());
+    return StringPrintf("%s/%s",
+            create_primary_cur_profile_dir_path(user).c_str(), package_name.c_str());
 }
 
-std::string create_data_ref_profile_package_path(const char* package_name) {
-    check_package_name(package_name);
-    return StringPrintf("%s/ref/%s", android_profiles_dir.path, package_name);
+std::string create_primary_ref_profile_dir_path() {
+    return StringPrintf("%s/ref", android_profiles_dir.path);
+}
+
+std::string create_primary_reference_profile_package_dir_path(const std::string& package_name) {
+    check_package_name(package_name.c_str());
+    return StringPrintf("%s/ref/%s", android_profiles_dir.path, package_name.c_str());
+}
+
+std::string create_data_dalvik_cache_path() {
+    return "/data/dalvik-cache";
+}
+
+// Keep profile paths in sync with ActivityThread and LoadedApk.
+const std::string PROFILE_EXT = ".prof";
+const std::string PRIMARY_PROFILE_NAME = "primary" + PROFILE_EXT;
+
+std::string create_current_profile_path(userid_t user, const std::string& location,
+        bool is_secondary_dex) {
+    if (is_secondary_dex) {
+        // Secondary dex profiles are stored next to the dex files using .prof extension.
+        return StringPrintf("%s%s", location.c_str(), PROFILE_EXT.c_str());
+    } else {
+        // Profiles for primary apks are under /data/misc/profiles/cur.
+        std::string profile_dir = create_primary_current_profile_package_dir_path(user, location);
+        return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME.c_str());
+    }
+}
+
+std::string create_reference_profile_path(const std::string& location, bool is_secondary_dex) {
+    if (is_secondary_dex) {
+        // Secondary dex reference profiles are stored next to the dex files under the oat folder.
+        size_t dirIndex = location.rfind('/');
+        CHECK(dirIndex != std::string::npos)
+                << "Unexpected dir structure for secondary dex " << location;
+
+        std::string dex_dir = location.substr(0, dirIndex);
+        std::string dex_name = location.substr(dirIndex +1);
+        return StringPrintf("%s/oat/%s%s",
+                dex_dir.c_str(), dex_name.c_str(), PROFILE_EXT.c_str());
+    } else {
+        // Reference profiles for primary apks are stored in /data/misc/profile/ref.
+        std::string profile_dir = create_primary_reference_profile_package_dir_path(location);
+        return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME.c_str());
+    }
 }
 
 std::vector<userid_t> get_known_users(const char* volume_uuid) {
@@ -248,6 +301,59 @@
     return users;
 }
 
+int calculate_tree_size(const std::string& path, int64_t* size,
+        int32_t include_gid, int32_t exclude_gid, bool exclude_apps) {
+    FTS *fts;
+    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 (errno != ENOENT) {
+            PLOG(ERROR) << "Failed to fts_open " << path;
+        }
+        return -1;
+    }
+    while ((p = fts_read(fts)) != NULL) {
+        switch (p->fts_info) {
+        case FTS_D:
+        case FTS_DEFAULT:
+        case FTS_F:
+        case FTS_SL:
+        case FTS_SLNONE:
+            int32_t uid = p->fts_statp->st_uid;
+            int32_t gid = p->fts_statp->st_gid;
+            int32_t user_uid = multiuser_get_app_id(uid);
+            int32_t user_gid = multiuser_get_app_id(gid);
+            if (exclude_apps && ((user_uid >= AID_APP_START && user_uid <= AID_APP_END)
+                    || (user_gid >= AID_CACHE_GID_START && user_gid <= AID_CACHE_GID_END)
+                    || (user_gid >= AID_SHARED_GID_START && user_gid <= AID_SHARED_GID_END))) {
+                // Don't traverse inside or measure
+                fts_set(fts, p, FTS_SKIP);
+                break;
+            }
+            if (include_gid != -1 && gid != include_gid) {
+                break;
+            }
+            if (exclude_gid != -1 && gid == exclude_gid) {
+                break;
+            }
+            matchedSize += (p->fts_statp->st_blocks * 512);
+            break;
+        }
+    }
+    fts_close(fts);
+#if MEASURE_DEBUG
+    if ((include_gid == -1) && (exclude_gid == -1)) {
+        LOG(DEBUG) << "Measured " << path << " size " << matchedSize;
+    } else {
+        LOG(DEBUG) << "Measured " << path << " size " << matchedSize << "; include " << include_gid
+                << " exclude " << exclude_gid;
+    }
+#endif
+    *size += matchedSize;
+    return 0;
+}
+
 int create_move_path(char path[PKG_PATH_MAX],
     const char* pkgname,
     const char* leaf,
@@ -266,49 +372,46 @@
  * Checks whether the package name is valid. Returns -1 on error and
  * 0 on success.
  */
-int is_valid_package_name(const char* pkgname) {
-    const char *x = pkgname;
-    int alpha = -1;
+bool is_valid_package_name(const std::string& packageName) {
+    // This logic is borrowed from PackageParser.java
+    bool hasSep = false;
+    bool front = true;
 
-    if (strlen(pkgname) > PKG_NAME_MAX) {
-        return -1;
-    }
-
-    while (*x) {
-        if (isalnum(*x) || (*x == '_')) {
-                /* alphanumeric or underscore are fine */
-        } else if (*x == '.') {
-            if ((x == pkgname) || (x[1] == '.') || (x[1] == 0)) {
-                    /* periods must not be first, last, or doubled */
-                ALOGE("invalid package name '%s'\n", pkgname);
-                return -1;
-            }
-        } else if (*x == '-') {
-            /* Suffix -X is fine to let versioning of packages.
-               But whatever follows should be alphanumeric.*/
-            alpha = 1;
-        } else {
-                /* anything not A-Z, a-z, 0-9, _, or . is invalid */
-            ALOGE("invalid package name '%s'\n", pkgname);
-            return -1;
+    auto it = packageName.begin();
+    for (; it != packageName.end() && *it != '-'; it++) {
+        char c = *it;
+        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+            front = false;
+            continue;
         }
-
-        x++;
-    }
-
-    if (alpha == 1) {
-        // Skip current character
-        x++;
-        while (*x) {
-            if (!isalnum(*x)) {
-                ALOGE("invalid package name '%s' should include only numbers after -\n", pkgname);
-                return -1;
+        if (!front) {
+            if ((c >= '0' && c <= '9') || c == '_') {
+                continue;
             }
-            x++;
         }
+        if (c == '.') {
+            hasSep = true;
+            front = true;
+            continue;
+        }
+        LOG(WARNING) << "Bad package character " << c << " in " << packageName;
+        return false;
     }
 
-    return 0;
+    if (front) {
+        LOG(WARNING) << "Missing separator in " << packageName;
+        return false;
+    }
+
+    for (; it != packageName.end(); it++) {
+        char c = *it;
+        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) continue;
+        if ((c >= '0' && c <= '9') || c == '_' || c == '-' || c == '=') continue;
+        LOG(WARNING) << "Bad suffix character " << c << " in " << packageName;
+        return false;
+    }
+
+    return true;
 }
 
 static int _delete_dir_contents(DIR *d,
@@ -526,264 +629,16 @@
     return res;
 }
 
-int64_t data_disk_free(const std::string& data_path)
-{
-    struct statfs sfs;
-    if (statfs(data_path.c_str(), &sfs) == 0) {
-        return sfs.f_bavail * sfs.f_bsize;
+int64_t data_disk_free(const std::string& data_path) {
+    struct statvfs sfs;
+    if (statvfs(data_path.c_str(), &sfs) == 0) {
+        return sfs.f_bavail * sfs.f_frsize;
     } else {
-        PLOG(ERROR) << "Couldn't statfs " << data_path;
+        PLOG(ERROR) << "Couldn't statvfs " << data_path;
         return -1;
     }
 }
 
-cache_t* start_cache_collection()
-{
-    cache_t* cache = (cache_t*)calloc(1, sizeof(cache_t));
-    return cache;
-}
-
-#define CACHE_BLOCK_SIZE (512*1024)
-
-static void* _cache_malloc(cache_t* cache, size_t len)
-{
-    len = (len+3)&~3;
-    if (len > (CACHE_BLOCK_SIZE/2)) {
-        // It doesn't make sense to try to put this allocation into one
-        // of our blocks, because it is so big.  Instead, make a new dedicated
-        // block for it.
-        int8_t* res = (int8_t*)malloc(len+sizeof(void*));
-        if (res == NULL) {
-            return NULL;
-        }
-        CACHE_NOISY(ALOGI("Allocated large cache mem block: %p size %zu", res, len));
-        // Link it into our list of blocks, not disrupting the current one.
-        if (cache->memBlocks == NULL) {
-            *(void**)res = NULL;
-            cache->memBlocks = res;
-        } else {
-            *(void**)res = *(void**)cache->memBlocks;
-            *(void**)cache->memBlocks = res;
-        }
-        return res + sizeof(void*);
-    }
-    int8_t* res = cache->curMemBlockAvail;
-    int8_t* nextPos = res + len;
-    if (cache->memBlocks == NULL || nextPos > cache->curMemBlockEnd) {
-        int8_t* newBlock = (int8_t*) malloc(CACHE_BLOCK_SIZE);
-        if (newBlock == NULL) {
-            return NULL;
-        }
-        CACHE_NOISY(ALOGI("Allocated new cache mem block: %p", newBlock));
-        *(void**)newBlock = cache->memBlocks;
-        cache->memBlocks = newBlock;
-        res = cache->curMemBlockAvail = newBlock + sizeof(void*);
-        cache->curMemBlockEnd = newBlock + CACHE_BLOCK_SIZE;
-        nextPos = res + len;
-    }
-    CACHE_NOISY(ALOGI("cache_malloc: ret %p size %zu, block=%p, nextPos=%p",
-            res, len, cache->memBlocks, nextPos));
-    cache->curMemBlockAvail = nextPos;
-    return res;
-}
-
-static void* _cache_realloc(cache_t* cache, void* cur, size_t origLen, size_t len)
-{
-    // This isn't really a realloc, but it is good enough for our purposes here.
-    void* alloc = _cache_malloc(cache, len);
-    if (alloc != NULL && cur != NULL) {
-        memcpy(alloc, cur, origLen < len ? origLen : len);
-    }
-    return alloc;
-}
-
-static void _inc_num_cache_collected(cache_t* cache)
-{
-    cache->numCollected++;
-    if ((cache->numCollected%20000) == 0) {
-        ALOGI("Collected cache so far: %zd directories, %zd files",
-            cache->numDirs, cache->numFiles);
-    }
-}
-
-static cache_dir_t* _add_cache_dir_t(cache_t* cache, cache_dir_t* parent, const char *name)
-{
-    size_t nameLen = strlen(name);
-    cache_dir_t* dir = (cache_dir_t*)_cache_malloc(cache, sizeof(cache_dir_t)+nameLen+1);
-    if (dir != NULL) {
-        dir->parent = parent;
-        dir->childCount = 0;
-        dir->hiddenCount = 0;
-        dir->deleted = 0;
-        strcpy(dir->name, name);
-        if (cache->numDirs >= cache->availDirs) {
-            size_t newAvail = cache->availDirs < 1000 ? 1000 : cache->availDirs*2;
-            cache_dir_t** newDirs = (cache_dir_t**)_cache_realloc(cache, cache->dirs,
-                    cache->availDirs*sizeof(cache_dir_t*), newAvail*sizeof(cache_dir_t*));
-            if (newDirs == NULL) {
-                ALOGE("Failure growing cache dirs array for %s\n", name);
-                return NULL;
-            }
-            cache->availDirs = newAvail;
-            cache->dirs = newDirs;
-        }
-        cache->dirs[cache->numDirs] = dir;
-        cache->numDirs++;
-        if (parent != NULL) {
-            parent->childCount++;
-        }
-        _inc_num_cache_collected(cache);
-    } else {
-        ALOGE("Failure allocating cache_dir_t for %s\n", name);
-    }
-    return dir;
-}
-
-static cache_file_t* _add_cache_file_t(cache_t* cache, cache_dir_t* dir, time_t modTime,
-        const char *name)
-{
-    size_t nameLen = strlen(name);
-    cache_file_t* file = (cache_file_t*)_cache_malloc(cache, sizeof(cache_file_t)+nameLen+1);
-    if (file != NULL) {
-        file->dir = dir;
-        file->modTime = modTime;
-        strcpy(file->name, name);
-        if (cache->numFiles >= cache->availFiles) {
-            size_t newAvail = cache->availFiles < 1000 ? 1000 : cache->availFiles*2;
-            cache_file_t** newFiles = (cache_file_t**)_cache_realloc(cache, cache->files,
-                    cache->availFiles*sizeof(cache_file_t*), newAvail*sizeof(cache_file_t*));
-            if (newFiles == NULL) {
-                ALOGE("Failure growing cache file array for %s\n", name);
-                return NULL;
-            }
-            cache->availFiles = newAvail;
-            cache->files = newFiles;
-        }
-        CACHE_NOISY(ALOGI("Setting file %p at position %zd in array %p", file,
-                cache->numFiles, cache->files));
-        cache->files[cache->numFiles] = file;
-        cache->numFiles++;
-        dir->childCount++;
-        _inc_num_cache_collected(cache);
-    } else {
-        ALOGE("Failure allocating cache_file_t for %s\n", name);
-    }
-    return file;
-}
-
-static int _add_cache_files(cache_t *cache, cache_dir_t *parentDir, const char *dirName,
-        DIR* dir, char *pathBase, char *pathPos, size_t pathAvailLen)
-{
-    struct dirent *de;
-    cache_dir_t* cacheDir = NULL;
-    int dfd;
-
-    CACHE_NOISY(ALOGI("_add_cache_files: parent=%p dirName=%s dir=%p pathBase=%s",
-            parentDir, dirName, dir, pathBase));
-
-    dfd = dirfd(dir);
-
-    if (dfd < 0) return 0;
-
-    // Sub-directories always get added to the data structure, so if they
-    // are empty we will know about them to delete them later.
-    cacheDir = _add_cache_dir_t(cache, parentDir, dirName);
-
-    while ((de = readdir(dir))) {
-        const char *name = de->d_name;
-
-        if (de->d_type == DT_DIR) {
-            int subfd;
-            DIR *subdir;
-
-                /* always skip "." and ".." */
-            if (name[0] == '.') {
-                if (name[1] == 0) continue;
-                if ((name[1] == '.') && (name[2] == 0)) continue;
-            }
-
-            subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
-            if (subfd < 0) {
-                ALOGE("Couldn't openat %s: %s\n", name, strerror(errno));
-                continue;
-            }
-            subdir = fdopendir(subfd);
-            if (subdir == NULL) {
-                ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
-                close(subfd);
-                continue;
-            }
-            if (cacheDir == NULL) {
-                cacheDir = _add_cache_dir_t(cache, parentDir, dirName);
-            }
-            if (cacheDir != NULL) {
-                // Update pathBase for the new path...  this may change dirName
-                // if that is also pointing to the path, but we are done with it
-                // now.
-                size_t finallen = snprintf(pathPos, pathAvailLen, "/%s", name);
-                CACHE_NOISY(ALOGI("Collecting dir %s\n", pathBase));
-                if (finallen < pathAvailLen) {
-                    _add_cache_files(cache, cacheDir, name, subdir, pathBase,
-                            pathPos+finallen, pathAvailLen-finallen);
-                } else {
-                    // Whoops, the final path is too long!  We'll just delete
-                    // this directory.
-                    ALOGW("Cache dir %s truncated in path %s; deleting dir\n",
-                            name, pathBase);
-                    _delete_dir_contents(subdir, NULL);
-                    if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) {
-                        ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno));
-                    }
-                }
-            }
-            closedir(subdir);
-        } else if (de->d_type == DT_REG) {
-            // Skip files that start with '.'; they will be deleted if
-            // their entire directory is deleted.  This allows for metadata
-            // like ".nomedia" to remain in the directory until the entire
-            // directory is deleted.
-            if (cacheDir == NULL) {
-                cacheDir = _add_cache_dir_t(cache, parentDir, dirName);
-            }
-            if (name[0] == '.') {
-                cacheDir->hiddenCount++;
-                continue;
-            }
-            if (cacheDir != NULL) {
-                // Build final full path for file...  this may change dirName
-                // if that is also pointing to the path, but we are done with it
-                // now.
-                size_t finallen = snprintf(pathPos, pathAvailLen, "/%s", name);
-                CACHE_NOISY(ALOGI("Collecting file %s\n", pathBase));
-                if (finallen < pathAvailLen) {
-                    struct stat s;
-                    if (stat(pathBase, &s) >= 0) {
-                        _add_cache_file_t(cache, cacheDir, s.st_mtime, name);
-                    } else {
-                        ALOGW("Unable to stat cache file %s; deleting\n", pathBase);
-                        if (unlink(pathBase) < 0) {
-                            ALOGE("Couldn't unlink %s: %s\n", pathBase, strerror(errno));
-                        }
-                    }
-                } else {
-                    // Whoops, the final path is too long!  We'll just delete
-                    // this file.
-                    ALOGW("Cache file %s truncated in path %s; deleting\n",
-                            name, pathBase);
-                    if (unlinkat(dfd, name, 0) < 0) {
-                        *pathPos = 0;
-                        ALOGE("Couldn't unlinkat %s in %s: %s\n", name, pathBase,
-                                strerror(errno));
-                    }
-                }
-            }
-        } else {
-            cacheDir->hiddenCount++;
-        }
-    }
-    return 0;
-}
-
 int get_path_inode(const std::string& path, ino_t *inode) {
     struct stat buf;
     memset(&buf, 0, sizeof(buf));
@@ -877,172 +732,6 @@
     }
 }
 
-void add_cache_files(cache_t* cache, const std::string& data_path) {
-    DIR *d;
-    struct dirent *de;
-    char dirname[PATH_MAX];
-
-    const char* basepath = data_path.c_str();
-    CACHE_NOISY(ALOGI("add_cache_files: basepath=%s\n", basepath));
-
-    d = opendir(basepath);
-    if (d == NULL) {
-        return;
-    }
-
-    while ((de = readdir(d))) {
-        if (de->d_type == DT_DIR) {
-            DIR* subdir;
-            const char *name = de->d_name;
-
-                /* always skip "." and ".." */
-            if (name[0] == '.') {
-                if (name[1] == 0) continue;
-                if ((name[1] == '.') && (name[2] == 0)) continue;
-            }
-
-            auto parent = StringPrintf("%s/%s", basepath, name);
-            auto resolved = read_path_inode(parent, "cache", kXattrInodeCache);
-            strcpy(dirname, resolved.c_str());
-            CACHE_NOISY(ALOGI("Adding cache files from dir: %s\n", dirname));
-
-            subdir = opendir(dirname);
-            if (subdir != NULL) {
-                size_t dirnameLen = strlen(dirname);
-                _add_cache_files(cache, NULL, dirname, subdir, dirname, dirname+dirnameLen,
-                        PATH_MAX - dirnameLen);
-                closedir(subdir);
-            }
-        }
-    }
-
-    closedir(d);
-}
-
-static char *create_dir_path(char path[PATH_MAX], cache_dir_t* dir)
-{
-    char *pos = path;
-    if (dir->parent != NULL) {
-        pos = create_dir_path(path, dir->parent);
-    }
-    // Note that we don't need to worry about going beyond the buffer,
-    // since when we were constructing the cache entries our maximum
-    // buffer size for full paths was PATH_MAX.
-    strcpy(pos, dir->name);
-    pos += strlen(pos);
-    *pos = '/';
-    pos++;
-    *pos = 0;
-    return pos;
-}
-
-static void delete_cache_dir(char path[PATH_MAX], cache_dir_t* dir)
-{
-    if (dir->parent != NULL) {
-        create_dir_path(path, dir);
-        ALOGI("DEL DIR %s\n", path);
-        if (dir->hiddenCount <= 0) {
-            if (rmdir(path)) {
-                ALOGE("Couldn't rmdir %s: %s\n", path, strerror(errno));
-                return;
-            }
-        } else {
-            // The directory contains hidden files so we need to delete
-            // them along with the directory itself.
-            if (delete_dir_contents(path, 1, NULL)) {
-                return;
-            }
-        }
-        dir->parent->childCount--;
-        dir->deleted = 1;
-        if (dir->parent->childCount <= 0) {
-            delete_cache_dir(path, dir->parent);
-        }
-    } else if (dir->hiddenCount > 0) {
-        // This is a root directory, but it has hidden files.  Get rid of
-        // all of those files, but not the directory itself.
-        create_dir_path(path, dir);
-        ALOGI("DEL CONTENTS %s\n", path);
-        delete_dir_contents(path, 0, NULL);
-    }
-}
-
-static int cache_modtime_sort(const void *lhsP, const void *rhsP)
-{
-    const cache_file_t *lhs = *(const cache_file_t**)lhsP;
-    const cache_file_t *rhs = *(const cache_file_t**)rhsP;
-    return lhs->modTime < rhs->modTime ? -1 : (lhs->modTime > rhs->modTime ? 1 : 0);
-}
-
-void clear_cache_files(const std::string& data_path, cache_t* cache, int64_t free_size)
-{
-    size_t i;
-    int skip = 0;
-    char path[PATH_MAX];
-
-    ALOGI("Collected cache files: %zd directories, %zd files",
-        cache->numDirs, cache->numFiles);
-
-    CACHE_NOISY(ALOGI("Sorting files..."));
-    qsort(cache->files, cache->numFiles, sizeof(cache_file_t*),
-            cache_modtime_sort);
-
-    CACHE_NOISY(ALOGI("Cleaning empty directories..."));
-    for (i=cache->numDirs; i>0; i--) {
-        cache_dir_t* dir = cache->dirs[i-1];
-        if (dir->childCount <= 0 && !dir->deleted) {
-            delete_cache_dir(path, dir);
-        }
-    }
-
-    CACHE_NOISY(ALOGI("Trimming files..."));
-    for (i=0; i<cache->numFiles; i++) {
-        skip++;
-        if (skip > 10) {
-            if (data_disk_free(data_path) > free_size) {
-                return;
-            }
-            skip = 0;
-        }
-        cache_file_t* file = cache->files[i];
-        strcpy(create_dir_path(path, file->dir), file->name);
-        ALOGI("DEL (mod %d) %s\n", (int)file->modTime, path);
-        if (unlink(path) < 0) {
-            ALOGE("Couldn't unlink %s: %s\n", path, strerror(errno));
-        }
-        file->dir->childCount--;
-        if (file->dir->childCount <= 0) {
-            delete_cache_dir(path, file->dir);
-        }
-    }
-}
-
-void finish_cache_collection(cache_t* cache)
-{
-    CACHE_NOISY(size_t i;)
-
-    CACHE_NOISY(ALOGI("clear_cache_files: %zu dirs, %zu files\n", cache->numDirs, cache->numFiles));
-    CACHE_NOISY(
-        for (i=0; i<cache->numDirs; i++) {
-            cache_dir_t* dir = cache->dirs[i];
-            ALOGI("dir #%zu: %p %s parent=%p\n", i, dir, dir->name, dir->parent);
-        })
-    CACHE_NOISY(
-        for (i=0; i<cache->numFiles; i++) {
-            cache_file_t* file = cache->files[i];
-            ALOGI("file #%zu: %p %s time=%d dir=%p\n", i, file, file->name,
-                    (int)file->modTime, file->dir);
-        })
-    void* block = cache->memBlocks;
-    while (block != NULL) {
-        void* nextBlock = *(void**)block;
-        CACHE_NOISY(ALOGI("Freeing cache mem block: %p", block));
-        free(block);
-        block = nextBlock;
-    }
-    free(cache);
-}
-
 /**
  * Validate that the path is valid in the context of the provided directory.
  * The path is allowed to have at most one subdirectory and no indirections
@@ -1087,6 +776,27 @@
     return -1;
 }
 
+bool validate_secondary_dex_path(const std::string& pkgname, const std::string& dex_path,
+        const char* volume_uuid, int uid, int storage_flag) {
+    CHECK(storage_flag == FLAG_STORAGE_CE || storage_flag == FLAG_STORAGE_DE);
+
+    std::string app_private_dir = storage_flag == FLAG_STORAGE_CE
+        ? create_data_user_ce_package_path(
+                volume_uuid, multiuser_get_user_id(uid), pkgname.c_str())
+        : create_data_user_de_package_path(
+                volume_uuid, multiuser_get_user_id(uid), pkgname.c_str());
+    dir_rec_t dir;
+    if (get_path_from_string(&dir, app_private_dir.c_str()) != 0) {
+        LOG(WARNING) << "Could not get dir rec for " << app_private_dir;
+        return false;
+    }
+    // Usually secondary dex files have a nested directory structure.
+    // Pick at most 10 subdirectories when validating (arbitrary value).
+    // If the secondary dex file is >10 directory nested then validation will
+    // fail and the file will not be compiled.
+    return validate_path(&dir, dex_path.c_str(), /*max_subdirs*/ 10) == 0;
+}
+
 /**
  * Get the contents of a environment variable that contains a path. Caller
  * owns the string that is inserted into the directory record. Returns
@@ -1286,5 +996,77 @@
     }
 }
 
+/**
+ * Prepare an app cache directory, which offers to fix-up the GID and
+ * directory mode flags during a platform upgrade.
+ * The app cache directory path will be 'parent'/'name'.
+ */
+int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t target_mode,
+        uid_t uid, gid_t gid) {
+    auto path = StringPrintf("%s/%s", parent.c_str(), name);
+    struct stat st;
+    if (stat(path.c_str(), &st) != 0) {
+        if (errno == ENOENT) {
+            // This is fine, just create it
+            if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, gid) != 0) {
+                PLOG(ERROR) << "Failed to prepare " << path;
+                return -1;
+            } else {
+                return 0;
+            }
+        } else {
+            PLOG(ERROR) << "Failed to stat " << path;
+            return -1;
+        }
+    }
+
+    mode_t actual_mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID);
+    if (st.st_uid != uid) {
+        // Mismatched UID is real trouble; we can't recover
+        LOG(ERROR) << "Mismatched UID at " << path << ": found " << st.st_uid
+                << " but expected " << uid;
+        return -1;
+    } else if (st.st_gid == gid && actual_mode == target_mode) {
+        // Everything looks good!
+        return 0;
+    } else {
+        // Mismatched GID/mode is recoverable; fall through to update
+        LOG(DEBUG) << "Mismatched cache GID/mode at " << path << ": found " << st.st_gid
+                << " but expected " << gid;
+    }
+
+    // Directory is owned correctly, but GID or mode mismatch means it's
+    // probably a platform upgrade so we need to fix them
+    FTS *fts;
+    FTSENT *p;
+    char *argv[] = { (char*) path.c_str(), nullptr };
+    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+        PLOG(ERROR) << "Failed to fts_open " << path;
+        return -1;
+    }
+    while ((p = fts_read(fts)) != NULL) {
+        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
+        case FTS_F:
+            if (chown(p->fts_path, -1, gid) != 0) {
+                PLOG(WARNING) << "Failed to chown " << p->fts_path;
+            }
+            break;
+        case FTS_SL:
+        case FTS_SLNONE:
+            if (lchown(p->fts_path, -1, gid) != 0) {
+                PLOG(WARNING) << "Failed to chown " << p->fts_path;
+            }
+            break;
+        }
+    }
+    fts_close(fts);
+    return 0;
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 8123e9b..070da84 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -30,40 +30,21 @@
 
 #include <installd_constants.h>
 
+#define MEASURE_DEBUG 0
+#define FIXUP_DEBUG 0
+
+#define BYPASS_QUOTA 0
+#define BYPASS_SDCARDFS 0
+
 namespace android {
 namespace installd {
 
 struct dir_rec_t;
 
-typedef struct cache_dir_struct {
-    struct cache_dir_struct* parent;
-    int32_t childCount;
-    int32_t hiddenCount;
-    int32_t deleted;
-    char name[];
-} cache_dir_t;
-
-typedef struct {
-    cache_dir_t* dir;
-    time_t modTime;
-    char name[];
-} cache_file_t;
-
-typedef struct {
-    size_t numDirs;
-    size_t availDirs;
-    cache_dir_t** dirs;
-    size_t numFiles;
-    size_t availFiles;
-    cache_file_t** files;
-    size_t numCollected;
-    void* memBlocks;
-    int8_t* curMemBlockAvail;
-    int8_t* curMemBlockEnd;
-} cache_t;
-
 constexpr const char* kXattrInodeCache = "user.inode_cache";
 constexpr const char* kXattrInodeCodeCache = "user.inode_code_cache";
+constexpr const char* kXattrCacheGroup = "user.cache_group";
+constexpr const char* kXattrCacheTombstone = "user.cache_tombstone";
 
 int create_pkg_path(char path[PKG_PATH_MAX],
                     const char *pkgname,
@@ -73,7 +54,6 @@
 std::string create_data_path(const char* volume_uuid);
 
 std::string create_data_app_path(const char* volume_uuid);
-
 std::string create_data_app_package_path(const char* volume_uuid, const char* package_name);
 
 std::string create_data_user_ce_path(const char* volume_uuid, userid_t userid);
@@ -87,15 +67,31 @@
         userid_t user, 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);
 
 std::string create_data_misc_legacy_path(userid_t userid);
 
-std::string create_data_user_profiles_path(userid_t userid);
-std::string create_data_user_profile_package_path(userid_t user, const char* package_name);
-std::string create_data_ref_profile_package_path(const char* package_name);
+std::string create_data_dalvik_cache_path();
+
+std::string create_primary_cur_profile_dir_path(userid_t userid);
+std::string create_primary_current_profile_package_dir_path(
+        userid_t user, const std::string& package_name);
+
+std::string create_primary_ref_profile_dir_path();
+std::string create_primary_reference_profile_package_dir_path(const std::string& package_name);
+
+std::string create_current_profile_path(
+        userid_t user, const std::string& package_name, bool is_secondary_dex);
+std::string create_reference_profile_path(
+        const std::string& package_name, bool is_secondary_dex);
 
 std::vector<userid_t> get_known_users(const char* volume_uuid);
 
+int calculate_tree_size(const std::string& path, int64_t* size,
+        int32_t include_gid = -1, int32_t exclude_gid = -1, bool exclude_apps = false);
+
 int create_user_config_path(char path[PKG_PATH_MAX], userid_t userid);
 
 int create_move_path(char path[PKG_PATH_MAX],
@@ -103,7 +99,8 @@
                      const char* leaf,
                      userid_t userid);
 
-int is_valid_package_name(const char* pkgname);
+bool is_valid_filename(const std::string& name);
+bool is_valid_package_name(const std::string& packageName);
 
 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);
@@ -119,20 +116,14 @@
 
 int64_t data_disk_free(const std::string& data_path);
 
-cache_t* start_cache_collection();
-
 int get_path_inode(const std::string& path, ino_t *inode);
 
 int write_path_inode(const std::string& parent, const char* name, const char* inode_xattr);
 std::string read_path_inode(const std::string& parent, const char* name, const char* inode_xattr);
 
-void add_cache_files(cache_t* cache, const std::string& data_path);
-
-void clear_cache_files(const std::string& data_path, cache_t* cache, int64_t free_size);
-
-void finish_cache_collection(cache_t* cache);
-
 int validate_system_app_path(const char* path);
+bool validate_secondary_dex_path(const std::string& pkgname, const std::string& dex_path,
+        const char* volume_uuid, int uid, int storage_flag);
 
 int get_path_from_env(dir_rec_t* rec, const char* var);
 
@@ -152,6 +143,9 @@
 
 int wait_child(pid_t pid);
 
+int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t target_mode,
+        uid_t uid, gid_t gid);
+
 }  // namespace installd
 }  // namespace android
 
diff --git a/cmds/ip-up-vpn/ip-up-vpn.c b/cmds/ip-up-vpn/ip-up-vpn.c
index 75b907c..3b8955b 100644
--- a/cmds/ip-up-vpn/ip-up-vpn.c
+++ b/cmds/ip-up-vpn/ip-up-vpn.c
@@ -14,22 +14,22 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "ip-up-vpn"
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <linux/if.h>
+#include <linux/route.h>
+#include <netinet/in.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <errno.h>
-
-#include <arpa/inet.h>
-#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <linux/if.h>
-#include <linux/route.h>
 
-#define LOG_TAG "ip-up-vpn"
-#include <cutils/log.h>
+#include <log/log.h>
 
 #define DIR "/data/misc/vpn/"
 
diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp
new file mode 100644
index 0000000..38647eb
--- /dev/null
+++ b/cmds/lshal/Android.bp
@@ -0,0 +1,68 @@
+// 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.
+
+cc_library_shared {
+    name: "liblshal",
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libutils",
+        "libhidlbase",
+        "libhidltransport",
+        "libhidl-gen-utils",
+        "libvintf",
+        "android.hidl.manager@1.0",
+    ],
+    srcs: [
+        "DebugCommand.cpp",
+        "Lshal.cpp",
+        "ListCommand.cpp",
+        "PipeRelay.cpp",
+        "utils.cpp",
+    ],
+}
+
+cc_defaults {
+    name: "lshal_defaults",
+    shared_libs: [
+        "libbase",
+        "libhidlbase",
+        "libhidltransport",
+        "liblshal",
+        "libutils",
+    ]
+}
+
+cc_binary {
+    name: "lshal",
+    defaults: ["lshal_defaults"],
+    srcs: [
+        "main.cpp"
+    ]
+}
+
+cc_test {
+    name: "lshal_test",
+    defaults: ["lshal_defaults"],
+    gtest: true,
+    static_libs: [
+        "libgmock"
+    ],
+    shared_libs: [
+        "android.hardware.tests.baz@1.0"
+    ],
+    srcs: [
+        "test.cpp"
+    ]
+}
diff --git a/cmds/lshal/DebugCommand.cpp b/cmds/lshal/DebugCommand.cpp
new file mode 100644
index 0000000..672cad6
--- /dev/null
+++ b/cmds/lshal/DebugCommand.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DebugCommand.h"
+
+#include "Lshal.h"
+
+namespace android {
+namespace lshal {
+
+DebugCommand::DebugCommand(Lshal &lshal) : mLshal(lshal) {
+}
+
+Status DebugCommand::parseArgs(const std::string &command, const Arg &arg) {
+    if (optind >= arg.argc) {
+        mLshal.usage(command);
+        return USAGE;
+    }
+    mInterfaceName = arg.argv[optind];
+    ++optind;
+    for (; optind < arg.argc; ++optind) {
+        mOptions.push_back(arg.argv[optind]);
+    }
+    return OK;
+}
+
+Status DebugCommand::main(const std::string &command, const Arg &arg) {
+    Status status = parseArgs(command, arg);
+    if (status != OK) {
+        return status;
+    }
+    auto pair = splitFirst(mInterfaceName, '/');
+    return mLshal.emitDebugInfo(
+            pair.first, pair.second.empty() ? "default" : pair.second, mOptions,
+            mLshal.out().buf(),
+            mLshal.err());
+}
+
+}  // namespace lshal
+}  // namespace android
+
diff --git a/cmds/lshal/DebugCommand.h b/cmds/lshal/DebugCommand.h
new file mode 100644
index 0000000..fa0f0fa
--- /dev/null
+++ b/cmds/lshal/DebugCommand.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_DEBUG_COMMAND_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_DEBUG_COMMAND_H_
+
+#include <string>
+
+#include <android-base/macros.h>
+
+#include "utils.h"
+
+namespace android {
+namespace lshal {
+
+class Lshal;
+
+class DebugCommand {
+public:
+    DebugCommand(Lshal &lshal);
+    Status main(const std::string &command, const Arg &arg);
+private:
+    Status parseArgs(const std::string &command, const Arg &arg);
+
+    Lshal &mLshal;
+    std::string mInterfaceName;
+    std::vector<std::string> mOptions;
+
+    DISALLOW_COPY_AND_ASSIGN(DebugCommand);
+};
+
+
+}  // namespace lshal
+}  // namespace android
+
+#endif  // FRAMEWORK_NATIVE_CMDS_LSHAL_DEBUG_COMMAND_H_
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
new file mode 100644
index 0000000..710b6e4
--- /dev/null
+++ b/cmds/lshal/ListCommand.cpp
@@ -0,0 +1,705 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ListCommand.h"
+
+#include <getopt.h>
+
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <regex>
+
+#include <android-base/parseint.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <hidl-util/FQName.h>
+#include <private/android_filesystem_config.h>
+#include <sys/stat.h>
+#include <vintf/HalManifest.h>
+#include <vintf/parse_xml.h>
+
+#include "Lshal.h"
+#include "PipeRelay.h"
+#include "Timeout.h"
+#include "utils.h"
+
+using ::android::hardware::hidl_string;
+using ::android::hidl::manager::V1_0::IServiceManager;
+
+namespace android {
+namespace lshal {
+
+ListCommand::ListCommand(Lshal &lshal) : mLshal(lshal), mErr(lshal.err()), mOut(lshal.out()) {
+}
+
+std::string getCmdline(pid_t pid) {
+    std::ifstream ifs("/proc/" + std::to_string(pid) + "/cmdline");
+    std::string cmdline;
+    if (!ifs.is_open()) {
+        return "";
+    }
+    ifs >> cmdline;
+    return cmdline;
+}
+
+const std::string &ListCommand::getCmdline(pid_t pid) {
+    auto pair = mCmdlines.find(pid);
+    if (pair != mCmdlines.end()) {
+        return pair->second;
+    }
+    mCmdlines[pid] = ::android::lshal::getCmdline(pid);
+    return mCmdlines[pid];
+}
+
+void ListCommand::removeDeadProcesses(Pids *pids) {
+    static const pid_t myPid = getpid();
+    pids->erase(std::remove_if(pids->begin(), pids->end(), [this](auto pid) {
+        return pid == myPid || this->getCmdline(pid).empty();
+    }), pids->end());
+}
+
+bool ListCommand::getReferencedPids(
+        pid_t serverPid, std::map<uint64_t, Pids> *objects) const {
+
+    std::ifstream ifs("/d/binder/proc/" + std::to_string(serverPid));
+    if (!ifs.is_open()) {
+        return false;
+    }
+
+    static const std::regex prefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
+
+    std::string line;
+    std::smatch match;
+    while(getline(ifs, line)) {
+        if (!std::regex_search(line, match, prefix)) {
+            // the line doesn't start with the correct prefix
+            continue;
+        }
+        std::string ptrString = "0x" + match.str(2); // use number after c
+        uint64_t ptr;
+        if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
+            // Should not reach here, but just be tolerant.
+            mErr << "Could not parse number " << ptrString << std::endl;
+            continue;
+        }
+        const std::string proc = " proc ";
+        auto pos = line.rfind(proc);
+        if (pos != std::string::npos) {
+            for (const std::string &pidStr : split(line.substr(pos + proc.size()), ' ')) {
+                int32_t pid;
+                if (!::android::base::ParseInt(pidStr, &pid)) {
+                    mErr << "Could not parse number " << pidStr << std::endl;
+                    continue;
+                }
+                (*objects)[ptr].push_back(pid);
+            }
+        }
+    }
+    return true;
+}
+
+// Must process hwbinder services first, then passthrough services.
+void ListCommand::forEachTable(const std::function<void(Table &)> &f) {
+    f(mServicesTable);
+    f(mPassthroughRefTable);
+    f(mImplementationsTable);
+}
+void ListCommand::forEachTable(const std::function<void(const Table &)> &f) const {
+    f(mServicesTable);
+    f(mPassthroughRefTable);
+    f(mImplementationsTable);
+}
+
+void ListCommand::postprocess() {
+    forEachTable([this](Table &table) {
+        if (mSortColumn) {
+            std::sort(table.begin(), table.end(), mSortColumn);
+        }
+        for (TableEntry &entry : table) {
+            entry.serverCmdline = getCmdline(entry.serverPid);
+            removeDeadProcesses(&entry.clientPids);
+            for (auto pid : entry.clientPids) {
+                entry.clientCmdlines.push_back(this->getCmdline(pid));
+            }
+        }
+    });
+    // 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()) {
+            continue;
+        }
+        for (TableEntry &interfaceEntry : mPassthroughRefTable) {
+            if (interfaceEntry.arch != ARCH_UNKNOWN) {
+                continue;
+            }
+            FQName interfaceName{splitFirst(interfaceEntry.interfaceName, '/').first};
+            if (!interfaceName.isValid()) {
+                continue;
+            }
+            if (interfaceName.getPackageAndVersion() == fqPackageName) {
+                interfaceEntry.arch = packageEntry.arch;
+            }
+        }
+    }
+}
+
+void ListCommand::printLine(
+        const std::string &interfaceName,
+        const std::string &transport,
+        const std::string &arch,
+        const std::string &server,
+        const std::string &serverCmdline,
+        const std::string &address, const std::string &clients,
+        const std::string &clientCmdlines) const {
+    if (mSelectedColumns & ENABLE_INTERFACE_NAME)
+        mOut << std::setw(80) << interfaceName << "\t";
+    if (mSelectedColumns & ENABLE_TRANSPORT)
+        mOut << std::setw(10) << transport << "\t";
+    if (mSelectedColumns & ENABLE_ARCH)
+        mOut << std::setw(5) << arch << "\t";
+    if (mSelectedColumns & ENABLE_SERVER_PID) {
+        if (mEnableCmdlines) {
+            mOut << std::setw(15) << serverCmdline << "\t";
+        } else {
+            mOut << std::setw(5)  << server << "\t";
+        }
+    }
+    if (mSelectedColumns & ENABLE_SERVER_ADDR)
+        mOut << std::setw(16) << address << "\t";
+    if (mSelectedColumns & ENABLE_CLIENT_PIDS) {
+        if (mEnableCmdlines) {
+            mOut << std::setw(0)  << clientCmdlines;
+        } else {
+            mOut << std::setw(0)  << clients;
+        }
+    }
+    mOut << std::endl;
+}
+
+void ListCommand::dumpVintf() const {
+    mOut << "<!-- " << std::endl
+         << "    This is a skeleton device manifest. Notes: " << std::endl
+         << "    1. android.hidl.*, android.frameworks.*, android.system.* are not included." << std::endl
+         << "    2. If a HAL is supported in both hwbinder and passthrough transport, " << std::endl
+         << "       only hwbinder is shown." << std::endl
+         << "    3. It is likely that HALs in passthrough transport does not have" << std::endl
+         << "       <interface> declared; users will have to write them by hand." << std::endl
+         << "    4. sepolicy version is set to 0.0. It is recommended that the entry" << std::endl
+         << "       is removed from the manifest file and written by assemble_vintf" << std::endl
+         << "       at build time." << std::endl
+         << "-->" << std::endl;
+
+    vintf::HalManifest manifest;
+    forEachTable([this, &manifest] (const Table &table) {
+        for (const TableEntry &entry : table) {
+
+            std::string fqInstanceName = 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()) {
+                mErr << "Warning: '" << splittedFqInstanceName.first
+                     << "' is not a valid FQName." << std::endl;
+                continue;
+            }
+            // Strip out system libs.
+            if (fqName.inPackage("android.hidl") ||
+                fqName.inPackage("android.frameworks") ||
+                fqName.inPackage("android.system")) {
+                continue;
+            }
+            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:
+                        mErr << "Warning: '" << fqName.package()
+                             << "' doesn't have bitness info, assuming 32+64." << std::endl;
+                        arch = vintf::Arch::ARCH_32_64;
+                }
+            } else {
+                mErr << "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) {
+                        mErr << "Fatal: should not reach here. Generated result may be wrong."
+                             << std::endl;
+                    }
+                    done = true;
+                    break;
+                }
+                if (hal->hasVersion(version)) {
+                    if (&table != &mImplementationsTable) {
+                        hal->interfaces[interfaceName].name = interfaceName;
+                        hal->interfaces[interfaceName].instances.insert(instanceName);
+                    }
+                    done = true;
+                    break;
+                }
+            }
+            if (done) {
+                continue; // to next TableEntry
+            }
+            decltype(vintf::ManifestHal::interfaces) interfaces;
+            if (&table != &mImplementationsTable) {
+                interfaces[interfaceName].name = interfaceName;
+                interfaces[interfaceName].instances.insert(instanceName);
+            }
+            if (!manifest.add(vintf::ManifestHal{
+                    .format = vintf::HalFormat::HIDL,
+                    .name = fqName.package(),
+                    .versions = {version},
+                    .transportArch = {transport, arch},
+                    .interfaces = interfaces})) {
+                mErr << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl;
+            }
+        }
+    });
+    mOut << vintf::gHalManifestConverter(manifest);
+}
+
+static const std::string &getArchString(Architecture 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 = "";
+    switch (arch) {
+        case ARCH64:
+            return sStr64;
+        case ARCH32:
+            return sStr32;
+        case ARCH_BOTH:
+            return sStrBoth;
+        case ARCH_UNKNOWN: // fall through
+        default:
+            return sStrUnknown;
+    }
+}
+
+static Architecture fromBaseArchitecture(::android::hidl::base::V1_0::DebugInfo::Architecture a) {
+    switch (a) {
+        case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_64BIT:
+            return ARCH64;
+        case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_32BIT:
+            return ARCH32;
+        case ::android::hidl::base::V1_0::DebugInfo::Architecture::UNKNOWN: // fallthrough
+        default:
+            return ARCH_UNKNOWN;
+    }
+}
+
+void ListCommand::dumpTable() {
+    mServicesTable.description =
+            "All binderized services (registered services through hwservicemanager)";
+    mPassthroughRefTable.description =
+            "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.";
+    mImplementationsTable.description =
+            "All available passthrough implementations (all -impl.so files)";
+    forEachTable([this] (const Table &table) {
+        mOut << table.description << std::endl;
+        mOut << std::left;
+        printLine("Interface", "Transport", "Arch", "Server", "Server CMD",
+                  "PTR", "Clients", "Clients CMD");
+
+        for (const auto &entry : table) {
+            printLine(entry.interfaceName,
+                    entry.transport,
+                    getArchString(entry.arch),
+                    entry.serverPid == NO_PID ? "N/A" : std::to_string(entry.serverPid),
+                    entry.serverCmdline,
+                    entry.serverObjectAddress == NO_PTR ? "N/A" : toHexString(entry.serverObjectAddress),
+                    join(entry.clientPids, " "),
+                    join(entry.clientCmdlines, ";"));
+
+            // We're only interested in dumping debug info for already
+            // instantiated services. There's little value in dumping the
+            // debug info for a service we create on the fly, so we only operate
+            // on the "mServicesTable".
+            if (mEmitDebugInfo && &table == &mServicesTable) {
+                auto pair = splitFirst(entry.interfaceName, '/');
+                mLshal.emitDebugInfo(pair.first, pair.second, {}, mOut.buf(),
+                        NullableOStream<std::ostream>(nullptr));
+            }
+        }
+        mOut << std::endl;
+    });
+
+}
+
+void ListCommand::dump() {
+    if (mVintf) {
+        dumpVintf();
+        if (!!mFileOutput) {
+            mFileOutput.buf().close();
+            delete &mFileOutput.buf();
+            mFileOutput = nullptr;
+        }
+        mOut = std::cout;
+    } else {
+        dumpTable();
+    }
+}
+
+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:
+            mErr << "Error: Unknown source of entry " << source << std::endl;
+    }
+    if (table) {
+        table->entries.push_back(std::forward<TableEntry>(entry));
+    }
+}
+
+Status ListCommand::fetchAllLibraries(const sp<IServiceManager> &manager) {
+    using namespace ::android::hardware;
+    using namespace ::android::hidl::manager::V1_0;
+    using namespace ::android::hidl::base::V1_0;
+    auto ret = timeoutIPC(manager, &IServiceManager::debugDump, [&] (const auto &infos) {
+        std::map<std::string, TableEntry> entries;
+        for (const auto &info : infos) {
+            std::string interfaceName = std::string{info.interfaceName.c_str()} + "/" +
+                    std::string{info.instanceName.c_str()};
+            entries.emplace(interfaceName, TableEntry{
+                .interfaceName = interfaceName,
+                .transport = "passthrough",
+                .serverPid = NO_PID,
+                .serverObjectAddress = NO_PTR,
+                .clientPids = {},
+                .arch = ARCH_UNKNOWN
+            }).first->second.arch |= fromBaseArchitecture(info.arch);
+        }
+        for (auto &&pair : entries) {
+            putEntry(LIST_DLLIB, std::move(pair.second));
+        }
+    });
+    if (!ret.isOk()) {
+        mErr << "Error: Failed to call list on getPassthroughServiceManager(): "
+             << ret.description() << std::endl;
+        return DUMP_ALL_LIBS_ERROR;
+    }
+    return OK;
+}
+
+Status ListCommand::fetchPassthrough(const sp<IServiceManager> &manager) {
+    using namespace ::android::hardware;
+    using namespace ::android::hardware::details;
+    using namespace ::android::hidl::manager::V1_0;
+    using namespace ::android::hidl::base::V1_0;
+    auto ret = timeoutIPC(manager, &IServiceManager::debugDump, [&] (const auto &infos) {
+        for (const auto &info : infos) {
+            if (info.clientPids.size() <= 0) {
+                continue;
+            }
+            putEntry(PTSERVICEMANAGER_REG_CLIENT, {
+                .interfaceName =
+                        std::string{info.interfaceName.c_str()} + "/" +
+                        std::string{info.instanceName.c_str()},
+                .transport = "passthrough",
+                .serverPid = info.clientPids.size() == 1 ? info.clientPids[0] : NO_PID,
+                .serverObjectAddress = NO_PTR,
+                .clientPids = info.clientPids,
+                .arch = fromBaseArchitecture(info.arch)
+            });
+        }
+    });
+    if (!ret.isOk()) {
+        mErr << "Error: Failed to call debugDump on defaultServiceManager(): "
+             << ret.description() << std::endl;
+        return DUMP_PASSTHROUGH_ERROR;
+    }
+    return OK;
+}
+
+Status ListCommand::fetchBinderized(const sp<IServiceManager> &manager) {
+    using namespace ::std;
+    using namespace ::android::hardware;
+    using namespace ::android::hidl::manager::V1_0;
+    using namespace ::android::hidl::base::V1_0;
+    const std::string mode = "hwbinder";
+
+    hidl_vec<hidl_string> fqInstanceNames;
+    // copying out for timeoutIPC
+    auto listRet = timeoutIPC(manager, &IServiceManager::list, [&] (const auto &names) {
+        fqInstanceNames = names;
+    });
+    if (!listRet.isOk()) {
+        mErr << "Error: Failed to list services for " << mode << ": "
+             << listRet.description() << std::endl;
+        return DUMP_BINDERIZED_ERROR;
+    }
+
+    Status status = OK;
+    // server pid, .ptr value of binder object, child pids
+    std::map<std::string, DebugInfo> allDebugInfos;
+    std::map<pid_t, std::map<uint64_t, Pids>> allPids;
+    for (const auto &fqInstanceName : fqInstanceNames) {
+        const auto pair = splitFirst(fqInstanceName, '/');
+        const auto &serviceName = pair.first;
+        const auto &instanceName = pair.second;
+        auto getRet = timeoutIPC(manager, &IServiceManager::get, serviceName, instanceName);
+        if (!getRet.isOk()) {
+            mErr << "Warning: Skipping \"" << fqInstanceName << "\": "
+                 << "cannot be fetched from service manager:"
+                 << getRet.description() << std::endl;
+            status |= DUMP_BINDERIZED_ERROR;
+            continue;
+        }
+        sp<IBase> service = getRet;
+        if (service == nullptr) {
+            mErr << "Warning: Skipping \"" << fqInstanceName << "\": "
+                 << "cannot be fetched from service manager (null)"
+                 << std::endl;
+            status |= DUMP_BINDERIZED_ERROR;
+            continue;
+        }
+        auto debugRet = timeoutIPC(service, &IBase::getDebugInfo, [&] (const auto &debugInfo) {
+            allDebugInfos[fqInstanceName] = debugInfo;
+            if (debugInfo.pid >= 0) {
+                allPids[static_cast<pid_t>(debugInfo.pid)].clear();
+            }
+        });
+        if (!debugRet.isOk()) {
+            mErr << "Warning: Skipping \"" << fqInstanceName << "\": "
+                 << "debugging information cannot be retrieved:"
+                 << debugRet.description() << std::endl;
+            status |= DUMP_BINDERIZED_ERROR;
+        }
+    }
+    for (auto &pair : allPids) {
+        pid_t serverPid = pair.first;
+        if (!getReferencedPids(serverPid, &allPids[serverPid])) {
+            mErr << "Warning: no information for PID " << serverPid
+                      << ", are you root?" << std::endl;
+            status |= DUMP_BINDERIZED_ERROR;
+        }
+    }
+    for (const auto &fqInstanceName : fqInstanceNames) {
+        auto it = allDebugInfos.find(fqInstanceName);
+        if (it == allDebugInfos.end()) {
+            putEntry(HWSERVICEMANAGER_LIST, {
+                .interfaceName = fqInstanceName,
+                .transport = mode,
+                .serverPid = NO_PID,
+                .serverObjectAddress = NO_PTR,
+                .clientPids = {},
+                .arch = ARCH_UNKNOWN
+            });
+            continue;
+        }
+        const DebugInfo &info = it->second;
+        putEntry(HWSERVICEMANAGER_LIST, {
+            .interfaceName = fqInstanceName,
+            .transport = mode,
+            .serverPid = info.pid,
+            .serverObjectAddress = info.ptr,
+            .clientPids = info.pid == NO_PID || info.ptr == NO_PTR
+                    ? Pids{} : allPids[info.pid][info.ptr],
+            .arch = fromBaseArchitecture(info.arch),
+        });
+    }
+    return status;
+}
+
+Status ListCommand::fetch() {
+    Status status = OK;
+    auto bManager = mLshal.serviceManager();
+    if (bManager == nullptr) {
+        mErr << "Failed to get defaultServiceManager()!" << std::endl;
+        status |= NO_BINDERIZED_MANAGER;
+    } else {
+        status |= fetchBinderized(bManager);
+        // Passthrough PIDs are registered to the binderized manager as well.
+        status |= fetchPassthrough(bManager);
+    }
+
+    auto pManager = mLshal.passthroughManager();
+    if (pManager == nullptr) {
+        mErr << "Failed to get getPassthroughServiceManager()!" << std::endl;
+        status |= NO_PASSTHROUGH_MANAGER;
+    } else {
+        status |= fetchAllLibraries(pManager);
+    }
+    return status;
+}
+
+Status ListCommand::parseArgs(const std::string &command, const Arg &arg) {
+    static struct option longOptions[] = {
+        // long options with short alternatives
+        {"help",      no_argument,       0, 'h' },
+        {"interface", no_argument,       0, 'i' },
+        {"transport", no_argument,       0, 't' },
+        {"arch",      no_argument,       0, 'r' },
+        {"pid",       no_argument,       0, 'p' },
+        {"address",   no_argument,       0, 'a' },
+        {"clients",   no_argument,       0, 'c' },
+        {"cmdline",   no_argument,       0, 'm' },
+        {"debug",     optional_argument, 0, 'd' },
+
+        // long options without short alternatives
+        {"sort",      required_argument, 0, 's' },
+        {"init-vintf",optional_argument, 0, 'v' },
+        { 0,          0,                 0,  0  }
+    };
+
+    int optionIndex;
+    int c;
+    // Lshal::parseArgs has set optind to the next option to parse
+    for (;;) {
+        // using getopt_long in case we want to add other options in the future
+        c = getopt_long(arg.argc, arg.argv,
+                "hitrpacmd", longOptions, &optionIndex);
+        if (c == -1) {
+            break;
+        }
+        switch (c) {
+        case 's': {
+            if (strcmp(optarg, "interface") == 0 || strcmp(optarg, "i") == 0) {
+                mSortColumn = TableEntry::sortByInterfaceName;
+            } else if (strcmp(optarg, "pid") == 0 || strcmp(optarg, "p") == 0) {
+                mSortColumn = TableEntry::sortByServerPid;
+            } else {
+                mErr << "Unrecognized sorting column: " << optarg << std::endl;
+                mLshal.usage(command);
+                return USAGE;
+            }
+            break;
+        }
+        case 'v': {
+            if (optarg) {
+                mFileOutput = new std::ofstream{optarg};
+                mOut = mFileOutput;
+                if (!mFileOutput.buf().is_open()) {
+                    mErr << "Could not open file '" << optarg << "'." << std::endl;
+                    return IO_ERROR;
+                }
+            }
+            mVintf = true;
+        }
+        case 'i': {
+            mSelectedColumns |= ENABLE_INTERFACE_NAME;
+            break;
+        }
+        case 't': {
+            mSelectedColumns |= ENABLE_TRANSPORT;
+            break;
+        }
+        case 'r': {
+            mSelectedColumns |= ENABLE_ARCH;
+            break;
+        }
+        case 'p': {
+            mSelectedColumns |= ENABLE_SERVER_PID;
+            break;
+        }
+        case 'a': {
+            mSelectedColumns |= ENABLE_SERVER_ADDR;
+            break;
+        }
+        case 'c': {
+            mSelectedColumns |= ENABLE_CLIENT_PIDS;
+            break;
+        }
+        case 'm': {
+            mEnableCmdlines = true;
+            break;
+        }
+        case 'd': {
+            mEmitDebugInfo = true;
+
+            if (optarg) {
+                mFileOutput = new std::ofstream{optarg};
+                mOut = mFileOutput;
+                if (!mFileOutput.buf().is_open()) {
+                    mErr << "Could not open file '" << optarg << "'." << std::endl;
+                    return IO_ERROR;
+                }
+                chown(optarg, AID_SHELL, AID_SHELL);
+            }
+            break;
+        }
+        case 'h': // falls through
+        default: // see unrecognized options
+            mLshal.usage(command);
+            return USAGE;
+        }
+    }
+    if (optind < arg.argc) {
+        // see non option
+        mErr << "Unrecognized option `" << arg.argv[optind] << "`" << std::endl;
+    }
+
+    if (mSelectedColumns == 0) {
+        mSelectedColumns = ENABLE_INTERFACE_NAME | ENABLE_SERVER_PID | ENABLE_CLIENT_PIDS;
+    }
+    return OK;
+}
+
+Status ListCommand::main(const std::string &command, const Arg &arg) {
+    Status status = parseArgs(command, arg);
+    if (status != OK) {
+        return status;
+    }
+    status = fetch();
+    postprocess();
+    dump();
+    return status;
+}
+
+}  // namespace lshal
+}  // namespace android
+
diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h
new file mode 100644
index 0000000..42c965f
--- /dev/null
+++ b/cmds/lshal/ListCommand.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_
+
+#include <stdint.h>
+
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include <android-base/macros.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+
+#include "NullableOStream.h"
+#include "TableEntry.h"
+#include "utils.h"
+
+namespace android {
+namespace lshal {
+
+class Lshal;
+
+class ListCommand {
+public:
+    ListCommand(Lshal &lshal);
+    Status main(const std::string &command, const Arg &arg);
+private:
+    Status parseArgs(const std::string &command, const Arg &arg);
+    Status fetch();
+    void postprocess();
+    void dump();
+    void putEntry(TableEntrySource source, 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);
+    bool getReferencedPids(
+        pid_t serverPid, std::map<uint64_t, Pids> *objects) const;
+    void dumpTable();
+    void dumpVintf() const;
+    void printLine(
+            const std::string &interfaceName,
+            const std::string &transport,
+            const std::string &arch,
+            const std::string &server,
+            const std::string &serverCmdline,
+            const std::string &address, const std::string &clients,
+            const std::string &clientCmdlines) const ;
+    // Return /proc/{pid}/cmdline if it exists, else empty string.
+    const std::string &getCmdline(pid_t pid);
+    // Call getCmdline on all pid in pids. If it returns empty string, the process might
+    // have died, and the pid is removed from pids.
+    void removeDeadProcesses(Pids *pids);
+    void forEachTable(const std::function<void(Table &)> &f);
+    void forEachTable(const std::function<void(const Table &)> &f) const;
+
+    Lshal &mLshal;
+
+    Table mServicesTable{};
+    Table mPassthroughRefTable{};
+    Table mImplementationsTable{};
+
+    NullableOStream<std::ostream> mErr;
+    NullableOStream<std::ostream> mOut;
+    NullableOStream<std::ofstream> mFileOutput = nullptr;
+    TableEntryCompare mSortColumn = nullptr;
+    TableEntrySelect mSelectedColumns = 0;
+    // If true, cmdlines will be printed instead of pid.
+    bool mEnableCmdlines = false;
+
+    // If true, calls IBase::debug(...) on each service.
+    bool mEmitDebugInfo = false;
+
+    bool mVintf = false;
+    // 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.
+    std::map<pid_t, std::string> mCmdlines;
+
+    DISALLOW_COPY_AND_ASSIGN(ListCommand);
+};
+
+
+}  // namespace lshal
+}  // namespace android
+
+#endif  // FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
new file mode 100644
index 0000000..9db42f1
--- /dev/null
+++ b/cmds/lshal/Lshal.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "lshal"
+#include <android-base/logging.h>
+
+#include "Lshal.h"
+
+#include <set>
+#include <string>
+
+#include <hidl/ServiceManagement.h>
+
+#include "DebugCommand.h"
+#include "ListCommand.h"
+#include "PipeRelay.h"
+
+namespace android {
+namespace lshal {
+
+using ::android::hidl::manager::V1_0::IServiceManager;
+
+Lshal::Lshal()
+    : mOut(std::cout), mErr(std::cerr),
+      mServiceManager(::android::hardware::defaultServiceManager()),
+      mPassthroughManager(::android::hardware::getPassthroughServiceManager()) {
+}
+
+Lshal::Lshal(std::ostream &out, std::ostream &err,
+            sp<hidl::manager::V1_0::IServiceManager> serviceManager,
+            sp<hidl::manager::V1_0::IServiceManager> passthroughManager)
+    : mOut(out), mErr(err),
+      mServiceManager(serviceManager),
+      mPassthroughManager(passthroughManager) {
+
+}
+
+void Lshal::usage(const std::string &command) const {
+    static const std::string helpSummary =
+            "lshal: List and debug HALs.\n"
+            "\n"
+            "commands:\n"
+            "    help            Print help message\n"
+            "    list            list HALs\n"
+            "    debug           debug a specified HAL\n"
+            "\n"
+            "If no command is specified, `list` is the default.\n";
+
+    static const std::string list =
+            "list:\n"
+            "    lshal\n"
+            "    lshal list\n"
+            "        List all hals with default ordering and columns (`lshal list -ipc`)\n"
+            "    lshal list [-h|--help]\n"
+            "        -h, --help: Print help message for list (`lshal help list`)\n"
+            "    lshal [list] [--interface|-i] [--transport|-t] [-r|--arch]\n"
+            "            [--pid|-p] [--address|-a] [--clients|-c] [--cmdline|-m]\n"
+            "            [--sort={interface|i|pid|p}] [--init-vintf[=<output file>]]\n"
+            "            [--debug|-d[=<output file>]]\n"
+            "        -i, --interface: print the interface name column\n"
+            "        -n, --instance: print the instance name column\n"
+            "        -t, --transport: print the transport mode column\n"
+            "        -r, --arch: print if the HAL is in 64-bit or 32-bit\n"
+            "        -p, --pid: print the server PID, or server cmdline if -m is set\n"
+            "        -a, --address: print the server object address column\n"
+            "        -c, --clients: print the client PIDs, or client cmdlines if -m is set\n"
+            "        -m, --cmdline: print cmdline instead of PIDs\n"
+            "        -d[=<output file>], --debug[=<output file>]: emit debug info from \n"
+            "                IBase::debug with empty options\n"
+            "        --sort=i, --sort=interface: sort by interface name\n"
+            "        --sort=p, --sort=pid: sort by server pid\n"
+            "        --init-vintf=<output file>: form a skeleton HAL manifest to specified\n"
+            "                      file, or stdout if no file specified.\n";
+
+    static const std::string debug =
+            "debug:\n"
+            "    lshal debug <interface> [options [options [...]]] \n"
+            "        Print debug information of a specified interface.\n"
+            "        <inteface>: Format is `android.hardware.foo@1.0::IFoo/default`.\n"
+            "            If instance name is missing `default` is used.\n"
+            "        options: space separated options to IBase::debug.\n";
+
+    static const std::string help =
+            "help:\n"
+            "    lshal -h\n"
+            "    lshal --help\n"
+            "    lshal help\n"
+            "        Print this help message\n"
+            "    lshal help list\n"
+            "        Print help message for list\n"
+            "    lshal help debug\n"
+            "        Print help message for debug\n";
+
+    if (command == "list") {
+        mErr << list;
+        return;
+    }
+    if (command == "debug") {
+        mErr << debug;
+        return;
+    }
+
+    mErr << helpSummary << "\n" << list << "\n" << debug << "\n" << help;
+}
+
+// A unique_ptr type using a custom deleter function.
+template<typename T>
+using deleted_unique_ptr = std::unique_ptr<T, std::function<void(T *)> >;
+
+static hardware::hidl_vec<hardware::hidl_string> convert(const std::vector<std::string> &v) {
+    hardware::hidl_vec<hardware::hidl_string> hv;
+    hv.resize(v.size());
+    for (size_t i = 0; i < v.size(); ++i) {
+        hv[i].setToExternal(v[i].c_str(), v[i].size());
+    }
+    return hv;
+}
+
+Status Lshal::emitDebugInfo(
+        const std::string &interfaceName,
+        const std::string &instanceName,
+        const std::vector<std::string> &options,
+        std::ostream &out,
+        NullableOStream<std::ostream> err) const {
+    using android::hidl::base::V1_0::IBase;
+
+    hardware::Return<sp<IBase>> retBase = serviceManager()->get(interfaceName, instanceName);
+
+    if (!retBase.isOk()) {
+        std::string msg = "Cannot get " + interfaceName + "/" + instanceName + ": "
+                + retBase.description();
+        err << msg << std::endl;
+        LOG(ERROR) << msg;
+        return TRANSACTION_ERROR;
+    }
+
+    sp<IBase> base = retBase;
+    if (base == nullptr) {
+        std::string msg = interfaceName + "/" + instanceName + " does not exist, or "
+                + "no permission to connect.";
+        err << msg << std::endl;
+        LOG(ERROR) << msg;
+        return NO_INTERFACE;
+    }
+
+    PipeRelay relay(out);
+
+    if (relay.initCheck() != OK) {
+        std::string msg = "PipeRelay::initCheck() FAILED w/ " + std::to_string(relay.initCheck());
+        err << msg << std::endl;
+        LOG(ERROR) << msg;
+        return IO_ERROR;
+    }
+
+    deleted_unique_ptr<native_handle_t> fdHandle(
+        native_handle_create(1 /* numFds */, 0 /* numInts */),
+        native_handle_delete);
+
+    fdHandle->data[0] = relay.fd();
+
+    hardware::Return<void> ret = base->debug(fdHandle.get(), convert(options));
+
+    if (!ret.isOk()) {
+        std::string msg = "debug() FAILED on " + interfaceName + "/" + instanceName + ": "
+                + ret.description();
+        err << msg << std::endl;
+        LOG(ERROR) << msg;
+        return TRANSACTION_ERROR;
+    }
+    return OK;
+}
+
+Status Lshal::parseArgs(const Arg &arg) {
+    static std::set<std::string> sAllCommands{"list", "debug", "help"};
+    optind = 1;
+    if (optind >= arg.argc) {
+        // no options at all.
+        return OK;
+    }
+    mCommand = arg.argv[optind];
+    if (sAllCommands.find(mCommand) != sAllCommands.end()) {
+        ++optind;
+        return OK; // mCommand is set correctly
+    }
+
+    if (mCommand.size() > 0 && mCommand[0] == '-') {
+        // first argument is an option, set command to "" (which is recognized as "list")
+        mCommand = "";
+        return OK;
+    }
+
+    mErr << arg.argv[0] << ": unrecognized option `" << arg.argv[optind] << "`" << std::endl;
+    usage();
+    return USAGE;
+}
+
+void signalHandler(int sig) {
+    if (sig == SIGINT) {
+        int retVal;
+        pthread_exit(&retVal);
+    }
+}
+
+Status Lshal::main(const Arg &arg) {
+    // Allow SIGINT to terminate all threads.
+    signal(SIGINT, signalHandler);
+
+    Status status = parseArgs(arg);
+    if (status != OK) {
+        return status;
+    }
+    if (mCommand == "help") {
+        usage(optind < arg.argc ? arg.argv[optind] : "");
+        return USAGE;
+    }
+    // Default command is list
+    if (mCommand == "list" || mCommand == "") {
+        return ListCommand{*this}.main(mCommand, arg);
+    }
+    if (mCommand == "debug") {
+        return DebugCommand{*this}.main(mCommand, arg);
+    }
+    usage();
+    return USAGE;
+}
+
+NullableOStream<std::ostream> Lshal::err() const {
+    return mErr;
+}
+NullableOStream<std::ostream> Lshal::out() const {
+    return mOut;
+}
+
+const sp<IServiceManager> &Lshal::serviceManager() const {
+    return mServiceManager;
+}
+
+const sp<IServiceManager> &Lshal::passthroughManager() const {
+    return mPassthroughManager;
+}
+
+}  // namespace lshal
+}  // namespace android
diff --git a/cmds/lshal/Lshal.h b/cmds/lshal/Lshal.h
new file mode 100644
index 0000000..00db5d0
--- /dev/null
+++ b/cmds/lshal/Lshal.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_LSHAL_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_LSHAL_H_
+
+#include <iostream>
+#include <string>
+
+#include <android-base/macros.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <utils/StrongPointer.h>
+
+#include "NullableOStream.h"
+#include "utils.h"
+
+namespace android {
+namespace lshal {
+
+class Lshal {
+public:
+    Lshal();
+    Lshal(std::ostream &out, std::ostream &err,
+            sp<hidl::manager::V1_0::IServiceManager> serviceManager,
+            sp<hidl::manager::V1_0::IServiceManager> passthroughManager);
+    Status main(const Arg &arg);
+    void usage(const std::string &command = "") const;
+    NullableOStream<std::ostream> err() const;
+    NullableOStream<std::ostream> out() const;
+    const sp<hidl::manager::V1_0::IServiceManager> &serviceManager() const;
+    const sp<hidl::manager::V1_0::IServiceManager> &passthroughManager() const;
+
+    Status emitDebugInfo(
+            const std::string &interfaceName,
+            const std::string &instanceName,
+            const std::vector<std::string> &options,
+            std::ostream &out,
+            NullableOStream<std::ostream> err) const;
+private:
+    Status parseArgs(const Arg &arg);
+    std::string mCommand;
+    Arg mCmdArgs;
+    NullableOStream<std::ostream> mOut;
+    NullableOStream<std::ostream> mErr;
+
+    sp<hidl::manager::V1_0::IServiceManager> mServiceManager;
+    sp<hidl::manager::V1_0::IServiceManager> mPassthroughManager;
+
+    DISALLOW_COPY_AND_ASSIGN(Lshal);
+};
+
+}  // namespace lshal
+}  // namespace android
+
+#endif  // FRAMEWORK_NATIVE_CMDS_LSHAL_LSHAL_H_
diff --git a/cmds/lshal/NullableOStream.h b/cmds/lshal/NullableOStream.h
new file mode 100644
index 0000000..ab37a04
--- /dev/null
+++ b/cmds/lshal/NullableOStream.h
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_NULLABLE_O_STREAM_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_NULLABLE_O_STREAM_H_
+
+#include <iostream>
+
+namespace android {
+namespace lshal {
+
+template<typename S>
+class NullableOStream {
+public:
+    NullableOStream(S &os) : mOs(&os) {}
+    NullableOStream(S *os) : mOs(os) {}
+    NullableOStream &operator=(S &os) {
+        mOs = &os;
+        return *this;
+    }
+    NullableOStream &operator=(S *os) {
+        mOs = os;
+        return *this;
+    }
+    template<typename Other>
+    NullableOStream &operator=(const NullableOStream<Other> &other) {
+        mOs = other.mOs;
+        return *this;
+    }
+
+    const NullableOStream &operator<<(std::ostream& (*pf)(std::ostream&)) const {
+        if (mOs) {
+            (*mOs) << pf;
+        }
+        return *this;
+    }
+    template<typename T>
+    const NullableOStream &operator<<(const T &rhs) const {
+        if (mOs) {
+            (*mOs) << rhs;
+        }
+        return *this;
+    }
+    S& buf() const {
+        return *mOs;
+    }
+    operator bool() const {
+        return mOs != nullptr;
+    }
+private:
+    template<typename>
+    friend class NullableOStream;
+
+    S *mOs = nullptr;
+};
+
+}  // namespace lshal
+}  // namespace android
+
+#endif  // FRAMEWORK_NATIVE_CMDS_LSHAL_NULLABLE_O_STREAM_H_
diff --git a/cmds/lshal/PipeRelay.cpp b/cmds/lshal/PipeRelay.cpp
new file mode 100644
index 0000000..54d19f6
--- /dev/null
+++ b/cmds/lshal/PipeRelay.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PipeRelay.h"
+
+#include <sys/socket.h>
+#include <utils/Thread.h>
+
+namespace android {
+namespace lshal {
+
+struct PipeRelay::RelayThread : public Thread {
+    explicit RelayThread(int fd, std::ostream &os);
+
+    bool threadLoop() override;
+
+private:
+    int mFd;
+    std::ostream &mOutStream;
+
+    DISALLOW_COPY_AND_ASSIGN(RelayThread);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+PipeRelay::RelayThread::RelayThread(int fd, std::ostream &os)
+    : mFd(fd),
+      mOutStream(os) {
+}
+
+bool PipeRelay::RelayThread::threadLoop() {
+    char buffer[1024];
+    ssize_t n = read(mFd, buffer, sizeof(buffer));
+
+    if (n <= 0) {
+        return false;
+    }
+
+    mOutStream.write(buffer, n);
+
+    return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+PipeRelay::PipeRelay(std::ostream &os)
+    : mOutStream(os),
+      mInitCheck(NO_INIT) {
+    int res = socketpair(AF_UNIX, SOCK_STREAM, 0 /* protocol */, mFds);
+
+    if (res < 0) {
+        mInitCheck = -errno;
+        return;
+    }
+
+    mThread = new RelayThread(mFds[0], os);
+    mInitCheck = mThread->run("RelayThread");
+}
+
+void PipeRelay::CloseFd(int *fd) {
+    if (*fd >= 0) {
+        close(*fd);
+        *fd = -1;
+    }
+}
+
+PipeRelay::~PipeRelay() {
+    if (mFds[1] >= 0) {
+        shutdown(mFds[1], SHUT_WR);
+    }
+
+    if (mFds[0] >= 0) {
+        shutdown(mFds[0], SHUT_RD);
+    }
+
+    if (mThread != NULL) {
+        mThread->join();
+        mThread.clear();
+    }
+
+    CloseFd(&mFds[1]);
+    CloseFd(&mFds[0]);
+}
+
+status_t PipeRelay::initCheck() const {
+    return mInitCheck;
+}
+
+int PipeRelay::fd() const {
+    return mFds[1];
+}
+
+}  // namespace lshal
+}  // namespace android
diff --git a/cmds/lshal/PipeRelay.h b/cmds/lshal/PipeRelay.h
new file mode 100644
index 0000000..76b2b23
--- /dev/null
+++ b/cmds/lshal/PipeRelay.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_
+
+#define FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_
+
+#include <android-base/macros.h>
+#include <ostream>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+namespace android {
+namespace lshal {
+
+/* Creates an AF_UNIX socketpair and spawns a thread that relays any data
+ * written to the "write"-end of the pair to the specified output stream "os".
+ */
+struct PipeRelay {
+    explicit PipeRelay(std::ostream &os);
+    ~PipeRelay();
+
+    status_t initCheck() const;
+
+    // Returns the file descriptor corresponding to the "write"-end of the
+    // connection.
+    int fd() const;
+
+private:
+    struct RelayThread;
+
+    std::ostream &mOutStream;
+    status_t mInitCheck;
+    int mFds[2];
+    sp<RelayThread> mThread;
+
+    static void CloseFd(int *fd);
+
+    DISALLOW_COPY_AND_ASSIGN(PipeRelay);
+};
+
+}  // namespace lshal
+}  // namespace android
+
+#endif  // FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_
+
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
new file mode 100644
index 0000000..9ae8f78
--- /dev/null
+++ b/cmds/lshal/TableEntry.h
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_TABLE_ENTRY_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_TABLE_ENTRY_H_
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+#include <iostream>
+
+namespace android {
+namespace lshal {
+
+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;
+
+struct TableEntry {
+    std::string interfaceName;
+    std::string transport;
+    int32_t serverPid;
+    std::string serverCmdline;
+    uint64_t serverObjectAddress;
+    Pids clientPids;
+    std::vector<std::string> clientCmdlines;
+    Architecture arch;
+
+    static bool sortByInterfaceName(const TableEntry &a, const TableEntry &b) {
+        return a.interfaceName < b.interfaceName;
+    };
+    static bool sortByServerPid(const TableEntry &a, const TableEntry &b) {
+        return a.serverPid < b.serverPid;
+    };
+};
+
+struct Table {
+    using Entries = std::vector<TableEntry>;
+    std::string description;
+    Entries entries;
+
+    Entries::iterator begin() { return entries.begin(); }
+    Entries::const_iterator begin() const { return entries.begin(); }
+    Entries::iterator end() { return entries.end(); }
+    Entries::const_iterator end() const { return entries.end(); }
+};
+
+using TableEntryCompare = std::function<bool(const TableEntry &, const TableEntry &)>;
+
+enum : unsigned int {
+    ENABLE_INTERFACE_NAME = 1 << 0,
+    ENABLE_TRANSPORT      = 1 << 1,
+    ENABLE_SERVER_PID     = 1 << 2,
+    ENABLE_SERVER_ADDR    = 1 << 3,
+    ENABLE_CLIENT_PIDS    = 1 << 4,
+    ENABLE_ARCH           = 1 << 5
+};
+
+using TableEntrySelect = unsigned int;
+
+enum {
+    NO_PID = -1,
+    NO_PTR = 0
+};
+
+}  // namespace lshal
+}  // namespace android
+
+#endif  // FRAMEWORK_NATIVE_CMDS_LSHAL_TABLE_ENTRY_H_
diff --git a/cmds/lshal/Timeout.h b/cmds/lshal/Timeout.h
new file mode 100644
index 0000000..ca477bf
--- /dev/null
+++ b/cmds/lshal/Timeout.h
@@ -0,0 +1,97 @@
+/*
+ * 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 <condition_variable>
+#include <chrono>
+#include <functional>
+#include <mutex>
+#include <thread>
+
+#include <hidl/Status.h>
+
+namespace android {
+namespace lshal {
+
+static constexpr std::chrono::milliseconds IPC_CALL_WAIT{500};
+
+class BackgroundTaskState {
+public:
+    BackgroundTaskState(std::function<void(void)> &&func)
+            : mFunc(std::forward<decltype(func)>(func)) {}
+    void notify() {
+        std::unique_lock<std::mutex> lock(mMutex);
+        mFinished = true;
+        lock.unlock();
+        mCondVar.notify_all();
+    }
+    template<class C, class D>
+    bool wait(std::chrono::time_point<C, D> end) {
+        std::unique_lock<std::mutex> lock(mMutex);
+        mCondVar.wait_until(lock, end, [this](){ return this->mFinished; });
+        return mFinished;
+    }
+    void operator()() {
+        mFunc();
+    }
+private:
+    std::mutex mMutex;
+    std::condition_variable mCondVar;
+    bool mFinished = false;
+    std::function<void(void)> mFunc;
+};
+
+void *callAndNotify(void *data) {
+    BackgroundTaskState &state = *static_cast<BackgroundTaskState *>(data);
+    state();
+    state.notify();
+    return NULL;
+}
+
+template<class R, class P>
+bool timeout(std::chrono::duration<R, P> delay, std::function<void(void)> &&func) {
+    auto now = std::chrono::system_clock::now();
+    BackgroundTaskState state{std::forward<decltype(func)>(func)};
+    pthread_t thread;
+    if (pthread_create(&thread, NULL, callAndNotify, &state)) {
+        std::cerr << "FATAL: could not create background thread." << std::endl;
+        return false;
+    }
+    bool success = state.wait(now + delay);
+    if (!success) {
+        pthread_kill(thread, SIGINT);
+    }
+    pthread_join(thread, NULL);
+    return success;
+}
+
+template<class Function, class I, class... Args>
+typename std::result_of<Function(I *, Args...)>::type
+timeoutIPC(const sp<I> &interfaceObject, Function &&func, Args &&... args) {
+    using ::android::hardware::Status;
+    typename std::result_of<Function(I *, Args...)>::type ret{Status::ok()};
+    auto boundFunc = std::bind(std::forward<Function>(func),
+            interfaceObject.get(), std::forward<Args>(args)...);
+    bool success = timeout(IPC_CALL_WAIT, [&ret, &boundFunc] {
+        ret = std::move(boundFunc());
+    });
+    if (!success) {
+        return Status::fromStatusT(TIMED_OUT);
+    }
+    return ret;
+}
+
+}  // namespace lshal
+}  // namespace android
diff --git a/cmds/lshal/main.cpp b/cmds/lshal/main.cpp
new file mode 100644
index 0000000..366c938
--- /dev/null
+++ b/cmds/lshal/main.cpp
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Lshal.h"
+
+int main(int argc, char **argv) {
+    using namespace ::android::lshal;
+    return Lshal{}.main(Arg{argc, argv});
+}
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
new file mode 100644
index 0000000..972d508
--- /dev/null
+++ b/cmds/lshal/test.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Lshal"
+#include <android-base/logging.h>
+
+#include <sstream>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+#include <android/hardware/tests/baz/1.0/IQuux.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "Lshal.h"
+
+#define NELEMS(array)   static_cast<int>(sizeof(array) / sizeof(array[0]))
+
+using namespace testing;
+
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hidl::manager::V1_0::IServiceManager;
+using ::android::hidl::manager::V1_0::IServiceNotification;
+using ::android::hardware::hidl_death_recipient;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+
+namespace android {
+namespace hardware {
+namespace tests {
+namespace baz {
+namespace V1_0 {
+namespace implementation {
+struct Quux : android::hardware::tests::baz::V1_0::IQuux {
+    ::android::hardware::Return<void> debug(const hidl_handle& hh, const hidl_vec<hidl_string>& options) override {
+        const native_handle_t *handle = hh.getNativeHandle();
+        if (handle->numFds < 1) {
+            return Void();
+        }
+        int fd = handle->data[0];
+        std::string content{descriptor};
+        for (const auto &option : options) {
+            content += "\n";
+            content += option.c_str();
+        }
+        ssize_t written = write(fd, content.c_str(), content.size());
+        if (written != (ssize_t)content.size()) {
+            LOG(WARNING) << "SERVER(Quux) debug writes " << written << " bytes < "
+                    << content.size() << " bytes, errno = " << errno;
+        }
+        return Void();
+    }
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace baz
+} // namespace tests
+} // namespace hardware
+
+namespace lshal {
+
+
+class MockServiceManager : public IServiceManager {
+public:
+    template<typename T>
+    using R = ::android::hardware::Return<T>;
+    using String = const hidl_string&;
+    ~MockServiceManager() = default;
+
+#define MOCK_METHOD_CB(name) MOCK_METHOD1(name, R<void>(IServiceManager::name##_cb))
+
+    MOCK_METHOD2(get, R<sp<IBase>>(String, String));
+    MOCK_METHOD2(add, R<bool>(String, const sp<IBase>&));
+    MOCK_METHOD2(getTransport, R<IServiceManager::Transport>(String, String));
+    MOCK_METHOD_CB(list);
+    MOCK_METHOD2(listByInterface, R<void>(String, listByInterface_cb));
+    MOCK_METHOD3(registerForNotifications, R<bool>(String, String, const sp<IServiceNotification>&));
+    MOCK_METHOD_CB(debugDump);
+    MOCK_METHOD2(registerPassthroughClient, R<void>(String, String));
+    MOCK_METHOD_CB(interfaceChain);
+    MOCK_METHOD2(debug, R<void>(const hidl_handle&, const hidl_vec<hidl_string>&));
+    MOCK_METHOD_CB(interfaceDescriptor);
+    MOCK_METHOD_CB(getHashChain);
+    MOCK_METHOD0(setHalInstrumentation, R<void>());
+    MOCK_METHOD2(linkToDeath, R<bool>(const sp<hidl_death_recipient>&, uint64_t));
+    MOCK_METHOD0(ping, R<void>());
+    MOCK_METHOD_CB(getDebugInfo);
+    MOCK_METHOD0(notifySyspropsChanged, R<void>());
+    MOCK_METHOD1(unlinkToDeath, R<bool>(const sp<hidl_death_recipient>&));
+
+};
+
+class LshalTest : public ::testing::Test {
+public:
+    void SetUp() override {
+        using ::android::hardware::tests::baz::V1_0::IQuux;
+        using ::android::hardware::tests::baz::V1_0::implementation::Quux;
+
+        err.str("");
+        out.str("");
+        serviceManager = new testing::NiceMock<MockServiceManager>();
+        ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
+            [](const auto &iface, const auto &inst) -> ::android::hardware::Return<sp<IBase>> {
+                if (iface == IQuux::descriptor && inst == "default")
+                    return new Quux();
+                return nullptr;
+            }));
+    }
+    void TearDown() override {}
+
+    std::stringstream err;
+    std::stringstream out;
+    sp<MockServiceManager> serviceManager;
+};
+
+TEST_F(LshalTest, Debug) {
+    const char *args[] = {
+        "lshal", "debug", "android.hardware.tests.baz@1.0::IQuux/default", "foo", "bar"
+    };
+    EXPECT_EQ(0u, Lshal(out, err, serviceManager, serviceManager)
+            .main({NELEMS(args), const_cast<char **>(args)}));
+    EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz@1.0::IQuux\nfoo\nbar"));
+    EXPECT_THAT(err.str(), IsEmpty());
+}
+
+TEST_F(LshalTest, Debug2) {
+    const char *args[] = {
+        "lshal", "debug", "android.hardware.tests.baz@1.0::IQuux", "baz", "quux"
+    };
+    EXPECT_EQ(0u, Lshal(out, err, serviceManager, serviceManager)
+            .main({NELEMS(args), const_cast<char **>(args)}));
+    EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz@1.0::IQuux\nbaz\nquux"));
+    EXPECT_THAT(err.str(), IsEmpty());
+}
+
+TEST_F(LshalTest, Debug3) {
+    const char *args[] = {
+        "lshal", "debug", "android.hardware.tests.doesnotexist@1.0::IDoesNotExist",
+    };
+    EXPECT_NE(0u, Lshal(out, err, serviceManager, serviceManager)
+            .main({NELEMS(args), const_cast<char **>(args)}));
+    EXPECT_THAT(err.str(), HasSubstr("does not exist"));
+}
+
+} // namespace lshal
+} // namespace android
+
+int main(int argc, char **argv) {
+    ::testing::InitGoogleMock(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/cmds/lshal/utils.cpp b/cmds/lshal/utils.cpp
new file mode 100644
index 0000000..5550721
--- /dev/null
+++ b/cmds/lshal/utils.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "utils.h"
+
+namespace android {
+namespace lshal {
+
+std::string toHexString(uint64_t t) {
+    std::ostringstream os;
+    os << std::hex << std::setfill('0') << std::setw(16) << t;
+    return os.str();
+}
+
+std::vector<std::string> split(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;
+}
+
+void replaceAll(std::string *s, char from, char to) {
+    for (size_t i = 0; i < s->size(); ++i) {
+        if (s->at(i) == from) {
+            s->at(i) = to;
+        }
+    }
+}
+
+}  // namespace lshal
+}  // namespace android
+
diff --git a/cmds/lshal/utils.h b/cmds/lshal/utils.h
new file mode 100644
index 0000000..45b922c
--- /dev/null
+++ b/cmds/lshal/utils.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_UTILS_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_UTILS_H_
+
+#include <iomanip>
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <utility>
+#include <vector>
+
+namespace android {
+namespace lshal {
+
+enum : unsigned int {
+    OK                                      = 0,
+    USAGE                                   = 1 << 0,
+    NO_BINDERIZED_MANAGER                   = 1 << 1,
+    NO_PASSTHROUGH_MANAGER                  = 1 << 2,
+    DUMP_BINDERIZED_ERROR                   = 1 << 3,
+    DUMP_PASSTHROUGH_ERROR                  = 1 << 4,
+    DUMP_ALL_LIBS_ERROR                     = 1 << 5,
+    IO_ERROR                                = 1 << 6,
+    NO_INTERFACE                            = 1 << 7,
+    TRANSACTION_ERROR                       = 1 << 8,
+};
+using Status = unsigned int;
+
+struct Arg {
+    int argc;
+    char **argv;
+};
+
+template <typename A>
+std::string join(const A &components, const std::string &separator) {
+    std::stringstream out;
+    bool first = true;
+    for (const auto &component : components) {
+        if (!first) {
+            out << separator;
+        }
+        out << component;
+
+        first = false;
+    }
+    return out.str();
+}
+
+std::string toHexString(uint64_t t);
+
+template<typename String>
+std::pair<String, String> splitFirst(const String &s, char c) {
+    const char *pos = strchr(s.c_str(), c);
+    if (pos == nullptr) {
+        return {s, {}};
+    }
+    return {String(s.c_str(), pos - s.c_str()), String(pos + 1)};
+}
+
+std::vector<std::string> split(const std::string &s, char c);
+
+void replaceAll(std::string *s, char from, char to);
+
+}  // namespace lshal
+}  // namespace android
+
+#endif  // FRAMEWORK_NATIVE_CMDS_LSHAL_UTILS_H_
diff --git a/cmds/service/Android.bp b/cmds/service/Android.bp
new file mode 100644
index 0000000..b703ed4
--- /dev/null
+++ b/cmds/service/Android.bp
@@ -0,0 +1,26 @@
+cc_binary {
+    name: "service",
+
+    srcs: ["service.cpp"],
+
+    shared_libs: [
+        "libutils",
+        "libbinder",
+    ],
+
+    cflags: ["-DXP_UNIX"],
+}
+
+cc_binary {
+    name: "vndservice",
+
+    proprietary: true,
+    srcs: ["service.cpp"],
+
+    shared_libs: [
+        "libutils",
+        "libbinder",
+    ],
+
+    cflags: ["-DXP_UNIX", "-DVENDORSERVICES"],
+}
diff --git a/cmds/service/Android.mk b/cmds/service/Android.mk
deleted file mode 100644
index 275bbb2..0000000
--- a/cmds/service/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	service.cpp
-
-LOCAL_SHARED_LIBRARIES := libutils libbinder
-
-ifeq ($(TARGET_OS),linux)
-	LOCAL_CFLAGS += -DXP_UNIX
-	#LOCAL_SHARED_LIBRARIES += librt
-endif
-
-LOCAL_MODULE:= service
-
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/service/service.cpp b/cmds/service/service.cpp
index 428b87c..bc11256 100644
--- a/cmds/service/service.cpp
+++ b/cmds/service/service.cpp
@@ -68,13 +68,6 @@
 
 int main(int argc, char* const argv[])
 {
-    sp<IServiceManager> sm = defaultServiceManager();
-    fflush(stdout);
-    if (sm == NULL) {
-        aerr << "service: Unable to get default service manager!" << endl;
-        return 20;
-    }
-    
     bool wantsUsage = false;
     int result = 0;
     
@@ -95,6 +88,15 @@
             break;
         }
     }
+#ifdef VENDORSERVICES
+    ProcessState::initWithDriver("/dev/vndbinder");
+#endif
+    sp<IServiceManager> sm = defaultServiceManager();
+    fflush(stdout);
+    if (sm == NULL) {
+        aerr << "service: Unable to get default service manager!" << endl;
+        return 20;
+    }
     
     if (optind >= argc) {
         wantsUsage = true;
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
new file mode 100644
index 0000000..39d92a7
--- /dev/null
+++ b/cmds/servicemanager/Android.bp
@@ -0,0 +1,52 @@
+cc_defaults {
+    name: "servicemanager_flags",
+
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    product_variables: {
+        binder32bit: {
+            cflags: ["-DBINDER_IPC_32BIT=1"],
+        },
+    },
+
+    shared_libs: ["liblog"],
+}
+
+cc_binary {
+    name: "bctest",
+    defaults: ["servicemanager_flags"],
+    srcs: [
+        "bctest.c",
+        "binder.c",
+    ],
+}
+
+cc_binary {
+    name: "servicemanager",
+    defaults: ["servicemanager_flags"],
+    srcs: [
+        "service_manager.c",
+        "binder.c",
+    ],
+    shared_libs: ["libcutils", "libselinux"],
+    init_rc: ["servicemanager.rc"],
+}
+
+cc_binary {
+    name: "vndservicemanager",
+    defaults: ["servicemanager_flags"],
+    vendor: true,
+    srcs: [
+        "service_manager.c",
+        "binder.c",
+    ],
+    cflags: [
+        "-DVENDORSERVICEMANAGER=1",
+    ],
+    shared_libs: ["libcutils"],
+    static_libs: ["libselinux"],
+    init_rc: ["vndservicemanager.rc"],
+}
diff --git a/cmds/servicemanager/Android.mk b/cmds/servicemanager/Android.mk
deleted file mode 100644
index b214f19..0000000
--- a/cmds/servicemanager/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-svc_c_flags =	\
-	-Wall -Wextra -Werror \
-
-ifneq ($(TARGET_USES_64_BIT_BINDER),true)
-ifneq ($(TARGET_IS_64_BIT),true)
-svc_c_flags += -DBINDER_IPC_32BIT=1
-endif
-endif
-
-include $(CLEAR_VARS)
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_SRC_FILES := bctest.c binder.c
-LOCAL_CFLAGS += $(svc_c_flags)
-LOCAL_MODULE := bctest
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-LOCAL_SHARED_LIBRARIES := liblog libcutils libselinux
-LOCAL_SRC_FILES := service_manager.c binder.c
-LOCAL_CFLAGS += $(svc_c_flags)
-LOCAL_MODULE := servicemanager
-LOCAL_INIT_RC := servicemanager.rc
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/servicemanager/bctest.c b/cmds/servicemanager/bctest.c
index 6466654..354df67 100644
--- a/cmds/servicemanager/bctest.c
+++ b/cmds/servicemanager/bctest.c
@@ -62,7 +62,7 @@
     uint32_t svcmgr = BINDER_SERVICE_MANAGER;
     uint32_t handle;
 
-    bs = binder_open(128*1024);
+    bs = binder_open("/dev/binder", 128*1024);
     if (!bs) {
         fprintf(stderr, "failed to open binder driver\n");
         return -1;
diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c
index 27c461a..93a18fc 100644
--- a/cmds/servicemanager/binder.c
+++ b/cmds/servicemanager/binder.c
@@ -1,14 +1,18 @@
 /* Copyright 2008 The Android Open Source Project
  */
 
+#define LOG_TAG "Binder"
+
+#include <errno.h>
+#include <fcntl.h>
 #include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
 #include <sys/mman.h>
+#include <unistd.h>
+
+#include <log/log.h>
 
 #include "binder.h"
 
@@ -16,9 +20,6 @@
 
 #define TRACE 0
 
-#define LOG_TAG "Binder"
-#include <cutils/log.h>
-
 void bio_init_from_txn(struct binder_io *io, struct binder_transaction_data *txn);
 
 #if TRACE
@@ -93,7 +94,7 @@
     size_t mapsize;
 };
 
-struct binder_state *binder_open(size_t mapsize)
+struct binder_state *binder_open(const char* driver, size_t mapsize)
 {
     struct binder_state *bs;
     struct binder_version vers;
@@ -104,10 +105,10 @@
         return NULL;
     }
 
-    bs->fd = open("/dev/binder", O_RDWR | O_CLOEXEC);
+    bs->fd = open(driver, O_RDWR | O_CLOEXEC);
     if (bs->fd < 0) {
-        fprintf(stderr,"binder: cannot open device (%s)\n",
-                strerror(errno));
+        fprintf(stderr,"binder: cannot open %s (%s)\n",
+                driver, strerror(errno));
         goto fail_open;
     }
 
diff --git a/cmds/servicemanager/binder.h b/cmds/servicemanager/binder.h
index 7915fc2..c95b33f 100644
--- a/cmds/servicemanager/binder.h
+++ b/cmds/servicemanager/binder.h
@@ -5,7 +5,7 @@
 #define _BINDER_H_
 
 #include <sys/ioctl.h>
-#include <linux/binder.h>
+#include <linux/android/binder.h>
 
 struct binder_state;
 
@@ -46,7 +46,7 @@
                               struct binder_io *msg,
                               struct binder_io *reply);
 
-struct binder_state *binder_open(size_t mapsize);
+struct binder_state *binder_open(const char* driver, size_t mapsize);
 void binder_close(struct binder_state *bs);
 
 /* initiate a blocking binder call
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 68e3ceb..45bb1d0 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -17,13 +17,12 @@
 
 #include "binder.h"
 
-#if 0
-#define ALOGI(x...) fprintf(stderr, "svcmgr: " x)
-#define ALOGE(x...) fprintf(stderr, "svcmgr: " x)
+#ifdef VENDORSERVICEMANAGER
+#define LOG_TAG "VendorServiceManager"
 #else
 #define LOG_TAG "ServiceManager"
-#include <cutils/log.h>
 #endif
+#include <log/log.h>
 
 struct audit_data {
     pid_t pid;
@@ -60,7 +59,6 @@
     return 1;
 }
 
-static int selinux_enabled;
 static char *service_manager_context;
 static struct selabel_handle* sehandle;
 
@@ -89,10 +87,6 @@
 
 static bool check_mac_perms_from_getcon(pid_t spid, uid_t uid, const char *perm)
 {
-    if (selinux_enabled <= 0) {
-        return true;
-    }
-
     return check_mac_perms(spid, uid, service_manager_context, perm, NULL);
 }
 
@@ -101,10 +95,6 @@
     bool allowed;
     char *tctx = NULL;
 
-    if (selinux_enabled <= 0) {
-        return true;
-    }
-
     if (!sehandle) {
         ALOGE("SELinux: Failed to find sehandle. Aborting service_manager.\n");
         abort();
@@ -369,13 +359,28 @@
     return 0;
 }
 
-int main()
+int main(int argc, char** argv)
 {
     struct binder_state *bs;
+    union selinux_callback cb;
+    char *driver;
 
-    bs = binder_open(128*1024);
+    if (argc > 1) {
+        driver = argv[1];
+    } else {
+        driver = "/dev/binder";
+    }
+
+    bs = binder_open(driver, 128*1024);
     if (!bs) {
-        ALOGE("failed to open binder driver\n");
+#ifdef VENDORSERVICEMANAGER
+        ALOGW("failed to open binder driver %s\n", driver);
+        while (true) {
+            sleep(UINT_MAX);
+        }
+#else
+        ALOGE("failed to open binder driver %s\n", driver);
+#endif
         return -1;
     }
 
@@ -384,28 +389,29 @@
         return -1;
     }
 
-    selinux_enabled = is_selinux_enabled();
-    sehandle = selinux_android_service_context_handle();
-    selinux_status_open(true);
-
-    if (selinux_enabled > 0) {
-        if (sehandle == NULL) {
-            ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");
-            abort();
-        }
-
-        if (getcon(&service_manager_context) != 0) {
-            ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
-            abort();
-        }
-    }
-
-    union selinux_callback cb;
     cb.func_audit = audit_callback;
     selinux_set_callback(SELINUX_CB_AUDIT, cb);
     cb.func_log = selinux_log_callback;
     selinux_set_callback(SELINUX_CB_LOG, cb);
 
+#ifdef VENDORSERVICEMANAGER
+    sehandle = selinux_android_vendor_service_context_handle();
+#else
+    sehandle = selinux_android_service_context_handle();
+#endif
+    selinux_status_open(true);
+
+    if (sehandle == NULL) {
+        ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");
+        abort();
+    }
+
+    if (getcon(&service_manager_context) != 0) {
+        ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
+        abort();
+    }
+
+
     binder_loop(bs, svcmgr_handler);
 
     return 0;
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index aee7bd8..aec211a 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -1,5 +1,5 @@
 service servicemanager /system/bin/servicemanager
-    class core
+    class core animation
     user system
     group system readproc
     critical
@@ -12,4 +12,3 @@
     onrestart restart drm
     onrestart restart cameraserver
     writepid /dev/cpuset/system-background/tasks
-
diff --git a/cmds/servicemanager/vndservicemanager.rc b/cmds/servicemanager/vndservicemanager.rc
new file mode 100644
index 0000000..d5ddaaf
--- /dev/null
+++ b/cmds/servicemanager/vndservicemanager.rc
@@ -0,0 +1,6 @@
+service vndservicemanager /vendor/bin/vndservicemanager /dev/vndbinder
+    class core
+    user system
+    group system readproc
+    writepid /dev/cpuset/system-background/tasks
+
diff --git a/cmds/surfacereplayer/proto/Android.mk b/cmds/surfacereplayer/proto/Android.mk
new file mode 100644
index 0000000..3cf1148
--- /dev/null
+++ b/cmds/surfacereplayer/proto/Android.mk
@@ -0,0 +1,28 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-proto-files-under, src)
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := lite
+
+LOCAL_MODULE := libtrace_proto
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
new file mode 100644
index 0000000..0bc08a9
--- /dev/null
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -0,0 +1,179 @@
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+message Trace {
+    repeated Increment increment = 1;
+}
+
+message Increment {
+    required int64 time_stamp = 1;
+
+    oneof increment {
+        Transaction        transaction          = 2;
+        SurfaceCreation    surface_creation     = 3;
+        SurfaceDeletion    surface_deletion     = 4;
+        BufferUpdate       buffer_update        = 5;
+        VSyncEvent         vsync_event          = 6;
+        DisplayCreation    display_creation     = 7;
+        DisplayDeletion    display_deletion     = 8;
+        PowerModeUpdate    power_mode_update    = 9;
+    }
+}
+
+message Transaction {
+    repeated SurfaceChange surface_change = 1;
+    repeated DisplayChange display_change = 2;
+
+    required bool synchronous = 3;
+    required bool animation   = 4;
+}
+
+message SurfaceChange {
+    required int32 id = 1;
+
+    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;
+        LayerStackChange            layer_stack             = 11;
+        HiddenFlagChange            hidden_flag             = 12;
+        OpaqueFlagChange            opaque_flag             = 13;
+        SecureFlagChange            secure_flag             = 14;
+        DeferredTransactionChange   deferred_transaction    = 15;
+    }
+}
+
+message PositionChange {
+    required float x = 1;
+    required float y = 2;
+}
+
+message SizeChange {
+    required uint32 w = 1;
+    required uint32 h = 2;
+}
+
+message AlphaChange {
+    required float alpha = 1;
+}
+
+message LayerChange {
+    required uint32 layer = 1;
+}
+
+message CropChange {
+    required Rectangle rectangle = 1;
+}
+
+message FinalCropChange {
+    required Rectangle rectangle = 1;
+}
+
+message MatrixChange {
+    required float dsdx = 1;
+    required float dtdx = 2;
+    required float dsdy = 3;
+    required float dtdy = 4;
+}
+
+message OverrideScalingModeChange {
+    required int32 override_scaling_mode = 1;
+}
+
+message TransparentRegionHintChange {
+    repeated Rectangle region = 1;
+}
+
+message LayerStackChange {
+    required uint32 layer_stack = 1;
+}
+
+message HiddenFlagChange {
+    required bool hidden_flag = 1;
+}
+
+message OpaqueFlagChange {
+    required bool opaque_flag = 1;
+}
+
+message SecureFlagChange {
+    required bool secure_flag = 1;
+}
+
+message DeferredTransactionChange {
+    required int32  layer_id     = 1;
+    required uint64 frame_number = 2;
+}
+
+message DisplayChange {
+    required int32 id = 1;
+
+    oneof DisplayChange {
+        DispSurfaceChange surface     = 2;
+        LayerStackChange  layer_stack = 3;
+        SizeChange        size        = 4;
+        ProjectionChange  projection  = 5;
+    }
+}
+
+message DispSurfaceChange {
+    required uint64 buffer_queue_id   = 1;
+    required string buffer_queue_name = 2;
+}
+
+message ProjectionChange {
+    required int32     orientation = 1;
+    required Rectangle viewport    = 2;
+    required Rectangle frame       = 3;
+}
+
+message Rectangle {
+    required int32 left   = 1;
+    required int32 top    = 2;
+    required int32 right  = 3;
+    required int32 bottom = 4;
+}
+
+message SurfaceCreation {
+    required int32  id   = 1;
+    required string name = 2;
+    required uint32 w    = 3;
+    required uint32 h    = 4;
+}
+
+message SurfaceDeletion {
+    required int32 id = 1;
+}
+
+message BufferUpdate {
+    required int32  id           = 1;
+    required uint32 w            = 2;
+    required uint32 h            = 3;
+    required uint64 frame_number = 4;
+}
+
+message VSyncEvent {
+    required int64 when = 1;
+}
+
+message DisplayCreation {
+    required int32     id                = 1;
+    required string    name              = 2;
+    required int32     type              = 3;
+    required bool      is_secure         = 4;
+}
+
+message DisplayDeletion {
+    required int32 id = 1;
+}
+
+message PowerModeUpdate {
+    required int32  id   = 1;
+    required int32  mode = 2;
+}
diff --git a/cmds/surfacereplayer/replayer/Android.mk b/cmds/surfacereplayer/replayer/Android.mk
new file mode 100644
index 0000000..1dd926c
--- /dev/null
+++ b/cmds/surfacereplayer/replayer/Android.mk
@@ -0,0 +1,75 @@
+# 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.
+
+LOCAL_TARGET_DIR := $(TARGET_OUT_DATA)/local/tmp
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(call first-makefiles-under, /frameworks/native/cmds/surfacereplayer/proto)
+
+include $(CLEAR_VARS)
+
+LOCAL_CPPFLAGS := -Weverything -Werror
+LOCAL_CPPFLAGS := -Wno-unused-parameter
+LOCAL_CPPFLAGS := -Wno-format
+
+LOCAL_MODULE := libsurfacereplayer
+
+LOCAL_SRC_FILES := \
+    BufferQueueScheduler.cpp \
+    Event.cpp \
+    Replayer.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+    libEGL \
+    libGLESv2 \
+    libbinder \
+    liblog \
+    libcutils \
+    libgui \
+    libui \
+    libutils \
+    libprotobuf-cpp-lite \
+    libbase \
+    libnativewindow \
+
+LOCAL_STATIC_LIBRARIES := \
+    libtrace_proto \
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/..
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := surfacereplayer
+
+LOCAL_SRC_FILES := \
+    Main.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+    libprotobuf-cpp-lite \
+    libsurfacereplayer \
+    libutils \
+    libgui \
+
+LOCAL_STATIC_LIBRARIES := \
+    libtrace_proto \
+
+LOCAL_CPPFLAGS := -Weverything -Werror
+LOCAL_CPPFLAGS := -Wno-unused-parameter
+
+LOCAL_MODULE_PATH := $(LOCAL_TARGET_DIR)
+
+include $(BUILD_EXECUTABLE)
diff --git a/cmds/surfacereplayer/replayer/BufferQueueScheduler.cpp b/cmds/surfacereplayer/replayer/BufferQueueScheduler.cpp
new file mode 100644
index 0000000..77de8dc
--- /dev/null
+++ b/cmds/surfacereplayer/replayer/BufferQueueScheduler.cpp
@@ -0,0 +1,109 @@
+/*
+ * 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 "BufferQueueScheduler"
+
+#include "BufferQueueScheduler.h"
+
+#include <android/native_window.h>
+#include <gui/Surface.h>
+
+using namespace android;
+
+BufferQueueScheduler::BufferQueueScheduler(
+        const sp<SurfaceControl>& surfaceControl, const HSV& color, int id)
+      : mSurfaceControl(surfaceControl), mColor(color), mSurfaceId(id), mContinueScheduling(true) {}
+
+void BufferQueueScheduler::startScheduling() {
+    ALOGV("Starting Scheduler for %d Layer", mSurfaceId);
+    std::unique_lock<std::mutex> lock(mMutex);
+    if (mSurfaceControl == nullptr) {
+        mCondition.wait(lock, [&] { return (mSurfaceControl != nullptr); });
+    }
+
+    while (mContinueScheduling) {
+        while (true) {
+            if (mBufferEvents.empty()) {
+                break;
+            }
+
+            BufferEvent event = mBufferEvents.front();
+            lock.unlock();
+
+            bufferUpdate(event.dimensions);
+            fillSurface(event.event);
+            mColor.modulate();
+            lock.lock();
+            mBufferEvents.pop();
+        }
+        mCondition.wait(lock);
+    }
+}
+
+void BufferQueueScheduler::addEvent(const BufferEvent& event) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    mBufferEvents.push(event);
+    mCondition.notify_one();
+}
+
+void BufferQueueScheduler::stopScheduling() {
+    std::lock_guard<std::mutex> lock(mMutex);
+    mContinueScheduling = false;
+    mCondition.notify_one();
+}
+
+void BufferQueueScheduler::setSurfaceControl(
+        const sp<SurfaceControl>& surfaceControl, const HSV& color) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    mSurfaceControl = surfaceControl;
+    mColor = color;
+    mCondition.notify_one();
+}
+
+void BufferQueueScheduler::bufferUpdate(const Dimensions& dimensions) {
+    sp<Surface> s = mSurfaceControl->getSurface();
+    s->setBuffersDimensions(dimensions.width, dimensions.height);
+}
+
+void BufferQueueScheduler::fillSurface(const std::shared_ptr<Event>& event) {
+    ANativeWindow_Buffer outBuffer;
+    sp<Surface> s = mSurfaceControl->getSurface();
+
+    status_t status = s->lock(&outBuffer, nullptr);
+
+    if (status != NO_ERROR) {
+        ALOGE("fillSurface: failed to lock buffer, (%d)", status);
+        return;
+    }
+
+    auto color = mColor.getRGB();
+
+    auto img = reinterpret_cast<uint8_t*>(outBuffer.bits);
+    for (int y = 0; y < outBuffer.height; y++) {
+        for (int x = 0; x < outBuffer.width; x++) {
+            uint8_t* pixel = img + (4 * (y * outBuffer.stride + x));
+            pixel[0] = color.r;
+            pixel[1] = color.g;
+            pixel[2] = color.b;
+            pixel[3] = LAYER_ALPHA;
+        }
+    }
+
+    event->readyToExecute();
+
+    status = s->unlockAndPost();
+
+    ALOGE_IF(status != NO_ERROR, "fillSurface: failed to unlock and post buffer, (%d)", status);
+}
diff --git a/cmds/surfacereplayer/replayer/BufferQueueScheduler.h b/cmds/surfacereplayer/replayer/BufferQueueScheduler.h
new file mode 100644
index 0000000..cb20fcc
--- /dev/null
+++ b/cmds/surfacereplayer/replayer/BufferQueueScheduler.h
@@ -0,0 +1,82 @@
+/*
+ * 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_SURFACEREPLAYER_BUFFERQUEUESCHEDULER_H
+#define ANDROID_SURFACEREPLAYER_BUFFERQUEUESCHEDULER_H
+
+#include "Color.h"
+#include "Event.h"
+
+#include <gui/SurfaceControl.h>
+
+#include <utils/StrongPointer.h>
+
+#include <atomic>
+#include <condition_variable>
+#include <mutex>
+#include <queue>
+#include <utility>
+
+namespace android {
+
+auto constexpr LAYER_ALPHA = 190;
+
+struct Dimensions {
+    Dimensions() = default;
+    Dimensions(int w, int h) : width(w), height(h) {}
+
+    int width = 0;
+    int height = 0;
+};
+
+struct BufferEvent {
+    BufferEvent() = default;
+    BufferEvent(std::shared_ptr<Event> e, Dimensions d) : event(e), dimensions(d) {}
+
+    std::shared_ptr<Event> event;
+    Dimensions dimensions;
+};
+
+class BufferQueueScheduler {
+  public:
+    BufferQueueScheduler(const sp<SurfaceControl>& surfaceControl, const HSV& color, int id);
+
+    void startScheduling();
+    void addEvent(const BufferEvent&);
+    void stopScheduling();
+
+    void setSurfaceControl(const sp<SurfaceControl>& surfaceControl, const HSV& color);
+
+  private:
+    void bufferUpdate(const Dimensions& dimensions);
+
+    // Lock and fill the surface, block until the event is signaled by the main loop,
+    // then unlock and post the buffer.
+    void fillSurface(const std::shared_ptr<Event>& event);
+
+    sp<SurfaceControl> mSurfaceControl;
+    HSV mColor;
+    const int mSurfaceId;
+
+    bool mContinueScheduling;
+
+    std::queue<BufferEvent> mBufferEvents;
+    std::mutex mMutex;
+    std::condition_variable mCondition;
+};
+
+}  // namespace android
+#endif
diff --git a/cmds/surfacereplayer/replayer/Color.h b/cmds/surfacereplayer/replayer/Color.h
new file mode 100644
index 0000000..ce644be
--- /dev/null
+++ b/cmds/surfacereplayer/replayer/Color.h
@@ -0,0 +1,124 @@
+/*
+ * 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_SURFACEREPLAYER_COLOR_H
+#define ANDROID_SURFACEREPLAYER_COLOR_H
+
+#include <cmath>
+#include <cstdlib>
+
+namespace android {
+
+constexpr double modulateFactor = .0001;
+constexpr double modulateLimit = .80;
+
+struct RGB {
+    RGB(uint8_t rIn, uint8_t gIn, uint8_t bIn) : r(rIn), g(gIn), b(bIn) {}
+
+    uint8_t r = 0;
+    uint8_t g = 0;
+    uint8_t b = 0;
+};
+
+struct HSV {
+    HSV() = default;
+    HSV(double hIn, double sIn, double vIn) : h(hIn), s(sIn), v(vIn) {}
+
+    double h = 0;
+    double s = 0;
+    double v = 0;
+
+    RGB getRGB() const;
+
+    bool modulateUp = false;
+
+    void modulate();
+};
+
+void inline HSV::modulate() {
+    if(modulateUp) {
+        v += modulateFactor;
+    } else {
+        v -= modulateFactor;
+    }
+
+    if(v <= modulateLimit || v >= 1) {
+        modulateUp = !modulateUp;
+    }
+}
+
+inline RGB HSV::getRGB() const {
+    using namespace std;
+    double r = 0, g = 0, b = 0;
+
+    if (s == 0) {
+        r = v;
+        g = v;
+        b = v;
+    } else {
+        auto tempHue = static_cast<int>(h) % 360;
+        tempHue = tempHue / 60;
+
+        int i = static_cast<int>(trunc(tempHue));
+        double f = h - i;
+
+        double x = v * (1.0 - s);
+        double y = v * (1.0 - (s * f));
+        double z = v * (1.0 - (s * (1.0 - f)));
+
+        switch (i) {
+            case 0:
+                r = v;
+                g = z;
+                b = x;
+                break;
+
+            case 1:
+                r = y;
+                g = v;
+                b = x;
+                break;
+
+            case 2:
+                r = x;
+                g = v;
+                b = z;
+                break;
+
+            case 3:
+                r = x;
+                g = y;
+                b = v;
+                break;
+
+            case 4:
+                r = z;
+                g = x;
+                b = v;
+                break;
+
+            default:
+                r = v;
+                g = x;
+                b = y;
+                break;
+        }
+    }
+
+    return RGB(round(r * 255), round(g * 255), round(b * 255));
+}
+}
+#endif
diff --git a/cmds/surfacereplayer/replayer/Event.cpp b/cmds/surfacereplayer/replayer/Event.cpp
new file mode 100644
index 0000000..390d398
--- /dev/null
+++ b/cmds/surfacereplayer/replayer/Event.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 "Event.h"
+
+using namespace android;
+
+Event::Event(Increment::IncrementCase type) : mIncrementType(type) {}
+
+void Event::readyToExecute() {
+    changeState(Event::EventState::Waiting);
+    waitUntil(Event::EventState::Signaled);
+    changeState(Event::EventState::Running);
+}
+
+void Event::complete() {
+    waitUntil(Event::EventState::Waiting);
+    changeState(Event::EventState::Signaled);
+    waitUntil(Event::EventState::Running);
+}
+
+void Event::waitUntil(Event::EventState state) {
+    std::unique_lock<std::mutex> lock(mLock);
+    mCond.wait(lock, [this, state] { return (mState == state); });
+}
+
+void Event::changeState(Event::EventState state) {
+    std::unique_lock<std::mutex> lock(mLock);
+    mState = state;
+    lock.unlock();
+
+    mCond.notify_one();
+}
+
+Increment::IncrementCase Event::getIncrementType() {
+    return mIncrementType;
+}
diff --git a/cmds/surfacereplayer/replayer/Event.h b/cmds/surfacereplayer/replayer/Event.h
new file mode 100644
index 0000000..44b60f5
--- /dev/null
+++ b/cmds/surfacereplayer/replayer/Event.h
@@ -0,0 +1,55 @@
+/*
+ * 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_SURFACEREPLAYER_EVENT_H
+#define ANDROID_SURFACEREPLAYER_EVENT_H
+
+#include <frameworks/native/cmds/surfacereplayer/proto/src/trace.pb.h>
+
+#include <condition_variable>
+#include <mutex>
+
+namespace android {
+
+class Event {
+  public:
+    Event(Increment::IncrementCase);
+
+    enum class EventState {
+        SettingUp,  // Completing as much time-independent work as possible
+        Waiting,    // Waiting for signal from main thread to finish execution
+        Signaled,   // Signaled by main thread, about to immediately switch to Running
+        Running     // Finishing execution of rest of work
+    };
+
+    void readyToExecute();
+    void complete();
+
+    Increment::IncrementCase getIncrementType();
+
+  private:
+    void waitUntil(EventState state);
+    void changeState(EventState state);
+
+    std::mutex mLock;
+    std::condition_variable mCond;
+
+    EventState mState = EventState::SettingUp;
+
+    Increment::IncrementCase mIncrementType;
+};
+}
+#endif
diff --git a/cmds/surfacereplayer/replayer/Main.cpp b/cmds/surfacereplayer/replayer/Main.cpp
new file mode 100644
index 0000000..dd1dd7d
--- /dev/null
+++ b/cmds/surfacereplayer/replayer/Main.cpp
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+
+/*
+ * Replayer - Main.cpp
+ *
+ * 1. Get flags from command line
+ * 2. Commit actions or settings based on the flags
+ * 3. Initalize a replayer object with the filename passed in
+ * 4. Replay
+ * 5. Exit successfully or print error statement
+ */
+
+#include <replayer/Replayer.h>
+
+#include <csignal>
+#include <iostream>
+#include <stdlib.h>
+#include <unistd.h>
+
+using namespace android;
+
+void printHelpMenu() {
+    std::cout << "SurfaceReplayer options:\n";
+    std::cout << "Usage: surfacereplayer [OPTIONS...] <TRACE FILE>\n";
+    std::cout << "  File path must be absolute" << std::endl << std::endl;
+
+    std::cout << "  -m  Stops the replayer at the start of the trace and switches ";
+                 "to manual replay\n";
+
+    std::cout << "\n  -t [Number of Threads]  Specifies the number of threads to be used while "
+                 "replaying (default is " << android::DEFAULT_THREADS << ")\n";
+
+    std::cout << "\n  -s [Timestamp]  Specify at what timestamp should the replayer switch "
+                 "to manual replay\n";
+
+    std::cout << "  -n  Ignore timestamps and run through trace as fast as possible\n";
+
+    std::cout << "  -l  Indefinitely loop the replayer\n";
+
+    std::cout << "  -h  Display help menu\n";
+
+    std::cout << std::endl;
+}
+
+int main(int argc, char** argv) {
+    std::string filename;
+    bool loop = false;
+    bool wait = true;
+    bool pauseBeginning = false;
+    int numThreads = DEFAULT_THREADS;
+    long stopHere = -1;
+
+    int opt = 0;
+    while ((opt = getopt(argc, argv, "mt:s:nlh?")) != -1) {
+        switch (opt) {
+            case 'm':
+                pauseBeginning = true;
+                break;
+            case 't':
+                numThreads = atoi(optarg);
+                break;
+            case 's':
+                stopHere = atol(optarg);
+                break;
+            case 'n':
+                wait = false;
+                break;
+            case 'l':
+                loop = true;
+                break;
+            case 'h':
+            case '?':
+                printHelpMenu();
+                exit(0);
+            default:
+                std::cerr << "Invalid argument...exiting" << std::endl;
+                printHelpMenu();
+                exit(0);
+        }
+    }
+
+    char** input = argv + optind;
+    if (input[0] == NULL) {
+        std::cerr << "No trace file provided...exiting" << std::endl;
+        abort();
+    }
+    filename.assign(input[0]);
+
+    status_t status = NO_ERROR;
+    do {
+        android::Replayer r(filename, pauseBeginning, numThreads, wait, stopHere);
+        status = r.replay();
+    } while(loop);
+
+    if (status == NO_ERROR) {
+        std::cout << "Successfully finished replaying trace" << std::endl;
+    } else {
+        std::cerr << "Trace replayer returned error: " << status << std::endl;
+    }
+
+    return 0;
+}
diff --git a/cmds/surfacereplayer/replayer/README.md b/cmds/surfacereplayer/replayer/README.md
new file mode 100644
index 0000000..893f0dc
--- /dev/null
+++ b/cmds/surfacereplayer/replayer/README.md
@@ -0,0 +1,262 @@
+SurfaceReplayer Documentation
+===================
+
+[go/SurfaceReplayer](go/SurfaceReplayer)
+
+SurfaceReplayer is a playback mechanism that allows the replaying of traces recorded by
+[SurfaceInterceptor](go/SurfaceInterceptor) from SurfaceFlinger. It specifically replays
+
+* Creation and deletion of surfaces/displays
+* Alterations to the surfaces/displays called Transactions
+* Buffer Updates to surfaces
+* VSync events
+
+At their specified times to be as close to the original trace.
+
+Usage
+--------
+
+###Creating a trace
+
+SurfaceInterceptor is the mechanism used to create traces. The device needs to be rooted in order to
+utilize it. To allow it to write to the device, run
+
+`setenforce 0`
+
+To start recording a trace, run
+
+`service call SurfaceFlinger 1020 i32 1`
+
+To stop recording, run
+
+`service call SurfaceFlinger 1020 i32 0`
+
+The default location for the trace is `/data/SurfaceTrace.dat`
+
+###Executable
+
+To replay a specific trace, execute
+
+`/data/local/tmp/surfacereplayer /absolute/path/to/trace`
+
+inside the android shell. This will replay the full trace and then exit. Running this command
+outside of the shell by prepending `adb shell` will not allow for manual control and will not turn
+off VSync injections if it interrupted in any way other than fully replaying the trace
+
+The replay will not fill surfaces with their contents during the capture. Rather they are given a
+random color which will be the same every time the trace is replayed. Surfaces modulate their color
+at buffer updates.
+
+**Options:**
+
+- -m    pause the replayer at the start of the trace for manual replay
+- -t [Number of Threads] uses specified number of threads to queue up actions (default is 3)
+- -s [Timestamp] switches to manual replay at specified timestamp
+- -n    Ignore timestamps and run through trace as fast as possible
+- -l    Indefinitely loop the replayer
+- -h    displays help menu
+
+**Manual Replay:**
+When replaying, if the user presses CTRL-C, the replay will stop and can be manually controlled
+by the user. Pressing CTRL-C again will exit the replayer.
+
+Manual replaying is similar to debugging in gdb. A prompt is presented and the user is able to
+input commands to choose how to proceed by hitting enter after inputting a command. Pressing enter
+without inputting a command repeats the previous command.
+
+- n  - steps the replayer to the next VSync event
+- ni - steps the replayer to the next increment
+- c  - continues normal replaying
+- c [milliseconds] - continue until specified number of milliseconds have passed
+- s [timestamp]    - continue and stop at specified timestamp
+- l  - list out timestamp of current increment
+- h  - displays help menu
+
+###Shared Library
+
+To use the shared library include these shared libraries
+
+`libsurfacereplayer`
+`libprotobuf-cpp-full`
+`libutils`
+
+And the static library
+
+`libtrace_proto`
+
+Include the replayer header at the top of your file
+
+`#include <replayer/Replayer.h>`
+
+There are two constructors for the replayer
+
+`Replayer(std::string& filename, bool replayManually, int numThreads, bool wait, nsecs_t stopHere)`
+`Replayer(Trace& trace, ... ditto ...)`
+
+The first constructor takes in the filepath where the trace is located and loads in the trace
+object internally.
+- replayManually - **True**: if the replayer will immediately switch to manual replay at the start
+- numThreads - Number of worker threads the replayer will use.
+- wait - **False**: Replayer ignores waits in between increments
+- stopHere - Time stamp of where the replayer should run to then switch to manual replay
+
+The second constructor includes all of the same parameters but takes in a preloaded trace object.
+To use add
+
+`#include <frameworks/native/cmds/surfacereplayer/proto/src/trace.pb.h>`
+
+To your file
+
+After initializing the Replayer call
+
+    replayer.replay();
+
+And the trace will start replaying. Once the trace is finished replaying, the function will return.
+The layers that are visible at the end of the trace will remain on screen until the program
+terminates.
+
+
+**If VSyncs are broken after running the replayer** that means `enableVSyncInjections(false)` was
+never executed. This can be fixed by executing
+
+`service call SurfaceFlinger 23 i32 0`
+
+in the android shell
+
+Code Breakdown
+-------------
+
+The Replayer is composed of 5 components.
+
+- The data format of the trace (Trace.proto)
+- The Replayer object (Replayer.cpp)
+- The synchronization mechanism to signal threads within the Replayer (Event.cpp)
+- The scheduler for buffer updates per surface (BufferQueueScheduler.cpp)
+- The Main executable (Main.cpp)
+
+### Traces
+
+Traces are represented as a protobuf message located in surfacereplayer/proto/src.
+
+**Traces** contain *repeated* **Increments** (events that have occurred in SurfaceFlinger).
+**Increments** contain the time stamp of when it occurred and a *oneof* which can be a
+
+ - Transaction
+ - SurfaceCreation
+ - SurfaceDeletion
+ - DisplayCreation
+ - DisplayDeleteion
+ - BufferUpdate
+ - VSyncEvent
+ - PowerModeUpdate
+
+**Transactions** contain whether the transaction was synchronous or animated and *repeated*
+**SurfaceChanges** and **DisplayChanges**
+
+- **SurfaceChanges** contain an id of the surface being manipulated and can be changes such as
+position, alpha, hidden, size, etc.
+- **DisplayChanges** contain the id of the display being manipulated and can be changes such as
+size, layer stack, projection, etc.
+
+**Surface/Display Creation** contain the id of the surface/display and the name of the
+surface/display
+
+**Surface/Display Deletion** contain the id of the surface/display to be deleted
+
+**Buffer Updates** contain the id of the surface who's buffer is being updated, the size of the
+buffer, and the frame number.
+
+**VSyncEvents** contain when the VSync event has occurred.
+
+**PowerModeUpdates** contain the id of the display being updated and what mode it is being
+changed to.
+
+To output the contents of a trace in a readable format, execute
+
+`**aprotoc** --decode=Trace \
+-I=$ANDROID_BUILD_TOP/frameworks/native/cmds/surfacereplayer/proto/src \
+$ANDROID_BUILD_TOP/frameworks/native/cmds/surfacereplayer/proto/src/trace.proto \
+ < **YourTraceFile.dat** > **YourOutputName.txt**`
+
+
+###Replayer
+
+Fundamentally the replayer loads a trace and iterates through each increment, waiting the required
+amount of time until the increment should be executed, then executing the increment. The first
+increment in a trace does not start at 0, rather the replayer treats its time stamp as time 0 and
+goes from there.
+
+Increments from the trace are played asynchronously rather than one by one, being dispatched by
+the main thread, queued up in a thread pool and completed when the main thread deems they are
+ready to finish execution.
+
+When an increment is dispatched, it completes as much work as it can before it has to be
+synchronized (e.g. prebaking a buffer for a BufferUpdate). When it gets to a critical action
+(e.g. locking and pushing a buffer), it waits for the main thread to complete it using an Event
+object. The main thread holds a queue of these Event objects and completes the
+corresponding Event base on its time stamp. After completing an increment, the main thread will
+dispatch another increment and continue.
+
+The main thread's execution flow is outlined below
+
+    initReplay() //queue up the initial increments
+    while(!pendingIncrements.empty()) { //while increments remaining
+        event = pendingIncrement.pop();
+        wait(event.time_stamp(); //waitUntil it is time to complete this increment
+
+        event.complete() //signal to let event finish
+        if(increments remaing()) {
+            dispatchEvent() //queue up another increment
+        }
+    }
+
+A worker thread's flow looks like so
+
+    //dispatched!
+    Execute non-time sensitive work here
+    ...
+    event.readyToExecute() //time sensitive point...waiting for Main Thread
+    ...
+    Finish execution
+
+
+### Event
+
+An Event is a simple synchronization mechanism used to facilitate communication between the main
+and worker threads. Every time an increment is dispatched, an Event object is also created.
+
+An Event can be in 4 different states:
+
+- **SettingUp** - The worker is in the process of completing all non-time sensitive work
+- **Waiting** - The worker is waiting on the main thread to signal it.
+- **Signaled** - The worker has just been signaled by the main thread
+- **Running** - The worker is running again and finishing the rest of its work.
+
+When the main thread wants to finish the execution of a worker, the worker can either still be
+**SettingUp**, in which the main thread will wait, or the worker will be **Waiting**, in which the
+main thread will **Signal** it to complete. The worker thread changes itself to the **Running**
+state once **Signaled**. This last step exists in order to communicate back to the main thread that
+the worker thread has actually started completing its execution, rather than being preempted right
+after signalling. Once this happens, the main thread schedules the next worker. This makes sure
+there is a constant amount of workers running at one time.
+
+This activity is encapsulated in the `readyToExecute()` and `complete()` functions called by the
+worker and main thread respectively.
+
+### BufferQueueScheduler
+
+During a **BuferUpdate**, the worker thread will wait until **Signaled** to unlock and post a
+buffer that has been prefilled during the **SettingUp** phase. However if there are two sequential
+**BufferUpdates** that act on the same surface, both threads will try to lock a buffer and fill it,
+which isn't possible and will cause a deadlock. The BufferQueueScheduler solves this problem by
+handling when **BufferUpdates** should be scheduled, making sure that they don't overlap.
+
+When a surface is created, a BufferQueueScheduler is also created along side it. Whenever a
+**BufferUpdate** is read, it schedules the event onto its own internal queue and then schedules one
+every time an Event is completed.
+
+### Main
+
+The main exectuable reads in the command line arguments. Creates the Replayer using those
+arguments. Executes `replay()` on the Replayer. If there are no errors while replaying it will exit
+gracefully, if there are then it will report the error and then exit.
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
new file mode 100644
index 0000000..35b63ec
--- /dev/null
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -0,0 +1,702 @@
+/* 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_NDEBUG 0
+#define LOG_TAG "SurfaceReplayer"
+
+#include "Replayer.h"
+
+#include <android/native_window.h>
+
+#include <android-base/file.h>
+
+#include <gui/BufferQueue.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/Surface.h>
+#include <private/gui/ComposerService.h>
+#include <private/gui/LayerState.h>
+
+#include <ui/DisplayInfo.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <utils/Trace.h>
+
+#include <chrono>
+#include <cmath>
+#include <condition_variable>
+#include <cstdlib>
+#include <fstream>
+#include <functional>
+#include <iostream>
+#include <mutex>
+#include <sstream>
+#include <string>
+#include <thread>
+#include <vector>
+
+using namespace android;
+
+std::atomic_bool Replayer::sReplayingManually(false);
+
+Replayer::Replayer(const std::string& filename, bool replayManually, int numThreads, bool wait,
+        nsecs_t stopHere)
+      : mTrace(),
+        mLoaded(false),
+        mIncrementIndex(0),
+        mCurrentTime(0),
+        mNumThreads(numThreads),
+        mWaitForTimeStamps(wait),
+        mStopTimeStamp(stopHere) {
+    srand(RAND_COLOR_SEED);
+
+    std::string input;
+    if (!android::base::ReadFileToString(filename, &input, true)) {
+        std::cerr << "Trace did not load. Does " << filename << " exist?" << std::endl;
+        abort();
+    }
+
+    mLoaded = mTrace.ParseFromString(input);
+    if (!mLoaded) {
+        std::cerr << "Trace did not load." << std::endl;
+        abort();
+    }
+
+    mCurrentTime = mTrace.increment(0).time_stamp();
+
+    sReplayingManually.store(replayManually);
+
+    if (stopHere < 0) {
+        mHasStopped = true;
+    }
+}
+
+Replayer::Replayer(const Trace& t, bool replayManually, int numThreads, bool wait, nsecs_t stopHere)
+      : mTrace(t),
+        mLoaded(true),
+        mIncrementIndex(0),
+        mCurrentTime(0),
+        mNumThreads(numThreads),
+        mWaitForTimeStamps(wait),
+        mStopTimeStamp(stopHere) {
+    srand(RAND_COLOR_SEED);
+    mCurrentTime = mTrace.increment(0).time_stamp();
+
+    sReplayingManually.store(replayManually);
+
+    if (stopHere < 0) {
+        mHasStopped = true;
+    }
+}
+
+status_t Replayer::replay() {
+    signal(SIGINT, Replayer::stopAutoReplayHandler); //for manual control
+
+    ALOGV("There are %d increments.", mTrace.increment_size());
+
+    status_t status = loadSurfaceComposerClient();
+
+    if (status != NO_ERROR) {
+        ALOGE("Couldn't create SurfaceComposerClient (%d)", status);
+        return status;
+    }
+
+    SurfaceComposerClient::enableVSyncInjections(true);
+
+    initReplay();
+
+    ALOGV("Starting actual Replay!");
+    while (!mPendingIncrements.empty()) {
+        mCurrentIncrement = mTrace.increment(mIncrementIndex);
+
+        if (mHasStopped == false && mCurrentIncrement.time_stamp() >= mStopTimeStamp) {
+            mHasStopped = true;
+            sReplayingManually.store(true);
+        }
+
+        waitForConsoleCommmand();
+
+        if (mWaitForTimeStamps) {
+            waitUntilTimestamp(mCurrentIncrement.time_stamp());
+        }
+
+        auto event = mPendingIncrements.front();
+        mPendingIncrements.pop();
+
+        event->complete();
+
+        if (event->getIncrementType() == Increment::kVsyncEvent) {
+            mWaitingForNextVSync = false;
+        }
+
+        if (mIncrementIndex + mNumThreads < mTrace.increment_size()) {
+            status = dispatchEvent(mIncrementIndex + mNumThreads);
+
+            if (status != NO_ERROR) {
+                SurfaceComposerClient::enableVSyncInjections(false);
+                return status;
+            }
+        }
+
+        mIncrementIndex++;
+        mCurrentTime = mCurrentIncrement.time_stamp();
+    }
+
+    SurfaceComposerClient::enableVSyncInjections(false);
+
+    return status;
+}
+
+status_t Replayer::initReplay() {
+    for (int i = 0; i < mNumThreads && i < mTrace.increment_size(); i++) {
+        status_t status = dispatchEvent(i);
+
+        if (status != NO_ERROR) {
+            ALOGE("Unable to dispatch event (%d)", status);
+            return status;
+        }
+    }
+
+    return NO_ERROR;
+}
+
+void Replayer::stopAutoReplayHandler(int /*signal*/) {
+    if (sReplayingManually) {
+        SurfaceComposerClient::enableVSyncInjections(false);
+        exit(0);
+    }
+
+    sReplayingManually.store(true);
+}
+
+std::vector<std::string> split(const std::string& s, const char delim) {
+    std::vector<std::string> elems;
+    std::stringstream ss(s);
+    std::string item;
+    while (getline(ss, item, delim)) {
+        elems.push_back(item);
+    }
+    return elems;
+}
+
+bool isNumber(const std::string& s) {
+    return !s.empty() &&
+           std::find_if(s.begin(), s.end(), [](char c) { return !std::isdigit(c); }) == s.end();
+}
+
+void Replayer::waitForConsoleCommmand() {
+    if (!sReplayingManually || mWaitingForNextVSync) {
+        return;
+    }
+
+    while (true) {
+        std::string input = "";
+        std::cout << "> ";
+        getline(std::cin, input);
+
+        if (input.empty()) {
+            input = mLastInput;
+        } else {
+            mLastInput = input;
+        }
+
+        if (mLastInput.empty()) {
+            continue;
+        }
+
+        std::vector<std::string> inputs = split(input, ' ');
+
+        if (inputs[0] == "n") {  // next vsync
+            mWaitingForNextVSync = true;
+            break;
+
+        } else if (inputs[0] == "ni") {  // next increment
+            break;
+
+        } else if (inputs[0] == "c") {  // continue
+            if (inputs.size() > 1 && isNumber(inputs[1])) {
+                long milliseconds = stoi(inputs[1]);
+                std::thread([&] {
+                    std::cout << "Started!" << std::endl;
+                    std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
+                    sReplayingManually.store(true);
+                    std::cout << "Should have stopped!" << std::endl;
+                }).detach();
+            }
+            sReplayingManually.store(false);
+            mWaitingForNextVSync = false;
+            break;
+
+        } else if (inputs[0] == "s") {  // stop at this timestamp
+            if (inputs.size() < 1) {
+                std::cout << "No time stamp given" << std::endl;
+                continue;
+            }
+            sReplayingManually.store(false);
+            mStopTimeStamp = stol(inputs[1]);
+            mHasStopped = false;
+            break;
+        } else if (inputs[0] == "l") {  // list
+            std::cout << "Time stamp: " << mCurrentIncrement.time_stamp() << "\n";
+            continue;
+        } else if (inputs[0] == "q") {  // quit
+            SurfaceComposerClient::enableVSyncInjections(false);
+            exit(0);
+
+        } else if (inputs[0] == "h") {  // help
+                                        // add help menu
+            std::cout << "Manual Replay options:\n";
+            std::cout << " n  - Go to next VSync\n";
+            std::cout << " ni - Go to next increment\n";
+            std::cout << " c  - Continue\n";
+            std::cout << " c [milliseconds] - Continue until specified number of milliseconds\n";
+            std::cout << " s [timestamp]    - Continue and stop at specified timestamp\n";
+            std::cout << " l  - List out timestamp of current increment\n";
+            std::cout << " h  - Display help menu\n";
+            std::cout << std::endl;
+            continue;
+        }
+
+        std::cout << "Invalid Command" << std::endl;
+    }
+}
+
+status_t Replayer::dispatchEvent(int index) {
+    auto increment = mTrace.increment(index);
+    std::shared_ptr<Event> event = std::make_shared<Event>(increment.increment_case());
+    mPendingIncrements.push(event);
+
+    status_t status = NO_ERROR;
+    switch (increment.increment_case()) {
+        case increment.kTransaction: {
+            std::thread(&Replayer::doTransaction, this, increment.transaction(), event).detach();
+        } break;
+        case increment.kSurfaceCreation: {
+            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);
+
+            Dimensions dimensions(increment.buffer_update().w(), increment.buffer_update().h());
+            BufferEvent bufferEvent(event, dimensions);
+
+            auto layerId = increment.buffer_update().id();
+            if (mBufferQueueSchedulers.count(layerId) == 0) {
+                mBufferQueueSchedulers[layerId] = std::make_shared<BufferQueueScheduler>(
+                        mLayers[layerId], mColors[layerId], layerId);
+                mBufferQueueSchedulers[layerId]->addEvent(bufferEvent);
+
+                std::thread(&BufferQueueScheduler::startScheduling,
+                        mBufferQueueSchedulers[increment.buffer_update().id()].get())
+                        .detach();
+            } else {
+                auto bqs = mBufferQueueSchedulers[increment.buffer_update().id()];
+                bqs->addEvent(bufferEvent);
+            }
+        } break;
+        case increment.kVsyncEvent: {
+            std::thread(&Replayer::injectVSyncEvent, this, increment.vsync_event(), event).detach();
+        } break;
+        case increment.kDisplayCreation: {
+            std::thread(&Replayer::createDisplay, this, increment.display_creation(), event)
+                    .detach();
+        } break;
+        case increment.kDisplayDeletion: {
+            std::thread(&Replayer::deleteDisplay, this, increment.display_deletion(), event)
+                    .detach();
+        } break;
+        case increment.kPowerModeUpdate: {
+            std::thread(&Replayer::updatePowerMode, this, increment.power_mode_update(), event)
+                    .detach();
+        } break;
+        default:
+            ALOGE("Unknown Increment Type: %d", increment.increment_case());
+            status = BAD_VALUE;
+            break;
+    }
+
+    return status;
+}
+
+status_t Replayer::doTransaction(const Transaction& t, const std::shared_ptr<Event>& event) {
+    ALOGV("Started Transaction");
+
+    SurfaceComposerClient::openGlobalTransaction();
+
+    status_t status = NO_ERROR;
+
+    status = doSurfaceTransaction(t.surface_change());
+    doDisplayTransaction(t.display_change());
+
+    if (t.animation()) {
+        SurfaceComposerClient::setAnimationTransaction();
+    }
+
+    event->readyToExecute();
+
+    SurfaceComposerClient::closeGlobalTransaction(t.synchronous());
+
+    ALOGV("Ended Transaction");
+
+    return status;
+}
+
+status_t Replayer::doSurfaceTransaction(const SurfaceChanges& surfaceChanges) {
+    status_t status = NO_ERROR;
+
+    for (const SurfaceChange& change : surfaceChanges) {
+        std::unique_lock<std::mutex> lock(mLayerLock);
+        if (mLayers[change.id()] == nullptr) {
+            mLayerCond.wait(lock, [&] { return (mLayers[change.id()] != nullptr); });
+        }
+
+        switch (change.SurfaceChange_case()) {
+            case SurfaceChange::SurfaceChangeCase::kPosition:
+                status = setPosition(change.id(), change.position());
+                break;
+            case SurfaceChange::SurfaceChangeCase::kSize:
+                status = setSize(change.id(), change.size());
+                break;
+            case SurfaceChange::SurfaceChangeCase::kAlpha:
+                status = setAlpha(change.id(), change.alpha());
+                break;
+            case SurfaceChange::SurfaceChangeCase::kLayer:
+                status = setLayer(change.id(), change.layer());
+                break;
+            case SurfaceChange::SurfaceChangeCase::kCrop:
+                status = setCrop(change.id(), change.crop());
+                break;
+            case SurfaceChange::SurfaceChangeCase::kMatrix:
+                status = setMatrix(change.id(), change.matrix());
+                break;
+            case SurfaceChange::SurfaceChangeCase::kFinalCrop:
+                status = setFinalCrop(change.id(), change.final_crop());
+                break;
+            case SurfaceChange::SurfaceChangeCase::kOverrideScalingMode:
+                status = setOverrideScalingMode(change.id(), change.override_scaling_mode());
+                break;
+            case SurfaceChange::SurfaceChangeCase::kTransparentRegionHint:
+                status = setTransparentRegionHint(change.id(), change.transparent_region_hint());
+                break;
+            case SurfaceChange::SurfaceChangeCase::kLayerStack:
+                status = setLayerStack(change.id(), change.layer_stack());
+                break;
+            case SurfaceChange::SurfaceChangeCase::kHiddenFlag:
+                status = setHiddenFlag(change.id(), change.hidden_flag());
+                break;
+            case SurfaceChange::SurfaceChangeCase::kOpaqueFlag:
+                status = setOpaqueFlag(change.id(), change.opaque_flag());
+                break;
+            case SurfaceChange::SurfaceChangeCase::kSecureFlag:
+                status = setSecureFlag(change.id(), change.secure_flag());
+                break;
+            case SurfaceChange::SurfaceChangeCase::kDeferredTransaction:
+                waitUntilDeferredTransactionLayerExists(change.deferred_transaction(), lock);
+                status = setDeferredTransaction(change.id(), change.deferred_transaction());
+                break;
+            default:
+                status = NO_ERROR;
+                break;
+        }
+
+        if (status != NO_ERROR) {
+            ALOGE("SET TRANSACTION FAILED");
+            return status;
+        }
+    }
+    return status;
+}
+
+void Replayer::doDisplayTransaction(const DisplayChanges& displayChanges) {
+    for (const DisplayChange& change : displayChanges) {
+        ALOGV("Doing display transaction");
+        std::unique_lock<std::mutex> lock(mDisplayLock);
+        if (mDisplays[change.id()] == nullptr) {
+            mDisplayCond.wait(lock, [&] { return (mDisplays[change.id()] != nullptr); });
+        }
+
+        switch (change.DisplayChange_case()) {
+            case DisplayChange::DisplayChangeCase::kSurface:
+                setDisplaySurface(change.id(), change.surface());
+                break;
+            case DisplayChange::DisplayChangeCase::kLayerStack:
+                setDisplayLayerStack(change.id(), change.layer_stack());
+                break;
+            case DisplayChange::DisplayChangeCase::kSize:
+                setDisplaySize(change.id(), change.size());
+                break;
+            case DisplayChange::DisplayChangeCase::kProjection:
+                setDisplayProjection(change.id(), change.projection());
+                break;
+            default:
+                break;
+        }
+    }
+}
+
+status_t Replayer::setPosition(layer_id id, const PositionChange& pc) {
+    ALOGV("Layer %d: Setting Position -- x=%f, y=%f", id, pc.x(), pc.y());
+    return mLayers[id]->setPosition(pc.x(), pc.y());
+}
+
+status_t Replayer::setSize(layer_id id, const SizeChange& sc) {
+    ALOGV("Layer %d: Setting Size -- w=%u, h=%u", id, sc.w(), sc.h());
+    return mLayers[id]->setSize(sc.w(), sc.h());
+}
+
+status_t Replayer::setLayer(layer_id id, const LayerChange& lc) {
+    ALOGV("Layer %d: Setting Layer -- layer=%d", id, lc.layer());
+    return mLayers[id]->setLayer(lc.layer());
+}
+
+status_t Replayer::setAlpha(layer_id id, const AlphaChange& ac) {
+    ALOGV("Layer %d: Setting Alpha -- alpha=%f", id, ac.alpha());
+    return mLayers[id]->setAlpha(ac.alpha());
+}
+
+status_t Replayer::setCrop(layer_id id, const CropChange& cc) {
+    ALOGV("Layer %d: Setting Crop -- left=%d, top=%d, right=%d, bottom=%d", id,
+            cc.rectangle().left(), cc.rectangle().top(), cc.rectangle().right(),
+            cc.rectangle().bottom());
+
+    Rect r = Rect(cc.rectangle().left(), cc.rectangle().top(), cc.rectangle().right(),
+            cc.rectangle().bottom());
+    return mLayers[id]->setCrop(r);
+}
+
+status_t Replayer::setFinalCrop(layer_id id, const FinalCropChange& fcc) {
+    ALOGV("Layer %d: Setting Final Crop -- left=%d, top=%d, right=%d, bottom=%d", id,
+            fcc.rectangle().left(), fcc.rectangle().top(), fcc.rectangle().right(),
+            fcc.rectangle().bottom());
+    Rect r = Rect(fcc.rectangle().left(), fcc.rectangle().top(), fcc.rectangle().right(),
+            fcc.rectangle().bottom());
+    return mLayers[id]->setFinalCrop(r);
+}
+
+status_t Replayer::setMatrix(layer_id id, const MatrixChange& mc) {
+    ALOGV("Layer %d: Setting Matrix -- dsdx=%f, dtdx=%f, dsdy=%f, dtdy=%f", id, mc.dsdx(),
+            mc.dtdx(), mc.dsdy(), mc.dtdy());
+    return mLayers[id]->setMatrix(mc.dsdx(), mc.dtdx(), mc.dsdy(), mc.dtdy());
+}
+
+status_t Replayer::setOverrideScalingMode(layer_id id, const OverrideScalingModeChange& osmc) {
+    ALOGV("Layer %d: Setting Override Scaling Mode -- mode=%d", id, osmc.override_scaling_mode());
+    return mLayers[id]->setOverrideScalingMode(osmc.override_scaling_mode());
+}
+
+status_t Replayer::setTransparentRegionHint(layer_id id, const TransparentRegionHintChange& trhc) {
+    ALOGV("Setting Transparent Region Hint");
+    Region re = Region();
+
+    for (auto r : trhc.region()) {
+        Rect rect = Rect(r.left(), r.top(), r.right(), r.bottom());
+        re.merge(rect);
+    }
+
+    return mLayers[id]->setTransparentRegionHint(re);
+}
+
+status_t Replayer::setLayerStack(layer_id id, const LayerStackChange& lsc) {
+    ALOGV("Layer %d: Setting LayerStack -- layer_stack=%d", id, lsc.layer_stack());
+    return mLayers[id]->setLayerStack(lsc.layer_stack());
+}
+
+status_t Replayer::setHiddenFlag(layer_id id, const HiddenFlagChange& hfc) {
+    ALOGV("Layer %d: Setting Hidden Flag -- hidden_flag=%d", id, hfc.hidden_flag());
+    layer_id flag = hfc.hidden_flag() ? layer_state_t::eLayerHidden : 0;
+
+    return mLayers[id]->setFlags(flag, layer_state_t::eLayerHidden);
+}
+
+status_t Replayer::setOpaqueFlag(layer_id id, const OpaqueFlagChange& ofc) {
+    ALOGV("Layer %d: Setting Opaque Flag -- opaque_flag=%d", id, ofc.opaque_flag());
+    layer_id flag = ofc.opaque_flag() ? layer_state_t::eLayerOpaque : 0;
+
+    return mLayers[id]->setFlags(flag, layer_state_t::eLayerOpaque);
+}
+
+status_t Replayer::setSecureFlag(layer_id id, const SecureFlagChange& sfc) {
+    ALOGV("Layer %d: Setting Secure Flag -- secure_flag=%d", id, sfc.secure_flag());
+    layer_id flag = sfc.secure_flag() ? layer_state_t::eLayerSecure : 0;
+
+    return mLayers[id]->setFlags(flag, layer_state_t::eLayerSecure);
+}
+
+status_t Replayer::setDeferredTransaction(layer_id id, const DeferredTransactionChange& dtc) {
+    ALOGV("Layer %d: Setting Deferred Transaction -- layer_id=%d, "
+          "frame_number=%llu",
+            id, dtc.layer_id(), dtc.frame_number());
+    if (mLayers.count(dtc.layer_id()) == 0 || mLayers[dtc.layer_id()] == nullptr) {
+        ALOGE("Layer %d not found in Deferred Transaction", dtc.layer_id());
+        return BAD_VALUE;
+    }
+
+    auto handle = mLayers[dtc.layer_id()]->getHandle();
+
+    return mLayers[id]->deferTransactionUntil(handle, dtc.frame_number());
+}
+
+void Replayer::setDisplaySurface(display_id id, const DispSurfaceChange& /*dsc*/) {
+    sp<IGraphicBufferProducer> outProducer;
+    sp<IGraphicBufferConsumer> outConsumer;
+    BufferQueue::createBufferQueue(&outProducer, &outConsumer);
+
+    SurfaceComposerClient::setDisplaySurface(mDisplays[id], outProducer);
+}
+
+void Replayer::setDisplayLayerStack(display_id id, const LayerStackChange& lsc) {
+    SurfaceComposerClient::setDisplayLayerStack(mDisplays[id], lsc.layer_stack());
+}
+
+void Replayer::setDisplaySize(display_id id, const SizeChange& sc) {
+    SurfaceComposerClient::setDisplaySize(mDisplays[id], sc.w(), sc.h());
+}
+
+void Replayer::setDisplayProjection(display_id id, const ProjectionChange& pc) {
+    Rect viewport = Rect(pc.viewport().left(), pc.viewport().top(), pc.viewport().right(),
+            pc.viewport().bottom());
+    Rect frame = Rect(pc.frame().left(), pc.frame().top(), pc.frame().right(), pc.frame().bottom());
+
+    SurfaceComposerClient::setDisplayProjection(mDisplays[id], pc.orientation(), viewport, frame);
+}
+
+status_t Replayer::createSurfaceControl(
+        const SurfaceCreation& create, const std::shared_ptr<Event>& event) {
+    event->readyToExecute();
+
+    ALOGV("Creating Surface Control: ID: %d", create.id());
+    sp<SurfaceControl> surfaceControl = mComposerClient->createSurface(
+            String8(create.name().c_str()), create.w(), create.h(), PIXEL_FORMAT_RGBA_8888, 0);
+
+    if (surfaceControl == nullptr) {
+        ALOGE("CreateSurfaceControl: unable to create surface control");
+        return BAD_VALUE;
+    }
+
+    std::lock_guard<std::mutex> lock1(mLayerLock);
+    auto& layer = mLayers[create.id()];
+    layer = surfaceControl;
+
+    mColors[create.id()] = HSV(rand() % 360, 1, 1);
+
+    mLayerCond.notify_all();
+
+    std::lock_guard<std::mutex> lock2(mBufferQueueSchedulerLock);
+    if (mBufferQueueSchedulers.count(create.id()) != 0) {
+        mBufferQueueSchedulers[create.id()]->setSurfaceControl(
+                mLayers[create.id()], mColors[create.id()]);
+    }
+
+    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());
+
+    return NO_ERROR;
+}
+
+void Replayer::createDisplay(const DisplayCreation& create, const std::shared_ptr<Event>& event) {
+    ALOGV("Creating display");
+    event->readyToExecute();
+
+    std::lock_guard<std::mutex> lock(mDisplayLock);
+    sp<IBinder> display = SurfaceComposerClient::createDisplay(
+            String8(create.name().c_str()), create.is_secure());
+    mDisplays[create.id()] = display;
+
+    mDisplayCond.notify_all();
+
+    ALOGV("Done creating display");
+}
+
+void Replayer::deleteDisplay(const DisplayDeletion& delete_, const std::shared_ptr<Event>& event) {
+    ALOGV("Delete display");
+    event->readyToExecute();
+
+    std::lock_guard<std::mutex> lock(mDisplayLock);
+    SurfaceComposerClient::destroyDisplay(mDisplays[delete_.id()]);
+    mDisplays.erase(delete_.id());
+}
+
+void Replayer::updatePowerMode(const PowerModeUpdate& pmu, const std::shared_ptr<Event>& event) {
+    ALOGV("Updating power mode");
+    event->readyToExecute();
+    SurfaceComposerClient::setDisplayPowerMode(mDisplays[pmu.id()], pmu.mode());
+}
+
+void Replayer::waitUntilTimestamp(int64_t timestamp) {
+    ALOGV("Waiting for %lld nanoseconds...", static_cast<int64_t>(timestamp - mCurrentTime));
+    std::this_thread::sleep_for(std::chrono::nanoseconds(timestamp - mCurrentTime));
+}
+
+void Replayer::waitUntilDeferredTransactionLayerExists(
+        const DeferredTransactionChange& dtc, std::unique_lock<std::mutex>& lock) {
+    if (mLayers.count(dtc.layer_id()) == 0 || mLayers[dtc.layer_id()] == nullptr) {
+        mLayerCond.wait(lock, [&] { return (mLayers[dtc.layer_id()] != nullptr); });
+    }
+}
+
+status_t Replayer::loadSurfaceComposerClient() {
+    mComposerClient = new SurfaceComposerClient;
+    return mComposerClient->initCheck();
+}
diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h
new file mode 100644
index 0000000..f36c9fd
--- /dev/null
+++ b/cmds/surfacereplayer/replayer/Replayer.h
@@ -0,0 +1,145 @@
+/*
+ * 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_SURFACEREPLAYER_H
+#define ANDROID_SURFACEREPLAYER_H
+
+#include "BufferQueueScheduler.h"
+#include "Color.h"
+#include "Event.h"
+
+#include <frameworks/native/cmds/surfacereplayer/proto/src/trace.pb.h>
+
+#include <gui/SurfaceComposerClient.h>
+#include <gui/SurfaceControl.h>
+
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include <stdatomic.h>
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <queue>
+#include <thread>
+#include <unordered_map>
+#include <utility>
+
+namespace android {
+
+const auto DEFAULT_PATH = "/data/local/tmp/SurfaceTrace.dat";
+const auto RAND_COLOR_SEED = 700;
+const auto DEFAULT_THREADS = 3;
+
+typedef int32_t layer_id;
+typedef int32_t display_id;
+
+typedef google::protobuf::RepeatedPtrField<SurfaceChange> SurfaceChanges;
+typedef google::protobuf::RepeatedPtrField<DisplayChange> DisplayChanges;
+
+class Replayer {
+  public:
+    Replayer(const std::string& filename, bool replayManually = false,
+            int numThreads = DEFAULT_THREADS, bool wait = true, nsecs_t stopHere = -1);
+    Replayer(const Trace& trace, bool replayManually = false, int numThreads = DEFAULT_THREADS,
+            bool wait = true, nsecs_t stopHere = -1);
+
+    status_t replay();
+
+  private:
+    status_t initReplay();
+
+    void waitForConsoleCommmand();
+    static void stopAutoReplayHandler(int signal);
+
+    status_t dispatchEvent(int index);
+
+    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);
+    void updatePowerMode(const PowerModeUpdate& update, const std::shared_ptr<Event>& event);
+
+    status_t doSurfaceTransaction(const SurfaceChanges& surfaceChange);
+    void doDisplayTransaction(const DisplayChanges& displayChange);
+
+    status_t setPosition(layer_id id, const PositionChange& pc);
+    status_t setSize(layer_id id, const SizeChange& sc);
+    status_t setAlpha(layer_id id, const AlphaChange& ac);
+    status_t setLayer(layer_id id, const LayerChange& lc);
+    status_t setCrop(layer_id id, const CropChange& cc);
+    status_t setFinalCrop(layer_id id, const FinalCropChange& fcc);
+    status_t setMatrix(layer_id id, const MatrixChange& mc);
+    status_t setOverrideScalingMode(layer_id id, const OverrideScalingModeChange& osmc);
+    status_t setTransparentRegionHint(layer_id id, const TransparentRegionHintChange& trgc);
+    status_t setLayerStack(layer_id id, const LayerStackChange& lsc);
+    status_t setHiddenFlag(layer_id id, const HiddenFlagChange& hfc);
+    status_t setOpaqueFlag(layer_id id, const OpaqueFlagChange& ofc);
+    status_t setSecureFlag(layer_id id, const SecureFlagChange& sfc);
+    status_t setDeferredTransaction(layer_id id, const DeferredTransactionChange& dtc);
+
+    void setDisplaySurface(display_id id, const DispSurfaceChange& dsc);
+    void setDisplayLayerStack(display_id id, const LayerStackChange& lsc);
+    void setDisplaySize(display_id id, const SizeChange& sc);
+    void setDisplayProjection(display_id id, const ProjectionChange& pc);
+
+    void doDeleteSurfaceControls();
+    void waitUntilTimestamp(int64_t timestamp);
+    void waitUntilDeferredTransactionLayerExists(
+            const DeferredTransactionChange& dtc, std::unique_lock<std::mutex>& lock);
+    status_t loadSurfaceComposerClient();
+
+    Trace mTrace;
+    bool mLoaded = false;
+    int32_t mIncrementIndex = 0;
+    int64_t mCurrentTime = 0;
+    int32_t mNumThreads = DEFAULT_THREADS;
+
+    Increment mCurrentIncrement;
+
+    std::string mLastInput;
+
+    static atomic_bool sReplayingManually;
+    bool mWaitingForNextVSync;
+    bool mWaitForTimeStamps;
+    nsecs_t mStopTimeStamp;
+    bool mHasStopped;
+
+    std::mutex mLayerLock;
+    std::condition_variable mLayerCond;
+    std::unordered_map<layer_id, sp<SurfaceControl>> mLayers;
+    std::unordered_map<layer_id, HSV> mColors;
+
+    std::mutex mPendingLayersLock;
+    std::vector<layer_id> mLayersPendingRemoval;
+
+    std::mutex mBufferQueueSchedulerLock;
+    std::unordered_map<layer_id, std::shared_ptr<BufferQueueScheduler>> mBufferQueueSchedulers;
+
+    std::mutex mDisplayLock;
+    std::condition_variable mDisplayCond;
+    std::unordered_map<display_id, sp<IBinder>> mDisplays;
+
+    sp<SurfaceComposerClient> mComposerClient;
+    std::queue<std::shared_ptr<Event>> mPendingIncrements;
+};
+
+}  // namespace android
+#endif
diff --git a/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py b/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
new file mode 100644
index 0000000..a892e46
--- /dev/null
+++ b/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
@@ -0,0 +1,294 @@
+#!/usr/bin/python
+from subprocess import call
+import os
+proto_path = os.environ['ANDROID_BUILD_TOP'] + "/frameworks/native/cmds/surfacereplayer/proto/src/"
+call(["aprotoc", "-I=" + proto_path, "--python_out=.", proto_path + "trace.proto"])
+
+from trace_pb2 import *
+
+trace = Trace()
+
+def main():
+    global trace
+    while(1):
+        option = main_menu()
+
+        if option == 0:
+            break
+
+        increment = trace.increment.add()
+        increment.time_stamp  = int(input("Time stamp of action: "))
+
+        if option == 1:
+           transaction(increment)
+        elif option == 2:
+            surface_create(increment)
+        elif option == 3:
+            surface_delete(increment)
+        elif option == 4:
+            display_create(increment)
+        elif option == 5:
+            display_delete(increment)
+        elif option == 6:
+            buffer_update(increment)
+        elif option == 7:
+            vsync_event(increment)
+        elif option == 8:
+            power_mode_update(increment)
+
+    seralizeTrace()
+
+def seralizeTrace():
+    with open("trace.dat", 'wb') as f:
+        f.write(trace.SerializeToString())
+
+
+def main_menu():
+    print ("")
+    print ("What would you like to do?")
+    print ("1. Add transaction")
+    print ("2. Add surface creation")
+    print ("3. Add surface deletion")
+    print ("4. Add display creation")
+    print ("5. Add display deletion")
+    print ("6. Add buffer update")
+    print ("7. Add VSync event")
+    print ("8. Add power mode update")
+    print ("0. Finish and serialize")
+    print ("")
+
+    return int(input("> "))
+
+def transaction_menu():
+    print ("")
+    print ("What kind of transaction?")
+    print ("1. Position Change")
+    print ("2. Size Change")
+    print ("3. Alpha Change")
+    print ("4. Layer Change")
+    print ("5. Crop Change")
+    print ("6. Final Crop Change")
+    print ("7. Matrix Change")
+    print ("8. Override Scaling Mode Change")
+    print ("9. Transparent Region Hint Change")
+    print ("10. Layer Stack Change")
+    print ("11. Hidden Flag Change")
+    print ("12. Opaque Flag Change")
+    print ("13. Secure Flag Change")
+    print ("14. Deferred Transaction Change")
+    print ("15. Display - Surface Change")
+    print ("16. Display - Layer Stack Change")
+    print ("17. Display - Size Change")
+    print ("18. Display - Projection Change")
+    print ("0. Finished adding Changes to this transaction")
+    print ("")
+
+    return int(input("> "))
+
+def transaction(increment):
+    global trace
+
+    increment.transaction.synchronous \
+            = bool(input("Is transaction synchronous (True/False): "))
+    increment.transaction.animation \
+            = bool(input("Is transaction animated (True/False): "))
+
+    while(1):
+        option = transaction_menu()
+
+        if option == 0:
+            break
+
+        change = None
+        if option <= 14:
+            change = increment.transaction.surface_change.add()
+        elif option >= 15 and option <= 18:
+            change = increment.transaction.display_change.add()
+
+        change.id = int(input("ID of layer/display to undergo a change: "))
+
+        if option == 1:
+            change.position.x, change.position.y = position()
+        elif option == 2:
+            change.size.w, change.size.h = size()
+        elif option == 3:
+            change.alpha.alpha = alpha()
+        elif option == 4:
+            change.layer.layer = layer()
+        elif option == 5:
+            change.crop.rectangle.left,  change.crop.rectangle.top, \
+            change.crop.rectangle.right, change.crop.rectangle.bottom = crop()
+        elif option == 6:
+            change.final_crop.rectangle.left, \
+            change.final_crop.rectangle.top,  \
+            change.final_crop.rectangle.right,\
+            change.final_crop.rectangle.bottom = final_crop()
+        elif option == 7:
+            change.matrix.dsdx,\
+            change.matrix.dtdx,\
+            change.matrix.dsdy,\
+            change.matrix.dtdy = layer()
+        elif option == 8:
+            change.override_scaling_mode.override_scaling_mode \
+                                     = override_scaling_mode()
+        elif option == 9:
+            for rect in transparent_region_hint():
+                new = increment.transparent_region_hint.region.add()
+                new.left = rect[0]
+                new.top = rect[1]
+                new.right = rect[2]
+                new.bottom = rect[3]
+        elif option == 10:
+            change.layer_stack.layer_stack = layer_stack()
+        elif option == 11:
+            change.hidden_flag.hidden_flag = hidden_flag()
+        elif option == 12:
+            change.opaque_flag.opaque_flag = opaque_flag()
+        elif option == 13:
+            change.secure_flag.secure_flag = secure_flag()
+        elif option == 14:
+            change.deferred_transaction.layer_id, \
+            change.deferred_transaction.frame_number = deferred_transaction()
+        elif option == 15:
+            change.surface.buffer_queue_id, \
+            change.surface.buffer_queue_name = surface()
+        elif option == 16:
+            change.layer_stack.layer_stack = layer_stack()
+        elif option == 17:
+            change.size.w, change.size.h = size()
+        elif option == 18:
+            projection(change)
+
+def surface_create(increment):
+    increment.surface_creation.id = int(input("Enter id: "))
+    n = str(raw_input("Enter name: "))
+    increment.surface_creation.name = n
+    increment.surface_creation.w = input("Enter w: ")
+    increment.surface_creation.h = input("Enter h: ")
+
+def surface_delete(increment):
+    increment.surface_deletion.id = int(input("Enter id: "))
+
+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.is_secure = bool(input("Enter if secure: "))
+
+def display_delete(increment):
+    increment.surface_deletion.id = int(input("Enter id: "))
+
+def buffer_update(increment):
+    increment.buffer_update.id = int(input("Enter id: "))
+    increment.buffer_update.w = int(input("Enter w: "))
+    increment.buffer_update.h = int(input("Enter h: "))
+    increment.buffer_update.frame_number = int(input("Enter frame_number: "))
+
+def vsync_event(increment):
+    increment.vsync_event.when = int(input("Enter when: "))
+
+def power_mode_update(increment):
+    increment.power_mode_update.id = int(input("Enter id: "))
+    increment.power_mode_update.mode = int(input("Enter mode: "))
+
+def position():
+    x = input("Enter x: ")
+    y = input("Enter y: ")
+
+    return float(x), float(y)
+
+def size():
+    w = input("Enter w: ")
+    h = input("Enter h: ")
+
+    return int(w), int(h)
+
+def alpha():
+    alpha = input("Enter alpha: ")
+
+    return float(alpha)
+
+def layer():
+    layer = input("Enter layer: ")
+
+    return int(layer)
+
+def crop():
+    return rectangle()
+
+def final_crop():
+    return rectangle()
+
+def matrix():
+    dsdx = input("Enter dsdx: ")
+    dtdx = input("Enter dtdx: ")
+    dsdy = input("Enter dsdy: ")
+    dtdy = input("Enter dtdy: ")
+
+    return float(dsdx)
+
+def override_scaling_mode():
+    mode = input("Enter override scaling mode: ")
+
+    return int(mode)
+
+def transparent_region_hint():
+    num = input("Enter number of rectangles in region: ")
+
+    return [rectangle() in range(x)]
+
+def layer_stack():
+    layer_stack = input("Enter layer stack: ")
+
+    return int(layer_stack)
+
+def hidden_flag():
+    flag = input("Enter hidden flag state (True/False): ")
+
+    return bool(flag)
+
+def opaque_flag():
+    flag = input("Enter opaque flag state (True/False): ")
+
+    return bool(flag)
+
+def secure_flag():
+    flag = input("Enter secure flag state (True/False): ")
+
+    return bool(flag)
+
+def deferred_transaction():
+    layer_id = input("Enter layer_id: ")
+    frame_number = input("Enter frame_number: ")
+
+    return int(layer_id), int(frame_number)
+
+def surface():
+    id = input("Enter id: ")
+    name = raw_input("Enter name: ")
+
+    return int(id), str(name)
+
+def projection(change):
+    change.projection.orientation = input("Enter orientation: ")
+    print("Enter rectangle for viewport")
+    change.projection.viewport.left, \
+    change.projection.viewport.top,  \
+    change.projection.viewport.right,\
+    change.projection.viewport.bottom = rectangle()
+    print("Enter rectangle for frame")
+    change.projection.frame.left, \
+    change.projection.frame.top,  \
+    change.projection.frame.right,\
+    change.projection.frame.bottom = rectangle()
+
+def rectangle():
+    left = input("Enter left: ")
+    top = input("Enter top: ")
+    right = input("Enter right: ")
+    bottom = input("Enter bottom: ")
+
+    return int(left), int(top), int(right), int(bottom)
+
+if __name__ == "__main__":
+    main()
diff --git a/cmds/vr/.clang-format b/cmds/vr/.clang-format
new file mode 100644
index 0000000..04d7970
--- /dev/null
+++ b/cmds/vr/.clang-format
@@ -0,0 +1,5 @@
+BasedOnStyle: Google
+DerivePointerAlignment: false
+PointerAlignment: Left
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
diff --git a/data/etc/android.hardware.nfc.hce.xml b/data/etc/android.hardware.nfc.hce.xml
index 10b96b1..95da181 100644
--- a/data/etc/android.hardware.nfc.hce.xml
+++ b/data/etc/android.hardware.nfc.hce.xml
@@ -18,4 +18,5 @@
      NFC card emulation -->
 <permissions>
     <feature name="android.hardware.nfc.hce" />
+    <feature name="android.hardware.nfc.any" />
 </permissions>
diff --git a/data/etc/android.hardware.nfc.hcef.xml b/data/etc/android.hardware.nfc.hcef.xml
index 0d03023..b86890d 100644
--- a/data/etc/android.hardware.nfc.hcef.xml
+++ b/data/etc/android.hardware.nfc.hcef.xml
@@ -18,4 +18,5 @@
      NFC-F card emulation -->
 <permissions>
     <feature name="android.hardware.nfc.hcef" />
+    <feature name="android.hardware.nfc.any" />
 </permissions>
diff --git a/data/etc/android.hardware.nfc.xml b/data/etc/android.hardware.nfc.xml
index 81c4a84..5201fa2 100644
--- a/data/etc/android.hardware.nfc.xml
+++ b/data/etc/android.hardware.nfc.xml
@@ -18,4 +18,5 @@
      using Near-Field Communications (NFC). -->
 <permissions>
     <feature name="android.hardware.nfc" />
+    <feature name="android.hardware.nfc.any" />
 </permissions>
diff --git a/data/etc/android.hardware.telephony.carrierlock.xml b/data/etc/android.hardware.telephony.carrierlock.xml
new file mode 100644
index 0000000..50b1fe9
--- /dev/null
+++ b/data/etc/android.hardware.telephony.carrierlock.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Feature for devices with telephony carrier restriction mechanism. -->
+<permissions>
+    <feature name="android.hardware.telephony.carrierlock" />
+</permissions>
diff --git a/data/etc/android.hardware.vr.headtracking-0.xml b/data/etc/android.hardware.vr.headtracking-0.xml
new file mode 100644
index 0000000..1b53995
--- /dev/null
+++ b/data/etc/android.hardware.vr.headtracking-0.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This is the feature indicating that the device supports VR headtracking
+     level 0 -->
+<permissions>
+    <feature name="android.hardware.vr.headtracking" version="0" />
+</permissions>
diff --git a/data/etc/android.hardware.vr.headtracking-1.xml b/data/etc/android.hardware.vr.headtracking-1.xml
new file mode 100644
index 0000000..2ad8ccc
--- /dev/null
+++ b/data/etc/android.hardware.vr.headtracking-1.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This is the feature indicating that the device supports VR headtracking
+     level 1 -->
+<permissions>
+    <feature name="android.hardware.vr.headtracking" version="1" />
+</permissions>
diff --git a/data/etc/android.hardware.vulkan.compute-0.xml b/data/etc/android.hardware.vulkan.compute-0.xml
new file mode 100644
index 0000000..bac2fde
--- /dev/null
+++ b/data/etc/android.hardware.vulkan.compute-0.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- This is the standard feature indicating that the device supports Vulkan
+     compute level 0. -->
+<permissions>
+    <feature name="android.hardware.vulkan.compute" version="0" />
+</permissions>
diff --git a/data/etc/android.hardware.wifi.aware.xml b/data/etc/android.hardware.wifi.aware.xml
new file mode 100644
index 0000000..ae6272e
--- /dev/null
+++ b/data/etc/android.hardware.wifi.aware.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- This is the standard feature indicating that the device includes WiFi Aware. -->
+<permissions>
+    <feature name="android.hardware.wifi.aware" />
+</permissions>
diff --git a/data/etc/android.hardware.wifi.nan.xml b/data/etc/android.hardware.wifi.nan.xml
deleted file mode 100644
index e557610..0000000
--- a/data/etc/android.hardware.wifi.nan.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<!-- This is the standard feature indicating that the device includes WiFi NAN. -->
-<permissions>
-    <feature name="android.hardware.wifi.nan" />
-</permissions>
diff --git a/data/etc/android.software.activities_on_secondary_displays.xml b/data/etc/android.software.activities_on_secondary_displays.xml
new file mode 100644
index 0000000..db1bdb5
--- /dev/null
+++ b/data/etc/android.software.activities_on_secondary_displays.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<permissions>
+    <feature name="android.software.activities_on_secondary_displays" />
+</permissions>
diff --git a/data/etc/android.software.autofill.xml b/data/etc/android.software.autofill.xml
new file mode 100644
index 0000000..c510d0c
--- /dev/null
+++ b/data/etc/android.software.autofill.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<permissions>
+    <feature name="android.software.autofill" />
+</permissions>
diff --git a/data/etc/android.software.companion_device_setup.xml b/data/etc/android.software.companion_device_setup.xml
new file mode 100644
index 0000000..e60ef88
--- /dev/null
+++ b/data/etc/android.software.companion_device_setup.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<permissions>
+    <feature name="android.software.companion_device_setup" />
+</permissions>
diff --git a/data/etc/android.software.cts.xml b/data/etc/android.software.cts.xml
new file mode 100644
index 0000000..0414c9a
--- /dev/null
+++ b/data/etc/android.software.cts.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<permissions>
+    <!-- This is Android and fully CTS compatible.  Basically this is for CTS tests to use. -->
+    <feature name="android.software.cts" />
+</permissions>
diff --git a/data/etc/android.software.preview_sdk.xml b/data/etc/android.software.preview_sdk.xml
new file mode 100644
index 0000000..928b4b3
--- /dev/null
+++ b/data/etc/android.software.preview_sdk.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<permissions>
+    <!-- The device is running a preview (i.e. unofficial) API version. -->
+    <feature name="android.software.preview_sdk" />
+</permissions>
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml
index ab89ef5..835504f 100644
--- a/data/etc/car_core_hardware.xml
+++ b/data/etc/car_core_hardware.xml
@@ -23,6 +23,9 @@
      devices.
 -->
 <permissions>
+    <!-- This is Android and fully CTS compatible.  Basically this is for CTS tests to use. -->
+    <feature name="android.software.cts" />
+
     <feature name="android.hardware.audio.output" />
     <feature name="android.hardware.location" />
     <feature name="android.hardware.location.network" />
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index f9464e8..0d5d206 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -23,6 +23,9 @@
      devices.
 -->
 <permissions>
+    <!-- This is Android and fully CTS compatible.  Basically this is for CTS tests to use. -->
+    <feature name="android.software.cts" />
+
     <feature name="android.hardware.audio.output" />
     <feature name="android.hardware.camera" />
     <feature name="android.hardware.location" />
@@ -42,7 +45,11 @@
     <feature name="android.software.backup" />
     <feature name="android.software.home_screen" />
     <feature name="android.software.input_methods" />
+    <feature name="android.software.picture_in_picture" />
+    <feature name="android.software.activities_on_secondary_displays" />
     <feature name="android.software.print" />
+    <feature name="android.software.companion_device_setup" />
+    <feature name="android.software.autofill" />
 
     <!-- Feature to specify if the device supports adding device admins. -->
     <feature name="android.software.device_admin" />
@@ -55,6 +62,9 @@
     <!-- Devices with all optimizations required to be a "VR Ready" device that
          pass all CTS tests for this feature must include feature
          android.hardware.vr.high_performance -->
+    <!-- Devices that support VR headtracking features and pass all CDD
+         requirements may include
+         android.hardware.vr.headtracking -->
 
     <!-- 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/tablet_core_hardware.xml b/data/etc/tablet_core_hardware.xml
index 8128165..9b88648 100644
--- a/data/etc/tablet_core_hardware.xml
+++ b/data/etc/tablet_core_hardware.xml
@@ -23,6 +23,9 @@
      devices.
 -->
 <permissions>
+    <!-- This is Android and fully CTS compatible.  Basically this is for CTS tests to use. -->
+    <feature name="android.software.cts" />
+
     <feature name="android.hardware.audio.output" />
     <feature name="android.hardware.location" />
     <feature name="android.hardware.location.network" />
@@ -42,7 +45,11 @@
     <feature name="android.software.backup" />
     <feature name="android.software.home_screen" />
     <feature name="android.software.input_methods" />
+    <feature name="android.software.picture_in_picture" />
+    <feature name="android.software.activities_on_secondary_displays" />
     <feature name="android.software.print" />
+    <feature name="android.software.companion_device_setup" />
+    <feature name="android.software.autofill" />
 
     <!-- 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 84230da..d7c3730 100644
--- a/data/etc/wearable_core_hardware.xml
+++ b/data/etc/wearable_core_hardware.xml
@@ -21,6 +21,9 @@
      Wearable devices include watches, glasses, backpacks, and sweaters.
 -->
 <permissions>
+    <!-- This is Android and fully CTS compatible.  Basically this is for CTS tests to use. -->
+    <feature name="android.software.cts" />
+
     <feature name="android.hardware.location" />
     <!-- devices supporting compass/magnitometer sensor must include
 	 android.hardware.sensor.compass.xml -->
@@ -36,6 +39,9 @@
     <!-- device administration -->
     <feature name="android.software.device_admin" />
 
+    <!-- input management and third-party input method editors -->
+    <feature name="android.software.input_methods" />
+
     <!-- devices with GPS must include device/google/clockwork/gps.xml -->
     <!-- devices with an autofocus camera and/or flash must include either
          android.hardware.camera.autofocus.xml or
diff --git a/docs/Doxyfile b/docs/Doxyfile
index 3ea453f..bb0ca32 100644
--- a/docs/Doxyfile
+++ b/docs/Doxyfile
@@ -14,90 +14,90 @@
 # Project related configuration options
 #---------------------------------------------------------------------------
 
-# This tag specifies the encoding used for all characters in the config file 
-# that follow. The default is UTF-8 which is also the encoding used for all 
-# text before the first occurrence of this tag. Doxygen uses libiconv (or the 
-# iconv built into libc) for the transcoding. See 
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
 # http://www.gnu.org/software/libiconv for the list of possible encodings.
 
 DOXYFILE_ENCODING      = UTF-8
 
-# The PROJECT_NAME tag is a single word (or sequence of words) that should 
-# identify the project. Note that if you do not use Doxywizard you need 
+# The PROJECT_NAME tag is a single word (or sequence of words) that should
+# identify the project. Note that if you do not use Doxywizard you need
 # to put quotes around the project name if it contains spaces.
 
 PROJECT_NAME           = "NDK API"
 
-# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
-# This could be handy for archiving the generated documentation or 
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
 # if some version control system is used.
 
-PROJECT_NUMBER         = 
+PROJECT_NUMBER         =
 
-# Using the PROJECT_BRIEF tag one can provide an optional one line description 
-# for a project that appears at the top of each page and should give viewer 
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer
 # a quick idea about the purpose of the project. Keep the description short.
 
 PROJECT_BRIEF          = ""
 
-# With the PROJECT_LOGO tag one can specify an logo or icon that is 
-# included in the documentation. The maximum height of the logo should not 
-# exceed 55 pixels and the maximum width should not exceed 200 pixels. 
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
 # Doxygen will copy the logo to the output directory.
 
 PROJECT_LOGO           = logo.png
 
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
-# base path where the generated documentation will be put. 
-# If a relative path is entered, it will be relative to the location 
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
 # where doxygen was started. If left blank the current directory will be used.
 
-OUTPUT_DIRECTORY       = 
+OUTPUT_DIRECTORY       =
 
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
-# 4096 sub-directories (in 2 levels) under the output directory of each output 
-# format and will distribute the generated files over these directories. 
-# Enabling this option can be useful when feeding doxygen a huge amount of 
-# source files, where putting all generated files in the same directory would 
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
 # otherwise cause performance problems for the file system.
 
 CREATE_SUBDIRS         = NO
 
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
-# documentation generated by doxygen is written. Doxygen will use this 
-# information to generate all constant output in the proper language. 
-# The default language is English, other supported languages are: 
-# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
-# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, 
-# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English 
-# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, 
-# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, 
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
 # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
 
 OUTPUT_LANGUAGE        = English
 
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
-# include brief member descriptions after the members that are listed in 
-# the file and class documentation (similar to JavaDoc). 
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
 # Set to NO to disable this.
 
 BRIEF_MEMBER_DESC      = YES
 
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
-# the brief description of a member or function before the detailed description. 
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
 # brief descriptions will be completely suppressed.
 
 REPEAT_BRIEF           = YES
 
-# This tag implements a quasi-intelligent brief description abbreviator 
-# that is used to form the text in various listings. Each string 
-# in this list, if found as the leading text of the brief description, will be 
-# stripped from the text and the result after processing the whole list, is 
-# used as the annotated text. Otherwise, the brief description is used as-is. 
-# If left blank, the following values are used ("$name" is automatically 
-# replaced with the name of the entity): "The $name class" "The $name widget" 
-# "The $name file" "is" "provides" "specifies" "contains" 
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
 # "represents" "a" "an" "the"
 
 ABBREVIATE_BRIEF       = "The $name class" \
@@ -112,256 +112,256 @@
                          an \
                          the
 
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
-# Doxygen will generate a detailed section even if there is only a brief 
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
 # description.
 
 ALWAYS_DETAILED_SEC    = NO
 
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 
-# inherited members of a class in the documentation of that class as if those 
-# members were ordinary class members. Constructors, destructors and assignment 
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
 # operators of the base classes will not be shown.
 
 INLINE_INHERITED_MEMB  = NO
 
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
-# path before files name in the file list and in the header files. If set 
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
 # to NO the shortest path that makes the file name unique will be used.
 
 FULL_PATH_NAMES        = NO
 
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
-# can be used to strip a user-defined part of the path. Stripping is 
-# only done if one of the specified strings matches the left-hand part of 
-# the path. The tag can be used to show relative paths in the file list. 
-# If left blank the directory from which doxygen is run is used as the 
-# path to strip. Note that you specify absolute paths here, but also 
-# relative paths, which will be relative from the directory where doxygen is 
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip. Note that you specify absolute paths here, but also
+# relative paths, which will be relative from the directory where doxygen is
 # started.
 
-STRIP_FROM_PATH        = 
+STRIP_FROM_PATH        =
 
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
-# the path mentioned in the documentation of a class, which tells 
-# the reader which header file to include in order to use a class. 
-# If left blank only the name of the header file containing the class 
-# definition is used. Otherwise one should specify the include paths that 
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
 # are normally passed to the compiler using the -I flag.
 
-STRIP_FROM_INC_PATH    = 
+STRIP_FROM_INC_PATH    =
 
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
-# (but less readable) file names. This can be useful if your file system 
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
 # doesn't support long names like on DOS, Mac, or CD-ROM.
 
 SHORT_NAMES            = NO
 
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
-# will interpret the first line (until the first dot) of a JavaDoc-style 
-# comment as the brief description. If set to NO, the JavaDoc 
-# comments will behave just like regular Qt-style comments 
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
 # (thus requiring an explicit @brief command for a brief description.)
 
 JAVADOC_AUTOBRIEF      = NO
 
-# If the QT_AUTOBRIEF tag is set to YES then Doxygen will 
-# interpret the first line (until the first dot) of a Qt-style 
-# comment as the brief description. If set to NO, the comments 
-# will behave just like regular Qt-style comments (thus requiring 
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
 # an explicit \brief command for a brief description.)
 
 QT_AUTOBRIEF           = NO
 
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
-# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
-# comments) as a brief description. This used to be the default behaviour. 
-# The new default is to treat a multi-line C++ comment block as a detailed 
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
 # description. Set this tag to YES if you prefer the old behaviour instead.
 
 MULTILINE_CPP_IS_BRIEF = NO
 
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
-# member inherits the documentation from any documented member that it 
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
 # re-implements.
 
 INHERIT_DOCS           = YES
 
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
-# a new page for each member. If set to NO, the documentation of a member will 
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
 # be part of the file/class/namespace that contains it.
 
 SEPARATE_MEMBER_PAGES  = NO
 
-# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
 # Doxygen uses this value to replace tabs by spaces in code fragments.
 
 TAB_SIZE               = 4
 
-# This tag can be used to specify a number of aliases that acts 
-# as commands in the documentation. An alias has the form "name=value". 
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
-# put the command \sideeffect (or @sideeffect) in the documentation, which 
-# will result in a user-defined paragraph with heading "Side Effects:". 
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
 # You can put \n's in the value part of an alias to insert newlines.
 
-ALIASES                = 
+ALIASES                =
 
-# This tag can be used to specify a number of word-keyword mappings (TCL only). 
-# A mapping has the form "name=value". For example adding 
-# "class=itcl::class" will allow you to use the command class in the 
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding
+# "class=itcl::class" will allow you to use the command class in the
 # itcl::class meaning.
 
-TCL_SUBST              = 
+TCL_SUBST              =
 
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
-# sources only. Doxygen will then generate output that is more tailored for C. 
-# For instance, some of the names that are used will be different. The list 
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
 # of all members will be omitted, etc.
 
 OPTIMIZE_OUTPUT_FOR_C  = YES
 
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
-# sources only. Doxygen will then generate output that is more tailored for 
-# Java. For instance, namespaces will be presented as packages, qualified 
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
 # scopes will look different, etc.
 
 OPTIMIZE_OUTPUT_JAVA   = NO
 
-# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran 
-# sources only. Doxygen will then generate output that is more tailored for 
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
 # Fortran.
 
 OPTIMIZE_FOR_FORTRAN   = NO
 
-# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL 
-# sources. Doxygen will then generate output that is tailored for 
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
 # VHDL.
 
 OPTIMIZE_OUTPUT_VHDL   = NO
 
-# Doxygen selects the parser to use depending on the extension of the files it 
-# parses. With this tag you can assign which parser to use for a given 
-# extension. Doxygen has a built-in mapping, but you can override or extend it 
-# using this tag. The format is ext=language, where ext is a file extension, 
-# and language is one of the parsers supported by doxygen: IDL, Java, 
-# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, 
-# C++. For instance to make doxygen treat .inc files as Fortran files (default 
-# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note 
-# that for custom extensions you also need to set FILE_PATTERNS otherwise the 
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension,
+# and language is one of the parsers supported by doxygen: IDL, Java,
+# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C,
+# C++. For instance to make doxygen treat .inc files as Fortran files (default
+# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note
+# that for custom extensions you also need to set FILE_PATTERNS otherwise the
 # files are not read by doxygen.
 
-EXTENSION_MAPPING      = 
+EXTENSION_MAPPING      =
 
-# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all 
-# comments according to the Markdown format, which allows for more readable 
-# documentation. See http://daringfireball.net/projects/markdown/ for details. 
-# The output of markdown processing is further processed by doxygen, so you 
-# can mix doxygen, HTML, and XML commands with Markdown formatting. 
+# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
+# comments according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you
+# can mix doxygen, HTML, and XML commands with Markdown formatting.
 # Disable only in case of backward compatibilities issues.
 
 MARKDOWN_SUPPORT       = YES
 
-# When enabled doxygen tries to link words that correspond to documented classes, 
-# or namespaces to their corresponding documentation. Such a link can be 
-# prevented in individual cases by by putting a % sign in front of the word or 
+# When enabled doxygen tries to link words that correspond to documented classes,
+# or namespaces to their corresponding documentation. Such a link can be
+# prevented in individual cases by by putting a % sign in front of the word or
 # globally by setting AUTOLINK_SUPPORT to NO.
 
 AUTOLINK_SUPPORT       = YES
 
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want 
-# to include (a tag file for) the STL sources as input, then you should 
-# set this tag to YES in order to let doxygen match functions declarations and 
-# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 
-# func(std::string) {}). This also makes the inheritance and collaboration 
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
 # diagrams that involve STL classes more complete and accurate.
 
 BUILTIN_STL_SUPPORT    = NO
 
-# If you use Microsoft's C++/CLI language, you should set this option to YES to 
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
 # enable parsing support.
 
 CPP_CLI_SUPPORT        = NO
 
-# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. 
-# Doxygen will parse them like normal C++ but will assume all classes use public 
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
 # instead of private inheritance when no explicit protection keyword is present.
 
 SIP_SUPPORT            = NO
 
-# For Microsoft's IDL there are propget and propput attributes to indicate 
-# getter and setter methods for a property. Setting this option to YES (the 
-# default) will make doxygen replace the get and set methods by a property in 
-# the documentation. This will only work if the methods are indeed getting or 
-# setting a simple type. If this is not the case, or you want to show the 
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES (the
+# default) will make doxygen replace the get and set methods by a property in
+# the documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
 # methods anyway, you should set this option to NO.
 
 IDL_PROPERTY_SUPPORT   = YES
 
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
-# tag is set to YES, then doxygen will reuse the documentation of the first 
-# member in the group (if any) for the other members of the group. By default 
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
 # all members of a group must be documented explicitly.
 
 DISTRIBUTE_GROUP_DOC   = NO
 
-# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
-# the same type (for instance a group of public functions) to be put as a 
-# subgroup of that type (e.g. under the Public Functions section). Set it to 
-# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
 # the \nosubgrouping command.
 
 SUBGROUPING            = YES
 
-# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and 
-# unions are shown inside the group in which they are included (e.g. using 
-# @ingroup) instead of on a separate page (for HTML and Man pages) or 
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
+# unions are shown inside the group in which they are included (e.g. using
+# @ingroup) instead of on a separate page (for HTML and Man pages) or
 # section (for LaTeX and RTF).
 
 INLINE_GROUPED_CLASSES = NO
 
-# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and 
-# unions with only public data fields will be shown inline in the documentation 
-# of the scope in which they are defined (i.e. file, namespace, or group 
-# documentation), provided this scope is documented. If set to NO (the default), 
-# structs, classes, and unions are shown on a separate page (for HTML and Man 
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
+# unions with only public data fields will be shown inline in the documentation
+# of the scope in which they are defined (i.e. file, namespace, or group
+# documentation), provided this scope is documented. If set to NO (the default),
+# structs, classes, and unions are shown on a separate page (for HTML and Man
 # pages) or section (for LaTeX and RTF).
 
 INLINE_SIMPLE_STRUCTS  = NO
 
-# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum 
-# is documented as struct, union, or enum with the name of the typedef. So 
-# typedef struct TypeS {} TypeT, will appear in the documentation as a struct 
-# with name TypeT. When disabled the typedef will appear as a member of a file, 
-# namespace, or class. And the struct will be named TypeS. This can typically 
-# be useful for C code in case the coding convention dictates that all compound 
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
 # types are typedef'ed and only the typedef is referenced, never the tag name.
 
 TYPEDEF_HIDES_STRUCT   = NO
 
-# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to 
-# determine which symbols to keep in memory and which to flush to disk. 
-# When the cache is full, less often used symbols will be written to disk. 
-# For small to medium size projects (<1000 input files) the default value is 
-# probably good enough. For larger projects a too small cache size can cause 
-# doxygen to be busy swapping symbols to and from disk most of the time 
-# causing a significant performance penalty. 
-# If the system has enough physical memory increasing the cache will improve the 
-# performance by keeping more symbols in memory. Note that the value works on 
-# a logarithmic scale so increasing the size by one will roughly double the 
-# memory usage. The cache size is given by this formula: 
-# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, 
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penalty.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will roughly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
 # corresponding to a cache size of 2^16 = 65536 symbols.
 
 SYMBOL_CACHE_SIZE      = 0
 
-# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be 
-# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given 
-# their name and scope. Since this can be an expensive process and often the 
-# same symbol appear multiple times in the code, doxygen keeps a cache of 
-# pre-resolved symbols. If the cache is too small doxygen will become slower. 
-# If the cache is too large, memory is wasted. The cache size is given by this 
-# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, 
+# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
+# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
+# their name and scope. Since this can be an expensive process and often the
+# same symbol appear multiple times in the code, doxygen keeps a cache of
+# pre-resolved symbols. If the cache is too small doxygen will become slower.
+# If the cache is too large, memory is wasted. The cache size is given by this
+# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
 # corresponding to a cache size of 2^16 = 65536 symbols.
 
 LOOKUP_CACHE_SIZE      = 0
@@ -370,329 +370,329 @@
 # Build related configuration options
 #---------------------------------------------------------------------------
 
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
-# documentation are documented, even if no documentation was available. 
-# Private class members and static file members will be hidden unless 
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
 # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
 
 EXTRACT_ALL            = YES
 
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
 # will be included in the documentation.
 
 EXTRACT_PRIVATE        = NO
 
-# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal 
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
 # scope will be included in the documentation.
 
 EXTRACT_PACKAGE        = NO
 
-# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
 # will be included in the documentation.
 
 EXTRACT_STATIC         = NO
 
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
-# defined locally in source files will be included in the documentation. 
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
 # If set to NO only classes defined in header files are included.
 
 EXTRACT_LOCAL_CLASSES  = YES
 
-# This flag is only useful for Objective-C code. When set to YES local 
-# methods, which are defined in the implementation section but not in 
-# the interface are included in the documentation. 
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
 # If set to NO (the default) only methods in the interface are included.
 
 EXTRACT_LOCAL_METHODS  = NO
 
-# If this flag is set to YES, the members of anonymous namespaces will be 
-# extracted and appear in the documentation as a namespace called 
-# 'anonymous_namespace{file}', where file will be replaced with the base 
-# name of the file that contains the anonymous namespace. By default 
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
 # anonymous namespaces are hidden.
 
 EXTRACT_ANON_NSPACES   = NO
 
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
-# undocumented members of documented classes, files or namespaces. 
-# If set to NO (the default) these members will be included in the 
-# various overviews, but no documentation section is generated. 
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
 # This option has no effect if EXTRACT_ALL is enabled.
 
 HIDE_UNDOC_MEMBERS     = NO
 
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
-# undocumented classes that are normally visible in the class hierarchy. 
-# If set to NO (the default) these classes will be included in the various 
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
 # overviews. This option has no effect if EXTRACT_ALL is enabled.
 
 HIDE_UNDOC_CLASSES     = NO
 
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
-# friend (class|struct|union) declarations. 
-# If set to NO (the default) these declarations will be included in the 
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
 # documentation.
 
 HIDE_FRIEND_COMPOUNDS  = NO
 
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
-# documentation blocks found inside the body of a function. 
-# If set to NO (the default) these blocks will be appended to the 
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
 # function's detailed documentation block.
 
 HIDE_IN_BODY_DOCS      = NO
 
-# The INTERNAL_DOCS tag determines if documentation 
-# that is typed after a \internal command is included. If the tag is set 
-# to NO (the default) then the documentation will be excluded. 
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
 # Set it to YES to include the internal documentation.
 
 INTERNAL_DOCS          = NO
 
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
-# file names in lower-case letters. If set to YES upper-case letters are also 
-# allowed. This is useful if you have classes or files whose names only differ 
-# in case and if your file system supports case sensitive file names. Windows 
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
 # and Mac users are advised to set this option to NO.
 
 CASE_SENSE_NAMES       = NO
 
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
-# will show members with their full class and namespace scopes in the 
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
 # documentation. If set to YES the scope will be hidden.
 
 HIDE_SCOPE_NAMES       = YES
 
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
-# will put a list of the files that are included by a file in the documentation 
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
 # of that file.
 
 SHOW_INCLUDE_FILES     = YES
 
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen 
-# will list include files with double quotes in the documentation 
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
 # rather than with sharp brackets.
 
 FORCE_LOCAL_INCLUDES   = NO
 
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
 # is inserted in the documentation for inline members.
 
 INLINE_INFO            = YES
 
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
-# will sort the (detailed) documentation of file and class members 
-# alphabetically by member name. If set to NO the members will appear in 
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
 # declaration order.
 
 SORT_MEMBER_DOCS       = YES
 
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
-# brief documentation of file, namespace and class members alphabetically 
-# by member name. If set to NO (the default) the members will appear in 
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
 # declaration order.
 
 SORT_BRIEF_DOCS        = NO
 
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen 
-# will sort the (brief and detailed) documentation of class members so that 
-# constructors and destructors are listed first. If set to NO (the default) 
-# the constructors will appear in the respective orders defined by 
-# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. 
-# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO 
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
 # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
 
 SORT_MEMBERS_CTORS_1ST = NO
 
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the 
-# hierarchy of group names into alphabetical order. If set to NO (the default) 
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
 # the group names will appear in their defined order.
 
 SORT_GROUP_NAMES       = NO
 
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
-# sorted by fully-qualified names, including namespaces. If set to 
-# NO (the default), the class list will be sorted only by class name, 
-# not including the namespace part. 
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. 
-# Note: This option applies only to the class list, not to the 
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
 # alphabetical list.
 
 SORT_BY_SCOPE_NAME     = NO
 
-# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to 
-# do proper type resolution of all parameters of a function it will reject a 
-# match between the prototype and the implementation of a member function even 
-# if there is only one candidate or it is obvious which candidate to choose 
-# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen 
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
+# do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even
+# if there is only one candidate or it is obvious which candidate to choose
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
 # will still accept a match between prototype and implementation in such cases.
 
 STRICT_PROTO_MATCHING  = NO
 
-# The GENERATE_TODOLIST tag can be used to enable (YES) or 
-# disable (NO) the todo list. This list is created by putting \todo 
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
 # commands in the documentation.
 
 GENERATE_TODOLIST      = YES
 
-# The GENERATE_TESTLIST tag can be used to enable (YES) or 
-# disable (NO) the test list. This list is created by putting \test 
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
 # commands in the documentation.
 
 GENERATE_TESTLIST      = YES
 
-# The GENERATE_BUGLIST tag can be used to enable (YES) or 
-# disable (NO) the bug list. This list is created by putting \bug 
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
 # commands in the documentation.
 
 GENERATE_BUGLIST       = YES
 
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
-# disable (NO) the deprecated list. This list is created by putting 
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
 # \deprecated commands in the documentation.
 
 GENERATE_DEPRECATEDLIST= YES
 
-# The ENABLED_SECTIONS tag can be used to enable conditional 
-# documentation sections, marked by \if section-label ... \endif 
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if section-label ... \endif
 # and \cond section-label ... \endcond blocks.
 
-ENABLED_SECTIONS       = 
+ENABLED_SECTIONS       =
 
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
-# the initial value of a variable or macro consists of for it to appear in 
-# the documentation. If the initializer consists of more lines than specified 
-# here it will be hidden. Use a value of 0 to hide initializers completely. 
-# The appearance of the initializer of individual variables and macros in the 
-# documentation can be controlled using \showinitializer or \hideinitializer 
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
 # command in the documentation regardless of this setting.
 
 MAX_INITIALIZER_LINES  = 26
 
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
-# at the bottom of the documentation of classes and structs. If set to YES the 
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
 # list will mention the files that were used to generate the documentation.
 
 SHOW_USED_FILES        = YES
 
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page. 
-# This will remove the Files entry from the Quick Index and from the 
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
 # Folder Tree View (if specified). The default is YES.
 
 SHOW_FILES             = YES
 
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the 
-# Namespaces page.  This will remove the Namespaces entry from the Quick Index 
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.  This will remove the Namespaces entry from the Quick Index
 # and from the Folder Tree View (if specified). The default is YES.
 
 SHOW_NAMESPACES        = YES
 
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
-# doxygen should invoke to get the current version for each file (typically from 
-# the version control system). Doxygen will invoke the program by executing (via 
-# popen()) the command <command> <input-file>, where <command> is the value of 
-# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
-# provided by doxygen. Whatever the program writes to standard output 
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
 # is used as the file version. See the manual for examples.
 
-FILE_VERSION_FILTER    = 
+FILE_VERSION_FILTER    =
 
-# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed 
-# by doxygen. The layout file controls the global structure of the generated 
-# output files in an output format independent way. To create the layout file 
-# that represents doxygen's defaults, run doxygen with the -l option. 
-# You can optionally specify a file name after the option, if omitted 
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
 # DoxygenLayout.xml will be used as the name of the layout file.
 
-LAYOUT_FILE            = 
+LAYOUT_FILE            =
 
-# The CITE_BIB_FILES tag can be used to specify one or more bib files 
-# containing the references data. This must be a list of .bib files. The 
-# .bib extension is automatically appended if omitted. Using this command 
-# requires the bibtex tool to be installed. See also 
-# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style 
-# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this 
-# feature you need bibtex and perl available in the search path. Do not use 
+# The CITE_BIB_FILES tag can be used to specify one or more bib files
+# containing the references data. This must be a list of .bib files. The
+# .bib extension is automatically appended if omitted. Using this command
+# requires the bibtex tool to be installed. See also
+# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
+# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
+# feature you need bibtex and perl available in the search path. Do not use
 # file names with spaces, bibtex cannot handle them.
 
-CITE_BIB_FILES         = 
+CITE_BIB_FILES         =
 
 #---------------------------------------------------------------------------
 # configuration options related to warning and progress messages
 #---------------------------------------------------------------------------
 
-# The QUIET tag can be used to turn on/off the messages that are generated 
+# The QUIET tag can be used to turn on/off the messages that are generated
 # by doxygen. Possible values are YES and NO. If left blank NO is used.
 
 QUIET                  = NO
 
-# The WARNINGS tag can be used to turn on/off the warning messages that are 
-# generated by doxygen. Possible values are YES and NO. If left blank 
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
 # NO is used.
 
 WARNINGS               = YES
 
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
 # automatically be disabled.
 
 WARN_IF_UNDOCUMENTED   = YES
 
-# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
-# potential errors in the documentation, such as not documenting some 
-# parameters in a documented function, or documenting parameters that 
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
 # don't exist or using markup commands wrongly.
 
 WARN_IF_DOC_ERROR      = YES
 
-# The WARN_NO_PARAMDOC option can be enabled to get warnings for 
-# functions that are documented, but have no documentation for their parameters 
-# or return value. If set to NO (the default) doxygen will only warn about 
-# wrong or incomplete parameter documentation, but not about the absence of 
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
 # documentation.
 
 WARN_NO_PARAMDOC       = NO
 
-# The WARN_FORMAT tag determines the format of the warning messages that 
-# doxygen can produce. The string should contain the $file, $line, and $text 
-# tags, which will be replaced by the file and line number from which the 
-# warning originated and the warning text. Optionally the format may contain 
-# $version, which will be replaced by the version of the file (if it could 
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
 # be obtained via FILE_VERSION_FILTER)
 
 WARN_FORMAT            = "$file:$line: $text"
 
-# The WARN_LOGFILE tag can be used to specify a file to which warning 
-# and error messages should be written. If left blank the output is written 
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
 # to stderr.
 
-WARN_LOGFILE           = 
+WARN_LOGFILE           =
 
 #---------------------------------------------------------------------------
 # configuration options related to the input files
 #---------------------------------------------------------------------------
 
-# The INPUT tag can be used to specify the files and/or directories that contain 
-# documented source files. You may enter file names like "myfile.cpp" or 
-# directories like "/usr/src/myproject". Separate the files or directories 
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
 # with spaces.
 
 INPUT                  = ../include/android ../../av/include/ndk ../../av/include/camera/ndk
 
-# This tag can be used to specify the character encoding of the source files 
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is 
-# also the default input encoding. Doxygen uses libiconv (or the iconv built 
-# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for 
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
 # the list of possible encodings.
 
 INPUT_ENCODING         = UTF-8
 
-# If the value of the INPUT tag contains directories, you can use the 
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
-# and *.h) to filter out the source-files in the directories. If left 
-# blank the following patterns are tested: 
-# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh 
-# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py 
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
 # *.f90 *.f *.for *.vhd *.vhdl
 
 FILE_PATTERNS          = *.c \
@@ -730,159 +730,159 @@
                          *.vhd \
                          *.vhdl
 
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
-# should be searched for input files as well. Possible values are YES and NO. 
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
 # If left blank NO is used.
 
 RECURSIVE              = YES
 
-# The EXCLUDE tag can be used to specify files and/or directories that should be 
-# excluded from the INPUT source files. This way you can easily exclude a 
-# subdirectory from a directory tree whose root is specified with the INPUT tag. 
-# Note that relative paths are relative to the directory from which doxygen is 
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+# Note that relative paths are relative to the directory from which doxygen is
 # run.
 
-EXCLUDE                = 
+EXCLUDE                =
 
-# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or 
-# directories that are symbolic links (a Unix file system feature) are excluded 
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
 # from the input.
 
 EXCLUDE_SYMLINKS       = NO
 
-# If the value of the INPUT tag contains directories, you can use the 
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
-# certain files from those directories. Note that the wildcards are matched 
-# against the file with absolute path, so to exclude all test directories 
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
 # for example use the pattern */test/*
 
-EXCLUDE_PATTERNS       = 
+EXCLUDE_PATTERNS       =
 
-# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 
-# (namespaces, classes, functions, etc.) that should be excluded from the 
-# output. The symbol name can be a fully qualified name, a word, or if the 
-# wildcard * is used, a substring. Examples: ANamespace, AClass, 
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
 # AClass::ANamespace, ANamespace::*Test
 
-EXCLUDE_SYMBOLS        = 
+EXCLUDE_SYMBOLS        =
 
-# The EXAMPLE_PATH tag can be used to specify one or more files or 
-# directories that contain example code fragments that are included (see 
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
 # the \include command).
 
-EXAMPLE_PATH           = 
+EXAMPLE_PATH           =
 
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
-# and *.h) to filter out the source-files in the directories. If left 
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
 # blank all files are included.
 
 EXAMPLE_PATTERNS       = *
 
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
-# searched for input files to be used with the \include or \dontinclude 
-# commands irrespective of the value of the RECURSIVE tag. 
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
 # Possible values are YES and NO. If left blank NO is used.
 
 EXAMPLE_RECURSIVE      = NO
 
-# The IMAGE_PATH tag can be used to specify one or more files or 
-# directories that contain image that are included in the documentation (see 
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
 # the \image command).
 
-IMAGE_PATH             = 
+IMAGE_PATH             =
 
-# The INPUT_FILTER tag can be used to specify a program that doxygen should 
-# invoke to filter for each input file. Doxygen will invoke the filter program 
-# by executing (via popen()) the command <filter> <input-file>, where <filter> 
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
-# input file. Doxygen will then use the output that the filter program writes 
-# to standard output.  If FILTER_PATTERNS is specified, this tag will be 
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.  If FILTER_PATTERNS is specified, this tag will be
 # ignored.
 
-INPUT_FILTER           = 
+INPUT_FILTER           =
 
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
-# basis.  Doxygen will compare the file name with each pattern and apply the 
-# filter if there is a match.  The filters are a list of the form: 
-# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
-# info on how filters are used. If FILTER_PATTERNS is empty or if 
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.  Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.  The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
 # non of the patterns match the file name, INPUT_FILTER is applied.
 
-FILTER_PATTERNS        = 
+FILTER_PATTERNS        =
 
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
-# INPUT_FILTER) will be used to filter the input files when producing source 
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
 # files to browse (i.e. when SOURCE_BROWSER is set to YES).
 
 FILTER_SOURCE_FILES    = NO
 
-# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file 
-# pattern. A pattern will override the setting for FILTER_PATTERN (if any) 
-# and it is also possible to disable source filtering for a specific pattern 
-# using *.ext= (so without naming a filter). This option only has effect when 
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
 # FILTER_SOURCE_FILES is enabled.
 
-FILTER_SOURCE_PATTERNS = 
+FILTER_SOURCE_PATTERNS =
 
-# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that 
-# is part of the input, its contents will be placed on the main page (index.html). 
-# This can be useful if you have a project on for instance GitHub and want reuse 
+# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page (index.html).
+# This can be useful if you have a project on for instance GitHub and want reuse
 # the introduction page also for the doxygen output.
 
-USE_MDFILE_AS_MAINPAGE = 
+USE_MDFILE_AS_MAINPAGE =
 
 #---------------------------------------------------------------------------
 # configuration options related to source browsing
 #---------------------------------------------------------------------------
 
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
-# be generated. Documented entities will be cross-referenced with these sources. 
-# Note: To get rid of all source code in the generated output, make sure also 
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
 # VERBATIM_HEADERS is set to NO.
 
 SOURCE_BROWSER         = NO
 
-# Setting the INLINE_SOURCES tag to YES will include the body 
+# Setting the INLINE_SOURCES tag to YES will include the body
 # of functions and classes directly in the documentation.
 
 INLINE_SOURCES         = NO
 
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
-# doxygen to hide any special comment blocks from generated source code 
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
 # fragments. Normal C, C++ and Fortran comments will always remain visible.
 
 STRIP_CODE_COMMENTS    = NO
 
-# If the REFERENCED_BY_RELATION tag is set to YES 
-# then for each documented function all documented 
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
 # functions referencing it will be listed.
 
 REFERENCED_BY_RELATION = NO
 
-# If the REFERENCES_RELATION tag is set to YES 
-# then for each documented function all documented entities 
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
 # called/used by that function will be listed.
 
 REFERENCES_RELATION    = NO
 
-# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) 
-# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from 
-# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will 
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
 # link to the source code.  Otherwise they will link to the documentation.
 
 REFERENCES_LINK_SOURCE = YES
 
-# If the USE_HTAGS tag is set to YES then the references to source code 
-# will point to the HTML generated by the htags(1) tool instead of doxygen 
-# built-in source browser. The htags tool is part of GNU's global source 
-# tagging system (see http://www.gnu.org/software/global/global.html). You 
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
 # will need version 4.8.6 or higher.
 
 USE_HTAGS              = NO
 
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
-# will generate a verbatim copy of the header file for each class for 
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
 # which an include is specified. Set to NO to disable this.
 
 VERBATIM_HEADERS       = NO
@@ -891,170 +891,170 @@
 # configuration options related to the alphabetical class index
 #---------------------------------------------------------------------------
 
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
-# of all compounds will be generated. Enable this if the project 
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
 # contains a lot of classes, structs, unions or interfaces.
 
 ALPHABETICAL_INDEX     = NO
 
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
 # in which this list will be split (can be a number in the range [1..20])
 
 COLS_IN_ALPHA_INDEX    = 5
 
-# In case all classes in a project start with a common prefix, all 
-# classes will be put under the same header in the alphabetical index. 
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
 # should be ignored while generating the index headers.
 
-IGNORE_PREFIX          = 
+IGNORE_PREFIX          =
 
 #---------------------------------------------------------------------------
 # configuration options related to the HTML output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
 # generate HTML output.
 
 GENERATE_HTML          = YES
 
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
 # put in front of it. If left blank `html' will be used as the default path.
 
 HTML_OUTPUT            = $(HTML_OUTPUT)
 
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
 # doxygen will generate files with .html extension.
 
 HTML_FILE_EXTENSION    = .html
 
-# The HTML_HEADER tag can be used to specify a personal HTML header for 
-# each generated HTML page. If it is left blank doxygen will generate a 
-# standard header. Note that when using a custom header you are responsible  
-# for the proper inclusion of any scripts and style sheets that doxygen 
-# needs, which is dependent on the configuration options used. 
-# It is advised to generate a default header using "doxygen -w html 
-# header.html footer.html stylesheet.css YourConfigFile" and then modify 
-# that header. Note that the header is subject to change so you typically 
-# have to redo this when upgrading to a newer version of doxygen or when 
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header. Note that when using a custom header you are responsible
+# for the proper inclusion of any scripts and style sheets that doxygen
+# needs, which is dependent on the configuration options used.
+# It is advised to generate a default header using "doxygen -w html
+# header.html footer.html stylesheet.css YourConfigFile" and then modify
+# that header. Note that the header is subject to change so you typically
+# have to redo this when upgrading to a newer version of doxygen or when
 # changing the value of configuration settings such as GENERATE_TREEVIEW!
 
 HTML_HEADER            = $(HTML_HEADER)
 
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
-# each generated HTML page. If it is left blank doxygen will generate a 
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
 # standard footer.
 
 HTML_FOOTER            = $(HTML_FOOTER)
 
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
-# style sheet that is used by each HTML page. It can be used to 
-# fine-tune the look of the HTML output. If left blank doxygen will 
-# generate a default style sheet. Note that it is recommended to use 
-# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this 
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If left blank doxygen will
+# generate a default style sheet. Note that it is recommended to use
+# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this
 # tag will in the future become obsolete.
 
-HTML_STYLESHEET        = 
+HTML_STYLESHEET        =
 
-# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional 
-# user-defined cascading style sheet that is included after the standard 
-# style sheets created by doxygen. Using this option one can overrule 
-# certain style aspects. This is preferred over using HTML_STYLESHEET 
-# since it does not replace the standard style sheet and is therefor more 
-# robust against future updates. Doxygen will copy the style sheet file to 
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional
+# user-defined cascading style sheet that is included after the standard
+# style sheets created by doxygen. Using this option one can overrule
+# certain style aspects. This is preferred over using HTML_STYLESHEET
+# since it does not replace the standard style sheet and is therefor more
+# robust against future updates. Doxygen will copy the style sheet file to
 # the output directory.
 
-HTML_EXTRA_STYLESHEET  = 
+HTML_EXTRA_STYLESHEET  =
 
-# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or 
-# other source files which should be copied to the HTML output directory. Note 
-# that these files will be copied to the base HTML output directory. Use the 
-# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these 
-# files. In the HTML_STYLESHEET file, use the file name only. Also note that 
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that
 # the files will be copied as-is; there are no commands or markers available.
 
-HTML_EXTRA_FILES       = 
+HTML_EXTRA_FILES       =
 
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. 
-# Doxygen will adjust the colors in the style sheet and background images 
-# according to this color. Hue is specified as an angle on a colorwheel, 
-# see http://en.wikipedia.org/wiki/Hue for more information. 
-# For instance the value 0 represents red, 60 is yellow, 120 is green, 
-# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. 
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the style sheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
 # The allowed range is 0 to 359.
 
 HTML_COLORSTYLE_HUE    = 220
 
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of 
-# the colors in the HTML output. For a value of 0 the output will use 
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
 # grayscales only. A value of 255 will produce the most vivid colors.
 
 HTML_COLORSTYLE_SAT    = 0
 
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to 
-# the luminance component of the colors in the HTML output. Values below 
-# 100 gradually make the output lighter, whereas values above 100 make 
-# the output darker. The value divided by 100 is the actual gamma applied, 
-# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, 
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
 # and 100 does not change the gamma.
 
 HTML_COLORSTYLE_GAMMA  = 80
 
-# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML 
-# page will contain the date and time when the page was generated. Setting 
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
 # this to NO can help when comparing the output of multiple runs.
 
 HTML_TIMESTAMP         = YES
 
-# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 
-# documentation will contain sections that can be hidden and shown after the 
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
 # page has loaded.
 
 HTML_DYNAMIC_SECTIONS  = NO
 
-# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of 
-# entries shown in the various tree structured indices initially; the user 
-# can expand and collapse entries dynamically later on. Doxygen will expand 
-# the tree to such a level that at most the specified number of entries are 
-# visible (unless a fully collapsed tree already exceeds this amount). 
-# So setting the number of entries 1 will produce a full collapsed tree by 
-# default. 0 is a special value representing an infinite number of entries 
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
+# entries shown in the various tree structured indices initially; the user
+# can expand and collapse entries dynamically later on. Doxygen will expand
+# the tree to such a level that at most the specified number of entries are
+# visible (unless a fully collapsed tree already exceeds this amount).
+# So setting the number of entries 1 will produce a full collapsed tree by
+# default. 0 is a special value representing an infinite number of entries
 # and will result in a full expanded tree by default.
 
 HTML_INDEX_NUM_ENTRIES = 100
 
-# If the GENERATE_DOCSET tag is set to YES, additional index files 
-# will be generated that can be used as input for Apple's Xcode 3 
-# integrated development environment, introduced with OSX 10.5 (Leopard). 
-# To create a documentation set, doxygen will generate a Makefile in the 
-# HTML output directory. Running make will produce the docset in that 
-# directory and running "make install" will install the docset in 
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find 
-# it at startup. 
-# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html 
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
 # for more information.
 
 GENERATE_DOCSET        = NO
 
-# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the 
-# feed. A documentation feed provides an umbrella under which multiple 
-# documentation sets from a single provider (such as a company or product suite) 
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
 # can be grouped.
 
 DOCSET_FEEDNAME        = "Doxygen generated docs"
 
-# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that 
-# should uniquely identify the documentation set bundle. This should be a 
-# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen 
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
 # will append .docset to the name.
 
 DOCSET_BUNDLE_ID       = org.doxygen.Project
 
-# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely 
-# identify the documentation publisher. This should be a reverse domain-name 
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely
+# identify the documentation publisher. This should be a reverse domain-name
 # style string, e.g. com.mycompany.MyDocSet.documentation.
 
 DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
@@ -1063,361 +1063,361 @@
 
 DOCSET_PUBLISHER_NAME  = Publisher
 
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
-# will be generated that can be used as input for tools like the 
-# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) 
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
 # of the generated HTML documentation.
 
 GENERATE_HTMLHELP      = NO
 
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
-# be used to specify the file name of the resulting .chm file. You 
-# can add a path in front of the file if the result should not be 
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
 # written to the html output directory.
 
-CHM_FILE               = 
+CHM_FILE               =
 
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
-# be used to specify the location (absolute path including file name) of 
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
 # the HTML help compiler on the generated index.hhp.
 
-HHC_LOCATION           = 
+HHC_LOCATION           =
 
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
-# controls if a separate .chi index file is generated (YES) or that 
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
 # it should be included in the master .chm file (NO).
 
 GENERATE_CHI           = NO
 
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING 
-# is used to encode HtmlHelp index (hhk), content (hhc) and project file 
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
 # content.
 
-CHM_INDEX_ENCODING     = 
+CHM_INDEX_ENCODING     =
 
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
-# controls whether a binary table of contents is generated (YES) or a 
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
 # normal table of contents (NO) in the .chm file.
 
 BINARY_TOC             = NO
 
-# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
 # to the contents of the HTML help documentation and to the tree view.
 
 TOC_EXPAND             = NO
 
-# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and 
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated 
-# that can be used as input for Qt's qhelpgenerator to generate a 
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
 # Qt Compressed Help (.qch) of the generated HTML documentation.
 
 GENERATE_QHP           = NO
 
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can 
-# be used to specify the file name of the resulting .qch file. 
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
 # The path specified is relative to the HTML output folder.
 
-QCH_FILE               = 
+QCH_FILE               =
 
-# The QHP_NAMESPACE tag specifies the namespace to use when generating 
-# Qt Help Project output. For more information please see 
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
 # http://doc.trolltech.com/qthelpproject.html#namespace
 
 QHP_NAMESPACE          = org.doxygen.Project
 
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating 
-# Qt Help Project output. For more information please see 
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
 # http://doc.trolltech.com/qthelpproject.html#virtual-folders
 
 QHP_VIRTUAL_FOLDER     = doc
 
-# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to 
-# add. For more information please see 
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
 # http://doc.trolltech.com/qthelpproject.html#custom-filters
 
-QHP_CUST_FILTER_NAME   = 
+QHP_CUST_FILTER_NAME   =
 
-# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the 
-# custom filter to add. For more information please see 
-# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> 
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
 # Qt Help Project / Custom Filters</a>.
 
-QHP_CUST_FILTER_ATTRS  = 
+QHP_CUST_FILTER_ATTRS  =
 
-# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this 
-# project's 
-# filter section matches. 
-# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> 
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
 # Qt Help Project / Filter Attributes</a>.
 
-QHP_SECT_FILTER_ATTRS  = 
+QHP_SECT_FILTER_ATTRS  =
 
-# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can 
-# be used to specify the location of Qt's qhelpgenerator. 
-# If non-empty doxygen will try to run qhelpgenerator on the generated 
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
 # .qhp file.
 
-QHG_LOCATION           = 
+QHG_LOCATION           =
 
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files  
-# will be generated, which together with the HTML files, form an Eclipse help 
-# plugin. To install this plugin and make it available under the help contents 
-# menu in Eclipse, the contents of the directory containing the HTML and XML 
-# files needs to be copied into the plugins directory of eclipse. The name of 
-# the directory within the plugins directory should be the same as 
-# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before 
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+# will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
 # the help appears.
 
 GENERATE_ECLIPSEHELP   = NO
 
-# A unique identifier for the eclipse help plugin. When installing the plugin 
-# the directory name containing the HTML and XML files should also have 
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
 # this name.
 
 ECLIPSE_DOC_ID         = org.doxygen.Project
 
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) 
-# at top of each HTML page. The value NO (the default) enables the index and 
-# the value YES disables it. Since the tabs have the same information as the 
-# navigation tree you can set this option to NO if you already set 
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
+# at top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it. Since the tabs have the same information as the
+# navigation tree you can set this option to NO if you already set
 # GENERATE_TREEVIEW to YES.
 
 DISABLE_INDEX          = YES
 
-# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index 
-# structure should be generated to display hierarchical information. 
-# If the tag value is set to YES, a side panel will be generated 
-# containing a tree-like index structure (just like the one that 
-# is generated for HTML Help). For this to work a browser that supports 
-# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). 
-# Windows users are probably better off using the HTML help feature. 
-# Since the tree basically has the same information as the tab index you 
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+# Since the tree basically has the same information as the tab index you
 # could consider to set DISABLE_INDEX to NO when enabling this option.
 
 GENERATE_TREEVIEW      = NO
 
-# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values 
-# (range [0,1..20]) that doxygen will group on one line in the generated HTML 
-# documentation. Note that a value of 0 will completely suppress the enum 
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML
+# documentation. Note that a value of 0 will completely suppress the enum
 # values from appearing in the overview section.
 
 ENUM_VALUES_PER_LINE   = 4
 
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
-# used to set the initial width (in pixels) of the frame in which the tree 
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
 # is shown.
 
 TREEVIEW_WIDTH         = 250
 
-# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open 
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
 # links to external symbols imported via tag files in a separate window.
 
 EXT_LINKS_IN_WINDOW    = NO
 
-# Use this tag to change the font size of Latex formulas included 
-# as images in the HTML documentation. The default is 10. Note that 
-# when you change the font size after a successful doxygen run you need 
-# to manually remove any form_*.png images from the HTML output directory 
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
 # to force them to be regenerated.
 
 FORMULA_FONTSIZE       = 10
 
-# Use the FORMULA_TRANPARENT tag to determine whether or not the images 
-# generated for formulas are transparent PNGs. Transparent PNGs are 
-# not supported properly for IE 6.0, but are supported on all modern browsers. 
-# Note that when changing this option you need to delete any form_*.png files 
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
 # in the HTML output before the changes have effect.
 
 FORMULA_TRANSPARENT    = YES
 
-# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax 
-# (see http://www.mathjax.org) which uses client side Javascript for the 
-# rendering instead of using prerendered bitmaps. Use this if you do not 
-# have LaTeX installed or if you want to formulas look prettier in the HTML 
-# output. When enabled you may also need to install MathJax separately and 
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you may also need to install MathJax separately and
 # configure the path to it using the MATHJAX_RELPATH option.
 
 USE_MATHJAX            = NO
 
-# When MathJax is enabled you can set the default output format to be used for 
-# thA MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and 
-# SVG. The default value is HTML-CSS, which is slower, but has the best 
+# When MathJax is enabled you can set the default output format to be used for
+# thA MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and
+# SVG. The default value is HTML-CSS, which is slower, but has the best
 # compatibility.
 
 MATHJAX_FORMAT         = HTML-CSS
 
-# When MathJax is enabled you need to specify the location relative to the 
-# HTML output directory using the MATHJAX_RELPATH option. The destination 
-# directory should contain the MathJax.js script. For instance, if the mathjax 
-# directory is located at the same level as the HTML output directory, then 
-# MATHJAX_RELPATH should be ../mathjax. The default value points to 
-# the MathJax Content Delivery Network so you can quickly see the result without 
-# installing MathJax.  However, it is strongly recommended to install a local 
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to
+# the MathJax Content Delivery Network so you can quickly see the result without
+# installing MathJax.  However, it is strongly recommended to install a local
 # copy of MathJax from http://www.mathjax.org before deployment.
 
 MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
 
-# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension 
+# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
 # names that should be enabled during MathJax rendering.
 
-MATHJAX_EXTENSIONS     = 
+MATHJAX_EXTENSIONS     =
 
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box 
-# for the HTML output. The underlying search engine uses javascript 
-# and DHTML and should work on any modern browser. Note that when using 
-# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets 
-# (GENERATE_DOCSET) there is already a search function so this one should 
-# typically be disabled. For large projects the javascript based search engine 
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
 # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
 
 SEARCHENGINE           = NO
 
-# When the SERVER_BASED_SEARCH tag is enabled the search engine will be 
-# implemented using a web server instead of a web client using Javascript. 
-# There are two flavours of web server based search depending on the 
-# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for 
-# searching and an index file used by the script. When EXTERNAL_SEARCH is 
-# enabled the indexing and searching needs to be provided by external tools. 
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript.
+# There are two flavours of web server based search depending on the
+# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
+# searching and an index file used by the script. When EXTERNAL_SEARCH is
+# enabled the indexing and searching needs to be provided by external tools.
 # See the manual for details.
 
 SERVER_BASED_SEARCH    = NO
 
-# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP 
-# script for searching. Instead the search results are written to an XML file 
-# which needs to be processed by an external indexer. Doxygen will invoke an 
-# external search engine pointed to by the SEARCHENGINE_URL option to obtain 
-# the search results. Doxygen ships with an example indexer (doxyindexer) and 
-# search engine (doxysearch.cgi) which are based on the open source search engine 
+# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain
+# the search results. Doxygen ships with an example indexer (doxyindexer) and
+# search engine (doxysearch.cgi) which are based on the open source search engine
 # library Xapian. See the manual for configuration details.
 
 EXTERNAL_SEARCH        = NO
 
-# The SEARCHENGINE_URL should point to a search engine hosted by a web server 
-# which will returned the search results when EXTERNAL_SEARCH is enabled. 
-# Doxygen ships with an example search engine (doxysearch) which is based on 
-# the open source search engine library Xapian. See the manual for configuration 
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will returned the search results when EXTERNAL_SEARCH is enabled.
+# Doxygen ships with an example search engine (doxysearch) which is based on
+# the open source search engine library Xapian. See the manual for configuration
 # details.
 
-SEARCHENGINE_URL       = 
+SEARCHENGINE_URL       =
 
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed 
-# search data is written to a file for indexing by an external tool. With the 
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
 # SEARCHDATA_FILE tag the name of this file can be specified.
 
 SEARCHDATA_FILE        = searchdata.xml
 
-# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the 
-# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is 
-# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple 
+# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
 # projects and redirect the results back to the right project.
 
-EXTERNAL_SEARCH_ID     = 
+EXTERNAL_SEARCH_ID     =
 
-# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen 
-# projects other than the one defined by this configuration file, but that are 
-# all added to the same external search index. Each project needs to have a 
-# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id 
-# of to a relative location where the documentation can be found. 
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id
+# of to a relative location where the documentation can be found.
 # The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ...
 
-EXTRA_SEARCH_MAPPINGS  = 
+EXTRA_SEARCH_MAPPINGS  =
 
 #---------------------------------------------------------------------------
 # configuration options related to the LaTeX output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
 # generate Latex output.
 
 GENERATE_LATEX         = NO
 
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
 # put in front of it. If left blank `latex' will be used as the default path.
 
 LATEX_OUTPUT           = latex
 
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
-# invoked. If left blank `latex' will be used as the default command name. 
-# Note that when enabling USE_PDFLATEX this option is only used for 
-# generating bitmaps for formulas in the HTML output, but not in the 
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
 # Makefile that is written to the output directory.
 
 LATEX_CMD_NAME         = latex
 
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
-# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
 # default command name.
 
 MAKEINDEX_CMD_NAME     = makeindex
 
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
-# LaTeX documents. This may be useful for small projects and may help to 
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
 # save some trees in general.
 
 COMPACT_LATEX          = NO
 
-# The PAPER_TYPE tag can be used to set the paper type that is used 
-# by the printer. Possible values are: a4, letter, legal and 
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
 # executive. If left blank a4wide will be used.
 
 PAPER_TYPE             = a4
 
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
 # packages that should be included in the LaTeX output.
 
-EXTRA_PACKAGES         = 
+EXTRA_PACKAGES         =
 
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
-# the generated latex document. The header should contain everything until 
-# the first chapter. If it is left blank doxygen will generate a 
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
 # standard header. Notice: only use this tag if you know what you are doing!
 
-LATEX_HEADER           = 
+LATEX_HEADER           =
 
-# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for 
-# the generated latex document. The footer should contain everything after 
-# the last chapter. If it is left blank doxygen will generate a 
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
+# the generated latex document. The footer should contain everything after
+# the last chapter. If it is left blank doxygen will generate a
 # standard footer. Notice: only use this tag if you know what you are doing!
 
-LATEX_FOOTER           = 
+LATEX_FOOTER           =
 
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
-# contain links (just like the HTML output) instead of page references 
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
 # This makes the output suitable for online browsing using a pdf viewer.
 
 PDF_HYPERLINKS         = YES
 
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
-# plain latex in the generated Makefile. Set this option to YES to get a 
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
 # higher quality PDF documentation.
 
 USE_PDFLATEX           = YES
 
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
-# command to the generated LaTeX files. This will instruct LaTeX to keep 
-# running if errors occur, instead of asking the user for help. 
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
 # This option is also used when generating formulas in HTML.
 
 LATEX_BATCHMODE        = NO
 
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
-# include the index chapters (such as File Index, Compound Index, etc.) 
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
 # in the output.
 
 LATEX_HIDE_INDICES     = NO
 
-# If LATEX_SOURCE_CODE is set to YES then doxygen will include 
-# source code with syntax highlighting in the LaTeX output. 
-# Note that which sources are shown also depends on other settings 
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
 # such as SOURCE_BROWSER.
 
 LATEX_SOURCE_CODE      = NO
 
-# The LATEX_BIB_STYLE tag can be used to specify the style to use for the 
-# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See 
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
 # http://en.wikipedia.org/wiki/BibTeX for more info.
 
 LATEX_BIB_STYLE        = plain
@@ -1426,68 +1426,68 @@
 # configuration options related to the RTF output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
-# The RTF output is optimized for Word 97 and may not look very pretty with 
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
 # other RTF readers or editors.
 
 GENERATE_RTF           = NO
 
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
 # put in front of it. If left blank `rtf' will be used as the default path.
 
 RTF_OUTPUT             = rtf
 
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
-# RTF documents. This may be useful for small projects and may help to 
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
 # save some trees in general.
 
 COMPACT_RTF            = NO
 
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
-# will contain hyperlink fields. The RTF file will 
-# contain links (just like the HTML output) instead of page references. 
-# This makes the output suitable for online browsing using WORD or other 
-# programs which support those fields. 
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
 # Note: wordpad (write) and others do not support links.
 
 RTF_HYPERLINKS         = NO
 
-# Load style sheet definitions from file. Syntax is similar to doxygen's 
-# config file, i.e. a series of assignments. You only have to provide 
+# Load style sheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
 # replacements, missing definitions are set to their default value.
 
-RTF_STYLESHEET_FILE    = 
+RTF_STYLESHEET_FILE    =
 
-# Set optional variables used in the generation of an rtf document. 
+# Set optional variables used in the generation of an rtf document.
 # Syntax is similar to doxygen's config file.
 
-RTF_EXTENSIONS_FILE    = 
+RTF_EXTENSIONS_FILE    =
 
 #---------------------------------------------------------------------------
 # configuration options related to the man page output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
 # generate man pages
 
 GENERATE_MAN           = NO
 
-# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
 # put in front of it. If left blank `man' will be used as the default path.
 
 MAN_OUTPUT             = man
 
-# The MAN_EXTENSION tag determines the extension that is added to 
+# The MAN_EXTENSION tag determines the extension that is added to
 # the generated man pages (default is the subroutine's section .3)
 
 MAN_EXTENSION          = .3
 
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
-# then it will generate one additional man file for each entity 
-# documented in the real man page(s). These additional files 
-# only source the real man page, but without them the man command 
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
 # would be unable to find the correct page. The default is NO.
 
 MAN_LINKS              = NO
@@ -1496,33 +1496,33 @@
 # configuration options related to the XML output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_XML tag is set to YES Doxygen will 
-# generate an XML file that captures the structure of 
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
 # the code including all documentation.
 
 GENERATE_XML           = NO
 
-# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
 # put in front of it. If left blank `xml' will be used as the default path.
 
 XML_OUTPUT             = xml
 
-# The XML_SCHEMA tag can be used to specify an XML schema, 
-# which can be used by a validating XML parser to check the 
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
 # syntax of the XML files.
 
-XML_SCHEMA             = 
+XML_SCHEMA             =
 
-# The XML_DTD tag can be used to specify an XML DTD, 
-# which can be used by a validating XML parser to check the 
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
 # syntax of the XML files.
 
-XML_DTD                = 
+XML_DTD                =
 
-# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
-# dump the program listings (including syntax highlighting 
-# and cross-referencing information) to the XML output. Note that 
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
 # enabling this will significantly increase the size of the XML output.
 
 XML_PROGRAMLISTING     = YES
@@ -1531,10 +1531,10 @@
 # configuration options for the AutoGen Definitions output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
-# generate an AutoGen Definitions (see autogen.sf.net) file 
-# that captures the structure of the code including all 
-# documentation. Note that this feature is still experimental 
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
 # and incomplete at the moment.
 
 GENERATE_AUTOGEN_DEF   = NO
@@ -1543,97 +1543,97 @@
 # configuration options related to the Perl module output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
-# generate a Perl module file that captures the structure of 
-# the code including all documentation. Note that this 
-# feature is still experimental and incomplete at the 
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
 # moment.
 
 GENERATE_PERLMOD       = NO
 
-# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
-# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
 # to generate PDF and DVI output from the Perl module output.
 
 PERLMOD_LATEX          = NO
 
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
-# nicely formatted so it can be parsed by a human reader.  This is useful 
-# if you want to understand what is going on.  On the other hand, if this 
-# tag is set to NO the size of the Perl module output will be much smaller 
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.  This is useful
+# if you want to understand what is going on.  On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
 # and Perl will parse it just the same.
 
 PERLMOD_PRETTY         = YES
 
-# The names of the make variables in the generated doxyrules.make file 
-# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
-# This is useful so different doxyrules.make files included by the same 
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
 # Makefile don't overwrite each other's variables.
 
-PERLMOD_MAKEVAR_PREFIX = 
+PERLMOD_MAKEVAR_PREFIX =
 
 #---------------------------------------------------------------------------
 # Configuration options related to the preprocessor
 #---------------------------------------------------------------------------
 
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
-# evaluate all C-preprocessor directives found in the sources and include 
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
 # files.
 
-ENABLE_PREPROCESSING   = YES
+ENABLE_PREPROCESSING   = NO
 
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
-# names in the source code. If set to NO (the default) only conditional 
-# compilation will be performed. Macro expansion can be done in a controlled 
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
 # way by setting EXPAND_ONLY_PREDEF to YES.
 
 MACRO_EXPANSION        = NO
 
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
-# then the macro expansion is limited to the macros specified with the 
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
 # PREDEFINED and EXPAND_AS_DEFINED tags.
 
 EXPAND_ONLY_PREDEF     = NO
 
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
 # pointed to by INCLUDE_PATH will be searched when a #include is found.
 
 SEARCH_INCLUDES        = YES
 
-# The INCLUDE_PATH tag can be used to specify one or more directories that 
-# contain include files that are not input files but should be processed by 
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
 # the preprocessor.
 
-INCLUDE_PATH           = 
+INCLUDE_PATH           =
 
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
-# patterns (like *.h and *.hpp) to filter out the header-files in the 
-# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
 # be used.
 
-INCLUDE_FILE_PATTERNS  = 
+INCLUDE_FILE_PATTERNS  =
 
-# The PREDEFINED tag can be used to specify one or more macro names that 
-# are defined before the preprocessor is started (similar to the -D option of 
-# gcc). The argument of the tag is a list of macros of the form: name 
-# or name=definition (no spaces). If the definition and the = are 
-# omitted =1 is assumed. To prevent a macro definition from being 
-# undefined via #undef or recursively expanded use the := operator 
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
 # instead of the = operator.
 
-PREDEFINED             = 
+PREDEFINED             =
 
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
-# this tag can be used to specify a list of macro names that should be expanded. 
-# The macro definition that is found in the sources will be used. 
-# Use the PREDEFINED tag if you want to use a different macro definition that 
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that
 # overrules the definition found in the source code.
 
-EXPAND_AS_DEFINED      = 
+EXPAND_AS_DEFINED      =
 
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
-# doxygen's preprocessor will remove all references to function-like macros 
-# that are alone on a line, have an all uppercase name, and do not end with a 
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
 # semicolon, because these will confuse the parser if not removed.
 
 SKIP_FUNCTION_MACROS   = YES
@@ -1642,37 +1642,37 @@
 # Configuration::additions related to external references
 #---------------------------------------------------------------------------
 
-# The TAGFILES option can be used to specify one or more tagfiles. For each 
-# tag file the location of the external documentation should be added. The 
-# format of a tag file without this location is as follows: 
-#   TAGFILES = file1 file2 ... 
-# Adding location for the tag files is done as follows: 
-#   TAGFILES = file1=loc1 "file2 = loc2" ... 
-# where "loc1" and "loc2" can be relative or absolute paths 
-# or URLs. Note that each tag file must have a unique name (where the name does 
-# NOT include the path). If a tag file is not located in the directory in which 
+# The TAGFILES option can be used to specify one or more tagfiles. For each
+# tag file the location of the external documentation should be added. The
+# format of a tag file without this location is as follows:
+#   TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#   TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths
+# or URLs. Note that each tag file must have a unique name (where the name does
+# NOT include the path). If a tag file is not located in the directory in which
 # doxygen is run, you must also specify the path to the tagfile here.
 
-TAGFILES               = 
+TAGFILES               =
 
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
 # a tag file that is based on the input files it reads.
 
-GENERATE_TAGFILE       = 
+GENERATE_TAGFILE       =
 
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
-# in the class index. If set to NO only the inherited external classes 
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
 # will be listed.
 
 ALLEXTERNALS           = NO
 
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
-# in the modules index. If set to NO, only the current project's groups will 
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
 # be listed.
 
 EXTERNAL_GROUPS        = YES
 
-# The PERL_PATH should be the absolute path and name of the perl script 
+# The PERL_PATH should be the absolute path and name of the perl script
 # interpreter (i.e. the result of `which perl').
 
 PERL_PATH              = /usr/bin/perl
@@ -1681,222 +1681,222 @@
 # Configuration options related to the dot tool
 #---------------------------------------------------------------------------
 
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
-# or super classes. Setting the tag to NO turns the diagrams off. Note that 
-# this option also works with HAVE_DOT disabled, but it is recommended to 
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
 # install and use dot, since it yields more powerful graphs.
 
 CLASS_DIAGRAMS         = NO
 
-# You can define message sequence charts within doxygen comments using the \msc 
-# command. Doxygen will then run the mscgen tool (see 
-# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the 
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where 
-# the mscgen tool resides. If left empty the tool is assumed to be found in the 
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
 # default search path.
 
-MSCGEN_PATH            = 
+MSCGEN_PATH            =
 
-# If set to YES, the inheritance and collaboration graphs will hide 
-# inheritance and usage relations if the target is undocumented 
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
 # or is not a class.
 
 HIDE_UNDOC_RELATIONS   = YES
 
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
-# available from the path. This tool is part of Graphviz, a graph visualization 
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
 # have no effect if this option is set to NO (the default)
 
 HAVE_DOT               = NO
 
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is 
-# allowed to run in parallel. When set to 0 (the default) doxygen will 
-# base this on the number of processors available in the system. You can set it 
-# explicitly to a value larger than 0 to get control over the balance 
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
 # between CPU load and processing speed.
 
 DOT_NUM_THREADS        = 0
 
-# By default doxygen will use the Helvetica font for all dot files that 
-# doxygen generates. When you want a differently looking font you can specify 
-# the font name using DOT_FONTNAME. You need to make sure dot is able to find 
-# the font, which can be done by putting it in a standard location or by setting 
-# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the 
+# By default doxygen will use the Helvetica font for all dot files that
+# doxygen generates. When you want a differently looking font you can specify
+# the font name using DOT_FONTNAME. You need to make sure dot is able to find
+# the font, which can be done by putting it in a standard location or by setting
+# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
 # directory containing the font.
 
 DOT_FONTNAME           = Helvetica
 
-# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. 
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
 # The default size is 10pt.
 
 DOT_FONTSIZE           = 10
 
-# By default doxygen will tell dot to use the Helvetica font. 
-# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to 
+# By default doxygen will tell dot to use the Helvetica font.
+# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
 # set the path where dot can find it.
 
-DOT_FONTPATH           = 
+DOT_FONTPATH           =
 
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
-# will generate a graph for each documented class showing the direct and 
-# indirect inheritance relations. Setting this tag to YES will force the 
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
 # CLASS_DIAGRAMS tag to NO.
 
 CLASS_GRAPH            = YES
 
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
-# will generate a graph for each documented class showing the direct and 
-# indirect implementation dependencies (inheritance, containment, and 
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
 # class references variables) of the class with other documented classes.
 
 COLLABORATION_GRAPH    = YES
 
-# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
 # will generate a graph for groups, showing the direct groups dependencies
 
 GROUP_GRAPHS           = YES
 
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
-# collaboration diagrams in a style similar to the OMG's Unified Modeling 
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
 # Language.
 
 UML_LOOK               = NO
 
-# If the UML_LOOK tag is enabled, the fields and methods are shown inside 
-# the class node. If there are many fields or methods and many nodes the 
-# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS 
-# threshold limits the number of items for each type to make the size more 
-# managable. Set this to 0 for no limit. Note that the threshold may be 
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside
+# the class node. If there are many fields or methods and many nodes the
+# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
+# threshold limits the number of items for each type to make the size more
+# managable. Set this to 0 for no limit. Note that the threshold may be
 # exceeded by 50% before the limit is enforced.
 
 UML_LIMIT_NUM_FIELDS   = 10
 
-# If set to YES, the inheritance and collaboration graphs will show the 
+# If set to YES, the inheritance and collaboration graphs will show the
 # relations between templates and their instances.
 
 TEMPLATE_RELATIONS     = NO
 
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
-# tags are set to YES then doxygen will generate a graph for each documented 
-# file showing the direct and indirect include dependencies of the file with 
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
 # other documented files.
 
 INCLUDE_GRAPH          = YES
 
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
-# documented header file showing the documented files that directly or 
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
 # indirectly include this file.
 
 INCLUDED_BY_GRAPH      = YES
 
-# If the CALL_GRAPH and HAVE_DOT options are set to YES then 
-# doxygen will generate a call dependency graph for every global function 
-# or class method. Note that enabling this option will significantly increase 
-# the time of a run. So in most cases it will be better to enable call graphs 
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
 # for selected functions only using the \callgraph command.
 
 CALL_GRAPH             = NO
 
-# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then 
-# doxygen will generate a caller dependency graph for every global function 
-# or class method. Note that enabling this option will significantly increase 
-# the time of a run. So in most cases it will be better to enable caller 
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
 # graphs for selected functions only using the \callergraph command.
 
 CALLER_GRAPH           = NO
 
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
 # will generate a graphical hierarchy of all classes instead of a textual one.
 
 GRAPHICAL_HIERARCHY    = YES
 
-# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES 
-# then doxygen will show the dependencies a directory has on other directories 
-# in a graphical way. The dependency relations are determined by the #include 
+# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
 # relations between the files in the directories.
 
 DIRECTORY_GRAPH        = YES
 
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
-# generated by dot. Possible values are svg, png, jpg, or gif. 
-# If left blank png will be used. If you choose svg you need to set 
-# HTML_FILE_EXTENSION to xhtml in order to make the SVG files 
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are svg, png, jpg, or gif.
+# If left blank png will be used. If you choose svg you need to set
+# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
 # visible in IE 9+ (other browsers do not have this requirement).
 
 DOT_IMAGE_FORMAT       = png
 
-# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to 
-# enable generation of interactive SVG images that allow zooming and panning. 
-# Note that this requires a modern browser other than Internet Explorer. 
-# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you 
-# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files 
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+# Note that this requires a modern browser other than Internet Explorer.
+# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
+# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
 # visible. Older versions of IE do not have SVG support.
 
 INTERACTIVE_SVG        = NO
 
-# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
 # found. If left blank, it is assumed the dot tool can be found in the path.
 
-DOT_PATH               = 
+DOT_PATH               =
 
-# The DOTFILE_DIRS tag can be used to specify one or more directories that 
-# contain dot files that are included in the documentation (see the 
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
 # \dotfile command).
 
-DOTFILE_DIRS           = 
+DOTFILE_DIRS           =
 
-# The MSCFILE_DIRS tag can be used to specify one or more directories that 
-# contain msc files that are included in the documentation (see the 
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
 # \mscfile command).
 
-MSCFILE_DIRS           = 
+MSCFILE_DIRS           =
 
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 
-# nodes that will be shown in the graph. If the number of nodes in a graph 
-# becomes larger than this value, doxygen will truncate the graph, which is 
-# visualized by representing a node as a red box. Note that doxygen if the 
-# number of direct children of the root node in a graph is already larger than 
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note 
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
 # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
 
 DOT_GRAPH_MAX_NODES    = 50
 
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
-# graphs generated by dot. A depth value of 3 means that only nodes reachable 
-# from the root by following a path via at most 3 edges will be shown. Nodes 
-# that lay further from the root node will be omitted. Note that setting this 
-# option to 1 or 2 may greatly reduce the computation time needed for large 
-# code bases. Also note that the size of a graph can be further restricted by 
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
 # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
 
 MAX_DOT_GRAPH_DEPTH    = 0
 
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
-# background. This is disabled by default, because dot on Windows does not 
-# seem to support this out of the box. Warning: Depending on the platform used, 
-# enabling this option may lead to badly anti-aliased labels on the edges of 
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
 # a graph (i.e. they become hard to read).
 
 DOT_TRANSPARENT        = NO
 
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
-# files in one run (i.e. multiple -o and -T options on the command line). This 
-# makes dot run faster, but since only newer versions of dot (>1.8.10) 
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
 # support this, this feature is disabled by default.
 
 DOT_MULTI_TARGETS      = NO
 
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
-# generate a legend page explaining the meaning of the various boxes and 
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
 # arrows in the dot generated graphs.
 
 GENERATE_LEGEND        = YES
 
-# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
-# remove the intermediate dot files that are used to generate 
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
 # the various graphs.
 
 DOT_CLEANUP            = YES
diff --git a/include/android/asset_manager.h b/include/android/asset_manager.h
index d654839..7ef3ecb 100644
--- a/include/android/asset_manager.h
+++ b/include/android/asset_manager.h
@@ -26,6 +26,9 @@
 #ifndef ANDROID_ASSET_MANAGER_H
 #define ANDROID_ASSET_MANAGER_H
 
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -131,6 +134,7 @@
  */
 off_t AAsset_seek(AAsset* asset, off_t offset, int whence);
 
+#if __ANDROID_API__ >= 13
 /**
  * Seek to the specified offset within the asset data.  'whence' uses the
  * same constants as lseek()/fseek().
@@ -141,6 +145,7 @@
  * Returns the new position on success, or (off64_t) -1 on error.
  */
 off64_t AAsset_seek64(AAsset* asset, off64_t offset, int whence);
+#endif
 
 /**
  * Close the asset, freeing all associated resources.
@@ -159,23 +164,27 @@
  */
 off_t AAsset_getLength(AAsset* asset);
 
+#if __ANDROID_API__ >= 13
 /**
  * Report the total size of the asset data. Reports the size using a 64-bit
  * number insted of 32-bit as AAsset_getLength.
  */
 off64_t AAsset_getLength64(AAsset* asset);
+#endif
 
 /**
  * Report the total amount of asset data that can be read from the current position.
  */
 off_t AAsset_getRemainingLength(AAsset* asset);
 
+#if __ANDROID_API__ >= 13
 /**
  * Report the total amount of asset data that can be read from the current position.
  *
  * Uses a 64-bit number instead of a 32-bit number as AAsset_getRemainingLength does.
  */
 off64_t AAsset_getRemainingLength64(AAsset* asset);
+#endif
 
 /**
  * Open a new file descriptor that can be used to read the asset data. If the
@@ -187,6 +196,7 @@
  */
 int AAsset_openFileDescriptor(AAsset* asset, off_t* outStart, off_t* outLength);
 
+#if __ANDROID_API__ >= 13
 /**
  * Open a new file descriptor that can be used to read the asset data.
  *
@@ -197,6 +207,7 @@
  * compressed).
  */
 int AAsset_openFileDescriptor64(AAsset* asset, off64_t* outStart, off64_t* outLength);
+#endif
 
 /**
  * Returns whether this asset's internal buffer is allocated in ordinary RAM (i.e. not
diff --git a/include/android/bitmap.h b/include/android/bitmap.h
index 261e64f..2def64d 100644
--- a/include/android/bitmap.h
+++ b/include/android/bitmap.h
@@ -56,9 +56,9 @@
     ANDROID_BITMAP_FORMAT_RGBA_8888 = 1,
     /** Red: 5 bits, Green: 6 bits, Blue: 5 bits. **/
     ANDROID_BITMAP_FORMAT_RGB_565   = 4,
-    /** Red: 4 bits, Green: 4 bits, Blue: 4 bits, Alpha: 4 bits. **/
+    /** Deprecated in API level 13. Because of the poor quality of this configuration, it is advised to use ARGB_8888 instead. **/
     ANDROID_BITMAP_FORMAT_RGBA_4444 = 7,
-    /** Deprecated. */
+    /** Alpha: 8 bits. */
     ANDROID_BITMAP_FORMAT_A_8       = 8,
 };
 
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index 02c83dc..43346fe 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -30,6 +30,8 @@
 
 __BEGIN_DECLS
 
+#if __ANDROID_API__ >= 24
+
 struct AChoreographer;
 typedef struct AChoreographer AChoreographer;
 
@@ -62,6 +64,9 @@
  */
 void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
                 AChoreographer_frameCallback callback, void* data, long delayMillis);
+
+#endif /* __ANDROID_API__ >= 24 */
+
 __END_DECLS
 
 #endif // ANDROID_CHOREOGRAPHER_H
diff --git a/include/android/configuration.h b/include/android/configuration.h
index 81f71a9..6287332 100644
--- a/include/android/configuration.h
+++ b/include/android/configuration.h
@@ -26,6 +26,8 @@
 #ifndef ANDROID_CONFIGURATION_H
 #define ANDROID_CONFIGURATION_H
 
+#include <sys/cdefs.h>
+
 #include <android/asset_manager.h>
 
 #ifdef __cplusplus
@@ -265,6 +267,36 @@
     ACONFIGURATION_SCREENROUND_NO = 0x1,
     ACONFIGURATION_SCREENROUND_YES = 0x2,
 
+    /** Wide color gamut: not specified. */
+    ACONFIGURATION_WIDE_COLOR_GAMUT_ANY = 0x00,
+    /**
+     * Wide color gamut: value that corresponds to
+     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#WideColorGamutQualifier">no
+     * nowidecg</a> resource qualifier specified.
+     */
+    ACONFIGURATION_WIDE_COLOR_GAMUT_NO = 0x1,
+    /**
+     * Wide color gamut: value that corresponds to
+     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#WideColorGamutQualifier">
+     * widecg</a> resource qualifier specified.
+     */
+    ACONFIGURATION_WIDE_COLOR_GAMUT_YES = 0x2,
+
+    /** HDR: not specified. */
+    ACONFIGURATION_HDR_ANY = 0x00,
+    /**
+     * HDR: value that corresponds to
+     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#HDRQualifier">
+     * lowdr</a> resource qualifier specified.
+     */
+    ACONFIGURATION_HDR_NO = 0x1,
+    /**
+     * HDR: value that corresponds to
+     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#HDRQualifier">
+     * highdr</a> resource qualifier specified.
+     */
+    ACONFIGURATION_HDR_YES = 0x2,
+
     /** UI mode: not specified. */
     ACONFIGURATION_UI_MODE_TYPE_ANY = 0x00,
     /**
@@ -298,6 +330,11 @@
      * <a href="@dacRoot/guide/topics/resources/providing-resources.html#UiModeQualifier">watch</a> resource qualifier specified.
      */
     ACONFIGURATION_UI_MODE_TYPE_WATCH = 0x06,
+    /**
+     * UI mode: value that corresponds to
+     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#UiModeQualifier">vr</a> resource qualifier specified.
+     */
+    ACONFIGURATION_UI_MODE_TYPE_VR_HEADSET = 0x07,
 
     /** UI night mode: not specified.*/
     ACONFIGURATION_UI_MODE_NIGHT_ANY = 0x00,
@@ -424,6 +461,12 @@
     ACONFIGURATION_LAYOUTDIR = 0x4000,
     ACONFIGURATION_SCREEN_ROUND = 0x8000,
     /**
+     * Bit mask for
+     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#WideColorGamutQualifier">wide color gamut</a>
+     * and <a href="@dacRoot/guide/topics/resources/providing-resources.html#HDRQualifier">HDR</a> configurations.
+     */
+    ACONFIGURATION_COLOR_MODE = 0x10000,
+    /**
      * Constant used to to represent MNC (Mobile Network Code) zero.
      * 0 cannot be used, since it is used to represent an undefined MNC.
      */
@@ -628,6 +671,7 @@
  */
 void AConfiguration_setUiModeNight(AConfiguration* config, int32_t uiModeNight);
 
+#if __ANDROID_API__ >= 13
 /**
  * Return the current configuration screen width in dp units, or
  * ACONFIGURATION_SCREEN_WIDTH_DP_ANY if not set.
@@ -660,7 +704,9 @@
  * Set the configuration's smallest screen width in dp units.
  */
 void AConfiguration_setSmallestScreenWidthDp(AConfiguration* config, int32_t value);
+#endif /* __ANDROID_API__ >= 13 */
 
+#if __ANDROID_API__ >= 17
 /**
  * Return the configuration's layout direction, or
  * ACONFIGURATION_LAYOUTDIR_ANY if not set.
@@ -671,6 +717,7 @@
  * Set the configuration's layout direction.
  */
 void AConfiguration_setLayoutDirection(AConfiguration* config, int32_t value);
+#endif /* __ANDROID_API__ >= 17 */
 
 /**
  * Perform a diff between two configurations.  Returns a bit mask of
diff --git a/include/android/hardware_buffer_jni.h b/include/android/hardware_buffer_jni.h
new file mode 100644
index 0000000..6020870
--- /dev/null
+++ b/include/android/hardware_buffer_jni.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file hardware_buffer_jni.h
+ */
+
+#ifndef ANDROID_HARDWARE_BUFFER_JNI_H
+#define ANDROID_HARDWARE_BUFFER_JNI_H
+
+#include <sys/cdefs.h>
+
+#include <android/hardware_buffer.h>
+
+#include <jni.h>
+
+__BEGIN_DECLS
+
+/**
+ * Return the AHardwareBuffer associated with a Java HardwareBuffer object,
+ * for interacting with it through native code.  This acquires a reference
+ * on the AHardwareBuffer that is returned; be sure to use
+ * AHardwareBuffer_release() when done with it so that it doesn't leak.
+ */
+AHardwareBuffer* AHardwareBuffer_fromHardwareBuffer(JNIEnv* env,
+        jobject hardwareBufferObj);
+
+/**
+ * Return a new Java HardwareBuffer object that wraps the passed native
+ * AHardwareBuffer object.
+ */
+jobject AHardwareBuffer_toHardwareBuffer(JNIEnv* env,
+        AHardwareBuffer* hardwareBuffer);
+
+__END_DECLS
+
+#endif // ANDROID_HARDWARE_BUFFER_JNI_H
diff --git a/include/android/input.h b/include/android/input.h
index fd9fa98..0829989 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -26,6 +26,8 @@
 #ifndef _ANDROID_INPUT_H
 #define _ANDROID_INPUT_H
 
+#include <sys/cdefs.h>
+
 /******************************************************************
  *
  * IMPORTANT NOTICE:
@@ -833,6 +835,8 @@
     AINPUT_SOURCE_BLUETOOTH_STYLUS = 0x00008000 | AINPUT_SOURCE_STYLUS,
     /** trackball */
     AINPUT_SOURCE_TRACKBALL = 0x00010000 | AINPUT_SOURCE_CLASS_NAVIGATION,
+    /** mouse relative */
+    AINPUT_SOURCE_MOUSE_RELATIVE = 0x00020000 | AINPUT_SOURCE_CLASS_NAVIGATION,
     /** touchpad */
     AINPUT_SOURCE_TOUCHPAD = 0x00100000 | AINPUT_SOURCE_CLASS_POSITION,
     /** navigation */
@@ -978,8 +982,10 @@
  */
 int32_t AMotionEvent_getMetaState(const AInputEvent* motion_event);
 
+#if __ANDROID_API__ >= 14
 /** Get the button state of all buttons that are pressed. */
 int32_t AMotionEvent_getButtonState(const AInputEvent* motion_event);
+#endif
 
 /**
  * Get a bitfield indicating which edges, if any, were touched by this motion event.
@@ -1044,12 +1050,14 @@
  */
 int32_t AMotionEvent_getPointerId(const AInputEvent* motion_event, size_t pointer_index);
 
+#if __ANDROID_API__ >= 14
 /**
  * Get the tool type of a pointer for the given pointer index.
  * 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);
+#endif
 
 /**
  * Get the original raw X coordinate of this event.
@@ -1139,9 +1147,11 @@
  */
 float AMotionEvent_getOrientation(const AInputEvent* motion_event, size_t pointer_index);
 
+#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);
+#endif
 
 /**
  * Get the number of historical points in this event.  These are movements that
@@ -1272,12 +1282,14 @@
 float AMotionEvent_getHistoricalOrientation(const AInputEvent* motion_event, size_t pointer_index,
         size_t history_index);
 
+#if __ANDROID_API__ >= 13
 /**
  * Get the historical value of the request axis for the given pointer index
  * 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);
+#endif
 
 
 struct AInputQueue;
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index 6c718c9..97892f8 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -51,16 +51,15 @@
  * on failure with an appropriate errno value set.
  */
 
+#if __ANDROID_API__ >= 24
 
 /**
  * Set the network to be used by the given socket file descriptor.
  *
- * To clear a previous socket binding invoke with NETWORK_UNSPECIFIED.
+ * To clear a previous socket binding, invoke with NETWORK_UNSPECIFIED.
  *
- * This is the equivalent of:
+ * This is the equivalent of: [android.net.Network#bindSocket()](https://developer.android.com/reference/android/net/Network.html#bindSocket(java.net.Socket))
  *
- *     [ 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);
 
@@ -74,12 +73,10 @@
  * resolutions will fail.  This is by design so an application doesn't
  * accidentally use sockets it thinks are still bound to a particular network.
  *
- * To clear a previous process binding invoke with NETWORK_UNSPECIFIED.
+ * To clear a previous process binding, invoke with NETWORK_UNSPECIFIED.
  *
- * This is the equivalent of:
+ * This is the equivalent of: [android.net.ConnectivityManager#setProcessDefaultNetwork()](https://developer.android.com/reference/android/net/ConnectivityManager.html#setProcessDefaultNetwork(android.net.Network))
  *
- *     [ android.net.ConnectivityManager#setProcessDefaultNetwork() ]
- *     https://developer.android.com/reference/android/net/ConnectivityManager.html#setProcessDefaultNetwork(android.net.Network)
  */
 int android_setprocnetwork(net_handle_t network);
 
@@ -95,15 +92,15 @@
  *     - either |node| or |service| may be NULL, but not both
  *     - |res| must not be NULL
  *
- * This is the equivalent of:
+ * This is the equivalent of: [android.net.Network#getAllByName()](https://developer.android.com/reference/android/net/Network.html#getAllByName(java.lang.String))
  *
- *     [ android.net.Network#getAllByName() ]
- *     https://developer.android.com/reference/android/net/Network.html#getAllByName(java.lang.String)
  */
 int android_getaddrinfofornetwork(net_handle_t network,
         const char *node, const char *service,
         const struct addrinfo *hints, struct addrinfo **res);
 
+#endif /* __ANDROID_API__ >= 24 */
+
 __END_DECLS
 
 #endif  // ANDROID_MULTINETWORK_H
diff --git a/include/android/native_window.h b/include/android/native_window.h
deleted file mode 100644
index cf07f1a..0000000
--- a/include/android/native_window.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * @addtogroup NativeActivity Native Activity
- * @{
- */
-
-/**
- * @file native_window.h
- */
-
-#ifndef ANDROID_NATIVE_WINDOW_H
-#define ANDROID_NATIVE_WINDOW_H
-
-#include <android/rect.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Pixel formats that a window can use.
- */
-enum {
-    /** Red: 8 bits, Green: 8 bits, Blue: 8 bits, Alpha: 8 bits. **/
-    WINDOW_FORMAT_RGBA_8888          = 1,
-    /** Red: 8 bits, Green: 8 bits, Blue: 8 bits, Unused: 8 bits. **/
-    WINDOW_FORMAT_RGBX_8888          = 2,
-    /** Red: 5 bits, Green: 6 bits, Blue: 5 bits. **/
-    WINDOW_FORMAT_RGB_565            = 4,
-};
-
-struct ANativeWindow;
-/**
- * {@link ANativeWindow} is opaque type that provides access to a native window.
- *
- * A pointer can be obtained using ANativeWindow_fromSurface().
- */
-typedef struct ANativeWindow ANativeWindow;
-
-/**
- * {@link ANativeWindow} is a struct that represents a windows buffer.
- *
- * A pointer can be obtained using ANativeWindow_lock().
- */
-typedef struct ANativeWindow_Buffer {
-    // The number of pixels that are show horizontally.
-    int32_t width;
-
-    // The number of pixels that are shown vertically.
-    int32_t height;
-
-    // The number of *pixels* that a line in the buffer takes in
-    // memory.  This may be >= width.
-    int32_t stride;
-
-    // The format of the buffer.  One of WINDOW_FORMAT_*
-    int32_t format;
-
-    // The actual bits.
-    void* bits;
-
-    // Do not touch.
-    uint32_t reserved[6];
-} ANativeWindow_Buffer;
-
-/**
- * Acquire a reference on the given ANativeWindow object.  This prevents the object
- * from being deleted until the reference is removed.
- */
-void ANativeWindow_acquire(ANativeWindow* window);
-
-/**
- * Remove a reference that was previously acquired with ANativeWindow_acquire().
- */
-void ANativeWindow_release(ANativeWindow* window);
-
-/**
- * Return the current width in pixels of the window surface.  Returns a
- * negative value on error.
- */
-int32_t ANativeWindow_getWidth(ANativeWindow* window);
-
-/**
- * Return the current height in pixels of the window surface.  Returns a
- * negative value on error.
- */
-int32_t ANativeWindow_getHeight(ANativeWindow* window);
-
-/**
- * Return the current pixel format of the window surface.  Returns a
- * negative value on error.
- */
-int32_t ANativeWindow_getFormat(ANativeWindow* window);
-
-/**
- * Change the format and size of the window buffers.
- *
- * The width and height control the number of pixels in the buffers, not the
- * dimensions of the window on screen.  If these are different than the
- * window's physical size, then it buffer will be scaled to match that size
- * when compositing it to the screen.
- *
- * For all of these parameters, if 0 is supplied then the window's base
- * value will come back in force.
- *
- * width and height must be either both zero or both non-zero.
- *
- */
-int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window,
-        int32_t width, int32_t height, int32_t format);
-
-/**
- * Lock the window's next drawing surface for writing.
- * inOutDirtyBounds is used as an in/out parameter, upon entering the
- * function, it contains the dirty region, that is, the region the caller
- * intends to redraw. When the function returns, inOutDirtyBounds is updated
- * with the actual area the caller needs to redraw -- this region is often
- * extended by ANativeWindow_lock.
- */
-int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
-        ARect* inOutDirtyBounds);
-
-/**
- * Unlock the window's drawing surface after previously locking it,
- * posting the new buffer to the display.
- */
-int32_t ANativeWindow_unlockAndPost(ANativeWindow* window);
-
-#ifdef __cplusplus
-};
-#endif
-
-#endif // ANDROID_NATIVE_WINDOW_H
-
-/** @} */
diff --git a/include/android/native_window_jni.h b/include/android/native_window_jni.h
index 60a36c3..23b39aa 100644
--- a/include/android/native_window_jni.h
+++ b/include/android/native_window_jni.h
@@ -26,6 +26,8 @@
 #ifndef ANDROID_NATIVE_WINDOW_JNI_H
 #define ANDROID_NATIVE_WINDOW_JNI_H
 
+#include <sys/cdefs.h>
+
 #include <android/native_window.h>
 
 #include <jni.h>
@@ -42,6 +44,27 @@
  */
 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
+ * with it through Java code. The returned Java object acquires a reference on
+ * the ANativeWindow; maintains it through general Java object's life cycle;
+ * and will automatically release the reference when the Java object gets garbage
+ * collected.
+ */
+jobject ANativeWindow_toSurface(JNIEnv* env, ANativeWindow* window);
+#endif
+
 #ifdef __cplusplus
 };
 #endif
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 5a61213..cdb3fff 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -48,14 +48,21 @@
  *
  */
 
-#include <sys/types.h>
-
 #include <android/looper.h>
 
+#include <sys/types.h>
+#include <math.h>
+#include <stdint.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+typedef struct AHardwareBuffer AHardwareBuffer;
+
+#define ASENSOR_RESOLUTION_INVALID     (nanf(""))
+#define ASENSOR_FIFO_COUNT_INVALID     (-1)
+#define ASENSOR_DELAY_INVALID          INT32_MIN
 
 /**
  * Sensor types.
@@ -63,6 +70,10 @@
  */
 enum {
     /**
+     * Invalid sensor type. Returned by {@link ASensor_getType} as error value.
+     */
+    ASENSOR_TYPE_INVALID = -1,
+    /**
      * {@link ASENSOR_TYPE_ACCELEROMETER}
      * reporting-mode: continuous
      *
@@ -134,6 +145,8 @@
  * Sensor Reporting Modes.
  */
 enum {
+    /** invalid reporting mode */
+    AREPORTING_MODE_INVALID = -1,
     /** continuous reporting */
     AREPORTING_MODE_CONTINUOUS = 0,
     /** reporting on change */
@@ -144,6 +157,30 @@
     AREPORTING_MODE_SPECIAL_TRIGGER = 3
 };
 
+/**
+ * Sensor Direct Report Rates.
+ */
+enum {
+    /** stopped */
+    ASENSOR_DIRECT_RATE_STOP = 0,
+    /** nominal 50Hz */
+    ASENSOR_DIRECT_RATE_NORMAL = 1,
+    /** nominal 200Hz */
+    ASENSOR_DIRECT_RATE_FAST = 2,
+    /** nominal 800Hz */
+    ASENSOR_DIRECT_RATE_VERY_FAST = 3
+};
+
+/**
+ * Sensor Direct Channel Type.
+ */
+enum {
+    /** shared memory created by ASharedMemory_create */
+    ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY = 1,
+    /** AHardwareBuffer */
+    ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER = 2
+};
+
 /*
  * A few useful constants
  */
@@ -367,12 +404,13 @@
  */
 ASensor const* ASensorManager_getDefaultSensor(ASensorManager* manager, int type);
 
+#if __ANDROID_API__ >= 21
 /**
  * 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);
+#endif
 
 /**
  * Creates a new sensor event queue and associate it with a looper.
@@ -389,15 +427,108 @@
  */
 int ASensorManager_destroyEventQueue(ASensorManager* manager, ASensorEventQueue* queue);
 
+#if __ANDROID_API__ >= __ANDROID_API_O__
+/**
+ * Create direct channel based on shared memory
+ *
+ * Create a direct channel of {@link ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY} to be used
+ * for configuring sensor direct report.
+ *
+ * \param manager the {@link ASensorManager} instance obtained from
+ *                {@link ASensorManager_getInstanceForPackage}.
+ * \param fd      file descriptor representing a shared memory created by
+ *                {@link ASharedMemory_create}
+ * \param size    size to be used, must be less or equal to size of shared memory.
+ *
+ * \return a positive integer as a channel id to be used in
+ *         {@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);
+
+/**
+ * Create direct channel based on AHardwareBuffer
+ *
+ * Create a direct channel of {@link ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER} type to be used
+ * for configuring sensor direct report.
+ *
+ * \param manager the {@link ASensorManager} instance obtained from
+ *                {@link ASensorManager_getInstanceForPackage}.
+ * \param buffer  {@link AHardwareBuffer} instance created by {@link AHardwareBuffer_allocate}.
+ * \param size    the intended size to be used, must be less or equal to size of buffer.
+ *
+ * \return a positive integer as a channel id to be used in
+ *         {@link ASensorManager_destroyDirectChannel} and
+ *         {@link ASensorManager_configureDirectReport}, or value less or equal to 0 for failures.
+ */
+int ASensorManager_createHardwareBufferDirectChannel(
+        ASensorManager* manager, AHardwareBuffer const * buffer, size_t size);
+
+/**
+ * Destroy a direct channel
+ *
+ * Destroy a direct channel previously created using {@link ASensorManager_createDirectChannel}.
+ * The buffer used for creating direct channel does not get destroyed with
+ * {@link ASensorManager_destroy} and has to be close or released separately.
+ *
+ * \param manager the {@link ASensorManager} instance obtained from
+ *                {@link ASensorManager_getInstanceForPackage}.
+ * \param channelId channel id (a positive integer) returned from
+ *                  {@link ASensorManager_createSharedMemoryDirectChannel} or
+ *                  {@link ASensorManager_createHardwareBufferDirectChannel}.
+ */
+void ASensorManager_destroyDirectChannel(ASensorManager* manager, int channelId);
+
+/**
+ * Configure direct report on channel
+ *
+ * Configure sensor direct report on a direct channel: set rate to value other than
+ * {@link ASENSOR_DIRECT_RATE_STOP} so that sensor event can be directly
+ * written into the shared memory region used for creating the buffer. It returns a positive token
+ * which can be used for identify sensor events from different sensors on success. Calling with rate
+ * {@link ASENSOR_DIRECT_RATE_STOP} will stop direct report of the sensor specified in the channel.
+ *
+ * To stop all active sensor direct report configured to a channel, set sensor to NULL and rate to
+ * {@link ASENSOR_DIRECT_RATE_STOP}.
+ *
+ * In order to successfully configure a direct report, the sensor has to support the specified rate
+ * and the channel type, which can be checked by {@link ASensor_getHighestDirectReportRateLevel} and
+ * {@link ASensor_isDirectChannelTypeSupported}, respectively.
+ *
+ * Example:
+ * \code{.cpp}
+ *      ASensorManager *manager = ...;
+ *      ASensor *sensor = ...;
+ *      int channelId = ...;
+ *
+ *      ASensorManager_configureDirectReport(
+ *              manager, sensor, channel_id, ASENSOR_DIRECT_RATE_FAST);
+ * \endcode
+ *
+ * \param manager   the {@link ASensorManager} instance obtained from
+ *                  {@link ASensorManager_getInstanceForPackage}.
+ * \param sensor    a {@link ASensor} to denote which sensor to be operate. It can be NULL if rate
+ *                  is {@link ASENSOR_DIRECT_RATE_STOP}, denoting stopping of all active sensor
+ *                  direct report.
+ * \param channelId channel id (a positive integer) returned from
+ *                  {@link ASensorManager_createSharedMemoryDirectChannel} or
+ *                  {@link ASensorManager_createHardwareBufferDirectChannel}.
+ *
+ * \return positive token for success or negative error code.
+ */
+int ASensorManager_configureDirectReport(
+        ASensorManager* manager, ASensor const* sensor, int channelId, int rate);
+#endif
 
 /*****************************************************************************/
 
 /**
  * Enable the selected sensor with a specified sampling period and max batch report latency.
  * Returns a negative error code on failure.
+ * Note: To disable the selected sensor, use ASensorEventQueue_disableSensor() same as before.
  */
 int ASensorEventQueue_registerSensor(ASensorEventQueue* queue, ASensor const* sensor,
-        int32_t samplingPeriodUs, int maxBatchReportLatencyUs);
+        int32_t samplingPeriodUs, int64_t maxBatchReportLatencyUs);
 
 /**
  * Enable the selected sensor. Returns a negative error code on failure.
@@ -438,8 +569,7 @@
  *   ssize_t numEvent = ASensorEventQueue_getEvents(queue, eventBuffer, 8);
  *
  */
-ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue,
-                ASensorEvent* events, size_t count);
+ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue, ASensorEvent* events, size_t count);
 
 
 /*****************************************************************************/
@@ -471,6 +601,7 @@
  */
 int ASensor_getMinDelay(ASensor const* sensor);
 
+#if __ANDROID_API__ >= 21
 /**
  * Returns the maximum size of batches for this sensor. Batches will often be
  * smaller, as the hardware fifo might be used for other sensors.
@@ -496,6 +627,30 @@
  * Returns true if this is a wake up sensor, false otherwise.
  */
 bool ASensor_isWakeUpSensor(ASensor const* sensor);
+#endif /* __ANDROID_API__ >= 21 */
+
+#if __ANDROID_API__ >= __ANDROID_API_O__
+/**
+ * Test if sensor supports a certain type of direct channel.
+ *
+ * \param sensor  a {@link ASensor} to denote the sensor to be checked.
+ * \param channelType  Channel type constant, either
+ *                     {@ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY}
+ *                     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);
+/**
+ * Get the highest direct rate level that a sensor support.
+ *
+ * \param sensor  a {@link ASensor} to denote the sensor to be checked.
+ *
+ * \return a ASENSOR_DIRECT_RATE_... enum denoting the highest rate level supported by the sensor.
+ *         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
 
 #ifdef __cplusplus
 };
diff --git a/include/android/sharedmem.h b/include/android/sharedmem.h
new file mode 100644
index 0000000..46d2f4b
--- /dev/null
+++ b/include/android/sharedmem.h
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup Memory
+ * @{
+ */
+
+/**
+ * @file sharedmem.h
+ */
+
+#ifndef ANDROID_SHARED_MEMORY_H
+#define ANDROID_SHARED_MEMORY_H
+
+#include <stddef.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
+ */
+
+/**
+ * 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__
+
+/**
+ * Create a shared memory region.
+ *
+ * Create shared memory region and returns an file descriptor.  The resulting file descriptor can be
+ * mmap'ed to process memory space with PROT_READ | PROT_WRITE | PROT_EXEC. Access to shared memory
+ * region can be restricted with {@link ASharedMemory_setProt}.
+ *
+ * Use close() to release the shared memory region.
+ *
+ * \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);
+
+/**
+ * Get the size of the shared memory region.
+ *
+ * \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);
+
+/**
+ * Restrict access of shared memory region.
+ *
+ * This function restricts access of a shared memory region. Access can only be removed. The effect
+ * applies globally to all file descriptors in all processes across the system that refer to this
+ * shared memory region. Existing memory mapped regions are not affected.
+ *
+ * It is a common use case to create a shared memory region, map it read/write locally to intialize
+ * content, and then send the shared memory to another process with read only access. Code example
+ * as below (error handling omited).
+ *
+ *
+ *     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);
+ *
+ *     strcpy(buffer, "This is an example."); // trivially initialize content
+ *
+ *     // limit access to read only
+ *     ASharedMemory_setProt(fd, PROT_READ);
+ *
+ *     // share fd with another process here and the other process can only map with PROT_READ.
+ *
+ * \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);
+
+#endif
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // ANDROID_SHARED_MEMORY_H
+
+/** @} */
diff --git a/include/android/trace.h b/include/android/trace.h
index e42e334..d3b1fb6 100644
--- a/include/android/trace.h
+++ b/include/android/trace.h
@@ -14,16 +14,26 @@
  * limitations under the License.
  */
 
+/**
+ * @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>.
+ */
 
 #ifndef ANDROID_NATIVE_TRACE_H
 #define ANDROID_NATIVE_TRACE_H
 
 #include <stdbool.h>
+#include <sys/cdefs.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+#if __ANDROID_API__ >= 23
+
 /**
  * Returns true if tracing is enabled. Use this signal to avoid expensive computation only necessary
  * when tracing is enabled.
@@ -48,6 +58,8 @@
  */
 void ATrace_endSection();
 
+#endif /* __ANDROID_API__ >= 23 */
+
 #ifdef __cplusplus
 };
 #endif
diff --git a/include/audiomanager/AudioManager.h b/include/audiomanager/AudioManager.h
new file mode 100644
index 0000000..009dc52
--- /dev/null
+++ b/include/audiomanager/AudioManager.h
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_AUDIOMANAGER_H
+#define ANDROID_AUDIOMANAGER_H
+
+namespace android {
+
+// must be kept in sync with definitions in AudioPlaybackConfiguration.java
+
+#define PLAYER_PIID_INVALID -1
+
+typedef enum {
+    PLAYER_TYPE_SLES_AUDIOPLAYER_BUFFERQUEUE = 11,
+    PLAYER_TYPE_SLES_AUDIOPLAYER_URI_FD = 12,
+    PLAYER_TYPE_AAUDIO = 13,
+    PLAYER_TYPE_HW_SOURCE = 14,
+    PLAYER_TYPE_EXTERNAL_PROXY = 15,
+} player_type_t;
+
+typedef enum {
+    PLAYER_STATE_UNKNOWN  = -1,
+    PLAYER_STATE_RELEASED = 0,
+    PLAYER_STATE_IDLE     = 1,
+    PLAYER_STATE_STARTED  = 2,
+    PLAYER_STATE_PAUSED   = 3,
+    PLAYER_STATE_STOPPED  = 4,
+} player_state_t;
+
+}; // namespace android
+
+#endif // ANDROID_AUDIOMANAGER_H
diff --git a/include/audiomanager/IAudioManager.h b/include/audiomanager/IAudioManager.h
new file mode 100644
index 0000000..ce7804b
--- /dev/null
+++ b/include/audiomanager/IAudioManager.h
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_IAUDIOMANAGER_H
+#define ANDROID_IAUDIOMANAGER_H
+
+#include <utils/Errors.h>
+#include <binder/IInterface.h>
+#include <hardware/power.h>
+#include <system/audio.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class IAudioManager : public IInterface
+{
+public:
+    // These transaction IDs must be kept in sync with the method order from
+    // IAudioService.aidl.
+    enum {
+        // transaction IDs for the unsupported methods are commented out
+        /*
+        ADJUSTSUGGESTEDSTREAMVOLUME           = IBinder::FIRST_CALL_TRANSACTION,
+        ADJUSTSTREAMVOLUME                    = IBinder::FIRST_CALL_TRANSACTION + 1,
+        SETSTREAMVOLUME                       = IBinder::FIRST_CALL_TRANSACTION + 2,
+        ISSTREAMMUTE                          = IBinder::FIRST_CALL_TRANSACTION + 3,
+        FORCEREMOTESUBMIXFULLVOLUME           = IBinder::FIRST_CALL_TRANSACTION + 4,
+        ISMASTERMUTE                          = IBinder::FIRST_CALL_TRANSACTION + 5,
+        SETMASTERMUTE                         = IBinder::FIRST_CALL_TRANSACTION + 6,
+        GETSTREAMVOLUME                       = IBinder::FIRST_CALL_TRANSACTION + 7,
+        GETSTREAMMINVOLUME                    = IBinder::FIRST_CALL_TRANSACTION + 8,
+        GETSTREAMMAXVOLUME                    = IBinder::FIRST_CALL_TRANSACTION + 9,
+        GETLASTAUDIBLESTREAMVOLUME            = IBinder::FIRST_CALL_TRANSACTION + 10,
+        SETMICROPHONEMUTE                     = IBinder::FIRST_CALL_TRANSACTION + 11,
+        SETRINGERMODEEXTERNAL                 = IBinder::FIRST_CALL_TRANSACTION + 12,
+        SETRINGERMODEINTERNAL                 = IBinder::FIRST_CALL_TRANSACTION + 13,
+        GETRINGERMODEEXTERNAL                 = IBinder::FIRST_CALL_TRANSACTION + 14,
+        GETRINGERMODEINTERNAL                 = IBinder::FIRST_CALL_TRANSACTION + 15,
+        ISVALIDRINGERMODE                     = IBinder::FIRST_CALL_TRANSACTION + 16,
+        SETVIBRATESETTING                     = IBinder::FIRST_CALL_TRANSACTION + 17,
+        GETVIBRATESETTING                     = IBinder::FIRST_CALL_TRANSACTION + 18,
+        SHOULDVIBRATE                         = IBinder::FIRST_CALL_TRANSACTION + 19,
+        SETMODE                               = IBinder::FIRST_CALL_TRANSACTION + 20,
+        GETMODE                               = IBinder::FIRST_CALL_TRANSACTION + 21,
+        PLAYSOUNDEFFECT                       = IBinder::FIRST_CALL_TRANSACTION + 22,
+        PLAYSOUNDEFFECTVOLUME                 = IBinder::FIRST_CALL_TRANSACTION + 23,
+        LOADSOUNDEFFECTS                      = IBinder::FIRST_CALL_TRANSACTION + 24,
+        UNLOADSOUNDEFFECTS                    = IBinder::FIRST_CALL_TRANSACTION + 25,
+        RELOADAUDIOSETTINGS                   = IBinder::FIRST_CALL_TRANSACTION + 26,
+        AVRCPSUPPORTSABSOLUTEVOLUME           = IBinder::FIRST_CALL_TRANSACTION + 27,
+        SETSPEAKERPHONEON                     = IBinder::FIRST_CALL_TRANSACTION + 28,
+        ISSPEAKERPHONEON                      = IBinder::FIRST_CALL_TRANSACTION + 29,
+        SETBLUETOOTHSCOON                     = IBinder::FIRST_CALL_TRANSACTION + 30,
+        ISBLUETOOTHSCOON                      = IBinder::FIRST_CALL_TRANSACTION + 31,
+        SETBLUETOOTHA2DPON                    = IBinder::FIRST_CALL_TRANSACTION + 32,
+        ISBLUETOOTHA2DPON                     = IBinder::FIRST_CALL_TRANSACTION + 33,
+        REQUESTAUDIOFOCUS                     = IBinder::FIRST_CALL_TRANSACTION + 34,
+        ABANDONAUDIOFOCUS                     = IBinder::FIRST_CALL_TRANSACTION + 35,
+        UNREGISTERAUDIOFOCUSCLIENT            = IBinder::FIRST_CALL_TRANSACTION + 36,
+        GETCURRENTAUDIOFOCUS                  = IBinder::FIRST_CALL_TRANSACTION + 37,
+        STARTBLUETOOTHSCO                     = IBinder::FIRST_CALL_TRANSACTION + 38,
+        STARTBLUETOOTHSCOVIRTUALCALL          = IBinder::FIRST_CALL_TRANSACTION + 39,
+        STOPBLUETOOTHSCO                      = IBinder::FIRST_CALL_TRANSACTION + 40,
+        FORCEVOLUMECONTROLSTREAM              = IBinder::FIRST_CALL_TRANSACTION + 41,
+        SETRINGTONEPLAYER                     = IBinder::FIRST_CALL_TRANSACTION + 42,
+        GETRINGTONEPLAYER                     = IBinder::FIRST_CALL_TRANSACTION + 43,
+        GETUISOUNDSSTREAMTYPE                 = IBinder::FIRST_CALL_TRANSACTION + 44,
+        SETWIREDDEVICECONNECTIONSTATE         = IBinder::FIRST_CALL_TRANSACTION + 45,
+        SETBLUETOOTHA2DPDEVICECONNECTIONSTATE = IBinder::FIRST_CALL_TRANSACTION + 46,
+        HANDLEBLUETOOTHA2DPDEVICECONFIGCHANGE = IBinder::FIRST_CALL_TRANSACTION + 47,
+        STARTWATCHINGROUTES                   = IBinder::FIRST_CALL_TRANSACTION + 48,
+        ISCAMERASOUNDFORCED                   = IBinder::FIRST_CALL_TRANSACTION + 49,
+        SETVOLUMECONTROLLER                   = IBinder::FIRST_CALL_TRANSACTION + 50,
+        NOTIFYVOLUMECONTROLLERVISIBLE         = IBinder::FIRST_CALL_TRANSACTION + 51,
+        ISSTREAMAFFECTEDBYRINGERMODE          = IBinder::FIRST_CALL_TRANSACTION + 52,
+        ISSTREAMAFFECTEDBYMUTE                = IBinder::FIRST_CALL_TRANSACTION + 53,
+        DISABLESAFEMEDIAVOLUME                = IBinder::FIRST_CALL_TRANSACTION + 54,
+        SETHDMISYSTEMAUDIOSUPPORTED           = IBinder::FIRST_CALL_TRANSACTION + 55,
+        ISHDMISYSTEMAUDIOSUPPORTED            = IBinder::FIRST_CALL_TRANSACTION + 56,
+        REGISTERAUDIOPOLICY                   = IBinder::FIRST_CALL_TRANSACTION + 57,
+        UNREGISTERAUDIOPOLICYASYNC            = IBinder::FIRST_CALL_TRANSACTION + 58,
+        SETFOCUSPROPERTIESFORPOLICY           = IBinder::FIRST_CALL_TRANSACTION + 59,
+        SETVOLUMEPOLICY                       = IBinder::FIRST_CALL_TRANSACTION + 60,
+        REGISTERRECORDINGCALLBACK             = IBinder::FIRST_CALL_TRANSACTION + 61,
+        UNREGISTERRECORDINGCALLBACK           = IBinder::FIRST_CALL_TRANSACTION + 62,
+        GETACTIVERECORDINGCONFIGURATIONS      = IBinder::FIRST_CALL_TRANSACTION + 63,
+        REGISTERPLAYBACKCALLBACK              = IBinder::FIRST_CALL_TRANSACTION + 64,
+        UNREGISTERPLAYBACKCALLBACK            = IBinder::FIRST_CALL_TRANSACTION + 65,
+        GETACTIVEPLAYBACKCONFIGURATIONS       = IBinder::FIRST_CALL_TRANSACTION + 66,
+        */
+
+        TRACK_PLAYER                          = IBinder::FIRST_CALL_TRANSACTION + 67,
+        PLAYER_ATTRIBUTES                     = IBinder::FIRST_CALL_TRANSACTION + 68,
+        PLAYER_EVENT                          = IBinder::FIRST_CALL_TRANSACTION + 69,
+        RELEASE_PLAYER                        = IBinder::FIRST_CALL_TRANSACTION + 70,
+
+        /*
+        DISABLE_RINGTONE_SYNC                 = IBinder::FIRST_CALL_TRANSACTION + 71,
+        */
+    };
+
+    DECLARE_META_INTERFACE(AudioManager)
+
+    // The parcels created by these methods must be kept in sync with the
+    // corresponding methods from IAudioService.aidl and objects it imports.
+    virtual audio_unique_id_t trackPlayer(player_type_t playerType, audio_usage_t usage,
+                audio_content_type_t content, const sp<IBinder>& player) = 0;
+    /*oneway*/ virtual status_t playerAttributes(audio_unique_id_t piid, audio_usage_t usage,
+                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;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IAUDIOMANAGER_H
diff --git a/include/audiomanager/IPlayer.h b/include/audiomanager/IPlayer.h
new file mode 100644
index 0000000..de5c1c7
--- /dev/null
+++ b/include/audiomanager/IPlayer.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_IPLAYER_H
+#define ANDROID_IPLAYER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <media/VolumeShaper.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class IPlayer : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(Player);
+
+    virtual void start() = 0;
+
+    virtual void pause() = 0;
+
+    virtual void stop() = 0;
+
+    virtual void setVolume(float vol) = 0;
+
+    virtual void setPan(float pan) = 0;
+
+    virtual void setStartDelayMs(int delayMs) = 0;
+
+    virtual void applyVolumeShaper(
+            const sp<VolumeShaper::Configuration>& configuration,
+            const sp<VolumeShaper::Operation>& operation) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnPlayer : public BnInterface<IPlayer>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IPLAYER_H
diff --git a/include/batteryservice/BatteryService.h b/include/batteryservice/BatteryService.h
index b399905..80ab7f3 100644
--- a/include/batteryservice/BatteryService.h
+++ b/include/batteryservice/BatteryService.h
@@ -24,33 +24,17 @@
 
 namespace android {
 
-// must be kept in sync with definitions in BatteryManager.java
-enum {
-    BATTERY_STATUS_UNKNOWN = 1, // equals BatteryManager.BATTERY_STATUS_UNKNOWN constant
-    BATTERY_STATUS_CHARGING = 2, // equals BatteryManager.BATTERY_STATUS_CHARGING constant
-    BATTERY_STATUS_DISCHARGING = 3, // equals BatteryManager.BATTERY_STATUS_DISCHARGING constant
-    BATTERY_STATUS_NOT_CHARGING = 4, // equals BatteryManager.BATTERY_STATUS_NOT_CHARGING constant
-    BATTERY_STATUS_FULL = 5, // equals BatteryManager.BATTERY_STATUS_FULL constant
-};
+#include "BatteryServiceConstants.h"
 
-// must be kept in sync with definitions in BatteryManager.java
+// must be kept in sync with definitions in
+// frameworks/base/core/java/android/os/BatteryManager.java
 enum {
-    BATTERY_HEALTH_UNKNOWN = 1, // equals BatteryManager.BATTERY_HEALTH_UNKNOWN constant
-    BATTERY_HEALTH_GOOD = 2, // equals BatteryManager.BATTERY_HEALTH_GOOD constant
-    BATTERY_HEALTH_OVERHEAT = 3, // equals BatteryManager.BATTERY_HEALTH_OVERHEAT constant
-    BATTERY_HEALTH_DEAD = 4, // equals BatteryManager.BATTERY_HEALTH_DEAD constant
-    BATTERY_HEALTH_OVER_VOLTAGE = 5, // equals BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE constant
-    BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6, // equals BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE constant
-    BATTERY_HEALTH_COLD = 7, // equals BatteryManager.BATTERY_HEALTH_COLD constant
-};
-
-// must be kept in sync with definitions in BatteryProperty.java
-enum {
-    BATTERY_PROP_CHARGE_COUNTER = 1, // equals BatteryProperty.CHARGE_COUNTER constant
-    BATTERY_PROP_CURRENT_NOW = 2, // equals BatteryProperty.CURRENT_NOW constant
-    BATTERY_PROP_CURRENT_AVG = 3, // equals BatteryProperty.CURRENT_AVG constant
-    BATTERY_PROP_CAPACITY = 4, // equals BatteryProperty.CAPACITY constant
-    BATTERY_PROP_ENERGY_COUNTER = 5, // equals BatteryProperty.ENERGY_COUNTER constant
+    BATTERY_PROP_CHARGE_COUNTER = 1, // equals BATTERY_PROPERTY_CHARGE_COUNTER
+    BATTERY_PROP_CURRENT_NOW = 2, // equals BATTERY_PROPERTY_CURRENT_NOW
+    BATTERY_PROP_CURRENT_AVG = 3, // equals BATTERY_PROPERTY_CURRENT_AVERAGE
+    BATTERY_PROP_CAPACITY = 4, // equals BATTERY_PROPERTY_CAPACITY
+    BATTERY_PROP_ENERGY_COUNTER = 5, // equals BATTERY_PROPERTY_ENERGY_COUNTER
+    BATTERY_PROP_BATTERY_STATUS = 6, // equals BATTERY_PROPERTY_BATTERY_STATUS
 };
 
 struct BatteryProperties {
diff --git a/include/batteryservice/BatteryServiceConstants.h b/include/batteryservice/BatteryServiceConstants.h
new file mode 100644
index 0000000..8a90a12
--- /dev/null
+++ b/include/batteryservice/BatteryServiceConstants.h
@@ -0,0 +1,32 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+#ifndef HIDL_GENERATED_android_hardware_health_V1_0_EXPORTED_CONSTANTS_H_
+#define HIDL_GENERATED_android_hardware_health_V1_0_EXPORTED_CONSTANTS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+    BATTERY_STATUS_UNKNOWN = 1,
+    BATTERY_STATUS_CHARGING = 2,
+    BATTERY_STATUS_DISCHARGING = 3,
+    BATTERY_STATUS_NOT_CHARGING = 4,
+    BATTERY_STATUS_FULL = 5,
+};
+
+enum {
+    BATTERY_HEALTH_UNKNOWN = 1,
+    BATTERY_HEALTH_GOOD = 2,
+    BATTERY_HEALTH_OVERHEAT = 3,
+    BATTERY_HEALTH_DEAD = 4,
+    BATTERY_HEALTH_OVER_VOLTAGE = 5,
+    BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6,
+    BATTERY_HEALTH_COLD = 7,
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // HIDL_GENERATED_android_hardware_health_V1_0_EXPORTED_CONSTANTS_H_
diff --git a/include/batteryservice/IBatteryPropertiesListener.h b/include/batteryservice/IBatteryPropertiesListener.h
index b02d8e9..b226dd6 100644
--- a/include/batteryservice/IBatteryPropertiesListener.h
+++ b/include/batteryservice/IBatteryPropertiesListener.h
@@ -33,13 +33,19 @@
 
 class IBatteryPropertiesListener : public IInterface {
 public:
-    DECLARE_META_INTERFACE(BatteryPropertiesListener);
+    DECLARE_META_INTERFACE(BatteryPropertiesListener)
 
     virtual void batteryPropertiesChanged(struct BatteryProperties props) = 0;
 };
 
 // ----------------------------------------------------------------------------
 
+class BnBatteryPropertiesListener: public BnInterface<IBatteryPropertiesListener> {
+public:
+    virtual status_t onTransact(uint32_t code, const Parcel& data,
+                                Parcel* reply, uint32_t flags = 0);
+};
+
 }; // namespace android
 
 #endif // ANDROID_IBATTERYPROPERTIESLISTENER_H
diff --git a/include/batteryservice/IBatteryPropertiesRegistrar.h b/include/batteryservice/IBatteryPropertiesRegistrar.h
index eca075d..a7dbea6 100644
--- a/include/batteryservice/IBatteryPropertiesRegistrar.h
+++ b/include/batteryservice/IBatteryPropertiesRegistrar.h
@@ -27,15 +27,17 @@
     REGISTER_LISTENER = IBinder::FIRST_CALL_TRANSACTION,
     UNREGISTER_LISTENER,
     GET_PROPERTY,
+    SCHEDULE_UPDATE,
 };
 
 class IBatteryPropertiesRegistrar : public IInterface {
 public:
-    DECLARE_META_INTERFACE(BatteryPropertiesRegistrar);
+    DECLARE_META_INTERFACE(BatteryPropertiesRegistrar)
 
     virtual void registerListener(const sp<IBatteryPropertiesListener>& listener) = 0;
     virtual void unregisterListener(const sp<IBatteryPropertiesListener>& listener) = 0;
     virtual status_t getProperty(int id, struct BatteryProperty *val) = 0;
+    virtual void scheduleUpdate() = 0;
 };
 
 class BnBatteryPropertiesRegistrar : public BnInterface<IBatteryPropertiesRegistrar> {
diff --git a/include/binder b/include/binder
new file mode 120000
index 0000000..35a022a
--- /dev/null
+++ b/include/binder
@@ -0,0 +1 @@
+../libs/binder/include/binder/
\ No newline at end of file
diff --git a/include/binder/AppOpsManager.h b/include/binder/AppOpsManager.h
deleted file mode 100644
index 042927c..0000000
--- a/include/binder/AppOpsManager.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 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 ANDROID_APP_OPS_MANAGER_H
-#define ANDROID_APP_OPS_MANAGER_H
-
-#include <binder/IAppOpsService.h>
-
-#include <utils/threads.h>
-
-// ---------------------------------------------------------------------------
-namespace android {
-
-class AppOpsManager
-{
-public:
-    enum {
-        MODE_ALLOWED = IAppOpsService::MODE_ALLOWED,
-        MODE_IGNORED = IAppOpsService::MODE_IGNORED,
-        MODE_ERRORED = IAppOpsService::MODE_ERRORED
-    };
-
-    enum {
-        OP_NONE = -1,
-        OP_COARSE_LOCATION = 0,
-        OP_FINE_LOCATION = 1,
-        OP_GPS = 2,
-        OP_VIBRATE = 3,
-        OP_READ_CONTACTS = 4,
-        OP_WRITE_CONTACTS = 5,
-        OP_READ_CALL_LOG = 6,
-        OP_WRITE_CALL_LOG = 7,
-        OP_READ_CALENDAR = 8,
-        OP_WRITE_CALENDAR = 9,
-        OP_WIFI_SCAN = 10,
-        OP_POST_NOTIFICATION = 11,
-        OP_NEIGHBORING_CELLS = 12,
-        OP_CALL_PHONE = 13,
-        OP_READ_SMS = 14,
-        OP_WRITE_SMS = 15,
-        OP_RECEIVE_SMS = 16,
-        OP_RECEIVE_EMERGECY_SMS = 17,
-        OP_RECEIVE_MMS = 18,
-        OP_RECEIVE_WAP_PUSH = 19,
-        OP_SEND_SMS = 20,
-        OP_READ_ICC_SMS = 21,
-        OP_WRITE_ICC_SMS = 22,
-        OP_WRITE_SETTINGS = 23,
-        OP_SYSTEM_ALERT_WINDOW = 24,
-        OP_ACCESS_NOTIFICATIONS = 25,
-        OP_CAMERA = 26,
-        OP_RECORD_AUDIO = 27,
-        OP_PLAY_AUDIO = 28,
-        OP_READ_CLIPBOARD = 29,
-        OP_WRITE_CLIPBOARD = 30,
-        OP_TAKE_MEDIA_BUTTONS = 31,
-        OP_TAKE_AUDIO_FOCUS = 32,
-        OP_AUDIO_MASTER_VOLUME = 33,
-        OP_AUDIO_VOICE_VOLUME = 34,
-        OP_AUDIO_RING_VOLUME = 35,
-        OP_AUDIO_MEDIA_VOLUME = 36,
-        OP_AUDIO_ALARM_VOLUME = 37,
-        OP_AUDIO_NOTIFICATION_VOLUME = 38,
-        OP_AUDIO_BLUETOOTH_VOLUME = 39,
-        OP_WAKE_LOCK = 40,
-        OP_MONITOR_LOCATION = 41,
-        OP_MONITOR_HIGH_POWER_LOCATION = 42,
-        OP_GET_USAGE_STATS = 43,
-        OP_MUTE_MICROPHONE = 44,
-        OP_TOAST_WINDOW = 45,
-        OP_PROJECT_MEDIA = 46,
-        OP_ACTIVATE_VPN = 47,
-        OP_WRITE_WALLPAPER = 48,
-        OP_ASSIST_STRUCTURE = 49,
-        OP_ASSIST_SCREENSHOT = 50,
-        OP_READ_PHONE_STATE = 51,
-        OP_ADD_VOICEMAIL = 52,
-        OP_USE_SIP = 53,
-        OP_PROCESS_OUTGOING_CALLS = 54,
-        OP_USE_FINGERPRINT = 55,
-        OP_BODY_SENSORS = 56
-    };
-
-    AppOpsManager();
-
-    int32_t checkOp(int32_t op, int32_t uid, const String16& callingPackage);
-    int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage);
-    int32_t startOp(int32_t op, int32_t uid, const String16& callingPackage);
-    void finishOp(int32_t op, int32_t uid, const String16& callingPackage);
-    void startWatchingMode(int32_t op, const String16& packageName,
-            const sp<IAppOpsCallback>& callback);
-    void stopWatchingMode(const sp<IAppOpsCallback>& callback);
-    int32_t permissionToOpCode(const String16& permission);
-
-private:
-    Mutex mLock;
-    sp<IAppOpsService> mService;
-
-    sp<IAppOpsService> getService();
-};
-
-
-}; // namespace android
-// ---------------------------------------------------------------------------
-#endif // ANDROID_APP_OPS_MANAGER_H
diff --git a/include/binder/Binder.h b/include/binder/Binder.h
deleted file mode 100644
index f849fd4..0000000
--- a/include/binder/Binder.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2008 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_BINDER_H
-#define ANDROID_BINDER_H
-
-#include <atomic>
-#include <stdint.h>
-#include <binder/IBinder.h>
-
-// ---------------------------------------------------------------------------
-namespace android {
-
-class BBinder : public IBinder
-{
-public:
-                        BBinder();
-
-    virtual const String16& getInterfaceDescriptor() const;
-    virtual bool        isBinderAlive() const;
-    virtual status_t    pingBinder();
-    virtual status_t    dump(int fd, const Vector<String16>& args);
-
-    virtual status_t    transact(   uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
-
-    virtual status_t    linkToDeath(const sp<DeathRecipient>& recipient,
-                                    void* cookie = NULL,
-                                    uint32_t flags = 0);
-
-    virtual status_t    unlinkToDeath(  const wp<DeathRecipient>& recipient,
-                                        void* cookie = NULL,
-                                        uint32_t flags = 0,
-                                        wp<DeathRecipient>* outRecipient = NULL);
-
-    virtual void        attachObject(   const void* objectID,
-                                        void* object,
-                                        void* cleanupCookie,
-                                        object_cleanup_func func);
-    virtual void*       findObject(const void* objectID) const;
-    virtual void        detachObject(const void* objectID);
-
-    virtual BBinder*    localBinder();
-
-protected:
-    virtual             ~BBinder();
-
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
-
-private:
-                        BBinder(const BBinder& o);
-            BBinder&    operator=(const BBinder& o);
-
-    class Extras;
-
-    std::atomic<Extras*> mExtras;
-            void*       mReserved0;
-};
-
-// ---------------------------------------------------------------------------
-
-class BpRefBase : public virtual RefBase
-{
-protected:
-                            BpRefBase(const sp<IBinder>& o);
-    virtual                 ~BpRefBase();
-    virtual void            onFirstRef();
-    virtual void            onLastStrongRef(const void* id);
-    virtual bool            onIncStrongAttempted(uint32_t flags, const void* id);
-
-    inline  IBinder*        remote()                { return mRemote; }
-    inline  IBinder*        remote() const          { return mRemote; }
-
-private:
-                            BpRefBase(const BpRefBase& o);
-    BpRefBase&              operator=(const BpRefBase& o);
-
-    IBinder* const          mRemote;
-    RefBase::weakref_type*  mRefs;
-    std::atomic<int32_t>    mState;
-};
-
-}; // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_BINDER_H
diff --git a/include/binder/IAppOpsCallback.h b/include/binder/IAppOpsCallback.h
deleted file mode 100644
index 7f8eb01..0000000
--- a/include/binder/IAppOpsCallback.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 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 ANDROID_IAPP_OPS_CALLBACK_H
-#define ANDROID_IAPP_OPS_CALLBACK_H
-
-#include <binder/IInterface.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class IAppOpsCallback : public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(AppOpsCallback);
-
-    virtual void opChanged(int32_t op, const String16& packageName) = 0;
-
-    enum {
-        OP_CHANGED_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION
-    };
-};
-
-// ----------------------------------------------------------------------
-
-class BnAppOpsCallback : public BnInterface<IAppOpsCallback>
-{
-public:
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_IAPP_OPS_CALLBACK_H
-
diff --git a/include/binder/IAppOpsService.h b/include/binder/IAppOpsService.h
deleted file mode 100644
index cd81efa..0000000
--- a/include/binder/IAppOpsService.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 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 ANDROID_IAPP_OPS_SERVICE_H
-#define ANDROID_IAPP_OPS_SERVICE_H
-
-#include <binder/IAppOpsCallback.h>
-#include <binder/IInterface.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class IAppOpsService : public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(AppOpsService);
-
-    virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
-    virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
-    virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
-            const String16& packageName) = 0;
-    virtual void finishOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
-            const String16& packageName) = 0;
-    virtual void startWatchingMode(int32_t op, const String16& packageName,
-            const sp<IAppOpsCallback>& callback) = 0;
-    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;
-
-    enum {
-        CHECK_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
-        NOTE_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+1,
-        START_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+2,
-        FINISH_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+3,
-        START_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+4,
-        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,
-    };
-
-    enum {
-        MODE_ALLOWED = 0,
-        MODE_IGNORED = 1,
-        MODE_ERRORED = 2
-    };
-};
-
-// ----------------------------------------------------------------------
-
-class BnAppOpsService : public BnInterface<IAppOpsService>
-{
-public:
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_IAPP_OPS_SERVICE_H
diff --git a/include/binder/IBatteryStats.h b/include/binder/IBatteryStats.h
deleted file mode 100644
index 5f38186..0000000
--- a/include/binder/IBatteryStats.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 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 ANDROID_IBATTERYSTATS_H
-#define ANDROID_IBATTERYSTATS_H
-
-#include <binder/IInterface.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class IBatteryStats : public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(BatteryStats);
-
-    virtual void noteStartSensor(int uid, int sensor) = 0;
-    virtual void noteStopSensor(int uid, int sensor) = 0;
-    virtual void noteStartVideo(int uid) = 0;
-    virtual void noteStopVideo(int uid) = 0;
-    virtual void noteStartAudio(int uid) = 0;
-    virtual void noteStopAudio(int uid) = 0;
-    virtual void noteResetVideo() = 0;
-    virtual void noteResetAudio() = 0;
-    virtual void noteFlashlightOn(int uid) = 0;
-    virtual void noteFlashlightOff(int uid) = 0;
-    virtual void noteStartCamera(int uid) = 0;
-    virtual void noteStopCamera(int uid) = 0;
-    virtual void noteResetCamera() = 0;
-    virtual void noteResetFlashlight() = 0;
-
-    enum {
-        NOTE_START_SENSOR_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
-        NOTE_STOP_SENSOR_TRANSACTION,
-        NOTE_START_VIDEO_TRANSACTION,
-        NOTE_STOP_VIDEO_TRANSACTION,
-        NOTE_START_AUDIO_TRANSACTION,
-        NOTE_STOP_AUDIO_TRANSACTION,
-        NOTE_RESET_VIDEO_TRANSACTION,
-        NOTE_RESET_AUDIO_TRANSACTION,
-        NOTE_FLASHLIGHT_ON_TRANSACTION,
-        NOTE_FLASHLIGHT_OFF_TRANSACTION,
-        NOTE_START_CAMERA_TRANSACTION,
-        NOTE_STOP_CAMERA_TRANSACTION,
-        NOTE_RESET_CAMERA_TRANSACTION,
-        NOTE_RESET_FLASHLIGHT_TRANSACTION
-    };
-};
-
-// ----------------------------------------------------------------------
-
-class BnBatteryStats : public BnInterface<IBatteryStats>
-{
-public:
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_IBATTERYSTATS_H
diff --git a/include/binder/IBinder.h b/include/binder/IBinder.h
deleted file mode 100644
index 5f1e87c..0000000
--- a/include/binder/IBinder.h
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2008 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_IBINDER_H
-#define ANDROID_IBINDER_H
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-
-
-// linux/binder.h already defines this, but we can't just include it from there
-// because there are host builds that include this file.
-#ifndef B_PACK_CHARS
-#define B_PACK_CHARS(c1, c2, c3, c4) \
-    ((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))
-#endif  // B_PACK_CHARS
-
-// ---------------------------------------------------------------------------
-namespace android {
-
-class BBinder;
-class BpBinder;
-class IInterface;
-class Parcel;
-class IResultReceiver;
-
-/**
- * Base class and low-level protocol for a remotable object.
- * You can derive from this class to create an object for which other
- * processes can hold references to it.  Communication between processes
- * (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
-{
-public:
-    enum {
-        FIRST_CALL_TRANSACTION  = 0x00000001,
-        LAST_CALL_TRANSACTION   = 0x00ffffff,
-
-        PING_TRANSACTION        = B_PACK_CHARS('_','P','N','G'),
-        DUMP_TRANSACTION        = B_PACK_CHARS('_','D','M','P'),
-        SHELL_COMMAND_TRANSACTION = B_PACK_CHARS('_','C','M','D'),
-        INTERFACE_TRANSACTION   = B_PACK_CHARS('_', 'N', 'T', 'F'),
-        SYSPROPS_TRANSACTION    = B_PACK_CHARS('_', 'S', 'P', 'R'),
-
-        // Corresponds to TF_ONE_WAY -- an asynchronous call.
-        FLAG_ONEWAY             = 0x00000001
-    };
-
-                          IBinder();
-
-    /**
-     * Check if this IBinder implements the interface named by
-     * @a descriptor.  If it does, the base pointer to it is returned,
-     * which you can safely static_cast<> to the concrete C++ interface.
-     */
-    virtual sp<IInterface>  queryLocalInterface(const String16& descriptor);
-
-    /**
-     * Return the canonical name of the interface provided by this IBinder
-     * object.
-     */
-    virtual const String16& getInterfaceDescriptor() const = 0;
-
-    virtual bool            isBinderAlive() const = 0;
-    virtual status_t        pingBinder() = 0;
-    virtual status_t        dump(int fd, const Vector<String16>& args) = 0;
-    static  status_t        shellCommand(const sp<IBinder>& target, int in, int out, int err,
-                                         Vector<String16>& args,
-                                         const sp<IResultReceiver>& resultReceiver);
-
-    virtual status_t        transact(   uint32_t code,
-                                        const Parcel& data,
-                                        Parcel* reply,
-                                        uint32_t flags = 0) = 0;
-
-    class DeathRecipient : public virtual RefBase
-    {
-    public:
-        virtual void binderDied(const wp<IBinder>& who) = 0;
-    };
-
-    /**
-     * Register the @a recipient for a notification if this binder
-     * goes away.  If this binder object unexpectedly goes away
-     * (typically because its hosting process has been killed),
-     * then DeathRecipient::binderDied() will be called with a reference
-     * to this.
-     *
-     * The @a cookie is optional -- if non-NULL, it should be a
-     * memory address that you own (that is, you know it is unique).
-     *
-     * @note You will only receive death notifications for remote binders,
-     * as local binders by definition can't die without you dying as well.
-     * Trying to use this function on a local binder will result in an
-     * INVALID_OPERATION code being returned and nothing happening.
-     *
-     * @note This link always holds a weak reference to its recipient.
-     *
-     * @note You will only receive a weak reference to the dead
-     * binder.  You should not try to promote this to a strong reference.
-     * (Nor should you need to, as there is nothing useful you can
-     * directly do with it now that it has passed on.)
-     */
-    virtual status_t        linkToDeath(const sp<DeathRecipient>& recipient,
-                                        void* cookie = NULL,
-                                        uint32_t flags = 0) = 0;
-
-    /**
-     * Remove a previously registered death notification.
-     * The @a recipient will no longer be called if this object
-     * 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.
-     */
-    virtual status_t        unlinkToDeath(  const wp<DeathRecipient>& recipient,
-                                            void* cookie = NULL,
-                                            uint32_t flags = 0,
-                                            wp<DeathRecipient>* outRecipient = NULL) = 0;
-
-    virtual bool            checkSubclass(const void* subclassID) const;
-
-    typedef void (*object_cleanup_func)(const void* id, void* obj, void* cleanupCookie);
-
-    virtual void            attachObject(   const void* objectID,
-                                            void* object,
-                                            void* cleanupCookie,
-                                            object_cleanup_func func) = 0;
-    virtual void*           findObject(const void* objectID) const = 0;
-    virtual void            detachObject(const void* objectID) = 0;
-
-    virtual BBinder*        localBinder();
-    virtual BpBinder*       remoteBinder();
-
-protected:
-    virtual          ~IBinder();
-
-private:
-};
-
-}; // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_IBINDER_H
diff --git a/include/binder/IInterface.h b/include/binder/IInterface.h
deleted file mode 100644
index 4ce3613..0000000
--- a/include/binder/IInterface.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2005 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_IINTERFACE_H
-#define ANDROID_IINTERFACE_H
-
-#include <binder/Binder.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class IInterface : public virtual RefBase
-{
-public:
-            IInterface();
-            static sp<IBinder>  asBinder(const IInterface*);
-            static sp<IBinder>  asBinder(const sp<IInterface>&);
-
-protected:
-    virtual                     ~IInterface();
-    virtual IBinder*            onAsBinder() = 0;
-};
-
-// ----------------------------------------------------------------------
-
-template<typename INTERFACE>
-inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
-{
-    return INTERFACE::asInterface(obj);
-}
-
-// ----------------------------------------------------------------------
-
-template<typename INTERFACE>
-class BnInterface : public INTERFACE, public BBinder
-{
-public:
-    virtual sp<IInterface>      queryLocalInterface(const String16& _descriptor);
-    virtual const String16&     getInterfaceDescriptor() const;
-
-protected:
-    virtual IBinder*            onAsBinder();
-};
-
-// ----------------------------------------------------------------------
-
-template<typename INTERFACE>
-class BpInterface : public INTERFACE, public BpRefBase
-{
-public:
-                                BpInterface(const sp<IBinder>& remote);
-
-protected:
-    virtual IBinder*            onAsBinder();
-};
-
-// ----------------------------------------------------------------------
-
-#define DECLARE_META_INTERFACE(INTERFACE)                               \
-    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();                                            \
-
-
-#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
-    const android::String16 I##INTERFACE::descriptor(NAME);             \
-    const android::String16&                                            \
-            I##INTERFACE::getInterfaceDescriptor() const {              \
-        return I##INTERFACE::descriptor;                                \
-    }                                                                   \
-    android::sp<I##INTERFACE> I##INTERFACE::asInterface(                \
-            const android::sp<android::IBinder>& obj)                   \
-    {                                                                   \
-        android::sp<I##INTERFACE> intr;                                 \
-        if (obj != NULL) {                                              \
-            intr = static_cast<I##INTERFACE*>(                          \
-                obj->queryLocalInterface(                               \
-                        I##INTERFACE::descriptor).get());               \
-            if (intr == NULL) {                                         \
-                intr = new Bp##INTERFACE(obj);                          \
-            }                                                           \
-        }                                                               \
-        return intr;                                                    \
-    }                                                                   \
-    I##INTERFACE::I##INTERFACE() { }                                    \
-    I##INTERFACE::~I##INTERFACE() { }                                   \
-
-
-#define CHECK_INTERFACE(interface, data, reply)                         \
-    if (!data.checkInterface(this)) { return PERMISSION_DENIED; }       \
-
-
-// ----------------------------------------------------------------------
-// No user-serviceable parts after this...
-
-template<typename INTERFACE>
-inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(
-        const String16& _descriptor)
-{
-    if (_descriptor == INTERFACE::descriptor) return this;
-    return NULL;
-}
-
-template<typename INTERFACE>
-inline const String16& BnInterface<INTERFACE>::getInterfaceDescriptor() const
-{
-    return INTERFACE::getInterfaceDescriptor();
-}
-
-template<typename INTERFACE>
-IBinder* BnInterface<INTERFACE>::onAsBinder()
-{
-    return this;
-}
-
-template<typename INTERFACE>
-inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
-    : BpRefBase(remote)
-{
-}
-
-template<typename INTERFACE>
-inline IBinder* BpInterface<INTERFACE>::onAsBinder()
-{
-    return remote();
-}
-    
-// ----------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_IINTERFACE_H
diff --git a/include/binder/IMediaResourceMonitor.h b/include/binder/IMediaResourceMonitor.h
deleted file mode 100644
index c671f7a..0000000
--- a/include/binder/IMediaResourceMonitor.h
+++ /dev/null
@@ -1,55 +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_I_MEDIA_RESOURCE_MONITOR_H
-#define ANDROID_I_MEDIA_RESOURCE_MONITOR_H
-
-#include <binder/IInterface.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class IMediaResourceMonitor : public IInterface {
-public:
-    DECLARE_META_INTERFACE(MediaResourceMonitor);
-
-    // Values should be in sync with Intent.EXTRA_MEDIA_RESOURCE_TYPE_XXX.
-    enum {
-        TYPE_VIDEO_CODEC = 0,
-        TYPE_AUDIO_CODEC = 1,
-    };
-
-    virtual void notifyResourceGranted(/*in*/ int32_t pid, /*in*/ const int32_t type) = 0;
-
-    enum {
-        NOTIFY_RESOURCE_GRANTED = IBinder::FIRST_CALL_TRANSACTION,
-    };
-};
-
-// ----------------------------------------------------------------------
-
-class BnMediaResourceMonitor : public BnInterface<IMediaResourceMonitor> {
-public:
-    virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
-            uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_I_MEDIA_RESOURCE_MONITOR_H
diff --git a/include/binder/IMemory.h b/include/binder/IMemory.h
deleted file mode 100644
index 2d0db00..0000000
--- a/include/binder/IMemory.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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_IMEMORY_H
-#define ANDROID_IMEMORY_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
-#include <binder/IInterface.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class IMemoryHeap : public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(MemoryHeap);
-
-    // flags returned by getFlags()
-    enum {
-        READ_ONLY   = 0x00000001
-    };
-
-    virtual int         getHeapID() const = 0;
-    virtual void*       getBase() const = 0;
-    virtual size_t      getSize() const = 0;
-    virtual uint32_t    getFlags() const = 0;
-    virtual uint32_t    getOffset() const = 0;
-
-    // these are there just for backward source compatibility
-    int32_t heapID() const { return getHeapID(); }
-    void*   base() const  { return getBase(); }
-    size_t  virtualSize() const { return getSize(); }
-};
-
-class BnMemoryHeap : public BnInterface<IMemoryHeap>
-{
-public:
-    virtual status_t onTransact( 
-            uint32_t code,
-            const Parcel& data,
-            Parcel* reply,
-            uint32_t flags = 0);
-    
-    BnMemoryHeap();
-protected:
-    virtual ~BnMemoryHeap();
-};
-
-// ----------------------------------------------------------------------------
-
-class IMemory : public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(Memory);
-
-    virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const = 0;
-
-    // helpers
-    void* fastPointer(const sp<IBinder>& heap, ssize_t offset) const;
-    void* pointer() const;
-    size_t size() const;
-    ssize_t offset() const;
-};
-
-class BnMemory : public BnInterface<IMemory>
-{
-public:
-    virtual status_t onTransact(
-            uint32_t code,
-            const Parcel& data,
-            Parcel* reply,
-            uint32_t flags = 0);
-
-    BnMemory();
-protected:
-    virtual ~BnMemory();
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_IMEMORY_H
diff --git a/include/binder/IPCThreadState.h b/include/binder/IPCThreadState.h
deleted file mode 100644
index 7b826d6..0000000
--- a/include/binder/IPCThreadState.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2005 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_IPC_THREAD_STATE_H
-#define ANDROID_IPC_THREAD_STATE_H
-
-#include <utils/Errors.h>
-#include <binder/Parcel.h>
-#include <binder/ProcessState.h>
-#include <utils/Vector.h>
-
-#if defined(_WIN32)
-typedef  int  uid_t;
-#endif
-
-// ---------------------------------------------------------------------------
-namespace android {
-
-class IPCThreadState
-{
-public:
-    static  IPCThreadState*     self();
-    static  IPCThreadState*     selfOrNull();  // self(), but won't instantiate
-    
-            sp<ProcessState>    process();
-            
-            status_t            clearLastError();
-
-            pid_t               getCallingPid() const;
-            uid_t               getCallingUid() const;
-
-            void                setStrictModePolicy(int32_t policy);
-            int32_t             getStrictModePolicy() const;
-
-            void                setLastTransactionBinderFlags(int32_t flags);
-            int32_t             getLastTransactionBinderFlags() const;
-
-            int64_t             clearCallingIdentity();
-            void                restoreCallingIdentity(int64_t token);
-            
-            int                 setupPolling(int* fd);
-            status_t            handlePolledCommands();
-            void                flushCommands();
-
-            void                joinThreadPool(bool isMain = true);
-            
-            // Stop the local process.
-            void                stopProcess(bool immediate = true);
-            
-            status_t            transact(int32_t handle,
-                                         uint32_t code, const Parcel& data,
-                                         Parcel* reply, uint32_t flags);
-
-            void                incStrongHandle(int32_t handle);
-            void                decStrongHandle(int32_t handle);
-            void                incWeakHandle(int32_t handle);
-            void                decWeakHandle(int32_t handle);
-            status_t            attemptIncStrongHandle(int32_t handle);
-    static  void                expungeHandle(int32_t handle, IBinder* binder);
-            status_t            requestDeathNotification(   int32_t handle,
-                                                            BpBinder* proxy); 
-            status_t            clearDeathNotification( int32_t handle,
-                                                        BpBinder* proxy); 
-
-    static  void                shutdown();
-
-    // Call this to disable switching threads to background scheduling when
-    // receiving incoming IPC calls.  This is specifically here for the
-    // Android system process, since it expects to have background apps calling
-    // in to it but doesn't want to acquire locks in its services while in
-    // the background.
-    static  void                disableBackgroundScheduling(bool disable);
-
-            // Call blocks until the number of executing binder threads is less than
-            // the maximum number of binder threads threads allowed for this process.
-            void                blockUntilThreadAvailable();
-
-private:
-                                IPCThreadState();
-                                ~IPCThreadState();
-
-            status_t            sendReply(const Parcel& reply, uint32_t flags);
-            status_t            waitForResponse(Parcel *reply,
-                                                status_t *acquireResult=NULL);
-            status_t            talkWithDriver(bool doReceive=true);
-            status_t            writeTransactionData(int32_t cmd,
-                                                     uint32_t binderFlags,
-                                                     int32_t handle,
-                                                     uint32_t code,
-                                                     const Parcel& data,
-                                                     status_t* statusBuffer);
-            status_t            getAndExecuteCommand();
-            status_t            executeCommand(int32_t command);
-            void                processPendingDerefs();
-
-            void                clearCaller();
-
-    static  void                threadDestructor(void *st);
-    static  void                freeBuffer(Parcel* parcel,
-                                           const uint8_t* data, size_t dataSize,
-                                           const binder_size_t* objects, size_t objectsSize,
-                                           void* cookie);
-    
-    const   sp<ProcessState>    mProcess;
-            Vector<BBinder*>    mPendingStrongDerefs;
-            Vector<RefBase::weakref_type*> mPendingWeakDerefs;
-
-            Parcel              mIn;
-            Parcel              mOut;
-            status_t            mLastError;
-            pid_t               mCallingPid;
-            uid_t               mCallingUid;
-            int32_t             mStrictModePolicy;
-            int32_t             mLastTransactionBinderFlags;
-};
-
-}; // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_IPC_THREAD_STATE_H
diff --git a/include/binder/IPermissionController.h b/include/binder/IPermissionController.h
deleted file mode 100644
index 4e5fb34..0000000
--- a/include/binder/IPermissionController.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2005 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_IPERMISSION_CONTROLLER_H
-#define ANDROID_IPERMISSION_CONTROLLER_H
-
-#include <binder/IInterface.h>
-#include <stdlib.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class IPermissionController : public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(PermissionController);
-
-    virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid) = 0;
-
-    virtual void getPackagesForUid(const uid_t uid, Vector<String16> &packages) = 0;
-
-    virtual bool isRuntimePermission(const String16& permission) = 0;
-
-    enum {
-        CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
-        GET_PACKAGES_FOR_UID_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1,
-        IS_RUNTIME_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 2
-    };
-};
-
-// ----------------------------------------------------------------------
-
-class BnPermissionController : public BnInterface<IPermissionController>
-{
-public:
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_IPERMISSION_CONTROLLER_H
-
diff --git a/include/binder/IProcessInfoService.h b/include/binder/IProcessInfoService.h
deleted file mode 100644
index 69dc9a7..0000000
--- a/include/binder/IProcessInfoService.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#ifndef ANDROID_I_PROCESS_INFO_SERVICE_H
-#define ANDROID_I_PROCESS_INFO_SERVICE_H
-
-#include <binder/IInterface.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class IProcessInfoService : public IInterface {
-public:
-    DECLARE_META_INTERFACE(ProcessInfoService);
-
-    virtual status_t    getProcessStatesFromPids( size_t length,
-                                                  /*in*/ int32_t* pids,
-                                                  /*out*/ int32_t* states) = 0;
-
-    virtual status_t    getProcessStatesAndOomScoresFromPids( size_t length,
-                                                  /*in*/ int32_t* pids,
-                                                  /*out*/ int32_t* states,
-                                                  /*out*/ int32_t* scores) = 0;
-
-    enum {
-        GET_PROCESS_STATES_FROM_PIDS = IBinder::FIRST_CALL_TRANSACTION,
-        GET_PROCESS_STATES_AND_OOM_SCORES_FROM_PIDS,
-    };
-};
-
-// ----------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_I_PROCESS_INFO_SERVICE_H
diff --git a/include/binder/IResultReceiver.h b/include/binder/IResultReceiver.h
deleted file mode 100644
index 02dc6a6..0000000
--- a/include/binder/IResultReceiver.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.
- */
-
-//
-#ifndef ANDROID_IRESULT_RECEIVER_H
-#define ANDROID_IRESULT_RECEIVER_H
-
-#include <binder/IInterface.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class IResultReceiver : public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(ResultReceiver);
-
-    virtual void send(int32_t resultCode) = 0;
-
-    enum {
-        OP_SEND = IBinder::FIRST_CALL_TRANSACTION
-    };
-};
-
-// ----------------------------------------------------------------------
-
-class BnResultReceiver : public BnInterface<IResultReceiver>
-{
-public:
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_IRESULT_RECEIVER_H
-
diff --git a/include/binder/IServiceManager.h b/include/binder/IServiceManager.h
deleted file mode 100644
index 7ccd9fe..0000000
--- a/include/binder/IServiceManager.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2005 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_ISERVICE_MANAGER_H
-#define ANDROID_ISERVICE_MANAGER_H
-
-#include <binder/IInterface.h>
-#include <binder/IPermissionController.h>
-#include <utils/Vector.h>
-#include <utils/String16.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class IServiceManager : public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(ServiceManager);
-
-    /**
-     * Retrieve an existing service, blocking for a few seconds
-     * if it doesn't yet exist.
-     */
-    virtual sp<IBinder>         getService( const String16& name) const = 0;
-
-    /**
-     * Retrieve an existing service, non-blocking.
-     */
-    virtual sp<IBinder>         checkService( const String16& name) const = 0;
-
-    /**
-     * Register a service.
-     */
-    virtual status_t            addService( const String16& name,
-                                            const sp<IBinder>& service,
-                                            bool allowIsolated = false) = 0;
-
-    /**
-     * Return list of all existing services.
-     */
-    virtual Vector<String16>    listServices() = 0;
-
-    enum {
-        GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
-        CHECK_SERVICE_TRANSACTION,
-        ADD_SERVICE_TRANSACTION,
-        LIST_SERVICES_TRANSACTION,
-    };
-};
-
-sp<IServiceManager> defaultServiceManager();
-
-template<typename INTERFACE>
-status_t getService(const String16& name, sp<INTERFACE>* outService)
-{
-    const sp<IServiceManager> sm = defaultServiceManager();
-    if (sm != NULL) {
-        *outService = interface_cast<INTERFACE>(sm->getService(name));
-        if ((*outService) != NULL) return NO_ERROR;
-    }
-    return NAME_NOT_FOUND;
-}
-
-bool checkCallingPermission(const String16& permission);
-bool checkCallingPermission(const String16& permission,
-                            int32_t* outPid, int32_t* outUid);
-bool checkPermission(const String16& permission, pid_t pid, uid_t uid);
-
-}; // namespace android
-
-#endif // ANDROID_ISERVICE_MANAGER_H
-
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
deleted file mode 100644
index 2490b82..0000000
--- a/include/binder/Parcel.h
+++ /dev/null
@@ -1,798 +0,0 @@
-/*
- * Copyright (C) 2005 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_H
-#define ANDROID_PARCEL_H
-
-#include <string>
-#include <vector>
-
-#include <cutils/native_handle.h>
-#include <nativehelper/ScopedFd.h>
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-#include <utils/Flattenable.h>
-#include <linux/binder.h>
-
-#include <binder/IInterface.h>
-#include <binder/Parcelable.h>
-
-// ---------------------------------------------------------------------------
-namespace android {
-
-template <typename T> class Flattenable;
-template <typename T> class LightFlattenable;
-class IBinder;
-class IPCThreadState;
-class ProcessState;
-class String8;
-class TextOutput;
-
-class Parcel {
-    friend class IPCThreadState;
-public:
-    class ReadableBlob;
-    class WritableBlob;
-
-                        Parcel();
-                        ~Parcel();
-    
-    const uint8_t*      data() const;
-    size_t              dataSize() const;
-    size_t              dataAvail() const;
-    size_t              dataPosition() const;
-    size_t              dataCapacity() const;
-
-    status_t            setDataSize(size_t size);
-    void                setDataPosition(size_t pos) const;
-    status_t            setDataCapacity(size_t size);
-    
-    status_t            setData(const uint8_t* buffer, size_t len);
-
-    status_t            appendFrom(const Parcel *parcel,
-                                   size_t start, size_t len);
-
-    bool                allowFds() const;
-    bool                pushAllowFds(bool allowFds);
-    void                restoreAllowFds(bool lastValue);
-
-    bool                hasFileDescriptors() const;
-
-    // Writes the RPC header.
-    status_t            writeInterfaceToken(const String16& interface);
-
-    // Parses the RPC header, returning true if the interface name
-    // in the header matches the expected interface from the caller.
-    //
-    // Additionally, enforceInterface does part of the work of
-    // propagating the StrictMode policy mask, populating the current
-    // IPCThreadState, which as an optimization may optionally be
-    // passed in.
-    bool                enforceInterface(const String16& interface,
-                                         IPCThreadState* threadState = NULL) const;
-    bool                checkInterface(IBinder*) const;
-
-    void                freeData();
-
-private:
-    const binder_size_t* objects() const;
-
-public:
-    size_t              objectsCount() const;
-    
-    status_t            errorCheck() const;
-    void                setError(status_t err);
-    
-    status_t            write(const void* data, size_t len);
-    void*               writeInplace(size_t len);
-    status_t            writeUnpadded(const void* data, size_t len);
-    status_t            writeInt32(int32_t val);
-    status_t            writeUint32(uint32_t val);
-    status_t            writeInt64(int64_t val);
-    status_t            writeUint64(uint64_t val);
-    status_t            writeFloat(float val);
-    status_t            writeDouble(double val);
-    status_t            writeCString(const char* str);
-    status_t            writeString8(const String8& str);
-    status_t            writeString16(const String16& str);
-    status_t            writeString16(const std::unique_ptr<String16>& str);
-    status_t            writeString16(const char16_t* str, size_t len);
-    status_t            writeStrongBinder(const sp<IBinder>& val);
-    status_t            writeWeakBinder(const wp<IBinder>& val);
-    status_t            writeInt32Array(size_t len, const int32_t *val);
-    status_t            writeByteArray(size_t len, const uint8_t *val);
-    status_t            writeBool(bool val);
-    status_t            writeChar(char16_t val);
-    status_t            writeByte(int8_t val);
-
-    // Take a UTF8 encoded string, convert to UTF16, write it to the parcel.
-    status_t            writeUtf8AsUtf16(const std::string& str);
-    status_t            writeUtf8AsUtf16(const std::unique_ptr<std::string>& str);
-
-    status_t            writeByteVector(const std::unique_ptr<std::vector<int8_t>>& val);
-    status_t            writeByteVector(const std::vector<int8_t>& val);
-    status_t            writeByteVector(const std::unique_ptr<std::vector<uint8_t>>& val);
-    status_t            writeByteVector(const std::vector<uint8_t>& val);
-    status_t            writeInt32Vector(const std::unique_ptr<std::vector<int32_t>>& val);
-    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            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);
-    status_t            writeDoubleVector(const std::vector<double>& val);
-    status_t            writeBoolVector(const std::unique_ptr<std::vector<bool>>& val);
-    status_t            writeBoolVector(const std::vector<bool>& val);
-    status_t            writeCharVector(const std::unique_ptr<std::vector<char16_t>>& val);
-    status_t            writeCharVector(const std::vector<char16_t>& val);
-    status_t            writeString16Vector(
-                            const std::unique_ptr<std::vector<std::unique_ptr<String16>>>& val);
-    status_t            writeString16Vector(const std::vector<String16>& val);
-    status_t            writeUtf8VectorAsUtf16Vector(
-                            const std::unique_ptr<std::vector<std::unique_ptr<std::string>>>& val);
-    status_t            writeUtf8VectorAsUtf16Vector(const std::vector<std::string>& val);
-
-    status_t            writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val);
-    status_t            writeStrongBinderVector(const std::vector<sp<IBinder>>& val);
-
-    template<typename T>
-    status_t            writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val);
-    template<typename T>
-    status_t            writeParcelableVector(const std::vector<T>& val);
-
-    template<typename T>
-    status_t            writeNullableParcelable(const std::unique_ptr<T>& parcelable);
-
-    status_t            writeParcelable(const Parcelable& parcelable);
-
-    template<typename T>
-    status_t            write(const Flattenable<T>& val);
-
-    template<typename T>
-    status_t            write(const LightFlattenable<T>& val);
-
-
-    // Place a native_handle into the parcel (the native_handle's file-
-    // descriptors are dup'ed, so it is safe to delete the native_handle
-    // when this function returns).
-    // Doesn't take ownership of the native_handle.
-    status_t            writeNativeHandle(const native_handle* handle);
-    
-    // Place a file descriptor into the parcel.  The given fd must remain
-    // valid for the lifetime of the parcel.
-    // The Parcel does not take ownership of the given fd unless you ask it to.
-    status_t            writeFileDescriptor(int fd, bool takeOwnership = false);
-    
-    // Place a file descriptor into the parcel.  A dup of the fd is made, which
-    // will be closed once the parcel is destroyed.
-    status_t            writeDupFileDescriptor(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.
-    status_t            writeUniqueFileDescriptor(
-                            const ScopedFd& fd);
-
-    // Place a vector of file desciptors into the parcel. Each descriptor is
-    // dup'd as in writeDupFileDescriptor
-    status_t            writeUniqueFileDescriptorVector(
-                            const std::unique_ptr<std::vector<ScopedFd>>& val);
-    status_t            writeUniqueFileDescriptorVector(
-                            const std::vector<ScopedFd>& val);
-
-    // Writes a blob to the parcel.
-    // If the blob is small, then it is stored in-place, otherwise it is
-    // transferred by way of an anonymous shared memory region.  Prefer sending
-    // immutable blobs if possible since they may be subsequently transferred between
-    // processes without further copying whereas mutable blobs always need to be copied.
-    // The caller should call release() on the blob after writing its contents.
-    status_t            writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob);
-
-    // Write an existing immutable blob file descriptor to the parcel.
-    // This allows the client to send the same blob to multiple processes
-    // as long as it keeps a dup of the blob file descriptor handy for later.
-    status_t            writeDupImmutableBlobFileDescriptor(int fd);
-
-    status_t            writeObject(const flat_binder_object& val, bool nullMetaData);
-
-    // Like Parcel.java's writeNoException().  Just writes a zero int32.
-    // Currently the native implementation doesn't do any of the StrictMode
-    // stack gathering and serialization that the Java implementation does.
-    status_t            writeNoException();
-
-    void                remove(size_t start, size_t amt);
-    
-    status_t            read(void* outData, size_t len) const;
-    const void*         readInplace(size_t len) const;
-    int32_t             readInt32() const;
-    status_t            readInt32(int32_t *pArg) const;
-    uint32_t            readUint32() const;
-    status_t            readUint32(uint32_t *pArg) const;
-    int64_t             readInt64() const;
-    status_t            readInt64(int64_t *pArg) const;
-    uint64_t            readUint64() const;
-    status_t            readUint64(uint64_t *pArg) const;
-    float               readFloat() const;
-    status_t            readFloat(float *pArg) const;
-    double              readDouble() const;
-    status_t            readDouble(double *pArg) const;
-    intptr_t            readIntPtr() const;
-    status_t            readIntPtr(intptr_t *pArg) const;
-    bool                readBool() const;
-    status_t            readBool(bool *pArg) const;
-    char16_t            readChar() const;
-    status_t            readChar(char16_t *pArg) const;
-    int8_t              readByte() const;
-    status_t            readByte(int8_t *pArg) const;
-
-    // Read a UTF16 encoded string, convert to UTF8
-    status_t            readUtf8FromUtf16(std::string* str) const;
-    status_t            readUtf8FromUtf16(std::unique_ptr<std::string>* str) const;
-
-    const char*         readCString() const;
-    String8             readString8() const;
-    String16            readString16() const;
-    status_t            readString16(String16* pArg) const;
-    status_t            readString16(std::unique_ptr<String16>* pArg) const;
-    const char16_t*     readString16Inplace(size_t* outLen) const;
-    sp<IBinder>         readStrongBinder() const;
-    status_t            readStrongBinder(sp<IBinder>* val) const;
-    wp<IBinder>         readWeakBinder() const;
-
-    template<typename T>
-    status_t            readParcelableVector(
-                            std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const;
-    template<typename T>
-    status_t            readParcelableVector(std::vector<T>* val) const;
-
-    status_t            readParcelable(Parcelable* parcelable) const;
-
-    template<typename T>
-    status_t            readParcelable(std::unique_ptr<T>* parcelable) const;
-
-    template<typename T>
-    status_t            readStrongBinder(sp<T>* val) const;
-
-    status_t            readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const;
-    status_t            readStrongBinderVector(std::vector<sp<IBinder>>* val) const;
-
-    status_t            readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const;
-    status_t            readByteVector(std::vector<int8_t>* val) const;
-    status_t            readByteVector(std::unique_ptr<std::vector<uint8_t>>* val) const;
-    status_t            readByteVector(std::vector<uint8_t>* val) const;
-    status_t            readInt32Vector(std::unique_ptr<std::vector<int32_t>>* val) const;
-    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            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;
-    status_t            readDoubleVector(std::vector<double>* val) const;
-    status_t            readBoolVector(std::unique_ptr<std::vector<bool>>* val) const;
-    status_t            readBoolVector(std::vector<bool>* val) const;
-    status_t            readCharVector(std::unique_ptr<std::vector<char16_t>>* val) const;
-    status_t            readCharVector(std::vector<char16_t>* val) const;
-    status_t            readString16Vector(
-                            std::unique_ptr<std::vector<std::unique_ptr<String16>>>* val) const;
-    status_t            readString16Vector(std::vector<String16>* val) const;
-    status_t            readUtf8VectorFromUtf16Vector(
-                            std::unique_ptr<std::vector<std::unique_ptr<std::string>>>* val) const;
-    status_t            readUtf8VectorFromUtf16Vector(std::vector<std::string>* val) const;
-
-    template<typename T>
-    status_t            read(Flattenable<T>& val) const;
-
-    template<typename T>
-    status_t            read(LightFlattenable<T>& val) const;
-
-    // Like Parcel.java's readExceptionCode().  Reads the first int32
-    // off of a Parcel's header, returning 0 or the negative error
-    // code on exceptions, but also deals with skipping over rich
-    // response headers.  Callers should use this to read & parse the
-    // response headers rather than doing it by hand.
-    int32_t             readExceptionCode() const;
-
-    // Retrieve native_handle from the parcel. This returns a copy of the
-    // parcel's native_handle (the caller takes ownership). The caller
-    // must free the native_handle with native_handle_close() and 
-    // native_handle_delete().
-    native_handle*     readNativeHandle() const;
-
-    
-    // Retrieve a file descriptor from the parcel.  This returns the raw fd
-    // in the parcel, which you do not own -- use dup() to get your own copy.
-    int                 readFileDescriptor() const;
-
-    // Retrieve a smart file descriptor from the parcel.
-    status_t            readUniqueFileDescriptor(
-                            ScopedFd* val) const;
-
-
-    // Retrieve a vector of smart file descriptors from the parcel.
-    status_t            readUniqueFileDescriptorVector(
-                            std::unique_ptr<std::vector<ScopedFd>>* val) const;
-    status_t            readUniqueFileDescriptorVector(
-                            std::vector<ScopedFd>* val) const;
-
-    // Reads a blob from the parcel.
-    // The caller should call release() on the blob after reading its contents.
-    status_t            readBlob(size_t len, ReadableBlob* outBlob) const;
-
-    const flat_binder_object* readObject(bool nullMetaData) const;
-
-    // Explicitly close all file descriptors in the parcel.
-    void                closeFileDescriptors();
-
-    // Debugging: get metrics on current allocations.
-    static size_t       getGlobalAllocSize();
-    static size_t       getGlobalAllocCount();
-
-private:
-    typedef void        (*release_func)(Parcel* parcel,
-                                        const uint8_t* data, size_t dataSize,
-                                        const binder_size_t* objects, size_t objectsSize,
-                                        void* cookie);
-                        
-    uintptr_t           ipcData() const;
-    size_t              ipcDataSize() const;
-    uintptr_t           ipcObjects() const;
-    size_t              ipcObjectsCount() const;
-    void                ipcSetDataReference(const uint8_t* data, size_t dataSize,
-                                            const binder_size_t* objects, size_t objectsCount,
-                                            release_func relFunc, void* relCookie);
-    
-public:
-    void                print(TextOutput& to, uint32_t flags = 0) const;
-
-private:
-                        Parcel(const Parcel& o);
-    Parcel&             operator=(const Parcel& o);
-    
-    status_t            finishWrite(size_t len);
-    void                releaseObjects();
-    void                acquireObjects();
-    status_t            growData(size_t len);
-    status_t            restartWrite(size_t desired);
-    status_t            continueWrite(size_t desired);
-    status_t            writePointer(uintptr_t val);
-    status_t            readPointer(uintptr_t *pArg) const;
-    uintptr_t           readPointer() const;
-    void                freeDataNoInit();
-    void                initState();
-    void                scanForFds() const;
-                        
-    template<class T>
-    status_t            readAligned(T *pArg) const;
-
-    template<class T>   T readAligned() const;
-
-    template<class T>
-    status_t            writeAligned(T val);
-
-    status_t            writeRawNullableParcelable(const Parcelable*
-                                                   parcelable);
-
-    template<typename T, typename U>
-    status_t            unsafeReadTypedVector(std::vector<T>* val,
-                                              status_t(Parcel::*read_func)(U*) const) const;
-    template<typename T>
-    status_t            readNullableTypedVector(std::unique_ptr<std::vector<T>>* val,
-                                                status_t(Parcel::*read_func)(T*) const) const;
-    template<typename T>
-    status_t            readTypedVector(std::vector<T>* val,
-                                        status_t(Parcel::*read_func)(T*) const) const;
-    template<typename T, typename U>
-    status_t            unsafeWriteTypedVector(const std::vector<T>& val,
-                                               status_t(Parcel::*write_func)(U));
-    template<typename T>
-    status_t            writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
-                                                 status_t(Parcel::*write_func)(const T&));
-    template<typename T>
-    status_t            writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
-                                                 status_t(Parcel::*write_func)(T));
-    template<typename T>
-    status_t            writeTypedVector(const std::vector<T>& val,
-                                         status_t(Parcel::*write_func)(const T&));
-    template<typename T>
-    status_t            writeTypedVector(const std::vector<T>& val,
-                                         status_t(Parcel::*write_func)(T));
-
-    status_t            mError;
-    uint8_t*            mData;
-    size_t              mDataSize;
-    size_t              mDataCapacity;
-    mutable size_t      mDataPos;
-    binder_size_t*      mObjects;
-    size_t              mObjectsSize;
-    size_t              mObjectsCapacity;
-    mutable size_t      mNextObjectHint;
-
-    mutable bool        mFdsKnown;
-    mutable bool        mHasFds;
-    bool                mAllowFds;
-
-    release_func        mOwner;
-    void*               mOwnerCookie;
-
-    class Blob {
-    public:
-        Blob();
-        ~Blob();
-
-        void clear();
-        void release();
-        inline size_t size() const { return mSize; }
-        inline int fd() const { return mFd; };
-        inline bool isMutable() const { return mMutable; }
-
-    protected:
-        void init(int fd, void* data, size_t size, bool isMutable);
-
-        int mFd; // owned by parcel so not closed when released
-        void* mData;
-        size_t mSize;
-        bool mMutable;
-    };
-
-    class FlattenableHelperInterface {
-    protected:
-        ~FlattenableHelperInterface() { }
-    public:
-        virtual size_t getFlattenedSize() const = 0;
-        virtual size_t getFdCount() const = 0;
-        virtual status_t flatten(void* buffer, size_t size, int* fds, size_t count) const = 0;
-        virtual status_t unflatten(void const* buffer, size_t size, int const* fds, size_t count) = 0;
-    };
-
-    template<typename T>
-    class FlattenableHelper : public FlattenableHelperInterface {
-        friend class Parcel;
-        const Flattenable<T>& val;
-        explicit FlattenableHelper(const Flattenable<T>& val) : val(val) { }
-
-    public:
-        virtual size_t getFlattenedSize() const {
-            return val.getFlattenedSize();
-        }
-        virtual size_t getFdCount() const {
-            return val.getFdCount();
-        }
-        virtual status_t flatten(void* buffer, size_t size, int* fds, size_t count) const {
-            return val.flatten(buffer, size, fds, count);
-        }
-        virtual status_t unflatten(void const* buffer, size_t size, int const* fds, size_t count) {
-            return const_cast<Flattenable<T>&>(val).unflatten(buffer, size, fds, count);
-        }
-    };
-    status_t write(const FlattenableHelperInterface& val);
-    status_t read(FlattenableHelperInterface& val) const;
-
-public:
-    class ReadableBlob : public Blob {
-        friend class Parcel;
-    public:
-        inline const void* data() const { return mData; }
-        inline void* mutableData() { return isMutable() ? mData : NULL; }
-    };
-
-    class WritableBlob : public Blob {
-        friend class Parcel;
-    public:
-        inline void* data() { return mData; }
-    };
-
-private:
-    size_t mOpenAshmemSize;
-
-public:
-    // TODO: Remove once ABI can be changed.
-    size_t getBlobAshmemSize() const;
-    size_t getOpenAshmemSize() const;
-};
-
-// ---------------------------------------------------------------------------
-
-template<typename T>
-status_t Parcel::write(const Flattenable<T>& val) {
-    const FlattenableHelper<T> helper(val);
-    return write(helper);
-}
-
-template<typename T>
-status_t Parcel::write(const LightFlattenable<T>& val) {
-    size_t size(val.getFlattenedSize());
-    if (!val.isFixedSize()) {
-        status_t err = writeInt32(size);
-        if (err != NO_ERROR) {
-            return err;
-        }
-    }
-    if (size) {
-        void* buffer = writeInplace(size);
-        if (buffer == NULL)
-            return NO_MEMORY;
-        return val.flatten(buffer, size);
-    }
-    return NO_ERROR;
-}
-
-template<typename T>
-status_t Parcel::read(Flattenable<T>& val) const {
-    FlattenableHelper<T> helper(val);
-    return read(helper);
-}
-
-template<typename T>
-status_t Parcel::read(LightFlattenable<T>& val) const {
-    size_t size;
-    if (val.isFixedSize()) {
-        size = val.getFlattenedSize();
-    } else {
-        int32_t s;
-        status_t err = readInt32(&s);
-        if (err != NO_ERROR) {
-            return err;
-        }
-        size = s;
-    }
-    if (size) {
-        void const* buffer = readInplace(size);
-        return buffer == NULL ? NO_MEMORY :
-                val.unflatten(buffer, size);
-    }
-    return NO_ERROR;
-}
-
-template<typename T>
-status_t Parcel::readStrongBinder(sp<T>* val) const {
-    sp<IBinder> tmp;
-    status_t ret = readStrongBinder(&tmp);
-
-    if (ret == OK) {
-        *val = interface_cast<T>(tmp);
-
-        if (val->get() == nullptr) {
-            return UNKNOWN_ERROR;
-        }
-    }
-
-    return ret;
-}
-
-template<typename T, typename U>
-status_t Parcel::unsafeReadTypedVector(
-        std::vector<T>* val,
-        status_t(Parcel::*read_func)(U*) const) const {
-    int32_t size;
-    status_t status = this->readInt32(&size);
-
-    if (status != OK) {
-        return status;
-    }
-
-    if (size < 0) {
-        return UNEXPECTED_NULL;
-    }
-
-    if (val->max_size() < size) {
-        return NO_MEMORY;
-    }
-
-    val->resize(size);
-
-    if (val->size() < size) {
-        return NO_MEMORY;
-    }
-
-    for (auto& v: *val) {
-        status = (this->*read_func)(&v);
-
-        if (status != OK) {
-            return status;
-        }
-    }
-
-    return OK;
-}
-
-template<typename T>
-status_t Parcel::readTypedVector(std::vector<T>* val,
-                                 status_t(Parcel::*read_func)(T*) const) const {
-    return unsafeReadTypedVector(val, read_func);
-}
-
-template<typename T>
-status_t Parcel::readNullableTypedVector(std::unique_ptr<std::vector<T>>* val,
-                                         status_t(Parcel::*read_func)(T*) const) const {
-    const int32_t start = dataPosition();
-    int32_t size;
-    status_t status = readInt32(&size);
-    val->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    setDataPosition(start);
-    val->reset(new std::vector<T>());
-
-    status = unsafeReadTypedVector(val->get(), read_func);
-
-    if (status != OK) {
-        val->reset();
-    }
-
-    return status;
-}
-
-template<typename T, typename U>
-status_t Parcel::unsafeWriteTypedVector(const std::vector<T>& val,
-                                        status_t(Parcel::*write_func)(U)) {
-    if (val.size() > std::numeric_limits<int32_t>::max()) {
-        return BAD_VALUE;
-    }
-
-    status_t status = this->writeInt32(val.size());
-
-    if (status != OK) {
-        return status;
-    }
-
-    for (const auto& item : val) {
-        status = (this->*write_func)(item);
-
-        if (status != OK) {
-            return status;
-        }
-    }
-
-    return OK;
-}
-
-template<typename T>
-status_t Parcel::writeTypedVector(const std::vector<T>& val,
-                                  status_t(Parcel::*write_func)(const T&)) {
-    return unsafeWriteTypedVector(val, write_func);
-}
-
-template<typename T>
-status_t Parcel::writeTypedVector(const std::vector<T>& val,
-                                  status_t(Parcel::*write_func)(T)) {
-    return unsafeWriteTypedVector(val, write_func);
-}
-
-template<typename T>
-status_t Parcel::writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
-                                          status_t(Parcel::*write_func)(const T&)) {
-    if (val.get() == nullptr) {
-        return this->writeInt32(-1);
-    }
-
-    return unsafeWriteTypedVector(*val, write_func);
-}
-
-template<typename T>
-status_t Parcel::writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
-                                          status_t(Parcel::*write_func)(T)) {
-    if (val.get() == nullptr) {
-        return this->writeInt32(-1);
-    }
-
-    return unsafeWriteTypedVector(*val, write_func);
-}
-
-template<typename T>
-status_t Parcel::readParcelableVector(std::vector<T>* val) const {
-    return unsafeReadTypedVector<T, Parcelable>(val, &Parcel::readParcelable);
-}
-
-template<typename T>
-status_t Parcel::readParcelableVector(std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const {
-    const int32_t start = dataPosition();
-    int32_t size;
-    status_t status = readInt32(&size);
-    val->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    setDataPosition(start);
-    val->reset(new std::vector<std::unique_ptr<T>>());
-
-    status = unsafeReadTypedVector(val->get(), &Parcel::readParcelable<T>);
-
-    if (status != OK) {
-        val->reset();
-    }
-
-    return status;
-}
-
-template<typename T>
-status_t Parcel::readParcelable(std::unique_ptr<T>* parcelable) const {
-    const int32_t start = dataPosition();
-    int32_t present;
-    status_t status = readInt32(&present);
-    parcelable->reset();
-
-    if (status != OK || !present) {
-        return status;
-    }
-
-    setDataPosition(start);
-    parcelable->reset(new T());
-
-    status = readParcelable(parcelable->get());
-
-    if (status != OK) {
-        parcelable->reset();
-    }
-
-    return status;
-}
-
-template<typename T>
-status_t Parcel::writeNullableParcelable(const std::unique_ptr<T>& parcelable) {
-    return writeRawNullableParcelable(parcelable.get());
-}
-
-template<typename T>
-status_t Parcel::writeParcelableVector(const std::vector<T>& val) {
-    return unsafeWriteTypedVector<T,const Parcelable&>(val, &Parcel::writeParcelable);
-}
-
-template<typename T>
-status_t Parcel::writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val) {
-    if (val.get() == nullptr) {
-        return this->writeInt32(-1);
-    }
-
-    return unsafeWriteTypedVector(*val, &Parcel::writeParcelable);
-}
-
-// ---------------------------------------------------------------------------
-
-inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel)
-{
-    parcel.print(to);
-    return to;
-}
-
-// ---------------------------------------------------------------------------
-
-// Generic acquire and release of objects.
-void acquire_object(const sp<ProcessState>& proc,
-                    const flat_binder_object& obj, const void* who);
-void release_object(const sp<ProcessState>& proc,
-                    const flat_binder_object& obj, const void* who);
-
-void flatten_binder(const sp<ProcessState>& proc,
-                    const sp<IBinder>& binder, flat_binder_object* out);
-void flatten_binder(const sp<ProcessState>& proc,
-                    const wp<IBinder>& binder, flat_binder_object* out);
-status_t unflatten_binder(const sp<ProcessState>& proc,
-                          const flat_binder_object& flat, sp<IBinder>* out);
-status_t unflatten_binder(const sp<ProcessState>& proc,
-                          const flat_binder_object& flat, wp<IBinder>* out);
-
-}; // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_PARCEL_H
diff --git a/include/binder/Parcelable.h b/include/binder/Parcelable.h
deleted file mode 100644
index faf0d34..0000000
--- a/include/binder/Parcelable.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_PARCELABLE_H
-#define ANDROID_PARCELABLE_H
-
-#include <vector>
-
-#include <utils/Errors.h>
-#include <utils/String16.h>
-
-namespace android {
-
-class Parcel;
-
-// Abstract interface of all parcelables.
-class Parcelable {
-public:
-    virtual ~Parcelable() = default;
-
-    // Write |this| parcelable to the given |parcel|.  Keep in mind that
-    // implementations of writeToParcel must be manually kept in sync
-    // with readFromParcel and the Java equivalent versions of these methods.
-    //
-    // Returns android::OK on success and an appropriate error otherwise.
-    virtual status_t writeToParcel(Parcel* parcel) const = 0;
-
-    // Read data from the given |parcel| into |this|.  After readFromParcel
-    // completes, |this| should have equivalent state to the object that
-    // wrote itself to the parcel.
-    //
-    // Returns android::OK on success and an appropriate error otherwise.
-    virtual status_t readFromParcel(const Parcel* parcel) = 0;
-};  // class Parcelable
-
-}  // namespace android
-
-#endif // ANDROID_PARCELABLE_H
diff --git a/include/binder/PersistableBundle.h b/include/binder/PersistableBundle.h
deleted file mode 100644
index fe5619f..0000000
--- a/include/binder/PersistableBundle.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_PERSISTABLE_BUNDLE_H
-#define ANDROID_PERSISTABLE_BUNDLE_H
-
-#include <map>
-#include <vector>
-
-#include <binder/Parcelable.h>
-#include <utils/String16.h>
-#include <utils/StrongPointer.h>
-
-namespace android {
-
-namespace os {
-
-/*
- * C++ implementation of PersistableBundle, a mapping from String values to
- * various types that can be saved to persistent and later restored.
- */
-class PersistableBundle : public Parcelable {
-public:
-    PersistableBundle() = default;
-    virtual ~PersistableBundle() = default;
-    PersistableBundle(const PersistableBundle& bundle) = default;
-
-    status_t writeToParcel(Parcel* parcel) const override;
-    status_t readFromParcel(const Parcel* parcel) override;
-
-    bool empty() const;
-    size_t size() const;
-    size_t erase(const String16& key);
-
-    /*
-     * Setters for PersistableBundle. Adds a a key-value pair instantiated with
-     * |key| and |value| into the member map appropriate for the type of |value|.
-     * If there is already an existing value for |key|, |value| will replace it.
-     */
-    void putBoolean(const String16& key, bool value);
-    void putInt(const String16& key, int32_t value);
-    void putLong(const String16& key, int64_t value);
-    void putDouble(const String16& key, double value);
-    void putString(const String16& key, const String16& value);
-    void putBooleanVector(const String16& key, const std::vector<bool>& value);
-    void putIntVector(const String16& key, const std::vector<int32_t>& value);
-    void putLongVector(const String16& key, const std::vector<int64_t>& value);
-    void putDoubleVector(const String16& key, const std::vector<double>& value);
-    void putStringVector(const String16& key, const std::vector<String16>& value);
-    void putPersistableBundle(const String16& key, const PersistableBundle& value);
-
-    /*
-     * Getters for PersistableBundle. If |key| exists, these methods write the
-     * value associated with |key| into |out|, and return true. Otherwise, these
-     * methods return false.
-     */
-    bool getBoolean(const String16& key, bool* out) const;
-    bool getInt(const String16& key, int32_t* out) const;
-    bool getLong(const String16& key, int64_t* out) const;
-    bool getDouble(const String16& key, double* out) const;
-    bool getString(const String16& key, String16* out) const;
-    bool getBooleanVector(const String16& key, std::vector<bool>* out) const;
-    bool getIntVector(const String16& key, std::vector<int32_t>* out) const;
-    bool getLongVector(const String16& key, std::vector<int64_t>* out) const;
-    bool getDoubleVector(const String16& key, std::vector<double>* out) const;
-    bool getStringVector(const String16& key, std::vector<String16>* out) const;
-    bool getPersistableBundle(const String16& key, PersistableBundle* out) const;
-
-    friend bool operator==(const PersistableBundle& lhs, const PersistableBundle& rhs) {
-        return (lhs.mBoolMap == rhs.mBoolMap && lhs.mIntMap == rhs.mIntMap &&
-                lhs.mLongMap == rhs.mLongMap && lhs.mDoubleMap == rhs.mDoubleMap &&
-                lhs.mStringMap == rhs.mStringMap && lhs.mBoolVectorMap == rhs.mBoolVectorMap &&
-                lhs.mIntVectorMap == rhs.mIntVectorMap &&
-                lhs.mLongVectorMap == rhs.mLongVectorMap &&
-                lhs.mDoubleVectorMap == rhs.mDoubleVectorMap &&
-                lhs.mStringVectorMap == rhs.mStringVectorMap &&
-                lhs.mPersistableBundleMap == rhs.mPersistableBundleMap);
-    }
-
-    friend bool operator!=(const PersistableBundle& lhs, const PersistableBundle& rhs) {
-        return !(lhs == rhs);
-    }
-
-private:
-    status_t writeToParcelInner(Parcel* parcel) const;
-    status_t readFromParcelInner(const Parcel* parcel, size_t length);
-
-    std::map<String16, bool> mBoolMap;
-    std::map<String16, int32_t> mIntMap;
-    std::map<String16, int64_t> mLongMap;
-    std::map<String16, double> mDoubleMap;
-    std::map<String16, String16> mStringMap;
-    std::map<String16, std::vector<bool>> mBoolVectorMap;
-    std::map<String16, std::vector<int32_t>> mIntVectorMap;
-    std::map<String16, std::vector<int64_t>> mLongVectorMap;
-    std::map<String16, std::vector<double>> mDoubleVectorMap;
-    std::map<String16, std::vector<String16>> mStringVectorMap;
-    std::map<String16, PersistableBundle> mPersistableBundleMap;
-};
-
-}  // namespace os
-
-}  // namespace android
-
-#endif  // ANDROID_PERSISTABLE_BUNDLE_H
diff --git a/include/binder/ProcessInfoService.h b/include/binder/ProcessInfoService.h
deleted file mode 100644
index c5ead20..0000000
--- a/include/binder/ProcessInfoService.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#ifndef ANDROID_PROCESS_INFO_SERVICE_H
-#define ANDROID_PROCESS_INFO_SERVICE_H
-
-#include <binder/IProcessInfoService.h>
-#include <utils/Errors.h>
-#include <utils/Singleton.h>
-#include <sys/types.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class ProcessInfoService : public Singleton<ProcessInfoService> {
-
-    friend class Singleton<ProcessInfoService>;
-    sp<IProcessInfoService> mProcessInfoService;
-    Mutex mProcessInfoLock;
-
-    ProcessInfoService();
-
-    status_t getProcessStatesImpl(size_t length, /*in*/ int32_t* pids, /*out*/ int32_t* states);
-    void updateBinderLocked();
-
-    static const int BINDER_ATTEMPT_LIMIT = 5;
-
-public:
-
-    /**
-     * For each PID in the given "pids" input array, write the current process state
-     * for that process into the "states" output array, or
-     * ActivityManager.PROCESS_STATE_NONEXISTENT * to indicate that no process with the given PID
-     * exists.
-     *
-     * Returns NO_ERROR if this operation was successful, or a negative error code otherwise.
-     */
-    static status_t getProcessStatesFromPids(size_t length, /*in*/ int32_t* pids,
-            /*out*/ int32_t* states) {
-        return ProcessInfoService::getInstance().getProcessStatesImpl(length, /*in*/ pids,
-                /*out*/ states);
-    }
-
-};
-
-// ----------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_PROCESS_INFO_SERVICE_H
-
diff --git a/include/binder/ProcessState.h b/include/binder/ProcessState.h
deleted file mode 100644
index 64cf72e..0000000
--- a/include/binder/ProcessState.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2005 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_PROCESS_STATE_H
-#define ANDROID_PROCESS_STATE_H
-
-#include <binder/IBinder.h>
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-#include <utils/String16.h>
-
-#include <utils/threads.h>
-
-#include <pthread.h>
-
-// ---------------------------------------------------------------------------
-namespace android {
-
-class IPCThreadState;
-
-class ProcessState : public virtual RefBase
-{
-public:
-    static  sp<ProcessState>    self();
-
-            void                setContextObject(const sp<IBinder>& object);
-            sp<IBinder>         getContextObject(const sp<IBinder>& caller);
-        
-            void                setContextObject(const sp<IBinder>& object,
-                                                 const String16& name);
-            sp<IBinder>         getContextObject(const String16& name,
-                                                 const sp<IBinder>& caller);
-
-            void                startThreadPool();
-                        
-    typedef bool (*context_check_func)(const String16& name,
-                                       const sp<IBinder>& caller,
-                                       void* userData);
-        
-            bool                isContextManager(void) const;
-            bool                becomeContextManager(
-                                    context_check_func checkFunc,
-                                    void* userData);
-
-            sp<IBinder>         getStrongProxyForHandle(int32_t handle);
-            wp<IBinder>         getWeakProxyForHandle(int32_t handle);
-            void                expungeHandle(int32_t handle, IBinder* binder);
-
-            void                spawnPooledThread(bool isMain);
-            
-            status_t            setThreadPoolMaxThreadCount(size_t maxThreads);
-            void                giveThreadPoolName();
-
-private:
-    friend class IPCThreadState;
-    
-                                ProcessState();
-                                ~ProcessState();
-
-                                ProcessState(const ProcessState& o);
-            ProcessState&       operator=(const ProcessState& o);
-            String8             makeBinderThreadName();
-
-            struct handle_entry {
-                IBinder* binder;
-                RefBase::weakref_type* refs;
-            };
-
-            handle_entry*       lookupHandleLocked(int32_t handle);
-
-            int                 mDriverFD;
-            void*               mVMStart;
-
-            // Protects thread count variable below.
-            pthread_mutex_t     mThreadCountLock;
-            pthread_cond_t      mThreadCountDecrement;
-            // Number of binder threads current executing a command.
-            size_t              mExecutingThreadsCount;
-            // Maximum number for binder threads allowed for this process.
-            size_t              mMaxThreads;
-            // Time when thread pool was emptied
-            int64_t             mStarvationStartTimeMs;
-
-    mutable Mutex               mLock;  // protects everything below.
-
-            Vector<handle_entry>mHandleToObject;
-
-            bool                mManagesContexts;
-            context_check_func  mBinderContextCheckFunc;
-            void*               mBinderContextUserData;
-
-            KeyedVector<String16, sp<IBinder> >
-                                mContexts;
-
-
-            String8             mRootDir;
-            bool                mThreadPoolStarted;
-    volatile int32_t            mThreadPoolSeq;
-};
-    
-}; // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_PROCESS_STATE_H
diff --git a/include/binder/Status.h b/include/binder/Status.h
deleted file mode 100644
index ce947fa..0000000
--- a/include/binder/Status.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_BINDER_STATUS_H
-#define ANDROID_BINDER_STATUS_H
-
-#include <cstdint>
-
-#include <binder/Parcel.h>
-#include <utils/String8.h>
-
-namespace android {
-namespace binder {
-
-// An object similar in function to a status_t except that it understands
-// how exceptions are encoded in the prefix of a Parcel. Used like:
-//
-//     Parcel data;
-//     Parcel reply;
-//     status_t status;
-//     binder::Status remote_exception;
-//     if ((status = data.writeInterfaceToken(interface_descriptor)) != OK ||
-//         (status = data.writeInt32(function_input)) != OK) {
-//         // We failed to write into the memory of our local parcel?
-//     }
-//     if ((status = remote()->transact(transaction, data, &reply)) != OK) {
-//        // Something has gone wrong in the binder driver or libbinder.
-//     }
-//     if ((status = remote_exception.readFromParcel(reply)) != OK) {
-//         // The remote didn't correctly write the exception header to the
-//         // reply.
-//     }
-//     if (!remote_exception.isOk()) {
-//         // The transaction went through correctly, but the remote reported an
-//         // exception during handling.
-//     }
-//
-class Status final {
-public:
-    // Keep the exception codes in sync with android/os/Parcel.java.
-    enum Exception {
-        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,
-
-        // This is special and Java specific; see Parcel.java.
-        EX_HAS_REPLY_HEADER = -128,
-        // This is special, and indicates to C++ binder proxies that the
-        // transaction has failed at a low level.
-        EX_TRANSACTION_FAILED = -129,
-    };
-
-    // A more readable alias for the default constructor.
-    static Status ok();
-    // Authors should explicitly pick whether their integer is:
-    //  - an exception code (EX_* above)
-    //  - service specific error code
-    //  - status_t
-    //
-    //  Prefer a generic exception code when possible, then a service specific
-    //  code, and finally a status_t for low level failures or legacy support.
-    //  Exception codes and service specific errors map to nicer exceptions for
-    //  Java clients.
-    static Status fromExceptionCode(int32_t exceptionCode);
-    static Status fromExceptionCode(int32_t exceptionCode,
-                                    const String8& message);
-    static Status fromServiceSpecificError(int32_t serviceSpecificErrorCode);
-    static Status fromServiceSpecificError(int32_t serviceSpecificErrorCode,
-                                           const String8& message);
-    static Status fromStatusT(status_t status);
-
-    Status() = default;
-    ~Status() = default;
-
-    // Status objects are copyable and contain just simple data.
-    Status(const Status& status) = default;
-    Status(Status&& status) = default;
-    Status& operator=(const Status& status) = default;
-
-    // Bear in mind that if the client or service is a Java endpoint, this
-    // is not the logic which will provide/interpret the data here.
-    status_t readFromParcel(const Parcel& parcel);
-    status_t writeToParcel(Parcel* parcel) const;
-
-    // Set one of the pre-defined exception types defined above.
-    void setException(int32_t ex, const String8& message);
-    // Set a service specific exception with error code.
-    void setServiceSpecificError(int32_t errorCode, const String8& message);
-    // Setting a |status| != OK causes generated code to return |status|
-    // from Binder transactions, rather than writing an exception into the
-    // reply Parcel.  This is the least preferable way of reporting errors.
-    void setFromStatusT(status_t status);
-
-    // Get information about an exception.
-    int32_t exceptionCode() const  { return mException; }
-    const String8& exceptionMessage() const { return mMessage; }
-    status_t transactionError() const {
-        return mException == EX_TRANSACTION_FAILED ? mErrorCode : OK;
-    }
-    int32_t serviceSpecificErrorCode() const {
-        return mException == EX_SERVICE_SPECIFIC ? mErrorCode : 0;
-    }
-
-    bool isOk() const { return mException == EX_NONE; }
-
-    // For logging.
-    String8 toString8() const;
-
-private:
-    Status(int32_t exceptionCode, int32_t errorCode);
-    Status(int32_t exceptionCode, int32_t errorCode, const String8& message);
-
-    // If |mException| == EX_TRANSACTION_FAILED, generated code will return
-    // |mErrorCode| as the result of the transaction rather than write an
-    // exception to the reply parcel.
-    //
-    // Otherwise, we always write |mException| to the parcel.
-    // If |mException| !=  EX_NONE, we write |mMessage| as well.
-    // If |mException| == EX_SERVICE_SPECIFIC we write |mErrorCode| as well.
-    int32_t mException = EX_NONE;
-    int32_t mErrorCode = 0;
-    String8 mMessage;
-};  // class Status
-
-// For gtest output logging
-template<typename T>
-T& operator<< (T& stream, const Status& s) {
-    stream << s.toString8().string();
-    return stream;
-}
-
-}  // namespace binder
-}  // namespace android
-
-#endif // ANDROID_BINDER_STATUS_H
diff --git a/include/binder/TextOutput.h b/include/binder/TextOutput.h
deleted file mode 100644
index 974a194..0000000
--- a/include/binder/TextOutput.h
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (C) 2006 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_TEXTOUTPUT_H
-#define ANDROID_TEXTOUTPUT_H
-
-#include <utils/Errors.h>
-
-#include <stdint.h>
-#include <string.h>
-
-// ---------------------------------------------------------------------------
-namespace android {
-
-class String8;
-class String16;
-
-class TextOutput
-{
-public:
-                        TextOutput();
-    virtual             ~TextOutput();
-    
-    virtual status_t    print(const char* txt, size_t len) = 0;
-    virtual void        moveIndent(int delta) = 0;
-    
-    class Bundle {
-    public:
-        inline Bundle(TextOutput& to) : mTO(to) { to.pushBundle(); }
-        inline ~Bundle() { mTO.popBundle(); }
-    private:
-        TextOutput&     mTO;
-    };
-    
-    virtual void        pushBundle() = 0;
-    virtual void        popBundle() = 0;
-};
-
-// ---------------------------------------------------------------------------
-
-// Text output stream for printing to the log (via utils/Log.h).
-extern TextOutput& alog;
-
-// Text output stream for printing to stdout.
-extern TextOutput& aout;
-
-// Text output stream for printing to stderr.
-extern TextOutput& aerr;
-
-typedef TextOutput& (*TextOutputManipFunc)(TextOutput&);
-
-TextOutput& endl(TextOutput& to);
-TextOutput& indent(TextOutput& to);
-TextOutput& dedent(TextOutput& to);
-
-TextOutput& operator<<(TextOutput& to, const char* str);
-TextOutput& operator<<(TextOutput& to, char);     // writes raw character
-TextOutput& operator<<(TextOutput& to, bool);
-TextOutput& operator<<(TextOutput& to, int);
-TextOutput& operator<<(TextOutput& to, long);
-TextOutput& operator<<(TextOutput& to, unsigned int);
-TextOutput& operator<<(TextOutput& to, unsigned long);
-TextOutput& operator<<(TextOutput& to, long long);
-TextOutput& operator<<(TextOutput& to, unsigned long long);
-TextOutput& operator<<(TextOutput& to, float);
-TextOutput& operator<<(TextOutput& to, double);
-TextOutput& operator<<(TextOutput& to, TextOutputManipFunc func);
-TextOutput& operator<<(TextOutput& to, const void*);
-TextOutput& operator<<(TextOutput& to, const String8& val);
-TextOutput& operator<<(TextOutput& to, const String16& val);
-
-class TypeCode 
-{
-public:
-    inline TypeCode(uint32_t code);
-    inline ~TypeCode();
-
-    inline uint32_t typeCode() const;
-    
-private:
-    uint32_t mCode;
-};
-
-TextOutput& operator<<(TextOutput& to, const TypeCode& val);
-
-class HexDump
-{
-public:
-    HexDump(const void *buf, size_t size, size_t bytesPerLine=16);
-    inline ~HexDump();
-    
-    inline HexDump& setBytesPerLine(size_t bytesPerLine);
-    inline HexDump& setSingleLineCutoff(int32_t bytes);
-    inline HexDump& setAlignment(size_t alignment);
-    inline HexDump& setCArrayStyle(bool enabled);
-    
-    inline const void* buffer() const;
-    inline size_t size() const;
-    inline size_t bytesPerLine() const;
-    inline int32_t singleLineCutoff() const;
-    inline size_t alignment() const;
-    inline bool carrayStyle() const;
-
-private:
-    const void* mBuffer;
-    size_t mSize;
-    size_t mBytesPerLine;
-    int32_t mSingleLineCutoff;
-    size_t mAlignment;
-    bool mCArrayStyle;
-};
-
-TextOutput& operator<<(TextOutput& to, const HexDump& val);
-
-// ---------------------------------------------------------------------------
-// No user servicable parts below.
-
-inline TextOutput& endl(TextOutput& to)
-{
-    to.print("\n", 1);
-    return to;
-}
-
-inline TextOutput& indent(TextOutput& to)
-{
-    to.moveIndent(1);
-    return to;
-}
-
-inline TextOutput& dedent(TextOutput& to)
-{
-    to.moveIndent(-1);
-    return to;
-}
-
-inline TextOutput& operator<<(TextOutput& to, const char* str)
-{
-    to.print(str, strlen(str));
-    return to;
-}
-
-inline TextOutput& operator<<(TextOutput& to, char c)
-{
-    to.print(&c, 1);
-    return to;
-}
-
-inline TextOutput& operator<<(TextOutput& to, TextOutputManipFunc func)
-{
-    return (*func)(to);
-}
-
-inline TypeCode::TypeCode(uint32_t code) : mCode(code) { }
-inline TypeCode::~TypeCode() { }
-inline uint32_t TypeCode::typeCode() const { return mCode; }
-
-inline HexDump::~HexDump() { }
-
-inline HexDump& HexDump::setBytesPerLine(size_t bytesPerLine) {
-    mBytesPerLine = bytesPerLine; return *this;
-}
-inline HexDump& HexDump::setSingleLineCutoff(int32_t bytes) {
-    mSingleLineCutoff = bytes; return *this;
-}
-inline HexDump& HexDump::setAlignment(size_t alignment) {
-    mAlignment = alignment; return *this;
-}
-inline HexDump& HexDump::setCArrayStyle(bool enabled) {
-    mCArrayStyle = enabled; return *this;
-}
-
-inline const void* HexDump::buffer() const { return mBuffer; }
-inline size_t HexDump::size() const { return mSize; }
-inline size_t HexDump::bytesPerLine() const { return mBytesPerLine; }
-inline int32_t HexDump::singleLineCutoff() const { return mSingleLineCutoff; }
-inline size_t HexDump::alignment() const { return mAlignment; }
-inline bool HexDump::carrayStyle() const { return mCArrayStyle; }
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_TEXTOUTPUT_H
diff --git a/include/gfx/.clang-format b/include/gfx/.clang-format
new file mode 100644
index 0000000..86763a0
--- /dev/null
+++ b/include/gfx/.clang-format
@@ -0,0 +1,11 @@
+BasedOnStyle: Google
+
+AccessModifierOffset: -2
+AllowShortFunctionsOnASingleLine: Inline
+BinPackParameters: false
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+ConstructorInitializerIndentWidth: 2
+ContinuationIndentWidth: 8
+IndentWidth: 4
diff --git a/include/gui/BitTube.h b/include/gui/BitTube.h
deleted file mode 100644
index 3ecac52..0000000
--- a/include/gui/BitTube.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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_GUI_SENSOR_CHANNEL_H
-#define ANDROID_GUI_SENSOR_CHANNEL_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <cutils/log.h>
-
-
-namespace android {
-// ----------------------------------------------------------------------------
-class Parcel;
-
-class BitTube : public RefBase
-{
-public:
-
-    // creates a BitTube with a default (4KB) send buffer
-    BitTube();
-
-    // creates a BitTube with a a specified send and receive buffer size
-    explicit BitTube(size_t bufsize);
-
-    explicit BitTube(const Parcel& data);
-    virtual ~BitTube();
-
-    // check state after construction
-    status_t initCheck() const;
-
-    // get receive file-descriptor
-    int getFd() const;
-
-    // get the send file-descriptor.
-    int getSendFd() const;
-
-    // send objects (sized blobs). All objects are guaranteed to be written or the call fails.
-    template <typename T>
-    static ssize_t sendObjects(const sp<BitTube>& tube,
-            T const* events, size_t count) {
-        return sendObjects(tube, events, count, sizeof(T));
-    }
-
-    // receive objects (sized blobs). If the receiving buffer isn't large enough,
-    // excess messages are silently discarded.
-    template <typename T>
-    static ssize_t recvObjects(const sp<BitTube>& tube,
-            T* events, size_t count) {
-        return recvObjects(tube, events, count, sizeof(T));
-    }
-
-    // parcels this BitTube
-    status_t writeToParcel(Parcel* reply) const;
-
-private:
-    void init(size_t rcvbuf, size_t sndbuf);
-
-    // send a message. The write is guaranteed to send the whole message or fail.
-    ssize_t write(void const* vaddr, size_t size);
-
-    // receive a message. the passed buffer must be at least as large as the
-    // write call used to send the message, excess data is silently discarded.
-    ssize_t read(void* vaddr, size_t size);
-
-    int mSendFd;
-    mutable int mReceiveFd;
-
-    static ssize_t sendObjects(const sp<BitTube>& tube,
-            void const* events, size_t count, size_t objSize);
-
-    static ssize_t recvObjects(const sp<BitTube>& tube,
-            void* events, size_t count, size_t objSize);
-};
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_GUI_SENSOR_CHANNEL_H
diff --git a/include/gui/BufferItem.h b/include/gui/BufferItem.h
index f45d852..55637a9 100644
--- a/include/gui/BufferItem.h
+++ b/include/gui/BufferItem.h
@@ -17,9 +17,7 @@
 #ifndef ANDROID_GUI_BUFFERITEM_H
 #define ANDROID_GUI_BUFFERITEM_H
 
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
+#include <ui/FenceTime.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
 
@@ -46,6 +44,8 @@
     enum { INVALID_BUFFER_SLOT = -1 };
     BufferItem();
     ~BufferItem();
+    BufferItem(const BufferItem&) = default;
+    BufferItem& operator=(const BufferItem&) = default;
 
     static const char* scalingModeName(uint32_t scalingMode);
 
@@ -57,6 +57,9 @@
     // mFence is a fence that will signal when the buffer is idle.
     sp<Fence> mFence;
 
+    // The std::shared_ptr<FenceTime> wrapper around mFence.
+    std::shared_ptr<FenceTime> mFenceTime{FenceTime::NO_FENCE};
+
     // mCrop is the current crop rectangle for this buffer slot.
     Rect mCrop;
 
@@ -72,13 +75,7 @@
     // to set by queueBuffer each time this slot is queued. This value
     // is guaranteed to be monotonically increasing for each newly
     // acquired buffer.
-    union {
-        int64_t mTimestamp;
-        struct {
-            uint32_t mTimestampLo;
-            uint32_t mTimestampHi;
-        };
-    };
+    int64_t mTimestamp;
 
     // mIsAutoTimestamp indicates whether mTimestamp was generated
     // automatically when the buffer was queued.
@@ -90,13 +87,7 @@
     android_dataspace mDataSpace;
 
     // mFrameNumber is the number of the queued frame for this slot.
-    union {
-        uint64_t mFrameNumber;
-        struct {
-            uint32_t mFrameNumberLo;
-            uint32_t mFrameNumberHi;
-        };
-    };
+    uint64_t mFrameNumber;
 
     // mSlot is the slot index of this buffer (default INVALID_BUFFER_SLOT).
     int mSlot;
diff --git a/include/gui/BufferItemConsumer.h b/include/gui/BufferItemConsumer.h
index 56c7a3f..db7e944 100644
--- a/include/gui/BufferItemConsumer.h
+++ b/include/gui/BufferItemConsumer.h
@@ -18,18 +18,13 @@
 #define ANDROID_GUI_BUFFERITEMCONSUMER_H
 
 #include <gui/ConsumerBase.h>
-
-#include <ui/GraphicBuffer.h>
-
-#include <utils/String8.h>
-#include <utils/Vector.h>
-#include <utils/threads.h>
+#include <gui/BufferQueue.h>
 
 #define ANDROID_GRAPHICS_BUFFERITEMCONSUMER_JNI_ID "mBufferItemConsumer"
 
 namespace android {
 
-class BufferQueue;
+class String8;
 
 /**
  * BufferItemConsumer is a BufferQueue consumer endpoint that allows clients
@@ -42,6 +37,10 @@
   public:
     typedef ConsumerBase::FrameAvailableListener FrameAvailableListener;
 
+    struct BufferFreedListener : public virtual RefBase {
+        virtual void onBufferFreed(const wp<GraphicBuffer>& graphicBuffer) = 0;
+    };
+
     enum { DEFAULT_MAX_BUFFERS = -1 };
     enum { INVALID_BUFFER_SLOT = BufferQueue::INVALID_BUFFER_SLOT };
     enum { NO_BUFFER_AVAILABLE = BufferQueue::NO_BUFFER_AVAILABLE };
@@ -62,6 +61,10 @@
     // log messages.
     void setName(const String8& name);
 
+    // setBufferFreedListener sets the listener object that will be notified
+    // when an old buffer is being freed.
+    void setBufferFreedListener(const wp<BufferFreedListener>& listener);
+
     // Gets the next graphics buffer from the producer, filling out the
     // passed-in BufferItem structure. Returns NO_BUFFER_AVAILABLE if the queue
     // of buffers is empty, and INVALID_OPERATION if the maximum number of
@@ -86,6 +89,13 @@
     status_t releaseBuffer(const BufferItem &item,
             const sp<Fence>& releaseFence = Fence::NO_FENCE);
 
+   private:
+    void freeBufferLocked(int slotIndex) override;
+
+    // mBufferFreedListener is the listener object that will be called when
+    // an old buffer is being freed. If it is not NULL it will be called from
+    // freeBufferLocked.
+    wp<BufferFreedListener> mBufferFreedListener;
 };
 
 } // namespace android
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index fe4b1fa..bd62d85 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -23,10 +23,6 @@
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/IConsumerListener.h>
 
-// These are only required to keep other parts of the framework with incomplete
-// dependencies building successfully
-#include <gui/IGraphicBufferAlloc.h>
-
 namespace android {
 
 class BufferQueue {
@@ -60,14 +56,16 @@
     // weak references.
     class ProxyConsumerListener : public BnConsumerListener {
     public:
-        ProxyConsumerListener(const wp<ConsumerListener>& consumerListener);
+        explicit ProxyConsumerListener(const wp<ConsumerListener>& consumerListener);
         virtual ~ProxyConsumerListener();
-        virtual void onFrameAvailable(const BufferItem& item) override;
-        virtual void onFrameReplaced(const BufferItem& item) override;
-        virtual void onBuffersReleased() override;
-        virtual void onSidebandStreamChanged() override;
-        virtual bool getFrameTimestamps(uint64_t frameNumber,
-                FrameTimestamps* outTimestamps) const override;
+        void onDisconnect() override;
+        void onFrameAvailable(const BufferItem& item) override;
+        void onFrameReplaced(const BufferItem& item) override;
+        void onBuffersReleased() override;
+        void onSidebandStreamChanged() override;
+        void addAndGetFrameTimestamps(
+                const NewFrameEventsEntry* newTimestamps,
+                FrameEventHistoryDelta* outDelta) override;
     private:
         // mConsumerListener is a weak reference to the IConsumerListener.  This is
         // the raison d'etre of ProxyConsumerListener.
@@ -79,10 +77,9 @@
     // needed gralloc buffers.
     static void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
             sp<IGraphicBufferConsumer>* outConsumer,
-            const sp<IGraphicBufferAlloc>& allocator = NULL);
+            bool consumerIsSurfaceFlinger = false);
 
-private:
-    BufferQueue(); // Create through createBufferQueue
+    BufferQueue() = delete; // Create through createBufferQueue
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/BufferQueueConsumer.h b/include/gui/BufferQueueConsumer.h
index 8ec0546..b383056 100644
--- a/include/gui/BufferQueueConsumer.h
+++ b/include/gui/BufferQueueConsumer.h
@@ -22,6 +22,7 @@
 
 #include <gui/BufferQueueDefs.h>
 #include <gui/IGraphicBufferConsumer.h>
+#include <utils/String8.h>
 
 namespace android {
 
@@ -109,7 +110,7 @@
     virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
 
     // setConsumerName sets the name used in logging
-    virtual void setConsumerName(const String8& name);
+    status_t setConsumerName(const String8& name) override;
 
     // setDefaultBufferFormat allows the BufferQueue to create
     // GraphicBuffers of a defaultFormat if no format is specified
@@ -128,13 +129,19 @@
     // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0.
     virtual status_t setConsumerUsageBits(uint32_t usage);
 
+    // setConsumerIsProtected will turn on an internal bit that indicates whether
+    // the consumer can handle protected gralloc buffers (i.e. with
+    // GRALLOC_USAGE_PROTECTED set). IGraphicBufferProducer can query this
+    // capability using NATIVE_WINDOW_CONSUMER_IS_PROTECTED.
+    virtual status_t setConsumerIsProtected(bool isProtected);
+
     // setTransformHint bakes in rotation to buffers so overlays can be used.
     // The values are enumerated in window.h, e.g.
     // NATIVE_WINDOW_TRANSFORM_ROT_90.  The default is 0 (no transform).
     virtual status_t setTransformHint(uint32_t hint);
 
     // Retrieve the sideband buffer stream, if any.
-    virtual sp<NativeHandle> getSidebandStream() const;
+    status_t getSidebandStream(sp<NativeHandle>* outStream) const override;
 
     // See IGraphicBufferConsumer::getOccupancyHistory
     virtual status_t getOccupancyHistory(bool forceFlush,
@@ -144,7 +151,7 @@
     virtual status_t discardFreeBuffers() override;
 
     // dump our state in a String
-    virtual void dump(String8& result, const char* prefix) const;
+    status_t dumpState(const String8& prefix, String8* outResult) const override;
 
     // Functions required for backwards compatibility.
     // These will be modified/renamed in IGraphicBufferConsumer and will be
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index 1226feb..dd8b992 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -51,7 +51,6 @@
 namespace android {
 
 class IConsumerListener;
-class IGraphicBufferAlloc;
 class IProducerListener;
 
 class BufferQueueCore : public virtual RefBase {
@@ -79,14 +78,13 @@
     typedef Vector<BufferItem> Fifo;
 
     // BufferQueueCore manages a pool of gralloc memory slots to be used by
-    // producers and consumers. allocator is used to allocate all the needed
-    // gralloc buffers.
-    BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator = NULL);
+    // producers and consumers.
+    BufferQueueCore();
     virtual ~BufferQueueCore();
 
 private:
     // Dump our state in a string
-    void dump(String8& result, const char* prefix) const;
+    void dumpState(const String8& prefix, String8* outResult) const;
 
     // getMinUndequeuedBufferCountLocked returns the minimum number of buffers
     // that must remain in a state other than DEQUEUED. The async parameter
@@ -143,10 +141,6 @@
     void validateConsistencyLocked() const;
 #endif
 
-    // mAllocator is the connection to SurfaceFlinger that is used to allocate
-    // new GraphicBuffer objects.
-    sp<IGraphicBufferAlloc> mAllocator;
-
     // 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.
@@ -178,6 +172,10 @@
     // GraphicBuffers.
     uint32_t mConsumerUsageBits;
 
+    // mConsumerIsProtected indicates the consumer is ready to handle protected
+    // buffer.
+    bool mConsumerIsProtected;
+
     // mConnectedApi indicates the producer API that is currently connected
     // to this BufferQueue. It defaults to NO_CONNECTED_API, and gets updated
     // by the connect and disconnect methods.
@@ -317,13 +315,13 @@
 
     // Cached data about the shared buffer in shared buffer mode
     struct SharedBufferCache {
-        SharedBufferCache(Rect _crop, uint32_t _transform, int _scalingMode,
-                android_dataspace _dataspace)
+        SharedBufferCache(Rect _crop, uint32_t _transform,
+                uint32_t _scalingMode, android_dataspace _dataspace)
         : crop(_crop),
           transform(_transform),
           scalingMode(_scalingMode),
           dataspace(_dataspace) {
-        };
+        }
 
         Rect crop;
         uint32_t transform;
diff --git a/include/gui/BufferQueueDefs.h b/include/gui/BufferQueueDefs.h
index 83e9580..ffafb49 100644
--- a/include/gui/BufferQueueDefs.h
+++ b/include/gui/BufferQueueDefs.h
@@ -18,16 +18,12 @@
 #define ANDROID_GUI_BUFFERQUEUECOREDEFS_H
 
 #include <gui/BufferSlot.h>
+#include <ui/BufferQueueDefs.h>
 
 namespace android {
     class BufferQueueCore;
 
     namespace BufferQueueDefs {
-        // BufferQueue will keep track of at most this value of buffers.
-        // Attempts at runtime to increase the number of buffers past this
-        // will fail.
-        enum { NUM_BUFFER_SLOTS = 64 };
-
         typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];
     } // namespace BufferQueueDefs
 } // namespace android
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
index 8f613ee..5541468 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/include/gui/BufferQueueProducer.h
@@ -22,14 +22,14 @@
 
 namespace android {
 
-class BufferSlot;
+struct BufferSlot;
 
 class BufferQueueProducer : public BnGraphicBufferProducer,
                             private IBinder::DeathRecipient {
 public:
     friend class BufferQueue; // Needed to access binderDied
 
-    BufferQueueProducer(const sp<BufferQueueCore>& core);
+    BufferQueueProducer(const sp<BufferQueueCore>& core, bool consumerIsSurfaceFlinger = false);
     virtual ~BufferQueueProducer();
 
     // requestBuffer returns the GraphicBuffer for slot N.
@@ -80,9 +80,9 @@
     //
     // In both cases, the producer will need to call requestBuffer to get a
     // GraphicBuffer handle for the returned slot.
-    virtual status_t dequeueBuffer(int *outSlot, sp<Fence>* outFence,
+    status_t dequeueBuffer(int *outSlot, sp<Fence>* outFence,
             uint32_t width, uint32_t height, PixelFormat format,
-            uint32_t usage);
+            uint32_t usage, FrameEventHistoryDelta* outTimestamps) override;
 
     // See IGraphicBufferProducer::detachBuffer
     virtual status_t detachBuffer(int slot);
@@ -177,8 +177,7 @@
             sp<Fence>* outFence, float outTransformMatrix[16]) override;
 
     // See IGraphicBufferProducer::getFrameTimestamps
-    virtual bool getFrameTimestamps(uint64_t frameNumber,
-            FrameTimestamps* outTimestamps) const override;
+    virtual void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override;
 
     // See IGraphicBufferProducer::getUniqueId
     virtual status_t getUniqueId(uint64_t* outId) const override;
@@ -195,6 +194,9 @@
     // BufferQueueCore::INVALID_BUFFER_SLOT otherwise
     int getFreeSlotLocked() const;
 
+    void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
+            FrameEventHistoryDelta* outDelta);
+
     // waitForFreeSlotThenRelock finds the oldest slot in the FREE state. It may
     // block if there are no available slots and we are not in non-blocking
     // mode (producer and consumer controlled by the application). If it blocks,
@@ -218,6 +220,10 @@
 
     uint32_t mStickyTransform;
 
+    // This controls whether the GraphicBuffer pointer in the BufferItem is
+    // cleared after being queued
+    bool mConsumerIsSurfaceFlinger;
+
     // This saves the fence from the last queueBuffer, such that the
     // next queueBuffer call can throttle buffer production. The prior
     // queueBuffer's fence is not nessessarily available elsewhere,
diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h
index 0490c3c..891290b 100644
--- a/include/gui/ConsumerBase.h
+++ b/include/gui/ConsumerBase.h
@@ -17,19 +17,23 @@
 #ifndef ANDROID_GUI_CONSUMERBASE_H
 #define ANDROID_GUI_CONSUMERBASE_H
 
-#include <gui/BufferQueue.h>
+#include <gui/BufferQueueDefs.h>
+#include <gui/IConsumerListener.h>
+#include <gui/IGraphicBufferConsumer.h>
+#include <gui/OccupancyTracker.h>
 
-#include <ui/GraphicBuffer.h>
+#include <ui/PixelFormat.h>
 
 #include <utils/String8.h>
 #include <utils/Vector.h>
 #include <utils/threads.h>
-#include <gui/IConsumerListener.h>
+
 
 namespace android {
 // ----------------------------------------------------------------------------
 
 class String8;
+class GraphicBuffer;
 
 // ConsumerBase is a base class for BufferQueue consumer end-points. It
 // handles common tasks like management of the connection to the BufferQueue
@@ -63,11 +67,11 @@
     // log messages.
     void setName(const String8& name);
 
-    // dump writes the current state to a string. Child classes should add
+    // dumpState writes the current state to a string. Child classes should add
     // their state to the dump by overriding the dumpLocked method, which is
     // called by these methods after locking the mutex.
-    void dump(String8& result) const;
-    void dump(String8& result, const char* prefix) const;
+    void dumpState(String8& result) const;
+    void dumpState(String8& result, const char* prefix) const;
 
     // setFrameAvailableListener sets the listener object that will be notified
     // when a new frame becomes available.
@@ -101,7 +105,7 @@
     // buffers from the given IGraphicBufferConsumer.
     // The controlledByApp flag indicates that this consumer is under the application's
     // control.
-    ConsumerBase(const sp<IGraphicBufferConsumer>& consumer, bool controlledByApp = false);
+    explicit ConsumerBase(const sp<IGraphicBufferConsumer>& consumer, bool controlledByApp = false);
 
     // onLastStrongRef gets called by RefBase just before the dtor of the most
     // derived class.  It is used to clean up the buffers so that ConsumerBase
@@ -180,7 +184,7 @@
     // Derived classes should override this method to perform any cleanup that
     // must take place when a buffer is released back to the BufferQueue.  If
     // it is overridden the derived class's implementation must call
-    // ConsumerBase::releaseBufferLocked.e
+    // ConsumerBase::releaseBufferLocked.
     virtual status_t releaseBufferLocked(int slot,
             const sp<GraphicBuffer> graphicBuffer,
             EGLDisplay display, EGLSyncKHR eglFence);
@@ -222,7 +226,7 @@
     // slot that has not yet been used. The buffer allocated to a slot will also
     // be replaced if the requested buffer usage or geometry differs from that
     // of the buffer allocated to a slot.
-    Slot mSlots[BufferQueue::NUM_BUFFER_SLOTS];
+    Slot mSlots[BufferQueueDefs::NUM_BUFFER_SLOTS];
 
     // mAbandoned indicates that the BufferQueue will no longer be used to
     // consume images buffers pushed to it using the IGraphicBufferProducer
@@ -237,13 +241,19 @@
 
     // mFrameAvailableListener is the listener object that will be called when a
     // new frame becomes available. If it is not NULL it will be called from
-    // queueBuffer.
+    // queueBuffer. The listener object is protected by mFrameAvailableMutex
+    // (not mMutex).
+    Mutex mFrameAvailableMutex;
     wp<FrameAvailableListener> mFrameAvailableListener;
 
     // The ConsumerBase has-a BufferQueue and is responsible for creating this object
     // if none is supplied
     sp<IGraphicBufferConsumer> mConsumer;
 
+    // The final release fence of the most recent buffer released by
+    // releaseBufferLocked.
+    sp<Fence> mPrevFinalReleaseFence;
+
     // mMutex is the mutex used to prevent concurrent access to the member
     // variables of ConsumerBase objects. It must be locked whenever the
     // member variables are accessed or when any of the *Locked methods are
diff --git a/include/gui/CpuConsumer.h b/include/gui/CpuConsumer.h
index b7aa463..58602bf 100644
--- a/include/gui/CpuConsumer.h
+++ b/include/gui/CpuConsumer.h
@@ -17,18 +17,19 @@
 #ifndef ANDROID_GUI_CPUCONSUMER_H
 #define ANDROID_GUI_CPUCONSUMER_H
 
+#include <system/window.h>
+
 #include <gui/ConsumerBase.h>
+#include <gui/BufferQueue.h>
 
-#include <ui/GraphicBuffer.h>
-
-#include <utils/String8.h>
 #include <utils/Vector.h>
-#include <utils/threads.h>
 
 
 namespace android {
 
 class BufferQueue;
+class GraphicBuffer;
+class String8;
 
 /**
  * CpuConsumer is a BufferQueue consumer endpoint that allows direct CPU
diff --git a/include/gui/DisplayEventReceiver.h b/include/gui/DisplayEventReceiver.h
index a4718b9..32ce59a 100644
--- a/include/gui/DisplayEventReceiver.h
+++ b/include/gui/DisplayEventReceiver.h
@@ -25,6 +25,7 @@
 #include <utils/Timers.h>
 
 #include <binder/IInterface.h>
+#include <gui/ISurfaceComposer.h>
 
 // ----------------------------------------------------------------------------
 
@@ -32,16 +33,25 @@
 
 // ----------------------------------------------------------------------------
 
-class BitTube;
 class IDisplayEventConnection;
 
-// ----------------------------------------------------------------------------
+namespace gui {
+class BitTube;
+} // namespace gui
 
+static inline constexpr uint32_t fourcc(char c1, char c2, char c3, char c4) {
+    return static_cast<uint32_t>(c1) << 24 |
+        static_cast<uint32_t>(c2) << 16 |
+        static_cast<uint32_t>(c3) << 8 |
+        static_cast<uint32_t>(c4);
+}
+
+// ----------------------------------------------------------------------------
 class DisplayEventReceiver {
 public:
     enum {
-        DISPLAY_EVENT_VSYNC = 'vsyn',
-        DISPLAY_EVENT_HOTPLUG = 'plug'
+        DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'),
+        DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'),
     };
 
     struct Event {
@@ -74,7 +84,8 @@
      * or requestNextVsync to receive them.
      * Other events start being delivered immediately.
      */
-    DisplayEventReceiver();
+    DisplayEventReceiver(
+            ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp);
 
     /*
      * ~DisplayEventReceiver severs the connection with SurfaceFlinger, new events
@@ -102,15 +113,13 @@
      * should be destroyed and getEvents() shouldn't be called again.
      */
     ssize_t getEvents(Event* events, size_t count);
-    static ssize_t getEvents(const sp<BitTube>& dataChannel,
-            Event* events, size_t count);
+    static ssize_t getEvents(gui::BitTube* dataChannel, Event* events, size_t count);
 
     /*
      * sendEvents write events to the queue and returns how many events were
      * written.
      */
-    static ssize_t sendEvents(const sp<BitTube>& dataChannel,
-            Event const* events, size_t count);
+    static ssize_t sendEvents(gui::BitTube* dataChannel, Event const* events, size_t count);
 
     /*
      * setVsyncRate() sets the Event::VSync delivery rate. A value of
@@ -128,7 +137,7 @@
 
 private:
     sp<IDisplayEventConnection> mEventConnection;
-    sp<BitTube> mDataChannel;
+    std::unique_ptr<gui::BitTube> mDataChannel;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/FrameTimestamps.h b/include/gui/FrameTimestamps.h
index 4dc7467..9716be4 100644
--- a/include/gui/FrameTimestamps.h
+++ b/include/gui/FrameTimestamps.h
@@ -17,29 +17,321 @@
 #ifndef ANDROID_GUI_FRAMETIMESTAMPS_H
 #define ANDROID_GUI_FRAMETIMESTAMPS_H
 
-#include <utils/Timers.h>
+#include <ui/FenceTime.h>
 #include <utils/Flattenable.h>
+#include <utils/StrongPointer.h>
+#include <utils/Timers.h>
+
+#include <array>
+#include <bitset>
+#include <vector>
 
 namespace android {
 
-struct FrameTimestamps : public LightFlattenablePod<FrameTimestamps> {
-    FrameTimestamps() :
-        frameNumber(0),
-        postedTime(0),
-        acquireTime(0),
-        refreshStartTime(0),
-        glCompositionDoneTime(0),
-        displayRetireTime(0),
-        releaseTime(0) {}
+struct FrameEvents;
+class FrameEventHistoryDelta;
+class String8;
 
-    uint64_t frameNumber;
-    nsecs_t postedTime;
-    nsecs_t acquireTime;
-    nsecs_t refreshStartTime;
-    nsecs_t glCompositionDoneTime;
-    nsecs_t displayRetireTime;
-    nsecs_t releaseTime;
+
+// Identifiers for all the events that may be recorded or reported.
+enum class FrameEvent {
+    POSTED,
+    REQUESTED_PRESENT,
+    LATCH,
+    ACQUIRE,
+    FIRST_REFRESH_START,
+    LAST_REFRESH_START,
+    GPU_COMPOSITION_DONE,
+    DISPLAY_PRESENT,
+    DEQUEUE_READY,
+    RELEASE,
+    EVENT_COUNT, // Not an actual event.
 };
 
+
+// A collection of timestamps corresponding to a single frame.
+struct FrameEvents {
+    static constexpr auto EVENT_COUNT =
+            static_cast<size_t>(FrameEvent::EVENT_COUNT);
+    static_assert(EVENT_COUNT <= 32, "Event count sanity check failed.");
+    static constexpr nsecs_t TIMESTAMP_PENDING = -2;
+
+    static inline bool isValidTimestamp(nsecs_t time) {
+        return time != TIMESTAMP_PENDING;
+    }
+
+    bool hasPostedInfo() const;
+    bool hasRequestedPresentInfo() const;
+    bool hasLatchInfo() const;
+    bool hasFirstRefreshStartInfo() const;
+    bool hasLastRefreshStartInfo() const;
+    bool hasAcquireInfo() const;
+    bool hasGpuCompositionDoneInfo() const;
+    bool hasDisplayPresentInfo() const;
+    bool hasReleaseInfo() const;
+    bool hasDequeueReadyInfo() const;
+
+    void checkFencesForCompletion();
+    void dump(String8& outString) const;
+
+    bool valid{false};
+    int connectId{0};
+    uint64_t frameNumber{0};
+
+    // Whether or not certain points in the frame's life cycle have been
+    // encountered help us determine if timestamps aren't available because
+    // a) we'll just never get them or b) they're not ready yet.
+    bool addPostCompositeCalled{false};
+    bool addReleaseCalled{false};
+
+    nsecs_t postedTime{TIMESTAMP_PENDING};
+    nsecs_t requestedPresentTime{TIMESTAMP_PENDING};
+    nsecs_t latchTime{TIMESTAMP_PENDING};
+    nsecs_t firstRefreshStartTime{TIMESTAMP_PENDING};
+    nsecs_t lastRefreshStartTime{TIMESTAMP_PENDING};
+    nsecs_t dequeueReadyTime{TIMESTAMP_PENDING};
+
+    std::shared_ptr<FenceTime> acquireFence{FenceTime::NO_FENCE};
+    std::shared_ptr<FenceTime> gpuCompositionDoneFence{FenceTime::NO_FENCE};
+    std::shared_ptr<FenceTime> displayPresentFence{FenceTime::NO_FENCE};
+    std::shared_ptr<FenceTime> releaseFence{FenceTime::NO_FENCE};
+};
+
+struct CompositorTiming {
+    nsecs_t deadline{0};
+    nsecs_t interval{16666667};
+    nsecs_t presentLatency{16666667};
+};
+
+// A short history of frames that are synchronized between the consumer and
+// producer via deltas.
+class FrameEventHistory {
+public:
+    virtual ~FrameEventHistory();
+
+    FrameEvents* getFrame(uint64_t frameNumber);
+    FrameEvents* getFrame(uint64_t frameNumber, size_t* iHint);
+    void checkFencesForCompletion();
+    void dump(String8& outString) const;
+
+    static constexpr size_t MAX_FRAME_HISTORY = 8;
+
+protected:
+    std::array<FrameEvents, MAX_FRAME_HISTORY> mFrames;
+
+    CompositorTiming mCompositorTiming;
+};
+
+
+// The producer's interface to FrameEventHistory
+class ProducerFrameEventHistory : public FrameEventHistory {
+public:
+    ~ProducerFrameEventHistory() override;
+
+    // Public for testing.
+    static nsecs_t snapToNextTick(
+            nsecs_t timestamp, nsecs_t tickPhase, nsecs_t tickInterval);
+
+    nsecs_t getNextCompositeDeadline(const nsecs_t now) const;
+    nsecs_t getCompositeInterval() const { return mCompositorTiming.interval; }
+    nsecs_t getCompositeToPresentLatency() const {
+        return mCompositorTiming.presentLatency;
+    }
+
+    // virtual for testing.
+    virtual void updateAcquireFence(
+            uint64_t frameNumber, std::shared_ptr<FenceTime>&& acquire);
+    void applyDelta(const FrameEventHistoryDelta& delta);
+
+    void updateSignalTimes();
+
+protected:
+    void applyFenceDelta(FenceTimeline* timeline,
+            std::shared_ptr<FenceTime>* dst,
+            const FenceTime::Snapshot& src) const;
+
+    // virtual for testing.
+    virtual std::shared_ptr<FenceTime> createFenceTime(
+            const sp<Fence>& fence) const;
+
+    size_t mAcquireOffset{0};
+
+    // The consumer updates it's timelines in Layer and SurfaceFlinger since
+    // they can coordinate shared timelines better. The producer doesn't have
+    // shared timelines though, so just let it own and update all of them.
+    FenceTimeline mAcquireTimeline;
+    FenceTimeline mGpuCompositionDoneTimeline;
+    FenceTimeline mPresentTimeline;
+    FenceTimeline mReleaseTimeline;
+};
+
+
+// Used by the consumer to create a new frame event record that is
+// partially complete.
+struct NewFrameEventsEntry {
+    uint64_t frameNumber{0};
+    nsecs_t postedTime{0};
+    nsecs_t requestedPresentTime{0};
+    std::shared_ptr<FenceTime> acquireFence{FenceTime::NO_FENCE};
+};
+
+
+// Used by the consumer to keep track of which fields it already sent to
+// the producer.
+class FrameEventDirtyFields {
+public:
+    inline void reset() { mBitset.reset(); }
+    inline bool anyDirty() const { return mBitset.any(); }
+
+    template <FrameEvent event>
+    inline void setDirty() {
+        constexpr size_t eventIndex = static_cast<size_t>(event);
+        static_assert(eventIndex < FrameEvents::EVENT_COUNT, "Bad index.");
+        mBitset.set(eventIndex);
+    }
+
+    template <FrameEvent event>
+    inline bool isDirty() const {
+        constexpr size_t eventIndex = static_cast<size_t>(event);
+        static_assert(eventIndex < FrameEvents::EVENT_COUNT, "Bad index.");
+        return mBitset[eventIndex];
+    }
+
+private:
+    std::bitset<FrameEvents::EVENT_COUNT> mBitset;
+};
+
+
+// The consumer's interface to FrameEventHistory
+class ConsumerFrameEventHistory : public FrameEventHistory {
+public:
+    ~ConsumerFrameEventHistory() override;
+
+    void onDisconnect();
+
+    void initializeCompositorTiming(const CompositorTiming& compositorTiming);
+
+    void addQueue(const NewFrameEventsEntry& newEntry);
+    void addLatch(uint64_t frameNumber, nsecs_t latchTime);
+    void addPreComposition(uint64_t frameNumber, nsecs_t refreshStartTime);
+    void addPostComposition(uint64_t frameNumber,
+            const std::shared_ptr<FenceTime>& gpuCompositionDone,
+            const std::shared_ptr<FenceTime>& displayPresent,
+            const CompositorTiming& compositorTiming);
+    void addRelease(uint64_t frameNumber, nsecs_t dequeueReadyTime,
+            std::shared_ptr<FenceTime>&& release);
+
+    void getAndResetDelta(FrameEventHistoryDelta* delta);
+
+private:
+    void getFrameDelta(FrameEventHistoryDelta* delta,
+            const std::array<FrameEvents, MAX_FRAME_HISTORY>::iterator& frame);
+
+    std::array<FrameEventDirtyFields, MAX_FRAME_HISTORY> mFramesDirty;
+
+    size_t mQueueOffset{0};
+    size_t mCompositionOffset{0};
+    size_t mReleaseOffset{0};
+
+    int mCurrentConnectId{0};
+    bool mProducerWantsEvents{false};
+};
+
+
+// A single frame update from the consumer to producer that can be sent
+// through Binder.
+// Although this may be sent multiple times for the same frame as new
+// timestamps are set, Fences only need to be sent once.
+class FrameEventsDelta : public Flattenable<FrameEventsDelta> {
+friend class ProducerFrameEventHistory;
+public:
+    FrameEventsDelta() = default;
+    FrameEventsDelta(size_t index,
+            const FrameEvents& frameTimestamps,
+            const FrameEventDirtyFields& dirtyFields);
+
+    // Movable.
+    FrameEventsDelta(FrameEventsDelta&& src) = default;
+    FrameEventsDelta& operator=(FrameEventsDelta&& src) = default;
+    // Not copyable.
+    FrameEventsDelta(const FrameEventsDelta& src) = delete;
+    FrameEventsDelta& operator=(const FrameEventsDelta& src) = delete;
+
+    // Flattenable implementation
+    size_t getFlattenedSize() const;
+    size_t getFdCount() const;
+    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);
+
+private:
+    static constexpr size_t minFlattenedSize();
+
+    size_t mIndex{0};
+    uint64_t mFrameNumber{0};
+
+    bool mAddPostCompositeCalled{0};
+    bool mAddReleaseCalled{0};
+
+    nsecs_t mPostedTime{FrameEvents::TIMESTAMP_PENDING};
+    nsecs_t mRequestedPresentTime{FrameEvents::TIMESTAMP_PENDING};
+    nsecs_t mLatchTime{FrameEvents::TIMESTAMP_PENDING};
+    nsecs_t mFirstRefreshStartTime{FrameEvents::TIMESTAMP_PENDING};
+    nsecs_t mLastRefreshStartTime{FrameEvents::TIMESTAMP_PENDING};
+    nsecs_t mDequeueReadyTime{FrameEvents::TIMESTAMP_PENDING};
+
+    FenceTime::Snapshot mGpuCompositionDoneFence;
+    FenceTime::Snapshot mDisplayPresentFence;
+    FenceTime::Snapshot mReleaseFence;
+
+    // This is a static method with an auto return value so we can call
+    // it without needing const and non-const versions.
+    template <typename ThisT>
+    static inline auto allFences(ThisT fed) ->
+            std::array<decltype(&fed->mReleaseFence), 3> {
+        return {{
+            &fed->mGpuCompositionDoneFence, &fed->mDisplayPresentFence,
+            &fed->mReleaseFence
+        }};
+    }
+};
+
+
+// A collection of updates from consumer to producer that can be sent
+// through Binder.
+class FrameEventHistoryDelta
+        : public Flattenable<FrameEventHistoryDelta> {
+
+friend class ConsumerFrameEventHistory;
+friend class ProducerFrameEventHistory;
+
+public:
+    FrameEventHistoryDelta() = default;
+
+    // Movable.
+    FrameEventHistoryDelta(FrameEventHistoryDelta&& src) = default;
+    FrameEventHistoryDelta& operator=(FrameEventHistoryDelta&& src);
+    // Not copyable.
+    FrameEventHistoryDelta(const FrameEventHistoryDelta& src) = delete;
+    FrameEventHistoryDelta& operator=(
+            const FrameEventHistoryDelta& src) = delete;
+
+    // Flattenable implementation.
+    size_t getFlattenedSize() const;
+    size_t getFdCount() const;
+    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);
+
+private:
+    static constexpr size_t minFlattenedSize();
+
+    std::vector<FrameEventsDelta> mDeltas;
+    CompositorTiming mCompositorTiming;
+};
+
+
 } // namespace android
 #endif
diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h
index 6267625..2cf6162 100644
--- a/include/gui/GLConsumer.h
+++ b/include/gui/GLConsumer.h
@@ -20,10 +20,10 @@
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 
-#include <gui/IGraphicBufferProducer.h>
-#include <gui/BufferQueue.h>
+#include <gui/BufferQueueDefs.h>
 #include <gui/ConsumerBase.h>
 
+#include <ui/FenceTime.h>
 #include <ui/GraphicBuffer.h>
 
 #include <utils/String8.h>
@@ -146,6 +146,10 @@
     // documented by the source.
     int64_t getTimestamp();
 
+    // getDataSpace retrieves the DataSpace associated with the texture image
+    // set by the most recent call to updateTexImage.
+    android_dataspace getCurrentDataSpace();
+
     // getFrameNumber retrieves the frame number associated with the texture
     // image set by the most recent call to updateTexImage.
     //
@@ -168,7 +172,9 @@
     void setFilteringEnabled(bool enabled);
 
     // getCurrentBuffer returns the buffer associated with the current image.
-    sp<GraphicBuffer> getCurrentBuffer() const;
+    // When outSlot is not nullptr, the current buffer slot index is also
+    // returned.
+    sp<GraphicBuffer> getCurrentBuffer(int* outSlot = nullptr) const;
 
     // getCurrentTextureTarget returns the texture target of the current
     // texture as returned by updateTexImage().
@@ -187,6 +193,10 @@
     // ready to be read from.
     sp<Fence> getCurrentFence() const;
 
+    // getCurrentFence returns the FenceTime indicating when the current
+    // buffer is ready to be read from.
+    std::shared_ptr<FenceTime> getCurrentFenceTime() const;
+
     // doGLFenceWait inserts a wait command into the OpenGL ES command stream
     // to ensure that it is safe for future OpenGL ES commands to access the
     // current texture buffer.
@@ -250,7 +260,7 @@
     // mEglSlots array in addition to the ConsumerBase.
     virtual status_t releaseBufferLocked(int slot,
             const sp<GraphicBuffer> graphicBuffer,
-            EGLDisplay display, EGLSyncKHR eglFence);
+            EGLDisplay display, EGLSyncKHR eglFence) override;
 
     status_t releaseBufferLocked(int slot,
             const sp<GraphicBuffer> graphicBuffer, EGLSyncKHR eglFence) {
@@ -398,6 +408,9 @@
     // mCurrentFence is the fence received from BufferQueue in updateTexImage.
     sp<Fence> mCurrentFence;
 
+    // The FenceTime wrapper around mCurrentFence.
+    std::shared_ptr<FenceTime> mCurrentFenceTime{FenceTime::NO_FENCE};
+
     // mCurrentTransformMatrix is the transform matrix for the current texture.
     // It gets computed by computeTransformMatrix each time updateTexImage is
     // called.
@@ -407,6 +420,10 @@
     // gets set each time updateTexImage is called.
     int64_t mCurrentTimestamp;
 
+    // mCurrentDataSpace is the dataspace for the current texture. It
+    // gets set each time updateTexImage is called.
+    android_dataspace mCurrentDataSpace;
+
     // mCurrentFrameNumber is the frame counter for the current texture.
     // It gets set each time updateTexImage is called.
     uint64_t mCurrentFrameNumber;
@@ -472,7 +489,7 @@
     // slot that has not yet been used. The buffer allocated to a slot will also
     // be replaced if the requested buffer usage or geometry differs from that
     // of the buffer allocated to a slot.
-    EglSlot mEglSlots[BufferQueue::NUM_BUFFER_SLOTS];
+    EglSlot mEglSlots[BufferQueueDefs::NUM_BUFFER_SLOTS];
 
     // mCurrentTexture is the buffer slot index of the buffer that is currently
     // bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT,
diff --git a/include/gui/GraphicBufferAlloc.h b/include/gui/GraphicBufferAlloc.h
deleted file mode 100644
index 62e3877..0000000
--- a/include/gui/GraphicBufferAlloc.h
+++ /dev/null
@@ -1,45 +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.
- */
-
-#ifndef ANDROID_SF_GRAPHIC_BUFFER_ALLOC_H
-#define ANDROID_SF_GRAPHIC_BUFFER_ALLOC_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <gui/IGraphicBufferAlloc.h>
-#include <ui/PixelFormat.h>
-#include <utils/Errors.h>
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-class GraphicBuffer;
-
-class GraphicBufferAlloc : public BnGraphicBufferAlloc {
-public:
-    GraphicBufferAlloc();
-    virtual ~GraphicBufferAlloc();
-    virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width,
-            uint32_t height, PixelFormat format, uint32_t usage,
-            std::string requestorName, status_t* error) override;
-};
-
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_SF_GRAPHIC_BUFFER_ALLOC_H
diff --git a/include/gui/GraphicsEnv.h b/include/gui/GraphicsEnv.h
deleted file mode 100644
index 4c7366f..0000000
--- a/include/gui/GraphicsEnv.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_GUI_GRAPHICS_ENV_H
-#define ANDROID_GUI_GRAPHICS_ENV_H 1
-
-#include <string>
-
-struct android_namespace_t;
-
-namespace android {
-
-class GraphicsEnv {
-public:
-    static GraphicsEnv& getInstance();
-
-    // 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);
-    android_namespace_t* getDriverNamespace();
-
-private:
-    GraphicsEnv() = default;
-    std::string mDriverPath;
-    android_namespace_t* mDriverNamespace = 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_GUI_GRAPHICS_ENV_H
diff --git a/include/gui/IConsumerListener.h b/include/gui/IConsumerListener.h
index 1efcf3c..c082882 100644
--- a/include/gui/IConsumerListener.h
+++ b/include/gui/IConsumerListener.h
@@ -14,98 +14,84 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_GUI_ICONSUMERLISTENER_H
-#define ANDROID_GUI_ICONSUMERLISTENER_H
+#pragma once
 
-#include <stdint.h>
-#include <sys/types.h>
+#include <binder/IInterface.h>
+#include <binder/SafeInterface.h>
 
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 
-#include <binder/IInterface.h>
-
-#include <gui/FrameTimestamps.h>
+#include <cstdint>
 
 namespace android {
-// ----------------------------------------------------------------------------
 
 class BufferItem;
+class FrameEventHistoryDelta;
+struct NewFrameEventsEntry;
 
-// ConsumerListener is the interface through which the BufferQueue notifies
-// the consumer of events that the consumer may wish to react to.  Because
-// the consumer will generally have a mutex that is locked during calls from
-// the consumer to the BufferQueue, these calls from the BufferQueue to the
+// ConsumerListener is the interface through which the BufferQueue notifies the consumer of events
+// that the consumer may wish to react to. Because the consumer will generally have a mutex that is
+// locked during calls from the consumer to the BufferQueue, these calls from the BufferQueue to the
 // consumer *MUST* be called only when the BufferQueue mutex is NOT locked.
 
 class ConsumerListener : public virtual RefBase {
 public:
-    ConsumerListener() { }
-    virtual ~ConsumerListener() { }
+    ConsumerListener() {}
+    virtual ~ConsumerListener();
 
-    // onFrameAvailable is called from queueBuffer each time an additional
-    // frame becomes available for consumption. This means that frames that
-    // are queued while in asynchronous mode only trigger the callback if no
-    // previous frames are pending. Frames queued while in synchronous mode
-    // always trigger the callback. The item passed to the callback will contain
-    // all of the information about the queued frame except for its
-    // GraphicBuffer pointer, which will always be null.
+    // onDisconnect is called when a producer disconnects from the BufferQueue.
+    virtual void onDisconnect() {} /* Asynchronous */
+
+    // onFrameAvailable is called from queueBuffer each time an additional frame becomes available
+    // for consumption. This means that frames that are queued while in asynchronous mode only
+    // trigger the callback if no previous frames are pending. Frames queued while in synchronous
+    // mode always trigger the callback. The item passed to the callback will contain all of the
+    // information about the queued frame except for its GraphicBuffer pointer, which will always be
+    // null (except if the consumer is SurfaceFlinger).
     //
-    // This is called without any lock held and can be called concurrently
-    // by multiple threads.
+    // This is called without any lock held and can be called concurrently by multiple threads.
     virtual void onFrameAvailable(const BufferItem& item) = 0; /* Asynchronous */
 
-    // onFrameReplaced is called from queueBuffer if the frame being queued is
-    // replacing an existing slot in the queue. Any call to queueBuffer that
-    // doesn't call onFrameAvailable will call this callback instead. The item
-    // passed to the callback will contain all of the information about the
-    // queued frame except for its GraphicBuffer pointer, which will always be
-    // null.
+    // onFrameReplaced is called from queueBuffer if the frame being queued is replacing an existing
+    // slot in the queue. Any call to queueBuffer that doesn't call onFrameAvailable will call this
+    // callback instead. The item passed to the callback will contain all of the information about
+    // the queued frame except for its GraphicBuffer pointer, which will always be null.
     //
-    // This is called without any lock held and can be called concurrently
-    // by multiple threads.
+    // This is called without any lock held and can be called concurrently by multiple threads.
     virtual void onFrameReplaced(const BufferItem& /* item */) {} /* Asynchronous */
 
-    // onBuffersReleased is called to notify the buffer consumer that the
-    // BufferQueue has released its references to one or more GraphicBuffers
-    // contained in its slots.  The buffer consumer should then call
-    // BufferQueue::getReleasedBuffers to retrieve the list of buffers
+    // onBuffersReleased is called to notify the buffer consumer that the BufferQueue has released
+    // its references to one or more GraphicBuffers contained in its slots. The buffer consumer
+    // should then call BufferQueue::getReleasedBuffers to retrieve the list of buffers.
     //
-    // This is called without any lock held and can be called concurrently
-    // by multiple threads.
+    // This is called without any lock held and can be called concurrently by multiple threads.
     virtual void onBuffersReleased() = 0; /* Asynchronous */
 
-    // onSidebandStreamChanged is called to notify the buffer consumer that the
-    // BufferQueue's sideband buffer stream has changed. This is called when a
-    // stream is first attached and when it is either detached or replaced by a
-    // different stream.
+    // onSidebandStreamChanged is called to notify the buffer consumer that the BufferQueue's
+    // sideband buffer stream has changed. This is called when a stream is first attached and when
+    // it is either detached or replaced by a different stream.
     virtual void onSidebandStreamChanged() = 0; /* Asynchronous */
 
-    // See IGraphicBufferProducer::getFrameTimestamps
-    // This queries the consumer for the timestamps
-    virtual bool getFrameTimestamps(uint64_t /*frameNumber*/,
-            FrameTimestamps* /*outTimestamps*/) const { return false; }
+    // Notifies the consumer of any new producer-side timestamps and returns the combined frame
+    // history that hasn't already been retrieved.
+    //
+    // WARNING: This method can only be called when the BufferQueue is in the consumer's process.
+    virtual void addAndGetFrameTimestamps(const NewFrameEventsEntry* /*newTimestamps*/,
+                                          FrameEventHistoryDelta* /*outDelta*/) {}
 };
 
-
-class IConsumerListener : public ConsumerListener, public IInterface
-{
+class IConsumerListener : public ConsumerListener, public IInterface {
 public:
-    DECLARE_META_INTERFACE(ConsumerListener);
+    DECLARE_META_INTERFACE(ConsumerListener)
 };
 
-// ----------------------------------------------------------------------------
-
-class BnConsumerListener : public BnInterface<IConsumerListener>
-{
+class BnConsumerListener : public SafeBnInterface<IConsumerListener> {
 public:
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
+    BnConsumerListener() : SafeBnInterface<IConsumerListener>("BnConsumerListener") {}
+
+    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                        uint32_t flags = 0) override;
 };
 
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_GUI_ICONSUMERLISTENER_H
+} // namespace android
diff --git a/include/gui/IDisplayEventConnection.h b/include/gui/IDisplayEventConnection.h
index 86247de..d783f74 100644
--- a/include/gui/IDisplayEventConnection.h
+++ b/include/gui/IDisplayEventConnection.h
@@ -14,60 +14,52 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_GUI_IDISPLAY_EVENT_CONNECTION_H
-#define ANDROID_GUI_IDISPLAY_EVENT_CONNECTION_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
+#pragma once
 
 #include <binder/IInterface.h>
+#include <binder/SafeInterface.h>
+
+#include <utils/Errors.h>
+
+#include <cstdint>
 
 namespace android {
-// ----------------------------------------------------------------------------
 
+namespace gui {
 class BitTube;
+} // namespace gui
 
-class IDisplayEventConnection : public IInterface
-{
+class IDisplayEventConnection : public IInterface {
 public:
-
-    DECLARE_META_INTERFACE(DisplayEventConnection);
+    DECLARE_META_INTERFACE(DisplayEventConnection)
 
     /*
-     * getDataChannel() returns a BitTube where to receive the events from
+     * stealReceiveChannel() returns a BitTube to receive events from. Only the receive file
+     * descriptor of outChannel will be initialized, and this effectively "steals" the receive
+     * channel from the remote end (such that the remote end can only use its send channel).
      */
-    virtual sp<BitTube> getDataChannel() const = 0;
+    virtual status_t stealReceiveChannel(gui::BitTube* outChannel) = 0;
 
     /*
-     * setVsyncRate() sets the vsync event delivery rate. A value of
-     * 1 returns every vsync events. A value of 2 returns every other events,
-     * etc... a value of 0 returns no event unless  requestNextVsync() has
-     * been called.
+     * setVsyncRate() sets the vsync event delivery rate. A value of 1 returns every vsync event.
+     * A value of 2 returns every other event, etc. A value of 0 returns no event unless
+     * requestNextVsync() has been called.
      */
-    virtual void setVsyncRate(uint32_t count) = 0;
+    virtual status_t setVsyncRate(uint32_t count) = 0;
 
     /*
-     * requestNextVsync() schedules the next vsync event. It has no effect
-     * if the vsync rate is > 0.
+     * requestNextVsync() schedules the next vsync event. It has no effect if the vsync rate is > 0.
      */
-    virtual void requestNextVsync() = 0;    // asynchronous
+    virtual void requestNextVsync() = 0; // Asynchronous
 };
 
-// ----------------------------------------------------------------------------
-
-class BnDisplayEventConnection : public BnInterface<IDisplayEventConnection>
-{
+class BnDisplayEventConnection : public SafeBnInterface<IDisplayEventConnection> {
 public:
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
+    BnDisplayEventConnection()
+          : SafeBnInterface<IDisplayEventConnection>("BnDisplayEventConnection") {}
+
+    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                        uint32_t flags = 0) override;
 };
 
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_GUI_IDISPLAY_EVENT_CONNECTION_H
+} // namespace android
diff --git a/include/gui/IGraphicBufferAlloc.h b/include/gui/IGraphicBufferAlloc.h
deleted file mode 100644
index 600cf27..0000000
--- a/include/gui/IGraphicBufferAlloc.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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 ANDROID_GUI_IGRAPHIC_BUFFER_ALLOC_H
-#define ANDROID_GUI_IGRAPHIC_BUFFER_ALLOC_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/IInterface.h>
-#include <ui/GraphicBuffer.h>
-#include <ui/PixelFormat.h>
-#include <utils/RefBase.h>
-
-#include <string>
-
-namespace android {
-// ----------------------------------------------------------------------------
-
-class IGraphicBufferAlloc : public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(GraphicBufferAlloc);
-
-    /* Create a new GraphicBuffer for the client to use.
-     */
-    virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
-            PixelFormat format, uint32_t usage, std::string requestorName,
-            status_t* error) = 0;
-
-    sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
-            PixelFormat format, uint32_t usage, status_t* error) {
-        return createGraphicBuffer(w, h, format, usage, "<Unknown>", error);
-    }
-};
-
-// ----------------------------------------------------------------------------
-
-class BnGraphicBufferAlloc : public BnInterface<IGraphicBufferAlloc>
-{
-public:
-    virtual status_t onTransact(uint32_t code,
-                                const Parcel& data,
-                                Parcel* reply,
-                                uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_GUI_IGRAPHIC_BUFFER_ALLOC_H
diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h
index 3b10d78..3d069df 100644
--- a/include/gui/IGraphicBufferConsumer.h
+++ b/include/gui/IGraphicBufferConsumer.h
@@ -14,26 +14,21 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_GUI_IGRAPHICBUFFERCONSUMER_H
-#define ANDROID_GUI_IGRAPHICBUFFERCONSUMER_H
+#pragma once
 
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/Timers.h>
+#include <gui/OccupancyTracker.h>
 
 #include <binder/IInterface.h>
-#include <ui/PixelFormat.h>
-#include <ui/Rect.h>
-#include <gui/OccupancyTracker.h>
+#include <binder/SafeInterface.h>
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 
+#include <ui/PixelFormat.h>
+
+#include <utils/Errors.h>
+
 namespace android {
-// ----------------------------------------------------------------------------
 
 class BufferItem;
 class Fence;
@@ -42,11 +37,12 @@
 class NativeHandle;
 
 class IGraphicBufferConsumer : public IInterface {
-
 public:
+    DECLARE_META_INTERFACE(GraphicBufferConsumer)
+
     enum {
-        // Returned by releaseBuffer, after which the consumer must
-        // free any references to the just-released buffer that it might have.
+        // Returned by releaseBuffer, after which the consumer must free any references to the
+        // just-released buffer that it might have.
         STALE_BUFFER_SLOT = 1,
         // Returned by dequeueBuffer if there are no pending buffers available.
         NO_BUFFER_AVAILABLE,
@@ -54,88 +50,79 @@
         PRESENT_LATER,
     };
 
-    // acquireBuffer attempts to acquire ownership of the next pending buffer in
-    // the BufferQueue.  If no buffer is pending then it returns
-    // NO_BUFFER_AVAILABLE.  If a buffer is successfully acquired, the
-    // information about the buffer is returned in BufferItem.
+    // acquireBuffer attempts to acquire ownership of the next pending buffer in the BufferQueue.
+    // If no buffer is pending then it returns NO_BUFFER_AVAILABLE. If a buffer is successfully
+    // acquired, the information about the buffer is returned in BufferItem.
     //
-    // If the buffer returned had previously been
-    // acquired then the BufferItem::mGraphicBuffer field of buffer is set to
-    // NULL and it is assumed that the consumer still holds a reference to the
+    // If the buffer returned had previously been acquired then the BufferItem::mGraphicBuffer field
+    // of buffer is set to NULL and it is assumed that the consumer still holds a reference to the
     // buffer.
     //
-    // If presentWhen is non-zero, it indicates the time when the buffer will
-    // be displayed on screen.  If the buffer's timestamp is farther in the
-    // future, the buffer won't be acquired, and PRESENT_LATER will be
-    // returned.  The presentation time is in nanoseconds, and the time base
+    // If presentWhen is non-zero, it indicates the time when the buffer will be displayed on
+    // screen. If the buffer's timestamp is farther in the future, the buffer won't be acquired, and
+    // PRESENT_LATER will be returned. The presentation time is in nanoseconds, and the time base
     // is CLOCK_MONOTONIC.
     //
-    // If maxFrameNumber is non-zero, it indicates that acquireBuffer should
-    // only return a buffer with a frame number less than or equal to
-    // maxFrameNumber. If no such frame is available (such as when a buffer has
-    // been replaced but the consumer has not received the onFrameReplaced
-    // callback), then PRESENT_LATER will be returned.
+    // If maxFrameNumber is non-zero, it indicates that acquireBuffer should only return a buffer
+    // with a frame number less than or equal to maxFrameNumber. If no such frame is available
+    // (such as when a buffer has been replaced but the consumer has not received the
+    // onFrameReplaced callback), then PRESENT_LATER will be returned.
     //
     // Return of NO_ERROR means the operation completed as normal.
     //
-    // Return of a positive value means the operation could not be completed
-    //    at this time, but the user should try again later:
+    // Return of a positive value means the operation could not be completed at this time, but the
+    // user should try again later:
     // * NO_BUFFER_AVAILABLE - no buffer is pending (nothing queued by producer)
     // * PRESENT_LATER - the buffer's timestamp is farther in the future
     //
     // Return of a negative value means an error has occurred:
     // * INVALID_OPERATION - too many buffers have been acquired
     virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen,
-            uint64_t maxFrameNumber = 0) = 0;
+                                   uint64_t maxFrameNumber = 0) = 0;
 
-    // detachBuffer attempts to remove all ownership of the buffer in the given
-    // slot from the buffer queue. If this call succeeds, the slot will be
-    // freed, and there will be no way to obtain the buffer from this interface.
-    // The freed slot will remain unallocated until either it is selected to
-    // hold a freshly allocated buffer in dequeueBuffer or a buffer is attached
-    // to the slot. The buffer must have already been acquired.
+    // detachBuffer attempts to remove all ownership of the buffer in the given slot from the buffer
+    // queue. If this call succeeds, the slot will be freed, and there will be no way to obtain the
+    // buffer from this interface. The freed slot will remain unallocated until either it is
+    // selected to hold a freshly allocated buffer in dequeueBuffer or a buffer is attached to the
+    // slot. The buffer must have already been acquired.
     //
     // Return of a value other than NO_ERROR means an error has occurred:
-    // * BAD_VALUE - the given slot number is invalid, either because it is
-    //               out of the range [0, NUM_BUFFER_SLOTS) or because the slot
-    //               it refers to is not currently acquired.
+    // * BAD_VALUE - the given slot number is invalid, either because it is out of the range
+    //               [0, NUM_BUFFER_SLOTS) or because the slot it refers to is not
+    //               currently acquired.
     virtual status_t detachBuffer(int slot) = 0;
 
-    // attachBuffer attempts to transfer ownership of a buffer to the buffer
-    // queue. If this call succeeds, it will be as if this buffer was acquired
-    // from the returned slot number. As such, this call will fail if attaching
-    // this buffer would cause too many buffers to be simultaneously acquired.
+    // attachBuffer attempts to transfer ownership of a buffer to the BufferQueue. If this call
+    // succeeds, it will be as if this buffer was acquired from the returned slot number. As such,
+    // this call will fail if attaching this buffer would cause too many buffers to be
+    // simultaneously acquired.
     //
-    // If the buffer is successfully attached, its frameNumber is initialized
-    // to 0. This must be passed into the releaseBuffer call or else the buffer
-    // will be deallocated as stale.
+    // If the buffer is successfully attached, its frameNumber is initialized to 0. This must be
+    // passed into the releaseBuffer call or else the buffer will be deallocated as stale.
     //
     // Return of a value other than NO_ERROR means an error has occurred:
-    // * BAD_VALUE - outSlot or buffer were NULL, or the generation number of
-    //               the buffer did not match the buffer queue.
-    // * INVALID_OPERATION - cannot attach the buffer because it would cause too
-    //                       many buffers to be acquired.
+    // * BAD_VALUE - outSlot or buffer were NULL, or the generation number of the buffer did not
+    //               match the BufferQueue.
+    // * INVALID_OPERATION - cannot attach the buffer because it would cause too many buffers
+    //                       to be acquired.
     // * NO_MEMORY - no free slots available
-    virtual status_t attachBuffer(int *outSlot,
-            const sp<GraphicBuffer>& buffer) = 0;
+    virtual status_t attachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer) = 0;
 
-    // releaseBuffer releases a buffer slot from the consumer back to the
-    // BufferQueue.  This may be done while the buffer's contents are still
-    // being accessed.  The fence will signal when the buffer is no longer
-    // in use. frameNumber is used to indentify the exact buffer returned.
+    // releaseBuffer releases a buffer slot from the consumer back to the BufferQueue. This may be
+    // done while the buffer's contents are still being accessed. The fence will signal when the
+    // buffer is no longer in use. frameNumber is used to identify the exact buffer returned.
     //
-    // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free
-    // any references to the just-released buffer that it might have, as if it
-    // had received a onBuffersReleased() call with a mask set for the released
-    // buffer.
+    // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free any references to the
+    // just-released buffer that it might have, as if it had received a onBuffersReleased() call
+    // with a mask set for the released buffer.
     //
-    // Note that the dependencies on EGL will be removed once we switch to using
-    // the Android HW Sync HAL.
+    // Note that the dependencies on EGL will be removed once we switch to using the Android HW
+    // Sync HAL.
     //
     // Return of NO_ERROR means the operation completed as normal.
     //
-    // Return of a positive value means the operation could not be completed
-    //    at this time, but the user should try again later:
+    // Return of a positive value means the operation could not be completed at this time, but the
+    // user should try again later:
     // * STALE_BUFFER_SLOT - see above (second paragraph)
     //
     // Return of a negative value means an error has occurred:
@@ -143,159 +130,165 @@
     //               * the buffer slot was invalid
     //               * the fence was NULL
     //               * the buffer slot specified is not in the acquired state
-    virtual status_t releaseBuffer(int buf, uint64_t frameNumber,
-            EGLDisplay display, EGLSyncKHR fence,
-            const sp<Fence>& releaseFence) = 0;
+    virtual status_t releaseBuffer(int buf, uint64_t frameNumber, EGLDisplay display,
+                                   EGLSyncKHR fence, const sp<Fence>& releaseFence) = 0;
 
-    // consumerConnect connects a consumer to the BufferQueue.  Only one
-    // consumer may be connected, and when that consumer disconnects the
-    // BufferQueue is placed into the "abandoned" state, causing most
-    // interactions with the BufferQueue by the producer to fail.
-    // controlledByApp indicates whether the consumer is controlled by
-    // the application.
+    status_t releaseHelper(int buf, uint64_t frameNumber, const sp<Fence>& releaseFence) {
+        return releaseBuffer(buf, frameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, releaseFence);
+    }
+    // This is explicitly *not* the actual signature of IGBC::releaseBuffer, but:
+    //     1) We have no easy way to send the EGL objects across Binder
+    //     2) This has always been broken, probably because
+    //     3) IGBC is rarely remoted
+    // For now, we will choose to bury our heads in the sand and ignore this problem until such time
+    // as we can finally finish converting away from EGL sync to native Android sync
+    using ReleaseBuffer = decltype(&IGraphicBufferConsumer::releaseHelper);
+
+    // consumerConnect connects a consumer to the BufferQueue. Only one consumer may be connected,
+    // and when that consumer disconnects the BufferQueue is placed into the "abandoned" state,
+    // causing most interactions with the BufferQueue by the producer to fail. controlledByApp
+    // indicates whether the consumer is controlled by the application.
     //
     // consumer may not be NULL.
     //
     // Return of a value other than NO_ERROR means an error has occurred:
-    // * NO_INIT - the buffer queue has been abandoned
+    // * NO_INIT - the BufferQueue has been abandoned
     // * BAD_VALUE - a NULL consumer was provided
-    virtual status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) = 0;
+    virtual status_t consumerConnect(const sp<IConsumerListener>& consumer,
+                                     bool controlledByApp) = 0;
 
-    // consumerDisconnect disconnects a consumer from the BufferQueue. All
-    // buffers will be freed and the BufferQueue is placed in the "abandoned"
-    // state, causing most interactions with the BufferQueue by the producer to
-    // fail.
+    // consumerDisconnect disconnects a consumer from the BufferQueue. All buffers will be freed and
+    // the BufferQueue is placed in the "abandoned" state, causing most interactions with the
+    // BufferQueue by the producer to fail.
     //
     // Return of a value other than NO_ERROR means an error has occurred:
     // * BAD_VALUE - no consumer is currently connected
     virtual status_t consumerDisconnect() = 0;
 
-    // getReleasedBuffers sets the value pointed to by slotMask to a bit set.
-    // Each bit index with a 1 corresponds to a released buffer slot with that
-    // index value.  In particular, a released buffer is one that has
-    // been released by the BufferQueue but have not yet been released by the consumer.
+    // getReleasedBuffers sets the value pointed to by slotMask to a bit set. Each bit index with a
+    // 1 corresponds to a released buffer slot with that index value. In particular, a released
+    // buffer is one that has been released by the BufferQueue but has not yet been released by
+    // the consumer.
     //
     // This should be called from the onBuffersReleased() callback.
     //
     // Return of a value other than NO_ERROR means an error has occurred:
-    // * NO_INIT - the buffer queue has been abandoned.
+    // * NO_INIT - the BufferQueue has been abandoned.
     virtual status_t getReleasedBuffers(uint64_t* slotMask) = 0;
 
-    // setDefaultBufferSize is used to set the size of buffers returned by
-    // dequeueBuffer when a width and height of zero is requested.  Default
-    // is 1x1.
+    // setDefaultBufferSize is used to set the size of buffers returned by dequeueBuffer when a
+    // width and height of zero is requested. Default is 1x1.
     //
     // Return of a value other than NO_ERROR means an error has occurred:
     // * BAD_VALUE - either w or h was zero
     virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) = 0;
 
-    // setMaxBufferCount sets the maximum value for the number of buffers used
-    // in the buffer queue (the initial default is NUM_BUFFER_SLOTS). If a call
-    // to setMaxAcquiredBufferCount (by the consumer), or a call to setAsyncMode
-    // or setMaxDequeuedBufferCount (by the producer), would cause this value to
-    // be exceeded then that call will fail. This call will fail if a producer
+    // setMaxBufferCount sets the maximum value for the number of buffers used in the BufferQueue
+    // (the initial default is NUM_BUFFER_SLOTS). If a call to setMaxAcquiredBufferCount (by the
+    // consumer), or a call to setAsyncMode or setMaxDequeuedBufferCount (by the producer), would
+    // cause this value to be exceeded then that call will fail. This call will fail if a producer
     // is connected to the BufferQueue.
     //
-    // The count must be between 1 and NUM_BUFFER_SLOTS, inclusive. The count
-    // cannot be less than maxAcquiredBufferCount.
+    // The count must be between 1 and NUM_BUFFER_SLOTS, inclusive. The count cannot be less than
+    // maxAcquiredBufferCount.
     //
     // Return of a value other than NO_ERROR means an error has occurred:
     // * BAD_VALUE - one of the below conditions occurred:
-    //             * bufferCount was out of range (see above).
-    //             * failure to adjust the number of available slots.
+    //               * bufferCount was out of range (see above).
+    //               * failure to adjust the number of available slots.
     // * INVALID_OPERATION - attempting to call this after a producer connected.
     virtual status_t setMaxBufferCount(int bufferCount) = 0;
 
-    // setMaxAcquiredBufferCount sets the maximum number of buffers that can
-    // be acquired by the consumer at one time (default 1). If this method
-    // succeeds, any new buffer slots will be both unallocated and owned by the
-    // BufferQueue object (i.e. they are not owned by the producer or consumer).
-    // Calling this may also cause some buffer slots to be emptied.
+    // setMaxAcquiredBufferCount sets the maximum number of buffers that can be acquired by the
+    // consumer at one time (default 1). If this method succeeds, any new buffer slots will be both
+    // unallocated and owned by the BufferQueue object (i.e. they are not owned by the producer or
+    // consumer). Calling this may also cause some buffer slots to be emptied.
     //
-    // This function should not be called with a value of maxAcquiredBuffers
-    // that is less than the number of currently acquired buffer slots. Doing so
-    // will result in a BAD_VALUE error.
+    // This function should not be called with a value of maxAcquiredBuffers that is less than the
+    // number of currently acquired buffer slots. Doing so will result in a BAD_VALUE error.
     //
-    // maxAcquiredBuffers must be (inclusive) between 1 and
-    // MAX_MAX_ACQUIRED_BUFFERS. It also cannot cause the maxBufferCount value
-    // to be exceeded.
+    // maxAcquiredBuffers must be (inclusive) between 1 and MAX_MAX_ACQUIRED_BUFFERS. It also cannot
+    // cause the maxBufferCount value to be exceeded.
     //
     // Return of a value other than NO_ERROR means an error has occurred:
-    // * NO_INIT - the buffer queue has been abandoned
+    // * NO_INIT - the BufferQueue has been abandoned
     // * BAD_VALUE - one of the below conditions occurred:
-    //             * maxAcquiredBuffers was out of range (see above).
-    //             * failure to adjust the number of available slots.
-    //             * client would have more than the requested number of
-    //               acquired buffers after this call
+    //               * maxAcquiredBuffers was out of range (see above).
+    //               * failure to adjust the number of available slots.
+    //               * client would have more than the requested number of acquired buffers after
+    //                 this call
     // * INVALID_OPERATION - attempting to call this after a producer connected.
     virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) = 0;
 
     // setConsumerName sets the name used in logging
-    virtual void setConsumerName(const String8& name) = 0;
+    virtual status_t setConsumerName(const String8& name) = 0;
 
-    // setDefaultBufferFormat allows the BufferQueue to create
-    // GraphicBuffers of a defaultFormat if no format is specified
-    // in dequeueBuffer.
-    // The initial default is PIXEL_FORMAT_RGBA_8888.
+    // setDefaultBufferFormat allows the BufferQueue to create GraphicBuffers of a defaultFormat if
+    // no format is specified in dequeueBuffer. The initial default is PIXEL_FORMAT_RGBA_8888.
     //
     // Return of a value other than NO_ERROR means an unknown error has occurred.
     virtual status_t setDefaultBufferFormat(PixelFormat defaultFormat) = 0;
 
-    // setDefaultBufferDataSpace is a request to the producer to provide buffers
-    // of the indicated dataSpace. The producer may ignore this request.
-    // The initial default is HAL_DATASPACE_UNKNOWN.
+    // setDefaultBufferDataSpace is a request to the producer to provide buffers of the indicated
+    // dataSpace. The producer may ignore this request. The initial default is
+    // HAL_DATASPACE_UNKNOWN.
     //
     // Return of a value other than NO_ERROR means an unknown error has occurred.
-    virtual status_t setDefaultBufferDataSpace(
-            android_dataspace defaultDataSpace) = 0;
+    virtual status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace) = 0;
 
-    // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer.
-    // These are merged with the bits passed to dequeueBuffer.  The values are
-    // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0.
+    // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer. These are merged
+    // with the bits passed to dequeueBuffer. The values are enumerated in gralloc.h,
+    // e.g. GRALLOC_USAGE_HW_RENDER; the default is 0.
     //
     // Return of a value other than NO_ERROR means an unknown error has occurred.
     virtual status_t setConsumerUsageBits(uint32_t usage) = 0;
 
-    // setTransformHint bakes in rotation to buffers so overlays can be used.
-    // The values are enumerated in window.h, e.g.
-    // NATIVE_WINDOW_TRANSFORM_ROT_90.  The default is 0 (no transform).
+    // setConsumerIsProtected will turn on an internal bit that indicates whether
+    // the consumer can handle protected gralloc buffers (i.e. with
+    // GRALLOC_USAGE_PROTECTED set). IGraphicBufferProducer can query this
+    // capability using NATIVE_WINDOW_CONSUMER_IS_PROTECTED.
+    virtual status_t setConsumerIsProtected(bool isProtected) = 0;
+
+    // setTransformHint bakes in rotation to buffers so overlays can be used. The values are
+    // enumerated in window.h, e.g. NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0
+    // (no transform).
     //
     // Return of a value other than NO_ERROR means an unknown error has occurred.
     virtual status_t setTransformHint(uint32_t hint) = 0;
 
     // Retrieve the sideband buffer stream, if any.
-    virtual sp<NativeHandle> getSidebandStream() const = 0;
+    virtual status_t getSidebandStream(sp<NativeHandle>* outStream) const = 0;
 
-    // Retrieves any stored segments of the occupancy history of this
-    // BufferQueue and clears them. Optionally closes out the pending segment if
-    // forceFlush is true.
+    // Retrieves any stored segments of the occupancy history of this BufferQueue and clears them.
+    // Optionally closes out the pending segment if forceFlush is true.
     virtual status_t getOccupancyHistory(bool forceFlush,
-            std::vector<OccupancyTracker::Segment>* outHistory) = 0;
+                                         std::vector<OccupancyTracker::Segment>* outHistory) = 0;
 
-    // discardFreeBuffers releases all currently-free buffers held by the queue,
-    // in order to reduce the memory consumption of the queue to the minimum
-    // possible without discarding data.
+    // discardFreeBuffers releases all currently-free buffers held by the BufferQueue, in order to
+    // reduce the memory consumption of the BufferQueue to the minimum possible without
+    // discarding data.
+    // The consumer invoking this method is responsible for calling getReleasedBuffers() after this
+    // call to free up any of its locally cached buffers.
     virtual status_t discardFreeBuffers() = 0;
 
     // dump state into a string
-    virtual void dump(String8& result, const char* prefix) const = 0;
+    virtual status_t dumpState(const String8& prefix, String8* outResult) const = 0;
 
-public:
-    DECLARE_META_INTERFACE(GraphicBufferConsumer);
+    // Provide backwards source compatibility
+    void dumpState(String8& result, const char* prefix) {
+        String8 returned;
+        dumpState(String8(prefix), &returned);
+        result.append(returned);
+    }
 };
 
-// ----------------------------------------------------------------------------
-
-class BnGraphicBufferConsumer : public BnInterface<IGraphicBufferConsumer>
-{
+class BnGraphicBufferConsumer : public SafeBnInterface<IGraphicBufferConsumer> {
 public:
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
+    BnGraphicBufferConsumer()
+          : SafeBnInterface<IGraphicBufferConsumer>("BnGraphicBufferConsumer") {}
+
+    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                        uint32_t flags = 0) override;
 };
 
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_GUI_IGRAPHICBUFFERCONSUMER_H
+} // namespace android
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index bf427fe..9250806 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -32,12 +32,17 @@
 
 #include <gui/FrameTimestamps.h>
 
+#include <hidl/HybridInterface.h>
+#include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
+
 namespace android {
 // ----------------------------------------------------------------------------
 
 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
@@ -56,7 +61,7 @@
 class IGraphicBufferProducer : public IInterface
 {
 public:
-    DECLARE_META_INTERFACE(GraphicBufferProducer);
+    DECLARE_HYBRID_META_INTERFACE(GraphicBufferProducer, HGraphicBufferProducer)
 
     enum {
         // A flag returned by dequeueBuffer when the client needs to call
@@ -190,7 +195,8 @@
     // All other negative values are an unknown error returned downstream
     // from the graphics allocator (typically errno).
     virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w,
-            uint32_t h, PixelFormat format, uint32_t usage) = 0;
+            uint32_t h, PixelFormat format, uint32_t usage,
+            FrameEventHistoryDelta* outTimestamps) = 0;
 
     // detachBuffer attempts to remove all ownership of the buffer in the given
     // slot from the buffer queue. If this call succeeds, the slot will be
@@ -294,7 +300,8 @@
 
     struct QueueBufferInput : public Flattenable<QueueBufferInput> {
         friend class Flattenable<QueueBufferInput>;
-        inline QueueBufferInput(const Parcel& parcel);
+        explicit inline QueueBufferInput(const Parcel& parcel);
+
         // timestamp - a monotonically increasing value in nanoseconds
         // isAutoTimestamp - if the timestamp was synthesized at queue time
         // dataSpace - description of the contents, interpretation depends on format
@@ -305,18 +312,23 @@
         //         set this to Fence::NO_FENCE if the buffer is ready immediately
         // sticky - the sticky transform set in Surface (only used by the LEGACY
         //          camera mode).
-        inline QueueBufferInput(int64_t timestamp, bool isAutoTimestamp,
-                android_dataspace dataSpace, const Rect& crop, int scalingMode,
-                uint32_t transform, const sp<Fence>& fence, uint32_t sticky = 0)
-                : timestamp(timestamp), isAutoTimestamp(isAutoTimestamp),
-                  dataSpace(dataSpace), crop(crop), scalingMode(scalingMode),
-                  transform(transform), stickyTransform(sticky), fence(fence),
-                  surfaceDamage() { }
+        // getFrameTimestamps - whether or not the latest frame timestamps
+        //                      should be retrieved from the consumer.
+        inline QueueBufferInput(int64_t _timestamp, bool _isAutoTimestamp,
+                android_dataspace _dataSpace, const Rect& _crop,
+                int _scalingMode, uint32_t _transform, const sp<Fence>& _fence,
+                uint32_t _sticky = 0, bool _getFrameTimestamps = false)
+                : timestamp(_timestamp), isAutoTimestamp(_isAutoTimestamp),
+                  dataSpace(_dataSpace), crop(_crop), scalingMode(_scalingMode),
+                  transform(_transform), stickyTransform(_sticky), fence(_fence),
+                  surfaceDamage(), getFrameTimestamps(_getFrameTimestamps) { }
+
         inline void deflate(int64_t* outTimestamp, bool* outIsAutoTimestamp,
                 android_dataspace* outDataSpace,
                 Rect* outCrop, int* outScalingMode,
                 uint32_t* outTransform, sp<Fence>* outFence,
-                uint32_t* outStickyTransform = NULL) const {
+                uint32_t* outStickyTransform = nullptr,
+                bool* outGetFrameTimestamps = nullptr) const {
             *outTimestamp = timestamp;
             *outIsAutoTimestamp = bool(isAutoTimestamp);
             *outDataSpace = dataSpace;
@@ -327,9 +339,13 @@
             if (outStickyTransform != NULL) {
                 *outStickyTransform = stickyTransform;
             }
+            if (outGetFrameTimestamps) {
+                *outGetFrameTimestamps = getFrameTimestamps;
+            }
         }
 
         // Flattenable protocol
+        static constexpr size_t minFlattenedSize();
         size_t getFlattenedSize() const;
         size_t getFdCount() const;
         status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const;
@@ -339,51 +355,42 @@
         void setSurfaceDamage(const Region& damage) { surfaceDamage = damage; }
 
     private:
-        int64_t timestamp;
-        int isAutoTimestamp;
-        android_dataspace dataSpace;
+        int64_t timestamp{0};
+        int isAutoTimestamp{0};
+        android_dataspace dataSpace{HAL_DATASPACE_UNKNOWN};
         Rect crop;
-        int scalingMode;
-        uint32_t transform;
-        uint32_t stickyTransform;
+        int scalingMode{0};
+        uint32_t transform{0};
+        uint32_t stickyTransform{0};
         sp<Fence> fence;
         Region surfaceDamage;
+        bool getFrameTimestamps{false};
     };
 
-    // QueueBufferOutput must be a POD structure
-    struct __attribute__ ((__packed__)) QueueBufferOutput {
-        inline QueueBufferOutput() { }
-        // outWidth - filled with default width applied to the buffer
-        // outHeight - filled with default height applied to the buffer
-        // outTransformHint - filled with default transform applied to the buffer
-        // outNumPendingBuffers - num buffers queued that haven't yet been acquired
-        //                        (counting the currently queued buffer)
-        inline void deflate(uint32_t* outWidth,
-                uint32_t* outHeight,
-                uint32_t* outTransformHint,
-                uint32_t* outNumPendingBuffers,
-                uint64_t* outNextFrameNumber) const {
-            *outWidth = width;
-            *outHeight = height;
-            *outTransformHint = transformHint;
-            *outNumPendingBuffers = numPendingBuffers;
-            *outNextFrameNumber = nextFrameNumber;
-        }
-        inline void inflate(uint32_t inWidth, uint32_t inHeight,
-                uint32_t inTransformHint, uint32_t inNumPendingBuffers,
-                uint64_t inNextFrameNumber) {
-            width = inWidth;
-            height = inHeight;
-            transformHint = inTransformHint;
-            numPendingBuffers = inNumPendingBuffers;
-            nextFrameNumber = inNextFrameNumber;
-        }
-    private:
-        uint32_t width;
-        uint32_t height;
-        uint32_t transformHint;
-        uint32_t numPendingBuffers;
+    struct QueueBufferOutput : public Flattenable<QueueBufferOutput> {
+        QueueBufferOutput() = default;
+
+        // Moveable.
+        QueueBufferOutput(QueueBufferOutput&& src) = default;
+        QueueBufferOutput& operator=(QueueBufferOutput&& src) = default;
+        // Not copyable.
+        QueueBufferOutput(const QueueBufferOutput& src) = delete;
+        QueueBufferOutput& operator=(const QueueBufferOutput& src) = delete;
+
+        // Flattenable protocol
+        static constexpr size_t minFlattenedSize();
+        size_t getFlattenedSize() const;
+        size_t getFdCount() const;
+        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);
+
+        uint32_t width{0};
+        uint32_t height{0};
+        uint32_t transformHint{0};
+        uint32_t numPendingBuffers{0};
         uint64_t nextFrameNumber{0};
+        FrameEventHistoryDelta frameTimestamps;
+        bool bufferReplaced{false};
     };
 
     virtual status_t queueBuffer(int slot, const QueueBufferInput& input,
@@ -480,6 +487,7 @@
     // is considered a no-op.
     //
     // Return of a value other than NO_ERROR means an error has occurred:
+    // * NO_INIT - the producer is not connected
     // * BAD_VALUE - one of the following has occurred:
     //             * the api specified does not match the one that was connected
     //             * api was out of range (see above).
@@ -580,13 +588,8 @@
     virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence, float outTransformMatrix[16]) = 0;
 
-    // Attempts to retrieve timestamp information for the given frame number.
-    // If information for the given frame number is not found, returns false.
-    // Returns true otherwise.
-    //
-    // If a fence has not yet signaled the timestamp returned will be 0;
-    virtual bool getFrameTimestamps(uint64_t /*frameNumber*/,
-            FrameTimestamps* /*outTimestamps*/) const { return false; }
+    // Gets the frame events that haven't already been retrieved.
+    virtual void getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) {}
 
     // Returns a unique id for this BufferQueue
     virtual status_t getUniqueId(uint64_t* outId) const = 0;
diff --git a/include/gui/IProducerListener.h b/include/gui/IProducerListener.h
index b7826c6..e808bd3 100644
--- a/include/gui/IProducerListener.h
+++ b/include/gui/IProducerListener.h
@@ -33,7 +33,7 @@
 {
 public:
     ProducerListener() {}
-    virtual ~ProducerListener() {}
+    virtual ~ProducerListener();
 
     // onBufferReleased is called from IGraphicBufferConsumer::releaseBuffer to
     // notify the producer that a new buffer is free and ready to be dequeued.
@@ -61,6 +61,7 @@
 class DummyProducerListener : public BnProducerListener
 {
 public:
+    virtual ~DummyProducerListener();
     virtual void onBufferReleased() {}
     virtual bool needsReleaseNotify() { return false; }
 };
diff --git a/include/gui/ISensorEventConnection.h b/include/gui/ISensorEventConnection.h
deleted file mode 100644
index f64c6b8..0000000
--- a/include/gui/ISensorEventConnection.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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_GUI_ISENSOR_EVENT_CONNECTION_H
-#define ANDROID_GUI_ISENSOR_EVENT_CONNECTION_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-
-#include <binder/IInterface.h>
-
-namespace android {
-// ----------------------------------------------------------------------------
-
-class BitTube;
-
-class ISensorEventConnection : public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(SensorEventConnection);
-
-    virtual sp<BitTube> getSensorChannel() const = 0;
-    virtual status_t enableDisable(int handle, bool enabled, nsecs_t samplingPeriodNs,
-                                   nsecs_t maxBatchReportLatencyNs, int reservedFlags) = 0;
-    virtual status_t setEventRate(int handle, nsecs_t ns) = 0;
-    virtual status_t flush() = 0;
-};
-
-// ----------------------------------------------------------------------------
-
-class BnSensorEventConnection : public BnInterface<ISensorEventConnection>
-{
-public:
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_GUI_ISENSOR_EVENT_CONNECTION_H
diff --git a/include/gui/ISensorServer.h b/include/gui/ISensorServer.h
deleted file mode 100644
index 571acb5..0000000
--- a/include/gui/ISensorServer.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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_GUI_ISENSORSERVER_H
-#define ANDROID_GUI_ISENSORSERVER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-
-#include <binder/IInterface.h>
-
-namespace android {
-// ----------------------------------------------------------------------------
-
-class Sensor;
-class ISensorEventConnection;
-class String8;
-
-class ISensorServer : public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(SensorServer);
-
-    virtual Vector<Sensor> getSensorList(const String16& opPackageName) = 0;
-    virtual Vector<Sensor> getDynamicSensorList(const String16& opPackageName) = 0;
-
-    virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName,
-             int mode, const String16& opPackageName) = 0;
-    virtual int32_t isDataInjectionEnabled() = 0;
-};
-
-// ----------------------------------------------------------------------------
-
-class BnSensorServer : public BnInterface<ISensorServer>
-{
-public:
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_GUI_ISENSORSERVER_H
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index 74a4123..f80ba00 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -28,21 +28,23 @@
 #include <binder/IInterface.h>
 
 #include <ui/FrameStats.h>
+#include <ui/PixelFormat.h>
 
-#include <gui/IGraphicBufferAlloc.h>
-#include <gui/ISurfaceComposerClient.h>
+#include <vector>
 
 namespace android {
 // ----------------------------------------------------------------------------
 
-class ComposerState;
-class DisplayState;
+struct ComposerState;
+struct DisplayState;
 struct DisplayInfo;
 struct DisplayStatInfo;
 class HdrCapabilities;
 class IDisplayEventConnection;
-class IMemoryHeap;
+class IGraphicBufferProducer;
+class ISurfaceComposerClient;
 class Rect;
+enum class FrameEvent;
 
 /*
  * This class defines the Binder IPC interface for accessing various
@@ -50,7 +52,7 @@
  */
 class ISurfaceComposer: public IInterface {
 public:
-    DECLARE_META_INTERFACE(SurfaceComposer);
+    DECLARE_META_INTERFACE(SurfaceComposer)
 
     // flags for setTransactionState()
     enum {
@@ -70,17 +72,30 @@
         eRotate270  = 3
     };
 
+    enum VsyncSource {
+        eVsyncSourceApp = 0,
+        eVsyncSourceSurfaceFlinger = 1
+    };
+
     /* create connection with surface flinger, requires
      * ACCESS_SURFACE_FLINGER permission
      */
     virtual sp<ISurfaceComposerClient> createConnection() = 0;
 
-    /* create a graphic buffer allocator
+    /** 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<IGraphicBufferAlloc> createGraphicBufferAlloc() = 0;
+    virtual sp<ISurfaceComposerClient> createScopedConnection(
+            const sp<IGraphicBufferProducer>& parent) = 0;
 
     /* return an IDisplayEventConnection */
-    virtual sp<IDisplayEventConnection> createDisplayEventConnection() = 0;
+    virtual sp<IDisplayEventConnection> createDisplayEventConnection(
+            VsyncSource vsyncSource = eVsyncSourceApp) = 0;
 
     /* create a virtual display
      * requires ACCESS_SURFACE_FLINGER permission.
@@ -112,6 +127,11 @@
     virtual bool authenticateSurfaceTexture(
             const sp<IGraphicBufferProducer>& surface) const = 0;
 
+    /* Returns the frame timestamps supported by SurfaceFlinger.
+     */
+    virtual status_t getSupportedFrameTimestamps(
+            std::vector<FrameEvent>* outSupported) const = 0;
+
     /* set display power mode. depending on the mode, it can either trigger
      * screen on, off or low power mode and wait for it to complete.
      * requires ACCESS_SURFACE_FLINGER permission.
@@ -149,7 +169,7 @@
     virtual status_t captureScreen(const sp<IBinder>& display,
             const sp<IGraphicBufferProducer>& producer,
             Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            uint32_t minLayerZ, uint32_t maxLayerZ,
+            int32_t minLayerZ, int32_t maxLayerZ,
             bool useIdentityTransform,
             Rotation rotation = eRotateNone) = 0;
 
@@ -171,6 +191,10 @@
      */
     virtual status_t getHdrCapabilities(const sp<IBinder>& display,
             HdrCapabilities* outCapabilities) const = 0;
+
+    virtual status_t enableVSyncInjections(bool enable) = 0;
+
+    virtual status_t injectVSync(nsecs_t when) = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -182,13 +206,14 @@
         // Java by ActivityManagerService.
         BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
         CREATE_CONNECTION,
-        CREATE_GRAPHIC_BUFFER_ALLOC,
+        UNUSED, // formerly CREATE_GRAPHIC_BUFFER_ALLOC
         CREATE_DISPLAY_EVENT_CONNECTION,
         CREATE_DISPLAY,
         DESTROY_DISPLAY,
         GET_BUILT_IN_DISPLAY,
         SET_TRANSACTION_STATE,
         AUTHENTICATE_SURFACE,
+        GET_SUPPORTED_FRAME_TIMESTAMPS,
         GET_DISPLAY_CONFIGS,
         GET_ACTIVE_CONFIG,
         SET_ACTIVE_CONFIG,
@@ -202,6 +227,9 @@
         GET_DISPLAY_COLOR_MODES,
         GET_ACTIVE_COLOR_MODE,
         SET_ACTIVE_COLOR_MODE,
+        ENABLE_VSYNC_INJECTIONS,
+        INJECT_VSYNC,
+        CREATE_SCOPED_CONNECTION
     };
 
     virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/include/gui/ISurfaceComposerClient.h b/include/gui/ISurfaceComposerClient.h
index c27a741..2c613ea 100644
--- a/include/gui/ISurfaceComposerClient.h
+++ b/include/gui/ISurfaceComposerClient.h
@@ -14,54 +14,44 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_GUI_ISURFACE_COMPOSER_CLIENT_H
-#define ANDROID_GUI_ISURFACE_COMPOSER_CLIENT_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
+#pragma once
 
 #include <binder/IInterface.h>
-
-#include <ui/FrameStats.h>
+#include <binder/SafeInterface.h>
 #include <ui/PixelFormat.h>
 
 namespace android {
-// ----------------------------------------------------------------------------
 
+class FrameStats;
 class IGraphicBufferProducer;
 
-class ISurfaceComposerClient : public IInterface
-{
+class ISurfaceComposerClient : public IInterface {
 public:
-    DECLARE_META_INTERFACE(SurfaceComposerClient);
+    DECLARE_META_INTERFACE(SurfaceComposerClient)
 
     // flags for createSurface()
     enum { // (keep in sync with Surface.java)
-        eHidden             = 0x00000004,
-        eDestroyBackbuffer  = 0x00000020,
-        eSecure             = 0x00000080,
-        eNonPremultiplied   = 0x00000100,
-        eOpaque             = 0x00000400,
-        eProtectedByApp     = 0x00000800,
-        eProtectedByDRM     = 0x00001000,
-        eCursorWindow       = 0x00002000,
+        eHidden = 0x00000004,
+        eDestroyBackbuffer = 0x00000020,
+        eSecure = 0x00000080,
+        eNonPremultiplied = 0x00000100,
+        eOpaque = 0x00000400,
+        eProtectedByApp = 0x00000800,
+        eProtectedByDRM = 0x00001000,
+        eCursorWindow = 0x00002000,
 
-        eFXSurfaceNormal    = 0x00000000,
-        eFXSurfaceDim       = 0x00020000,
-        eFXSurfaceMask      = 0x000F0000,
+        eFXSurfaceNormal = 0x00000000,
+        eFXSurfaceDim = 0x00020000,
+        eFXSurfaceMask = 0x000F0000,
     };
 
     /*
      * Requires ACCESS_SURFACE_FLINGER permission
      */
-    virtual status_t createSurface(
-            const String8& name, uint32_t w, uint32_t h,
-            PixelFormat format, uint32_t flags,
-            sp<IBinder>* handle,
-            sp<IGraphicBufferProducer>* gbp) = 0;
+    virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format,
+                                   uint32_t flags, const sp<IBinder>& parent, uint32_t windowType,
+                                   uint32_t ownerUid, sp<IBinder>* handle,
+                                   sp<IGraphicBufferProducer>* gbp) = 0;
 
     /*
      * Requires ACCESS_SURFACE_FLINGER permission
@@ -77,21 +67,14 @@
      * Requires ACCESS_SURFACE_FLINGER permission
      */
     virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const = 0;
-
-    virtual status_t getTransformToDisplayInverse(const sp<IBinder>& handle,
-            bool* outTransformToDisplayInverse) const = 0;
 };
 
-// ----------------------------------------------------------------------------
-
-class BnSurfaceComposerClient: public BnInterface<ISurfaceComposerClient> {
+class BnSurfaceComposerClient : public SafeBnInterface<ISurfaceComposerClient> {
 public:
-    virtual status_t onTransact(uint32_t code, const Parcel& data,
-            Parcel* reply, uint32_t flags = 0);
+    BnSurfaceComposerClient()
+          : SafeBnInterface<ISurfaceComposerClient>("BnSurfaceComposerClient") {}
+
+    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override;
 };
 
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_GUI_ISURFACE_COMPOSER_CLIENT_H
+} // namespace android
diff --git a/include/gui/OccupancyTracker.h b/include/gui/OccupancyTracker.h
index 1d15e7f..d4de8f2 100644
--- a/include/gui/OccupancyTracker.h
+++ b/include/gui/OccupancyTracker.h
@@ -45,12 +45,12 @@
             occupancyAverage(0.0f),
             usedThirdBuffer(false) {}
 
-        Segment(nsecs_t totalTime, size_t numFrames, float occupancyAverage,
-                bool usedThirdBuffer)
-          : totalTime(totalTime),
-            numFrames(numFrames),
-            occupancyAverage(occupancyAverage),
-            usedThirdBuffer(usedThirdBuffer) {}
+        Segment(nsecs_t _totalTime, size_t _numFrames, float _occupancyAverage,
+                bool _usedThirdBuffer)
+          : totalTime(_totalTime),
+            numFrames(_numFrames),
+            occupancyAverage(_occupancyAverage),
+            usedThirdBuffer(_usedThirdBuffer) {}
 
         // Parcelable interface
         virtual status_t writeToParcel(Parcel* parcel) const override;
diff --git a/include/gui/Sensor.h b/include/gui/Sensor.h
deleted file mode 100644
index 094fd16..0000000
--- a/include/gui/Sensor.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * 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_GUI_SENSOR_H
-#define ANDROID_GUI_SENSOR_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/Flattenable.h>
-#include <utils/String8.h>
-#include <utils/Timers.h>
-
-#include <hardware/sensors.h>
-
-#include <android/sensor.h>
-
-// ----------------------------------------------------------------------------
-// Concrete types for the NDK
-struct ASensor { };
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-class Parcel;
-
-// ----------------------------------------------------------------------------
-
-class Sensor : public ASensor, public LightFlattenable<Sensor>
-{
-public:
-    enum {
-        TYPE_ACCELEROMETER  = ASENSOR_TYPE_ACCELEROMETER,
-        TYPE_MAGNETIC_FIELD = ASENSOR_TYPE_MAGNETIC_FIELD,
-        TYPE_GYROSCOPE      = ASENSOR_TYPE_GYROSCOPE,
-        TYPE_LIGHT          = ASENSOR_TYPE_LIGHT,
-        TYPE_PROXIMITY      = ASENSOR_TYPE_PROXIMITY
-    };
-
-    struct uuid_t{
-        union {
-            uint8_t b[16];
-            int64_t i64[2];
-        };
-        uuid_t(const uint8_t (&uuid)[16]) { memcpy(b, uuid, sizeof(b));}
-        uuid_t() : b{0} {}
-    };
-
-    Sensor(const char * name = "");
-    Sensor(struct sensor_t const* hwSensor, int halVersion = 0);
-    Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersion = 0);
-    ~Sensor();
-
-    const String8& getName() const;
-    const String8& getVendor() const;
-    int32_t getHandle() const;
-    int32_t getType() const;
-    float getMinValue() const;
-    float getMaxValue() const;
-    float getResolution() const;
-    float getPowerUsage() const;
-    int32_t getMinDelay() const;
-    nsecs_t getMinDelayNs() const;
-    int32_t getVersion() const;
-    uint32_t getFifoReservedEventCount() const;
-    uint32_t getFifoMaxEventCount() const;
-    const String8& getStringType() const;
-    const String8& getRequiredPermission() const;
-    bool isRequiredPermissionRuntime() const;
-    int32_t getRequiredAppOp() const;
-    int32_t getMaxDelay() const;
-    uint32_t getFlags() const;
-    bool isWakeUpSensor() const;
-    bool isDynamicSensor() const;
-    bool hasAdditionalInfo() const;
-    int32_t getReportingMode() const;
-
-    // Note that after setId() has been called, getUuid() no longer
-    // returns the UUID.
-    // TODO(b/29547335): Remove getUuid(), add getUuidIndex(), and
-    //     make sure setId() doesn't change the UuidIndex.
-    const uuid_t& getUuid() const;
-    int32_t getId() const;
-    void setId(int32_t id);
-
-    // LightFlattenable protocol
-    inline bool isFixedSize() const { return false; }
-    size_t getFlattenedSize() const;
-    status_t flatten(void* buffer, size_t size) const;
-    status_t unflatten(void const* buffer, size_t size);
-
-private:
-    String8 mName;
-    String8 mVendor;
-    int32_t mHandle;
-    int32_t mType;
-    float   mMinValue;
-    float   mMaxValue;
-    float   mResolution;
-    float   mPower;
-    int32_t mMinDelay;
-    int32_t mVersion;
-    uint32_t mFifoReservedEventCount;
-    uint32_t mFifoMaxEventCount;
-    String8 mStringType;
-    String8 mRequiredPermission;
-    bool mRequiredPermissionRuntime = false;
-    int32_t mRequiredAppOp;
-    int32_t mMaxDelay;
-    uint32_t mFlags;
-    // TODO(b/29547335): Get rid of this field and replace with an index.
-    //     The index will be into a separate global vector of UUIDs.
-    //     Also add an mId field (and change flatten/unflatten appropriately).
-    uuid_t  mUuid;
-    static void flattenString8(void*& buffer, size_t& size, const String8& string8);
-    static bool unflattenString8(void const*& buffer, size_t& size, String8& outputString8);
-};
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_GUI_SENSOR_H
diff --git a/include/gui/SensorEventQueue.h b/include/gui/SensorEventQueue.h
deleted file mode 100644
index 4ee7c02..0000000
--- a/include/gui/SensorEventQueue.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * 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_SENSOR_EVENT_QUEUE_H
-#define ANDROID_SENSOR_EVENT_QUEUE_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/Timers.h>
-#include <utils/String16.h>
-
-#include <gui/BitTube.h>
-
-// ----------------------------------------------------------------------------
-#define WAKE_UP_SENSOR_EVENT_NEEDS_ACK (1U << 31)
-struct ALooper;
-struct ASensorEvent;
-
-// Concrete types for the NDK
-struct ASensorEventQueue {
-    ALooper* looper;
-};
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-class ISensorEventConnection;
-class Sensor;
-class Looper;
-
-// ----------------------------------------------------------------------------
-
-class SensorEventQueue : public ASensorEventQueue, public RefBase
-{
-public:
-
-    enum { MAX_RECEIVE_BUFFER_EVENT_COUNT = 256 };
-
-    /**
-     * Typical sensor delay (sample period) in microseconds.
-     */
-    // Fastest sampling, system will bound it to minDelay
-    static constexpr int32_t SENSOR_DELAY_FASTEST = 0;
-    // Typical sample period for game, 50Hz;
-    static constexpr int32_t SENSOR_DELAY_GAME = 20000;
-    // Typical sample period for UI, 15Hz
-    static constexpr int32_t SENSOR_DELAY_UI = 66667;
-    // Default sensor sample period
-    static constexpr int32_t SENSOR_DELAY_NORMAL = 200000;
-
-    SensorEventQueue(const sp<ISensorEventConnection>& connection);
-    virtual ~SensorEventQueue();
-    virtual void onFirstRef();
-
-    int getFd() const;
-
-    static ssize_t write(const sp<BitTube>& tube,
-            ASensorEvent const* events, size_t numEvents);
-
-    ssize_t read(ASensorEvent* events, size_t numEvents);
-
-    status_t waitForEvent() const;
-    status_t wake() const;
-
-    status_t enableSensor(Sensor const* sensor) const;
-    status_t enableSensor(Sensor const* sensor, int32_t samplingPeriodUs) const;
-    status_t disableSensor(Sensor const* sensor) const;
-    status_t setEventRate(Sensor const* sensor, nsecs_t ns) const;
-
-    // these are here only to support SensorManager.java
-    status_t enableSensor(int32_t handle, int32_t samplingPeriodUs, int maxBatchReportLatencyUs,
-                          int reservedFlags) const;
-    status_t disableSensor(int32_t handle) const;
-    status_t flush() const;
-    // Send an ack for every wake_up sensor event that is set to WAKE_UP_SENSOR_EVENT_NEEDS_ACK.
-    void sendAck(const ASensorEvent* events, int count);
-
-    status_t injectSensorEvent(const ASensorEvent& event);
-private:
-    sp<Looper> getLooper() const;
-    sp<ISensorEventConnection> mSensorEventConnection;
-    sp<BitTube> mSensorChannel;
-    mutable Mutex mLock;
-    mutable sp<Looper> mLooper;
-    ASensorEvent* mRecBuffer;
-    size_t mAvailable;
-    size_t mConsumed;
-    uint32_t mNumAcksToSend;
-};
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_SENSOR_EVENT_QUEUE_H
diff --git a/include/gui/SensorManager.h b/include/gui/SensorManager.h
deleted file mode 100644
index 6c6230f..0000000
--- a/include/gui/SensorManager.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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_GUI_SENSOR_MANAGER_H
-#define ANDROID_GUI_SENSOR_MANAGER_H
-
-#include <map>
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/IBinder.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/Singleton.h>
-#include <utils/Vector.h>
-#include <utils/String8.h>
-
-#include <gui/SensorEventQueue.h>
-
-// ----------------------------------------------------------------------------
-// Concrete types for the NDK
-struct ASensorManager { };
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-class ISensorServer;
-class Sensor;
-class SensorEventQueue;
-// ----------------------------------------------------------------------------
-
-class SensorManager :
-    public ASensorManager
-{
-public:
-    static SensorManager& getInstanceForPackage(const String16& packageName);
-    ~SensorManager();
-
-    ssize_t getSensorList(Sensor const* const** list);
-    ssize_t getDynamicSensorList(Vector<Sensor>& list);
-    Sensor const* getDefaultSensor(int type);
-    sp<SensorEventQueue> createEventQueue(String8 packageName = String8(""), int mode = 0);
-    bool isDataInjectionEnabled();
-
-private:
-    // DeathRecipient interface
-    void sensorManagerDied();
-
-    SensorManager(const String16& opPackageName);
-    status_t assertStateLocked();
-
-private:
-    static Mutex sLock;
-    static std::map<String16, SensorManager*> sPackageInstances;
-
-    Mutex mLock;
-    sp<ISensorServer> mSensorServer;
-    Sensor const** mSensorList;
-    Vector<Sensor> mSensors;
-    sp<IBinder::DeathRecipient> mDeathObserver;
-    const String16 mOpPackageName;
-};
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_GUI_SENSOR_MANAGER_H
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index f4a22cb..e8dc83e 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -18,21 +18,21 @@
 #define ANDROID_GUI_SURFACE_H
 
 #include <gui/IGraphicBufferProducer.h>
-#include <gui/BufferQueue.h>
+#include <gui/BufferQueueDefs.h>
 
 #include <ui/ANativeObjectBase.h>
 #include <ui/Region.h>
 
-#include <binder/Parcelable.h>
-
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
 #include <utils/RefBase.h>
-#include <utils/threads.h>
-#include <utils/KeyedVector.h>
 
 struct ANativeWindow_Buffer;
 
 namespace android {
 
+class ISurfaceComposer;
+
 /*
  * An implementation of ANativeWindow that feeds graphics buffers into a
  * BufferQueue.
@@ -66,7 +66,8 @@
      * the controlledByApp flag indicates that this Surface (producer) is
      * controlled by the application. This flag is used at connect time.
      */
-    Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp = false);
+    explicit Surface(const sp<IGraphicBufferProducer>& bufferProducer,
+            bool controlledByApp = false);
 
     /* getIGraphicBufferProducer() returns the IGraphicBufferProducer this
      * Surface was created with. Usually it's an error to use the
@@ -134,17 +135,41 @@
     status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence, float outTransformMatrix[16]);
 
+    status_t getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration);
+
+    /* Enables or disables frame timestamp tracking. It is disabled by default
+     * to avoid overhead during queue and dequeue for applications that don't
+     * need the feature. If disabled, calls to getFrameTimestamps will fail.
+     */
+    void enableFrameTimestamps(bool enable);
+
+    status_t getCompositorTiming(
+            nsecs_t* compositeDeadline, nsecs_t* compositeInterval,
+            nsecs_t* compositeToPresentLatency);
+
     // See IGraphicBufferProducer::getFrameTimestamps
-    bool getFrameTimestamps(uint64_t frameNumber, nsecs_t* outPostedTime,
-            nsecs_t* outAcquireTime, nsecs_t* outRefreshStartTime,
-            nsecs_t* outGlCompositionDoneTime, nsecs_t* outDisplayRetireTime,
+    status_t getFrameTimestamps(uint64_t frameNumber,
+            nsecs_t* outRequestedPresentTime, nsecs_t* outAcquireTime,
+            nsecs_t* outLatchTime, nsecs_t* outFirstRefreshStartTime,
+            nsecs_t* outLastRefreshStartTime, nsecs_t* outGlCompositionDoneTime,
+            nsecs_t* outDisplayPresentTime, nsecs_t* outDequeueReadyTime,
             nsecs_t* outReleaseTime);
 
+    status_t getWideColorSupport(bool* supported);
+    status_t getHdrSupport(bool* supported);
+
     status_t getUniqueId(uint64_t* outId) const;
 
+    // Returns the CLOCK_MONOTONIC start time of the last dequeueBuffer call
+    nsecs_t getLastDequeueStartTime() const;
+
 protected:
     virtual ~Surface();
 
+    // Virtual for testing.
+    virtual sp<ISurfaceComposer> composerService() const;
+    virtual nsecs_t now() const;
+
 private:
     // can't be copied
     Surface& operator = (const Surface& rhs);
@@ -191,7 +216,13 @@
     int dispatchSetSurfaceDamage(va_list args);
     int dispatchSetSharedBufferMode(va_list args);
     int dispatchSetAutoRefresh(va_list args);
+    int dispatchGetDisplayRefreshCycleDuration(va_list args);
+    int dispatchGetNextFrameId(va_list args);
+    int dispatchEnableFrameTimestamps(va_list args);
+    int dispatchGetCompositorTiming(va_list args);
     int dispatchGetFrameTimestamps(va_list args);
+    int dispatchGetWideColorSupport(va_list args);
+    int dispatchGetHdrSupport(va_list args);
 
 protected:
     virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
@@ -204,7 +235,6 @@
 
     virtual int connect(int api);
     virtual int setBufferCount(int bufferCount);
-    virtual int setBuffersDimensions(uint32_t width, uint32_t height);
     virtual int setBuffersUserDimensions(uint32_t width, uint32_t height);
     virtual int setBuffersFormat(PixelFormat format);
     virtual int setBuffersTransform(uint32_t transform);
@@ -224,20 +254,37 @@
     virtual int setAsyncMode(bool async);
     virtual int setSharedBufferMode(bool sharedBufferMode);
     virtual int setAutoRefresh(bool autoRefresh);
+    virtual int setBuffersDimensions(uint32_t width, uint32_t height);
     virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
     virtual int unlockAndPost();
     virtual int query(int what, int* value) const;
 
     virtual int connect(int api, const sp<IProducerListener>& listener);
+
+    // When reportBufferRemoval is true, clients must call getAndFlushRemovedBuffers to fetch
+    // GraphicBuffers removed from this surface after a dequeueBuffer, detachNextBuffer or
+    // attachBuffer call. This allows clients with their own buffer caches to free up buffers no
+    // longer in use by this surface.
+    virtual int connect(
+            int api, const sp<IProducerListener>& listener,
+            bool reportBufferRemoval);
     virtual int detachNextBuffer(sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence);
     virtual int attachBuffer(ANativeWindowBuffer*);
 
+    // When client connects to Surface with reportBufferRemoval set to true, any buffers removed
+    // from this Surface will be collected and returned here. Once this method returns, these
+    // buffers will no longer be referenced by this Surface unless they are attached to this
+    // Surface later. The list of removed buffers will only be stored until the next dequeueBuffer,
+    // detachNextBuffer, or attachBuffer call.
+    status_t getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out);
+
 protected:
-    enum { NUM_BUFFER_SLOTS = BufferQueue::NUM_BUFFER_SLOTS };
+    enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS };
     enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
 
-private:
+    void querySupportedTimestampsLocked() const;
+
     void freeAllBuffers();
     int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
 
@@ -377,48 +424,26 @@
     nsecs_t mLastDequeueDuration = 0;
     nsecs_t mLastQueueDuration = 0;
 
+    // Stores the time right before we call IGBP::dequeueBuffer
+    nsecs_t mLastDequeueStartTime = 0;
+
     Condition mQueueBufferCondition;
 
-    uint64_t mNextFrameNumber;
+    uint64_t mNextFrameNumber = 1;
+    uint64_t mLastFrameNumber = 0;
+
+    // Mutable because ANativeWindow::query needs this class const.
+    mutable bool mQueriedSupportedTimestamps;
+    mutable bool mFrameTimestampsSupportsPresent;
+
+    // A cached copy of the FrameEventHistory maintained by the consumer.
+    bool mEnableFrameTimestamps = false;
+    std::unique_ptr<ProducerFrameEventHistory> mFrameEventHistory;
+
+    bool mReportRemovedBuffers = false;
+    std::vector<sp<GraphicBuffer>> mRemovedBuffers;
 };
 
-namespace view {
-
-/**
- * A simple holder for an IGraphicBufferProducer, to match the managed-side
- * android.view.Surface parcelable behavior.
- *
- * This implements android/view/Surface.aidl
- *
- * TODO: Convert IGraphicBufferProducer into AIDL so that it can be directly
- * used in managed Binder calls.
- */
-class Surface : public Parcelable {
-  public:
-
-    String16 name;
-    sp<IGraphicBufferProducer> graphicBufferProducer;
-
-    virtual status_t writeToParcel(Parcel* parcel) const override;
-    virtual status_t readFromParcel(const Parcel* parcel) override;
-
-    // nameAlreadyWritten set to true by Surface.java, because it splits
-    // Parceling itself between managed and native code, so it only wants a part
-    // of the full parceling to happen on its native side.
-    status_t writeToParcel(Parcel* parcel, bool nameAlreadyWritten) const;
-
-    // nameAlreadyRead set to true by Surface.java, because it splits
-    // Parceling itself between managed and native code, so it only wants a part
-    // of the full parceling to happen on its native side.
-    status_t readFromParcel(const Parcel* parcel, bool nameAlreadyRead);
-
-  private:
-
-    static String16 readMaybeEmptyString16(const Parcel* parcel);
-};
-
-} // namespace view
-
-}; // namespace android
+} // namespace android
 
 #endif  // ANDROID_GUI_SURFACE_H
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index c4f88b6..ec310cf 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -21,7 +21,6 @@
 #include <sys/types.h>
 
 #include <binder/IBinder.h>
-#include <binder/IMemory.h>
 
 #include <utils/RefBase.h>
 #include <utils/Singleton.h>
@@ -38,7 +37,7 @@
 
 // ---------------------------------------------------------------------------
 
-class DisplayInfo;
+struct DisplayInfo;
 class Composer;
 class HdrCapabilities;
 class ISurfaceComposerClient;
@@ -52,6 +51,7 @@
     friend class Composer;
 public:
                 SurfaceComposerClient();
+                SurfaceComposerClient(const sp<IGraphicBufferProducer>& parent);
     virtual     ~SurfaceComposerClient();
 
     // Always make sure we could initialize
@@ -105,7 +105,10 @@
             uint32_t w,         // width in pixel
             uint32_t h,         // height in pixel
             PixelFormat format, // pixel-format desired
-            uint32_t flags = 0  // usage flags
+            uint32_t flags = 0, // usage flags
+            SurfaceControl* parent = nullptr, // parent
+            uint32_t windowType = 0, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.)
+            uint32_t ownerUid = 0 // UID of the task
     );
 
     //! Create a virtual display
@@ -131,6 +134,10 @@
     //! Close a composer transaction on all active SurfaceComposerClients.
     static void closeGlobalTransaction(bool synchronous = false);
 
+    static status_t enableVSyncInjections(bool enable);
+
+    static status_t injectVSync(nsecs_t when);
+
     //! Flag the currently open transaction as an animation transaction.
     static void setAnimationTransaction();
 
@@ -138,9 +145,11 @@
     status_t    show(const sp<IBinder>& id);
     status_t    setFlags(const sp<IBinder>& id, uint32_t flags, uint32_t mask);
     status_t    setTransparentRegionHint(const sp<IBinder>& id, const Region& transparent);
-    status_t    setLayer(const sp<IBinder>& id, uint32_t layer);
+    status_t    setLayer(const sp<IBinder>& id, int32_t layer);
+    status_t    setRelativeLayer(const sp<IBinder>& id,
+            const sp<IBinder>& relativeTo, int32_t layer);
     status_t    setAlpha(const sp<IBinder>& id, float alpha=1.0f);
-    status_t    setMatrix(const sp<IBinder>& id, float dsdx, float dtdx, float dsdy, float dtdy);
+    status_t    setMatrix(const sp<IBinder>& id, float dsdx, float dtdx, float dtdy, float dsdy);
     status_t    setPosition(const sp<IBinder>& id, float x, float y);
     status_t    setSize(const sp<IBinder>& id, uint32_t w, uint32_t h);
     status_t    setCrop(const sp<IBinder>& id, const Rect& crop);
@@ -148,6 +157,11 @@
     status_t    setLayerStack(const sp<IBinder>& id, uint32_t layerStack);
     status_t    deferTransactionUntil(const sp<IBinder>& id,
             const sp<IBinder>& handle, uint64_t frameNumber);
+    status_t    deferTransactionUntil(const sp<IBinder>& id,
+            const sp<Surface>& handle, uint64_t frameNumber);
+    status_t    reparentChildren(const sp<IBinder>& id,
+            const sp<IBinder>& newParentHandle);
+    status_t    detachChildren(const sp<IBinder>& id);
     status_t    setOverrideScalingMode(const sp<IBinder>& id,
             int32_t overrideScalingMode);
     status_t    setGeometryAppliesWithResize(const sp<IBinder>& id);
@@ -157,9 +171,6 @@
     status_t clearLayerFrameStats(const sp<IBinder>& token) const;
     status_t getLayerFrameStats(const sp<IBinder>& token, FrameStats* outStats) const;
 
-    status_t getTransformToDisplayInverse(const sp<IBinder>& token,
-            bool* outTransformToDisplayInverse) const;
-
     static status_t clearAnimationFrameStats();
     static status_t getAnimationFrameStats(FrameStats* outStats);
 
@@ -195,6 +206,7 @@
                 status_t                    mStatus;
                 sp<ISurfaceComposerClient>  mClient;
                 Composer&                   mComposer;
+                wp<IGraphicBufferProducer>  mParent;
 };
 
 // ---------------------------------------------------------------------------
@@ -208,9 +220,15 @@
             const sp<IBinder>& display,
             const sp<IGraphicBufferProducer>& producer,
             Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            uint32_t minLayerZ, uint32_t maxLayerZ,
+            int32_t minLayerZ, int32_t maxLayerZ,
             bool useIdentityTransform);
-
+    static status_t captureToBuffer(
+            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);
 private:
     mutable sp<CpuConsumer> mCpuConsumer;
     mutable sp<IGraphicBufferProducer> mProducer;
@@ -231,11 +249,11 @@
             bool useIdentityTransform);
     status_t update(const sp<IBinder>& display,
             Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            uint32_t minLayerZ, uint32_t maxLayerZ,
+            int32_t minLayerZ, int32_t maxLayerZ,
             bool useIdentityTransform);
     status_t update(const sp<IBinder>& display,
             Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            uint32_t minLayerZ, uint32_t maxLayerZ,
+            int32_t minLayerZ, int32_t maxLayerZ,
             bool useIdentityTransform, uint32_t rotation);
 
     sp<CpuConsumer> getCpuConsumer() const;
diff --git a/include/gui/SurfaceControl.h b/include/gui/SurfaceControl.h
index 5e731c3..8bb705c 100644
--- a/include/gui/SurfaceControl.h
+++ b/include/gui/SurfaceControl.h
@@ -61,7 +61,28 @@
     void        disconnect();
 
     status_t    setLayerStack(uint32_t layerStack);
-    status_t    setLayer(uint32_t layer);
+    status_t    setLayer(int32_t layer);
+
+    // Sets a Z order relative to the Surface specified by "relativeTo" but
+    // without becoming a full child of the relative. Z-ordering works exactly
+    // as if it were a child however.
+    //
+    // As a nod to sanity, only non-child surfaces may have a relative Z-order.
+    //
+    // This overrides any previous and is overriden by any future calls
+    // to setLayer.
+    //
+    // If the relative dissapears, the Surface will have no layer and be
+    // invisible, until the next time set(Relative)Layer is called.
+    //
+    // TODO: This is probably a hack. Currently it exists only to work around
+    // some framework usage of the hidden APPLICATION_MEDIA_OVERLAY window type
+    // which allows inserting a window between a SurfaceView and it's main application
+    // window. However, since we are using child windows for the SurfaceView, but not using
+    // child windows elsewhere in O, the WindowManager can't set the layer appropriately.
+    // This is only used by the "TvInputService" and following the port of ViewRootImpl
+    // to child surfaces, we can then port this and remove this method.
+    status_t    setRelativeLayer(const sp<IBinder>& relativeTo, int32_t layer);
     status_t    setPosition(float x, float y);
     status_t    setSize(uint32_t w, uint32_t h);
     status_t    hide();
@@ -69,7 +90,7 @@
     status_t    setFlags(uint32_t flags, uint32_t mask);
     status_t    setTransparentRegionHint(const Region& transparent);
     status_t    setAlpha(float alpha=1.0f);
-    status_t    setMatrix(float dsdx, float dtdx, float dsdy, float dtdy);
+    status_t    setMatrix(float dsdx, float dtdx, float dtdy, float dsdy);
     status_t    setCrop(const Rect& crop);
     status_t    setFinalCrop(const Rect& crop);
 
@@ -80,8 +101,30 @@
     status_t    setGeometryAppliesWithResize();
 
     // Defers applying any changes made in this transaction until the Layer
-    // identified by handle reaches the given frameNumber
-    status_t deferTransactionUntil(sp<IBinder> handle, uint64_t frameNumber);
+    // identified by handle reaches the given frameNumber. If the Layer identified
+    // by handle is removed, then we will apply this transaction regardless of
+    // what frame number has been reached.
+    status_t deferTransactionUntil(const sp<IBinder>& handle, uint64_t frameNumber);
+
+    // A variant of deferTransactionUntil which identifies the Layer we wait for by
+    // Surface instead of Handle. Useful for clients which may not have the
+    // SurfaceControl for some of their Surfaces. Otherwise behaves identically.
+    status_t deferTransactionUntil(const sp<Surface>& barrier, uint64_t frameNumber);
+
+    // Reparents all children of this layer to the new parent handle.
+    status_t reparentChildren(const sp<IBinder>& newParentHandle);
+
+    // Detaches all child surfaces (and their children recursively)
+    // from their SurfaceControl.
+    // The child SurfaceControl's will not throw exceptions or return errors,
+    // but transactions will have no effect.
+    // The child surfaces will continue to follow their parent surfaces,
+    // and remain eligible for rendering, but their relative state will be
+    // frozen. We use this in the WindowManager, in app shutdown/relaunch
+    // scenarios, where the app would otherwise clean up its child Surfaces.
+    // Sometimes the WindowManager needs to extend their lifetime slightly
+    // in order to perform an exit animation or prevent flicker.
+    status_t detachChildren();
 
     // Set an override scaling mode as documented in <system/window.h>
     // the override scaling mode will take precedence over any client
@@ -92,13 +135,12 @@
             const sp<SurfaceControl>& control, Parcel* parcel);
 
     sp<Surface> getSurface() const;
+    sp<Surface> createSurface() const;
     sp<IBinder> getHandle() const;
 
     status_t clearLayerFrameStats() const;
     status_t getLayerFrameStats(FrameStats* outStats) const;
 
-    status_t getTransformToDisplayInverse(bool* outTransformToDisplayInverse) const;
-
 private:
     // can't be copied
     SurfaceControl& operator = (SurfaceControl& rhs);
@@ -114,6 +156,7 @@
 
     ~SurfaceControl();
 
+    sp<Surface> generateSurfaceLocked() const;
     status_t validate() const;
     void destroy();
 
diff --git a/include/gui/bufferqueue/1.0/B2HProducerListener.h b/include/gui/bufferqueue/1.0/B2HProducerListener.h
new file mode 100644
index 0000000..fa6c2d9
--- /dev/null
+++ b/include/gui/bufferqueue/1.0/B2HProducerListener.h
@@ -0,0 +1,66 @@
+/*
+ * 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_B2HPRODUCERLISTENER_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_B2HPRODUCERLISTENER_H
+
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <binder/IBinder.h>
+#include <gui/IProducerListener.h>
+
+#include <android/hidl/base/1.0/IBase.h>
+#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V1_0 {
+namespace utils {
+
+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;
+
+struct B2HProducerListener : public HProducerListener {
+    sp<BProducerListener> mBase;
+    B2HProducerListener(sp<BProducerListener> const& base);
+    Return<void> onBufferReleased() override;
+    Return<bool> needsReleaseNotify() override;
+};
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_B2HPRODUCERLISTENER_H
+
diff --git a/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h b/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
new file mode 100644
index 0000000..93c452a
--- /dev/null
+++ b/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
@@ -0,0 +1,106 @@
+/*
+ * 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_H2BGRAPHICBUFFERPRODUCER_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_H2BGRAPHICBUFFERPRODUCER_H
+
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <binder/Binder.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/IProducerListener.h>
+
+#include <hidl/HybridInterface.h>
+#include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V1_0 {
+namespace utils {
+
+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;
+
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::media::V1_0::AnwBuffer;
+
+typedef ::android::hardware::graphics::bufferqueue::V1_0::IGraphicBufferProducer
+        HGraphicBufferProducer;
+typedef ::android::hardware::graphics::bufferqueue::V1_0::IProducerListener
+        HProducerListener;
+
+typedef ::android::IGraphicBufferProducer BGraphicBufferProducer;
+using ::android::BnGraphicBufferProducer;
+using ::android::IProducerListener;
+
+struct H2BGraphicBufferProducer : public ::android::H2BConverter<
+        HGraphicBufferProducer,
+        BGraphicBufferProducer,
+        BnGraphicBufferProducer> {
+    H2BGraphicBufferProducer(sp<HGraphicBufferProducer> const& base) : CBase(base) {}
+
+    status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override;
+    status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) override;
+    status_t setAsyncMode(bool async) override;
+    status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w,
+            uint32_t h, ::android::PixelFormat format, uint32_t usage,
+            FrameEventHistoryDelta* outTimestamps) override;
+    status_t detachBuffer(int slot) override;
+    status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence)
+            override;
+    status_t attachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer)
+            override;
+    status_t queueBuffer(int slot,
+            const QueueBufferInput& input,
+            QueueBufferOutput* output) override;
+    status_t cancelBuffer(int slot, const sp<Fence>& fence) override;
+    int query(int what, int* value) override;
+    status_t connect(const sp<IProducerListener>& listener, int api,
+            bool producerControlledByApp, QueueBufferOutput* output) override;
+    status_t disconnect(int api, DisconnectMode mode = DisconnectMode::Api)
+            override;
+    status_t setSidebandStream(const sp<NativeHandle>& stream) override;
+    void allocateBuffers(uint32_t width, uint32_t height,
+            ::android::PixelFormat format, uint32_t usage) override;
+    status_t allowAllocation(bool allow) override;
+    status_t setGenerationNumber(uint32_t generationNumber) override;
+    String8 getConsumerName() const override;
+    status_t setSharedBufferMode(bool sharedBufferMode) override;
+    status_t setAutoRefresh(bool autoRefresh) override;
+    status_t setDequeueTimeout(nsecs_t timeout) override;
+    status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
+          sp<Fence>* outFence, float outTransformMatrix[16]) override;
+    void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override;
+    status_t getUniqueId(uint64_t* outId) const override;
+};
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace bufferqueue
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_H2BGRAPHICBUFFERPRODUCER_H
diff --git a/include/gui/view/Surface.h b/include/gui/view/Surface.h
new file mode 100644
index 0000000..cc64fd4
--- /dev/null
+++ b/include/gui/view/Surface.h
@@ -0,0 +1,68 @@
+/*
+ * 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_GUI_VIEW_SURFACE_H
+#define ANDROID_GUI_VIEW_SURFACE_H
+
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+#include <utils/String16.h>
+
+#include <binder/Parcelable.h>
+
+namespace android {
+
+class IGraphicBufferProducer;
+
+namespace view {
+
+/**
+ * A simple holder for an IGraphicBufferProducer, to match the managed-side
+ * android.view.Surface parcelable behavior.
+ *
+ * This implements android/view/Surface.aidl
+ *
+ * TODO: Convert IGraphicBufferProducer into AIDL so that it can be directly
+ * used in managed Binder calls.
+ */
+class Surface : public Parcelable {
+  public:
+
+    String16 name;
+    sp<IGraphicBufferProducer> graphicBufferProducer;
+
+    virtual status_t writeToParcel(Parcel* parcel) const override;
+    virtual status_t readFromParcel(const Parcel* parcel) override;
+
+    // nameAlreadyWritten set to true by Surface.java, because it splits
+    // Parceling itself between managed and native code, so it only wants a part
+    // of the full parceling to happen on its native side.
+    status_t writeToParcel(Parcel* parcel, bool nameAlreadyWritten) const;
+
+    // nameAlreadyRead set to true by Surface.java, because it splits
+    // Parceling itself between managed and native code, so it only wants a part
+    // of the full parceling to happen on its native side.
+    status_t readFromParcel(const Parcel* parcel, bool nameAlreadyRead);
+
+  private:
+
+    static String16 readMaybeEmptyString16(const Parcel* parcel);
+};
+
+} // namespace view
+} // namespace android
+
+#endif  // ANDROID_GUI_VIEW_SURFACE_H
diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h
new file mode 100644
index 0000000..86da4d3
--- /dev/null
+++ b/include/input/DisplayViewport.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBINPUT_DISPLAY_VIEWPORT_H
+#define _LIBINPUT_DISPLAY_VIEWPORT_H
+
+#include <ui/DisplayInfo.h>
+#include <input/Input.h>
+
+namespace android {
+
+/*
+ * Describes how coordinates are mapped on a physical display.
+ * See com.android.server.display.DisplayViewport.
+ */
+struct DisplayViewport {
+    int32_t displayId; // -1 if invalid
+    int32_t orientation;
+    int32_t logicalLeft;
+    int32_t logicalTop;
+    int32_t logicalRight;
+    int32_t logicalBottom;
+    int32_t physicalLeft;
+    int32_t physicalTop;
+    int32_t physicalRight;
+    int32_t physicalBottom;
+    int32_t deviceWidth;
+    int32_t deviceHeight;
+    String8 uniqueId;
+
+    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) {
+    }
+
+    bool operator==(const DisplayViewport& other) const {
+        return displayId == other.displayId
+                && orientation == other.orientation
+                && logicalLeft == other.logicalLeft
+                && logicalTop == other.logicalTop
+                && logicalRight == other.logicalRight
+                && logicalBottom == other.logicalBottom
+                && physicalLeft == other.physicalLeft
+                && physicalTop == other.physicalTop
+                && physicalRight == other.physicalRight
+                && physicalBottom == other.physicalBottom
+                && deviceWidth == other.deviceWidth
+                && deviceHeight == other.deviceHeight
+                && uniqueId == other.uniqueId;
+    }
+
+    bool operator!=(const DisplayViewport& other) const {
+        return !(*this == other);
+    }
+
+    inline bool isValid() const {
+        return displayId >= 0;
+    }
+
+    void setNonDisplayViewport(int32_t width, int32_t height) {
+        displayId = ADISPLAY_ID_NONE;
+        orientation = DISPLAY_ORIENTATION_0;
+        logicalLeft = 0;
+        logicalTop = 0;
+        logicalRight = width;
+        logicalBottom = height;
+        physicalLeft = 0;
+        physicalTop = 0;
+        physicalRight = width;
+        physicalBottom = height;
+        deviceWidth = width;
+        deviceHeight = height;
+        uniqueId.clear();
+    }
+};
+
+/**
+ * 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,
+};
+
+} // namespace android
+
+#endif // _LIBINPUT_DISPLAY_VIEWPORT_H
diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h
index 629310f..11bb721 100644
--- a/include/input/IInputFlinger.h
+++ b/include/input/IInputFlinger.h
@@ -30,7 +30,7 @@
  */
 class IInputFlinger : public IInterface {
 public:
-    DECLARE_META_INTERFACE(InputFlinger);
+    DECLARE_META_INTERFACE(InputFlinger)
 };
 
 
diff --git a/include/input/Input.h b/include/input/Input.h
index 55787e7..cfcafab 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -398,7 +398,7 @@
 
     inline int32_t getButtonState() const { return mButtonState; }
 
-    inline int32_t setButtonState(int32_t buttonState) { mButtonState = buttonState; }
+    inline void setButtonState(int32_t buttonState) { mButtonState = buttonState; }
 
     inline int32_t getActionButton() const { return mActionButton; }
 
diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h
index 0bd14ea..20154eb 100644
--- a/include/input/InputEventLabels.h
+++ b/include/input/InputEventLabels.h
@@ -425,30 +425,30 @@
     return NULL;
 }
 
-static int32_t getKeyCodeByLabel(const char* label) {
+static inline int32_t getKeyCodeByLabel(const char* label) {
     return int32_t(lookupValueByLabel(label, KEYCODES));
 }
 
-static const char* getLabelByKeyCode(int32_t keyCode) {
-    if (keyCode >= 0 && keyCode < size(KEYCODES)) {
+static inline const char* getLabelByKeyCode(int32_t keyCode) {
+    if (keyCode >= 0 && keyCode < static_cast<int32_t>(size(KEYCODES))) {
         return KEYCODES[keyCode].literal;
     }
     return NULL;
 }
 
-static uint32_t getKeyFlagByLabel(const char* label) {
+static inline uint32_t getKeyFlagByLabel(const char* label) {
     return uint32_t(lookupValueByLabel(label, FLAGS));
 }
 
-static int32_t getAxisByLabel(const char* label) {
+static inline int32_t getAxisByLabel(const char* label) {
     return int32_t(lookupValueByLabel(label, AXES));
 }
 
-static const char* getAxisLabel(int32_t axisId) {
+static inline const char* getAxisLabel(int32_t axisId) {
     return lookupLabelByValue(axisId, AXES);
 }
 
-static int32_t getLedByLabel(const char* label) {
+static inline int32_t getLedByLabel(const char* label) {
     return int32_t(lookupValueByLabel(label, LEDS));
 }
 
diff --git a/include/media/cas/CasAPI.h b/include/media/cas/CasAPI.h
new file mode 100644
index 0000000..67f4511
--- /dev/null
+++ b/include/media/cas/CasAPI.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CAS_API_H_
+#define CAS_API_H_
+
+#include <vector>
+#include <utils/String8.h>
+
+//  Loadable CasPlugin shared libraries should define the entry points
+//  as shown below:
+//
+//  extern "C" {
+//      extern android::CasFactory *createCasFactory();
+//      extern android::DescramblerFactory *createDescramblerFactory();
+//  }
+
+namespace android {
+
+struct CasPlugin;
+
+struct CasPluginDescriptor {
+    int32_t CA_system_id;
+    String8 name;
+};
+
+typedef std::vector<uint8_t> CasData;
+typedef std::vector<uint8_t> CasSessionId;
+typedef std::vector<uint8_t> CasEmm;
+typedef std::vector<uint8_t> CasEcm;
+typedef void (*CasPluginCallback)(
+        void *appData,
+        int32_t event,
+        int32_t arg,
+        uint8_t *data,
+        size_t size);
+
+struct CasFactory {
+    CasFactory() {}
+    virtual ~CasFactory() {}
+
+    // Determine if the plugin can handle the CA scheme identified by CA_system_id.
+    virtual bool isSystemIdSupported(
+            int32_t CA_system_id) const = 0;
+
+    // Get a list of the CA schemes supported by the plugin.
+    virtual status_t queryPlugins(
+            std::vector<CasPluginDescriptor> *descriptors) const = 0;
+
+    // Construct a new instance of a CasPlugin given a CA_system_id
+    virtual status_t createPlugin(
+            int32_t CA_system_id,
+            uint64_t appData,
+            CasPluginCallback callback,
+            CasPlugin **plugin) = 0;
+
+private:
+    CasFactory(const CasFactory &);
+    CasFactory &operator=(const CasFactory &); /* NOLINT */
+};
+
+struct CasPlugin {
+    CasPlugin() {}
+    virtual ~CasPlugin() {}
+
+    // Provide the CA private data from a CA_descriptor in the conditional
+    // access table to a CasPlugin.
+    virtual status_t setPrivateData(
+            const CasData &privateData) = 0;
+
+    // Open a session for descrambling a program, or one or more elementary
+    // streams.
+    virtual status_t openSession(CasSessionId *sessionId) = 0;
+
+    // Close a previously opened session.
+    virtual status_t closeSession(const CasSessionId &sessionId) = 0;
+
+    // Provide the CA private data from a CA_descriptor in the program map
+    // table to a CasPlugin.
+    virtual status_t setSessionPrivateData(
+            const CasSessionId &sessionId,
+            const CasData &privateData) = 0;
+
+    // Process an ECM from the ECM stream for this session’s elementary stream.
+    virtual status_t processEcm(
+            const CasSessionId &sessionId,
+            const CasEcm &ecm) = 0;
+
+    // Process an in-band EMM from the EMM stream.
+    virtual status_t processEmm(
+            const CasEmm &emm) = 0;
+
+    // Deliver an event to the CasPlugin. The format of the event is specific
+    // to the CA scheme and is opaque to the framework.
+    virtual status_t sendEvent(
+            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;
+
+    // Native implementation of the MediaCas Java API refreshEntitlements method
+    virtual status_t refreshEntitlements(
+            int32_t refreshType,
+            const CasData &refreshData) = 0;
+
+private:
+    CasPlugin(const CasPlugin &);
+    CasPlugin &operator=(const CasPlugin &); /* NOLINT */
+};
+
+extern "C" {
+    extern android::CasFactory *createCasFactory();
+}
+
+} // namespace android
+
+#endif // CAS_API_H_
diff --git a/include/media/cas/DescramblerAPI.h b/include/media/cas/DescramblerAPI.h
new file mode 100644
index 0000000..0a51952
--- /dev/null
+++ b/include/media/cas/DescramblerAPI.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DESCRAMBLER_API_H_
+#define DESCRAMBLER_API_H_
+
+#include <media/stagefright/MediaErrors.h>
+#include <media/cas/CasAPI.h>
+
+namespace android {
+
+struct AString;
+struct DescramblerPlugin;
+
+struct DescramblerFactory {
+    DescramblerFactory() {}
+    virtual ~DescramblerFactory() {}
+
+    // Determine if the plugin can handle the CA scheme identified by CA_system_id.
+    virtual bool isSystemIdSupported(
+            int32_t CA_system_id) const = 0;
+
+    // Construct a new instance of a DescramblerPlugin given a CA_system_id
+    virtual status_t createPlugin(
+            int32_t CA_system_id, DescramblerPlugin **plugin) = 0;
+
+private:
+    DescramblerFactory(const DescramblerFactory &);
+    DescramblerFactory &operator=(const DescramblerFactory &);
+};
+
+struct DescramblerPlugin {
+    enum ScramblingControl {
+        kScrambling_Unscrambled = 0,
+        kScrambling_Reserved    = 1,
+        kScrambling_EvenKey     = 2,
+        kScrambling_OddKey      = 3,
+    };
+
+    struct SubSample {
+        uint32_t mNumBytesOfClearData;
+        uint32_t mNumBytesOfEncryptedData;
+    };
+
+    DescramblerPlugin() {}
+    virtual ~DescramblerPlugin() {}
+
+    // If this method returns false, a non-secure decoder will be used to
+    // decode the data after decryption. The decrypt API below will have
+    // to support insecure decryption of the data (secure = false) for
+    // media data of the given mime type.
+    virtual bool requiresSecureDecoderComponent(const char *mime) const = 0;
+
+    // A MediaCas session may be associated with a MediaCrypto session.  The
+    // 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
+    // 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
+    // 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
+    // the error code and the errorDetailMsg.
+    // Returns a non-negative result to indicate the number of bytes written
+    // to the dstPtr, or a negative result to indicate an error.
+    virtual ssize_t descramble(
+            bool secure,
+            ScramblingControl scramblingControl,
+            size_t numSubSamples,
+            const SubSample *subSamples,
+            const void *srcPtr,
+            int32_t srcOffset,
+            void *dstPtr,
+            int32_t dstOffset,
+            AString *errorDetailMsg) = 0;
+
+private:
+    DescramblerPlugin(const DescramblerPlugin &);
+    DescramblerPlugin &operator=(const DescramblerPlugin &);
+};
+
+}  // namespace android
+
+extern "C" {
+    extern android::DescramblerFactory *createDescramblerFactory();
+}
+
+#endif  // DESCRAMBLER_API_H_
diff --git a/include/media/hardware/HDCPAPI.h b/include/media/hardware/HDCPAPI.h
index 3a53e9f..30cd5fd 100644
--- a/include/media/hardware/HDCPAPI.h
+++ b/include/media/hardware/HDCPAPI.h
@@ -73,7 +73,7 @@
     // Module can call the notification function to signal completion/failure
     // of asynchronous operations (such as initialization) or out of band
     // events.
-    HDCPModule(void *cookie, ObserverFunc observerNotify) {};
+    HDCPModule(void * /*cookie*/, ObserverFunc /*observerNotify*/) {};
 
     virtual ~HDCPModule() {};
 
@@ -104,8 +104,8 @@
     // 1 for the second and so on)
     // inputCTR _will_be_maintained_by_the_callee_ for each PES stream.
     virtual status_t encrypt(
-            const void *inData, size_t size, uint32_t streamCTR,
-            uint64_t *outInputCTR, void *outData) {
+            const void * /*inData*/, size_t /*size*/, uint32_t /*streamCTR*/,
+            uint64_t * /*outInputCTR*/, void * /*outData*/) {
         return INVALID_OPERATION;
     }
 
@@ -119,8 +119,8 @@
     // 1 for the second and so on)
     // inputCTR _will_be_maintained_by_the_callee_ for each PES stream.
     virtual status_t encryptNative(
-            buffer_handle_t buffer, size_t offset, size_t size,
-            uint32_t streamCTR, uint64_t *outInputCTR, void *outData) {
+            buffer_handle_t /*buffer*/, size_t /*offset*/, size_t /*size*/,
+            uint32_t /*streamCTR*/, uint64_t * /*outInputCTR*/, void * /*outData*/) {
         return INVALID_OPERATION;
     }
     // DECRYPTION only:
@@ -133,9 +133,9 @@
     // until outData contains size bytes of decrypted data.
     // Both streamCTR and inputCTR will be provided by the caller.
     virtual status_t decrypt(
-            const void *inData, size_t size,
-            uint32_t streamCTR, uint64_t inputCTR,
-            void *outData) {
+            const void * /*inData*/, size_t /*size*/,
+            uint32_t /*streamCTR*/, uint64_t /*inputCTR*/,
+            void * /*outData*/) {
         return INVALID_OPERATION;
     }
 
diff --git a/include/media/hardware/HardwareAPI.h b/include/media/hardware/HardwareAPI.h
index 2c50ad6..cecf715 100644
--- a/include/media/hardware/HardwareAPI.h
+++ b/include/media/hardware/HardwareAPI.h
@@ -270,7 +270,7 @@
     // output: fill out the MediaImage fields
     MediaImage sMediaImage;
 
-    DescribeColorFormatParams(const DescribeColorFormat2Params&); // for internal use only
+    explicit DescribeColorFormatParams(const DescribeColorFormat2Params&); // for internal use only
 };
 
 // A pointer to this struct is passed to OMX_GetParameter when the extension
diff --git a/include/media/hardware/VideoAPI.h b/include/media/hardware/VideoAPI.h
index 3667c4b..a090876 100644
--- a/include/media/hardware/VideoAPI.h
+++ b/include/media/hardware/VideoAPI.h
@@ -110,7 +110,7 @@
 // though could verify that nSize is at least the size of the structure at the
 // time of implementation. All new fields will be added at the end of the structure
 // ensuring backward compatibility.
-struct __attribute__ ((__packed__)) ColorAspects {
+struct __attribute__ ((__packed__, aligned(alignof(uint32_t)))) ColorAspects {
     // this is in sync with the range values in graphics.h
     enum Range : uint32_t {
         RangeUnspecified,
diff --git a/include/media/openmax/OMX_AsString.h b/include/media/openmax/OMX_AsString.h
index 7ae07ad..56d7cc8 100644
--- a/include/media/openmax/OMX_AsString.h
+++ b/include/media/openmax/OMX_AsString.h
@@ -107,6 +107,7 @@
         case OMX_AUDIO_AACObjectLTP:      return "LTP";
         case OMX_AUDIO_AACObjectHE:       return "HE";
         case OMX_AUDIO_AACObjectScalable: return "Scalable";
+        case OMX_AUDIO_AACObjectER_Scalable: return "ER_Scalable";
         case OMX_AUDIO_AACObjectERLC:     return "ERLC";
         case OMX_AUDIO_AACObjectLD:       return "LD";
         case OMX_AUDIO_AACObjectHE_PS:    return "HE_PS";
@@ -530,9 +531,12 @@
 //      case OMX_IndexConfigCallbackRequest:            return "ConfigCallbackRequest";
 //      case OMX_IndexConfigCommitMode:                 return "ConfigCommitMode";
 //      case OMX_IndexConfigCommit:                     return "ConfigCommit";
+        case OMX_IndexConfigAndroidVendorExtension:     return "ConfigAndroidVendorExtension";
         case OMX_IndexParamAudioAndroidAc3:             return "ParamAudioAndroidAc3";
         case OMX_IndexParamAudioAndroidOpus:            return "ParamAudioAndroidOpus";
         case OMX_IndexParamAudioAndroidAacPresentation: return "ParamAudioAndroidAacPresentation";
+        case OMX_IndexParamAudioAndroidEac3:            return "ParamAudioAndroidEac3";
+        case OMX_IndexParamAudioProfileQuerySupported:  return "ParamAudioProfileQuerySupported";
 //      case OMX_IndexParamNalStreamFormatSupported:    return "ParamNalStreamFormatSupported";
 //      case OMX_IndexParamNalStreamFormat:             return "ParamNalStreamFormat";
 //      case OMX_IndexParamNalStreamFormatSelect:       return "ParamNalStreamFormatSelect";
@@ -545,10 +549,15 @@
         case OMX_IndexConfigAndroidIntraRefresh:        return "ConfigAndroidIntraRefresh";
         case OMX_IndexParamAndroidVideoTemporalLayering: return "ParamAndroidVideoTemporalLayering";
         case OMX_IndexConfigAndroidVideoTemporalLayering: return "ConfigAndroidVideoTemporalLayering";
+        case OMX_IndexParamMaxFrameDurationForBitrateControl:
+            return "ParamMaxFrameDurationForBitrateControl";
+        case OMX_IndexParamVideoVp9:                    return "ParamVideoVp9";
+        case OMX_IndexParamVideoAndroidVp9Encoder:      return "ParamVideoAndroidVp9Encoder";
         case OMX_IndexConfigAutoFramerateConversion:    return "ConfigAutoFramerateConversion";
         case OMX_IndexConfigPriority:                   return "ConfigPriority";
         case OMX_IndexConfigOperatingRate:              return "ConfigOperatingRate";
         case OMX_IndexParamConsumerUsageBits:           return "ParamConsumerUsageBits";
+        case OMX_IndexConfigLatency:                    return "ConfigLatency";
         default:                                        return asString((OMX_INDEXTYPE)i, def);
     }
 }
diff --git a/include/media/openmax/OMX_Audio.h b/include/media/openmax/OMX_Audio.h
index d8bee76..9c0296b 100644
--- a/include/media/openmax/OMX_Audio.h
+++ b/include/media/openmax/OMX_Audio.h
@@ -259,6 +259,7 @@
   OMX_AUDIO_AACObjectHE,            /**< AAC High Efficiency (object type SBR, HE-AAC profile) */
   OMX_AUDIO_AACObjectScalable,      /**< AAC Scalable object */
   OMX_AUDIO_AACObjectERLC = 17,     /**< ER AAC Low Complexity object (Error Resilient AAC-LC) */
+  OMX_AUDIO_AACObjectER_Scalable = 20, /**< ER AAC scalable object */
   OMX_AUDIO_AACObjectLD = 23,       /**< AAC Low Delay object (Error Resilient) */
   OMX_AUDIO_AACObjectHE_PS = 29,    /**< AAC High Efficiency with Parametric Stereo coding (HE-AAC v2, object type PS) */
   OMX_AUDIO_AACObjectELD = 39,      /** AAC Enhanced Low Delay. NOTE: Pending Khronos standardization **/
diff --git a/include/media/openmax/OMX_Core.h b/include/media/openmax/OMX_Core.h
index 88dd585..bb974b3 100644
--- a/include/media/openmax/OMX_Core.h
+++ b/include/media/openmax/OMX_Core.h
@@ -738,7 +738,7 @@
         pComponentVersion,                                  \
         pSpecVersion,                                       \
         pComponentUUID)                                     \
-    ((OMX_COMPONENTTYPE*)hComponent)->GetComponentVersion(  \
+    ((OMX_COMPONENTTYPE*)(hComponent))->GetComponentVersion(\
         hComponent,                                         \
         pComponentName,                                     \
         pComponentVersion,                                  \
@@ -804,7 +804,7 @@
          Cmd,                                               \
          nParam,                                            \
          pCmdData)                                          \
-     ((OMX_COMPONENTTYPE*)hComponent)->SendCommand(         \
+     ((OMX_COMPONENTTYPE*)(hComponent))->SendCommand(       \
          hComponent,                                        \
          Cmd,                                               \
          nParam,                                            \
@@ -843,8 +843,8 @@
 #define OMX_GetParameter(                                   \
         hComponent,                                         \
         nParamIndex,                                        \
-        pComponentParameterStructure)                        \
-    ((OMX_COMPONENTTYPE*)hComponent)->GetParameter(         \
+        pComponentParameterStructure)                       \
+    ((OMX_COMPONENTTYPE*)(hComponent))->GetParameter(       \
         hComponent,                                         \
         nParamIndex,                                        \
         pComponentParameterStructure)    /* Macro End */
@@ -882,8 +882,8 @@
 #define OMX_SetParameter(                                   \
         hComponent,                                         \
         nParamIndex,                                        \
-        pComponentParameterStructure)                        \
-    ((OMX_COMPONENTTYPE*)hComponent)->SetParameter(         \
+        pComponentParameterStructure)                       \
+    ((OMX_COMPONENTTYPE*)(hComponent))->SetParameter(       \
         hComponent,                                         \
         nParamIndex,                                        \
         pComponentParameterStructure)    /* Macro End */
@@ -918,8 +918,8 @@
 #define OMX_GetConfig(                                      \
         hComponent,                                         \
         nConfigIndex,                                       \
-        pComponentConfigStructure)                           \
-    ((OMX_COMPONENTTYPE*)hComponent)->GetConfig(            \
+        pComponentConfigStructure)                          \
+    ((OMX_COMPONENTTYPE*)(hComponent))->GetConfig(          \
         hComponent,                                         \
         nConfigIndex,                                       \
         pComponentConfigStructure)       /* Macro End */
@@ -954,8 +954,8 @@
 #define OMX_SetConfig(                                      \
         hComponent,                                         \
         nConfigIndex,                                       \
-        pComponentConfigStructure)                           \
-    ((OMX_COMPONENTTYPE*)hComponent)->SetConfig(            \
+        pComponentConfigStructure)                          \
+    ((OMX_COMPONENTTYPE*)(hComponent))->SetConfig(          \
         hComponent,                                         \
         nConfigIndex,                                       \
         pComponentConfigStructure)       /* Macro End */
@@ -989,7 +989,7 @@
         hComponent,                                         \
         cParameterName,                                     \
         pIndexType)                                         \
-    ((OMX_COMPONENTTYPE*)hComponent)->GetExtensionIndex(    \
+    ((OMX_COMPONENTTYPE*)(hComponent))->GetExtensionIndex(  \
         hComponent,                                         \
         cParameterName,                                     \
         pIndexType)                     /* Macro End */
@@ -1015,7 +1015,7 @@
 #define OMX_GetState(                                       \
         hComponent,                                         \
         pState)                                             \
-    ((OMX_COMPONENTTYPE*)hComponent)->GetState(             \
+    ((OMX_COMPONENTTYPE*)(hComponent))->GetState(           \
         hComponent,                                         \
         pState)                         /* Macro End */
 
@@ -1046,7 +1046,7 @@
            pAppPrivate,                                     \
            nSizeBytes,                                      \
            pBuffer)                                         \
-    ((OMX_COMPONENTTYPE*)hComponent)->UseBuffer(            \
+    ((OMX_COMPONENTTYPE*)(hComponent))->UseBuffer(          \
            hComponent,                                      \
            ppBufferHdr,                                     \
            nPortIndex,                                      \
@@ -1088,7 +1088,7 @@
         nPortIndex,                                         \
         pAppPrivate,                                        \
         nSizeBytes)                                         \
-    ((OMX_COMPONENTTYPE*)hComponent)->AllocateBuffer(       \
+    ((OMX_COMPONENTTYPE*)(hComponent))->AllocateBuffer(     \
         hComponent,                                         \
         ppBuffer,                                           \
         nPortIndex,                                         \
@@ -1122,7 +1122,7 @@
         hComponent,                                         \
         nPortIndex,                                         \
         pBuffer)                                            \
-    ((OMX_COMPONENTTYPE*)hComponent)->FreeBuffer(           \
+    ((OMX_COMPONENTTYPE*)(hComponent))->FreeBuffer(         \
         hComponent,                                         \
         nPortIndex,                                         \
         pBuffer)                        /* Macro End */
@@ -1153,7 +1153,7 @@
 #define OMX_EmptyThisBuffer(                                \
         hComponent,                                         \
         pBuffer)                                            \
-    ((OMX_COMPONENTTYPE*)hComponent)->EmptyThisBuffer(      \
+    ((OMX_COMPONENTTYPE*)(hComponent))->EmptyThisBuffer(    \
         hComponent,                                         \
         pBuffer)                        /* Macro End */
 
@@ -1183,7 +1183,7 @@
 #define OMX_FillThisBuffer(                                 \
         hComponent,                                         \
         pBuffer)                                            \
-    ((OMX_COMPONENTTYPE*)hComponent)->FillThisBuffer(       \
+    ((OMX_COMPONENTTYPE*)(hComponent))->FillThisBuffer(     \
         hComponent,                                         \
         pBuffer)                        /* Macro End */
 
@@ -1225,7 +1225,7 @@
            nPortIndex,                                      \
            pAppPrivate,                                     \
            eglImage)                                        \
-    ((OMX_COMPONENTTYPE*)hComponent)->UseEGLImage(          \
+    ((OMX_COMPONENTTYPE*)(hComponent))->UseEGLImage(        \
            hComponent,                                      \
            ppBufferHdr,                                     \
            nPortIndex,                                      \
diff --git a/include/media/openmax/OMX_Index.h b/include/media/openmax/OMX_Index.h
index 1a2a548..5be1355 100644
--- a/include/media/openmax/OMX_Index.h
+++ b/include/media/openmax/OMX_Index.h
@@ -98,10 +98,13 @@
     OMX_IndexParamMetadataKeyFilter,        /**< reference: OMX_PARAM_METADATAFILTERTYPE */
     OMX_IndexConfigPriorityMgmt,            /**< reference: OMX_PRIORITYMGMTTYPE */
     OMX_IndexParamStandardComponentRole,    /**< reference: OMX_PARAM_COMPONENTROLETYPE */
+    OMX_IndexComponentEndUnused,
 
     OMX_IndexPortStartUnused = 0x02000000,
     OMX_IndexParamPortDefinition,           /**< reference: OMX_PARAM_PORTDEFINITIONTYPE */
     OMX_IndexParamCompBufferSupplier,       /**< reference: OMX_PARAM_BUFFERSUPPLIERTYPE */
+    OMX_IndexPortEndUnused,
+
     OMX_IndexReservedStartUnused = 0x03000000,
 
     /* Audio parameters and configurations */
@@ -134,6 +137,7 @@
     OMX_IndexParamAudioSmv,                 /**< reference: OMX_AUDIO_PARAM_SMVTYPE */
     OMX_IndexParamAudioVorbis,              /**< reference: OMX_AUDIO_PARAM_VORBISTYPE */
     OMX_IndexParamAudioFlac,                /**< reference: OMX_AUDIO_PARAM_FLACTYPE */
+    OMX_IndexAudioEndUnused,
 
     OMX_IndexConfigAudioMidiImmediateEvent, /**< reference: OMX_AUDIO_CONFIG_MIDIIMMEDIATEEVENTTYPE */
     OMX_IndexConfigAudioMidiControl,        /**< reference: OMX_AUDIO_CONFIG_MIDICONTROLTYPE */
@@ -194,6 +198,7 @@
     OMX_IndexParamVideoSliceFMO,            /**< reference: OMX_VIDEO_PARAM_AVCSLICEFMO */
     OMX_IndexConfigVideoAVCIntraPeriod,     /**< reference: OMX_VIDEO_CONFIG_AVCINTRAPERIOD */
     OMX_IndexConfigVideoNalSize,            /**< reference: OMX_VIDEO_CONFIG_NALSIZE */
+    OMX_IndexVideoEndUnused,
 
     /* Image & Video common Configurations */
     OMX_IndexCommonStartUnused = 0x07000000,
@@ -231,6 +236,7 @@
     OMX_IndexConfigCommonFocusRegion,       /**< reference: OMX_CONFIG_FOCUSREGIONTYPE */
     OMX_IndexConfigCommonFocusStatus,       /**< reference: OMX_PARAM_FOCUSSTATUSTYPE */
     OMX_IndexConfigCommonTransitionEffect,  /**< reference: OMX_CONFIG_TRANSITIONEFFECTTYPE */
+    OMX_IndexCommonEndUnused,
 
     /* Reserved Configuration range */
     OMX_IndexOtherStartUnused = 0x08000000,
diff --git a/include/media/openmax/OMX_IndexExt.h b/include/media/openmax/OMX_IndexExt.h
index b688d1d..5a029d0 100644
--- a/include/media/openmax/OMX_IndexExt.h
+++ b/include/media/openmax/OMX_IndexExt.h
@@ -51,6 +51,7 @@
     OMX_IndexConfigCallbackRequest,                 /**< reference: OMX_CONFIG_CALLBACKREQUESTTYPE */
     OMX_IndexConfigCommitMode,                      /**< reference: OMX_CONFIG_COMMITMODETYPE */
     OMX_IndexConfigCommit,                          /**< reference: OMX_CONFIG_COMMITTYPE */
+    OMX_IndexConfigAndroidVendorExtension,          /**< reference: OMX_CONFIG_VENDOR_EXTENSIONTYPE */
 
     /* Port parameters and configurations */
     OMX_IndexExtPortStartUnused = OMX_IndexKhronosExtensions + 0x00200000,
@@ -62,6 +63,7 @@
     OMX_IndexParamAudioAndroidAacPresentation,      /**< reference: OMX_AUDIO_PARAM_ANDROID_AACPRESENTATIONTYPE */
     OMX_IndexParamAudioAndroidEac3,                 /**< reference: OMX_AUDIO_PARAM_ANDROID_EAC3TYPE */
     OMX_IndexParamAudioProfileQuerySupported,       /**< reference: OMX_AUDIO_PARAM_ANDROID_PROFILETYPE */
+    OMX_IndexExtAudioEndUnused,
 
     /* Image parameters and configurations */
     OMX_IndexExtImageStartUnused = OMX_IndexKhronosExtensions + 0x00500000,
@@ -80,6 +82,10 @@
     OMX_IndexConfigAndroidIntraRefresh,             /**< reference: OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE */
     OMX_IndexParamAndroidVideoTemporalLayering,     /**< reference: OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERINGTYPE */
     OMX_IndexConfigAndroidVideoTemporalLayering,    /**< reference: OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERINGTYPE */
+    OMX_IndexParamMaxFrameDurationForBitrateControl,/**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexParamVideoVp9,                         /**< reference: OMX_VIDEO_PARAM_VP9TYPE */
+    OMX_IndexParamVideoAndroidVp9Encoder,           /**< reference: OMX_VIDEO_PARAM_ANDROID_VP9ENCODERTYPE */
+    OMX_IndexExtVideoEndUnused,
 
     /* Image & Video common configurations */
     OMX_IndexExtCommonStartUnused = OMX_IndexKhronosExtensions + 0x00700000,
@@ -90,6 +96,8 @@
     OMX_IndexConfigPriority,                        /**< reference: OMX_PARAM_U32TYPE */
     OMX_IndexConfigOperatingRate,                   /**< reference: OMX_PARAM_U32TYPE in Q16 format for video and in Hz for audio */
     OMX_IndexParamConsumerUsageBits,                /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigLatency,                         /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexExtOtherEndUnused,
 
     /* Time configurations */
     OMX_IndexExtTimeStartUnused = OMX_IndexKhronosExtensions + 0x00900000,
@@ -97,6 +105,117 @@
     OMX_IndexExtMax = 0x7FFFFFFF
 } OMX_INDEXEXTTYPE;
 
+#define OMX_MAX_STRINGVALUE_SIZE OMX_MAX_STRINGNAME_SIZE
+#define OMX_MAX_ANDROID_VENDOR_PARAMCOUNT 32
+
+typedef enum OMX_ANDROID_VENDOR_VALUETYPE {
+    OMX_AndroidVendorValueInt32 = 0,   /*<< int32_t value */
+    OMX_AndroidVendorValueInt64,       /*<< int64_t value */
+    OMX_AndroidVendorValueString,      /*<< string value */
+    OMX_AndroidVendorValueEndUnused,
+} OMX_ANDROID_VENDOR_VALUETYPE;
+
+/**
+ * Structure describing a single value of an Android vendor extension.
+ *
+ * STRUCTURE MEMBERS:
+ *  cKey        : parameter value name.
+ *  eValueType  : parameter value type
+ *  bSet        : if false, the parameter is not set (for OMX_GetConfig) or is unset (OMX_SetConfig)
+ *                if true, the parameter is set to the corresponding value below
+ *  nInt64      : int64 value
+ *  cString     : string value
+ */
+typedef struct OMX_CONFIG_ANDROID_VENDOR_PARAMTYPE {
+    OMX_U8 cKey[OMX_MAX_STRINGNAME_SIZE];
+    OMX_ANDROID_VENDOR_VALUETYPE eValueType;
+    OMX_BOOL bSet;
+    union {
+        OMX_S32 nInt32;
+        OMX_S64 nInt64;
+        OMX_U8 cString[OMX_MAX_STRINGVALUE_SIZE];
+    };
+} OMX_CONFIG_ANDROID_VENDOR_PARAMTYPE;
+
+/**
+ * OMX_CONFIG_ANDROID_VENDOR_EXTENSIONTYPE is the structure for an Android vendor extension
+ * supported by the component. This structure enumerates the various extension parameters and their
+ * values.
+ *
+ * Android vendor extensions have a name and one or more parameter values - each with a string key -
+ * that are set together. The values are exposed to Android applications via a string key that is
+ * the concatenation of 'vendor', the extension name and the parameter key, each separated by dot
+ * (.), with any trailing '.value' suffix(es) removed (though optionally allowed).
+ *
+ * Extension names and parameter keys are subject to the following rules:
+ *   - Each SHALL contain a set of lowercase alphanumeric (underscore allowed) tags separated by
+ *     dot (.) or dash (-).
+ *   - The first character of the first tag, and any tag following a dot SHALL not start with a
+ *     digit.
+ *   - Tags 'value', 'vendor', 'omx' and 'android' (even if trailed and/or followed by any number
+ *     of underscores) are prohibited in the extension name.
+ *   - Tags 'vendor', 'omx' and 'android' (even if trailed and/or followed by any number
+ *     of underscores) are prohibited in parameter keys.
+ *   - The tag 'value' (even if trailed and/or followed by any number
+ *     of underscores) is prohibited in parameter keys with the following exception:
+ *     the parameter key may be exactly 'value'
+ *   - The parameter key for extensions with a single parameter value SHALL be 'value'
+ *   - No two extensions SHALL have the same name
+ *   - No extension's name SHALL start with another extension's NAME followed by a dot (.)
+ *   - No two parameters of an extension SHALL have the same key
+ *
+ * This config can be used with both OMX_GetConfig and OMX_SetConfig. In the OMX_GetConfig
+ * case, the caller specifies nIndex and nParamSizeUsed. The component fills in cName,
+ * eDir and nParamCount. Additionally, if nParamSizeUsed is not less than nParamCount, the
+ * component fills out the parameter values (nParam) with the current values for each parameter
+ * of the vendor extension.
+ *
+ * The value of nIndex goes from 0 to N-1, where N is the number of Android vendor extensions
+ * supported by the component. The component does not need to report N as the caller can determine
+ * N by enumerating all extensions supported by the component. The component may not support any
+ * extensions. If there are no more extensions, OMX_GetParameter returns OMX_ErrorNoMore. The
+ * component supplies extensions in the order it wants clients to set them.
+ *
+ * The component SHALL return OMX_ErrorNone for all cases where nIndex is less than N (specifically
+ * even in the case of where nParamCount is greater than nParamSizeUsed).
+ *
+ * In the OMX_SetConfig case the field nIndex is ignored. If the component supports an Android
+ * vendor extension with the name in cName, it SHALL configure the parameter values for that
+ * extension according to the parameters in nParam. nParamCount is the number of valid parameters
+ * in the nParam array, and nParamSizeUsed is the size of the nParam array. (nParamSizeUsed
+ * SHALL be at least nParamCount) Parameters that are part of a vendor extension but are not
+ * in the nParam array are assumed to be unset (this is different from not changed).
+ * All parameter values SHALL have distinct keys in nParam (the component can assume that this
+ * is the case. Otherwise, the actual value for the parameters that are multiply defined can
+ * be any of the set values.)
+ *
+ * Return values in case of OMX_SetConfig:
+ *   OMX_ErrorUnsupportedIndex: the component does not support the extension specified by cName
+ *   OMX_ErrorUnsupportedSetting: the component does not support some or any of the parameters
+ *       (names) specified in nParam
+ *   OMX_ErrorBadParameter: the parameter is invalid (e.g. nParamCount is greater than
+ *       nParamSizeUsed, or some parameter value has invalid type)
+ *
+ * STRUCTURE MEMBERS:
+ *  nSize       : size of the structure in bytes
+ *  nVersion    : OMX specification version information
+ *  cName       : name of vendor extension
+ *  nParamCount : the number of parameter values that are part of this vendor extension
+ *  nParamSizeUsed : the size of nParam
+ *                (must be at least 1 and at most OMX_MAX_ANDROID_VENDOR_PARAMCOUNT)
+ *  param       : the parameter values
+ */
+typedef struct OMX_CONFIG_ANDROID_VENDOR_EXTENSIONTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nIndex;
+    OMX_U8  cName[OMX_MAX_STRINGNAME_SIZE];
+    OMX_DIRTYPE eDir;
+    OMX_U32 nParamCount;
+    OMX_U32 nParamSizeUsed;
+    OMX_CONFIG_ANDROID_VENDOR_PARAMTYPE param[1];
+} OMX_CONFIG_ANDROID_VENDOR_EXTENSIONTYPE;
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/include/media/openmax/OMX_VideoExt.h b/include/media/openmax/OMX_VideoExt.h
index 2c02431..128dd2d 100644
--- a/include/media/openmax/OMX_VideoExt.h
+++ b/include/media/openmax/OMX_VideoExt.h
@@ -75,39 +75,6 @@
     OMX_VIDEO_VP8LevelMax = 0x7FFFFFFF
 } OMX_VIDEO_VP8LEVELTYPE;
 
-/** VP9 profiles */
-typedef enum OMX_VIDEO_VP9PROFILETYPE {
-    OMX_VIDEO_VP9Profile0       = 0x1,
-    OMX_VIDEO_VP9Profile1       = 0x2,
-    OMX_VIDEO_VP9Profile2       = 0x4,
-    OMX_VIDEO_VP9Profile3       = 0x8,
-    // HDR profiles also support passing HDR metadata
-    OMX_VIDEO_VP9Profile2HDR    = 0x1000,
-    OMX_VIDEO_VP9Profile3HDR    = 0x2000,
-    OMX_VIDEO_VP9ProfileUnknown = 0x6EFFFFFF,
-    OMX_VIDEO_VP9ProfileMax     = 0x7FFFFFFF
-} OMX_VIDEO_VP9PROFILETYPE;
-
-/** VP9 levels */
-typedef enum OMX_VIDEO_VP9LEVELTYPE {
-    OMX_VIDEO_VP9Level1       = 0x1,
-    OMX_VIDEO_VP9Level11      = 0x2,
-    OMX_VIDEO_VP9Level2       = 0x4,
-    OMX_VIDEO_VP9Level21      = 0x8,
-    OMX_VIDEO_VP9Level3       = 0x10,
-    OMX_VIDEO_VP9Level31      = 0x20,
-    OMX_VIDEO_VP9Level4       = 0x40,
-    OMX_VIDEO_VP9Level41      = 0x80,
-    OMX_VIDEO_VP9Level5       = 0x100,
-    OMX_VIDEO_VP9Level51      = 0x200,
-    OMX_VIDEO_VP9Level52      = 0x400,
-    OMX_VIDEO_VP9Level6       = 0x800,
-    OMX_VIDEO_VP9Level61      = 0x1000,
-    OMX_VIDEO_VP9Level62      = 0x2000,
-    OMX_VIDEO_VP9LevelUnknown = 0x6EFFFFFF,
-    OMX_VIDEO_VP9LevelMax     = 0x7FFFFFFF
-} OMX_VIDEO_VP9LEVELTYPE;
-
 /** VP8 Param */
 typedef struct OMX_VIDEO_PARAM_VP8TYPE {
     OMX_U32 nSize;
@@ -152,7 +119,7 @@
 } OMX_VIDEO_ANDROID_VPXTEMPORALLAYERPATTERNTYPE;
 
 /**
- * Android specific VP8 encoder params
+ * Android specific VP8/VP9 encoder params
  *
  * STRUCT MEMBERS:
  *  nSize                      : Size of the structure in bytes
@@ -182,6 +149,59 @@
     OMX_U32 nMaxQuantizer;
 } OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE;
 
+/** VP9 profiles */
+typedef enum OMX_VIDEO_VP9PROFILETYPE {
+    OMX_VIDEO_VP9Profile0 = 0x1,
+    OMX_VIDEO_VP9Profile1 = 0x2,
+    OMX_VIDEO_VP9Profile2 = 0x4,
+    OMX_VIDEO_VP9Profile3 = 0x8,
+    // HDR profiles also support passing HDR metadata
+    OMX_VIDEO_VP9Profile2HDR = 0x1000,
+    OMX_VIDEO_VP9Profile3HDR = 0x2000,
+    OMX_VIDEO_VP9ProfileUnknown = 0x6EFFFFFF,
+    OMX_VIDEO_VP9ProfileMax = 0x7FFFFFFF
+} OMX_VIDEO_VP9PROFILETYPE;
+
+/** VP9 levels */
+typedef enum OMX_VIDEO_VP9LEVELTYPE {
+    OMX_VIDEO_VP9Level1  = 0x0,
+    OMX_VIDEO_VP9Level11 = 0x1,
+    OMX_VIDEO_VP9Level2  = 0x2,
+    OMX_VIDEO_VP9Level21 = 0x4,
+    OMX_VIDEO_VP9Level3  = 0x8,
+    OMX_VIDEO_VP9Level31 = 0x10,
+    OMX_VIDEO_VP9Level4  = 0x20,
+    OMX_VIDEO_VP9Level41 = 0x40,
+    OMX_VIDEO_VP9Level5  = 0x80,
+    OMX_VIDEO_VP9Level51 = 0x100,
+    OMX_VIDEO_VP9Level52 = 0x200,
+    OMX_VIDEO_VP9Level6  = 0x400,
+    OMX_VIDEO_VP9Level61 = 0x800,
+    OMX_VIDEO_VP9Level62 = 0x1000,
+    OMX_VIDEO_VP9LevelUnknown = 0x6EFFFFFF,
+    OMX_VIDEO_VP9LevelMax = 0x7FFFFFFF
+} OMX_VIDEO_VP9LEVELTYPE;
+
+/**
+* VP9 Parameters.
+*   Encoder specific parameters (decoders should ignore these fields):
+*     - bErrorResilientMode
+*     - nTileRows
+*     - nTileColumns
+*     - bEnableFrameParallelDecoding
+*/
+typedef struct OMX_VIDEO_PARAM_VP9TYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_VIDEO_VP9PROFILETYPE eProfile;
+    OMX_VIDEO_VP9LEVELTYPE eLevel;
+    OMX_BOOL bErrorResilientMode;
+    OMX_U32 nTileRows;
+    OMX_U32 nTileColumns;
+    OMX_BOOL bEnableFrameParallelDecoding;
+} OMX_VIDEO_PARAM_VP9TYPE;
+
 /** HEVC Profile enum type */
 typedef enum OMX_VIDEO_HEVCPROFILETYPE {
     OMX_VIDEO_HEVCProfileUnknown      = 0x0,
diff --git a/include/powermanager/IPowerManager.h b/include/powermanager/IPowerManager.h
index 461fad7..3c81f0f 100644
--- a/include/powermanager/IPowerManager.h
+++ b/include/powermanager/IPowerManager.h
@@ -44,13 +44,15 @@
         NAP                          = IBinder::FIRST_CALL_TRANSACTION + 10,
         IS_INTERACTIVE               = IBinder::FIRST_CALL_TRANSACTION + 11,
         IS_POWER_SAVE_MODE           = IBinder::FIRST_CALL_TRANSACTION + 12,
-        SET_POWER_SAVE_MODE          = IBinder::FIRST_CALL_TRANSACTION + 13,
-        REBOOT                       = IBinder::FIRST_CALL_TRANSACTION + 14,
-        SHUTDOWN                     = IBinder::FIRST_CALL_TRANSACTION + 15,
-        CRASH                        = IBinder::FIRST_CALL_TRANSACTION + 16,
+        GET_POWER_SAVE_STATE         = IBinder::FIRST_CALL_TRANSACTION + 13,
+        SET_POWER_SAVE_MODE          = 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,
+        CRASH                        = IBinder::FIRST_CALL_TRANSACTION + 20,
     };
 
-    DECLARE_META_INTERFACE(PowerManager);
+    DECLARE_META_INTERFACE(PowerManager)
 
     // The parcels created by these methods must be kept in sync with the
     // corresponding methods from IPowerManager.aidl.
diff --git a/include/private/binder b/include/private/binder
new file mode 120000
index 0000000..09e9076
--- /dev/null
+++ b/include/private/binder
@@ -0,0 +1 @@
+../../libs/binder/include/private/binder
\ No newline at end of file
diff --git a/include/private/binder/Static.h b/include/private/binder/Static.h
deleted file mode 100644
index d104646..0000000
--- a/include/private/binder/Static.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2008 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.
- */
-
-// All static variables go here, to control initialization and
-// destruction order in the library.
-
-#include <utils/threads.h>
-
-#include <binder/IBinder.h>
-#include <binder/IMemory.h>
-#include <binder/ProcessState.h>
-#include <binder/IPermissionController.h>
-#include <binder/IServiceManager.h>
-
-namespace android {
-
-// For TextStream.cpp
-extern Vector<int32_t> gTextBuffers;
-
-// For ProcessState.cpp
-extern Mutex gProcessMutex;
-extern sp<ProcessState> gProcess;
-
-// For IServiceManager.cpp
-extern Mutex gDefaultServiceManagerLock;
-extern sp<IServiceManager> gDefaultServiceManager;
-extern sp<IPermissionController> gPermissionController;
-
-}   // namespace android
diff --git a/include/private/binder/binder_module.h b/include/private/binder/binder_module.h
deleted file mode 100644
index a8dd64f..0000000
--- a/include/private/binder/binder_module.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2008 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_MODULE_H_
-#define _BINDER_MODULE_H_
-
-#ifdef __cplusplus
-namespace android {
-#endif
-
-/* obtain structures and constants from the kernel header */
-
-#include <sys/ioctl.h>
-#include <linux/binder.h>
-
-#ifdef __cplusplus
-}   // namespace android
-#endif
-
-#endif // _BINDER_MODULE_H_
diff --git a/include/private/gui/ComposerService.h b/include/private/gui/ComposerService.h
index ff2f9bf..50bd742 100644
--- a/include/private/gui/ComposerService.h
+++ b/include/private/gui/ComposerService.h
@@ -28,7 +28,6 @@
 
 // ---------------------------------------------------------------------------
 
-class IMemoryHeap;
 class ISurfaceComposer;
 
 // ---------------------------------------------------------------------------
diff --git a/include/private/gui/LayerState.h b/include/private/gui/LayerState.h
index 4b3fcc6..307c764 100644
--- a/include/private/gui/LayerState.h
+++ b/include/private/gui/LayerState.h
@@ -24,6 +24,7 @@
 
 #include <ui/Region.h>
 #include <ui/Rect.h>
+#include <gui/IGraphicBufferProducer.h>
 
 namespace android {
 
@@ -56,6 +57,9 @@
         eFinalCropChanged           = 0x00000400,
         eOverrideScalingModeChanged = 0x00000800,
         eGeometryAppliesWithResize  = 0x00001000,
+        eReparentChildren           = 0x00002000,
+        eDetachChildren             = 0x00004000,
+        eRelativeLayerChanged       = 0x00008000
     };
 
     layer_state_t()
@@ -74,16 +78,16 @@
     status_t    read(const Parcel& input);
 
             struct matrix22_t {
-                float   dsdx;
-                float   dtdx;
-                float   dsdy;
-                float   dtdy;
+                float   dsdx{0};
+                float   dtdx{0};
+                float   dtdy{0};
+                float   dsdy{0};
             };
             sp<IBinder>     surface;
             uint32_t        what;
             float           x;
             float           y;
-            uint32_t        z;
+            int32_t         z;
             uint32_t        w;
             uint32_t        h;
             uint32_t        layerStack;
@@ -94,9 +98,15 @@
             matrix22_t      matrix;
             Rect            crop;
             Rect            finalCrop;
-            sp<IBinder>     handle;
+            sp<IBinder>     barrierHandle;
+            sp<IBinder>     reparentHandle;
             uint64_t        frameNumber;
             int32_t         overrideScalingMode;
+
+            sp<IGraphicBufferProducer> barrierGbp;
+
+            sp<IBinder>     relativeLayerHandle;
+
             // non POD must be last. see write/read
             Region          transparentRegion;
 };
diff --git a/include/private/ui/RegionHelper.h b/include/private/ui/RegionHelper.h
index 84eb100..a86c586 100644
--- a/include/private/ui/RegionHelper.h
+++ b/include/private/ui/RegionHelper.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_UI_PRIVATE_REGION_HELPER_H
 #define ANDROID_UI_PRIVATE_REGION_HELPER_H
 
+#include <limits>
 #include <stdint.h>
 #include <sys/types.h>
 
@@ -27,10 +28,10 @@
 class region_operator
 {
 public:
-    typedef typename RECT::value_type TYPE;    
-    static const TYPE max_value = 0x7FFFFFF;
+    typedef typename RECT::value_type TYPE;
+    static const TYPE max_value = std::numeric_limits<TYPE>::max();
 
-    /* 
+    /*
      * Common boolean operations:
      * value is computed as 0b101 op 0b110
      *    other boolean operation are possible, simply compute
@@ -53,20 +54,20 @@
         TYPE dy;
         inline region(const region& rhs) 
             : rects(rhs.rects), count(rhs.count), dx(rhs.dx), dy(rhs.dy) { }
-        inline region(RECT const* r, size_t c) 
-            : rects(r), count(c), dx(), dy() { }
-        inline region(RECT const* r, size_t c, TYPE dx, TYPE dy) 
-            : rects(r), count(c), dx(dx), dy(dy) { }
+        inline region(RECT const* _r, size_t _c)
+            : rects(_r), count(_c), dx(), dy() { }
+        inline region(RECT const* _r, size_t _c, TYPE _dx, TYPE _dy)
+            : rects(_r), count(_c), dx(_dx), dy(_dy) { }
     };
 
     class region_rasterizer {
         friend class region_operator;
         virtual void operator()(const RECT& rect) = 0;
     public:
-        virtual ~region_rasterizer() { };
+        virtual ~region_rasterizer() { }
     };
     
-    inline region_operator(int op, const region& lhs, const region& rhs) 
+    inline region_operator(uint32_t op, const region& lhs, const region& rhs)
         : op_mask(op), spanner(lhs, rhs) 
     {
     }
@@ -79,8 +80,8 @@
             spannerInner.prepare(inside);
             do {
                 TYPE left, right;
-                int inside = spannerInner.next(current.left, current.right);
-                if ((op_mask >> inside) & 1) {
+                int inner_inside = spannerInner.next(current.left, current.right);
+                if ((op_mask >> inner_inside) & 1) {
                     if (current.left < current.right && 
                             current.top < current.bottom) {
                         rasterizer(current);
@@ -162,8 +163,8 @@
         region rhs;
 
     public:
-        inline Spanner(const region& lhs, const region& rhs)
-        : lhs(lhs), rhs(rhs)
+        inline Spanner(const region& _lhs, const region& _rhs)
+        : lhs(_lhs), rhs(_rhs)
         {
             if (lhs.count) {
                 SpannerBase::lhs_head = lhs.rects->top      + lhs.dy;
@@ -223,8 +224,8 @@
         region rhs;
         
     public:
-        inline SpannerInner(const region& lhs, const region& rhs)
-            : lhs(lhs), rhs(rhs) 
+        inline SpannerInner(const region& _lhs, const region& _rhs)
+            : lhs(_lhs), rhs(_rhs)
         {
         }
 
diff --git a/include/ui/ANativeObjectBase.h b/include/ui/ANativeObjectBase.h
index 76e850f..640e34b 100644
--- a/include/ui/ANativeObjectBase.h
+++ b/include/ui/ANativeObjectBase.h
@@ -18,9 +18,7 @@
 #define ANDROID_ANDROID_NATIVES_H
 
 #include <sys/types.h>
-#include <string.h>
 
-#include <hardware/gralloc.h>
 #include <system/window.h>
 
 // ---------------------------------------------------------------------------
diff --git a/include/ui/BufferQueueDefs.h b/include/ui/BufferQueueDefs.h
new file mode 100644
index 0000000..56de181
--- /dev/null
+++ b/include/ui/BufferQueueDefs.h
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_UI_BUFFERQUEUEDEFS_H
+#define ANDROID_UI_BUFFERQUEUEDEFS_H
+
+namespace android {
+    namespace BufferQueueDefs {
+        // BufferQueue will keep track of at most this value of buffers.
+        // Attempts at runtime to increase the number of buffers past this
+        // will fail.
+        static constexpr int NUM_BUFFER_SLOTS = 64;
+    } // namespace BufferQueueDefs
+} // namespace android
+
+#endif
diff --git a/include/ui/ColorSpace.h b/include/ui/ColorSpace.h
new file mode 100644
index 0000000..8ccf6d3
--- /dev/null
+++ b/include/ui/ColorSpace.h
@@ -0,0 +1,305 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_UI_COLOR_SPACE
+#define ANDROID_UI_COLOR_SPACE
+
+#include <array>
+#include <cmath>
+#include <functional>
+#include <memory>
+#include <string>
+
+#include <math/mat3.h>
+#include <math/scalar.h>
+#include <math/vec2.h>
+#include <math/vec3.h>
+
+namespace android {
+
+class ColorSpace {
+public:
+    typedef std::function<float(float)> transfer_function;
+    typedef std::function<float(float)> clamping_function;
+
+    struct TransferParameters {
+        float g = 0.0f;
+        float a = 0.0f;
+        float b = 0.0f;
+        float c = 0.0f;
+        float d = 0.0f;
+        float e = 0.0f;
+        float f = 0.0f;
+    };
+
+    /**
+     * Creates a named color space with the specified RGB->XYZ
+     * conversion matrix. The white point and primaries will be
+     * computed from the supplied matrix.
+     *
+     * The default transfer functions are a linear response x->x
+     * and the default clamping function is a simple saturate
+     * (clamp(x, 0, 1)).
+     */
+    ColorSpace(
+            const std::string& name,
+            const mat3& rgbToXYZ,
+            transfer_function OETF = linearResponse,
+            transfer_function EOTF = linearResponse,
+            clamping_function clamper = saturate<float>
+    ) noexcept;
+
+    /**
+     * Creates a named color space with the specified RGB->XYZ
+     * conversion matrix. The white point and primaries will be
+     * computed from the supplied matrix.
+     *
+     * The transfer functions are defined by the set of supplied
+     * transfer parameters. The default clamping function is a
+     * simple saturate (clamp(x, 0, 1)).
+     */
+    ColorSpace(
+            const std::string& name,
+            const mat3& rgbToXYZ,
+            const TransferParameters parameters,
+            clamping_function clamper = saturate<float>
+    ) noexcept;
+
+    /**
+     * Creates a named color space with the specified RGB->XYZ
+     * conversion matrix. The white point and primaries will be
+     * computed from the supplied matrix.
+     *
+     * The transfer functions are defined by a simple gamma value.
+     * The default clamping function is a saturate (clamp(x, 0, 1)).
+     */
+    ColorSpace(
+            const std::string& name,
+            const mat3& rgbToXYZ,
+            float gamma,
+            clamping_function clamper = saturate<float>
+    ) noexcept;
+
+    /**
+     * Creates a named color space with the specified primaries
+     * and white point. The RGB<>XYZ conversion matrices are
+     * computed from the primaries and white point.
+     *
+     * The default transfer functions are a linear response x->x
+     * and the default clamping function is a simple saturate
+     * (clamp(x, 0, 1)).
+     */
+    ColorSpace(
+            const std::string& name,
+            const std::array<float2, 3>& primaries,
+            const float2& whitePoint,
+            transfer_function OETF = linearResponse,
+            transfer_function EOTF = linearResponse,
+            clamping_function clamper = saturate<float>
+    ) noexcept;
+
+    /**
+     * Creates a named color space with the specified primaries
+     * and white point. The RGB<>XYZ conversion matrices are
+     * computed from the primaries and white point.
+     *
+     * The transfer functions are defined by the set of supplied
+     * transfer parameters. The default clamping function is a
+     * simple saturate (clamp(x, 0, 1)).
+     */
+    ColorSpace(
+            const std::string& name,
+            const std::array<float2, 3>& primaries,
+            const float2& whitePoint,
+            const TransferParameters parameters,
+            clamping_function clamper = saturate<float>
+    ) noexcept;
+
+    /**
+     * Creates a named color space with the specified primaries
+     * and white point. The RGB<>XYZ conversion matrices are
+     * computed from the primaries and white point.
+     *
+     * The transfer functions are defined by a single gamma value.
+     * The default clamping function is a saturate (clamp(x, 0, 1)).
+     */
+    ColorSpace(
+            const std::string& name,
+            const std::array<float2, 3>& primaries,
+            const float2& whitePoint,
+            float gamma,
+            clamping_function clamper = saturate<float>
+    ) noexcept;
+
+    ColorSpace() noexcept = delete;
+
+    /**
+     * Encodes the supplied RGB value using this color space's
+     * opto-electronic transfer function.
+     */
+    constexpr float3 fromLinear(const float3& v) const noexcept {
+        return apply(v, mOETF);
+    }
+
+    /**
+     * Decodes the supplied RGB value using this color space's
+     * electro-optical transfer function.
+     */
+    constexpr float3 toLinear(const float3& v) const noexcept {
+        return apply(v, mEOTF);
+    }
+
+    /**
+     * Converts the supplied XYZ value to RGB. The returned value
+     * is encoded with this color space's opto-electronic transfer
+     * function and clamped by this color space's clamping function.
+     */
+    constexpr float3 xyzToRGB(const float3& xyz) const noexcept {
+        return apply(fromLinear(mXYZtoRGB * xyz), mClamper);
+    }
+
+    /**
+     * Converts the supplied RGB value to XYZ. The input RGB value
+     * is decoded using this color space's electro-optical function
+     * before being converted to XYZ.
+     */
+    constexpr float3 rgbToXYZ(const float3& rgb) const noexcept {
+        return mRGBtoXYZ * toLinear(rgb);
+    }
+
+    constexpr const std::string& getName() const noexcept {
+        return mName;
+    }
+
+    constexpr const mat3& getRGBtoXYZ() const noexcept {
+        return mRGBtoXYZ;
+    }
+
+    constexpr const mat3& getXYZtoRGB() const noexcept {
+        return mXYZtoRGB;
+    }
+
+    constexpr const transfer_function& getOETF() const noexcept {
+        return mOETF;
+    }
+
+    constexpr const transfer_function& getEOTF() const noexcept {
+        return mEOTF;
+    }
+
+    constexpr const clamping_function& getClamper() const noexcept {
+        return mClamper;
+    }
+
+    constexpr const std::array<float2, 3>& getPrimaries() const noexcept {
+        return mPrimaries;
+    }
+
+    constexpr const float2& getWhitePoint() const noexcept {
+        return mWhitePoint;
+    }
+
+    constexpr const TransferParameters& getTransferParameters() const noexcept {
+        return mParameters;
+    }
+
+    /**
+     * Converts the supplied XYZ value to xyY.
+     */
+    static constexpr float2 xyY(const float3& XYZ) {
+        return XYZ.xy / dot(XYZ, float3{1});
+    }
+
+    /**
+     * Converts the supplied xyY value to XYZ.
+     */
+    static constexpr float3 XYZ(const float3& xyY) {
+        return float3{(xyY.x * xyY.z) / xyY.y, xyY.z, ((1 - xyY.x - xyY.y) * xyY.z) / xyY.y};
+    }
+
+    static const ColorSpace sRGB();
+    static const ColorSpace linearSRGB();
+    static const ColorSpace extendedSRGB();
+    static const ColorSpace linearExtendedSRGB();
+    static const ColorSpace NTSC();
+    static const ColorSpace BT709();
+    static const ColorSpace BT2020();
+    static const ColorSpace AdobeRGB();
+    static const ColorSpace ProPhotoRGB();
+    static const ColorSpace DisplayP3();
+    static const ColorSpace DCIP3();
+    static const ColorSpace ACES();
+    static const ColorSpace ACEScg();
+
+    // Creates a NxNxN 3D LUT, where N is the specified size (min=2, max=256)
+    // The 3D lookup coordinates map to the RGB components: u=R, v=G, w=B
+    // The generated 3D LUT is meant to be used as a 3D texture and its Y
+    // 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);
+
+private:
+    static constexpr mat3 computeXYZMatrix(
+            const std::array<float2, 3>& primaries, const float2& whitePoint);
+
+    static constexpr float linearResponse(float v) {
+        return v;
+    }
+
+    std::string mName;
+
+    mat3 mRGBtoXYZ;
+    mat3 mXYZtoRGB;
+
+    TransferParameters mParameters;
+    transfer_function mOETF;
+    transfer_function mEOTF;
+    clamping_function mClamper;
+
+    std::array<float2, 3> mPrimaries;
+    float2 mWhitePoint;
+};
+
+class ColorSpaceConnector {
+public:
+    ColorSpaceConnector(const ColorSpace& src, const ColorSpace& dst) noexcept;
+
+    constexpr const ColorSpace& getSource() const noexcept { return mSource; }
+    constexpr const ColorSpace& getDestination() const noexcept { return mDestination; }
+
+    constexpr const mat3& getTransform() const noexcept { return mTransform; }
+
+    constexpr float3 transform(const float3& v) const noexcept {
+        float3 linear = mSource.toLinear(apply(v, mSource.getClamper()));
+        return apply(mDestination.fromLinear(mTransform * linear), mDestination.getClamper());
+    }
+
+    constexpr float3 transformLinear(const float3& v) const noexcept {
+        float3 linear = apply(v, mSource.getClamper());
+        return apply(mTransform * linear, mDestination.getClamper());
+    }
+
+private:
+    ColorSpace mSource;
+    ColorSpace mDestination;
+    mat3 mTransform;
+};
+
+}; // namespace android
+
+#endif // ANDROID_UI_COLOR_SPACE
diff --git a/include/ui/DebugUtils.h b/include/ui/DebugUtils.h
new file mode 100644
index 0000000..8483808
--- /dev/null
+++ b/include/ui/DebugUtils.h
@@ -0,0 +1,27 @@
+/*
+ * 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
+
+#include <system/graphics.h>
+
+#include <string>
+
+std::string decodeStandard(android_dataspace dataspace);
+std::string decodeTransfer(android_dataspace dataspace);
+std::string decodeRange(android_dataspace dataspace);
+std::string dataspaceDetails(android_dataspace dataspace);
+std::string decodeColorMode(android_color_mode colormode);
diff --git a/include/ui/DisplayInfo.h b/include/ui/DisplayInfo.h
index 799944f..94caf6b 100644
--- a/include/ui/DisplayInfo.h
+++ b/include/ui/DisplayInfo.h
@@ -19,23 +19,22 @@
 
 #include <stdint.h>
 #include <sys/types.h>
-#include <utils/Timers.h>
 
-#include <ui/PixelFormat.h>
+#include <utils/Timers.h>
 
 namespace android {
 
 struct DisplayInfo {
-    uint32_t w;
-    uint32_t h;
-    float xdpi;
-    float ydpi;
-    float fps;
-    float density;
-    uint8_t orientation;
-    bool secure;
-    nsecs_t appVsyncOffset;
-    nsecs_t presentationDeadline;
+    uint32_t w{0};
+    uint32_t h{0};
+    float xdpi{0};
+    float ydpi{0};
+    float fps{0};
+    float density{0};
+    uint8_t orientation{0};
+    bool secure{false};
+    nsecs_t appVsyncOffset{0};
+    nsecs_t presentationDeadline{0};
 };
 
 /* Display orientations as defined in Surface.java and ISurfaceComposer.h. */
diff --git a/include/ui/DisplayStatInfo.h b/include/ui/DisplayStatInfo.h
index 0549a83..09543ec 100644
--- a/include/ui/DisplayStatInfo.h
+++ b/include/ui/DisplayStatInfo.h
@@ -22,8 +22,8 @@
 namespace android {
 
 struct DisplayStatInfo {
-    nsecs_t vsyncTime;
-    nsecs_t vsyncPeriod;
+    nsecs_t vsyncTime{0};
+    nsecs_t vsyncPeriod{0};
 };
 
 }; // namespace android
diff --git a/include/ui/Fence.h b/include/ui/Fence.h
index 48a7aa3..37811bc 100644
--- a/include/ui/Fence.h
+++ b/include/ui/Fence.h
@@ -18,21 +18,15 @@
 #define ANDROID_FENCE_H
 
 #include <stdint.h>
-#include <sys/types.h>
 
-#include <ui/ANativeObjectBase.h>
-#include <ui/PixelFormat.h>
-#include <ui/Rect.h>
 #include <utils/Flattenable.h>
-#include <utils/String8.h>
+#include <utils/RefBase.h>
 #include <utils/Timers.h>
 
-#include <experimental/optional>
-
-struct ANativeWindowBuffer;
-
 namespace android {
 
+class String8;
+
 // ===========================================================================
 // Fence
 // ===========================================================================
@@ -42,6 +36,11 @@
 {
 public:
     static const sp<Fence> NO_FENCE;
+    static constexpr nsecs_t SIGNAL_TIME_PENDING = INT64_MAX;
+    static constexpr nsecs_t SIGNAL_TIME_INVALID = -1;
+    static inline bool isValidTimestamp(nsecs_t time) {
+        return time >= 0 && time < INT64_MAX;
+    }
 
     // TIMEOUT_NEVER may be passed to the wait method to indicate that it
     // should wait indefinitely for the fence to signal.
@@ -55,7 +54,13 @@
     // Construct a new Fence object to manage a given fence file descriptor.
     // When the new Fence object is destructed the file descriptor will be
     // closed.
-    Fence(int fenceFd);
+    explicit Fence(int fenceFd);
+
+    // Not copyable or movable.
+    Fence(const Fence& rhs) = delete;
+    Fence& operator=(const Fence& rhs) = delete;
+    Fence(Fence&& rhs) = delete;
+    Fence& operator=(Fence&& rhs) = delete;
 
     // Check whether the Fence has an open fence file descriptor. Most Fence
     // methods treat an invalid file descriptor just like a valid fence that
@@ -94,30 +99,33 @@
 
     // getSignalTime returns the system monotonic clock time at which the
     // fence transitioned to the signaled state.  If the fence is not signaled
-    // then INT64_MAX is returned.  If the fence is invalid or if an error
-    // occurs then -1 is returned.
+    // then SIGNAL_TIME_PENDING is returned.  If the fence is invalid or if an
+    // error occurs then SIGNAL_TIME_INVALID is returned.
     nsecs_t getSignalTime() const;
 
-#if __cplusplus > 201103L
-    // hasSignaled returns whether the fence has signaled yet. Prefer this to
+    enum class Status {
+        Invalid,     // Fence is invalid
+        Unsignaled,  // Fence is valid but has not yet signaled
+        Signaled,    // Fence is valid and has signaled
+    };
+
+    // getStatus() returns whether the fence has signaled yet. Prefer this to
     // getSignalTime() or wait() if all you care about is whether the fence has
-    // signaled. Returns an optional bool, which will have a value if there was
-    // no error.
-    inline std::experimental::optional<bool> hasSignaled() {
+    // signaled.
+    inline Status getStatus() {
         // The sync_wait call underlying wait() has been measured to be
         // significantly faster than the sync_fence_info call underlying
         // getSignalTime(), which might otherwise appear to be the more obvious
         // way to check whether a fence has signaled.
         switch (wait(0)) {
             case NO_ERROR:
-                return true;
+                return Status::Signaled;
             case -ETIME:
-                return false;
+                return Status::Unsignaled;
             default:
-                return {};
+                return Status::Invalid;
         }
     }
-#endif
 
     // Flattenable interface
     size_t getFlattenedSize() const;
@@ -130,11 +138,6 @@
     friend class LightRefBase<Fence>;
     ~Fence();
 
-    // Disallow copying
-    Fence(const Fence& rhs);
-    Fence& operator = (const Fence& rhs);
-    const Fence& operator = (const Fence& rhs) const;
-
     int mFenceFd;
 };
 
diff --git a/include/ui/FenceTime.h b/include/ui/FenceTime.h
new file mode 100644
index 0000000..871fcf2
--- /dev/null
+++ b/include/ui/FenceTime.h
@@ -0,0 +1,208 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_FENCE_TIME_H
+#define ANDROID_FENCE_TIME_H
+
+#include <ui/Fence.h>
+#include <utils/Flattenable.h>
+#include <utils/Timers.h>
+
+#include <atomic>
+#include <mutex>
+#include <queue>
+#include <unordered_map>
+
+namespace android {
+
+class FenceToFenceTimeMap;
+
+// A wrapper around fence that only implements isValid and getSignalTime.
+// It automatically closes the fence in a thread-safe manner once the signal
+// time is known.
+class FenceTime {
+friend class FenceToFenceTimeMap;
+public:
+    // An atomic snapshot of the FenceTime that is flattenable.
+    //
+    // This class is needed because the FenceTime class may not stay
+    // consistent for all steps of the flattening process.
+    //
+    // Not thread safe.
+    struct Snapshot : public Flattenable<Snapshot> {
+        enum class State {
+            EMPTY,
+            FENCE,
+            SIGNAL_TIME,
+        };
+
+        Snapshot() = default;  // Creates an empty snapshot.
+        explicit Snapshot(const sp<Fence>& fence);
+        explicit Snapshot(nsecs_t signalTime);
+
+        // Movable.
+        Snapshot(Snapshot&& src) = default;
+        Snapshot& operator=(Snapshot&& src) = default;
+        // Not copyable.
+        Snapshot(const Snapshot& src) = delete;
+        Snapshot& operator=(const Snapshot&& src) = delete;
+
+        // Flattenable implementation.
+        size_t getFlattenedSize() const;
+        size_t getFdCount() const;
+        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);
+
+        State state{State::EMPTY};
+        sp<Fence> fence{Fence::NO_FENCE};
+        nsecs_t signalTime{Fence::SIGNAL_TIME_INVALID};
+    };
+
+    static const std::shared_ptr<FenceTime> NO_FENCE;
+
+    explicit FenceTime(const sp<Fence>& fence);
+    explicit FenceTime(sp<Fence>&& fence);
+
+    // Passing in Fence::SIGNAL_TIME_PENDING is not allowed.
+    // Doing so will convert the signalTime to Fence::SIGNAL_TIME_INVALID.
+    explicit FenceTime(nsecs_t signalTime);
+
+    // Do not allow default construction. Share NO_FENCE or explicitly construct
+    // with Fence::SIGNAL_TIME_INVALID instead.
+    FenceTime() = delete;
+
+    // Do not allow copy, assign, or move. Use a shared_ptr to share the
+    // signalTime result. Or use getSnapshot() if a thread-safe copy is really
+    // needed.
+    FenceTime(const FenceTime&) = delete;
+    FenceTime(FenceTime&&) = delete;
+    FenceTime& operator=(const FenceTime&) = delete;
+    FenceTime& operator=(FenceTime&&) = delete;
+
+    // This method should only be called when replacing the fence with
+    // a signalTime. Since this is an indirect way of setting the signal time
+    // of a fence, the snapshot should come from a trusted source.
+    void applyTrustedSnapshot(const Snapshot& src);
+
+    bool isValid() const;
+
+    // Attempts to get the timestamp from the Fence if the timestamp isn't
+    // already cached. Otherwise, it returns the cached value.
+    nsecs_t getSignalTime();
+
+    // Gets the cached timestamp without attempting to query the Fence.
+    nsecs_t getCachedSignalTime() const;
+
+    // Returns a snapshot of the FenceTime in its current state.
+    Snapshot getSnapshot() const;
+
+    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.
+    FenceTime(const sp<Fence>& fence, bool forceValidForTest);
+
+    enum class State {
+        VALID,
+        INVALID,
+        FORCED_VALID_FOR_TEST,
+    };
+
+    const State mState{State::INVALID};
+
+    // mMutex guards mFence and mSignalTime.
+    // mSignalTime is also atomic since it is sometimes read outside the lock
+    // for quick checks.
+    mutable std::mutex mMutex;
+    sp<Fence> mFence{Fence::NO_FENCE};
+    std::atomic<nsecs_t> mSignalTime{Fence::SIGNAL_TIME_INVALID};
+};
+
+// A queue of FenceTimes that are expected to signal in FIFO order.
+// Only maintains a queue of weak pointers so it doesn't keep references
+// to Fences on its own.
+//
+// Can be used to get the signal time of a fence and close its file descriptor
+// without making a syscall for every fence later in the timeline.
+// Additionally, since the FenceTime caches the timestamp internally,
+// other timelines that reference the same FenceTime can avoid the syscall.
+//
+// FenceTimeline only keeps track of a limited number of entries to avoid
+// growing unbounded. Users of FenceTime must make sure they can work even
+// if FenceTimeline did nothing. i.e. they should eventually call
+// Fence::getSignalTime(), not only Fence::getCachedSignalTime().
+//
+// push() and updateSignalTimes() are safe to call simultaneously from
+// different threads.
+class FenceTimeline {
+public:
+    static constexpr size_t MAX_ENTRIES = 64;
+
+    void push(const std::shared_ptr<FenceTime>& fence);
+    void updateSignalTimes();
+
+private:
+    mutable std::mutex mMutex;
+    std::queue<std::weak_ptr<FenceTime>> mQueue;
+};
+
+// Used by test code to create or get FenceTimes for a given Fence.
+//
+// By design, Fences cannot be signaled from user space. However, this class
+// allows test code to set the apparent signalTime of a Fence and
+// have it be visible to all FenceTimes. Release code should not use
+// FenceToFenceTimeMap.
+//
+// FenceToFenceTimeMap keeps a weak reference to the FenceTime and automatically
+// garbage collects entries every time a new FenceTime is created to avoid
+// leaks. This prevents us from having to make the Fence destructor
+// automatically notify that the underlying fence has been destroyed, which
+// would affect release code paths. Garbage collecting so often is inefficient,
+// but acceptable for testing.
+//
+// Since FenceTimes maintain a strong reference to underlying Fences, there
+// should not be any aliasing issues where a new Fence happens to have the same
+// address as a previous Fence; the previous entry will be garbage collected
+// before the new one is added.
+class FenceToFenceTimeMap {
+public:
+    // Create a new FenceTime with that wraps the provided Fence.
+    std::shared_ptr<FenceTime> createFenceTimeForTest(const sp<Fence>& fence);
+
+    // Signals all FenceTimes created through this class that are wrappers
+    // around |fence|.
+    void signalAllForTest(const sp<Fence>& fence, nsecs_t signalTime);
+
+private:
+    // Cleans up the entries that no longer have a strong reference.
+    void garbageCollectLocked();
+
+    mutable std::mutex mMutex;
+    std::unordered_map<Fence*, std::vector<std::weak_ptr<FenceTime>>> mMap;
+};
+
+
+}; // namespace android
+
+#endif // ANDROID_FENCE_TIME_H
diff --git a/include/ui/FloatRect.h b/include/ui/FloatRect.h
new file mode 100644
index 0000000..270675c
--- /dev/null
+++ b/include/ui/FloatRect.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+namespace android {
+
+class FloatRect {
+public:
+    FloatRect() = default;
+    constexpr FloatRect(float _left, float _top, float _right, float _bottom)
+      : left(_left), top(_top), right(_right), bottom(_bottom) {}
+
+    float getWidth() const { return right - left; }
+    float getHeight() const { return bottom - top; }
+
+    float left = 0.0f;
+    float top = 0.0f;
+    float right = 0.0f;
+    float bottom = 0.0f;
+};
+
+inline bool operator==(const FloatRect& a, const FloatRect& b) {
+    return a.left == b.left && a.top == b.top && a.right == b.right && a.bottom == b.bottom;
+}
+
+}  // namespace android
diff --git a/include/ui/FrameStats.h b/include/ui/FrameStats.h
index 6bfe635..bc9d3ec 100644
--- a/include/ui/FrameStats.h
+++ b/include/ui/FrameStats.h
@@ -25,7 +25,7 @@
 
 class FrameStats : public LightFlattenable<FrameStats> {
 public:
-    FrameStats() : refreshPeriodNano(0) {};
+    FrameStats() : refreshPeriodNano(0) {}
 
     /*
      * Approximate refresh time, in nanoseconds.
diff --git a/include/ui/Gralloc1.h b/include/ui/Gralloc1.h
deleted file mode 100644
index cf8c173..0000000
--- a/include/ui/Gralloc1.h
+++ /dev/null
@@ -1,238 +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_UI_GRALLOC1_H
-#define ANDROID_UI_GRALLOC1_H
-
-#define GRALLOC1_LOG_TAG "Gralloc1"
-
-#include <ui/Gralloc1On0Adapter.h>
-
-#include <unordered_set>
-
-namespace std {
-    template <>
-    struct hash<gralloc1_capability_t> {
-        size_t operator()(gralloc1_capability_t capability) const {
-            return std::hash<int32_t>()(static_cast<int32_t>(capability));
-        }
-    };
-}
-
-namespace android {
-
-class Fence;
-class GraphicBuffer;
-
-namespace Gralloc1 {
-
-class Device;
-
-class Descriptor {
-public:
-    Descriptor(Device& device, gralloc1_buffer_descriptor_t deviceId)
-      : mShimDevice(device),
-        mDeviceId(deviceId),
-        mWidth(0),
-        mHeight(0),
-        mFormat(static_cast<android_pixel_format_t>(0)),
-        mProducerUsage(GRALLOC1_PRODUCER_USAGE_NONE),
-        mConsumerUsage(GRALLOC1_CONSUMER_USAGE_NONE) {}
-
-    ~Descriptor();
-
-    gralloc1_buffer_descriptor_t getDeviceId() const { return mDeviceId; }
-
-    gralloc1_error_t setDimensions(uint32_t width, uint32_t height);
-    gralloc1_error_t setFormat(android_pixel_format_t format);
-    gralloc1_error_t setProducerUsage(gralloc1_producer_usage_t usage);
-    gralloc1_error_t setConsumerUsage(gralloc1_consumer_usage_t usage);
-
-private:
-    Device& mShimDevice;
-    const gralloc1_buffer_descriptor_t mDeviceId;
-
-    uint32_t mWidth;
-    uint32_t mHeight;
-    android_pixel_format_t mFormat;
-    gralloc1_producer_usage_t mProducerUsage;
-    gralloc1_consumer_usage_t mConsumerUsage;
-
-}; // Descriptor
-
-class Device {
-    friend class Gralloc1::Descriptor;
-
-public:
-    Device(gralloc1_device_t* device);
-
-    bool hasCapability(gralloc1_capability_t capability) const;
-
-    std::string dump();
-
-    std::shared_ptr<Descriptor> createDescriptor();
-
-    gralloc1_error_t getStride(buffer_handle_t buffer, uint32_t* outStride);
-
-    gralloc1_error_t allocate(
-            const std::vector<std::shared_ptr<const Descriptor>>& descriptors,
-            std::vector<buffer_handle_t>* outBuffers);
-    gralloc1_error_t allocate(
-            const std::shared_ptr<const Descriptor>& descriptor,
-            gralloc1_backing_store_t id, buffer_handle_t* outBuffer);
-
-    gralloc1_error_t retain(buffer_handle_t buffer);
-    gralloc1_error_t retain(const GraphicBuffer* buffer);
-
-    gralloc1_error_t release(buffer_handle_t buffer);
-
-    gralloc1_error_t getNumFlexPlanes(buffer_handle_t buffer,
-            uint32_t* outNumPlanes);
-
-    gralloc1_error_t lock(buffer_handle_t buffer,
-            gralloc1_producer_usage_t producerUsage,
-            gralloc1_consumer_usage_t consumerUsage,
-            const gralloc1_rect_t* accessRegion, void** outData,
-            const sp<Fence>& acquireFence);
-    gralloc1_error_t lockFlex(buffer_handle_t buffer,
-            gralloc1_producer_usage_t producerUsage,
-            gralloc1_consumer_usage_t consumerUsage,
-            const gralloc1_rect_t* accessRegion,
-            struct android_flex_layout* outData, const sp<Fence>& acquireFence);
-    gralloc1_error_t lockYCbCr(buffer_handle_t buffer,
-            gralloc1_producer_usage_t producerUsage,
-            gralloc1_consumer_usage_t consumerUsage,
-            const gralloc1_rect_t* accessRegion, struct android_ycbcr* outData,
-            const sp<Fence>& acquireFence);
-
-    gralloc1_error_t unlock(buffer_handle_t buffer, sp<Fence>* outFence);
-
-private:
-    std::unordered_set<gralloc1_capability_t> loadCapabilities();
-
-    bool loadFunctions();
-
-    template <typename LockType, typename OutType>
-    gralloc1_error_t lockHelper(LockType pfn, buffer_handle_t buffer,
-            gralloc1_producer_usage_t producerUsage,
-            gralloc1_consumer_usage_t consumerUsage,
-            const gralloc1_rect_t* accessRegion, OutType* outData,
-            const sp<Fence>& acquireFence) {
-        int32_t intError = pfn(mDevice, buffer,
-                static_cast<uint64_t>(producerUsage),
-                static_cast<uint64_t>(consumerUsage), accessRegion, outData,
-                acquireFence->dup());
-        return static_cast<gralloc1_error_t>(intError);
-    }
-
-    gralloc1_device_t* const mDevice;
-
-    const std::unordered_set<gralloc1_capability_t> mCapabilities;
-
-    template <typename PFN, gralloc1_function_descriptor_t descriptor>
-    struct FunctionLoader {
-        FunctionLoader() : pfn(nullptr) {}
-
-        bool load(gralloc1_device_t* device, bool errorIfNull) {
-            gralloc1_function_pointer_t rawPointer =
-                    device->getFunction(device, descriptor);
-            pfn = reinterpret_cast<PFN>(rawPointer);
-            if (errorIfNull && !rawPointer) {
-                ALOG(LOG_ERROR, GRALLOC1_LOG_TAG,
-                        "Failed to load function pointer %d", descriptor);
-            }
-            return rawPointer != nullptr;
-        }
-
-        template <typename ...Args>
-        typename std::result_of<PFN(Args...)>::type operator()(Args... args) {
-            return pfn(args...);
-        }
-
-        PFN pfn;
-    };
-
-    // Function pointers
-    struct Functions {
-        FunctionLoader<GRALLOC1_PFN_DUMP, GRALLOC1_FUNCTION_DUMP> dump;
-        FunctionLoader<GRALLOC1_PFN_CREATE_DESCRIPTOR,
-                GRALLOC1_FUNCTION_CREATE_DESCRIPTOR> createDescriptor;
-        FunctionLoader<GRALLOC1_PFN_DESTROY_DESCRIPTOR,
-                GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR> destroyDescriptor;
-        FunctionLoader<GRALLOC1_PFN_SET_CONSUMER_USAGE,
-                GRALLOC1_FUNCTION_SET_CONSUMER_USAGE> setConsumerUsage;
-        FunctionLoader<GRALLOC1_PFN_SET_DIMENSIONS,
-                GRALLOC1_FUNCTION_SET_DIMENSIONS> setDimensions;
-        FunctionLoader<GRALLOC1_PFN_SET_FORMAT,
-                GRALLOC1_FUNCTION_SET_FORMAT> setFormat;
-        FunctionLoader<GRALLOC1_PFN_SET_PRODUCER_USAGE,
-                GRALLOC1_FUNCTION_SET_PRODUCER_USAGE> setProducerUsage;
-        FunctionLoader<GRALLOC1_PFN_GET_BACKING_STORE,
-                GRALLOC1_FUNCTION_GET_BACKING_STORE> getBackingStore;
-        FunctionLoader<GRALLOC1_PFN_GET_CONSUMER_USAGE,
-                GRALLOC1_FUNCTION_GET_CONSUMER_USAGE> getConsumerUsage;
-        FunctionLoader<GRALLOC1_PFN_GET_DIMENSIONS,
-                GRALLOC1_FUNCTION_GET_DIMENSIONS> getDimensions;
-        FunctionLoader<GRALLOC1_PFN_GET_FORMAT,
-                GRALLOC1_FUNCTION_GET_FORMAT> getFormat;
-        FunctionLoader<GRALLOC1_PFN_GET_PRODUCER_USAGE,
-                GRALLOC1_FUNCTION_GET_PRODUCER_USAGE> getProducerUsage;
-        FunctionLoader<GRALLOC1_PFN_GET_STRIDE,
-                GRALLOC1_FUNCTION_GET_STRIDE> getStride;
-        FunctionLoader<GRALLOC1_PFN_ALLOCATE,
-                GRALLOC1_FUNCTION_ALLOCATE> allocate;
-        FunctionLoader<GRALLOC1_PFN_RETAIN,
-                GRALLOC1_FUNCTION_RETAIN> retain;
-        FunctionLoader<GRALLOC1_PFN_RELEASE,
-                GRALLOC1_FUNCTION_RELEASE> release;
-        FunctionLoader<GRALLOC1_PFN_GET_NUM_FLEX_PLANES,
-                GRALLOC1_FUNCTION_GET_NUM_FLEX_PLANES> getNumFlexPlanes;
-        FunctionLoader<GRALLOC1_PFN_LOCK,
-                GRALLOC1_FUNCTION_LOCK> lock;
-        FunctionLoader<GRALLOC1_PFN_LOCK_FLEX,
-                GRALLOC1_FUNCTION_LOCK_FLEX> lockFlex;
-        FunctionLoader<GRALLOC1_PFN_LOCK_YCBCR,
-                GRALLOC1_FUNCTION_LOCK_YCBCR> lockYCbCr;
-        FunctionLoader<GRALLOC1_PFN_UNLOCK,
-                GRALLOC1_FUNCTION_UNLOCK> unlock;
-
-        // Adapter-only functions
-        FunctionLoader<GRALLOC1_PFN_RETAIN_GRAPHIC_BUFFER,
-                GRALLOC1_FUNCTION_RETAIN_GRAPHIC_BUFFER> retainGraphicBuffer;
-        FunctionLoader<GRALLOC1_PFN_ALLOCATE_WITH_ID,
-                GRALLOC1_FUNCTION_ALLOCATE_WITH_ID> allocateWithId;
-    } mFunctions;
-
-}; // class android::Gralloc1::Device
-
-class Loader
-{
-public:
-    Loader();
-    ~Loader();
-
-    std::unique_ptr<Device> getDevice();
-
-private:
-    static std::unique_ptr<Gralloc1On0Adapter> mAdapter;
-    std::unique_ptr<Device> mDevice;
-};
-
-} // namespace android::Gralloc1
-
-} // namespace android
-
-#endif
diff --git a/include/ui/Gralloc1On0Adapter.h b/include/ui/Gralloc1On0Adapter.h
deleted file mode 100644
index 97c9a89..0000000
--- a/include/ui/Gralloc1On0Adapter.h
+++ /dev/null
@@ -1,481 +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_UI_GRALLOC_1_ON_0_ADAPTER_H
-#define ANDROID_UI_GRALLOC_1_ON_0_ADAPTER_H
-
-#include <ui/Fence.h>
-#include <ui/GraphicBuffer.h>
-
-#include <hardware/gralloc1.h>
-
-#include <mutex>
-#include <string>
-#include <unordered_map>
-#include <vector>
-
-struct gralloc_module_t;
-
-// This is not an "official" capability (i.e., it is not found in gralloc1.h),
-// but we will use it to detect that we are running through the adapter, which
-// is capable of collaborating with GraphicBuffer such that queries on a
-// buffer_handle_t succeed
-static const auto GRALLOC1_CAPABILITY_ON_ADAPTER =
-        static_cast<gralloc1_capability_t>(GRALLOC1_LAST_CAPABILITY + 1);
-
-static const auto GRALLOC1_FUNCTION_RETAIN_GRAPHIC_BUFFER =
-        static_cast<gralloc1_function_descriptor_t>(GRALLOC1_LAST_FUNCTION + 1);
-static const auto GRALLOC1_FUNCTION_ALLOCATE_WITH_ID =
-        static_cast<gralloc1_function_descriptor_t>(GRALLOC1_LAST_FUNCTION + 2);
-static const auto GRALLOC1_FUNCTION_LOCK_YCBCR =
-        static_cast<gralloc1_function_descriptor_t>(GRALLOC1_LAST_FUNCTION + 3);
-static const auto GRALLOC1_LAST_ADAPTER_FUNCTION = GRALLOC1_FUNCTION_LOCK_YCBCR;
-
-typedef gralloc1_error_t (*GRALLOC1_PFN_RETAIN_GRAPHIC_BUFFER)(
-        gralloc1_device_t* device, const android::GraphicBuffer* buffer);
-typedef gralloc1_error_t (*GRALLOC1_PFN_ALLOCATE_WITH_ID)(
-        gralloc1_device_t* device, gralloc1_buffer_descriptor_t descriptor,
-        gralloc1_backing_store_t id, buffer_handle_t* outBuffer);
-typedef int32_t /*gralloc1_error_t*/ (*GRALLOC1_PFN_LOCK_YCBCR)(
-        gralloc1_device_t* device, buffer_handle_t buffer,
-        uint64_t /*gralloc1_producer_usage_t*/ producerUsage,
-        uint64_t /*gralloc1_consumer_usage_t*/ consumerUsage,
-        const gralloc1_rect_t* accessRegion, struct android_ycbcr* outYCbCr,
-        int32_t acquireFence);
-
-namespace android {
-
-class Gralloc1On0Adapter : public gralloc1_device_t
-{
-public:
-    Gralloc1On0Adapter(const hw_module_t* module);
-    ~Gralloc1On0Adapter();
-
-    gralloc1_device_t* getDevice() {
-        return static_cast<gralloc1_device_t*>(this);
-    }
-
-private:
-    static inline Gralloc1On0Adapter* getAdapter(gralloc1_device_t* device) {
-        return static_cast<Gralloc1On0Adapter*>(device);
-    }
-
-    // getCapabilities
-
-    void doGetCapabilities(uint32_t* outCount,
-            int32_t* /*gralloc1_capability_t*/ outCapabilities);
-    static void getCapabilitiesHook(gralloc1_device_t* device,
-            uint32_t* outCount,
-            int32_t* /*gralloc1_capability_t*/ outCapabilities) {
-        getAdapter(device)->doGetCapabilities(outCount, outCapabilities);
-    };
-
-    // getFunction
-
-    gralloc1_function_pointer_t doGetFunction(
-            int32_t /*gralloc1_function_descriptor_t*/ descriptor);
-    static gralloc1_function_pointer_t getFunctionHook(
-            gralloc1_device_t* device,
-            int32_t /*gralloc1_function_descriptor_t*/ descriptor) {
-        return getAdapter(device)->doGetFunction(descriptor);
-    }
-
-    // dump
-
-    void dump(uint32_t* outSize, char* outBuffer);
-    static void dumpHook(gralloc1_device_t* device, uint32_t* outSize,
-            char* outBuffer) {
-        return getAdapter(device)->dump(outSize, outBuffer);
-    }
-    std::string mCachedDump;
-
-    // Buffer descriptor lifecycle functions
-
-    class Descriptor;
-
-    gralloc1_error_t createDescriptor(
-            gralloc1_buffer_descriptor_t* outDescriptor);
-    static int32_t createDescriptorHook(gralloc1_device_t* device,
-            gralloc1_buffer_descriptor_t* outDescriptor) {
-        auto error = getAdapter(device)->createDescriptor(outDescriptor);
-        return static_cast<int32_t>(error);
-    }
-
-    gralloc1_error_t destroyDescriptor(gralloc1_buffer_descriptor_t descriptor);
-    static int32_t destroyDescriptorHook(gralloc1_device_t* device,
-            gralloc1_buffer_descriptor_t descriptor) {
-        auto error = getAdapter(device)->destroyDescriptor(descriptor);
-        return static_cast<int32_t>(error);
-    }
-
-    // Buffer descriptor modification functions
-
-    struct Descriptor : public std::enable_shared_from_this<Descriptor> {
-        Descriptor(Gralloc1On0Adapter* adapter,
-                gralloc1_buffer_descriptor_t id)
-          : adapter(adapter),
-            id(id),
-            width(0),
-            height(0),
-            format(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
-            producerUsage(GRALLOC1_PRODUCER_USAGE_NONE),
-            consumerUsage(GRALLOC1_CONSUMER_USAGE_NONE) {}
-
-        gralloc1_error_t setDimensions(uint32_t w, uint32_t h) {
-            width = w;
-            height = h;
-            return GRALLOC1_ERROR_NONE;
-        }
-
-        gralloc1_error_t setFormat(int32_t f) {
-            format = f;
-            return GRALLOC1_ERROR_NONE;
-        }
-
-        gralloc1_error_t setProducerUsage(gralloc1_producer_usage_t usage) {
-            producerUsage = usage;
-            return GRALLOC1_ERROR_NONE;
-        }
-
-        gralloc1_error_t setConsumerUsage(gralloc1_consumer_usage_t usage) {
-            consumerUsage = usage;
-            return GRALLOC1_ERROR_NONE;
-        }
-
-        Gralloc1On0Adapter* const adapter;
-        const gralloc1_buffer_descriptor_t id;
-
-        uint32_t width;
-        uint32_t height;
-        int32_t format;
-        gralloc1_producer_usage_t producerUsage;
-        gralloc1_consumer_usage_t consumerUsage;
-    };
-
-    template <typename ...Args>
-    static int32_t callDescriptorFunction(gralloc1_device_t* device,
-            gralloc1_buffer_descriptor_t descriptorId,
-            gralloc1_error_t (Descriptor::*member)(Args...), Args... args) {
-        auto descriptor = getAdapter(device)->getDescriptor(descriptorId);
-        if (!descriptor) {
-            return static_cast<int32_t>(GRALLOC1_ERROR_BAD_DESCRIPTOR);
-        }
-        auto error = ((*descriptor).*member)(std::forward<Args>(args)...);
-        return static_cast<int32_t>(error);
-    }
-
-    static int32_t setConsumerUsageHook(gralloc1_device_t* device,
-            gralloc1_buffer_descriptor_t descriptorId, uint64_t intUsage) {
-        auto usage = static_cast<gralloc1_consumer_usage_t>(intUsage);
-        return callDescriptorFunction(device, descriptorId,
-                &Descriptor::setConsumerUsage, usage);
-    }
-
-    static int32_t setDimensionsHook(gralloc1_device_t* device,
-            gralloc1_buffer_descriptor_t descriptorId, uint32_t width,
-            uint32_t height) {
-        return callDescriptorFunction(device, descriptorId,
-                &Descriptor::setDimensions, width, height);
-    }
-
-    static int32_t setFormatHook(gralloc1_device_t* device,
-            gralloc1_buffer_descriptor_t descriptorId, int32_t format) {
-        return callDescriptorFunction(device, descriptorId,
-                &Descriptor::setFormat, format);
-    }
-
-    static int32_t setProducerUsageHook(gralloc1_device_t* device,
-            gralloc1_buffer_descriptor_t descriptorId, uint64_t intUsage) {
-        auto usage = static_cast<gralloc1_producer_usage_t>(intUsage);
-        return callDescriptorFunction(device, descriptorId,
-                &Descriptor::setProducerUsage, usage);
-    }
-
-    // Buffer handle query functions
-
-    class Buffer {
-    public:
-        Buffer(buffer_handle_t handle, gralloc1_backing_store_t store,
-                const Descriptor& descriptor, uint32_t stride,
-                bool wasAllocated);
-
-        buffer_handle_t getHandle() const { return mHandle; }
-
-        void retain() { ++mReferenceCount; }
-
-        // Returns true if the reference count has dropped to 0, indicating that
-        // the buffer needs to be released
-        bool release() { return --mReferenceCount == 0; }
-
-        bool wasAllocated() const { return mWasAllocated; }
-
-        gralloc1_error_t getBackingStore(
-                gralloc1_backing_store_t* outStore) const {
-            *outStore = mStore;
-            return GRALLOC1_ERROR_NONE;
-        }
-
-        gralloc1_error_t getConsumerUsage(
-                gralloc1_consumer_usage_t* outUsage) const {
-            *outUsage = mDescriptor.consumerUsage;
-            return GRALLOC1_ERROR_NONE;
-        }
-
-        gralloc1_error_t getDimensions(uint32_t* outWidth,
-                uint32_t* outHeight) const {
-            *outWidth = mDescriptor.width;
-            *outHeight = mDescriptor.height;
-            return GRALLOC1_ERROR_NONE;
-        }
-
-        gralloc1_error_t getFormat(int32_t* outFormat) const {
-            *outFormat = mDescriptor.format;
-            return GRALLOC1_ERROR_NONE;
-        }
-
-        gralloc1_error_t getNumFlexPlanes(uint32_t* outNumPlanes) const {
-            // TODO: This is conservative, and we could do better by examining
-            // the format, but it won't hurt anything for now
-            *outNumPlanes = 4;
-            return GRALLOC1_ERROR_NONE;
-        }
-
-        gralloc1_error_t getProducerUsage(
-                gralloc1_producer_usage_t* outUsage) const {
-            *outUsage = mDescriptor.producerUsage;
-            return GRALLOC1_ERROR_NONE;
-        }
-
-        gralloc1_error_t getStride(uint32_t* outStride) const {
-            *outStride = mStride;
-            return GRALLOC1_ERROR_NONE;
-        }
-
-    private:
-
-        const buffer_handle_t mHandle;
-        size_t mReferenceCount;
-
-        // Since we're adapting to gralloc0, there will always be a 1:1
-        // correspondence between buffer handles and backing stores, and the
-        // backing store ID will be the same as the GraphicBuffer unique ID
-        const gralloc1_backing_store_t mStore;
-
-        const Descriptor mDescriptor;
-        const uint32_t mStride;
-
-        // Whether this buffer allocated in this process (as opposed to just
-        // being retained here), which determines whether to free or unregister
-        // the buffer when this Buffer is released
-        const bool mWasAllocated;
-    };
-
-    template <typename ...Args>
-    static int32_t callBufferFunction(gralloc1_device_t* device,
-            buffer_handle_t bufferHandle,
-            gralloc1_error_t (Buffer::*member)(Args...) const, Args... args) {
-        auto buffer = getAdapter(device)->getBuffer(bufferHandle);
-        if (!buffer) {
-            return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE);
-        }
-        auto error = ((*buffer).*member)(std::forward<Args>(args)...);
-        return static_cast<int32_t>(error);
-    }
-
-    template <typename MF, MF memFunc, typename ...Args>
-    static int32_t bufferHook(gralloc1_device_t* device,
-            buffer_handle_t bufferHandle, Args... args) {
-        return Gralloc1On0Adapter::callBufferFunction(device, bufferHandle,
-                memFunc, std::forward<Args>(args)...);
-    }
-
-    static int32_t getConsumerUsageHook(gralloc1_device_t* device,
-            buffer_handle_t bufferHandle, uint64_t* outUsage) {
-        auto usage = GRALLOC1_CONSUMER_USAGE_NONE;
-        auto error = callBufferFunction(device, bufferHandle,
-                &Buffer::getConsumerUsage, &usage);
-        if (error != GRALLOC1_ERROR_NONE) {
-            *outUsage = static_cast<uint64_t>(usage);
-        }
-        return error;
-    }
-
-    static int32_t getProducerUsageHook(gralloc1_device_t* device,
-            buffer_handle_t bufferHandle, uint64_t* outUsage) {
-        auto usage = GRALLOC1_PRODUCER_USAGE_NONE;
-        auto error = callBufferFunction(device, bufferHandle,
-                &Buffer::getProducerUsage, &usage);
-        if (error != GRALLOC1_ERROR_NONE) {
-            *outUsage = static_cast<uint64_t>(usage);
-        }
-        return error;
-    }
-
-    // Buffer management functions
-
-    // We don't provide GRALLOC1_FUNCTION_ALLOCATE, since this should always be
-    // called through GRALLOC1_FUNCTION_ALLOCATE_WITH_ID
-    gralloc1_error_t allocate(
-            const std::shared_ptr<Descriptor>& descriptor,
-            gralloc1_backing_store_t id,
-            buffer_handle_t* outBufferHandle);
-    static gralloc1_error_t allocateWithIdHook(gralloc1_device_t* device,
-            gralloc1_buffer_descriptor_t descriptors,
-            gralloc1_backing_store_t id, buffer_handle_t* outBuffer);
-
-    gralloc1_error_t retain(const std::shared_ptr<Buffer>& buffer);
-    gralloc1_error_t release(const std::shared_ptr<Buffer>& buffer);
-
-    // Member function pointer 'member' will either be retain or release
-    template <gralloc1_error_t (Gralloc1On0Adapter::*member)(
-            const std::shared_ptr<Buffer>& buffer)>
-    static int32_t managementHook(gralloc1_device_t* device,
-            buffer_handle_t bufferHandle) {
-        auto adapter = getAdapter(device);
-
-        auto buffer = adapter->getBuffer(bufferHandle);
-        if (!buffer) {
-            return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE);
-        }
-
-        auto error = ((*adapter).*member)(buffer);
-        return static_cast<int32_t>(error);
-    }
-
-    gralloc1_error_t retain(const GraphicBuffer* buffer);
-    static gralloc1_error_t retainGraphicBufferHook(gralloc1_device_t* device,
-            const GraphicBuffer* buffer) {
-        auto adapter = getAdapter(device);
-        return adapter->retain(buffer);
-    }
-
-    // Buffer access functions
-
-    gralloc1_error_t lock(const std::shared_ptr<Buffer>& buffer,
-            gralloc1_producer_usage_t producerUsage,
-            gralloc1_consumer_usage_t consumerUsage,
-            const gralloc1_rect_t& accessRegion, void** outData,
-            const sp<Fence>& acquireFence);
-    gralloc1_error_t lockFlex(const std::shared_ptr<Buffer>& buffer,
-            gralloc1_producer_usage_t producerUsage,
-            gralloc1_consumer_usage_t consumerUsage,
-            const gralloc1_rect_t& accessRegion,
-            struct android_flex_layout* outFlex,
-            const sp<Fence>& acquireFence);
-    gralloc1_error_t lockYCbCr(const std::shared_ptr<Buffer>& buffer,
-            gralloc1_producer_usage_t producerUsage,
-            gralloc1_consumer_usage_t consumerUsage,
-            const gralloc1_rect_t& accessRegion,
-            struct android_ycbcr* outFlex,
-            const sp<Fence>& acquireFence);
-
-    template <typename OUT, gralloc1_error_t (Gralloc1On0Adapter::*member)(
-            const std::shared_ptr<Buffer>&, gralloc1_producer_usage_t,
-            gralloc1_consumer_usage_t, const gralloc1_rect_t&, OUT*,
-            const sp<Fence>&)>
-    static int32_t lockHook(gralloc1_device_t* device,
-            buffer_handle_t bufferHandle,
-            uint64_t /*gralloc1_producer_usage_t*/ uintProducerUsage,
-            uint64_t /*gralloc1_consumer_usage_t*/ uintConsumerUsage,
-            const gralloc1_rect_t* accessRegion, OUT* outData,
-            int32_t acquireFenceFd) {
-        auto adapter = getAdapter(device);
-
-        // Exactly one of producer and consumer usage must be *_USAGE_NONE,
-        // but we can't check this until the upper levels of the framework
-        // correctly distinguish between producer and consumer usage
-        /*
-        bool hasProducerUsage =
-                uintProducerUsage != GRALLOC1_PRODUCER_USAGE_NONE;
-        bool hasConsumerUsage =
-                uintConsumerUsage != GRALLOC1_CONSUMER_USAGE_NONE;
-        if (hasProducerUsage && hasConsumerUsage ||
-                !hasProducerUsage && !hasConsumerUsage) {
-            return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE);
-        }
-        */
-
-        auto producerUsage =
-                static_cast<gralloc1_producer_usage_t>(uintProducerUsage);
-        auto consumerUsage =
-                static_cast<gralloc1_consumer_usage_t>(uintConsumerUsage);
-
-        if (!outData) {
-            const auto producerCpuUsage = GRALLOC1_PRODUCER_USAGE_CPU_READ |
-                    GRALLOC1_PRODUCER_USAGE_CPU_WRITE;
-            if (producerUsage & producerCpuUsage != 0) {
-                return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE);
-            }
-            if (consumerUsage & GRALLOC1_CONSUMER_USAGE_CPU_READ != 0) {
-                return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE);
-            }
-        }
-
-        auto buffer = adapter->getBuffer(bufferHandle);
-        if (!buffer) {
-            return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE);
-        }
-
-        if (!accessRegion) {
-            ALOGE("accessRegion is null");
-            return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE);
-        }
-
-        sp<Fence> acquireFence{new Fence(acquireFenceFd)};
-        auto error = ((*adapter).*member)(buffer, producerUsage, consumerUsage,
-                *accessRegion, outData, acquireFence);
-        return static_cast<int32_t>(error);
-    }
-
-    gralloc1_error_t unlock(const std::shared_ptr<Buffer>& buffer,
-            sp<Fence>* outReleaseFence);
-    static int32_t unlockHook(gralloc1_device_t* device,
-            buffer_handle_t bufferHandle, int32_t* outReleaseFenceFd) {
-        auto adapter = getAdapter(device);
-
-        auto buffer = adapter->getBuffer(bufferHandle);
-        if (!buffer) {
-            return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE);
-        }
-
-        sp<Fence> releaseFence = Fence::NO_FENCE;
-        auto error = adapter->unlock(buffer, &releaseFence);
-        if (error == GRALLOC1_ERROR_NONE) {
-            *outReleaseFenceFd = releaseFence->dup();
-        }
-        return static_cast<int32_t>(error);
-    }
-
-    // Adapter internals
-    const gralloc_module_t* mModule;
-    uint8_t mMinorVersion;
-    alloc_device_t* mDevice;
-
-    std::shared_ptr<Descriptor> getDescriptor(
-            gralloc1_buffer_descriptor_t descriptorId);
-    std::shared_ptr<Buffer> getBuffer(buffer_handle_t bufferHandle);
-
-    static std::atomic<gralloc1_buffer_descriptor_t> sNextBufferDescriptorId;
-    std::mutex mDescriptorMutex;
-    std::unordered_map<gralloc1_buffer_descriptor_t,
-            std::shared_ptr<Descriptor>> mDescriptors;
-    std::mutex mBufferMutex;
-    std::unordered_map<buffer_handle_t, std::shared_ptr<Buffer>> mBuffers;
-};
-
-} // namespace android
-
-#endif
diff --git a/include/ui/Gralloc2.h b/include/ui/Gralloc2.h
new file mode 100644
index 0000000..f826b92
--- /dev/null
+++ b/include/ui/Gralloc2.h
@@ -0,0 +1,126 @@
+/*
+ * 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_GRALLOC2_H
+#define ANDROID_UI_GRALLOC2_H
+
+#include <string>
+
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <system/window.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+namespace Gralloc2 {
+
+using hardware::graphics::allocator::V2_0::IAllocator;
+using hardware::graphics::common::V1_0::BufferUsage;
+using hardware::graphics::common::V1_0::PixelFormat;
+using hardware::graphics::mapper::V2_0::BufferDescriptor;
+using hardware::graphics::mapper::V2_0::Error;
+using hardware::graphics::mapper::V2_0::IMapper;
+using hardware::graphics::mapper::V2_0::YCbCrLayout;
+
+// A wrapper to IMapper
+class Mapper {
+public:
+    Mapper();
+
+    Error createDescriptor(
+            const IMapper::BufferDescriptorInfo& descriptorInfo,
+            BufferDescriptor* outDescriptor) const;
+
+    // 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;
+
+    void freeBuffer(buffer_handle_t bufferHandle) const;
+
+    // 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;
+
+    // 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;
+
+    // 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;
+
+private:
+    sp<IMapper> mMapper;
+};
+
+// A wrapper to IAllocator
+class Allocator {
+public:
+    // An allocator relies on a mapper, and that mapper must be alive at all
+    // time.
+    Allocator(const Mapper& mapper);
+
+    std::string dumpDebugInfo() const;
+
+    /*
+     * 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;
+
+    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);
+    }
+
+private:
+    const Mapper& mMapper;
+    sp<IAllocator> mAllocator;
+};
+
+} // namespace Gralloc2
+
+} // namespace android
+
+#endif // ANDROID_UI_GRALLOC2_H
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index 3e127a1..4b82cff 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -20,13 +20,15 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <string>
+
 #include <ui/ANativeObjectBase.h>
 #include <ui/PixelFormat.h>
 #include <ui/Rect.h>
 #include <utils/Flattenable.h>
 #include <utils/RefBase.h>
 
-#include <string>
+#include <hardware/gralloc.h>
 
 struct ANativeWindowBuffer;
 
@@ -70,20 +72,69 @@
         USAGE_CURSOR            = GRALLOC_USAGE_CURSOR,
     };
 
+    static sp<GraphicBuffer> from(ANativeWindowBuffer *);
+
+
+    // Create a GraphicBuffer to be unflatten'ed into or be reallocated.
     GraphicBuffer();
 
-    // creates w * h buffer
+    // Create a GraphicBuffer by allocating and managing a buffer internally.
+    // This function is privileged.  See reallocate for details.
+    GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+            uint32_t inLayerCount, uint64_t inUsage,
+            std::string requestorName = "<Unknown>");
+
+    // Create a GraphicBuffer from an existing handle.
+    enum HandleWrapMethod : uint8_t {
+        // Wrap and use the handle directly.  It assumes the handle has been
+        // registered and never fails.  The handle must have a longer lifetime
+        // than this wrapping GraphicBuffer.
+        //
+        // This can be used when, for example, you want to wrap a handle that
+        // is already managed by another GraphicBuffer.
+        WRAP_HANDLE,
+
+        // Take ownership of the handle and use it directly.  It assumes the
+        // handle has been registered and never fails.
+        //
+        // This can be used to manage an already registered handle with
+        // GraphicBuffer.
+        TAKE_HANDLE,
+
+        // Take onwership of an unregistered handle and use it directly.  It
+        // can fail when the buffer does not register.  There is no ownership
+        // transfer on failures.
+        //
+        // This can be used to, for example, create a GraphicBuffer from a
+        // handle returned by Parcel::readNativeHandle.
+        TAKE_UNREGISTERED_HANDLE,
+
+        // Make a clone of the handle and use the cloned handle.  It can fail
+        // when cloning fails or when the buffer does not register.  There is
+        // never ownership transfer.
+        //
+        // This can be used to create a GraphicBuffer from a handle that
+        // 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);
+
+    // 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(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>");
 
-    // create a buffer from an existing handle
-    GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
-            uint32_t inUsage, uint32_t inStride, native_handle_t* inHandle,
-            bool keepOwnership);
-
-    // create a buffer from an existing ANativeWindowBuffer
-    GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership);
-
     // return status
     status_t initCheck() const;
 
@@ -92,6 +143,7 @@
     uint32_t getStride() const          { return static_cast<uint32_t>(stride); }
     uint32_t getUsage() const           { return static_cast<uint32_t>(usage); }
     PixelFormat getPixelFormat() const  { return format; }
+    uint32_t getLayerCount() const      { return static_cast<uint32_t>(layerCount); }
     Rect getBounds() const              { return Rect(width, height); }
     uint64_t getId() const              { return mId; }
 
@@ -100,11 +152,14 @@
         mGenerationNumber = generation;
     }
 
+    // This function is privileged.  It requires access to the allocator
+    // device or service, which usually involves adding suitable selinux
+    // rules.
     status_t reallocate(uint32_t inWidth, uint32_t inHeight,
-            PixelFormat inFormat, uint32_t inUsage);
+            PixelFormat inFormat, uint32_t inLayerCount, uint64_t inUsage);
 
     bool needsReallocation(uint32_t inWidth, uint32_t inHeight,
-            PixelFormat inFormat, uint32_t inUsage);
+            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);
@@ -116,6 +171,8 @@
     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);
     status_t lockAsyncYCbCr(uint32_t inUsage, android_ycbcr *ycbcr,
             int fenceFd);
     status_t lockAsyncYCbCr(uint32_t inUsage, const Rect& rect,
@@ -159,18 +216,20 @@
     GraphicBuffer& operator = (const GraphicBuffer& rhs);
     const GraphicBuffer& operator = (const GraphicBuffer& rhs) const;
 
-    status_t initSize(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
-            uint32_t inUsage, std::string requestorName);
+    status_t initWithSize(uint32_t inWidth, uint32_t inHeight,
+            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);
 
     void free_handle();
 
     GraphicBufferMapper& mBufferMapper;
     ssize_t mInitCheck;
 
-    // If we're wrapping another buffer then this reference will make sure it
-    // doesn't get freed.
-    sp<ANativeWindowBuffer> mWrappedBuffer;
-
     uint64_t mId;
 
     // Stores the generation number of this buffer. If this number does not
diff --git a/include/ui/GraphicBufferAllocator.h b/include/ui/GraphicBufferAllocator.h
index 28d0238..fe99de1 100644
--- a/include/ui/GraphicBufferAllocator.h
+++ b/include/ui/GraphicBufferAllocator.h
@@ -20,48 +20,38 @@
 
 #include <stdint.h>
 
+#include <memory>
+#include <string>
+
 #include <cutils/native_handle.h>
 
+#include <system/window.h>
+
+#include <ui/PixelFormat.h>
+
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
-#include <utils/threads.h>
+#include <utils/Mutex.h>
 #include <utils/Singleton.h>
 
-#include <ui/Gralloc1.h>
-#include <ui/PixelFormat.h>
-
 namespace android {
 
-class Gralloc1Loader;
+namespace Gralloc2 {
+class Allocator;
+}
+
+class GraphicBufferMapper;
 class String8;
 
 class GraphicBufferAllocator : public Singleton<GraphicBufferAllocator>
 {
 public:
-    enum {
-        USAGE_SW_READ_NEVER     = GRALLOC1_CONSUMER_USAGE_CPU_READ_NEVER,
-        USAGE_SW_READ_RARELY    = GRALLOC1_CONSUMER_USAGE_CPU_READ,
-        USAGE_SW_READ_OFTEN     = GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN,
-        USAGE_SW_READ_MASK      = GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN,
-
-        USAGE_SW_WRITE_NEVER    = GRALLOC1_PRODUCER_USAGE_CPU_WRITE_NEVER,
-        USAGE_SW_WRITE_RARELY   = GRALLOC1_PRODUCER_USAGE_CPU_WRITE,
-        USAGE_SW_WRITE_OFTEN    = GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN,
-        USAGE_SW_WRITE_MASK     = GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN,
-
-        USAGE_SOFTWARE_MASK     = USAGE_SW_READ_MASK|USAGE_SW_WRITE_MASK,
-
-        USAGE_HW_TEXTURE        = GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE,
-        USAGE_HW_RENDER         = GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET,
-        USAGE_HW_2D             = 0x00000400, // Deprecated
-        USAGE_HW_MASK           = 0x00071F00, // Deprecated
-    };
-
     static inline GraphicBufferAllocator& get() { return getInstance(); }
 
     status_t allocate(uint32_t w, uint32_t h, PixelFormat format,
-            uint32_t usage, buffer_handle_t* handle, uint32_t* stride,
-            uint64_t graphicBufferId, std::string requestorName);
+            uint32_t layerCount, uint64_t usage,
+            buffer_handle_t* handle, uint32_t* stride, uint64_t graphicBufferId,
+            std::string requestorName);
 
     status_t free(buffer_handle_t handle);
 
@@ -74,7 +64,8 @@
         uint32_t height;
         uint32_t stride;
         PixelFormat format;
-        uint32_t usage;
+        uint32_t layerCount;
+        uint64_t usage;
         size_t size;
         std::string requestorName;
     };
@@ -86,8 +77,8 @@
     GraphicBufferAllocator();
     ~GraphicBufferAllocator();
 
-    std::unique_ptr<Gralloc1::Loader> mLoader;
-    std::unique_ptr<Gralloc1::Device> mDevice;
+    GraphicBufferMapper& mMapper;
+    const std::unique_ptr<const Gralloc2::Allocator> mAllocator;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/include/ui/GraphicBufferMapper.h b/include/ui/GraphicBufferMapper.h
index a25809c..e0702e9 100644
--- a/include/ui/GraphicBufferMapper.h
+++ b/include/ui/GraphicBufferMapper.h
@@ -20,14 +20,24 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <ui/Gralloc1.h>
+#include <memory>
 
 #include <utils/Singleton.h>
 
+
+// Needed by code that still uses the GRALLOC_USAGE_* constants.
+// when/if we get rid of gralloc, we should provide aliases or fix call sites.
+#include <hardware/gralloc.h>
+
+
 namespace android {
 
 // ---------------------------------------------------------------------------
 
+namespace Gralloc2 {
+class Mapper;
+}
+
 class Rect;
 
 class GraphicBufferMapper : public Singleton<GraphicBufferMapper>
@@ -35,10 +45,12 @@
 public:
     static inline GraphicBufferMapper& get() { return getInstance(); }
 
-    status_t registerBuffer(buffer_handle_t handle);
-    status_t registerBuffer(const GraphicBuffer* buffer);
+    // The imported outHandle must be freed with freeBuffer when no longer
+    // needed. rawHandle is owned by the caller.
+    status_t importBuffer(buffer_handle_t rawHandle,
+            buffer_handle_t* outHandle);
 
-    status_t unregisterBuffer(buffer_handle_t handle);
+    status_t freeBuffer(buffer_handle_t handle);
 
     status_t lock(buffer_handle_t handle,
             uint32_t usage, const Rect& bounds, void** vaddr);
@@ -51,19 +63,27 @@
     status_t lockAsync(buffer_handle_t handle,
             uint32_t usage, 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);
+
     status_t lockAsyncYCbCr(buffer_handle_t handle,
             uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr,
             int fenceFd);
 
     status_t unlockAsync(buffer_handle_t handle, int *fenceFd);
 
+    const Gralloc2::Mapper& getGrallocMapper() const
+    {
+        return *mMapper;
+    }
+
 private:
     friend class Singleton<GraphicBufferMapper>;
 
     GraphicBufferMapper();
 
-    std::unique_ptr<Gralloc1::Loader> mLoader;
-    std::unique_ptr<Gralloc1::Device> mDevice;
+    const std::unique_ptr<const Gralloc2::Mapper> mMapper;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/include/ui/GraphicsEnv.h b/include/ui/GraphicsEnv.h
new file mode 100644
index 0000000..7817076
--- /dev/null
+++ b/include/ui/GraphicsEnv.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_UI_GRAPHICS_ENV_H
+#define ANDROID_UI_GRAPHICS_ENV_H 1
+
+#include <string>
+
+struct android_namespace_t;
+
+namespace android {
+
+class GraphicsEnv {
+public:
+    static GraphicsEnv& getInstance();
+
+    // 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);
+    android_namespace_t* getDriverNamespace();
+
+private:
+    GraphicsEnv() = default;
+    std::string mDriverPath;
+    android_namespace_t* mDriverNamespace = 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/include/ui/HdrCapabilities.h b/include/ui/HdrCapabilities.h
index a7cd5fb..925aa1b 100644
--- a/include/ui/HdrCapabilities.h
+++ b/include/ui/HdrCapabilities.h
@@ -17,11 +17,15 @@
 #ifndef ANDROID_UI_HDR_CAPABILTIES_H
 #define ANDROID_UI_HDR_CAPABILTIES_H
 
-#include <binder/Parcelable.h>
+#include <stdint.h>
+
+#include <vector>
+
+#include <utils/Flattenable.h>
 
 namespace android {
 
-class HdrCapabilities : public Parcelable
+class HdrCapabilities : public LightFlattenable<HdrCapabilities>
 {
 public:
     HdrCapabilities(const std::vector<int32_t /*android_hdr_t*/>& types,
@@ -32,8 +36,8 @@
         mMinLuminance(minLuminance) {}
 
     // Make this move-constructable and move-assignable
-    HdrCapabilities(HdrCapabilities&& other) = default;
-    HdrCapabilities& operator=(HdrCapabilities&& other) = default;
+    HdrCapabilities(HdrCapabilities&& other);
+    HdrCapabilities& operator=(HdrCapabilities&& other);
 
     HdrCapabilities()
       : mSupportedHdrTypes(),
@@ -41,7 +45,7 @@
         mMaxAverageLuminance(-1.0f),
         mMinLuminance(-1.0f) {}
 
-    virtual ~HdrCapabilities() = default;
+    ~HdrCapabilities();
 
     const std::vector<int32_t /*android_hdr_t*/>& getSupportedHdrTypes() const {
         return mSupportedHdrTypes;
@@ -50,9 +54,11 @@
     float getDesiredMaxAverageLuminance() const { return mMaxAverageLuminance; }
     float getDesiredMinLuminance() const { return mMinLuminance; }
 
-    // Parcelable interface
-    virtual status_t writeToParcel(Parcel* parcel) const override;
-    virtual status_t readFromParcel(const Parcel* parcel) override;
+    // Flattenable protocol
+    bool isFixedSize() const { return false; }
+    size_t getFlattenedSize() const;
+    status_t flatten(void* buffer, size_t size) const;
+    status_t unflatten(void const* buffer, size_t size);
 
 private:
     std::vector<int32_t /*android_hdr_t*/> mSupportedHdrTypes;
diff --git a/include/ui/PixelFormat.h b/include/ui/PixelFormat.h
index f26fecb..02773d9 100644
--- a/include/ui/PixelFormat.h
+++ b/include/ui/PixelFormat.h
@@ -53,13 +53,15 @@
 
     // real pixel formats supported for rendering -----------------------------
 
-    PIXEL_FORMAT_RGBA_8888   = HAL_PIXEL_FORMAT_RGBA_8888,   // 4x8-bit RGBA
-    PIXEL_FORMAT_RGBX_8888   = HAL_PIXEL_FORMAT_RGBX_8888,   // 4x8-bit RGB0
-    PIXEL_FORMAT_RGB_888     = HAL_PIXEL_FORMAT_RGB_888,     // 3x8-bit RGB
-    PIXEL_FORMAT_RGB_565     = HAL_PIXEL_FORMAT_RGB_565,     // 16-bit RGB
-    PIXEL_FORMAT_BGRA_8888   = HAL_PIXEL_FORMAT_BGRA_8888,   // 4x8-bit BGRA
-    PIXEL_FORMAT_RGBA_5551   = 6,                            // 16-bit ARGB
-    PIXEL_FORMAT_RGBA_4444   = 7,                            // 16-bit ARGB
+    PIXEL_FORMAT_RGBA_8888    = HAL_PIXEL_FORMAT_RGBA_8888,    // 4x8-bit RGBA
+    PIXEL_FORMAT_RGBX_8888    = HAL_PIXEL_FORMAT_RGBX_8888,    // 4x8-bit RGB0
+    PIXEL_FORMAT_RGB_888      = HAL_PIXEL_FORMAT_RGB_888,      // 3x8-bit RGB
+    PIXEL_FORMAT_RGB_565      = HAL_PIXEL_FORMAT_RGB_565,      // 16-bit RGB
+    PIXEL_FORMAT_BGRA_8888    = HAL_PIXEL_FORMAT_BGRA_8888,    // 4x8-bit BGRA
+    PIXEL_FORMAT_RGBA_5551    = 6,                             // 16-bit ARGB
+    PIXEL_FORMAT_RGBA_4444    = 7,                             // 16-bit ARGB
+    PIXEL_FORMAT_RGBA_FP16    = HAL_PIXEL_FORMAT_RGBA_FP16,    // 64-bit RGBA
+    PIXEL_FORMAT_RGBA_1010102 = HAL_PIXEL_FORMAT_RGBA_1010102, // 32-bit RGBA
 };
 
 typedef int32_t PixelFormat;
diff --git a/include/ui/Point.h b/include/ui/Point.h
index 1d7f64d..d050ede 100644
--- a/include/ui/Point.h
+++ b/include/ui/Point.h
@@ -34,7 +34,7 @@
     // Default constructor doesn't initialize the Point
     inline Point() {
     }
-    inline Point(int x, int y) : x(x), y(y) {
+    inline Point(int _x, int _y) : x(_x), y(_y) {
     }
 
     inline bool operator == (const Point& rhs) const {
diff --git a/include/ui/Rect.h b/include/ui/Rect.h
index a8513a9..b50e4ec 100644
--- a/include/ui/Rect.h
+++ b/include/ui/Rect.h
@@ -20,6 +20,9 @@
 #include <utils/Flattenable.h>
 #include <utils/Log.h>
 #include <utils/TypeHelpers.h>
+#include <log/log.h>
+
+#include <ui/FloatRect.h>
 #include <ui/Point.h>
 
 #include <android/rect.h>
@@ -42,13 +45,9 @@
     template <typename T>
     inline Rect(T w, T h) {
         if (w > INT32_MAX) {
-            ALOG(LOG_WARN, "Rect",
-                    "Width %u too large for Rect class, clamping", w);
             w = INT32_MAX;
         }
         if (h > INT32_MAX) {
-            ALOG(LOG_WARN, "Rect",
-                    "Height %u too large for Rect class, clamping", h);
             h = INT32_MAX;
         }
         left = top = 0;
@@ -177,11 +176,15 @@
     // this calculates (Region(*this) - exclude).bounds() efficiently
     Rect reduce(const Rect& exclude) const;
 
-
     // for backward compatibility
     inline int32_t width() const { return getWidth(); }
     inline int32_t height() const { return getHeight(); }
     inline void set(const Rect& rhs) { operator = (rhs); }
+
+    FloatRect toFloatRect() const {
+        return {static_cast<float>(left), static_cast<float>(top),
+                static_cast<float>(right), static_cast<float>(bottom)};
+    }
 };
 
 ANDROID_BASIC_TYPES_TRAITS(Rect)
diff --git a/include/ui/Region.h b/include/ui/Region.h
index 810f098..7788452 100644
--- a/include/ui/Region.h
+++ b/include/ui/Region.h
@@ -147,21 +147,21 @@
     class rasterizer;
     friend class rasterizer;
 
-    Region& operationSelf(const Rect& r, int op);
-    Region& operationSelf(const Region& r, int op);
-    Region& operationSelf(const Region& r, int dx, int dy, int op);
-    const Region operation(const Rect& rhs, int op) const;
-    const Region operation(const Region& rhs, int op) const;
-    const Region operation(const Region& rhs, int dx, int dy, int op) const;
+    Region& operationSelf(const Rect& r, uint32_t op);
+    Region& operationSelf(const Region& r, uint32_t op);
+    Region& operationSelf(const Region& r, int dx, int dy, uint32_t op);
+    const Region operation(const Rect& rhs, uint32_t op) const;
+    const Region operation(const Region& rhs, uint32_t op) const;
+    const Region operation(const Region& rhs, int dx, int dy, uint32_t op) const;
 
-    static void boolean_operation(int op, Region& dst,
+    static void boolean_operation(uint32_t op, Region& dst,
             const Region& lhs, const Region& rhs, int dx, int dy);
-    static void boolean_operation(int op, Region& dst,
+    static void boolean_operation(uint32_t op, Region& dst,
             const Region& lhs, const Rect& rhs, int dx, int dy);
 
-    static void boolean_operation(int op, Region& dst,
+    static void boolean_operation(uint32_t op, Region& dst,
             const Region& lhs, const Region& rhs);
-    static void boolean_operation(int op, Region& dst,
+    static void boolean_operation(uint32_t op, Region& dst,
             const Region& lhs, const Rect& rhs);
 
     static void translate(Region& reg, int dx, int dy);
diff --git a/include/ui/TMatHelpers.h b/include/ui/TMatHelpers.h
deleted file mode 100644
index a6aadca..0000000
--- a/include/ui/TMatHelpers.h
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * 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 TMAT_IMPLEMENTATION
-#error "Don't include TMatHelpers.h directly. use ui/mat*.h instead"
-#else
-#undef TMAT_IMPLEMENTATION
-#endif
-
-
-#ifndef UI_TMAT_HELPERS_H
-#define UI_TMAT_HELPERS_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <math.h>
-#include <utils/Debug.h>
-#include <utils/String8.h>
-
-#define PURE __attribute__((pure))
-
-namespace android {
-// -------------------------------------------------------------------------------------
-
-/*
- * No user serviceable parts here.
- *
- * Don't use this file directly, instead include ui/mat*.h
- */
-
-
-/*
- * Matrix utilities
- */
-
-namespace matrix {
-
-inline int     PURE transpose(int v)    { return v; }
-inline float   PURE transpose(float v)  { return v; }
-inline double  PURE transpose(double v) { return v; }
-
-inline int     PURE trace(int v)    { return v; }
-inline float   PURE trace(float v)  { return v; }
-inline double  PURE trace(double v) { return v; }
-
-template<typename MATRIX>
-MATRIX PURE inverse(const MATRIX& src) {
-
-    COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX::COL_SIZE == MATRIX::ROW_SIZE );
-
-    typename MATRIX::value_type t;
-    const size_t N = MATRIX::col_size();
-    size_t swap;
-    MATRIX tmp(src);
-    MATRIX inverse(1);
-
-    for (size_t i=0 ; i<N ; i++) {
-        // look for largest element in column
-        swap = i;
-        for (size_t j=i+1 ; j<N ; j++) {
-            if (fabs(tmp[j][i]) > fabs(tmp[i][i])) {
-                swap = j;
-            }
-        }
-
-        if (swap != i) {
-            /* swap rows. */
-            for (size_t k=0 ; k<N ; k++) {
-                t = tmp[i][k];
-                tmp[i][k] = tmp[swap][k];
-                tmp[swap][k] = t;
-
-                t = inverse[i][k];
-                inverse[i][k] = inverse[swap][k];
-                inverse[swap][k] = t;
-            }
-        }
-
-        t = 1 / tmp[i][i];
-        for (size_t k=0 ; k<N ; k++) {
-            tmp[i][k] *= t;
-            inverse[i][k] *= t;
-        }
-        for (size_t j=0 ; j<N ; j++) {
-            if (j != i) {
-                t = tmp[j][i];
-                for (size_t k=0 ; k<N ; k++) {
-                    tmp[j][k] -= tmp[i][k] * t;
-                    inverse[j][k] -= inverse[i][k] * t;
-                }
-            }
-        }
-    }
-    return inverse;
-}
-
-template<typename MATRIX_R, typename MATRIX_A, typename MATRIX_B>
-MATRIX_R PURE multiply(const MATRIX_A& lhs, const MATRIX_B& rhs) {
-    // pre-requisite:
-    //  lhs : D columns, R rows
-    //  rhs : C columns, D rows
-    //  res : C columns, R rows
-
-    COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX_A::ROW_SIZE == MATRIX_B::COL_SIZE );
-    COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX_R::ROW_SIZE == MATRIX_B::ROW_SIZE );
-    COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX_R::COL_SIZE == MATRIX_A::COL_SIZE );
-
-    MATRIX_R res(MATRIX_R::NO_INIT);
-    for (size_t r=0 ; r<MATRIX_R::row_size() ; r++) {
-        res[r] = lhs * rhs[r];
-    }
-    return res;
-}
-
-// transpose. this handles matrices of matrices
-template <typename MATRIX>
-MATRIX PURE transpose(const MATRIX& m) {
-    // for now we only handle square matrix transpose
-    COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX::ROW_SIZE == MATRIX::COL_SIZE );
-    MATRIX result(MATRIX::NO_INIT);
-    for (size_t r=0 ; r<MATRIX::row_size() ; r++)
-        for (size_t c=0 ; c<MATRIX::col_size() ; c++)
-            result[c][r] = transpose(m[r][c]);
-    return result;
-}
-
-// trace. this handles matrices of matrices
-template <typename MATRIX>
-typename MATRIX::value_type PURE trace(const MATRIX& m) {
-    COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX::ROW_SIZE == MATRIX::COL_SIZE );
-    typename MATRIX::value_type result(0);
-    for (size_t r=0 ; r<MATRIX::row_size() ; r++)
-        result += trace(m[r][r]);
-    return result;
-}
-
-// trace. this handles matrices of matrices
-template <typename MATRIX>
-typename MATRIX::col_type PURE diag(const MATRIX& m) {
-    COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX::ROW_SIZE == MATRIX::COL_SIZE );
-    typename MATRIX::col_type result(MATRIX::col_type::NO_INIT);
-    for (size_t r=0 ; r<MATRIX::row_size() ; r++)
-        result[r] = m[r][r];
-    return result;
-}
-
-template <typename MATRIX>
-String8 asString(const MATRIX& m) {
-    String8 s;
-    for (size_t c=0 ; c<MATRIX::col_size() ; c++) {
-        s.append("|  ");
-        for (size_t r=0 ; r<MATRIX::row_size() ; r++) {
-            s.appendFormat("%7.2f  ", m[r][c]);
-        }
-        s.append("|\n");
-    }
-    return s;
-}
-
-}; // namespace matrix
-
-// -------------------------------------------------------------------------------------
-
-/*
- * TMatProductOperators implements basic arithmetic and basic compound assignments
- * operators on a vector of type BASE<T>.
- *
- * BASE only needs to implement operator[] and size().
- * By simply inheriting from TMatProductOperators<BASE, T> BASE will automatically
- * get all the functionality here.
- */
-
-template <template<typename T> class BASE, typename T>
-class TMatProductOperators {
-public:
-    // multiply by a scalar
-    BASE<T>& operator *= (T v) {
-        BASE<T>& lhs(static_cast< BASE<T>& >(*this));
-        for (size_t r=0 ; r<lhs.row_size() ; r++) {
-            lhs[r] *= v;
-        }
-        return lhs;
-    }
-
-    // divide by a scalar
-    BASE<T>& operator /= (T v) {
-        BASE<T>& lhs(static_cast< BASE<T>& >(*this));
-        for (size_t r=0 ; r<lhs.row_size() ; r++) {
-            lhs[r] /= v;
-        }
-        return lhs;
-    }
-
-    // matrix * matrix, result is a matrix of the same type than the lhs matrix
-    template<typename U>
-    friend BASE<T> PURE operator *(const BASE<T>& lhs, const BASE<U>& rhs) {
-        return matrix::multiply<BASE<T> >(lhs, rhs);
-    }
-};
-
-
-/*
- * TMatSquareFunctions implements functions on a matrix of type BASE<T>.
- *
- * BASE only needs to implement:
- *  - operator[]
- *  - col_type
- *  - row_type
- *  - COL_SIZE
- *  - ROW_SIZE
- *
- * By simply inheriting from TMatSquareFunctions<BASE, T> BASE will automatically
- * get all the functionality here.
- */
-
-template<template<typename U> class BASE, typename T>
-class TMatSquareFunctions {
-public:
-    /*
-     * NOTE: the functions below ARE NOT member methods. They are friend functions
-     * with they definition inlined with their declaration. This makes these
-     * template functions available to the compiler when (and only when) this class
-     * is instantiated, at which point they're only templated on the 2nd parameter
-     * (the first one, BASE<T> being known).
-     */
-    friend BASE<T> PURE inverse(const BASE<T>& m)   { return matrix::inverse(m); }
-    friend BASE<T> PURE transpose(const BASE<T>& m) { return matrix::transpose(m); }
-    friend T       PURE trace(const BASE<T>& m)     { return matrix::trace(m); }
-};
-
-template <template<typename T> class BASE, typename T>
-class TMatDebug {
-public:
-    String8 asString() const {
-        return matrix::asString( static_cast< const BASE<T>& >(*this) );
-    }
-};
-
-// -------------------------------------------------------------------------------------
-}; // namespace android
-
-#undef PURE
-
-#endif /* UI_TMAT_HELPERS_H */
diff --git a/include/ui/TVecHelpers.h b/include/ui/TVecHelpers.h
deleted file mode 100644
index bb7dbfc..0000000
--- a/include/ui/TVecHelpers.h
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * 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 TVEC_IMPLEMENTATION
-#error "Don't include TVecHelpers.h directly. use ui/vec*.h instead"
-#else
-#undef TVEC_IMPLEMENTATION
-#endif
-
-
-#ifndef UI_TVEC_HELPERS_H
-#define UI_TVEC_HELPERS_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#define PURE __attribute__((pure))
-
-namespace android {
-// -------------------------------------------------------------------------------------
-
-/*
- * No user serviceable parts here.
- *
- * Don't use this file directly, instead include ui/vec{2|3|4}.h
- */
-
-/*
- * This class casts itself into anything and assign itself from anything!
- * Use with caution!
- */
-template <typename TYPE>
-struct Impersonator {
-    Impersonator& operator = (const TYPE& rhs) {
-        reinterpret_cast<TYPE&>(*this) = rhs;
-        return *this;
-    }
-    operator TYPE& () {
-        return reinterpret_cast<TYPE&>(*this);
-    }
-    operator TYPE const& () const {
-        return reinterpret_cast<TYPE const&>(*this);
-    }
-};
-
-/*
- * TVec{Add|Product}Operators implements basic arithmetic and basic compound assignments
- * operators on a vector of type BASE<T>.
- *
- * BASE only needs to implement operator[] and size().
- * By simply inheriting from TVec{Add|Product}Operators<BASE, T> BASE will automatically
- * get all the functionality here.
- */
-
-template <template<typename T> class BASE, typename T>
-class TVecAddOperators {
-public:
-    /* compound assignment from a another vector of the same size but different
-     * element type.
-     */
-    template <typename OTHER>
-    BASE<T>& operator += (const BASE<OTHER>& v) {
-        BASE<T>& rhs = static_cast<BASE<T>&>(*this);
-        for (size_t i=0 ; i<BASE<T>::size() ; i++) {
-            rhs[i] += v[i];
-        }
-        return rhs;
-    }
-    template <typename OTHER>
-    BASE<T>& operator -= (const BASE<OTHER>& v) {
-        BASE<T>& rhs = static_cast<BASE<T>&>(*this);
-        for (size_t i=0 ; i<BASE<T>::size() ; i++) {
-            rhs[i] -= v[i];
-        }
-        return rhs;
-    }
-
-    /* compound assignment from a another vector of the same type.
-     * These operators can be used for implicit conversion and  handle operations
-     * like "vector *= scalar" by letting the compiler implicitly convert a scalar
-     * to a vector (assuming the BASE<T> allows it).
-     */
-    BASE<T>& operator += (const BASE<T>& v) {
-        BASE<T>& rhs = static_cast<BASE<T>&>(*this);
-        for (size_t i=0 ; i<BASE<T>::size() ; i++) {
-            rhs[i] += v[i];
-        }
-        return rhs;
-    }
-    BASE<T>& operator -= (const BASE<T>& v) {
-        BASE<T>& rhs = static_cast<BASE<T>&>(*this);
-        for (size_t i=0 ; i<BASE<T>::size() ; i++) {
-            rhs[i] -= v[i];
-        }
-        return rhs;
-    }
-
-    /*
-     * NOTE: the functions below ARE NOT member methods. They are friend functions
-     * with they definition inlined with their declaration. This makes these
-     * template functions available to the compiler when (and only when) this class
-     * is instantiated, at which point they're only templated on the 2nd parameter
-     * (the first one, BASE<T> being known).
-     */
-
-    /* The operators below handle operation between vectors of the same side
-     * but of a different element type.
-     */
-    template<typename RT>
-    friend inline
-    BASE<T> PURE operator +(const BASE<T>& lv, const BASE<RT>& rv) {
-        return BASE<T>(lv) += rv;
-    }
-    template<typename RT>
-    friend inline
-    BASE<T> PURE operator -(const BASE<T>& lv, const BASE<RT>& rv) {
-        return BASE<T>(lv) -= rv;
-    }
-
-    /* The operators below (which are not templates once this class is instanced,
-     * i.e.: BASE<T> is known) can be used for implicit conversion on both sides.
-     * These handle operations like "vector * scalar" and "scalar * vector" by
-     * letting the compiler implicitly convert a scalar to a vector (assuming
-     * the BASE<T> allows it).
-     */
-    friend inline
-    BASE<T> PURE operator +(const BASE<T>& lv, const BASE<T>& rv) {
-        return BASE<T>(lv) += rv;
-    }
-    friend inline
-    BASE<T> PURE operator -(const BASE<T>& lv, const BASE<T>& rv) {
-        return BASE<T>(lv) -= rv;
-    }
-};
-
-template <template<typename T> class BASE, typename T>
-class TVecProductOperators {
-public:
-    /* compound assignment from a another vector of the same size but different
-     * element type.
-     */
-    template <typename OTHER>
-    BASE<T>& operator *= (const BASE<OTHER>& v) {
-        BASE<T>& rhs = static_cast<BASE<T>&>(*this);
-        for (size_t i=0 ; i<BASE<T>::size() ; i++) {
-            rhs[i] *= v[i];
-        }
-        return rhs;
-    }
-    template <typename OTHER>
-    BASE<T>& operator /= (const BASE<OTHER>& v) {
-        BASE<T>& rhs = static_cast<BASE<T>&>(*this);
-        for (size_t i=0 ; i<BASE<T>::size() ; i++) {
-            rhs[i] /= v[i];
-        }
-        return rhs;
-    }
-
-    /* compound assignment from a another vector of the same type.
-     * These operators can be used for implicit conversion and  handle operations
-     * like "vector *= scalar" by letting the compiler implicitly convert a scalar
-     * to a vector (assuming the BASE<T> allows it).
-     */
-    BASE<T>& operator *= (const BASE<T>& v) {
-        BASE<T>& rhs = static_cast<BASE<T>&>(*this);
-        for (size_t i=0 ; i<BASE<T>::size() ; i++) {
-            rhs[i] *= v[i];
-        }
-        return rhs;
-    }
-    BASE<T>& operator /= (const BASE<T>& v) {
-        BASE<T>& rhs = static_cast<BASE<T>&>(*this);
-        for (size_t i=0 ; i<BASE<T>::size() ; i++) {
-            rhs[i] /= v[i];
-        }
-        return rhs;
-    }
-
-    /*
-     * NOTE: the functions below ARE NOT member methods. They are friend functions
-     * with they definition inlined with their declaration. This makes these
-     * template functions available to the compiler when (and only when) this class
-     * is instantiated, at which point they're only templated on the 2nd parameter
-     * (the first one, BASE<T> being known).
-     */
-
-    /* The operators below handle operation between vectors of the same side
-     * but of a different element type.
-     */
-    template<typename RT>
-    friend inline
-    BASE<T> PURE operator *(const BASE<T>& lv, const BASE<RT>& rv) {
-        return BASE<T>(lv) *= rv;
-    }
-    template<typename RT>
-    friend inline
-    BASE<T> PURE operator /(const BASE<T>& lv, const BASE<RT>& rv) {
-        return BASE<T>(lv) /= rv;
-    }
-
-    /* The operators below (which are not templates once this class is instanced,
-     * i.e.: BASE<T> is known) can be used for implicit conversion on both sides.
-     * These handle operations like "vector * scalar" and "scalar * vector" by
-     * letting the compiler implicitly convert a scalar to a vector (assuming
-     * the BASE<T> allows it).
-     */
-    friend inline
-    BASE<T> PURE operator *(const BASE<T>& lv, const BASE<T>& rv) {
-        return BASE<T>(lv) *= rv;
-    }
-    friend inline
-    BASE<T> PURE operator /(const BASE<T>& lv, const BASE<T>& rv) {
-        return BASE<T>(lv) /= rv;
-    }
-};
-
-/*
- * TVecUnaryOperators implements unary operators on a vector of type BASE<T>.
- *
- * BASE only needs to implement operator[] and size().
- * By simply inheriting from TVecUnaryOperators<BASE, T> BASE will automatically
- * get all the functionality here.
- *
- * These operators are implemented as friend functions of TVecUnaryOperators<BASE, T>
- */
-template <template<typename T> class BASE, typename T>
-class TVecUnaryOperators {
-public:
-    BASE<T>& operator ++ () {
-        BASE<T>& rhs = static_cast<BASE<T>&>(*this);
-        for (size_t i=0 ; i<BASE<T>::size() ; i++) {
-            ++rhs[i];
-        }
-        return rhs;
-    }
-    BASE<T>& operator -- () {
-        BASE<T>& rhs = static_cast<BASE<T>&>(*this);
-        for (size_t i=0 ; i<BASE<T>::size() ; i++) {
-            --rhs[i];
-        }
-        return rhs;
-    }
-    BASE<T> operator - () const {
-        BASE<T> r(BASE<T>::NO_INIT);
-        BASE<T> const& rv(static_cast<BASE<T> const&>(*this));
-        for (size_t i=0 ; i<BASE<T>::size() ; i++) {
-            r[i] = -rv[i];
-        }
-        return r;
-    }
-};
-
-
-/*
- * TVecComparisonOperators implements relational/comparison operators
- * on a vector of type BASE<T>.
- *
- * BASE only needs to implement operator[] and size().
- * By simply inheriting from TVecComparisonOperators<BASE, T> BASE will automatically
- * get all the functionality here.
- */
-template <template<typename T> class BASE, typename T>
-class TVecComparisonOperators {
-public:
-    /*
-     * NOTE: the functions below ARE NOT member methods. They are friend functions
-     * with they definition inlined with their declaration. This makes these
-     * template functions available to the compiler when (and only when) this class
-     * is instantiated, at which point they're only templated on the 2nd parameter
-     * (the first one, BASE<T> being known).
-     */
-    template<typename RT>
-    friend inline
-    bool PURE operator ==(const BASE<T>& lv, const BASE<RT>& rv) {
-        for (size_t i = 0; i < BASE<T>::size(); i++)
-            if (lv[i] != rv[i])
-                return false;
-        return true;
-    }
-
-    template<typename RT>
-    friend inline
-    bool PURE operator !=(const BASE<T>& lv, const BASE<RT>& rv) {
-        return !operator ==(lv, rv);
-    }
-
-    template<typename RT>
-    friend inline
-    bool PURE operator >(const BASE<T>& lv, const BASE<RT>& rv) {
-        for (size_t i = 0; i < BASE<T>::size(); i++)
-            if (lv[i] <= rv[i])
-                return false;
-        return true;
-    }
-
-    template<typename RT>
-    friend inline
-    bool PURE operator <=(const BASE<T>& lv, const BASE<RT>& rv) {
-        return !(lv > rv);
-    }
-
-    template<typename RT>
-    friend inline
-    bool PURE operator <(const BASE<T>& lv, const BASE<RT>& rv) {
-        for (size_t i = 0; i < BASE<T>::size(); i++)
-            if (lv[i] >= rv[i])
-                return false;
-        return true;
-    }
-
-    template<typename RT>
-    friend inline
-    bool PURE operator >=(const BASE<T>& lv, const BASE<RT>& rv) {
-        return !(lv < rv);
-    }
-};
-
-
-/*
- * TVecFunctions implements functions on a vector of type BASE<T>.
- *
- * BASE only needs to implement operator[] and size().
- * By simply inheriting from TVecFunctions<BASE, T> BASE will automatically
- * get all the functionality here.
- */
-template <template<typename T> class BASE, typename T>
-class TVecFunctions {
-public:
-    /*
-     * NOTE: the functions below ARE NOT member methods. They are friend functions
-     * with they definition inlined with their declaration. This makes these
-     * template functions available to the compiler when (and only when) this class
-     * is instantiated, at which point they're only templated on the 2nd parameter
-     * (the first one, BASE<T> being known).
-     */
-    template<typename RT>
-    friend inline
-    T PURE dot(const BASE<T>& lv, const BASE<RT>& rv) {
-        T r(0);
-        for (size_t i = 0; i < BASE<T>::size(); i++)
-            r += lv[i]*rv[i];
-        return r;
-    }
-
-    friend inline
-    T PURE length(const BASE<T>& lv) {
-        return sqrt( dot(lv, lv) );
-    }
-
-    template<typename RT>
-    friend inline
-    T PURE distance(const BASE<T>& lv, const BASE<RT>& rv) {
-        return length(rv - lv);
-    }
-
-    friend inline
-    BASE<T> PURE normalize(const BASE<T>& lv) {
-        return lv * (1 / length(lv));
-    }
-};
-
-#undef PURE
-
-// -------------------------------------------------------------------------------------
-}; // namespace android
-
-
-#endif /* UI_TVEC_HELPERS_H */
diff --git a/include/ui/mat4.h b/include/ui/mat4.h
deleted file mode 100644
index 4fd1eff..0000000
--- a/include/ui/mat4.h
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * 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 UI_MAT4_H
-#define UI_MAT4_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <ui/vec4.h>
-#include <utils/String8.h>
-
-#define TMAT_IMPLEMENTATION
-#include <ui/TMatHelpers.h>
-
-#define PURE __attribute__((pure))
-
-namespace android {
-// -------------------------------------------------------------------------------------
-
-template <typename T>
-class tmat44 :  public TVecUnaryOperators<tmat44, T>,
-                public TVecComparisonOperators<tmat44, T>,
-                public TVecAddOperators<tmat44, T>,
-                public TMatProductOperators<tmat44, T>,
-                public TMatSquareFunctions<tmat44, T>,
-                public TMatDebug<tmat44, T>
-{
-public:
-    enum no_init { NO_INIT };
-    typedef T value_type;
-    typedef T& reference;
-    typedef T const& const_reference;
-    typedef size_t size_type;
-    typedef tvec4<T> col_type;
-    typedef tvec4<T> row_type;
-
-    // size of a column (i.e.: number of rows)
-    enum { COL_SIZE = col_type::SIZE };
-    static inline size_t col_size() { return COL_SIZE; }
-
-    // size of a row (i.e.: number of columns)
-    enum { ROW_SIZE = row_type::SIZE };
-    static inline size_t row_size() { return ROW_SIZE; }
-    static inline size_t size()     { return row_size(); }  // for TVec*<>
-
-private:
-
-    /*
-     *  <--  N columns  -->
-     *
-     *  a00 a10 a20 ... aN0    ^
-     *  a01 a11 a21 ... aN1    |
-     *  a02 a12 a22 ... aN2  M rows
-     *  ...                    |
-     *  a0M a1M a2M ... aNM    v
-     *
-     *  COL_SIZE = M
-     *  ROW_SIZE = N
-     *  m[0] = [a00 a01 a02 ... a01M]
-     */
-
-    col_type mValue[ROW_SIZE];
-
-public:
-    // array access
-    inline col_type const& operator [] (size_t i) const { return mValue[i]; }
-    inline col_type&       operator [] (size_t i)       { return mValue[i]; }
-
-    T const* asArray() const { return &mValue[0][0]; }
-
-    // -----------------------------------------------------------------------
-    // we don't provide copy-ctor and operator= on purpose
-    // because we want the compiler generated versions
-
-    /*
-     *  constructors
-     */
-
-    // leaves object uninitialized. use with caution.
-    explicit tmat44(no_init) { }
-
-    // initialize to identity
-    tmat44();
-
-    // initialize to Identity*scalar.
-    template<typename U>
-    explicit tmat44(U v);
-
-    // sets the diagonal to the passed vector
-    template <typename U>
-    explicit tmat44(const tvec4<U>& rhs);
-
-    // construct from another matrix of the same size
-    template <typename U>
-    explicit tmat44(const tmat44<U>& rhs);
-
-    // construct from 4 column vectors
-    template <typename A, typename B, typename C, typename D>
-    tmat44(const tvec4<A>& v0, const tvec4<B>& v1, const tvec4<C>& v2, const tvec4<D>& v3);
-
-    // construct from 16 scalars
-    template <
-        typename A, typename B, typename C, typename D,
-        typename E, typename F, typename G, typename H,
-        typename I, typename J, typename K, typename L,
-        typename M, typename N, typename O, typename P>
-    tmat44( A m00, B m01, C m02, D m03,
-            E m10, F m11, G m12, H m13,
-            I m20, J m21, K m22, L m23,
-            M m30, N m31, O m32, P m33);
-
-    // construct from a C array
-    template <typename U>
-    explicit tmat44(U const* rawArray);
-
-    /*
-     *  helpers
-     */
-
-    static tmat44 ortho(T left, T right, T bottom, T top, T near, T far);
-
-    static tmat44 frustum(T left, T right, T bottom, T top, T near, T far);
-
-    template <typename A, typename B, typename C>
-    static tmat44 lookAt(const tvec3<A>& eye, const tvec3<B>& center, const tvec3<C>& up);
-
-    template <typename A>
-    static tmat44 translate(const tvec4<A>& t);
-
-    template <typename A>
-    static tmat44 scale(const tvec4<A>& s);
-
-    template <typename A, typename B>
-    static tmat44 rotate(A radian, const tvec3<B>& about);
-};
-
-// ----------------------------------------------------------------------------------------
-// Constructors
-// ----------------------------------------------------------------------------------------
-
-/*
- * Since the matrix code could become pretty big quickly, we don't inline most
- * operations.
- */
-
-template <typename T>
-tmat44<T>::tmat44() {
-    mValue[0] = col_type(1,0,0,0);
-    mValue[1] = col_type(0,1,0,0);
-    mValue[2] = col_type(0,0,1,0);
-    mValue[3] = col_type(0,0,0,1);
-}
-
-template <typename T>
-template <typename U>
-tmat44<T>::tmat44(U v) {
-    mValue[0] = col_type(v,0,0,0);
-    mValue[1] = col_type(0,v,0,0);
-    mValue[2] = col_type(0,0,v,0);
-    mValue[3] = col_type(0,0,0,v);
-}
-
-template<typename T>
-template<typename U>
-tmat44<T>::tmat44(const tvec4<U>& v) {
-    mValue[0] = col_type(v.x,0,0,0);
-    mValue[1] = col_type(0,v.y,0,0);
-    mValue[2] = col_type(0,0,v.z,0);
-    mValue[3] = col_type(0,0,0,v.w);
-}
-
-// construct from 16 scalars
-template<typename T>
-template <
-    typename A, typename B, typename C, typename D,
-    typename E, typename F, typename G, typename H,
-    typename I, typename J, typename K, typename L,
-    typename M, typename N, typename O, typename P>
-tmat44<T>::tmat44(  A m00, B m01, C m02, D m03,
-                    E m10, F m11, G m12, H m13,
-                    I m20, J m21, K m22, L m23,
-                    M m30, N m31, O m32, P m33) {
-    mValue[0] = col_type(m00, m01, m02, m03);
-    mValue[1] = col_type(m10, m11, m12, m13);
-    mValue[2] = col_type(m20, m21, m22, m23);
-    mValue[3] = col_type(m30, m31, m32, m33);
-}
-
-template <typename T>
-template <typename U>
-tmat44<T>::tmat44(const tmat44<U>& rhs) {
-    for (size_t r=0 ; r<row_size() ; r++)
-        mValue[r] = rhs[r];
-}
-
-template <typename T>
-template <typename A, typename B, typename C, typename D>
-tmat44<T>::tmat44(const tvec4<A>& v0, const tvec4<B>& v1, const tvec4<C>& v2, const tvec4<D>& v3) {
-    mValue[0] = v0;
-    mValue[1] = v1;
-    mValue[2] = v2;
-    mValue[3] = v3;
-}
-
-template <typename T>
-template <typename U>
-tmat44<T>::tmat44(U const* rawArray) {
-    for (size_t r=0 ; r<row_size() ; r++)
-        for (size_t c=0 ; c<col_size() ; c++)
-            mValue[r][c] = *rawArray++;
-}
-
-// ----------------------------------------------------------------------------------------
-// Helpers
-// ----------------------------------------------------------------------------------------
-
-template <typename T>
-tmat44<T> tmat44<T>::ortho(T left, T right, T bottom, T top, T near, T far) {
-    tmat44<T> m;
-    m[0][0] =  2 / (right - left);
-    m[1][1] =  2 / (top   - bottom);
-    m[2][2] = -2 / (far   - near);
-    m[3][0] = -(right + left)   / (right - left);
-    m[3][1] = -(top   + bottom) / (top   - bottom);
-    m[3][2] = -(far   + near)   / (far   - near);
-    return m;
-}
-
-template <typename T>
-tmat44<T> tmat44<T>::frustum(T left, T right, T bottom, T top, T near, T far) {
-    tmat44<T> m;
-    T A = (right + left)   / (right - left);
-    T B = (top   + bottom) / (top   - bottom);
-    T C = (far   + near)   / (far   - near);
-    T D = (2 * far * near) / (far   - near);
-    m[0][0] = (2 * near) / (right - left);
-    m[1][1] = (2 * near) / (top   - bottom);
-    m[2][0] = A;
-    m[2][1] = B;
-    m[2][2] = C;
-    m[2][3] =-1;
-    m[3][2] = D;
-    m[3][3] = 0;
-    return m;
-}
-
-template <typename T>
-template <typename A, typename B, typename C>
-tmat44<T> tmat44<T>::lookAt(const tvec3<A>& eye, const tvec3<B>& center, const tvec3<C>& up) {
-    tvec3<T> L(normalize(center - eye));
-    tvec3<T> S(normalize( cross(L, up) ));
-    tvec3<T> U(cross(S, L));
-    return tmat44<T>(
-            tvec4<T>( S, 0),
-            tvec4<T>( U, 0),
-            tvec4<T>(-L, 0),
-            tvec4<T>(-eye, 1));
-}
-
-template <typename T>
-template <typename A>
-tmat44<T> tmat44<T>::translate(const tvec4<A>& t) {
-    tmat44<T> r;
-    r[3] = t;
-    return r;
-}
-
-template <typename T>
-template <typename A>
-tmat44<T> tmat44<T>::scale(const tvec4<A>& s) {
-    tmat44<T> r;
-    r[0][0] = s[0];
-    r[1][1] = s[1];
-    r[2][2] = s[2];
-    r[3][3] = s[3];
-    return r;
-}
-
-template <typename T>
-template <typename A, typename B>
-tmat44<T> tmat44<T>::rotate(A radian, const tvec3<B>& about) {
-    tmat44<T> rotation;
-    T* r = const_cast<T*>(rotation.asArray());
-    T c = cos(radian);
-    T s = sin(radian);
-    if (about.x==1 && about.y==0 && about.z==0) {
-        r[5] = c;   r[10]= c;
-        r[6] = s;   r[9] = -s;
-    } else if (about.x==0 && about.y==1 && about.z==0) {
-        r[0] = c;   r[10]= c;
-        r[8] = s;   r[2] = -s;
-    } else if (about.x==0 && about.y==0 && about.z==1) {
-        r[0] = c;   r[5] = c;
-        r[1] = s;   r[4] = -s;
-    } else {
-        tvec3<B> nabout = normalize(about);
-        B x = nabout.x;
-        B y = nabout.y;
-        B z = nabout.z;
-        T nc = 1 - c;
-        T xy = x * y;
-        T yz = y * z;
-        T zx = z * x;
-        T xs = x * s;
-        T ys = y * s;
-        T zs = z * s;
-        r[ 0] = x*x*nc +  c;    r[ 4] =  xy*nc - zs;    r[ 8] =  zx*nc + ys;
-        r[ 1] =  xy*nc + zs;    r[ 5] = y*y*nc +  c;    r[ 9] =  yz*nc - xs;
-        r[ 2] =  zx*nc - ys;    r[ 6] =  yz*nc + xs;    r[10] = z*z*nc +  c;
-    }
-    return rotation;
-}
-
-// ----------------------------------------------------------------------------------------
-// Arithmetic operators outside of class
-// ----------------------------------------------------------------------------------------
-
-/* We use non-friend functions here to prevent the compiler from using
- * implicit conversions, for instance of a scalar to a vector. The result would
- * not be what the caller expects.
- *
- * Also note that the order of the arguments in the inner loop is important since
- * it determines the output type (only relevant when T != U).
- */
-
-// matrix * vector, result is a vector of the same type than the input vector
-template <typename T, typename U>
-typename tmat44<U>::col_type PURE operator *(const tmat44<T>& lv, const tvec4<U>& rv) {
-    typename tmat44<U>::col_type result;
-    for (size_t r=0 ; r<tmat44<T>::row_size() ; r++)
-        result += rv[r]*lv[r];
-    return result;
-}
-
-// vector * matrix, result is a vector of the same type than the input vector
-template <typename T, typename U>
-typename tmat44<U>::row_type PURE operator *(const tvec4<U>& rv, const tmat44<T>& lv) {
-    typename tmat44<U>::row_type result(tmat44<U>::row_type::NO_INIT);
-    for (size_t r=0 ; r<tmat44<T>::row_size() ; r++)
-        result[r] = dot(rv, lv[r]);
-    return result;
-}
-
-// matrix * scalar, result is a matrix of the same type than the input matrix
-template <typename T, typename U>
-tmat44<T> PURE operator *(const tmat44<T>& lv, U rv) {
-    tmat44<T> result(tmat44<T>::NO_INIT);
-    for (size_t r=0 ; r<tmat44<T>::row_size() ; r++)
-        result[r] = lv[r]*rv;
-    return result;
-}
-
-// scalar * matrix, result is a matrix of the same type than the input matrix
-template <typename T, typename U>
-tmat44<T> PURE operator *(U rv, const tmat44<T>& lv) {
-    tmat44<T> result(tmat44<T>::NO_INIT);
-    for (size_t r=0 ; r<tmat44<T>::row_size() ; r++)
-        result[r] = lv[r]*rv;
-    return result;
-}
-
-// ----------------------------------------------------------------------------------------
-
-/* FIXME: this should go into TMatSquareFunctions<> but for some reason
- * BASE<T>::col_type is not accessible from there (???)
- */
-template<typename T>
-typename tmat44<T>::col_type PURE diag(const tmat44<T>& m) {
-    return matrix::diag(m);
-}
-
-// ----------------------------------------------------------------------------------------
-
-typedef tmat44<float> mat4;
-
-// ----------------------------------------------------------------------------------------
-}; // namespace android
-
-#undef PURE
-
-#endif /* UI_MAT4_H */
diff --git a/include/ui/vec2.h b/include/ui/vec2.h
deleted file mode 100644
index c31d0e4..0000000
--- a/include/ui/vec2.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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 UI_VEC2_H
-#define UI_VEC2_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#define TVEC_IMPLEMENTATION
-#include <ui/TVecHelpers.h>
-
-namespace android {
-// -------------------------------------------------------------------------------------
-
-template <typename T>
-class tvec2 :   public TVecProductOperators<tvec2, T>,
-                public TVecAddOperators<tvec2, T>,
-                public TVecUnaryOperators<tvec2, T>,
-                public TVecComparisonOperators<tvec2, T>,
-                public TVecFunctions<tvec2, T>
-{
-public:
-    enum no_init { NO_INIT };
-    typedef T value_type;
-    typedef T& reference;
-    typedef T const& const_reference;
-    typedef size_t size_type;
-
-    union {
-        struct { T x, y; };
-        struct { T s, t; };
-        struct { T r, g; };
-    };
-
-    enum { SIZE = 2 };
-    inline static size_type size() { return SIZE; }
-
-    // array access
-    inline T const& operator [] (size_t i) const { return (&x)[i]; }
-    inline T&       operator [] (size_t i)       { return (&x)[i]; }
-
-    // -----------------------------------------------------------------------
-    // we don't provide copy-ctor and operator= on purpose
-    // because we want the compiler generated versions
-
-    // constructors
-
-    // leaves object uninitialized. use with caution.
-    explicit tvec2(no_init) { }
-
-    // default constructor
-    tvec2() : x(0), y(0) { }
-
-    // handles implicit conversion to a tvec4. must not be explicit.
-    template<typename A>
-    tvec2(A v) : x(v), y(v) { }
-
-    template<typename A, typename B>
-    tvec2(A x, B y) : x(x), y(y) { }
-
-    template<typename A>
-    explicit tvec2(const tvec2<A>& v) : x(v.x), y(v.y) { }
-
-    template<typename A>
-    tvec2(const Impersonator< tvec2<A> >& v)
-        : x(((const tvec2<A>&)v).x),
-          y(((const tvec2<A>&)v).y) { }
-};
-
-// ----------------------------------------------------------------------------------------
-
-typedef tvec2<float> vec2;
-
-// ----------------------------------------------------------------------------------------
-}; // namespace android
-
-#endif /* UI_VEC4_H */
diff --git a/include/ui/vec3.h b/include/ui/vec3.h
deleted file mode 100644
index dde59a9..0000000
--- a/include/ui/vec3.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * 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 UI_VEC3_H
-#define UI_VEC3_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <ui/vec2.h>
-
-namespace android {
-// -------------------------------------------------------------------------------------
-
-template <typename T>
-class tvec3 :   public TVecProductOperators<tvec3, T>,
-                public TVecAddOperators<tvec3, T>,
-                public TVecUnaryOperators<tvec3, T>,
-                public TVecComparisonOperators<tvec3, T>,
-                public TVecFunctions<tvec3, T>
-{
-public:
-    enum no_init { NO_INIT };
-    typedef T value_type;
-    typedef T& reference;
-    typedef T const& const_reference;
-    typedef size_t size_type;
-
-    union {
-        struct { T x, y, z; };
-        struct { T s, t, p; };
-        struct { T r, g, b; };
-        Impersonator< tvec2<T> > xy;
-        Impersonator< tvec2<T> > st;
-        Impersonator< tvec2<T> > rg;
-    };
-
-    enum { SIZE = 3 };
-    inline static size_type size() { return SIZE; }
-
-    // array access
-    inline T const& operator [] (size_t i) const { return (&x)[i]; }
-    inline T&       operator [] (size_t i)       { return (&x)[i]; }
-
-    // -----------------------------------------------------------------------
-    // we don't provide copy-ctor and operator= on purpose
-    // because we want the compiler generated versions
-
-    // constructors
-    // leaves object uninitialized. use with caution.
-    explicit tvec3(no_init) { }
-
-    // default constructor
-    tvec3() : x(0), y(0), z(0) { }
-
-    // handles implicit conversion to a tvec4. must not be explicit.
-    template<typename A>
-    tvec3(A v) : x(v), y(v), z(v) { }
-
-    template<typename A, typename B, typename C>
-    tvec3(A x, B y, C z) : x(x), y(y), z(z) { }
-
-    template<typename A, typename B>
-    tvec3(const tvec2<A>& v, B z) : x(v.x), y(v.y), z(z) { }
-
-    template<typename A>
-    explicit tvec3(const tvec3<A>& v) : x(v.x), y(v.y), z(v.z) { }
-
-    template<typename A>
-    tvec3(const Impersonator< tvec3<A> >& v)
-        : x(((const tvec3<A>&)v).x),
-          y(((const tvec3<A>&)v).y),
-          z(((const tvec3<A>&)v).z) { }
-
-    template<typename A, typename B>
-    tvec3(const Impersonator< tvec2<A> >& v, B z)
-        : x(((const tvec2<A>&)v).x),
-          y(((const tvec2<A>&)v).y),
-          z(z) { }
-
-    // cross product works only on vectors of size 3
-    template <typename RT>
-    friend inline
-    tvec3 __attribute__((pure)) cross(const tvec3& u, const tvec3<RT>& v) {
-        return tvec3(
-                u.y*v.z - u.z*v.y,
-                u.z*v.x - u.x*v.z,
-                u.x*v.y - u.y*v.x);
-    }
-};
-
-
-// ----------------------------------------------------------------------------------------
-
-typedef tvec3<float> vec3;
-
-// ----------------------------------------------------------------------------------------
-}; // namespace android
-
-#endif /* UI_VEC4_H */
diff --git a/include/ui/vec4.h b/include/ui/vec4.h
deleted file mode 100644
index e03d331..0000000
--- a/include/ui/vec4.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * 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 UI_VEC4_H
-#define UI_VEC4_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <ui/vec3.h>
-
-namespace android {
-// -------------------------------------------------------------------------------------
-
-template <typename T>
-class tvec4 :   public TVecProductOperators<tvec4, T>,
-                public TVecAddOperators<tvec4, T>,
-                public TVecUnaryOperators<tvec4, T>,
-                public TVecComparisonOperators<tvec4, T>,
-                public TVecFunctions<tvec4, T>
-{
-public:
-    enum no_init { NO_INIT };
-    typedef T value_type;
-    typedef T& reference;
-    typedef T const& const_reference;
-    typedef size_t size_type;
-
-    union {
-        struct { T x, y, z, w; };
-        struct { T s, t, p, q; };
-        struct { T r, g, b, a; };
-        Impersonator< tvec2<T> > xy;
-        Impersonator< tvec2<T> > st;
-        Impersonator< tvec2<T> > rg;
-        Impersonator< tvec3<T> > xyz;
-        Impersonator< tvec3<T> > stp;
-        Impersonator< tvec3<T> > rgb;
-    };
-
-    enum { SIZE = 4 };
-    inline static size_type size() { return SIZE; }
-
-    // array access
-    inline T const& operator [] (size_t i) const { return (&x)[i]; }
-    inline T&       operator [] (size_t i)       { return (&x)[i]; }
-
-    // -----------------------------------------------------------------------
-    // we don't provide copy-ctor and operator= on purpose
-    // because we want the compiler generated versions
-
-    // constructors
-
-    // leaves object uninitialized. use with caution.
-    explicit tvec4(no_init) { }
-
-    // default constructor
-    tvec4() : x(0), y(0), z(0), w(0) { }
-
-    // handles implicit conversion to a tvec4. must not be explicit.
-    template<typename A>
-    tvec4(A v) : x(v), y(v), z(v), w(v) { }
-
-    template<typename A, typename B, typename C, typename D>
-    tvec4(A x, B y, C z, D w) : x(x), y(y), z(z), w(w) { }
-
-    template<typename A, typename B, typename C>
-    tvec4(const tvec2<A>& v, B z, C w) : x(v.x), y(v.y), z(z), w(w) { }
-
-    template<typename A, typename B>
-    tvec4(const tvec3<A>& v, B w) : x(v.x), y(v.y), z(v.z), w(w) { }
-
-    template<typename A>
-    explicit tvec4(const tvec4<A>& v) : x(v.x), y(v.y), z(v.z), w(v.w) { }
-
-    template<typename A>
-    tvec4(const Impersonator< tvec4<A> >& v)
-        : x(((const tvec4<A>&)v).x),
-          y(((const tvec4<A>&)v).y),
-          z(((const tvec4<A>&)v).z),
-          w(((const tvec4<A>&)v).w) { }
-
-    template<typename A, typename B>
-    tvec4(const Impersonator< tvec3<A> >& v, B w)
-        : x(((const tvec3<A>&)v).x),
-          y(((const tvec3<A>&)v).y),
-          z(((const tvec3<A>&)v).z),
-          w(w) { }
-
-    template<typename A, typename B, typename C>
-    tvec4(const Impersonator< tvec2<A> >& v, B z, C w)
-        : x(((const tvec2<A>&)v).x),
-          y(((const tvec2<A>&)v).y),
-          z(z),
-          w(w) { }
-};
-
-// ----------------------------------------------------------------------------------------
-
-typedef tvec4<float> vec4;
-
-// ----------------------------------------------------------------------------------------
-}; // namespace android
-
-#endif /* UI_VEC4_H */
diff --git a/include/vr/vr_manager/vr_manager.h b/include/vr/vr_manager/vr_manager.h
new file mode 100644
index 0000000..9df2c6b
--- /dev/null
+++ b/include/vr/vr_manager/vr_manager.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_VR_MANAGER_H
+#define ANDROID_VR_MANAGER_H
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+// Must be kept in sync with interface defined in IVrStateCallbacks.aidl.
+
+class IVrStateCallbacks : public IInterface {
+public:
+    DECLARE_META_INTERFACE(VrStateCallbacks)
+
+    virtual void onVrStateChanged(bool enabled) = 0;
+};
+
+enum VrStateCallbacksTransaction {
+    ON_VR_STATE_CHANGED = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+class BnVrStateCallbacks : public BnInterface<IVrStateCallbacks> {
+public:
+    status_t onTransact(uint32_t code, const Parcel& data,
+                        Parcel* reply, uint32_t flags = 0) override;
+};
+
+
+// Must be kept in sync with interface defined in
+// IPersistentVrStateCallbacks.aidl.
+
+class IPersistentVrStateCallbacks : public IInterface {
+public:
+    DECLARE_META_INTERFACE(PersistentVrStateCallbacks)
+
+    virtual void onPersistentVrStateChanged(bool enabled) = 0;
+};
+
+enum PersistentVrStateCallbacksTransaction {
+    ON_PERSISTENT_VR_STATE_CHANGED = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+class BnPersistentVrStateCallbacks
+        : public BnInterface<IPersistentVrStateCallbacks> {
+public:
+    status_t onTransact(uint32_t code, const Parcel& data,
+                        Parcel* reply, uint32_t flags = 0) override;
+};
+
+
+// Must be kept in sync with interface defined in IVrManager.aidl.
+
+class IVrManager : public IInterface {
+public:
+    DECLARE_META_INTERFACE(VrManager)
+
+    virtual void registerListener(const sp<IVrStateCallbacks>& cb) = 0;
+    virtual void unregisterListener(const sp<IVrStateCallbacks>& cb) = 0;
+    virtual void registerPersistentVrStateListener(
+        const sp<IPersistentVrStateCallbacks>& cb) = 0;
+    virtual void unregisterPersistentVrStateListener(
+        const sp<IPersistentVrStateCallbacks>& cb) = 0;
+    virtual bool getVrModeState() = 0;
+};
+
+enum VrManagerTransaction {
+    REGISTER_LISTENER = IBinder::FIRST_CALL_TRANSACTION,
+    UNREGISTER_LISTENER,
+    REGISTER_PERSISTENT_VR_STATE_LISTENER,
+    UNREGISTER_PERSISTENT_VR_STATE_LISTENER,
+    GET_VR_MODE_STATE,
+};
+
+};  // namespace android
+
+#endif // ANDROID_VR_MANAGER_H
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
new file mode 100644
index 0000000..0d25176
--- /dev/null
+++ b/libs/arect/Android.bp
@@ -0,0 +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.
+
+ndk_headers {
+    name: "libarect_headers",
+    from: "include/android",
+    to: "android",
+    srcs: ["include/android/*.h"],
+    license: "NOTICE",
+}
+
+cc_library_static {
+    name: "libarect",
+    host_supported: true,
+    export_include_dirs: ["include"],
+}
diff --git a/libs/arect/MODULE_LICENSE_APACHE2 b/libs/arect/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libs/arect/MODULE_LICENSE_APACHE2
diff --git a/libs/arect/NOTICE b/libs/arect/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/libs/arect/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, 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/include/android/rect.h b/libs/arect/include/android/rect.h
similarity index 100%
rename from include/android/rect.h
rename to libs/arect/include/android/rect.h
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
new file mode 100644
index 0000000..204fdb5
--- /dev/null
+++ b/libs/binder/Android.bp
@@ -0,0 +1,92 @@
+// Copyright (C) 2009 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_headers {
+    name: "libbinder_headers",
+    export_include_dirs: ["include"],
+}
+
+cc_library {
+    name: "libbinder",
+
+    // for vndbinder
+    vendor_available: true,
+
+    srcs: [
+        "AppOpsManager.cpp",
+        "Binder.cpp",
+        "BpBinder.cpp",
+        "BufferedTextOutput.cpp",
+        "Debug.cpp",
+        "IActivityManager.cpp",
+        "IAppOpsCallback.cpp",
+        "IAppOpsService.cpp",
+        "IBatteryStats.cpp",
+        "IInterface.cpp",
+        "IMediaResourceMonitor.cpp",
+        "IMemory.cpp",
+        "IPCThreadState.cpp",
+        "IPermissionController.cpp",
+        "IProcessInfoService.cpp",
+        "IResultReceiver.cpp",
+        "IServiceManager.cpp",
+        "IShellCallback.cpp",
+        "MemoryBase.cpp",
+        "MemoryDealer.cpp",
+        "MemoryHeapBase.cpp",
+        "Parcel.cpp",
+        "PermissionCache.cpp",
+        "PersistableBundle.cpp",
+        "ProcessInfoService.cpp",
+        "ProcessState.cpp",
+        "Static.cpp",
+        "Status.cpp",
+        "TextOutput.cpp",
+        "IpPrefix.cpp",
+        "Value.cpp",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    product_variables: {
+        binder32bit: {
+            cflags: ["-DBINDER_IPC_32BIT=1"],
+        },
+    },
+
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libcutils",
+        "libutils",
+    ],
+    export_shared_lib_headers: [
+        "libbase",
+        "libutils",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+
+    clang: true,
+    sanitize: {
+        misc_undefined: ["integer"],
+    },
+}
+
+subdirs = ["tests"]
diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk
deleted file mode 100644
index 14be920..0000000
--- a/libs/binder/Android.mk
+++ /dev/null
@@ -1,72 +0,0 @@
-# Copyright (C) 2009 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.
-
-# we have the common sources, plus some device-specific stuff
-sources := \
-    AppOpsManager.cpp \
-    Binder.cpp \
-    BpBinder.cpp \
-    BufferedTextOutput.cpp \
-    Debug.cpp \
-    IAppOpsCallback.cpp \
-    IAppOpsService.cpp \
-    IBatteryStats.cpp \
-    IInterface.cpp \
-    IMediaResourceMonitor.cpp \
-    IMemory.cpp \
-    IPCThreadState.cpp \
-    IPermissionController.cpp \
-    IProcessInfoService.cpp \
-    IResultReceiver.cpp \
-    IServiceManager.cpp \
-    MemoryBase.cpp \
-    MemoryDealer.cpp \
-    MemoryHeapBase.cpp \
-    Parcel.cpp \
-    PermissionCache.cpp \
-    PersistableBundle.cpp \
-    ProcessInfoService.cpp \
-    ProcessState.cpp \
-    Static.cpp \
-    Status.cpp \
-    TextOutput.cpp \
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libbinder
-LOCAL_SHARED_LIBRARIES := liblog libcutils libutils
-
-LOCAL_CLANG := true
-LOCAL_SANITIZE := integer
-LOCAL_SRC_FILES := $(sources)
-ifneq ($(TARGET_USES_64_BIT_BINDER),true)
-ifneq ($(TARGET_IS_64_BIT),true)
-LOCAL_CFLAGS += -DBINDER_IPC_32BIT=1
-endif
-endif
-LOCAL_CFLAGS += -Werror
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libbinder
-LOCAL_STATIC_LIBRARIES += libutils
-LOCAL_SRC_FILES := $(sources)
-ifneq ($(TARGET_USES_64_BIT_BINDER),true)
-ifneq ($(TARGET_IS_64_BIT),true)
-LOCAL_CFLAGS += -DBINDER_IPC_32BIT=1
-endif
-endif
-LOCAL_CFLAGS += -Werror
-include $(BUILD_STATIC_LIBRARY)
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index 9a061a0..f3b86ae 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <mutex>
 #include <binder/AppOpsManager.h>
 #include <binder/Binder.h>
 #include <binder/IServiceManager.h>
@@ -22,6 +23,19 @@
 
 namespace android {
 
+namespace {
+
+#if defined(__BRILLO__)
+// Because Brillo has no application model, security policy is managed
+// statically (at build time) with SELinux controls.
+// As a consequence, it also never runs the AppOpsManager service.
+const int APP_OPS_MANAGER_UNAVAILABLE_MODE = AppOpsManager::MODE_ALLOWED;
+#else
+const int APP_OPS_MANAGER_UNAVAILABLE_MODE = AppOpsManager::MODE_IGNORED;
+#endif  // defined(__BRILLO__)
+
+}  // namespace
+
 static String16 _appops("appops");
 static pthread_mutex_t gTokenMutex = PTHREAD_MUTEX_INITIALIZER;
 static sp<IBinder> gToken;
@@ -39,10 +53,15 @@
 {
 }
 
+#if defined(__BRILLO__)
+// There is no AppOpsService on Brillo
+sp<IAppOpsService> AppOpsManager::getService() { return NULL; }
+#else
 sp<IAppOpsService> AppOpsManager::getService()
 {
+
+    std::lock_guard<Mutex> scoped_lock(mLock);
     int64_t startTime = 0;
-    mLock.lock();
     sp<IAppOpsService> service = mService;
     while (service == NULL || !IInterface::asBinder(service)->isBinderAlive()) {
         sp<IBinder> binder = defaultServiceManager()->checkService(_appops);
@@ -53,7 +72,8 @@
                 ALOGI("Waiting for app ops service");
             } else if ((uptimeMillis()-startTime) > 10000) {
                 ALOGW("Waiting too long for app ops service, giving up");
-                return NULL;
+                service = NULL;
+                break;
             }
             sleep(1);
         } else {
@@ -61,25 +81,30 @@
             mService = service;
         }
     }
-    mLock.unlock();
     return service;
 }
+#endif  // defined(__BRILLO__)
 
 int32_t AppOpsManager::checkOp(int32_t op, int32_t uid, const String16& callingPackage)
 {
     sp<IAppOpsService> service = getService();
-    return service != NULL ? service->checkOperation(op, uid, callingPackage) : MODE_IGNORED;
+    return service != NULL
+            ? service->checkOperation(op, 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 ? service->noteOperation(op, uid, callingPackage) : MODE_IGNORED;
+    return service != NULL
+            ? service->noteOperation(op, uid, callingPackage)
+            : APP_OPS_MANAGER_UNAVAILABLE_MODE;
 }
 
 int32_t AppOpsManager::startOp(int32_t op, int32_t uid, const String16& callingPackage) {
     sp<IAppOpsService> service = getService();
-    return service != NULL ? service->startOperation(getToken(service), op, uid, callingPackage)
-            : MODE_IGNORED;
+    return service != NULL
+            ? service->startOperation(getToken(service), op, uid, callingPackage)
+            : APP_OPS_MANAGER_UNAVAILABLE_MODE;
 }
 
 void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage) {
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index c4d47ca..890ef30 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -21,6 +21,7 @@
 #include <binder/BpBinder.h>
 #include <binder/IInterface.h>
 #include <binder/IResultReceiver.h>
+#include <binder/IShellCallback.h>
 #include <binder/Parcel.h>
 
 #include <stdio.h>
@@ -62,7 +63,8 @@
 
 
 status_t IBinder::shellCommand(const sp<IBinder>& target, int in, int out, int err,
-    Vector<String16>& args, const sp<IResultReceiver>& resultReceiver)
+    Vector<String16>& args, const sp<IShellCallback>& callback,
+    const sp<IResultReceiver>& resultReceiver)
 {
     Parcel send;
     Parcel reply;
@@ -74,6 +76,7 @@
     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);
     return target->transact(SHELL_COMMAND_TRANSACTION, send, &reply);
 }
@@ -232,11 +235,17 @@
             for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
                args.add(data.readString16());
             }
+            sp<IShellCallback> shellCallback = IShellCallback::asInterface(
+                    data.readStrongBinder());
             sp<IResultReceiver> resultReceiver = IResultReceiver::asInterface(
                     data.readStrongBinder());
 
             // XXX can't add virtuals until binaries are updated.
             //return shellCommand(in, out, err, args, resultReceiver);
+            (void)in;
+            (void)out;
+            (void)err;
+
             if (resultReceiver != NULL) {
                 resultReceiver->send(INVALID_OPERATION);
             }
diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp
index 1339a67..a2443c0 100644
--- a/libs/binder/BufferedTextOutput.cpp
+++ b/libs/binder/BufferedTextOutput.cpp
@@ -34,7 +34,7 @@
 
 struct BufferedTextOutput::BufferState : public RefBase
 {
-    BufferState(int32_t _seq)
+    explicit BufferState(int32_t _seq)
         : seq(_seq)
         , buffer(NULL)
         , bufferPos(0)
diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp
new file mode 100644
index 0000000..50a8b28
--- /dev/null
+++ b/libs/binder/IActivityManager.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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 <unistd.h>
+#include <fcntl.h>
+
+#include <binder/IActivityManager.h>
+
+#include <binder/Parcel.h>
+
+namespace android {
+
+// ------------------------------------------------------------------------------------
+
+class BpActivityManager : public BpInterface<IActivityManager>
+{
+public:
+    explicit BpActivityManager(const sp<IBinder>& impl)
+        : BpInterface<IActivityManager>(impl)
+    {
+    }
+
+    virtual int openContentUri(const String16& stringUri)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor());
+        data.writeString16(stringUri);
+        status_t ret = remote()->transact(OPEN_CONTENT_URI_TRANSACTION, data, & reply);
+        int fd = -1;
+        if (ret == NO_ERROR) {
+            int32_t exceptionCode = reply.readExceptionCode();
+            if (!exceptionCode) {
+                // Success is indicated here by a nonzero int followed by the fd;
+                // failure by a zero int with no data following.
+                if (reply.readInt32() != 0) {
+                    fd = fcntl(reply.readParcelFileDescriptor(), F_DUPFD_CLOEXEC, 0);
+                }
+            } else {
+                // An exception was thrown back; fall through to return failure
+                ALOGD("openContentUri(%s) caught exception %d\n",
+                        String8(stringUri).string(), exceptionCode);
+            }
+        }
+        return fd;
+    }
+};
+
+// ------------------------------------------------------------------------------------
+
+IMPLEMENT_META_INTERFACE(ActivityManager, "android.app.IActivityManager");
+
+}; // namespace android
diff --git a/libs/binder/IAppOpsCallback.cpp b/libs/binder/IAppOpsCallback.cpp
index 2aaf566..f9ec593 100644
--- a/libs/binder/IAppOpsCallback.cpp
+++ b/libs/binder/IAppOpsCallback.cpp
@@ -31,7 +31,7 @@
 class BpAppOpsCallback : public BpInterface<IAppOpsCallback>
 {
 public:
-    BpAppOpsCallback(const sp<IBinder>& impl)
+    explicit BpAppOpsCallback(const sp<IBinder>& impl)
         : BpInterface<IAppOpsCallback>(impl)
     {
     }
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index 9558376..638ae5c 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -31,7 +31,7 @@
 class BpAppOpsService : public BpInterface<IAppOpsService>
 {
 public:
-    BpAppOpsService(const sp<IBinder>& impl)
+    explicit BpAppOpsService(const sp<IBinder>& impl)
         : BpInterface<IAppOpsService>(impl)
     {
     }
diff --git a/libs/binder/IBatteryStats.cpp b/libs/binder/IBatteryStats.cpp
index e32c628..ad1e69f 100644
--- a/libs/binder/IBatteryStats.cpp
+++ b/libs/binder/IBatteryStats.cpp
@@ -29,7 +29,7 @@
 class BpBatteryStats : public BpInterface<IBatteryStats>
 {
 public:
-    BpBatteryStats(const sp<IBinder>& impl)
+    explicit BpBatteryStats(const sp<IBinder>& impl)
         : BpInterface<IBatteryStats>(impl)
     {
     }
diff --git a/libs/binder/IMediaResourceMonitor.cpp b/libs/binder/IMediaResourceMonitor.cpp
index 4800f5b..77e3d23 100644
--- a/libs/binder/IMediaResourceMonitor.cpp
+++ b/libs/binder/IMediaResourceMonitor.cpp
@@ -25,7 +25,7 @@
 
 class BpMediaResourceMonitor : public BpInterface<IMediaResourceMonitor> {
 public:
-    BpMediaResourceMonitor(const sp<IBinder>& impl)
+    explicit BpMediaResourceMonitor(const sp<IBinder>& impl)
         : BpInterface<IMediaResourceMonitor>(impl) {}
 
     virtual void notifyResourceGranted(/*in*/ int32_t pid, /*in*/ const int32_t type)
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index 5f345cf..5c1a4f4 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -16,22 +16,24 @@
 
 #define LOG_TAG "IMemory"
 
+#include <atomic>
+#include <stdatomic.h>
+
+#include <fcntl.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <fcntl.h>
-#include <unistd.h>
-
 #include <sys/types.h>
 #include <sys/mman.h>
+#include <unistd.h>
 
 #include <binder/IMemory.h>
-#include <cutils/log.h>
+#include <binder/Parcel.h>
+#include <log/log.h>
+
+#include <utils/CallStack.h>
 #include <utils/KeyedVector.h>
 #include <utils/threads.h>
-#include <utils/Atomic.h>
-#include <binder/Parcel.h>
-#include <utils/CallStack.h>
 
 #define VERBOSE   0
 
@@ -56,12 +58,15 @@
     struct heap_info_t {
         sp<IMemoryHeap> heap;
         int32_t         count;
+        // Note that this cannot be meaningfully copied.
     };
 
     void free_heap(const wp<IBinder>& binder);
 
-    Mutex mHeapCacheLock;
+    Mutex mHeapCacheLock;  // Protects entire vector below.
     KeyedVector< wp<IBinder>, heap_info_t > mHeapCache;
+    // We do not use the copy-on-write capabilities of KeyedVector.
+    // TODO: Reimplemement based on standard C++ container?
 };
 
 static sp<HeapCache> gHeapCache = new HeapCache();
@@ -75,7 +80,7 @@
 class BpMemoryHeap : public BpInterface<IMemoryHeap>
 {
 public:
-    BpMemoryHeap(const sp<IBinder>& impl);
+    explicit BpMemoryHeap(const sp<IBinder>& impl);
     virtual ~BpMemoryHeap();
 
     virtual int getHeapID() const;
@@ -105,7 +110,7 @@
     void assertMapped() const;
     void assertReallyMapped() const;
 
-    mutable volatile int32_t mHeapId;
+    mutable std::atomic<int32_t> mHeapId;
     mutable void*       mBase;
     mutable size_t      mSize;
     mutable uint32_t    mFlags;
@@ -123,7 +128,7 @@
 class BpMemory : public BpInterface<IMemory>
 {
 public:
-    BpMemory(const sp<IBinder>& impl);
+    explicit BpMemory(const sp<IBinder>& impl);
     virtual ~BpMemory();
     virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const;
 
@@ -248,8 +253,9 @@
 }
 
 BpMemoryHeap::~BpMemoryHeap() {
-    if (mHeapId != -1) {
-        close(mHeapId);
+    int32_t heapId = mHeapId.load(memory_order_relaxed);
+    if (heapId != -1) {
+        close(heapId);
         if (mRealHeap) {
             // by construction we're the last one
             if (mBase != MAP_FAILED) {
@@ -257,7 +263,7 @@
 
                 if (VERBOSE) {
                     ALOGD("UNMAPPING binder=%p, heap=%p, size=%zu, fd=%d",
-                            binder.get(), this, mSize, mHeapId);
+                            binder.get(), this, mSize, heapId);
                     CallStack stack(LOG_TAG);
                 }
 
@@ -273,17 +279,21 @@
 
 void BpMemoryHeap::assertMapped() const
 {
-    if (mHeapId == -1) {
+    int32_t heapId = mHeapId.load(memory_order_acquire);
+    if (heapId == -1) {
         sp<IBinder> binder(IInterface::asBinder(const_cast<BpMemoryHeap*>(this)));
         sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get()));
         heap->assertReallyMapped();
         if (heap->mBase != MAP_FAILED) {
             Mutex::Autolock _l(mLock);
-            if (mHeapId == -1) {
+            if (mHeapId.load(memory_order_relaxed) == -1) {
                 mBase   = heap->mBase;
                 mSize   = heap->mSize;
                 mOffset = heap->mOffset;
-                android_atomic_write( dup( heap->mHeapId ), &mHeapId );
+                int fd = fcntl(heap->mHeapId.load(memory_order_relaxed), F_DUPFD_CLOEXEC, 0);
+                ALOGE_IF(fd==-1, "cannot dup fd=%d",
+                        heap->mHeapId.load(memory_order_relaxed));
+                mHeapId.store(fd, memory_order_release);
             }
         } else {
             // something went wrong
@@ -294,7 +304,8 @@
 
 void BpMemoryHeap::assertReallyMapped() const
 {
-    if (mHeapId == -1) {
+    int32_t heapId = mHeapId.load(memory_order_acquire);
+    if (heapId == -1) {
 
         // remote call without mLock held, worse case scenario, we end up
         // calling transact() from multiple threads, but that's not a problem,
@@ -313,8 +324,8 @@
                 parcel_fd, size, err, strerror(-err));
 
         Mutex::Autolock _l(mLock);
-        if (mHeapId == -1) {
-            int fd = dup( parcel_fd );
+        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)",
                     parcel_fd, size, err, strerror(errno));
 
@@ -322,7 +333,6 @@
             if (!(flags & READ_ONLY)) {
                 access |= PROT_WRITE;
             }
-
             mRealHeap = true;
             mBase = mmap(0, size, access, MAP_SHARED, fd, offset);
             if (mBase == MAP_FAILED) {
@@ -333,7 +343,7 @@
                 mSize = size;
                 mFlags = flags;
                 mOffset = offset;
-                android_atomic_write(fd, &mHeapId);
+                mHeapId.store(fd, memory_order_release);
             }
         }
     }
@@ -341,7 +351,8 @@
 
 int BpMemoryHeap::getHeapID() const {
     assertMapped();
-    return mHeapId;
+    // We either stored mHeapId ourselves, or loaded it with acquire semantics.
+    return mHeapId.load(memory_order_relaxed);
 }
 
 void* BpMemoryHeap::getBase() const {
@@ -418,9 +429,10 @@
                 "found binder=%p, heap=%p, size=%zu, fd=%d, count=%d",
                 binder.get(), info.heap.get(),
                 static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
-                static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
+                static_cast<BpMemoryHeap*>(info.heap.get())
+                    ->mHeapId.load(memory_order_relaxed),
                 info.count);
-        android_atomic_inc(&info.count);
+        ++info.count;
         return info.heap;
     } else {
         heap_info_t info;
@@ -445,13 +457,13 @@
         ssize_t i = mHeapCache.indexOfKey(binder);
         if (i>=0) {
             heap_info_t& info(mHeapCache.editValueAt(i));
-            int32_t c = android_atomic_dec(&info.count);
-            if (c == 1) {
+            if (--info.count == 0) {
                 ALOGD_IF(VERBOSE,
                         "removing binder=%p, heap=%p, size=%zu, fd=%d, count=%d",
                         binder.unsafe_get(), info.heap.get(),
                         static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
-                        static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
+                        static_cast<BpMemoryHeap*>(info.heap.get())
+                            ->mHeapId.load(memory_order_relaxed),
                         info.count);
                 rel = mHeapCache.valueAt(i).heap;
                 mHeapCache.removeItemsAt(i);
@@ -482,7 +494,7 @@
         ALOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%zu)",
                 mHeapCache.keyAt(i).unsafe_get(),
                 info.heap.get(), info.count,
-                h->mHeapId, h->mBase, h->mSize);
+                h->mHeapId.load(memory_order_relaxed), h->mBase, h->mSize);
     }
 }
 
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index eccc400..e832961 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -65,10 +65,6 @@
 
 namespace android {
 
-static const char* getReturnString(size_t idx);
-static const void* printReturnCommand(TextOutput& out, const void* _cmd);
-static const void* printCommand(TextOutput& out, const void* _cmd);
-
 // Static const and functions will be optimized out if not used,
 // when LOG_NDEBUG and references in IF_LOG_COMMANDS() are optimized out.
 static const char *kReturnStrings[] = {
@@ -112,8 +108,9 @@
     "BC_DEAD_BINDER_DONE"
 };
 
-static const char* getReturnString(size_t idx)
+static const char* getReturnString(uint32_t cmd)
 {
+    size_t idx = cmd & 0xff;
     if (idx < sizeof(kReturnStrings) / sizeof(kReturnStrings[0]))
         return kReturnStrings[idx];
     else
@@ -331,6 +328,7 @@
             delete st;
             pthread_setspecific(gTLS, NULL);
         }
+        pthread_key_delete(gTLS);
         gHaveTLS = false;
     }
 }
@@ -340,6 +338,11 @@
     gDisableBackgroundScheduling = disable;
 }
 
+bool IPCThreadState::backgroundSchedulingDisabled()
+{
+    return gDisableBackgroundScheduling;
+}
+
 sp<ProcessState> IPCThreadState::process()
 {
     return mProcess;
@@ -512,9 +515,9 @@
         }
     } while (result != -ECONNREFUSED && result != -EBADF);
 
-    LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",
-        (void*)pthread_self(), getpid(), (void*)result);
-    
+    LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%d\n",
+        (void*)pthread_self(), getpid(), result);
+
     mOut.writeInt32(BC_EXIT_LOOPER);
     talkWithDriver(false);
 }
@@ -655,7 +658,7 @@
     waitForResponse(NULL, &result);
 
 #if LOG_REFCOUNTS
-    printf("IPCThreadState::attemptIncStrongHandle(%ld) = %s\n",
+    ALOGV("IPCThreadState::attemptIncStrongHandle(%ld) = %s\n",
         handle, result == NO_ERROR ? "SUCCESS" : "FAILURE");
 #endif
 
@@ -670,7 +673,7 @@
 void IPCThreadState::expungeHandle(int32_t handle, IBinder* binder)
 {
 #if LOG_REFCOUNTS
-    printf("IPCThreadState::expungeHandle(%ld)\n", handle);
+    ALOGV("IPCThreadState::expungeHandle(%ld)\n", handle);
 #endif
     self()->mProcess->expungeHandle(handle, binder);
 }
@@ -1136,7 +1139,7 @@
         break;
 
     default:
-        printf("*** BAD COMMAND %d received from Binder driver\n", cmd);
+        ALOGE("*** BAD COMMAND %d received from Binder driver\n", cmd);
         result = UNKNOWN_ERROR;
         break;
     }
diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp
index 6bba996..674bddf 100644
--- a/libs/binder/IPermissionController.cpp
+++ b/libs/binder/IPermissionController.cpp
@@ -31,7 +31,7 @@
 class BpPermissionController : public BpInterface<IPermissionController>
 {
 public:
-    BpPermissionController(const sp<IBinder>& impl)
+    explicit BpPermissionController(const sp<IBinder>& impl)
         : BpInterface<IPermissionController>(impl)
     {
     }
diff --git a/libs/binder/IProcessInfoService.cpp b/libs/binder/IProcessInfoService.cpp
index 76508b8..96e1a8c 100644
--- a/libs/binder/IProcessInfoService.cpp
+++ b/libs/binder/IProcessInfoService.cpp
@@ -25,7 +25,7 @@
 
 class BpProcessInfoService : public BpInterface<IProcessInfoService> {
 public:
-    BpProcessInfoService(const sp<IBinder>& impl)
+    explicit BpProcessInfoService(const sp<IBinder>& impl)
         : BpInterface<IProcessInfoService>(impl) {}
 
     virtual status_t getProcessStatesFromPids(size_t length, /*in*/ int32_t* pids,
diff --git a/libs/binder/IResultReceiver.cpp b/libs/binder/IResultReceiver.cpp
index 2a22b69..646809e 100644
--- a/libs/binder/IResultReceiver.cpp
+++ b/libs/binder/IResultReceiver.cpp
@@ -31,7 +31,7 @@
 class BpResultReceiver : public BpInterface<IResultReceiver>
 {
 public:
-    BpResultReceiver(const sp<IBinder>& impl)
+    explicit BpResultReceiver(const sp<IBinder>& impl)
         : BpInterface<IResultReceiver>(impl)
     {
     }
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 44d235f..c7a0f43 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -23,6 +23,7 @@
 #include <binder/Parcel.h>
 #include <utils/String8.h>
 #include <utils/SystemClock.h>
+#include <utils/CallStack.h>
 
 #include <private/binder/Static.h>
 
@@ -67,11 +68,6 @@
 
 bool checkPermission(const String16& permission, pid_t pid, uid_t uid)
 {
-#ifdef __BRILLO__
-    // Brillo doesn't currently run ActivityManager or support framework permissions.
-    return true;
-#endif
-
     sp<IPermissionController> pc;
     gDefaultServiceManagerLock.lock();
     pc = gPermissionController;
@@ -131,7 +127,7 @@
 class BpServiceManager : public BpInterface<IServiceManager>
 {
 public:
-    BpServiceManager(const sp<IBinder>& impl)
+    explicit BpServiceManager(const sp<IBinder>& impl)
         : BpInterface<IServiceManager>(impl)
     {
     }
@@ -141,7 +137,12 @@
         unsigned n;
         for (n = 0; n < 5; n++){
             if (n > 0) {
-                ALOGI("Waiting for service %s...", String8(name).string());
+                if (!strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder")) {
+                    ALOGI("Waiting for vendor service %s...", String8(name).string());
+                    CallStack stack(LOG_TAG);
+                } else {
+                    ALOGI("Waiting for service %s...", String8(name).string());
+                }
                 sleep(1);
             }
             sp<IBinder> svc = checkService(name);
diff --git a/libs/binder/IShellCallback.cpp b/libs/binder/IShellCallback.cpp
new file mode 100644
index 0000000..c793df3
--- /dev/null
+++ b/libs/binder/IShellCallback.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ShellCallback"
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <binder/IShellCallback.h>
+
+#include <utils/Log.h>
+#include <binder/Parcel.h>
+#include <utils/String8.h>
+
+#include <private/binder/Static.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class BpShellCallback : public BpInterface<IShellCallback>
+{
+public:
+    explicit BpShellCallback(const sp<IBinder>& impl)
+        : BpInterface<IShellCallback>(impl)
+    {
+    }
+
+    virtual int openOutputFile(const String16& path, const String16& seLinuxContext) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IShellCallback::getInterfaceDescriptor());
+        data.writeString16(path);
+        data.writeString16(seLinuxContext);
+        remote()->transact(OP_OPEN_OUTPUT_FILE, data, &reply, 0);
+        reply.readExceptionCode();
+        int fd = reply.readParcelFileDescriptor();
+        return fd >= 0 ? fcntl(fd, F_DUPFD_CLOEXEC, 0) : fd;
+
+    }
+};
+
+IMPLEMENT_META_INTERFACE(ShellCallback, "com.android.internal.os.IShellCallback");
+
+// ----------------------------------------------------------------------
+
+status_t BnShellCallback::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case OP_OPEN_OUTPUT_FILE: {
+            CHECK_INTERFACE(IShellCallback, data, reply);
+            String16 path(data.readString16());
+            String16 seLinuxContext(data.readString16());
+            int fd = openOutputFile(path, seLinuxContext);
+            if (reply != NULL) {
+                reply->writeNoException();
+                if (fd >= 0) {
+                    reply->writeInt32(1);
+                    reply->writeParcelFileDescriptor(fd, true);
+                } else {
+                    reply->writeInt32(0);
+                }
+            } else if (fd >= 0) {
+                close(fd);
+            }
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+}; // namespace android
diff --git a/libs/binder/IpPrefix.cpp b/libs/binder/IpPrefix.cpp
new file mode 100644
index 0000000..3a8a63c
--- /dev/null
+++ b/libs/binder/IpPrefix.cpp
@@ -0,0 +1,174 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "IpPrefix"
+
+#include <binder/IpPrefix.h>
+#include <vector>
+
+#include <binder/IBinder.h>
+#include <binder/Parcel.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+
+using android::BAD_TYPE;
+using android::BAD_VALUE;
+using android::NO_ERROR;
+using android::Parcel;
+using android::status_t;
+using android::UNEXPECTED_NULL;
+using namespace ::android::binder;
+
+namespace android {
+
+namespace net {
+
+#define RETURN_IF_FAILED(calledOnce)                                     \
+    {                                                                    \
+        status_t returnStatus = calledOnce;                              \
+        if (returnStatus) {                                              \
+            ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \
+            return returnStatus;                                         \
+         }                                                               \
+    }
+
+status_t IpPrefix::writeToParcel(Parcel* parcel) const {
+    /*
+     * Keep implementation in sync with writeToParcel() in
+     * frameworks/base/core/java/android/net/IpPrefix.java.
+     */
+    std::vector<uint8_t> byte_vector;
+
+    if (mIsIpv6) {
+        const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&mUnion.mIn6Addr);
+        byte_vector.insert(byte_vector.end(), bytes, bytes+sizeof(mUnion.mIn6Addr));
+    } else {
+        const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&mUnion.mInAddr);
+        byte_vector.insert(byte_vector.end(), bytes, bytes+sizeof(mUnion.mIn6Addr));
+    }
+
+    RETURN_IF_FAILED(parcel->writeByteVector(byte_vector));
+    RETURN_IF_FAILED(parcel->writeInt32(static_cast<int32_t>(mPrefixLength)));
+
+    return NO_ERROR;
+}
+
+status_t IpPrefix::readFromParcel(const Parcel* parcel) {
+    /*
+     * Keep implementation in sync with readFromParcel() in
+     * frameworks/base/core/java/android/net/IpPrefix.java.
+     */
+    std::vector<uint8_t> byte_vector;
+
+    RETURN_IF_FAILED(parcel->readByteVector(&byte_vector));
+    RETURN_IF_FAILED(parcel->readInt32(&mPrefixLength));
+
+    if (byte_vector.size() == 16) {
+        mIsIpv6 = true;
+        memcpy((void*)&mUnion.mIn6Addr, &byte_vector[0], sizeof(mUnion.mIn6Addr));
+
+    } else if (byte_vector.size() == 4) {
+        mIsIpv6 = false;
+        memcpy((void*)&mUnion.mInAddr, &byte_vector[0], sizeof(mUnion.mInAddr));
+
+    } else {
+        ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \
+        return BAD_VALUE;
+    }
+
+    return NO_ERROR;
+}
+
+const struct in6_addr& IpPrefix::getAddressAsIn6Addr() const
+{
+    return mUnion.mIn6Addr;
+}
+
+const struct in_addr& IpPrefix::getAddressAsInAddr() const
+{
+    return mUnion.mInAddr;
+}
+
+bool IpPrefix::getAddressAsIn6Addr(struct in6_addr* addr) const
+{
+    if (isIpv6()) {
+        *addr = mUnion.mIn6Addr;
+        return true;
+    }
+    return false;
+}
+
+bool IpPrefix::getAddressAsInAddr(struct in_addr* addr) const
+{
+    if (isIpv4()) {
+        *addr = mUnion.mInAddr;
+        return true;
+    }
+    return false;
+}
+
+bool IpPrefix::isIpv6() const
+{
+    return mIsIpv6;
+}
+
+bool IpPrefix::isIpv4() const
+{
+    return !mIsIpv6;
+}
+
+int32_t IpPrefix::getPrefixLength() const
+{
+    return mPrefixLength;
+}
+
+void IpPrefix::setAddress(const struct in6_addr& addr)
+{
+    mUnion.mIn6Addr = addr;
+    mIsIpv6 = true;
+}
+
+void IpPrefix::setAddress(const struct in_addr& addr)
+{
+    mUnion.mInAddr = addr;
+    mIsIpv6 = false;
+}
+
+void IpPrefix::setPrefixLength(int32_t prefix)
+{
+    mPrefixLength = prefix;
+}
+
+bool operator==(const IpPrefix& lhs, const IpPrefix& rhs)
+{
+    if (lhs.mIsIpv6 != rhs.mIsIpv6) {
+        return false;
+    }
+
+    if (lhs.mPrefixLength != rhs.mPrefixLength) {
+        return false;
+    }
+
+    if (lhs.mIsIpv6) {
+        return 0 == memcmp(lhs.mUnion.mIn6Addr.s6_addr, rhs.mUnion.mIn6Addr.s6_addr, sizeof(struct in6_addr));
+    }
+
+    return 0 == memcmp(&lhs.mUnion.mInAddr, &rhs.mUnion.mInAddr, sizeof(struct in_addr));
+}
+
+}  // namespace net
+
+}  // namespace android
diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp
index 51eac11..2a15773 100644
--- a/libs/binder/MemoryDealer.cpp
+++ b/libs/binder/MemoryDealer.cpp
@@ -126,7 +126,7 @@
         PAGE_ALIGNED = 0x00000001
     };
 public:
-    SimpleBestFitAllocator(size_t size);
+    explicit SimpleBestFitAllocator(size_t size);
     ~SimpleBestFitAllocator();
 
     size_t      allocate(size_t size, uint32_t flags = 0);
diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
index 43a01e4..03f00be 100644
--- a/libs/binder/MemoryHeapBase.cpp
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -16,20 +16,19 @@
 
 #define LOG_TAG "MemoryHeapBase"
 
-#include <stdlib.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <fcntl.h>
 #include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdlib.h>
 #include <sys/ioctl.h>
-
-#include <cutils/log.h>
-#include <cutils/ashmem.h>
-#include <cutils/atomic.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include <binder/MemoryHeapBase.h>
+#include <cutils/ashmem.h>
+#include <cutils/atomic.h>
+#include <log/log.h>
 
 namespace android {
 
@@ -83,7 +82,7 @@
 {
     const size_t pagesize = getpagesize();
     size = ((size + pagesize-1) & ~(pagesize-1));
-    mapfd(dup(fd), size, offset);
+    mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), size, offset);
 }
 
 status_t MemoryHeapBase::init(int fd, void *base, int size, int flags, const char* device)
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 19ce3eb..aec8f10 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -37,6 +37,7 @@
 #include <binder/ProcessState.h>
 #include <binder/Status.h>
 #include <binder/TextOutput.h>
+#include <binder/Value.h>
 
 #include <cutils/ashmem.h>
 #include <utils/Debug.h>
@@ -100,32 +101,6 @@
     BLOB_ASHMEM_MUTABLE = 2,
 };
 
-static dev_t ashmem_rdev()
-{
-    static dev_t __ashmem_rdev;
-    static pthread_mutex_t __ashmem_rdev_lock = PTHREAD_MUTEX_INITIALIZER;
-
-    pthread_mutex_lock(&__ashmem_rdev_lock);
-
-    dev_t rdev = __ashmem_rdev;
-    if (!rdev) {
-        int fd = TEMP_FAILURE_RETRY(open("/dev/ashmem", O_RDONLY));
-        if (fd >= 0) {
-            struct stat st;
-
-            int ret = TEMP_FAILURE_RETRY(fstat(fd, &st));
-            close(fd);
-            if ((ret >= 0) && S_ISCHR(st.st_mode)) {
-                rdev = __ashmem_rdev = st.st_rdev;
-            }
-        }
-    }
-
-    pthread_mutex_unlock(&__ashmem_rdev_lock);
-
-    return rdev;
-}
-
 void acquire_object(const sp<ProcessState>& proc,
     const flat_binder_object& obj, const void* who, size_t* outAshmemSize)
 {
@@ -154,15 +129,11 @@
             return;
         }
         case BINDER_TYPE_FD: {
-            if ((obj.cookie != 0) && (outAshmemSize != NULL)) {
-                struct stat st;
-                int ret = fstat(obj.handle, &st);
-                if (!ret && S_ISCHR(st.st_mode) && (st.st_rdev == ashmem_rdev())) {
-                    // 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) {
-                        *outAshmemSize += size;
-                    }
+            if ((obj.cookie != 0) && (outAshmemSize != NULL) && 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) {
+                    *outAshmemSize += size;
                 }
             }
             return;
@@ -207,14 +178,10 @@
         }
         case BINDER_TYPE_FD: {
             if (obj.cookie != 0) { // owned
-                if (outAshmemSize != NULL) {
-                    struct stat st;
-                    int ret = fstat(obj.handle, &st);
-                    if (!ret && S_ISCHR(st.st_mode) && (st.st_rdev == ashmem_rdev())) {
-                        int size = ashmem_get_size_region(obj.handle);
-                        if (size > 0) {
-                            *outAshmemSize -= size;
-                        }
+                if ((outAshmemSize != NULL) && ashmem_valid(obj.handle)) {
+                    int size = ashmem_get_size_region(obj.handle);
+                    if (size > 0) {
+                        *outAshmemSize -= size;
                     }
                 }
 
@@ -244,7 +211,14 @@
 {
     flat_binder_object obj;
 
-    obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+    if (IPCThreadState::self()->backgroundSchedulingDisabled()) {
+        /* minimum priority for all nodes is nice 0 */
+        obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;
+    } else {
+        /* minimum priority for all nodes is MAX_NICE(19) */
+        obj.flags = 0x13 | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+    }
+
     if (binder != NULL) {
         IBinder *local = binder->localBinder();
         if (!local) {
@@ -573,7 +547,7 @@
                 // If this is a file descriptor, we need to dup it so the
                 // new Parcel now owns its own fd, and can declare that we
                 // officially know we have fds.
-                flat->handle = dup(flat->handle);
+                flat->handle = fcntl(flat->handle, F_DUPFD_CLOEXEC, 0);
                 flat->cookie = 1;
                 mHasFds = mFdsKnown = true;
                 if (!mAllowFds) {
@@ -586,6 +560,14 @@
     return err;
 }
 
+int Parcel::compareData(const Parcel& other) {
+    size_t size = dataSize();
+    if (size != other.dataSize()) {
+        return size < other.dataSize() ? -1 : 1;
+    }
+    return memcmp(data(), other.data(), size);
+}
+
 bool Parcel::allowFds() const
 {
     return mAllowFds;
@@ -784,7 +766,7 @@
     const uint8_t* strData = (uint8_t*)str.data();
     const size_t strLen= str.length();
     const ssize_t utf16Len = utf8_to_utf16_length(strData, strLen);
-    if (utf16Len < 0 || utf16Len> std::numeric_limits<int32_t>::max()) {
+    if (utf16Len < 0 || utf16Len > std::numeric_limits<int32_t>::max()) {
         return BAD_VALUE;
     }
 
@@ -799,7 +781,7 @@
         return NO_MEMORY;
     }
 
-    utf8_to_utf16(strData, strLen, (char16_t*)dst);
+    utf8_to_utf16(strData, strLen, (char16_t*)dst, (size_t) utf16Len + 1);
 
     return NO_ERROR;
 }
@@ -1112,7 +1094,7 @@
 }
 
 status_t Parcel::readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readStrongBinder);
+    return readNullableTypedVector(val, &Parcel::readNullableStrongBinder);
 }
 
 status_t Parcel::readStrongBinderVector(std::vector<sp<IBinder>>* val) const {
@@ -1140,6 +1122,10 @@
     return parcelable.writeToParcel(this);
 }
 
+status_t Parcel::writeValue(const binder::Value& value) {
+    return value.writeToParcel(this);
+}
+
 status_t Parcel::writeNativeHandle(const native_handle* handle)
 {
     if (!handle || handle->version != sizeof(native_handle))
@@ -1176,7 +1162,7 @@
 
 status_t Parcel::writeDupFileDescriptor(int fd)
 {
-    int dupFd = dup(fd);
+    int dupFd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
     if (dupFd < 0) {
         return -errno;
     }
@@ -1187,15 +1173,21 @@
     return err;
 }
 
-status_t Parcel::writeUniqueFileDescriptor(const ScopedFd& fd) {
+status_t Parcel::writeParcelFileDescriptor(int fd, bool takeOwnership)
+{
+    writeInt32(0);
+    return writeFileDescriptor(fd, takeOwnership);
+}
+
+status_t Parcel::writeUniqueFileDescriptor(const base::unique_fd& fd) {
     return writeDupFileDescriptor(fd.get());
 }
 
-status_t Parcel::writeUniqueFileDescriptorVector(const std::vector<ScopedFd>& val) {
+status_t Parcel::writeUniqueFileDescriptorVector(const std::vector<base::unique_fd>& val) {
     return writeTypedVector(val, &Parcel::writeUniqueFileDescriptor);
 }
 
-status_t Parcel::writeUniqueFileDescriptorVector(const std::unique_ptr<std::vector<ScopedFd>>& val) {
+status_t Parcel::writeUniqueFileDescriptorVector(const std::unique_ptr<std::vector<base::unique_fd>>& val) {
     return writeNullableTypedVector(val, &Parcel::writeUniqueFileDescriptor);
 }
 
@@ -1358,6 +1350,120 @@
     return status.writeToParcel(this);
 }
 
+status_t Parcel::writeMap(const ::android::binder::Map& map_in)
+{
+    using ::std::map;
+    using ::android::binder::Value;
+    using ::android::binder::Map;
+
+    Map::const_iterator iter;
+    status_t ret;
+
+    ret = writeInt32(map_in.size());
+
+    if (ret != NO_ERROR) {
+        return ret;
+    }
+
+    for (iter = map_in.begin(); iter != map_in.end(); ++iter) {
+        ret = writeValue(Value(iter->first));
+        if (ret != NO_ERROR) {
+            return ret;
+        }
+
+        ret = writeValue(iter->second);
+        if (ret != NO_ERROR) {
+            return ret;
+        }
+    }
+
+    return ret;
+}
+
+status_t Parcel::writeNullableMap(const std::unique_ptr<binder::Map>& map)
+{
+    if (map == NULL) {
+        return writeInt32(-1);
+    }
+
+    return writeMap(*map.get());
+}
+
+status_t Parcel::readMap(::android::binder::Map* map_out)const
+{
+    using ::std::map;
+    using ::android::String16;
+    using ::android::String8;
+    using ::android::binder::Value;
+    using ::android::binder::Map;
+
+    status_t ret = NO_ERROR;
+    int32_t count;
+
+    ret = readInt32(&count);
+    if (ret != NO_ERROR) {
+        return ret;
+    }
+
+    if (count < 0) {
+        ALOGE("readMap: Unexpected count: %d", count);
+        return (count == -1)
+            ? UNEXPECTED_NULL
+            : BAD_VALUE;
+    }
+
+    map_out->clear();
+
+    while (count--) {
+        Map::key_type key;
+        Value value;
+
+        ret = readValue(&value);
+        if (ret != NO_ERROR) {
+            return ret;
+        }
+
+        if (!value.getString(&key)) {
+            ALOGE("readMap: Key type not a string (parcelType = %d)", value.parcelType());
+            return BAD_VALUE;
+        }
+
+        ret = readValue(&value);
+        if (ret != NO_ERROR) {
+            return ret;
+        }
+
+        (*map_out)[key] = value;
+    }
+
+    return ret;
+}
+
+status_t Parcel::readNullableMap(std::unique_ptr<binder::Map>* map) const
+{
+    const size_t start = dataPosition();
+    int32_t count;
+    status_t status = readInt32(&count);
+    map->reset();
+
+    if (status != OK || count == -1) {
+        return status;
+    }
+
+    setDataPosition(start);
+    map->reset(new binder::Map());
+
+    status = readMap(map->get());
+
+    if (status != OK) {
+        map->reset();
+    }
+
+    return status;
+}
+
+
+
 void Parcel::remove(size_t /*start*/, size_t /*amt*/)
 {
     LOG_ALWAYS_FATAL("Parcel::remove() not yet implemented!");
@@ -1461,13 +1567,13 @@
         return status;
     }
 
-    const void* data = parcel->readInplace(size);
+    T* data = const_cast<T*>(reinterpret_cast<const T*>(parcel->readInplace(size)));
     if (!data) {
         status = BAD_VALUE;
         return status;
     }
-    val->resize(size);
-    memcpy(val->data(), data, size);
+    val->reserve(size);
+    val->insert(val->end(), data, data + size);
 
     return status;
 }
@@ -1842,13 +1948,37 @@
 
 String8 Parcel::readString8() const
 {
-    int32_t size = readInt32();
-    // watch for potential int overflow adding 1 for trailing NUL
-    if (size > 0 && size < INT32_MAX) {
-        const char* str = (const char*)readInplace(size+1);
-        if (str) return String8(str, size);
+    String8 retString;
+    status_t status = readString8(&retString);
+    if (status != OK) {
+        // We don't care about errors here, so just return an empty string.
+        return String8();
     }
-    return String8();
+    return retString;
+}
+
+status_t Parcel::readString8(String8* pArg) const
+{
+    int32_t size;
+    status_t status = readInt32(&size);
+    if (status != OK) {
+        return status;
+    }
+    // watch for potential int overflow from size+1
+    if (size < 0 || size >= INT32_MAX) {
+        return BAD_VALUE;
+    }
+    // |writeString8| writes nothing for empty string.
+    if (size == 0) {
+        *pArg = String8();
+        return OK;
+    }
+    const char* str = (const char*)readInplace(size + 1);
+    if (str == NULL) {
+        return BAD_VALUE;
+    }
+    pArg->setTo(str, size);
+    return OK;
 }
 
 String16 Parcel::readString16() const
@@ -1913,13 +2043,25 @@
 
 status_t Parcel::readStrongBinder(sp<IBinder>* val) const
 {
+    status_t status = readNullableStrongBinder(val);
+    if (status == OK && !val->get()) {
+        status = UNEXPECTED_NULL;
+    }
+    return status;
+}
+
+status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
+{
     return unflatten_binder(ProcessState::self(), *this, val);
 }
 
 sp<IBinder> Parcel::readStrongBinder() const
 {
     sp<IBinder> val;
-    readStrongBinder(&val);
+    // Note that a lot of code in Android reads binders by hand with this
+    // method, and that code has historically been ok with getting nullptr
+    // back (while ignoring error codes).
+    readNullableStrongBinder(&val);
     return val;
 }
 
@@ -1942,6 +2084,10 @@
     return parcelable->readFromParcel(this);
 }
 
+status_t Parcel::readValue(binder::Value* value) const {
+    return value->readFromParcel(this);
+}
+
 int32_t Parcel::readExceptionCode() const
 {
     binder::Status status;
@@ -1964,7 +2110,7 @@
     }
 
     for (int i=0 ; err==NO_ERROR && i<numFds ; i++) {
-        h->data[i] = dup(readFileDescriptor());
+        h->data[i] = fcntl(readFileDescriptor(), F_DUPFD_CLOEXEC, 0);
         if (h->data[i] < 0) {
             for (int j = 0; j < i; j++) {
                 close(h->data[j]);
@@ -1982,7 +2128,6 @@
     return h;
 }
 
-
 int Parcel::readFileDescriptor() const
 {
     const flat_binder_object* flat = readObject(true);
@@ -1994,7 +2139,18 @@
     return BAD_TYPE;
 }
 
-status_t Parcel::readUniqueFileDescriptor(ScopedFd* val) const
+int Parcel::readParcelFileDescriptor() const
+{
+    int32_t hasComm = readInt32();
+    int fd = readFileDescriptor();
+    if (hasComm != 0) {
+        // skip
+        readFileDescriptor();
+    }
+    return fd;
+}
+
+status_t Parcel::readUniqueFileDescriptor(base::unique_fd* val) const
 {
     int got = readFileDescriptor();
 
@@ -2002,7 +2158,7 @@
         return BAD_TYPE;
     }
 
-    val->reset(dup(got));
+    val->reset(fcntl(got, F_DUPFD_CLOEXEC, 0));
 
     if (val->get() < 0) {
         return BAD_VALUE;
@@ -2012,11 +2168,11 @@
 }
 
 
-status_t Parcel::readUniqueFileDescriptorVector(std::unique_ptr<std::vector<ScopedFd>>* val) const {
+status_t Parcel::readUniqueFileDescriptorVector(std::unique_ptr<std::vector<base::unique_fd>>* val) const {
     return readNullableTypedVector(val, &Parcel::readUniqueFileDescriptor);
 }
 
-status_t Parcel::readUniqueFileDescriptorVector(std::vector<ScopedFd>* val) const {
+status_t Parcel::readUniqueFileDescriptorVector(std::vector<base::unique_fd>* val) const {
     return readTypedVector(val, &Parcel::readUniqueFileDescriptor);
 }
 
@@ -2076,11 +2232,15 @@
 
     status_t err = NO_ERROR;
     for (size_t i=0 ; i<fd_count && err==NO_ERROR ; i++) {
-        fds[i] = dup(this->readFileDescriptor());
-        if (fds[i] < 0) {
+        int fd = this->readFileDescriptor();
+        if (fd < 0 || ((fds[i] = fcntl(fd, F_DUPFD_CLOEXEC, 0)) < 0)) {
             err = BAD_VALUE;
-            ALOGE("dup() failed in Parcel::read, i is %zu, fds[i] is %d, fd_count is %zu, error: %s",
-                i, fds[i], fd_count, strerror(errno));
+            ALOGE("fcntl(F_DUPFD_CLOEXEC) failed in Parcel::read, i is %zu, fds[i] is %d, fd_count is %zu, error: %s",
+                  i, fds[i], fd_count, strerror(fd < 0 ? -fd : errno));
+            // Close all the file descriptors that were dup-ed.
+            for (size_t j=0; j<i ;j++) {
+                close(fds[j]);
+            }
         }
     }
 
diff --git a/libs/binder/PersistableBundle.cpp b/libs/binder/PersistableBundle.cpp
index aef791c..d617b5a 100644
--- a/libs/binder/PersistableBundle.cpp
+++ b/libs/binder/PersistableBundle.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "PersistableBundle"
 
 #include <binder/PersistableBundle.h>
+#include <private/binder/ParcelValTypes.h>
 
 #include <limits>
 
@@ -32,35 +33,34 @@
 using android::sp;
 using android::status_t;
 using android::UNEXPECTED_NULL;
+using std::map;
+using std::set;
+using std::vector;
+using namespace ::android::binder;
 
 enum {
     // Keep in sync with BUNDLE_MAGIC in frameworks/base/core/java/android/os/BaseBundle.java.
     BUNDLE_MAGIC = 0x4C444E42,
 };
 
-enum {
-    // Keep in sync with frameworks/base/core/java/android/os/Parcel.java.
-    VAL_STRING = 0,
-    VAL_INTEGER = 1,
-    VAL_LONG = 6,
-    VAL_DOUBLE = 8,
-    VAL_BOOLEAN = 9,
-    VAL_STRINGARRAY = 14,
-    VAL_INTARRAY = 18,
-    VAL_LONGARRAY = 19,
-    VAL_BOOLEANARRAY = 23,
-    VAL_PERSISTABLEBUNDLE = 25,
-    VAL_DOUBLEARRAY = 28,
-};
-
 namespace {
 template <typename T>
-bool getValue(const android::String16& key, T* out, const std::map<android::String16, T>& map) {
+bool getValue(const android::String16& key, T* out, const map<android::String16, T>& map) {
     const auto& it = map.find(key);
     if (it == map.end()) return false;
     *out = it->second;
     return true;
 }
+
+template <typename T>
+set<android::String16> getKeys(const map<android::String16, T>& map) {
+    if (map.empty()) return set<android::String16>();
+    set<android::String16> keys;
+    for (const auto& key_value_pair : map) {
+        keys.emplace(key_value_pair.first);
+    }
+    return keys;
+}
 }  // namespace
 
 namespace android {
@@ -78,7 +78,7 @@
 
 #define RETURN_IF_ENTRY_ERASED(map, key)                                 \
     {                                                                    \
-        size_t num_erased = map.erase(key);                              \
+        size_t num_erased = (map).erase(key);                            \
         if (num_erased) {                                                \
             ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \
             return num_erased;                                           \
@@ -188,27 +188,27 @@
     mStringMap[key] = value;
 }
 
-void PersistableBundle::putBooleanVector(const String16& key, const std::vector<bool>& value) {
+void PersistableBundle::putBooleanVector(const String16& key, const vector<bool>& value) {
     erase(key);
     mBoolVectorMap[key] = value;
 }
 
-void PersistableBundle::putIntVector(const String16& key, const std::vector<int32_t>& value) {
+void PersistableBundle::putIntVector(const String16& key, const vector<int32_t>& value) {
     erase(key);
     mIntVectorMap[key] = value;
 }
 
-void PersistableBundle::putLongVector(const String16& key, const std::vector<int64_t>& value) {
+void PersistableBundle::putLongVector(const String16& key, const vector<int64_t>& value) {
     erase(key);
     mLongVectorMap[key] = value;
 }
 
-void PersistableBundle::putDoubleVector(const String16& key, const std::vector<double>& value) {
+void PersistableBundle::putDoubleVector(const String16& key, const vector<double>& value) {
     erase(key);
     mDoubleVectorMap[key] = value;
 }
 
-void PersistableBundle::putStringVector(const String16& key, const std::vector<String16>& value) {
+void PersistableBundle::putStringVector(const String16& key, const vector<String16>& value) {
     erase(key);
     mStringVectorMap[key] = value;
 }
@@ -238,23 +238,23 @@
     return getValue(key, out, mStringMap);
 }
 
-bool PersistableBundle::getBooleanVector(const String16& key, std::vector<bool>* out) const {
+bool PersistableBundle::getBooleanVector(const String16& key, vector<bool>* out) const {
     return getValue(key, out, mBoolVectorMap);
 }
 
-bool PersistableBundle::getIntVector(const String16& key, std::vector<int32_t>* out) const {
+bool PersistableBundle::getIntVector(const String16& key, vector<int32_t>* out) const {
     return getValue(key, out, mIntVectorMap);
 }
 
-bool PersistableBundle::getLongVector(const String16& key, std::vector<int64_t>* out) const {
+bool PersistableBundle::getLongVector(const String16& key, vector<int64_t>* out) const {
     return getValue(key, out, mLongVectorMap);
 }
 
-bool PersistableBundle::getDoubleVector(const String16& key, std::vector<double>* out) const {
+bool PersistableBundle::getDoubleVector(const String16& key, vector<double>* out) const {
     return getValue(key, out, mDoubleVectorMap);
 }
 
-bool PersistableBundle::getStringVector(const String16& key, std::vector<String16>* out) const {
+bool PersistableBundle::getStringVector(const String16& key, vector<String16>* out) const {
     return getValue(key, out, mStringVectorMap);
 }
 
@@ -262,6 +262,50 @@
     return getValue(key, out, mPersistableBundleMap);
 }
 
+set<String16> PersistableBundle::getBooleanKeys() const {
+    return getKeys(mBoolMap);
+}
+
+set<String16> PersistableBundle::getIntKeys() const {
+    return getKeys(mIntMap);
+}
+
+set<String16> PersistableBundle::getLongKeys() const {
+    return getKeys(mLongMap);
+}
+
+set<String16> PersistableBundle::getDoubleKeys() const {
+    return getKeys(mDoubleMap);
+}
+
+set<String16> PersistableBundle::getStringKeys() const {
+    return getKeys(mStringMap);
+}
+
+set<String16> PersistableBundle::getBooleanVectorKeys() const {
+    return getKeys(mBoolVectorMap);
+}
+
+set<String16> PersistableBundle::getIntVectorKeys() const {
+    return getKeys(mIntVectorMap);
+}
+
+set<String16> PersistableBundle::getLongVectorKeys() const {
+    return getKeys(mLongVectorMap);
+}
+
+set<String16> PersistableBundle::getDoubleVectorKeys() const {
+    return getKeys(mDoubleVectorMap);
+}
+
+set<String16> PersistableBundle::getStringVectorKeys() const {
+    return getKeys(mStringVectorMap);
+}
+
+set<String16> PersistableBundle::getPersistableBundleKeys() const {
+    return getKeys(mPersistableBundleMap);
+}
+
 status_t PersistableBundle::writeToParcelInner(Parcel* parcel) const {
     /*
      * To keep this implementation in sync with writeArrayMapInternal() in
@@ -363,7 +407,6 @@
     RETURN_IF_FAILED(parcel->readInt32(&num_entries));
 
     for (; num_entries > 0; --num_entries) {
-        size_t start_pos = parcel->dataPosition();
         String16 key;
         int32_t value_type;
         RETURN_IF_FAILED(parcel->readString16(&key));
diff --git a/libs/binder/ProcessInfoService.cpp b/libs/binder/ProcessInfoService.cpp
index fb28643..8939d9c 100644
--- a/libs/binder/ProcessInfoService.cpp
+++ b/libs/binder/ProcessInfoService.cpp
@@ -57,6 +57,40 @@
     return TIMED_OUT;
 }
 
+status_t ProcessInfoService::getProcessStatesScoresImpl(size_t length,
+        /*in*/ int32_t* pids, /*out*/ int32_t* states,
+        /*out*/ int32_t *scores) {
+    status_t err = NO_ERROR;
+    sp<IProcessInfoService> pis;
+    mProcessInfoLock.lock();
+    pis = mProcessInfoService;
+    mProcessInfoLock.unlock();
+
+    for (int i = 0; i < BINDER_ATTEMPT_LIMIT; i++) {
+
+        if (pis != NULL) {
+            err = pis->getProcessStatesAndOomScoresFromPids(length,
+                    /*in*/ pids, /*out*/ states, /*out*/ scores);
+            if (err == NO_ERROR) return NO_ERROR; // success
+            if (IInterface::asBinder(pis)->isBinderAlive()) return err;
+        }
+        sleep(1);
+
+        mProcessInfoLock.lock();
+        if (pis == mProcessInfoService) {
+            updateBinderLocked();
+        }
+        pis = mProcessInfoService;
+        mProcessInfoLock.unlock();
+    }
+
+    ALOGW("%s: Could not retrieve process states and scores "
+            "from ProcessInfoService after %d retries.", __FUNCTION__,
+            BINDER_ATTEMPT_LIMIT);
+
+    return TIMED_OUT;
+}
+
 void ProcessInfoService::updateBinderLocked() {
     const sp<IServiceManager> sm(defaultServiceManager());
     if (sm != NULL) {
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index f13f49f..add5e74 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -16,8 +16,6 @@
 
 #define LOG_TAG "ProcessState"
 
-#include <cutils/process_name.h>
-
 #include <binder/ProcessState.h>
 
 #include <utils/Atomic.h>
@@ -42,7 +40,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
-#define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2))
+#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
 #define DEFAULT_MAX_BINDER_THREADS 15
 
 // -------------------------------------------------------------------------
@@ -52,7 +50,7 @@
 class PoolThread : public Thread
 {
 public:
-    PoolThread(bool isMain)
+    explicit PoolThread(bool isMain)
         : mIsMain(isMain)
     {
     }
@@ -73,7 +71,22 @@
     if (gProcess != NULL) {
         return gProcess;
     }
-    gProcess = new ProcessState;
+    gProcess = new ProcessState("/dev/binder");
+    return gProcess;
+}
+
+sp<ProcessState> ProcessState::initWithDriver(const char* driver)
+{
+    Mutex::Autolock _l(gProcessMutex);
+    if (gProcess != NULL) {
+        // Allow for initWithDriver to be called repeatedly with the same
+        // driver.
+        if (!strcmp(gProcess->getDriverName().c_str(), driver)) {
+            return gProcess;
+        }
+        LOG_ALWAYS_FATAL("ProcessState was already initialized.");
+    }
+    gProcess = new ProcessState(driver);
     return gProcess;
 }
 
@@ -309,9 +322,13 @@
     androidSetThreadName( makeBinderThreadName().string() );
 }
 
-static int open_driver()
+String8 ProcessState::getDriverName() {
+    return mDriverName;
+}
+
+static int open_driver(const char *driver)
 {
-    int fd = open("/dev/binder", O_RDWR | O_CLOEXEC);
+    int fd = open(driver, O_RDWR | O_CLOEXEC);
     if (fd >= 0) {
         int vers = 0;
         status_t result = ioctl(fd, BINDER_VERSION, &vers);
@@ -321,7 +338,8 @@
             fd = -1;
         }
         if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
-            ALOGE("Binder driver protocol does not match user space protocol!");
+          ALOGE("Binder driver protocol(%d) does not match user space protocol(%d)! ioctl() return value: %d",
+                vers, BINDER_CURRENT_PROTOCOL_VERSION, result);
             close(fd);
             fd = -1;
         }
@@ -331,13 +349,14 @@
             ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
         }
     } else {
-        ALOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
+        ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));
     }
     return fd;
 }
 
-ProcessState::ProcessState()
-    : mDriverFD(open_driver())
+ProcessState::ProcessState(const char *driver)
+    : mDriverName(String8(driver))
+    , mDriverFD(open_driver(driver))
     , mVMStart(MAP_FAILED)
     , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
     , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
@@ -358,6 +377,7 @@
             ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
             close(mDriverFD);
             mDriverFD = -1;
+            mDriverName.clear();
         }
     }
 
@@ -366,6 +386,13 @@
 
 ProcessState::~ProcessState()
 {
+    if (mDriverFD >= 0) {
+        if (mVMStart != MAP_FAILED) {
+            munmap(mVMStart, BINDER_VM_SIZE);
+        }
+        close(mDriverFD);
+    }
+    mDriverFD = -1;
 }
         
 }; // namespace android
diff --git a/libs/binder/Static.cpp b/libs/binder/Static.cpp
index cd9509f..f0613d1 100644
--- a/libs/binder/Static.cpp
+++ b/libs/binder/Static.cpp
@@ -48,7 +48,7 @@
 class FdTextOutput : public BufferedTextOutput
 {
 public:
-    FdTextOutput(int fd) : BufferedTextOutput(MULTITHREADED), mFD(fd) { }
+    explicit FdTextOutput(int fd) : BufferedTextOutput(MULTITHREADED), mFD(fd) { }
     virtual ~FdTextOutput() { };
 
 protected:
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index d3520d6..006f7f9 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -32,6 +32,11 @@
     return Status(exceptionCode, OK, message);
 }
 
+Status Status::fromExceptionCode(int32_t exceptionCode,
+                                 const char* message) {
+    return fromExceptionCode(exceptionCode, String8(message));
+}
+
 Status Status::fromServiceSpecificError(int32_t serviceSpecificErrorCode) {
     return Status(EX_SERVICE_SPECIFIC, serviceSpecificErrorCode);
 }
@@ -41,6 +46,11 @@
     return Status(EX_SERVICE_SPECIFIC, serviceSpecificErrorCode, message);
 }
 
+Status Status::fromServiceSpecificError(int32_t serviceSpecificErrorCode,
+                                        const char* message) {
+    return fromServiceSpecificError(serviceSpecificErrorCode, String8(message));
+}
+
 Status Status::fromStatusT(status_t status) {
     Status ret;
     ret.setFromStatusT(status);
@@ -94,6 +104,16 @@
 
     if (mException == EX_SERVICE_SPECIFIC) {
         status = parcel.readInt32(&mErrorCode);
+    } else if (mException == EX_PARCELABLE) {
+        // Skip over the blob of Parcelable data
+        const int32_t header_start = parcel.dataPosition();
+        int32_t header_size;
+        status = parcel.readInt32(&header_size);
+        if (status != OK) {
+            setFromStatusT(status);
+            return status;
+        }
+        parcel.setDataPosition(header_start + header_size);
     }
     if (status != OK) {
         setFromStatusT(status);
@@ -117,11 +137,12 @@
         return status;
     }
     status = parcel->writeString16(String16(mMessage));
-    if (mException != EX_SERVICE_SPECIFIC) {
-        // We have no more information to write.
-        return status;
+    if (mException == EX_SERVICE_SPECIFIC) {
+        status = parcel->writeInt32(mErrorCode);
+    } else if (mException == EX_PARCELABLE) {
+        // Sending Parcelable blobs currently not supported
+        status = parcel->writeInt32(0);
     }
-    status = parcel->writeInt32(mErrorCode);
     return status;
 }
 
@@ -158,5 +179,10 @@
     return ret;
 }
 
+std::stringstream& operator<< (std::stringstream& stream, const Status& s) {
+    stream << s.toString8().string();
+    return stream;
+}
+
 }  // namespace binder
 }  // namespace android
diff --git a/libs/binder/TextOutput.cpp b/libs/binder/TextOutput.cpp
index 2ed5188..101eba3 100644
--- a/libs/binder/TextOutput.cpp
+++ b/libs/binder/TextOutput.cpp
@@ -29,111 +29,14 @@
 
 // ---------------------------------------------------------------------------
 
-TextOutput::TextOutput() { 
+TextOutput::TextOutput() {
 }
 
-TextOutput::~TextOutput() { 
+TextOutput::~TextOutput() {
 }
 
 // ---------------------------------------------------------------------------
 
-TextOutput& operator<<(TextOutput& to, bool val)
-{
-    if (val) to.print("true", 4);
-    else to.print("false", 5);
-    return to;
-}
-
-TextOutput& operator<<(TextOutput& to, int val)
-{
-    char buf[16];
-    sprintf(buf, "%d", val);
-    to.print(buf, strlen(buf));
-    return to;
-}
-
-TextOutput& operator<<(TextOutput& to, long val)
-{
-    char buf[16];
-    sprintf(buf, "%ld", val);
-    to.print(buf, strlen(buf));
-    return to;
-}
-
-TextOutput& operator<<(TextOutput& to, unsigned int val)
-{
-    char buf[16];
-    sprintf(buf, "%u", val);
-    to.print(buf, strlen(buf));
-    return to;
-}
-
-TextOutput& operator<<(TextOutput& to, unsigned long val)
-{
-    char buf[16];
-    sprintf(buf, "%lu", val);
-    to.print(buf, strlen(buf));
-    return to;
-}
-
-TextOutput& operator<<(TextOutput& to, long long val)
-{
-    char buf[32];
-    sprintf(buf, "%Ld", val);
-    to.print(buf, strlen(buf));
-    return to;
-}
-
-TextOutput& operator<<(TextOutput& to, unsigned long long val)
-{
-    char buf[32];
-    sprintf(buf, "%Lu", val);
-    to.print(buf, strlen(buf));
-    return to;
-}
-
-static TextOutput& print_float(TextOutput& to, double value)
-{
-    char buf[64];
-    sprintf(buf, "%g", value);
-    if( !strchr(buf, '.') && !strchr(buf, 'e') &&
-        !strchr(buf, 'E') ) {
-        strncat(buf, ".0", sizeof(buf)-1);
-    }
-    to.print(buf, strlen(buf));
-    return to;
-}
-
-TextOutput& operator<<(TextOutput& to, float val)
-{
-    return print_float(to,val);
-}
-
-TextOutput& operator<<(TextOutput& to, double val)
-{
-    return print_float(to,val);
-}
-
-TextOutput& operator<<(TextOutput& to, const void* val)
-{
-    char buf[32];
-    snprintf(buf, sizeof(buf), "%p", val);
-    to.print(buf, strlen(buf));
-    return to;
-}
-
-TextOutput& operator<<(TextOutput& to, const String8& val)
-{
-    to << val.string();
-    return to;
-}
-
-TextOutput& operator<<(TextOutput& to, const String16& val)
-{
-    to << String8(val).string();
-    return to;
-}
-
 static void textOutputPrinter(void* cookie, const char* txt)
 {
     ((TextOutput*)cookie)->print(txt, strlen(txt));
diff --git a/libs/binder/Value.cpp b/libs/binder/Value.cpp
new file mode 100644
index 0000000..fd1dfd5
--- /dev/null
+++ b/libs/binder/Value.cpp
@@ -0,0 +1,418 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "Value"
+
+#include <binder/Value.h>
+
+#include <limits>
+
+#include <binder/IBinder.h>
+#include <binder/Parcel.h>
+#include <binder/Map.h>
+#include <private/binder/ParcelValTypes.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+
+using android::BAD_TYPE;
+using android::BAD_VALUE;
+using android::NO_ERROR;
+using android::UNEXPECTED_NULL;
+using android::Parcel;
+using android::sp;
+using android::status_t;
+using std::map;
+using std::set;
+using std::vector;
+using android::binder::Value;
+using android::IBinder;
+using android::os::PersistableBundle;
+using namespace android::binder;
+
+// ====================================================================
+
+#define RETURN_IF_FAILED(calledOnce)                                     \
+    do {                                                                 \
+        status_t returnStatus = calledOnce;                              \
+        if (returnStatus) {                                              \
+            ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \
+            return returnStatus;                                         \
+         }                                                               \
+    } while(false)
+
+// ====================================================================
+
+/* These `internal_type_ptr()` functions allow this
+ * class to work without C++ RTTI support. This technique
+ * only works properly when called directly from this file,
+ * but that is OK because that is the only place we will
+ * be calling them from. */
+template<class T> const void* internal_type_ptr()
+{
+    static const T *marker;
+    return (void*)&marker;
+}
+
+/* Allows the type to be specified by the argument
+ * instead of inside angle brackets. */
+template<class T> const void* internal_type_ptr(const T&)
+{
+    return internal_type_ptr<T>();
+}
+
+// ====================================================================
+
+namespace android {
+
+namespace binder {
+
+class Value::ContentBase {
+public:
+    virtual ~ContentBase() = default;
+    virtual const void* type_ptr() const = 0;
+    virtual ContentBase * clone() const = 0;
+    virtual bool operator==(const ContentBase& rhs) const = 0;
+
+#ifdef LIBBINDER_VALUE_SUPPORTS_TYPE_INFO
+    virtual const std::type_info &type() const = 0;
+#endif
+
+    template<typename T> bool get(T* out) const;
+};
+
+/* This is the actual class that holds the value. */
+template<typename T> class Value::Content : public Value::ContentBase {
+public:
+    Content() = default;
+    Content(const T & value) : mValue(value) { }
+
+    virtual ~Content() = default;
+
+#ifdef LIBBINDER_VALUE_SUPPORTS_TYPE_INFO
+    virtual const std::type_info &type() const override
+    {
+        return typeid(T);
+    }
+#endif
+
+    virtual const void* type_ptr() const override
+    {
+        return internal_type_ptr<T>();
+    }
+
+    virtual ContentBase * clone() const override
+    {
+        return new Content(mValue);
+    };
+
+    virtual bool operator==(const ContentBase& rhs) const override
+    {
+        if (type_ptr() != rhs.type_ptr()) {
+            return false;
+        }
+        return mValue == static_cast<const Content<T>* >(&rhs)->mValue;
+    }
+
+    T mValue;
+};
+
+template<typename T> bool Value::ContentBase::get(T* out) const
+{
+    if (internal_type_ptr(*out) != type_ptr())
+    {
+        return false;
+    }
+
+    *out = static_cast<const Content<T>*>(this)->mValue;
+
+    return true;
+}
+
+// ====================================================================
+
+Value::Value() : mContent(NULL)
+{
+}
+
+Value::Value(const Value& value)
+    : mContent(value.mContent ? value.mContent->clone() : NULL)
+{
+}
+
+Value::~Value()
+{
+    delete mContent;
+}
+
+bool Value::operator==(const Value& rhs) const
+{
+    const Value& lhs(*this);
+
+    if (lhs.empty() && rhs.empty()) {
+        return true;
+    }
+
+    if ( (lhs.mContent == NULL)
+      || (rhs.mContent == NULL)
+    ) {
+        return false;
+    }
+
+    return *lhs.mContent == *rhs.mContent;
+}
+
+Value& Value::swap(Value &rhs)
+{
+    std::swap(mContent, rhs.mContent);
+    return *this;
+}
+
+Value& Value::operator=(const Value& rhs)
+{
+    delete mContent;
+    mContent = rhs.mContent
+        ? rhs.mContent->clone()
+        : NULL;
+    return *this;
+}
+
+bool Value::empty() const
+{
+    return mContent == NULL;
+}
+
+void Value::clear()
+{
+    delete mContent;
+    mContent = NULL;
+}
+
+int32_t Value::parcelType() const
+{
+    const void* t_info(mContent ? mContent->type_ptr() : NULL);
+
+    if (t_info == internal_type_ptr<bool>()) return VAL_BOOLEAN;
+    if (t_info == internal_type_ptr<uint8_t>()) return VAL_BYTE;
+    if (t_info == internal_type_ptr<int32_t>()) return VAL_INTEGER;
+    if (t_info == internal_type_ptr<int64_t>()) return VAL_LONG;
+    if (t_info == internal_type_ptr<double>()) return VAL_DOUBLE;
+    if (t_info == internal_type_ptr<String16>()) return VAL_STRING;
+
+    if (t_info == internal_type_ptr<vector<bool>>()) return VAL_BOOLEANARRAY;
+    if (t_info == internal_type_ptr<vector<uint8_t>>()) return VAL_BYTEARRAY;
+    if (t_info == internal_type_ptr<vector<int32_t>>()) return VAL_INTARRAY;
+    if (t_info == internal_type_ptr<vector<int64_t>>()) return VAL_LONGARRAY;
+    if (t_info == internal_type_ptr<vector<double>>()) return VAL_DOUBLEARRAY;
+    if (t_info == internal_type_ptr<vector<String16>>()) return VAL_STRINGARRAY;
+
+    if (t_info == internal_type_ptr<Map>()) return VAL_MAP;
+    if (t_info == internal_type_ptr<PersistableBundle>()) return VAL_PERSISTABLEBUNDLE;
+
+    return VAL_NULL;
+}
+
+#ifdef LIBBINDER_VALUE_SUPPORTS_TYPE_INFO
+const std::type_info& Value::type() const
+{
+    return mContent != NULL
+        ? mContent->type()
+        : typeid(void);
+}
+#endif // ifdef LIBBINDER_VALUE_SUPPORTS_TYPE_INFO
+
+#define DEF_TYPE_ACCESSORS(T, TYPENAME)                      \
+    bool Value::is ## TYPENAME() const                       \
+    {                                                        \
+        return mContent                                      \
+            ? internal_type_ptr<T>() == mContent->type_ptr() \
+            : false;                                         \
+    }                                                        \
+    bool Value::get ## TYPENAME(T* out) const                \
+    {                                                        \
+        return mContent                                      \
+            ? mContent->get(out)                             \
+            : false;                                         \
+    }                                                        \
+    void Value::put ## TYPENAME(const T& in)                 \
+    {                                                        \
+        *this = in;                                          \
+    }                                                        \
+    Value& Value::operator=(const T& rhs)                    \
+    {                                                        \
+        delete mContent;                                     \
+        mContent = new Content< T >(rhs);                    \
+        return *this;                                        \
+    }                                                        \
+    Value::Value(const T& value)                             \
+        : mContent(new Content< T >(value))                  \
+    { }
+
+DEF_TYPE_ACCESSORS(bool, Boolean)
+DEF_TYPE_ACCESSORS(int8_t, Byte)
+DEF_TYPE_ACCESSORS(int32_t, Int)
+DEF_TYPE_ACCESSORS(int64_t, Long)
+DEF_TYPE_ACCESSORS(double, Double)
+DEF_TYPE_ACCESSORS(String16, String)
+
+DEF_TYPE_ACCESSORS(std::vector<bool>, BooleanVector)
+DEF_TYPE_ACCESSORS(std::vector<uint8_t>, ByteVector)
+DEF_TYPE_ACCESSORS(std::vector<int32_t>, IntVector)
+DEF_TYPE_ACCESSORS(std::vector<int64_t>, LongVector)
+DEF_TYPE_ACCESSORS(std::vector<double>, DoubleVector)
+DEF_TYPE_ACCESSORS(std::vector<String16>, StringVector)
+
+DEF_TYPE_ACCESSORS(::android::binder::Map, Map)
+DEF_TYPE_ACCESSORS(PersistableBundle, PersistableBundle)
+
+bool Value::getString(String8* out) const
+{
+    String16 val;
+    bool ret = getString(&val);
+    if (ret) {
+        *out = String8(val);
+    }
+    return ret;
+}
+
+bool Value::getString(::std::string* out) const
+{
+    String8 val;
+    bool ret = getString(&val);
+    if (ret) {
+        *out = val.string();
+    }
+    return ret;
+}
+
+status_t Value::writeToParcel(Parcel* parcel) const
+{
+    // This implementation needs to be kept in sync with the writeValue
+    // implementation in frameworks/base/core/java/android/os/Parcel.java
+
+#define BEGIN_HANDLE_WRITE()                                                                      \
+    do {                                                                                          \
+        const void* t_info(mContent?mContent->type_ptr():NULL);                                   \
+        if (false) { }
+#define HANDLE_WRITE_TYPE(T, TYPEVAL, TYPEMETHOD)                                                 \
+    else if (t_info == internal_type_ptr<T>()) {                                                  \
+        RETURN_IF_FAILED(parcel->writeInt32(TYPEVAL));                                            \
+        RETURN_IF_FAILED(parcel->TYPEMETHOD(static_cast<const Content<T>*>(mContent)->mValue));   \
+    }
+#define HANDLE_WRITE_PARCELABLE(T, TYPEVAL)                                                       \
+    else if (t_info == internal_type_ptr<T>()) {                                                  \
+        RETURN_IF_FAILED(parcel->writeInt32(TYPEVAL));                                            \
+        RETURN_IF_FAILED(static_cast<const Content<T>*>(mContent)->mValue.writeToParcel(parcel)); \
+    }
+#define END_HANDLE_WRITE()                                                                        \
+        else {                                                                                    \
+            ALOGE("writeToParcel: Type not supported");                                           \
+            return BAD_TYPE;                                                                      \
+        }                                                                                         \
+    } while (false);
+
+    BEGIN_HANDLE_WRITE()
+
+    HANDLE_WRITE_TYPE(bool,     VAL_BOOLEAN, writeBool)
+    HANDLE_WRITE_TYPE(int8_t,   VAL_BYTE,    writeByte)
+    HANDLE_WRITE_TYPE(int8_t,   VAL_BYTE,    writeByte)
+    HANDLE_WRITE_TYPE(int32_t,  VAL_INTEGER, writeInt32)
+    HANDLE_WRITE_TYPE(int64_t,  VAL_LONG,    writeInt64)
+    HANDLE_WRITE_TYPE(double,   VAL_DOUBLE,  writeDouble)
+    HANDLE_WRITE_TYPE(String16, VAL_STRING,  writeString16)
+
+    HANDLE_WRITE_TYPE(vector<bool>,     VAL_BOOLEANARRAY, writeBoolVector)
+    HANDLE_WRITE_TYPE(vector<uint8_t>,  VAL_BYTEARRAY,    writeByteVector)
+    HANDLE_WRITE_TYPE(vector<int8_t>,   VAL_BYTEARRAY,    writeByteVector)
+    HANDLE_WRITE_TYPE(vector<int32_t>,  VAL_INTARRAY,     writeInt32Vector)
+    HANDLE_WRITE_TYPE(vector<int64_t>,  VAL_LONGARRAY,    writeInt64Vector)
+    HANDLE_WRITE_TYPE(vector<double>,   VAL_DOUBLEARRAY,  writeDoubleVector)
+    HANDLE_WRITE_TYPE(vector<String16>, VAL_STRINGARRAY,  writeString16Vector)
+
+    HANDLE_WRITE_PARCELABLE(PersistableBundle, VAL_PERSISTABLEBUNDLE)
+
+    END_HANDLE_WRITE()
+
+    return NO_ERROR;
+
+#undef BEGIN_HANDLE_WRITE
+#undef HANDLE_WRITE_TYPE
+#undef HANDLE_WRITE_PARCELABLE
+#undef END_HANDLE_WRITE
+}
+
+status_t Value::readFromParcel(const Parcel* parcel)
+{
+    // This implementation needs to be kept in sync with the readValue
+    // implementation in frameworks/base/core/java/android/os/Parcel.javai
+
+#define BEGIN_HANDLE_READ()                                                                      \
+    switch(value_type) {                                                                         \
+        default:                                                                                 \
+            ALOGE("readFromParcel: Parcel type %d is not supported", value_type);                \
+            return BAD_TYPE;
+#define HANDLE_READ_TYPE(T, TYPEVAL, TYPEMETHOD)                                                 \
+        case TYPEVAL:                                                                            \
+            mContent = new Content<T>();                                                         \
+            RETURN_IF_FAILED(parcel->TYPEMETHOD(&static_cast<Content<T>*>(mContent)->mValue));   \
+            break;
+#define HANDLE_READ_PARCELABLE(T, TYPEVAL)                                                       \
+        case TYPEVAL:                                                                            \
+            mContent = new Content<T>();                                                         \
+            RETURN_IF_FAILED(static_cast<Content<T>*>(mContent)->mValue.readFromParcel(parcel)); \
+            break;
+#define END_HANDLE_READ()                                                                        \
+    }
+
+    int32_t value_type = VAL_NULL;
+
+    delete mContent;
+    mContent = NULL;
+
+    RETURN_IF_FAILED(parcel->readInt32(&value_type));
+
+    BEGIN_HANDLE_READ()
+
+    HANDLE_READ_TYPE(bool,     VAL_BOOLEAN, readBool)
+    HANDLE_READ_TYPE(int8_t,   VAL_BYTE,    readByte)
+    HANDLE_READ_TYPE(int32_t,  VAL_INTEGER, readInt32)
+    HANDLE_READ_TYPE(int64_t,  VAL_LONG,    readInt64)
+    HANDLE_READ_TYPE(double,   VAL_DOUBLE,  readDouble)
+    HANDLE_READ_TYPE(String16, VAL_STRING,  readString16)
+
+    HANDLE_READ_TYPE(vector<bool>,     VAL_BOOLEANARRAY, readBoolVector)
+    HANDLE_READ_TYPE(vector<uint8_t>,  VAL_BYTEARRAY,    readByteVector)
+    HANDLE_READ_TYPE(vector<int32_t>,  VAL_INTARRAY,     readInt32Vector)
+    HANDLE_READ_TYPE(vector<int64_t>,  VAL_LONGARRAY,    readInt64Vector)
+    HANDLE_READ_TYPE(vector<double>,   VAL_DOUBLEARRAY,  readDoubleVector)
+    HANDLE_READ_TYPE(vector<String16>, VAL_STRINGARRAY,  readString16Vector)
+
+    HANDLE_READ_PARCELABLE(PersistableBundle, VAL_PERSISTABLEBUNDLE)
+
+    END_HANDLE_READ()
+
+    return NO_ERROR;
+
+#undef BEGIN_HANDLE_READ
+#undef HANDLE_READ_TYPE
+#undef HANDLE_READ_PARCELABLE
+#undef END_HANDLE_READ
+}
+
+}  // namespace binder
+
+}  // namespace android
+
+/* vim: set ts=4 sw=4 tw=0 et :*/
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
new file mode 100644
index 0000000..4212776
--- /dev/null
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 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 ANDROID_APP_OPS_MANAGER_H
+#define ANDROID_APP_OPS_MANAGER_H
+
+#include <binder/IAppOpsService.h>
+
+#include <utils/threads.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class AppOpsManager
+{
+public:
+    enum {
+        MODE_ALLOWED = IAppOpsService::MODE_ALLOWED,
+        MODE_IGNORED = IAppOpsService::MODE_IGNORED,
+        MODE_ERRORED = IAppOpsService::MODE_ERRORED
+    };
+
+    enum {
+        OP_NONE = -1,
+        OP_COARSE_LOCATION = 0,
+        OP_FINE_LOCATION = 1,
+        OP_GPS = 2,
+        OP_VIBRATE = 3,
+        OP_READ_CONTACTS = 4,
+        OP_WRITE_CONTACTS = 5,
+        OP_READ_CALL_LOG = 6,
+        OP_WRITE_CALL_LOG = 7,
+        OP_READ_CALENDAR = 8,
+        OP_WRITE_CALENDAR = 9,
+        OP_WIFI_SCAN = 10,
+        OP_POST_NOTIFICATION = 11,
+        OP_NEIGHBORING_CELLS = 12,
+        OP_CALL_PHONE = 13,
+        OP_READ_SMS = 14,
+        OP_WRITE_SMS = 15,
+        OP_RECEIVE_SMS = 16,
+        OP_RECEIVE_EMERGECY_SMS = 17,
+        OP_RECEIVE_MMS = 18,
+        OP_RECEIVE_WAP_PUSH = 19,
+        OP_SEND_SMS = 20,
+        OP_READ_ICC_SMS = 21,
+        OP_WRITE_ICC_SMS = 22,
+        OP_WRITE_SETTINGS = 23,
+        OP_SYSTEM_ALERT_WINDOW = 24,
+        OP_ACCESS_NOTIFICATIONS = 25,
+        OP_CAMERA = 26,
+        OP_RECORD_AUDIO = 27,
+        OP_PLAY_AUDIO = 28,
+        OP_READ_CLIPBOARD = 29,
+        OP_WRITE_CLIPBOARD = 30,
+        OP_TAKE_MEDIA_BUTTONS = 31,
+        OP_TAKE_AUDIO_FOCUS = 32,
+        OP_AUDIO_MASTER_VOLUME = 33,
+        OP_AUDIO_VOICE_VOLUME = 34,
+        OP_AUDIO_RING_VOLUME = 35,
+        OP_AUDIO_MEDIA_VOLUME = 36,
+        OP_AUDIO_ALARM_VOLUME = 37,
+        OP_AUDIO_NOTIFICATION_VOLUME = 38,
+        OP_AUDIO_BLUETOOTH_VOLUME = 39,
+        OP_WAKE_LOCK = 40,
+        OP_MONITOR_LOCATION = 41,
+        OP_MONITOR_HIGH_POWER_LOCATION = 42,
+        OP_GET_USAGE_STATS = 43,
+        OP_MUTE_MICROPHONE = 44,
+        OP_TOAST_WINDOW = 45,
+        OP_PROJECT_MEDIA = 46,
+        OP_ACTIVATE_VPN = 47,
+        OP_WRITE_WALLPAPER = 48,
+        OP_ASSIST_STRUCTURE = 49,
+        OP_ASSIST_SCREENSHOT = 50,
+        OP_READ_PHONE_STATE = 51,
+        OP_ADD_VOICEMAIL = 52,
+        OP_USE_SIP = 53,
+        OP_PROCESS_OUTGOING_CALLS = 54,
+        OP_USE_FINGERPRINT = 55,
+        OP_BODY_SENSORS = 56,
+        OP_AUDIO_ACCESSIBILITY_VOLUME = 64,
+    };
+
+    AppOpsManager();
+
+    int32_t checkOp(int32_t op, int32_t uid, const String16& callingPackage);
+    int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage);
+    int32_t startOp(int32_t op, int32_t uid, const String16& callingPackage);
+    void finishOp(int32_t op, int32_t uid, const String16& callingPackage);
+    void startWatchingMode(int32_t op, const String16& packageName,
+            const sp<IAppOpsCallback>& callback);
+    void stopWatchingMode(const sp<IAppOpsCallback>& callback);
+    int32_t permissionToOpCode(const String16& permission);
+
+private:
+    Mutex mLock;
+    sp<IAppOpsService> mService;
+
+    sp<IAppOpsService> getService();
+};
+
+
+}; // namespace android
+// ---------------------------------------------------------------------------
+#endif // ANDROID_APP_OPS_MANAGER_H
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
new file mode 100644
index 0000000..3404881
--- /dev/null
+++ b/libs/binder/include/binder/Binder.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2008 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_BINDER_H
+#define ANDROID_BINDER_H
+
+#include <atomic>
+#include <stdint.h>
+#include <binder/IBinder.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class BBinder : public IBinder
+{
+public:
+                        BBinder();
+
+    virtual const String16& getInterfaceDescriptor() const;
+    virtual bool        isBinderAlive() const;
+    virtual status_t    pingBinder();
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+
+    virtual status_t    transact(   uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+
+    virtual status_t    linkToDeath(const sp<DeathRecipient>& recipient,
+                                    void* cookie = NULL,
+                                    uint32_t flags = 0);
+
+    virtual status_t    unlinkToDeath(  const wp<DeathRecipient>& recipient,
+                                        void* cookie = NULL,
+                                        uint32_t flags = 0,
+                                        wp<DeathRecipient>* outRecipient = NULL);
+
+    virtual void        attachObject(   const void* objectID,
+                                        void* object,
+                                        void* cleanupCookie,
+                                        object_cleanup_func func);
+    virtual void*       findObject(const void* objectID) const;
+    virtual void        detachObject(const void* objectID);
+
+    virtual BBinder*    localBinder();
+
+protected:
+    virtual             ~BBinder();
+
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+
+private:
+                        BBinder(const BBinder& o);
+            BBinder&    operator=(const BBinder& o);
+
+    class Extras;
+
+    std::atomic<Extras*> mExtras;
+            void*       mReserved0;
+};
+
+// ---------------------------------------------------------------------------
+
+class BpRefBase : public virtual RefBase
+{
+protected:
+    explicit                BpRefBase(const sp<IBinder>& o);
+    virtual                 ~BpRefBase();
+    virtual void            onFirstRef();
+    virtual void            onLastStrongRef(const void* id);
+    virtual bool            onIncStrongAttempted(uint32_t flags, const void* id);
+
+    inline  IBinder*        remote()                { return mRemote; }
+    inline  IBinder*        remote() const          { return mRemote; }
+
+private:
+                            BpRefBase(const BpRefBase& o);
+    BpRefBase&              operator=(const BpRefBase& o);
+
+    IBinder* const          mRemote;
+    RefBase::weakref_type*  mRefs;
+    std::atomic<int32_t>    mState;
+};
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_BINDER_H
diff --git a/include/binder/BinderService.h b/libs/binder/include/binder/BinderService.h
similarity index 100%
rename from include/binder/BinderService.h
rename to libs/binder/include/binder/BinderService.h
diff --git a/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
similarity index 100%
rename from include/binder/BpBinder.h
rename to libs/binder/include/binder/BpBinder.h
diff --git a/include/binder/BufferedTextOutput.h b/libs/binder/include/binder/BufferedTextOutput.h
similarity index 100%
rename from include/binder/BufferedTextOutput.h
rename to libs/binder/include/binder/BufferedTextOutput.h
diff --git a/include/binder/Debug.h b/libs/binder/include/binder/Debug.h
similarity index 100%
rename from include/binder/Debug.h
rename to libs/binder/include/binder/Debug.h
diff --git a/libs/binder/include/binder/IActivityManager.h b/libs/binder/include/binder/IActivityManager.h
new file mode 100644
index 0000000..5ad2180
--- /dev/null
+++ b/libs/binder/include/binder/IActivityManager.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_IACTIVITY_MANAGER_H
+#define ANDROID_IACTIVITY_MANAGER_H
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ------------------------------------------------------------------------------------
+
+class IActivityManager : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(ActivityManager)
+
+    virtual int openContentUri(const String16& /* stringUri */) = 0;
+
+    enum {
+        OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION
+    };
+};
+
+// ------------------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IACTIVITY_MANAGER_H
\ No newline at end of file
diff --git a/libs/binder/include/binder/IAppOpsCallback.h b/libs/binder/include/binder/IAppOpsCallback.h
new file mode 100644
index 0000000..b62e9e2
--- /dev/null
+++ b/libs/binder/include/binder/IAppOpsCallback.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 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 ANDROID_IAPP_OPS_CALLBACK_H
+#define ANDROID_IAPP_OPS_CALLBACK_H
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IAppOpsCallback : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(AppOpsCallback)
+
+    virtual void opChanged(int32_t op, const String16& packageName) = 0;
+
+    enum {
+        OP_CHANGED_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION
+    };
+};
+
+// ----------------------------------------------------------------------
+
+class BnAppOpsCallback : public BnInterface<IAppOpsCallback>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IAPP_OPS_CALLBACK_H
+
diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h
new file mode 100644
index 0000000..dc18045
--- /dev/null
+++ b/libs/binder/include/binder/IAppOpsService.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 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 ANDROID_IAPP_OPS_SERVICE_H
+#define ANDROID_IAPP_OPS_SERVICE_H
+
+#include <binder/IAppOpsCallback.h>
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IAppOpsService : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(AppOpsService)
+
+    virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
+    virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
+    virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
+            const String16& packageName) = 0;
+    virtual void finishOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
+            const String16& packageName) = 0;
+    virtual void startWatchingMode(int32_t op, const String16& packageName,
+            const sp<IAppOpsCallback>& callback) = 0;
+    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;
+
+    enum {
+        CHECK_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+        NOTE_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+1,
+        START_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+2,
+        FINISH_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+3,
+        START_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+4,
+        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,
+    };
+
+    enum {
+        MODE_ALLOWED = 0,
+        MODE_IGNORED = 1,
+        MODE_ERRORED = 2
+    };
+};
+
+// ----------------------------------------------------------------------
+
+class BnAppOpsService : public BnInterface<IAppOpsService>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IAPP_OPS_SERVICE_H
diff --git a/libs/binder/include/binder/IBatteryStats.h b/libs/binder/include/binder/IBatteryStats.h
new file mode 100644
index 0000000..e15d6f0
--- /dev/null
+++ b/libs/binder/include/binder/IBatteryStats.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 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 ANDROID_IBATTERYSTATS_H
+#define ANDROID_IBATTERYSTATS_H
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IBatteryStats : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(BatteryStats)
+
+    virtual void noteStartSensor(int uid, int sensor) = 0;
+    virtual void noteStopSensor(int uid, int sensor) = 0;
+    virtual void noteStartVideo(int uid) = 0;
+    virtual void noteStopVideo(int uid) = 0;
+    virtual void noteStartAudio(int uid) = 0;
+    virtual void noteStopAudio(int uid) = 0;
+    virtual void noteResetVideo() = 0;
+    virtual void noteResetAudio() = 0;
+    virtual void noteFlashlightOn(int uid) = 0;
+    virtual void noteFlashlightOff(int uid) = 0;
+    virtual void noteStartCamera(int uid) = 0;
+    virtual void noteStopCamera(int uid) = 0;
+    virtual void noteResetCamera() = 0;
+    virtual void noteResetFlashlight() = 0;
+
+    enum {
+        NOTE_START_SENSOR_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+        NOTE_STOP_SENSOR_TRANSACTION,
+        NOTE_START_VIDEO_TRANSACTION,
+        NOTE_STOP_VIDEO_TRANSACTION,
+        NOTE_START_AUDIO_TRANSACTION,
+        NOTE_STOP_AUDIO_TRANSACTION,
+        NOTE_RESET_VIDEO_TRANSACTION,
+        NOTE_RESET_AUDIO_TRANSACTION,
+        NOTE_FLASHLIGHT_ON_TRANSACTION,
+        NOTE_FLASHLIGHT_OFF_TRANSACTION,
+        NOTE_START_CAMERA_TRANSACTION,
+        NOTE_STOP_CAMERA_TRANSACTION,
+        NOTE_RESET_CAMERA_TRANSACTION,
+        NOTE_RESET_FLASHLIGHT_TRANSACTION
+    };
+};
+
+// ----------------------------------------------------------------------
+
+class BnBatteryStats : public BnInterface<IBatteryStats>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IBATTERYSTATS_H
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
new file mode 100644
index 0000000..2e62957
--- /dev/null
+++ b/libs/binder/include/binder/IBinder.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2008 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_IBINDER_H
+#define ANDROID_IBINDER_H
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+
+// linux/binder.h already defines this, but we can't just include it from there
+// because there are host builds that include this file.
+#ifndef B_PACK_CHARS
+#define B_PACK_CHARS(c1, c2, c3, c4) \
+    ((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))
+#endif  // B_PACK_CHARS
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class BBinder;
+class BpBinder;
+class IInterface;
+class Parcel;
+class IResultReceiver;
+class IShellCallback;
+
+/**
+ * Base class and low-level protocol for a remotable object.
+ * You can derive from this class to create an object for which other
+ * processes can hold references to it.  Communication between processes
+ * (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
+{
+public:
+    enum {
+        FIRST_CALL_TRANSACTION  = 0x00000001,
+        LAST_CALL_TRANSACTION   = 0x00ffffff,
+
+        PING_TRANSACTION        = B_PACK_CHARS('_','P','N','G'),
+        DUMP_TRANSACTION        = B_PACK_CHARS('_','D','M','P'),
+        SHELL_COMMAND_TRANSACTION = B_PACK_CHARS('_','C','M','D'),
+        INTERFACE_TRANSACTION   = B_PACK_CHARS('_', 'N', 'T', 'F'),
+        SYSPROPS_TRANSACTION    = B_PACK_CHARS('_', 'S', 'P', 'R'),
+
+        // Corresponds to TF_ONE_WAY -- an asynchronous call.
+        FLAG_ONEWAY             = 0x00000001
+    };
+
+                          IBinder();
+
+    /**
+     * Check if this IBinder implements the interface named by
+     * @a descriptor.  If it does, the base pointer to it is returned,
+     * which you can safely static_cast<> to the concrete C++ interface.
+     */
+    virtual sp<IInterface>  queryLocalInterface(const String16& descriptor);
+
+    /**
+     * Return the canonical name of the interface provided by this IBinder
+     * object.
+     */
+    virtual const String16& getInterfaceDescriptor() const = 0;
+
+    virtual bool            isBinderAlive() const = 0;
+    virtual status_t        pingBinder() = 0;
+    virtual status_t        dump(int fd, const Vector<String16>& args) = 0;
+    static  status_t        shellCommand(const sp<IBinder>& target, int in, int out, int err,
+                                         Vector<String16>& args, const sp<IShellCallback>& callback,
+                                         const sp<IResultReceiver>& resultReceiver);
+
+    virtual status_t        transact(   uint32_t code,
+                                        const Parcel& data,
+                                        Parcel* reply,
+                                        uint32_t flags = 0) = 0;
+
+    // DeathRecipient is pure abstract, there is no virtual method
+    // implementation to put in a translation unit in order to silence the
+    // weak vtables warning.
+    #if defined(__clang__)
+    #pragma clang diagnostic push
+    #pragma clang diagnostic ignored "-Wweak-vtables"
+    #endif
+
+    class DeathRecipient : public virtual RefBase
+    {
+    public:
+        virtual void binderDied(const wp<IBinder>& who) = 0;
+    };
+
+    #if defined(__clang__)
+    #pragma clang diagnostic pop
+    #endif
+
+    /**
+     * Register the @a recipient for a notification if this binder
+     * goes away.  If this binder object unexpectedly goes away
+     * (typically because its hosting process has been killed),
+     * then DeathRecipient::binderDied() will be called with a reference
+     * to this.
+     *
+     * The @a cookie is optional -- if non-NULL, it should be a
+     * memory address that you own (that is, you know it is unique).
+     *
+     * @note You will only receive death notifications for remote binders,
+     * as local binders by definition can't die without you dying as well.
+     * Trying to use this function on a local binder will result in an
+     * INVALID_OPERATION code being returned and nothing happening.
+     *
+     * @note This link always holds a weak reference to its recipient.
+     *
+     * @note You will only receive a weak reference to the dead
+     * binder.  You should not try to promote this to a strong reference.
+     * (Nor should you need to, as there is nothing useful you can
+     * directly do with it now that it has passed on.)
+     */
+    virtual status_t        linkToDeath(const sp<DeathRecipient>& recipient,
+                                        void* cookie = NULL,
+                                        uint32_t flags = 0) = 0;
+
+    /**
+     * Remove a previously registered death notification.
+     * The @a recipient will no longer be called if this object
+     * 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.
+     */
+    virtual status_t        unlinkToDeath(  const wp<DeathRecipient>& recipient,
+                                            void* cookie = NULL,
+                                            uint32_t flags = 0,
+                                            wp<DeathRecipient>* outRecipient = NULL) = 0;
+
+    virtual bool            checkSubclass(const void* subclassID) const;
+
+    typedef void (*object_cleanup_func)(const void* id, void* obj, void* cleanupCookie);
+
+    virtual void            attachObject(   const void* objectID,
+                                            void* object,
+                                            void* cleanupCookie,
+                                            object_cleanup_func func) = 0;
+    virtual void*           findObject(const void* objectID) const = 0;
+    virtual void            detachObject(const void* objectID) = 0;
+
+    virtual BBinder*        localBinder();
+    virtual BpBinder*       remoteBinder();
+
+protected:
+    virtual          ~IBinder();
+
+private:
+};
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_IBINDER_H
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
new file mode 100644
index 0000000..0f1fe5b
--- /dev/null
+++ b/libs/binder/include/binder/IInterface.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2005 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_IINTERFACE_H
+#define ANDROID_IINTERFACE_H
+
+#include <binder/Binder.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IInterface : public virtual RefBase
+{
+public:
+            IInterface();
+            static sp<IBinder>  asBinder(const IInterface*);
+            static sp<IBinder>  asBinder(const sp<IInterface>&);
+
+protected:
+    virtual                     ~IInterface();
+    virtual IBinder*            onAsBinder() = 0;
+};
+
+// ----------------------------------------------------------------------
+
+template<typename INTERFACE>
+inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
+{
+    return INTERFACE::asInterface(obj);
+}
+
+// ----------------------------------------------------------------------
+
+template<typename INTERFACE>
+class BnInterface : public INTERFACE, public BBinder
+{
+public:
+    virtual sp<IInterface>      queryLocalInterface(const String16& _descriptor);
+    virtual const String16&     getInterfaceDescriptor() const;
+
+protected:
+    virtual IBinder*            onAsBinder();
+};
+
+// ----------------------------------------------------------------------
+
+template<typename INTERFACE>
+class BpInterface : public INTERFACE, public BpRefBase
+{
+public:
+    explicit                    BpInterface(const sp<IBinder>& remote);
+
+protected:
+    virtual IBinder*            onAsBinder();
+};
+
+// ----------------------------------------------------------------------
+
+#define DECLARE_META_INTERFACE(INTERFACE)                               \
+    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();                                            \
+
+
+#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
+    const ::android::String16 I##INTERFACE::descriptor(NAME);           \
+    const ::android::String16&                                          \
+            I##INTERFACE::getInterfaceDescriptor() const {              \
+        return I##INTERFACE::descriptor;                                \
+    }                                                                   \
+    ::android::sp<I##INTERFACE> I##INTERFACE::asInterface(              \
+            const ::android::sp<::android::IBinder>& obj)               \
+    {                                                                   \
+        ::android::sp<I##INTERFACE> intr;                               \
+        if (obj != NULL) {                                              \
+            intr = static_cast<I##INTERFACE*>(                          \
+                obj->queryLocalInterface(                               \
+                        I##INTERFACE::descriptor).get());               \
+            if (intr == NULL) {                                         \
+                intr = new Bp##INTERFACE(obj);                          \
+            }                                                           \
+        }                                                               \
+        return intr;                                                    \
+    }                                                                   \
+    I##INTERFACE::I##INTERFACE() { }                                    \
+    I##INTERFACE::~I##INTERFACE() { }                                   \
+
+
+#define CHECK_INTERFACE(interface, data, reply)                         \
+    if (!(data).checkInterface(this)) { return PERMISSION_DENIED; }     \
+
+
+// ----------------------------------------------------------------------
+// No user-serviceable parts after this...
+
+template<typename INTERFACE>
+inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(
+        const String16& _descriptor)
+{
+    if (_descriptor == INTERFACE::descriptor) return this;
+    return NULL;
+}
+
+template<typename INTERFACE>
+inline const String16& BnInterface<INTERFACE>::getInterfaceDescriptor() const
+{
+    return INTERFACE::getInterfaceDescriptor();
+}
+
+template<typename INTERFACE>
+IBinder* BnInterface<INTERFACE>::onAsBinder()
+{
+    return this;
+}
+
+template<typename INTERFACE>
+inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
+    : BpRefBase(remote)
+{
+}
+
+template<typename INTERFACE>
+inline IBinder* BpInterface<INTERFACE>::onAsBinder()
+{
+    return remote();
+}
+    
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IINTERFACE_H
diff --git a/libs/binder/include/binder/IMediaResourceMonitor.h b/libs/binder/include/binder/IMediaResourceMonitor.h
new file mode 100644
index 0000000..b21047f
--- /dev/null
+++ b/libs/binder/include/binder/IMediaResourceMonitor.h
@@ -0,0 +1,55 @@
+/*
+ * 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_I_MEDIA_RESOURCE_MONITOR_H
+#define ANDROID_I_MEDIA_RESOURCE_MONITOR_H
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IMediaResourceMonitor : public IInterface {
+public:
+    DECLARE_META_INTERFACE(MediaResourceMonitor)
+
+    // Values should be in sync with Intent.EXTRA_MEDIA_RESOURCE_TYPE_XXX.
+    enum {
+        TYPE_VIDEO_CODEC = 0,
+        TYPE_AUDIO_CODEC = 1,
+    };
+
+    virtual void notifyResourceGranted(/*in*/ int32_t pid, /*in*/ const int32_t type) = 0;
+
+    enum {
+        NOTIFY_RESOURCE_GRANTED = IBinder::FIRST_CALL_TRANSACTION,
+    };
+};
+
+// ----------------------------------------------------------------------
+
+class BnMediaResourceMonitor : public BnInterface<IMediaResourceMonitor> {
+public:
+    virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+            uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_I_MEDIA_RESOURCE_MONITOR_H
diff --git a/libs/binder/include/binder/IMemory.h b/libs/binder/include/binder/IMemory.h
new file mode 100644
index 0000000..15a104f
--- /dev/null
+++ b/libs/binder/include/binder/IMemory.h
@@ -0,0 +1,102 @@
+/*
+ * 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_IMEMORY_H
+#define ANDROID_IMEMORY_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class IMemoryHeap : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(MemoryHeap)
+
+    // flags returned by getFlags()
+    enum {
+        READ_ONLY   = 0x00000001
+    };
+
+    virtual int         getHeapID() const = 0;
+    virtual void*       getBase() const = 0;
+    virtual size_t      getSize() const = 0;
+    virtual uint32_t    getFlags() const = 0;
+    virtual uint32_t    getOffset() const = 0;
+
+    // these are there just for backward source compatibility
+    int32_t heapID() const { return getHeapID(); }
+    void*   base() const  { return getBase(); }
+    size_t  virtualSize() const { return getSize(); }
+};
+
+class BnMemoryHeap : public BnInterface<IMemoryHeap>
+{
+public:
+    virtual status_t onTransact( 
+            uint32_t code,
+            const Parcel& data,
+            Parcel* reply,
+            uint32_t flags = 0);
+    
+    BnMemoryHeap();
+protected:
+    virtual ~BnMemoryHeap();
+};
+
+// ----------------------------------------------------------------------------
+
+class IMemory : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(Memory)
+
+    virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const = 0;
+
+    // helpers
+    void* fastPointer(const sp<IBinder>& heap, ssize_t offset) const;
+    void* pointer() const;
+    size_t size() const;
+    ssize_t offset() const;
+};
+
+class BnMemory : public BnInterface<IMemory>
+{
+public:
+    virtual status_t onTransact(
+            uint32_t code,
+            const Parcel& data,
+            Parcel* reply,
+            uint32_t flags = 0);
+
+    BnMemory();
+protected:
+    virtual ~BnMemory();
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IMEMORY_H
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
new file mode 100644
index 0000000..245607e
--- /dev/null
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2005 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_IPC_THREAD_STATE_H
+#define ANDROID_IPC_THREAD_STATE_H
+
+#include <utils/Errors.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
+#include <utils/Vector.h>
+
+#if defined(_WIN32)
+typedef  int  uid_t;
+#endif
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class IPCThreadState
+{
+public:
+    static  IPCThreadState*     self();
+    static  IPCThreadState*     selfOrNull();  // self(), but won't instantiate
+    
+            sp<ProcessState>    process();
+            
+            status_t            clearLastError();
+
+            pid_t               getCallingPid() const;
+            uid_t               getCallingUid() const;
+
+            void                setStrictModePolicy(int32_t policy);
+            int32_t             getStrictModePolicy() const;
+
+            void                setLastTransactionBinderFlags(int32_t flags);
+            int32_t             getLastTransactionBinderFlags() const;
+
+            int64_t             clearCallingIdentity();
+            void                restoreCallingIdentity(int64_t token);
+            
+            int                 setupPolling(int* fd);
+            status_t            handlePolledCommands();
+            void                flushCommands();
+
+            void                joinThreadPool(bool isMain = true);
+            
+            // Stop the local process.
+            void                stopProcess(bool immediate = true);
+            
+            status_t            transact(int32_t handle,
+                                         uint32_t code, const Parcel& data,
+                                         Parcel* reply, uint32_t flags);
+
+            void                incStrongHandle(int32_t handle);
+            void                decStrongHandle(int32_t handle);
+            void                incWeakHandle(int32_t handle);
+            void                decWeakHandle(int32_t handle);
+            status_t            attemptIncStrongHandle(int32_t handle);
+    static  void                expungeHandle(int32_t handle, IBinder* binder);
+            status_t            requestDeathNotification(   int32_t handle,
+                                                            BpBinder* proxy); 
+            status_t            clearDeathNotification( int32_t handle,
+                                                        BpBinder* proxy); 
+
+    static  void                shutdown();
+
+    // Call this to disable switching threads to background scheduling when
+    // receiving incoming IPC calls.  This is specifically here for the
+    // Android system process, since it expects to have background apps calling
+    // in to it but doesn't want to acquire locks in its services while in
+    // the background.
+    static  void                disableBackgroundScheduling(bool disable);
+            bool                backgroundSchedulingDisabled();
+
+            // Call blocks until the number of executing binder threads is less than
+            // the maximum number of binder threads threads allowed for this process.
+            void                blockUntilThreadAvailable();
+
+private:
+                                IPCThreadState();
+                                ~IPCThreadState();
+
+            status_t            sendReply(const Parcel& reply, uint32_t flags);
+            status_t            waitForResponse(Parcel *reply,
+                                                status_t *acquireResult=NULL);
+            status_t            talkWithDriver(bool doReceive=true);
+            status_t            writeTransactionData(int32_t cmd,
+                                                     uint32_t binderFlags,
+                                                     int32_t handle,
+                                                     uint32_t code,
+                                                     const Parcel& data,
+                                                     status_t* statusBuffer);
+            status_t            getAndExecuteCommand();
+            status_t            executeCommand(int32_t command);
+            void                processPendingDerefs();
+
+            void                clearCaller();
+
+    static  void                threadDestructor(void *st);
+    static  void                freeBuffer(Parcel* parcel,
+                                           const uint8_t* data, size_t dataSize,
+                                           const binder_size_t* objects, size_t objectsSize,
+                                           void* cookie);
+    
+    const   sp<ProcessState>    mProcess;
+            Vector<BBinder*>    mPendingStrongDerefs;
+            Vector<RefBase::weakref_type*> mPendingWeakDerefs;
+
+            Parcel              mIn;
+            Parcel              mOut;
+            status_t            mLastError;
+            pid_t               mCallingPid;
+            uid_t               mCallingUid;
+            int32_t             mStrictModePolicy;
+            int32_t             mLastTransactionBinderFlags;
+};
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_IPC_THREAD_STATE_H
diff --git a/libs/binder/include/binder/IPermissionController.h b/libs/binder/include/binder/IPermissionController.h
new file mode 100644
index 0000000..25f3431
--- /dev/null
+++ b/libs/binder/include/binder/IPermissionController.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2005 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_IPERMISSION_CONTROLLER_H
+#define ANDROID_IPERMISSION_CONTROLLER_H
+
+#include <binder/IInterface.h>
+#include <stdlib.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IPermissionController : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(PermissionController)
+
+    virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid) = 0;
+
+    virtual void getPackagesForUid(const uid_t uid, Vector<String16> &packages) = 0;
+
+    virtual bool isRuntimePermission(const String16& permission) = 0;
+
+    enum {
+        CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+        GET_PACKAGES_FOR_UID_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1,
+        IS_RUNTIME_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 2
+    };
+};
+
+// ----------------------------------------------------------------------
+
+class BnPermissionController : public BnInterface<IPermissionController>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IPERMISSION_CONTROLLER_H
+
diff --git a/libs/binder/include/binder/IProcessInfoService.h b/libs/binder/include/binder/IProcessInfoService.h
new file mode 100644
index 0000000..2669f91
--- /dev/null
+++ b/libs/binder/include/binder/IProcessInfoService.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef ANDROID_I_PROCESS_INFO_SERVICE_H
+#define ANDROID_I_PROCESS_INFO_SERVICE_H
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IProcessInfoService : public IInterface {
+public:
+    DECLARE_META_INTERFACE(ProcessInfoService)
+
+    virtual status_t    getProcessStatesFromPids( size_t length,
+                                                  /*in*/ int32_t* pids,
+                                                  /*out*/ int32_t* states) = 0;
+
+    virtual status_t    getProcessStatesAndOomScoresFromPids( size_t length,
+                                                  /*in*/ int32_t* pids,
+                                                  /*out*/ int32_t* states,
+                                                  /*out*/ int32_t* scores) = 0;
+
+    enum {
+        GET_PROCESS_STATES_FROM_PIDS = IBinder::FIRST_CALL_TRANSACTION,
+        GET_PROCESS_STATES_AND_OOM_SCORES_FROM_PIDS,
+    };
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_I_PROCESS_INFO_SERVICE_H
diff --git a/libs/binder/include/binder/IResultReceiver.h b/libs/binder/include/binder/IResultReceiver.h
new file mode 100644
index 0000000..e494fba
--- /dev/null
+++ b/libs/binder/include/binder/IResultReceiver.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+//
+#ifndef ANDROID_IRESULT_RECEIVER_H
+#define ANDROID_IRESULT_RECEIVER_H
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IResultReceiver : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(ResultReceiver)
+
+    virtual void send(int32_t resultCode) = 0;
+
+    enum {
+        OP_SEND = IBinder::FIRST_CALL_TRANSACTION
+    };
+};
+
+// ----------------------------------------------------------------------
+
+class BnResultReceiver : public BnInterface<IResultReceiver>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IRESULT_RECEIVER_H
+
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
new file mode 100644
index 0000000..3b23f81
--- /dev/null
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2005 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_ISERVICE_MANAGER_H
+#define ANDROID_ISERVICE_MANAGER_H
+
+#include <binder/IInterface.h>
+#include <binder/IPermissionController.h>
+#include <utils/Vector.h>
+#include <utils/String16.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IServiceManager : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(ServiceManager)
+
+    /**
+     * Retrieve an existing service, blocking for a few seconds
+     * if it doesn't yet exist.
+     */
+    virtual sp<IBinder>         getService( const String16& name) const = 0;
+
+    /**
+     * Retrieve an existing service, non-blocking.
+     */
+    virtual sp<IBinder>         checkService( const String16& name) const = 0;
+
+    /**
+     * Register a service.
+     */
+    virtual status_t            addService( const String16& name,
+                                            const sp<IBinder>& service,
+                                            bool allowIsolated = false) = 0;
+
+    /**
+     * Return list of all existing services.
+     */
+    virtual Vector<String16>    listServices() = 0;
+
+    enum {
+        GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+        CHECK_SERVICE_TRANSACTION,
+        ADD_SERVICE_TRANSACTION,
+        LIST_SERVICES_TRANSACTION,
+    };
+};
+
+sp<IServiceManager> defaultServiceManager();
+
+template<typename INTERFACE>
+status_t getService(const String16& name, sp<INTERFACE>* outService)
+{
+    const sp<IServiceManager> sm = defaultServiceManager();
+    if (sm != NULL) {
+        *outService = interface_cast<INTERFACE>(sm->getService(name));
+        if ((*outService) != NULL) return NO_ERROR;
+    }
+    return NAME_NOT_FOUND;
+}
+
+bool checkCallingPermission(const String16& permission);
+bool checkCallingPermission(const String16& permission,
+                            int32_t* outPid, int32_t* outUid);
+bool checkPermission(const String16& permission, pid_t pid, uid_t uid);
+
+}; // namespace android
+
+#endif // ANDROID_ISERVICE_MANAGER_H
+
diff --git a/libs/binder/include/binder/IShellCallback.h b/libs/binder/include/binder/IShellCallback.h
new file mode 100644
index 0000000..fda9ee6
--- /dev/null
+++ b/libs/binder/include/binder/IShellCallback.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+//
+#ifndef ANDROID_ISHELL_CALLBACK_H
+#define ANDROID_ISHELL_CALLBACK_H
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IShellCallback : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(ShellCallback);
+
+    virtual int openOutputFile(const String16& path, const String16& seLinuxContext) = 0;
+
+    enum {
+        OP_OPEN_OUTPUT_FILE = IBinder::FIRST_CALL_TRANSACTION
+    };
+};
+
+// ----------------------------------------------------------------------
+
+class BnShellCallback : public BnInterface<IShellCallback>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_ISHELL_CALLBACK_H
+
diff --git a/libs/binder/include/binder/IpPrefix.h b/libs/binder/include/binder/IpPrefix.h
new file mode 100644
index 0000000..96ebaac
--- /dev/null
+++ b/libs/binder/include/binder/IpPrefix.h
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_IP_PREFIX_H
+#define ANDROID_IP_PREFIX_H
+
+#include <netinet/in.h>
+
+#include <binder/Parcelable.h>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+namespace net {
+
+/*
+ * C++ implementation of the Java class android.net.IpPrefix
+ */
+class IpPrefix : public Parcelable {
+public:
+    IpPrefix() = default;
+    virtual ~IpPrefix() = default;
+    IpPrefix(const IpPrefix& prefix) = default;
+
+    IpPrefix(const struct in6_addr& addr, int32_t plen):
+        mUnion(addr), mPrefixLength(plen), mIsIpv6(true) { }
+
+    IpPrefix(const struct in_addr& addr, int32_t plen):
+        mUnion(addr), mPrefixLength(plen), mIsIpv6(false) { }
+
+    bool getAddressAsIn6Addr(struct in6_addr* addr) const;
+    bool getAddressAsInAddr(struct in_addr* addr) const;
+
+    const struct in6_addr& getAddressAsIn6Addr() const;
+    const struct in_addr& getAddressAsInAddr() const;
+
+    bool isIpv6() const;
+    bool isIpv4() const;
+
+    int32_t getPrefixLength() const;
+
+    void setAddress(const struct in6_addr& addr);
+    void setAddress(const struct in_addr& addr);
+
+    void setPrefixLength(int32_t prefix);
+
+    friend bool operator==(const IpPrefix& lhs, const IpPrefix& rhs);
+
+    friend bool operator!=(const IpPrefix& lhs, const IpPrefix& rhs) {
+        return !(lhs == rhs);
+    }
+
+public:
+    // Overrides
+    status_t writeToParcel(Parcel* parcel) const override;
+    status_t readFromParcel(const Parcel* parcel) override;
+
+private:
+    union InternalUnion {
+        InternalUnion() = default;
+        InternalUnion(const struct in6_addr &addr):mIn6Addr(addr) { };
+        InternalUnion(const struct in_addr &addr):mInAddr(addr) { };
+        struct in6_addr mIn6Addr;
+        struct in_addr mInAddr;
+    } mUnion;
+    int32_t mPrefixLength;
+    bool mIsIpv6;
+};
+
+}  // namespace net
+
+}  // namespace android
+
+#endif  // ANDROID_IP_PREFIX_H
diff --git a/libs/binder/include/binder/Map.h b/libs/binder/include/binder/Map.h
new file mode 100644
index 0000000..96a4f8a
--- /dev/null
+++ b/libs/binder/include/binder/Map.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2005 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_MAP_H
+#define ANDROID_MAP_H
+
+#include <map>
+#include <string>
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace binder {
+
+class Value;
+
+/**
+ * Convenience typedef for ::std::map<::std::string,::android::binder::Value>
+ */
+typedef ::std::map<::std::string, Value> Map;
+
+} // namespace binder
+} // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_MAP_H
diff --git a/include/binder/MemoryBase.h b/libs/binder/include/binder/MemoryBase.h
similarity index 100%
rename from include/binder/MemoryBase.h
rename to libs/binder/include/binder/MemoryBase.h
diff --git a/include/binder/MemoryDealer.h b/libs/binder/include/binder/MemoryDealer.h
similarity index 100%
rename from include/binder/MemoryDealer.h
rename to libs/binder/include/binder/MemoryDealer.h
diff --git a/include/binder/MemoryHeapBase.h b/libs/binder/include/binder/MemoryHeapBase.h
similarity index 100%
rename from include/binder/MemoryHeapBase.h
rename to libs/binder/include/binder/MemoryHeapBase.h
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
new file mode 100644
index 0000000..5d36526
--- /dev/null
+++ b/libs/binder/include/binder/Parcel.h
@@ -0,0 +1,932 @@
+/*
+ * Copyright (C) 2005 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_H
+#define ANDROID_PARCEL_H
+
+#include <string>
+#include <vector>
+
+#include <android-base/unique_fd.h>
+#include <cutils/native_handle.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#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>
+#include <binder/Map.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+template <typename T> class Flattenable;
+template <typename T> class LightFlattenable;
+class IBinder;
+class IPCThreadState;
+class ProcessState;
+class String8;
+class TextOutput;
+
+namespace binder {
+class Value;
+};
+
+class Parcel {
+    friend class IPCThreadState;
+public:
+    class ReadableBlob;
+    class WritableBlob;
+
+                        Parcel();
+                        ~Parcel();
+    
+    const uint8_t*      data() const;
+    size_t              dataSize() const;
+    size_t              dataAvail() const;
+    size_t              dataPosition() const;
+    size_t              dataCapacity() const;
+
+    status_t            setDataSize(size_t size);
+    void                setDataPosition(size_t pos) const;
+    status_t            setDataCapacity(size_t size);
+    
+    status_t            setData(const uint8_t* buffer, size_t len);
+
+    status_t            appendFrom(const Parcel *parcel,
+                                   size_t start, size_t len);
+
+    int                 compareData(const Parcel& other);
+
+    bool                allowFds() const;
+    bool                pushAllowFds(bool allowFds);
+    void                restoreAllowFds(bool lastValue);
+
+    bool                hasFileDescriptors() const;
+
+    // Writes the RPC header.
+    status_t            writeInterfaceToken(const String16& interface);
+
+    // Parses the RPC header, returning true if the interface name
+    // in the header matches the expected interface from the caller.
+    //
+    // Additionally, enforceInterface does part of the work of
+    // propagating the StrictMode policy mask, populating the current
+    // IPCThreadState, which as an optimization may optionally be
+    // passed in.
+    bool                enforceInterface(const String16& interface,
+                                         IPCThreadState* threadState = NULL) const;
+    bool                checkInterface(IBinder*) const;
+
+    void                freeData();
+
+private:
+    const binder_size_t* objects() const;
+
+public:
+    size_t              objectsCount() const;
+    
+    status_t            errorCheck() const;
+    void                setError(status_t err);
+    
+    status_t            write(const void* data, size_t len);
+    void*               writeInplace(size_t len);
+    status_t            writeUnpadded(const void* data, size_t len);
+    status_t            writeInt32(int32_t val);
+    status_t            writeUint32(uint32_t val);
+    status_t            writeInt64(int64_t val);
+    status_t            writeUint64(uint64_t val);
+    status_t            writeFloat(float val);
+    status_t            writeDouble(double val);
+    status_t            writeCString(const char* str);
+    status_t            writeString8(const String8& str);
+    status_t            writeString16(const String16& str);
+    status_t            writeString16(const std::unique_ptr<String16>& str);
+    status_t            writeString16(const char16_t* str, size_t len);
+    status_t            writeStrongBinder(const sp<IBinder>& val);
+    status_t            writeWeakBinder(const wp<IBinder>& val);
+    status_t            writeInt32Array(size_t len, const int32_t *val);
+    status_t            writeByteArray(size_t len, const uint8_t *val);
+    status_t            writeBool(bool val);
+    status_t            writeChar(char16_t val);
+    status_t            writeByte(int8_t val);
+
+    // Take a UTF8 encoded string, convert to UTF16, write it to the parcel.
+    status_t            writeUtf8AsUtf16(const std::string& str);
+    status_t            writeUtf8AsUtf16(const std::unique_ptr<std::string>& str);
+
+    status_t            writeByteVector(const std::unique_ptr<std::vector<int8_t>>& val);
+    status_t            writeByteVector(const std::vector<int8_t>& val);
+    status_t            writeByteVector(const std::unique_ptr<std::vector<uint8_t>>& val);
+    status_t            writeByteVector(const std::vector<uint8_t>& val);
+    status_t            writeInt32Vector(const std::unique_ptr<std::vector<int32_t>>& val);
+    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            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);
+    status_t            writeDoubleVector(const std::vector<double>& val);
+    status_t            writeBoolVector(const std::unique_ptr<std::vector<bool>>& val);
+    status_t            writeBoolVector(const std::vector<bool>& val);
+    status_t            writeCharVector(const std::unique_ptr<std::vector<char16_t>>& val);
+    status_t            writeCharVector(const std::vector<char16_t>& val);
+    status_t            writeString16Vector(
+                            const std::unique_ptr<std::vector<std::unique_ptr<String16>>>& val);
+    status_t            writeString16Vector(const std::vector<String16>& val);
+    status_t            writeUtf8VectorAsUtf16Vector(
+                            const std::unique_ptr<std::vector<std::unique_ptr<std::string>>>& val);
+    status_t            writeUtf8VectorAsUtf16Vector(const std::vector<std::string>& val);
+
+    status_t            writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val);
+    status_t            writeStrongBinderVector(const std::vector<sp<IBinder>>& val);
+
+    template<typename T>
+    status_t            writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val);
+    template<typename T>
+    status_t            writeParcelableVector(const std::shared_ptr<std::vector<std::unique_ptr<T>>>& val);
+    template<typename T>
+    status_t            writeParcelableVector(const std::vector<T>& val);
+
+    template<typename T>
+    status_t            writeNullableParcelable(const std::unique_ptr<T>& parcelable);
+
+    status_t            writeParcelable(const Parcelable& parcelable);
+
+    status_t            writeValue(const binder::Value& value);
+
+    template<typename T>
+    status_t            write(const Flattenable<T>& val);
+
+    template<typename T>
+    status_t            write(const LightFlattenable<T>& val);
+
+    template<typename T>
+    status_t            writeVectorSize(const std::vector<T>& val);
+    template<typename T>
+    status_t            writeVectorSize(const std::unique_ptr<std::vector<T>>& val);
+
+    status_t            writeMap(const binder::Map& map);
+    status_t            writeNullableMap(const std::unique_ptr<binder::Map>& map);
+
+    // Place a native_handle into the parcel (the native_handle's file-
+    // descriptors are dup'ed, so it is safe to delete the native_handle
+    // when this function returns).
+    // Doesn't take ownership of the native_handle.
+    status_t            writeNativeHandle(const native_handle* handle);
+
+    // Place a file descriptor into the parcel.  The given fd must remain
+    // valid for the lifetime of the parcel.
+    // The Parcel does not take ownership of the given fd unless you ask it to.
+    status_t            writeFileDescriptor(int fd, bool takeOwnership = false);
+
+    // Place a file descriptor into the parcel.  A dup of the fd is made, which
+    // will be closed once the parcel is destroyed.
+    status_t            writeDupFileDescriptor(int fd);
+
+    // Place a Java "parcel file descriptor" into the parcel.  The given fd must remain
+    // valid for the lifetime of the parcel.
+    // 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 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.
+    status_t            writeUniqueFileDescriptor(
+                            const base::unique_fd& fd);
+
+    // Place a vector of file desciptors into the parcel. Each descriptor is
+    // dup'd as in writeDupFileDescriptor
+    status_t            writeUniqueFileDescriptorVector(
+                            const std::unique_ptr<std::vector<base::unique_fd>>& val);
+    status_t            writeUniqueFileDescriptorVector(
+                            const std::vector<base::unique_fd>& val);
+
+    // Writes a blob to the parcel.
+    // If the blob is small, then it is stored in-place, otherwise it is
+    // transferred by way of an anonymous shared memory region.  Prefer sending
+    // immutable blobs if possible since they may be subsequently transferred between
+    // processes without further copying whereas mutable blobs always need to be copied.
+    // The caller should call release() on the blob after writing its contents.
+    status_t            writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob);
+
+    // Write an existing immutable blob file descriptor to the parcel.
+    // This allows the client to send the same blob to multiple processes
+    // as long as it keeps a dup of the blob file descriptor handy for later.
+    status_t            writeDupImmutableBlobFileDescriptor(int fd);
+
+    status_t            writeObject(const flat_binder_object& val, bool nullMetaData);
+
+    // Like Parcel.java's writeNoException().  Just writes a zero int32.
+    // Currently the native implementation doesn't do any of the StrictMode
+    // stack gathering and serialization that the Java implementation does.
+    status_t            writeNoException();
+
+    void                remove(size_t start, size_t amt);
+    
+    status_t            read(void* outData, size_t len) const;
+    const void*         readInplace(size_t len) const;
+    int32_t             readInt32() const;
+    status_t            readInt32(int32_t *pArg) const;
+    uint32_t            readUint32() const;
+    status_t            readUint32(uint32_t *pArg) const;
+    int64_t             readInt64() const;
+    status_t            readInt64(int64_t *pArg) const;
+    uint64_t            readUint64() const;
+    status_t            readUint64(uint64_t *pArg) const;
+    float               readFloat() const;
+    status_t            readFloat(float *pArg) const;
+    double              readDouble() const;
+    status_t            readDouble(double *pArg) const;
+    intptr_t            readIntPtr() const;
+    status_t            readIntPtr(intptr_t *pArg) const;
+    bool                readBool() const;
+    status_t            readBool(bool *pArg) const;
+    char16_t            readChar() const;
+    status_t            readChar(char16_t *pArg) const;
+    int8_t              readByte() const;
+    status_t            readByte(int8_t *pArg) const;
+
+    // Read a UTF16 encoded string, convert to UTF8
+    status_t            readUtf8FromUtf16(std::string* str) const;
+    status_t            readUtf8FromUtf16(std::unique_ptr<std::string>* str) const;
+
+    const char*         readCString() const;
+    String8             readString8() const;
+    status_t            readString8(String8* pArg) const;
+    String16            readString16() const;
+    status_t            readString16(String16* pArg) const;
+    status_t            readString16(std::unique_ptr<String16>* pArg) const;
+    const char16_t*     readString16Inplace(size_t* outLen) const;
+    sp<IBinder>         readStrongBinder() const;
+    status_t            readStrongBinder(sp<IBinder>* val) const;
+    status_t            readNullableStrongBinder(sp<IBinder>* val) const;
+    wp<IBinder>         readWeakBinder() const;
+
+    template<typename T>
+    status_t            readParcelableVector(
+                            std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const;
+    template<typename T>
+    status_t            readParcelableVector(std::vector<T>* val) const;
+
+    status_t            readParcelable(Parcelable* parcelable) const;
+
+    template<typename T>
+    status_t            readParcelable(std::unique_ptr<T>* parcelable) const;
+
+    status_t            readValue(binder::Value* value) const;
+
+    template<typename T>
+    status_t            readStrongBinder(sp<T>* val) const;
+
+    template<typename T>
+    status_t            readNullableStrongBinder(sp<T>* val) const;
+
+    status_t            readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const;
+    status_t            readStrongBinderVector(std::vector<sp<IBinder>>* val) const;
+
+    status_t            readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const;
+    status_t            readByteVector(std::vector<int8_t>* val) const;
+    status_t            readByteVector(std::unique_ptr<std::vector<uint8_t>>* val) const;
+    status_t            readByteVector(std::vector<uint8_t>* val) const;
+    status_t            readInt32Vector(std::unique_ptr<std::vector<int32_t>>* val) const;
+    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            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;
+    status_t            readDoubleVector(std::vector<double>* val) const;
+    status_t            readBoolVector(std::unique_ptr<std::vector<bool>>* val) const;
+    status_t            readBoolVector(std::vector<bool>* val) const;
+    status_t            readCharVector(std::unique_ptr<std::vector<char16_t>>* val) const;
+    status_t            readCharVector(std::vector<char16_t>* val) const;
+    status_t            readString16Vector(
+                            std::unique_ptr<std::vector<std::unique_ptr<String16>>>* val) const;
+    status_t            readString16Vector(std::vector<String16>* val) const;
+    status_t            readUtf8VectorFromUtf16Vector(
+                            std::unique_ptr<std::vector<std::unique_ptr<std::string>>>* val) const;
+    status_t            readUtf8VectorFromUtf16Vector(std::vector<std::string>* val) const;
+
+    template<typename T>
+    status_t            read(Flattenable<T>& val) const;
+
+    template<typename T>
+    status_t            read(LightFlattenable<T>& val) const;
+
+    template<typename T>
+    status_t            resizeOutVector(std::vector<T>* val) const;
+    template<typename T>
+    status_t            resizeOutVector(std::unique_ptr<std::vector<T>>* val) const;
+
+    status_t            readMap(binder::Map* map)const;
+    status_t            readNullableMap(std::unique_ptr<binder::Map>* map) const;
+
+    // Like Parcel.java's readExceptionCode().  Reads the first int32
+    // off of a Parcel's header, returning 0 or the negative error
+    // code on exceptions, but also deals with skipping over rich
+    // response headers.  Callers should use this to read & parse the
+    // response headers rather than doing it by hand.
+    int32_t             readExceptionCode() const;
+
+    // Retrieve native_handle from the parcel. This returns a copy of the
+    // parcel's native_handle (the caller takes ownership). The caller
+    // must free the native_handle with native_handle_close() and 
+    // native_handle_delete().
+    native_handle*     readNativeHandle() const;
+
+    
+    // Retrieve a file descriptor from the parcel.  This returns the raw fd
+    // in the parcel, which you do not own -- use dup() to get your own copy.
+    int                 readFileDescriptor() const;
+
+    // Retrieve a Java "parcel file descriptor" from the parcel.  This returns the raw fd
+    // in the parcel, which you do not own -- use dup() to get your own copy.
+    int                 readParcelFileDescriptor() const;
+
+    // Retrieve a smart file descriptor from the parcel.
+    status_t            readUniqueFileDescriptor(
+                            base::unique_fd* val) const;
+
+
+    // Retrieve a vector of smart file descriptors from the parcel.
+    status_t            readUniqueFileDescriptorVector(
+                            std::unique_ptr<std::vector<base::unique_fd>>* val) const;
+    status_t            readUniqueFileDescriptorVector(
+                            std::vector<base::unique_fd>* val) const;
+
+    // Reads a blob from the parcel.
+    // The caller should call release() on the blob after reading its contents.
+    status_t            readBlob(size_t len, ReadableBlob* outBlob) const;
+
+    const flat_binder_object* readObject(bool nullMetaData) const;
+
+    // Explicitly close all file descriptors in the parcel.
+    void                closeFileDescriptors();
+
+    // Debugging: get metrics on current allocations.
+    static size_t       getGlobalAllocSize();
+    static size_t       getGlobalAllocCount();
+
+private:
+    typedef void        (*release_func)(Parcel* parcel,
+                                        const uint8_t* data, size_t dataSize,
+                                        const binder_size_t* objects, size_t objectsSize,
+                                        void* cookie);
+                        
+    uintptr_t           ipcData() const;
+    size_t              ipcDataSize() const;
+    uintptr_t           ipcObjects() const;
+    size_t              ipcObjectsCount() const;
+    void                ipcSetDataReference(const uint8_t* data, size_t dataSize,
+                                            const binder_size_t* objects, size_t objectsCount,
+                                            release_func relFunc, void* relCookie);
+    
+public:
+    void                print(TextOutput& to, uint32_t flags = 0) const;
+
+private:
+                        Parcel(const Parcel& o);
+    Parcel&             operator=(const Parcel& o);
+    
+    status_t            finishWrite(size_t len);
+    void                releaseObjects();
+    void                acquireObjects();
+    status_t            growData(size_t len);
+    status_t            restartWrite(size_t desired);
+    status_t            continueWrite(size_t desired);
+    status_t            writePointer(uintptr_t val);
+    status_t            readPointer(uintptr_t *pArg) const;
+    uintptr_t           readPointer() const;
+    void                freeDataNoInit();
+    void                initState();
+    void                scanForFds() const;
+                        
+    template<class T>
+    status_t            readAligned(T *pArg) const;
+
+    template<class T>   T readAligned() const;
+
+    template<class T>
+    status_t            writeAligned(T val);
+
+    status_t            writeRawNullableParcelable(const Parcelable*
+                                                   parcelable);
+
+    template<typename T, typename U>
+    status_t            unsafeReadTypedVector(std::vector<T>* val,
+                                              status_t(Parcel::*read_func)(U*) const) const;
+    template<typename T>
+    status_t            readNullableTypedVector(std::unique_ptr<std::vector<T>>* val,
+                                                status_t(Parcel::*read_func)(T*) const) const;
+    template<typename T>
+    status_t            readTypedVector(std::vector<T>* val,
+                                        status_t(Parcel::*read_func)(T*) const) const;
+    template<typename T, typename U>
+    status_t            unsafeWriteTypedVector(const std::vector<T>& val,
+                                               status_t(Parcel::*write_func)(U));
+    template<typename T>
+    status_t            writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
+                                                 status_t(Parcel::*write_func)(const T&));
+    template<typename T>
+    status_t            writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
+                                                 status_t(Parcel::*write_func)(T));
+    template<typename T>
+    status_t            writeTypedVector(const std::vector<T>& val,
+                                         status_t(Parcel::*write_func)(const T&));
+    template<typename T>
+    status_t            writeTypedVector(const std::vector<T>& val,
+                                         status_t(Parcel::*write_func)(T));
+
+    status_t            mError;
+    uint8_t*            mData;
+    size_t              mDataSize;
+    size_t              mDataCapacity;
+    mutable size_t      mDataPos;
+    binder_size_t*      mObjects;
+    size_t              mObjectsSize;
+    size_t              mObjectsCapacity;
+    mutable size_t      mNextObjectHint;
+
+    mutable bool        mFdsKnown;
+    mutable bool        mHasFds;
+    bool                mAllowFds;
+
+    release_func        mOwner;
+    void*               mOwnerCookie;
+
+    class Blob {
+    public:
+        Blob();
+        ~Blob();
+
+        void clear();
+        void release();
+        inline size_t size() const { return mSize; }
+        inline int fd() const { return mFd; }
+        inline bool isMutable() const { return mMutable; }
+
+    protected:
+        void init(int fd, void* data, size_t size, bool isMutable);
+
+        int mFd; // owned by parcel so not closed when released
+        void* mData;
+        size_t mSize;
+        bool mMutable;
+    };
+
+    #if defined(__clang__)
+    #pragma clang diagnostic push
+    #pragma clang diagnostic ignored "-Wweak-vtables"
+    #endif
+
+    // FlattenableHelperInterface and FlattenableHelper avoid generating a vtable entry in objects
+    // following Flattenable template/protocol.
+    class FlattenableHelperInterface {
+    protected:
+        ~FlattenableHelperInterface() { }
+    public:
+        virtual size_t getFlattenedSize() const = 0;
+        virtual size_t getFdCount() const = 0;
+        virtual status_t flatten(void* buffer, size_t size, int* fds, size_t count) const = 0;
+        virtual status_t unflatten(void const* buffer, size_t size, int const* fds, size_t count) = 0;
+    };
+
+    #if defined(__clang__)
+    #pragma clang diagnostic pop
+    #endif
+
+    // Concrete implementation of FlattenableHelperInterface that delegates virtual calls to the
+    // specified class T implementing the Flattenable protocol. It "virtualizes" a compile-time
+    // protocol.
+    template<typename T>
+    class FlattenableHelper : public FlattenableHelperInterface {
+        friend class Parcel;
+        const Flattenable<T>& val;
+        explicit FlattenableHelper(const Flattenable<T>& _val) : val(_val) { }
+
+    protected:
+        ~FlattenableHelper() = default;
+    public:
+        virtual size_t getFlattenedSize() const {
+            return val.getFlattenedSize();
+        }
+        virtual size_t getFdCount() const {
+            return val.getFdCount();
+        }
+        virtual status_t flatten(void* buffer, size_t size, int* fds, size_t count) const {
+            return val.flatten(buffer, size, fds, count);
+        }
+        virtual status_t unflatten(void const* buffer, size_t size, int const* fds, size_t count) {
+            return const_cast<Flattenable<T>&>(val).unflatten(buffer, size, fds, count);
+        }
+    };
+    status_t write(const FlattenableHelperInterface& val);
+    status_t read(FlattenableHelperInterface& val) const;
+
+public:
+    class ReadableBlob : public Blob {
+        friend class Parcel;
+    public:
+        inline const void* data() const { return mData; }
+        inline void* mutableData() { return isMutable() ? mData : NULL; }
+    };
+
+    class WritableBlob : public Blob {
+        friend class Parcel;
+    public:
+        inline void* data() { return mData; }
+    };
+
+private:
+    size_t mOpenAshmemSize;
+
+public:
+    // TODO: Remove once ABI can be changed.
+    size_t getBlobAshmemSize() const;
+    size_t getOpenAshmemSize() const;
+};
+
+// ---------------------------------------------------------------------------
+
+template<typename T>
+status_t Parcel::write(const Flattenable<T>& val) {
+    const FlattenableHelper<T> helper(val);
+    return write(helper);
+}
+
+template<typename T>
+status_t Parcel::write(const LightFlattenable<T>& val) {
+    size_t size(val.getFlattenedSize());
+    if (!val.isFixedSize()) {
+        if (size > INT32_MAX) {
+            return BAD_VALUE;
+        }
+        status_t err = writeInt32(static_cast<int32_t>(size));
+        if (err != NO_ERROR) {
+            return err;
+        }
+    }
+    if (size) {
+        void* buffer = writeInplace(size);
+        if (buffer == NULL)
+            return NO_MEMORY;
+        return val.flatten(buffer, size);
+    }
+    return NO_ERROR;
+}
+
+template<typename T>
+status_t Parcel::read(Flattenable<T>& val) const {
+    FlattenableHelper<T> helper(val);
+    return read(helper);
+}
+
+template<typename T>
+status_t Parcel::read(LightFlattenable<T>& val) const {
+    size_t size;
+    if (val.isFixedSize()) {
+        size = val.getFlattenedSize();
+    } else {
+        int32_t s;
+        status_t err = readInt32(&s);
+        if (err != NO_ERROR) {
+            return err;
+        }
+        size = static_cast<size_t>(s);
+    }
+    if (size) {
+        void const* buffer = readInplace(size);
+        return buffer == NULL ? NO_MEMORY :
+                val.unflatten(buffer, size);
+    }
+    return NO_ERROR;
+}
+
+template<typename T>
+status_t Parcel::writeVectorSize(const std::vector<T>& val) {
+    if (val.size() > INT32_MAX) {
+        return BAD_VALUE;
+    }
+    return writeInt32(static_cast<int32_t>(val.size()));
+}
+
+template<typename T>
+status_t Parcel::writeVectorSize(const std::unique_ptr<std::vector<T>>& val) {
+    if (!val) {
+        return writeInt32(-1);
+    }
+
+    return writeVectorSize(*val);
+}
+
+template<typename T>
+status_t Parcel::resizeOutVector(std::vector<T>* val) const {
+    int32_t size;
+    status_t err = readInt32(&size);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    if (size < 0) {
+        return UNEXPECTED_NULL;
+    }
+    val->resize(size_t(size));
+    return OK;
+}
+
+template<typename T>
+status_t Parcel::resizeOutVector(std::unique_ptr<std::vector<T>>* val) const {
+    int32_t size;
+    status_t err = readInt32(&size);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    val->reset();
+    if (size >= 0) {
+        val->reset(new std::vector<T>(size_t(size)));
+    }
+
+    return OK;
+}
+
+template<typename T>
+status_t Parcel::readStrongBinder(sp<T>* val) const {
+    sp<IBinder> tmp;
+    status_t ret = readStrongBinder(&tmp);
+
+    if (ret == OK) {
+        *val = interface_cast<T>(tmp);
+
+        if (val->get() == nullptr) {
+            return UNKNOWN_ERROR;
+        }
+    }
+
+    return ret;
+}
+
+template<typename T>
+status_t Parcel::readNullableStrongBinder(sp<T>* val) const {
+    sp<IBinder> tmp;
+    status_t ret = readNullableStrongBinder(&tmp);
+
+    if (ret == OK) {
+        *val = interface_cast<T>(tmp);
+
+        if (val->get() == nullptr && tmp.get() != nullptr) {
+            ret = UNKNOWN_ERROR;
+        }
+    }
+
+    return ret;
+}
+
+template<typename T, typename U>
+status_t Parcel::unsafeReadTypedVector(
+        std::vector<T>* val,
+        status_t(Parcel::*read_func)(U*) const) const {
+    int32_t size;
+    status_t status = this->readInt32(&size);
+
+    if (status != OK) {
+        return status;
+    }
+
+    if (size < 0) {
+        return UNEXPECTED_NULL;
+    }
+
+    if (val->max_size() < static_cast<size_t>(size)) {
+        return NO_MEMORY;
+    }
+
+    val->resize(static_cast<size_t>(size));
+
+    if (val->size() < static_cast<size_t>(size)) {
+        return NO_MEMORY;
+    }
+
+    for (auto& v: *val) {
+        status = (this->*read_func)(&v);
+
+        if (status != OK) {
+            return status;
+        }
+    }
+
+    return OK;
+}
+
+template<typename T>
+status_t Parcel::readTypedVector(std::vector<T>* val,
+                                 status_t(Parcel::*read_func)(T*) const) const {
+    return unsafeReadTypedVector(val, read_func);
+}
+
+template<typename T>
+status_t Parcel::readNullableTypedVector(std::unique_ptr<std::vector<T>>* val,
+                                         status_t(Parcel::*read_func)(T*) const) const {
+    const size_t start = dataPosition();
+    int32_t size;
+    status_t status = readInt32(&size);
+    val->reset();
+
+    if (status != OK || size < 0) {
+        return status;
+    }
+
+    setDataPosition(start);
+    val->reset(new std::vector<T>());
+
+    status = unsafeReadTypedVector(val->get(), read_func);
+
+    if (status != OK) {
+        val->reset();
+    }
+
+    return status;
+}
+
+template<typename T, typename U>
+status_t Parcel::unsafeWriteTypedVector(const std::vector<T>& val,
+                                        status_t(Parcel::*write_func)(U)) {
+    if (val.size() > std::numeric_limits<int32_t>::max()) {
+        return BAD_VALUE;
+    }
+
+    status_t status = this->writeInt32(static_cast<int32_t>(val.size()));
+
+    if (status != OK) {
+        return status;
+    }
+
+    for (const auto& item : val) {
+        status = (this->*write_func)(item);
+
+        if (status != OK) {
+            return status;
+        }
+    }
+
+    return OK;
+}
+
+template<typename T>
+status_t Parcel::writeTypedVector(const std::vector<T>& val,
+                                  status_t(Parcel::*write_func)(const T&)) {
+    return unsafeWriteTypedVector(val, write_func);
+}
+
+template<typename T>
+status_t Parcel::writeTypedVector(const std::vector<T>& val,
+                                  status_t(Parcel::*write_func)(T)) {
+    return unsafeWriteTypedVector(val, write_func);
+}
+
+template<typename T>
+status_t Parcel::writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
+                                          status_t(Parcel::*write_func)(const T&)) {
+    if (val.get() == nullptr) {
+        return this->writeInt32(-1);
+    }
+
+    return unsafeWriteTypedVector(*val, write_func);
+}
+
+template<typename T>
+status_t Parcel::writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
+                                          status_t(Parcel::*write_func)(T)) {
+    if (val.get() == nullptr) {
+        return this->writeInt32(-1);
+    }
+
+    return unsafeWriteTypedVector(*val, write_func);
+}
+
+template<typename T>
+status_t Parcel::readParcelableVector(std::vector<T>* val) const {
+    return unsafeReadTypedVector<T, Parcelable>(val, &Parcel::readParcelable);
+}
+
+template<typename T>
+status_t Parcel::readParcelableVector(std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const {
+    const size_t start = dataPosition();
+    int32_t size;
+    status_t status = readInt32(&size);
+    val->reset();
+
+    if (status != OK || size < 0) {
+        return status;
+    }
+
+    setDataPosition(start);
+    val->reset(new std::vector<std::unique_ptr<T>>());
+
+    status = unsafeReadTypedVector(val->get(), &Parcel::readParcelable<T>);
+
+    if (status != OK) {
+        val->reset();
+    }
+
+    return status;
+}
+
+template<typename T>
+status_t Parcel::readParcelable(std::unique_ptr<T>* parcelable) const {
+    const size_t start = dataPosition();
+    int32_t present;
+    status_t status = readInt32(&present);
+    parcelable->reset();
+
+    if (status != OK || !present) {
+        return status;
+    }
+
+    setDataPosition(start);
+    parcelable->reset(new T());
+
+    status = readParcelable(parcelable->get());
+
+    if (status != OK) {
+        parcelable->reset();
+    }
+
+    return status;
+}
+
+template<typename T>
+status_t Parcel::writeNullableParcelable(const std::unique_ptr<T>& parcelable) {
+    return writeRawNullableParcelable(parcelable.get());
+}
+
+template<typename T>
+status_t Parcel::writeParcelableVector(const std::vector<T>& val) {
+    return unsafeWriteTypedVector<T,const Parcelable&>(val, &Parcel::writeParcelable);
+}
+
+template<typename T>
+status_t Parcel::writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val) {
+    if (val.get() == nullptr) {
+        return this->writeInt32(-1);
+    }
+
+    return unsafeWriteTypedVector(*val, &Parcel::writeNullableParcelable<T>);
+}
+
+template<typename T>
+status_t Parcel::writeParcelableVector(const std::shared_ptr<std::vector<std::unique_ptr<T>>>& val) {
+    if (val.get() == nullptr) {
+        return this->writeInt32(-1);
+    }
+
+    return unsafeWriteTypedVector(*val, &Parcel::writeNullableParcelable<T>);
+}
+
+// ---------------------------------------------------------------------------
+
+inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel)
+{
+    parcel.print(to);
+    return to;
+}
+
+// ---------------------------------------------------------------------------
+
+// Generic acquire and release of objects.
+void acquire_object(const sp<ProcessState>& proc,
+                    const flat_binder_object& obj, const void* who);
+void release_object(const sp<ProcessState>& proc,
+                    const flat_binder_object& obj, const void* who);
+
+void flatten_binder(const sp<ProcessState>& proc,
+                    const sp<IBinder>& binder, flat_binder_object* out);
+void flatten_binder(const sp<ProcessState>& proc,
+                    const wp<IBinder>& binder, flat_binder_object* out);
+status_t unflatten_binder(const sp<ProcessState>& proc,
+                          const flat_binder_object& flat, sp<IBinder>* out);
+status_t unflatten_binder(const sp<ProcessState>& proc,
+                          const flat_binder_object& flat, wp<IBinder>* out);
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_PARCEL_H
diff --git a/libs/binder/include/binder/Parcelable.h b/libs/binder/include/binder/Parcelable.h
new file mode 100644
index 0000000..d5b57ac
--- /dev/null
+++ b/libs/binder/include/binder/Parcelable.h
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_PARCELABLE_H
+#define ANDROID_PARCELABLE_H
+
+#include <vector>
+
+#include <utils/Errors.h>
+#include <utils/String16.h>
+
+namespace android {
+
+class Parcel;
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#endif
+
+// Abstract interface of all parcelables.
+class Parcelable {
+public:
+    virtual ~Parcelable() = default;
+
+    // Write |this| parcelable to the given |parcel|.  Keep in mind that
+    // implementations of writeToParcel must be manually kept in sync
+    // with readFromParcel and the Java equivalent versions of these methods.
+    //
+    // Returns android::OK on success and an appropriate error otherwise.
+    virtual status_t writeToParcel(Parcel* parcel) const = 0;
+
+    // Read data from the given |parcel| into |this|.  After readFromParcel
+    // completes, |this| should have equivalent state to the object that
+    // wrote itself to the parcel.
+    //
+    // Returns android::OK on success and an appropriate error otherwise.
+    virtual status_t readFromParcel(const Parcel* parcel) = 0;
+};  // class Parcelable
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
+}  // namespace android
+
+#endif // ANDROID_PARCELABLE_H
diff --git a/include/binder/PermissionCache.h b/libs/binder/include/binder/PermissionCache.h
similarity index 100%
rename from include/binder/PermissionCache.h
rename to libs/binder/include/binder/PermissionCache.h
diff --git a/libs/binder/include/binder/PersistableBundle.h b/libs/binder/include/binder/PersistableBundle.h
new file mode 100644
index 0000000..322fef9
--- /dev/null
+++ b/libs/binder/include/binder/PersistableBundle.h
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_PERSISTABLE_BUNDLE_H
+#define ANDROID_PERSISTABLE_BUNDLE_H
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include <binder/Parcelable.h>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+namespace os {
+
+/*
+ * C++ implementation of PersistableBundle, a mapping from String values to
+ * various types that can be saved to persistent and later restored.
+ */
+class PersistableBundle : public Parcelable {
+public:
+    PersistableBundle() = default;
+    virtual ~PersistableBundle() = default;
+    PersistableBundle(const PersistableBundle& bundle) = default;
+
+    status_t writeToParcel(Parcel* parcel) const override;
+    status_t readFromParcel(const Parcel* parcel) override;
+
+    bool empty() const;
+    size_t size() const;
+    size_t erase(const String16& key);
+
+    /*
+     * Setters for PersistableBundle. Adds a a key-value pair instantiated with
+     * |key| and |value| into the member map appropriate for the type of |value|.
+     * If there is already an existing value for |key|, |value| will replace it.
+     */
+    void putBoolean(const String16& key, bool value);
+    void putInt(const String16& key, int32_t value);
+    void putLong(const String16& key, int64_t value);
+    void putDouble(const String16& key, double value);
+    void putString(const String16& key, const String16& value);
+    void putBooleanVector(const String16& key, const std::vector<bool>& value);
+    void putIntVector(const String16& key, const std::vector<int32_t>& value);
+    void putLongVector(const String16& key, const std::vector<int64_t>& value);
+    void putDoubleVector(const String16& key, const std::vector<double>& value);
+    void putStringVector(const String16& key, const std::vector<String16>& value);
+    void putPersistableBundle(const String16& key, const PersistableBundle& value);
+
+    /*
+     * Getters for PersistableBundle. If |key| exists, these methods write the
+     * value associated with |key| into |out|, and return true. Otherwise, these
+     * methods return false.
+     */
+    bool getBoolean(const String16& key, bool* out) const;
+    bool getInt(const String16& key, int32_t* out) const;
+    bool getLong(const String16& key, int64_t* out) const;
+    bool getDouble(const String16& key, double* out) const;
+    bool getString(const String16& key, String16* out) const;
+    bool getBooleanVector(const String16& key, std::vector<bool>* out) const;
+    bool getIntVector(const String16& key, std::vector<int32_t>* out) const;
+    bool getLongVector(const String16& key, std::vector<int64_t>* out) const;
+    bool getDoubleVector(const String16& key, std::vector<double>* out) const;
+    bool getStringVector(const String16& key, std::vector<String16>* out) const;
+    bool getPersistableBundle(const String16& key, PersistableBundle* out) const;
+
+    /* Getters for all keys for each value type */
+    std::set<String16> getBooleanKeys() const;
+    std::set<String16> getIntKeys() const;
+    std::set<String16> getLongKeys() const;
+    std::set<String16> getDoubleKeys() const;
+    std::set<String16> getStringKeys() const;
+    std::set<String16> getBooleanVectorKeys() const;
+    std::set<String16> getIntVectorKeys() const;
+    std::set<String16> getLongVectorKeys() const;
+    std::set<String16> getDoubleVectorKeys() const;
+    std::set<String16> getStringVectorKeys() const;
+    std::set<String16> getPersistableBundleKeys() const;
+
+    friend bool operator==(const PersistableBundle& lhs, const PersistableBundle& rhs) {
+        return (lhs.mBoolMap == rhs.mBoolMap && lhs.mIntMap == rhs.mIntMap &&
+                lhs.mLongMap == rhs.mLongMap && lhs.mDoubleMap == rhs.mDoubleMap &&
+                lhs.mStringMap == rhs.mStringMap && lhs.mBoolVectorMap == rhs.mBoolVectorMap &&
+                lhs.mIntVectorMap == rhs.mIntVectorMap &&
+                lhs.mLongVectorMap == rhs.mLongVectorMap &&
+                lhs.mDoubleVectorMap == rhs.mDoubleVectorMap &&
+                lhs.mStringVectorMap == rhs.mStringVectorMap &&
+                lhs.mPersistableBundleMap == rhs.mPersistableBundleMap);
+    }
+
+    friend bool operator!=(const PersistableBundle& lhs, const PersistableBundle& rhs) {
+        return !(lhs == rhs);
+    }
+
+private:
+    status_t writeToParcelInner(Parcel* parcel) const;
+    status_t readFromParcelInner(const Parcel* parcel, size_t length);
+
+    std::map<String16, bool> mBoolMap;
+    std::map<String16, int32_t> mIntMap;
+    std::map<String16, int64_t> mLongMap;
+    std::map<String16, double> mDoubleMap;
+    std::map<String16, String16> mStringMap;
+    std::map<String16, std::vector<bool>> mBoolVectorMap;
+    std::map<String16, std::vector<int32_t>> mIntVectorMap;
+    std::map<String16, std::vector<int64_t>> mLongVectorMap;
+    std::map<String16, std::vector<double>> mDoubleVectorMap;
+    std::map<String16, std::vector<String16>> mStringVectorMap;
+    std::map<String16, PersistableBundle> mPersistableBundleMap;
+};
+
+}  // namespace os
+
+}  // namespace android
+
+#endif  // ANDROID_PERSISTABLE_BUNDLE_H
diff --git a/libs/binder/include/binder/ProcessInfoService.h b/libs/binder/include/binder/ProcessInfoService.h
new file mode 100644
index 0000000..0da61ee
--- /dev/null
+++ b/libs/binder/include/binder/ProcessInfoService.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef ANDROID_PROCESS_INFO_SERVICE_H
+#define ANDROID_PROCESS_INFO_SERVICE_H
+
+#include <binder/IProcessInfoService.h>
+#include <utils/Errors.h>
+#include <utils/Singleton.h>
+#include <sys/types.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class ProcessInfoService : public Singleton<ProcessInfoService> {
+
+    friend class Singleton<ProcessInfoService>;
+    sp<IProcessInfoService> mProcessInfoService;
+    Mutex mProcessInfoLock;
+
+    ProcessInfoService();
+
+    status_t getProcessStatesImpl(size_t length, /*in*/ int32_t* pids, /*out*/ int32_t* states);
+    status_t getProcessStatesScoresImpl(size_t length, /*in*/ int32_t* pids,
+            /*out*/ int32_t* states, /*out*/ int32_t *scores);
+    void updateBinderLocked();
+
+    static const int BINDER_ATTEMPT_LIMIT = 5;
+
+public:
+
+    /**
+     * For each PID in the given "pids" input array, write the current process state
+     * for that process into the "states" output array, or
+     * ActivityManager.PROCESS_STATE_NONEXISTENT * to indicate that no process with the given PID
+     * exists.
+     *
+     * Returns NO_ERROR if this operation was successful, or a negative error code otherwise.
+     */
+    static status_t getProcessStatesFromPids(size_t length, /*in*/ int32_t* pids,
+            /*out*/ int32_t* states) {
+        return ProcessInfoService::getInstance().getProcessStatesImpl(length, /*in*/ pids,
+                /*out*/ states);
+    }
+
+    /**
+     * For each PID in the given "pids" input array, write the current process state
+     * for that process into the "states" output array, or
+     * ActivityManager.PROCESS_STATE_NONEXISTENT * to indicate that no process with the given PID
+     * exists. OoM scores will also be written in the "scores" output array.
+     * Please also note that clients calling this method need to have
+     * "GET_PROCESS_STATE_AND_OOM_SCORE" permission.
+     *
+     * Returns NO_ERROR if this operation was successful, or a negative error code otherwise.
+     */
+    static status_t getProcessStatesScoresFromPids(size_t length, /*in*/ int32_t* pids,
+            /*out*/ int32_t* states, /*out*/ int32_t *scores) {
+        return ProcessInfoService::getInstance().getProcessStatesScoresImpl(
+                length, /*in*/ pids, /*out*/ states, /*out*/ scores);
+    }
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_PROCESS_INFO_SERVICE_H
+
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
new file mode 100644
index 0000000..1ef045d
--- /dev/null
+++ b/libs/binder/include/binder/ProcessState.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2005 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_PROCESS_STATE_H
+#define ANDROID_PROCESS_STATE_H
+
+#include <binder/IBinder.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+#include <utils/threads.h>
+
+#include <pthread.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class IPCThreadState;
+
+class ProcessState : public virtual RefBase
+{
+public:
+    static  sp<ProcessState>    self();
+    /* 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.
+     */
+    static  sp<ProcessState>    initWithDriver(const char *driver);
+
+            void                setContextObject(const sp<IBinder>& object);
+            sp<IBinder>         getContextObject(const sp<IBinder>& caller);
+        
+            void                setContextObject(const sp<IBinder>& object,
+                                                 const String16& name);
+            sp<IBinder>         getContextObject(const String16& name,
+                                                 const sp<IBinder>& caller);
+
+            void                startThreadPool();
+                        
+    typedef bool (*context_check_func)(const String16& name,
+                                       const sp<IBinder>& caller,
+                                       void* userData);
+        
+            bool                isContextManager(void) const;
+            bool                becomeContextManager(
+                                    context_check_func checkFunc,
+                                    void* userData);
+
+            sp<IBinder>         getStrongProxyForHandle(int32_t handle);
+            wp<IBinder>         getWeakProxyForHandle(int32_t handle);
+            void                expungeHandle(int32_t handle, IBinder* binder);
+
+            void                spawnPooledThread(bool isMain);
+            
+            status_t            setThreadPoolMaxThreadCount(size_t maxThreads);
+            void                giveThreadPoolName();
+
+            String8             getDriverName();
+
+private:
+    friend class IPCThreadState;
+    
+                                ProcessState(const char* driver);
+                                ~ProcessState();
+
+                                ProcessState(const ProcessState& o);
+            ProcessState&       operator=(const ProcessState& o);
+            String8             makeBinderThreadName();
+
+            struct handle_entry {
+                IBinder* binder;
+                RefBase::weakref_type* refs;
+            };
+
+            handle_entry*       lookupHandleLocked(int32_t handle);
+
+            String8             mDriverName;
+            int                 mDriverFD;
+            void*               mVMStart;
+
+            // Protects thread count variable below.
+            pthread_mutex_t     mThreadCountLock;
+            pthread_cond_t      mThreadCountDecrement;
+            // Number of binder threads current executing a command.
+            size_t              mExecutingThreadsCount;
+            // Maximum number for binder threads allowed for this process.
+            size_t              mMaxThreads;
+            // Time when thread pool was emptied
+            int64_t             mStarvationStartTimeMs;
+
+    mutable Mutex               mLock;  // protects everything below.
+
+            Vector<handle_entry>mHandleToObject;
+
+            bool                mManagesContexts;
+            context_check_func  mBinderContextCheckFunc;
+            void*               mBinderContextUserData;
+
+            KeyedVector<String16, sp<IBinder> >
+                                mContexts;
+
+
+            String8             mRootDir;
+            bool                mThreadPoolStarted;
+    volatile int32_t            mThreadPoolSeq;
+};
+    
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_PROCESS_STATE_H
diff --git a/libs/binder/include/binder/SafeInterface.h b/libs/binder/include/binder/SafeInterface.h
new file mode 100644
index 0000000..3bfd462
--- /dev/null
+++ b/libs/binder/include/binder/SafeInterface.h
@@ -0,0 +1,705 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <cutils/compiler.h>
+
+// Set to 1 to enable CallStacks when logging errors
+#define SI_DUMP_CALLSTACKS 0
+#if SI_DUMP_CALLSTACKS
+#include <utils/CallStack.h>
+#endif
+
+#include <utils/NativeHandle.h>
+
+#include <functional>
+#include <type_traits>
+
+namespace android {
+namespace SafeInterface {
+
+// ParcelHandler is responsible for writing/reading various types to/from a Parcel in a generic way
+class ParcelHandler {
+public:
+    explicit ParcelHandler(const char* logTag) : mLogTag(logTag) {}
+
+    // Specializations for types with dedicated handling in Parcel
+    status_t read(const Parcel& parcel, bool* b) const {
+        return callParcel("readBool", [&]() { return parcel.readBool(b); });
+    }
+    status_t write(Parcel* parcel, bool b) const {
+        return callParcel("writeBool", [&]() { return parcel->writeBool(b); });
+    }
+    template <typename E>
+    typename std::enable_if<std::is_enum<E>::value, status_t>::type read(const Parcel& parcel,
+                                                                         E* e) const {
+        typename std::underlying_type<E>::type u{};
+        status_t result = read(parcel, &u);
+        *e = static_cast<E>(u);
+        return result;
+    }
+    template <typename E>
+    typename std::enable_if<std::is_enum<E>::value, status_t>::type write(Parcel* parcel,
+                                                                          E e) const {
+        return write(parcel, static_cast<typename std::underlying_type<E>::type>(e));
+    }
+    template <typename T>
+    typename std::enable_if<std::is_base_of<Flattenable<T>, T>::value, status_t>::type read(
+            const Parcel& parcel, T* t) const {
+        return callParcel("read(Flattenable)", [&]() { return parcel.read(*t); });
+    }
+    template <typename T>
+    typename std::enable_if<std::is_base_of<Flattenable<T>, T>::value, status_t>::type write(
+            Parcel* parcel, const T& t) const {
+        return callParcel("write(Flattenable)", [&]() { return parcel->write(t); });
+    }
+    template <typename T>
+    typename std::enable_if<std::is_base_of<Flattenable<T>, T>::value, status_t>::type read(
+            const Parcel& parcel, sp<T>* t) const {
+        *t = new T{};
+        return callParcel("read(sp<Flattenable>)", [&]() { return parcel.read(*(t->get())); });
+    }
+    template <typename T>
+    typename std::enable_if<std::is_base_of<Flattenable<T>, T>::value, status_t>::type write(
+            Parcel* parcel, const sp<T>& t) const {
+        return callParcel("write(sp<Flattenable>)", [&]() { return parcel->write(*(t.get())); });
+    }
+    template <typename T>
+    typename std::enable_if<std::is_base_of<LightFlattenable<T>, T>::value, status_t>::type read(
+            const Parcel& parcel, T* t) const {
+        return callParcel("read(LightFlattenable)", [&]() { return parcel.read(*t); });
+    }
+    template <typename T>
+    typename std::enable_if<std::is_base_of<LightFlattenable<T>, T>::value, status_t>::type write(
+            Parcel* parcel, const T& t) const {
+        return callParcel("write(LightFlattenable)", [&]() { return parcel->write(t); });
+    }
+    template <typename NH>
+    typename std::enable_if<std::is_same<NH, sp<NativeHandle>>::value, status_t>::type read(
+            const Parcel& parcel, NH* nh) {
+        *nh = NativeHandle::create(parcel.readNativeHandle(), true);
+        return NO_ERROR;
+    }
+    template <typename NH>
+    typename std::enable_if<std::is_same<NH, sp<NativeHandle>>::value, status_t>::type write(
+            Parcel* parcel, const NH& nh) {
+        return callParcel("write(sp<NativeHandle>)",
+                          [&]() { return parcel->writeNativeHandle(nh->handle()); });
+    }
+    template <typename T>
+    typename std::enable_if<std::is_base_of<Parcelable, T>::value, status_t>::type read(
+            const Parcel& parcel, T* t) const {
+        return callParcel("readParcelable", [&]() { return parcel.readParcelable(t); });
+    }
+    template <typename T>
+    typename std::enable_if<std::is_base_of<Parcelable, T>::value, status_t>::type write(
+            Parcel* parcel, const T& t) const {
+        return callParcel("writeParcelable", [&]() { return parcel->writeParcelable(t); });
+    }
+    status_t read(const Parcel& parcel, String8* str) const {
+        return callParcel("readString8", [&]() { return parcel.readString8(str); });
+    }
+    status_t write(Parcel* parcel, const String8& str) const {
+        return callParcel("writeString8", [&]() { return parcel->writeString8(str); });
+    }
+    template <typename T>
+    typename std::enable_if<std::is_same<IBinder, T>::value, status_t>::type read(
+            const Parcel& parcel, sp<T>* pointer) const {
+        return callParcel("readNullableStrongBinder",
+                          [&]() { return parcel.readNullableStrongBinder(pointer); });
+    }
+    template <typename T>
+    typename std::enable_if<std::is_same<IBinder, T>::value, status_t>::type write(
+            Parcel* parcel, const sp<T>& pointer) const {
+        return callParcel("writeStrongBinder",
+                          [&]() { return parcel->writeStrongBinder(pointer); });
+    }
+    template <typename T>
+    typename std::enable_if<std::is_base_of<IInterface, T>::value, status_t>::type read(
+            const Parcel& parcel, sp<T>* pointer) const {
+        return callParcel("readNullableStrongBinder[IInterface]",
+                          [&]() { return parcel.readNullableStrongBinder(pointer); });
+    }
+    template <typename T>
+    typename std::enable_if<std::is_base_of<IInterface, T>::value, status_t>::type write(
+            Parcel* parcel, const sp<T>& interface) const {
+        return write(parcel, IInterface::asBinder(interface));
+    }
+    template <typename T>
+    typename std::enable_if<std::is_base_of<Parcelable, T>::value, status_t>::type read(
+            const Parcel& parcel, std::vector<T>* v) const {
+        return callParcel("readParcelableVector", [&]() { return parcel.readParcelableVector(v); });
+    }
+    template <typename T>
+    typename std::enable_if<std::is_base_of<Parcelable, T>::value, status_t>::type write(
+            Parcel* parcel, const std::vector<T>& v) const {
+        return callParcel("writeParcelableVector",
+                          [&]() { return parcel->writeParcelableVector(v); });
+    }
+
+    // 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
+    // silently widened).
+    template <bool isSigned, size_t size, typename I>
+    struct HandleInt;
+    template <typename I>
+    struct HandleInt<true, 4, I> {
+        static status_t read(const ParcelHandler& handler, const Parcel& parcel, I* i) {
+            return handler.callParcel("readInt32", [&]() { return parcel.readInt32(i); });
+        }
+        static status_t write(const ParcelHandler& handler, Parcel* parcel, I i) {
+            return handler.callParcel("writeInt32", [&]() { return parcel->writeInt32(i); });
+        }
+    };
+    template <typename I>
+    struct HandleInt<false, 4, I> {
+        static status_t read(const ParcelHandler& handler, const Parcel& parcel, I* i) {
+            return handler.callParcel("readUint32", [&]() { return parcel.readUint32(i); });
+        }
+        static status_t write(const ParcelHandler& handler, Parcel* parcel, I i) {
+            return handler.callParcel("writeUint32", [&]() { return parcel->writeUint32(i); });
+        }
+    };
+    template <typename I>
+    struct HandleInt<true, 8, I> {
+        static status_t read(const ParcelHandler& handler, const Parcel& parcel, I* i) {
+            return handler.callParcel("readInt64", [&]() { return parcel.readInt64(i); });
+        }
+        static status_t write(const ParcelHandler& handler, Parcel* parcel, I i) {
+            return handler.callParcel("writeInt64", [&]() { return parcel->writeInt64(i); });
+        }
+    };
+    template <typename I>
+    struct HandleInt<false, 8, I> {
+        static status_t read(const ParcelHandler& handler, const Parcel& parcel, I* i) {
+            return handler.callParcel("readUint64", [&]() { return parcel.readUint64(i); });
+        }
+        static status_t write(const ParcelHandler& handler, Parcel* parcel, I i) {
+            return handler.callParcel("writeUint64", [&]() { return parcel->writeUint64(i); });
+        }
+    };
+    template <typename I>
+    typename std::enable_if<std::is_integral<I>::value, status_t>::type read(const Parcel& parcel,
+                                                                             I* i) const {
+        return HandleInt<std::is_signed<I>::value, sizeof(I), I>::read(*this, parcel, i);
+    }
+    template <typename I>
+    typename std::enable_if<std::is_integral<I>::value, status_t>::type write(Parcel* parcel,
+                                                                              I i) const {
+        return HandleInt<std::is_signed<I>::value, sizeof(I), I>::write(*this, parcel, i);
+    }
+
+private:
+    const char* const mLogTag;
+
+    // Helper to encapsulate error handling while calling the various Parcel methods
+    template <typename Function>
+    status_t callParcel(const char* name, Function f) const {
+        status_t error = f();
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            ALOG(LOG_ERROR, mLogTag, "Failed to %s, (%d: %s)", name, error, strerror(-error));
+#if SI_DUMP_CALLSTACKS
+            CallStack callStack(mLogTag);
+#endif
+        }
+        return error;
+    }
+};
+
+// Utility struct template which allows us to retrieve the types of the parameters of a member
+// function pointer
+template <typename T>
+struct ParamExtractor;
+template <typename Class, typename Return, typename... Params>
+struct ParamExtractor<Return (Class::*)(Params...)> {
+    using ParamTuple = std::tuple<Params...>;
+};
+template <typename Class, typename Return, typename... Params>
+struct ParamExtractor<Return (Class::*)(Params...) const> {
+    using ParamTuple = std::tuple<Params...>;
+};
+
+} // namespace SafeInterface
+
+template <typename Interface>
+class SafeBpInterface : public BpInterface<Interface> {
+protected:
+    SafeBpInterface(const sp<IBinder>& impl, const char* logTag)
+          : BpInterface<Interface>(impl), mLogTag(logTag) {}
+    ~SafeBpInterface() override = default;
+
+    // callRemote is used to invoke a synchronous procedure call over Binder
+    template <typename Method, typename TagType, typename... Args>
+    status_t callRemote(TagType tag, Args&&... args) const {
+        static_assert(sizeof(TagType) <= sizeof(uint32_t), "Tag must fit inside uint32_t");
+
+        // Verify that the arguments are compatible with the parameters
+        using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple;
+        static_assert(ArgsMatchParams<std::tuple<Args...>, ParamTuple>::value,
+                      "Invalid argument type");
+
+        // Write the input arguments to the data Parcel
+        Parcel data;
+        data.writeInterfaceToken(this->getInterfaceDescriptor());
+
+        status_t error = writeInputs(&data, std::forward<Args>(args)...);
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            // A message will have been logged by writeInputs
+            return error;
+        }
+
+        // Send the data Parcel to the remote and retrieve the reply parcel
+        Parcel reply;
+        error = this->remote()->transact(static_cast<uint32_t>(tag), data, &reply);
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            ALOG(LOG_ERROR, mLogTag, "Failed to transact (%d)", error);
+#if SI_DUMP_CALLSTACKS
+            CallStack callStack(mLogTag);
+#endif
+            return error;
+        }
+
+        // Read the outputs from the reply Parcel into the output arguments
+        error = readOutputs(reply, std::forward<Args>(args)...);
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            // A message will have been logged by readOutputs
+            return error;
+        }
+
+        // Retrieve the result code from the reply Parcel
+        status_t result = NO_ERROR;
+        error = reply.readInt32(&result);
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            ALOG(LOG_ERROR, mLogTag, "Failed to obtain result");
+#if SI_DUMP_CALLSTACKS
+            CallStack callStack(mLogTag);
+#endif
+            return error;
+        }
+        return result;
+    }
+
+    // callRemoteAsync is used to invoke an asynchronous procedure call over Binder
+    template <typename Method, typename TagType, typename... Args>
+    void callRemoteAsync(TagType tag, Args&&... args) const {
+        static_assert(sizeof(TagType) <= sizeof(uint32_t), "Tag must fit inside uint32_t");
+
+        // Verify that the arguments are compatible with the parameters
+        using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple;
+        static_assert(ArgsMatchParams<std::tuple<Args...>, ParamTuple>::value,
+                      "Invalid argument type");
+
+        // Write the input arguments to the data Parcel
+        Parcel data;
+        data.writeInterfaceToken(this->getInterfaceDescriptor());
+        status_t error = writeInputs(&data, std::forward<Args>(args)...);
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            // A message will have been logged by writeInputs
+            return;
+        }
+
+        // There will be no data in the reply Parcel since the call is one-way
+        Parcel reply;
+        error = this->remote()->transact(static_cast<uint32_t>(tag), data, &reply,
+                                         IBinder::FLAG_ONEWAY);
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            ALOG(LOG_ERROR, mLogTag, "Failed to transact (%d)", error);
+#if SI_DUMP_CALLSTACKS
+            CallStack callStack(mLogTag);
+#endif
+        }
+    }
+
+private:
+    const char* const mLogTag;
+
+    // This struct provides information on whether the decayed types of the elements at Index in the
+    // tuple types T and U (that is, the types after stripping cv-qualifiers, removing references,
+    // and a few other less common operations) are the same
+    template <size_t Index, typename T, typename U>
+    struct DecayedElementsMatch {
+    private:
+        using FirstT = typename std::tuple_element<Index, T>::type;
+        using DecayedT = typename std::decay<FirstT>::type;
+        using FirstU = typename std::tuple_element<Index, U>::type;
+        using DecayedU = typename std::decay<FirstU>::type;
+
+    public:
+        static constexpr bool value = std::is_same<DecayedT, DecayedU>::value;
+    };
+
+    // When comparing whether the argument types match the parameter types, we first decay them (see
+    // DecayedElementsMatch) to avoid falsely flagging, say, T&& against T even though they are
+    // equivalent enough for our purposes
+    template <typename T, typename U>
+    struct ArgsMatchParams {};
+    template <typename... Args, typename... Params>
+    struct ArgsMatchParams<std::tuple<Args...>, std::tuple<Params...>> {
+        static_assert(sizeof...(Args) <= sizeof...(Params), "Too many arguments");
+        static_assert(sizeof...(Args) >= sizeof...(Params), "Not enough arguments");
+
+    private:
+        template <size_t Index>
+        static constexpr typename std::enable_if<(Index < sizeof...(Args)), bool>::type
+        elementsMatch() {
+            if (!DecayedElementsMatch<Index, std::tuple<Args...>, std::tuple<Params...>>::value) {
+                return false;
+            }
+            return elementsMatch<Index + 1>();
+        }
+        template <size_t Index>
+        static constexpr typename std::enable_if<(Index >= sizeof...(Args)), bool>::type
+        elementsMatch() {
+            return true;
+        }
+
+    public:
+        static constexpr bool value = elementsMatch<0>();
+    };
+
+    // Since we assume that pointer arguments are outputs, we can use this template struct to
+    // determine whether or not a given argument is fundamentally a pointer type and thus an output
+    template <typename T>
+    struct IsPointerIfDecayed {
+    private:
+        using Decayed = typename std::decay<T>::type;
+
+    public:
+        static constexpr bool value = std::is_pointer<Decayed>::value;
+    };
+
+    template <typename T>
+    typename std::enable_if<!IsPointerIfDecayed<T>::value, status_t>::type writeIfInput(
+            Parcel* data, T&& t) const {
+        return SafeInterface::ParcelHandler{mLogTag}.write(data, std::forward<T>(t));
+    }
+    template <typename T>
+    typename std::enable_if<IsPointerIfDecayed<T>::value, status_t>::type writeIfInput(
+            Parcel* /*data*/, T&& /*t*/) const {
+        return NO_ERROR;
+    }
+
+    // This method iterates through all of the arguments, writing them to the data Parcel if they
+    // are an input (i.e., if they are not a pointer type)
+    template <typename T, typename... Remaining>
+    status_t writeInputs(Parcel* data, T&& t, Remaining&&... remaining) const {
+        status_t error = writeIfInput(data, std::forward<T>(t));
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            // A message will have been logged by writeIfInput
+            return error;
+        }
+        return writeInputs(data, std::forward<Remaining>(remaining)...);
+    }
+    static status_t writeInputs(Parcel* /*data*/) { return NO_ERROR; }
+
+    template <typename T>
+    typename std::enable_if<IsPointerIfDecayed<T>::value, status_t>::type readIfOutput(
+            const Parcel& reply, T&& t) const {
+        return SafeInterface::ParcelHandler{mLogTag}.read(reply, std::forward<T>(t));
+    }
+    template <typename T>
+    static typename std::enable_if<!IsPointerIfDecayed<T>::value, status_t>::type readIfOutput(
+            const Parcel& /*reply*/, T&& /*t*/) {
+        return NO_ERROR;
+    }
+
+    // Similar to writeInputs except that it reads output arguments from the reply Parcel
+    template <typename T, typename... Remaining>
+    status_t readOutputs(const Parcel& reply, T&& t, Remaining&&... remaining) const {
+        status_t error = readIfOutput(reply, std::forward<T>(t));
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            // A message will have been logged by readIfOutput
+            return error;
+        }
+        return readOutputs(reply, std::forward<Remaining>(remaining)...);
+    }
+    static status_t readOutputs(const Parcel& /*data*/) { return NO_ERROR; }
+};
+
+template <typename Interface>
+class SafeBnInterface : public BnInterface<Interface> {
+public:
+    explicit SafeBnInterface(const char* logTag) : mLogTag(logTag) {}
+
+protected:
+    template <typename Method>
+    status_t callLocal(const Parcel& data, Parcel* reply, Method method) {
+        CHECK_INTERFACE(this, data, reply);
+
+        // Since we need to both pass inputs into the call as well as retrieve outputs, we create a
+        // "raw" tuple, where the inputs are interleaved with actual, non-pointer versions of the
+        // outputs. When we ultimately call into the method, we will pass the addresses of the
+        // output arguments instead of their tuple members directly, but the storage will live in
+        // the tuple.
+        using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple;
+        typename RawConverter<std::tuple<>, ParamTuple>::type rawArgs{};
+
+        // Read the inputs from the data Parcel into the argument tuple
+        status_t error = InputReader<ParamTuple>{mLogTag}.readInputs(data, &rawArgs);
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            // A message will have been logged by read
+            return error;
+        }
+
+        // Call the local method
+        status_t result = MethodCaller<ParamTuple>::call(this, method, &rawArgs);
+
+        // Extract the outputs from the argument tuple and write them into the reply Parcel
+        error = OutputWriter<ParamTuple>{mLogTag}.writeOutputs(reply, &rawArgs);
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            // A message will have been logged by write
+            return error;
+        }
+
+        // Return the result code in the reply Parcel
+        error = reply->writeInt32(result);
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            ALOG(LOG_ERROR, mLogTag, "Failed to write result");
+#if SI_DUMP_CALLSTACKS
+            CallStack callStack(mLogTag);
+#endif
+            return error;
+        }
+        return NO_ERROR;
+    }
+
+    template <typename Method>
+    status_t callLocalAsync(const Parcel& data, Parcel* /*reply*/, Method method) {
+        // reply is not actually used by CHECK_INTERFACE
+        CHECK_INTERFACE(this, data, reply);
+
+        // Since we need to both pass inputs into the call as well as retrieve outputs, we create a
+        // "raw" tuple, where the inputs are interleaved with actual, non-pointer versions of the
+        // outputs. When we ultimately call into the method, we will pass the addresses of the
+        // output arguments instead of their tuple members directly, but the storage will live in
+        // the tuple.
+        using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple;
+        typename RawConverter<std::tuple<>, ParamTuple>::type rawArgs{};
+
+        // Read the inputs from the data Parcel into the argument tuple
+        status_t error = InputReader<ParamTuple>{mLogTag}.readInputs(data, &rawArgs);
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            // A message will have been logged by read
+            return error;
+        }
+
+        // Call the local method
+        MethodCaller<ParamTuple>::callVoid(this, method, &rawArgs);
+
+        // After calling, there is nothing more to do since asynchronous calls do not return a value
+        // to the caller
+        return NO_ERROR;
+    }
+
+private:
+    const char* const mLogTag;
+
+    // RemoveFirst strips the first element from a tuple.
+    // For example, given T = std::tuple<A, B, C>, RemoveFirst<T>::type = std::tuple<B, C>
+    template <typename T, typename... Args>
+    struct RemoveFirst;
+    template <typename T, typename... Args>
+    struct RemoveFirst<std::tuple<T, Args...>> {
+        using type = std::tuple<Args...>;
+    };
+
+    // RawConverter strips a tuple down to its fundamental types, discarding both pointers and
+    // references. This allows us to allocate storage for both input (non-pointer) arguments and
+    // output (pointer) arguments in one tuple.
+    // For example, given T = std::tuple<const A&, B*>, RawConverter<T>::type = std::tuple<A, B>
+    template <typename Unconverted, typename... Converted>
+    struct RawConverter;
+    template <typename Unconverted, typename... Converted>
+    struct RawConverter<std::tuple<Converted...>, Unconverted> {
+    private:
+        using ElementType = typename std::tuple_element<0, Unconverted>::type;
+        using Decayed = typename std::decay<ElementType>::type;
+        using WithoutPointer = typename std::remove_pointer<Decayed>::type;
+
+    public:
+        using type = typename RawConverter<std::tuple<Converted..., WithoutPointer>,
+                                           typename RemoveFirst<Unconverted>::type>::type;
+    };
+    template <typename... Converted>
+    struct RawConverter<std::tuple<Converted...>, std::tuple<>> {
+        using type = std::tuple<Converted...>;
+    };
+
+    // This provides a simple way to determine whether the indexed element of Args... is a pointer
+    template <size_t I, typename... Args>
+    struct ElementIsPointer {
+    private:
+        using ElementType = typename std::tuple_element<I, std::tuple<Args...>>::type;
+
+    public:
+        static constexpr bool value = std::is_pointer<ElementType>::value;
+    };
+
+    // This class iterates over the parameter types, and if a given parameter is an input
+    // (i.e., is not a pointer), reads the corresponding argument tuple element from the data Parcel
+    template <typename... Params>
+    class InputReader;
+    template <typename... Params>
+    class InputReader<std::tuple<Params...>> {
+    public:
+        explicit InputReader(const char* logTag) : mLogTag(logTag) {}
+
+        // Note that in this case (as opposed to in SafeBpInterface), we iterate using an explicit
+        // index (starting with 0 here) instead of using recursion and stripping the first element.
+        // This is because in SafeBpInterface we aren't actually operating on a real tuple, but are
+        // instead just using a tuple as a convenient container for variadic types, whereas here we
+        // can't modify the argument tuple without causing unnecessary copies or moves of the data
+        // contained therein.
+        template <typename RawTuple>
+        status_t readInputs(const Parcel& data, RawTuple* args) {
+            return dispatchArg<0>(data, args);
+        }
+
+    private:
+        const char* const mLogTag;
+
+        template <std::size_t I, typename RawTuple>
+        typename std::enable_if<!ElementIsPointer<I, Params...>::value, status_t>::type readIfInput(
+                const Parcel& data, RawTuple* args) {
+            return SafeInterface::ParcelHandler{mLogTag}.read(data, &std::get<I>(*args));
+        }
+        template <std::size_t I, typename RawTuple>
+        typename std::enable_if<ElementIsPointer<I, Params...>::value, status_t>::type readIfInput(
+                const Parcel& /*data*/, RawTuple* /*args*/) {
+            return NO_ERROR;
+        }
+
+        // Recursively iterate through the arguments
+        template <std::size_t I, typename RawTuple>
+        typename std::enable_if<(I < sizeof...(Params)), status_t>::type dispatchArg(
+                const Parcel& data, RawTuple* args) {
+            status_t error = readIfInput<I>(data, args);
+            if (CC_UNLIKELY(error != NO_ERROR)) {
+                // A message will have been logged in read
+                return error;
+            }
+            return dispatchArg<I + 1>(data, args);
+        }
+        template <std::size_t I, typename RawTuple>
+        typename std::enable_if<(I >= sizeof...(Params)), status_t>::type dispatchArg(
+                const Parcel& /*data*/, RawTuple* /*args*/) {
+            return NO_ERROR;
+        }
+    };
+
+    // getForCall uses the types of the parameters to determine whether a given element of the
+    // argument tuple is an input, which should be passed directly into the call, or an output, for
+    // which its address should be passed into the call
+    template <size_t I, typename RawTuple, typename... Params>
+    static typename std::enable_if<
+            ElementIsPointer<I, Params...>::value,
+            typename std::tuple_element<I, std::tuple<Params...>>::type>::type
+    getForCall(RawTuple* args) {
+        return &std::get<I>(*args);
+    }
+    template <size_t I, typename RawTuple, typename... Params>
+    static typename std::enable_if<
+            !ElementIsPointer<I, Params...>::value,
+            typename std::tuple_element<I, std::tuple<Params...>>::type>::type&
+    getForCall(RawTuple* args) {
+        return std::get<I>(*args);
+    }
+
+    // This template class uses std::index_sequence and parameter pack expansion to call the given
+    // method using the elements of the argument tuple (after those arguments are passed through
+    // getForCall to get addresses instead of values for output arguments)
+    template <typename... Params>
+    struct MethodCaller;
+    template <typename... Params>
+    struct MethodCaller<std::tuple<Params...>> {
+    public:
+        // The calls through these to the helper methods are necessary to generate the
+        // std::index_sequences used to unpack the argument tuple into the method call
+        template <typename Class, typename MemberFunction, typename RawTuple>
+        static status_t call(Class* instance, MemberFunction function, RawTuple* args) {
+            return callHelper(instance, function, args, std::index_sequence_for<Params...>{});
+        }
+        template <typename Class, typename MemberFunction, typename RawTuple>
+        static void callVoid(Class* instance, MemberFunction function, RawTuple* args) {
+            callVoidHelper(instance, function, args, std::index_sequence_for<Params...>{});
+        }
+
+    private:
+        template <typename Class, typename MemberFunction, typename RawTuple, std::size_t... I>
+        static status_t callHelper(Class* instance, MemberFunction function, RawTuple* args,
+                                   std::index_sequence<I...> /*unused*/) {
+            return (instance->*function)(getForCall<I, RawTuple, Params...>(args)...);
+        }
+        template <typename Class, typename MemberFunction, typename RawTuple, std::size_t... I>
+        static void callVoidHelper(Class* instance, MemberFunction function, RawTuple* args,
+                                   std::index_sequence<I...> /*unused*/) {
+            (instance->*function)(getForCall<I, RawTuple, Params...>(args)...);
+        }
+    };
+
+    // This class iterates over the parameter types, and if a given parameter is an output
+    // (i.e., is a pointer), writes the corresponding argument tuple element into the reply Parcel
+    template <typename... Params>
+    struct OutputWriter;
+    template <typename... Params>
+    struct OutputWriter<std::tuple<Params...>> {
+    public:
+        explicit OutputWriter(const char* logTag) : mLogTag(logTag) {}
+
+        // See the note on InputReader::readInputs for why this differs from the arguably simpler
+        // RemoveFirst approach in SafeBpInterface
+        template <typename RawTuple>
+        status_t writeOutputs(Parcel* reply, RawTuple* args) {
+            return dispatchArg<0>(reply, args);
+        }
+
+    private:
+        const char* const mLogTag;
+
+        template <std::size_t I, typename RawTuple>
+        typename std::enable_if<ElementIsPointer<I, Params...>::value, status_t>::type
+        writeIfOutput(Parcel* reply, RawTuple* args) {
+            return SafeInterface::ParcelHandler{mLogTag}.write(reply, std::get<I>(*args));
+        }
+        template <std::size_t I, typename RawTuple>
+        typename std::enable_if<!ElementIsPointer<I, Params...>::value, status_t>::type
+        writeIfOutput(Parcel* /*reply*/, RawTuple* /*args*/) {
+            return NO_ERROR;
+        }
+
+        // Recursively iterate through the arguments
+        template <std::size_t I, typename RawTuple>
+        typename std::enable_if<(I < sizeof...(Params)), status_t>::type dispatchArg(
+                Parcel* reply, RawTuple* args) {
+            status_t error = writeIfOutput<I>(reply, args);
+            if (CC_UNLIKELY(error != NO_ERROR)) {
+                // A message will have been logged in read
+                return error;
+            }
+            return dispatchArg<I + 1>(reply, args);
+        }
+        template <std::size_t I, typename RawTuple>
+        typename std::enable_if<(I >= sizeof...(Params)), status_t>::type dispatchArg(
+                Parcel* /*reply*/, RawTuple* /*args*/) {
+            return NO_ERROR;
+        }
+    };
+};
+
+} // namespace android
diff --git a/libs/binder/include/binder/Status.h b/libs/binder/include/binder/Status.h
new file mode 100644
index 0000000..c3738f8
--- /dev/null
+++ b/libs/binder/include/binder/Status.h
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_BINDER_STATUS_H
+#define ANDROID_BINDER_STATUS_H
+
+#include <cstdint>
+#include <sstream>
+
+#include <binder/Parcel.h>
+#include <utils/String8.h>
+
+namespace android {
+namespace binder {
+
+// An object similar in function to a status_t except that it understands
+// how exceptions are encoded in the prefix of a Parcel. Used like:
+//
+//     Parcel data;
+//     Parcel reply;
+//     status_t status;
+//     binder::Status remote_exception;
+//     if ((status = data.writeInterfaceToken(interface_descriptor)) != OK ||
+//         (status = data.writeInt32(function_input)) != OK) {
+//         // We failed to write into the memory of our local parcel?
+//     }
+//     if ((status = remote()->transact(transaction, data, &reply)) != OK) {
+//        // Something has gone wrong in the binder driver or libbinder.
+//     }
+//     if ((status = remote_exception.readFromParcel(reply)) != OK) {
+//         // The remote didn't correctly write the exception header to the
+//         // reply.
+//     }
+//     if (!remote_exception.isOk()) {
+//         // The transaction went through correctly, but the remote reported an
+//         // exception during handling.
+//     }
+//
+class Status final {
+public:
+    // Keep the exception codes in sync with android/os/Parcel.java.
+    enum Exception {
+        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 Java specific; see Parcel.java.
+        EX_HAS_REPLY_HEADER = -128,
+        // This is special, and indicates to C++ binder proxies that the
+        // transaction has failed at a low level.
+        EX_TRANSACTION_FAILED = -129,
+    };
+
+    // A more readable alias for the default constructor.
+    static Status ok();
+
+    // Authors should explicitly pick whether their integer is:
+    //  - an exception code (EX_* above)
+    //  - service specific error code
+    //  - status_t
+    //
+    //  Prefer a generic exception code when possible, then a service specific
+    //  code, and finally a status_t for low level failures or legacy support.
+    //  Exception codes and service specific errors map to nicer exceptions for
+    //  Java clients.
+    static Status fromExceptionCode(int32_t exceptionCode);
+    static Status fromExceptionCode(int32_t exceptionCode,
+                                    const String8& message);
+    static Status fromExceptionCode(int32_t exceptionCode,
+                                    const char* message);
+
+    static Status fromServiceSpecificError(int32_t serviceSpecificErrorCode);
+    static Status fromServiceSpecificError(int32_t serviceSpecificErrorCode,
+                                           const String8& message);
+    static Status fromServiceSpecificError(int32_t serviceSpecificErrorCode,
+                                           const char* message);
+
+    static Status fromStatusT(status_t status);
+
+    Status() = default;
+    ~Status() = default;
+
+    // Status objects are copyable and contain just simple data.
+    Status(const Status& status) = default;
+    Status(Status&& status) = default;
+    Status& operator=(const Status& status) = default;
+
+    // Bear in mind that if the client or service is a Java endpoint, this
+    // is not the logic which will provide/interpret the data here.
+    status_t readFromParcel(const Parcel& parcel);
+    status_t writeToParcel(Parcel* parcel) const;
+
+    // Set one of the pre-defined exception types defined above.
+    void setException(int32_t ex, const String8& message);
+    // Set a service specific exception with error code.
+    void setServiceSpecificError(int32_t errorCode, const String8& message);
+    // Setting a |status| != OK causes generated code to return |status|
+    // from Binder transactions, rather than writing an exception into the
+    // reply Parcel.  This is the least preferable way of reporting errors.
+    void setFromStatusT(status_t status);
+
+    // Get information about an exception.
+    int32_t exceptionCode() const  { return mException; }
+    const String8& exceptionMessage() const { return mMessage; }
+    status_t transactionError() const {
+        return mException == EX_TRANSACTION_FAILED ? mErrorCode : OK;
+    }
+    int32_t serviceSpecificErrorCode() const {
+        return mException == EX_SERVICE_SPECIFIC ? mErrorCode : 0;
+    }
+
+    bool isOk() const { return mException == EX_NONE; }
+
+    // For logging.
+    String8 toString8() const;
+
+private:
+    Status(int32_t exceptionCode, int32_t errorCode);
+    Status(int32_t exceptionCode, int32_t errorCode, const String8& message);
+
+    // If |mException| == EX_TRANSACTION_FAILED, generated code will return
+    // |mErrorCode| as the result of the transaction rather than write an
+    // exception to the reply parcel.
+    //
+    // Otherwise, we always write |mException| to the parcel.
+    // If |mException| !=  EX_NONE, we write |mMessage| as well.
+    // If |mException| == EX_SERVICE_SPECIFIC we write |mErrorCode| as well.
+    int32_t mException = EX_NONE;
+    int32_t mErrorCode = 0;
+    String8 mMessage;
+};  // class Status
+
+// For gtest output logging
+std::stringstream& operator<< (std::stringstream& stream, const Status& s);
+
+}  // namespace binder
+}  // namespace android
+
+#endif // ANDROID_BINDER_STATUS_H
diff --git a/libs/binder/include/binder/TextOutput.h b/libs/binder/include/binder/TextOutput.h
new file mode 100644
index 0000000..851e01f
--- /dev/null
+++ b/libs/binder/include/binder/TextOutput.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2006 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_TEXTOUTPUT_H
+#define ANDROID_TEXTOUTPUT_H
+
+#include <utils/Errors.h>
+#include <utils/String8.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <sstream>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class TextOutput
+{
+public:
+                        TextOutput();
+    virtual             ~TextOutput();
+    
+    virtual status_t    print(const char* txt, size_t len) = 0;
+    virtual void        moveIndent(int delta) = 0;
+    
+    class Bundle {
+    public:
+        inline Bundle(TextOutput& to) : mTO(to) { to.pushBundle(); }
+        inline ~Bundle() { mTO.popBundle(); }
+    private:
+        TextOutput&     mTO;
+    };
+    
+    virtual void        pushBundle() = 0;
+    virtual void        popBundle() = 0;
+};
+
+// ---------------------------------------------------------------------------
+
+// Text output stream for printing to the log (via utils/Log.h).
+extern TextOutput& alog;
+
+// Text output stream for printing to stdout.
+extern TextOutput& aout;
+
+// Text output stream for printing to stderr.
+extern TextOutput& aerr;
+
+typedef TextOutput& (*TextOutputManipFunc)(TextOutput&);
+
+TextOutput& endl(TextOutput& to);
+TextOutput& indent(TextOutput& to);
+TextOutput& dedent(TextOutput& to);
+
+template<typename T>
+TextOutput& operator<<(TextOutput& to, const T& val)
+{
+    std::stringstream strbuf;
+    strbuf << val;
+    std::string str = strbuf.str();
+    to.print(str.c_str(), str.size());
+    return to;
+}
+
+TextOutput& operator<<(TextOutput& to, TextOutputManipFunc func);
+
+class TypeCode
+{
+public:
+    inline TypeCode(uint32_t code);
+    inline ~TypeCode();
+
+    inline uint32_t typeCode() const;
+
+private:
+    uint32_t mCode;
+};
+
+TextOutput& operator<<(TextOutput& to, const TypeCode& val);
+
+class HexDump
+{
+public:
+    HexDump(const void *buf, size_t size, size_t bytesPerLine=16);
+    inline ~HexDump();
+    
+    inline HexDump& setBytesPerLine(size_t bytesPerLine);
+    inline HexDump& setSingleLineCutoff(int32_t bytes);
+    inline HexDump& setAlignment(size_t alignment);
+    inline HexDump& setCArrayStyle(bool enabled);
+    
+    inline const void* buffer() const;
+    inline size_t size() const;
+    inline size_t bytesPerLine() const;
+    inline int32_t singleLineCutoff() const;
+    inline size_t alignment() const;
+    inline bool carrayStyle() const;
+
+private:
+    const void* mBuffer;
+    size_t mSize;
+    size_t mBytesPerLine;
+    int32_t mSingleLineCutoff;
+    size_t mAlignment;
+    bool mCArrayStyle;
+};
+
+TextOutput& operator<<(TextOutput& to, const HexDump& val);
+inline TextOutput& operator<<(TextOutput& to,
+                              decltype(std::endl<char,
+                                       std::char_traits<char>>)
+                              /*val*/) {
+    endl(to);
+    return to;
+}
+
+inline TextOutput& operator<<(TextOutput& to, const char &c)
+{
+    to.print(&c, 1);
+    return to;
+}
+
+inline TextOutput& operator<<(TextOutput& to, const bool &val)
+{
+    if (val) to.print("true", 4);
+    else to.print("false", 5);
+    return to;
+}
+
+inline TextOutput& operator<<(TextOutput& to, const String16& val)
+{
+    to << String8(val).string();
+    return to;
+}
+
+// ---------------------------------------------------------------------------
+// No user servicable parts below.
+
+inline TextOutput& endl(TextOutput& to)
+{
+    to.print("\n", 1);
+    return to;
+}
+
+inline TextOutput& indent(TextOutput& to)
+{
+    to.moveIndent(1);
+    return to;
+}
+
+inline TextOutput& dedent(TextOutput& to)
+{
+    to.moveIndent(-1);
+    return to;
+}
+
+inline TextOutput& operator<<(TextOutput& to, TextOutputManipFunc func)
+{
+    return (*func)(to);
+}
+
+inline TypeCode::TypeCode(uint32_t code) : mCode(code) { }
+inline TypeCode::~TypeCode() { }
+inline uint32_t TypeCode::typeCode() const { return mCode; }
+
+inline HexDump::~HexDump() { }
+
+inline HexDump& HexDump::setBytesPerLine(size_t bytesPerLine) {
+    mBytesPerLine = bytesPerLine; return *this;
+}
+inline HexDump& HexDump::setSingleLineCutoff(int32_t bytes) {
+    mSingleLineCutoff = bytes; return *this;
+}
+inline HexDump& HexDump::setAlignment(size_t alignment) {
+    mAlignment = alignment; return *this;
+}
+inline HexDump& HexDump::setCArrayStyle(bool enabled) {
+    mCArrayStyle = enabled; return *this;
+}
+
+inline const void* HexDump::buffer() const { return mBuffer; }
+inline size_t HexDump::size() const { return mSize; }
+inline size_t HexDump::bytesPerLine() const { return mBytesPerLine; }
+inline int32_t HexDump::singleLineCutoff() const { return mSingleLineCutoff; }
+inline size_t HexDump::alignment() const { return mAlignment; }
+inline bool HexDump::carrayStyle() const { return mCArrayStyle; }
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_TEXTOUTPUT_H
diff --git a/libs/binder/include/binder/Value.h b/libs/binder/include/binder/Value.h
new file mode 100644
index 0000000..4dee3d8
--- /dev/null
+++ b/libs/binder/include/binder/Value.h
@@ -0,0 +1,186 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_VALUE_H
+#define ANDROID_VALUE_H
+
+#include <stdint.h>
+#include <map>
+#include <set>
+#include <vector>
+#include <string>
+
+#include <binder/Parcelable.h>
+#include <binder/PersistableBundle.h>
+#include <binder/Map.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class Parcel;
+
+namespace binder {
+
+/**
+ * A limited C++ generic type. The purpose of this class is to allow C++
+ * programs to make use of (or implement) Binder interfaces which make use
+ * the Java "Object" generic type (either via the use of the Map type or
+ * some other mechanism).
+ *
+ * This class only supports a limited set of types, but additional types
+ * may be easily added to this class in the future as needed---without
+ * breaking binary compatability.
+ *
+ * This class was written in such a way as to help avoid type errors by
+ * giving each type their own explicity-named accessor methods (rather than
+ * overloaded methods).
+ *
+ * When reading or writing this class to a Parcel, use the `writeValue()`
+ * and `readValue()` methods.
+ */
+class Value {
+public:
+    Value();
+    virtual ~Value();
+
+    Value& swap(Value &);
+
+    bool empty() const;
+
+    void clear();
+
+#ifdef LIBBINDER_VALUE_SUPPORTS_TYPE_INFO
+    const std::type_info& type() const;
+#endif
+
+    int32_t parcelType() const;
+
+    bool operator==(const Value& rhs) const;
+    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& operator=(const Value& rhs);
+    Value& operator=(const int8_t& rhs);
+    Value& operator=(const bool& rhs);
+    Value& operator=(const int32_t& rhs);
+    Value& operator=(const int64_t& rhs);
+    Value& operator=(const double& rhs);
+    Value& operator=(const String16& rhs);
+    Value& operator=(const std::vector<bool>& rhs);
+    Value& operator=(const std::vector<uint8_t>& rhs);
+    Value& operator=(const std::vector<int32_t>& rhs);
+    Value& operator=(const std::vector<int64_t>& rhs);
+    Value& operator=(const std::vector<double>& rhs);
+    Value& operator=(const std::vector<String16>& rhs);
+    Value& operator=(const os::PersistableBundle& rhs);
+    Value& operator=(const binder::Map& rhs);
+
+    void putBoolean(const bool& value);
+    void putByte(const int8_t& value);
+    void putInt(const int32_t& value);
+    void putLong(const int64_t& value);
+    void putDouble(const double& value);
+    void putString(const String16& value);
+    void putBooleanVector(const std::vector<bool>& value);
+    void putByteVector(const std::vector<uint8_t>& value);
+    void putIntVector(const std::vector<int32_t>& value);
+    void putLongVector(const std::vector<int64_t>& value);
+    void putDoubleVector(const std::vector<double>& value);
+    void putStringVector(const std::vector<String16>& value);
+    void putPersistableBundle(const os::PersistableBundle& value);
+    void putMap(const binder::Map& value);
+
+    bool getBoolean(bool* out) const;
+    bool getByte(int8_t* out) const;
+    bool getInt(int32_t* out) const;
+    bool getLong(int64_t* out) const;
+    bool getDouble(double* out) const;
+    bool getString(String16* out) const;
+    bool getBooleanVector(std::vector<bool>* out) const;
+    bool getByteVector(std::vector<uint8_t>* out) const;
+    bool getIntVector(std::vector<int32_t>* out) const;
+    bool getLongVector(std::vector<int64_t>* out) const;
+    bool getDoubleVector(std::vector<double>* out) const;
+    bool getStringVector(std::vector<String16>* out) const;
+    bool getPersistableBundle(os::PersistableBundle* out) const;
+    bool getMap(binder::Map* out) const;
+
+    bool isBoolean() const;
+    bool isByte() const;
+    bool isInt() const;
+    bool isLong() const;
+    bool isDouble() const;
+    bool isString() const;
+    bool isBooleanVector() const;
+    bool isByteVector() const;
+    bool isIntVector() const;
+    bool isLongVector() const;
+    bool isDoubleVector() const;
+    bool isStringVector() const;
+    bool isPersistableBundle() const;
+    bool isMap() const;
+
+    // String Convenience Adapters
+    // ---------------------------
+
+    Value(const String8& value):               Value(String16(value)) { }
+    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); }
+    Value& operator=(const ::std::string& rhs) { return *this = String8(rhs.c_str()); }
+    bool getString(String8* out) const;
+    bool getString(::std::string* out) const;
+
+private:
+
+    // This allows ::android::Parcel to call the two methods below.
+    friend class ::android::Parcel;
+
+    // This is called by ::android::Parcel::writeValue()
+    status_t writeToParcel(Parcel* parcel) const;
+
+    // This is called by ::android::Parcel::readValue()
+    status_t readFromParcel(const Parcel* parcel);
+
+    template<typename T> class Content;
+    class ContentBase;
+
+    ContentBase* mContent;
+};
+
+}  // namespace binder
+
+}  // namespace android
+
+#endif  // ANDROID_VALUE_H
diff --git a/libs/binder/include/private/binder/ParcelValTypes.h b/libs/binder/include/private/binder/ParcelValTypes.h
new file mode 100644
index 0000000..666d22a
--- /dev/null
+++ b/libs/binder/include/private/binder/ParcelValTypes.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+namespace android {
+namespace binder {
+
+// Keep in sync with frameworks/base/core/java/android/os/Parcel.java.
+enum {
+    VAL_NULL = -1,
+    VAL_STRING = 0,
+    VAL_INTEGER = 1,
+    VAL_MAP = 2,
+    VAL_BUNDLE = 3,
+    VAL_PARCELABLE = 4,
+    VAL_SHORT = 5,
+    VAL_LONG = 6,
+    VAL_DOUBLE = 8,
+    VAL_BOOLEAN = 9,
+    VAL_BYTEARRAY = 13,
+    VAL_STRINGARRAY = 14,
+    VAL_IBINDER = 15,
+    VAL_INTARRAY = 18,
+    VAL_LONGARRAY = 19,
+    VAL_BYTE = 20,
+    VAL_SERIALIZABLE = 21,
+    VAL_BOOLEANARRAY = 23,
+    VAL_PERSISTABLEBUNDLE = 25,
+    VAL_DOUBLEARRAY = 28,
+};
+
+} // namespace binder
+} // namespace android
diff --git a/libs/binder/include/private/binder/Static.h b/libs/binder/include/private/binder/Static.h
new file mode 100644
index 0000000..3d10456
--- /dev/null
+++ b/libs/binder/include/private/binder/Static.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+// All static variables go here, to control initialization and
+// destruction order in the library.
+
+#include <utils/threads.h>
+
+#include <binder/IBinder.h>
+#include <binder/ProcessState.h>
+#include <binder/IPermissionController.h>
+#include <binder/IServiceManager.h>
+
+namespace android {
+
+// For TextStream.cpp
+extern Vector<int32_t> gTextBuffers;
+
+// For ProcessState.cpp
+extern Mutex gProcessMutex;
+extern sp<ProcessState> gProcess;
+
+// For IServiceManager.cpp
+extern Mutex gDefaultServiceManagerLock;
+extern sp<IServiceManager> gDefaultServiceManager;
+extern sp<IPermissionController> gPermissionController;
+
+}   // namespace android
diff --git a/libs/binder/include/private/binder/binder_module.h b/libs/binder/include/private/binder/binder_module.h
new file mode 100644
index 0000000..2f11622
--- /dev/null
+++ b/libs/binder/include/private/binder/binder_module.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2008 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_MODULE_H_
+#define _BINDER_MODULE_H_
+
+#ifdef __cplusplus
+namespace android {
+#endif
+
+/* obtain structures and constants from the kernel header */
+
+#include <sys/ioctl.h>
+#include <linux/android/binder.h>
+
+#ifdef __cplusplus
+}   // namespace android
+#endif
+
+#endif // _BINDER_MODULE_H_
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
new file mode 100644
index 0000000..3071408
--- /dev/null
+++ b/libs/binder/tests/Android.bp
@@ -0,0 +1,131 @@
+//
+// 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.
+//
+
+cc_test {
+    name: "binderDriverInterfaceTest_IPC_32",
+    srcs: ["binderDriverInterfaceTest.cpp"],
+    compile_multilib: "32",
+    cflags: ["-DBINDER_IPC_32BIT=1"],
+}
+
+cc_test {
+    product_variables: {
+        binder32bit: {
+            cflags: ["-DBINDER_IPC_32BIT=1"],
+        },
+    },
+
+    name: "binderDriverInterfaceTest",
+    srcs: ["binderDriverInterfaceTest.cpp"],
+}
+
+cc_test {
+    name: "binderValueTypeTest",
+    srcs: ["binderValueTypeTest.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libutils",
+    ],
+}
+
+cc_test {
+    name: "binderLibTest_IPC_32",
+    srcs: ["binderLibTest.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libutils",
+    ],
+    compile_multilib: "32",
+    cflags: ["-DBINDER_IPC_32BIT=1"],
+}
+
+cc_test {
+    product_variables: {
+        binder32bit: {
+            cflags: ["-DBINDER_IPC_32BIT=1"],
+        },
+    },
+
+    name: "binderLibTest",
+    srcs: ["binderLibTest.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libutils",
+    ],
+}
+
+cc_test {
+    name: "binderThroughputTest",
+    srcs: ["binderThroughputTest.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libutils",
+    ],
+    clang: true,
+    cflags: [
+        "-g",
+        "-Wall",
+        "-Werror",
+        "-Wno-missing-field-initializers",
+        "-Wno-sign-compare",
+        "-O3",
+    ],
+}
+
+cc_test {
+    name: "binderTextOutputTest",
+    srcs: ["binderTextOutputTest.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libutils",
+        "libbase",
+    ],
+}
+
+cc_test {
+    name: "schd-dbg",
+    srcs: ["schd-dbg.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libutils",
+        "libbase",
+    ],
+}
+
+cc_test {
+    name: "binderSafeInterfaceTest",
+    srcs: ["binderSafeInterfaceTest.cpp"],
+
+    cppflags: [
+        "-Werror",
+        "-Weverything",
+        "-Wno-c++98-compat",
+        "-Wno-c++98-compat-pedantic",
+        "-Wno-global-constructors",
+        "-Wno-padded",
+        "-Wno-weak-vtables",
+    ],
+
+    cpp_std: "experimental",
+    gnu_extensions: false,
+
+    shared_libs: [
+        "libbinder",
+        "libcutils",
+        "liblog",
+        "libutils",
+    ],
+}
diff --git a/libs/binder/tests/Android.mk b/libs/binder/tests/Android.mk
deleted file mode 100644
index a40523d..0000000
--- a/libs/binder/tests/Android.mk
+++ /dev/null
@@ -1,42 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-ifneq ($(TARGET_USES_64_BIT_BINDER),true)
-ifneq ($(TARGET_IS_64_BIT),true)
-LOCAL_CFLAGS += -DBINDER_IPC_32BIT=1
-endif
-endif
-
-LOCAL_MODULE := binderDriverInterfaceTest
-LOCAL_SRC_FILES := binderDriverInterfaceTest.cpp
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := binderLibTest
-LOCAL_SRC_FILES := binderLibTest.cpp
-LOCAL_SHARED_LIBRARIES := libbinder libutils
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := binderThroughputTest
-LOCAL_SRC_FILES := binderThroughputTest.cpp
-LOCAL_SHARED_LIBRARIES := libbinder libutils
-LOCAL_CLANG := true
-LOCAL_CFLAGS += -g -Wall -Werror -std=c++11 -Wno-missing-field-initializers -Wno-sign-compare -O3
-include $(BUILD_NATIVE_TEST)
diff --git a/libs/binder/tests/binderDriverInterfaceTest.cpp b/libs/binder/tests/binderDriverInterfaceTest.cpp
index 0277550..ff5912f 100644
--- a/libs/binder/tests/binderDriverInterfaceTest.cpp
+++ b/libs/binder/tests/binderDriverInterfaceTest.cpp
@@ -20,7 +20,7 @@
 #include <stdlib.h>
 
 #include <gtest/gtest.h>
-#include <linux/binder.h>
+#include <linux/android/binder.h>
 #include <binder/IBinder.h>
 #include <sys/mman.h>
 #include <poll.h>
@@ -229,7 +229,9 @@
             .sender_euid = 0,
             .data_size = 0,
             .offsets_size = 0,
-            .data = {0, 0},
+            .data = {
+                .ptr = {0, 0},
+            },
         },
     };
     struct {
@@ -350,4 +352,3 @@
 
     return RUN_ALL_TESTS();
 }
-
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 3df3acf..a04869a 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -34,6 +34,7 @@
 
 static testing::Environment* binder_env;
 static char *binderservername;
+static char *binderserversuffix;
 static char binderserverarg[] = "--binderserver";
 
 static String16 binderLibTestServiceName = String16("test.binderLib");
@@ -44,6 +45,7 @@
     BINDER_LIB_TEST_ADD_SERVER,
     BINDER_LIB_TEST_CALL_BACK,
     BINDER_LIB_TEST_NOP_CALL_BACK,
+    BINDER_LIB_TEST_GET_SELF_TRANSACTION,
     BINDER_LIB_TEST_GET_ID_TRANSACTION,
     BINDER_LIB_TEST_INDIRECT_TRANSACTION,
     BINDER_LIB_TEST_SET_ERROR_TRANSACTION,
@@ -55,6 +57,7 @@
     BINDER_LIB_TEST_EXIT_TRANSACTION,
     BINDER_LIB_TEST_DELAYED_EXIT_TRANSACTION,
     BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION,
+    BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION,
 };
 
 pid_t start_server_process(int arg2)
@@ -70,6 +73,7 @@
         binderserverarg,
         stri,
         strpipefd1,
+        binderserversuffix,
         NULL
     };
 
@@ -252,14 +256,10 @@
             int ret;
             pthread_mutex_lock(&m_waitMutex);
             if (!m_eventTriggered) {
-#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)
-                pthread_cond_timeout_np(&m_waitCond, &m_waitMutex, timeout_s * 1000);
-#else
                 struct timespec ts;
                 clock_gettime(CLOCK_REALTIME, &ts);
                 ts.tv_sec += timeout_s;
                 pthread_cond_timedwait(&m_waitCond, &m_waitMutex, &ts);
-#endif
             }
             ret = m_eventTriggered ? NO_ERROR : TIMED_OUT;
             pthread_mutex_unlock(&m_waitMutex);
@@ -391,7 +391,7 @@
 
     ret = reply.readInt32(&count);
     ASSERT_EQ(NO_ERROR, ret);
-    EXPECT_EQ(ARRAY_SIZE(serverId), count);
+    EXPECT_EQ(ARRAY_SIZE(serverId), (size_t)count);
 
     for (size_t i = 0; i < (size_t)count; i++) {
         BinderLibTestBundle replyi(&reply);
@@ -441,7 +441,7 @@
 
     ret = reply.readInt32(&count);
     ASSERT_EQ(NO_ERROR, ret);
-    EXPECT_EQ(ARRAY_SIZE(serverId), count);
+    EXPECT_EQ(ARRAY_SIZE(serverId), (size_t)count);
 
     for (size_t i = 0; i < (size_t)count; i++) {
         int32_t counti;
@@ -633,7 +633,7 @@
     }
 
     ret = read(pipefd[0], buf, sizeof(buf));
-    EXPECT_EQ(sizeof(buf), ret);
+    EXPECT_EQ(sizeof(buf), (size_t)ret);
     EXPECT_EQ(write_value, buf[0]);
 
     waitForReadData(pipefd[0], 5000); /* wait for other proccess to close pipe */
@@ -672,6 +672,62 @@
     EXPECT_GE(ret, 0);
 }
 
+TEST_F(BinderLibTest, CheckHandleZeroBinderHighBitsZeroCookie) {
+    status_t ret;
+    Parcel data, reply;
+
+    ret = m_server->transact(BINDER_LIB_TEST_GET_SELF_TRANSACTION, data, &reply);
+    EXPECT_EQ(NO_ERROR, ret);
+
+    const flat_binder_object *fb = reply.readObject(false);
+    ASSERT_TRUE(fb != NULL);
+    EXPECT_EQ(BINDER_TYPE_HANDLE, fb->type);
+    EXPECT_EQ(m_server, ProcessState::self()->getStrongProxyForHandle(fb->handle));
+    EXPECT_EQ((binder_uintptr_t)0, fb->cookie);
+    EXPECT_EQ((uint64_t)0, (uint64_t)fb->binder >> 32);
+}
+
+TEST_F(BinderLibTest, FreedBinder) {
+    status_t ret;
+
+    sp<IBinder> server = addServer();
+    ASSERT_TRUE(server != NULL);
+
+    __u32 freedHandle;
+    wp<IBinder> keepFreedBinder;
+    {
+        Parcel data, reply;
+        data.writeBool(false); /* request weak reference */
+        ret = server->transact(BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION, data, &reply);
+        ASSERT_EQ(NO_ERROR, ret);
+        struct flat_binder_object *freed = (struct flat_binder_object *)(reply.data());
+        freedHandle = freed->handle;
+        /* Add a weak ref to the freed binder so the driver does not
+         * delete its reference to it - otherwise the transaction
+         * fails regardless of whether the driver is fixed.
+         */
+        keepFreedBinder = reply.readWeakBinder();
+    }
+    {
+        Parcel data, reply;
+        data.writeStrongBinder(server);
+        /* Replace original handle with handle to the freed binder */
+        struct flat_binder_object *strong = (struct flat_binder_object *)(data.data());
+        __u32 oldHandle = strong->handle;
+        strong->handle = freedHandle;
+        ret = server->transact(BINDER_LIB_TEST_ADD_STRONG_REF_TRANSACTION, data, &reply);
+        /* Returns DEAD_OBJECT (-32) if target crashes and
+         * FAILED_TRANSACTION if the driver rejects the invalid
+         * object.
+         */
+        EXPECT_EQ((status_t)FAILED_TRANSACTION, ret);
+        /* Restore original handle so parcel destructor does not use
+         * the wrong handle.
+         */
+        strong->handle = oldHandle;
+    }
+}
+
 class BinderLibTestService : public BBinder
 {
     public:
@@ -739,14 +795,10 @@
                 }
                 if (ret > 0) {
                     if (m_serverStartRequested) {
-#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)
-                        ret = pthread_cond_timeout_np(&m_serverWaitCond, &m_serverWaitMutex, 5000);
-#else
                         struct timespec ts;
                         clock_gettime(CLOCK_REALTIME, &ts);
                         ts.tv_sec += 5;
                         ret = pthread_cond_timedwait(&m_serverWaitCond, &m_serverWaitMutex, &ts);
-#endif
                     }
                     if (m_serverStartRequested) {
                         m_serverStartRequested = false;
@@ -777,6 +829,9 @@
                 binder->transact(BINDER_LIB_TEST_CALL_BACK, data2, &reply2);
                 return NO_ERROR;
             }
+            case BINDER_LIB_TEST_GET_SELF_TRANSACTION:
+                reply->writeStrongBinder(this);
+                return NO_ERROR;
             case BINDER_LIB_TEST_GET_ID_TRANSACTION:
                 reply->writeInt32(m_id);
                 return NO_ERROR;
@@ -890,6 +945,16 @@
                 while (wait(NULL) != -1 || errno != ECHILD)
                     ;
                 exit(EXIT_SUCCESS);
+            case BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION: {
+                bool strongRef = data.readBool();
+                sp<IBinder> binder = new BBinder();
+                if (strongRef) {
+                    reply->writeStrongBinder(binder);
+                } else {
+                    reply->writeWeakBinder(binder);
+                }
+                return NO_ERROR;
+            }
             default:
                 return UNKNOWN_TRANSACTION;
             };
@@ -906,6 +971,8 @@
 
 int run_server(int index, int readypipefd)
 {
+    binderLibTestServiceName += String16(binderserversuffix);
+
     status_t ret;
     sp<IServiceManager> sm = defaultServiceManager();
     {
@@ -936,15 +1003,19 @@
 int main(int argc, char **argv) {
     int ret;
 
-    if (argc == 3 && !strcmp(argv[1], "--servername")) {
+    if (argc == 4 && !strcmp(argv[1], "--servername")) {
         binderservername = argv[2];
     } else {
         binderservername = argv[0];
     }
 
-    if (argc == 4 && !strcmp(argv[1], binderserverarg)) {
+    if (argc == 5 && !strcmp(argv[1], binderserverarg)) {
+        binderserversuffix = argv[4];
         return run_server(atoi(argv[2]), atoi(argv[3]));
     }
+    binderserversuffix = new char[16];
+    snprintf(binderserversuffix, 16, "%d", getpid());
+    binderLibTestServiceName += String16(binderserversuffix);
 
     ::testing::InitGoogleTest(&argc, argv);
     binder_env = AddGlobalTestEnvironment(new BinderLibTestEnv());
diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp
new file mode 100644
index 0000000..6a16e24
--- /dev/null
+++ b/libs/binder/tests/binderSafeInterfaceTest.cpp
@@ -0,0 +1,819 @@
+/*
+ * 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 <binder/SafeInterface.h>
+
+#include <binder/IInterface.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <binder/ProcessState.h>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Weverything"
+#include <gtest/gtest.h>
+#pragma clang diagnostic pop
+
+#include <utils/LightRefBase.h>
+#include <utils/NativeHandle.h>
+
+#include <cutils/native_handle.h>
+
+#include <optional>
+
+#include <sys/eventfd.h>
+
+using namespace std::chrono_literals; // NOLINT - google-build-using-namespace
+
+namespace android {
+namespace tests {
+
+enum class TestEnum : uint32_t {
+    INVALID = 0,
+    INITIAL = 1,
+    FINAL = 2,
+};
+
+// This class serves two purposes:
+//   1) It ensures that the implementation doesn't require copying or moving the data (for
+//      efficiency purposes)
+//   2) It tests that Parcelables can be passed correctly
+class NoCopyNoMove : public Parcelable {
+public:
+    NoCopyNoMove() = default;
+    explicit NoCopyNoMove(int32_t value) : mValue(value) {}
+    ~NoCopyNoMove() override = default;
+
+    // Not copyable
+    NoCopyNoMove(const NoCopyNoMove&) = delete;
+    NoCopyNoMove& operator=(const NoCopyNoMove&) = delete;
+
+    // Not movable
+    NoCopyNoMove(NoCopyNoMove&&) = delete;
+    NoCopyNoMove& operator=(NoCopyNoMove&&) = delete;
+
+    // Parcelable interface
+    status_t writeToParcel(Parcel* parcel) const override { return parcel->writeInt32(mValue); }
+    status_t readFromParcel(const Parcel* parcel) override { return parcel->readInt32(&mValue); }
+
+    int32_t getValue() const { return mValue; }
+    void setValue(int32_t value) { mValue = value; }
+
+private:
+    int32_t mValue = 0;
+    uint8_t mPadding[4] = {}; // Avoids a warning from -Wpadded
+};
+
+struct TestFlattenable : Flattenable<TestFlattenable> {
+    TestFlattenable() = default;
+    explicit TestFlattenable(int32_t v) : value(v) {}
+
+    // Flattenable protocol
+    size_t getFlattenedSize() const { return sizeof(value); }
+    size_t getFdCount() const { return 0; }
+    status_t flatten(void*& buffer, size_t& size, int*& /*fds*/, size_t& /*count*/) const {
+        FlattenableUtils::write(buffer, size, value);
+        return NO_ERROR;
+    }
+    status_t unflatten(void const*& buffer, size_t& size, int const*& /*fds*/, size_t& /*count*/) {
+        FlattenableUtils::read(buffer, size, value);
+        return NO_ERROR;
+    }
+
+    int32_t value = 0;
+};
+
+struct TestLightFlattenable : LightFlattenablePod<TestLightFlattenable> {
+    TestLightFlattenable() = default;
+    explicit TestLightFlattenable(int32_t v) : value(v) {}
+    int32_t value = 0;
+};
+
+// It seems like this should be able to inherit from TestFlattenable (to avoid duplicating code),
+// but the SafeInterface logic can't easily be extended to find an indirect Flattenable<T>
+// base class
+class TestLightRefBaseFlattenable : public Flattenable<TestLightRefBaseFlattenable>,
+                                    public LightRefBase<TestLightRefBaseFlattenable> {
+public:
+    TestLightRefBaseFlattenable() = default;
+    explicit TestLightRefBaseFlattenable(int32_t v) : value(v) {}
+
+    // Flattenable protocol
+    size_t getFlattenedSize() const { return sizeof(value); }
+    size_t getFdCount() const { return 0; }
+    status_t flatten(void*& buffer, size_t& size, int*& /*fds*/, size_t& /*count*/) const {
+        FlattenableUtils::write(buffer, size, value);
+        return NO_ERROR;
+    }
+    status_t unflatten(void const*& buffer, size_t& size, int const*& /*fds*/, size_t& /*count*/) {
+        FlattenableUtils::read(buffer, size, value);
+        return NO_ERROR;
+    }
+
+    int32_t value = 0;
+};
+
+class TestParcelable : public Parcelable {
+public:
+    TestParcelable() = default;
+    explicit TestParcelable(int32_t value) : mValue(value) {}
+    TestParcelable(const TestParcelable& other) : TestParcelable(other.mValue) {}
+    TestParcelable(TestParcelable&& other) : TestParcelable(other.mValue) {}
+
+    // Parcelable interface
+    status_t writeToParcel(Parcel* parcel) const override { return parcel->writeInt32(mValue); }
+    status_t readFromParcel(const Parcel* parcel) override { return parcel->readInt32(&mValue); }
+
+    int32_t getValue() const { return mValue; }
+    void setValue(int32_t value) { mValue = value; }
+
+private:
+    int32_t mValue = 0;
+};
+
+class ExitOnDeath : public IBinder::DeathRecipient {
+public:
+    ~ExitOnDeath() override = default;
+
+    void binderDied(const wp<IBinder>& /*who*/) override {
+        ALOG(LOG_INFO, "ExitOnDeath", "Exiting");
+        exit(0);
+    }
+};
+
+// This callback class is used to test both one-way transactions and that sp<IInterface> can be
+// passed correctly
+class ICallback : public IInterface {
+public:
+    DECLARE_META_INTERFACE(Callback)
+
+    enum class Tag : uint32_t {
+        OnCallback = IBinder::FIRST_CALL_TRANSACTION,
+        Last,
+    };
+
+    virtual void onCallback(int32_t aPlusOne) = 0;
+};
+
+class BpCallback : public SafeBpInterface<ICallback> {
+public:
+    explicit BpCallback(const sp<IBinder>& impl) : SafeBpInterface<ICallback>(impl, getLogTag()) {}
+
+    void onCallback(int32_t aPlusOne) override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        return callRemoteAsync<decltype(&ICallback::onCallback)>(Tag::OnCallback, aPlusOne);
+    }
+
+private:
+    static constexpr const char* getLogTag() { return "BpCallback"; }
+};
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wexit-time-destructors"
+IMPLEMENT_META_INTERFACE(Callback, "android.gfx.tests.ICallback");
+#pragma clang diagnostic pop
+
+class BnCallback : public SafeBnInterface<ICallback> {
+public:
+    BnCallback() : SafeBnInterface("BnCallback") {}
+
+    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                        uint32_t /*flags*/) override {
+        EXPECT_GE(code, IBinder::FIRST_CALL_TRANSACTION);
+        EXPECT_LT(code, static_cast<uint32_t>(ICallback::Tag::Last));
+        ICallback::Tag tag = static_cast<ICallback::Tag>(code);
+        switch (tag) {
+            case ICallback::Tag::OnCallback: {
+                return callLocalAsync(data, reply, &ICallback::onCallback);
+            }
+            case ICallback::Tag::Last:
+                // Should not be possible because of the asserts at the beginning of the method
+                [&]() { FAIL(); }();
+                return UNKNOWN_ERROR;
+        }
+    }
+};
+
+class ISafeInterfaceTest : public IInterface {
+public:
+    DECLARE_META_INTERFACE(SafeInterfaceTest)
+
+    enum class Tag : uint32_t {
+        SetDeathToken = IBinder::FIRST_CALL_TRANSACTION,
+        ReturnsNoMemory,
+        LogicalNot,
+        ModifyEnum,
+        IncrementFlattenable,
+        IncrementLightFlattenable,
+        IncrementLightRefBaseFlattenable,
+        IncrementNativeHandle,
+        IncrementNoCopyNoMove,
+        IncrementParcelableVector,
+        ToUpper,
+        CallMeBack,
+        IncrementInt32,
+        IncrementUint32,
+        IncrementInt64,
+        IncrementUint64,
+        IncrementTwo,
+        Last,
+    };
+
+    // This is primarily so that the remote service dies when the test does, but it also serves to
+    // test the handling of sp<IBinder> and non-const methods
+    virtual status_t setDeathToken(const sp<IBinder>& token) = 0;
+
+    // This is the most basic test since it doesn't require parceling any arguments
+    virtual status_t returnsNoMemory() const = 0;
+
+    // These are ordered according to their corresponding methods in SafeInterface::ParcelHandler
+    virtual status_t logicalNot(bool a, bool* notA) const = 0;
+    virtual status_t modifyEnum(TestEnum a, TestEnum* b) const = 0;
+    virtual status_t increment(const TestFlattenable& a, TestFlattenable* aPlusOne) const = 0;
+    virtual status_t increment(const TestLightFlattenable& a,
+                               TestLightFlattenable* aPlusOne) const = 0;
+    virtual status_t increment(const sp<TestLightRefBaseFlattenable>& a,
+                               sp<TestLightRefBaseFlattenable>* aPlusOne) const = 0;
+    virtual status_t increment(const sp<NativeHandle>& a, sp<NativeHandle>* aPlusOne) const = 0;
+    virtual status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const = 0;
+    virtual status_t increment(const std::vector<TestParcelable>& a,
+                               std::vector<TestParcelable>* aPlusOne) const = 0;
+    virtual status_t toUpper(const String8& str, String8* upperStr) const = 0;
+    // As mentioned above, sp<IBinder> is already tested by setDeathToken
+    virtual void callMeBack(const sp<ICallback>& callback, int32_t a) const = 0;
+    virtual status_t increment(int32_t a, int32_t* aPlusOne) const = 0;
+    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;
+
+    // This tests that input/output parameter interleaving works correctly
+    virtual status_t increment(int32_t a, int32_t* aPlusOne, int32_t b,
+                               int32_t* bPlusOne) const = 0;
+};
+
+class BpSafeInterfaceTest : public SafeBpInterface<ISafeInterfaceTest> {
+public:
+    explicit BpSafeInterfaceTest(const sp<IBinder>& impl)
+          : SafeBpInterface<ISafeInterfaceTest>(impl, getLogTag()) {}
+
+    status_t setDeathToken(const sp<IBinder>& token) override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        return callRemote<decltype(&ISafeInterfaceTest::setDeathToken)>(Tag::SetDeathToken, token);
+    }
+    status_t returnsNoMemory() const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        return callRemote<decltype(&ISafeInterfaceTest::returnsNoMemory)>(Tag::ReturnsNoMemory);
+    }
+    status_t logicalNot(bool a, bool* notA) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        return callRemote<decltype(&ISafeInterfaceTest::logicalNot)>(Tag::LogicalNot, a, notA);
+    }
+    status_t modifyEnum(TestEnum a, TestEnum* b) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        return callRemote<decltype(&ISafeInterfaceTest::modifyEnum)>(Tag::ModifyEnum, a, b);
+    }
+    status_t increment(const TestFlattenable& a, TestFlattenable* aPlusOne) const override {
+        using Signature =
+                status_t (ISafeInterfaceTest::*)(const TestFlattenable&, TestFlattenable*) const;
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        return callRemote<Signature>(Tag::IncrementFlattenable, a, aPlusOne);
+    }
+    status_t increment(const TestLightFlattenable& a,
+                       TestLightFlattenable* aPlusOne) const override {
+        using Signature = status_t (ISafeInterfaceTest::*)(const TestLightFlattenable&,
+                                                           TestLightFlattenable*) const;
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        return callRemote<Signature>(Tag::IncrementLightFlattenable, a, aPlusOne);
+    }
+    status_t increment(const sp<TestLightRefBaseFlattenable>& a,
+                       sp<TestLightRefBaseFlattenable>* aPlusOne) const override {
+        using Signature = status_t (ISafeInterfaceTest::*)(const sp<TestLightRefBaseFlattenable>&,
+                                                           sp<TestLightRefBaseFlattenable>*) const;
+        return callRemote<Signature>(Tag::IncrementLightRefBaseFlattenable, a, aPlusOne);
+    }
+    status_t increment(const sp<NativeHandle>& a, sp<NativeHandle>* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        using Signature =
+                status_t (ISafeInterfaceTest::*)(const sp<NativeHandle>&, sp<NativeHandle>*) const;
+        return callRemote<Signature>(Tag::IncrementNativeHandle, a, aPlusOne);
+    }
+    status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        using Signature = status_t (ISafeInterfaceTest::*)(const NoCopyNoMove& a,
+                                                           NoCopyNoMove* aPlusOne) const;
+        return callRemote<Signature>(Tag::IncrementNoCopyNoMove, a, aPlusOne);
+    }
+    status_t increment(const std::vector<TestParcelable>& a,
+                       std::vector<TestParcelable>* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        using Signature = status_t (ISafeInterfaceTest::*)(const std::vector<TestParcelable>&,
+                                                           std::vector<TestParcelable>*);
+        return callRemote<Signature>(Tag::IncrementParcelableVector, a, aPlusOne);
+    }
+    status_t toUpper(const String8& str, String8* upperStr) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        return callRemote<decltype(&ISafeInterfaceTest::toUpper)>(Tag::ToUpper, str, upperStr);
+    }
+    void callMeBack(const sp<ICallback>& callback, int32_t a) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        return callRemoteAsync<decltype(&ISafeInterfaceTest::callMeBack)>(Tag::CallMeBack, callback,
+                                                                          a);
+    }
+    status_t increment(int32_t a, int32_t* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        using Signature = status_t (ISafeInterfaceTest::*)(int32_t, int32_t*) const;
+        return callRemote<Signature>(Tag::IncrementInt32, a, aPlusOne);
+    }
+    status_t increment(uint32_t a, uint32_t* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        using Signature = status_t (ISafeInterfaceTest::*)(uint32_t, uint32_t*) const;
+        return callRemote<Signature>(Tag::IncrementUint32, a, aPlusOne);
+    }
+    status_t increment(int64_t a, int64_t* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        using Signature = status_t (ISafeInterfaceTest::*)(int64_t, int64_t*) const;
+        return callRemote<Signature>(Tag::IncrementInt64, a, aPlusOne);
+    }
+    status_t increment(uint64_t a, uint64_t* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        using Signature = status_t (ISafeInterfaceTest::*)(uint64_t, uint64_t*) const;
+        return callRemote<Signature>(Tag::IncrementUint64, 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 =
+                status_t (ISafeInterfaceTest::*)(int32_t, int32_t*, int32_t, int32_t*) const;
+        return callRemote<Signature>(Tag::IncrementTwo, a, aPlusOne, b, bPlusOne);
+    }
+
+private:
+    static constexpr const char* getLogTag() { return "BpSafeInterfaceTest"; }
+};
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wexit-time-destructors"
+IMPLEMENT_META_INTERFACE(SafeInterfaceTest, "android.gfx.tests.ISafeInterfaceTest");
+
+static sp<IBinder::DeathRecipient> getDeathRecipient() {
+    static sp<IBinder::DeathRecipient> recipient = new ExitOnDeath;
+    return recipient;
+}
+#pragma clang diagnostic pop
+
+class BnSafeInterfaceTest : public SafeBnInterface<ISafeInterfaceTest> {
+public:
+    BnSafeInterfaceTest() : SafeBnInterface(getLogTag()) {}
+
+    status_t setDeathToken(const sp<IBinder>& token) override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        token->linkToDeath(getDeathRecipient());
+        return NO_ERROR;
+    }
+    status_t returnsNoMemory() const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        return NO_MEMORY;
+    }
+    status_t logicalNot(bool a, bool* notA) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        *notA = !a;
+        return NO_ERROR;
+    }
+    status_t modifyEnum(TestEnum a, TestEnum* b) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        *b = (a == TestEnum::INITIAL) ? TestEnum::FINAL : TestEnum::INVALID;
+        return NO_ERROR;
+    }
+    status_t increment(const TestFlattenable& a, TestFlattenable* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        aPlusOne->value = a.value + 1;
+        return NO_ERROR;
+    }
+    status_t increment(const TestLightFlattenable& a,
+                       TestLightFlattenable* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        aPlusOne->value = a.value + 1;
+        return NO_ERROR;
+    }
+    status_t increment(const sp<TestLightRefBaseFlattenable>& a,
+                       sp<TestLightRefBaseFlattenable>* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        *aPlusOne = new TestLightRefBaseFlattenable(a->value + 1);
+        return NO_ERROR;
+    }
+    status_t increment(const sp<NativeHandle>& a, sp<NativeHandle>* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        native_handle* rawHandle = native_handle_create(1 /*numFds*/, 1 /*numInts*/);
+        if (rawHandle == nullptr) return NO_MEMORY;
+
+        // Copy the fd over directly
+        rawHandle->data[0] = dup(a->handle()->data[0]);
+
+        // Increment the int
+        rawHandle->data[1] = a->handle()->data[1] + 1;
+
+        // This cannot fail, as it is just the sp<NativeHandle> taking responsibility for closing
+        // the native_handle when it goes out of scope
+        *aPlusOne = NativeHandle::create(rawHandle, true);
+        return NO_ERROR;
+    }
+    status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        aPlusOne->setValue(a.getValue() + 1);
+        return NO_ERROR;
+    }
+    status_t increment(const std::vector<TestParcelable>& a,
+                       std::vector<TestParcelable>* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        aPlusOne->resize(a.size());
+        for (size_t i = 0; i < a.size(); ++i) {
+            (*aPlusOne)[i].setValue(a[i].getValue() + 1);
+        }
+        return NO_ERROR;
+    }
+    status_t toUpper(const String8& str, String8* upperStr) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        *upperStr = str;
+        upperStr->toUpper();
+        return NO_ERROR;
+    }
+    void callMeBack(const sp<ICallback>& callback, int32_t a) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        callback->onCallback(a + 1);
+    }
+    status_t increment(int32_t a, int32_t* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        *aPlusOne = a + 1;
+        return NO_ERROR;
+    }
+    status_t increment(uint32_t a, uint32_t* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        *aPlusOne = a + 1;
+        return NO_ERROR;
+    }
+    status_t increment(int64_t a, int64_t* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        *aPlusOne = a + 1;
+        return NO_ERROR;
+    }
+    status_t increment(uint64_t a, uint64_t* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        *aPlusOne = a + 1;
+        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;
+        *bPlusOne = b + 1;
+        return NO_ERROR;
+    }
+
+    // BnInterface
+    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                        uint32_t /*flags*/) override {
+        EXPECT_GE(code, IBinder::FIRST_CALL_TRANSACTION);
+        EXPECT_LT(code, static_cast<uint32_t>(Tag::Last));
+        ISafeInterfaceTest::Tag tag = static_cast<ISafeInterfaceTest::Tag>(code);
+        switch (tag) {
+            case ISafeInterfaceTest::Tag::SetDeathToken: {
+                return callLocal(data, reply, &ISafeInterfaceTest::setDeathToken);
+            }
+            case ISafeInterfaceTest::Tag::ReturnsNoMemory: {
+                return callLocal(data, reply, &ISafeInterfaceTest::returnsNoMemory);
+            }
+            case ISafeInterfaceTest::Tag::LogicalNot: {
+                return callLocal(data, reply, &ISafeInterfaceTest::logicalNot);
+            }
+            case ISafeInterfaceTest::Tag::ModifyEnum: {
+                return callLocal(data, reply, &ISafeInterfaceTest::modifyEnum);
+            }
+            case ISafeInterfaceTest::Tag::IncrementFlattenable: {
+                using Signature = status_t (ISafeInterfaceTest::*)(const TestFlattenable& a,
+                                                                   TestFlattenable* aPlusOne) const;
+                return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+            }
+            case ISafeInterfaceTest::Tag::IncrementLightFlattenable: {
+                using Signature =
+                        status_t (ISafeInterfaceTest::*)(const TestLightFlattenable& a,
+                                                         TestLightFlattenable* aPlusOne) const;
+                return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+            }
+            case ISafeInterfaceTest::Tag::IncrementLightRefBaseFlattenable: {
+                using Signature =
+                        status_t (ISafeInterfaceTest::*)(const sp<TestLightRefBaseFlattenable>&,
+                                                         sp<TestLightRefBaseFlattenable>*) const;
+                return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+            }
+            case ISafeInterfaceTest::Tag::IncrementNativeHandle: {
+                using Signature = status_t (ISafeInterfaceTest::*)(const sp<NativeHandle>&,
+                                                                   sp<NativeHandle>*) const;
+                return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+            }
+            case ISafeInterfaceTest::Tag::IncrementNoCopyNoMove: {
+                using Signature = status_t (ISafeInterfaceTest::*)(const NoCopyNoMove& a,
+                                                                   NoCopyNoMove* aPlusOne) const;
+                return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+            }
+            case ISafeInterfaceTest::Tag::IncrementParcelableVector: {
+                using Signature =
+                        status_t (ISafeInterfaceTest::*)(const std::vector<TestParcelable>&,
+                                                         std::vector<TestParcelable>*) const;
+                return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+            }
+            case ISafeInterfaceTest::Tag::ToUpper: {
+                return callLocal(data, reply, &ISafeInterfaceTest::toUpper);
+            }
+            case ISafeInterfaceTest::Tag::CallMeBack: {
+                return callLocalAsync(data, reply, &ISafeInterfaceTest::callMeBack);
+            }
+            case ISafeInterfaceTest::Tag::IncrementInt32: {
+                using Signature = status_t (ISafeInterfaceTest::*)(int32_t, int32_t*) const;
+                return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+            }
+            case ISafeInterfaceTest::Tag::IncrementUint32: {
+                using Signature = status_t (ISafeInterfaceTest::*)(uint32_t, uint32_t*) const;
+                return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+            }
+            case ISafeInterfaceTest::Tag::IncrementInt64: {
+                using Signature = status_t (ISafeInterfaceTest::*)(int64_t, int64_t*) const;
+                return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+            }
+            case ISafeInterfaceTest::Tag::IncrementUint64: {
+                using Signature = status_t (ISafeInterfaceTest::*)(uint64_t, uint64_t*) 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;
+                return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+            }
+            case ISafeInterfaceTest::Tag::Last:
+                // Should not be possible because of the asserts at the beginning of the method
+                [&]() { FAIL(); }();
+                return UNKNOWN_ERROR;
+        }
+    }
+
+private:
+    static constexpr const char* getLogTag() { return "BnSafeInterfaceTest"; }
+};
+
+class SafeInterfaceTest : public ::testing::Test {
+public:
+    SafeInterfaceTest() : mSafeInterfaceTest(getRemoteService()) {
+        ProcessState::self()->startThreadPool();
+    }
+    ~SafeInterfaceTest() override = default;
+
+protected:
+    sp<ISafeInterfaceTest> mSafeInterfaceTest;
+
+private:
+    static constexpr const char* getLogTag() { return "SafeInterfaceTest"; }
+
+    sp<ISafeInterfaceTest> getRemoteService() {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wexit-time-destructors"
+        static std::mutex sMutex;
+        static sp<ISafeInterfaceTest> sService;
+        static sp<IBinder> sDeathToken = new BBinder;
+#pragma clang diagnostic pop
+
+        std::unique_lock<decltype(sMutex)> lock;
+        if (sService == nullptr) {
+            ALOG(LOG_INFO, getLogTag(), "Forking remote process");
+            pid_t forkPid = fork();
+            EXPECT_NE(forkPid, -1);
+
+            const String16 serviceName("SafeInterfaceTest");
+
+            if (forkPid == 0) {
+                ALOG(LOG_INFO, getLogTag(), "Remote process checking in");
+                sp<ISafeInterfaceTest> nativeService = new BnSafeInterfaceTest;
+                defaultServiceManager()->addService(serviceName,
+                                                    IInterface::asBinder(nativeService));
+                ProcessState::self()->startThreadPool();
+                IPCThreadState::self()->joinThreadPool();
+                // We shouldn't get to this point
+                [&]() { FAIL(); }();
+            }
+
+            sp<IBinder> binder = defaultServiceManager()->getService(serviceName);
+            sService = interface_cast<ISafeInterfaceTest>(binder);
+            EXPECT_TRUE(sService != nullptr);
+
+            sService->setDeathToken(sDeathToken);
+        }
+
+        return sService;
+    }
+};
+
+TEST_F(SafeInterfaceTest, TestReturnsNoMemory) {
+    status_t result = mSafeInterfaceTest->returnsNoMemory();
+    ASSERT_EQ(NO_MEMORY, result);
+}
+
+TEST_F(SafeInterfaceTest, TestLogicalNot) {
+    const bool a = true;
+    bool notA = true;
+    status_t result = mSafeInterfaceTest->logicalNot(a, &notA);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_EQ(!a, notA);
+    // Test both since we don't want to accidentally catch a default false somewhere
+    const bool b = false;
+    bool notB = false;
+    result = mSafeInterfaceTest->logicalNot(b, &notB);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_EQ(!b, notB);
+}
+
+TEST_F(SafeInterfaceTest, TestModifyEnum) {
+    const TestEnum a = TestEnum::INITIAL;
+    TestEnum b = TestEnum::INVALID;
+    status_t result = mSafeInterfaceTest->modifyEnum(a, &b);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_EQ(TestEnum::FINAL, b);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementFlattenable) {
+    const TestFlattenable a{1};
+    TestFlattenable aPlusOne{0};
+    status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_EQ(a.value + 1, aPlusOne.value);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementLightFlattenable) {
+    const TestLightFlattenable a{1};
+    TestLightFlattenable aPlusOne{0};
+    status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_EQ(a.value + 1, aPlusOne.value);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementLightRefBaseFlattenable) {
+    sp<TestLightRefBaseFlattenable> a = new TestLightRefBaseFlattenable{1};
+    sp<TestLightRefBaseFlattenable> aPlusOne;
+    status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_NE(nullptr, aPlusOne.get());
+    ASSERT_EQ(a->value + 1, aPlusOne->value);
+}
+
+namespace { // Anonymous namespace
+
+bool fdsAreEquivalent(int a, int b) {
+    struct stat statA {};
+    struct stat statB {};
+    if (fstat(a, &statA) != 0) return false;
+    if (fstat(b, &statB) != 0) return false;
+    return (statA.st_dev == statB.st_dev) && (statA.st_ino == statB.st_ino);
+}
+
+} // Anonymous namespace
+
+TEST_F(SafeInterfaceTest, TestIncrementNativeHandle) {
+    // Create an fd we can use to send and receive from the remote process
+    base::unique_fd eventFd{eventfd(0 /*initval*/, 0 /*flags*/)};
+    ASSERT_NE(-1, eventFd);
+
+    // Determine the maximum number of fds this process can have open
+    struct rlimit limit {};
+    ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &limit));
+    uint32_t maxFds = static_cast<uint32_t>(limit.rlim_cur);
+
+    // Perform this test enough times to rule out fd leaks
+    for (uint32_t iter = 0; iter < (2 * maxFds); ++iter) {
+        native_handle* handle = native_handle_create(1 /*numFds*/, 1 /*numInts*/);
+        ASSERT_NE(nullptr, handle);
+        handle->data[0] = dup(eventFd.get());
+        handle->data[1] = 1;
+
+        // This cannot fail, as it is just the sp<NativeHandle> taking responsibility for closing
+        // the native_handle when it goes out of scope
+        sp<NativeHandle> a = NativeHandle::create(handle, true);
+
+        sp<NativeHandle> aPlusOne;
+        status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+        ASSERT_EQ(NO_ERROR, result);
+        ASSERT_TRUE(fdsAreEquivalent(a->handle()->data[0], aPlusOne->handle()->data[0]));
+        ASSERT_EQ(a->handle()->data[1] + 1, aPlusOne->handle()->data[1]);
+    }
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementNoCopyNoMove) {
+    const NoCopyNoMove a{1};
+    NoCopyNoMove aPlusOne{0};
+    status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_EQ(a.getValue() + 1, aPlusOne.getValue());
+}
+
+TEST_F(SafeInterfaceTest, TestIncremementParcelableVector) {
+    const std::vector<TestParcelable> a{TestParcelable{1}, TestParcelable{2}};
+    std::vector<TestParcelable> aPlusOne;
+    status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+    ASSERT_EQ(a.size(), aPlusOne.size());
+    for (size_t i = 0; i < a.size(); ++i) {
+        ASSERT_EQ(a[i].getValue() + 1, aPlusOne[i].getValue());
+    }
+}
+
+TEST_F(SafeInterfaceTest, TestToUpper) {
+    const String8 str{"Hello, world!"};
+    String8 upperStr;
+    status_t result = mSafeInterfaceTest->toUpper(str, &upperStr);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_TRUE(upperStr == String8{"HELLO, WORLD!"});
+}
+
+TEST_F(SafeInterfaceTest, TestCallMeBack) {
+    class CallbackReceiver : public BnCallback {
+    public:
+        void onCallback(int32_t aPlusOne) override {
+            ALOG(LOG_INFO, "CallbackReceiver", "%s", __PRETTY_FUNCTION__);
+            std::unique_lock<decltype(mMutex)> lock(mMutex);
+            mValue = aPlusOne;
+            mCondition.notify_one();
+        }
+
+        std::optional<int32_t> waitForCallback() {
+            std::unique_lock<decltype(mMutex)> lock(mMutex);
+            bool success =
+                    mCondition.wait_for(lock, 100ms, [&]() { return static_cast<bool>(mValue); });
+            return success ? mValue : std::nullopt;
+        }
+
+    private:
+        std::mutex mMutex;
+        std::condition_variable mCondition;
+        std::optional<int32_t> mValue;
+    };
+
+    sp<CallbackReceiver> receiver = new CallbackReceiver;
+    const int32_t a = 1;
+    mSafeInterfaceTest->callMeBack(receiver, a);
+    auto result = receiver->waitForCallback();
+    ASSERT_TRUE(result);
+    ASSERT_EQ(a + 1, *result);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementInt32) {
+    const int32_t a = 1;
+    int32_t aPlusOne = 0;
+    status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_EQ(a + 1, aPlusOne);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementUint32) {
+    const uint32_t a = 1;
+    uint32_t aPlusOne = 0;
+    status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_EQ(a + 1, aPlusOne);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementInt64) {
+    const int64_t a = 1;
+    int64_t aPlusOne = 0;
+    status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_EQ(a + 1, aPlusOne);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementUint64) {
+    const uint64_t a = 1;
+    uint64_t aPlusOne = 0;
+    status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_EQ(a + 1, aPlusOne);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementTwo) {
+    const int32_t a = 1;
+    int32_t aPlusOne = 0;
+    const int32_t b = 2;
+    int32_t bPlusOne = 0;
+    status_t result = mSafeInterfaceTest->increment(1, &aPlusOne, 2, &bPlusOne);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_EQ(a + 1, aPlusOne);
+    ASSERT_EQ(b + 1, bPlusOne);
+}
+
+} // namespace tests
+} // namespace android
diff --git a/libs/binder/tests/binderTextOutputTest.cpp b/libs/binder/tests/binderTextOutputTest.cpp
new file mode 100644
index 0000000..f6dd22d
--- /dev/null
+++ b/libs/binder/tests/binderTextOutputTest.cpp
@@ -0,0 +1,176 @@
+/*
+ * 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 <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits>
+#include <cstddef>
+
+#include "android-base/file.h"
+#include "android-base/test_utils.h"
+#include <gtest/gtest.h>
+
+#include <binder/Parcel.h>
+#include <binder/TextOutput.h>
+#include <binder/Debug.h>
+
+static void CheckMessage(const 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);
+    if (singleline)
+        output.erase(std::remove(output.begin(), output.end(), '\n'));
+    ASSERT_STREQ(output.c_str(), expected);
+}
+
+#define CHECK_LOG_(input, expect, singleline)    \
+{                                                \
+    CapturedStderr cap;                          \
+    android::aerr << input << android::endl;     \
+    CheckMessage(cap, expect, singleline);       \
+}                                                \
+
+#define CHECK_VAL_(val, singleline)              \
+{                                                \
+    std::stringstream ss;                        \
+    ss << val;                                   \
+    std::string s = ss.str();                    \
+    CHECK_LOG_(val, s.c_str(), singleline);      \
+}                                                \
+
+#define CHECK_LOG(input, expect) CHECK_LOG_(input, expect, true)
+#define CHECK_VAL(val) CHECK_VAL_(val, true)
+
+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");
+}
+
+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");
+}
+
+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");
+}
+
+TEST(TextOutput, HandleEmptyString) {
+    CHECK_LOG("", "");
+}
+
+TEST(TextOutput, HandleString) {
+    CHECK_LOG("foobar", "foobar");
+}
+
+TEST(TextOutput, HandleNum) {
+    CHECK_LOG(12345, "12345");
+}
+
+TEST(TextOutput, HandleBool) {
+    CHECK_LOG(false, "false");
+}
+
+TEST(TextOutput, HandleChar) {
+    CHECK_LOG('T', "T");
+}
+
+TEST(TextOutput, HandleParcel) {
+    android::Parcel val;
+    CHECK_LOG(val, "Parcel(NULL)");
+}
+
+TEST(TextOutput, HandleHexDump) {
+    const char buf[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+    android::HexDump val(buf, sizeof(buf));
+    CHECK_LOG(val, "03020100 07060504 0b0a0908 0f0e0d0c '................'");
+}
+
+TEST(TextOutput, HandleHexDumpCustom) {
+    const char buf[4] = {0x11,0x22,0x33,0x44};
+    android::HexDump val(buf, sizeof(buf), 4);
+    CHECK_LOG(val, "11 22 33 44 '.\"3D'");
+}
+
+TEST(TextOutput, HandleTypeCode) {
+    android::TypeCode val(1234);
+    CHECK_LOG(val, "'\\x04\\xd2'");
+}
+
+TEST(TextOutput, HandleCookie) {
+    int32_t val = 321; //0x141
+    CHECK_LOG((void*)(long)val, "0x141");
+}
+
+TEST(TextOutput, HandleString8) {
+    android::String8 val("foobar");
+    CHECK_LOG(val, "foobar");
+}
+
+TEST(TextOutput, HandleString16) {
+    android::String16 val("foobar");
+    CHECK_LOG(val, "foobar");
+}
+
+template <typename T>
+class TextTest : public testing::Test {};
+
+typedef testing::Types<short, unsigned short,
+                       int, unsigned int,
+                       long, unsigned long,
+                       long long, unsigned long long,
+                       float, double, long double> TestTypes;
+TYPED_TEST_CASE(TextTest, TestTypes);
+
+TYPED_TEST(TextTest, TextMax)
+{
+    TypeParam max = std::numeric_limits<TypeParam>::max();
+    CHECK_VAL(max);
+}
+
+TYPED_TEST(TextTest, TestMin)
+{
+    TypeParam min = std::numeric_limits<TypeParam>::min();
+    CHECK_VAL(min);
+}
+
+TYPED_TEST(TextTest, TestDenom)
+{
+    TypeParam min = std::numeric_limits<TypeParam>::denorm_min();
+    CHECK_VAL(min);
+}
+
+TYPED_TEST(TextTest, TestEpsilon)
+{
+    TypeParam eps = std::numeric_limits<TypeParam>::epsilon();
+    CHECK_VAL(eps);
+}
diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp
index 71b96d4..6e8f7df 100644
--- a/libs/binder/tests/binderThroughputTest.cpp
+++ b/libs/binder/tests/binderThroughputTest.cpp
@@ -170,6 +170,8 @@
     int num,
     int worker_count,
     int iterations,
+    int payload_size,
+    bool cs_pair,
     Pipe p)
 {
     // Create BinderWorkerService and for go.
@@ -182,22 +184,32 @@
     p.signal();
     p.wait();
 
+    // If client/server pairs, then half the workers are
+    // servers and half are clients
+    int server_count = cs_pair ? worker_count / 2 : worker_count;
+
     // Get references to other binder services.
     cout << "Created BinderWorker" << num << endl;
     (void)worker_count;
     vector<sp<IBinder> > workers;
-    for (int i = 0; i < worker_count; i++) {
+    for (int i = 0; i < server_count; i++) {
         if (num == i)
             continue;
         workers.push_back(serviceMgr->getService(generateServiceName(i)));
     }
 
-    // Run the benchmark.
+    // Run the benchmark if client
     ProcResults results;
     chrono::time_point<chrono::high_resolution_clock> start, end;
-    for (int i = 0; i < iterations; i++) {
-        int target = rand() % workers.size();
+    for (int i = 0; (!cs_pair || num >= server_count) && i < iterations; i++) {
         Parcel data, reply;
+        int target = cs_pair ? num % server_count : rand() % workers.size();
+	int sz = payload_size;
+
+	while (sz > sizeof(uint32_t)) {
+		data.writeInt32(0);
+		sz -= sizeof(uint32_t);
+	}
         start = chrono::high_resolution_clock::now();
         status_t ret = workers[target]->transact(BINDER_NOP, data, &reply);
         end = chrono::high_resolution_clock::now();
@@ -210,6 +222,7 @@
            exit(EXIT_FAILURE);
         }
     }
+
     // Signal completion to master and wait.
     p.signal();
     p.wait();
@@ -221,7 +234,7 @@
     exit(EXIT_SUCCESS);
 }
 
-Pipe make_worker(int num, int iterations, int worker_count)
+Pipe make_worker(int num, int iterations, int worker_count, int payload_size, bool cs_pair)
 {
     auto pipe_pair = Pipe::createPipePair();
     pid_t pid = fork();
@@ -230,7 +243,7 @@
         return move(get<0>(pipe_pair));
     } else {
         /* child */
-        worker_fx(num, worker_count, iterations, move(get<1>(pipe_pair)));
+        worker_fx(num, worker_count, iterations, payload_size, cs_pair, move(get<1>(pipe_pair)));
         /* never get here */
         return move(get<0>(pipe_pair));
     }
@@ -255,6 +268,8 @@
 {
     int workers = 2;
     int iterations = 10000;
+    int payload_size = 0;
+    bool cs_pair = false;
     (void)argc;
     (void)argv;
     vector<Pipe> pipes;
@@ -271,11 +286,21 @@
             i++;
             continue;
         }
+        if (string(argv[i]) == "-s") {
+            payload_size = atoi(argv[i+1]);
+	    i++;
+	}
+        if (string(argv[i]) == "-p") {
+		// client/server pairs instead of spreading
+		// requests to all workers. If true, half
+		// the workers become clients and half servers
+		cs_pair = true;
+	}
     }
 
     // Create all the workers and wait for them to spawn.
     for (int i = 0; i < workers; i++) {
-        pipes.push_back(make_worker(i, iterations, workers));
+        pipes.push_back(make_worker(i, iterations, workers, payload_size, cs_pair));
     }
     wait_all(pipes);
 
diff --git a/libs/binder/tests/binderValueTypeTest.cpp b/libs/binder/tests/binderValueTypeTest.cpp
new file mode 100644
index 0000000..c8f4697
--- /dev/null
+++ b/libs/binder/tests/binderValueTypeTest.cpp
@@ -0,0 +1,111 @@
+/*
+ * 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 <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits>
+#include <cstddef>
+#include <vector>
+
+#include "android-base/file.h"
+#include "android-base/test_utils.h"
+#include <gtest/gtest.h>
+
+#include <binder/Parcel.h>
+#include <binder/Value.h>
+#include <binder/Debug.h>
+
+using ::android::binder::Value;
+using ::android::os::PersistableBundle;
+using ::android::String16;
+using ::std::vector;
+
+#define VALUE_TYPE_TEST(T, TYPENAME, VAL)         \
+    TEST(ValueType, Handles ## TYPENAME) {        \
+        T x = VAL;                                \
+        T y = T();                                \
+        Value value = VAL;                        \
+        ASSERT_FALSE(value.empty());              \
+        ASSERT_TRUE(value.is ## TYPENAME ());     \
+        ASSERT_TRUE(value.get ## TYPENAME (&y));  \
+        ASSERT_EQ(x, y);                          \
+        ASSERT_EQ(value, Value(y));               \
+        value.put ## TYPENAME (x);                \
+        ASSERT_EQ(value, Value(y));               \
+        value = Value();                          \
+        ASSERT_TRUE(value.empty());               \
+        ASSERT_NE(value, Value(y));               \
+        value = y;                                \
+        ASSERT_EQ(value, Value(x));               \
+    }
+
+#define VALUE_TYPE_VECTOR_TEST(T, TYPENAME, VAL)      \
+    TEST(ValueType, Handles ## TYPENAME ## Vector) {  \
+        vector<T> x;                                  \
+        vector<T> y;                                  \
+        x.push_back(VAL);                             \
+        x.push_back(T());                             \
+        Value value(x);                               \
+        ASSERT_FALSE(value.empty());                  \
+        ASSERT_TRUE(value.is ## TYPENAME ## Vector());    \
+        ASSERT_TRUE(value.get ## TYPENAME ## Vector(&y)); \
+        ASSERT_EQ(x, y);                              \
+        ASSERT_EQ(value, Value(y));                   \
+        value.put ## TYPENAME ## Vector(x);           \
+        ASSERT_EQ(value, Value(y));                   \
+        value = Value();                              \
+        ASSERT_TRUE(value.empty());                   \
+        ASSERT_NE(value, Value(y));                   \
+        value = y;                                    \
+        ASSERT_EQ(value, Value(x));                   \
+    }
+
+VALUE_TYPE_TEST(bool, Boolean, true)
+VALUE_TYPE_TEST(int32_t, Int, 31337)
+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(double, Double, 3.14159265358979323846)
+VALUE_TYPE_VECTOR_TEST(String16, String, String16("Lovely"))
+
+VALUE_TYPE_TEST(PersistableBundle, PersistableBundle, PersistableBundle())
+
+TEST(ValueType, HandlesClear) {
+    Value value;
+    ASSERT_TRUE(value.empty());
+    value.putInt(31337);
+    ASSERT_FALSE(value.empty());
+    value.clear();
+    ASSERT_TRUE(value.empty());
+}
+
+TEST(ValueType, HandlesSwap) {
+    Value value_a, value_b;
+    int32_t int_x;
+    value_a.putInt(31337);
+    ASSERT_FALSE(value_a.empty());
+    ASSERT_TRUE(value_b.empty());
+    value_a.swap(value_b);
+    ASSERT_FALSE(value_b.empty());
+    ASSERT_TRUE(value_a.empty());
+    ASSERT_TRUE(value_b.getInt(&int_x));
+    ASSERT_EQ(31337, int_x);
+}
diff --git a/libs/binder/tests/schd-dbg.cpp b/libs/binder/tests/schd-dbg.cpp
new file mode 100644
index 0000000..13f03b1
--- /dev/null
+++ b/libs/binder/tests/schd-dbg.cpp
@@ -0,0 +1,502 @@
+#include <binder/Binder.h>
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <string>
+
+#include <iomanip>
+#include <iostream>
+#include <tuple>
+#include <vector>
+
+#include <pthread.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fstream>
+
+using namespace std;
+using namespace android;
+
+enum BinderWorkerServiceCode {
+  BINDER_NOP = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+#define ASSERT(cond)                                                \
+  do {                                                              \
+    if (!(cond)) {                                                  \
+      cerr << __func__ << ":" << __LINE__ << " condition:" << #cond \
+           << " failed\n"                                           \
+           << endl;                                                 \
+      exit(EXIT_FAILURE);                                           \
+    }                                                               \
+  } while (0)
+
+vector<sp<IBinder> > workers;
+
+// the ratio that the service is synced on the same cpu beyond
+// GOOD_SYNC_MIN is considered as good
+#define GOOD_SYNC_MIN (0.6)
+
+#define DUMP_PRESICION 2
+
+string trace_path = "/sys/kernel/debug/tracing";
+
+// the default value
+int no_process = 2;
+int iterations = 100;
+int payload_size = 16;
+int no_inherent = 0;
+int no_sync = 0;
+int verbose = 0;
+int trace;
+
+bool traceIsOn() {
+  fstream file;
+  file.open(trace_path + "/tracing_on", ios::in);
+  char on;
+  file >> on;
+  file.close();
+  return on == '1';
+}
+
+void traceStop() {
+  ofstream file;
+  file.open(trace_path + "/tracing_on", ios::out | ios::trunc);
+  file << '0' << endl;
+  file.close();
+}
+
+// the deadline latency that we are interested in
+uint64_t deadline_us = 2500;
+
+int thread_pri() {
+  struct sched_param param;
+  int policy;
+  ASSERT(!pthread_getschedparam(pthread_self(), &policy, &param));
+  return param.sched_priority;
+}
+
+void thread_dump(const char* prefix) {
+  struct sched_param param;
+  int policy;
+  if (!verbose) return;
+  cout << "--------------------------------------------------" << endl;
+  cout << setw(12) << left << prefix << " pid: " << getpid()
+       << " tid: " << gettid() << " cpu: " << sched_getcpu() << endl;
+  ASSERT(!pthread_getschedparam(pthread_self(), &policy, &param));
+  string s = (policy == SCHED_OTHER)
+                 ? "SCHED_OTHER"
+                 : (policy == SCHED_FIFO)
+                       ? "SCHED_FIFO"
+                       : (policy == SCHED_RR) ? "SCHED_RR" : "???";
+  cout << setw(12) << left << s << param.sched_priority << endl;
+  return;
+}
+
+class BinderWorkerService : public BBinder {
+ public:
+  BinderWorkerService() {
+  }
+  ~BinderWorkerService() {
+  }
+  virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                              uint32_t flags = 0) {
+    (void)flags;
+    (void)data;
+    (void)reply;
+    switch (code) {
+      // The transaction format is like
+      //
+      // data[in]:  int32: caller priority
+      //            int32: caller cpu
+      //
+      // reply[out]: int32: 1 if caller's priority != callee's priority
+      //             int32: 1 if caller's cpu != callee's cpu
+      //
+      // note the caller cpu read here is not always correct
+      // there're still chances that the caller got switched out
+      // right after it read the cpu number and still before the transaction.
+      case BINDER_NOP: {
+        thread_dump("binder");
+        int priority = thread_pri();
+        int priority_caller = data.readInt32();
+        int h = 0, s = 0;
+        if (priority_caller != priority) {
+          h++;
+          if (verbose) {
+            cout << "err priority_caller:" << priority_caller
+                 << ", priority:" << priority << endl;
+          }
+        }
+        if (priority == sched_get_priority_max(SCHED_FIFO)) {
+          int cpu = sched_getcpu();
+          int cpu_caller = data.readInt32();
+          if (cpu != cpu_caller) {
+            s++;
+          }
+        }
+        reply->writeInt32(h);
+        reply->writeInt32(s);
+        return NO_ERROR;
+      }
+      default:
+        return UNKNOWN_TRANSACTION;
+    };
+  }
+};
+
+class Pipe {
+  int m_readFd;
+  int m_writeFd;
+  Pipe(int readFd, int writeFd) : m_readFd{readFd}, m_writeFd{writeFd} {
+  }
+  Pipe(const Pipe&) = delete;
+  Pipe& operator=(const Pipe&) = delete;
+  Pipe& operator=(const Pipe&&) = delete;
+
+ public:
+  Pipe(Pipe&& rval) noexcept {
+    m_readFd = rval.m_readFd;
+    m_writeFd = rval.m_writeFd;
+    rval.m_readFd = 0;
+    rval.m_writeFd = 0;
+  }
+  ~Pipe() {
+    if (m_readFd) close(m_readFd);
+    if (m_writeFd) close(m_writeFd);
+  }
+  void signal() {
+    bool val = true;
+    int error = write(m_writeFd, &val, sizeof(val));
+    ASSERT(error >= 0);
+  };
+  void wait() {
+    bool val = false;
+    int error = read(m_readFd, &val, sizeof(val));
+    ASSERT(error >= 0);
+  }
+  template <typename T>
+  void send(const T& v) {
+    int error = write(m_writeFd, &v, sizeof(T));
+    ASSERT(error >= 0);
+  }
+  template <typename T>
+  void recv(T& v) {
+    int error = read(m_readFd, &v, sizeof(T));
+    ASSERT(error >= 0);
+  }
+  static tuple<Pipe, Pipe> createPipePair() {
+    int a[2];
+    int b[2];
+
+    int error1 = pipe(a);
+    int error2 = pipe(b);
+    ASSERT(error1 >= 0);
+    ASSERT(error2 >= 0);
+
+    return make_tuple(Pipe(a[0], b[1]), Pipe(b[0], a[1]));
+  }
+};
+
+typedef chrono::time_point<chrono::high_resolution_clock> Tick;
+
+static inline Tick tickNow() {
+  return chrono::high_resolution_clock::now();
+}
+
+static inline uint64_t tickNano(Tick& sta, Tick& end) {
+  return uint64_t(chrono::duration_cast<chrono::nanoseconds>(end - sta).count());
+}
+
+struct Results {
+  uint64_t m_best = 0xffffffffffffffffULL;
+  uint64_t m_worst = 0;
+  uint64_t m_transactions = 0;
+  uint64_t m_total_time = 0;
+  uint64_t m_miss = 0;
+  bool tracing;
+  Results(bool _tracing) : tracing(_tracing) {
+  }
+  inline bool miss_deadline(uint64_t nano) {
+    return nano > deadline_us * 1000;
+  }
+  void add_time(uint64_t nano) {
+    m_best = min(nano, m_best);
+    m_worst = max(nano, m_worst);
+    m_transactions += 1;
+    m_total_time += nano;
+    if (miss_deadline(nano)) m_miss++;
+    if (miss_deadline(nano) && tracing) {
+      // There might be multiple process pair running the test concurrently
+      // each may execute following statements and only the first one actually
+      // stop the trace and any traceStop() afterthen has no effect.
+      traceStop();
+      cout << endl;
+      cout << "deadline triggered: halt & stop trace" << endl;
+      cout << "log:" + trace_path + "/trace" << endl;
+      cout << endl;
+      exit(1);
+    }
+  }
+  void dump() {
+    double best = (double)m_best / 1.0E6;
+    double worst = (double)m_worst / 1.0E6;
+    double average = (double)m_total_time / m_transactions / 1.0E6;
+    // FIXME: libjson?
+    int W = DUMP_PRESICION + 2;
+    cout << setprecision(DUMP_PRESICION) << "{ \"avg\":" << setw(W) << left
+         << average << ",\"wst\":" << setw(W) << left << worst
+         << ",\"bst\":" << setw(W) << left << best << ",\"miss\":" << left
+         << m_miss << ",\"meetR\":" << left << setprecision(DUMP_PRESICION + 3)
+         << (1.0 - (double)m_miss / m_transactions) << "}";
+  }
+};
+
+String16 generateServiceName(int num) {
+  char num_str[32];
+  snprintf(num_str, sizeof(num_str), "%d", num);
+  String16 serviceName = String16("binderWorker") + String16(num_str);
+  return serviceName;
+}
+
+static void parcel_fill(Parcel& data, int sz, int priority, int cpu) {
+  ASSERT(sz >= (int)sizeof(uint32_t) * 2);
+  data.writeInt32(priority);
+  data.writeInt32(cpu);
+  sz -= sizeof(uint32_t);
+  while (sz > (int)sizeof(uint32_t)) {
+    data.writeInt32(0);
+    sz -= sizeof(uint32_t);
+  }
+}
+
+typedef struct {
+  void* result;
+  int target;
+} thread_priv_t;
+
+static void* thread_start(void* p) {
+  thread_priv_t* priv = (thread_priv_t*)p;
+  int target = priv->target;
+  Results* results_fifo = (Results*)priv->result;
+  Parcel data, reply;
+  Tick sta, end;
+
+  parcel_fill(data, payload_size, thread_pri(), sched_getcpu());
+  thread_dump("fifo-caller");
+
+  sta = tickNow();
+  status_t ret = workers[target]->transact(BINDER_NOP, data, &reply);
+  end = tickNow();
+  results_fifo->add_time(tickNano(sta, end));
+
+  no_inherent += reply.readInt32();
+  no_sync += reply.readInt32();
+  return 0;
+}
+
+// create a fifo thread to transact and wait it to finished
+static void thread_transaction(int target, Results* results_fifo) {
+  thread_priv_t thread_priv;
+  void* dummy;
+  pthread_t thread;
+  pthread_attr_t attr;
+  struct sched_param param;
+  thread_priv.target = target;
+  thread_priv.result = results_fifo;
+  ASSERT(!pthread_attr_init(&attr));
+  ASSERT(!pthread_attr_setschedpolicy(&attr, SCHED_FIFO));
+  param.sched_priority = sched_get_priority_max(SCHED_FIFO);
+  ASSERT(!pthread_attr_setschedparam(&attr, &param));
+  ASSERT(!pthread_create(&thread, &attr, &thread_start, &thread_priv));
+  ASSERT(!pthread_join(thread, &dummy));
+}
+
+#define is_client(_num) ((_num) >= (no_process / 2))
+
+void worker_fx(int num, int no_process, int iterations, int payload_size,
+               Pipe p) {
+  int dummy;
+  Results results_other(false), results_fifo(trace);
+
+  // Create BinderWorkerService and for go.
+  ProcessState::self()->startThreadPool();
+  sp<IServiceManager> serviceMgr = defaultServiceManager();
+  sp<BinderWorkerService> service = new BinderWorkerService;
+  serviceMgr->addService(generateServiceName(num), service);
+  // init done
+  p.signal();
+  // wait for kick-off
+  p.wait();
+
+  // If client/server pairs, then half the workers are
+  // servers and half are clients
+  int server_count = no_process / 2;
+
+  for (int i = 0; i < server_count; i++) {
+    // self service is in-process so just skip
+    if (num == i) continue;
+    workers.push_back(serviceMgr->getService(generateServiceName(i)));
+  }
+
+  // Client for each pair iterates here
+  // each iterations contains exatcly 2 transactions
+  for (int i = 0; is_client(num) && i < iterations; i++) {
+    Parcel data, reply;
+    Tick sta, end;
+    // the target is paired to make it easier to diagnose
+    int target = num % server_count;
+
+    // 1. transaction by fifo thread
+    thread_transaction(target, &results_fifo);
+    parcel_fill(data, payload_size, thread_pri(), sched_getcpu());
+    thread_dump("other-caller");
+
+    // 2. transaction by other thread
+    sta = tickNow();
+    ASSERT(NO_ERROR == workers[target]->transact(BINDER_NOP, data, &reply));
+    end = tickNow();
+    results_other.add_time(tickNano(sta, end));
+
+    no_inherent += reply.readInt32();
+    no_sync += reply.readInt32();
+  }
+  // Signal completion to master and wait.
+  p.signal();
+  p.wait();
+
+  p.send(&dummy);
+  // wait for kill
+  p.wait();
+  // Client for each pair dump here
+  if (is_client(num)) {
+    int no_trans = iterations * 2;
+    double sync_ratio = (1.0 - (double)no_sync / no_trans);
+    // FIXME: libjson?
+    cout << "\"P" << (num - server_count) << "\":{\"SYNC\":\""
+         << ((sync_ratio > GOOD_SYNC_MIN) ? "GOOD" : "POOR") << "\","
+         << "\"S\":" << (no_trans - no_sync) << ",\"I\":" << no_trans << ","
+         << "\"R\":" << sync_ratio << "," << endl;
+
+    cout << "  \"other_ms\":";
+    results_other.dump();
+    cout << "," << endl;
+    cout << "  \"fifo_ms\": ";
+    results_fifo.dump();
+    cout << endl;
+    cout << "}," << endl;
+  }
+  exit(no_inherent);
+}
+
+Pipe make_process(int num, int iterations, int no_process, int payload_size) {
+  auto pipe_pair = Pipe::createPipePair();
+  pid_t pid = fork();
+  if (pid) {
+    // parent
+    return move(get<0>(pipe_pair));
+  } else {
+    // child
+    thread_dump(is_client(num) ? "client" : "server");
+    worker_fx(num, no_process, iterations, payload_size,
+              move(get<1>(pipe_pair)));
+    // never get here
+    return move(get<0>(pipe_pair));
+  }
+}
+
+void wait_all(vector<Pipe>& v) {
+  for (size_t i = 0; i < v.size(); i++) {
+    v[i].wait();
+  }
+}
+
+void signal_all(vector<Pipe>& v) {
+  for (size_t i = 0; i < v.size(); i++) {
+    v[i].signal();
+  }
+}
+
+// This test is modified from binderThroughputTest.cpp
+int main(int argc, char** argv) {
+  for (int i = 1; i < argc; i++) {
+    if (string(argv[i]) == "-i") {
+      iterations = atoi(argv[i + 1]);
+      i++;
+      continue;
+    }
+    if (string(argv[i]) == "-pair") {
+      no_process = 2 * atoi(argv[i + 1]);
+      i++;
+      continue;
+    }
+    if (string(argv[i]) == "-deadline_us") {
+      deadline_us = atoi(argv[i + 1]);
+      i++;
+      continue;
+    }
+    if (string(argv[i]) == "-v") {
+      verbose = 1;
+    }
+    // The -trace argument is used like that:
+    //
+    // First start trace with atrace command as usual
+    // >atrace --async_start sched freq
+    //
+    // then use schd-dbg with -trace arguments
+    //./schd-dbg -trace -deadline_us 2500
+    //
+    // This makes schd-dbg to stop trace once it detects a transaction
+    // duration over the deadline. By writing '0' to
+    // /sys/kernel/debug/tracing and halt the process. The tracelog is
+    // then available on /sys/kernel/debug/trace
+    if (string(argv[i]) == "-trace") {
+      trace = 1;
+    }
+  }
+  if (trace && !traceIsOn()) {
+    cout << "trace is not running" << endl;
+    cout << "check " << trace_path + "/tracing_on" << endl;
+    cout << "use atrace --async_start first" << endl;
+    exit(-1);
+  }
+  vector<Pipe> pipes;
+  thread_dump("main");
+  // FIXME: libjson?
+  cout << "{" << endl;
+  cout << "\"cfg\":{\"pair\":" << (no_process / 2)
+       << ",\"iterations\":" << iterations << ",\"deadline_us\":" << deadline_us
+       << "}," << endl;
+
+  // the main process fork 2 processes for each pairs
+  // 1 server + 1 client
+  // each has a pipe to communicate with
+  for (int i = 0; i < no_process; i++) {
+    pipes.push_back(make_process(i, iterations, no_process, payload_size));
+  }
+  // wait for init done
+  wait_all(pipes);
+  // kick-off iterations
+  signal_all(pipes);
+  // wait for completion
+  wait_all(pipes);
+  // start to send result
+  signal_all(pipes);
+  for (int i = 0; i < no_process; i++) {
+    int status;
+    // kill
+    pipes[i].signal();
+    wait(&status);
+    // the exit status is number of transactions without priority inheritance
+    // detected in the child process
+    no_inherent += status;
+  }
+  // FIXME: libjson?
+  cout << "\"inheritance\": " << (no_inherent == 0 ? "\"PASS\"" : "\"FAIL\"")
+       << endl;
+  cout << "}" << endl;
+  return -no_inherent;
+}
diff --git a/libs/diskusage/Android.bp b/libs/diskusage/Android.bp
new file mode 100644
index 0000000..156ddff
--- /dev/null
+++ b/libs/diskusage/Android.bp
@@ -0,0 +1,18 @@
+// 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.
+
+cc_library_static {
+    name: "libdiskusage",
+    srcs: ["dirsize.c"],
+}
diff --git a/libs/diskusage/Android.mk b/libs/diskusage/Android.mk
deleted file mode 100644
index d54f8ad..0000000
--- a/libs/diskusage/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libdiskusage
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := dirsize.c
-
-include $(BUILD_STATIC_LIBRARY)
\ No newline at end of file
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
new file mode 100644
index 0000000..a07726a
--- /dev/null
+++ b/libs/gui/Android.bp
@@ -0,0 +1,133 @@
+// Copyright 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.
+
+cc_library_shared {
+    name: "libgui",
+
+    clang: true,
+    cppflags: [
+        "-Weverything",
+        "-Werror",
+
+        // 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",
+
+        "-DDEBUG_ONLY_CODE=0",
+    ],
+
+    product_variables: {
+        brillo: {
+            cflags: ["-DHAVE_NO_SURFACE_FLINGER"],
+        },
+        eng: {
+            cppflags: [
+                "-UDEBUG_ONLY_CODE",
+                "-DDEBUG_ONLY_CODE=1",
+            ],
+        },
+    },
+
+    srcs: [
+        "BitTube.cpp",
+        "BufferItem.cpp",
+        "BufferItemConsumer.cpp",
+        "BufferQueue.cpp",
+        "BufferQueueConsumer.cpp",
+        "BufferQueueCore.cpp",
+        "BufferQueueProducer.cpp",
+        "BufferSlot.cpp",
+        "ConsumerBase.cpp",
+        "CpuConsumer.cpp",
+        "DisplayEventReceiver.cpp",
+        "FrameTimestamps.cpp",
+        "GLConsumer.cpp",
+        "GuiConfig.cpp",
+        "IDisplayEventConnection.cpp",
+        "IConsumerListener.cpp",
+        "IGraphicBufferConsumer.cpp",
+        "IGraphicBufferProducer.cpp",
+        "IProducerListener.cpp",
+        "ISurfaceComposer.cpp",
+        "ISurfaceComposerClient.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"
+    ],
+
+    shared_libs: [
+        "libsync",
+        "libbinder",
+        "libcutils",
+        "libEGL",
+        "libGLESv2",
+        "libui",
+        "libutils",
+        "libnativewindow",
+        "liblog",
+        "libhidlbase",
+        "libhidltransport",
+        "android.hidl.base@1.0",
+        "android.hidl.token@1.0-utils",
+        "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.configstore@1.0",
+        "android.hardware.configstore-utils",
+    ],
+
+    export_shared_lib_headers: [
+        "libbinder",
+        "libui",
+        "android.hidl.token@1.0-utils",
+        "android.hardware.graphics.bufferqueue@1.0",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+}
+
+subdirs = ["tests"]
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
deleted file mode 100644
index 9e2fc2b..0000000
--- a/libs/gui/Android.mk
+++ /dev/null
@@ -1,103 +0,0 @@
-# Copyright 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.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-LOCAL_CPPFLAGS := -std=c++1y -Weverything -Werror
-
-# The static constructors and destructors in this library have not been noted to
-# introduce significant overheads
-LOCAL_CPPFLAGS += -Wno-exit-time-destructors
-LOCAL_CPPFLAGS += -Wno-global-constructors
-
-# We only care about compiling as C++14
-LOCAL_CPPFLAGS += -Wno-c++98-compat-pedantic
-
-# We don't need to enumerate every case in a switch as long as a default case
-# is present
-LOCAL_CPPFLAGS += -Wno-switch-enum
-
-# Allow calling variadic macros without a __VA_ARGS__ list
-LOCAL_CPPFLAGS += -Wno-gnu-zero-variadic-macro-arguments
-
-# Don't warn about struct padding
-LOCAL_CPPFLAGS += -Wno-padded
-
-LOCAL_CPPFLAGS += -DDEBUG_ONLY_CODE=$(if $(filter userdebug eng,$(TARGET_BUILD_VARIANT)),1,0)
-
-LOCAL_SRC_FILES := \
-	IGraphicBufferConsumer.cpp \
-	IConsumerListener.cpp \
-	BitTube.cpp \
-	BufferItem.cpp \
-	BufferItemConsumer.cpp \
-	BufferQueue.cpp \
-	BufferQueueConsumer.cpp \
-	BufferQueueCore.cpp \
-	BufferQueueProducer.cpp \
-	BufferSlot.cpp \
-	ConsumerBase.cpp \
-	CpuConsumer.cpp \
-	DisplayEventReceiver.cpp \
-	GLConsumer.cpp \
-	GraphicBufferAlloc.cpp \
-	GraphicsEnv.cpp \
-	GuiConfig.cpp \
-	IDisplayEventConnection.cpp \
-	IGraphicBufferAlloc.cpp \
-	IGraphicBufferProducer.cpp \
-	IProducerListener.cpp \
-	ISensorEventConnection.cpp \
-	ISensorServer.cpp \
-	ISurfaceComposer.cpp \
-	ISurfaceComposerClient.cpp \
-	LayerState.cpp \
-	OccupancyTracker.cpp \
-	Sensor.cpp \
-	SensorEventQueue.cpp \
-	SensorManager.cpp \
-	StreamSplitter.cpp \
-	Surface.cpp \
-	SurfaceControl.cpp \
-	SurfaceComposerClient.cpp \
-	SyncFeatures.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
- 	libnativeloader \
-	libbinder \
-	libcutils \
-	libEGL \
-	libGLESv2 \
-	libsync \
-	libui \
-	libutils \
-	liblog
-
-
-LOCAL_MODULE := libgui
-
-ifeq ($(TARGET_BOARD_PLATFORM), tegra)
-	LOCAL_CFLAGS += -DDONT_USE_FENCE_SYNC
-endif
-ifeq ($(TARGET_BOARD_PLATFORM), tegra3)
-	LOCAL_CFLAGS += -DDONT_USE_FENCE_SYNC
-endif
-
-include $(BUILD_SHARED_LIBRARY)
-
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/libs/gui/BitTube.cpp b/libs/gui/BitTube.cpp
index b653c5b..ef7a6f5 100644
--- a/libs/gui/BitTube.cpp
+++ b/libs/gui/BitTube.cpp
@@ -14,9 +14,11 @@
  * limitations under the License.
  */
 
+#include <private/gui/BitTube.h>
+
 #include <stdint.h>
-#include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/types.h>
 
 #include <fcntl.h>
 #include <unistd.h>
@@ -25,46 +27,21 @@
 
 #include <binder/Parcel.h>
 
-#include <gui/BitTube.h>
-
 namespace android {
-// ----------------------------------------------------------------------------
+namespace gui {
 
-// Socket buffer size.  The default is typically about 128KB, which is much larger than
-// we really need.  So we make it smaller.
+// Socket buffer size.  The default is typically about 128KB, which is much larger than we really
+// need. So we make it smaller.
 static const size_t DEFAULT_SOCKET_BUFFER_SIZE = 4 * 1024;
 
-
-BitTube::BitTube()
-    : mSendFd(-1), mReceiveFd(-1)
-{
-    init(DEFAULT_SOCKET_BUFFER_SIZE, DEFAULT_SOCKET_BUFFER_SIZE);
-}
-
-BitTube::BitTube(size_t bufsize)
-    : mSendFd(-1), mReceiveFd(-1)
-{
+BitTube::BitTube(size_t bufsize) {
     init(bufsize, bufsize);
 }
 
-BitTube::BitTube(const Parcel& data)
-    : mSendFd(-1), mReceiveFd(-1)
-{
-    mReceiveFd = dup(data.readFileDescriptor());
-    if (mReceiveFd < 0) {
-        mReceiveFd = -errno;
-        ALOGE("BitTube(Parcel): can't dup filedescriptor (%s)",
-                strerror(-mReceiveFd));
-    }
-}
+BitTube::BitTube(DefaultSizeType) : BitTube(DEFAULT_SOCKET_BUFFER_SIZE) {}
 
-BitTube::~BitTube()
-{
-    if (mSendFd >= 0)
-        close(mSendFd);
-
-    if (mReceiveFd >= 0)
-        close(mReceiveFd);
+BitTube::BitTube(const Parcel& data) {
+    readFromParcel(&data);
 }
 
 void BitTube::init(size_t rcvbuf, size_t sndbuf) {
@@ -73,39 +50,43 @@
         size_t size = DEFAULT_SOCKET_BUFFER_SIZE;
         setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
         setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf));
-        // sine we don't use the "return channel", we keep it small...
+        // since we don't use the "return channel", we keep it small...
         setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
         setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
         fcntl(sockets[0], F_SETFL, O_NONBLOCK);
         fcntl(sockets[1], F_SETFL, O_NONBLOCK);
-        mReceiveFd = sockets[0];
-        mSendFd = sockets[1];
+        mReceiveFd.reset(sockets[0]);
+        mSendFd.reset(sockets[1]);
     } else {
-        mReceiveFd = -errno;
-        ALOGE("BitTube: pipe creation failed (%s)", strerror(-mReceiveFd));
+        mReceiveFd.reset();
+        ALOGE("BitTube: pipe creation failed (%s)", strerror(errno));
     }
 }
 
-status_t BitTube::initCheck() const
-{
+status_t BitTube::initCheck() const {
     if (mReceiveFd < 0) {
         return status_t(mReceiveFd);
     }
     return NO_ERROR;
 }
 
-int BitTube::getFd() const
-{
+int BitTube::getFd() const {
     return mReceiveFd;
 }
 
-int BitTube::getSendFd() const
-{
+int BitTube::getSendFd() const {
     return mSendFd;
 }
 
-ssize_t BitTube::write(void const* vaddr, size_t size)
-{
+base::unique_fd BitTube::moveReceiveFd() {
+    return std::move(mReceiveFd);
+}
+
+void BitTube::setReceiveFd(base::unique_fd&& receiveFd) {
+    mReceiveFd = std::move(receiveFd);
+}
+
+ssize_t BitTube::write(void const* vaddr, size_t size) {
     ssize_t err, len;
     do {
         len = ::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL);
@@ -115,62 +96,66 @@
     return err == 0 ? len : -err;
 }
 
-ssize_t BitTube::read(void* vaddr, size_t size)
-{
+ssize_t BitTube::read(void* vaddr, size_t size) {
     ssize_t err, len;
     do {
         len = ::recv(mReceiveFd, vaddr, size, MSG_DONTWAIT);
         err = len < 0 ? errno : 0;
     } while (err == EINTR);
     if (err == EAGAIN || err == EWOULDBLOCK) {
-        // EAGAIN means that we have non-blocking I/O but there was
-        // no data to be read. Nothing the client should care about.
+        // EAGAIN means that we have non-blocking I/O but there was no data to be read. Nothing the
+        // client should care about.
         return 0;
     }
     return err == 0 ? len : -err;
 }
 
-status_t BitTube::writeToParcel(Parcel* reply) const
-{
-    if (mReceiveFd < 0)
-        return -EINVAL;
+status_t BitTube::writeToParcel(Parcel* reply) const {
+    if (mReceiveFd < 0) return -EINVAL;
 
     status_t result = reply->writeDupFileDescriptor(mReceiveFd);
-    close(mReceiveFd);
-    mReceiveFd = -1;
+    mReceiveFd.reset();
     return result;
 }
 
+status_t BitTube::readFromParcel(const Parcel* parcel) {
+    mReceiveFd.reset(dup(parcel->readFileDescriptor()));
+    if (mReceiveFd < 0) {
+        mReceiveFd.reset();
+        int error = errno;
+        ALOGE("BitTube::readFromParcel: can't dup file descriptor (%s)", strerror(error));
+        return -error;
+    }
+    return NO_ERROR;
+}
 
-ssize_t BitTube::sendObjects(const sp<BitTube>& tube,
-        void const* events, size_t count, size_t objSize)
-{
+ssize_t BitTube::sendObjects(BitTube* tube, void const* events, size_t count, size_t objSize) {
     const char* vaddr = reinterpret_cast<const char*>(events);
-    ssize_t size = tube->write(vaddr, count*objSize);
+    ssize_t size = tube->write(vaddr, count * objSize);
 
     // should never happen because of SOCK_SEQPACKET
     LOG_ALWAYS_FATAL_IF((size >= 0) && (size % static_cast<ssize_t>(objSize)),
-            "BitTube::sendObjects(count=%zu, size=%zu), res=%zd (partial events were sent!)",
-            count, objSize, size);
+                        "BitTube::sendObjects(count=%zu, size=%zu), res=%zd (partial events were "
+                        "sent!)",
+                        count, objSize, size);
 
-    //ALOGE_IF(size<0, "error %d sending %d events", size, count);
+    // ALOGE_IF(size<0, "error %d sending %d events", size, count);
     return size < 0 ? size : size / static_cast<ssize_t>(objSize);
 }
 
-ssize_t BitTube::recvObjects(const sp<BitTube>& tube,
-        void* events, size_t count, size_t objSize)
-{
+ssize_t BitTube::recvObjects(BitTube* tube, void* events, size_t count, size_t objSize) {
     char* vaddr = reinterpret_cast<char*>(events);
-    ssize_t size = tube->read(vaddr, count*objSize);
+    ssize_t size = tube->read(vaddr, count * objSize);
 
     // should never happen because of SOCK_SEQPACKET
     LOG_ALWAYS_FATAL_IF((size >= 0) && (size % static_cast<ssize_t>(objSize)),
-            "BitTube::recvObjects(count=%zu, size=%zu), res=%zd (partial events were received!)",
-            count, objSize, size);
+                        "BitTube::recvObjects(count=%zu, size=%zu), res=%zd (partial events were "
+                        "received!)",
+                        count, objSize, size);
 
-    //ALOGE_IF(size<0, "error %d receiving %d events", size, count);
+    // ALOGE_IF(size<0, "error %d receiving %d events", size, count);
     return size < 0 ? size : size / static_cast<ssize_t>(objSize);
 }
 
-// ----------------------------------------------------------------------------
-}; // namespace android
+} // namespace gui
+} // namespace android
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index 5e3924a..69b5962 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -23,6 +23,21 @@
 
 namespace android {
 
+template<typename T>
+static inline constexpr uint32_t low32(const T n) {
+    return static_cast<uint32_t>(static_cast<uint64_t>(n));
+}
+
+template<typename T>
+static inline constexpr uint32_t high32(const T n) {
+    return static_cast<uint32_t>(static_cast<uint64_t>(n)>>32);
+}
+
+template<typename T>
+static inline constexpr T to64(const uint32_t lo, const uint32_t hi) {
+    return static_cast<T>(static_cast<uint64_t>(hi)<<32 | lo);
+}
+
 BufferItem::BufferItem() :
     mGraphicBuffer(NULL),
     mFence(NULL),
@@ -56,16 +71,19 @@
     addAligned(size, mCrop);
     addAligned(size, mTransform);
     addAligned(size, mScalingMode);
-    addAligned(size, mTimestampLo);
-    addAligned(size, mTimestampHi);
+    addAligned(size, low32(mTimestamp));
+    addAligned(size, high32(mTimestamp));
     addAligned(size, mIsAutoTimestamp);
     addAligned(size, mDataSpace);
-    addAligned(size, mFrameNumberLo);
-    addAligned(size, mFrameNumberHi);
+    addAligned(size, low32(mFrameNumber));
+    addAligned(size, high32(mFrameNumber));
     addAligned(size, mSlot);
     addAligned(size, mIsDroppable);
     addAligned(size, mAcquireCalled);
     addAligned(size, mTransformToDisplayInverse);
+    addAligned(size, mAutoRefresh);
+    addAligned(size, mQueuedBuffer);
+    addAligned(size, mIsStale);
     return size;
 }
 
@@ -73,11 +91,11 @@
     size_t size = sizeof(uint32_t); // Flags
     if (mGraphicBuffer != 0) {
         size += mGraphicBuffer->getFlattenedSize();
-        FlattenableUtils::align<4>(size);
+        size = FlattenableUtils::align<4>(size);
     }
     if (mFence != 0) {
         size += mFence->getFlattenedSize();
-        FlattenableUtils::align<4>(size);
+        size = FlattenableUtils::align<4>(size);
     }
     size += mSurfaceDamage.getFlattenedSize();
     size = FlattenableUtils::align<8>(size);
@@ -141,16 +159,19 @@
     writeAligned(buffer, size, mCrop);
     writeAligned(buffer, size, mTransform);
     writeAligned(buffer, size, mScalingMode);
-    writeAligned(buffer, size, mTimestampLo);
-    writeAligned(buffer, size, mTimestampHi);
+    writeAligned(buffer, size, low32(mTimestamp));
+    writeAligned(buffer, size, high32(mTimestamp));
     writeAligned(buffer, size, mIsAutoTimestamp);
     writeAligned(buffer, size, mDataSpace);
-    writeAligned(buffer, size, mFrameNumberLo);
-    writeAligned(buffer, size, mFrameNumberHi);
+    writeAligned(buffer, size, low32(mFrameNumber));
+    writeAligned(buffer, size, high32(mFrameNumber));
     writeAligned(buffer, size, mSlot);
     writeAligned(buffer, size, mIsDroppable);
     writeAligned(buffer, size, mAcquireCalled);
     writeAligned(buffer, size, mTransformToDisplayInverse);
+    writeAligned(buffer, size, mAutoRefresh);
+    writeAligned(buffer, size, mQueuedBuffer);
+    writeAligned(buffer, size, mIsStale);
 
     return NO_ERROR;
 }
@@ -183,6 +204,8 @@
         status_t err = mFence->unflatten(buffer, size, fds, count);
         if (err) return err;
         size -= FlattenableUtils::align<4>(buffer);
+
+        mFenceTime = std::make_shared<FenceTime>(mFence);
     }
 
     status_t err = mSurfaceDamage.unflatten(buffer, size);
@@ -194,19 +217,27 @@
         return NO_MEMORY;
     }
 
+    uint32_t timestampLo = 0, timestampHi = 0;
+    uint32_t frameNumberLo = 0, frameNumberHi = 0;
+
     readAligned(buffer, size, mCrop);
     readAligned(buffer, size, mTransform);
     readAligned(buffer, size, mScalingMode);
-    readAligned(buffer, size, mTimestampLo);
-    readAligned(buffer, size, mTimestampHi);
+    readAligned(buffer, size, timestampLo);
+    readAligned(buffer, size, timestampHi);
+    mTimestamp = to64<int64_t>(timestampLo, timestampHi);
     readAligned(buffer, size, mIsAutoTimestamp);
     readAligned(buffer, size, mDataSpace);
-    readAligned(buffer, size, mFrameNumberLo);
-    readAligned(buffer, size, mFrameNumberHi);
+    readAligned(buffer, size, frameNumberLo);
+    readAligned(buffer, size, frameNumberHi);
+    mFrameNumber = to64<uint64_t>(frameNumberLo, frameNumberHi);
     readAligned(buffer, size, mSlot);
     readAligned(buffer, size, mIsDroppable);
     readAligned(buffer, size, mAcquireCalled);
     readAligned(buffer, size, mTransformToDisplayInverse);
+    readAligned(buffer, size, mAutoRefresh);
+    readAligned(buffer, size, mQueuedBuffer);
+    readAligned(buffer, size, mIsStale);
 
     return NO_ERROR;
 }
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index 3491043..d9d50db 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -22,7 +22,7 @@
 #include <gui/BufferItem.h>
 #include <gui/BufferItemConsumer.h>
 
-//#define BI_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__)
+#define BI_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__)
 //#define BI_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__)
 //#define BI_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__)
 //#define BI_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__)
@@ -57,6 +57,12 @@
     mConsumer->setConsumerName(name);
 }
 
+void BufferItemConsumer::setBufferFreedListener(
+        const wp<BufferFreedListener>& listener) {
+    Mutex::Autolock _l(mMutex);
+    mBufferFreedListener = listener;
+}
+
 status_t BufferItemConsumer::acquireBuffer(BufferItem *item,
         nsecs_t presentWhen, bool waitForFence) {
     status_t err;
@@ -104,4 +110,14 @@
     return err;
 }
 
+void BufferItemConsumer::freeBufferLocked(int slotIndex) {
+    sp<BufferFreedListener> listener = mBufferFreedListener.promote();
+    if (listener != NULL && mSlots[slotIndex].mGraphicBuffer != NULL) {
+        // 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);
+    }
+    ConsumerBase::freeBufferLocked(slotIndex);
+}
+
 } // namespace android
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 6de98f5..4151212 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -31,6 +31,13 @@
 
 BufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {}
 
+void BufferQueue::ProxyConsumerListener::onDisconnect() {
+    sp<ConsumerListener> listener(mConsumerListener.promote());
+    if (listener != NULL) {
+        listener->onDisconnect();
+    }
+}
+
 void BufferQueue::ProxyConsumerListener::onFrameAvailable(
         const BufferItem& item) {
     sp<ConsumerListener> listener(mConsumerListener.promote());
@@ -61,28 +68,28 @@
     }
 }
 
-bool BufferQueue::ProxyConsumerListener::getFrameTimestamps(
-        uint64_t frameNumber, FrameTimestamps* outTimestamps) const {
+void BufferQueue::ProxyConsumerListener::addAndGetFrameTimestamps(
+        const NewFrameEventsEntry* newTimestamps,
+        FrameEventHistoryDelta* outDelta) {
     sp<ConsumerListener> listener(mConsumerListener.promote());
-    if (listener != NULL) {
-        return listener->getFrameTimestamps(frameNumber, outTimestamps);
+    if (listener != nullptr) {
+        listener->addAndGetFrameTimestamps(newTimestamps, outDelta);
     }
-    return false;
 }
 
 void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
         sp<IGraphicBufferConsumer>* outConsumer,
-        const sp<IGraphicBufferAlloc>& allocator) {
+        bool consumerIsSurfaceFlinger) {
     LOG_ALWAYS_FATAL_IF(outProducer == NULL,
             "BufferQueue: outProducer must not be NULL");
     LOG_ALWAYS_FATAL_IF(outConsumer == NULL,
             "BufferQueue: outConsumer must not be NULL");
 
-    sp<BufferQueueCore> core(new BufferQueueCore(allocator));
+    sp<BufferQueueCore> core(new BufferQueueCore());
     LOG_ALWAYS_FATAL_IF(core == NULL,
             "BufferQueue: failed to create BufferQueueCore");
 
-    sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core));
+    sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core, consumerIsSurfaceFlinger));
     LOG_ALWAYS_FATAL_IF(producer == NULL,
             "BufferQueue: failed to create BufferQueueProducer");
 
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 73d2042..5e5de44 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -205,6 +205,7 @@
             // was cached when it was last queued.
             outBuffer->mGraphicBuffer = mSlots[slot].mGraphicBuffer;
             outBuffer->mFence = Fence::NO_FENCE;
+            outBuffer->mFenceTime = FenceTime::NO_FENCE;
             outBuffer->mCrop = mCore->mSharedBufferCache.crop;
             outBuffer->mTransform = mCore->mSharedBufferCache.transform &
                     ~static_cast<uint32_t>(
@@ -259,7 +260,8 @@
         // decrease.
         mCore->mDequeueCondition.broadcast();
 
-        ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());
+        ATRACE_INT(mCore->mConsumerName.string(),
+                static_cast<int32_t>(mCore->mQueue.size()));
         mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size());
 
         VALIDATE_CONSISTENCY();
@@ -673,12 +675,13 @@
     return NO_ERROR;
 }
 
-void BufferQueueConsumer::setConsumerName(const String8& name) {
+status_t BufferQueueConsumer::setConsumerName(const String8& name) {
     ATRACE_CALL();
     BQ_LOGV("setConsumerName: '%s'", name.string());
     Mutex::Autolock lock(mCore->mMutex);
     mCore->mConsumerName = name;
     mConsumerName = name;
+    return NO_ERROR;
 }
 
 status_t BufferQueueConsumer::setDefaultBufferFormat(PixelFormat defaultFormat) {
@@ -706,6 +709,14 @@
     return NO_ERROR;
 }
 
+status_t BufferQueueConsumer::setConsumerIsProtected(bool isProtected) {
+    ATRACE_CALL();
+    BQ_LOGV("setConsumerIsProtected: %s", isProtected ? "true" : "false");
+    Mutex::Autolock lock(mCore->mMutex);
+    mCore->mConsumerIsProtected = isProtected;
+    return NO_ERROR;
+}
+
 status_t BufferQueueConsumer::setTransformHint(uint32_t hint) {
     ATRACE_CALL();
     BQ_LOGV("setTransformHint: %#x", hint);
@@ -714,9 +725,10 @@
     return NO_ERROR;
 }
 
-sp<NativeHandle> BufferQueueConsumer::getSidebandStream() const {
+status_t BufferQueueConsumer::getSidebandStream(sp<NativeHandle>* outStream) const {
     Mutex::Autolock lock(mCore->mMutex);
-    return mCore->mSidebandStream;
+    *outStream = mCore->mSidebandStream;
+    return NO_ERROR;
 }
 
 status_t BufferQueueConsumer::getOccupancyHistory(bool forceFlush,
@@ -732,19 +744,22 @@
     return NO_ERROR;
 }
 
-void BufferQueueConsumer::dump(String8& result, const char* prefix) const {
+status_t BufferQueueConsumer::dumpState(const String8& prefix, String8* outResult) const {
     const IPCThreadState* ipc = IPCThreadState::self();
     const pid_t pid = ipc->getCallingPid();
     const uid_t uid = ipc->getCallingUid();
     if ((uid != AID_SHELL)
             && !PermissionCache::checkPermission(String16(
             "android.permission.DUMP"), pid, uid)) {
-        result.appendFormat("Permission Denial: can't dump BufferQueueConsumer "
+        outResult->appendFormat("Permission Denial: can't dump BufferQueueConsumer "
                 "from pid=%d, uid=%d\n", pid, uid);
-        android_errorWriteWithInfoLog(0x534e4554, "27046057", uid, NULL, 0);
-    } else {
-        mCore->dump(result, prefix);
+        android_errorWriteWithInfoLog(0x534e4554, "27046057",
+                static_cast<int32_t>(uid), NULL, 0);
+        return PERMISSION_DENIED;
     }
+
+    mCore->dumpState(prefix, outResult);
+    return NO_ERROR;
 }
 
 } // namespace android
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index c4714e3..cfb25e0 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -28,10 +28,12 @@
 
 #include <inttypes.h>
 
+#include <cutils/properties.h>
+#include <cutils/atomic.h>
+
 #include <gui/BufferItem.h>
 #include <gui/BufferQueueCore.h>
 #include <gui/IConsumerListener.h>
-#include <gui/IGraphicBufferAlloc.h>
 #include <gui/IProducerListener.h>
 #include <gui/ISurfaceComposer.h>
 #include <private/gui/ComposerService.h>
@@ -50,14 +52,14 @@
     return id | counter++;
 }
 
-BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) :
-    mAllocator(allocator),
+BufferQueueCore::BufferQueueCore() :
     mMutex(),
     mIsAbandoned(false),
     mConsumerControlledByApp(false),
     mConsumerName(getUniqueName()),
     mConsumerListener(),
     mConsumerUsageBits(0),
+    mConsumerIsProtected(false),
     mConnectedApi(NO_CONNECTED_API),
     mLinkedToDeath(),
     mConnectedProducerListener(),
@@ -93,14 +95,6 @@
     mLastQueuedSlot(INVALID_BUFFER_SLOT),
     mUniqueId(getUniqueId())
 {
-    if (allocator == NULL) {
-        sp<ISurfaceComposer> composer(ComposerService::getComposerService());
-        mAllocator = composer->createGraphicBufferAlloc();
-        if (mAllocator == NULL) {
-            BQ_LOGE("createGraphicBufferAlloc failed");
-        }
-    }
-
     int numStartingBuffers = getMaxBufferCountLocked();
     for (int s = 0; s < numStartingBuffers; s++) {
         mFreeSlots.insert(s);
@@ -113,7 +107,7 @@
 
 BufferQueueCore::~BufferQueueCore() {}
 
-void BufferQueueCore::dump(String8& result, const char* prefix) const {
+void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const {
     Mutex::Autolock lock(mMutex);
 
     String8 fifo;
@@ -128,10 +122,10 @@
         ++current;
     }
 
-    result.appendFormat("%s-BufferQueue mMaxAcquiredBufferCount=%d, "
+    outResult->appendFormat("%s-BufferQueue mMaxAcquiredBufferCount=%d, "
             "mMaxDequeuedBufferCount=%d, mDequeueBufferCannotBlock=%d "
             "mAsyncMode=%d, default-size=[%dx%d], default-format=%d, "
-            "transform-hint=%02x, FIFO(%zu)={%s}\n", prefix,
+            "transform-hint=%02x, FIFO(%zu)={%s}\n", prefix.string(),
             mMaxAcquiredBufferCount, mMaxDequeuedBufferCount,
             mDequeueBufferCannotBlock, mAsyncMode, mDefaultWidth,
             mDefaultHeight, mDefaultBufferFormat, mTransformHint, mQueue.size(),
@@ -141,28 +135,28 @@
         const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
         // A dequeued buffer might be null if it's still being allocated
         if (buffer.get()) {
-            result.appendFormat("%s%s[%02d:%p] state=%-8s, %p "
-                    "[%4ux%4u:%4u,%3X]\n", prefix,
+            outResult->appendFormat("%s%s[%02d:%p] state=%-8s, %p "
+                    "[%4ux%4u:%4u,%3X]\n", prefix.string(),
                     (mSlots[s].mBufferState.isAcquired()) ? ">" : " ", s,
                     buffer.get(), mSlots[s].mBufferState.string(),
                     buffer->handle, buffer->width, buffer->height,
                     buffer->stride, buffer->format);
         } else {
-            result.appendFormat("%s [%02d:%p] state=%-8s\n", prefix, s,
+            outResult->appendFormat("%s [%02d:%p] state=%-8s\n", prefix.string(), s,
                     buffer.get(), mSlots[s].mBufferState.string());
         }
     }
     for (int s : mFreeBuffers) {
         const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
-        result.appendFormat("%s [%02d:%p] state=%-8s, %p [%4ux%4u:%4u,%3X]\n",
-                prefix, s, buffer.get(), mSlots[s].mBufferState.string(),
+        outResult->appendFormat("%s [%02d:%p] state=%-8s, %p [%4ux%4u:%4u,%3X]\n",
+                prefix.string(), s, buffer.get(), mSlots[s].mBufferState.string(),
                 buffer->handle, buffer->width, buffer->height, buffer->stride,
                 buffer->format);
     }
 
     for (int s : mFreeSlots) {
         const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
-        result.appendFormat("%s [%02d:%p] state=%-8s\n", prefix, s,
+        outResult->appendFormat("%s [%02d:%p] state=%-8s\n", prefix.string(), s,
                 buffer.get(), mSlots[s].mBufferState.string());
     }
 }
@@ -241,6 +235,13 @@
 
     for (auto& b : mQueue) {
         b.mIsStale = true;
+
+        // We set this to false to force the BufferQueue to resend the buffer
+        // handle upon acquire, since if we're here due to a producer
+        // disconnect, the consumer will have been told to purge its cache of
+        // slot-to-buffer-handle mappings and will not be able to otherwise
+        // obtain a valid buffer handle.
+        b.mAcquireCalled = false;
     }
 
     VALIDATE_CONSISTENCY();
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index ff85eb5..8385864 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -34,7 +34,6 @@
 #include <gui/BufferQueueProducer.h>
 #include <gui/GLConsumer.h>
 #include <gui/IConsumerListener.h>
-#include <gui/IGraphicBufferAlloc.h>
 #include <gui/IProducerListener.h>
 
 #include <utils/Log.h>
@@ -42,12 +41,17 @@
 
 namespace android {
 
-BufferQueueProducer::BufferQueueProducer(const sp<BufferQueueCore>& core) :
+static constexpr uint32_t BQ_LAYER_COUNT = 1;
+
+BufferQueueProducer::BufferQueueProducer(const sp<BufferQueueCore>& core,
+        bool consumerIsSurfaceFlinger) :
     mCore(core),
     mSlots(core->mSlots),
     mConsumerName(),
     mStickyTransform(0),
+    mConsumerIsSurfaceFlinger(consumerIsSurfaceFlinger),
     mLastQueueBufferFence(Fence::NO_FENCE),
+    mLastQueuedTransform(0),
     mCallbackMutex(),
     mNextCallbackTicket(0),
     mCurrentCallbackTicket(0),
@@ -343,7 +347,8 @@
 
 status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
         sp<android::Fence> *outFence, uint32_t width, uint32_t height,
-        PixelFormat format, uint32_t usage) {
+        PixelFormat format, uint32_t usage,
+        FrameEventHistoryDelta* outTimestamps) {
     ATRACE_CALL();
     { // Autolock scope
         Mutex::Autolock lock(mCore->mMutex);
@@ -411,7 +416,8 @@
             // buffer. If this buffer would require reallocation to meet the
             // requested attributes, we free it and attempt to get another one.
             if (!mCore->mAllowAllocation) {
-                if (buffer->needsReallocation(width, height, format, usage)) {
+                if (buffer->needsReallocation(width, height, format,
+                        BQ_LAYER_COUNT, usage)) {
                     if (mCore->mSharedBufferSlot == found) {
                         BQ_LOGE("dequeueBuffer: cannot re-allocate a shared"
                                 "buffer");
@@ -427,7 +433,8 @@
 
         const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
         if (mCore->mSharedBufferSlot == found &&
-                buffer->needsReallocation(width,  height, format, usage)) {
+                buffer->needsReallocation(width, height, format,
+                        BQ_LAYER_COUNT, usage)) {
             BQ_LOGE("dequeueBuffer: cannot re-allocate a shared"
                     "buffer");
 
@@ -446,7 +453,7 @@
         mSlots[found].mBufferState.dequeue();
 
         if ((buffer == NULL) ||
-                buffer->needsReallocation(width, height, format, usage))
+                buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage))
         {
             mSlots[found].mAcquireCalled = false;
             mSlots[found].mGraphicBuffer = NULL;
@@ -494,15 +501,17 @@
     } // Autolock scope
 
     if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
-        status_t error;
         BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
-        sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
-                width, height, format, usage,
-                {mConsumerName.string(), mConsumerName.size()}, &error));
+        sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
+                width, height, format, BQ_LAYER_COUNT, usage,
+                {mConsumerName.string(), mConsumerName.size()});
+
+        status_t error = graphicBuffer->initCheck();
+
         { // Autolock scope
             Mutex::Autolock lock(mCore->mMutex);
 
-            if (graphicBuffer != NULL && !mCore->mIsAbandoned) {
+            if (error == NO_ERROR && !mCore->mIsAbandoned) {
                 graphicBuffer->setGenerationNumber(mCore->mGenerationNumber);
                 mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
             }
@@ -510,7 +519,7 @@
             mCore->mIsAllocating = false;
             mCore->mIsAllocatingCondition.broadcast();
 
-            if (graphicBuffer == NULL) {
+            if (error != NO_ERROR) {
                 mCore->mFreeSlots.insert(*outSlot);
                 mCore->clearBufferSlotLocked(*outSlot);
                 BQ_LOGE("dequeueBuffer: createGraphicBuffer failed");
@@ -552,6 +561,8 @@
             mSlots[*outSlot].mFrameNumber,
             mSlots[*outSlot].mGraphicBuffer->handle, returnFlags);
 
+    addAndGetFrameTimestamps(nullptr, outTimestamps);
+
     return returnFlags;
 }
 
@@ -621,41 +632,49 @@
         return BAD_VALUE;
     }
 
-    Mutex::Autolock lock(mCore->mMutex);
+    sp<IConsumerListener> listener;
+    {
+        Mutex::Autolock lock(mCore->mMutex);
 
-    if (mCore->mIsAbandoned) {
-        BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned");
-        return NO_INIT;
+        if (mCore->mIsAbandoned) {
+            BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned");
+            return NO_INIT;
+        }
+
+        if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+            BQ_LOGE("detachNextBuffer: BufferQueue has no connected producer");
+            return NO_INIT;
+        }
+
+        if (mCore->mSharedBufferMode) {
+            BQ_LOGE("detachNextBuffer: cannot detach a buffer in shared buffer "
+                    "mode");
+            return BAD_VALUE;
+        }
+
+        mCore->waitWhileAllocatingLocked();
+
+        if (mCore->mFreeBuffers.empty()) {
+            return NO_MEMORY;
+        }
+
+        int found = mCore->mFreeBuffers.front();
+        mCore->mFreeBuffers.remove(found);
+        mCore->mFreeSlots.insert(found);
+
+        BQ_LOGV("detachNextBuffer detached slot %d", found);
+
+        *outBuffer = mSlots[found].mGraphicBuffer;
+        *outFence = mSlots[found].mFence;
+        mCore->clearBufferSlotLocked(found);
+        VALIDATE_CONSISTENCY();
+        listener = mCore->mConsumerListener;
     }
 
-    if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
-        BQ_LOGE("detachNextBuffer: BufferQueue has no connected producer");
-        return NO_INIT;
+    if (listener != NULL) {
+        listener->onBuffersReleased();
     }
 
-    if (mCore->mSharedBufferMode) {
-        BQ_LOGE("detachNextBuffer: cannot detach a buffer in shared buffer "
-            "mode");
-        return BAD_VALUE;
-    }
-
-    mCore->waitWhileAllocatingLocked();
-
-    if (mCore->mFreeBuffers.empty()) {
-        return NO_MEMORY;
-    }
-
-    int found = mCore->mFreeBuffers.front();
-    mCore->mFreeBuffers.remove(found);
-    mCore->mFreeSlots.insert(found);
-
-    BQ_LOGV("detachNextBuffer detached slot %d", found);
-
-    *outBuffer = mSlots[found].mGraphicBuffer;
-    *outFence = mSlots[found].mFence;
-    mCore->clearBufferSlotLocked(found);
-    VALIDATE_CONSISTENCY();
-
     return NO_ERROR;
 }
 
@@ -721,6 +740,7 @@
     mSlots[*outSlot].mFence = Fence::NO_FENCE;
     mSlots[*outSlot].mRequestBufferCalled = true;
     mSlots[*outSlot].mAcquireCalled = false;
+    mSlots[*outSlot].mNeedsReallocation = false;
     mCore->mActiveBuffers.insert(found);
     VALIDATE_CONSISTENCY();
 
@@ -732,23 +752,27 @@
     ATRACE_CALL();
     ATRACE_BUFFER_INDEX(slot);
 
-    int64_t timestamp;
+    int64_t requestedPresentTimestamp;
     bool isAutoTimestamp;
     android_dataspace dataSpace;
     Rect crop(Rect::EMPTY_RECT);
     int scalingMode;
     uint32_t transform;
     uint32_t stickyTransform;
-    sp<Fence> fence;
-    input.deflate(&timestamp, &isAutoTimestamp, &dataSpace, &crop, &scalingMode,
-            &transform, &fence, &stickyTransform);
+    sp<Fence> acquireFence;
+    bool getFrameTimestamps = false;
+    input.deflate(&requestedPresentTimestamp, &isAutoTimestamp, &dataSpace,
+            &crop, &scalingMode, &transform, &acquireFence, &stickyTransform,
+            &getFrameTimestamps);
     Region surfaceDamage = input.getSurfaceDamage();
 
-    if (fence == NULL) {
+    if (acquireFence == NULL) {
         BQ_LOGE("queueBuffer: fence is NULL");
         return BAD_VALUE;
     }
 
+    auto acquireFenceTime = std::make_shared<FenceTime>(acquireFence);
+
     switch (scalingMode) {
         case NATIVE_WINDOW_SCALING_MODE_FREEZE:
         case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
@@ -763,6 +787,7 @@
     sp<IConsumerListener> frameAvailableListener;
     sp<IConsumerListener> frameReplacedListener;
     int callbackTicket = 0;
+    uint64_t currentFrameNumber = 0;
     BufferItem item;
     { // Autolock scope
         Mutex::Autolock lock(mCore->mMutex);
@@ -801,8 +826,9 @@
 
         BQ_LOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 " dataSpace=%d"
                 " crop=[%d,%d,%d,%d] transform=%#x scale=%s",
-                slot, mCore->mFrameCounter + 1, timestamp, dataSpace,
-                crop.left, crop.top, crop.right, crop.bottom, transform,
+                slot, mCore->mFrameCounter + 1, requestedPresentTimestamp,
+                dataSpace, crop.left, crop.top, crop.right, crop.bottom,
+                transform,
                 BufferItem::scalingModeName(static_cast<uint32_t>(scalingMode)));
 
         const sp<GraphicBuffer>& graphicBuffer(mSlots[slot].mGraphicBuffer);
@@ -820,11 +846,14 @@
             dataSpace = mCore->mDefaultBufferDataSpace;
         }
 
-        mSlots[slot].mFence = fence;
+        mSlots[slot].mFence = acquireFence;
         mSlots[slot].mBufferState.queue();
 
+        // Increment the frame counter and store a local version of it
+        // for use outside the lock on mCore->mMutex.
         ++mCore->mFrameCounter;
-        mSlots[slot].mFrameNumber = mCore->mFrameCounter;
+        currentFrameNumber = mCore->mFrameCounter;
+        mSlots[slot].mFrameNumber = currentFrameNumber;
 
         item.mAcquireCalled = mSlots[slot].mAcquireCalled;
         item.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
@@ -834,12 +863,13 @@
         item.mTransformToDisplayInverse =
                 (transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0;
         item.mScalingMode = static_cast<uint32_t>(scalingMode);
-        item.mTimestamp = timestamp;
+        item.mTimestamp = requestedPresentTimestamp;
         item.mIsAutoTimestamp = isAutoTimestamp;
         item.mDataSpace = dataSpace;
-        item.mFrameNumber = mCore->mFrameCounter;
+        item.mFrameNumber = currentFrameNumber;
         item.mSlot = slot;
-        item.mFence = fence;
+        item.mFence = acquireFence;
+        item.mFenceTime = acquireFenceTime;
         item.mIsDroppable = mCore->mAsyncMode ||
                 mCore->mDequeueBufferCannotBlock ||
                 (mCore->mSharedBufferMode && mCore->mSharedBufferSlot == slot);
@@ -858,6 +888,7 @@
             mCore->mSharedBufferCache.dataspace = dataSpace;
         }
 
+        output->bufferReplaced = false;
         if (mCore->mQueue.empty()) {
             // When the queue is empty, we can ignore mDequeueBufferCannotBlock
             // and simply queue this buffer
@@ -884,6 +915,7 @@
                     if (!mSlots[last.mSlot].mBufferState.isShared()) {
                         mCore->mActiveBuffers.erase(last.mSlot);
                         mCore->mFreeBuffers.push_back(last.mSlot);
+                        output->bufferReplaced = true;
                     }
                 }
 
@@ -900,12 +932,14 @@
         mCore->mDequeueCondition.broadcast();
         mCore->mLastQueuedSlot = slot;
 
-        output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight,
-                mCore->mTransformHint,
-                static_cast<uint32_t>(mCore->mQueue.size()),
-                mCore->mFrameCounter + 1);
+        output->width = mCore->mDefaultWidth;
+        output->height = mCore->mDefaultHeight;
+        output->transformHint = mCore->mTransformHint;
+        output->numPendingBuffers = static_cast<uint32_t>(mCore->mQueue.size());
+        output->nextFrameNumber = mCore->mFrameCounter + 1;
 
-        ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());
+        ATRACE_INT(mCore->mConsumerName.string(),
+                static_cast<int32_t>(mCore->mQueue.size()));
         mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size());
 
         // Take a ticket for the callback functions
@@ -914,9 +948,14 @@
         VALIDATE_CONSISTENCY();
     } // Autolock scope
 
-    // Don't send the GraphicBuffer through the callback, and don't send
-    // the slot number, since the consumer shouldn't need it
-    item.mGraphicBuffer.clear();
+    // It is okay not to clear the GraphicBuffer when the consumer is SurfaceFlinger because
+    // it is guaranteed that the BufferQueue is inside SurfaceFlinger's process and
+    // there will be no Binder call
+    if (!mConsumerIsSurfaceFlinger) {
+        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
@@ -940,7 +979,7 @@
         connectedApi = mCore->mConnectedApi;
         lastQueuedFence = std::move(mLastQueueBufferFence);
 
-        mLastQueueBufferFence = std::move(fence);
+        mLastQueueBufferFence = std::move(acquireFence);
         mLastQueuedCrop = item.mCrop;
         mLastQueuedTransform = item.mTransform;
 
@@ -956,6 +995,17 @@
         lastQueuedFence->waitForever("Throttling EGL Production");
     }
 
+    // Update and get FrameEventHistory.
+    nsecs_t postedTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    NewFrameEventsEntry newFrameEventsEntry = {
+        currentFrameNumber,
+        postedTime,
+        requestedPresentTimestamp,
+        std::move(acquireFenceTime)
+    };
+    addAndGetFrameTimestamps(&newFrameEventsEntry,
+            getFrameTimestamps ? &output->frameTimestamps : nullptr);
+
     return NO_ERROR;
 }
 
@@ -1038,6 +1088,10 @@
         case NATIVE_WINDOW_FORMAT:
             value = static_cast<int32_t>(mCore->mDefaultBufferFormat);
             break;
+        case NATIVE_WINDOW_LAYER_COUNT:
+            // All BufferQueue buffers have a single layer.
+            value = BQ_LAYER_COUNT;
+            break;
         case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
             value = mCore->getMinUndequeuedBufferCountLocked();
             break;
@@ -1060,6 +1114,9 @@
                 value = static_cast<int32_t>(mCore->mBufferAge);
             }
             break;
+        case NATIVE_WINDOW_CONSUMER_IS_PROTECTED:
+            value = static_cast<int32_t>(mCore->mConsumerIsProtected);
+            break;
         default:
             return BAD_VALUE;
     }
@@ -1116,10 +1173,14 @@
         case NATIVE_WINDOW_API_MEDIA:
         case NATIVE_WINDOW_API_CAMERA:
             mCore->mConnectedApi = api;
-            output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight,
-                    mCore->mTransformHint,
-                    static_cast<uint32_t>(mCore->mQueue.size()),
-                    mCore->mFrameCounter + 1);
+
+            output->width = mCore->mDefaultWidth;
+            output->height = mCore->mDefaultHeight;
+            output->transformHint = mCore->mTransformHint;
+            output->numPendingBuffers =
+                    static_cast<uint32_t>(mCore->mQueue.size());
+            output->nextFrameNumber = mCore->mFrameCounter + 1;
+            output->bufferReplaced = false;
 
             if (listener != NULL) {
                 // Set up a death notification so that we can disconnect
@@ -1181,6 +1242,9 @@
         }
 
         if (api == BufferQueueCore::CURRENTLY_CONNECTED_API) {
+            if (mCore->mConnectedApi == NATIVE_WINDOW_API_MEDIA) {
+                ALOGD("About to force-disconnect API_MEDIA, mode=%d", mode);
+            }
             api = mCore->mConnectedApi;
             // If we're asked to disconnect the currently connected api but
             // nobody is connected, it's not really an error.
@@ -1215,7 +1279,10 @@
                     mCore->mSidebandStream.clear();
                     mCore->mDequeueCondition.broadcast();
                     listener = mCore->mConsumerListener;
-                } else if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
+                } else if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+                    BQ_LOGE("disconnect: not connected (req=%d)", api);
+                    status = NO_INIT;
+                } else {
                     BQ_LOGE("disconnect: still connected to another API "
                             "(cur=%d req=%d)", mCore->mConnectedApi, api);
                     status = BAD_VALUE;
@@ -1231,6 +1298,7 @@
     // Call back without lock held
     if (listener != NULL) {
         listener->onBuffersReleased();
+        listener->onDisconnect();
     }
 
     return status;
@@ -1284,10 +1352,12 @@
 
         Vector<sp<GraphicBuffer>> buffers;
         for (size_t i = 0; i <  newBufferCount; ++i) {
-            status_t result = NO_ERROR;
-            sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
-                    allocWidth, allocHeight, allocFormat, allocUsage,
-                    {mConsumerName.string(), mConsumerName.size()}, &result));
+            sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
+                    allocWidth, allocHeight, allocFormat, BQ_LAYER_COUNT,
+                    allocUsage, {mConsumerName.string(), mConsumerName.size()});
+
+            status_t result = graphicBuffer->initCheck();
+
             if (result != NO_ERROR) {
                 BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format"
                         " %u, usage %u)", width, height, format, usage);
@@ -1438,20 +1508,27 @@
     return NO_ERROR;
 }
 
-bool BufferQueueProducer::getFrameTimestamps(uint64_t frameNumber,
-        FrameTimestamps* outTimestamps) const {
-    ATRACE_CALL();
-    BQ_LOGV("getFrameTimestamps, %" PRIu64, frameNumber);
-    sp<IConsumerListener> listener;
+void BufferQueueProducer::getFrameTimestamps(FrameEventHistoryDelta* outDelta) {
+    addAndGetFrameTimestamps(nullptr, outDelta);
+}
 
+void BufferQueueProducer::addAndGetFrameTimestamps(
+        const NewFrameEventsEntry* newTimestamps,
+        FrameEventHistoryDelta* outDelta) {
+    if (newTimestamps == nullptr && outDelta == nullptr) {
+        return;
+    }
+
+    ATRACE_CALL();
+    BQ_LOGV("addAndGetFrameTimestamps");
+    sp<IConsumerListener> listener;
     {
         Mutex::Autolock lock(mCore->mMutex);
         listener = mCore->mConsumerListener;
     }
     if (listener != NULL) {
-        return listener->getFrameTimestamps(frameNumber, outTimestamps);
+        listener->addAndGetFrameTimestamps(newTimestamps, outDelta);
     }
-    return false;
 }
 
 void BufferQueueProducer::binderDied(const wp<android::IBinder>& /* who */) {
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 65e4fee..3d36376 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -27,8 +27,9 @@
 
 #include <hardware/hardware.h>
 
+#include <cutils/atomic.h>
+
 #include <gui/BufferItem.h>
-#include <gui/IGraphicBufferAlloc.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/SurfaceComposerClient.h>
 #include <gui/ConsumerBase.h>
@@ -56,7 +57,8 @@
 
 ConsumerBase::ConsumerBase(const sp<IGraphicBufferConsumer>& bufferQueue, bool controlledByApp) :
         mAbandoned(false),
-        mConsumer(bufferQueue) {
+        mConsumer(bufferQueue),
+        mPrevFinalReleaseFence(Fence::NO_FENCE) {
     // Choose a name using the PID and a process-unique ID.
     mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
 
@@ -104,7 +106,7 @@
 
     sp<FrameAvailableListener> listener;
     { // scope for the lock
-        Mutex::Autolock lock(mMutex);
+        Mutex::Autolock lock(mFrameAvailableMutex);
         listener = mFrameAvailableListener.promote();
     }
 
@@ -119,7 +121,7 @@
 
     sp<FrameAvailableListener> listener;
     {
-        Mutex::Autolock lock(mMutex);
+        Mutex::Autolock lock(mFrameAvailableMutex);
         listener = mFrameAvailableListener.promote();
     }
 
@@ -183,7 +185,7 @@
 void ConsumerBase::setFrameAvailableListener(
         const wp<FrameAvailableListener>& listener) {
     CB_LOGV("setFrameAvailableListener");
-    Mutex::Autolock lock(mMutex);
+    Mutex::Autolock lock(mFrameAvailableMutex);
     mFrameAvailableListener = listener;
 }
 
@@ -251,14 +253,25 @@
         CB_LOGE("discardFreeBuffers: ConsumerBase is abandoned!");
         return NO_INIT;
     }
-    return mConsumer->discardFreeBuffers();
+    status_t err = mConsumer->discardFreeBuffers();
+    if (err != OK) {
+        return err;
+    }
+    uint64_t mask;
+    mConsumer->getReleasedBuffers(&mask);
+    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+        if (mask & (1ULL << i)) {
+            freeBufferLocked(i);
+        }
+    }
+    return OK;
 }
 
-void ConsumerBase::dump(String8& result) const {
-    dump(result, "");
+void ConsumerBase::dumpState(String8& result) const {
+    dumpState(result, "");
 }
 
-void ConsumerBase::dump(String8& result, const char* prefix) const {
+void ConsumerBase::dumpState(String8& result, const char* prefix) const {
     Mutex::Autolock _l(mMutex);
     dumpLocked(result, prefix);
 }
@@ -267,7 +280,9 @@
     result.appendFormat("%smAbandoned=%d\n", prefix, int(mAbandoned));
 
     if (!mAbandoned) {
-        mConsumer->dump(result, prefix);
+        String8 consumerState;
+        mConsumer->dumpState(String8(prefix), &consumerState);
+        result.append(consumerState);
     }
 }
 
@@ -284,6 +299,9 @@
     }
 
     if (item->mGraphicBuffer != NULL) {
+        if (mSlots[item->mSlot].mGraphicBuffer != NULL) {
+            freeBufferLocked(item->mSlot);
+        }
         mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer;
     }
 
@@ -317,16 +335,16 @@
         return OK;
     }
 
-    auto signaled = mSlots[slot].mFence->hasSignaled();
+    auto status = mSlots[slot].mFence->getStatus();
 
-    if (!signaled) {
+    if (status == Fence::Status::Invalid) {
         CB_LOGE("fence has invalid state");
         return BAD_VALUE;
     }
 
-    if (*signaled) {
+    if (status == Fence::Status::Signaled) {
         mSlots[slot].mFence = fence;
-    } else {
+    } else {  // status == Fence::Status::Unsignaled
         char fenceName[32] = {};
         snprintf(fenceName, 32, "%.28s:%d", mName.string(), slot);
         sp<Fence> mergedFence = Fence::merge(
@@ -366,6 +384,7 @@
         freeBufferLocked(slot);
     }
 
+    mPrevFinalReleaseFence = mSlots[slot].mFence;
     mSlots[slot].mFence = Fence::NO_FENCE;
 
     return err;
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index 8393160..ae7c65c 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -64,6 +64,8 @@
     switch (static_cast<int>(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_BGRA_8888:
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index 9973e8d..1757ec1 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -18,25 +18,27 @@
 
 #include <utils/Errors.h>
 
-#include <gui/BitTube.h>
 #include <gui/DisplayEventReceiver.h>
 #include <gui/IDisplayEventConnection.h>
 #include <gui/ISurfaceComposer.h>
 
 #include <private/gui/ComposerService.h>
 
+#include <private/gui/BitTube.h>
+
 // ---------------------------------------------------------------------------
 
 namespace android {
 
 // ---------------------------------------------------------------------------
 
-DisplayEventReceiver::DisplayEventReceiver() {
+DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) {
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
     if (sf != NULL) {
-        mEventConnection = sf->createDisplayEventConnection();
+        mEventConnection = sf->createDisplayEventConnection(vsyncSource);
         if (mEventConnection != NULL) {
-            mDataChannel = mEventConnection->getDataChannel();
+            mDataChannel = std::make_unique<gui::BitTube>();
+            mEventConnection->stealReceiveChannel(mDataChannel.get());
         }
     }
 }
@@ -79,19 +81,19 @@
 
 ssize_t DisplayEventReceiver::getEvents(DisplayEventReceiver::Event* events,
         size_t count) {
-    return DisplayEventReceiver::getEvents(mDataChannel, events, count);
+    return DisplayEventReceiver::getEvents(mDataChannel.get(), events, count);
 }
 
-ssize_t DisplayEventReceiver::getEvents(const sp<BitTube>& dataChannel,
+ssize_t DisplayEventReceiver::getEvents(gui::BitTube* dataChannel,
         Event* events, size_t count)
 {
-    return BitTube::recvObjects(dataChannel, events, count);
+    return gui::BitTube::recvObjects(dataChannel, events, count);
 }
 
-ssize_t DisplayEventReceiver::sendEvents(const sp<BitTube>& dataChannel,
+ssize_t DisplayEventReceiver::sendEvents(gui::BitTube* dataChannel,
         Event const* events, size_t count)
 {
-    return BitTube::sendObjects(dataChannel, events, count);
+    return gui::BitTube::sendObjects(dataChannel, events, count);
 }
 
 // ---------------------------------------------------------------------------
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
new file mode 100644
index 0000000..fccca97
--- /dev/null
+++ b/libs/gui/FrameTimestamps.cpp
@@ -0,0 +1,701 @@
+/*
+* 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/FrameTimestamps.h>
+
+#define LOG_TAG "FrameEvents"
+
+#include <cutils/compiler.h>  // For CC_[UN]LIKELY
+#include <inttypes.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include <algorithm>
+#include <limits>
+#include <numeric>
+
+namespace android {
+
+
+// ============================================================================
+// FrameEvents
+// ============================================================================
+
+bool FrameEvents::hasPostedInfo() const {
+    return FrameEvents::isValidTimestamp(postedTime);
+}
+
+bool FrameEvents::hasRequestedPresentInfo() const {
+    return FrameEvents::isValidTimestamp(requestedPresentTime);
+}
+
+bool FrameEvents::hasLatchInfo() const {
+    return FrameEvents::isValidTimestamp(latchTime);
+}
+
+bool FrameEvents::hasFirstRefreshStartInfo() const {
+    return FrameEvents::isValidTimestamp(firstRefreshStartTime);
+}
+
+bool FrameEvents::hasLastRefreshStartInfo() const {
+    // The last refresh start time may continue to update until a new frame
+    // is latched. We know we have the final value once the release info is set.
+    return addReleaseCalled;
+}
+
+bool FrameEvents::hasDequeueReadyInfo() const {
+    return FrameEvents::isValidTimestamp(dequeueReadyTime);
+}
+
+bool FrameEvents::hasAcquireInfo() const {
+    return acquireFence->isValid();
+}
+
+bool FrameEvents::hasGpuCompositionDoneInfo() const {
+    // We may not get a gpuCompositionDone in addPostComposite if
+    // client/gles compositing isn't needed.
+    return addPostCompositeCalled;
+}
+
+bool FrameEvents::hasDisplayPresentInfo() const {
+    // We may not get a displayPresent in addPostComposite for HWC1.
+    return addPostCompositeCalled;
+}
+
+bool FrameEvents::hasReleaseInfo() const {
+    return addReleaseCalled;
+}
+
+void FrameEvents::checkFencesForCompletion() {
+    acquireFence->getSignalTime();
+    gpuCompositionDoneFence->getSignalTime();
+    displayPresentFence->getSignalTime();
+    releaseFence->getSignalTime();
+}
+
+static void dumpFenceTime(String8& outString, const char* name,
+        bool pending, const FenceTime& fenceTime) {
+    outString.appendFormat("--- %s", name);
+    nsecs_t signalTime = fenceTime.getCachedSignalTime();
+    if (Fence::isValidTimestamp(signalTime)) {
+        outString.appendFormat("%" PRId64 "\n", signalTime);
+    } else if (pending || signalTime == Fence::SIGNAL_TIME_PENDING) {
+        outString.appendFormat("Pending\n");
+    } else if (&fenceTime == FenceTime::NO_FENCE.get()){
+        outString.appendFormat("N/A\n");
+    } else {
+        outString.appendFormat("Error\n");
+    }
+}
+
+void FrameEvents::dump(String8& 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);
+
+    outString.appendFormat("--- Latched     \t");
+    if (FrameEvents::isValidTimestamp(latchTime)) {
+        outString.appendFormat("%" PRId64 "\n", latchTime);
+    } else {
+        outString.appendFormat("Pending\n");
+    }
+
+    outString.appendFormat("--- Refresh (First)\t");
+    if (FrameEvents::isValidTimestamp(firstRefreshStartTime)) {
+        outString.appendFormat("%" PRId64 "\n", firstRefreshStartTime);
+    } else {
+        outString.appendFormat("Pending\n");
+    }
+
+    outString.appendFormat("--- Refresh (Last)\t");
+    if (FrameEvents::isValidTimestamp(lastRefreshStartTime)) {
+        outString.appendFormat("%" PRId64 "\n", lastRefreshStartTime);
+    } else {
+        outString.appendFormat("Pending\n");
+    }
+
+    dumpFenceTime(outString, "Acquire           \t",
+            true, *acquireFence);
+    dumpFenceTime(outString, "GPU Composite Done\t",
+            !addPostCompositeCalled, *gpuCompositionDoneFence);
+    dumpFenceTime(outString, "Display Present   \t",
+            !addPostCompositeCalled, *displayPresentFence);
+
+    outString.appendFormat("--- DequeueReady  \t");
+    if (FrameEvents::isValidTimestamp(dequeueReadyTime)) {
+        outString.appendFormat("%" PRId64 "\n", dequeueReadyTime);
+    } else {
+        outString.appendFormat("Pending\n");
+    }
+
+    dumpFenceTime(outString, "Release           \t",
+            true, *releaseFence);
+}
+
+
+// ============================================================================
+// FrameEventHistory
+// ============================================================================
+
+namespace {
+
+struct FrameNumberEqual {
+    FrameNumberEqual(uint64_t frameNumber) : mFrameNumber(frameNumber) {}
+    bool operator()(const FrameEvents& frame) {
+        return frame.valid && mFrameNumber == frame.frameNumber;
+    }
+    const uint64_t mFrameNumber;
+};
+
+}  // namespace
+
+FrameEventHistory::~FrameEventHistory() = default;
+
+FrameEvents* FrameEventHistory::getFrame(uint64_t frameNumber) {
+    auto frame = std::find_if(
+            mFrames.begin(), mFrames.end(), FrameNumberEqual(frameNumber));
+    return frame == mFrames.end() ? nullptr : &(*frame);
+}
+
+FrameEvents* FrameEventHistory::getFrame(uint64_t frameNumber, size_t* iHint) {
+    *iHint = std::min(*iHint, mFrames.size());
+    auto hint = mFrames.begin() + *iHint;
+    auto frame = std::find_if(
+            hint, mFrames.end(), FrameNumberEqual(frameNumber));
+    if (frame == mFrames.end()) {
+        frame = std::find_if(
+                mFrames.begin(), hint, FrameNumberEqual(frameNumber));
+        if (frame == hint) {
+            return nullptr;
+        }
+    }
+    *iHint = static_cast<size_t>(std::distance(mFrames.begin(), frame));
+    return &(*frame);
+}
+
+void FrameEventHistory::checkFencesForCompletion() {
+    for (auto& frame : mFrames) {
+        frame.checkFencesForCompletion();
+    }
+}
+
+// Uses !|valid| as the MSB.
+static bool FrameNumberLessThan(
+        const FrameEvents& lhs, const FrameEvents& rhs) {
+    if (lhs.valid == rhs.valid) {
+        return lhs.frameNumber < rhs.frameNumber;
+    }
+    return lhs.valid;
+}
+
+void FrameEventHistory::dump(String8& outString) const {
+    auto earliestFrame = std::min_element(
+            mFrames.begin(), mFrames.end(), &FrameNumberLessThan);
+    if (!earliestFrame->valid) {
+        outString.appendFormat("-- N/A\n");
+        return;
+    }
+    for (auto frame = earliestFrame; frame != mFrames.end(); ++frame) {
+        frame->dump(outString);
+    }
+    for (auto frame = mFrames.begin(); frame != earliestFrame; ++frame) {
+        frame->dump(outString);
+    }
+}
+
+
+// ============================================================================
+// ProducerFrameEventHistory
+// ============================================================================
+
+ProducerFrameEventHistory::~ProducerFrameEventHistory() = default;
+
+nsecs_t ProducerFrameEventHistory::snapToNextTick(
+        nsecs_t timestamp, nsecs_t tickPhase, nsecs_t tickInterval) {
+    nsecs_t tickOffset = (tickPhase - timestamp) % tickInterval;
+    // Integer modulo rounds towards 0 and not -inf before taking the remainder,
+    // so adjust the offset if it is negative.
+    if (tickOffset < 0) {
+        tickOffset += tickInterval;
+    }
+    return timestamp + tickOffset;
+}
+
+nsecs_t ProducerFrameEventHistory::getNextCompositeDeadline(
+        const nsecs_t now) const{
+    return snapToNextTick(
+            now, mCompositorTiming.deadline, mCompositorTiming.interval);
+}
+
+void ProducerFrameEventHistory::updateAcquireFence(
+        uint64_t frameNumber, std::shared_ptr<FenceTime>&& acquire) {
+    FrameEvents* frame = getFrame(frameNumber, &mAcquireOffset);
+    if (frame == nullptr) {
+        ALOGE("updateAcquireFence: Did not find frame.");
+        return;
+    }
+
+    if (acquire->isValid()) {
+        mAcquireTimeline.push(acquire);
+        frame->acquireFence = std::move(acquire);
+    } else {
+        // If there isn't an acquire fence, assume that buffer was
+        // ready for the consumer when posted.
+        frame->acquireFence = std::make_shared<FenceTime>(frame->postedTime);
+    }
+}
+
+void ProducerFrameEventHistory::applyDelta(
+        const FrameEventHistoryDelta& delta) {
+    mCompositorTiming = delta.mCompositorTiming;
+
+    for (auto& d : delta.mDeltas) {
+        // Avoid out-of-bounds access.
+        if (CC_UNLIKELY(d.mIndex >= mFrames.size())) {
+            ALOGE("applyDelta: Bad index.");
+            return;
+        }
+
+        FrameEvents& frame = mFrames[d.mIndex];
+
+        frame.addPostCompositeCalled = d.mAddPostCompositeCalled != 0;
+        frame.addReleaseCalled = d.mAddReleaseCalled != 0;
+
+        frame.postedTime = d.mPostedTime;
+        frame.requestedPresentTime = d.mRequestedPresentTime;
+        frame.latchTime = d.mLatchTime;
+        frame.firstRefreshStartTime = d.mFirstRefreshStartTime;
+        frame.lastRefreshStartTime = d.mLastRefreshStartTime;
+        frame.dequeueReadyTime = d.mDequeueReadyTime;
+
+        if (frame.frameNumber != d.mFrameNumber) {
+            // We got a new frame. Initialize some of the fields.
+            frame.frameNumber = d.mFrameNumber;
+            frame.acquireFence = FenceTime::NO_FENCE;
+            frame.gpuCompositionDoneFence = FenceTime::NO_FENCE;
+            frame.displayPresentFence = FenceTime::NO_FENCE;
+            frame.releaseFence = FenceTime::NO_FENCE;
+            // The consumer only sends valid frames.
+            frame.valid = true;
+        }
+
+        applyFenceDelta(&mGpuCompositionDoneTimeline,
+                &frame.gpuCompositionDoneFence, d.mGpuCompositionDoneFence);
+        applyFenceDelta(&mPresentTimeline,
+                &frame.displayPresentFence, d.mDisplayPresentFence);
+        applyFenceDelta(&mReleaseTimeline,
+                &frame.releaseFence, d.mReleaseFence);
+    }
+}
+
+void ProducerFrameEventHistory::updateSignalTimes() {
+    mAcquireTimeline.updateSignalTimes();
+    mGpuCompositionDoneTimeline.updateSignalTimes();
+    mPresentTimeline.updateSignalTimes();
+    mReleaseTimeline.updateSignalTimes();
+}
+
+void ProducerFrameEventHistory::applyFenceDelta(FenceTimeline* timeline,
+        std::shared_ptr<FenceTime>* dst, const FenceTime::Snapshot& src) const {
+    if (CC_UNLIKELY(dst == nullptr || dst->get() == nullptr)) {
+        ALOGE("applyFenceDelta: dst is null.");
+        return;
+    }
+
+    switch (src.state) {
+        case FenceTime::Snapshot::State::EMPTY:
+            return;
+        case FenceTime::Snapshot::State::FENCE:
+            ALOGE_IF((*dst)->isValid(), "applyFenceDelta: Unexpected fence.");
+            *dst = createFenceTime(src.fence);
+            timeline->push(*dst);
+            return;
+        case FenceTime::Snapshot::State::SIGNAL_TIME:
+            if ((*dst)->isValid()) {
+                (*dst)->applyTrustedSnapshot(src);
+            } else {
+                *dst = std::make_shared<FenceTime>(src.signalTime);
+            }
+            return;
+    }
+}
+
+std::shared_ptr<FenceTime> ProducerFrameEventHistory::createFenceTime(
+        const sp<Fence>& fence) const {
+    return std::make_shared<FenceTime>(fence);
+}
+
+
+// ============================================================================
+// ConsumerFrameEventHistory
+// ============================================================================
+
+ConsumerFrameEventHistory::~ConsumerFrameEventHistory() = default;
+
+void ConsumerFrameEventHistory::onDisconnect() {
+    mCurrentConnectId++;
+    mProducerWantsEvents = false;
+}
+
+void ConsumerFrameEventHistory::initializeCompositorTiming(
+        const CompositorTiming& compositorTiming) {
+    mCompositorTiming = compositorTiming;
+}
+
+void ConsumerFrameEventHistory::addQueue(const NewFrameEventsEntry& newEntry) {
+    // Overwrite all fields of the frame with default values unless set here.
+    FrameEvents newTimestamps;
+    newTimestamps.connectId = mCurrentConnectId;
+    newTimestamps.frameNumber = newEntry.frameNumber;
+    newTimestamps.postedTime = newEntry.postedTime;
+    newTimestamps.requestedPresentTime = newEntry.requestedPresentTime;
+    newTimestamps.acquireFence = newEntry.acquireFence;
+    newTimestamps.valid = true;
+    mFrames[mQueueOffset] = newTimestamps;
+
+    // Note: We avoid sending the acquire fence back to the caller since
+    // they have the original one already, so there is no need to set the
+    // acquire dirty bit.
+    mFramesDirty[mQueueOffset].setDirty<FrameEvent::POSTED>();
+
+    mQueueOffset = (mQueueOffset + 1) % mFrames.size();
+}
+
+void ConsumerFrameEventHistory::addLatch(
+        uint64_t frameNumber, nsecs_t latchTime) {
+    FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset);
+    if (frame == nullptr) {
+        ALOGE_IF(mProducerWantsEvents, "addLatch: Did not find frame.");
+        return;
+    }
+    frame->latchTime = latchTime;
+    mFramesDirty[mCompositionOffset].setDirty<FrameEvent::LATCH>();
+}
+
+void ConsumerFrameEventHistory::addPreComposition(
+        uint64_t frameNumber, nsecs_t refreshStartTime) {
+    FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset);
+    if (frame == nullptr) {
+        ALOGE_IF(mProducerWantsEvents,
+                "addPreComposition: Did not find frame.");
+        return;
+    }
+    frame->lastRefreshStartTime = refreshStartTime;
+    mFramesDirty[mCompositionOffset].setDirty<FrameEvent::LAST_REFRESH_START>();
+    if (!FrameEvents::isValidTimestamp(frame->firstRefreshStartTime)) {
+        frame->firstRefreshStartTime = refreshStartTime;
+        mFramesDirty[mCompositionOffset].setDirty<FrameEvent::FIRST_REFRESH_START>();
+    }
+}
+
+void ConsumerFrameEventHistory::addPostComposition(uint64_t frameNumber,
+        const std::shared_ptr<FenceTime>& gpuCompositionDone,
+        const std::shared_ptr<FenceTime>& displayPresent,
+        const CompositorTiming& compositorTiming) {
+    mCompositorTiming = compositorTiming;
+
+    FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset);
+    if (frame == nullptr) {
+        ALOGE_IF(mProducerWantsEvents,
+                "addPostComposition: Did not find frame.");
+        return;
+    }
+    // Only get GPU and present info for the first composite.
+    if (!frame->addPostCompositeCalled) {
+        frame->addPostCompositeCalled = true;
+        frame->gpuCompositionDoneFence = gpuCompositionDone;
+        mFramesDirty[mCompositionOffset].setDirty<FrameEvent::GPU_COMPOSITION_DONE>();
+        if (!frame->displayPresentFence->isValid()) {
+            frame->displayPresentFence = displayPresent;
+            mFramesDirty[mCompositionOffset].setDirty<FrameEvent::DISPLAY_PRESENT>();
+        }
+    }
+}
+
+void ConsumerFrameEventHistory::addRelease(uint64_t frameNumber,
+        nsecs_t dequeueReadyTime, std::shared_ptr<FenceTime>&& release) {
+    FrameEvents* frame = getFrame(frameNumber, &mReleaseOffset);
+    if (frame == nullptr) {
+        ALOGE_IF(mProducerWantsEvents, "addRelease: Did not find frame.");
+        return;
+    }
+    frame->addReleaseCalled = true;
+    frame->dequeueReadyTime = dequeueReadyTime;
+    frame->releaseFence = std::move(release);
+    mFramesDirty[mReleaseOffset].setDirty<FrameEvent::RELEASE>();
+}
+
+void ConsumerFrameEventHistory::getFrameDelta(
+        FrameEventHistoryDelta* delta,
+        const std::array<FrameEvents, MAX_FRAME_HISTORY>::iterator& frame) {
+    mProducerWantsEvents = true;
+    size_t i = static_cast<size_t>(std::distance(mFrames.begin(), frame));
+    if (mFramesDirty[i].anyDirty()) {
+        // Make sure only to send back deltas for the current connection
+        // since the producer won't have the correct state to apply a delta
+        // from a previous connection.
+        if (mFrames[i].connectId == mCurrentConnectId) {
+            delta->mDeltas.emplace_back(i, *frame, mFramesDirty[i]);
+        }
+        mFramesDirty[i].reset();
+    }
+}
+
+void ConsumerFrameEventHistory::getAndResetDelta(
+        FrameEventHistoryDelta* delta) {
+    mProducerWantsEvents = true;
+    delta->mCompositorTiming = mCompositorTiming;
+
+    // Write these in order of frame number so that it is easy to
+    // add them to a FenceTimeline in the proper order producer side.
+    delta->mDeltas.reserve(mFramesDirty.size());
+    auto earliestFrame = std::min_element(
+            mFrames.begin(), mFrames.end(), &FrameNumberLessThan);
+    for (auto frame = earliestFrame; frame != mFrames.end(); ++frame) {
+        getFrameDelta(delta, frame);
+    }
+    for (auto frame = mFrames.begin(); frame != earliestFrame; ++frame) {
+        getFrameDelta(delta, frame);
+    }
+}
+
+
+// ============================================================================
+// FrameEventsDelta
+// ============================================================================
+
+FrameEventsDelta::FrameEventsDelta(
+        size_t index,
+        const FrameEvents& frameTimestamps,
+        const FrameEventDirtyFields& dirtyFields)
+    : mIndex(index),
+      mFrameNumber(frameTimestamps.frameNumber),
+      mAddPostCompositeCalled(frameTimestamps.addPostCompositeCalled),
+      mAddReleaseCalled(frameTimestamps.addReleaseCalled),
+      mPostedTime(frameTimestamps.postedTime),
+      mRequestedPresentTime(frameTimestamps.requestedPresentTime),
+      mLatchTime(frameTimestamps.latchTime),
+      mFirstRefreshStartTime(frameTimestamps.firstRefreshStartTime),
+      mLastRefreshStartTime(frameTimestamps.lastRefreshStartTime),
+      mDequeueReadyTime(frameTimestamps.dequeueReadyTime) {
+    if (dirtyFields.isDirty<FrameEvent::GPU_COMPOSITION_DONE>()) {
+        mGpuCompositionDoneFence =
+                frameTimestamps.gpuCompositionDoneFence->getSnapshot();
+    }
+    if (dirtyFields.isDirty<FrameEvent::DISPLAY_PRESENT>()) {
+        mDisplayPresentFence =
+                frameTimestamps.displayPresentFence->getSnapshot();
+    }
+    if (dirtyFields.isDirty<FrameEvent::RELEASE>()) {
+        mReleaseFence = frameTimestamps.releaseFence->getSnapshot();
+    }
+}
+
+constexpr size_t FrameEventsDelta::minFlattenedSize() {
+    return sizeof(FrameEventsDelta::mFrameNumber) +
+            sizeof(uint16_t) + // mIndex
+            sizeof(uint8_t) + // mAddPostCompositeCalled
+            sizeof(uint8_t) + // mAddReleaseCalled
+            sizeof(FrameEventsDelta::mPostedTime) +
+            sizeof(FrameEventsDelta::mRequestedPresentTime) +
+            sizeof(FrameEventsDelta::mLatchTime) +
+            sizeof(FrameEventsDelta::mFirstRefreshStartTime) +
+            sizeof(FrameEventsDelta::mLastRefreshStartTime) +
+            sizeof(FrameEventsDelta::mDequeueReadyTime);
+}
+
+// Flattenable implementation
+size_t FrameEventsDelta::getFlattenedSize() const {
+    auto fences = allFences(this);
+    return minFlattenedSize() +
+            std::accumulate(fences.begin(), fences.end(), size_t(0),
+                    [](size_t a, const FenceTime::Snapshot* fence) {
+                            return a + fence->getFlattenedSize();
+                    });
+}
+
+size_t FrameEventsDelta::getFdCount() const {
+    auto fences = allFences(this);
+    return std::accumulate(fences.begin(), fences.end(), size_t(0),
+            [](size_t a, const FenceTime::Snapshot* fence) {
+                return a + fence->getFdCount();
+            });
+}
+
+status_t FrameEventsDelta::flatten(void*& buffer, size_t& size, int*& fds,
+            size_t& count) const {
+    if (size < getFlattenedSize() || count < getFdCount()) {
+        return NO_MEMORY;
+    }
+
+    if (mIndex >= FrameEventHistory::MAX_FRAME_HISTORY ||
+            mIndex > std::numeric_limits<uint16_t>::max()) {
+        return BAD_VALUE;
+    }
+
+    FlattenableUtils::write(buffer, size, mFrameNumber);
+
+    // These are static_cast to uint16_t/uint8_t for alignment.
+    FlattenableUtils::write(buffer, size, static_cast<uint16_t>(mIndex));
+    FlattenableUtils::write(
+            buffer, size, static_cast<uint8_t>(mAddPostCompositeCalled));
+    FlattenableUtils::write(
+            buffer, size, static_cast<uint8_t>(mAddReleaseCalled));
+
+    FlattenableUtils::write(buffer, size, mPostedTime);
+    FlattenableUtils::write(buffer, size, mRequestedPresentTime);
+    FlattenableUtils::write(buffer, size, mLatchTime);
+    FlattenableUtils::write(buffer, size, mFirstRefreshStartTime);
+    FlattenableUtils::write(buffer, size, mLastRefreshStartTime);
+    FlattenableUtils::write(buffer, size, mDequeueReadyTime);
+
+    // Fences
+    for (auto fence : allFences(this)) {
+        status_t status = fence->flatten(buffer, size, fds, count);
+        if (status != NO_ERROR) {
+            return status;
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t FrameEventsDelta::unflatten(void const*& buffer, size_t& size,
+            int const*& fds, size_t& count) {
+    if (size < minFlattenedSize()) {
+        return NO_MEMORY;
+    }
+
+    FlattenableUtils::read(buffer, size, mFrameNumber);
+
+    // These were written as uint16_t/uint8_t for alignment.
+    uint16_t temp16 = 0;
+    FlattenableUtils::read(buffer, size, temp16);
+    mIndex = temp16;
+    if (mIndex >= FrameEventHistory::MAX_FRAME_HISTORY) {
+        return BAD_VALUE;
+    }
+    uint8_t temp8 = 0;
+    FlattenableUtils::read(buffer, size, temp8);
+    mAddPostCompositeCalled = static_cast<bool>(temp8);
+    FlattenableUtils::read(buffer, size, temp8);
+    mAddReleaseCalled = static_cast<bool>(temp8);
+
+    FlattenableUtils::read(buffer, size, mPostedTime);
+    FlattenableUtils::read(buffer, size, mRequestedPresentTime);
+    FlattenableUtils::read(buffer, size, mLatchTime);
+    FlattenableUtils::read(buffer, size, mFirstRefreshStartTime);
+    FlattenableUtils::read(buffer, size, mLastRefreshStartTime);
+    FlattenableUtils::read(buffer, size, mDequeueReadyTime);
+
+    // Fences
+    for (auto fence : allFences(this)) {
+        status_t status = fence->unflatten(buffer, size, fds, count);
+        if (status != NO_ERROR) {
+            return status;
+        }
+    }
+    return NO_ERROR;
+}
+
+
+// ============================================================================
+// FrameEventHistoryDelta
+// ============================================================================
+
+FrameEventHistoryDelta& FrameEventHistoryDelta::operator=(
+        FrameEventHistoryDelta&& src) {
+    mCompositorTiming = src.mCompositorTiming;
+
+    if (CC_UNLIKELY(!mDeltas.empty())) {
+        ALOGE("FrameEventHistoryDelta assign clobbering history.");
+    }
+    mDeltas = std::move(src.mDeltas);
+    ALOGE_IF(src.mDeltas.empty(), "Source mDeltas not empty.");
+    return *this;
+}
+
+constexpr size_t FrameEventHistoryDelta::minFlattenedSize() {
+    return sizeof(uint32_t) + // mDeltas.size()
+            sizeof(mCompositorTiming);
+}
+
+size_t FrameEventHistoryDelta::getFlattenedSize() const {
+    return minFlattenedSize() +
+            std::accumulate(mDeltas.begin(), mDeltas.end(), size_t(0),
+                    [](size_t a, const FrameEventsDelta& delta) {
+                            return a + delta.getFlattenedSize();
+                    });
+}
+
+size_t FrameEventHistoryDelta::getFdCount() const {
+    return std::accumulate(mDeltas.begin(), mDeltas.end(), size_t(0),
+            [](size_t a, const FrameEventsDelta& delta) {
+                    return a + delta.getFdCount();
+            });
+}
+
+status_t FrameEventHistoryDelta::flatten(
+            void*& buffer, size_t& size, int*& fds, size_t& count) const {
+    if (mDeltas.size() > FrameEventHistory::MAX_FRAME_HISTORY) {
+        return BAD_VALUE;
+    }
+    if (size < getFlattenedSize()) {
+        return NO_MEMORY;
+    }
+
+    FlattenableUtils::write(buffer, size, mCompositorTiming);
+
+    FlattenableUtils::write(
+            buffer, size, static_cast<uint32_t>(mDeltas.size()));
+    for (auto& d : mDeltas) {
+        status_t status = d.flatten(buffer, size, fds, count);
+        if (status != NO_ERROR) {
+            return status;
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t FrameEventHistoryDelta::unflatten(
+            void const*& buffer, size_t& size, int const*& fds, size_t& count) {
+    if (size < minFlattenedSize()) {
+        return NO_MEMORY;
+    }
+
+    FlattenableUtils::read(buffer, size, mCompositorTiming);
+
+    uint32_t deltaCount = 0;
+    FlattenableUtils::read(buffer, size, deltaCount);
+    if (deltaCount > FrameEventHistory::MAX_FRAME_HISTORY) {
+        return BAD_VALUE;
+    }
+    mDeltas.resize(deltaCount);
+    for (auto& d : mDeltas) {
+        status_t status = d.unflatten(buffer, size, fds, count);
+        if (status != NO_ERROR) {
+            return status;
+        }
+    }
+    return NO_ERROR;
+}
+
+
+} // namespace android
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 10e999c..c654f08 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -31,7 +31,6 @@
 
 #include <gui/BufferItem.h>
 #include <gui/GLConsumer.h>
-#include <gui/IGraphicBufferAlloc.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/SurfaceComposerClient.h>
 
@@ -157,6 +156,7 @@
     mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
     mCurrentFence(Fence::NO_FENCE),
     mCurrentTimestamp(0),
+    mCurrentDataSpace(HAL_DATASPACE_UNKNOWN),
     mCurrentFrameNumber(0),
     mDefaultWidth(1),
     mDefaultHeight(1),
@@ -185,6 +185,7 @@
     mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
     mCurrentFence(Fence::NO_FENCE),
     mCurrentTimestamp(0),
+    mCurrentDataSpace(HAL_DATASPACE_UNKNOWN),
     mCurrentFrameNumber(0),
     mDefaultWidth(1),
     mDefaultHeight(1),
@@ -321,7 +322,9 @@
         mCurrentCrop.makeInvalid();
         mCurrentTransform = 0;
         mCurrentTimestamp = 0;
+        mCurrentDataSpace = HAL_DATASPACE_UNKNOWN;
         mCurrentFence = Fence::NO_FENCE;
+        mCurrentFenceTime = FenceTime::NO_FENCE;
 
         if (mAttached) {
             // This binds a dummy buffer (mReleasedTexImage).
@@ -487,7 +490,9 @@
     mCurrentTransform = item.mTransform;
     mCurrentScalingMode = item.mScalingMode;
     mCurrentTimestamp = item.mTimestamp;
+    mCurrentDataSpace = item.mDataSpace;
     mCurrentFence = item.mFence;
+    mCurrentFenceTime = item.mFenceTime;
     mCurrentFrameNumber = item.mFrameNumber;
 
     computeCurrentTransformMatrixLocked();
@@ -856,6 +861,8 @@
             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:
@@ -911,15 +918,26 @@
     return mCurrentTimestamp;
 }
 
+android_dataspace GLConsumer::getCurrentDataSpace() {
+    GLC_LOGV("getCurrentDataSpace");
+    Mutex::Autolock lock(mMutex);
+    return mCurrentDataSpace;
+}
+
 uint64_t GLConsumer::getFrameNumber() {
     GLC_LOGV("getFrameNumber");
     Mutex::Autolock lock(mMutex);
     return mCurrentFrameNumber;
 }
 
-sp<GraphicBuffer> GLConsumer::getCurrentBuffer() const {
+sp<GraphicBuffer> GLConsumer::getCurrentBuffer(int* outSlot) const {
     Mutex::Autolock lock(mMutex);
-    return (mCurrentTextureImage == NULL) ?
+
+    if (outSlot != nullptr) {
+        *outSlot = mCurrentTexture;
+    }
+
+    return (mCurrentTextureImage == nullptr) ?
             NULL : mCurrentTextureImage->graphicBuffer();
 }
 
@@ -981,6 +999,11 @@
     return mCurrentFence;
 }
 
+std::shared_ptr<FenceTime> GLConsumer::getCurrentFenceTime() const {
+    Mutex::Autolock lock(mMutex);
+    return mCurrentFenceTime;
+}
+
 status_t GLConsumer::doGLFenceWait() const {
     Mutex::Autolock lock(mMutex);
     return doGLFenceWaitLocked();
diff --git a/libs/gui/GraphicBufferAlloc.cpp b/libs/gui/GraphicBufferAlloc.cpp
deleted file mode 100644
index e6150f4..0000000
--- a/libs/gui/GraphicBufferAlloc.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- **
- ** Copyright 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.
- */
-
-#include <cutils/log.h>
-
-#include <ui/GraphicBuffer.h>
-
-#include <gui/GraphicBufferAlloc.h>
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-GraphicBufferAlloc::GraphicBufferAlloc() {
-}
-
-GraphicBufferAlloc::~GraphicBufferAlloc() {
-}
-
-sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t width,
-        uint32_t height, PixelFormat format, uint32_t usage,
-        std::string requestorName, status_t* error) {
-    sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(
-            width, height, format, usage, std::move(requestorName)));
-    status_t err = graphicBuffer->initCheck();
-    *error = err;
-    if (err != 0 || graphicBuffer->handle == 0) {
-        if (err == NO_MEMORY) {
-            GraphicBuffer::dumpAllocationsToSystemLog();
-        }
-        ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) "
-             "failed (%s), handle=%p",
-                width, height, strerror(-err), graphicBuffer->handle);
-        return 0;
-    }
-    return graphicBuffer;
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
diff --git a/libs/gui/GraphicsEnv.cpp b/libs/gui/GraphicsEnv.cpp
deleted file mode 100644
index 68f0f98..0000000
--- a/libs/gui/GraphicsEnv.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 1
-#define LOG_TAG "GraphicsEnv"
-#include <gui/GraphicsEnv.h>
-
-#include <mutex>
-
-#include <log/log.h>
-#include <nativeloader/dlext_namespaces.h>
-
-namespace android {
-
-/*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;
-    }
-    ALOGV("setting driver path to '%s'", path.c_str());
-    mDriverPath = path;
-}
-
-android_namespace_t* GraphicsEnv::getDriverNamespace() {
-    static std::once_flag once;
-    std::call_once(once, [this]() {
-        // TODO; In the next version of Android, all graphics drivers will be
-        // loaded into a custom namespace. To minimize risk for this release,
-        // only updated drivers use a custom namespace.
-        //
-        // Additionally, the custom namespace will be
-        // ANDROID_NAMESPACE_TYPE_ISOLATED, and will only have access to a
-        // subset of the system.
-        if (mDriverPath.empty())
-            return;
-
-        char defaultPath[PATH_MAX];
-        android_get_LD_LIBRARY_PATH(defaultPath, sizeof(defaultPath));
-        size_t defaultPathLen = strlen(defaultPath);
-
-        std::string path;
-        path.reserve(mDriverPath.size() + 1 + defaultPathLen);
-        path.append(mDriverPath);
-        path.push_back(':');
-        path.append(defaultPath, defaultPathLen);
-
-        mDriverNamespace = android_create_namespace(
-                "gfx driver",
-                nullptr,                    // ld_library_path
-                path.c_str(),               // default_library_path
-                ANDROID_NAMESPACE_TYPE_SHARED,
-                nullptr,                    // permitted_when_isolated_path
-                nullptr);                   // parent
-    });
-    return mDriverNamespace;
-}
-
-} // namespace android
-
-extern "C" android_namespace_t* android_getDriverNamespace() {
-    return android::GraphicsEnv::getInstance().getDriverNamespace();
-}
diff --git a/libs/gui/IConsumerListener.cpp b/libs/gui/IConsumerListener.cpp
index 9a06011..85ac304 100644
--- a/libs/gui/IConsumerListener.cpp
+++ b/libs/gui/IConsumerListener.cpp
@@ -14,146 +14,86 @@
  * limitations under the License.
  */
 
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
 #include <gui/IConsumerListener.h>
+
 #include <gui/BufferItem.h>
 
-// ---------------------------------------------------------------------------
 namespace android {
-// ---------------------------------------------------------------------------
 
-enum {
-    ON_FRAME_AVAILABLE = IBinder::FIRST_CALL_TRANSACTION,
-    ON_BUFFER_RELEASED,
+namespace { // Anonymous
+
+enum class Tag : uint32_t {
+    ON_DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
+    ON_FRAME_AVAILABLE,
+    ON_FRAME_REPLACED,
+    ON_BUFFERS_RELEASED,
     ON_SIDEBAND_STREAM_CHANGED,
-    GET_FRAME_TIMESTAMPS
+    LAST = ON_SIDEBAND_STREAM_CHANGED,
 };
 
-class BpConsumerListener : public BpInterface<IConsumerListener>
-{
+} // Anonymous namespace
+
+class BpConsumerListener : public SafeBpInterface<IConsumerListener> {
 public:
-    BpConsumerListener(const sp<IBinder>& impl)
-        : BpInterface<IConsumerListener>(impl) {
+    explicit BpConsumerListener(const sp<IBinder>& impl)
+          : SafeBpInterface<IConsumerListener>(impl, "BpConsumerListener") {}
+
+    ~BpConsumerListener() override;
+
+    void onDisconnect() override {
+        callRemoteAsync<decltype(&IConsumerListener::onDisconnect)>(Tag::ON_DISCONNECT);
     }
 
-    virtual ~BpConsumerListener();
-
-    virtual void onFrameAvailable(const BufferItem& item) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
-        data.write(item);
-        remote()->transact(ON_FRAME_AVAILABLE, data, &reply, IBinder::FLAG_ONEWAY);
+    void onFrameAvailable(const BufferItem& item) override {
+        callRemoteAsync<decltype(&IConsumerListener::onFrameAvailable)>(Tag::ON_FRAME_AVAILABLE,
+                                                                        item);
     }
 
-    virtual void onBuffersReleased() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
-        remote()->transact(ON_BUFFER_RELEASED, data, &reply, IBinder::FLAG_ONEWAY);
+    void onFrameReplaced(const BufferItem& item) override {
+        callRemoteAsync<decltype(&IConsumerListener::onFrameReplaced)>(Tag::ON_FRAME_REPLACED,
+                                                                       item);
     }
 
-    virtual void onSidebandStreamChanged() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
-        remote()->transact(ON_SIDEBAND_STREAM_CHANGED, data, &reply, IBinder::FLAG_ONEWAY);
+    void onBuffersReleased() override {
+        callRemoteAsync<decltype(&IConsumerListener::onBuffersReleased)>(Tag::ON_BUFFERS_RELEASED);
     }
 
-    virtual bool getFrameTimestamps(uint64_t frameNumber,
-            FrameTimestamps* outTimestamps) const {
-        Parcel data, reply;
-        status_t result = data.writeInterfaceToken(
-                IConsumerListener::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            ALOGE("getFrameTimestamps failed to write token: %d", result);
-            return false;
-        }
-        result = data.writeUint64(frameNumber);
-        if (result != NO_ERROR) {
-            ALOGE("getFrameTimestamps failed to write: %d", result);
-            return false;
-        }
-        result = remote()->transact(GET_FRAME_TIMESTAMPS, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("getFrameTimestamps failed to transact: %d", result);
-            return false;
-        }
-        bool found = false;
-        result = reply.readBool(&found);
-        if (result != NO_ERROR) {
-            ALOGE("getFrameTimestamps failed to read: %d", result);
-            return false;
-        }
-        if (found) {
-            result = reply.read(*outTimestamps);
-            if (result != NO_ERROR) {
-                ALOGE("getFrameTimestamps failed to read timestamps: %d",
-                        result);
-                return false;
-            }
-        }
-        return found;
+    void onSidebandStreamChanged() override {
+        callRemoteAsync<decltype(&IConsumerListener::onSidebandStreamChanged)>(
+                Tag::ON_SIDEBAND_STREAM_CHANGED);
+    }
+
+    void addAndGetFrameTimestamps(const NewFrameEventsEntry* /*newTimestamps*/,
+                                  FrameEventHistoryDelta* /*outDelta*/) override {
+        LOG_ALWAYS_FATAL("IConsumerListener::addAndGetFrameTimestamps cannot be proxied");
     }
 };
 
-// Out-of-line virtual method definition to trigger vtable emission in this
-// translation unit (see clang warning -Wweak-vtables)
-BpConsumerListener::~BpConsumerListener() {}
+// Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see
+// clang warning -Wweak-vtables)
+BpConsumerListener::~BpConsumerListener() = default;
+ConsumerListener::~ConsumerListener() = default;
 
 IMPLEMENT_META_INTERFACE(ConsumerListener, "android.gui.IConsumerListener");
 
-// ----------------------------------------------------------------------
-
-status_t BnConsumerListener::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    switch(code) {
-        case ON_FRAME_AVAILABLE: {
-            CHECK_INTERFACE(IConsumerListener, data, reply);
-            BufferItem item;
-            data.read(item);
-            onFrameAvailable(item);
-            return NO_ERROR; }
-        case ON_BUFFER_RELEASED: {
-            CHECK_INTERFACE(IConsumerListener, data, reply);
-            onBuffersReleased();
-            return NO_ERROR; }
-        case ON_SIDEBAND_STREAM_CHANGED: {
-            CHECK_INTERFACE(IConsumerListener, data, reply);
-            onSidebandStreamChanged();
-            return NO_ERROR; }
-        case GET_FRAME_TIMESTAMPS: {
-            CHECK_INTERFACE(IConsumerListener, data, reply);
-            uint64_t frameNumber = 0;
-            status_t result = data.readUint64(&frameNumber);
-            if (result != NO_ERROR) {
-                ALOGE("onTransact failed to read: %d", result);
-                return result;
-            }
-            FrameTimestamps timestamps;
-            bool found = getFrameTimestamps(frameNumber, &timestamps);
-            result = reply->writeBool(found);
-            if (result != NO_ERROR) {
-                ALOGE("onTransact failed to write: %d", result);
-                return result;
-            }
-            if (found) {
-                result = reply->write(timestamps);
-                if (result != NO_ERROR) {
-                    ALOGE("onTransact failed to write timestamps: %d", result);
-                    return result;
-                }
-            }
-            return NO_ERROR;
-        }
+status_t BnConsumerListener::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);
     }
-    return BBinder::onTransact(code, data, reply, flags);
+    auto tag = static_cast<Tag>(code);
+    switch (tag) {
+        case Tag::ON_DISCONNECT:
+            return callLocalAsync(data, reply, &IConsumerListener::onDisconnect);
+        case Tag::ON_FRAME_AVAILABLE:
+            return callLocalAsync(data, reply, &IConsumerListener::onFrameAvailable);
+        case Tag::ON_FRAME_REPLACED:
+            return callLocalAsync(data, reply, &IConsumerListener::onFrameReplaced);
+        case Tag::ON_BUFFERS_RELEASED:
+            return callLocalAsync(data, reply, &IConsumerListener::onBuffersReleased);
+        case Tag::ON_SIDEBAND_STREAM_CHANGED:
+            return callLocalAsync(data, reply, &IConsumerListener::onSidebandStreamChanged);
+    }
 }
 
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-// ---------------------------------------------------------------------------
+} // namespace android
diff --git a/libs/gui/IDisplayEventConnection.cpp b/libs/gui/IDisplayEventConnection.cpp
index 9890f44..c0e246f 100644
--- a/libs/gui/IDisplayEventConnection.cpp
+++ b/libs/gui/IDisplayEventConnection.cpp
@@ -14,91 +14,67 @@
  * limitations under the License.
  */
 
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/Timers.h>
-
-#include <binder/Parcel.h>
-#include <binder/IInterface.h>
-
 #include <gui/IDisplayEventConnection.h>
-#include <gui/BitTube.h>
+
+#include <private/gui/BitTube.h>
 
 namespace android {
-// ----------------------------------------------------------------------------
 
-enum {
-    GET_DATA_CHANNEL = IBinder::FIRST_CALL_TRANSACTION,
+namespace { // Anonymous
+
+enum class Tag : uint32_t {
+    STEAL_RECEIVE_CHANNEL = IBinder::FIRST_CALL_TRANSACTION,
     SET_VSYNC_RATE,
-    REQUEST_NEXT_VSYNC
+    REQUEST_NEXT_VSYNC,
+    LAST = REQUEST_NEXT_VSYNC,
 };
 
-class BpDisplayEventConnection : public BpInterface<IDisplayEventConnection>
-{
+} // Anonymous namespace
+
+class BpDisplayEventConnection : public SafeBpInterface<IDisplayEventConnection> {
 public:
-    BpDisplayEventConnection(const sp<IBinder>& impl)
-        : BpInterface<IDisplayEventConnection>(impl)
-    {
+    explicit BpDisplayEventConnection(const sp<IBinder>& impl)
+          : SafeBpInterface<IDisplayEventConnection>(impl, "BpDisplayEventConnection") {}
+
+    ~BpDisplayEventConnection() override;
+
+    status_t stealReceiveChannel(gui::BitTube* outChannel) override {
+        return callRemote<decltype(
+                &IDisplayEventConnection::stealReceiveChannel)>(Tag::STEAL_RECEIVE_CHANNEL,
+                                                                outChannel);
     }
 
-    virtual ~BpDisplayEventConnection();
-
-    virtual sp<BitTube> getDataChannel() const
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDisplayEventConnection::getInterfaceDescriptor());
-        remote()->transact(GET_DATA_CHANNEL, data, &reply);
-        return new BitTube(reply);
+    status_t setVsyncRate(uint32_t count) override {
+        return callRemote<decltype(&IDisplayEventConnection::setVsyncRate)>(Tag::SET_VSYNC_RATE,
+                                                                            count);
     }
 
-    virtual void setVsyncRate(uint32_t count) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDisplayEventConnection::getInterfaceDescriptor());
-        data.writeUint32(count);
-        remote()->transact(SET_VSYNC_RATE, data, &reply);
-    }
-
-    virtual void requestNextVsync() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDisplayEventConnection::getInterfaceDescriptor());
-        remote()->transact(REQUEST_NEXT_VSYNC, data, &reply, IBinder::FLAG_ONEWAY);
+    void requestNextVsync() override {
+        callRemoteAsync<decltype(&IDisplayEventConnection::requestNextVsync)>(
+                Tag::REQUEST_NEXT_VSYNC);
     }
 };
 
-// Out-of-line virtual method definition to trigger vtable emission in this
-// translation unit (see clang warning -Wweak-vtables)
-BpDisplayEventConnection::~BpDisplayEventConnection() {}
+// Out-of-line virtual method definition to trigger vtable emission in this translation unit (see
+// clang warning -Wweak-vtables)
+BpDisplayEventConnection::~BpDisplayEventConnection() = default;
 
 IMPLEMENT_META_INTERFACE(DisplayEventConnection, "android.gui.DisplayEventConnection");
 
-// ----------------------------------------------------------------------------
-
-status_t BnDisplayEventConnection::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    switch(code) {
-        case GET_DATA_CHANNEL: {
-            CHECK_INTERFACE(IDisplayEventConnection, data, reply);
-            sp<BitTube> channel(getDataChannel());
-            channel->writeToParcel(reply);
-            return NO_ERROR;
-        }
-        case SET_VSYNC_RATE: {
-            CHECK_INTERFACE(IDisplayEventConnection, data, reply);
-            setVsyncRate(data.readUint32());
-            return NO_ERROR;
-        }
-        case REQUEST_NEXT_VSYNC: {
-            CHECK_INTERFACE(IDisplayEventConnection, data, reply);
-            requestNextVsync();
-            return NO_ERROR;
-        }
+status_t BnDisplayEventConnection::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);
     }
-    return BBinder::onTransact(code, data, reply, flags);
+    auto tag = static_cast<Tag>(code);
+    switch (tag) {
+        case Tag::STEAL_RECEIVE_CHANNEL:
+            return callLocal(data, reply, &IDisplayEventConnection::stealReceiveChannel);
+        case Tag::SET_VSYNC_RATE:
+            return callLocal(data, reply, &IDisplayEventConnection::setVsyncRate);
+        case Tag::REQUEST_NEXT_VSYNC:
+            return callLocalAsync(data, reply, &IDisplayEventConnection::requestNextVsync);
+    }
 }
 
-// ----------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp
deleted file mode 100644
index 7b3b7c1..0000000
--- a/libs/gui/IGraphicBufferAlloc.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * 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.
- */
-
-// tag as surfaceflinger
-#define LOG_TAG "SurfaceFlinger"
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/Parcel.h>
-
-#include <ui/GraphicBuffer.h>
-
-#include <gui/IGraphicBufferAlloc.h>
-
-// ---------------------------------------------------------------------------
-
-namespace android {
-
-enum {
-    CREATE_GRAPHIC_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
-};
-
-class BpGraphicBufferAlloc : public BpInterface<IGraphicBufferAlloc>
-{
-public:
-    BpGraphicBufferAlloc(const sp<IBinder>& impl)
-        : BpInterface<IGraphicBufferAlloc>(impl)
-    {
-    }
-
-    virtual ~BpGraphicBufferAlloc();
-
-    virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width,
-            uint32_t height, PixelFormat format, uint32_t usage,
-            std::string requestorName, status_t* error) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferAlloc::getInterfaceDescriptor());
-        data.writeUint32(width);
-        data.writeUint32(height);
-        data.writeInt32(static_cast<int32_t>(format));
-        data.writeUint32(usage);
-        if (requestorName.empty()) {
-            requestorName += "[PID ";
-            requestorName += std::to_string(getpid());
-            requestorName += ']';
-        }
-        data.writeUtf8AsUtf16(requestorName);
-        remote()->transact(CREATE_GRAPHIC_BUFFER, data, &reply);
-        sp<GraphicBuffer> graphicBuffer;
-        status_t result = reply.readInt32();
-        if (result == NO_ERROR) {
-            graphicBuffer = new GraphicBuffer();
-            result = reply.read(*graphicBuffer);
-            if (result != NO_ERROR) {
-                graphicBuffer.clear();
-            }
-            // reply.readStrongBinder();
-            // here we don't even have to read the BufferReference from
-            // the parcel, it'll die with the parcel.
-        }
-        *error = result;
-        return graphicBuffer;
-    }
-};
-
-// Out-of-line virtual method definition to trigger vtable emission in this
-// translation unit (see clang warning -Wweak-vtables)
-BpGraphicBufferAlloc::~BpGraphicBufferAlloc() {}
-
-IMPLEMENT_META_INTERFACE(GraphicBufferAlloc, "android.ui.IGraphicBufferAlloc");
-
-// ----------------------------------------------------------------------
-
-status_t BnGraphicBufferAlloc::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    // codes that don't require permission check
-
-    // BufferReference just keeps a strong reference to a GraphicBuffer until it
-    // is destroyed (that is, until no local or remote process have a reference
-    // to it).
-    class BufferReference : public BBinder {
-        sp<GraphicBuffer> mBuffer;
-    public:
-        BufferReference(const sp<GraphicBuffer>& buffer) : mBuffer(buffer) {}
-    };
-
-
-    switch (code) {
-        case CREATE_GRAPHIC_BUFFER: {
-            CHECK_INTERFACE(IGraphicBufferAlloc, data, reply);
-            uint32_t width = data.readUint32();
-            uint32_t height = data.readUint32();
-            PixelFormat format = static_cast<PixelFormat>(data.readInt32());
-            uint32_t usage = data.readUint32();
-            status_t error = NO_ERROR;
-            std::string requestorName;
-            data.readUtf8FromUtf16(&requestorName);
-            sp<GraphicBuffer> result = createGraphicBuffer(width, height,
-                    format, usage, requestorName, &error);
-            reply->writeInt32(error);
-            if (result != 0) {
-                reply->write(*result);
-                // We add a BufferReference to this parcel to make sure the
-                // buffer stays alive until the GraphicBuffer object on
-                // the other side has been created.
-                // This is needed so that the buffer handle can be
-                // registered before the buffer is destroyed on implementations
-                // that do not use file-descriptors to track their buffers.
-                reply->writeStrongBinder( new BufferReference(result) );
-            }
-            return NO_ERROR;
-        }
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
-}; // namespace android
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index c8eff00..a573bee 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -14,27 +14,24 @@
  * limitations under the License.
  */
 
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/NativeHandle.h>
-
-#include <binder/Parcel.h>
-#include <binder/IInterface.h>
+#include <gui/IGraphicBufferConsumer.h>
 
 #include <gui/BufferItem.h>
 #include <gui/IConsumerListener.h>
-#include <gui/IGraphicBufferConsumer.h>
 
-#include <ui/GraphicBuffer.h>
+#include <binder/Parcel.h>
+
 #include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
 
-#include <system/window.h>
+#include <utils/NativeHandle.h>
+#include <utils/String8.h>
 
 namespace android {
 
-enum {
+namespace { // Anonymous namespace
+
+enum class Tag : uint32_t {
     ACQUIRE_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
     DETACH_BUFFER,
     ATTACH_BUFFER,
@@ -49,443 +46,185 @@
     SET_DEFAULT_BUFFER_FORMAT,
     SET_DEFAULT_BUFFER_DATA_SPACE,
     SET_CONSUMER_USAGE_BITS,
+    SET_CONSUMER_IS_PROTECTED,
     SET_TRANSFORM_HINT,
     GET_SIDEBAND_STREAM,
     GET_OCCUPANCY_HISTORY,
     DISCARD_FREE_BUFFERS,
-    DUMP,
+    DUMP_STATE,
+    LAST = DUMP_STATE,
 };
 
+} // Anonymous namespace
 
-class BpGraphicBufferConsumer : public BpInterface<IGraphicBufferConsumer>
-{
+class BpGraphicBufferConsumer : public SafeBpInterface<IGraphicBufferConsumer> {
 public:
-    BpGraphicBufferConsumer(const sp<IBinder>& impl)
-        : BpInterface<IGraphicBufferConsumer>(impl)
-    {
+    explicit BpGraphicBufferConsumer(const sp<IBinder>& impl)
+          : SafeBpInterface<IGraphicBufferConsumer>(impl, "BpGraphicBufferConsumer") {}
+
+    ~BpGraphicBufferConsumer() override;
+
+    status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen,
+                           uint64_t maxFrameNumber) override {
+        using Signature = decltype(&IGraphicBufferConsumer::acquireBuffer);
+        return callRemote<Signature>(Tag::ACQUIRE_BUFFER, buffer, presentWhen, maxFrameNumber);
     }
 
-    virtual ~BpGraphicBufferConsumer();
-
-    virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen,
-            uint64_t maxFrameNumber) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
-        data.writeInt64(presentWhen);
-        data.writeUint64(maxFrameNumber);
-        status_t result = remote()->transact(ACQUIRE_BUFFER, data, &reply);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        result = reply.read(*buffer);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        return reply.readInt32();
+    status_t detachBuffer(int slot) override {
+        using Signature = decltype(&IGraphicBufferConsumer::detachBuffer);
+        return callRemote<Signature>(Tag::DETACH_BUFFER, slot);
     }
 
-    virtual status_t detachBuffer(int slot) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
-        data.writeInt32(slot);
-        status_t result = remote()->transact(DETACH_BUFFER, data, &reply);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        result = reply.readInt32();
-        return result;
+    status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer) override {
+        using Signature = decltype(&IGraphicBufferConsumer::attachBuffer);
+        return callRemote<Signature>(Tag::ATTACH_BUFFER, slot, buffer);
     }
 
-    virtual status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
-        data.write(*buffer.get());
-        status_t result = remote()->transact(ATTACH_BUFFER, data, &reply);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        *slot = reply.readInt32();
-        result = reply.readInt32();
-        return result;
+    status_t releaseBuffer(int buf, uint64_t frameNumber,
+                           EGLDisplay display __attribute__((unused)),
+                           EGLSyncKHR fence __attribute__((unused)),
+                           const sp<Fence>& releaseFence) override {
+        return callRemote<ReleaseBuffer>(Tag::RELEASE_BUFFER, buf, frameNumber, releaseFence);
     }
 
-    virtual status_t releaseBuffer(int buf, uint64_t frameNumber,
-            EGLDisplay display __attribute__((unused)), EGLSyncKHR fence __attribute__((unused)),
-            const sp<Fence>& releaseFence) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
-        data.writeInt32(buf);
-        data.writeInt64(static_cast<int64_t>(frameNumber));
-        data.write(*releaseFence);
-        status_t result = remote()->transact(RELEASE_BUFFER, data, &reply);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        return reply.readInt32();
+    status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) override {
+        using Signature = decltype(&IGraphicBufferConsumer::consumerConnect);
+        return callRemote<Signature>(Tag::CONSUMER_CONNECT, consumer, controlledByApp);
     }
 
-    virtual status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
-        data.writeStrongBinder(IInterface::asBinder(consumer));
-        data.writeInt32(controlledByApp);
-        status_t result = remote()->transact(CONSUMER_CONNECT, data, &reply);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        return reply.readInt32();
+    status_t consumerDisconnect() override {
+        return callRemote<decltype(&IGraphicBufferConsumer::consumerDisconnect)>(
+                Tag::CONSUMER_DISCONNECT);
     }
 
-    virtual status_t consumerDisconnect() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
-        status_t result = remote()->transact(CONSUMER_DISCONNECT, data, &reply);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        return reply.readInt32();
+    status_t getReleasedBuffers(uint64_t* slotMask) override {
+        using Signature = decltype(&IGraphicBufferConsumer::getReleasedBuffers);
+        return callRemote<Signature>(Tag::GET_RELEASED_BUFFERS, slotMask);
     }
 
-    virtual status_t getReleasedBuffers(uint64_t* slotMask) {
-        Parcel data, reply;
-        if (slotMask == NULL) {
-            ALOGE("getReleasedBuffers: slotMask must not be NULL");
-            return BAD_VALUE;
-        }
-        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
-        status_t result = remote()->transact(GET_RELEASED_BUFFERS, data, &reply);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        *slotMask = static_cast<uint64_t>(reply.readInt64());
-        return reply.readInt32();
+    status_t setDefaultBufferSize(uint32_t width, uint32_t height) override {
+        using Signature = decltype(&IGraphicBufferConsumer::setDefaultBufferSize);
+        return callRemote<Signature>(Tag::SET_DEFAULT_BUFFER_SIZE, width, height);
     }
 
-    virtual status_t setDefaultBufferSize(uint32_t width, uint32_t height) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
-        data.writeUint32(width);
-        data.writeUint32(height);
-        status_t result = remote()->transact(SET_DEFAULT_BUFFER_SIZE, data, &reply);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        return reply.readInt32();
+    status_t setMaxBufferCount(int bufferCount) override {
+        using Signature = decltype(&IGraphicBufferConsumer::setMaxBufferCount);
+        return callRemote<Signature>(Tag::SET_MAX_BUFFER_COUNT, bufferCount);
     }
 
-    virtual status_t setMaxBufferCount(int bufferCount) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
-        data.writeInt32(bufferCount);
-        status_t result = remote()->transact(SET_MAX_BUFFER_COUNT, data, &reply);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        return reply.readInt32();
+    status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) override {
+        using Signature = decltype(&IGraphicBufferConsumer::setMaxAcquiredBufferCount);
+        return callRemote<Signature>(Tag::SET_MAX_ACQUIRED_BUFFER_COUNT, maxAcquiredBuffers);
     }
 
-    virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
-        data.writeInt32(maxAcquiredBuffers);
-        status_t result = remote()->transact(SET_MAX_ACQUIRED_BUFFER_COUNT, data, &reply);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        return reply.readInt32();
+    status_t setConsumerName(const String8& name) override {
+        using Signature = decltype(&IGraphicBufferConsumer::setConsumerName);
+        return callRemote<Signature>(Tag::SET_CONSUMER_NAME, name);
     }
 
-    virtual void setConsumerName(const String8& name) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
-        data.writeString8(name);
-        remote()->transact(SET_CONSUMER_NAME, data, &reply);
+    status_t setDefaultBufferFormat(PixelFormat defaultFormat) override {
+        using Signature = decltype(&IGraphicBufferConsumer::setDefaultBufferFormat);
+        return callRemote<Signature>(Tag::SET_DEFAULT_BUFFER_FORMAT, defaultFormat);
     }
 
-    virtual status_t setDefaultBufferFormat(PixelFormat defaultFormat) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
-        data.writeInt32(static_cast<int32_t>(defaultFormat));
-        status_t result = remote()->transact(SET_DEFAULT_BUFFER_FORMAT, data, &reply);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        return reply.readInt32();
+    status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace) override {
+        using Signature = decltype(&IGraphicBufferConsumer::setDefaultBufferDataSpace);
+        return callRemote<Signature>(Tag::SET_DEFAULT_BUFFER_DATA_SPACE, defaultDataSpace);
     }
 
-    virtual status_t setDefaultBufferDataSpace(
-            android_dataspace defaultDataSpace) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
-        data.writeInt32(static_cast<int32_t>(defaultDataSpace));
-        status_t result = remote()->transact(SET_DEFAULT_BUFFER_DATA_SPACE,
-                data, &reply);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        return reply.readInt32();
+    status_t setConsumerUsageBits(uint32_t usage) override {
+        using Signature = decltype(&IGraphicBufferConsumer::setConsumerUsageBits);
+        return callRemote<Signature>(Tag::SET_CONSUMER_USAGE_BITS, usage);
     }
 
-    virtual status_t setConsumerUsageBits(uint32_t usage) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
-        data.writeUint32(usage);
-        status_t result = remote()->transact(SET_CONSUMER_USAGE_BITS, data, &reply);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        return reply.readInt32();
+    status_t setConsumerIsProtected(bool isProtected) override {
+        using Signature = decltype(&IGraphicBufferConsumer::setConsumerIsProtected);
+        return callRemote<Signature>(Tag::SET_CONSUMER_IS_PROTECTED, isProtected);
     }
 
-    virtual status_t setTransformHint(uint32_t hint) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
-        data.writeUint32(hint);
-        status_t result = remote()->transact(SET_TRANSFORM_HINT, data, &reply);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        return reply.readInt32();
+    status_t setTransformHint(uint32_t hint) override {
+        using Signature = decltype(&IGraphicBufferConsumer::setTransformHint);
+        return callRemote<Signature>(Tag::SET_TRANSFORM_HINT, hint);
     }
 
-    virtual sp<NativeHandle> getSidebandStream() const {
-        Parcel data, reply;
-        status_t err;
-        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
-        if ((err = remote()->transact(GET_SIDEBAND_STREAM, data, &reply)) != NO_ERROR) {
-            return NULL;
-        }
-        sp<NativeHandle> stream;
-        if (reply.readInt32()) {
-            stream = NativeHandle::create(reply.readNativeHandle(), true);
-        }
-        return stream;
+    status_t getSidebandStream(sp<NativeHandle>* outStream) const override {
+        using Signature = decltype(&IGraphicBufferConsumer::getSidebandStream);
+        return callRemote<Signature>(Tag::GET_SIDEBAND_STREAM, outStream);
     }
 
-    virtual status_t getOccupancyHistory(bool forceFlush,
-            std::vector<OccupancyTracker::Segment>* outHistory) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
-        status_t error = data.writeBool(forceFlush);
-        if (error != NO_ERROR) {
-            return error;
-        }
-        error = remote()->transact(GET_OCCUPANCY_HISTORY, data,
-                &reply);
-        if (error != NO_ERROR) {
-            return error;
-        }
-        error = reply.readParcelableVector(outHistory);
-        if (error != NO_ERROR) {
-            return error;
-        }
-        status_t result = NO_ERROR;
-        error = reply.readInt32(&result);
-        if (error != NO_ERROR) {
-            return error;
-        }
-        return result;
+    status_t getOccupancyHistory(bool forceFlush,
+                                 std::vector<OccupancyTracker::Segment>* outHistory) override {
+        using Signature = decltype(&IGraphicBufferConsumer::getOccupancyHistory);
+        return callRemote<Signature>(Tag::GET_OCCUPANCY_HISTORY, forceFlush, outHistory);
     }
 
-    virtual status_t discardFreeBuffers() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
-        status_t error = remote()->transact(DISCARD_FREE_BUFFERS, data, &reply);
-        if (error != NO_ERROR) {
-            return error;
-        }
-        int32_t result = NO_ERROR;
-        error = reply.readInt32(&result);
-        if (error != NO_ERROR) {
-            return error;
-        }
-        return result;
+    status_t discardFreeBuffers() override {
+        return callRemote<decltype(&IGraphicBufferConsumer::discardFreeBuffers)>(
+                Tag::DISCARD_FREE_BUFFERS);
     }
 
-    virtual void dump(String8& result, const char* prefix) const {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
-        data.writeString8(result);
-        data.writeString8(String8(prefix ? prefix : ""));
-        remote()->transact(DUMP, data, &reply);
-        reply.readString8();
+    status_t dumpState(const String8& prefix, String8* outResult) const override {
+        using Signature = status_t (IGraphicBufferConsumer::*)(const String8&, String8*) const;
+        return callRemote<Signature>(Tag::DUMP_STATE, prefix, outResult);
     }
 };
 
-// Out-of-line virtual method definition to trigger vtable emission in this
-// translation unit (see clang warning -Wweak-vtables)
-BpGraphicBufferConsumer::~BpGraphicBufferConsumer() {}
+// Out-of-line virtual method definition to trigger vtable emission in this translation unit
+// (see clang warning -Wweak-vtables)
+BpGraphicBufferConsumer::~BpGraphicBufferConsumer() = default;
 
 IMPLEMENT_META_INTERFACE(GraphicBufferConsumer, "android.gui.IGraphicBufferConsumer");
 
-// ----------------------------------------------------------------------
-
-status_t BnGraphicBufferConsumer::onTransact(
-        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    switch(code) {
-        case ACQUIRE_BUFFER: {
-            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
-            BufferItem item;
-            int64_t presentWhen = data.readInt64();
-            uint64_t maxFrameNumber = data.readUint64();
-            status_t result = acquireBuffer(&item, presentWhen, maxFrameNumber);
-            status_t err = reply->write(item);
-            if (err) return err;
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case DETACH_BUFFER: {
-            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
-            int slot = data.readInt32();
-            int result = detachBuffer(slot);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case ATTACH_BUFFER: {
-            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
-            sp<GraphicBuffer> buffer = new GraphicBuffer();
-            data.read(*buffer.get());
-            int slot = -1;
-            int result = attachBuffer(&slot, buffer);
-            reply->writeInt32(slot);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case RELEASE_BUFFER: {
-            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
-            int buf = data.readInt32();
-            uint64_t frameNumber = static_cast<uint64_t>(data.readInt64());
-            sp<Fence> releaseFence = new Fence();
-            status_t err = data.read(*releaseFence);
-            if (err) return err;
-            status_t result = releaseBuffer(buf, frameNumber,
-                    EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, releaseFence);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case CONSUMER_CONNECT: {
-            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
-            sp<IConsumerListener> consumer = IConsumerListener::asInterface( data.readStrongBinder() );
-            bool controlledByApp = data.readInt32();
-            status_t result = consumerConnect(consumer, controlledByApp);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case CONSUMER_DISCONNECT: {
-            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
-            status_t result = consumerDisconnect();
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case GET_RELEASED_BUFFERS: {
-            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
-            uint64_t slotMask = 0;
-            status_t result = getReleasedBuffers(&slotMask);
-            reply->writeInt64(static_cast<int64_t>(slotMask));
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case SET_DEFAULT_BUFFER_SIZE: {
-            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
-            uint32_t width = data.readUint32();
-            uint32_t height = data.readUint32();
-            status_t result = setDefaultBufferSize(width, height);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case SET_MAX_BUFFER_COUNT: {
-            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
-            int bufferCount = data.readInt32();
-            status_t result = setMaxBufferCount(bufferCount);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case SET_MAX_ACQUIRED_BUFFER_COUNT: {
-            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
-            int maxAcquiredBuffers = data.readInt32();
-            status_t result = setMaxAcquiredBufferCount(maxAcquiredBuffers);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case SET_CONSUMER_NAME: {
-            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
-            setConsumerName( data.readString8() );
-            return NO_ERROR;
-        }
-        case SET_DEFAULT_BUFFER_FORMAT: {
-            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
-            PixelFormat defaultFormat = static_cast<PixelFormat>(data.readInt32());
-            status_t result = setDefaultBufferFormat(defaultFormat);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case SET_DEFAULT_BUFFER_DATA_SPACE: {
-            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
-            android_dataspace defaultDataSpace =
-                    static_cast<android_dataspace>(data.readInt32());
-            status_t result = setDefaultBufferDataSpace(defaultDataSpace);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case SET_CONSUMER_USAGE_BITS: {
-            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
-            uint32_t usage = data.readUint32();
-            status_t result = setConsumerUsageBits(usage);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case SET_TRANSFORM_HINT: {
-            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
-            uint32_t hint = data.readUint32();
-            status_t result = setTransformHint(hint);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case GET_SIDEBAND_STREAM: {
-            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
-            sp<NativeHandle> stream = getSidebandStream();
-            reply->writeInt32(static_cast<int32_t>(stream != NULL));
-            if (stream != NULL) {
-                reply->writeNativeHandle(stream->handle());
-            }
-            return NO_ERROR;
-        }
-        case GET_OCCUPANCY_HISTORY: {
-            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
-            bool forceFlush = false;
-            status_t error = data.readBool(&forceFlush);
-            if (error != NO_ERROR) {
-                return error;
-            }
-            std::vector<OccupancyTracker::Segment> history;
-            status_t result = getOccupancyHistory(forceFlush, &history);
-            error = reply->writeParcelableVector(history);
-            if (error != NO_ERROR) {
-                return error;
-            }
-            error = reply->writeInt32(result);
-            if (error != NO_ERROR) {
-                return error;
-            }
-            return NO_ERROR;
-        }
-        case DISCARD_FREE_BUFFERS: {
-            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
-            status_t result = discardFreeBuffers();
-            status_t error = reply->writeInt32(result);
-            return error;
-        }
-        case DUMP: {
-            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
-            String8 result = data.readString8();
-            String8 prefix = data.readString8();
-            static_cast<IGraphicBufferConsumer*>(this)->dump(result, prefix);
-            reply->writeString8(result);
-            return NO_ERROR;
+status_t BnGraphicBufferConsumer::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::ACQUIRE_BUFFER:
+            return callLocal(data, reply, &IGraphicBufferConsumer::acquireBuffer);
+        case Tag::DETACH_BUFFER:
+            return callLocal(data, reply, &IGraphicBufferConsumer::detachBuffer);
+        case Tag::ATTACH_BUFFER:
+            return callLocal(data, reply, &IGraphicBufferConsumer::attachBuffer);
+        case Tag::RELEASE_BUFFER:
+            return callLocal(data, reply, &IGraphicBufferConsumer::releaseHelper);
+        case Tag::CONSUMER_CONNECT:
+            return callLocal(data, reply, &IGraphicBufferConsumer::consumerConnect);
+        case Tag::CONSUMER_DISCONNECT:
+            return callLocal(data, reply, &IGraphicBufferConsumer::consumerDisconnect);
+        case Tag::GET_RELEASED_BUFFERS:
+            return callLocal(data, reply, &IGraphicBufferConsumer::getReleasedBuffers);
+        case Tag::SET_DEFAULT_BUFFER_SIZE:
+            return callLocal(data, reply, &IGraphicBufferConsumer::setDefaultBufferSize);
+        case Tag::SET_MAX_BUFFER_COUNT:
+            return callLocal(data, reply, &IGraphicBufferConsumer::setMaxBufferCount);
+        case Tag::SET_MAX_ACQUIRED_BUFFER_COUNT:
+            return callLocal(data, reply, &IGraphicBufferConsumer::setMaxAcquiredBufferCount);
+        case Tag::SET_CONSUMER_NAME:
+            return callLocal(data, reply, &IGraphicBufferConsumer::setConsumerName);
+        case Tag::SET_DEFAULT_BUFFER_FORMAT:
+            return callLocal(data, reply, &IGraphicBufferConsumer::setDefaultBufferFormat);
+        case Tag::SET_DEFAULT_BUFFER_DATA_SPACE:
+            return callLocal(data, reply, &IGraphicBufferConsumer::setDefaultBufferDataSpace);
+        case Tag::SET_CONSUMER_USAGE_BITS:
+            return callLocal(data, reply, &IGraphicBufferConsumer::setConsumerUsageBits);
+        case Tag::SET_CONSUMER_IS_PROTECTED:
+            return callLocal(data, reply, &IGraphicBufferConsumer::setConsumerIsProtected);
+        case Tag::SET_TRANSFORM_HINT:
+            return callLocal(data, reply, &IGraphicBufferConsumer::setTransformHint);
+        case Tag::GET_SIDEBAND_STREAM:
+            return callLocal(data, reply, &IGraphicBufferConsumer::getSidebandStream);
+        case Tag::GET_OCCUPANCY_HISTORY:
+            return callLocal(data, reply, &IGraphicBufferConsumer::getOccupancyHistory);
+        case Tag::DISCARD_FREE_BUFFERS:
+            return callLocal(data, reply, &IGraphicBufferConsumer::discardFreeBuffers);
+        case Tag::DUMP_STATE: {
+            using Signature = status_t (IGraphicBufferConsumer::*)(const String8&, String8*) const;
+            return callLocal<Signature>(data, reply, &IGraphicBufferConsumer::dumpState);
         }
     }
-    return BBinder::onTransact(code, data, reply, flags);
 }
 
-}; // namespace android
+} // namespace android
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 1a08130..bca645f 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -20,6 +20,7 @@
 #include <utils/Errors.h>
 #include <utils/NativeHandle.h>
 #include <utils/RefBase.h>
+#include <utils/String8.h>
 #include <utils/Timers.h>
 #include <utils/Vector.h>
 
@@ -30,9 +31,14 @@
 #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::
+        H2BGraphicBufferProducer;
+
 enum {
     REQUEST_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
     DEQUEUE_BUFFER,
@@ -62,7 +68,7 @@
 class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
 {
 public:
-    BpGraphicBufferProducer(const sp<IBinder>& impl)
+    explicit BpGraphicBufferProducer(const sp<IBinder>& impl)
         : BpInterface<IGraphicBufferProducer>(impl)
     {
     }
@@ -119,24 +125,35 @@
     }
 
     virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, uint32_t width,
-            uint32_t height, PixelFormat format, uint32_t usage) {
+            uint32_t height, PixelFormat format, uint32_t usage,
+            FrameEventHistoryDelta* outTimestamps) {
         Parcel data, reply;
+        bool getFrameTimestamps = (outTimestamps != nullptr);
+
         data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
         data.writeUint32(width);
         data.writeUint32(height);
         data.writeInt32(static_cast<int32_t>(format));
         data.writeUint32(usage);
+        data.writeBool(getFrameTimestamps);
+
         status_t result = remote()->transact(DEQUEUE_BUFFER, data, &reply);
         if (result != NO_ERROR) {
             return result;
         }
+
         *buf = reply.readInt32();
-        bool nonNull = reply.readInt32();
-        if (nonNull) {
-            *fence = new Fence();
-            result = reply.read(**fence);
+        *fence = new Fence();
+        result = reply.read(**fence);
+        if (result != NO_ERROR) {
+            fence->clear();
+            return result;
+        }
+        if (getFrameTimestamps) {
+            result = reply.read(*outTimestamps);
             if (result != NO_ERROR) {
-                fence->clear();
+                ALOGE("IGBP::dequeueBuffer failed to read timestamps: %d",
+                        result);
                 return result;
             }
         }
@@ -220,14 +237,21 @@
     virtual status_t queueBuffer(int buf,
             const QueueBufferInput& input, QueueBufferOutput* output) {
         Parcel data, reply;
+
         data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
         data.writeInt32(buf);
         data.write(input);
+
         status_t result = remote()->transact(QUEUE_BUFFER, data, &reply);
         if (result != NO_ERROR) {
             return result;
         }
-        memcpy(output, reply.readInplace(sizeof(*output)), sizeof(*output));
+
+        result = reply.read(*output);
+        if (result != NO_ERROR) {
+            return result;
+        }
+
         result = reply.readInt32();
         return result;
     }
@@ -274,7 +298,7 @@
         if (result != NO_ERROR) {
             return result;
         }
-        memcpy(output, reply.readInplace(sizeof(*output)), sizeof(*output));
+        reply.read(*output);
         result = reply.readInt32();
         return result;
     }
@@ -431,40 +455,24 @@
         return result;
     }
 
-    virtual bool getFrameTimestamps(uint64_t frameNumber,
-                FrameTimestamps* outTimestamps) const {
+    virtual void getFrameTimestamps(FrameEventHistoryDelta* outDelta) {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(
                 IGraphicBufferProducer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
-            ALOGE("getFrameTimestamps failed to write token: %d", result);
-            return false;
-        }
-        result = data.writeUint64(frameNumber);
-        if (result != NO_ERROR) {
-            ALOGE("getFrameTimestamps failed to write: %d", result);
-            return false;
+            ALOGE("IGBP::getFrameTimestamps failed to write token: %d", result);
+            return;
         }
         result = remote()->transact(GET_FRAME_TIMESTAMPS, data, &reply);
         if (result != NO_ERROR) {
-            ALOGE("getFrameTimestamps failed to transact: %d", result);
-            return false;
+            ALOGE("IGBP::getFrameTimestamps failed to transact: %d", result);
+            return;
         }
-        bool found = false;
-        result = reply.readBool(&found);
+        result = reply.read(*outDelta);
         if (result != NO_ERROR) {
-            ALOGE("getFrameTimestamps failed to read: %d", result);
-            return false;
+            ALOGE("IGBP::getFrameTimestamps failed to read timestamps: %d",
+                    result);
         }
-        if (found) {
-            result = reply.read(*outTimestamps);
-            if (result != NO_ERROR) {
-                ALOGE("getFrameTimestamps failed to read timestamps: %d",
-                        result);
-                return false;
-            }
-        }
-        return found;
     }
 
     virtual status_t getUniqueId(uint64_t* outId) const {
@@ -491,7 +499,123 @@
 // translation unit (see clang warning -Wweak-vtables)
 BpGraphicBufferProducer::~BpGraphicBufferProducer() {}
 
-IMPLEMENT_META_INTERFACE(GraphicBufferProducer, "android.gui.IGraphicBufferProducer");
+class HpGraphicBufferProducer : public HpInterface<
+        BpGraphicBufferProducer, H2BGraphicBufferProducer> {
+public:
+    HpGraphicBufferProducer(const sp<IBinder>& base) : PBase(base) {}
+
+    status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override {
+        return mBase->requestBuffer(slot, buf);
+    }
+
+    status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) override {
+        return mBase->setMaxDequeuedBufferCount(maxDequeuedBuffers);
+    }
+
+    status_t setAsyncMode(bool async) override {
+        return mBase->setAsyncMode(async);
+    }
+
+    status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h,
+            PixelFormat format, uint32_t usage,
+            FrameEventHistoryDelta* outTimestamps) override {
+        return mBase->dequeueBuffer(
+                slot, fence, w, h, format, usage, outTimestamps);
+    }
+
+    status_t detachBuffer(int slot) override {
+        return mBase->detachBuffer(slot);
+    }
+
+    status_t detachNextBuffer(
+            sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) override {
+        return mBase->detachNextBuffer(outBuffer, outFence);
+    }
+
+    status_t attachBuffer(
+            int* outSlot, const sp<GraphicBuffer>& buffer) override {
+        return mBase->attachBuffer(outSlot, buffer);
+    }
+
+    status_t queueBuffer(
+            int slot,
+            const QueueBufferInput& input,
+            QueueBufferOutput* output) override {
+        return mBase->queueBuffer(slot, input, output);
+    }
+
+    status_t cancelBuffer(int slot, const sp<Fence>& fence) override {
+        return mBase->cancelBuffer(slot, fence);
+    }
+
+    int query(int what, int* value) override {
+        return mBase->query(what, value);
+    }
+
+    status_t connect(
+            const sp<IProducerListener>& listener,
+            int api, bool producerControlledByApp,
+            QueueBufferOutput* output) override {
+        return mBase->connect(listener, api, producerControlledByApp, output);
+    }
+
+    status_t disconnect(
+            int api, DisconnectMode mode = DisconnectMode::Api) override {
+        return mBase->disconnect(api, mode);
+    }
+
+    status_t setSidebandStream(const sp<NativeHandle>& stream) override {
+        return mBase->setSidebandStream(stream);
+    }
+
+    void allocateBuffers(uint32_t width, uint32_t height,
+            PixelFormat format, uint32_t usage) override {
+        return mBase->allocateBuffers(width, height, format, usage);
+    }
+
+    status_t allowAllocation(bool allow) override {
+        return mBase->allowAllocation(allow);
+    }
+
+    status_t setGenerationNumber(uint32_t generationNumber) override {
+        return mBase->setGenerationNumber(generationNumber);
+    }
+
+    String8 getConsumerName() const override {
+        return mBase->getConsumerName();
+    }
+
+    status_t setSharedBufferMode(bool sharedBufferMode) override {
+        return mBase->setSharedBufferMode(sharedBufferMode);
+    }
+
+    status_t setAutoRefresh(bool autoRefresh) override {
+        return mBase->setAutoRefresh(autoRefresh);
+    }
+
+    status_t setDequeueTimeout(nsecs_t timeout) override {
+        return mBase->setDequeueTimeout(timeout);
+    }
+
+    status_t getLastQueuedBuffer(
+            sp<GraphicBuffer>* outBuffer,
+            sp<Fence>* outFence,
+            float outTransformMatrix[16]) override {
+        return mBase->getLastQueuedBuffer(
+                outBuffer, outFence, outTransformMatrix);
+    }
+
+    void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override {
+        return mBase->getFrameTimestamps(outDelta);
+    }
+
+    status_t getUniqueId(uint64_t* outId) const override {
+        return mBase->getUniqueId(outId);
+    }
+};
+
+IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer, HGraphicBufferProducer,
+        "android.gui.IGraphicBufferProducer");
 
 // ----------------------------------------------------------------------
 
@@ -531,14 +655,18 @@
             uint32_t height = data.readUint32();
             PixelFormat format = static_cast<PixelFormat>(data.readInt32());
             uint32_t usage = data.readUint32();
+            bool getTimestamps = data.readBool();
+
             int buf = 0;
-            sp<Fence> fence;
+            sp<Fence> fence = Fence::NO_FENCE;
+            FrameEventHistoryDelta frameTimestamps;
             int result = dequeueBuffer(&buf, &fence, width, height, format,
-                    usage);
+                    usage, getTimestamps ? &frameTimestamps : nullptr);
+
             reply->writeInt32(buf);
-            reply->writeInt32(fence != NULL);
-            if (fence != NULL) {
-                reply->write(*fence);
+            reply->write(*fence);
+            if (getTimestamps) {
+                reply->write(frameTimestamps);
             }
             reply->writeInt32(result);
             return NO_ERROR;
@@ -582,14 +710,14 @@
         }
         case QUEUE_BUFFER: {
             CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+
             int buf = data.readInt32();
             QueueBufferInput input(data);
-            QueueBufferOutput* const output =
-                    reinterpret_cast<QueueBufferOutput *>(
-                            reply->writeInplace(sizeof(QueueBufferOutput)));
-            memset(output, 0, sizeof(QueueBufferOutput));
-            status_t result = queueBuffer(buf, input, output);
+            QueueBufferOutput output;
+            status_t result = queueBuffer(buf, input, &output);
+            reply->write(output);
             reply->writeInt32(result);
+
             return NO_ERROR;
         }
         case CANCEL_BUFFER: {
@@ -620,11 +748,9 @@
             }
             int api = data.readInt32();
             bool producerControlledByApp = data.readInt32();
-            QueueBufferOutput* const output =
-                    reinterpret_cast<QueueBufferOutput *>(
-                            reply->writeInplace(sizeof(QueueBufferOutput)));
-            memset(output, 0, sizeof(QueueBufferOutput));
-            status_t res = connect(listener, api, producerControlledByApp, output);
+            QueueBufferOutput output;
+            status_t res = connect(listener, api, producerControlledByApp, &output);
+            reply->write(output);
             reply->writeInt32(res);
             return NO_ERROR;
         }
@@ -727,26 +853,14 @@
         }
         case GET_FRAME_TIMESTAMPS: {
             CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
-            uint64_t frameNumber = 0;
-            status_t result = data.readUint64(&frameNumber);
+            FrameEventHistoryDelta frameTimestamps;
+            getFrameTimestamps(&frameTimestamps);
+            status_t result = reply->write(frameTimestamps);
             if (result != NO_ERROR) {
-                ALOGE("onTransact failed to read: %d", result);
+                ALOGE("BnGBP::GET_FRAME_TIMESTAMPS failed to write buffer: %d",
+                        result);
                 return result;
             }
-            FrameTimestamps timestamps;
-            bool found = getFrameTimestamps(frameNumber, &timestamps);
-            result = reply->writeBool(found);
-            if (result != NO_ERROR) {
-                ALOGE("onTransact failed to write: %d", result);
-                return result;
-            }
-            if (found) {
-                result = reply->write(timestamps);
-                if (result != NO_ERROR) {
-                    ALOGE("onTransact failed to write timestamps: %d", result);
-                    return result;
-                }
-            }
             return NO_ERROR;
         }
         case GET_UNIQUE_ID: {
@@ -773,16 +887,21 @@
     parcel.read(*this);
 }
 
+constexpr size_t IGraphicBufferProducer::QueueBufferInput::minFlattenedSize() {
+    return sizeof(timestamp) +
+            sizeof(isAutoTimestamp) +
+            sizeof(dataSpace) +
+            sizeof(crop) +
+            sizeof(scalingMode) +
+            sizeof(transform) +
+            sizeof(stickyTransform) +
+            sizeof(getFrameTimestamps);
+}
+
 size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const {
-    return sizeof(timestamp)
-         + sizeof(isAutoTimestamp)
-         + sizeof(dataSpace)
-         + sizeof(crop)
-         + sizeof(scalingMode)
-         + sizeof(transform)
-         + sizeof(stickyTransform)
-         + fence->getFlattenedSize()
-         + surfaceDamage.getFlattenedSize();
+    return minFlattenedSize() +
+            fence->getFlattenedSize() +
+            surfaceDamage.getFlattenedSize();
 }
 
 size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const {
@@ -795,6 +914,7 @@
     if (size < getFlattenedSize()) {
         return NO_MEMORY;
     }
+
     FlattenableUtils::write(buffer, size, timestamp);
     FlattenableUtils::write(buffer, size, isAutoTimestamp);
     FlattenableUtils::write(buffer, size, dataSpace);
@@ -802,6 +922,8 @@
     FlattenableUtils::write(buffer, size, scalingMode);
     FlattenableUtils::write(buffer, size, transform);
     FlattenableUtils::write(buffer, size, stickyTransform);
+    FlattenableUtils::write(buffer, size, getFrameTimestamps);
+
     status_t result = fence->flatten(buffer, size, fds, count);
     if (result != NO_ERROR) {
         return result;
@@ -812,16 +934,7 @@
 status_t IGraphicBufferProducer::QueueBufferInput::unflatten(
         void const*& buffer, size_t& size, int const*& fds, size_t& count)
 {
-    size_t minNeeded =
-              sizeof(timestamp)
-            + sizeof(isAutoTimestamp)
-            + sizeof(dataSpace)
-            + sizeof(crop)
-            + sizeof(scalingMode)
-            + sizeof(transform)
-            + sizeof(stickyTransform);
-
-    if (size < minNeeded) {
+    if (size < minFlattenedSize()) {
         return NO_MEMORY;
     }
 
@@ -832,6 +945,7 @@
     FlattenableUtils::read(buffer, size, scalingMode);
     FlattenableUtils::read(buffer, size, transform);
     FlattenableUtils::read(buffer, size, stickyTransform);
+    FlattenableUtils::read(buffer, size, getFrameTimestamps);
 
     fence = new Fence();
     status_t result = fence->unflatten(buffer, size, fds, count);
@@ -841,4 +955,56 @@
     return surfaceDamage.unflatten(buffer, size);
 }
 
+// ----------------------------------------------------------------------------
+constexpr size_t IGraphicBufferProducer::QueueBufferOutput::minFlattenedSize() {
+    return sizeof(width) +
+            sizeof(height) +
+            sizeof(transformHint) +
+            sizeof(numPendingBuffers) +
+            sizeof(nextFrameNumber) +
+            sizeof(bufferReplaced);
+}
+
+size_t IGraphicBufferProducer::QueueBufferOutput::getFlattenedSize() const {
+    return minFlattenedSize() + frameTimestamps.getFlattenedSize();
+}
+
+size_t IGraphicBufferProducer::QueueBufferOutput::getFdCount() const {
+    return frameTimestamps.getFdCount();
+}
+
+status_t IGraphicBufferProducer::QueueBufferOutput::flatten(
+        void*& buffer, size_t& size, int*& fds, size_t& count) const
+{
+    if (size < getFlattenedSize()) {
+        return NO_MEMORY;
+    }
+
+    FlattenableUtils::write(buffer, size, width);
+    FlattenableUtils::write(buffer, size, height);
+    FlattenableUtils::write(buffer, size, transformHint);
+    FlattenableUtils::write(buffer, size, numPendingBuffers);
+    FlattenableUtils::write(buffer, size, nextFrameNumber);
+    FlattenableUtils::write(buffer, size, bufferReplaced);
+
+    return frameTimestamps.flatten(buffer, size, fds, count);
+}
+
+status_t IGraphicBufferProducer::QueueBufferOutput::unflatten(
+        void const*& buffer, size_t& size, int const*& fds, size_t& count)
+{
+    if (size < minFlattenedSize()) {
+        return NO_MEMORY;
+    }
+
+    FlattenableUtils::read(buffer, size, width);
+    FlattenableUtils::read(buffer, size, height);
+    FlattenableUtils::read(buffer, size, transformHint);
+    FlattenableUtils::read(buffer, size, numPendingBuffers);
+    FlattenableUtils::read(buffer, size, nextFrameNumber);
+    FlattenableUtils::read(buffer, size, bufferReplaced);
+
+    return frameTimestamps.unflatten(buffer, size, fds, count);
+}
+
 }; // namespace android
diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp
index da54ce1..62abfa8 100644
--- a/libs/gui/IProducerListener.cpp
+++ b/libs/gui/IProducerListener.cpp
@@ -28,7 +28,7 @@
 class BpProducerListener : public BpInterface<IProducerListener>
 {
 public:
-    BpProducerListener(const sp<IBinder>& impl)
+    explicit BpProducerListener(const sp<IBinder>& impl)
         : BpInterface<IProducerListener>(impl) {}
 
     virtual ~BpProducerListener();
@@ -78,6 +78,10 @@
     return BBinder::onTransact(code, data, reply, flags);
 }
 
+ProducerListener::~ProducerListener() = default;
+
+DummyProducerListener::~DummyProducerListener() = default;
+
 bool BnProducerListener::needsReleaseNotify() {
     return true;
 }
diff --git a/libs/gui/ISensorEventConnection.cpp b/libs/gui/ISensorEventConnection.cpp
deleted file mode 100644
index dc7a35c..0000000
--- a/libs/gui/ISensorEventConnection.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * 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 <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/Timers.h>
-
-#include <binder/Parcel.h>
-#include <binder/IInterface.h>
-
-#include <gui/ISensorEventConnection.h>
-#include <gui/BitTube.h>
-
-namespace android {
-// ----------------------------------------------------------------------------
-
-enum {
-    GET_SENSOR_CHANNEL = IBinder::FIRST_CALL_TRANSACTION,
-    ENABLE_DISABLE,
-    SET_EVENT_RATE,
-    FLUSH_SENSOR
-};
-
-class BpSensorEventConnection : public BpInterface<ISensorEventConnection>
-{
-public:
-    BpSensorEventConnection(const sp<IBinder>& impl)
-        : BpInterface<ISensorEventConnection>(impl)
-    {
-    }
-
-    virtual ~BpSensorEventConnection();
-
-    virtual sp<BitTube> getSensorChannel() const
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISensorEventConnection::getInterfaceDescriptor());
-        remote()->transact(GET_SENSOR_CHANNEL, data, &reply);
-        return new BitTube(reply);
-    }
-
-    virtual status_t enableDisable(int handle, bool enabled, nsecs_t samplingPeriodNs,
-                                   nsecs_t maxBatchReportLatencyNs, int reservedFlags)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISensorEventConnection::getInterfaceDescriptor());
-        data.writeInt32(handle);
-        data.writeInt32(enabled);
-        data.writeInt64(samplingPeriodNs);
-        data.writeInt64(maxBatchReportLatencyNs);
-        data.writeInt32(reservedFlags);
-        remote()->transact(ENABLE_DISABLE, data, &reply);
-        return reply.readInt32();
-    }
-
-    virtual status_t setEventRate(int handle, nsecs_t ns)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISensorEventConnection::getInterfaceDescriptor());
-        data.writeInt32(handle);
-        data.writeInt64(ns);
-        remote()->transact(SET_EVENT_RATE, data, &reply);
-        return reply.readInt32();
-    }
-
-    virtual status_t flush() {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISensorEventConnection::getInterfaceDescriptor());
-        remote()->transact(FLUSH_SENSOR, data, &reply);
-        return reply.readInt32();
-    }
-};
-
-// Out-of-line virtual method definition to trigger vtable emission in this
-// translation unit (see clang warning -Wweak-vtables)
-BpSensorEventConnection::~BpSensorEventConnection() {}
-
-IMPLEMENT_META_INTERFACE(SensorEventConnection, "android.gui.SensorEventConnection");
-
-// ----------------------------------------------------------------------------
-
-status_t BnSensorEventConnection::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    switch(code) {
-        case GET_SENSOR_CHANNEL: {
-            CHECK_INTERFACE(ISensorEventConnection, data, reply);
-            sp<BitTube> channel(getSensorChannel());
-            channel->writeToParcel(reply);
-            return NO_ERROR;
-        }
-        case ENABLE_DISABLE: {
-            CHECK_INTERFACE(ISensorEventConnection, data, reply);
-            int handle = data.readInt32();
-            int enabled = data.readInt32();
-            nsecs_t samplingPeriodNs = data.readInt64();
-            nsecs_t maxBatchReportLatencyNs = data.readInt64();
-            int reservedFlags = data.readInt32();
-            status_t result = enableDisable(handle, enabled, samplingPeriodNs,
-                                            maxBatchReportLatencyNs, reservedFlags);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case SET_EVENT_RATE: {
-            CHECK_INTERFACE(ISensorEventConnection, data, reply);
-            int handle = data.readInt32();
-            nsecs_t ns = data.readInt64();
-            status_t result = setEventRate(handle, ns);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case FLUSH_SENSOR: {
-            CHECK_INTERFACE(ISensorEventConnection, data, reply);
-            status_t result = flush();
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-    }
-    return BBinder::onTransact(code, data, reply, flags);
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
diff --git a/libs/gui/ISensorServer.cpp b/libs/gui/ISensorServer.cpp
deleted file mode 100644
index 3a4c7e4..0000000
--- a/libs/gui/ISensorServer.cpp
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * 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 <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/Vector.h>
-#include <utils/Timers.h>
-
-#include <binder/Parcel.h>
-#include <binder/IInterface.h>
-
-#include <gui/Sensor.h>
-#include <gui/ISensorServer.h>
-#include <gui/ISensorEventConnection.h>
-
-namespace android {
-// ----------------------------------------------------------------------------
-
-enum {
-    GET_SENSOR_LIST = IBinder::FIRST_CALL_TRANSACTION,
-    CREATE_SENSOR_EVENT_CONNECTION,
-    ENABLE_DATA_INJECTION,
-    GET_DYNAMIC_SENSOR_LIST,
-};
-
-class BpSensorServer : public BpInterface<ISensorServer>
-{
-public:
-    BpSensorServer(const sp<IBinder>& impl)
-        : BpInterface<ISensorServer>(impl)
-    {
-    }
-
-    virtual ~BpSensorServer();
-
-    virtual Vector<Sensor> getSensorList(const String16& opPackageName)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor());
-        data.writeString16(opPackageName);
-        remote()->transact(GET_SENSOR_LIST, data, &reply);
-        Sensor s;
-        Vector<Sensor> v;
-        uint32_t n = reply.readUint32();
-        v.setCapacity(n);
-        while (n--) {
-            reply.read(s);
-            v.add(s);
-        }
-        return v;
-    }
-
-    virtual Vector<Sensor> getDynamicSensorList(const String16& opPackageName)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor());
-        data.writeString16(opPackageName);
-        remote()->transact(GET_DYNAMIC_SENSOR_LIST, data, &reply);
-        Sensor s;
-        Vector<Sensor> v;
-        uint32_t n = reply.readUint32();
-        v.setCapacity(n);
-        while (n--) {
-            reply.read(s);
-            v.add(s);
-        }
-        return v;
-    }
-
-    virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName,
-             int mode, const String16& opPackageName)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor());
-        data.writeString8(packageName);
-        data.writeInt32(mode);
-        data.writeString16(opPackageName);
-        remote()->transact(CREATE_SENSOR_EVENT_CONNECTION, data, &reply);
-        return interface_cast<ISensorEventConnection>(reply.readStrongBinder());
-    }
-
-    virtual int isDataInjectionEnabled() {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor());
-        remote()->transact(ENABLE_DATA_INJECTION, data, &reply);
-        return reply.readInt32();
-    }
-};
-
-// Out-of-line virtual method definition to trigger vtable emission in this
-// translation unit (see clang warning -Wweak-vtables)
-BpSensorServer::~BpSensorServer() {}
-
-IMPLEMENT_META_INTERFACE(SensorServer, "android.gui.SensorServer");
-
-// ----------------------------------------------------------------------
-
-status_t BnSensorServer::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    switch(code) {
-        case GET_SENSOR_LIST: {
-            CHECK_INTERFACE(ISensorServer, data, reply);
-            const String16& opPackageName = data.readString16();
-            Vector<Sensor> v(getSensorList(opPackageName));
-            size_t n = v.size();
-            reply->writeUint32(static_cast<uint32_t>(n));
-            for (size_t i = 0; i < n; i++) {
-                reply->write(v[i]);
-            }
-            return NO_ERROR;
-        }
-        case CREATE_SENSOR_EVENT_CONNECTION: {
-            CHECK_INTERFACE(ISensorServer, data, reply);
-            String8 packageName = data.readString8();
-            int32_t mode = data.readInt32();
-            const String16& opPackageName = data.readString16();
-            sp<ISensorEventConnection> connection(createSensorEventConnection(packageName, mode,
-                    opPackageName));
-            reply->writeStrongBinder(IInterface::asBinder(connection));
-            return NO_ERROR;
-        }
-        case ENABLE_DATA_INJECTION: {
-            CHECK_INTERFACE(ISensorServer, data, reply);
-            int32_t ret = isDataInjectionEnabled();
-            reply->writeInt32(static_cast<int32_t>(ret));
-            return NO_ERROR;
-        }
-        case GET_DYNAMIC_SENSOR_LIST: {
-            CHECK_INTERFACE(ISensorServer, data, reply);
-            const String16& opPackageName = data.readString16();
-            Vector<Sensor> v(getDynamicSensorList(opPackageName));
-            size_t n = v.size();
-            reply->writeUint32(static_cast<uint32_t>(n));
-            for (size_t i = 0; i < n; i++) {
-                reply->write(v[i]);
-            }
-            return NO_ERROR;
-        }
-    }
-    return BBinder::onTransact(code, data, reply, flags);
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index f0b0ada..0a0d112 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -21,14 +21,13 @@
 #include <sys/types.h>
 
 #include <binder/Parcel.h>
-#include <binder/IMemory.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 
-#include <gui/BitTube.h>
 #include <gui/IDisplayEventConnection.h>
-#include <gui/ISurfaceComposer.h>
 #include <gui/IGraphicBufferProducer.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/ISurfaceComposerClient.h>
 
 #include <private/gui/LayerState.h>
 
@@ -44,12 +43,10 @@
 
 namespace android {
 
-class IDisplayEventConnection;
-
 class BpSurfaceComposer : public BpInterface<ISurfaceComposer>
 {
 public:
-    BpSurfaceComposer(const sp<IBinder>& impl)
+    explicit BpSurfaceComposer(const sp<IBinder>& impl)
         : BpInterface<ISurfaceComposer>(impl)
     {
     }
@@ -64,12 +61,14 @@
         return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
     }
 
-    virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc()
+    virtual sp<ISurfaceComposerClient> createScopedConnection(
+            const sp<IGraphicBufferProducer>& parent)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        remote()->transact(BnSurfaceComposer::CREATE_GRAPHIC_BUFFER_ALLOC, data, &reply);
-        return interface_cast<IGraphicBufferAlloc>(reply.readStrongBinder());
+        data.writeStrongBinder(IInterface::asBinder(parent));
+        remote()->transact(BnSurfaceComposer::CREATE_SCOPED_CONNECTION, data, &reply);
+        return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
     }
 
     virtual void setTransactionState(
@@ -104,7 +103,7 @@
     virtual status_t captureScreen(const sp<IBinder>& display,
             const sp<IGraphicBufferProducer>& producer,
             Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            uint32_t minLayerZ, uint32_t maxLayerZ,
+            int32_t minLayerZ, int32_t maxLayerZ,
             bool useIdentityTransform,
             ISurfaceComposer::Rotation rotation)
     {
@@ -115,8 +114,8 @@
         data.write(sourceCrop);
         data.writeUint32(reqWidth);
         data.writeUint32(reqHeight);
-        data.writeUint32(minLayerZ);
-        data.writeUint32(maxLayerZ);
+        data.writeInt32(minLayerZ);
+        data.writeInt32(maxLayerZ);
         data.writeInt32(static_cast<int32_t>(useIdentityTransform));
         data.writeInt32(static_cast<int32_t>(rotation));
         remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
@@ -158,7 +157,51 @@
         return result != 0;
     }
 
-    virtual sp<IDisplayEventConnection> createDisplayEventConnection()
+    virtual status_t getSupportedFrameTimestamps(
+            std::vector<FrameEvent>* outSupported) const {
+        if (!outSupported) {
+            return UNEXPECTED_NULL;
+        }
+        outSupported->clear();
+
+        Parcel data, reply;
+
+        status_t err = data.writeInterfaceToken(
+                ISurfaceComposer::getInterfaceDescriptor());
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+        err = remote()->transact(
+                BnSurfaceComposer::GET_SUPPORTED_FRAME_TIMESTAMPS,
+                data, &reply);
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+        int32_t result = 0;
+        err = reply.readInt32(&result);
+        if (err != NO_ERROR) {
+            return err;
+        }
+        if (result != NO_ERROR) {
+            return result;
+        }
+
+        std::vector<int32_t> supported;
+        err = reply.readInt32Vector(&supported);
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+        outSupported->reserve(supported.size());
+        for (int32_t s : supported) {
+            outSupported->push_back(static_cast<FrameEvent>(s));
+        }
+        return NO_ERROR;
+    }
+
+    virtual sp<IDisplayEventConnection> createDisplayEventConnection(VsyncSource vsyncSource)
     {
         Parcel data, reply;
         sp<IDisplayEventConnection> result;
@@ -167,6 +210,7 @@
         if (err != NO_ERROR) {
             return result;
         }
+        data.writeInt32(static_cast<int32_t>(vsyncSource));
         err = remote()->transact(
                 BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION,
                 data, &reply);
@@ -379,10 +423,52 @@
         }
         result = reply.readInt32();
         if (result == NO_ERROR) {
-            result = reply.readParcelable(outCapabilities);
+            result = reply.read(*outCapabilities);
         }
         return result;
     }
+
+    virtual status_t enableVSyncInjections(bool enable) {
+        Parcel data, reply;
+        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (result != NO_ERROR) {
+            ALOGE("enableVSyncInjections failed to writeInterfaceToken: %d", result);
+            return result;
+        }
+        result = data.writeBool(enable);
+        if (result != NO_ERROR) {
+            ALOGE("enableVSyncInjections failed to writeBool: %d", result);
+            return result;
+        }
+        result = remote()->transact(BnSurfaceComposer::ENABLE_VSYNC_INJECTIONS,
+                data, &reply, TF_ONE_WAY);
+        if (result != NO_ERROR) {
+            ALOGE("enableVSyncInjections failed to transact: %d", result);
+            return result;
+        }
+        return result;
+    }
+
+    virtual status_t injectVSync(nsecs_t when) {
+        Parcel data, reply;
+        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (result != NO_ERROR) {
+            ALOGE("injectVSync failed to writeInterfaceToken: %d", result);
+            return result;
+        }
+        result = data.writeInt64(when);
+        if (result != NO_ERROR) {
+            ALOGE("injectVSync failed to writeInt64: %d", result);
+            return result;
+        }
+        result = remote()->transact(BnSurfaceComposer::INJECT_VSYNC, data, &reply, TF_ONE_WAY);
+        if (result != NO_ERROR) {
+            ALOGE("injectVSync failed to transact: %d", result);
+            return result;
+        }
+        return result;
+    }
+
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -403,9 +489,11 @@
             reply->writeStrongBinder(b);
             return NO_ERROR;
         }
-        case CREATE_GRAPHIC_BUFFER_ALLOC: {
+        case CREATE_SCOPED_CONNECTION: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> b = IInterface::asBinder(createGraphicBufferAlloc());
+            sp<IGraphicBufferProducer> bufferProducer =
+                interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
+            sp<IBinder> b = IInterface::asBinder(createScopedConnection(bufferProducer));
             reply->writeStrongBinder(b);
             return NO_ERROR;
         }
@@ -458,8 +546,8 @@
             data.read(sourceCrop);
             uint32_t reqWidth = data.readUint32();
             uint32_t reqHeight = data.readUint32();
-            uint32_t minLayerZ = data.readUint32();
-            uint32_t maxLayerZ = data.readUint32();
+            int32_t minLayerZ = data.readInt32();
+            int32_t maxLayerZ = data.readInt32();
             bool useIdentityTransform = static_cast<bool>(data.readInt32());
             int32_t rotation = data.readInt32();
 
@@ -478,9 +566,29 @@
             reply->writeInt32(result);
             return NO_ERROR;
         }
+        case GET_SUPPORTED_FRAME_TIMESTAMPS: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            std::vector<FrameEvent> supportedTimestamps;
+            status_t result = getSupportedFrameTimestamps(&supportedTimestamps);
+            status_t err = reply->writeInt32(result);
+            if (err != NO_ERROR) {
+                return err;
+            }
+            if (result != NO_ERROR) {
+                return result;
+            }
+
+            std::vector<int32_t> supported;
+            supported.reserve(supportedTimestamps.size());
+            for (FrameEvent s : supportedTimestamps) {
+                supported.push_back(static_cast<int32_t>(s));
+            }
+            return reply->writeInt32Vector(supported);
+        }
         case CREATE_DISPLAY_EVENT_CONNECTION: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IDisplayEventConnection> connection(createDisplayEventConnection());
+            sp<IDisplayEventConnection> connection(createDisplayEventConnection(
+                    static_cast<ISurfaceComposer::VsyncSource>(data.readInt32())));
             reply->writeStrongBinder(IInterface::asBinder(connection));
             return NO_ERROR;
         }
@@ -631,10 +739,30 @@
             result = getHdrCapabilities(display, &capabilities);
             reply->writeInt32(result);
             if (result == NO_ERROR) {
-                reply->writeParcelable(capabilities);
+                reply->write(capabilities);
             }
             return NO_ERROR;
         }
+        case ENABLE_VSYNC_INJECTIONS: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            bool enable = false;
+            status_t result = data.readBool(&enable);
+            if (result != NO_ERROR) {
+                ALOGE("enableVSyncInjections failed to readBool: %d", result);
+                return result;
+            }
+            return enableVSyncInjections(enable);
+        }
+        case INJECT_VSYNC: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            int64_t when = 0;
+            status_t result = data.readInt64(&when);
+            if (result != NO_ERROR) {
+                ALOGE("enableVSyncInjections failed to readInt64: %d", result);
+                return result;
+            }
+            return injectVSync(when);
+        }
         default: {
             return BBinder::onTransact(code, data, reply, flags);
         }
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index dd5b169..679f44b 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -17,112 +17,61 @@
 // tag as surfaceflinger
 #define LOG_TAG "SurfaceFlinger"
 
-#include <stdio.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/Parcel.h>
-#include <binder/IMemory.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-
-#include <ui/Point.h>
-#include <ui/Rect.h>
+#include <gui/ISurfaceComposerClient.h>
 
 #include <gui/IGraphicBufferProducer.h>
-#include <gui/ISurfaceComposerClient.h>
-#include <private/gui/LayerState.h>
 
-// ---------------------------------------------------------------------------
+#include <binder/SafeInterface.h>
+
+#include <ui/FrameStats.h>
 
 namespace android {
 
-enum {
+namespace { // Anonymous
+
+enum class Tag : uint32_t {
     CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
     DESTROY_SURFACE,
     CLEAR_LAYER_FRAME_STATS,
     GET_LAYER_FRAME_STATS,
-    GET_TRANSFORM_TO_DISPLAY_INVERSE
+    LAST = GET_LAYER_FRAME_STATS,
 };
 
-class BpSurfaceComposerClient : public BpInterface<ISurfaceComposerClient>
-{
+} // Anonymous namespace
+
+class BpSurfaceComposerClient : public SafeBpInterface<ISurfaceComposerClient> {
 public:
-    BpSurfaceComposerClient(const sp<IBinder>& impl)
-        : BpInterface<ISurfaceComposerClient>(impl) {
+    explicit BpSurfaceComposerClient(const sp<IBinder>& impl)
+          : SafeBpInterface<ISurfaceComposerClient>(impl, "BpSurfaceComposerClient") {}
+
+    ~BpSurfaceComposerClient() override;
+
+    status_t createSurface(const String8& name, uint32_t width, uint32_t height, PixelFormat format,
+                           uint32_t flags, const sp<IBinder>& parent, uint32_t windowType,
+                           uint32_t ownerUid, sp<IBinder>* handle,
+                           sp<IGraphicBufferProducer>* gbp) override {
+        return callRemote<decltype(&ISurfaceComposerClient::createSurface)>(Tag::CREATE_SURFACE,
+                                                                            name, width, height,
+                                                                            format, flags, parent,
+                                                                            windowType, ownerUid,
+                                                                            handle, gbp);
     }
 
-    virtual ~BpSurfaceComposerClient();
-
-    virtual status_t createSurface(const String8& name, uint32_t width,
-            uint32_t height, PixelFormat format, uint32_t flags,
-            sp<IBinder>* handle,
-            sp<IGraphicBufferProducer>* gbp) {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
-        data.writeString8(name);
-        data.writeUint32(width);
-        data.writeUint32(height);
-        data.writeInt32(static_cast<int32_t>(format));
-        data.writeUint32(flags);
-        remote()->transact(CREATE_SURFACE, data, &reply);
-        *handle = reply.readStrongBinder();
-        *gbp = interface_cast<IGraphicBufferProducer>(reply.readStrongBinder());
-        return reply.readInt32();
+    status_t destroySurface(const sp<IBinder>& handle) override {
+        return callRemote<decltype(&ISurfaceComposerClient::destroySurface)>(Tag::DESTROY_SURFACE,
+                                                                             handle);
     }
 
-    virtual status_t destroySurface(const sp<IBinder>& handle) {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
-        data.writeStrongBinder(handle);
-        remote()->transact(DESTROY_SURFACE, data, &reply);
-        return reply.readInt32();
+    status_t clearLayerFrameStats(const sp<IBinder>& handle) const override {
+        return callRemote<decltype(
+                &ISurfaceComposerClient::clearLayerFrameStats)>(Tag::CLEAR_LAYER_FRAME_STATS,
+                                                                handle);
     }
 
-    virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
-        data.writeStrongBinder(handle);
-        remote()->transact(CLEAR_LAYER_FRAME_STATS, data, &reply);
-        return reply.readInt32();
-    }
-
-    virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
-        data.writeStrongBinder(handle);
-        remote()->transact(GET_LAYER_FRAME_STATS, data, &reply);
-        reply.read(*outStats);
-        return reply.readInt32();
-    }
-
-    virtual status_t getTransformToDisplayInverse(const sp<IBinder>& handle,
-            bool* outTransformToDisplayInverse) const {
-        Parcel data, reply;
-        status_t result =
-                data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            return result;
-        }
-        result = data.writeStrongBinder(handle);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        result = remote()->transact(GET_TRANSFORM_TO_DISPLAY_INVERSE, data, &reply);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        int transformInverse;
-        result = reply.readInt32(&transformInverse);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        *outTransformToDisplayInverse = transformInverse != 0 ? true : false;
-        status_t result2 = reply.readInt32(&result);
-        if (result2 != NO_ERROR) {
-            return result2;
-        }
-        return result;
+    status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const override {
+        return callRemote<decltype(
+                &ISurfaceComposerClient::getLayerFrameStats)>(Tag::GET_LAYER_FRAME_STATS, handle,
+                                                              outStats);
     }
 };
 
@@ -134,69 +83,22 @@
 
 // ----------------------------------------------------------------------
 
-status_t BnSurfaceComposerClient::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-     switch(code) {
-        case CREATE_SURFACE: {
-            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
-            String8 name = data.readString8();
-            uint32_t width = data.readUint32();
-            uint32_t height = data.readUint32();
-            PixelFormat format = static_cast<PixelFormat>(data.readInt32());
-            uint32_t createFlags = data.readUint32();
-            sp<IBinder> handle;
-            sp<IGraphicBufferProducer> gbp;
-            status_t result = createSurface(name, width, height, format,
-                    createFlags, &handle, &gbp);
-            reply->writeStrongBinder(handle);
-            reply->writeStrongBinder(IInterface::asBinder(gbp));
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case DESTROY_SURFACE: {
-            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
-            reply->writeInt32(destroySurface( data.readStrongBinder() ) );
-            return NO_ERROR;
-        }
-       case CLEAR_LAYER_FRAME_STATS: {
-            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
-            sp<IBinder> handle = data.readStrongBinder();
-            status_t result = clearLayerFrameStats(handle);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case GET_LAYER_FRAME_STATS: {
-            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
-            sp<IBinder> handle = data.readStrongBinder();
-            FrameStats stats;
-            status_t result = getLayerFrameStats(handle, &stats);
-            reply->write(stats);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case GET_TRANSFORM_TO_DISPLAY_INVERSE: {
-            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
-            sp<IBinder> handle;
-            status_t result = data.readStrongBinder(&handle);
-            if (result != NO_ERROR) {
-                return result;
-            }
-            bool transformInverse = false;
-            result = getTransformToDisplayInverse(handle, &transformInverse);
-            if (result != NO_ERROR) {
-                return result;
-            }
-            result = reply->writeInt32(transformInverse ? 1 : 0);
-            if (result != NO_ERROR) {
-                return result;
-            }
-            result = reply->writeInt32(NO_ERROR);
-            return result;
-        }
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
+status_t BnSurfaceComposerClient::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::CREATE_SURFACE:
+            return callLocal(data, reply, &ISurfaceComposerClient::createSurface);
+        case Tag::DESTROY_SURFACE:
+            return callLocal(data, reply, &ISurfaceComposerClient::destroySurface);
+        case Tag::CLEAR_LAYER_FRAME_STATS:
+            return callLocal(data, reply, &ISurfaceComposerClient::clearLayerFrameStats);
+        case Tag::GET_LAYER_FRAME_STATS:
+            return callLocal(data, reply, &ISurfaceComposerClient::getLayerFrameStats);
     }
 }
 
-}; // namespace android
+} // namespace android
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index d1c576e..9b06e63 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -28,7 +28,7 @@
     output.writeUint32(what);
     output.writeFloat(x);
     output.writeFloat(y);
-    output.writeUint32(z);
+    output.writeInt32(z);
     output.writeUint32(w);
     output.writeUint32(h);
     output.writeUint32(layerStack);
@@ -39,9 +39,12 @@
             output.writeInplace(sizeof(layer_state_t::matrix22_t))) = matrix;
     output.write(crop);
     output.write(finalCrop);
-    output.writeStrongBinder(handle);
+    output.writeStrongBinder(barrierHandle);
+    output.writeStrongBinder(reparentHandle);
     output.writeUint64(frameNumber);
     output.writeInt32(overrideScalingMode);
+    output.writeStrongBinder(IInterface::asBinder(barrierGbp));
+    output.writeStrongBinder(relativeLayerHandle);
     output.write(transparentRegion);
     return NO_ERROR;
 }
@@ -52,7 +55,7 @@
     what = input.readUint32();
     x = input.readFloat();
     y = input.readFloat();
-    z = input.readUint32();
+    z = input.readInt32();
     w = input.readUint32();
     h = input.readUint32();
     layerStack = input.readUint32();
@@ -67,9 +70,13 @@
     }
     input.read(crop);
     input.read(finalCrop);
-    handle = input.readStrongBinder();
+    barrierHandle = input.readStrongBinder();
+    reparentHandle = input.readStrongBinder();
     frameNumber = input.readUint64();
     overrideScalingMode = input.readInt32();
+    barrierGbp =
+        interface_cast<IGraphicBufferProducer>(input.readStrongBinder());
+    relativeLayerHandle = input.readStrongBinder();
     input.read(transparentRegion);
     return NO_ERROR;
 }
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
deleted file mode 100644
index 053d153..0000000
--- a/libs/gui/Sensor.cpp
+++ /dev/null
@@ -1,547 +0,0 @@
-/*
- * 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 <binder/AppOpsManager.h>
-#include <binder/IServiceManager.h>
-#include <gui/Sensor.h>
-#include <hardware/sensors.h>
-#include <log/log.h>
-#include <utils/Errors.h>
-#include <utils/String8.h>
-#include <utils/Flattenable.h>
-
-#include <inttypes.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <sys/limits.h>
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-Sensor::Sensor(const char * name) :
-        mName(name), mHandle(0), mType(0),
-        mMinValue(0), mMaxValue(0), mResolution(0),
-        mPower(0), mMinDelay(0), mVersion(0), mFifoReservedEventCount(0),
-        mFifoMaxEventCount(0), mRequiredAppOp(0),
-        mMaxDelay(0), mFlags(0) {
-}
-
-Sensor::Sensor(struct sensor_t const* hwSensor, int halVersion) :
-        Sensor(*hwSensor, uuid_t(), halVersion) {
-}
-
-Sensor::Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersion) {
-    mName = hwSensor.name;
-    mVendor = hwSensor.vendor;
-    mVersion = hwSensor.version;
-    mHandle = hwSensor.handle;
-    mType = hwSensor.type;
-    mMinValue = 0;                      // FIXME: minValue
-    mMaxValue = hwSensor.maxRange;     // FIXME: maxValue
-    mResolution = hwSensor.resolution;
-    mPower = hwSensor.power;
-    mMinDelay = hwSensor.minDelay;
-    mFlags = 0;
-    mUuid = uuid;
-
-    // Set fifo event count zero for older devices which do not support batching. Fused
-    // sensors also have their fifo counts set to zero.
-    if (halVersion > SENSORS_DEVICE_API_VERSION_1_0) {
-        mFifoReservedEventCount = hwSensor.fifoReservedEventCount;
-        mFifoMaxEventCount = hwSensor.fifoMaxEventCount;
-    } else {
-        mFifoReservedEventCount = 0;
-        mFifoMaxEventCount = 0;
-    }
-
-    if (halVersion >= SENSORS_DEVICE_API_VERSION_1_3) {
-        if (hwSensor.maxDelay > INT_MAX) {
-            // Max delay is declared as a 64 bit integer for 64 bit architectures. But it should
-            // always fit in a 32 bit integer, log error and cap it to INT_MAX.
-            ALOGE("Sensor maxDelay overflow error %s %" PRId64, mName.string(),
-                  static_cast<int64_t>(hwSensor.maxDelay));
-            mMaxDelay = INT_MAX;
-        } else {
-            mMaxDelay = static_cast<int32_t>(hwSensor.maxDelay);
-        }
-    } else {
-        // For older hals set maxDelay to 0.
-        mMaxDelay = 0;
-    }
-
-    // Ensure existing sensors have correct string type, required permissions and reporting mode.
-    // Set reportingMode for all android defined sensor types, set wake-up flag only for proximity
-    // sensor, significant motion, tilt, pick_up gesture, wake gesture and glance gesture on older
-    // HALs. Newer HALs can define both wake-up and non wake-up proximity sensors.
-    // All the OEM defined defined sensors have flags set to whatever is provided by the HAL.
-    switch (mType) {
-    case SENSOR_TYPE_ACCELEROMETER:
-        mStringType = SENSOR_STRING_TYPE_ACCELEROMETER;
-        mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
-        break;
-    case SENSOR_TYPE_AMBIENT_TEMPERATURE:
-        mStringType = SENSOR_STRING_TYPE_AMBIENT_TEMPERATURE;
-        mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
-        break;
-    case SENSOR_TYPE_GAME_ROTATION_VECTOR:
-        mStringType = SENSOR_STRING_TYPE_GAME_ROTATION_VECTOR;
-        mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
-        break;
-    case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR:
-        mStringType = SENSOR_STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR;
-        mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
-        break;
-    case SENSOR_TYPE_GRAVITY:
-        mStringType = SENSOR_STRING_TYPE_GRAVITY;
-        mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
-        break;
-    case SENSOR_TYPE_GYROSCOPE:
-        mStringType = SENSOR_STRING_TYPE_GYROSCOPE;
-        mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
-        break;
-    case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
-        mStringType = SENSOR_STRING_TYPE_GYROSCOPE_UNCALIBRATED;
-        mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
-        break;
-    case SENSOR_TYPE_HEART_RATE: {
-        mStringType = SENSOR_STRING_TYPE_HEART_RATE;
-        mRequiredPermission = SENSOR_PERMISSION_BODY_SENSORS;
-        AppOpsManager appOps;
-        mRequiredAppOp = appOps.permissionToOpCode(String16(SENSOR_PERMISSION_BODY_SENSORS));
-        mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
-        } break;
-    case SENSOR_TYPE_LIGHT:
-        mStringType = SENSOR_STRING_TYPE_LIGHT;
-        mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
-        break;
-    case SENSOR_TYPE_LINEAR_ACCELERATION:
-        mStringType = SENSOR_STRING_TYPE_LINEAR_ACCELERATION;
-        mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
-        break;
-    case SENSOR_TYPE_MAGNETIC_FIELD:
-        mStringType = SENSOR_STRING_TYPE_MAGNETIC_FIELD;
-        mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
-        break;
-    case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
-        mStringType = SENSOR_STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED;
-        mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
-        break;
-    case SENSOR_TYPE_ORIENTATION:
-        mStringType = SENSOR_STRING_TYPE_ORIENTATION;
-        mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
-        break;
-    case SENSOR_TYPE_PRESSURE:
-        mStringType = SENSOR_STRING_TYPE_PRESSURE;
-        mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
-        break;
-    case SENSOR_TYPE_PROXIMITY:
-        mStringType = SENSOR_STRING_TYPE_PROXIMITY;
-        mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
-        if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) {
-            mFlags |= SENSOR_FLAG_WAKE_UP;
-        }
-        break;
-    case SENSOR_TYPE_RELATIVE_HUMIDITY:
-        mStringType = SENSOR_STRING_TYPE_RELATIVE_HUMIDITY;
-        mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
-        break;
-    case SENSOR_TYPE_ROTATION_VECTOR:
-        mStringType = SENSOR_STRING_TYPE_ROTATION_VECTOR;
-        mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
-        break;
-    case SENSOR_TYPE_SIGNIFICANT_MOTION:
-        mStringType = SENSOR_STRING_TYPE_SIGNIFICANT_MOTION;
-        mFlags |= SENSOR_FLAG_ONE_SHOT_MODE;
-        if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) {
-            mFlags |= SENSOR_FLAG_WAKE_UP;
-        }
-        break;
-    case SENSOR_TYPE_STEP_COUNTER:
-        mStringType = SENSOR_STRING_TYPE_STEP_COUNTER;
-        mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
-        break;
-    case SENSOR_TYPE_STEP_DETECTOR:
-        mStringType = SENSOR_STRING_TYPE_STEP_DETECTOR;
-        mFlags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE;
-        break;
-    case SENSOR_TYPE_TEMPERATURE:
-        mStringType = SENSOR_STRING_TYPE_TEMPERATURE;
-        mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
-        break;
-    case SENSOR_TYPE_TILT_DETECTOR:
-        mStringType = SENSOR_STRING_TYPE_TILT_DETECTOR;
-        mFlags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE;
-        if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) {
-            mFlags |= SENSOR_FLAG_WAKE_UP;
-        }
-        break;
-    case SENSOR_TYPE_WAKE_GESTURE:
-        mStringType = SENSOR_STRING_TYPE_WAKE_GESTURE;
-        mFlags |= SENSOR_FLAG_ONE_SHOT_MODE;
-        if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) {
-            mFlags |= SENSOR_FLAG_WAKE_UP;
-        }
-        break;
-    case SENSOR_TYPE_GLANCE_GESTURE:
-        mStringType = SENSOR_STRING_TYPE_GLANCE_GESTURE;
-        mFlags |= SENSOR_FLAG_ONE_SHOT_MODE;
-        if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) {
-            mFlags |= SENSOR_FLAG_WAKE_UP;
-        }
-        break;
-    case SENSOR_TYPE_PICK_UP_GESTURE:
-        mStringType = SENSOR_STRING_TYPE_PICK_UP_GESTURE;
-        mFlags |= SENSOR_FLAG_ONE_SHOT_MODE;
-        if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) {
-            mFlags |= SENSOR_FLAG_WAKE_UP;
-        }
-        break;
-    case SENSOR_TYPE_WRIST_TILT_GESTURE:
-        mStringType = SENSOR_STRING_TYPE_WRIST_TILT_GESTURE;
-        mFlags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE;
-        if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) {
-            mFlags |= SENSOR_FLAG_WAKE_UP;
-        }
-        break;
-    case SENSOR_TYPE_DYNAMIC_SENSOR_META:
-        mStringType = SENSOR_STRING_TYPE_DYNAMIC_SENSOR_META;
-        mFlags = SENSOR_FLAG_SPECIAL_REPORTING_MODE; // special trigger and non-wake up
-        break;
-    case SENSOR_TYPE_POSE_6DOF:
-        mStringType = SENSOR_STRING_TYPE_POSE_6DOF;
-        mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
-        break;
-    case SENSOR_TYPE_STATIONARY_DETECT:
-        mStringType = SENSOR_STRING_TYPE_STATIONARY_DETECT;
-        mFlags |= SENSOR_FLAG_ONE_SHOT_MODE;
-        if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) {
-            mFlags |= SENSOR_FLAG_WAKE_UP;
-        }
-        break;
-    case SENSOR_TYPE_MOTION_DETECT:
-        mStringType = SENSOR_STRING_TYPE_MOTION_DETECT;
-        mFlags |= SENSOR_FLAG_ONE_SHOT_MODE;
-        if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) {
-            mFlags |= SENSOR_FLAG_WAKE_UP;
-        }
-        break;
-    case SENSOR_TYPE_HEART_BEAT:
-        mStringType = SENSOR_STRING_TYPE_HEART_BEAT;
-        mFlags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE;
-        break;
-    default:
-        // Only pipe the stringType, requiredPermission and flags for custom sensors.
-        if (halVersion > SENSORS_DEVICE_API_VERSION_1_0 && hwSensor.stringType) {
-            mStringType = hwSensor.stringType;
-        }
-        if (halVersion > SENSORS_DEVICE_API_VERSION_1_0 && hwSensor.requiredPermission) {
-            mRequiredPermission = hwSensor.requiredPermission;
-            if (!strcmp(mRequiredPermission, SENSOR_PERMISSION_BODY_SENSORS)) {
-                AppOpsManager appOps;
-                mRequiredAppOp = appOps.permissionToOpCode(String16(SENSOR_PERMISSION_BODY_SENSORS));
-            }
-        }
-
-        if (halVersion >= SENSORS_DEVICE_API_VERSION_1_3) {
-            mFlags = static_cast<uint32_t>(hwSensor.flags);
-        } else {
-            // This is an OEM defined sensor on an older HAL. Use minDelay to determine the
-            // reporting mode of the sensor.
-            if (mMinDelay > 0) {
-                mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
-            } else if (mMinDelay == 0) {
-                mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
-            } else if (mMinDelay < 0) {
-                mFlags |= SENSOR_FLAG_ONE_SHOT_MODE;
-            }
-        }
-        break;
-    }
-
-    if (halVersion >= SENSORS_DEVICE_API_VERSION_1_3) {
-        // Wake-up flag of HAL 1.3 and above is set here
-        mFlags |= (hwSensor.flags & SENSOR_FLAG_WAKE_UP);
-
-        // Log error if the reporting mode is not as expected, but respect HAL setting.
-        int actualReportingMode = (hwSensor.flags & REPORTING_MODE_MASK) >> REPORTING_MODE_SHIFT;
-        int expectedReportingMode = (mFlags & REPORTING_MODE_MASK) >> REPORTING_MODE_SHIFT;
-        if (actualReportingMode != expectedReportingMode) {
-            ALOGE("Reporting Mode incorrect: sensor %s handle=%#010" PRIx32 " type=%" PRId32 " "
-                   "actual=%d expected=%d",
-                   mName.string(), mHandle, mType, actualReportingMode, expectedReportingMode);
-        }
-    }
-
-    // Feature flags
-    // Set DYNAMIC_SENSOR_MASK and ADDITIONAL_INFO_MASK flag here. Compatible with HAL 1_3.
-    if (halVersion >= SENSORS_DEVICE_API_VERSION_1_3) {
-        mFlags |= (hwSensor.flags & (DYNAMIC_SENSOR_MASK | ADDITIONAL_INFO_MASK));
-    }
-    // Set DATA_INJECTION flag here. Defined in HAL 1_4.
-    if (halVersion >= SENSORS_DEVICE_API_VERSION_1_4) {
-        mFlags |= (hwSensor.flags & DATA_INJECTION_MASK);
-    }
-
-    if (mRequiredPermission.length() > 0) {
-        // 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) {
-            sp<IPermissionController> permCtrl = interface_cast<IPermissionController>(binder);
-            mRequiredPermissionRuntime = permCtrl->isRuntimePermission(
-                    String16(mRequiredPermission));
-        }
-    }
-}
-
-Sensor::~Sensor() {
-}
-
-const String8& Sensor::getName() const {
-    return mName;
-}
-
-const String8& Sensor::getVendor() const {
-    return mVendor;
-}
-
-int32_t Sensor::getHandle() const {
-    return mHandle;
-}
-
-int32_t Sensor::getType() const {
-    return mType;
-}
-
-float Sensor::getMinValue() const {
-    return mMinValue;
-}
-
-float Sensor::getMaxValue() const {
-    return mMaxValue;
-}
-
-float Sensor::getResolution() const {
-    return mResolution;
-}
-
-float Sensor::getPowerUsage() const {
-    return mPower;
-}
-
-int32_t Sensor::getMinDelay() const {
-    return mMinDelay;
-}
-
-nsecs_t Sensor::getMinDelayNs() const {
-    return getMinDelay() * 1000;
-}
-
-int32_t Sensor::getVersion() const {
-    return mVersion;
-}
-
-uint32_t Sensor::getFifoReservedEventCount() const {
-    return mFifoReservedEventCount;
-}
-
-uint32_t Sensor::getFifoMaxEventCount() const {
-    return mFifoMaxEventCount;
-}
-
-const String8& Sensor::getStringType() const {
-    return mStringType;
-}
-
-const String8& Sensor::getRequiredPermission() const {
-    return mRequiredPermission;
-}
-
-bool Sensor::isRequiredPermissionRuntime() const {
-    return mRequiredPermissionRuntime;
-}
-
-int32_t Sensor::getRequiredAppOp() const {
-    return mRequiredAppOp;
-}
-
-int32_t Sensor::getMaxDelay() const {
-    return mMaxDelay;
-}
-
-uint32_t Sensor::getFlags() const {
-    return mFlags;
-}
-
-bool Sensor::isWakeUpSensor() const {
-    return (mFlags & SENSOR_FLAG_WAKE_UP) != 0;
-}
-
-bool Sensor::isDynamicSensor() const {
-    return (mFlags & SENSOR_FLAG_DYNAMIC_SENSOR) != 0;
-}
-
-bool Sensor::hasAdditionalInfo() const {
-    return (mFlags & SENSOR_FLAG_ADDITIONAL_INFO) != 0;
-}
-
-int32_t Sensor::getReportingMode() const {
-    return ((mFlags & REPORTING_MODE_MASK) >> REPORTING_MODE_SHIFT);
-}
-
-const Sensor::uuid_t& Sensor::getUuid() const {
-    return mUuid;
-}
-
-void Sensor::setId(int32_t id) {
-    mUuid.i64[0] = id;
-    mUuid.i64[1] = 0;
-}
-
-int32_t Sensor::getId() const {
-    return int32_t(mUuid.i64[0]);
-}
-
-size_t Sensor::getFlattenedSize() const {
-    size_t fixedSize =
-            sizeof(mVersion) + sizeof(mHandle) + sizeof(mType) +
-            sizeof(mMinValue) + sizeof(mMaxValue) + sizeof(mResolution) +
-            sizeof(mPower) + sizeof(mMinDelay) + sizeof(mFifoMaxEventCount) +
-            sizeof(mFifoMaxEventCount) + sizeof(mRequiredPermissionRuntime) +
-            sizeof(mRequiredAppOp) + sizeof(mMaxDelay) + sizeof(mFlags) + sizeof(mUuid);
-
-    size_t variableSize =
-            sizeof(uint32_t) + FlattenableUtils::align<4>(mName.length()) +
-            sizeof(uint32_t) + FlattenableUtils::align<4>(mVendor.length()) +
-            sizeof(uint32_t) + FlattenableUtils::align<4>(mStringType.length()) +
-            sizeof(uint32_t) + FlattenableUtils::align<4>(mRequiredPermission.length());
-
-    return fixedSize + variableSize;
-}
-
-status_t Sensor::flatten(void* buffer, size_t size) const {
-    if (size < getFlattenedSize()) {
-        return NO_MEMORY;
-    }
-
-    flattenString8(buffer, size, mName);
-    flattenString8(buffer, size, mVendor);
-    FlattenableUtils::write(buffer, size, mVersion);
-    FlattenableUtils::write(buffer, size, mHandle);
-    FlattenableUtils::write(buffer, size, mType);
-    FlattenableUtils::write(buffer, size, mMinValue);
-    FlattenableUtils::write(buffer, size, mMaxValue);
-    FlattenableUtils::write(buffer, size, mResolution);
-    FlattenableUtils::write(buffer, size, mPower);
-    FlattenableUtils::write(buffer, size, mMinDelay);
-    FlattenableUtils::write(buffer, size, mFifoReservedEventCount);
-    FlattenableUtils::write(buffer, size, mFifoMaxEventCount);
-    flattenString8(buffer, size, mStringType);
-    flattenString8(buffer, size, mRequiredPermission);
-    FlattenableUtils::write(buffer, size, mRequiredPermissionRuntime);
-    FlattenableUtils::write(buffer, size, mRequiredAppOp);
-    FlattenableUtils::write(buffer, size, mMaxDelay);
-    FlattenableUtils::write(buffer, size, mFlags);
-    if (mUuid.i64[1] != 0) {
-        // We should never hit this case with our current API, but we
-        // could via a careless API change.  If that happens,
-        // this code will keep us from leaking our UUID (while probably
-        // breaking dynamic sensors).  See b/29547335.
-        ALOGW("Sensor with UUID being flattened; sending 0.  Expect "
-              "bad dynamic sensor behavior");
-        uuid_t tmpUuid;  // default constructor makes this 0.
-        FlattenableUtils::write(buffer, size, tmpUuid);
-    } else {
-        FlattenableUtils::write(buffer, size, mUuid);
-    }
-    return NO_ERROR;
-}
-
-status_t Sensor::unflatten(void const* buffer, size_t size) {
-    if (!unflattenString8(buffer, size, mName)) {
-        return NO_MEMORY;
-    }
-    if (!unflattenString8(buffer, size, mVendor)) {
-        return NO_MEMORY;
-    }
-
-    size_t fixedSize1 =
-            sizeof(mVersion) + sizeof(mHandle) + sizeof(mType) + sizeof(mMinValue) +
-            sizeof(mMaxValue) + sizeof(mResolution) + sizeof(mPower) + sizeof(mMinDelay) +
-            sizeof(mFifoMaxEventCount) + sizeof(mFifoMaxEventCount);
-    if (size < fixedSize1) {
-        return NO_MEMORY;
-    }
-
-    FlattenableUtils::read(buffer, size, mVersion);
-    FlattenableUtils::read(buffer, size, mHandle);
-    FlattenableUtils::read(buffer, size, mType);
-    FlattenableUtils::read(buffer, size, mMinValue);
-    FlattenableUtils::read(buffer, size, mMaxValue);
-    FlattenableUtils::read(buffer, size, mResolution);
-    FlattenableUtils::read(buffer, size, mPower);
-    FlattenableUtils::read(buffer, size, mMinDelay);
-    FlattenableUtils::read(buffer, size, mFifoReservedEventCount);
-    FlattenableUtils::read(buffer, size, mFifoMaxEventCount);
-
-    if (!unflattenString8(buffer, size, mStringType)) {
-        return NO_MEMORY;
-    }
-    if (!unflattenString8(buffer, size, mRequiredPermission)) {
-        return NO_MEMORY;
-    }
-
-    size_t fixedSize2 =
-            sizeof(mRequiredPermissionRuntime) + sizeof(mRequiredAppOp) + sizeof(mMaxDelay) +
-            sizeof(mFlags) + sizeof(mUuid);
-    if (size < fixedSize2) {
-        return NO_MEMORY;
-    }
-
-    FlattenableUtils::read(buffer, size, mRequiredPermissionRuntime);
-    FlattenableUtils::read(buffer, size, mRequiredAppOp);
-    FlattenableUtils::read(buffer, size, mMaxDelay);
-    FlattenableUtils::read(buffer, size, mFlags);
-    FlattenableUtils::read(buffer, size, mUuid);
-    return NO_ERROR;
-}
-
-void Sensor::flattenString8(void*& buffer, size_t& size,
-        const String8& string8) {
-    uint32_t len = static_cast<uint32_t>(string8.length());
-    FlattenableUtils::write(buffer, size, len);
-    memcpy(static_cast<char*>(buffer), string8.string(), len);
-    FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(len));
-}
-
-bool Sensor::unflattenString8(void const*& buffer, size_t& size, String8& outputString8) {
-    uint32_t len;
-    if (size < sizeof(len)) {
-        return false;
-    }
-    FlattenableUtils::read(buffer, size, len);
-    if (size < len) {
-        return false;
-    }
-    outputString8.setTo(static_cast<char const*>(buffer), len);
-    FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(len));
-    return true;
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp
deleted file mode 100644
index 6d69839..0000000
--- a/libs/gui/SensorEventQueue.cpp
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * 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 "Sensors"
-
-#include <algorithm>
-#include <stdint.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <linux/errno.h>
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/Looper.h>
-
-#include <gui/Sensor.h>
-#include <gui/BitTube.h>
-#include <gui/SensorEventQueue.h>
-#include <gui/ISensorEventConnection.h>
-
-#include <android/sensor.h>
-
-using std::min;
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-SensorEventQueue::SensorEventQueue(const sp<ISensorEventConnection>& connection)
-    : mSensorEventConnection(connection), mRecBuffer(NULL), mAvailable(0), mConsumed(0),
-      mNumAcksToSend(0) {
-    mRecBuffer = new ASensorEvent[MAX_RECEIVE_BUFFER_EVENT_COUNT];
-}
-
-SensorEventQueue::~SensorEventQueue() {
-    delete [] mRecBuffer;
-}
-
-void SensorEventQueue::onFirstRef()
-{
-    mSensorChannel = mSensorEventConnection->getSensorChannel();
-}
-
-int SensorEventQueue::getFd() const
-{
-    return mSensorChannel->getFd();
-}
-
-
-ssize_t SensorEventQueue::write(const sp<BitTube>& tube,
-        ASensorEvent const* events, size_t numEvents) {
-    return BitTube::sendObjects(tube, events, numEvents);
-}
-
-ssize_t SensorEventQueue::read(ASensorEvent* events, size_t numEvents) {
-    if (mAvailable == 0) {
-        ssize_t err = BitTube::recvObjects(mSensorChannel,
-                mRecBuffer, MAX_RECEIVE_BUFFER_EVENT_COUNT);
-        if (err < 0) {
-            return err;
-        }
-        mAvailable = static_cast<size_t>(err);
-        mConsumed = 0;
-    }
-    size_t count = min(numEvents, mAvailable);
-    memcpy(events, mRecBuffer + mConsumed, count * sizeof(ASensorEvent));
-    mAvailable -= count;
-    mConsumed += count;
-    return static_cast<ssize_t>(count);
-}
-
-sp<Looper> SensorEventQueue::getLooper() const
-{
-    Mutex::Autolock _l(mLock);
-    if (mLooper == 0) {
-        mLooper = new Looper(true);
-        mLooper->addFd(getFd(), getFd(), ALOOPER_EVENT_INPUT, NULL, NULL);
-    }
-    return mLooper;
-}
-
-status_t SensorEventQueue::waitForEvent() const
-{
-    const int fd = getFd();
-    sp<Looper> looper(getLooper());
-
-    int events;
-    int32_t result;
-    do {
-        result = looper->pollOnce(-1, NULL, &events, NULL);
-        if (result == ALOOPER_POLL_ERROR) {
-            ALOGE("SensorEventQueue::waitForEvent error (errno=%d)", errno);
-            result = -EPIPE; // unknown error, so we make up one
-            break;
-        }
-        if (events & ALOOPER_EVENT_HANGUP) {
-            // the other-side has died
-            ALOGE("SensorEventQueue::waitForEvent error HANGUP");
-            result = -EPIPE; // unknown error, so we make up one
-            break;
-        }
-    } while (result != fd);
-
-    return  (result == fd) ? status_t(NO_ERROR) : result;
-}
-
-status_t SensorEventQueue::wake() const
-{
-    sp<Looper> looper(getLooper());
-    looper->wake();
-    return NO_ERROR;
-}
-
-status_t SensorEventQueue::enableSensor(Sensor const* sensor) const {
-    return enableSensor(sensor, SENSOR_DELAY_NORMAL);
-}
-
-status_t SensorEventQueue::enableSensor(Sensor const* sensor, int32_t samplingPeriodUs) const {
-    return mSensorEventConnection->enableDisable(sensor->getHandle(), true,
-                                                 us2ns(samplingPeriodUs), 0, 0);
-}
-
-status_t SensorEventQueue::disableSensor(Sensor const* sensor) const {
-    return mSensorEventConnection->enableDisable(sensor->getHandle(), false, 0, 0, 0);
-}
-
-status_t SensorEventQueue::enableSensor(int32_t handle, int32_t samplingPeriodUs,
-                                        int maxBatchReportLatencyUs, int reservedFlags) const {
-    return mSensorEventConnection->enableDisable(handle, true, us2ns(samplingPeriodUs),
-                                                 us2ns(maxBatchReportLatencyUs), reservedFlags);
-}
-
-status_t SensorEventQueue::flush() const {
-    return mSensorEventConnection->flush();
-}
-
-status_t SensorEventQueue::disableSensor(int32_t handle) const {
-    return mSensorEventConnection->enableDisable(handle, false, 0, 0, false);
-}
-
-status_t SensorEventQueue::setEventRate(Sensor const* sensor, nsecs_t ns) const {
-    return mSensorEventConnection->setEventRate(sensor->getHandle(), ns);
-}
-
-status_t SensorEventQueue::injectSensorEvent(const ASensorEvent& event) {
-    do {
-        // Blocking call.
-        ssize_t size = ::send(mSensorChannel->getFd(), &event, sizeof(event), MSG_NOSIGNAL);
-        if (size >= 0) {
-            return NO_ERROR;
-        } else if (size < 0 && errno == EAGAIN) {
-            // If send is returning a "Try again" error, sleep for 100ms and try again. In all
-            // other cases log a failure and exit.
-            usleep(100000);
-        } else {
-            ALOGE("injectSensorEvent failure %s %zd", strerror(errno), size);
-            return INVALID_OPERATION;
-        }
-    } while (true);
-}
-
-void SensorEventQueue::sendAck(const ASensorEvent* events, int count) {
-    for (int i = 0; i < count; ++i) {
-        if (events[i].flags & WAKE_UP_SENSOR_EVENT_NEEDS_ACK) {
-            ++mNumAcksToSend;
-        }
-    }
-    // Send mNumAcksToSend to acknowledge for the wake up sensor events received.
-    if (mNumAcksToSend > 0) {
-        ssize_t size = ::send(mSensorChannel->getFd(), &mNumAcksToSend, sizeof(mNumAcksToSend),
-                MSG_DONTWAIT | MSG_NOSIGNAL);
-        if (size < 0) {
-            ALOGE("sendAck failure %zd %d", size, mNumAcksToSend);
-        } else {
-            mNumAcksToSend = 0;
-        }
-    }
-    return;
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
diff --git a/libs/gui/SensorManager.cpp b/libs/gui/SensorManager.cpp
deleted file mode 100644
index 9fcf9ab..0000000
--- a/libs/gui/SensorManager.cpp
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * 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 "Sensors"
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/Singleton.h>
-
-#include <binder/IBinder.h>
-#include <binder/IServiceManager.h>
-
-#include <gui/ISensorServer.h>
-#include <gui/ISensorEventConnection.h>
-#include <gui/Sensor.h>
-#include <gui/SensorManager.h>
-#include <gui/SensorEventQueue.h>
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-android::Mutex android::SensorManager::sLock;
-std::map<String16, SensorManager*> android::SensorManager::sPackageInstances;
-
-SensorManager& SensorManager::getInstanceForPackage(const String16& packageName) {
-    Mutex::Autolock _l(sLock);
-    SensorManager* sensorManager;
-    std::map<String16, SensorManager*>::iterator iterator =
-        sPackageInstances.find(packageName);
-
-    if (iterator != sPackageInstances.end()) {
-        sensorManager = iterator->second;
-    } else {
-        String16 opPackageName = packageName;
-
-        // It is possible that the calling code has no access to the package name.
-        // In this case we will get the packages for the calling UID and pick the
-        // first one for attributing the app op. This will work correctly for
-        // runtime permissions as for legacy apps we will toggle the app op for
-        // all packages in the UID. The caveat is that the operation may be attributed
-        // 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) {
-                const uid_t uid = IPCThreadState::self()->getCallingUid();
-                Vector<String16> packages;
-                interface_cast<IPermissionController>(binder)->getPackagesForUid(uid, packages);
-                if (!packages.isEmpty()) {
-                    opPackageName = packages[0];
-                } else {
-                    ALOGE("No packages for calling UID");
-                }
-            } else {
-                ALOGE("Cannot get permission service");
-            }
-        }
-
-        sensorManager = new SensorManager(opPackageName);
-
-        // If we had no package name, we looked it up from the UID and the sensor
-        // manager instance we created should also be mapped to the empty package
-        // name, to avoid looking up the packages for a UID and get the same result.
-        if (packageName.size() <= 0) {
-            sPackageInstances.insert(std::make_pair(String16(), sensorManager));
-        }
-
-        // Stash the per package sensor manager.
-        sPackageInstances.insert(std::make_pair(opPackageName, sensorManager));
-    }
-
-    return *sensorManager;
-}
-
-SensorManager::SensorManager(const String16& opPackageName)
-    : mSensorList(0), mOpPackageName(opPackageName) {
-    // okay we're not locked here, but it's not needed during construction
-    assertStateLocked();
-}
-
-SensorManager::~SensorManager() {
-    free(mSensorList);
-}
-
-void SensorManager::sensorManagerDied() {
-    Mutex::Autolock _l(mLock);
-    mSensorServer.clear();
-    free(mSensorList);
-    mSensorList = NULL;
-    mSensors.clear();
-}
-
-status_t SensorManager::assertStateLocked() {
-    bool initSensorManager = false;
-    if (mSensorServer == NULL) {
-        initSensorManager = true;
-    } else {
-        // Ping binder to check if sensorservice is alive.
-        status_t err = IInterface::asBinder(mSensorServer)->pingBinder();
-        if (err != NO_ERROR) {
-            initSensorManager = true;
-        }
-    }
-    if (initSensorManager) {
-        // try for 300 seconds (60*5(getService() tries for 5 seconds)) before giving up ...
-        const String16 name("sensorservice");
-        for (int i = 0; i < 60; i++) {
-            status_t err = getService(name, &mSensorServer);
-            if (err == NAME_NOT_FOUND) {
-                sleep(1);
-                continue;
-            }
-            if (err != NO_ERROR) {
-                return err;
-            }
-            break;
-        }
-
-        class DeathObserver : public IBinder::DeathRecipient {
-            SensorManager& mSensorManager;
-            virtual void binderDied(const wp<IBinder>& who) {
-                ALOGW("sensorservice died [%p]", who.unsafe_get());
-                mSensorManager.sensorManagerDied();
-            }
-        public:
-            DeathObserver(SensorManager& mgr) : mSensorManager(mgr) { }
-        };
-
-        LOG_ALWAYS_FATAL_IF(mSensorServer.get() == NULL, "getService(SensorService) NULL");
-
-        mDeathObserver = new DeathObserver(*const_cast<SensorManager *>(this));
-        IInterface::asBinder(mSensorServer)->linkToDeath(mDeathObserver);
-
-        mSensors = mSensorServer->getSensorList(mOpPackageName);
-        size_t count = mSensors.size();
-        mSensorList =
-                static_cast<Sensor const**>(malloc(count * sizeof(Sensor*)));
-        LOG_ALWAYS_FATAL_IF(mSensorList == NULL, "mSensorList NULL");
-
-        for (size_t i=0 ; i<count ; i++) {
-            mSensorList[i] = mSensors.array() + i;
-        }
-    }
-
-    return NO_ERROR;
-}
-
-ssize_t SensorManager::getSensorList(Sensor const* const** list) {
-    Mutex::Autolock _l(mLock);
-    status_t err = assertStateLocked();
-    if (err < 0) {
-        return static_cast<ssize_t>(err);
-    }
-    *list = mSensorList;
-    return static_cast<ssize_t>(mSensors.size());
-}
-
-ssize_t SensorManager::getDynamicSensorList(Vector<Sensor> & dynamicSensors) {
-    Mutex::Autolock _l(mLock);
-    status_t err = assertStateLocked();
-    if (err < 0) {
-        return static_cast<ssize_t>(err);
-    }
-
-    dynamicSensors = mSensorServer->getDynamicSensorList(mOpPackageName);
-    size_t count = dynamicSensors.size();
-
-    return static_cast<ssize_t>(count);
-}
-
-Sensor const* SensorManager::getDefaultSensor(int type)
-{
-    Mutex::Autolock _l(mLock);
-    if (assertStateLocked() == NO_ERROR) {
-        bool wakeUpSensor = false;
-        // For the following sensor types, return a wake-up sensor. These types are by default
-        // defined as wake-up sensors. For the rest of the sensor types defined in sensors.h return
-        // a non_wake-up version.
-        if (type == SENSOR_TYPE_PROXIMITY || type == SENSOR_TYPE_SIGNIFICANT_MOTION ||
-            type == SENSOR_TYPE_TILT_DETECTOR || type == SENSOR_TYPE_WAKE_GESTURE ||
-            type == SENSOR_TYPE_GLANCE_GESTURE || type == SENSOR_TYPE_PICK_UP_GESTURE ||
-            type == SENSOR_TYPE_WRIST_TILT_GESTURE) {
-            wakeUpSensor = true;
-        }
-        // For now we just return the first sensor of that type we find.
-        // in the future it will make sense to let the SensorService make
-        // that decision.
-        for (size_t i=0 ; i<mSensors.size() ; i++) {
-            if (mSensorList[i]->getType() == type &&
-                mSensorList[i]->isWakeUpSensor() == wakeUpSensor) {
-                return mSensorList[i];
-            }
-        }
-    }
-    return NULL;
-}
-
-sp<SensorEventQueue> SensorManager::createEventQueue(String8 packageName, int mode) {
-    sp<SensorEventQueue> queue;
-
-    Mutex::Autolock _l(mLock);
-    while (assertStateLocked() == NO_ERROR) {
-        sp<ISensorEventConnection> connection =
-                mSensorServer->createSensorEventConnection(packageName, mode, mOpPackageName);
-        if (connection == NULL) {
-            // SensorService just died or the app doesn't have required permissions.
-            ALOGE("createEventQueue: connection is NULL.");
-            return NULL;
-        }
-        queue = new SensorEventQueue(connection);
-        break;
-    }
-    return queue;
-}
-
-bool SensorManager::isDataInjectionEnabled() {
-    Mutex::Autolock _l(mLock);
-    if (assertStateLocked() == NO_ERROR) {
-        return mSensorServer->isDataInjectionEnabled();
-    }
-    return false;
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 5a2ca8d..7b2b5c3 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -18,25 +18,28 @@
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 //#define LOG_NDEBUG 0
 
-#include <android/native_window.h>
+#include <gui/Surface.h>
 
-#include <binder/Parcel.h>
+#include <android/native_window.h>
 
 #include <utils/Log.h>
 #include <utils/Trace.h>
 #include <utils/NativeHandle.h>
 
+#include <ui/DisplayStatInfo.h>
 #include <ui/Fence.h>
+#include <ui/HdrCapabilities.h>
 #include <ui/Region.h>
 
+#include <gui/BufferItem.h>
 #include <gui/IProducerListener.h>
-#include <gui/ISurfaceComposer.h>
-#include <gui/SurfaceComposerClient.h>
-#include <gui/GLConsumer.h>
-#include <gui/Surface.h>
 
+#include <gui/ISurfaceComposer.h>
 #include <private/gui/ComposerService.h>
 
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <configstore/Utils.h>
+
 namespace android {
 
 Surface::Surface(
@@ -49,7 +52,10 @@
       mAutoRefresh(false),
       mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT),
       mSharedBufferHasBeenQueued(false),
-      mNextFrameNumber(1)
+      mQueriedSupportedTimestamps(false),
+      mFrameTimestampsSupportsPresent(false),
+      mEnableFrameTimestamps(false),
+      mFrameEventHistory(std::make_unique<ProducerFrameEventHistory>())
 {
     // Initialize the ANativeWindow function pointers.
     ANativeWindow::setSwapInterval  = hook_setSwapInterval;
@@ -93,6 +99,14 @@
     }
 }
 
+sp<ISurfaceComposer> Surface::composerService() const {
+    return ComposerService::getComposerService();
+}
+
+nsecs_t Surface::now() const {
+    return systemTime();
+}
+
 sp<IGraphicBufferProducer> Surface::getIGraphicBufferProducer() const {
     return mGraphicBufferProducer;
 }
@@ -135,37 +149,224 @@
             outTransformMatrix);
 }
 
-bool Surface::getFrameTimestamps(uint64_t frameNumber, nsecs_t* outPostedTime,
-        nsecs_t* outAcquireTime, nsecs_t* outRefreshStartTime,
-        nsecs_t* outGlCompositionDoneTime, nsecs_t* outDisplayRetireTime,
+status_t Surface::getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration) {
+    ATRACE_CALL();
+
+    DisplayStatInfo stats;
+    status_t err = composerService()->getDisplayStats(NULL, &stats);
+
+    *outRefreshDuration = stats.vsyncPeriod;
+
+    return NO_ERROR;
+}
+
+void Surface::enableFrameTimestamps(bool enable) {
+    Mutex::Autolock lock(mMutex);
+    // If going from disabled to enabled, get the initial values for
+    // compositor and display timing.
+    if (!mEnableFrameTimestamps && enable) {
+        FrameEventHistoryDelta delta;
+        mGraphicBufferProducer->getFrameTimestamps(&delta);
+        mFrameEventHistory->applyDelta(delta);
+    }
+    mEnableFrameTimestamps = enable;
+}
+
+status_t Surface::getCompositorTiming(
+        nsecs_t* compositeDeadline, nsecs_t* compositeInterval,
+        nsecs_t* compositeToPresentLatency) {
+    Mutex::Autolock lock(mMutex);
+    if (!mEnableFrameTimestamps) {
+        return INVALID_OPERATION;
+    }
+
+    if (compositeDeadline != nullptr) {
+        *compositeDeadline =
+                mFrameEventHistory->getNextCompositeDeadline(now());
+    }
+    if (compositeInterval != nullptr) {
+        *compositeInterval = mFrameEventHistory->getCompositeInterval();
+    }
+    if (compositeToPresentLatency != nullptr) {
+        *compositeToPresentLatency =
+                mFrameEventHistory->getCompositeToPresentLatency();
+    }
+    return NO_ERROR;
+}
+
+static bool checkConsumerForUpdates(
+        const FrameEvents* e, const uint64_t lastFrameNumber,
+        const nsecs_t* outLatchTime,
+        const nsecs_t* outFirstRefreshStartTime,
+        const nsecs_t* outLastRefreshStartTime,
+        const nsecs_t* outGpuCompositionDoneTime,
+        const nsecs_t* outDisplayPresentTime,
+        const nsecs_t* outDequeueReadyTime,
+        const nsecs_t* outReleaseTime) {
+    bool checkForLatch = (outLatchTime != nullptr) && !e->hasLatchInfo();
+    bool checkForFirstRefreshStart = (outFirstRefreshStartTime != nullptr) &&
+            !e->hasFirstRefreshStartInfo();
+    bool checkForGpuCompositionDone = (outGpuCompositionDoneTime != nullptr) &&
+            !e->hasGpuCompositionDoneInfo();
+    bool checkForDisplayPresent = (outDisplayPresentTime != nullptr) &&
+            !e->hasDisplayPresentInfo();
+
+    // LastRefreshStart, DequeueReady, and Release are never available for the
+    // last frame.
+    bool checkForLastRefreshStart = (outLastRefreshStartTime != nullptr) &&
+            !e->hasLastRefreshStartInfo() &&
+            (e->frameNumber != lastFrameNumber);
+    bool checkForDequeueReady = (outDequeueReadyTime != nullptr) &&
+            !e->hasDequeueReadyInfo() && (e->frameNumber != lastFrameNumber);
+    bool checkForRelease = (outReleaseTime != nullptr) &&
+            !e->hasReleaseInfo() && (e->frameNumber != lastFrameNumber);
+
+    // RequestedPresent and Acquire info are always available producer-side.
+    return checkForLatch || checkForFirstRefreshStart ||
+            checkForLastRefreshStart || checkForGpuCompositionDone ||
+            checkForDisplayPresent || checkForDequeueReady || checkForRelease;
+}
+
+static void getFrameTimestamp(nsecs_t *dst, const nsecs_t& src) {
+    if (dst != nullptr) {
+        // We always get valid timestamps for these eventually.
+        *dst = (src == FrameEvents::TIMESTAMP_PENDING) ?
+                NATIVE_WINDOW_TIMESTAMP_PENDING : src;
+    }
+}
+
+static void getFrameTimestampFence(nsecs_t *dst,
+        const std::shared_ptr<FenceTime>& src, bool fenceShouldBeKnown) {
+    if (dst != nullptr) {
+        if (!fenceShouldBeKnown) {
+            *dst = NATIVE_WINDOW_TIMESTAMP_PENDING;
+            return;
+        }
+
+        nsecs_t signalTime = src->getSignalTime();
+        *dst = (signalTime == Fence::SIGNAL_TIME_PENDING) ?
+                    NATIVE_WINDOW_TIMESTAMP_PENDING :
+                (signalTime == Fence::SIGNAL_TIME_INVALID) ?
+                    NATIVE_WINDOW_TIMESTAMP_INVALID :
+                signalTime;
+    }
+}
+
+status_t Surface::getFrameTimestamps(uint64_t frameNumber,
+        nsecs_t* outRequestedPresentTime, nsecs_t* outAcquireTime,
+        nsecs_t* outLatchTime, nsecs_t* outFirstRefreshStartTime,
+        nsecs_t* outLastRefreshStartTime, nsecs_t* outGpuCompositionDoneTime,
+        nsecs_t* outDisplayPresentTime, nsecs_t* outDequeueReadyTime,
         nsecs_t* outReleaseTime) {
     ATRACE_CALL();
 
-    FrameTimestamps timestamps;
-    bool found = mGraphicBufferProducer->getFrameTimestamps(frameNumber,
-            &timestamps);
-    if (found) {
-        if (outPostedTime) {
-            *outPostedTime = timestamps.postedTime;
-        }
-        if (outAcquireTime) {
-            *outAcquireTime = timestamps.acquireTime;
-        }
-        if (outRefreshStartTime) {
-            *outRefreshStartTime = timestamps.refreshStartTime;
-        }
-        if (outGlCompositionDoneTime) {
-            *outGlCompositionDoneTime = timestamps.glCompositionDoneTime;
-        }
-        if (outDisplayRetireTime) {
-            *outDisplayRetireTime = timestamps.displayRetireTime;
-        }
-        if (outReleaseTime) {
-            *outReleaseTime = timestamps.releaseTime;
-        }
-        return true;
+    Mutex::Autolock lock(mMutex);
+
+    if (!mEnableFrameTimestamps) {
+        return INVALID_OPERATION;
     }
-    return false;
+
+    // Verify the requested timestamps are supported.
+    querySupportedTimestampsLocked();
+    if (outDisplayPresentTime != nullptr && !mFrameTimestampsSupportsPresent) {
+        return BAD_VALUE;
+    }
+
+    FrameEvents* events = mFrameEventHistory->getFrame(frameNumber);
+    if (events == nullptr) {
+        // If the entry isn't available in the producer, it's definitely not
+        // available in the consumer.
+        return NAME_NOT_FOUND;
+    }
+
+    // Update our cache of events if the requested events are not available.
+    if (checkConsumerForUpdates(events, mLastFrameNumber,
+            outLatchTime, outFirstRefreshStartTime, outLastRefreshStartTime,
+            outGpuCompositionDoneTime, outDisplayPresentTime,
+            outDequeueReadyTime, outReleaseTime)) {
+        FrameEventHistoryDelta delta;
+        mGraphicBufferProducer->getFrameTimestamps(&delta);
+        mFrameEventHistory->applyDelta(delta);
+        events = mFrameEventHistory->getFrame(frameNumber);
+    }
+
+    if (events == nullptr) {
+        // The entry was available before the update, but was overwritten
+        // after the update. Make sure not to send the wrong frame's data.
+        return NAME_NOT_FOUND;
+    }
+
+    getFrameTimestamp(outRequestedPresentTime, events->requestedPresentTime);
+    getFrameTimestamp(outLatchTime, events->latchTime);
+    getFrameTimestamp(outFirstRefreshStartTime, events->firstRefreshStartTime);
+    getFrameTimestamp(outLastRefreshStartTime, events->lastRefreshStartTime);
+    getFrameTimestamp(outDequeueReadyTime, events->dequeueReadyTime);
+
+    getFrameTimestampFence(outAcquireTime, events->acquireFence,
+            events->hasAcquireInfo());
+    getFrameTimestampFence(outGpuCompositionDoneTime,
+            events->gpuCompositionDoneFence,
+            events->hasGpuCompositionDoneInfo());
+    getFrameTimestampFence(outDisplayPresentTime, events->displayPresentFence,
+            events->hasDisplayPresentInfo());
+    getFrameTimestampFence(outReleaseTime, events->releaseFence,
+            events->hasReleaseInfo());
+
+    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<android_color_mode_t> colorModes;
+    status_t err =
+        composerService()->getDisplayColorModes(display, &colorModes);
+
+    if (err)
+        return err;
+
+    bool wideColorBoardConfig =
+        getBool<ISurfaceFlingerConfigs,
+                &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
+
+    *supported = false;
+    for (android_color_mode_t colorMode : colorModes) {
+        switch (colorMode) {
+            case HAL_COLOR_MODE_DISPLAY_P3:
+            case HAL_COLOR_MODE_ADOBE_RGB:
+            case HAL_COLOR_MODE_DCI_P3:
+                if (wideColorBoardConfig) {
+                    *supported = true;
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    return NO_ERROR;
+}
+
+status_t Surface::getHdrSupport(bool* supported) {
+    ATRACE_CALL();
+
+    sp<IBinder> display(
+        composerService()->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+    HdrCapabilities hdrCapabilities;
+    status_t err =
+        composerService()->getHdrCapabilities(display, &hdrCapabilities);
+
+    if (err)
+        return err;
+
+    *supported = !hdrCapabilities.getSupportedHdrTypes().empty();
+
+    return NO_ERROR;
 }
 
 int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) {
@@ -271,9 +472,13 @@
     uint32_t reqHeight;
     PixelFormat reqFormat;
     uint32_t reqUsage;
+    bool enableFrameTimestamps;
 
     {
         Mutex::Autolock lock(mMutex);
+        if (mReportRemovedBuffers) {
+            mRemovedBuffers.clear();
+        }
 
         reqWidth = mReqWidth ? mReqWidth : mUserWidth;
         reqHeight = mReqHeight ? mReqHeight : mUserHeight;
@@ -281,6 +486,8 @@
         reqFormat = mReqFormat;
         reqUsage = mReqUsage;
 
+        enableFrameTimestamps = mEnableFrameTimestamps;
+
         if (mSharedBufferMode && mAutoRefresh && mSharedBufferSlot !=
                 BufferItem::INVALID_BUFFER_SLOT) {
             sp<GraphicBuffer>& gbuf(mSlots[mSharedBufferSlot].buffer);
@@ -294,10 +501,13 @@
 
     int buf = -1;
     sp<Fence> fence;
-    nsecs_t now = systemTime();
+    nsecs_t startTime = systemTime();
+
+    FrameEventHistoryDelta frameTimestamps;
     status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence,
-            reqWidth, reqHeight, reqFormat, reqUsage);
-    mLastDequeueDuration = systemTime() - now;
+            reqWidth, reqHeight, reqFormat, reqUsage,
+            enableFrameTimestamps ? &frameTimestamps : nullptr);
+    mLastDequeueDuration = systemTime() - startTime;
 
     if (result < 0) {
         ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer"
@@ -314,6 +524,9 @@
 
     Mutex::Autolock lock(mMutex);
 
+    // Write this while holding the mutex
+    mLastDequeueStartTime = startTime;
+
     sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
 
     // this should never happen
@@ -323,7 +536,14 @@
         freeAllBuffers();
     }
 
-    if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
+    if (enableFrameTimestamps) {
+         mFrameEventHistory->applyDelta(frameTimestamps);
+    }
+
+    if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == nullptr) {
+        if (mReportRemovedBuffers && (gbuf != nullptr)) {
+            mRemovedBuffers.push_back(gbuf);
+        }
         result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
         if (result != NO_ERROR) {
             ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result);
@@ -414,7 +634,7 @@
         timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
         isAutoTimestamp = true;
         ALOGV("Surface::queueBuffer making up timestamp: %.2f ms",
-            timestamp / 1000000.f);
+            timestamp / 1000000.0);
     } else {
         timestamp = mTimestamp;
     }
@@ -441,7 +661,7 @@
     IGraphicBufferProducer::QueueBufferOutput output;
     IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp,
             mDataSpace, crop, mScalingMode, mTransform ^ mStickyTransform,
-            fence, mStickyTransform);
+            fence, mStickyTransform, mEnableFrameTimestamps);
 
     if (mConnectedToCpu || mDirtyRegion.bounds() == Rect::INVALID_RECT) {
         input.setSurfaceDamage(Region::INVALID_REGION);
@@ -513,17 +733,31 @@
         ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);
     }
 
-    uint32_t numPendingBuffers = 0;
-    uint32_t hint = 0;
-    output.deflate(&mDefaultWidth, &mDefaultHeight, &hint,
-            &numPendingBuffers, &mNextFrameNumber);
+    if (mEnableFrameTimestamps) {
+        mFrameEventHistory->applyDelta(output.frameTimestamps);
+        // Update timestamps with the local acquire fence.
+        // 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)));
+
+        // Cache timestamps of signaled fences so we can close their file
+        // descriptors.
+        mFrameEventHistory->updateSignalTimes();
+    }
+
+    mLastFrameNumber = mNextFrameNumber;
+
+    mDefaultWidth = output.width;
+    mDefaultHeight = output.height;
+    mNextFrameNumber = output.nextFrameNumber;
 
     // Disable transform hint if sticky transform is set.
     if (mStickyTransform == 0) {
-        mTransformHint = hint;
+        mTransformHint = output.transformHint;
     }
 
-    mConsumerRunningBehind = (numPendingBuffers >= 2);
+    mConsumerRunningBehind = (output.numPendingBuffers >= 2);
 
     if (!mConnectedToCpu) {
         // Clear surface damage back to full-buffer
@@ -539,6 +773,29 @@
     return err;
 }
 
+void Surface::querySupportedTimestampsLocked() const {
+    // mMutex must be locked when calling this method.
+
+    if (mQueriedSupportedTimestamps) {
+        return;
+    }
+    mQueriedSupportedTimestamps = true;
+
+    std::vector<FrameEvent> supportedFrameTimestamps;
+    status_t err = composerService()->getSupportedFrameTimestamps(
+            &supportedFrameTimestamps);
+
+    if (err != NO_ERROR) {
+        return;
+    }
+
+    for (auto sft : supportedFrameTimestamps) {
+        if (sft == FrameEvent::DISPLAY_PRESENT) {
+            mFrameTimestampsSupportsPresent = true;
+        }
+    }
+}
+
 int Surface::query(int what, int* value) const {
     ATRACE_CALL();
     ALOGV("Surface::query");
@@ -552,9 +809,8 @@
                 }
                 break;
             case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: {
-                sp<ISurfaceComposer> composer(
-                        ComposerService::getComposerService());
-                if (composer->authenticateSurfaceTexture(mGraphicBufferProducer)) {
+                if (composerService()->authenticateSurfaceTexture(
+                        mGraphicBufferProducer)) {
                     *value = 1;
                 } else {
                     *value = 0;
@@ -601,6 +857,15 @@
                         static_cast<int>(durationUs);
                 return NO_ERROR;
             }
+            case NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT: {
+                querySupportedTimestampsLocked();
+                *value = mFrameTimestampsSupportsPresent ? 1 : 0;
+                return NO_ERROR;
+            }
+            case NATIVE_WINDOW_IS_VALID: {
+                *value = mGraphicBufferProducer != nullptr ? 1 : 0;
+                return NO_ERROR;
+            }
         }
     }
     return mGraphicBufferProducer->query(what, value);
@@ -676,9 +941,27 @@
     case NATIVE_WINDOW_SET_AUTO_REFRESH:
         res = dispatchSetAutoRefresh(args);
         break;
+    case NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION:
+        res = dispatchGetDisplayRefreshCycleDuration(args);
+        break;
+    case NATIVE_WINDOW_GET_NEXT_FRAME_ID:
+        res = dispatchGetNextFrameId(args);
+        break;
+    case NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS:
+        res = dispatchEnableFrameTimestamps(args);
+        break;
+    case NATIVE_WINDOW_GET_COMPOSITOR_TIMING:
+        res = dispatchGetCompositorTiming(args);
+        break;
     case NATIVE_WINDOW_GET_FRAME_TIMESTAMPS:
         res = dispatchGetFrameTimestamps(args);
         break;
+    case NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT:
+        res = dispatchGetWideColorSupport(args);
+        break;
+    case NATIVE_WINDOW_GET_HDR_SUPPORT:
+        res = dispatchGetHdrSupport(args);
+        break;
     default:
         res = NAME_NOT_FOUND;
         break;
@@ -799,18 +1082,57 @@
     return setAutoRefresh(autoRefresh);
 }
 
+int Surface::dispatchGetDisplayRefreshCycleDuration(va_list args) {
+    nsecs_t* outRefreshDuration = va_arg(args, int64_t*);
+    return getDisplayRefreshCycleDuration(outRefreshDuration);
+}
+
+int Surface::dispatchGetNextFrameId(va_list args) {
+    uint64_t* nextFrameId = va_arg(args, uint64_t*);
+    *nextFrameId = getNextFrameNumber();
+    return NO_ERROR;
+}
+
+int Surface::dispatchEnableFrameTimestamps(va_list args) {
+    bool enable = va_arg(args, int);
+    enableFrameTimestamps(enable);
+    return NO_ERROR;
+}
+
+int Surface::dispatchGetCompositorTiming(va_list args) {
+    nsecs_t* compositeDeadline = va_arg(args, int64_t*);
+    nsecs_t* compositeInterval = va_arg(args, int64_t*);
+    nsecs_t* compositeToPresentLatency = va_arg(args, int64_t*);
+    return getCompositorTiming(compositeDeadline, compositeInterval,
+            compositeToPresentLatency);
+}
+
 int Surface::dispatchGetFrameTimestamps(va_list args) {
-    uint32_t framesAgo = va_arg(args, uint32_t);
-    nsecs_t* outPostedTime = va_arg(args, int64_t*);
+    uint64_t frameId = va_arg(args, uint64_t);
+    nsecs_t* outRequestedPresentTime = va_arg(args, int64_t*);
     nsecs_t* outAcquireTime = va_arg(args, int64_t*);
-    nsecs_t* outRefreshStartTime = va_arg(args, int64_t*);
-    nsecs_t* outGlCompositionDoneTime = va_arg(args, int64_t*);
-    nsecs_t* outDisplayRetireTime = va_arg(args, int64_t*);
+    nsecs_t* outLatchTime = va_arg(args, int64_t*);
+    nsecs_t* outFirstRefreshStartTime = va_arg(args, int64_t*);
+    nsecs_t* outLastRefreshStartTime = va_arg(args, int64_t*);
+    nsecs_t* outGpuCompositionDoneTime = va_arg(args, int64_t*);
+    nsecs_t* outDisplayPresentTime = va_arg(args, int64_t*);
+    nsecs_t* outDequeueReadyTime = va_arg(args, int64_t*);
     nsecs_t* outReleaseTime = va_arg(args, int64_t*);
-    bool ret = getFrameTimestamps(getNextFrameNumber() - 1 - framesAgo,
-            outPostedTime, outAcquireTime, outRefreshStartTime,
-            outGlCompositionDoneTime, outDisplayRetireTime, outReleaseTime);
-    return ret ? NO_ERROR : BAD_VALUE;
+    return getFrameTimestamps(frameId,
+            outRequestedPresentTime, outAcquireTime, outLatchTime,
+            outFirstRefreshStartTime, outLastRefreshStartTime,
+            outGpuCompositionDoneTime, outDisplayPresentTime,
+            outDequeueReadyTime, outReleaseTime);
+}
+
+int Surface::dispatchGetWideColorSupport(va_list args) {
+    bool* outSupport = va_arg(args, bool*);
+    return getWideColorSupport(outSupport);
+}
+
+int Surface::dispatchGetHdrSupport(va_list args) {
+    bool* outSupport = va_arg(args, bool*);
+    return getHdrSupport(outSupport);
 }
 
 int Surface::connect(int api) {
@@ -819,23 +1141,28 @@
 }
 
 int Surface::connect(int api, const sp<IProducerListener>& listener) {
+    return connect(api, listener, false);
+}
+
+int Surface::connect(
+        int api, const sp<IProducerListener>& listener, bool reportBufferRemoval) {
     ATRACE_CALL();
     ALOGV("Surface::connect");
     Mutex::Autolock lock(mMutex);
     IGraphicBufferProducer::QueueBufferOutput output;
+    mReportRemovedBuffers = reportBufferRemoval;
     int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output);
     if (err == NO_ERROR) {
-        uint32_t numPendingBuffers = 0;
-        uint32_t hint = 0;
-        output.deflate(&mDefaultWidth, &mDefaultHeight, &hint,
-                &numPendingBuffers, &mNextFrameNumber);
+        mDefaultWidth = output.width;
+        mDefaultHeight = output.height;
+        mNextFrameNumber = output.nextFrameNumber;
 
         // Disable transform hint if sticky transform is set.
         if (mStickyTransform == 0) {
-            mTransformHint = hint;
+            mTransformHint = output.transformHint;
         }
 
-        mConsumerRunningBehind = (numPendingBuffers >= 2);
+        mConsumerRunningBehind = (output.numPendingBuffers >= 2);
     }
     if (!err && api == NATIVE_WINDOW_API_CPU) {
         mConnectedToCpu = true;
@@ -854,6 +1181,7 @@
     ATRACE_CALL();
     ALOGV("Surface::disconnect");
     Mutex::Autolock lock(mMutex);
+    mRemovedBuffers.clear();
     mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
     mSharedBufferHasBeenQueued = false;
     freeAllBuffers();
@@ -885,6 +1213,9 @@
     }
 
     Mutex::Autolock lock(mMutex);
+    if (mReportRemovedBuffers) {
+        mRemovedBuffers.clear();
+    }
 
     sp<GraphicBuffer> buffer(NULL);
     sp<Fence> fence(NULL);
@@ -903,7 +1234,10 @@
 
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
         if (mSlots[i].buffer != NULL &&
-                mSlots[i].buffer->handle == buffer->handle) {
+                mSlots[i].buffer->getId() == buffer->getId()) {
+            if (mReportRemovedBuffers) {
+                mRemovedBuffers.push_back(mSlots[i].buffer);
+            }
             mSlots[i].buffer = NULL;
         }
     }
@@ -917,6 +1251,9 @@
     ALOGV("Surface::attachBuffer");
 
     Mutex::Autolock lock(mMutex);
+    if (mReportRemovedBuffers) {
+        mRemovedBuffers.clear();
+    }
 
     sp<GraphicBuffer> graphicBuffer(static_cast<GraphicBuffer*>(buffer));
     uint32_t priorGeneration = graphicBuffer->mGenerationNumber;
@@ -929,6 +1266,9 @@
         graphicBuffer->mGenerationNumber = priorGeneration;
         return result;
     }
+    if (mReportRemovedBuffers && (mSlots[attachedSlot].buffer != nullptr)) {
+        mRemovedBuffers.push_back(mSlots[attachedSlot].buffer);
+    }
     mSlots[attachedSlot].buffer = graphicBuffer;
 
     return NO_ERROR;
@@ -1178,7 +1518,8 @@
 static status_t copyBlt(
         const sp<GraphicBuffer>& dst,
         const sp<GraphicBuffer>& src,
-        const Region& reg)
+        const Region& reg,
+        int *dstFenceFd)
 {
     // src and dst with, height and format must be identical. no verification
     // is done here.
@@ -1189,9 +1530,10 @@
     ALOGE_IF(err, "error locking src buffer %s", strerror(-err));
 
     uint8_t* dst_bits = NULL;
-    err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(),
-            reinterpret_cast<void**>(&dst_bits));
+    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));
+    *dstFenceFd = -1;
 
     Region::const_iterator head(reg.begin());
     Region::const_iterator tail(reg.end());
@@ -1225,7 +1567,7 @@
         src->unlock();
 
     if (dst_bits)
-        dst->unlock();
+        dst->unlockAsync(dstFenceFd);
 
     return err;
 }
@@ -1275,8 +1617,9 @@
         if (canCopyBack) {
             // copy the area that is invalid and not repainted this round
             const Region copyback(mDirtyRegion.subtract(newDirtyRegion));
-            if (!copyback.isEmpty())
-                copyBlt(backBuffer, frontBuffer, copyback);
+            if (!copyback.isEmpty()) {
+                copyBlt(backBuffer, frontBuffer, copyback, &fenceFd);
+            }
         } else {
             // if we can't copy-back anything, modify the user's dirty
             // region to make sure they redraw the whole buffer
@@ -1359,70 +1702,21 @@
     return mGraphicBufferProducer->getUniqueId(outId);
 }
 
-namespace view {
-
-status_t Surface::writeToParcel(Parcel* parcel) const {
-    return writeToParcel(parcel, false);
+nsecs_t Surface::getLastDequeueStartTime() const {
+    Mutex::Autolock lock(mMutex);
+    return mLastDequeueStartTime;
 }
 
-status_t Surface::writeToParcel(Parcel* parcel, bool nameAlreadyWritten) const {
-    if (parcel == nullptr) return BAD_VALUE;
-
-    status_t res = OK;
-
-    if (!nameAlreadyWritten) {
-        res = parcel->writeString16(name);
-        if (res != OK) return res;
-
-        /* isSingleBuffered defaults to no */
-        res = parcel->writeInt32(0);
-        if (res != OK) return res;
+status_t Surface::getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out) {
+    if (out == nullptr) {
+        ALOGE("%s: out must not be null!", __FUNCTION__);
+        return BAD_VALUE;
     }
 
-    res = parcel->writeStrongBinder(
-            IGraphicBufferProducer::asBinder(graphicBufferProducer));
-
-    return res;
-}
-
-status_t Surface::readFromParcel(const Parcel* parcel) {
-    return readFromParcel(parcel, false);
-}
-
-status_t Surface::readFromParcel(const Parcel* parcel, bool nameAlreadyRead) {
-    if (parcel == nullptr) return BAD_VALUE;
-
-    status_t res = OK;
-    if (!nameAlreadyRead) {
-        name = readMaybeEmptyString16(parcel);
-        // Discard this for now
-        int isSingleBuffered;
-        res = parcel->readInt32(&isSingleBuffered);
-        if (res != OK) {
-            return res;
-        }
-    }
-
-    sp<IBinder> binder;
-
-    res = parcel->readStrongBinder(&binder);
-    if (res != OK) return res;
-
-    graphicBufferProducer = interface_cast<IGraphicBufferProducer>(binder);
-
+    Mutex::Autolock lock(mMutex);
+    *out = mRemovedBuffers;
+    mRemovedBuffers.clear();
     return OK;
 }
 
-String16 Surface::readMaybeEmptyString16(const Parcel* parcel) {
-    size_t len;
-    const char16_t* str = parcel->readString16Inplace(&len);
-    if (str != nullptr) {
-        return String16(str, len);
-    } else {
-        return String16();
-    }
-}
-
-} // namespace view
-
 }; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index b78de2e..8c83843 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -26,17 +26,18 @@
 #include <utils/String8.h>
 #include <utils/threads.h>
 
-#include <binder/IMemory.h>
 #include <binder/IServiceManager.h>
 
 #include <system/graphics.h>
 
 #include <ui/DisplayInfo.h>
 
+#include <gui/BufferItemConsumer.h>
 #include <gui/CpuConsumer.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/ISurfaceComposerClient.h>
+#include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 
 #include <private/gui/ComposerService.h>
@@ -69,7 +70,7 @@
             mComposerService.composerServiceDied();
         }
      public:
-        DeathObserver(ComposerService& mgr) : mComposerService(mgr) { }
+        explicit DeathObserver(ComposerService& mgr) : mComposerService(mgr) { }
     };
 
     mDeathObserver = new DeathObserver(*const_cast<ComposerService*>(this));
@@ -129,6 +130,8 @@
     void openGlobalTransactionImpl();
     void closeGlobalTransactionImpl(bool synchronous);
     void setAnimationTransactionImpl();
+    status_t enableVSyncInjectionsImpl(bool enable);
+    status_t injectVSyncImpl(nsecs_t when);
 
     layer_state_t* getLayerStateLocked(
             const sp<SurfaceComposerClient>& client, const sp<IBinder>& id);
@@ -145,7 +148,9 @@
     status_t setSize(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
             uint32_t w, uint32_t h);
     status_t setLayer(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            uint32_t z);
+            int32_t z);
+    status_t setRelativeLayer(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
+            const sp<IBinder>& relativeTo, int32_t z);
     status_t setFlags(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
             uint32_t flags, uint32_t mask);
     status_t setTransparentRegionHint(
@@ -154,7 +159,7 @@
     status_t setAlpha(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
             float alpha);
     status_t setMatrix(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            float dsdx, float dtdx, float dsdy, float dtdy);
+            float dsdx, float dtdx, float dtdy, float dsdy);
     status_t setOrientation(int orientation);
     status_t setCrop(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
             const Rect& crop);
@@ -165,6 +170,14 @@
     status_t deferTransactionUntil(const sp<SurfaceComposerClient>& client,
             const sp<IBinder>& id, const sp<IBinder>& handle,
             uint64_t frameNumber);
+    status_t deferTransactionUntil(const sp<SurfaceComposerClient>& client,
+            const sp<IBinder>& id, const sp<Surface>& barrierSurface,
+            uint64_t frameNumber);
+    status_t reparentChildren(const sp<SurfaceComposerClient>& client,
+            const sp<IBinder>& id,
+            const sp<IBinder>& newParentHandle);
+    status_t detachChildren(const sp<SurfaceComposerClient>& client,
+            const sp<IBinder>& id);
     status_t setOverrideScalingMode(const sp<SurfaceComposerClient>& client,
             const sp<IBinder>& id, int32_t overrideScalingMode);
     status_t setGeometryAppliesWithResize(const sp<SurfaceComposerClient>& client,
@@ -190,6 +203,14 @@
     static void closeGlobalTransaction(bool synchronous) {
         Composer::getInstance().closeGlobalTransactionImpl(synchronous);
     }
+
+    static status_t enableVSyncInjections(bool enable) {
+        return Composer::getInstance().enableVSyncInjectionsImpl(enable);
+    }
+
+    static status_t injectVSync(nsecs_t when) {
+        return Composer::getInstance().injectVSyncImpl(when);
+    }
 };
 
 ANDROID_SINGLETON_STATIC_INSTANCE(Composer);
@@ -253,6 +274,16 @@
    sm->setTransactionState(transaction, displayTransaction, flags);
 }
 
+status_t Composer::enableVSyncInjectionsImpl(bool enable) {
+    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
+    return sm->enableVSyncInjections(enable);
+}
+
+status_t Composer::injectVSyncImpl(nsecs_t when) {
+    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
+    return sm->injectVSync(when);
+}
+
 void Composer::setAnimationTransactionImpl() {
     Mutex::Autolock _l(mLock);
     mAnimation = true;
@@ -304,7 +335,7 @@
 }
 
 status_t Composer::setLayer(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, uint32_t z) {
+        const sp<IBinder>& id, int32_t z) {
     Mutex::Autolock _l(mLock);
     layer_state_t* s = getLayerStateLocked(client, id);
     if (!s)
@@ -314,6 +345,20 @@
     return NO_ERROR;
 }
 
+status_t Composer::setRelativeLayer(const sp<SurfaceComposerClient>& client,
+        const sp<IBinder>& id, const sp<IBinder>& relativeTo,
+        int32_t z) {
+    Mutex::Autolock _l(mLock);
+    layer_state_t* s = getLayerStateLocked(client, id);
+    if (!s) {
+        return BAD_INDEX;
+    }
+    s->what |= layer_state_t::eRelativeLayerChanged;
+    s->relativeLayerHandle = relativeTo;
+    s->z = z;
+    return NO_ERROR;
+}
+
 status_t Composer::setFlags(const sp<SurfaceComposerClient>& client,
         const sp<IBinder>& id, uint32_t flags,
         uint32_t mask) {
@@ -368,7 +413,7 @@
 
 status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client,
         const sp<IBinder>& id, float dsdx, float dtdx,
-        float dsdy, float dtdy) {
+        float dtdy, float dsdy) {
     Mutex::Autolock _l(mLock);
     layer_state_t* s = getLayerStateLocked(client, id);
     if (!s)
@@ -415,11 +460,51 @@
         return BAD_INDEX;
     }
     s->what |= layer_state_t::eDeferTransaction;
-    s->handle = handle;
+    s->barrierHandle = handle;
     s->frameNumber = frameNumber;
     return NO_ERROR;
 }
 
+status_t Composer::deferTransactionUntil(
+        const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
+        const sp<Surface>& barrierSurface, uint64_t frameNumber) {
+    Mutex::Autolock lock(mLock);
+    layer_state_t* s = getLayerStateLocked(client, id);
+    if (!s) {
+        return BAD_INDEX;
+    }
+    s->what |= layer_state_t::eDeferTransaction;
+    s->barrierGbp = barrierSurface->getIGraphicBufferProducer();
+    s->frameNumber = frameNumber;
+    return NO_ERROR;
+}
+
+status_t Composer::reparentChildren(
+        const sp<SurfaceComposerClient>& client,
+        const sp<IBinder>& id,
+        const sp<IBinder>& newParentHandle) {
+    Mutex::Autolock lock(mLock);
+    layer_state_t* s = getLayerStateLocked(client, id);
+    if (!s) {
+        return BAD_INDEX;
+    }
+    s->what |= layer_state_t::eReparentChildren;
+    s->reparentHandle = newParentHandle;
+    return NO_ERROR;
+}
+
+status_t Composer::detachChildren(
+        const sp<SurfaceComposerClient>& client,
+        const sp<IBinder>& id) {
+    Mutex::Autolock lock(mLock);
+    layer_state_t* s = getLayerStateLocked(client, id);
+    if (!s) {
+        return BAD_INDEX;
+    }
+    s->what |= layer_state_t::eDetachChildren;
+    return NO_ERROR;
+}
+
 status_t Composer::setOverrideScalingMode(
         const sp<SurfaceComposerClient>& client,
         const sp<IBinder>& id, int32_t overrideScalingMode) {
@@ -529,10 +614,18 @@
 {
 }
 
+SurfaceComposerClient::SurfaceComposerClient(const sp<IGraphicBufferProducer>& root)
+    : mStatus(NO_INIT), mComposer(Composer::getInstance()), mParent(root)
+{
+}
+
 void SurfaceComposerClient::onFirstRef() {
     sp<ISurfaceComposer> sm(ComposerService::getComposerService());
     if (sm != 0) {
-        sp<ISurfaceComposerClient> conn = sm->createConnection();
+        auto rootProducer = mParent.promote();
+        sp<ISurfaceComposerClient> conn;
+        conn = (rootProducer != nullptr) ? sm->createScopedConnection(rootProducer) :
+                sm->createConnection();
         if (conn != 0) {
             mClient = conn;
             mStatus = NO_ERROR;
@@ -575,14 +668,22 @@
         uint32_t w,
         uint32_t h,
         PixelFormat format,
-        uint32_t flags)
+        uint32_t flags,
+        SurfaceControl* parent,
+        uint32_t windowType,
+        uint32_t ownerUid)
 {
     sp<SurfaceControl> sur;
     if (mStatus == NO_ERROR) {
         sp<IBinder> handle;
+        sp<IBinder> parentHandle;
         sp<IGraphicBufferProducer> gbp;
-        status_t err = mClient->createSurface(name, w, h, format, flags,
-                &handle, &gbp);
+
+        if (parent != nullptr) {
+            parentHandle = parent->getHandle();
+        }
+        status_t err = mClient->createSurface(name, w, h, format, flags, parentHandle,
+                windowType, ownerUid, &handle, &gbp);
         ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
         if (err == NO_ERROR) {
             sur = new SurfaceControl(this, handle, gbp);
@@ -626,14 +727,6 @@
     return mClient->getLayerFrameStats(token, outStats);
 }
 
-status_t SurfaceComposerClient::getTransformToDisplayInverse(const sp<IBinder>& token,
-        bool* outTransformToDisplayInverse) const {
-    if (mStatus != NO_ERROR) {
-        return mStatus;
-    }
-    return mClient->getTransformToDisplayInverse(token, outTransformToDisplayInverse);
-}
-
 inline Composer& SurfaceComposerClient::getComposer() {
     return mComposer;
 }
@@ -652,6 +745,14 @@
     Composer::setAnimationTransaction();
 }
 
+status_t SurfaceComposerClient::enableVSyncInjections(bool enable) {
+    return Composer::enableVSyncInjections(enable);
+}
+
+status_t SurfaceComposerClient::injectVSync(nsecs_t when) {
+    return Composer::injectVSync(when);
+}
+
 // ----------------------------------------------------------------------------
 
 status_t SurfaceComposerClient::setCrop(const sp<IBinder>& id, const Rect& crop) {
@@ -671,10 +772,15 @@
     return getComposer().setSize(this, id, w, h);
 }
 
-status_t SurfaceComposerClient::setLayer(const sp<IBinder>& id, uint32_t z) {
+status_t SurfaceComposerClient::setLayer(const sp<IBinder>& id, int32_t z) {
     return getComposer().setLayer(this, id, z);
 }
 
+status_t SurfaceComposerClient::setRelativeLayer(const sp<IBinder>& id,
+        const sp<IBinder>& relativeTo, int32_t z) {
+    return getComposer().setRelativeLayer(this, id, relativeTo, z);
+}
+
 status_t SurfaceComposerClient::hide(const sp<IBinder>& id) {
     return getComposer().setFlags(this, id,
             layer_state_t::eLayerHidden,
@@ -706,8 +812,8 @@
 }
 
 status_t SurfaceComposerClient::setMatrix(const sp<IBinder>& id, float dsdx, float dtdx,
-        float dsdy, float dtdy) {
-    return getComposer().setMatrix(this, id, dsdx, dtdx, dsdy, dtdy);
+        float dtdy, float dsdy) {
+    return getComposer().setMatrix(this, id, dsdx, dtdx, dtdy, dsdy);
 }
 
 status_t SurfaceComposerClient::deferTransactionUntil(const sp<IBinder>& id,
@@ -715,6 +821,20 @@
     return getComposer().deferTransactionUntil(this, id, handle, frameNumber);
 }
 
+status_t SurfaceComposerClient::deferTransactionUntil(const sp<IBinder>& id,
+        const sp<Surface>& barrierSurface, uint64_t frameNumber) {
+    return getComposer().deferTransactionUntil(this, id, barrierSurface, frameNumber);
+}
+
+status_t SurfaceComposerClient::reparentChildren(const sp<IBinder>& id,
+        const sp<IBinder>& newParentHandle) {
+    return getComposer().reparentChildren(this, id, newParentHandle);
+}
+
+status_t SurfaceComposerClient::detachChildren(const sp<IBinder>& id) {
+    return getComposer().detachChildren(this, id);
+}
+
 status_t SurfaceComposerClient::setOverrideScalingMode(
         const sp<IBinder>& id, int32_t overrideScalingMode) {
     return getComposer().setOverrideScalingMode(
@@ -824,13 +944,40 @@
         const sp<IBinder>& display,
         const sp<IGraphicBufferProducer>& producer,
         Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-        uint32_t minLayerZ, uint32_t maxLayerZ, bool useIdentityTransform) {
+        int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
     if (s == NULL) return NO_INIT;
     return s->captureScreen(display, producer, sourceCrop,
             reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform);
 }
 
+status_t ScreenshotClient::captureToBuffer(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) {
+    sp<ISurfaceComposer> s(ComposerService::getComposerService());
+    if (s == NULL) return NO_INIT;
+
+    sp<IGraphicBufferConsumer> gbpConsumer;
+    sp<IGraphicBufferProducer> producer;
+    BufferQueue::createBufferQueue(&producer, &gbpConsumer);
+    sp<BufferItemConsumer> consumer(new BufferItemConsumer(gbpConsumer,
+           GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_NEVER,
+           1, true));
+
+    status_t ret = s->captureScreen(display, producer, sourceCrop, reqWidth, reqHeight,
+            minLayerZ, maxLayerZ, useIdentityTransform,
+            static_cast<ISurfaceComposer::Rotation>(rotation));
+    if (ret != NO_ERROR) {
+        return ret;
+    }
+    BufferItem b;
+    consumer->acquireBuffer(&b, 0, true);
+    *outBuffer = b.mGraphicBuffer;
+    return ret;
+}
+
 ScreenshotClient::ScreenshotClient()
     : mHaveBuffer(false) {
     memset(&mBuffer, 0, sizeof(mBuffer));
@@ -852,7 +999,7 @@
 
 status_t ScreenshotClient::update(const sp<IBinder>& display,
         Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-        uint32_t minLayerZ, uint32_t maxLayerZ,
+        int32_t minLayerZ, int32_t maxLayerZ,
         bool useIdentityTransform, uint32_t rotation) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
     if (s == NULL) return NO_INIT;
@@ -879,7 +1026,7 @@
 
 status_t ScreenshotClient::update(const sp<IBinder>& display,
         Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-        uint32_t minLayerZ, uint32_t maxLayerZ,
+        int32_t minLayerZ, int32_t maxLayerZ,
         bool useIdentityTransform) {
 
     return ScreenshotClient::update(display, sourceCrop, reqWidth, reqHeight,
@@ -888,14 +1035,16 @@
 
 status_t ScreenshotClient::update(const sp<IBinder>& display, Rect sourceCrop,
         bool useIdentityTransform) {
-    return ScreenshotClient::update(display, sourceCrop, 0, 0, 0, -1U,
+    return ScreenshotClient::update(display, sourceCrop, 0, 0,
+            INT32_MIN, INT32_MAX,
             useIdentityTransform, ISurfaceComposer::eRotateNone);
 }
 
 status_t ScreenshotClient::update(const sp<IBinder>& display, Rect sourceCrop,
         uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform) {
     return ScreenshotClient::update(display, sourceCrop, reqWidth, reqHeight,
-            0, -1U, useIdentityTransform, ISurfaceComposer::eRotateNone);
+            INT32_MIN, INT32_MAX,
+            useIdentityTransform, ISurfaceComposer::eRotateNone);
 }
 
 void ScreenshotClient::release() {
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 33c1d90..58bd273 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -102,11 +102,19 @@
     if (err < 0) return err;
     return mClient->setLayerStack(mHandle, layerStack);
 }
-status_t SurfaceControl::setLayer(uint32_t layer) {
+
+status_t SurfaceControl::setLayer(int32_t layer) {
     status_t err = validate();
     if (err < 0) return err;
     return mClient->setLayer(mHandle, layer);
 }
+
+status_t SurfaceControl::setRelativeLayer(const sp<IBinder>& relativeTo, int32_t layer) {
+    status_t err = validate();
+    if (err < 0) return err;
+    return mClient->setRelativeLayer(mHandle, relativeTo, layer);
+}
+
 status_t SurfaceControl::setPosition(float x, float y) {
     status_t err = validate();
     if (err < 0) return err;
@@ -147,10 +155,10 @@
     if (err < 0) return err;
     return mClient->setAlpha(mHandle, alpha);
 }
-status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
+status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dtdy, float dsdy) {
     status_t err = validate();
     if (err < 0) return err;
-    return mClient->setMatrix(mHandle, dsdx, dtdx, dsdy, dtdy);
+    return mClient->setMatrix(mHandle, dsdx, dtdx, dtdy, dsdy);
 }
 status_t SurfaceControl::setCrop(const Rect& crop) {
     status_t err = validate();
@@ -163,13 +171,32 @@
     return mClient->setFinalCrop(mHandle, crop);
 }
 
-status_t SurfaceControl::deferTransactionUntil(sp<IBinder> handle,
+status_t SurfaceControl::deferTransactionUntil(const sp<IBinder>& handle,
         uint64_t frameNumber) {
     status_t err = validate();
     if (err < 0) return err;
     return mClient->deferTransactionUntil(mHandle, handle, frameNumber);
 }
 
+status_t SurfaceControl::deferTransactionUntil(const sp<Surface>& handle,
+        uint64_t frameNumber) {
+    status_t err = validate();
+    if (err < 0) return err;
+    return mClient->deferTransactionUntil(mHandle, handle, frameNumber);
+}
+
+status_t SurfaceControl::reparentChildren(const sp<IBinder>& newParentHandle) {
+    status_t err = validate();
+    if (err < 0) return err;
+    return mClient->reparentChildren(mHandle, newParentHandle);
+}
+
+status_t SurfaceControl::detachChildren() {
+    status_t err = validate();
+    if (err < 0) return err;
+    return mClient->detachChildren(mHandle);
+}
+
 status_t SurfaceControl::setOverrideScalingMode(int32_t overrideScalingMode) {
     status_t err = validate();
     if (err < 0) return err;
@@ -190,13 +217,6 @@
     return client->getLayerFrameStats(mHandle, outStats);
 }
 
-status_t SurfaceControl::getTransformToDisplayInverse(bool* outTransformToDisplayInverse) const {
-    status_t err = validate();
-    if (err < 0) return err;
-    const sp<SurfaceComposerClient>& client(mClient);
-    return client->getTransformToDisplayInverse(mHandle, outTransformToDisplayInverse);
-}
-
 status_t SurfaceControl::validate() const
 {
     if (mHandle==0 || mClient==0) {
@@ -217,17 +237,30 @@
     return parcel->writeStrongBinder(IInterface::asBinder(bp));
 }
 
+sp<Surface> SurfaceControl::generateSurfaceLocked() const
+{
+    // This surface is always consumed by SurfaceFlinger, so the
+    // producerControlledByApp value doesn't matter; using false.
+    mSurfaceData = new Surface(mGraphicBufferProducer, false);
+
+    return mSurfaceData;
+}
+
 sp<Surface> SurfaceControl::getSurface() const
 {
     Mutex::Autolock _l(mLock);
     if (mSurfaceData == 0) {
-        // This surface is always consumed by SurfaceFlinger, so the
-        // producerControlledByApp value doesn't matter; using false.
-        mSurfaceData = new Surface(mGraphicBufferProducer, false);
+        return generateSurfaceLocked();
     }
     return mSurfaceData;
 }
 
+sp<Surface> SurfaceControl::createSurface() const
+{
+    Mutex::Autolock _l(mLock);
+    return generateSurfaceLocked();
+}
+
 sp<IBinder> SurfaceControl::getHandle() const
 {
     Mutex::Autolock lock(mLock);
diff --git a/libs/gui/bufferqueue/1.0/B2HProducerListener.cpp b/libs/gui/bufferqueue/1.0/B2HProducerListener.cpp
new file mode 100644
index 0000000..a5f28cd
--- /dev/null
+++ b/libs/gui/bufferqueue/1.0/B2HProducerListener.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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/B2HProducerListener.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V1_0 {
+namespace utils {
+
+// B2HProducerListener
+B2HProducerListener::B2HProducerListener(
+        sp<BProducerListener> const& base):
+    mBase(base) {
+}
+
+Return<void> B2HProducerListener::onBufferReleased() {
+    mBase->onBufferReleased();
+    return Void();
+}
+
+Return<bool> B2HProducerListener::needsReleaseNotify() {
+    return mBase->needsReleaseNotify();
+}
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace bufferqueue
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
new file mode 100644
index 0000000..fda5b94
--- /dev/null
+++ b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
@@ -0,0 +1,1234 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "H2BGraphicBufferProducer"
+
+#include <android-base/logging.h>
+
+#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
+#include <gui/bufferqueue/1.0/B2HProducerListener.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V1_0 {
+namespace utils {
+
+using Status = HGraphicBufferProducer::Status;
+using ::android::hardware::graphics::common::V1_0::Dataspace;
+typedef ::android::hardware::media::V1_0::Rect HRect;
+typedef ::android::hardware::media::V1_0::Region HRegion;
+
+// Conversion functions
+
+// 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.
+ */
+inline native_handle_t* native_handle_create_from_fd(int fd) {
+    if (fd < 0) {
+        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.
+ */
+inline int native_handle_read_fd(native_handle_t const* nh, int index = 0) {
+    return ((nh == nullptr) || (nh->numFds == 0) ||
+            (nh->numFds <= index) || (index < 0)) ?
+            -1 : nh->data[index];
+}
+
+/**
+ * \brief Convert `Return<Status>` to `status_t`. This is for legacy binder
+ * calls.
+ *
+ * \param[in] t The source `Return<Status>`.
+ * \return The corresponding `status_t`.
+ *
+ * This function first check if \p t has a transport error. If it does, then the
+ * return value is the transport error code. Otherwise, the return value is
+ * converted from `Status` contained inside \p t.
+ *
+ * Note:
+ * - This `Status` is omx-specific. It is defined in `types.hal`.
+ * - The name of this function is not `convert`.
+ */
+// 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;
+}
+
+/**
+ * \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
+inline status_t toStatusT(Return<void> const& t) {
+    return t.isOk() ? OK : UNKNOWN_ERROR;
+}
+
+/**
+ * \brief Wrap `GraphicBuffer` in `AnwBuffer`.
+ *
+ * \param[out] t The wrapper of type `AnwBuffer`.
+ * \param[in] l The source `GraphicBuffer`.
+ */
+// wrap: GraphicBuffer -> AnwBuffer
+inline 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 = 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
+inline 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;
+}
+
+// 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.
+ */
+inline 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.
+ */
+inline 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.
+ */
+inline 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] fence 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.
+ */
+inline 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
+inline 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
+inline 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/Region.cpp
+
+/**
+ * \brief Unflatten `HRegion`.
+ *
+ * \param[out] t The destination `HRegion`.
+ * \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.
+ */
+inline status_t unflatten(HRegion* 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(HRect)) {
+        return NO_MEMORY;
+    }
+    if (numRects > (UINT32_MAX / sizeof(HRect))) {
+        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] = HRect{
+                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;
+}
+
+// Ref: frameworks/native/libs/gui/IGraphicBufferProducer.cpp:
+//      IGraphicBufferProducer::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 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.
+ */
+inline 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);
+    ::android::Rect lCrop;
+    FlattenableUtils::read(buffer, size, lCrop);
+    t->crop = HRect{
+            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;
+    }
+    return unflatten(&(t->surfaceDamage), buffer, size);
+}
+
+/**
+ * \brief Wrap `IGraphicBufferProducer::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 `IGraphicBufferProducer::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.
+ */
+inline 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;
+}
+
+// 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.
+ */
+inline 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.
+ */
+inline 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[out] nh The cloned native handle, if necessary.
+ * \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`, in which case \p nh will be returned.
+ */
+inline status_t flatten(HGraphicBufferProducer::FenceTimeSnapshot const& t,
+        native_handle_t** nh,
+        void*& buffer, size_t& size, int*& fds, size_t& numFds) {
+    if (size < getFlattenedSize(t)) {
+        return NO_MEMORY;
+    }
+
+    *nh = nullptr;
+    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);
+            *nh = t.fence.getNativeHandle() == nullptr ?
+                    nullptr : native_handle_clone(t.fence);
+            return flattenFence(hidl_handle(*nh), 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;
+}
+
+// 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.
+ */
+inline 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.
+ */
+inline size_t getFdCount(
+        HGraphicBufferProducer::FrameEventsDelta const& t) {
+    return getFdCount(t.gpuCompositionDoneFence) +
+            getFdCount(t.displayPresentFence) +
+            getFdCount(t.displayRetireFence) +
+            getFdCount(t.releaseFence);
+};
+
+/**
+ * \brief Flatten `FrameEventsDelta`.
+ *
+ * \param[in] t The source `FrameEventsDelta`.
+ * \param[out] nh The array of native handles that are cloned.
+ * \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.
+ *
+ * On success, this function will duplicate file descriptors contained in \p t.
+ * The cloned native handles will be stored in \p nh. These native handles will
+ * need to be closed by the caller.
+ */
+// Ref: frameworks/native/libs/gui/FrameTimestamp.cpp:
+//      FrameEventsDelta::flatten
+inline status_t flatten(HGraphicBufferProducer::FrameEventsDelta const& t,
+        std::vector<native_handle_t*>* nh,
+        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;
+    nh->resize(4);
+    for (size_t snapshotIndex = 0; snapshotIndex < 4; ++snapshotIndex) {
+        status_t status = flatten(
+                *(tSnapshot[snapshotIndex]),
+                &((*nh)[snapshotIndex]),
+                buffer, size, fds, numFds);
+        if (status != NO_ERROR) {
+            while (snapshotIndex > 0) {
+                --snapshotIndex;
+                native_handle_close((*nh)[snapshotIndex]);
+                native_handle_delete((*nh)[snapshotIndex]);
+                (*nh)[snapshotIndex] = nullptr;
+            }
+            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.
+ */
+inline 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.
+ */
+inline 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 Flatten `FrameEventHistoryDelta`.
+ *
+ * \param[in] t The source `FrameEventHistoryDelta`.
+ * \param[out] nh The array of arrays of cloned 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.
+ *
+ * On success, this function will duplicate file descriptors contained in \p t.
+ * The cloned native handles will be stored in \p nh. Before making the call, \p
+ * nh should have enough space to store `n` pointers to arrays of native
+ * handles, where `n` is the length of `t.deltas`, and each `nh[i]` should have
+ * enough space to store `4` native handles.
+ */
+inline status_t flatten(
+        HGraphicBufferProducer::FrameEventHistoryDelta const& t,
+        std::vector<std::vector<native_handle_t*> >* nh,
+        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()));
+    nh->resize(t.deltas.size());
+    for (size_t deltaIndex = 0; deltaIndex < t.deltas.size(); ++deltaIndex) {
+        status_t status = flatten(
+                t.deltas[deltaIndex], &((*nh)[deltaIndex]),
+                buffer, size, fds, numFds);
+        if (status != NO_ERROR) {
+            while (deltaIndex > 0) {
+                --deltaIndex;
+                for (size_t snapshotIndex = 0;
+                        snapshotIndex < 4; ++snapshotIndex) {
+                    native_handle_close((*nh)[deltaIndex][snapshotIndex]);
+                    native_handle_delete((*nh)[deltaIndex][snapshotIndex]);
+                    (*nh)[deltaIndex][snapshotIndex] = nullptr;
+                }
+            }
+            return status;
+        }
+    }
+    return NO_ERROR;
+}
+
+/**
+ * \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.
+ */
+inline 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;
+    std::vector<std::vector<native_handle_t*> > nhAA;
+    if (flatten(t, &nhAA, 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) {
+        for (auto nhA : nhAA) {
+            for (auto nh : nhA) {
+                if (nh != nullptr) {
+                    native_handle_close(nh);
+                    native_handle_delete(nh);
+                }
+            }
+        }
+        return false;
+    }
+
+    for (auto nhA : nhAA) {
+        for (auto nh : nhA) {
+            if (nh != nullptr) {
+                native_handle_delete(nh);
+            }
+        }
+    }
+    return true;
+}
+
+// Ref: frameworks/native/libs/gui/IGraphicBufferProducer.cpp:
+//      IGraphicBufferProducer::QueueBufferOutput
+
+/**
+ * \brief Convert `HGraphicBufferProducer::QueueBufferOutput` to
+ * `IGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * \param[out] l The destination `IGraphicBufferProducer::QueueBufferOutput`.
+ * \param[in] t The source `HGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * This function will duplicate all file descriptors contained in \p t.
+ */
+// convert: HGraphicBufferProducer::QueueBufferOutput ->
+// IGraphicBufferProducer::QueueBufferOutput
+inline 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 `IGraphicBufferProducer::DisconnectMode` to
+ * `HGraphicBufferProducer::DisconnectMode`.
+ *
+ * \param[in] l The source `IGraphicBufferProducer::DisconnectMode`.
+ * \return The corresponding `HGraphicBufferProducer::DisconnectMode`.
+ */
+inline HGraphicBufferProducer::DisconnectMode toHDisconnectMode(
+        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;
+}
+
+// H2BGraphicBufferProducer
+
+status_t H2BGraphicBufferProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
+    *buf = new GraphicBuffer();
+    status_t fnStatus;
+    status_t transStatus = toStatusT(mBase->requestBuffer(
+            static_cast<int32_t>(slot),
+            [&fnStatus, &buf] (Status status, AnwBuffer const& buffer) {
+                fnStatus = toStatusT(status);
+                if (!convertTo(buf->get(), buffer)) {
+                    fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+                }
+            }));
+    return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t H2BGraphicBufferProducer::setMaxDequeuedBufferCount(
+        int maxDequeuedBuffers) {
+    return toStatusT(mBase->setMaxDequeuedBufferCount(
+            static_cast<int32_t>(maxDequeuedBuffers)));
+}
+
+status_t H2BGraphicBufferProducer::setAsyncMode(bool async) {
+    return toStatusT(mBase->setAsyncMode(async));
+}
+
+status_t H2BGraphicBufferProducer::dequeueBuffer(
+        int* slot, sp<Fence>* fence,
+        uint32_t w, uint32_t h, ::android::PixelFormat format,
+        uint32_t usage, FrameEventHistoryDelta* outTimestamps) {
+    *fence = new Fence();
+    status_t fnStatus;
+    status_t transStatus = toStatusT(mBase->dequeueBuffer(
+            w, h, static_cast<PixelFormat>(format), usage,
+            outTimestamps != nullptr,
+            [&fnStatus, slot, fence, outTimestamps] (
+                    Status status,
+                    int32_t tSlot,
+                    hidl_handle const& tFence,
+                    HGraphicBufferProducer::FrameEventHistoryDelta const& tTs) {
+                fnStatus = toStatusT(status);
+                *slot = tSlot;
+                if (!convertTo(fence->get(), tFence)) {
+                    ALOGE("H2BGraphicBufferProducer::dequeueBuffer - "
+                            "Invalid output fence");
+                    fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+                }
+                if (outTimestamps && !convertTo(outTimestamps, tTs)) {
+                    ALOGE("H2BGraphicBufferProducer::dequeueBuffer - "
+                            "Invalid output timestamps");
+                    fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+                }
+            }));
+    return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t H2BGraphicBufferProducer::detachBuffer(int slot) {
+    return toStatusT(mBase->detachBuffer(static_cast<int>(slot)));
+}
+
+status_t H2BGraphicBufferProducer::detachNextBuffer(
+        sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) {
+    *outBuffer = new GraphicBuffer();
+    *outFence = new Fence();
+    status_t fnStatus;
+    status_t transStatus = toStatusT(mBase->detachNextBuffer(
+            [&fnStatus, outBuffer, outFence] (
+                    Status status,
+                    AnwBuffer const& tBuffer,
+                    hidl_handle const& tFence) {
+                fnStatus = toStatusT(status);
+                if (!convertTo(outFence->get(), tFence)) {
+                    ALOGE("H2BGraphicBufferProducer::detachNextBuffer - "
+                            "Invalid output fence");
+                    fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+                }
+                if (!convertTo(outBuffer->get(), tBuffer)) {
+                    ALOGE("H2BGraphicBufferProducer::detachNextBuffer - "
+                            "Invalid output buffer");
+                    fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+                }
+            }));
+    return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t H2BGraphicBufferProducer::attachBuffer(
+        int* outSlot, const sp<GraphicBuffer>& buffer) {
+    AnwBuffer tBuffer;
+    wrapAs(&tBuffer, *buffer);
+    status_t fnStatus;
+    status_t transStatus = toStatusT(mBase->attachBuffer(tBuffer,
+            [&fnStatus, outSlot] (Status status, int32_t slot) {
+                fnStatus = toStatusT(status);
+                *outSlot = slot;
+            }));
+    return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t H2BGraphicBufferProducer::queueBuffer(
+        int slot,
+        const QueueBufferInput& input,
+        QueueBufferOutput* output) {
+    HGraphicBufferProducer::QueueBufferInput tInput;
+    native_handle_t* nh;
+    if (!wrapAs(&tInput, &nh, input)) {
+        ALOGE("H2BGraphicBufferProducer::queueBuffer - "
+                "Invalid input");
+        return BAD_VALUE;
+    }
+    status_t fnStatus;
+    status_t transStatus = toStatusT(mBase->queueBuffer(slot, tInput,
+            [&fnStatus, output] (
+                    Status status,
+                    HGraphicBufferProducer::QueueBufferOutput const& tOutput) {
+                fnStatus = toStatusT(status);
+                if (!convertTo(output, tOutput)) {
+                    ALOGE("H2BGraphicBufferProducer::queueBuffer - "
+                            "Invalid output");
+                    fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+                }
+            }));
+    native_handle_delete(nh);
+    return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t H2BGraphicBufferProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
+    hidl_handle tFence;
+    native_handle_t* nh = nullptr;
+    if ((fence == nullptr) || !wrapAs(&tFence, &nh, *fence)) {
+        ALOGE("H2BGraphicBufferProducer::cancelBuffer - "
+                "Invalid input fence");
+        return BAD_VALUE;
+    }
+
+    status_t status = toStatusT(mBase->cancelBuffer(
+            static_cast<int32_t>(slot), tFence));
+    native_handle_delete(nh);
+    return status;
+}
+
+int H2BGraphicBufferProducer::query(int what, int* value) {
+    int result;
+    status_t transStatus = toStatusT(mBase->query(
+            static_cast<int32_t>(what),
+            [&result, value] (int32_t tResult, int32_t tValue) {
+                result = static_cast<int>(tResult);
+                *value = static_cast<int>(tValue);
+            }));
+    return transStatus == NO_ERROR ? result : static_cast<int>(transStatus);
+}
+
+status_t H2BGraphicBufferProducer::connect(
+        const sp<IProducerListener>& listener, int api,
+        bool producerControlledByApp, QueueBufferOutput* output) {
+    sp<HProducerListener> tListener = listener == nullptr ?
+            nullptr : new B2HProducerListener(listener);
+    status_t fnStatus;
+    status_t transStatus = toStatusT(mBase->connect(
+            tListener, static_cast<int32_t>(api), producerControlledByApp,
+            [&fnStatus, output] (
+                    Status status,
+                    HGraphicBufferProducer::QueueBufferOutput const& tOutput) {
+                fnStatus = toStatusT(status);
+                if (!convertTo(output, tOutput)) {
+                    ALOGE("H2BGraphicBufferProducer::connect - "
+                            "Invalid output");
+                    fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+                }
+            }));
+    return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t H2BGraphicBufferProducer::disconnect(int api, DisconnectMode mode) {
+    return toStatusT(mBase->disconnect(
+            static_cast<int32_t>(api), toHDisconnectMode(mode)));
+}
+
+status_t H2BGraphicBufferProducer::setSidebandStream(
+        const sp<NativeHandle>& stream) {
+    return toStatusT(mBase->setSidebandStream(stream == nullptr ? nullptr : stream->handle()));
+}
+
+void H2BGraphicBufferProducer::allocateBuffers(uint32_t width, uint32_t height,
+        ::android::PixelFormat format, uint32_t usage) {
+    mBase->allocateBuffers(
+            width, height, static_cast<PixelFormat>(format), usage);
+}
+
+status_t H2BGraphicBufferProducer::allowAllocation(bool allow) {
+    return toStatusT(mBase->allowAllocation(allow));
+}
+
+status_t H2BGraphicBufferProducer::setGenerationNumber(uint32_t generationNumber) {
+    return toStatusT(mBase->setGenerationNumber(generationNumber));
+}
+
+String8 H2BGraphicBufferProducer::getConsumerName() const {
+    String8 lName;
+    mBase->getConsumerName([&lName] (hidl_string const& name) {
+                lName = name.c_str();
+            });
+    return lName;
+}
+
+status_t H2BGraphicBufferProducer::setSharedBufferMode(bool sharedBufferMode) {
+    return toStatusT(mBase->setSharedBufferMode(sharedBufferMode));
+}
+
+status_t H2BGraphicBufferProducer::setAutoRefresh(bool autoRefresh) {
+    return toStatusT(mBase->setAutoRefresh(autoRefresh));
+}
+
+status_t H2BGraphicBufferProducer::setDequeueTimeout(nsecs_t timeout) {
+    return toStatusT(mBase->setDequeueTimeout(static_cast<int64_t>(timeout)));
+}
+
+status_t H2BGraphicBufferProducer::getLastQueuedBuffer(
+        sp<GraphicBuffer>* outBuffer,
+        sp<Fence>* outFence,
+        float outTransformMatrix[16]) {
+    status_t fnStatus;
+    status_t transStatus = toStatusT(mBase->getLastQueuedBuffer(
+            [&fnStatus, outBuffer, outFence, &outTransformMatrix] (
+                    Status status,
+                    AnwBuffer const& buffer,
+                    hidl_handle const& fence,
+                    hidl_array<float, 16> const& transformMatrix) {
+                fnStatus = toStatusT(status);
+                *outBuffer = new GraphicBuffer();
+                if (!convertTo(outBuffer->get(), buffer)) {
+                    ALOGE("H2BGraphicBufferProducer::getLastQueuedBuffer - "
+                            "Invalid output buffer");
+                    fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+                }
+                *outFence = new Fence();
+                if (!convertTo(outFence->get(), fence)) {
+                    ALOGE("H2BGraphicBufferProducer::getLastQueuedBuffer - "
+                            "Invalid output fence");
+                    fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
+                }
+                std::copy(transformMatrix.data(),
+                        transformMatrix.data() + 16,
+                        outTransformMatrix);
+            }));
+    return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+void H2BGraphicBufferProducer::getFrameTimestamps(FrameEventHistoryDelta* outDelta) {
+    mBase->getFrameTimestamps([outDelta] (
+            HGraphicBufferProducer::FrameEventHistoryDelta const& tDelta) {
+                convertTo(outDelta, tDelta);
+            });
+}
+
+status_t H2BGraphicBufferProducer::getUniqueId(uint64_t* outId) const {
+    status_t fnStatus;
+    status_t transStatus = toStatusT(mBase->getUniqueId(
+            [&fnStatus, outId] (Status status, uint64_t id) {
+                fnStatus = toStatusT(status);
+                *outId = id;
+            }));
+    return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace bufferqueue
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/libs/gui/include/private/gui/BitTube.h b/libs/gui/include/private/gui/BitTube.h
new file mode 100644
index 0000000..13c0162
--- /dev/null
+++ b/libs/gui/include/private/gui/BitTube.h
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+#include <binder/Parcelable.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+class Parcel;
+
+namespace gui {
+
+class BitTube : public Parcelable {
+public:
+    // creates an uninitialized BitTube (to unparcel into)
+    BitTube() = default;
+
+    // creates a BitTube with a a specified send and receive buffer size
+    explicit BitTube(size_t bufsize);
+
+    // creates a BitTube with a default (4KB) send buffer
+    struct DefaultSizeType {};
+    static constexpr DefaultSizeType DefaultSize{};
+    explicit BitTube(DefaultSizeType);
+
+    explicit BitTube(const Parcel& data);
+
+    virtual ~BitTube() = default;
+
+    // check state after construction
+    status_t initCheck() const;
+
+    // get receive file-descriptor
+    int getFd() const;
+
+    // get the send file-descriptor.
+    int getSendFd() const;
+
+    // moves the receive file descriptor out of this BitTube
+    base::unique_fd moveReceiveFd();
+
+    // resets this BitTube's receive file descriptor to receiveFd
+    void setReceiveFd(base::unique_fd&& receiveFd);
+
+    // send objects (sized blobs). All objects are guaranteed to be written or the call fails.
+    template <typename T>
+    static ssize_t sendObjects(BitTube* tube, T const* events, size_t count) {
+        return sendObjects(tube, events, count, sizeof(T));
+    }
+
+    // receive objects (sized blobs). If the receiving buffer isn't large enough, excess messages
+    // are silently discarded.
+    template <typename T>
+    static ssize_t recvObjects(BitTube* tube, T* events, size_t count) {
+        return recvObjects(tube, events, count, sizeof(T));
+    }
+
+    // implement the Parcelable protocol. Only parcels the receive file descriptor
+    status_t writeToParcel(Parcel* reply) const;
+    status_t readFromParcel(const Parcel* parcel);
+
+private:
+    void init(size_t rcvbuf, size_t sndbuf);
+
+    // send a message. The write is guaranteed to send the whole message or fail.
+    ssize_t write(void const* vaddr, size_t size);
+
+    // receive a message. the passed buffer must be at least as large as the write call used to send
+    // the message, excess data is silently discarded.
+    ssize_t read(void* vaddr, size_t size);
+
+    base::unique_fd mSendFd;
+    mutable base::unique_fd mReceiveFd;
+
+    static ssize_t sendObjects(BitTube* tube, void const* events, size_t count, size_t objSize);
+
+    static ssize_t recvObjects(BitTube* tube, void* events, size_t count, size_t objSize);
+};
+
+} // namespace gui
+} // namespace android
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
new file mode 100644
index 0000000..7efdb14
--- /dev/null
+++ b/libs/gui/tests/Android.bp
@@ -0,0 +1,46 @@
+// Build the unit tests,
+
+// Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
+// to integrate with auto-test framework.
+cc_test {
+    name: "libgui_test",
+
+    clang: true,
+
+    srcs: [
+        "BufferItemConsumer_test.cpp",
+        "BufferQueue_test.cpp",
+        "CpuConsumer_test.cpp",
+        "FillBuffer.cpp",
+        "GLTest.cpp",
+        "IGraphicBufferProducer_test.cpp",
+        "Malicious.cpp",
+        "MultiTextureConsumer_test.cpp",
+        "StreamSplitter_test.cpp",
+        "SurfaceTextureClient_test.cpp",
+        "SurfaceTextureFBO_test.cpp",
+        "SurfaceTextureGLThreadToGL_test.cpp",
+        "SurfaceTextureGLToGL_test.cpp",
+        "SurfaceTextureGL_test.cpp",
+        "SurfaceTextureMultiContextGL_test.cpp",
+        "Surface_test.cpp",
+        "TextureRenderer.cpp",
+    ],
+
+    shared_libs: [
+        "android.hardware.configstore@1.0",
+        "android.hardware.configstore-utils",
+        "liblog",
+        "libEGL",
+        "libGLESv1_CM",
+        "libGLESv2",
+        "libbinder",
+        "libcutils",
+        "libgui",
+        "libhidlbase",
+        "libhidltransport",
+        "libui",
+        "libutils",
+        "libnativewindow"
+    ],
+}
diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk
deleted file mode 100644
index 6ad9986..0000000
--- a/libs/gui/tests/Android.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-# Build the unit tests,
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_CLANG := true
-
-LOCAL_MODULE := libgui_test
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
-    BufferQueue_test.cpp \
-    CpuConsumer_test.cpp \
-    FillBuffer.cpp \
-    GLTest.cpp \
-    IGraphicBufferProducer_test.cpp \
-    MultiTextureConsumer_test.cpp \
-    SRGB_test.cpp \
-    StreamSplitter_test.cpp \
-    SurfaceTextureClient_test.cpp \
-    SurfaceTextureFBO_test.cpp \
-    SurfaceTextureGLThreadToGL_test.cpp \
-    SurfaceTextureGLToGL_test.cpp \
-    SurfaceTextureGL_test.cpp \
-    SurfaceTextureMultiContextGL_test.cpp \
-    Surface_test.cpp \
-    TextureRenderer.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-	libEGL \
-	libGLESv1_CM \
-	libGLESv2 \
-	libbinder \
-	libcutils \
-	libgui \
-	libsync \
-	libui \
-	libutils \
-
-# Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
-# to integrate with auto-test framework.
-include $(BUILD_NATIVE_TEST)
-
-# Include subdirectory makefiles
-# ============================================================
-
-# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
-# team really wants is to build the stuff defined by this makefile.
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/libs/gui/tests/BufferItemConsumer_test.cpp b/libs/gui/tests/BufferItemConsumer_test.cpp
new file mode 100644
index 0000000..d64e530
--- /dev/null
+++ b/libs/gui/tests/BufferItemConsumer_test.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BufferItemConsumer_test"
+//#define LOG_NDEBUG 0
+
+#include <gtest/gtest.h>
+#include <gui/BufferItemConsumer.h>
+#include <gui/IProducerListener.h>
+#include <gui/Surface.h>
+
+namespace android {
+
+static constexpr int kWidth = 100;
+static constexpr int kHeight = 100;
+static constexpr int kMaxLockedBuffers = 3;
+static constexpr int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+static constexpr int kFrameSleepUs = 30 * 1000;
+
+class BufferItemConsumerTest : public ::testing::Test {
+   protected:
+    struct BufferFreedListener
+        : public BufferItemConsumer::BufferFreedListener {
+        explicit BufferFreedListener(BufferItemConsumerTest* test)
+            : mTest(test) {}
+        void onBufferFreed(const wp<GraphicBuffer>& /* gBuffer */) override {
+            mTest->HandleBufferFreed();
+        }
+        BufferItemConsumerTest* mTest;
+    };
+
+    void SetUp() override {
+        BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+        mBIC =
+            new BufferItemConsumer(mConsumer, kFormat, kMaxLockedBuffers, true);
+        String8 name("BufferItemConsumer_Under_Test");
+        mBIC->setName(name);
+        mBFL = new BufferFreedListener(this);
+        mBIC->setBufferFreedListener(mBFL);
+
+        sp<IProducerListener> producerListener = new DummyProducerListener();
+        IGraphicBufferProducer::QueueBufferOutput bufferOutput;
+        ASSERT_EQ(NO_ERROR,
+                  mProducer->connect(producerListener, NATIVE_WINDOW_API_CPU,
+                                     true, &bufferOutput));
+        ASSERT_EQ(NO_ERROR,
+                  mProducer->setMaxDequeuedBufferCount(kMaxLockedBuffers));
+    }
+
+    int GetFreedBufferCount() {
+        std::lock_guard<std::mutex> lock(mMutex);
+        return mFreedBufferCount;
+    }
+
+    void HandleBufferFreed() {
+        std::lock_guard<std::mutex> lock(mMutex);
+        mFreedBufferCount++;
+        ALOGV("HandleBufferFreed, mFreedBufferCount=%d", mFreedBufferCount);
+    }
+
+    void DequeueBuffer(int* outSlot) {
+        ASSERT_NE(outSlot, nullptr);
+
+        int slot;
+        sp<Fence> outFence;
+        status_t ret = mProducer->dequeueBuffer(&slot, &outFence, kWidth,
+                                                kHeight, 0, 0, nullptr);
+        ASSERT_GE(ret, 0);
+
+        ALOGV("dequeueBuffer: slot=%d", slot);
+        if (ret & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
+            ret = mProducer->requestBuffer(slot, &mBuffers[slot]);
+            ASSERT_EQ(NO_ERROR, ret);
+        }
+        *outSlot = slot;
+    }
+
+    void QueueBuffer(int slot) {
+        ALOGV("enqueueBuffer: slot=%d", slot);
+        IGraphicBufferProducer::QueueBufferInput bufferInput(
+            0ULL, true, HAL_DATASPACE_UNKNOWN, Rect::INVALID_RECT,
+            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
+        IGraphicBufferProducer::QueueBufferOutput bufferOutput;
+        status_t ret = mProducer->queueBuffer(slot, bufferInput, &bufferOutput);
+        ASSERT_EQ(NO_ERROR, ret);
+    }
+
+    void AcquireBuffer(int* outSlot) {
+        ASSERT_NE(outSlot, nullptr);
+        BufferItem buffer;
+        status_t ret = mBIC->acquireBuffer(&buffer, 0, false);
+        ASSERT_EQ(NO_ERROR, ret);
+
+        ALOGV("acquireBuffer: slot=%d", buffer.mSlot);
+        *outSlot = buffer.mSlot;
+    }
+
+    void ReleaseBuffer(int slot) {
+        ALOGV("releaseBuffer: slot=%d", slot);
+        BufferItem buffer;
+        buffer.mSlot = slot;
+        buffer.mGraphicBuffer = mBuffers[slot];
+        status_t ret = mBIC->releaseBuffer(buffer, Fence::NO_FENCE);
+        ASSERT_EQ(NO_ERROR, ret);
+    }
+
+
+    std::mutex mMutex;
+    int mFreedBufferCount{0};
+
+    sp<BufferItemConsumer> mBIC;
+    sp<BufferFreedListener> mBFL;
+    sp<IGraphicBufferProducer> mProducer;
+    sp<IGraphicBufferConsumer> mConsumer;
+    sp<GraphicBuffer> mBuffers[BufferQueueDefs::NUM_BUFFER_SLOTS];
+};
+
+// Test that detaching buffer from consumer side triggers onBufferFreed.
+TEST_F(BufferItemConsumerTest, TriggerBufferFreed_DetachBufferFromConsumer) {
+    int slot;
+    // Producer: generate a dummy buffer.
+    DequeueBuffer(&slot);
+    QueueBuffer(slot);
+
+    ASSERT_EQ(0, GetFreedBufferCount());
+    // Consumer: acquire the buffer and then detach it.
+    AcquireBuffer(&slot);
+    status_t ret = mBIC->detachBuffer(slot);
+    ASSERT_EQ(NO_ERROR, ret);
+
+    // Sleep to give some time for callbacks to happen.
+    usleep(kFrameSleepUs);
+    ASSERT_EQ(1, GetFreedBufferCount());
+}
+
+// Test that detaching buffer from producer side triggers onBufferFreed.
+TEST_F(BufferItemConsumerTest, TriggerBufferFreed_DetachBufferFromProducer) {
+    int slot;
+    // Let buffer go through the cycle at least once.
+    DequeueBuffer(&slot);
+    QueueBuffer(slot);
+    AcquireBuffer(&slot);
+    ReleaseBuffer(slot);
+
+    ASSERT_EQ(0, GetFreedBufferCount());
+
+    // Producer: generate the buffer again.
+    DequeueBuffer(&slot);
+
+    // Producer: detach the buffer.
+    status_t ret = mProducer->detachBuffer(slot);
+    ASSERT_EQ(NO_ERROR, ret);
+
+    // Sleep to give some time for callbacks to happen.
+    usleep(kFrameSleepUs);
+    ASSERT_EQ(1, GetFreedBufferCount());
+}
+
+// Test that abandoning BufferItemConsumer triggers onBufferFreed.
+TEST_F(BufferItemConsumerTest, TriggerBufferFreed_AbandonBufferItemConsumer) {
+    int slot;
+    // Let buffer go through the cycle at least once.
+    DequeueBuffer(&slot);
+    QueueBuffer(slot);
+    AcquireBuffer(&slot);
+    ReleaseBuffer(slot);
+
+    // Abandon the BufferItemConsumer.
+    mBIC->abandon();
+
+    // Sleep to give some time for callbacks to happen.
+    usleep(kFrameSleepUs);
+    ASSERT_EQ(1, GetFreedBufferCount());
+}
+
+// Test that delete BufferItemConsumer triggers onBufferFreed.
+TEST_F(BufferItemConsumerTest, TriggerBufferFreed_DeleteBufferItemConsumer) {
+    int slot;
+    // Let buffer go through the cycle at least once.
+    DequeueBuffer(&slot);
+    QueueBuffer(slot);
+    AcquireBuffer(&slot);
+    ReleaseBuffer(slot);
+
+    // Delete the BufferItemConsumer.
+    mBIC.clear();
+
+    // Sleep to give some time for callbacks to happen.
+    usleep(kFrameSleepUs);
+    ASSERT_EQ(1, GetFreedBufferCount());
+}
+
+}  // namespace android
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 8a9eeee..60c1277 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -98,7 +98,11 @@
 
 // XXX: Tests that fork a process to hold the BufferQueue must run before tests
 // that use a local BufferQueue, or else Binder will get unhappy
-TEST_F(BufferQueueTest, BufferQueueInAnotherProcess) {
+//
+// In one instance this was a crash in the createBufferQueue where the
+// binder call to create a buffer allocator apparently got garbage back.
+// See b/36592665.
+TEST_F(BufferQueueTest, DISABLED_BufferQueueInAnotherProcess) {
     const String16 PRODUCER_NAME = String16("BQTestProducer");
     const String16 CONSUMER_NAME = String16("BQTestConsumer");
 
@@ -139,7 +143,7 @@
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
             mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-                    GRALLOC_USAGE_SW_WRITE_OFTEN));
+                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
 
     uint32_t* dataIn;
@@ -183,7 +187,7 @@
     for (int i = 0; i < 2; i++) {
         ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
                 mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0,
-                    GRALLOC_USAGE_SW_READ_OFTEN));
+                    GRALLOC_USAGE_SW_READ_OFTEN, nullptr));
         ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
         ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
         ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
@@ -191,7 +195,7 @@
 
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
             mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0,
-                GRALLOC_USAGE_SW_READ_OFTEN));
+                GRALLOC_USAGE_SW_READ_OFTEN, nullptr));
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
 
@@ -234,7 +238,7 @@
     for (int i = 0; i < 3; i++) {
         ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
                 mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0,
-                    GRALLOC_USAGE_SW_READ_OFTEN));
+                    GRALLOC_USAGE_SW_READ_OFTEN, nullptr));
         ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
         ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
         ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
@@ -270,7 +274,7 @@
 
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
             mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0,
-            GRALLOC_USAGE_SW_READ_OFTEN));
+            GRALLOC_USAGE_SW_READ_OFTEN, nullptr));
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
     ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
@@ -280,7 +284,7 @@
     for (int i = 0; i < 2; i++) {
         ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
                 mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0,
-                GRALLOC_USAGE_SW_READ_OFTEN));
+                GRALLOC_USAGE_SW_READ_OFTEN, nullptr));
         ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
         ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
         ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
@@ -330,7 +334,7 @@
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
             mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-                    GRALLOC_USAGE_SW_WRITE_OFTEN));
+                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
     ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer(slot)); // Not requested
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
     ASSERT_EQ(OK, mProducer->detachBuffer(slot));
@@ -379,7 +383,7 @@
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
             mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-                    GRALLOC_USAGE_SW_WRITE_OFTEN));
+                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
     IGraphicBufferProducer::QueueBufferInput input(0, false,
             HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1),
@@ -415,7 +419,7 @@
 
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
             mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-                    GRALLOC_USAGE_SW_WRITE_OFTEN));
+                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
 
     uint32_t* dataOut;
@@ -438,7 +442,7 @@
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
             mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-                    GRALLOC_USAGE_SW_WRITE_OFTEN));
+                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
 
     uint32_t* dataIn;
@@ -487,13 +491,13 @@
     // This should return an error since it would require an allocation
     ASSERT_EQ(OK, mProducer->allowAllocation(false));
     ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, 0, 0,
-            0, GRALLOC_USAGE_SW_WRITE_OFTEN));
+            0, GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
 
     // This should succeed, now that we've lifted the prohibition
     ASSERT_EQ(OK, mProducer->allowAllocation(true));
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
             mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-            GRALLOC_USAGE_SW_WRITE_OFTEN));
+            GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
 
     // Release the previous buffer back to the BufferQueue
     mProducer->cancelBuffer(slot, fence);
@@ -501,7 +505,7 @@
     // This should fail since we're requesting a different size
     ASSERT_EQ(OK, mProducer->allowAllocation(false));
     ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence,
-            WIDTH * 2, HEIGHT * 2, 0, GRALLOC_USAGE_SW_WRITE_OFTEN));
+            WIDTH * 2, HEIGHT * 2, 0, GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
 }
 
 TEST_F(BufferQueueTest, TestGenerationNumbers) {
@@ -518,7 +522,7 @@
     int slot;
     sp<Fence> fence;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+            mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
 
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
@@ -561,7 +565,7 @@
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0));
+            mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr));
     ASSERT_EQ(OK, mProducer->requestBuffer(sharedSlot, &buffer));
 
     // Queue the buffer
@@ -575,7 +579,8 @@
     // always the same one and because async mode gets enabled.
     int slot;
     for (int i = 0; i < 5; i++) {
-        ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+        ASSERT_EQ(OK, mProducer->dequeueBuffer(
+                &slot, &fence, 0, 0, 0, 0, nullptr));
         ASSERT_EQ(sharedSlot, slot);
         ASSERT_EQ(OK, mProducer->queueBuffer(sharedSlot, input, &output));
     }
@@ -612,7 +617,7 @@
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0));
+            mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr));
     ASSERT_EQ(OK, mProducer->requestBuffer(sharedSlot, &buffer));
 
     // Queue the buffer
@@ -639,7 +644,8 @@
     // always return the same one.
     int slot;
     for (int i = 0; i < 5; i++) {
-        ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+        ASSERT_EQ(OK, mProducer->dequeueBuffer(
+                &slot, &fence, 0, 0, 0, 0, nullptr));
         ASSERT_EQ(sharedSlot, slot);
         ASSERT_EQ(OK, mProducer->queueBuffer(sharedSlot, input, &output));
     }
@@ -678,7 +684,7 @@
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0));
+            mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr));
     ASSERT_EQ(OK, mProducer->requestBuffer(sharedSlot, &buffer));
 
     // Enable shared buffer mode
@@ -695,7 +701,8 @@
     // always the same one and because async mode gets enabled.
     int slot;
     for (int i = 0; i < 5; i++) {
-        ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+        ASSERT_EQ(OK, mProducer->dequeueBuffer(
+                &slot, &fence, 0, 0, 0, 0, nullptr));
         ASSERT_EQ(sharedSlot, slot);
         ASSERT_EQ(OK, mProducer->queueBuffer(sharedSlot, input, &output));
     }
@@ -730,7 +737,8 @@
     for (int i = 0; i < 5; ++i) {
         int slot = BufferQueue::INVALID_BUFFER_SLOT;
         sp<Fence> fence = Fence::NO_FENCE;
-        auto result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0);
+        auto result = mProducer->dequeueBuffer(
+                &slot, &fence, 0, 0, 0, 0, nullptr);
         if (i < 2) {
             ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
                     result);
@@ -757,7 +765,8 @@
     for (int i = 0; i < 2; ++i) {
         int slot = BufferQueue::INVALID_BUFFER_SLOT;
         sp<Fence> fence = Fence::NO_FENCE;
-        ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+        ASSERT_EQ(OK, mProducer->dequeueBuffer(
+                &slot, &fence, 0, 0, 0, 0, nullptr));
         ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
         IGraphicBufferProducer::QueueBufferInput input(0ull, true,
                 HAL_DATASPACE_UNKNOWN, Rect::INVALID_RECT,
@@ -768,7 +777,8 @@
     int slot = BufferQueue::INVALID_BUFFER_SLOT;
     sp<Fence> fence = Fence::NO_FENCE;
     auto startTime = systemTime();
-    ASSERT_EQ(TIMED_OUT, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+    ASSERT_EQ(TIMED_OUT, mProducer->dequeueBuffer(
+            &slot, &fence, 0, 0, 0, 0, nullptr));
     ASSERT_GE(systemTime() - startTime, TIMEOUT);
 
     // We're technically attaching the same buffer multiple times (since we
@@ -789,7 +799,7 @@
     int slot = BufferQueue::INVALID_BUFFER_SLOT;
     sp<Fence> sourceFence;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &sourceFence, 0, 0, 0, 0));
+            mProducer->dequeueBuffer(&slot, &sourceFence, 0, 0, 0, 0, nullptr));
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
     ASSERT_EQ(OK, mProducer->detachBuffer(slot));
@@ -812,7 +822,7 @@
     int slot = BufferQueue::INVALID_BUFFER_SLOT;
     sp<Fence> fence;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+            mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
     sp<GraphicBuffer> firstBuffer;
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &firstBuffer));
 
@@ -824,7 +834,7 @@
     // Dequeue a second buffer
     slot = BufferQueue::INVALID_BUFFER_SLOT;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+            mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
     sp<GraphicBuffer> secondBuffer;
     ASSERT_EQ(OK, mProducer->requestBuffer(slot, &secondBuffer));
 
@@ -876,7 +886,7 @@
     mProducer->setMaxDequeuedBufferCount(3);
     for (size_t i = 0; i < 3; ++i) {
         status_t result = mProducer->dequeueBuffer(&slots[i], &fence,
-                0, 0, 0, 0);
+                0, 0, 0, 0, nullptr);
         ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result);
         ASSERT_EQ(OK, mProducer->requestBuffer(slots[i], &buffer));
     }
@@ -889,7 +899,8 @@
     // The first segment is a two-buffer segment, so we only put one buffer into
     // the queue at a time
     for (size_t i = 0; i < 5; ++i) {
-        ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+        ASSERT_EQ(OK, mProducer->dequeueBuffer(
+                &slot, &fence, 0, 0, 0, 0, nullptr));
         ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
         ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
         ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
@@ -904,16 +915,17 @@
     // two-buffer segment, but then at the end, we put two buffers in the queue
     // at the same time before draining it.
     for (size_t i = 0; i < 5; ++i) {
-        ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+        ASSERT_EQ(OK, mProducer->dequeueBuffer(
+                &slot, &fence, 0, 0, 0, 0, nullptr));
         ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
         ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
         ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
                 EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
         std::this_thread::sleep_for(16ms);
     }
-    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
-    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
     ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
     ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
@@ -928,10 +940,11 @@
 
     // The third segment is a triple-buffer segment, so the queue is switching
     // between one buffer and two buffers deep.
-    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
     for (size_t i = 0; i < 5; ++i) {
-        ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+        ASSERT_EQ(OK, mProducer->dequeueBuffer(
+                &slot, &fence, 0, 0, 0, 0, nullptr));
         ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
         ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
         ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
@@ -1012,7 +1025,7 @@
     mProducer->setMaxDequeuedBufferCount(4);
     for (size_t i = 0; i < 4; ++i) {
         status_t result = mProducer->dequeueBuffer(&slots[i], &fence,
-                0, 0, 0, 0);
+                0, 0, 0, 0, nullptr);
         ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result);
         ASSERT_EQ(OK, mProducer->requestBuffer(slots[i], &buffer));
     }
@@ -1023,14 +1036,14 @@
     // Get buffers in all states: dequeued, filled, acquired, free
 
     // Fill 3 buffers
-    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
-    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
-    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
     ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
     // Dequeue 1 buffer
-    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
 
     // Acquire and free 1 buffer
     ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
@@ -1044,7 +1057,7 @@
 
     // Check no free buffers in dump
     String8 dumpString;
-    mConsumer->dump(dumpString, nullptr);
+    mConsumer->dumpState(String8{}, &dumpString);
 
     // Parse the dump to ensure that all buffer slots that are FREE also
     // have a null GraphicBuffer
@@ -1067,4 +1080,122 @@
     }
 }
 
+TEST_F(BufferQueueTest, TestBufferReplacedInQueueBuffer) {
+    createBufferQueue();
+    sp<DummyConsumer> dc(new DummyConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
+    IGraphicBufferProducer::QueueBufferOutput output;
+    ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
+            NATIVE_WINDOW_API_CPU, true, &output));
+    ASSERT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(1));
+
+    int slot = BufferQueue::INVALID_BUFFER_SLOT;
+    sp<Fence> fence = Fence::NO_FENCE;
+    sp<GraphicBuffer> buffer = nullptr;
+    IGraphicBufferProducer::QueueBufferInput input(0ull, true,
+        HAL_DATASPACE_UNKNOWN, Rect::INVALID_RECT,
+        NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
+    BufferItem item{};
+
+    // Preallocate, dequeue, request, and cancel 2 buffers so we don't get
+    // BUFFER_NEEDS_REALLOCATION below
+    int slots[2] = {};
+    ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(2));
+    for (size_t i = 0; i < 2; ++i) {
+        status_t result = mProducer->dequeueBuffer(&slots[i], &fence,
+                0, 0, 0, 0, nullptr);
+        ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result);
+        ASSERT_EQ(OK, mProducer->requestBuffer(slots[i], &buffer));
+    }
+    for (size_t i = 0; i < 2; ++i) {
+        ASSERT_EQ(OK, mProducer->cancelBuffer(slots[i], Fence::NO_FENCE));
+    }
+
+    // Fill 2 buffers without consumer consuming them. Verify that all
+    // queued buffer returns proper bufferReplaced flag
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+    ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
+    ASSERT_EQ(false, output.bufferReplaced);
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+    ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
+    ASSERT_EQ(true, output.bufferReplaced);
+}
+
+TEST_F(BufferQueueTest, TestStaleBufferHandleSentAfterDisconnect) {
+    createBufferQueue();
+    sp<DummyConsumer> dc(new DummyConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
+    IGraphicBufferProducer::QueueBufferOutput output;
+    sp<IProducerListener> dummyListener(new DummyProducerListener);
+    ASSERT_EQ(OK, mProducer->connect(dummyListener, NATIVE_WINDOW_API_CPU,
+            true, &output));
+
+    int slot = BufferQueue::INVALID_BUFFER_SLOT;
+    sp<Fence> fence = Fence::NO_FENCE;
+    sp<GraphicBuffer> buffer = nullptr;
+    IGraphicBufferProducer::QueueBufferInput input(0ull, true,
+            HAL_DATASPACE_UNKNOWN, Rect::INVALID_RECT,
+            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
+
+    // Dequeue, request, and queue one buffer
+    status_t result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0,
+            nullptr);
+    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result);
+    ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
+    ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
+
+    // Acquire and release the buffer. Upon acquiring, the buffer handle should
+    // be non-null since this is the first time we've acquired this slot.
+    BufferItem item;
+    ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+    ASSERT_EQ(slot, item.mSlot);
+    ASSERT_NE(nullptr, item.mGraphicBuffer.get());
+    ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
+            EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
+
+    // Dequeue and queue the buffer again
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+    ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
+
+    // Acquire and release the buffer again. Upon acquiring, the buffer handle
+    // should be null since this is not the first time we've acquired this slot.
+    ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+    ASSERT_EQ(slot, item.mSlot);
+    ASSERT_EQ(nullptr, item.mGraphicBuffer.get());
+    ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
+            EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
+
+    // Dequeue and queue the buffer again
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+    ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
+
+    // Disconnect the producer end. This should clear all of the slots and mark
+    // the buffer in the queue as stale.
+    ASSERT_EQ(OK, mProducer->disconnect(NATIVE_WINDOW_API_CPU));
+
+    // Acquire the buffer again. Upon acquiring, the buffer handle should not be
+    // null since the queued buffer should have been marked as stale, which
+    // should trigger the BufferQueue to resend the buffer handle.
+    ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+    ASSERT_EQ(slot, item.mSlot);
+    ASSERT_NE(nullptr, item.mGraphicBuffer.get());
+}
+
+TEST_F(BufferQueueTest, TestProducerConnectDisconnect) {
+    createBufferQueue();
+    sp<DummyConsumer> dc(new DummyConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
+    IGraphicBufferProducer::QueueBufferOutput output;
+    sp<IProducerListener> dummyListener(new DummyProducerListener);
+    ASSERT_EQ(NO_INIT, mProducer->disconnect(NATIVE_WINDOW_API_CPU));
+    ASSERT_EQ(OK, mProducer->connect(
+            dummyListener, NATIVE_WINDOW_API_CPU, true, &output));
+    ASSERT_EQ(BAD_VALUE, mProducer->connect(
+            dummyListener, NATIVE_WINDOW_API_MEDIA, true, &output));
+
+    ASSERT_EQ(BAD_VALUE, mProducer->disconnect(NATIVE_WINDOW_API_MEDIA));
+    ASSERT_EQ(OK, mProducer->disconnect(NATIVE_WINDOW_API_CPU));
+    ASSERT_EQ(NO_INIT, mProducer->disconnect(NATIVE_WINDOW_API_CPU));
+}
+
 } // namespace android
diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp
index 289cc74..5848c74 100644
--- a/libs/gui/tests/CpuConsumer_test.cpp
+++ b/libs/gui/tests/CpuConsumer_test.cpp
@@ -160,7 +160,7 @@
 };
 
 #define ASSERT_NO_ERROR(err, msg) \
-    ASSERT_EQ(NO_ERROR, err) << msg << strerror(-err)
+    ASSERT_EQ(NO_ERROR, err) << (msg) << strerror(-(err))
 
 void checkPixel(const CpuConsumer::LockedBuffer &buf,
         uint32_t x, uint32_t y, uint32_t r, uint32_t g=0, uint32_t b=0) {
@@ -490,7 +490,7 @@
 
     ASSERT_TRUE(anb != NULL);
 
-    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+    sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
     *stride = buf->getStride();
     uint8_t* img = NULL;
diff --git a/libs/gui/tests/DummyConsumer.h b/libs/gui/tests/DummyConsumer.h
index 0511e16..502bdf9 100644
--- a/libs/gui/tests/DummyConsumer.h
+++ b/libs/gui/tests/DummyConsumer.h
@@ -19,9 +19,9 @@
 namespace android {
 
 struct DummyConsumer : public BnConsumerListener {
-    virtual void onFrameAvailable(const BufferItem& /* item */) {}
-    virtual void onBuffersReleased() {}
-    virtual void onSidebandStreamChanged() {}
+    void onFrameAvailable(const BufferItem& /* item */) override {}
+    void onBuffersReleased() override {}
+    void onSidebandStreamChanged() override {}
 };
 
 } // namespace android
diff --git a/libs/gui/tests/FillBuffer.cpp b/libs/gui/tests/FillBuffer.cpp
index 079962c..ccd674f 100644
--- a/libs/gui/tests/FillBuffer.cpp
+++ b/libs/gui/tests/FillBuffer.cpp
@@ -95,7 +95,7 @@
             &anb));
     ASSERT_TRUE(anb != NULL);
 
-    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+    sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
     uint8_t* img = NULL;
     ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN,
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index 9f33047..aa071f6 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -17,6 +17,8 @@
 #define LOG_TAG "IGraphicBufferProducer_test"
 //#define LOG_NDEBUG 0
 
+#include "DummyConsumer.h"
+
 #include <gtest/gtest.h>
 
 #include <utils/String8.h>
@@ -64,12 +66,6 @@
     const sp<Fence> QUEUE_BUFFER_INPUT_FENCE = Fence::NO_FENCE;
 }; // namespace anonymous
 
-struct DummyConsumer : public BnConsumerListener {
-    virtual void onFrameAvailable(const BufferItem& /* item */) {}
-    virtual void onBuffersReleased() {}
-    virtual void onSidebandStreamChanged() {}
-};
-
 class IGraphicBufferProducerTest : public ::testing::Test {
 protected:
 
@@ -196,7 +192,7 @@
     };
 
     status_t dequeueBuffer(uint32_t w, uint32_t h, uint32_t format, uint32_t usage, DequeueBufferResult* result) {
-        return mProducer->dequeueBuffer(&result->slot, &result->fence, w, h, format, usage);
+        return mProducer->dequeueBuffer(&result->slot, &result->fence, w, h, format, usage, nullptr);
     }
 
     void setupDequeueRequestBuffer(int *slot, sp<Fence> *fence,
@@ -210,7 +206,7 @@
 
         ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
                 (mProducer->dequeueBuffer(slot, fence, DEFAULT_WIDTH,
-                DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS)));
+                DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS, nullptr)));
 
         EXPECT_LE(0, *slot);
         EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, *slot);
@@ -349,7 +345,7 @@
     ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
             (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
                                      DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
-                                     TEST_PRODUCER_USAGE_BITS)));
+                                     TEST_PRODUCER_USAGE_BITS, nullptr)));
 
     EXPECT_LE(0, dequeuedSlot);
     EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, dequeuedSlot);
@@ -366,20 +362,12 @@
     ASSERT_OK(mProducer->queueBuffer(dequeuedSlot, input, &output));
 
     {
-        uint32_t width;
-        uint32_t height;
-        uint32_t transformHint;
-        uint32_t numPendingBuffers;
-        uint64_t nextFrameNumber;
-
-        output.deflate(&width, &height, &transformHint, &numPendingBuffers,
-                &nextFrameNumber);
-
-        EXPECT_EQ(DEFAULT_WIDTH, width);
-        EXPECT_EQ(DEFAULT_HEIGHT, height);
-        EXPECT_EQ(DEFAULT_TRANSFORM_HINT, transformHint);
-        EXPECT_EQ(1u, numPendingBuffers); // since queueBuffer was called exactly once
-        EXPECT_EQ(2u, nextFrameNumber);
+        EXPECT_EQ(DEFAULT_WIDTH, output.width);
+        EXPECT_EQ(DEFAULT_HEIGHT, output.height);
+        EXPECT_EQ(DEFAULT_TRANSFORM_HINT, output.transformHint);
+        // Since queueBuffer was called exactly once
+        EXPECT_EQ(1u, output.numPendingBuffers);
+        EXPECT_EQ(2u, output.nextFrameNumber);
     }
 
     // Buffer was not in the dequeued state
@@ -416,7 +404,7 @@
     ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
             (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
                                      DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
-                                     TEST_PRODUCER_USAGE_BITS)));
+                                     TEST_PRODUCER_USAGE_BITS, nullptr)));
 
     // Slot was enqueued without requesting a buffer
     {
@@ -485,7 +473,7 @@
     ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
             (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
                                      DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
-                                     TEST_PRODUCER_USAGE_BITS)));
+                                     TEST_PRODUCER_USAGE_BITS, nullptr)));
 
     // No return code, but at least test that it doesn't blow up...
     // TODO: add a return code
@@ -534,7 +522,7 @@
                 (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
                                          DEFAULT_WIDTH, DEFAULT_HEIGHT,
                                          DEFAULT_FORMAT,
-                                         TEST_PRODUCER_USAGE_BITS)))
+                                         TEST_PRODUCER_USAGE_BITS, nullptr)))
                 << "iteration: " << i << ", slot: " << dequeuedSlot;
     }
 
@@ -571,7 +559,7 @@
                 (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
                                          DEFAULT_WIDTH, DEFAULT_HEIGHT,
                                          DEFAULT_FORMAT,
-                                         TEST_PRODUCER_USAGE_BITS)))
+                                         TEST_PRODUCER_USAGE_BITS, nullptr)))
                 << "slot: " << dequeuedSlot;
     }
 
@@ -606,7 +594,8 @@
         ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
                 (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
                 DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
-                TEST_PRODUCER_USAGE_BITS))) << "slot : " << dequeuedSlot;
+                TEST_PRODUCER_USAGE_BITS, nullptr)))
+                << "slot : " << dequeuedSlot;
         ASSERT_OK(mProducer->requestBuffer(dequeuedSlot, &dequeuedBuffer));
         ASSERT_OK(mProducer->queueBuffer(dequeuedSlot, input, &output));
     }
@@ -622,7 +611,8 @@
         ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
                 (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
                 DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
-                TEST_PRODUCER_USAGE_BITS))) << "slot: " << dequeuedSlot;
+                TEST_PRODUCER_USAGE_BITS, nullptr)))
+                << "slot: " << dequeuedSlot;
     }
 
     // Abandon buffer queue
@@ -639,7 +629,7 @@
     sp<Fence> fence;
 
     ASSERT_EQ(NO_INIT, mProducer->dequeueBuffer(&slot, &fence, DEFAULT_WIDTH,
-            DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS));
+            DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS, nullptr));
 }
 
 TEST_F(IGraphicBufferProducerTest,
@@ -659,7 +649,8 @@
 
     ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
             (mProducer->dequeueBuffer(&slot, &fence, DEFAULT_WIDTH,
-            DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS)));
+            DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS,
+            nullptr)));
 
     EXPECT_LE(0, slot);
     EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, slot);
diff --git a/libs/gui/tests/Malicious.cpp b/libs/gui/tests/Malicious.cpp
new file mode 100644
index 0000000..7ecf08c
--- /dev/null
+++ b/libs/gui/tests/Malicious.cpp
@@ -0,0 +1,202 @@
+/*
+ * 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.
+ */
+
+#include <gui/BufferQueue.h>
+#include <gui/IProducerListener.h>
+#include <gui/Surface.h>
+
+#include <android/native_window.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace test {
+
+class ProxyBQP : public BnGraphicBufferProducer {
+public:
+    ProxyBQP(const sp<IGraphicBufferProducer>& producer) : mProducer(producer) {}
+
+    // Pass through calls to mProducer
+    status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override {
+        return mProducer->requestBuffer(slot, buf);
+    }
+    status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) override {
+        return mProducer->setMaxDequeuedBufferCount(maxDequeuedBuffers);
+    }
+    status_t setAsyncMode(bool async) override { return mProducer->setAsyncMode(async); }
+    status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h, PixelFormat format,
+                           uint32_t usage, FrameEventHistoryDelta* outTimestamps) override {
+        return mProducer->dequeueBuffer(slot, fence, w, h, format, usage, outTimestamps);
+    }
+    status_t detachBuffer(int slot) override { return mProducer->detachBuffer(slot); }
+    status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) override {
+        return mProducer->detachNextBuffer(outBuffer, outFence);
+    }
+    status_t attachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer) override {
+        return mProducer->attachBuffer(outSlot, buffer);
+    }
+    status_t queueBuffer(int slot, const QueueBufferInput& input,
+                         QueueBufferOutput* output) override {
+        return mProducer->queueBuffer(slot, input, output);
+    }
+    status_t cancelBuffer(int slot, const sp<Fence>& fence) override {
+        return mProducer->cancelBuffer(slot, fence);
+    }
+    int query(int what, int* value) override { return mProducer->query(what, value); }
+    status_t connect(const sp<IProducerListener>& listener, int api, bool producerControlledByApp,
+                     QueueBufferOutput* output) override {
+        return mProducer->connect(listener, api, producerControlledByApp, output);
+    }
+    status_t disconnect(int api, DisconnectMode mode) override {
+        return mProducer->disconnect(api, mode);
+    }
+    status_t setSidebandStream(const sp<NativeHandle>& stream) override {
+        return mProducer->setSidebandStream(stream);
+    }
+    void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format,
+                         uint32_t usage) override {
+        mProducer->allocateBuffers(width, height, format, usage);
+    }
+    status_t allowAllocation(bool allow) override { return mProducer->allowAllocation(allow); }
+    status_t setGenerationNumber(uint32_t generationNumber) override {
+        return mProducer->setGenerationNumber(generationNumber);
+    }
+    String8 getConsumerName() const override { return mProducer->getConsumerName(); }
+    status_t setSharedBufferMode(bool sharedBufferMode) override {
+        return mProducer->setSharedBufferMode(sharedBufferMode);
+    }
+    status_t setAutoRefresh(bool autoRefresh) override {
+        return mProducer->setAutoRefresh(autoRefresh);
+    }
+    status_t setDequeueTimeout(nsecs_t timeout) override {
+        return mProducer->setDequeueTimeout(timeout);
+    }
+    status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence,
+                                 float outTransformMatrix[16]) override {
+        return mProducer->getLastQueuedBuffer(outBuffer, outFence, outTransformMatrix);
+    }
+    void getFrameTimestamps(FrameEventHistoryDelta*) override {}
+    status_t getUniqueId(uint64_t* outId) const override { return mProducer->getUniqueId(outId); }
+
+protected:
+    sp<IGraphicBufferProducer> mProducer;
+};
+
+class MaliciousBQP : public ProxyBQP {
+public:
+    MaliciousBQP(const sp<IGraphicBufferProducer>& producer) : ProxyBQP(producer) {}
+
+    void beMalicious(int32_t value) { mMaliciousValue = value; }
+
+    void setExpectedSlot(int32_t slot) { mExpectedSlot = slot; }
+
+    // Override dequeueBuffer, optionally corrupting the returned slot number
+    status_t dequeueBuffer(int* buf, sp<Fence>* fence, uint32_t width, uint32_t height,
+                           PixelFormat format, uint32_t usage,
+                           FrameEventHistoryDelta* outTimestamps) override {
+        EXPECT_EQ(BUFFER_NEEDS_REALLOCATION,
+                  mProducer->dequeueBuffer(buf, fence, width, height, format, usage,
+                                           outTimestamps));
+        EXPECT_EQ(mExpectedSlot, *buf);
+        if (mMaliciousValue != 0) {
+            *buf = mMaliciousValue;
+            return NO_ERROR;
+        } else {
+            return BUFFER_NEEDS_REALLOCATION;
+        }
+    }
+
+private:
+    int32_t mMaliciousValue = 0;
+    int32_t mExpectedSlot = 0;
+};
+
+class DummyListener : public BnConsumerListener {
+public:
+    void onFrameAvailable(const BufferItem&) override {}
+    void onBuffersReleased() override {}
+    void onSidebandStreamChanged() override {}
+};
+
+sp<MaliciousBQP> getMaliciousBQP() {
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    sp<IConsumerListener> listener = new DummyListener;
+    consumer->consumerConnect(listener, false);
+
+    sp<MaliciousBQP> malicious = new MaliciousBQP(producer);
+    return malicious;
+}
+
+TEST(Malicious, Bug36991414Max) {
+    sp<MaliciousBQP> malicious = getMaliciousBQP();
+    sp<Surface> surface = new Surface(malicious);
+
+    ASSERT_EQ(NO_ERROR, surface->connect(NATIVE_WINDOW_API_CPU, nullptr, false));
+    ANativeWindow_Buffer buffer;
+    ASSERT_EQ(NO_ERROR, surface->lock(&buffer, nullptr));
+    ASSERT_EQ(NO_ERROR, surface->unlockAndPost());
+
+    malicious->setExpectedSlot(1);
+    malicious->beMalicious(std::numeric_limits<int32_t>::max());
+    ASSERT_EQ(FAILED_TRANSACTION, surface->lock(&buffer, nullptr));
+}
+
+TEST(Malicious, Bug36991414Min) {
+    sp<MaliciousBQP> malicious = getMaliciousBQP();
+    sp<Surface> surface = new Surface(malicious);
+
+    ASSERT_EQ(NO_ERROR, surface->connect(NATIVE_WINDOW_API_CPU, nullptr, false));
+    ANativeWindow_Buffer buffer;
+    ASSERT_EQ(NO_ERROR, surface->lock(&buffer, nullptr));
+    ASSERT_EQ(NO_ERROR, surface->unlockAndPost());
+
+    malicious->setExpectedSlot(1);
+    malicious->beMalicious(std::numeric_limits<int32_t>::min());
+    ASSERT_EQ(FAILED_TRANSACTION, surface->lock(&buffer, nullptr));
+}
+
+TEST(Malicious, Bug36991414NegativeOne) {
+    sp<MaliciousBQP> malicious = getMaliciousBQP();
+    sp<Surface> surface = new Surface(malicious);
+
+    ASSERT_EQ(NO_ERROR, surface->connect(NATIVE_WINDOW_API_CPU, nullptr, false));
+    ANativeWindow_Buffer buffer;
+    ASSERT_EQ(NO_ERROR, surface->lock(&buffer, nullptr));
+    ASSERT_EQ(NO_ERROR, surface->unlockAndPost());
+
+    malicious->setExpectedSlot(1);
+    malicious->beMalicious(-1);
+    ASSERT_EQ(FAILED_TRANSACTION, surface->lock(&buffer, nullptr));
+}
+
+TEST(Malicious, Bug36991414NumSlots) {
+    sp<MaliciousBQP> malicious = getMaliciousBQP();
+    sp<Surface> surface = new Surface(malicious);
+
+    ASSERT_EQ(NO_ERROR, surface->connect(NATIVE_WINDOW_API_CPU, nullptr, false));
+    ANativeWindow_Buffer buffer;
+    ASSERT_EQ(NO_ERROR, surface->lock(&buffer, nullptr));
+    ASSERT_EQ(NO_ERROR, surface->unlockAndPost());
+
+    malicious->setExpectedSlot(1);
+    malicious->beMalicious(BufferQueueDefs::NUM_BUFFER_SLOTS);
+    ASSERT_EQ(FAILED_TRANSACTION, surface->lock(&buffer, nullptr));
+}
+
+} // namespace test
+} // namespace android
diff --git a/libs/gui/tests/SRGB_test.cpp b/libs/gui/tests/SRGB_test.cpp
deleted file mode 100644
index 3b11b97..0000000
--- a/libs/gui/tests/SRGB_test.cpp
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- * 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_TAG "SRGB_test"
-//#define LOG_NDEBUG 0
-
-// Ignore for this file because it flags every instance of
-// ASSERT_EQ(GL_NO_ERROR, glGetError());
-#pragma clang diagnostic ignored "-Wsign-compare"
-
-#include "GLTest.h"
-
-#include <math.h>
-
-#include <gui/CpuConsumer.h>
-#include <gui/Surface.h>
-#include <gui/SurfaceComposerClient.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES3/gl3.h>
-
-#include <android/native_window.h>
-
-#include <gtest/gtest.h>
-
-namespace android {
-
-class SRGBTest : public ::testing::Test {
-protected:
-    // Class constants
-    enum {
-        DISPLAY_WIDTH = 512,
-        DISPLAY_HEIGHT = 512,
-        PIXEL_SIZE = 4, // bytes or components
-        DISPLAY_SIZE = DISPLAY_WIDTH * DISPLAY_HEIGHT * PIXEL_SIZE,
-        ALPHA_VALUE = 223, // should be in [0, 255]
-        TOLERANCE = 1,
-    };
-    static const char SHOW_DEBUG_STRING[];
-
-    SRGBTest() :
-            mInputSurface(), mCpuConsumer(), mLockedBuffer(),
-            mEglDisplay(EGL_NO_DISPLAY), mEglConfig(),
-            mEglContext(EGL_NO_CONTEXT), mEglSurface(EGL_NO_SURFACE),
-            mComposerClient(), mSurfaceControl(), mOutputSurface() {
-    }
-
-    virtual ~SRGBTest() {
-        if (mEglDisplay != EGL_NO_DISPLAY) {
-            if (mEglSurface != EGL_NO_SURFACE) {
-                eglDestroySurface(mEglDisplay, mEglSurface);
-            }
-            if (mEglContext != EGL_NO_CONTEXT) {
-                eglDestroyContext(mEglDisplay, mEglContext);
-            }
-            eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
-                    EGL_NO_CONTEXT);
-            eglTerminate(mEglDisplay);
-        }
-    }
-
-    virtual void SetUp() {
-        sp<IGraphicBufferProducer> producer;
-        sp<IGraphicBufferConsumer> consumer;
-        BufferQueue::createBufferQueue(&producer, &consumer);
-        ASSERT_EQ(NO_ERROR, consumer->setDefaultBufferSize(
-                DISPLAY_WIDTH, DISPLAY_HEIGHT));
-        mCpuConsumer = new CpuConsumer(consumer, 1);
-        String8 name("CpuConsumer_for_SRGBTest");
-        mCpuConsumer->setName(name);
-        mInputSurface = new Surface(producer);
-
-        ASSERT_NO_FATAL_FAILURE(createEGLSurface(mInputSurface.get()));
-        ASSERT_NO_FATAL_FAILURE(createDebugSurface());
-    }
-
-    virtual void TearDown() {
-        ASSERT_NO_FATAL_FAILURE(copyToDebugSurface());
-        ASSERT_TRUE(mLockedBuffer.data != NULL);
-        ASSERT_EQ(NO_ERROR, mCpuConsumer->unlockBuffer(mLockedBuffer));
-    }
-
-    static float linearToSRGB(float l) {
-        if (l <= 0.0031308f) {
-            return l * 12.92f;
-        } else {
-            return 1.055f * pow(l, (1 / 2.4f)) - 0.055f;
-        }
-    }
-
-    static float srgbToLinear(float s) {
-        if (s <= 0.04045) {
-            return s / 12.92f;
-        } else {
-            return pow(((s + 0.055f) / 1.055f), 2.4f);
-        }
-    }
-
-    static uint8_t srgbToLinear(uint8_t u) {
-        float f = u / 255.0f;
-        return static_cast<uint8_t>(srgbToLinear(f) * 255.0f + 0.5f);
-    }
-
-    void fillTexture(bool writeAsSRGB) {
-        uint8_t* textureData = new uint8_t[DISPLAY_SIZE];
-
-        for (int y = 0; y < DISPLAY_HEIGHT; ++y) {
-            for (int x = 0; x < DISPLAY_WIDTH; ++x) {
-                float realValue = static_cast<float>(x) / (DISPLAY_WIDTH - 1);
-                realValue *= ALPHA_VALUE / 255.0f; // Premultiply by alpha
-                if (writeAsSRGB) {
-                    realValue = linearToSRGB(realValue);
-                }
-
-                int offset = (y * DISPLAY_WIDTH + x) * PIXEL_SIZE;
-                for (int c = 0; c < 3; ++c) {
-                    uint8_t intValue = static_cast<uint8_t>(
-                            realValue * 255.0f + 0.5f);
-                    textureData[offset + c] = intValue;
-                }
-                textureData[offset + 3] = ALPHA_VALUE;
-            }
-        }
-
-        glTexImage2D(GL_TEXTURE_2D, 0, writeAsSRGB ? GL_SRGB8_ALPHA8 : GL_RGBA8,
-                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE,
-                textureData);
-        ASSERT_EQ(GL_NO_ERROR, glGetError());
-
-        delete[] textureData;
-    }
-
-    void initShaders() {
-        static const char vertexSource[] =
-            "attribute vec4 vPosition;\n"
-            "varying vec2 texCoords;\n"
-            "void main() {\n"
-            "  texCoords = 0.5 * (vPosition.xy + vec2(1.0, 1.0));\n"
-            "  gl_Position = vPosition;\n"
-            "}\n";
-
-        static const char fragmentSource[] =
-            "precision mediump float;\n"
-            "uniform sampler2D texSampler;\n"
-            "varying vec2 texCoords;\n"
-            "void main() {\n"
-            "  gl_FragColor = texture2D(texSampler, texCoords);\n"
-            "}\n";
-
-        GLuint program;
-        {
-            SCOPED_TRACE("Creating shader program");
-            ASSERT_NO_FATAL_FAILURE(GLTest::createProgram(
-                    vertexSource, fragmentSource, &program));
-        }
-
-        GLint positionHandle = glGetAttribLocation(program, "vPosition");
-        ASSERT_EQ(GL_NO_ERROR, glGetError());
-        ASSERT_NE(-1, positionHandle);
-
-        GLint samplerHandle = glGetUniformLocation(program, "texSampler");
-        ASSERT_EQ(GL_NO_ERROR, glGetError());
-        ASSERT_NE(-1, samplerHandle);
-
-        static const GLfloat vertices[] = {
-            -1.0f, 1.0f,
-            -1.0f, -1.0f,
-            1.0f, -1.0f,
-            1.0f, 1.0f,
-        };
-
-        glVertexAttribPointer(positionHandle, 2, GL_FLOAT, GL_FALSE, 0, vertices);
-        ASSERT_EQ(GL_NO_ERROR, glGetError());
-        glEnableVertexAttribArray(positionHandle);
-        ASSERT_EQ(GL_NO_ERROR, glGetError());
-
-        glUseProgram(program);
-        ASSERT_EQ(GL_NO_ERROR, glGetError());
-        glUniform1i(samplerHandle, 0);
-        ASSERT_EQ(GL_NO_ERROR, glGetError());
-
-        GLuint textureHandle;
-        glGenTextures(1, &textureHandle);
-        ASSERT_EQ(GL_NO_ERROR, glGetError());
-        glBindTexture(GL_TEXTURE_2D, textureHandle);
-        ASSERT_EQ(GL_NO_ERROR, glGetError());
-
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-        ASSERT_EQ(GL_NO_ERROR, glGetError());
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-        ASSERT_EQ(GL_NO_ERROR, glGetError());
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-        ASSERT_EQ(GL_NO_ERROR, glGetError());
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-        ASSERT_EQ(GL_NO_ERROR, glGetError());
-    }
-
-    void drawTexture(bool asSRGB, GLint x, GLint y, GLsizei width,
-            GLsizei height) {
-        ASSERT_NO_FATAL_FAILURE(fillTexture(asSRGB));
-        glViewport(x, y, width, height);
-        ASSERT_EQ(GL_NO_ERROR, glGetError());
-        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-        ASSERT_EQ(GL_NO_ERROR, glGetError());
-    }
-
-    void checkLockedBuffer(PixelFormat format, android_dataspace dataSpace) {
-        ASSERT_EQ(mLockedBuffer.format, format);
-        ASSERT_EQ(mLockedBuffer.width, DISPLAY_WIDTH);
-        ASSERT_EQ(mLockedBuffer.height, DISPLAY_HEIGHT);
-        ASSERT_EQ(mLockedBuffer.dataSpace, dataSpace);
-    }
-
-    static bool withinTolerance(int a, int b) {
-        int diff = a - b;
-        return diff >= 0 ? diff <= TOLERANCE : -diff <= TOLERANCE;
-    }
-
-    // Primary producer and consumer
-    sp<Surface> mInputSurface;
-    sp<CpuConsumer> mCpuConsumer;
-    CpuConsumer::LockedBuffer mLockedBuffer;
-
-    EGLDisplay mEglDisplay;
-    EGLConfig mEglConfig;
-    EGLContext mEglContext;
-    EGLSurface mEglSurface;
-
-    // Auxiliary display output
-    sp<SurfaceComposerClient> mComposerClient;
-    sp<SurfaceControl> mSurfaceControl;
-    sp<Surface> mOutputSurface;
-
-private:
-    void createEGLSurface(Surface* inputSurface) {
-        mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-        ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
-
-        EXPECT_TRUE(eglInitialize(mEglDisplay, NULL, NULL));
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
-        static const EGLint configAttribs[] = {
-            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
-            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
-            EGL_RED_SIZE, 8,
-            EGL_GREEN_SIZE, 8,
-            EGL_BLUE_SIZE, 8,
-            EGL_ALPHA_SIZE, 8,
-            EGL_NONE };
-
-        EGLint numConfigs = 0;
-        EXPECT_TRUE(eglChooseConfig(mEglDisplay, configAttribs, &mEglConfig, 1,
-                &numConfigs));
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-        ASSERT_GT(numConfigs, 0);
-
-        static const EGLint contextAttribs[] = {
-            EGL_CONTEXT_CLIENT_VERSION, 3,
-            EGL_NONE } ;
-
-        mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT,
-                contextAttribs);
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-        ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
-
-        mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig,
-                inputSurface, NULL);
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-        ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
-
-        EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
-                mEglContext));
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-    }
-
-    void createDebugSurface() {
-        if (getenv(SHOW_DEBUG_STRING) == NULL) return;
-
-        mComposerClient = new SurfaceComposerClient;
-        ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
-
-        mSurfaceControl = mComposerClient->createSurface(
-                String8("SRGBTest Surface"), DISPLAY_WIDTH, DISPLAY_HEIGHT,
-                PIXEL_FORMAT_RGBA_8888);
-
-        ASSERT_TRUE(mSurfaceControl != NULL);
-        ASSERT_TRUE(mSurfaceControl->isValid());
-
-        SurfaceComposerClient::openGlobalTransaction();
-        ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF));
-        ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
-        SurfaceComposerClient::closeGlobalTransaction();
-
-        ANativeWindow_Buffer outBuffer;
-        ARect inOutDirtyBounds;
-        mOutputSurface = mSurfaceControl->getSurface();
-        mOutputSurface->lock(&outBuffer, &inOutDirtyBounds);
-        uint8_t* bytePointer = reinterpret_cast<uint8_t*>(outBuffer.bits);
-        for (int y = 0; y < outBuffer.height; ++y) {
-            int rowOffset = y * outBuffer.stride; // pixels
-            for (int x = 0; x < outBuffer.width; ++x) {
-                int colOffset = (rowOffset + x) * PIXEL_SIZE; // bytes
-                for (int c = 0; c < PIXEL_SIZE; ++c) {
-                    int offset = colOffset + c;
-                    bytePointer[offset] = ((c + 1) * 56) - 1;
-                }
-            }
-        }
-        mOutputSurface->unlockAndPost();
-    }
-
-    void copyToDebugSurface() {
-        if (!mOutputSurface.get()) return;
-
-        size_t bufferSize = mLockedBuffer.height * mLockedBuffer.stride *
-                PIXEL_SIZE;
-
-        ANativeWindow_Buffer outBuffer;
-        ARect outBufferBounds;
-        mOutputSurface->lock(&outBuffer, &outBufferBounds);
-        ASSERT_EQ(mLockedBuffer.width, static_cast<uint32_t>(outBuffer.width));
-        ASSERT_EQ(mLockedBuffer.height, static_cast<uint32_t>(outBuffer.height));
-        ASSERT_EQ(mLockedBuffer.stride, static_cast<uint32_t>(outBuffer.stride));
-
-        if (mLockedBuffer.format == outBuffer.format) {
-            memcpy(outBuffer.bits, mLockedBuffer.data, bufferSize);
-        } else {
-            ASSERT_EQ(mLockedBuffer.format, PIXEL_FORMAT_RGBA_8888);
-            ASSERT_EQ(mLockedBuffer.dataSpace, HAL_DATASPACE_SRGB);
-            ASSERT_EQ(outBuffer.format, PIXEL_FORMAT_RGBA_8888);
-            uint8_t* outPointer = reinterpret_cast<uint8_t*>(outBuffer.bits);
-            for (int y = 0; y < outBuffer.height; ++y) {
-                int rowOffset = y * outBuffer.stride; // pixels
-                for (int x = 0; x < outBuffer.width; ++x) {
-                    int colOffset = (rowOffset + x) * PIXEL_SIZE; // bytes
-
-                    // RGB are converted
-                    for (int c = 0; c < (PIXEL_SIZE - 1); ++c) {
-                        outPointer[colOffset + c] = srgbToLinear(
-                                mLockedBuffer.data[colOffset + c]);
-                    }
-
-                    // Alpha isn't converted
-                    outPointer[colOffset + 3] =
-                            mLockedBuffer.data[colOffset + 3];
-                }
-            }
-        }
-        mOutputSurface->unlockAndPost();
-
-        int sleepSeconds = atoi(getenv(SHOW_DEBUG_STRING));
-        sleep(sleepSeconds);
-    }
-};
-
-const char SRGBTest::SHOW_DEBUG_STRING[] = "DEBUG_OUTPUT_SECONDS";
-
-TEST_F(SRGBTest, GLRenderFromSRGBTexture) {
-    ASSERT_NO_FATAL_FAILURE(initShaders());
-
-    // The RGB texture is displayed in the top half
-    ASSERT_NO_FATAL_FAILURE(drawTexture(false, 0, DISPLAY_HEIGHT / 2,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT / 2));
-
-    // The SRGB texture is displayed in the bottom half
-    ASSERT_NO_FATAL_FAILURE(drawTexture(true, 0, 0,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT / 2));
-
-    eglSwapBuffers(mEglDisplay, mEglSurface);
-    ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
-    // Lock
-    ASSERT_EQ(NO_ERROR, mCpuConsumer->lockNextBuffer(&mLockedBuffer));
-    ASSERT_NO_FATAL_FAILURE(
-        checkLockedBuffer(PIXEL_FORMAT_RGBA_8888, HAL_DATASPACE_UNKNOWN));
-
-    // Compare a pixel in the middle of each texture
-    int midSRGBOffset = (DISPLAY_HEIGHT / 4) * mLockedBuffer.stride *
-            PIXEL_SIZE;
-    int midRGBOffset = midSRGBOffset * 3;
-    midRGBOffset += (DISPLAY_WIDTH / 2) * PIXEL_SIZE;
-    midSRGBOffset += (DISPLAY_WIDTH / 2) * PIXEL_SIZE;
-    for (int c = 0; c < PIXEL_SIZE; ++c) {
-        int expectedValue = mLockedBuffer.data[midRGBOffset + c];
-        int actualValue = mLockedBuffer.data[midSRGBOffset + c];
-        ASSERT_PRED2(withinTolerance, expectedValue, actualValue);
-    }
-
-    // mLockedBuffer is unlocked in TearDown so we can copy data from it to
-    // the debug surface if necessary
-}
-
-// XXX: Disabled since we don't currently expect this to work
-TEST_F(SRGBTest, DISABLED_RenderToSRGBSurface) {
-    ASSERT_NO_FATAL_FAILURE(initShaders());
-
-    // By default, the first buffer we write into will be RGB
-
-    // Render an RGB texture across the whole surface
-    ASSERT_NO_FATAL_FAILURE(drawTexture(false, 0, 0,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT));
-    eglSwapBuffers(mEglDisplay, mEglSurface);
-    ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
-    // Lock
-    ASSERT_EQ(NO_ERROR, mCpuConsumer->lockNextBuffer(&mLockedBuffer));
-    ASSERT_NO_FATAL_FAILURE(
-        checkLockedBuffer(PIXEL_FORMAT_RGBA_8888, HAL_DATASPACE_UNKNOWN));
-
-    // Save the values of the middle pixel for later comparison against SRGB
-    uint8_t values[PIXEL_SIZE] = {};
-    int middleOffset = (DISPLAY_HEIGHT / 2) * mLockedBuffer.stride *
-            PIXEL_SIZE;
-    middleOffset += (DISPLAY_WIDTH / 2) * PIXEL_SIZE;
-    for (int c = 0; c < PIXEL_SIZE; ++c) {
-        values[c] = mLockedBuffer.data[middleOffset + c];
-    }
-
-    // Unlock
-    ASSERT_EQ(NO_ERROR, mCpuConsumer->unlockBuffer(mLockedBuffer));
-
-    // Switch to SRGB window surface
-#define EGL_GL_COLORSPACE_KHR      EGL_VG_COLORSPACE
-#define EGL_GL_COLORSPACE_SRGB_KHR EGL_VG_COLORSPACE_sRGB
-
-    static const int srgbAttribs[] = {
-        EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR,
-        EGL_NONE,
-    };
-
-    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
-            mEglContext));
-    ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
-    EXPECT_TRUE(eglDestroySurface(mEglDisplay, mEglSurface));
-    ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
-    mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig,
-            mInputSurface.get(), srgbAttribs);
-    ASSERT_EQ(EGL_SUCCESS, eglGetError());
-    ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
-
-    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
-            mEglContext));
-    ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
-    // Render the texture again
-    ASSERT_NO_FATAL_FAILURE(drawTexture(false, 0, 0,
-            DISPLAY_WIDTH, DISPLAY_HEIGHT));
-    eglSwapBuffers(mEglDisplay, mEglSurface);
-    ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
-    // Lock
-    ASSERT_EQ(NO_ERROR, mCpuConsumer->lockNextBuffer(&mLockedBuffer));
-
-    // Make sure we actually got the SRGB buffer on the consumer side
-    ASSERT_NO_FATAL_FAILURE(
-        checkLockedBuffer(PIXEL_FORMAT_RGBA_8888, HAL_DATASPACE_SRGB));
-
-    // Verify that the stored value is the same, accounting for RGB/SRGB
-    for (int c = 0; c < PIXEL_SIZE; ++c) {
-        // The alpha value should be equivalent before linear->SRGB
-        float rgbAsSRGB = (c == 3) ? values[c] / 255.0f :
-                linearToSRGB(values[c] / 255.0f);
-        int expectedValue = rgbAsSRGB * 255.0f + 0.5f;
-        int actualValue = mLockedBuffer.data[middleOffset + c];
-        ASSERT_PRED2(withinTolerance, expectedValue, actualValue);
-    }
-
-    // mLockedBuffer is unlocked in TearDown so we can copy data from it to
-    // the debug surface if necessary
-}
-
-} // namespace android
diff --git a/libs/gui/tests/StreamSplitter_test.cpp b/libs/gui/tests/StreamSplitter_test.cpp
index 498492e..80e30da 100644
--- a/libs/gui/tests/StreamSplitter_test.cpp
+++ b/libs/gui/tests/StreamSplitter_test.cpp
@@ -81,7 +81,7 @@
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
             inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-                    GRALLOC_USAGE_SW_WRITE_OFTEN));
+                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
     ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer));
 
     uint32_t* dataIn;
@@ -115,7 +115,7 @@
     // received the buffer back from the output BufferQueue
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
             inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-                    GRALLOC_USAGE_SW_WRITE_OFTEN));
+                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
 }
 
 TEST_F(StreamSplitterTest, OneInputMultipleOutputs) {
@@ -153,7 +153,7 @@
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
             inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-                    GRALLOC_USAGE_SW_WRITE_OFTEN));
+                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
     ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer));
 
     uint32_t* dataIn;
@@ -190,7 +190,7 @@
     // received the buffer back from the output BufferQueues
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
             inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-                    GRALLOC_USAGE_SW_WRITE_OFTEN));
+                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
 }
 
 TEST_F(StreamSplitterTest, OutputAbandonment) {
@@ -217,7 +217,7 @@
     sp<GraphicBuffer> buffer;
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
             inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-                    GRALLOC_USAGE_SW_WRITE_OFTEN));
+                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
     ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer));
 
     // Abandon the output
@@ -230,7 +230,7 @@
 
     // Input should be abandoned
     ASSERT_EQ(NO_INIT, inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
-            GRALLOC_USAGE_SW_WRITE_OFTEN));
+            GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
 }
 
 } // namespace android
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index a1578f6..bd598e4 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -23,6 +23,7 @@
 #include <gtest/gtest.h>
 #include <gui/GLConsumer.h>
 #include <gui/Surface.h>
+#include <gui/BufferQueue.h>
 #include <system/graphics.h>
 #include <utils/Log.h>
 #include <utils/Thread.h>
@@ -535,7 +536,7 @@
             return false;
         }
     public:
-        MyThread(const sp<GLConsumer>& mST)
+        explicit MyThread(const sp<GLConsumer>& mST)
             : mST(mST), mBufferRetired(false) {
             ctx = eglGetCurrentContext();
             sur = eglGetCurrentSurface(EGL_DRAW);
diff --git a/libs/gui/tests/SurfaceTextureFBO_test.cpp b/libs/gui/tests/SurfaceTextureFBO_test.cpp
index 0606839..0134273 100644
--- a/libs/gui/tests/SurfaceTextureFBO_test.cpp
+++ b/libs/gui/tests/SurfaceTextureFBO_test.cpp
@@ -41,7 +41,7 @@
             &anb));
     ASSERT_TRUE(anb != NULL);
 
-    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+    sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
     // Fill the buffer with green
     uint8_t* img = NULL;
@@ -65,7 +65,7 @@
                 &anb));
         ASSERT_TRUE(anb != NULL);
 
-        buf = new GraphicBuffer(anb, false);
+        buf = GraphicBuffer::from(anb);
 
         // Fill the buffer with red
         ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN,
diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp
index 5311c59..c6745d0 100644
--- a/libs/gui/tests/SurfaceTextureGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGL_test.cpp
@@ -42,7 +42,7 @@
             &anb));
     ASSERT_TRUE(anb != NULL);
 
-    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+    sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
     // Fill the buffer with the a checkerboard pattern
     uint8_t* img = NULL;
@@ -92,7 +92,7 @@
             &anb));
     ASSERT_TRUE(anb != NULL);
 
-    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+    sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
     // Fill the buffer with the a checkerboard pattern
     uint8_t* img = NULL;
@@ -157,7 +157,7 @@
                 &anb));
         ASSERT_TRUE(anb != NULL);
 
-        sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+        sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
         uint8_t* img = NULL;
         buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
@@ -238,7 +238,7 @@
                     return false;
                 }
 
-                sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+                sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
                 const int yuvTexOffsetY = 0;
                 int stride = buf->getStride();
@@ -437,7 +437,7 @@
 
     class ProducerThread : public Thread {
     public:
-        ProducerThread(const sp<ANativeWindow>& anw):
+        explicit ProducerThread(const sp<ANativeWindow>& anw):
                 mANW(anw) {
         }
 
@@ -620,7 +620,7 @@
 TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) {
     class ProducerThread : public Thread {
     public:
-        ProducerThread(const sp<ANativeWindow>& anw):
+        explicit ProducerThread(const sp<ANativeWindow>& anw):
                 mANW(anw),
                 mDequeueError(NO_ERROR) {
         }
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 0de60c9..e18af17 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -18,19 +18,38 @@
 
 #include <gtest/gtest.h>
 
-#include <binder/IMemory.h>
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <binder/ProcessState.h>
+#include <configstore/Utils.h>
+#include <cutils/properties.h>
+#include <gui/BufferItemConsumer.h>
+#include <gui/IDisplayEventConnection.h>
+#include <gui/IProducerListener.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
-#include <gui/BufferItemConsumer.h>
+#include <private/gui/ComposerService.h>
 #include <ui/Rect.h>
 #include <utils/String8.h>
 
-#include <private/gui/ComposerService.h>
-#include <binder/ProcessState.h>
+#include <limits>
+#include <thread>
 
 namespace android {
 
+using namespace std::chrono_literals;
+// retrieve wide-color and hdr settings from configstore
+using namespace android::hardware::configstore;
+using namespace android::hardware::configstore::V1_0;
+
+static bool hasWideColorDisplay =
+        getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
+
+class FakeSurfaceComposer;
+class FakeProducerFrameEventHistory;
+
+static constexpr uint64_t NO_FRAME_INDEX = std::numeric_limits<uint64_t>::max();
+
 class SurfaceTest : public ::testing::Test {
 protected:
 
@@ -42,6 +61,8 @@
         mComposerClient = new SurfaceComposerClient;
         ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
 
+        // TODO(brianderson): The following sometimes fails and is a source of
+        //   test flakiness.
         mSurfaceControl = mComposerClient->createSurface(
                 String8("Test Surface"), 32, 32, PIXEL_FORMAT_RGBA_8888, 0);
 
@@ -77,6 +98,8 @@
 
 TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenPurgatorized) {
     mSurfaceControl.clear();
+    // Wait for the async clean-up to complete.
+    std::this_thread::sleep_for(50ms);
 
     sp<ANativeWindow> anw(mSurface);
     int result = -123;
@@ -96,7 +119,8 @@
     BufferQueue::createBufferQueue(&producer, &consumer);
     sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-    sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+    sp<IBinder> display(sf->getBuiltInDisplay(
+            ISurfaceComposer::eDisplayIdMain));
     ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(),
             64, 64, 0, 0x7fffffff, false));
 
@@ -140,6 +164,14 @@
     EXPECT_EQ(NATIVE_WINDOW_SURFACE, result);
 }
 
+TEST_F(SurfaceTest, LayerCountIsOne) {
+    sp<ANativeWindow> anw(mSurface);
+    int result = -123;
+    int err = anw->query(anw.get(), NATIVE_WINDOW_LAYER_COUNT, &result);
+    EXPECT_EQ(NO_ERROR, err);
+    EXPECT_EQ(1, result);
+}
+
 TEST_F(SurfaceTest, QueryConsumerUsage) {
     const int TEST_USAGE_FLAGS =
             GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER;
@@ -232,6 +264,37 @@
     EXPECT_STREQ("TestConsumer", surface->getConsumerName().string());
 }
 
+TEST_F(SurfaceTest, GetWideColorSupport) {
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+
+    sp<DummyConsumer> dummyConsumer(new DummyConsumer);
+    consumer->consumerConnect(dummyConsumer, false);
+    consumer->setConsumerName(String8("TestConsumer"));
+
+    sp<Surface> surface = new Surface(producer);
+    sp<ANativeWindow> window(surface);
+    native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU);
+
+    bool supported;
+    surface->getWideColorSupport(&supported);
+
+    // NOTE: This test assumes that device that supports
+    // wide-color (as indicated by BoardConfig) must also
+    // have a wide-color primary display.
+    // That assumption allows this test to cover devices
+    // that advertised a wide-color color mode without
+    // actually supporting wide-color to pass this test
+    // as well as the case of a device that does support
+    // wide-color (via BoardConfig) and has a wide-color
+    // primary display.
+    // NOT covered at this time is a device that supports
+    // wide color in the BoardConfig but does not support
+    // a wide-color color mode on the primary display.
+    ASSERT_EQ(hasWideColorDisplay, supported);
+}
+
 TEST_F(SurfaceTest, DynamicSetBufferCount) {
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
@@ -258,4 +321,1268 @@
     ASSERT_EQ(NO_ERROR, window->queueBuffer(window.get(), buffer, fence));
 }
 
+TEST_F(SurfaceTest, GetAndFlushRemovedBuffers) {
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+
+    sp<DummyConsumer> dummyConsumer(new DummyConsumer);
+    consumer->consumerConnect(dummyConsumer, false);
+    consumer->setConsumerName(String8("TestConsumer"));
+
+    sp<Surface> surface = new Surface(producer);
+    sp<ANativeWindow> window(surface);
+    sp<DummyProducerListener> listener = new DummyProducerListener();
+    ASSERT_EQ(OK, surface->connect(
+            NATIVE_WINDOW_API_CPU,
+            /*listener*/listener,
+            /*reportBufferRemoval*/true));
+    const int BUFFER_COUNT = 4;
+    ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(window.get(), BUFFER_COUNT));
+
+    sp<GraphicBuffer> detachedBuffer;
+    sp<Fence> outFence;
+    int fences[BUFFER_COUNT];
+    ANativeWindowBuffer* buffers[BUFFER_COUNT];
+    // Allocate buffers because detachNextBuffer requires allocated buffers
+    for (int i = 0; i < BUFFER_COUNT; i++) {
+        ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffers[i], &fences[i]));
+    }
+    for (int i = 0; i < BUFFER_COUNT; i++) {
+        ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffers[i], fences[i]));
+    }
+
+    // Test detached buffer is correctly reported
+    ASSERT_EQ(NO_ERROR, surface->detachNextBuffer(&detachedBuffer, &outFence));
+    std::vector<sp<GraphicBuffer>> removedBuffers;
+    ASSERT_EQ(OK, surface->getAndFlushRemovedBuffers(&removedBuffers));
+    ASSERT_EQ(1u, removedBuffers.size());
+    ASSERT_EQ(detachedBuffer->handle, removedBuffers.at(0)->handle);
+    // Test the list is flushed one getAndFlushRemovedBuffers returns
+    ASSERT_EQ(OK, surface->getAndFlushRemovedBuffers(&removedBuffers));
+    ASSERT_EQ(0u, removedBuffers.size());
+
+
+    // Test removed buffer list is cleanup after next dequeueBuffer call
+    ASSERT_EQ(NO_ERROR, surface->detachNextBuffer(&detachedBuffer, &outFence));
+    ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffers[0], &fences[0]));
+    ASSERT_EQ(OK, surface->getAndFlushRemovedBuffers(&removedBuffers));
+    ASSERT_EQ(0u, removedBuffers.size());
+    ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffers[0], fences[0]));
+
+    // Test removed buffer list is cleanup after next detachNextBuffer call
+    ASSERT_EQ(NO_ERROR, surface->detachNextBuffer(&detachedBuffer, &outFence));
+    ASSERT_EQ(NO_ERROR, surface->detachNextBuffer(&detachedBuffer, &outFence));
+    ASSERT_EQ(OK, surface->getAndFlushRemovedBuffers(&removedBuffers));
+    ASSERT_EQ(1u, removedBuffers.size());
+    ASSERT_EQ(detachedBuffer->handle, removedBuffers.at(0)->handle);
+
+    // Re-allocate buffers since all buffers are detached up to now
+    for (int i = 0; i < BUFFER_COUNT; i++) {
+        ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffers[i], &fences[i]));
+    }
+    for (int i = 0; i < BUFFER_COUNT; i++) {
+        ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffers[i], fences[i]));
+    }
+
+    ASSERT_EQ(NO_ERROR, surface->detachNextBuffer(&detachedBuffer, &outFence));
+    ASSERT_EQ(NO_ERROR, surface->attachBuffer(detachedBuffer.get()));
+    ASSERT_EQ(OK, surface->getAndFlushRemovedBuffers(&removedBuffers));
+    // Depends on which slot GraphicBufferProducer impl pick, the attach call might
+    // get 0 or 1 buffer removed.
+    ASSERT_LE(removedBuffers.size(), 1u);
 }
+
+TEST_F(SurfaceTest, TestGetLastDequeueStartTime) {
+    sp<ANativeWindow> anw(mSurface);
+    ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(), NATIVE_WINDOW_API_CPU));
+
+    ANativeWindowBuffer* buffer = nullptr;
+    int32_t fenceFd = -1;
+
+    nsecs_t before = systemTime(CLOCK_MONOTONIC);
+    anw->dequeueBuffer(anw.get(), &buffer, &fenceFd);
+    nsecs_t after = systemTime(CLOCK_MONOTONIC);
+
+    nsecs_t lastDequeueTime = mSurface->getLastDequeueStartTime();
+    ASSERT_LE(before, lastDequeueTime);
+    ASSERT_GE(after, lastDequeueTime);
+}
+
+class FakeConsumer : public BnConsumerListener {
+public:
+    void onFrameAvailable(const BufferItem& /*item*/) override {}
+    void onBuffersReleased() override {}
+    void onSidebandStreamChanged() override {}
+
+    void addAndGetFrameTimestamps(
+            const NewFrameEventsEntry* newTimestamps,
+            FrameEventHistoryDelta* outDelta) override {
+        if (newTimestamps) {
+            if (mGetFrameTimestampsEnabled) {
+                EXPECT_GT(mNewFrameEntryOverride.frameNumber, 0u) <<
+                        "Test should set mNewFrameEntryOverride before queuing "
+                        "a frame.";
+                EXPECT_EQ(newTimestamps->frameNumber,
+                        mNewFrameEntryOverride.frameNumber) <<
+                        "Test attempting to add NewFrameEntryOverride with "
+                        "incorrect frame number.";
+                mFrameEventHistory.addQueue(mNewFrameEntryOverride);
+                mNewFrameEntryOverride.frameNumber = 0;
+            }
+            mAddFrameTimestampsCount++;
+            mLastAddedFrameNumber = newTimestamps->frameNumber;
+        }
+        if (outDelta) {
+            mFrameEventHistory.getAndResetDelta(outDelta);
+            mGetFrameTimestampsCount++;
+        }
+        mAddAndGetFrameTimestampsCallCount++;
+    }
+
+    bool mGetFrameTimestampsEnabled = false;
+
+    ConsumerFrameEventHistory mFrameEventHistory;
+    int mAddAndGetFrameTimestampsCallCount = 0;
+    int mAddFrameTimestampsCount = 0;
+    int mGetFrameTimestampsCount = 0;
+    uint64_t mLastAddedFrameNumber = NO_FRAME_INDEX;
+
+    NewFrameEventsEntry mNewFrameEntryOverride = { 0, 0, 0, nullptr };
+};
+
+
+class FakeSurfaceComposer : public ISurfaceComposer{
+public:
+    ~FakeSurfaceComposer() override {}
+
+    void setSupportsPresent(bool supportsPresent) {
+        mSupportsPresent = supportsPresent;
+    }
+
+    sp<ISurfaceComposerClient> createConnection() override { return nullptr; }
+    sp<ISurfaceComposerClient> createScopedConnection(
+            const sp<IGraphicBufferProducer>& /* parent */) override {
+        return nullptr;
+    }
+    sp<IDisplayEventConnection> createDisplayEventConnection(ISurfaceComposer::VsyncSource)
+            override {
+        return nullptr;
+    }
+    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; }
+    void setTransactionState(const Vector<ComposerState>& /*state*/,
+            const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/)
+            override {}
+    void bootFinished() override {}
+    bool authenticateSurfaceTexture(
+            const sp<IGraphicBufferProducer>& /*surface*/) const override {
+        return false;
+    }
+
+    status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported)
+            const override {
+        *outSupported = {
+                FrameEvent::REQUESTED_PRESENT,
+                FrameEvent::ACQUIRE,
+                FrameEvent::LATCH,
+                FrameEvent::FIRST_REFRESH_START,
+                FrameEvent::LAST_REFRESH_START,
+                FrameEvent::GPU_COMPOSITION_DONE,
+                FrameEvent::DEQUEUE_READY,
+                FrameEvent::RELEASE
+        };
+        if (mSupportsPresent) {
+            outSupported->push_back(
+                        FrameEvent::DISPLAY_PRESENT);
+        }
+        return NO_ERROR;
+    }
+
+    void setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override {}
+    status_t getDisplayConfigs(const sp<IBinder>& /*display*/,
+            Vector<DisplayInfo>* /*configs*/) override { return NO_ERROR; }
+    status_t getDisplayStats(const sp<IBinder>& /*display*/,
+            DisplayStatInfo* /*stats*/) override { return NO_ERROR; }
+    int getActiveConfig(const sp<IBinder>& /*display*/) override { return 0; }
+    status_t setActiveConfig(const sp<IBinder>& /*display*/, int /*id*/)
+            override {
+        return NO_ERROR;
+    }
+    status_t getDisplayColorModes(const sp<IBinder>& /*display*/,
+            Vector<android_color_mode_t>* /*outColorModes*/) override {
+        return NO_ERROR;
+    }
+    android_color_mode_t getActiveColorMode(const sp<IBinder>& /*display*/)
+            override {
+        return HAL_COLOR_MODE_NATIVE;
+    }
+    status_t setActiveColorMode(const sp<IBinder>& /*display*/,
+            android_color_mode_t /*colorMode*/) override { return NO_ERROR; }
+    status_t captureScreen(const sp<IBinder>& /*display*/,
+            const sp<IGraphicBufferProducer>& /*producer*/,
+            Rect /*sourceCrop*/, uint32_t /*reqWidth*/, uint32_t /*reqHeight*/,
+            int32_t /*minLayerZ*/, int32_t /*maxLayerZ*/,
+            bool /*useIdentityTransform*/,
+            Rotation /*rotation*/) override { return NO_ERROR; }
+    status_t clearAnimationFrameStats() override { return NO_ERROR; }
+    status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override {
+        return NO_ERROR;
+    }
+    status_t getHdrCapabilities(const sp<IBinder>& /*display*/,
+            HdrCapabilities* /*outCapabilities*/) const override {
+        return NO_ERROR;
+    }
+    status_t enableVSyncInjections(bool /*enable*/) override {
+        return NO_ERROR;
+    }
+    status_t injectVSync(nsecs_t /*when*/) override { return NO_ERROR; }
+
+protected:
+    IBinder* onAsBinder() override { return nullptr; }
+
+private:
+    bool mSupportsPresent{true};
+};
+
+class FakeProducerFrameEventHistory : public ProducerFrameEventHistory {
+public:
+    FakeProducerFrameEventHistory(FenceToFenceTimeMap* fenceMap)
+        : mFenceMap(fenceMap) {}
+
+    ~FakeProducerFrameEventHistory() {}
+
+    void updateAcquireFence(uint64_t frameNumber,
+            std::shared_ptr<FenceTime>&& acquire) override {
+        // Verify the acquire fence being added isn't the one from the consumer.
+        EXPECT_NE(mConsumerAcquireFence, acquire);
+        // Override the fence, so we can verify this was called by the
+        // producer after the frame is queued.
+        ProducerFrameEventHistory::updateAcquireFence(frameNumber,
+                std::shared_ptr<FenceTime>(mAcquireFenceOverride));
+    }
+
+    void setAcquireFenceOverride(
+            const std::shared_ptr<FenceTime>& acquireFenceOverride,
+            const std::shared_ptr<FenceTime>& consumerAcquireFence) {
+        mAcquireFenceOverride = acquireFenceOverride;
+        mConsumerAcquireFence = consumerAcquireFence;
+    }
+
+protected:
+    std::shared_ptr<FenceTime> createFenceTime(const sp<Fence>& fence)
+            const override {
+        return mFenceMap->createFenceTimeForTest(fence);
+    }
+
+    FenceToFenceTimeMap* mFenceMap{nullptr};
+
+    std::shared_ptr<FenceTime> mAcquireFenceOverride{FenceTime::NO_FENCE};
+    std::shared_ptr<FenceTime> mConsumerAcquireFence{FenceTime::NO_FENCE};
+};
+
+
+class TestSurface : public Surface {
+public:
+    TestSurface(const sp<IGraphicBufferProducer>& bufferProducer,
+            FenceToFenceTimeMap* fenceMap)
+        : Surface(bufferProducer),
+          mFakeSurfaceComposer(new FakeSurfaceComposer) {
+        mFakeFrameEventHistory = new FakeProducerFrameEventHistory(fenceMap);
+        mFrameEventHistory.reset(mFakeFrameEventHistory);
+    }
+
+    ~TestSurface() override {}
+
+    sp<ISurfaceComposer> composerService() const override {
+        return mFakeSurfaceComposer;
+    }
+
+    nsecs_t now() const override {
+        return mNow;
+    }
+
+    void setNow(nsecs_t now) {
+        mNow = now;
+    }
+
+public:
+    sp<FakeSurfaceComposer> mFakeSurfaceComposer;
+    nsecs_t mNow = 0;
+
+    // mFrameEventHistory owns the instance of FakeProducerFrameEventHistory,
+    // but this raw pointer gives access to test functionality.
+    FakeProducerFrameEventHistory* mFakeFrameEventHistory;
+};
+
+
+class GetFrameTimestampsTest : public ::testing::Test {
+protected:
+    struct FenceAndFenceTime {
+        explicit FenceAndFenceTime(FenceToFenceTimeMap& fenceMap)
+           : mFence(new Fence),
+             mFenceTime(fenceMap.createFenceTimeForTest(mFence)) {}
+        sp<Fence> mFence { nullptr };
+        std::shared_ptr<FenceTime> mFenceTime { nullptr };
+    };
+
+    struct RefreshEvents {
+        RefreshEvents(FenceToFenceTimeMap& fenceMap, nsecs_t refreshStart)
+          : mFenceMap(fenceMap),
+            kCompositorTiming(
+                {refreshStart, refreshStart + 1, refreshStart + 2 }),
+            kStartTime(refreshStart + 3),
+            kGpuCompositionDoneTime(refreshStart + 4),
+            kPresentTime(refreshStart + 5) {}
+
+        void signalPostCompositeFences() {
+            mFenceMap.signalAllForTest(
+                        mGpuCompositionDone.mFence, kGpuCompositionDoneTime);
+            mFenceMap.signalAllForTest(mPresent.mFence, kPresentTime);
+        }
+
+        FenceToFenceTimeMap& mFenceMap;
+
+        FenceAndFenceTime mGpuCompositionDone { mFenceMap };
+        FenceAndFenceTime mPresent { mFenceMap };
+
+        const CompositorTiming kCompositorTiming;
+
+        const nsecs_t kStartTime;
+        const nsecs_t kGpuCompositionDoneTime;
+        const nsecs_t kPresentTime;
+    };
+
+    struct FrameEvents {
+        FrameEvents(FenceToFenceTimeMap& fenceMap, nsecs_t frameStartTime)
+            : mFenceMap(fenceMap),
+              kPostedTime(frameStartTime + 100),
+              kRequestedPresentTime(frameStartTime + 200),
+              kProducerAcquireTime(frameStartTime + 300),
+              kConsumerAcquireTime(frameStartTime + 301),
+              kLatchTime(frameStartTime + 500),
+              kDequeueReadyTime(frameStartTime + 600),
+              kReleaseTime(frameStartTime + 700),
+              mRefreshes {
+                    { mFenceMap, frameStartTime + 410 },
+                    { mFenceMap, frameStartTime + 420 },
+                    { mFenceMap, frameStartTime + 430 } } {}
+
+        void signalQueueFences() {
+            mFenceMap.signalAllForTest(
+                        mAcquireConsumer.mFence, kConsumerAcquireTime);
+            mFenceMap.signalAllForTest(
+                        mAcquireProducer.mFence, kProducerAcquireTime);
+        }
+
+        void signalRefreshFences() {
+            for (auto& re : mRefreshes) {
+                re.signalPostCompositeFences();
+            }
+        }
+
+        void signalReleaseFences() {
+            mFenceMap.signalAllForTest(mRelease.mFence, kReleaseTime);
+        }
+
+        FenceToFenceTimeMap& mFenceMap;
+
+        FenceAndFenceTime mAcquireConsumer { mFenceMap };
+        FenceAndFenceTime mAcquireProducer { mFenceMap };
+        FenceAndFenceTime mRelease { mFenceMap };
+
+        const nsecs_t kPostedTime;
+        const nsecs_t kRequestedPresentTime;
+        const nsecs_t kProducerAcquireTime;
+        const nsecs_t kConsumerAcquireTime;
+        const nsecs_t kLatchTime;
+        const nsecs_t kDequeueReadyTime;
+        const nsecs_t kReleaseTime;
+
+        RefreshEvents mRefreshes[3];
+    };
+
+    GetFrameTimestampsTest() {}
+
+    virtual void SetUp() {
+        BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+        mFakeConsumer = new FakeConsumer;
+        mCfeh = &mFakeConsumer->mFrameEventHistory;
+        mConsumer->consumerConnect(mFakeConsumer, false);
+        mConsumer->setConsumerName(String8("TestConsumer"));
+        mSurface = new TestSurface(mProducer, &mFenceMap);
+        mWindow = mSurface;
+
+        ASSERT_EQ(NO_ERROR, native_window_api_connect(mWindow.get(),
+                NATIVE_WINDOW_API_CPU));
+        native_window_set_buffer_count(mWindow.get(), 4);
+    }
+
+    void disableFrameTimestamps() {
+        mFakeConsumer->mGetFrameTimestampsEnabled = false;
+        native_window_enable_frame_timestamps(mWindow.get(), 0);
+        mFrameTimestampsEnabled = false;
+    }
+
+    void enableFrameTimestamps() {
+        mFakeConsumer->mGetFrameTimestampsEnabled = true;
+        native_window_enable_frame_timestamps(mWindow.get(), 1);
+        mFrameTimestampsEnabled = true;
+    }
+
+    int getAllFrameTimestamps(uint64_t frameId) {
+        return native_window_get_frame_timestamps(mWindow.get(), frameId,
+                &outRequestedPresentTime, &outAcquireTime, &outLatchTime,
+                &outFirstRefreshStartTime, &outLastRefreshStartTime,
+                &outGpuCompositionDoneTime, &outDisplayPresentTime,
+                &outDequeueReadyTime, &outReleaseTime);
+    }
+
+    void resetTimestamps() {
+        outRequestedPresentTime = -1;
+        outAcquireTime = -1;
+        outLatchTime = -1;
+        outFirstRefreshStartTime = -1;
+        outLastRefreshStartTime = -1;
+        outGpuCompositionDoneTime = -1;
+        outDisplayPresentTime = -1;
+        outDequeueReadyTime = -1;
+        outReleaseTime = -1;
+    }
+
+    uint64_t getNextFrameId() {
+        uint64_t frameId = -1;
+        int status = native_window_get_next_frame_id(mWindow.get(), &frameId);
+        EXPECT_EQ(status, NO_ERROR);
+        return frameId;
+    }
+
+    void dequeueAndQueue(uint64_t frameIndex) {
+        int fence = -1;
+        ANativeWindowBuffer* buffer = nullptr;
+        ASSERT_EQ(NO_ERROR,
+                mWindow->dequeueBuffer(mWindow.get(), &buffer, &fence));
+
+        int oldAddFrameTimestampsCount =
+                mFakeConsumer->mAddFrameTimestampsCount;
+
+        FrameEvents* frame = &mFrames[frameIndex];
+        uint64_t frameNumber = frameIndex + 1;
+
+        NewFrameEventsEntry fe;
+        fe.frameNumber = frameNumber;
+        fe.postedTime = frame->kPostedTime;
+        fe.requestedPresentTime = frame->kRequestedPresentTime;
+        fe.acquireFence = frame->mAcquireConsumer.mFenceTime;
+        mFakeConsumer->mNewFrameEntryOverride = fe;
+
+        mSurface->mFakeFrameEventHistory->setAcquireFenceOverride(
+                    frame->mAcquireProducer.mFenceTime,
+                    frame->mAcquireConsumer.mFenceTime);
+
+        ASSERT_EQ(NO_ERROR, mWindow->queueBuffer(mWindow.get(), buffer, fence));
+
+        EXPECT_EQ(frameNumber, mFakeConsumer->mLastAddedFrameNumber);
+
+        EXPECT_EQ(
+                oldAddFrameTimestampsCount + (mFrameTimestampsEnabled ? 1 : 0),
+                mFakeConsumer->mAddFrameTimestampsCount);
+    }
+
+    void addFrameEvents(
+            bool gpuComposited, uint64_t iOldFrame, int64_t iNewFrame) {
+        FrameEvents* oldFrame =
+                (iOldFrame == NO_FRAME_INDEX) ? nullptr : &mFrames[iOldFrame];
+        FrameEvents* newFrame = &mFrames[iNewFrame];
+
+        uint64_t nOldFrame = iOldFrame + 1;
+        uint64_t nNewFrame = iNewFrame + 1;
+
+        // Latch, Composite, and Release the frames in a plausible order.
+        // Note: The timestamps won't necessarily match the order, but
+        // that's okay for the purposes of this test.
+        std::shared_ptr<FenceTime> gpuDoneFenceTime = FenceTime::NO_FENCE;
+
+        // Composite the previous frame one more time, which helps verify
+        // LastRefresh is updated properly.
+        if (oldFrame != nullptr) {
+            mCfeh->addPreComposition(nOldFrame,
+                                     oldFrame->mRefreshes[2].kStartTime);
+            gpuDoneFenceTime = gpuComposited ?
+                    oldFrame->mRefreshes[2].mGpuCompositionDone.mFenceTime :
+                    FenceTime::NO_FENCE;
+            mCfeh->addPostComposition(nOldFrame, gpuDoneFenceTime,
+                    oldFrame->mRefreshes[2].mPresent.mFenceTime,
+                    oldFrame->mRefreshes[2].kCompositorTiming);
+        }
+
+        // Latch the new frame.
+        mCfeh->addLatch(nNewFrame, newFrame->kLatchTime);
+
+        mCfeh->addPreComposition(nNewFrame, newFrame->mRefreshes[0].kStartTime);
+        gpuDoneFenceTime = gpuComposited ?
+                newFrame->mRefreshes[0].mGpuCompositionDone.mFenceTime :
+                FenceTime::NO_FENCE;
+        // HWC2 releases the previous buffer after a new latch just before
+        // calling postComposition.
+        if (oldFrame != nullptr) {
+            mCfeh->addRelease(nOldFrame, oldFrame->kDequeueReadyTime,
+                    std::shared_ptr<FenceTime>(oldFrame->mRelease.mFenceTime));
+        }
+        mCfeh->addPostComposition(nNewFrame, gpuDoneFenceTime,
+                newFrame->mRefreshes[0].mPresent.mFenceTime,
+                newFrame->mRefreshes[0].kCompositorTiming);
+
+        mCfeh->addPreComposition(nNewFrame, newFrame->mRefreshes[1].kStartTime);
+        gpuDoneFenceTime = gpuComposited ?
+                newFrame->mRefreshes[1].mGpuCompositionDone.mFenceTime :
+                FenceTime::NO_FENCE;
+        mCfeh->addPostComposition(nNewFrame, gpuDoneFenceTime,
+                newFrame->mRefreshes[1].mPresent.mFenceTime,
+                newFrame->mRefreshes[1].kCompositorTiming);
+    }
+
+    sp<IGraphicBufferProducer> mProducer;
+    sp<IGraphicBufferConsumer> mConsumer;
+    sp<FakeConsumer> mFakeConsumer;
+    ConsumerFrameEventHistory* mCfeh;
+    sp<TestSurface> mSurface;
+    sp<ANativeWindow> mWindow;
+
+    FenceToFenceTimeMap mFenceMap;
+
+    bool mFrameTimestampsEnabled = false;
+
+    int64_t outRequestedPresentTime = -1;
+    int64_t outAcquireTime = -1;
+    int64_t outLatchTime = -1;
+    int64_t outFirstRefreshStartTime = -1;
+    int64_t outLastRefreshStartTime = -1;
+    int64_t outGpuCompositionDoneTime = -1;
+    int64_t outDisplayPresentTime = -1;
+    int64_t outDequeueReadyTime = -1;
+    int64_t outReleaseTime = -1;
+
+    FrameEvents mFrames[3] {
+        { mFenceMap, 1000 }, { mFenceMap, 2000 }, { mFenceMap, 3000 } };
+};
+
+
+// This test verifies that the frame timestamps are not retrieved when not
+// explicitly enabled via native_window_enable_frame_timestamps.
+// We want to check this to make sure there's no overhead for users
+// that don't need the timestamp information.
+TEST_F(GetFrameTimestampsTest, DefaultDisabled) {
+    int fence;
+    ANativeWindowBuffer* buffer;
+
+    EXPECT_EQ(0, mFakeConsumer->mAddFrameTimestampsCount);
+    EXPECT_EQ(0, mFakeConsumer->mGetFrameTimestampsCount);
+
+    const uint64_t fId = getNextFrameId();
+
+    // Verify the producer doesn't get frame timestamps piggybacked on dequeue.
+    ASSERT_EQ(NO_ERROR, mWindow->dequeueBuffer(mWindow.get(), &buffer, &fence));
+    EXPECT_EQ(0, mFakeConsumer->mAddFrameTimestampsCount);
+    EXPECT_EQ(0, mFakeConsumer->mGetFrameTimestampsCount);
+
+    // Verify the producer doesn't get frame timestamps piggybacked on queue.
+    // It is okay that frame timestamps are added in the consumer since it is
+    // still needed for SurfaceFlinger dumps.
+    ASSERT_EQ(NO_ERROR, mWindow->queueBuffer(mWindow.get(), buffer, fence));
+    EXPECT_EQ(1, mFakeConsumer->mAddFrameTimestampsCount);
+    EXPECT_EQ(0, mFakeConsumer->mGetFrameTimestampsCount);
+
+    // Verify attempts to get frame timestamps fail.
+    int result = getAllFrameTimestamps(fId);
+    EXPECT_EQ(INVALID_OPERATION, result);
+    EXPECT_EQ(0, mFakeConsumer->mGetFrameTimestampsCount);
+
+    // Verify compositor timing query fails.
+    nsecs_t compositeDeadline = 0;
+    nsecs_t compositeInterval = 0;
+    nsecs_t compositeToPresentLatency = 0;
+    result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(INVALID_OPERATION, result);
+}
+
+// This test verifies that the frame timestamps are retrieved if explicitly
+// enabled via native_window_enable_frame_timestamps.
+TEST_F(GetFrameTimestampsTest, EnabledSimple) {
+    CompositorTiming initialCompositorTiming {
+        1000000000, // 1s deadline
+        16666667, // 16ms interval
+        50000000, // 50ms present latency
+    };
+    mCfeh->initializeCompositorTiming(initialCompositorTiming);
+
+    enableFrameTimestamps();
+
+    // Verify the compositor timing query gets the initial compositor values
+    // after timststamps are enabled; even before the first frame is queued
+    // or dequeued.
+    nsecs_t compositeDeadline = 0;
+    nsecs_t compositeInterval = 0;
+    nsecs_t compositeToPresentLatency = 0;
+    mSurface->setNow(initialCompositorTiming.deadline - 1);
+    int result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(initialCompositorTiming.deadline, compositeDeadline);
+    EXPECT_EQ(initialCompositorTiming.interval, compositeInterval);
+    EXPECT_EQ(initialCompositorTiming.presentLatency,
+              compositeToPresentLatency);
+
+    int fence;
+    ANativeWindowBuffer* buffer;
+
+    EXPECT_EQ(0, mFakeConsumer->mAddFrameTimestampsCount);
+    EXPECT_EQ(1, mFakeConsumer->mGetFrameTimestampsCount);
+
+    const uint64_t fId1 = getNextFrameId();
+
+    // Verify getFrameTimestamps is piggybacked on dequeue.
+    ASSERT_EQ(NO_ERROR, mWindow->dequeueBuffer(mWindow.get(), &buffer, &fence));
+    EXPECT_EQ(0, mFakeConsumer->mAddFrameTimestampsCount);
+    EXPECT_EQ(2, mFakeConsumer->mGetFrameTimestampsCount);
+
+    NewFrameEventsEntry f1;
+    f1.frameNumber = 1;
+    f1.postedTime = mFrames[0].kPostedTime;
+    f1.requestedPresentTime = mFrames[0].kRequestedPresentTime;
+    f1.acquireFence = mFrames[0].mAcquireConsumer.mFenceTime;
+    mSurface->mFakeFrameEventHistory->setAcquireFenceOverride(
+            mFrames[0].mAcquireProducer.mFenceTime,
+            mFrames[0].mAcquireConsumer.mFenceTime);
+    mFakeConsumer->mNewFrameEntryOverride = f1;
+    mFrames[0].signalQueueFences();
+
+    // Verify getFrameTimestamps is piggybacked on queue.
+    ASSERT_EQ(NO_ERROR, mWindow->queueBuffer(mWindow.get(), buffer, fence));
+    EXPECT_EQ(1, mFakeConsumer->mAddFrameTimestampsCount);
+    EXPECT_EQ(1u, mFakeConsumer->mLastAddedFrameNumber);
+    EXPECT_EQ(3, mFakeConsumer->mGetFrameTimestampsCount);
+
+    // Verify queries for timestamps that the producer doesn't know about
+    // triggers a call to see if the consumer has any new timestamps.
+    result = getAllFrameTimestamps(fId1);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(4, mFakeConsumer->mGetFrameTimestampsCount);
+}
+
+TEST_F(GetFrameTimestampsTest, QueryPresentSupported) {
+    bool displayPresentSupported = true;
+    mSurface->mFakeSurfaceComposer->setSupportsPresent(displayPresentSupported);
+
+    // Verify supported bits are forwarded.
+    int supportsPresent = -1;
+    mWindow.get()->query(mWindow.get(),
+            NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &supportsPresent);
+    EXPECT_EQ(displayPresentSupported, supportsPresent);
+}
+
+TEST_F(GetFrameTimestampsTest, QueryPresentNotSupported) {
+    bool displayPresentSupported = false;
+    mSurface->mFakeSurfaceComposer->setSupportsPresent(displayPresentSupported);
+
+    // Verify supported bits are forwarded.
+    int supportsPresent = -1;
+    mWindow.get()->query(mWindow.get(),
+            NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &supportsPresent);
+    EXPECT_EQ(displayPresentSupported, supportsPresent);
+}
+
+TEST_F(GetFrameTimestampsTest, SnapToNextTickBasic) {
+    nsecs_t phase = 4000;
+    nsecs_t interval = 1000;
+
+    // Timestamp in previous interval.
+    nsecs_t timestamp = 3500;
+    EXPECT_EQ(4000, ProducerFrameEventHistory::snapToNextTick(
+            timestamp, phase, interval));
+
+    // Timestamp in next interval.
+    timestamp = 4500;
+    EXPECT_EQ(5000, ProducerFrameEventHistory::snapToNextTick(
+            timestamp, phase, interval));
+
+    // Timestamp multiple intervals before.
+    timestamp = 2500;
+    EXPECT_EQ(3000, ProducerFrameEventHistory::snapToNextTick(
+            timestamp, phase, interval));
+
+    // Timestamp multiple intervals after.
+    timestamp = 6500;
+    EXPECT_EQ(7000, ProducerFrameEventHistory::snapToNextTick(
+            timestamp, phase, interval));
+
+    // Timestamp on previous interval.
+    timestamp = 3000;
+    EXPECT_EQ(3000, ProducerFrameEventHistory::snapToNextTick(
+            timestamp, phase, interval));
+
+    // Timestamp on next interval.
+    timestamp = 5000;
+    EXPECT_EQ(5000, ProducerFrameEventHistory::snapToNextTick(
+            timestamp, phase, interval));
+
+    // Timestamp equal to phase.
+    timestamp = 4000;
+    EXPECT_EQ(4000, ProducerFrameEventHistory::snapToNextTick(
+            timestamp, phase, interval));
+}
+
+// int(big_timestamp / interval) < 0, which can cause a crash or invalid result
+// if the number of intervals elapsed is internally stored in an int.
+TEST_F(GetFrameTimestampsTest, SnapToNextTickOverflow) {
+      nsecs_t phase = 0;
+      nsecs_t interval = 4000;
+      nsecs_t big_timestamp = 8635916564000;
+      int32_t intervals = big_timestamp / interval;
+
+      EXPECT_LT(intervals, 0);
+      EXPECT_EQ(8635916564000, ProducerFrameEventHistory::snapToNextTick(
+            big_timestamp, phase, interval));
+      EXPECT_EQ(8635916564000, ProducerFrameEventHistory::snapToNextTick(
+            big_timestamp, big_timestamp, interval));
+}
+
+// This verifies the compositor timing is updated by refresh events
+// and piggy backed on a queue, dequeue, and enabling of timestamps..
+TEST_F(GetFrameTimestampsTest, CompositorTimingUpdatesBasic) {
+    CompositorTiming initialCompositorTiming {
+        1000000000, // 1s deadline
+        16666667, // 16ms interval
+        50000000, // 50ms present latency
+    };
+    mCfeh->initializeCompositorTiming(initialCompositorTiming);
+
+    enableFrameTimestamps();
+
+    // We get the initial values before any frames are submitted.
+    nsecs_t compositeDeadline = 0;
+    nsecs_t compositeInterval = 0;
+    nsecs_t compositeToPresentLatency = 0;
+    mSurface->setNow(initialCompositorTiming.deadline - 1);
+    int result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(initialCompositorTiming.deadline, compositeDeadline);
+    EXPECT_EQ(initialCompositorTiming.interval, compositeInterval);
+    EXPECT_EQ(initialCompositorTiming.presentLatency,
+              compositeToPresentLatency);
+
+    const uint64_t fId1 = getNextFrameId();
+    dequeueAndQueue(0);
+    addFrameEvents(true, NO_FRAME_INDEX, 0);
+
+    // Still get the initial values because the frame events for frame 0
+    // didn't get a chance to piggyback on a queue or dequeue yet.
+    result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(initialCompositorTiming.deadline, compositeDeadline);
+    EXPECT_EQ(initialCompositorTiming.interval, compositeInterval);
+    EXPECT_EQ(initialCompositorTiming.presentLatency,
+              compositeToPresentLatency);
+
+    const uint64_t fId2 = getNextFrameId();
+    dequeueAndQueue(1);
+    addFrameEvents(true, 0, 1);
+
+    // Now expect the composite values associated with frame 1.
+    mSurface->setNow(mFrames[0].mRefreshes[1].kCompositorTiming.deadline);
+    result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[0].mRefreshes[1].kCompositorTiming.deadline,
+            compositeDeadline);
+    EXPECT_EQ(mFrames[0].mRefreshes[1].kCompositorTiming.interval,
+            compositeInterval);
+    EXPECT_EQ(mFrames[0].mRefreshes[1].kCompositorTiming.presentLatency,
+            compositeToPresentLatency);
+
+    dequeueAndQueue(2);
+    addFrameEvents(true, 1, 2);
+
+    // Now expect the composite values associated with frame 2.
+    mSurface->setNow(mFrames[1].mRefreshes[1].kCompositorTiming.deadline);
+    result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[1].mRefreshes[1].kCompositorTiming.deadline,
+            compositeDeadline);
+    EXPECT_EQ(mFrames[1].mRefreshes[1].kCompositorTiming.interval,
+            compositeInterval);
+    EXPECT_EQ(mFrames[1].mRefreshes[1].kCompositorTiming.presentLatency,
+            compositeToPresentLatency);
+
+    // Re-enabling frame timestamps should get the latest values.
+    disableFrameTimestamps();
+    enableFrameTimestamps();
+
+    // Now expect the composite values associated with frame 3.
+    mSurface->setNow(mFrames[2].mRefreshes[1].kCompositorTiming.deadline);
+    result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[2].mRefreshes[1].kCompositorTiming.deadline,
+            compositeDeadline);
+    EXPECT_EQ(mFrames[2].mRefreshes[1].kCompositorTiming.interval,
+            compositeInterval);
+    EXPECT_EQ(mFrames[2].mRefreshes[1].kCompositorTiming.presentLatency,
+            compositeToPresentLatency);
+}
+
+// This verifies the compositor deadline properly snaps to the the next
+// deadline based on the current time.
+TEST_F(GetFrameTimestampsTest, CompositorTimingDeadlineSnaps) {
+    CompositorTiming initialCompositorTiming {
+        1000000000, // 1s deadline
+        16666667, // 16ms interval
+        50000000, // 50ms present latency
+    };
+    mCfeh->initializeCompositorTiming(initialCompositorTiming);
+
+    enableFrameTimestamps();
+
+    nsecs_t compositeDeadline = 0;
+    nsecs_t compositeInterval = 0;
+    nsecs_t compositeToPresentLatency = 0;
+
+    // A "now" just before the deadline snaps to the deadline.
+    mSurface->setNow(initialCompositorTiming.deadline - 1);
+    int result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(initialCompositorTiming.deadline, compositeDeadline);
+    nsecs_t expectedDeadline = initialCompositorTiming.deadline;
+    EXPECT_EQ(expectedDeadline, compositeDeadline);
+
+    const uint64_t fId1 = getNextFrameId();
+    dequeueAndQueue(0);
+    addFrameEvents(true, NO_FRAME_INDEX, 0);
+
+    // A "now" just after the deadline snaps properly.
+    mSurface->setNow(initialCompositorTiming.deadline + 1);
+    result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(NO_ERROR, result);
+    expectedDeadline =
+            initialCompositorTiming.deadline +initialCompositorTiming.interval;
+    EXPECT_EQ(expectedDeadline, compositeDeadline);
+
+    const uint64_t fId2 = getNextFrameId();
+    dequeueAndQueue(1);
+    addFrameEvents(true, 0, 1);
+
+    // A "now" just after the next interval snaps properly.
+    mSurface->setNow(
+            mFrames[0].mRefreshes[1].kCompositorTiming.deadline +
+            mFrames[0].mRefreshes[1].kCompositorTiming.interval + 1);
+    result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(NO_ERROR, result);
+    expectedDeadline =
+            mFrames[0].mRefreshes[1].kCompositorTiming.deadline +
+            mFrames[0].mRefreshes[1].kCompositorTiming.interval * 2;
+    EXPECT_EQ(expectedDeadline, compositeDeadline);
+
+    dequeueAndQueue(2);
+    addFrameEvents(true, 1, 2);
+
+    // A "now" over 1 interval before the deadline snaps properly.
+    mSurface->setNow(
+            mFrames[1].mRefreshes[1].kCompositorTiming.deadline -
+            mFrames[1].mRefreshes[1].kCompositorTiming.interval - 1);
+    result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(NO_ERROR, result);
+    expectedDeadline =
+            mFrames[1].mRefreshes[1].kCompositorTiming.deadline -
+            mFrames[1].mRefreshes[1].kCompositorTiming.interval;
+    EXPECT_EQ(expectedDeadline, compositeDeadline);
+
+    // Re-enabling frame timestamps should get the latest values.
+    disableFrameTimestamps();
+    enableFrameTimestamps();
+
+    // A "now" over 2 intervals before the deadline snaps properly.
+    mSurface->setNow(
+            mFrames[2].mRefreshes[1].kCompositorTiming.deadline -
+            mFrames[2].mRefreshes[1].kCompositorTiming.interval * 2 - 1);
+    result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(NO_ERROR, result);
+    expectedDeadline =
+            mFrames[2].mRefreshes[1].kCompositorTiming.deadline -
+            mFrames[2].mRefreshes[1].kCompositorTiming.interval * 2;
+    EXPECT_EQ(expectedDeadline, compositeDeadline);
+}
+
+// This verifies the timestamps recorded in the consumer's
+// FrameTimestampsHistory are properly retrieved by the producer for the
+// correct frames.
+TEST_F(GetFrameTimestampsTest, TimestampsAssociatedWithCorrectFrame) {
+    enableFrameTimestamps();
+
+    const uint64_t fId1 = getNextFrameId();
+    dequeueAndQueue(0);
+    mFrames[0].signalQueueFences();
+
+    const uint64_t fId2 = getNextFrameId();
+    dequeueAndQueue(1);
+    mFrames[1].signalQueueFences();
+
+    addFrameEvents(true, NO_FRAME_INDEX, 0);
+    mFrames[0].signalRefreshFences();
+    addFrameEvents(true, 0, 1);
+    mFrames[0].signalReleaseFences();
+    mFrames[1].signalRefreshFences();
+
+    // Verify timestamps are correct for frame 1.
+    resetTimestamps();
+    int result = getAllFrameTimestamps(fId1);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+    EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kGpuCompositionDoneTime,
+            outGpuCompositionDoneTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kPresentTime, outDisplayPresentTime);
+    EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
+    EXPECT_EQ(mFrames[0].kReleaseTime, outReleaseTime);
+
+    // Verify timestamps are correct for frame 2.
+    resetTimestamps();
+    result = getAllFrameTimestamps(fId2);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[1].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(mFrames[1].kProducerAcquireTime, outAcquireTime);
+    EXPECT_EQ(mFrames[1].kLatchTime, outLatchTime);
+    EXPECT_EQ(mFrames[1].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+    EXPECT_EQ(mFrames[1].mRefreshes[1].kStartTime, outLastRefreshStartTime);
+    EXPECT_EQ(mFrames[1].mRefreshes[0].kGpuCompositionDoneTime,
+            outGpuCompositionDoneTime);
+    EXPECT_EQ(mFrames[1].mRefreshes[0].kPresentTime, outDisplayPresentTime);
+    EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDequeueReadyTime);
+    EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime);
+}
+
+// This test verifies the acquire fence recorded by the consumer is not sent
+// back to the producer and the producer saves its own fence.
+TEST_F(GetFrameTimestampsTest, QueueTimestampsNoSync) {
+    enableFrameTimestamps();
+
+    // Dequeue and queue frame 1.
+    const uint64_t fId1 = getNextFrameId();
+    dequeueAndQueue(0);
+
+    // Verify queue-related timestamps for f1 are available immediately in the
+    // producer without asking the consumer again, even before signaling the
+    // acquire fence.
+    resetTimestamps();
+    int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    int result = native_window_get_frame_timestamps(mWindow.get(), fId1,
+            &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
+            nullptr, nullptr, nullptr, nullptr, nullptr);
+    EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outAcquireTime);
+
+    // Signal acquire fences. Verify a sync call still isn't necessary.
+    mFrames[0].signalQueueFences();
+
+    oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    result = native_window_get_frame_timestamps(mWindow.get(), fId1,
+            &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
+            nullptr, nullptr, nullptr, nullptr, nullptr);
+    EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+
+    // Dequeue and queue frame 2.
+    const uint64_t fId2 = getNextFrameId();
+    dequeueAndQueue(1);
+
+    // Verify queue-related timestamps for f2 are available immediately in the
+    // producer without asking the consumer again, even before signaling the
+    // acquire fence.
+    resetTimestamps();
+    oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    result = native_window_get_frame_timestamps(mWindow.get(), fId2,
+            &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
+            nullptr, nullptr, nullptr, nullptr, nullptr);
+    EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[1].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outAcquireTime);
+
+    // Signal acquire fences. Verify a sync call still isn't necessary.
+    mFrames[1].signalQueueFences();
+
+    oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    result = native_window_get_frame_timestamps(mWindow.get(), fId2,
+            &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
+            nullptr, nullptr, nullptr, nullptr, nullptr);
+    EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[1].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(mFrames[1].kProducerAcquireTime, outAcquireTime);
+}
+
+TEST_F(GetFrameTimestampsTest, ZeroRequestedTimestampsNoSync) {
+    enableFrameTimestamps();
+
+    // Dequeue and queue frame 1.
+    dequeueAndQueue(0);
+    mFrames[0].signalQueueFences();
+
+    // Dequeue and queue frame 2.
+    const uint64_t fId2 = getNextFrameId();
+    dequeueAndQueue(1);
+    mFrames[1].signalQueueFences();
+
+    addFrameEvents(true, NO_FRAME_INDEX, 0);
+    mFrames[0].signalRefreshFences();
+    addFrameEvents(true, 0, 1);
+    mFrames[0].signalReleaseFences();
+    mFrames[1].signalRefreshFences();
+
+    // Verify a request for no timestamps doesn't result in a sync call.
+    int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    int result = native_window_get_frame_timestamps(mWindow.get(), fId2,
+            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+            nullptr, nullptr);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+}
+
+// This test verifies that fences can signal and update timestamps producer
+// side without an additional sync call to the consumer.
+TEST_F(GetFrameTimestampsTest, FencesInProducerNoSync) {
+    enableFrameTimestamps();
+
+    // Dequeue and queue frame 1.
+    const uint64_t fId1 = getNextFrameId();
+    dequeueAndQueue(0);
+    mFrames[0].signalQueueFences();
+
+    // Dequeue and queue frame 2.
+    dequeueAndQueue(1);
+    mFrames[1].signalQueueFences();
+
+    addFrameEvents(true, NO_FRAME_INDEX, 0);
+    addFrameEvents(true, 0, 1);
+
+    // Verify available timestamps are correct for frame 1, before any
+    // fence has been signaled.
+    // Note: A sync call is necessary here since the events triggered by
+    // addFrameEvents didn't get to piggyback on the earlier queues/dequeues.
+    resetTimestamps();
+    int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    int result = getAllFrameTimestamps(fId1);
+    EXPECT_EQ(oldCount + 1, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+    EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
+    EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outGpuCompositionDoneTime);
+    EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDisplayPresentTime);
+    EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
+    EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime);
+
+    // Verify available timestamps are correct for frame 1 again, before any
+    // fence has been signaled.
+    // This time a sync call should not be necessary.
+    resetTimestamps();
+    oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    result = getAllFrameTimestamps(fId1);
+    EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+    EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
+    EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outGpuCompositionDoneTime);
+    EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDisplayPresentTime);
+    EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
+    EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime);
+
+    // Signal the fences for frame 1.
+    mFrames[0].signalRefreshFences();
+    mFrames[0].signalReleaseFences();
+
+    // Verify all timestamps are available without a sync call.
+    resetTimestamps();
+    oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    result = getAllFrameTimestamps(fId1);
+    EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+    EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kGpuCompositionDoneTime,
+            outGpuCompositionDoneTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kPresentTime, outDisplayPresentTime);
+    EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
+    EXPECT_EQ(mFrames[0].kReleaseTime, outReleaseTime);
+}
+
+// This test verifies that if the frame wasn't GPU composited but has a refresh
+// event a sync call isn't made to get the GPU composite done time since it will
+// never exist.
+TEST_F(GetFrameTimestampsTest, NoGpuNoSync) {
+    enableFrameTimestamps();
+
+    // Dequeue and queue frame 1.
+    const uint64_t fId1 = getNextFrameId();
+    dequeueAndQueue(0);
+    mFrames[0].signalQueueFences();
+
+    // Dequeue and queue frame 2.
+    dequeueAndQueue(1);
+    mFrames[1].signalQueueFences();
+
+    addFrameEvents(false, NO_FRAME_INDEX, 0);
+    addFrameEvents(false, 0, 1);
+
+    // Verify available timestamps are correct for frame 1, before any
+    // fence has been signaled.
+    // Note: A sync call is necessary here since the events triggered by
+    // addFrameEvents didn't get to piggyback on the earlier queues/dequeues.
+    resetTimestamps();
+    int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    int result = getAllFrameTimestamps(fId1);
+    EXPECT_EQ(oldCount + 1, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+    EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
+    EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_INVALID, outGpuCompositionDoneTime);
+    EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDisplayPresentTime);
+    EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
+    EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime);
+
+    // Signal the fences for frame 1.
+    mFrames[0].signalRefreshFences();
+    mFrames[0].signalReleaseFences();
+
+    // Verify all timestamps, except GPU composition, are available without a
+    // sync call.
+    resetTimestamps();
+    oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    result = getAllFrameTimestamps(fId1);
+    EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+    EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
+    EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_INVALID, outGpuCompositionDoneTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kPresentTime, outDisplayPresentTime);
+    EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
+    EXPECT_EQ(mFrames[0].kReleaseTime, outReleaseTime);
+}
+
+// This test verifies that if the certain timestamps can't possibly exist for
+// the most recent frame, then a sync call is not done.
+TEST_F(GetFrameTimestampsTest, NoReleaseNoSync) {
+    enableFrameTimestamps();
+
+    // Dequeue and queue frame 1.
+    const uint64_t fId1 = getNextFrameId();
+    dequeueAndQueue(0);
+    mFrames[0].signalQueueFences();
+
+    // Dequeue and queue frame 2.
+    const uint64_t fId2 = getNextFrameId();
+    dequeueAndQueue(1);
+    mFrames[1].signalQueueFences();
+
+    addFrameEvents(false, NO_FRAME_INDEX, 0);
+    addFrameEvents(false, 0, 1);
+
+    // Verify available timestamps are correct for frame 1, before any
+    // fence has been signaled.
+    // Note: A sync call is necessary here since the events triggered by
+    // addFrameEvents didn't get to piggyback on the earlier queues/dequeues.
+    resetTimestamps();
+    int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    int result = getAllFrameTimestamps(fId1);
+    EXPECT_EQ(oldCount + 1, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+    EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+    EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
+    EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_INVALID, outGpuCompositionDoneTime);
+    EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDisplayPresentTime);
+    EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
+    EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime);
+
+    mFrames[0].signalRefreshFences();
+    mFrames[0].signalReleaseFences();
+    mFrames[1].signalRefreshFences();
+
+    // Verify querying for all timestmaps of f2 does not do a sync call. Even
+    // though the lastRefresh, dequeueReady, and release times aren't
+    // available, a sync call should not occur because it's not possible for f2
+    // to encounter the final value for those events until another frame is
+    // queued.
+    resetTimestamps();
+    oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    result = getAllFrameTimestamps(fId2);
+    EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[1].kRequestedPresentTime, outRequestedPresentTime);
+    EXPECT_EQ(mFrames[1].kProducerAcquireTime, outAcquireTime);
+    EXPECT_EQ(mFrames[1].kLatchTime, outLatchTime);
+    EXPECT_EQ(mFrames[1].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+    EXPECT_EQ(mFrames[1].mRefreshes[1].kStartTime, outLastRefreshStartTime);
+    EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_INVALID, outGpuCompositionDoneTime);
+    EXPECT_EQ(mFrames[1].mRefreshes[0].kPresentTime, outDisplayPresentTime);
+    EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDequeueReadyTime);
+    EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime);
+}
+
+// This test verifies there are no sync calls for present times
+// when they aren't supported and that an error is returned.
+
+TEST_F(GetFrameTimestampsTest, PresentUnsupportedNoSync) {
+    enableFrameTimestamps();
+    mSurface->mFakeSurfaceComposer->setSupportsPresent(false);
+
+    // Dequeue and queue frame 1.
+    const uint64_t fId1 = getNextFrameId();
+    dequeueAndQueue(0);
+
+    // Verify a query for the Present times do not trigger a sync call if they
+    // are not supported.
+    resetTimestamps();
+    int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+    int result = native_window_get_frame_timestamps(mWindow.get(), fId1,
+            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+            &outDisplayPresentTime, nullptr, nullptr);
+    EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(BAD_VALUE, result);
+    EXPECT_EQ(-1, outDisplayPresentTime);
+}
+
+} // namespace android
diff --git a/libs/gui/view/Surface.cpp b/libs/gui/view/Surface.cpp
new file mode 100644
index 0000000..5ed3d3b
--- /dev/null
+++ b/libs/gui/view/Surface.cpp
@@ -0,0 +1,97 @@
+/*
+ * 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 "Surface"
+
+#include <gui/view/Surface.h>
+
+#include <binder/Parcel.h>
+
+#include <utils/Log.h>
+
+#include <gui/IGraphicBufferProducer.h>
+
+namespace android {
+namespace view {
+
+status_t Surface::writeToParcel(Parcel* parcel) const {
+    return writeToParcel(parcel, false);
+}
+
+status_t Surface::writeToParcel(Parcel* parcel, bool nameAlreadyWritten) const {
+    if (parcel == nullptr) return BAD_VALUE;
+
+    status_t res = OK;
+
+    if (!nameAlreadyWritten) {
+        res = parcel->writeString16(name);
+        if (res != OK) return res;
+
+        /* isSingleBuffered defaults to no */
+        res = parcel->writeInt32(0);
+        if (res != OK) return res;
+    }
+
+    res = parcel->writeStrongBinder(
+            IGraphicBufferProducer::asBinder(graphicBufferProducer));
+
+    return res;
+}
+
+status_t Surface::readFromParcel(const Parcel* parcel) {
+    return readFromParcel(parcel, false);
+}
+
+status_t Surface::readFromParcel(const Parcel* parcel, bool nameAlreadyRead) {
+    if (parcel == nullptr) return BAD_VALUE;
+
+    status_t res = OK;
+    if (!nameAlreadyRead) {
+        name = readMaybeEmptyString16(parcel);
+        // Discard this for now
+        int isSingleBuffered;
+        res = parcel->readInt32(&isSingleBuffered);
+        if (res != OK) {
+            ALOGE("Can't read isSingleBuffered");
+            return res;
+        }
+    }
+
+    sp<IBinder> binder;
+
+    res = parcel->readNullableStrongBinder(&binder);
+    if (res != OK) {
+        ALOGE("%s: Can't read strong binder", __FUNCTION__);
+        return res;
+    }
+
+    graphicBufferProducer = interface_cast<IGraphicBufferProducer>(binder);
+
+    return OK;
+}
+
+String16 Surface::readMaybeEmptyString16(const Parcel* parcel) {
+    size_t len;
+    const char16_t* str = parcel->readString16Inplace(&len);
+    if (str != nullptr) {
+        return String16(str, len);
+    } else {
+        return String16();
+    }
+}
+
+} // namespace view
+} // namespace android
diff --git a/libs/hwc2on1adapter/Android.bp b/libs/hwc2on1adapter/Android.bp
new file mode 100644
index 0000000..ec9cbf8
--- /dev/null
+++ b/libs/hwc2on1adapter/Android.bp
@@ -0,0 +1,72 @@
+// Copyright 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.
+
+cc_library_shared {
+    name: "libhwc2on1adapter",
+    vendor: true,
+
+    clang: true,
+    cppflags: [
+        "-Weverything",
+        "-Wall",
+        "-Wunused",
+        "-Wunreachable-code",
+
+        // 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",
+
+        // android/sensors.h uses nested anonymous unions and anonymous structs
+        "-Wno-nested-anon-types",
+        "-Wno-gnu-anonymous-struct",
+
+        // Don't warn about struct padding
+        "-Wno-padded",
+
+        // hwcomposer2.h features switch covering all cases.
+        "-Wno-covered-switch-default",
+
+        // hwcomposer.h features zero size array.
+        "-Wno-zero-length-array",
+
+        // Disabling warning specific to hwc2on1adapter code
+        "-Wno-double-promotion",
+        "-Wno-sign-conversion",
+        "-Wno-switch-enum",
+        "-Wno-float-equal",
+        "-Wno-shorten-64-to-32",
+        "-Wno-sign-compare",
+        "-Wno-missing-prototypes",
+    ],
+
+    srcs: [
+        "HWC2On1Adapter.cpp",
+        "MiniFence.cpp",
+    ],
+
+    shared_libs: [
+        "libutils",
+        "libcutils",
+        "liblog",
+        "libhardware",
+    ],
+
+    export_include_dirs: ["include"],
+
+    export_shared_lib_headers: ["libutils"],
+}
diff --git a/libs/hwc2on1adapter/CleanSpec.mk b/libs/hwc2on1adapter/CleanSpec.mk
new file mode 100644
index 0000000..7fc2216
--- /dev/null
+++ b/libs/hwc2on1adapter/CleanSpec.mk
@@ -0,0 +1,52 @@
+# 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.
+#
+
+# 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, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libhwc2on1adapter_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libhwc2on1adapter.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/libhwc2on1adapter.so)
diff --git a/libs/hwc2on1adapter/HWC2On1Adapter.cpp b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
new file mode 100644
index 0000000..8c6ef69
--- /dev/null
+++ b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
@@ -0,0 +1,2620 @@
+/*
+ * Copyright 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 "hwc2on1adapter/HWC2On1Adapter.h"
+
+//#define LOG_NDEBUG 0
+
+#undef LOG_TAG
+#define LOG_TAG "HWC2On1Adapter"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+
+#include <inttypes.h>
+
+#include <chrono>
+#include <cstdlib>
+#include <sstream>
+
+#include <hardware/hwcomposer.h>
+#include <log/log.h>
+#include <utils/Trace.h>
+
+using namespace std::chrono_literals;
+
+static uint8_t getMinorVersion(struct hwc_composer_device_1* device)
+{
+    auto version = device->common.version & HARDWARE_API_VERSION_2_MAJ_MIN_MASK;
+    return (version >> 16) & 0xF;
+}
+
+template <typename PFN, typename T>
+static hwc2_function_pointer_t asFP(T function)
+{
+    static_assert(std::is_same<PFN, T>::value, "Incompatible function pointer");
+    return reinterpret_cast<hwc2_function_pointer_t>(function);
+}
+
+using namespace HWC2;
+
+static constexpr Attribute ColorMode = static_cast<Attribute>(6);
+
+namespace android {
+
+class HWC2On1Adapter::Callbacks : public hwc_procs_t {
+    public:
+        explicit Callbacks(HWC2On1Adapter& adapter) : mAdapter(adapter) {
+            invalidate = &invalidateHook;
+            vsync = &vsyncHook;
+            hotplug = &hotplugHook;
+        }
+
+        static void invalidateHook(const hwc_procs_t* procs) {
+            auto callbacks = static_cast<const Callbacks*>(procs);
+            callbacks->mAdapter.hwc1Invalidate();
+        }
+
+        static void vsyncHook(const hwc_procs_t* procs, int display,
+                int64_t timestamp) {
+            auto callbacks = static_cast<const Callbacks*>(procs);
+            callbacks->mAdapter.hwc1Vsync(display, timestamp);
+        }
+
+        static void hotplugHook(const hwc_procs_t* procs, int display,
+                int connected) {
+            auto callbacks = static_cast<const Callbacks*>(procs);
+            callbacks->mAdapter.hwc1Hotplug(display, connected);
+        }
+
+    private:
+        HWC2On1Adapter& mAdapter;
+};
+
+static int closeHook(hw_device_t* /*device*/)
+{
+    // Do nothing, since the real work is done in the class destructor, but we
+    // need to provide a valid function pointer for hwc2_close to call
+    return 0;
+}
+
+HWC2On1Adapter::HWC2On1Adapter(hwc_composer_device_1_t* hwc1Device)
+  : mDumpString(),
+    mHwc1Device(hwc1Device),
+    mHwc1MinorVersion(getMinorVersion(hwc1Device)),
+    mHwc1SupportsVirtualDisplays(false),
+    mHwc1SupportsBackgroundColor(false),
+    mHwc1Callbacks(std::make_unique<Callbacks>(*this)),
+    mCapabilities(),
+    mLayers(),
+    mHwc1VirtualDisplay(),
+    mStateMutex(),
+    mCallbacks(),
+    mHasPendingInvalidate(false),
+    mPendingVsyncs(),
+    mPendingHotplugs(),
+    mDisplays(),
+    mHwc1DisplayMap()
+{
+    common.close = closeHook;
+    getCapabilities = getCapabilitiesHook;
+    getFunction = getFunctionHook;
+    populateCapabilities();
+    populatePrimary();
+    mHwc1Device->registerProcs(mHwc1Device,
+            static_cast<const hwc_procs_t*>(mHwc1Callbacks.get()));
+}
+
+HWC2On1Adapter::~HWC2On1Adapter() {
+    hwc_close_1(mHwc1Device);
+}
+
+void HWC2On1Adapter::doGetCapabilities(uint32_t* outCount,
+        int32_t* outCapabilities) {
+    if (outCapabilities == nullptr) {
+        *outCount = mCapabilities.size();
+        return;
+    }
+
+    auto capabilityIter = mCapabilities.cbegin();
+    for (size_t written = 0; written < *outCount; ++written) {
+        if (capabilityIter == mCapabilities.cend()) {
+            return;
+        }
+        outCapabilities[written] = static_cast<int32_t>(*capabilityIter);
+        ++capabilityIter;
+    }
+}
+
+hwc2_function_pointer_t HWC2On1Adapter::doGetFunction(
+        FunctionDescriptor descriptor) {
+    switch (descriptor) {
+        // Device functions
+        case FunctionDescriptor::CreateVirtualDisplay:
+            return asFP<HWC2_PFN_CREATE_VIRTUAL_DISPLAY>(
+                    createVirtualDisplayHook);
+        case FunctionDescriptor::DestroyVirtualDisplay:
+            return asFP<HWC2_PFN_DESTROY_VIRTUAL_DISPLAY>(
+                    destroyVirtualDisplayHook);
+        case FunctionDescriptor::Dump:
+            return asFP<HWC2_PFN_DUMP>(dumpHook);
+        case FunctionDescriptor::GetMaxVirtualDisplayCount:
+            return asFP<HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT>(
+                    getMaxVirtualDisplayCountHook);
+        case FunctionDescriptor::RegisterCallback:
+            return asFP<HWC2_PFN_REGISTER_CALLBACK>(registerCallbackHook);
+
+        // Display functions
+        case FunctionDescriptor::AcceptDisplayChanges:
+            return asFP<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>(
+                    displayHook<decltype(&Display::acceptChanges),
+                    &Display::acceptChanges>);
+        case FunctionDescriptor::CreateLayer:
+            return asFP<HWC2_PFN_CREATE_LAYER>(
+                    displayHook<decltype(&Display::createLayer),
+                    &Display::createLayer, hwc2_layer_t*>);
+        case FunctionDescriptor::DestroyLayer:
+            return asFP<HWC2_PFN_DESTROY_LAYER>(
+                    displayHook<decltype(&Display::destroyLayer),
+                    &Display::destroyLayer, hwc2_layer_t>);
+        case FunctionDescriptor::GetActiveConfig:
+            return asFP<HWC2_PFN_GET_ACTIVE_CONFIG>(
+                    displayHook<decltype(&Display::getActiveConfig),
+                    &Display::getActiveConfig, hwc2_config_t*>);
+        case FunctionDescriptor::GetChangedCompositionTypes:
+            return asFP<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>(
+                    displayHook<decltype(&Display::getChangedCompositionTypes),
+                    &Display::getChangedCompositionTypes, uint32_t*,
+                    hwc2_layer_t*, int32_t*>);
+        case FunctionDescriptor::GetColorModes:
+            return asFP<HWC2_PFN_GET_COLOR_MODES>(
+                    displayHook<decltype(&Display::getColorModes),
+                    &Display::getColorModes, uint32_t*, int32_t*>);
+        case FunctionDescriptor::GetDisplayAttribute:
+            return asFP<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>(
+                    getDisplayAttributeHook);
+        case FunctionDescriptor::GetDisplayConfigs:
+            return asFP<HWC2_PFN_GET_DISPLAY_CONFIGS>(
+                    displayHook<decltype(&Display::getConfigs),
+                    &Display::getConfigs, uint32_t*, hwc2_config_t*>);
+        case FunctionDescriptor::GetDisplayName:
+            return asFP<HWC2_PFN_GET_DISPLAY_NAME>(
+                    displayHook<decltype(&Display::getName),
+                    &Display::getName, uint32_t*, char*>);
+        case FunctionDescriptor::GetDisplayRequests:
+            return asFP<HWC2_PFN_GET_DISPLAY_REQUESTS>(
+                    displayHook<decltype(&Display::getRequests),
+                    &Display::getRequests, int32_t*, uint32_t*, hwc2_layer_t*,
+                    int32_t*>);
+        case FunctionDescriptor::GetDisplayType:
+            return asFP<HWC2_PFN_GET_DISPLAY_TYPE>(
+                    displayHook<decltype(&Display::getType),
+                    &Display::getType, int32_t*>);
+        case FunctionDescriptor::GetDozeSupport:
+            return asFP<HWC2_PFN_GET_DOZE_SUPPORT>(
+                    displayHook<decltype(&Display::getDozeSupport),
+                    &Display::getDozeSupport, int32_t*>);
+        case FunctionDescriptor::GetHdrCapabilities:
+            return asFP<HWC2_PFN_GET_HDR_CAPABILITIES>(
+                    displayHook<decltype(&Display::getHdrCapabilities),
+                    &Display::getHdrCapabilities, uint32_t*, int32_t*, float*,
+                    float*, float*>);
+        case FunctionDescriptor::GetReleaseFences:
+            return asFP<HWC2_PFN_GET_RELEASE_FENCES>(
+                    displayHook<decltype(&Display::getReleaseFences),
+                    &Display::getReleaseFences, uint32_t*, hwc2_layer_t*,
+                    int32_t*>);
+        case FunctionDescriptor::PresentDisplay:
+            return asFP<HWC2_PFN_PRESENT_DISPLAY>(
+                    displayHook<decltype(&Display::present),
+                    &Display::present, int32_t*>);
+        case FunctionDescriptor::SetActiveConfig:
+            return asFP<HWC2_PFN_SET_ACTIVE_CONFIG>(
+                    displayHook<decltype(&Display::setActiveConfig),
+                    &Display::setActiveConfig, hwc2_config_t>);
+        case FunctionDescriptor::SetClientTarget:
+            return asFP<HWC2_PFN_SET_CLIENT_TARGET>(
+                    displayHook<decltype(&Display::setClientTarget),
+                    &Display::setClientTarget, buffer_handle_t, int32_t,
+                    int32_t, hwc_region_t>);
+        case FunctionDescriptor::SetColorMode:
+            return asFP<HWC2_PFN_SET_COLOR_MODE>(setColorModeHook);
+        case FunctionDescriptor::SetColorTransform:
+            return asFP<HWC2_PFN_SET_COLOR_TRANSFORM>(setColorTransformHook);
+        case FunctionDescriptor::SetOutputBuffer:
+            return asFP<HWC2_PFN_SET_OUTPUT_BUFFER>(
+                    displayHook<decltype(&Display::setOutputBuffer),
+                    &Display::setOutputBuffer, buffer_handle_t, int32_t>);
+        case FunctionDescriptor::SetPowerMode:
+            return asFP<HWC2_PFN_SET_POWER_MODE>(setPowerModeHook);
+        case FunctionDescriptor::SetVsyncEnabled:
+            return asFP<HWC2_PFN_SET_VSYNC_ENABLED>(setVsyncEnabledHook);
+        case FunctionDescriptor::ValidateDisplay:
+            return asFP<HWC2_PFN_VALIDATE_DISPLAY>(
+                    displayHook<decltype(&Display::validate),
+                    &Display::validate, uint32_t*, uint32_t*>);
+        case FunctionDescriptor::GetClientTargetSupport:
+            return asFP<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>(
+                    displayHook<decltype(&Display::getClientTargetSupport),
+                    &Display::getClientTargetSupport, uint32_t, uint32_t,
+                                                      int32_t, int32_t>);
+
+        // Layer functions
+        case FunctionDescriptor::SetCursorPosition:
+            return asFP<HWC2_PFN_SET_CURSOR_POSITION>(
+                    layerHook<decltype(&Layer::setCursorPosition),
+                    &Layer::setCursorPosition, int32_t, int32_t>);
+        case FunctionDescriptor::SetLayerBuffer:
+            return asFP<HWC2_PFN_SET_LAYER_BUFFER>(
+                    layerHook<decltype(&Layer::setBuffer), &Layer::setBuffer,
+                    buffer_handle_t, int32_t>);
+        case FunctionDescriptor::SetLayerSurfaceDamage:
+            return asFP<HWC2_PFN_SET_LAYER_SURFACE_DAMAGE>(
+                    layerHook<decltype(&Layer::setSurfaceDamage),
+                    &Layer::setSurfaceDamage, hwc_region_t>);
+
+        // Layer state functions
+        case FunctionDescriptor::SetLayerBlendMode:
+            return asFP<HWC2_PFN_SET_LAYER_BLEND_MODE>(
+                    setLayerBlendModeHook);
+        case FunctionDescriptor::SetLayerColor:
+            return asFP<HWC2_PFN_SET_LAYER_COLOR>(
+                    layerHook<decltype(&Layer::setColor), &Layer::setColor,
+                    hwc_color_t>);
+        case FunctionDescriptor::SetLayerCompositionType:
+            return asFP<HWC2_PFN_SET_LAYER_COMPOSITION_TYPE>(
+                    setLayerCompositionTypeHook);
+        case FunctionDescriptor::SetLayerDataspace:
+            return asFP<HWC2_PFN_SET_LAYER_DATASPACE>(setLayerDataspaceHook);
+        case FunctionDescriptor::SetLayerDisplayFrame:
+            return asFP<HWC2_PFN_SET_LAYER_DISPLAY_FRAME>(
+                    layerHook<decltype(&Layer::setDisplayFrame),
+                    &Layer::setDisplayFrame, hwc_rect_t>);
+        case FunctionDescriptor::SetLayerPlaneAlpha:
+            return asFP<HWC2_PFN_SET_LAYER_PLANE_ALPHA>(
+                    layerHook<decltype(&Layer::setPlaneAlpha),
+                    &Layer::setPlaneAlpha, float>);
+        case FunctionDescriptor::SetLayerSidebandStream:
+            return asFP<HWC2_PFN_SET_LAYER_SIDEBAND_STREAM>(
+                    layerHook<decltype(&Layer::setSidebandStream),
+                    &Layer::setSidebandStream, const native_handle_t*>);
+        case FunctionDescriptor::SetLayerSourceCrop:
+            return asFP<HWC2_PFN_SET_LAYER_SOURCE_CROP>(
+                    layerHook<decltype(&Layer::setSourceCrop),
+                    &Layer::setSourceCrop, hwc_frect_t>);
+        case FunctionDescriptor::SetLayerTransform:
+            return asFP<HWC2_PFN_SET_LAYER_TRANSFORM>(setLayerTransformHook);
+        case FunctionDescriptor::SetLayerVisibleRegion:
+            return asFP<HWC2_PFN_SET_LAYER_VISIBLE_REGION>(
+                    layerHook<decltype(&Layer::setVisibleRegion),
+                    &Layer::setVisibleRegion, hwc_region_t>);
+        case FunctionDescriptor::SetLayerZOrder:
+            return asFP<HWC2_PFN_SET_LAYER_Z_ORDER>(setLayerZOrderHook);
+
+        default:
+            ALOGE("doGetFunction: Unknown function descriptor: %d (%s)",
+                    static_cast<int32_t>(descriptor),
+                    to_string(descriptor).c_str());
+            return nullptr;
+    }
+}
+
+// Device functions
+
+Error HWC2On1Adapter::createVirtualDisplay(uint32_t width,
+        uint32_t height, hwc2_display_t* outDisplay) {
+    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+    if (mHwc1VirtualDisplay) {
+        // We have already allocated our only HWC1 virtual display
+        ALOGE("createVirtualDisplay: HWC1 virtual display already allocated");
+        return Error::NoResources;
+    }
+
+    mHwc1VirtualDisplay = std::make_shared<HWC2On1Adapter::Display>(*this,
+            HWC2::DisplayType::Virtual);
+    mHwc1VirtualDisplay->populateConfigs(width, height);
+    const auto displayId = mHwc1VirtualDisplay->getId();
+    mHwc1DisplayMap[HWC_DISPLAY_VIRTUAL] = displayId;
+    mHwc1VirtualDisplay->setHwc1Id(HWC_DISPLAY_VIRTUAL);
+    mDisplays.emplace(displayId, mHwc1VirtualDisplay);
+    *outDisplay = displayId;
+
+    return Error::None;
+}
+
+Error HWC2On1Adapter::destroyVirtualDisplay(hwc2_display_t displayId) {
+    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+    if (!mHwc1VirtualDisplay || (mHwc1VirtualDisplay->getId() != displayId)) {
+        return Error::BadDisplay;
+    }
+
+    mHwc1VirtualDisplay.reset();
+    mHwc1DisplayMap.erase(HWC_DISPLAY_VIRTUAL);
+    mDisplays.erase(displayId);
+
+    return Error::None;
+}
+
+void HWC2On1Adapter::dump(uint32_t* outSize, char* outBuffer) {
+    if (outBuffer != nullptr) {
+        auto copiedBytes = mDumpString.copy(outBuffer, *outSize);
+        *outSize = static_cast<uint32_t>(copiedBytes);
+        return;
+    }
+
+    std::stringstream output;
+
+    output << "-- HWC2On1Adapter --\n";
+
+    output << "Adapting to a HWC 1." << static_cast<int>(mHwc1MinorVersion) <<
+            " device\n";
+
+    // Attempt to acquire the lock for 1 second, but proceed without the lock
+    // after that, so we can still get some information if we're deadlocked
+    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex,
+            std::defer_lock);
+    lock.try_lock_for(1s);
+
+    if (mCapabilities.empty()) {
+        output << "Capabilities: None\n";
+    } else {
+        output << "Capabilities:\n";
+        for (auto capability : mCapabilities) {
+            output << "  " << to_string(capability) << '\n';
+        }
+    }
+
+    output << "Displays:\n";
+    for (const auto& element : mDisplays) {
+        const auto& display = element.second;
+        output << display->dump();
+    }
+    output << '\n';
+
+    // Release the lock before calling into HWC1, and since we no longer require
+    // mutual exclusion to access mCapabilities or mDisplays
+    lock.unlock();
+
+    if (mHwc1Device->dump) {
+        output << "HWC1 dump:\n";
+        std::vector<char> hwc1Dump(4096);
+        // Call with size - 1 to preserve a null character at the end
+        mHwc1Device->dump(mHwc1Device, hwc1Dump.data(),
+                static_cast<int>(hwc1Dump.size() - 1));
+        output << hwc1Dump.data();
+    }
+
+    mDumpString = output.str();
+    *outSize = static_cast<uint32_t>(mDumpString.size());
+}
+
+uint32_t HWC2On1Adapter::getMaxVirtualDisplayCount() {
+    return mHwc1SupportsVirtualDisplays ? 1 : 0;
+}
+
+static bool isValid(Callback descriptor) {
+    switch (descriptor) {
+        case Callback::Hotplug: // Fall-through
+        case Callback::Refresh: // Fall-through
+        case Callback::Vsync: return true;
+        default: return false;
+    }
+}
+
+Error HWC2On1Adapter::registerCallback(Callback descriptor,
+        hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer) {
+    if (!isValid(descriptor)) {
+        return Error::BadParameter;
+    }
+
+    ALOGV("registerCallback(%s, %p, %p)", to_string(descriptor).c_str(),
+            callbackData, pointer);
+
+    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+    mCallbacks[descriptor] = {callbackData, pointer};
+
+    bool hasPendingInvalidate = false;
+    std::vector<hwc2_display_t> displayIds;
+    std::vector<std::pair<hwc2_display_t, int64_t>> pendingVsyncs;
+    std::vector<std::pair<hwc2_display_t, int>> pendingHotplugs;
+
+    if (descriptor == Callback::Refresh) {
+        hasPendingInvalidate = mHasPendingInvalidate;
+        if (hasPendingInvalidate) {
+            for (auto& displayPair : mDisplays) {
+                displayIds.emplace_back(displayPair.first);
+            }
+        }
+        mHasPendingInvalidate = false;
+    } else if (descriptor == Callback::Vsync) {
+        for (auto pending : mPendingVsyncs) {
+            auto hwc1DisplayId = pending.first;
+            if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
+                ALOGE("hwc1Vsync: Couldn't find display for HWC1 id %d",
+                        hwc1DisplayId);
+                continue;
+            }
+            auto displayId = mHwc1DisplayMap[hwc1DisplayId];
+            auto timestamp = pending.second;
+            pendingVsyncs.emplace_back(displayId, timestamp);
+        }
+        mPendingVsyncs.clear();
+    } else if (descriptor == Callback::Hotplug) {
+        // Hotplug the primary display
+        pendingHotplugs.emplace_back(mHwc1DisplayMap[HWC_DISPLAY_PRIMARY],
+                static_cast<int32_t>(Connection::Connected));
+
+        for (auto pending : mPendingHotplugs) {
+            auto hwc1DisplayId = pending.first;
+            if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
+                ALOGE("hwc1Hotplug: Couldn't find display for HWC1 id %d",
+                        hwc1DisplayId);
+                continue;
+            }
+            auto displayId = mHwc1DisplayMap[hwc1DisplayId];
+            auto connected = pending.second;
+            pendingHotplugs.emplace_back(displayId, connected);
+        }
+    }
+
+    // Call pending callbacks without the state lock held
+    lock.unlock();
+
+    if (hasPendingInvalidate) {
+        auto refresh = reinterpret_cast<HWC2_PFN_REFRESH>(pointer);
+        for (auto displayId : displayIds) {
+            refresh(callbackData, displayId);
+        }
+    }
+    if (!pendingVsyncs.empty()) {
+        auto vsync = reinterpret_cast<HWC2_PFN_VSYNC>(pointer);
+        for (auto& pendingVsync : pendingVsyncs) {
+            vsync(callbackData, pendingVsync.first, pendingVsync.second);
+        }
+    }
+    if (!pendingHotplugs.empty()) {
+        auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(pointer);
+        for (auto& pendingHotplug : pendingHotplugs) {
+            hotplug(callbackData, pendingHotplug.first, pendingHotplug.second);
+        }
+    }
+    return Error::None;
+}
+
+// Display functions
+
+std::atomic<hwc2_display_t> HWC2On1Adapter::Display::sNextId(1);
+
+HWC2On1Adapter::Display::Display(HWC2On1Adapter& device, HWC2::DisplayType type)
+  : mId(sNextId++),
+    mDevice(device),
+    mStateMutex(),
+    mHwc1RequestedContents(nullptr),
+    mRetireFence(),
+    mChanges(),
+    mHwc1Id(-1),
+    mConfigs(),
+    mActiveConfig(nullptr),
+    mActiveColorMode(static_cast<android_color_mode_t>(-1)),
+    mName(),
+    mType(type),
+    mPowerMode(PowerMode::Off),
+    mVsyncEnabled(Vsync::Invalid),
+    mClientTarget(),
+    mOutputBuffer(),
+    mHasColorTransform(false),
+    mLayers(),
+    mHwc1LayerMap(),
+    mNumAvailableRects(0),
+    mNextAvailableRect(nullptr),
+    mGeometryChanged(false)
+    {}
+
+Error HWC2On1Adapter::Display::acceptChanges() {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    if (!mChanges) {
+        ALOGV("[%" PRIu64 "] acceptChanges failed, not validated", mId);
+        return Error::NotValidated;
+    }
+
+    ALOGV("[%" PRIu64 "] acceptChanges", mId);
+
+    for (auto& change : mChanges->getTypeChanges()) {
+        auto layerId = change.first;
+        auto type = change.second;
+        if (mDevice.mLayers.count(layerId) == 0) {
+            // This should never happen but somehow does.
+            ALOGW("Cannot accept change for unknown layer (%" PRIu64 ")",
+                  layerId);
+            continue;
+        }
+        auto layer = mDevice.mLayers[layerId];
+        layer->setCompositionType(type);
+    }
+
+    mChanges->clearTypeChanges();
+
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Display::createLayer(hwc2_layer_t* outLayerId) {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    auto layer = *mLayers.emplace(std::make_shared<Layer>(*this));
+    mDevice.mLayers.emplace(std::make_pair(layer->getId(), layer));
+    *outLayerId = layer->getId();
+    ALOGV("[%" PRIu64 "] created layer %" PRIu64, mId, *outLayerId);
+    markGeometryChanged();
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Display::destroyLayer(hwc2_layer_t layerId) {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    const auto mapLayer = mDevice.mLayers.find(layerId);
+    if (mapLayer == mDevice.mLayers.end()) {
+        ALOGV("[%" PRIu64 "] destroyLayer(%" PRIu64 ") failed: no such layer",
+                mId, layerId);
+        return Error::BadLayer;
+    }
+    const auto layer = mapLayer->second;
+    mDevice.mLayers.erase(mapLayer);
+    const auto zRange = mLayers.equal_range(layer);
+    for (auto current = zRange.first; current != zRange.second; ++current) {
+        if (**current == *layer) {
+            current = mLayers.erase(current);
+            break;
+        }
+    }
+    ALOGV("[%" PRIu64 "] destroyed layer %" PRIu64, mId, layerId);
+    markGeometryChanged();
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getActiveConfig(hwc2_config_t* outConfig) {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    if (!mActiveConfig) {
+        ALOGV("[%" PRIu64 "] getActiveConfig --> %s", mId,
+                to_string(Error::BadConfig).c_str());
+        return Error::BadConfig;
+    }
+    auto configId = mActiveConfig->getId();
+    ALOGV("[%" PRIu64 "] getActiveConfig --> %u", mId, configId);
+    *outConfig = configId;
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getAttribute(hwc2_config_t configId,
+        Attribute attribute, int32_t* outValue) {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    if (configId > mConfigs.size() || !mConfigs[configId]->isOnDisplay(*this)) {
+        ALOGV("[%" PRIu64 "] getAttribute failed: bad config (%u)", mId,
+                configId);
+        return Error::BadConfig;
+    }
+    *outValue = mConfigs[configId]->getAttribute(attribute);
+    ALOGV("[%" PRIu64 "] getAttribute(%u, %s) --> %d", mId, configId,
+            to_string(attribute).c_str(), *outValue);
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getChangedCompositionTypes(
+        uint32_t* outNumElements, hwc2_layer_t* outLayers, int32_t* outTypes) {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    if (!mChanges) {
+        ALOGE("[%" PRIu64 "] getChangedCompositionTypes failed: not validated",
+                mId);
+        return Error::NotValidated;
+    }
+
+    if ((outLayers == nullptr) || (outTypes == nullptr)) {
+        *outNumElements = mChanges->getTypeChanges().size();
+        return Error::None;
+    }
+
+    uint32_t numWritten = 0;
+    for (const auto& element : mChanges->getTypeChanges()) {
+        if (numWritten == *outNumElements) {
+            break;
+        }
+        auto layerId = element.first;
+        auto intType = static_cast<int32_t>(element.second);
+        ALOGV("Adding %" PRIu64 " %s", layerId,
+                to_string(element.second).c_str());
+        outLayers[numWritten] = layerId;
+        outTypes[numWritten] = intType;
+        ++numWritten;
+    }
+    *outNumElements = numWritten;
+
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getColorModes(uint32_t* outNumModes,
+        int32_t* outModes) {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    if (!outModes) {
+        *outNumModes = mColorModes.size();
+        return Error::None;
+    }
+    uint32_t numModes = std::min(*outNumModes,
+            static_cast<uint32_t>(mColorModes.size()));
+    std::copy_n(mColorModes.cbegin(), numModes, outModes);
+    *outNumModes = numModes;
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getConfigs(uint32_t* outNumConfigs,
+        hwc2_config_t* outConfigs) {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    if (!outConfigs) {
+        *outNumConfigs = mConfigs.size();
+        return Error::None;
+    }
+    uint32_t numWritten = 0;
+    for (const auto& config : mConfigs) {
+        if (numWritten == *outNumConfigs) {
+            break;
+        }
+        outConfigs[numWritten] = config->getId();
+        ++numWritten;
+    }
+    *outNumConfigs = numWritten;
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getDozeSupport(int32_t* outSupport) {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    if (mDevice.mHwc1MinorVersion < 4 || mHwc1Id != 0) {
+        *outSupport = 0;
+    } else {
+        *outSupport = 1;
+    }
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getHdrCapabilities(uint32_t* outNumTypes,
+        int32_t* /*outTypes*/, float* /*outMaxLuminance*/,
+        float* /*outMaxAverageLuminance*/, float* /*outMinLuminance*/) {
+    // This isn't supported on HWC1, so per the HWC2 header, return numTypes = 0
+    *outNumTypes = 0;
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getName(uint32_t* outSize, char* outName) {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    if (!outName) {
+        *outSize = mName.size();
+        return Error::None;
+    }
+    auto numCopied = mName.copy(outName, *outSize);
+    *outSize = numCopied;
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getReleaseFences(uint32_t* outNumElements,
+        hwc2_layer_t* outLayers, int32_t* outFences) {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    uint32_t numWritten = 0;
+    bool outputsNonNull = (outLayers != nullptr) && (outFences != nullptr);
+    for (const auto& layer : mLayers) {
+        if (outputsNonNull && (numWritten == *outNumElements)) {
+            break;
+        }
+
+        auto releaseFence = layer->getReleaseFence();
+        if (releaseFence != MiniFence::NO_FENCE) {
+            if (outputsNonNull) {
+                outLayers[numWritten] = layer->getId();
+                outFences[numWritten] = releaseFence->dup();
+            }
+            ++numWritten;
+        }
+    }
+    *outNumElements = numWritten;
+
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getRequests(int32_t* outDisplayRequests,
+        uint32_t* outNumElements, hwc2_layer_t* outLayers,
+        int32_t* outLayerRequests) {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    if (!mChanges) {
+        return Error::NotValidated;
+    }
+
+    if (outLayers == nullptr || outLayerRequests == nullptr) {
+        *outNumElements = mChanges->getNumLayerRequests();
+        return Error::None;
+    }
+
+    // Display requests (HWC2::DisplayRequest) are not supported by hwc1:
+    // A hwc1 has always zero requests for the client.
+    *outDisplayRequests = 0;
+
+    uint32_t numWritten = 0;
+    for (const auto& request : mChanges->getLayerRequests()) {
+        if (numWritten == *outNumElements) {
+            break;
+        }
+        outLayers[numWritten] = request.first;
+        outLayerRequests[numWritten] = static_cast<int32_t>(request.second);
+        ++numWritten;
+    }
+
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getType(int32_t* outType) {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    *outType = static_cast<int32_t>(mType);
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Display::present(int32_t* outRetireFence) {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    if (mChanges) {
+        Error error = mDevice.setAllDisplays();
+        if (error != Error::None) {
+            ALOGE("[%" PRIu64 "] present: setAllDisplaysFailed (%s)", mId,
+                    to_string(error).c_str());
+            return error;
+        }
+    }
+
+    *outRetireFence = mRetireFence.get()->dup();
+    ALOGV("[%" PRIu64 "] present returning retire fence %d", mId,
+            *outRetireFence);
+
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Display::setActiveConfig(hwc2_config_t configId) {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    auto config = getConfig(configId);
+    if (!config) {
+        return Error::BadConfig;
+    }
+    if (config == mActiveConfig) {
+        return Error::None;
+    }
+
+    if (mDevice.mHwc1MinorVersion >= 4) {
+        uint32_t hwc1Id = 0;
+        auto error = config->getHwc1IdForColorMode(mActiveColorMode, &hwc1Id);
+        if (error != Error::None) {
+            return error;
+        }
+
+        int intError = mDevice.mHwc1Device->setActiveConfig(mDevice.mHwc1Device,
+                mHwc1Id, static_cast<int>(hwc1Id));
+        if (intError != 0) {
+            ALOGE("setActiveConfig: Failed to set active config on HWC1 (%d)",
+                intError);
+            return Error::BadConfig;
+        }
+        mActiveConfig = config;
+    }
+
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Display::setClientTarget(buffer_handle_t target,
+        int32_t acquireFence, int32_t /*dataspace*/, hwc_region_t /*damage*/) {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    ALOGV("[%" PRIu64 "] setClientTarget(%p, %d)", mId, target, acquireFence);
+    mClientTarget.setBuffer(target);
+    mClientTarget.setFence(acquireFence);
+    // dataspace and damage can't be used by HWC1, so ignore them
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Display::setColorMode(android_color_mode_t mode) {
+    std::unique_lock<std::recursive_mutex> lock (mStateMutex);
+
+    ALOGV("[%" PRIu64 "] setColorMode(%d)", mId, mode);
+
+    if (mode == mActiveColorMode) {
+        return Error::None;
+    }
+    if (mColorModes.count(mode) == 0) {
+        ALOGE("[%" PRIu64 "] Mode %d not found in mColorModes", mId, mode);
+        return Error::Unsupported;
+    }
+
+    uint32_t hwc1Config = 0;
+    auto error = mActiveConfig->getHwc1IdForColorMode(mode, &hwc1Config);
+    if (error != Error::None) {
+        return error;
+    }
+
+    ALOGV("[%" PRIu64 "] Setting HWC1 config %u", mId, hwc1Config);
+    int intError = mDevice.mHwc1Device->setActiveConfig(mDevice.mHwc1Device,
+            mHwc1Id, hwc1Config);
+    if (intError != 0) {
+        ALOGE("[%" PRIu64 "] Failed to set HWC1 config (%d)", mId, intError);
+        return Error::Unsupported;
+    }
+
+    mActiveColorMode = mode;
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Display::setColorTransform(android_color_transform_t hint) {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    ALOGV("%" PRIu64 "] setColorTransform(%d)", mId,
+            static_cast<int32_t>(hint));
+    mHasColorTransform = (hint != HAL_COLOR_TRANSFORM_IDENTITY);
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Display::setOutputBuffer(buffer_handle_t buffer,
+        int32_t releaseFence) {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    ALOGV("[%" PRIu64 "] setOutputBuffer(%p, %d)", mId, buffer, releaseFence);
+    mOutputBuffer.setBuffer(buffer);
+    mOutputBuffer.setFence(releaseFence);
+    return Error::None;
+}
+
+static bool isValid(PowerMode mode) {
+    switch (mode) {
+        case PowerMode::Off: // Fall-through
+        case PowerMode::DozeSuspend: // Fall-through
+        case PowerMode::Doze: // Fall-through
+        case PowerMode::On: return true;
+    }
+}
+
+static int getHwc1PowerMode(PowerMode mode) {
+    switch (mode) {
+        case PowerMode::Off: return HWC_POWER_MODE_OFF;
+        case PowerMode::DozeSuspend: return HWC_POWER_MODE_DOZE_SUSPEND;
+        case PowerMode::Doze: return HWC_POWER_MODE_DOZE;
+        case PowerMode::On: return HWC_POWER_MODE_NORMAL;
+    }
+}
+
+Error HWC2On1Adapter::Display::setPowerMode(PowerMode mode) {
+    if (!isValid(mode)) {
+        return Error::BadParameter;
+    }
+    if (mode == mPowerMode) {
+        return Error::None;
+    }
+
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    int error = 0;
+    if (mDevice.mHwc1MinorVersion < 4) {
+        error = mDevice.mHwc1Device->blank(mDevice.mHwc1Device, mHwc1Id,
+                mode == PowerMode::Off);
+    } else {
+        error = mDevice.mHwc1Device->setPowerMode(mDevice.mHwc1Device,
+                mHwc1Id, getHwc1PowerMode(mode));
+    }
+    ALOGE_IF(error != 0, "setPowerMode: Failed to set power mode on HWC1 (%d)",
+            error);
+
+    ALOGV("[%" PRIu64 "] setPowerMode(%s)", mId, to_string(mode).c_str());
+    mPowerMode = mode;
+    return Error::None;
+}
+
+static bool isValid(Vsync enable) {
+    switch (enable) {
+        case Vsync::Enable: // Fall-through
+        case Vsync::Disable: return true;
+        case Vsync::Invalid: return false;
+    }
+}
+
+Error HWC2On1Adapter::Display::setVsyncEnabled(Vsync enable) {
+    if (!isValid(enable)) {
+        return Error::BadParameter;
+    }
+    if (enable == mVsyncEnabled) {
+        return Error::None;
+    }
+
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    int error = mDevice.mHwc1Device->eventControl(mDevice.mHwc1Device,
+            mHwc1Id, HWC_EVENT_VSYNC, enable == Vsync::Enable);
+    ALOGE_IF(error != 0, "setVsyncEnabled: Failed to set vsync on HWC1 (%d)",
+            error);
+
+    mVsyncEnabled = enable;
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Display::validate(uint32_t* outNumTypes,
+        uint32_t* outNumRequests) {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    if (!mChanges) {
+        if (!mDevice.prepareAllDisplays()) {
+            return Error::BadDisplay;
+        }
+    } else {
+        ALOGE("Validate was called more than once!");
+    }
+
+    *outNumTypes = mChanges->getNumTypes();
+    *outNumRequests = mChanges->getNumLayerRequests();
+    ALOGV("[%" PRIu64 "] validate --> %u types, %u requests", mId, *outNumTypes,
+            *outNumRequests);
+    for (auto request : mChanges->getTypeChanges()) {
+        ALOGV("Layer %" PRIu64 " --> %s", request.first,
+                to_string(request.second).c_str());
+    }
+    return *outNumTypes > 0 ? Error::HasChanges : Error::None;
+}
+
+Error HWC2On1Adapter::Display::updateLayerZ(hwc2_layer_t layerId, uint32_t z) {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    const auto mapLayer = mDevice.mLayers.find(layerId);
+    if (mapLayer == mDevice.mLayers.end()) {
+        ALOGE("[%" PRIu64 "] updateLayerZ failed to find layer", mId);
+        return Error::BadLayer;
+    }
+
+    const auto layer = mapLayer->second;
+    const auto zRange = mLayers.equal_range(layer);
+    bool layerOnDisplay = false;
+    for (auto current = zRange.first; current != zRange.second; ++current) {
+        if (**current == *layer) {
+            if ((*current)->getZ() == z) {
+                // Don't change anything if the Z hasn't changed
+                return Error::None;
+            }
+            current = mLayers.erase(current);
+            layerOnDisplay = true;
+            break;
+        }
+    }
+
+    if (!layerOnDisplay) {
+        ALOGE("[%" PRIu64 "] updateLayerZ failed to find layer on display",
+                mId);
+        return Error::BadLayer;
+    }
+
+    layer->setZ(z);
+    mLayers.emplace(std::move(layer));
+    markGeometryChanged();
+
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getClientTargetSupport(uint32_t width, uint32_t height,
+                                      int32_t format, int32_t dataspace){
+    if (mActiveConfig == nullptr) {
+        return Error::Unsupported;
+    }
+
+    if (width == mActiveConfig->getAttribute(Attribute::Width) &&
+            height == mActiveConfig->getAttribute(Attribute::Height) &&
+            format == HAL_PIXEL_FORMAT_RGBA_8888 &&
+            dataspace == HAL_DATASPACE_UNKNOWN) {
+        return Error::None;
+    }
+
+    return Error::Unsupported;
+}
+
+static constexpr uint32_t ATTRIBUTES_WITH_COLOR[] = {
+    HWC_DISPLAY_VSYNC_PERIOD,
+    HWC_DISPLAY_WIDTH,
+    HWC_DISPLAY_HEIGHT,
+    HWC_DISPLAY_DPI_X,
+    HWC_DISPLAY_DPI_Y,
+    HWC_DISPLAY_COLOR_TRANSFORM,
+    HWC_DISPLAY_NO_ATTRIBUTE,
+};
+
+static constexpr uint32_t ATTRIBUTES_WITHOUT_COLOR[] = {
+    HWC_DISPLAY_VSYNC_PERIOD,
+    HWC_DISPLAY_WIDTH,
+    HWC_DISPLAY_HEIGHT,
+    HWC_DISPLAY_DPI_X,
+    HWC_DISPLAY_DPI_Y,
+    HWC_DISPLAY_NO_ATTRIBUTE,
+};
+
+static constexpr size_t NUM_ATTRIBUTES_WITH_COLOR =
+        sizeof(ATTRIBUTES_WITH_COLOR) / sizeof(uint32_t);
+static_assert(sizeof(ATTRIBUTES_WITH_COLOR) > sizeof(ATTRIBUTES_WITHOUT_COLOR),
+        "Attribute tables have unexpected sizes");
+
+static constexpr uint32_t ATTRIBUTE_MAP_WITH_COLOR[] = {
+    6, // HWC_DISPLAY_NO_ATTRIBUTE = 0
+    0, // HWC_DISPLAY_VSYNC_PERIOD = 1,
+    1, // HWC_DISPLAY_WIDTH = 2,
+    2, // HWC_DISPLAY_HEIGHT = 3,
+    3, // HWC_DISPLAY_DPI_X = 4,
+    4, // HWC_DISPLAY_DPI_Y = 5,
+    5, // HWC_DISPLAY_COLOR_TRANSFORM = 6,
+};
+
+static constexpr uint32_t ATTRIBUTE_MAP_WITHOUT_COLOR[] = {
+    5, // HWC_DISPLAY_NO_ATTRIBUTE = 0
+    0, // HWC_DISPLAY_VSYNC_PERIOD = 1,
+    1, // HWC_DISPLAY_WIDTH = 2,
+    2, // HWC_DISPLAY_HEIGHT = 3,
+    3, // HWC_DISPLAY_DPI_X = 4,
+    4, // HWC_DISPLAY_DPI_Y = 5,
+};
+
+template <uint32_t attribute>
+static constexpr bool attributesMatch()
+{
+    bool match = (attribute ==
+            ATTRIBUTES_WITH_COLOR[ATTRIBUTE_MAP_WITH_COLOR[attribute]]);
+    if (attribute == HWC_DISPLAY_COLOR_TRANSFORM) {
+        return match;
+    }
+
+    return match && (attribute ==
+            ATTRIBUTES_WITHOUT_COLOR[ATTRIBUTE_MAP_WITHOUT_COLOR[attribute]]);
+}
+static_assert(attributesMatch<HWC_DISPLAY_VSYNC_PERIOD>(),
+        "Tables out of sync");
+static_assert(attributesMatch<HWC_DISPLAY_WIDTH>(), "Tables out of sync");
+static_assert(attributesMatch<HWC_DISPLAY_HEIGHT>(), "Tables out of sync");
+static_assert(attributesMatch<HWC_DISPLAY_DPI_X>(), "Tables out of sync");
+static_assert(attributesMatch<HWC_DISPLAY_DPI_Y>(), "Tables out of sync");
+static_assert(attributesMatch<HWC_DISPLAY_COLOR_TRANSFORM>(),
+        "Tables out of sync");
+
+void HWC2On1Adapter::Display::populateConfigs() {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    ALOGV("[%" PRIu64 "] populateConfigs", mId);
+
+    if (mHwc1Id == -1) {
+        ALOGE("populateConfigs: HWC1 ID not set");
+        return;
+    }
+
+    const size_t MAX_NUM_CONFIGS = 128;
+    uint32_t configs[MAX_NUM_CONFIGS] = {};
+    size_t numConfigs = MAX_NUM_CONFIGS;
+    mDevice.mHwc1Device->getDisplayConfigs(mDevice.mHwc1Device, mHwc1Id,
+            configs, &numConfigs);
+
+    for (size_t c = 0; c < numConfigs; ++c) {
+        uint32_t hwc1ConfigId = configs[c];
+        auto newConfig = std::make_shared<Config>(*this);
+
+        int32_t values[NUM_ATTRIBUTES_WITH_COLOR] = {};
+        bool hasColor = true;
+        auto result = mDevice.mHwc1Device->getDisplayAttributes(
+                mDevice.mHwc1Device, mHwc1Id, hwc1ConfigId,
+                ATTRIBUTES_WITH_COLOR, values);
+        if (result != 0) {
+            mDevice.mHwc1Device->getDisplayAttributes(mDevice.mHwc1Device,
+                    mHwc1Id, hwc1ConfigId, ATTRIBUTES_WITHOUT_COLOR, values);
+            hasColor = false;
+        }
+
+        auto attributeMap = hasColor ?
+                ATTRIBUTE_MAP_WITH_COLOR : ATTRIBUTE_MAP_WITHOUT_COLOR;
+
+        newConfig->setAttribute(Attribute::VsyncPeriod,
+                values[attributeMap[HWC_DISPLAY_VSYNC_PERIOD]]);
+        newConfig->setAttribute(Attribute::Width,
+                values[attributeMap[HWC_DISPLAY_WIDTH]]);
+        newConfig->setAttribute(Attribute::Height,
+                values[attributeMap[HWC_DISPLAY_HEIGHT]]);
+        newConfig->setAttribute(Attribute::DpiX,
+                values[attributeMap[HWC_DISPLAY_DPI_X]]);
+        newConfig->setAttribute(Attribute::DpiY,
+                values[attributeMap[HWC_DISPLAY_DPI_Y]]);
+        if (hasColor) {
+            // In HWC1, color modes are referred to as color transforms. To avoid confusion with
+            // the HWC2 concept of color transforms, we internally refer to them as color modes for
+            // both HWC1 and 2.
+            newConfig->setAttribute(ColorMode,
+                    values[attributeMap[HWC_DISPLAY_COLOR_TRANSFORM]]);
+        }
+
+        // We can only do this after attempting to read the color mode
+        newConfig->setHwc1Id(hwc1ConfigId);
+
+        for (auto& existingConfig : mConfigs) {
+            if (existingConfig->merge(*newConfig)) {
+                ALOGV("Merged config %d with existing config %u: %s",
+                        hwc1ConfigId, existingConfig->getId(),
+                        existingConfig->toString().c_str());
+                newConfig.reset();
+                break;
+            }
+        }
+
+        // If it wasn't merged with any existing config, add it to the end
+        if (newConfig) {
+            newConfig->setId(static_cast<hwc2_config_t>(mConfigs.size()));
+            ALOGV("Found new config %u: %s", newConfig->getId(),
+                    newConfig->toString().c_str());
+            mConfigs.emplace_back(std::move(newConfig));
+        }
+    }
+
+    initializeActiveConfig();
+    populateColorModes();
+}
+
+void HWC2On1Adapter::Display::populateConfigs(uint32_t width, uint32_t height) {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    mConfigs.emplace_back(std::make_shared<Config>(*this));
+    auto& config = mConfigs[0];
+
+    config->setAttribute(Attribute::Width, static_cast<int32_t>(width));
+    config->setAttribute(Attribute::Height, static_cast<int32_t>(height));
+    config->setHwc1Id(0);
+    config->setId(0);
+    mActiveConfig = config;
+}
+
+bool HWC2On1Adapter::Display::prepare() {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    // Only prepare display contents for displays HWC1 knows about
+    if (mHwc1Id == -1) {
+        return true;
+    }
+
+    // It doesn't make sense to prepare a display for which there is no active
+    // config, so return early
+    if (!mActiveConfig) {
+        ALOGE("[%" PRIu64 "] Attempted to prepare, but no config active", mId);
+        return false;
+    }
+
+    allocateRequestedContents();
+    assignHwc1LayerIds();
+
+    mHwc1RequestedContents->retireFenceFd = -1;
+    mHwc1RequestedContents->flags = 0;
+    if (mGeometryChanged) {
+        mHwc1RequestedContents->flags |= HWC_GEOMETRY_CHANGED;
+    }
+    mHwc1RequestedContents->outbuf = mOutputBuffer.getBuffer();
+    mHwc1RequestedContents->outbufAcquireFenceFd = mOutputBuffer.getFence();
+
+    // +1 is for framebuffer target layer.
+    mHwc1RequestedContents->numHwLayers = mLayers.size() + 1;
+    for (auto& layer : mLayers) {
+        auto& hwc1Layer = mHwc1RequestedContents->hwLayers[layer->getHwc1Id()];
+        hwc1Layer.releaseFenceFd = -1;
+        hwc1Layer.acquireFenceFd = -1;
+        ALOGV("Applying states for layer %" PRIu64 " ", layer->getId());
+        layer->applyState(hwc1Layer);
+    }
+
+    prepareFramebufferTarget();
+
+    resetGeometryMarker();
+
+    return true;
+}
+
+void HWC2On1Adapter::Display::generateChanges() {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    mChanges.reset(new Changes);
+
+    size_t numLayers = mHwc1RequestedContents->numHwLayers;
+    for (size_t hwc1Id = 0; hwc1Id < numLayers; ++hwc1Id) {
+        const auto& receivedLayer = mHwc1RequestedContents->hwLayers[hwc1Id];
+        if (mHwc1LayerMap.count(hwc1Id) == 0) {
+            ALOGE_IF(receivedLayer.compositionType != HWC_FRAMEBUFFER_TARGET,
+                    "generateChanges: HWC1 layer %zd doesn't have a"
+                    " matching HWC2 layer, and isn't the framebuffer target",
+                    hwc1Id);
+            continue;
+        }
+
+        Layer& layer = *mHwc1LayerMap[hwc1Id];
+        updateTypeChanges(receivedLayer, layer);
+        updateLayerRequests(receivedLayer, layer);
+    }
+}
+
+bool HWC2On1Adapter::Display::hasChanges() const {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+    return mChanges != nullptr;
+}
+
+Error HWC2On1Adapter::Display::set(hwc_display_contents_1& hwcContents) {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    if (!mChanges || (mChanges->getNumTypes() > 0)) {
+        ALOGE("[%" PRIu64 "] set failed: not validated", mId);
+        return Error::NotValidated;
+    }
+
+    // Set up the client/framebuffer target
+    auto numLayers = hwcContents.numHwLayers;
+
+    // Close acquire fences on FRAMEBUFFER layers, since they will not be used
+    // by HWC
+    for (size_t l = 0; l < numLayers - 1; ++l) {
+        auto& layer = hwcContents.hwLayers[l];
+        if (layer.compositionType == HWC_FRAMEBUFFER) {
+            ALOGV("Closing fence %d for layer %zd", layer.acquireFenceFd, l);
+            close(layer.acquireFenceFd);
+            layer.acquireFenceFd = -1;
+        }
+    }
+
+    auto& clientTargetLayer = hwcContents.hwLayers[numLayers - 1];
+    if (clientTargetLayer.compositionType == HWC_FRAMEBUFFER_TARGET) {
+        clientTargetLayer.handle = mClientTarget.getBuffer();
+        clientTargetLayer.acquireFenceFd = mClientTarget.getFence();
+    } else {
+        ALOGE("[%" PRIu64 "] set: last HWC layer wasn't FRAMEBUFFER_TARGET",
+                mId);
+    }
+
+    mChanges.reset();
+
+    return Error::None;
+}
+
+void HWC2On1Adapter::Display::addRetireFence(int fenceFd) {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+    mRetireFence.add(fenceFd);
+}
+
+void HWC2On1Adapter::Display::addReleaseFences(
+        const hwc_display_contents_1_t& hwcContents) {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    size_t numLayers = hwcContents.numHwLayers;
+    for (size_t hwc1Id = 0; hwc1Id < numLayers; ++hwc1Id) {
+        const auto& receivedLayer = hwcContents.hwLayers[hwc1Id];
+        if (mHwc1LayerMap.count(hwc1Id) == 0) {
+            if (receivedLayer.compositionType != HWC_FRAMEBUFFER_TARGET) {
+                ALOGE("addReleaseFences: HWC1 layer %zd doesn't have a"
+                        " matching HWC2 layer, and isn't the framebuffer"
+                        " target", hwc1Id);
+            }
+            // Close the framebuffer target release fence since we will use the
+            // display retire fence instead
+            if (receivedLayer.releaseFenceFd != -1) {
+                close(receivedLayer.releaseFenceFd);
+            }
+            continue;
+        }
+
+        Layer& layer = *mHwc1LayerMap[hwc1Id];
+        ALOGV("Adding release fence %d to layer %" PRIu64,
+                receivedLayer.releaseFenceFd, layer.getId());
+        layer.addReleaseFence(receivedLayer.releaseFenceFd);
+    }
+}
+
+bool HWC2On1Adapter::Display::hasColorTransform() const {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+    return mHasColorTransform;
+}
+
+static std::string hwc1CompositionString(int32_t type) {
+    switch (type) {
+        case HWC_FRAMEBUFFER: return "Framebuffer";
+        case HWC_OVERLAY: return "Overlay";
+        case HWC_BACKGROUND: return "Background";
+        case HWC_FRAMEBUFFER_TARGET: return "FramebufferTarget";
+        case HWC_SIDEBAND: return "Sideband";
+        case HWC_CURSOR_OVERLAY: return "CursorOverlay";
+        default:
+            return std::string("Unknown (") + std::to_string(type) + ")";
+    }
+}
+
+static std::string hwc1TransformString(int32_t transform) {
+    switch (transform) {
+        case 0: return "None";
+        case HWC_TRANSFORM_FLIP_H: return "FlipH";
+        case HWC_TRANSFORM_FLIP_V: return "FlipV";
+        case HWC_TRANSFORM_ROT_90: return "Rotate90";
+        case HWC_TRANSFORM_ROT_180: return "Rotate180";
+        case HWC_TRANSFORM_ROT_270: return "Rotate270";
+        case HWC_TRANSFORM_FLIP_H_ROT_90: return "FlipHRotate90";
+        case HWC_TRANSFORM_FLIP_V_ROT_90: return "FlipVRotate90";
+        default:
+            return std::string("Unknown (") + std::to_string(transform) + ")";
+    }
+}
+
+static std::string hwc1BlendModeString(int32_t mode) {
+    switch (mode) {
+        case HWC_BLENDING_NONE: return "None";
+        case HWC_BLENDING_PREMULT: return "Premultiplied";
+        case HWC_BLENDING_COVERAGE: return "Coverage";
+        default:
+            return std::string("Unknown (") + std::to_string(mode) + ")";
+    }
+}
+
+static std::string rectString(hwc_rect_t rect) {
+    std::stringstream output;
+    output << "[" << rect.left << ", " << rect.top << ", ";
+    output << rect.right << ", " << rect.bottom << "]";
+    return output.str();
+}
+
+static std::string approximateFloatString(float f) {
+    if (static_cast<int32_t>(f) == f) {
+        return std::to_string(static_cast<int32_t>(f));
+    }
+    int32_t truncated = static_cast<int32_t>(f * 10);
+    bool approximate = (static_cast<float>(truncated) != f * 10);
+    const size_t BUFFER_SIZE = 32;
+    char buffer[BUFFER_SIZE] = {};
+    auto bytesWritten = snprintf(buffer, BUFFER_SIZE,
+            "%s%.1f", approximate ? "~" : "", f);
+    return std::string(buffer, bytesWritten);
+}
+
+static std::string frectString(hwc_frect_t frect) {
+    std::stringstream output;
+    output << "[" << approximateFloatString(frect.left) << ", ";
+    output << approximateFloatString(frect.top) << ", ";
+    output << approximateFloatString(frect.right) << ", ";
+    output << approximateFloatString(frect.bottom) << "]";
+    return output.str();
+}
+
+static std::string colorString(hwc_color_t color) {
+    std::stringstream output;
+    output << "RGBA [";
+    output << static_cast<int32_t>(color.r) << ", ";
+    output << static_cast<int32_t>(color.g) << ", ";
+    output << static_cast<int32_t>(color.b) << ", ";
+    output << static_cast<int32_t>(color.a) << "]";
+    return output.str();
+}
+
+static std::string alphaString(float f) {
+    const size_t BUFFER_SIZE = 8;
+    char buffer[BUFFER_SIZE] = {};
+    auto bytesWritten = snprintf(buffer, BUFFER_SIZE, "%.3f", f);
+    return std::string(buffer, bytesWritten);
+}
+
+static std::string to_string(const hwc_layer_1_t& hwcLayer,
+        int32_t hwc1MinorVersion) {
+    const char* fill = "          ";
+
+    std::stringstream output;
+
+    output << "  Composition: " <<
+            hwc1CompositionString(hwcLayer.compositionType);
+
+    if (hwcLayer.compositionType == HWC_BACKGROUND) {
+        output << "  Color: " << colorString(hwcLayer.backgroundColor) << '\n';
+    } else if (hwcLayer.compositionType == HWC_SIDEBAND) {
+        output << "  Stream: " << hwcLayer.sidebandStream << '\n';
+    } else {
+        output << "  Buffer: " << hwcLayer.handle << "/" <<
+                hwcLayer.acquireFenceFd << '\n';
+    }
+
+    output << fill << "Display frame: " << rectString(hwcLayer.displayFrame) <<
+            '\n';
+
+    output << fill << "Source crop: ";
+    if (hwc1MinorVersion >= 3) {
+        output << frectString(hwcLayer.sourceCropf) << '\n';
+    } else {
+        output << rectString(hwcLayer.sourceCropi) << '\n';
+    }
+
+    output << fill << "Transform: " << hwc1TransformString(hwcLayer.transform);
+    output << "  Blend mode: " << hwc1BlendModeString(hwcLayer.blending);
+    if (hwcLayer.planeAlpha != 0xFF) {
+        output << "  Alpha: " << alphaString(hwcLayer.planeAlpha / 255.0f);
+    }
+    output << '\n';
+
+    if (hwcLayer.hints != 0) {
+        output << fill << "Hints:";
+        if ((hwcLayer.hints & HWC_HINT_TRIPLE_BUFFER) != 0) {
+            output << " TripleBuffer";
+        }
+        if ((hwcLayer.hints & HWC_HINT_CLEAR_FB) != 0) {
+            output << " ClearFB";
+        }
+        output << '\n';
+    }
+
+    if (hwcLayer.flags != 0) {
+        output << fill << "Flags:";
+        if ((hwcLayer.flags & HWC_SKIP_LAYER) != 0) {
+            output << " SkipLayer";
+        }
+        if ((hwcLayer.flags & HWC_IS_CURSOR_LAYER) != 0) {
+            output << " IsCursorLayer";
+        }
+        output << '\n';
+    }
+
+    return output.str();
+}
+
+static std::string to_string(const hwc_display_contents_1_t& hwcContents,
+        int32_t hwc1MinorVersion) {
+    const char* fill = "      ";
+
+    std::stringstream output;
+    output << fill << "Geometry changed: " <<
+            ((hwcContents.flags & HWC_GEOMETRY_CHANGED) != 0 ? "Y\n" : "N\n");
+
+    output << fill << hwcContents.numHwLayers << " Layer" <<
+            ((hwcContents.numHwLayers == 1) ? "\n" : "s\n");
+    for (size_t layer = 0; layer < hwcContents.numHwLayers; ++layer) {
+        output << fill << "  Layer " << layer;
+        output << to_string(hwcContents.hwLayers[layer], hwc1MinorVersion);
+    }
+
+    if (hwcContents.outbuf != nullptr) {
+        output << fill << "Output buffer: " << hwcContents.outbuf << "/" <<
+                hwcContents.outbufAcquireFenceFd << '\n';
+    }
+
+    return output.str();
+}
+
+std::string HWC2On1Adapter::Display::dump() const {
+    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+    std::stringstream output;
+
+    output << "  Display " << mId << ": ";
+    output << to_string(mType) << "  ";
+    output << "HWC1 ID: " << mHwc1Id << "  ";
+    output << "Power mode: " << to_string(mPowerMode) << "  ";
+    output << "Vsync: " << to_string(mVsyncEnabled) << '\n';
+
+    output << "    Color modes [active]:";
+    for (const auto& mode : mColorModes) {
+        if (mode == mActiveColorMode) {
+            output << " [" << mode << ']';
+        } else {
+            output << " " << mode;
+        }
+    }
+    output << '\n';
+
+    output << "    " << mConfigs.size() << " Config" <<
+            (mConfigs.size() == 1 ? "" : "s") << " (* active)\n";
+    for (const auto& config : mConfigs) {
+        output << (config == mActiveConfig ? "    * " : "      ");
+        output << config->toString(true) << '\n';
+    }
+
+    output << "    " << mLayers.size() << " Layer" <<
+            (mLayers.size() == 1 ? "" : "s") << '\n';
+    for (const auto& layer : mLayers) {
+        output << layer->dump();
+    }
+
+    output << "    Client target: " << mClientTarget.getBuffer() << '\n';
+
+    if (mOutputBuffer.getBuffer() != nullptr) {
+        output << "    Output buffer: " << mOutputBuffer.getBuffer() << '\n';
+    }
+
+    if (mHwc1RequestedContents) {
+        output << "    Last requested HWC1 state\n";
+        output << to_string(*mHwc1RequestedContents, mDevice.mHwc1MinorVersion);
+    }
+
+    return output.str();
+}
+
+hwc_rect_t* HWC2On1Adapter::Display::GetRects(size_t numRects) {
+    if (numRects == 0) {
+        return nullptr;
+    }
+
+    if (numRects > mNumAvailableRects) {
+        // This should NEVER happen since we calculated how many rects the
+        // display would need.
+        ALOGE("Rect allocation failure! SF is likely to crash soon!");
+        return nullptr;
+
+    }
+    hwc_rect_t* rects = mNextAvailableRect;
+    mNextAvailableRect += numRects;
+    mNumAvailableRects -= numRects;
+    return rects;
+}
+
+hwc_display_contents_1* HWC2On1Adapter::Display::getDisplayContents() {
+    return mHwc1RequestedContents.get();
+}
+
+void HWC2On1Adapter::Display::Config::setAttribute(HWC2::Attribute attribute,
+        int32_t value) {
+    mAttributes[attribute] = value;
+}
+
+int32_t HWC2On1Adapter::Display::Config::getAttribute(Attribute attribute) const {
+    if (mAttributes.count(attribute) == 0) {
+        return -1;
+    }
+    return mAttributes.at(attribute);
+}
+
+void HWC2On1Adapter::Display::Config::setHwc1Id(uint32_t id) {
+    android_color_mode_t colorMode = static_cast<android_color_mode_t>(getAttribute(ColorMode));
+    mHwc1Ids.emplace(colorMode, id);
+}
+
+bool HWC2On1Adapter::Display::Config::hasHwc1Id(uint32_t id) const {
+    for (const auto& idPair : mHwc1Ids) {
+        if (id == idPair.second) {
+            return true;
+        }
+    }
+    return false;
+}
+
+Error HWC2On1Adapter::Display::Config::getColorModeForHwc1Id(
+        uint32_t id, android_color_mode_t* outMode) const {
+    for (const auto& idPair : mHwc1Ids) {
+        if (id == idPair.second) {
+            *outMode = idPair.first;
+            return Error::None;
+        }
+    }
+    ALOGE("Unable to find color mode for HWC ID %" PRIu32 " on config %u", id, mId);
+    return Error::BadParameter;
+}
+
+Error HWC2On1Adapter::Display::Config::getHwc1IdForColorMode(android_color_mode_t mode,
+        uint32_t* outId) const {
+    for (const auto& idPair : mHwc1Ids) {
+        if (mode == idPair.first) {
+            *outId = idPair.second;
+            return Error::None;
+        }
+    }
+    ALOGE("Unable to find HWC1 ID for color mode %d on config %u", mode, mId);
+    return Error::BadParameter;
+}
+
+bool HWC2On1Adapter::Display::Config::merge(const Config& other) {
+    auto attributes = {HWC2::Attribute::Width, HWC2::Attribute::Height,
+            HWC2::Attribute::VsyncPeriod, HWC2::Attribute::DpiX,
+            HWC2::Attribute::DpiY};
+    for (auto attribute : attributes) {
+        if (getAttribute(attribute) != other.getAttribute(attribute)) {
+            return false;
+        }
+    }
+    android_color_mode_t otherColorMode =
+            static_cast<android_color_mode_t>(other.getAttribute(ColorMode));
+    if (mHwc1Ids.count(otherColorMode) != 0) {
+        ALOGE("Attempted to merge two configs (%u and %u) which appear to be "
+                "identical", mHwc1Ids.at(otherColorMode),
+                other.mHwc1Ids.at(otherColorMode));
+        return false;
+    }
+    mHwc1Ids.emplace(otherColorMode,
+            other.mHwc1Ids.at(otherColorMode));
+    return true;
+}
+
+std::set<android_color_mode_t> HWC2On1Adapter::Display::Config::getColorModes() const {
+    std::set<android_color_mode_t> colorModes;
+    for (const auto& idPair : mHwc1Ids) {
+        colorModes.emplace(idPair.first);
+    }
+    return colorModes;
+}
+
+std::string HWC2On1Adapter::Display::Config::toString(bool splitLine) const {
+    std::string output;
+
+    const size_t BUFFER_SIZE = 100;
+    char buffer[BUFFER_SIZE] = {};
+    auto writtenBytes = snprintf(buffer, BUFFER_SIZE,
+            "%u x %u", mAttributes.at(HWC2::Attribute::Width),
+            mAttributes.at(HWC2::Attribute::Height));
+    output.append(buffer, writtenBytes);
+
+    if (mAttributes.count(HWC2::Attribute::VsyncPeriod) != 0) {
+        std::memset(buffer, 0, BUFFER_SIZE);
+        writtenBytes = snprintf(buffer, BUFFER_SIZE, " @ %.1f Hz",
+                1e9 / mAttributes.at(HWC2::Attribute::VsyncPeriod));
+        output.append(buffer, writtenBytes);
+    }
+
+    if (mAttributes.count(HWC2::Attribute::DpiX) != 0 &&
+            mAttributes.at(HWC2::Attribute::DpiX) != -1) {
+        std::memset(buffer, 0, BUFFER_SIZE);
+        writtenBytes = snprintf(buffer, BUFFER_SIZE,
+                ", DPI: %.1f x %.1f",
+                mAttributes.at(HWC2::Attribute::DpiX) / 1000.0f,
+                mAttributes.at(HWC2::Attribute::DpiY) / 1000.0f);
+        output.append(buffer, writtenBytes);
+    }
+
+    std::memset(buffer, 0, BUFFER_SIZE);
+    if (splitLine) {
+        writtenBytes = snprintf(buffer, BUFFER_SIZE,
+                "\n        HWC1 ID/Color transform:");
+    } else {
+        writtenBytes = snprintf(buffer, BUFFER_SIZE,
+                ", HWC1 ID/Color transform:");
+    }
+    output.append(buffer, writtenBytes);
+
+
+    for (const auto& id : mHwc1Ids) {
+        android_color_mode_t colorMode = id.first;
+        uint32_t hwc1Id = id.second;
+        std::memset(buffer, 0, BUFFER_SIZE);
+        if (colorMode == mDisplay.mActiveColorMode) {
+            writtenBytes = snprintf(buffer, BUFFER_SIZE, " [%u/%d]", hwc1Id,
+                    colorMode);
+        } else {
+            writtenBytes = snprintf(buffer, BUFFER_SIZE, " %u/%d", hwc1Id,
+                    colorMode);
+        }
+        output.append(buffer, writtenBytes);
+    }
+
+    return output;
+}
+
+std::shared_ptr<const HWC2On1Adapter::Display::Config>
+        HWC2On1Adapter::Display::getConfig(hwc2_config_t configId) const {
+    if (configId > mConfigs.size() || !mConfigs[configId]->isOnDisplay(*this)) {
+        return nullptr;
+    }
+    return mConfigs[configId];
+}
+
+void HWC2On1Adapter::Display::populateColorModes() {
+    mColorModes = mConfigs[0]->getColorModes();
+    for (const auto& config : mConfigs) {
+        std::set<android_color_mode_t> intersection;
+        auto configModes = config->getColorModes();
+        std::set_intersection(mColorModes.cbegin(), mColorModes.cend(),
+                configModes.cbegin(), configModes.cend(),
+                std::inserter(intersection, intersection.begin()));
+        std::swap(intersection, mColorModes);
+    }
+}
+
+void HWC2On1Adapter::Display::initializeActiveConfig() {
+    if (mDevice.mHwc1Device->getActiveConfig == nullptr) {
+        ALOGV("getActiveConfig is null, choosing config 0");
+        mActiveConfig = mConfigs[0];
+        mActiveColorMode = HAL_COLOR_MODE_NATIVE;
+        return;
+    }
+
+    auto activeConfig = mDevice.mHwc1Device->getActiveConfig(
+            mDevice.mHwc1Device, mHwc1Id);
+
+    // Some devices startup without an activeConfig:
+    // We need to set one ourselves.
+    if (activeConfig == HWC_ERROR) {
+        ALOGV("There is no active configuration: Picking the first one: 0.");
+        const int defaultIndex = 0;
+        mDevice.mHwc1Device->setActiveConfig(mDevice.mHwc1Device, mHwc1Id, defaultIndex);
+        activeConfig = defaultIndex;
+    }
+
+    for (const auto& config : mConfigs) {
+        if (config->hasHwc1Id(activeConfig)) {
+            ALOGE("Setting active config to %d for HWC1 config %u", config->getId(), activeConfig);
+            mActiveConfig = config;
+            if (config->getColorModeForHwc1Id(activeConfig, &mActiveColorMode) != Error::None) {
+                // This should never happen since we checked for the config's presence before
+                // setting it as active.
+                ALOGE("Unable to find color mode for active HWC1 config %d", config->getId());
+                mActiveColorMode = HAL_COLOR_MODE_NATIVE;
+            }
+            break;
+        }
+    }
+    if (!mActiveConfig) {
+        ALOGV("Unable to find active HWC1 config %u, defaulting to "
+                "config 0", activeConfig);
+        mActiveConfig = mConfigs[0];
+        mActiveColorMode = HAL_COLOR_MODE_NATIVE;
+    }
+
+
+
+
+}
+
+void HWC2On1Adapter::Display::allocateRequestedContents() {
+    // What needs to be allocated:
+    // 1 hwc_display_contents_1_t
+    // 1 hwc_layer_1_t for each layer
+    // 1 hwc_rect_t for each layer's surfaceDamage
+    // 1 hwc_rect_t for each layer's visibleRegion
+    // 1 hwc_layer_1_t for the framebuffer
+    // 1 hwc_rect_t for the framebuffer's visibleRegion
+
+    // Count # of surfaceDamage
+    size_t numSurfaceDamages = 0;
+    for (const auto& layer : mLayers) {
+        numSurfaceDamages += layer->getNumSurfaceDamages();
+    }
+
+    // Count # of visibleRegions (start at 1 for mandatory framebuffer target
+    // region)
+    size_t numVisibleRegion = 1;
+    for (const auto& layer : mLayers) {
+        numVisibleRegion += layer->getNumVisibleRegions();
+    }
+
+    size_t numRects = numVisibleRegion + numSurfaceDamages;
+    auto numLayers = mLayers.size() + 1;
+    size_t size = sizeof(hwc_display_contents_1_t) +
+            sizeof(hwc_layer_1_t) * numLayers +
+            sizeof(hwc_rect_t) * numRects;
+    auto contents = static_cast<hwc_display_contents_1_t*>(std::calloc(size, 1));
+    mHwc1RequestedContents.reset(contents);
+    mNextAvailableRect = reinterpret_cast<hwc_rect_t*>(&contents->hwLayers[numLayers]);
+    mNumAvailableRects = numRects;
+}
+
+void HWC2On1Adapter::Display::assignHwc1LayerIds() {
+    mHwc1LayerMap.clear();
+    size_t nextHwc1Id = 0;
+    for (auto& layer : mLayers) {
+        mHwc1LayerMap[nextHwc1Id] = layer;
+        layer->setHwc1Id(nextHwc1Id++);
+    }
+}
+
+void HWC2On1Adapter::Display::updateTypeChanges(const hwc_layer_1_t& hwc1Layer,
+        const Layer& layer) {
+    auto layerId = layer.getId();
+    switch (hwc1Layer.compositionType) {
+        case HWC_FRAMEBUFFER:
+            if (layer.getCompositionType() != Composition::Client) {
+                mChanges->addTypeChange(layerId, Composition::Client);
+            }
+            break;
+        case HWC_OVERLAY:
+            if (layer.getCompositionType() != Composition::Device) {
+                mChanges->addTypeChange(layerId, Composition::Device);
+            }
+            break;
+        case HWC_BACKGROUND:
+            ALOGE_IF(layer.getCompositionType() != Composition::SolidColor,
+                    "updateTypeChanges: HWC1 requested BACKGROUND, but HWC2"
+                    " wasn't expecting SolidColor");
+            break;
+        case HWC_FRAMEBUFFER_TARGET:
+            // Do nothing, since it shouldn't be modified by HWC1
+            break;
+        case HWC_SIDEBAND:
+            ALOGE_IF(layer.getCompositionType() != Composition::Sideband,
+                    "updateTypeChanges: HWC1 requested SIDEBAND, but HWC2"
+                    " wasn't expecting Sideband");
+            break;
+        case HWC_CURSOR_OVERLAY:
+            ALOGE_IF(layer.getCompositionType() != Composition::Cursor,
+                    "updateTypeChanges: HWC1 requested CURSOR_OVERLAY, but"
+                    " HWC2 wasn't expecting Cursor");
+            break;
+    }
+}
+
+void HWC2On1Adapter::Display::updateLayerRequests(
+        const hwc_layer_1_t& hwc1Layer, const Layer& layer) {
+    if ((hwc1Layer.hints & HWC_HINT_CLEAR_FB) != 0) {
+        mChanges->addLayerRequest(layer.getId(),
+                LayerRequest::ClearClientTarget);
+    }
+}
+
+void HWC2On1Adapter::Display::prepareFramebufferTarget() {
+    // We check that mActiveConfig is valid in Display::prepare
+    int32_t width = mActiveConfig->getAttribute(Attribute::Width);
+    int32_t height = mActiveConfig->getAttribute(Attribute::Height);
+
+    auto& hwc1Target = mHwc1RequestedContents->hwLayers[mLayers.size()];
+    hwc1Target.compositionType = HWC_FRAMEBUFFER_TARGET;
+    hwc1Target.releaseFenceFd = -1;
+    hwc1Target.hints = 0;
+    hwc1Target.flags = 0;
+    hwc1Target.transform = 0;
+    hwc1Target.blending = HWC_BLENDING_PREMULT;
+    if (mDevice.getHwc1MinorVersion() < 3) {
+        hwc1Target.sourceCropi = {0, 0, width, height};
+    } else {
+        hwc1Target.sourceCropf = {0.0f, 0.0f, static_cast<float>(width),
+                static_cast<float>(height)};
+    }
+    hwc1Target.displayFrame = {0, 0, width, height};
+    hwc1Target.planeAlpha = 255;
+
+    hwc1Target.visibleRegionScreen.numRects = 1;
+    hwc_rect_t* rects = GetRects(1);
+    rects[0].left = 0;
+    rects[0].top = 0;
+    rects[0].right = width;
+    rects[0].bottom = height;
+    hwc1Target.visibleRegionScreen.rects = rects;
+
+    // We will set this to the correct value in set
+    hwc1Target.acquireFenceFd = -1;
+}
+
+// Layer functions
+
+std::atomic<hwc2_layer_t> HWC2On1Adapter::Layer::sNextId(1);
+
+HWC2On1Adapter::Layer::Layer(Display& display)
+  : mId(sNextId++),
+    mDisplay(display),
+    mBuffer(),
+    mSurfaceDamage(),
+    mBlendMode(BlendMode::None),
+    mColor({0, 0, 0, 0}),
+    mCompositionType(Composition::Invalid),
+    mDisplayFrame({0, 0, -1, -1}),
+    mPlaneAlpha(0.0f),
+    mSidebandStream(nullptr),
+    mSourceCrop({0.0f, 0.0f, -1.0f, -1.0f}),
+    mTransform(Transform::None),
+    mVisibleRegion(),
+    mZ(0),
+    mReleaseFence(),
+    mHwc1Id(0),
+    mHasUnsupportedPlaneAlpha(false) {}
+
+bool HWC2On1Adapter::SortLayersByZ::operator()(
+        const std::shared_ptr<Layer>& lhs, const std::shared_ptr<Layer>& rhs) {
+    return lhs->getZ() < rhs->getZ();
+}
+
+Error HWC2On1Adapter::Layer::setBuffer(buffer_handle_t buffer,
+        int32_t acquireFence) {
+    ALOGV("Setting acquireFence to %d for layer %" PRIu64, acquireFence, mId);
+    mBuffer.setBuffer(buffer);
+    mBuffer.setFence(acquireFence);
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setCursorPosition(int32_t x, int32_t y) {
+    if (mCompositionType != Composition::Cursor) {
+        return Error::BadLayer;
+    }
+
+    if (mDisplay.hasChanges()) {
+        return Error::NotValidated;
+    }
+
+    auto displayId = mDisplay.getHwc1Id();
+    auto hwc1Device = mDisplay.getDevice().getHwc1Device();
+    hwc1Device->setCursorPositionAsync(hwc1Device, displayId, x, y);
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setSurfaceDamage(hwc_region_t damage) {
+    // HWC1 supports surface damage starting only with version 1.5.
+    if (mDisplay.getDevice().mHwc1MinorVersion < 5) {
+        return Error::None;
+    }
+    mSurfaceDamage.resize(damage.numRects);
+    std::copy_n(damage.rects, damage.numRects, mSurfaceDamage.begin());
+    return Error::None;
+}
+
+// Layer state functions
+
+Error HWC2On1Adapter::Layer::setBlendMode(BlendMode mode) {
+    mBlendMode = mode;
+    mDisplay.markGeometryChanged();
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setColor(hwc_color_t color) {
+    mColor = color;
+    mDisplay.markGeometryChanged();
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setCompositionType(Composition type) {
+    mCompositionType = type;
+    mDisplay.markGeometryChanged();
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setDataspace(android_dataspace_t) {
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setDisplayFrame(hwc_rect_t frame) {
+    mDisplayFrame = frame;
+    mDisplay.markGeometryChanged();
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setPlaneAlpha(float alpha) {
+    mPlaneAlpha = alpha;
+    mDisplay.markGeometryChanged();
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setSidebandStream(const native_handle_t* stream) {
+    mSidebandStream = stream;
+    mDisplay.markGeometryChanged();
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setSourceCrop(hwc_frect_t crop) {
+    mSourceCrop = crop;
+    mDisplay.markGeometryChanged();
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setTransform(Transform transform) {
+    mTransform = transform;
+    mDisplay.markGeometryChanged();
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setVisibleRegion(hwc_region_t visible) {
+    mVisibleRegion.resize(visible.numRects);
+    std::copy_n(visible.rects, visible.numRects, mVisibleRegion.begin());
+    mDisplay.markGeometryChanged();
+    return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setZ(uint32_t z) {
+    mZ = z;
+    return Error::None;
+}
+
+void HWC2On1Adapter::Layer::addReleaseFence(int fenceFd) {
+    ALOGV("addReleaseFence %d to layer %" PRIu64, fenceFd, mId);
+    mReleaseFence.add(fenceFd);
+}
+
+const sp<MiniFence>& HWC2On1Adapter::Layer::getReleaseFence() const {
+    return mReleaseFence.get();
+}
+
+void HWC2On1Adapter::Layer::applyState(hwc_layer_1_t& hwc1Layer) {
+    applyCommonState(hwc1Layer);
+    applyCompositionType(hwc1Layer);
+    switch (mCompositionType) {
+        case Composition::SolidColor : applySolidColorState(hwc1Layer); break;
+        case Composition::Sideband : applySidebandState(hwc1Layer); break;
+        default: applyBufferState(hwc1Layer); break;
+    }
+}
+
+static std::string regionStrings(const std::vector<hwc_rect_t>& visibleRegion,
+        const std::vector<hwc_rect_t>& surfaceDamage) {
+    std::string regions;
+    regions += "        Visible Region";
+    regions.resize(40, ' ');
+    regions += "Surface Damage\n";
+
+    size_t numPrinted = 0;
+    size_t maxSize = std::max(visibleRegion.size(), surfaceDamage.size());
+    while (numPrinted < maxSize) {
+        std::string line("        ");
+        if (visibleRegion.empty() && numPrinted == 0) {
+            line += "None";
+        } else if (numPrinted < visibleRegion.size()) {
+            line += rectString(visibleRegion[numPrinted]);
+        }
+        line.resize(40, ' ');
+        if (surfaceDamage.empty() && numPrinted == 0) {
+            line += "None";
+        } else if (numPrinted < surfaceDamage.size()) {
+            line += rectString(surfaceDamage[numPrinted]);
+        }
+        line += '\n';
+        regions += line;
+        ++numPrinted;
+    }
+    return regions;
+}
+
+std::string HWC2On1Adapter::Layer::dump() const {
+    std::stringstream output;
+    const char* fill = "      ";
+
+    output << fill << to_string(mCompositionType);
+    output << " Layer  HWC2/1: " << mId << "/" << mHwc1Id << "  ";
+    output << "Z: " << mZ;
+    if (mCompositionType == HWC2::Composition::SolidColor) {
+        output << "  " << colorString(mColor);
+    } else if (mCompositionType == HWC2::Composition::Sideband) {
+        output << "  Handle: " << mSidebandStream << '\n';
+    } else {
+        output << "  Buffer: " << mBuffer.getBuffer() << "/" <<
+                mBuffer.getFence() << '\n';
+        output << fill << "  Display frame [LTRB]: " <<
+                rectString(mDisplayFrame) << '\n';
+        output << fill << "  Source crop: " <<
+                frectString(mSourceCrop) << '\n';
+        output << fill << "  Transform: " << to_string(mTransform);
+        output << "  Blend mode: " << to_string(mBlendMode);
+        if (mPlaneAlpha != 1.0f) {
+            output << "  Alpha: " <<
+                alphaString(mPlaneAlpha) << '\n';
+        } else {
+            output << '\n';
+        }
+        output << regionStrings(mVisibleRegion, mSurfaceDamage);
+    }
+    return output.str();
+}
+
+static int getHwc1Blending(HWC2::BlendMode blendMode) {
+    switch (blendMode) {
+        case BlendMode::Coverage: return HWC_BLENDING_COVERAGE;
+        case BlendMode::Premultiplied: return HWC_BLENDING_PREMULT;
+        default: return HWC_BLENDING_NONE;
+    }
+}
+
+void HWC2On1Adapter::Layer::applyCommonState(hwc_layer_1_t& hwc1Layer) {
+    auto minorVersion = mDisplay.getDevice().getHwc1MinorVersion();
+    hwc1Layer.blending = getHwc1Blending(mBlendMode);
+    hwc1Layer.displayFrame = mDisplayFrame;
+
+    auto pendingAlpha = mPlaneAlpha;
+    if (minorVersion < 2) {
+        mHasUnsupportedPlaneAlpha = pendingAlpha < 1.0f;
+    } else {
+        hwc1Layer.planeAlpha =
+                static_cast<uint8_t>(255.0f * pendingAlpha + 0.5f);
+    }
+
+    if (minorVersion < 3) {
+        auto pending = mSourceCrop;
+        hwc1Layer.sourceCropi.left =
+                static_cast<int32_t>(std::ceil(pending.left));
+        hwc1Layer.sourceCropi.top =
+                static_cast<int32_t>(std::ceil(pending.top));
+        hwc1Layer.sourceCropi.right =
+                static_cast<int32_t>(std::floor(pending.right));
+        hwc1Layer.sourceCropi.bottom =
+                static_cast<int32_t>(std::floor(pending.bottom));
+    } else {
+        hwc1Layer.sourceCropf = mSourceCrop;
+    }
+
+    hwc1Layer.transform = static_cast<uint32_t>(mTransform);
+
+    auto& hwc1VisibleRegion = hwc1Layer.visibleRegionScreen;
+    hwc1VisibleRegion.numRects = mVisibleRegion.size();
+    hwc_rect_t* rects = mDisplay.GetRects(hwc1VisibleRegion.numRects);
+    hwc1VisibleRegion.rects = rects;
+    for (size_t i = 0; i < mVisibleRegion.size(); i++) {
+        rects[i] = mVisibleRegion[i];
+    }
+}
+
+void HWC2On1Adapter::Layer::applySolidColorState(hwc_layer_1_t& hwc1Layer) {
+    // If the device does not support background color it is likely to make
+    // assumption regarding backgroundColor and handle (both fields occupy
+    // the same location in hwc_layer_1_t union).
+    // To not confuse these devices we don't set background color and we
+    // make sure handle is a null pointer.
+    if (hasUnsupportedBackgroundColor()) {
+        hwc1Layer.handle = nullptr;
+    } else {
+        hwc1Layer.backgroundColor = mColor;
+    }
+}
+
+void HWC2On1Adapter::Layer::applySidebandState(hwc_layer_1_t& hwc1Layer) {
+    hwc1Layer.sidebandStream = mSidebandStream;
+}
+
+void HWC2On1Adapter::Layer::applyBufferState(hwc_layer_1_t& hwc1Layer) {
+    hwc1Layer.handle = mBuffer.getBuffer();
+    hwc1Layer.acquireFenceFd = mBuffer.getFence();
+}
+
+void HWC2On1Adapter::Layer::applyCompositionType(hwc_layer_1_t& hwc1Layer) {
+    // HWC1 never supports color transforms or dataspaces and only sometimes
+    // supports plane alpha (depending on the version). These require us to drop
+    // some or all layers to client composition.
+    if (mHasUnsupportedPlaneAlpha || mDisplay.hasColorTransform() ||
+            hasUnsupportedBackgroundColor()) {
+        hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+        hwc1Layer.flags = HWC_SKIP_LAYER;
+        return;
+    }
+
+    hwc1Layer.flags = 0;
+    switch (mCompositionType) {
+        case Composition::Client:
+            hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+            hwc1Layer.flags |= HWC_SKIP_LAYER;
+            break;
+        case Composition::Device:
+            hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+            break;
+        case Composition::SolidColor:
+            // In theory the following line should work, but since the HWC1
+            // version of SurfaceFlinger never used HWC_BACKGROUND, HWC1
+            // devices may not work correctly. To be on the safe side, we
+            // fall back to client composition.
+            //
+            // hwc1Layer.compositionType = HWC_BACKGROUND;
+            hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+            hwc1Layer.flags |= HWC_SKIP_LAYER;
+            break;
+        case Composition::Cursor:
+            hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+            if (mDisplay.getDevice().getHwc1MinorVersion() >= 4) {
+                hwc1Layer.hints |= HWC_IS_CURSOR_LAYER;
+            }
+            break;
+        case Composition::Sideband:
+            if (mDisplay.getDevice().getHwc1MinorVersion() < 4) {
+                hwc1Layer.compositionType = HWC_SIDEBAND;
+            } else {
+                hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+                hwc1Layer.flags |= HWC_SKIP_LAYER;
+            }
+            break;
+        default:
+            hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+            hwc1Layer.flags |= HWC_SKIP_LAYER;
+            break;
+    }
+    ALOGV("Layer %" PRIu64 " %s set to %d", mId,
+            to_string(mCompositionType).c_str(),
+            hwc1Layer.compositionType);
+    ALOGV_IF(hwc1Layer.flags & HWC_SKIP_LAYER, "    and skipping");
+}
+
+// Adapter helpers
+
+void HWC2On1Adapter::populateCapabilities() {
+    if (mHwc1MinorVersion >= 3U) {
+        int supportedTypes = 0;
+        auto result = mHwc1Device->query(mHwc1Device,
+                HWC_DISPLAY_TYPES_SUPPORTED, &supportedTypes);
+        if ((result == 0) && ((supportedTypes & HWC_DISPLAY_VIRTUAL_BIT) != 0)) {
+            ALOGI("Found support for HWC virtual displays");
+            mHwc1SupportsVirtualDisplays = true;
+        }
+    }
+    if (mHwc1MinorVersion >= 4U) {
+        mCapabilities.insert(Capability::SidebandStream);
+    }
+
+    // Check for HWC background color layer support.
+    if (mHwc1MinorVersion >= 1U) {
+        int backgroundColorSupported = 0;
+        auto result = mHwc1Device->query(mHwc1Device,
+                                         HWC_BACKGROUND_LAYER_SUPPORTED,
+                                         &backgroundColorSupported);
+        if ((result == 0) && (backgroundColorSupported == 1)) {
+            ALOGV("Found support for HWC background color");
+            mHwc1SupportsBackgroundColor = true;
+        }
+    }
+
+    // Some devices might have HWC1 retire fences that accurately emulate
+    // HWC2 present fences when they are deferred, but it's not very reliable.
+    // To be safe, we indicate PresentFenceIsNotReliable for all HWC1 devices.
+    mCapabilities.insert(Capability::PresentFenceIsNotReliable);
+}
+
+HWC2On1Adapter::Display* HWC2On1Adapter::getDisplay(hwc2_display_t id) {
+    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+    auto display = mDisplays.find(id);
+    if (display == mDisplays.end()) {
+        return nullptr;
+    }
+
+    return display->second.get();
+}
+
+std::tuple<HWC2On1Adapter::Layer*, Error> HWC2On1Adapter::getLayer(
+        hwc2_display_t displayId, hwc2_layer_t layerId) {
+    auto display = getDisplay(displayId);
+    if (!display) {
+        return std::make_tuple(static_cast<Layer*>(nullptr), Error::BadDisplay);
+    }
+
+    auto layerEntry = mLayers.find(layerId);
+    if (layerEntry == mLayers.end()) {
+        return std::make_tuple(static_cast<Layer*>(nullptr), Error::BadLayer);
+    }
+
+    auto layer = layerEntry->second;
+    if (layer->getDisplay().getId() != displayId) {
+        return std::make_tuple(static_cast<Layer*>(nullptr), Error::BadLayer);
+    }
+    return std::make_tuple(layer.get(), Error::None);
+}
+
+void HWC2On1Adapter::populatePrimary() {
+    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+    auto display = std::make_shared<Display>(*this, HWC2::DisplayType::Physical);
+    mHwc1DisplayMap[HWC_DISPLAY_PRIMARY] = display->getId();
+    display->setHwc1Id(HWC_DISPLAY_PRIMARY);
+    display->populateConfigs();
+    mDisplays.emplace(display->getId(), std::move(display));
+}
+
+bool HWC2On1Adapter::prepareAllDisplays() {
+    ATRACE_CALL();
+
+    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+    for (const auto& displayPair : mDisplays) {
+        auto& display = displayPair.second;
+        if (!display->prepare()) {
+            return false;
+        }
+    }
+
+    if (mHwc1DisplayMap.count(HWC_DISPLAY_PRIMARY) == 0) {
+        ALOGE("prepareAllDisplays: Unable to find primary HWC1 display");
+        return false;
+    }
+
+    // Build an array of hwc_display_contents_1 to call prepare() on HWC1.
+    mHwc1Contents.clear();
+
+    // Always push the primary display
+    auto primaryDisplayId = mHwc1DisplayMap[HWC_DISPLAY_PRIMARY];
+    auto& primaryDisplay = mDisplays[primaryDisplayId];
+    mHwc1Contents.push_back(primaryDisplay->getDisplayContents());
+
+    // Push the external display, if present
+    if (mHwc1DisplayMap.count(HWC_DISPLAY_EXTERNAL) != 0) {
+        auto externalDisplayId = mHwc1DisplayMap[HWC_DISPLAY_EXTERNAL];
+        auto& externalDisplay = mDisplays[externalDisplayId];
+        mHwc1Contents.push_back(externalDisplay->getDisplayContents());
+    } else {
+        // Even if an external display isn't present, we still need to send
+        // at least two displays down to HWC1
+        mHwc1Contents.push_back(nullptr);
+    }
+
+    // Push the hardware virtual display, if supported and present
+    if (mHwc1MinorVersion >= 3) {
+        if (mHwc1DisplayMap.count(HWC_DISPLAY_VIRTUAL) != 0) {
+            auto virtualDisplayId = mHwc1DisplayMap[HWC_DISPLAY_VIRTUAL];
+            auto& virtualDisplay = mDisplays[virtualDisplayId];
+            mHwc1Contents.push_back(virtualDisplay->getDisplayContents());
+        } else {
+            mHwc1Contents.push_back(nullptr);
+        }
+    }
+
+    for (auto& displayContents : mHwc1Contents) {
+        if (!displayContents) {
+            continue;
+        }
+
+        ALOGV("Display %zd layers:", mHwc1Contents.size() - 1);
+        for (size_t l = 0; l < displayContents->numHwLayers; ++l) {
+            auto& layer = displayContents->hwLayers[l];
+            ALOGV("  %zd: %d", l, layer.compositionType);
+        }
+    }
+
+    ALOGV("Calling HWC1 prepare");
+    {
+        ATRACE_NAME("HWC1 prepare");
+        mHwc1Device->prepare(mHwc1Device, mHwc1Contents.size(),
+                mHwc1Contents.data());
+    }
+
+    for (size_t c = 0; c < mHwc1Contents.size(); ++c) {
+        auto& contents = mHwc1Contents[c];
+        if (!contents) {
+            continue;
+        }
+        ALOGV("Display %zd layers:", c);
+        for (size_t l = 0; l < contents->numHwLayers; ++l) {
+            ALOGV("  %zd: %d", l, contents->hwLayers[l].compositionType);
+        }
+    }
+
+    // Return the received contents to their respective displays
+    for (size_t hwc1Id = 0; hwc1Id < mHwc1Contents.size(); ++hwc1Id) {
+        if (mHwc1Contents[hwc1Id] == nullptr) {
+            continue;
+        }
+
+        auto displayId = mHwc1DisplayMap[hwc1Id];
+        auto& display = mDisplays[displayId];
+        display->generateChanges();
+    }
+
+    return true;
+}
+
+void dumpHWC1Message(hwc_composer_device_1* device, size_t numDisplays,
+                     hwc_display_contents_1_t** displays) {
+    ALOGV("*****************************");
+    size_t displayId = 0;
+    while (displayId < numDisplays) {
+        hwc_display_contents_1_t* display = displays[displayId];
+
+        ALOGV("hwc_display_contents_1_t[%zu] @0x%p", displayId, display);
+        if (display == nullptr) {
+            displayId++;
+            continue;
+        }
+        ALOGV("  retirefd:0x%08x", display->retireFenceFd);
+        ALOGV("  outbuf  :0x%p", display->outbuf);
+        ALOGV("  outbuffd:0x%08x", display->outbufAcquireFenceFd);
+        ALOGV("  flags   :0x%08x", display->flags);
+        for(size_t layerId=0 ; layerId < display->numHwLayers ; layerId++) {
+            hwc_layer_1_t& layer = display->hwLayers[layerId];
+            ALOGV("    Layer[%zu]:", layerId);
+            ALOGV("      composition        : 0x%08x", layer.compositionType);
+            ALOGV("      hints              : 0x%08x", layer.hints);
+            ALOGV("      flags              : 0x%08x", layer.flags);
+            ALOGV("      handle             : 0x%p", layer.handle);
+            ALOGV("      transform          : 0x%08x", layer.transform);
+            ALOGV("      blending           : 0x%08x", layer.blending);
+            ALOGV("      sourceCropf        : %f, %f, %f, %f",
+                  layer.sourceCropf.left,
+                  layer.sourceCropf.top,
+                  layer.sourceCropf.right,
+                  layer.sourceCropf.bottom);
+            ALOGV("      displayFrame       : %d, %d, %d, %d",
+                  layer.displayFrame.left,
+                  layer.displayFrame.left,
+                  layer.displayFrame.left,
+                  layer.displayFrame.left);
+            hwc_region_t& visReg = layer.visibleRegionScreen;
+            ALOGV("      visibleRegionScreen: #0x%08zx[@0x%p]",
+                  visReg.numRects,
+                  visReg.rects);
+            for (size_t visRegId=0; visRegId < visReg.numRects ; visRegId++) {
+                if (layer.visibleRegionScreen.rects == nullptr) {
+                    ALOGV("        null");
+                } else {
+                    ALOGV("        visibleRegionScreen[%zu] %d, %d, %d, %d",
+                          visRegId,
+                          visReg.rects[visRegId].left,
+                          visReg.rects[visRegId].top,
+                          visReg.rects[visRegId].right,
+                          visReg.rects[visRegId].bottom);
+                }
+            }
+            ALOGV("      acquireFenceFd     : 0x%08x", layer.acquireFenceFd);
+            ALOGV("      releaseFenceFd     : 0x%08x", layer.releaseFenceFd);
+            ALOGV("      planeAlpha         : 0x%08x", layer.planeAlpha);
+            if (getMinorVersion(device) < 5)
+               continue;
+            ALOGV("      surfaceDamage      : #0x%08zx[@0x%p]",
+                  layer.surfaceDamage.numRects,
+                  layer.surfaceDamage.rects);
+            for (size_t sdId=0; sdId < layer.surfaceDamage.numRects ; sdId++) {
+                if (layer.surfaceDamage.rects == nullptr) {
+                    ALOGV("      null");
+                } else {
+                    ALOGV("      surfaceDamage[%zu] %d, %d, %d, %d",
+                          sdId,
+                          layer.surfaceDamage.rects[sdId].left,
+                          layer.surfaceDamage.rects[sdId].top,
+                          layer.surfaceDamage.rects[sdId].right,
+                          layer.surfaceDamage.rects[sdId].bottom);
+                }
+            }
+        }
+        displayId++;
+    }
+    ALOGV("-----------------------------");
+}
+
+Error HWC2On1Adapter::setAllDisplays() {
+    ATRACE_CALL();
+
+    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+    // Make sure we're ready to validate
+    for (size_t hwc1Id = 0; hwc1Id < mHwc1Contents.size(); ++hwc1Id) {
+        if (mHwc1Contents[hwc1Id] == nullptr) {
+            continue;
+        }
+
+        auto displayId = mHwc1DisplayMap[hwc1Id];
+        auto& display = mDisplays[displayId];
+        Error error = display->set(*mHwc1Contents[hwc1Id]);
+        if (error != Error::None) {
+            ALOGE("setAllDisplays: Failed to set display %zd: %s", hwc1Id,
+                    to_string(error).c_str());
+            return error;
+        }
+    }
+
+    ALOGV("Calling HWC1 set");
+    {
+        ATRACE_NAME("HWC1 set");
+        //dumpHWC1Message(mHwc1Device, mHwc1Contents.size(), mHwc1Contents.data());
+        mHwc1Device->set(mHwc1Device, mHwc1Contents.size(),
+                mHwc1Contents.data());
+    }
+
+    // Add retire and release fences
+    for (size_t hwc1Id = 0; hwc1Id < mHwc1Contents.size(); ++hwc1Id) {
+        if (mHwc1Contents[hwc1Id] == nullptr) {
+            continue;
+        }
+
+        auto displayId = mHwc1DisplayMap[hwc1Id];
+        auto& display = mDisplays[displayId];
+        auto retireFenceFd = mHwc1Contents[hwc1Id]->retireFenceFd;
+        ALOGV("setAllDisplays: Adding retire fence %d to display %zd",
+                retireFenceFd, hwc1Id);
+        display->addRetireFence(mHwc1Contents[hwc1Id]->retireFenceFd);
+        display->addReleaseFences(*mHwc1Contents[hwc1Id]);
+    }
+
+    return Error::None;
+}
+
+void HWC2On1Adapter::hwc1Invalidate() {
+    ALOGV("Received hwc1Invalidate");
+
+    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+    // If the HWC2-side callback hasn't been registered yet, buffer this until
+    // it is registered.
+    if (mCallbacks.count(Callback::Refresh) == 0) {
+        mHasPendingInvalidate = true;
+        return;
+    }
+
+    const auto& callbackInfo = mCallbacks[Callback::Refresh];
+    std::vector<hwc2_display_t> displays;
+    for (const auto& displayPair : mDisplays) {
+        displays.emplace_back(displayPair.first);
+    }
+
+    // Call back without the state lock held.
+    lock.unlock();
+
+    auto refresh = reinterpret_cast<HWC2_PFN_REFRESH>(callbackInfo.pointer);
+    for (auto display : displays) {
+        refresh(callbackInfo.data, display);
+    }
+}
+
+void HWC2On1Adapter::hwc1Vsync(int hwc1DisplayId, int64_t timestamp) {
+    ALOGV("Received hwc1Vsync(%d, %" PRId64 ")", hwc1DisplayId, timestamp);
+
+    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+    // If the HWC2-side callback hasn't been registered yet, buffer this until
+    // it is registered.
+    if (mCallbacks.count(Callback::Vsync) == 0) {
+        mPendingVsyncs.emplace_back(hwc1DisplayId, timestamp);
+        return;
+    }
+
+    if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
+        ALOGE("hwc1Vsync: Couldn't find display for HWC1 id %d", hwc1DisplayId);
+        return;
+    }
+
+    const auto& callbackInfo = mCallbacks[Callback::Vsync];
+    auto displayId = mHwc1DisplayMap[hwc1DisplayId];
+
+    // Call back without the state lock held.
+    lock.unlock();
+
+    auto vsync = reinterpret_cast<HWC2_PFN_VSYNC>(callbackInfo.pointer);
+    vsync(callbackInfo.data, displayId, timestamp);
+}
+
+void HWC2On1Adapter::hwc1Hotplug(int hwc1DisplayId, int connected) {
+    ALOGV("Received hwc1Hotplug(%d, %d)", hwc1DisplayId, connected);
+
+    if (hwc1DisplayId != HWC_DISPLAY_EXTERNAL) {
+        ALOGE("hwc1Hotplug: Received hotplug for non-external display");
+        return;
+    }
+
+    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+    // If the HWC2-side callback hasn't been registered yet, buffer this until
+    // it is registered
+    if (mCallbacks.count(Callback::Hotplug) == 0) {
+        mPendingHotplugs.emplace_back(hwc1DisplayId, connected);
+        return;
+    }
+
+    hwc2_display_t displayId = UINT64_MAX;
+    if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
+        if (connected == 0) {
+            ALOGW("hwc1Hotplug: Received disconnect for unconnected display");
+            return;
+        }
+
+        // Create a new display on connect
+        auto display = std::make_shared<HWC2On1Adapter::Display>(*this,
+                HWC2::DisplayType::Physical);
+        display->setHwc1Id(HWC_DISPLAY_EXTERNAL);
+        display->populateConfigs();
+        displayId = display->getId();
+        mHwc1DisplayMap[HWC_DISPLAY_EXTERNAL] = displayId;
+        mDisplays.emplace(displayId, std::move(display));
+    } else {
+        if (connected != 0) {
+            ALOGW("hwc1Hotplug: Received connect for previously connected "
+                    "display");
+            return;
+        }
+
+        // Disconnect an existing display
+        displayId = mHwc1DisplayMap[hwc1DisplayId];
+        mHwc1DisplayMap.erase(HWC_DISPLAY_EXTERNAL);
+        mDisplays.erase(displayId);
+    }
+
+    const auto& callbackInfo = mCallbacks[Callback::Hotplug];
+
+    // Call back without the state lock held
+    lock.unlock();
+
+    auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(callbackInfo.pointer);
+    auto hwc2Connected = (connected == 0) ?
+            HWC2::Connection::Disconnected : HWC2::Connection::Connected;
+    hotplug(callbackInfo.data, displayId, static_cast<int32_t>(hwc2Connected));
+}
+} // namespace android
diff --git a/libs/hwc2on1adapter/MiniFence.cpp b/libs/hwc2on1adapter/MiniFence.cpp
new file mode 100644
index 0000000..dfbe4d6
--- /dev/null
+++ b/libs/hwc2on1adapter/MiniFence.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "hwc2on1adapter/MiniFence.h"
+
+#include <unistd.h>
+
+namespace android {
+
+const sp<MiniFence> MiniFence::NO_FENCE = sp<MiniFence>(new MiniFence);
+
+MiniFence::MiniFence() :
+    mFenceFd(-1) {
+}
+
+MiniFence::MiniFence(int fenceFd) :
+    mFenceFd(fenceFd) {
+}
+
+MiniFence::~MiniFence() {
+    if (mFenceFd != -1) {
+        close(mFenceFd);
+    }
+}
+
+int MiniFence::dup() const {
+    return ::dup(mFenceFd);
+}
+}
diff --git a/libs/hwc2on1adapter/include/hwc2on1adapter/HWC2On1Adapter.h b/libs/hwc2on1adapter/include/hwc2on1adapter/HWC2On1Adapter.h
new file mode 100644
index 0000000..3badfce
--- /dev/null
+++ b/libs/hwc2on1adapter/include/hwc2on1adapter/HWC2On1Adapter.h
@@ -0,0 +1,738 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef ANDROID_SF_HWC2_ON_1_ADAPTER_H
+#define ANDROID_SF_HWC2_ON_1_ADAPTER_H
+
+#define HWC2_INCLUDE_STRINGIFICATION
+#define HWC2_USE_CPP11
+#include <hardware/hwcomposer2.h>
+#undef HWC2_INCLUDE_STRINGIFICATION
+#undef HWC2_USE_CPP11
+
+#include "MiniFence.h"
+
+#include <atomic>
+#include <map>
+#include <mutex>
+#include <queue>
+#include <set>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+struct hwc_composer_device_1;
+struct hwc_display_contents_1;
+struct hwc_layer_1;
+
+namespace android {
+
+// For devices unable to provide an implementation of HWC2 (see hwcomposer2.h),
+// we provide an adapter able to talk to HWC1 (see hwcomposer.h). It translates
+// streamed function calls ala HWC2 model to batched array of structs calls ala
+// HWC1 model.
+class HWC2On1Adapter : public hwc2_device_t
+{
+public:
+    explicit HWC2On1Adapter(struct hwc_composer_device_1* hwc1Device);
+    ~HWC2On1Adapter();
+
+    struct hwc_composer_device_1* getHwc1Device() const { return mHwc1Device; }
+    uint8_t getHwc1MinorVersion() const { return mHwc1MinorVersion; }
+
+private:
+    static inline HWC2On1Adapter* getAdapter(hwc2_device_t* device) {
+        return static_cast<HWC2On1Adapter*>(device);
+    }
+
+    // getCapabilities
+
+    void doGetCapabilities(uint32_t* outCount,
+            int32_t* /*hwc2_capability_t*/ outCapabilities);
+    static void getCapabilitiesHook(hwc2_device_t* device, uint32_t* outCount,
+            int32_t* /*hwc2_capability_t*/ outCapabilities) {
+        getAdapter(device)->doGetCapabilities(outCount, outCapabilities);
+    }
+
+    bool supportsBackgroundColor() {
+        return mHwc1SupportsBackgroundColor;
+    }
+
+    // getFunction
+
+    hwc2_function_pointer_t doGetFunction(HWC2::FunctionDescriptor descriptor);
+    static hwc2_function_pointer_t getFunctionHook(hwc2_device_t* device,
+            int32_t intDesc) {
+        auto descriptor = static_cast<HWC2::FunctionDescriptor>(intDesc);
+        return getAdapter(device)->doGetFunction(descriptor);
+    }
+
+    // Device functions
+
+    HWC2::Error createVirtualDisplay(uint32_t width, uint32_t height,
+            hwc2_display_t* outDisplay);
+    static int32_t createVirtualDisplayHook(hwc2_device_t* device,
+            uint32_t width, uint32_t height, int32_t* /*format*/,
+            hwc2_display_t* outDisplay) {
+        // HWC1 implementations cannot override the buffer format requested by
+        // the consumer
+        auto error = getAdapter(device)->createVirtualDisplay(width, height,
+                outDisplay);
+        return static_cast<int32_t>(error);
+    }
+
+    HWC2::Error destroyVirtualDisplay(hwc2_display_t display);
+    static int32_t destroyVirtualDisplayHook(hwc2_device_t* device,
+            hwc2_display_t display) {
+        auto error = getAdapter(device)->destroyVirtualDisplay(display);
+        return static_cast<int32_t>(error);
+    }
+
+    std::string mDumpString;
+    void dump(uint32_t* outSize, char* outBuffer);
+    static void dumpHook(hwc2_device_t* device, uint32_t* outSize,
+            char* outBuffer) {
+        getAdapter(device)->dump(outSize, outBuffer);
+    }
+
+    uint32_t getMaxVirtualDisplayCount();
+    static uint32_t getMaxVirtualDisplayCountHook(hwc2_device_t* device) {
+        return getAdapter(device)->getMaxVirtualDisplayCount();
+    }
+
+    HWC2::Error registerCallback(HWC2::Callback descriptor,
+            hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer);
+    static int32_t registerCallbackHook(hwc2_device_t* device,
+            int32_t intDesc, hwc2_callback_data_t callbackData,
+            hwc2_function_pointer_t pointer) {
+        auto descriptor = static_cast<HWC2::Callback>(intDesc);
+        auto error = getAdapter(device)->registerCallback(descriptor,
+                callbackData, pointer);
+        return static_cast<int32_t>(error);
+    }
+
+    // Display functions
+
+    class Layer;
+
+    class SortLayersByZ {
+        public:
+            bool operator()(const std::shared_ptr<Layer>& lhs,
+                    const std::shared_ptr<Layer>& rhs);
+    };
+
+    // The semantics of the fences returned by the device differ between
+    // hwc1.set() and hwc2.present(). Read hwcomposer.h and hwcomposer2.h
+    // for more information.
+    //
+    // Release fences in hwc1 are obtained on set() for a frame n and signaled
+    // when the layer buffer is not needed for read operations anymore
+    // (typically on frame n+1). In HWC2, release fences are obtained with a
+    // special call after present() for frame n. These fences signal
+    // on frame n: More specifically, the fence for a given buffer provided in
+    // frame n will signal when the prior buffer is no longer required.
+    //
+    // A retire fence (HWC1) is signaled when a composition is replaced
+    // on the panel whereas a present fence (HWC2) is signaled when a
+    // composition starts to be displayed on a panel.
+    //
+    // The HWC2to1Adapter emulates the new fence semantics for a frame
+    // n by returning the fence from frame n-1. For frame 0, the adapter
+    // returns NO_FENCE.
+    class DeferredFence {
+        public:
+            DeferredFence()
+              : mFences({MiniFence::NO_FENCE, MiniFence::NO_FENCE}) {}
+
+            void add(int32_t fenceFd) {
+                mFences.emplace(new MiniFence(fenceFd));
+                mFences.pop();
+            }
+
+            const sp<MiniFence>& get() const {
+                return mFences.front();
+            }
+
+        private:
+            // There are always two fences in this queue.
+            std::queue<sp<MiniFence>> mFences;
+    };
+
+    class FencedBuffer {
+        public:
+            FencedBuffer() : mBuffer(nullptr), mFence(MiniFence::NO_FENCE) {}
+
+            void setBuffer(buffer_handle_t buffer) { mBuffer = buffer; }
+            void setFence(int fenceFd) { mFence = new MiniFence(fenceFd); }
+
+            buffer_handle_t getBuffer() const { return mBuffer; }
+            int getFence() const { return mFence->dup(); }
+
+        private:
+            buffer_handle_t mBuffer;
+            sp<MiniFence> mFence;
+    };
+
+    class Display {
+        public:
+            Display(HWC2On1Adapter& device, HWC2::DisplayType type);
+
+            hwc2_display_t getId() const { return mId; }
+            HWC2On1Adapter& getDevice() const { return mDevice; }
+
+            // Does not require locking because it is set before adding the
+            // Displays to the Adapter's list of displays
+            void setHwc1Id(int32_t id) { mHwc1Id = id; }
+            int32_t getHwc1Id() const { return mHwc1Id; }
+
+            // HWC2 Display functions
+            HWC2::Error acceptChanges();
+            HWC2::Error createLayer(hwc2_layer_t* outLayerId);
+            HWC2::Error destroyLayer(hwc2_layer_t layerId);
+            HWC2::Error getActiveConfig(hwc2_config_t* outConfigId);
+            HWC2::Error getAttribute(hwc2_config_t configId,
+                    HWC2::Attribute attribute, int32_t* outValue);
+            HWC2::Error getChangedCompositionTypes(uint32_t* outNumElements,
+                    hwc2_layer_t* outLayers, int32_t* outTypes);
+            HWC2::Error getColorModes(uint32_t* outNumModes, int32_t* outModes);
+            HWC2::Error getConfigs(uint32_t* outNumConfigs,
+                    hwc2_config_t* outConfigIds);
+            HWC2::Error getDozeSupport(int32_t* outSupport);
+            HWC2::Error getHdrCapabilities(uint32_t* outNumTypes,
+                    int32_t* outTypes, float* outMaxLuminance,
+                    float* outMaxAverageLuminance, float* outMinLuminance);
+            HWC2::Error getName(uint32_t* outSize, char* outName);
+            HWC2::Error getReleaseFences(uint32_t* outNumElements,
+                    hwc2_layer_t* outLayers, int32_t* outFences);
+            HWC2::Error getRequests(int32_t* outDisplayRequests,
+                    uint32_t* outNumElements, hwc2_layer_t* outLayers,
+                    int32_t* outLayerRequests);
+            HWC2::Error getType(int32_t* outType);
+
+            // Since HWC1 "presents" (called "set" in HWC1) all Displays
+            // at once, the first call to any Display::present will trigger
+            // present() on all Displays in the Device. Subsequent calls without
+            // first calling validate() are noop (except for duping/returning
+            // the retire fence).
+            HWC2::Error present(int32_t* outRetireFence);
+
+            HWC2::Error setActiveConfig(hwc2_config_t configId);
+            HWC2::Error setClientTarget(buffer_handle_t target,
+                    int32_t acquireFence, int32_t dataspace,
+                    hwc_region_t damage);
+            HWC2::Error setColorMode(android_color_mode_t mode);
+            HWC2::Error setColorTransform(android_color_transform_t hint);
+            HWC2::Error setOutputBuffer(buffer_handle_t buffer,
+                    int32_t releaseFence);
+            HWC2::Error setPowerMode(HWC2::PowerMode mode);
+            HWC2::Error setVsyncEnabled(HWC2::Vsync enabled);
+
+            // Since HWC1 "validates" (called "prepare" in HWC1) all Displays
+            // at once, the first call to any Display::validate() will trigger
+            // validate() on all other Displays in the Device.
+            HWC2::Error validate(uint32_t* outNumTypes,
+                    uint32_t* outNumRequests);
+
+            HWC2::Error updateLayerZ(hwc2_layer_t layerId, uint32_t z);
+
+            HWC2::Error getClientTargetSupport(uint32_t width, uint32_t height,
+                     int32_t format, int32_t dataspace);
+
+            // Read configs from HWC1 device
+            void populateConfigs();
+
+            // Set configs for a virtual display
+            void populateConfigs(uint32_t width, uint32_t height);
+
+            bool prepare();
+
+            // Called after hwc.prepare() with responses from the device.
+            void generateChanges();
+
+            bool hasChanges() const;
+            HWC2::Error set(hwc_display_contents_1& hwcContents);
+            void addRetireFence(int fenceFd);
+            void addReleaseFences(const hwc_display_contents_1& hwcContents);
+
+            bool hasColorTransform() const;
+
+            std::string dump() const;
+
+            // Return a rect from the pool allocated during validate()
+            hwc_rect_t* GetRects(size_t numRects);
+
+            hwc_display_contents_1* getDisplayContents();
+
+            void markGeometryChanged() { mGeometryChanged = true; }
+            void resetGeometryMarker() { mGeometryChanged = false;}
+        private:
+            class Config {
+                public:
+                    Config(Display& display)
+                      : mDisplay(display),
+                        mId(0),
+                        mAttributes() {}
+
+                    bool isOnDisplay(const Display& display) const {
+                        return display.getId() == mDisplay.getId();
+                    }
+
+                    void setAttribute(HWC2::Attribute attribute, int32_t value);
+                    int32_t getAttribute(HWC2::Attribute attribute) const;
+
+                    void setHwc1Id(uint32_t id);
+                    bool hasHwc1Id(uint32_t id) const;
+                    HWC2::Error getColorModeForHwc1Id(uint32_t id,
+                            android_color_mode_t *outMode) const;
+                    HWC2::Error getHwc1IdForColorMode(android_color_mode_t mode,
+                            uint32_t* outId) const;
+
+                    void setId(hwc2_config_t id) { mId = id; }
+                    hwc2_config_t getId() const { return mId; }
+
+                    // Attempts to merge two configs that differ only in color
+                    // mode. Returns whether the merge was successful
+                    bool merge(const Config& other);
+
+                    std::set<android_color_mode_t> getColorModes() const;
+
+                    // splitLine divides the output into two lines suitable for
+                    // dumpsys SurfaceFlinger
+                    std::string toString(bool splitLine = false) const;
+
+                private:
+                    Display& mDisplay;
+                    hwc2_config_t mId;
+                    std::unordered_map<HWC2::Attribute, int32_t> mAttributes;
+
+                    // Maps from color transform to HWC1 config ID
+                    std::unordered_map<android_color_mode_t, uint32_t> mHwc1Ids;
+            };
+
+            // Stores changes requested from the device upon calling prepare().
+            // Handles change request to:
+            //   - Layer composition type.
+            //   - Layer hints.
+            class Changes {
+                public:
+                    uint32_t getNumTypes() const {
+                        return static_cast<uint32_t>(mTypeChanges.size());
+                    }
+
+                    uint32_t getNumLayerRequests() const {
+                        return static_cast<uint32_t>(mLayerRequests.size());
+                    }
+
+                    const std::unordered_map<hwc2_layer_t, HWC2::Composition>&
+                            getTypeChanges() const {
+                        return mTypeChanges;
+                    }
+
+                    const std::unordered_map<hwc2_layer_t, HWC2::LayerRequest>&
+                            getLayerRequests() const {
+                        return mLayerRequests;
+                    }
+
+                    void addTypeChange(hwc2_layer_t layerId,
+                            HWC2::Composition type) {
+                        mTypeChanges.insert({layerId, type});
+                    }
+
+                    void clearTypeChanges() { mTypeChanges.clear(); }
+
+                    void addLayerRequest(hwc2_layer_t layerId,
+                            HWC2::LayerRequest request) {
+                        mLayerRequests.insert({layerId, request});
+                    }
+
+                private:
+                    std::unordered_map<hwc2_layer_t, HWC2::Composition>
+                            mTypeChanges;
+                    std::unordered_map<hwc2_layer_t, HWC2::LayerRequest>
+                            mLayerRequests;
+            };
+
+            std::shared_ptr<const Config>
+                    getConfig(hwc2_config_t configId) const;
+
+            void populateColorModes();
+            void initializeActiveConfig();
+
+            // Creates a bi-directional mapping between index in HWC1
+            // prepare/set array and Layer object. Stores mapping in
+            // mHwc1LayerMap and also updates Layer's attribute mHwc1Id.
+            void assignHwc1LayerIds();
+
+            // Called after a response to prepare() has been received:
+            // Ingest composition type changes requested by the device.
+            void updateTypeChanges(const struct hwc_layer_1& hwc1Layer,
+                    const Layer& layer);
+
+            // Called after a response to prepare() has been received:
+            // Ingest layer hint changes requested by the device.
+            void updateLayerRequests(const struct hwc_layer_1& hwc1Layer,
+                    const Layer& layer);
+
+            // Set all fields in HWC1 comm array for layer containing the
+            // HWC_FRAMEBUFFER_TARGET (always the last layer).
+            void prepareFramebufferTarget();
+
+            // Display ID generator.
+            static std::atomic<hwc2_display_t> sNextId;
+            const hwc2_display_t mId;
+
+
+            HWC2On1Adapter& mDevice;
+
+            // The state of this display should only be modified from
+            // SurfaceFlinger's main loop, with the exception of when dump is
+            // called. To prevent a bad state from crashing us during a dump
+            // call, all public calls into Display must acquire this mutex.
+            //
+            // It is recursive because we don't want to deadlock in validate
+            // (or present) when we call HWC2On1Adapter::prepareAllDisplays
+            // (or setAllDisplays), which calls back into Display functions
+            // which require locking.
+            mutable std::recursive_mutex mStateMutex;
+
+            // Allocate RAM able to store all layers and rects used for
+            // communication with HWC1. Place allocated RAM in variable
+            // mHwc1RequestedContents.
+            void allocateRequestedContents();
+
+            // Array of structs exchanged between client and hwc1 device.
+            // Sent to device upon calling prepare().
+            std::unique_ptr<hwc_display_contents_1> mHwc1RequestedContents;
+    private:
+            DeferredFence mRetireFence;
+
+            // Will only be non-null after the Display has been validated and
+            // before it has been presented
+            std::unique_ptr<Changes> mChanges;
+
+            int32_t mHwc1Id;
+
+            std::vector<std::shared_ptr<Config>> mConfigs;
+            std::shared_ptr<const Config> mActiveConfig;
+            std::set<android_color_mode_t> mColorModes;
+            android_color_mode_t mActiveColorMode;
+            std::string mName;
+            HWC2::DisplayType mType;
+            HWC2::PowerMode mPowerMode;
+            HWC2::Vsync mVsyncEnabled;
+
+            // Used to populate HWC1 HWC_FRAMEBUFFER_TARGET layer
+            FencedBuffer mClientTarget;
+
+
+            FencedBuffer mOutputBuffer;
+
+            bool mHasColorTransform;
+
+            // All layers this Display is aware of.
+            std::multiset<std::shared_ptr<Layer>, SortLayersByZ> mLayers;
+
+            // Mapping between layer index in array of hwc_display_contents_1*
+            // passed to HWC1 during validate/set and Layer object.
+            std::unordered_map<size_t, std::shared_ptr<Layer>> mHwc1LayerMap;
+
+            // All communication with HWC1 via prepare/set is done with one
+            // alloc. This pointer is pointing to a pool of hwc_rect_t.
+            size_t mNumAvailableRects;
+            hwc_rect_t* mNextAvailableRect;
+
+            // True if any of the Layers contained in this Display have been
+            // updated with anything other than a buffer since last call to
+            // Display::set()
+            bool mGeometryChanged;
+    };
+
+    // Utility template calling a Display object method directly based on the
+    // hwc2_display_t displayId parameter.
+    template <typename ...Args>
+    static int32_t callDisplayFunction(hwc2_device_t* device,
+            hwc2_display_t displayId, HWC2::Error (Display::*member)(Args...),
+            Args... args) {
+        auto display = getAdapter(device)->getDisplay(displayId);
+        if (!display) {
+            return static_cast<int32_t>(HWC2::Error::BadDisplay);
+        }
+        auto error = ((*display).*member)(std::forward<Args>(args)...);
+        return static_cast<int32_t>(error);
+    }
+
+    template <typename MF, MF memFunc, typename ...Args>
+    static int32_t displayHook(hwc2_device_t* device, hwc2_display_t displayId,
+            Args... args) {
+        return HWC2On1Adapter::callDisplayFunction(device, displayId, memFunc,
+                std::forward<Args>(args)...);
+    }
+
+    static int32_t getDisplayAttributeHook(hwc2_device_t* device,
+            hwc2_display_t display, hwc2_config_t config,
+            int32_t intAttribute, int32_t* outValue) {
+        auto attribute = static_cast<HWC2::Attribute>(intAttribute);
+        return callDisplayFunction(device, display, &Display::getAttribute,
+                config, attribute, outValue);
+    }
+
+    static int32_t setColorTransformHook(hwc2_device_t* device,
+            hwc2_display_t display, const float* /*matrix*/,
+            int32_t /*android_color_transform_t*/ intHint) {
+        // We intentionally throw away the matrix, because if the hint is
+        // anything other than IDENTITY, we have to fall back to client
+        // composition anyway
+        auto hint = static_cast<android_color_transform_t>(intHint);
+        return callDisplayFunction(device, display, &Display::setColorTransform,
+                hint);
+    }
+
+    static int32_t setColorModeHook(hwc2_device_t* device,
+            hwc2_display_t display, int32_t /*android_color_mode_t*/ intMode) {
+        auto mode = static_cast<android_color_mode_t>(intMode);
+        return callDisplayFunction(device, display, &Display::setColorMode,
+                mode);
+    }
+
+    static int32_t setPowerModeHook(hwc2_device_t* device,
+            hwc2_display_t display, int32_t intMode) {
+        auto mode = static_cast<HWC2::PowerMode>(intMode);
+        return callDisplayFunction(device, display, &Display::setPowerMode,
+                mode);
+    }
+
+    static int32_t setVsyncEnabledHook(hwc2_device_t* device,
+            hwc2_display_t display, int32_t intEnabled) {
+        auto enabled = static_cast<HWC2::Vsync>(intEnabled);
+        return callDisplayFunction(device, display, &Display::setVsyncEnabled,
+                enabled);
+    }
+
+    class Layer {
+        public:
+            explicit Layer(Display& display);
+
+            bool operator==(const Layer& other) { return mId == other.mId; }
+            bool operator!=(const Layer& other) { return !(*this == other); }
+
+            hwc2_layer_t getId() const { return mId; }
+            Display& getDisplay() const { return mDisplay; }
+
+            // HWC2 Layer functions
+            HWC2::Error setBuffer(buffer_handle_t buffer, int32_t acquireFence);
+            HWC2::Error setCursorPosition(int32_t x, int32_t y);
+            HWC2::Error setSurfaceDamage(hwc_region_t damage);
+
+            // HWC2 Layer state functions
+            HWC2::Error setBlendMode(HWC2::BlendMode mode);
+            HWC2::Error setColor(hwc_color_t color);
+            HWC2::Error setCompositionType(HWC2::Composition type);
+            HWC2::Error setDataspace(android_dataspace_t dataspace);
+            HWC2::Error setDisplayFrame(hwc_rect_t frame);
+            HWC2::Error setPlaneAlpha(float alpha);
+            HWC2::Error setSidebandStream(const native_handle_t* stream);
+            HWC2::Error setSourceCrop(hwc_frect_t crop);
+            HWC2::Error setTransform(HWC2::Transform transform);
+            HWC2::Error setVisibleRegion(hwc_region_t visible);
+            HWC2::Error setZ(uint32_t z);
+
+            HWC2::Composition getCompositionType() const {
+                return mCompositionType;
+            }
+            uint32_t getZ() const { return mZ; }
+
+            void addReleaseFence(int fenceFd);
+            const sp<MiniFence>& getReleaseFence() const;
+
+            void setHwc1Id(size_t id) { mHwc1Id = id; }
+            size_t getHwc1Id() const { return mHwc1Id; }
+
+            // Write state to HWC1 communication struct.
+            void applyState(struct hwc_layer_1& hwc1Layer);
+
+            std::string dump() const;
+
+            std::size_t getNumVisibleRegions() { return mVisibleRegion.size(); }
+
+            std::size_t getNumSurfaceDamages() { return mSurfaceDamage.size(); }
+
+            // True if a layer cannot be properly rendered by the device due
+            // to usage of SolidColor (a.k.a BackgroundColor in HWC1).
+            bool hasUnsupportedBackgroundColor() {
+                return (mCompositionType == HWC2::Composition::SolidColor &&
+                        !mDisplay.getDevice().supportsBackgroundColor());
+            }
+        private:
+            void applyCommonState(struct hwc_layer_1& hwc1Layer);
+            void applySolidColorState(struct hwc_layer_1& hwc1Layer);
+            void applySidebandState(struct hwc_layer_1& hwc1Layer);
+            void applyBufferState(struct hwc_layer_1& hwc1Layer);
+            void applyCompositionType(struct hwc_layer_1& hwc1Layer);
+
+            static std::atomic<hwc2_layer_t> sNextId;
+            const hwc2_layer_t mId;
+            Display& mDisplay;
+
+            FencedBuffer mBuffer;
+            std::vector<hwc_rect_t> mSurfaceDamage;
+
+            HWC2::BlendMode mBlendMode;
+            hwc_color_t mColor;
+            HWC2::Composition mCompositionType;
+            hwc_rect_t mDisplayFrame;
+            float mPlaneAlpha;
+            const native_handle_t* mSidebandStream;
+            hwc_frect_t mSourceCrop;
+            HWC2::Transform mTransform;
+            std::vector<hwc_rect_t> mVisibleRegion;
+
+            uint32_t mZ;
+
+            DeferredFence mReleaseFence;
+
+            size_t mHwc1Id;
+            bool mHasUnsupportedPlaneAlpha;
+    };
+
+    // Utility tempate calling a Layer object method based on ID parameters:
+    // hwc2_display_t displayId
+    // and
+    // hwc2_layer_t layerId
+    template <typename ...Args>
+    static int32_t callLayerFunction(hwc2_device_t* device,
+            hwc2_display_t displayId, hwc2_layer_t layerId,
+            HWC2::Error (Layer::*member)(Args...), Args... args) {
+        auto result = getAdapter(device)->getLayer(displayId, layerId);
+        auto error = std::get<HWC2::Error>(result);
+        if (error == HWC2::Error::None) {
+            auto layer = std::get<Layer*>(result);
+            error = ((*layer).*member)(std::forward<Args>(args)...);
+        }
+        return static_cast<int32_t>(error);
+    }
+
+    template <typename MF, MF memFunc, typename ...Args>
+    static int32_t layerHook(hwc2_device_t* device, hwc2_display_t displayId,
+            hwc2_layer_t layerId, Args... args) {
+        return HWC2On1Adapter::callLayerFunction(device, displayId, layerId,
+                memFunc, std::forward<Args>(args)...);
+    }
+
+    // Layer state functions
+
+    static int32_t setLayerBlendModeHook(hwc2_device_t* device,
+            hwc2_display_t display, hwc2_layer_t layer, int32_t intMode) {
+        auto mode = static_cast<HWC2::BlendMode>(intMode);
+        return callLayerFunction(device, display, layer,
+                &Layer::setBlendMode, mode);
+    }
+
+    static int32_t setLayerCompositionTypeHook(hwc2_device_t* device,
+            hwc2_display_t display, hwc2_layer_t layer, int32_t intType) {
+        auto type = static_cast<HWC2::Composition>(intType);
+        return callLayerFunction(device, display, layer,
+                &Layer::setCompositionType, type);
+    }
+
+    static int32_t setLayerDataspaceHook(hwc2_device_t* device,
+            hwc2_display_t display, hwc2_layer_t layer, int32_t intDataspace) {
+        auto dataspace = static_cast<android_dataspace_t>(intDataspace);
+        return callLayerFunction(device, display, layer, &Layer::setDataspace,
+                dataspace);
+    }
+
+    static int32_t setLayerTransformHook(hwc2_device_t* device,
+            hwc2_display_t display, hwc2_layer_t layer, int32_t intTransform) {
+        auto transform = static_cast<HWC2::Transform>(intTransform);
+        return callLayerFunction(device, display, layer, &Layer::setTransform,
+                transform);
+    }
+
+    static int32_t setLayerZOrderHook(hwc2_device_t* device,
+            hwc2_display_t display, hwc2_layer_t layer, uint32_t z) {
+        return callDisplayFunction(device, display, &Display::updateLayerZ,
+                layer, z);
+    }
+
+    // Adapter internals
+
+    void populateCapabilities();
+    Display* getDisplay(hwc2_display_t id);
+    std::tuple<Layer*, HWC2::Error> getLayer(hwc2_display_t displayId,
+            hwc2_layer_t layerId);
+    void populatePrimary();
+
+    bool prepareAllDisplays();
+    std::vector<struct hwc_display_contents_1*> mHwc1Contents;
+    HWC2::Error setAllDisplays();
+
+    // Callbacks
+    void hwc1Invalidate();
+    void hwc1Vsync(int hwc1DisplayId, int64_t timestamp);
+    void hwc1Hotplug(int hwc1DisplayId, int connected);
+
+    // These are set in the constructor and before any asynchronous events are
+    // possible
+
+    struct hwc_composer_device_1* const mHwc1Device;
+    const uint8_t mHwc1MinorVersion;
+    bool mHwc1SupportsVirtualDisplays;
+    bool mHwc1SupportsBackgroundColor;
+
+    class Callbacks;
+    const std::unique_ptr<Callbacks> mHwc1Callbacks;
+
+    std::unordered_set<HWC2::Capability> mCapabilities;
+
+    // These are only accessed from the main SurfaceFlinger thread (not from
+    // callbacks or dump
+
+    std::map<hwc2_layer_t, std::shared_ptr<Layer>> mLayers;
+
+    // A HWC1 supports only one virtual display.
+    std::shared_ptr<Display> mHwc1VirtualDisplay;
+
+    // These are potentially accessed from multiple threads, and are protected
+    // by this mutex. This needs to be recursive, since the HWC1 implementation
+    // can call back into the invalidate callback on the same thread that is
+    // calling prepare.
+    std::recursive_timed_mutex mStateMutex;
+
+    struct CallbackInfo {
+        hwc2_callback_data_t data;
+        hwc2_function_pointer_t pointer;
+    };
+    std::unordered_map<HWC2::Callback, CallbackInfo> mCallbacks;
+    bool mHasPendingInvalidate;
+
+    // There is a small gap between the time the HWC1 module is started and
+    // when the callbacks for vsync and hotplugs are registered by the
+    // HWC2on1Adapter. To prevent losing events they are stored in these arrays
+    // and fed to the callback as soon as possible.
+    std::vector<std::pair<int, int64_t>> mPendingVsyncs;
+    std::vector<std::pair<int, int>> mPendingHotplugs;
+
+    // Mapping between HWC1 display id and Display objects.
+    std::map<hwc2_display_t, std::shared_ptr<Display>> mDisplays;
+
+    // Map HWC1 display type (HWC_DISPLAY_PRIMARY, HWC_DISPLAY_EXTERNAL,
+    // HWC_DISPLAY_VIRTUAL) to Display IDs generated by HWC2on1Adapter objects.
+    std::unordered_map<int, hwc2_display_t> mHwc1DisplayMap;
+};
+
+} // namespace android
+
+#endif
diff --git a/libs/hwc2on1adapter/include/hwc2on1adapter/MiniFence.h b/libs/hwc2on1adapter/include/hwc2on1adapter/MiniFence.h
new file mode 100644
index 0000000..75de764
--- /dev/null
+++ b/libs/hwc2on1adapter/include/hwc2on1adapter/MiniFence.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MINIFENCE_H
+#define MINIFENCE_H
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+/* MiniFence is a minimal re-implementation of Fence from libui. It exists to
+ * avoid linking the HWC2on1Adapter to libui and satisfy Treble requirements.
+ */
+class MiniFence : public LightRefBase<MiniFence> {
+public:
+    static const sp<MiniFence> NO_FENCE;
+
+    // Construct a new MiniFence object with an invalid file descriptor.
+    MiniFence();
+
+    // Construct a new MiniFence object to manage a given fence file descriptor.
+    // When the new MiniFence object is destructed the file descriptor will be
+    // closed.
+    explicit MiniFence(int fenceFd);
+
+    // Not copyable or movable.
+    MiniFence(const MiniFence& rhs) = delete;
+    MiniFence& operator=(const MiniFence& rhs) = delete;
+    MiniFence(MiniFence&& rhs) = delete;
+    MiniFence& operator=(MiniFence&& rhs) = delete;
+
+    // Return a duplicate of the fence file descriptor. The caller is
+    // responsible for closing the returned file descriptor. On error, -1 will
+    // be returned and errno will indicate the problem.
+    int dup() const;
+
+private:
+    // Only allow instantiation using ref counting.
+    friend class LightRefBase<MiniFence>;
+    ~MiniFence();
+
+    int mFenceFd;
+
+};
+}
+#endif //MINIFENCE_H
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
new file mode 100644
index 0000000..9294419
--- /dev/null
+++ b/libs/input/Android.bp
@@ -0,0 +1,67 @@
+// Copyright (C) 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.
+
+// libinput is partially built for the host (used by build time keymap validation tool)
+
+cc_library {
+    name: "libinput",
+    host_supported: true,
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    srcs: [
+        "Input.cpp",
+        "InputDevice.cpp",
+        "Keyboard.cpp",
+        "KeyCharacterMap.cpp",
+        "KeyLayoutMap.cpp",
+        "VirtualKeyMap.cpp",
+    ],
+
+    clang: true,
+
+    shared_libs: [
+        "liblog",
+        "libcutils",
+    ],
+
+    target: {
+        android: {
+            srcs: [
+                "IInputFlinger.cpp",
+                "InputTransport.cpp",
+                "VelocityControl.cpp",
+                "VelocityTracker.cpp",
+            ],
+
+            shared_libs: [
+                "libutils",
+                "libbinder",
+            ],
+
+            sanitize: {
+                misc_undefined: ["integer"],
+            },
+        },
+        host: {
+            shared: {
+                enabled: false,
+            },
+        },
+    },
+}
+
+subdirs = ["tests"]
diff --git a/libs/input/Android.mk b/libs/input/Android.mk
deleted file mode 100644
index 746de66..0000000
--- a/libs/input/Android.mk
+++ /dev/null
@@ -1,82 +0,0 @@
-# Copyright (C) 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-# libinput is partially built for the host (used by build time keymap validation tool)
-# These files are common to host and target builds.
-
-commonSources := \
-    Input.cpp \
-    InputDevice.cpp \
-    Keyboard.cpp \
-    KeyCharacterMap.cpp \
-    KeyLayoutMap.cpp \
-    VirtualKeyMap.cpp
-
-deviceSources := \
-    $(commonSources) \
-    IInputFlinger.cpp \
-    InputTransport.cpp \
-    VelocityControl.cpp \
-    VelocityTracker.cpp
-
-hostSources := \
-    $(commonSources)
-
-# For the host
-# =====================================================
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= $(hostSources)
-
-LOCAL_MODULE:= libinput
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-
-# For the device
-# =====================================================
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= $(deviceSources)
-
-LOCAL_CLANG := true
-LOCAL_SANITIZE := integer
-
-LOCAL_SHARED_LIBRARIES := \
-	liblog \
-	libcutils \
-	libutils \
-	libbinder
-
-LOCAL_MODULE:= libinput
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-
-# Include subdirectory makefiles
-# ============================================================
-
-# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
-# team really wants is to build the stuff defined by this makefile.
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp
index e009731..003e73d 100644
--- a/libs/input/IInputFlinger.cpp
+++ b/libs/input/IInputFlinger.cpp
@@ -28,7 +28,7 @@
 
 class BpInputFlinger : public BpInterface<IInputFlinger> {
 public:
-    BpInputFlinger(const sp<IBinder>& impl) :
+    explicit BpInputFlinger(const sp<IBinder>& impl) :
             BpInterface<IInputFlinger>(impl) { }
 
     virtual status_t doSomething() {
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index d755ed3..4287abe 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -21,6 +21,7 @@
 #include <ctype.h>
 
 #include <input/InputDevice.h>
+#include <input/InputEventLabels.h>
 
 namespace android {
 
@@ -87,17 +88,23 @@
         const String8& name, InputDeviceConfigurationFileType type) {
     // Search system repository.
     String8 path;
-    path.setTo(getenv("ANDROID_ROOT"));
-    path.append("/usr/");
-    appendInputDeviceConfigurationFileRelativePath(path, name, type);
+
+    // 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/");
+        appendInputDeviceConfigurationFileRelativePath(path, name, type);
 #if DEBUG_PROBE
-    ALOGD("Probing for system provided input device configuration file: path='%s'", path.string());
+        ALOGD("Probing for system provided input device configuration file: path='%s'",
+              path.string());
 #endif
-    if (!access(path.string(), R_OK)) {
+        if (!access(path.string(), R_OK)) {
 #if DEBUG_PROBE
-        ALOGD("Found");
+            ALOGD("Found");
 #endif
-        return path;
+            return path;
+        }
     }
 
     // Search user repository.
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 2dff4e0..af1c0af 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -19,19 +19,18 @@
 // Log debug messages about touch event resampling
 #define DEBUG_RESAMPLING 0
 
-
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
 #include <math.h>
-#include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/types.h>
 #include <unistd.h>
 
-#include <cutils/log.h>
 #include <cutils/properties.h>
-#include <input/InputTransport.h>
+#include <log/log.h>
 
+#include <input/InputTransport.h>
 
 namespace android {
 
diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp
index 9a01395..07f2289 100644
--- a/libs/input/Keyboard.cpp
+++ b/libs/input/Keyboard.cpp
@@ -208,7 +208,6 @@
 }
 
 int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) {
-    int32_t mask;
     switch (keyCode) {
     case AKEYCODE_ALT_LEFT:
         return setEphemeralMetaState(AMETA_ALT_LEFT_ON, down, oldMetaState);
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
new file mode 100644
index 0000000..029a420
--- /dev/null
+++ b/libs/input/tests/Android.bp
@@ -0,0 +1,28 @@
+// Build the unit tests.
+cc_test {
+    name: "libinput_tests",
+    test_per_src: true,
+    srcs: [
+        "InputChannel_test.cpp",
+        "InputEvent_test.cpp",
+        "InputPublisherAndConsumer_test.cpp",
+    ],
+    shared_libs: [
+        "libinput",
+        "libcutils",
+        "libutils",
+        "libbinder",
+        "libui",
+    ]
+}
+
+// NOTE: This is a compile time test, and does not need to be
+// run. All assertions are static_asserts and will fail during
+// buildtime if something's wrong.
+cc_library_static {
+    name: "StructLayout_test",
+    srcs: ["StructLayout_test.cpp"],
+    cflags: [
+        "-O0",
+    ],
+}
diff --git a/libs/input/tests/Android.mk b/libs/input/tests/Android.mk
deleted file mode 100644
index 5bfa3d4..0000000
--- a/libs/input/tests/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-# Build the unit tests.
-LOCAL_PATH:= $(call my-dir)
-
-# Build the unit tests.
-test_src_files := \
-    InputChannel_test.cpp \
-    InputEvent_test.cpp \
-    InputPublisherAndConsumer_test.cpp
-
-shared_libraries := \
-    libinput \
-    libcutils \
-    libutils \
-    libbinder \
-    libui \
-
-$(foreach file,$(test_src_files), \
-    $(eval include $(CLEAR_VARS)) \
-    $(eval LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk) \
-    $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
-    $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
-    $(eval LOCAL_SRC_FILES := $(file)) \
-    $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
-    $(eval include $(BUILD_NATIVE_TEST)) \
-)
-
-# NOTE: This is a compile time test, and does not need to be
-# run. All assertions are static_asserts and will fail during
-# buildtime if something's wrong.
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_SRC_FILES := StructLayout_test.cpp
-LOCAL_MODULE := StructLayout_test
-LOCAL_CFLAGS := -std=c++11 -O0
-LOCAL_MULTILIB := both
-include $(BUILD_STATIC_LIBRARY)
-
-
-# Build the manual test programs.
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 8d73f45..81b9953 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -20,7 +20,7 @@
 namespace android {
 
 #define CHECK_OFFSET(type, member, expected_offset) \
-  static_assert((offsetof(type, member) == expected_offset), "")
+  static_assert((offsetof(type, member) == (expected_offset)), "")
 
 struct Foo {
   uint32_t dummy;
diff --git a/libs/math/Android.bp b/libs/math/Android.bp
new file mode 100644
index 0000000..3ef8b4a
--- /dev/null
+++ b/libs/math/Android.bp
@@ -0,0 +1,21 @@
+// 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.
+
+cc_library_static {
+    name: "libmath",
+    host_supported: true,
+    export_include_dirs: ["include"],
+}
+
+subdirs = ["tests"]
diff --git a/libs/math/MODULE_LICENSE_APACHE2 b/libs/math/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libs/math/MODULE_LICENSE_APACHE2
diff --git a/libs/math/NOTICE b/libs/math/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/libs/math/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, 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/math/include/math/TMatHelpers.h b/libs/math/include/math/TMatHelpers.h
new file mode 100644
index 0000000..5cb725d
--- /dev/null
+++ b/libs/math/include/math/TMatHelpers.h
@@ -0,0 +1,644 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <math.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <cmath>
+#include <exception>
+#include <iomanip>
+#include <stdexcept>
+
+#include <math/quat.h>
+#include <math/TVecHelpers.h>
+
+#include  <utils/String8.h>
+
+#ifndef LIKELY
+#define LIKELY_DEFINED_LOCAL
+#ifdef __cplusplus
+#   define LIKELY( exp )    (__builtin_expect( !!(exp), true ))
+#   define UNLIKELY( exp )  (__builtin_expect( !!(exp), false ))
+#else
+#   define LIKELY( exp )    (__builtin_expect( !!(exp), 1 ))
+#   define UNLIKELY( exp )  (__builtin_expect( !!(exp), 0 ))
+#endif
+#endif
+
+#define PURE __attribute__((pure))
+
+#if __cplusplus >= 201402L
+#define CONSTEXPR constexpr
+#else
+#define CONSTEXPR
+#endif
+
+namespace android {
+namespace details {
+// -------------------------------------------------------------------------------------
+
+/*
+ * No user serviceable parts here.
+ *
+ * Don't use this file directly, instead include ui/mat*.h
+ */
+
+
+/*
+ * Matrix utilities
+ */
+
+namespace matrix {
+
+inline constexpr int     transpose(int v)    { return v; }
+inline constexpr float   transpose(float v)  { return v; }
+inline constexpr double  transpose(double v) { return v; }
+
+inline constexpr int     trace(int v)    { return v; }
+inline constexpr float   trace(float v)  { return v; }
+inline constexpr double  trace(double v) { return v; }
+
+/*
+ * Matrix inversion
+ */
+template<typename MATRIX>
+MATRIX PURE gaussJordanInverse(const MATRIX& src) {
+    typedef typename MATRIX::value_type T;
+    static constexpr unsigned int N = MATRIX::NUM_ROWS;
+    MATRIX tmp(src);
+    MATRIX inverted(1);
+
+    for (size_t i = 0; i < N; ++i) {
+        // look for largest element in i'th column
+        size_t swap = i;
+        T t = std::abs(tmp[i][i]);
+        for (size_t j = i + 1; j < N; ++j) {
+            const T t2 = std::abs(tmp[j][i]);
+            if (t2 > t) {
+                swap = j;
+                t = t2;
+            }
+        }
+
+        if (swap != i) {
+            // swap columns.
+            std::swap(tmp[i], tmp[swap]);
+            std::swap(inverted[i], inverted[swap]);
+        }
+
+        const T denom(tmp[i][i]);
+        for (size_t k = 0; k < N; ++k) {
+            tmp[i][k] /= denom;
+            inverted[i][k] /= denom;
+        }
+
+        // Factor out the lower triangle
+        for (size_t j = 0; j < N; ++j) {
+            if (j != i) {
+                const T d = tmp[j][i];
+                for (size_t k = 0; k < N; ++k) {
+                    tmp[j][k] -= tmp[i][k] * d;
+                    inverted[j][k] -= inverted[i][k] * d;
+                }
+            }
+        }
+    }
+
+    return inverted;
+}
+
+
+//------------------------------------------------------------------------------
+// 2x2 matrix inverse is easy.
+template <typename MATRIX>
+CONSTEXPR MATRIX PURE fastInverse2(const MATRIX& x) {
+    typedef typename MATRIX::value_type T;
+
+    // Assuming the input matrix is:
+    // | a b |
+    // | c d |
+    //
+    // The analytic inverse is
+    // | d -b |
+    // | -c a | / (a d - b c)
+    //
+    // Importantly, our matrices are column-major!
+
+    MATRIX inverted(MATRIX::NO_INIT);
+
+    const T a = x[0][0];
+    const T c = x[0][1];
+    const T b = x[1][0];
+    const T d = x[1][1];
+
+    const T det((a * d) - (b * c));
+    inverted[0][0] =  d / det;
+    inverted[0][1] = -c / det;
+    inverted[1][0] = -b / det;
+    inverted[1][1] =  a / det;
+    return inverted;
+}
+
+
+//------------------------------------------------------------------------------
+// From the Wikipedia article on matrix inversion's section on fast 3x3
+// matrix inversion:
+// http://en.wikipedia.org/wiki/Invertible_matrix#Inversion_of_3.C3.973_matrices
+template <typename MATRIX>
+CONSTEXPR MATRIX PURE fastInverse3(const MATRIX& x) {
+    typedef typename MATRIX::value_type T;
+
+    // Assuming the input matrix is:
+    // | a b c |
+    // | d e f |
+    // | g h i |
+    //
+    // The analytic inverse is
+    // | A B C |^T
+    // | D E F |
+    // | G H I | / determinant
+    //
+    // Which is
+    // | A D G |
+    // | B E H |
+    // | C F I | / determinant
+    //
+    // Where:
+    // A = (ei - fh), B = (fg - di), C = (dh - eg)
+    // D = (ch - bi), E = (ai - cg), F = (bg - ah)
+    // G = (bf - ce), H = (cd - af), I = (ae - bd)
+    //
+    // and the determinant is a*A + b*B + c*C (The rule of Sarrus)
+    //
+    // Importantly, our matrices are column-major!
+
+    MATRIX inverted(MATRIX::NO_INIT);
+
+    const T a = x[0][0];
+    const T b = x[1][0];
+    const T c = x[2][0];
+    const T d = x[0][1];
+    const T e = x[1][1];
+    const T f = x[2][1];
+    const T g = x[0][2];
+    const T h = x[1][2];
+    const T i = x[2][2];
+
+    // Do the full analytic inverse
+    const T A = e * i - f * h;
+    const T B = f * g - d * i;
+    const T C = d * h - e * g;
+    inverted[0][0] = A;                 // A
+    inverted[0][1] = B;                 // B
+    inverted[0][2] = C;                 // C
+    inverted[1][0] = c * h - b * i;     // D
+    inverted[1][1] = a * i - c * g;     // E
+    inverted[1][2] = b * g - a * h;     // F
+    inverted[2][0] = b * f - c * e;     // G
+    inverted[2][1] = c * d - a * f;     // H
+    inverted[2][2] = a * e - b * d;     // I
+
+    const T det(a * A + b * B + c * C);
+    for (size_t col = 0; col < 3; ++col) {
+        for (size_t row = 0; row < 3; ++row) {
+            inverted[col][row] /= det;
+        }
+    }
+
+    return inverted;
+}
+
+/**
+ * Inversion function which switches on the matrix size.
+ * @warning This function assumes the matrix is invertible. The result is
+ * undefined if it is not. It is the responsibility of the caller to
+ * make sure the matrix is not singular.
+ */
+template <typename MATRIX>
+inline constexpr MATRIX PURE inverse(const MATRIX& matrix) {
+    static_assert(MATRIX::NUM_ROWS == MATRIX::NUM_COLS, "only square matrices can be inverted");
+    return (MATRIX::NUM_ROWS == 2) ? fastInverse2<MATRIX>(matrix) :
+          ((MATRIX::NUM_ROWS == 3) ? fastInverse3<MATRIX>(matrix) :
+                    gaussJordanInverse<MATRIX>(matrix));
+}
+
+template<typename MATRIX_R, typename MATRIX_A, typename MATRIX_B>
+CONSTEXPR MATRIX_R PURE multiply(const MATRIX_A& lhs, const MATRIX_B& rhs) {
+    // pre-requisite:
+    //  lhs : D columns, R rows
+    //  rhs : C columns, D rows
+    //  res : C columns, R rows
+
+    static_assert(MATRIX_A::NUM_COLS == MATRIX_B::NUM_ROWS,
+            "matrices can't be multiplied. invalid dimensions.");
+    static_assert(MATRIX_R::NUM_COLS == MATRIX_B::NUM_COLS,
+            "invalid dimension of matrix multiply result.");
+    static_assert(MATRIX_R::NUM_ROWS == MATRIX_A::NUM_ROWS,
+            "invalid dimension of matrix multiply result.");
+
+    MATRIX_R res(MATRIX_R::NO_INIT);
+    for (size_t col = 0; col < MATRIX_R::NUM_COLS; ++col) {
+        res[col] = lhs * rhs[col];
+    }
+    return res;
+}
+
+// transpose. this handles matrices of matrices
+template <typename MATRIX>
+CONSTEXPR MATRIX PURE transpose(const MATRIX& m) {
+    // for now we only handle square matrix transpose
+    static_assert(MATRIX::NUM_COLS == MATRIX::NUM_ROWS, "transpose only supports square matrices");
+    MATRIX result(MATRIX::NO_INIT);
+    for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) {
+        for (size_t row = 0; row < MATRIX::NUM_ROWS; ++row) {
+            result[col][row] = transpose(m[row][col]);
+        }
+    }
+    return result;
+}
+
+// trace. this handles matrices of matrices
+template <typename MATRIX>
+CONSTEXPR typename MATRIX::value_type PURE trace(const MATRIX& m) {
+    static_assert(MATRIX::NUM_COLS == MATRIX::NUM_ROWS, "trace only defined for square matrices");
+    typename MATRIX::value_type result(0);
+    for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) {
+        result += trace(m[col][col]);
+    }
+    return result;
+}
+
+// diag. this handles matrices of matrices
+template <typename MATRIX>
+CONSTEXPR typename MATRIX::col_type PURE diag(const MATRIX& m) {
+    static_assert(MATRIX::NUM_COLS == MATRIX::NUM_ROWS, "diag only defined for square matrices");
+    typename MATRIX::col_type result(MATRIX::col_type::NO_INIT);
+    for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) {
+        result[col] = m[col][col];
+    }
+    return result;
+}
+
+//------------------------------------------------------------------------------
+// This is taken from the Imath MatrixAlgo code, and is identical to Eigen.
+template <typename MATRIX>
+TQuaternion<typename MATRIX::value_type> extractQuat(const MATRIX& mat) {
+    typedef typename MATRIX::value_type T;
+
+    TQuaternion<T> quat(TQuaternion<T>::NO_INIT);
+
+    // Compute the trace to see if it is positive or not.
+    const T trace = mat[0][0] + mat[1][1] + mat[2][2];
+
+    // check the sign of the trace
+    if (LIKELY(trace > 0)) {
+        // trace is positive
+        T s = std::sqrt(trace + 1);
+        quat.w = T(0.5) * s;
+        s = T(0.5) / s;
+        quat.x = (mat[1][2] - mat[2][1]) * s;
+        quat.y = (mat[2][0] - mat[0][2]) * s;
+        quat.z = (mat[0][1] - mat[1][0]) * s;
+    } else {
+        // trace is negative
+
+        // Find the index of the greatest diagonal
+        size_t i = 0;
+        if (mat[1][1] > mat[0][0]) { i = 1; }
+        if (mat[2][2] > mat[i][i]) { i = 2; }
+
+        // Get the next indices: (n+1)%3
+        static constexpr size_t next_ijk[3] = { 1, 2, 0 };
+        size_t j = next_ijk[i];
+        size_t k = next_ijk[j];
+        T s = std::sqrt((mat[i][i] - (mat[j][j] + mat[k][k])) + 1);
+        quat[i] = T(0.5) * s;
+        if (s != 0) {
+            s = T(0.5) / s;
+        }
+        quat.w  = (mat[j][k] - mat[k][j]) * s;
+        quat[j] = (mat[i][j] + mat[j][i]) * s;
+        quat[k] = (mat[i][k] + mat[k][i]) * s;
+    }
+    return quat;
+}
+
+template <typename MATRIX>
+String8 asString(const MATRIX& m) {
+    String8 s;
+    for (size_t c = 0; c < MATRIX::col_size(); c++) {
+        s.append("|  ");
+        for (size_t r = 0; r < MATRIX::row_size(); r++) {
+            s.appendFormat("%7.2f  ", m[r][c]);
+        }
+        s.append("|\n");
+    }
+    return s;
+}
+
+}  // namespace matrix
+
+// -------------------------------------------------------------------------------------
+
+/*
+ * TMatProductOperators implements basic arithmetic and basic compound assignments
+ * operators on a vector of type BASE<T>.
+ *
+ * BASE only needs to implement operator[] and size().
+ * By simply inheriting from TMatProductOperators<BASE, T> BASE will automatically
+ * get all the functionality here.
+ */
+
+template <template<typename T> class BASE, typename T>
+class TMatProductOperators {
+public:
+    // multiply by a scalar
+    BASE<T>& operator *= (T v) {
+        BASE<T>& lhs(static_cast< BASE<T>& >(*this));
+        for (size_t col = 0; col < BASE<T>::NUM_COLS; ++col) {
+            lhs[col] *= v;
+        }
+        return lhs;
+    }
+
+    //  matrix *= matrix
+    template<typename U>
+    const BASE<T>& operator *= (const BASE<U>& rhs) {
+        BASE<T>& lhs(static_cast< BASE<T>& >(*this));
+        lhs = matrix::multiply<BASE<T> >(lhs, rhs);
+        return lhs;
+    }
+
+    // divide by a scalar
+    BASE<T>& operator /= (T v) {
+        BASE<T>& lhs(static_cast< BASE<T>& >(*this));
+        for (size_t col = 0; col < BASE<T>::NUM_COLS; ++col) {
+            lhs[col] /= v;
+        }
+        return lhs;
+    }
+
+    // matrix * matrix, result is a matrix of the same type than the lhs matrix
+    template<typename U>
+    friend CONSTEXPR BASE<T> PURE operator *(const BASE<T>& lhs, const BASE<U>& rhs) {
+        return matrix::multiply<BASE<T> >(lhs, rhs);
+    }
+};
+
+/*
+ * TMatSquareFunctions implements functions on a matrix of type BASE<T>.
+ *
+ * BASE only needs to implement:
+ *  - operator[]
+ *  - col_type
+ *  - row_type
+ *  - COL_SIZE
+ *  - ROW_SIZE
+ *
+ * By simply inheriting from TMatSquareFunctions<BASE, T> BASE will automatically
+ * get all the functionality here.
+ */
+
+template<template<typename U> class BASE, typename T>
+class TMatSquareFunctions {
+public:
+
+    /*
+     * NOTE: the functions below ARE NOT member methods. They are friend functions
+     * with they definition inlined with their declaration. This makes these
+     * template functions available to the compiler when (and only when) this class
+     * is instantiated, at which point they're only templated on the 2nd parameter
+     * (the first one, BASE<T> being known).
+     */
+    friend inline CONSTEXPR BASE<T> PURE inverse(const BASE<T>& matrix) {
+        return matrix::inverse(matrix);
+    }
+    friend inline constexpr BASE<T> PURE transpose(const BASE<T>& m) {
+        return matrix::transpose(m);
+    }
+    friend inline constexpr T PURE trace(const BASE<T>& m) {
+        return matrix::trace(m);
+    }
+};
+
+template<template<typename U> class BASE, typename T>
+class TMatHelpers {
+public:
+    constexpr inline size_t getColumnSize() const   { return BASE<T>::COL_SIZE; }
+    constexpr inline size_t getRowSize() const      { return BASE<T>::ROW_SIZE; }
+    constexpr inline size_t getColumnCount() const  { return BASE<T>::NUM_COLS; }
+    constexpr inline size_t getRowCount() const     { return BASE<T>::NUM_ROWS; }
+    constexpr inline size_t size()  const           { return BASE<T>::ROW_SIZE; }  // for TVec*<>
+
+    // array access
+    constexpr T const* asArray() const {
+        return &static_cast<BASE<T> const &>(*this)[0][0];
+    }
+
+    // element access
+    inline constexpr T const& operator()(size_t row, size_t col) const {
+        return static_cast<BASE<T> const &>(*this)[col][row];
+    }
+
+    inline T& operator()(size_t row, size_t col) {
+        return static_cast<BASE<T>&>(*this)[col][row];
+    }
+
+    template <typename VEC>
+    static CONSTEXPR BASE<T> translate(const VEC& t) {
+        BASE<T> r;
+        r[BASE<T>::NUM_COLS-1] = t;
+        return r;
+    }
+
+    template <typename VEC>
+    static constexpr BASE<T> scale(const VEC& s) {
+        return BASE<T>(s);
+    }
+
+    friend inline CONSTEXPR BASE<T> PURE abs(BASE<T> m) {
+        for (size_t col = 0; col < BASE<T>::NUM_COLS; ++col) {
+            m[col] = abs(m[col]);
+        }
+        return m;
+    }
+};
+
+// functions for 3x3 and 4x4 matrices
+template<template<typename U> class BASE, typename T>
+class TMatTransform {
+public:
+    inline constexpr TMatTransform() {
+        static_assert(BASE<T>::NUM_ROWS == 3 || BASE<T>::NUM_ROWS == 4, "3x3 or 4x4 matrices only");
+    }
+
+    template <typename A, typename VEC>
+    static CONSTEXPR BASE<T> rotate(A radian, const VEC& about) {
+        BASE<T> r;
+        T c = std::cos(radian);
+        T s = std::sin(radian);
+        if (about.x == 1 && about.y == 0 && about.z == 0) {
+            r[1][1] = c;   r[2][2] = c;
+            r[1][2] = s;   r[2][1] = -s;
+        } else if (about.x == 0 && about.y == 1 && about.z == 0) {
+            r[0][0] = c;   r[2][2] = c;
+            r[2][0] = s;   r[0][2] = -s;
+        } else if (about.x == 0 && about.y == 0 && about.z == 1) {
+            r[0][0] = c;   r[1][1] = c;
+            r[0][1] = s;   r[1][0] = -s;
+        } else {
+            VEC nabout = normalize(about);
+            typename VEC::value_type x = nabout.x;
+            typename VEC::value_type y = nabout.y;
+            typename VEC::value_type z = nabout.z;
+            T nc = 1 - c;
+            T xy = x * y;
+            T yz = y * z;
+            T zx = z * x;
+            T xs = x * s;
+            T ys = y * s;
+            T zs = z * s;
+            r[0][0] = x*x*nc +  c;    r[1][0] =  xy*nc - zs;    r[2][0] =  zx*nc + ys;
+            r[0][1] =  xy*nc + zs;    r[1][1] = y*y*nc +  c;    r[2][1] =  yz*nc - xs;
+            r[0][2] =  zx*nc - ys;    r[1][2] =  yz*nc + xs;    r[2][2] = z*z*nc +  c;
+
+            // Clamp results to -1, 1.
+            for (size_t col = 0; col < 3; ++col) {
+                for (size_t row = 0; row < 3; ++row) {
+                    r[col][row] = std::min(std::max(r[col][row], T(-1)), T(1));
+                }
+            }
+        }
+        return r;
+    }
+
+    /**
+     * Create a matrix from euler angles using YPR around YXZ respectively
+     * @param yaw about Y axis
+     * @param pitch about X axis
+     * @param roll about Z axis
+     */
+    template <
+        typename Y, typename P, typename R,
+        typename = typename std::enable_if<std::is_arithmetic<Y>::value >::type,
+        typename = typename std::enable_if<std::is_arithmetic<P>::value >::type,
+        typename = typename std::enable_if<std::is_arithmetic<R>::value >::type
+    >
+    static CONSTEXPR BASE<T> eulerYXZ(Y yaw, P pitch, R roll) {
+        return eulerZYX(roll, pitch, yaw);
+    }
+
+    /**
+     * Create a matrix from euler angles using YPR around ZYX respectively
+     * @param roll about X axis
+     * @param pitch about Y axis
+     * @param yaw about Z axis
+     *
+     * The euler angles are applied in ZYX order. i.e: a vector is first rotated
+     * about X (roll) then Y (pitch) and then Z (yaw).
+     */
+    template <
+    typename Y, typename P, typename R,
+    typename = typename std::enable_if<std::is_arithmetic<Y>::value >::type,
+    typename = typename std::enable_if<std::is_arithmetic<P>::value >::type,
+    typename = typename std::enable_if<std::is_arithmetic<R>::value >::type
+    >
+    static CONSTEXPR BASE<T> eulerZYX(Y yaw, P pitch, R roll) {
+        BASE<T> r;
+        T cy = std::cos(yaw);
+        T sy = std::sin(yaw);
+        T cp = std::cos(pitch);
+        T sp = std::sin(pitch);
+        T cr = std::cos(roll);
+        T sr = std::sin(roll);
+        T cc = cr * cy;
+        T cs = cr * sy;
+        T sc = sr * cy;
+        T ss = sr * sy;
+        r[0][0] = cp * cy;
+        r[0][1] = cp * sy;
+        r[0][2] = -sp;
+        r[1][0] = sp * sc - cs;
+        r[1][1] = sp * ss + cc;
+        r[1][2] = cp * sr;
+        r[2][0] = sp * cc + ss;
+        r[2][1] = sp * cs - sc;
+        r[2][2] = cp * cr;
+
+        // Clamp results to -1, 1.
+        for (size_t col = 0; col < 3; ++col) {
+            for (size_t row = 0; row < 3; ++row) {
+                r[col][row] = std::min(std::max(r[col][row], T(-1)), T(1));
+            }
+        }
+        return r;
+    }
+
+    TQuaternion<T> toQuaternion() const {
+        return matrix::extractQuat(static_cast<const BASE<T>&>(*this));
+    }
+};
+
+
+template <template<typename T> class BASE, typename T>
+class TMatDebug {
+public:
+    friend std::ostream& operator<<(std::ostream& stream, const BASE<T>& m) {
+        for (size_t row = 0; row < BASE<T>::NUM_ROWS; ++row) {
+            if (row != 0) {
+                stream << std::endl;
+            }
+            if (row == 0) {
+                stream << "/ ";
+            } else if (row == BASE<T>::NUM_ROWS-1) {
+                stream << "\\ ";
+            } else {
+                stream << "| ";
+            }
+            for (size_t col = 0; col < BASE<T>::NUM_COLS; ++col) {
+                stream << std::setw(10) << std::to_string(m[col][row]);
+            }
+            if (row == 0) {
+                stream << " \\";
+            } else if (row == BASE<T>::NUM_ROWS-1) {
+                stream << " /";
+            } else {
+                stream << " |";
+            }
+        }
+        return stream;
+    }
+
+    String8 asString() const {
+        return matrix::asString(static_cast<const BASE<T>&>(*this));
+    }
+};
+
+// -------------------------------------------------------------------------------------
+}  // namespace details
+}  // namespace android
+
+#ifdef LIKELY_DEFINED_LOCAL
+#undef LIKELY_DEFINED_LOCAL
+#undef LIKELY
+#undef UNLIKELY
+#endif //LIKELY_DEFINED_LOCAL
+
+#undef PURE
+#undef CONSTEXPR
diff --git a/libs/math/include/math/TQuatHelpers.h b/libs/math/include/math/TQuatHelpers.h
new file mode 100644
index 0000000..f0a71ae
--- /dev/null
+++ b/libs/math/include/math/TQuatHelpers.h
@@ -0,0 +1,300 @@
+/*
+ * 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.
+ */
+
+
+#pragma once
+
+#include <math.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <iostream>
+
+#include <math/vec3.h>
+
+#define PURE __attribute__((pure))
+
+namespace android {
+namespace details {
+// -------------------------------------------------------------------------------------
+
+/*
+ * No user serviceable parts here.
+ *
+ * Don't use this file directly, instead include ui/quat.h
+ */
+
+
+/*
+ * TQuatProductOperators implements basic arithmetic and basic compound assignment
+ * operators on a quaternion of type BASE<T>.
+ *
+ * BASE only needs to implement operator[] and size().
+ * By simply inheriting from TQuatProductOperators<BASE, T> BASE will automatically
+ * get all the functionality here.
+ */
+
+template <template<typename T> class QUATERNION, typename T>
+class TQuatProductOperators {
+public:
+    /* compound assignment from a another quaternion of the same size but different
+     * element type.
+     */
+    template <typename OTHER>
+    QUATERNION<T>& operator *= (const QUATERNION<OTHER>& r) {
+        QUATERNION<T>& q = static_cast<QUATERNION<T>&>(*this);
+        q = q * r;
+        return q;
+    }
+
+    /* compound assignment products by a scalar
+     */
+    QUATERNION<T>& operator *= (T v) {
+        QUATERNION<T>& lhs = static_cast<QUATERNION<T>&>(*this);
+        for (size_t i = 0; i < QUATERNION<T>::size(); i++) {
+            lhs[i] *= v;
+        }
+        return lhs;
+    }
+    QUATERNION<T>& operator /= (T v) {
+        QUATERNION<T>& lhs = static_cast<QUATERNION<T>&>(*this);
+        for (size_t i = 0; i < QUATERNION<T>::size(); i++) {
+            lhs[i] /= v;
+        }
+        return lhs;
+    }
+
+    /*
+     * NOTE: the functions below ARE NOT member methods. They are friend functions
+     * with they definition inlined with their declaration. This makes these
+     * template functions available to the compiler when (and only when) this class
+     * is instantiated, at which point they're only templated on the 2nd parameter
+     * (the first one, BASE<T> being known).
+     */
+
+    /* The operators below handle operation between quaternion of the same size
+     * but of a different element type.
+     */
+    template<typename RT>
+    friend inline
+    constexpr QUATERNION<T> PURE operator *(const QUATERNION<T>& q, const QUATERNION<RT>& r) {
+        // could be written as:
+        //  return QUATERNION<T>(
+        //            q.w*r.w - dot(q.xyz, r.xyz),
+        //            q.w*r.xyz + r.w*q.xyz + cross(q.xyz, r.xyz));
+
+        return QUATERNION<T>(
+                q.w*r.w - q.x*r.x - q.y*r.y - q.z*r.z,
+                q.w*r.x + q.x*r.w + q.y*r.z - q.z*r.y,
+                q.w*r.y - q.x*r.z + q.y*r.w + q.z*r.x,
+                q.w*r.z + q.x*r.y - q.y*r.x + q.z*r.w);
+    }
+
+    template<typename RT>
+    friend inline
+    constexpr TVec3<T> PURE operator *(const QUATERNION<T>& q, const TVec3<RT>& v) {
+        // note: if q is known to be a unit quaternion, then this simplifies to:
+        //  TVec3<T> t = 2 * cross(q.xyz, v)
+        //  return v + (q.w * t) + cross(q.xyz, t)
+        return imaginary(q * QUATERNION<T>(v, 0) * inverse(q));
+    }
+
+
+    /* For quaternions, we use explicit "by a scalar" products because it's much faster
+     * than going (implicitly) through the quaternion multiplication.
+     * For reference: we could use the code below instead, but it would be a lot slower.
+     *  friend inline
+     *  constexpr BASE<T> PURE operator *(const BASE<T>& q, const BASE<T>& r) {
+     *      return BASE<T>(
+     *              q.w*r.w - q.x*r.x - q.y*r.y - q.z*r.z,
+     *              q.w*r.x + q.x*r.w + q.y*r.z - q.z*r.y,
+     *              q.w*r.y - q.x*r.z + q.y*r.w + q.z*r.x,
+     *              q.w*r.z + q.x*r.y - q.y*r.x + q.z*r.w);
+     *
+     */
+    friend inline
+    constexpr QUATERNION<T> PURE operator *(QUATERNION<T> q, T scalar) {
+        // don't pass q by reference because we need a copy anyways
+        return q *= scalar;
+    }
+    friend inline
+    constexpr QUATERNION<T> PURE operator *(T scalar, QUATERNION<T> q) {
+        // don't pass q by reference because we need a copy anyways
+        return q *= scalar;
+    }
+
+    friend inline
+    constexpr QUATERNION<T> PURE operator /(QUATERNION<T> q, T scalar) {
+        // don't pass q by reference because we need a copy anyways
+        return q /= scalar;
+    }
+};
+
+
+/*
+ * TQuatFunctions implements functions on a quaternion of type BASE<T>.
+ *
+ * BASE only needs to implement operator[] and size().
+ * By simply inheriting from TQuatFunctions<BASE, T> BASE will automatically
+ * get all the functionality here.
+ */
+template <template<typename T> class QUATERNION, typename T>
+class TQuatFunctions {
+public:
+    /*
+     * NOTE: the functions below ARE NOT member methods. They are friend functions
+     * with they definition inlined with their declaration. This makes these
+     * template functions available to the compiler when (and only when) this class
+     * is instantiated, at which point they're only templated on the 2nd parameter
+     * (the first one, BASE<T> being known).
+     */
+
+    template<typename RT>
+    friend inline
+    constexpr T PURE dot(const QUATERNION<T>& p, const QUATERNION<RT>& q) {
+        return p.x * q.x +
+               p.y * q.y +
+               p.z * q.z +
+               p.w * q.w;
+    }
+
+    friend inline
+    constexpr T PURE norm(const QUATERNION<T>& q) {
+        return std::sqrt( dot(q, q) );
+    }
+
+    friend inline
+    constexpr T PURE length(const QUATERNION<T>& q) {
+        return norm(q);
+    }
+
+    friend inline
+    constexpr T PURE length2(const QUATERNION<T>& q) {
+        return dot(q, q);
+    }
+
+    friend inline
+    constexpr QUATERNION<T> PURE normalize(const QUATERNION<T>& q) {
+        return length(q) ? q / length(q) : QUATERNION<T>(1);
+    }
+
+    friend inline
+    constexpr QUATERNION<T> PURE conj(const QUATERNION<T>& q) {
+        return QUATERNION<T>(q.w, -q.x, -q.y, -q.z);
+    }
+
+    friend inline
+    constexpr QUATERNION<T> PURE inverse(const QUATERNION<T>& q) {
+        return conj(q) * (1 / dot(q, q));
+    }
+
+    friend inline
+    constexpr T PURE real(const QUATERNION<T>& q) {
+        return q.w;
+    }
+
+    friend inline
+    constexpr TVec3<T> PURE imaginary(const QUATERNION<T>& q) {
+        return q.xyz;
+    }
+
+    friend inline
+    constexpr QUATERNION<T> PURE unreal(const QUATERNION<T>& q) {
+        return QUATERNION<T>(q.xyz, 0);
+    }
+
+    friend inline
+    constexpr QUATERNION<T> PURE cross(const QUATERNION<T>& p, const QUATERNION<T>& q) {
+        return unreal(p*q);
+    }
+
+    friend inline
+    QUATERNION<T> PURE exp(const QUATERNION<T>& q) {
+        const T nq(norm(q.xyz));
+        return std::exp(q.w)*QUATERNION<T>((sin(nq)/nq)*q.xyz, cos(nq));
+    }
+
+    friend inline
+    QUATERNION<T> PURE log(const QUATERNION<T>& q) {
+        const T nq(norm(q));
+        return QUATERNION<T>((std::acos(q.w/nq)/norm(q.xyz))*q.xyz, log(nq));
+    }
+
+    friend inline
+    QUATERNION<T> PURE pow(const QUATERNION<T>& q, T a) {
+        // could also be computed as: exp(a*log(q));
+        const T nq(norm(q));
+        const T theta(a*std::acos(q.w / nq));
+        return std::pow(nq, a) * QUATERNION<T>(normalize(q.xyz) * std::sin(theta), std::cos(theta));
+    }
+
+    friend inline
+    QUATERNION<T> PURE slerp(const QUATERNION<T>& p, const QUATERNION<T>& q, T t) {
+        // could also be computed as: pow(q * inverse(p), t) * p;
+        const T d = dot(p, q);
+        const T npq = sqrt(dot(p, p) * dot(q, q));  // ||p|| * ||q||
+        const T a = std::acos(std::abs(d) / npq);
+        const T a0 = a * (1 - t);
+        const T a1 = a * t;
+        const T isina = 1 / sin(a);
+        const T s0 = std::sin(a0) * isina;
+        const T s1 = std::sin(a1) * isina;
+        // ensure we're taking the "short" side
+        return normalize(s0 * p + ((d < 0) ? (-s1) : (s1)) * q);
+    }
+
+    friend inline
+    constexpr QUATERNION<T> PURE lerp(const QUATERNION<T>& p, const QUATERNION<T>& q, T t) {
+        return ((1 - t) * p) + (t * q);
+    }
+
+    friend inline
+    constexpr QUATERNION<T> PURE nlerp(const QUATERNION<T>& p, const QUATERNION<T>& q, T t) {
+        return normalize(lerp(p, q, t));
+    }
+
+    friend inline
+    constexpr QUATERNION<T> PURE positive(const QUATERNION<T>& q) {
+        return q.w < 0 ? -q : q;
+    }
+};
+
+/*
+ * TQuatDebug implements functions on a vector of type BASE<T>.
+ *
+ * BASE only needs to implement operator[] and size().
+ * By simply inheriting from TQuatDebug<BASE, T> BASE will automatically
+ * get all the functionality here.
+ */
+template <template<typename T> class QUATERNION, typename T>
+class TQuatDebug {
+public:
+    /*
+     * NOTE: the functions below ARE NOT member methods. They are friend functions
+     * with they definition inlined with their declaration. This makes these
+     * template functions available to the compiler when (and only when) this class
+     * is instantiated, at which point they're only templated on the 2nd parameter
+     * (the first one, BASE<T> being known).
+     */
+    friend std::ostream& operator<< (std::ostream& stream, const QUATERNION<T>& q) {
+        return stream << "< " << q.w << " + " << q.x << "i + " << q.y << "j + " << q.z << "k >";
+    }
+};
+#undef PURE
+
+// -------------------------------------------------------------------------------------
+}  // namespace details
+}  // namespace android
diff --git a/libs/math/include/math/TVecHelpers.h b/libs/math/include/math/TVecHelpers.h
new file mode 100644
index 0000000..20f852f
--- /dev/null
+++ b/libs/math/include/math/TVecHelpers.h
@@ -0,0 +1,608 @@
+/*
+ * 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.
+ */
+
+
+#pragma once
+
+#include <math.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <cmath>
+#include <limits>
+#include <iostream>
+
+#define PURE __attribute__((pure))
+
+#if __cplusplus >= 201402L
+#define CONSTEXPR constexpr
+#else
+#define CONSTEXPR
+#endif
+
+namespace android {
+namespace details {
+// -------------------------------------------------------------------------------------
+
+/*
+ * No user serviceable parts here.
+ *
+ * Don't use this file directly, instead include ui/vec{2|3|4}.h
+ */
+
+/*
+ * TVec{Add|Product}Operators implements basic arithmetic and basic compound assignments
+ * operators on a vector of type BASE<T>.
+ *
+ * BASE only needs to implement operator[] and size().
+ * By simply inheriting from TVec{Add|Product}Operators<BASE, T> BASE will automatically
+ * get all the functionality here.
+ */
+
+template <template<typename T> class VECTOR, typename T>
+class TVecAddOperators {
+public:
+    /* compound assignment from a another vector of the same size but different
+     * element type.
+     */
+    template<typename OTHER>
+    VECTOR<T>& operator +=(const VECTOR<OTHER>& v) {
+        VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
+        for (size_t i = 0; i < lhs.size(); i++) {
+            lhs[i] += v[i];
+        }
+        return lhs;
+    }
+    template<typename OTHER>
+    VECTOR<T>& operator -=(const VECTOR<OTHER>& v) {
+        VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
+        for (size_t i = 0; i < lhs.size(); i++) {
+            lhs[i] -= v[i];
+        }
+        return lhs;
+    }
+
+    /* compound assignment from a another vector of the same type.
+     * These operators can be used for implicit conversion and  handle operations
+     * like "vector *= scalar" by letting the compiler implicitly convert a scalar
+     * to a vector (assuming the BASE<T> allows it).
+     */
+    VECTOR<T>& operator +=(const VECTOR<T>& v) {
+        VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
+        for (size_t i = 0; i < lhs.size(); i++) {
+            lhs[i] += v[i];
+        }
+        return lhs;
+    }
+    VECTOR<T>& operator -=(const VECTOR<T>& v) {
+        VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
+        for (size_t i = 0; i < lhs.size(); i++) {
+            lhs[i] -= v[i];
+        }
+        return lhs;
+    }
+
+    /*
+     * NOTE: the functions below ARE NOT member methods. They are friend functions
+     * with they definition inlined with their declaration. This makes these
+     * template functions available to the compiler when (and only when) this class
+     * is instantiated, at which point they're only templated on the 2nd parameter
+     * (the first one, BASE<T> being known).
+     */
+
+    /* The operators below handle operation between vectors of the same size
+     * but of a different element type.
+     */
+    template<typename RT>
+    friend inline constexpr VECTOR<T> PURE operator +(VECTOR<T> lv, const VECTOR<RT>& rv) {
+        // don't pass lv by reference because we need a copy anyways
+        return lv += rv;
+    }
+    template<typename RT>
+    friend inline constexpr VECTOR<T> PURE operator -(VECTOR<T> lv, const VECTOR<RT>& rv) {
+        // don't pass lv by reference because we need a copy anyways
+        return lv -= rv;
+    }
+
+    /* The operators below (which are not templates once this class is instanced,
+     * i.e.: BASE<T> is known) can be used for implicit conversion on both sides.
+     * These handle operations like "vector + scalar" and "scalar + vector" by
+     * letting the compiler implicitly convert a scalar to a vector (assuming
+     * the BASE<T> allows it).
+     */
+    friend inline constexpr VECTOR<T> PURE operator +(VECTOR<T> lv, const VECTOR<T>& rv) {
+        // don't pass lv by reference because we need a copy anyways
+        return lv += rv;
+    }
+    friend inline constexpr VECTOR<T> PURE operator -(VECTOR<T> lv, const VECTOR<T>& rv) {
+        // don't pass lv by reference because we need a copy anyways
+        return lv -= rv;
+    }
+};
+
+template<template<typename T> class VECTOR, typename T>
+class TVecProductOperators {
+public:
+    /* compound assignment from a another vector of the same size but different
+     * element type.
+     */
+    template<typename OTHER>
+    VECTOR<T>& operator *=(const VECTOR<OTHER>& v) {
+        VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
+        for (size_t i = 0; i < lhs.size(); i++) {
+            lhs[i] *= v[i];
+        }
+        return lhs;
+    }
+    template<typename OTHER>
+    VECTOR<T>& operator /=(const VECTOR<OTHER>& v) {
+        VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
+        for (size_t i = 0; i < lhs.size(); i++) {
+            lhs[i] /= v[i];
+        }
+        return lhs;
+    }
+
+    /* compound assignment from a another vector of the same type.
+     * These operators can be used for implicit conversion and  handle operations
+     * like "vector *= scalar" by letting the compiler implicitly convert a scalar
+     * to a vector (assuming the BASE<T> allows it).
+     */
+    VECTOR<T>& operator *=(const VECTOR<T>& v) {
+        VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
+        for (size_t i = 0; i < lhs.size(); i++) {
+            lhs[i] *= v[i];
+        }
+        return lhs;
+    }
+    VECTOR<T>& operator /=(const VECTOR<T>& v) {
+        VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
+        for (size_t i = 0; i < lhs.size(); i++) {
+            lhs[i] /= v[i];
+        }
+        return lhs;
+    }
+
+    /*
+     * NOTE: the functions below ARE NOT member methods. They are friend functions
+     * with they definition inlined with their declaration. This makes these
+     * template functions available to the compiler when (and only when) this class
+     * is instantiated, at which point they're only templated on the 2nd parameter
+     * (the first one, BASE<T> being known).
+     */
+
+    /* The operators below handle operation between vectors of the same size
+     * but of a different element type.
+     */
+    template<typename RT>
+    friend inline constexpr VECTOR<T> PURE operator *(VECTOR<T> lv, const VECTOR<RT>& rv) {
+        // don't pass lv by reference because we need a copy anyways
+        return lv *= rv;
+    }
+    template<typename RT>
+    friend inline constexpr VECTOR<T> PURE operator /(VECTOR<T> lv, const VECTOR<RT>& rv) {
+        // don't pass lv by reference because we need a copy anyways
+        return lv /= rv;
+    }
+
+    /* The operators below (which are not templates once this class is instanced,
+     * i.e.: BASE<T> is known) can be used for implicit conversion on both sides.
+     * These handle operations like "vector * scalar" and "scalar * vector" by
+     * letting the compiler implicitly convert a scalar to a vector (assuming
+     * the BASE<T> allows it).
+     */
+    friend inline constexpr VECTOR<T> PURE operator *(VECTOR<T> lv, const VECTOR<T>& rv) {
+        // don't pass lv by reference because we need a copy anyways
+        return lv *= rv;
+    }
+    friend inline constexpr VECTOR<T> PURE operator /(VECTOR<T> lv, const VECTOR<T>& rv) {
+        // don't pass lv by reference because we need a copy anyways
+        return lv /= rv;
+    }
+};
+
+/*
+ * TVecUnaryOperators implements unary operators on a vector of type BASE<T>.
+ *
+ * BASE only needs to implement operator[] and size().
+ * By simply inheriting from TVecUnaryOperators<BASE, T> BASE will automatically
+ * get all the functionality here.
+ *
+ * These operators are implemented as friend functions of TVecUnaryOperators<BASE, T>
+ */
+template<template<typename T> class VECTOR, typename T>
+class TVecUnaryOperators {
+public:
+    VECTOR<T>& operator ++() {
+        VECTOR<T>& rhs = static_cast<VECTOR<T>&>(*this);
+        for (size_t i = 0; i < rhs.size(); i++) {
+            ++rhs[i];
+        }
+        return rhs;
+    }
+
+    VECTOR<T>& operator --() {
+        VECTOR<T>& rhs = static_cast<VECTOR<T>&>(*this);
+        for (size_t i = 0; i < rhs.size(); i++) {
+            --rhs[i];
+        }
+        return rhs;
+    }
+
+    CONSTEXPR VECTOR<T> operator -() const {
+        VECTOR<T> r(VECTOR<T>::NO_INIT);
+        VECTOR<T> const& rv(static_cast<VECTOR<T> const&>(*this));
+        for (size_t i = 0; i < r.size(); i++) {
+            r[i] = -rv[i];
+        }
+        return r;
+    }
+};
+
+/*
+ * TVecComparisonOperators implements relational/comparison operators
+ * on a vector of type BASE<T>.
+ *
+ * BASE only needs to implement operator[] and size().
+ * By simply inheriting from TVecComparisonOperators<BASE, T> BASE will automatically
+ * get all the functionality here.
+ */
+template<template<typename T> class VECTOR, typename T>
+class TVecComparisonOperators {
+public:
+    /*
+     * NOTE: the functions below ARE NOT member methods. They are friend functions
+     * with they definition inlined with their declaration. This makes these
+     * template functions available to the compiler when (and only when) this class
+     * is instantiated, at which point they're only templated on the 2nd parameter
+     * (the first one, BASE<T> being known).
+     */
+    template<typename RT>
+    friend inline
+    bool PURE operator ==(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
+        for (size_t i = 0; i < lv.size(); i++)
+            if (lv[i] != rv[i])
+                return false;
+        return true;
+    }
+
+    template<typename RT>
+    friend inline
+    bool PURE operator !=(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
+        return !operator ==(lv, rv);
+    }
+
+    template<typename RT>
+    friend inline
+    bool PURE operator >(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
+        for (size_t i = 0; i < lv.size(); i++) {
+            if (lv[i] == rv[i]) {
+                continue;
+            }
+            return lv[i] > rv[i];
+        }
+        return false;
+    }
+
+    template<typename RT>
+    friend inline
+    constexpr bool PURE operator <=(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
+        return !(lv > rv);
+    }
+
+    template<typename RT>
+    friend inline
+    bool PURE operator <(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
+        for (size_t i = 0; i < lv.size(); i++) {
+            if (lv[i] == rv[i]) {
+                continue;
+            }
+            return lv[i] < rv[i];
+        }
+        return false;
+    }
+
+    template<typename RT>
+    friend inline
+    constexpr bool PURE operator >=(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
+        return !(lv < rv);
+    }
+
+    template<typename RT>
+    friend inline
+    CONSTEXPR VECTOR<bool> PURE equal(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
+        VECTOR<bool> r;
+        for (size_t i = 0; i < lv.size(); i++) {
+            r[i] = lv[i] == rv[i];
+        }
+        return r;
+    }
+
+    template<typename RT>
+    friend inline
+    CONSTEXPR VECTOR<bool> PURE notEqual(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
+        VECTOR<bool> r;
+        for (size_t i = 0; i < lv.size(); i++) {
+            r[i] = lv[i] != rv[i];
+        }
+        return r;
+    }
+
+    template<typename RT>
+    friend inline
+    CONSTEXPR VECTOR<bool> PURE lessThan(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
+        VECTOR<bool> r;
+        for (size_t i = 0; i < lv.size(); i++) {
+            r[i] = lv[i] < rv[i];
+        }
+        return r;
+    }
+
+    template<typename RT>
+    friend inline
+    CONSTEXPR VECTOR<bool> PURE lessThanEqual(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
+        VECTOR<bool> r;
+        for (size_t i = 0; i < lv.size(); i++) {
+            r[i] = lv[i] <= rv[i];
+        }
+        return r;
+    }
+
+    template<typename RT>
+    friend inline
+    CONSTEXPR VECTOR<bool> PURE greaterThan(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
+        VECTOR<bool> r;
+        for (size_t i = 0; i < lv.size(); i++) {
+            r[i] = lv[i] > rv[i];
+        }
+        return r;
+    }
+
+    template<typename RT>
+    friend inline
+    CONSTEXPR VECTOR<bool> PURE greaterThanEqual(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
+        VECTOR<bool> r;
+        for (size_t i = 0; i < lv.size(); i++) {
+            r[i] = lv[i] >= rv[i];
+        }
+        return r;
+    }
+};
+
+/*
+ * TVecFunctions implements functions on a vector of type BASE<T>.
+ *
+ * BASE only needs to implement operator[] and size().
+ * By simply inheriting from TVecFunctions<BASE, T> BASE will automatically
+ * get all the functionality here.
+ */
+template<template<typename T> class VECTOR, typename T>
+class TVecFunctions {
+public:
+    /*
+     * NOTE: the functions below ARE NOT member methods. They are friend functions
+     * with they definition inlined with their declaration. This makes these
+     * template functions available to the compiler when (and only when) this class
+     * is instantiated, at which point they're only templated on the 2nd parameter
+     * (the first one, BASE<T> being known).
+     */
+    template<typename RT>
+    friend inline CONSTEXPR T PURE dot(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
+        T r(0);
+        for (size_t i = 0; i < lv.size(); i++) {
+            //r = std::fma(lv[i], rv[i], r);
+            r += lv[i] * rv[i];
+        }
+        return r;
+    }
+
+    friend inline constexpr T PURE norm(const VECTOR<T>& lv) {
+        return std::sqrt(dot(lv, lv));
+    }
+
+    friend inline constexpr T PURE length(const VECTOR<T>& lv) {
+        return norm(lv);
+    }
+
+    friend inline constexpr T PURE norm2(const VECTOR<T>& lv) {
+        return dot(lv, lv);
+    }
+
+    friend inline constexpr T PURE length2(const VECTOR<T>& lv) {
+        return norm2(lv);
+    }
+
+    template<typename RT>
+    friend inline constexpr T PURE distance(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
+        return length(rv - lv);
+    }
+
+    template<typename RT>
+    friend inline constexpr T PURE distance2(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
+        return length2(rv - lv);
+    }
+
+    friend inline constexpr VECTOR<T> PURE normalize(const VECTOR<T>& lv) {
+        return lv * (T(1) / length(lv));
+    }
+
+    friend inline constexpr VECTOR<T> PURE rcp(VECTOR<T> v) {
+        return T(1) / v;
+    }
+
+    friend inline CONSTEXPR VECTOR<T> PURE abs(VECTOR<T> v) {
+        for (size_t i = 0; i < v.size(); i++) {
+            v[i] = std::abs(v[i]);
+        }
+        return v;
+    }
+
+    friend inline CONSTEXPR VECTOR<T> PURE floor(VECTOR<T> v) {
+        for (size_t i = 0; i < v.size(); i++) {
+            v[i] = std::floor(v[i]);
+        }
+        return v;
+    }
+
+    friend inline CONSTEXPR VECTOR<T> PURE ceil(VECTOR<T> v) {
+        for (size_t i = 0; i < v.size(); i++) {
+            v[i] = std::ceil(v[i]);
+        }
+        return v;
+    }
+
+    friend inline CONSTEXPR VECTOR<T> PURE round(VECTOR<T> v) {
+        for (size_t i = 0; i < v.size(); i++) {
+            v[i] = std::round(v[i]);
+        }
+        return v;
+    }
+
+    friend inline CONSTEXPR VECTOR<T> PURE inversesqrt(VECTOR<T> v) {
+        for (size_t i = 0; i < v.size(); i++) {
+            v[i] = T(1) / std::sqrt(v[i]);
+        }
+        return v;
+    }
+
+    friend inline CONSTEXPR VECTOR<T> PURE sqrt(VECTOR<T> v) {
+        for (size_t i = 0; i < v.size(); i++) {
+            v[i] = std::sqrt(v[i]);
+        }
+        return v;
+    }
+
+    friend inline CONSTEXPR VECTOR<T> PURE pow(VECTOR<T> v, T p) {
+        for (size_t i = 0; i < v.size(); i++) {
+            v[i] = std::pow(v[i], p);
+        }
+        return v;
+    }
+
+    friend inline CONSTEXPR VECTOR<T> PURE saturate(const VECTOR<T>& lv) {
+        return clamp(lv, T(0), T(1));
+    }
+
+    friend inline CONSTEXPR VECTOR<T> PURE clamp(VECTOR<T> v, T min, T max) {
+        for (size_t i = 0; i< v.size(); i++) {
+            v[i] = std::min(max, std::max(min, v[i]));
+        }
+        return v;
+    }
+
+    friend inline CONSTEXPR VECTOR<T> PURE fma(const VECTOR<T>& lv, const VECTOR<T>& rv, VECTOR<T> a) {
+        for (size_t i = 0; i<lv.size(); i++) {
+            //a[i] = std::fma(lv[i], rv[i], a[i]);
+            a[i] += (lv[i] * rv[i]);
+        }
+        return a;
+    }
+
+    friend inline CONSTEXPR VECTOR<T> PURE min(const VECTOR<T>& u, VECTOR<T> v) {
+        for (size_t i = 0; i < v.size(); i++) {
+            v[i] = std::min(u[i], v[i]);
+        }
+        return v;
+    }
+
+    friend inline CONSTEXPR VECTOR<T> PURE max(const VECTOR<T>& u, VECTOR<T> v) {
+        for (size_t i = 0; i < v.size(); i++) {
+            v[i] = std::max(u[i], v[i]);
+        }
+        return v;
+    }
+
+    friend inline CONSTEXPR T PURE max(const VECTOR<T>& v) {
+        T r(std::numeric_limits<T>::lowest());
+        for (size_t i = 0; i < v.size(); i++) {
+            r = std::max(r, v[i]);
+        }
+        return r;
+    }
+
+    friend inline CONSTEXPR T PURE min(const VECTOR<T>& v) {
+        T r(std::numeric_limits<T>::max());
+        for (size_t i = 0; i < v.size(); i++) {
+            r = std::min(r, v[i]);
+        }
+        return r;
+    }
+
+    friend inline CONSTEXPR VECTOR<T> PURE apply(VECTOR<T> v, const std::function<T(T)>& f) {
+        for (size_t i = 0; i < v.size(); i++) {
+            v[i] = f(v[i]);
+        }
+        return v;
+    }
+
+    friend inline CONSTEXPR bool PURE any(const VECTOR<T>& v) {
+        for (size_t i = 0; i < v.size(); i++) {
+            if (v[i] != T(0)) return true;
+        }
+        return false;
+    }
+
+    friend inline CONSTEXPR bool PURE all(const VECTOR<T>& v) {
+        bool result = true;
+        for (size_t i = 0; i < v.size(); i++) {
+            result &= (v[i] != T(0));
+        }
+        return result;
+    }
+
+    template<typename R>
+    friend inline CONSTEXPR VECTOR<R> PURE map(VECTOR<T> v, const std::function<R(T)>& f) {
+        VECTOR<R> result;
+        for (size_t i = 0; i < v.size(); i++) {
+            result[i] = f(v[i]);
+        }
+        return result;
+    }
+};
+
+/*
+ * TVecDebug implements functions on a vector of type BASE<T>.
+ *
+ * BASE only needs to implement operator[] and size().
+ * By simply inheriting from TVecDebug<BASE, T> BASE will automatically
+ * get all the functionality here.
+ */
+template<template<typename T> class VECTOR, typename T>
+class TVecDebug {
+public:
+    /*
+     * NOTE: the functions below ARE NOT member methods. They are friend functions
+     * with they definition inlined with their declaration. This makes these
+     * template functions available to the compiler when (and only when) this class
+     * is instantiated, at which point they're only templated on the 2nd parameter
+     * (the first one, BASE<T> being known).
+     */
+    friend std::ostream& operator<<(std::ostream& stream, const VECTOR<T>& v) {
+        stream << "< ";
+        for (size_t i = 0; i < v.size() - 1; i++) {
+            stream << T(v[i]) << ", ";
+        }
+        stream << T(v[v.size() - 1]) << " >";
+        return stream;
+    }
+};
+
+#undef CONSTEXPR
+#undef PURE
+
+// -------------------------------------------------------------------------------------
+}  // namespace details
+}  // namespace android
diff --git a/libs/math/include/math/half.h b/libs/math/include/math/half.h
new file mode 100644
index 0000000..615b840
--- /dev/null
+++ b/libs/math/include/math/half.h
@@ -0,0 +1,212 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <iosfwd>
+#include <limits>
+#include <type_traits>
+
+#ifndef LIKELY
+#define LIKELY_DEFINED_LOCAL
+#ifdef __cplusplus
+#   define LIKELY( exp )    (__builtin_expect( !!(exp), true ))
+#   define UNLIKELY( exp )  (__builtin_expect( !!(exp), false ))
+#else
+#   define LIKELY( exp )    (__builtin_expect( !!(exp), 1 ))
+#   define UNLIKELY( exp )  (__builtin_expect( !!(exp), 0 ))
+#endif
+#endif
+
+#if __cplusplus >= 201402L
+#define CONSTEXPR constexpr
+#else
+#define CONSTEXPR
+#endif
+
+namespace android {
+
+/*
+ * half-float
+ *
+ *  1   5       10
+ * +-+------+------------+
+ * |s|eee.ee|mm.mmmm.mmmm|
+ * +-+------+------------+
+ *
+ * minimum (denormal) value: 2^-24 = 5.96e-8
+ * minimum (normal) value:   2^-14 = 6.10e-5
+ * maximum value:            2-2^-10 = 65504
+ *
+ * Integers between 0 and 2048 can be represented exactly
+ */
+class half {
+    struct fp16 {
+        uint16_t bits = 0;
+        fp16() noexcept = default;
+        explicit constexpr fp16(uint16_t b) noexcept : bits(b) { }
+        void setS(unsigned int s) noexcept { bits = uint16_t((bits & 0x7FFF) | (s<<15)); }
+        void setE(unsigned int s) noexcept { bits = uint16_t((bits & 0xE3FF) | (s<<10)); }
+        void setM(unsigned int s) noexcept { bits = uint16_t((bits & 0xFC00) | (s<< 0)); }
+        constexpr unsigned int getS() const noexcept { return  bits >> 15u; }
+        constexpr unsigned int getE() const noexcept { return (bits >> 10u) & 0x1Fu; }
+        constexpr unsigned int getM() const noexcept { return  bits         & 0x3FFu; }
+    };
+    struct fp32 {
+        union {
+            uint32_t bits = 0;
+            float fp;
+        };
+        fp32() noexcept = default;
+        explicit constexpr fp32(float f) : fp(f) { }
+        void setS(unsigned int s) noexcept { bits = uint32_t((bits & 0x7FFFFFFF) | (s<<31)); }
+        void setE(unsigned int s) noexcept { bits = uint32_t((bits & 0x807FFFFF) | (s<<23)); }
+        void setM(unsigned int s) noexcept { bits = uint32_t((bits & 0xFF800000) | (s<< 0)); }
+        constexpr unsigned int getS() const noexcept { return  bits >> 31u; }
+        constexpr unsigned int getE() const noexcept { return (bits >> 23u) & 0xFFu; }
+        constexpr unsigned int getM() const noexcept { return  bits         & 0x7FFFFFu; }
+    };
+
+public:
+    CONSTEXPR half(float v) noexcept : mBits(ftoh(v)) { }
+    CONSTEXPR operator float() const noexcept { return htof(mBits); }
+
+    uint16_t getBits() const noexcept { return mBits.bits; }
+    unsigned int getExponent() const noexcept { return mBits.getE(); }
+    unsigned int getMantissa() const noexcept { return mBits.getM(); }
+
+private:
+    friend class std::numeric_limits<half>;
+    friend CONSTEXPR half operator"" _hf(long double v);
+
+    enum Binary { binary };
+    explicit constexpr half(Binary, uint16_t bits) noexcept : mBits(bits) { }
+    static CONSTEXPR fp16 ftoh(float v) noexcept;
+    static CONSTEXPR float htof(fp16 v) noexcept;
+    fp16 mBits;
+};
+
+inline CONSTEXPR half::fp16 half::ftoh(float v) noexcept {
+    fp16 out;
+    fp32 in(v);
+    if (UNLIKELY(in.getE() == 0xFF)) { // inf or nan
+        out.setE(0x1F);
+        out.setM(in.getM() ? 0x200 : 0);
+    } else {
+        int e = static_cast<int>(in.getE()) - 127 + 15;
+        if (e >= 0x1F) {
+            // overflow
+            out.setE(0x31); // +/- inf
+        } else if (e <= 0) {
+            // underflow
+            // flush to +/- 0
+        } else {
+            unsigned int m = in.getM();
+            out.setE(uint16_t(e));
+            out.setM(m >> 13);
+            if (m & 0x1000) {
+                // rounding
+                out.bits++;
+            }
+        }
+    }
+    out.setS(in.getS());
+    return out;
+}
+
+inline CONSTEXPR float half::htof(half::fp16 in) noexcept {
+    fp32 out;
+    if (UNLIKELY(in.getE() == 0x1F)) { // inf or nan
+        out.setE(0xFF);
+        out.setM(in.getM() ? 0x400000 : 0);
+    } else {
+        if (in.getE() == 0) {
+            if (in.getM()) {
+                // TODO: denormal half float, treat as zero for now
+                // (it's stupid because they can be represented as regular float)
+            }
+        } else {
+            int e = static_cast<int>(in.getE()) - 15 + 127;
+            unsigned int m = in.getM();
+            out.setE(uint32_t(e));
+            out.setM(m << 13);
+        }
+    }
+    out.setS(in.getS());
+    return out.fp;
+}
+
+inline CONSTEXPR android::half operator"" _hf(long double v) {
+    return android::half(android::half::binary, android::half::ftoh(static_cast<float>(v)).bits);
+}
+
+} // namespace android
+
+namespace std {
+
+template<> struct is_floating_point<android::half> : public std::true_type {};
+
+template<>
+class numeric_limits<android::half> {
+public:
+    typedef android::half type;
+
+    static constexpr const bool is_specialized = true;
+    static constexpr const bool is_signed = true;
+    static constexpr const bool is_integer = false;
+    static constexpr const bool is_exact = false;
+    static constexpr const bool has_infinity = true;
+    static constexpr const bool has_quiet_NaN = true;
+    static constexpr const bool has_signaling_NaN = false;
+    static constexpr const float_denorm_style has_denorm = denorm_absent;
+    static constexpr const bool has_denorm_loss = true;
+    static constexpr const bool is_iec559 = false;
+    static constexpr const bool is_bounded = true;
+    static constexpr const bool is_modulo = false;
+    static constexpr const bool traps = false;
+    static constexpr const bool tinyness_before = false;
+    static constexpr const float_round_style round_style = round_indeterminate;
+
+    static constexpr const int digits = 11;
+    static constexpr const int digits10 = 3;
+    static constexpr const int max_digits10 = 5;
+    static constexpr const int radix = 2;
+    static constexpr const int min_exponent = -13;
+    static constexpr const int min_exponent10 = -4;
+    static constexpr const int max_exponent = 16;
+    static constexpr const int max_exponent10 = 4;
+
+    inline static constexpr type round_error() noexcept { return android::half(android::half::binary, 0x3800); }
+    inline static constexpr type min() noexcept { return android::half(android::half::binary, 0x0400); }
+    inline static constexpr type max() noexcept { return android::half(android::half::binary, 0x7bff); }
+    inline static constexpr type lowest() noexcept { return android::half(android::half::binary, 0xfbff); }
+    inline static constexpr type epsilon() noexcept { return android::half(android::half::binary, 0x1400); }
+    inline static constexpr type infinity() noexcept { return android::half(android::half::binary, 0x7c00); }
+    inline static constexpr type quiet_NaN() noexcept { return android::half(android::half::binary, 0x7fff); }
+    inline static constexpr type denorm_min() noexcept { return android::half(android::half::binary, 0x0001); }
+    inline static constexpr type signaling_NaN() noexcept { return android::half(android::half::binary, 0x7dff); }
+};
+
+} // namespace std
+
+#ifdef LIKELY_DEFINED_LOCAL
+#undef LIKELY_DEFINED_LOCAL
+#undef LIKELY
+#undef UNLIKELY
+#endif // LIKELY_DEFINED_LOCAL
+
+#undef CONSTEXPR
diff --git a/libs/math/include/math/mat2.h b/libs/math/include/math/mat2.h
new file mode 100644
index 0000000..3e6cd4c
--- /dev/null
+++ b/libs/math/include/math/mat2.h
@@ -0,0 +1,377 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <math/TMatHelpers.h>
+#include <math/vec2.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#define PURE __attribute__((pure))
+
+#if __cplusplus >= 201402L
+#define CONSTEXPR constexpr
+#else
+#define CONSTEXPR
+#endif
+
+namespace android {
+// -------------------------------------------------------------------------------------
+namespace details {
+
+/**
+ * A 2x2 column-major matrix class.
+ *
+ * Conceptually a 2x2 matrix is a an array of 2 column vec2:
+ *
+ * mat2 m =
+ *      \f$
+ *      \left(
+ *      \begin{array}{cc}
+ *      m[0] & m[1] \\
+ *      \end{array}
+ *      \right)
+ *      \f$
+ *      =
+ *      \f$
+ *      \left(
+ *      \begin{array}{cc}
+ *      m[0][0] & m[1][0] \\
+ *      m[0][1] & m[1][1] \\
+ *      \end{array}
+ *      \right)
+ *      \f$
+ *      =
+ *      \f$
+ *      \left(
+ *      \begin{array}{cc}
+ *      m(0,0) & m(0,1) \\
+ *      m(1,0) & m(1,1) \\
+ *      \end{array}
+ *      \right)
+ *      \f$
+ *
+ * m[n] is the \f$ n^{th} \f$ column of the matrix and is a vec2.
+ *
+ */
+template <typename T>
+class TMat22 :  public TVecUnaryOperators<TMat22, T>,
+                public TVecComparisonOperators<TMat22, T>,
+                public TVecAddOperators<TMat22, T>,
+                public TMatProductOperators<TMat22, T>,
+                public TMatSquareFunctions<TMat22, T>,
+                public TMatHelpers<TMat22, T>,
+                public TMatDebug<TMat22, T> {
+public:
+    enum no_init { NO_INIT };
+    typedef T value_type;
+    typedef T& reference;
+    typedef T const& const_reference;
+    typedef size_t size_type;
+    typedef TVec2<T> col_type;
+    typedef TVec2<T> row_type;
+
+    static constexpr size_t COL_SIZE = col_type::SIZE;  // size of a column (i.e.: number of rows)
+    static constexpr size_t ROW_SIZE = row_type::SIZE;  // size of a row (i.e.: number of columns)
+    static constexpr size_t NUM_ROWS = COL_SIZE;
+    static constexpr size_t NUM_COLS = ROW_SIZE;
+
+private:
+    /*
+     *  <--  N columns  -->
+     *
+     *  a[0][0] a[1][0] a[2][0] ... a[N][0]    ^
+     *  a[0][1] a[1][1] a[2][1] ... a[N][1]    |
+     *  a[0][2] a[1][2] a[2][2] ... a[N][2]  M rows
+     *  ...                                    |
+     *  a[0][M] a[1][M] a[2][M] ... a[N][M]    v
+     *
+     *  COL_SIZE = M
+     *  ROW_SIZE = N
+     *  m[0] = [ a[0][0] a[0][1] a[0][2] ... a[0][M] ]
+     */
+
+    col_type m_value[NUM_COLS];
+
+public:
+    // array access
+    inline constexpr col_type const& operator[](size_t column) const {
+#if __cplusplus >= 201402L
+        // only possible in C++0x14 with constexpr
+        assert(column < NUM_COLS);
+#endif
+        return m_value[column];
+    }
+
+    inline col_type& operator[](size_t column) {
+        assert(column < NUM_COLS);
+        return m_value[column];
+    }
+
+    // -----------------------------------------------------------------------
+    // we want the compiler generated versions for these...
+    TMat22(const TMat22&) = default;
+    ~TMat22() = default;
+    TMat22& operator = (const TMat22&) = default;
+
+    /**
+     *  constructors
+     */
+
+    /**
+     * leaves object uninitialized. use with caution.
+     */
+    explicit constexpr TMat22(no_init)
+            : m_value{ col_type(col_type::NO_INIT),
+                       col_type(col_type::NO_INIT) } {}
+
+
+    /**
+     * initialize to identity.
+     *
+     *      \f$
+     *      \left(
+     *      \begin{array}{cc}
+     *      1 & 0 \\
+     *      0 & 1 \\
+     *      \end{array}
+     *      \right)
+     *      \f$
+     */
+    CONSTEXPR TMat22();
+
+    /**
+     * initialize to Identity*scalar.
+     *
+     *      \f$
+     *      \left(
+     *      \begin{array}{cc}
+     *      v & 0 \\
+     *      0 & v \\
+     *      \end{array}
+     *      \right)
+     *      \f$
+     */
+    template<typename U>
+    explicit CONSTEXPR TMat22(U v);
+
+    /**
+     * sets the diagonal to a vector.
+     *
+     *      \f$
+     *      \left(
+     *      \begin{array}{cc}
+     *      v[0] & 0 \\
+     *      0 & v[1] \\
+     *      \end{array}
+     *      \right)
+     *      \f$
+     */
+    template <typename U>
+    explicit CONSTEXPR TMat22(const TVec2<U>& v);
+
+    /**
+     * construct from another matrix of the same size
+     */
+    template <typename U>
+    explicit CONSTEXPR TMat22(const TMat22<U>& rhs);
+
+    /**
+     * construct from 2 column vectors.
+     *
+     *      \f$
+     *      \left(
+     *      \begin{array}{cc}
+     *      v0 & v1 \\
+     *      \end{array}
+     *      \right)
+     *      \f$
+     */
+    template <typename A, typename B>
+    CONSTEXPR TMat22(const TVec2<A>& v0, const TVec2<B>& v1);
+
+    /** construct from 4 elements in column-major form.
+     *
+     *      \f$
+     *      \left(
+     *      \begin{array}{cc}
+     *      m[0][0] & m[1][0] \\
+     *      m[0][1] & m[1][1] \\
+     *      \end{array}
+     *      \right)
+     *      \f$
+     */
+    template <
+        typename A, typename B,
+        typename C, typename D>
+    CONSTEXPR TMat22(A m00, B m01, C m10, D m11);
+
+    /**
+     * construct from a C array in column major form.
+     */
+    template <typename U>
+    explicit CONSTEXPR TMat22(U const* rawArray);
+
+    /**
+     * Rotate by radians in the 2D plane
+     */
+    static CONSTEXPR TMat22<T> rotate(T radian) {
+        TMat22<T> r(TMat22<T>::NO_INIT);
+        T c = std::cos(radian);
+        T s = std::sin(radian);
+        r[0][0] = c;   r[1][1] = c;
+        r[0][1] = s;   r[1][0] = -s;
+        return r;
+    }
+};
+
+// ----------------------------------------------------------------------------------------
+// Constructors
+// ----------------------------------------------------------------------------------------
+
+// Since the matrix code could become pretty big quickly, we don't inline most
+// operations.
+
+template <typename T>
+CONSTEXPR TMat22<T>::TMat22() {
+    m_value[0] = col_type(1, 0);
+    m_value[1] = col_type(0, 1);
+}
+
+template <typename T>
+template <typename U>
+CONSTEXPR TMat22<T>::TMat22(U v) {
+    m_value[0] = col_type(v, 0);
+    m_value[1] = col_type(0, v);
+}
+
+template<typename T>
+template<typename U>
+CONSTEXPR TMat22<T>::TMat22(const TVec2<U>& v) {
+    m_value[0] = col_type(v.x, 0);
+    m_value[1] = col_type(0, v.y);
+}
+
+// construct from 4 scalars. Note that the arrangement
+// of values in the constructor is the transpose of the matrix
+// notation.
+template<typename T>
+template <
+    typename A, typename B,
+    typename C, typename D>
+CONSTEXPR TMat22<T>::TMat22( A m00, B m01, C m10, D m11) {
+    m_value[0] = col_type(m00, m01);
+    m_value[1] = col_type(m10, m11);
+}
+
+template <typename T>
+template <typename U>
+CONSTEXPR TMat22<T>::TMat22(const TMat22<U>& rhs) {
+    for (size_t col = 0; col < NUM_COLS; ++col) {
+        m_value[col] = col_type(rhs[col]);
+    }
+}
+
+// Construct from 2 column vectors.
+template <typename T>
+template <typename A, typename B>
+CONSTEXPR TMat22<T>::TMat22(const TVec2<A>& v0, const TVec2<B>& v1) {
+    m_value[0] = v0;
+    m_value[1] = v1;
+}
+
+// Construct from raw array, in column-major form.
+template <typename T>
+template <typename U>
+CONSTEXPR TMat22<T>::TMat22(U const* rawArray) {
+    for (size_t col = 0; col < NUM_COLS; ++col) {
+        for (size_t row = 0; row < NUM_ROWS; ++row) {
+            m_value[col][row] = *rawArray++;
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------------------
+// Arithmetic operators outside of class
+// ----------------------------------------------------------------------------------------
+
+/* We use non-friend functions here to prevent the compiler from using
+ * implicit conversions, for instance of a scalar to a vector. The result would
+ * not be what the caller expects.
+ *
+ * Also note that the order of the arguments in the inner loop is important since
+ * it determines the output type (only relevant when T != U).
+ */
+
+// matrix * column-vector, result is a vector of the same type than the input vector
+template <typename T, typename U>
+CONSTEXPR typename TMat22<U>::col_type PURE operator *(const TMat22<T>& lhs, const TVec2<U>& rhs) {
+    // Result is initialized to zero.
+    typename TMat22<U>::col_type result;
+    for (size_t col = 0; col < TMat22<T>::NUM_COLS; ++col) {
+        result += lhs[col] * rhs[col];
+    }
+    return result;
+}
+
+// row-vector * matrix, result is a vector of the same type than the input vector
+template <typename T, typename U>
+CONSTEXPR typename TMat22<U>::row_type PURE operator *(const TVec2<U>& lhs, const TMat22<T>& rhs) {
+    typename TMat22<U>::row_type result(TMat22<U>::row_type::NO_INIT);
+    for (size_t col = 0; col < TMat22<T>::NUM_COLS; ++col) {
+        result[col] = dot(lhs, rhs[col]);
+    }
+    return result;
+}
+
+// matrix * scalar, result is a matrix of the same type than the input matrix
+template<typename T, typename U>
+constexpr typename std::enable_if<std::is_arithmetic<U>::value, TMat22<T>>::type PURE
+operator*(TMat22<T> lhs, U rhs) {
+    return lhs *= rhs;
+}
+
+// scalar * matrix, result is a matrix of the same type than the input matrix
+template<typename T, typename U>
+constexpr typename std::enable_if<std::is_arithmetic<U>::value, TMat22<T>>::type PURE
+operator*(U lhs, const TMat22<T>& rhs) {
+    return rhs * lhs;
+}
+
+// ----------------------------------------------------------------------------------------
+
+/* FIXME: this should go into TMatSquareFunctions<> but for some reason
+ * BASE<T>::col_type is not accessible from there (???)
+ */
+template<typename T>
+CONSTEXPR typename TMat22<T>::col_type PURE diag(const TMat22<T>& m) {
+    return matrix::diag(m);
+}
+
+}  // namespace details
+
+// ----------------------------------------------------------------------------------------
+
+typedef details::TMat22<double> mat2d;
+typedef details::TMat22<float> mat2;
+typedef details::TMat22<float> mat2f;
+
+// ----------------------------------------------------------------------------------------
+}  // namespace android
+
+#undef PURE
+#undef CONSTEXPR
diff --git a/libs/math/include/math/mat3.h b/libs/math/include/math/mat3.h
new file mode 100644
index 0000000..5c8a9b2
--- /dev/null
+++ b/libs/math/include/math/mat3.h
@@ -0,0 +1,440 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <math/quat.h>
+#include <math/TMatHelpers.h>
+#include <math/vec3.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#define PURE __attribute__((pure))
+
+#if __cplusplus >= 201402L
+#define CONSTEXPR constexpr
+#else
+#define CONSTEXPR
+#endif
+
+namespace android {
+// -------------------------------------------------------------------------------------
+namespace details {
+
+template<typename T>
+class TQuaternion;
+
+/**
+ * A 3x3 column-major matrix class.
+ *
+ * Conceptually a 3x3 matrix is a an array of 3 column vec3:
+ *
+ * mat3 m =
+ *      \f$
+ *      \left(
+ *      \begin{array}{ccc}
+ *      m[0] & m[1] & m[2] \\
+ *      \end{array}
+ *      \right)
+ *      \f$
+ *      =
+ *      \f$
+ *      \left(
+ *      \begin{array}{ccc}
+ *      m[0][0] & m[1][0] & m[2][0] \\
+ *      m[0][1] & m[1][1] & m[2][1] \\
+ *      m[0][2] & m[1][2] & m[2][2] \\
+ *      \end{array}
+ *      \right)
+ *      \f$
+ *      =
+ *      \f$
+ *      \left(
+ *      \begin{array}{ccc}
+ *      m(0,0) & m(0,1) & m(0,2) \\
+ *      m(1,0) & m(1,1) & m(1,2) \\
+ *      m(2,0) & m(2,1) & m(2,2) \\
+ *      \end{array}
+ *      \right)
+ *      \f$
+ *
+ * m[n] is the \f$ n^{th} \f$ column of the matrix and is a vec3.
+ *
+ */
+template <typename T>
+class TMat33 :  public TVecUnaryOperators<TMat33, T>,
+                public TVecComparisonOperators<TMat33, T>,
+                public TVecAddOperators<TMat33, T>,
+                public TMatProductOperators<TMat33, T>,
+                public TMatSquareFunctions<TMat33, T>,
+                public TMatTransform<TMat33, T>,
+                public TMatHelpers<TMat33, T>,
+                public TMatDebug<TMat33, T> {
+public:
+    enum no_init { NO_INIT };
+    typedef T value_type;
+    typedef T& reference;
+    typedef T const& const_reference;
+    typedef size_t size_type;
+    typedef TVec3<T> col_type;
+    typedef TVec3<T> row_type;
+
+    static constexpr size_t COL_SIZE = col_type::SIZE;  // size of a column (i.e.: number of rows)
+    static constexpr size_t ROW_SIZE = row_type::SIZE;  // size of a row (i.e.: number of columns)
+    static constexpr size_t NUM_ROWS = COL_SIZE;
+    static constexpr size_t NUM_COLS = ROW_SIZE;
+
+private:
+    /*
+     *  <--  N columns  -->
+     *
+     *  a[0][0] a[1][0] a[2][0] ... a[N][0]    ^
+     *  a[0][1] a[1][1] a[2][1] ... a[N][1]    |
+     *  a[0][2] a[1][2] a[2][2] ... a[N][2]  M rows
+     *  ...                                    |
+     *  a[0][M] a[1][M] a[2][M] ... a[N][M]    v
+     *
+     *  COL_SIZE = M
+     *  ROW_SIZE = N
+     *  m[0] = [ a[0][0] a[0][1] a[0][2] ... a[0][M] ]
+     */
+
+    col_type m_value[NUM_COLS];
+
+public:
+    // array access
+    inline constexpr col_type const& operator[](size_t column) const {
+#if __cplusplus >= 201402L
+        // only possible in C++0x14 with constexpr
+        assert(column < NUM_COLS);
+#endif
+        return m_value[column];
+    }
+
+    inline col_type& operator[](size_t column) {
+        assert(column < NUM_COLS);
+        return m_value[column];
+    }
+
+    // -----------------------------------------------------------------------
+    // we want the compiler generated versions for these...
+    TMat33(const TMat33&) = default;
+    ~TMat33() = default;
+    TMat33& operator = (const TMat33&) = default;
+
+    /**
+     *  constructors
+     */
+
+    /**
+     * leaves object uninitialized. use with caution.
+     */
+    explicit constexpr TMat33(no_init)
+            : m_value{ col_type(col_type::NO_INIT),
+                       col_type(col_type::NO_INIT),
+                       col_type(col_type::NO_INIT) } {}
+
+
+    /**
+     * initialize to identity.
+     *
+     *      \f$
+     *      \left(
+     *      \begin{array}{ccc}
+     *      1 & 0 & 0 \\
+     *      0 & 1 & 0 \\
+     *      0 & 0 & 1 \\
+     *      \end{array}
+     *      \right)
+     *      \f$
+     */
+    CONSTEXPR TMat33();
+
+    /**
+     * initialize to Identity*scalar.
+     *
+     *      \f$
+     *      \left(
+     *      \begin{array}{ccc}
+     *      v & 0 & 0 \\
+     *      0 & v & 0 \\
+     *      0 & 0 & v \\
+     *      \end{array}
+     *      \right)
+     *      \f$
+     */
+    template<typename U>
+    explicit CONSTEXPR TMat33(U v);
+
+    /**
+     * sets the diagonal to a vector.
+     *
+     *      \f$
+     *      \left(
+     *      \begin{array}{ccc}
+     *      v[0] & 0 & 0 \\
+     *      0 & v[1] & 0 \\
+     *      0 & 0 & v[2] \\
+     *      \end{array}
+     *      \right)
+     *      \f$
+     */
+    template <typename U>
+    explicit CONSTEXPR TMat33(const TVec3<U>& v);
+
+    /**
+     * construct from another matrix of the same size
+     */
+    template <typename U>
+    explicit CONSTEXPR TMat33(const TMat33<U>& rhs);
+
+    /**
+     * construct from 3 column vectors.
+     *
+     *      \f$
+     *      \left(
+     *      \begin{array}{ccc}
+     *      v0 & v1 & v2 \\
+     *      \end{array}
+     *      \right)
+     *      \f$
+     */
+    template <typename A, typename B, typename C>
+    CONSTEXPR TMat33(const TVec3<A>& v0, const TVec3<B>& v1, const TVec3<C>& v2);
+
+    /** construct from 9 elements in column-major form.
+     *
+     *      \f$
+     *      \left(
+     *      \begin{array}{ccc}
+     *      m[0][0] & m[1][0] & m[2][0] \\
+     *      m[0][1] & m[1][1] & m[2][1] \\
+     *      m[0][2] & m[1][2] & m[2][2] \\
+     *      \end{array}
+     *      \right)
+     *      \f$
+     */
+    template <
+        typename A, typename B, typename C,
+        typename D, typename E, typename F,
+        typename G, typename H, typename I>
+    CONSTEXPR TMat33(
+           A m00, B m01, C m02,
+           D m10, E m11, F m12,
+           G m20, H m21, I m22);
+
+    /**
+     * construct from a quaternion
+     */
+    template <typename U>
+    explicit CONSTEXPR TMat33(const TQuaternion<U>& q);
+
+    /**
+     * construct from a C array in column major form.
+     */
+    template <typename U>
+    explicit CONSTEXPR TMat33(U const* rawArray);
+
+    /**
+     * orthogonalize only works on matrices of size 3x3
+     */
+    friend inline
+    CONSTEXPR TMat33 orthogonalize(const TMat33& m) {
+        TMat33 ret(TMat33::NO_INIT);
+        ret[0] = normalize(m[0]);
+        ret[2] = normalize(cross(ret[0], m[1]));
+        ret[1] = normalize(cross(ret[2], ret[0]));
+        return ret;
+    }
+};
+
+// ----------------------------------------------------------------------------------------
+// Constructors
+// ----------------------------------------------------------------------------------------
+
+// Since the matrix code could become pretty big quickly, we don't inline most
+// operations.
+
+template <typename T>
+CONSTEXPR TMat33<T>::TMat33() {
+    m_value[0] = col_type(1, 0, 0);
+    m_value[1] = col_type(0, 1, 0);
+    m_value[2] = col_type(0, 0, 1);
+}
+
+template <typename T>
+template <typename U>
+CONSTEXPR TMat33<T>::TMat33(U v) {
+    m_value[0] = col_type(v, 0, 0);
+    m_value[1] = col_type(0, v, 0);
+    m_value[2] = col_type(0, 0, v);
+}
+
+template<typename T>
+template<typename U>
+CONSTEXPR TMat33<T>::TMat33(const TVec3<U>& v) {
+    m_value[0] = col_type(v.x, 0, 0);
+    m_value[1] = col_type(0, v.y, 0);
+    m_value[2] = col_type(0, 0, v.z);
+}
+
+// construct from 9 scalars. Note that the arrangement
+// of values in the constructor is the transpose of the matrix
+// notation.
+template<typename T>
+template <
+    typename A, typename B, typename C,
+    typename D, typename E, typename F,
+    typename G, typename H, typename I>
+CONSTEXPR TMat33<T>::TMat33(
+        A m00, B m01, C m02,
+        D m10, E m11, F m12,
+        G m20, H m21, I m22) {
+    m_value[0] = col_type(m00, m01, m02);
+    m_value[1] = col_type(m10, m11, m12);
+    m_value[2] = col_type(m20, m21, m22);
+}
+
+template <typename T>
+template <typename U>
+CONSTEXPR TMat33<T>::TMat33(const TMat33<U>& rhs) {
+    for (size_t col = 0; col < NUM_COLS; ++col) {
+        m_value[col] = col_type(rhs[col]);
+    }
+}
+
+// Construct from 3 column vectors.
+template <typename T>
+template <typename A, typename B, typename C>
+CONSTEXPR TMat33<T>::TMat33(const TVec3<A>& v0, const TVec3<B>& v1, const TVec3<C>& v2) {
+    m_value[0] = v0;
+    m_value[1] = v1;
+    m_value[2] = v2;
+}
+
+// Construct from raw array, in column-major form.
+template <typename T>
+template <typename U>
+CONSTEXPR TMat33<T>::TMat33(U const* rawArray) {
+    for (size_t col = 0; col < NUM_COLS; ++col) {
+        for (size_t row = 0; row < NUM_ROWS; ++row) {
+            m_value[col][row] = *rawArray++;
+        }
+    }
+}
+
+template <typename T>
+template <typename U>
+CONSTEXPR TMat33<T>::TMat33(const TQuaternion<U>& q) {
+    const U n = q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w;
+    const U s = n > 0 ? 2/n : 0;
+    const U x = s*q.x;
+    const U y = s*q.y;
+    const U z = s*q.z;
+    const U xx = x*q.x;
+    const U xy = x*q.y;
+    const U xz = x*q.z;
+    const U xw = x*q.w;
+    const U yy = y*q.y;
+    const U yz = y*q.z;
+    const U yw = y*q.w;
+    const U zz = z*q.z;
+    const U zw = z*q.w;
+    m_value[0] = col_type(1-yy-zz,    xy+zw,    xz-yw);  // NOLINT
+    m_value[1] = col_type(  xy-zw,  1-xx-zz,    yz+xw);  // NOLINT
+    m_value[2] = col_type(  xz+yw,    yz-xw,  1-xx-yy);  // NOLINT
+}
+
+// ----------------------------------------------------------------------------------------
+// Arithmetic operators outside of class
+// ----------------------------------------------------------------------------------------
+
+/* We use non-friend functions here to prevent the compiler from using
+ * implicit conversions, for instance of a scalar to a vector. The result would
+ * not be what the caller expects.
+ *
+ * Also note that the order of the arguments in the inner loop is important since
+ * it determines the output type (only relevant when T != U).
+ */
+
+// matrix * column-vector, result is a vector of the same type than the input vector
+template <typename T, typename U>
+CONSTEXPR typename TMat33<U>::col_type PURE operator *(const TMat33<T>& lhs, const TVec3<U>& rhs) {
+    // Result is initialized to zero.
+    typename TMat33<U>::col_type result;
+    for (size_t col = 0; col < TMat33<T>::NUM_COLS; ++col) {
+        result += lhs[col] * rhs[col];
+    }
+    return result;
+}
+
+// row-vector * matrix, result is a vector of the same type than the input vector
+template <typename T, typename U>
+CONSTEXPR typename TMat33<U>::row_type PURE operator *(const TVec3<U>& lhs, const TMat33<T>& rhs) {
+    typename TMat33<U>::row_type result(TMat33<U>::row_type::NO_INIT);
+    for (size_t col = 0; col < TMat33<T>::NUM_COLS; ++col) {
+        result[col] = dot(lhs, rhs[col]);
+    }
+    return result;
+}
+
+// matrix * scalar, result is a matrix of the same type than the input matrix
+template<typename T, typename U>
+constexpr typename std::enable_if<std::is_arithmetic<U>::value, TMat33<T>>::type PURE
+operator*(TMat33<T> lhs, U rhs) {
+    return lhs *= rhs;
+}
+
+// scalar * matrix, result is a matrix of the same type than the input matrix
+template<typename T, typename U>
+constexpr typename std::enable_if<std::is_arithmetic<U>::value, TMat33<T>>::type PURE
+operator*(U lhs, const TMat33<T>& rhs) {
+    return rhs * lhs;
+}
+
+//------------------------------------------------------------------------------
+template <typename T>
+CONSTEXPR TMat33<T> orthogonalize(const TMat33<T>& m) {
+    TMat33<T> ret(TMat33<T>::NO_INIT);
+    ret[0] = normalize(m[0]);
+    ret[2] = normalize(cross(ret[0], m[1]));
+    ret[1] = normalize(cross(ret[2], ret[0]));
+    return ret;
+}
+
+// ----------------------------------------------------------------------------------------
+
+/* FIXME: this should go into TMatSquareFunctions<> but for some reason
+ * BASE<T>::col_type is not accessible from there (???)
+ */
+template<typename T>
+CONSTEXPR typename TMat33<T>::col_type PURE diag(const TMat33<T>& m) {
+    return matrix::diag(m);
+}
+
+}  // namespace details
+
+// ----------------------------------------------------------------------------------------
+
+typedef details::TMat33<double> mat3d;
+typedef details::TMat33<float> mat3;
+typedef details::TMat33<float> mat3f;
+
+// ----------------------------------------------------------------------------------------
+}  // namespace android
+
+#undef PURE
+#undef CONSTEXPR
diff --git a/libs/math/include/math/mat4.h b/libs/math/include/math/mat4.h
new file mode 100644
index 0000000..6119ba7
--- /dev/null
+++ b/libs/math/include/math/mat4.h
@@ -0,0 +1,586 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <math/mat3.h>
+#include <math/quat.h>
+#include <math/TMatHelpers.h>
+#include <math/vec3.h>
+#include <math/vec4.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <limits>
+
+#define PURE __attribute__((pure))
+
+#if __cplusplus >= 201402L
+#define CONSTEXPR constexpr
+#else
+#define CONSTEXPR
+#endif
+
+namespace android {
+// -------------------------------------------------------------------------------------
+namespace details {
+
+template<typename T>
+class TQuaternion;
+
+/**
+ * A 4x4 column-major matrix class.
+ *
+ * Conceptually a 4x4 matrix is a an array of 4 column double4:
+ *
+ * mat4 m =
+ *      \f$
+ *      \left(
+ *      \begin{array}{cccc}
+ *      m[0] & m[1] & m[2] & m[3] \\
+ *      \end{array}
+ *      \right)
+ *      \f$
+ *      =
+ *      \f$
+ *      \left(
+ *      \begin{array}{cccc}
+ *      m[0][0] & m[1][0] & m[2][0] & m[3][0] \\
+ *      m[0][1] & m[1][1] & m[2][1] & m[3][1] \\
+ *      m[0][2] & m[1][2] & m[2][2] & m[3][2] \\
+ *      m[0][3] & m[1][3] & m[2][3] & m[3][3] \\
+ *      \end{array}
+ *      \right)
+ *      \f$
+ *      =
+ *      \f$
+ *      \left(
+ *      \begin{array}{cccc}
+ *      m(0,0) & m(0,1) & m(0,2) & m(0,3) \\
+ *      m(1,0) & m(1,1) & m(1,2) & m(1,3) \\
+ *      m(2,0) & m(2,1) & m(2,2) & m(2,3) \\
+ *      m(3,0) & m(3,1) & m(3,2) & m(3,3) \\
+ *      \end{array}
+ *      \right)
+ *      \f$
+ *
+ * m[n] is the \f$ n^{th} \f$ column of the matrix and is a double4.
+ *
+ */
+template <typename T>
+class TMat44 :  public TVecUnaryOperators<TMat44, T>,
+                public TVecComparisonOperators<TMat44, T>,
+                public TVecAddOperators<TMat44, T>,
+                public TMatProductOperators<TMat44, T>,
+                public TMatSquareFunctions<TMat44, T>,
+                public TMatTransform<TMat44, T>,
+                public TMatHelpers<TMat44, T>,
+                public TMatDebug<TMat44, T> {
+public:
+    enum no_init { NO_INIT };
+    typedef T value_type;
+    typedef T& reference;
+    typedef T const& const_reference;
+    typedef size_t size_type;
+    typedef TVec4<T> col_type;
+    typedef TVec4<T> row_type;
+
+    static constexpr size_t COL_SIZE = col_type::SIZE;  // size of a column (i.e.: number of rows)
+    static constexpr size_t ROW_SIZE = row_type::SIZE;  // size of a row (i.e.: number of columns)
+    static constexpr size_t NUM_ROWS = COL_SIZE;
+    static constexpr size_t NUM_COLS = ROW_SIZE;
+
+private:
+    /*
+     *  <--  N columns  -->
+     *
+     *  a[0][0] a[1][0] a[2][0] ... a[N][0]    ^
+     *  a[0][1] a[1][1] a[2][1] ... a[N][1]    |
+     *  a[0][2] a[1][2] a[2][2] ... a[N][2]  M rows
+     *  ...                                    |
+     *  a[0][M] a[1][M] a[2][M] ... a[N][M]    v
+     *
+     *  COL_SIZE = M
+     *  ROW_SIZE = N
+     *  m[0] = [ a[0][0] a[0][1] a[0][2] ... a[0][M] ]
+     */
+
+    col_type m_value[NUM_COLS];
+
+public:
+    // array access
+    inline constexpr col_type const& operator[](size_t column) const {
+#if __cplusplus >= 201402L
+        // only possible in C++0x14 with constexpr
+        assert(column < NUM_COLS);
+#endif
+        return m_value[column];
+    }
+
+    inline col_type& operator[](size_t column) {
+        assert(column < NUM_COLS);
+        return m_value[column];
+    }
+
+    // -----------------------------------------------------------------------
+    // we want the compiler generated versions for these...
+    TMat44(const TMat44&) = default;
+    ~TMat44() = default;
+    TMat44& operator = (const TMat44&) = default;
+
+    /*
+     *  constructors
+     */
+
+    // leaves object uninitialized. use with caution.
+    explicit constexpr TMat44(no_init)
+            : m_value{ col_type(col_type::NO_INIT),
+                       col_type(col_type::NO_INIT),
+                       col_type(col_type::NO_INIT),
+                       col_type(col_type::NO_INIT) } {}
+
+    /** initialize to identity.
+     *
+     *      \f$
+     *      \left(
+     *      \begin{array}{cccc}
+     *      1 & 0 & 0 & 0 \\
+     *      0 & 1 & 0 & 0 \\
+     *      0 & 0 & 1 & 0 \\
+     *      0 & 0 & 0 & 1 \\
+     *      \end{array}
+     *      \right)
+     *      \f$
+     */
+    CONSTEXPR TMat44();
+
+    /** initialize to Identity*scalar.
+     *
+     *      \f$
+     *      \left(
+     *      \begin{array}{cccc}
+     *      v & 0 & 0 & 0 \\
+     *      0 & v & 0 & 0 \\
+     *      0 & 0 & v & 0 \\
+     *      0 & 0 & 0 & v \\
+     *      \end{array}
+     *      \right)
+     *      \f$
+     */
+    template<typename U>
+    explicit CONSTEXPR TMat44(U v);
+
+    /** sets the diagonal to a vector.
+     *
+     *      \f$
+     *      \left(
+     *      \begin{array}{cccc}
+     *      v[0] & 0 & 0 & 0 \\
+     *      0 & v[1] & 0 & 0 \\
+     *      0 & 0 & v[2] & 0 \\
+     *      0 & 0 & 0 & v[3] \\
+     *      \end{array}
+     *      \right)
+     *      \f$
+     */
+    template <typename U>
+    explicit CONSTEXPR TMat44(const TVec4<U>& v);
+
+    // construct from another matrix of the same size
+    template <typename U>
+    explicit CONSTEXPR TMat44(const TMat44<U>& rhs);
+
+    /** construct from 4 column vectors.
+     *
+     *      \f$
+     *      \left(
+     *      \begin{array}{cccc}
+     *      v0 & v1 & v2 & v3 \\
+     *      \end{array}
+     *      \right)
+     *      \f$
+     */
+    template <typename A, typename B, typename C, typename D>
+    CONSTEXPR TMat44(const TVec4<A>& v0, const TVec4<B>& v1, const TVec4<C>& v2, const TVec4<D>& v3);
+
+    /** construct from 16 elements in column-major form.
+     *
+     *      \f$
+     *      \left(
+     *      \begin{array}{cccc}
+     *      m[0][0] & m[1][0] & m[2][0] & m[3][0] \\
+     *      m[0][1] & m[1][1] & m[2][1] & m[3][1] \\
+     *      m[0][2] & m[1][2] & m[2][2] & m[3][2] \\
+     *      m[0][3] & m[1][3] & m[2][3] & m[3][3] \\
+     *      \end{array}
+     *      \right)
+     *      \f$
+     */
+    template <
+        typename A, typename B, typename C, typename D,
+        typename E, typename F, typename G, typename H,
+        typename I, typename J, typename K, typename L,
+        typename M, typename N, typename O, typename P>
+    CONSTEXPR TMat44(
+            A m00, B m01, C m02, D m03,
+            E m10, F m11, G m12, H m13,
+            I m20, J m21, K m22, L m23,
+            M m30, N m31, O m32, P m33);
+
+    /**
+     * construct from a quaternion
+     */
+    template <typename U>
+    explicit CONSTEXPR TMat44(const TQuaternion<U>& q);
+
+    /**
+     * construct from a C array in column major form.
+     */
+    template <typename U>
+    explicit CONSTEXPR TMat44(U const* rawArray);
+
+    /**
+     * construct from a 3x3 matrix
+     */
+    template <typename U>
+    explicit CONSTEXPR TMat44(const TMat33<U>& matrix);
+
+    /**
+     * construct from a 3x3 matrix and 3d translation
+     */
+    template <typename U, typename V>
+    CONSTEXPR TMat44(const TMat33<U>& matrix, const TVec3<V>& translation);
+
+    /**
+     * construct from a 3x3 matrix and 4d last column.
+     */
+    template <typename U, typename V>
+    CONSTEXPR TMat44(const TMat33<U>& matrix, const TVec4<V>& column3);
+
+    /*
+     *  helpers
+     */
+
+    static CONSTEXPR TMat44 ortho(T left, T right, T bottom, T top, T near, T far);
+
+    static CONSTEXPR TMat44 frustum(T left, T right, T bottom, T top, T near, T far);
+
+    enum class Fov {
+        HORIZONTAL,
+        VERTICAL
+    };
+    static CONSTEXPR TMat44 perspective(T fov, T aspect, T near, T far, Fov direction = Fov::VERTICAL);
+
+    template <typename A, typename B, typename C>
+    static CONSTEXPR TMat44 lookAt(const TVec3<A>& eye, const TVec3<B>& center, const TVec3<C>& up);
+
+    template <typename A>
+    static CONSTEXPR TVec3<A> project(const TMat44& projectionMatrix, TVec3<A> vertice) {
+        TVec4<A> r = projectionMatrix * TVec4<A>{ vertice, 1 };
+        return r.xyz / r.w;
+    }
+
+    template <typename A>
+    static CONSTEXPR TVec4<A> project(const TMat44& projectionMatrix, TVec4<A> vertice) {
+        vertice = projectionMatrix * vertice;
+        return { vertice.xyz / vertice.w, 1 };
+    }
+
+    /**
+     * Constructs a 3x3 matrix from the upper-left corner of this 4x4 matrix
+     */
+    inline constexpr TMat33<T> upperLeft() const {
+        return TMat33<T>(m_value[0].xyz, m_value[1].xyz, m_value[2].xyz);
+    }
+};
+
+// ----------------------------------------------------------------------------------------
+// Constructors
+// ----------------------------------------------------------------------------------------
+
+// Since the matrix code could become pretty big quickly, we don't inline most
+// operations.
+
+template <typename T>
+CONSTEXPR TMat44<T>::TMat44() {
+    m_value[0] = col_type(1, 0, 0, 0);
+    m_value[1] = col_type(0, 1, 0, 0);
+    m_value[2] = col_type(0, 0, 1, 0);
+    m_value[3] = col_type(0, 0, 0, 1);
+}
+
+template <typename T>
+template <typename U>
+CONSTEXPR TMat44<T>::TMat44(U v) {
+    m_value[0] = col_type(v, 0, 0, 0);
+    m_value[1] = col_type(0, v, 0, 0);
+    m_value[2] = col_type(0, 0, v, 0);
+    m_value[3] = col_type(0, 0, 0, v);
+}
+
+template<typename T>
+template<typename U>
+CONSTEXPR TMat44<T>::TMat44(const TVec4<U>& v) {
+    m_value[0] = col_type(v.x, 0, 0, 0);
+    m_value[1] = col_type(0, v.y, 0, 0);
+    m_value[2] = col_type(0, 0, v.z, 0);
+    m_value[3] = col_type(0, 0, 0, v.w);
+}
+
+// construct from 16 scalars
+template<typename T>
+template <
+    typename A, typename B, typename C, typename D,
+    typename E, typename F, typename G, typename H,
+    typename I, typename J, typename K, typename L,
+    typename M, typename N, typename O, typename P>
+CONSTEXPR TMat44<T>::TMat44(
+        A m00, B m01, C m02, D m03,
+        E m10, F m11, G m12, H m13,
+        I m20, J m21, K m22, L m23,
+        M m30, N m31, O m32, P m33) {
+    m_value[0] = col_type(m00, m01, m02, m03);
+    m_value[1] = col_type(m10, m11, m12, m13);
+    m_value[2] = col_type(m20, m21, m22, m23);
+    m_value[3] = col_type(m30, m31, m32, m33);
+}
+
+template <typename T>
+template <typename U>
+CONSTEXPR TMat44<T>::TMat44(const TMat44<U>& rhs) {
+    for (size_t col = 0; col < NUM_COLS; ++col) {
+        m_value[col] = col_type(rhs[col]);
+    }
+}
+
+// Construct from 4 column vectors.
+template <typename T>
+template <typename A, typename B, typename C, typename D>
+CONSTEXPR TMat44<T>::TMat44(
+        const TVec4<A>& v0, const TVec4<B>& v1,
+        const TVec4<C>& v2, const TVec4<D>& v3) {
+    m_value[0] = col_type(v0);
+    m_value[1] = col_type(v1);
+    m_value[2] = col_type(v2);
+    m_value[3] = col_type(v3);
+}
+
+// Construct from raw array, in column-major form.
+template <typename T>
+template <typename U>
+CONSTEXPR TMat44<T>::TMat44(U const* rawArray) {
+    for (size_t col = 0; col < NUM_COLS; ++col) {
+        for (size_t row = 0; row < NUM_ROWS; ++row) {
+            m_value[col][row] = *rawArray++;
+        }
+    }
+}
+
+template <typename T>
+template <typename U>
+CONSTEXPR TMat44<T>::TMat44(const TQuaternion<U>& q) {
+    const U n = q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w;
+    const U s = n > 0 ? 2/n : 0;
+    const U x = s*q.x;
+    const U y = s*q.y;
+    const U z = s*q.z;
+    const U xx = x*q.x;
+    const U xy = x*q.y;
+    const U xz = x*q.z;
+    const U xw = x*q.w;
+    const U yy = y*q.y;
+    const U yz = y*q.z;
+    const U yw = y*q.w;
+    const U zz = z*q.z;
+    const U zw = z*q.w;
+    m_value[0] = col_type(1-yy-zz,    xy+zw,    xz-yw,   0);
+    m_value[1] = col_type(  xy-zw,  1-xx-zz,    yz+xw,   0);  // NOLINT
+    m_value[2] = col_type(  xz+yw,    yz-xw,  1-xx-yy,   0);  // NOLINT
+    m_value[3] = col_type(      0,        0,        0,   1);  // NOLINT
+}
+
+template <typename T>
+template <typename U>
+CONSTEXPR TMat44<T>::TMat44(const TMat33<U>& m) {
+    m_value[0] = col_type(m[0][0], m[0][1], m[0][2], 0);
+    m_value[1] = col_type(m[1][0], m[1][1], m[1][2], 0);
+    m_value[2] = col_type(m[2][0], m[2][1], m[2][2], 0);
+    m_value[3] = col_type(      0,       0,       0, 1);  // NOLINT
+}
+
+template <typename T>
+template <typename U, typename V>
+CONSTEXPR TMat44<T>::TMat44(const TMat33<U>& m, const TVec3<V>& v) {
+    m_value[0] = col_type(m[0][0], m[0][1], m[0][2], 0);
+    m_value[1] = col_type(m[1][0], m[1][1], m[1][2], 0);
+    m_value[2] = col_type(m[2][0], m[2][1], m[2][2], 0);
+    m_value[3] = col_type(   v[0],    v[1],    v[2], 1);  // NOLINT
+}
+
+template <typename T>
+template <typename U, typename V>
+CONSTEXPR TMat44<T>::TMat44(const TMat33<U>& m, const TVec4<V>& v) {
+    m_value[0] = col_type(m[0][0], m[0][1], m[0][2],    0);  // NOLINT
+    m_value[1] = col_type(m[1][0], m[1][1], m[1][2],    0);  // NOLINT
+    m_value[2] = col_type(m[2][0], m[2][1], m[2][2],    0);  // NOLINT
+    m_value[3] = col_type(   v[0],    v[1],    v[2], v[3]);  // NOLINT
+}
+
+// ----------------------------------------------------------------------------------------
+// Helpers
+// ----------------------------------------------------------------------------------------
+
+template <typename T>
+CONSTEXPR TMat44<T> TMat44<T>::ortho(T left, T right, T bottom, T top, T near, T far) {
+    TMat44<T> m;
+    m[0][0] =  2 / (right - left);
+    m[1][1] =  2 / (top   - bottom);
+    m[2][2] = -2 / (far   - near);
+    m[3][0] = -(right + left)   / (right - left);
+    m[3][1] = -(top   + bottom) / (top   - bottom);
+    m[3][2] = -(far   + near)   / (far   - near);
+    return m;
+}
+
+template <typename T>
+CONSTEXPR TMat44<T> TMat44<T>::frustum(T left, T right, T bottom, T top, T near, T far) {
+    TMat44<T> m;
+    m[0][0] =  (2 * near) / (right - left);
+    m[1][1] =  (2 * near) / (top   - bottom);
+    m[2][0] =  (right + left)   / (right - left);
+    m[2][1] =  (top   + bottom) / (top   - bottom);
+    m[2][2] = -(far   + near)   / (far   - near);
+    m[2][3] = -1;
+    m[3][2] = -(2 * far * near) / (far   - near);
+    m[3][3] =  0;
+    return m;
+}
+
+template <typename T>
+CONSTEXPR TMat44<T> TMat44<T>::perspective(T fov, T aspect, T near, T far, TMat44::Fov direction) {
+    T h;
+    T w;
+
+    if (direction == TMat44::Fov::VERTICAL) {
+        h = std::tan(fov * M_PI / 360.0f) * near;
+        w = h * aspect;
+    } else {
+        w = std::tan(fov * M_PI / 360.0f) * near;
+        h = w / aspect;
+    }
+    return frustum(-w, w, -h, h, near, far);
+}
+
+/*
+ * Returns a matrix representing the pose of a virtual camera looking towards -Z in its
+ * local Y-up coordinate system. "eye" is where the camera is located, "center" is the points its
+ * looking at and "up" defines where the Y axis of the camera's local coordinate system is.
+ */
+template <typename T>
+template <typename A, typename B, typename C>
+CONSTEXPR TMat44<T> TMat44<T>::lookAt(const TVec3<A>& eye, const TVec3<B>& center, const TVec3<C>& up) {
+    TVec3<T> z_axis(normalize(center - eye));
+    TVec3<T> norm_up(normalize(up));
+    if (std::abs(dot(z_axis, norm_up)) > 0.999) {
+        // Fix up vector if we're degenerate (looking straight up, basically)
+        norm_up = { norm_up.z, norm_up.x, norm_up.y };
+    }
+    TVec3<T> x_axis(normalize(cross(z_axis, norm_up)));
+    TVec3<T> y_axis(cross(x_axis, z_axis));
+    return TMat44<T>(
+            TVec4<T>(x_axis, 0),
+            TVec4<T>(y_axis, 0),
+            TVec4<T>(-z_axis, 0),
+            TVec4<T>(eye, 1));
+}
+
+// ----------------------------------------------------------------------------------------
+// Arithmetic operators outside of class
+// ----------------------------------------------------------------------------------------
+
+/* We use non-friend functions here to prevent the compiler from using
+ * implicit conversions, for instance of a scalar to a vector. The result would
+ * not be what the caller expects.
+ *
+ * Also note that the order of the arguments in the inner loop is important since
+ * it determines the output type (only relevant when T != U).
+ */
+
+// matrix * column-vector, result is a vector of the same type than the input vector
+template <typename T, typename U>
+CONSTEXPR typename TMat44<T>::col_type PURE operator *(const TMat44<T>& lhs, const TVec4<U>& rhs) {
+    // Result is initialized to zero.
+    typename TMat44<T>::col_type result;
+    for (size_t col = 0; col < TMat44<T>::NUM_COLS; ++col) {
+        result += lhs[col] * rhs[col];
+    }
+    return result;
+}
+
+// mat44 * vec3, result is vec3( mat44 * {vec3, 1} )
+template <typename T, typename U>
+CONSTEXPR typename TMat44<T>::col_type PURE operator *(const TMat44<T>& lhs, const TVec3<U>& rhs) {
+    return lhs * TVec4<U>{ rhs, 1 };
+}
+
+
+// row-vector * matrix, result is a vector of the same type than the input vector
+template <typename T, typename U>
+CONSTEXPR typename TMat44<U>::row_type PURE operator *(const TVec4<U>& lhs, const TMat44<T>& rhs) {
+    typename TMat44<U>::row_type result(TMat44<U>::row_type::NO_INIT);
+    for (size_t col = 0; col < TMat44<T>::NUM_COLS; ++col) {
+        result[col] = dot(lhs, rhs[col]);
+    }
+    return result;
+}
+
+// matrix * scalar, result is a matrix of the same type than the input matrix
+template <typename T, typename U>
+constexpr typename std::enable_if<std::is_arithmetic<U>::value, TMat44<T>>::type PURE
+operator *(TMat44<T> lhs, U rhs) {
+    return lhs *= rhs;
+}
+
+// scalar * matrix, result is a matrix of the same type than the input matrix
+template <typename T, typename U>
+constexpr typename std::enable_if<std::is_arithmetic<U>::value, TMat44<T>>::type PURE
+operator *(U lhs, const TMat44<T>& rhs) {
+    return rhs * lhs;
+}
+
+// ----------------------------------------------------------------------------------------
+
+/* FIXME: this should go into TMatSquareFunctions<> but for some reason
+ * BASE<T>::col_type is not accessible from there (???)
+ */
+template<typename T>
+typename TMat44<T>::col_type PURE diag(const TMat44<T>& m) {
+    return matrix::diag(m);
+}
+
+} // namespace details
+
+// ----------------------------------------------------------------------------------------
+
+typedef details::TMat44<double> mat4d;
+typedef details::TMat44<float> mat4;
+typedef details::TMat44<float> mat4f;
+
+// ----------------------------------------------------------------------------------------
+}  // namespace android
+
+#undef PURE
+#undef CONSTEXPR
diff --git a/libs/math/include/math/quat.h b/libs/math/include/math/quat.h
new file mode 100644
index 0000000..1936a2b
--- /dev/null
+++ b/libs/math/include/math/quat.h
@@ -0,0 +1,192 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <math/half.h>
+#include <math/TQuatHelpers.h>
+#include <math/vec3.h>
+#include <math/vec4.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#ifndef PURE
+#define PURE __attribute__((pure))
+#endif
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
+#pragma clang diagnostic ignored "-Wnested-anon-types"
+
+namespace android {
+// -------------------------------------------------------------------------------------
+
+namespace details {
+
+template <typename T>
+class TQuaternion : public TVecAddOperators<TQuaternion, T>,
+                    public TVecUnaryOperators<TQuaternion, T>,
+                    public TVecComparisonOperators<TQuaternion, T>,
+                    public TQuatProductOperators<TQuaternion, T>,
+                    public TQuatFunctions<TQuaternion, T>,
+                    public TQuatDebug<TQuaternion, T> {
+public:
+    enum no_init { NO_INIT };
+    typedef T value_type;
+    typedef T& reference;
+    typedef T const& const_reference;
+    typedef size_t size_type;
+
+    /*
+     * quaternion internals stored as:
+     *
+     * q = w + xi + yj + zk
+     *
+     *  q[0] = x;
+     *  q[1] = y;
+     *  q[2] = z;
+     *  q[3] = w;
+     *
+     */
+    union {
+        struct { T x, y, z, w; };
+        TVec4<T> xyzw;
+        TVec3<T> xyz;
+        TVec2<T> xy;
+    };
+
+    enum { SIZE = 4 };
+    inline constexpr static size_type size() { return SIZE; }
+
+    // array access
+    inline constexpr T const& operator[](size_t i) const {
+#if __cplusplus >= 201402L
+        // only possible in C++0x14 with constexpr
+        assert(i < SIZE);
+#endif
+        return (&x)[i];
+    }
+
+    inline T& operator[](size_t i) {
+        assert(i < SIZE);
+        return (&x)[i];
+    }
+
+    // -----------------------------------------------------------------------
+    // we want the compiler generated versions for these...
+    TQuaternion(const TQuaternion&) = default;
+    ~TQuaternion() = default;
+    TQuaternion& operator = (const TQuaternion&) = default;
+
+    // constructors
+
+    // leaves object uninitialized. use with caution.
+    explicit
+    constexpr TQuaternion(no_init) : xyzw(TVec4<T>::NO_INIT) {}
+
+    // default constructor. sets all values to zero.
+    constexpr TQuaternion() : x(0), y(0), z(0), w(0) { }
+
+    // handles implicit conversion to a tvec4. must not be explicit.
+    template<typename A>
+    constexpr TQuaternion(A w) : x(0), y(0), z(0), w(w) {
+        static_assert(std::is_arithmetic<A>::value, "requires arithmetic type");
+    }
+
+    // initialize from 4 values to w + xi + yj + zk
+    template<typename A, typename B, typename C, typename D>
+    constexpr TQuaternion(A w, B x, C y, D z) : x(x), y(y), z(z), w(w) { }
+
+    // initialize from a vec3 + a value to : v.xi + v.yj + v.zk + w
+    template<typename A, typename B>
+    constexpr TQuaternion(const TVec3<A>& v, B w) : x(v.x), y(v.y), z(v.z), w(w) { }
+
+    // initialize from a double4
+    template<typename A>
+    constexpr explicit TQuaternion(const TVec4<A>& v) : x(v.x), y(v.y), z(v.z), w(v.w) { }
+
+    // initialize from a quaternion of a different type
+    template<typename A>
+    constexpr explicit TQuaternion(const TQuaternion<A>& v) : x(v.x), y(v.y), z(v.z), w(v.w) { }
+
+    // conjugate operator
+    constexpr TQuaternion operator~() const {
+        return conj(*this);
+    }
+
+    // constructs a quaternion from an axis and angle
+    template <typename A, typename B>
+    constexpr static TQuaternion PURE fromAxisAngle(const TVec3<A>& axis, B angle) {
+        return TQuaternion(std::sin(angle*0.5) * normalize(axis), std::cos(angle*0.5));
+    }
+};
+
+}  // namespace details
+
+// ----------------------------------------------------------------------------------------
+
+typedef details::TQuaternion<double> quatd;
+typedef details::TQuaternion<float> quat;
+typedef details::TQuaternion<float> quatf;
+typedef details::TQuaternion<half> quath;
+
+constexpr inline quat operator"" _i(long double v) {
+    return quat(0, static_cast<float>(v), 0, 0);
+}
+constexpr inline quat operator"" _j(long double v) {
+    return quat(0, 0, static_cast<float>(v), 0);
+}
+constexpr inline quat operator"" _k(long double v) {
+    return quat(0, 0, 0, static_cast<float>(v));
+}
+
+constexpr inline quat operator"" _i(unsigned long long v) {  // NOLINT
+    return quat(0, static_cast<float>(v), 0, 0);
+}
+constexpr inline quat operator"" _j(unsigned long long v) {  // NOLINT
+    return quat(0, 0, static_cast<float>(v), 0);
+}
+constexpr inline quat operator"" _k(unsigned long long v) {  // NOLINT
+    return quat(0, 0, 0, static_cast<float>(v));
+}
+
+constexpr inline quatd operator"" _id(long double v) {
+    return quatd(0, static_cast<double>(v), 0, 0);
+}
+constexpr inline quatd operator"" _jd(long double v) {
+    return quatd(0, 0, static_cast<double>(v), 0);
+}
+constexpr inline quatd operator"" _kd(long double v) {
+    return quatd(0, 0, 0, static_cast<double>(v));
+}
+
+constexpr inline quatd operator"" _id(unsigned long long v) {  // NOLINT
+    return quatd(0, static_cast<double>(v), 0, 0);
+}
+constexpr inline quatd operator"" _jd(unsigned long long v) {  // NOLINT
+    return quatd(0, 0, static_cast<double>(v), 0);
+}
+constexpr inline quatd operator"" _kd(unsigned long long v) {  // NOLINT
+    return quatd(0, 0, 0, static_cast<double>(v));
+}
+
+// ----------------------------------------------------------------------------------------
+}  // namespace android
+
+#pragma clang diagnostic pop
+
+#undef PURE
diff --git a/libs/math/include/math/scalar.h b/libs/math/include/math/scalar.h
new file mode 100644
index 0000000..2eced92
--- /dev/null
+++ b/libs/math/include/math/scalar.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <cmath>
+
+namespace android {
+
+template<typename T>
+static constexpr T saturate(T v) noexcept {
+    return T(std::min(T(1), std::max(T(0), v)));
+}
+
+template<typename T>
+static constexpr T clamp(T v, T min, T max) noexcept {
+    return T(std::min(max, std::max(min, v)));
+}
+
+template<typename T>
+static constexpr T mix(T x, T y, T a) noexcept {
+    return x * (T(1) - a) + y * a;
+}
+
+template<typename T>
+static constexpr T lerp(T x, T y, T a) noexcept {
+    return mix(x, y, a);
+}
+
+} // namespace std
diff --git a/libs/math/include/math/vec2.h b/libs/math/include/math/vec2.h
new file mode 100644
index 0000000..a347633
--- /dev/null
+++ b/libs/math/include/math/vec2.h
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <math/TVecHelpers.h>
+#include <math/half.h>
+#include <assert.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <type_traits>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
+#pragma clang diagnostic ignored "-Wnested-anon-types"
+
+namespace android {
+// -------------------------------------------------------------------------------------
+
+namespace details {
+
+template <typename T>
+class TVec2 :   public TVecProductOperators<TVec2, T>,
+                public TVecAddOperators<TVec2, T>,
+                public TVecUnaryOperators<TVec2, T>,
+                public TVecComparisonOperators<TVec2, T>,
+                public TVecFunctions<TVec2, T>,
+                public TVecDebug<TVec2, T> {
+public:
+    enum no_init { NO_INIT };
+    typedef T value_type;
+    typedef T& reference;
+    typedef T const& const_reference;
+    typedef size_t size_type;
+
+    union {
+        struct { T x, y; };
+        struct { T s, t; };
+        struct { T r, g; };
+    };
+
+    static constexpr size_t SIZE = 2;
+    inline constexpr size_type size() const { return SIZE; }
+
+    // array access
+    inline constexpr T const& operator[](size_t i) const {
+#if __cplusplus >= 201402L
+        // only possible in C++0x14 with constexpr
+        assert(i < SIZE);
+#endif
+        return (&x)[i];
+    }
+
+    inline T& operator[](size_t i) {
+        assert(i < SIZE);
+        return (&x)[i];
+    }
+
+    // -----------------------------------------------------------------------
+    // we want the compiler generated versions for these...
+    TVec2(const TVec2&) = default;
+    ~TVec2() = default;
+    TVec2& operator = (const TVec2&) = default;
+
+    // constructors
+
+    // leaves object uninitialized. use with caution.
+    explicit
+    constexpr TVec2(no_init) { }
+
+    // default constructor
+    constexpr TVec2() : x(0), y(0) { }
+
+    // handles implicit conversion to a tvec4. must not be explicit.
+    template<typename A, typename = typename std::enable_if<std::is_arithmetic<A>::value >::type>
+    constexpr TVec2(A v) : x(v), y(v) { }
+
+    template<typename A, typename B>
+    constexpr TVec2(A x, B y) : x(x), y(y) { }
+
+    template<typename A>
+    explicit
+    constexpr TVec2(const TVec2<A>& v) : x(v.x), y(v.y) { }
+
+    // cross product works only on vectors of size 2 or 3
+    template<typename RT>
+    friend inline
+    constexpr value_type cross(const TVec2& u, const TVec2<RT>& v) {
+        return value_type(u.x*v.y - u.y*v.x);
+    }
+};
+
+}  // namespace details
+
+// ----------------------------------------------------------------------------------------
+
+typedef details::TVec2<double> double2;
+typedef details::TVec2<float> float2;
+typedef details::TVec2<float> vec2;
+typedef details::TVec2<half> half2;
+typedef details::TVec2<int32_t> int2;
+typedef details::TVec2<uint32_t> uint2;
+typedef details::TVec2<int16_t> short2;
+typedef details::TVec2<uint16_t> ushort2;
+typedef details::TVec2<int8_t> byte2;
+typedef details::TVec2<uint8_t> ubyte2;
+typedef details::TVec2<bool> bool2;
+
+// ----------------------------------------------------------------------------------------
+}  // namespace android
+
+#pragma clang diagnostic pop
diff --git a/libs/math/include/math/vec3.h b/libs/math/include/math/vec3.h
new file mode 100644
index 0000000..009fd84
--- /dev/null
+++ b/libs/math/include/math/vec3.h
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <math/vec2.h>
+#include <math/half.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
+#pragma clang diagnostic ignored "-Wnested-anon-types"
+
+namespace android {
+// -------------------------------------------------------------------------------------
+
+namespace details {
+
+template <typename T>
+class TVec3 :   public TVecProductOperators<TVec3, T>,
+                public TVecAddOperators<TVec3, T>,
+                public TVecUnaryOperators<TVec3, T>,
+                public TVecComparisonOperators<TVec3, T>,
+                public TVecFunctions<TVec3, T>,
+                public TVecDebug<TVec3, T> {
+public:
+    enum no_init { NO_INIT };
+    typedef T value_type;
+    typedef T& reference;
+    typedef T const& const_reference;
+    typedef size_t size_type;
+
+    union {
+        struct { T x, y, z; };
+        struct { T s, t, p; };
+        struct { T r, g, b; };
+        TVec2<T> xy;
+        TVec2<T> st;
+        TVec2<T> rg;
+    };
+
+    static constexpr size_t SIZE = 3;
+    inline constexpr size_type size() const { return SIZE; }
+
+    // array access
+    inline constexpr T const& operator[](size_t i) const {
+#if __cplusplus >= 201402L
+        // only possible in C++0x14 with constexpr
+        assert(i < SIZE);
+#endif
+        return (&x)[i];
+    }
+
+    inline T& operator[](size_t i) {
+        assert(i < SIZE);
+        return (&x)[i];
+    }
+
+    // -----------------------------------------------------------------------
+    // we want the compiler generated versions for these...
+    TVec3(const TVec3&) = default;
+    ~TVec3() = default;
+    TVec3& operator = (const TVec3&) = default;
+
+    // constructors
+    // leaves object uninitialized. use with caution.
+    explicit
+    constexpr TVec3(no_init) { }
+
+    // default constructor
+    constexpr TVec3() : x(0), y(0), z(0) { }
+
+    // handles implicit conversion to a tvec4. must not be explicit.
+    template<typename A, typename = typename std::enable_if<std::is_arithmetic<A>::value >::type>
+    constexpr TVec3(A v) : x(v), y(v), z(v) { }
+
+    template<typename A, typename B, typename C>
+    constexpr TVec3(A x, B y, C z) : x(x), y(y), z(z) { }
+
+    template<typename A, typename B>
+    constexpr TVec3(const TVec2<A>& v, B z) : x(v.x), y(v.y), z(z) { }
+
+    template<typename A>
+    explicit
+    constexpr TVec3(const TVec3<A>& v) : x(v.x), y(v.y), z(v.z) { }
+
+    // cross product works only on vectors of size 3
+    template <typename RT>
+    friend inline
+    constexpr TVec3 cross(const TVec3& u, const TVec3<RT>& v) {
+        return TVec3(
+                u.y*v.z - u.z*v.y,
+                u.z*v.x - u.x*v.z,
+                u.x*v.y - u.y*v.x);
+    }
+};
+
+}  // namespace details
+
+// ----------------------------------------------------------------------------------------
+
+typedef details::TVec3<double> double3;
+typedef details::TVec3<float> float3;
+typedef details::TVec3<float> vec3;
+typedef details::TVec3<half> half3;
+typedef details::TVec3<int32_t> int3;
+typedef details::TVec3<uint32_t> uint3;
+typedef details::TVec3<int16_t> short3;
+typedef details::TVec3<uint16_t> ushort3;
+typedef details::TVec3<int8_t> byte3;
+typedef details::TVec3<uint8_t> ubyte3;
+typedef details::TVec3<bool> bool3;
+
+// ----------------------------------------------------------------------------------------
+}  // namespace android
+
+#pragma clang diagnostic pop
diff --git a/libs/math/include/math/vec4.h b/libs/math/include/math/vec4.h
new file mode 100644
index 0000000..1e279fe
--- /dev/null
+++ b/libs/math/include/math/vec4.h
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <math/vec3.h>
+#include <math/half.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
+#pragma clang diagnostic ignored "-Wnested-anon-types"
+
+namespace android {
+// -------------------------------------------------------------------------------------
+
+namespace details {
+
+template <typename T>
+class  TVec4 :  public TVecProductOperators<TVec4, T>,
+                public TVecAddOperators<TVec4, T>,
+                public TVecUnaryOperators<TVec4, T>,
+                public TVecComparisonOperators<TVec4, T>,
+                public TVecFunctions<TVec4, T>,
+                public TVecDebug<TVec4, T> {
+public:
+    enum no_init { NO_INIT };
+    typedef T value_type;
+    typedef T& reference;
+    typedef T const& const_reference;
+    typedef size_t size_type;
+
+    union {
+        struct { T x, y, z, w; };
+        struct { T s, t, p, q; };
+        struct { T r, g, b, a; };
+        TVec2<T> xy;
+        TVec2<T> st;
+        TVec2<T> rg;
+        TVec3<T> xyz;
+        TVec3<T> stp;
+        TVec3<T> rgb;
+    };
+
+    static constexpr size_t SIZE = 4;
+    inline constexpr size_type size() const { return SIZE; }
+
+    // array access
+    inline constexpr T const& operator[](size_t i) const {
+#if __cplusplus >= 201402L
+        // only possible in C++0x14 with constexpr
+        assert(i < SIZE);
+#endif
+        return (&x)[i];
+    }
+
+    inline T& operator[](size_t i) {
+        assert(i < SIZE);
+        return (&x)[i];
+    }
+
+    // -----------------------------------------------------------------------
+    // we want the compiler generated versions for these...
+    TVec4(const TVec4&) = default;
+    ~TVec4() = default;
+    TVec4& operator = (const TVec4&) = default;
+
+    // constructors
+
+    // leaves object uninitialized. use with caution.
+    explicit
+    constexpr TVec4(no_init) { }
+
+    // default constructor
+    constexpr TVec4() : x(0), y(0), z(0), w(0) { }
+
+    // handles implicit conversion to a tvec4. must not be explicit.
+    template<typename A, typename = typename std::enable_if<std::is_arithmetic<A>::value >::type>
+    constexpr TVec4(A v) : x(v), y(v), z(v), w(v) { }
+
+    template<typename A, typename B, typename C, typename D>
+    constexpr TVec4(A x, B y, C z, D w) : x(x), y(y), z(z), w(w) { }
+
+    template<typename A, typename B, typename C>
+    constexpr TVec4(const TVec2<A>& v, B z, C w) : x(v.x), y(v.y), z(z), w(w) { }
+
+    template<typename A, typename B>
+    constexpr TVec4(const TVec3<A>& v, B w) : x(v.x), y(v.y), z(v.z), w(w) { }
+
+    template<typename A>
+    explicit
+    constexpr TVec4(const TVec4<A>& v) : x(v.x), y(v.y), z(v.z), w(v.w) { }
+};
+
+}  // namespace details
+
+// ----------------------------------------------------------------------------------------
+
+typedef details::TVec4<double> double4;
+typedef details::TVec4<float> float4;
+typedef details::TVec4<float> vec4;
+typedef details::TVec4<half> half4;
+typedef details::TVec4<int32_t> int4;
+typedef details::TVec4<uint32_t> uint4;
+typedef details::TVec4<int16_t> short4;
+typedef details::TVec4<uint16_t> ushort4;
+typedef details::TVec4<int8_t> byte4;
+typedef details::TVec4<uint8_t> ubyte4;
+typedef details::TVec4<bool> bool4;
+
+// ----------------------------------------------------------------------------------------
+}  // namespace android
+
+#pragma clang diagnostic pop
diff --git a/libs/math/tests/Android.bp b/libs/math/tests/Android.bp
new file mode 100644
index 0000000..0ed24a2
--- /dev/null
+++ b/libs/math/tests/Android.bp
@@ -0,0 +1,39 @@
+//
+// 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.
+//
+
+cc_test {
+    name: "vec_test",
+    srcs: ["vec_test.cpp"],
+    static_libs: ["libmath"],
+}
+
+cc_test {
+    name: "mat_test",
+    srcs: ["mat_test.cpp"],
+    static_libs: ["libmath"],
+}
+
+cc_test {
+    name: "half_test",
+    srcs: ["half_test.cpp"],
+    static_libs: ["libmath"],
+}
+
+cc_test {
+    name: "quat_test",
+    srcs: ["quat_test.cpp"],
+    static_libs: ["libmath"],
+}
diff --git a/libs/math/tests/half_test.cpp b/libs/math/tests/half_test.cpp
new file mode 100644
index 0000000..496a7ef
--- /dev/null
+++ b/libs/math/tests/half_test.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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_TAG "HalfTest"
+
+#include <math.h>
+#include <stdlib.h>
+
+#include <math/half.h>
+#include <math/vec4.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+
+class HalfTest : public testing::Test {
+protected:
+};
+
+TEST_F(HalfTest, Basics) {
+
+    EXPECT_EQ(2UL, sizeof(half));
+
+    // test +/- zero
+    EXPECT_EQ(0x0000, half( 0.0f).getBits());
+    EXPECT_EQ(0x8000, half(-0.0f).getBits());
+
+    // test nan
+    EXPECT_EQ(0x7e00, half(NAN).getBits());
+
+    // test +/- infinity
+    EXPECT_EQ(0x7C00, half( std::numeric_limits<float>::infinity()).getBits());
+    EXPECT_EQ(0xFC00, half(-std::numeric_limits<float>::infinity()).getBits());
+
+    // test a few known values
+    EXPECT_EQ(0x3C01, half(1.0009765625).getBits());
+    EXPECT_EQ(0xC000, half(-2).getBits());
+    EXPECT_EQ(0x0400, half(6.10352e-5).getBits());
+    EXPECT_EQ(0x7BFF, half(65504).getBits());
+    EXPECT_EQ(0x3555, half(1.0f/3).getBits());
+
+    // numeric limits
+    EXPECT_EQ(0x7C00, std::numeric_limits<half>::infinity().getBits());
+    EXPECT_EQ(0x0400, std::numeric_limits<half>::min().getBits());
+    EXPECT_EQ(0x7BFF, std::numeric_limits<half>::max().getBits());
+    EXPECT_EQ(0xFBFF, std::numeric_limits<half>::lowest().getBits());
+
+    // denormals (flushed to zero)
+    EXPECT_EQ(0x0000, half( 6.09756e-5).getBits());      // if handled, should be: 0x03FF
+    EXPECT_EQ(0x0000, half( 5.96046e-8).getBits());      // if handled, should be: 0x0001
+    EXPECT_EQ(0x8000, half(-6.09756e-5).getBits());      // if handled, should be: 0x83FF
+    EXPECT_EQ(0x8000, half(-5.96046e-8).getBits());      // if handled, should be: 0x8001
+
+    // test all exactly representable integers
+    for (int i=-2048 ; i<= 2048 ; ++i) {
+        half h = i;
+        EXPECT_EQ(i, float(h));
+    }
+}
+
+TEST_F(HalfTest, Literals) {
+    half one = 1.0_hf;
+    half pi = 3.1415926_hf;
+    half minusTwo = -2.0_hf;
+
+    EXPECT_EQ(half(1.0f), one);
+    EXPECT_EQ(half(3.1415926), pi);
+    EXPECT_EQ(half(-2.0f), minusTwo);
+}
+
+
+TEST_F(HalfTest, Vec) {
+    float4 f4(1,2,3,4);
+    half4 h4(f4);
+    half3 h3(f4.xyz);
+    half2 h2(f4.xy);
+
+    EXPECT_EQ(f4, h4);
+    EXPECT_EQ(f4.xyz, h3);
+    EXPECT_EQ(f4.xy, h2);
+}
+
+}; // namespace android
diff --git a/libs/math/tests/mat_test.cpp b/libs/math/tests/mat_test.cpp
new file mode 100644
index 0000000..c365366
--- /dev/null
+++ b/libs/math/tests/mat_test.cpp
@@ -0,0 +1,692 @@
+/*
+ * 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_TAG "MatTest"
+
+#include <stdlib.h>
+
+#include <limits>
+#include <random>
+#include <functional>
+
+#include <gtest/gtest.h>
+
+#include <math/mat2.h>
+#include <math/mat4.h>
+
+namespace android {
+
+class MatTest : public testing::Test {
+protected:
+};
+
+TEST_F(MatTest, Basics) {
+    mat4 m0;
+    EXPECT_EQ(sizeof(mat4), sizeof(float)*16);
+}
+
+TEST_F(MatTest, ComparisonOps) {
+    mat4 m0;
+    mat4 m1(2);
+
+    EXPECT_TRUE(m0 == m0);
+    EXPECT_TRUE(m0 != m1);
+    EXPECT_FALSE(m0 != m0);
+    EXPECT_FALSE(m0 == m1);
+}
+
+TEST_F(MatTest, Constructors) {
+    mat4 m0;
+    ASSERT_EQ(m0[0].x, 1);
+    ASSERT_EQ(m0[0].y, 0);
+    ASSERT_EQ(m0[0].z, 0);
+    ASSERT_EQ(m0[0].w, 0);
+    ASSERT_EQ(m0[1].x, 0);
+    ASSERT_EQ(m0[1].y, 1);
+    ASSERT_EQ(m0[1].z, 0);
+    ASSERT_EQ(m0[1].w, 0);
+    ASSERT_EQ(m0[2].x, 0);
+    ASSERT_EQ(m0[2].y, 0);
+    ASSERT_EQ(m0[2].z, 1);
+    ASSERT_EQ(m0[2].w, 0);
+    ASSERT_EQ(m0[3].x, 0);
+    ASSERT_EQ(m0[3].y, 0);
+    ASSERT_EQ(m0[3].z, 0);
+    ASSERT_EQ(m0[3].w, 1);
+
+    mat4 m1(2);
+    mat4 m2(vec4(2));
+    mat4 m3(m2);
+
+    EXPECT_EQ(m1, m2);
+    EXPECT_EQ(m2, m3);
+    EXPECT_EQ(m3, m1);
+
+    mat4 m4(vec4(1), vec4(2), vec4(3), vec4(4));
+}
+
+TEST_F(MatTest, ArithmeticOps) {
+    mat4 m0;
+    mat4 m1(2);
+    mat4 m2(vec4(2));
+
+    m1 += m2;
+    EXPECT_EQ(mat4(4), m1);
+
+    m2 -= m1;
+    EXPECT_EQ(mat4(-2), m2);
+
+    m1 *= 2;
+    EXPECT_EQ(mat4(8), m1);
+
+    m1 /= 2;
+    EXPECT_EQ(mat4(4), m1);
+
+    m0 = -m0;
+    EXPECT_EQ(mat4(-1), m0);
+}
+
+TEST_F(MatTest, UnaryOps) {
+    const mat4 identity;
+    mat4 m0;
+
+    m0 = -m0;
+    EXPECT_EQ(mat4(vec4(-1, 0,  0,  0),
+                   vec4(0, -1,  0,  0),
+                   vec4(0,  0, -1,