Merge "init.rc: tune F2FS to be aligned to system settings"
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 0e43dae..ebe5f4a 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -78,3 +78,5 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/llndk.libraries.txt)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/vndksp.libraries.txt)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/sbin/charger)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/sbin/charger)
diff --git a/adb/Android.bp b/adb/Android.bp
index 1e085a7..01e00dd 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -24,7 +24,8 @@
         "-Wno-missing-field-initializers",
         "-Wthread-safety",
         "-Wvla",
-        "-DADB_HOST=1", // overridden by adbd_defaults
+        "-DADB_HOST=1",         // overridden by adbd_defaults
+        "-DALLOW_ADBD_ROOT=0",  // overridden by adbd_defaults
     ],
     cpp_std: "experimental",
 
@@ -79,7 +80,8 @@
     product_variables: {
         debuggable: {
             cflags: [
-                "-DALLOW_ADBD_ROOT",
+                "-UALLOW_ADBD_ROOT",
+                "-DALLOW_ADBD_ROOT=1",
                 "-DALLOW_ADBD_DISABLE_VERITY",
                 "-DALLOW_ADBD_NO_AUTH",
             ],
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 6960345..9791769 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -312,7 +312,7 @@
     std::string android_dir = user_dir + OS_PATH_SEPARATOR + ".android";
     struct stat buf;
     if (stat(android_dir.c_str(), &buf) == -1) {
-        if (adb_mkdir(android_dir.c_str(), 0750) == -1) {
+        if (adb_mkdir(android_dir, 0750) == -1) {
             PLOG(FATAL) << "Cannot mkdir '" << android_dir << "'";
         }
     }
diff --git a/adb/bugreport_test.cpp b/adb/bugreport_test.cpp
index 72ca59a..a6be203 100644
--- a/adb/bugreport_test.cpp
+++ b/adb/bugreport_test.cpp
@@ -136,7 +136,7 @@
 
     void ExpectBugreportzVersion(const std::string& version) {
         EXPECT_CALL(br_, SendShellCommand("bugreportz -v", false, _))
-            .WillOnce(DoAll(WithArg<2>(WriteOnStderr(version.c_str())),
+            .WillOnce(DoAll(WithArg<2>(WriteOnStderr(version)),
                             WithArg<2>(ReturnCallbackDone(0))));
     }
 
diff --git a/adb/client/adb_client.cpp b/adb/client/adb_client.cpp
index 4cf3a74..5a7bc8d 100644
--- a/adb/client/adb_client.cpp
+++ b/adb/client/adb_client.cpp
@@ -31,10 +31,12 @@
 
 #include <condition_variable>
 #include <mutex>
+#include <optional>
 #include <string>
 #include <thread>
 #include <vector>
 
+#include <android-base/file.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/thread_annotations.h>
@@ -214,15 +216,26 @@
     return adb_connect(nullptr, service, error);
 }
 
-int adb_connect(TransportId* transport, std::string_view service, std::string* error) {
-    // first query the adb server's version
+#if defined(__linux__)
+std::optional<std::string> adb_get_server_executable_path() {
+    int port;
+    std::string error;
+    if (!parse_tcp_socket_spec(__adb_server_socket_spec, nullptr, &port, nullptr, &error)) {
+        LOG(FATAL) << "failed to parse server socket spec: " << error;
+    }
+
+    return adb_get_android_dir_path() + OS_PATH_SEPARATOR + "adb." + std::to_string(port);
+}
+#endif
+
+static bool __adb_check_server_version(std::string* error) {
     unique_fd fd(_adb_connect("host:version", nullptr, error));
 
-    LOG(DEBUG) << "adb_connect: service: " << service;
-    if (fd == -2 && !is_local_socket_spec(__adb_server_socket_spec)) {
+    bool local = is_local_socket_spec(__adb_server_socket_spec);
+    if (fd == -2 && !local) {
         fprintf(stderr, "* cannot start server on remote host\n");
         // error is the original network connection error
-        return fd;
+        return false;
     } else if (fd == -2) {
         fprintf(stderr, "* daemon not running; starting now at %s\n", __adb_server_socket_spec);
     start_server:
@@ -232,7 +245,7 @@
             // return a generic error string about the overall adb_connect()
             // that the caller requested.
             *error = "cannot connect to daemon";
-            return -1;
+            return false;
         } else {
             fprintf(stderr, "* daemon started successfully\n");
         }
@@ -246,7 +259,7 @@
         if (fd >= 0) {
             std::string version_string;
             if (!ReadProtocolString(fd, &version_string, error)) {
-                return -1;
+                return false;
             }
 
             ReadOrderlyShutdown(fd);
@@ -254,18 +267,39 @@
             if (sscanf(&version_string[0], "%04x", &version) != 1) {
                 *error = android::base::StringPrintf("cannot parse version string: %s",
                                                      version_string.c_str());
-                return -1;
+                return false;
             }
         } else {
             // If fd is -1 check for "unknown host service" which would
             // indicate a version of adb that does not support the
             // version command, in which case we should fall-through to kill it.
             if (*error != "unknown host service") {
-                return fd;
+                return false;
             }
         }
 
         if (version != ADB_SERVER_VERSION) {
+#if defined(__linux__)
+            if (version > ADB_SERVER_VERSION && local) {
+                // Try to re-exec the existing adb server's binary.
+                constexpr const char* adb_reexeced = "adb (re-execed)";
+                if (strcmp(adb_reexeced, *__adb_argv) != 0) {
+                    __adb_argv[0] = adb_reexeced;
+                    std::optional<std::string> server_path_path = adb_get_server_executable_path();
+                    std::string server_path;
+                    if (server_path_path &&
+                        android::base::ReadFileToString(*server_path_path, &server_path)) {
+                        if (execve(server_path.c_str(), const_cast<char**>(__adb_argv),
+                                   const_cast<char**>(__adb_envp)) == -1) {
+                            LOG(ERROR) << "failed to exec newer version at " << server_path;
+                        }
+
+                        // Fall-through to restarting the server.
+                    }
+                }
+            }
+#endif
+
             fprintf(stderr, "adb server version (%d) doesn't match this client (%d); killing...\n",
                     version, ADB_SERVER_VERSION);
             adb_kill_server();
@@ -273,12 +307,36 @@
         }
     }
 
+    return true;
+}
+
+bool adb_check_server_version(std::string* error) {
+    // Only check the version once per process, since this isn't atomic anyway.
+    static std::once_flag once;
+    static bool result;
+    static std::string* err;
+    std::call_once(once, []() {
+        err = new std::string();
+        result = __adb_check_server_version(err);
+    });
+    *error = *err;
+    return result;
+}
+
+int adb_connect(TransportId* transport, std::string_view service, std::string* error) {
+    LOG(DEBUG) << "adb_connect: service: " << service;
+
+    // Query the adb server's version.
+    if (!adb_check_server_version(error)) {
+        return -1;
+    }
+
     // if the command is start-server, we are done.
     if (service == "host:start-server") {
         return 0;
     }
 
-    fd.reset(_adb_connect(service, transport, error));
+    unique_fd fd(_adb_connect(service, transport, error));
     if (fd == -1) {
         D("_adb_connect error: %s", error->c_str());
     } else if(fd == -2) {
diff --git a/adb/client/adb_client.h b/adb/client/adb_client.h
index 0a73787..8d32c93 100644
--- a/adb/client/adb_client.h
+++ b/adb/client/adb_client.h
@@ -20,8 +20,14 @@
 #include "sysdeps.h"
 #include "transport.h"
 
+#include <optional>
 #include <string>
 
+// Explicitly check the adb server version.
+// All of the commands below do this implicitly.
+// Only the first invocation of this function will check the server version.
+bool adb_check_server_version(std::string* _Nonnull error);
+
 // Connect to adb, connect to the named service, and return a valid fd for
 // interacting with that service upon success or a negative number on failure.
 int adb_connect(std::string_view service, std::string* _Nonnull error);
@@ -65,3 +71,13 @@
 
 // Get the feature set of the current preferred transport.
 bool adb_get_feature_set(FeatureSet* _Nonnull feature_set, std::string* _Nonnull error);
+
+#if defined(__linux__)
+// Get the path of a file containing the path to the server executable, if the socket spec set via
+// adb_set_socket_spec is a local one.
+std::optional<std::string> adb_get_server_executable_path();
+#endif
+
+// Globally acccesible argv/envp, for the purpose of re-execing adb.
+extern const char* _Nullable * _Nullable __adb_argv;
+extern const char* _Nullable * _Nullable __adb_envp;
diff --git a/adb/client/auth.cpp b/adb/client/auth.cpp
index bcb829b..3eee426 100644
--- a/adb/client/auth.cpp
+++ b/adb/client/auth.cpp
@@ -416,7 +416,7 @@
 #endif
 
     for (const std::string& path : key_paths) {
-        load_keys(path.c_str());
+        load_keys(path);
     }
 }
 
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 2b328ab..43a3e5e 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -295,7 +295,10 @@
                     callback->OnStderr(buffer_ptr, length);
                     break;
                 case ShellProtocol::kIdExit:
-                    exit_code = protocol->data()[0];
+                    // data() returns a char* which doesn't have defined signedness.
+                    // Cast to uint8_t to prevent 255 from being sign extended to INT_MIN,
+                    // which doesn't get truncated on Windows.
+                    exit_code = static_cast<uint8_t>(protocol->data()[0]);
                     continue;
                 default:
                     continue;
@@ -1005,7 +1008,8 @@
 #endif /* !defined(_WIN32) */
 }
 
-static bool wait_for_device(const char* service) {
+static bool wait_for_device(const char* service,
+                            std::optional<std::chrono::milliseconds> timeout = std::nullopt) {
     std::vector<std::string> components = android::base::Split(service, "-");
     if (components.size() < 3 || components.size() > 4) {
         fprintf(stderr, "adb: couldn't parse 'wait-for' command: %s\n", service);
@@ -1043,6 +1047,13 @@
     }
 
     std::string cmd = format_host_command(android::base::Join(components, "-").c_str());
+    if (timeout) {
+        std::thread([timeout]() {
+            std::this_thread::sleep_for(*timeout);
+            fprintf(stderr, "timeout expired while waiting for device\n");
+            _exit(1);
+        }).detach();
+    }
     return adb_command(cmd);
 }
 
@@ -1084,8 +1095,21 @@
     }
 
     // Wait for the device to go away.
+    TransportType previous_type;
+    const char* previous_serial;
+    TransportId previous_id;
+    adb_get_transport(&previous_type, &previous_serial, &previous_id);
+
     adb_set_transport(kTransportAny, nullptr, transport_id);
     wait_for_device("wait-for-disconnect");
+
+    // Wait for the device to come back.
+    // If we were using a specific transport ID, there's nothing we can wait for.
+    if (previous_id == 0) {
+        adb_set_transport(previous_type, previous_serial, 0);
+        wait_for_device("wait-for-device", 3000ms);
+    }
+
     return true;
 }
 
@@ -1282,9 +1306,9 @@
     }
 }
 
-static int adb_connect_command(const std::string& command) {
+static int adb_connect_command(const std::string& command, TransportId* transport = nullptr) {
     std::string error;
-    unique_fd fd(adb_connect(command, &error));
+    unique_fd fd(adb_connect(transport, command, &error));
     if (fd < 0) {
         fprintf(stderr, "error: %s\n", error.c_str());
         return 1;
@@ -1373,9 +1397,9 @@
     TransportId transport_id = 0;
 
     while (argc > 0) {
-        if (!strcmp(argv[0],"server")) {
+        if (!strcmp(argv[0], "server")) {
             is_server = true;
-        } else if (!strcmp(argv[0],"nodaemon")) {
+        } else if (!strcmp(argv[0], "nodaemon")) {
             no_daemon = true;
         } else if (!strcmp(argv[0], "fork-server")) {
             /* this is a special flag used only when the ADB client launches the ADB Server */
@@ -1412,11 +1436,11 @@
             if (*id != '\0') {
                 error_exit("invalid transport id");
             }
-        } else if (!strcmp(argv[0],"-d")) {
+        } else if (!strcmp(argv[0], "-d")) {
             transport_type = kTransportUsb;
-        } else if (!strcmp(argv[0],"-e")) {
+        } else if (!strcmp(argv[0], "-e")) {
             transport_type = kTransportLocal;
-        } else if (!strcmp(argv[0],"-a")) {
+        } else if (!strcmp(argv[0], "-a")) {
             gListenAll = 1;
         } else if (!strncmp(argv[0], "-H", 2)) {
             if (argv[0][2] == '\0') {
@@ -1548,6 +1572,10 @@
         }
 
         std::string query = android::base::StringPrintf("host:%s%s", argv[0], listopt);
+        std::string error;
+        if (!adb_check_server_version(&error)) {
+            error_exit("failed to check server version: %s", error.c_str());
+        }
         printf("List of devices attached\n");
         return adb_query_command(query);
     }
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
index 7e470e1..5d10238 100644
--- a/adb/client/file_sync_client.cpp
+++ b/adb/client/file_sync_client.cpp
@@ -1012,7 +1012,7 @@
                 dst_dir.append(android::base::Basename(src_path));
             }
 
-            success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(), sync, false);
+            success &= copy_local_dir_remote(sc, src_path, dst_dir, sync, false);
             continue;
         } else if (!should_push_file(st.st_mode)) {
             sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, st.st_mode);
@@ -1128,7 +1128,7 @@
     // Recursively build the list of files to copy.
     sc.Printf("pull: building file list...");
     std::vector<copyinfo> file_list;
-    if (!remote_build_list(sc, &file_list, rpath.c_str(), lpath.c_str())) {
+    if (!remote_build_list(sc, &file_list, rpath, lpath)) {
         return false;
     }
 
@@ -1240,7 +1240,7 @@
                 dst_dir.append(android::base::Basename(src_path));
             }
 
-            success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(), copy_attrs);
+            success &= copy_remote_dir_local(sc, src_path, dst_dir, copy_attrs);
             continue;
         } else if (!should_pull_file(src_st.st_mode)) {
             sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, src_st.st_mode);
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 2ee81a9..0c5c28f 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -32,12 +32,16 @@
 
 #include "adb.h"
 #include "adb_auth.h"
+#include "adb_client.h"
 #include "adb_listeners.h"
 #include "adb_utils.h"
 #include "commandline.h"
 #include "sysdeps/chrono.h"
 #include "transport.h"
 
+const char** __adb_argv;
+const char** __adb_envp;
+
 static void setup_daemon_logging() {
     const std::string log_file_path(GetLogFilePath());
     int fd = unix_open(log_file_path, O_WRONLY | O_CREAT | O_APPEND, 0640);
@@ -191,13 +195,29 @@
         notify_thread.detach();
     }
 
+#if defined(__linux__)
+    // Write our location to .android/adb.$PORT, so that older clients can exec us.
+    std::string path;
+    if (!android::base::Readlink("/proc/self/exe", &path)) {
+        PLOG(ERROR) << "failed to readlink /proc/self/exe";
+    }
+
+    std::optional<std::string> server_executable_path = adb_get_server_executable_path();
+    if (server_executable_path) {
+      if (!android::base::WriteStringToFile(path, *server_executable_path)) {
+          PLOG(ERROR) << "failed to write server path to " << path;
+      }
+    }
+#endif
+
     D("Event loop starting");
     fdevent_loop();
-
     return 0;
 }
 
-int main(int argc, char** argv) {
+int main(int argc, char* argv[], char* envp[]) {
+    __adb_argv = const_cast<const char**>(argv);
+    __adb_envp = const_cast<const char**>(envp);
     adb_trace_init(argv);
     return adb_commandline(argc - 1, const_cast<const char**>(argv + 1));
 }
diff --git a/adb/daemon/file_sync_service.cpp b/adb/daemon/file_sync_service.cpp
index 70deb31..e82a51f 100644
--- a/adb/daemon/file_sync_service.cpp
+++ b/adb/daemon/file_sync_service.cpp
@@ -25,7 +25,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/mount.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/types.h>
@@ -211,22 +210,6 @@
     return WriteFdExactly(s, &msg.dent, sizeof(msg.dent));
 }
 
-static bool is_mountpoint(const std::string& path, pid_t tid) {
-    const std::string mountinfo_path = "/proc/" + std::to_string(tid) + "/mountinfo";
-    std::string mountinfo;
-    if (!android::base::ReadFileToString(mountinfo_path, &mountinfo)) {
-        PLOG(ERROR) << "Failed to open " << mountinfo_path;
-        return false;
-    }
-    std::vector<std::string> lines = android::base::Split(mountinfo, "\n");
-    return std::find_if(lines.begin(), lines.end(), [&path](const auto& line) {
-               auto tokens = android::base::Split(line, " ");
-               // line format is ...
-               // mountid parentmountid major:minor sourcepath targetpath option ...
-               return tokens.size() >= 4 && tokens[4] == path;
-           }) != lines.end();
-}
-
 // Make sure that SendFail from adb_io.cpp isn't accidentally used in this file.
 #pragma GCC poison SendFail
 
@@ -432,18 +415,6 @@
     struct stat st;
     bool do_unlink = (lstat(path.c_str(), &st) == -1) || S_ISREG(st.st_mode) ||
                      (S_ISLNK(st.st_mode) && !S_ISLNK(mode));
-
-    // If the path is a file that is a mount point, don't unlink it, but instead
-    // truncate to zero. If unlinked, existing mounts on the path is all
-    // unmounted
-    if (S_ISREG(st.st_mode) && is_mountpoint(path, getpid())) {
-        do_unlink = false;
-        if (truncate(path.c_str(), 0) == -1) {
-            SendSyncFail(s, "truncate to zero failed");
-            return false;
-        }
-    }
-
     if (do_unlink) {
         adb_unlink(path.c_str());
     }
@@ -451,7 +422,7 @@
     bool result;
     uint32_t timestamp;
     if (S_ISLNK(mode)) {
-        result = handle_send_link(s, path.c_str(), &timestamp, buffer);
+        result = handle_send_link(s, path, &timestamp, buffer);
     } else {
         // Copy user permission bits to "group" and "other" permissions.
         mode &= 0777;
@@ -591,64 +562,7 @@
     return true;
 }
 
-#if defined(__ANDROID__)
-class FileSyncPreparer {
-  public:
-    FileSyncPreparer() : saved_ns_fd_(-1), rooted_(getuid() == 0) {
-        const std::string namespace_path = "/proc/" + std::to_string(gettid()) + "/ns/mnt";
-        const int ns_fd = adb_open(namespace_path.c_str(), O_RDONLY | O_CLOEXEC);
-        if (ns_fd == -1) {
-            if (rooted_) PLOG(ERROR) << "Failed to save mount namespace";
-            return;
-        }
-        saved_ns_fd_.reset(ns_fd);
-
-        // Note: this is for the current thread only
-        if (unshare(CLONE_NEWNS) != 0) {
-            if (rooted_) PLOG(ERROR) << "Failed to clone mount namespace";
-            return;
-        }
-
-        // Set the propagation type of / to private so that unmount below is
-        // not propagated to other mount namespaces.
-        if (mount(nullptr, "/", nullptr, MS_PRIVATE | MS_REC, nullptr) == -1) {
-            if (rooted_) PLOG(ERROR) << "Could not change propagation type of / to MS_PRIVATE";
-            return;
-        }
-
-        // unmount /bionic which is bind-mount to itself by init. Under /bionic,
-        // there are other bind mounts for the bionic files. By unmounting this,
-        // we unmount them all thus revealing the raw file system that is the
-        // same as the local file system seen by the adb client.
-        if (umount2("/bionic", MNT_DETACH) == -1 && errno != ENOENT) {
-            if (rooted_) PLOG(ERROR) << "Could not unmount /bionic to reveal raw filesystem";
-            return;
-        }
-    }
-
-    ~FileSyncPreparer() {
-        if (saved_ns_fd_.get() != -1) {
-            // In fact, this is not strictly required because this thread for file
-            // sync service will be destroyed after the current transfer is all
-            // done. However, let's restore the ns in case the same thread is
-            // reused by multiple transfers in the future refactoring.
-            if (setns(saved_ns_fd_, CLONE_NEWNS) == -1) {
-                PLOG(ERROR) << "Failed to restore saved mount namespace";
-            }
-        }
-    }
-
-  private:
-    unique_fd saved_ns_fd_;
-    bool rooted_;
-};
-#endif
-
 void file_sync_service(unique_fd fd) {
-#if defined(__ANDROID__)
-    FileSyncPreparer preparer;
-#endif
-
     std::vector<char> buffer(SYNC_DATA_MAX);
 
     while (handle_sync_command(fd.get(), buffer)) {
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index fce3a4f..e5a4917 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -58,17 +58,23 @@
 #if defined(__ANDROID__)
 static const char* root_seclabel = nullptr;
 
+static inline bool is_device_unlocked() {
+    return "orange" == android::base::GetProperty("ro.boot.verifiedbootstate", "");
+}
+
 static bool should_drop_capabilities_bounding_set() {
-#if defined(ALLOW_ADBD_ROOT)
-    if (__android_log_is_debuggable()) {
-        return false;
+    if (ALLOW_ADBD_ROOT || is_device_unlocked()) {
+        if (__android_log_is_debuggable()) {
+            return false;
+        }
     }
-#endif
     return true;
 }
 
 static bool should_drop_privileges() {
-#if defined(ALLOW_ADBD_ROOT)
+    // "adb root" not allowed, always drop privileges.
+    if (!ALLOW_ADBD_ROOT && !is_device_unlocked()) return true;
+
     // The properties that affect `adb root` and `adb unroot` are ro.secure and
     // ro.debuggable. In this context the names don't make the expected behavior
     // particularly obvious.
@@ -98,9 +104,6 @@
     }
 
     return drop;
-#else
-    return true; // "adb root" not allowed, always drop privileges.
-#endif // ALLOW_ADBD_ROOT
 }
 
 static void drop_privileges(int server_port) {
@@ -205,6 +208,10 @@
 #if defined(ALLOW_ADBD_NO_AUTH)
     // If ro.adb.secure is unset, default to no authentication required.
     auth_required = android::base::GetBoolProperty("ro.adb.secure", false);
+#elif defined(__ANDROID__)
+    if (is_device_unlocked()) {  // allows no authentication when the device is unlocked.
+        auth_required = android::base::GetBoolProperty("ro.adb.secure", false);
+    }
 #endif
 
     adbd_auth_init();
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index a44ff43..14cdb69 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -115,7 +115,7 @@
 };
 
 struct IoBlock {
-    bool pending;
+    bool pending = false;
     struct iocb control;
     std::shared_ptr<Block> payload;
 
@@ -168,7 +168,8 @@
 struct UsbFfsConnection : public Connection {
     UsbFfsConnection(unique_fd control, unique_fd read, unique_fd write,
                      std::promise<void> destruction_notifier)
-        : stopped_(false),
+        : worker_started_(false),
+          stopped_(false),
           destruction_notifier_(std::move(destruction_notifier)),
           control_fd_(std::move(control)),
           read_fd_(std::move(read)),
@@ -194,6 +195,7 @@
 
         // We need to explicitly close our file descriptors before we notify our destruction,
         // because the thread listening on the future will immediately try to reopen the endpoint.
+        aio_context_.reset();
         control_fd_.reset();
         read_fd_.reset();
         write_fd_.reset();
@@ -267,32 +269,23 @@
             adb_thread_setname("UsbFfs-monitor");
 
             bool bound = false;
-            bool started = false;
+            bool enabled = false;
             bool running = true;
             while (running) {
-                int timeout = -1;
-                if (!bound || !started) {
-                    timeout = 5000 /*ms*/;
-                }
-
                 adb_pollfd pfd[2] = {
                   { .fd = control_fd_.get(), .events = POLLIN, .revents = 0 },
                   { .fd = monitor_event_fd_.get(), .events = POLLIN, .revents = 0 },
                 };
-                int rc = TEMP_FAILURE_RETRY(adb_poll(pfd, 2, timeout));
+
+                // If we don't see our first bind within a second, try again.
+                int timeout_ms = bound ? -1 : 1000;
+
+                int rc = TEMP_FAILURE_RETRY(adb_poll(pfd, 2, timeout_ms));
                 if (rc == -1) {
                     PLOG(FATAL) << "poll on USB control fd failed";
                 } else if (rc == 0) {
-                    // Something in the kernel presumably went wrong.
-                    // Close our endpoints, wait for a bit, and then try again.
-                    StopWorker();
-                    aio_context_.reset();
-                    read_fd_.reset();
-                    write_fd_.reset();
-                    control_fd_.reset();
-                    std::this_thread::sleep_for(5s);
-                    HandleError("didn't receive FUNCTIONFS_ENABLE, retrying");
-                    return;
+                    LOG(WARNING) << "timed out while waiting for FUNCTIONFS_BIND, trying again";
+                    break;
                 }
 
                 if (pfd[1].revents) {
@@ -312,29 +305,45 @@
                 switch (event.type) {
                     case FUNCTIONFS_BIND:
                         CHECK(!bound) << "received FUNCTIONFS_BIND while already bound?";
+                        CHECK(!enabled) << "received FUNCTIONFS_BIND while already enabled?";
                         bound = true;
+
                         break;
 
                     case FUNCTIONFS_ENABLE:
-                        CHECK(!started) << "received FUNCTIONFS_ENABLE while already running?";
-                        started = true;
+                        CHECK(bound) << "received FUNCTIONFS_ENABLE while not bound?";
+                        CHECK(!enabled) << "received FUNCTIONFS_ENABLE while already enabled?";
+                        enabled = true;
+
                         StartWorker();
                         break;
 
                     case FUNCTIONFS_DISABLE:
+                        CHECK(bound) << "received FUNCTIONFS_DISABLE while not bound?";
+                        CHECK(enabled) << "received FUNCTIONFS_DISABLE while not enabled?";
+                        enabled = false;
+
+                        running = false;
+                        break;
+
+                    case FUNCTIONFS_UNBIND:
+                        CHECK(!enabled) << "received FUNCTIONFS_UNBIND while still enabled?";
+                        CHECK(bound) << "received FUNCTIONFS_UNBIND when not bound?";
+                        bound = false;
+
                         running = false;
                         break;
                 }
             }
 
             StopWorker();
-            aio_context_.reset();
-            read_fd_.reset();
-            write_fd_.reset();
+            HandleError("monitor thread finished");
         });
     }
 
     void StartWorker() {
+        CHECK(!worker_started_);
+        worker_started_ = true;
         worker_thread_ = std::thread([this]() {
             adb_thread_setname("UsbFfs-worker");
             for (size_t i = 0; i < kUsbReadQueueDepth; ++i) {
@@ -353,12 +362,16 @@
                     LOG(FATAL) << "hit EOF on eventfd";
                 }
 
-                WaitForEvents();
+                ReadEvents();
             }
         });
     }
 
     void StopWorker() {
+        if (!worker_started_) {
+            return;
+        }
+
         pthread_t worker_thread_handle = worker_thread_.native_handle();
         while (true) {
             int rc = pthread_kill(worker_thread_handle, kInterruptionSignal);
@@ -403,7 +416,7 @@
         return block;
     }
 
-    void WaitForEvents() {
+    void ReadEvents() {
         static constexpr size_t kMaxEvents = kUsbReadQueueDepth + kUsbWriteQueueDepth;
         struct io_event events[kMaxEvents];
         struct timespec timeout = {.tv_sec = 0, .tv_nsec = 0};
@@ -566,6 +579,8 @@
             LOG(VERBOSE) << "submitting write_request " << static_cast<void*>(iocbs[i]);
         }
 
+        writes_submitted_ += writes_to_submit;
+
         int rc = io_submit(aio_context_.get(), writes_to_submit, iocbs);
         if (rc == -1) {
             HandleError(StringPrintf("failed to submit write requests: %s", strerror(errno)));
@@ -574,8 +589,6 @@
             LOG(FATAL) << "failed to submit all writes: wanted to submit " << writes_to_submit
                        << ", actually submitted " << rc;
         }
-
-        writes_submitted_ += rc;
     }
 
     void HandleError(const std::string& error) {
@@ -588,6 +601,8 @@
     }
 
     std::thread monitor_thread_;
+
+    bool worker_started_;
     std::thread worker_thread_;
 
     std::atomic<bool> stopped_;
@@ -654,7 +669,10 @@
 }
 
 void usb_init() {
-    bool use_nonblocking = android::base::GetBoolProperty("persist.adb.nonblocking_ffs", true);
+    bool use_nonblocking = android::base::GetBoolProperty(
+            "persist.adb.nonblocking_ffs",
+            android::base::GetBoolProperty("ro.adb.nonblocking_ffs", true));
+
     if (use_nonblocking) {
         std::thread(usb_ffs_open_thread).detach();
     } else {
diff --git a/adb/services.cpp b/adb/services.cpp
index 80f9f79..cf346ba 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -188,7 +188,7 @@
     if (!strncmp(host.c_str(), "emu:", 4)) {
         connect_emulator(host.c_str() + 4, &response);
     } else {
-        connect_device(host.c_str(), &response);
+        connect_device(host, &response);
     }
 
     // Send response for emulator and device
diff --git a/adb/socket_spec.h b/adb/socket_spec.h
index 687d751..7cc2fac 100644
--- a/adb/socket_spec.h
+++ b/adb/socket_spec.h
@@ -29,6 +29,5 @@
                          std::string* error);
 int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_tcp_port = nullptr);
 
-// Exposed for testing.
 bool parse_tcp_socket_spec(std::string_view spec, std::string* hostname, int* port,
                            std::string* serial, std::string* error);
diff --git a/base/file.cpp b/base/file.cpp
index 2f4a517..adc8984 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -385,7 +385,12 @@
 bool Realpath(const std::string& path, std::string* result) {
   result->clear();
 
-  char* realpath_buf = realpath(path.c_str(), nullptr);
+  // realpath may exit with EINTR. Retry if so.
+  char* realpath_buf = nullptr;
+  do {
+    realpath_buf = realpath(path.c_str(), nullptr);
+  } while (realpath_buf == nullptr && errno == EINTR);
+
   if (realpath_buf == nullptr) {
     return false;
   }
diff --git a/base/include/android-base/strings.h b/base/include/android-base/strings.h
index fc5c1ce..8e9716f 100644
--- a/base/include/android-base/strings.h
+++ b/base/include/android-base/strings.h
@@ -56,23 +56,17 @@
 extern template std::string Join(const std::vector<const char*>&, const std::string&);
 
 // Tests whether 's' starts with 'prefix'.
-// TODO: string_view
-bool StartsWith(const std::string& s, const char* prefix);
-bool StartsWithIgnoreCase(const std::string& s, const char* prefix);
-bool StartsWith(const std::string& s, const std::string& prefix);
-bool StartsWithIgnoreCase(const std::string& s, const std::string& prefix);
-bool StartsWith(const std::string& s, char prefix);
+bool StartsWith(std::string_view s, std::string_view prefix);
+bool StartsWith(std::string_view s, char prefix);
+bool StartsWithIgnoreCase(std::string_view s, std::string_view prefix);
 
 // Tests whether 's' ends with 'suffix'.
-// TODO: string_view
-bool EndsWith(const std::string& s, const char* suffix);
-bool EndsWithIgnoreCase(const std::string& s, const char* suffix);
-bool EndsWith(const std::string& s, const std::string& suffix);
-bool EndsWithIgnoreCase(const std::string& s, const std::string& suffix);
-bool EndsWith(const std::string& s, char suffix);
+bool EndsWith(std::string_view s, std::string_view suffix);
+bool EndsWith(std::string_view s, char suffix);
+bool EndsWithIgnoreCase(std::string_view s, std::string_view suffix);
 
 // Tests whether 'lhs' equals 'rhs', ignoring case.
-bool EqualsIgnoreCase(const std::string& lhs, const std::string& rhs);
+bool EqualsIgnoreCase(std::string_view lhs, std::string_view rhs);
 
 }  // namespace base
 }  // namespace android
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index 83213e9..3fa3bea 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -105,6 +105,9 @@
   int get() const { return fd_; }
   operator int() const { return get(); }  // NOLINT
 
+  // Catch bogus error checks (i.e.: "!fd" instead of "fd != -1").
+  bool operator!() const = delete;
+
   int release() __attribute__((warn_unused_result)) {
     tag(fd_, this, nullptr);
     int ret = fd_;
diff --git a/base/mapped_file.cpp b/base/mapped_file.cpp
index faa845d..7c65dc3 100644
--- a/base/mapped_file.cpp
+++ b/base/mapped_file.cpp
@@ -41,7 +41,14 @@
   HANDLE handle =
       CreateFileMapping(reinterpret_cast<HANDLE>(_get_osfhandle(fd)), nullptr,
                         (prot & PROT_WRITE) ? PAGE_READWRITE : PAGE_READONLY, 0, 0, nullptr);
-  if (handle == nullptr) return nullptr;
+  if (handle == nullptr) {
+    // http://b/119818070 "app crashes when reading asset of zero length".
+    // Return a MappedFile that's only valid for reading the size.
+    if (length == 0) {
+      return std::unique_ptr<MappedFile>(new MappedFile{nullptr, 0, 0, nullptr});
+    }
+    return nullptr;
+  }
   void* base = MapViewOfFile(handle, (prot & PROT_WRITE) ? FILE_MAP_ALL_ACCESS : FILE_MAP_READ, 0,
                              file_offset, file_length);
   if (base == nullptr) {
diff --git a/base/strings.cpp b/base/strings.cpp
index 2d6eef0..bb3167e 100644
--- a/base/strings.cpp
+++ b/base/strings.cpp
@@ -87,58 +87,33 @@
 template std::string Join(const std::vector<std::string>&, const std::string&);
 template std::string Join(const std::vector<const char*>&, const std::string&);
 
-bool StartsWith(const std::string& s, const char* prefix) {
-  return strncmp(s.c_str(), prefix, strlen(prefix)) == 0;
+bool StartsWith(std::string_view s, std::string_view prefix) {
+  return s.substr(0, prefix.size()) == prefix;
 }
 
-bool StartsWith(const std::string& s, const std::string& prefix) {
-  return strncmp(s.c_str(), prefix.c_str(), prefix.size()) == 0;
+bool StartsWith(std::string_view s, char prefix) {
+  return !s.empty() && s.front() == prefix;
 }
 
-bool StartsWith(const std::string& s, char prefix) {
-  return *s.c_str() == prefix;  // Use c_str() to guarantee there is at least a '\0'.
+bool StartsWithIgnoreCase(std::string_view s, std::string_view prefix) {
+  return s.size() >= prefix.size() && strncasecmp(s.data(), prefix.data(), prefix.size()) == 0;
 }
 
-bool StartsWithIgnoreCase(const std::string& s, const char* prefix) {
-  return strncasecmp(s.c_str(), prefix, strlen(prefix)) == 0;
+bool EndsWith(std::string_view s, std::string_view suffix) {
+  return s.size() >= suffix.size() && s.substr(s.size() - suffix.size(), suffix.size()) == suffix;
 }
 
-bool StartsWithIgnoreCase(const std::string& s, const std::string& prefix) {
-  return strncasecmp(s.c_str(), prefix.c_str(), prefix.size()) == 0;
+bool EndsWith(std::string_view s, char suffix) {
+  return !s.empty() && s.back() == suffix;
 }
 
-static bool EndsWith(const std::string& s, const char* suffix, size_t suffix_length,
-                     bool case_sensitive) {
-  size_t string_length = s.size();
-  if (suffix_length > string_length) {
-    return false;
-  }
-  size_t offset = string_length - suffix_length;
-  return (case_sensitive ? strncmp : strncasecmp)(s.c_str() + offset, suffix, suffix_length) == 0;
+bool EndsWithIgnoreCase(std::string_view s, std::string_view suffix) {
+  return s.size() >= suffix.size() &&
+         strncasecmp(s.data() + (s.size() - suffix.size()), suffix.data(), suffix.size()) == 0;
 }
 
-bool EndsWith(const std::string& s, const char* suffix) {
-  return EndsWith(s, suffix, strlen(suffix), true);
-}
-
-bool EndsWith(const std::string& s, const std::string& suffix) {
-  return EndsWith(s, suffix.c_str(), suffix.size(), true);
-}
-
-bool EndsWith(const std::string& s, char suffix) {
-  return EndsWith(s, &suffix, 1, true);
-}
-
-bool EndsWithIgnoreCase(const std::string& s, const char* suffix) {
-  return EndsWith(s, suffix, strlen(suffix), false);
-}
-
-bool EndsWithIgnoreCase(const std::string& s, const std::string& suffix) {
-  return EndsWith(s, suffix.c_str(), suffix.size(), false);
-}
-
-bool EqualsIgnoreCase(const std::string& lhs, const std::string& rhs) {
-  return strcasecmp(lhs.c_str(), rhs.c_str()) == 0;
+bool EqualsIgnoreCase(std::string_view lhs, std::string_view rhs) {
+  return lhs.size() == rhs.size() && strncasecmp(lhs.data(), rhs.data(), lhs.size()) == 0;
 }
 
 }  // namespace base
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index ed955ea..1ce0ec4 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -293,6 +293,12 @@
     {"kernel_panic,dsps", 166},
     {"kernel_panic,wcnss", 167},
     {"kernel_panic,_sde_encoder_phys_cmd_handle_ppdone_timeout", 168},
+    {"recovery,quiescent", 169},
+    {"reboot,quiescent", 170},
+    {"reboot,rtc", 171},
+    {"reboot,dm-verity_device_corrupted", 172},
+    {"reboot,dm-verity_enforcing", 173},
+    {"reboot,keys_clear", 174},
 };
 
 // Converts a string value representing the reason the system booted to an
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index a064ca0..bca5e36 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -383,7 +383,9 @@
 
     execle(CRASH_DUMP_PATH, CRASH_DUMP_NAME, main_tid, pseudothread_tid, debuggerd_dump_type,
            nullptr, nullptr);
-    fatal_errno("exec failed");
+    async_safe_format_log(ANDROID_LOG_FATAL, "libc", "failed to exec crash_dump helper: %s",
+                          strerror(errno));
+    return 1;
   }
 
   input_write.reset();
diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp
index 753ebcb..94fcfb2 100644
--- a/debuggerd/libdebuggerd/backtrace.cpp
+++ b/debuggerd/libdebuggerd/backtrace.cpp
@@ -74,6 +74,7 @@
     return;
   }
 
+  unwinder->SetDisplayBuildID(true);
   for (size_t i = 0; i < unwinder->NumFrames(); i++) {
     _LOG(&log, logtype::BACKTRACE, "  %s\n", unwinder->FormatFrame(i).c_str());
   }
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index c08afda..47a7a8f 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -371,6 +371,7 @@
 }
 
 void dump_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) {
+  unwinder->SetDisplayBuildID(true);
   for (size_t i = 0; i < unwinder->NumFrames(); i++) {
     _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str());
   }
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 4cdd8bc..827db96 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -1805,7 +1805,7 @@
             auto format = [&](const std::string& partition) {
                 fb_perform_format(partition, 0, type_override, size_override, "");
             };
-            do_for_partitions(partition.c_str(), slot_override, format, true);
+            do_for_partitions(partition, slot_override, format, true);
         } else if (command == "signature") {
             std::string filename = next_arg(&args);
             std::vector<char> data;
@@ -1876,7 +1876,7 @@
                 }
                 do_flash(partition.c_str(), fname.c_str());
             };
-            do_for_partitions(pname.c_str(), slot_override, flash, true);
+            do_for_partitions(pname, slot_override, flash, true);
         } else if (command == "flash:raw") {
             std::string partition = next_arg(&args);
             std::string kernel = next_arg(&args);
diff --git a/fastboot/fuzzy_fastboot/fixtures.cpp b/fastboot/fuzzy_fastboot/fixtures.cpp
index 280cfb6..c23da01 100644
--- a/fastboot/fuzzy_fastboot/fixtures.cpp
+++ b/fastboot/fuzzy_fastboot/fixtures.cpp
@@ -55,6 +55,8 @@
 #include "test_utils.h"
 #include "usb_transport_sniffer.h"
 
+using namespace std::literals::chrono_literals;
+
 namespace fastboot {
 
 int FastBootTest::MatchFastboot(usb_ifc_info* info, const char* local_serial) {
@@ -128,10 +130,14 @@
         ASSERT_EQ(device_path, cb_scratch);  // The path can not change
     }
     fb = std::unique_ptr<FastBootDriver>(new FastBootDriver(transport.get(), {}, true));
+    // No error checking since non-A/B devices may not support the command
+    fb->GetVar("current-slot", &initial_slot);
 }
 
 void FastBootTest::TearDown() {
     EXPECT_TRUE(UsbStillAvailible()) << USB_PORT_GONE;
+    // No error checking since non-A/B devices may not support the command
+    fb->SetActive(initial_slot);
 
     TearDownSerial();
 
@@ -159,6 +165,26 @@
     }
 }
 
+void FastBootTest::ReconnectFastbootDevice() {
+    fb.reset();
+    transport.reset();
+    while (UsbStillAvailible())
+        ;
+    printf("WAITING FOR DEVICE\n");
+    // Need to wait for device
+    const auto matcher = [](usb_ifc_info* info) -> int { return MatchFastboot(info, nullptr); };
+    while (!transport) {
+        std::unique_ptr<UsbTransport> usb(usb_open(matcher, USB_TIMEOUT));
+        if (usb) {
+            transport = std::unique_ptr<UsbTransportSniffer>(
+                    new UsbTransportSniffer(std::move(usb), serial_port));
+        }
+        std::this_thread::sleep_for(1s);
+    }
+    device_path = cb_scratch;
+    fb = std::unique_ptr<FastBootDriver>(new FastBootDriver(transport.get(), {}, true));
+}
+
 void FastBootTest::SetLockState(bool unlock, bool assert_change) {
     if (!fb) {
         return;
@@ -197,25 +223,8 @@
         std::string cmd = unlock ? "unlock" : "lock";
         ASSERT_EQ(fb->RawCommand("flashing " + cmd, &resp), SUCCESS)
                 << "Attempting to change locked state, but 'flashing" + cmd + "' command failed";
-        fb.reset();
-        transport.reset();
         printf("PLEASE RESPOND TO PROMPT FOR '%sing' BOOTLOADER ON DEVICE\n", cmd.c_str());
-        while (UsbStillAvailible())
-            ;  // Wait for disconnect
-        printf("WAITING FOR DEVICE");
-        // Need to wait for device
-        const auto matcher = [](usb_ifc_info* info) -> int { return MatchFastboot(info, nullptr); };
-        while (!transport) {
-            std::unique_ptr<UsbTransport> usb(usb_open(matcher, USB_TIMEOUT));
-            if (usb) {
-                transport = std::unique_ptr<UsbTransportSniffer>(
-                        new UsbTransportSniffer(std::move(usb), serial_port));
-            }
-            std::this_thread::sleep_for(std::chrono::milliseconds(1000));
-            putchar('.');
-        }
-        device_path = cb_scratch;
-        fb = std::unique_ptr<FastBootDriver>(new FastBootDriver(transport.get(), {}, true));
+        ReconnectFastbootDevice();
         if (assert_change) {
             ASSERT_EQ(fb->GetVar("unlocked", &resp), SUCCESS) << "getvar:unlocked failed";
             ASSERT_EQ(resp, unlock ? "yes" : "no")
@@ -227,6 +236,7 @@
 
 std::string FastBootTest::device_path = "";
 std::string FastBootTest::cb_scratch = "";
+std::string FastBootTest::initial_slot = "";
 int FastBootTest::serial_port = 0;
 
 template <bool UNLOCKED>
diff --git a/fastboot/fuzzy_fastboot/fixtures.h b/fastboot/fuzzy_fastboot/fixtures.h
index e0f829e..7c8d54d 100644
--- a/fastboot/fuzzy_fastboot/fixtures.h
+++ b/fastboot/fuzzy_fastboot/fixtures.h
@@ -48,6 +48,7 @@
     static int MatchFastboot(usb_ifc_info* info, const char* local_serial = nullptr);
     bool UsbStillAvailible();
     bool UserSpaceFastboot();
+    void ReconnectFastbootDevice();
 
   protected:
     RetCode DownloadCommand(uint32_t size, std::string* response = nullptr,
@@ -69,6 +70,7 @@
     // This is an annoying hack
     static std::string cb_scratch;
     static std::string device_path;
+    static std::string initial_slot;
 };
 
 template <bool UNLOCKED>
@@ -86,6 +88,7 @@
 // differently
 class BasicFunctionality : public ModeTest<true> {};
 class Conformance : public ModeTest<true> {};
+class LogicalPartitionCompliance : public ModeTest<true> {};
 class UnlockPermissions : public ModeTest<true> {};
 class LockPermissions : public ModeTest<false> {};
 
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index ef34771..7ffc7d5 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -177,6 +177,93 @@
     }
 }
 
+// Test commands related to super partition
+TEST_F(LogicalPartitionCompliance, SuperPartition) {
+    ASSERT_TRUE(UserSpaceFastboot());
+    std::string partition_type;
+    // getvar partition-type:super must fail for retrofit devices because the
+    // partition does not exist.
+    if (fb->GetVar("partition-type:super", &partition_type) == SUCCESS) {
+        std::string is_logical;
+        EXPECT_EQ(fb->GetVar("is-logical:super", &is_logical), SUCCESS)
+                << "getvar is-logical:super failed";
+        EXPECT_EQ(is_logical, "no") << "super must not be a logical partition";
+        std::string super_name;
+        EXPECT_EQ(fb->GetVar("super-partition-name", &super_name), SUCCESS)
+                << "'getvar super-partition-name' failed";
+        EXPECT_EQ(super_name, "super") << "'getvar super-partition-name' must return 'super' for "
+                                          "device with a super partition";
+    }
+}
+
+// Test 'fastboot getvar is-logical'
+TEST_F(LogicalPartitionCompliance, GetVarIsLogical) {
+    ASSERT_TRUE(UserSpaceFastboot());
+    std::string has_slot;
+    EXPECT_EQ(fb->GetVar("has-slot:system", &has_slot), SUCCESS) << "getvar has-slot:system failed";
+    std::string is_logical_cmd;
+    if (has_slot == "yes") {
+        std::string current_slot;
+        EXPECT_EQ(fb->GetVar("current-slot", &current_slot), SUCCESS)
+                << "getvar current-slot failed";
+        is_logical_cmd = "is-logical:system_" + current_slot;
+    } else {
+        is_logical_cmd = "is-logical:system";
+    }
+    std::string is_logical;
+    EXPECT_EQ(fb->GetVar(is_logical_cmd, &is_logical), SUCCESS) << "getvar is-logical failed";
+    ASSERT_EQ(is_logical, "yes");
+}
+
+TEST_F(LogicalPartitionCompliance, FastbootRebootTest) {
+    ASSERT_TRUE(UserSpaceFastboot());
+    GTEST_LOG_(INFO) << "Rebooting to bootloader mode";
+    // Test 'fastboot reboot bootloader' from fastbootd
+    fb->RebootTo("bootloader");
+
+    // Test fastboot reboot fastboot from bootloader
+    ReconnectFastbootDevice();
+    ASSERT_FALSE(UserSpaceFastboot());
+    GTEST_LOG_(INFO) << "Rebooting back to fastbootd mode";
+    fb->RebootTo("fastboot");
+
+    ReconnectFastbootDevice();
+    ASSERT_TRUE(UserSpaceFastboot());
+}
+
+// Testing creation/resize/delete of logical partitions
+TEST_F(LogicalPartitionCompliance, CreateResizeDeleteLP) {
+    ASSERT_TRUE(UserSpaceFastboot());
+    GTEST_LOG_(INFO) << "Testing 'fastboot create-logical-partition' command";
+    EXPECT_EQ(fb->CreatePartition("test_partition_a", "0"), SUCCESS)
+            << "create-logical-partition failed";
+    GTEST_LOG_(INFO) << "Testing 'fastboot resize-logical-partition' command";
+    EXPECT_EQ(fb->ResizePartition("test_partition_a", "4096"), SUCCESS)
+            << "resize-logical-partition failed";
+    std::vector<char> buf(4096);
+
+    GTEST_LOG_(INFO) << "Flashing a logical partition..";
+    EXPECT_EQ(fb->FlashPartition("test_partition_a", buf), SUCCESS)
+            << "flash logical -partition failed";
+    GTEST_LOG_(INFO) << "Rebooting to bootloader mode";
+    // Reboot to bootloader mode and attempt to flash the logical partitions
+    fb->RebootTo("bootloader");
+
+    ReconnectFastbootDevice();
+    ASSERT_FALSE(UserSpaceFastboot());
+    GTEST_LOG_(INFO) << "Attempt to flash a logical partition..";
+    EXPECT_EQ(fb->FlashPartition("test_partition", buf), DEVICE_FAIL)
+            << "flash logical partition must fail in bootloader";
+    GTEST_LOG_(INFO) << "Rebooting back to fastbootd mode";
+    fb->RebootTo("fastboot");
+
+    ReconnectFastbootDevice();
+    ASSERT_TRUE(UserSpaceFastboot());
+    GTEST_LOG_(INFO) << "Testing 'fastboot delete-logical-partition' command";
+    EXPECT_EQ(fb->DeletePartition("test_partition_a"), SUCCESS)
+            << "delete logical-partition failed";
+}
+
 // Conformance tests
 TEST_F(Conformance, GetVar) {
     std::string product;
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 272190e..ba6b9eb 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -307,7 +307,7 @@
         return false;
     }
 
-    if (pread(fd, sb, sizeof(*sb), 1024) != sizeof(*sb)) {
+    if (TEMP_FAILURE_RETRY(pread(fd, sb, sizeof(*sb), 1024)) != sizeof(*sb)) {
         PERROR << "Can't read '" << blk_device << "' superblock";
         return false;
     }
@@ -326,6 +326,17 @@
     return true;
 }
 
+// exported silent version of the above that just answer the question is_ext4
+bool fs_mgr_is_ext4(const std::string& blk_device) {
+    android::base::ErrnoRestorer restore;
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(blk_device.c_str(), O_RDONLY | O_CLOEXEC)));
+    if (fd < 0) return false;
+    ext4_super_block sb;
+    if (TEMP_FAILURE_RETRY(pread(fd, &sb, sizeof(sb), 1024)) != sizeof(sb)) return false;
+    if (!is_ext4_superblock_valid(&sb)) return false;
+    return true;
+}
+
 // Some system images do not have tune2fs for licensing reasons.
 // Detect these and skip running it.
 static bool tune2fs_available(void) {
@@ -494,11 +505,12 @@
         return false;
     }
 
-    if (pread(fd, &sb1, sizeof(sb1), F2FS_SUPER_OFFSET) != sizeof(sb1)) {
+    if (TEMP_FAILURE_RETRY(pread(fd, &sb1, sizeof(sb1), F2FS_SUPER_OFFSET)) != sizeof(sb1)) {
         PERROR << "Can't read '" << blk_device << "' superblock1";
         return false;
     }
-    if (pread(fd, &sb2, sizeof(sb2), F2FS_BLKSIZE + F2FS_SUPER_OFFSET) != sizeof(sb2)) {
+    if (TEMP_FAILURE_RETRY(pread(fd, &sb2, sizeof(sb2), F2FS_BLKSIZE + F2FS_SUPER_OFFSET)) !=
+        sizeof(sb2)) {
         PERROR << "Can't read '" << blk_device << "' superblock2";
         return false;
     }
@@ -511,6 +523,23 @@
     return true;
 }
 
+// exported silent version of the above that just answer the question is_f2fs
+bool fs_mgr_is_f2fs(const std::string& blk_device) {
+    android::base::ErrnoRestorer restore;
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(blk_device.c_str(), O_RDONLY | O_CLOEXEC)));
+    if (fd < 0) return false;
+    __le32 sb;
+    if (TEMP_FAILURE_RETRY(pread(fd, &sb, sizeof(sb), F2FS_SUPER_OFFSET)) != sizeof(sb)) {
+        return false;
+    }
+    if (sb == cpu_to_le32(F2FS_SUPER_MAGIC)) return true;
+    if (TEMP_FAILURE_RETRY(pread(fd, &sb, sizeof(sb), F2FS_BLKSIZE + F2FS_SUPER_OFFSET)) !=
+        sizeof(sb)) {
+        return false;
+    }
+    return sb == cpu_to_le32(F2FS_SUPER_MAGIC);
+}
+
 //
 // Prepare the filesystem on the given block device to be mounted.
 //
@@ -1573,6 +1602,14 @@
     return true;
 }
 
+std::string fs_mgr_get_verity_device_name(const FstabEntry& entry) {
+    if (entry.mount_point == "/") {
+        // In AVB, the dm device name is vroot instead of system.
+        return entry.fs_mgr_flags.avb ? "vroot" : "system";
+    }
+    return Basename(entry.mount_point);
+}
+
 bool fs_mgr_is_verity_enabled(const FstabEntry& entry) {
     if (!entry.fs_mgr_flags.verify && !entry.fs_mgr_flags.avb) {
         return false;
@@ -1580,14 +1617,7 @@
 
     DeviceMapper& dm = DeviceMapper::Instance();
 
-    std::string mount_point;
-    if (entry.mount_point == "/") {
-        // In AVB, the dm device name is vroot instead of system.
-        mount_point = entry.fs_mgr_flags.avb ? "vroot" : "system";
-    } else {
-        mount_point = Basename(entry.mount_point);
-    }
-
+    std::string mount_point = fs_mgr_get_verity_device_name(entry);
     if (dm.GetState(mount_point) == DmDeviceState::INVALID) {
         return false;
     }
@@ -1610,6 +1640,27 @@
     return false;
 }
 
+bool fs_mgr_verity_is_check_at_most_once(const android::fs_mgr::FstabEntry& entry) {
+    if (!entry.fs_mgr_flags.verify && !entry.fs_mgr_flags.avb) {
+        return false;
+    }
+
+    DeviceMapper& dm = DeviceMapper::Instance();
+    std::string device = fs_mgr_get_verity_device_name(entry);
+
+    std::vector<DeviceMapper::TargetInfo> table;
+    if (dm.GetState(device) == DmDeviceState::INVALID || !dm.GetTableInfo(device, &table)) {
+        return false;
+    }
+    for (const auto& target : table) {
+        if (strcmp(target.spec.target_type, "verity") == 0 &&
+            target.data.find("check_at_most_once") != std::string::npos) {
+            return true;
+        }
+    }
+    return false;
+}
+
 std::string fs_mgr_get_super_partition_name(int slot) {
     // Devices upgrading to dynamic partitions are allowed to specify a super
     // partition name, assumed to be A/B (non-A/B retrofit is not supported).
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index e61f588..dea4844 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -543,6 +543,10 @@
         if (!fs_mgr_rw_access(device_path)) return false;
     }
 
+    auto f2fs = fs_mgr_is_f2fs(device_path);
+    auto ext4 = fs_mgr_is_ext4(device_path);
+    if (!f2fs && !ext4) return false;
+
     if (setfscreatecon(kOverlayfsFileContext)) {
         PERROR << "setfscreatecon " << kOverlayfsFileContext;
     }
@@ -554,6 +558,8 @@
     entry.blk_device = device_path;
     entry.mount_point = kScratchMountPoint;
     entry.fs_type = mnt_type;
+    if ((mnt_type == "f2fs") && !f2fs) entry.fs_type = "ext4";
+    if ((mnt_type == "ext4") && !ext4) entry.fs_type = "f2fs";
     entry.flags = MS_RELATIME;
     if (readonly) {
         entry.flags |= MS_RDONLY;
@@ -563,12 +569,13 @@
     auto save_errno = errno;
     auto mounted = fs_mgr_do_mount_one(entry) == 0;
     if (!mounted) {
-        if (mnt_type == "f2fs") {
+        if ((entry.fs_type == "f2fs") && ext4) {
             entry.fs_type = "ext4";
-        } else {
+            mounted = fs_mgr_do_mount_one(entry) == 0;
+        } else if ((entry.fs_type == "ext4") && f2fs) {
             entry.fs_type = "f2fs";
+            mounted = fs_mgr_do_mount_one(entry) == 0;
         }
-        mounted = fs_mgr_do_mount_one(entry) == 0;
         if (!mounted) save_errno = errno;
     }
     setfscreatecon(nullptr);
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 166c32b..11602ea 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -100,3 +100,6 @@
 const std::string& get_android_dt_dir();
 bool is_dt_compatible();
 int load_verity_state(const android::fs_mgr::FstabEntry& entry, int* mode);
+
+bool fs_mgr_is_ext4(const std::string& blk_device);
+bool fs_mgr_is_f2fs(const std::string& blk_device);
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index 5c4008c..24044d8 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -80,29 +80,6 @@
     return &(*it);
 }
 
-void try_unmount_bionic(android::fs_mgr::Fstab* mounts) {
-    static constexpr const char* kBionic = "/bionic";
-
-    auto entry = GetEntryForMountPoint(mounts, kBionic);
-    if (!entry) return;
-
-    struct statfs buf;
-    if (::statfs(kBionic, &buf) == -1) {
-        PLOG(ERROR) << "statfs of " << kBionic;
-        return;
-    }
-    if (buf.f_flags & MS_RDONLY) {
-        // /bionic is on a read-only partition; can happen for
-        // non-system-as-root-devices. Don' try to unmount.
-        return;
-    }
-    fs_mgr_set_blk_ro(entry->blk_device, false);
-    if (::mount(entry->blk_device.c_str(), entry->mount_point.c_str(), entry->fs_type.c_str(),
-                MS_REMOUNT, nullptr) == -1) {
-        PLOG(ERROR) << "remount of " << kBionic;
-    }
-}
-
 void MyLogger(android::base::LogId id, android::base::LogSeverity severity, const char* tag,
               const char* file, unsigned int line, const char* message) {
     static const char log_characters[] = "VD\0WEFF";
@@ -199,6 +176,15 @@
         fstab_read = android::fs_mgr::ReadFstabFromFile(fstab_file, &fstab);
     } else {
         fstab_read = android::fs_mgr::ReadDefaultFstab(&fstab);
+        // Manufacture a / entry from /proc/mounts if missing.
+        if (!GetEntryForMountPoint(&fstab, "/system") && !GetEntryForMountPoint(&fstab, "/")) {
+            android::fs_mgr::Fstab mounts;
+            if (android::fs_mgr::ReadFstabFromFile("/proc/mounts", &mounts)) {
+                if (auto entry = GetEntryForMountPoint(&mounts, "/")) {
+                    if (entry->fs_type != "rootfs") fstab.emplace_back(*entry);
+                }
+            }
+        }
     }
     if (!fstab_read || fstab.empty()) {
         PLOG(ERROR) << "Failed to read fstab";
@@ -234,21 +220,21 @@
         // Do we know about the partition?
         auto it = std::find_if(fstab.begin(), fstab.end(), find_part);
         if (it == fstab.end()) {
-            LOG(ERROR) << "Unknown partition " << partition << ", skipping";
+            LOG(ERROR) << "Unknown partition " << argv[optind] << ", skipping";
             retval = UNKNOWN_PARTITION;
             continue;
         }
         // Is that one covered by an existing overlayfs?
         auto wrap = is_wrapped(overlayfs_candidates, *it);
         if (wrap) {
-            LOG(INFO) << "partition " << partition << " covered by overlayfs for "
+            LOG(INFO) << "partition " << argv[optind] << " covered by overlayfs for "
                       << wrap->mount_point << ", switching";
             partition = system_mount_point(*wrap);
         }
         // Is it a remountable partition?
         it = std::find_if(all.begin(), all.end(), find_part);
         if (it == all.end()) {
-            LOG(ERROR) << "Invalid partition " << partition << ", skipping";
+            LOG(ERROR) << "Invalid partition " << argv[optind] << ", skipping";
             retval = INVALID_PARTITION;
             continue;
         }
@@ -395,7 +381,5 @@
 
     if (reboot_later) reboot(false);
 
-    try_unmount_bionic(&mounts);
-
     return retval;
 }
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index a3bb852..8abe609 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -77,6 +77,10 @@
 bool fs_mgr_swapon_all(const android::fs_mgr::Fstab& fstab);
 bool fs_mgr_update_logical_partition(android::fs_mgr::FstabEntry* entry);
 
+// Returns true if the given fstab entry has verity enabled, *and* the verity
+// device is in "check_at_most_once" mode.
+bool fs_mgr_verity_is_check_at_most_once(const android::fs_mgr::FstabEntry& entry);
+
 int fs_mgr_do_format(const android::fs_mgr::FstabEntry& entry, bool reserve_footer);
 
 #define FS_MGR_SETUP_VERITY_SKIPPED  (-3)
diff --git a/fs_mgr/libdm/Android.mk b/fs_mgr/libdm/Android.mk
new file mode 100644
index 0000000..6aedc25
--- /dev/null
+++ b/fs_mgr/libdm/Android.mk
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := VtsKernelLibdmTest
+-include test/vts/tools/build/Android.host_config.mk
diff --git a/fs_mgr/libdm/AndroidTest.xml b/fs_mgr/libdm/AndroidTest.xml
new file mode 100644
index 0000000..b4e0c23
--- /dev/null
+++ b/fs_mgr/libdm/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for VTS VtsKernelLibdmTest">
+    <option name="config-descriptor:metadata" key="plan" value="vts-kernel" />
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+        <option name="abort-on-push-failure" value="false"/>
+        <option name="push-group" value="HostDrivenTest.push"/>
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+      <option name="test-module-name" value="VtsKernelLibdmTest"/>
+        <option name="binary-test-source" value="_32bit::DATA/nativetest/libdm_test/libdm_test" />
+        <option name="binary-test-source" value="_64bit::DATA/nativetest64/libdm_test/libdm_test" />
+        <option name="binary-test-type" value="gtest"/>
+        <option name="test-timeout" value="1m"/>
+        <option name="precondition-first-api-level" value="29" />
+    </test>
+</configuration>
+
diff --git a/fs_mgr/libfiemap_writer/Android.bp b/fs_mgr/libfiemap_writer/Android.bp
index 7463810..32fc3d2 100644
--- a/fs_mgr/libfiemap_writer/Android.bp
+++ b/fs_mgr/libfiemap_writer/Android.bp
@@ -41,6 +41,9 @@
 
 cc_test {
     name: "fiemap_writer_test",
+    cflags: [
+        "-D_FILE_OFFSET_BITS=64",
+    ],
     static_libs: [
         "libbase",
         "libdm",
diff --git a/fs_mgr/libfiemap_writer/fiemap_writer.cpp b/fs_mgr/libfiemap_writer/fiemap_writer.cpp
index 99a1a2f..85589cc 100644
--- a/fs_mgr/libfiemap_writer/fiemap_writer.cpp
+++ b/fs_mgr/libfiemap_writer/fiemap_writer.cpp
@@ -51,6 +51,9 @@
         FIEMAP_EXTENT_NOT_ALIGNED | FIEMAP_EXTENT_DATA_INLINE | FIEMAP_EXTENT_DATA_TAIL |
         FIEMAP_EXTENT_UNWRITTEN | FIEMAP_EXTENT_SHARED | FIEMAP_EXTENT_MERGED;
 
+// Large file support must be enabled.
+static_assert(sizeof(off_t) == sizeof(uint64_t));
+
 static inline void cleanup(const std::string& file_path, bool created) {
     if (created) {
         unlink(file_path.c_str());
@@ -229,6 +232,42 @@
     return true;
 }
 
+static bool FallocateFallback(int file_fd, uint64_t block_size, uint64_t file_size,
+                              const std::string& file_path,
+                              const std::function<bool(uint64_t, uint64_t)>& on_progress) {
+    // Even though this is much faster than writing zeroes, it is still slow
+    // enough that we need to fire the progress callback periodically. To
+    // easily achieve this, we seek in chunks. We use 1000 chunks since
+    // normally we only fire the callback on 1/1000th increments.
+    uint64_t bytes_per_chunk = std::max(file_size / 1000, block_size);
+
+    // Seek just to the end of each chunk and write a single byte, causing
+    // the filesystem to allocate blocks.
+    off_t cursor = 0;
+    off_t end = static_cast<off_t>(file_size);
+    while (cursor < end) {
+        cursor = std::min(static_cast<off_t>(cursor + bytes_per_chunk), end);
+        auto rv = TEMP_FAILURE_RETRY(lseek(file_fd, cursor - 1, SEEK_SET));
+        if (rv < 0) {
+            PLOG(ERROR) << "Failed to lseek " << file_path;
+            return false;
+        }
+        if (rv != cursor - 1) {
+            LOG(ERROR) << "Seek returned wrong offset " << rv << " for file " << file_path;
+            return false;
+        }
+        char buffer[] = {0};
+        if (!android::base::WriteFully(file_fd, buffer, 1)) {
+            PLOG(ERROR) << "Write failed: " << file_path;
+            return false;
+        }
+        if (on_progress && !on_progress(cursor, file_size)) {
+            return false;
+        }
+    }
+    return true;
+}
+
 static bool AllocateFile(int file_fd, const std::string& file_path, uint64_t blocksz,
                          uint64_t file_size, unsigned int fs_type,
                          std::function<bool(uint64_t, uint64_t)> on_progress) {
@@ -245,28 +284,10 @@
                 return false;
             }
             break;
-        case MSDOS_SUPER_MAGIC: {
+        case MSDOS_SUPER_MAGIC:
             // fallocate() is not supported, and not needed, since VFAT does not support holes.
             // Instead we can perform a much faster allocation.
-            auto offset = TEMP_FAILURE_RETRY(lseek(file_fd, file_size - 1, SEEK_SET));
-            if (offset < 0) {
-                PLOG(ERROR) << "Failed to lseek " << file_path;
-                return false;
-            }
-            if (offset != file_size - 1) {
-                LOG(ERROR) << "Seek returned wrong offset " << offset << " for file " << file_path;
-                return false;
-            }
-            char buffer[] = {0};
-            if (!android::base::WriteFully(file_fd, buffer, 1)) {
-                PLOG(ERROR) << "Write failed: " << file_path;
-                return false;
-            }
-            if (on_progress && !on_progress(file_size, file_size)) {
-                return false;
-            }
-            return true;
-        }
+            return FallocateFallback(file_fd, blocksz, file_size, file_path, on_progress);
         default:
             LOG(ERROR) << "Missing fallocate() support for file system " << fs_type;
             return false;
@@ -288,16 +309,19 @@
     }
 
     int permille = -1;
-    for (; offset < file_size; offset += blocksz) {
+    while (offset < file_size) {
         if (!::android::base::WriteFully(file_fd, buffer.get(), blocksz)) {
             PLOG(ERROR) << "Failed to write" << blocksz << " bytes at offset" << offset
                         << " in file " << file_path;
             return false;
         }
+
+        offset += blocksz;
+
         // Don't invoke the callback every iteration - wait until a significant
         // chunk (here, 1/1000th) of the data has been processed.
         int new_permille = (static_cast<uint64_t>(offset) * 1000) / file_size;
-        if (new_permille != permille) {
+        if (new_permille != permille && static_cast<uint64_t>(offset) != file_size) {
             if (on_progress && !on_progress(offset, file_size)) {
                 return false;
             }
@@ -483,7 +507,17 @@
         return false;
     }
 
-    uint64_t num_blocks = (s.st_size + s.st_blksize - 1) / s.st_blksize;
+    unsigned int blksize;
+    if (ioctl(file_fd, FIGETBSZ, &blksize) < 0) {
+        PLOG(ERROR) << "Failed to get FIGETBSZ for " << file_path;
+        return false;
+    }
+    if (!blksize) {
+        LOG(ERROR) << "Invalid filesystem block size: " << blksize;
+        return false;
+    }
+
+    uint64_t num_blocks = (s.st_size + blksize - 1) / blksize;
     if (num_blocks > std::numeric_limits<uint32_t>::max()) {
         LOG(ERROR) << "Too many blocks for FIBMAP (" << num_blocks << ")";
         return false;
@@ -501,11 +535,11 @@
         }
 
         if (!extents->empty() && block == last_block + 1) {
-            extents->back().fe_length++;
+            extents->back().fe_length += blksize;
         } else {
             extents->push_back(fiemap_extent{.fe_logical = block_number,
-                                             .fe_physical = block,
-                                             .fe_length = 1,
+                                             .fe_physical = static_cast<uint64_t>(block) * blksize,
+                                             .fe_length = static_cast<uint64_t>(blksize),
                                              .fe_flags = 0});
         }
         last_block = block;
diff --git a/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp b/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
index 66eb9ae..ca51689 100644
--- a/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
+++ b/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
@@ -108,28 +108,29 @@
     EXPECT_EQ(access(testfile.c_str(), F_OK), 0);
 }
 
+TEST_F(FiemapWriterTest, CheckFileSize) {
+    // Create a large-ish file and test that the expected size matches.
+    FiemapUniquePtr fptr = FiemapWriter::Open(testfile, 1024 * 1024 * 16);
+    ASSERT_NE(fptr, nullptr);
+
+    struct stat s;
+    ASSERT_EQ(stat(testfile.c_str(), &s), 0);
+    EXPECT_EQ(static_cast<uint64_t>(s.st_size), fptr->size());
+}
+
 TEST_F(FiemapWriterTest, CheckProgress) {
     std::vector<uint64_t> expected;
     size_t invocations = 0;
     auto callback = [&](uint64_t done, uint64_t total) -> bool {
-        EXPECT_LT(invocations, expected.size());
+        if (invocations >= expected.size()) {
+            return false;
+        }
         EXPECT_EQ(done, expected[invocations]);
         EXPECT_EQ(total, gBlockSize);
         invocations++;
         return true;
     };
 
-    uint32_t fs_type;
-    {
-        auto ptr = FiemapWriter::Open(testfile, gBlockSize, true);
-        ASSERT_NE(ptr, nullptr);
-        fs_type = ptr->fs_type();
-    }
-    ASSERT_EQ(unlink(testfile.c_str()), 0);
-
-    if (fs_type != MSDOS_SUPER_MAGIC) {
-        expected.push_back(0);
-    }
     expected.push_back(gBlockSize);
 
     auto ptr = FiemapWriter::Open(testfile, gBlockSize, true, std::move(callback));
@@ -163,7 +164,7 @@
 
     struct stat sb;
     ASSERT_EQ(stat(testfile.c_str(), &sb), 0);
-    EXPECT_EQ(sb.st_size, testfile_size);
+    EXPECT_GE(sb.st_size, testfile_size);
 }
 
 TEST_F(FiemapWriterTest, CheckFileExtents) {
@@ -195,6 +196,61 @@
     ASSERT_GT(DetermineMaximumFileSize(testfile), 0);
 }
 
+TEST_F(FiemapWriterTest, FibmapBlockAddressing) {
+    FiemapUniquePtr fptr = FiemapWriter::Open(testfile, gBlockSize);
+    ASSERT_NE(fptr, nullptr);
+
+    switch (fptr->fs_type()) {
+        case F2FS_SUPER_MAGIC:
+        case EXT4_SUPER_MAGIC:
+            // Skip the test for FIEMAP supported filesystems. This is really
+            // because f2fs/ext4 have caches that seem to defeat reading back
+            // directly from the block device, and writing directly is too
+            // dangerous.
+            std::cout << "Skipping test, filesystem does not use FIBMAP\n";
+            return;
+    }
+
+    bool uses_dm;
+    std::string bdev_path;
+    ASSERT_TRUE(FiemapWriter::GetBlockDeviceForFile(testfile, &bdev_path, &uses_dm));
+
+    if (uses_dm) {
+        // We could use a device-mapper wrapper here to bypass encryption, but
+        // really this test is for FIBMAP correctness on VFAT (where encryption
+        // is never used), so we don't bother.
+        std::cout << "Skipping test, block device is metadata encrypted\n";
+        return;
+    }
+
+    std::string data(fptr->size(), '\0');
+    for (size_t i = 0; i < data.size(); i++) {
+        data[i] = 'A' + static_cast<char>(data.size() % 26);
+    }
+
+    {
+        unique_fd fd(open(testfile.c_str(), O_WRONLY | O_CLOEXEC));
+        ASSERT_GE(fd, 0);
+        ASSERT_TRUE(android::base::WriteFully(fd, data.data(), data.size()));
+        ASSERT_EQ(fsync(fd), 0);
+    }
+
+    ASSERT_FALSE(fptr->extents().empty());
+    const auto& first_extent = fptr->extents()[0];
+
+    unique_fd bdev(open(fptr->bdev_path().c_str(), O_RDONLY | O_CLOEXEC));
+    ASSERT_GE(bdev, 0);
+
+    off_t where = first_extent.fe_physical;
+    ASSERT_EQ(lseek(bdev, where, SEEK_SET), where);
+
+    // Note: this will fail on encrypted folders.
+    std::string actual(data.size(), '\0');
+    ASSERT_GE(first_extent.fe_length, data.size());
+    ASSERT_TRUE(android::base::ReadFully(bdev, actual.data(), actual.size()));
+    EXPECT_EQ(memcmp(actual.data(), data.data(), data.size()), 0);
+}
+
 TEST_F(SplitFiemapTest, Create) {
     auto ptr = SplitFiemap::Create(testfile, 1024 * 768, 1024 * 32);
     ASSERT_NE(ptr, nullptr);
@@ -227,7 +283,7 @@
 }
 
 TEST_F(SplitFiemapTest, DeleteOnFail) {
-    auto ptr = SplitFiemap::Create(testfile, 1024 * 1024 * 10, 1);
+    auto ptr = SplitFiemap::Create(testfile, 1024 * 1024 * 100, 1);
     ASSERT_EQ(ptr, nullptr);
 
     std::string first_file = testfile + ".0001";
@@ -445,7 +501,7 @@
     if (argc <= 1) {
         cerr << "Usage: <test_dir> [file_size]\n";
         cerr << "\n";
-        cerr << "Note: test_dir must be a writable directory.\n";
+        cerr << "Note: test_dir must be a writable, unencrypted directory.\n";
         exit(EXIT_FAILURE);
     }
     ::android::base::InitLogging(argv, ::android::base::StderrLogger);
diff --git a/fs_mgr/libfiemap_writer/include/libfiemap_writer/split_fiemap_writer.h b/fs_mgr/libfiemap_writer/include/libfiemap_writer/split_fiemap_writer.h
index 07f3c10..7b977e1 100644
--- a/fs_mgr/libfiemap_writer/include/libfiemap_writer/split_fiemap_writer.h
+++ b/fs_mgr/libfiemap_writer/include/libfiemap_writer/split_fiemap_writer.h
@@ -69,6 +69,7 @@
     const std::vector<struct fiemap_extent>& extents();
     uint32_t block_size() const;
     uint64_t size() const { return total_size_; }
+    const std::string& bdev_path() const;
 
     // Non-copyable & Non-movable
     SplitFiemap(const SplitFiemap&) = delete;
diff --git a/fs_mgr/libfiemap_writer/split_fiemap_writer.cpp b/fs_mgr/libfiemap_writer/split_fiemap_writer.cpp
index dbb67a8..a0ccc10 100644
--- a/fs_mgr/libfiemap_writer/split_fiemap_writer.cpp
+++ b/fs_mgr/libfiemap_writer/split_fiemap_writer.cpp
@@ -289,5 +289,9 @@
     return files_[0]->block_size();
 }
 
+const std::string& SplitFiemap::bdev_path() const {
+    return files_[0]->bdev_path();
+}
+
 }  // namespace fiemap_writer
 }  // namespace android
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index 355b7a1..7039994 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -43,6 +43,11 @@
         windows: {
             enabled: true,
         },
+        android: {
+            shared_libs: [
+                "libcutils",
+            ],
+        },
     },
     export_include_dirs: ["include"],
 }
diff --git a/fs_mgr/liblp/Android.mk b/fs_mgr/liblp/Android.mk
new file mode 100644
index 0000000..7f7f891
--- /dev/null
+++ b/fs_mgr/liblp/Android.mk
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := VtsKernelLiblpTest
+-include test/vts/tools/build/Android.host_config.mk
diff --git a/fs_mgr/liblp/AndroidTest.xml b/fs_mgr/liblp/AndroidTest.xml
new file mode 100644
index 0000000..007a302
--- /dev/null
+++ b/fs_mgr/liblp/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for VTS VtsKernelLiblpTest">
+    <option name="config-descriptor:metadata" key="plan" value="vts-kernel" />
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+        <option name="abort-on-push-failure" value="false"/>
+        <option name="push-group" value="HostDrivenTest.push"/>
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+      <option name="test-module-name" value="VtsKernelLiblpTest"/>
+        <option name="binary-test-source" value="_32bit::DATA/nativetest/liblp_test/liblp_test" />
+        <option name="binary-test-source" value="_64bit::DATA/nativetest64/liblp_test/liblp_test" />
+        <option name="binary-test-type" value="gtest"/>
+        <option name="test-timeout" value="1m"/>
+        <option name="precondition-first-api-level" value="29" />
+    </test>
+</configuration>
+
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index ebd6997..27222af 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -591,11 +591,25 @@
         free_regions = PrioritizeSecondHalfOfSuper(free_regions);
     }
 
-    // Find gaps that we can use for new extents. Note we store new extents in a
-    // temporary vector, and only commit them if we are guaranteed enough free
-    // space.
+    // Note we store new extents in a temporary vector, and only commit them
+    // if we are guaranteed enough free space.
     std::vector<std::unique_ptr<LinearExtent>> new_extents;
+
+    // If the last extent in the partition has a size < alignment, then the
+    // difference is unallocatable due to being misaligned. We peek for that
+    // case here to avoid wasting space.
+    if (auto extent = ExtendFinalExtent(partition, free_regions, sectors_needed)) {
+        sectors_needed -= extent->num_sectors();
+        new_extents.emplace_back(std::move(extent));
+    }
+
     for (auto& region : free_regions) {
+        // Note: this comes first, since we may enter the loop not needing any
+        // more sectors.
+        if (!sectors_needed) {
+            break;
+        }
+
         if (region.length() % sectors_per_block != 0) {
             // This should never happen, because it would imply that we
             // once allocated an extent that was not a multiple of the
@@ -613,22 +627,10 @@
         }
 
         uint64_t sectors = std::min(sectors_needed, region.length());
-        if (sectors < region.length()) {
-            const auto& block_device = block_devices_[region.device_index];
-            if (block_device.alignment) {
-                const uint64_t alignment = block_device.alignment / LP_SECTOR_SIZE;
-                sectors = AlignTo(sectors, alignment);
-                sectors = std::min(sectors, region.length());
-            }
-        }
         CHECK(sectors % sectors_per_block == 0);
 
         auto extent = std::make_unique<LinearExtent>(sectors, region.device_index, region.start);
         new_extents.push_back(std::move(extent));
-        if (sectors >= sectors_needed) {
-            sectors_needed = 0;
-            break;
-        }
         sectors_needed -= sectors;
     }
     if (sectors_needed) {
@@ -677,6 +679,64 @@
     return second_half;
 }
 
+std::unique_ptr<LinearExtent> MetadataBuilder::ExtendFinalExtent(
+        Partition* partition, const std::vector<Interval>& free_list,
+        uint64_t sectors_needed) const {
+    if (partition->extents().empty()) {
+        return nullptr;
+    }
+    LinearExtent* extent = partition->extents().back()->AsLinearExtent();
+    if (!extent) {
+        return nullptr;
+    }
+
+    // If the sector ends where the next aligned chunk begins, then there's
+    // no missing gap to try and allocate.
+    const auto& block_device = block_devices_[extent->device_index()];
+    uint64_t next_aligned_sector = AlignSector(block_device, extent->end_sector());
+    if (extent->end_sector() == next_aligned_sector) {
+        return nullptr;
+    }
+
+    uint64_t num_sectors = std::min(next_aligned_sector - extent->end_sector(), sectors_needed);
+    auto new_extent = std::make_unique<LinearExtent>(num_sectors, extent->device_index(),
+                                                     extent->end_sector());
+    if (IsAnyRegionAllocated(*new_extent.get()) ||
+        IsAnyRegionCovered(free_list, *new_extent.get())) {
+        LERROR << "Misaligned region " << new_extent->physical_sector() << ".."
+               << new_extent->end_sector() << " was allocated or marked allocatable.";
+        return nullptr;
+    }
+    return new_extent;
+}
+
+bool MetadataBuilder::IsAnyRegionCovered(const std::vector<Interval>& regions,
+                                         const LinearExtent& candidate) const {
+    for (const auto& region : regions) {
+        if (region.device_index == candidate.device_index() &&
+            (candidate.OwnsSector(region.start) || candidate.OwnsSector(region.end))) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool MetadataBuilder::IsAnyRegionAllocated(const LinearExtent& candidate) const {
+    for (const auto& partition : partitions_) {
+        for (const auto& extent : partition->extents()) {
+            LinearExtent* linear = extent->AsLinearExtent();
+            if (!linear || linear->device_index() != candidate.device_index()) {
+                continue;
+            }
+            if (linear->OwnsSector(candidate.physical_sector()) ||
+                linear->OwnsSector(candidate.end_sector() - 1)) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
 void MetadataBuilder::ShrinkPartition(Partition* partition, uint64_t aligned_size) {
     partition->ShrinkTo(aligned_size);
 }
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index 81305b3..46bfe92 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -209,8 +209,8 @@
         ASSERT_TRUE(builder->ResizePartition(a, a->size() + 4096));
         ASSERT_TRUE(builder->ResizePartition(b, b->size() + 4096));
     }
-    EXPECT_EQ(a->size(), 7864320);
-    EXPECT_EQ(b->size(), 7864320);
+    EXPECT_EQ(a->size(), 40960);
+    EXPECT_EQ(b->size(), 40960);
 
     unique_ptr<LpMetadata> exported = builder->Export();
     ASSERT_NE(exported, nullptr);
@@ -218,7 +218,7 @@
     // Check that each starting sector is aligned.
     for (const auto& extent : exported->extents) {
         ASSERT_EQ(extent.target_type, LP_TARGET_TYPE_LINEAR);
-        EXPECT_EQ(extent.num_sectors, 1536);
+        EXPECT_EQ(extent.num_sectors, 80);
 
         uint64_t lba = extent.target_data * LP_SECTOR_SIZE;
         uint64_t aligned_lba = AlignTo(lba, device_info.alignment, device_info.alignment_offset);
@@ -226,7 +226,7 @@
     }
 
     // Sanity check one extent.
-    EXPECT_EQ(exported->extents.back().target_data, 30656);
+    EXPECT_EQ(exported->extents.back().target_data, 3008);
 }
 
 TEST_F(BuilderTest, UseAllDiskSpace) {
@@ -698,7 +698,7 @@
     EXPECT_EQ(metadata->extents[1].target_type, LP_TARGET_TYPE_LINEAR);
     EXPECT_EQ(metadata->extents[1].target_data, 1472);
     EXPECT_EQ(metadata->extents[1].target_source, 1);
-    EXPECT_EQ(metadata->extents[2].num_sectors, 129600);
+    EXPECT_EQ(metadata->extents[2].num_sectors, 129088);
     EXPECT_EQ(metadata->extents[2].target_type, LP_TARGET_TYPE_LINEAR);
     EXPECT_EQ(metadata->extents[2].target_data, 1472);
     EXPECT_EQ(metadata->extents[2].target_source, 2);
@@ -805,7 +805,7 @@
     EXPECT_EQ(exported->extents[0].target_data, 10487808);
     EXPECT_EQ(exported->extents[0].num_sectors, 10483712);
     EXPECT_EQ(exported->extents[1].target_data, 6292992);
-    EXPECT_EQ(exported->extents[1].num_sectors, 2099712);
+    EXPECT_EQ(exported->extents[1].num_sectors, 2099200);
     EXPECT_EQ(exported->extents[2].target_data, 1536);
     EXPECT_EQ(exported->extents[2].num_sectors, 6291456);
 }
@@ -821,7 +821,7 @@
     ASSERT_NE(vendor, nullptr);
     ASSERT_TRUE(builder->ResizePartition(system, device_info.alignment + 4096));
     ASSERT_TRUE(builder->ResizePartition(vendor, device_info.alignment));
-    ASSERT_EQ(system->size(), device_info.alignment * 2);
+    ASSERT_EQ(system->size(), device_info.alignment + 4096);
     ASSERT_EQ(vendor->size(), device_info.alignment);
 
     ASSERT_TRUE(builder->ResizePartition(system, device_info.alignment * 2));
diff --git a/fs_mgr/liblp/images.cpp b/fs_mgr/liblp/images.cpp
index 5a498f9..56b5353 100644
--- a/fs_mgr/liblp/images.cpp
+++ b/fs_mgr/liblp/images.cpp
@@ -68,7 +68,7 @@
 }
 
 std::unique_ptr<LpMetadata> ReadFromImageFile(const std::string& image_file) {
-    unique_fd fd(open(image_file.c_str(), O_RDONLY | O_CLOEXEC));
+    unique_fd fd = GetControlFileOrOpen(image_file.c_str(), O_RDONLY | O_CLOEXEC);
     if (fd < 0) {
         PERROR << __PRETTY_FUNCTION__ << " open failed: " << image_file;
         return nullptr;
@@ -408,7 +408,7 @@
 }
 
 int SparseBuilder::OpenImageFile(const std::string& file) {
-    android::base::unique_fd source_fd(open(file.c_str(), O_RDONLY | O_CLOEXEC));
+    android::base::unique_fd source_fd = GetControlFileOrOpen(file.c_str(), O_RDONLY | O_CLOEXEC);
     if (source_fd < 0) {
         PERROR << "open image file failed: " << file;
         return -1;
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index 486a71f..c706f2a 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -66,6 +66,10 @@
     uint64_t end_sector() const { return physical_sector_ + num_sectors_; }
     uint32_t device_index() const { return device_index_; }
 
+    bool OwnsSector(uint64_t sector) const {
+        return sector >= physical_sector_ && sector < end_sector();
+    }
+
   private:
     uint32_t device_index_;
     uint64_t physical_sector_;
@@ -322,9 +326,15 @@
         }
     };
     std::vector<Interval> GetFreeRegions() const;
+    bool IsAnyRegionCovered(const std::vector<Interval>& regions,
+                            const LinearExtent& candidate) const;
+    bool IsAnyRegionAllocated(const LinearExtent& candidate) const;
     void ExtentsToFreeList(const std::vector<Interval>& extents,
                            std::vector<Interval>* free_regions) const;
     std::vector<Interval> PrioritizeSecondHalfOfSuper(const std::vector<Interval>& free_list);
+    std::unique_ptr<LinearExtent> ExtendFinalExtent(Partition* partition,
+                                                    const std::vector<Interval>& free_list,
+                                                    uint64_t sectors_needed) const;
 
     static bool sABOverrideValue;
     static bool sABOverrideSet;
diff --git a/fs_mgr/liblp/partition_opener.cpp b/fs_mgr/liblp/partition_opener.cpp
index 898f241..bb8ec9c 100644
--- a/fs_mgr/liblp/partition_opener.cpp
+++ b/fs_mgr/liblp/partition_opener.cpp
@@ -45,7 +45,7 @@
 
 bool GetBlockDeviceInfo(const std::string& block_device, BlockDeviceInfo* device_info) {
 #if defined(__linux__)
-    unique_fd fd(open(block_device.c_str(), O_RDONLY));
+    unique_fd fd = GetControlFileOrOpen(block_device.c_str(), O_RDONLY);
     if (fd < 0) {
         PERROR << __PRETTY_FUNCTION__ << "open '" << block_device << "' failed";
         return false;
@@ -85,7 +85,7 @@
 
 unique_fd PartitionOpener::Open(const std::string& partition_name, int flags) const {
     std::string path = GetPartitionAbsolutePath(partition_name);
-    return unique_fd{open(path.c_str(), flags | O_CLOEXEC)};
+    return GetControlFileOrOpen(path.c_str(), flags | O_CLOEXEC);
 }
 
 bool PartitionOpener::GetInfo(const std::string& partition_name, BlockDeviceInfo* info) const {
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index ecf94a4..72a3c57 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -28,6 +28,10 @@
 #include <ext4_utils/ext4_utils.h>
 #include <openssl/sha.h>
 
+#ifdef __ANDROID__
+#include <cutils/android_get_control_file.h>
+#endif
+
 #include "utility.h"
 
 namespace android {
@@ -171,5 +175,19 @@
 #endif
 }
 
+base::unique_fd GetControlFileOrOpen(const char* path, int flags) {
+#if defined(__ANDROID__)
+    int fd = android_get_control_file(path);
+    if (fd >= 0) {
+        int newfd = TEMP_FAILURE_RETRY(dup(fd));
+        if (newfd >= 0) {
+            return base::unique_fd(newfd);
+        }
+        PERROR << "Cannot dup fd for already controlled file: " << path << ", reopening...";
+    }
+#endif
+    return base::unique_fd(open(path, flags));
+}
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/liblp/utility.h b/fs_mgr/liblp/utility.h
index e8b2ca9..96f1717 100644
--- a/fs_mgr/liblp/utility.h
+++ b/fs_mgr/liblp/utility.h
@@ -22,6 +22,7 @@
 #include <sys/types.h>
 
 #include <android-base/logging.h>
+#include <android-base/unique_fd.h>
 
 #include "liblp/liblp.h"
 
@@ -92,6 +93,8 @@
 // Call BLKROSET ioctl on fd so that fd is readonly / read-writable.
 bool SetBlockReadonly(int fd, bool readonly);
 
+::android::base::unique_fd GetControlFileOrOpen(const char* path, int flags);
+
 }  // namespace fs_mgr
 }  // namespace android
 
diff --git a/fs_mgr/tests/Android.bp b/fs_mgr/tests/Android.bp
index 19737fe..eb9f525 100644
--- a/fs_mgr/tests/Android.bp
+++ b/fs_mgr/tests/Android.bp
@@ -52,6 +52,14 @@
     host_supported: true,
 }
 
+sh_test {
+    name: "adb-remount-sh",
+    src: "adb-remount-test.sh",
+    filename: "adb-remount-test.sh",
+    test_suites: ["general-tests"],
+    test_config: "adb-remount-sh.xml",
+}
+
 java_test_host {
     name: "fs_mgr_vendor_overlay_test",
 
diff --git a/fs_mgr/tests/adb-remount-sh.xml b/fs_mgr/tests/adb-remount-sh.xml
new file mode 100644
index 0000000..716e324
--- /dev/null
+++ b/fs_mgr/tests/adb-remount-sh.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<configuration description="Config for adb remount test cases">
+    <option name="test-suite-tag" value="adb-remount" />
+    <!-- This test requires a device, so it's not annotated with a null-device -->
+    <test class="com.android.tradefed.testtype.binary.ExecutableHostTest" >
+        <option name="binary" value="adb-remount-test.sh" />
+    </test>
+</configuration>
+
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index bd5a4fe..c09dc3d 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -447,59 +447,71 @@
   exit 1
 }
 
-[ "USAGE: EXPECT_EQ <lval> <rval> [message]
+[ "USAGE: EXPECT_EQ <lval> <rval> [--warning [message]]
 
 Returns true if (regex) lval matches rval" ]
 EXPECT_EQ() {
   local lval="${1}"
   local rval="${2}"
   shift 2
+  local error=1
+  local prefix="${RED}[    ERROR ]${NORMAL}"
+  if [ X"${1}" = X"--warning" ]; then
+      prefix="${RED}[  WARNING ]${NORMAL}"
+      error=0
+      shift 1
+  fi
   if ! ( echo X"${rval}" | grep '^X'"${lval}"'$' >/dev/null 2>/dev/null ); then
     if [ `echo ${lval}${rval}${*} | wc -c` -gt 50 -o "${rval}" != "${rval%
 *}" ]; then
-      echo "ERROR: expected \"${lval}\"" >&2
-      echo "       got \"${rval}\"" |
+      echo "${prefix} expected \"${lval}\"" >&2
+      echo "${prefix} got \"${rval}\"" |
         sed ': again
              N
              s/\(\n\)\([^ ]\)/\1             \2/
              t again' >&2
       if [ -n "${*}" ] ; then
-        echo "       ${*}" >&2
+        echo "${prefix} ${*}" >&2
       fi
     else
-      echo "ERROR: expected \"${lval}\" got \"${rval}\" ${*}" >&2
+      echo "${prefix} expected \"${lval}\" got \"${rval}\" ${*}" >&2
     fi
-    return 1
+    return ${error}
   fi
   if [ -n "${*}" ] ; then
-    if [ X"${lval}" != X"${rval}" ]; then
+    prefix="${GREEN}[     INFO ]${NORMAL}"
+    if [ X"${lval}" != X"${rval}" ]; then  # we were supplied a regex?
       if [ `echo ${lval}${rval}${*} | wc -c` -gt 60 -o "${rval}" != "${rval% *}" ]; then
-        echo "INFO: ok \"${lval}\"" >&2
+        echo "${prefix} ok \"${lval}\"" >&2
         echo "       = \"${rval}\"" |
           sed ': again
                N
                s/\(\n\)\([^ ]\)/\1          \2/
                t again' >&2
         if [ -n "${*}" ] ; then
-          echo "      ${*}" >&2
+          echo "${prefix} ${*}" >&2
         fi
       else
-        echo "INFO: ok \"${lval}\" = \"${rval}\" ${*}" >&2
+        echo "${prefix} ok \"${lval}\" = \"${rval}\" ${*}" >&2
       fi
     else
-      echo "INFO: ok \"${lval}\" ${*}" >&2
+      echo "${prefix} ok \"${lval}\" ${*}" >&2
     fi
   fi
   return 0
 }
 
-[ "USAGE: check_eq <lval> <rval> [message]
+[ "USAGE: check_eq <lval> <rval> [--warning [message]]
 
 Exits if (regex) lval mismatches rval" ]
 check_eq() {
   local lval="${1}"
   local rval="${2}"
   shift 2
+  if [ X"${1}" = X"--warning" ]; then
+      EXPECT_EQ "${lval}" "${rval}" ${*}
+      return
+  fi
   EXPECT_EQ "${lval}" "${rval}" ||
     die "${@}"
 }
@@ -514,8 +526,8 @@
     cat -
   fi |
   grep -v \
-    -e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\) " \
-    -e "^\(bpf\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\) " \
+    -e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\|bpf\) " \
+    -e "^\(binfmt_misc\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\) " \
     -e "^\(/data/media\|/dev/block/loop[0-9]*\) " \
     -e "^rootfs / rootfs rw," \
     -e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|persist\|metadata\) "
@@ -608,7 +620,7 @@
 
 D=`get_property ro.serialno`
 [ -n "${D}" ] || D=`get_property ro.boot.serialno`
-[ -z "${D}" ] || ANDROID_SERIAL=${D}
+[ -z "${D}" -o -n "${ANDROID_SERIAL}" ] || ANDROID_SERIAL=${D}
 USB_SERIAL=
 [ -z "${ANDROID_SERIAL}" ] || USB_SERIAL=`find /sys/devices -name serial |
                                           grep usb |
@@ -951,7 +963,7 @@
 
 adb_reboot &&
   adb_wait 2m ||
-  die "reboot after override content added failed"
+  die "reboot after override content added failed `usb_status`"
 
 if ${overlayfs_needed}; then
   D=`adb_su df -k </dev/null` &&
@@ -998,8 +1010,14 @@
 echo "${GREEN}[ RUN      ]${NORMAL} flash vendor, confirm its content disappears" >&2
 
 H=`adb_sh echo '${HOSTNAME}' </dev/null 2>/dev/null`
+is_bootloader_fastboot=false
+# cuttlefish?
+[ X"${H}" != X"${H#vsoc}" ] || is_bootloader_fastboot=true
 is_userspace_fastboot=false
-if [ -z "${ANDROID_PRODUCT_OUT}" ]; then
+
+if ! ${is_bootloader_fastboot}; then
+  echo "${ORANGE}[  WARNING ]${NORMAL} does not support fastboot, skipping"
+elif [ -z "${ANDROID_PRODUCT_OUT}" ]; then
   echo "${ORANGE}[  WARNING ]${NORMAL} build tree not setup, skipping"
 elif [ ! -s "${ANDROID_PRODUCT_OUT}/vendor.img" ]; then
   echo "${ORANGE}[  WARNING ]${NORMAL} vendor image missing, skipping"
@@ -1079,14 +1097,9 @@
     check_eq "cat: /vendor/hello: No such file or directory" "${B}" \
              vendor content after flash vendor
   else
-    (
-      echo "${ORANGE}[  WARNING ]${NORMAL} user fastboot missing required to invalidate, ignoring a failure" >&2
-      restore() {
-        true
-      }
-      check_eq "cat: /vendor/hello: No such file or directory" "${B}" \
-               vendor content after flash vendor
-    )
+    echo "${ORANGE}[  WARNING ]${NORMAL} user fastboot missing required to invalidate, ignoring a failure" >&2
+    check_eq "cat: /vendor/hello: No such file or directory" "${B}" \
+             --warning vendor content after flash vendor
   fi
 fi
 
diff --git a/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp
index 63661f0..9309aad 100644
--- a/fs_mgr/tools/dmctl.cpp
+++ b/fs_mgr/tools/dmctl.cpp
@@ -316,7 +316,7 @@
 
     DeviceMapper& dm = DeviceMapper::Instance();
     std::vector<DeviceMapper::TargetInfo> table;
-    if (!dm.GetTableStatus(argv[0], &table)) {
+    if (!dm.GetTableInfo(argv[0], &table)) {
         std::cerr << "Could not query table status of device \"" << argv[0] << "\"." << std::endl;
         return -EINVAL;
     }
diff --git a/healthd/Android.bp b/healthd/Android.bp
index 6b00f81..2cf6be9 100644
--- a/healthd/Android.bp
+++ b/healthd/Android.bp
@@ -84,3 +84,29 @@
         "manifest_healthd.xml"
     ],
 }
+
+cc_library_static {
+    name: "libhealthd_charger_nops",
+
+    srcs: [
+        "healthd_mode_charger_nops.cpp",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    header_libs: [
+        "libhealthd_headers",
+    ],
+
+    static_libs: [
+        "android.hardware.health@2.0-impl",
+    ],
+
+    shared_libs: [
+        "android.hardware.health@2.0",
+        "libutils",
+    ],
+}
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 823ed06..d18f15a 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -2,14 +2,14 @@
 
 LOCAL_PATH := $(call my-dir)
 
+### libhealthd_draw ###
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := libhealthd_draw
 
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-LOCAL_STATIC_LIBRARIES := \
-	libminui \
-	libbase
+LOCAL_STATIC_LIBRARIES := libminui
+LOCAL_SHARED_LIBRARIES := libbase
 LOCAL_SRC_FILES := healthd_draw.cpp
 
 ifneq ($(TARGET_HEALTHD_DRAW_SPLIT_SCREEN),)
@@ -28,6 +28,7 @@
 
 include $(BUILD_STATIC_LIBRARY)
 
+### libhealthd_charger ###
 include $(CLEAR_VARS)
 
 LOCAL_CFLAGS := -Werror
@@ -49,24 +50,22 @@
     $(LOCAL_PATH)/include
 
 LOCAL_STATIC_LIBRARIES := \
-    android.hardware.health@2.0 \
     android.hardware.health@2.0-impl \
-    android.hardware.health@1.0 \
     android.hardware.health@1.0-convert \
     libhealthstoragedefault \
+    libhealthd_draw \
     libminui \
-    libpng \
-    libz \
-    libutils \
+
+LOCAL_SHARED_LIBRARIES := \
+    android.hardware.health@2.0 \
     libbase \
     libcutils \
-    libhealthd_draw \
     liblog \
-    libm \
-    libc \
+    libpng \
+    libutils \
 
 ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
-LOCAL_STATIC_LIBRARIES += libsuspend
+LOCAL_SHARED_LIBRARIES += libsuspend
 endif
 
 include $(BUILD_STATIC_LIBRARY)
@@ -81,10 +80,6 @@
     charger.cpp \
 
 LOCAL_MODULE := charger
-LOCAL_MODULE_TAGS := optional
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
-LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 
 LOCAL_CFLAGS := -Werror
@@ -94,8 +89,6 @@
 
 CHARGER_STATIC_LIBRARIES := \
     android.hardware.health@2.0-impl \
-    android.hardware.health@2.0 \
-    android.hardware.health@1.0 \
     android.hardware.health@1.0-convert \
     libbinderthreadstate \
     libhidltransport \
@@ -104,54 +97,97 @@
     libhealthstoragedefault \
     libvndksupport \
     libhealthd_charger \
+    libhealthd_charger_nops \
     libhealthd_draw \
     libbatterymonitor \
+
+CHARGER_SHARED_LIBRARIES := \
+    android.hardware.health@2.0 \
     libbase \
-    libutils \
     libcutils \
     libjsoncpp \
     libprocessgroup \
     liblog \
-    libm \
-    libc \
-
-LOCAL_STATIC_LIBRARIES := $(CHARGER_STATIC_LIBRARIES)
+    libutils \
 
 ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
-LOCAL_STATIC_LIBRARIES += \
-    libminui \
-    libpng \
-    libz \
-
+CHARGER_STATIC_LIBRARIES += libminui
+CHARGER_SHARED_LIBRARIES += libpng
 endif
 
 ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
-LOCAL_STATIC_LIBRARIES += libsuspend
+CHARGER_SHARED_LIBRARIES += libsuspend
 endif
 
+LOCAL_STATIC_LIBRARIES := $(CHARGER_STATIC_LIBRARIES)
+LOCAL_SHARED_LIBRARIES := $(CHARGER_SHARED_LIBRARIES)
+
 LOCAL_HAL_STATIC_LIBRARIES := libhealthd
 
-# Symlink /charger to /sbin/charger
+# Symlink /charger to /system/bin/charger
 LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT) \
-    && ln -sf /sbin/charger $(TARGET_ROOT_OUT)/charger
+    && ln -sf /system/bin/charger $(TARGET_ROOT_OUT)/charger
 
 include $(BUILD_EXECUTABLE)
 
+### charger.recovery ###
 include $(CLEAR_VARS)
-LOCAL_MODULE := charger_test
-LOCAL_MODULE_TAGS := optional
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Wall -Werror -DCHARGER_TEST -DCHARGER_NO_UI
-LOCAL_STATIC_LIBRARIES := $(CHARGER_STATIC_LIBRARIES)
+
 LOCAL_SRC_FILES := \
     charger.cpp \
+
+LOCAL_MODULE := charger.recovery
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/system/bin
+LOCAL_MODULE_STEM := charger
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Wall -Werror
+LOCAL_CFLAGS += -DCHARGER_NO_UI
+
+# charger.recovery doesn't link against libhealthd_{charger,draw} or libminui, since it doesn't need
+# any UI support.
+LOCAL_STATIC_LIBRARIES := \
+    android.hardware.health@2.0-impl \
+    android.hardware.health@1.0-convert \
+    libbinderthreadstate \
+    libhidltransport \
+    libhidlbase \
+    libhwbinder_noltopgo \
+    libhealthstoragedefault \
+    libvndksupport \
+    libhealthd_charger_nops \
+    libbatterymonitor \
+
+# These shared libs will be installed to recovery image because of the dependency in `recovery`
+# module.
+LOCAL_SHARED_LIBRARIES := \
+    android.hardware.health@2.0 \
+    libbase \
+    libcutils \
+    liblog \
+    libutils \
+
+# The use of LOCAL_HAL_STATIC_LIBRARIES prevents from building this module with Android.bp.
+LOCAL_HAL_STATIC_LIBRARIES := libhealthd
+
+include $(BUILD_EXECUTABLE)
+
+### charger_test ###
+include $(CLEAR_VARS)
+LOCAL_MODULE := charger_test
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Wall -Werror -DCHARGER_NO_UI
+LOCAL_STATIC_LIBRARIES := $(CHARGER_STATIC_LIBRARIES)
+LOCAL_SHARED_LIBRARIES := $(CHARGER_SHARED_LIBRARIES)
+LOCAL_SRC_FILES := \
     charger_test.cpp \
 
 include $(BUILD_EXECUTABLE)
 
 CHARGER_STATIC_LIBRARIES :=
+CHARGER_SHARED_LIBRARIES :=
 
+### charger_res_images ###
 ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
 define _add-charger-image
 include $$(CLEAR_VARS)
diff --git a/healthd/charger.cpp b/healthd/charger.cpp
index 43e7fd5..085cceb 100644
--- a/healthd/charger.cpp
+++ b/healthd/charger.cpp
@@ -14,98 +14,13 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "charger"
-#define KLOG_LEVEL 6
+#include "healthd_mode_charger.h"
+#include "healthd_mode_charger_nops.h"
 
-#include <health2/Health.h>
-#include <healthd/healthd.h>
-
-#include <stdlib.h>
-#include <string.h>
-#include <cutils/klog.h>
-
-using namespace android;
-
-// main healthd loop
-extern int healthd_main(void);
-
-// Charger mode
-
-extern void healthd_mode_charger_init(struct healthd_config *config);
-extern int healthd_mode_charger_preparetowait(void);
-extern void healthd_mode_charger_heartbeat(void);
-extern void healthd_mode_charger_battery_update(
-    struct android::BatteryProperties *props);
-
-// NOPs for modes that need no special action
-
-static void healthd_mode_nop_init(struct healthd_config *config);
-static int healthd_mode_nop_preparetowait(void);
-static void healthd_mode_nop_heartbeat(void);
-static void healthd_mode_nop_battery_update(
-    struct android::BatteryProperties *props);
-
-static struct healthd_mode_ops healthd_nops = {
-    .init = healthd_mode_nop_init,
-    .preparetowait = healthd_mode_nop_preparetowait,
-    .heartbeat = healthd_mode_nop_heartbeat,
-    .battery_update = healthd_mode_nop_battery_update,
-};
-
-#ifdef CHARGER_NO_UI
-static struct healthd_mode_ops charger_ops = healthd_nops;
-#else
-static struct healthd_mode_ops charger_ops = {
-    .init = healthd_mode_charger_init,
-    .preparetowait = healthd_mode_charger_preparetowait,
-    .heartbeat = healthd_mode_charger_heartbeat,
-    .battery_update = healthd_mode_charger_battery_update,
-};
-#endif
-
-static void healthd_mode_nop_init(struct healthd_config* config) {
-    using android::hardware::health::V2_0::implementation::Health;
-    Health::initInstance(config);
-}
-
-static int healthd_mode_nop_preparetowait(void) {
-    return -1;
-}
-
-static void healthd_mode_nop_heartbeat(void) {
-}
-
-static void healthd_mode_nop_battery_update(
-    struct android::BatteryProperties* /*props*/) {
-}
-
-int healthd_charger_main(int argc, char** argv) {
-    int ch;
-
-    healthd_mode_ops = &charger_ops;
-
-    while ((ch = getopt(argc, argv, "cr")) != -1) {
-        switch (ch) {
-            case 'c':
-                // -c is now a noop
-                break;
-            case 'r':
-                // force nops for recovery
-                healthd_mode_ops = &healthd_nops;
-                break;
-            case '?':
-            default:
-                KLOG_ERROR(LOG_TAG, "Unrecognized charger option: %c\n",
-                        optopt);
-                exit(1);
-        }
-    }
-
-    return healthd_main();
-}
-
-#ifndef CHARGER_TEST
 int main(int argc, char** argv) {
+#ifdef CHARGER_NO_UI
+    return healthd_charger_nops(argc, argv);
+#else
     return healthd_charger_main(argc, argv);
-}
 #endif
+}
diff --git a/healthd/healthd_draw.cpp b/healthd/healthd_draw.cpp
index 706dc80..3da8bda 100644
--- a/healthd/healthd_draw.cpp
+++ b/healthd/healthd_draw.cpp
@@ -64,7 +64,8 @@
     clear_screen();
 
     /* try to display *something* */
-    if (batt_anim->cur_level < 0 || batt_anim->num_frames == 0)
+    if (batt_anim->cur_status == BATTERY_STATUS_UNKNOWN || batt_anim->cur_level < 0 ||
+        batt_anim->num_frames == 0)
         draw_unknown(surf_unknown);
     else
         draw_battery(batt_anim);
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 8f2f727..0e5aa4f 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -36,6 +36,7 @@
 #include <linux/netlink.h>
 #include <sys/socket.h>
 
+#include <cutils/android_get_control_file.h>
 #include <cutils/klog.h>
 #include <cutils/misc.h>
 #include <cutils/properties.h>
@@ -54,6 +55,9 @@
 
 using namespace android;
 
+// main healthd loop
+extern int healthd_main(void);
+
 char* locale;
 
 #ifndef max
@@ -73,6 +77,7 @@
 #define POWER_ON_KEY_TIME (2 * MSEC_PER_SEC)
 #define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
 #define UNPLUGGED_DISPLAY_TIME (3 * MSEC_PER_SEC)
+#define MAX_BATT_LEVEL_WAIT_TIME (3 * MSEC_PER_SEC)
 
 #define LAST_KMSG_MAX_SZ (32 * 1024)
 
@@ -101,6 +106,7 @@
     int64_t next_screen_transition;
     int64_t next_key_check;
     int64_t next_pwr_check;
+    int64_t wait_batt_level_timestamp;
 
     key_state keys[KEY_MAX + 1];
 
@@ -203,10 +209,9 @@
 #define MAX_KLOG_WRITE_BUF_SZ 256
 
 static void dump_last_kmsg(void) {
-    char* buf;
+    std::string buf;
     char* ptr;
-    unsigned sz = 0;
-    int len;
+    size_t len;
 
     LOGW("\n");
     LOGW("*************** LAST KMSG ***************\n");
@@ -218,21 +223,25 @@
         "/proc/last_kmsg",
         // clang-format on
     };
-    for (size_t i = 0; i < arraysize(kmsg); ++i) {
-        buf = (char*)load_file(kmsg[i], &sz);
-        if (buf && sz) break;
+    for (size_t i = 0; i < arraysize(kmsg) && buf.empty(); ++i) {
+        auto fd = android_get_control_file(kmsg[i]);
+        if (fd >= 0) {
+            android::base::ReadFdToString(fd, &buf);
+        } else {
+            android::base::ReadFileToString(kmsg[i], &buf);
+        }
     }
 
-    if (!buf || !sz) {
+    if (buf.empty()) {
         LOGW("last_kmsg not found. Cold reset?\n");
         goto out;
     }
 
-    len = min(sz, LAST_KMSG_MAX_SZ);
-    ptr = buf + (sz - len);
+    len = min(buf.size(), LAST_KMSG_MAX_SZ);
+    ptr = &buf[buf.size() - len];
 
     while (len > 0) {
-        int cnt = min(len, MAX_KLOG_WRITE_BUF_SZ);
+        size_t cnt = min(len, MAX_KLOG_WRITE_BUF_SZ);
         char yoink;
         char* nl;
 
@@ -248,8 +257,6 @@
         ptr += cnt;
     }
 
-    free(buf);
-
 out:
     LOGW("\n");
     LOGW("************* END LAST KMSG *************\n");
@@ -285,6 +292,21 @@
 
     if (!batt_anim->run || now < charger->next_screen_transition) return;
 
+    // If battery level is not ready, keep checking in the defined time
+    if (batt_prop == nullptr ||
+        (batt_prop->batteryLevel == 0 && batt_prop->batteryStatus == BATTERY_STATUS_UNKNOWN)) {
+        if (charger->wait_batt_level_timestamp == 0) {
+            // Set max delay time and skip drawing screen
+            charger->wait_batt_level_timestamp = now + MAX_BATT_LEVEL_WAIT_TIME;
+            LOGV("[%" PRId64 "] wait for battery capacity ready\n", now);
+            return;
+        } else if (now <= charger->wait_batt_level_timestamp) {
+            // Do nothing, keep waiting
+            return;
+        }
+        // If timeout and battery level is still not ready, draw unknown battery
+    }
+
     if (healthd_draw == nullptr) {
         if (healthd_config && healthd_config->screen_on) {
             if (!healthd_config->screen_on(batt_prop)) {
@@ -704,6 +726,7 @@
     charger->next_screen_transition = -1;
     charger->next_key_check = -1;
     charger->next_pwr_check = -1;
+    charger->wait_batt_level_timestamp = 0;
 
     // Initialize Health implementation (which initializes the internal BatteryMonitor).
     Health::initInstance(config);
@@ -711,3 +734,33 @@
     healthd_config = config;
     charger->boot_min_cap = config->boot_min_cap;
 }
+
+static struct healthd_mode_ops charger_ops = {
+        .init = healthd_mode_charger_init,
+        .preparetowait = healthd_mode_charger_preparetowait,
+        .heartbeat = healthd_mode_charger_heartbeat,
+        .battery_update = healthd_mode_charger_battery_update,
+};
+
+int healthd_charger_main(int argc, char** argv) {
+    int ch;
+
+    healthd_mode_ops = &charger_ops;
+
+    while ((ch = getopt(argc, argv, "cr")) != -1) {
+        switch (ch) {
+            case 'c':
+                // -c is now a noop
+                break;
+            case 'r':
+                // -r is now a noop
+                break;
+            case '?':
+            default:
+                LOGE("Unrecognized charger option: %c\n", optopt);
+                exit(1);
+        }
+    }
+
+    return healthd_main();
+}
diff --git a/healthd/healthd_mode_charger.h b/healthd/healthd_mode_charger.h
new file mode 100644
index 0000000..2f0c9f2
--- /dev/null
+++ b/healthd/healthd_mode_charger.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+int healthd_charger_main(int argc, char** argv);
diff --git a/healthd/healthd_mode_charger_nops.cpp b/healthd/healthd_mode_charger_nops.cpp
new file mode 100644
index 0000000..bcc04d5
--- /dev/null
+++ b/healthd/healthd_mode_charger_nops.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "healthd_mode_charger_nops.h"
+
+#include <health2/Health.h>
+#include <healthd/healthd.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+using namespace android;
+
+// main healthd loop
+extern int healthd_main(void);
+
+// NOPs for modes that need no special action
+
+static void healthd_mode_nop_init(struct healthd_config* config);
+static int healthd_mode_nop_preparetowait(void);
+static void healthd_mode_nop_heartbeat(void);
+static void healthd_mode_nop_battery_update(struct android::BatteryProperties* props);
+
+static struct healthd_mode_ops healthd_nops = {
+        .init = healthd_mode_nop_init,
+        .preparetowait = healthd_mode_nop_preparetowait,
+        .heartbeat = healthd_mode_nop_heartbeat,
+        .battery_update = healthd_mode_nop_battery_update,
+};
+
+static void healthd_mode_nop_init(struct healthd_config* config) {
+    using android::hardware::health::V2_0::implementation::Health;
+    Health::initInstance(config);
+}
+
+static int healthd_mode_nop_preparetowait(void) {
+    return -1;
+}
+
+static void healthd_mode_nop_heartbeat(void) {}
+
+static void healthd_mode_nop_battery_update(struct android::BatteryProperties* /*props*/) {}
+
+int healthd_charger_nops(int /* argc */, char** /* argv */) {
+    healthd_mode_ops = &healthd_nops;
+    return healthd_main();
+}
diff --git a/healthd/healthd_mode_charger_nops.h b/healthd/healthd_mode_charger_nops.h
new file mode 100644
index 0000000..a37b247
--- /dev/null
+++ b/healthd/healthd_mode_charger_nops.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+int healthd_charger_nops(int argc, char** argv);
diff --git a/init/Android.bp b/init/Android.bp
index 9aeb837..8292aa0 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -91,7 +91,7 @@
 cc_library_static {
     name: "libinit",
     recovery_available: true,
-    defaults: ["init_defaults"],
+    defaults: ["init_defaults", "selinux_policy_version"],
     srcs: [
         "action.cpp",
         "action_manager.cpp",
@@ -110,6 +110,7 @@
         "init.cpp",
         "keychords.cpp",
         "modalias_handler.cpp",
+        "mount_handler.cpp",
         "mount_namespace.cpp",
         "parser.cpp",
         "persistent_properties.cpp",
diff --git a/init/Android.mk b/init/Android.mk
index cc514ed..39af0e6 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -2,6 +2,8 @@
 
 LOCAL_PATH:= $(call my-dir)
 
+-include system/sepolicy/policy_version.mk
+
 # --
 
 ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
@@ -28,7 +30,8 @@
     -DSHUTDOWN_ZERO_TIMEOUT=0
 endif
 
-init_options += -DLOG_UEVENTS=0
+init_options += -DLOG_UEVENTS=0 \
+    -DSEPOLICY_VERSION=$(POLICYVERS)
 
 init_cflags += \
     $(init_options) \
diff --git a/init/README.md b/init/README.md
index f0e5d55..d86f077 100644
--- a/init/README.md
+++ b/init/README.md
@@ -277,10 +277,6 @@
   since it has some peculiarities for backwards compatibility reasons. The 'imports' section of
   this file has more details on the order.
 
-`parse_apex_configs`
-  Parses config file(s) from the mounted APEXes. Intented to be used only once
-  when apexd notifies the mount event by setting apexd.status to ready.
-
 `priority <priority>`
 > Scheduling priority of the service process. This value has to be in range
   -20 to 19. Default priority is 0. Priority is set via setpriority().
@@ -512,6 +508,10 @@
   _options_ include "barrier=1", "noauto\_da\_alloc", "discard", ... as
   a comma separated string, eg: barrier=1,noauto\_da\_alloc
 
+`parse_apex_configs`
+> Parses config file(s) from the mounted APEXes. Intented to be used only once
+  when apexd notifies the mount event by setting apexd.status to ready.
+
 `restart <service>`
 > Stops and restarts a running service, does nothing if the service is currently
   restarting, otherwise, it just starts the service.
@@ -660,12 +660,19 @@
 
 Properties
 ----------
-Init provides information about the services that it is responsible
-for via the below properties.
+Init provides state information with the following properties.
 
 `init.svc.<name>`
 > State of a named service ("stopped", "stopping", "running", "restarting")
 
+`dev.mnt.blk.<mount_point>`
+> Block device base name associated with a *mount_point*.
+  The *mount_point* has / replaced by . and if referencing the root mount point
+  "/", it will use "/root", specifically `dev.mnt.blk.root`.
+  Meant for references to `/sys/device/block/${dev.mnt.blk.<mount_point>}/` and
+  `/sys/fs/ext4/${dev.mnt.blk.<mount_point>}/` to tune the block device
+  characteristics in a device agnostic manner.
+
 
 Boot timing
 -----------
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 6511d29..8437e37 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -1118,14 +1118,6 @@
     }
 }
 
-static Result<Success> do_setup_runtime_bionic(const BuiltinArguments& args) {
-    if (SetupRuntimeBionic()) {
-        return Success();
-    } else {
-        return Error() << "Failed to setup runtime bionic";
-    }
-}
-
 static Result<Success> do_enter_default_mount_ns(const BuiltinArguments& args) {
     if (SwitchToDefaultMountNamespace()) {
         return Success();
@@ -1181,7 +1173,6 @@
         {"rmdir",                   {1,     1,    {true,   do_rmdir}}},
         {"setprop",                 {2,     2,    {true,   do_setprop}}},
         {"setrlimit",               {3,     3,    {false,  do_setrlimit}}},
-        {"setup_runtime_bionic",    {0,     0,    {false,  do_setup_runtime_bionic}}},
         {"start",                   {1,     1,    {false,  do_start}}},
         {"stop",                    {1,     1,    {false,  do_stop}}},
         {"swapon_all",              {1,     1,    {false,  do_swapon_all}}},
diff --git a/init/epoll.cpp b/init/epoll.cpp
index 4bca09e..94dd553 100644
--- a/init/epoll.cpp
+++ b/init/epoll.cpp
@@ -16,6 +16,7 @@
 
 #include "epoll.h"
 
+#include <stdint.h>
 #include <sys/epoll.h>
 
 #include <chrono>
@@ -37,13 +38,16 @@
     return Success();
 }
 
-Result<Success> Epoll::RegisterHandler(int fd, std::function<void()> handler) {
+Result<Success> Epoll::RegisterHandler(int fd, std::function<void()> handler, uint32_t events) {
+    if (!events) {
+        return Error() << "Must specify events";
+    }
     auto [it, inserted] = epoll_handlers_.emplace(fd, std::move(handler));
     if (!inserted) {
         return Error() << "Cannot specify two epoll handlers for a given FD";
     }
     epoll_event ev;
-    ev.events = EPOLLIN;
+    ev.events = events;
     // std::map's iterators do not get invalidated until erased, so we use the
     // pointer to the std::function in the map directly for epoll_ctl.
     ev.data.ptr = reinterpret_cast<void*>(&it->second);
diff --git a/init/epoll.h b/init/epoll.h
index 85a791c..9789bef 100644
--- a/init/epoll.h
+++ b/init/epoll.h
@@ -17,6 +17,9 @@
 #ifndef _INIT_EPOLL_H
 #define _INIT_EPOLL_H
 
+#include <stdint.h>
+#include <sys/epoll.h>
+
 #include <chrono>
 #include <functional>
 #include <map>
@@ -34,7 +37,8 @@
     Epoll();
 
     Result<Success> Open();
-    Result<Success> RegisterHandler(int fd, std::function<void()> handler);
+    Result<Success> RegisterHandler(int fd, std::function<void()> handler,
+                                    uint32_t events = EPOLLIN);
     Result<Success> UnregisterHandler(int fd);
     Result<Success> Wait(std::optional<std::chrono::milliseconds> timeout);
 
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index 7cf4c3f..c566676 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -199,6 +199,12 @@
         SwitchRoot("/first_stage_ramdisk");
     }
 
+    // If this file is present, the second-stage init will use a userdebug sepolicy
+    // and load adb_debug.prop to allow adb root, if the device is unlocked.
+    if (access("/force_debuggable", F_OK) == 0) {
+        setenv("INIT_FORCE_DEBUGGABLE", "true", 1);
+    }
+
     if (!DoFirstStageMount()) {
         LOG(FATAL) << "Failed to mount required partitions early ...";
     }
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 17cd470..d458924 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -78,6 +78,7 @@
     ListenerAction HandleBlockDevice(const std::string& name, const Uevent&);
     bool InitRequiredDevices();
     bool InitMappedDevice(const std::string& verity_device);
+    bool InitDeviceMapper();
     bool CreateLogicalPartitions();
     bool MountPartition(const Fstab::iterator& begin, bool erase_used_fstab_entry,
                         Fstab::iterator* end = nullptr);
@@ -97,6 +98,7 @@
     virtual bool SetUpDmVerity(FstabEntry* fstab_entry) = 0;
 
     bool need_dm_verity_;
+    bool gsi_not_on_userdata_ = false;
 
     Fstab fstab_;
     std::string lp_metadata_partition_;
@@ -267,8 +269,6 @@
     }
 
     required_devices_partition_names_.emplace(super_partition_name_);
-    // When booting from live GSI images, userdata is the super device.
-    required_devices_partition_names_.emplace("userdata");
     return true;
 }
 
@@ -281,25 +281,7 @@
     }
 
     if (IsDmLinearEnabled() || need_dm_verity_) {
-        const std::string dm_path = "/devices/virtual/misc/device-mapper";
-        bool found = false;
-        auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
-            if (uevent.path == dm_path) {
-                device_handler_->HandleUevent(uevent);
-                found = true;
-                return ListenerAction::kStop;
-            }
-            return ListenerAction::kContinue;
-        };
-        uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path, dm_callback);
-        if (!found) {
-            LOG(INFO) << "device-mapper device not found in /sys, waiting for its uevent";
-            Timer t;
-            uevent_listener_.Poll(dm_callback, 10s);
-            LOG(INFO) << "Wait for device-mapper returned after " << t;
-        }
-        if (!found) {
-            LOG(ERROR) << "device-mapper device not found after polling timeout";
+        if (!InitDeviceMapper()) {
             return false;
         }
     }
@@ -327,11 +309,36 @@
     return true;
 }
 
+bool FirstStageMount::InitDeviceMapper() {
+    const std::string dm_path = "/devices/virtual/misc/device-mapper";
+    bool found = false;
+    auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
+        if (uevent.path == dm_path) {
+            device_handler_->HandleUevent(uevent);
+            found = true;
+            return ListenerAction::kStop;
+        }
+        return ListenerAction::kContinue;
+    };
+    uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path, dm_callback);
+    if (!found) {
+        LOG(INFO) << "device-mapper device not found in /sys, waiting for its uevent";
+        Timer t;
+        uevent_listener_.Poll(dm_callback, 10s);
+        LOG(INFO) << "Wait for device-mapper returned after " << t;
+    }
+    if (!found) {
+        LOG(ERROR) << "device-mapper device not found after polling timeout";
+        return false;
+    }
+    return true;
+}
+
 bool FirstStageMount::InitDmLinearBackingDevices(const android::fs_mgr::LpMetadata& metadata) {
     auto partition_names = android::fs_mgr::GetBlockDevicePartitionNames(metadata);
     for (const auto& partition_name : partition_names) {
-        const auto super_device = android::fs_mgr::GetMetadataSuperBlockDevice(metadata);
-        if (partition_name == android::fs_mgr::GetBlockDevicePartitionName(*super_device)) {
+        // The super partition was found in the earlier pass.
+        if (partition_name == super_partition_name_) {
             continue;
         }
         required_devices_partition_names_.emplace(partition_name);
@@ -499,6 +506,10 @@
     if (system_partition == fstab_.end()) return true;
 
     if (MountPartition(system_partition, false)) {
+        if (gsi_not_on_userdata_ && fs_mgr_verity_is_check_at_most_once(*system_partition)) {
+            LOG(ERROR) << "check_most_at_once forbidden on external media";
+            return false;
+        }
         SwitchRoot("/system");
     } else {
         PLOG(ERROR) << "Failed to mount /system";
@@ -580,7 +591,14 @@
             required_devices_partition_names_.emplace(basename(device.c_str()));
             auto uevent_callback = [this](const Uevent& uevent) { return UeventCallback(uevent); };
             uevent_listener_.RegenerateUevents(uevent_callback);
-            uevent_listener_.Poll(uevent_callback, 10s);
+            if (!required_devices_partition_names_.empty()) {
+                uevent_listener_.Poll(uevent_callback, 10s);
+                if (!required_devices_partition_names_.empty()) {
+                    LOG(ERROR) << __PRETTY_FUNCTION__
+                               << ": partition(s) not found after polling timeout: "
+                               << android::base::Join(required_devices_partition_names_, ", ");
+                }
+            }
         } else {
             InitMappedDevice(device);
         }
@@ -605,7 +623,29 @@
         return;
     }
 
-    if (!android::fs_mgr::CreateLogicalPartitions(*metadata.get(), "/dev/block/by-name/userdata")) {
+    if (!InitDmLinearBackingDevices(*metadata.get())) {
+        return;
+    }
+
+    // Device-mapper might not be ready if the device doesn't use DAP or verity
+    // (for example, hikey).
+    if (access("/dev/device-mapper", F_OK) && !InitDeviceMapper()) {
+        return;
+    }
+
+    // Find the name of the super partition for the GSI. It will either be
+    // "userdata", or a block device such as an sdcard. There are no by-name
+    // partitions other than userdata that we support installing GSIs to.
+    auto super = GetMetadataSuperBlockDevice(*metadata.get());
+    std::string super_name = android::fs_mgr::GetBlockDevicePartitionName(*super);
+    std::string super_path;
+    if (super_name == "userdata") {
+        super_path = "/dev/block/by-name/" + super_name;
+    } else {
+        super_path = "/dev/block/" + super_name;
+    }
+
+    if (!android::fs_mgr::CreateLogicalPartitions(*metadata.get(), super_path)) {
         LOG(ERROR) << "GSI partition layout could not be instantiated";
         return;
     }
@@ -623,6 +663,7 @@
         fstab_.erase(system_partition);
     }
     fstab_.emplace_back(BuildGsiSystemFstabEntry());
+    gsi_not_on_userdata_ = (super_name != "userdata");
 }
 
 bool FirstStageMountVBootV1::GetDmVerityDevices() {
diff --git a/init/init.cpp b/init/init.cpp
index bbef1a9..cdec41c 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -39,6 +39,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <cutils/android_reboot.h>
+#include <fs_avb/fs_avb.h>
 #include <fs_mgr_vendor_overlay.h>
 #include <keyutils.h>
 #include <libavb/libavb.h>
@@ -56,6 +57,7 @@
 #include "first_stage_mount.h"
 #include "import_parser.h"
 #include "keychords.h"
+#include "mount_handler.h"
 #include "mount_namespace.h"
 #include "property_service.h"
 #include "reboot.h"
@@ -74,6 +76,7 @@
 using android::base::StringPrintf;
 using android::base::Timer;
 using android::base::Trim;
+using android::fs_mgr::AvbHandle;
 
 namespace android {
 namespace init {
@@ -92,6 +95,7 @@
 static bool shutting_down;
 static std::string shutdown_command;
 static bool do_shutdown = false;
+static bool load_debug_prop = false;
 
 std::vector<std::string> late_import_paths;
 
@@ -353,7 +357,7 @@
 static Result<Success> SetupCgroupsAction(const BuiltinArguments&) {
     // Have to create <CGROUPS_RC_DIR> using make_dir function
     // for appropriate sepolicy to be set for it
-    make_dir(CGROUPS_RC_DIR, 0711);
+    make_dir(android::base::Dirname(CGROUPS_RC_PATH), 0711);
     if (!CgroupSetupCgroups()) {
         return ErrnoError() << "Failed to setup cgroups";
     }
@@ -655,10 +659,17 @@
     const char* avb_version = getenv("INIT_AVB_VERSION");
     if (avb_version) property_set("ro.boot.avb_version", avb_version);
 
+    // See if need to load debug props to allow adb root, when the device is unlocked.
+    const char* force_debuggable_env = getenv("INIT_FORCE_DEBUGGABLE");
+    if (force_debuggable_env && AvbHandle::IsDeviceUnlocked()) {
+        load_debug_prop = "true"s == force_debuggable_env;
+    }
+
     // Clean up our environment.
     unsetenv("INIT_STARTED_AT");
     unsetenv("INIT_SELINUX_TOOK");
     unsetenv("INIT_AVB_VERSION");
+    unsetenv("INIT_FORCE_DEBUGGABLE");
 
     // Now set up SELinux for second stage.
     SelinuxSetupKernelLogging();
@@ -672,10 +683,11 @@
 
     InstallSignalFdHandler(&epoll);
 
-    property_load_boot_defaults();
+    property_load_boot_defaults(load_debug_prop);
     fs_mgr_vendor_overlay_mount_all();
     export_oem_lock_status();
     StartPropertyService(&epoll);
+    MountHandler mount_handler(&epoll);
     set_usb_controller();
 
     const BuiltinFunctionMap function_map;
diff --git a/init/mount_handler.cpp b/init/mount_handler.cpp
new file mode 100644
index 0000000..c8f0e76
--- /dev/null
+++ b/init/mount_handler.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mount_handler.h"
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <fs_mgr.h>
+#include <fstab/fstab.h>
+#include <libdm/dm.h>
+
+#include "epoll.h"
+#include "property_service.h"
+
+namespace android {
+namespace init {
+
+namespace {
+
+MountHandlerEntry ParseMount(const std::string& line) {
+    auto fields = android::base::Split(line, " ");
+    while (fields.size() < 3) fields.emplace_back("");
+    if (fields[0] == "/dev/root") {
+        auto& dm = dm::DeviceMapper::Instance();
+        std::string path;
+        if (dm.GetDmDevicePathByName("system", &path) || dm.GetDmDevicePathByName("vroot", &path)) {
+            fields[0] = path;
+        } else if (android::fs_mgr::Fstab fstab; android::fs_mgr::ReadDefaultFstab(&fstab)) {
+            auto entry = GetEntryForMountPoint(&fstab, "/");
+            if (entry || (entry = GetEntryForMountPoint(&fstab, "/system"))) {
+                fields[0] = entry->blk_device;
+            }
+        }
+    }
+    if (android::base::StartsWith(fields[0], "/dev/")) {
+        if (std::string link; android::base::Readlink(fields[0], &link)) {
+            fields[0] = link;
+        }
+    }
+    return MountHandlerEntry(fields[0], fields[1], fields[2]);
+}
+
+void SetMountProperty(const MountHandlerEntry& entry, bool add) {
+    static constexpr char devblock[] = "/dev/block/";
+    if (!android::base::StartsWith(entry.blk_device, devblock)) return;
+    std::string value;
+    if (add) {
+        value = entry.blk_device.substr(strlen(devblock));
+        if (android::base::StartsWith(value, "sd")) {
+            // All sd partitions inherit their queue characteristics
+            // from the whole device reference.  Strip partition number.
+            auto it = std::find_if(value.begin(), value.end(), [](char c) { return isdigit(c); });
+            if (it != value.end()) value.erase(it, value.end());
+        }
+        auto queue = "/sys/block/" + value + "/queue";
+        struct stat sb;
+        if (stat(queue.c_str(), &sb) || !S_ISDIR(sb.st_mode)) value = "";
+        if (stat(entry.mount_point.c_str(), &sb) || !S_ISDIR(sb.st_mode)) value = "";
+        // Clear the noise associated with loopback and APEX.
+        if (android::base::StartsWith(value, "loop")) value = "";
+        if (android::base::StartsWith(entry.mount_point, "/apex/")) value = "";
+    }
+    auto mount_prop = entry.mount_point;
+    if (mount_prop == "/") mount_prop = "/root";
+    std::replace(mount_prop.begin(), mount_prop.end(), '/', '.');
+    mount_prop = "dev.mnt.blk" + mount_prop;
+    // Set property even if its value does not change to trigger 'on property:'
+    // handling, except for clearing non-existent or already clear property.
+    // Goal is reduction of empty properties and associated triggers.
+    if (value.empty() && android::base::GetProperty(mount_prop, "").empty()) return;
+    property_set(mount_prop, value);
+}
+
+}  // namespace
+
+MountHandlerEntry::MountHandlerEntry(const std::string& blk_device, const std::string& mount_point,
+                                     const std::string& fs_type)
+    : blk_device(blk_device), mount_point(mount_point), fs_type(fs_type) {}
+
+bool MountHandlerEntry::operator<(const MountHandlerEntry& r) const {
+    if (blk_device < r.blk_device) return true;
+    if (blk_device > r.blk_device) return false;
+    if (mount_point < r.mount_point) return true;
+    if (mount_point > r.mount_point) return false;
+    return fs_type < r.fs_type;
+}
+
+MountHandler::MountHandler(Epoll* epoll) : epoll_(epoll), fp_(fopen("/proc/mounts", "re"), fclose) {
+    if (!fp_) PLOG(FATAL) << "Could not open /proc/mounts";
+    auto result = epoll->RegisterHandler(
+            fileno(fp_.get()), [this]() { this->MountHandlerFunction(); }, EPOLLERR | EPOLLPRI);
+    if (!result) LOG(FATAL) << result.error();
+}
+
+MountHandler::~MountHandler() {
+    if (fp_) epoll_->UnregisterHandler(fileno(fp_.get())).IgnoreError();
+}
+
+void MountHandler::MountHandlerFunction() {
+    rewind(fp_.get());
+    std::vector<MountHandlerEntry> touched;
+    auto untouched = mounts_;
+    char* buf = nullptr;
+    size_t len = 0;
+    while (getline(&buf, &len, fp_.get()) != -1) {
+        auto entry = ParseMount(std::string(buf));
+        auto match = untouched.find(entry);
+        if (match == untouched.end()) {
+            touched.emplace_back(std::move(entry));
+        } else {
+            untouched.erase(match);
+        }
+    }
+    free(buf);
+    for (auto entry : untouched) {
+        SetMountProperty(entry, false);
+        mounts_.erase(entry);
+    }
+    for (auto entry : touched) {
+        SetMountProperty(entry, true);
+        mounts_.emplace(std::move(entry));
+    }
+}
+
+}  // namespace init
+}  // namespace android
diff --git a/init/mount_handler.h b/init/mount_handler.h
new file mode 100644
index 0000000..e524a74
--- /dev/null
+++ b/init/mount_handler.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdio.h>
+
+#include <memory>
+#include <set>
+#include <string>
+
+#include "epoll.h"
+
+namespace android {
+namespace init {
+
+struct MountHandlerEntry {
+    MountHandlerEntry(const std::string& blk_device, const std::string& mount_point,
+                      const std::string& fs_type);
+
+    bool operator<(const MountHandlerEntry& r) const;
+
+    const std::string blk_device;
+    const std::string mount_point;
+    const std::string fs_type;
+};
+
+class MountHandler {
+  public:
+    explicit MountHandler(Epoll* epoll);
+    MountHandler(const MountHandler&) = delete;
+    MountHandler(MountHandler&&) = delete;
+    MountHandler& operator=(const MountHandler&) = delete;
+    MountHandler& operator=(MountHandler&&) = delete;
+    ~MountHandler();
+
+  private:
+    void MountHandlerFunction();
+
+    Epoll* epoll_;
+    std::unique_ptr<FILE, decltype(&fclose)> fp_;
+    std::set<MountHandlerEntry> mounts_;
+};
+
+}  // namespace init
+}  // namespace android
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index 4161df2..5305dc7 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -33,37 +33,6 @@
 namespace init {
 namespace {
 
-static constexpr const char* kLinkerMountPoint = "/bionic/bin/linker";
-static constexpr const char* kBootstrapLinkerPath = "/system/bin/bootstrap/linker";
-static constexpr const char* kRuntimeLinkerPath = "/apex/com.android.runtime/bin/linker";
-
-static constexpr const char* kBionicLibsMountPointDir = "/bionic/lib/";
-static constexpr const char* kBootstrapBionicLibsDir = "/system/lib/bootstrap/";
-static constexpr const char* kRuntimeBionicLibsDir = "/apex/com.android.runtime/lib/bionic/";
-
-static constexpr const char* kLinkerMountPoint64 = "/bionic/bin/linker64";
-static constexpr const char* kBootstrapLinkerPath64 = "/system/bin/bootstrap/linker64";
-static constexpr const char* kRuntimeLinkerPath64 = "/apex/com.android.runtime/bin/linker64";
-
-static constexpr const char* kBionicLibsMountPointDir64 = "/bionic/lib64/";
-static constexpr const char* kBootstrapBionicLibsDir64 = "/system/lib64/bootstrap/";
-static constexpr const char* kRuntimeBionicLibsDir64 = "/apex/com.android.runtime/lib64/bionic/";
-
-static const std::vector<std::string> kBionicLibFileNames = {"libc.so", "libm.so", "libdl.so"};
-
-static bool BindMount(const std::string& source, const std::string& mount_point,
-                      bool recursive = false) {
-    unsigned long mountflags = MS_BIND;
-    if (recursive) {
-        mountflags |= MS_REC;
-    }
-    if (mount(source.c_str(), mount_point.c_str(), nullptr, mountflags, nullptr) == -1) {
-        PLOG(ERROR) << "Could not bind-mount " << source << " to " << mount_point;
-        return false;
-    }
-    return true;
-}
-
 static bool MakeShared(const std::string& mount_point, bool recursive = false) {
     unsigned long mountflags = MS_SHARED;
     if (recursive) {
@@ -105,34 +74,6 @@
     return ret;
 }
 
-static bool BindMountBionic(const std::string& linker_source, const std::string& lib_dir_source,
-                            const std::string& linker_mount_point,
-                            const std::string& lib_mount_dir) {
-    if (access(linker_source.c_str(), F_OK) != 0) {
-        PLOG(INFO) << linker_source << " does not exist. skipping mounting bionic there.";
-        // This can happen for 64-bit bionic in 32-bit only device.
-        // It is okay to skip mounting the 64-bit bionic.
-        return true;
-    }
-    if (!BindMount(linker_source, linker_mount_point)) {
-        return false;
-    }
-    if (!MakePrivate(linker_mount_point)) {
-        return false;
-    }
-    for (const auto& libname : kBionicLibFileNames) {
-        std::string mount_point = lib_mount_dir + libname;
-        std::string source = lib_dir_source + libname;
-        if (!BindMount(source, mount_point)) {
-            return false;
-        }
-        if (!MakePrivate(mount_point)) {
-            return false;
-        }
-    }
-    return true;
-}
-
 static bool IsApexUpdatable() {
     static bool updatable = android::sysprop::ApexProperties::updatable().value_or(false);
     return updatable;
@@ -154,26 +95,7 @@
     // point to private.
     if (!MakeShared("/", true /*recursive*/)) return false;
 
-    // Since different files (bootstrap or runtime APEX) should be mounted to
-    // the same mount point paths (e.g. /bionic/bin/linker, /bionic/lib/libc.so,
-    // etc.) across the two mount namespaces, we create a private mount point at
-    // /bionic so that a mount event for the bootstrap bionic in the mount
-    // namespace for pre-apexd processes is not propagated to the other mount
-    // namespace for post-apexd process, and vice versa.
-    //
-    // Other mount points other than /bionic, however, are all still shared.
-    if (!BindMount("/bionic", "/bionic", true /*recursive*/)) return false;
-    if (!MakePrivate("/bionic")) return false;
-
-    // Bind-mount bootstrap bionic.
-    if (!BindMountBionic(kBootstrapLinkerPath, kBootstrapBionicLibsDir, kLinkerMountPoint,
-                         kBionicLibsMountPointDir))
-        return false;
-    if (!BindMountBionic(kBootstrapLinkerPath64, kBootstrapBionicLibsDir64, kLinkerMountPoint64,
-                         kBionicLibsMountPointDir64))
-        return false;
-
-    // /apex is also a private mountpoint to give different sets of APEXes for
+    // /apex is a private mountpoint to give different sets of APEXes for
     // the bootstrap and default mount namespaces. The processes running with
     // the bootstrap namespace get APEXes from the read-only partition.
     if (!(MakePrivate("/apex"))) return false;
@@ -181,12 +103,11 @@
     bootstrap_ns_fd.reset(OpenMountNamespace());
     bootstrap_ns_id = GetMountNamespaceId();
 
-    // When bionic is updatable via the runtime APEX, we create separate mount
+    // When APEXes are updatable (e.g. not-flattened), we create separate mount
     // namespaces for processes that are started before and after the APEX is
-    // activated by apexd. In the namespace for pre-apexd processes, the bionic
-    // from the /system partition (that we call bootstrap bionic) is
-    // bind-mounted. In the namespace for post-apexd processes, the bionic from
-    // the runtime APEX is bind-mounted.
+    // activated by apexd. In the namespace for pre-apexd processes, small
+    // number of essential APEXes (e.g. com.android.runtime) are activated.
+    // In the namespace for post-apexd processes, all APEXes are activated.
     bool success = true;
     if (IsApexUpdatable() && !IsRecoveryMode()) {
         // Creating a new namespace by cloning, saving, and switching back to
@@ -198,15 +119,6 @@
         default_ns_fd.reset(OpenMountNamespace());
         default_ns_id = GetMountNamespaceId();
 
-        // By this unmount, the bootstrap bionic are not mounted in the default
-        // mount namespace.
-        if (umount2("/bionic", MNT_DETACH) == -1) {
-            PLOG(ERROR) << "Cannot unmount /bionic";
-            // Don't return here. We have to switch back to the bootstrap
-            // namespace.
-            success = false;
-        }
-
         if (setns(bootstrap_ns_fd.get(), CLONE_NEWNS) == -1) {
             PLOG(ERROR) << "Cannot switch back to bootstrap mount namespace";
             return false;
@@ -237,28 +149,6 @@
     return true;
 }
 
-// TODO(jiyong): remove this when /system/lib/libc.so becomes
-// a symlink to /apex/com.android.runtime/lib/bionic/libc.so
-bool SetupRuntimeBionic() {
-    if (IsRecoveryMode()) {
-        // We don't have multiple namespaces in recovery mode
-        return true;
-    }
-    // Bind-mount bionic from the runtime APEX since it is now available. Note
-    // that in case of IsApexUpdatable() == false, these mounts are over the
-    // existing existing bind mounts for the bootstrap bionic, which effectively
-    // becomes hidden.
-    if (!BindMountBionic(kRuntimeLinkerPath, kRuntimeBionicLibsDir, kLinkerMountPoint,
-                         kBionicLibsMountPointDir))
-        return false;
-    if (!BindMountBionic(kRuntimeLinkerPath64, kRuntimeBionicLibsDir64, kLinkerMountPoint64,
-                         kBionicLibsMountPointDir64))
-        return false;
-
-    LOG(INFO) << "Runtime bionic is set up";
-    return true;
-}
-
 bool SwitchToBootstrapMountNamespaceIfNeeded() {
     if (IsRecoveryMode()) {
         // we don't have multiple namespaces in recovery mode
diff --git a/init/mount_namespace.h b/init/mount_namespace.h
index 4eef785..c41a449 100644
--- a/init/mount_namespace.h
+++ b/init/mount_namespace.h
@@ -20,7 +20,6 @@
 namespace init {
 
 bool SetupMountNamespaces();
-bool SetupRuntimeBionic();
 bool SwitchToDefaultMountNamespace();
 bool SwitchToBootstrapMountNamespaceIfNeeded();
 
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 4bc857a..fc5538c 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -866,7 +866,7 @@
     }
 }
 
-void property_load_boot_defaults() {
+void property_load_boot_defaults(bool load_debug_prop) {
     // TODO(b/117892318): merge prop.default and build.prop files into one
     // We read the properties and their values into a map, in order to always allow properties
     // loaded in the later property files to override the properties in loaded in the earlier
@@ -888,6 +888,12 @@
     load_properties_from_file("/product_services/build.prop", nullptr, &properties);
     load_properties_from_file("/factory/factory.prop", "ro.*", &properties);
 
+    if (load_debug_prop) {
+        constexpr static const char kAdbDebugProp[] = "/system/etc/adb_debug.prop";
+        LOG(INFO) << "Loading " << kAdbDebugProp;
+        load_properties_from_file(kAdbDebugProp, nullptr, &properties);
+    }
+
     for (const auto& [name, value] : properties) {
         std::string error;
         if (PropertySet(name, value, &error) != PROP_SUCCESS) {
diff --git a/init/property_service.h b/init/property_service.h
index 9022f5a..85e7bc0 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -36,7 +36,7 @@
 extern bool PropertyChildReap(pid_t pid);
 
 void property_init(void);
-void property_load_boot_defaults(void);
+void property_load_boot_defaults(bool);
 void load_persist_props(void);
 void load_system_props(void);
 void StartPropertyService(Epoll* epoll);
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 3fadfed..aa66baa 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -61,14 +61,18 @@
 #include <android-base/parseint.h>
 #include <android-base/unique_fd.h>
 #include <cutils/android_reboot.h>
+#include <fs_avb/fs_avb.h>
 #include <selinux/android.h>
 
 #include "reboot_utils.h"
 #include "util.h"
 
+using namespace std::string_literals;
+
 using android::base::ParseInt;
 using android::base::Timer;
 using android::base::unique_fd;
+using android::fs_mgr::AvbHandle;
 
 namespace android {
 namespace init {
@@ -267,6 +271,8 @@
 }
 
 constexpr const char plat_policy_cil_file[] = "/system/etc/selinux/plat_sepolicy.cil";
+constexpr const char userdebug_plat_policy_cil_file[] =
+        "/system/etc/selinux/userdebug_plat_sepolicy.cil";
 
 bool IsSplitPolicyDevice() {
     return access(plat_policy_cil_file, R_OK) != -1;
@@ -282,10 +288,21 @@
     // secilc is invoked to compile the above three policy files into a single monolithic policy
     // file. This file is then loaded into the kernel.
 
+    // See if we need to load userdebug_plat_sepolicy.cil instead of plat_sepolicy.cil.
+    const char* force_debuggable_env = getenv("INIT_FORCE_DEBUGGABLE");
+    bool use_userdebug_policy =
+            ((force_debuggable_env && "true"s == force_debuggable_env) &&
+             AvbHandle::IsDeviceUnlocked() && access(userdebug_plat_policy_cil_file, F_OK) == 0);
+    if (use_userdebug_policy) {
+        LOG(WARNING) << "Using userdebug system sepolicy";
+    }
+
     // Load precompiled policy from vendor image, if a matching policy is found there. The policy
     // must match the platform policy on the system image.
     std::string precompiled_sepolicy_file;
-    if (FindPrecompiledSplitPolicy(&precompiled_sepolicy_file)) {
+    // use_userdebug_policy requires compiling sepolicy with userdebug_plat_sepolicy.cil.
+    // Thus it cannot use the precompiled policy from vendor image.
+    if (!use_userdebug_policy && FindPrecompiledSplitPolicy(&precompiled_sepolicy_file)) {
         unique_fd fd(open(precompiled_sepolicy_file.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY));
         if (fd != -1) {
             if (selinux_android_load_policy_from_fd(fd, precompiled_sepolicy_file.c_str()) < 0) {
@@ -299,14 +316,6 @@
 
     LOG(INFO) << "Compiling SELinux policy";
 
-    // Determine the highest policy language version supported by the kernel
-    set_selinuxmnt("/sys/fs/selinux");
-    int max_policy_version = security_policyvers();
-    if (max_policy_version == -1) {
-        PLOG(ERROR) << "Failed to determine highest policy version supported by kernel";
-        return false;
-    }
-
     // We store the output of the compilation on /dev because this is the most convenient tmpfs
     // storage mount available this early in the boot sequence.
     char compiled_sepolicy[] = "/dev/sepolicy.XXXXXX";
@@ -353,14 +362,13 @@
     if (access(odm_policy_cil_file.c_str(), F_OK) == -1) {
         odm_policy_cil_file.clear();
     }
-    const std::string version_as_string = std::to_string(max_policy_version);
+    const std::string version_as_string = std::to_string(SEPOLICY_VERSION);
 
     // clang-format off
     std::vector<const char*> compile_args {
         "/system/bin/secilc",
-        plat_policy_cil_file,
+        use_userdebug_policy ? userdebug_plat_policy_cil_file : plat_policy_cil_file,
         "-m", "-M", "true", "-G", "-N",
-        // Target the highest policy language version supported by the kernel
         "-c", version_as_string.c_str(),
         plat_mapping_file.c_str(),
         "-o", compiled_sepolicy,
diff --git a/init/service.cpp b/init/service.cpp
index 2186a85..f5c13b9 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -177,7 +177,7 @@
 Result<Success> Service::EnterNamespaces() const {
     for (const auto& [nstype, path] : namespaces_to_enter_) {
         auto fd = unique_fd{open(path.c_str(), O_RDONLY | O_CLOEXEC)};
-        if (!fd) {
+        if (fd == -1) {
             return ErrnoError() << "Could not open namespace at " << path;
         }
         if (setns(fd, nstype) == -1) {
@@ -756,6 +756,11 @@
     if (args[2] != "r" && args[2] != "w" && args[2] != "rw") {
         return Error() << "file type must be 'r', 'w' or 'rw'";
     }
+    std::string expanded;
+    if (!expand_props(args[1], &expanded)) {
+        return Error() << "Could not expand property in file path '" << args[1] << "'";
+    }
+    args[1] = std::move(expanded);
     if ((args[1][0] != '/') || (args[1].find("../") != std::string::npos)) {
         return Error() << "file name must not be relative";
     }
@@ -1059,7 +1064,7 @@
         std::string oom_str = std::to_string(oom_score_adjust_);
         std::string oom_file = StringPrintf("/proc/%d/oom_score_adj", pid);
         if (!WriteStringToFile(oom_str, oom_file)) {
-            PLOG(ERROR) << "couldn't write oom_score_adj: " << strerror(errno);
+            PLOG(ERROR) << "couldn't write oom_score_adj";
         }
     }
 
diff --git a/janitors/OWNERS b/janitors/OWNERS
index 0610b41..3e32c26 100644
--- a/janitors/OWNERS
+++ b/janitors/OWNERS
@@ -1,4 +1,6 @@
 # OWNERS file for projects that don't really have owners so much as volunteer janitors.
+ccross@google.com
+dwillemsen@google.com
 enh@google.com
 hhb@google.com
 narayan@google.com
diff --git a/libasyncio/Android.bp b/libasyncio/Android.bp
index 0fd2a3a..4ab439d 100644
--- a/libasyncio/Android.bp
+++ b/libasyncio/Android.bp
@@ -27,7 +27,6 @@
     name: "libasyncio",
     defaults: ["libasyncio_defaults"],
     vendor_available: true,
-    double_loadable: true,
     recovery_available: true,
     host_supported: true,
     srcs: [
diff --git a/libbacktrace/UnwindStack.h b/libbacktrace/UnwindStack.h
index 33c4282..4ec591d 100644
--- a/libbacktrace/UnwindStack.h
+++ b/libbacktrace/UnwindStack.h
@@ -58,7 +58,7 @@
 
   bool Unwind(size_t num_ignore_frames, void* context) override;
 
-  std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset);
+  std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset) override;
 
   size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) override;
 
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index b4b8cd1..a27ecef 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -18,7 +18,6 @@
 // they correspond to features not used by our host development tools
 // which are also hard or even impossible to port to native Win32
 libcutils_nonwindows_sources = [
-    "android_get_control_file.cpp",
     "fs.cpp",
     "hashmap.cpp",
     "multiuser.cpp",
@@ -84,6 +83,8 @@
             ],
         },
         windows: {
+            host_ldlibs: ["-lws2_32"],
+
             srcs: [
                 "socket_inaddr_any_server_windows.cpp",
                 "socket_network_client_windows.cpp",
@@ -92,9 +93,6 @@
             ],
 
             enabled: true,
-            shared: {
-                enabled: false,
-            },
             cflags: [
                 "-D_GNU_SOURCE",
             ],
@@ -102,6 +100,7 @@
 
         android: {
             srcs: libcutils_nonwindows_sources + [
+                "android_get_control_file.cpp",
                 "android_reboot.cpp",
                 "ashmem-dev.cpp",
                 "fs_config.cpp",
diff --git a/libcutils/android_get_control_env.h b/libcutils/android_get_control_env.h
index 638c831..a830269 100644
--- a/libcutils/android_get_control_env.h
+++ b/libcutils/android_get_control_env.h
@@ -14,20 +14,13 @@
  * limitations under the License.
  */
 
-#ifndef __CUTILS_ANDROID_GET_CONTROL_ENV_H
-#define __CUTILS_ANDROID_GET_CONTROL_ENV_H
+#pragma once
 
-/* To declare library function hidden and internal */
-#define LIBCUTILS_HIDDEN __attribute__((visibility("hidden")))
+#include <sys/cdefs.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+__BEGIN_DECLS
 
-LIBCUTILS_HIDDEN int __android_get_control_from_env(const char* prefix,
-                                                    const char* name);
-#ifdef __cplusplus
-}
-#endif
+int __android_get_control_from_env(const char* prefix, const char* name)
+        __attribute__((visibility("hidden")));
 
-#endif /* __CUTILS_ANDROID_GET_CONTROL_ENV_H */
+__END_DECLS
diff --git a/libcutils/android_get_control_file.cpp b/libcutils/android_get_control_file.cpp
index d8121f5..d5b0894 100644
--- a/libcutils/android_get_control_file.cpp
+++ b/libcutils/android_get_control_file.cpp
@@ -39,14 +39,14 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+
 #include "android_get_control_env.h"
 
-#ifndef TEMP_FAILURE_RETRY
-#define TEMP_FAILURE_RETRY(exp) (exp) // KISS implementation
-#endif
-
-LIBCUTILS_HIDDEN int __android_get_control_from_env(const char* prefix,
-                                                    const char* name) {
+int __android_get_control_from_env(const char* prefix, const char* name) {
     if (!prefix || !name) return -1;
 
     char *key = NULL;
@@ -67,48 +67,33 @@
     long fd = strtol(val, NULL, 10);
     if (errno) return -1;
 
-    // validity checking
+    // Since we are inheriting an fd, it could legitimately exceed _SC_OPEN_MAX
     if ((fd < 0) || (fd > INT_MAX)) return -1;
 
-    // Since we are inheriting an fd, it could legitimately exceed _SC_OPEN_MAX
-
     // Still open?
-#if defined(F_GETFD) // Lowest overhead
     if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD)) < 0) return -1;
-#elif defined(F_GETFL) // Alternate lowest overhead
-    if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL)) < 0) return -1;
-#else // Hail Mary pass
-    struct stat s;
-    if (TEMP_FAILURE_RETRY(fstat(fd, &s)) < 0) return -1;
-#endif
 
     return static_cast<int>(fd);
 }
 
 int android_get_control_file(const char* path) {
-    int fd = __android_get_control_from_env(ANDROID_FILE_ENV_PREFIX, path);
+    std::string given_path;
+    if (!android::base::Realpath(path, &given_path)) return -1;
 
-#if defined(__linux__)
-    // Find file path from /proc and make sure it is correct
-    char *proc = NULL;
-    if (asprintf(&proc, "/proc/self/fd/%d", fd) < 0) return -1;
-    if (!proc) return -1;
-
-    size_t len = strlen(path);
-    // readlink() does not guarantee a nul byte, len+2 so we catch truncation.
-    char *buf = static_cast<char *>(calloc(1, len + 2));
-    if (!buf) {
-        free(proc);
-        return -1;
+    // Try path, then realpath(path), as keys to get the fd from env.
+    auto fd = __android_get_control_from_env(ANDROID_FILE_ENV_PREFIX, path);
+    if (fd < 0) {
+        fd = __android_get_control_from_env(ANDROID_FILE_ENV_PREFIX, given_path.c_str());
+        if (fd < 0) return fd;
     }
-    ssize_t ret = TEMP_FAILURE_RETRY(readlink(proc, buf, len + 1));
-    free(proc);
-    int cmp = (len != static_cast<size_t>(ret)) || strcmp(buf, path);
-    free(buf);
-    if (ret < 0) return -1;
-    if (cmp != 0) return -1;
+
+    // Find file path from /proc and make sure it is correct
+    auto proc = android::base::StringPrintf("/proc/self/fd/%d", fd);
+    std::string fd_path;
+    if (!android::base::Realpath(proc, &fd_path)) return -1;
+
+    if (given_path != fd_path) return -1;
     // It is what we think it is
-#endif
 
     return fd;
 }
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index f1dcd50..a3df380 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -219,8 +219,6 @@
     { 00755, AID_ROOT,      AID_SHELL,     0, "product/bin/*" },
     { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/*" },
-    { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib/valgrind/*" },
-    { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib64/valgrind/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/xbin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/apex/*/bin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/bin/*" },
diff --git a/libcutils/include/cutils/native_handle.h b/libcutils/include/cutils/native_handle.h
index 10f5bc0..f6cae36 100644
--- a/libcutils/include/cutils/native_handle.h
+++ b/libcutils/include/cutils/native_handle.h
@@ -23,6 +23,9 @@
 extern "C" {
 #endif
 
+#define NATIVE_HANDLE_MAX_FDS 1024
+#define NATIVE_HANDLE_MAX_INTS 1024
+
 /* Declare a char array for use with native_handle_init */
 #define NATIVE_HANDLE_DECLARE_STORAGE(name, maxFds, maxInts) \
     alignas(native_handle_t) char (name)[                            \
diff --git a/libcutils/native_handle.cpp b/libcutils/native_handle.cpp
index 66f7a3d..b409e5b 100644
--- a/libcutils/native_handle.cpp
+++ b/libcutils/native_handle.cpp
@@ -22,9 +22,6 @@
 #include <string.h>
 #include <unistd.h>
 
-static const int kMaxNativeFds = 1024;
-static const int kMaxNativeInts = 1024;
-
 native_handle_t* native_handle_init(char* storage, int numFds, int numInts) {
     if ((uintptr_t) storage % alignof(native_handle_t)) {
         errno = EINVAL;
@@ -39,7 +36,8 @@
 }
 
 native_handle_t* native_handle_create(int numFds, int numInts) {
-    if (numFds < 0 || numInts < 0 || numFds > kMaxNativeFds || numInts > kMaxNativeInts) {
+    if (numFds < 0 || numInts < 0 || numFds > NATIVE_HANDLE_MAX_FDS ||
+        numInts > NATIVE_HANDLE_MAX_INTS) {
         errno = EINVAL;
         return NULL;
     }
diff --git a/libcutils/sockets_unix.cpp b/libcutils/sockets_unix.cpp
index 2248817..6acdcd8 100644
--- a/libcutils/sockets_unix.cpp
+++ b/libcutils/sockets_unix.cpp
@@ -16,8 +16,6 @@
 
 #include <cutils/sockets.h>
 
-#define LOG_TAG "socket-unix"
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -27,9 +25,6 @@
 #include <time.h>
 #include <unistd.h>
 
-#include <cutils/android_get_control_file.h>
-#include <log/log.h>
-
 #include "android_get_control_env.h"
 
 int socket_close(int sock) {
@@ -62,6 +57,7 @@
     return writev(sock, iovec_buffers, num_buffers);
 }
 
+#if defined(__ANDROID__)
 int android_get_control_socket(const char* name) {
     int fd = __android_get_control_from_env(ANDROID_SOCKET_ENV_PREFIX, name);
 
@@ -82,3 +78,8 @@
     }
     return -1;
 }
+#else
+int android_get_control_socket(const char*) {
+    return -1;
+}
+#endif
diff --git a/libkeyutils/Android.bp b/libkeyutils/Android.bp
index e816926..dda491a 100644
--- a/libkeyutils/Android.bp
+++ b/libkeyutils/Android.bp
@@ -19,13 +19,14 @@
 
 cc_binary {
     name: "mini-keyctl",
-    srcs: ["mini_keyctl.cpp"],
-
+    srcs: [
+        "mini_keyctl.cpp",
+        "mini_keyctl_utils.cpp"
+    ],
     shared_libs: [
         "libbase",
         "libkeyutils",
         "liblog",
     ],
-
-    cflags: ["-Werror", "-Wall", "-Wextra"],
+    cflags: ["-Werror", "-Wall", "-Wextra", "-fexceptions"],
 }
diff --git a/libkeyutils/mini_keyctl.cpp b/libkeyutils/mini_keyctl.cpp
index abc8f82..fe89e62 100644
--- a/libkeyutils/mini_keyctl.cpp
+++ b/libkeyutils/mini_keyctl.cpp
@@ -18,159 +18,73 @@
  * A tool loads keys to keyring.
  */
 
-#include <dirent.h>
-#include <errno.h>
-#include <sys/types.h>
+#include "mini_keyctl_utils.h"
+
+#include <error.h>
+#include <stdio.h>
 #include <unistd.h>
 
-#include <fstream>
-#include <iostream>
-#include <iterator>
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android-base/strings.h>
-#include <keyutils.h>
-
-static constexpr int kMaxCertSize = 4096;
-
-// Add all the certs from directory path to keyring with keyring_id. Returns the number of keys
-// added.
-int AddKeys(const std::string& path, const key_serial_t keyring_id, const std::string& keyring_desc,
-            int start_index) {
-  std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(path.c_str()), closedir);
-  if (!dir) {
-    PLOG(WARNING) << "Failed to open directory " << path;
-    return 0;
-  }
-  int keys_added = 0;
-  struct dirent* dp;
-  while ((dp = readdir(dir.get())) != NULL) {
-    if (dp->d_type != DT_REG) {
-      continue;
-    }
-    std::string cert_path = path + "/" + dp->d_name;
-    std::string cert_buf;
-    if (!android::base::ReadFileToString(cert_path, &cert_buf, false /* follow_symlinks */)) {
-      LOG(ERROR) << "Failed to read " << cert_path;
-      continue;
-    }
-
-    if (cert_buf.size() > kMaxCertSize) {
-      LOG(ERROR) << "Certficate size too large: " << cert_path;
-      continue;
-    }
-
-    // Add key to keyring.
-    int key_desc_index = keys_added + start_index;
-    std::string key_desc = keyring_desc + "-key" + std::to_string(key_desc_index);
-    key_serial_t key =
-        add_key("asymmetric", key_desc.c_str(), &cert_buf[0], cert_buf.size(), keyring_id);
-    if (key < 0) {
-      PLOG(ERROR) << "Failed to add key to keyring: " << cert_path;
-      continue;
-    }
-    keys_added++;
-  }
-  return keys_added;
-}
-
-std::vector<std::string> SplitBySpace(const std::string& s) {
-  std::istringstream iss(s);
-  return std::vector<std::string>{std::istream_iterator<std::string>{iss},
-                                  std::istream_iterator<std::string>{}};
-}
-
-// Find the keyring id. Because request_key(2) syscall is not available or the key is
-// kernel keyring, the id is looked up from /proc/keys. The keyring description may contain other
-// information in the descritption section depending on the key type, only the first word in the
-// keyring description is used for searching.
-bool GetKeyringId(const std::string& keyring_desc, key_serial_t* keyring_id) {
-  if (!keyring_id) {
-    LOG(ERROR) << "keyring_id is null";
-    return false;
-  }
-
-  // Only keys allowed by SELinux rules will be shown here.
-  std::ifstream proc_keys_file("/proc/keys");
-  if (!proc_keys_file.is_open()) {
-    PLOG(ERROR) << "Failed to open /proc/keys";
-    return false;
-  }
-
-  std::string line;
-  while (getline(proc_keys_file, line)) {
-    std::vector<std::string> tokens = SplitBySpace(line);
-    if (tokens.size() < 9) {
-      continue;
-    }
-    std::string key_id = tokens[0];
-    std::string key_type = tokens[7];
-    // The key description may contain space.
-    std::string key_desc_prefix = tokens[8];
-    // The prefix has a ":" at the end
-    std::string key_desc_pattern = keyring_desc + ":";
-    if (key_type != "keyring" || key_desc_prefix != key_desc_pattern) {
-      continue;
-    }
-    *keyring_id = std::stoi(key_id, nullptr, 16);
-    return true;
-  }
-  return false;
-}
+#include <android-base/parseint.h>
 
 static void Usage(int exit_code) {
-  fprintf(stderr, "usage: mini-keyctl -c PATHS -s DESCRIPTION\n");
-  fprintf(stderr, "\n");
-  fprintf(stderr, "-c, --cert_dirs     the certificate locations, separated by comma\n");
-  fprintf(stderr, "-k, --keyring       the keyring description\n");
+  fprintf(stderr, "usage: mini-keyctl <action> [args,]\n");
+  fprintf(stderr, "       mini-keyctl add <type> <desc> <data> <keyring>\n");
+  fprintf(stderr, "       mini-keyctl padd <type> <desc> <keyring>\n");
+  fprintf(stderr, "       mini-keyctl unlink <key> <keyring>\n");
+  fprintf(stderr, "       mini-keyctl restrict_keyring <keyring>\n");
+  fprintf(stderr, "       mini-keyctl security <key>\n");
   _exit(exit_code);
 }
 
-int main(int argc, char** argv) {
-  if (argc < 5) Usage(1);
+static key_serial_t parseKeyOrDie(const char* str) {
+  key_serial_t key;
+  if (!android::base::ParseInt(str, &key)) {
+    error(1 /* exit code */, 0 /* errno */, "Unparsable key: '%s'\n", str);
+  }
+  return key;
+}
 
-  std::string arg_cert_dirs;
-  std::string arg_keyring_desc;
+int main(int argc, const char** argv) {
+  if (argc < 2) Usage(1);
+  const std::string action = argv[1];
 
-  for (int i = 1; i < argc; i++) {
-    std::string option = argv[i];
-    if (option == "-c" || option == "--cert_dirs") {
-      if (i + 1 < argc) arg_cert_dirs = argv[++i];
-    } else if (option == "-k" || option == "--keyring") {
-      if (i + 1 < argc) arg_keyring_desc = argv[++i];
+  if (action == "add") {
+    if (argc != 6) Usage(1);
+    std::string type = argv[2];
+    std::string desc = argv[3];
+    std::string data = argv[4];
+    std::string keyring = argv[5];
+    return Add(type, desc, data, keyring);
+  } else if (action == "padd") {
+    if (argc != 5) Usage(1);
+    std::string type = argv[2];
+    std::string desc = argv[3];
+    std::string keyring = argv[4];
+    return Padd(type, desc, keyring);
+  } else if (action == "restrict_keyring") {
+    if (argc != 3) Usage(1);
+    std::string keyring = argv[2];
+    return RestrictKeyring(keyring);
+  } else if (action == "unlink") {
+    if (argc != 4) Usage(1);
+    key_serial_t key = parseKeyOrDie(argv[2]);
+    const std::string keyring = argv[3];
+    return Unlink(key, keyring);
+  } else if (action == "security") {
+    if (argc != 3) Usage(1);
+    const char* key_str = argv[2];
+    key_serial_t key = parseKeyOrDie(key_str);
+    std::string context = RetrieveSecurityContext(key);
+    if (context.empty()) {
+      perror(key_str);
+      return 1;
     }
-  }
-
-  if (arg_cert_dirs.empty() || arg_keyring_desc.empty()) {
-    LOG(ERROR) << "Missing cert_dirs or keyring desc";
+    fprintf(stderr, "%s\n", context.c_str());
+    return 0;
+  } else {
+    fprintf(stderr, "Unrecognized action: %s\n", action.c_str());
     Usage(1);
   }
 
-  // Get the keyring id
-  key_serial_t key_ring_id;
-  if (!GetKeyringId(arg_keyring_desc, &key_ring_id)) {
-    PLOG(ERROR) << "Can't find keyring with " << arg_keyring_desc;
-    return 1;
-  }
-
-  std::vector<std::string> cert_dirs = android::base::Split(arg_cert_dirs, ",");
-  int start_index = 0;
-  for (const auto& cert_dir : cert_dirs) {
-    int keys_added = AddKeys(cert_dir, key_ring_id, arg_keyring_desc, start_index);
-    start_index += keys_added;
-  }
-
-  // Prevent new keys to be added.
-  if (!android::base::GetBoolProperty("ro.debuggable", false) &&
-      keyctl_restrict_keyring(key_ring_id, nullptr, nullptr) < 0) {
-    PLOG(ERROR) << "Failed to restrict key ring " << arg_keyring_desc;
-    return 1;
-  }
-
   return 0;
 }
diff --git a/libkeyutils/mini_keyctl_utils.cpp b/libkeyutils/mini_keyctl_utils.cpp
new file mode 100644
index 0000000..56afea4
--- /dev/null
+++ b/libkeyutils/mini_keyctl_utils.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <mini_keyctl_utils.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <fstream>
+#include <iostream>
+#include <iterator>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <keyutils.h>
+
+static constexpr int kMaxCertSize = 4096;
+
+static std::vector<std::string> SplitBySpace(const std::string& s) {
+  std::istringstream iss(s);
+  return std::vector<std::string>{std::istream_iterator<std::string>{iss},
+                                  std::istream_iterator<std::string>{}};
+}
+
+// Find the keyring id. Because request_key(2) syscall is not available or the key is
+// kernel keyring, the id is looked up from /proc/keys. The keyring description may contain other
+// information in the descritption section depending on the key type, only the first word in the
+// keyring description is used for searching.
+static bool GetKeyringId(const std::string& keyring_desc, key_serial_t* keyring_id) {
+  if (!keyring_id) {
+    LOG(ERROR) << "keyring_id is null";
+    return false;
+  }
+
+  // If the keyring id is already a hex number, directly convert it to keyring id
+  if (android::base::ParseInt(keyring_desc.c_str(), keyring_id)) {
+    return true;
+  }
+
+  // Only keys allowed by SELinux rules will be shown here.
+  std::ifstream proc_keys_file("/proc/keys");
+  if (!proc_keys_file.is_open()) {
+    PLOG(ERROR) << "Failed to open /proc/keys";
+    return false;
+  }
+
+  std::string line;
+  while (getline(proc_keys_file, line)) {
+    std::vector<std::string> tokens = SplitBySpace(line);
+    if (tokens.size() < 9) {
+      continue;
+    }
+    std::string key_id = tokens[0];
+    std::string key_type = tokens[7];
+    // The key description may contain space.
+    std::string key_desc_prefix = tokens[8];
+    // The prefix has a ":" at the end
+    std::string key_desc_pattern = keyring_desc + ":";
+    if (key_type != "keyring" || key_desc_prefix != key_desc_pattern) {
+      continue;
+    }
+    *keyring_id = std::stoi(key_id, nullptr, 16);
+    return true;
+  }
+  return false;
+}
+
+int Unlink(key_serial_t key, const std::string& keyring) {
+  key_serial_t keyring_id;
+  if (!GetKeyringId(keyring, &keyring_id)) {
+    LOG(ERROR) << "Can't find keyring " << keyring;
+    return 1;
+  }
+
+  if (keyctl_unlink(key, keyring_id) < 0) {
+    PLOG(ERROR) << "Failed to unlink key 0x" << std::hex << key << " from keyring " << keyring_id;
+    return 1;
+  }
+  return 0;
+}
+
+int Add(const std::string& type, const std::string& desc, const std::string& data,
+        const std::string& keyring) {
+  if (data.size() > kMaxCertSize) {
+    LOG(ERROR) << "Certificate too large";
+    return 1;
+  }
+
+  key_serial_t keyring_id;
+  if (!GetKeyringId(keyring, &keyring_id)) {
+    LOG(ERROR) << "Can not find keyring id";
+    return 1;
+  }
+
+  key_serial_t key = add_key(type.c_str(), desc.c_str(), data.c_str(), data.size(), keyring_id);
+
+  if (key < 0) {
+    PLOG(ERROR) << "Failed to add key";
+    return 1;
+  }
+
+  LOG(INFO) << "Key " << desc << " added to " << keyring << " with key id: 0x" << std::hex << key;
+  return 0;
+}
+
+int Padd(const std::string& type, const std::string& desc, const std::string& keyring) {
+  key_serial_t keyring_id;
+  if (!GetKeyringId(keyring, &keyring_id)) {
+    LOG(ERROR) << "Can not find keyring id";
+    return 1;
+  }
+
+  // read from stdin to get the certificates
+  std::istreambuf_iterator<char> begin(std::cin), end;
+  std::string data(begin, end);
+
+  if (data.size() > kMaxCertSize) {
+    LOG(ERROR) << "Certificate too large";
+    return 1;
+  }
+
+  key_serial_t key = add_key(type.c_str(), desc.c_str(), data.c_str(), data.size(), keyring_id);
+
+  if (key < 0) {
+    PLOG(ERROR) << "Failed to add key";
+    return 1;
+  }
+
+  LOG(INFO) << "Key " << desc << " added to " << keyring << " with key id: 0x" << std::hex << key;
+  return 0;
+}
+
+int RestrictKeyring(const std::string& keyring) {
+  key_serial_t keyring_id;
+  if (!GetKeyringId(keyring, &keyring_id)) {
+    LOG(ERROR) << "Cannot find keyring id";
+    return 1;
+  }
+
+  if (keyctl_restrict_keyring(keyring_id, nullptr, nullptr) < 0) {
+    PLOG(ERROR) << "Cannot restrict keyring " << keyring;
+    return 1;
+  }
+  return 0;
+}
+
+std::string RetrieveSecurityContext(key_serial_t key) {
+  // Simply assume this size is enough in practice.
+  const int kMaxSupportedSize = 256;
+  std::string context;
+  context.resize(kMaxSupportedSize);
+  long retval = keyctl_get_security(key, context.data(), kMaxSupportedSize);
+  if (retval < 0) {
+    PLOG(ERROR) << "Cannot get security context of key 0x" << std::hex << key;
+    return std::string();
+  }
+  if (retval > kMaxSupportedSize) {
+    LOG(ERROR) << "The key has unexpectedly long security context than " << kMaxSupportedSize;
+    return std::string();
+  }
+  context.resize(retval);
+  return context;
+}
diff --git a/libkeyutils/mini_keyctl_utils.h b/libkeyutils/mini_keyctl_utils.h
new file mode 100644
index 0000000..3616831
--- /dev/null
+++ b/libkeyutils/mini_keyctl_utils.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "include/keyutils.h"
+
+#include <string>
+
+// Add key to a keyring. Returns non-zero if error happens.
+int Add(const std::string& type, const std::string& desc, const std::string& data,
+        const std::string& keyring);
+
+// Add key from stdin to a keyring. Returns non-zero if error happens.
+int Padd(const std::string& type, const std::string& desc, const std::string& keyring);
+
+// Removes the link from a keyring to a key if exists. Return non-zero if error happens.
+int Unlink(key_serial_t key, const std::string& keyring);
+
+// Apply key-linking to a keyring. Return non-zero if error happens.
+int RestrictKeyring(const std::string& keyring);
+
+// Retrieves a key's security context. Return the context string, or empty string on error.
+std::string RetrieveSecurityContext(key_serial_t key);
diff --git a/liblog/logger_name.cpp b/liblog/logger_name.cpp
index 3aa6841..ece0550 100644
--- a/liblog/logger_name.cpp
+++ b/liblog/logger_name.cpp
@@ -50,8 +50,9 @@
   unsigned int ret;
 
   if (!logName) {
-    return static_cast<log_id_t>(0xFFFFFFFF);
+    return static_cast<log_id_t>(LOG_ID_MAX);
   }
+
   b = strrchr(logName, '/');
   if (!b) {
     b = logName;
@@ -65,5 +66,6 @@
       return static_cast<log_id_t>(ret);
     }
   }
-  return static_cast<log_id_t>(0xFFFFFFFF); /* should never happen */
+
+  return static_cast<log_id_t>(LOG_ID_MAX);
 }
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index 908fe7f..7fa3f43 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -413,6 +413,8 @@
   if (!tag) tag = "";
 
   /* XXX: This needs to go! */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wstring-plus-int"
   if (bufID != LOG_ID_RADIO) {
     switch (tag[0]) {
       case 'H':
@@ -454,6 +456,7 @@
         break;
     }
   }
+#pragma clang diagnostic pop
 
 #if __BIONIC__
   if (prio == ANDROID_LOG_FATAL) {
diff --git a/libmemtrack/Android.bp b/libmemtrack/Android.bp
index 320b851..4e4554a 100644
--- a/libmemtrack/Android.bp
+++ b/libmemtrack/Android.bp
@@ -6,7 +6,6 @@
     vndk: {
         enabled: true,
     },
-    double_loadable: true,
     srcs: ["memtrack.cpp"],
     export_include_dirs: ["include"],
     local_include_dirs: ["include"],
diff --git a/libmemunreachable/HeapWalker.cpp b/libmemunreachable/HeapWalker.cpp
index 89837f7..7cae048 100644
--- a/libmemunreachable/HeapWalker.cpp
+++ b/libmemunreachable/HeapWalker.cpp
@@ -59,12 +59,19 @@
   }
 }
 
+// Sanitizers may consider certain memory inaccessible through certain pointers.
+// With MTE this will need to use unchecked instructions or disable tag checking globally.
+static uintptr_t ReadWordAtAddressUnsafe(uintptr_t word_ptr)
+    __attribute__((no_sanitize("address", "hwaddress"))) {
+  return *reinterpret_cast<uintptr_t*>(word_ptr);
+}
+
 bool HeapWalker::WordContainsAllocationPtr(uintptr_t word_ptr, Range* range, AllocationInfo** info) {
   walking_ptr_ = word_ptr;
   // This access may segfault if the process under test has done something strange,
   // for example mprotect(PROT_NONE) on a native heap page.  If so, it will be
   // caught and handled by mmaping a zero page over the faulting page.
-  uintptr_t value = *reinterpret_cast<uintptr_t*>(word_ptr);
+  uintptr_t value = ReadWordAtAddressUnsafe(word_ptr);
   walking_ptr_ = 0;
   if (value >= valid_allocations_range_.begin && value < valid_allocations_range_.end) {
     AllocationMap::iterator it = allocations_.find(Range{value, value + 1});
@@ -200,6 +207,6 @@
   }
 }
 
-ScopedSignalHandler::SignalFn ScopedSignalHandler::handler_;
+Allocator<ScopedSignalHandler::SignalFnMap>::unique_ptr ScopedSignalHandler::handler_map_;
 
 }  // namespace android
diff --git a/libmemunreachable/HeapWalker.h b/libmemunreachable/HeapWalker.h
index 9e3db08..f00bcca 100644
--- a/libmemunreachable/HeapWalker.h
+++ b/libmemunreachable/HeapWalker.h
@@ -52,7 +52,8 @@
         allocation_bytes_(0),
         roots_(allocator),
         root_vals_(allocator),
-        segv_handler_(),
+        sigsegv_handler_(allocator),
+        sigbus_handler_(allocator),
         walking_ptr_(0),
         walking_range_{0, 0},
         segv_logged_(false),
@@ -62,10 +63,14 @@
     valid_mappings_range_.end = 0;
     valid_mappings_range_.begin = ~valid_allocations_range_.end;
 
-    segv_handler_.install(
+    sigsegv_handler_.install(
         SIGSEGV, [=](ScopedSignalHandler& handler, int signal, siginfo_t* siginfo, void* uctx) {
           this->HandleSegFault(handler, signal, siginfo, uctx);
         });
+    sigbus_handler_.install(
+        SIGBUS, [=](ScopedSignalHandler& handler, int signal, siginfo_t* siginfo, void* uctx) {
+          this->HandleSegFault(handler, signal, siginfo, uctx);
+        });
   }
 
   ~HeapWalker() {}
@@ -106,7 +111,8 @@
   allocator::vector<Range> roots_;
   allocator::vector<uintptr_t> root_vals_;
 
-  ScopedSignalHandler segv_handler_;
+  ScopedSignalHandler sigsegv_handler_;
+  ScopedSignalHandler sigbus_handler_;
   volatile uintptr_t walking_ptr_;
   Range walking_range_;
   bool segv_logged_;
diff --git a/libmemunreachable/MemUnreachable.cpp b/libmemunreachable/MemUnreachable.cpp
index 3d7b8a8..299c320 100644
--- a/libmemunreachable/MemUnreachable.cpp
+++ b/libmemunreachable/MemUnreachable.cpp
@@ -217,6 +217,10 @@
   return ret == 0;
 }
 
+static bool is_sanitizer_mapping(const allocator::string& s) {
+  return s == "[anon:low shadow]" || s == "[anon:high shadow]" || has_prefix(s, "[anon:hwasan");
+}
+
 bool MemUnreachable::ClassifyMappings(const allocator::vector<Mapping>& mappings,
                                       allocator::vector<Mapping>& heap_mappings,
                                       allocator::vector<Mapping>& anon_mappings,
@@ -258,7 +262,8 @@
     } else if (mapping_name.size() == 0) {
       globals_mappings.emplace_back(*it);
     } else if (has_prefix(mapping_name, "[anon:") &&
-               mapping_name != "[anon:leak_detector_malloc]") {
+               mapping_name != "[anon:leak_detector_malloc]" &&
+               !is_sanitizer_mapping(mapping_name)) {
       // TODO(ccross): it would be nice to treat named anonymous mappings as
       // possible leaks, but naming something in a .bss or .data section makes
       // it impossible to distinguish them from mmaped and then named mappings.
diff --git a/libmemunreachable/ScopedSignalHandler.h b/libmemunreachable/ScopedSignalHandler.h
index 9e08a8e..ef4473f 100644
--- a/libmemunreachable/ScopedSignalHandler.h
+++ b/libmemunreachable/ScopedSignalHandler.h
@@ -24,6 +24,7 @@
 
 #include "android-base/macros.h"
 
+#include "Allocator.h"
 #include "log.h"
 
 namespace android {
@@ -32,17 +33,29 @@
  public:
   using Fn = std::function<void(ScopedSignalHandler&, int, siginfo_t*, void*)>;
 
-  explicit ScopedSignalHandler() : signal_(-1) {}
+  explicit ScopedSignalHandler(Allocator<ScopedSignalHandler> allocator) : signal_(-1) {
+    if (handler_map_ == nullptr) {
+      Allocator<SignalFnMap> map_allocator = allocator;
+      handler_map_ = map_allocator.make_unique(allocator);
+    }
+  }
   ~ScopedSignalHandler() { reset(); }
 
   template <class F>
   void install(int signal, F&& f) {
     if (signal_ != -1) MEM_LOG_ALWAYS_FATAL("ScopedSignalHandler already installed");
 
-    handler_ = SignalFn([=](int signal, siginfo_t* si, void* uctx) { f(*this, signal, si, uctx); });
+    if (handler_map_->find(signal) != handler_map_->end()) {
+      MEM_LOG_ALWAYS_FATAL("ScopedSignalHandler already installed for %d", signal);
+    }
+
+    (*handler_map_)[signal] =
+        SignalFn([=](int signal, siginfo_t* si, void* uctx) { f(*this, signal, si, uctx); });
 
     struct sigaction act {};
-    act.sa_sigaction = [](int signal, siginfo_t* si, void* uctx) { handler_(signal, si, uctx); };
+    act.sa_sigaction = [](int signal, siginfo_t* si, void* uctx) {
+      ((*handler_map_)[signal])(signal, si, uctx);
+    };
     act.sa_flags = SA_SIGINFO;
 
     int ret = sigaction(signal, &act, &old_act_);
@@ -59,19 +72,22 @@
       if (ret < 0) {
         MEM_ALOGE("failed to uninstall segfault handler");
       }
-      handler_ = SignalFn{};
+
+      handler_map_->erase(signal_);
+      if (handler_map_->empty()) {
+        handler_map_.reset();
+      }
       signal_ = -1;
     }
   }
 
  private:
   using SignalFn = std::function<void(int, siginfo_t*, void*)>;
+  using SignalFnMap = allocator::unordered_map<int, SignalFn>;
   DISALLOW_COPY_AND_ASSIGN(ScopedSignalHandler);
   int signal_;
   struct sigaction old_act_;
-  // TODO(ccross): to support multiple ScopedSignalHandlers handler_ would need
-  // to be a static map of signals to handlers, but allocated with Allocator.
-  static SignalFn handler_;
+  static Allocator<SignalFnMap>::unique_ptr handler_map_;
 };
 
 }  // namespace android
diff --git a/libnativeloader/include/nativeloader/native_loader.h b/libnativeloader/include/nativeloader/native_loader.h
index 260f655..51fb875 100644
--- a/libnativeloader/include/nativeloader/native_loader.h
+++ b/libnativeloader/include/nativeloader/native_loader.h
@@ -36,14 +36,9 @@
 __attribute__((visibility("default")))
 void InitializeNativeLoader();
 
-__attribute__((visibility("default")))
-jstring CreateClassLoaderNamespace(JNIEnv* env,
-                                   int32_t target_sdk_version,
-                                   jobject class_loader,
-                                   bool is_shared,
-                                   bool is_for_vendor,
-                                   jstring library_path,
-                                   jstring permitted_path);
+__attribute__((visibility("default"))) jstring CreateClassLoaderNamespace(
+    JNIEnv* env, int32_t target_sdk_version, jobject class_loader, bool is_shared, jstring dex_path,
+    jstring library_path, jstring permitted_path);
 
 __attribute__((visibility("default"))) void* OpenNativeLibrary(
     JNIEnv* env, int32_t target_sdk_version, const char* path, jobject class_loader,
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 043f038..5cc0857 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -31,6 +31,7 @@
 #include <list>
 #include <memory>
 #include <mutex>
+#include <regex>
 #include <string>
 #include <vector>
 
@@ -140,10 +141,24 @@
 
 #if defined(__LP64__)
 static constexpr const char* kRuntimeApexLibPath = "/apex/com.android.runtime/lib64";
+static constexpr const char* kVendorLibPath = "/vendor/lib64";
+static constexpr const char* kProductLibPath = "/product/lib64:/system/product/lib64";
 #else
 static constexpr const char* kRuntimeApexLibPath = "/apex/com.android.runtime/lib";
+static constexpr const char* kVendorLibPath = "/vendor/lib";
+static constexpr const char* kProductLibPath = "/product/lib:/system/product/lib";
 #endif
 
+static const std::regex kVendorDexPathRegex("(^|:)/vendor/");
+static const std::regex kProductDexPathRegex("(^|:)(/system)?/product/");
+
+// Define origin of APK if it is from vendor partition or product partition
+typedef enum {
+  APK_ORIGIN_DEFAULT = 0,
+  APK_ORIGIN_VENDOR = 1,
+  APK_ORIGIN_PRODUCT = 2,
+} ApkOrigin;
+
 static bool is_debuggable() {
   bool debuggable = false;
 #ifdef __BIONIC__
@@ -179,7 +194,7 @@
   LibraryNamespaces() : initialized_(false) { }
 
   NativeLoaderNamespace* Create(JNIEnv* env, uint32_t target_sdk_version, jobject class_loader,
-                                bool is_shared, bool is_for_vendor, jstring java_library_path,
+                                bool is_shared, jstring dex_path, jstring java_library_path,
                                 jstring java_permitted_path, std::string* error_msg) {
     std::string library_path; // empty string by default.
 
@@ -188,6 +203,8 @@
       library_path = library_path_utf_chars.c_str();
     }
 
+    ApkOrigin apk_origin = GetApkOriginFromDexPath(env, dex_path);
+
     // (http://b/27588281) This is a workaround for apps using custom
     // classloaders and calling System.load() with an absolute path which
     // is outside of the classloader library search path.
@@ -234,31 +251,51 @@
     std::string system_exposed_libraries = system_public_libraries_;
     const char* namespace_name = kClassloaderNamespaceName;
     android_namespace_t* vndk_ns = nullptr;
-    if (is_for_vendor && !is_shared) {
-      LOG_FATAL_IF(is_native_bridge, "Unbundled vendor apk must not use translated architecture");
+    if ((apk_origin == APK_ORIGIN_VENDOR ||
+         (apk_origin == APK_ORIGIN_PRODUCT && target_sdk_version > 29)) &&
+        !is_shared) {
+      LOG_FATAL_IF(is_native_bridge,
+                   "Unbundled vendor / product apk must not use translated architecture");
 
-      // For vendor apks, give access to the vendor lib even though
+      // For vendor / product apks, give access to the vendor / product lib even though
       // they are treated as unbundled; the libs and apks are still bundled
-      // together in the vendor partition.
-#if defined(__LP64__)
-      std::string vendor_lib_path = "/vendor/lib64";
-#else
-      std::string vendor_lib_path = "/vendor/lib";
-#endif
-      library_path = library_path + ":" + vendor_lib_path.c_str();
-      permitted_path = permitted_path + ":" + vendor_lib_path.c_str();
+      // together in the vendor / product partition.
+      const char* origin_partition;
+      const char* origin_lib_path;
+
+      switch (apk_origin) {
+        case APK_ORIGIN_VENDOR:
+          origin_partition = "vendor";
+          origin_lib_path = kVendorLibPath;
+          break;
+        case APK_ORIGIN_PRODUCT:
+          origin_partition = "product";
+          origin_lib_path = kProductLibPath;
+          break;
+        default:
+          origin_partition = "unknown";
+          origin_lib_path = "";
+      }
+
+      LOG_FATAL_IF(is_native_bridge, "Unbundled %s apk must not use translated architecture",
+                   origin_partition);
+
+      library_path = library_path + ":" + origin_lib_path;
+      permitted_path = permitted_path + ":" + origin_lib_path;
 
       // Also give access to LLNDK libraries since they are available to vendors
       system_exposed_libraries = system_exposed_libraries + ":" + system_llndk_libraries_.c_str();
 
       // Give access to VNDK-SP libraries from the 'vndk' namespace.
       vndk_ns = android_get_exported_namespace(kVndkNamespaceName);
-      LOG_ALWAYS_FATAL_IF(vndk_ns == nullptr,
-                          "Cannot find \"%s\" namespace for vendor apks", kVndkNamespaceName);
+      if (vndk_ns == nullptr) {
+        ALOGW("Cannot find \"%s\" namespace for %s apks", kVndkNamespaceName, origin_partition);
+      }
 
       // Different name is useful for debugging
       namespace_name = kVendorClassloaderNamespaceName;
-      ALOGD("classloader namespace configured for unbundled vendor apk. library_path=%s", library_path.c_str());
+      ALOGD("classloader namespace configured for unbundled %s apk. library_path=%s",
+            origin_partition, library_path.c_str());
     } else {
       // oem and product public libraries are NOT available to vendor apks, otherwise it
       // would be system->vendor violation.
@@ -660,6 +697,28 @@
     return nullptr;
   }
 
+  ApkOrigin GetApkOriginFromDexPath(JNIEnv* env, jstring dex_path) {
+    ApkOrigin apk_origin = APK_ORIGIN_DEFAULT;
+
+    if (dex_path != nullptr) {
+      ScopedUtfChars dex_path_utf_chars(env, dex_path);
+
+      if (std::regex_search(dex_path_utf_chars.c_str(), kVendorDexPathRegex)) {
+        apk_origin = APK_ORIGIN_VENDOR;
+      }
+
+      if (std::regex_search(dex_path_utf_chars.c_str(), kProductDexPathRegex)) {
+        LOG_ALWAYS_FATAL_IF(apk_origin == APK_ORIGIN_VENDOR,
+                            "Dex path contains both vendor and product partition : %s",
+                            dex_path_utf_chars.c_str());
+
+        apk_origin = APK_ORIGIN_PRODUCT;
+      }
+    }
+
+    return apk_origin;
+  }
+
   bool initialized_;
   std::list<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
   std::string system_public_libraries_;
@@ -690,31 +749,20 @@
 #endif
 }
 
-jstring CreateClassLoaderNamespace(JNIEnv* env,
-                                   int32_t target_sdk_version,
-                                   jobject class_loader,
-                                   bool is_shared,
-                                   bool is_for_vendor,
-                                   jstring library_path,
+jstring CreateClassLoaderNamespace(JNIEnv* env, int32_t target_sdk_version, jobject class_loader,
+                                   bool is_shared, jstring dex_path, jstring library_path,
                                    jstring permitted_path) {
 #if defined(__ANDROID__)
   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
 
   std::string error_msg;
-  bool success = g_namespaces->Create(env,
-                                      target_sdk_version,
-                                      class_loader,
-                                      is_shared,
-                                      is_for_vendor,
-                                      library_path,
-                                      permitted_path,
-                                      &error_msg) != nullptr;
+  bool success = g_namespaces->Create(env, target_sdk_version, class_loader, is_shared, dex_path,
+                                      library_path, permitted_path, &error_msg) != nullptr;
   if (!success) {
     return env->NewStringUTF(error_msg.c_str());
   }
 #else
-  UNUSED(env, target_sdk_version, class_loader, is_shared, is_for_vendor,
-         library_path, permitted_path);
+  UNUSED(env, target_sdk_version, class_loader, is_shared, dex_path, library_path, permitted_path);
 #endif
   return nullptr;
 }
@@ -779,8 +827,7 @@
     // In this case we create an isolated not-shared namespace for it.
     std::string create_error_msg;
     if ((ns = g_namespaces->Create(env, target_sdk_version, class_loader, false /* is_shared */,
-                                   false /* is_for_vendor */, library_path, nullptr,
-                                   &create_error_msg)) == nullptr) {
+                                   nullptr, library_path, nullptr, &create_error_msg)) == nullptr) {
       *error_msg = strdup(create_error_msg.c_str());
       return nullptr;
     }
diff --git a/libnativeloader/native_loader_lazy.cpp b/libnativeloader/native_loader_lazy.cpp
index 11ecc43..2eb1203 100644
--- a/libnativeloader/native_loader_lazy.cpp
+++ b/libnativeloader/native_loader_lazy.cpp
@@ -50,10 +50,10 @@
 }
 
 jstring CreateClassLoaderNamespace(JNIEnv* env, int32_t target_sdk_version, jobject class_loader,
-                                   bool is_shared, bool is_for_vendor, jstring library_path,
+                                   bool is_shared, jstring dex_path, jstring library_path,
                                    jstring permitted_path) {
   static auto f = GET_FUNC_PTR(CreateClassLoaderNamespace);
-  return f(env, target_sdk_version, class_loader, is_shared, is_for_vendor, library_path,
+  return f(env, target_sdk_version, class_loader, is_shared, dex_path, library_path,
            permitted_path);
 }
 
diff --git a/libpackagelistparser/include/packagelistparser/packagelistparser.h b/libpackagelistparser/include/packagelistparser/packagelistparser.h
index 8bcc1e2..3cb6b9a 100644
--- a/libpackagelistparser/include/packagelistparser/packagelistparser.h
+++ b/libpackagelistparser/include/packagelistparser/packagelistparser.h
@@ -54,6 +54,7 @@
     gid_list gids;
     void *private_data;
     bool profileable_from_shell;
+    long version_code;
 };
 
 /**
diff --git a/libpackagelistparser/packagelistparser.c b/libpackagelistparser/packagelistparser.c
index 4ce2363..edc533c 100644
--- a/libpackagelistparser/packagelistparser.c
+++ b/libpackagelistparser/packagelistparser.c
@@ -239,6 +239,15 @@
 
             pkg_info->profileable_from_shell = (bool)tmp;
         }
+        cur = strsep(&next, " \t\r\n");
+        if (cur) {
+            tmp = strtoul(cur, &endptr, 10);
+            if (*endptr != '\0') {
+                errmsg = "Could not convert field \"versionCode\" to integer value";
+                goto err;
+            }
+            pkg_info->version_code = tmp;
+        }
 
         rc = callback(pkg_info, userdata);
         if (rc == false) {
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index d97f09f..07cbce9 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -45,5 +45,6 @@
     cflags: [
         "-Wall",
         "-Werror",
+        "-Wexit-time-destructors",
     ],
 }
diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp
index 26d0754..1e66fa4 100644
--- a/libprocessgroup/cgroup_map.cpp
+++ b/libprocessgroup/cgroup_map.cpp
@@ -117,7 +117,7 @@
     std::string json_doc;
 
     if (!android::base::ReadFileToString(file_name, &json_doc)) {
-        LOG(ERROR) << "Failed to read task profiles from " << file_name;
+        PLOG(ERROR) << "Failed to read task profiles from " << file_name;
         return false;
     }
 
@@ -185,7 +185,7 @@
 
     // mkdir <path> [mode] [owner] [group]
     if (!Mkdir(controller->path(), descriptor.mode(), descriptor.uid(), descriptor.gid())) {
-        PLOG(ERROR) << "Failed to create directory for " << controller->name() << " cgroup";
+        LOG(ERROR) << "Failed to create directory for " << controller->name() << " cgroup";
         return false;
     }
 
@@ -227,13 +227,16 @@
 
 #endif
 
+// WARNING: This function should be called only from SetupCgroups and only once.
+// It intentionally leaks an FD, so additional invocation will result in additional leak.
 static bool WriteRcFile(const std::map<std::string, CgroupDescriptor>& descriptors) {
-    std::string cgroup_rc_path = StringPrintf("%s/%s", CGROUPS_RC_DIR, CgroupMap::CGROUPS_RC_FILE);
-    unique_fd fd(TEMP_FAILURE_RETRY(open(cgroup_rc_path.c_str(),
-                                         O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC,
-                                         S_IRUSR | S_IRGRP | S_IROTH)));
+    // WARNING: We are intentionally leaking the FD to keep the file open forever.
+    // Let init keep the FD open to prevent file mappings from becoming invalid in
+    // case the file gets deleted somehow.
+    int fd = TEMP_FAILURE_RETRY(open(CGROUPS_RC_PATH, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC,
+                                     S_IRUSR | S_IRGRP | S_IROTH));
     if (fd < 0) {
-        PLOG(ERROR) << "open() failed for " << cgroup_rc_path;
+        PLOG(ERROR) << "open() failed for " << CGROUPS_RC_PATH;
         return false;
     }
 
@@ -242,14 +245,14 @@
     fl.controller_count_ = descriptors.size();
     int ret = TEMP_FAILURE_RETRY(write(fd, &fl, sizeof(fl)));
     if (ret < 0) {
-        PLOG(ERROR) << "write() failed for " << cgroup_rc_path;
+        PLOG(ERROR) << "write() failed for " << CGROUPS_RC_PATH;
         return false;
     }
 
     for (const auto& [name, descriptor] : descriptors) {
         ret = TEMP_FAILURE_RETRY(write(fd, descriptor.controller(), sizeof(CgroupController)));
         if (ret < 0) {
-            PLOG(ERROR) << "write() failed for " << cgroup_rc_path;
+            PLOG(ERROR) << "write() failed for " << CGROUPS_RC_PATH;
             return false;
         }
     }
@@ -289,7 +292,7 @@
     std::string file_name = StringPrintf("/proc/%d/cgroup", tid);
     std::string content;
     if (!android::base::ReadFileToString(file_name, &content)) {
-        LOG(ERROR) << "Failed to read " << file_name;
+        PLOG(ERROR) << "Failed to read " << file_name;
         return false;
     }
 
@@ -323,7 +326,7 @@
 
 CgroupMap::CgroupMap() : cg_file_data_(nullptr), cg_file_size_(0) {
     if (!LoadRcFile()) {
-        PLOG(ERROR) << "CgroupMap::LoadRcFile called for [" << getpid() << "] failed";
+        LOG(ERROR) << "CgroupMap::LoadRcFile called for [" << getpid() << "] failed";
     }
 }
 
@@ -336,8 +339,10 @@
 }
 
 CgroupMap& CgroupMap::GetInstance() {
-    static CgroupMap instance;
-    return instance;
+    // Deliberately leak this object to avoid a race between destruction on
+    // process exit and concurrent access from another thread.
+    static auto* instance = new CgroupMap;
+    return *instance;
 }
 
 bool CgroupMap::LoadRcFile() {
@@ -348,39 +353,53 @@
         return true;
     }
 
-    std::string cgroup_rc_path = StringPrintf("%s/%s", CGROUPS_RC_DIR, CGROUPS_RC_FILE);
-    unique_fd fd(TEMP_FAILURE_RETRY(open(cgroup_rc_path.c_str(), O_RDONLY | O_CLOEXEC)));
+    unique_fd fd(TEMP_FAILURE_RETRY(open(CGROUPS_RC_PATH, O_RDONLY | O_CLOEXEC)));
     if (fd < 0) {
-        PLOG(ERROR) << "open() failed for " << cgroup_rc_path;
+        PLOG(ERROR) << "open() failed for " << CGROUPS_RC_PATH;
         return false;
     }
 
     if (fstat(fd, &sb) < 0) {
-        PLOG(ERROR) << "fstat() failed for " << cgroup_rc_path;
+        PLOG(ERROR) << "fstat() failed for " << CGROUPS_RC_PATH;
         return false;
     }
 
-    cg_file_size_ = sb.st_size;
-    if (cg_file_size_ < sizeof(CgroupFile)) {
-        PLOG(ERROR) << "Invalid file format " << cgroup_rc_path;
+    size_t file_size = sb.st_size;
+    if (file_size < sizeof(CgroupFile)) {
+        LOG(ERROR) << "Invalid file format " << CGROUPS_RC_PATH;
         return false;
     }
 
-    cg_file_data_ = (CgroupFile*)mmap(nullptr, cg_file_size_, PROT_READ, MAP_SHARED, fd, 0);
-    if (cg_file_data_ == MAP_FAILED) {
-        PLOG(ERROR) << "Failed to mmap " << cgroup_rc_path;
+    CgroupFile* file_data = (CgroupFile*)mmap(nullptr, file_size, PROT_READ, MAP_SHARED, fd, 0);
+    if (file_data == MAP_FAILED) {
+        PLOG(ERROR) << "Failed to mmap " << CGROUPS_RC_PATH;
         return false;
     }
 
-    if (cg_file_data_->version_ != CgroupFile::FILE_CURR_VERSION) {
-        PLOG(ERROR) << cgroup_rc_path << " file version mismatch";
+    if (file_data->version_ != CgroupFile::FILE_CURR_VERSION) {
+        LOG(ERROR) << CGROUPS_RC_PATH << " file version mismatch";
+        munmap(file_data, file_size);
         return false;
     }
 
+    if (file_size != sizeof(CgroupFile) + file_data->controller_count_ * sizeof(CgroupController)) {
+        LOG(ERROR) << CGROUPS_RC_PATH << " file has invalid size";
+        munmap(file_data, file_size);
+        return false;
+    }
+
+    cg_file_data_ = file_data;
+    cg_file_size_ = file_size;
+
     return true;
 }
 
-void CgroupMap::Print() {
+void CgroupMap::Print() const {
+    if (!cg_file_data_) {
+        LOG(ERROR) << "CgroupMap::Print called for [" << getpid()
+                   << "] failed, RC file was not initialized properly";
+        return;
+    }
     LOG(INFO) << "File version = " << cg_file_data_->version_;
     LOG(INFO) << "File controller count = " << cg_file_data_->controller_count_;
 
@@ -395,9 +414,21 @@
 bool CgroupMap::SetupCgroups() {
     std::map<std::string, CgroupDescriptor> descriptors;
 
+    if (getpid() != 1) {
+        LOG(ERROR) << "Cgroup setup can be done only by init process";
+        return false;
+    }
+
+    // Make sure we do this only one time. No need for std::call_once because
+    // init is a single-threaded process
+    if (access(CGROUPS_RC_PATH, F_OK) == 0) {
+        LOG(WARNING) << "Attempt to call SetupCgroups more than once";
+        return true;
+    }
+
     // load cgroups.json file
     if (!ReadDescriptors(&descriptors)) {
-        PLOG(ERROR) << "Failed to load cgroup description file";
+        LOG(ERROR) << "Failed to load cgroup description file";
         return false;
     }
 
@@ -411,8 +442,8 @@
     }
 
     // mkdir <CGROUPS_RC_DIR> 0711 system system
-    if (!Mkdir(CGROUPS_RC_DIR, 0711, "system", "system")) {
-        PLOG(ERROR) << "Failed to create directory for <CGROUPS_RC_FILE> file";
+    if (!Mkdir(android::base::Dirname(CGROUPS_RC_PATH), 0711, "system", "system")) {
+        LOG(ERROR) << "Failed to create directory for " << CGROUPS_RC_PATH << " file";
         return false;
     }
 
@@ -421,14 +452,13 @@
     // and limits infrormation shared with unprivileged processes
     // to the minimum subset of information from cgroups.json
     if (!WriteRcFile(descriptors)) {
-        LOG(ERROR) << "Failed to write " << CGROUPS_RC_FILE << " file";
+        LOG(ERROR) << "Failed to write " << CGROUPS_RC_PATH << " file";
         return false;
     }
 
-    std::string cgroup_rc_path = StringPrintf("%s/%s", CGROUPS_RC_DIR, CGROUPS_RC_FILE);
-    // chmod 0644 <cgroup_rc_path>
-    if (fchmodat(AT_FDCWD, cgroup_rc_path.c_str(), 0644, AT_SYMLINK_NOFOLLOW) < 0) {
-        LOG(ERROR) << "fchmodat() failed";
+    // chmod 0644 <CGROUPS_RC_PATH>
+    if (fchmodat(AT_FDCWD, CGROUPS_RC_PATH, 0644, AT_SYMLINK_NOFOLLOW) < 0) {
+        PLOG(ERROR) << "fchmodat() failed";
         return false;
     }
 
@@ -437,6 +467,8 @@
 
 const CgroupController* CgroupMap::FindController(const std::string& name) const {
     if (!cg_file_data_) {
+        LOG(ERROR) << "CgroupMap::FindController called for [" << getpid()
+                   << "] failed, RC file was not initialized properly";
         return nullptr;
     }
 
diff --git a/libprocessgroup/cgroup_map.h b/libprocessgroup/cgroup_map.h
index ba2caf7..304ae15 100644
--- a/libprocessgroup/cgroup_map.h
+++ b/libprocessgroup/cgroup_map.h
@@ -75,8 +75,6 @@
 
 class CgroupMap {
   public:
-    static constexpr const char* CGROUPS_RC_FILE = "cgroup.rc";
-
     // Selinux policy ensures only init process can successfully use this function
     static bool SetupCgroups();
 
@@ -92,5 +90,5 @@
     ~CgroupMap();
 
     bool LoadRcFile();
-    void Print();
+    void Print() const;
 };
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index 6f973b8..46b8676 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -24,7 +24,7 @@
 __BEGIN_DECLS
 
 static constexpr const char* CGROUPV2_CONTROLLER_NAME = "cgroup2";
-static constexpr const char* CGROUPS_RC_DIR = "/dev/cgroup_info";
+static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc";
 
 bool CgroupSetupCgroups();
 bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path);
diff --git a/libprocessgroup/profiles/Android.bp b/libprocessgroup/profiles/Android.bp
index 15d0172..e05a690 100644
--- a/libprocessgroup/profiles/Android.bp
+++ b/libprocessgroup/profiles/Android.bp
@@ -29,9 +29,21 @@
     src: "task_profiles.json",
 }
 
+cc_defaults {
+    name: "libprocessgroup_test_defaults",
+    cflags: [
+        "-Wall",
+        "-Werror",
+
+        // Needed for headers from libprotobuf.
+        "-Wno-unused-parameter",
+    ],
+}
+
 cc_library_static {
     name: "libprocessgroup_proto",
     host_supported: true,
+    defaults: ["libprocessgroup_test_defaults"],
     srcs: [
         "cgroups.proto",
         "task_profiles.proto",
@@ -40,15 +52,11 @@
         type: "full",
         export_proto_headers: true,
     },
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wno-unused-parameter",
-    ],
 }
 
 cc_test_host {
     name: "libprocessgroup_proto_test",
+    defaults: ["libprocessgroup_test_defaults"],
     srcs: [
         "test.cpp",
     ],
@@ -64,11 +72,6 @@
     shared_libs: [
         "libprotobuf-cpp-full",
     ],
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wno-unused-parameter",
-    ],
     data: [
         "cgroups.json",
         "cgroups.recovery.json",
@@ -78,3 +81,28 @@
         "general-tests",
     ],
 }
+
+cc_test {
+    name: "vts_processgroup_validate_test",
+    defaults: ["libprocessgroup_test_defaults"],
+    srcs: [
+        "test_vendor.cpp",
+    ],
+    static_libs: [
+        "libgmock",
+        "libjsonpbverify",
+        "libjsonpbparse",
+        "libprocessgroup_proto",
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libjsoncpp",
+        "libprotobuf-cpp-full",
+    ],
+    target: {
+        android: {
+            test_config: "vts_processgroup_validate_test.xml",
+        },
+    },
+}
diff --git a/libprocessgroup/profiles/Android.mk b/libprocessgroup/profiles/Android.mk
new file mode 100644
index 0000000..eab96d4
--- /dev/null
+++ b/libprocessgroup/profiles/Android.mk
@@ -0,0 +1,21 @@
+#
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := VtsProcessgroupValidateTest
+-include test/vts/tools/build/Android.host_config.mk
diff --git a/libprocessgroup/profiles/cgroups_test.h b/libprocessgroup/profiles/cgroups_test.h
new file mode 100644
index 0000000..1309957
--- /dev/null
+++ b/libprocessgroup/profiles/cgroups_test.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <gmock/gmock.h>
+#include <jsonpb/json_schema_test.h>
+
+#include "cgroups.pb.h"
+
+using ::testing::MatchesRegex;
+
+namespace android {
+namespace profiles {
+
+class CgroupsTest : public jsonpb::JsonSchemaTest {
+  public:
+    void SetUp() override {
+        JsonSchemaTest::SetUp();
+        cgroups_ = static_cast<Cgroups*>(message());
+    }
+    Cgroups* cgroups_;
+};
+
+TEST_P(CgroupsTest, CgroupRequiredFields) {
+    for (int i = 0; i < cgroups_->cgroups_size(); ++i) {
+        auto&& cgroup = cgroups_->cgroups(i);
+        EXPECT_FALSE(cgroup.controller().empty())
+                << "No controller name for cgroup #" << i << " in " << file_path_;
+        EXPECT_FALSE(cgroup.path().empty()) << "No path for cgroup #" << i << " in " << file_path_;
+    }
+}
+
+TEST_P(CgroupsTest, Cgroup2RequiredFields) {
+    if (cgroups_->has_cgroups2()) {
+        EXPECT_FALSE(cgroups_->cgroups2().path().empty())
+                << "No path for cgroup2 in " << file_path_;
+    }
+}
+
+// "Mode" field must be in the format of "0xxx".
+static inline constexpr const char* REGEX_MODE = "(0[0-7]{3})?";
+TEST_P(CgroupsTest, CgroupMode) {
+    for (int i = 0; i < cgroups_->cgroups_size(); ++i) {
+        EXPECT_THAT(cgroups_->cgroups(i).mode(), MatchesRegex(REGEX_MODE))
+                << "For cgroup controller #" << i << " in " << file_path_;
+    }
+}
+
+TEST_P(CgroupsTest, Cgroup2Mode) {
+    EXPECT_THAT(cgroups_->cgroups2().mode(), MatchesRegex(REGEX_MODE))
+            << "For cgroups2 in " << file_path_;
+}
+
+}  // namespace profiles
+}  // namespace android
diff --git a/libprocessgroup/profiles/task_profiles_test.h b/libprocessgroup/profiles/task_profiles_test.h
new file mode 100644
index 0000000..32f122d
--- /dev/null
+++ b/libprocessgroup/profiles/task_profiles_test.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <gmock/gmock.h>
+#include <jsonpb/json_schema_test.h>
+
+#include "task_profiles.pb.h"
+
+namespace android {
+namespace profiles {
+
+class TaskProfilesTest : public jsonpb::JsonSchemaTest {
+  public:
+    void SetUp() override {
+        JsonSchemaTest::SetUp();
+        task_profiles_ = static_cast<TaskProfiles*>(message());
+    }
+    TaskProfiles* task_profiles_;
+};
+
+TEST_P(TaskProfilesTest, AttributeRequiredFields) {
+    for (int i = 0; i < task_profiles_->attributes_size(); ++i) {
+        auto&& attribute = task_profiles_->attributes(i);
+        EXPECT_FALSE(attribute.name().empty())
+                << "No name for attribute #" << i << " in " << file_path_;
+        EXPECT_FALSE(attribute.controller().empty())
+                << "No controller for attribute #" << i << " in " << file_path_;
+        EXPECT_FALSE(attribute.file().empty())
+                << "No file for attribute #" << i << " in " << file_path_;
+    }
+}
+
+TEST_P(TaskProfilesTest, ProfileRequiredFields) {
+    for (int profile_idx = 0; profile_idx < task_profiles_->profiles_size(); ++profile_idx) {
+        auto&& profile = task_profiles_->profiles(profile_idx);
+        EXPECT_FALSE(profile.name().empty())
+                << "No name for profile #" << profile_idx << " in " << file_path_;
+        for (int action_idx = 0; action_idx < profile.actions_size(); ++action_idx) {
+            auto&& action = profile.actions(action_idx);
+            EXPECT_FALSE(action.name().empty())
+                    << "No name for profiles[" << profile_idx << "].actions[" << action_idx
+                    << "] in " << file_path_;
+        }
+    }
+}
+
+}  // namespace profiles
+}  // namespace android
diff --git a/libprocessgroup/profiles/test.cpp b/libprocessgroup/profiles/test.cpp
index 8ba14d6..bc9aade 100644
--- a/libprocessgroup/profiles/test.cpp
+++ b/libprocessgroup/profiles/test.cpp
@@ -14,18 +14,15 @@
  * limitations under the License.
  */
 
-#include <string>
-
 #include <android-base/file.h>
-#include <gmock/gmock.h>
+#include <gtest/gtest.h>
 #include <jsonpb/json_schema_test.h>
 
-#include "cgroups.pb.h"
-#include "task_profiles.pb.h"
+#include "cgroups_test.h"
+#include "task_profiles_test.h"
 
 using namespace ::android::jsonpb;
 using ::android::base::GetExecutableDirectory;
-using ::testing::MatchesRegex;
 
 namespace android {
 namespace profiles {
@@ -35,87 +32,7 @@
     return jsonpb::MakeTestParam<T>(GetExecutableDirectory() + path);
 }
 
-TEST(LibProcessgroupProto, EmptyMode) {
-    EXPECT_EQ(0, strtoul("", nullptr, 8))
-            << "Empty mode string cannot be silently converted to 0; this should not happen";
-}
-
-class CgroupsTest : public JsonSchemaTest {
-  public:
-    void SetUp() override {
-        JsonSchemaTest::SetUp();
-        cgroups_ = static_cast<Cgroups*>(message());
-    }
-    Cgroups* cgroups_;
-};
-
-TEST_P(CgroupsTest, CgroupRequiredFields) {
-    for (int i = 0; i < cgroups_->cgroups_size(); ++i) {
-        auto&& cgroup = cgroups_->cgroups(i);
-        EXPECT_FALSE(cgroup.controller().empty())
-                << "No controller name for cgroup #" << i << " in " << file_path_;
-        EXPECT_FALSE(cgroup.path().empty()) << "No path for cgroup #" << i << " in " << file_path_;
-    }
-}
-
-TEST_P(CgroupsTest, Cgroup2RequiredFields) {
-    if (cgroups_->has_cgroups2()) {
-        EXPECT_FALSE(cgroups_->cgroups2().path().empty())
-                << "No path for cgroup2 in " << file_path_;
-    }
-}
-
-// "Mode" field must be in the format of "0xxx".
-static constexpr const char* REGEX_MODE = "(0[0-7]{3})?";
-TEST_P(CgroupsTest, CgroupMode) {
-    for (int i = 0; i < cgroups_->cgroups_size(); ++i) {
-        EXPECT_THAT(cgroups_->cgroups(i).mode(), MatchesRegex(REGEX_MODE))
-                << "For cgroup controller #" << i << " in " << file_path_;
-    }
-}
-
-TEST_P(CgroupsTest, Cgroup2Mode) {
-    EXPECT_THAT(cgroups_->cgroups2().mode(), MatchesRegex(REGEX_MODE))
-            << "For cgroups2 in " << file_path_;
-}
-
-class TaskProfilesTest : public JsonSchemaTest {
-  public:
-    void SetUp() override {
-        JsonSchemaTest::SetUp();
-        task_profiles_ = static_cast<TaskProfiles*>(message());
-    }
-    TaskProfiles* task_profiles_;
-};
-
-TEST_P(TaskProfilesTest, AttributeRequiredFields) {
-    for (int i = 0; i < task_profiles_->attributes_size(); ++i) {
-        auto&& attribute = task_profiles_->attributes(i);
-        EXPECT_FALSE(attribute.name().empty())
-                << "No name for attribute #" << i << " in " << file_path_;
-        EXPECT_FALSE(attribute.controller().empty())
-                << "No controller for attribute #" << i << " in " << file_path_;
-        EXPECT_FALSE(attribute.file().empty())
-                << "No file for attribute #" << i << " in " << file_path_;
-    }
-}
-
-TEST_P(TaskProfilesTest, ProfileRequiredFields) {
-    for (int profile_idx = 0; profile_idx < task_profiles_->profiles_size(); ++profile_idx) {
-        auto&& profile = task_profiles_->profiles(profile_idx);
-        EXPECT_FALSE(profile.name().empty())
-                << "No name for profile #" << profile_idx << " in " << file_path_;
-        for (int action_idx = 0; action_idx < profile.actions_size(); ++action_idx) {
-            auto&& action = profile.actions(action_idx);
-            EXPECT_FALSE(action.name().empty())
-                    << "No name for profiles[" << profile_idx << "].actions[" << action_idx
-                    << "] in " << file_path_;
-        }
-    }
-}
-
 // Test suite instantiations
-
 INSTANTIATE_TEST_SUITE_P(, JsonSchemaTest,
                          ::testing::Values(MakeTestParam<Cgroups>("/cgroups.json"),
                                            MakeTestParam<Cgroups>("/cgroups.recovery.json"),
diff --git a/libprocessgroup/profiles/test_vendor.cpp b/libprocessgroup/profiles/test_vendor.cpp
new file mode 100644
index 0000000..3ec7fcf
--- /dev/null
+++ b/libprocessgroup/profiles/test_vendor.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/file.h>
+#include <gtest/gtest.h>
+#include <jsonpb/json_schema_test.h>
+
+#include "cgroups_test.h"
+#include "task_profiles_test.h"
+
+using ::android::base::GetExecutableDirectory;
+using namespace ::android::jsonpb;
+
+namespace android {
+namespace profiles {
+
+static constexpr const char* kVendorCgroups = "/vendor/etc/cgroups.json";
+static constexpr const char* kVendorTaskProfiles = "/vendor/etc/task_profiles.json";
+
+template <typename T>
+class TestConfig : public JsonSchemaTestConfig {
+  public:
+    TestConfig(const std::string& path) : file_path_(path){};
+    std::unique_ptr<google::protobuf::Message> CreateMessage() const override {
+        return std::make_unique<T>();
+    }
+    std::string file_path() const override { return file_path_; }
+    bool optional() const override {
+        // Ignore when vendor JSON files are missing.
+        return true;
+    }
+
+  private:
+    std::string file_path_;
+};
+
+template <typename T>
+JsonSchemaTestConfigFactory MakeTestParam(const std::string& path) {
+    return [path]() { return std::make_unique<TestConfig<T>>(path); };
+}
+
+INSTANTIATE_TEST_SUITE_P(VendorCgroups, JsonSchemaTest,
+                         ::testing::Values(MakeTestParam<Cgroups>(kVendorCgroups)));
+INSTANTIATE_TEST_SUITE_P(VendorCgroups, CgroupsTest,
+                         ::testing::Values(MakeTestParam<Cgroups>(kVendorCgroups)));
+
+INSTANTIATE_TEST_SUITE_P(VendorTaskProfiles, JsonSchemaTest,
+                         ::testing::Values(MakeTestParam<TaskProfiles>(kVendorTaskProfiles)));
+INSTANTIATE_TEST_SUITE_P(VendorTaskProfiles, TaskProfilesTest,
+                         ::testing::Values(MakeTestParam<TaskProfiles>(kVendorTaskProfiles)));
+
+}  // namespace profiles
+}  // namespace android
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/libprocessgroup/profiles/vts_processgroup_validate_test.xml b/libprocessgroup/profiles/vts_processgroup_validate_test.xml
new file mode 100644
index 0000000..21d29cd
--- /dev/null
+++ b/libprocessgroup/profiles/vts_processgroup_validate_test.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+          http://www.apache.org/licenses/LICENSE-2.0
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for VtsProcessgroupValidateTest">
+    <option name="config-descriptor:metadata" key="plan" value="vts-treble" />
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+        <option name="abort-on-push-failure" value="false"/>
+        <option name="push-group" value="HostDrivenTest.push"/>
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+        <option name="test-module-name" value="VtsProcessgroupValidateTest"/>
+        <option name="binary-test-working-directory" value="_32bit::/data/nativetest/" />
+        <option name="binary-test-working-directory" value="_64bit::/data/nativetest64/" />
+        <option name="binary-test-source" value="_32bit::DATA/nativetest/vts_processgroup_validate_test/vts_processgroup_validate_test" />
+        <option name="binary-test-source" value="_64bit::DATA/nativetest64/vts_processgroup_validate_test/vts_processgroup_validate_test" />
+        <option name="binary-test-type" value="gtest"/>
+        <option name="binary-test-disable-framework" value="false"/>
+        <option name="test-timeout" value="30s"/>
+    </test>
+</configuration>
diff --git a/libprocessgroup/sched_policy.cpp b/libprocessgroup/sched_policy.cpp
index 026c011..1eefada 100644
--- a/libprocessgroup/sched_policy.cpp
+++ b/libprocessgroup/sched_policy.cpp
@@ -167,7 +167,7 @@
     if (!controller) return -1;
 
     if (!controller->GetTaskGroup(tid, &subgroup)) {
-        PLOG(ERROR) << "Failed to find cgroup for tid " << tid;
+        LOG(ERROR) << "Failed to find cgroup for tid " << tid;
         return -1;
     }
     return 0;
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index fded417..9362c03 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -119,7 +119,7 @@
     std::string path;
 
     if (!attribute_->GetPathForTask(tid, &path)) {
-        PLOG(ERROR) << "Failed to find cgroup for tid " << tid;
+        LOG(ERROR) << "Failed to find cgroup for tid " << tid;
         return false;
     }
 
@@ -174,7 +174,7 @@
     if (TEMP_FAILURE_RETRY(write(fd, value.c_str(), value.length())) < 0) {
         // If the thread is in the process of exiting, don't flag an error
         if (errno != ESRCH) {
-            PLOG(ERROR) << "JoinGroup failed to write '" << value << "'; fd=" << fd;
+            PLOG(ERROR) << "AddTidToCgroup failed to write '" << value << "'; fd=" << fd;
             return false;
         }
     }
@@ -187,7 +187,7 @@
     if (fd_ >= 0) {
         // fd is cached, reuse it
         if (!AddTidToCgroup(pid, fd_)) {
-            PLOG(ERROR) << "Failed to add task into cgroup";
+            LOG(ERROR) << "Failed to add task into cgroup";
             return false;
         }
         return true;
@@ -202,11 +202,11 @@
     std::string procs_path = controller_->GetProcsFilePath(path_, uid, pid);
     unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(procs_path.c_str(), O_WRONLY | O_CLOEXEC)));
     if (tmp_fd < 0) {
-        PLOG(WARNING) << "Failed to open " << procs_path << ": " << strerror(errno);
+        PLOG(WARNING) << "Failed to open " << procs_path;
         return false;
     }
     if (!AddTidToCgroup(pid, tmp_fd)) {
-        PLOG(ERROR) << "Failed to add task into cgroup";
+        LOG(ERROR) << "Failed to add task into cgroup";
         return false;
     }
 
@@ -219,7 +219,7 @@
         return true;
     }
     if (!AddTidToCgroup(pid, tmp_fd)) {
-        PLOG(ERROR) << "Failed to add task into cgroup";
+        LOG(ERROR) << "Failed to add task into cgroup";
         return false;
     }
 
@@ -232,7 +232,7 @@
     if (fd_ >= 0) {
         // fd is cached, reuse it
         if (!AddTidToCgroup(tid, fd_)) {
-            PLOG(ERROR) << "Failed to add task into cgroup";
+            LOG(ERROR) << "Failed to add task into cgroup";
             return false;
         }
         return true;
@@ -244,7 +244,7 @@
     }
 
     // application-dependent path can't be used with tid
-    PLOG(ERROR) << "Application profile can't be applied to a thread";
+    LOG(ERROR) << "Application profile can't be applied to a thread";
     return false;
 #else
     std::string tasks_path = controller_->GetTasksFilePath(path_);
@@ -254,7 +254,7 @@
         return true;
     }
     if (!AddTidToCgroup(tid, tmp_fd)) {
-        PLOG(ERROR) << "Failed to add task into cgroup";
+        LOG(ERROR) << "Failed to add task into cgroup";
         return false;
     }
 
@@ -284,8 +284,10 @@
 }
 
 TaskProfiles& TaskProfiles::GetInstance() {
-    static TaskProfiles instance;
-    return instance;
+    // Deliberately leak this object to avoid a race between destruction on
+    // process exit and concurrent access from another thread.
+    static auto* instance = new TaskProfiles;
+    return *instance;
 }
 
 TaskProfiles::TaskProfiles() {
diff --git a/libprocinfo/Android.bp b/libprocinfo/Android.bp
index 27cda93..15f03d0 100644
--- a/libprocinfo/Android.bp
+++ b/libprocinfo/Android.bp
@@ -31,7 +31,6 @@
     vndk: {
         enabled: true,
     },
-    double_loadable: true,
     host_supported: true,
     srcs: [
         "process.cpp",
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index b07853a..523584a 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -26,7 +26,7 @@
 #include <sysutils/FrameworkListener.h>
 #include <sysutils/SocketClient.h>
 
-static const int CMD_BUF_SIZE = 1024;
+static const int CMD_BUF_SIZE = 4096;
 
 FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) :
                             SocketListener(socketName, true, withSeq) {
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index a49fd9e..b7650a1 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -248,6 +248,7 @@
         "tests/files/offline/offset_arm/*",
         "tests/files/offline/shared_lib_in_apk_arm64/*",
         "tests/files/offline/shared_lib_in_apk_memory_only_arm64/*",
+        "tests/files/offline/shared_lib_in_apk_single_map_arm64/*",
         "tests/files/offline/straddle_arm/*",
         "tests/files/offline/straddle_arm64/*",
     ],
diff --git a/libunwindstack/DwarfEhFrameWithHdr.cpp b/libunwindstack/DwarfEhFrameWithHdr.cpp
index 668527a..802beca 100644
--- a/libunwindstack/DwarfEhFrameWithHdr.cpp
+++ b/libunwindstack/DwarfEhFrameWithHdr.cpp
@@ -61,6 +61,14 @@
   table_encoding_ = data[3];
   table_entry_size_ = memory_.template GetEncodedSize<AddressType>(table_encoding_);
 
+  // If we can't perform a binary search on the entries, it's not worth
+  // using this object. The calling code will fall back to the DwarfEhFrame
+  // object in this case.
+  if (table_entry_size_ == 0) {
+    last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
+    return false;
+  }
+
   memory_.set_pc_offset(memory_.cur_offset());
   if (!memory_.template ReadEncodedValue<AddressType>(ptr_encoding_, &ptr_offset_)) {
     last_error_.code = DWARF_ERROR_MEMORY_INVALID;
@@ -137,13 +145,13 @@
 }
 
 template <typename AddressType>
-bool DwarfEhFrameWithHdr<AddressType>::GetFdeOffsetBinary(uint64_t pc, uint64_t* fde_offset,
-                                                          uint64_t total_entries) {
-  CHECK(fde_count_ > 0);
-  CHECK(total_entries <= fde_count_);
+bool DwarfEhFrameWithHdr<AddressType>::GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) {
+  if (fde_count_ == 0) {
+    return false;
+  }
 
   size_t first = 0;
-  size_t last = total_entries;
+  size_t last = fde_count_;
   while (first < last) {
     size_t current = (first + last) / 2;
     const FdeInfo* info = GetFdeInfoFromIndex(current);
@@ -172,87 +180,6 @@
 }
 
 template <typename AddressType>
-bool DwarfEhFrameWithHdr<AddressType>::GetFdeOffsetSequential(uint64_t pc, uint64_t* fde_offset) {
-  CHECK(fde_count_ != 0);
-  last_error_.code = DWARF_ERROR_NONE;
-  last_error_.address = 0;
-
-  // We can do a binary search if the pc is in the range of the elements
-  // that have already been cached.
-  if (!fde_info_.empty()) {
-    const FdeInfo* info = &fde_info_[fde_info_.size() - 1];
-    if (pc >= info->pc) {
-      *fde_offset = info->offset;
-      return true;
-    }
-    if (pc < info->pc) {
-      return GetFdeOffsetBinary(pc, fde_offset, fde_info_.size());
-    }
-  }
-
-  if (cur_entries_offset_ == 0) {
-    // All entries read, or error encountered.
-    return false;
-  }
-
-  memory_.set_data_offset(entries_data_offset_);
-  memory_.set_cur_offset(cur_entries_offset_);
-  memory_.set_pc_offset(0);
-  cur_entries_offset_ = 0;
-
-  FdeInfo* prev_info = nullptr;
-  for (size_t current = fde_info_.size();
-       current < fde_count_ && memory_.cur_offset() < entries_end_; current++) {
-    FdeInfo* info = &fde_info_[current];
-    uint64_t value;
-    if (!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &value) ||
-        !memory_.template ReadEncodedValue<AddressType>(table_encoding_, &info->offset)) {
-      fde_info_.erase(current);
-      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-      last_error_.address = memory_.cur_offset();
-      return false;
-    }
-
-    // Relative encodings require adding in the load bias.
-    if (IsEncodingRelative(table_encoding_)) {
-      value += load_bias_;
-    }
-    info->pc = value;
-
-    if (pc < info->pc) {
-      if (prev_info == nullptr) {
-        return false;
-      }
-      cur_entries_offset_ = memory_.cur_offset();
-      *fde_offset = prev_info->offset;
-      return true;
-    }
-    prev_info = info;
-  }
-
-  if (fde_count_ == fde_info_.size() && pc >= prev_info->pc) {
-    *fde_offset = prev_info->offset;
-    return true;
-  }
-  return false;
-}
-
-template <typename AddressType>
-bool DwarfEhFrameWithHdr<AddressType>::GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) {
-  if (fde_count_ == 0) {
-    return false;
-  }
-
-  if (table_entry_size_ > 0) {
-    // Do a binary search since the size of each table entry is fixed.
-    return GetFdeOffsetBinary(pc, fde_offset, fde_count_);
-  } else {
-    // Do a sequential search since each table entry size is variable.
-    return GetFdeOffsetSequential(pc, fde_offset);
-  }
-}
-
-template <typename AddressType>
 void DwarfEhFrameWithHdr<AddressType>::GetFdes(std::vector<const DwarfFde*>* fdes) {
   for (size_t i = 0; i < fde_count_; i++) {
     const FdeInfo* info = GetFdeInfoFromIndex(i);
diff --git a/libunwindstack/DwarfEhFrameWithHdr.h b/libunwindstack/DwarfEhFrameWithHdr.h
index e3e9ca8..0e5eef7 100644
--- a/libunwindstack/DwarfEhFrameWithHdr.h
+++ b/libunwindstack/DwarfEhFrameWithHdr.h
@@ -69,10 +69,6 @@
 
   const FdeInfo* GetFdeInfoFromIndex(size_t index);
 
-  bool GetFdeOffsetSequential(uint64_t pc, uint64_t* fde_offset);
-
-  bool GetFdeOffsetBinary(uint64_t pc, uint64_t* fde_offset, uint64_t total_entries);
-
   void GetFdes(std::vector<const DwarfFde*>* fdes) override;
 
  protected:
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 2f5eed9..4b93abb 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -93,9 +93,12 @@
   valid_ = false;
 }
 
-bool Elf::GetSoname(std::string* name) {
+std::string Elf::GetSoname() {
   std::lock_guard<std::mutex> guard(lock_);
-  return valid_ && interface_->GetSoname(name);
+  if (!valid_) {
+    return "";
+  }
+  return interface_->GetSoname();
 }
 
 uint64_t Elf::GetRelPc(uint64_t pc, const MapInfo* map_info) {
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index c1b98d9..12efb94 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -374,13 +374,12 @@
 }
 
 template <typename DynType>
-bool ElfInterface::GetSonameWithTemplate(std::string* soname) {
+std::string ElfInterface::GetSonameWithTemplate() {
   if (soname_type_ == SONAME_INVALID) {
-    return false;
+    return "";
   }
   if (soname_type_ == SONAME_VALID) {
-    *soname = soname_;
-    return true;
+    return soname_;
   }
 
   soname_type_ = SONAME_INVALID;
@@ -397,7 +396,7 @@
     if (!memory_->ReadFully(offset, &dyn, sizeof(dyn))) {
       last_error_.code = ERROR_MEMORY_INVALID;
       last_error_.address = offset;
-      return false;
+      return "";
     }
 
     if (dyn.d_tag == DT_STRTAB) {
@@ -416,17 +415,16 @@
     if (entry.first == strtab_addr) {
       soname_offset = entry.second + soname_offset;
       if (soname_offset >= entry.second + strtab_size) {
-        return false;
+        return "";
       }
       if (!memory_->ReadString(soname_offset, &soname_)) {
-        return false;
+        return "";
       }
       soname_type_ = SONAME_VALID;
-      *soname = soname_;
-      return true;
+      return soname_;
     }
   }
-  return false;
+  return "";
 }
 
 template <typename SymType>
@@ -653,8 +651,8 @@
 template std::string ElfInterface::ReadBuildID<Elf32_Nhdr>();
 template std::string ElfInterface::ReadBuildID<Elf64_Nhdr>();
 
-template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*);
-template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*);
+template std::string ElfInterface::GetSonameWithTemplate<Elf32_Dyn>();
+template std::string ElfInterface::GetSonameWithTemplate<Elf64_Dyn>();
 
 template bool ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(uint64_t, std::string*,
                                                                    uint64_t*);
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 89a6a79..28373b2 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -88,6 +88,7 @@
   // Check if the start of this map is an embedded elf.
   uint64_t max_size = 0;
   if (Elf::GetInfo(memory.get(), &max_size)) {
+    elf_start_offset = offset;
     if (max_size > map_size) {
       if (memory->Init(name, offset, max_size)) {
         return memory.release();
@@ -96,6 +97,7 @@
       if (memory->Init(name, offset, map_size)) {
         return memory.release();
       }
+      elf_start_offset = 0;
       return nullptr;
     }
     return memory.release();
@@ -186,44 +188,57 @@
 }
 
 Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, ArchEnum expected_arch) {
-  // Make sure no other thread is trying to add the elf to this map.
-  std::lock_guard<std::mutex> guard(mutex_);
+  {
+    // Make sure no other thread is trying to add the elf to this map.
+    std::lock_guard<std::mutex> guard(mutex_);
 
-  if (elf.get() != nullptr) {
-    return elf.get();
-  }
-
-  bool locked = false;
-  if (Elf::CachingEnabled() && !name.empty()) {
-    Elf::CacheLock();
-    locked = true;
-    if (Elf::CacheGet(this)) {
-      Elf::CacheUnlock();
+    if (elf.get() != nullptr) {
       return elf.get();
     }
+
+    bool locked = false;
+    if (Elf::CachingEnabled() && !name.empty()) {
+      Elf::CacheLock();
+      locked = true;
+      if (Elf::CacheGet(this)) {
+        Elf::CacheUnlock();
+        return elf.get();
+      }
+    }
+
+    Memory* memory = CreateMemory(process_memory);
+    if (locked) {
+      if (Elf::CacheAfterCreateMemory(this)) {
+        delete memory;
+        Elf::CacheUnlock();
+        return elf.get();
+      }
+    }
+    elf.reset(new Elf(memory));
+    // If the init fails, keep the elf around as an invalid object so we
+    // don't try to reinit the object.
+    elf->Init();
+    if (elf->valid() && expected_arch != elf->arch()) {
+      // Make the elf invalid, mismatch between arch and expected arch.
+      elf->Invalidate();
+    }
+
+    if (locked) {
+      Elf::CacheAdd(this);
+      Elf::CacheUnlock();
+    }
   }
 
-  Memory* memory = CreateMemory(process_memory);
-  if (locked) {
-    if (Elf::CacheAfterCreateMemory(this)) {
-      delete memory;
-      Elf::CacheUnlock();
-      return elf.get();
+  // If there is a read-only map then a read-execute map that represents the
+  // same elf object, make sure the previous map is using the same elf
+  // object if it hasn't already been set.
+  if (prev_map != nullptr && elf_start_offset != offset && prev_map->offset == elf_start_offset &&
+      prev_map->name == name) {
+    std::lock_guard<std::mutex> guard(prev_map->mutex_);
+    if (prev_map->elf.get() == nullptr) {
+      prev_map->elf = elf;
     }
   }
-  elf.reset(new Elf(memory));
-  // If the init fails, keep the elf around as an invalid object so we
-  // don't try to reinit the object.
-  elf->Init();
-  if (elf->valid() && expected_arch != elf->arch()) {
-    // Make the elf invalid, mismatch between arch and expected arch.
-    elf->Invalidate();
-  }
-
-  if (locked) {
-    Elf::CacheAdd(this);
-    Elf::CacheUnlock();
-  }
   return elf.get();
 }
 
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 2734cf8..3f2e1c1 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -105,6 +105,12 @@
 
   if (resolve_names_) {
     frame->map_name = map_info->name;
+    if (embedded_soname_ && map_info->elf_start_offset != 0 && !frame->map_name.empty()) {
+      std::string soname = elf->GetSoname();
+      if (!soname.empty()) {
+        frame->map_name += '!' + soname;
+      }
+    }
   }
   frame->map_elf_start_offset = map_info->elf_start_offset;
   frame->map_exact_offset = map_info->offset;
@@ -278,17 +284,9 @@
   }
 }
 
-std::string Unwinder::FormatFrame(size_t frame_num) {
-  if (frame_num >= frames_.size()) {
-    return "";
-  }
-  return FormatFrame(frames_[frame_num], regs_->Is32Bit());
-}
-
-std::string Unwinder::FormatFrame(const FrameData& frame, bool is32bit) {
+std::string Unwinder::FormatFrame(const FrameData& frame) {
   std::string data;
-
-  if (is32bit) {
+  if (regs_->Is32Bit()) {
     data += android::base::StringPrintf("  #%02zu pc %08" PRIx64, frame.num, frame.rel_pc);
   } else {
     data += android::base::StringPrintf("  #%02zu pc %016" PRIx64, frame.num, frame.rel_pc);
@@ -314,9 +312,24 @@
     }
     data += ')';
   }
+
+  MapInfo* map_info = maps_->Find(frame.map_start);
+  if (map_info != nullptr && display_build_id_) {
+    std::string build_id = map_info->GetPrintableBuildID();
+    if (!build_id.empty()) {
+      data += " (BuildId: " + build_id + ')';
+    }
+  }
   return data;
 }
 
+std::string Unwinder::FormatFrame(size_t frame_num) {
+  if (frame_num >= frames_.size()) {
+    return "";
+  }
+  return FormatFrame(frames_[frame_num]);
+}
+
 void Unwinder::SetJitDebug(JitDebug* jit_debug, ArchEnum arch) {
   jit_debug->SetArch(arch);
   jit_debug_ = jit_debug;
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index 00a249f..ac94f10 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -59,7 +59,7 @@
 
   void Invalidate();
 
-  bool GetSoname(std::string* name);
+  std::string GetSoname();
 
   bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset);
 
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
index d41bb13..dbd917d 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -56,7 +56,7 @@
 
   virtual void InitHeaders(uint64_t load_bias) = 0;
 
-  virtual bool GetSoname(std::string* name) = 0;
+  virtual std::string GetSoname() = 0;
 
   virtual bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* offset) = 0;
 
@@ -117,7 +117,7 @@
   void ReadSectionHeaders(const EhdrType& ehdr);
 
   template <typename DynType>
-  bool GetSonameWithTemplate(std::string* soname);
+  std::string GetSonameWithTemplate();
 
   template <typename SymType>
   bool GetFunctionNameWithTemplate(uint64_t addr, std::string* name, uint64_t* func_offset);
@@ -183,9 +183,7 @@
     ElfInterface::InitHeadersWithTemplate<uint32_t>(load_bias);
   }
 
-  bool GetSoname(std::string* soname) override {
-    return ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(soname);
-  }
+  std::string GetSoname() override { return ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(); }
 
   bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override {
     return ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(addr, name, func_offset);
@@ -215,9 +213,7 @@
     ElfInterface::InitHeadersWithTemplate<uint64_t>(load_bias);
   }
 
-  bool GetSoname(std::string* soname) override {
-    return ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(soname);
-  }
+  std::string GetSoname() override { return ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(); }
 
   bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override {
     return ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(addr, name, func_offset);
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
index dba41d1..b3beb6e 100644
--- a/libunwindstack/include/unwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -101,7 +101,7 @@
 
   size_t Size() { return size_; }
 
-  void Clear();
+  void Clear() override;
 
  protected:
   size_t size_ = 0;
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
index 878ced3..1c2a81c 100644
--- a/libunwindstack/include/unwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -18,6 +18,7 @@
 #define _LIBUNWINDSTACK_REGS_H
 
 #include <stdint.h>
+#include <unistd.h>
 
 #include <functional>
 #include <string>
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index ddda7fd..8b01654 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -88,7 +88,7 @@
   }
 
   std::string FormatFrame(size_t frame_num);
-  static std::string FormatFrame(const FrameData& frame, bool is32bit);
+  std::string FormatFrame(const FrameData& frame);
 
   void SetJitDebug(JitDebug* jit_debug, ArchEnum arch);
 
@@ -100,6 +100,13 @@
   // set to an empty string and the function offset being set to zero.
   void SetResolveNames(bool resolve) { resolve_names_ = resolve; }
 
+  // Enable/disable soname printing the soname for a map name if the elf is
+  // embedded in a file. This is enabled by default.
+  // NOTE: This does nothing unless resolving names is enabled.
+  void SetEmbeddedSoname(bool embedded_soname) { embedded_soname_ = embedded_soname; }
+
+  void SetDisplayBuildID(bool display_build_id) { display_build_id_ = display_build_id; }
+
 #if !defined(NO_LIBDEXFILE_SUPPORT)
   void SetDexFiles(DexFiles* dex_files, ArchEnum arch);
 #endif
@@ -124,6 +131,8 @@
   DexFiles* dex_files_ = nullptr;
 #endif
   bool resolve_names_ = true;
+  bool embedded_soname_ = true;
+  bool display_build_id_ = false;
   ErrorData last_error_;
 };
 
diff --git a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
index 910ae36..be9e721 100644
--- a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
@@ -95,6 +95,13 @@
   EXPECT_EQ(0x1000U, this->eh_frame_->TestGetEntriesDataOffset());
   EXPECT_EQ(0x100aU, this->eh_frame_->TestGetCurEntriesOffset());
 
+  // Verify a zero table entry size fails to init.
+  this->memory_.SetData8(0x1003, 0x1);
+  ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100, 0));
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->LastErrorCode());
+  // Reset the value back to the original.
+  this->memory_.SetData8(0x1003, DW_EH_PE_sdata4);
+
   // Verify a zero fde count fails to init.
   this->memory_.SetData32(0x1006, 0);
   ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100, 0));
@@ -276,9 +283,8 @@
   EXPECT_EQ(0x500U, info->offset);
 }
 
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetBinary_verify) {
+TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_verify) {
   this->eh_frame_->TestSetTableEntrySize(0x10);
-  this->eh_frame_->TestSetFdeCount(10);
 
   typename DwarfEhFrameWithHdr<TypeParam>::FdeInfo info;
   for (size_t i = 0; i < 10; i++) {
@@ -288,105 +294,42 @@
   }
 
   uint64_t fde_offset;
-  EXPECT_FALSE(this->eh_frame_->GetFdeOffsetBinary(0x100, &fde_offset, 10));
+  this->eh_frame_->TestSetFdeCount(10);
+  EXPECT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x100, &fde_offset));
   // Not an error, just not found.
   ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
   // Even number of elements.
   for (size_t i = 0; i < 10; i++) {
+    SCOPED_TRACE(testing::Message() << "Failed at index " << i);
     TypeParam pc = 0x1000 * (i + 1);
-    EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc, &fde_offset, 10)) << "Failed at index " << i;
-    EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
-    EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc + 1, &fde_offset, 10))
-        << "Failed at index " << i;
-    EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
-    EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc + 0xfff, &fde_offset, 10))
-        << "Failed at index " << i;
-    EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
+    EXPECT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc, &fde_offset));
+    EXPECT_EQ(0x5000 + i * 0x20, fde_offset);
+    EXPECT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 1, &fde_offset));
+    EXPECT_EQ(0x5000 + i * 0x20, fde_offset);
+    EXPECT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset));
+    EXPECT_EQ(0x5000 + i * 0x20, fde_offset);
   }
+
   // Odd number of elements.
+  this->eh_frame_->TestSetFdeCount(9);
   for (size_t i = 0; i < 9; i++) {
+    SCOPED_TRACE(testing::Message() << "Failed at index " << i);
     TypeParam pc = 0x1000 * (i + 1);
-    EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc, &fde_offset, 9)) << "Failed at index " << i;
-    EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
-    EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc + 1, &fde_offset, 9))
-        << "Failed at index " << i;
-    EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
-    EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc + 0xfff, &fde_offset, 9))
-        << "Failed at index " << i;
-    EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
+    EXPECT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc, &fde_offset));
+    EXPECT_EQ(0x5000 + i * 0x20, fde_offset);
+    EXPECT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 1, &fde_offset));
+    EXPECT_EQ(0x5000 + i * 0x20, fde_offset);
+    EXPECT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset));
+    EXPECT_EQ(0x5000 + i * 0x20, fde_offset);
   }
 }
 
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetBinary_index_fail) {
+TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_index_fail) {
   this->eh_frame_->TestSetTableEntrySize(0x10);
   this->eh_frame_->TestSetFdeCount(10);
 
   uint64_t fde_offset;
-  EXPECT_FALSE(this->eh_frame_->GetFdeOffsetBinary(0x1000, &fde_offset, 10));
-}
-
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetSequential) {
-  this->eh_frame_->TestSetFdeCount(10);
-  this->eh_frame_->TestSetEntriesDataOffset(0x100);
-  this->eh_frame_->TestSetEntriesEnd(0x2000);
-  this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
-
-  this->memory_.SetData32(0x1040, 0x340);
-  this->memory_.SetData32(0x1044, 0x500);
-
-  this->memory_.SetData32(0x1048, 0x440);
-  this->memory_.SetData32(0x104c, 0x600);
-
-  // Verify that if entries is zero, that it fails.
-  uint64_t fde_offset;
-  ASSERT_FALSE(this->eh_frame_->GetFdeOffsetSequential(0x344, &fde_offset));
-  this->eh_frame_->TestSetCurEntriesOffset(0x1040);
-
-  ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x344, &fde_offset));
-  EXPECT_EQ(0x500U, fde_offset);
-
-  ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x444, &fde_offset));
-  EXPECT_EQ(0x600U, fde_offset);
-
-  // Expect that the data is cached so no more memory reads will occur.
-  this->memory_.Clear();
-  ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x444, &fde_offset));
-  EXPECT_EQ(0x600U, fde_offset);
-}
-
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetSequential_last_element) {
-  this->eh_frame_->TestSetFdeCount(2);
-  this->eh_frame_->TestSetEntriesDataOffset(0x100);
-  this->eh_frame_->TestSetEntriesEnd(0x2000);
-  this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
-  this->eh_frame_->TestSetCurEntriesOffset(0x1040);
-
-  this->memory_.SetData32(0x1040, 0x340);
-  this->memory_.SetData32(0x1044, 0x500);
-
-  this->memory_.SetData32(0x1048, 0x440);
-  this->memory_.SetData32(0x104c, 0x600);
-
-  uint64_t fde_offset;
-  ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x540, &fde_offset));
-  EXPECT_EQ(0x600U, fde_offset);
-}
-
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetSequential_end_check) {
-  this->eh_frame_->TestSetFdeCount(2);
-  this->eh_frame_->TestSetEntriesDataOffset(0x100);
-  this->eh_frame_->TestSetEntriesEnd(0x1048);
-  this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
-
-  this->memory_.SetData32(0x1040, 0x340);
-  this->memory_.SetData32(0x1044, 0x500);
-
-  this->memory_.SetData32(0x1048, 0x440);
-  this->memory_.SetData32(0x104c, 0x600);
-
-  uint64_t fde_offset;
-  ASSERT_FALSE(this->eh_frame_->GetFdeOffsetSequential(0x540, &fde_offset));
-  ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
+  EXPECT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x1000, &fde_offset));
 }
 
 TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_fail_fde_count) {
@@ -397,7 +340,7 @@
   ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
 }
 
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_binary_search) {
+TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_search) {
   this->eh_frame_->TestSetTableEntrySize(16);
   this->eh_frame_->TestSetFdeCount(10);
 
@@ -417,26 +360,6 @@
   EXPECT_EQ(0x10700U, fde_offset);
 }
 
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_sequential_search) {
-  this->eh_frame_->TestSetFdeCount(10);
-  this->eh_frame_->TestSetTableEntrySize(0);
-
-  typename DwarfEhFrameWithHdr<TypeParam>::FdeInfo info;
-  info.pc = 0x50;
-  info.offset = 0x10000;
-  this->eh_frame_->TestSetFdeInfo(0, info);
-  info.pc = 0x150;
-  info.offset = 0x10100;
-  this->eh_frame_->TestSetFdeInfo(1, info);
-  info.pc = 0x250;
-  info.offset = 0x10200;
-  this->eh_frame_->TestSetFdeInfo(2, info);
-
-  uint64_t fde_offset;
-  ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(0x200, &fde_offset));
-  EXPECT_EQ(0x10100U, fde_offset);
-}
-
 TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetCieFde32) {
   // CIE 32 information.
   this->memory_.SetData32(0xf000, 0x100);
@@ -526,10 +449,8 @@
 REGISTER_TYPED_TEST_CASE_P(DwarfEhFrameWithHdrTest, Init, Init_non_zero_load_bias, GetFdes,
                            GetFdeInfoFromIndex_expect_cache_fail, GetFdeInfoFromIndex_read_pcrel,
                            GetFdeInfoFromIndex_read_datarel, GetFdeInfoFromIndex_cached,
-                           GetFdeOffsetBinary_verify, GetFdeOffsetBinary_index_fail,
-                           GetFdeOffsetSequential, GetFdeOffsetSequential_last_element,
-                           GetFdeOffsetSequential_end_check, GetFdeOffsetFromPc_fail_fde_count,
-                           GetFdeOffsetFromPc_binary_search, GetFdeOffsetFromPc_sequential_search,
+                           GetFdeOffsetFromPc_verify, GetFdeOffsetFromPc_index_fail,
+                           GetFdeOffsetFromPc_fail_fde_count, GetFdeOffsetFromPc_search,
                            GetCieFde32, GetCieFde64, GetFdeFromPc_fde_not_found);
 
 typedef ::testing::Types<uint32_t, uint64_t> DwarfEhFrameWithHdrTestTypes;
diff --git a/libunwindstack/tests/ElfFake.h b/libunwindstack/tests/ElfFake.h
index 946bc3c..bd3083c 100644
--- a/libunwindstack/tests/ElfFake.h
+++ b/libunwindstack/tests/ElfFake.h
@@ -68,7 +68,7 @@
 
   bool Init(uint64_t*) override { return false; }
   void InitHeaders(uint64_t) override {}
-  bool GetSoname(std::string*) override { return false; }
+  std::string GetSoname() override { return fake_soname_; }
 
   bool GetFunctionName(uint64_t, std::string*, uint64_t*) override;
   bool GetGlobalVariable(const std::string&, uint64_t*) override;
@@ -83,6 +83,8 @@
   void FakeSetBuildID(std::string& build_id) { fake_build_id_ = build_id; }
   void FakeSetBuildID(const char* build_id) { fake_build_id_ = build_id; }
 
+  void FakeSetSoname(const char* soname) { fake_soname_ = soname; }
+
   static void FakePushFunctionData(const FunctionData data) { functions_.push_back(data); }
   static void FakePushStepData(const StepData data) { steps_.push_back(data); }
 
@@ -98,6 +100,7 @@
  private:
   std::unordered_map<std::string, uint64_t> globals_;
   std::string fake_build_id_;
+  std::string fake_soname_;
 
   static std::deque<FunctionData> functions_;
   static std::deque<StepData> steps_;
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index 7239749..d895863 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -555,9 +555,7 @@
   ASSERT_TRUE(elf->Init(&load_bias));
   EXPECT_EQ(0U, load_bias);
 
-  std::string name;
-  ASSERT_TRUE(elf->GetSoname(&name));
-  ASSERT_STREQ("fake_soname.so", name.c_str());
+  ASSERT_EQ("fake_soname.so", elf->GetSoname());
 }
 
 TEST_F(ElfInterfaceTest, elf32_soname) {
@@ -578,8 +576,7 @@
   ASSERT_TRUE(elf->Init(&load_bias));
   EXPECT_EQ(0U, load_bias);
 
-  std::string name;
-  ASSERT_FALSE(elf->GetSoname(&name));
+  ASSERT_EQ("", elf->GetSoname());
 }
 
 TEST_F(ElfInterfaceTest, elf32_soname_after_dt_null) {
@@ -600,8 +597,7 @@
   ASSERT_TRUE(elf->Init(&load_bias));
   EXPECT_EQ(0U, load_bias);
 
-  std::string name;
-  ASSERT_FALSE(elf->GetSoname(&name));
+  ASSERT_EQ("", elf->GetSoname());
 }
 
 TEST_F(ElfInterfaceTest, elf32_soname_size) {
@@ -624,8 +620,7 @@
   ASSERT_TRUE(elf->Init(&load_bias));
   EXPECT_EQ(0U, load_bias);
 
-  std::string name;
-  ASSERT_FALSE(elf->GetSoname(&name));
+  ASSERT_EQ("", elf->GetSoname());
 }
 
 TEST_F(ElfInterfaceTest, elf32_soname_missing_map) {
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 1ff2306..23c9cf8 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -126,9 +126,9 @@
   ASSERT_FALSE(elf.valid());
   ASSERT_TRUE(elf.interface() == nullptr);
 
-  std::string name;
-  ASSERT_FALSE(elf.GetSoname(&name));
+  ASSERT_EQ("", elf.GetSoname());
 
+  std::string name;
   uint64_t func_offset;
   ASSERT_FALSE(elf.GetFunctionName(0, &name, &func_offset));
 
@@ -309,7 +309,7 @@
 
   bool Init(uint64_t*) override { return false; }
   void InitHeaders(uint64_t) override {}
-  bool GetSoname(std::string*) override { return false; }
+  std::string GetSoname() override { return ""; }
   bool GetFunctionName(uint64_t, std::string*, uint64_t*) override { return false; }
   std::string GetBuildID() override { return ""; }
 
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index a66685a..2ddadef 100644
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -178,7 +178,7 @@
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
   ASSERT_EQ(0U, info.elf_offset);
-  EXPECT_EQ(0U, info.elf_start_offset);
+  EXPECT_EQ(0x1000U, info.elf_start_offset);
 
   // Read the valid part of the file.
   std::vector<uint8_t> buffer(0x100);
@@ -202,7 +202,7 @@
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
   ASSERT_EQ(0U, info.elf_offset);
-  EXPECT_EQ(0U, info.elf_start_offset);
+  EXPECT_EQ(0x1000U, info.elf_start_offset);
 
   // Verify the memory is a valid elf.
   uint8_t e_ident[SELFMAG + 1];
@@ -219,7 +219,7 @@
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
   ASSERT_EQ(0U, info.elf_offset);
-  EXPECT_EQ(0U, info.elf_start_offset);
+  EXPECT_EQ(0x2000U, info.elf_start_offset);
 
   // Verify the memory is a valid elf.
   uint8_t e_ident[SELFMAG + 1];
diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp
index d7b8485..d60b8b1 100644
--- a/libunwindstack/tests/MapInfoGetElfTest.cpp
+++ b/libunwindstack/tests/MapInfoGetElfTest.cpp
@@ -371,4 +371,35 @@
   }
 }
 
+// Verify that previous maps don't automatically get the same elf object.
+TEST_F(MapInfoGetElfTest, prev_map_elf_not_set) {
+  MapInfo info1(nullptr, 0x1000, 0x2000, 0, PROT_READ, "/not/present");
+  MapInfo info2(&info1, 0x2000, 0x3000, 0, PROT_READ, elf_.path);
+
+  Elf32_Ehdr ehdr;
+  TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
+  memory_->SetMemory(0x2000, &ehdr, sizeof(ehdr));
+  Elf* elf = info2.GetElf(process_memory_, ARCH_ARM);
+  ASSERT_TRUE(elf != nullptr);
+  ASSERT_TRUE(elf->valid());
+
+  ASSERT_NE(elf, info1.GetElf(process_memory_, ARCH_ARM));
+}
+
+// Verify that a read-only map followed by a read-execute map will result
+// in the same elf object in both maps.
+TEST_F(MapInfoGetElfTest, read_only_followed_by_read_exec_share_elf) {
+  MapInfo r_info(nullptr, 0x1000, 0x2000, 0, PROT_READ, elf_.path);
+  MapInfo rw_info(&r_info, 0x2000, 0x3000, 0x1000, PROT_READ | PROT_EXEC, elf_.path);
+
+  Elf32_Ehdr ehdr;
+  TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
+  memory_->SetMemory(0x1000, &ehdr, sizeof(ehdr));
+  Elf* elf = rw_info.GetElf(process_memory_, ARCH_ARM);
+  ASSERT_TRUE(elf != nullptr);
+  ASSERT_TRUE(elf->valid());
+
+  ASSERT_EQ(elf, r_info.GetElf(process_memory_, ARCH_ARM));
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h
index d6ca9b7..207d46e 100644
--- a/libunwindstack/tests/RegsFake.h
+++ b/libunwindstack/tests/RegsFake.h
@@ -23,6 +23,8 @@
 #include <unwindstack/Memory.h>
 #include <unwindstack/Regs.h>
 
+#include "Check.h"
+
 namespace unwindstack {
 
 class RegsFake : public Regs {
@@ -47,7 +49,10 @@
 
   void IterateRegisters(std::function<void(const char*, uint64_t)>) override {}
 
-  bool Is32Bit() { return false; }
+  bool Is32Bit() {
+    CHECK(fake_arch_ != ARCH_UNKNOWN);
+    return fake_arch_ == ARCH_ARM || fake_arch_ == ARCH_X86 || fake_arch_ == ARCH_MIPS;
+  }
 
   uint64_t GetPcAdjustment(uint64_t, Elf*) override { return 2; }
 
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index b5feb38..655579e 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -300,7 +300,7 @@
   EXPECT_EQ(
       "  #00 pc 00068fb8  libarttestd.so (art::CauseSegfault()+72)\n"
       "  #01 pc 00067f00  libarttestd.so (Java_Main_unwindInProcess+10032)\n"
-      "  #02 pc 000021a8  137-cfi.odex (offset 0x2000) (boolean Main.unwindInProcess(boolean, int, "
+      "  #02 pc 000021a8  137-cfi.odex (boolean Main.unwindInProcess(boolean, int, "
       "boolean)+136)\n"
       "  #03 pc 0000fe80  anonymous:ee74c000 (boolean Main.bar(boolean)+64)\n"
       "  #04 pc 006ad4d2  libartd.so (art_quick_invoke_stub+338)\n"
@@ -601,7 +601,7 @@
   ASSERT_EQ(76U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
   EXPECT_EQ(
       "  #00 pc 00018a5e  libarttestd.so (Java_Main_unwindInProcess+866)\n"
-      "  #01 pc 0000212d  137-cfi.odex (offset 0x2000) (boolean Main.unwindInProcess(boolean, int, "
+      "  #01 pc 0000212d  137-cfi.odex (boolean Main.unwindInProcess(boolean, int, "
       "boolean)+92)\n"
       "  #02 pc 00011cb1  anonymous:e2796000 (boolean Main.bar(boolean)+72)\n"
       "  #03 pc 00462175  libartd.so (art_quick_invoke_stub_internal+68)\n"
@@ -1312,7 +1312,8 @@
       "  #02 pc 00000000000008bc  vdso.so\n"
       "  #03 pc 00000000000846f4  libc.so (abort+172)\n"
       "  #04 pc 0000000000084ad4  libc.so (__assert2+36)\n"
-      "  #05 pc 000000000003d5b4  ANGLEPrebuilt.apk (offset 0x4000) (ANGLEGetUtilityAPI+56)\n"
+      "  #05 pc 000000000003d5b4  ANGLEPrebuilt.apk!libfeature_support_angle.so (offset 0x4000) "
+      "(ANGLEGetUtilityAPI+56)\n"
       "  #06 pc 000000000007fe68  libc.so (__libc_init)\n",
       frame_info);
 
@@ -1372,4 +1373,56 @@
   // Ignore top frame since the test code was modified to end in __libc_init.
 }
 
+TEST_F(UnwindOfflineTest, shared_lib_in_apk_single_map_arm64) {
+  ASSERT_NO_FATAL_FAILURE(Init("shared_lib_in_apk_single_map_arm64/", ARCH_ARM64));
+
+  Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+  unwinder.Unwind();
+
+  std::string frame_info(DumpFrames(unwinder));
+  ASSERT_EQ(13U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+  EXPECT_EQ(
+      "  #00 pc 00000000000814bc  libc.so (syscall+28)\n"
+      "  #01 pc 00000000008cdf5c  test.apk (offset 0x5000)\n"
+      "  #02 pc 00000000008cde9c  test.apk (offset 0x5000)\n"
+      "  #03 pc 00000000008cdd70  test.apk (offset 0x5000)\n"
+      "  #04 pc 00000000008ce408  test.apk (offset 0x5000)\n"
+      "  #05 pc 00000000008ce8d8  test.apk (offset 0x5000)\n"
+      "  #06 pc 00000000008ce814  test.apk (offset 0x5000)\n"
+      "  #07 pc 00000000008bcf60  test.apk (offset 0x5000)\n"
+      "  #08 pc 0000000000133024  test.apk (offset 0x5000)\n"
+      "  #09 pc 0000000000134ad0  test.apk (offset 0x5000)\n"
+      "  #10 pc 0000000000134b64  test.apk (offset 0x5000)\n"
+      "  #11 pc 00000000000e406c  libc.so (__pthread_start(void*)+36)\n"
+      "  #12 pc 0000000000085e18  libc.so (__start_thread+64)\n",
+      frame_info);
+
+  EXPECT_EQ(0x7cbe0b14bcULL, unwinder.frames()[0].pc);
+  EXPECT_EQ(0x7be4f077d0ULL, unwinder.frames()[0].sp);
+  EXPECT_EQ(0x7be6715f5cULL, unwinder.frames()[1].pc);
+  EXPECT_EQ(0x7be4f077d0ULL, unwinder.frames()[1].sp);
+  EXPECT_EQ(0x7be6715e9cULL, unwinder.frames()[2].pc);
+  EXPECT_EQ(0x7be4f07800ULL, unwinder.frames()[2].sp);
+  EXPECT_EQ(0x7be6715d70ULL, unwinder.frames()[3].pc);
+  EXPECT_EQ(0x7be4f07840ULL, unwinder.frames()[3].sp);
+  EXPECT_EQ(0x7be6716408ULL, unwinder.frames()[4].pc);
+  EXPECT_EQ(0x7be4f07860ULL, unwinder.frames()[4].sp);
+  EXPECT_EQ(0x7be67168d8ULL, unwinder.frames()[5].pc);
+  EXPECT_EQ(0x7be4f07880ULL, unwinder.frames()[5].sp);
+  EXPECT_EQ(0x7be6716814ULL, unwinder.frames()[6].pc);
+  EXPECT_EQ(0x7be4f078f0ULL, unwinder.frames()[6].sp);
+  EXPECT_EQ(0x7be6704f60ULL, unwinder.frames()[7].pc);
+  EXPECT_EQ(0x7be4f07910ULL, unwinder.frames()[7].sp);
+  EXPECT_EQ(0x7be5f7b024ULL, unwinder.frames()[8].pc);
+  EXPECT_EQ(0x7be4f07950ULL, unwinder.frames()[8].sp);
+  EXPECT_EQ(0x7be5f7cad0ULL, unwinder.frames()[9].pc);
+  EXPECT_EQ(0x7be4f07aa0ULL, unwinder.frames()[9].sp);
+  EXPECT_EQ(0x7be5f7cb64ULL, unwinder.frames()[10].pc);
+  EXPECT_EQ(0x7be4f07ce0ULL, unwinder.frames()[10].sp);
+  EXPECT_EQ(0x7cbe11406cULL, unwinder.frames()[11].pc);
+  EXPECT_EQ(0x7be4f07d00ULL, unwinder.frames()[11].sp);
+  EXPECT_EQ(0x7cbe0b5e18ULL, unwinder.frames()[12].pc);
+  EXPECT_EQ(0x7be4f07d20ULL, unwinder.frames()[12].sp);
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 2dc5118..48e038e 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -58,7 +58,9 @@
     maps_.reset(new Maps);
 
     ElfFake* elf = new ElfFake(new MemoryFake);
-    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+    ElfInterfaceFake* interface_fake = new ElfInterfaceFake(nullptr);
+    interface_fake->FakeSetBuildID("FAKE");
+    elf->FakeSetInterface(interface_fake);
     AddMapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so", elf);
 
     AddMapInfo(0x10000, 0x12000, 0, PROT_READ | PROT_WRITE, "[stack]");
@@ -79,8 +81,13 @@
     AddMapInfo(0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so", elf);
 
     elf = new ElfFake(new MemoryFake);
-    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+    ElfInterfaceFake* interface = new ElfInterfaceFake(nullptr);
+    interface->FakeSetSoname("lib_fake.so");
+    elf->FakeSetInterface(interface);
     AddMapInfo(0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk", elf);
+    MapInfo* map_info = maps_->Find(0x43000);
+    ASSERT_TRUE(map_info != nullptr);
+    map_info->elf_start_offset = 0x1d000;
 
     AddMapInfo(0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat");
 
@@ -324,8 +331,38 @@
   EXPECT_EQ(0x10000U, frame->sp);
   EXPECT_EQ("Frame0", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
+  EXPECT_EQ("/fake/fake.apk!lib_fake.so", frame->map_name);
+  EXPECT_EQ(0x1d000U, frame->map_elf_start_offset);
+  EXPECT_EQ(0x1d000U, frame->map_exact_offset);
+  EXPECT_EQ(0x43000U, frame->map_start);
+  EXPECT_EQ(0x44000U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
+}
+
+TEST_F(UnwinderTest, disable_embedded_soname) {
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+
+  regs_.set_pc(0x43000);
+  regs_.set_sp(0x10000);
+  ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
+  unwinder.SetEmbeddedSoname(false);
+  unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+
+  ASSERT_EQ(1U, unwinder.NumFrames());
+
+  auto* frame = &unwinder.frames()[0];
+  EXPECT_EQ(0U, frame->num);
+  EXPECT_EQ(0U, frame->rel_pc);
+  EXPECT_EQ(0x43000U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("Frame0", frame->function_name);
+  EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("/fake/fake.apk", frame->map_name);
-  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0x1d000U, frame->map_elf_start_offset);
   EXPECT_EQ(0x1d000U, frame->map_exact_offset);
   EXPECT_EQ(0x43000U, frame->map_start);
   EXPECT_EQ(0x44000U, frame->map_end);
@@ -813,8 +850,8 @@
   EXPECT_EQ(0x10010U, frame->sp);
   EXPECT_EQ("Frame1", frame->function_name);
   EXPECT_EQ(1U, frame->function_offset);
-  EXPECT_EQ("/fake/fake.apk", frame->map_name);
-  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ("/fake/fake.apk!lib_fake.so", frame->map_name);
+  EXPECT_EQ(0x1d000U, frame->map_elf_start_offset);
   EXPECT_EQ(0x1d000U, frame->map_exact_offset);
   EXPECT_EQ(0x43000U, frame->map_start);
   EXPECT_EQ(0x44000U, frame->map_end);
@@ -1067,7 +1104,15 @@
 }
 
 // Verify format frame code.
-TEST_F(UnwinderTest, format_frame_static) {
+TEST_F(UnwinderTest, format_frame) {
+  RegsFake regs_arm(10);
+  regs_arm.FakeSetArch(ARCH_ARM);
+  Unwinder unwinder32(10, maps_.get(), &regs_arm, process_memory_);
+
+  RegsFake regs_arm64(10);
+  regs_arm64.FakeSetArch(ARCH_ARM64);
+  Unwinder unwinder64(10, maps_.get(), &regs_arm64, process_memory_);
+
   FrameData frame;
   frame.num = 1;
   frame.rel_pc = 0x1000;
@@ -1082,39 +1127,61 @@
   frame.map_flags = PROT_READ;
 
   EXPECT_EQ("  #01 pc 0000000000001000  /fake/libfake.so (offset 0x2000) (function+100)",
-            Unwinder::FormatFrame(frame, false));
+            unwinder64.FormatFrame(frame));
   EXPECT_EQ("  #01 pc 00001000  /fake/libfake.so (offset 0x2000) (function+100)",
-            Unwinder::FormatFrame(frame, true));
+            unwinder32.FormatFrame(frame));
 
   frame.map_elf_start_offset = 0;
   EXPECT_EQ("  #01 pc 0000000000001000  /fake/libfake.so (function+100)",
-            Unwinder::FormatFrame(frame, false));
-  EXPECT_EQ("  #01 pc 00001000  /fake/libfake.so (function+100)",
-            Unwinder::FormatFrame(frame, true));
+            unwinder64.FormatFrame(frame));
+  EXPECT_EQ("  #01 pc 00001000  /fake/libfake.so (function+100)", unwinder32.FormatFrame(frame));
 
   frame.function_offset = 0;
   EXPECT_EQ("  #01 pc 0000000000001000  /fake/libfake.so (function)",
-            Unwinder::FormatFrame(frame, false));
-  EXPECT_EQ("  #01 pc 00001000  /fake/libfake.so (function)", Unwinder::FormatFrame(frame, true));
+            unwinder64.FormatFrame(frame));
+  EXPECT_EQ("  #01 pc 00001000  /fake/libfake.so (function)", unwinder32.FormatFrame(frame));
 
   // Verify the function name is demangled.
   frame.function_name = "_ZN4funcEv";
-  EXPECT_EQ("  #01 pc 0000000000001000  /fake/libfake.so (func())",
-            Unwinder::FormatFrame(frame, false));
-  EXPECT_EQ("  #01 pc 00001000  /fake/libfake.so (func())", Unwinder::FormatFrame(frame, true));
+  EXPECT_EQ("  #01 pc 0000000000001000  /fake/libfake.so (func())", unwinder64.FormatFrame(frame));
+  EXPECT_EQ("  #01 pc 00001000  /fake/libfake.so (func())", unwinder32.FormatFrame(frame));
 
   frame.function_name = "";
-  EXPECT_EQ("  #01 pc 0000000000001000  /fake/libfake.so", Unwinder::FormatFrame(frame, false));
-  EXPECT_EQ("  #01 pc 00001000  /fake/libfake.so", Unwinder::FormatFrame(frame, true));
+  EXPECT_EQ("  #01 pc 0000000000001000  /fake/libfake.so", unwinder64.FormatFrame(frame));
+  EXPECT_EQ("  #01 pc 00001000  /fake/libfake.so", unwinder32.FormatFrame(frame));
 
   frame.map_name = "";
-  EXPECT_EQ("  #01 pc 0000000000001000  <anonymous:3000>", Unwinder::FormatFrame(frame, false));
-  EXPECT_EQ("  #01 pc 00001000  <anonymous:3000>", Unwinder::FormatFrame(frame, true));
+  EXPECT_EQ("  #01 pc 0000000000001000  <anonymous:3000>", unwinder64.FormatFrame(frame));
+  EXPECT_EQ("  #01 pc 00001000  <anonymous:3000>", unwinder32.FormatFrame(frame));
 
   frame.map_start = 0;
   frame.map_end = 0;
-  EXPECT_EQ("  #01 pc 0000000000001000  <unknown>", Unwinder::FormatFrame(frame, false));
-  EXPECT_EQ("  #01 pc 00001000  <unknown>", Unwinder::FormatFrame(frame, true));
+  EXPECT_EQ("  #01 pc 0000000000001000  <unknown>", unwinder64.FormatFrame(frame));
+  EXPECT_EQ("  #01 pc 00001000  <unknown>", unwinder32.FormatFrame(frame));
+}
+
+TEST_F(UnwinderTest, format_frame_build_id) {
+  RegsFake regs(10);
+  regs.FakeSetArch(ARCH_ARM);
+  Unwinder unwinder(10, maps_.get(), &regs, process_memory_);
+
+  FrameData frame;
+  frame.num = 1;
+  frame.rel_pc = 0x1000;
+  frame.pc = 0x4000;
+  frame.sp = 0x1000;
+  frame.function_name = "function";
+  frame.function_offset = 100;
+  frame.map_name = "/fake/libfake.so";
+  frame.map_elf_start_offset = 0;
+  frame.map_start = 0x3000;
+  frame.map_end = 0x6000;
+  frame.map_flags = PROT_READ;
+
+  EXPECT_EQ("  #01 pc 00001000  /fake/libfake.so (function+100)", unwinder.FormatFrame(frame));
+  unwinder.SetDisplayBuildID(true);
+  EXPECT_EQ("  #01 pc 00001000  /fake/libfake.so (function+100) (BuildId: 46414b45)",
+            unwinder.FormatFrame(frame));
 }
 
 static std::string ArchToString(ArchEnum arch) {
@@ -1132,7 +1199,7 @@
 }
 
 // Verify format frame code.
-TEST_F(UnwinderTest, format_frame) {
+TEST_F(UnwinderTest, format_frame_by_arch) {
   std::vector<Regs*> reg_list;
   RegsArm* arm = new RegsArm;
   arm->set_pc(0x2300);
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/maps.txt b/libunwindstack/tests/files/offline/jit_debug_arm/maps.txt
index 3cd9d40..4043122 100644
--- a/libunwindstack/tests/files/offline/jit_debug_arm/maps.txt
+++ b/libunwindstack/tests/files/offline/jit_debug_arm/maps.txt
@@ -1,5 +1,6 @@
 ab0d3000-ab0d8000 r-xp 0 00:00 0   dalvikvm32
 dfe4e000-dfe7b000 r-xp 0 00:00 0   libarttestd.so
+e0445000-e0447000 r--p 0 00:00 0   137-cfi.odex
 e0447000-e0448000 r-xp 2000 00:00 0   137-cfi.odex
 e2796000-e4796000 r-xp 0 00:00 0   anonymous:e2796000
 e648e000-e690f000 r-xp 0 00:00 0  libart.so
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/maps.txt b/libunwindstack/tests/files/offline/jit_debug_x86/maps.txt
index a8d215c..f255a44 100644
--- a/libunwindstack/tests/files/offline/jit_debug_x86/maps.txt
+++ b/libunwindstack/tests/files/offline/jit_debug_x86/maps.txt
@@ -1,5 +1,6 @@
 56573000-56577000 r-xp 0 00:00 0   dalvikvm32
 eb833000-eb8cc000 r-xp 0 00:00 0   libarttestd.so
+ec604000-ec606000 r--p 0 00:00 0   137-cfi.odex
 ec606000-ec607000 r-xp 2000 00:00 0   137-cfi.odex
 ee74c000-f074c000 r-xp 0 00:00 0   anonymous:ee74c000
 f6be1000-f732b000 r-xp 0 00:00 0   libartd.so
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/libc.so b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/libc.so
new file mode 100644
index 0000000..cac1dd9
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/maps.txt b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/maps.txt
new file mode 100644
index 0000000..2c5ca62
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/maps.txt
@@ -0,0 +1,3 @@
+7be5e48000-7be6b2b000 r-xp 5000 00:00 0   test.apk
+7cbe030000-7cbe070000 r--p 0 00:00 0   libc.so
+7cbe070000-7cbe11a000 r-xp 40000 00:00 0   libc.so
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/regs.txt b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/regs.txt
new file mode 100644
index 0000000..090aeda
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/regs.txt
@@ -0,0 +1,33 @@
+x0: 7c326f6568
+x1: 80
+x2: 0
+x3: 0
+x4: 0
+x5: 0
+x6: 0
+x7: 7f7f7f7f7f7f7f7f
+x8: 62
+x9: 1
+x10: 1
+x11: 0
+x12: ffffffffc4653600
+x13: 17645696f
+x14: 2742ed97ca77a3
+x15: 3ab49084
+x16: 7be6b6bdb8
+x17: 7cbe0b14a0
+x18: 7c2b02a000
+x19: 0
+x20: 7c326f6568
+x21: 7be69c827c
+x22: 7be69c8272
+x23: 1
+x24: 7be74f7100
+x25: 881
+x26: 7be4f07a00
+x27: c479c000
+x28: 7be4f07998
+x29: 7be4f079b4
+sp: 7be4f077d0
+lr: 7be6715f60
+pc: 7cbe0b14bc
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/stack.data b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/stack.data
new file mode 100644
index 0000000..27d5bf3
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/test.apk b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/test.apk
new file mode 100644
index 0000000..70a9c71
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/test.apk
Binary files differ
diff --git a/libunwindstack/tools/unwind_info.cpp b/libunwindstack/tools/unwind_info.cpp
index 19982d8..92e5c0a 100644
--- a/libunwindstack/tools/unwind_info.cpp
+++ b/libunwindstack/tools/unwind_info.cpp
@@ -118,8 +118,8 @@
     return 1;
   }
 
-  std::string soname;
-  if (elf.GetSoname(&soname)) {
+  std::string soname(elf.GetSoname());
+  if (!soname.empty()) {
     printf("Soname: %s\n", soname.c_str());
   }
 
diff --git a/libunwindstack/tools/unwind_reg_info.cpp b/libunwindstack/tools/unwind_reg_info.cpp
index 4b6f49a..b77a86b 100644
--- a/libunwindstack/tools/unwind_reg_info.cpp
+++ b/libunwindstack/tools/unwind_reg_info.cpp
@@ -185,8 +185,8 @@
     return 1;
   }
 
-  std::string soname;
-  if (elf.GetSoname(&soname)) {
+  std::string soname(elf.GetSoname());
+  if (!soname.empty()) {
     printf("Soname: %s\n\n", soname.c_str());
   }
 
diff --git a/libunwindstack/tools/unwind_symbols.cpp b/libunwindstack/tools/unwind_symbols.cpp
index 9128430..b0a4dd0 100644
--- a/libunwindstack/tools/unwind_symbols.cpp
+++ b/libunwindstack/tools/unwind_symbols.cpp
@@ -71,8 +71,8 @@
     return 1;
   }
 
-  std::string soname;
-  if (elf.GetSoname(&soname)) {
+  std::string soname(elf.GetSoname());
+  if (!soname.empty()) {
     printf("Soname: %s\n\n", soname.c_str());
   }
 
diff --git a/libusbhost/Android.bp b/libusbhost/Android.bp
index 39bf3a5..fc6f305 100644
--- a/libusbhost/Android.bp
+++ b/libusbhost/Android.bp
@@ -20,7 +20,6 @@
     vndk: {
         enabled: true,
     },
-    double_loadable: true,
     host_supported: true,
     srcs: ["usbhost.c"],
     cflags: ["-Werror"],
diff --git a/libutils/Android.bp b/libutils/Android.bp
index c67ff8f..3e7d0ba 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -69,6 +69,7 @@
     ],
 
     shared_libs: [
+        "libcutils",
         "liblog",
     ],
 
@@ -83,7 +84,6 @@
             cflags: ["-fvisibility=protected"],
 
             shared_libs: [
-                "libcutils",
                 "libprocessgroup",
                 "libdl",
                 "libvndksupport",
@@ -98,14 +98,6 @@
             exclude_shared_libs: ["libvndksupport"],
         },
 
-        host: {
-            cflags: ["-DLIBUTILS_NATIVE=1"],
-
-            shared: {
-                enabled: false,
-            },
-        },
-
         linux_bionic: {
             enabled: true,
         },
@@ -180,18 +172,20 @@
         },
     },
 
+    shared_libs: [
+         "libutils",
+         "libbacktrace",
+    ],
+
     target: {
-        android: {
-            shared_libs: [
-                "libutils",
-                "libbacktrace",
-            ],
-        },
         linux: {
             srcs: [
                 "ProcessCallStack.cpp",
             ],
         },
+        windows: {
+            enabled: false,
+        },
     },
 }
 
diff --git a/libutils/Mutex_test.cpp b/libutils/Mutex_test.cpp
index 8a1805f..79f4302 100644
--- a/libutils/Mutex_test.cpp
+++ b/libutils/Mutex_test.cpp
@@ -29,4 +29,20 @@
     android::Mutex::Autolock _l(mLock);
     i = 0;
     modifyLockedVariable();
-}
\ No newline at end of file
+}
+
+TEST(Mutex, tryLock) {
+    if (mLock.tryLock() != 0) {
+        return;
+    }
+    mLock.unlock();
+}
+
+#if defined(__ANDROID__)
+TEST(Mutex, timedLock) {
+    if (mLock.timedLock(1) != 0) {
+        return;
+    }
+    mLock.unlock();
+}
+#endif
diff --git a/libutils/RefBase_test.cpp b/libutils/RefBase_test.cpp
index 2e0cf6e..c9b4894 100644
--- a/libutils/RefBase_test.cpp
+++ b/libutils/RefBase_test.cpp
@@ -45,6 +45,44 @@
     bool* mDeleted;
 };
 
+// A version of Foo that ensures that all objects are allocated at the same
+// address. No more than one can be allocated at a time. Thread-hostile.
+class FooFixedAlloc : public RefBase {
+public:
+    static void* operator new(size_t size) {
+        if (mAllocCount != 0) {
+            abort();
+        }
+        mAllocCount = 1;
+        if (theMemory == nullptr) {
+            theMemory = malloc(size);
+        }
+        return theMemory;
+    }
+
+    static void operator delete(void *p) {
+        if (mAllocCount != 1 || p != theMemory) {
+            abort();
+        }
+        mAllocCount = 0;
+    }
+
+    FooFixedAlloc(bool* deleted_check) : mDeleted(deleted_check) {
+        *mDeleted = false;
+    }
+
+    ~FooFixedAlloc() {
+        *mDeleted = true;
+    }
+private:
+    bool* mDeleted;
+    static int mAllocCount;
+    static void* theMemory;
+};
+
+int FooFixedAlloc::mAllocCount(0);
+void* FooFixedAlloc::theMemory(nullptr);
+
 TEST(RefBase, StrongMoves) {
     bool isDeleted;
     Foo* foo = new Foo(&isDeleted);
@@ -90,6 +128,118 @@
     ASSERT_FALSE(isDeleted) << "Deletion on wp destruction should no longer occur";
 }
 
+TEST(RefBase, Comparisons) {
+    bool isDeleted, isDeleted2, isDeleted3;
+    Foo* foo = new Foo(&isDeleted);
+    Foo* foo2 = new Foo(&isDeleted2);
+    sp<Foo> sp1(foo);
+    sp<Foo> sp2(foo2);
+    wp<Foo> wp1(sp1);
+    wp<Foo> wp2(sp1);
+    wp<Foo> wp3(sp2);
+    ASSERT_TRUE(wp1 == wp2);
+    ASSERT_TRUE(wp1 == sp1);
+    ASSERT_TRUE(wp3 == sp2);
+    ASSERT_TRUE(wp1 != sp2);
+    ASSERT_TRUE(wp1 <= wp2);
+    ASSERT_TRUE(wp1 >= wp2);
+    ASSERT_FALSE(wp1 != wp2);
+    ASSERT_FALSE(wp1 > wp2);
+    ASSERT_FALSE(wp1 < wp2);
+    ASSERT_FALSE(sp1 == sp2);
+    ASSERT_TRUE(sp1 != sp2);
+    bool sp1_smaller = sp1 < sp2;
+    wp<Foo>wp_smaller = sp1_smaller ? wp1 : wp3;
+    wp<Foo>wp_larger = sp1_smaller ? wp3 : wp1;
+    ASSERT_TRUE(wp_smaller < wp_larger);
+    ASSERT_TRUE(wp_smaller != wp_larger);
+    ASSERT_TRUE(wp_smaller <= wp_larger);
+    ASSERT_FALSE(wp_smaller == wp_larger);
+    ASSERT_FALSE(wp_smaller > wp_larger);
+    ASSERT_FALSE(wp_smaller >= wp_larger);
+    sp2 = nullptr;
+    ASSERT_TRUE(isDeleted2);
+    ASSERT_FALSE(isDeleted);
+    ASSERT_FALSE(wp3 == sp2);
+    // Comparison results on weak pointers should not be affected.
+    ASSERT_TRUE(wp_smaller < wp_larger);
+    ASSERT_TRUE(wp_smaller != wp_larger);
+    ASSERT_TRUE(wp_smaller <= wp_larger);
+    ASSERT_FALSE(wp_smaller == wp_larger);
+    ASSERT_FALSE(wp_smaller > wp_larger);
+    ASSERT_FALSE(wp_smaller >= wp_larger);
+    wp2 = nullptr;
+    ASSERT_FALSE(wp1 == wp2);
+    ASSERT_TRUE(wp1 != wp2);
+    wp1.clear();
+    ASSERT_TRUE(wp1 == wp2);
+    ASSERT_FALSE(wp1 != wp2);
+    wp3.clear();
+    ASSERT_TRUE(wp1 == wp3);
+    ASSERT_FALSE(wp1 != wp3);
+    ASSERT_FALSE(isDeleted);
+    sp1.clear();
+    ASSERT_TRUE(isDeleted);
+    ASSERT_TRUE(sp1 == sp2);
+    // Try to check that null pointers are properly initialized.
+    {
+        // Try once with non-null, to maximize chances of getting junk on the
+        // stack.
+        sp<Foo> sp3(new Foo(&isDeleted3));
+        wp<Foo> wp4(sp3);
+        wp<Foo> wp5;
+        ASSERT_FALSE(wp4 == wp5);
+        ASSERT_TRUE(wp4 != wp5);
+        ASSERT_FALSE(sp3 == wp5);
+        ASSERT_FALSE(wp5 == sp3);
+        ASSERT_TRUE(sp3 != wp5);
+        ASSERT_TRUE(wp5 != sp3);
+        ASSERT_TRUE(sp3 == wp4);
+    }
+    {
+        sp<Foo> sp3;
+        wp<Foo> wp4(sp3);
+        wp<Foo> wp5;
+        ASSERT_TRUE(wp4 == wp5);
+        ASSERT_FALSE(wp4 != wp5);
+        ASSERT_TRUE(sp3 == wp5);
+        ASSERT_TRUE(wp5 == sp3);
+        ASSERT_FALSE(sp3 != wp5);
+        ASSERT_FALSE(wp5 != sp3);
+        ASSERT_TRUE(sp3 == wp4);
+    }
+}
+
+// Check whether comparison against dead wp works, even if the object referenced
+// by the new wp happens to be at the same address.
+TEST(RefBase, ReplacedComparison) {
+    bool isDeleted, isDeleted2;
+    FooFixedAlloc* foo = new FooFixedAlloc(&isDeleted);
+    sp<FooFixedAlloc> sp1(foo);
+    wp<FooFixedAlloc> wp1(sp1);
+    ASSERT_TRUE(wp1 == sp1);
+    sp1.clear();  // Deallocates the object.
+    ASSERT_TRUE(isDeleted);
+    FooFixedAlloc* foo2 = new FooFixedAlloc(&isDeleted2);
+    ASSERT_FALSE(isDeleted2);
+    ASSERT_EQ(foo, foo2);  // Not technically a legal comparison, but ...
+    sp<FooFixedAlloc> sp2(foo2);
+    wp<FooFixedAlloc> wp2(sp2);
+    ASSERT_TRUE(sp2 == wp2);
+    ASSERT_FALSE(sp2 != wp2);
+    ASSERT_TRUE(sp2 != wp1);
+    ASSERT_FALSE(sp2 == wp1);
+    ASSERT_FALSE(sp2 == sp1);  // sp1 is null.
+    ASSERT_FALSE(wp1 == wp2);  // wp1 refers to old object.
+    ASSERT_TRUE(wp1 != wp2);
+    ASSERT_TRUE(wp1 > wp2 || wp1 < wp2);
+    ASSERT_TRUE(wp1 >= wp2 || wp1 <= wp2);
+    ASSERT_FALSE(wp1 >= wp2 && wp1 <= wp2);
+    ASSERT_FALSE(wp1 == nullptr);
+    wp1 = sp2;
+    ASSERT_TRUE(wp1 == wp2);
+    ASSERT_FALSE(wp1 != wp2);
+}
 
 // Set up a situation in which we race with visit2AndRremove() to delete
 // 2 strong references.  Bar destructor checks that there are no early
diff --git a/libutils/include/utils/Mutex.h b/libutils/include/utils/Mutex.h
index 29c2e8c..1325bf3 100644
--- a/libutils/include/utils/Mutex.h
+++ b/libutils/include/utils/Mutex.h
@@ -108,7 +108,7 @@
     void unlock() RELEASE();
 
     // lock if possible; returns 0 on success, error otherwise
-    status_t tryLock() TRY_ACQUIRE(true);
+    status_t tryLock() TRY_ACQUIRE(0);
 
 #if defined(__ANDROID__)
     // Lock the mutex, but don't wait longer than timeoutNs (relative time).
@@ -122,7 +122,7 @@
     // which is subject to NTP adjustments, and includes time during suspend,
     // so a timeout may occur even though no processes could run.
     // Not holding a partial wakelock may lead to a system suspend.
-    status_t timedLock(nsecs_t timeoutNs) TRY_ACQUIRE(true);
+    status_t timedLock(nsecs_t timeoutNs) TRY_ACQUIRE(0);
 #endif
 
     // Manages the mutex automatically. It'll be locked when Autolock is
diff --git a/libutils/include/utils/RefBase.h b/libutils/include/utils/RefBase.h
index 1780cf2..a105474 100644
--- a/libutils/include/utils/RefBase.h
+++ b/libutils/include/utils/RefBase.h
@@ -171,6 +171,8 @@
 #define ANDROID_REF_BASE_H
 
 #include <atomic>
+#include <functional>
+#include <type_traits>  // for common_type.
 
 #include <stdint.h>
 #include <sys/types.h>
@@ -192,19 +194,26 @@
 // ---------------------------------------------------------------------------
 
 #define COMPARE_WEAK(_op_)                                      \
-inline bool operator _op_ (const sp<T>& o) const {              \
-    return m_ptr _op_ o.m_ptr;                                  \
-}                                                               \
-inline bool operator _op_ (const T* o) const {                  \
-    return m_ptr _op_ o;                                        \
-}                                                               \
-template<typename U>                                            \
-inline bool operator _op_ (const sp<U>& o) const {              \
-    return m_ptr _op_ o.m_ptr;                                  \
-}                                                               \
 template<typename U>                                            \
 inline bool operator _op_ (const U* o) const {                  \
     return m_ptr _op_ o;                                        \
+}                                                               \
+/* Needed to handle type inference for nullptr: */              \
+inline bool operator _op_ (const T* o) const {                  \
+    return m_ptr _op_ o;                                        \
+}
+
+template<template<typename C> class comparator, typename T, typename U>
+static inline bool _wp_compare_(T* a, U* b) {
+    return comparator<typename std::common_type<T*, U*>::type>()(a, b);
+}
+
+// Use std::less and friends to avoid undefined behavior when ordering pointers
+// to different objects.
+#define COMPARE_WEAK_FUNCTIONAL(_op_, _compare_)                 \
+template<typename U>                                             \
+inline bool operator _op_ (const U* o) const {                   \
+    return _wp_compare_<_compare_>(m_ptr, o);                    \
 }
 
 // ---------------------------------------------------------------------------
@@ -354,7 +363,7 @@
 public:
     typedef typename RefBase::weakref_type weakref_type;
 
-    inline wp() : m_ptr(nullptr) { }
+    inline wp() : m_ptr(nullptr), m_refs(nullptr) { }
 
     wp(T* other);  // NOLINT(implicit)
     wp(const wp<T>& other);
@@ -395,39 +404,51 @@
 
     COMPARE_WEAK(==)
     COMPARE_WEAK(!=)
-    COMPARE_WEAK(>)
-    COMPARE_WEAK(<)
-    COMPARE_WEAK(<=)
-    COMPARE_WEAK(>=)
+    COMPARE_WEAK_FUNCTIONAL(>, std::greater)
+    COMPARE_WEAK_FUNCTIONAL(<, std::less)
+    COMPARE_WEAK_FUNCTIONAL(<=, std::less_equal)
+    COMPARE_WEAK_FUNCTIONAL(>=, std::greater_equal)
 
-    inline bool operator == (const wp<T>& o) const {
-        return (m_ptr == o.m_ptr) && (m_refs == o.m_refs);
-    }
     template<typename U>
     inline bool operator == (const wp<U>& o) const {
-        return m_ptr == o.m_ptr;
+        return m_refs == o.m_refs;  // Implies m_ptr == o.mptr; see invariants below.
     }
 
-    inline bool operator > (const wp<T>& o) const {
-        return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
+    template<typename U>
+    inline bool operator == (const sp<U>& o) const {
+        // Just comparing m_ptr fields is often dangerous, since wp<> may refer to an older
+        // object at the same address.
+        if (o == nullptr) {
+          return m_ptr == nullptr;
+        } else {
+          return m_refs == o->getWeakRefs();  // Implies m_ptr == o.mptr.
+        }
     }
+
+    template<typename U>
+    inline bool operator != (const sp<U>& o) const {
+        return !(*this == o);
+    }
+
     template<typename U>
     inline bool operator > (const wp<U>& o) const {
-        return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
+        if (m_ptr == o.m_ptr) {
+            return _wp_compare_<std::greater>(m_refs, o.m_refs);
+        } else {
+            return _wp_compare_<std::greater>(m_ptr, o.m_ptr);
+        }
     }
 
-    inline bool operator < (const wp<T>& o) const {
-        return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
-    }
     template<typename U>
     inline bool operator < (const wp<U>& o) const {
-        return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
+        if (m_ptr == o.m_ptr) {
+            return _wp_compare_<std::less>(m_refs, o.m_refs);
+        } else {
+            return _wp_compare_<std::less>(m_ptr, o.m_ptr);
+        }
     }
-                         inline bool operator != (const wp<T>& o) const { return m_refs != o.m_refs; }
     template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); }
-                         inline bool operator <= (const wp<T>& o) const { return !operator > (o); }
     template<typename U> inline bool operator <= (const wp<U>& o) const { return !operator > (o); }
-                         inline bool operator >= (const wp<T>& o) const { return !operator < (o); }
     template<typename U> inline bool operator >= (const wp<U>& o) const { return !operator < (o); }
 
 private:
@@ -446,11 +467,27 @@
 // ---------------------------------------------------------------------------
 // No user serviceable parts below here.
 
+// Implementation invariants:
+// Either
+// 1) m_ptr and m_refs are both null, or
+// 2) m_refs == m_ptr->mRefs, or
+// 3) *m_ptr is no longer live, and m_refs points to the weakref_type object that corresponded
+//    to m_ptr while it was live. *m_refs remains live while a wp<> refers to it.
+//
+// The m_refs field in a RefBase object is allocated on construction, unique to that RefBase
+// object, and never changes. Thus if two wp's have identical m_refs fields, they are either both
+// null or point to the same object. If two wp's have identical m_ptr fields, they either both
+// point to the same live object and thus have the same m_ref fields, or at least one of the
+// objects is no longer live.
+//
+// Note that the above comparison operations go out of their way to provide an ordering consistent
+// with ordinary pointer comparison; otherwise they could ignore m_ptr, and just compare m_refs.
+
 template<typename T>
 wp<T>::wp(T* other)
     : m_ptr(other)
 {
-    if (other) m_refs = other->createWeak(this);
+    m_refs = other ? m_refs = other->createWeak(this) : nullptr;
 }
 
 template<typename T>
@@ -464,16 +501,14 @@
 wp<T>::wp(const sp<T>& other)
     : m_ptr(other.m_ptr)
 {
-    if (m_ptr) {
-        m_refs = m_ptr->createWeak(this);
-    }
+    m_refs = m_ptr ? m_ptr->createWeak(this) : nullptr;
 }
 
 template<typename T> template<typename U>
 wp<T>::wp(U* other)
     : m_ptr(other)
 {
-    if (other) m_refs = other->createWeak(this);
+    m_refs = other ? other->createWeak(this) : nullptr;
 }
 
 template<typename T> template<typename U>
@@ -483,6 +518,8 @@
     if (m_ptr) {
         m_refs = other.m_refs;
         m_refs->incWeak(this);
+    } else {
+        m_refs = nullptr;
     }
 }
 
@@ -490,9 +527,7 @@
 wp<T>::wp(const sp<U>& other)
     : m_ptr(other.m_ptr)
 {
-    if (m_ptr) {
-        m_refs = m_ptr->createWeak(this);
-    }
+    m_refs = m_ptr ? m_ptr->createWeak(this) : nullptr;
 }
 
 template<typename T>
@@ -595,6 +630,7 @@
 {
     if (m_ptr) {
         m_refs->decWeak(this);
+        m_refs = 0;
         m_ptr = 0;
     }
 }
diff --git a/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h
index 1571129..9cd7c75 100644
--- a/libutils/include/utils/StrongPointer.h
+++ b/libutils/include/utils/StrongPointer.h
@@ -17,6 +17,9 @@
 #ifndef ANDROID_STRONG_POINTER_H
 #define ANDROID_STRONG_POINTER_H
 
+#include <functional>
+#include <type_traits>  // for common_type.
+
 // ---------------------------------------------------------------------------
 namespace android {
 
@@ -24,13 +27,12 @@
 
 // ---------------------------------------------------------------------------
 
-#define COMPARE(_op_)                                           \
-inline bool operator _op_ (const sp<T>& o) const {              \
-    return m_ptr _op_ o.m_ptr;                                  \
-}                                                               \
-inline bool operator _op_ (const T* o) const {                  \
-    return m_ptr _op_ o;                                        \
-}                                                               \
+// TODO: Maybe remove sp<> ? wp<> comparison? These are dangerous: If the wp<>
+// was created before the sp<>, and they point to different objects, they may
+// compare equal even if they are entirely unrelated. E.g. CameraService
+// currently performa such comparisons.
+
+#define COMPARE_STRONG(_op_)                                           \
 template<typename U>                                            \
 inline bool operator _op_ (const sp<U>& o) const {              \
     return m_ptr _op_ o.m_ptr;                                  \
@@ -39,14 +41,27 @@
 inline bool operator _op_ (const U* o) const {                  \
     return m_ptr _op_ o;                                        \
 }                                                               \
-inline bool operator _op_ (const wp<T>& o) const {              \
-    return m_ptr _op_ o.m_ptr;                                  \
-}                                                               \
-template<typename U>                                            \
-inline bool operator _op_ (const wp<U>& o) const {              \
-    return m_ptr _op_ o.m_ptr;                                  \
+/* Needed to handle type inference for nullptr: */              \
+inline bool operator _op_ (const T* o) const {                  \
+    return m_ptr _op_ o;                                        \
 }
 
+template<template<typename C> class comparator, typename T, typename U>
+static inline bool _sp_compare_(T* a, U* b) {
+    return comparator<typename std::common_type<T*, U*>::type>()(a, b);
+}
+
+// Use std::less and friends to avoid undefined behavior when ordering pointers
+// to different objects.
+#define COMPARE_STRONG_FUNCTIONAL(_op_, _compare_)               \
+template<typename U>                                             \
+inline bool operator _op_ (const sp<U>& o) const {               \
+    return _sp_compare_<_compare_>(m_ptr, o.m_ptr);              \
+}                                                                \
+template<typename U>                                             \
+inline bool operator _op_ (const U* o) const {                   \
+    return _sp_compare_<_compare_>(m_ptr, o);                    \
+}
 // ---------------------------------------------------------------------------
 
 template<typename T>
@@ -89,12 +104,23 @@
 
     // Operators
 
-    COMPARE(==)
-    COMPARE(!=)
-    COMPARE(>)
-    COMPARE(<)
-    COMPARE(<=)
-    COMPARE(>=)
+    COMPARE_STRONG(==)
+    COMPARE_STRONG(!=)
+    COMPARE_STRONG_FUNCTIONAL(>, std::greater)
+    COMPARE_STRONG_FUNCTIONAL(<, std::less)
+    COMPARE_STRONG_FUNCTIONAL(<=, std::less_equal)
+    COMPARE_STRONG_FUNCTIONAL(>=, std::greater_equal)
+
+    // Punt these to the wp<> implementation.
+    template<typename U>
+    inline bool operator == (const wp<U>& o) const {
+        return o == *this;
+    }
+
+    template<typename U>
+    inline bool operator != (const wp<U>& o) const {
+        return o != *this;
+    }
 
 private:    
     template<typename Y> friend class sp;
diff --git a/libvndksupport/linker.c b/libvndksupport/linker.c
index 821940a..84c2132 100644
--- a/libvndksupport/linker.c
+++ b/libvndksupport/linker.c
@@ -20,6 +20,8 @@
 
 #define LOG_TAG "vndksupport"
 #include <log/log.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 __attribute__((weak)) extern struct android_namespace_t* android_get_exported_namespace(const char*);
 __attribute__((weak)) extern void* android_dlopen_ext(const char*, int, const android_dlextinfo*);
@@ -46,6 +48,11 @@
 }
 
 int android_is_in_vendor_process() {
+    // Special case init, since when init runs, ld.config.<ver>.txt hasn't been
+    // loaded (sysprop service isn't up for init to know <ver>).
+    if (getpid() == 1) {
+        return 0;
+    }
     if (android_get_exported_namespace == NULL) {
         ALOGD("android_get_exported_namespace() not available. Assuming system process.");
         return 0;
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 9538bba..bc1543b 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -38,6 +38,19 @@
             ],
         },
     },
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+            "shift",
+            "integer-divide-by-zero",
+            "implicit-signed-integer-truncation",
+            // TODO: Fix crash when we enable this option
+            // "implicit-unsigned-integer-truncation",
+            // TODO: not tested yet.
+            // "implicit-integer-sign-change",
+        ],
+    },
 }
 
 cc_defaults {
diff --git a/libziparchive/entry_name_utils-inl.h b/libziparchive/entry_name_utils-inl.h
index 5fc2fb4..1714586 100644
--- a/libziparchive/entry_name_utils-inl.h
+++ b/libziparchive/entry_name_utils-inl.h
@@ -35,7 +35,7 @@
       return false;
     } else {
       // 2-5 byte sequences.
-      for (uint8_t first = byte << 1; first & 0x80; first <<= 1) {
+      for (uint8_t first = (byte & 0x7f) << 1; first & 0x80; first = (first & 0x7f) << 1) {
         ++i;
 
         // Missing continuation byte..
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 6b9f6e1..0710d0a 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -278,11 +278,6 @@
   if (static_cast<off64_t>(eocd->cd_start_offset) + eocd->cd_size > eocd_offset) {
     ALOGW("Zip: bad offsets (dir %" PRIu32 ", size %" PRIu32 ", eocd %" PRId64 ")",
           eocd->cd_start_offset, eocd->cd_size, static_cast<int64_t>(eocd_offset));
-#if defined(__ANDROID__)
-    if (eocd->cd_start_offset + eocd->cd_size <= eocd_offset) {
-      android_errorWriteLog(0x534e4554, "31251826");
-    }
-#endif
     return kInvalidOffset;
   }
   if (eocd->num_records == 0) {
diff --git a/libziparchive/zip_writer.cc b/libziparchive/zip_writer.cc
index 981df3a..0df0fa5 100644
--- a/libziparchive/zip_writer.cc
+++ b/libziparchive/zip_writer.cc
@@ -30,9 +30,13 @@
 #include "entry_name_utils-inl.h"
 #include "zip_archive_common.h"
 
-#if !defined(powerof2)
-#define powerof2(x) ((((x)-1) & (x)) == 0)
-#endif
+#undef powerof2
+#define powerof2(x)                                               \
+  ({                                                              \
+    __typeof__(x) _x = (x);                                       \
+    __typeof__(x) _x2;                                            \
+    __builtin_add_overflow(_x, -1, &_x2) ? 1 : ((_x2 & _x) == 0); \
+  })
 
 /* Zip compression methods we support */
 enum {
diff --git a/lmkd/event.logtags b/lmkd/event.logtags
index 7c2cd18..065c6db 100644
--- a/lmkd/event.logtags
+++ b/lmkd/event.logtags
@@ -35,4 +35,4 @@
 # TODO: generate ".java" and ".h" files with integer constants from this file.
 
 # for meminfo logs
-10195355 meminfo (MemFree|1),(Cached|1),(SwapCached|1),(Buffers|1),(Shmem|1),(Unevictable|1),(SwapFree|1),(ActiveAnon|1),(InactiveAnon|1),(ActiveFile|1),(InactiveFile|1),(SReclaimable|1),(SUnreclaim|1),(KernelStack|1),(PageTables|1),(ION_heap|1),(ION_heap_pool|1),(CmaFree|1)
+10195355 meminfo (MemFree|1),(Cached|1),(SwapCached|1),(Buffers|1),(Shmem|1),(Unevictable|1),(SwapTotal|1),(SwapFree|1),(ActiveAnon|1),(InactiveAnon|1),(ActiveFile|1),(InactiveFile|1),(SReclaimable|1),(SUnreclaim|1),(KernelStack|1),(PageTables|1),(ION_heap|1),(ION_heap_pool|1),(CmaFree|1)
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 18421e8..2de7378 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -110,7 +110,7 @@
  */
 #define PSI_WINDOW_SIZE_MS 1000
 /* Polling period after initial PSI signal */
-#define PSI_POLL_PERIOD_MS 200
+#define PSI_POLL_PERIOD_MS 10
 /* Poll for the duration of one window after initial PSI signal */
 #define PSI_POLL_COUNT (PSI_WINDOW_SIZE_MS / PSI_POLL_PERIOD_MS)
 
diff --git a/logcat/event.logtags b/logcat/event.logtags
index da8d2d4..3a1d36f 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -116,8 +116,8 @@
 # audio
 # 61000 - 61199 reserved for audioserver
 
-# 0 for screen off, 1 for screen on, 2 for key-guard done
-70000 screen_toggled (screen_state|1|5)
+# com.android.server.policy
+# 70000 - 70199 reserved for PhoneWindowManager and other policies
 
 # aggregation service
 70200 aggregation (aggregation time|2|3)
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index d5c40be..b32b437 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -33,6 +33,7 @@
 #include <android-base/file.h>
 #include <android-base/macros.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <gtest/gtest.h>
 #include <log/event_tag_map.h>
 #include <log/log.h>
@@ -1747,3 +1748,13 @@
     EXPECT_EQ(logcatHelpTextSize * 2, logcatLastHelpTextSize);
 #endif
 }
+
+TEST(logcat, invalid_buffer) {
+  FILE* fp = popen("logcat -b foo 2>&1", "r");
+  ASSERT_NE(nullptr, fp);
+  std::string output;
+  ASSERT_TRUE(android::base::ReadFdToString(fileno(fp), &output));
+  pclose(fp);
+
+  ASSERT_TRUE(android::base::StartsWith(output, "unknown buffer foo\n"));
+}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index d2125d8..5d307b8 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -8,6 +8,7 @@
 LOCAL_SRC_FILES := $(LOCAL_MODULE)
 LOCAL_MODULE_CLASS := ETC
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
+LOCAL_REQUIRED_MODULES := fsverity_init
 
 # The init symlink must be a post install command of a file that is to TARGET_ROOT_OUT.
 # Since init.rc is required for init and satisfies that requirement, we hijack it to create the symlink.
@@ -24,44 +25,6 @@
 LOCAL_MODULE_CLASS := ETC
 LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/init
 
-# Start of runtime APEX compatibility.
-#
-# Meta-comment:
-# The placing of this section is somewhat arbitrary. The LOCAL_POST_INSTALL_CMD
-# entries need to be associated with something that goes into /system.
-# init-debug.rc qualifies but it could be anything else in /system until soong
-# supports creation of symlinks. http://b/123333111
-#
-# Keeping the appearance of files/dirs having old locations for apps that have
-# come to rely on them.
-
-# http://b/121248172 - create a link from /system/usr/icu to
-# /apex/com.android.runtime/etc/icu so that apps can find the ICU .dat file.
-# A symlink can't overwrite a directory and the /system/usr/icu directory once
-# existed so the required structure must be created whatever we find.
-LOCAL_POST_INSTALL_CMD = mkdir -p $(TARGET_OUT)/usr && rm -rf $(TARGET_OUT)/usr/icu
-LOCAL_POST_INSTALL_CMD += ; ln -sf /apex/com.android.runtime/etc/icu $(TARGET_OUT)/usr/icu
-
-# TODO(b/124106384): Clean up compat symlinks for ART binaries.
-ART_BINARIES= \
-  dalvikvm \
-  dalvikvm32 \
-  dalvikvm64 \
-  dex2oat \
-  dexdiag \
-  dexdump \
-  dexlist \
-  dexoptanalyzer \
-  oatdump \
-  profman \
-
-$(foreach b,$(ART_BINARIES), \
-  $(eval LOCAL_POST_INSTALL_CMD += \
-    ; ln -sf /apex/com.android.runtime/bin/$(b) $(TARGET_OUT)/bin/$(b)) \
-)
-
-# End of runtime APEX compatibilty.
-
 include $(BUILD_PREBUILT)
 
 #######################################
@@ -95,6 +58,15 @@
 endif
 
 #######################################
+# fsverity_init
+
+include $(CLEAR_VARS)
+LOCAL_MODULE:= fsverity_init
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_SRC_FILES := fsverity_init.sh
+include $(BUILD_PREBUILT)
+
+#######################################
 # init.environ.rc
 
 include $(CLEAR_VARS)
@@ -242,6 +214,45 @@
 LOCAL_MODULE_CLASS := ETC
 LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
 
+# Start of runtime APEX compatibility.
+#
+# Meta-comment:
+# The placing of this section is somewhat arbitrary. The LOCAL_POST_INSTALL_CMD
+# entries need to be associated with something that goes into /system.
+# ld.config.txt qualifies but it could be anything else in /system until soong
+# supports creation of symlinks. http://b/123333111
+#
+# Keeping the appearance of files/dirs having old locations for apps that have
+# come to rely on them.
+
+# http://b/121248172 - create a link from /system/usr/icu to
+# /apex/com.android.runtime/etc/icu so that apps can find the ICU .dat file.
+# A symlink can't overwrite a directory and the /system/usr/icu directory once
+# existed so the required structure must be created whatever we find.
+LOCAL_POST_INSTALL_CMD = mkdir -p $(TARGET_OUT)/usr && rm -rf $(TARGET_OUT)/usr/icu
+LOCAL_POST_INSTALL_CMD += && ln -sf /apex/com.android.runtime/etc/icu $(TARGET_OUT)/usr/icu
+
+# TODO(b/124106384): Clean up compat symlinks for ART binaries.
+ART_BINARIES := \
+  dalvikvm \
+  dalvikvm32 \
+  dalvikvm64 \
+  dex2oat \
+  dexdiag \
+  dexdump \
+  dexlist \
+  dexoptanalyzer \
+  oatdump \
+  profman \
+
+LOCAL_POST_INSTALL_CMD += && mkdir -p $(TARGET_OUT)/bin
+$(foreach b,$(ART_BINARIES), \
+  $(eval LOCAL_POST_INSTALL_CMD += \
+    && ln -sf /apex/com.android.runtime/bin/$(b) $(TARGET_OUT)/bin/$(b)) \
+)
+
+# End of runtime APEX compatibilty.
+
 ifeq ($(_enforce_vndk_at_runtime),true)
 
 # for VNDK enforced devices
@@ -365,3 +376,5 @@
 	$(hide) echo -n > $@
 	$(hide) $(foreach lib,$(PRIVATE_VNDK_SAMEPROCESS_LIBRARIES), \
 		echo $(lib).so >> $@;)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/rootdir/avb/Android.mk b/rootdir/avb/Android.mk
new file mode 100644
index 0000000..5dc019c
--- /dev/null
+++ b/rootdir/avb/Android.mk
@@ -0,0 +1,46 @@
+LOCAL_PATH:= $(call my-dir)
+
+#######################################
+# q-gsi.avbpubkey
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := q-gsi.avbpubkey
+LOCAL_MODULE_CLASS := ETC
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/first_stage_ramdisk/avb
+else
+LOCAL_MODULE_PATH := $(TARGET_RAMDISK_OUT)/avb
+endif
+
+include $(BUILD_PREBUILT)
+
+#######################################
+# r-gsi.avbpubkey
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := r-gsi.avbpubkey
+LOCAL_MODULE_CLASS := ETC
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/first_stage_ramdisk/avb
+else
+LOCAL_MODULE_PATH := $(TARGET_RAMDISK_OUT)/avb
+endif
+
+include $(BUILD_PREBUILT)
+
+#######################################
+# s-gsi.avbpubkey
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := s-gsi.avbpubkey
+LOCAL_MODULE_CLASS := ETC
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/first_stage_ramdisk/avb
+else
+LOCAL_MODULE_PATH := $(TARGET_RAMDISK_OUT)/avb
+endif
+
+include $(BUILD_PREBUILT)
diff --git a/rootdir/avb/q-gsi.avbpubkey b/rootdir/avb/q-gsi.avbpubkey
new file mode 100644
index 0000000..5ed7543
--- /dev/null
+++ b/rootdir/avb/q-gsi.avbpubkey
Binary files differ
diff --git a/rootdir/avb/r-gsi.avbpubkey b/rootdir/avb/r-gsi.avbpubkey
new file mode 100644
index 0000000..2609b30
--- /dev/null
+++ b/rootdir/avb/r-gsi.avbpubkey
Binary files differ
diff --git a/rootdir/avb/s-gsi.avbpubkey b/rootdir/avb/s-gsi.avbpubkey
new file mode 100644
index 0000000..9065fb8
--- /dev/null
+++ b/rootdir/avb/s-gsi.avbpubkey
Binary files differ
diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt
index d4d5c28..0fccd31 100644
--- a/rootdir/etc/ld.config.legacy.txt
+++ b/rootdir/etc/ld.config.legacy.txt
@@ -14,6 +14,10 @@
 # Except for /postinstall, where only /system and /product are searched
 dir.postinstall = /postinstall
 
+# Fallback entry to provide APEX namespace lookups for binaries anywhere else.
+# This must be last.
+dir.legacy = /data
+
 [legacy]
 namespace.default.isolated = false
 
@@ -49,8 +53,7 @@
 # Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
 # libart.
 namespace.default.visible = true
-namespace.default.link.runtime.shared_libs  = libart.so:libartd.so
-namespace.default.link.runtime.shared_libs += libdexfile_external.so
+namespace.default.link.runtime.shared_libs  = libdexfile_external.so
 namespace.default.link.runtime.shared_libs += libnativebridge.so
 namespace.default.link.runtime.shared_libs += libnativehelper.so
 namespace.default.link.runtime.shared_libs += libnativeloader.so
@@ -94,7 +97,21 @@
 namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors
 
 namespace.media.links = default
-namespace.media.link.default.allow_all_shared_libs = true
+namespace.media.link.default.shared_libs  = libandroid.so
+namespace.media.link.default.shared_libs += libbinder_ndk.so
+namespace.media.link.default.shared_libs += libc.so
+namespace.media.link.default.shared_libs += libdl.so
+namespace.media.link.default.shared_libs += liblog.so
+namespace.media.link.default.shared_libs += libmediametrics.so
+namespace.media.link.default.shared_libs += libmediandk.so
+namespace.media.link.default.shared_libs += libm.so
+namespace.media.link.default.shared_libs += libvndksupport.so
+
+namespace.media.link.default.shared_libs += libclang_rt.asan-aarch64-android.so
+namespace.media.link.default.shared_libs += libclang_rt.asan-arm-android.so
+namespace.media.link.default.shared_libs += libclang_rt.asan-i686-android.so
+namespace.media.link.default.shared_libs += libclang_rt.asan-x86_64-android.so
+namespace.media.link.default.shared_libs += libclang_rt.hwasan-aarch64-android.so
 
 ###############################################################################
 # "conscrypt" APEX namespace
@@ -108,7 +125,7 @@
 namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.links = runtime,default
-namespace.conscrypt.link.runtime.shared_libs  = libjavacore.so
+namespace.conscrypt.link.runtime.shared_libs  = libandroidio.so
 namespace.conscrypt.link.default.shared_libs  = libc.so
 namespace.conscrypt.link.default.shared_libs += libm.so
 namespace.conscrypt.link.default.shared_libs += libdl.so
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 552d685..2b0ef4c 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -27,13 +27,12 @@
 # necessary) the unrestricted subdirs above. Then clean this up.
 dir.unrestricted = /data/local/tmp
 
-dir.system = /data/nativetest
-dir.system = /data/nativetest64
-dir.system = /data/benchmarktest
-dir.system = /data/benchmarktest64
-
 dir.postinstall = /postinstall
 
+# Fallback entry to provide APEX namespace lookups for binaries anywhere else.
+# This must be last.
+dir.system = /data
+
 [system]
 additional.namespaces = runtime,conscrypt,media,resolv,sphal,vndk,rs
 
@@ -83,7 +82,7 @@
 namespace.default.permitted.paths += /%PRODUCT_SERVICES%/priv-app
 namespace.default.permitted.paths += /data
 namespace.default.permitted.paths += /mnt/expand
-namespace.default.permitted.paths += /bionic/${LIB}
+namespace.default.permitted.paths += /apex/com.android.runtime/${LIB}/bionic
 namespace.default.permitted.paths += /system/${LIB}/bootstrap
 
 namespace.default.asan.search.paths  = /data/asan/system/${LIB}
@@ -119,7 +118,7 @@
 namespace.default.asan.permitted.paths += /%PRODUCT_SERVICES%/app
 namespace.default.asan.permitted.paths += /%PRODUCT_SERVICES%/priv-app
 namespace.default.asan.permitted.paths += /mnt/expand
-namespace.default.asan.permitted.paths += /bionic/${LIB}
+namespace.default.asan.permitted.paths += /apex/com.android.runtime/${LIB}/bionic
 namespace.default.asan.permitted.paths += /system/${LIB}/bootstrap
 
 # Keep in sync with ld.config.txt in the com.android.runtime APEX.
@@ -133,8 +132,7 @@
 # Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
 # libart.
 namespace.default.visible = true
-namespace.default.link.runtime.shared_libs  = libart.so:libartd.so
-namespace.default.link.runtime.shared_libs += libdexfile_external.so
+namespace.default.link.runtime.shared_libs  = libdexfile_external.so
 namespace.default.link.runtime.shared_libs += libnativebridge.so
 namespace.default.link.runtime.shared_libs += libnativehelper.so
 namespace.default.link.runtime.shared_libs += libnativeloader.so
@@ -196,7 +194,7 @@
 namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.links = runtime,default
-namespace.conscrypt.link.runtime.shared_libs  = libjavacore.so
+namespace.conscrypt.link.runtime.shared_libs  = libandroidio.so
 namespace.conscrypt.link.default.shared_libs  = libc.so
 namespace.conscrypt.link.default.shared_libs += libm.so
 namespace.conscrypt.link.default.shared_libs += libdl.so
@@ -377,7 +375,7 @@
 # (LL-NDK only) access.
 ###############################################################################
 [vendor]
-additional.namespaces = runtime,system,vndk
+additional.namespaces = runtime,system,vndk%VNDK_IN_SYSTEM_NS%
 
 ###############################################################################
 # "default" namespace
@@ -418,8 +416,9 @@
 namespace.default.asan.permitted.paths += /data/asan/vendor
 namespace.default.asan.permitted.paths +=           /vendor
 
-namespace.default.links = system,vndk
+namespace.default.links = system,vndk%VNDK_IN_SYSTEM_NS%
 namespace.default.link.system.shared_libs = %LLNDK_LIBRARIES%
+namespace.default.link.vndk_in_system.shared_libs = %VNDK_USING_CORE_VARIANT_LIBRARIES%
 namespace.default.link.vndk.shared_libs  = %VNDK_SAMEPROCESS_LIBRARIES%
 namespace.default.link.vndk.shared_libs += %VNDK_CORE_LIBRARIES%
 
@@ -468,14 +467,18 @@
 
 # When these NDK libs are required inside this namespace, then it is redirected
 # to the system namespace. This is possible since their ABI is stable across
-# Android releases.
-namespace.vndk.links = system,default
+# Android releases.  The links here should be identical to that of the
+# 'vndk_in_system' namespace, except for the link between 'vndk' and
+# 'vndk_in_system'.
+namespace.vndk.links = system,default%VNDK_IN_SYSTEM_NS%
 
 namespace.vndk.link.system.shared_libs  = %LLNDK_LIBRARIES%
 namespace.vndk.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
 
 namespace.vndk.link.default.allow_all_shared_libs = true
 
+namespace.vndk.link.vndk_in_system.shared_libs = %VNDK_USING_CORE_VARIANT_LIBRARIES%
+
 ###############################################################################
 # "system" namespace
 #
@@ -504,6 +507,51 @@
 namespace.system.link.runtime.shared_libs += libandroidicu.so
 
 ###############################################################################
+# "vndk_in_system" namespace
+#
+# This namespace is where no-vendor-variant VNDK libraries are loaded for a
+# vendor process.  Note that we do not simply export these libraries from
+# "system" namespace, because in some case both the core variant and the
+# vendor variant of a VNDK library may be loaded.  In such case, we do not
+# want to eliminate double-loading because doing so means the global states
+# of the library would be shared.
+#
+# Only the no-vendor-variant VNDK libraries are whitelisted in this namespace.
+# This is to ensure that we do not load libraries needed by no-vendor-variant
+# VNDK libraries into vndk_in_system namespace.
+###############################################################################
+namespace.vndk_in_system.isolated = true
+namespace.vndk_in_system.visible = true
+
+# The search paths here should be kept the same as that of the 'system'
+# namespace.
+namespace.vndk_in_system.search.paths  = /system/${LIB}
+namespace.vndk_in_system.search.paths += /%PRODUCT%/${LIB}
+namespace.vndk_in_system.search.paths += /%PRODUCT_SERVICES%/${LIB}
+
+namespace.vndk_in_system.asan.search.paths  = /data/asan/system/${LIB}
+namespace.vndk_in_system.asan.search.paths +=           /system/${LIB}
+namespace.vndk_in_system.asan.search.paths += /data/asan/product/${LIB}
+namespace.vndk_in_system.asan.search.paths +=           /%PRODUCT%/${LIB}
+namespace.vndk_in_system.asan.search.paths += /data/asan/product_services/${LIB}
+namespace.vndk_in_system.asan.search.paths +=           /%PRODUCT_SERVICES%/${LIB}
+
+namespace.vndk_in_system.whitelisted = %VNDK_USING_CORE_VARIANT_LIBRARIES%
+
+# The links here should be identical to that of the 'vndk' namespace, with the
+# following exception:
+#   1. 'vndk_in_system' needs to be freely linked back to 'vndk'.
+#   2. 'vndk_in_system' does not need to link to 'default', as any library that
+#      requires anything vendor would not be a vndk_in_system library.
+namespace.vndk_in_system.links = vndk,system
+
+namespace.vndk_in_system.link.system.shared_libs  = %LLNDK_LIBRARIES%
+namespace.vndk_in_system.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+
+namespace.vndk_in_system.link.vndk.allow_all_shared_libs = true
+
+
+###############################################################################
 # Namespace config for native tests that need access to both system and vendor
 # libraries. This replicates the default linker config (done by
 # init_default_namespace_no_config in bionic/linker/linker.cpp), except that it
@@ -527,8 +575,7 @@
 namespace.default.links = runtime,resolv
 namespace.default.visible = true
 
-namespace.default.link.runtime.shared_libs  = libart.so:libartd.so
-namespace.default.link.runtime.shared_libs += libdexfile_external.so
+namespace.default.link.runtime.shared_libs  = libdexfile_external.so
 namespace.default.link.runtime.shared_libs += libnativebridge.so
 namespace.default.link.runtime.shared_libs += libnativehelper.so
 namespace.default.link.runtime.shared_libs += libnativeloader.so
@@ -587,7 +634,7 @@
 namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.links = runtime,default
-namespace.conscrypt.link.runtime.shared_libs  = libjavacore.so
+namespace.conscrypt.link.runtime.shared_libs  = libandroidio.so
 namespace.conscrypt.link.default.shared_libs  = libc.so
 namespace.conscrypt.link.default.shared_libs += libm.so
 namespace.conscrypt.link.default.shared_libs += libdl.so
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index beb6125..c8312df 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -27,13 +27,12 @@
 # necessary) the unrestricted subdirs above. Then clean this up.
 dir.unrestricted = /data/local/tmp
 
-dir.system = /data/nativetest
-dir.system = /data/nativetest64
-dir.system = /data/benchmarktest
-dir.system = /data/benchmarktest64
-
 dir.postinstall = /postinstall
 
+# Fallback entry to provide APEX namespace lookups for binaries anywhere else.
+# This must be last.
+dir.system = /data
+
 [system]
 additional.namespaces = runtime,conscrypt,media,resolv,sphal,vndk,rs
 
@@ -74,8 +73,7 @@
 # Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
 # libart.
 namespace.default.visible = true
-namespace.default.link.runtime.shared_libs  = libart.so:libartd.so
-namespace.default.link.runtime.shared_libs += libdexfile_external.so
+namespace.default.link.runtime.shared_libs  = libdexfile_external.so
 namespace.default.link.runtime.shared_libs += libnativebridge.so
 namespace.default.link.runtime.shared_libs += libnativehelper.so
 namespace.default.link.runtime.shared_libs += libnativeloader.so
@@ -138,7 +136,7 @@
 namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.links = runtime,default
-namespace.conscrypt.link.runtime.shared_libs  = libjavacore.so
+namespace.conscrypt.link.runtime.shared_libs  = libandroidio.so
 namespace.conscrypt.link.default.shared_libs  = libc.so
 namespace.conscrypt.link.default.shared_libs += libm.so
 namespace.conscrypt.link.default.shared_libs += libdl.so
@@ -400,8 +398,7 @@
 namespace.default.links = runtime,resolv
 namespace.default.visible = true
 
-namespace.default.link.runtime.shared_libs  = libart.so:libartd.so
-namespace.default.link.runtime.shared_libs += libdexfile_external.so
+namespace.default.link.runtime.shared_libs  = libdexfile_external.so
 namespace.default.link.runtime.shared_libs += libnativebridge.so
 namespace.default.link.runtime.shared_libs += libnativehelper.so
 namespace.default.link.runtime.shared_libs += libnativeloader.so
@@ -460,7 +457,7 @@
 namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.links = runtime,default
-namespace.conscrypt.link.runtime.shared_libs  = libjavacore.so
+namespace.conscrypt.link.runtime.shared_libs  = libandroidio.so
 namespace.conscrypt.link.default.shared_libs  = libc.so
 namespace.conscrypt.link.default.shared_libs += libm.so
 namespace.conscrypt.link.default.shared_libs += libdl.so
diff --git a/rootdir/fsverity_init.sh b/rootdir/fsverity_init.sh
new file mode 100644
index 0000000..29e4519
--- /dev/null
+++ b/rootdir/fsverity_init.sh
@@ -0,0 +1,29 @@
+#!/system/bin/sh
+#
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Enforce fsverity signature checking
+echo 1 > /proc/sys/fs/verity/require_signatures
+
+# Load all keys
+for cert in /product/etc/security/fsverity/*.der; do
+  /system/bin/mini-keyctl padd asymmetric fsv_product .fs-verity < "$cert" ||
+    log -p e -t fsverity_init "Failed to load $cert"
+done
+
+# Prevent future key links to .fs-verity keyring
+/system/bin/mini-keyctl restrict_keyring .fs-verity ||
+  log -p e -t fsverity_init "Failed to restrict .fs-verity keyring"
diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in
index 5d6cd2d..455c9a8 100644
--- a/rootdir/init.environ.rc.in
+++ b/rootdir/init.environ.rc.in
@@ -6,6 +6,7 @@
     export ANDROID_DATA /data
     export ANDROID_STORAGE /storage
     export ANDROID_RUNTIME_ROOT /apex/com.android.runtime
+    export ANDROID_TZDATA_ROOT /apex/com.android.tzdata
     export EXTERNAL_STORAGE /sdcard
     export ASEC_MOUNTPOINT /mnt/asec
     export BOOTCLASSPATH %BOOTCLASSPATH%
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 478f744..473cd8d 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -222,6 +222,9 @@
     chmod 0664 /dev/cpuset/restricted/tasks
     chmod 0664 /dev/cpuset/tasks
 
+    # make the PSI monitor accessible to others
+    chown system system /proc/pressure/memory
+    chmod 0664 /proc/pressure/memory
 
     # qtaguid will limit access to specific data based on group memberships.
     #   net_bw_acct grants impersonation of socket owners.
@@ -389,6 +392,8 @@
     chmod 0700 /metadata/vold
     mkdir /metadata/password_slots 0771 root system
 
+    mkdir /metadata/apex 0700 root system
+    mkdir /metadata/apex/sessions 0700 root system
 on late-fs
     # Ensure that tracefs has the correct permissions.
     # This does not work correctly if it is called in post-fs.
@@ -416,6 +421,10 @@
     mkdir /data/bootchart 0755 shell shell
     bootchart start
 
+    # Load fsverity keys. This needs to happen before apexd, as post-install of
+    # APEXes may rely on keys.
+    exec -- /system/bin/fsverity_init
+
     # Make sure that apexd is started in the default namespace
     enter_default_mount_ns
 
@@ -424,7 +433,7 @@
     mkdir /data/apex/active 0750 root system
     mkdir /data/apex/backup 0700 root system
     mkdir /data/apex/sessions 0700 root system
-    mkdir /data/pkg_staging 0750 system system
+    mkdir /data/app-staging 0750 system system
     start apexd
 
     # Avoid predictable entropy pool. Carry over entropy from previous boot.
@@ -576,8 +585,6 @@
 
     # Wait for apexd to finish activating APEXes before starting more processes.
     wait_for_prop apexd.status ready
-    # TODO(jiyong): remove setup_runtime_bionic
-    setup_runtime_bionic
     parse_apex_configs
 
     init_user0
@@ -585,9 +592,6 @@
     # Set SELinux security contexts on upgrade or policy update.
     restorecon --recursive --skip-ce /data
 
-    # load fsverity keys
-    exec -- /system/bin/mini-keyctl -c /product/etc/security/cacerts_fsverity,/vendor/etc/security/cacerts_fsverity -k .fs-verity
-
     # Check any timezone data in /data is newer than the copy in the runtime module, delete if not.
     exec - system system -- /system/bin/tzdatacheck /apex/com.android.runtime/etc/tz /data/misc/zoneinfo
 
diff --git a/rootdir/update_and_install_ld_config.mk b/rootdir/update_and_install_ld_config.mk
index 852e234..f62c3df 100644
--- a/rootdir/update_and_install_ld_config.mk
+++ b/rootdir/update_and_install_ld_config.mk
@@ -23,6 +23,11 @@
 lib_list_from_prebuilts := $(strip $(lib_list_from_prebuilts))
 libz_is_llndk := $(strip $(libz_is_llndk))
 
+my_vndk_use_core_variant := $(TARGET_VNDK_USE_CORE_VARIANT)
+ifeq ($(lib_list_from_prebuilts),true)
+my_vndk_use_core_variant := false
+endif
+
 compatibility_check_script := \
   $(LOCAL_PATH)/ld_config_backward_compatibility_check.py
 intermediates_dir := $(call intermediates-dir-for,ETC,$(LOCAL_MODULE))
@@ -35,6 +40,9 @@
 vndksp_libraries_file := $(library_lists_dir)/vndksp.libraries.$(vndk_version).txt
 vndkcore_libraries_file := $(library_lists_dir)/vndkcore.libraries.txt
 vndkprivate_libraries_file := $(library_lists_dir)/vndkprivate.libraries.txt
+ifeq ($(my_vndk_use_core_variant),true)
+vndk_using_core_variant_libraries_file := $(library_lists_dir)/vndk_using_core_variant.libraries.$(vndk_version).txt
+endif
 
 sanitizer_runtime_libraries := $(call normalize-path-list,$(addsuffix .so,\
   $(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
@@ -68,6 +76,9 @@
 $(eval $(call write-libs-to-file,$(vndksp_libraries_list),$(vndksp_libraries_file)))
 $(eval $(call write-libs-to-file,$(VNDK_CORE_LIBRARIES),$(vndkcore_libraries_file)))
 $(eval $(call write-libs-to-file,$(VNDK_PRIVATE_LIBRARIES),$(vndkprivate_libraries_file)))
+ifeq ($(my_vndk_use_core_variant),true)
+$(eval $(call write-libs-to-file,$(VNDK_USING_CORE_VARIANT_LIBRARIES),$(vndk_using_core_variant_libraries_file)))
+endif
 endif # ifneq ($(lib_list_from_prebuilts),true)
 
 # Given a file with a list of libs, filter-out the VNDK private libraries
@@ -94,6 +105,10 @@
 ifeq ($(check_backward_compatibility),true)
 deps += $(compatibility_check_script)
 endif
+ifeq ($(my_vndk_use_core_variant),true)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_USING_CORE_VARIANT_LIBRARIES_FILE := $(vndk_using_core_variant_libraries_file)
+deps += $(vndk_using_core_variant_libraries_file)
+endif
 
 $(LOCAL_BUILT_MODULE): $(ld_config_template) $(deps)
 	@echo "Generate: $< -> $@"
@@ -109,6 +124,20 @@
 	$(call private-filter-out-private-libs,$(PRIVATE_VNDK_CORE_LIBRARIES_FILE),$(PRIVATE_INTERMEDIATES_DIR)/vndkcore_filtered)
 	$(hide) sed -i.bak -e "s?%VNDK_CORE_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/vndkcore_filtered)?g" $@
 
+ifeq ($(my_vndk_use_core_variant),true)
+	$(call private-filter-out-private-libs,$(PRIVATE_VNDK_USING_CORE_VARIANT_LIBRARIES_FILE),$(PRIVATE_INTERMEDIATES_DIR)/vndk_using_core_variant_filtered)
+	$(hide) sed -i.bak -e "s?%VNDK_IN_SYSTEM_NS%?,vndk_in_system?g" $@
+	$(hide) sed -i.bak -e "s?%VNDK_USING_CORE_VARIANT_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/vndk_using_core_variant_filtered)?g" $@
+else
+	$(hide) sed -i.bak -e "s?%VNDK_IN_SYSTEM_NS%??g" $@
+	# Unlike LLNDK or VNDK-SP, VNDK_USING_CORE_VARIANT_LIBRARIES can be nothing
+	# if TARGET_VNDK_USE_CORE_VARIANT is not set.  In this case, we need to remove
+	# the entire line in the linker config so that we are not left with a line
+	# like:
+	#   namespace.vndk.link.vndk_in_system.shared_libs =
+	$(hide) sed -i.bak -e 's?^.*= %VNDK_USING_CORE_VARIANT_LIBRARIES%$$??' $@
+endif
+
 	$(hide) echo -n > $(PRIVATE_INTERMEDIATES_DIR)/private_llndk && \
 	cat $(PRIVATE_VNDK_PRIVATE_LIBRARIES_FILE) | \
 	xargs -n 1 -I privatelib bash -c "(grep privatelib $(PRIVATE_LLNDK_LIBRARIES_FILE) || true) >> $(PRIVATE_INTERMEDIATES_DIR)/private_llndk" && \
@@ -146,3 +175,10 @@
 llndk_libraries_list :=
 vndksp_libraries_list :=
 write-libs-to-file :=
+
+ifeq ($(my_vndk_use_core_variant),true)
+vndk_using_core_variant_libraries_file :=
+vndk_using_core_variant_libraries_list :=
+endif
+
+my_vndk_use_core_variant :=
diff --git a/run-as/run-as.cpp b/run-as/run-as.cpp
index 8752eef..432c434 100644
--- a/run-as/run-as.cpp
+++ b/run-as/run-as.cpp
@@ -70,32 +70,40 @@
   return true; // Keep searching.
 }
 
-static bool check_directory(const char* path, uid_t uid) {
+static void check_directory(const char* path, uid_t uid) {
   struct stat st;
-  if (TEMP_FAILURE_RETRY(lstat(path, &st)) == -1) return false;
+  if (TEMP_FAILURE_RETRY(lstat(path, &st)) == -1) {
+    error(1, errno, "couldn't stat %s", path);
+  }
 
   // /data/user/0 is a known safe symlink.
-  if (strcmp("/data/user/0", path) == 0) return true;
+  if (strcmp("/data/user/0", path) == 0) return;
 
   // Must be a real directory, not a symlink.
-  if (!S_ISDIR(st.st_mode)) return false;
+  if (!S_ISDIR(st.st_mode)) {
+    error(1, 0, "%s not a directory: %o", path, st.st_mode);
+  }
 
   // Must be owned by specific uid/gid.
-  if (st.st_uid != uid || st.st_gid != uid) return false;
+  if (st.st_uid != uid || st.st_gid != uid) {
+    error(1, 0, "%s has wrong owner: %d/%d, not %d", path, st.st_uid, st.st_gid, uid);
+  }
 
   // Must not be readable or writable by others.
-  if ((st.st_mode & (S_IROTH|S_IWOTH)) != 0) return false;
-
-  return true;
+  if ((st.st_mode & (S_IROTH | S_IWOTH)) != 0) {
+    error(1, 0, "%s readable or writable by others: %o", path, st.st_mode);
+  }
 }
 
 // This function is used to check the data directory path for safety.
 // We check that every sub-directory is owned by the 'system' user
 // and exists and is not a symlink. We also check that the full directory
 // path is properly owned by the user ID.
-static bool check_data_path(const char* data_path, uid_t uid) {
+static void check_data_path(const char* package_name, const char* data_path, uid_t uid) {
   // The path should be absolute.
-  if (data_path[0] != '/') return false;
+  if (data_path[0] != '/') {
+    error(1, 0, "%s data path not absolute: %s", package_name, data_path);
+  }
 
   // Look for all sub-paths, we do that by finding
   // directory separators in the input path and
@@ -110,26 +118,28 @@
     if (data_path[nn+1] == '\0') break;
 
     /* found a separator, check that data_path is not too long. */
-    if (nn >= (int)(sizeof subpath)) return false;
+    if (nn >= (int)(sizeof subpath)) {
+      error(1, 0, "%s data path too long: %s", package_name, data_path);
+    }
 
     /* reject any '..' subpath */
     if (nn >= 3               &&
         data_path[nn-3] == '/' &&
         data_path[nn-2] == '.' &&
         data_path[nn-1] == '.') {
-      return false;
+      error(1, 0, "%s contains '..': %s", package_name, data_path);
     }
 
     /* copy to 'subpath', then check ownership */
     memcpy(subpath, data_path, nn);
     subpath[nn] = '\0';
 
-    if (!check_directory(subpath, AID_SYSTEM)) return false;
+    check_directory(subpath, AID_SYSTEM);
   }
 
   // All sub-paths were checked, now verify that the full data
   // directory is owned by the application uid.
-  return check_directory(data_path, uid);
+  check_directory(data_path, uid);
 }
 
 std::vector<gid_t> get_supplementary_gids(uid_t userAppId) {
@@ -222,9 +232,7 @@
   }
 
   // Check that the data directory path is valid.
-  if (!check_data_path(info.data_dir, userAppId)) {
-    error(1, 0, "package has corrupt installation: %s", pkgname);
-  }
+  check_data_path(pkgname, info.data_dir, userAppId);
 
   // Ensure that we change all real/effective/saved IDs at the
   // same time to avoid nasty surprises.
diff --git a/toolbox/Android.bp b/toolbox/Android.bp
index 7ad6f1c..1f852ff 100644
--- a/toolbox/Android.bp
+++ b/toolbox/Android.bp
@@ -7,6 +7,8 @@
         "-Wno-unused-const-variable",
         "-D_FILE_OFFSET_BITS=64",
         "-DWITHOUT_NLS",
+        "-DWITHOUT_BZ2",
+        "-DWITHOUT_GZIP",
     ],
 }
 
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/file.c b/toolbox/upstream-netbsd/usr.bin/grep/file.c
index cf4a0fa..ef057ba 100644
--- a/toolbox/upstream-netbsd/usr.bin/grep/file.c
+++ b/toolbox/upstream-netbsd/usr.bin/grep/file.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: file.c,v 1.7 2011/04/18 22:46:48 joerg Exp $	*/
+/*	$NetBSD: file.c,v 1.10 2018/08/12 09:03:21 christos Exp $	*/
 /*	$FreeBSD: head/usr.bin/grep/file.c 211496 2010-08-19 09:28:59Z des $	*/
 /*	$OpenBSD: file.c,v 1.11 2010/07/02 20:48:48 nicm Exp $	*/
 
@@ -35,15 +35,12 @@
 #endif
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: file.c,v 1.7 2011/04/18 22:46:48 joerg Exp $");
+__RCSID("$NetBSD: file.c,v 1.10 2018/08/12 09:03:21 christos Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
-#ifndef __ANDROID__
-#include <bzlib.h>
-#endif
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -53,17 +50,16 @@
 #include <unistd.h>
 #include <wchar.h>
 #include <wctype.h>
-#ifndef __ANDROID__
-#include <zlib.h>
-#endif
 
 #include "grep.h"
 
 #define	MAXBUFSIZ	(32 * 1024)
 #define	LNBUFBUMP	80
 
-#ifndef __ANDROID__
+#ifndef WITHOUT_GZIP
 static gzFile gzbufdesc;
+#endif
+#ifndef WITHOUT_BZ2
 static BZFILE* bzbufdesc;
 #endif
 
@@ -77,18 +73,21 @@
 static inline int
 grep_refill(struct file *f)
 {
-	ssize_t nr;
-#ifndef __ANDROID__
+	ssize_t nr = -1;
 	int bzerr;
-#endif
 
 	bufpos = buffer;
 	bufrem = 0;
 
-#ifndef __ANDROID__
-	if (filebehave == FILE_GZIP)
+#ifndef WITHOUT_GZIP
+	if (filebehave == FILE_GZIP) {
 		nr = gzread(gzbufdesc, buffer, MAXBUFSIZ);
-	else if (filebehave == FILE_BZIP && bzbufdesc != NULL) {
+		if (nr == -1)
+			return -1;
+	}
+#endif
+#ifndef WITHOUT_BZ2
+	if (filebehave == FILE_BZIP && bzbufdesc != NULL) {
 		nr = BZ2_bzRead(&bzerr, bzbufdesc, buffer, MAXBUFSIZ);
 		switch (bzerr) {
 		case BZ_OK:
@@ -114,9 +113,13 @@
 			/* Make sure we exit with an error */
 			nr = -1;
 		}
-	} else
+		if (nr == -1)
+			return -1;
+	}
 #endif
+	if (nr == -1) {
 		nr = read(f->fd, buffer, MAXBUFSIZ);
+	}
 
 	if (nr < 0)
 		return (-1);
@@ -204,11 +207,13 @@
 grep_file_init(struct file *f)
 {
 
-#ifndef __ANDROID__
+#ifndef WITHOUT_GZIP
 	if (filebehave == FILE_GZIP &&
 	    (gzbufdesc = gzdopen(f->fd, "r")) == NULL)
 		goto error;
+#endif
 
+#ifndef WITHOUT_BZ2
 	if (filebehave == FILE_BZIP &&
 	    (bzbufdesc = BZ2_bzdopen(f->fd, "r")) == NULL)
 		goto error;
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/grep.c b/toolbox/upstream-netbsd/usr.bin/grep/grep.c
index 1ea6ed3..bad2a73 100644
--- a/toolbox/upstream-netbsd/usr.bin/grep/grep.c
+++ b/toolbox/upstream-netbsd/usr.bin/grep/grep.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: grep.c,v 1.12 2014/07/11 16:30:45 christos Exp $	*/
+/*	$NetBSD: grep.c,v 1.15 2018/08/12 09:03:21 christos Exp $	*/
 /* 	$FreeBSD: head/usr.bin/grep/grep.c 211519 2010-08-19 22:55:17Z delphij $	*/
 /*	$OpenBSD: grep.c,v 1.42 2010/07/02 22:18:03 tedu Exp $	*/
 
@@ -34,7 +34,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: grep.c,v 1.12 2014/07/11 16:30:45 christos Exp $");
+__RCSID("$NetBSD: grep.c,v 1.15 2018/08/12 09:03:21 christos Exp $");
 
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -170,7 +170,9 @@
 struct option long_options[] =
 {
 	{"binary-files",	required_argument,	NULL, BIN_OPT},
+#ifndef WITHOUT_GZIP
 	{"decompress",          no_argument,            NULL, DECOMPRESS_OPT},
+#endif
 	{"help",		no_argument,		NULL, HELP_OPT},
 	{"mmap",		no_argument,		NULL, MMAP_OPT},
 	{"line-buffered",	no_argument,		NULL, LINEBUF_OPT},
@@ -197,7 +199,9 @@
 	{"no-filename",		no_argument,		NULL, 'h'},
 	{"with-filename",	no_argument,		NULL, 'H'},
 	{"ignore-case",		no_argument,		NULL, 'i'},
+#ifndef WITHOUT_BZ2
 	{"bz2decompress",	no_argument,		NULL, 'J'},
+#endif
 	{"files-with-matches",	no_argument,		NULL, 'l'},
 	{"files-without-match", no_argument,            NULL, 'L'},
 	{"max-count",		required_argument,	NULL, 'm'},
@@ -338,6 +342,7 @@
 	case 'g':
 		grepbehave = GREP_BASIC;
 		break;
+#ifndef WITHOUT_GZIP
 	case 'z':
 		filebehave = FILE_GZIP;
 		switch(__progname[1]) {
@@ -352,6 +357,7 @@
 			break;
 		}
 		break;
+#endif
 	}
 
 	lastc = '\0';
@@ -491,9 +497,11 @@
 			iflag =  true;
 			cflags |= REG_ICASE;
 			break;
+#ifndef WITHOUT_BZ2
 		case 'J':
 			filebehave = FILE_BZIP;
 			break;
+#endif
 		case 'L':
 			lflag = false;
 			Lflag = true;
@@ -596,9 +604,11 @@
 			    strcasecmp("no", optarg) != 0)
 				errx(2, getstr(3), "--color");
 			break;
+#ifndef WITHOUT_GZIP
 		case DECOMPRESS_OPT:
 			filebehave = FILE_GZIP;
 			break;
+#endif
 		case LABEL_OPT:
 			label = optarg;
 			break;
@@ -679,8 +689,13 @@
 		}
 	}
 
-	if (lbflag)
+	if (lbflag) {
+#ifdef _IOLBF
+		setvbuf(stdout, NULL, _IOLBF, 0);
+#else
 		setlinebuf(stdout);
+#endif
+	}
 
 	if ((aargc == 0 || aargc == 1) && !Hflag)
 		hflag = true;
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/grep.h b/toolbox/upstream-netbsd/usr.bin/grep/grep.h
index fa2a3e3..b7ef7fa 100644
--- a/toolbox/upstream-netbsd/usr.bin/grep/grep.h
+++ b/toolbox/upstream-netbsd/usr.bin/grep/grep.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: grep.h,v 1.8 2012/05/06 22:27:00 joerg Exp $	*/
+/*	$NetBSD: grep.h,v 1.10 2018/08/12 09:03:21 christos Exp $	*/
 /*	$OpenBSD: grep.h,v 1.15 2010/04/05 03:03:55 tedu Exp $	*/
 /*	$FreeBSD: head/usr.bin/grep/grep.h 211496 2010-08-19 09:28:59Z des $	*/
 
@@ -29,14 +29,14 @@
  * SUCH DAMAGE.
  */
 
-#ifndef __ANDROID__
+#ifndef WITHOUT_BZ2
 #include <bzlib.h>
 #endif
 #include <limits.h>
 #include <regex.h>
 #include <stdbool.h>
 #include <stdio.h>
-#ifndef __ANDROID__
+#ifndef WITHOUT_GZIP
 #include <zlib.h>
 #endif
 
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/util.c b/toolbox/upstream-netbsd/usr.bin/grep/util.c
index ecd948d..a3c9e4c 100644
--- a/toolbox/upstream-netbsd/usr.bin/grep/util.c
+++ b/toolbox/upstream-netbsd/usr.bin/grep/util.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: util.c,v 1.17 2013/01/21 03:24:43 msaitoh Exp $	*/
+/*	$NetBSD: util.c,v 1.19 2018/02/05 22:14:26 mrg Exp $	*/
 /*	$FreeBSD: head/usr.bin/grep/util.c 211496 2010-08-19 09:28:59Z des $	*/
 /*	$OpenBSD: util.c,v 1.39 2010/07/02 22:18:03 tedu Exp $	*/
 
@@ -34,7 +34,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: util.c,v 1.17 2013/01/21 03:24:43 msaitoh Exp $");
+__RCSID("$NetBSD: util.c,v 1.19 2018/02/05 22:14:26 mrg Exp $");
 
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -478,9 +478,10 @@
 			if (color) 
 				fprintf(stdout, "\33[%sm\33[K", color);
 
-				fwrite(line->dat + matches[i].rm_so, 
-				    matches[i].rm_eo - matches[i].rm_so, 1,
-				    stdout);
+			fwrite(line->dat + matches[i].rm_so, 
+			    matches[i].rm_eo - matches[i].rm_so, 1,
+			    stdout);
+
 			if (color) 
 				fprintf(stdout, "\33[m\33[K");
 			a = matches[i].rm_eo;