Merge "Fix one last use of TRACE()."
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 46a6365..352283c 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -371,19 +371,7 @@
     *buf = '\0';
 }
 
-static void copy_to_file(int inFd, int outFd) {
-    const size_t BUFSIZE = 32 * 1024;
-    char* buf = (char*) malloc(BUFSIZE);
-    if (buf == nullptr) fatal("couldn't allocate buffer for copy_to_file");
-    int len;
-    long total = 0;
-#ifdef _WIN32
-    int old_stdin_mode = -1;
-    int old_stdout_mode = -1;
-#endif
-
-    D("copy_to_file(%d -> %d)", inFd, outFd);
-
+static void stdinout_raw_prologue(int inFd, int outFd, int& old_stdin_mode, int& old_stdout_mode) {
     if (inFd == STDIN_FILENO) {
         stdin_raw_init();
 #ifdef _WIN32
@@ -402,6 +390,39 @@
         }
     }
 #endif
+}
+
+static void stdinout_raw_epilogue(int inFd, int outFd, int old_stdin_mode, int old_stdout_mode) {
+    if (inFd == STDIN_FILENO) {
+        stdin_raw_restore();
+#ifdef _WIN32
+        if (_setmode(STDIN_FILENO, old_stdin_mode) == -1) {
+            fatal_errno("could not restore stdin mode");
+        }
+#endif
+    }
+
+#ifdef _WIN32
+    if (outFd == STDOUT_FILENO) {
+        if (_setmode(STDOUT_FILENO, old_stdout_mode) == -1) {
+            fatal_errno("could not restore stdout mode");
+        }
+    }
+#endif
+}
+
+static void copy_to_file(int inFd, int outFd) {
+    const size_t BUFSIZE = 32 * 1024;
+    char* buf = (char*) malloc(BUFSIZE);
+    if (buf == nullptr) fatal("couldn't allocate buffer for copy_to_file");
+    int len;
+    long total = 0;
+    int old_stdin_mode = -1;
+    int old_stdout_mode = -1;
+
+    D("copy_to_file(%d -> %d)", inFd, outFd);
+
+    stdinout_raw_prologue(inFd, outFd, old_stdin_mode, old_stdout_mode);
 
     while (true) {
         if (inFd == STDIN_FILENO) {
@@ -426,22 +447,7 @@
         total += len;
     }
 
-    if (inFd == STDIN_FILENO) {
-        stdin_raw_restore();
-#ifdef _WIN32
-        if (_setmode(STDIN_FILENO, old_stdin_mode) == -1) {
-            fatal_errno("could not restore stdin mode");
-        }
-#endif
-    }
-
-#ifdef _WIN32
-    if (outFd == STDOUT_FILENO) {
-        if (_setmode(STDOUT_FILENO, old_stdout_mode) == -1) {
-            fatal_errno("could not restore stdout mode");
-        }
-    }
-#endif
+    stdinout_raw_epilogue(inFd, outFd, old_stdin_mode, old_stdout_mode);
 
     D("copy_to_file() finished after %lu bytes", total);
     free(buf);
@@ -1222,6 +1228,29 @@
     return send_shell_command(transport, serial, cmd, true);
 }
 
+static void write_zeros(int bytes, int fd) {
+    int old_stdin_mode = -1;
+    int old_stdout_mode = -1;
+    char* buf = (char*) calloc(1, bytes);
+    if (buf == nullptr) fatal("couldn't allocate buffer for write_zeros");
+
+    D("write_zeros(%d) -> %d", bytes, fd);
+
+    stdinout_raw_prologue(-1, fd, old_stdin_mode, old_stdout_mode);
+
+    if (fd == STDOUT_FILENO) {
+        fwrite(buf, 1, bytes, stdout);
+        fflush(stdout);
+    } else {
+        adb_write(fd, buf, bytes);
+    }
+
+    stdinout_raw_prologue(-1, fd, old_stdin_mode, old_stdout_mode);
+
+    D("write_zeros() finished");
+    free(buf);
+}
+
 static int backup(int argc, const char** argv) {
     const char* filename = "backup.ab";
 
@@ -1302,6 +1331,9 @@
     printf("Now unlock your device and confirm the restore operation.\n");
     copy_to_file(tarFd, fd);
 
+    // Provide an in-band EOD marker in case the archive file is malformed
+    write_zeros(512*2, fd);
+
     // Wait until the other side finishes, or it'll get sent SIGHUP.
     copy_to_file(fd, STDOUT_FILENO);
 
@@ -1436,6 +1468,16 @@
 #endif
 }
 
+static bool _use_legacy_install() {
+    FeatureSet features;
+    std::string error;
+    if (!adb_get_feature_set(&features, &error)) {
+        fprintf(stderr, "error: %s\n", error.c_str());
+        return true;
+    }
+    return !CanUseFeature(features, kFeatureCmd);
+}
+
 int adb_commandline(int argc, const char **argv) {
     int no_daemon = 0;
     int is_daemon = 0;
@@ -1830,17 +1872,10 @@
     }
     else if (!strcmp(argv[0], "install")) {
         if (argc < 2) return usage();
-        FeatureSet features;
-        std::string error;
-        if (!adb_get_feature_set(&features, &error)) {
-            fprintf(stderr, "error: %s\n", error.c_str());
-            return 1;
+        if (_use_legacy_install()) {
+            return install_app_legacy(transport_type, serial, argc, argv);
         }
-
-        if (CanUseFeature(features, kFeatureCmd)) {
-            return install_app(transport_type, serial, argc, argv);
-        }
-        return install_app_legacy(transport_type, serial, argc, argv);
+        return install_app(transport_type, serial, argc, argv);
     }
     else if (!strcmp(argv[0], "install-multiple")) {
         if (argc < 2) return usage();
@@ -1848,17 +1883,10 @@
     }
     else if (!strcmp(argv[0], "uninstall")) {
         if (argc < 2) return usage();
-        FeatureSet features;
-        std::string error;
-        if (!adb_get_feature_set(&features, &error)) {
-            fprintf(stderr, "error: %s\n", error.c_str());
-            return 1;
+        if (_use_legacy_install()) {
+            return uninstall_app_legacy(transport_type, serial, argc, argv);
         }
-
-        if (CanUseFeature(features, kFeatureCmd)) {
-            return uninstall_app(transport_type, serial, argc, argv);
-        }
-        return uninstall_app_legacy(transport_type, serial, argc, argv);
+        return uninstall_app(transport_type, serial, argc, argv);
     }
     else if (!strcmp(argv[0], "sync")) {
         std::string src;
@@ -2072,7 +2100,6 @@
     int i;
     struct stat sb;
     uint64_t total_size = 0;
-
     // Find all APK arguments starting at end.
     // All other arguments passed through verbatim.
     int first_apk = -1;
@@ -2097,7 +2124,14 @@
         return 1;
     }
 
-    std::string cmd = android::base::StringPrintf("exec:pm install-create -S %" PRIu64, total_size);
+    std::string install_cmd;
+    if (_use_legacy_install()) {
+        install_cmd = "exec:pm";
+    } else {
+        install_cmd = "exec:cmd package";
+    }
+
+    std::string cmd = android::base::StringPrintf("%s install-create -S %" PRIu64, install_cmd.c_str(), total_size);
     for (i = 1; i < first_apk; i++) {
         cmd += " " + escape_arg(argv[i]);
     }
@@ -2139,8 +2173,8 @@
         }
 
         std::string cmd = android::base::StringPrintf(
-                "exec:pm install-write -S %" PRIu64 " %d %d_%s -",
-                static_cast<uint64_t>(sb.st_size), session_id, i, adb_basename(file).c_str());
+                "%s install-write -S %" PRIu64 " %d %d_%s -",
+                install_cmd.c_str(), static_cast<uint64_t>(sb.st_size), session_id, i, adb_basename(file).c_str());
 
         int localFd = adb_open(file, O_RDONLY);
         if (localFd < 0) {
@@ -2175,8 +2209,8 @@
 finalize_session:
     // Commit session if we streamed everything okay; otherwise abandon
     std::string service =
-            android::base::StringPrintf("exec:pm install-%s %d",
-                                        success ? "commit" : "abandon", session_id);
+            android::base::StringPrintf("%s install-%s %d",
+                                        install_cmd.c_str(), success ? "commit" : "abandon", session_id);
     fd = adb_connect(service, &error);
     if (fd < 0) {
         fprintf(stderr, "Connect error for finalize: %s\n", error.c_str());
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index a4e9cae..c352aeb 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -182,6 +182,16 @@
    return allowed;
 }
 
+static bool pid_contains_tid(pid_t pid, pid_t tid) {
+  char task_path[PATH_MAX];
+  if (snprintf(task_path, PATH_MAX, "/proc/%d/task/%d", pid, tid) >= PATH_MAX) {
+    ALOGE("debuggerd: task path overflow (pid = %d, tid = %d)\n", pid, tid);
+    exit(1);
+  }
+
+  return access(task_path, F_OK) == 0;
+}
+
 static int read_request(int fd, debugger_request_t* out_request) {
   ucred cr;
   socklen_t len = sizeof(cr);
@@ -226,16 +236,13 @@
 
   if (msg.action == DEBUGGER_ACTION_CRASH) {
     // Ensure that the tid reported by the crashing process is valid.
-    char buf[64];
-    struct stat s;
-    snprintf(buf, sizeof buf, "/proc/%d/task/%d", out_request->pid, out_request->tid);
-    if (stat(buf, &s)) {
-      ALOGE("tid %d does not exist in pid %d. ignoring debug request\n",
-          out_request->tid, out_request->pid);
+    // This check needs to happen again after ptracing the requested thread to prevent a race.
+    if (!pid_contains_tid(out_request->pid, out_request->tid)) {
+      ALOGE("tid %d does not exist in pid %d. ignoring debug request\n", out_request->tid,
+            out_request->pid);
       return -1;
     }
-  } else if (cr.uid == 0
-            || (cr.uid == AID_SYSTEM && msg.action == DEBUGGER_ACTION_DUMP_BACKTRACE)) {
+  } else if (cr.uid == 0 || (cr.uid == AID_SYSTEM && msg.action == DEBUGGER_ACTION_DUMP_BACKTRACE)) {
     // Only root or system can ask us to attach to any process and dump it explicitly.
     // However, system is only allowed to collect backtraces but cannot dump tombstones.
     status = get_process_info(out_request->tid, &out_request->pid,
@@ -412,10 +419,31 @@
 }
 #endif
 
-static void ptrace_siblings(pid_t pid, pid_t main_tid, std::set<pid_t>& tids) {
-  char task_path[64];
+// Attach to a thread, and verify that it's still a member of the given process
+static bool ptrace_attach_thread(pid_t pid, pid_t tid) {
+  if (ptrace(PTRACE_ATTACH, tid, 0, 0) != 0) {
+    return false;
+  }
 
-  snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
+  // Make sure that the task we attached to is actually part of the pid we're dumping.
+  if (!pid_contains_tid(pid, tid)) {
+    if (ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
+      ALOGE("debuggerd: failed to detach from thread '%d'", tid);
+      exit(1);
+    }
+    return false;
+  }
+
+  return true;
+}
+
+static void ptrace_siblings(pid_t pid, pid_t main_tid, std::set<pid_t>& tids) {
+  char task_path[PATH_MAX];
+
+  if (snprintf(task_path, PATH_MAX, "/proc/%d/task", pid) >= PATH_MAX) {
+    ALOGE("debuggerd: task path overflow (pid = %d)\n", pid);
+    abort();
+  }
 
   std::unique_ptr<DIR, int (*)(DIR*)> d(opendir(task_path), closedir);
 
@@ -442,7 +470,7 @@
       continue;
     }
 
-    if (ptrace(PTRACE_ATTACH, tid, 0, 0) < 0) {
+    if (!ptrace_attach_thread(pid, tid)) {
       ALOGE("debuggerd: ptrace attach to %d failed: %s", tid, strerror(errno));
       continue;
     }
@@ -567,11 +595,33 @@
   // debugger_signal_handler().
 
   // Attach to the target process.
-  if (ptrace(PTRACE_ATTACH, request.tid, 0, 0) != 0) {
+  if (!ptrace_attach_thread(request.pid, request.tid)) {
     ALOGE("debuggerd: ptrace attach failed: %s", strerror(errno));
     exit(1);
   }
 
+  // DEBUGGER_ACTION_CRASH requests can come from arbitrary processes and the tid field in the
+  // request is sent from the other side. If an attacker can cause a process to be spawned with the
+  // pid of their process, they could trick debuggerd into dumping that process by exiting after
+  // sending the request. Validate the trusted request.uid/gid to defend against this.
+  if (request.action == DEBUGGER_ACTION_CRASH) {
+    pid_t pid;
+    uid_t uid;
+    gid_t gid;
+    if (get_process_info(request.tid, &pid, &uid, &gid) != 0) {
+      ALOGE("debuggerd: failed to get process info for tid '%d'", request.tid);
+      exit(1);
+    }
+
+    if (pid != request.pid || uid != request.uid || gid != request.gid) {
+      ALOGE(
+        "debuggerd: attached task %d does not match request: "
+        "expected pid=%d,uid=%d,gid=%d, actual pid=%d,uid=%d,gid=%d",
+        request.tid, request.pid, request.uid, request.gid, pid, uid, gid);
+      exit(1);
+    }
+  }
+
   // Don't attach to the sibling threads if we want to attach gdb.
   // Supposedly, it makes the process less reliable.
   bool attach_gdb = should_attach_gdb(request);
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index aeef43d..5dde490 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -99,20 +99,42 @@
 };
 
 static struct {
-    char img_name[13];
-    char sig_name[13];
+    char img_name[17];
+    char sig_name[17];
     char part_name[9];
     bool is_optional;
+    bool is_secondary;
 } images[] = {
-    {"boot.img", "boot.sig", "boot", false},
-    {"recovery.img", "recovery.sig", "recovery", true},
-    {"system.img", "system.sig", "system", false},
-    {"vendor.img", "vendor.sig", "vendor", true},
+    {"boot.img", "boot.sig", "boot", false, false},
+    {"boot_other.img", "boot.sig", "boot", true, true},
+    {"recovery.img", "recovery.sig", "recovery", true, false},
+    {"system.img", "system.sig", "system", false, false},
+    {"system_other.img", "system.sig", "system", true, true},
+    {"vendor.img", "vendor.sig", "vendor", true, false},
+    {"vendor_other.img", "vendor.sig", "vendor", true, true},
 };
 
-static std::string find_item(const char* item, const char* product) {
+static std::string find_item_given_name(const char* img_name, const char* product) {
+    char *dir;
+
+    if(product) {
+        std::string path = get_my_path();
+        return android::base::StringPrintf("%s/../../../target/product/%s/%s",
+                                           path.c_str(), product, img_name);
+    }
+
+    dir = getenv("ANDROID_PRODUCT_OUT");
+    if((dir == 0) || (dir[0] == 0)) {
+        die("neither -p product specified nor ANDROID_PRODUCT_OUT set");
+    }
+
+    return android::base::StringPrintf("%s/%s", dir, img_name);
+}
+
+std::string find_item(const char* item, const char* product) {
     const char *fn;
-    if (!strcmp(item,"boot")) {
+
+    if(!strcmp(item,"boot")) {
         fn = "boot.img";
     } else if(!strcmp(item,"recovery")) {
         fn = "recovery.img";
@@ -131,19 +153,7 @@
         return "";
     }
 
-    if (product) {
-        std::string path = get_my_path();
-        path.erase(path.find_last_of('/'));
-        return android::base::StringPrintf("%s/../../../target/product/%s/%s",
-                                           path.c_str(), product, fn);
-    }
-
-    char* dir = getenv("ANDROID_PRODUCT_OUT");
-    if (dir == nullptr || dir[0] == '\0') {
-        die("neither -p product specified nor ANDROID_PRODUCT_OUT set");
-    }
-
-    return android::base::StringPrintf("%s/%s", dir, fn);
+    return find_item_given_name(fn, product);
 }
 
 static int64_t get_file_size(int fd) {
@@ -309,8 +319,13 @@
             "\n"
             "commands:\n"
             "  update <filename>                        Reflash device from update.zip.\n"
+            "                                           Sets the flashed slot as active.\n"
             "  flashall                                 Flash boot, system, vendor, and --\n"
-            "                                           if found -- recovery.\n"
+            "                                           if found -- recovery. If the device\n"
+            "                                           supports slots, the slot that has\n"
+            "                                           been flashed to is set as active.\n"
+            "                                           Secondary images may be flashed to\n"
+            "                                           an inactive slot.\n"
             "  flash <partition> [ <filename> ]         Write a file to a flash partition.\n"
             "  flashing lock                            Locks the device. Prevents flashing.\n"
             "  flashing unlock                          Unlocks the device. Allows flashing\n"
@@ -333,7 +348,7 @@
             "                                           override the fs type and/or size\n"
             "                                           the bootloader reports.\n"
             "  getvar <variable>                        Display a bootloader variable.\n"
-            "  set_active <suffix>                      Sets the active slot. If slots are\n"
+            "  set_active <slot>                        Sets the active slot. If slots are\n"
             "                                           not supported, this does nothing.\n"
             "  boot <kernel> [ <ramdisk> [ <second> ] ] Download and boot kernel.\n"
             "  flash:raw boot <kernel> [ <ramdisk> [ <second> ] ]\n"
@@ -370,19 +385,24 @@
             "                                           (default: 2048).\n"
             "  -S <size>[K|M|G]                         Automatically sparse files greater\n"
             "                                           than 'size'. 0 to disable.\n"
-            "  --slot <suffix>                          Specify slot suffix to be used if the\n"
-            "                                           device supports slots. This will be\n"
-            "                                           added to all partition names that use\n"
-            "                                           slots. 'all' can be given to refer\n"
-            "                                           to all slots. 'other' can be given to\n"
-            "                                           refer to a non-current slot. If this\n"
-            "                                           flag is not used, slotted partitions\n"
-            "                                           will default to the current active slot.\n"
-            "  -a, --set-active[=<suffix>]              Sets the active slot. If no suffix is\n"
+            "  --slot <slot>                            Specify slot name to be used if the\n"
+            "                                           device supports slots. All operations\n"
+            "                                           on partitions that support slots will\n"
+            "                                           be done on the slot specified.\n"
+            "                                           'all' can be given to refer to all slots.\n"
+            "                                           'other' can be given to refer to a\n"
+            "                                           non-current slot. If this flag is not\n"
+            "                                           used, slotted partitions will default\n"
+            "                                           to the current active slot.\n"
+            "  -a, --set-active[=<slot>]                Sets the active slot. If no slot is\n"
             "                                           provided, this will default to the value\n"
             "                                           given by --slot. If slots are not\n"
-            "                                           supported, this does nothing. This will\n"
-            "                                           run after all non-reboot commands.\n"
+            "                                           supported, this sets the current slot\n"
+            "                                           to be active. This will run after all\n"
+            "                                           non-reboot commands.\n"
+            "  --skip-secondary                         Will not flash secondary slots when\n"
+            "                                           performing a flashall or update. This\n"
+            "                                           will preserve data on other slots.\n"
 #if !defined(_WIN32)
             "  --wipe-and-use-fbe                       On devices which support it,\n"
             "                                           erase userdata and cache, and\n"
@@ -839,83 +859,138 @@
     }
 }
 
-static std::vector<std::string> get_suffixes(Transport* transport) {
+static std::string get_current_slot(Transport* transport)
+{
+    std::string current_slot;
+    if (fb_getvar(transport, "current-slot", &current_slot)) {
+        if (current_slot == "_a") return "a"; // Legacy support
+        if (current_slot == "_b") return "b"; // Legacy support
+        return current_slot;
+    }
+    return "";
+}
+
+// Legacy support
+static std::vector<std::string> get_suffixes_obsolete(Transport* transport) {
     std::vector<std::string> suffixes;
     std::string suffix_list;
     if (!fb_getvar(transport, "slot-suffixes", &suffix_list)) {
-        die("Could not get suffixes.\n");
+        return suffixes;
     }
-    return android::base::Split(suffix_list, ",");
+    suffixes = android::base::Split(suffix_list, ",");
+    // Unfortunately some devices will return an error message in the
+    // guise of a valid value. If we only see only one suffix, it's probably
+    // not real.
+    if (suffixes.size() == 1) {
+        suffixes.clear();
+    }
+    return suffixes;
 }
 
-static std::string verify_slot(Transport* transport, const char *slot, bool allow_all) {
-    if (strcmp(slot, "all") == 0) {
+// Legacy support
+static bool supports_AB_obsolete(Transport* transport) {
+  return !get_suffixes_obsolete(transport).empty();
+}
+
+static int get_slot_count(Transport* transport) {
+    std::string var;
+    int count;
+    if (!fb_getvar(transport, "slot-count", &var)) {
+        if (supports_AB_obsolete(transport)) return 2; // Legacy support
+    }
+    if (!android::base::ParseInt(var.c_str(), &count)) return 0;
+    return count;
+}
+
+static bool supports_AB(Transport* transport) {
+  return get_slot_count(transport) >= 2;
+}
+
+// Given a current slot, this returns what the 'other' slot is.
+static std::string get_other_slot(const std::string& current_slot, int count) {
+    if (count == 0) return "";
+
+    char next = (current_slot[0] - 'a' + 1)%count + 'a';
+    return std::string(1, next);
+}
+
+static std::string get_other_slot(Transport* transport, const std::string& current_slot) {
+    return get_other_slot(current_slot, get_slot_count(transport));
+}
+
+static std::string get_other_slot(Transport* transport, int count) {
+    return get_other_slot(get_current_slot(transport), count);
+}
+
+static std::string get_other_slot(Transport* transport) {
+    return get_other_slot(get_current_slot(transport), get_slot_count(transport));
+}
+
+static std::string verify_slot(Transport* transport, const std::string& slot_name, bool allow_all) {
+    std::string slot = slot_name;
+    if (slot == "_a") slot = "a"; // Legacy support
+    if (slot == "_b") slot = "b"; // Legacy support
+    if (slot == "all") {
         if (allow_all) {
             return "all";
         } else {
-            std::vector<std::string> suffixes = get_suffixes(transport);
-            if (!suffixes.empty()) {
-                return suffixes[0];
+            int count = get_slot_count(transport);
+            if (count > 0) {
+                return "a";
             } else {
                 die("No known slots.");
             }
         }
     }
 
-    std::vector<std::string> suffixes = get_suffixes(transport);
+    int count = get_slot_count(transport);
+    if (count == 0) die("Device does not support slots.\n");
 
-    if (strcmp(slot, "other") == 0) {
-        std::string current_slot;
-        if (!fb_getvar(transport, "current-slot", &current_slot)) {
-            die("Failed to identify current slot.");
+    if (slot == "other") {
+        std::string other = get_other_slot(transport, count);
+        if (other == "") {
+           die("No known slots.");
         }
-        if (!suffixes.empty()) {
-            for (size_t i = 0; i < suffixes.size(); i++) {
-                if (current_slot == suffixes[i])
-                    return suffixes[(i+1)%suffixes.size()];
-            }
-        } else {
-            die("No known slots.");
-        }
+        return other;
     }
 
-    for (const std::string &suffix : suffixes) {
-        if (suffix == slot)
-            return slot;
+    if (slot.size() == 1 && (slot[0]-'a' >= 0 && slot[0]-'a' < count)) return slot;
+
+    fprintf(stderr, "Slot %s does not exist. supported slots are:\n", slot.c_str());
+    for (int i=0; i<count; i++) {
+        fprintf(stderr, "%c\n", (char)(i + 'a'));
     }
-    fprintf(stderr, "Slot %s does not exist. supported slots are:\n", slot);
-    for (const std::string &suffix : suffixes) {
-        fprintf(stderr, "%s\n", suffix.c_str());
-    }
+
     exit(1);
 }
 
-static std::string verify_slot(Transport* transport, const char *slot) {
+static std::string verify_slot(Transport* transport, const std::string& slot) {
    return verify_slot(transport, slot, true);
 }
 
-static void do_for_partition(Transport* transport, const char *part, const char *slot,
+static void do_for_partition(Transport* transport, const std::string& part, const std::string& slot,
                              std::function<void(const std::string&)> func, bool force_slot) {
     std::string has_slot;
     std::string current_slot;
 
-    if (!fb_getvar(transport, std::string("has-slot:")+part, &has_slot)) {
+    if (!fb_getvar(transport, "has-slot:" + part, &has_slot)) {
         /* If has-slot is not supported, the answer is no. */
         has_slot = "no";
     }
     if (has_slot == "yes") {
-        if (!slot || slot[0] == 0) {
-            if (!fb_getvar(transport, "current-slot", &current_slot)) {
+        if (slot == "") {
+            current_slot = get_current_slot(transport);
+            if (current_slot == "") {
                 die("Failed to identify current slot.\n");
             }
-            func(std::string(part) + current_slot);
+            func(part + "_" + current_slot);
         } else {
-            func(std::string(part) + slot);
+            func(part + '_' + slot);
         }
     } else {
-        if (force_slot && slot && slot[0]) {
+        if (force_slot && slot != "") {
              fprintf(stderr, "Warning: %s does not support slots, and slot %s was requested.\n",
-                     part, slot);
+                     part.c_str(), slot.c_str());
         }
         func(part);
     }
@@ -926,18 +1001,17 @@
  * partition names. If force_slot is true, it will fail if a slot is specified, and the given
  * partition does not support slots.
  */
-static void do_for_partitions(Transport* transport, const char *part, const char *slot,
+static void do_for_partitions(Transport* transport, const std::string& part, const std::string& slot,
                               std::function<void(const std::string&)> func, bool force_slot) {
     std::string has_slot;
 
-    if (slot && strcmp(slot, "all") == 0) {
-        if (!fb_getvar(transport, std::string("has-slot:") + part, &has_slot)) {
-            die("Could not check if partition %s has slot.", part);
+    if (slot == "all") {
+        if (!fb_getvar(transport, "has-slot:" + part, &has_slot)) {
+            die("Could not check if partition %s has slot.", part.c_str());
         }
         if (has_slot == "yes") {
-            std::vector<std::string> suffixes = get_suffixes(transport);
-            for (std::string &suffix : suffixes) {
-                do_for_partition(transport, part, suffix.c_str(), func, force_slot);
+            for (int i=0; i < get_slot_count(transport); i++) {
+                do_for_partition(transport, part, std::string(1, (char)(i + 'a')), func, force_slot);
             }
         } else {
             do_for_partition(transport, part, "", func, force_slot);
@@ -964,7 +1038,28 @@
     fb_queue_command("signature", "installing signature");
 }
 
-static void do_update(Transport* transport, const char* filename, const char* slot_override, bool erase_first) {
+// Sets slot_override as the active slot. If slot_override is blank,
+// set current slot as active instead. This clears slot-unbootable.
+static void set_active(Transport* transport, const std::string& slot_override) {
+    std::string separator = "";
+    if (!supports_AB(transport)) {
+        if (supports_AB_obsolete(transport)) {
+            separator = "_"; // Legacy support
+        } else {
+            return;
+        }
+    }
+    if (slot_override != "") {
+        fb_set_active((separator + slot_override).c_str());
+    } else {
+        std::string current_slot = get_current_slot(transport);
+        if (current_slot != "") {
+            fb_set_active((separator + current_slot).c_str());
+        }
+    }
+}
+
+static void do_update(Transport* transport, const char* filename, const std::string& slot_override, bool erase_first, bool skip_secondary) {
     queue_info_dump();
 
     fb_queue_query_save("product", cur_product, sizeof(cur_product));
@@ -985,7 +1080,30 @@
 
     setup_requirements(reinterpret_cast<char*>(data), sz);
 
+    std::string secondary;
+    if (!skip_secondary) {
+        if (slot_override != "") {
+            secondary = get_other_slot(transport, slot_override);
+        } else {
+            secondary = get_other_slot(transport);
+        }
+        if (secondary == "") {
+            if (supports_AB(transport)) {
+                fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n");
+            }
+            skip_secondary = true;
+        }
+    }
     for (size_t i = 0; i < arraysize(images); ++i) {
+        const char* slot = slot_override.c_str();
+        if (images[i].is_secondary) {
+            if (!skip_secondary) {
+                slot = secondary.c_str();
+            } else {
+                continue;
+            }
+        }
+
         int fd = unzip_to_file(zip, images[i].img_name);
         if (fd == -1) {
             if (images[i].is_optional) {
@@ -1010,10 +1128,15 @@
              * program exits.
              */
         };
-        do_for_partitions(transport, images[i].part_name, slot_override, update, false);
+        do_for_partitions(transport, images[i].part_name, slot, update, false);
     }
 
     CloseArchive(zip);
+    if (slot_override == "all") {
+        set_active(transport, "a");
+    } else {
+        set_active(transport, slot_override);
+    }
 }
 
 static void do_send_signature(const char* filename) {
@@ -1033,26 +1156,49 @@
     fb_queue_command("signature", "installing signature");
 }
 
-static void do_flashall(Transport* transport, const char* slot_override, int erase_first) {
+static void do_flashall(Transport* transport, const std::string& slot_override, int erase_first, bool skip_secondary) {
+    std::string fname;
     queue_info_dump();
 
     fb_queue_query_save("product", cur_product, sizeof(cur_product));
 
-    std::string fname = find_item("info", product);
+    fname = find_item("info", product);
     if (fname.empty()) die("cannot find android-info.txt");
 
     int64_t sz;
-    void* data = load_file(fname, &sz);
+    void* data = load_file(fname.c_str(), &sz);
     if (data == nullptr) die("could not load android-info.txt: %s", strerror(errno));
 
     setup_requirements(reinterpret_cast<char*>(data), sz);
 
+    std::string secondary;
+    if (!skip_secondary) {
+        if (slot_override != "") {
+            secondary = get_other_slot(transport, slot_override);
+        } else {
+            secondary = get_other_slot(transport);
+        }
+        if (secondary == "") {
+            if (supports_AB(transport)) {
+                fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n");
+            }
+            skip_secondary = true;
+        }
+    }
+
     for (size_t i = 0; i < arraysize(images); i++) {
-        fname = find_item(images[i].part_name, product);
+        const char* slot = NULL;
+        if (images[i].is_secondary) {
+            if (!skip_secondary) slot = secondary.c_str();
+        } else {
+            slot = slot_override.c_str();
+        }
+        if (!slot) continue;
+        fname = find_item_given_name(images[i].img_name, product);
         fastboot_buffer buf;
         if (!load_buf(transport, fname.c_str(), &buf)) {
             if (images[i].is_optional) continue;
-            die("could not load '%s': %s", images[i].img_name, strerror(errno));
+            die("could not load %s\n", images[i].img_name);
         }
 
         auto flashall = [&](const std::string &partition) {
@@ -1062,7 +1208,13 @@
             }
             flash_buf(partition.c_str(), &buf);
         };
-        do_for_partitions(transport, images[i].part_name, slot_override, flashall, false);
+        do_for_partitions(transport, images[i].part_name, slot, flashall, false);
+    }
+
+    if (slot_override == "all") {
+        set_active(transport, "a");
+    } else {
+        set_active(transport, slot_override);
     }
 }
 
@@ -1242,6 +1394,7 @@
     bool wants_reboot = false;
     bool wants_reboot_bootloader = false;
     bool wants_set_active = false;
+    bool skip_secondary = false;
     bool erase_first = true;
     bool set_fbe_marker = false;
     void *data;
@@ -1266,6 +1419,7 @@
         {"slot", required_argument, 0, 0},
         {"set_active", optional_argument, 0, 'a'},
         {"set-active", optional_argument, 0, 'a'},
+        {"skip-secondary", no_argument, 0, 0},
 #if !defined(_WIN32)
         {"wipe-and-use-fbe", no_argument, 0, 0},
 #endif
@@ -1350,6 +1504,8 @@
                 return 0;
             } else if (strcmp("slot", longopts[longindex].name) == 0) {
                 slot_override = std::string(optarg);
+            } else if (strcmp("skip-secondary", longopts[longindex].name) == 0 ) {
+                skip_secondary = true;
 #if !defined(_WIN32)
             } else if (strcmp("wipe-and-use-fbe", longopts[longindex].name) == 0) {
                 wants_wipe = true;
@@ -1390,17 +1546,23 @@
         return 1;
     }
 
-    if (slot_override != "")
-        slot_override = verify_slot(transport, slot_override.c_str());
-    if (next_active != "")
-        next_active = verify_slot(transport, next_active.c_str(), false);
+    if (!supports_AB(transport) && supports_AB_obsolete(transport)) {
+        fprintf(stderr, "Warning: Device A/B support is outdated. Bootloader update required.\n");
+    }
+    if (slot_override != "") slot_override = verify_slot(transport, slot_override);
+    if (next_active != "") next_active = verify_slot(transport, next_active, false);
 
     if (wants_set_active) {
         if (next_active == "") {
             if (slot_override == "") {
-                wants_set_active = false;
+                std::string current_slot;
+                if (fb_getvar(transport, "current-slot", &current_slot)) {
+                    next_active = verify_slot(transport, current_slot, false);
+                } else {
+                    wants_set_active = false;
+                }
             } else {
-                next_active = verify_slot(transport, slot_override.c_str(), false);
+                next_active = verify_slot(transport, slot_override, false);
             }
         }
     }
@@ -1423,7 +1585,7 @@
 
                 fb_queue_erase(partition.c_str());
             };
-            do_for_partitions(transport, argv[1], slot_override.c_str(), erase, true);
+            do_for_partitions(transport, argv[1], slot_override, erase, true);
             skip(2);
         } else if(!strncmp(*argv, "format", strlen("format"))) {
             char *overrides;
@@ -1459,7 +1621,7 @@
                 fb_perform_format(transport, partition.c_str(), 0,
                     type_override, size_override, "");
             };
-            do_for_partitions(transport, argv[1], slot_override.c_str(), format, true);
+            do_for_partitions(transport, argv[1], slot_override, format, true);
             skip(2);
         } else if(!strcmp(*argv, "signature")) {
             require(2);
@@ -1526,7 +1688,7 @@
                 }
                 do_flash(transport, partition.c_str(), fname.c_str());
             };
-            do_for_partitions(transport, pname, slot_override.c_str(), flash, true);
+            do_for_partitions(transport, pname, slot_override, flash, true);
         } else if(!strcmp(*argv, "flash:raw")) {
             char *kname = argv[2];
             char *rname = 0;
@@ -1546,23 +1708,32 @@
             auto flashraw = [&](const std::string &partition) {
                 fb_queue_flash(partition.c_str(), data, sz);
             };
-            do_for_partitions(transport, argv[1], slot_override.c_str(), flashraw, true);
+            do_for_partitions(transport, argv[1], slot_override, flashraw, true);
         } else if(!strcmp(*argv, "flashall")) {
             skip(1);
-            do_flashall(transport, slot_override.c_str(), erase_first);
+            if (slot_override == "all") {
+                fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed.\n");
+                do_flashall(transport, slot_override, erase_first, true);
+            } else {
+                do_flashall(transport, slot_override, erase_first, skip_secondary);
+            }
             wants_reboot = true;
         } else if(!strcmp(*argv, "update")) {
+            bool slot_all = (slot_override == "all");
+            if (slot_all) {
+                fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed.\n");
+            }
             if (argc > 1) {
-                do_update(transport, argv[1], slot_override.c_str(), erase_first);
+                do_update(transport, argv[1], slot_override, erase_first, skip_secondary || slot_all);
                 skip(2);
             } else {
-                do_update(transport, "update.zip", slot_override.c_str(), erase_first);
+                do_update(transport, "update.zip", slot_override, erase_first, skip_secondary || slot_all);
                 skip(1);
             }
             wants_reboot = 1;
         } else if(!strcmp(*argv, "set_active")) {
             require(2);
-            std::string slot = verify_slot(transport, argv[1], false);
+            std::string slot = verify_slot(transport, std::string(argv[1]), false);
             fb_set_active(slot.c_str());
             skip(2);
         } else if(!strcmp(*argv, "oem")) {
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index 6d44e06..45adb34 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -32,11 +32,12 @@
     int partnum;
     int swap_prio;
     unsigned int zram_size;
+    unsigned int file_encryption_mode;
 };
 
 struct flag_list {
     const char *name;
-    unsigned flag;
+    unsigned int flag;
 };
 
 static struct flag_list mount_flags[] = {
@@ -63,7 +64,7 @@
     { "check",       MF_CHECK },
     { "encryptable=",MF_CRYPT },
     { "forceencrypt=",MF_FORCECRYPT },
-    { "fileencryption",MF_FILEENCRYPTION },
+    { "fileencryption=",MF_FILEENCRYPTION },
     { "forcefdeorfbe=",MF_FORCEFDEORFBE },
     { "nonremovable",MF_NONREMOVABLE },
     { "voldmanaged=",MF_VOLDMANAGED},
@@ -81,6 +82,15 @@
     { 0,             0 },
 };
 
+#define EM_SOFTWARE 1
+#define EM_ICE      2
+
+static struct flag_list encryption_modes[] = {
+    {"software", EM_SOFTWARE},
+    {"ice", EM_ICE},
+    {0, 0}
+};
+
 static uint64_t calculate_zram_size(unsigned int percentage)
 {
     uint64_t total;
@@ -147,6 +157,21 @@
                      * location of the keys.  Get it and return it.
                      */
                     flag_vals->key_loc = strdup(strchr(p, '=') + 1);
+                    flag_vals->file_encryption_mode = EM_SOFTWARE;
+                } else if ((fl[i].flag == MF_FILEENCRYPTION) && flag_vals) {
+                    /* The fileencryption flag is followed by an = and the
+                     * type of the encryption.  Get it and return it.
+                     */
+                    const struct flag_list *j;
+                    const char *mode = strchr(p, '=') + 1;
+                    for (j = encryption_modes; j->name; ++j) {
+                        if (!strcmp(mode, j->name)) {
+                            flag_vals->file_encryption_mode = j->flag;
+                        }
+                    }
+                    if (flag_vals->file_encryption_mode == 0) {
+                        ERROR("Unknown file encryption mode: %s\n", mode);
+                    }
                 } else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
                     /* The length flag is followed by an = and the
                      * size of the partition.  Get it and return it.
@@ -337,6 +362,7 @@
         fstab->recs[cnt].partnum = flag_vals.partnum;
         fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
         fstab->recs[cnt].zram_size = flag_vals.zram_size;
+        fstab->recs[cnt].file_encryption_mode = flag_vals.file_encryption_mode;
         cnt++;
     }
     /* If an A/B partition, modify block device to be the real block device */
@@ -479,6 +505,17 @@
     return fstab->fs_mgr_flags & MF_FILEENCRYPTION;
 }
 
+const char* fs_mgr_get_file_encryption_mode(const struct fstab_rec *fstab)
+{
+    const struct flag_list *j;
+    for (j = encryption_modes; j->name; ++j) {
+        if (fstab->file_encryption_mode == j->flag) {
+            return j->name;
+        }
+    }
+    return NULL;
+}
+
 int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab)
 {
     return fstab->fs_mgr_flags & MF_FORCEFDEORFBE;
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 25b023e..759c5e8 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -181,7 +181,7 @@
     return -1;
 }
 
-static void verity_ioctl_init(struct dm_ioctl *io, char *name, unsigned flags)
+static void verity_ioctl_init(struct dm_ioctl *io, const char *name, unsigned flags)
 {
     memset(io, 0, DM_BUF_SIZE);
     io->data_size = DM_BUF_SIZE;
@@ -784,8 +784,9 @@
 int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback)
 {
     alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
+    bool system_root = false;
     char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
-    char *mount_point;
+    const char *mount_point;
     char propbuf[PROPERTY_VALUE_MAX];
     char *status;
     int fd = -1;
@@ -813,6 +814,9 @@
     property_get("ro.hardware", propbuf, "");
     snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
 
+    property_get("ro.build.system_root_image", propbuf, "");
+    system_root = !strcmp(propbuf, "true");
+
     fstab = fs_mgr_read_fstab(fstab_filename);
 
     if (!fstab) {
@@ -825,7 +829,12 @@
             continue;
         }
 
-        mount_point = basename(fstab->recs[i].mount_point);
+        if (system_root && !strcmp(fstab->recs[i].mount_point, "/")) {
+            mount_point = "system";
+        } else {
+            mount_point = basename(fstab->recs[i].mount_point);
+        }
+
         verity_ioctl_init(io, mount_point, 0);
 
         if (ioctl(fd, DM_TABLE_STATUS, io)) {
@@ -836,7 +845,9 @@
 
         status = &buffer[io->data_start + sizeof(struct dm_target_spec)];
 
-        callback(&fstab->recs[i], mount_point, mode, *status);
+        if (*status == 'C' || *status == 'V') {
+            callback(&fstab->recs[i], mount_point, mode, *status);
+        }
     }
 
     rc = 0;
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 3847011..6f2548d 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -66,6 +66,7 @@
     int partnum;
     int swap_prio;
     unsigned int zram_size;
+    unsigned int file_encryption_mode;
 };
 
 // Callback function for verity status
@@ -86,6 +87,7 @@
 
 #define FS_MGR_DOMNT_FAILED (-1)
 #define FS_MGR_DOMNT_BUSY (-2)
+
 int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
                     char *tmp_mount_point);
 int fs_mgr_do_tmpfs_mount(char *n_name);
@@ -103,6 +105,7 @@
 int fs_mgr_is_verified(const struct fstab_rec *fstab);
 int fs_mgr_is_encryptable(const struct fstab_rec *fstab);
 int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab);
+const char* fs_mgr_get_file_encryption_mode(const struct fstab_rec *fstab);
 int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab);
 int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
 int fs_mgr_is_notrim(struct fstab_rec *fstab);
diff --git a/include/system/graphics.h b/include/system/graphics.h
index a9e451f..529a562 100644
--- a/include/system/graphics.h
+++ b/include/system/graphics.h
@@ -477,6 +477,102 @@
     uint32_t reserved[8];
 };
 
+/*
+ * Structures for describing flexible YUVA/RGBA formats for consumption by
+ * applications. Such flexible formats contain a plane for each component (e.g.
+ * red, green, blue), where each plane is laid out in a grid-like pattern
+ * occupying unique byte addresses and with consistent byte offsets between
+ * neighboring pixels.
+ *
+ * The android_flex_layout structure is used with any pixel format that can be
+ * represented by it, such as:
+ *  - HAL_PIXEL_FORMAT_YCbCr_*_888
+ *  - HAL_PIXEL_FORMAT_FLEX_RGB*_888
+ *  - HAL_PIXEL_FORMAT_RGB[AX]_888[8],BGRA_8888,RGB_888
+ *  - HAL_PIXEL_FORMAT_YV12,Y8,Y16,YCbCr_422_SP/I,YCrCb_420_SP
+ *  - even implementation defined formats that can be represented by
+ *    the structures
+ *
+ * Vertical increment (aka. row increment or stride) describes the distance in
+ * bytes from the first pixel of one row to the first pixel of the next row
+ * (below) for the component plane. This can be negative.
+ *
+ * Horizontal increment (aka. column or pixel increment) describes the distance
+ * in bytes from one pixel to the next pixel (to the right) on the same row for
+ * the component plane. This can be negative.
+ *
+ * Each plane can be subsampled either vertically or horizontally by
+ * a power-of-two factor.
+ *
+ * The bit-depth of each component can be arbitrary, as long as the pixels are
+ * laid out on whole bytes, in native byte-order, using the most significant
+ * bits of each unit.
+ */
+
+typedef enum android_flex_component {
+    /* luma */
+    FLEX_COMPONENT_Y = 1 << 0,
+    /* chroma blue */
+    FLEX_COMPONENT_Cb = 1 << 1,
+    /* chroma red */
+    FLEX_COMPONENT_Cr = 1 << 2,
+
+    /* red */
+    FLEX_COMPONENT_R = 1 << 10,
+    /* green */
+    FLEX_COMPONENT_G = 1 << 11,
+    /* blue */
+    FLEX_COMPONENT_B = 1 << 12,
+
+    /* alpha */
+    FLEX_COMPONENT_A = 1 << 30,
+} android_flex_component_t;
+
+typedef struct android_flex_plane {
+    /* pointer to the first byte of the top-left pixel of the plane. */
+    uint8_t *top_left;
+
+    android_flex_component_t component;
+
+    /* bits allocated for the component in each pixel. Must be a positive
+       multiple of 8. */
+    int32_t bits_per_component;
+    /* number of the most significant bits used in the format for this
+       component. Must be between 1 and bits_per_component, inclusive. */
+    int32_t bits_used;
+
+    /* horizontal increment */
+    int32_t h_increment;
+    /* vertical increment */
+    int32_t v_increment;
+    /* horizontal subsampling. Must be a positive power of 2. */
+    int32_t h_subsampling;
+    /* vertical subsampling. Must be a positive power of 2. */
+    int32_t v_subsampling;
+} android_flex_plane_t;
+
+typedef enum android_flex_format {
+    /* not a flexible format */
+    FLEX_FORMAT_INVALID = 0x0,
+    FLEX_FORMAT_Y = FLEX_COMPONENT_Y,
+    FLEX_FORMAT_YCbCr = FLEX_COMPONENT_Y | FLEX_COMPONENT_Cb | FLEX_COMPONENT_Cr,
+    FLEX_FORMAT_YCbCrA = FLEX_FORMAT_YCbCr | FLEX_COMPONENT_A,
+    FLEX_FORMAT_RGB = FLEX_COMPONENT_R | FLEX_COMPONENT_G | FLEX_COMPONENT_B,
+    FLEX_FORMAT_RGBA = FLEX_FORMAT_RGB | FLEX_COMPONENT_A,
+} android_flex_format_t;
+
+typedef struct android_flex_layout {
+    /* the kind of flexible format */
+    android_flex_format_t format;
+
+    /* number of planes; 0 for FLEX_FORMAT_INVALID */
+    uint32_t num_planes;
+    /* a plane for each component; ordered in increasing component value order.
+       E.g. FLEX_FORMAT_RGBA maps 0 -> R, 1 -> G, etc.
+       Can be NULL for FLEX_FORMAT_INVALID */
+    android_flex_plane_t *planes;
+} android_flex_layout_t;
+
 /**
  * Structure used to define depth point clouds for format HAL_PIXEL_FORMAT_BLOB
  * with dataSpace value of HAL_DATASPACE_DEPTH.
@@ -1039,6 +1135,236 @@
 } android_dataspace_t;
 
 /*
+ * Color modes that may be supported by a display.
+ *
+ * Definitions:
+ * Rendering intent generally defines the goal in mapping a source (input)
+ * color to a destination device color for a given color mode.
+ *
+ *  It is important to keep in mind three cases where mapping may be applied:
+ *  1. The source gamut is much smaller than the destination (display) gamut
+ *  2. The source gamut is much larger than the destination gamut (this will
+ *  ordinarily be handled using colorimetric rendering, below)
+ *  3. The source and destination gamuts are roughly equal, although not
+ *  completely overlapping
+ *  Also, a common requirement for mappings is that skin tones should be
+ *  preserved, or at least remain natural in appearance.
+ *
+ *  Colorimetric Rendering Intent (All cases):
+ *  Colorimetric indicates that colors should be preserved. In the case
+ *  that the source gamut lies wholly within the destination gamut or is
+ *  about the same (#1, #3), this will simply mean that no manipulations
+ *  (no saturation boost, for example) are applied. In the case where some
+ *  source colors lie outside the destination gamut (#2, #3), those will
+ *  need to be mapped to colors that are within the destination gamut,
+ *  while the already in-gamut colors remain unchanged.
+ *
+ *  Non-colorimetric transforms can take many forms. There are no hard
+ *  rules and it's left to the implementation to define.
+ *  Two common intents are described below.
+ *
+ *  Stretched-Gamut Enhancement Intent (Source < Destination):
+ *  When the destination gamut is much larger than the source gamut (#1), the
+ *  source primaries may be redefined to reflect the full extent of the
+ *  destination space, or to reflect an intermediate gamut.
+ *  Skin-tone preservation would likely be applied. An example might be sRGB
+ *  input displayed on a DCI-P3 capable device, with skin-tone preservation.
+ *
+ *  Within-Gamut Enhancement Intent (Source >= Destination):
+ *  When the device (destination) gamut is not larger than the source gamut
+ *  (#2 or #3), but the appearance of a larger gamut is desired, techniques
+ *  such as saturation boost may be applied to the source colors. Skin-tone
+ *  preservation may be applied. There is no unique method for within-gamut
+ *  enhancement; it would be defined within a flexible color mode.
+ *
+ */
+typedef enum android_color_mode {
+
+  /*
+   * HAL_COLOR_MODE_DEFAULT is the "native" gamut of the display.
+   * White Point: Vendor/OEM defined
+   * Panel Gamma: Vendor/OEM defined (typically 2.2)
+   * Rendering Intent: Vendor/OEM defined (typically 'enhanced')
+   */
+  HAL_COLOR_MODE_NATIVE = 0,
+
+  /*
+   * HAL_COLOR_MODE_STANDARD_BT601_625 corresponds with display
+   * settings that implement the ITU-R Recommendation BT.601
+   * or Rec 601. Using 625 line version
+   * Rendering Intent: Colorimetric
+   * Primaries:
+   *                  x       y
+   *  green           0.290   0.600
+   *  blue            0.150   0.060
+   *  red             0.640   0.330
+   *  white (D65)     0.3127  0.3290
+   *
+   *  KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
+   *  for RGB conversion from the one purely determined by the primaries
+   *  to minimize the color shift into RGB space that uses BT.709
+   *  primaries.
+   *
+   * Gamma Correction (GC):
+   *
+   *  if Vlinear < 0.018
+   *    Vnonlinear = 4.500 * Vlinear
+   *  else
+   *    Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
+   */
+  HAL_COLOR_MODE_STANDARD_BT601_625 = 1,
+
+  /*
+   * Primaries:
+   *                  x       y
+   *  green           0.290   0.600
+   *  blue            0.150   0.060
+   *  red             0.640   0.330
+   *  white (D65)     0.3127  0.3290
+   *
+   *  Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation
+   *  for RGB conversion.
+   *
+   * Gamma Correction (GC):
+   *
+   *  if Vlinear < 0.018
+   *    Vnonlinear = 4.500 * Vlinear
+   *  else
+   *    Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
+   */
+  HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED = 2,
+
+  /*
+   * Primaries:
+   *                  x       y
+   *  green           0.310   0.595
+   *  blue            0.155   0.070
+   *  red             0.630   0.340
+   *  white (D65)     0.3127  0.3290
+   *
+   *  KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
+   *  for RGB conversion from the one purely determined by the primaries
+   *  to minimize the color shift into RGB space that uses BT.709
+   *  primaries.
+   *
+   * Gamma Correction (GC):
+   *
+   *  if Vlinear < 0.018
+   *    Vnonlinear = 4.500 * Vlinear
+   *  else
+   *    Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
+   */
+  HAL_COLOR_MODE_STANDARD_BT601_525 = 3,
+
+  /*
+   * Primaries:
+   *                  x       y
+   *  green           0.310   0.595
+   *  blue            0.155   0.070
+   *  red             0.630   0.340
+   *  white (D65)     0.3127  0.3290
+   *
+   *  Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation
+   *  for RGB conversion (as in SMPTE 240M).
+   *
+   * Gamma Correction (GC):
+   *
+   *  if Vlinear < 0.018
+   *    Vnonlinear = 4.500 * Vlinear
+   *  else
+   *    Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
+   */
+  HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED = 4,
+
+  /*
+   * HAL_COLOR_MODE_REC709 corresponds with display settings that implement
+   * the ITU-R Recommendation BT.709 / Rec. 709 for high-definition television.
+   * Rendering Intent: Colorimetric
+   * Primaries:
+   *                  x       y
+   *  green           0.300   0.600
+   *  blue            0.150   0.060
+   *  red             0.640   0.330
+   *  white (D65)     0.3127  0.3290
+   *
+   * HDTV REC709 Inverse Gamma Correction (IGC): V represents normalized
+   * (with [0 to 1] range) value of R, G, or B.
+   *
+   *  if Vnonlinear < 0.081
+   *    Vlinear = Vnonlinear / 4.5
+   *  else
+   *    Vlinear = ((Vnonlinear + 0.099) / 1.099) ^ (1/0.45)
+   *
+   * HDTV REC709 Gamma Correction (GC):
+   *
+   *  if Vlinear < 0.018
+   *    Vnonlinear = 4.5 * Vlinear
+   *  else
+   *    Vnonlinear = 1.099 * (Vlinear) ^ 0.45 – 0.099
+   */
+  HAL_COLOR_MODE_STANDARD_BT709 = 5,
+
+  /*
+   * HAL_COLOR_MODE_DCI_P3 corresponds with display settings that implement
+   * SMPTE EG 432-1 and SMPTE RP 431-2
+   * Rendering Intent: Colorimetric
+   * Primaries:
+   *                  x       y
+   *  green           0.265   0.690
+   *  blue            0.150   0.060
+   *  red             0.680   0.320
+   *  white (D65)     0.3127  0.3290
+   *
+   * Gamma: 2.2
+   */
+  HAL_COLOR_MODE_DCI_P3 = 6,
+
+  /*
+   * HAL_COLOR_MODE_SRGB corresponds with display settings that implement
+   * the sRGB color space. Uses the same primaries as ITU-R Recommendation
+   * BT.709
+   * Rendering Intent: Colorimetric
+   * Primaries:
+   *                  x       y
+   *  green           0.300   0.600
+   *  blue            0.150   0.060
+   *  red             0.640   0.330
+   *  white (D65)     0.3127  0.3290
+   *
+   * PC/Internet (sRGB) Inverse Gamma Correction (IGC):
+   *
+   *  if Vnonlinear ≤ 0.03928
+   *    Vlinear = Vnonlinear / 12.92
+   *  else
+   *    Vlinear = ((Vnonlinear + 0.055)/1.055) ^ 2.4
+   *
+   * PC/Internet (sRGB) Gamma Correction (GC):
+   *
+   *  if Vlinear ≤ 0.0031308
+   *    Vnonlinear = 12.92 * Vlinear
+   *  else
+   *    Vnonlinear = 1.055 * (Vlinear)^(1/2.4) – 0.055
+   */
+  HAL_COLOR_MODE_SRGB = 7,
+
+  /*
+   * HAL_COLOR_MODE_ADOBE_RGB corresponds with the RGB color space developed
+   * by Adobe Systems, Inc. in 1998.
+   * Rendering Intent: Colorimetric
+   * Primaries:
+   *                  x       y
+   *  green           0.210   0.710
+   *  blue            0.150   0.060
+   *  red             0.640   0.330
+   *  white (D65)     0.3127  0.3290
+   *
+   * Gamma: 2.2
+   */
+  HAL_COLOR_MODE_ADOBE_RGB = 8
+
+} android_color_mode_t;
+
+/*
  * Color transforms that may be applied by hardware composer to the whole
  * display.
  */
diff --git a/include/system/window.h b/include/system/window.h
index b8f33ff..33b7c3d 100644
--- a/include/system/window.h
+++ b/include/system/window.h
@@ -278,6 +278,16 @@
      * age will be 0.
      */
     NATIVE_WINDOW_BUFFER_AGE = 13,
+
+    /*
+     * Returns the duration of the last dequeueBuffer call in microseconds
+     */
+    NATIVE_WINDOW_LAST_DEQUEUE_DURATION = 14,
+
+    /*
+     * Returns the duration of the last queueBuffer call in microseconds
+     */
+    NATIVE_WINDOW_LAST_QUEUE_DURATION = 15,
 };
 
 /* Valid operations for the (*perform)() hook.
@@ -314,6 +324,7 @@
     NATIVE_WINDOW_SET_SURFACE_DAMAGE        = 20,   /* private */
     NATIVE_WINDOW_SET_SHARED_BUFFER_MODE    = 21,
     NATIVE_WINDOW_SET_AUTO_REFRESH          = 22,
+    NATIVE_WINDOW_GET_FRAME_TIMESTAMPS      = 23,
 };
 
 /* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */
@@ -976,6 +987,18 @@
     return window->perform(window, NATIVE_WINDOW_SET_AUTO_REFRESH, autoRefresh);
 }
 
+static inline int native_window_get_frame_timestamps(
+        struct ANativeWindow* window, uint32_t framesAgo,
+        int64_t* outPostedTime, int64_t* outAcquireTime,
+        int64_t* outRefreshStartTime, int64_t* outGlCompositionDoneTime,
+        int64_t* outDisplayRetireTime, int64_t* outReleaseTime)
+{
+    return window->perform(window, NATIVE_WINDOW_GET_FRAME_TIMESTAMPS,
+            framesAgo, outPostedTime, outAcquireTime, outRefreshStartTime,
+            outGlCompositionDoneTime, outDisplayRetireTime, outReleaseTime);
+}
+
+
 __END_DECLS
 
 #endif /* SYSTEM_CORE_INCLUDE_ANDROID_WINDOW_H */
diff --git a/include/utils/SortedVector.h b/include/utils/SortedVector.h
index 2d3e82a..85bd263 100644
--- a/include/utils/SortedVector.h
+++ b/include/utils/SortedVector.h
@@ -38,18 +38,18 @@
 
 public:
             typedef TYPE    value_type;
-    
-    /*! 
+
+    /*!
      * Constructors and destructors
      */
-    
+
                             SortedVector();
                             SortedVector(const SortedVector<TYPE>& rhs);
     virtual                 ~SortedVector();
 
     /*! copy operator */
-    const SortedVector<TYPE>&   operator = (const SortedVector<TYPE>& rhs) const;    
-    SortedVector<TYPE>&         operator = (const SortedVector<TYPE>& rhs);    
+    const SortedVector<TYPE>&   operator = (const SortedVector<TYPE>& rhs) const;
+    SortedVector<TYPE>&         operator = (const SortedVector<TYPE>& rhs);
 
     /*
      * empty the vector
@@ -57,7 +57,7 @@
 
     inline  void            clear()             { VectorImpl::clear(); }
 
-    /*! 
+    /*!
      * vector stats
      */
 
@@ -70,11 +70,11 @@
     //! sets the capacity. capacity can never be reduced less than size()
     inline  ssize_t         setCapacity(size_t size)    { return VectorImpl::setCapacity(size); }
 
-    /*! 
+    /*!
      * C-style array access
      */
-     
-    //! read-only C-style access 
+
+    //! read-only C-style access
     inline  const TYPE*     array() const;
 
     //! read-write C-style access. BE VERY CAREFUL when modifying the array
@@ -83,12 +83,12 @@
 
             //! finds the index of an item
             ssize_t         indexOf(const TYPE& item) const;
-            
+
             //! finds where this item should be inserted
             size_t          orderOf(const TYPE& item) const;
-            
-    
-    /*! 
+
+
+    /*!
      * accessors
      */
 
@@ -105,7 +105,7 @@
 
             //! add an item in the right place (and replace the one that is there)
             ssize_t         add(const TYPE& item);
-            
+
             //! editItemAt() MUST NOT change the order of this item
             TYPE&           editItemAt(size_t index) {
                 return *( static_cast<TYPE *>(VectorImpl::editItemLocation(index)) );
@@ -114,7 +114,7 @@
             //! merges a vector into this one
             ssize_t         merge(const Vector<TYPE>& vector);
             ssize_t         merge(const SortedVector<TYPE>& vector);
-            
+
             //! removes an item
             ssize_t         remove(const TYPE&);
 
@@ -122,7 +122,24 @@
     inline  ssize_t         removeItemsAt(size_t index, size_t count = 1);
     //! remove one item
     inline  ssize_t         removeAt(size_t index)  { return removeItemsAt(index); }
-            
+
+    /*
+     * these inlines add some level of compatibility with STL.
+     */
+    typedef TYPE* iterator;
+    typedef TYPE const* const_iterator;
+
+    inline iterator begin() { return editArray(); }
+    inline iterator end()   { return editArray() + size(); }
+    inline const_iterator begin() const { return array(); }
+    inline const_iterator end() const   { return array() + size(); }
+    inline void reserve(size_t n) { setCapacity(n); }
+    inline bool empty() const{ return isEmpty(); }
+    inline iterator erase(iterator pos) {
+        ssize_t index = removeItemsAt(pos-array());
+        return begin() + index;
+    }
+
 protected:
     virtual void    do_construct(void* storage, size_t num) const;
     virtual void    do_destroy(void* storage, size_t num) const;
@@ -164,13 +181,13 @@
 template<class TYPE> inline
 SortedVector<TYPE>& SortedVector<TYPE>::operator = (const SortedVector<TYPE>& rhs) {
     SortedVectorImpl::operator = (rhs);
-    return *this; 
+    return *this;
 }
 
 template<class TYPE> inline
 const SortedVector<TYPE>& SortedVector<TYPE>::operator = (const SortedVector<TYPE>& rhs) const {
     SortedVectorImpl::operator = (rhs);
-    return *this; 
+    return *this;
 }
 
 template<class TYPE> inline
diff --git a/include/utils/Unicode.h b/include/utils/Unicode.h
index a006082..cddbab4 100644
--- a/include/utils/Unicode.h
+++ b/include/utils/Unicode.h
@@ -88,7 +88,7 @@
  * "dst" becomes \xE3\x81\x82\xE3\x81\x84
  * (note that "dst" is NOT null-terminated, like strncpy)
  */
-void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst);
+void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst, size_t dst_len);
 
 /**
  * Returns the unicode value at "index".
@@ -110,7 +110,7 @@
  * enough to fit the UTF-16 as measured by utf16_to_utf8_length with an added
  * NULL terminator.
  */
-void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst);
+void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst, size_t dst_len);
 
 /**
  * Returns the length of "src" when "src" is valid UTF-8 string.
diff --git a/init/Android.mk b/init/Android.mk
index f83924e..36a5713 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -83,7 +83,7 @@
 
 LOCAL_STATIC_LIBRARIES := \
     libinit \
-    libbootloader_message_writer \
+    libbootloader_message \
     libfs_mgr \
     libfec \
     libfec_rs \
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 4ba7f11..b227d40 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -48,7 +48,7 @@
 #include <android-base/parseint.h>
 #include <android-base/strings.h>
 #include <android-base/stringprintf.h>
-#include <bootloader_message_writer.h>
+#include <bootloader_message/bootloader_message.h>
 #include <cutils/partition_utils.h>
 #include <cutils/android_reboot.h>
 #include <logwrap/logwrap.h>
@@ -346,6 +346,11 @@
     return 0;
 }
 
+/* umount <path> */
+static int do_umount(const std::vector<std::string>& args) {
+  return umount(args[1].c_str());
+}
+
 static struct {
     const char *name;
     unsigned flag;
@@ -856,8 +861,12 @@
     int ret = 0;
 
     for (auto it = std::next(args.begin()); it != args.end(); ++it) {
-        if (restorecon_recursive(it->c_str()) < 0)
+        /* The contents of CE paths are encrypted on FBE devices until user
+         * credentials are presented (filenames inside are mangled), so we need
+         * to delay restorecon of those until vold explicitly requests it. */
+        if (restorecon_recursive_skipce(it->c_str()) < 0) {
             ret = -errno;
+        }
     }
     return ret;
 }
@@ -944,6 +953,7 @@
         {"mkdir",                   {1,     4,    do_mkdir}},
         {"mount_all",               {1,     kMax, do_mount_all}},
         {"mount",                   {3,     kMax, do_mount}},
+        {"umount",                  {1,     1,    do_umount}},
         {"powerctl",                {1,     1,    do_powerctl}},
         {"restart",                 {1,     1,    do_restart}},
         {"restorecon",              {1,     kMax, do_restorecon}},
diff --git a/init/init.cpp b/init/init.cpp
index fc3e80f..4fcb0db 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -18,6 +18,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <fstream>
 #include <libgen.h>
 #include <paths.h>
 #include <signal.h>
@@ -246,6 +247,113 @@
     return result;
 }
 
+static void security_failure() {
+    LOG(ERROR) << "Security failure; rebooting into recovery mode...";
+    android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
+    while (true) { pause(); }  // never reached
+}
+
+#define MMAP_RND_PATH "/proc/sys/vm/mmap_rnd_bits"
+#define MMAP_RND_COMPAT_PATH "/proc/sys/vm/mmap_rnd_compat_bits"
+
+/* __attribute__((unused)) due to lack of mips support: see mips block
+ * in set_mmap_rnd_bits_action */
+static bool __attribute__((unused)) set_mmap_rnd_bits_min(int start, int min, bool compat) {
+    std::string path;
+    if (compat) {
+        path = MMAP_RND_COMPAT_PATH;
+    } else {
+        path = MMAP_RND_PATH;
+    }
+    std::ifstream inf(path, std::fstream::in);
+    if (!inf) {
+        LOG(ERROR) << "Cannot open for reading: " << path;
+        return false;
+    }
+    while (start >= min) {
+        // try to write out new value
+        std::string str_val = std::to_string(start);
+        std::ofstream of(path, std::fstream::out);
+        if (!of) {
+            LOG(ERROR) << "Cannot open for writing: " << path;
+            return false;
+        }
+        of << str_val << std::endl;
+        of.close();
+
+        // check to make sure it was recorded
+        inf.seekg(0);
+        std::string str_rec;
+        inf >> str_rec;
+        if (str_val.compare(str_rec) == 0) {
+            break;
+        }
+        start--;
+    }
+    inf.close();
+    if (start < min) {
+        LOG(ERROR) << "Unable to set minimum required entropy " << min << " in " << path;
+        return false;
+    }
+    return true;
+}
+
+/*
+ * Set /proc/sys/vm/mmap_rnd_bits and potentially
+ * /proc/sys/vm/mmap_rnd_compat_bits to the maximum supported values.
+ * Returns -1 if unable to set these to an acceptable value.
+ *
+ * To support this sysctl, the following upstream commits are needed:
+ *
+ * d07e22597d1d mm: mmap: add new /proc tunable for mmap_base ASLR
+ * e0c25d958f78 arm: mm: support ARCH_MMAP_RND_BITS
+ * 8f0d3aa9de57 arm64: mm: support ARCH_MMAP_RND_BITS
+ * 9e08f57d684a x86: mm: support ARCH_MMAP_RND_BITS
+ * ec9ee4acd97c drivers: char: random: add get_random_long()
+ * 5ef11c35ce86 mm: ASLR: use get_random_long()
+ */
+static int set_mmap_rnd_bits_action(const std::vector<std::string>& args)
+{
+    int ret = -1;
+
+    /* values are arch-dependent */
+#if defined(__aarch64__)
+    /* arm64 supports 18 - 33 bits depending on pagesize and VA_SIZE */
+    if (set_mmap_rnd_bits_min(33, 24, false)
+            && set_mmap_rnd_bits_min(16, 16, true)) {
+        ret = 0;
+    }
+#elif defined(__x86_64__)
+    /* x86_64 supports 28 - 32 bits */
+    if (set_mmap_rnd_bits_min(32, 32, false)
+            && set_mmap_rnd_bits_min(16, 16, true)) {
+        ret = 0;
+    }
+#elif defined(__arm__) || defined(__i386__)
+    /* check to see if we're running on 64-bit kernel */
+    bool h64 = !access(MMAP_RND_COMPAT_PATH, F_OK);
+    /* supported 32-bit architecture must have 16 bits set */
+    if (set_mmap_rnd_bits_min(16, 16, h64)) {
+        ret = 0;
+    }
+#elif defined(__mips__) || defined(__mips64__)
+    // TODO: add mips support b/27788820
+    ret = 0;
+#else
+    ERROR("Unknown architecture\n");
+#endif
+
+#ifdef __BRILLO__
+    // TODO: b/27794137
+    ret = 0;
+#endif
+    if (ret == -1) {
+        LOG(ERROR) << "Unable to set adequate mmap entropy value!";
+        security_failure();
+    }
+    return ret;
+}
+
 static int keychord_init_action(const std::vector<std::string>& args)
 {
     keychord_init();
@@ -402,12 +510,6 @@
     return 0;
 }
 
-static void security_failure() {
-    LOG(ERROR) << "Security failure; rebooting into recovery mode...";
-    android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
-    while (true) { pause(); }  // never reached
-}
-
 static void selinux_initialize(bool in_kernel_domain) {
     Timer t;
 
@@ -571,6 +673,7 @@
     am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
     // ... so that we can start queuing up actions that require stuff from /dev.
     am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
+    am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");
     am.QueueBuiltinAction(keychord_init_action, "keychord_init");
     am.QueueBuiltinAction(console_init_action, "console_init");
 
diff --git a/init/readme.txt b/init/readme.txt
index 7260775..cde4055 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -366,6 +366,9 @@
    Trigger an event.  Used to queue an action from another
    action.
 
+umount <path>
+   Unmount the filesystem mounted at that path.
+
 verity_load_state
    Internal implementation detail used to load dm-verity state.
 
diff --git a/init/util.cpp b/init/util.cpp
index 6c1923f..80b2325 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -362,6 +362,12 @@
     return selinux_android_restorecon(pathname, SELINUX_ANDROID_RESTORECON_RECURSE);
 }
 
+int restorecon_recursive_skipce(const char* pathname)
+{
+    return selinux_android_restorecon(pathname,
+            SELINUX_ANDROID_RESTORECON_RECURSE | SELINUX_ANDROID_RESTORECON_SKIPCE);
+}
+
 /*
  * Writes hex_len hex characters (1/2 byte) to hex from bytes.
  */
diff --git a/init/util.h b/init/util.h
index 9d522cc..651e609 100644
--- a/init/util.h
+++ b/init/util.h
@@ -59,6 +59,7 @@
 int make_dir(const char *path, mode_t mode);
 int restorecon(const char *pathname);
 int restorecon_recursive(const char *pathname);
+int restorecon_recursive_skipce(const char *pathname);
 std::string bytes_to_hex(const uint8_t *bytes, size_t bytes_len);
 bool is_dir(const char* pathname);
 bool expand_props(const std::string& src, std::string* dst);
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 840ac86..a6eaf11 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -91,6 +91,7 @@
     { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" },
     { 00750, AID_ROOT,   AID_SHELL,  0, "data/nativetest" },
     { 00750, AID_ROOT,   AID_SHELL,  0, "data/nativetest64" },
+    { 00775, AID_ROOT,   AID_ROOT,   0, "data/preloads" },
     { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" },
     { 00755, AID_ROOT,   AID_SYSTEM, 0, "mnt" },
     { 00755, AID_ROOT,   AID_ROOT,   0, "root" },
@@ -142,6 +143,13 @@
     { 00750, AID_ROOT,      AID_SHELL,     CAP_MASK_LONG(CAP_SETUID) | CAP_MASK_LONG(CAP_SETGID), "system/bin/run-as" },
     { 00700, AID_SYSTEM,    AID_SHELL,     CAP_MASK_LONG(CAP_BLOCK_SUSPEND), "system/bin/inputflinger" },
 
+    /* Support FIFO scheduling mode in SurfaceFlinger. */
+    { 00755, AID_SYSTEM,    AID_GRAPHICS,     CAP_MASK_LONG(CAP_SYS_NICE), "system/bin/surfaceflinger" },
+
+    /* Support hostapd administering a network interface. */
+    { 00755, AID_WIFI,      AID_WIFI,     CAP_MASK_LONG(CAP_NET_ADMIN) |
+                                          CAP_MASK_LONG(CAP_NET_RAW),    "system/bin/hostapd" },
+
     { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/uncrypt" },
     { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/install-recovery.sh" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/*" },
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index 884ee17..6e6a9eb 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -66,9 +66,12 @@
 static int bg_cpuset_fd = -1;
 static int fg_cpuset_fd = -1;
 static int ta_cpuset_fd = -1; // special cpuset for top app
+#endif
+
+// File descriptors open to /dev/stune/../tasks, setup by initialize, or -1 on error
 static int bg_schedboost_fd = -1;
 static int fg_schedboost_fd = -1;
-#endif
+static int ta_schedboost_fd = -1;
 
 /* Add tid to the scheduling group defined by the policy */
 static int add_tid_to_cgroup(int tid, int fd)
@@ -138,9 +141,11 @@
         ta_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
 
 #ifdef USE_SCHEDBOOST
+        filename = "/dev/stune/top-app/tasks";
+        ta_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
         filename = "/dev/stune/foreground/tasks";
         fg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
-        filename = "/dev/stune/tasks";
+        filename = "/dev/stune/background/tasks";
         bg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
 #endif
     }
@@ -298,11 +303,10 @@
         break;
     case SP_TOP_APP :
         fd = ta_cpuset_fd;
-        boost_fd = fg_schedboost_fd;
+        boost_fd = ta_schedboost_fd;
         break;
     case SP_SYSTEM:
         fd = system_bg_cpuset_fd;
-        boost_fd = bg_schedboost_fd;
         break;
     default:
         boost_fd = fd = -1;
@@ -314,10 +318,12 @@
             return -errno;
     }
 
+#ifdef USE_SCHEDBOOST
     if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) {
         if (errno != ESRCH && errno != ENOENT)
             return -errno;
     }
+#endif
 
     return 0;
 #endif
@@ -374,19 +380,26 @@
 #endif
 
     if (__sys_supports_schedgroups) {
-        int fd;
+        int fd = -1;
+        int boost_fd = -1;
         switch (policy) {
         case SP_BACKGROUND:
             fd = bg_cgroup_fd;
+            boost_fd = bg_schedboost_fd;
             break;
         case SP_FOREGROUND:
         case SP_AUDIO_APP:
         case SP_AUDIO_SYS:
+            fd = fg_cgroup_fd;
+            boost_fd = fg_schedboost_fd;
+            break;
         case SP_TOP_APP:
             fd = fg_cgroup_fd;
+            boost_fd = ta_schedboost_fd;
             break;
         default:
             fd = -1;
+            boost_fd = -1;
             break;
         }
 
@@ -395,6 +408,13 @@
             if (errno != ESRCH && errno != ENOENT)
                 return -errno;
         }
+
+#ifdef USE_SCHEDBOOST
+        if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) {
+            if (errno != ESRCH && errno != ENOENT)
+                return -errno;
+        }
+#endif
     } else {
         struct sched_param param;
 
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index ad45282..cacaf91 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -104,20 +104,21 @@
 {
     if (len == 0) return getEmptyString();
 
-    const ssize_t bytes = utf16_to_utf8_length(in, len);
-    if (bytes < 0) {
+     // Allow for closing '\0'
+    const ssize_t resultStrLen = utf16_to_utf8_length(in, len) + 1;
+    if (resultStrLen < 1) {
         return getEmptyString();
     }
 
-    SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
+    SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
     ALOG_ASSERT(buf, "Unable to allocate shared buffer");
     if (!buf) {
         return getEmptyString();
     }
 
-    char* str = (char*)buf->data();
-    utf16_to_utf8(in, len, str);
-    return str;
+    char* resultStr = (char*)buf->data();
+    utf16_to_utf8(in, len, resultStr, resultStrLen);
+    return resultStr;
 }
 
 static char* allocFromUTF32(const char32_t* in, size_t len)
@@ -126,21 +127,21 @@
         return getEmptyString();
     }
 
-    const ssize_t bytes = utf32_to_utf8_length(in, len);
-    if (bytes < 0) {
+    const ssize_t resultStrLen = utf32_to_utf8_length(in, len) + 1;
+    if (resultStrLen < 1) {
         return getEmptyString();
     }
 
-    SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
+    SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
     ALOG_ASSERT(buf, "Unable to allocate shared buffer");
     if (!buf) {
         return getEmptyString();
     }
 
-    char* str = (char*) buf->data();
-    utf32_to_utf8(in, len, str);
+    char* resultStr = (char*) buf->data();
+    utf32_to_utf8(in, len, resultStr, resultStrLen);
 
-    return str;
+    return resultStr;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index f1f8bc9..ba084f6 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <log/log.h>
 #include <utils/Unicode.h>
 
 #include <stddef.h>
@@ -182,7 +183,7 @@
     return ret;
 }
 
-void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst)
+void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst, size_t dst_len)
 {
     if (src == NULL || src_len == 0 || dst == NULL) {
         return;
@@ -193,9 +194,12 @@
     char *cur = dst;
     while (cur_utf32 < end_utf32) {
         size_t len = utf32_codepoint_utf8_length(*cur_utf32);
+        LOG_ALWAYS_FATAL_IF(dst_len < len, "%zu < %zu", dst_len, len);
         utf32_codepoint_to_utf8((uint8_t *)cur, *cur_utf32++, len);
         cur += len;
+        dst_len -= len;
     }
+    LOG_ALWAYS_FATAL_IF(dst_len < 1, "dst_len < 1: %zu < 1", dst_len);
     *cur = '\0';
 }
 
@@ -348,7 +352,7 @@
            : 0);
 }
 
-void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst)
+void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst, size_t dst_len)
 {
     if (src == NULL || src_len == 0 || dst == NULL) {
         return;
@@ -369,9 +373,12 @@
             utf32 = (char32_t) *cur_utf16++;
         }
         const size_t len = utf32_codepoint_utf8_length(utf32);
+        LOG_ALWAYS_FATAL_IF(dst_len < len, "%zu < %zu", dst_len, len);
         utf32_codepoint_to_utf8((uint8_t*)cur, utf32, len);
         cur += len;
+        dst_len -= len;
     }
+    LOG_ALWAYS_FATAL_IF(dst_len < 1, "%zu < 1", dst_len);
     *cur = '\0';
 }
 
@@ -432,10 +439,10 @@
     const char16_t* const end = src + src_len;
     while (src < end) {
         if ((*src & 0xFC00) == 0xD800 && (src + 1) < end
-                && (*++src & 0xFC00) == 0xDC00) {
+                && (*(src + 1) & 0xFC00) == 0xDC00) {
             // surrogate pairs are always 4 bytes.
             ret += 4;
-            src++;
+            src += 2;
         } else {
             ret += utf32_codepoint_utf8_length((char32_t) *src++);
         }
diff --git a/libutils/tests/String8_test.cpp b/libutils/tests/String8_test.cpp
index 01e64f6..3947a5f 100644
--- a/libutils/tests/String8_test.cpp
+++ b/libutils/tests/String8_test.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "String8_test"
 #include <utils/Log.h>
 #include <utils/String8.h>
+#include <utils/String16.h>
 
 #include <gtest/gtest.h>
 
@@ -77,4 +78,22 @@
     EXPECT_EQ(NO_MEMORY, String8("").setTo(in, SIZE_MAX));
 }
 
+// http://b/29250543
+TEST_F(String8Test, CorrectInvalidSurrogate) {
+    // d841d8 is an invalid start for a surrogate pair. Make sure this is handled by ignoring the
+    // first character in the pair and handling the rest correctly.
+    String16 string16(u"\xd841\xd841\xdc41\x0000");
+    String8 string8(string16);
+
+    EXPECT_EQ(4U, string8.length());
+}
+
+TEST_F(String8Test, CheckUtf32Conversion) {
+    // Since bound checks were added, check the conversion can be done without fatal errors.
+    // The utf8 lengths of these are chars are 1 + 2 + 3 + 4 = 10.
+    const char32_t string32[] = U"\x0000007f\x000007ff\x0000911\x0010fffe";
+    String8 string8(string32);
+    EXPECT_EQ(10U, string8.length());
+}
+
 }
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index ac2b128..a0b7499 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -401,7 +401,32 @@
     }
 }
 
-pid_t LogKlog::sniffPid(const char *cp, size_t len) {
+pid_t LogKlog::sniffPid(const char **buf, size_t len) {
+    const char *cp = *buf;
+    // HTC kernels with modified printk "c0   1648 "
+    if ((len > 9) &&
+            (cp[0] == 'c') &&
+            isdigit(cp[1]) &&
+            (isdigit(cp[2]) || (cp[2] == ' ')) &&
+            (cp[3] == ' ')) {
+        bool gotDigit = false;
+        int i;
+        for (i = 4; i < 9; ++i) {
+            if (isdigit(cp[i])) {
+                gotDigit = true;
+            } else if (gotDigit || (cp[i] != ' ')) {
+                break;
+            }
+        }
+        if ((i == 9) && (cp[i] == ' ')) {
+            int pid = 0;
+            char dummy;
+            if (sscanf(cp + 4, "%d%c", &pid, &dummy) == 2) {
+                *buf = cp + 10; // skip-it-all
+                return pid;
+            }
+        }
+    }
     while (len) {
         // Mediatek kernels with modified printk
         if (*cp == '[') {
@@ -587,7 +612,7 @@
     }
 
     // Parse pid, tid and uid
-    const pid_t pid = sniffPid(p, len - (p - buf));
+    const pid_t pid = sniffPid(&p, len - (p - buf));
     const pid_t tid = pid;
     const uid_t uid = pid ? logbuf->pidToUid(pid) : 0;
 
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
index ee73b71..a4f871e 100644
--- a/logd/LogKlog.h
+++ b/logd/LogKlog.h
@@ -51,7 +51,7 @@
 
 protected:
     void sniffTime(log_time &now, const char **buf, size_t len, bool reverse);
-    pid_t sniffPid(const char *buf, size_t len);
+    pid_t sniffPid(const char **buf, size_t len);
     void calculateCorrection(const log_time &monotonic,
                              const char *real_string, size_t len);
     virtual bool onDataAvailable(SocketClient *cli);
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index e060a2c..aa5a520 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -26,6 +26,7 @@
 #######################################
 # asan.options
 ifneq ($(filter address,$(SANITIZE_TARGET)),)
+
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := asan.options
@@ -34,6 +35,72 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT)
 
 include $(BUILD_PREBUILT)
+
+# Modules for asan.options.X files.
+
+ASAN_OPTIONS_FILES :=
+
+define create-asan-options-module
+include $$(CLEAR_VARS)
+LOCAL_MODULE := asan.options.$(1)
+ASAN_OPTIONS_FILES += asan.options.$(1)
+LOCAL_MODULE_CLASS := ETC
+# The asan.options.off.template tries to turn off as much of ASAN as is possible.
+LOCAL_SRC_FILES := asan.options.off.template
+LOCAL_MODULE_PATH := $(TARGET_OUT)
+include $$(BUILD_PREBUILT)
+endef
+
+# Pretty comprehensive set of native services. This list is helpful if all that's to be checked is an
+# app.
+ifeq ($(SANITIZE_LITE),true)
+SANITIZE_ASAN_OPTIONS_FOR := \
+  adbd \
+  ATFWD-daemon \
+  audioserver \
+  bridgemgrd \
+  cameraserver \
+  cnd \
+  debuggerd \
+  debuggerd64 \
+  dex2oat \
+  drmserver \
+  fingerprintd \
+  gatekeeperd \
+  installd \
+  keystore \
+  lmkd \
+  logcat \
+  logd \
+  lowi-server \
+  media.codec \
+  mediadrmserver \
+  media.extractor \
+  mediaserver \
+  mm-qcamera-daemon \
+  mpdecision \
+  netmgrd \
+  perfd \
+  perfprofd \
+  qmuxd \
+  qseecomd \
+  rild \
+  sdcard \
+  servicemanager \
+  slim_daemon \
+  surfaceflinger \
+  thermal-engine \
+  time_daemon \
+  update_engine \
+  vold \
+  wpa_supplicant \
+  zip
+endif
+
+ifneq ($(SANITIZE_ASAN_OPTIONS_FOR),)
+  $(foreach binary, $(SANITIZE_ASAN_OPTIONS_FOR), $(eval $(call create-asan-options-module,$(binary))))
+endif
+
 endif
 
 #######################################
@@ -47,14 +114,14 @@
 EXPORT_GLOBAL_ASAN_OPTIONS :=
 ifneq ($(filter address,$(SANITIZE_TARGET)),)
   EXPORT_GLOBAL_ASAN_OPTIONS := export ASAN_OPTIONS include=/system/asan.options
-  LOCAL_REQUIRED_MODULES := asan.options
+  LOCAL_REQUIRED_MODULES := asan.options $(ASAN_OPTIONS_FILES)
 endif
 # Put it here instead of in init.rc module definition,
 # because init.rc is conditionally included.
 #
 # create some directories (some are mount points) and symlinks
 LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
-    sbin dev proc sys system data oem acct cache config storage mnt root $(BOARD_ROOT_EXTRA_FOLDERS)); \
+    sbin dev proc sys system data oem acct config storage mnt root $(BOARD_ROOT_EXTRA_FOLDERS)); \
     ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
     ln -sf /sys/kernel/debug $(TARGET_ROOT_OUT)/d; \
     ln -sf /storage/self/primary $(TARGET_ROOT_OUT)/sdcard
@@ -63,6 +130,11 @@
 else
   LOCAL_POST_INSTALL_CMD += ; ln -sf /system/vendor $(TARGET_ROOT_OUT)/vendor
 endif
+ifdef BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
+  LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/cache
+else
+  LOCAL_POST_INSTALL_CMD += ; ln -sf /data/cache $(TARGET_ROOT_OUT)/cache
+endif
 ifdef BOARD_ROOT_EXTRA_SYMLINKS
 # BOARD_ROOT_EXTRA_SYMLINKS is a list of <target>:<link_name>.
   LOCAL_POST_INSTALL_CMD += $(foreach s, $(BOARD_ROOT_EXTRA_SYMLINKS),\
diff --git a/rootdir/asan.options b/rootdir/asan.options
index 43896a1..70e0eca 100644
--- a/rootdir/asan.options
+++ b/rootdir/asan.options
@@ -3,3 +3,4 @@
 alloc_dealloc_mismatch=0
 allocator_may_return_null=1
 detect_container_overflow=0
+include_if_exists=/system/asan.options.%b
diff --git a/rootdir/asan.options.off.template b/rootdir/asan.options.off.template
new file mode 100644
index 0000000..59a1249
--- /dev/null
+++ b/rootdir/asan.options.off.template
@@ -0,0 +1,7 @@
+quarantine_size_mb=0
+max_redzone=16
+poison_heap=false
+poison_partial=false
+poison_array_cookie=false
+alloc_dealloc_mismatch=false
+new_delete_type_mismatch=false
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a68cb78..f65f470 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -50,12 +50,20 @@
     mkdir /dev/stune
     mount cgroup none /dev/stune schedtune
     mkdir /dev/stune/foreground
+    mkdir /dev/stune/background
+    mkdir /dev/stune/top-app
     chown system system /dev/stune
     chown system system /dev/stune/foreground
+    chown system system /dev/stune/background
+    chown system system /dev/stune/top-app
     chown system system /dev/stune/tasks
     chown system system /dev/stune/foreground/tasks
+    chown system system /dev/stune/background/tasks
+    chown system system /dev/stune/top-app/tasks
     chmod 0664 /dev/stune/tasks
     chmod 0664 /dev/stune/foreground/tasks
+    chmod 0664 /dev/stune/background/tasks
+    chmod 0664 /dev/stune/top-app/tasks
 
     # Mount staging areas for devices managed by vold
     # See storage config details at http://source.android.com/tech/storage/
@@ -134,16 +142,17 @@
     chown system system /dev/cpuctl
     chown system system /dev/cpuctl/tasks
     chmod 0666 /dev/cpuctl/tasks
-    write /dev/cpuctl/cpu.rt_runtime_us 800000
     write /dev/cpuctl/cpu.rt_period_us 1000000
+    write /dev/cpuctl/cpu.rt_runtime_us 950000
 
     mkdir /dev/cpuctl/bg_non_interactive
     chown system system /dev/cpuctl/bg_non_interactive/tasks
     chmod 0666 /dev/cpuctl/bg_non_interactive/tasks
     # 5.0 %
     write /dev/cpuctl/bg_non_interactive/cpu.shares 52
-    write /dev/cpuctl/bg_non_interactive/cpu.rt_runtime_us 700000
     write /dev/cpuctl/bg_non_interactive/cpu.rt_period_us 1000000
+    # active FIFO threads will never be in BG
+    write /dev/cpuctl/bg_non_interactive/cpu.rt_runtime_us 10000
 
     # sets up initial cpusets for ActivityManager
     mkdir /dev/cpuset
@@ -225,6 +234,8 @@
     # expecting it to point to /proc/self/fd
     symlink /proc/self/fd /dev/fd
 
+    export DOWNLOAD_CACHE /data/cache
+
 # Healthd can trigger a full boot from charger mode by signaling this
 # property when the power button is held.
 on property:sys.boot_from_charger_mode=1
@@ -274,7 +285,8 @@
     # Mount shared so changes propagate into child namespaces
     mount rootfs rootfs / shared rec
     # Mount default storage into root namespace
-    mount none /mnt/runtime/default /storage slave bind rec
+    mount none /mnt/runtime/default /storage bind rec
+    mount none none /storage slave rec
 
     # Make sure /sys/kernel/debug (if present) is labeled properly
     restorecon_recursive /sys/kernel/debug
@@ -394,6 +406,10 @@
     # create the A/B OTA directory, so as to enforce our permissions
     mkdir /data/ota 0771 root root
 
+    # create the OTA package directory. It will be accessed by GmsCore (cache
+    # group), update_engine and update_verifier.
+    mkdir /data/ota_package 0770 system cache
+
     # create resource-cache and double-check the perms
     mkdir /data/resource-cache 0771 system system
     chown system system /data/resource-cache
@@ -438,6 +454,11 @@
     mkdir /data/media 0770 media_rw media_rw
     mkdir /data/media/obb 0770 media_rw media_rw
 
+    mkdir /data/cache 0770 system cache
+    mkdir /data/cache/recovery 0770 system cache
+    mkdir /data/cache/backup_stage 0700 system system
+    mkdir /data/cache/backup 0700 system system
+
     init_user0
 
     # Set SELinux security contexts on upgrade or policy update.
@@ -546,7 +567,7 @@
 
 on nonencrypted
     # A/B update verifier that marks a successful boot.
-    exec - root -- /system/bin/update_verifier nonencrypted
+    exec - root cache -- /system/bin/update_verifier nonencrypted
     class_start main
     class_start late_start
 
@@ -569,12 +590,12 @@
 
 on property:vold.decrypt=trigger_restart_min_framework
     # A/B update verifier that marks a successful boot.
-    exec - root -- /system/bin/update_verifier trigger_restart_min_framework
+    exec - root cache -- /system/bin/update_verifier trigger_restart_min_framework
     class_start main
 
 on property:vold.decrypt=trigger_restart_framework
     # A/B update verifier that marks a successful boot.
-    exec - root -- /system/bin/update_verifier trigger_restart_framework
+    exec - root cache -- /system/bin/update_verifier trigger_restart_framework
     class_start main
     class_start late_start
 
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index 807f9bc..2d7d5c2 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -8,4 +8,4 @@
     onrestart restart cameraserver
     onrestart restart media
     onrestart restart netd
-    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index 10fa915..a5e32c2 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -8,11 +8,11 @@
     onrestart restart cameraserver
     onrestart restart media
     onrestart restart netd
-    writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks
 
 service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
     class main
     priority -20
     socket zygote_secondary stream 660 root system
     onrestart restart zygote
-    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index 13ffd7e..8584cbb 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -8,4 +8,4 @@
     onrestart restart cameraserver
     onrestart restart media
     onrestart restart netd
-    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 1164ac5..4a32097 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -8,11 +8,11 @@
     onrestart restart cameraserver
     onrestart restart media
     onrestart restart netd
-    writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks
 
 service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
     class main
     priority -20
     socket zygote_secondary stream 660 root system
     onrestart restart zygote
-    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks
diff --git a/sdcard/Android.mk b/sdcard/Android.mk
index 992b51c..0c58574 100644
--- a/sdcard/Android.mk
+++ b/sdcard/Android.mk
@@ -5,7 +5,7 @@
 LOCAL_SRC_FILES := sdcard.cpp fuse.cpp
 LOCAL_MODULE := sdcard
 LOCAL_CFLAGS := -Wall -Wno-unused-parameter -Werror
-LOCAL_SHARED_LIBRARIES := libbase liblog libcutils libminijail libpackagelistparser
+LOCAL_SHARED_LIBRARIES := libbase libcutils libminijail libpackagelistparser
 
 LOCAL_SANITIZE := integer
 LOCAL_CLANG := true
diff --git a/sdcard/fuse.cpp b/sdcard/fuse.cpp
index 0d3e378..6a972ea 100644
--- a/sdcard/fuse.cpp
+++ b/sdcard/fuse.cpp
@@ -45,18 +45,20 @@
 static void acquire_node_locked(struct node* node)
 {
     node->refcount++;
-    TRACE("ACQUIRE %p (%s) rc=%d\n", node, node->name, node->refcount);
+    DLOG(INFO) << "ACQUIRE " << std::hex << node << std::dec
+               << " (" << node->name << ") rc=" << node->refcount;
 }
 
 static void remove_node_from_parent_locked(struct node* node);
 
 static void release_node_locked(struct node* node)
 {
-    TRACE("RELEASE %p (%s) rc=%d\n", node, node->name, node->refcount);
+    DLOG(INFO) << "RELEASE " << std::hex << node << std::dec
+               << " (" << node->name << ") rc=" << node->refcount;
     if (node->refcount > 0) {
         node->refcount--;
         if (!node->refcount) {
-            TRACE("DESTROY %p (%s)\n", node, node->name);
+            DLOG(INFO) << "DESTROY " << std::hex << node << std::dec << " (" << node->name << ")";
             remove_node_from_parent_locked(node);
 
             /* TODO: remove debugging - poison memory */
@@ -67,7 +69,7 @@
             free(node);
         }
     } else {
-        ERROR("Zero refcnt %p\n", node);
+        LOG(ERROR) << std::hex << node << std::dec << " refcount=0";
     }
 }
 
@@ -161,7 +163,7 @@
         struct dirent* entry;
         DIR* dir = opendir(path);
         if (!dir) {
-            ERROR("opendir %s failed: %s\n", path, strerror(errno));
+            PLOG(ERROR) << "opendir(" << path << ") failed";
             return actual;
         }
         while ((entry = readdir(dir))) {
@@ -229,7 +231,7 @@
         if (errno == EEXIST) {
             return 0;
         } else {
-            ERROR("Failed to open(%s): %s\n", path, strerror(errno));
+            PLOG(ERROR) << "open(" << path << ") failed";
             return -1;
         }
     }
@@ -341,7 +343,7 @@
     // Detect overflows in the inode counter. "4 billion nodes should be enough
     // for everybody".
     if (fuse->global->inode_ctr == 0) {
-        ERROR("No more inode numbers available");
+        LOG(ERROR) << "No more inode numbers available";
         return NULL;
     }
 
@@ -490,7 +492,7 @@
 
     res = writev(fuse->fd, vec, 2);
     if (res < 0) {
-        ERROR("*** REPLY FAILED *** %d\n", errno);
+        PLOG(ERROR) << "*** REPLY FAILED ***";
     }
 }
 
@@ -566,7 +568,7 @@
     res = writev(fuse->fd, vec, 3);
     /* Ignore ENOENT, since other views may not have seen the entry */
     if (res < 0 && errno != ENOENT) {
-        ERROR("*** NOTIFY FAILED *** %d\n", errno);
+        PLOG(ERROR) << "*** NOTIFY FAILED ***";
     }
 }
 
@@ -626,7 +628,7 @@
     pthread_mutex_lock(&fuse->global->lock);
     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
     DLOG(INFO) << "[" << handler->token << "] GETATTR flags=" << req->getattr_flags
-               << " fh=" << std::hex << req->fh << " @ " << std::hex << hdr->nodeid
+               << " fh=" << std::hex << req->fh << " @ " << hdr->nodeid << std::dec
                << " (" << (node ? node->name : "?") << ")";
     pthread_mutex_unlock(&fuse->global->lock);
 
@@ -650,7 +652,7 @@
     pthread_mutex_lock(&fuse->global->lock);
     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
     DLOG(INFO) << "[" << handler->token << "] SETATTR fh=" << std::hex << req->fh
-               << " valid=" << std::hex << req->valid << " @ " << std::hex << hdr->nodeid
+               << " valid=" << std::hex << req->valid << " @ " << hdr->nodeid << std::dec
                << " (" << (node ? node->name : "?") << ")";
     pthread_mutex_unlock(&fuse->global->lock);
 
@@ -695,8 +697,8 @@
               times[1].tv_nsec = req->mtimensec;
             }
         }
-        TRACE("[%d] Calling utimensat on %s with atime %ld, mtime=%ld\n",
-                handler->token, path, times[0].tv_sec, times[1].tv_sec);
+        DLOG(INFO) << "[" << handler->token << "] Calling utimensat on " << path
+                   << " with atime " << times[0].tv_sec << ", mtime=" << times[1].tv_sec;
         if (utimensat(-1, path, times, 0) < 0) {
             return -errno;
         }
@@ -767,7 +769,7 @@
         char nomedia[PATH_MAX];
         snprintf(nomedia, PATH_MAX, "%s/.nomedia", child_path);
         if (touch(nomedia, 0664) != 0) {
-            ERROR("Failed to touch(%s): %s\n", nomedia, strerror(errno));
+            PLOG(ERROR) << "touch(" << nomedia << ") failed";
             return -ENOENT;
         }
     }
@@ -775,7 +777,7 @@
         char nomedia[PATH_MAX];
         snprintf(nomedia, PATH_MAX, "%s/.nomedia", fuse->global->obb_path);
         if (touch(nomedia, 0664) != 0) {
-            ERROR("Failed to touch(%s): %s\n", nomedia, strerror(errno));
+            PLOG(ERROR) << "touch(" << nomedia << ") failed";
             return -ENOENT;
         }
     }
@@ -818,7 +820,8 @@
         /* Tell all other views that node is gone */
         DLOG(INFO) << "[" << handler->token << "] fuse_notify_delete"
                    << " parent=" << std::hex << parent_node->nid
-                   << ", child=" << std::hex << child_node->nid << ", name=" << name;
+                   << ", child=" << std::hex << child_node->nid << std::dec
+                   << ", name=" << name;
         if (fuse != fuse->global->fuse_default) {
             fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
         }
@@ -867,7 +870,8 @@
         /* Tell all other views that node is gone */
         DLOG(INFO) << "[" << handler->token << "] fuse_notify_delete"
                    << " parent=" << std::hex << parent_node->nid
-                   << ", child=" << std::hex << child_node->nid << ", name=" << name;
+                   << ", child=" << std::hex << child_node->nid << std::dec
+                   << ", name=" << name;
         if (fuse != fuse->global->fuse_default) {
             fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
         }
@@ -939,7 +943,7 @@
         goto io_error;
     }
 
-    TRACE("[%d] RENAME %s->%s\n", handler->token, old_child_path, new_child_path);
+    DLOG(INFO) << "[" << handler->token << "] RENAME " << old_child_path << "->" << new_child_path;
     res = rename(old_child_path, new_child_path);
     if (res < 0) {
         res = -errno;
@@ -987,7 +991,8 @@
     pthread_mutex_lock(&fuse->global->lock);
     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
     DLOG(INFO) << "[" << handler->token << "] OPEN 0" << std::oct << req->flags
-               << " @ " << std::hex << hdr->nodeid << " (" << (node ? node->name : "?") << ")";
+               << " @ " << std::hex << hdr->nodeid << std::dec
+               << " (" << (node ? node->name : "?") << ")";
     pthread_mutex_unlock(&fuse->global->lock);
 
     if (!node) {
@@ -1001,7 +1006,7 @@
     if (!h) {
         return -ENOMEM;
     }
-    TRACE("[%d] OPEN %s\n", handler->token, path);
+    DLOG(INFO) << "[" << handler->token << "] OPEN " << path;
     h->fd = open(path, req->flags);
     if (h->fd < 0) {
         free(h);
@@ -1028,8 +1033,8 @@
      * overlaps the request buffer and will clobber data in the request.  This
      * saves us 128KB per request handler thread at the cost of this scary comment. */
 
-    DLOG(INFO) << "[" << handler->token << "] READ " << std::hex << h << "(" << h->fd << ") "
-               << size << "@" << offset;
+    DLOG(INFO) << "[" << handler->token << "] READ " << std::hex << h << std::dec
+               << "(" << h->fd << ") " << size << "@" << offset;
     if (size > MAX_READ) {
         return -EINVAL;
     }
@@ -1055,8 +1060,8 @@
         buffer = (const __u8*) aligned_buffer;
     }
 
-    DLOG(INFO) << "[" << handler->token << "] WRITE " << std::hex << h << "(" << h->fd << ") "
-               << req->size << "@" << req->offset;
+    DLOG(INFO) << "[" << handler->token << "] WRITE " << std::hex << h << std::dec
+               << "(" << h->fd << ") " << req->size << "@" << req->offset;
     res = pwrite64(h->fd, buffer, req->size, req->offset);
     if (res < 0) {
         return -errno;
@@ -1076,7 +1081,7 @@
     int res;
 
     pthread_mutex_lock(&fuse->global->lock);
-    TRACE("[%d] STATFS\n", handler->token);
+    DLOG(INFO) << "[" << handler->token << "] STATFS";
     res = get_node_path_locked(&fuse->global->root, path, sizeof(path));
     pthread_mutex_unlock(&fuse->global->lock);
     if (res < 0) {
@@ -1103,7 +1108,8 @@
 {
     struct handle *h = static_cast<struct handle*>(id_to_ptr(req->fh));
 
-    TRACE("[%d] RELEASE %p(%d)\n", handler->token, h, h->fd);
+    DLOG(INFO) << "[" << handler->token << "] RELEASE " << std::hex << h << std::dec
+               << "(" << h->fd << ")";
     close(h->fd);
     free(h);
     return 0;
@@ -1124,9 +1130,8 @@
       fd = h->fd;
     }
 
-    TRACE("[%d] %s %p(%d) is_data_sync=%d\n", handler->token,
-            is_dir ? "FSYNCDIR" : "FSYNC",
-            static_cast<struct node*>(id_to_ptr(req->fh)), fd, is_data_sync);
+    DLOG(INFO) << "[" << handler->token << "] " << (is_dir ? "FSYNCDIR" : "FSYNC") << " "
+               << std::hex << req->fh << std::dec << "(" << fd << ") is_data_sync=" << is_data_sync;
     int res = is_data_sync ? fdatasync(fd) : fsync(fd);
     if (res == -1) {
         return -errno;
@@ -1137,7 +1142,7 @@
 static int handle_flush(struct fuse* fuse, struct fuse_handler* handler,
         const struct fuse_in_header* hdr)
 {
-    TRACE("[%d] FLUSH\n", handler->token);
+    DLOG(INFO) << "[" << handler->token << "] FLUSH";
     return 0;
 }
 
@@ -1165,7 +1170,7 @@
     if (!h) {
         return -ENOMEM;
     }
-    TRACE("[%d] OPENDIR %s\n", handler->token, path);
+    DLOG(INFO) << "[" << handler->token << "] OPENDIR " << path;
     h->d = opendir(path);
     if (!h->d) {
         free(h);
@@ -1186,10 +1191,10 @@
     struct dirent *de;
     struct dirhandle *h = static_cast<struct dirhandle*>(id_to_ptr(req->fh));
 
-    TRACE("[%d] READDIR %p\n", handler->token, h);
+    DLOG(INFO) << "[" << handler->token << "] READDIR " << h;
     if (req->offset == 0) {
         /* rewinddir() might have been called above us, so rewind here too */
-        TRACE("[%d] calling rewinddir()\n", handler->token);
+        DLOG(INFO) << "[" << handler->token << "] calling rewinddir()";
         rewinddir(h->d);
     }
     de = readdir(h->d);
@@ -1212,7 +1217,7 @@
 {
     struct dirhandle *h = static_cast<struct dirhandle*>(id_to_ptr(req->fh));
 
-    TRACE("[%d] RELEASEDIR %p\n", handler->token, h);
+    DLOG(INFO) << "[" << handler->token << "] RELEASEDIR " << h;
     closedir(h->d);
     free(h);
     return 0;
@@ -1224,8 +1229,8 @@
     struct fuse_init_out out;
     size_t fuse_struct_size;
 
-    TRACE("[%d] INIT ver=%d.%d maxread=%d flags=%x\n",
-            handler->token, req->major, req->minor, req->max_readahead, req->flags);
+    DLOG(INFO) << "[" << handler->token << "] INIT ver=" << req->major << "." << req->minor
+               << " maxread=" << req->max_readahead << " flags=" << std::hex << req->flags;
 
     /* Kernel 2.6.16 is the first stable kernel with struct fuse_init_out
      * defined (fuse version 7.6). The structure is the same from 7.6 through
@@ -1233,8 +1238,9 @@
      * new parameters.
      */
     if (req->major != FUSE_KERNEL_VERSION || req->minor < 6) {
-        ERROR("Fuse kernel version mismatch: Kernel version %d.%d, Expected at least %d.6",
-              req->major, req->minor, FUSE_KERNEL_VERSION);
+        LOG(ERROR) << "Fuse kernel version mismatch: Kernel version "
+                   << req->major << "." << req->minor
+                   << ", Expected at least " << FUSE_KERNEL_VERSION << ".6";
         return -1;
     }
 
@@ -1412,7 +1418,7 @@
 
     default: {
         DLOG(INFO) << "[" << handler->token << "] NOTIMPL op=" << hdr->opcode
-                   << "uniq=" << std::hex << hdr->unique << "nid=" << std::hex << hdr->nodeid;
+                   << "uniq=" << std::hex << hdr->unique << "nid=" << hdr->nodeid << std::dec;
         return -ENOSYS;
     }
     }
@@ -1426,23 +1432,23 @@
                 handler->request_buffer, sizeof(handler->request_buffer)));
         if (len < 0) {
             if (errno == ENODEV) {
-                ERROR("[%d] someone stole our marbles!\n", handler->token);
+                LOG(ERROR) << "[" << handler->token << "] someone stole our marbles!";
                 exit(2);
             }
-            ERROR("[%d] handle_fuse_requests: errno=%d\n", handler->token, errno);
+            PLOG(ERROR) << "[" << handler->token << "] handle_fuse_requests";
             continue;
         }
 
         if ((size_t)len < sizeof(struct fuse_in_header)) {
-            ERROR("[%d] request too short: len=%zu\n", handler->token, (size_t)len);
+            LOG(ERROR) << "[" << handler->token << "] request too short: len=" << len;
             continue;
         }
 
         const struct fuse_in_header* hdr =
             reinterpret_cast<const struct fuse_in_header*>(handler->request_buffer);
         if (hdr->len != (size_t)len) {
-            ERROR("[%d] malformed header: len=%zu, hdr->len=%u\n",
-                    handler->token, (size_t)len, hdr->len);
+            LOG(ERROR) << "[" << handler->token << "] malformed header: len=" << len
+                       << ", hdr->len=" << hdr->len;
             continue;
         }
 
@@ -1456,7 +1462,7 @@
 
         if (res != NO_STATUS) {
             if (res) {
-                TRACE("[%d] ERROR %d\n", handler->token, res);
+                DLOG(INFO) << "[" << handler->token << "] ERROR " << res;
             }
             fuse_status(fuse, unique, res);
         }
diff --git a/sdcard/fuse.h b/sdcard/fuse.h
index 9dafa79..9ccd21d 100644
--- a/sdcard/fuse.h
+++ b/sdcard/fuse.h
@@ -35,7 +35,6 @@
 
 #include <android-base/logging.h>
 #include <cutils/fs.h>
-#include <cutils/log.h>
 #include <cutils/multiuser.h>
 #include <packagelistparser/packagelistparser.h>
 
@@ -44,10 +43,8 @@
 #define FUSE_TRACE 0
 
 #if FUSE_TRACE
-#define TRACE(x...) ALOGD(x)
 static constexpr bool kEnableDLog = true;
 #else  // FUSE_TRACE == 0
-#define TRACE(x...) do {} while (0)
 static constexpr bool kEnableDLog = false;
 #endif
 
@@ -55,8 +52,6 @@
 #define DLOG(x) \
     if (kEnableDLog) LOG(x)
 
-#define ERROR(x...) ALOGE(x)
-
 /* Maximum number of bytes to write in one request. */
 #define MAX_WRITE (256 * 1024)
 
diff --git a/sdcard/sdcard.cpp b/sdcard/sdcard.cpp
index 3d7bdc9..3481ec3 100644
--- a/sdcard/sdcard.cpp
+++ b/sdcard/sdcard.cpp
@@ -32,7 +32,6 @@
 #include <android-base/macros.h>
 
 #include <cutils/fs.h>
-#include <cutils/log.h>
 #include <cutils/multiuser.h>
 #include <packagelistparser/packagelistparser.h>
 
@@ -89,8 +88,7 @@
 
     global->package_to_appid->clear();
     bool rc = packagelist_parse(package_parse_callback, global);
-    TRACE("read_package_list: found %zu packages\n",
-            global->package_to_appid->size());
+    DLOG(INFO) << "read_package_list: found " << global->package_to_appid->size() << " packages";
 
     // Regenerate ownership details using newly loaded mapping.
     derive_permissions_recursive_locked(global->fuse_default, &global->root);
@@ -148,7 +146,7 @@
             int event_size;
             event = (struct inotify_event *) (event_buf + event_pos);
 
-            TRACE("inotify event: %08x\n", event->mask);
+            DLOG(INFO) << "inotify event: " << std::hex << event->mask << std::dec;
             if ((event->mask & IN_IGNORED) == IN_IGNORED) {
                 /* Previously watched file was deleted, probably due to move
                  * that swapped in new data; re-arm the watch and read. */