Merge changes from topic "libmeminfo"

* changes:
  meminfo: Add Smaps(), showmap and friends.
  libmeminfo: Add SmapsRollup
  meminfo: Add ReadVmallocInfo()
diff --git a/adb/Android.bp b/adb/Android.bp
index 6234af1..36bfad4 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -355,6 +355,7 @@
     compile_multilib: "both",
 
     srcs: [
+        "daemon/abb_service.cpp",
         "daemon/file_sync_service.cpp",
         "daemon/framebuffer_service.cpp",
         "daemon/mdns.cpp",
@@ -391,6 +392,14 @@
         "libmdnssd",
         "libselinux",
     ],
+
+    target: {
+        recovery: {
+            exclude_srcs: [
+                "daemon/abb_service.cpp",
+            ],
+        },
+    },
 }
 
 cc_library {
@@ -455,6 +464,40 @@
     ],
 }
 
+cc_binary {
+    name: "abb",
+
+    defaults: ["adb_defaults"],
+    recovery_available: false,
+
+    srcs: [
+        "daemon/abb.cpp",
+    ],
+
+    cflags: [
+        "-D_GNU_SOURCE",
+        "-Wno-deprecated-declarations",
+    ],
+
+    strip: {
+        keep_symbols: true,
+    },
+
+    static_libs: [
+        "libadbd_core",
+        "libadbd_services",
+        "libcmd",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "liblog",
+        "libutils",
+        "libselinux",
+    ],
+}
+
 cc_test {
     name: "adbd_test",
     defaults: ["adb_defaults"],
diff --git a/adb/adb.h b/adb/adb.h
index 47ea0e8..d79cd2d 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -153,6 +153,10 @@
 #endif
 
 #if !ADB_HOST
+unique_fd execute_binder_command(std::string_view command);
+#endif
+
+#if !ADB_HOST
 int init_jdwp(void);
 asocket* create_jdwp_service_socket();
 asocket* create_jdwp_tracker_service_socket();
@@ -202,6 +206,9 @@
 
 #define CHUNK_SIZE (64 * 1024)
 
+// Argument delimeter for adb abb command.
+#define ABB_ARG_DELIMETER ('\0')
+
 #if !ADB_HOST
 #define USB_FFS_ADB_PATH "/dev/usb-ffs/adb/"
 #define USB_FFS_ADB_EP(x) USB_FFS_ADB_PATH #x
diff --git a/adb/adb_io.cpp b/adb/adb_io.cpp
index e6fefda..605d27d 100644
--- a/adb/adb_io.cpp
+++ b/adb/adb_io.cpp
@@ -20,6 +20,11 @@
 
 #include <unistd.h>
 
+#if !ADB_HOST
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif
+
 #include <thread>
 
 #include <android-base/stringprintf.h>
@@ -182,3 +187,79 @@
         return false;
     }
 }
+
+#if defined(__linux__)
+bool SendFileDescriptor(int socket_fd, int fd) {
+    struct msghdr msg;
+    struct iovec iov;
+    char dummy = '!';
+    union {
+        cmsghdr cm;
+        char buffer[CMSG_SPACE(sizeof(int))];
+    } cm_un;
+
+    iov.iov_base = &dummy;
+    iov.iov_len = 1;
+    msg.msg_name = nullptr;
+    msg.msg_namelen = 0;
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+    msg.msg_flags = 0;
+    msg.msg_control = cm_un.buffer;
+    msg.msg_controllen = sizeof(cm_un.buffer);
+
+    cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
+    cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+    cmsg->cmsg_level = SOL_SOCKET;
+    cmsg->cmsg_type = SCM_RIGHTS;
+    ((int*)CMSG_DATA(cmsg))[0] = fd;
+
+    int ret = TEMP_FAILURE_RETRY(sendmsg(socket_fd, &msg, 0));
+    if (ret < 0) {
+        D("sending file descriptor via socket %d failed: %s", socket_fd, strerror(errno));
+        return false;
+    }
+
+    D("sent file descriptor %d to via socket %d", fd, socket_fd);
+    return true;
+}
+
+bool ReceiveFileDescriptor(int socket_fd, unique_fd* fd, std::string* error) {
+    char dummy = '!';
+    union {
+        cmsghdr cm;
+        char buffer[CMSG_SPACE(sizeof(int))];
+    } cm_un;
+
+    iovec iov;
+    iov.iov_base = &dummy;
+    iov.iov_len = 1;
+
+    msghdr msg;
+    msg.msg_name = nullptr;
+    msg.msg_namelen = 0;
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+    msg.msg_flags = 0;
+    msg.msg_control = cm_un.buffer;
+    msg.msg_controllen = sizeof(cm_un.buffer);
+
+    cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
+    cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+    cmsg->cmsg_level = SOL_SOCKET;
+    cmsg->cmsg_type = SCM_RIGHTS;
+    ((int*)(CMSG_DATA(cmsg)))[0] = -1;
+
+    int rc = TEMP_FAILURE_RETRY(recvmsg(socket_fd, &msg, 0));
+    if (rc <= 0) {
+        *error = perror_str("receiving file descriptor via socket failed");
+        D("receiving file descriptor via socket %d failed: %s", socket_fd, strerror(errno));
+        return false;
+    }
+
+    fd->reset(((int*)(CMSG_DATA(cmsg)))[0]);
+    D("received file descriptor %d to via socket %d", fd->get(), socket_fd);
+
+    return true;
+}
+#endif
diff --git a/adb/adb_io.h b/adb/adb_io.h
index aa550af..2ccaa32 100644
--- a/adb/adb_io.h
+++ b/adb/adb_io.h
@@ -21,6 +21,8 @@
 
 #include <string>
 
+#include "adb_unique_fd.h"
+
 // Sends the protocol "OKAY" message.
 bool SendOkay(int fd);
 
@@ -73,4 +75,12 @@
 // Same as above, but formats the string to send.
 bool WriteFdFmt(int fd, const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3)));
 
+#if !ADB_HOST
+// Sends an FD via Unix domain socket.
+bool SendFileDescriptor(int socket_fd, int fd);
+
+// Receives an FD via Unix domain socket.
+bool ReceiveFileDescriptor(int socket_fd, unique_fd* fd, std::string* error);
+#endif
+
 #endif /* ADB_IO_H */
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 8676214..ce51b1c 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -579,12 +579,8 @@
 //
 // On success returns the remote exit code if |use_shell_protocol| is true,
 // 0 otherwise. On failure returns 1.
-static int RemoteShell(bool use_shell_protocol, const std::string& type_arg,
-                       char escape_char,
-                       const std::string& command) {
-    std::string service_string = ShellServiceString(use_shell_protocol,
-                                                    type_arg, command);
-
+static int RemoteShell(bool use_shell_protocol, const std::string& type_arg, char escape_char,
+                       bool empty_command, const std::string& service_string) {
     // Old devices can't handle a service string that's longer than MAX_PAYLOAD_V1.
     // Use |use_shell_protocol| to determine whether to allow a command longer than that.
     if (service_string.size() > MAX_PAYLOAD_V1 && !use_shell_protocol) {
@@ -595,8 +591,7 @@
     // Make local stdin raw if the device allocates a PTY, which happens if:
     //   1. We are explicitly asking for a PTY shell, or
     //   2. We don't specify shell type and are starting an interactive session.
-    bool raw_stdin = (type_arg == kShellServiceArgPty ||
-                      (type_arg.empty() && command.empty()));
+    bool raw_stdin = (type_arg == kShellServiceArgPty || (type_arg.empty() && empty_command));
 
     std::string error;
     int fd = adb_connect(service_string, &error);
@@ -756,7 +751,29 @@
         command = android::base::Join(std::vector<const char*>(argv + optind, argv + argc), ' ');
     }
 
-    return RemoteShell(use_shell_protocol, shell_type_arg, escape_char, command);
+    std::string service_string = ShellServiceString(use_shell_protocol, shell_type_arg, command);
+    return RemoteShell(use_shell_protocol, shell_type_arg, escape_char, command.empty(),
+                       service_string);
+}
+
+static int adb_abb(int argc, const char** argv) {
+    // Defaults.
+    constexpr char escape_char = '~';  // -e
+    constexpr bool use_shell_protocol = true;
+    constexpr auto shell_type_arg = kShellServiceArgRaw;
+    constexpr bool empty_command = false;
+
+    std::string service_string("abb:");
+    for (auto i = optind; i < argc; ++i) {
+        service_string.append(argv[i]);
+        service_string.push_back(ABB_ARG_DELIMETER);
+    }
+
+    D("abb -e 0x%x [%*.s]\n", escape_char, static_cast<int>(service_string.size()),
+      service_string.data());
+
+    return RemoteShell(use_shell_protocol, shell_type_arg, escape_char, empty_command,
+                       service_string);
 }
 
 static int adb_sideload_legacy(const char* filename, int in_fd, int size) {
@@ -1546,14 +1563,13 @@
         std::string query = android::base::StringPrintf("host:disconnect:%s",
                                                         (argc == 2) ? argv[1] : "");
         return adb_query_command(query);
-    }
-    else if (!strcmp(argv[0], "emu")) {
+    } else if (!strcmp(argv[0], "abb")) {
+        return adb_abb(argc, argv);
+    } else if (!strcmp(argv[0], "emu")) {
         return adb_send_emulator_command(argc, argv, serial);
-    }
-    else if (!strcmp(argv[0], "shell")) {
+    } else if (!strcmp(argv[0], "shell")) {
         return adb_shell(argc, argv);
-    }
-    else if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {
+    } else if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {
         int exec_in = !strcmp(argv[0], "exec-in");
 
         if (argc < 2) error_exit("usage: adb %s command", argv[0]);
@@ -1581,11 +1597,9 @@
 
         adb_close(fd);
         return 0;
-    }
-    else if (!strcmp(argv[0], "kill-server")) {
+    } else if (!strcmp(argv[0], "kill-server")) {
         return adb_kill_server() ? 0 : 1;
-    }
-    else if (!strcmp(argv[0], "sideload")) {
+    } else if (!strcmp(argv[0], "sideload")) {
         if (argc != 2) error_exit("sideload requires an argument");
         if (adb_sideload_host(argv[1])) {
             return 1;
@@ -1695,8 +1709,7 @@
     else if (!strcmp(argv[0], "ls")) {
         if (argc != 2) error_exit("ls requires an argument");
         return do_sync_ls(argv[1]) ? 0 : 1;
-    }
-    else if (!strcmp(argv[0], "push")) {
+    } else if (!strcmp(argv[0], "push")) {
         bool copy_attrs = false;
         bool sync = false;
         std::vector<const char*> srcs;
@@ -1705,8 +1718,7 @@
         parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, &copy_attrs, &sync);
         if (srcs.empty() || !dst) error_exit("push requires an argument");
         return do_sync_push(srcs, dst, sync) ? 0 : 1;
-    }
-    else if (!strcmp(argv[0], "pull")) {
+    } else if (!strcmp(argv[0], "pull")) {
         bool copy_attrs = false;
         std::vector<const char*> srcs;
         const char* dst = ".";
@@ -1714,20 +1726,16 @@
         parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, &copy_attrs, nullptr);
         if (srcs.empty()) error_exit("pull requires an argument");
         return do_sync_pull(srcs, dst, copy_attrs) ? 0 : 1;
-    }
-    else if (!strcmp(argv[0], "install")) {
+    } else if (!strcmp(argv[0], "install")) {
         if (argc < 2) error_exit("install requires an argument");
         return install_app(argc, argv);
-    }
-    else if (!strcmp(argv[0], "install-multiple")) {
+    } else if (!strcmp(argv[0], "install-multiple")) {
         if (argc < 2) error_exit("install-multiple requires an argument");
         return install_multiple_app(argc, argv);
-    }
-    else if (!strcmp(argv[0], "uninstall")) {
+    } else if (!strcmp(argv[0], "uninstall")) {
         if (argc < 2) error_exit("uninstall requires an argument");
         return uninstall_app(argc, argv);
-    }
-    else if (!strcmp(argv[0], "sync")) {
+    } else if (!strcmp(argv[0], "sync")) {
         std::string src;
         bool list_only = false;
         if (argc < 2) {
@@ -1757,34 +1765,28 @@
         return 0;
     }
     /* passthrough commands */
-    else if (!strcmp(argv[0],"get-state") ||
-        !strcmp(argv[0],"get-serialno") ||
-        !strcmp(argv[0],"get-devpath"))
-    {
+    else if (!strcmp(argv[0], "get-state") || !strcmp(argv[0], "get-serialno") ||
+             !strcmp(argv[0], "get-devpath")) {
         return adb_query_command(format_host_command(argv[0]));
     }
     /* other commands */
-    else if (!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat") || !strcmp(argv[0],"longcat")) {
+    else if (!strcmp(argv[0], "logcat") || !strcmp(argv[0], "lolcat") ||
+             !strcmp(argv[0], "longcat")) {
         return logcat(argc, argv);
-    }
-    else if (!strcmp(argv[0],"ppp")) {
+    } else if (!strcmp(argv[0], "ppp")) {
         return ppp(argc, argv);
-    }
-    else if (!strcmp(argv[0], "start-server")) {
+    } else if (!strcmp(argv[0], "start-server")) {
         std::string error;
         const int result = adb_connect("host:start-server", &error);
         if (result < 0) {
             fprintf(stderr, "error: %s\n", error.c_str());
         }
         return result;
-    }
-    else if (!strcmp(argv[0], "backup")) {
+    } else if (!strcmp(argv[0], "backup")) {
         return backup(argc, argv);
-    }
-    else if (!strcmp(argv[0], "restore")) {
+    } else if (!strcmp(argv[0], "restore")) {
         return restore(argc, argv);
-    }
-    else if (!strcmp(argv[0], "keygen")) {
+    } else if (!strcmp(argv[0], "keygen")) {
         if (argc != 2) error_exit("keygen requires an argument");
         // Always print key generation information for keygen command.
         adb_trace_enable(AUTH);
diff --git a/adb/daemon/abb.cpp b/adb/daemon/abb.cpp
new file mode 100644
index 0000000..f69babe
--- /dev/null
+++ b/adb/daemon/abb.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "adb.h"
+#include "adb_io.h"
+#include "shell_service.h"
+
+#include "cmd.h"
+
+#include <sys/wait.h>
+
+namespace {
+
+class AdbFdTextOutput : public android::TextOutput {
+  public:
+    explicit AdbFdTextOutput(int fd) : mFD(fd) {}
+
+  private:
+    android::status_t print(const char* txt, size_t len) override {
+        return WriteFdExactly(mFD, txt, len) ? android::OK : -errno;
+    }
+    void moveIndent(int delta) override { /*not implemented*/
+    }
+
+    void pushBundle() override { /*not implemented*/
+    }
+    void popBundle() override { /*not implemented*/
+    }
+
+  private:
+    int mFD;
+};
+
+std::vector<std::string_view> parseCmdArgs(std::string_view args) {
+    std::vector<std::string_view> argv;
+
+    char delim = ABB_ARG_DELIMETER;
+    size_t size = args.size();
+    size_t base = 0;
+    while (base < size) {
+        size_t found;
+        for (found = base; found < size && args[found] && args[found] != delim; ++found)
+            ;
+        if (found > base) {
+            argv.emplace_back(args.substr(base, found - base));
+        }
+        base = found + 1;
+    }
+
+    return argv;
+}
+
+}  // namespace
+
+static int execCmd(std::string_view args, int in, int out, int err) {
+    AdbFdTextOutput oin(out);
+    AdbFdTextOutput oerr(err);
+    return cmdMain(parseCmdArgs(args), oin, oerr, in, out, err, RunMode::kLibrary);
+}
+
+int main(int argc, char* const argv[]) {
+    signal(SIGPIPE, SIG_IGN);
+
+    int fd = STDIN_FILENO;
+    std::string data;
+    while (true) {
+        std::string error;
+        if (!ReadProtocolString(fd, &data, &error)) {
+            PLOG(ERROR) << "Failed to read message: " << error;
+            break;
+        }
+
+        auto result = StartCommandInProcess(std::move(data), &execCmd);
+        if (!SendFileDescriptor(fd, result)) {
+            PLOG(ERROR) << "Failed to send an inprocess fd for command: " << data;
+            break;
+        }
+    }
+}
diff --git a/adb/daemon/abb_service.cpp b/adb/daemon/abb_service.cpp
new file mode 100644
index 0000000..817aea1
--- /dev/null
+++ b/adb/daemon/abb_service.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "adb.h"
+#include "adb_io.h"
+#include "adb_unique_fd.h"
+#include "adb_utils.h"
+#include "shell_service.h"
+
+namespace {
+
+struct AbbProcess;
+static auto& abbp = *new std::unique_ptr<AbbProcess>(std::make_unique<AbbProcess>());
+
+struct AbbProcess {
+    unique_fd sendCommand(std::string_view command);
+
+  private:
+    static unique_fd startAbbProcess(unique_fd* error_fd);
+
+    static constexpr auto kRetries = 2;
+    static constexpr auto kErrorProtocol = SubprocessProtocol::kShell;
+
+    std::mutex locker_;
+    unique_fd socket_fd_;
+};
+
+unique_fd AbbProcess::sendCommand(std::string_view command) {
+    std::unique_lock lock{locker_};
+
+    for (int i = 0; i < kRetries; ++i) {
+        unique_fd error_fd;
+        if (socket_fd_ == -1) {
+            socket_fd_ = startAbbProcess(&error_fd);
+        }
+        if (socket_fd_ == -1) {
+            LOG(ERROR) << "failed to start abb process";
+            return error_fd;
+        }
+
+        if (!SendProtocolString(socket_fd_, std::string(command))) {
+            PLOG(ERROR) << "failed to send command to abb";
+            socket_fd_.reset();
+            continue;
+        }
+
+        unique_fd fd;
+        std::string error;
+        if (!ReceiveFileDescriptor(socket_fd_, &fd, &error)) {
+            LOG(ERROR) << "failed to receive FD from abb: " << error;
+            socket_fd_.reset();
+            continue;
+        }
+
+        return fd;
+    }
+
+    LOG(ERROR) << "abb is unavailable";
+    socket_fd_.reset();
+    return ReportError(kErrorProtocol, "abb is unavailable");
+}
+
+unique_fd AbbProcess::startAbbProcess(unique_fd* error_fd) {
+    constexpr auto abb_process_type = SubprocessType::kRaw;
+    constexpr auto abb_protocol = SubprocessProtocol::kNone;
+    constexpr auto make_pty_raw = false;
+    return StartSubprocess("abb", "dumb", abb_process_type, abb_protocol, make_pty_raw,
+                           kErrorProtocol, error_fd);
+}
+
+}  // namespace
+
+unique_fd execute_binder_command(std::string_view command) {
+    return abbp->sendCommand(command);
+}
diff --git a/adb/daemon/jdwp_service.cpp b/adb/daemon/jdwp_service.cpp
index 1363976..f02cc13 100644
--- a/adb/daemon/jdwp_service.cpp
+++ b/adb/daemon/jdwp_service.cpp
@@ -237,30 +237,7 @@
         CHECK(!proc->out_fds.empty());
 
         int fd = proc->out_fds.back().get();
-        struct cmsghdr* cmsg;
-        struct msghdr msg;
-        struct iovec iov;
-        char dummy = '!';
-        char buffer[sizeof(struct cmsghdr) + sizeof(int)];
-
-        iov.iov_base = &dummy;
-        iov.iov_len = 1;
-        msg.msg_name = nullptr;
-        msg.msg_namelen = 0;
-        msg.msg_iov = &iov;
-        msg.msg_iovlen = 1;
-        msg.msg_flags = 0;
-        msg.msg_control = buffer;
-        msg.msg_controllen = sizeof(buffer);
-
-        cmsg = CMSG_FIRSTHDR(&msg);
-        cmsg->cmsg_len = msg.msg_controllen;
-        cmsg->cmsg_level = SOL_SOCKET;
-        cmsg->cmsg_type = SCM_RIGHTS;
-        ((int*)CMSG_DATA(cmsg))[0] = fd;
-
-        int ret = TEMP_FAILURE_RETRY(sendmsg(socket, &msg, 0));
-        if (ret < 0) {
+        if (!SendFileDescriptor(socket, fd)) {
             D("sending new file descriptor to JDWP %d failed: %s", proc->pid, strerror(errno));
             goto CloseProcess;
         }
diff --git a/adb/daemon/services.cpp b/adb/daemon/services.cpp
index 3693997..5ae210f 100644
--- a/adb/daemon/services.cpp
+++ b/adb/daemon/services.cpp
@@ -328,6 +328,13 @@
 }
 
 unique_fd daemon_service_to_fd(std::string_view name, atransport* transport) {
+#ifndef __ANDROID_RECOVERY__
+    if (name.starts_with("abb:")) {
+        name.remove_prefix(strlen("abb:"));
+        return execute_binder_command(name);
+    }
+#endif
+
     if (name.starts_with("dev:")) {
         name.remove_prefix(strlen("dev:"));
         return unique_fd{unix_open(name, O_RDWR | O_CLOEXEC)};
diff --git a/adb/daemon/shell_service.cpp b/adb/daemon/shell_service.cpp
index 595d5c6..455595f 100644
--- a/adb/daemon/shell_service.cpp
+++ b/adb/daemon/shell_service.cpp
@@ -141,7 +141,7 @@
 class Subprocess {
   public:
     Subprocess(std::string command, const char* terminal_type, SubprocessType type,
-               SubprocessProtocol protocol);
+               SubprocessProtocol protocol, bool make_pty_raw);
     ~Subprocess();
 
     const std::string& command() const { return command_; }
@@ -154,6 +154,10 @@
     // and exec's the child. Returns false and sets error on failure.
     bool ForkAndExec(std::string* _Nonnull error);
 
+    // Sets up FDs, starts a thread executing command and the manager thread,
+    // Returns false and sets error on failure.
+    bool ExecInProcess(Command command, std::string* _Nonnull error);
+
     // Start the subprocess manager thread. Consumes the subprocess, regardless of success.
     // Returns false and sets error on failure.
     static bool StartThread(std::unique_ptr<Subprocess> subprocess,
@@ -177,9 +181,9 @@
 
     const std::string command_;
     const std::string terminal_type_;
-    bool make_pty_raw_ = false;
     SubprocessType type_;
     SubprocessProtocol protocol_;
+    bool make_pty_raw_;
     pid_t pid_ = -1;
     unique_fd local_socket_sfd_;
 
@@ -192,24 +196,12 @@
 };
 
 Subprocess::Subprocess(std::string command, const char* terminal_type, SubprocessType type,
-                       SubprocessProtocol protocol)
+                       SubprocessProtocol protocol, bool make_pty_raw)
     : command_(std::move(command)),
       terminal_type_(terminal_type ? terminal_type : ""),
       type_(type),
-      protocol_(protocol) {
-    // If we aren't using the shell protocol we must allocate a PTY to properly close the
-    // subprocess. PTYs automatically send SIGHUP to the slave-side process when the master side
-    // of the PTY closes, which we rely on. If we use a raw pipe, processes that don't read/write,
-    // e.g. screenrecord, will never notice the broken pipe and terminate.
-    // The shell protocol doesn't require a PTY because it's always monitoring the local socket FD
-    // with select() and will send SIGHUP manually to the child process.
-    if (protocol_ == SubprocessProtocol::kNone && type_ == SubprocessType::kRaw) {
-        // Disable PTY input/output processing since the client is expecting raw data.
-        D("Can't create raw subprocess without shell protocol, using PTY in raw mode instead");
-        type_ = SubprocessType::kPty;
-        make_pty_raw_ = true;
-    }
-}
+      protocol_(protocol),
+      make_pty_raw_(make_pty_raw) {}
 
 Subprocess::~Subprocess() {
     WaitForExit();
@@ -430,6 +422,67 @@
     return true;
 }
 
+bool Subprocess::ExecInProcess(Command command, std::string* _Nonnull error) {
+    unique_fd child_stdinout_sfd, child_stderr_sfd;
+
+    CHECK(type_ == SubprocessType::kRaw);
+    CHECK(protocol_ == SubprocessProtocol::kShell);
+
+    __android_log_security_bswrite(SEC_TAG_ADB_SHELL_CMD, command_.c_str());
+
+    if (!CreateSocketpair(&stdinout_sfd_, &child_stdinout_sfd)) {
+        *error = android::base::StringPrintf("failed to create socketpair for stdin/out: %s",
+                                             strerror(errno));
+        return false;
+    }
+    // Raw subprocess + shell protocol allows for splitting stderr.
+    if (!CreateSocketpair(&stderr_sfd_, &child_stderr_sfd)) {
+        *error = android::base::StringPrintf("failed to create socketpair for stderr: %s",
+                                             strerror(errno));
+        return false;
+    }
+
+    D("execinprocess: stdin/stdout FD = %d, stderr FD = %d", stdinout_sfd_.get(),
+      stderr_sfd_.get());
+
+    // Required for shell protocol: create another socketpair to intercept data.
+    if (!CreateSocketpair(&protocol_sfd_, &local_socket_sfd_)) {
+        *error = android::base::StringPrintf("failed to create socketpair to intercept data: %s",
+                                             strerror(errno));
+        return false;
+    }
+    D("protocol FD = %d", protocol_sfd_.get());
+
+    input_ = std::make_unique<ShellProtocol>(protocol_sfd_);
+    output_ = std::make_unique<ShellProtocol>(protocol_sfd_);
+    if (!input_ || !output_) {
+        *error = "failed to allocate shell protocol objects";
+        return false;
+    }
+
+    // Don't let reads/writes to the subprocess block our thread. This isn't
+    // likely but could happen under unusual circumstances, such as if we
+    // write a ton of data to stdin but the subprocess never reads it and
+    // the pipe fills up.
+    for (int fd : {stdinout_sfd_.get(), stderr_sfd_.get()}) {
+        if (fd >= 0) {
+            if (!set_file_block_mode(fd, false)) {
+                *error = android::base::StringPrintf("failed to set non-blocking mode for fd %d",
+                                                     fd);
+                return false;
+            }
+        }
+    }
+
+    std::thread([inout_sfd = std::move(child_stdinout_sfd), err_sfd = std::move(child_stderr_sfd),
+                 command = std::move(command),
+                 args = command_]() { command(args, inout_sfd, inout_sfd, err_sfd); })
+            .detach();
+
+    D("execinprocess: completed");
+    return true;
+}
+
 bool Subprocess::StartThread(std::unique_ptr<Subprocess> subprocess, std::string* error) {
     Subprocess* raw = subprocess.release();
     std::thread(ThreadHandler, raw).detach();
@@ -512,7 +565,9 @@
                 // needed (e.g. SIGINT), pass those through the shell protocol
                 // and only fall back on this for unexpected closures.
                 D("protocol FD died, sending SIGHUP to pid %d", pid_);
-                kill(pid_, SIGHUP);
+                if (pid_ != -1) {
+                    kill(pid_, SIGHUP);
+                }
 
                 // We also need to close the pipes connected to the child process
                 // so that if it ignores SIGHUP and continues to write data it
@@ -682,7 +737,7 @@
     int exit_code = 1;
 
     D("waiting for pid %d", pid_);
-    while (true) {
+    while (pid_ != -1) {
         int status;
         if (pid_ == waitpid(pid_, &status, 0)) {
             D("post waitpid (pid=%d) status=%04x", pid_, status);
@@ -716,7 +771,7 @@
 }  // namespace
 
 // Create a pipe containing the error.
-static unique_fd ReportError(SubprocessProtocol protocol, const std::string& message) {
+unique_fd ReportError(SubprocessProtocol protocol, const std::string& message) {
     unique_fd read, write;
     if (!Pipe(&read, &write)) {
         PLOG(ERROR) << "failed to create pipe to report error";
@@ -747,20 +802,49 @@
 
 unique_fd StartSubprocess(std::string name, const char* terminal_type, SubprocessType type,
                           SubprocessProtocol protocol) {
+    // If we aren't using the shell protocol we must allocate a PTY to properly close the
+    // subprocess. PTYs automatically send SIGHUP to the slave-side process when the master side
+    // of the PTY closes, which we rely on. If we use a raw pipe, processes that don't read/write,
+    // e.g. screenrecord, will never notice the broken pipe and terminate.
+    // The shell protocol doesn't require a PTY because it's always monitoring the local socket FD
+    // with select() and will send SIGHUP manually to the child process.
+    bool make_pty_raw = false;
+    if (protocol == SubprocessProtocol::kNone && type == SubprocessType::kRaw) {
+        // Disable PTY input/output processing since the client is expecting raw data.
+        D("Can't create raw subprocess without shell protocol, using PTY in raw mode instead");
+        type = SubprocessType::kPty;
+        make_pty_raw = true;
+    }
+
+    unique_fd error_fd;
+    unique_fd fd = StartSubprocess(std::move(name), terminal_type, type, protocol, make_pty_raw,
+                                   protocol, &error_fd);
+    if (fd == -1) {
+        return error_fd;
+    }
+    return fd;
+}
+
+unique_fd StartSubprocess(std::string name, const char* terminal_type, SubprocessType type,
+                          SubprocessProtocol protocol, bool make_pty_raw,
+                          SubprocessProtocol error_protocol, unique_fd* error_fd) {
     D("starting %s subprocess (protocol=%s, TERM=%s): '%s'",
       type == SubprocessType::kRaw ? "raw" : "PTY",
       protocol == SubprocessProtocol::kNone ? "none" : "shell", terminal_type, name.c_str());
 
-    auto subprocess = std::make_unique<Subprocess>(std::move(name), terminal_type, type, protocol);
+    auto subprocess = std::make_unique<Subprocess>(std::move(name), terminal_type, type, protocol,
+                                                   make_pty_raw);
     if (!subprocess) {
         LOG(ERROR) << "failed to allocate new subprocess";
-        return ReportError(protocol, "failed to allocate new subprocess");
+        *error_fd = ReportError(error_protocol, "failed to allocate new subprocess");
+        return {};
     }
 
     std::string error;
     if (!subprocess->ForkAndExec(&error)) {
         LOG(ERROR) << "failed to start subprocess: " << error;
-        return ReportError(protocol, error);
+        *error_fd = ReportError(error_protocol, error);
+        return {};
     }
 
     unique_fd local_socket(subprocess->ReleaseLocalSocket());
@@ -769,6 +853,40 @@
 
     if (!Subprocess::StartThread(std::move(subprocess), &error)) {
         LOG(ERROR) << "failed to start subprocess management thread: " << error;
+        *error_fd = ReportError(error_protocol, error);
+        return {};
+    }
+
+    return local_socket;
+}
+
+unique_fd StartCommandInProcess(std::string name, Command command) {
+    LOG(INFO) << "StartCommandInProcess(" << dump_hex(name.data(), name.size()) << ")";
+
+    constexpr auto terminal_type = "";
+    constexpr auto type = SubprocessType::kRaw;
+    constexpr auto protocol = SubprocessProtocol::kShell;
+    constexpr auto make_pty_raw = false;
+
+    auto subprocess = std::make_unique<Subprocess>(std::move(name), terminal_type, type, protocol,
+                                                   make_pty_raw);
+    if (!subprocess) {
+        LOG(ERROR) << "failed to allocate new subprocess";
+        return ReportError(protocol, "failed to allocate new subprocess");
+    }
+
+    std::string error;
+    if (!subprocess->ExecInProcess(std::move(command), &error)) {
+        LOG(ERROR) << "failed to start subprocess: " << error;
+        return ReportError(protocol, error);
+    }
+
+    unique_fd local_socket(subprocess->ReleaseLocalSocket());
+    D("inprocess creation successful: local_socket_fd=%d, pid=%d", local_socket.get(),
+      subprocess->pid());
+
+    if (!Subprocess::StartThread(std::move(subprocess), &error)) {
+        LOG(ERROR) << "failed to start inprocess management thread: " << error;
         return ReportError(protocol, error);
     }
 
diff --git a/adb/daemon/shell_service.h b/adb/daemon/shell_service.h
index 421d61f..fc66377 100644
--- a/adb/daemon/shell_service.h
+++ b/adb/daemon/shell_service.h
@@ -20,6 +20,8 @@
 
 #include "adb_unique_fd.h"
 
+#include <string_view>
+
 enum class SubprocessType {
     kPty,
     kRaw,
@@ -36,3 +38,18 @@
 // Returns an open FD connected to the subprocess or -1 on failure.
 unique_fd StartSubprocess(std::string name, const char* terminal_type, SubprocessType type,
                           SubprocessProtocol protocol);
+
+// The same as above but with more fined grained control and custom error handling.
+unique_fd StartSubprocess(std::string name, const char* terminal_type, SubprocessType type,
+                          SubprocessProtocol protocol, bool make_pty_raw,
+                          SubprocessProtocol error_protocol, unique_fd* error_fd);
+
+// Executes |command| in a separate thread.
+// Sets up in/out and error streams to emulate shell-like behavior.
+//
+// Returns an open FD connected to the thread or -1 on failure.
+using Command = int(std::string_view args, int in, int out, int err);
+unique_fd StartCommandInProcess(std::string name, Command command);
+
+// Create a pipe containing the error.
+unique_fd ReportError(SubprocessProtocol protocol, const std::string& message);
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 5167481..10f52f4 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -150,6 +150,7 @@
     shared_libs: [
         "libbase",
         "libcutils",
+        "libprocinfo",
     ],
 
     export_header_lib_headers: ["libdebuggerd_common_headers"],
diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp
index 77f3515..610b96b 100644
--- a/debuggerd/client/debuggerd_client.cpp
+++ b/debuggerd/client/debuggerd_client.cpp
@@ -33,6 +33,7 @@
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <cutils/sockets.h>
+#include <procinfo/process.h>
 
 #include "debuggerd/handler.h"
 #include "protocol.h"
@@ -62,8 +63,20 @@
   tv->tv_usec = static_cast<long>(microseconds.count());
 }
 
-bool debuggerd_trigger_dump(pid_t pid, DebuggerdDumpType dump_type, unsigned int timeout_ms,
+bool debuggerd_trigger_dump(pid_t tid, DebuggerdDumpType dump_type, unsigned int timeout_ms,
                             unique_fd output_fd) {
+  pid_t pid = tid;
+  if (dump_type == kDebuggerdJavaBacktrace) {
+    // Java dumps always get sent to the tgid, so we need to resolve our tid to a tgid.
+    android::procinfo::ProcessInfo procinfo;
+    std::string error;
+    if (!android::procinfo::GetProcessInfo(tid, &procinfo, &error)) {
+      LOG(ERROR) << "libdebugged_client: failed to get process info: " << error;
+      return false;
+    }
+    pid = procinfo.pid;
+  }
+
   LOG(INFO) << "libdebuggerd_client: started dumping process " << pid;
   unique_fd sockfd;
   const auto end = std::chrono::steady_clock::now() + std::chrono::milliseconds(timeout_ms);
@@ -162,7 +175,7 @@
     return false;
   }
 
-  if (!send_signal(pid, dump_type)) {
+  if (!send_signal(tid, dump_type)) {
     return false;
   }
 
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 824511e..1616a61 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -92,6 +92,7 @@
     name: "libfstab",
     vendor_available: true,
     recovery_available: true,
+    host_supported: true,
     defaults: ["fs_mgr_defaults"],
     srcs: [
         "fs_mgr_fstab.cpp",
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
index 3f075ef..45cbff3 100644
--- a/fs_mgr/fs_mgr_dm_linear.cpp
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -168,6 +168,19 @@
     return true;
 }
 
+bool CreateLogicalPartition(const std::string& block_device, const LpMetadata& metadata,
+                            const std::string& partition_name, bool force_writable,
+                            const std::chrono::milliseconds& timeout_ms, std::string* path) {
+    for (const auto& partition : metadata.partitions) {
+        if (GetPartitionName(partition) == partition_name) {
+            return CreateLogicalPartition(metadata, partition, force_writable, timeout_ms,
+                                          block_device, path);
+        }
+    }
+    LERROR << "Could not find any partition with name: " << partition_name;
+    return false;
+}
+
 bool CreateLogicalPartition(const std::string& block_device, uint32_t metadata_slot,
                             const std::string& partition_name, bool force_writable,
                             const std::chrono::milliseconds& timeout_ms, std::string* path) {
@@ -176,14 +189,8 @@
         LOG(ERROR) << "Could not read partition table.";
         return true;
     }
-    for (const auto& partition : metadata->partitions) {
-        if (GetPartitionName(partition) == partition_name) {
-            return CreateLogicalPartition(*metadata.get(), partition, force_writable, timeout_ms,
-                                          block_device, path);
-        }
-    }
-    LERROR << "Could not find any partition with name: " << partition_name;
-    return false;
+    return CreateLogicalPartition(block_device, *metadata.get(), partition_name, force_writable,
+                                  timeout_ms, path);
 }
 
 bool DestroyLogicalPartition(const std::string& name, const std::chrono::milliseconds& timeout_ms) {
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index e0891eb..53b47be 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -209,17 +209,12 @@
 }
 
 static uint64_t parse_flags(char* flags, struct flag_list* fl, struct fs_mgr_flag_values* flag_vals,
-                            char* fs_options, int fs_options_len) {
+                            std::string* fs_options) {
     uint64_t f = 0;
     int i;
     char *p;
     char *savep;
 
-    /* initialize fs_options to the null string */
-    if (fs_options && (fs_options_len > 0)) {
-        fs_options[0] = '\0';
-    }
-
     p = strtok_r(flags, ",", &savep);
     while (p) {
         /* Look for the flag "p" in the flag list "fl"
@@ -356,26 +351,20 @@
 
         if (!fl[i].name) {
             if (fs_options) {
-                /* It's not a known flag, so it must be a filesystem specific
-                 * option.  Add it to fs_options if it was passed in.
-                 */
-                strlcat(fs_options, p, fs_options_len);
-                strlcat(fs_options, ",", fs_options_len);
+                // It's not a known flag, so it must be a filesystem specific
+                // option.  Add it to fs_options if it was passed in.
+                if (!fs_options->empty()) {
+                    fs_options->append(",");  // appends a comma if not the first
+                }
+                fs_options->append(p);
             } else {
-                /* fs_options was not passed in, so if the flag is unknown
-                 * it's an error.
-                 */
+                // fs_options was not passed in, so if the flag is unknown it's an error.
                 LERROR << "Warning: unknown flag " << p;
             }
         }
         p = strtok_r(NULL, ",", &savep);
     }
 
-    if (fs_options && fs_options[0]) {
-        /* remove the last trailing comma from the list of options */
-        fs_options[strlen(fs_options) - 1] = '\0';
-    }
-
     return f;
 }
 
@@ -513,8 +502,6 @@
     char *save_ptr, *p;
     Fstab fstab;
     struct fs_mgr_flag_values flag_vals;
-#define FS_OPTIONS_LEN 1024
-    char tmp_fs_options[FS_OPTIONS_LEN];
 
     while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
         /* if the last character is a newline, shorten the string by 1 byte */
@@ -555,13 +542,7 @@
             LERROR << "Error parsing mount_flags";
             goto err;
         }
-        tmp_fs_options[0] = '\0';
-        entry.flags = parse_flags(p, mount_flags, NULL, tmp_fs_options, FS_OPTIONS_LEN);
-
-        /* fs_options are optional */
-        if (tmp_fs_options[0]) {
-            entry.fs_options = tmp_fs_options;
-        }
+        entry.flags = parse_flags(p, mount_flags, nullptr, &entry.fs_options);
 
         // For /proc/mounts, ignore everything after mnt_freq and mnt_passno
         if (proc_mounts) {
@@ -570,7 +551,7 @@
             LERROR << "Error parsing fs_mgr_options";
             goto err;
         }
-        entry.fs_mgr_flags.val = parse_flags(p, fs_mgr_flags, &flag_vals, NULL, 0);
+        entry.fs_mgr_flags.val = parse_flags(p, fs_mgr_flags, &flag_vals, nullptr);
 
         entry.key_loc = std::move(flag_vals.key_loc);
         entry.key_dir = std::move(flag_vals.key_dir);
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 8bfcd81..7dae7f1 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -575,8 +575,14 @@
 }
 
 // Mount kScratchMountPoint
-bool fs_mgr_overlayfs_mount_scratch(const std::string& device_path, const std::string mnt_type) {
-    if (!fs_mgr_rw_access(device_path)) return false;
+bool fs_mgr_overlayfs_mount_scratch(const std::string& device_path, const std::string mnt_type,
+                                    bool readonly = false) {
+    if (readonly) {
+        if (!fs_mgr_access(device_path)) return false;
+    } else {
+        if (!fs_mgr_rw_access(device_path)) return false;
+    }
+
     if (setfscreatecon(kOverlayfsFileContext)) {
         PERROR << "setfscreatecon " << kOverlayfsFileContext;
     }
@@ -589,6 +595,7 @@
     entry.mount_point = kScratchMountPoint;
     entry.fs_type = mnt_type;
     entry.flags = MS_RELATIME;
+    if (readonly) entry.flags |= MS_RDONLY;
     auto save_errno = errno;
     auto mounted = fs_mgr_do_mount_one(entry) == 0;
     if (!mounted) {
@@ -751,8 +758,14 @@
     auto mnt_type = fs_mgr_overlayfs_scratch_mount_type();
     if (partition_exists) {
         if (fs_mgr_overlayfs_mount_scratch(scratch_device, mnt_type)) {
-            if (change) *change = true;
-            return true;
+            if (!fs_mgr_access(kScratchMountPoint + kOverlayTopDir) &&
+                !fs_mgr_filesystem_has_space(kScratchMountPoint)) {
+                // declare it useless, no overrides and no free space
+                fs_mgr_overlayfs_umount_scratch();
+            } else {
+                if (change) *change = true;
+                return true;
+            }
         }
         // partition existed, but was not initialized; fall through to make it.
         errno = 0;
@@ -800,11 +813,15 @@
             scratch_can_be_mounted = false;
             auto scratch_device = fs_mgr_overlayfs_scratch_device();
             if (fs_mgr_overlayfs_scratch_can_be_mounted(scratch_device) &&
-                fs_mgr_wait_for_file(scratch_device, 10s) &&
-                fs_mgr_overlayfs_mount_scratch(scratch_device,
-                                               fs_mgr_overlayfs_scratch_mount_type()) &&
-                !fs_mgr_access(kScratchMountPoint + kOverlayTopDir)) {
-                fs_mgr_overlayfs_umount_scratch();
+                fs_mgr_wait_for_file(scratch_device, 10s)) {
+                const auto mount_type = fs_mgr_overlayfs_scratch_mount_type();
+                if (fs_mgr_overlayfs_mount_scratch(scratch_device, mount_type,
+                                                   true /* readonly */)) {
+                    auto has_overlayfs_dir = fs_mgr_access(kScratchMountPoint + kOverlayTopDir);
+                    fs_mgr_overlayfs_umount_scratch();
+                    if (has_overlayfs_dir)
+                        fs_mgr_overlayfs_mount_scratch(scratch_device, mount_type);
+                }
             }
         }
         if (fs_mgr_overlayfs_mount(mount_point)) ret = true;
diff --git a/fs_mgr/fs_mgr_roots.cpp b/fs_mgr/fs_mgr_roots.cpp
index f44ff41..32a5d21 100644
--- a/fs_mgr/fs_mgr_roots.cpp
+++ b/fs_mgr/fs_mgr_roots.cpp
@@ -114,7 +114,7 @@
 
     const std::string mount_point = mount_pt.empty() ? rec->mount_point : mount_pt;
 
-    static const std::vector<std::string> supported_fs{"ext4", "squashfs", "vfat", "f2fs"};
+    static const std::vector<std::string> supported_fs{"ext4", "squashfs", "vfat", "f2fs", "none"};
     if (std::find(supported_fs.begin(), supported_fs.end(), rec->fs_type) == supported_fs.end()) {
         LERROR << "unknown fs_type \"" << rec->fs_type << "\" for " << mount_point;
         return false;
diff --git a/fs_mgr/include/fs_mgr_dm_linear.h b/fs_mgr/include/fs_mgr_dm_linear.h
index f065071..f33fc02 100644
--- a/fs_mgr/include/fs_mgr_dm_linear.h
+++ b/fs_mgr/include/fs_mgr_dm_linear.h
@@ -60,6 +60,12 @@
                             const std::string& partition_name, bool force_writable,
                             const std::chrono::milliseconds& timeout_ms, std::string* path);
 
+// Same as above, but with a given metadata object. Care should be taken that
+// the metadata represents a valid partition layout.
+bool CreateLogicalPartition(const std::string& block_device, const LpMetadata& metadata,
+                            const std::string& partition_name, bool force_writable,
+                            const std::chrono::milliseconds& timeout_ms, std::string* path);
+
 // Destroy the block device for a logical partition, by name. If |timeout_ms|
 // is non-zero, then this will block until the device path has been unlinked.
 bool DestroyLogicalPartition(const std::string& name, const std::chrono::milliseconds& timeout_ms);
diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp
index 90bce51..fc1aafb 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -18,6 +18,7 @@
     name: "libdm",
     defaults: ["fs_mgr_defaults"],
     recovery_available: true,
+    host_supported: true,
 
     export_include_dirs: ["include"],
 
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index d9786ad..c6a9e0b 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -349,7 +349,7 @@
     io->data_size = sizeof(*io);
     io->data_start = 0;
     if (!name.empty()) {
-        strlcpy(io->name, name.c_str(), sizeof(io->name));
+        snprintf(io->name, sizeof(io->name), "%s", name.c_str());
     }
 }
 
diff --git a/fs_mgr/libdm/dm_target.cpp b/fs_mgr/libdm/dm_target.cpp
index 7c18267..cb33eea 100644
--- a/fs_mgr/libdm/dm_target.cpp
+++ b/fs_mgr/libdm/dm_target.cpp
@@ -42,7 +42,7 @@
     struct dm_target_spec* spec = reinterpret_cast<struct dm_target_spec*>(&data[0]);
     spec->sector_start = start();
     spec->length = size();
-    strlcpy(spec->target_type, name().c_str(), sizeof(spec->target_type));
+    snprintf(spec->target_type, sizeof(spec->target_type), "%s", name().c_str());
     spec->next = (uint32_t)data.size();
     return data;
 }
diff --git a/fs_mgr/tests/Android.bp b/fs_mgr/tests/Android.bp
index 5497223..ea12e96 100644
--- a/fs_mgr/tests/Android.bp
+++ b/fs_mgr/tests/Android.bp
@@ -23,7 +23,9 @@
         "libfs_mgr",
         "libfstab",
     ],
-
+    data: [
+        "data/*",
+    ],
     srcs: [
         "fs_mgr_test.cpp",
     ],
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 9e211e3..160e076 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -49,7 +49,7 @@
 Returns: true if device is in adb mode" ]
 inAdb() {
   adb devices |
-    grep -v 'List of devices attached' |
+    grep -v -e 'List of devices attached' -e '^$' |
     if [ -n "${ANDROID_SERIAL}" ]; then
       grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
     else
@@ -61,7 +61,17 @@
 
 Returns: true if the command succeeded" ]
 adb_sh() {
-  adb shell "${@}"
+  args=
+  for i in ${@}; do
+    if [ X"${i}" != X"${i#\'}" ]; then
+      args="${args} ${i}"
+    elif [ X"${i}" != X"${i#* }" ]; then
+      args="${args} '${i}'"
+    else
+      args="${args} ${i}"
+    fi
+  done
+  adb shell ${args}
 }
 
 [ "USAGE: adb_date >/dev/stdout
@@ -92,7 +102,7 @@
 
 Returns: true if device is (likely) a debug build" ]
 isDebuggable() {
-  if inAdb && [ 1 -ne "`get_property ro.debuggable`" ]; then
+  if inAdb && [ 1 != "`get_property ro.debuggable`" ]; then
     false
   fi
 }
@@ -363,8 +373,12 @@
   echo "${GREEN}[       OK ]${NORMAL} no overlay present before setup" >&2
 overlayfs_needed=true
 D=`adb_sh cat /proc/mounts </dev/null |
-   skip_administrative_mounts data |
-   cut -s -d' ' -f1`
+   skip_administrative_mounts data`
+if echo "${D}" | grep /dev/root >/dev/null; then
+  D=`echo / /
+     echo "${D}" | grep -v /dev/root`
+fi
+D=`echo "${D}" | cut -s -d' ' -f1`
 D=`adb_sh df -k ${D} </dev/null`
 echo "${D}"
 if [ X"${D}" = X"${D##* 100[%] }" ]; then
diff --git a/fs_mgr/tests/data/fstab.example b/fs_mgr/tests/data/fstab.example
new file mode 100644
index 0000000..1a3dfa1
--- /dev/null
+++ b/fs_mgr/tests/data/fstab.example
@@ -0,0 +1,11 @@
+# Android fstab file.
+
+#<src>                                              <mnt_point>        <type>      <mnt_flags and options>                               <fs_mgr_flags>
+
+/dev/block/bootdevice/by-name/system                /                  ext4        ro,barrier=1                                          wait,slotselect,avb
+/dev/block/bootdevice/by-name/metadata              /metadata          ext4        noatime,nosuid,nodev,discard                          wait,formattable
+/dev/block/bootdevice/by-name/userdata              /data              f2fs        noatime,nosuid,nodev,discard,reserve_root=32768,resgid=1065,fsync_mode=nobarrier       latemount,wait,check,fileencryption=ice,keydirectory=/metadata/vold/metadata_encryption,quota,formattable,sysfs_path=/sys/devices/platform/soc/1d84000.ufshc,reservedsize=128M
+/dev/block/bootdevice/by-name/misc                  /misc              emmc        defaults                                              defaults
+/dev/block/bootdevice/by-name/modem                 /vendor/firmware_mnt          vfat        ro,shortname=lower,uid=1000,gid=1000,dmask=227,fmask=337,context=u:object_r:firmware_file:s0   wait,slotselect
+/devices/platform/soc/a600000.ssusb/a600000.dwc3*   auto               vfat        defaults                                              voldmanaged=usb:auto
+/dev/block/zram0                                    none               swap        defaults                                              zramsize=1073741824,max_comp_streams=8
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index db01c1e..1922a69 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -24,6 +24,8 @@
 #include <utility>
 #include <vector>
 
+#include <android-base/file.h>
+#include <android-base/properties.h>
 #include <android-base/strings.h>
 #include <fstab/fstab.h>
 #include <gtest/gtest.h>
@@ -201,3 +203,33 @@
         ++i;
     }
 }
+
+TEST(fs_mgr, ReadFstabFromFile_FsOptions) {
+    Fstab fstab;
+    std::string fstab_file = android::base::GetExecutableDirectory() + "/data/fstab.example";
+    EXPECT_TRUE(ReadFstabFromFile(fstab_file, &fstab));
+
+    EXPECT_EQ("/", fstab[0].mount_point);
+    EXPECT_EQ("barrier=1", fstab[0].fs_options);
+
+    EXPECT_EQ("/metadata", fstab[1].mount_point);
+    EXPECT_EQ("discard", fstab[1].fs_options);
+
+    EXPECT_EQ("/data", fstab[2].mount_point);
+    EXPECT_EQ("discard,reserve_root=32768,resgid=1065,fsync_mode=nobarrier", fstab[2].fs_options);
+
+    EXPECT_EQ("/misc", fstab[3].mount_point);
+    EXPECT_EQ("", fstab[3].fs_options);
+
+    EXPECT_EQ("/vendor/firmware_mnt", fstab[4].mount_point);
+    EXPECT_EQ(
+            "shortname=lower,uid=1000,gid=1000,dmask=227,fmask=337,"
+            "context=u:object_r:firmware_file:s0",
+            fstab[4].fs_options);
+
+    EXPECT_EQ("auto", fstab[5].mount_point);
+    EXPECT_EQ("", fstab[5].fs_options);
+
+    EXPECT_EQ("none", fstab[6].mount_point);
+    EXPECT_EQ("", fstab[6].fs_options);
+}
diff --git a/healthd/android.hardware.health@2.0-service.rc b/healthd/android.hardware.health@2.0-service.rc
index dca0ccc..6960c5d 100644
--- a/healthd/android.hardware.health@2.0-service.rc
+++ b/healthd/android.hardware.health@2.0-service.rc
@@ -2,4 +2,5 @@
     class hal
     user system
     group system
+    capabilities WAKE_ALARM
     file /dev/kmsg w
diff --git a/init/service.cpp b/init/service.cpp
index 5aa3764..272809f 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -367,12 +367,19 @@
         return;
     }
 
-    // If we crash > 4 times in 4 minutes, reboot into bootloader.
+    // If we crash > 4 times in 4 minutes, reboot into bootloader or set crashing property
     boot_clock::time_point now = boot_clock::now();
-    if ((flags_ & SVC_CRITICAL) && !(flags_ & SVC_RESTART)) {
+    if (((flags_ & SVC_CRITICAL) || classnames_.count("updatable")) && !(flags_ & SVC_RESTART)) {
         if (now < time_crashed_ + 4min) {
             if (++crash_count_ > 4) {
-                LOG(FATAL) << "critical process '" << name_ << "' exited 4 times in 4 minutes";
+                if (flags_ & SVC_CRITICAL) {
+                    // Aborts into bootloader
+                    LOG(FATAL) << "critical process '" << name_ << "' exited 4 times in 4 minutes";
+                } else {
+                    LOG(ERROR) << "updatable process '" << name_ << "' exited 4 times in 4 minutes";
+                    // Notifies update_verifier and apexd
+                    property_set("ro.init.updatable_crashing", "1");
+                }
             }
         } else {
             time_crashed_ = now;
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 37afb98..4291212 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -89,6 +89,7 @@
                 "socket_inaddr_any_server_windows.cpp",
                 "socket_network_client_windows.cpp",
                 "sockets_windows.cpp",
+                "trace-host.cpp",
             ],
 
             enabled: true,
diff --git a/libunwindstack/DwarfMemory.cpp b/libunwindstack/DwarfMemory.cpp
index 6ffdc0d..b505900 100644
--- a/libunwindstack/DwarfMemory.cpp
+++ b/libunwindstack/DwarfMemory.cpp
@@ -104,7 +104,6 @@
 
 bool DwarfMemory::AdjustEncodedValue(uint8_t encoding, uint64_t* value) {
   CHECK((encoding & 0x0f) == 0);
-  CHECK(encoding != DW_EH_PE_aligned);
 
   // Handle the encoding.
   switch (encoding) {
diff --git a/libunwindstack/tests/DwarfMemoryTest.cpp b/libunwindstack/tests/DwarfMemoryTest.cpp
index f12d2fe..650e965 100644
--- a/libunwindstack/tests/DwarfMemoryTest.cpp
+++ b/libunwindstack/tests/DwarfMemoryTest.cpp
@@ -54,6 +54,8 @@
   void ReadEncodedValue_overflow();
   template <typename AddressType>
   void ReadEncodedValue_high_bit_set();
+  template <typename AddressType>
+  void ReadEncodedValue_all();
 
   MemoryFake memory_;
   std::unique_ptr<DwarfMemory> dwarf_mem_;
@@ -457,6 +459,27 @@
   ReadEncodedValue_high_bit_set<uint64_t>();
 }
 
+template <typename AddressType>
+void DwarfMemoryTest::ReadEncodedValue_all() {
+  MemoryFakeAlwaysReadZero memory;
+  DwarfMemory dwarf_mem(&memory);
+
+  for (size_t i = 0; i <= 0xff; i++) {
+    uint64_t value;
+    if (dwarf_mem.ReadEncodedValue<AddressType>(static_cast<uint8_t>(i), &value)) {
+      ASSERT_EQ(0U, value);
+    }
+  }
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_all_uint32_t) {
+  ReadEncodedValue_all<uint32_t>();
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_all_uint64_t) {
+  ReadEncodedValue_all<uint64_t>();
+}
+
 TEST_F(DwarfMemoryTest, AdjustEncodedValue_absptr) {
   uint64_t value = 0x1234;
   ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x00, &value));
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 600c91c..3e8417e 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -155,7 +155,7 @@
             ],
         },
         linux: {
-            shared_libs: ["libbase"],
+            header_libs: ["libbase_headers"],
             srcs: [
                 "Looper.cpp",
             ],
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 483fc51..0ec6e17 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -544,7 +544,7 @@
 
     mkdir /data/anr 0775 system system
 
-    mkdir /data/apex 0770 root root
+    mkdir /data/apex 0750 root system
     mkdir /data/staging 0750 system system
 
     # NFC: create data/nfc for nv storage
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 35f469a..451f5ad 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -44,8 +44,6 @@
 /dev/dri/*                0666   root       graphics
 
 # these should not be world writable
-/dev/diag                 0660   radio      radio
-/dev/ttyMSM0              0600   bluetooth  bluetooth
 /dev/uhid                 0660   uhid       uhid
 /dev/uinput               0660   uhid       uhid
 /dev/rtc0                 0640   system     system
@@ -54,7 +52,6 @@
 /dev/input/*              0660   root       input
 /dev/v4l-touch*           0660   root       input
 /dev/snd/*                0660   system     audio
-/dev/msm_mp3*             0660   system     audio
 /dev/bus/usb/*            0660   root       usb
 /dev/mtp_usb              0660   root       mtp
 /dev/usb_accessory        0660   root       usb