[automerger skipped] Merge changes from topic "generic_by_name" into pi-dev
am: 34de3c84fe  -s ours

Change-Id: I4bbcfafd21370d14d796fff341d5bf83b91fff95
diff --git a/OWNERS b/OWNERS
index 682a067..1d319af 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1 +1,5 @@
 enh@google.com
+per-file libsysutils/src/Netlink* = ek@google.com
+per-file libsysutils/src/Netlink* = lorenzo@google.com
+per-file libsysutils/include/sysutils/Netlink* = ek@google.com
+per-file libsysutils/include/sysutils/Netlink* = lorenzo@google.com
diff --git a/adb/Android.bp b/adb/Android.bp
index 0858a6c..99de54e 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -12,6 +12,365 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+cc_defaults {
+    name: "adb_defaults",
+
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-Wno-missing-field-initializers",
+        "-Wvla",
+    ],
+    rtti: true,
+
+    clang_cflags: [
+        "-Wexit-time-destructors",
+        "-Wthread-safety",
+    ],
+
+    use_version_lib: true,
+
+    compile_multilib: "first",
+    product_variables: {
+        debuggable: {
+            cflags: [
+                "-DALLOW_ADBD_ROOT",
+                "-DALLOW_ADBD_DISABLE_VERITY",
+                "-DALLOW_ADBD_NO_AUTH",
+            ],
+        },
+    },
+
+    target: {
+        android: {
+            cflags: ["-DADB_HOST=0"],
+        },
+
+        host: {
+            cflags: ["-DADB_HOST=1"],
+        },
+
+        darwin: {
+            host_ldlibs: [
+                "-lpthread",
+                "-framework CoreFoundation",
+                "-framework IOKit",
+                "-lobjc",
+            ],
+        },
+
+        windows: {
+            cflags: [
+                // Define windows.h and tchar.h Unicode preprocessor symbols so that
+                // CreateFile(), _tfopen(), etc. map to versions that take wchar_t*, breaking the
+                // build if you accidentally pass char*. Fix by calling like:
+                //   std::wstring path_wide;
+                //   if (!android::base::UTF8ToWide(path_utf8, &path_wide)) { /* error handling */ }
+                //   CreateFileW(path_wide.c_str());
+                "-DUNICODE=1",
+                "-D_UNICODE=1",
+
+                // -std=gnu++11 doesn't set _GNU_SOURCE on Windows.
+                "-D_GNU_SOURCE",
+
+                // MinGW hides some things behind _POSIX_SOURCE.
+                "-D_POSIX_SOURCE",
+            ],
+
+            host_ldlibs: [
+                "-lws2_32",
+                "-lgdi32",
+                "-luserenv",
+            ],
+        },
+    },
+}
+
+// libadb
+// =========================================================
+// These files are compiled for both the host and the device.
+libadb_srcs = [
+    "adb.cpp",
+    "adb_io.cpp",
+    "adb_listeners.cpp",
+    "adb_trace.cpp",
+    "adb_utils.cpp",
+    "fdevent.cpp",
+    "services.cpp",
+    "sockets.cpp",
+    "socket_spec.cpp",
+    "sysdeps/errno.cpp",
+    "transport.cpp",
+    "transport_local.cpp",
+    "transport_usb.cpp",
+]
+
+libadb_posix_srcs = [
+    "sysdeps_unix.cpp",
+    "sysdeps/posix/network.cpp",
+]
+
+libadb_test_srcs = [
+    "adb_io_test.cpp",
+    "adb_listeners_test.cpp",
+    "adb_utils_test.cpp",
+    "fdevent_test.cpp",
+    "socket_spec_test.cpp",
+    "socket_test.cpp",
+    "sysdeps_test.cpp",
+    "sysdeps/stat_test.cpp",
+    "transport_test.cpp",
+]
+
+cc_library_host_static {
+    name: "libadb_host",
+    defaults: ["adb_defaults"],
+
+    srcs: libadb_srcs + [
+        "client/auth.cpp",
+        "client/usb_libusb.cpp",
+        "client/usb_dispatch.cpp",
+        "client/transport_mdns.cpp",
+    ],
+
+    target: {
+        linux: {
+            srcs: ["client/usb_linux.cpp"],
+        },
+        darwin: {
+            srcs: ["client/usb_osx.cpp"],
+        },
+
+        not_windows: {
+            srcs: libadb_posix_srcs,
+        },
+        windows: {
+            enabled: true,
+            srcs: [
+                "client/usb_windows.cpp",
+                "sysdeps_win32.cpp",
+                "sysdeps/win32/errno.cpp",
+                "sysdeps/win32/stat.cpp",
+            ],
+            shared_libs: ["AdbWinApi"],
+        },
+    },
+
+    static_libs: [
+        "libbase",
+        "libcrypto_utils",
+        "libcrypto",
+        "libdiagnose_usb",
+        "libmdnssd",
+        "libusb",
+    ],
+}
+
+cc_test_host {
+    name: "adb_test",
+    defaults: ["adb_defaults"],
+    srcs: libadb_test_srcs,
+    static_libs: [
+        "libadb_host",
+        "libbase",
+        "libcutils",
+        "libcrypto_utils",
+        "libcrypto",
+        "libmdnssd",
+        "libdiagnose_usb",
+        "libusb",
+    ],
+
+    target: {
+        windows: {
+            enabled: true,
+            shared_libs: ["AdbWinApi"],
+        },
+    },
+}
+
+cc_benchmark {
+    name: "adb_benchmark",
+    defaults: ["adb_defaults"],
+
+    srcs: ["transport_benchmark.cpp"],
+    target: {
+        android: {
+            static_libs: [
+                "libadbd",
+            ],
+        },
+        host: {
+            static_libs: [
+                "libadb_host",
+            ],
+        },
+    },
+
+    static_libs: [
+        "libbase",
+        "libcutils",
+        "libcrypto_utils",
+        "libcrypto",
+        "libdiagnose_usb",
+        "liblog",
+        "libusb",
+    ],
+}
+
+cc_binary_host {
+    name: "adb",
+
+    defaults: ["adb_defaults"],
+
+    srcs: [
+        "client/adb_client.cpp",
+        "client/bugreport.cpp",
+        "client/commandline.cpp",
+        "client/file_sync_client.cpp",
+        "client/main.cpp",
+        "client/console.cpp",
+        "client/line_printer.cpp",
+        "shell_service_protocol.cpp",
+    ],
+
+    static_libs: [
+        "libadb_host",
+        "libbase",
+        "libcutils",
+        "libcrypto_utils",
+        "libcrypto",
+        "libdiagnose_usb",
+        "liblog",
+        "libmdnssd",
+        "libusb",
+    ],
+
+    stl: "libc++_static",
+
+    // Don't add anything here, we don't want additional shared dependencies
+    // on the host adb tool, and shared libraries that link against libc++
+    // will violate ODR
+    shared_libs: [],
+
+    target: {
+        darwin: {
+            cflags: [
+                "-Wno-sizeof-pointer-memaccess",
+            ],
+        },
+        windows: {
+            enabled: true,
+            ldflags: ["-municode"],
+            shared_libs: ["AdbWinApi"],
+            required: [
+                "AdbWinUsbApi",
+            ],
+        },
+    },
+}
+
+cc_library_static {
+    name: "libadbd",
+    defaults: ["adb_defaults"],
+
+    // libminadbd wants both, for some reason.
+    compile_multilib: "both",
+    srcs: libadb_srcs + libadb_posix_srcs + [
+        "daemon/auth.cpp",
+        "daemon/usb.cpp",
+        "daemon/jdwp_service.cpp",
+    ],
+
+    static_libs: [
+        "libasyncio",
+        "libbootloader_message",
+        "libcrypto_utils",
+        "libcrypto",
+        "libdiagnose_usb",
+        "libqemu_pipe",
+        "libbase",
+    ],
+}
+
+cc_binary {
+    name: "adbd",
+    defaults: ["adb_defaults"],
+
+    // adbd must be static, as it is copied into the recovery image.
+    static_executable: true,
+
+    srcs: [
+        "daemon/main.cpp",
+        "daemon/mdns.cpp",
+        "daemon/file_sync_service.cpp",
+        "daemon/framebuffer_service.cpp",
+        "daemon/remount_service.cpp",
+        "daemon/set_verity_enable_state_service.cpp",
+        "daemon/shell_service.cpp",
+        "shell_service_protocol.cpp",
+    ],
+
+    cflags: [
+        "-D_GNU_SOURCE",
+        "-Wno-deprecated-declarations",
+    ],
+
+    strip: {
+        keep_symbols: true,
+    },
+
+    static_libs: [
+        "libadbd",
+        "libasyncio",
+        "libavb_user",
+        "libbootloader_message",
+        "libcrypto_utils",
+        "libcrypto",
+        "libdiagnose_usb",
+        "libfec",
+        "libfec_rs",
+        "libfs_mgr",
+        "liblog",
+        "libext4_utils",
+        "libmdnssd",
+        "libminijail",
+        "libselinux",
+        "libsquashfs_utils",
+        "libqemu_pipe",
+        "libdebuggerd_handler",
+
+        "libbase",
+        "libcutils",
+    ],
+}
+
+cc_test {
+    name: "adbd_test",
+    defaults: ["adb_defaults"],
+    srcs: libadb_test_srcs + [
+        "daemon/shell_service.cpp",
+        "daemon/shell_service_test.cpp",
+        "shell_service_protocol.cpp",
+        "shell_service_protocol_test.cpp",
+    ],
+
+    static_libs: [
+        "libadbd",
+        "libbase",
+        "libcutils",
+        "libcrypto_utils",
+        "libcrypto",
+        "libdiagnose_usb",
+        "liblog",
+        "libusb",
+        "libmdnssd",
+    ],
+    test_suites: ["device-tests"],
+}
+
 python_binary_host {
     name: "adb_integration_test_adb",
     main: "test_adb.py",
diff --git a/adb/Android.mk b/adb/Android.mk
index c473ed2..8b2d558 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -1,388 +1,8 @@
-# Copyright 2005 The Android Open Source Project
-#
-# Android.mk for adb
-#
+LOCAL_PATH := $(call my-dir)
 
-LOCAL_PATH:= $(call my-dir)
+# Archive adb, adb.exe.
+$(call dist-for-goals,dist_files sdk win_sdk,$(HOST_OUT_EXECUTABLES)/adb)
 
-include $(LOCAL_PATH)/../platform_tools_tool_version.mk
-
-adb_host_sanitize :=
-adb_target_sanitize :=
-
-ADB_COMMON_CFLAGS := \
-    -frtti \
-    -Wall -Wextra -Werror \
-    -Wno-unused-parameter \
-    -Wno-missing-field-initializers \
-    -Wvla \
-    -DADB_VERSION="\"$(tool_version)\"" \
-
-ADB_COMMON_posix_CFLAGS := \
-    -Wexit-time-destructors \
-    -Wthread-safety \
-
-ADB_COMMON_linux_CFLAGS := \
-    $(ADB_COMMON_posix_CFLAGS) \
-
-ADB_COMMON_darwin_CFLAGS := \
-    $(ADB_COMMON_posix_CFLAGS) \
-
-# Define windows.h and tchar.h Unicode preprocessor symbols so that
-# CreateFile(), _tfopen(), etc. map to versions that take wchar_t*, breaking the
-# build if you accidentally pass char*. Fix by calling like:
-#   std::wstring path_wide;
-#   if (!android::base::UTF8ToWide(path_utf8, &path_wide)) { /* error handling */ }
-#   CreateFileW(path_wide.c_str());
-ADB_COMMON_windows_CFLAGS := \
-    -DUNICODE=1 -D_UNICODE=1 \
-    -D_POSIX_SOURCE
-
-# libadb
-# =========================================================
-
-# Much of adb is duplicated in bootable/recovery/minadb and fastboot. Changes
-# made to adb rarely get ported to the other two, so the trees have diverged a
-# bit. We'd like to stop this because it is a maintenance nightmare, but the
-# divergence makes this difficult to do all at once. For now, we will start
-# small by moving common files into a static library. Hopefully some day we can
-# get enough of adb in here that we no longer need minadb. https://b/17626262
-LIBADB_SRC_FILES := \
-    adb.cpp \
-    adb_io.cpp \
-    adb_listeners.cpp \
-    adb_trace.cpp \
-    adb_utils.cpp \
-    fdevent.cpp \
-    sockets.cpp \
-    socket_spec.cpp \
-    sysdeps/errno.cpp \
-    transport.cpp \
-    transport_local.cpp \
-    transport_usb.cpp \
-
-LIBADB_TEST_SRCS := \
-    adb_io_test.cpp \
-    adb_listeners_test.cpp \
-    adb_utils_test.cpp \
-    fdevent_test.cpp \
-    socket_spec_test.cpp \
-    socket_test.cpp \
-    sysdeps_test.cpp \
-    sysdeps/stat_test.cpp \
-    transport_test.cpp \
-
-LIBADB_CFLAGS := \
-    $(ADB_COMMON_CFLAGS) \
-    -fvisibility=hidden \
-
-LIBADB_linux_CFLAGS := \
-    $(ADB_COMMON_linux_CFLAGS) \
-
-LIBADB_darwin_CFLAGS := \
-    $(ADB_COMMON_darwin_CFLAGS) \
-
-LIBADB_windows_CFLAGS := \
-    $(ADB_COMMON_windows_CFLAGS) \
-
-LIBADB_darwin_SRC_FILES := \
-    sysdeps_unix.cpp \
-    sysdeps/posix/network.cpp \
-    client/usb_dispatch.cpp \
-    client/usb_libusb.cpp \
-    client/usb_osx.cpp \
-
-LIBADB_linux_SRC_FILES := \
-    sysdeps_unix.cpp \
-    sysdeps/posix/network.cpp \
-    client/usb_dispatch.cpp \
-    client/usb_libusb.cpp \
-    client/usb_linux.cpp \
-
-LIBADB_windows_SRC_FILES := \
-    sysdeps_win32.cpp \
-    sysdeps/win32/errno.cpp \
-    sysdeps/win32/stat.cpp \
-    client/usb_dispatch.cpp \
-    client/usb_libusb.cpp \
-    client/usb_windows.cpp \
-
-LIBADB_TEST_windows_SRCS := \
-    sysdeps/win32/errno_test.cpp \
-    sysdeps_win32_test.cpp \
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libadbd_usb
-LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=0
-LOCAL_SRC_FILES := daemon/usb.cpp
-
-LOCAL_SANITIZE := $(adb_target_sanitize)
-
-# Even though we're building a static library (and thus there's no link step for
-# this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libbase libasyncio
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libadbd
-LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=0
-LOCAL_SRC_FILES := \
-    $(LIBADB_SRC_FILES) \
-    adbd_auth.cpp \
-    jdwp_service.cpp \
-    sysdeps/posix/network.cpp \
-
-LOCAL_SANITIZE := $(adb_target_sanitize)
-
-# Even though we're building a static library (and thus there's no link step for
-# this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libqemu_pipe libbase
-
-LOCAL_WHOLE_STATIC_LIBRARIES := libadbd_usb
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libadb
-LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=1
-LOCAL_CFLAGS_windows := $(LIBADB_windows_CFLAGS)
-LOCAL_CFLAGS_linux := $(LIBADB_linux_CFLAGS)
-LOCAL_CFLAGS_darwin := $(LIBADB_darwin_CFLAGS)
-LOCAL_SRC_FILES := \
-    $(LIBADB_SRC_FILES) \
-    adb_auth_host.cpp \
-    transport_mdns.cpp \
-
-LOCAL_SRC_FILES_darwin := $(LIBADB_darwin_SRC_FILES)
-LOCAL_SRC_FILES_linux := $(LIBADB_linux_SRC_FILES)
-LOCAL_SRC_FILES_windows := $(LIBADB_windows_SRC_FILES)
-
-LOCAL_SANITIZE := $(adb_host_sanitize)
-
-# Even though we're building a static library (and thus there's no link step for
-# this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libbase libmdnssd libusb
-
-LOCAL_C_INCLUDES_windows := development/host/windows/usb/api/
-LOCAL_MULTILIB := first
-
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := adbd_test
-LOCAL_CFLAGS := -DADB_HOST=0 $(LIBADB_CFLAGS)
-LOCAL_SRC_FILES := \
-    $(LIBADB_TEST_SRCS) \
-    $(LIBADB_TEST_linux_SRCS) \
-    shell_service.cpp \
-    shell_service_protocol.cpp \
-    shell_service_protocol_test.cpp \
-    shell_service_test.cpp \
-
-LOCAL_SANITIZE := $(adb_target_sanitize)
-LOCAL_STATIC_LIBRARIES := libadbd libcrypto_utils libcrypto libusb libmdnssd
-LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
-include $(BUILD_NATIVE_TEST)
-
-# libdiagnose_usb
-# =========================================================
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libdiagnose_usb
-LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_CFLAGS := $(LIBADB_CFLAGS)
-LOCAL_SRC_FILES := diagnose_usb.cpp
-# Even though we're building a static library (and thus there's no link step for
-# this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libbase
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-# adb_test
-# =========================================================
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := adb_test
-LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_CFLAGS := -DADB_HOST=1 $(LIBADB_CFLAGS)
-LOCAL_CFLAGS_windows := $(LIBADB_windows_CFLAGS)
-LOCAL_CFLAGS_linux := $(LIBADB_linux_CFLAGS)
-LOCAL_CFLAGS_darwin := $(LIBADB_darwin_CFLAGS)
-LOCAL_SRC_FILES := \
-    $(LIBADB_TEST_SRCS) \
-    adb_client.cpp \
-    bugreport.cpp \
-    bugreport_test.cpp \
-    line_printer.cpp \
-    services.cpp \
-    shell_service_protocol.cpp \
-    shell_service_protocol_test.cpp \
-
-LOCAL_SRC_FILES_linux := $(LIBADB_TEST_linux_SRCS)
-LOCAL_SRC_FILES_darwin := $(LIBADB_TEST_darwin_SRCS)
-LOCAL_SRC_FILES_windows := $(LIBADB_TEST_windows_SRCS)
-LOCAL_SANITIZE := $(adb_host_sanitize)
-LOCAL_STATIC_LIBRARIES := \
-    libadb \
-    libbase \
-    libcrypto_utils \
-    libcrypto \
-    libcutils \
-    libdiagnose_usb \
-    libmdnssd \
-    libgmock_host \
-    libusb \
-
-# Set entrypoint to wmain from sysdeps_win32.cpp instead of main
-LOCAL_LDFLAGS_windows := -municode
-LOCAL_LDLIBS_linux := -lrt -ldl -lpthread
-LOCAL_LDLIBS_darwin := -framework CoreFoundation -framework IOKit -lobjc
-LOCAL_LDLIBS_windows := -lws2_32 -luserenv
-LOCAL_SHARED_LIBRARIES_windows := AdbWinApi
-
-LOCAL_MULTILIB := first
-
-include $(BUILD_HOST_NATIVE_TEST)
-
-# adb host tool
-# =========================================================
-include $(CLEAR_VARS)
-
-LOCAL_LDLIBS_linux := -lrt -ldl -lpthread
-
-LOCAL_LDLIBS_darwin := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon -lobjc
-
-# Use wmain instead of main
-LOCAL_LDFLAGS_windows := -municode
-LOCAL_LDLIBS_windows := -lws2_32 -lgdi32
-LOCAL_SHARED_LIBRARIES_windows := AdbWinApi
-LOCAL_REQUIRED_MODULES_windows := AdbWinUsbApi
-
-LOCAL_SRC_FILES := \
-    adb_client.cpp \
-    bugreport.cpp \
-    client/main.cpp \
-    console.cpp \
-    commandline.cpp \
-    file_sync_client.cpp \
-    line_printer.cpp \
-    services.cpp \
-    shell_service_protocol.cpp \
-
-LOCAL_CFLAGS += \
-    $(ADB_COMMON_CFLAGS) \
-    -D_GNU_SOURCE \
-    -DADB_HOST=1 \
-
-LOCAL_CFLAGS_windows := \
-    $(ADB_COMMON_windows_CFLAGS)
-
-LOCAL_CFLAGS_linux := \
-    $(ADB_COMMON_linux_CFLAGS) \
-
-LOCAL_CFLAGS_darwin := \
-    $(ADB_COMMON_darwin_CFLAGS) \
-    -Wno-sizeof-pointer-memaccess -Wno-unused-parameter \
-
-LOCAL_MODULE := adb
-LOCAL_MODULE_TAGS := debug
-LOCAL_MODULE_HOST_OS := darwin linux windows
-
-LOCAL_SANITIZE := $(adb_host_sanitize)
-LOCAL_STATIC_LIBRARIES := \
-    libadb \
-    libbase \
-    libcrypto_utils \
-    libcrypto \
-    libdiagnose_usb \
-    liblog \
-    libmdnssd \
-    libusb \
-
-# Don't use libcutils on Windows.
-LOCAL_STATIC_LIBRARIES_darwin := libcutils
-LOCAL_STATIC_LIBRARIES_linux := libcutils
-
-LOCAL_CXX_STL := libc++_static
-
-# Don't add anything here, we don't want additional shared dependencies
-# on the host adb tool, and shared libraries that link against libc++
-# will violate ODR
-LOCAL_SHARED_LIBRARIES :=
-
-include $(BUILD_HOST_EXECUTABLE)
-
-$(call dist-for-goals,dist_files sdk win_sdk,$(LOCAL_BUILT_MODULE))
 ifdef HOST_CROSS_OS
-# Archive adb.exe for win_sdk build.
-$(call dist-for-goals,win_sdk,$(ALL_MODULES.host_cross_adb.BUILT))
+$(call dist-for-goals,dist_files sdk win_sdk,$(ALL_MODULES.host_cross_adb.BUILT))
 endif
-
-
-# adbd device daemon
-# =========================================================
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-    daemon/main.cpp \
-    daemon/mdns.cpp \
-    services.cpp \
-    file_sync_service.cpp \
-    framebuffer_service.cpp \
-    remount_service.cpp \
-    set_verity_enable_state_service.cpp \
-    shell_service.cpp \
-    shell_service_protocol.cpp \
-
-LOCAL_CFLAGS := \
-    $(ADB_COMMON_CFLAGS) \
-    $(ADB_COMMON_linux_CFLAGS) \
-    -DADB_HOST=0 \
-    -D_GNU_SOURCE \
-    -Wno-deprecated-declarations \
-
-LOCAL_CFLAGS += -DALLOW_ADBD_NO_AUTH=$(if $(filter userdebug eng,$(TARGET_BUILD_VARIANT)),1,0)
-
-ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
-LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1
-LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=1
-endif
-
-LOCAL_MODULE := adbd
-
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-
-LOCAL_SANITIZE := $(adb_target_sanitize)
-LOCAL_STRIP_MODULE := keep_symbols
-LOCAL_STATIC_LIBRARIES := \
-    libadbd \
-    libasyncio \
-    libavb_user \
-    libbase \
-    libqemu_pipe \
-    libbootloader_message \
-    libfs_mgr \
-    libfec \
-    libfec_rs \
-    libselinux \
-    liblog \
-    libext4_utils \
-    libsquashfs_utils \
-    libcutils \
-    libbase \
-    libcrypto_utils \
-    libcrypto \
-    libminijail \
-    libmdnssd \
-    libdebuggerd_handler \
-
-include $(BUILD_EXECUTABLE)
-
-# adb integration test
-# =========================================================
-$(call dist-for-goals,sdk,$(ALL_MODULES.adb_integration_test_adb.BUILT))
-$(call dist-for-goals,sdk,$(ALL_MODULES.adb_integration_test_device.BUILT))
-
-include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/adb/CPPLINT.cfg b/adb/CPPLINT.cfg
deleted file mode 100644
index f496490..0000000
--- a/adb/CPPLINT.cfg
+++ /dev/null
@@ -1,2 +0,0 @@
-set noparent
-filter=-build/header_guard,-build/include,-readability/function,-whitespace/indent
diff --git a/adb/adb.bash b/adb/adb.bash
new file mode 100644
index 0000000..d36bec3
--- /dev/null
+++ b/adb/adb.bash
@@ -0,0 +1,499 @@
+# /* vim: set ai ts=4 ft=sh: */
+#
+# Copyright 2011, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+_adb() {
+    if ! type -t "$1" >/dev/null; then
+        return
+    fi
+
+    if type -t _init_completion >/dev/null; then
+        _init_completion || return
+    fi
+
+    local where i cur serial
+    COMPREPLY=()
+
+    serial="${ANDROID_SERIAL:-none}"
+    where=OPTIONS
+    for ((i=1; i <= COMP_CWORD; i++)); do
+        cur="${COMP_WORDS[i]}"
+        case "${cur}" in
+            -s)
+                where=OPT_SERIAL
+                ;;
+            -p)
+                where=OPT_PATH
+                ;;
+            -*)
+                where=OPTIONS
+                ;;
+            *)
+                if [[ $where == OPT_SERIAL ]]; then
+                    where=OPT_SERIAL_ARG
+                    serial=${cur}
+                else
+                    where=COMMAND
+                    break
+                fi
+                ;;
+        esac
+    done
+
+    if [[ $where == COMMAND && $i -ge $COMP_CWORD ]]; then
+        where=OPTIONS
+    fi
+
+    OPTIONS="-d -e -s -p"
+    COMMAND="devices connect disconnect push pull sync shell emu logcat lolcat forward jdwp install uninstall bugreport help version start-server kill-server get-state get-serialno status-window remount reboot reboot-bootloader root usb tcpip disable-verity"
+
+    case $where in
+        OPTIONS|OPT_SERIAL|OPT_PATH)
+            COMPREPLY=( $(compgen -W "$OPTIONS $COMMAND" -- "$cur") )
+            ;;
+        OPT_SERIAL_ARG)
+            local devices=$(command adb devices 2> /dev/null | grep -v "List of devices" | awk '{ print $1 }')
+            COMPREPLY=( $(compgen -W "${devices}" -- ${cur}) )
+            ;;
+        COMMAND)
+            if [[ $i -eq $COMP_CWORD ]]; then
+                COMPREPLY=( $(compgen -W "$COMMAND" -- "$cur") )
+            else
+                i=$((i+1))
+                case "${cur}" in
+                    install)
+                        _adb_cmd_install "$serial" $i
+                        ;;
+                    sideload)
+                        _adb_cmd_sideload "$serial" $i
+                        ;;
+                    pull)
+                        _adb_cmd_pull "$serial" $i
+                        ;;
+                    push)
+                        _adb_cmd_push "$serial" $i
+                        ;;
+                    reboot)
+                        if [[ $COMP_CWORD == $i ]]; then
+                            args="bootloader recovery"
+                            COMPREPLY=( $(compgen -W "${args}" -- "${COMP_WORDS[i]}") )
+                        fi
+                        ;;
+                    shell)
+                        _adb_cmd_shell "$serial" $i
+                        ;;
+                    uninstall)
+                        _adb_cmd_uninstall "$serial" $i
+                        ;;
+                esac
+            fi
+            ;;
+    esac
+
+    return 0
+}
+
+_adb_cmd_install() {
+    local serial i cur where
+
+    serial=$1
+    i=$2
+
+    where=OPTIONS
+    for ((; i <= COMP_CWORD; i++)); do
+        cur="${COMP_WORDS[i]}"
+        case "${cur}" in
+            -*)
+                where=OPTIONS
+                ;;
+            *)
+                where=FILE
+                break
+                ;;
+        esac
+    done
+
+    cur="${COMP_WORDS[COMP_CWORD]}"
+    if [[ $where == OPTIONS ]]; then
+        COMPREPLY=( $(compgen -W "-d -l -r -s" -- "${cur}") )
+        return
+    fi
+
+    _adb_util_complete_local_file "${cur}" '!*.apk'
+}
+
+_adb_cmd_sideload() {
+    local serial i cur
+
+    serial=$1
+    i=$2
+
+    cur="${COMP_WORDS[COMP_CWORD]}"
+
+    _adb_util_complete_local_file "${cur}" '!*.zip'
+}
+
+_adb_cmd_push() {
+    local serial IFS=$'\n' i cur
+
+    serial=$1
+    i=$2
+
+    cur="${COMP_WORDS[COMP_CWORD]}"
+
+    if [[ $COMP_CWORD == $i ]]; then
+        _adb_util_complete_local_file "${cur}"
+    elif [[ $COMP_CWORD == $(($i+1)) ]]; then
+        if [ "${cur}" == "" ]; then
+            cur="/"
+        fi
+        _adb_util_list_files $serial "${cur}"
+    fi
+}
+
+_adb_cmd_pull() {
+    local serial IFS=$'\n' i cur
+
+    serial=$1
+    i=$2
+
+    cur="${COMP_WORDS[COMP_CWORD]}"
+
+    if [[ $COMP_CWORD == $i ]]; then
+        if [ "${cur}" == "" ]; then
+            cur="/"
+        fi
+        _adb_util_list_files $serial "${cur}"
+    elif [[ $COMP_CWORD == $(($i+1)) ]]; then
+        _adb_util_complete_local_file "${cur}"
+    fi
+}
+
+_adb_cmd_shell() {
+    local serial IFS=$'\n' i cur
+    local -a args
+
+    serial=$1
+    i=$2
+
+    cur="${COMP_WORDS[i]}"
+    if [ "$serial" != "none" ]; then
+        args=(-s $serial)
+    fi
+
+    if [[ $i -eq $COMP_CWORD && ${cur:0:1} != "/" ]]; then
+        paths=$(command adb ${args[@]} shell echo '$'PATH 2> /dev/null | tr -d '\r' | tr : '\n')
+        COMMAND=$(command adb ${args[@]} shell ls $paths '2>' /dev/null | tr -d '\r' | {
+            while read -r tmp; do
+                command=${tmp##*/}
+                printf '%s\n' "$command"
+            done
+        })
+        COMPREPLY=( $(compgen -W "$COMMAND" -- "$cur") )
+        return 0
+    fi
+
+    i=$((i+1))
+    case "$cur" in
+        ls)
+            _adb_shell_file_command $serial $i "--color -A -C -F -H -L -R -S -Z -a -c -d -f -h -i -k -l -m -n -p -q -r -s -t -u -x -1"
+            ;;
+        cat)
+            _adb_shell_file_command $serial $i "-h -e -t -u -v"
+            ;;
+        dumpsys)
+            _adb_cmd_shell_dumpsys "$serial" $i
+            ;;
+        am)
+            _adb_cmd_shell_am "$serial" $i
+            ;;
+        pm)
+            _adb_cmd_shell_pm "$serial" $i
+            ;;
+        /*)
+            _adb_util_list_files $serial "$cur"
+            ;;
+        *)
+            COMPREPLY=( )
+            ;;
+    esac
+
+    return 0
+}
+
+_adb_cmd_shell_dumpsys() {
+    local serial i cur
+    local -a args
+    local candidates
+
+    unset IFS
+
+    serial=$1
+    i=$2
+
+    if [ "$serial" != "none" ]; then
+        args=(-s $serial)
+    fi
+
+    if (( $i == $COMP_CWORD )) ; then
+        cur="${COMP_WORDS[COMP_CWORD]}"
+        # First line is a header, so need "1d".
+        candidates=$(command adb ${args[@]} shell dumpsys -l 2> /dev/null | sed -e '1d;s/^  *//' | tr -d '\r')
+        candidates="-l $candidates"
+        COMPREPLY=( $(compgen -W "$candidates" -- "$cur") )
+        return 0
+    fi
+
+    COMPREPLY=( )
+    return 0
+}
+
+_adb_cmd_shell_am() {
+    local serial i cur
+    local candidates
+
+    unset IFS
+
+    serial=$1
+    i=$2
+
+    if (( $i == $COMP_CWORD )) ; then
+        cur="${COMP_WORDS[COMP_CWORD]}"
+        candidates="broadcast clear-debug-app clear-watch-heap dumpheap force-stop get-config get-inactive hang idle-maintenance instrument kill kill-all monitor package-importance profile restart screen-compat send-trim-memory set-debug-app set-inactive set-watch-heap stack start startservice start-user stopservice stop-user suppress-resize-config-changes switch-user task to-app-uri to-intent-uri to-uri"
+        COMPREPLY=( $(compgen -W "$candidates" -- "$cur") )
+        return 0
+    fi
+
+    COMPREPLY=( )
+    return 0
+}
+
+
+_adb_cmd_shell_pm() {
+    local serial i cur
+    local candidates
+
+    unset IFS
+
+    serial=$1
+    i=$2
+
+    if (( $i == $COMP_CWORD )) ; then
+        cur="${COMP_WORDS[COMP_CWORD]}"
+        candidates="-l -lf -p clear create-user default-state disable"
+        candidates+=" disable-until-used disable-user dump enable"
+        candidates+=" get-app-link get-install-location get-max-users"
+        candidates+=" get-max-running-users grant hide install"
+        candidates+=" install-abandon install-commit install-create"
+        candidates+=" install-write list move-package"
+        candidates+=" move-primary-storage path remove-user"
+        candidates+=" reset-permissions revoke set-app-link"
+        candidates+=" set-installer set-install-location"
+        candidates+=" set-permission-enforced trim-caches unhide"
+        candidates+=" uninstall"
+        COMPREPLY=( $(compgen -W "$candidates" -- "$cur") )
+        return 0
+    fi
+
+    if (( $i + 1 == $COMP_CWORD )) && [[ "${COMP_WORDS[COMP_CWORD -1]}" == "list" ]]  ; then
+        cur="${COMP_WORDS[COMP_CWORD]}"
+        candidates="packages permission-groups permissions instrumentation features libraries users"
+        COMPREPLY=( $(compgen -W "$candidates" -- "$cur") )
+        return 0
+    fi
+
+    COMPREPLY=( )
+    return 0
+}
+
+_adb_cmd_uninstall() {
+    local serial i where cur packages
+
+    serial=$1
+    i=$2
+    if [ "$serial" != "none" ]; then
+        args=(-s $serial)
+    fi
+
+    where=OPTIONS
+    for ((; i <= COMP_CWORD; i++)); do
+        cur="${COMP_WORDS[i]}"
+        case "${cur}" in
+            -*)
+                where=OPTIONS
+                ;;
+            *)
+                where=FILE
+                break
+                ;;
+        esac
+    done
+
+    cur="${COMP_WORDS[COMP_CWORD]}"
+    if [[ $where == OPTIONS ]]; then
+        COMPREPLY=( $(compgen -W "-k" -- "${cur}") )
+    fi
+
+    packages="$(
+        command adb ${args[@]} shell pm list packages '2>' /dev/null 2> /dev/null | tr -d '\r' | {
+            while read -r tmp; do
+                local package=${tmp#package:}
+                echo -n "${package} "
+            done
+        }
+    )"
+
+    COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W "${packages}" -- "${cur}") )
+}
+
+_adb_shell_file_command() {
+    local serial i cur file options
+    local -a args
+
+    serial=$1
+    i=$2
+    if [ "$serial" != "none" ]; then
+        args=(-s $serial)
+    fi
+    options=$3
+
+    where=OPTIONS
+    for ((; i <= COMP_CWORD; i++)); do
+        cur="${COMP_WORDS[i]}"
+        case "${cur}" in
+            -*)
+                where=OPTIONS
+                ;;
+            *)
+                where=FILE
+                break
+                ;;
+        esac
+    done
+
+    file="${COMP_WORDS[COMP_CWORD]}"
+    if [[ ${file} == "" ]]; then
+        file="/"
+    fi
+
+    case $where in
+        OPTIONS)
+            unset IFS
+            COMPREPLY=( $(compgen -W "$options" -- "$cur") )
+            ;;
+        FILE)
+            _adb_util_list_files $serial "$file"
+            ;;
+    esac
+
+    return 0
+}
+
+_adb_util_list_files() {
+    local serial dir IFS=$'\n'
+    local -a toks
+    local -a args
+
+    serial="$1"
+    file="$2"
+
+    if [ "$serial" != "none" ]; then
+        args=(-s $serial)
+    fi
+
+    if [[ $( command adb ${args[@]} shell ls -dF / '2>/dev/null' | tr -d '\r' ) == "d /" ]] ; then
+        toks=( ${toks[@]-} $(
+            command adb ${args[@]} shell ls -dF ${file}"*" '2>' /dev/null 2> /dev/null | tr -d '\r' | {
+                while read -r tmp; do
+                    filetype=${tmp%% *}
+                    filename=${tmp:${#filetype}+1}
+                    if [[ ${filetype:${#filetype}-1:1} == d ]]; then
+                        printf '%s/\n' "$filename"
+                    else
+                        printf '%s\n' "$filename"
+                    fi
+                done
+            }
+        ))
+    else
+        toks=( ${toks[@]-} $(
+            command adb ${args[@]} shell ls -dp ${file}"*" '2>/dev/null' 2> /dev/null | tr -d '\r'
+        ))
+    fi
+
+    # Since we're probably doing file completion here, don't add a space after.
+    if [[ $(type -t compopt) = "builtin" ]]; then
+        compopt -o nospace
+    fi
+
+    COMPREPLY=( ${COMPREPLY[@]:-} "${toks[@]}" )
+}
+
+_adb_util_complete_local_file()
+{
+    local file xspec i j IFS=$'\n'
+    local -a dirs files
+
+    file=$1
+    xspec=$2
+
+    # Since we're probably doing file completion here, don't add a space after.
+    if [[ $(type -t compopt) = "builtin" ]]; then
+        compopt -o plusdirs
+        if [[ "${xspec}" == "" ]]; then
+            COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") )
+        else
+            compopt +o filenames
+            COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") )
+        fi
+    else
+        # Work-around for shells with no compopt
+
+        dirs=( $(compgen -d -- "${cur}" ) )
+
+        if [[ "${xspec}" == "" ]]; then
+            files=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") )
+        else
+            files=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") )
+        fi
+
+        COMPREPLY=( $(
+            for i in "${files[@]}"; do
+                local skip=
+                for j in "${dirs[@]}"; do
+                    if [[ $i == $j ]]; then
+                        skip=1
+                        break
+                    fi
+                done
+                [[ -n $skip ]] || printf "%s\n" "$i"
+            done
+        ))
+
+        COMPREPLY=( ${COMPREPLY[@]:-} $(
+            for i in "${dirs[@]}"; do
+                printf "%s/\n" "$i"
+            done
+        ))
+    fi
+}
+
+
+if [[ $(type -t compopt) = "builtin" ]]; then
+    complete -F _adb adb
+else
+    complete -o nospace -F _adb adb
+fi
diff --git a/adb/adb.cpp b/adb/adb.cpp
index c791c7b..76ca19a 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -44,6 +44,7 @@
 #include <android-base/parsenetaddress.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <build/version.h>
 
 #include "adb_auth.h"
 #include "adb_io.h"
@@ -66,8 +67,8 @@
         "Android Debug Bridge version %d.%d.%d\n"
         "Version %s\n"
         "Installed as %s\n",
-        ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION, ADB_VERSION,
-        android::base::GetExecutablePath().c_str());
+        ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION,
+        android::build::GetBuildNumber().c_str(), android::base::GetExecutablePath().c_str());
 }
 
 void fatal(const char *fmt, ...) {
@@ -131,12 +132,21 @@
 {
     D("adb: online");
     t->online = 1;
+    t->SetConnectionEstablished(true);
 }
 
 void handle_offline(atransport *t)
 {
-    D("adb: offline");
-    //Close the associated usb
+    if (t->GetConnectionState() == kCsOffline) {
+        LOG(INFO) << t->serial_name() << ": already offline";
+        return;
+    }
+
+    LOG(INFO) << t->serial_name() << ": offline";
+
+    t->SetConnectionState(kCsOffline);
+
+    // Close the associated usb
     t->online = 0;
 
     // This is necessary to avoid a race condition that occurred when a transport closes
@@ -248,7 +258,7 @@
                    << connection_str.length() << ")";
     }
 
-    cp->payload = std::move(connection_str);
+    cp->payload.assign(connection_str.begin(), connection_str.end());
     cp->msg.data_length = cp->payload.size();
 
     send_packet(cp, t);
@@ -317,13 +327,11 @@
 }
 
 static void handle_new_connection(atransport* t, apacket* p) {
-    if (t->GetConnectionState() != kCsOffline) {
-        t->SetConnectionState(kCsOffline);
-        handle_offline(t);
-    }
+    handle_offline(t);
 
     t->update_version(p->msg.arg0, p->msg.arg1);
-    parse_banner(p->payload, t);
+    std::string banner(p->payload.begin(), p->payload.end());
+    parse_banner(banner, t);
 
 #if ADB_HOST
     handle_online(t);
@@ -349,19 +357,6 @@
     CHECK_EQ(p->payload.size(), p->msg.data_length);
 
     switch(p->msg.command){
-    case A_SYNC:
-        if (p->msg.arg0){
-            send_packet(p, t);
-#if ADB_HOST
-            send_connect(t);
-#endif
-        } else {
-            t->SetConnectionState(kCsOffline);
-            handle_offline(t);
-            send_packet(p, t);
-        }
-        return;
-
     case A_CNXN:  // CONNECT(version, maxdata, "system-id-string")
         handle_new_connection(t, p);
         break;
@@ -370,14 +365,16 @@
         switch (p->msg.arg0) {
 #if ADB_HOST
             case ADB_AUTH_TOKEN:
-                if (t->GetConnectionState() == kCsOffline) {
-                    t->SetConnectionState(kCsUnauthorized);
+                if (t->GetConnectionState() != kCsAuthorizing) {
+                    t->SetConnectionState(kCsAuthorizing);
                 }
                 send_auth_response(p->payload.data(), p->msg.data_length, t);
                 break;
 #else
-            case ADB_AUTH_SIGNATURE:
-                if (adbd_auth_verify(t->token, sizeof(t->token), p->payload)) {
+            case ADB_AUTH_SIGNATURE: {
+                // TODO: Switch to string_view.
+                std::string signature(p->payload.begin(), p->payload.end());
+                if (adbd_auth_verify(t->token, sizeof(t->token), signature)) {
                     adbd_auth_verified(t);
                     t->failed_auth_attempts = 0;
                 } else {
@@ -385,6 +382,7 @@
                     send_auth_request(t);
                 }
                 break;
+            }
 
             case ADB_AUTH_RSAPUBLICKEY:
                 adbd_auth_confirm_key(p->payload.data(), p->msg.data_length, t);
@@ -399,7 +397,9 @@
 
     case A_OPEN: /* OPEN(local-id, 0, "destination") */
         if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) {
-            asocket* s = create_local_service_socket(p->payload.c_str(), t);
+            // TODO: Switch to string_view.
+            std::string address(p->payload.begin(), p->payload.end());
+            asocket* s = create_local_service_socket(address.c_str(), t);
             if (s == nullptr) {
                 send_close(0, p->msg.arg0, t);
             } else {
@@ -1103,14 +1103,11 @@
     if (!strcmp(service, "reconnect-offline")) {
         std::string response;
         close_usb_devices([&response](const atransport* transport) {
-            switch (transport->GetConnectionState()) {
-                case kCsOffline:
-                case kCsUnauthorized:
-                    response += "reconnecting " + transport->serial_name() + "\n";
-                    return true;
-                default:
-                    return false;
+            if (!ConnectionStateIsOnline(transport->GetConnectionState())) {
+                response += "reconnecting " + transport->serial_name() + "\n";
+                return true;
             }
+            return false;
         });
         if (!response.empty()) {
             response.resize(response.size() - 1);
diff --git a/adb/adb.h b/adb/adb.h
index 65b5fc0..ede55da 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -28,6 +28,7 @@
 #include "adb_trace.h"
 #include "fdevent.h"
 #include "socket.h"
+#include "types.h"
 #include "usb.h"
 
 constexpr size_t MAX_PAYLOAD_V1 = 4 * 1024;
@@ -63,20 +64,6 @@
 using TransportId = uint64_t;
 class atransport;
 
-struct amessage {
-    uint32_t command;     /* command identifier constant      */
-    uint32_t arg0;        /* first argument                   */
-    uint32_t arg1;        /* second argument                  */
-    uint32_t data_length; /* length of payload (0 is allowed) */
-    uint32_t data_check;  /* checksum of data payload         */
-    uint32_t magic;       /* command ^ 0xffffffff             */
-};
-
-struct apacket {
-    amessage msg;
-    std::string payload;
-};
-
 uint32_t calculate_apacket_checksum(const apacket* packet);
 
 /* the adisconnect structure is used to record a callback that
@@ -108,16 +95,33 @@
 
 enum ConnectionState {
     kCsAny = -1,
-    kCsOffline = 0,
+
+    kCsConnecting = 0,  // Haven't received a response from the device yet.
+    kCsAuthorizing,     // Authorizing with keys from ADB_VENDOR_KEYS.
+    kCsUnauthorized,    // ADB_VENDOR_KEYS exhausted, fell back to user prompt.
+    kCsNoPerm,          // Insufficient permissions to communicate with the device.
+    kCsOffline,
+
     kCsBootloader,
     kCsDevice,
     kCsHost,
     kCsRecovery,
-    kCsNoPerm,  // Insufficient permissions to communicate with the device.
     kCsSideload,
-    kCsUnauthorized,
 };
 
+inline bool ConnectionStateIsOnline(ConnectionState state) {
+    switch (state) {
+        case kCsBootloader:
+        case kCsDevice:
+        case kCsHost:
+        case kCsRecovery:
+        case kCsSideload:
+            return true;
+        default:
+            return false;
+    }
+}
+
 void print_packet(const char* label, apacket* p);
 
 // These use the system (v)fprintf, not the adb prefixed ones defined in sysdeps.h, so they
diff --git a/adb/adb_client.cpp b/adb/client/adb_client.cpp
similarity index 100%
rename from adb/adb_client.cpp
rename to adb/client/adb_client.cpp
diff --git a/adb/adb_client.h b/adb/client/adb_client.h
similarity index 100%
rename from adb/adb_client.h
rename to adb/client/adb_client.h
diff --git a/adb/adb_auth_host.cpp b/adb/client/auth.cpp
similarity index 98%
rename from adb/adb_auth_host.cpp
rename to adb/client/auth.cpp
index c3aef16..0f4dd33 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/client/auth.cpp
@@ -454,10 +454,8 @@
     p->msg.command = A_AUTH;
     p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
 
-    p->payload = std::move(key);
-
     // adbd expects a null-terminated string.
-    p->payload.push_back('\0');
+    p->payload.assign(key.data(), key.data() + key.size() + 1);
     p->msg.data_length = p->payload.size();
     send_packet(p, t);
 }
@@ -466,6 +464,7 @@
     std::shared_ptr<RSA> key = t->NextKey();
     if (key == nullptr) {
         // No more private keys to try, send the public key.
+        t->SetConnectionState(kCsUnauthorized);
         send_auth_publickey(t);
         return;
     }
@@ -482,7 +481,7 @@
 
     p->msg.command = A_AUTH;
     p->msg.arg0 = ADB_AUTH_SIGNATURE;
-    p->payload = std::move(result);
+    p->payload.assign(result.begin(), result.end());
     p->msg.data_length = p->payload.size();
     send_packet(p, t);
 }
diff --git a/adb/bugreport.cpp b/adb/client/bugreport.cpp
similarity index 100%
rename from adb/bugreport.cpp
rename to adb/client/bugreport.cpp
diff --git a/adb/bugreport.h b/adb/client/bugreport.h
similarity index 100%
rename from adb/bugreport.h
rename to adb/client/bugreport.h
diff --git a/adb/commandline.cpp b/adb/client/commandline.cpp
similarity index 100%
rename from adb/commandline.cpp
rename to adb/client/commandline.cpp
diff --git a/adb/commandline.h b/adb/client/commandline.h
similarity index 100%
rename from adb/commandline.h
rename to adb/client/commandline.h
diff --git a/adb/console.cpp b/adb/client/console.cpp
similarity index 100%
rename from adb/console.cpp
rename to adb/client/console.cpp
diff --git a/adb/file_sync_client.cpp b/adb/client/file_sync_client.cpp
similarity index 100%
rename from adb/file_sync_client.cpp
rename to adb/client/file_sync_client.cpp
diff --git a/adb/line_printer.cpp b/adb/client/line_printer.cpp
similarity index 100%
rename from adb/line_printer.cpp
rename to adb/client/line_printer.cpp
diff --git a/adb/line_printer.h b/adb/client/line_printer.h
similarity index 100%
rename from adb/line_printer.h
rename to adb/client/line_printer.h
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 31cb853..44ed3a2 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -117,6 +117,7 @@
     atexit(adb_server_cleanup);
 
     init_transport_registration();
+    init_reconnect_handler();
     init_mdns_transport_discovery();
 
     usb_init();
diff --git a/adb/transport_mdns.cpp b/adb/client/transport_mdns.cpp
similarity index 100%
rename from adb/transport_mdns.cpp
rename to adb/client/transport_mdns.cpp
diff --git a/adb/adbd_auth.cpp b/adb/daemon/auth.cpp
similarity index 100%
rename from adb/adbd_auth.cpp
rename to adb/daemon/auth.cpp
diff --git a/adb/file_sync_service.cpp b/adb/daemon/file_sync_service.cpp
similarity index 100%
rename from adb/file_sync_service.cpp
rename to adb/daemon/file_sync_service.cpp
diff --git a/adb/framebuffer_service.cpp b/adb/daemon/framebuffer_service.cpp
similarity index 100%
rename from adb/framebuffer_service.cpp
rename to adb/daemon/framebuffer_service.cpp
diff --git a/adb/jdwp_service.cpp b/adb/daemon/jdwp_service.cpp
similarity index 96%
rename from adb/jdwp_service.cpp
rename to adb/daemon/jdwp_service.cpp
index 5f070d9..3a3f399 100644
--- a/adb/jdwp_service.cpp
+++ b/adb/daemon/jdwp_service.cpp
@@ -128,7 +128,7 @@
 static void jdwp_process_list_updated(void);
 
 struct JdwpProcess;
-static std::list<std::unique_ptr<JdwpProcess>> _jdwp_list;
+static auto& _jdwp_list = *new std::list<std::unique_ptr<JdwpProcess>>();
 
 struct JdwpProcess {
     explicit JdwpProcess(int socket) {
@@ -457,7 +457,7 @@
     delete s;
 }
 
-static int jdwp_socket_enqueue(asocket* s, std::string) {
+static int jdwp_socket_enqueue(asocket* s, apacket::payload_type) {
     /* you can't write to this asocket */
     D("LS(%d): JDWP socket received data?", s->id);
     s->peer->close(s->peer);
@@ -472,7 +472,7 @@
      * on the second one, close the connection
      */
     if (!jdwp->pass) {
-        std::string data;
+        apacket::payload_type data;
         data.resize(s->get_max_payload());
         size_t len = jdwp_process_list(&data[0], data.size());
         data.resize(len);
@@ -509,7 +509,7 @@
     bool need_initial;
 };
 
-static std::vector<std::unique_ptr<JdwpTracker>> _jdwp_trackers;
+static auto& _jdwp_trackers = *new std::vector<std::unique_ptr<JdwpTracker>>();
 
 static void jdwp_process_list_updated(void) {
     std::string data;
@@ -519,7 +519,8 @@
     for (auto& t : _jdwp_trackers) {
         if (t->peer) {
             // The tracker might not have been connected yet.
-            t->peer->enqueue(t->peer, data);
+            apacket::payload_type payload(data.begin(), data.end());
+            t->peer->enqueue(t->peer, std::move(payload));
         }
     }
 }
@@ -545,7 +546,7 @@
     JdwpTracker* t = (JdwpTracker*)s;
 
     if (t->need_initial) {
-        std::string data;
+        apacket::payload_type data;
         data.resize(s->get_max_payload());
         data.resize(jdwp_process_list_msg(&data[0], data.size()));
         t->need_initial = false;
@@ -553,7 +554,7 @@
     }
 }
 
-static int jdwp_tracker_enqueue(asocket* s, std::string) {
+static int jdwp_tracker_enqueue(asocket* s, apacket::payload_type) {
     /* you can't write to this socket */
     D("LS(%d): JDWP tracker received data?", s->id);
     s->peer->close(s->peer);
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 5adeb44..232d9c5 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -20,6 +20,7 @@
 
 #include <errno.h>
 #include <getopt.h>
+#include <malloc.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -183,9 +184,10 @@
     // descriptor will always be open.
     adbd_cloexec_auth_socket();
 
-    if (ALLOW_ADBD_NO_AUTH && !android::base::GetBoolProperty("ro.adb.secure", false)) {
-        auth_required = false;
-    }
+#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);
+#endif
 
     adbd_auth_init();
 
@@ -237,6 +239,9 @@
 }
 
 int main(int argc, char** argv) {
+    // Set M_DECAY_TIME so that our allocations aren't immediately purged on free.
+    mallopt(M_DECAY_TIME, 1);
+
     while (true) {
         static struct option opts[] = {
             {"root_seclabel", required_argument, nullptr, 's'},
diff --git a/adb/remount_service.cpp b/adb/daemon/remount_service.cpp
similarity index 60%
rename from adb/remount_service.cpp
rename to adb/daemon/remount_service.cpp
index d679a6d..eb46903 100644
--- a/adb/remount_service.cpp
+++ b/adb/daemon/remount_service.cpp
@@ -21,18 +21,23 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <mntent.h>
+#include <spawn.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/mount.h>
+#include <sys/vfs.h>
 #include <unistd.h>
 
 #include <string>
+#include <vector>
 
 #include <android-base/properties.h>
+#include <ext4_utils/ext4_utils.h>
 
 #include "adb.h"
 #include "adb_io.h"
+#include "adb_unique_fd.h"
 #include "adb_utils.h"
 #include "fs_mgr.h"
 
@@ -82,7 +87,62 @@
     return result;
 }
 
-static bool remount_partition(int fd, const char* dir) {
+static bool fs_has_shared_blocks(const char* dev) {
+    struct statfs fs;
+    if (statfs(dev, &fs) == -1 || fs.f_type == EXT4_SUPER_MAGIC) {
+        return false;
+    }
+    unique_fd fd(unix_open(dev, O_RDONLY));
+    if (fd < 0) {
+        return false;
+    }
+    struct ext4_super_block sb;
+    if (lseek64(fd, 1024, SEEK_SET) < 0 || unix_read(fd, &sb, sizeof(sb)) < 0) {
+        return false;
+    }
+    struct fs_info info;
+    if (ext4_parse_sb(&sb, &info) < 0) {
+        return false;
+    }
+    return (info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS) != 0;
+}
+
+static bool can_unshare_blocks(int fd, const char* dev) {
+    const char* E2FSCK_BIN = "/system/bin/e2fsck";
+    if (access(E2FSCK_BIN, X_OK)) {
+        WriteFdFmt(fd, "e2fsck is not available, cannot undo deduplication on %s\n", dev);
+        return false;
+    }
+
+    pid_t child;
+    char* env[] = {nullptr};
+    const char* argv[] = {E2FSCK_BIN, "-n", "-E", "unshare_blocks", dev, nullptr};
+    if (posix_spawn(&child, E2FSCK_BIN, nullptr, nullptr, const_cast<char**>(argv), env)) {
+        WriteFdFmt(fd, "failed to e2fsck to check deduplication: %s\n", strerror(errno));
+        return false;
+    }
+    int status = 0;
+    int ret = TEMP_FAILURE_RETRY(waitpid(child, &status, 0));
+    if (ret < 0) {
+        WriteFdFmt(fd, "failed to get e2fsck status: %s\n", strerror(errno));
+        return false;
+    }
+    if (!WIFEXITED(status)) {
+        WriteFdFmt(fd, "e2fsck exited abnormally with status %d\n", status);
+        return false;
+    }
+    int rc = WEXITSTATUS(status);
+    if (rc != 0) {
+        WriteFdFmt(fd,
+                   "%s is deduplicated, and an e2fsck check failed. It might not "
+                   "have enough free-space to be remounted as writable.\n",
+                   dev);
+        return false;
+    }
+    return true;
+}
+
+static bool remount_partition(int fd, const char* dir, std::vector<std::string>& dedup) {
     if (!directory_exists(dir)) {
         return true;
     }
@@ -108,6 +168,15 @@
         return false;
     }
     if (mount(dev.c_str(), dir, "none", MS_REMOUNT, nullptr) == -1) {
+        if (errno == EROFS && fs_has_shared_blocks(dev.c_str())) {
+            if (!can_unshare_blocks(fd, dev.c_str())) {
+                return false;
+            }
+            // We return true so remount_service() can detect that the only
+            // failure was deduplicated filesystems.
+            dedup.push_back(dev);
+            return true;
+        }
         WriteFdFmt(fd, "remount of the %s superblock failed: %s\n", dir, strerror(errno));
         return false;
     }
@@ -140,17 +209,29 @@
     }
 
     bool success = true;
+    std::vector<std::string> dedup;
     if (android::base::GetBoolProperty("ro.build.system_root_image", false)) {
-        success &= remount_partition(fd, "/");
+        success &= remount_partition(fd, "/", dedup);
     } else {
-        success &= remount_partition(fd, "/system");
+        success &= remount_partition(fd, "/system", dedup);
     }
-    success &= remount_partition(fd, "/odm");
-    success &= remount_partition(fd, "/oem");
-    success &= remount_partition(fd, "/product");
-    success &= remount_partition(fd, "/vendor");
+    success &= remount_partition(fd, "/odm", dedup);
+    success &= remount_partition(fd, "/oem", dedup);
+    success &= remount_partition(fd, "/product", dedup);
+    success &= remount_partition(fd, "/vendor", dedup);
 
-    WriteFdExactly(fd, success ? "remount succeeded\n" : "remount failed\n");
+    if (!success) {
+        WriteFdExactly(fd, "remount failed\n");
+    } else if (dedup.empty()) {
+        WriteFdExactly(fd, "remount succeeded\n");
+    } else {
+        WriteFdExactly(fd,
+                       "The following partitions are deduplicated and could "
+                       "not be remounted:\n");
+        for (const std::string& name : dedup) {
+            WriteFdFmt(fd, "  %s\n", name.c_str());
+        }
+    }
 
     adb_close(fd);
 }
diff --git a/adb/set_verity_enable_state_service.cpp b/adb/daemon/set_verity_enable_state_service.cpp
similarity index 100%
rename from adb/set_verity_enable_state_service.cpp
rename to adb/daemon/set_verity_enable_state_service.cpp
diff --git a/adb/shell_service.cpp b/adb/daemon/shell_service.cpp
similarity index 99%
rename from adb/shell_service.cpp
rename to adb/daemon/shell_service.cpp
index da1222b..401c99c 100644
--- a/adb/shell_service.cpp
+++ b/adb/daemon/shell_service.cpp
@@ -344,7 +344,8 @@
         }
 
         if (command_.empty()) {
-            execle(_PATH_BSHELL, _PATH_BSHELL, "-", nullptr, cenv.data());
+            // Spawn a login shell if we don't have a command.
+            execle(_PATH_BSHELL, "-" _PATH_BSHELL, nullptr, cenv.data());
         } else {
             execle(_PATH_BSHELL, _PATH_BSHELL, "-c", command_.c_str(), nullptr, cenv.data());
         }
diff --git a/adb/shell_service_test.cpp b/adb/daemon/shell_service_test.cpp
similarity index 100%
rename from adb/shell_service_test.cpp
rename to adb/daemon/shell_service_test.cpp
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index 7869324..c724b11 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -234,6 +234,10 @@
     for (unsigned i = 0; i < USB_FFS_NUM_BUFS; i++) {
         aiob->iocbs[i] = &aiob->iocb[i];
     }
+    memset(&aiob->ctx, 0, sizeof(aiob->ctx));
+    if (io_setup(USB_FFS_NUM_BUFS, &aiob->ctx)) {
+        D("[ aio: got error on io_setup (%d) ]", errno);
+    }
 }
 
 static int getMaxPacketSize(int ffs_fd) {
@@ -269,7 +273,7 @@
 
     if (h->control < 0) { // might have already done this before
         LOG(INFO) << "opening control endpoint " << USB_FFS_ADB_EP0;
-        h->control = adb_open(USB_FFS_ADB_EP0, O_RDWR);
+        h->control = adb_open(USB_FFS_ADB_EP0, O_WRONLY);
         if (h->control < 0) {
             PLOG(ERROR) << "cannot open control endpoint " << USB_FFS_ADB_EP0;
             goto err;
@@ -300,23 +304,18 @@
         android::base::SetProperty("sys.usb.ffs.ready", "1");
     }
 
-    h->bulk_out = adb_open(USB_FFS_ADB_OUT, O_RDWR);
+    h->bulk_out = adb_open(USB_FFS_ADB_OUT, O_RDONLY);
     if (h->bulk_out < 0) {
         PLOG(ERROR) << "cannot open bulk-out endpoint " << USB_FFS_ADB_OUT;
         goto err;
     }
 
-    h->bulk_in = adb_open(USB_FFS_ADB_IN, O_RDWR);
+    h->bulk_in = adb_open(USB_FFS_ADB_IN, O_WRONLY);
     if (h->bulk_in < 0) {
         PLOG(ERROR) << "cannot open bulk-in endpoint " << USB_FFS_ADB_IN;
         goto err;
     }
 
-    if (io_setup(USB_FFS_NUM_BUFS, &h->read_aiob.ctx) ||
-        io_setup(USB_FFS_NUM_BUFS, &h->write_aiob.ctx)) {
-        D("[ aio: got error on io_setup (%d) ]", errno);
-    }
-
     h->read_aiob.fd = h->bulk_out;
     h->write_aiob.fd = h->bulk_in;
     return true;
@@ -498,8 +497,6 @@
     h->kicked = false;
     adb_close(h->bulk_out);
     adb_close(h->bulk_in);
-    io_destroy(h->read_aiob.ctx);
-    io_destroy(h->write_aiob.ctx);
 
     // Notify usb_adb_open_thread to open a new connection.
     h->lock.lock();
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 42d851a..cf441cf 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -21,6 +21,7 @@
 #include "fdevent.h"
 
 #include <fcntl.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -36,6 +37,7 @@
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android-base/thread_annotations.h>
+#include <android-base/threads.h>
 
 #include "adb_io.h"
 #include "adb_trace.h"
@@ -71,21 +73,22 @@
 static auto& g_pending_list = *new std::list<fdevent*>();
 static std::atomic<bool> terminate_loop(false);
 static bool main_thread_valid;
-static unsigned long main_thread_id;
+static uint64_t main_thread_id;
 
+static bool run_needs_flush = false;
 static auto& run_queue_notify_fd = *new unique_fd();
 static auto& run_queue_mutex = *new std::mutex();
 static auto& run_queue GUARDED_BY(run_queue_mutex) = *new std::deque<std::function<void()>>();
 
 void check_main_thread() {
     if (main_thread_valid) {
-        CHECK_EQ(main_thread_id, adb_thread_id());
+        CHECK_EQ(main_thread_id, android::base::GetThreadId());
     }
 }
 
 void set_main_thread() {
     main_thread_valid = true;
-    main_thread_id = adb_thread_id();
+    main_thread_id = android::base::GetThreadId();
 }
 
 static std::string dump_fde(const fdevent* fde) {
@@ -315,7 +318,8 @@
         PLOG(FATAL) << "failed to empty run queue notify fd";
     }
 
-    fdevent_run_flush();
+    // Mark that we need to flush, and then run it at the end of fdevent_loop.
+    run_needs_flush = true;
 }
 
 static void fdevent_run_setup() {
@@ -376,6 +380,11 @@
             g_pending_list.pop_front();
             fdevent_call_fdfunc(fde);
         }
+
+        if (run_needs_flush) {
+            fdevent_run_flush();
+            run_needs_flush = false;
+        }
     }
 }
 
diff --git a/adb/fdevent_test.cpp b/adb/fdevent_test.cpp
index e3d5a35..2f0ff18 100644
--- a/adb/fdevent_test.cpp
+++ b/adb/fdevent_test.cpp
@@ -80,30 +80,7 @@
 
 TEST_F(FdeventTest, fdevent_terminate) {
     PrepareThread();
-
-    std::thread thread(fdevent_loop);
-    TerminateThread(thread);
-}
-
-static void FdEventThreadFunc(ThreadArg* arg) {
-    std::vector<int> read_fds;
-    std::vector<int> write_fds;
-
-    read_fds.push_back(arg->first_read_fd);
-    for (size_t i = 0; i < arg->middle_pipe_count; ++i) {
-        int fds[2];
-        ASSERT_EQ(0, adb_socketpair(fds));
-        read_fds.push_back(fds[0]);
-        write_fds.push_back(fds[1]);
-    }
-    write_fds.push_back(arg->last_write_fd);
-
-    std::vector<std::unique_ptr<FdHandler>> fd_handlers;
-    for (size_t i = 0; i < read_fds.size(); ++i) {
-        fd_handlers.push_back(std::make_unique<FdHandler>(read_fds[i], write_fds[i]));
-    }
-
-    fdevent_loop();
+    TerminateThread();
 }
 
 TEST_F(FdeventTest, smoke) {
@@ -122,7 +99,26 @@
     int reader = fd_pair2[0];
 
     PrepareThread();
-    std::thread thread(FdEventThreadFunc, &thread_arg);
+
+    std::vector<std::unique_ptr<FdHandler>> fd_handlers;
+    fdevent_run_on_main_thread([&thread_arg, &fd_handlers]() {
+        std::vector<int> read_fds;
+        std::vector<int> write_fds;
+
+        read_fds.push_back(thread_arg.first_read_fd);
+        for (size_t i = 0; i < thread_arg.middle_pipe_count; ++i) {
+            int fds[2];
+            ASSERT_EQ(0, adb_socketpair(fds));
+            read_fds.push_back(fds[0]);
+            write_fds.push_back(fds[1]);
+        }
+        write_fds.push_back(thread_arg.last_write_fd);
+
+        for (size_t i = 0; i < read_fds.size(); ++i) {
+            fd_handlers.push_back(std::make_unique<FdHandler>(read_fds[i], write_fds[i]));
+        }
+    });
+    WaitForFdeventLoop();
 
     for (size_t i = 0; i < MESSAGE_LOOP_COUNT; ++i) {
         std::string read_buffer = MESSAGE;
@@ -132,7 +128,10 @@
         ASSERT_EQ(read_buffer, write_buffer);
     }
 
-    TerminateThread(thread);
+    fdevent_run_on_main_thread([&fd_handlers]() { fd_handlers.clear(); });
+    WaitForFdeventLoop();
+
+    TerminateThread();
     ASSERT_EQ(0, adb_close(writer));
     ASSERT_EQ(0, adb_close(reader));
 }
@@ -143,7 +142,7 @@
     size_t* happened_event_count;
 };
 
-static void InvalidFdEventCallback(int fd, unsigned events, void* userdata) {
+static void InvalidFdEventCallback(int, unsigned events, void* userdata) {
     InvalidFdArg* arg = reinterpret_cast<InvalidFdArg*>(userdata);
     ASSERT_EQ(arg->expected_events, events);
     fdevent_remove(&arg->fde);
@@ -179,7 +178,6 @@
     std::vector<int> vec;
 
     PrepareThread();
-    std::thread thread(fdevent_loop);
 
     // Block the main thread for a long time while we queue our callbacks.
     fdevent_run_on_main_thread([]() {
@@ -194,7 +192,7 @@
         });
     }
 
-    TerminateThread(thread);
+    TerminateThread();
 
     ASSERT_EQ(1000000u, vec.size());
     for (int i = 0; i < 1000000; ++i) {
@@ -218,11 +216,8 @@
     std::vector<int> vec;
 
     PrepareThread();
-    std::thread thread(fdevent_loop);
-
     fdevent_run_on_main_thread(make_appender(&vec, 0));
-
-    TerminateThread(thread);
+    TerminateThread();
 
     ASSERT_EQ(100u, vec.size());
     for (int i = 0; i < 100; ++i) {
diff --git a/adb/fdevent_test.h b/adb/fdevent_test.h
index 1a2d41c..5a417e0 100644
--- a/adb/fdevent_test.h
+++ b/adb/fdevent_test.h
@@ -16,10 +16,31 @@
 
 #include <gtest/gtest.h>
 
+#include <condition_variable>
+#include <mutex>
 #include <thread>
 
 #include "socket.h"
 #include "sysdeps.h"
+#include "sysdeps/chrono.h"
+
+static void WaitForFdeventLoop() {
+    // Sleep for a bit to make sure that network events have propagated.
+    std::this_thread::sleep_for(100ms);
+
+    // fdevent_run_on_main_thread has a guaranteed ordering, and is guaranteed to happen after
+    // socket events, so as soon as our function is called, we know that we've processed all
+    // previous events.
+    std::mutex mutex;
+    std::condition_variable cv;
+    std::unique_lock<std::mutex> lock(mutex);
+    fdevent_run_on_main_thread([&]() {
+        mutex.lock();
+        mutex.unlock();
+        cv.notify_one();
+    });
+    cv.wait(lock);
+}
 
 class FdeventTest : public ::testing::Test {
   protected:
@@ -49,6 +70,9 @@
         }
         dummy_socket->ready(dummy_socket);
         dummy = dummy_fds[0];
+
+        thread_ = std::thread([]() { fdevent_loop(); });
+        WaitForFdeventLoop();
     }
 
     size_t GetAdditionalLocalSocketCount() {
@@ -56,10 +80,12 @@
         return 2;
     }
 
-    void TerminateThread(std::thread& thread) {
+    void TerminateThread() {
         fdevent_terminate_loop();
         ASSERT_TRUE(WriteFdExactly(dummy, "", 1));
-        thread.join();
+        thread_.join();
         ASSERT_EQ(0, adb_close(dummy));
     }
+
+    std::thread thread_;
 };
diff --git a/adb/protocol.txt b/adb/protocol.txt
index 55ea87f..f4523c4 100644
--- a/adb/protocol.txt
+++ b/adb/protocol.txt
@@ -183,9 +183,11 @@
 
 Command constant: A_SYNC
 
-The SYNC message is used by the io pump to make sure that stale
+*** obsolete, no longer used ***
+
+The SYNC message was used by the io pump to make sure that stale
 outbound messages are discarded when the connection to the remote side
-is broken.  It is only used internally to the bridge and never valid
+is broken.  It was only used internally to the bridge and never valid
 to send across the wire.
 
 * when the connection to the remote side goes offline, the io pump
diff --git a/adb/range.h b/adb/range.h
deleted file mode 100644
index 7a0b822..0000000
--- a/adb/range.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#pragma once
-
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <string>
-
-#include <android-base/logging.h>
-
-struct Range {
-    explicit Range(std::string data) : data_(std::move(data)) {}
-
-    Range(const Range& copy) = delete;
-    Range& operator=(const Range& copy) = delete;
-
-    Range(Range&& move) = default;
-    Range& operator=(Range&& move) = default;
-
-    bool empty() const {
-        return size() == 0;
-    }
-
-    size_t size() const {
-        return data_.size() - begin_offset_ - end_offset_;
-    };
-
-    void drop_front(size_t n) {
-        CHECK_GE(size(), n);
-        begin_offset_ += n;
-    }
-
-    void drop_end(size_t n) {
-        CHECK_GE(size(), n);
-        end_offset_ += n;
-    }
-
-    char* data() {
-        return &data_[0] + begin_offset_;
-    }
-
-    std::string::iterator begin() {
-        return data_.begin() + begin_offset_;
-    }
-
-    std::string::iterator end() {
-        return data_.end() - end_offset_;
-    }
-
-    std::string data_;
-    size_t begin_offset_ = 0;
-    size_t end_offset_ = 0;
-};
diff --git a/adb/socket.h b/adb/socket.h
index 88499b5..e0fd87f 100644
--- a/adb/socket.h
+++ b/adb/socket.h
@@ -24,9 +24,8 @@
 #include <string>
 
 #include "fdevent.h"
-#include "range.h"
+#include "types.h"
 
-struct apacket;
 class atransport;
 
 /* An asocket represents one half of a connection between a local and
@@ -73,7 +72,7 @@
      * peer->ready() when we once again are ready to
      * receive data.
      */
-    int (*enqueue)(asocket* s, std::string data) = nullptr;
+    int (*enqueue)(asocket* s, apacket::payload_type data) = nullptr;
 
     /* ready is called by the peer when it is ready for
      * us to send data via enqueue again
diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp
index 6b40056..04214a2 100644
--- a/adb/socket_test.cpp
+++ b/adb/socket_test.cpp
@@ -42,8 +42,6 @@
 
 class LocalSocketTest : public FdeventTest {};
 
-constexpr auto SLEEP_FOR_FDEVENT = 100ms;
-
 TEST_F(LocalSocketTest, smoke) {
     // Join two socketpairs with a chain of intermediate socketpairs.
     int first[2];
@@ -84,7 +82,6 @@
     connect(prev_tail, end);
 
     PrepareThread();
-    std::thread thread(fdevent_loop);
 
     for (size_t i = 0; i < MESSAGE_LOOP_COUNT; ++i) {
         std::string read_buffer = MESSAGE;
@@ -98,9 +95,9 @@
     ASSERT_EQ(0, adb_close(last[1]));
 
     // Wait until the local sockets are closed.
-    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+    WaitForFdeventLoop();
     ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
-    TerminateThread(thread);
+    TerminateThread();
 }
 
 struct CloseWithPacketArg {
@@ -109,24 +106,39 @@
     int cause_close_fd;
 };
 
-static void CloseWithPacketThreadFunc(CloseWithPacketArg* arg) {
-    asocket* s = create_local_socket(arg->socket_fd);
-    ASSERT_TRUE(s != nullptr);
-    arg->bytes_written = 0;
+static void CreateCloser(CloseWithPacketArg* arg) {
+    fdevent_run_on_main_thread([arg]() {
+        asocket* s = create_local_socket(arg->socket_fd);
+        ASSERT_TRUE(s != nullptr);
+        arg->bytes_written = 0;
 
-    std::string data;
-    data.resize(MAX_PAYLOAD);
-    arg->bytes_written += data.size();
-    int ret = s->enqueue(s, std::move(data));
-    ASSERT_EQ(1, ret);
+        // On platforms that implement sockets via underlying sockets (e.g. Wine),
+        // a socket can appear to be full, and then become available for writes
+        // again without read being called on the other end. Loop and sleep after
+        // each write to give the underlying implementation time to flush.
+        bool socket_filled = false;
+        for (int i = 0; i < 128; ++i) {
+            apacket::payload_type data;
+            data.resize(MAX_PAYLOAD);
+            arg->bytes_written += data.size();
+            int ret = s->enqueue(s, std::move(data));
+            if (ret == 1) {
+                socket_filled = true;
+                break;
+            }
+            ASSERT_NE(-1, ret);
 
-    asocket* cause_close_s = create_local_socket(arg->cause_close_fd);
-    ASSERT_TRUE(cause_close_s != nullptr);
-    cause_close_s->peer = s;
-    s->peer = cause_close_s;
-    cause_close_s->ready(cause_close_s);
+            std::this_thread::sleep_for(250ms);
+        }
+        ASSERT_TRUE(socket_filled);
 
-    fdevent_loop();
+        asocket* cause_close_s = create_local_socket(arg->cause_close_fd);
+        ASSERT_TRUE(cause_close_s != nullptr);
+        cause_close_s->peer = s;
+        s->peer = cause_close_s;
+        cause_close_s->ready(cause_close_s);
+    });
+    WaitForFdeventLoop();
 }
 
 // This test checks if we can close local socket in the following situation:
@@ -143,16 +155,17 @@
     arg.cause_close_fd = cause_close_fd[1];
 
     PrepareThread();
-    std::thread thread(CloseWithPacketThreadFunc, &arg);
-    // Wait until the fdevent_loop() starts.
-    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+    CreateCloser(&arg);
+
     ASSERT_EQ(0, adb_close(cause_close_fd[0]));
-    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+
+    WaitForFdeventLoop();
     EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
     ASSERT_EQ(0, adb_close(socket_fd[0]));
-    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+
+    WaitForFdeventLoop();
     ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
-    TerminateThread(thread);
+    TerminateThread();
 }
 
 // This test checks if we can read packets from a closing local socket.
@@ -166,11 +179,12 @@
     arg.cause_close_fd = cause_close_fd[1];
 
     PrepareThread();
-    std::thread thread(CloseWithPacketThreadFunc, &arg);
-    // Wait until the fdevent_loop() starts.
-    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+    CreateCloser(&arg);
+
+    WaitForFdeventLoop();
     ASSERT_EQ(0, adb_close(cause_close_fd[0]));
-    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+
+    WaitForFdeventLoop();
     EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
 
     // Verify if we can read successfully.
@@ -179,9 +193,9 @@
     ASSERT_EQ(true, ReadFdExactly(socket_fd[0], buf.data(), buf.size()));
     ASSERT_EQ(0, adb_close(socket_fd[0]));
 
-    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+    WaitForFdeventLoop();
     ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
-    TerminateThread(thread);
+    TerminateThread();
 }
 
 // This test checks if we can close local socket in the following situation:
@@ -198,15 +212,15 @@
     arg.cause_close_fd = cause_close_fd[1];
 
     PrepareThread();
-    std::thread thread(CloseWithPacketThreadFunc, &arg);
-    // Wait until the fdevent_loop() starts.
-    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+    CreateCloser(&arg);
+
+    WaitForFdeventLoop();
     EXPECT_EQ(2u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
     ASSERT_EQ(0, adb_close(socket_fd[0]));
 
-    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+    WaitForFdeventLoop();
     ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
-    TerminateThread(thread);
+    TerminateThread();
 }
 
 // Ensure that if we fail to write output to an fd, we will still flush data coming from it.
@@ -226,7 +240,6 @@
     tail->ready(tail);
 
     PrepareThread();
-    std::thread thread(fdevent_loop);
 
     EXPECT_TRUE(WriteFdExactly(head_fd[0], "foo", 3));
 
@@ -242,10 +255,9 @@
     adb_close(head_fd[0]);
     adb_close(tail_fd[0]);
 
-    // Wait until the local sockets are closed.
-    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+    WaitForFdeventLoop();
     ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
-    TerminateThread(thread);
+    TerminateThread();
 }
 
 #if defined(__linux__)
@@ -254,21 +266,10 @@
     std::string error;
     int fd = network_loopback_client(5038, SOCK_STREAM, &error);
     ASSERT_GE(fd, 0) << error;
-    std::this_thread::sleep_for(200ms);
+    std::this_thread::sleep_for(1s);
     ASSERT_EQ(0, adb_close(fd));
 }
 
-struct CloseRdHupSocketArg {
-    int socket_fd;
-};
-
-static void CloseRdHupSocketThreadFunc(CloseRdHupSocketArg* arg) {
-    asocket* s = create_local_socket(arg->socket_fd);
-    ASSERT_TRUE(s != nullptr);
-
-    fdevent_loop();
-}
-
 // This test checks if we can close sockets in CLOSE_WAIT state.
 TEST_F(LocalSocketTest, close_socket_in_CLOSE_WAIT_state) {
     std::string error;
@@ -279,22 +280,23 @@
 
     int accept_fd = adb_socket_accept(listen_fd, nullptr, nullptr);
     ASSERT_GE(accept_fd, 0);
-    CloseRdHupSocketArg arg;
-    arg.socket_fd = accept_fd;
 
     PrepareThread();
-    std::thread thread(CloseRdHupSocketThreadFunc, &arg);
 
-    // Wait until the fdevent_loop() starts.
-    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+    fdevent_run_on_main_thread([accept_fd]() {
+        asocket* s = create_local_socket(accept_fd);
+        ASSERT_TRUE(s != nullptr);
+    });
+
+    WaitForFdeventLoop();
     EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
 
     // Wait until the client closes its socket.
     client_thread.join();
 
-    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+    WaitForFdeventLoop();
     ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
-    TerminateThread(thread);
+    TerminateThread();
 }
 
 #endif  // defined(__linux__)
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 04bd080..e567ff4 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -37,8 +37,8 @@
 
 #include "adb.h"
 #include "adb_io.h"
-#include "range.h"
 #include "transport.h"
+#include "types.h"
 
 static std::recursive_mutex& local_socket_list_lock = *new std::recursive_mutex();
 static unsigned local_socket_next_id = 1;
@@ -126,12 +126,12 @@
         } else if (rc == -1 && errno == EAGAIN) {
             fdevent_add(&s->fde, FDE_WRITE);
             return SocketFlushResult::TryAgain;
+        } else {
+            // We failed to write, but it's possible that we can still read from the socket.
+            // Give that a try before giving up.
+            s->has_write_error = true;
+            break;
         }
-
-        // We failed to write, but it's possible that we can still read from the socket.
-        // Give that a try before giving up.
-        s->has_write_error = true;
-        break;
     }
 
     // If we sent the last packet of a closing socket, we can now destroy it.
@@ -147,7 +147,7 @@
 // Returns false if the socket has been closed and destroyed as a side-effect of this function.
 static bool local_socket_flush_outgoing(asocket* s) {
     const size_t max_payload = s->get_max_payload();
-    std::string data;
+    apacket::payload_type data;
     data.resize(max_payload);
     char* x = &data[0];
     size_t avail = max_payload;
@@ -214,7 +214,7 @@
     return true;
 }
 
-static int local_socket_enqueue(asocket* s, std::string data) {
+static int local_socket_enqueue(asocket* s, apacket::payload_type data) {
     D("LS(%d): enqueue %zu", s->id, data.size());
 
     Range r(std::move(data));
@@ -394,7 +394,7 @@
 }
 #endif /* ADB_HOST */
 
-static int remote_socket_enqueue(asocket* s, std::string data) {
+static int remote_socket_enqueue(asocket* s, apacket::payload_type data) {
     D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd);
     apacket* p = get_apacket();
 
@@ -476,8 +476,7 @@
     p->msg.arg0 = s->id;
 
     // adbd expects a null-terminated string.
-    p->payload = destination;
-    p->payload.push_back('\0');
+    p->payload.assign(destination, destination + strlen(destination) + 1);
     p->msg.data_length = p->payload.size();
 
     if (p->msg.data_length > s->get_max_payload()) {
@@ -612,7 +611,7 @@
 
 #endif  // ADB_HOST
 
-static int smart_socket_enqueue(asocket* s, std::string data) {
+static int smart_socket_enqueue(asocket* s, apacket::payload_type data) {
 #if ADB_HOST
     char* service = nullptr;
     char* serial = nullptr;
@@ -623,7 +622,8 @@
     D("SS(%d): enqueue %zu", s->id, data.size());
 
     if (s->smart_socket_data.empty()) {
-        s->smart_socket_data = std::move(data);
+        // TODO: Make this a BlockChain?
+        s->smart_socket_data.assign(data.begin(), data.end());
     } else {
         std::copy(data.begin(), data.end(), std::back_inserter(s->smart_socket_data));
     }
@@ -750,7 +750,7 @@
     if (!s->transport) {
         SendFail(s->peer->fd, "device offline (no transport)");
         goto fail;
-    } else if (s->transport->GetConnectionState() == kCsOffline) {
+    } else if (!ConnectionStateIsOnline(s->transport->GetConnectionState())) {
         /* if there's no remote we fail the connection
          ** right here and terminate it
          */
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index edeacc1..3be99f6 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -92,11 +92,6 @@
     return 0;
 }
 
-static __inline__  unsigned long adb_thread_id()
-{
-    return GetCurrentThreadId();
-}
-
 static __inline__ void  close_on_exec(int  fd)
 {
     /* nothing really */
@@ -621,11 +616,6 @@
     return path[0] == '/';
 }
 
-static __inline__ unsigned long adb_thread_id()
-{
-    return (unsigned long)gettid();
-}
-
 #endif /* !_WIN32 */
 
 static inline void disable_tcp_nagle(int fd) {
diff --git a/adb/sysdeps/uio.h b/adb/sysdeps/uio.h
new file mode 100644
index 0000000..d06ef89
--- /dev/null
+++ b/adb/sysdeps/uio.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <sys/types.h>
+
+#if defined(_WIN32)
+
+// Layout of this struct must match struct WSABUF (verified via static assert in sysdeps_win32.cpp)
+struct adb_iovec {
+    size_t iov_len;
+    void* iov_base;
+};
+
+ssize_t adb_writev(int fd, const adb_iovec* iov, int iovcnt);
+
+#else
+
+#include <sys/uio.h>
+using adb_iovec = struct iovec;
+#define adb_writev writev
+
+#endif
+
+#pragma GCC poison writev
diff --git a/adb/sysdeps_test.cpp b/adb/sysdeps_test.cpp
index fd19882..79cebe6 100644
--- a/adb/sysdeps_test.cpp
+++ b/adb/sysdeps_test.cpp
@@ -121,10 +121,13 @@
     adb_pollfd pfd[3] = {};
     pfd[0].fd = fds[0];
     pfd[0].events = POLLRDNORM;
+    pfd[0].revents = ~0;
     pfd[1].fd = INT_MAX;
     pfd[1].events = POLLRDNORM;
+    pfd[1].revents = ~0;
     pfd[2].fd = fds[1];
     pfd[2].events = POLLWRNORM;
+    pfd[2].revents = ~0;
 
     ASSERT_TRUE(WriteFdExactly(fds[1], "foo", 4));
 
@@ -136,6 +139,17 @@
     EXPECT_EQ(POLLRDNORM, pfd[0].revents);
     EXPECT_EQ(POLLNVAL, pfd[1].revents);
     EXPECT_EQ(POLLWRNORM, pfd[2].revents);
+
+    // Make sure that we return immediately if an invalid FD is given.
+    pfd[0].fd = fds[0];
+    pfd[0].events = POLLRDNORM;
+    pfd[0].revents = ~0;
+    pfd[1].fd = INT_MAX;
+    pfd[1].events = POLLRDNORM;
+    pfd[1].revents = ~0;
+    EXPECT_EQ(2, adb_poll(pfd, 2, -1));
+    EXPECT_EQ(POLLRDNORM, pfd[0].revents);
+    EXPECT_EQ(POLLNVAL, pfd[1].revents);
 }
 
 TEST_F(sysdeps_poll, duplicate_fd) {
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index 62f4ac8..bfac342 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -36,6 +36,7 @@
 
 #include <android-base/errors.h>
 #include <android-base/logging.h>
+#include <android-base/macros.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/utf8.h>
@@ -43,6 +44,8 @@
 #include "adb.h"
 #include "adb_utils.h"
 
+#include "sysdeps/uio.h"
+
 extern void fatal(const char *fmt, ...);
 
 /* forward declarations */
@@ -57,6 +60,7 @@
     int (*_fh_lseek)(FH, int, int);
     int (*_fh_read)(FH, void*, int);
     int (*_fh_write)(FH, const void*, int);
+    int (*_fh_writev)(FH, const adb_iovec*, int);
 } FHClassRec;
 
 static void _fh_file_init(FH);
@@ -64,6 +68,7 @@
 static int _fh_file_lseek(FH, int, int);
 static int _fh_file_read(FH, void*, int);
 static int _fh_file_write(FH, const void*, int);
+static int _fh_file_writev(FH, const adb_iovec*, int);
 
 static const FHClassRec _fh_file_class = {
     _fh_file_init,
@@ -71,6 +76,7 @@
     _fh_file_lseek,
     _fh_file_read,
     _fh_file_write,
+    _fh_file_writev,
 };
 
 static void _fh_socket_init(FH);
@@ -78,6 +84,7 @@
 static int _fh_socket_lseek(FH, int, int);
 static int _fh_socket_read(FH, void*, int);
 static int _fh_socket_write(FH, const void*, int);
+static int _fh_socket_writev(FH, const adb_iovec*, int);
 
 static const FHClassRec _fh_socket_class = {
     _fh_socket_init,
@@ -85,6 +92,7 @@
     _fh_socket_lseek,
     _fh_socket_read,
     _fh_socket_write,
+    _fh_socket_writev,
 };
 
 #define assert(cond)                                                                       \
@@ -248,57 +256,88 @@
 /**************************************************************************/
 /**************************************************************************/
 
-static void _fh_file_init( FH  f ) {
+static void _fh_file_init(FH f) {
     f->fh_handle = INVALID_HANDLE_VALUE;
 }
 
-static int _fh_file_close( FH  f ) {
-    CloseHandle( f->fh_handle );
+static int _fh_file_close(FH f) {
+    CloseHandle(f->fh_handle);
     f->fh_handle = INVALID_HANDLE_VALUE;
     return 0;
 }
 
-static int _fh_file_read( FH  f,  void*  buf, int   len ) {
-    DWORD  read_bytes;
+static int _fh_file_read(FH f, void* buf, int len) {
+    DWORD read_bytes;
 
-    if ( !ReadFile( f->fh_handle, buf, (DWORD)len, &read_bytes, NULL ) ) {
-        D( "adb_read: could not read %d bytes from %s", len, f->name );
+    if (!ReadFile(f->fh_handle, buf, (DWORD)len, &read_bytes, NULL)) {
+        D("adb_read: could not read %d bytes from %s", len, f->name);
         errno = EIO;
         return -1;
     } else if (read_bytes < (DWORD)len) {
         f->eof = 1;
     }
-    return (int)read_bytes;
+    return read_bytes;
 }
 
-static int _fh_file_write( FH  f,  const void*  buf, int   len ) {
-    DWORD  wrote_bytes;
+static int _fh_file_write(FH f, const void* buf, int len) {
+    DWORD wrote_bytes;
 
-    if ( !WriteFile( f->fh_handle, buf, (DWORD)len, &wrote_bytes, NULL ) ) {
-        D( "adb_file_write: could not write %d bytes from %s", len, f->name );
+    if (!WriteFile(f->fh_handle, buf, (DWORD)len, &wrote_bytes, NULL)) {
+        D("adb_file_write: could not write %d bytes from %s", len, f->name);
         errno = EIO;
         return -1;
     } else if (wrote_bytes < (DWORD)len) {
         f->eof = 1;
     }
-    return  (int)wrote_bytes;
+    return wrote_bytes;
 }
 
-static int _fh_file_lseek( FH  f, int  pos, int  origin ) {
-    DWORD  method;
-    DWORD  result;
+static int _fh_file_writev(FH f, const adb_iovec* iov, int iovcnt) {
+    if (iovcnt <= 0) {
+        errno = EINVAL;
+        return -1;
+    }
 
-    switch (origin)
-    {
-        case SEEK_SET:  method = FILE_BEGIN; break;
-        case SEEK_CUR:  method = FILE_CURRENT; break;
-        case SEEK_END:  method = FILE_END; break;
+    DWORD wrote_bytes = 0;
+
+    for (int i = 0; i < iovcnt; ++i) {
+        ssize_t rc = _fh_file_write(f, iov[i].iov_base, iov[i].iov_len);
+        if (rc == -1) {
+            return wrote_bytes > 0 ? wrote_bytes : -1;
+        } else if (rc == 0) {
+            return wrote_bytes;
+        }
+
+        wrote_bytes += rc;
+
+        if (static_cast<size_t>(rc) < iov[i].iov_len) {
+            return wrote_bytes;
+        }
+    }
+
+    return wrote_bytes;
+}
+
+static int _fh_file_lseek(FH f, int pos, int origin) {
+    DWORD method;
+    DWORD result;
+
+    switch (origin) {
+        case SEEK_SET:
+            method = FILE_BEGIN;
+            break;
+        case SEEK_CUR:
+            method = FILE_CURRENT;
+            break;
+        case SEEK_END:
+            method = FILE_END;
+            break;
         default:
             errno = EINVAL;
             return -1;
     }
 
-    result = SetFilePointer( f->fh_handle, pos, NULL, method );
+    result = SetFilePointer(f->fh_handle, pos, NULL, method);
     if (result == INVALID_SET_FILE_POINTER) {
         errno = EIO;
         return -1;
@@ -308,7 +347,6 @@
     return (int)result;
 }
 
-
 /**************************************************************************/
 /**************************************************************************/
 /*****                                                                *****/
@@ -317,12 +355,11 @@
 /**************************************************************************/
 /**************************************************************************/
 
-int  adb_open(const char*  path, int  options)
-{
-    FH  f;
+int adb_open(const char* path, int options) {
+    FH f;
 
-    DWORD  desiredAccess       = 0;
-    DWORD  shareMode           = FILE_SHARE_READ | FILE_SHARE_WRITE;
+    DWORD desiredAccess = 0;
+    DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
 
     switch (options) {
         case O_RDONLY:
@@ -340,8 +377,8 @@
             return -1;
     }
 
-    f = _fh_alloc( &_fh_file_class );
-    if ( !f ) {
+    f = _fh_alloc(&_fh_file_class);
+    if (!f) {
         return -1;
     }
 
@@ -349,21 +386,21 @@
     if (!android::base::UTF8ToWide(path, &path_wide)) {
         return -1;
     }
-    f->fh_handle = CreateFileW( path_wide.c_str(), desiredAccess, shareMode,
-                                NULL, OPEN_EXISTING, 0, NULL );
+    f->fh_handle =
+        CreateFileW(path_wide.c_str(), desiredAccess, shareMode, NULL, OPEN_EXISTING, 0, NULL);
 
-    if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
+    if (f->fh_handle == INVALID_HANDLE_VALUE) {
         const DWORD err = GetLastError();
         _fh_close(f);
-        D( "adb_open: could not open '%s': ", path );
+        D("adb_open: could not open '%s': ", path);
         switch (err) {
             case ERROR_FILE_NOT_FOUND:
-                D( "file not found" );
+                D("file not found");
                 errno = ENOENT;
                 return -1;
 
             case ERROR_PATH_NOT_FOUND:
-                D( "path not found" );
+                D("path not found");
                 errno = ENOTDIR;
                 return -1;
 
@@ -374,18 +411,17 @@
         }
     }
 
-    snprintf( f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path );
-    D( "adb_open: '%s' => fd %d", path, _fh_to_int(f) );
+    snprintf(f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path);
+    D("adb_open: '%s' => fd %d", path, _fh_to_int(f));
     return _fh_to_int(f);
 }
 
 /* ignore mode on Win32 */
-int  adb_creat(const char*  path, int  mode)
-{
-    FH  f;
+int adb_creat(const char* path, int mode) {
+    FH f;
 
-    f = _fh_alloc( &_fh_file_class );
-    if ( !f ) {
+    f = _fh_alloc(&_fh_file_class);
+    if (!f) {
         return -1;
     }
 
@@ -393,23 +429,21 @@
     if (!android::base::UTF8ToWide(path, &path_wide)) {
         return -1;
     }
-    f->fh_handle = CreateFileW( path_wide.c_str(), GENERIC_WRITE,
-                                FILE_SHARE_READ | FILE_SHARE_WRITE,
-                                NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
-                                NULL );
+    f->fh_handle = CreateFileW(path_wide.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+                               NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
 
-    if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
+    if (f->fh_handle == INVALID_HANDLE_VALUE) {
         const DWORD err = GetLastError();
         _fh_close(f);
-        D( "adb_creat: could not open '%s': ", path );
+        D("adb_creat: could not open '%s': ", path);
         switch (err) {
             case ERROR_FILE_NOT_FOUND:
-                D( "file not found" );
+                D("file not found");
                 errno = ENOENT;
                 return -1;
 
             case ERROR_PATH_NOT_FOUND:
-                D( "path not found" );
+                D("path not found");
                 errno = ENOTDIR;
                 return -1;
 
@@ -419,57 +453,64 @@
                 return -1;
         }
     }
-    snprintf( f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path );
-    D( "adb_creat: '%s' => fd %d", path, _fh_to_int(f) );
+    snprintf(f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path);
+    D("adb_creat: '%s' => fd %d", path, _fh_to_int(f));
     return _fh_to_int(f);
 }
 
-
-int  adb_read(int  fd, void* buf, int len)
-{
-    FH     f = _fh_from_int(fd, __func__);
+int adb_read(int fd, void* buf, int len) {
+    FH f = _fh_from_int(fd, __func__);
 
     if (f == NULL) {
+        errno = EBADF;
         return -1;
     }
 
-    return f->clazz->_fh_read( f, buf, len );
+    return f->clazz->_fh_read(f, buf, len);
 }
 
-
-int  adb_write(int  fd, const void*  buf, int  len)
-{
-    FH     f = _fh_from_int(fd, __func__);
+int adb_write(int fd, const void* buf, int len) {
+    FH f = _fh_from_int(fd, __func__);
 
     if (f == NULL) {
+        errno = EBADF;
         return -1;
     }
 
     return f->clazz->_fh_write(f, buf, len);
 }
 
+ssize_t adb_writev(int fd, const adb_iovec* iov, int iovcnt) {
+    FH f = _fh_from_int(fd, __func__);
 
-int  adb_lseek(int  fd, int  pos, int  where)
-{
-    FH     f = _fh_from_int(fd, __func__);
+    if (f == NULL) {
+        errno = EBADF;
+        return -1;
+    }
+
+    return f->clazz->_fh_writev(f, iov, iovcnt);
+}
+
+int adb_lseek(int fd, int pos, int where) {
+    FH f = _fh_from_int(fd, __func__);
 
     if (!f) {
+        errno = EBADF;
         return -1;
     }
 
     return f->clazz->_fh_lseek(f, pos, where);
 }
 
-
-int  adb_close(int  fd)
-{
-    FH   f = _fh_from_int(fd, __func__);
+int adb_close(int fd) {
+    FH f = _fh_from_int(fd, __func__);
 
     if (!f) {
+        errno = EBADF;
         return -1;
     }
 
-    D( "adb_close: %s", f->name);
+    D("adb_close: %s", f->name);
     _fh_close(f);
     return 0;
 }
@@ -529,6 +570,7 @@
     int skipped = 0;
     std::vector<WSAPOLLFD> sockets;
     std::vector<adb_pollfd*> original;
+
     for (size_t i = 0; i < nfds; ++i) {
         FH fh = _fh_from_int(fds[i].fd, __func__);
         if (!fh || !fh->used || fh->clazz != &_fh_socket_class) {
@@ -549,6 +591,11 @@
         return skipped;
     }
 
+    // If we have any invalid FDs in our FD set, make sure to return immediately.
+    if (skipped > 0) {
+        timeout = 0;
+    }
+
     int result = WSAPoll(sockets.data(), sockets.size(), timeout);
     if (result == SOCKET_ERROR) {
         _socket_set_errno(WSAGetLastError());
@@ -560,7 +607,7 @@
         original[i]->revents = sockets[i].revents;
     }
 
-    // WSAPoll appears to return the number of unique FDs with avaiable events, instead of how many
+    // WSAPoll appears to return the number of unique FDs with available events, instead of how many
     // of the pollfd elements have a non-zero revents field, which is what it and poll are specified
     // to do. Ignore its result and calculate the proper return value.
     result = 0;
@@ -576,7 +623,7 @@
     f->fh_socket = INVALID_SOCKET;
 }
 
-static int _fh_socket_close( FH  f ) {
+static int _fh_socket_close(FH f) {
     if (f->fh_socket != INVALID_SOCKET) {
         /* gently tell any peer that we're closing the socket */
         if (shutdown(f->fh_socket, SD_BOTH) == SOCKET_ERROR) {
@@ -597,13 +644,13 @@
     return 0;
 }
 
-static int _fh_socket_lseek( FH  f, int pos, int origin ) {
+static int _fh_socket_lseek(FH f, int pos, int origin) {
     errno = EPIPE;
     return -1;
 }
 
 static int _fh_socket_read(FH f, void* buf, int len) {
-    int  result = recv(f->fh_socket, reinterpret_cast<char*>(buf), len, 0);
+    int result = recv(f->fh_socket, reinterpret_cast<char*>(buf), len, 0);
     if (result == SOCKET_ERROR) {
         const DWORD err = WSAGetLastError();
         // WSAEWOULDBLOCK is normal with a non-blocking socket, so don't trace
@@ -615,11 +662,11 @@
         _socket_set_errno(err);
         result = -1;
     }
-    return  result;
+    return result;
 }
 
 static int _fh_socket_write(FH f, const void* buf, int len) {
-    int  result = send(f->fh_socket, reinterpret_cast<const char*>(buf), len, 0);
+    int result = send(f->fh_socket, reinterpret_cast<const char*>(buf), len, 0);
     if (result == SOCKET_ERROR) {
         const DWORD err = WSAGetLastError();
         // WSAEWOULDBLOCK is normal with a non-blocking socket, so don't trace
@@ -633,13 +680,44 @@
     } else {
         // According to https://code.google.com/p/chromium/issues/detail?id=27870
         // Winsock Layered Service Providers may cause this.
-        CHECK_LE(result, len) << "Tried to write " << len << " bytes to "
-                              << f->name << ", but " << result
-                              << " bytes reportedly written";
+        CHECK_LE(result, len) << "Tried to write " << len << " bytes to " << f->name << ", but "
+                              << result << " bytes reportedly written";
     }
     return result;
 }
 
+// Make sure that adb_iovec is compatible with WSABUF.
+static_assert(sizeof(adb_iovec) == sizeof(WSABUF), "");
+static_assert(SIZEOF_MEMBER(adb_iovec, iov_len) == SIZEOF_MEMBER(WSABUF, len), "");
+static_assert(offsetof(adb_iovec, iov_len) == offsetof(WSABUF, len), "");
+
+static_assert(SIZEOF_MEMBER(adb_iovec, iov_base) == SIZEOF_MEMBER(WSABUF, buf), "");
+static_assert(offsetof(adb_iovec, iov_base) == offsetof(WSABUF, buf), "");
+
+static int _fh_socket_writev(FH f, const adb_iovec* iov, int iovcnt) {
+    if (iovcnt <= 0) {
+        errno = EINVAL;
+        return -1;
+    }
+
+    WSABUF* wsabuf = reinterpret_cast<WSABUF*>(const_cast<adb_iovec*>(iov));
+    DWORD bytes_written = 0;
+    int result = WSASend(f->fh_socket, wsabuf, iovcnt, &bytes_written, 0, nullptr, nullptr);
+    if (result == SOCKET_ERROR) {
+        const DWORD err = WSAGetLastError();
+        // WSAEWOULDBLOCK is normal with a non-blocking socket, so don't trace
+        // that to reduce spam and confusion.
+        if (err != WSAEWOULDBLOCK) {
+            D("send fd %d failed: %s", _fh_to_int(f),
+              android::base::SystemErrorCodeToString(err).c_str());
+        }
+        _socket_set_errno(err);
+        result = -1;
+    }
+    CHECK_GE(static_cast<DWORD>(std::numeric_limits<int>::max()), bytes_written);
+    return static_cast<int>(bytes_written);
+}
+
 /**************************************************************************/
 /**************************************************************************/
 /*****                                                                *****/
@@ -648,23 +726,15 @@
 /**************************************************************************/
 /**************************************************************************/
 
-#include <winsock2.h>
-
-static int  _winsock_init;
-
-static void
-_init_winsock( void )
-{
-    // TODO: Multiple threads calling this may potentially cause multiple calls
-    // to WSAStartup() which offers no real benefit.
-    if (!_winsock_init) {
-        WSADATA  wsaData;
-        int      rc = WSAStartup( MAKEWORD(2,2), &wsaData);
+static int _init_winsock(void) {
+    static std::once_flag once;
+    std::call_once(once, []() {
+        WSADATA wsaData;
+        int rc = WSAStartup(MAKEWORD(2, 2), &wsaData);
         if (rc != 0) {
             fatal("adb: could not initialize Winsock: %s",
                   android::base::SystemErrorCodeToString(rc).c_str());
         }
-        _winsock_init = 1;
 
         // Note that we do not call atexit() to register WSACleanup to be called
         // at normal process termination because:
@@ -679,9 +749,12 @@
         //    setupapi.dll which tries to load wintrust.dll which tries to load
         //    crypt32.dll which calls atexit() which tries to acquire the C
         //    Runtime lock that the other thread holds.
-    }
+    });
+    return 0;
 }
 
+static int _winsock_init = _init_winsock();
+
 // Map a socket type to an explicit socket protocol instead of using the socket
 // protocol of 0. Explicit socket protocols are used by most apps and we should
 // do the same to reduce the chance of exercising uncommon code-paths that might
@@ -709,8 +782,6 @@
         return -1;
     }
 
-    if (!_winsock_init) _init_winsock();
-
     memset(&addr, 0, sizeof(addr));
     addr.sin_family = AF_INET;
     addr.sin_port = htons(port);
@@ -759,8 +830,6 @@
         return -1;
     }
 
-    if (!_winsock_init) _init_winsock();
-
     memset(&addr, 0, sizeof(addr));
     addr.sin_family = AF_INET;
     addr.sin_port = htons(port);
@@ -837,8 +906,6 @@
         return -1;
     }
 
-    if (!_winsock_init) _init_winsock();
-
     struct addrinfo hints;
     memset(&hints, 0, sizeof(hints));
     hints.ai_family = AF_UNSPEC;
@@ -906,52 +973,49 @@
     return fd;
 }
 
-int  adb_register_socket(SOCKET s) {
-    FH f = _fh_alloc( &_fh_socket_class );
+int adb_register_socket(SOCKET s) {
+    FH f = _fh_alloc(&_fh_socket_class);
     f->fh_socket = s;
     return _fh_to_int(f);
 }
 
 #undef accept
-int  adb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen)
-{
-    FH   serverfh = _fh_from_int(serverfd, __func__);
+int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t* addrlen) {
+    FH serverfh = _fh_from_int(serverfd, __func__);
 
-    if ( !serverfh || serverfh->clazz != &_fh_socket_class ) {
+    if (!serverfh || serverfh->clazz != &_fh_socket_class) {
         D("adb_socket_accept: invalid fd %d", serverfd);
         errno = EBADF;
         return -1;
     }
 
-    unique_fh fh(_fh_alloc( &_fh_socket_class ));
+    unique_fh fh(_fh_alloc(&_fh_socket_class));
     if (!fh) {
         PLOG(ERROR) << "adb_socket_accept: failed to allocate accepted socket "
                        "descriptor";
         return -1;
     }
 
-    fh->fh_socket = accept( serverfh->fh_socket, addr, addrlen );
+    fh->fh_socket = accept(serverfh->fh_socket, addr, addrlen);
     if (fh->fh_socket == INVALID_SOCKET) {
         const DWORD err = WSAGetLastError();
-        LOG(ERROR) << "adb_socket_accept: accept on fd " << serverfd <<
-                      " failed: " + android::base::SystemErrorCodeToString(err);
-        _socket_set_errno( err );
+        LOG(ERROR) << "adb_socket_accept: accept on fd " << serverfd
+                   << " failed: " + android::base::SystemErrorCodeToString(err);
+        _socket_set_errno(err);
         return -1;
     }
 
     const int fd = _fh_to_int(fh.get());
-    snprintf( fh->name, sizeof(fh->name), "%d(accept:%s)", fd, serverfh->name );
-    D( "adb_socket_accept on fd %d returns fd %d", serverfd, fd );
+    snprintf(fh->name, sizeof(fh->name), "%d(accept:%s)", fd, serverfh->name);
+    D("adb_socket_accept on fd %d returns fd %d", serverfd, fd);
     fh.release();
-    return  fd;
+    return fd;
 }
 
+int adb_setsockopt(int fd, int level, int optname, const void* optval, socklen_t optlen) {
+    FH fh = _fh_from_int(fd, __func__);
 
-int  adb_setsockopt( int  fd, int  level, int  optname, const void*  optval, socklen_t  optlen )
-{
-    FH   fh = _fh_from_int(fd, __func__);
-
-    if ( !fh || fh->clazz != &_fh_socket_class ) {
+    if (!fh || fh->clazz != &_fh_socket_class) {
         D("adb_setsockopt: invalid fd %d", fd);
         errno = EBADF;
         return -1;
@@ -961,13 +1025,13 @@
     // to set SOL_SOCKET, SO_SNDBUF/SO_RCVBUF, ignore it since the OS has
     // auto-tuning.
 
-    int result = setsockopt( fh->fh_socket, level, optname,
-                             reinterpret_cast<const char*>(optval), optlen );
-    if ( result == SOCKET_ERROR ) {
+    int result =
+        setsockopt(fh->fh_socket, level, optname, reinterpret_cast<const char*>(optval), optlen);
+    if (result == SOCKET_ERROR) {
         const DWORD err = WSAGetLastError();
-        D("adb_setsockopt: setsockopt on fd %d level %d optname %d failed: %s\n",
-          fd, level, optname, android::base::SystemErrorCodeToString(err).c_str());
-        _socket_set_errno( err );
+        D("adb_setsockopt: setsockopt on fd %d level %d optname %d failed: %s\n", fd, level,
+          optname, android::base::SystemErrorCodeToString(err).c_str());
+        _socket_set_errno(err);
         result = -1;
     }
     return result;
diff --git a/adb/test_adb.py b/adb/test_adb.py
index e771106..ddd3ff0 100644
--- a/adb/test_adb.py
+++ b/adb/test_adb.py
@@ -21,9 +21,11 @@
 """
 from __future__ import print_function
 
+import binascii
 import contextlib
 import os
 import random
+import select
 import socket
 import struct
 import subprocess
@@ -33,8 +35,117 @@
 import adb
 
 
-class NonApiTest(unittest.TestCase):
-    """Tests for ADB that aren't a part of the AndroidDevice API."""
+@contextlib.contextmanager
+def fake_adbd(protocol=socket.AF_INET, port=0):
+    """Creates a fake ADB daemon that just replies with a CNXN packet."""
+
+    serversock = socket.socket(protocol, socket.SOCK_STREAM)
+    serversock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+    if protocol == socket.AF_INET:
+        serversock.bind(('127.0.0.1', port))
+    else:
+        serversock.bind(('::1', port))
+    serversock.listen(1)
+
+    # A pipe that is used to signal the thread that it should terminate.
+    readpipe, writepipe = os.pipe()
+
+    def _adb_packet(command, arg0, arg1, data):
+        bin_command = struct.unpack('I', command)[0]
+        buf = struct.pack('IIIIII', bin_command, arg0, arg1, len(data), 0,
+                          bin_command ^ 0xffffffff)
+        buf += data
+        return buf
+
+    def _handle():
+        rlist = [readpipe, serversock]
+        cnxn_sent = {}
+        while True:
+            read_ready, _, _ = select.select(rlist, [], [])
+            for ready in read_ready:
+                if ready == readpipe:
+                    # Closure pipe
+                    os.close(ready)
+                    serversock.shutdown(socket.SHUT_RDWR)
+                    serversock.close()
+                    return
+                elif ready == serversock:
+                    # Server socket
+                    conn, _ = ready.accept()
+                    rlist.append(conn)
+                else:
+                    # Client socket
+                    data = ready.recv(1024)
+                    if not data or data.startswith('OPEN'):
+                        if ready in cnxn_sent:
+                            del cnxn_sent[ready]
+                        ready.shutdown(socket.SHUT_RDWR)
+                        ready.close()
+                        rlist.remove(ready)
+                        continue
+                    if ready in cnxn_sent:
+                        continue
+                    cnxn_sent[ready] = True
+                    ready.sendall(_adb_packet('CNXN', 0x01000001, 1024 * 1024,
+                                              'device::ro.product.name=fakeadb'))
+
+    port = serversock.getsockname()[1]
+    server_thread = threading.Thread(target=_handle)
+    server_thread.start()
+
+    try:
+        yield port
+    finally:
+        os.close(writepipe)
+        server_thread.join()
+
+
+@contextlib.contextmanager
+def adb_connect(unittest, serial):
+    """Context manager for an ADB connection.
+
+    This automatically disconnects when done with the connection.
+    """
+
+    output = subprocess.check_output(['adb', 'connect', serial])
+    unittest.assertEqual(output.strip(), 'connected to {}'.format(serial))
+
+    try:
+        yield
+    finally:
+        # Perform best-effort disconnection. Discard the output.
+        subprocess.Popen(['adb', 'disconnect', serial],
+                         stdout=subprocess.PIPE,
+                         stderr=subprocess.PIPE).communicate()
+
+
+@contextlib.contextmanager
+def adb_server():
+    """Context manager for an ADB server.
+
+    This creates an ADB server and returns the port it's listening on.
+    """
+
+    port = 5038
+    # Kill any existing server on this non-default port.
+    subprocess.check_output(['adb', '-P', str(port), 'kill-server'],
+                            stderr=subprocess.STDOUT)
+    read_pipe, write_pipe = os.pipe()
+    proc = subprocess.Popen(['adb', '-L', 'tcp:localhost:{}'.format(port),
+                             'fork-server', 'server',
+                             '--reply-fd', str(write_pipe)])
+    try:
+        os.close(write_pipe)
+        greeting = os.read(read_pipe, 1024)
+        assert greeting == 'OK\n', repr(greeting)
+        yield port
+    finally:
+        proc.terminate()
+        proc.wait()
+
+
+class CommandlineTest(unittest.TestCase):
+    """Tests for the ADB commandline."""
 
     def test_help(self):
         """Make sure we get _something_ out of help."""
@@ -56,28 +167,37 @@
                 revision_line, r'^Revision [0-9a-f]{12}-android$')
 
     def test_tcpip_error_messages(self):
-        p = subprocess.Popen(['adb', 'tcpip'], stdout=subprocess.PIPE,
-                             stderr=subprocess.STDOUT)
-        out, _ = p.communicate()
-        self.assertEqual(1, p.returncode)
+        """Make sure 'adb tcpip' parsing is sane."""
+        proc = subprocess.Popen(['adb', 'tcpip'], stdout=subprocess.PIPE,
+                                stderr=subprocess.STDOUT)
+        out, _ = proc.communicate()
+        self.assertEqual(1, proc.returncode)
         self.assertIn('requires an argument', out)
 
-        p = subprocess.Popen(['adb', 'tcpip', 'foo'], stdout=subprocess.PIPE,
-                             stderr=subprocess.STDOUT)
-        out, _ = p.communicate()
-        self.assertEqual(1, p.returncode)
+        proc = subprocess.Popen(['adb', 'tcpip', 'foo'], stdout=subprocess.PIPE,
+                                stderr=subprocess.STDOUT)
+        out, _ = proc.communicate()
+        self.assertEqual(1, proc.returncode)
         self.assertIn('invalid port', out)
 
-    # Helper method that reads a pipe until it is closed, then sets the event.
-    def _read_pipe_and_set_event(self, pipe, event):
-        x = pipe.read()
+
+class ServerTest(unittest.TestCase):
+    """Tests for the ADB server."""
+
+    @staticmethod
+    def _read_pipe_and_set_event(pipe, event):
+        """Reads a pipe until it is closed, then sets the event."""
+        pipe.read()
         event.set()
 
-    # Test that launch_server() does not let the adb server inherit
-    # stdin/stdout/stderr handles which can cause callers of adb.exe to hang.
-    # This test also runs fine on unix even though the impetus is an issue
-    # unique to Windows.
     def test_handle_inheritance(self):
+        """Test that launch_server() does not inherit handles.
+
+        launch_server() should not let the adb server inherit
+        stdin/stdout/stderr handles, which can cause callers of adb.exe to hang.
+        This test also runs fine on unix even though the impetus is an issue
+        unique to Windows.
+        """
         # This test takes 5 seconds to run on Windows: if there is no adb server
         # running on the the port used below, adb kill-server tries to make a
         # TCP connection to a closed port and that takes 1 second on Windows;
@@ -99,29 +219,30 @@
 
         try:
             # Run the adb client and have it start the adb server.
-            p = subprocess.Popen(['adb', '-P', str(port), 'start-server'],
-                                 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
-                                 stderr=subprocess.PIPE)
+            proc = subprocess.Popen(['adb', '-P', str(port), 'start-server'],
+                                    stdin=subprocess.PIPE,
+                                    stdout=subprocess.PIPE,
+                                    stderr=subprocess.PIPE)
 
             # Start threads that set events when stdout/stderr are closed.
             stdout_event = threading.Event()
             stdout_thread = threading.Thread(
-                    target=self._read_pipe_and_set_event,
-                    args=(p.stdout, stdout_event))
+                target=ServerTest._read_pipe_and_set_event,
+                args=(proc.stdout, stdout_event))
             stdout_thread.daemon = True
             stdout_thread.start()
 
             stderr_event = threading.Event()
             stderr_thread = threading.Thread(
-                    target=self._read_pipe_and_set_event,
-                    args=(p.stderr, stderr_event))
+                target=ServerTest._read_pipe_and_set_event,
+                args=(proc.stderr, stderr_event))
             stderr_thread.daemon = True
             stderr_thread.start()
 
             # Wait for the adb client to finish. Once that has occurred, if
             # stdin/stderr/stdout are still open, it must be open in the adb
             # server.
-            p.wait()
+            proc.wait()
 
             # Try to write to stdin which we expect is closed. If it isn't
             # closed, we should get an IOError. If we don't get an IOError,
@@ -129,7 +250,7 @@
             # probably letting the adb server inherit stdin which would be
             # wrong.
             with self.assertRaises(IOError):
-                p.stdin.write('x')
+                proc.stdin.write('x')
 
             # Wait a few seconds for stdout/stderr to be closed (in the success
             # case, this won't wait at all). If there is a timeout, that means
@@ -143,8 +264,12 @@
             subprocess.check_output(['adb', '-P', str(port), 'kill-server'],
                                     stderr=subprocess.STDOUT)
 
-    # Use SO_LINGER to cause TCP RST segment to be sent on socket close.
+
+class EmulatorTest(unittest.TestCase):
+    """Tests for the emulator connection."""
+
     def _reset_socket_on_close(self, sock):
+        """Use SO_LINGER to cause TCP RST segment to be sent on socket close."""
         # The linger structure is two shorts on Windows, but two ints on Unix.
         linger_format = 'hh' if os.name == 'nt' else 'ii'
         l_onoff = 1
@@ -162,19 +287,18 @@
 
         Bug: https://code.google.com/p/android/issues/detail?id=21021
         """
-        port = 12345
-
         with contextlib.closing(
-                socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as listener:
+            socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as listener:
             # Use SO_REUSEADDR so subsequent runs of the test can grab the port
             # even if it is in TIME_WAIT.
             listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-            listener.bind(('127.0.0.1', port))
+            listener.bind(('127.0.0.1', 0))
             listener.listen(4)
+            port = listener.getsockname()[1]
 
             # Now that listening has started, start adb emu kill, telling it to
             # connect to our mock emulator.
-            p = subprocess.Popen(
+            proc = subprocess.Popen(
                 ['adb', '-s', 'emulator-' + str(port), 'emu', 'kill'],
                 stderr=subprocess.STDOUT)
 
@@ -183,12 +307,16 @@
                 # If WSAECONNABORTED (10053) is raised by any socket calls,
                 # then adb probably isn't reading the data that we sent it.
                 conn.sendall('Android Console: type \'help\' for a list ' +
-                                'of commands\r\n')
+                             'of commands\r\n')
                 conn.sendall('OK\r\n')
 
-                with contextlib.closing(conn.makefile()) as f:
-                    self.assertEqual('kill\n', f.readline())
-                    self.assertEqual('quit\n', f.readline())
+                with contextlib.closing(conn.makefile()) as connf:
+                    line = connf.readline()
+                    if line.startswith('auth'):
+                        # Ignore the first auth line.
+                        line = connf.readline()
+                    self.assertEqual('kill\n', line)
+                    self.assertEqual('quit\n', connf.readline())
 
                 conn.sendall('OK: killing emulator, bye bye\r\n')
 
@@ -201,46 +329,117 @@
                 self._reset_socket_on_close(conn)
 
             # Wait for adb to finish, so we can check return code.
-            p.communicate()
+            proc.communicate()
 
             # If this fails, adb probably isn't ignoring WSAECONNRESET when
             # reading the response from the adb emu kill command (on Windows).
-            self.assertEqual(0, p.returncode)
+            self.assertEqual(0, proc.returncode)
+
+    def test_emulator_connect(self):
+        """Ensure that the emulator can connect.
+
+        Bug: http://b/78991667
+        """
+        with adb_server() as server_port:
+            with fake_adbd() as port:
+                serial = 'emulator-{}'.format(port - 1)
+                # Ensure that the emulator is not there.
+                try:
+                    subprocess.check_output(['adb', '-P', str(server_port),
+                                             '-s', serial, 'get-state'],
+                                            stderr=subprocess.STDOUT)
+                    self.fail('Device should not be available')
+                except subprocess.CalledProcessError as err:
+                    self.assertEqual(
+                        err.output.strip(),
+                        'error: device \'{}\' not found'.format(serial))
+
+                # Let the ADB server know that the emulator has started.
+                with contextlib.closing(
+                    socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
+                    sock.connect(('localhost', server_port))
+                    command = 'host:emulator:{}'.format(port)
+                    sock.sendall('%04x%s' % (len(command), command))
+
+                # Ensure the emulator is there.
+                subprocess.check_call(['adb', '-P', str(server_port),
+                                       '-s', serial, 'wait-for-device'])
+                output = subprocess.check_output(['adb', '-P', str(server_port),
+                                                  '-s', serial, 'get-state'])
+                self.assertEqual(output.strip(), 'device')
+
+
+class ConnectionTest(unittest.TestCase):
+    """Tests for adb connect."""
 
     def test_connect_ipv4_ipv6(self):
         """Ensure that `adb connect localhost:1234` will try both IPv4 and IPv6.
 
         Bug: http://b/30313466
         """
-        ipv4 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        ipv4.bind(('127.0.0.1', 0))
-        ipv4.listen(1)
+        for protocol in (socket.AF_INET, socket.AF_INET6):
+            try:
+                with fake_adbd(protocol=protocol) as port:
+                    serial = 'localhost:{}'.format(port)
+                    with adb_connect(self, serial):
+                        pass
+            except socket.error:
+                print("IPv6 not available, skipping")
+                continue
 
-        ipv6 = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
-        try:
-            ipv6.bind(('::1', ipv4.getsockname()[1] + 1))
-            ipv6.listen(1)
-        except socket.error:
-            print("IPv6 not available, skipping")
-            return
+    def test_already_connected(self):
+        """Ensure that an already-connected device stays connected."""
 
-        for s in (ipv4, ipv6):
-            port = s.getsockname()[1]
-            output = subprocess.check_output(
-                ['adb', 'connect', 'localhost:{}'.format(port)])
+        with fake_adbd() as port:
+            serial = 'localhost:{}'.format(port)
+            with adb_connect(self, serial):
+                # b/31250450: this always returns 0 but probably shouldn't.
+                output = subprocess.check_output(['adb', 'connect', serial])
+                self.assertEqual(
+                    output.strip(), 'already connected to {}'.format(serial))
 
-            self.assertEqual(
-                output.strip(), 'connected to localhost:{}'.format(port))
-            s.close()
+    def test_reconnect(self):
+        """Ensure that a disconnected device reconnects."""
+
+        with fake_adbd() as port:
+            serial = 'localhost:{}'.format(port)
+            with adb_connect(self, serial):
+                output = subprocess.check_output(['adb', '-s', serial,
+                                                  'get-state'])
+                self.assertEqual(output.strip(), 'device')
+
+                # This will fail.
+                proc = subprocess.Popen(['adb', '-s', serial, 'shell', 'true'],
+                                        stdout=subprocess.PIPE,
+                                        stderr=subprocess.STDOUT)
+                output, _ = proc.communicate()
+                self.assertEqual(output.strip(), 'error: closed')
+
+                subprocess.check_call(['adb', '-s', serial, 'wait-for-device'])
+
+                output = subprocess.check_output(['adb', '-s', serial,
+                                                  'get-state'])
+                self.assertEqual(output.strip(), 'device')
+
+                # Once we explicitly kick a device, it won't attempt to
+                # reconnect.
+                output = subprocess.check_output(['adb', 'disconnect', serial])
+                self.assertEqual(
+                    output.strip(), 'disconnected {}'.format(serial))
+                try:
+                    subprocess.check_output(['adb', '-s', serial, 'get-state'],
+                                            stderr=subprocess.STDOUT)
+                    self.fail('Device should not be available')
+                except subprocess.CalledProcessError as err:
+                    self.assertEqual(
+                        err.output.strip(),
+                        'error: device \'{}\' not found'.format(serial))
 
 
 def main():
+    """Main entrypoint."""
     random.seed(0)
-    if len(adb.get_devices()) > 0:
-        suite = unittest.TestLoader().loadTestsFromName(__name__)
-        unittest.TextTestRunner(verbosity=3).run(suite)
-    else:
-        print('Test suite must be run with attached devices')
+    unittest.main(verbosity=3)
 
 
 if __name__ == '__main__':
diff --git a/adb/test_device.py b/adb/test_device.py
index 72e1c67..f995be2 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -188,8 +188,6 @@
         finally:
             self.device.reverse_remove_all()
 
-    # Note: If you run this test when adb connect'd to a physical device over
-    # TCP, it will fail in adb reverse due to https://code.google.com/p/android/issues/detail?id=189821
     def test_forward_reverse_echo(self):
         """Send data through adb forward and read it back via adb reverse"""
         forward_port = 12345
@@ -1187,7 +1185,7 @@
         # Verify that the device ended up with the expected UTF-8 path
         output = self.device.shell(
                 ['ls', '/data/local/tmp/adb-test-*'])[0].strip()
-        self.assertEqual(remote_path.encode('utf-8'), output)
+        self.assertEqual(remote_path, output)
 
         # pull.
         self.device.pull(remote_path, tf.name)
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 6b1a00b..beec13a 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -17,6 +17,8 @@
 #define TRACE_TAG TRANSPORT
 
 #include "sysdeps.h"
+#include "sysdeps/memory.h"
+
 #include "transport.h"
 
 #include <ctype.h>
@@ -28,8 +30,10 @@
 #include <unistd.h>
 
 #include <algorithm>
+#include <deque>
 #include <list>
 #include <mutex>
+#include <queue>
 #include <thread>
 
 #include <android-base/logging.h>
@@ -38,15 +42,18 @@
 #include <android-base/strings.h>
 #include <android-base/thread_annotations.h>
 
+#include <diagnose_usb.h>
+
 #include "adb.h"
 #include "adb_auth.h"
 #include "adb_io.h"
 #include "adb_trace.h"
 #include "adb_utils.h"
-#include "diagnose_usb.h"
 #include "fdevent.h"
 
-static void transport_unref(atransport *t);
+static void register_transport(atransport* transport);
+static void remove_transport(atransport* transport);
+static void transport_unref(atransport* transport);
 
 // TODO: unordered_map<TransportId, atransport*>
 static auto& transport_list = *new std::list<atransport*>();
@@ -60,11 +67,254 @@
 const char* const kFeatureLibusb = "libusb";
 const char* const kFeaturePushSync = "push_sync";
 
+namespace {
+
+// A class that helps the Clang Thread Safety Analysis deal with
+// std::unique_lock. Given that std::unique_lock is movable, and the analysis
+// can not currently perform alias analysis, it is not annotated. In order to
+// assert that the mutex is held, a ScopedAssumeLocked can be created just after
+// the std::unique_lock.
+class SCOPED_CAPABILITY ScopedAssumeLocked {
+  public:
+    ScopedAssumeLocked(std::mutex& mutex) ACQUIRE(mutex) {}
+    ~ScopedAssumeLocked() RELEASE() {}
+};
+
+// Tracks and handles atransport*s that are attempting reconnection.
+class ReconnectHandler {
+  public:
+    ReconnectHandler() = default;
+    ~ReconnectHandler() = default;
+
+    // Starts the ReconnectHandler thread.
+    void Start();
+
+    // Requests the ReconnectHandler thread to stop.
+    void Stop();
+
+    // Adds the atransport* to the queue of reconnect attempts.
+    void TrackTransport(atransport* transport);
+
+  private:
+    // The main thread loop.
+    void Run();
+
+    // Tracks a reconnection attempt.
+    struct ReconnectAttempt {
+        atransport* transport;
+        std::chrono::system_clock::time_point deadline;
+        size_t attempts_left;
+    };
+
+    // Only retry for up to one minute.
+    static constexpr const std::chrono::seconds kDefaultTimeout = std::chrono::seconds(10);
+    static constexpr const size_t kMaxAttempts = 6;
+
+    // Protects all members.
+    std::mutex reconnect_mutex_;
+    bool running_ GUARDED_BY(reconnect_mutex_) = true;
+    std::thread handler_thread_;
+    std::condition_variable reconnect_cv_;
+    std::queue<ReconnectAttempt> reconnect_queue_ GUARDED_BY(reconnect_mutex_);
+
+    DISALLOW_COPY_AND_ASSIGN(ReconnectHandler);
+};
+
+void ReconnectHandler::Start() {
+    check_main_thread();
+    handler_thread_ = std::thread(&ReconnectHandler::Run, this);
+}
+
+void ReconnectHandler::Stop() {
+    check_main_thread();
+    {
+        std::lock_guard<std::mutex> lock(reconnect_mutex_);
+        running_ = false;
+    }
+    reconnect_cv_.notify_one();
+    handler_thread_.join();
+
+    // Drain the queue to free all resources.
+    std::lock_guard<std::mutex> lock(reconnect_mutex_);
+    while (!reconnect_queue_.empty()) {
+        ReconnectAttempt attempt = reconnect_queue_.front();
+        reconnect_queue_.pop();
+        remove_transport(attempt.transport);
+    }
+}
+
+void ReconnectHandler::TrackTransport(atransport* transport) {
+    check_main_thread();
+    {
+        std::lock_guard<std::mutex> lock(reconnect_mutex_);
+        if (!running_) return;
+        reconnect_queue_.emplace(ReconnectAttempt{
+            transport, std::chrono::system_clock::now() + ReconnectHandler::kDefaultTimeout,
+            ReconnectHandler::kMaxAttempts});
+    }
+    reconnect_cv_.notify_one();
+}
+
+void ReconnectHandler::Run() {
+    while (true) {
+        ReconnectAttempt attempt;
+        {
+            std::unique_lock<std::mutex> lock(reconnect_mutex_);
+            ScopedAssumeLocked assume_lock(reconnect_mutex_);
+
+            auto deadline = std::chrono::time_point<std::chrono::system_clock>::max();
+            if (!reconnect_queue_.empty()) deadline = reconnect_queue_.front().deadline;
+            reconnect_cv_.wait_until(lock, deadline, [&]() REQUIRES(reconnect_mutex_) {
+                return !running_ ||
+                       (!reconnect_queue_.empty() && reconnect_queue_.front().deadline < deadline);
+            });
+
+            if (!running_) return;
+            attempt = reconnect_queue_.front();
+            reconnect_queue_.pop();
+            if (attempt.transport->kicked()) {
+                D("transport %s was kicked. giving up on it.", attempt.transport->serial);
+                remove_transport(attempt.transport);
+                continue;
+            }
+        }
+        D("attempting to reconnect %s", attempt.transport->serial);
+
+        if (!attempt.transport->Reconnect()) {
+            D("attempting to reconnect %s failed.", attempt.transport->serial);
+            if (attempt.attempts_left == 0) {
+                D("transport %s exceeded the number of retry attempts. giving up on it.",
+                  attempt.transport->serial);
+                remove_transport(attempt.transport);
+                continue;
+            }
+
+            std::lock_guard<std::mutex> lock(reconnect_mutex_);
+            reconnect_queue_.emplace(ReconnectAttempt{
+                attempt.transport,
+                std::chrono::system_clock::now() + ReconnectHandler::kDefaultTimeout,
+                attempt.attempts_left - 1});
+            continue;
+        }
+
+        D("reconnection to %s succeeded.", attempt.transport->serial);
+        register_transport(attempt.transport);
+    }
+}
+
+static auto& reconnect_handler = *new ReconnectHandler();
+
+}  // namespace
+
 TransportId NextTransportId() {
     static std::atomic<TransportId> next(1);
     return next++;
 }
 
+BlockingConnectionAdapter::BlockingConnectionAdapter(std::unique_ptr<BlockingConnection> connection)
+    : underlying_(std::move(connection)) {}
+
+BlockingConnectionAdapter::~BlockingConnectionAdapter() {
+    LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): destructing";
+    Stop();
+}
+
+void BlockingConnectionAdapter::Start() {
+    std::lock_guard<std::mutex> lock(mutex_);
+    if (started_) {
+        LOG(FATAL) << "BlockingConnectionAdapter(" << this->transport_name_
+                   << "): started multiple times";
+    }
+
+    read_thread_ = std::thread([this]() {
+        LOG(INFO) << this->transport_name_ << ": read thread spawning";
+        while (true) {
+            auto packet = std::make_unique<apacket>();
+            if (!underlying_->Read(packet.get())) {
+                PLOG(INFO) << this->transport_name_ << ": read failed";
+                break;
+            }
+            read_callback_(this, std::move(packet));
+        }
+        std::call_once(this->error_flag_, [this]() { this->error_callback_(this, "read failed"); });
+    });
+
+    write_thread_ = std::thread([this]() {
+        LOG(INFO) << this->transport_name_ << ": write thread spawning";
+        while (true) {
+            std::unique_lock<std::mutex> lock(mutex_);
+            ScopedAssumeLocked assume_locked(mutex_);
+            cv_.wait(lock, [this]() REQUIRES(mutex_) {
+                return this->stopped_ || !this->write_queue_.empty();
+            });
+
+            if (this->stopped_) {
+                return;
+            }
+
+            std::unique_ptr<apacket> packet = std::move(this->write_queue_.front());
+            this->write_queue_.pop_front();
+            lock.unlock();
+
+            if (!this->underlying_->Write(packet.get())) {
+                break;
+            }
+        }
+        std::call_once(this->error_flag_, [this]() { this->error_callback_(this, "write failed"); });
+    });
+
+    started_ = true;
+}
+
+void BlockingConnectionAdapter::Stop() {
+    {
+        std::lock_guard<std::mutex> lock(mutex_);
+        if (!started_) {
+            LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): not started";
+            return;
+        }
+
+        if (stopped_) {
+            LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_
+                      << "): already stopped";
+            return;
+        }
+
+        stopped_ = true;
+    }
+
+    LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): stopping";
+
+    this->underlying_->Close();
+    this->cv_.notify_one();
+
+    // Move the threads out into locals with the lock taken, and then unlock to let them exit.
+    std::thread read_thread;
+    std::thread write_thread;
+
+    {
+        std::lock_guard<std::mutex> lock(mutex_);
+        read_thread = std::move(read_thread_);
+        write_thread = std::move(write_thread_);
+    }
+
+    read_thread.join();
+    write_thread.join();
+
+    LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): stopped";
+    std::call_once(this->error_flag_, [this]() { this->error_callback_(this, "requested stop"); });
+}
+
+bool BlockingConnectionAdapter::Write(std::unique_ptr<apacket> packet) {
+    {
+        std::lock_guard<std::mutex> lock(this->mutex_);
+        write_queue_.emplace_back(std::move(packet));
+    }
+
+    cv_.notify_one();
+    return true;
+}
+
 bool FdConnection::Read(apacket* packet) {
     if (!ReadFdExactly(fd_.get(), &packet->msg, sizeof(amessage))) {
         D("remote local: read terminated (message)");
@@ -143,67 +393,6 @@
     return result;
 }
 
-static int read_packet(int fd, const char* name, apacket** ppacket) {
-    ATRACE_NAME("read_packet");
-    char buff[8];
-    if (!name) {
-        snprintf(buff, sizeof buff, "fd=%d", fd);
-        name = buff;
-    }
-    char* p = reinterpret_cast<char*>(ppacket); /* really read a packet address */
-    int len = sizeof(apacket*);
-    while (len > 0) {
-        int r = adb_read(fd, p, len);
-        if (r > 0) {
-            len -= r;
-            p += r;
-        } else {
-            D("%s: read_packet (fd=%d), error ret=%d: %s", name, fd, r, strerror(errno));
-            return -1;
-        }
-    }
-
-    VLOG(TRANSPORT) << dump_packet(name, "from remote", *ppacket);
-    return 0;
-}
-
-static int write_packet(int fd, const char* name, apacket** ppacket) {
-    ATRACE_NAME("write_packet");
-    char buff[8];
-    if (!name) {
-        snprintf(buff, sizeof buff, "fd=%d", fd);
-        name = buff;
-    }
-    VLOG(TRANSPORT) << dump_packet(name, "to remote", *ppacket);
-    char* p = reinterpret_cast<char*>(ppacket); /* we really write the packet address */
-    int len = sizeof(apacket*);
-    while (len > 0) {
-        int r = adb_write(fd, p, len);
-        if (r > 0) {
-            len -= r;
-            p += r;
-        } else {
-            D("%s: write_packet (fd=%d) error ret=%d: %s", name, fd, r, strerror(errno));
-            return -1;
-        }
-    }
-    return 0;
-}
-
-static void transport_socket_events(int fd, unsigned events, void* _t) {
-    atransport* t = reinterpret_cast<atransport*>(_t);
-    D("transport_socket_events(fd=%d, events=%04x,...)", fd, events);
-    if (events & FDE_READ) {
-        apacket* p = 0;
-        if (read_packet(fd, t->serial, &p)) {
-            D("%s: failed to read packet from transport socket on fd %d", t->serial, fd);
-            return;
-        }
-
-        handle_packet(p, (atransport*)_t);
-    }
-}
-
 void send_packet(apacket* p, atransport* t) {
     p->msg.magic = p->msg.command ^ 0xffffffff;
     // compute a checksum for connection/auth packets for compatibility reasons
@@ -213,162 +402,18 @@
         p->msg.data_check = calculate_apacket_checksum(p);
     }
 
-    print_packet("send", p);
+    VLOG(TRANSPORT) << dump_packet(t->serial, "to remote", p);
 
     if (t == NULL) {
         fatal("Transport is null");
     }
 
-    if (write_packet(t->transport_socket, t->serial, &p)) {
-        fatal_errno("cannot enqueue packet on transport socket");
+    if (t->Write(p) != 0) {
+        D("%s: failed to enqueue packet, closing transport", t->serial);
+        t->Kick();
     }
 }
 
-// The transport is opened by transport_register_func before
-// the read_transport and write_transport threads are started.
-//
-// The read_transport thread issues a SYNC(1, token) message to let
-// the write_transport thread know to start things up.  In the event
-// of transport IO failure, the read_transport thread will post a
-// SYNC(0,0) message to ensure shutdown.
-//
-// The transport will not actually be closed until both threads exit, but the threads
-// will kick the transport on their way out to disconnect the underlying device.
-//
-// read_transport thread reads data from a transport (representing a usb/tcp connection),
-// and makes the main thread call handle_packet().
-static void read_transport_thread(void* _t) {
-    atransport* t = reinterpret_cast<atransport*>(_t);
-    apacket* p;
-
-    adb_thread_setname(
-        android::base::StringPrintf("<-%s", (t->serial != nullptr ? t->serial : "transport")));
-    D("%s: starting read_transport thread on fd %d, SYNC online (%d)", t->serial, t->fd,
-      t->sync_token + 1);
-    p = get_apacket();
-    p->msg.command = A_SYNC;
-    p->msg.arg0 = 1;
-    p->msg.arg1 = ++(t->sync_token);
-    p->msg.magic = A_SYNC ^ 0xffffffff;
-    D("sending SYNC packet (len = %u, payload.size() = %zu)", p->msg.data_length, p->payload.size());
-    if (write_packet(t->fd, t->serial, &p)) {
-        put_apacket(p);
-        D("%s: failed to write SYNC packet", t->serial);
-        goto oops;
-    }
-
-    D("%s: data pump started", t->serial);
-    for (;;) {
-        ATRACE_NAME("read_transport loop");
-        p = get_apacket();
-
-        {
-            ATRACE_NAME("read_transport read_remote");
-            if (!t->connection->Read(p)) {
-                D("%s: remote read failed for transport", t->serial);
-                put_apacket(p);
-                break;
-            }
-
-            if (!check_header(p, t)) {
-                D("%s: remote read: bad header", t->serial);
-                put_apacket(p);
-                break;
-            }
-
-#if ADB_HOST
-            if (p->msg.command == 0) {
-                put_apacket(p);
-                continue;
-            }
-#endif
-        }
-
-        D("%s: received remote packet, sending to transport", t->serial);
-        if (write_packet(t->fd, t->serial, &p)) {
-            put_apacket(p);
-            D("%s: failed to write apacket to transport", t->serial);
-            goto oops;
-        }
-    }
-
-    D("%s: SYNC offline for transport", t->serial);
-    p = get_apacket();
-    p->msg.command = A_SYNC;
-    p->msg.arg0 = 0;
-    p->msg.arg1 = 0;
-    p->msg.magic = A_SYNC ^ 0xffffffff;
-    if (write_packet(t->fd, t->serial, &p)) {
-        put_apacket(p);
-        D("%s: failed to write SYNC apacket to transport", t->serial);
-    }
-
-oops:
-    D("%s: read_transport thread is exiting", t->serial);
-    kick_transport(t);
-    transport_unref(t);
-}
-
-// write_transport thread gets packets sent by the main thread (through send_packet()),
-// and writes to a transport (representing a usb/tcp connection).
-static void write_transport_thread(void* _t) {
-    atransport* t = reinterpret_cast<atransport*>(_t);
-    apacket* p;
-    int active = 0;
-
-    adb_thread_setname(
-        android::base::StringPrintf("->%s", (t->serial != nullptr ? t->serial : "transport")));
-    D("%s: starting write_transport thread, reading from fd %d", t->serial, t->fd);
-
-    for (;;) {
-        ATRACE_NAME("write_transport loop");
-        if (read_packet(t->fd, t->serial, &p)) {
-            D("%s: failed to read apacket from transport on fd %d", t->serial, t->fd);
-            break;
-        }
-
-        if (p->msg.command == A_SYNC) {
-            if (p->msg.arg0 == 0) {
-                D("%s: transport SYNC offline", t->serial);
-                put_apacket(p);
-                break;
-            } else {
-                if (p->msg.arg1 == t->sync_token) {
-                    D("%s: transport SYNC online", t->serial);
-                    active = 1;
-                } else {
-                    D("%s: transport ignoring SYNC %d != %d", t->serial, p->msg.arg1, t->sync_token);
-                }
-            }
-        } else {
-            if (active) {
-                D("%s: transport got packet, sending to remote", t->serial);
-                ATRACE_NAME("write_transport write_remote");
-
-                // Allow sending the payload's implicit null terminator.
-                if (p->msg.data_length != p->payload.size()) {
-                    LOG(FATAL) << "packet data length doesn't match payload: msg.data_length = "
-                               << p->msg.data_length << ", payload.size() = " << p->payload.size();
-                }
-
-                if (t->Write(p) != 0) {
-                    D("%s: remote write failed for transport", t->serial);
-                    put_apacket(p);
-                    break;
-                }
-            } else {
-                D("%s: transport ignoring packet while offline", t->serial);
-            }
-        }
-
-        put_apacket(p);
-    }
-
-    D("%s: write_transport thread is exiting, fd %d", t->serial, t->fd);
-    kick_transport(t);
-    transport_unref(t);
-}
-
 void kick_transport(atransport* t) {
     std::lock_guard<std::recursive_mutex> lock(transport_lock);
     // As kick_transport() can be called from threads without guarantee that t is valid,
@@ -429,7 +474,7 @@
     delete tracker;
 }
 
-static int device_tracker_enqueue(asocket* socket, std::string) {
+static int device_tracker_enqueue(asocket* socket, apacket::payload_type) {
     /* you can't read from a device tracker, close immediately */
     device_tracker_close(socket);
     return -1;
@@ -438,7 +483,7 @@
 static int device_tracker_send(device_tracker* tracker, const std::string& string) {
     asocket* peer = tracker->socket.peer;
 
-    std::string data;
+    apacket::payload_type data;
     data.resize(4 + string.size());
     char buf[5];
     snprintf(buf, sizeof(buf), "%04x", static_cast<int>(string.size()));
@@ -559,9 +604,8 @@
     return 0;
 }
 
-static void transport_registration_func(int _fd, unsigned ev, void* data) {
+static void transport_registration_func(int _fd, unsigned ev, void*) {
     tmsg m;
-    int s[2];
     atransport* t;
 
     if (!(ev & FDE_READ)) {
@@ -575,13 +619,7 @@
     t = m.transport;
 
     if (m.action == 0) {
-        D("transport: %s removing and free'ing %d", t->serial, t->transport_socket);
-
-        /* IMPORTANT: the remove closes one half of the
-        ** socket pair.  The close closes the other half.
-        */
-        fdevent_remove(&(t->transport_fde));
-        adb_close(t->fd);
+        D("transport: %s deleting", t->serial);
 
         {
             std::lock_guard<std::recursive_mutex> lock(transport_lock);
@@ -602,35 +640,53 @@
 
     /* don't create transport threads for inaccessible devices */
     if (t->GetConnectionState() != kCsNoPerm) {
-        /* initial references are the two threads */
-        t->ref_count = 2;
+        // The connection gets a reference to the atransport. It will release it
+        // upon a read/write error.
+        t->ref_count++;
+        t->connection()->SetTransportName(t->serial_name());
+        t->connection()->SetReadCallback([t](Connection*, std::unique_ptr<apacket> p) {
+            if (!check_header(p.get(), t)) {
+                D("%s: remote read: bad header", t->serial);
+                return false;
+            }
 
-        if (adb_socketpair(s)) {
-            fatal_errno("cannot open transport socketpair");
-        }
+            VLOG(TRANSPORT) << dump_packet(t->serial, "from remote", p.get());
+            apacket* packet = p.release();
 
-        D("transport: %s socketpair: (%d,%d) starting", t->serial, s[0], s[1]);
+            // TODO: Does this need to run on the main thread?
+            fdevent_run_on_main_thread([packet, t]() { handle_packet(packet, t); });
+            return true;
+        });
+        t->connection()->SetErrorCallback([t](Connection*, const std::string& error) {
+            D("%s: connection terminated: %s", t->serial, error.c_str());
+            fdevent_run_on_main_thread([t]() {
+                handle_offline(t);
+                transport_unref(t);
+            });
+        });
 
-        t->transport_socket = s[0];
-        t->fd = s[1];
-
-        fdevent_install(&(t->transport_fde), t->transport_socket, transport_socket_events, t);
-
-        fdevent_set(&(t->transport_fde), FDE_READ);
-
-        std::thread(write_transport_thread, t).detach();
-        std::thread(read_transport_thread, t).detach();
+        t->connection()->Start();
+#if ADB_HOST
+        send_connect(t);
+#endif
     }
 
     {
         std::lock_guard<std::recursive_mutex> lock(transport_lock);
-        pending_list.remove(t);
-        transport_list.push_front(t);
+        auto it = std::find(pending_list.begin(), pending_list.end(), t);
+        if (it != pending_list.end()) {
+            pending_list.remove(t);
+            transport_list.push_front(t);
+        }
     }
 
     update_transports();
 }
 
+void init_reconnect_handler(void) {
+    reconnect_handler.Start();
+}
+
 void init_transport_registration(void) {
     int s[2];
 
@@ -649,6 +705,7 @@
 }
 
 void kick_all_transports() {
+    reconnect_handler.Stop();
     // To avoid only writing part of a packet to a transport after exit, kick all transports.
     std::lock_guard<std::recursive_mutex> lock(transport_lock);
     for (auto t : transport_list) {
@@ -678,15 +735,21 @@
 }
 
 static void transport_unref(atransport* t) {
+    check_main_thread();
     CHECK(t != nullptr);
 
     std::lock_guard<std::recursive_mutex> lock(transport_lock);
     CHECK_GT(t->ref_count, 0u);
     t->ref_count--;
     if (t->ref_count == 0) {
-        D("transport: %s unref (kicking and closing)", t->serial);
-        t->connection->Close();
-        remove_transport(t);
+        t->connection()->Stop();
+        if (t->IsTcpDevice() && !t->kicked()) {
+            D("transport: %s unref (attempting reconnection) %d", t->serial, t->kicked());
+            reconnect_handler.TrackTransport(t);
+        } else {
+            D("transport: %s unref (kicking and closing)", t->serial);
+            remove_transport(t);
+        }
     } else {
         D("transport: %s unref (count=%zu)", t->serial, t->ref_count);
     }
@@ -736,9 +799,7 @@
     std::unique_lock<std::recursive_mutex> lock(transport_lock);
     for (const auto& t : transport_list) {
         if (t->GetConnectionState() == kCsNoPerm) {
-#if ADB_HOST
             *error_out = UsbNoPermissionsLongHelpText();
-#endif
             continue;
         }
 
@@ -787,22 +848,41 @@
     }
     lock.unlock();
 
-    // Don't return unauthorized devices; the caller can't do anything with them.
-    if (result && result->GetConnectionState() == kCsUnauthorized && !accept_any_state) {
-        *error_out = "device unauthorized.\n";
-        char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
-        *error_out += "This adb server's $ADB_VENDOR_KEYS is ";
-        *error_out += ADB_VENDOR_KEYS ? ADB_VENDOR_KEYS : "not set";
-        *error_out += "\n";
-        *error_out += "Try 'adb kill-server' if that seems wrong.\n";
-        *error_out += "Otherwise check for a confirmation dialog on your device.";
-        result = nullptr;
-    }
+    if (result && !accept_any_state) {
+        // The caller requires an active transport.
+        // Make sure that we're actually connected.
+        ConnectionState state = result->GetConnectionState();
+        switch (state) {
+            case kCsConnecting:
+                *error_out = "device still connecting";
+                result = nullptr;
+                break;
 
-    // Don't return offline devices; the caller can't do anything with them.
-    if (result && result->GetConnectionState() == kCsOffline && !accept_any_state) {
-        *error_out = "device offline";
-        result = nullptr;
+            case kCsAuthorizing:
+                *error_out = "device still authorizing";
+                result = nullptr;
+                break;
+
+            case kCsUnauthorized: {
+                *error_out = "device unauthorized.\n";
+                char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
+                *error_out += "This adb server's $ADB_VENDOR_KEYS is ";
+                *error_out += ADB_VENDOR_KEYS ? ADB_VENDOR_KEYS : "not set";
+                *error_out += "\n";
+                *error_out += "Try 'adb kill-server' if that seems wrong.\n";
+                *error_out += "Otherwise check for a confirmation dialog on your device.";
+                result = nullptr;
+                break;
+            }
+
+            case kCsOffline:
+                *error_out = "device offline";
+                result = nullptr;
+                break;
+
+            default:
+                break;
+        }
     }
 
     if (result) {
@@ -812,15 +892,38 @@
     return result;
 }
 
+bool ConnectionWaitable::WaitForConnection(std::chrono::milliseconds timeout) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    ScopedAssumeLocked assume_locked(mutex_);
+    return cv_.wait_for(lock, timeout, [&]() REQUIRES(mutex_) {
+        return connection_established_ready_;
+    }) && connection_established_;
+}
+
+void ConnectionWaitable::SetConnectionEstablished(bool success) {
+    {
+        std::lock_guard<std::mutex> lock(mutex_);
+        if (connection_established_ready_) return;
+        connection_established_ready_ = true;
+        connection_established_ = success;
+        D("connection established with %d", success);
+    }
+    cv_.notify_one();
+}
+
+atransport::~atransport() {
+    // If the connection callback had not been run before, run it now.
+    SetConnectionEstablished(false);
+}
+
 int atransport::Write(apacket* p) {
-    return this->connection->Write(p) ? 0 : -1;
+    return this->connection()->Write(std::unique_ptr<apacket>(p)) ? 0 : -1;
 }
 
 void atransport::Kick() {
-    if (!kicked_) {
-        D("kicking transport %s", this->serial);
-        kicked_ = true;
-        this->connection->Close();
+    if (!kicked_.exchange(true)) {
+        D("kicking transport %p %s", this, this->serial);
+        this->connection()->Stop();
     }
 }
 
@@ -833,7 +936,12 @@
     connection_state_ = state;
 }
 
-const std::string atransport::connection_state_name() const {
+void atransport::SetConnection(std::unique_ptr<Connection> connection) {
+    std::lock_guard<std::mutex> lock(mutex_);
+    connection_ = std::shared_ptr<Connection>(std::move(connection));
+}
+
+std::string atransport::connection_state_name() const {
     ConnectionState state = GetConnectionState();
     switch (state) {
         case kCsOffline:
@@ -852,6 +960,10 @@
             return "sideload";
         case kCsUnauthorized:
             return "unauthorized";
+        case kCsAuthorizing:
+            return "authorizing";
+        case kCsConnecting:
+            return "connecting";
         default:
             return "unknown";
     }
@@ -964,6 +1076,14 @@
            qual_match(target.c_str(), "device:", device, false);
 }
 
+void atransport::SetConnectionEstablished(bool success) {
+    connection_waitable_->SetConnectionEstablished(success);
+}
+
+bool atransport::Reconnect() {
+    return reconnect_(this);
+}
+
 #if ADB_HOST
 
 // We use newline as our delimiter, make sure to never output it.
@@ -1044,8 +1164,9 @@
 }
 #endif  // ADB_HOST
 
-int register_socket_transport(int s, const char* serial, int port, int local) {
-    atransport* t = new atransport();
+int register_socket_transport(int s, const char* serial, int port, int local,
+                              atransport::ReconnectCallback reconnect) {
+    atransport* t = new atransport(std::move(reconnect), kCsOffline);
 
     if (!serial) {
         char buf[32];
@@ -1065,7 +1186,7 @@
             VLOG(TRANSPORT) << "socket transport " << transport->serial
                             << " is already in pending_list and fails to register";
             delete t;
-            return -1;
+            return -EALREADY;
         }
     }
 
@@ -1074,7 +1195,7 @@
             VLOG(TRANSPORT) << "socket transport " << transport->serial
                             << " is already in transport_list and fails to register";
             delete t;
-            return -1;
+            return -EALREADY;
         }
     }
 
@@ -1083,8 +1204,15 @@
 
     lock.unlock();
 
+    auto waitable = t->connection_waitable();
     register_transport(t);
-    return 0;
+
+    if (local == 1) {
+        // Do not wait for emulator transports.
+        return 0;
+    }
+
+    return waitable->WaitForConnection(std::chrono::seconds(10)) ? 0 : -1;
 }
 
 #if ADB_HOST
@@ -1119,7 +1247,7 @@
 
 void register_usb_transport(usb_handle* usb, const char* serial, const char* devpath,
                             unsigned writeable) {
-    atransport* t = new atransport((writeable ? kCsOffline : kCsNoPerm));
+    atransport* t = new atransport(writeable ? kCsOffline : kCsNoPerm);
 
     D("transport: %p init'ing for usb_handle %p (sn='%s')", t, usb, serial ? serial : "");
     init_usb_transport(t, usb);
@@ -1143,8 +1271,9 @@
 void unregister_usb_transport(usb_handle* usb) {
     std::lock_guard<std::recursive_mutex> lock(transport_lock);
     transport_list.remove_if([usb](atransport* t) {
-        if (auto connection = dynamic_cast<UsbConnection*>(t->connection.get())) {
-            return connection->handle_ == usb && t->GetConnectionState() == kCsNoPerm;
+        auto connection = t->connection();
+        if (auto usb_connection = dynamic_cast<UsbConnection*>(connection.get())) {
+            return usb_connection->handle_ == usb && t->GetConnectionState() == kCsNoPerm;
         }
         return false;
     });
diff --git a/adb/transport.h b/adb/transport.h
index 9700f44..ae9cc02 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -20,14 +20,19 @@
 #include <sys/types.h>
 
 #include <atomic>
+#include <chrono>
+#include <condition_variable>
 #include <deque>
 #include <functional>
 #include <list>
 #include <memory>
 #include <mutex>
 #include <string>
+#include <thread>
 #include <unordered_set>
 
+#include <android-base/macros.h>
+#include <android-base/thread_annotations.h>
 #include <openssl/rsa.h>
 
 #include "adb.h"
@@ -57,15 +62,47 @@
 
 TransportId NextTransportId();
 
-// Abstraction for a blocking packet transport.
+// Abstraction for a non-blocking packet transport.
 struct Connection {
     Connection() = default;
-    Connection(const Connection& copy) = delete;
-    Connection(Connection&& move) = delete;
-
-    // Destroy a Connection. Formerly known as 'Close' in atransport.
     virtual ~Connection() = default;
 
+    void SetTransportName(std::string transport_name) {
+        transport_name_ = std::move(transport_name);
+    }
+
+    using ReadCallback = std::function<bool(Connection*, std::unique_ptr<apacket>)>;
+    void SetReadCallback(ReadCallback callback) {
+        CHECK(!read_callback_);
+        read_callback_ = callback;
+    }
+
+    // Called after the Connection has terminated, either by an error or because Stop was called.
+    using ErrorCallback = std::function<void(Connection*, const std::string&)>;
+    void SetErrorCallback(ErrorCallback callback) {
+        CHECK(!error_callback_);
+        error_callback_ = callback;
+    }
+
+    virtual bool Write(std::unique_ptr<apacket> packet) = 0;
+
+    virtual void Start() = 0;
+    virtual void Stop() = 0;
+
+    std::string transport_name_;
+    ReadCallback read_callback_;
+    ErrorCallback error_callback_;
+};
+
+// Abstraction for a blocking packet transport.
+struct BlockingConnection {
+    BlockingConnection() = default;
+    BlockingConnection(const BlockingConnection& copy) = delete;
+    BlockingConnection(BlockingConnection&& move) = delete;
+
+    // Destroy a BlockingConnection. Formerly known as 'Close' in atransport.
+    virtual ~BlockingConnection() = default;
+
     // Read/Write a packet. These functions are concurrently called from a transport's reader/writer
     // threads.
     virtual bool Read(apacket* packet) = 0;
@@ -77,7 +114,31 @@
     virtual void Close() = 0;
 };
 
-struct FdConnection : public Connection {
+struct BlockingConnectionAdapter : public Connection {
+    explicit BlockingConnectionAdapter(std::unique_ptr<BlockingConnection> connection);
+
+    virtual ~BlockingConnectionAdapter();
+
+    virtual bool Write(std::unique_ptr<apacket> packet) override final;
+
+    virtual void Start() override final;
+    virtual void Stop() override final;
+
+    bool started_ GUARDED_BY(mutex_) = false;
+    bool stopped_ GUARDED_BY(mutex_) = false;
+
+    std::unique_ptr<BlockingConnection> underlying_;
+    std::thread read_thread_ GUARDED_BY(mutex_);
+    std::thread write_thread_ GUARDED_BY(mutex_);
+
+    std::deque<std::unique_ptr<apacket>> write_queue_ GUARDED_BY(mutex_);
+    std::mutex mutex_;
+    std::condition_variable cv_;
+
+    std::once_flag error_flag_;
+};
+
+struct FdConnection : public BlockingConnection {
     explicit FdConnection(unique_fd fd) : fd_(std::move(fd)) {}
 
     bool Read(apacket* packet) override final;
@@ -89,7 +150,7 @@
     unique_fd fd_;
 };
 
-struct UsbConnection : public Connection {
+struct UsbConnection : public BlockingConnection {
     explicit UsbConnection(usb_handle* handle) : handle_(handle) {}
     ~UsbConnection();
 
@@ -101,6 +162,35 @@
     usb_handle* handle_;
 };
 
+// Waits for a transport's connection to be not pending. This is a separate
+// object so that the transport can be destroyed and another thread can be
+// notified of it in a race-free way.
+class ConnectionWaitable {
+  public:
+    ConnectionWaitable() = default;
+    ~ConnectionWaitable() = default;
+
+    // Waits until the first CNXN packet has been received by the owning
+    // atransport, or the specified timeout has elapsed. Can be called from any
+    // thread.
+    //
+    // Returns true if the CNXN packet was received in a timely fashion, false
+    // otherwise.
+    bool WaitForConnection(std::chrono::milliseconds timeout);
+
+    // Can be called from any thread when the connection stops being pending.
+    // Only the first invocation will be acknowledged, the rest will be no-ops.
+    void SetConnectionEstablished(bool success);
+
+  private:
+    bool connection_established_ GUARDED_BY(mutex_) = false;
+    bool connection_established_ready_ GUARDED_BY(mutex_) = false;
+    std::mutex mutex_;
+    std::condition_variable cv_;
+
+    DISALLOW_COPY_AND_ASSIGN(ConnectionWaitable);
+};
+
 class atransport {
   public:
     // TODO(danalbert): We expose waaaaaaay too much stuff because this was
@@ -108,34 +198,43 @@
     // class in one go is a very large change. Given how bad our testing is,
     // it's better to do this piece by piece.
 
-    atransport(ConnectionState state = kCsOffline)
-        : id(NextTransportId()), connection_state_(state) {
-        transport_fde = {};
+    using ReconnectCallback = std::function<bool(atransport*)>;
+
+    atransport(ReconnectCallback reconnect, ConnectionState state)
+        : id(NextTransportId()),
+          kicked_(false),
+          connection_state_(state),
+          connection_waitable_(std::make_shared<ConnectionWaitable>()),
+          connection_(nullptr),
+          reconnect_(std::move(reconnect)) {
         // Initialize protocol to min version for compatibility with older versions.
         // Version will be updated post-connect.
         protocol_version = A_VERSION_MIN;
         max_payload = MAX_PAYLOAD;
     }
-    virtual ~atransport() {}
+    atransport(ConnectionState state = kCsOffline)
+        : atransport([](atransport*) { return false; }, state) {}
+    virtual ~atransport();
 
     int Write(apacket* p);
     void Kick();
+    bool kicked() const { return kicked_; }
 
     // ConnectionState can be read by all threads, but can only be written in the main thread.
     ConnectionState GetConnectionState() const;
     void SetConnectionState(ConnectionState state);
 
+    void SetConnection(std::unique_ptr<Connection> connection);
+    std::shared_ptr<Connection> connection() {
+        std::lock_guard<std::mutex> lock(mutex_);
+        return connection_;
+    }
+
     const TransportId id;
-    int fd = -1;
-    int transport_socket = -1;
-    fdevent transport_fde;
     size_t ref_count = 0;
-    uint32_t sync_token = 0;
     bool online = false;
     TransportType type = kTransportAny;
 
-    std::unique_ptr<Connection> connection;
-
     // Used to identify transports for clients.
     char* serial = nullptr;
     char* product = nullptr;
@@ -152,8 +251,8 @@
     char token[TOKEN_SIZE] = {};
     size_t failed_auth_attempts = 0;
 
-    const std::string serial_name() const { return serial ? serial : "<unknown>"; }
-    const std::string connection_state_name() const;
+    std::string serial_name() const { return serial ? serial : "<unknown>"; }
+    std::string connection_state_name() const;
 
     void update_version(int version, size_t payload);
     int get_protocol_version() const;
@@ -187,8 +286,19 @@
     // This is to make it easier to use the same network target for both fastboot and adb.
     bool MatchesTarget(const std::string& target) const;
 
-private:
-    bool kicked_ = false;
+    // Notifies that the atransport is no longer waiting for the connection
+    // being established.
+    void SetConnectionEstablished(bool success);
+
+    // Gets a shared reference to the ConnectionWaitable.
+    std::shared_ptr<ConnectionWaitable> connection_waitable() { return connection_waitable_; }
+
+    // Attempts to reconnect with the underlying Connection. Returns true if the
+    // reconnection attempt succeeded.
+    bool Reconnect();
+
+  private:
+    std::atomic<bool> kicked_;
 
     // A set of features transmitted in the banner with the initial connection.
     // This is stored in the banner as 'features=feature0,feature1,etc'.
@@ -204,6 +314,18 @@
     std::deque<std::shared_ptr<RSA>> keys_;
 #endif
 
+    // A sharable object that can be used to wait for the atransport's
+    // connection to be established.
+    std::shared_ptr<ConnectionWaitable> connection_waitable_;
+
+    // The underlying connection object.
+    std::shared_ptr<Connection> connection_ GUARDED_BY(mutex_);
+
+    // A callback that will be invoked when the atransport needs to reconnect.
+    ReconnectCallback reconnect_;
+
+    std::mutex mutex_;
+
     DISALLOW_COPY_AND_ASSIGN(atransport);
 };
 
@@ -225,6 +347,7 @@
 // Stops iteration and returns false if fn returns false, otherwise returns true.
 bool iterate_transports(std::function<bool(const atransport*)> fn);
 
+void init_reconnect_handler(void);
 void init_transport_registration(void);
 void init_mdns_transport_discovery(void);
 std::string list_transports(bool long_listing);
@@ -239,7 +362,8 @@
 void connect_device(const std::string& address, std::string* response);
 
 /* cause new transports to be init'd and added to the list */
-int register_socket_transport(int s, const char* serial, int port, int local);
+int register_socket_transport(int s, const char* serial, int port, int local,
+                              atransport::ReconnectCallback reconnect);
 
 // This should only be used for transports with connection_state == kCsNoPerm.
 void unregister_usb_transport(usb_handle* usb);
diff --git a/adb/transport_benchmark.cpp b/adb/transport_benchmark.cpp
new file mode 100644
index 0000000..da24aa7
--- /dev/null
+++ b/adb/transport_benchmark.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <malloc.h>
+#include <stdio.h>
+
+#include <android-base/logging.h>
+#include <benchmark/benchmark.h>
+
+#include "adb_trace.h"
+#include "sysdeps.h"
+#include "transport.h"
+
+#define ADB_CONNECTION_BENCHMARK(benchmark_name, ...)               \
+    BENCHMARK_TEMPLATE(benchmark_name, FdConnection, ##__VA_ARGS__) \
+        ->Arg(1)                                                    \
+        ->Arg(16384)                                                \
+        ->Arg(MAX_PAYLOAD)                                          \
+        ->UseRealTime()
+
+template <typename ConnectionType>
+std::unique_ptr<Connection> MakeConnection(unique_fd fd);
+
+template <>
+std::unique_ptr<Connection> MakeConnection<FdConnection>(unique_fd fd) {
+    auto fd_connection = std::make_unique<FdConnection>(std::move(fd));
+    return std::make_unique<BlockingConnectionAdapter>(std::move(fd_connection));
+}
+
+template <typename ConnectionType>
+void BM_Connection_Unidirectional(benchmark::State& state) {
+    int fds[2];
+    if (adb_socketpair(fds) != 0) {
+        LOG(FATAL) << "failed to create socketpair";
+    }
+
+    auto client = MakeConnection<ConnectionType>(unique_fd(fds[0]));
+    auto server = MakeConnection<ConnectionType>(unique_fd(fds[1]));
+
+    std::atomic<size_t> received_bytes;
+
+    client->SetReadCallback([](Connection*, std::unique_ptr<apacket>) -> bool { return true; });
+    server->SetReadCallback([&received_bytes](Connection*, std::unique_ptr<apacket> packet) -> bool {
+        received_bytes += packet->payload.size();
+        return true;
+    });
+
+    client->SetErrorCallback(
+        [](Connection*, const std::string& error) { LOG(INFO) << "client closed: " << error; });
+    server->SetErrorCallback(
+        [](Connection*, const std::string& error) { LOG(INFO) << "server closed: " << error; });
+
+    client->Start();
+    server->Start();
+
+    for (auto _ : state) {
+        size_t data_size = state.range(0);
+        std::unique_ptr<apacket> packet = std::make_unique<apacket>();
+        memset(&packet->msg, 0, sizeof(packet->msg));
+        packet->msg.command = A_WRTE;
+        packet->msg.data_length = data_size;
+        packet->payload.resize(data_size);
+
+        memset(&packet->payload[0], 0xff, data_size);
+
+        received_bytes = 0;
+        client->Write(std::move(packet));
+        while (received_bytes < data_size) {
+            continue;
+        }
+    }
+    state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) * state.range(0));
+
+    client->Stop();
+    server->Stop();
+}
+
+ADB_CONNECTION_BENCHMARK(BM_Connection_Unidirectional);
+
+enum class ThreadPolicy {
+    MainThread,
+    SameThread,
+};
+
+template <typename ConnectionType, enum ThreadPolicy Policy>
+void BM_Connection_Echo(benchmark::State& state) {
+    int fds[2];
+    if (adb_socketpair(fds) != 0) {
+        LOG(FATAL) << "failed to create socketpair";
+    }
+
+    auto client = MakeConnection<ConnectionType>(unique_fd(fds[0]));
+    auto server = MakeConnection<ConnectionType>(unique_fd(fds[1]));
+
+    std::atomic<size_t> received_bytes;
+
+    fdevent_reset();
+    std::thread fdevent_thread([]() { fdevent_loop(); });
+
+    client->SetReadCallback([&received_bytes](Connection*, std::unique_ptr<apacket> packet) -> bool {
+        received_bytes += packet->payload.size();
+        return true;
+    });
+
+    static const auto handle_packet = [](Connection* connection, std::unique_ptr<apacket> packet) {
+        connection->Write(std::move(packet));
+    };
+
+    server->SetReadCallback([](Connection* connection, std::unique_ptr<apacket> packet) -> bool {
+        if (Policy == ThreadPolicy::MainThread) {
+            auto raw_packet = packet.release();
+            fdevent_run_on_main_thread([connection, raw_packet]() {
+                std::unique_ptr<apacket> packet(raw_packet);
+                handle_packet(connection, std::move(packet));
+            });
+        } else {
+            handle_packet(connection, std::move(packet));
+        }
+        return true;
+    });
+
+    client->SetErrorCallback(
+        [](Connection*, const std::string& error) { LOG(INFO) << "client closed: " << error; });
+    server->SetErrorCallback(
+        [](Connection*, const std::string& error) { LOG(INFO) << "server closed: " << error; });
+
+    client->Start();
+    server->Start();
+
+    for (auto _ : state) {
+        size_t data_size = state.range(0);
+        std::unique_ptr<apacket> packet = std::make_unique<apacket>();
+        memset(&packet->msg, 0, sizeof(packet->msg));
+        packet->msg.command = A_WRTE;
+        packet->msg.data_length = data_size;
+        packet->payload.resize(data_size);
+
+        memset(&packet->payload[0], 0xff, data_size);
+
+        received_bytes = 0;
+        client->Write(std::move(packet));
+        while (received_bytes < data_size) {
+            continue;
+        }
+    }
+    state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) * state.range(0));
+
+    client->Stop();
+    server->Stop();
+
+    // TODO: Make it so that you don't need to poke the fdevent loop to make it terminate?
+    fdevent_terminate_loop();
+    fdevent_run_on_main_thread([]() {});
+
+    fdevent_thread.join();
+}
+
+ADB_CONNECTION_BENCHMARK(BM_Connection_Echo, ThreadPolicy::SameThread);
+ADB_CONNECTION_BENCHMARK(BM_Connection_Echo, ThreadPolicy::MainThread);
+
+int main(int argc, char** argv) {
+    // Set M_DECAY_TIME so that our allocations aren't immediately purged on free.
+    mallopt(M_DECAY_TIME, 1);
+
+    android::base::SetMinimumLogSeverity(android::base::WARNING);
+    adb_trace_init(argv);
+    ::benchmark::Initialize(&argc, argv);
+    if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1;
+    ::benchmark::RunSpecifiedBenchmarks();
+}
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 560a031..181d666 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -45,6 +45,7 @@
 #include "adb_unique_fd.h"
 #include "adb_utils.h"
 #include "sysdeps/chrono.h"
+#include "sysdeps/memory.h"
 
 #if ADB_HOST
 
@@ -67,28 +68,24 @@
     return local_connect_arbitrary_ports(port - 1, port, &dummy) == 0;
 }
 
-void connect_device(const std::string& address, std::string* response) {
-    if (address.empty()) {
-        *response = "empty address";
-        return;
-    }
-
+std::tuple<unique_fd, int, std::string> tcp_connect(const std::string& address,
+                                                    std::string* response) {
     std::string serial;
     std::string host;
     int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
     if (!android::base::ParseNetAddress(address, &host, &port, &serial, response)) {
-        return;
+        return std::make_tuple(unique_fd(), port, serial);
     }
 
     std::string error;
-    int fd = network_connect(host.c_str(), port, SOCK_STREAM, 10, &error);
+    unique_fd fd(network_connect(host.c_str(), port, SOCK_STREAM, 10, &error));
     if (fd == -1) {
         *response = android::base::StringPrintf("unable to connect to %s: %s",
                                                 serial.c_str(), error.c_str());
-        return;
+        return std::make_tuple(std::move(fd), port, serial);
     }
 
-    D("client: connected %s remote on fd %d", serial.c_str(), fd);
+    D("client: connected %s remote on fd %d", serial.c_str(), fd.get());
     close_on_exec(fd);
     disable_tcp_nagle(fd);
 
@@ -97,10 +94,45 @@
         D("warning: failed to configure TCP keepalives (%s)", strerror(errno));
     }
 
-    int ret = register_socket_transport(fd, serial.c_str(), port, 0);
+    return std::make_tuple(std::move(fd), port, serial);
+}
+
+void connect_device(const std::string& address, std::string* response) {
+    if (address.empty()) {
+        *response = "empty address";
+        return;
+    }
+
+    unique_fd fd;
+    int port;
+    std::string serial;
+    std::tie(fd, port, serial) = tcp_connect(address, response);
+    auto reconnect = [address](atransport* t) {
+        std::string response;
+        unique_fd fd;
+        int port;
+        std::string serial;
+        std::tie(fd, port, serial) = tcp_connect(address, &response);
+        if (fd == -1) {
+            D("reconnect failed: %s", response.c_str());
+            return false;
+        }
+
+        // This invokes the part of register_socket_transport() that needs to be
+        // invoked if the atransport* has already been setup. This eventually
+        // calls atransport->SetConnection() with a newly created Connection*
+        // that will in turn send the CNXN packet.
+        return init_socket_transport(t, fd.release(), port, 0) >= 0;
+    };
+
+    int ret = register_socket_transport(fd.release(), serial.c_str(), port, 0, std::move(reconnect));
     if (ret < 0) {
         adb_close(fd);
-        *response = android::base::StringPrintf("already connected to %s", serial.c_str());
+        if (ret == -EALREADY) {
+            *response = android::base::StringPrintf("already connected to %s", serial.c_str());
+        } else {
+            *response = android::base::StringPrintf("failed to connect to %s", serial.c_str());
+        }
     } else {
         *response = android::base::StringPrintf("connected to %s", serial.c_str());
     }
@@ -130,7 +162,8 @@
         close_on_exec(fd);
         disable_tcp_nagle(fd);
         std::string serial = getEmulatorSerialString(console_port);
-        if (register_socket_transport(fd, serial.c_str(), adb_port, 1) == 0) {
+        if (register_socket_transport(fd, serial.c_str(), adb_port, 1,
+                                      [](atransport*) { return false; }) == 0) {
             return 0;
         }
         adb_close(fd);
@@ -234,7 +267,8 @@
             close_on_exec(fd);
             disable_tcp_nagle(fd);
             std::string serial = android::base::StringPrintf("host-%d", fd);
-            if (register_socket_transport(fd, serial.c_str(), port, 1) != 0) {
+            if (register_socket_transport(fd, serial.c_str(), port, 1,
+                                          [](atransport*) { return false; }) != 0) {
                 adb_close(fd);
             }
         }
@@ -333,7 +367,8 @@
                 /* Host is connected. Register the transport, and start the
                  * exchange. */
                 std::string serial = android::base::StringPrintf("host-%d", fd);
-                if (register_socket_transport(fd, serial.c_str(), port, 1) != 0 ||
+                if (register_socket_transport(fd, serial.c_str(), port, 1,
+                                              [](atransport*) { return false; }) != 0 ||
                     !WriteFdExactly(fd, _start_req, strlen(_start_req))) {
                     adb_close(fd);
                 }
@@ -445,13 +480,14 @@
     int fail = 0;
 
     unique_fd fd(s);
-    t->sync_token = 1;
     t->type = kTransportLocal;
 
 #if ADB_HOST
     // Emulator connection.
     if (local) {
-        t->connection.reset(new EmulatorConnection(std::move(fd), adb_port));
+        auto emulator_connection = std::make_unique<EmulatorConnection>(std::move(fd), adb_port);
+        t->SetConnection(
+            std::make_unique<BlockingConnectionAdapter>(std::move(emulator_connection)));
         std::lock_guard<std::mutex> lock(local_transports_lock);
         atransport* existing_transport = find_emulator_transport_by_adb_port_locked(adb_port);
         if (existing_transport != NULL) {
@@ -470,6 +506,7 @@
 #endif
 
     // Regular tcp connection.
-    t->connection.reset(new FdConnection(std::move(fd)));
+    auto fd_connection = std::make_unique<FdConnection>(std::move(fd));
+    t->SetConnection(std::make_unique<BlockingConnectionAdapter>(std::move(fd_connection)));
     return fail;
 }
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index d7565f6..94b2e37 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -17,6 +17,7 @@
 #define TRACE_TAG TRANSPORT
 
 #include "sysdeps.h"
+#include "sysdeps/memory.h"
 #include "transport.h"
 
 #include <stdio.h>
@@ -174,8 +175,8 @@
 
 void init_usb_transport(atransport* t, usb_handle* h) {
     D("transport: usb");
-    t->connection.reset(new UsbConnection(h));
-    t->sync_token = 1;
+    auto connection = std::make_unique<UsbConnection>(h);
+    t->SetConnection(std::make_unique<BlockingConnectionAdapter>(std::move(connection)));
     t->type = kTransportUsb;
 }
 
diff --git a/adb/types.h b/adb/types.h
new file mode 100644
index 0000000..dd3e063
--- /dev/null
+++ b/adb/types.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <utility>
+
+#include <android-base/logging.h>
+
+#include "sysdeps/memory.h"
+
+// Essentially std::vector<char>, except without zero initialization or reallocation.
+struct Block {
+    using iterator = char*;
+
+    Block() {}
+
+    explicit Block(size_t size) { allocate(size); }
+
+    template <typename Iterator>
+    Block(Iterator begin, Iterator end) : Block(end - begin) {
+        std::copy(begin, end, data_);
+    }
+
+    Block(const Block& copy) = delete;
+    Block(Block&& move) {
+        std::swap(data_, move.data_);
+        std::swap(capacity_, move.capacity_);
+        std::swap(size_, move.size_);
+    }
+
+    Block& operator=(const Block& copy) = delete;
+    Block& operator=(Block&& move) {
+        clear();
+
+        std::swap(data_, move.data_);
+        std::swap(capacity_, move.capacity_);
+        std::swap(size_, move.size_);
+
+        return *this;
+    }
+
+    ~Block() { clear(); }
+
+    void resize(size_t new_size) {
+        if (!data_) {
+            allocate(new_size);
+        } else {
+            CHECK_GE(capacity_, new_size);
+            size_ = new_size;
+        }
+    }
+
+    template <typename InputIt>
+    void assign(InputIt begin, InputIt end) {
+        clear();
+        allocate(end - begin);
+        std::copy(begin, end, data_);
+    }
+
+    void clear() {
+        free(data_);
+        capacity_ = 0;
+        size_ = 0;
+    }
+
+    size_t capacity() const { return capacity_; }
+    size_t size() const { return size_; }
+    bool empty() const { return size() == 0; }
+
+    char* data() { return data_; }
+    const char* data() const { return data_; }
+
+    char* begin() { return data_; }
+    const char* begin() const { return data_; }
+
+    char* end() { return data() + size_; }
+    const char* end() const { return data() + size_; }
+
+    char& operator[](size_t idx) { return data()[idx]; }
+    const char& operator[](size_t idx) const { return data()[idx]; }
+
+    bool operator==(const Block& rhs) const {
+        return size() == rhs.size() && memcmp(data(), rhs.data(), size()) == 0;
+    }
+
+  private:
+    void allocate(size_t size) {
+        CHECK(data_ == nullptr);
+        CHECK_EQ(0ULL, capacity_);
+        CHECK_EQ(0ULL, size_);
+        if (size != 0) {
+            data_ = static_cast<char*>(malloc(size));
+            capacity_ = size;
+            size_ = size;
+        }
+    }
+
+    char* data_ = nullptr;
+    size_t capacity_ = 0;
+    size_t size_ = 0;
+};
+
+struct amessage {
+    uint32_t command;     /* command identifier constant      */
+    uint32_t arg0;        /* first argument                   */
+    uint32_t arg1;        /* second argument                  */
+    uint32_t data_length; /* length of payload (0 is allowed) */
+    uint32_t data_check;  /* checksum of data payload         */
+    uint32_t magic;       /* command ^ 0xffffffff             */
+};
+
+struct apacket {
+    using payload_type = Block;
+    amessage msg;
+    payload_type payload;
+};
+
+struct Range {
+    explicit Range(apacket::payload_type data) : data_(std::move(data)) {}
+
+    Range(const Range& copy) = delete;
+    Range& operator=(const Range& copy) = delete;
+
+    Range(Range&& move) = default;
+    Range& operator=(Range&& move) = default;
+
+    size_t size() const { return data_.size() - begin_offset_ - end_offset_; };
+    bool empty() const { return size() == 0; }
+
+    void drop_front(size_t n) {
+        CHECK_GE(size(), n);
+        begin_offset_ += n;
+    }
+
+    void drop_end(size_t n) {
+        CHECK_GE(size(), n);
+        end_offset_ += n;
+    }
+
+    char* data() { return &data_[0] + begin_offset_; }
+
+    apacket::payload_type::iterator begin() { return data_.begin() + begin_offset_; }
+    apacket::payload_type::iterator end() { return data_.end() - end_offset_; }
+
+    apacket::payload_type data_;
+    size_t begin_offset_ = 0;
+    size_t end_offset_ = 0;
+};
diff --git a/base/Android.bp b/base/Android.bp
index 5d70d47..ec81f61 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -50,6 +50,7 @@
         "quick_exit.cpp",
         "stringprintf.cpp",
         "strings.cpp",
+        "threads.cpp",
         "test_utils.cpp",
     ],
 
@@ -123,6 +124,7 @@
         "errors_test.cpp",
         "file_test.cpp",
         "logging_test.cpp",
+        "macros_test.cpp",
         "parsedouble_test.cpp",
         "parseint_test.cpp",
         "parsenetaddress_test.cpp",
@@ -160,4 +162,5 @@
             suffix: "64",
         },
     },
+    test_suites: ["device-tests"],
 }
diff --git a/base/include/android-base/macros.h b/base/include/android-base/macros.h
index 25f2ff4..fd6efb2 100644
--- a/base/include/android-base/macros.h
+++ b/base/include/android-base/macros.h
@@ -20,6 +20,8 @@
 #include <stddef.h>  // for size_t
 #include <unistd.h>  // for TEMP_FAILURE_RETRY
 
+#include <utility>
+
 // bionic and glibc both have TEMP_FAILURE_RETRY, but eg Mac OS' libc doesn't.
 #ifndef TEMP_FAILURE_RETRY
 #define TEMP_FAILURE_RETRY(exp)            \
@@ -114,6 +116,8 @@
   ((sizeof(a) / sizeof(*(a))) / \
     static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
 
+#define SIZEOF_MEMBER(t, f) sizeof(std::declval<t>().f)
+
 // Changing this definition will cause you a lot of pain.  A majority of
 // vendor code defines LIKELY and UNLIKELY this way, and includes
 // this header through an indirect path.
diff --git a/base/include/android-base/parseint.h b/base/include/android-base/parseint.h
index 2c8570e..1b7cc5f 100644
--- a/base/include/android-base/parseint.h
+++ b/base/include/android-base/parseint.h
@@ -19,6 +19,7 @@
 
 #include <errno.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include <limits>
 #include <string>
@@ -31,14 +32,20 @@
 // otherwise valid values will be rejected. Returns boolean success; 'out'
 // is untouched if parsing fails.
 template <typename T>
-bool ParseUint(const char* s, T* out,
-               T max = std::numeric_limits<T>::max()) {
+bool ParseUint(const char* s, T* out, T max = std::numeric_limits<T>::max(),
+               bool allow_suffixes = false) {
   int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
   errno = 0;
   char* end;
   unsigned long long int result = strtoull(s, &end, base);
-  if (errno != 0 || s == end || *end != '\0') {
-    return false;
+  if (errno != 0 || end == s) return false;
+  if (*end != '\0') {
+    const char* suffixes = "bkmgtpe";
+    const char* suffix;
+    if (!allow_suffixes || (suffix = strchr(suffixes, tolower(*end))) == nullptr) return false;
+#if __clang__  // TODO: win32 still builds with GCC :-(
+    if (__builtin_mul_overflow(result, 1ULL << (10 * (suffix - suffixes)), &result)) return false;
+#endif
   }
   if (max < result) {
     return false;
@@ -49,9 +56,20 @@
 
 // TODO: string_view
 template <typename T>
-bool ParseUint(const std::string& s, T* out,
-               T max = std::numeric_limits<T>::max()) {
-  return ParseUint(s.c_str(), out, max);
+bool ParseUint(const std::string& s, T* out, T max = std::numeric_limits<T>::max(),
+               bool allow_suffixes = false) {
+  return ParseUint(s.c_str(), out, max, allow_suffixes);
+}
+
+template <typename T>
+bool ParseByteCount(const char* s, T* out, T max = std::numeric_limits<T>::max()) {
+  return ParseUint(s, out, max, true);
+}
+
+// TODO: string_view
+template <typename T>
+bool ParseByteCount(const std::string& s, T* out, T max = std::numeric_limits<T>::max()) {
+  return ParseByteCount(s.c_str(), out, max);
 }
 
 // Parses the signed decimal integer in the string 's' and sets 'out' to
diff --git a/base/include/android-base/test_utils.h b/base/include/android-base/test_utils.h
index 2edafe3..b95fa07 100644
--- a/base/include/android-base/test_utils.h
+++ b/base/include/android-base/test_utils.h
@@ -31,6 +31,8 @@
   // Release the ownership of fd, caller is reponsible for closing the
   // fd or stream properly.
   int release();
+  // Don't remove the temporary file in the destructor.
+  void DoNotRemove() { remove_file_ = false; }
 
   int fd;
   char path[1024];
@@ -38,6 +40,8 @@
  private:
   void init(const std::string& tmp_dir);
 
+  bool remove_file_ = true;
+
   DISALLOW_COPY_AND_ASSIGN(TemporaryFile);
 };
 
diff --git a/adb/transport_mdns_unsupported.cpp b/base/include/android-base/threads.h
similarity index 70%
rename from adb/transport_mdns_unsupported.cpp
rename to base/include/android-base/threads.h
index 387d341..85e65ba 100644
--- a/adb/transport_mdns_unsupported.cpp
+++ b/base/include/android-base/threads.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -14,5 +14,15 @@
  * limitations under the License.
  */
 
-/* For when mDNS discovery is unsupported */
-void init_mdns_transport_discovery(void) {}
+#ifndef ANDROID_BASE_THREADS_H
+#define ANDROID_BASE_THREADS_H
+
+#include <stdint.h>
+
+namespace android {
+namespace base {
+uint64_t GetThreadId();
+}
+}  // namespace android
+
+#endif
diff --git a/base/logging.cpp b/base/logging.cpp
index a31feef..a33da22 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -21,6 +21,7 @@
 #include "android-base/logging.h"
 
 #include <fcntl.h>
+#include <inttypes.h>
 #include <libgen.h>
 #include <time.h>
 
@@ -53,42 +54,9 @@
 #endif
 
 #include <android-base/macros.h>
+#include <android-base/parseint.h>
 #include <android-base/strings.h>
-
-// For gettid.
-#if defined(__APPLE__)
-#include "AvailabilityMacros.h"  // For MAC_OS_X_VERSION_MAX_ALLOWED
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/syscall.h>
-#include <sys/time.h>
-#include <unistd.h>
-#elif defined(__linux__) && !defined(__ANDROID__)
-#include <syscall.h>
-#include <unistd.h>
-#elif defined(_WIN32)
-#include <windows.h>
-#endif
-
-#if defined(_WIN32)
-typedef uint32_t thread_id;
-#else
-typedef pid_t thread_id;
-#endif
-
-static thread_id GetThreadId() {
-#if defined(__BIONIC__)
-  return gettid();
-#elif defined(__APPLE__)
-  uint64_t tid;
-  pthread_threadid_np(NULL, &tid);
-  return tid;
-#elif defined(__linux__)
-  return syscall(__NR_gettid);
-#elif defined(_WIN32)
-  return GetCurrentThreadId();
-#endif
-}
+#include <android-base/threads.h>
 
 namespace {
 #if defined(__GLIBC__)
@@ -115,6 +83,23 @@
   return progname;
 }
 #endif
+
+#if defined(__linux__)
+int OpenKmsg() {
+#if defined(__ANDROID__)
+  // pick up 'file w /dev/kmsg' environment from daemon's init rc file
+  const auto val = getenv("ANDROID_FILE__dev_kmsg");
+  if (val != nullptr) {
+    int fd;
+    if (android::base::ParseInt(val, &fd, 0)) {
+      auto flags = fcntl(fd, F_GETFL);
+      if ((flags != -1) && ((flags & O_ACCMODE) == O_WRONLY)) return fd;
+    }
+  }
+#endif
+  return TEMP_FAILURE_RETRY(open("/dev/kmsg", O_WRONLY | O_CLOEXEC));
+}
+#endif
 } // namespace
 
 namespace android {
@@ -183,7 +168,7 @@
   static_assert(arraysize(kLogSeverityToKernelLogLevel) == android::base::FATAL + 1,
                 "Mismatch in size of kLogSeverityToKernelLogLevel and values in LogSeverity");
 
-  static int klog_fd = TEMP_FAILURE_RETRY(open("/dev/kmsg", O_WRONLY | O_CLOEXEC));
+  static int klog_fd = OpenKmsg();
   if (klog_fd == -1) return;
 
   int level = kLogSeverityToKernelLogLevel[severity];
@@ -223,8 +208,8 @@
   static_assert(arraysize(log_characters) - 1 == FATAL + 1,
                 "Mismatch in size of log_characters and values in LogSeverity");
   char severity_char = log_characters[severity];
-  fprintf(stderr, "%s %c %s %5d %5d %s:%u] %s\n", tag ? tag : "nullptr", severity_char, timestamp,
-          getpid(), GetThreadId(), file, line, message);
+  fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s:%u] %s\n", tag ? tag : "nullptr", severity_char,
+          timestamp, getpid(), GetThreadId(), file, line, message);
 }
 
 void DefaultAborter(const char* abort_message) {
diff --git a/adb/transport_mdns_unsupported.cpp b/base/macros_test.cpp
similarity index 64%
copy from adb/transport_mdns_unsupported.cpp
copy to base/macros_test.cpp
index 387d341..2b522db 100644
--- a/adb/transport_mdns_unsupported.cpp
+++ b/base/macros_test.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -14,5 +14,17 @@
  * limitations under the License.
  */
 
-/* For when mDNS discovery is unsupported */
-void init_mdns_transport_discovery(void) {}
+#include "android-base/macros.h"
+
+#include <stdint.h>
+
+#include <gtest/gtest.h>
+
+TEST(macros, SIZEOF_MEMBER_macro) {
+  struct S {
+    int32_t i32;
+    double d;
+  };
+  ASSERT_EQ(4U, SIZEOF_MEMBER(S, i32));
+  ASSERT_EQ(8U, SIZEOF_MEMBER(S, d));
+}
diff --git a/base/parseint_test.cpp b/base/parseint_test.cpp
index 483b1d3..fb1c339 100644
--- a/base/parseint_test.cpp
+++ b/base/parseint_test.cpp
@@ -96,3 +96,44 @@
   ASSERT_FALSE(android::base::ParseInt("456x", &u));
   ASSERT_EQ(123u, u);
 }
+
+TEST(parseint, ParseByteCount) {
+  uint64_t i = 0;
+  ASSERT_TRUE(android::base::ParseByteCount("123b", &i));
+  ASSERT_EQ(123ULL, i);
+
+  ASSERT_TRUE(android::base::ParseByteCount("8k", &i));
+  ASSERT_EQ(8ULL * 1024, i);
+
+  ASSERT_TRUE(android::base::ParseByteCount("8M", &i));
+  ASSERT_EQ(8ULL * 1024 * 1024, i);
+
+  ASSERT_TRUE(android::base::ParseByteCount("6g", &i));
+  ASSERT_EQ(6ULL * 1024 * 1024 * 1024, i);
+
+  ASSERT_TRUE(android::base::ParseByteCount("1T", &i));
+  ASSERT_EQ(1ULL * 1024 * 1024 * 1024 * 1024, i);
+
+  ASSERT_TRUE(android::base::ParseByteCount("2p", &i));
+  ASSERT_EQ(2ULL * 1024 * 1024 * 1024 * 1024 * 1024, i);
+
+  ASSERT_TRUE(android::base::ParseByteCount("4e", &i));
+  ASSERT_EQ(4ULL * 1024 * 1024 * 1024 * 1024 * 1024 * 1024, i);
+}
+
+TEST(parseint, ParseByteCount_invalid_suffix) {
+  unsigned u;
+  ASSERT_FALSE(android::base::ParseByteCount("1x", &u));
+}
+
+TEST(parseint, ParseByteCount_overflow) {
+  uint64_t u64;
+  ASSERT_FALSE(android::base::ParseByteCount("4294967295E", &u64));
+
+  uint16_t u16;
+  ASSERT_TRUE(android::base::ParseByteCount("63k", &u16));
+  ASSERT_EQ(63U * 1024, u16);
+  ASSERT_TRUE(android::base::ParseByteCount("65535b", &u16));
+  ASSERT_EQ(65535U, u16);
+  ASSERT_FALSE(android::base::ParseByteCount("65k", &u16));
+}
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
index 9d8dfb2..1619c21 100644
--- a/base/test_utils.cpp
+++ b/base/test_utils.cpp
@@ -92,7 +92,9 @@
   if (fd != -1) {
     close(fd);
   }
-  unlink(path);
+  if (remove_file_) {
+    unlink(path);
+  }
 }
 
 int TemporaryFile::release() {
diff --git a/base/threads.cpp b/base/threads.cpp
new file mode 100644
index 0000000..a71382b
--- /dev/null
+++ b/base/threads.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/threads.h>
+
+#include <stdint.h>
+#include <unistd.h>
+
+#if defined(__APPLE__)
+#include <pthread.h>
+#elif defined(__linux__) && !defined(__ANDROID__)
+#include <syscall.h>
+#elif defined(_WIN32)
+#include <windows.h>
+#endif
+
+namespace android {
+namespace base {
+
+uint64_t GetThreadId() {
+#if defined(__BIONIC__)
+  return gettid();
+#elif defined(__APPLE__)
+  uint64_t tid;
+  pthread_threadid_np(NULL, &tid);
+  return tid;
+#elif defined(__linux__)
+  return syscall(__NR_gettid);
+#elif defined(_WIN32)
+  return GetCurrentThreadId();
+#endif
+}
+
+}  // namespace base
+}  // namespace android
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
index 79702a6..01b8948 100755
--- a/bootstat/boot_reason_test.sh
+++ b/bootstat/boot_reason_test.sh
@@ -239,6 +239,8 @@
   return 0
 }
 
+BAD_BOOTLOADER_REASON=
+
 [ "USAGE: EXPECT_PROPERTY <prop> <value> [--allow_failure]
 
 Returns true (0) if current return (regex) value is true and the result matches
@@ -249,9 +251,20 @@
   value="${2}"
   shift 2
   val=`adb shell getprop ${property} 2>&1`
-  EXPECT_EQ "${value}" "${val}" for Android property ${property} ||
-    [ -n "${1}" ] ||
-    save_ret=${?}
+  EXPECT_EQ "${value}" "${val}" for Android property ${property}
+  local_ret=${?}
+  if [ 0 != ${local_ret} -a "ro.boot.bootreason" = "${property}" ]; then
+    if [ -z "${BAD_BOOTLOADER_REASON}" ]; then
+      BAD_BOOTLOADER_REASON=${val}
+    elif [ X"${BAD_BOOTLOADER_REASON}" = X"${val}" ]; then
+      local_ret=0
+    fi
+  fi
+  if [ 0 != ${local_ret} ]; then
+    if [ -z "${1}" ] ; then
+      save_ret=${local_ret}
+    fi
+  fi
   return ${save_ret}
 }
 
@@ -287,6 +300,7 @@
 bootstat: Service started: /system/bin/bootstat --record_boot_reason
 bootstat: Service started: /system/bin/bootstat --record_time_since_factory_reset
 bootstat: Service started: /system/bin/bootstat -l
+bootstat: Service started: /system/bin/bootstat --set_system_boot_reason --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l
 bootstat: Battery level at shutdown 100%
 bootstat: Battery level at startup 100%
 init    : Parsing file /system/etc/init/bootstat.rc...
@@ -298,6 +312,7 @@
 init    : processing action (ro.boot.bootreason=*) from (/system/etc/init/bootstat.rc
 init    : processing action (sys.boot_completed=1 && sys.logbootcomplete=1) from (/system/etc/init/bootstat.rc
  (/system/bin/bootstat --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l)'
+ (/system/bin/bootstat --set_system_boot_reason --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l)'
  (/system/bin/bootstat -r post_decrypt_time_elapsed)'
 init    : Command 'exec - system log -- /system/bin/bootstat --record_boot_complete' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
 init    : Command 'exec - system log -- /system/bin/bootstat --record_boot_reason' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
@@ -407,29 +422,31 @@
        tr ' \f\t\r\n' '_____'`
   case ${var} in
     watchdog | watchdog,?* ) ;;
-    kernel_panic | kernel_panic,?*) ;;
-    recovery | recovery,?*) ;;
-    bootloader | bootloader,?*) ;;
-    cold | cold,?*) ;;
-    hard | hard,?*) ;;
-    warm | warm,?*) ;;
-    shutdown | shutdown,?*) ;;
+    kernel_panic | kernel_panic,?* ) ;;
+    recovery | recovery,?* ) ;;
+    bootloader | bootloader,?* ) ;;
+    cold | cold,?* ) ;;
+    hard | hard,?* ) ;;
+    warm | warm,?* ) ;;
+    shutdown | shutdown,?* ) ;;
     reboot,reboot | reboot,reboot,* )     var=${var#reboot,} ; var=${var%,} ;;
     reboot,cold | reboot,cold,* )         var=${var#reboot,} ; var=${var%,} ;;
     reboot,hard | reboot,hard,* )         var=${var#reboot,} ; var=${var%,} ;;
     reboot,warm | reboot,warm,* )         var=${var#reboot,} ; var=${var%,} ;;
     reboot,recovery | reboot,recovery,* ) var=${var#reboot,} ; var=${var%,} ;;
     reboot,bootloader | reboot,bootloader,* ) var=${var#reboot,} ; var=${var%,} ;;
-    reboot | reboot,?*) ;;
+    reboot | reboot,?* ) ;;
     # Aliases and Heuristics
-    *wdog* | *watchdog* )     var="watchdog" ;;
-    *powerkey* )              var="cold,powerkey" ;;
-    *panic* | *kernel_panic*) var="kernel_panic" ;;
-    *thermal*)                var="shutdown,thermal" ;;
-    *s3_wakeup*)              var="warm,s3_wakeup" ;;
-    *hw_reset*)               var="hard,hw_reset" ;;
-    *bootloader*)             var="bootloader" ;;
-    *)                        var="reboot" ;;
+    *wdog* | *watchdog* )                   var="watchdog" ;;
+    *powerkey* | *power_key* | *PowerKey* ) var="cold,powerkey" ;;
+    *panic* | *kernel_panic* )              var="kernel_panic" ;;
+    *thermal* )                             var="shutdown,thermal" ;;
+    *s3_wakeup* )                           var="warm,s3_wakeup" ;;
+    *hw_reset* )                            var="hard,hw_reset" ;;
+    *usb* )                                 var="cold,charger" ;;
+    *rtc* )                                 var="cold,rtc" ;;
+    *bootloader* )                          var="bootloader" ;;
+    * )                                     var="reboot" ;;
   esac
   echo ${var}
 }
@@ -566,9 +583,9 @@
   duration_test
   case ${TEST} in
     bootloader | recovery | cold | hard | warm ) reason=${TEST} ;;
-    *)                                           reason=reboot,${TEST} ;;
+    *)                                           reason=reboot,${TEST#optional_} ;;
   esac
-  adb reboot ${TEST}
+  adb reboot ${TEST#optional_}
   wait_for_screen
   bootloader_reason=`validate_property ro.boot.bootreason`
   EXPECT_PROPERTY ro.boot.bootreason ${bootloader_reason}
@@ -792,6 +809,63 @@
   exitPstore
 }
 
+[ "USAGE: test_kernel_panic_subreason
+
+kernel_panic_subreason test:
+- echo SysRq : Trigger a crash : 'test' | adb shell su root tee /dev/kmsg
+- echo c | adb shell su root tee /proc/sysrq-trigger
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report kernel_panic,sysrq,test" ]
+test_kernel_panic_subreason() {
+  checkDebugBuild || return
+  duration_test ">90"
+  panic_msg="kernel_panic,sysrq,test"
+  enterPstore
+  if [ ${?} != 0 ]; then
+    echo "         or functional bootloader" >&2
+    panic_msg="\(kernel_panic,sysrq,test\|kernel_panic\)"
+    pstore_ok=true
+  fi
+  echo "SysRq : Trigger a crash : 'test'" | adb shell su root tee /dev/kmsg
+  echo c | adb shell su root tee /proc/sysrq-trigger >/dev/null
+  wait_for_screen
+  EXPECT_PROPERTY sys.boot.reason ${panic_msg}
+  EXPECT_PROPERTY persist.sys.boot.reason ${panic_msg}
+  report_bootstat_logs kernel_panic,sysrq,test \
+    "-bootstat: Unknown boot reason: kernel_panic,sysrq,test"
+  exitPstore
+}
+
+[ "USAGE: test_kernel_panic_hung
+
+kernel_panic_hung test:
+- echo Kernel panic - not synching: hung_task: blocked tasks |
+  adb shell su root tee /dev/kmsg
+- adb reboot warm
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- NB: should report kernel_panic,hung" ]
+test_kernel_panic_hung() {
+  checkDebugBuild || return
+  duration_test
+  panic_msg="kernel_panic,hung"
+  enterPstore
+  if [ ${?} != 0 ]; then
+    echo "         or functional bootloader" >&2
+    panic_msg="\(kernel_panic,hung\|reboot,hung\)"
+    pstore_ok=true
+  fi
+  echo "Kernel panic - not syncing: hung_task: blocked tasks" |
+    adb shell su root tee /dev/kmsg
+  adb reboot warm
+  wait_for_screen
+  EXPECT_PROPERTY sys.boot.reason ${panic_msg}
+  EXPECT_PROPERTY persist.sys.boot.reason ${panic_msg}
+  report_bootstat_logs kernel_panic,hung
+  exitPstore
+}
+
 [ "USAGE: test_warm
 
 warm test
@@ -875,6 +949,20 @@
   report_bootstat_logs reboot,adb
 }
 
+[ "USAGE: test_rescueparty
+
+rescueparty test
+- adb reboot rescueparty
+- (wait until screen is up, boot has completed)
+- adb shell getprop sys.boot.reason
+- adb shell getprop ro.boot.bootreason
+- NB: should report reboot,rescueparty" ]
+test_optional_rescueparty() {
+  blind_reboot_test
+  echo "WARNING: legacy devices are allowed to fail following ro.boot.bootreason result" >&2
+  EXPECT_PROPERTY ro.boot.bootreason reboot,rescueparty
+}
+
 [ "USAGE: test_Its_Just_So_Hard_reboot
 
 Its Just So Hard reboot test:
@@ -1051,12 +1139,12 @@
   if [ -z "${2}" ]; then
     # Hard coded should shell fail to find them above (search/permission issues)
     eval set properties ota cold factory_reset hard battery unknown \
-             kernel_panic warm thermal_shutdown userrequested_shutdown \
-             shell_reboot adb_reboot Its_Just_So_Hard_reboot \
-             bootloader_normal bootloader_watchdog bootloader_kernel_panic \
-             bootloader_oem_powerkey bootloader_wdog_reset \
-             bootloader_wdog_reset bootloader_wdog_reset bootloader_hard \
-             bootloader_recovery
+             kernel_panic kernel_panic_subreason kernel_panic_hung warm \
+             thermal_shutdown userrequested_shutdown shell_reboot adb_reboot \
+             Its_Just_So_Hard_reboot bootloader_normal bootloader_watchdog \
+             bootloader_kernel_panic bootloader_oem_powerkey \
+             bootloader_wdog_reset bootloader_wdog_reset bootloader_wdog_reset \
+             bootloader_hard bootloader_recovery
   fi
   if [ X"nothing" = X"${1}" ]; then
     shift 1
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 7a67894..39912f0 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -29,7 +29,9 @@
 #include <ctime>
 #include <map>
 #include <memory>
+#include <regex>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include <android-base/chrono_utils.h>
@@ -140,7 +142,7 @@
 // values.
 const std::map<std::string, int32_t> kBootReasonMap = {
     {"empty", kEmptyBootReason},
-    {"unknown", kUnknownBootReason},
+    {"__BOOTSTAT_UNKNOWN__", kUnknownBootReason},
     {"normal", 2},
     {"recovery", 3},
     {"reboot", 4},
@@ -193,12 +195,14 @@
     {"s3_wakeup", 51},
     {"kernel_panic,sysrq", 52},
     {"kernel_panic,NULL", 53},
+    {"kernel_panic,null", 53},
     {"kernel_panic,BUG", 54},
+    {"kernel_panic,bug", 54},
     {"bootloader", 55},
     {"cold", 56},
     {"hard", 57},
     {"warm", 58},
-    {"recovery", 59},
+    // {"recovery", 59},  // Duplicate of enum 3 above. Immediate reuse possible.
     {"thermal-shutdown", 60},
     {"shutdown,thermal", 61},
     {"shutdown,battery", 62},
@@ -229,7 +233,7 @@
     {"shutdown,thermal,battery", 87},
     {"reboot,its_just_so_hard", 88},  // produced by boot_reason_test
     {"reboot,Its Just So Hard", 89},  // produced by boot_reason_test
-    {"usb", 90},
+    {"reboot,rescueparty", 90},
     {"charge", 91},
     {"oem_tz_crash", 92},
     {"uvlo", 93},
@@ -287,6 +291,22 @@
     {"oem_sdi_err_fatal", 145},
     {"pmic_watchdog", 146},
     {"software_master", 147},
+    {"cold,charger", 148},
+    {"cold,rtc", 149},
+    {"cold,rtc,2sec", 150},
+    {"reboot,tool", 151},
+    {"reboot,wdt", 152},
+    {"reboot,unknown", 153},
+    {"kernel_panic,audit", 154},
+    {"kernel_panic,atomic", 155},
+    {"kernel_panic,hung", 156},
+    {"kernel_panic,hung,rcu", 157},
+    {"kernel_panic,init", 158},
+    {"kernel_panic,oom", 159},
+    {"kernel_panic,stack", 160},
+    {"kernel_panic,sysrq,livelock,alarm", 161},   // llkd
+    {"kernel_panic,sysrq,livelock,driver", 162},  // llkd
+    {"kernel_panic,sysrq,livelock,zombie", 163},  // llkd
 };
 
 // Converts a string value representing the reason the system booted to an
@@ -463,11 +483,13 @@
     }
     return std::string::npos;
   }
+
+  operator const std::string&() const { return console; }
 };
 
 // If bit error match to needle, correct it.
 // Return true if any corrections were discovered and applied.
-bool correctForBer(std::string& reason, const std::string& needle) {
+bool correctForBitError(std::string& reason, const std::string& needle) {
   bool corrected = false;
   if (reason.length() < needle.length()) return corrected;
   const pstoreConsole console(reason);
@@ -485,20 +507,215 @@
   return corrected;
 }
 
+// If bit error match to needle, correct it.
+// Return true if any corrections were discovered and applied.
+// Try again if we can replace underline with spaces.
+bool correctForBitErrorOrUnderline(std::string& reason, const std::string& needle) {
+  bool corrected = correctForBitError(reason, needle);
+  std::string _needle(needle);
+  std::transform(_needle.begin(), _needle.end(), _needle.begin(),
+                 [](char c) { return (c == '_') ? ' ' : c; });
+  if (needle != _needle) {
+    corrected |= correctForBitError(reason, _needle);
+  }
+  return corrected;
+}
+
+// Converts a string value representing the reason the system booted to a
+// string complying with Android system standard reason.
+void transformReason(std::string& reason) {
+  std::transform(reason.begin(), reason.end(), reason.begin(), ::tolower);
+  std::transform(reason.begin(), reason.end(), reason.begin(),
+                 [](char c) { return ::isblank(c) ? '_' : c; });
+  std::transform(reason.begin(), reason.end(), reason.begin(),
+                 [](char c) { return ::isprint(c) ? c : '?'; });
+}
+
+// Check subreasons for reboot,<subreason> kernel_panic,sysrq,<subreason> or
+// kernel_panic,<subreason>.
+//
+// If quoted flag is set, pull out and correct single quoted ('), newline (\n)
+// or unprintable character terminated subreason, pos is supplied just beyond
+// first quote.  if quoted false, pull out and correct newline (\n) or
+// unprintable character terminated subreason.
+//
+// Heuristics to find termination is painted into a corner:
+
+// single bit error for quote ' that we can block.  It is acceptable for
+// the others 7, g in reason.  2/9 chance will miss the terminating quote,
+// but there is always the terminating newline that usually immediately
+// follows to fortify our chances.
+bool likely_single_quote(char c) {
+  switch (static_cast<uint8_t>(c)) {
+    case '\'':         // '\''
+    case '\'' ^ 0x01:  // '&'
+    case '\'' ^ 0x02:  // '%'
+    case '\'' ^ 0x04:  // '#'
+    case '\'' ^ 0x08:  // '/'
+      return true;
+    case '\'' ^ 0x10:  // '7'
+      break;
+    case '\'' ^ 0x20:  // '\a' (unprintable)
+      return true;
+    case '\'' ^ 0x40:  // 'g'
+      break;
+    case '\'' ^ 0x80:  // 0xA7 (unprintable)
+      return true;
+  }
+  return false;
+}
+
+// ::isprint(c) and likely_space() will prevent us from being called for
+// fundamentally printable entries, except for '\r' and '\b'.
+//
+// Except for * and J, single bit errors for \n, all others are non-
+// printable so easy catch.  It is _acceptable_ for *, J or j to exist in
+// the reason string, so 2/9 chance we will miss the terminating newline.
+//
+// NB: J might not be acceptable, except if at the beginning or preceded
+//     with a space, '(' or any of the quotes and their BER aliases.
+// NB: * might not be acceptable, except if at the beginning or preceded
+//     with a space, another *, or any of the quotes or their BER aliases.
+//
+// To reduce the chances to closer to 1/9 is too complicated for the gain.
+bool likely_newline(char c) {
+  switch (static_cast<uint8_t>(c)) {
+    case '\n':         // '\n' (unprintable)
+    case '\n' ^ 0x01:  // '\r' (unprintable)
+    case '\n' ^ 0x02:  // '\b' (unprintable)
+    case '\n' ^ 0x04:  // 0x0E (unprintable)
+    case '\n' ^ 0x08:  // 0x02 (unprintable)
+    case '\n' ^ 0x10:  // 0x1A (unprintable)
+      return true;
+    case '\n' ^ 0x20:  // '*'
+    case '\n' ^ 0x40:  // 'J'
+      break;
+    case '\n' ^ 0x80:  // 0x8A (unprintable)
+      return true;
+  }
+  return false;
+}
+
+// ::isprint(c) will prevent us from being called for all the printable
+// matches below.  If we let unprintables through because of this, they
+// get converted to underscore (_) by the validation phase.
+bool likely_space(char c) {
+  switch (static_cast<uint8_t>(c)) {
+    case ' ':          // ' '
+    case ' ' ^ 0x01:   // '!'
+    case ' ' ^ 0x02:   // '"'
+    case ' ' ^ 0x04:   // '$'
+    case ' ' ^ 0x08:   // '('
+    case ' ' ^ 0x10:   // '0'
+    case ' ' ^ 0x20:   // '\0' (unprintable)
+    case ' ' ^ 0x40:   // 'P'
+    case ' ' ^ 0x80:   // 0xA0 (unprintable)
+    case '\t':         // '\t'
+    case '\t' ^ 0x01:  // '\b' (unprintable) (likely_newline counters)
+    case '\t' ^ 0x02:  // '\v' (unprintable)
+    case '\t' ^ 0x04:  // '\r' (unprintable) (likely_newline counters)
+    case '\t' ^ 0x08:  // 0x01 (unprintable)
+    case '\t' ^ 0x10:  // 0x19 (unprintable)
+    case '\t' ^ 0x20:  // ')'
+    case '\t' ^ 0x40:  // '1'
+    case '\t' ^ 0x80:  // 0x89 (unprintable)
+      return true;
+  }
+  return false;
+}
+
+std::string getSubreason(const std::string& content, size_t pos, bool quoted) {
+  static constexpr size_t max_reason_length = 256;
+
+  std::string subReason(content.substr(pos, max_reason_length));
+  // Correct against any known strings that Bit Error Match
+  for (const auto& s : knownReasons) {
+    correctForBitErrorOrUnderline(subReason, s);
+  }
+  std::string terminator(quoted ? "'" : "");
+  for (const auto& m : kBootReasonMap) {
+    if (m.first.length() <= strlen("cold")) continue;  // too short?
+    if (correctForBitErrorOrUnderline(subReason, m.first + terminator)) continue;
+    if (m.first.length() <= strlen("reboot,cold")) continue;  // short?
+    if (android::base::StartsWith(m.first, "reboot,")) {
+      correctForBitErrorOrUnderline(subReason, m.first.substr(strlen("reboot,")) + terminator);
+    } else if (android::base::StartsWith(m.first, "kernel_panic,sysrq,")) {
+      correctForBitErrorOrUnderline(subReason,
+                                    m.first.substr(strlen("kernel_panic,sysrq,")) + terminator);
+    } else if (android::base::StartsWith(m.first, "kernel_panic,")) {
+      correctForBitErrorOrUnderline(subReason, m.first.substr(strlen("kernel_panic,")) + terminator);
+    }
+  }
+  for (pos = 0; pos < subReason.length(); ++pos) {
+    char c = subReason[pos];
+    if (!(::isprint(c) || likely_space(c)) || likely_newline(c) ||
+        (quoted && likely_single_quote(c))) {
+      subReason.erase(pos);
+      break;
+    }
+  }
+  transformReason(subReason);
+  return subReason;
+}
+
 bool addKernelPanicSubReason(const pstoreConsole& console, std::string& ret) {
   // Check for kernel panic types to refine information
-  if (console.rfind("SysRq : Trigger a crash") != std::string::npos) {
-    // Can not happen, except on userdebug, during testing/debugging.
+  if ((console.rfind("SysRq : Trigger a crash") != std::string::npos) ||
+      (console.rfind("PC is at sysrq_handle_crash+") != std::string::npos)) {
     ret = "kernel_panic,sysrq";
+    // Invented for Android to allow daemons that specifically trigger sysrq
+    // to communicate more accurate boot subreasons via last console messages.
+    static constexpr char sysrqSubreason[] = "SysRq : Trigger a crash : '";
+    auto pos = console.rfind(sysrqSubreason);
+    if (pos != std::string::npos) {
+      ret += "," + getSubreason(console, pos + strlen(sysrqSubreason), /* quoted */ true);
+    }
     return true;
   }
   if (console.rfind("Unable to handle kernel NULL pointer dereference at virtual address") !=
       std::string::npos) {
-    ret = "kernel_panic,NULL";
+    ret = "kernel_panic,null";
     return true;
   }
   if (console.rfind("Kernel BUG at ") != std::string::npos) {
-    ret = "kernel_panic,BUG";
+    ret = "kernel_panic,bug";
+    return true;
+  }
+
+  std::string panic("Kernel panic - not syncing: ");
+  auto pos = console.rfind(panic);
+  if (pos != std::string::npos) {
+    static const std::vector<std::pair<const std::string, const std::string>> panicReasons = {
+        {"Out of memory", "oom"},
+        {"out of memory", "oom"},
+        {"Oh boy, that early out of memory", "oom"},  // omg
+        {"BUG!", "bug"},
+        {"hung_task: blocked tasks", "hung"},
+        {"audit: ", "audit"},
+        {"scheduling while atomic", "atomic"},
+        {"Attempted to kill init!", "init"},
+        {"Requested init", "init"},
+        {"No working init", "init"},
+        {"Could not decompress init", "init"},
+        {"RCU Stall", "hung,rcu"},
+        {"stack-protector", "stack"},
+        {"kernel stack overflow", "stack"},
+        {"Corrupt kernel stack", "stack"},
+        {"low stack detected", "stack"},
+        {"corrupted stack end", "stack"},
+    };
+
+    ret = "kernel_panic";
+    for (auto& s : panicReasons) {
+      if (console.find(panic + s.first, pos) != std::string::npos) {
+        ret += "," + s.second;
+        return true;
+      }
+    }
+    auto reason = getSubreason(console, pos + panic.length(), /* newline */ false);
+    if (reason.length() > 3) {
+      ret += "," + reason;
+    }
     return true;
   }
   return false;
@@ -508,32 +725,12 @@
   return addKernelPanicSubReason(pstoreConsole(content), ret);
 }
 
-// std::transform Helper callback functions:
-// Converts a string value representing the reason the system booted to a
-// string complying with Android system standard reason.
-char tounderline(char c) {
-  return ::isblank(c) ? '_' : c;
-}
-
-char toprintable(char c) {
-  return ::isprint(c) ? c : '?';
-}
-
-// Cleanup boot_reason regarding acceptable character set
-void transformReason(std::string& reason) {
-  std::transform(reason.begin(), reason.end(), reason.begin(), ::tolower);
-  std::transform(reason.begin(), reason.end(), reason.begin(), tounderline);
-  std::transform(reason.begin(), reason.end(), reason.begin(), toprintable);
-}
-
 const char system_reboot_reason_property[] = "sys.boot.reason";
 const char last_reboot_reason_property[] = LAST_REBOOT_REASON_PROPERTY;
 const char bootloader_reboot_reason_property[] = "ro.boot.bootreason";
 
 // Scrub, Sanitize, Standardize and Enhance the boot reason string supplied.
 std::string BootReasonStrToReason(const std::string& boot_reason) {
-  static const size_t max_reason_length = 256;
-
   std::string ret(GetProperty(system_reboot_reason_property));
   std::string reason(boot_reason);
   // If sys.boot.reason == ro.boot.bootreason, let's re-evaluate
@@ -568,26 +765,36 @@
     // A series of checks to take some officially unsupported reasons
     // reported by the bootloader and find some logical and canonical
     // sense.  In an ideal world, we would require those bootloaders
-    // to behave and follow our standards.
+    // to behave and follow our CTS standards.
+    //
+    // first member is the output
+    // second member is an unanchored regex for an alias
+    //
+    // If output has a prefix of <bang> '!', we do not use it as a
+    // match needle (and drop the <bang> prefix when landing in output),
+    // otherwise look for it as well. This helps keep the scale of the
+    // following table smaller.
     static const std::vector<std::pair<const std::string, const std::string>> aliasReasons = {
         {"watchdog", "wdog"},
-        {"cold,powerkey", "powerkey"},
+        {"cold,powerkey", "powerkey|power_key|PowerKey"},
         {"kernel_panic", "panic"},
         {"shutdown,thermal", "thermal"},
         {"warm,s3_wakeup", "s3_wakeup"},
         {"hard,hw_reset", "hw_reset"},
+        {"cold,charger", "usb"},
+        {"cold,rtc", "rtc"},
         {"reboot,2sec", "2sec_reboot"},
         {"bootloader", ""},
     };
 
-    // Either the primary or alias is found _somewhere_ in the reason string.
     for (auto& s : aliasReasons) {
-      if (reason.find(s.first) != std::string::npos) {
+      size_t firstHasNot = s.first[0] == '!';
+      if (!firstHasNot && (reason.find(s.first) != std::string::npos)) {
         ret = s.first;
         break;
       }
-      if (s.second.size() && (reason.find(s.second) != std::string::npos)) {
-        ret = s.first;
+      if (s.second.size() && std::regex_search(reason, std::regex(s.second))) {
+        ret = s.first.substr(firstHasNot);
         break;
       }
     }
@@ -626,28 +833,7 @@
       static const char cmd[] = "reboot: Restarting system with command '";
       size_t pos = console.rfind(cmd);
       if (pos != std::string::npos) {
-        pos += strlen(cmd);
-        std::string subReason(content.substr(pos, max_reason_length));
-        // Correct against any known strings that Bit Error Match
-        for (const auto& s : knownReasons) {
-          correctForBer(subReason, s);
-        }
-        for (const auto& m : kBootReasonMap) {
-          if (m.first.length() <= strlen("cold")) continue;  // too short?
-          if (correctForBer(subReason, m.first + "'")) continue;
-          if (m.first.length() <= strlen("reboot,cold")) continue;  // short?
-          if (!android::base::StartsWith(m.first, "reboot,")) continue;
-          correctForBer(subReason, m.first.substr(strlen("reboot,")) + "'");
-        }
-        for (pos = 0; pos < subReason.length(); ++pos) {
-          char c = subReason[pos];
-          // #, &, %, / are common single bit error for ' that we can block
-          if (!::isprint(c) || (c == '\'') || (c == '#') || (c == '&') || (c == '%') || (c == '/')) {
-            subReason.erase(pos);
-            break;
-          }
-        }
-        transformReason(subReason);
+        std::string subReason(getSubreason(content, pos + strlen(cmd), /* quoted */ true));
         if (subReason != "") {  // Will not land "reboot" as that is too blunt.
           if (isKernelRebootReason(subReason)) {
             ret = "reboot," + subReason;  // User space can't talk kernel reasons.
@@ -685,7 +871,7 @@
       if (pos != std::string::npos) {
         digits = content.substr(pos + strlen(battery), strlen("100 "));
         // correct common errors
-        correctForBer(digits, "100 ");
+        correctForBitError(digits, "100 ");
         if (digits[0] == '!') digits[0] = '1';
         if (digits[1] == '!') digits[1] = '1';
       }
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 7e6f24d..7c28b28 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -112,7 +112,6 @@
         "libbase",
         "libdebuggerd",
         "libbacktrace",
-        "libunwind",
         "libunwindstack",
         "libdexfile",
         "liblzma",
@@ -158,7 +157,6 @@
 
     static_libs: [
         "libbacktrace",
-        "libunwind",
         "libunwindstack",
         "liblzma",
         "libbase",
@@ -221,6 +219,8 @@
             stem: "debuggerd_test64",
         },
     },
+
+    test_suites: ["device-tests"],
 }
 
 cc_benchmark {
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 397ff2f..dfb7a6a 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -80,8 +80,13 @@
     return value;                                                  \
   }()
 
+// Backtrace frame dump could contain:
+//   #01 pc 0001cded  /data/tmp/debuggerd_test32 (raise_debugger_signal+80)
+// or
+//   #01 pc 00022a09  /data/tmp/debuggerd_test32 (offset 0x12000) (raise_debugger_signal+80)
 #define ASSERT_BACKTRACE_FRAME(result, frame_name) \
-  ASSERT_MATCH(result, R"(#\d\d pc [0-9a-f]+\s+ \S+ \()" frame_name R"(\+)");
+  ASSERT_MATCH(result,                             \
+               R"(#\d\d pc [0-9a-f]+\s+ \S+ (\(offset 0x[0-9a-f]+\) )?\()" frame_name R"(\+)");
 
 static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
                                  InterceptStatus* status, DebuggerdDumpType intercept_type) {
@@ -346,7 +351,9 @@
 
   std::string result;
   ConsumeFd(std::move(output_fd), &result);
-  ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER\), fault addr --------)");
+  ASSERT_MATCH(
+      result,
+      R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
   ASSERT_MATCH(result, R"(backtrace:)");
 }
 
@@ -354,7 +361,14 @@
   int intercept_result;
   unique_fd output_fd;
   StartProcess([]() {
-    android_set_abort_message("abort message goes here");
+    // Arrived at experimentally;
+    // logd truncates at 4062.
+    // strlen("Abort message: ''") is 17.
+    // That's 4045, but we also want a NUL.
+    char buf[4045 + 1];
+    memset(buf, 'x', sizeof(buf));
+    buf[sizeof(buf) - 1] = '\0';
+    android_set_abort_message(buf);
     abort();
   });
   StartIntercept(&output_fd);
@@ -366,7 +380,7 @@
 
   std::string result;
   ConsumeFd(std::move(output_fd), &result);
-  ASSERT_MATCH(result, R"(Abort message: 'abort message goes here')");
+  ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
 }
 
 TEST_F(CrasherTest, abort_message_backtrace) {
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index dea2e17..079a574 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -304,7 +304,16 @@
 
   crash_mutex.lock();
   if (lock_count++ > 0) {
-    async_safe_format_log(ANDROID_LOG_ERROR, "libc", "recursed signal handler call, exiting");
+    async_safe_format_log(ANDROID_LOG_ERROR, "libc", "recursed signal handler call, aborting");
+    signal(SIGABRT, SIG_DFL);
+    raise(SIGABRT);
+    sigset_t sigset;
+    sigemptyset(&sigset);
+    sigaddset(&sigset, SIGABRT);
+    sigprocmask(SIG_UNBLOCK, &sigset, nullptr);
+
+    // Just in case...
+    async_safe_format_log(ANDROID_LOG_ERROR, "libc", "abort didn't exit, exiting");
     _exit(1);
   }
 
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 05e6efa..c07a34a 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -169,24 +169,26 @@
     return;
   }
 
-  const char* signal_name = get_signame(info->si_signo);
-  bool has_address = signal_has_si_addr(info->si_signo, info->si_code);
-
-  // Many signals don't have an address.
+  // Many signals don't have an address or sender.
   char addr_desc[32] = "";  // ", fault addr 0x1234"
-  if (has_address) {
+  if (signal_has_si_addr(info)) {
     async_safe_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr);
   }
+  pid_t self_pid = __getpid();
+  char sender_desc[32] = {};  // " from pid 1234, uid 666"
+  if (signal_has_sender(info, self_pid)) {
+    get_signal_sender(sender_desc, sizeof(sender_desc), info);
+  }
 
   char main_thread_name[MAX_TASK_NAME_LEN + 1];
   if (!get_main_thread_name(main_thread_name, sizeof(main_thread_name))) {
     strncpy(main_thread_name, "<unknown>", sizeof(main_thread_name));
   }
 
-  async_safe_format_log(
-      ANDROID_LOG_FATAL, "libc", "Fatal signal %d (%s), code %d (%s)%s in tid %d (%s), pid %d (%s)",
-      info->si_signo, signal_name, info->si_code, get_sigcode(info->si_signo, info->si_code),
-      addr_desc, __gettid(), thread_name, __getpid(), main_thread_name);
+  async_safe_format_log(ANDROID_LOG_FATAL, "libc",
+                        "Fatal signal %d (%s), code %d (%s%s)%s in tid %d (%s), pid %d (%s)",
+                        info->si_signo, get_signame(info), info->si_code, get_sigcode(info),
+                        sender_desc, addr_desc, __gettid(), thread_name, self_pid, main_thread_name);
 }
 
 /*
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index 7b04e71..7c5304e 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -74,8 +74,10 @@
 
 void drop_capabilities();
 
-bool signal_has_si_addr(int si_signo, int si_code);
-const char* get_signame(int sig);
-const char* get_sigcode(int signo, int code);
+bool signal_has_sender(const siginfo_t*, pid_t caller_pid);
+bool signal_has_si_addr(const siginfo_t*);
+void get_signal_sender(char* buf, size_t n, const siginfo_t*);
+const char* get_signame(const siginfo_t*);
+const char* get_sigcode(const siginfo_t*);
 
 #endif // _DEBUGGERD_UTILITY_H
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 933a597..e11be1e 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -102,18 +102,24 @@
   if (!cause.empty()) _LOG(log, logtype::HEADER, "Cause: %s\n", cause.c_str());
 }
 
-static void dump_signal_info(log_t* log, const siginfo_t* si) {
+static void dump_signal_info(log_t* log, const ThreadInfo& thread_info) {
   char addr_desc[32]; // ", fault addr 0x1234"
-  if (signal_has_si_addr(si->si_signo, si->si_code)) {
-    snprintf(addr_desc, sizeof(addr_desc), "%p", si->si_addr);
+  if (signal_has_si_addr(thread_info.siginfo)) {
+    snprintf(addr_desc, sizeof(addr_desc), "%p", thread_info.siginfo->si_addr);
   } else {
     snprintf(addr_desc, sizeof(addr_desc), "--------");
   }
 
-  _LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s), fault addr %s\n", si->si_signo,
-       get_signame(si->si_signo), si->si_code, get_sigcode(si->si_signo, si->si_code), addr_desc);
+  char sender_desc[32] = {};  // " from pid 1234, uid 666"
+  if (signal_has_sender(thread_info.siginfo, thread_info.pid)) {
+    get_signal_sender(sender_desc, sizeof(sender_desc), thread_info.siginfo);
+  }
 
-  dump_probable_cause(log, si);
+  _LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s%s), fault addr %s\n",
+       thread_info.siginfo->si_signo, get_signame(thread_info.siginfo),
+       thread_info.siginfo->si_code, get_sigcode(thread_info.siginfo), sender_desc, addr_desc);
+
+  dump_probable_cause(log, thread_info.siginfo);
 }
 
 static void dump_thread_info(log_t* log, const ThreadInfo& thread_info) {
@@ -239,19 +245,22 @@
     return;
   }
 
-  char msg[512];
-  if (length >= sizeof(msg)) {
-    _LOG(log, logtype::HEADER, "Abort message too long: claimed length = %zd\n", length);
+  // The length field includes the length of the length field itself.
+  if (length < sizeof(size_t)) {
+    _LOG(log, logtype::HEADER, "Abort message header malformed: claimed length = %zd\n", length);
     return;
   }
 
-  if (!process_memory->ReadFully(address + sizeof(length), msg, length)) {
+  length -= sizeof(size_t);
+
+  // The abort message should be null terminated already, but reserve a spot for NUL just in case.
+  std::vector<char> msg(length + 1);
+  if (!process_memory->ReadFully(address + sizeof(length), &msg[0], length)) {
     _LOG(log, logtype::HEADER, "Failed to read abort message: %s\n", strerror(errno));
     return;
   }
 
-  msg[length] = '\0';
-  _LOG(log, logtype::HEADER, "Abort message: '%s'\n", msg);
+  _LOG(log, logtype::HEADER, "Abort message: '%s'\n", &msg[0]);
 }
 
 static void dump_all_maps(log_t* log, BacktraceMap* map, Memory* process_memory, uint64_t addr) {
@@ -409,7 +418,7 @@
   dump_thread_info(log, thread_info);
 
   if (thread_info.siginfo) {
-    dump_signal_info(log, thread_info.siginfo);
+    dump_signal_info(log, thread_info);
   }
 
   if (primary_thread) {
@@ -439,7 +448,7 @@
     if (map) {
       uint64_t addr = 0;
       siginfo_t* si = thread_info.siginfo;
-      if (signal_has_si_addr(si->si_signo, si->si_code)) {
+      if (signal_has_si_addr(si)) {
         addr = reinterpret_cast<uint64_t>(si->si_addr);
       }
       dump_all_maps(log, map, process_memory, addr);
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index d153865..1f6f3c8 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -74,25 +74,22 @@
                       && (log->crashed_tid == log->current_tid);
   static bool write_to_kmsg = should_write_to_kmsg();
 
-  char buf[512];
+  std::string msg;
   va_list ap;
   va_start(ap, fmt);
-  vsnprintf(buf, sizeof(buf), fmt, ap);
+  android::base::StringAppendV(&msg, fmt, ap);
   va_end(ap);
 
-  size_t len = strlen(buf);
-  if (len <= 0) {
-    return;
-  }
+  if (msg.empty()) return;
 
   if (write_to_tombstone) {
-    TEMP_FAILURE_RETRY(write(log->tfd, buf, len));
+    TEMP_FAILURE_RETRY(write(log->tfd, msg.c_str(), msg.size()));
   }
 
   if (write_to_logcat) {
-    __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_FATAL, LOG_TAG, buf);
+    __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_FATAL, LOG_TAG, msg.c_str());
     if (log->amfd_data != nullptr) {
-      *log->amfd_data += buf;
+      *log->amfd_data += msg;
     }
 
     if (write_to_kmsg) {
@@ -100,11 +97,11 @@
       if (kmsg_fd.get() >= 0) {
         // Our output might contain newlines which would otherwise be handled by the android logger.
         // Split the lines up ourselves before sending to the kernel logger.
-        if (buf[len - 1] == '\n') {
-          buf[len - 1] = '\0';
+        if (msg.back() == '\n') {
+          msg.back() = '\0';
         }
 
-        std::vector<std::string> fragments = android::base::Split(buf, "\n");
+        std::vector<std::string> fragments = android::base::Split(msg, "\n");
         for (const std::string& fragment : fragments) {
           static constexpr char prefix[] = "<3>DEBUG: ";
           struct iovec iov[3];
@@ -257,13 +254,13 @@
   }
 }
 
-bool signal_has_si_addr(int si_signo, int si_code) {
+bool signal_has_si_addr(const siginfo_t* si) {
   // Manually sent signals won't have si_addr.
-  if (si_code == SI_USER || si_code == SI_QUEUE || si_code == SI_TKILL) {
+  if (si->si_code == SI_USER || si->si_code == SI_QUEUE || si->si_code == SI_TKILL) {
     return false;
   }
 
-  switch (si_signo) {
+  switch (si->si_signo) {
     case SIGBUS:
     case SIGFPE:
     case SIGILL:
@@ -275,8 +272,16 @@
   }
 }
 
-const char* get_signame(int sig) {
-  switch (sig) {
+bool signal_has_sender(const siginfo_t* si, pid_t caller_pid) {
+  return SI_FROMUSER(si) && (si->si_pid != 0) && (si->si_pid != caller_pid);
+}
+
+void get_signal_sender(char* buf, size_t n, const siginfo_t* si) {
+  snprintf(buf, n, " from pid %d, uid %d", si->si_pid, si->si_uid);
+}
+
+const char* get_signame(const siginfo_t* si) {
+  switch (si->si_signo) {
     case SIGABRT: return "SIGABRT";
     case SIGBUS: return "SIGBUS";
     case SIGFPE: return "SIGFPE";
@@ -293,11 +298,11 @@
   }
 }
 
-const char* get_sigcode(int signo, int code) {
+const char* get_sigcode(const siginfo_t* si) {
   // Try the signal-specific codes...
-  switch (signo) {
+  switch (si->si_signo) {
     case SIGILL:
-      switch (code) {
+      switch (si->si_code) {
         case ILL_ILLOPC: return "ILL_ILLOPC";
         case ILL_ILLOPN: return "ILL_ILLOPN";
         case ILL_ILLADR: return "ILL_ILLADR";
@@ -310,7 +315,7 @@
       static_assert(NSIGILL == ILL_BADSTK, "missing ILL_* si_code");
       break;
     case SIGBUS:
-      switch (code) {
+      switch (si->si_code) {
         case BUS_ADRALN: return "BUS_ADRALN";
         case BUS_ADRERR: return "BUS_ADRERR";
         case BUS_OBJERR: return "BUS_OBJERR";
@@ -320,7 +325,7 @@
       static_assert(NSIGBUS == BUS_MCEERR_AO, "missing BUS_* si_code");
       break;
     case SIGFPE:
-      switch (code) {
+      switch (si->si_code) {
         case FPE_INTDIV: return "FPE_INTDIV";
         case FPE_INTOVF: return "FPE_INTOVF";
         case FPE_FLTDIV: return "FPE_FLTDIV";
@@ -333,7 +338,7 @@
       static_assert(NSIGFPE == FPE_FLTSUB, "missing FPE_* si_code");
       break;
     case SIGSEGV:
-      switch (code) {
+      switch (si->si_code) {
         case SEGV_MAPERR: return "SEGV_MAPERR";
         case SEGV_ACCERR: return "SEGV_ACCERR";
 #if defined(SEGV_BNDERR)
@@ -353,21 +358,21 @@
       break;
 #if defined(SYS_SECCOMP) // Our glibc is too old, and we build this for the host too.
     case SIGSYS:
-      switch (code) {
+      switch (si->si_code) {
         case SYS_SECCOMP: return "SYS_SECCOMP";
       }
       static_assert(NSIGSYS == SYS_SECCOMP, "missing SYS_* si_code");
       break;
 #endif
     case SIGTRAP:
-      switch (code) {
+      switch (si->si_code) {
         case TRAP_BRKPT: return "TRAP_BRKPT";
         case TRAP_TRACE: return "TRAP_TRACE";
         case TRAP_BRANCH: return "TRAP_BRANCH";
         case TRAP_HWBKPT: return "TRAP_HWBKPT";
       }
-      if ((code & 0xff) == SIGTRAP) {
-        switch ((code >> 8) & 0xff) {
+      if ((si->si_code & 0xff) == SIGTRAP) {
+        switch ((si->si_code >> 8) & 0xff) {
           case PTRACE_EVENT_FORK:
             return "PTRACE_EVENT_FORK";
           case PTRACE_EVENT_VFORK:
@@ -390,7 +395,7 @@
       break;
   }
   // Then the other codes...
-  switch (code) {
+  switch (si->si_code) {
     case SI_USER: return "SI_USER";
     case SI_KERNEL: return "SI_KERNEL";
     case SI_QUEUE: return "SI_QUEUE";
diff --git a/demangle/Android.bp b/demangle/Android.bp
index 8d5b135..cf6abfd 100644
--- a/demangle/Android.bp
+++ b/demangle/Android.bp
@@ -78,4 +78,9 @@
     shared_libs: [
         "libdemangle",
     ],
+
+    test_suites: ["device-tests"],
+    required: [
+        "libdemangle",
+    ],
 }
diff --git a/demangle/Android.mk b/demangle/Android.mk
index e3cfc2a..d8082a9 100644
--- a/demangle/Android.mk
+++ b/demangle/Android.mk
@@ -19,7 +19,6 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := demangle_fuzzer
-LOCAL_MODULE_TAGS := optional
 LOCAL_SRC_FILES := \
     Demangler.cpp \
     demangle_fuzzer.cpp \
diff --git a/diagnose_usb/Android.bp b/diagnose_usb/Android.bp
new file mode 100644
index 0000000..a7ecf37
--- /dev/null
+++ b/diagnose_usb/Android.bp
@@ -0,0 +1,13 @@
+cc_library_static {
+    name: "libdiagnose_usb",
+    cflags: ["-Wall", "-Wextra", "-Werror"],
+    host_supported: true,
+    target: {
+        windows: {
+            enabled: true,
+        },
+    },
+    srcs: ["diagnose_usb.cpp"],
+    export_include_dirs: ["include"],
+    static_libs: ["libbase"],
+}
diff --git a/diagnose_usb/OWNERS b/diagnose_usb/OWNERS
new file mode 100644
index 0000000..643b448
--- /dev/null
+++ b/diagnose_usb/OWNERS
@@ -0,0 +1,2 @@
+jmgao@google.com
+yabinc@google.com
diff --git a/adb/diagnose_usb.cpp b/diagnose_usb/diagnose_usb.cpp
similarity index 97%
rename from adb/diagnose_usb.cpp
rename to diagnose_usb/diagnose_usb.cpp
index 9f721bf..5695ece 100644
--- a/adb/diagnose_usb.cpp
+++ b/diagnose_usb/diagnose_usb.cpp
@@ -33,7 +33,7 @@
 // Returns a message describing any potential problems we find with udev, or an empty string if we
 // can't find plugdev information (i.e. udev is not installed).
 static std::string GetUdevProblem() {
-#if defined(__linux__)
+#if defined(__linux__) && !defined(__BIONIC__)
     errno = 0;
     group* plugdev_group = getgrnam("plugdev");
 
diff --git a/adb/diagnose_usb.h b/diagnose_usb/include/diagnose_usb.h
similarity index 100%
rename from adb/diagnose_usb.h
rename to diagnose_usb/include/diagnose_usb.h
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 944b00b..983e195 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -16,14 +16,35 @@
 
 include $(LOCAL_PATH)/../platform_tools_tool_version.mk
 
+fastboot_cflags := -Wall -Wextra -Werror -Wunreachable-code
+fastboot_cflags += -DFASTBOOT_VERSION="\"$(tool_version)\""
+fastboot_cflags_darwin := -Wno-unused-parameter
+fastboot_ldlibs_darwin := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
+fastboot_ldlibs_windows := -lws2_32
+# Don't add anything here, we don't want additional shared dependencies
+# on the host fastboot tool, and shared libraries that link against libc++
+# will violate ODR.
+fastboot_shared_libs :=
+fastboot_static_libs := \
+    libziparchive \
+    libsparse \
+    libutils \
+    liblog \
+    libz \
+    libdiagnose_usb \
+    libbase \
+    libcutils \
+    libgtest_host \
+
+fastboot_stl := libc++_static
+
+#
+# Build host libfastboot.
+#
+
 include $(CLEAR_VARS)
-
-LOCAL_CFLAGS += -DFASTBOOT_VERSION="\"$(tool_version)\""
-
-LOCAL_C_INCLUDES := \
-  $(LOCAL_PATH)/../adb \
-
-LOCAL_HEADER_LIBRARIES := bootimg_headers
+LOCAL_MODULE := libfastboot
+LOCAL_MODULE_HOST_OS := darwin linux windows
 
 LOCAL_SRC_FILES := \
     bootimg_utils.cpp \
@@ -36,92 +57,83 @@
     udp.cpp \
     util.cpp \
 
-LOCAL_MODULE := fastboot
-LOCAL_MODULE_TAGS := debug
-LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
-LOCAL_REQUIRED_MODULES := mke2fs make_f2fs
-
-LOCAL_SRC_FILES_linux := usb_linux.cpp
-LOCAL_STATIC_LIBRARIES_linux := libselinux
-LOCAL_REQUIRED_MODULES_linux := e2fsdroid mke2fs.conf sload_f2fs
-
 LOCAL_SRC_FILES_darwin := usb_osx.cpp
-LOCAL_STATIC_LIBRARIES_darwin := libselinux
-LOCAL_REQUIRED_MODULES_darwin := e2fsdroid mke2fs.conf sload_f2fs
-LOCAL_LDLIBS_darwin := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
-LOCAL_CFLAGS_darwin := -Wno-unused-parameter
-
+LOCAL_SRC_FILES_linux := usb_linux.cpp
 LOCAL_SRC_FILES_windows := usb_windows.cpp
-LOCAL_SHARED_LIBRARIES_windows := AdbWinApi
-LOCAL_REQUIRED_MODULES_windows := AdbWinUsbApi
-LOCAL_LDLIBS_windows := -lws2_32
+
 LOCAL_C_INCLUDES_windows := development/host/windows/usb/api
+LOCAL_CFLAGS := $(fastboot_cflags)
+LOCAL_CFLAGS_darwin := $(fastboot_cflags_darwin)
+LOCAL_CXX_STL := $(fastboot_stl)
+LOCAL_HEADER_LIBRARIES := bootimg_headers
+LOCAL_LDLIBS_darwin := $(fastboot_ldlibs_darwin)
+LOCAL_LDLIBS_windows := $(fastboot_ldlibs_windows)
+LOCAL_SHARED_LIBRARIES := $(fastboot_shared_libs)
+LOCAL_STATIC_LIBRARIES := $(fastboot_static_libs)
+include $(BUILD_HOST_STATIC_LIBRARY)
 
-LOCAL_STATIC_LIBRARIES := \
-    libziparchive \
-    libsparse \
-    libutils \
-    liblog \
-    libz \
-    libdiagnose_usb \
-    libbase \
-    libcutils \
-    libgtest_host \
+#
+# Build host fastboot / fastboot.exe
+#
 
-LOCAL_CXX_STL := libc++_static
+include $(CLEAR_VARS)
+LOCAL_MODULE := fastboot
+LOCAL_MODULE_HOST_OS := darwin linux windows
 
-# Don't add anything here, we don't want additional shared dependencies
-# on the host fastboot tool, and shared libraries that link against libc++
-# will violate ODR
-LOCAL_SHARED_LIBRARIES :=
-
+LOCAL_CFLAGS := $(fastboot_cflags)
+LOCAL_CFLAGS_darwin := $(fastboot_cflags_darwin)
+LOCAL_CXX_STL := $(fastboot_stl)
+LOCAL_HEADER_LIBRARIES := bootimg_headers
+LOCAL_LDLIBS_darwin := $(fastboot_ldlibs_darwin)
+LOCAL_LDLIBS_windows := $(fastboot_ldlibs_windows)
+LOCAL_REQUIRED_MODULES := mke2fs make_f2fs
+LOCAL_REQUIRED_MODULES_darwin := e2fsdroid mke2fs.conf sload_f2fs
+LOCAL_REQUIRED_MODULES_linux := e2fsdroid mke2fs.conf sload_f2fs
+LOCAL_REQUIRED_MODULES_windows := AdbWinUsbApi
+LOCAL_SRC_FILES := main.cpp
+LOCAL_SHARED_LIBRARIES := $(fastboot_shared_libs)
+LOCAL_SHARED_LIBRARIES_windows := AdbWinApi
+LOCAL_STATIC_LIBRARIES := libfastboot $(fastboot_static_libs)
 include $(BUILD_HOST_EXECUTABLE)
 
-my_dist_files := $(LOCAL_BUILT_MODULE)
-my_dist_files += $(HOST_OUT_EXECUTABLES)/mke2fs$(HOST_EXECUTABLE_SUFFIX)
-my_dist_files += $(HOST_OUT_EXECUTABLES)/e2fsdroid$(HOST_EXECUTABLE_SUFFIX)
-my_dist_files += $(HOST_OUT_EXECUTABLES)/make_f2fs$(HOST_EXECUTABLE_SUFFIX)
-my_dist_files += $(HOST_OUT_EXECUTABLES)/sload_f2fs$(HOST_EXECUTABLE_SUFFIX)
+#
+# Package fastboot-related executables.
+#
+
+my_dist_files := $(HOST_OUT_EXECUTABLES)/fastboot
+my_dist_files += $(HOST_OUT_EXECUTABLES)/mke2fs
+my_dist_files += $(HOST_OUT_EXECUTABLES)/e2fsdroid
+my_dist_files += $(HOST_OUT_EXECUTABLES)/make_f2fs
+my_dist_files += $(HOST_OUT_EXECUTABLES)/sload_f2fs
 $(call dist-for-goals,dist_files sdk win_sdk,$(my_dist_files))
 ifdef HOST_CROSS_OS
-# Archive fastboot.exe for win_sdk build.
-$(call dist-for-goals,win_sdk,$(ALL_MODULES.host_cross_fastboot.BUILT))
+$(call dist-for-goals,dist_files sdk win_sdk,$(ALL_MODULES.host_cross_fastboot.BUILT))
 endif
 my_dist_files :=
 
-ifeq ($(HOST_OS),linux)
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := usbtest.cpp usb_linux.cpp util.cpp
-LOCAL_MODULE := usbtest
-LOCAL_CFLAGS := -Werror
-LOCAL_STATIC_LIBRARIES := libbase
-include $(BUILD_HOST_EXECUTABLE)
-endif
+#
+# Build host fastboot_test.
+#
 
-# fastboot_test
-# =========================================================
 include $(CLEAR_VARS)
-
 LOCAL_MODULE := fastboot_test
 LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_MODULE_HOST_CROSS_ARCH := x86 # Avoid trying to build for win64.
 
 LOCAL_SRC_FILES := \
-    socket.cpp \
+    fastboot_test.cpp \
     socket_mock.cpp \
     socket_test.cpp \
-    tcp.cpp \
     tcp_test.cpp \
-    udp.cpp \
     udp_test.cpp \
 
-LOCAL_STATIC_LIBRARIES := libbase libcutils
-
-LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
-
-LOCAL_LDLIBS_darwin := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
-LOCAL_CFLAGS_darwin := -Wno-unused-parameter
-
-LOCAL_LDLIBS_windows := -lws2_32
-
+LOCAL_CFLAGS := $(fastboot_cflags)
+LOCAL_CFLAGS_darwin := $(fastboot_cflags_darwin)
+LOCAL_CXX_STL := $(fastboot_stl)
+LOCAL_HEADER_LIBRARIES := bootimg_headers
+LOCAL_LDLIBS_darwin := $(fastboot_ldlibs_darwin)
+LOCAL_LDLIBS_windows := $(fastboot_ldlibs_windows)
+LOCAL_SHARED_LIBRARIES := $(fastboot_shared_libs)
+LOCAL_SHARED_LIBRARIES_windows := AdbWinApi
+LOCAL_STATIC_LIBRARIES := libfastboot $(fastboot_static_libs)
 include $(BUILD_HOST_NATIVE_TEST)
diff --git a/fastboot/bootimg_utils.cpp b/fastboot/bootimg_utils.cpp
index 2e8c334..c9814e4 100644
--- a/fastboot/bootimg_utils.cpp
+++ b/fastboot/bootimg_utils.cpp
@@ -34,16 +34,15 @@
 #include <stdlib.h>
 #include <string.h>
 
-void bootimg_set_cmdline(boot_img_hdr_v1* h, const char* cmdline) {
-    if (strlen(cmdline) >= sizeof(h->cmdline)) die("command line too large: %zu", strlen(cmdline));
-    strcpy(reinterpret_cast<char*>(h->cmdline), cmdline);
+void bootimg_set_cmdline(boot_img_hdr_v1* h, const std::string& cmdline) {
+    if (cmdline.size() >= sizeof(h->cmdline)) die("command line too large: %zu", cmdline.size());
+    strcpy(reinterpret_cast<char*>(h->cmdline), cmdline.c_str());
 }
 
-boot_img_hdr_v1* mkbootimg(void* kernel, int64_t kernel_size, off_t kernel_offset, void* ramdisk,
-                           int64_t ramdisk_size, off_t ramdisk_offset, void* second,
-                           int64_t second_size, off_t second_offset, size_t page_size, size_t base,
-                           off_t tags_offset, uint32_t header_version, int64_t* bootimg_size) {
-    size_t page_mask = page_size - 1;
+boot_img_hdr_v1* mkbootimg(void* kernel, int64_t kernel_size, void* ramdisk, int64_t ramdisk_size,
+                           void* second, int64_t second_size, size_t base,
+                           const boot_img_hdr_v1& src, int64_t* bootimg_size) {
+    const size_t page_mask = src.page_size - 1;
 
     int64_t header_actual = (sizeof(boot_img_hdr_v1) + page_mask) & (~page_mask);
     int64_t kernel_actual = (kernel_size + page_mask) & (~page_mask);
@@ -53,30 +52,26 @@
     *bootimg_size = header_actual + kernel_actual + ramdisk_actual + second_actual;
 
     boot_img_hdr_v1* hdr = reinterpret_cast<boot_img_hdr_v1*>(calloc(*bootimg_size, 1));
-    if (hdr == nullptr) {
-        return hdr;
-    }
+    if (hdr == nullptr) die("couldn't allocate boot image: %" PRId64 " bytes", *bootimg_size);
 
+    *hdr = src;
     memcpy(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
 
     hdr->kernel_size =  kernel_size;
     hdr->ramdisk_size = ramdisk_size;
     hdr->second_size =  second_size;
 
-    hdr->kernel_addr =  base + kernel_offset;
-    hdr->ramdisk_addr = base + ramdisk_offset;
-    hdr->second_addr =  base + second_offset;
-    hdr->tags_addr =    base + tags_offset;
+    hdr->kernel_addr += base;
+    hdr->ramdisk_addr += base;
+    hdr->second_addr += base;
+    hdr->tags_addr += base;
 
-    hdr->page_size =    page_size;
-
-    if (header_version) {
-        hdr->header_version = header_version;
+    if (hdr->header_version != 0) {
         hdr->header_size = sizeof(boot_img_hdr_v1);
     }
 
-    memcpy(hdr->magic + page_size, kernel, kernel_size);
-    memcpy(hdr->magic + page_size + kernel_actual, ramdisk, ramdisk_size);
-    memcpy(hdr->magic + page_size + kernel_actual + ramdisk_actual, second, second_size);
+    memcpy(hdr->magic + hdr->page_size, kernel, kernel_size);
+    memcpy(hdr->magic + hdr->page_size + kernel_actual, ramdisk, ramdisk_size);
+    memcpy(hdr->magic + hdr->page_size + kernel_actual + ramdisk_actual, second, second_size);
     return hdr;
 }
diff --git a/fastboot/bootimg_utils.h b/fastboot/bootimg_utils.h
index d3993f5..fe805b0 100644
--- a/fastboot/bootimg_utils.h
+++ b/fastboot/bootimg_utils.h
@@ -26,17 +26,15 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _FASTBOOT_BOOTIMG_UTILS_H_
-#define _FASTBOOT_BOOTIMG_UTILS_H_
+#pragma once
 
 #include <bootimg.h>
 #include <inttypes.h>
 #include <sys/types.h>
 
-void bootimg_set_cmdline(boot_img_hdr_v1* h, const char* cmdline);
-boot_img_hdr_v1* mkbootimg(void* kernel, int64_t kernel_size, off_t kernel_offset, void* ramdisk,
-                           int64_t ramdisk_size, off_t ramdisk_offset, void* second,
-                           int64_t second_size, off_t second_offset, size_t page_size, size_t base,
-                           off_t tags_offset, uint32_t header_version, int64_t* bootimg_size);
+#include <string>
 
-#endif
+boot_img_hdr_v1* mkbootimg(void* kernel, int64_t kernel_size, void* ramdisk, int64_t ramdisk_size,
+                           void* second, int64_t second_size, size_t base,
+                           const boot_img_hdr_v1& src, int64_t* bootimg_size);
+void bootimg_set_cmdline(boot_img_hdr_v1* h, const std::string& cmdline);
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index 60b7124..f271d09 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -42,6 +42,8 @@
 
 #include <android-base/stringprintf.h>
 
+#include "transport.h"
+
 enum Op {
     OP_DOWNLOAD,
     OP_COMMAND,
@@ -109,32 +111,32 @@
 
 void fb_set_active(const std::string& slot) {
     Action& a = queue_action(OP_COMMAND, "set_active:" + slot);
-    a.msg = "Setting current slot to '" + slot + "'...";
+    a.msg = "Setting current slot to '" + slot + "'";
 }
 
 void fb_queue_erase(const std::string& partition) {
     Action& a = queue_action(OP_COMMAND, "erase:" + partition);
-    a.msg = "Erasing '" + partition + "'...";
+    a.msg = "Erasing '" + partition + "'";
 }
 
 void fb_queue_flash_fd(const std::string& partition, int fd, uint32_t sz) {
     Action& a = queue_action(OP_DOWNLOAD_FD, "");
     a.fd = fd;
     a.size = sz;
-    a.msg = android::base::StringPrintf("Sending '%s' (%d KB)...", partition.c_str(), sz / 1024);
+    a.msg = android::base::StringPrintf("Sending '%s' (%u KB)", partition.c_str(), sz / 1024);
 
     Action& b = queue_action(OP_COMMAND, "flash:" + partition);
-    b.msg = "Writing '" + partition + "'...";
+    b.msg = "Writing '" + partition + "'";
 }
 
 void fb_queue_flash(const std::string& partition, void* data, uint32_t sz) {
     Action& a = queue_action(OP_DOWNLOAD, "");
     a.data = data;
     a.size = sz;
-    a.msg = android::base::StringPrintf("Sending '%s' (%d KB)...", partition.c_str(), sz / 1024);
+    a.msg = android::base::StringPrintf("Sending '%s' (%u KB)", partition.c_str(), sz / 1024);
 
     Action& b = queue_action(OP_COMMAND, "flash:" + partition);
-    b.msg = "Writing '" + partition + "'...";
+    b.msg = "Writing '" + partition + "'";
 }
 
 void fb_queue_flash_sparse(const std::string& partition, struct sparse_file* s, uint32_t sz,
@@ -142,12 +144,12 @@
     Action& a = queue_action(OP_DOWNLOAD_SPARSE, "");
     a.data = s;
     a.size = 0;
-    a.msg = android::base::StringPrintf("Sending sparse '%s' %zu/%zu (%d KB)...", partition.c_str(),
+    a.msg = android::base::StringPrintf("Sending sparse '%s' %zu/%zu (%u KB)", partition.c_str(),
                                         current, total, sz / 1024);
 
     Action& b = queue_action(OP_COMMAND, "flash:" + partition);
-    b.msg =
-        android::base::StringPrintf("Writing '%s' %zu/%zu...", partition.c_str(), current, total);
+    b.msg = android::base::StringPrintf("Writing sparse '%s' %zu/%zu", partition.c_str(), current,
+                                        total);
 }
 
 static int match(const char* str, const char** value, unsigned count) {
@@ -270,7 +272,7 @@
 void fb_queue_reboot() {
     Action& a = queue_action(OP_COMMAND, "reboot");
     a.func = cb_do_nothing;
-    a.msg = "Rebooting...";
+    a.msg = "Rebooting";
 }
 
 void fb_queue_command(const std::string& cmd, const std::string& msg) {
@@ -289,7 +291,7 @@
     Action& a = queue_action(OP_DOWNLOAD_FD, "");
     a.fd = fd;
     a.size = sz;
-    a.msg = android::base::StringPrintf("Sending '%s' (%d KB)", name.c_str(), sz / 1024);
+    a.msg = android::base::StringPrintf("Sending '%s' (%u KB)", name.c_str(), sz / 1024);
 }
 
 void fb_queue_upload(const std::string& outfile) {
@@ -312,7 +314,8 @@
     for (auto& a : action_list) {
         a->start = now();
         if (!a->msg.empty()) {
-            fprintf(stderr, "%s\n", a->msg.c_str());
+            fprintf(stderr, "%-50s ", a->msg.c_str());
+            verbose("\n");
         }
         if (a->op == OP_DOWNLOAD) {
             status = fb_download_data(transport, a->data, a->size);
@@ -333,6 +336,7 @@
             if (status) break;
         } else if (a->op == OP_NOTICE) {
             // We already showed the notice because it's in `Action::msg`.
+            fprintf(stderr, "\n");
         } else if (a->op == OP_DOWNLOAD_SPARSE) {
             status = fb_download_data_sparse(transport, reinterpret_cast<sparse_file*>(a->data));
             status = a->func(*a, status, status ? fb_get_error().c_str() : "");
diff --git a/fastboot/fastboot.bash b/fastboot/fastboot.bash
new file mode 100644
index 0000000..dca3b4e
--- /dev/null
+++ b/fastboot/fastboot.bash
@@ -0,0 +1,182 @@
+# /* vim: set ai ts=4 ft=sh: */
+#
+# Copyright 2017, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+_fastboot() {
+    if ! type -t "$1" >/dev/null; then
+        return
+    fi
+
+    if type -t _init_completion >/dev/null; then
+        _init_completion || return
+    fi
+
+    local where i cur serial
+    COMPREPLY=()
+
+    serial="${ANDROID_SERIAL:-none}"
+    where=OPTIONS
+    for ((i=1; i <= COMP_CWORD; i++)); do
+        cur="${COMP_WORDS[i]}"
+        case "${cur}" in
+            -s)
+                where=OPT_SERIAL
+                ;;
+            --slot)
+                where=OPT_SLOT
+                ;;
+            -*)
+                where=OPTIONS
+                ;;
+            *)
+                if [[ $where == OPT_SERIAL ]]; then
+                    where=OPT_SERIAL_ARG
+                    serial=${cur}
+                elif [[ $where == OPT_SLOT ]]; then
+                    where=OPT_SLOT_ARG
+                else
+                    where=COMMAND
+                    break
+                fi
+                ;;
+        esac
+    done
+
+    if [[ $where == COMMAND && $i -ge $COMP_CWORD ]]; then
+        where=OPTIONS
+    fi
+
+    OPTIONS="-a -c --disable-verification --disable-verity -h --help -s --set-active --skip-secondary --skip-reboot --slot -u --version -w"
+    COMMAND="continue devices erase flash flashall flashing format getvar get_staged help oem reboot stage update"
+
+    case $where in
+        OPTIONS|OPT_SERIAL)
+            COMPREPLY=( $(compgen -W "$OPTIONS $COMMAND" -- "$cur") )
+            ;;
+        OPT_SERIAL_ARG)
+            local devices=$(command fastboot devices 2> /dev/null | awk '{ print $1 }')
+            COMPREPLY=( $(compgen -W "${devices}" -- ${cur}) )
+            ;;
+        OPT_SLOT_ARG)
+            local slots="a all b other"
+            COMPREPLY=( $(compgen -W "${slots}" -- ${cur}) )
+            ;;
+        COMMAND)
+            if [[ $i -eq $COMP_CWORD ]]; then
+                COMPREPLY=( $(compgen -W "$COMMAND" -- "$cur") )
+            else
+                i=$((i+1))
+                case "${cur}" in
+                    flash)
+                        _fastboot_cmd_flash "$serial" $i
+                        ;;
+                    reboot)
+                        if [[ $COMP_CWORD == $i ]]; then
+                            args="bootloader"
+                            COMPREPLY=( $(compgen -W "${args}" -- "${COMP_WORDS[i]}") )
+                        fi
+                        ;;
+                    update)
+                        _fastboot_cmd_update "$serial" $i
+                        ;;
+                esac
+            fi
+            ;;
+    esac
+
+    return 0
+}
+
+_fastboot_cmd_flash() {
+    local serial i cur
+    local partitions
+
+    serial=$1
+    i=$2
+
+    cur="${COMP_WORDS[COMP_CWORD]}"
+    if [[ $i -eq $COMP_CWORD ]]; then
+        partitions="boot bootloader dtbo modem odm oem product radio recovery system vbmeta vendor"
+        COMPREPLY=( $(compgen -W "$partitions" -- $cur) )
+    else
+        _fastboot_util_complete_local_file "${cur}" '!*.img'
+    fi
+}
+
+_fastboot_cmd_update() {
+    local serial i cur
+
+    serial=$1
+    i=$2
+
+    cur="${COMP_WORDS[COMP_CWORD]}"
+
+    _fastboot_util_complete_local_file "${cur}" '!*.zip'
+}
+
+_fastboot_util_complete_local_file() {
+    local file xspec i j IFS=$'\n'
+    local -a dirs files
+
+    file=$1
+    xspec=$2
+
+    # Since we're probably doing file completion here, don't add a space after.
+    if [[ $(type -t compopt) = "builtin" ]]; then
+        compopt -o plusdirs
+        if [[ "${xspec}" == "" ]]; then
+            COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") )
+        else
+            compopt +o filenames
+            COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") )
+        fi
+    else
+        # Work-around for shells with no compopt
+
+        dirs=( $(compgen -d -- "${cur}" ) )
+
+        if [[ "${xspec}" == "" ]]; then
+            files=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") )
+        else
+            files=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") )
+        fi
+
+        COMPREPLY=( $(
+            for i in "${files[@]}"; do
+                local skip=
+                for j in "${dirs[@]}"; do
+                    if [[ $i == $j ]]; then
+                        skip=1
+                        break
+                    fi
+                done
+                [[ -n $skip ]] || printf "%s\n" "$i"
+            done
+        ))
+
+        COMPREPLY=( ${COMPREPLY[@]:-} $(
+            for i in "${dirs[@]}"; do
+                printf "%s/\n" "$i"
+            done
+        ))
+    fi
+}
+
+if [[ $(type -t compopt) = "builtin" ]]; then
+    complete -F _fastboot fastboot
+else
+    complete -o nospace -F _fastboot fastboot
+fi
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index e89586f..9463cc9 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -76,22 +76,18 @@
 char cur_product[FB_RESPONSE_SZ + 1];
 
 static const char* serial = nullptr;
-static const char* cmdline = nullptr;
-static unsigned short vendor_id = 0;
-static int long_listing = 0;
+
+static bool g_long_listing = false;
 // Don't resparse files in too-big chunks.
 // libsparse will support INT_MAX, but this results in large allocations, so
 // let's keep it at 1GB to avoid memory pressure on the host.
 static constexpr int64_t RESPARSE_LIMIT = 1 * 1024 * 1024 * 1024;
-static int64_t sparse_limit = -1;
+static uint64_t sparse_limit = 0;
 static int64_t target_sparse_limit = -1;
 
-static unsigned page_size = 2048;
-static unsigned base_addr      = 0x10000000;
-static unsigned kernel_offset  = 0x00008000;
-static unsigned ramdisk_offset = 0x01000000;
-static unsigned second_offset  = 0x00f00000;
-static unsigned tags_offset    = 0x00000100;
+static unsigned g_base_addr = 0x10000000;
+static boot_img_hdr_v1 g_boot_img_hdr = {};
+static std::string g_cmdline;
 
 static bool g_disable_verity = false;
 static bool g_disable_verification = false;
@@ -193,11 +189,6 @@
 }
 
 static int match_fastboot_with_serial(usb_ifc_info* info, const char* local_serial) {
-    // Require a matching vendor id if the user specified one with -i.
-    if (vendor_id != 0 && info->dev_vendor != vendor_id) {
-        return -1;
-    }
-
     if (info->ifc_class != 0xff || info->ifc_subclass != 0x42 || info->ifc_protocol != 0x03) {
         return -1;
     }
@@ -223,7 +214,7 @@
             serial = "????????????";
         }
         // output compatible with "adb devices"
-        if (!long_listing) {
+        if (!g_long_listing) {
             printf("%s\tfastboot", serial.c_str());
         } else {
             printf("%-22s fastboot", serial.c_str());
@@ -238,7 +229,7 @@
 // Opens a new Transport connected to a device. If |serial| is non-null it will be used to identify
 // a specific device, otherwise the first USB device found will be used.
 //
-// If |serial| is non-null but invalid, this prints an error message to stderr and returns nullptr.
+// If |serial| is non-null but invalid, this exits.
 // Otherwise it blocks until the target is available.
 //
 // The returned Transport is a singleton, so multiple calls to this function will return the same
@@ -270,9 +261,7 @@
         if (net_address != nullptr) {
             std::string error;
             if (!android::base::ParseNetAddress(net_address, &host, &port, nullptr, &error)) {
-                fprintf(stderr, "error: Invalid network address '%s': %s\n", net_address,
-                        error.c_str());
-                return nullptr;
+                die("invalid network address '%s': %s\n", net_address, error.c_str());
             }
         }
     }
@@ -328,125 +317,87 @@
     // clang-format off
     fprintf(stdout,
 /*           1234567890123456789012345678901234567890123456789012345678901234567890123456 */
-            "usage: fastboot [ <option> ] <command>\n"
+            "usage: fastboot [OPTION...] COMMAND...\n"
             "\n"
-            "commands:\n"
-            "  update <filename>                        Reflash device from update.zip.\n"
-            "                                           Sets the flashed slot as active.\n"
-            "  flashall                                 Flash boot, system, vendor, and --\n"
-            "                                           if found -- recovery. If the device\n"
-            "                                           supports slots, the slot that has\n"
-            "                                           been flashed to is set as active.\n"
-            "                                           Secondary images may be flashed to\n"
-            "                                           an inactive slot.\n"
-            "  flash <partition> [ <filename> ]         Write a file to a flash partition.\n"
-            "  flashing lock                            Locks the device. Prevents flashing.\n"
-            "  flashing unlock                          Unlocks the device. Allows flashing\n"
-            "                                           any partition except\n"
-            "                                           bootloader-related partitions.\n"
-            "  flashing lock_critical                   Prevents flashing bootloader-related\n"
-            "                                           partitions.\n"
-            "  flashing unlock_critical                 Enables flashing bootloader-related\n"
-            "                                           partitions.\n"
-            "  flashing get_unlock_ability              Queries bootloader to see if the\n"
-            "                                           device is unlocked.\n"
-            "  flashing get_unlock_bootloader_nonce     Queries the bootloader to get the\n"
-            "                                           unlock nonce.\n"
-            "  flashing unlock_bootloader <request>     Issue unlock bootloader using request.\n"
-            "  flashing lock_bootloader                 Locks the bootloader to prevent\n"
-            "                                           bootloader version rollback.\n"
-            "  erase <partition>                        Erase a flash partition.\n"
-            "  format[:[<fs type>][:[<size>]] <partition>\n"
-            "                                           Format a flash partition. Can\n"
-            "                                           override the fs type and/or size\n"
-            "                                           the bootloader reports.\n"
-            "  getvar <variable>                        Display a bootloader variable.\n"
-            "  set_active <slot>                        Sets the active slot. If slots are\n"
-            "                                           not supported, this does nothing.\n"
-            "  boot <kernel> [ <ramdisk> [ <second> ] ] Download and boot kernel.\n"
-            "  flash:raw <bootable-partition> <kernel> [ <ramdisk> [ <second> ] ]\n"
-            "                                           Create bootimage and flash it.\n"
-            "  devices [-l]                             List all connected devices [with\n"
-            "                                           device paths].\n"
-            "  continue                                 Continue with autoboot.\n"
-            "  reboot [bootloader|emergency]            Reboot device [into bootloader or emergency mode].\n"
-            "  reboot-bootloader                        Reboot device into bootloader.\n"
-            "  oem <parameter1> ... <parameterN>        Executes oem specific command.\n"
-            "  stage <infile>                           Sends contents of <infile> to stage for\n"
-            "                                           the next command. Supported only on\n"
-            "                                           Android Things devices.\n"
-            "  get_staged <outfile>                     Receives data to <outfile> staged by the\n"
-            "                                           last command. Supported only on Android\n"
-            "                                           Things devices.\n"
-            "  help                                     Show this help message.\n"
+            "flashing:\n"
+            " update ZIP                 Flash all partitions from an update.zip package.\n"
+            " flashall                   Flash all partitions from $ANDROID_PRODUCT_OUT.\n"
+            "                            On A/B devices, flashed slot is set as active.\n"
+            "                            Secondary images may be flashed to inactive slot.\n"
+            " flash PARTITION [FILENAME]\n"
+            "                            Flash given partition only.\n"
+            "\n"
+            "basics:\n"
+            " devices [-l]               List devices in bootloader (-l: with device paths).\n"
+            " getvar NAME                Display given bootloader variable.\n"
+            " reboot [bootloader]        Reboot device.\n"
+            "\n"
+            "locking/unlocking:\n"
+            " flashing lock|unlock       Lock/unlock partitions for flashing\n"
+            " flashing lock_critical|unlock_critical\n"
+            "                            Lock/unlock 'critical' bootloader partitions.\n"
+            " flashing get_unlock_ability\n"
+            "                            Check whether unlocking is allowed (1) or not(0).\n"
+            "\n"
+            "advanced:\n"
+            " erase PARTITION            Erase a flash partition.\n"
+            " format[:FS_TYPE[:SIZE]] PARTITION\n"
+            "                            Format a flash partition.\n"
+            " set_active SLOT            Set the active slot.\n"
+            " oem [COMMAND...]           Execute OEM-specific command.\n"
+            "\n"
+            "boot image:\n"
+            " boot KERNEL [RAMDISK [SECOND]]\n"
+            "                            Download and boot kernel from RAM.\n"
+            " flash:raw PARTITION KERNEL [RAMDISK [SECOND]]\n"
+            "                            Create boot image and flash it.\n"
+            " --cmdline CMDLINE          Override kernel command line.\n"
+            " --base ADDRESS             Set kernel base address (default: 0x10000000).\n"
+            " --kernel-offset            Set kernel offset (default: 0x00008000).\n"
+            " --ramdisk-offset           Set ramdisk offset (default: 0x01000000).\n"
+            " --tags-offset              Set tags offset (default: 0x00000100).\n"
+            " --page-size BYTES          Set flash page size (default: 2048).\n"
+            " --header-version VERSION   Set boot image header version.\n"
+            " --os-version MAJOR[.MINOR[.PATCH]]\n"
+            "                            Set boot image OS version (default: 0.0.0).\n"
+            " --os-patch-level YYYY-MM-DD\n"
+            "                            Set boot image OS security patch level.\n"
+            // TODO: still missing: `second_addr`, `name`, `id`, `recovery_dtbo_*`.
+            "\n"
+            // TODO: what device(s) used this? is there any documentation?
+            //" continue                               Continue with autoboot.\n"
+            //"\n"
+            "Android Things:\n"
+            " stage IN_FILE              Sends given file to stage for the next command.\n"
+            " get_staged OUT_FILE        Writes data staged by the last command to a file.\n"
             "\n"
             "options:\n"
-            "  -w                                       Erase userdata and cache (and format\n"
-            "                                           if supported by partition type).\n"
-            "  -u                                       Do not erase partition before\n"
-            "                                           formatting.\n"
-            "  -s <specific device>                     Specify a device. For USB, provide either\n"
-            "                                           a serial number or path to device port.\n"
-            "                                           For ethernet, provide an address in the\n"
-            "                                           form <protocol>:<hostname>[:port] where\n"
-            "                                           <protocol> is either tcp or udp.\n"
-            "  -c <cmdline>                             Override kernel commandline.\n"
-            "  -i <vendor id>                           Specify a custom USB vendor id.\n"
-            "  -b, --base <base_addr>                   Specify a custom kernel base\n"
-            "                                           address (default: 0x10000000).\n"
-            "  --kernel-offset                          Specify a custom kernel offset.\n"
-            "                                           (default: 0x00008000)\n"
-            "  --ramdisk-offset                         Specify a custom ramdisk offset.\n"
-            "                                           (default: 0x01000000)\n"
-            "  --tags-offset                            Specify a custom tags offset.\n"
-            "                                           (default: 0x00000100)\n"
-            "  -n, --page-size <page size>              Specify the nand page size\n"
-            "                                           (default: 2048).\n"
-            "  -S <size>[K|M|G]                         Automatically sparse files greater\n"
-            "                                           than 'size'. 0 to disable.\n"
-            "  --slot <slot>                            Specify slot name to be used if the\n"
-            "                                           device supports slots. All operations\n"
-            "                                           on partitions that support slots will\n"
-            "                                           be done on the slot specified.\n"
-            "                                           'all' can be given to refer to all slots.\n"
-            "                                           'other' can be given to refer to a\n"
-            "                                           non-current slot. If this flag is not\n"
-            "                                           used, slotted partitions will default\n"
-            "                                           to the current active slot.\n"
-            "  -a, --set-active[=<slot>]                Sets the active slot. If no slot is\n"
-            "                                           provided, this will default to the value\n"
-            "                                           given by --slot. If slots are not\n"
-            "                                           supported, this does nothing. This will\n"
-            "                                           run after all non-reboot commands.\n"
-            "  --skip-secondary                         Will not flash secondary slots when\n"
-            "                                           performing a flashall or update. This\n"
-            "                                           will preserve data on other slots.\n"
-            "  --skip-reboot                            Will not reboot the device when\n"
-            "                                           performing commands that normally\n"
-            "                                           trigger a reboot.\n"
-            "  --disable-verity                         Set the disable-verity flag in the\n"
-            "                                           the vbmeta image being flashed.\n"
-            "  --disable-verification                   Set the disable-verification flag in"
-            "                                           the vbmeta image being flashed.\n"
+            " -w                         Wipe userdata.\n"
+            " -s SERIAL                  Specify a USB device.\n"
+            " -s tcp|udp:HOST[:PORT]     Specify a network device.\n"
+            " -S SIZE[K|M|G]             Break into sparse files no larger than SIZE.\n"
+            " --slot SLOT                Use SLOT; 'all' for both slots, 'other' for\n"
+            "                            non-current slot (default: current active slot).\n"
+            " --set-active[=SLOT]        Sets the active slot before rebooting.\n"
+            " --skip-secondary           Don't flash secondary slots in flashall/update.\n"
+            " --skip-reboot              Don't reboot device after flashing.\n"
+            " --disable-verity           Sets disable-verity when flashing vbmeta.\n"
+            " --disable-verification     Sets disable-verification when flashing vbmeta.\n"
 #if !defined(_WIN32)
-            "  --wipe-and-use-fbe                       On devices which support it,\n"
-            "                                           erase userdata and cache, and\n"
-            "                                           enable file-based encryption\n"
+            " --wipe-and-use-fbe         Enable file-based encryption, wiping userdata.\n"
 #endif
-            "  --unbuffered                             Do not buffer input or output.\n"
-            "  --version                                Display version.\n"
-            "  --header-version                         Set boot image header version while\n"
-            "                                           using flash:raw and boot commands to \n"
-            "                                           to create a boot image.\n"
-            "  -h, --help                               show this message.\n"
+            // TODO: remove --unbuffered?
+            " --unbuffered               Don't buffer input or output.\n"
+            " --verbose, -v              Verbose output.\n"
+            " --version                  Display version.\n"
+            " --help, -h                 Show this message.\n"
         );
     // clang-format off
     return 0;
 }
 
 static void* load_bootable_image(const std::string& kernel, const std::string& ramdisk,
-                                 const std::string& second_stage, int64_t* sz,
-                                 const char* cmdline, uint32_t header_version) {
+                                 const std::string& second_stage, int64_t* sz) {
     int64_t ksize;
     void* kdata = load_file(kernel.c_str(), &ksize);
     if (kdata == nullptr) die("cannot load '%s': %s", kernel.c_str(), strerror(errno));
@@ -456,7 +407,9 @@
         die("cannot load '%s': too short", kernel.c_str());
     }
     if (!memcmp(kdata, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
-        if (cmdline) bootimg_set_cmdline(reinterpret_cast<boot_img_hdr_v1*>(kdata), cmdline);
+        if (!g_cmdline.empty()) {
+            bootimg_set_cmdline(reinterpret_cast<boot_img_hdr_v1*>(kdata), g_cmdline);
+        }
 
         if (!ramdisk.empty()) die("cannot boot a boot.img *and* ramdisk");
 
@@ -479,16 +432,12 @@
     }
 
     fprintf(stderr,"creating boot image...\n");
-    int64_t bsize = 0;
-    boot_img_hdr_v1* bdata = mkbootimg(kdata, ksize, kernel_offset,
-                      rdata, rsize, ramdisk_offset,
-                      sdata, ssize, second_offset,
-                      page_size, base_addr, tags_offset, header_version, &bsize);
+    boot_img_hdr_v1* bdata = mkbootimg(kdata, ksize, rdata, rsize, sdata, ssize,
+                                       g_base_addr, g_boot_img_hdr, sz);
     if (bdata == nullptr) die("failed to create boot.img");
 
-    if (cmdline) bootimg_set_cmdline(bdata, cmdline);
-    fprintf(stderr, "creating boot image - %" PRId64 " bytes\n", bsize);
-    *sz = bsize;
+    if (!g_cmdline.empty()) bootimg_set_cmdline(bdata, g_cmdline);
+    fprintf(stderr, "creating boot image - %" PRId64 " bytes\n", *sz);
 
     return bdata;
 }
@@ -542,7 +491,7 @@
     die("make_temporary_directory not supported under Windows, sorry!");
 }
 
-static int make_temporary_fd() {
+static int make_temporary_fd(const char* /*what*/) {
     // TODO: reimplement to avoid leaking a FILE*.
     return fileno(tmpfile());
 }
@@ -558,18 +507,16 @@
 static std::string make_temporary_directory() {
     std::string result(make_temporary_template());
     if (mkdtemp(&result[0]) == nullptr) {
-        fprintf(stderr, "Unable to create temporary directory: %s\n", strerror(errno));
-        return "";
+        die("unable to create temporary directory: %s", strerror(errno));
     }
     return result;
 }
 
-static int make_temporary_fd() {
+static int make_temporary_fd(const char* what) {
     std::string path_template(make_temporary_template());
     int fd = mkstemp(&path_template[0]);
     if (fd == -1) {
-        fprintf(stderr, "Unable to create temporary file: %s\n", strerror(errno));
-        return -1;
+        die("failed to create temporary file for %s: %s\n", what, strerror(errno));
     }
     unlink(path_template.c_str());
     return fd;
@@ -579,16 +526,11 @@
 
 static std::string create_fbemarker_tmpdir() {
     std::string dir = make_temporary_directory();
-    if (dir.empty()) {
-        fprintf(stderr, "Unable to create local temp directory for FBE marker\n");
-        return "";
-    }
     std::string marker_file = dir + "/" + convert_fbe_marker_filename;
     int fd = open(marker_file.c_str(), O_CREAT | O_WRONLY | O_CLOEXEC, 0666);
     if (fd == -1) {
-        fprintf(stderr, "Unable to create FBE marker file %s locally: %d, %s\n",
-            marker_file.c_str(), errno, strerror(errno));
-        return "";
+        die("unable to create FBE marker file %s locally: %s",
+            marker_file.c_str(), strerror(errno));
     }
     close(fd);
     return dir;
@@ -609,10 +551,7 @@
 }
 
 static int unzip_to_file(ZipArchiveHandle zip, const char* entry_name) {
-    unique_fd fd(make_temporary_fd());
-    if (fd == -1) {
-        die("failed to create temporary file for '%s': %s", entry_name, strerror(errno));
-    }
+    unique_fd fd(make_temporary_fd(entry_name));
 
     ZipString zip_entry_name(entry_name);
     ZipEntry zip_entry;
@@ -754,10 +693,14 @@
     fb_queue_notice("--------------------------------------------");
 }
 
-static struct sparse_file** load_sparse_files(int fd, int max_size) {
+static struct sparse_file** load_sparse_files(int fd, int64_t max_size) {
     struct sparse_file* s = sparse_file_import_auto(fd, false, true);
     if (!s) die("cannot sparse read file");
 
+    if (max_size <= 0 || max_size > std::numeric_limits<uint32_t>::max()) {
+      die("invalid max size %" PRId64, max_size);
+    }
+
     int files = sparse_file_resparse(s, max_size, nullptr, 0);
     if (files < 0) die("Failed to resparse");
 
@@ -773,8 +716,8 @@
 static int64_t get_target_sparse_limit(Transport* transport) {
     std::string max_download_size;
     if (!fb_getvar(transport, "max-download-size", &max_download_size) ||
-            max_download_size.empty()) {
-        fprintf(stderr, "target didn't report max-download-size\n");
+        max_download_size.empty()) {
+        verbose("target didn't report max-download-size");
         return 0;
     }
 
@@ -786,20 +729,15 @@
         fprintf(stderr, "couldn't parse max-download-size '%s'\n", max_download_size.c_str());
         return 0;
     }
-    if (limit > 0) {
-        fprintf(stderr, "target reported max download size of %" PRId64 " bytes\n", limit);
-    }
+    if (limit > 0) verbose("target reported max download size of %" PRId64 " bytes", limit);
     return limit;
 }
 
 static int64_t get_sparse_limit(Transport* transport, int64_t size) {
-    int64_t limit;
-
-    if (sparse_limit == 0) {
-        return 0;
-    } else if (sparse_limit > 0) {
-        limit = sparse_limit;
-    } else {
+    int64_t limit = sparse_limit;
+    if (limit == 0) {
+        // Unlimited, so see what the target device's limit is.
+        // TODO: shouldn't we apply this limit even if you've used -S?
         if (target_sparse_limit == -1) {
             target_sparse_limit = get_target_sparse_limit(transport);
         }
@@ -817,17 +755,6 @@
     return 0;
 }
 
-// Until we get lazy inode table init working in make_ext4fs, we need to
-// erase partitions of type ext4 before flashing a filesystem so no stale
-// inodes are left lying around.  Otherwise, e2fsck gets very upset.
-static bool needs_erase(Transport* transport, const char* partition) {
-    std::string partition_type;
-    if (!fb_getvar(transport, std::string("partition-type:") + partition, &partition_type)) {
-        return false;
-    }
-    return partition_type == "ext4";
-}
-
 static bool load_buf_fd(Transport* transport, int fd, struct fastboot_buffer* buf) {
     int64_t sz = get_file_size(fd);
     if (sz == -1) {
@@ -879,10 +806,7 @@
         return;
     }
 
-    int fd = make_temporary_fd();
-    if (fd == -1) {
-        die("Failed to create temporary file for vbmeta rewriting");
-    }
+    int fd = make_temporary_fd("vbmeta rewriting");
 
     std::string data;
     if (!android::base::ReadFdToString(buf->fd, &data)) {
@@ -944,46 +868,18 @@
     }
 }
 
-static std::string get_current_slot(Transport* transport)
-{
+static std::string get_current_slot(Transport* transport) {
     std::string current_slot;
-    if (fb_getvar(transport, "current-slot", &current_slot)) {
-        if (current_slot == "_a") return "a"; // Legacy support
-        if (current_slot == "_b") return "b"; // Legacy support
-        return current_slot;
-    }
-    return "";
-}
-
-// Legacy support
-static std::vector<std::string> get_suffixes_obsolete(Transport* transport) {
-    std::vector<std::string> suffixes;
-    std::string suffix_list;
-    if (!fb_getvar(transport, "slot-suffixes", &suffix_list)) {
-        return suffixes;
-    }
-    suffixes = android::base::Split(suffix_list, ",");
-    // Unfortunately some devices will return an error message in the
-    // guise of a valid value. If we only see only one suffix, it's probably
-    // not real.
-    if (suffixes.size() == 1) {
-        suffixes.clear();
-    }
-    return suffixes;
-}
-
-// Legacy support
-static bool supports_AB_obsolete(Transport* transport) {
-  return !get_suffixes_obsolete(transport).empty();
+    if (!fb_getvar(transport, "current-slot", &current_slot)) return "";
+    return current_slot;
 }
 
 static int get_slot_count(Transport* transport) {
     std::string var;
-    int count;
-    if (!fb_getvar(transport, "slot-count", &var)) {
-        if (supports_AB_obsolete(transport)) return 2; // Legacy support
+    int count = 0;
+    if (!fb_getvar(transport, "slot-count", &var) || !android::base::ParseInt(var, &count)) {
+        return 0;
     }
-    if (!android::base::ParseInt(var, &count)) return 0;
     return count;
 }
 
@@ -1013,8 +909,6 @@
 
 static std::string verify_slot(Transport* transport, const std::string& slot_name, bool allow_all) {
     std::string slot = slot_name;
-    if (slot == "_a") slot = "a"; // Legacy support
-    if (slot == "_b") slot = "b"; // Legacy support
     if (slot == "all") {
         if (allow_all) {
             return "all";
@@ -1126,25 +1020,19 @@
 // Sets slot_override as the active slot. If slot_override is blank,
 // set current slot as active instead. This clears slot-unbootable.
 static void set_active(Transport* transport, const std::string& slot_override) {
-    std::string separator = "";
-    if (!supports_AB(transport)) {
-        if (supports_AB_obsolete(transport)) {
-            separator = "_"; // Legacy support
-        } else {
-            return;
-        }
-    }
+    if (!supports_AB(transport)) return;
+
     if (slot_override != "") {
-        fb_set_active(separator + slot_override);
+        fb_set_active(slot_override);
     } else {
         std::string current_slot = get_current_slot(transport);
         if (current_slot != "") {
-            fb_set_active(separator + current_slot);
+            fb_set_active(current_slot);
         }
     }
 }
 
-static void do_update(Transport* transport, const char* filename, const std::string& slot_override, bool erase_first, bool skip_secondary) {
+static void do_update(Transport* transport, const char* filename, const std::string& slot_override, bool skip_secondary) {
     queue_info_dump();
 
     fb_queue_query_save("product", cur_product, sizeof(cur_product));
@@ -1202,9 +1090,6 @@
 
         auto update = [&](const std::string& partition) {
             do_update_signature(zip, images[i].sig_name);
-            if (erase_first && needs_erase(transport, partition.c_str())) {
-                fb_queue_erase(partition);
-            }
             flash_buf(partition.c_str(), &buf);
             /* not closing the fd here since the sparse code keeps the fd around
              * but hasn't mmaped data yet. The temporary file will get cleaned up when the
@@ -1237,7 +1122,7 @@
     fb_queue_command("signature", "installing signature");
 }
 
-static void do_flashall(Transport* transport, const std::string& slot_override, int erase_first, bool skip_secondary) {
+static void do_flashall(Transport* transport, const std::string& slot_override, bool skip_secondary) {
     std::string fname;
     queue_info_dump();
 
@@ -1284,9 +1169,6 @@
 
         auto flashall = [&](const std::string &partition) {
             do_send_signature(fname.c_str());
-            if (erase_first && needs_erase(transport, partition.c_str())) {
-                fb_queue_erase(partition);
-            }
             flash_buf(partition.c_str(), &buf);
         };
         do_for_partitions(transport, images[i].part_name, slot, flashall, false);
@@ -1306,18 +1188,6 @@
     return result;
 }
 
-static void do_bypass_unlock_command(std::vector<std::string>* args) {
-    if (args->empty()) syntax_error("missing unlock_bootloader request");
-
-    std::string filename = next_arg(args);
-
-    int64_t sz;
-    void* data = load_file(filename.c_str(), &sz);
-    if (data == nullptr) die("could not load '%s': %s", filename.c_str(), strerror(errno));
-    fb_queue_download("unlock_message", data, sz);
-    fb_queue_command("flashing unlock_bootloader", "unlocking bootloader");
-}
-
 static void do_oem_command(const std::string& cmd, std::vector<std::string>* args) {
     if (args->empty()) syntax_error("empty oem command");
 
@@ -1328,47 +1198,6 @@
     fb_queue_command(command, "");
 }
 
-static int64_t parse_num(const char *arg)
-{
-    char *endptr;
-    unsigned long long num;
-
-    num = strtoull(arg, &endptr, 0);
-    if (endptr == arg) {
-        return -1;
-    }
-
-    if (*endptr == 'k' || *endptr == 'K') {
-        if (num >= (-1ULL) / 1024) {
-            return -1;
-        }
-        num *= 1024LL;
-        endptr++;
-    } else if (*endptr == 'm' || *endptr == 'M') {
-        if (num >= (-1ULL) / (1024 * 1024)) {
-            return -1;
-        }
-        num *= 1024LL * 1024LL;
-        endptr++;
-    } else if (*endptr == 'g' || *endptr == 'G') {
-        if (num >= (-1ULL) / (1024 * 1024 * 1024)) {
-            return -1;
-        }
-        num *= 1024LL * 1024LL * 1024LL;
-        endptr++;
-    }
-
-    if (*endptr != '\0') {
-        return -1;
-    }
-
-    if (num > INT64_MAX) {
-        return -1;
-    }
-
-    return num;
-}
-
 static std::string fb_fix_numeric_var(std::string var) {
     // Some bootloaders (angler, for example), send spurious leading whitespace.
     var = android::base::Trim(var);
@@ -1491,45 +1320,46 @@
     fprintf(stderr, "FAILED (%s)\n", fb_get_error().c_str());
 }
 
-int main(int argc, char **argv)
-{
+int FastBoot::Main(int argc, char* argv[]) {
     bool wants_wipe = false;
     bool wants_reboot = false;
     bool wants_reboot_bootloader = false;
-    bool wants_reboot_emergency = false;
     bool skip_reboot = false;
     bool wants_set_active = false;
     bool skip_secondary = false;
-    bool erase_first = true;
     bool set_fbe_marker = false;
     void *data;
-    uint32_t header_version = 0;
     int64_t sz;
     int longindex;
     std::string slot_override;
     std::string next_active;
 
+    g_boot_img_hdr.kernel_addr = 0x00008000;
+    g_boot_img_hdr.ramdisk_addr = 0x01000000;
+    g_boot_img_hdr.second_addr = 0x00f00000;
+    g_boot_img_hdr.tags_addr = 0x00000100;
+    g_boot_img_hdr.page_size = 2048;
+
     const struct option longopts[] = {
-        {"base", required_argument, 0, 'b'},
-        {"kernel_offset", required_argument, 0, 'k'},
-        {"kernel-offset", required_argument, 0, 'k'},
-        {"page_size", required_argument, 0, 'n'},
-        {"page-size", required_argument, 0, 'n'},
-        {"ramdisk_offset", required_argument, 0, 'r'},
-        {"ramdisk-offset", required_argument, 0, 'r'},
-        {"tags_offset", required_argument, 0, 't'},
-        {"tags-offset", required_argument, 0, 't'},
-        {"help", no_argument, 0, 'h'},
-        {"unbuffered", no_argument, 0, 0},
-        {"version", no_argument, 0, 0},
-        {"slot", required_argument, 0, 0},
-        {"set_active", optional_argument, 0, 'a'},
-        {"set-active", optional_argument, 0, 'a'},
-        {"skip-secondary", no_argument, 0, 0},
-        {"skip-reboot", no_argument, 0, 0},
-        {"disable-verity", no_argument, 0, 0},
+        {"base", required_argument, 0, 0},
+        {"cmdline", required_argument, 0, 0},
         {"disable-verification", no_argument, 0, 0},
+        {"disable-verity", no_argument, 0, 0},
         {"header-version", required_argument, 0, 0},
+        {"help", no_argument, 0, 'h'},
+        {"kernel-offset", required_argument, 0, 0},
+        {"os-patch-level", required_argument, 0, 0},
+        {"os-version", required_argument, 0, 0},
+        {"page-size", required_argument, 0, 0},
+        {"ramdisk-offset", required_argument, 0, 0},
+        {"set-active", optional_argument, 0, 'a'},
+        {"skip-reboot", no_argument, 0, 0},
+        {"skip-secondary", no_argument, 0, 0},
+        {"slot", required_argument, 0, 0},
+        {"tags-offset", required_argument, 0, 0},
+        {"unbuffered", no_argument, 0, 0},
+        {"verbose", no_argument, 0, 'v'},
+        {"version", no_argument, 0, 0},
 #if !defined(_WIN32)
         {"wipe-and-use-fbe", no_argument, 0, 0},
 #endif
@@ -1538,100 +1368,84 @@
 
     serial = getenv("ANDROID_SERIAL");
 
-    while (1) {
-        int c = getopt_long(argc, argv, "wub:k:n:r:t:s:S:lc:i:m:ha::", longopts, &longindex);
-        if (c < 0) {
-            break;
-        }
-        /* Alphabetical cases */
-        switch (c) {
-        case 'a':
-            wants_set_active = true;
-            if (optarg)
-                next_active = optarg;
-            break;
-        case 'b':
-            base_addr = strtoul(optarg, 0, 16);
-            break;
-        case 'c':
-            cmdline = optarg;
-            break;
-        case 'h':
-            return show_help();
-        case 'i': {
-                char *endptr = nullptr;
-                unsigned long val;
-
-                val = strtoul(optarg, &endptr, 0);
-                if (!endptr || *endptr != '\0' || (val & ~0xffff))
-                    die("invalid vendor id '%s'", optarg);
-                vendor_id = (unsigned short)val;
-                break;
-            }
-        case 'k':
-            kernel_offset = strtoul(optarg, 0, 16);
-            break;
-        case 'l':
-            long_listing = 1;
-            break;
-        case 'n':
-            page_size = (unsigned)strtoul(optarg, nullptr, 0);
-            if (!page_size) die("invalid page size");
-            break;
-        case 'r':
-            ramdisk_offset = strtoul(optarg, 0, 16);
-            break;
-        case 't':
-            tags_offset = strtoul(optarg, 0, 16);
-            break;
-        case 's':
-            serial = optarg;
-            break;
-        case 'S':
-            sparse_limit = parse_num(optarg);
-            if (sparse_limit < 0) die("invalid sparse limit");
-            break;
-        case 'u':
-            erase_first = false;
-            break;
-        case 'w':
-            wants_wipe = true;
-            break;
-        case '?':
-            return 1;
-        case 0:
-            if (strcmp("unbuffered", longopts[longindex].name) == 0) {
+    int c;
+    while ((c = getopt_long(argc, argv, "a::hls:S:vw", longopts, &longindex)) != -1) {
+        if (c == 0) {
+            std::string name{longopts[longindex].name};
+            if (name == "base") {
+                g_base_addr = strtoul(optarg, 0, 16);
+            } else if (name == "cmdline") {
+                g_cmdline = optarg;
+            } else if (name == "disable-verification") {
+                g_disable_verification = true;
+            } else if (name == "disable-verity") {
+                g_disable_verity = true;
+            } else if (name == "header-version") {
+                g_boot_img_hdr.header_version = strtoul(optarg, nullptr, 0);
+            } else if (name == "kernel-offset") {
+                g_boot_img_hdr.kernel_addr = strtoul(optarg, 0, 16);
+            } else if (name == "os-patch-level") {
+                ParseOsPatchLevel(&g_boot_img_hdr, optarg);
+            } else if (name == "os-version") {
+                ParseOsVersion(&g_boot_img_hdr, optarg);
+            } else if (name == "page-size") {
+                g_boot_img_hdr.page_size = strtoul(optarg, nullptr, 0);
+                if (g_boot_img_hdr.page_size == 0) die("invalid page size");
+            } else if (name == "ramdisk-offset") {
+                g_boot_img_hdr.ramdisk_addr = strtoul(optarg, 0, 16);
+            } else if (name == "skip-reboot") {
+                skip_reboot = true;
+            } else if (name == "skip-secondary") {
+                skip_secondary = true;
+            } else if (name == "slot") {
+                slot_override = optarg;
+            } else if (name == "tags-offset") {
+                g_boot_img_hdr.tags_addr = strtoul(optarg, 0, 16);
+            } else if (name == "unbuffered") {
                 setvbuf(stdout, nullptr, _IONBF, 0);
                 setvbuf(stderr, nullptr, _IONBF, 0);
-            } else if (strcmp("version", longopts[longindex].name) == 0) {
+            } else if (name == "version") {
                 fprintf(stdout, "fastboot version %s\n", FASTBOOT_VERSION);
                 fprintf(stdout, "Installed as %s\n", android::base::GetExecutablePath().c_str());
                 return 0;
-            } else if (strcmp("slot", longopts[longindex].name) == 0) {
-                slot_override = std::string(optarg);
-            } else if (strcmp("skip-secondary", longopts[longindex].name) == 0 ) {
-                skip_secondary = true;
-            } else if (strcmp("skip-reboot", longopts[longindex].name) == 0 ) {
-                skip_reboot = true;
-            } else if (strcmp("disable-verity", longopts[longindex].name) == 0 ) {
-                g_disable_verity = true;
-            } else if (strcmp("disable-verification", longopts[longindex].name) == 0 ) {
-                g_disable_verification = true;
 #if !defined(_WIN32)
-            } else if (strcmp("wipe-and-use-fbe", longopts[longindex].name) == 0) {
+            } else if (name == "wipe-and-use-fbe") {
                 wants_wipe = true;
                 set_fbe_marker = true;
 #endif
-            } else if (strcmp("header-version", longopts[longindex].name) == 0) {
-                header_version = strtoul(optarg, nullptr, 0);
             } else {
-                fprintf(stderr, "Internal error in options processing for %s\n",
-                    longopts[longindex].name);
-                return 1;
+                die("unknown option %s", longopts[longindex].name);
             }
-            break;
-        default:
-            abort();
+        } else {
+            switch (c) {
+                case 'a':
+                    wants_set_active = true;
+                    if (optarg) next_active = optarg;
+                    break;
+                case 'h':
+                    return show_help();
+                case 'l':
+                    g_long_listing = true;
+                    break;
+                case 's':
+                    serial = optarg;
+                    break;
+                case 'S':
+                    if (!android::base::ParseByteCount(optarg, &sparse_limit)) {
+                        die("invalid sparse limit %s", optarg);
+                    }
+                    break;
+                case 'v':
+                    set_verbose();
+                    break;
+                case 'w':
+                    wants_wipe = true;
+                    break;
+                case '?':
+                    return 1;
+                default:
+                    abort();
+            }
         }
     }
 
@@ -1656,9 +1470,6 @@
 
     const double start = now();
 
-    if (!supports_AB(transport) && supports_AB_obsolete(transport)) {
-        fprintf(stderr, "Warning: Device A/B support is outdated. Bootloader update required.\n");
-    }
     if (slot_override != "") slot_override = verify_slot(transport, slot_override);
     if (next_active != "") next_active = verify_slot(transport, next_active, false);
 
@@ -1715,9 +1526,6 @@
             std::string partition = next_arg(&args);
 
             auto format = [&](const std::string& partition) {
-                if (erase_first && needs_erase(transport, partition.c_str())) {
-                    fb_queue_erase(partition);
-                }
                 fb_perform_format(transport, partition, 0, type_override, size_override, "");
             };
             do_for_partitions(transport, partition.c_str(), slot_override, format, true);
@@ -1736,9 +1544,6 @@
                 if (what == "bootloader") {
                     wants_reboot = false;
                     wants_reboot_bootloader = true;
-                } else if (what == "emergency") {
-                    wants_reboot = false;
-                    wants_reboot_emergency = true;
                 } else {
                     syntax_error("unknown reboot target %s", what.c_str());
                 }
@@ -1756,7 +1561,7 @@
             std::string second_stage;
             if (!args.empty()) second_stage = next_arg(&args);
 
-            data = load_bootable_image(kernel, ramdisk, second_stage, &sz, cmdline, header_version);
+            data = load_bootable_image(kernel, ramdisk, second_stage, &sz);
             fb_queue_download("boot.img", data, sz);
             fb_queue_command("boot", "booting");
         } else if (command == "flash") {
@@ -1771,9 +1576,6 @@
             if (fname.empty()) die("cannot determine image filename for '%s'", pname.c_str());
 
             auto flash = [&](const std::string &partition) {
-                if (erase_first && needs_erase(transport, partition.c_str())) {
-                    fb_queue_erase(partition);
-                }
                 do_flash(transport, partition.c_str(), fname.c_str());
             };
             do_for_partitions(transport, pname.c_str(), slot_override, flash, true);
@@ -1785,7 +1587,7 @@
             std::string second_stage;
             if (!args.empty()) second_stage = next_arg(&args);
 
-            data = load_bootable_image(kernel, ramdisk, second_stage, &sz, cmdline, header_version);
+            data = load_bootable_image(kernel, ramdisk, second_stage, &sz);
             auto flashraw = [&](const std::string& partition) {
                 fb_queue_flash(partition, data, sz);
             };
@@ -1793,9 +1595,9 @@
         } else if (command == "flashall") {
             if (slot_override == "all") {
                 fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed.\n");
-                do_flashall(transport, slot_override, erase_first, true);
+                do_flashall(transport, slot_override, true);
             } else {
-                do_flashall(transport, slot_override, erase_first, skip_secondary);
+                do_flashall(transport, slot_override, skip_secondary);
             }
             wants_reboot = true;
         } else if (command == "update") {
@@ -1807,20 +1609,10 @@
             if (!args.empty()) {
                 filename = next_arg(&args);
             }
-            do_update(transport, filename.c_str(), slot_override, erase_first,
-                      skip_secondary || slot_all);
+            do_update(transport, filename.c_str(), slot_override, skip_secondary || slot_all);
             wants_reboot = true;
         } else if (command == "set_active") {
             std::string slot = verify_slot(transport, next_arg(&args), false);
-
-            // Legacy support: verify_slot() removes leading underscores, we need to put them back
-            // in for old bootloaders. Legacy bootloaders do not have the slot-count variable but
-            // do have slot-suffixes.
-            std::string var;
-            if (!fb_getvar(transport, "slot-count", &var) &&
-                    fb_getvar(transport, "slot-suffixes", &var)) {
-                slot = "_" + slot;
-            }
             fb_set_active(slot);
         } else if (command == "stage") {
             std::string filename = next_arg(&args);
@@ -1841,12 +1633,8 @@
             } else if (args.size() == 1 && (args[0] == "unlock" || args[0] == "lock" ||
                                             args[0] == "unlock_critical" ||
                                             args[0] == "lock_critical" ||
-                                            args[0] == "get_unlock_ability" ||
-                                            args[0] == "get_unlock_bootloader_nonce" ||
-                                            args[0] == "lock_bootloader")) {
+                                            args[0] == "get_unlock_ability")) {
                 do_oem_command("flashing", &args);
-            } else if (args.size() == 2 && args[0] == "unlock_bootloader") {
-                do_bypass_unlock_command(&args);
             } else {
                 syntax_error("unknown 'flashing' command %s", args[0].c_str());
             }
@@ -1881,12 +1669,32 @@
     } else if (wants_reboot_bootloader) {
         fb_queue_command("reboot-bootloader", "rebooting into bootloader");
         fb_queue_wait_for_disconnect();
-    } else if (wants_reboot_emergency) {
-        fb_queue_command("reboot-emergency", "rebooting into emergency download (EDL) mode");
-        fb_queue_wait_for_disconnect();
     }
 
     int status = fb_execute_queue(transport) ? EXIT_FAILURE : EXIT_SUCCESS;
     fprintf(stderr, "Finished. Total time: %.3fs\n", (now() - start));
     return status;
 }
+
+void FastBoot::ParseOsPatchLevel(boot_img_hdr_v1* hdr, const char* arg) {
+    unsigned year, month, day;
+    if (sscanf(arg, "%u-%u-%u", &year, &month, &day) != 3) {
+        syntax_error("OS patch level should be YYYY-MM-DD: %s", arg);
+    }
+    if (year < 2000 || year >= 2128) syntax_error("year out of range: %d", year);
+    if (month < 1 || month > 12) syntax_error("month out of range: %d", month);
+    hdr->SetOsPatchLevel(year, month);
+}
+
+void FastBoot::ParseOsVersion(boot_img_hdr_v1* hdr, const char* arg) {
+    unsigned major = 0, minor = 0, patch = 0;
+    std::vector<std::string> versions = android::base::Split(arg, ".");
+    if (versions.size() < 1 || versions.size() > 3 ||
+        (versions.size() >= 1 && !android::base::ParseUint(versions[0], &major)) ||
+        (versions.size() >= 2 && !android::base::ParseUint(versions[1], &minor)) ||
+        (versions.size() == 3 && !android::base::ParseUint(versions[2], &patch)) ||
+        (major > 0x7f || minor > 0x7f || patch > 0x7f)) {
+        syntax_error("bad OS version: %s", arg);
+    }
+    hdr->SetOsVersion(major, minor, patch);
+}
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index a31057a..2935eb5 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -26,16 +26,16 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _FASTBOOT_H_
-#define _FASTBOOT_H_
+#pragma once
 
 #include <inttypes.h>
 #include <stdlib.h>
 
 #include <string>
 
-#include "transport.h"
+#include <bootimg.h>
 
+class Transport;
 struct sparse_file;
 
 /* protocol.c - fastboot protocol */
@@ -75,6 +75,7 @@
 /* util stuff */
 double now();
 char* xstrdup(const char*);
+void set_verbose();
 
 // These printf-like functions are implemented in terms of vsnprintf, so they
 // use the same attribute for compile-time format string checking. On Windows,
@@ -90,9 +91,16 @@
 #endif
 void die(const char* fmt, ...) __attribute__((__noreturn__))
 __attribute__((__format__(FASTBOOT_FORMAT_ARCHETYPE, 1, 2)));
+void verbose(const char* fmt, ...) __attribute__((__format__(FASTBOOT_FORMAT_ARCHETYPE, 1, 2)));
 #undef FASTBOOT_FORMAT_ARCHETYPE
 
 /* Current product */
 extern char cur_product[FB_RESPONSE_SZ + 1];
 
-#endif
+class FastBoot {
+  public:
+    int Main(int argc, char* argv[]);
+
+    void ParseOsPatchLevel(boot_img_hdr_v1*, const char*);
+    void ParseOsVersion(boot_img_hdr_v1*, const char*);
+};
diff --git a/fastboot/fastboot_test.cpp b/fastboot/fastboot_test.cpp
new file mode 100644
index 0000000..1681427
--- /dev/null
+++ b/fastboot/fastboot_test.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "fastboot.h"
+
+#include <gtest/gtest.h>
+
+TEST(FastBoot, ParseOsPatchLevel) {
+    FastBoot fb;
+    boot_img_hdr_v1 hdr;
+
+    hdr = {};
+    fb.ParseOsPatchLevel(&hdr, "2018-01-05");
+    ASSERT_EQ(2018U, 2000U + ((hdr.os_version >> 4) & 0x7f));
+    ASSERT_EQ(1U, ((hdr.os_version >> 0) & 0xf));
+
+    EXPECT_DEATH(fb.ParseOsPatchLevel(&hdr, "2018"), "should be YYYY-MM-DD");
+    EXPECT_DEATH(fb.ParseOsPatchLevel(&hdr, "2018-01"), "should be YYYY-MM-DD");
+    EXPECT_DEATH(fb.ParseOsPatchLevel(&hdr, "2128-01-05"), "year out of range");
+    EXPECT_DEATH(fb.ParseOsPatchLevel(&hdr, "2018-13-05"), "month out of range");
+}
+
+TEST(FastBoot, ParseOsVersion) {
+    FastBoot fb;
+    boot_img_hdr_v1 hdr;
+
+    hdr = {};
+    fb.ParseOsVersion(&hdr, "1.2.3");
+    ASSERT_EQ(1U, ((hdr.os_version >> 25) & 0x7f));
+    ASSERT_EQ(2U, ((hdr.os_version >> 18) & 0x7f));
+    ASSERT_EQ(3U, ((hdr.os_version >> 11) & 0x7f));
+
+    fb.ParseOsVersion(&hdr, "1.2");
+    ASSERT_EQ(1U, ((hdr.os_version >> 25) & 0x7f));
+    ASSERT_EQ(2U, ((hdr.os_version >> 18) & 0x7f));
+    ASSERT_EQ(0U, ((hdr.os_version >> 11) & 0x7f));
+
+    fb.ParseOsVersion(&hdr, "1");
+    ASSERT_EQ(1U, ((hdr.os_version >> 25) & 0x7f));
+    ASSERT_EQ(0U, ((hdr.os_version >> 18) & 0x7f));
+    ASSERT_EQ(0U, ((hdr.os_version >> 11) & 0x7f));
+
+    EXPECT_DEATH(fb.ParseOsVersion(&hdr, ""), "bad OS version");
+    EXPECT_DEATH(fb.ParseOsVersion(&hdr, "1.2.3.4"), "bad OS version");
+    EXPECT_DEATH(fb.ParseOsVersion(&hdr, "128.2.3"), "bad OS version");
+    EXPECT_DEATH(fb.ParseOsVersion(&hdr, "1.128.3"), "bad OS version");
+    EXPECT_DEATH(fb.ParseOsVersion(&hdr, "1.2.128"), "bad OS version");
+}
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index c30ca1e..6f51cf6 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -20,6 +20,7 @@
 
 #include <android-base/errors.h>
 #include <android-base/file.h>
+#include <android-base/macros.h>
 #include <android-base/stringprintf.h>
 #include <android-base/unique_fd.h>
 
diff --git a/fastboot/fs.h b/fastboot/fs.h
index c6baa7f..331100d 100644
--- a/fastboot/fs.h
+++ b/fastboot/fs.h
@@ -1,5 +1,4 @@
-#ifndef _FS_H_
-#define _FS_H_
+#pragma once
 
 #include <string>
 #include <stdint.h>
@@ -9,5 +8,3 @@
 const struct fs_generator* fs_get_generator(const std::string& fs_type);
 int fs_generator_generate(const struct fs_generator* gen, const char* fileName, long long partSize,
     const std::string& initial_dir, unsigned eraseBlkSize = 0, unsigned logicalBlkSize = 0);
-
-#endif
diff --git a/fastboot/main.cpp b/fastboot/main.cpp
new file mode 100644
index 0000000..f1c8afb
--- /dev/null
+++ b/fastboot/main.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "fastboot.h"
+
+int main(int argc, char* argv[]) {
+    FastBoot fb;
+    return fb.Main(argc, argv);
+}
diff --git a/fastboot/protocol.cpp b/fastboot/protocol.cpp
index c239861..fda6f5d 100644
--- a/fastboot/protocol.cpp
+++ b/fastboot/protocol.cpp
@@ -57,10 +57,10 @@
 }
 
 static int64_t check_response(Transport* transport, uint32_t size, char* response) {
-    char status[65];
+    char status[FB_RESPONSE_SZ + 1];
 
     while (true) {
-        int r = transport->Read(status, 64);
+        int r = transport->Read(status, FB_RESPONSE_SZ);
         if (r < 0) {
             g_error = android::base::StringPrintf("status read failed (%s)", strerror(errno));
             transport->Close();
@@ -75,18 +75,21 @@
         }
 
         if (!memcmp(status, "INFO", 4)) {
-            fprintf(stderr,"(bootloader) %s\n", status + 4);
+            verbose("received INFO \"%s\"", status + 4);
+            fprintf(stderr, "(bootloader) %s\n", status + 4);
             continue;
         }
 
         if (!memcmp(status, "OKAY", 4)) {
+            verbose("received OKAY \"%s\"", status + 4);
             if (response) {
-                strcpy(response, (char*) status + 4);
+                strcpy(response, status + 4);
             }
             return 0;
         }
 
         if (!memcmp(status, "FAIL", 4)) {
+            verbose("received FAIL \"%s\"", status + 4);
             if (r > 4) {
                 g_error = android::base::StringPrintf("remote: %s", status + 4);
             } else {
@@ -96,6 +99,7 @@
         }
 
         if (!memcmp(status, "DATA", 4) && size > 0){
+            verbose("received DATA %s", status + 4);
             uint32_t dsize = strtol(status + 4, 0, 16);
             if (dsize > size) {
                 g_error = android::base::StringPrintf("data size too large (%d)", dsize);
@@ -105,6 +109,7 @@
             return dsize;
         }
 
+        verbose("received unknown status code \"%4.4s\"", status);
         g_error = "unknown status code";
         transport->Close();
         break;
@@ -115,7 +120,7 @@
 
 static int64_t _command_start(Transport* transport, const std::string& cmd, uint32_t size,
                               char* response) {
-    if (cmd.size() > 64) {
+    if (cmd.size() > FB_COMMAND_SZ) {
         g_error = android::base::StringPrintf("command too large (%zu)", cmd.size());
         return -1;
     }
@@ -124,6 +129,8 @@
         response[0] = 0;
     }
 
+    verbose("sending command \"%s\"", cmd.c_str());
+
     if (transport->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) {
         g_error = android::base::StringPrintf("command write failed (%s)", strerror(errno));
         transport->Close();
@@ -134,6 +141,8 @@
 }
 
 static int64_t _command_write_data(Transport* transport, const void* data, uint32_t size) {
+    verbose("sending data (%" PRIu32 " bytes)", size);
+
     int64_t r = transport->Write(data, size);
     if (r < 0) {
         g_error = android::base::StringPrintf("data write failure (%s)", strerror(errno));
@@ -149,6 +158,8 @@
 }
 
 static int64_t _command_read_data(Transport* transport, void* data, uint32_t size) {
+    verbose("reading data (%" PRIu32 " bytes)", size);
+
     int64_t r = transport->Read(data, size);
     if (r < 0) {
         g_error = android::base::StringPrintf("data read failure (%s)", strerror(errno));
@@ -267,19 +278,14 @@
     return _command_end(transport);
 }
 
-#define TRANSPORT_BUF_SIZE 1024
+static constexpr size_t TRANSPORT_BUF_SIZE = 1024;
 static char transport_buf[TRANSPORT_BUF_SIZE];
-static int transport_buf_len;
+static size_t transport_buf_len;
 
-static int fb_download_data_sparse_write(void *priv, const void *data, int len)
-{
-    int r;
-    Transport* transport = reinterpret_cast<Transport*>(priv);
-    int to_write;
-    const char* ptr = reinterpret_cast<const char*>(data);
-
+static int fb_download_data_sparse_write(void* priv, const void* data, size_t len) {
+    const char* ptr = static_cast<const char*>(data);
     if (transport_buf_len) {
-        to_write = std::min(TRANSPORT_BUF_SIZE - transport_buf_len, len);
+        size_t to_write = std::min(TRANSPORT_BUF_SIZE - transport_buf_len, len);
 
         memcpy(transport_buf + transport_buf_len, ptr, to_write);
         transport_buf_len += to_write;
@@ -287,9 +293,10 @@
         len -= to_write;
     }
 
+    Transport* transport = static_cast<Transport*>(priv);
     if (transport_buf_len == TRANSPORT_BUF_SIZE) {
-        r = _command_write_data(transport, transport_buf, TRANSPORT_BUF_SIZE);
-        if (r != TRANSPORT_BUF_SIZE) {
+        int64_t r = _command_write_data(transport, transport_buf, TRANSPORT_BUF_SIZE);
+        if (r != static_cast<int64_t>(TRANSPORT_BUF_SIZE)) {
             return -1;
         }
         transport_buf_len = 0;
@@ -300,9 +307,9 @@
             g_error = "internal error: transport_buf not empty";
             return -1;
         }
-        to_write = round_down(len, TRANSPORT_BUF_SIZE);
-        r = _command_write_data(transport, ptr, to_write);
-        if (r != to_write) {
+        size_t to_write = round_down(len, TRANSPORT_BUF_SIZE);
+        int64_t r = _command_write_data(transport, ptr, to_write);
+        if (r != static_cast<int64_t>(to_write)) {
             return -1;
         }
         ptr += to_write;
@@ -333,12 +340,12 @@
 }
 
 int fb_download_data_sparse(Transport* transport, struct sparse_file* s) {
-    int size = sparse_file_len(s, true, false);
-    if (size <= 0) {
+    int64_t size = sparse_file_len(s, true, false);
+    if (size <= 0 || size > std::numeric_limits<uint32_t>::max()) {
         return -1;
     }
 
-    std::string cmd(android::base::StringPrintf("download:%08x", size));
+    std::string cmd(android::base::StringPrintf("download:%08" PRIx64, size));
     int r = _command_start(transport, cmd, size, 0);
     if (r < 0) {
         return -1;
diff --git a/fastboot/socket.h b/fastboot/socket.h
index 7eaa0ab..e791f2c 100644
--- a/fastboot/socket.h
+++ b/fastboot/socket.h
@@ -30,8 +30,7 @@
 // engine should not be using this interface directly, but instead should use a higher-level
 // interface that enforces the fastboot protocol.
 
-#ifndef SOCKET_H_
-#define SOCKET_H_
+#pragma once
 
 #include <functional>
 #include <memory>
@@ -125,5 +124,3 @@
 
     DISALLOW_COPY_AND_ASSIGN(Socket);
 };
-
-#endif  // SOCKET_H_
diff --git a/fastboot/socket_mock.h b/fastboot/socket_mock.h
index eacd6bb..6e95b16 100644
--- a/fastboot/socket_mock.h
+++ b/fastboot/socket_mock.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef SOCKET_MOCK_H_
-#define SOCKET_MOCK_H_
+#pragma once
 
 #include <memory>
 #include <queue>
@@ -97,5 +96,3 @@
 
     DISALLOW_COPY_AND_ASSIGN(SocketMock);
 };
-
-#endif  // SOCKET_MOCK_H_
diff --git a/fastboot/tcp.h b/fastboot/tcp.h
index aa3ef13..8b638a4 100644
--- a/fastboot/tcp.h
+++ b/fastboot/tcp.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef TCP_H_
-#define TCP_H_
+#pragma once
 
 #include <memory>
 #include <string>
@@ -55,5 +54,3 @@
 }  // namespace internal
 
 }  // namespace tcp
-
-#endif  // TCP_H_
diff --git a/fastboot/transport.h b/fastboot/transport.h
index 67d01f9..96b90d2 100644
--- a/fastboot/transport.h
+++ b/fastboot/transport.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef TRANSPORT_H_
-#define TRANSPORT_H_
+#pragma once
 
 #include <android-base/macros.h>
 
@@ -44,5 +43,3 @@
   private:
     DISALLOW_COPY_AND_ASSIGN(Transport);
 };
-
-#endif  // TRANSPORT_H_
diff --git a/fastboot/udp.h b/fastboot/udp.h
index 14f5b35..8d37b84 100644
--- a/fastboot/udp.h
+++ b/fastboot/udp.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef UDP_H_
-#define UDP_H_
+#pragma once
 
 #include <memory>
 #include <string>
@@ -77,5 +76,3 @@
 }  // namespace internal
 
 }  // namespace udp
-
-#endif  // UDP_H_
diff --git a/fastboot/usb.h b/fastboot/usb.h
index 4acf12d..5b44468 100644
--- a/fastboot/usb.h
+++ b/fastboot/usb.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _USB_H_
-#define _USB_H_
+#pragma once
 
 #include "transport.h"
 
@@ -56,5 +55,3 @@
 typedef int (*ifc_match_func)(usb_ifc_info *ifc);
 
 Transport* usb_open(ifc_match_func callback);
-
-#endif
diff --git a/fastboot/usbtest.cpp b/fastboot/usbtest.cpp
deleted file mode 100644
index 9423c6d..0000000
--- a/fastboot/usbtest.cpp
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include <sys/time.h>
-
-#include "usb.h"
-
-static unsigned arg_size = 4096;
-static unsigned arg_count = 4096;
-
-long long NOW(void)
-{
-    struct timeval tv;
-    gettimeofday(&tv, 0);
-
-    return (((long long) tv.tv_sec) * ((long long) 1000000)) +
-        (((long long) tv.tv_usec));
-}
-
-int printifc(usb_ifc_info *info)
-{
-    printf("dev: csp=%02x/%02x/%02x v=%04x p=%04x  ",
-           info->dev_class, info->dev_subclass, info->dev_protocol,
-           info->dev_vendor, info->dev_product);
-    printf("ifc: csp=%02x/%02x/%02x%s%s\n",
-           info->ifc_class, info->ifc_subclass, info->ifc_protocol,
-           info->has_bulk_in ? " in" : "",
-           info->has_bulk_out ? " out" : "");
-    return -1;
-}
-
-int match_null(usb_ifc_info *info)
-{
-    if(info->dev_vendor != 0x18d1) return -1;
-    if(info->ifc_class != 0xff) return -1;
-    if(info->ifc_subclass != 0xfe) return -1;
-    if(info->ifc_protocol != 0x01) return -1;
-    return 0;
-}
-
-int match_zero(usb_ifc_info *info)
-{
-    if(info->dev_vendor != 0x18d1) return -1;
-    if(info->ifc_class != 0xff) return -1;
-    if(info->ifc_subclass != 0xfe) return -1;
-    if(info->ifc_protocol != 0x02) return -1;
-    return 0;
-}
-
-int match_loop(usb_ifc_info *info)
-{
-    if(info->dev_vendor != 0x18d1) return -1;
-    if(info->ifc_class != 0xff) return -1;
-    if(info->ifc_subclass != 0xfe) return -1;
-    if(info->ifc_protocol != 0x03) return -1;
-    return 0;
-}
-
-int test_null(Transport* usb)
-{
-    unsigned i;
-    unsigned char buf[4096];
-    memset(buf, 0xee, 4096);
-    long long t0, t1;
-
-    t0 = NOW();
-    for (i = 0; i < arg_count; i++) {
-        if (usb->Write(buf, arg_size) != static_cast<int>(arg_size)) {
-            fprintf(stderr,"write failed (%s)\n", strerror(errno));
-            return -1;
-        }
-    }
-    t1 = NOW();
-    fprintf(stderr,"%d bytes in %lld uS\n", arg_count * arg_size, (t1 - t0));
-    return 0;
-}
-
-int test_zero(Transport* usb)
-{
-    unsigned i;
-    unsigned char buf[4096];
-    long long t0, t1;
-
-    t0 = NOW();
-    for (i = 0; i < arg_count; i++) {
-        if (usb->Read(buf, arg_size) != static_cast<int>(arg_size)) {
-            fprintf(stderr,"read failed (%s)\n", strerror(errno));
-            return -1;
-        }
-    }
-    t1 = NOW();
-    fprintf(stderr,"%d bytes in %lld uS\n", arg_count * arg_size, (t1 - t0));
-    return 0;
-}
-
-struct
-{
-    const char *cmd;
-    ifc_match_func match;
-    int (*test)(Transport* usb);
-    const char *help;
-} tests[] = {
-    { "list", printifc,   NULL,      "list interfaces" },
-    { "send", match_null, test_null, "send to null interface" },
-    { "recv", match_zero, test_zero, "recv from zero interface" },
-    { "loop", match_loop, NULL,      "exercise loopback interface" },
-    { NULL, NULL, NULL, NULL },
-};
-
-int usage(void)
-{
-    int i;
-
-    fprintf(stderr,"usage: usbtest <testname>\n\navailable tests:\n");
-    for(i = 0; tests[i].cmd; i++) {
-        fprintf(stderr," %-8s %s\n", tests[i].cmd, tests[i].help);
-    }
-    return -1;
-}
-
-int process_args(int argc, char **argv)
-{
-    while(argc-- > 0) {
-        char *arg = *argv++;
-        if(!strncmp(arg,"count=",6)) {
-            arg_count = atoi(arg + 6);
-        } else if(!strncmp(arg,"size=",5)) {
-            arg_size = atoi(arg + 5);
-        } else {
-            fprintf(stderr,"unknown argument: %s\n", arg);
-            return -1;
-        }
-    }
-
-    if(arg_count == 0) {
-        fprintf(stderr,"count may not be zero\n");
-        return -1;
-    }
-
-    if(arg_size > 4096) {
-        fprintf(stderr,"size may not be greater than 4096\n");
-        return -1;
-    }
-
-    return 0;
-}
-
-int main(int argc, char **argv)
-{
-    Transport* usb;
-    int i;
-
-    if(argc < 2)
-        return usage();
-
-    if(argc > 2) {
-        if(process_args(argc - 2, argv + 2))
-            return -1;
-    }
-
-    for(i = 0; tests[i].cmd; i++) {
-        if(!strcmp(argv[1], tests[i].cmd)) {
-            usb = usb_open(tests[i].match);
-            if(tests[i].test) {
-                if(usb == 0) {
-                    fprintf(stderr,"usbtest: %s: could not find interface\n",
-                            tests[i].cmd);
-                    return -1;
-                }
-                if(tests[i].test(usb)) {
-                    fprintf(stderr,"usbtest: %s: FAIL\n", tests[i].cmd);
-                    return -1;
-                } else {
-                    fprintf(stderr,"usbtest: %s: OKAY\n", tests[i].cmd);
-                }
-            }
-            return 0;
-        }
-    }
-
-    return usage();
-}
diff --git a/fastboot/util.cpp b/fastboot/util.cpp
index fb085e7..140270f 100644
--- a/fastboot/util.cpp
+++ b/fastboot/util.cpp
@@ -35,6 +35,8 @@
 
 #include "fastboot.h"
 
+static bool g_verbose = false;
+
 double now() {
     struct timeval tv;
     gettimeofday(&tv, NULL);
@@ -44,13 +46,30 @@
 void die(const char* fmt, ...) {
     va_list ap;
     va_start(ap, fmt);
-    fprintf(stderr,"error: ");
+    fprintf(stderr, "fastboot: error: ");
     vfprintf(stderr, fmt, ap);
-    fprintf(stderr,"\n");
+    fprintf(stderr, "\n");
     va_end(ap);
     exit(EXIT_FAILURE);
 }
 
+void set_verbose() {
+    g_verbose = true;
+}
+
+void verbose(const char* fmt, ...) {
+    if (!g_verbose) return;
+
+    if (*fmt != '\n') {
+        va_list ap;
+        va_start(ap, fmt);
+        fprintf(stderr, "fastboot: verbose: ");
+        vfprintf(stderr, fmt, ap);
+        va_end(ap);
+    }
+    fprintf(stderr, "\n");
+}
+
 char* xstrdup(const char* s) {
     char* result = strdup(s);
     if (!result) die("out of memory");
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index f23150d..05dba15 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -42,6 +42,7 @@
         "fs_mgr_verity.cpp",
         "fs_mgr_avb.cpp",
         "fs_mgr_avb_ops.cpp",
+        "fs_mgr_dm_linear.cpp",
     ],
     static_libs: [
         "libfec",
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 9aab0ba..6e9ffba 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -794,6 +794,29 @@
     return true;
 }
 
+bool fs_mgr_update_logical_partition(struct fstab_rec* rec) {
+    // Logical partitions are specified with a named partition rather than a
+    // block device, so if the block device is a path, then it has already
+    // been updated.
+    if (rec->blk_device[0] == '/') {
+        return true;
+    }
+
+    android::base::unique_fd dm_fd(open("/dev/device-mapper", O_RDONLY));
+    if (dm_fd < 0) {
+        PLOG(ERROR) << "open /dev/device-mapper failed";
+        return false;
+    }
+    struct dm_ioctl io;
+    std::string device_name;
+    if (!fs_mgr_dm_get_device_name(&io, rec->blk_device, dm_fd, &device_name)) {
+        return false;
+    }
+    free(rec->blk_device);
+    rec->blk_device = strdup(device_name.c_str());
+    return true;
+}
+
 /* When multiple fstab records share the same mount_point, it will
  * try to mount each one in turn, and ignore any duplicates after a
  * first successful mount.
@@ -845,6 +868,13 @@
             }
         }
 
+        if ((fstab->recs[i].fs_mgr_flags & MF_LOGICAL)) {
+            if (!fs_mgr_update_logical_partition(&fstab->recs[i])) {
+                LERROR << "Could not set up logical partition, skipping!";
+                continue;
+            }
+        }
+
         if (fstab->recs[i].fs_mgr_flags & MF_WAIT &&
             !fs_mgr_wait_for_file(fstab->recs[i].blk_device, 20s)) {
             LERROR << "Skipping '" << fstab->recs[i].blk_device << "' during mount_all";
@@ -1065,6 +1095,13 @@
             return FS_MGR_DOMNT_FAILED;
         }
 
+        if ((fstab->recs[i].fs_mgr_flags & MF_LOGICAL)) {
+            if (!fs_mgr_update_logical_partition(&fstab->recs[i])) {
+                LERROR << "Could not set up logical partition, skipping!";
+                continue;
+            }
+        }
+
         /* First check the filesystem if requested */
         if (fstab->recs[i].fs_mgr_flags & MF_WAIT && !fs_mgr_wait_for_file(n_blk_device, 20s)) {
             LERROR << "Skipping mounting '" << n_blk_device << "'";
@@ -1383,7 +1420,7 @@
             mount_point = basename(fstab->recs[i].mount_point);
         }
 
-        fs_mgr_verity_ioctl_init(io, mount_point, 0);
+        fs_mgr_dm_ioctl_init(io, DM_BUF_SIZE, mount_point);
 
         const char* status;
         if (ioctl(fd, DM_TABLE_STATUS, io)) {
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index 7824cfa..5a9cb65 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -303,13 +303,14 @@
 
 static bool load_verity_table(struct dm_ioctl* io, const std::string& dm_device_name, int fd,
                               uint64_t image_size, const std::string& verity_table) {
-    fs_mgr_verity_ioctl_init(io, dm_device_name, DM_STATUS_TABLE_FLAG);
+    fs_mgr_dm_ioctl_init(io, DM_BUF_SIZE, dm_device_name);
 
     // The buffer consists of [dm_ioctl][dm_target_spec][verity_params].
     char* buffer = (char*)io;
 
     // Builds the dm_target_spec arguments.
     struct dm_target_spec* dm_target = (struct dm_target_spec*)&buffer[sizeof(struct dm_ioctl)];
+    io->flags = DM_READONLY_FLAG;
     io->target_count = 1;
     dm_target->status = 0;
     dm_target->sector_start = 0;
@@ -359,14 +360,14 @@
     alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
     struct dm_ioctl* io = (struct dm_ioctl*)buffer;
     const std::string mount_point(basename(fstab_entry->mount_point));
-    if (!fs_mgr_create_verity_device(io, mount_point, fd)) {
+    if (!fs_mgr_dm_create_device(io, mount_point, fd)) {
         LERROR << "Couldn't create verity device!";
         return false;
     }
 
     // Gets the name of the device file.
     std::string verity_blk_name;
-    if (!fs_mgr_get_verity_device_name(io, mount_point, fd, &verity_blk_name)) {
+    if (!fs_mgr_dm_get_device_name(io, mount_point, fd, &verity_blk_name)) {
         LERROR << "Couldn't get verity device number!";
         return false;
     }
@@ -385,7 +386,7 @@
     }
 
     // Activates the device.
-    if (!fs_mgr_resume_verity_table(io, mount_point, fd)) {
+    if (!fs_mgr_dm_resume_table(io, mount_point, fd)) {
         return false;
     }
 
@@ -584,7 +585,13 @@
 
     // Derives partition_name from blk_device to query the corresponding AVB HASHTREE descriptor
     // to setup dm-verity. The partition_names in AVB descriptors are without A/B suffix.
-    std::string partition_name(basename(fstab_entry->blk_device));
+    std::string partition_name;
+    if (fstab_entry->fs_mgr_flags & MF_LOGICAL) {
+        partition_name = fstab_entry->logical_partition_name;
+    } else {
+        partition_name = basename(fstab_entry->blk_device);
+    }
+
     if (fstab_entry->fs_mgr_flags & MF_SLOTSELECT) {
         auto ab_suffix = partition_name.rfind(fs_mgr_get_slot_suffix());
         if (ab_suffix != std::string::npos) {
diff --git a/fs_mgr/fs_mgr_dm_ioctl.cpp b/fs_mgr/fs_mgr_dm_ioctl.cpp
index 4cbd5a8..3a7fae4 100644
--- a/fs_mgr/fs_mgr_dm_ioctl.cpp
+++ b/fs_mgr/fs_mgr_dm_ioctl.cpp
@@ -23,21 +23,20 @@
 #include "fs_mgr_priv.h"
 #include "fs_mgr_priv_dm_ioctl.h"
 
-void fs_mgr_verity_ioctl_init(struct dm_ioctl* io, const std::string& name, unsigned flags) {
-    memset(io, 0, DM_BUF_SIZE);
-    io->data_size = DM_BUF_SIZE;
+void fs_mgr_dm_ioctl_init(struct dm_ioctl* io, size_t size, const std::string& name) {
+    memset(io, 0, size);
+    io->data_size = size;
     io->data_start = sizeof(struct dm_ioctl);
     io->version[0] = 4;
     io->version[1] = 0;
     io->version[2] = 0;
-    io->flags = flags | DM_READONLY_FLAG;
     if (!name.empty()) {
         strlcpy(io->name, name.c_str(), sizeof(io->name));
     }
 }
 
-bool fs_mgr_create_verity_device(struct dm_ioctl* io, const std::string& name, int fd) {
-    fs_mgr_verity_ioctl_init(io, name, 1);
+bool fs_mgr_dm_create_device(struct dm_ioctl* io, const std::string& name, int fd) {
+    fs_mgr_dm_ioctl_init(io, sizeof(*io), name);
     if (ioctl(fd, DM_DEV_CREATE, io)) {
         PERROR << "Error creating device mapping";
         return false;
@@ -45,8 +44,8 @@
     return true;
 }
 
-bool fs_mgr_destroy_verity_device(struct dm_ioctl* io, const std::string& name, int fd) {
-    fs_mgr_verity_ioctl_init(io, name, 0);
+bool fs_mgr_dm_destroy_device(struct dm_ioctl* io, const std::string& name, int fd) {
+    fs_mgr_dm_ioctl_init(io, sizeof(*io), name);
     if (ioctl(fd, DM_DEV_REMOVE, io)) {
         PERROR << "Error removing device mapping";
         return false;
@@ -54,13 +53,13 @@
     return true;
 }
 
-bool fs_mgr_get_verity_device_name(struct dm_ioctl* io, const std::string& name, int fd,
-                                   std::string* out_dev_name) {
+bool fs_mgr_dm_get_device_name(struct dm_ioctl* io, const std::string& name, int fd,
+                               std::string* out_dev_name) {
     FS_MGR_CHECK(out_dev_name != nullptr);
 
-    fs_mgr_verity_ioctl_init(io, name, 0);
+    fs_mgr_dm_ioctl_init(io, sizeof(*io), name);
     if (ioctl(fd, DM_DEV_STATUS, io)) {
-        PERROR << "Error fetching verity device number";
+        PERROR << "Error fetching device-mapper device number";
         return false;
     }
 
@@ -70,10 +69,10 @@
     return true;
 }
 
-bool fs_mgr_resume_verity_table(struct dm_ioctl* io, const std::string& name, int fd) {
-    fs_mgr_verity_ioctl_init(io, name, 0);
+bool fs_mgr_dm_resume_table(struct dm_ioctl* io, const std::string& name, int fd) {
+    fs_mgr_dm_ioctl_init(io, sizeof(*io), name);
     if (ioctl(fd, DM_DEV_SUSPEND, io)) {
-        PERROR << "Error activating verity device";
+        PERROR << "Error activating device table";
         return false;
     }
     return true;
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
new file mode 100644
index 0000000..b2f3a68
--- /dev/null
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "fs_mgr_dm_linear.h"
+
+#include <inttypes.h>
+#include <linux/dm-ioctl.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <sstream>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+
+#include "fs_mgr_priv.h"
+#include "fs_mgr_priv_dm_ioctl.h"
+
+namespace android {
+namespace fs_mgr {
+
+std::string LogicalPartitionExtent::Serialize() const {
+    // Note: we need to include an explicit null-terminator.
+    std::string argv =
+        android::base::StringPrintf("%s %" PRIu64, block_device_.c_str(), first_sector_);
+    argv.push_back(0);
+
+    // The kernel expects each target to be aligned.
+    size_t spec_bytes = sizeof(struct dm_target_spec) + argv.size();
+    size_t padding = ((spec_bytes + 7) & ~7) - spec_bytes;
+    for (size_t i = 0; i < padding; i++) {
+        argv.push_back(0);
+    }
+
+    struct dm_target_spec spec;
+    spec.sector_start = logical_sector_;
+    spec.length = num_sectors_;
+    spec.status = 0;
+    strcpy(spec.target_type, "linear");
+    spec.next = sizeof(struct dm_target_spec) + argv.size();
+
+    return std::string((char*)&spec, sizeof(spec)) + argv;
+}
+
+static bool LoadDmTable(int dm_fd, const LogicalPartition& partition) {
+    // Combine all dm_target_spec buffers together.
+    std::string target_string;
+    for (const auto& extent : partition.extents) {
+        target_string += extent.Serialize();
+    }
+
+    // Allocate the ioctl buffer.
+    size_t buffer_size = sizeof(struct dm_ioctl) + target_string.size();
+    std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(buffer_size);
+
+    // Initialize the ioctl buffer header, then copy our target specs in.
+    struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(buffer.get());
+    fs_mgr_dm_ioctl_init(io, buffer_size, partition.name);
+    io->target_count = partition.extents.size();
+    if (partition.attributes & kPartitionReadonly) {
+        io->flags |= DM_READONLY_FLAG;
+    }
+    memcpy(io + 1, target_string.c_str(), target_string.size());
+
+    if (ioctl(dm_fd, DM_TABLE_LOAD, io)) {
+        PERROR << "Failed ioctl() on DM_TABLE_LOAD, partition " << partition.name;
+        return false;
+    }
+    return true;
+}
+
+static bool LoadTablesAndActivate(int dm_fd, const LogicalPartition& partition) {
+    if (!LoadDmTable(dm_fd, partition)) {
+        return false;
+    }
+
+    struct dm_ioctl io;
+    return fs_mgr_dm_resume_table(&io, partition.name, dm_fd);
+}
+
+static bool CreateDmDeviceForPartition(int dm_fd, const LogicalPartition& partition) {
+    struct dm_ioctl io;
+    if (!fs_mgr_dm_create_device(&io, partition.name, dm_fd)) {
+        return false;
+    }
+    if (!LoadTablesAndActivate(dm_fd, partition)) {
+        // Remove the device rather than leave it in an inactive state.
+        fs_mgr_dm_destroy_device(&io, partition.name, dm_fd);
+        return false;
+    }
+
+    LINFO << "Created device-mapper device: " << partition.name;
+    return true;
+}
+
+bool CreateLogicalPartitions(const LogicalPartitionTable& table) {
+    android::base::unique_fd dm_fd(open("/dev/device-mapper", O_RDWR));
+    if (dm_fd < 0) {
+        PLOG(ERROR) << "failed to open /dev/device-mapper";
+        return false;
+    }
+    for (const auto& partition : table.partitions) {
+        if (!CreateDmDeviceForPartition(dm_fd, partition)) {
+            LOG(ERROR) << "could not create dm-linear device for partition: " << partition.name;
+            return false;
+        }
+    }
+    return true;
+}
+
+std::unique_ptr<LogicalPartitionTable> LoadPartitionsFromDeviceTree() {
+    return nullptr;
+}
+
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 68cc530..af4d6c1 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -33,6 +33,8 @@
 
 #include "fs_mgr_priv.h"
 
+using android::base::StartsWith;
+
 const std::string kDefaultAndroidDtDir("/proc/device-tree/firmware/android");
 
 struct fs_mgr_flag_values {
@@ -107,6 +109,7 @@
     {"logicalblk=", MF_LOGICALBLKSIZE},
     {"sysfs_path=", MF_SYSFS},
     {"defaults", 0},
+    {"logical", MF_LOGICAL},
     {0, 0},
 };
 
@@ -625,6 +628,10 @@
         fstab->recs[cnt].erase_blk_size = flag_vals.erase_blk_size;
         fstab->recs[cnt].logical_blk_size = flag_vals.logical_blk_size;
         fstab->recs[cnt].sysfs_path = flag_vals.sysfs_path;
+        if (fstab->recs[cnt].fs_mgr_flags & MF_LOGICAL) {
+            fstab->recs[cnt].logical_partition_name = strdup(fstab->recs[cnt].blk_device);
+        }
+
         cnt++;
     }
     /* If an A/B partition, modify block device to be the real block device */
@@ -834,6 +841,7 @@
     for (i = 0; i < fstab->num_entries; i++) {
         /* Free the pointers return by strdup(3) */
         free(fstab->recs[i].blk_device);
+        free(fstab->recs[i].logical_partition_name);
         free(fstab->recs[i].mount_point);
         free(fstab->recs[i].fs_type);
         free(fstab->recs[i].fs_options);
@@ -998,3 +1006,7 @@
 {
     return fstab->fs_mgr_flags & MF_SYSFS;
 }
+
+int fs_mgr_is_logical(const struct fstab_rec* fstab) {
+    return fstab->fs_mgr_flags & MF_LOGICAL;
+}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 9011bb3..a347faf 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -82,6 +82,7 @@
  *
  */
 
+// clang-format off
 #define MF_WAIT                  0x1
 #define MF_CHECK                 0x2
 #define MF_CRYPT                 0x4
@@ -111,6 +112,8 @@
 #define MF_AVB             0X2000000
 #define MF_KEYDIRECTORY    0X4000000
 #define MF_SYSFS           0X8000000
+#define MF_LOGICAL        0x10000000
+// clang-format on
 
 #define DM_BUF_SIZE 4096
 
diff --git a/fs_mgr/fs_mgr_priv_dm_ioctl.h b/fs_mgr/fs_mgr_priv_dm_ioctl.h
index a00a9c1..792475d 100644
--- a/fs_mgr/fs_mgr_priv_dm_ioctl.h
+++ b/fs_mgr/fs_mgr_priv_dm_ioctl.h
@@ -20,15 +20,15 @@
 #include <linux/dm-ioctl.h>
 #include <string>
 
-void fs_mgr_verity_ioctl_init(struct dm_ioctl* io, const std::string& name, unsigned flags);
+void fs_mgr_dm_ioctl_init(struct dm_ioctl* io, size_t size, const std::string& name);
 
-bool fs_mgr_create_verity_device(struct dm_ioctl* io, const std::string& name, int fd);
+bool fs_mgr_dm_create_device(struct dm_ioctl* io, const std::string& name, int fd);
 
-bool fs_mgr_destroy_verity_device(struct dm_ioctl* io, const std::string& name, int fd);
+bool fs_mgr_dm_destroy_device(struct dm_ioctl* io, const std::string& name, int fd);
 
-bool fs_mgr_get_verity_device_name(struct dm_ioctl* io, const std::string& name, int fd,
-                                   std::string* out_dev_name);
+bool fs_mgr_dm_get_device_name(struct dm_ioctl* io, const std::string& name, int fd,
+                               std::string* out_dev_name);
 
-bool fs_mgr_resume_verity_table(struct dm_ioctl* io, const std::string& name, int fd);
+bool fs_mgr_dm_resume_table(struct dm_ioctl* io, const std::string& name, int fd);
 
 #endif /* __CORE_FS_MGR_PRIV_DM_IOCTL_H */
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp
index 0a113b4..3b01d0e 100644
--- a/fs_mgr/fs_mgr_slotselect.cpp
+++ b/fs_mgr/fs_mgr_slotselect.cpp
@@ -36,19 +36,30 @@
     std::string ab_suffix;
 
     for (n = 0; n < fstab->num_entries; n++) {
-        if (fstab->recs[n].fs_mgr_flags & MF_SLOTSELECT) {
-            char *tmp;
+        fstab_rec& record = fstab->recs[n];
+        if (record.fs_mgr_flags & MF_SLOTSELECT) {
             if (ab_suffix.empty()) {
                 ab_suffix = fs_mgr_get_slot_suffix();
                 // Return false if failed to get ab_suffix when MF_SLOTSELECT is specified.
                 if (ab_suffix.empty()) return false;
             }
-            if (asprintf(&tmp, "%s%s", fstab->recs[n].blk_device, ab_suffix.c_str()) > 0) {
-                free(fstab->recs[n].blk_device);
-                fstab->recs[n].blk_device = tmp;
-            } else {
+
+            char* new_blk_device;
+            if (asprintf(&new_blk_device, "%s%s", record.blk_device, ab_suffix.c_str()) <= 0) {
                 return false;
             }
+            free(record.blk_device);
+            record.blk_device = new_blk_device;
+
+            char* new_partition_name;
+            if (record.logical_partition_name) {
+                if (asprintf(&new_partition_name, "%s%s", record.logical_partition_name,
+                             ab_suffix.c_str()) <= 0) {
+                    return false;
+                }
+                free(record.logical_partition_name);
+                record.logical_partition_name = new_partition_name;
+            }
         }
     }
     return true;
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 896b603..fe41f8a 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -258,12 +258,13 @@
     char *buffer = (char*) io;
     size_t bufsize;
 
-    fs_mgr_verity_ioctl_init(io, name, DM_STATUS_TABLE_FLAG);
+    fs_mgr_dm_ioctl_init(io, DM_BUF_SIZE, name);
 
     struct dm_target_spec *tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
 
     // set tgt arguments
     io->target_count = 1;
+    io->flags = DM_READONLY_FLAG;
     tgt->status = 0;
     tgt->sector_start = 0;
     tgt->length = device_size / 512;
@@ -804,13 +805,13 @@
     }
 
     // create the device
-    if (!fs_mgr_create_verity_device(io, mount_point, fd)) {
+    if (!fs_mgr_dm_create_device(io, mount_point, fd)) {
         LERROR << "Couldn't create verity device!";
         goto out;
     }
 
     // get the name of the device file
-    if (!fs_mgr_get_verity_device_name(io, mount_point, fd, &verity_blk_name)) {
+    if (!fs_mgr_dm_get_device_name(io, mount_point, fd, &verity_blk_name)) {
         LERROR << "Couldn't get verity device number!";
         goto out;
     }
@@ -899,7 +900,7 @@
 loaded:
 
     // activate the device
-    if (!fs_mgr_resume_verity_table(io, mount_point, fd)) {
+    if (!fs_mgr_dm_resume_table(io, mount_point, fd)) {
         goto out;
     }
 
@@ -922,7 +923,7 @@
     if (!verified_at_boot) {
         free(fstab->blk_device);
         fstab->blk_device = strdup(verity_blk_name.c_str());
-    } else if (!fs_mgr_destroy_verity_device(io, mount_point, fd)) {
+    } else if (!fs_mgr_dm_destroy_device(io, mount_point, fd)) {
         LERROR << "Failed to remove verity device " << mount_point.c_str();
         goto out;
     }
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 653d8fa..72f019e 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -76,6 +76,7 @@
 bool fs_mgr_load_verity_state(int* mode);
 bool fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback);
 int fs_mgr_swapon_all(struct fstab *fstab);
+bool fs_mgr_update_logical_partition(struct fstab_rec* rec);
 
 int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer);
 
diff --git a/fs_mgr/include/fs_mgr_dm_linear.h b/fs_mgr/include/fs_mgr_dm_linear.h
new file mode 100644
index 0000000..7f928e5
--- /dev/null
+++ b/fs_mgr/include/fs_mgr_dm_linear.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __CORE_FS_MGR_DM_LINEAR_H
+#define __CORE_FS_MGR_DM_LINEAR_H
+
+#include <stdint.h>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace android {
+namespace fs_mgr {
+
+static const uint32_t kPartitionReadonly = 0x1;
+
+class LogicalPartitionExtent {
+  public:
+    LogicalPartitionExtent() : logical_sector_(0), first_sector_(0), num_sectors_(0) {}
+    LogicalPartitionExtent(uint64_t logical_sector, uint64_t first_sector, uint64_t num_sectors,
+                           const std::string& block_device)
+        : logical_sector_(logical_sector),
+          first_sector_(first_sector),
+          num_sectors_(num_sectors),
+          block_device_(block_device) {}
+
+    // Return a string containing the dm_target_spec buffer needed to use this
+    // extent in a device-mapper table.
+    std::string Serialize() const;
+
+    const std::string& block_device() const { return block_device_; }
+
+  private:
+    // Logical sector this extent represents in the presented block device.
+    // This is equal to the previous extent's logical sector plus the number
+    // of sectors in that extent. The first extent always starts at 0.
+    uint64_t logical_sector_;
+    // First 512-byte sector of this extent, on the source block device.
+    uint64_t first_sector_;
+    // Number of 512-byte sectors.
+    uint64_t num_sectors_;
+    // Target block device.
+    std::string block_device_;
+};
+
+struct LogicalPartition {
+    LogicalPartition() : attributes(0), num_sectors(0) {}
+
+    std::string name;
+    uint32_t attributes;
+    // Number of 512-byte sectors total.
+    uint64_t num_sectors;
+    // List of extents.
+    std::vector<LogicalPartitionExtent> extents;
+};
+
+struct LogicalPartitionTable {
+    // List of partitions in the partition table.
+    std::vector<LogicalPartition> partitions;
+};
+
+// Load a dm-linear table from the device tree if one is available; otherwise,
+// return null.
+std::unique_ptr<LogicalPartitionTable> LoadPartitionsFromDeviceTree();
+
+// Create device-mapper devices for the given partition table.
+//
+// On success, two devices nodes will be created for each partition, both
+// pointing to the same device:
+//   /dev/block/dm-<N> where N is a sequential ID assigned by device-mapper.
+//   /dev/block/dm-<name> where |name| is the partition name.
+//
+bool CreateLogicalPartitions(const LogicalPartitionTable& table);
+
+}  // namespace fs_mgr
+}  // namespace android
+
+#endif  // __CORE_FS_MGR_DM_LINEAR_H
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index e8da2ac..d232cca 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -38,6 +38,7 @@
 
 struct fstab_rec {
     char* blk_device;
+    char* logical_partition_name;
     char* mount_point;
     char* fs_type;
     unsigned long flags;
@@ -85,6 +86,7 @@
 int fs_mgr_is_nofail(const struct fstab_rec* fstab);
 int fs_mgr_is_latemount(const struct fstab_rec* fstab);
 int fs_mgr_is_quota(const struct fstab_rec* fstab);
+int fs_mgr_is_logical(const struct fstab_rec* fstab);
 int fs_mgr_has_sysfs_path(const struct fstab_rec* fstab);
 
 std::string fs_mgr_get_slot_suffix();
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 818488d..86f7cf0 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -74,9 +74,6 @@
 ifeq ($(strip $(BOARD_CHARGER_NO_UI)),true)
 LOCAL_CHARGER_NO_UI := true
 endif
-ifdef BRILLO
-LOCAL_CHARGER_NO_UI := true
-endif
 
 LOCAL_SRC_FILES := \
     charger.cpp \
diff --git a/healthd/OWNERS b/healthd/OWNERS
index 2375f7c..00df08a 100644
--- a/healthd/OWNERS
+++ b/healthd/OWNERS
@@ -1 +1,2 @@
+elsk@google.com
 toddpoynor@google.com
diff --git a/init/Android.bp b/init/Android.bp
index 70a4ac6..a31c5a5 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -180,6 +180,7 @@
         "util_test.cpp",
     ],
     static_libs: ["libinit"],
+    test_suites: ["device-tests"],
 }
 
 cc_benchmark {
diff --git a/init/README.md b/init/README.md
index 5c2352b..550ef05 100644
--- a/init/README.md
+++ b/init/README.md
@@ -161,6 +161,25 @@
 Options are modifiers to services.  They affect how and when init
 runs the service.
 
+`capabilities <capability> [ <capability>\* ]`
+> Set capabilities when exec'ing this service. 'capability' should be a Linux
+  capability without the "CAP\_" prefix, like "NET\_ADMIN" or "SETPCAP". See
+  http://man7.org/linux/man-pages/man7/capabilities.7.html for a list of Linux
+  capabilities.
+
+`class <name> [ <name>\* ]`
+> Specify class names for the service.  All services in a
+  named class may be started or stopped together.  A service
+  is in the class "default" if one is not specified via the
+  class option. Additional classnames beyond the (required) first
+  one are used to group services.
+  The `animation` class should include all services necessary for both
+  boot animation and shutdown animation. As these services can be
+  launched very early during bootup and can run until the last stage
+  of shutdown, access to /data partition is not guaranteed. These
+  services can check files under /data but it should not keep files opened
+  and should work when /data is not available.
+
 `console [<console>]`
 > This service needs a console. The optional second parameter chooses a
   specific console instead of the default. The default "/dev/console" can
@@ -174,11 +193,103 @@
 
 `disabled`
 > This service will not automatically start with its class.
-  It must be explicitly started by name.
+  It must be explicitly started by name or by interface name.
+
+`enter_namespace <type> <path>`
+> Enters the namespace of type _type_ located at _path_. Only network namespaces are supported with
+  _type_ set to "net". Note that only one namespace of a given _type_ may be entered.
+
+`file <path> <type>`
+> Open a file path and pass its fd to the launched process. _type_ must be
+  "r", "w" or "rw".  For native executables see libcutils
+  android\_get\_control\_file().
+
+`group <groupname> [ <groupname>\* ]`
+> Change to 'groupname' before exec'ing this service.  Additional
+  groupnames beyond the (required) first one are used to set the
+  supplemental groups of the process (via setgroups()).
+  Currently defaults to root.  (??? probably should default to nobody)
+
+`interface <interface name> <instance name>`
+> Associates this service with a list of the HIDL services that it provides. The interface name
+  must be a fully-qualified name and not a value name. This is used to allow hwservicemanager to
+  lazily start services.
+  For example: interface vendor.foo.bar@1.0::IBaz default
+
+`ioprio <class> <priority>`
+> Sets the IO priority and IO priority class for this service via the SYS_ioprio_set syscall.
+  _class_ must be one of "rt", "be", or "idle". _priority_ must be an integer in the range 0 - 7.
+
+`keycodes <keycode> [ <keycode>\* ]`
+> Sets the keycodes that will trigger this service. If all of the keys corresponding to the passed
+  keycodes are pressed at once, the service will start. This is typically used to start the
+  bugreport service.
+
+`memcg.limit_in_bytes <value>`
+> Sets the child's memory.limit_in_bytes to the specified value (only if memcg is mounted),
+  which must be equal or greater than 0.
+
+`memcg.soft_limit_in_bytes <value>`
+> Sets the child's memory.soft_limit_in_bytes to the specified value (only if memcg is mounted),
+  which must be equal or greater than 0.
+
+`memcg.swappiness <value>`
+> Sets the child's memory.swappiness to the specified value (only if memcg is mounted),
+  which must be equal or greater than 0.
+
+`namespace <pid|mnt>`
+> Enter a new PID or mount namespace when forking the service.
+
+`oneshot`
+> Do not restart the service when it exits.
+
+`onrestart`
+> Execute a Command (see below) when service restarts.
+
+`oom_score_adjust <value>`
+> Sets the child's /proc/self/oom\_score\_adj to the specified value,
+  which must range from -1000 to 1000.
+
+`override`
+> Indicates that this service definition is meant to override a previous definition for a service
+  with the same name. This is typically meant for services on /odm to override those defined on
+  /vendor. The last service definition that init parses with this keyword is the service definition
+  will use for this service. Pay close attention to the order in which init.rc files are parsed,
+  since it has some peculiarities for backwards compatibility reasons. The 'imports' section of
+  this file has more details on the order.
+
+`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().
+
+`rlimit <resource> <cur> <max>`
+> This applies the given rlimit to the service. rlimits are inherited by child
+  processes, so this effectively applies the given rlimit to the process tree
+  started by this service.
+  It is parsed similarly to the setrlimit command specified below.
+
+`seclabel <seclabel>`
+> Change to 'seclabel' before exec'ing this service.
+  Primarily for use by services run from the rootfs, e.g. ueventd, adbd.
+  Services on the system partition can instead use policy-defined transitions
+  based on their file security context.
+  If not specified and no transition is defined in policy, defaults to the init context.
 
 `setenv <name> <value>`
 > Set the environment variable _name_ to _value_ in the launched process.
 
+`shutdown <shutdown_behavior>`
+> Set shutdown behavior of the service process. When this is not specified,
+  the service is killed during shutdown process by using SIGTERM and SIGKILL.
+  The service with shutdown_behavior of "critical" is not killed during shutdown
+  until shutdown times out. When shutdown times out, even services tagged with
+  "shutdown critical" will be killed. When the service tagged with "shutdown critical"
+  is not running when shut down starts, it will be started.
+
+`sigstop`
+> Send SIGSTOP to the service immediately before exec is called. This is intended for debugging.
+  See the below section on debugging for how this can be used.
+
 `socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]`
 > Create a unix domain socket named /dev/socket/_name_ and pass its fd to the
   launched process.  _type_ must be "dgram", "stream" or "seqpacket".  User and
@@ -187,11 +298,6 @@
   seclabel or computed based on the service executable file security context.
   For native executables see libcutils android\_get\_control\_socket().
 
-`file <path> <type>`
-> Open a file path and pass its fd to the launched process. _type_ must be
-  "r", "w" or "rw".  For native executables see libcutils
-  android\_get\_control\_file().
-
 `user <username>`
 > Change to 'username' before exec'ing this service.
   Currently defaults to root.  (??? probably should default to nobody)
@@ -208,88 +314,12 @@
   As of Android O, processes can also request capabilities directly in their .rc
   files. See the "capabilities" option below.
 
-`group <groupname> [ <groupname>\* ]`
-> Change to 'groupname' before exec'ing this service.  Additional
-  groupnames beyond the (required) first one are used to set the
-  supplemental groups of the process (via setgroups()).
-  Currently defaults to root.  (??? probably should default to nobody)
-
-`capabilities <capability> [ <capability>\* ]`
-> Set capabilities when exec'ing this service. 'capability' should be a Linux
-  capability without the "CAP\_" prefix, like "NET\_ADMIN" or "SETPCAP". See
-  http://man7.org/linux/man-pages/man7/capabilities.7.html for a list of Linux
-  capabilities.
-
-`setrlimit <resource> <cur> <max>`
-> This applies the given rlimit to the service. rlimits are inherited by child
-  processes, so this effectively applies the given rlimit to the process tree
-  started by this service.
-  It is parsed similarly to the setrlimit command specified below.
-
-`seclabel <seclabel>`
-> Change to 'seclabel' before exec'ing this service.
-  Primarily for use by services run from the rootfs, e.g. ueventd, adbd.
-  Services on the system partition can instead use policy-defined transitions
-  based on their file security context.
-  If not specified and no transition is defined in policy, defaults to the init context.
-
-`oneshot`
-> Do not restart the service when it exits.
-
-`class <name> [ <name>\* ]`
-> Specify class names for the service.  All services in a
-  named class may be started or stopped together.  A service
-  is in the class "default" if one is not specified via the
-  class option. Additional classnames beyond the (required) first
-  one are used to group services.
-`animation class`
-> 'animation' class should include all services necessary for both
-  boot animation and shutdown animation. As these services can be
-  launched very early during bootup and can run until the last stage
-  of shutdown, access to /data partition is not guaranteed. These
-  services can check files under /data but it should not keep files opened
-  and should work when /data is not available.
-
-`onrestart`
-> Execute a Command (see below) when service restarts.
-
 `writepid <file> [ <file>\* ]`
 > Write the child's pid to the given files when it forks. Meant for
   cgroup/cpuset usage. If no files under /dev/cpuset/ are specified, but the
   system property 'ro.cpuset.default' is set to a non-empty cpuset name (e.g.
   '/foreground'), then the pid is written to file /dev/cpuset/_cpuset\_name_/tasks.
 
-`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().
-
-`namespace <pid|mnt>`
-> Enter a new PID or mount namespace when forking the service.
-
-`oom_score_adjust <value>`
-> Sets the child's /proc/self/oom\_score\_adj to the specified value,
-  which must range from -1000 to 1000.
-
-`memcg.swappiness <value>`
-> Sets the child's memory.swappiness to the specified value (only if memcg is mounted),
-  which must be equal or greater than 0.
-
-`memcg.soft_limit_in_bytes <value>`
-> Sets the child's memory.soft_limit_in_bytes to the specified value (only if memcg is mounted),
-  which must be equal or greater than 0.
-
-`memcg.limit_in_bytes <value>`
-> Sets the child's memory.limit_in_bytes to the specified value (only if memcg is mounted),
-  which must be equal or greater than 0.
-
-`shutdown <shutdown_behavior>`
-> Set shutdown behavior of the service process. When this is not specified,
-  the service is killed during shutdown process by using SIGTERM and SIGKILL.
-  The service with shutdown_behavior of "critical" is not killed during shutdown
-  until shutdown times out. When shutdown times out, even services tagged with
-  "shutdown critical" will be killed. When the service tagged with "shutdown critical"
-  is not running when shut down starts, it will be started.
-
 
 Triggers
 --------
@@ -686,23 +716,39 @@
 
 Debugging init
 --------------
-By default, programs executed by init will drop stdout and stderr into
-/dev/null. To help with debugging, you can execute your program via the
-Android program logwrapper. This will redirect stdout/stderr into the
-Android logging system (accessed via logcat).
+Launching init services without init is not recommended as init sets up a significant amount of
+environment (user, groups, security label, capabilities, etc) that is hard to replicate manually.
 
-For example
-service akmd /system/bin/logwrapper /sbin/akmd
+If it is required to debug a service from its very start, the `sigstop` service option is added.
+This option will send SIGSTOP to a service immediately before calling exec. This gives a window
+where developers can attach a debugger, strace, etc before continuing the service with SIGCONT.
 
-For quicker turnaround when working on init itself, use:
+This flag can also be dynamically controled via the ctl.sigstop_on and ctl.sigstop_off properties.
 
-    mm -j &&
-    m ramdisk-nodeps &&
-    m bootimage-nodeps &&
-    adb reboot bootloader &&
-    fastboot boot $ANDROID_PRODUCT_OUT/boot.img
+Below is an example of dynamically debugging logd via the above:
 
-Alternatively, use the emulator:
+    stop logd
+    setprop ctl.sigstop_on logd
+    start logd
+    ps -e | grep logd
+    > logd          4343     1   18156   1684 do_signal_stop 538280 T init
+    gdbclient.py -p 4343
+    b main
+    c
+    c
+    c
+    > Breakpoint 1, main (argc=1, argv=0x7ff8c9a488) at system/core/logd/main.cpp:427
 
-    emulator -partition-size 1024 \
-        -verbose -show-kernel -no-window
+Below is an example of doing the same but with strace
+
+    stop logd
+    setprop ctl.sigstop_on logd
+    start logd
+    ps -e | grep logd
+    > logd          4343     1   18156   1684 do_signal_stop 538280 T init
+    strace -p 4343
+
+    (From a different shell)
+    kill -SIGCONT 4343
+
+    > strace runs
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
index 379b4fa..c2cf573 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -32,12 +32,14 @@
 #include <mutex>
 #include <thread>
 
+#include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 
 using android::base::StringPrintf;
+using android::base::boot_clock;
 using namespace std::chrono_literals;
 
 namespace android {
@@ -50,9 +52,9 @@
 static bool g_bootcharting_finished;
 
 static long long get_uptime_jiffies() {
-  std::string uptime;
-  if (!android::base::ReadFileToString("/proc/uptime", &uptime)) return 0;
-  return 100LL * strtod(uptime.c_str(), NULL);
+    constexpr int64_t kNanosecondsPerJiffy = 10000000;
+    boot_clock::time_point uptime = boot_clock::now();
+    return uptime.time_since_epoch().count() / kNanosecondsPerJiffy;
 }
 
 static std::unique_ptr<FILE, decltype(&fclose)> fopen_unique(const char* filename,
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 8bd92cc..17d34e1 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -240,6 +240,29 @@
     return Success();
 }
 
+static Result<Success> do_interface_restart(const BuiltinArguments& args) {
+    Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
+    if (!svc) return Error() << "interface " << args[1] << " not found";
+    svc->Restart();
+    return Success();
+}
+
+static Result<Success> do_interface_start(const BuiltinArguments& args) {
+    Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
+    if (!svc) return Error() << "interface " << args[1] << " not found";
+    if (auto result = svc->Start(); !result) {
+        return Error() << "Could not start interface: " << result.error();
+    }
+    return Success();
+}
+
+static Result<Success> do_interface_stop(const BuiltinArguments& args) {
+    Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
+    if (!svc) return Error() << "interface " << args[1] << " not found";
+    svc->Stop();
+    return Success();
+}
+
 // mkdir <path> [mode] [owner] [group]
 static Result<Success> do_mkdir(const BuiltinArguments& args) {
     mode_t mode = 0755;
@@ -1050,6 +1073,9 @@
         {"init_user0",              {0,     0,    {false,  do_init_user0}}},
         {"insmod",                  {1,     kMax, {true,   do_insmod}}},
         {"installkey",              {1,     1,    {false,  do_installkey}}},
+        {"interface_restart",       {1,     1,    {false,  do_interface_restart}}},
+        {"interface_start",         {1,     1,    {false,  do_interface_start}}},
+        {"interface_stop",          {1,     1,    {false,  do_interface_stop}}},
         {"load_persist_props",      {0,     0,    {false,  do_load_persist_props}}},
         {"load_system_props",       {0,     0,    {false,  do_load_system_props}}},
         {"loglevel",                {1,     1,    {false,  do_loglevel}}},
diff --git a/init/host_init_stubs.h b/init/host_init_stubs.h
index ad48602..bb241af 100644
--- a/init/host_init_stubs.h
+++ b/init/host_init_stubs.h
@@ -35,11 +35,6 @@
 
 std::string GetProperty(const std::string& key, const std::string& default_value);
 bool GetBoolProperty(const std::string& key, bool default_value);
-template <typename T>
-T GetIntProperty(const std::string&, T default_value, T = std::numeric_limits<T>::min(),
-                 T = std::numeric_limits<T>::max()) {
-    return default_value;
-}
 
 }  // namespace base
 }  // namespace android
diff --git a/init/init.cpp b/init/init.cpp
index 4fe115e..645184b 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -31,6 +31,10 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <map>
+#include <memory>
+#include <optional>
+
 #include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
@@ -43,9 +47,6 @@
 #include <private/android_filesystem_config.h>
 #include <selinux/android.h>
 
-#include <memory>
-#include <optional>
-
 #include "action_parser.h"
 #include "import_parser.h"
 #include "init_first_stage.h"
@@ -79,7 +80,7 @@
 std::string default_console = "/dev/console";
 
 static int epoll_fd = -1;
-static int sigterm_signal_fd = -1;
+static int signal_fd = -1;
 
 static std::unique_ptr<Timer> waiting_for_prop(nullptr);
 static std::string wait_prop_name;
@@ -130,12 +131,31 @@
     }
 }
 
-void register_epoll_handler(int fd, void (*fn)()) {
+static std::map<int, std::function<void()>> epoll_handlers;
+
+void register_epoll_handler(int fd, std::function<void()> handler) {
+    auto[it, inserted] = epoll_handlers.emplace(fd, std::move(handler));
+    if (!inserted) {
+        LOG(ERROR) << "Cannot specify two epoll handlers for a given FD";
+        return;
+    }
     epoll_event ev;
     ev.events = EPOLLIN;
-    ev.data.ptr = reinterpret_cast<void*>(fn);
+    // 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);
     if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
-        PLOG(ERROR) << "epoll_ctl failed";
+        PLOG(ERROR) << "epoll_ctl failed to add fd";
+        epoll_handlers.erase(fd);
+    }
+}
+
+void unregister_epoll_handler(int fd) {
+    if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, nullptr) == -1) {
+        PLOG(ERROR) << "epoll_ctl failed to remove fd";
+    }
+    if (epoll_handlers.erase(fd) != 1) {
+        LOG(ERROR) << "Attempting to remove epoll handler for FD without an existing handler";
     }
 }
 
@@ -238,6 +258,10 @@
 static const std::map<std::string, ControlMessageFunction>& get_control_message_map() {
     // clang-format off
     static const std::map<std::string, ControlMessageFunction> control_message_functions = {
+        {"sigstop_on",        {ControlTarget::SERVICE,
+                               [](auto* service) { service->set_sigstop(true); return Success(); }}},
+        {"sigstop_off",       {ControlTarget::SERVICE,
+                               [](auto* service) { service->set_sigstop(false); return Success(); }}},
         {"start",             {ControlTarget::SERVICE,   DoControlStart}},
         {"stop",              {ControlTarget::SERVICE,   DoControlStop}},
         {"restart",           {ControlTarget::SERVICE,   DoControlRestart}},
@@ -273,40 +297,29 @@
 
     const ControlMessageFunction& function = it->second;
 
-    if (function.target == ControlTarget::SERVICE) {
-        Service* svc = ServiceList::GetInstance().FindService(name);
-        if (svc == nullptr) {
-            LOG(ERROR) << "No such service '" << name << "' for ctl." << msg;
-            return;
-        }
-        if (auto result = function.action(svc); !result) {
-            LOG(ERROR) << "Could not ctl." << msg << " for service " << name << ": "
-                       << result.error();
-        }
+    Service* svc = nullptr;
 
+    switch (function.target) {
+        case ControlTarget::SERVICE:
+            svc = ServiceList::GetInstance().FindService(name);
+            break;
+        case ControlTarget::INTERFACE:
+            svc = ServiceList::GetInstance().FindInterface(name);
+            break;
+        default:
+            LOG(ERROR) << "Invalid function target from static map key '" << msg << "': "
+                       << static_cast<std::underlying_type<ControlTarget>::type>(function.target);
+            return;
+    }
+
+    if (svc == nullptr) {
+        LOG(ERROR) << "Could not find '" << name << "' for ctl." << msg;
         return;
     }
 
-    if (function.target == ControlTarget::INTERFACE) {
-        for (const auto& svc : ServiceList::GetInstance()) {
-            if (svc->interfaces().count(name) == 0) {
-                continue;
-            }
-
-            if (auto result = function.action(svc.get()); !result) {
-                LOG(ERROR) << "Could not handle ctl." << msg << " for service " << svc->name()
-                           << " with interface " << name << ": " << result.error();
-            }
-
-            return;
-        }
-
-        LOG(ERROR) << "Could not find service hosting interface " << name;
-        return;
+    if (auto result = function.action(svc); !result) {
+        LOG(ERROR) << "Could not ctl." << msg << " for '" << name << "': " << result.error();
     }
-
-    LOG(ERROR) << "Invalid function target from static map key '" << msg
-               << "': " << static_cast<std::underlying_type<ControlTarget>::type>(function.target);
 }
 
 static Result<Success> wait_for_coldboot_done_action(const BuiltinArguments& args) {
@@ -330,8 +343,8 @@
     return Success();
 }
 
-static Result<Success> keychord_init_action(const BuiltinArguments& args) {
-    keychord_init();
+static Result<Success> KeychordInitAction(const BuiltinArguments& args) {
+    KeychordInit();
     return Success();
 }
 
@@ -492,14 +505,7 @@
     sigaction(SIGTRAP, &action, nullptr);
 }
 
-static void HandleSigtermSignal() {
-    signalfd_siginfo siginfo;
-    ssize_t bytes_read = TEMP_FAILURE_RETRY(read(sigterm_signal_fd, &siginfo, sizeof(siginfo)));
-    if (bytes_read != sizeof(siginfo)) {
-        PLOG(ERROR) << "Failed to read siginfo from sigterm_signal_fd";
-        return;
-    }
-
+static void HandleSigtermSignal(const signalfd_siginfo& siginfo) {
     if (siginfo.ssi_pid != 0) {
         // Drop any userspace SIGTERM requests.
         LOG(DEBUG) << "Ignoring SIGTERM from pid " << siginfo.ssi_pid;
@@ -509,37 +515,73 @@
     HandlePowerctlMessage("shutdown,container");
 }
 
-static void UnblockSigterm() {
-    sigset_t mask;
-    sigemptyset(&mask);
-    sigaddset(&mask, SIGTERM);
+static void HandleSignalFd() {
+    signalfd_siginfo siginfo;
+    ssize_t bytes_read = TEMP_FAILURE_RETRY(read(signal_fd, &siginfo, sizeof(siginfo)));
+    if (bytes_read != sizeof(siginfo)) {
+        PLOG(ERROR) << "Failed to read siginfo from signal_fd";
+        return;
+    }
 
-    if (sigprocmask(SIG_UNBLOCK, &mask, nullptr) == -1) {
-        PLOG(FATAL) << "failed to unblock SIGTERM for PID " << getpid();
+    switch (siginfo.ssi_signo) {
+        case SIGCHLD:
+            ReapAnyOutstandingChildren();
+            break;
+        case SIGTERM:
+            HandleSigtermSignal(siginfo);
+            break;
+        default:
+            PLOG(ERROR) << "signal_fd: received unexpected signal " << siginfo.ssi_signo;
+            break;
     }
 }
 
-static void InstallSigtermHandler() {
+static void UnblockSignals() {
+    const struct sigaction act { .sa_handler = SIG_DFL };
+    sigaction(SIGCHLD, &act, nullptr);
+
     sigset_t mask;
     sigemptyset(&mask);
+    sigaddset(&mask, SIGCHLD);
     sigaddset(&mask, SIGTERM);
 
-    if (sigprocmask(SIG_BLOCK, &mask, nullptr) == -1) {
-        PLOG(FATAL) << "failed to block SIGTERM";
+    if (sigprocmask(SIG_UNBLOCK, &mask, nullptr) == -1) {
+        PLOG(FATAL) << "failed to unblock signals for PID " << getpid();
+    }
+}
+
+static void InstallSignalFdHandler() {
+    // Applying SA_NOCLDSTOP to a defaulted SIGCHLD handler prevents the signalfd from receiving
+    // SIGCHLD when a child process stops or continues (b/77867680#comment9).
+    const struct sigaction act { .sa_handler = SIG_DFL, .sa_flags = SA_NOCLDSTOP };
+    sigaction(SIGCHLD, &act, nullptr);
+
+    sigset_t mask;
+    sigemptyset(&mask);
+    sigaddset(&mask, SIGCHLD);
+
+    if (!IsRebootCapable()) {
+        // If init does not have the CAP_SYS_BOOT capability, it is running in a container.
+        // In that case, receiving SIGTERM will cause the system to shut down.
+        sigaddset(&mask, SIGTERM);
     }
 
-    // Register a handler to unblock SIGTERM in the child processes.
-    const int result = pthread_atfork(nullptr, nullptr, &UnblockSigterm);
+    if (sigprocmask(SIG_BLOCK, &mask, nullptr) == -1) {
+        PLOG(FATAL) << "failed to block signals";
+    }
+
+    // Register a handler to unblock signals in the child processes.
+    const int result = pthread_atfork(nullptr, nullptr, &UnblockSignals);
     if (result != 0) {
         LOG(FATAL) << "Failed to register a fork handler: " << strerror(result);
     }
 
-    sigterm_signal_fd = signalfd(-1, &mask, SFD_CLOEXEC);
-    if (sigterm_signal_fd == -1) {
-        PLOG(FATAL) << "failed to create signalfd for SIGTERM";
+    signal_fd = signalfd(-1, &mask, SFD_CLOEXEC);
+    if (signal_fd == -1) {
+        PLOG(FATAL) << "failed to create signalfd";
     }
 
-    register_epoll_handler(sigterm_signal_fd, HandleSigtermSignal);
+    register_epoll_handler(signal_fd, HandleSignalFd);
 }
 
 int main(int argc, char** argv) {
@@ -690,13 +732,7 @@
         PLOG(FATAL) << "epoll_create1 failed";
     }
 
-    sigchld_handler_init();
-
-    if (!IsRebootCapable()) {
-        // If init does not have the CAP_SYS_BOOT capability, it is running in a container.
-        // In that case, receiving SIGTERM will cause the system to shut down.
-        InstallSigtermHandler();
-    }
+    InstallSignalFdHandler();
 
     property_load_boot_defaults();
     export_oem_lock_status();
@@ -725,7 +761,7 @@
     am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
     am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
     am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
-    am.QueueBuiltinAction(keychord_init_action, "keychord_init");
+    am.QueueBuiltinAction(KeychordInitAction, "KeychordInit");
     am.QueueBuiltinAction(console_init_action, "console_init");
 
     // Trigger all the boot actions to get us started.
@@ -782,7 +818,7 @@
         if (nr == -1) {
             PLOG(ERROR) << "epoll_wait failed";
         } else if (nr == 1) {
-            ((void (*)()) ev.data.ptr)();
+            std::invoke(*reinterpret_cast<std::function<void()>*>(ev.data.ptr));
         }
     }
 
diff --git a/init/init.h b/init/init.h
index d4a0e96..e7c4d8d 100644
--- a/init/init.h
+++ b/init/init.h
@@ -19,6 +19,7 @@
 
 #include <sys/types.h>
 
+#include <functional>
 #include <string>
 #include <vector>
 
@@ -42,7 +43,8 @@
 
 void property_changed(const std::string& name, const std::string& value);
 
-void register_epoll_handler(int fd, void (*fn)());
+void register_epoll_handler(int fd, std::function<void()> handler);
+void unregister_epoll_handler(int fd);
 
 bool start_waiting_for_property(const char *name, const char *value);
 
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index 033ce41..34de640 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -33,11 +33,13 @@
 #include "devices.h"
 #include "fs_mgr.h"
 #include "fs_mgr_avb.h"
+#include "fs_mgr_dm_linear.h"
 #include "uevent.h"
 #include "uevent_listener.h"
 #include "util.h"
 
 using android::base::Timer;
+using android::fs_mgr::LogicalPartitionTable;
 
 namespace android {
 namespace init {
@@ -58,18 +60,21 @@
   protected:
     ListenerAction HandleBlockDevice(const std::string& name, const Uevent&);
     bool InitRequiredDevices();
-    bool InitVerityDevice(const std::string& verity_device);
+    bool InitMappedDevice(const std::string& verity_device);
+    bool CreateLogicalPartitions();
     bool MountPartitions();
+    bool GetBackingDmLinearDevices();
 
     virtual ListenerAction UeventCallback(const Uevent& uevent);
 
     // Pure virtual functions.
-    virtual bool GetRequiredDevices() = 0;
+    virtual bool GetDmVerityDevices() = 0;
     virtual bool SetUpDmVerity(fstab_rec* fstab_rec) = 0;
 
     bool need_dm_verity_;
 
     std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> device_tree_fstab_;
+    std::unique_ptr<LogicalPartitionTable> dm_linear_table_;
     std::vector<fstab_rec*> mount_fstab_recs_;
     std::set<std::string> required_devices_partition_names_;
     std::unique_ptr<DeviceHandler> device_handler_;
@@ -82,7 +87,7 @@
     ~FirstStageMountVBootV1() override = default;
 
   protected:
-    bool GetRequiredDevices() override;
+    bool GetDmVerityDevices() override;
     bool SetUpDmVerity(fstab_rec* fstab_rec) override;
 };
 
@@ -95,7 +100,7 @@
 
   protected:
     ListenerAction UeventCallback(const Uevent& uevent) override;
-    bool GetRequiredDevices() override;
+    bool GetDmVerityDevices() override;
     bool SetUpDmVerity(fstab_rec* fstab_rec) override;
     bool InitAvbHandle();
 
@@ -114,18 +119,33 @@
     return access("/sbin/recovery", F_OK) == 0;
 }
 
+static inline bool IsDmLinearEnabled() {
+    bool enabled = false;
+    import_kernel_cmdline(
+        false, [&enabled](const std::string& key, const std::string& value, bool in_qemu) {
+            if (key == "androidboot.lrap" && value == "1") {
+                enabled = true;
+            }
+        });
+    return enabled;
+}
+
 // Class Definitions
 // -----------------
 FirstStageMount::FirstStageMount()
     : need_dm_verity_(false), device_tree_fstab_(fs_mgr_read_fstab_dt(), fs_mgr_free_fstab) {
-    if (!device_tree_fstab_) {
+    if (device_tree_fstab_) {
+        // Stores device_tree_fstab_->recs[] into mount_fstab_recs_ (vector<fstab_rec*>)
+        // for easier manipulation later, e.g., range-base for loop.
+        for (int i = 0; i < device_tree_fstab_->num_entries; i++) {
+            mount_fstab_recs_.push_back(&device_tree_fstab_->recs[i]);
+        }
+    } else {
         LOG(INFO) << "Failed to read fstab from device tree";
-        return;
     }
-    // Stores device_tree_fstab_->recs[] into mount_fstab_recs_ (vector<fstab_rec*>)
-    // for easier manipulation later, e.g., range-base for loop.
-    for (int i = 0; i < device_tree_fstab_->num_entries; i++) {
-        mount_fstab_recs_.push_back(&device_tree_fstab_->recs[i]);
+
+    if (IsDmLinearEnabled()) {
+        dm_linear_table_ = android::fs_mgr::LoadPartitionsFromDeviceTree();
     }
 
     auto boot_devices = fs_mgr_get_boot_devices();
@@ -143,18 +163,38 @@
 }
 
 bool FirstStageMount::DoFirstStageMount() {
-    // Nothing to mount.
-    if (mount_fstab_recs_.empty()) return true;
+    if (!dm_linear_table_ && mount_fstab_recs_.empty()) {
+        // Nothing to mount.
+        LOG(INFO) << "First stage mount skipped (missing/incompatible/empty fstab in device tree)";
+        return true;
+    }
 
     if (!InitDevices()) return false;
 
+    if (!CreateLogicalPartitions()) return false;
+
     if (!MountPartitions()) return false;
 
     return true;
 }
 
 bool FirstStageMount::InitDevices() {
-    return GetRequiredDevices() && InitRequiredDevices();
+    return GetBackingDmLinearDevices() && GetDmVerityDevices() && InitRequiredDevices();
+}
+
+bool FirstStageMount::GetBackingDmLinearDevices() {
+    // Add any additional devices required for dm-linear mappings.
+    if (!dm_linear_table_) {
+        return true;
+    }
+
+    for (const auto& partition : dm_linear_table_->partitions) {
+        for (const auto& extent : partition.extents) {
+            const std::string& partition_name = android::base::Basename(extent.block_device());
+            required_devices_partition_names_.emplace(partition_name);
+        }
+    }
+    return true;
 }
 
 // Creates devices with uevent->partition_name matching one in the member variable
@@ -165,7 +205,7 @@
         return true;
     }
 
-    if (need_dm_verity_) {
+    if (dm_linear_table_ || 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) {
@@ -212,6 +252,13 @@
     return true;
 }
 
+bool FirstStageMount::CreateLogicalPartitions() {
+    if (!dm_linear_table_) {
+        return true;
+    }
+    return android::fs_mgr::CreateLogicalPartitions(*dm_linear_table_.get());
+}
+
 ListenerAction FirstStageMount::HandleBlockDevice(const std::string& name, const Uevent& uevent) {
     // Matches partition name to create device nodes.
     // Both required_devices_partition_names_ and uevent->partition_name have A/B
@@ -249,14 +296,14 @@
 }
 
 // Creates "/dev/block/dm-XX" for dm-verity by running coldboot on /sys/block/dm-XX.
-bool FirstStageMount::InitVerityDevice(const std::string& verity_device) {
-    const std::string device_name(basename(verity_device.c_str()));
+bool FirstStageMount::InitMappedDevice(const std::string& dm_device) {
+    const std::string device_name(basename(dm_device.c_str()));
     const std::string syspath = "/sys/block/" + device_name;
     bool found = false;
 
-    auto verity_callback = [&device_name, &verity_device, this, &found](const Uevent& uevent) {
+    auto verity_callback = [&device_name, &dm_device, this, &found](const Uevent& uevent) {
         if (uevent.device_name == device_name) {
-            LOG(VERBOSE) << "Creating dm-verity device : " << verity_device;
+            LOG(VERBOSE) << "Creating device-mapper device : " << dm_device;
             device_handler_->HandleDeviceEvent(uevent);
             found = true;
             return ListenerAction::kStop;
@@ -281,6 +328,14 @@
 
 bool FirstStageMount::MountPartitions() {
     for (auto fstab_rec : mount_fstab_recs_) {
+        if (fs_mgr_is_logical(fstab_rec)) {
+            if (!fs_mgr_update_logical_partition(fstab_rec)) {
+                return false;
+            }
+            if (!InitMappedDevice(fstab_rec->blk_device)) {
+                return false;
+            }
+        }
         if (!SetUpDmVerity(fstab_rec)) {
             PLOG(ERROR) << "Failed to setup verity for '" << fstab_rec->mount_point << "'";
             return false;
@@ -293,7 +348,7 @@
     return true;
 }
 
-bool FirstStageMountVBootV1::GetRequiredDevices() {
+bool FirstStageMountVBootV1::GetDmVerityDevices() {
     std::string verity_loc_device;
     need_dm_verity_ = false;
 
@@ -346,7 +401,7 @@
                 // The exact block device name (fstab_rec->blk_device) is changed to
                 // "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
                 // first stage.
-                return InitVerityDevice(fstab_rec->blk_device);
+                return InitMappedDevice(fstab_rec->blk_device);
             default:
                 return false;
         }
@@ -373,7 +428,7 @@
     }
 }
 
-bool FirstStageMountVBootV2::GetRequiredDevices() {
+bool FirstStageMountVBootV2::GetDmVerityDevices() {
     need_dm_verity_ = false;
 
     // fstab_rec->blk_device has A/B suffix.
@@ -445,7 +500,7 @@
                 // The exact block device name (fstab_rec->blk_device) is changed to
                 // "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
                 // first stage.
-                return InitVerityDevice(fstab_rec->blk_device);
+                return InitMappedDevice(fstab_rec->blk_device);
             default:
                 return false;
         }
@@ -483,12 +538,6 @@
         return true;
     }
 
-    // Firstly checks if device tree fstab entries are compatible.
-    if (!is_android_dt_value_expected("fstab/compatible", "android,fstab")) {
-        LOG(INFO) << "First stage mount skipped (missing/incompatible fstab in device tree)";
-        return true;
-    }
-
     std::unique_ptr<FirstStageMount> handle = FirstStageMount::Create();
     if (!handle) {
         LOG(ERROR) << "Failed to create FirstStageMount";
diff --git a/init/keychords.cpp b/init/keychords.cpp
index e686ce1..293736d 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -16,13 +16,22 @@
 
 #include "keychords.h"
 
+#include <dirent.h>
 #include <fcntl.h>
-#include <stdlib.h>
-#include <sys/stat.h>
+#include <linux/input.h>
+#include <sys/cdefs.h>
+#include <sys/inotify.h>
+#include <sys/ioctl.h>
 #include <sys/types.h>
-#include <linux/keychord.h>
 #include <unistd.h>
 
+#include <algorithm>
+#include <functional>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
 #include <android-base/logging.h>
 #include <android-base/properties.h>
 
@@ -31,51 +40,89 @@
 namespace android {
 namespace init {
 
-static struct input_keychord *keychords = 0;
-static int keychords_count = 0;
-static int keychords_length = 0;
-static int keychord_fd = -1;
+namespace {
 
-void add_service_keycodes(Service* svc)
-{
-    struct input_keychord *keychord;
-    size_t i, size;
+int keychords_count;
 
-    if (!svc->keycodes().empty()) {
-        /* add a new keychord to the list */
-        size = sizeof(*keychord) + svc->keycodes().size() * sizeof(keychord->keycodes[0]);
-        keychords = (input_keychord*) realloc(keychords, keychords_length + size);
-        if (!keychords) {
-            PLOG(ERROR) << "could not allocate keychords";
-            keychords_length = 0;
-            keychords_count = 0;
-            return;
+struct KeychordEntry {
+    const std::vector<int> keycodes;
+    bool notified;
+    int id;
+
+    KeychordEntry(const std::vector<int>& keycodes, int id)
+        : keycodes(keycodes), notified(false), id(id) {}
+};
+
+std::vector<KeychordEntry> keychord_entries;
+
+// Bit management
+class KeychordMask {
+  private:
+    typedef unsigned int mask_t;
+    std::vector<mask_t> bits;
+    static constexpr size_t bits_per_byte = 8;
+
+  public:
+    explicit KeychordMask(size_t bit = 0) : bits((bit + sizeof(mask_t) - 1) / sizeof(mask_t), 0) {}
+
+    void SetBit(size_t bit, bool value = true) {
+        auto idx = bit / (bits_per_byte * sizeof(mask_t));
+        if (idx >= bits.size()) return;
+        if (value) {
+            bits[idx] |= mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t)));
+        } else {
+            bits[idx] &= ~(mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t))));
         }
-
-        keychord = (struct input_keychord *)((char *)keychords + keychords_length);
-        keychord->version = KEYCHORD_VERSION;
-        keychord->id = keychords_count + 1;
-        keychord->count = svc->keycodes().size();
-        svc->set_keychord_id(keychord->id);
-
-        for (i = 0; i < svc->keycodes().size(); i++) {
-            keychord->keycodes[i] = svc->keycodes()[i];
-        }
-        keychords_count++;
-        keychords_length += size;
-    }
-}
-
-static void handle_keychord() {
-    int ret;
-    __u16 id;
-
-    ret = read(keychord_fd, &id, sizeof(id));
-    if (ret != sizeof(id)) {
-        PLOG(ERROR) << "could not read keychord id";
-        return;
     }
 
+    bool GetBit(size_t bit) const {
+        auto idx = bit / (bits_per_byte * sizeof(mask_t));
+        return bits[idx] & (mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t))));
+    }
+
+    size_t bytesize() const { return bits.size() * sizeof(mask_t); }
+    void* data() { return bits.data(); }
+    size_t size() const { return bits.size() * sizeof(mask_t) * bits_per_byte; }
+    void resize(size_t bit) {
+        auto idx = bit / (bits_per_byte * sizeof(mask_t));
+        if (idx >= bits.size()) {
+            bits.resize(idx + 1, 0);
+        }
+    }
+
+    operator bool() const {
+        for (size_t i = 0; i < bits.size(); ++i) {
+            if (bits[i]) return true;
+        }
+        return false;
+    }
+
+    KeychordMask operator&(const KeychordMask& rval) const {
+        auto len = std::min(bits.size(), rval.bits.size());
+        KeychordMask ret;
+        ret.bits.resize(len);
+        for (size_t i = 0; i < len; ++i) {
+            ret.bits[i] = bits[i] & rval.bits[i];
+        }
+        return ret;
+    }
+
+    void operator|=(const KeychordMask& rval) {
+        size_t len = rval.bits.size();
+        bits.resize(len);
+        for (size_t i = 0; i < len; ++i) {
+            bits[i] |= rval.bits[i];
+        }
+    }
+};
+
+KeychordMask keychord_current;
+
+constexpr char kDevicePath[] = "/dev/input";
+
+std::map<std::string, int> keychord_registration;
+
+void HandleKeychord(int id) {
     // Only handle keychords if adb is enabled.
     std::string adb_enabled = android::base::GetProperty("init.svc.adbd", "");
     if (adb_enabled == "running") {
@@ -94,32 +141,179 @@
     }
 }
 
-void keychord_init() {
+void KeychordLambdaCheck() {
+    for (auto& e : keychord_entries) {
+        bool found = true;
+        for (auto& code : e.keycodes) {
+            if (!keychord_current.GetBit(code)) {
+                e.notified = false;
+                found = false;
+                break;
+            }
+        }
+        if (!found) continue;
+        if (e.notified) continue;
+        e.notified = true;
+        HandleKeychord(e.id);
+    }
+}
+
+void KeychordLambdaHandler(int fd) {
+    input_event event;
+    auto res = TEMP_FAILURE_RETRY(::read(fd, &event, sizeof(event)));
+    if ((res != sizeof(event)) || (event.type != EV_KEY)) return;
+    keychord_current.SetBit(event.code, event.value);
+    KeychordLambdaCheck();
+}
+
+bool KeychordGeteventEnable(int fd) {
+    static bool EviocsmaskSupported = true;
+
+    // Make sure it is an event channel, should pass this ioctl call
+    int version;
+    if (::ioctl(fd, EVIOCGVERSION, &version)) return false;
+
+    if (EviocsmaskSupported) {
+        KeychordMask mask(EV_KEY);
+        mask.SetBit(EV_KEY);
+        input_mask msg = {};
+        msg.type = EV_SYN;
+        msg.codes_size = mask.bytesize();
+        msg.codes_ptr = reinterpret_cast<uintptr_t>(mask.data());
+        if (::ioctl(fd, EVIOCSMASK, &msg) == -1) {
+            PLOG(WARNING) << "EVIOCSMASK not supported";
+            EviocsmaskSupported = false;
+        }
+    }
+
+    KeychordMask mask;
+    for (auto& e : keychord_entries) {
+        for (auto& code : e.keycodes) {
+            mask.resize(code);
+            mask.SetBit(code);
+        }
+    }
+
+    keychord_current.resize(mask.size());
+    KeychordMask available(mask.size());
+    auto res = ::ioctl(fd, EVIOCGBIT(EV_KEY, available.bytesize()), available.data());
+    if (res == -1) return false;
+    if (!(available & mask)) return false;
+
+    if (EviocsmaskSupported) {
+        input_mask msg = {};
+        msg.type = EV_KEY;
+        msg.codes_size = mask.bytesize();
+        msg.codes_ptr = reinterpret_cast<uintptr_t>(mask.data());
+        ::ioctl(fd, EVIOCSMASK, &msg);
+    }
+
+    KeychordMask set(mask.size());
+    res = ::ioctl(fd, EVIOCGKEY(res), set.data());
+    if (res > 0) {
+        keychord_current |= mask & available & set;
+        KeychordLambdaCheck();
+    }
+    register_epoll_handler(fd, [fd]() { KeychordLambdaHandler(fd); });
+    return true;
+}
+
+void GeteventOpenDevice(const std::string& device) {
+    if (keychord_registration.count(device)) return;
+    auto fd = TEMP_FAILURE_RETRY(::open(device.c_str(), O_RDWR | O_CLOEXEC));
+    if (fd == -1) {
+        PLOG(ERROR) << "Can not open " << device;
+        return;
+    }
+    if (!KeychordGeteventEnable(fd)) {
+        ::close(fd);
+    } else {
+        keychord_registration.emplace(device, fd);
+    }
+}
+
+void GeteventCloseDevice(const std::string& device) {
+    auto it = keychord_registration.find(device);
+    if (it == keychord_registration.end()) return;
+    auto fd = (*it).second;
+    unregister_epoll_handler(fd);
+    keychord_registration.erase(it);
+    ::close(fd);
+}
+
+int inotify_fd = -1;
+
+void InotifyHandler() {
+    unsigned char buf[512];
+
+    auto res = TEMP_FAILURE_RETRY(::read(inotify_fd, buf, sizeof(buf)));
+    if (res < 0) {
+        PLOG(WARNING) << "could not get event";
+        return;
+    }
+
+    auto event_buf = buf;
+    while (static_cast<size_t>(res) >= sizeof(inotify_event)) {
+        auto event = reinterpret_cast<inotify_event*>(event_buf);
+        auto event_size = sizeof(inotify_event) + event->len;
+        if (static_cast<size_t>(res) < event_size) break;
+        if (event->len) {
+            std::string devname(kDevicePath);
+            devname += '/';
+            devname += event->name;
+            if (event->mask & IN_CREATE) {
+                GeteventOpenDevice(devname);
+            } else {
+                GeteventCloseDevice(devname);
+            }
+        }
+        res -= event_size;
+        event_buf += event_size;
+    }
+}
+
+void GeteventOpenDevice() {
+    inotify_fd = ::inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
+    if (inotify_fd < 0) {
+        PLOG(WARNING) << "Could not instantiate inotify for " << kDevicePath;
+    } else if (::inotify_add_watch(inotify_fd, kDevicePath, IN_DELETE | IN_CREATE | IN_ONLYDIR) < 0) {
+        PLOG(WARNING) << "Could not add watch for " << kDevicePath;
+        ::close(inotify_fd);
+        inotify_fd = -1;
+    }
+
+    std::unique_ptr<DIR, decltype(&closedir)> device(opendir(kDevicePath), closedir);
+    if (device) {
+        dirent* entry;
+        while ((entry = readdir(device.get()))) {
+            if (entry->d_name[0] == '.') continue;
+            std::string devname(kDevicePath);
+            devname += '/';
+            devname += entry->d_name;
+            GeteventOpenDevice(devname);
+        }
+    }
+
+    if (inotify_fd >= 0) register_epoll_handler(inotify_fd, InotifyHandler);
+}
+
+void AddServiceKeycodes(Service* svc) {
+    if (svc->keycodes().empty()) return;
+    for (auto& code : svc->keycodes()) {
+        if ((code < 0) || (code >= KEY_MAX)) return;
+    }
+    ++keychords_count;
+    keychord_entries.emplace_back(KeychordEntry(svc->keycodes(), keychords_count));
+    svc->set_keychord_id(keychords_count);
+}
+
+}  // namespace
+
+void KeychordInit() {
     for (const auto& service : ServiceList::GetInstance()) {
-        add_service_keycodes(service.get());
+        AddServiceKeycodes(service.get());
     }
-
-    // Nothing to do if no services require keychords.
-    if (!keychords) {
-        return;
-    }
-
-    keychord_fd = TEMP_FAILURE_RETRY(open("/dev/keychord", O_RDWR | O_CLOEXEC));
-    if (keychord_fd == -1) {
-        PLOG(ERROR) << "could not open /dev/keychord";
-        return;
-    }
-
-    int ret = write(keychord_fd, keychords, keychords_length);
-    if (ret != keychords_length) {
-        PLOG(ERROR) << "could not configure /dev/keychord " << ret;
-        close(keychord_fd);
-    }
-
-    free(keychords);
-    keychords = nullptr;
-
-    register_epoll_handler(keychord_fd, handle_keychord);
+    if (keychords_count) GeteventOpenDevice();
 }
 
 }  // namespace init
diff --git a/init/keychords.h b/init/keychords.h
index 1c34098..689a3b5 100644
--- a/init/keychords.h
+++ b/init/keychords.h
@@ -22,8 +22,7 @@
 namespace android {
 namespace init {
 
-void add_service_keycodes(Service* svc);
-void keychord_init();
+void KeychordInit();
 
 }  // namespace init
 }  // namespace android
diff --git a/init/property_service.cpp b/init/property_service.cpp
index c3100a5..47e45ef 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -65,7 +65,6 @@
 
 using namespace std::literals;
 
-using android::base::GetIntProperty;
 using android::base::ReadFileToString;
 using android::base::Split;
 using android::base::StartsWith;
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 328164f..6f6e39f 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -458,10 +458,20 @@
         if (kill_after_apps.count(s->name())) s->Stop();
     }
     // 4. sync, try umount, and optionally run fsck for user shutdown
-    sync();
+    {
+        Timer sync_timer;
+        LOG(INFO) << "sync() before umount...";
+        sync();
+        LOG(INFO) << "sync() before umount took" << sync_timer;
+    }
     UmountStat stat = TryUmountAndFsck(runFsck, shutdown_timeout - t.duration());
     // Follow what linux shutdown is doing: one more sync with little bit delay
-    sync();
+    {
+        Timer sync_timer;
+        LOG(INFO) << "sync() after umount...";
+        sync();
+        LOG(INFO) << "sync() after umount took" << sync_timer;
+    }
     if (!is_thermal_shutdown) std::this_thread::sleep_for(100ms);
     LogShutdownTime(stat, &t);
     // Reboot regardless of umount status. If umount fails, fsck after reboot will fix it.
diff --git a/init/service.cpp b/init/service.cpp
index 09d8dae..0e08d9b 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -34,6 +34,7 @@
 #include <android-base/parseint.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <android-base/unique_fd.h>
 #include <hidl-util/FQName.h>
 #include <processgroup/processgroup.h>
 #include <selinux/selinux.h>
@@ -59,13 +60,13 @@
 using android::base::ParseInt;
 using android::base::StartsWith;
 using android::base::StringPrintf;
+using android::base::unique_fd;
 using android::base::WriteStringToFile;
 
 namespace android {
 namespace init {
 
-static Result<std::string> ComputeContextFromExecutable(std::string& service_name,
-                                                        const std::string& service_path) {
+static Result<std::string> ComputeContextFromExecutable(const std::string& service_path) {
     std::string computed_context;
 
     char* raw_con = nullptr;
@@ -101,36 +102,49 @@
     return computed_context;
 }
 
-static void SetUpPidNamespace(const std::string& service_name) {
+Result<Success> Service::SetUpMountNamespace() const {
     constexpr unsigned int kSafeFlags = MS_NODEV | MS_NOEXEC | MS_NOSUID;
 
-    // It's OK to LOG(FATAL) in this function since it's running in the first
-    // child process.
-
     // Recursively remount / as slave like zygote does so unmounting and mounting /proc
     // doesn't interfere with the parent namespace's /proc mount. This will also
     // prevent any other mounts/unmounts initiated by the service from interfering
     // with the parent namespace but will still allow mount events from the parent
     // namespace to propagate to the child.
     if (mount("rootfs", "/", nullptr, (MS_SLAVE | MS_REC), nullptr) == -1) {
-        PLOG(FATAL) << "couldn't remount(/) recursively as slave for " << service_name;
-    }
-    // umount() then mount() /proc.
-    // Note that it is not sufficient to mount with MS_REMOUNT.
-    if (umount("/proc") == -1) {
-        PLOG(FATAL) << "couldn't umount(/proc) for " << service_name;
-    }
-    if (mount("", "/proc", "proc", kSafeFlags, "") == -1) {
-        PLOG(FATAL) << "couldn't mount(/proc) for " << service_name;
+        return ErrnoError() << "Could not remount(/) recursively as slave";
     }
 
-    if (prctl(PR_SET_NAME, service_name.c_str()) == -1) {
-        PLOG(FATAL) << "couldn't set name for " << service_name;
+    // umount() then mount() /proc and/or /sys
+    // Note that it is not sufficient to mount with MS_REMOUNT.
+    if (namespace_flags_ & CLONE_NEWPID) {
+        if (umount("/proc") == -1) {
+            return ErrnoError() << "Could not umount(/proc)";
+        }
+        if (mount("", "/proc", "proc", kSafeFlags, "") == -1) {
+            return ErrnoError() << "Could not mount(/proc)";
+        }
+    }
+    bool remount_sys = std::any_of(namespaces_to_enter_.begin(), namespaces_to_enter_.end(),
+                                   [](const auto& entry) { return entry.first == CLONE_NEWNET; });
+    if (remount_sys) {
+        if (umount2("/sys", MNT_DETACH) == -1) {
+            return ErrnoError() << "Could not umount(/sys)";
+        }
+        if (mount("", "/sys", "sys", kSafeFlags, "") == -1) {
+            return ErrnoError() << "Could not mount(/sys)";
+        }
+    }
+    return Success();
+}
+
+Result<Success> Service::SetUpPidNamespace() const {
+    if (prctl(PR_SET_NAME, name_.c_str()) == -1) {
+        return ErrnoError() << "Could not set name";
     }
 
     pid_t child_pid = fork();
     if (child_pid == -1) {
-        PLOG(FATAL) << "couldn't fork init inside the PID namespace for " << service_name;
+        return ErrnoError() << "Could not fork init inside the PID namespace";
     }
 
     if (child_pid > 0) {
@@ -153,9 +167,23 @@
         }
         _exit(WEXITSTATUS(init_exitstatus));
     }
+    return Success();
 }
 
-static bool ExpandArgsAndExecv(const std::vector<std::string>& args) {
+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) {
+            return ErrnoError() << "Could not open namespace at " << path;
+        }
+        if (setns(fd, nstype) == -1) {
+            return ErrnoError() << "Could not setns() namespace at " << path;
+        }
+    }
+    return Success();
+}
+
+static bool ExpandArgsAndExecv(const std::vector<std::string>& args, bool sigstop) {
     std::vector<std::string> expanded_args;
     std::vector<char*> c_strings;
 
@@ -169,6 +197,10 @@
     }
     c_strings.push_back(nullptr);
 
+    if (sigstop) {
+        kill(getpid(), SIGSTOP);
+    }
+
     return execv(c_strings[0], c_strings.data()) == 0;
 }
 
@@ -418,6 +450,20 @@
     return Success();
 }
 
+Result<Success> Service::ParseEnterNamespace(const std::vector<std::string>& args) {
+    if (args[1] != "net") {
+        return Error() << "Init only supports entering network namespaces";
+    }
+    if (!namespaces_to_enter_.empty()) {
+        return Error() << "Only one network namespace may be entered";
+    }
+    // Network namespaces require that /sys is remounted, otherwise the old adapters will still be
+    // present. Therefore, they also require mount namespaces.
+    namespace_flags_ |= CLONE_NEWNS;
+    namespaces_to_enter_.emplace_back(CLONE_NEWNET, args[2]);
+    return Success();
+}
+
 Result<Success> Service::ParseGroup(const std::vector<std::string>& args) {
     auto gid = DecodeUid(args[1]);
     if (!gid) {
@@ -450,8 +496,8 @@
     const std::string& interface_name = args[1];
     const std::string& instance_name = args[2];
 
-    const FQName fq_name = FQName(interface_name);
-    if (!fq_name.isValid()) {
+    FQName fq_name;
+    if (!FQName::parse(interface_name, &fq_name)) {
         return Error() << "Invalid fully-qualified name for interface '" << interface_name << "'";
     }
 
@@ -582,6 +628,11 @@
     return Success();
 }
 
+Result<Success> Service::ParseSigstop(const std::vector<std::string>& args) {
+    sigstop_ = true;
+    return Success();
+}
+
 Result<Success> Service::ParseSetenv(const std::vector<std::string>& args) {
     environment_vars_.emplace_back(args[1], args[2]);
     return Success();
@@ -682,29 +733,32 @@
         {"console",     {0,     1,    &Service::ParseConsole}},
         {"critical",    {0,     0,    &Service::ParseCritical}},
         {"disabled",    {0,     0,    &Service::ParseDisabled}},
+        {"enter_namespace",
+                        {2,     2,    &Service::ParseEnterNamespace}},
+        {"file",        {2,     2,    &Service::ParseFile}},
         {"group",       {1,     NR_SVC_SUPP_GIDS + 1, &Service::ParseGroup}},
         {"interface",   {2,     2,    &Service::ParseInterface}},
         {"ioprio",      {2,     2,    &Service::ParseIoprio}},
-        {"priority",    {1,     1,    &Service::ParsePriority}},
         {"keycodes",    {1,     kMax, &Service::ParseKeycodes}},
-        {"oneshot",     {0,     0,    &Service::ParseOneshot}},
-        {"onrestart",   {1,     kMax, &Service::ParseOnrestart}},
-        {"override",    {0,     0,    &Service::ParseOverride}},
-        {"oom_score_adjust",
-                        {1,     1,    &Service::ParseOomScoreAdjust}},
-        {"memcg.swappiness",
-                        {1,     1,    &Service::ParseMemcgSwappiness}},
-        {"memcg.soft_limit_in_bytes",
-                        {1,     1,    &Service::ParseMemcgSoftLimitInBytes}},
         {"memcg.limit_in_bytes",
                         {1,     1,    &Service::ParseMemcgLimitInBytes}},
+        {"memcg.soft_limit_in_bytes",
+                        {1,     1,    &Service::ParseMemcgSoftLimitInBytes}},
+        {"memcg.swappiness",
+                        {1,     1,    &Service::ParseMemcgSwappiness}},
         {"namespace",   {1,     2,    &Service::ParseNamespace}},
+        {"oneshot",     {0,     0,    &Service::ParseOneshot}},
+        {"onrestart",   {1,     kMax, &Service::ParseOnrestart}},
+        {"oom_score_adjust",
+                        {1,     1,    &Service::ParseOomScoreAdjust}},
+        {"override",    {0,     0,    &Service::ParseOverride}},
+        {"priority",    {1,     1,    &Service::ParsePriority}},
         {"rlimit",      {3,     3,    &Service::ParseProcessRlimit}},
         {"seclabel",    {1,     1,    &Service::ParseSeclabel}},
         {"setenv",      {2,     2,    &Service::ParseSetenv}},
         {"shutdown",    {1,     1,    &Service::ParseShutdown}},
+        {"sigstop",     {0,     0,    &Service::ParseSigstop}},
         {"socket",      {3,     6,    &Service::ParseSocket}},
-        {"file",        {2,     2,    &Service::ParseFile}},
         {"user",        {1,     1,    &Service::ParseUser}},
         {"writepid",    {1,     kMax, &Service::ParseWritepid}},
     };
@@ -783,7 +837,7 @@
     if (!seclabel_.empty()) {
         scon = seclabel_;
     } else {
-        auto result = ComputeContextFromExecutable(name_, args_[0]);
+        auto result = ComputeContextFromExecutable(args_[0]);
         if (!result) {
             return result.error();
         }
@@ -802,10 +856,24 @@
     if (pid == 0) {
         umask(077);
 
+        if (auto result = EnterNamespaces(); !result) {
+            LOG(FATAL) << "Service '" << name_ << "' could not enter namespaces: " << result.error();
+        }
+
+        if (namespace_flags_ & CLONE_NEWNS) {
+            if (auto result = SetUpMountNamespace(); !result) {
+                LOG(FATAL) << "Service '" << name_
+                           << "' could not set up mount namespace: " << result.error();
+            }
+        }
+
         if (namespace_flags_ & CLONE_NEWPID) {
             // This will fork again to run an init process inside the PID
             // namespace.
-            SetUpPidNamespace(name_);
+            if (auto result = SetUpPidNamespace(); !result) {
+                LOG(FATAL) << "Service '" << name_
+                           << "' could not set up PID namespace: " << result.error();
+            }
         }
 
         for (const auto& [key, value] : environment_vars_) {
@@ -862,7 +930,7 @@
         // priority. Aborts on failure.
         SetProcessAttributes();
 
-        if (!ExpandArgsAndExecv(args_)) {
+        if (!ExpandArgsAndExecv(args_, sigstop_)) {
             PLOG(ERROR) << "cannot execve('" << args_[0] << "')";
         }
 
diff --git a/init/service.h b/init/service.h
index bcf1943..cbfd52f 100644
--- a/init/service.h
+++ b/init/service.h
@@ -118,12 +118,16 @@
     bool is_override() const { return override_; }
     bool process_cgroup_empty() const { return process_cgroup_empty_; }
     unsigned long start_order() const { return start_order_; }
+    void set_sigstop(bool value) { sigstop_ = value; }
     const std::vector<std::string>& args() const { return args_; }
 
   private:
     using OptionParser = Result<Success> (Service::*)(const std::vector<std::string>& args);
     class OptionParserMap;
 
+    Result<Success> SetUpMountNamespace() const;
+    Result<Success> SetUpPidNamespace() const;
+    Result<Success> EnterNamespaces() const;
     void NotifyStateChange(const std::string& new_state) const;
     void StopOrReset(int how);
     void ZapStdio() const;
@@ -136,6 +140,7 @@
     Result<Success> ParseConsole(const std::vector<std::string>& args);
     Result<Success> ParseCritical(const std::vector<std::string>& args);
     Result<Success> ParseDisabled(const std::vector<std::string>& args);
+    Result<Success> ParseEnterNamespace(const std::vector<std::string>& args);
     Result<Success> ParseGroup(const std::vector<std::string>& args);
     Result<Success> ParsePriority(const std::vector<std::string>& args);
     Result<Success> ParseInterface(const std::vector<std::string>& args);
@@ -153,6 +158,7 @@
     Result<Success> ParseSeclabel(const std::vector<std::string>& args);
     Result<Success> ParseSetenv(const std::vector<std::string>& args);
     Result<Success> ParseShutdown(const std::vector<std::string>& args);
+    Result<Success> ParseSigstop(const std::vector<std::string>& args);
     Result<Success> ParseSocket(const std::vector<std::string>& args);
     Result<Success> ParseFile(const std::vector<std::string>& args);
     Result<Success> ParseUser(const std::vector<std::string>& args);
@@ -179,6 +185,8 @@
     std::vector<gid_t> supp_gids_;
     CapSet capabilities_;
     unsigned namespace_flags_;
+    // Pair of namespace type, path to namespace.
+    std::vector<std::pair<int, std::string>> namespaces_to_enter_;
 
     std::string seclabel_;
 
@@ -213,6 +221,8 @@
 
     std::vector<std::pair<int, rlimit>> rlimits_;
 
+    bool sigstop_ = false;
+
     std::vector<std::string> args_;
 
     std::vector<std::function<void(const siginfo_t& siginfo)>> reap_callbacks_;
@@ -240,6 +250,16 @@
         return nullptr;
     }
 
+    Service* FindInterface(const std::string& interface_name) {
+        for (const auto& svc : services_) {
+            if (svc->interfaces().count(interface_name) > 0) {
+                return svc.get();
+            }
+        }
+
+        return nullptr;
+    }
+
     void DumpState() const;
 
     auto begin() const { return services_.begin(); }
diff --git a/init/sigchld_handler.cpp b/init/sigchld_handler.cpp
index badacaf..0b03324 100644
--- a/init/sigchld_handler.cpp
+++ b/init/sigchld_handler.cpp
@@ -39,9 +39,6 @@
 namespace android {
 namespace init {
 
-static int signal_write_fd = -1;
-static int signal_read_fd = -1;
-
 static bool ReapOneProcess() {
     siginfo_t siginfo = {};
     // This returns a zombie pid or informs us that there are no zombies left to be reaped.
@@ -101,46 +98,10 @@
     return true;
 }
 
-static void handle_signal() {
-    // Clear outstanding requests.
-    char buf[32];
-    read(signal_read_fd, buf, sizeof(buf));
-
-    ReapAnyOutstandingChildren();
-}
-
-static void SIGCHLD_handler(int) {
-    if (TEMP_FAILURE_RETRY(write(signal_write_fd, "1", 1)) == -1) {
-        PLOG(ERROR) << "write(signal_write_fd) failed";
-    }
-}
-
 void ReapAnyOutstandingChildren() {
     while (ReapOneProcess()) {
     }
 }
 
-void sigchld_handler_init() {
-    // Create a signalling mechanism for SIGCHLD.
-    int s[2];
-    if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {
-        PLOG(FATAL) << "socketpair failed in sigchld_handler_init";
-    }
-
-    signal_write_fd = s[0];
-    signal_read_fd = s[1];
-
-    // Write to signal_write_fd if we catch SIGCHLD.
-    struct sigaction act;
-    memset(&act, 0, sizeof(act));
-    act.sa_handler = SIGCHLD_handler;
-    act.sa_flags = SA_NOCLDSTOP;
-    sigaction(SIGCHLD, &act, 0);
-
-    ReapAnyOutstandingChildren();
-
-    register_epoll_handler(signal_read_fd, handle_signal);
-}
-
 }  // namespace init
 }  // namespace android
diff --git a/init/sigchld_handler.h b/init/sigchld_handler.h
index c86dc8d..30063f2 100644
--- a/init/sigchld_handler.h
+++ b/init/sigchld_handler.h
@@ -22,8 +22,6 @@
 
 void ReapAnyOutstandingChildren();
 
-void sigchld_handler_init(void);
-
 }  // namespace init
 }  // namespace android
 
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index fdb4641..267d530 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -30,8 +30,6 @@
 #include "util.h"
 
 #if defined(__ANDROID__)
-#include <android-base/properties.h>
-
 #include "property_service.h"
 #include "selinux.h"
 #else
@@ -39,7 +37,6 @@
 #endif
 
 using android::base::GetExecutablePath;
-using android::base::GetIntProperty;
 using android::base::Join;
 using android::base::Socketpair;
 using android::base::Split;
diff --git a/libasyncio/AsyncIO.cpp b/libasyncio/AsyncIO.cpp
index 7430bc8..6149f09 100644
--- a/libasyncio/AsyncIO.cpp
+++ b/libasyncio/AsyncIO.cpp
@@ -17,9 +17,10 @@
 #include <asyncio/AsyncIO.h>
 #include <sys/syscall.h>
 #include <unistd.h>
+#include <cstdint>
+#include <cstring>
 
 int io_setup(unsigned nr, aio_context_t* ctxp) {
-    memset(ctxp, 0, sizeof(*ctxp));
     return syscall(__NR_io_setup, nr, ctxp);
 }
 
@@ -48,3 +49,11 @@
     iocb->aio_nbytes = count;
     iocb->aio_offset = offset;
 }
+
+void io_prep_pread(struct iocb* iocb, int fd, void* buf, size_t count, long long offset) {
+    io_prep(iocb, fd, buf, count, offset, true);
+}
+
+void io_prep_pwrite(struct iocb* iocb, int fd, void* buf, size_t count, long long offset) {
+    io_prep(iocb, fd, buf, count, offset, false);
+}
diff --git a/libasyncio/include/asyncio/AsyncIO.h b/libasyncio/include/asyncio/AsyncIO.h
index e3fb93a..9620d2a 100644
--- a/libasyncio/include/asyncio/AsyncIO.h
+++ b/libasyncio/include/asyncio/AsyncIO.h
@@ -17,9 +17,9 @@
 #ifndef _ASYNCIO_H
 #define _ASYNCIO_H
 
-#include <cstring>
-#include <cstdint>
 #include <linux/aio_abi.h>
+#include <stdbool.h>
+#include <stdint.h>
 #include <sys/cdefs.h>
 #include <sys/types.h>
 #include <time.h>
@@ -35,10 +35,14 @@
 
 int io_setup(unsigned nr, aio_context_t* ctxp);
 int io_destroy(aio_context_t ctx);
-int io_submit(aio_context_t ctx, long nr, iocb** iocbpp);
-int io_getevents(aio_context_t ctx, long min_nr, long max_nr, io_event* events, timespec* timeout);
-int io_cancel(aio_context_t ctx, iocb*, io_event* result);
-void io_prep(iocb* iocb, int fd, const void* buf, uint64_t count, int64_t offset, bool read);
+int io_submit(aio_context_t ctx, long nr, struct iocb** iocbpp);
+int io_getevents(aio_context_t ctx, long min_nr, long max_nr, struct io_event* events,
+                 struct timespec* timeout);
+int io_cancel(aio_context_t ctx, struct iocb*, struct io_event* result);
+
+void io_prep_pread(struct iocb* iocb, int fd, void* buf, size_t count, long long offset);
+void io_prep_pwrite(struct iocb* iocb, int fd, void* buf, size_t count, long long offset);
+void io_prep(struct iocb* iocb, int fd, const void* buf, uint64_t count, int64_t offset, bool read);
 
 #ifdef __cplusplus
 };
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 4bd01d2..4987ba1 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -22,11 +22,6 @@
         "-Werror",
     ],
 
-    // The latest clang (r230699) does not allow SP/PC to be declared in inline asm lists.
-    clang_cflags: ["-Wno-inline-asm"],
-
-    include_dirs: ["external/libunwind/include/tdep"],
-
     target: {
         darwin: {
             enabled: false,
@@ -92,12 +87,14 @@
             shared_libs: [
                 "libbase",
                 "liblog",
-                "libunwind",
                 "libunwindstack",
                 "libdexfile",
             ],
 
-            static_libs: ["libcutils"],
+            static_libs: [
+                "libcutils",
+                "libprocinfo",
+            ],
 
             // libdexfile will eventually properly export headers, for now
             // include these directly.
@@ -183,12 +180,16 @@
         "art/runtime",
     ],
 
+    test_suites: ["device-tests"],
     data: [
         "testdata/arm/*",
         "testdata/arm64/*",
         "testdata/x86/*",
         "testdata/x86_64/*",
     ],
+    required: [
+        "libbacktrace_test",
+    ],
 }
 
 cc_benchmark {
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index bdae140..399721d 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -28,6 +28,9 @@
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 #include <backtrace/backtrace_constants.h>
+#if defined(__linux__)
+#include <procinfo/process_map.h>
+#endif
 
 #include "thread_utils.h"
 
@@ -60,27 +63,19 @@
   *map = {};
 }
 
-bool BacktraceMap::ParseLine(const char* line, backtrace_map_t* map) {
+#if defined(__APPLE__)
+static bool ParseLine(const char* line, backtrace_map_t* map) {
   uint64_t start;
   uint64_t end;
   char permissions[5];
   int name_pos;
 
-#if defined(__APPLE__)
 // Mac OS vmmap(1) output:
 // __TEXT                 0009f000-000a1000 [    8K     8K] r-x/rwx SM=COW  /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n
 // 012345678901234567890123456789012345678901234567890123456789
 // 0         1         2         3         4         5
   if (sscanf(line, "%*21c %" SCNx64 "-%" SCNx64 " [%*13c] %3c/%*3c SM=%*3c  %n",
              &start, &end, permissions, &name_pos) != 3) {
-#else
-// Linux /proc/<pid>/maps lines:
-// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /system/lib/libcomposer.so\n
-// 012345678901234567890123456789012345678901234567890123456789
-// 0         1         2         3         4         5
-  if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %4s %*x %*x:%*x %*d %n",
-             &start, &end, permissions, &name_pos) != 3) {
-#endif
     return false;
   }
 
@@ -107,24 +102,15 @@
         map->flags, map->name.c_str());
   return true;
 }
+#endif  // defined(__APPLE__)
 
 bool BacktraceMap::Build() {
 #if defined(__APPLE__)
   char cmd[sizeof(pid_t)*3 + sizeof("vmmap -w -resident -submap -allSplitLibs -interleaved ") + 1];
-#else
-  char path[sizeof(pid_t)*3 + sizeof("/proc//maps") + 1];
-#endif
   char line[1024];
-
-#if defined(__APPLE__)
   // cmd is guaranteed to always be big enough to hold this string.
   snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid_);
   FILE* fp = popen(cmd, "r");
-#else
-  // path is guaranteed to always be big enough to hold this string.
-  snprintf(path, sizeof(path), "/proc/%d/maps", pid_);
-  FILE* fp = fopen(path, "r");
-#endif
   if (fp == nullptr) {
     return false;
   }
@@ -135,13 +121,19 @@
       maps_.push_back(map);
     }
   }
-#if defined(__APPLE__)
   pclose(fp);
-#else
-  fclose(fp);
-#endif
-
   return true;
+#else
+  return android::procinfo::ReadProcessMaps(
+      pid_, [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t, const char* name) {
+        maps_.resize(maps_.size() + 1);
+        backtrace_map_t& map = maps_.back();
+        map.start = start;
+        map.end = end;
+        map.flags = flags;
+        map.name = name;
+      });
+#endif
 }
 
 #if defined(__APPLE__)
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index 473d195..a9cfce4 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -40,6 +40,10 @@
 // Special flag to indicate a map is in /dev/. However, a map in
 // /dev/ashmem/... does not set this flag.
 static constexpr int PROT_DEVICE_MAP = 0x8000;
+// Special flag to indicate that this map represents an elf file
+// created by ART for use with the gdb jit debug interface.
+// This should only ever appear in offline maps data.
+static constexpr int PROT_JIT_SYMFILE_MAP = 0x4000;
 
 struct backtrace_map_t {
   uint64_t start = 0;
@@ -165,8 +169,6 @@
 
   virtual uint64_t GetLoadBias(size_t /* index */) { return 0; }
 
-  virtual bool ParseLine(const char* line, backtrace_map_t* map);
-
   pid_t pid_;
   std::deque<backtrace_map_t> maps_;
   std::vector<std::string> suffixes_to_ignore_;
diff --git a/libbinderwrapper/Android.bp b/libbinderwrapper/Android.bp
index 6fac0d8..d2487e2 100644
--- a/libbinderwrapper/Android.bp
+++ b/libbinderwrapper/Android.bp
@@ -38,6 +38,7 @@
 cc_library_shared {
     name: "libbinderwrapper",
     defaults: ["libbinderwrapper_defaults"],
+    vendor_available: true,
 
     srcs: [
         "binder_wrapper.cc",
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index bcc9b1c..e823257 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -173,6 +173,7 @@
 
     shared_libs: ["liblog"],
     header_libs: [
+        "libbase_headers",
         "libcutils_headers",
         "libutils_headers",
     ],
diff --git a/libcutils/ashmem-host.cpp b/libcutils/ashmem-host.cpp
index b2bec99..bb990d5 100644
--- a/libcutils/ashmem-host.cpp
+++ b/libcutils/ashmem-host.cpp
@@ -24,7 +24,6 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
-#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
diff --git a/libcutils/canned_fs_config.cpp b/libcutils/canned_fs_config.cpp
index 6b5763b..2772ef0 100644
--- a/libcutils/canned_fs_config.cpp
+++ b/libcutils/canned_fs_config.cpp
@@ -21,7 +21,6 @@
 #include <errno.h>
 #include <inttypes.h>
 #include <limits.h>
-#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
diff --git a/libcutils/hashmap.cpp b/libcutils/hashmap.cpp
index 65b6ab1..10e3b25 100644
--- a/libcutils/hashmap.cpp
+++ b/libcutils/hashmap.cpp
@@ -21,7 +21,6 @@
 #include <cutils/threads.h>
 #include <stdlib.h>
 #include <string.h>
-#include <stdbool.h>
 #include <sys/types.h>
 
 typedef struct Entry Entry;
diff --git a/libcutils/include/cutils/trace.h b/libcutils/include/cutils/trace.h
index bbb150d..58b9f09 100644
--- a/libcutils/include/cutils/trace.h
+++ b/libcutils/include/cutils/trace.h
@@ -74,7 +74,8 @@
 #define ATRACE_TAG_ADB              (1<<22)
 #define ATRACE_TAG_VIBRATOR         (1<<23)
 #define ATRACE_TAG_AIDL             (1<<24)
-#define ATRACE_TAG_LAST             ATRACE_TAG_AIDL
+#define ATRACE_TAG_NNAPI            (1<<25)
+#define ATRACE_TAG_LAST             ATRACE_TAG_NNAPI
 
 // Reserved for initialization.
 #define ATRACE_TAG_NOT_READY        (1ULL<<63)
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 5d17698..3be8ad0 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -129,6 +129,8 @@
 #define AID_STATSD 1066          /* statsd daemon */
 #define AID_INCIDENTD 1067       /* incidentd daemon */
 #define AID_SECURE_ELEMENT 1068  /* secure element subsystem */
+#define AID_LMKD 1069            /* low memory killer daemon */
+#define AID_LLKD 1070            /* live lock daemon */
 /* Changes to this file must be made in AOSP, *not* in internal branches. */
 
 #define AID_SHELL 2000 /* adb and debug shell user */
diff --git a/libcutils/sched_policy.cpp b/libcutils/sched_policy.cpp
index f72ec52..3fa548f 100644
--- a/libcutils/sched_policy.cpp
+++ b/libcutils/sched_policy.cpp
@@ -25,6 +25,7 @@
 #include <string.h>
 #include <unistd.h>
 
+#include <android-base/macros.h>
 #include <log/log.h>
 
 /* Re-map SP_DEFAULT to the system default policy, and leave other values unchanged.
@@ -460,16 +461,16 @@
 
 #endif
 
-const char *get_sched_policy_name(SchedPolicy policy)
-{
+const char* get_sched_policy_name(SchedPolicy policy) {
     policy = _policy(policy);
-    static const char* const strings[SP_CNT] = {
+    static const char* const kSchedPolicyNames[] = {
             [SP_BACKGROUND] = "bg", [SP_FOREGROUND] = "fg", [SP_SYSTEM] = "  ",
             [SP_AUDIO_APP] = "aa",  [SP_AUDIO_SYS] = "as",  [SP_TOP_APP] = "ta",
             [SP_RT_APP] = "rt",     [SP_RESTRICTED] = "rs",
     };
-    if ((policy < SP_CNT) && (strings[policy] != NULL))
-        return strings[policy];
-    else
+    static_assert(arraysize(kSchedPolicyNames) == SP_CNT, "missing name");
+    if (policy < SP_BACKGROUND || policy >= SP_CNT) {
         return "error";
+    }
+    return kSchedPolicyNames[policy];
 }
diff --git a/libcutils/tests/sched_policy_test.cpp b/libcutils/tests/sched_policy_test.cpp
index 173174a..5942ee5 100644
--- a/libcutils/tests/sched_policy_test.cpp
+++ b/libcutils/tests/sched_policy_test.cpp
@@ -60,6 +60,12 @@
     return sleepTimes[median];
 }
 
+static void AssertPolicy(SchedPolicy expected_policy) {
+    SchedPolicy current_policy;
+    ASSERT_EQ(0, get_sched_policy(0, &current_policy));
+    EXPECT_EQ(expected_policy, current_policy);
+}
+
 TEST(SchedPolicy, set_sched_policy) {
     if (!hasCapSysNice()) {
         GTEST_LOG_(INFO) << "skipping test that requires CAP_SYS_NICE";
@@ -76,23 +82,17 @@
     const unsigned int BG_FG_SLACK_FACTOR = 100;
 
     ASSERT_EQ(0, set_sched_policy(0, SP_BACKGROUND));
+    AssertPolicy(SP_BACKGROUND);
     auto bgSleepTime = medianSleepTime();
 
     ASSERT_EQ(0, set_sched_policy(0, SP_FOREGROUND));
+    AssertPolicy(SP_FOREGROUND);
     auto fgSleepTime = medianSleepTime();
     ASSERT_GT(bgSleepTime, fgSleepTime * BG_FG_SLACK_FACTOR);
 }
 
-TEST(SchedPolicy, get_sched_policy) {
-    SchedPolicy policy;
-    ASSERT_EQ(0, get_sched_policy(0, &policy));
-
-    const char *policyName = get_sched_policy_name(policy);
-    EXPECT_NE(nullptr, policyName);
-    EXPECT_STRNE("error", policyName);
-
-    ASSERT_EQ(0, set_sched_policy(0, SP_BACKGROUND));
-    SchedPolicy newPolicy;
-    ASSERT_EQ(0, get_sched_policy(0, &newPolicy));
-    EXPECT_EQ(SP_BACKGROUND, newPolicy);
+TEST(SchedPolicy, get_sched_policy_name) {
+    EXPECT_STREQ("bg", get_sched_policy_name(SP_BACKGROUND));
+    EXPECT_STREQ("error", get_sched_policy_name(SchedPolicy(-2)));
+    EXPECT_STREQ("error", get_sched_policy_name(SP_CNT));
 }
diff --git a/libcutils/trace-dev.inc b/libcutils/trace-dev.inc
index f95c6c5..c9580af 100644
--- a/libcutils/trace-dev.inc
+++ b/libcutils/trace-dev.inc
@@ -24,7 +24,6 @@
 #include <limits.h>
 #include <pthread.h>
 #include <stdatomic.h>
-#include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
diff --git a/libion/ion.c b/libion/ion.c
index 5836128..b8de5a4 100644
--- a/libion/ion.c
+++ b/libion/ion.c
@@ -55,7 +55,7 @@
 
 int ion_open() {
     int fd = open("/dev/ion", O_RDONLY | O_CLOEXEC);
-    if (fd < 0) ALOGE("open /dev/ion failed!\n");
+    if (fd < 0) ALOGE("open /dev/ion failed: %s", strerror(errno));
 
     return fd;
 }
@@ -69,7 +69,7 @@
 static int ion_ioctl(int fd, int req, void* arg) {
     int ret = ioctl(fd, req, arg);
     if (ret < 0) {
-        ALOGE("ioctl %x failed with code %d: %s\n", req, ret, strerror(errno));
+        ALOGE("ioctl %x failed with code %d: %s", req, ret, strerror(errno));
         return -errno;
     }
     return ret;
@@ -115,12 +115,12 @@
     ret = ion_ioctl(fd, ION_IOC_MAP, &data);
     if (ret < 0) return ret;
     if (data.fd < 0) {
-        ALOGE("map ioctl returned negative fd\n");
+        ALOGE("map ioctl returned negative fd");
         return -EINVAL;
     }
     tmp_ptr = mmap(NULL, length, prot, flags, data.fd, offset);
     if (tmp_ptr == MAP_FAILED) {
-        ALOGE("mmap failed: %s\n", strerror(errno));
+        ALOGE("mmap failed: %s", strerror(errno));
         return -errno;
     }
     *map_fd = data.fd;
@@ -140,7 +140,7 @@
     ret = ion_ioctl(fd, ION_IOC_SHARE, &data);
     if (ret < 0) return ret;
     if (data.fd < 0) {
-        ALOGE("share ioctl returned negative fd\n");
+        ALOGE("share ioctl returned negative fd");
         return -EINVAL;
     }
     *share_fd = data.fd;
diff --git a/libkeyutils/Android.bp b/libkeyutils/Android.bp
index 0285259..f3593ff 100644
--- a/libkeyutils/Android.bp
+++ b/libkeyutils/Android.bp
@@ -13,4 +13,5 @@
     cflags: ["-Werror"],
     shared_libs: ["libkeyutils"],
     srcs: ["keyutils_test.cpp"],
+    test_suites: ["device-tests"],
 }
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
index 28c87e4..52cbe8b 100644
--- a/liblog/include/android/log.h
+++ b/liblog/include/android/log.h
@@ -35,6 +35,11 @@
  */
 
 /**
+ * @addtogroup Logging
+ * @{
+ */
+
+/**
  * \file
  *
  * Support routines to send messages to the Android log buffer,
@@ -205,4 +210,6 @@
 }
 #endif
 
+/** @} */
+
 #endif /* _ANDROID_LOG_H */
diff --git a/libmemunreachable/Android.bp b/libmemunreachable/Android.bp
index f872d0f..248a9d2 100644
--- a/libmemunreachable/Android.bp
+++ b/libmemunreachable/Android.bp
@@ -29,7 +29,6 @@
         "HeapWalker.cpp",
         "LeakFolding.cpp",
         "LeakPipe.cpp",
-        "LineBuffer.cpp",
         "MemUnreachable.cpp",
         "ProcessMappings.cpp",
         "PtracerThread.cpp",
@@ -38,6 +37,7 @@
 
     static_libs: [
         "libc_malloc_debug_backtrace",
+        "libprocinfo",
     ],
     // Only need this for arm since libc++ uses its own unwind code that
     // doesn't mix with the other default unwind code.
@@ -46,6 +46,12 @@
             static_libs: ["libunwind_llvm"],
         },
     },
+
+    // TODO(b/78118944), clang lld link flags do not work with special link
+    // rules for libunwind_llvm yet. Linked aosp_arm-eng image failed to
+    // boot up in the emulator.
+    use_clang_lld: false,
+
     export_include_dirs: ["include"],
     local_include_dirs: ["include"],
 }
@@ -83,6 +89,8 @@
             enabled: false,
         },
     },
+
+    test_suites: ["device-tests"],
 }
 
 cc_test {
@@ -97,4 +105,5 @@
         "libhwbinder",
         "libutils",
     ],
+    test_suites: ["device-tests"],
 }
diff --git a/libmemunreachable/LineBuffer.cpp b/libmemunreachable/LineBuffer.cpp
deleted file mode 100644
index 4ea0542..0000000
--- a/libmemunreachable/LineBuffer.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Copied from system/extras/memory_replay/LineBuffer.cpp
-// TODO(ccross): find a way to share between libmemunreachable and memory_replay?
-
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "LineBuffer.h"
-
-namespace android {
-
-LineBuffer::LineBuffer(int fd, char* buffer, size_t buffer_len)
-    : fd_(fd), buffer_(buffer), buffer_len_(buffer_len) {}
-
-bool LineBuffer::GetLine(char** line, size_t* line_len) {
-  while (true) {
-    if (bytes_ > 0) {
-      char* newline = reinterpret_cast<char*>(memchr(buffer_ + start_, '\n', bytes_));
-      if (newline != nullptr) {
-        *newline = '\0';
-        *line = buffer_ + start_;
-        start_ = newline - buffer_ + 1;
-        bytes_ -= newline - *line + 1;
-        *line_len = newline - *line;
-        return true;
-      }
-    }
-    if (start_ > 0) {
-      // Didn't find anything, copy the current to the front of the buffer.
-      memmove(buffer_, buffer_ + start_, bytes_);
-      start_ = 0;
-    }
-    ssize_t bytes = TEMP_FAILURE_RETRY(read(fd_, buffer_ + bytes_, buffer_len_ - bytes_ - 1));
-    if (bytes <= 0) {
-      if (bytes_ > 0) {
-        // The read data might not contain a nul terminator, so add one.
-        buffer_[bytes_] = '\0';
-        *line = buffer_ + start_;
-        *line_len = bytes_;
-        bytes_ = 0;
-        start_ = 0;
-        return true;
-      }
-      return false;
-    }
-    bytes_ += bytes;
-  }
-}
-
-}  // namespace android
diff --git a/libmemunreachable/LineBuffer.h b/libmemunreachable/LineBuffer.h
deleted file mode 100644
index cc6cd0c..0000000
--- a/libmemunreachable/LineBuffer.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBMEMUNREACHABLE_LINE_BUFFER_H
-#define _LIBMEMUNREACHABLE_LINE_BUFFER_H
-
-#include <stdint.h>
-
-namespace android {
-
-class LineBuffer {
- public:
-  LineBuffer(int fd, char* buffer, size_t buffer_len);
-
-  bool GetLine(char** line, size_t* line_len);
-
- private:
-  int fd_;
-  char* buffer_ = nullptr;
-  size_t buffer_len_ = 0;
-  size_t start_ = 0;
-  size_t bytes_ = 0;
-};
-
-}  // namespace android
-
-#endif  // _LIBMEMUNREACHABLE_LINE_BUFFER_H
diff --git a/libmemunreachable/ProcessMappings.cpp b/libmemunreachable/ProcessMappings.cpp
index 9a06870..701ce16 100644
--- a/libmemunreachable/ProcessMappings.cpp
+++ b/libmemunreachable/ProcessMappings.cpp
@@ -14,21 +14,30 @@
  * limitations under the License.
  */
 
+#include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
 #include <string.h>
 #include <unistd.h>
 
 #include <android-base/unique_fd.h>
+#include <procinfo/process_map.h>
 
-#include "LineBuffer.h"
 #include "ProcessMappings.h"
-#include "log.h"
 
 namespace android {
 
-// This function is not re-entrant since it uses a static buffer for
-// the line data.
+struct ReadMapCallback {
+  ReadMapCallback(allocator::vector<Mapping>& mappings) : mappings_(mappings) {}
+
+  void operator()(uint64_t start, uint64_t end, uint16_t flags, uint64_t, const char* name) const {
+    mappings_.emplace_back(start, end, flags & PROT_READ, flags & PROT_WRITE, flags & PROT_EXEC,
+                           name);
+  }
+
+  allocator::vector<Mapping>& mappings_;
+};
+
 bool ProcessMappings(pid_t pid, allocator::vector<Mapping>& mappings) {
   char map_buffer[1024];
   snprintf(map_buffer, sizeof(map_buffer), "/proc/%d/maps", pid);
@@ -36,35 +45,13 @@
   if (fd == -1) {
     return false;
   }
-
-  LineBuffer line_buf(fd, map_buffer, sizeof(map_buffer));
-  char* line;
-  size_t line_len;
-  while (line_buf.GetLine(&line, &line_len)) {
-    int name_pos;
-    char perms[5];
-    Mapping mapping{};
-    if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " %4s %*x %*x:%*x %*d %n", &mapping.begin,
-               &mapping.end, perms, &name_pos) == 3) {
-      if (perms[0] == 'r') {
-        mapping.read = true;
-      }
-      if (perms[1] == 'w') {
-        mapping.write = true;
-      }
-      if (perms[2] == 'x') {
-        mapping.execute = true;
-      }
-      if (perms[3] == 'p') {
-        mapping.priv = true;
-      }
-      if ((size_t)name_pos < line_len) {
-        strlcpy(mapping.name, line + name_pos, sizeof(mapping.name));
-      }
-      mappings.emplace_back(mapping);
-    }
+  allocator::string content(mappings.get_allocator());
+  ssize_t n;
+  while ((n = TEMP_FAILURE_RETRY(read(fd, map_buffer, sizeof(map_buffer)))) > 0) {
+    content.append(map_buffer, n);
   }
-  return true;
+  ReadMapCallback callback(mappings);
+  return android::procinfo::ReadMapFileContent(&content[0], callback);
 }
 
 }  // namespace android
diff --git a/libmemunreachable/ProcessMappings.h b/libmemunreachable/ProcessMappings.h
index a0e97e9..94da69b 100644
--- a/libmemunreachable/ProcessMappings.h
+++ b/libmemunreachable/ProcessMappings.h
@@ -17,6 +17,8 @@
 #ifndef LIBMEMUNREACHABLE_PROCESS_MAPPING_H_
 #define LIBMEMUNREACHABLE_PROCESS_MAPPING_H_
 
+#include <string.h>
+
 #include "Allocator.h"
 
 namespace android {
@@ -27,8 +29,13 @@
   bool read;
   bool write;
   bool execute;
-  bool priv;
   char name[96];
+
+  Mapping() {}
+  Mapping(uintptr_t begin, uintptr_t end, bool read, bool write, bool execute, const char* name)
+      : begin(begin), end(end), read(read), write(write), execute(execute) {
+    strlcpy(this->name, name, sizeof(this->name));
+  }
 };
 
 // This function is not re-entrant since it uses a static buffer for
diff --git a/libmemunreachable/README.md b/libmemunreachable/README.md
index ae8fa94..6d9141a 100644
--- a/libmemunreachable/README.md
+++ b/libmemunreachable/README.md
@@ -12,6 +12,27 @@
 Usage
 -------
 
+### In Android apps ###
+
+libmemunreachble is loaded by zygote and can be triggered with `dumpsys -t 600 meminfo --unreachable [process]`.
+
+To enable malloc\_debug backtraces on allocations for a single app process on a userdebug device, use:
+```
+adb root
+adb shell setprop libc.debug.malloc.program app_process
+adb shell setprop wrap.[process] "\$\@"
+adb shell setprop libc.debug.malloc.options backtrace=4
+```
+
+Kill and restart the app, trigger the leak, and then run `dumpsys -t 600 meminfo --unreachable [process]`.
+
+To disable malloc\_debug:
+```
+adb shell setprop libc.debug.malloc.options "''"
+adb shell setprop libc.debug.malloc.program "''"
+adb shell setprop wrap.[process]  "''"
+```
+
 ### C interface ###
 
 #### `bool LogUnreachableMemory(bool log_contents, size_t limit)` ####
diff --git a/libprocinfo/Android.bp b/libprocinfo/Android.bp
index 83b0a7f..d776b3d 100644
--- a/libprocinfo/Android.bp
+++ b/libprocinfo/Android.bp
@@ -59,6 +59,7 @@
     host_supported: true,
     srcs: [
         "process_test.cpp",
+        "process_map_test.cpp",
     ],
     target: {
         darwin: {
@@ -83,4 +84,37 @@
             suffix: "64",
         },
     },
+
+    data: [
+        "testdata/*",
+    ],
+
+    test_suites: ["device-tests"],
+}
+
+cc_benchmark {
+    name: "libprocinfo_benchmark",
+    defaults: ["libprocinfo_defaults"],
+    srcs: [
+        "process_map_benchmark.cpp",
+    ],
+    shared_libs: [
+        "libbacktrace",
+        "libbase",
+        "libprocinfo",
+        "libunwindstack",
+    ],
+    compile_multilib: "both",
+    multilib: {
+        lib32: {
+            suffix: "32",
+        },
+        lib64: {
+            suffix: "64",
+        },
+    },
+
+    data: [
+        "testdata/*",
+    ],
 }
diff --git a/libprocinfo/include/procinfo/process_map.h b/libprocinfo/include/procinfo/process_map.h
new file mode 100644
index 0000000..3771f9f
--- /dev/null
+++ b/libprocinfo/include/procinfo/process_map.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <functional>
+#include <string>
+
+#include <android-base/file.h>
+
+namespace android {
+namespace procinfo {
+
+template <class CallbackType>
+bool ReadMapFileContent(char* content, const CallbackType& callback) {
+  uint64_t start_addr;
+  uint64_t end_addr;
+  uint16_t flags;
+  uint64_t pgoff;
+  char* next_line = content;
+  char* p;
+
+  auto pass_space = [&]() {
+    if (*p != ' ') {
+      return false;
+    }
+    while (*p == ' ') {
+      p++;
+    }
+    return true;
+  };
+
+  auto pass_xdigit = [&]() {
+    if (!isxdigit(*p)) {
+      return false;
+    }
+    do {
+      p++;
+    } while (isxdigit(*p));
+    return true;
+  };
+
+  while (next_line != nullptr && *next_line != '\0') {
+    p = next_line;
+    next_line = strchr(next_line, '\n');
+    if (next_line != nullptr) {
+      *next_line = '\0';
+      next_line++;
+    }
+    // Parse line like: 00400000-00409000 r-xp 00000000 fc:00 426998  /usr/lib/gvfs/gvfsd-http
+    char* end;
+    // start_addr
+    start_addr = strtoull(p, &end, 16);
+    if (end == p || *end != '-') {
+      return false;
+    }
+    p = end + 1;
+    // end_addr
+    end_addr = strtoull(p, &end, 16);
+    if (end == p) {
+      return false;
+    }
+    p = end;
+    if (!pass_space()) {
+      return false;
+    }
+    // flags
+    flags = 0;
+    if (*p == 'r') {
+      flags |= PROT_READ;
+    } else if (*p != '-') {
+      return false;
+    }
+    p++;
+    if (*p == 'w') {
+      flags |= PROT_WRITE;
+    } else if (*p != '-') {
+      return false;
+    }
+    p++;
+    if (*p == 'x') {
+      flags |= PROT_EXEC;
+    } else if (*p != '-') {
+      return false;
+    }
+    p++;
+    if (*p != 'p' && *p != 's') {
+      return false;
+    }
+    p++;
+    if (!pass_space()) {
+      return false;
+    }
+    // pgoff
+    pgoff = strtoull(p, &end, 16);
+    if (end == p) {
+      return false;
+    }
+    p = end;
+    if (!pass_space()) {
+      return false;
+    }
+    // major:minor
+    if (!pass_xdigit() || *p++ != ':' || !pass_xdigit() || !pass_space()) {
+      return false;
+    }
+    // inode
+    if (!pass_xdigit() || (*p != '\0' && !pass_space())) {
+      return false;
+    }
+    // filename
+    callback(start_addr, end_addr, flags, pgoff, p);
+  }
+  return true;
+}
+
+inline bool ReadMapFile(
+    const std::string& map_file,
+    const std::function<void(uint64_t, uint64_t, uint16_t, uint64_t, const char*)>& callback) {
+  std::string content;
+  if (!android::base::ReadFileToString(map_file, &content)) {
+    return false;
+  }
+  return ReadMapFileContent(&content[0], callback);
+}
+
+inline bool ReadProcessMaps(
+    pid_t pid,
+    const std::function<void(uint64_t, uint64_t, uint16_t, uint64_t, const char*)>& callback) {
+  return ReadMapFile("/proc/" + std::to_string(pid) + "/maps", callback);
+}
+
+} /* namespace procinfo */
+} /* namespace android */
diff --git a/libprocinfo/process_map_benchmark.cpp b/libprocinfo/process_map_benchmark.cpp
new file mode 100644
index 0000000..d9e8a4d
--- /dev/null
+++ b/libprocinfo/process_map_benchmark.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <procinfo/process_map.h>
+
+#include <string.h>
+
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <backtrace/BacktraceMap.h>
+#include <unwindstack/Maps.h>
+
+#include <benchmark/benchmark.h>
+
+struct MapInfo {
+  uint64_t start;
+  uint64_t end;
+  uint16_t flags;
+  uint64_t pgoff;
+  const std::string name;
+
+  MapInfo(uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, const char* name)
+      : start(start), end(end), flags(flags), pgoff(pgoff), name(name) {}
+};
+
+static void BM_ReadMapFile(benchmark::State& state) {
+  std::string map_file = android::base::GetExecutableDirectory() + "/testdata/maps";
+  for (auto _ : state) {
+    std::vector<MapInfo> maps;
+    android::procinfo::ReadMapFile(
+        map_file, [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff,
+                      const char* name) { maps.emplace_back(start, end, flags, pgoff, name); });
+    CHECK_EQ(maps.size(), 2043u);
+  }
+}
+BENCHMARK(BM_ReadMapFile);
+
+static void BM_unwindstack_FileMaps(benchmark::State& state) {
+  std::string map_file = android::base::GetExecutableDirectory() + "/testdata/maps";
+  for (auto _ : state) {
+    unwindstack::FileMaps maps(map_file);
+    maps.Parse();
+    CHECK_EQ(maps.Total(), 2043u);
+  }
+}
+BENCHMARK(BM_unwindstack_FileMaps);
+
+static void BM_unwindstack_BufferMaps(benchmark::State& state) {
+  std::string map_file = android::base::GetExecutableDirectory() + "/testdata/maps";
+  std::string content;
+  CHECK(android::base::ReadFileToString(map_file, &content));
+  for (auto _ : state) {
+    unwindstack::BufferMaps maps(content.c_str());
+    maps.Parse();
+    CHECK_EQ(maps.Total(), 2043u);
+  }
+}
+BENCHMARK(BM_unwindstack_BufferMaps);
+
+static void BM_backtrace_BacktraceMap(benchmark::State& state) {
+  pid_t pid = getpid();
+  for (auto _ : state) {
+    BacktraceMap* map = BacktraceMap::Create(pid, true);
+    CHECK(map != nullptr);
+    delete map;
+  }
+}
+BENCHMARK(BM_backtrace_BacktraceMap);
+
+BENCHMARK_MAIN();
diff --git a/libprocinfo/process_map_test.cpp b/libprocinfo/process_map_test.cpp
new file mode 100644
index 0000000..900fd85
--- /dev/null
+++ b/libprocinfo/process_map_test.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <procinfo/process_map.h>
+
+#include <string>
+
+#include <android-base/file.h>
+
+#include <gtest/gtest.h>
+
+struct MapInfo {
+  uint64_t start;
+  uint64_t end;
+  uint16_t flags;
+  uint64_t pgoff;
+  const std::string name;
+
+  MapInfo(uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, const char* name)
+      : start(start), end(end), flags(flags), pgoff(pgoff), name(name) {}
+};
+
+TEST(process_map, smoke) {
+  std::string map_file = android::base::GetExecutableDirectory() + "/testdata/maps";
+  std::vector<MapInfo> maps;
+  ASSERT_TRUE(android::procinfo::ReadMapFile(
+      map_file, [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff,
+                    const char* name) { maps.emplace_back(start, end, flags, pgoff, name); }));
+  ASSERT_EQ(2043u, maps.size());
+  ASSERT_EQ(maps[0].start, 0x12c00000ULL);
+  ASSERT_EQ(maps[0].end, 0x2ac00000ULL);
+  ASSERT_EQ(maps[0].flags, PROT_READ | PROT_WRITE);
+  ASSERT_EQ(maps[0].pgoff, 0ULL);
+  ASSERT_EQ(maps[0].name, "/dev/ashmem/dalvik-main space (region space) (deleted)");
+  ASSERT_EQ(maps[876].start, 0x70e6c4f000ULL);
+  ASSERT_EQ(maps[876].end, 0x70e6c6b000ULL);
+  ASSERT_EQ(maps[876].flags, PROT_READ | PROT_EXEC);
+  ASSERT_EQ(maps[876].pgoff, 0ULL);
+  ASSERT_EQ(maps[876].name, "/system/lib64/libutils.so");
+  ASSERT_EQ(maps[1260].start, 0x70e96fa000ULL);
+  ASSERT_EQ(maps[1260].end, 0x70e96fb000ULL);
+  ASSERT_EQ(maps[1260].flags, PROT_READ);
+  ASSERT_EQ(maps[1260].pgoff, 0ULL);
+  ASSERT_EQ(maps[1260].name,
+            "/dev/ashmem/dalvik-classes.dex extracted in memory from "
+            "/data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/base.apk (deleted)");
+}
diff --git a/libprocinfo/testdata/maps b/libprocinfo/testdata/maps
new file mode 100644
index 0000000..3b312e3
--- /dev/null
+++ b/libprocinfo/testdata/maps
@@ -0,0 +1,2043 @@
+12c00000-2ac00000 rw-p 00000000 00:05 10267643                           /dev/ashmem/dalvik-main space (region space) (deleted)
+6fb5d000-6fd6e000 rw-p 00000000 103:1d 639511                            /data/dalvik-cache/arm64/system@framework@boot.art
+6fd6e000-6fd82000 r--p 00211000 103:1d 639511                            /data/dalvik-cache/arm64/system@framework@boot.art
+6fd82000-6fe47000 rw-p 00000000 103:1d 639514                            /data/dalvik-cache/arm64/system@framework@boot-core-libart.art
+6fe47000-6fe52000 r--p 000c5000 103:1d 639514                            /data/dalvik-cache/arm64/system@framework@boot-core-libart.art
+6fe52000-6fe84000 rw-p 00000000 103:1d 639517                            /data/dalvik-cache/arm64/system@framework@boot-conscrypt.art
+6fe84000-6fe87000 r--p 00032000 103:1d 639517                            /data/dalvik-cache/arm64/system@framework@boot-conscrypt.art
+6fe87000-6feb2000 rw-p 00000000 103:1d 639520                            /data/dalvik-cache/arm64/system@framework@boot-okhttp.art
+6feb2000-6feb5000 r--p 0002b000 103:1d 639520                            /data/dalvik-cache/arm64/system@framework@boot-okhttp.art
+6feb5000-6fef4000 rw-p 00000000 103:1d 639523                            /data/dalvik-cache/arm64/system@framework@boot-bouncycastle.art
+6fef4000-6fefb000 r--p 0003f000 103:1d 639523                            /data/dalvik-cache/arm64/system@framework@boot-bouncycastle.art
+6fefb000-6ff3f000 rw-p 00000000 103:1d 639526                            /data/dalvik-cache/arm64/system@framework@boot-apache-xml.art
+6ff3f000-6ff45000 r--p 00044000 103:1d 639526                            /data/dalvik-cache/arm64/system@framework@boot-apache-xml.art
+6ff45000-6ff7a000 rw-p 00000000 103:1d 639529                            /data/dalvik-cache/arm64/system@framework@boot-ext.art
+6ff7a000-6ff85000 r--p 00035000 103:1d 639529                            /data/dalvik-cache/arm64/system@framework@boot-ext.art
+6ff85000-70594000 rw-p 00000000 103:1d 639532                            /data/dalvik-cache/arm64/system@framework@boot-framework.art
+70594000-705cb000 r--p 0060f000 103:1d 639532                            /data/dalvik-cache/arm64/system@framework@boot-framework.art
+705cb000-7061f000 rw-p 00000000 103:1d 639535                            /data/dalvik-cache/arm64/system@framework@boot-telephony-common.art
+7061f000-70629000 r--p 00054000 103:1d 639535                            /data/dalvik-cache/arm64/system@framework@boot-telephony-common.art
+70629000-70635000 rw-p 00000000 103:1d 639538                            /data/dalvik-cache/arm64/system@framework@boot-voip-common.art
+70635000-70636000 r--p 0000c000 103:1d 639538                            /data/dalvik-cache/arm64/system@framework@boot-voip-common.art
+70636000-70644000 rw-p 00000000 103:1d 639541                            /data/dalvik-cache/arm64/system@framework@boot-ims-common.art
+70644000-70645000 r--p 0000e000 103:1d 639541                            /data/dalvik-cache/arm64/system@framework@boot-ims-common.art
+70645000-70648000 rw-p 00000000 103:1d 639544                            /data/dalvik-cache/arm64/system@framework@boot-android.hidl.base-V1.0-java.art
+70648000-7064c000 rw-p 00000000 103:1d 639547                            /data/dalvik-cache/arm64/system@framework@boot-android.hidl.manager-V1.0-java.art
+7064c000-7064d000 r--p 00004000 103:1d 639547                            /data/dalvik-cache/arm64/system@framework@boot-android.hidl.manager-V1.0-java.art
+7064d000-7064e000 rw-p 00000000 103:1d 639550                            /data/dalvik-cache/arm64/system@framework@boot-framework-oahl-backward-compatibility.art
+7064e000-70652000 rw-p 00000000 103:1d 639553                            /data/dalvik-cache/arm64/system@framework@boot-android.test.base.art
+70652000-70653000 r--p 00004000 103:1d 639553                            /data/dalvik-cache/arm64/system@framework@boot-android.test.base.art
+70653000-70654000 rw-p 00000000 103:1d 639556                            /data/dalvik-cache/arm64/system@framework@boot-com.google.vr.platform.art
+70654000-70655000 r--p 00001000 103:1d 639556                            /data/dalvik-cache/arm64/system@framework@boot-com.google.vr.platform.art
+70655000-70731000 r--p 00000000 fc:00 940                                /system/framework/arm64/boot.oat
+70731000-709ca000 r-xp 000dc000 fc:00 940                                /system/framework/arm64/boot.oat
+709ca000-709cb000 rw-p 00000000 00:00 0                                  [anon:.bss]
+709cb000-70e4c000 r--s 00000000 fc:00 961                                /system/framework/boot.vdex
+70e4c000-70e4d000 r--p 00375000 fc:00 940                                /system/framework/arm64/boot.oat
+70e4d000-70e4e000 rw-p 00376000 fc:00 940                                /system/framework/arm64/boot.oat
+70e4e000-70eab000 r--p 00000000 fc:00 916                                /system/framework/arm64/boot-core-libart.oat
+70eab000-70fad000 r-xp 0005d000 fc:00 916                                /system/framework/arm64/boot-core-libart.oat
+70fad000-70fae000 rw-p 00000000 00:00 0                                  [anon:.bss]
+70fae000-712a9000 r--s 00000000 fc:00 702                                /system/framework/boot-core-libart.vdex
+712a9000-712aa000 r--p 0015f000 fc:00 916                                /system/framework/arm64/boot-core-libart.oat
+712aa000-712ab000 rw-p 00160000 fc:00 916                                /system/framework/arm64/boot-core-libart.oat
+712ab000-712bb000 r--p 00000000 fc:00 941                                /system/framework/arm64/boot-conscrypt.oat
+712bb000-712e4000 r-xp 00010000 fc:00 941                                /system/framework/arm64/boot-conscrypt.oat
+712e4000-712e5000 rw-p 00000000 00:00 0                                  [anon:.bss]
+712e5000-71346000 r--s 00000000 fc:00 970                                /system/framework/boot-conscrypt.vdex
+71346000-71347000 r--p 00039000 fc:00 941                                /system/framework/arm64/boot-conscrypt.oat
+71347000-71348000 rw-p 0003a000 fc:00 941                                /system/framework/arm64/boot-conscrypt.oat
+71348000-71361000 r--p 00000000 fc:00 908                                /system/framework/arm64/boot-okhttp.oat
+71361000-713a3000 r-xp 00019000 fc:00 908                                /system/framework/arm64/boot-okhttp.oat
+713a3000-713a4000 rw-p 00000000 00:00 0                                  [anon:.bss]
+713a4000-71403000 r--s 00000000 fc:00 886                                /system/framework/boot-okhttp.vdex
+71403000-71404000 r--p 0005b000 fc:00 908                                /system/framework/arm64/boot-okhttp.oat
+71404000-71405000 rw-p 0005c000 fc:00 908                                /system/framework/arm64/boot-okhttp.oat
+71405000-71415000 r--p 00000000 fc:00 936                                /system/framework/arm64/boot-bouncycastle.oat
+71415000-71437000 r-xp 00010000 fc:00 936                                /system/framework/arm64/boot-bouncycastle.oat
+71437000-71438000 rw-p 00000000 00:00 0                                  [anon:.bss]
+71438000-7157b000 r--s 00000000 fc:00 1006                               /system/framework/boot-bouncycastle.vdex
+7157b000-7157c000 r--p 00032000 fc:00 936                                /system/framework/arm64/boot-bouncycastle.oat
+7157c000-7157d000 rw-p 00033000 fc:00 936                                /system/framework/arm64/boot-bouncycastle.oat
+7157d000-71583000 r--p 00000000 fc:00 932                                /system/framework/arm64/boot-apache-xml.oat
+71583000-71584000 r-xp 00006000 fc:00 932                                /system/framework/arm64/boot-apache-xml.oat
+71584000-716a7000 r--s 00000000 fc:00 883                                /system/framework/boot-apache-xml.vdex
+716a7000-716a8000 r--p 00007000 fc:00 932                                /system/framework/arm64/boot-apache-xml.oat
+716a8000-716a9000 rw-p 00008000 fc:00 932                                /system/framework/arm64/boot-apache-xml.oat
+716a9000-716b5000 r--p 00000000 fc:00 891                                /system/framework/arm64/boot-ext.oat
+716b5000-716cc000 r-xp 0000c000 fc:00 891                                /system/framework/arm64/boot-ext.oat
+716cc000-716cd000 rw-p 00000000 00:00 0                                  [anon:.bss]
+716cd000-717b8000 r--s 00000000 fc:00 879                                /system/framework/boot-ext.vdex
+717b8000-717b9000 r--p 00023000 fc:00 891                                /system/framework/arm64/boot-ext.oat
+717b9000-717ba000 rw-p 00024000 fc:00 891                                /system/framework/arm64/boot-ext.oat
+717ba000-71aeb000 r--p 00000000 fc:00 943                                /system/framework/arm64/boot-framework.oat
+71aeb000-72390000 r-xp 00331000 fc:00 943                                /system/framework/arm64/boot-framework.oat
+72390000-72396000 rw-p 00000000 00:00 0                                  [anon:.bss]
+72396000-73746000 r--s 00000000 fc:00 985                                /system/framework/boot-framework.vdex
+73746000-73747000 r--p 00bd6000 fc:00 943                                /system/framework/arm64/boot-framework.oat
+73747000-73748000 rw-p 00bd7000 fc:00 943                                /system/framework/arm64/boot-framework.oat
+73748000-73780000 r--p 00000000 fc:00 893                                /system/framework/arm64/boot-telephony-common.oat
+73780000-73818000 r-xp 00038000 fc:00 893                                /system/framework/arm64/boot-telephony-common.oat
+73818000-7381a000 rw-p 00000000 00:00 0                                  [anon:.bss]
+7381a000-73af0000 r--s 00000000 fc:00 697                                /system/framework/boot-telephony-common.vdex
+73af0000-73af1000 r--p 000d0000 fc:00 893                                /system/framework/arm64/boot-telephony-common.oat
+73af1000-73af2000 rw-p 000d1000 fc:00 893                                /system/framework/arm64/boot-telephony-common.oat
+73af2000-73af6000 r--p 00000000 fc:00 922                                /system/framework/arm64/boot-voip-common.oat
+73af6000-73af8000 r-xp 00004000 fc:00 922                                /system/framework/arm64/boot-voip-common.oat
+73af8000-73af9000 rw-p 00000000 00:00 0                                  [anon:.bss]
+73af9000-73b1e000 r--s 00000000 fc:00 959                                /system/framework/boot-voip-common.vdex
+73b1e000-73b1f000 r--p 00006000 fc:00 922                                /system/framework/arm64/boot-voip-common.oat
+73b1f000-73b20000 rw-p 00007000 fc:00 922                                /system/framework/arm64/boot-voip-common.oat
+73b20000-73b23000 r--p 00000000 fc:00 918                                /system/framework/arm64/boot-ims-common.oat
+73b23000-73b25000 r-xp 00003000 fc:00 918                                /system/framework/arm64/boot-ims-common.oat
+73b25000-73b26000 rw-p 00000000 00:00 0                                  [anon:.bss]
+73b26000-73b48000 r--s 00000000 fc:00 957                                /system/framework/boot-ims-common.vdex
+73b48000-73b49000 r--p 00005000 fc:00 918                                /system/framework/arm64/boot-ims-common.oat
+73b49000-73b4a000 rw-p 00006000 fc:00 918                                /system/framework/arm64/boot-ims-common.oat
+73b4a000-73b4d000 r--p 00000000 fc:00 909                                /system/framework/arm64/boot-android.hidl.base-V1.0-java.oat
+73b4d000-73b4e000 r-xp 00003000 fc:00 909                                /system/framework/arm64/boot-android.hidl.base-V1.0-java.oat
+73b4e000-73b55000 r--s 00000000 fc:00 972                                /system/framework/boot-android.hidl.base-V1.0-java.vdex
+73b55000-73b56000 r--p 00004000 fc:00 909                                /system/framework/arm64/boot-android.hidl.base-V1.0-java.oat
+73b56000-73b57000 rw-p 00005000 fc:00 909                                /system/framework/arm64/boot-android.hidl.base-V1.0-java.oat
+73b57000-73b5a000 r--p 00000000 fc:00 954                                /system/framework/arm64/boot-android.hidl.manager-V1.0-java.oat
+73b5a000-73b5c000 r-xp 00003000 fc:00 954                                /system/framework/arm64/boot-android.hidl.manager-V1.0-java.oat
+73b5c000-73b5d000 rw-p 00000000 00:00 0                                  [anon:.bss]
+73b5d000-73b68000 r--s 00000000 fc:00 704                                /system/framework/boot-android.hidl.manager-V1.0-java.vdex
+73b68000-73b69000 r--p 00005000 fc:00 954                                /system/framework/arm64/boot-android.hidl.manager-V1.0-java.oat
+73b69000-73b6a000 rw-p 00006000 fc:00 954                                /system/framework/arm64/boot-android.hidl.manager-V1.0-java.oat
+73b6a000-73b6d000 r--p 00000000 fc:00 904                                /system/framework/arm64/boot-framework-oahl-backward-compatibility.oat
+73b6d000-73b6e000 r-xp 00003000 fc:00 904                                /system/framework/arm64/boot-framework-oahl-backward-compatibility.oat
+73b6e000-73b6f000 r--s 00000000 fc:00 994                                /system/framework/boot-framework-oahl-backward-compatibility.vdex
+73b6f000-73b70000 r--p 00004000 fc:00 904                                /system/framework/arm64/boot-framework-oahl-backward-compatibility.oat
+73b70000-73b71000 rw-p 00005000 fc:00 904                                /system/framework/arm64/boot-framework-oahl-backward-compatibility.oat
+73b71000-73b75000 r--p 00000000 fc:00 896                                /system/framework/arm64/boot-android.test.base.oat
+73b75000-73b79000 r-xp 00004000 fc:00 896                                /system/framework/arm64/boot-android.test.base.oat
+73b79000-73b7a000 rw-p 00000000 00:00 0                                  [anon:.bss]
+73b7a000-73b82000 r--s 00000000 fc:00 706                                /system/framework/boot-android.test.base.vdex
+73b82000-73b83000 r--p 00008000 fc:00 896                                /system/framework/arm64/boot-android.test.base.oat
+73b83000-73b84000 rw-p 00009000 fc:00 896                                /system/framework/arm64/boot-android.test.base.oat
+73b84000-73b87000 r--p 00000000 fc:00 899                                /system/framework/arm64/boot-com.google.vr.platform.oat
+73b87000-73b88000 r-xp 00003000 fc:00 899                                /system/framework/arm64/boot-com.google.vr.platform.oat
+73b88000-73b89000 r--s 00000000 fc:00 884                                /system/framework/boot-com.google.vr.platform.vdex
+73b89000-73b8a000 r--p 00004000 fc:00 899                                /system/framework/arm64/boot-com.google.vr.platform.oat
+73b8a000-73b8b000 rw-p 00005000 fc:00 899                                /system/framework/arm64/boot-com.google.vr.platform.oat
+73b8b000-73b93000 rw-p 00000000 00:05 10267640                           /dev/ashmem/dalvik-non moving space (deleted)
+73b93000-77b8b000 ---p 00008000 00:05 10267640                           /dev/ashmem/dalvik-non moving space (deleted)
+77b8b000-97b8b000 rw-p 00000000 00:05 10267645                           /dev/ashmem/dalvik-free list large object space (deleted)
+97b8b000-99b8b000 rw-p 00000000 00:05 10270989                           /dev/ashmem/dalvik-data-code-cache (deleted)
+99b8b000-9bb8b000 r-xp 00000000 00:05 10270990                           /dev/ashmem/dalvik-jit-code-cache (deleted)
+ebad6000-ebad7000 ---p 00000000 00:05 10269717                           /dev/ashmem/dalvik-Sentinel fault page (deleted)
+7ffb6e000-7ffb76000 rw-s 000e5000 00:10 20630                            /dev/kgsl-3d0
+7ffb76000-7ffb78000 rw-s 000e0000 00:10 20630                            /dev/kgsl-3d0
+7ffbc3000-7ffbc4000 rw-s 000e8000 00:10 20630                            /dev/kgsl-3d0
+7ffbc4000-7ffbc5000 rw-s 000e7000 00:10 20630                            /dev/kgsl-3d0
+7ffbc6000-7ffbce000 rw-s 000e4000 00:10 20630                            /dev/kgsl-3d0
+7ffbd0000-7ffbd2000 rw-s 000df000 00:10 20630                            /dev/kgsl-3d0
+7ffbd2000-7ffbd4000 rw-s 000de000 00:10 20630                            /dev/kgsl-3d0
+7ffbd4000-7ffbd6000 rw-s 000dd000 00:10 20630                            /dev/kgsl-3d0
+7ffbd6000-7ffbd8000 rw-s 000dc000 00:10 20630                            /dev/kgsl-3d0
+7ffbd8000-7ffbda000 rw-s 000db000 00:10 20630                            /dev/kgsl-3d0
+7ffbda000-7ffbdc000 rw-s 000da000 00:10 20630                            /dev/kgsl-3d0
+7ffbdd000-7ffbde000 rw-s 000ec000 00:10 20630                            /dev/kgsl-3d0
+7ffbde000-7ffbe0000 rw-s 000d8000 00:10 20630                            /dev/kgsl-3d0
+7ffce1000-7ffce2000 rw-s 000e6000 00:10 20630                            /dev/kgsl-3d0
+7ffce2000-7ffce4000 rw-s 000d9000 00:10 20630                            /dev/kgsl-3d0
+7ffce4000-7ffce8000 rw-s 000d4000 00:10 20630                            /dev/kgsl-3d0
+7ffce8000-7ffcf8000 rw-s 000d2000 00:10 20630                            /dev/kgsl-3d0
+7ffcf8000-7ffd08000 rw-s 000d1000 00:10 20630                            /dev/kgsl-3d0
+7ffd08000-7ffd10000 rw-s 000d0000 00:10 20630                            /dev/kgsl-3d0
+7ffd14000-7ffd18000 rw-s 000cd000 00:10 20630                            /dev/kgsl-3d0
+7ffd18000-7ffd28000 rw-s 000cc000 00:10 20630                            /dev/kgsl-3d0
+7ffd28000-7ffd38000 rw-s 000cb000 00:10 20630                            /dev/kgsl-3d0
+7ffd38000-7ffd48000 rw-s 000ca000 00:10 20630                            /dev/kgsl-3d0
+7ffd48000-7ffd58000 rw-s 000c9000 00:10 20630                            /dev/kgsl-3d0
+7ffd58000-7ffd68000 rw-s 000c8000 00:10 20630                            /dev/kgsl-3d0
+7ffd68000-7ffd6c000 rw-s 000c7000 00:10 20630                            /dev/kgsl-3d0
+7ffdb1000-7ffdb2000 rw-s 000e3000 00:10 20630                            /dev/kgsl-3d0
+7ffdb4000-7ffdb5000 rw-s 000e2000 00:10 20630                            /dev/kgsl-3d0
+7ffdb5000-7ffdb7000 rw-s 000d7000 00:10 20630                            /dev/kgsl-3d0
+7ffdb7000-7ffdb8000 rw-s 000c2000 00:10 20630                            /dev/kgsl-3d0
+7ffdb8000-7ffdbc000 rw-s 000c0000 00:10 20630                            /dev/kgsl-3d0
+7ffdbc000-7ffdc0000 rw-s 000be000 00:10 20630                            /dev/kgsl-3d0
+7ffdc0000-7ffe00000 rw-s 000bb000 00:10 20630                            /dev/kgsl-3d0
+7ffe00000-7ffe20000 rw-s 000ba000 00:10 20630                            /dev/kgsl-3d0
+7ffe20000-7ffee0000 rw-s 000b9000 00:10 20630                            /dev/kgsl-3d0
+7ffee1000-7ffee3000 rw-s 000c1000 00:10 20630                            /dev/kgsl-3d0
+7ffee3000-7ffee4000 rw-s 000bf000 00:10 20630                            /dev/kgsl-3d0
+7ffee4000-7ffee8000 rw-s 000bd000 00:10 20630                            /dev/kgsl-3d0
+7ffee8000-7ffee9000 rw-s 000bc000 00:10 20630                            /dev/kgsl-3d0
+7ffeea000-7ffeeb000 rw-s 000e1000 00:10 20630                            /dev/kgsl-3d0
+7ffeeb000-7ffeec000 rw-s 000b6000 00:10 20630                            /dev/kgsl-3d0
+7ffeec000-7ffeed000 rw-s 000b5000 00:10 20630                            /dev/kgsl-3d0
+7ffeed000-7ffeee000 rw-s 000b4000 00:10 20630                            /dev/kgsl-3d0
+7ffeee000-7ffeef000 rw-s 000b3000 00:10 20630                            /dev/kgsl-3d0
+7ffeef000-7ffef0000 rw-s 000b2000 00:10 20630                            /dev/kgsl-3d0
+7ffef0000-7ffef1000 rw-s 000b1000 00:10 20630                            /dev/kgsl-3d0
+7ffef1000-7ffef2000 rw-s 000b0000 00:10 20630                            /dev/kgsl-3d0
+7ffef2000-7ffef3000 rw-s 000af000 00:10 20630                            /dev/kgsl-3d0
+7ffef3000-7ffef4000 rw-s 000ae000 00:10 20630                            /dev/kgsl-3d0
+7ffef4000-7ffef5000 rw-s 000ad000 00:10 20630                            /dev/kgsl-3d0
+7ffef5000-7ffef6000 rw-s 000ac000 00:10 20630                            /dev/kgsl-3d0
+7ffef6000-7ffef7000 rw-s 000ab000 00:10 20630                            /dev/kgsl-3d0
+7ffef7000-7ffef8000 rw-s 000aa000 00:10 20630                            /dev/kgsl-3d0
+7ffef8000-7ffef9000 rw-s 000a9000 00:10 20630                            /dev/kgsl-3d0
+7ffef9000-7ffefa000 rw-s 000a8000 00:10 20630                            /dev/kgsl-3d0
+7ffefa000-7ffefb000 rw-s 000a7000 00:10 20630                            /dev/kgsl-3d0
+7ffefb000-7ffefc000 rw-s 000a6000 00:10 20630                            /dev/kgsl-3d0
+7ffefc000-7ffefd000 rw-s 000a5000 00:10 20630                            /dev/kgsl-3d0
+7ffefd000-7ffefe000 rw-s 000a4000 00:10 20630                            /dev/kgsl-3d0
+7ffefe000-7ffeff000 rw-s 000a3000 00:10 20630                            /dev/kgsl-3d0
+7ffeff000-7fff00000 rw-s 000a2000 00:10 20630                            /dev/kgsl-3d0
+7fff00000-7fff01000 rw-s 000a1000 00:10 20630                            /dev/kgsl-3d0
+7fff01000-7fff02000 rw-s 000a0000 00:10 20630                            /dev/kgsl-3d0
+7fff02000-7fff03000 rw-s 0009f000 00:10 20630                            /dev/kgsl-3d0
+7fff03000-7fff04000 rw-s 0009e000 00:10 20630                            /dev/kgsl-3d0
+7fff04000-7fff05000 rw-s 0009d000 00:10 20630                            /dev/kgsl-3d0
+7fff05000-7fff06000 rw-s 0009c000 00:10 20630                            /dev/kgsl-3d0
+7fff06000-7fff07000 rw-s 0009b000 00:10 20630                            /dev/kgsl-3d0
+7fff07000-7fff08000 rw-s 0009a000 00:10 20630                            /dev/kgsl-3d0
+7fff08000-7fff09000 rw-s 00099000 00:10 20630                            /dev/kgsl-3d0
+7fff09000-7fff0a000 rw-s 00098000 00:10 20630                            /dev/kgsl-3d0
+7fff0a000-7fff0b000 rw-s 00097000 00:10 20630                            /dev/kgsl-3d0
+7fff0b000-7fff0c000 rw-s 00096000 00:10 20630                            /dev/kgsl-3d0
+7fff0c000-7fff0d000 rw-s 00095000 00:10 20630                            /dev/kgsl-3d0
+7fff0d000-7fff0e000 rw-s 00094000 00:10 20630                            /dev/kgsl-3d0
+7fff0e000-7fff0f000 rw-s 00093000 00:10 20630                            /dev/kgsl-3d0
+7fff0f000-7fff10000 rw-s 00092000 00:10 20630                            /dev/kgsl-3d0
+7fff10000-7fff11000 rw-s 00091000 00:10 20630                            /dev/kgsl-3d0
+7fff11000-7fff12000 rw-s 00090000 00:10 20630                            /dev/kgsl-3d0
+7fff12000-7fff13000 rw-s 0008f000 00:10 20630                            /dev/kgsl-3d0
+7fff13000-7fff14000 rw-s 0008e000 00:10 20630                            /dev/kgsl-3d0
+7fff14000-7fff15000 rw-s 0008d000 00:10 20630                            /dev/kgsl-3d0
+7fff15000-7fff16000 rw-s 0008c000 00:10 20630                            /dev/kgsl-3d0
+7fff16000-7fff17000 rw-s 0008b000 00:10 20630                            /dev/kgsl-3d0
+7fff17000-7fff18000 rw-s 0008a000 00:10 20630                            /dev/kgsl-3d0
+7fff18000-7fff19000 rw-s 00089000 00:10 20630                            /dev/kgsl-3d0
+7fff19000-7fff1a000 rw-s 00088000 00:10 20630                            /dev/kgsl-3d0
+7fff1a000-7fff1b000 rw-s 00087000 00:10 20630                            /dev/kgsl-3d0
+7fff1b000-7fff1c000 rw-s 00086000 00:10 20630                            /dev/kgsl-3d0
+7fff1c000-7fff1d000 rw-s 00085000 00:10 20630                            /dev/kgsl-3d0
+7fff1d000-7fff1e000 rw-s 00084000 00:10 20630                            /dev/kgsl-3d0
+7fff1e000-7fff1f000 rw-s 00083000 00:10 20630                            /dev/kgsl-3d0
+7fff1f000-7fff20000 rw-s 00082000 00:10 20630                            /dev/kgsl-3d0
+7fff20000-7fff21000 rw-s 00081000 00:10 20630                            /dev/kgsl-3d0
+7fff21000-7fff22000 rw-s 00080000 00:10 20630                            /dev/kgsl-3d0
+7fff22000-7fff23000 rw-s 0007f000 00:10 20630                            /dev/kgsl-3d0
+7fff23000-7fff24000 rw-s 0007e000 00:10 20630                            /dev/kgsl-3d0
+7fff24000-7fff25000 rw-s 0007d000 00:10 20630                            /dev/kgsl-3d0
+7fff25000-7fff26000 rw-s 0007c000 00:10 20630                            /dev/kgsl-3d0
+7fff26000-7fff27000 rw-s 0007b000 00:10 20630                            /dev/kgsl-3d0
+7fff27000-7fff28000 rw-s 0007a000 00:10 20630                            /dev/kgsl-3d0
+7fff28000-7fff29000 rw-s 00079000 00:10 20630                            /dev/kgsl-3d0
+7fff29000-7fff2a000 rw-s 00078000 00:10 20630                            /dev/kgsl-3d0
+7fff2a000-7fff2b000 rw-s 00077000 00:10 20630                            /dev/kgsl-3d0
+7fff2b000-7fff2c000 rw-s 00076000 00:10 20630                            /dev/kgsl-3d0
+7fff2c000-7fff2d000 rw-s 00075000 00:10 20630                            /dev/kgsl-3d0
+7fff2d000-7fff2e000 rw-s 00074000 00:10 20630                            /dev/kgsl-3d0
+7fff2e000-7fff2f000 rw-s 00073000 00:10 20630                            /dev/kgsl-3d0
+7fff2f000-7fff30000 rw-s 00072000 00:10 20630                            /dev/kgsl-3d0
+7fff30000-7fff31000 rw-s 00071000 00:10 20630                            /dev/kgsl-3d0
+7fff31000-7fff32000 rw-s 00070000 00:10 20630                            /dev/kgsl-3d0
+7fff32000-7fff33000 rw-s 0006f000 00:10 20630                            /dev/kgsl-3d0
+7fff33000-7fff34000 rw-s 0006e000 00:10 20630                            /dev/kgsl-3d0
+7fff34000-7fff35000 rw-s 0006d000 00:10 20630                            /dev/kgsl-3d0
+7fff35000-7fff36000 rw-s 0006c000 00:10 20630                            /dev/kgsl-3d0
+7fff36000-7fff37000 rw-s 0006b000 00:10 20630                            /dev/kgsl-3d0
+7fff37000-7fff38000 rw-s 0006a000 00:10 20630                            /dev/kgsl-3d0
+7fff38000-7fff39000 rw-s 00069000 00:10 20630                            /dev/kgsl-3d0
+7fff39000-7fff3a000 rw-s 00068000 00:10 20630                            /dev/kgsl-3d0
+7fff3a000-7fff3b000 rw-s 00067000 00:10 20630                            /dev/kgsl-3d0
+7fff3b000-7fff3c000 rw-s 00066000 00:10 20630                            /dev/kgsl-3d0
+7fff3c000-7fff3d000 rw-s 00065000 00:10 20630                            /dev/kgsl-3d0
+7fff3d000-7fff3e000 rw-s 00064000 00:10 20630                            /dev/kgsl-3d0
+7fff3e000-7fff3f000 rw-s 00063000 00:10 20630                            /dev/kgsl-3d0
+7fff3f000-7fff40000 rw-s 00062000 00:10 20630                            /dev/kgsl-3d0
+7fff40000-7fff41000 rw-s 00061000 00:10 20630                            /dev/kgsl-3d0
+7fff41000-7fff42000 rw-s 00060000 00:10 20630                            /dev/kgsl-3d0
+7fff42000-7fff43000 rw-s 0005f000 00:10 20630                            /dev/kgsl-3d0
+7fff43000-7fff44000 rw-s 0005e000 00:10 20630                            /dev/kgsl-3d0
+7fff44000-7fff45000 rw-s 0005d000 00:10 20630                            /dev/kgsl-3d0
+7fff45000-7fff46000 rw-s 0005c000 00:10 20630                            /dev/kgsl-3d0
+7fff46000-7fff47000 rw-s 0005b000 00:10 20630                            /dev/kgsl-3d0
+7fff47000-7fff48000 rw-s 0005a000 00:10 20630                            /dev/kgsl-3d0
+7fff48000-7fff49000 rw-s 00059000 00:10 20630                            /dev/kgsl-3d0
+7fff49000-7fff4a000 rw-s 00058000 00:10 20630                            /dev/kgsl-3d0
+7fff4a000-7fff4b000 rw-s 00057000 00:10 20630                            /dev/kgsl-3d0
+7fff4b000-7fff4c000 rw-s 00056000 00:10 20630                            /dev/kgsl-3d0
+7fff4c000-7fff4d000 rw-s 00055000 00:10 20630                            /dev/kgsl-3d0
+7fff4d000-7fff4e000 rw-s 00054000 00:10 20630                            /dev/kgsl-3d0
+7fff4e000-7fff4f000 rw-s 00053000 00:10 20630                            /dev/kgsl-3d0
+7fff4f000-7fff50000 rw-s 00052000 00:10 20630                            /dev/kgsl-3d0
+7fff50000-7fff51000 rw-s 00051000 00:10 20630                            /dev/kgsl-3d0
+7fff51000-7fff52000 rw-s 00050000 00:10 20630                            /dev/kgsl-3d0
+7fff52000-7fff53000 rw-s 0004f000 00:10 20630                            /dev/kgsl-3d0
+7fff53000-7fff54000 rw-s 0004e000 00:10 20630                            /dev/kgsl-3d0
+7fff54000-7fff55000 rw-s 0004d000 00:10 20630                            /dev/kgsl-3d0
+7fff55000-7fff56000 rw-s 0004c000 00:10 20630                            /dev/kgsl-3d0
+7fff56000-7fff57000 rw-s 0004b000 00:10 20630                            /dev/kgsl-3d0
+7fff57000-7fff58000 rw-s 0004a000 00:10 20630                            /dev/kgsl-3d0
+7fff58000-7fff59000 rw-s 00049000 00:10 20630                            /dev/kgsl-3d0
+7fff59000-7fff5a000 rw-s 00048000 00:10 20630                            /dev/kgsl-3d0
+7fff5a000-7fff5b000 rw-s 00047000 00:10 20630                            /dev/kgsl-3d0
+7fff5b000-7fff5c000 rw-s 00046000 00:10 20630                            /dev/kgsl-3d0
+7fff5c000-7fff5d000 rw-s 00045000 00:10 20630                            /dev/kgsl-3d0
+7fff5d000-7fff5e000 rw-s 00044000 00:10 20630                            /dev/kgsl-3d0
+7fff5e000-7fff5f000 rw-s 00043000 00:10 20630                            /dev/kgsl-3d0
+7fff5f000-7fff60000 rw-s 00042000 00:10 20630                            /dev/kgsl-3d0
+7fff60000-7fff61000 rw-s 00041000 00:10 20630                            /dev/kgsl-3d0
+7fff61000-7fff62000 rw-s 00040000 00:10 20630                            /dev/kgsl-3d0
+7fff62000-7fff63000 rw-s 0003f000 00:10 20630                            /dev/kgsl-3d0
+7fff63000-7fff64000 rw-s 0003e000 00:10 20630                            /dev/kgsl-3d0
+7fff64000-7fff65000 rw-s 0003d000 00:10 20630                            /dev/kgsl-3d0
+7fff65000-7fff66000 rw-s 0003c000 00:10 20630                            /dev/kgsl-3d0
+7fff66000-7fff67000 rw-s 0003b000 00:10 20630                            /dev/kgsl-3d0
+7fff67000-7fff68000 rw-s 0003a000 00:10 20630                            /dev/kgsl-3d0
+7fff68000-7fff69000 rw-s 00039000 00:10 20630                            /dev/kgsl-3d0
+7fff69000-7fff6a000 rw-s 00038000 00:10 20630                            /dev/kgsl-3d0
+7fff6a000-7fff6b000 rw-s 00037000 00:10 20630                            /dev/kgsl-3d0
+7fff6b000-7fff6c000 rw-s 00036000 00:10 20630                            /dev/kgsl-3d0
+7fff6c000-7fff6d000 rw-s 00035000 00:10 20630                            /dev/kgsl-3d0
+7fff6d000-7fff6e000 rw-s 00034000 00:10 20630                            /dev/kgsl-3d0
+7fff6e000-7fff6f000 rw-s 00033000 00:10 20630                            /dev/kgsl-3d0
+7fff6f000-7fff70000 rw-s 00032000 00:10 20630                            /dev/kgsl-3d0
+7fff70000-7fff71000 rw-s 00031000 00:10 20630                            /dev/kgsl-3d0
+7fff71000-7fff72000 rw-s 00030000 00:10 20630                            /dev/kgsl-3d0
+7fff72000-7fff73000 rw-s 0002f000 00:10 20630                            /dev/kgsl-3d0
+7fff73000-7fff74000 rw-s 0002e000 00:10 20630                            /dev/kgsl-3d0
+7fff74000-7fff75000 rw-s 0002d000 00:10 20630                            /dev/kgsl-3d0
+7fff75000-7fff76000 rw-s 0002c000 00:10 20630                            /dev/kgsl-3d0
+7fff76000-7fff77000 rw-s 0002b000 00:10 20630                            /dev/kgsl-3d0
+7fff77000-7fff78000 rw-s 0002a000 00:10 20630                            /dev/kgsl-3d0
+7fff78000-7fff79000 rw-s 00029000 00:10 20630                            /dev/kgsl-3d0
+7fff79000-7fff7a000 rw-s 00028000 00:10 20630                            /dev/kgsl-3d0
+7fff7a000-7fff7b000 rw-s 00027000 00:10 20630                            /dev/kgsl-3d0
+7fff7b000-7fff7c000 rw-s 00026000 00:10 20630                            /dev/kgsl-3d0
+7fff7c000-7fff7d000 rw-s 00025000 00:10 20630                            /dev/kgsl-3d0
+7fff7d000-7fff7e000 rw-s 00024000 00:10 20630                            /dev/kgsl-3d0
+7fff7e000-7fff7f000 rw-s 00023000 00:10 20630                            /dev/kgsl-3d0
+7fff7f000-7fff80000 rw-s 00022000 00:10 20630                            /dev/kgsl-3d0
+7fff80000-7fff90000 rw-s 00019000 00:10 20630                            /dev/kgsl-3d0
+7fff90000-7fffb0000 rw-s 00018000 00:10 20630                            /dev/kgsl-3d0
+7fffb1000-7fffb2000 rw-s 00021000 00:10 20630                            /dev/kgsl-3d0
+7fffb2000-7fffb3000 rw-s 00020000 00:10 20630                            /dev/kgsl-3d0
+7fffb3000-7fffb4000 rw-s 0001f000 00:10 20630                            /dev/kgsl-3d0
+7fffba000-7fffbe000 rw-s 0001b000 00:10 20630                            /dev/kgsl-3d0
+7fffbe000-7fffbf000 rw-s 0001a000 00:10 20630                            /dev/kgsl-3d0
+7fffbf000-7fffc0000 rw-s 00017000 00:10 20630                            /dev/kgsl-3d0
+7fffc0000-7fffe0000 rw-s 00016000 00:10 20630                            /dev/kgsl-3d0
+7fffe0000-7fffe1000 rw-s 00014000 00:10 20630                            /dev/kgsl-3d0
+7fffe1000-7fffe5000 rw-s 00013000 00:10 20630                            /dev/kgsl-3d0
+7fffe5000-7fffe6000 rw-s 00012000 00:10 20630                            /dev/kgsl-3d0
+7fffe6000-7fffe7000 rw-s 00011000 00:10 20630                            /dev/kgsl-3d0
+7fffe7000-7fffe8000 rw-s 00010000 00:10 20630                            /dev/kgsl-3d0
+7fffe8000-7fffe9000 rw-s 0000f000 00:10 20630                            /dev/kgsl-3d0
+7fffe9000-7fffea000 rw-s 0000e000 00:10 20630                            /dev/kgsl-3d0
+7fffea000-7fffeb000 rw-s 0000d000 00:10 20630                            /dev/kgsl-3d0
+7fffeb000-7fffec000 rw-s 0000c000 00:10 20630                            /dev/kgsl-3d0
+7fffec000-7ffff0000 rw-s 0000b000 00:10 20630                            /dev/kgsl-3d0
+7ffff0000-7ffff1000 rw-s 0000a000 00:10 20630                            /dev/kgsl-3d0
+7ffff1000-7ffff5000 rw-s 00009000 00:10 20630                            /dev/kgsl-3d0
+7ffff5000-7ffff6000 rw-s 00008000 00:10 20630                            /dev/kgsl-3d0
+7ffff6000-7ffff7000 rw-s 00007000 00:10 20630                            /dev/kgsl-3d0
+7ffff7000-7ffff8000 rw-s 00006000 00:10 20630                            /dev/kgsl-3d0
+7ffff8000-7ffff9000 rw-s 00005000 00:10 20630                            /dev/kgsl-3d0
+7ffff9000-7ffffa000 rw-s 00004000 00:10 20630                            /dev/kgsl-3d0
+7ffffa000-7ffffb000 rw-s 00003000 00:10 20630                            /dev/kgsl-3d0
+7ffffb000-7ffffc000 rw-s 00002000 00:10 20630                            /dev/kgsl-3d0
+7ffffc000-800000000 rw-s 00001000 00:10 20630                            /dev/kgsl-3d0
+5ff1d4f000-5ff1d54000 r-xp 00000000 fc:00 3419                           /system/bin/app_process64
+5ff1d6e000-5ff1d6f000 r--p 0000f000 fc:00 3419                           /system/bin/app_process64
+5ff1d6f000-5ff1d71000 rw-p 00000000 00:00 0 
+704defa000-704defb000 ---p 00000000 00:00 0                              [anon:thread stack guard]
+704defb000-704defc000 ---p 00000000 00:00 0 
+704defc000-704e000000 rw-p 00000000 00:00 0 
+704e000000-704e400000 rw-p 00000000 00:00 0                              [anon:libc_malloc]
+704e455000-704e456000 ---p 00000000 00:00 0                              [anon:thread stack guard]
+704e456000-704e457000 ---p 00000000 00:00 0 
+704e457000-704e553000 rw-p 00000000 00:00 0 
+704e553000-704e651000 r--p 00000000 00:10 16029                          /dev/hwbinder
+704e651000-704e65f000 r-xp 00000000 fc:01 1040                           /vendor/lib64/egl/eglSubDriverAndroid.so
+704e65f000-704e660000 r--p 0000e000 fc:01 1040                           /vendor/lib64/egl/eglSubDriverAndroid.so
+704e660000-704e661000 rw-p 0000f000 fc:01 1040                           /vendor/lib64/egl/eglSubDriverAndroid.so
+704e69d000-704e69e000 ---p 00000000 00:00 0                              [anon:thread stack guard]
+704e69e000-704e79b000 rw-p 00000000 00:00 0 
+704e79b000-704f79b000 rw-s 00000000 00:05 10271021                       /dev/ashmem/AudioFlinger::Client(29312) (deleted)
+704f79b000-704f79c000 ---p 00000000 00:00 0                              [anon:thread stack guard]
+704f79c000-704f899000 rw-p 00000000 00:00 0 
+704f899000-704f89a000 ---p 00000000 00:00 0                              [anon:thread stack guard]
+704f89a000-704f89b000 ---p 00000000 00:00 0 
+704f89b000-704f997000 rw-p 00000000 00:00 0 
+704f997000-704f9ee000 r-xp 00000000 103:1d 1737338                       /data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/lib/arm64/libgame.so
+704f9ee000-704f9fd000 ---p 00000000 00:00 0 
+704f9fd000-704fa00000 r--p 00056000 103:1d 1737338                       /data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/lib/arm64/libgame.so
+704fa00000-704fa01000 rw-p 00059000 103:1d 1737338                       /data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/lib/arm64/libgame.so
+704fa01000-704fa19000 rw-p 00000000 00:00 0                              [anon:.bss]
+704fa40000-70507e7000 r-xp 00000000 fc:01 1026                           /vendor/lib64/libllvm-glnext.so
+70507e7000-70507fc000 ---p 00000000 00:00 0 
+70507fc000-7050835000 r--p 00da7000 fc:01 1026                           /vendor/lib64/libllvm-glnext.so
+7050835000-705083a000 rw-p 00de0000 fc:01 1026                           /vendor/lib64/libllvm-glnext.so
+705083a000-7050855000 rw-p 00000000 00:00 0                              [anon:.bss]
+705089b000-7050f19000 r-xp 00000000 fc:01 1039                           /vendor/lib64/egl/libGLESv2_adreno.so
+7050f19000-7050f22000 r--p 0067e000 fc:01 1039                           /vendor/lib64/egl/libGLESv2_adreno.so
+7050f22000-7050f29000 rw-p 00687000 fc:01 1039                           /vendor/lib64/egl/libGLESv2_adreno.so
+7050f29000-7050f2c000 rw-p 00000000 00:00 0                              [anon:.bss]
+7050f83000-7050fbc000 r-xp 00000000 fc:01 1041                           /vendor/lib64/egl/libGLESv1_CM_adreno.so
+7050fbc000-7050fbd000 r--p 00039000 fc:01 1041                           /vendor/lib64/egl/libGLESv1_CM_adreno.so
+7050fbd000-7050fbe000 rw-p 0003a000 fc:01 1041                           /vendor/lib64/egl/libGLESv1_CM_adreno.so
+7050fbe000-7050fbf000 rw-p 00000000 00:00 0                              [anon:.bss]
+7050fc6000-705111d000 r-xp 00000000 fc:01 865                            /vendor/lib64/libgsl.so
+705111d000-705111e000 r--p 00157000 fc:01 865                            /vendor/lib64/libgsl.so
+705111e000-705111f000 rw-p 00158000 fc:01 865                            /vendor/lib64/libgsl.so
+705111f000-7051120000 rw-p 00000000 00:00 0                              [anon:.bss]
+7051146000-705115d000 r-xp 00000000 fc:00 2587                           /system/lib64/vndk-sp-28/libz.so
+705115d000-7051175000 ---p 00000000 00:00 0 
+7051175000-7051176000 r--p 0001f000 fc:00 2587                           /system/lib64/vndk-sp-28/libz.so
+7051176000-7051177000 rw-p 00020000 fc:00 2587                           /system/lib64/vndk-sp-28/libz.so
+705119f000-70511ac000 r-xp 00000000 fc:01 886                            /vendor/lib64/libadreno_utils.so
+70511ac000-70511ad000 r--p 0000d000 fc:01 886                            /vendor/lib64/libadreno_utils.so
+70511ad000-70511ae000 rw-p 0000e000 fc:01 886                            /vendor/lib64/libadreno_utils.so
+70511ae000-70511b0000 rw-p 00000000 00:00 0                              [anon:.bss]
+70511c0000-70511d7000 r-xp 00000000 fc:01 1044                           /vendor/lib64/egl/libEGL_adreno.so
+70511d7000-70511d8000 r--p 00017000 fc:01 1044                           /vendor/lib64/egl/libEGL_adreno.so
+70511d8000-70511d9000 rw-p 00018000 fc:01 1044                           /vendor/lib64/egl/libEGL_adreno.so
+70511d9000-70511da000 rw-p 00000000 00:00 0                              [anon:.bss]
+705120a000-705120d000 r-xp 00000000 fc:01 972                            /vendor/lib64/libdrmutils.so
+705120d000-7051229000 ---p 00000000 00:00 0 
+7051229000-705122a000 r--p 0000f000 fc:01 972                            /vendor/lib64/libdrmutils.so
+705122a000-705122b000 rw-p 00010000 fc:01 972                            /vendor/lib64/libdrmutils.so
+705125a000-705125c000 r-xp 00000000 fc:01 1046                           /vendor/lib64/libqdMetaData.so
+705125c000-7051279000 ---p 00000000 00:00 0 
+7051279000-705127a000 r--p 0000f000 fc:01 1046                           /vendor/lib64/libqdMetaData.so
+705127a000-705127b000 rw-p 00010000 fc:01 1046                           /vendor/lib64/libqdMetaData.so
+7051286000-7051297000 r-xp 00000000 fc:01 1024                           /vendor/lib64/libdrm.so
+7051297000-70512b5000 ---p 00000000 00:00 0 
+70512b5000-70512b6000 r--p 0001f000 fc:01 1024                           /vendor/lib64/libdrm.so
+70512b6000-70512b7000 rw-p 00020000 fc:01 1024                           /vendor/lib64/libdrm.so
+70512cb000-70512de000 r-xp 00000000 fc:01 1008                           /vendor/lib64/hw/gralloc.msm8998.so
+70512de000-70512fa000 ---p 00000000 00:00 0 
+70512fa000-70512fb000 r--p 0001f000 fc:01 1008                           /vendor/lib64/hw/gralloc.msm8998.so
+70512fb000-70512fc000 rw-p 00020000 fc:01 1008                           /vendor/lib64/hw/gralloc.msm8998.so
+7051326000-7051327000 ---p 00000000 00:00 0                              [anon:thread stack guard]
+7051327000-7051328000 ---p 00000000 00:00 0 
+7051328000-7051424000 rw-p 00000000 00:00 0 
+7051424000-705143d000 r--p 00000000 fc:00 739                            /system/framework/oat/arm64/org.apache.http.legacy.boot.odex
+705143d000-7051480000 r-xp 00019000 fc:00 739                            /system/framework/oat/arm64/org.apache.http.legacy.boot.odex
+7051480000-7051494000 r--p 00211000 103:1d 639511                        /data/dalvik-cache/arm64/system@framework@boot.art
+7051494000-705149f000 r--p 000c5000 103:1d 639514                        /data/dalvik-cache/arm64/system@framework@boot-core-libart.art
+705149f000-70514a2000 r--p 00032000 103:1d 639517                        /data/dalvik-cache/arm64/system@framework@boot-conscrypt.art
+70514a2000-70514a5000 r--p 0002b000 103:1d 639520                        /data/dalvik-cache/arm64/system@framework@boot-okhttp.art
+70514a5000-70514ac000 r--p 0003f000 103:1d 639523                        /data/dalvik-cache/arm64/system@framework@boot-bouncycastle.art
+70514ac000-70514b2000 r--p 00044000 103:1d 639526                        /data/dalvik-cache/arm64/system@framework@boot-apache-xml.art
+70514b2000-70514bd000 r--p 00035000 103:1d 639529                        /data/dalvik-cache/arm64/system@framework@boot-ext.art
+70514bd000-70514f4000 r--p 0060f000 103:1d 639532                        /data/dalvik-cache/arm64/system@framework@boot-framework.art
+70514f4000-70514fe000 r--p 00054000 103:1d 639535                        /data/dalvik-cache/arm64/system@framework@boot-telephony-common.art
+70514fe000-70514ff000 r--p 0000c000 103:1d 639538                        /data/dalvik-cache/arm64/system@framework@boot-voip-common.art
+70514ff000-7051500000 r--p 0000e000 103:1d 639541                        /data/dalvik-cache/arm64/system@framework@boot-ims-common.art
+7051500000-7051501000 r--p 00004000 103:1d 639547                        /data/dalvik-cache/arm64/system@framework@boot-android.hidl.manager-V1.0-java.art
+7051501000-7051502000 r--p 00004000 103:1d 639553                        /data/dalvik-cache/arm64/system@framework@boot-android.test.base.art
+7051502000-7051503000 r--p 00001000 103:1d 639556                        /data/dalvik-cache/arm64/system@framework@boot-com.google.vr.platform.art
+7051503000-7051504000 rw-p 00000000 00:00 0                              [anon:.bss]
+7051504000-7051579000 r--s 00000000 fc:00 790                            /system/framework/oat/arm64/org.apache.http.legacy.boot.vdex
+7051579000-705157a000 r--p 0005c000 fc:00 739                            /system/framework/oat/arm64/org.apache.http.legacy.boot.odex
+705157a000-705157b000 rw-p 0005d000 fc:00 739                            /system/framework/oat/arm64/org.apache.http.legacy.boot.odex
+705158b000-7057f4d000 ---p 00000000 00:00 0 
+7057f4d000-7057f4f000 r-xp 00000000 fc:00 2646                           /system/lib64/libwebviewchromium_loader.so
+7057f4f000-7057f6c000 ---p 00000000 00:00 0 
+7057f6c000-7057f6d000 r--p 0000f000 fc:00 2646                           /system/lib64/libwebviewchromium_loader.so
+7057f6d000-7057f6e000 rw-p 00010000 fc:00 2646                           /system/lib64/libwebviewchromium_loader.so
+7057f76000-7057f96000 r--s 00000000 00:10 16615                          /dev/__properties__/u:object_r:hwservicemanager_prop:s0
+7057f96000-7057fb6000 r--s 00000000 00:10 16639                          /dev/__properties__/u:object_r:public_vendor_default_prop:s0
+7057fb6000-7058004000 r--s 00000000 fc:00 1112                           /system/usr/hyphen-data/hyph-hu.hyb
+7058004000-7058024000 r-xp 00000000 fc:00 2354                           /system/lib64/libcompiler_rt.so
+7058024000-7058043000 ---p 00000000 00:00 0 
+7058043000-7058044000 r--p 0002f000 fc:00 2354                           /system/lib64/libcompiler_rt.so
+7058044000-7058045000 rw-p 00030000 fc:00 2354                           /system/lib64/libcompiler_rt.so
+7058045000-70580b2000 rw-p 00000000 00:00 0                              [anon:.bss]
+70580bd000-70580dd000 rw-p 00000000 00:05 10265386                       /dev/ashmem/dalvik-LinearAlloc (deleted)
+70580dd000-70580df000 r-xp 00000000 fc:00 2597                           /system/lib64/vndk-sp-28/libhardware.so
+70580df000-70580fc000 ---p 00000000 00:00 0 
+70580fc000-70580fd000 r--p 0000f000 fc:00 2597                           /system/lib64/vndk-sp-28/libhardware.so
+70580fd000-70580fe000 rw-p 00010000 fc:00 2597                           /system/lib64/vndk-sp-28/libhardware.so
+705810e000-705811f000 r-xp 00000000 fc:00 2589                           /system/lib64/vndk-sp-28/libbase.so
+705811f000-705813d000 ---p 00000000 00:00 0 
+705813d000-705813e000 r--p 0001f000 fc:00 2589                           /system/lib64/vndk-sp-28/libbase.so
+705813e000-705813f000 rw-p 00020000 fc:00 2589                           /system/lib64/vndk-sp-28/libbase.so
+7058140000-7058167000 r-xp 00000000 fc:00 2572                           /system/lib64/vndk-sp-28/libhwbinder.so
+7058167000-705817d000 ---p 00000000 00:00 0 
+705817d000-705817f000 r--p 0002e000 fc:00 2572                           /system/lib64/vndk-sp-28/libhwbinder.so
+705817f000-7058180000 rw-p 00030000 fc:00 2572                           /system/lib64/vndk-sp-28/libhwbinder.so
+705818c000-705818d000 r-xp 00000000 fc:00 2584                           /system/lib64/vndk-sp-28/android.hardware.graphics.common@1.0.so
+705818d000-70581ab000 ---p 00000000 00:00 0 
+70581ab000-70581ac000 r--p 0000f000 fc:00 2584                           /system/lib64/vndk-sp-28/android.hardware.graphics.common@1.0.so
+70581ac000-70581ad000 rw-p 00010000 fc:00 2584                           /system/lib64/vndk-sp-28/android.hardware.graphics.common@1.0.so
+70581b7000-70581d7000 r--s 00000000 00:10 16619                          /dev/__properties__/u:object_r:log_prop:s0
+70581d7000-7058237000 r-xp 00000000 fc:00 2574                           /system/lib64/vndk-sp-28/libhidltransport.so
+7058237000-7058255000 ---p 00000000 00:00 0 
+7058255000-705825d000 r--p 00068000 fc:00 2574                           /system/lib64/vndk-sp-28/libhidltransport.so
+705825d000-705825e000 rw-p 00070000 fc:00 2574                           /system/lib64/vndk-sp-28/libhidltransport.so
+7058260000-7058284000 r--s 00000000 fc:00 1138                           /system/usr/hyphen-data/hyph-nn.hyb
+7058284000-70582a0000 r-xp 00000000 fc:00 2576                           /system/lib64/vndk-sp-28/libutils.so
+70582a0000-70582b3000 ---p 00000000 00:00 0 
+70582b3000-70582b4000 r--p 0001f000 fc:00 2576                           /system/lib64/vndk-sp-28/libutils.so
+70582b4000-70582b5000 rw-p 00020000 fc:00 2576                           /system/lib64/vndk-sp-28/libutils.so
+70582c4000-7058391000 r-xp 00000000 fc:00 2568                           /system/lib64/vndk-sp-28/libc++.so
+7058391000-70583ad000 ---p 00000000 00:00 0 
+70583ad000-70583b7000 r--p 000d6000 fc:00 2568                           /system/lib64/vndk-sp-28/libc++.so
+70583b7000-70583b8000 rw-p 000e0000 fc:00 2568                           /system/lib64/vndk-sp-28/libc++.so
+70583b8000-70583bb000 rw-p 00000000 00:00 0                              [anon:.bss]
+70583cd000-70583e4000 r-xp 00000000 fc:00 2580                           /system/lib64/vndk-sp-28/android.hardware.graphics.mapper@2.0.so
+70583e4000-70583f9000 ---p 00000000 00:00 0 
+70583f9000-70583fb000 r--p 0001e000 fc:00 2580                           /system/lib64/vndk-sp-28/android.hardware.graphics.mapper@2.0.so
+70583fb000-70583fc000 rw-p 00020000 fc:00 2580                           /system/lib64/vndk-sp-28/android.hardware.graphics.mapper@2.0.so
+705841b000-7058421000 r-xp 00000000 fc:01 1001                           /vendor/lib64/hw/android.hardware.graphics.mapper@2.0-impl.so
+7058421000-705843a000 ---p 00000000 00:00 0 
+705843a000-705843b000 r--p 0000f000 fc:01 1001                           /vendor/lib64/hw/android.hardware.graphics.mapper@2.0-impl.so
+705843b000-705843c000 rw-p 00010000 fc:01 1001                           /vendor/lib64/hw/android.hardware.graphics.mapper@2.0-impl.so
+705844f000-7058473000 r--s 00000000 fc:00 1150                           /system/usr/hyphen-data/hyph-nb.hyb
+7058473000-7058495000 r-xp 00000000 fc:00 2582                           /system/lib64/vndk-sp-28/libhidlbase.so
+7058495000-70584b1000 ---p 00000000 00:00 0 
+70584b1000-70584b3000 r--p 0002e000 fc:00 2582                           /system/lib64/vndk-sp-28/libhidlbase.so
+70584b3000-70584b4000 rw-p 00030000 fc:00 2582                           /system/lib64/vndk-sp-28/libhidlbase.so
+70584cd000-70584df000 r-xp 00000000 fc:00 2595                           /system/lib64/vndk-sp-28/libcutils.so
+70584df000-70584fb000 ---p 00000000 00:00 0 
+70584fb000-70584fd000 r--p 0001e000 fc:00 2595                           /system/lib64/vndk-sp-28/libcutils.so
+70584fd000-70584fe000 rw-p 00020000 fc:00 2595                           /system/lib64/vndk-sp-28/libcutils.so
+7058519000-7058537000 r--s 00000000 fc:00 1124                           /system/usr/hyphen-data/hyph-de-ch-1901.hyb
+7058537000-7059fd1000 r--s 0070b000 fc:00 989                            /system/framework/framework-res.apk
+7059fd1000-705a013000 r-xp 00000000 fc:00 2610                           /system/lib64/libjavacrypto.so
+705a013000-705a02b000 ---p 00000000 00:00 0 
+705a02b000-705a02d000 r--p 0004e000 fc:00 2610                           /system/lib64/libjavacrypto.so
+705a02d000-705a02f000 rw-p 00050000 fc:00 2610                           /system/lib64/libjavacrypto.so
+705a041000-705a05f000 r--s 00000000 fc:00 1128                           /system/usr/hyphen-data/hyph-de-1996.hyb
+705a05f000-705a06a000 r-xp 00000000 fc:00 2917                           /system/lib64/libsoundpool.so
+705a06a000-705a07e000 ---p 00000000 00:00 0 
+705a07e000-705a07f000 r--p 0000f000 fc:00 2917                           /system/lib64/libsoundpool.so
+705a07f000-705a080000 rw-p 00010000 fc:00 2917                           /system/lib64/libsoundpool.so
+705a087000-705a102000 r--s 00000000 fc:00 1246                           /system/usr/share/zoneinfo/tzdata
+705a102000-705a863000 r--s 00000000 fc:00 101                            /system/fonts/NotoColorEmoji.ttf
+705a863000-705c000000 r--s 00000000 fc:00 251                            /system/fonts/NotoSerifCJK-Regular.ttc
+705c000000-705c200000 rw-p 00000000 00:00 0                              [anon:libc_malloc]
+705c209000-705c227000 r--s 00000000 fc:00 1077                           /system/usr/hyphen-data/hyph-de-1901.hyb
+705c227000-705c26e000 r--s 02284000 fc:00 989                            /system/framework/framework-res.apk
+705c26e000-705d43e000 r--s 00000000 fc:00 95                             /system/fonts/NotoSansCJK-Regular.ttc
+705d43e000-705d4ec000 r--s 00000000 fc:00 278                            /system/fonts/NotoSansSymbols-Regular-Subsetted.ttf
+705d4ec000-705d548000 r--s 00000000 fc:00 233                            /system/fonts/NotoSansTibetan-Bold.ttf
+705d548000-705d5ab000 r--s 00000000 fc:00 177                            /system/fonts/NotoSansTibetan-Regular.ttf
+705d5ab000-705d627000 r--s 00000000 fc:00 197                            /system/fonts/NotoSansEgyptianHieroglyphs-Regular.ttf
+705d627000-705d6a2000 r--s 00000000 fc:00 76                             /system/fonts/NotoSansCuneiform-Regular.ttf
+705d6a2000-705d6f3000 r--s 00000000 fc:00 67                             /system/fonts/RobotoCondensed-BoldItalic.ttf
+705d6f3000-705d73e000 r--s 00000000 fc:00 199                            /system/fonts/RobotoCondensed-Bold.ttf
+705d73e000-705d78f000 r--s 00000000 fc:00 230                            /system/fonts/RobotoCondensed-MediumItalic.ttf
+705d78f000-705d7da000 r--s 00000000 fc:00 92                             /system/fonts/RobotoCondensed-Medium.ttf
+705d7da000-705d82b000 r--s 00000000 fc:00 128                            /system/fonts/RobotoCondensed-Italic.ttf
+705d82b000-705d875000 r--s 00000000 fc:00 164                            /system/fonts/RobotoCondensed-Regular.ttf
+705d875000-705d8c7000 r--s 00000000 fc:00 292                            /system/fonts/RobotoCondensed-LightItalic.ttf
+705d8c7000-705d919000 r--s 00000000 fc:00 85                             /system/fonts/Roboto-BoldItalic.ttf
+705d919000-705d964000 r--s 00000000 fc:00 175                            /system/fonts/Roboto-Bold.ttf
+705d964000-705d9b5000 r--s 00000000 fc:00 266                            /system/fonts/Roboto-BlackItalic.ttf
+705d9b5000-705da00000 r--s 00000000 fc:00 187                            /system/fonts/Roboto-Black.ttf
+705da00000-705dc00000 rw-p 00000000 00:00 0                              [anon:libc_malloc]
+705dc1d000-705dc6e000 r--s 00000000 fc:00 148                            /system/fonts/Roboto-MediumItalic.ttf
+705dc6e000-705dcb9000 r--s 00000000 fc:00 284                            /system/fonts/Roboto-Medium.ttf
+705dcb9000-705dd0a000 r--s 00000000 fc:00 105                            /system/fonts/Roboto-Italic.ttf
+705dd0a000-705dd55000 r--s 00000000 fc:00 156                            /system/fonts/Roboto-Regular.ttf
+705dd55000-705dda7000 r--s 00000000 fc:00 217                            /system/fonts/Roboto-LightItalic.ttf
+705dda7000-705ddf8000 r--s 00000000 fc:00 166                            /system/fonts/Roboto-ThinItalic.ttf
+705ddf8000-705ddf9000 ---p 00000000 00:00 0                              [anon:thread stack guard]
+705ddf9000-705ddfa000 ---p 00000000 00:00 0 
+705ddfa000-705def6000 rw-p 00000000 00:00 0 
+705def6000-705f5ec000 r--s 00000000 fc:00 1350                           /system/usr/icu/icudt60l.dat
+705f5ec000-705f5ed000 ---p 00000000 00:00 0                              [anon:thread stack guard]
+705f5ed000-705f5ee000 ---p 00000000 00:00 0 
+705f5ee000-705f6ea000 rw-p 00000000 00:00 0 
+705f6ea000-705f7e8000 r--p 00000000 00:10 20636                          /dev/binder
+705f7e8000-705f7e9000 ---p 00000000 00:00 0                              [anon:thread stack guard]
+705f7e9000-705f7ea000 ---p 00000000 00:00 0 
+705f7ea000-705f8ee000 rw-p 00000000 00:00 0 
+705f8ee000-705f8ef000 ---p 00000000 00:00 0                              [anon:thread stack guard]
+705f8ef000-705f8f0000 ---p 00000000 00:00 0 
+705f8f0000-705f9f4000 rw-p 00000000 00:00 0 
+705f9f4000-705f9f5000 ---p 00000000 00:00 0                              [anon:thread stack guard]
+705f9f5000-705f9f6000 ---p 00000000 00:00 0 
+705f9f6000-705fafa000 rw-p 00000000 00:00 0 
+705fafa000-705fafb000 ---p 00000000 00:00 0                              [anon:thread stack guard]
+705fafb000-705fafc000 ---p 00000000 00:00 0 
+705fafc000-705fc00000 rw-p 00000000 00:00 0 
+705fc00000-705fe00000 rw-p 00000000 00:00 0                              [anon:libc_malloc]
+705fe01000-705fe4c000 r--s 00000000 fc:00 97                             /system/fonts/Roboto-Light.ttf
+705fe4c000-705fe4d000 ---p 00000000 00:00 0                              [anon:thread stack guard]
+705fe4d000-705fe4e000 ---p 00000000 00:00 0 
+705fe4e000-705ff4a000 rw-p 00000000 00:00 0 
+705ff4a000-705ff4b000 ---p 00000000 00:05 10270991                       /dev/ashmem/dalvik-Jit thread pool worker thread 0 (deleted)
+705ff4b000-705ff4c000 ---p 00001000 00:05 10270991                       /dev/ashmem/dalvik-Jit thread pool worker thread 0 (deleted)
+705ff4c000-706004b000 rw-p 00002000 00:05 10270991                       /dev/ashmem/dalvik-Jit thread pool worker thread 0 (deleted)
+706004b000-706010f000 r-xp 00000000 fc:00 2390                           /system/lib64/libvixl-arm64.so
+706010f000-7060120000 ---p 00000000 00:00 0 
+7060120000-7060125000 r--p 000cb000 fc:00 2390                           /system/lib64/libvixl-arm64.so
+7060125000-7060126000 rw-p 000d0000 fc:00 2390                           /system/lib64/libvixl-arm64.so
+7060126000-706012d000 rw-p 00000000 00:00 0                              [anon:.bss]
+7060135000-7060151000 r--s 00000000 fc:01 1180                           /vendor/overlay/framework-res__auto_generated_rro.apk
+7060151000-7060263000 r-xp 00000000 fc:00 2669                           /system/lib64/libvixl-arm.so
+7060263000-7060275000 ---p 00000000 00:00 0 
+7060275000-706027a000 r--p 0011b000 fc:00 2669                           /system/lib64/libvixl-arm.so
+706027a000-706027b000 rw-p 00120000 fc:00 2669                           /system/lib64/libvixl-arm.so
+706028b000-706056c000 r-xp 00000000 fc:00 2972                           /system/lib64/libart-compiler.so
+706056c000-7060580000 ---p 00000000 00:00 0 
+7060580000-7060598000 r--p 002e8000 fc:00 2972                           /system/lib64/libart-compiler.so
+7060598000-7060599000 rw-p 00300000 fc:00 2972                           /system/lib64/libart-compiler.so
+7060599000-70605a0000 rw-p 00000000 00:00 0                              [anon:.bss]
+70605b0000-70605d0000 r--s 00000000 00:10 16571                          /dev/__properties__/u:object_r:config_prop:s0
+70605d0000-7060619000 r-xp 00000000 fc:00 2702                           /system/lib64/libssl.so
+7060619000-706062d000 ---p 00000000 00:00 0 
+706062d000-7060630000 r--p 0004d000 fc:00 2702                           /system/lib64/libssl.so
+7060630000-7060631000 rw-p 00050000 fc:00 2702                           /system/lib64/libssl.so
+7060647000-7060667000 r--s 00000000 00:10 16595                          /dev/__properties__/u:object_r:exported3_radio_prop:s0
+7060667000-706069d000 r-xp 00000000 fc:00 2371                           /system/lib64/libopenjdk.so
+706069d000-70606b2000 ---p 00000000 00:00 0 
+70606b2000-70606b4000 r--p 0003e000 fc:00 2371                           /system/lib64/libopenjdk.so
+70606b4000-70606b6000 rw-p 00040000 fc:00 2371                           /system/lib64/libopenjdk.so
+70606bb000-70606db000 r--s 00000000 00:10 16608                          /dev/__properties__/u:object_r:exported_system_prop:s0
+70606db000-70606e3000 r-xp 00000000 fc:00 2538                           /system/lib64/libopenjdkjvm.so
+70606e3000-70606fa000 ---p 00000000 00:00 0 
+70606fa000-70606fb000 r--p 0000f000 fc:00 2538                           /system/lib64/libopenjdkjvm.so
+70606fb000-70606fc000 rw-p 00010000 fc:00 2538                           /system/lib64/libopenjdkjvm.so
+7060701000-7060722000 r--s 00000000 fc:00 227                            /system/fonts/NotoSansAnatolianHieroglyphs-Regular.otf
+7060722000-7061e18000 r--s 00000000 fc:00 1350                           /system/usr/icu/icudt60l.dat
+7061e18000-7061e5d000 r-xp 00000000 fc:00 2368                           /system/lib64/libjavacore.so
+7061e5d000-7061e71000 ---p 00000000 00:00 0 
+7061e71000-7061e73000 r--p 0004e000 fc:00 2368                           /system/lib64/libjavacore.so
+7061e73000-7061e75000 rw-p 00050000 fc:00 2368                           /system/lib64/libjavacore.so
+7061e75000-7061e76000 rw-p 00000000 00:00 0                              [anon:.bss]
+7061e77000-7061e96000 r--s 00000000 fc:00 186                            /system/fonts/NotoSansYi-Regular.ttf
+7061e96000-7061e99000 r-xp 00000000 fc:00 2953                           /system/lib64/libwebviewchromium_plat_support.so
+7061e99000-7061eb5000 ---p 00000000 00:00 0 
+7061eb5000-7061eb6000 r--p 0000f000 fc:00 2953                           /system/lib64/libwebviewchromium_plat_support.so
+7061eb6000-7061eb7000 rw-p 00010000 fc:00 2953                           /system/lib64/libwebviewchromium_plat_support.so
+7061ebc000-7061edd000 r--s 00000000 fc:00 100                            /system/fonts/NotoSansBamum-Regular.ttf
+7061edd000-7061eed000 r-xp 00000000 fc:00 2945                           /system/lib64/libRS.so
+7061eed000-7061efc000 ---p 00000000 00:00 0 
+7061efc000-7061efd000 r--p 0000f000 fc:00 2945                           /system/lib64/libRS.so
+7061efd000-7061efe000 rw-p 00010000 fc:00 2945                           /system/lib64/libRS.so
+7061f05000-7061f6b000 r-xp 00000000 fc:00 2423                           /system/lib64/android.hardware.renderscript@1.0.so
+7061f6b000-7061f7a000 ---p 00000000 00:00 0 
+7061f7a000-7061f7f000 r--p 0006b000 fc:00 2423                           /system/lib64/android.hardware.renderscript@1.0.so
+7061f7f000-7061f80000 rw-p 00070000 fc:00 2423                           /system/lib64/android.hardware.renderscript@1.0.so
+7061f99000-7061f9b000 r-xp 00000000 fc:00 2614                           /system/lib64/libOpenSLES.so
+7061f9b000-7061fb8000 ---p 00000000 00:00 0 
+7061fb8000-7061fb9000 r--p 0000f000 fc:00 2614                           /system/lib64/libOpenSLES.so
+7061fb9000-7061fba000 rw-p 00010000 fc:00 2614                           /system/lib64/libOpenSLES.so
+7061fc6000-7061fc8000 r-xp 00000000 fc:00 2963                           /system/lib64/libOpenMAXAL.so
+7061fc8000-7061fe5000 ---p 00000000 00:00 0 
+7061fe5000-7061fe6000 r--p 0000f000 fc:00 2963                           /system/lib64/libOpenMAXAL.so
+7061fe6000-7061fe7000 rw-p 00010000 fc:00 2963                           /system/lib64/libOpenMAXAL.so
+7061fe7000-7062000000 r--s 00000000 fc:00 143                            /system/fonts/NotoSansBhaiksuki-Regular.otf
+7062000000-7062003000 r-xp 00000000 fc:00 2447                           /system/lib64/libtextclassifier_hash.so
+7062003000-706201f000 ---p 00000000 00:00 0 
+706201f000-7062020000 r--p 0000f000 fc:00 2447                           /system/lib64/libtextclassifier_hash.so
+7062020000-7062021000 rw-p 00010000 fc:00 2447                           /system/lib64/libtextclassifier_hash.so
+7062022000-7062042000 rw-p 00000000 00:05 10269731                       /dev/ashmem/dalvik-CompilerMetadata (deleted)
+7062042000-7062077000 r-xp 00000000 fc:00 2372                           /system/lib64/android.hardware.neuralnetworks@1.0.so
+7062077000-7062095000 ---p 00000000 00:00 0 
+7062095000-706209b000 r--p 0003a000 fc:00 2372                           /system/lib64/android.hardware.neuralnetworks@1.0.so
+706209b000-706209c000 rw-p 00040000 fc:00 2372                           /system/lib64/android.hardware.neuralnetworks@1.0.so
+70620a9000-70620c9000 rw-p 00000000 00:05 10269730                       /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70620c9000-70620e3000 r-xp 00000000 fc:00 2956                           /system/lib64/android.hardware.neuralnetworks@1.1.so
+70620e3000-70620f4000 ---p 00000000 00:00 0 
+70620f4000-70620f7000 r--p 0001d000 fc:00 2956                           /system/lib64/android.hardware.neuralnetworks@1.1.so
+70620f7000-70620f8000 rw-p 00020000 fc:00 2956                           /system/lib64/android.hardware.neuralnetworks@1.1.so
+706210b000-70621d0000 r-xp 00000000 fc:00 2387                           /system/lib64/libneuralnetworks.so
+70621d0000-70621e3000 ---p 00000000 00:00 0 
+70621e3000-70621e5000 r--p 000ce000 fc:00 2387                           /system/lib64/libneuralnetworks.so
+70621e5000-70621e7000 rw-p 000d0000 fc:00 2387                           /system/lib64/libneuralnetworks.so
+70621e7000-7062372000 rw-p 00000000 00:00 0                              [anon:.bss]
+7062373000-7062395000 r--s 00000000 fc:00 274                            /system/fonts/NotoSerifMyanmar-Bold.otf
+7062395000-7062398000 r-xp 00000000 fc:00 2937                           /system/lib64/libjnigraphics.so
+7062398000-70623b4000 ---p 00000000 00:00 0 
+70623b4000-70623b5000 r--p 0000f000 fc:00 2937                           /system/lib64/libjnigraphics.so
+70623b5000-70623b6000 rw-p 00010000 fc:00 2937                           /system/lib64/libjnigraphics.so
+70623c8000-70623e0000 r-xp 00000000 fc:00 2662                           /system/lib64/libGLESv3.so
+70623e0000-70623f7000 ---p 00000000 00:00 0 
+70623f7000-70623f8000 r--p 0001f000 fc:00 2662                           /system/lib64/libGLESv3.so
+70623f8000-70623f9000 rw-p 00020000 fc:00 2662                           /system/lib64/libGLESv3.so
+70623fc000-706241c000 rw-p 00000000 00:05 10269729                       /dev/ashmem/dalvik-CompilerMetadata (deleted)
+706241c000-7062444000 r-xp 00000000 fc:00 2603                           /system/lib64/libexif.so
+7062444000-706245f000 ---p 00000000 00:00 0 
+706245f000-7062472000 r--p 0002d000 fc:00 2603                           /system/lib64/libexif.so
+7062472000-7062473000 rw-p 00040000 fc:00 2603                           /system/lib64/libexif.so
+7062474000-7062490000 r--s 00000000 fc:00 286                            /system/fonts/NotoSansMongolian-Regular.ttf
+7062490000-7062491000 r-xp 00000000 fc:00 2357                           /system/lib64/libasyncio.so
+7062491000-70624af000 ---p 00000000 00:00 0 
+70624af000-70624b0000 r--p 0000f000 fc:00 2357                           /system/lib64/libasyncio.so
+70624b0000-70624b1000 rw-p 00010000 fc:00 2357                           /system/lib64/libasyncio.so
+70624b5000-70624cf000 r--s 00000000 fc:00 221                            /system/fonts/NotoSansMyanmarUI-Bold.ttf
+70624cf000-7062508000 r-xp 00000000 fc:00 2401                           /system/lib64/libmtp.so
+7062508000-7062522000 ---p 00000000 00:00 0 
+7062522000-7062525000 r--p 0003d000 fc:00 2401                           /system/lib64/libmtp.so
+7062525000-706252c000 rw-p 00040000 fc:00 2401                           /system/lib64/libmtp.so
+7062530000-7062550000 rw-p 00000000 00:05 10269728                       /dev/ashmem/dalvik-CompilerMetadata (deleted)
+7062550000-7062572000 r--s 00000000 fc:00 234                            /system/fonts/NotoSerifMyanmar-Regular.otf
+7062572000-706259e000 r-xp 00000000 fc:00 2620                           /system/lib64/libmediandk.so
+706259e000-70625b9000 ---p 00000000 00:00 0 
+70625b9000-70625bc000 r--p 0002d000 fc:00 2620                           /system/lib64/libmediandk.so
+70625bc000-70625c0000 rw-p 00030000 fc:00 2620                           /system/lib64/libmediandk.so
+70625c2000-70625d1000 r-xp 00000000 fc:00 2613                           /system/lib64/libmidi.so
+70625d1000-70625ef000 ---p 00000000 00:00 0 
+70625ef000-70625f1000 r--p 0000e000 fc:00 2613                           /system/lib64/libmidi.so
+70625f1000-70625f2000 rw-p 00010000 fc:00 2613                           /system/lib64/libmidi.so
+7062600000-7062621000 r-xp 00000000 fc:00 2366                           /system/lib64/libmediadrmmetrics_lite.so
+7062621000-706263d000 ---p 00000000 00:00 0 
+706263d000-706263f000 r--p 0002e000 fc:00 2366                           /system/lib64/libmediadrmmetrics_lite.so
+706263f000-7062640000 rw-p 00030000 fc:00 2366                           /system/lib64/libmediadrmmetrics_lite.so
+706264b000-706266b000 rw-p 00000000 00:05 10269727                       /dev/ashmem/dalvik-CompilerMetadata (deleted)
+706266b000-70626d4000 r-xp 00000000 fc:00 2727                           /system/lib64/libmedia_jni.so
+70626d4000-70626eb000 ---p 00000000 00:00 0 
+70626eb000-70626f2000 r--p 00069000 fc:00 2727                           /system/lib64/libmedia_jni.so
+70626f2000-70626f3000 rw-p 00070000 fc:00 2727                           /system/lib64/libmedia_jni.so
+7062703000-7062732000 r-xp 00000000 fc:00 2399                           /system/lib64/libcamera2ndk.so
+7062732000-7062748000 ---p 00000000 00:00 0 
+7062748000-706274b000 r--p 0003d000 fc:00 2399                           /system/lib64/libcamera2ndk.so
+706274b000-7062750000 rw-p 00040000 fc:00 2399                           /system/lib64/libcamera2ndk.so
+7062768000-7062788000 rw-p 00000000 00:05 10269726                       /dev/ashmem/dalvik-CompilerMetadata (deleted)
+7062788000-70627ee000 r-xp 00000000 fc:00 2974                           /system/lib64/android.hardware.drm@1.0.so
+70627ee000-7062805000 ---p 00000000 00:00 0 
+7062805000-706280d000 r--p 00068000 fc:00 2974                           /system/lib64/android.hardware.drm@1.0.so
+706280d000-706280e000 rw-p 00070000 fc:00 2974                           /system/lib64/android.hardware.drm@1.0.so
+706281a000-706281b000 ---p 00000000 00:00 0                              [anon:thread signal stack guard]
+706281b000-706281f000 rw-p 00000000 00:00 0                              [anon:thread signal stack]
+706281f000-7062843000 r--s 00000000 fc:00 142                            /system/fonts/NotoSansKhmer-VF.ttf
+7062843000-7062886000 r-xp 00000000 fc:00 2637                           /system/lib64/android.hardware.drm@1.1.so
+7062886000-70628a5000 ---p 00000000 00:00 0 
+70628a5000-70628ab000 r--p 0004a000 fc:00 2637                           /system/lib64/android.hardware.drm@1.1.so
+70628ab000-70628ac000 rw-p 00050000 fc:00 2637                           /system/lib64/android.hardware.drm@1.1.so
+70628b0000-70628b1000 ---p 00000000 00:00 0                              [anon:thread signal stack guard]
+70628b1000-70628b5000 rw-p 00000000 00:00 0                              [anon:thread signal stack]
+70628b5000-70628db000 r--s 00000000 fc:00 137                            /system/fonts/NotoSansSinhala-Bold.ttf
+70628db000-7062907000 r-xp 00000000 fc:00 2478                           /system/lib64/libmediadrm.so
+7062907000-7062918000 ---p 00000000 00:00 0 
+7062918000-7062920000 r--p 00038000 fc:00 2478                           /system/lib64/libmediadrm.so
+7062920000-7062921000 rw-p 00040000 fc:00 2478                           /system/lib64/libmediadrm.so
+7062922000-7062929000 rw-p 00000000 fc:00 583                            /system/etc/event-log-tags
+7062929000-7062951000 r--s 00000000 fc:00 296                            /system/fonts/NotoSansSinhala-Regular.ttf
+7062951000-7062997000 r-xp 00000000 fc:00 2448                           /system/lib64/libaaudio.so
+7062997000-70629ac000 ---p 00000000 00:00 0 
+70629ac000-70629b2000 r--p 0004a000 fc:00 2448                           /system/lib64/libaaudio.so
+70629b2000-70629ba000 rw-p 00050000 fc:00 2448                           /system/lib64/libaaudio.so
+70629ba000-70629bb000 ---p 00000000 00:00 0                              [anon:thread signal stack guard]
+70629bb000-70629bf000 rw-p 00000000 00:00 0                              [anon:thread signal stack]
+70629bf000-70629c0000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70629c0000-70629c3000 rw-p 00000000 00:00 0                              [anon:bionic TLS]
+70629c3000-70629c4000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70629c4000-70629c5000 ---p 00000000 00:00 0                              [anon:thread signal stack guard]
+70629c5000-70629c9000 rw-p 00000000 00:00 0                              [anon:thread signal stack]
+70629c9000-70629e3000 r-xp 00000000 fc:00 2940                           /system/lib64/libandroid.so
+70629e3000-70629f3000 ---p 00000000 00:00 0 
+70629f3000-70629f6000 r--p 0001d000 fc:00 2940                           /system/lib64/libandroid.so
+70629f6000-70629f7000 rw-p 00020000 fc:00 2940                           /system/lib64/libandroid.so
+70629f8000-70629f9000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70629f9000-70629fc000 rw-p 00000000 00:00 0                              [anon:bionic TLS]
+70629fc000-70629fd000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70629fd000-7062a3e000 r--s 00000000 fc:00 216                            /system/fonts/NotoSerif-BoldItalic.ttf
+7062a3e000-7062b06000 rw-p 00000000 00:05 10270984                       /dev/ashmem/dalvik-indirect ref table (deleted)
+7062b06000-7062bce000 rw-p 00000000 00:05 10270983                       /dev/ashmem/dalvik-indirect ref table (deleted)
+7062bce000-7062dce000 rw-p 00000000 00:05 10270726                       /dev/ashmem/dalvik-rb copying gc mark stack (deleted)
+7062dce000-70635ce000 rw-p 00000000 00:05 10270725                       /dev/ashmem/dalvik-concurrent copying gc mark stack (deleted)
+70635ce000-7063dcf000 rw-p 00000000 00:05 10270724                       /dev/ashmem/dalvik-live stack (deleted)
+7063dcf000-70645d0000 rw-p 00000000 00:05 10270723                       /dev/ashmem/dalvik-allocation stack (deleted)
+70645d0000-70649d1000 rw-p 00000000 00:05 10270721                       /dev/ashmem/dalvik-card table (deleted)
+70649d1000-7064ad1000 rw-p 00000000 00:05 10267648                       /dev/ashmem/dalvik-large object free list space allocation info map (deleted)
+7064ad1000-7065ad1000 rw-p 00000000 00:05 10267644                       /dev/ashmem/dalvik-region space live bitmap (deleted)
+7065ad1000-7065bd1000 rw-p 00000000 00:05 10267642                       /dev/ashmem/dalvik-allocspace zygote / non moving space mark-bitmap 0 (deleted)
+7065bd1000-7065cd1000 rw-p 00000000 00:05 10267641                       /dev/ashmem/dalvik-allocspace zygote / non moving space live-bitmap 0 (deleted)
+7065cd1000-7065cd2000 r-xp 00000000 fc:00 2946                           /system/lib64/libsigchain.so
+7065cd2000-7065cf0000 ---p 00000000 00:00 0 
+7065cf0000-7065cf1000 r--p 0000f000 fc:00 2946                           /system/lib64/libsigchain.so
+7065cf1000-7065cf2000 rw-p 00010000 fc:00 2946                           /system/lib64/libsigchain.so
+7065cf4000-7065d0f000 r--s 00000000 fc:00 190                            /system/fonts/NotoSansMyanmar-Bold.ttf
+7065d0f000-7065d22000 r-xp 00000000 fc:00 2405                           /system/lib64/liblz4.so
+7065d22000-7065d3e000 ---p 00000000 00:00 0 
+7065d3e000-7065d3f000 r--p 0001f000 fc:00 2405                           /system/lib64/liblz4.so
+7065d3f000-7065d40000 rw-p 00020000 fc:00 2405                           /system/lib64/liblz4.so
+7065d40000-7065d5a000 r--s 00000000 fc:00 222                            /system/fonts/NotoSansMyanmarUI-Regular.ttf
+7065d5a000-7065d5e000 r-xp 00000000 fc:00 2609                           /system/lib64/libtombstoned_client.so
+7065d5e000-7065d79000 ---p 00000000 00:00 0 
+7065d79000-7065d7a000 r--p 0000f000 fc:00 2609                           /system/lib64/libtombstoned_client.so
+7065d7a000-7065d7b000 rw-p 00010000 fc:00 2609                           /system/lib64/libtombstoned_client.so
+7065d7f000-7065d80000 ---p 00000000 00:00 0                              [anon:thread signal stack guard]
+7065d80000-7065d84000 rw-p 00000000 00:00 0                              [anon:thread signal stack]
+7065d84000-706636e000 r-xp 00000000 fc:00 2671                           /system/lib64/libart.so
+706636e000-706638d000 ---p 00000000 00:00 0 
+706638d000-706639e000 r--p 005ef000 fc:00 2671                           /system/lib64/libart.so
+706639e000-70663a1000 rw-p 00600000 fc:00 2671                           /system/lib64/libart.so
+70663a1000-70663a4000 rw-p 00000000 00:00 0                              [anon:.bss]
+70663a6000-70663c6000 rw-p 00000000 00:05 10269725                       /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70663c6000-70663c8000 r-xp 00000000 fc:00 2673                           /system/lib64/libmetricslogger.so
+70663c8000-70663e5000 ---p 00000000 00:00 0 
+70663e5000-70663e6000 r--p 0000f000 fc:00 2673                           /system/lib64/libmetricslogger.so
+70663e6000-70663e7000 rw-p 00010000 fc:00 2673                           /system/lib64/libmetricslogger.so
+70663e7000-7066400000 r--s 00000000 fc:00 110                            /system/fonts/NotoSansLepcha-Regular.ttf
+7066400000-7066800000 rw-p 00000000 00:00 0                              [anon:libc_malloc]
+7066803000-706681e000 r--s 00000000 fc:00 297                            /system/fonts/NotoSansMyanmar-Regular.ttf
+706681e000-7066821000 r--p 00000000 00:00 0                              [anon:cfi shadow]
+7066821000-7066822000 r--p 00000000 00:00 0                              [anon:cfi shadow]
+7066822000-7066b1d000 r--p 00000000 00:00 0                              [anon:cfi shadow]
+7066b1d000-7066b1e000 r--p 00000000 00:00 0                              [anon:cfi shadow]
+7066b1e000-7066ba0000 r--p 00000000 00:00 0                              [anon:cfi shadow]
+7066ba0000-7066ba1000 r--p 00000000 00:00 0                              [anon:cfi shadow]
+7066ba1000-7066ba2000 r--p 00000000 00:00 0                              [anon:cfi shadow]
+7066ba2000-7066ba5000 r--p 00000000 00:00 0                              [anon:cfi shadow]
+7066ba5000-7066ba6000 r--p 00000000 00:00 0                              [anon:cfi shadow]
+7066ba6000-70e681e000 r--p 00000000 00:00 0                              [anon:cfi shadow]
+70e681e000-70e6854000 r-xp 00000000 fc:00 2431                           /system/lib64/libstagefright_foundation.so
+70e6854000-70e6865000 ---p 00000000 00:00 0 
+70e6865000-70e6867000 r--p 0003e000 fc:00 2431                           /system/lib64/libstagefright_foundation.so
+70e6867000-70e686c000 rw-p 00040000 fc:00 2431                           /system/lib64/libstagefright_foundation.so
+70e686d000-70e686e000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70e686e000-70e6871000 rw-p 00000000 00:00 0                              [anon:bionic TLS]
+70e6871000-70e6873000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70e6873000-70e6876000 rw-p 00000000 00:00 0                              [anon:bionic TLS]
+70e6876000-70e6877000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70e6877000-70e688c000 r--s 00000000 fc:00 301                            /system/fonts/NotoSansSinhalaUI-Bold.otf
+70e688c000-70e688e000 r-xp 00000000 fc:00 2943                           /system/lib64/libion.so
+70e688e000-70e68ab000 ---p 00000000 00:00 0 
+70e68ab000-70e68ac000 r--p 0000f000 fc:00 2943                           /system/lib64/libion.so
+70e68ac000-70e68ad000 rw-p 00010000 fc:00 2943                           /system/lib64/libion.so
+70e68ad000-70e68af000 rw-p 00000000 00:05 10282496                       /dev/ashmem/dalvik-indirect ref table (deleted)
+70e68af000-70e68b1000 rw-p 00000000 00:05 10282493                       /dev/ashmem/dalvik-indirect ref table (deleted)
+70e68b1000-70e68ee000 r--s 00000000 fc:00 256                            /system/fonts/NotoSerif-Italic.ttf
+70e68ee000-70e6910000 r-xp 00000000 fc:00 2502                           /system/lib64/libhidlbase.so
+70e6910000-70e692c000 ---p 00000000 00:00 0 
+70e692c000-70e692e000 r--p 0002e000 fc:00 2502                           /system/lib64/libhidlbase.so
+70e692e000-70e692f000 rw-p 00030000 fc:00 2502                           /system/lib64/libhidlbase.so
+70e6930000-70e693f000 r--s 00000000 fc:00 1082                           /system/usr/hyphen-data/hyph-en-us.hyb
+70e693f000-70e6954000 r--s 00000000 fc:00 138                            /system/fonts/NotoSansSinhalaUI-Regular.otf
+70e6954000-70e6978000 r-xp 00000000 fc:00 2482                           /system/lib64/libui.so
+70e6978000-70e6992000 ---p 00000000 00:00 0 
+70e6992000-70e6994000 r--p 0002e000 fc:00 2482                           /system/lib64/libui.so
+70e6994000-70e6995000 rw-p 00030000 fc:00 2482                           /system/lib64/libui.so
+70e6996000-70e69a2000 r--s 00000000 fc:00 1117                           /system/usr/hyphen-data/hyph-en-gb.hyb
+70e69a2000-70e69b7000 r--s 00000000 fc:00 202                            /system/fonts/NotoSerifSinhala-Bold.otf
+70e69b7000-70e69cb000 r--s 00000000 fc:00 124                            /system/fonts/NotoSansOriyaUI-Bold.ttf
+70e69cb000-70e69e1000 r-xp 00000000 fc:00 2537                           /system/lib64/liblog.so
+70e69e1000-70e69fa000 ---p 00000000 00:00 0 
+70e69fa000-70e69fb000 r--p 0001f000 fc:00 2537                           /system/lib64/liblog.so
+70e69fb000-70e69fc000 rw-p 00020000 fc:00 2537                           /system/lib64/liblog.so
+70e69fc000-70e69fe000 rw-p 00000000 00:05 10266158                       /dev/ashmem/dalvik-indirect ref table (deleted)
+70e69fe000-70e69ff000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70e69ff000-70e6a02000 rw-p 00000000 00:00 0                              [anon:bionic TLS]
+70e6a02000-70e6a03000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70e6a03000-70e6a05000 r-xp 00000000 fc:00 2489                           /system/lib64/android.hidl.token@1.0-utils.so
+70e6a05000-70e6a22000 ---p 00000000 00:00 0 
+70e6a22000-70e6a23000 r--p 0000f000 fc:00 2489                           /system/lib64/android.hidl.token@1.0-utils.so
+70e6a23000-70e6a24000 rw-p 00010000 fc:00 2489                           /system/lib64/android.hidl.token@1.0-utils.so
+70e6a25000-70e6a2e000 r--s 00000000 fc:00 1120                           /system/usr/hyphen-data/hyph-ga.hyb
+70e6a2e000-70e6a42000 r--s 00000000 fc:00 109                            /system/fonts/NotoSansOriyaUI-Regular.ttf
+70e6a42000-70e6a59000 r-xp 00000000 fc:00 2446                           /system/lib64/android.hardware.graphics.mapper@2.0.so
+70e6a59000-70e6a6e000 ---p 00000000 00:00 0 
+70e6a6e000-70e6a70000 r--p 0001e000 fc:00 2446                           /system/lib64/android.hardware.graphics.mapper@2.0.so
+70e6a70000-70e6a71000 rw-p 00020000 fc:00 2446                           /system/lib64/android.hardware.graphics.mapper@2.0.so
+70e6a72000-70e6a78000 r--s 00000000 fc:00 1084                           /system/usr/hyphen-data/hyph-et.hyb
+70e6a78000-70e6a9d000 r--s 00000000 fc:00 207                            /system/fonts/NotoSerifTelugu-Bold.ttf
+70e6a9d000-70e6a9f000 r-xp 00000000 fc:00 2330                           /system/lib64/android.hardware.configstore-utils.so
+70e6a9f000-70e6abc000 ---p 00000000 00:00 0 
+70e6abc000-70e6abd000 r--p 0000f000 fc:00 2330                           /system/lib64/android.hardware.configstore-utils.so
+70e6abd000-70e6abe000 rw-p 00010000 fc:00 2330                           /system/lib64/android.hardware.configstore-utils.so
+70e6abe000-70e6ac0000 r--s f8042000 00:10 20630                          /dev/kgsl-3d0
+70e6ac0000-70e6adc000 r--s 00000000 fc:00 172                            /system/fonts/NotoSansTeluguUI-Bold.ttf
+70e6adc000-70e6ae0000 r-xp 00000000 fc:00 2555                           /system/lib64/libstagefright_omx_utils.so
+70e6ae0000-70e6afb000 ---p 00000000 00:00 0 
+70e6afb000-70e6afc000 r--p 0000f000 fc:00 2555                           /system/lib64/libstagefright_omx_utils.so
+70e6afc000-70e6afd000 rw-p 00010000 fc:00 2555                           /system/lib64/libstagefright_omx_utils.so
+70e6afd000-70e6afe000 ---p 00000000 00:00 0                              [anon:thread signal stack guard]
+70e6afe000-70e6b02000 rw-p 00000000 00:00 0                              [anon:thread signal stack]
+70e6b02000-70e6b27000 r--s 00000000 fc:00 271                            /system/fonts/NotoSerifTelugu-Regular.ttf
+70e6b27000-70e6b61000 r-xp 00000000 fc:00 2695                           /system/lib64/libdexfile.so
+70e6b61000-70e6b73000 ---p 00000000 00:00 0 
+70e6b73000-70e6b75000 r--p 0003e000 fc:00 2695                           /system/lib64/libdexfile.so
+70e6b75000-70e6b76000 rw-p 00040000 fc:00 2695                           /system/lib64/libdexfile.so
+70e6b76000-70e6b78000 rw-p 00000000 00:05 10253452                       /dev/ashmem/dalvik-indirect ref table (deleted)
+70e6b78000-70e6b85000 r--s 00000000 fc:00 1080                           /system/usr/hyphen-data/hyph-cu.hyb
+70e6b85000-70e6b96000 r-xp 00000000 fc:00 2957                           /system/lib64/libaudioutils.so
+70e6b96000-70e6bb4000 ---p 00000000 00:00 0 
+70e6bb4000-70e6bb5000 r--p 0001f000 fc:00 2957                           /system/lib64/libaudioutils.so
+70e6bb5000-70e6bb6000 rw-p 00020000 fc:00 2957                           /system/lib64/libaudioutils.so
+70e6bb6000-70e6bb7000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70e6bb7000-70e6bba000 rw-p 00000000 00:00 0                              [anon:bionic TLS]
+70e6bba000-70e6bbb000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70e6bbb000-70e6bd7000 r--s 00000000 fc:00 132                            /system/fonts/NotoSansTeluguUI-Regular.ttf
+70e6bd7000-70e6bdc000 r-xp 00000000 fc:00 2409                           /system/lib64/libprocessgroup.so
+70e6bdc000-70e6bf6000 ---p 00000000 00:00 0 
+70e6bf6000-70e6bf7000 r--p 0000f000 fc:00 2409                           /system/lib64/libprocessgroup.so
+70e6bf7000-70e6bf8000 rw-p 00010000 fc:00 2409                           /system/lib64/libprocessgroup.so
+70e6bf8000-70e6c09000 r--s 00000000 fc:00 79                             /system/fonts/NotoSansNewa-Regular.otf
+70e6c09000-70e6c1c000 r-xp 00000000 fc:00 2329                           /system/lib64/android.hidl.memory.token@1.0.so
+70e6c1c000-70e6c36000 ---p 00000000 00:00 0 
+70e6c36000-70e6c38000 r--p 0001e000 fc:00 2329                           /system/lib64/android.hidl.memory.token@1.0.so
+70e6c38000-70e6c39000 rw-p 00020000 fc:00 2329                           /system/lib64/android.hidl.memory.token@1.0.so
+70e6c3a000-70e6c4f000 r--s 00000000 fc:00 253                            /system/fonts/NotoSansOriya-Bold.ttf
+70e6c4f000-70e6c6b000 r-xp 00000000 fc:00 2407                           /system/lib64/libutils.so
+70e6c6b000-70e6c7e000 ---p 00000000 00:00 0 
+70e6c7e000-70e6c7f000 r--p 0001f000 fc:00 2407                           /system/lib64/libutils.so
+70e6c7f000-70e6c80000 rw-p 00020000 fc:00 2407                           /system/lib64/libutils.so
+70e6c80000-70e6c9d000 r-xp 00000000 fc:00 2934                           /system/lib64/libtinyxml2.so
+70e6c9d000-70e6cba000 ---p 00000000 00:00 0 
+70e6cba000-70e6cbc000 r--p 0001e000 fc:00 2934                           /system/lib64/libtinyxml2.so
+70e6cbc000-70e6cbf000 rw-p 00020000 fc:00 2934                           /system/lib64/libtinyxml2.so
+70e6cbf000-70e6ccf000 r--s 00000000 fc:00 80                             /system/fonts/NotoSansMarchen-Regular.otf
+70e6ccf000-70e6ce0000 r-xp 00000000 fc:00 2655                           /system/lib64/libbase.so
+70e6ce0000-70e6cfe000 ---p 00000000 00:00 0 
+70e6cfe000-70e6cff000 r--p 0001f000 fc:00 2655                           /system/lib64/libbase.so
+70e6cff000-70e6d00000 rw-p 00020000 fc:00 2655                           /system/lib64/libbase.so
+70e6d00000-70e6d09000 r--s 00000000 fc:00 1113                           /system/usr/hyphen-data/hyph-cy.hyb
+70e6d09000-70e6d50000 r-xp 00000000 fc:00 2495                           /system/lib64/libRScpp.so
+70e6d50000-70e6d68000 ---p 00000000 00:00 0 
+70e6d68000-70e6d69000 r--p 0004f000 fc:00 2495                           /system/lib64/libRScpp.so
+70e6d69000-70e6d6a000 rw-p 00050000 fc:00 2495                           /system/lib64/libRScpp.so
+70e6d6b000-70e6d6d000 r--s 00088000 103:1d 1736830                       /data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/base.apk
+70e6d6d000-70e6d7d000 r--s 00000000 fc:00 238                            /system/fonts/NotoSansVai-Regular.ttf
+70e6d7d000-70e6d98000 r--s 00000000 fc:00 276                            /system/fonts/NotoSansTelugu-Bold.ttf
+70e6d98000-70e6f2b000 r-xp 00000000 fc:00 2961                           /system/lib64/libicuuc.so
+70e6f2b000-70e6f47000 ---p 00000000 00:00 0 
+70e6f47000-70e6f5c000 r--p 0019b000 fc:00 2961                           /system/lib64/libicuuc.so
+70e6f5c000-70e6f5d000 rw-p 001b0000 fc:00 2961                           /system/lib64/libicuuc.so
+70e6f5d000-70e6f5e000 rw-p 00000000 00:00 0                              [anon:.bss]
+70e6f5f000-70e6f68000 r--s 00000000 fc:00 159                            /system/fonts/NotoSansLinearA-Regular.otf
+70e6f68000-70e6f84000 r--s 00000000 fc:00 170                            /system/fonts/NotoSansTelugu-Regular.ttf
+70e6f84000-70e7058000 r-xp 00000000 fc:00 2356                           /system/lib64/libc.so
+70e7058000-70e706e000 ---p 00000000 00:00 0 
+70e706e000-70e7074000 r--p 000da000 fc:00 2356                           /system/lib64/libc.so
+70e7074000-70e7076000 rw-p 000e0000 fc:00 2356                           /system/lib64/libc.so
+70e7076000-70e7077000 rw-p 00000000 00:00 0                              [anon:.bss]
+70e7077000-70e7078000 r--p 00000000 00:00 0                              [anon:.bss]
+70e7078000-70e7080000 rw-p 00000000 00:00 0                              [anon:.bss]
+70e7080000-70e7087000 r--s 00000000 fc:00 102                            /system/fonts/NotoSansSharada-Regular.otf
+70e7087000-70e708e000 r-xp 00000000 fc:00 2378                           /system/lib64/libheif.so
+70e708e000-70e70a4000 ---p 00000000 00:00 0 
+70e70a4000-70e70a6000 r--p 0000e000 fc:00 2378                           /system/lib64/libheif.so
+70e70a6000-70e70a7000 rw-p 00010000 fc:00 2378                           /system/lib64/libheif.so
+70e70a7000-70e70a9000 r--s 00000000 fc:00 1116                           /system/usr/hyphen-data/hyph-sl.hyb
+70e70a9000-70e70ab000 r--s 00000000 fc:00 1147                           /system/usr/hyphen-data/hyph-mn-cyrl.hyb
+70e70ab000-70e70c5000 r--s 00000000 fc:00 291                            /system/fonts/NotoSansBengaliUI-Bold.ttf
+70e70c5000-70e70ea000 r-xp 00000000 fc:00 2545                           /system/lib64/libEGL.so
+70e70ea000-70e7109000 ---p 00000000 00:00 0 
+70e7109000-70e710d000 r--p 0002c000 fc:00 2545                           /system/lib64/libEGL.so
+70e710d000-70e710e000 rw-p 00030000 fc:00 2545                           /system/lib64/libEGL.so
+70e710e000-70e7115000 rw-p 00000000 00:00 0                              [anon:.bss]
+70e7115000-70e7119000 r--s 00000000 fc:00 1143                           /system/usr/hyphen-data/hyph-es.hyb
+70e7119000-70e712e000 r--s 00000000 fc:00 71                             /system/fonts/NotoSansOriya-Regular.ttf
+70e712e000-70e717a000 r--s 00000000 fc:00 272                            /system/fonts/Roboto-Thin.ttf
+70e717a000-70e71db000 r-xp 00000000 fc:00 2393                           /system/lib64/libpdx_default_transport.so
+70e71db000-70e71f7000 ---p 00000000 00:00 0 
+70e71f7000-70e71f9000 r--p 0006e000 fc:00 2393                           /system/lib64/libpdx_default_transport.so
+70e71f9000-70e71fa000 rw-p 00070000 fc:00 2393                           /system/lib64/libpdx_default_transport.so
+70e71fa000-70e71fb000 rw-p 00000000 00:00 0                              [anon:.bss]
+70e71fc000-70e71fe000 r--s 00000000 fc:00 1107                           /system/usr/hyphen-data/hyph-fr.hyb
+70e71fe000-70e7200000 r--s 00000000 fc:00 1097                           /system/usr/hyphen-data/hyph-da.hyb
+70e7200000-70e7223000 r-xp 00000000 fc:00 2380                           /system/lib64/libminikin.so
+70e7223000-70e723e000 ---p 00000000 00:00 0 
+70e723e000-70e723f000 r--p 0002f000 fc:00 2380                           /system/lib64/libminikin.so
+70e723f000-70e7240000 rw-p 00030000 fc:00 2380                           /system/lib64/libminikin.so
+70e7241000-70e724d000 r--s 00000000 fc:00 179                            /system/fonts/NotoSansTaiTham-Regular.ttf
+70e724d000-70e725c000 r-xp 00000000 fc:00 2527                           /system/lib64/libmediautils.so
+70e725c000-70e7279000 ---p 00000000 00:00 0 
+70e7279000-70e727b000 r--p 0001e000 fc:00 2527                           /system/lib64/libmediautils.so
+70e727b000-70e727c000 rw-p 00020000 fc:00 2527                           /system/lib64/libmediautils.so
+70e727d000-70e7283000 r--s 00000000 fc:00 136                            /system/fonts/NotoSansMiao-Regular.otf
+70e7283000-70e74d2000 r-xp 00000000 fc:00 2349                           /system/lib64/libicui18n.so
+70e74d2000-70e74e6000 ---p 00000000 00:00 0 
+70e74e6000-70e74fa000 r--p 0025c000 fc:00 2349                           /system/lib64/libicui18n.so
+70e74fa000-70e74fb000 rw-p 00270000 fc:00 2349                           /system/lib64/libicui18n.so
+70e74fc000-70e74ff000 r--s 00000000 103:1d 1474562                       /data/resource-cache/vendor@overlay@framework-res__auto_generated_rro.apk@idmap
+70e74ff000-70e750c000 r--s 00000000 fc:00 126                            /system/fonts/NotoSansSyriacWestern-Regular.ttf
+70e750c000-70e751b000 r-xp 00000000 fc:00 2466                           /system/lib64/libmediaextractor.so
+70e751b000-70e753a000 ---p 00000000 00:00 0 
+70e753a000-70e753b000 r--p 0000f000 fc:00 2466                           /system/lib64/libmediaextractor.so
+70e753b000-70e753c000 rw-p 00010000 fc:00 2466                           /system/lib64/libmediaextractor.so
+70e753d000-70e7540000 r--s 00000000 fc:00 107                            /system/fonts/NotoSansPauCinHau-Regular.otf
+70e7540000-70e7593000 r-xp 00000000 fc:00 2363                           /system/lib64/libandroidfw.so
+70e7593000-70e75ac000 ---p 00000000 00:00 0 
+70e75ac000-70e75af000 r--p 0005d000 fc:00 2363                           /system/lib64/libandroidfw.so
+70e75af000-70e75b0000 rw-p 00060000 fc:00 2363                           /system/lib64/libandroidfw.so
+70e75b0000-70e75b2000 r--s 00000000 fc:00 1083                           /system/usr/hyphen-data/hyph-be.hyb
+70e75b2000-70e75cd000 r--s 00000000 fc:00 270                            /system/fonts/NotoSansBengaliUI-Regular.ttf
+70e75cd000-70e75cf000 r-xp 00000000 fc:00 2701                           /system/lib64/libmemtrack.so
+70e75cf000-70e75ec000 ---p 00000000 00:00 0 
+70e75ec000-70e75ed000 r--p 0000f000 fc:00 2701                           /system/lib64/libmemtrack.so
+70e75ed000-70e75ee000 rw-p 00010000 fc:00 2701                           /system/lib64/libmemtrack.so
+70e75ee000-70e75f0000 r--s 00000000 fc:00 209                            /system/fonts/NotoSansSoraSompeng-Regular.otf
+70e75f0000-70e760d000 r--s 00000000 fc:00 243                            /system/fonts/NotoSerifBengali-Bold.ttf
+70e760d000-70e7613000 r-xp 00000000 fc:00 2667                           /system/lib64/libutilscallstack.so
+70e7613000-70e762c000 ---p 00000000 00:00 0 
+70e762c000-70e762d000 r--p 0000f000 fc:00 2667                           /system/lib64/libutilscallstack.so
+70e762d000-70e762e000 rw-p 00010000 fc:00 2667                           /system/lib64/libutilscallstack.so
+70e762e000-70e7632000 r--s 00000000 fc:00 99                             /system/fonts/NotoSansPahawhHmong-Regular.otf
+70e7632000-70e764f000 r--s 00000000 fc:00 205                            /system/fonts/NotoSerifBengali-Regular.ttf
+70e764f000-70e7661000 r-xp 00000000 fc:00 2710                           /system/lib64/libcutils.so
+70e7661000-70e767d000 ---p 00000000 00:00 0 
+70e767d000-70e767f000 r--p 0001e000 fc:00 2710                           /system/lib64/libcutils.so
+70e767f000-70e7680000 rw-p 00020000 fc:00 2710                           /system/lib64/libcutils.so
+70e7680000-70e7683000 r--s 00000000 fc:00 257                            /system/fonts/NotoSansPalmyrene-Regular.otf
+70e7683000-70e7697000 r--s 00000000 fc:00 78                             /system/fonts/NotoSansKannadaUI-Bold.ttf
+70e7697000-70e769a000 r-xp 00000000 fc:00 2362                           /system/lib64/libstagefright_http_support.so
+70e769a000-70e76b6000 ---p 00000000 00:00 0 
+70e76b6000-70e76b7000 r--p 0000f000 fc:00 2362                           /system/lib64/libstagefright_http_support.so
+70e76b7000-70e76b8000 rw-p 00010000 fc:00 2362                           /system/lib64/libstagefright_http_support.so
+70e76b8000-70e76b9000 rw-p 00000000 00:00 0                              [anon:linker_alloc_lob]
+70e76b9000-70e76be000 r--s 00000000 fc:00 165                            /system/fonts/NotoSansMeroitic-Regular.otf
+70e76be000-70e76cb000 r--s 00000000 fc:00 112                            /system/fonts/NotoSansSyriacEastern-Regular.ttf
+70e76cb000-70e76de000 r-xp 00000000 fc:00 2343                           /system/lib64/libsensor.so
+70e76de000-70e76f5000 ---p 00000000 00:00 0 
+70e76f5000-70e76f8000 r--p 0001d000 fc:00 2343                           /system/lib64/libsensor.so
+70e76f8000-70e76f9000 rw-p 00020000 fc:00 2343                           /system/lib64/libsensor.so
+70e76f9000-70e76fc000 r--s 00000000 fc:00 157                            /system/fonts/NotoSansOldPermic-Regular.otf
+70e76fc000-70e7708000 r--s 00000000 fc:00 189                            /system/fonts/NotoSansSyriacEstrangela-Regular.ttf
+70e7708000-70e771d000 r-xp 00000000 fc:00 2339                           /system/lib64/android.hidl.token@1.0.so
+70e771d000-70e7735000 ---p 00000000 00:00 0 
+70e7735000-70e7737000 r--p 0001e000 fc:00 2339                           /system/lib64/android.hidl.token@1.0.so
+70e7737000-70e7738000 rw-p 00020000 fc:00 2339                           /system/lib64/android.hidl.token@1.0.so
+70e7738000-70e7739000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70e7739000-70e773b000 r--s 00000000 fc:00 267                            /system/fonts/NotoSansOldNorthArabian-Regular.otf
+70e773b000-70e7740000 r--s 00000000 fc:00 208                            /system/fonts/NotoSansManichaean-Regular.otf
+70e7740000-70e775c000 r--s 00000000 fc:00 118                            /system/fonts/NotoSansGujaratiUI-Bold.ttf
+70e775c000-70e7767000 r-xp 00000000 fc:00 2525                           /system/lib64/libappfuse.so
+70e7767000-70e777b000 ---p 00000000 00:00 0 
+70e777b000-70e777c000 r--p 0000f000 fc:00 2525                           /system/lib64/libappfuse.so
+70e777c000-70e777d000 rw-p 00010000 fc:00 2525                           /system/lib64/libappfuse.so
+70e777e000-70e7795000 r--s 00000000 fc:00 250                            /system/fonts/NotoSerifKannada-Bold.ttf
+70e7795000-70e7798000 r-xp 00000000 fc:00 2413                           /system/lib64/libpackagelistparser.so
+70e7798000-70e77b4000 ---p 00000000 00:00 0 
+70e77b4000-70e77b5000 r--p 0000f000 fc:00 2413                           /system/lib64/libpackagelistparser.so
+70e77b5000-70e77b6000 rw-p 00010000 fc:00 2413                           /system/lib64/libpackagelistparser.so
+70e77b6000-70e77b8000 r--s 00000000 fc:00 147                            /system/fonts/NotoSansNabataean-Regular.otf
+70e77b8000-70e77ba000 r--s 00000000 fc:00 146                            /system/fonts/NotoSansMultani-Regular.otf
+70e77ba000-70e77c1000 r--s 00000000 fc:00 214                            /system/fonts/NotoSansPhagsPa-Regular.ttf
+70e77c1000-70e77de000 r--s 00000000 fc:00 90                             /system/fonts/NotoSansGujaratiUI-Regular.ttf
+70e77de000-70e77e0000 r-xp 00000000 fc:00 2430                           /system/lib64/libdl.so
+70e77e0000-70e77fd000 ---p 00000000 00:00 0 
+70e77fd000-70e77fe000 r--p 0000f000 fc:00 2430                           /system/lib64/libdl.so
+70e77fe000-70e77ff000 r--p 00000000 00:00 0                              [anon:.bss]
+70e7800000-70e7809000 r--s 00000000 fc:00 258                            /system/fonts/NotoSansSymbols-Regular-Subsetted2.ttf
+70e7809000-70e7857000 r-xp 00000000 fc:00 2560                           /system/lib64/libjpeg.so
+70e7857000-70e7868000 ---p 00000000 00:00 0 
+70e7868000-70e7869000 r--p 0004f000 fc:00 2560                           /system/lib64/libjpeg.so
+70e7869000-70e786a000 rw-p 00050000 fc:00 2560                           /system/lib64/libjpeg.so
+70e786a000-70e7887000 r--s 00000000 fc:00 237                            /system/fonts/NotoSansGujarati-Bold.ttf
+70e7887000-70e788a000 r-xp 00000000 fc:00 2608                           /system/lib64/libnetd_client.so
+70e788a000-70e78a6000 ---p 00000000 00:00 0 
+70e78a6000-70e78a7000 r--p 0000f000 fc:00 2608                           /system/lib64/libnetd_client.so
+70e78a7000-70e78a8000 rw-p 00010000 fc:00 2608                           /system/lib64/libnetd_client.so
+70e78a8000-70e78aa000 r--s 00000000 fc:00 290                            /system/fonts/NotoSansMro-Regular.otf
+70e78aa000-70e78b9000 r--s 00000000 fc:00 84                             /system/fonts/NotoSansLinearB-Regular.ttf
+70e78b9000-70e78d7000 r--s 00000000 fc:00 287                            /system/fonts/NotoSansGujarati-Regular.ttf
+70e78d7000-70e78d8000 r-xp 00000000 fc:00 2651                           /system/lib64/libvndksupport.so
+70e78d8000-70e78f6000 ---p 00000000 00:00 0 
+70e78f6000-70e78f7000 r--p 0000f000 fc:00 2651                           /system/lib64/libvndksupport.so
+70e78f7000-70e78f8000 rw-p 00010000 fc:00 2651                           /system/lib64/libvndksupport.so
+70e78f9000-70e78fc000 r--s 00000000 fc:00 178                            /system/fonts/NotoSansTaiLe-Regular.ttf
+70e78fc000-70e7900000 r--s 00000000 fc:00 163                            /system/fonts/NotoSansTifinagh-Regular.ttf
+70e7900000-70e7906000 r-xp 00000000 fc:00 2659                           /system/lib64/libnativeloader.so
+70e7906000-70e791f000 ---p 00000000 00:00 0 
+70e791f000-70e7920000 r--p 0000f000 fc:00 2659                           /system/lib64/libnativeloader.so
+70e7920000-70e7921000 rw-p 00010000 fc:00 2659                           /system/lib64/libnativeloader.so
+70e7921000-70e7923000 r--s 00000000 fc:00 268                            /system/fonts/NotoSansHatran-Regular.otf
+70e7923000-70e7927000 r--s 00000000 fc:00 195                            /system/fonts/NotoSansTaiViet-Regular.ttf
+70e7927000-70e7945000 r--s 00000000 fc:00 139                            /system/fonts/NotoSansDevanagariUI-Bold.ttf
+70e7945000-70e79a3000 r-xp 00000000 fc:00 2450                           /system/lib64/libharfbuzz_ng.so
+70e79a3000-70e79b3000 ---p 00000000 00:00 0 
+70e79b3000-70e79b5000 r--p 0005e000 fc:00 2450                           /system/lib64/libharfbuzz_ng.so
+70e79b5000-70e79b6000 rw-p 00060000 fc:00 2450                           /system/lib64/libharfbuzz_ng.so
+70e79b6000-70e79c5000 r--s 00000000 fc:00 111                            /system/fonts/NotoSansKaithi-Regular.ttf
+70e79c5000-70e7a92000 r-xp 00000000 fc:00 2332                           /system/lib64/libc++.so
+70e7a92000-70e7aae000 ---p 00000000 00:00 0 
+70e7aae000-70e7ab8000 r--p 000d6000 fc:00 2332                           /system/lib64/libc++.so
+70e7ab8000-70e7ab9000 rw-p 000e0000 fc:00 2332                           /system/lib64/libc++.so
+70e7ab9000-70e7abc000 rw-p 00000000 00:00 0                              [anon:.bss]
+70e7abc000-70e7abe000 r--s 00000000 fc:00 73                             /system/fonts/NotoSansBassaVah-Regular.otf
+70e7abe000-70e7ac8000 r--s 00000000 fc:00 254                            /system/fonts/NotoSansJavanese-Regular.ttf
+70e7ac8000-70e7acb000 r-xp 00000000 fc:00 2660                           /system/lib64/libnativebridge.so
+70e7acb000-70e7ae7000 ---p 00000000 00:00 0 
+70e7ae7000-70e7ae8000 r--p 0000f000 fc:00 2660                           /system/lib64/libnativebridge.so
+70e7ae8000-70e7ae9000 rw-p 00010000 fc:00 2660                           /system/lib64/libnativebridge.so
+70e7ae9000-70e7aee000 r--s 00000000 fc:00 158                            /system/fonts/NotoSansSaurashtra-Regular.ttf
+70e7aee000-70e7b0f000 r--s 00000000 fc:00 82                             /system/fonts/NotoSansDevanagari-Bold.ttf
+70e7b0f000-70e7b2e000 r-xp 00000000 fc:00 2612                           /system/lib64/libpcre2.so
+70e7b2e000-70e7b3e000 ---p 00000000 00:00 0 
+70e7b3e000-70e7b3f000 r--p 0001f000 fc:00 2612                           /system/lib64/libpcre2.so
+70e7b3f000-70e7b40000 rw-p 00020000 fc:00 2612                           /system/lib64/libpcre2.so
+70e7b40000-70e7bcc000 r-xp 00000000 fc:00 2975                           /system/lib64/libgui.so
+70e7bcc000-70e7be2000 ---p 00000000 00:00 0 
+70e7be2000-70e7bf5000 r--p 0008d000 fc:00 2975                           /system/lib64/libgui.so
+70e7bf5000-70e7bf6000 rw-p 000a0000 fc:00 2975                           /system/lib64/libgui.so
+70e7bf6000-70e7bf7000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70e7bf7000-70e7bf9000 r--s 00000000 fc:00 228                            /system/fonts/NotoSansUgaritic-Regular.ttf
+70e7bf9000-70e7c08000 r--s 00000000 fc:00 89                             /system/fonts/NotoSansCherokee-Regular.ttf
+70e7c08000-70e7dea000 r-xp 00000000 fc:00 2441                           /system/lib64/libandroid_runtime.so
+70e7dea000-70e7e04000 ---p 00000000 00:00 0 
+70e7e04000-70e7e23000 r--p 001e1000 fc:00 2441                           /system/lib64/libandroid_runtime.so
+70e7e23000-70e7e24000 rw-p 00200000 fc:00 2441                           /system/lib64/libandroid_runtime.so
+70e7e24000-70e7e28000 rw-p 00000000 00:00 0                              [anon:.bss]
+70e7e29000-70e7e66000 r--s 00000000 fc:00 74                             /system/fonts/NotoSerif-Bold.ttf
+70e7e66000-70e7ed0000 r-xp 00000000 fc:00 2547                           /system/lib64/libclang_rt.ubsan_standalone-aarch64-android.so
+70e7ed0000-70e7edf000 ---p 00000000 00:00 0 
+70e7edf000-70e7ee1000 r--p 00069000 fc:00 2547                           /system/lib64/libclang_rt.ubsan_standalone-aarch64-android.so
+70e7ee1000-70e7ee4000 rw-p 0006b000 fc:00 2547                           /system/lib64/libclang_rt.ubsan_standalone-aarch64-android.so
+70e7ee4000-70e89f6000 rw-p 00000000 00:00 0                              [anon:.bss]
+70e89f6000-70e89fa000 r--s 00000000 fc:00 127                            /system/fonts/NotoSansSylotiNagri-Regular.ttf
+70e89fa000-70e8a06000 r--s 00000000 fc:00 93                             /system/fonts/NotoSansCanadianAboriginal-Regular.ttf
+70e8a06000-70e8a1b000 r-xp 00000000 fc:00 2460                           /system/lib64/android.hardware.graphics.allocator@2.0.so
+70e8a1b000-70e8a33000 ---p 00000000 00:00 0 
+70e8a33000-70e8a35000 r--p 0001e000 fc:00 2460                           /system/lib64/android.hardware.graphics.allocator@2.0.so
+70e8a35000-70e8a36000 rw-p 00020000 fc:00 2460                           /system/lib64/android.hardware.graphics.allocator@2.0.so
+70e8a36000-70e8a55000 r--s 00000000 fc:00 145                            /system/fonts/NotoSansDevanagariUI-Regular.ttf
+70e8a55000-70e8a61000 r-xp 00000000 fc:00 2540                           /system/lib64/libstagefright_xmlparser.so
+70e8a61000-70e8a74000 ---p 00000000 00:00 0 
+70e8a74000-70e8a75000 r--p 0000f000 fc:00 2540                           /system/lib64/libstagefright_xmlparser.so
+70e8a75000-70e8a76000 rw-p 00010000 fc:00 2540                           /system/lib64/libstagefright_xmlparser.so
+70e8a76000-70e8a78000 r--s 00000000 fc:00 293                            /system/fonts/NotoSansTagbanwa-Regular.ttf
+70e8a78000-70e8a8f000 r--s 00000000 fc:00 161                            /system/fonts/NotoSerifKannada-Regular.ttf
+70e8a8f000-70e8b23000 r-xp 00000000 fc:00 2633                           /system/lib64/libaudioclient.so
+70e8b23000-70e8b37000 ---p 00000000 00:00 0 
+70e8b37000-70e8b49000 r--p 0009e000 fc:00 2633                           /system/lib64/libaudioclient.so
+70e8b49000-70e8b55000 rw-p 000b0000 fc:00 2633                           /system/lib64/libaudioclient.so
+70e8b55000-70e8b9f000 r--s 00000000 fc:00 83                             /system/fonts/RobotoCondensed-Light.ttf
+70e8b9f000-70e8ba1000 r-xp 00000000 fc:00 2520                           /system/lib64/libhardware_legacy.so
+70e8ba1000-70e8bbe000 ---p 00000000 00:00 0 
+70e8bbe000-70e8bbf000 r--p 0000f000 fc:00 2520                           /system/lib64/libhardware_legacy.so
+70e8bbf000-70e8bc0000 rw-p 00010000 fc:00 2520                           /system/lib64/libhardware_legacy.so
+70e8bc0000-70e8be0000 r-xp 00000000 fc:00 2410                           /system/lib64/android.hidl.memory@1.0.so
+70e8be0000-70e8bfa000 ---p 00000000 00:00 0 
+70e8bfa000-70e8bfd000 r--p 0002d000 fc:00 2410                           /system/lib64/android.hidl.memory@1.0.so
+70e8bfd000-70e8bfe000 rw-p 00030000 fc:00 2410                           /system/lib64/android.hidl.memory@1.0.so
+70e8bfe000-70e8bff000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70e8bff000-70e8c02000 r--s 00000000 fc:00 273                            /system/fonts/NotoSansSundanese-Regular.ttf
+70e8c02000-70e8c0f000 r--s 00000000 fc:00 115                            /system/fonts/NotoSansAdlam-Regular.ttf
+70e8c0f000-70e8c18000 r-xp 00000000 fc:00 2350                           /system/lib64/libnetdutils.so
+70e8c18000-70e8c2e000 ---p 00000000 00:00 0 
+70e8c2e000-70e8c2f000 r--p 0000f000 fc:00 2350                           /system/lib64/libnetdutils.so
+70e8c2f000-70e8c30000 rw-p 00010000 fc:00 2350                           /system/lib64/libnetdutils.so
+70e8c30000-70e8c44000 r--s 00000000 fc:00 283                            /system/fonts/NotoSansKannadaUI-Regular.ttf
+70e8c44000-70e8c45000 r-xp 00000000 fc:00 2926                           /system/lib64/libhidlallocatorutils.so
+70e8c45000-70e8c63000 ---p 00000000 00:00 0 
+70e8c63000-70e8c64000 r--p 0000f000 fc:00 2926                           /system/lib64/libhidlallocatorutils.so
+70e8c64000-70e8c65000 rw-p 00010000 fc:00 2926                           /system/lib64/libhidlallocatorutils.so
+70e8c65000-70e8c67000 r--s 00000000 fc:00 65                             /system/fonts/NotoSansTagalog-Regular.ttf
+70e8c67000-70e8c70000 r--s 00000000 fc:00 294                            /system/fonts/NotoSansChakma-Regular.ttf
+70e8c70000-70e8c92000 r--s 00000000 fc:00 116                            /system/fonts/NotoSansDevanagari-Regular.ttf
+70e8c92000-70e8c94000 r-xp 00000000 fc:00 2501                           /system/lib64/libsync.so
+70e8c94000-70e8cb1000 ---p 00000000 00:00 0 
+70e8cb1000-70e8cb2000 r--p 0000f000 fc:00 2501                           /system/lib64/libsync.so
+70e8cb2000-70e8cb3000 rw-p 00010000 fc:00 2501                           /system/lib64/libsync.so
+70e8cb3000-70e8cc6000 r--s 00000000 fc:00 196                            /system/fonts/NotoSerifSinhala-Regular.otf
+70e8cc6000-70e8d5c000 r-xp 00000000 fc:00 2403                           /system/lib64/libmedia.so
+70e8d5c000-70e8d70000 ---p 00000000 00:00 0 
+70e8d70000-70e8d88000 r--p 00098000 fc:00 2403                           /system/lib64/libmedia.so
+70e8d88000-70e8d95000 rw-p 000b0000 fc:00 2403                           /system/lib64/libmedia.so
+70e8d95000-70e8d96000 r--p 00000000 00:00 0                              [anon:atexit handlers]
+70e8d96000-70e8d99000 r--s 00000000 fc:00 247                            /system/fonts/NotoSansSamaritan-Regular.ttf
+70e8d99000-70e8dad000 r--s 00000000 fc:00 108                            /system/fonts/NotoSansKannada-Bold.ttf
+70e8dad000-70e8dcd000 r--s 00000000 fc:00 303                            /system/fonts/NotoSerifEthiopic-Bold.otf
+70e8dcd000-70e8de5000 r-xp 00000000 fc:00 2954                           /system/lib64/libGLESv2.so
+70e8de5000-70e8dfc000 ---p 00000000 00:00 0 
+70e8dfc000-70e8dfd000 r--p 0001f000 fc:00 2954                           /system/lib64/libGLESv2.so
+70e8dfd000-70e8dfe000 rw-p 00020000 fc:00 2954                           /system/lib64/libGLESv2.so
+70e8dfe000-70e8e06000 r--s 00000000 fc:00 265                            /system/fonts/NotoSansBalinese-Regular.ttf
+70e8e06000-70e8e0e000 r--s 00000000 fc:00 219                            /system/fonts/NotoSansLaoUI-Bold.ttf
+70e8e0e000-70e8e12000 r-xp 00000000 fc:00 2617                           /system/lib64/libdebuggerd_client.so
+70e8e12000-70e8e2d000 ---p 00000000 00:00 0 
+70e8e2d000-70e8e2e000 r--p 0000f000 fc:00 2617                           /system/lib64/libdebuggerd_client.so
+70e8e2e000-70e8e2f000 rw-p 00010000 fc:00 2617                           /system/lib64/libdebuggerd_client.so
+70e8e2f000-70e8e4b000 r--s 00000000 fc:00 211                            /system/fonts/NotoSerifEthiopic-Regular.otf
+70e8e4b000-70e8e5e000 r-xp 00000000 fc:00 2484                           /system/lib64/android.hardware.memtrack@1.0.so
+70e8e5e000-70e8e78000 ---p 00000000 00:00 0 
+70e8e78000-70e8e7a000 r--p 0001e000 fc:00 2484                           /system/lib64/android.hardware.memtrack@1.0.so
+70e8e7a000-70e8e7b000 rw-p 00020000 fc:00 2484                           /system/lib64/android.hardware.memtrack@1.0.so
+70e8e7b000-70e8e7d000 r--s 00000000 fc:00 261                            /system/fonts/NotoSansShavian-Regular.ttf
+70e8e7d000-70e8e80000 r--s 00000000 fc:00 204                            /system/fonts/NotoSansRunic-Regular.ttf
+70e8e80000-70e8ea1000 r-xp 00000000 fc:00 2512                           /system/lib64/android.hardware.configstore@1.0.so
+70e8ea1000-70e8ebb000 ---p 00000000 00:00 0 
+70e8ebb000-70e8ebe000 r--p 0002d000 fc:00 2512                           /system/lib64/android.hardware.configstore@1.0.so
+70e8ebe000-70e8ebf000 rw-p 00030000 fc:00 2512                           /system/lib64/android.hardware.configstore@1.0.so
+70e8ebf000-70e8ee3000 r--s 00000000 fc:00 226                            /system/fonts/NotoSansEthiopic-Bold.ttf
+70e8ee3000-70e8f1a000 r-xp 00000000 fc:00 2337                           /system/lib64/libm.so
+70e8f1a000-70e8f32000 ---p 00000000 00:00 0 
+70e8f32000-70e8f33000 r--p 0003f000 fc:00 2337                           /system/lib64/libm.so
+70e8f33000-70e8f34000 rw-p 00040000 fc:00 2337                           /system/lib64/libm.so
+70e8f34000-70e8f36000 r--s 00000000 fc:00 133                            /system/fonts/NotoSansRejang-Regular.ttf
+70e8f36000-70e8f38000 r--s 00000000 fc:00 69                             /system/fonts/NotoSansPhoenician-Regular.ttf
+70e8f38000-70e8f40000 r--s 00000000 fc:00 245                            /system/fonts/NotoSansLaoUI-Regular.ttf
+70e8f40000-70e8f45000 r-xp 00000000 fc:00 2341                           /system/lib64/libstagefright_codecbase.so
+70e8f45000-70e8f5f000 ---p 00000000 00:00 0 
+70e8f5f000-70e8f60000 r--p 0000f000 fc:00 2341                           /system/lib64/libstagefright_codecbase.so
+70e8f60000-70e8f61000 rw-p 00010000 fc:00 2341                           /system/lib64/libstagefright_codecbase.so
+70e8f61000-70e8f62000 r--p 00000000 00:00 0                              [anon:atexit handlers]
+70e8f62000-70e8f66000 r--s 00000000 fc:00 225                            /system/fonts/NotoSansOldPersian-Regular.ttf
+70e8f66000-70e8f89000 r--s 00000000 fc:00 167                            /system/fonts/NotoSansEthiopic-Regular.ttf
+70e8f89000-70e8f92000 r-xp 00000000 fc:00 2515                           /system/lib64/libGLESv1_CM.so
+70e8f92000-70e8fa8000 ---p 00000000 00:00 0 
+70e8fa8000-70e8fa9000 r--p 0000f000 fc:00 2515                           /system/lib64/libGLESv1_CM.so
+70e8fa9000-70e8faa000 rw-p 00010000 fc:00 2515                           /system/lib64/libGLESv1_CM.so
+70e8faa000-70e8fad000 r--s 00000000 fc:00 206                            /system/fonts/NotoSansOsage-Regular.ttf
+70e8fad000-70e8fb5000 r--s 00000000 fc:00 121                            /system/fonts/NotoSerifLao-Bold.ttf
+70e8fb5000-70e8fd3000 r--s 00000000 fc:00 68                             /system/fonts/NotoNaskhArabicUI-Bold.ttf
+70e8fd3000-70e9010000 r-xp 00000000 fc:00 2600                           /system/lib64/android.hardware.cas@1.0.so
+70e9010000-70e9026000 ---p 00000000 00:00 0 
+70e9026000-70e902c000 r--p 0004a000 fc:00 2600                           /system/lib64/android.hardware.cas@1.0.so
+70e902c000-70e902d000 rw-p 00050000 fc:00 2600                           /system/lib64/android.hardware.cas@1.0.so
+70e902d000-70e902e000 r--s 00000000 00:05 31475                          /dev/ashmem/5c7d41a6-003d-45a5-9e3b-2d34c5829a2d (deleted)
+70e902e000-70e9043000 r--s 00000000 fc:00 120                            /system/fonts/NotoSansKannada-Regular.ttf
+70e9043000-70e9067000 r-xp 00000000 fc:00 2729                           /system/lib64/libexpat.so
+70e9067000-70e9081000 ---p 00000000 00:00 0 
+70e9081000-70e9083000 r--p 0002e000 fc:00 2729                           /system/lib64/libexpat.so
+70e9083000-70e9084000 rw-p 00030000 fc:00 2729                           /system/lib64/libexpat.so
+70e9084000-70e9086000 r--s 00000000 fc:00 155                            /system/fonts/NotoSansOsmanya-Regular.ttf
+70e9086000-70e90c3000 r--s 00000000 fc:00 91                             /system/fonts/NotoSerif-Regular.ttf
+70e90c3000-70e91ce000 r-xp 00000000 fc:00 2647                           /system/lib64/libcrypto.so
+70e91ce000-70e91e2000 ---p 00000000 00:00 0 
+70e91e2000-70e91f3000 r--p 0010f000 fc:00 2647                           /system/lib64/libcrypto.so
+70e91f3000-70e91f4000 rw-p 00120000 fc:00 2647                           /system/lib64/libcrypto.so
+70e91f4000-70e91f5000 rw-p 00000000 00:00 0                              [anon:.bss]
+70e91f5000-70e91fa000 r--s 00000000 fc:00 149                            /system/fonts/NotoSansNKo-Regular.ttf
+70e91fa000-70e9202000 r--s 00000000 fc:00 198                            /system/fonts/NotoSerifLao-Regular.ttf
+70e9202000-70e921b000 r-xp 00000000 fc:00 2682                           /system/lib64/libmedia_helper.so
+70e921b000-70e922d000 ---p 00000000 00:00 0 
+70e922d000-70e9230000 r--p 0001d000 fc:00 2682                           /system/lib64/libmedia_helper.so
+70e9230000-70e9231000 rw-p 00020000 fc:00 2682                           /system/lib64/libmedia_helper.so
+70e9231000-70e924a000 r--s 00000000 fc:00 232                            /system/fonts/NotoSansBengali-Bold.ttf
+70e924a000-70e9256000 r-xp 00000000 fc:00 2467                           /system/lib64/libsoundtrigger.so
+70e9256000-70e9272000 ---p 00000000 00:00 0 
+70e9272000-70e9276000 r--p 0000c000 fc:00 2467                           /system/lib64/libsoundtrigger.so
+70e9276000-70e9277000 rw-p 00010000 fc:00 2467                           /system/lib64/libsoundtrigger.so
+70e9277000-70e9278000 r--s 00000000 fc:01 1177                           /vendor/overlay/Pixel/PixelThemeOverlay.apk
+70e9278000-70e927c000 r--s 00000000 fc:00 215                            /system/fonts/NotoSansNewTaiLue-Regular.ttf
+70e927c000-70e929a000 r--s 00000000 fc:00 235                            /system/fonts/NotoNaskhArabicUI-Regular.ttf
+70e929a000-70e929b000 r-xp 00000000 fc:00 2375                           /system/lib64/android.hardware.graphics.common@1.1.so
+70e929b000-70e92b9000 ---p 00000000 00:00 0 
+70e92b9000-70e92ba000 r--p 0000f000 fc:00 2375                           /system/lib64/android.hardware.graphics.common@1.1.so
+70e92ba000-70e92bb000 rw-p 00010000 fc:00 2375                           /system/lib64/android.hardware.graphics.common@1.1.so
+70e92bb000-70e92da000 r--s 00000000 fc:00 281                            /system/fonts/GoogleSans-BoldItalic.ttf
+70e92da000-70e9302000 r-xp 00000000 fc:00 2529                           /system/lib64/libinput.so
+70e9302000-70e931b000 ---p 00000000 00:00 0 
+70e931b000-70e9322000 r--p 00029000 fc:00 2529                           /system/lib64/libinput.so
+70e9322000-70e9323000 rw-p 00030000 fc:00 2529                           /system/lib64/libinput.so
+70e9323000-70e9340000 r--s 00000000 fc:00 130                            /system/fonts/NotoNaskhArabic-Bold.ttf
+70e9340000-70e934b000 r-xp 00000000 fc:00 2451                           /system/lib64/libbpf.so
+70e934b000-70e935f000 ---p 00000000 00:00 0 
+70e935f000-70e9360000 r--p 0000f000 fc:00 2451                           /system/lib64/libbpf.so
+70e9360000-70e9361000 rw-p 00010000 fc:00 2451                           /system/lib64/libbpf.so
+70e9361000-70e9367000 r--s 00000000 fc:00 96                             /system/fonts/NotoSansKharoshthi-Regular.ttf
+70e9367000-70e9385000 r--s 00000000 fc:00 151                            /system/fonts/GoogleSans-Bold.ttf
+70e9385000-70e93b8000 r-xp 00000000 fc:00 2494                           /system/lib64/libpng.so
+70e93b8000-70e93d4000 ---p 00000000 00:00 0 
+70e93d4000-70e93d5000 r--p 0003f000 fc:00 2494                           /system/lib64/libpng.so
+70e93d5000-70e93d6000 rw-p 00040000 fc:00 2494                           /system/lib64/libpng.so
+70e93d6000-70e93d7000 r--s 00004000 fc:01 1177                           /vendor/overlay/Pixel/PixelThemeOverlay.apk
+70e93d7000-70e93d9000 r--s 00000000 fc:00 295                            /system/fonts/NotoSansOldTurkic-Regular.ttf
+70e93d9000-70e93e5000 r--s 00000000 fc:00 86                             /system/fonts/NotoSerifKhmer-Bold.otf
+70e93e5000-70e9404000 r--s 00000000 fc:00 240                            /system/fonts/GoogleSans-MediumItalic.ttf
+70e9404000-70e9409000 r-xp 00000000 fc:00 2404                           /system/lib64/libhidlmemory.so
+70e9409000-70e9423000 ---p 00000000 00:00 0 
+70e9423000-70e9424000 r--p 0000f000 fc:00 2404                           /system/lib64/libhidlmemory.so
+70e9424000-70e9425000 rw-p 00010000 fc:00 2404                           /system/lib64/libhidlmemory.so
+70e9425000-70e943e000 r--s 00000000 fc:00 185                            /system/fonts/NotoSansBengali-Regular.ttf
+70e943e000-70e945c000 r--s 00000000 fc:00 129                            /system/fonts/GoogleSans-Medium.ttf
+70e945c000-70e960c000 r-xp 00000000 fc:00 2398                           /system/lib64/libstagefright.so
+70e960c000-70e9625000 ---p 00000000 00:00 0 
+70e9625000-70e9638000 r--p 001bd000 fc:00 2398                           /system/lib64/libstagefright.so
+70e9638000-70e966c000 rw-p 001d0000 fc:00 2398                           /system/lib64/libstagefright.so
+70e966c000-70e966d000 rw-p 00000000 00:00 0                              [anon:.bss]
+70e966d000-70e966e000 r--s 00000000 103:1d 1474566                       /data/resource-cache/vendor@overlay@Pixel@PixelThemeOverlay.apk@idmap
+70e966e000-70e9672000 r--s 00000000 fc:00 241                            /system/fonts/NotoSansMeeteiMayek-Regular.ttf
+70e9672000-70e9680000 r--s 00000000 fc:00 150                            /system/fonts/NotoSansMalayalamUI-Bold.ttf
+70e9680000-70e96a7000 r-xp 00000000 fc:00 2365                           /system/lib64/libhwbinder.so
+70e96a7000-70e96bd000 ---p 00000000 00:00 0 
+70e96bd000-70e96bf000 r--p 0002e000 fc:00 2365                           /system/lib64/libhwbinder.so
+70e96bf000-70e96c0000 rw-p 00030000 fc:00 2365                           /system/lib64/libhwbinder.so
+70e96c0000-70e96c1000 r--s 00088000 103:1d 1736830                       /data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/base.apk
+70e96c1000-70e96cb000 r--s 00000000 fc:00 94                             /system/fonts/NotoSansKhmerUI-Regular.ttf
+70e96cb000-70e96d9000 r--s 00000000 fc:00 275                            /system/fonts/NotoSansMalayalamUI-Regular.ttf
+70e96d9000-70e96dd000 r-xp 00000000 fc:00 2386                           /system/lib64/libusbhost.so
+70e96dd000-70e96f8000 ---p 00000000 00:00 0 
+70e96f8000-70e96f9000 r--p 0000f000 fc:00 2386                           /system/lib64/libusbhost.so
+70e96f9000-70e96fa000 rw-p 00010000 fc:00 2386                           /system/lib64/libusbhost.so
+70e96fa000-70e96fb000 r--p 00000000 00:05 10266154                       /dev/ashmem/dalvik-classes.dex extracted in memory from /data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/base.apk (deleted)
+70e96fb000-70e9701000 r--s 00000000 fc:00 280                            /system/fonts/NotoSansCoptic-Regular.ttf
+70e9701000-70e9720000 r-xp 00000000 fc:00 2490                           /system/lib64/libstagefright_bufferqueue_helper.so
+70e9720000-70e973b000 ---p 00000000 00:00 0 
+70e973b000-70e973e000 r--p 0002d000 fc:00 2490                           /system/lib64/libstagefright_bufferqueue_helper.so
+70e973e000-70e9740000 rw-p 00030000 fc:00 2490                           /system/lib64/libstagefright_bufferqueue_helper.so
+70e9740000-70e9742000 r--s 00000000 fc:00 141                            /system/fonts/NotoSansOldSouthArabian-Regular.ttf
+70e9742000-70e974c000 r--s 00000000 fc:00 229                            /system/fonts/NotoSerifKhmer-Regular.otf
+70e974c000-70e9759000 r--s 00000000 fc:00 260                            /system/fonts/NotoSerifMalayalam-Bold.ttf
+70e9759000-70e97c7000 r-xp 00000000 fc:00 2428                           /system/lib64/libstagefright_omx.so
+70e97c7000-70e97dc000 ---p 00000000 00:00 0 
+70e97dc000-70e97e6000 r--p 00076000 fc:00 2428                           /system/lib64/libstagefright_omx.so
+70e97e6000-70e97ed000 rw-p 00080000 fc:00 2428                           /system/lib64/libstagefright_omx.so
+70e97ed000-70e97fa000 r--s 00000000 fc:00 66                             /system/fonts/NotoSerifMalayalam-Regular.ttf
+70e97fa000-70e9819000 r--s 00000000 fc:00 183                            /system/fonts/GoogleSans-Italic.ttf
+70e9819000-70e9856000 r-xp 00000000 fc:00 2434                           /system/lib64/libprotobuf-cpp-lite.so
+70e9856000-70e9867000 ---p 00000000 00:00 0 
+70e9867000-70e9869000 r--p 0003e000 fc:00 2434                           /system/lib64/libprotobuf-cpp-lite.so
+70e9869000-70e986a000 rw-p 00040000 fc:00 2434                           /system/lib64/libprotobuf-cpp-lite.so
+70e986a000-70e9873000 r--s 00000000 fc:00 134                            /system/fonts/NotoSansKhmerUI-Bold.ttf
+70e9873000-70e9891000 r--s 00000000 fc:00 81                             /system/fonts/GoogleSans-Regular.ttf
+70e9891000-70e989e000 r-xp 00000000 fc:00 2377                           /system/lib64/libmediametrics.so
+70e989e000-70e98ae000 ---p 00000000 00:00 0 
+70e98ae000-70e98b0000 r--p 0000e000 fc:00 2377                           /system/lib64/libmediametrics.so
+70e98b0000-70e98b1000 rw-p 00010000 fc:00 2377                           /system/lib64/libmediametrics.so
+70e98b1000-70e98b9000 r--s 00000000 fc:00 152                            /system/fonts/NotoSansLao-Bold.ttf
+70e98b9000-70e98c7000 r--s 00000000 fc:00 279                            /system/fonts/NotoSansMalayalam-Bold.ttf
+70e98c7000-70e98ca000 r-xp 00000000 fc:00 2952                           /system/lib64/libETC1.so
+70e98ca000-70e98e6000 ---p 00000000 00:00 0 
+70e98e6000-70e98e7000 r--p 0000f000 fc:00 2952                           /system/lib64/libETC1.so
+70e98e7000-70e98e8000 rw-p 00010000 fc:00 2952                           /system/lib64/libETC1.so
+70e98e8000-70e98e9000 r--s 00000000 fc:00 1121                           /system/usr/hyphen-data/hyph-und-ethi.hyb
+70e98e9000-70e98ef000 r--s 00000000 fc:00 64                             /system/fonts/NotoSansBrahmi-Regular.ttf
+70e98ef000-70e990f000 rw-p 00000000 00:05 10271012                       /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70e990f000-70e9926000 r-xp 00000000 fc:00 2526                           /system/lib64/libbacktrace.so
+70e9926000-70e993e000 ---p 00000000 00:00 0 
+70e993e000-70e993f000 r--p 0001f000 fc:00 2526                           /system/lib64/libbacktrace.so
+70e993f000-70e9940000 rw-p 00020000 fc:00 2526                           /system/lib64/libbacktrace.so
+70e9940000-70e9941000 r--s 00000000 fc:00 1129                           /system/usr/hyphen-data/hyph-tk.hyb
+70e9941000-70e99a4000 r-xp 00000000 fc:00 2528                           /system/lib64/libcamera_client.so
+70e99a4000-70e99bc000 ---p 00000000 00:00 0 
+70e99bc000-70e99c9000 r--p 00063000 fc:00 2528                           /system/lib64/libcamera_client.so
+70e99c9000-70e99d0000 rw-p 00070000 fc:00 2528                           /system/lib64/libcamera_client.so
+70e99d0000-70e99d1000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70e99d1000-70e99d3000 r--s 00000000 fc:00 200                            /system/fonts/NotoSansOldItalic-Regular.ttf
+70e99d3000-70e99e1000 r--s 00000000 fc:00 153                            /system/fonts/NotoSansMalayalam-Regular.ttf
+70e99e1000-70e9a01000 rw-p 00000000 00:05 10271011                       /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70e9a01000-70e9a1e000 r-xp 00000000 fc:00 2542                           /system/lib64/libimg_utils.so
+70e9a1e000-70e9a39000 ---p 00000000 00:00 0 
+70e9a39000-70e9a3c000 r--p 0001d000 fc:00 2542                           /system/lib64/libimg_utils.so
+70e9a3c000-70e9a3f000 rw-p 00020000 fc:00 2542                           /system/lib64/libimg_utils.so
+70e9a3f000-70e9a5c000 r--s 00000000 fc:00 262                            /system/fonts/NotoNaskhArabic-Regular.ttf
+70e9a5c000-70e9a69000 r-xp 00000000 fc:00 2706                           /system/lib64/libziparchive.so
+70e9a69000-70e9a7b000 ---p 00000000 00:00 0 
+70e9a7b000-70e9a7c000 r--p 0000f000 fc:00 2706                           /system/lib64/libziparchive.so
+70e9a7c000-70e9a7d000 rw-p 00010000 fc:00 2706                           /system/lib64/libziparchive.so
+70e9a7d000-70e9a85000 r--s 00000000 fc:00 119                            /system/fonts/NotoSansLao-Regular.ttf
+70e9a85000-70e9a8e000 r--s 00000000 fc:00 77                             /system/fonts/NotoSansTamilUI-Bold.ttf
+70e9a8e000-70e9a97000 r--s 00000000 fc:00 160                            /system/fonts/NotoSansTamilUI-Regular.ttf
+70e9a97000-70e9a9d000 r-xp 00000000 fc:00 2536                           /system/lib64/libnativehelper.so
+70e9a9d000-70e9ab6000 ---p 00000000 00:00 0 
+70e9ab6000-70e9ab7000 r--p 0000f000 fc:00 2536                           /system/lib64/libnativehelper.so
+70e9ab7000-70e9ab8000 rw-p 00010000 fc:00 2536                           /system/lib64/libnativehelper.so
+70e9ab8000-70e9ab9000 r--s 00000000 fc:00 1134                           /system/usr/hyphen-data/hyph-te.hyb
+70e9ab9000-70e9ac2000 r--s 00000000 fc:00 246                            /system/fonts/NotoSerifTamil-Bold.ttf
+70e9ac2000-70e9acb000 r--s 00000000 fc:00 302                            /system/fonts/NotoSerifTamil-Regular.ttf
+70e9acb000-70e9af4000 r-xp 00000000 fc:00 2950                           /system/lib64/libmemunreachable.so
+70e9af4000-70e9b09000 ---p 00000000 00:00 0 
+70e9b09000-70e9b0b000 r--p 0002e000 fc:00 2950                           /system/lib64/libmemunreachable.so
+70e9b0b000-70e9b0c000 rw-p 00030000 fc:00 2950                           /system/lib64/libmemunreachable.so
+70e9b0c000-70e9b0d000 r--s 00000000 fc:00 1088                           /system/usr/hyphen-data/hyph-ta.hyb
+70e9b0d000-70e9b0f000 r--s 00000000 fc:00 72                             /system/fonts/NotoSansOlChiki-Regular.ttf
+70e9b0f000-70e9b2f000 rw-p 00000000 00:05 10271010                       /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70e9b2f000-70e9b4f000 r--s 00000000 00:10 16633                          /dev/__properties__/u:object_r:persist_debug_prop:s0
+70e9b4f000-70e9b65000 r-xp 00000000 fc:00 2920                           /system/lib64/android.hardware.cas.native@1.0.so
+70e9b65000-70e9b7b000 ---p 00000000 00:00 0 
+70e9b7b000-70e9b7d000 r--p 0001e000 fc:00 2920                           /system/lib64/android.hardware.cas.native@1.0.so
+70e9b7d000-70e9b7e000 rw-p 00020000 fc:00 2920                           /system/lib64/android.hardware.cas.native@1.0.so
+70e9b7e000-70e9b7f000 r--s 00000000 fc:00 1145                           /system/usr/hyphen-data/hyph-pt.hyb
+70e9b7f000-70e9b83000 r--s 00000000 fc:00 277                            /system/fonts/NotoSansMandaic-Regular.ttf
+70e9b83000-70e9bdb000 r-xp 00000000 fc:00 2334                           /system/lib64/libsonivox.so
+70e9bdb000-70e9bf2000 ---p 00000000 00:00 0 
+70e9bf2000-70e9bf3000 r--p 0005f000 fc:00 2334                           /system/lib64/libsonivox.so
+70e9bf3000-70e9bf4000 rw-p 00060000 fc:00 2334                           /system/lib64/libsonivox.so
+70e9bf4000-70e9bfb000 rw-p 00000000 00:00 0                              [anon:.bss]
+70e9bfb000-70e9c01000 r--s 00000000 fc:00 123                            /system/fonts/NotoSansCham-Bold.ttf
+70e9c01000-70e9c0a000 r--s 00000000 fc:00 255                            /system/fonts/NotoSansTamil-Bold.ttf
+70e9c0a000-70e9c13000 r--s 00000000 fc:00 135                            /system/fonts/NotoSansTamil-Regular.ttf
+70e9c13000-70e9c15000 r-xp 00000000 fc:00 2519                           /system/lib64/libgraphicsenv.so
+70e9c15000-70e9c32000 ---p 00000000 00:00 0 
+70e9c32000-70e9c33000 r--p 0000f000 fc:00 2519                           /system/lib64/libgraphicsenv.so
+70e9c33000-70e9c34000 rw-p 00010000 fc:00 2519                           /system/lib64/libgraphicsenv.so
+70e9c34000-70e9c3a000 r--s 00000000 fc:00 259                            /system/fonts/NotoSansCham-Regular.ttf
+70e9c3a000-70e9c42000 r--s 00000000 fc:00 114                            /system/fonts/NotoSansGurmukhiUI-Bold.ttf
+70e9c42000-70e9c4a000 r--s 00000000 fc:00 122                            /system/fonts/NotoSansGurmukhiUI-Regular.ttf
+70e9c4a000-70e9c5f000 r-xp 00000000 fc:00 2348                           /system/lib64/android.hidl.allocator@1.0.so
+70e9c5f000-70e9c77000 ---p 00000000 00:00 0 
+70e9c77000-70e9c79000 r--p 0001e000 fc:00 2348                           /system/lib64/android.hidl.allocator@1.0.so
+70e9c79000-70e9c7a000 rw-p 00020000 fc:00 2348                           /system/lib64/android.hidl.allocator@1.0.so
+70e9c7a000-70e9c7b000 r--s 00000000 fc:00 1095                           /system/usr/hyphen-data/hyph-pa.hyb
+70e9c7b000-70e9c83000 r--s 00000000 fc:00 298                            /system/fonts/NotoSerifGurmukhi-Bold.otf
+70e9c83000-70e9d01000 r-xp 00000000 fc:00 2665                           /system/lib64/libbinder.so
+70e9d01000-70e9d1e000 ---p 00000000 00:00 0 
+70e9d1e000-70e9d2e000 r--p 00080000 fc:00 2665                           /system/lib64/libbinder.so
+70e9d2e000-70e9d2f000 rw-p 00090000 fc:00 2665                           /system/lib64/libbinder.so
+70e9d2f000-70e9d4f000 rw-p 00000000 00:05 10271009                       /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70e9d4f000-70e9d53000 r-xp 00000000 fc:00 2454                           /system/lib64/libaudiomanager.so
+70e9d53000-70e9d6e000 ---p 00000000 00:00 0 
+70e9d6e000-70e9d6f000 r--p 0000f000 fc:00 2454                           /system/lib64/libaudiomanager.so
+70e9d6f000-70e9d70000 rw-p 00010000 fc:00 2454                           /system/lib64/libaudiomanager.so
+70e9d70000-70e9d71000 r--s 00000000 fc:00 1087                           /system/usr/hyphen-data/hyph-or.hyb
+70e9d71000-70e9d91000 rw-p 00000000 00:05 10271008                       /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70e9d91000-70e9e21000 r-xp 00000000 fc:00 2627                           /system/lib64/libft2.so
+70e9e21000-70e9e37000 ---p 00000000 00:00 0 
+70e9e37000-70e9e3c000 r--p 0009b000 fc:00 2627                           /system/lib64/libft2.so
+70e9e3c000-70e9e3d000 rw-p 000a0000 fc:00 2627                           /system/lib64/libft2.so
+70e9e3d000-70e9e3e000 r--s 00000000 fc:00 1142                           /system/usr/hyphen-data/hyph-mr.hyb
+70e9e3e000-70e9e45000 r--s 00000000 fc:00 88                             /system/fonts/NotoSerifGurmukhi-Regular.otf
+70e9e45000-70e9e65000 r--s 00000000 00:10 16594                          /dev/__properties__/u:object_r:exported3_default_prop:s0
+70e9e65000-70e9e7f000 r-xp 00000000 fc:00 2643                           /system/lib64/libunwind.so
+70e9e7f000-70e9e94000 ---p 00000000 00:00 0 
+70e9e94000-70e9e95000 r--p 0001f000 fc:00 2643                           /system/lib64/libunwind.so
+70e9e95000-70e9e96000 rw-p 00020000 fc:00 2643                           /system/lib64/libunwind.so
+70e9e96000-70e9eff000 rw-p 00000000 00:00 0                              [anon:.bss]
+70e9eff000-70e9f00000 r--s 00000000 fc:00 1130                           /system/usr/hyphen-data/hyph-ml.hyb
+70e9f00000-70e9f02000 r--s 00000000 fc:00 75                             /system/fonts/NotoSansOgham-Regular.ttf
+70e9f02000-70e9f0a000 r--s 00000000 fc:00 193                            /system/fonts/NotoSansGurmukhi-Bold.ttf
+70e9f0a000-70ea022000 r-xp 00000000 fc:00 2328                           /system/lib64/libsqlite.so
+70ea022000-70ea033000 ---p 00000000 00:00 0 
+70ea033000-70ea036000 r--p 0011d000 fc:00 2328                           /system/lib64/libsqlite.so
+70ea036000-70ea038000 rw-p 00120000 fc:00 2328                           /system/lib64/libsqlite.so
+70ea038000-70ea03c000 r--s 00000000 fc:00 285                            /system/fonts/NotoSansGlagolitic-Regular.ttf
+70ea03c000-70ea04c000 r--s 00000000 fc:00 184                            /system/fonts/NotoSerifGujarati-Bold.ttf
+70ea04c000-70ea060000 r-xp 00000000 fc:00 2731                           /system/lib64/libstatslog.so
+70ea060000-70ea07b000 ---p 00000000 00:00 0 
+70ea07b000-70ea07c000 r--p 0001f000 fc:00 2731                           /system/lib64/libstatslog.so
+70ea07c000-70ea07d000 rw-p 00020000 fc:00 2731                           /system/lib64/libstatslog.so
+70ea07d000-70ea081000 r--s 00000000 fc:00 182                            /system/fonts/NotoSansBatak-Regular.ttf
+70ea081000-70ea091000 r--s 00000000 fc:00 264                            /system/fonts/NotoSerifGujarati-Regular.ttf
+70ea091000-70ea160000 r-xp 00000000 fc:00 2728                           /system/lib64/libdng_sdk.so
+70ea160000-70ea173000 ---p 00000000 00:00 0 
+70ea173000-70ea17a000 r--p 000d9000 fc:00 2728                           /system/lib64/libdng_sdk.so
+70ea17a000-70ea17b000 rw-p 000e0000 fc:00 2728                           /system/lib64/libdng_sdk.so
+70ea17b000-70ea198000 r--s 00000000 fc:00 223                            /system/fonts/DancingScript-Bold.ttf
+70ea198000-70ea19c000 r-xp 00000000 fc:00 2344                           /system/lib64/libnativewindow.so
+70ea19c000-70ea1b7000 ---p 00000000 00:00 0 
+70ea1b7000-70ea1b8000 r--p 0000f000 fc:00 2344                           /system/lib64/libnativewindow.so
+70ea1b8000-70ea1b9000 rw-p 00010000 fc:00 2344                           /system/lib64/libnativewindow.so
+70ea1b9000-70ea1bd000 r--s 00000000 fc:00 98                             /system/fonts/NotoSansAhom-Regular.otf
+70ea1bd000-70ea1d1000 r--s 00000000 fc:00 104                            /system/fonts/NotoSerifDevanagari-Bold.ttf
+70ea1d1000-70ea1d4000 r-xp 00000000 fc:00 2923                           /system/lib64/libstdc++.so
+70ea1d4000-70ea1f0000 ---p 00000000 00:00 0 
+70ea1f0000-70ea1f1000 r--p 0000f000 fc:00 2923                           /system/lib64/libstdc++.so
+70ea1f1000-70ea1f2000 rw-p 00010000 fc:00 2923                           /system/lib64/libstdc++.so
+70ea1f2000-70ea1f4000 r--s 00000000 fc:00 117                            /system/fonts/NotoSansLydian-Regular.ttf
+70ea1f4000-70ea211000 r--s 00000000 fc:00 239                            /system/fonts/DancingScript-Regular.ttf
+70ea211000-70ea24a000 r-xp 00000000 fc:00 2933                           /system/lib64/android.hardware.graphics.bufferqueue@1.0.so
+70ea24a000-70ea268000 ---p 00000000 00:00 0 
+70ea268000-70ea26c000 r--p 0003c000 fc:00 2933                           /system/lib64/android.hardware.graphics.bufferqueue@1.0.so
+70ea26c000-70ea26d000 rw-p 00040000 fc:00 2933                           /system/lib64/android.hardware.graphics.bufferqueue@1.0.so
+70ea26d000-70ea26f000 r--s 00000000 fc:00 244                            /system/fonts/NotoSansLycian-Regular.ttf
+70ea26f000-70ea273000 r--s 00000000 fc:00 173                            /system/fonts/NotoSansThaana-Bold.ttf
+70ea273000-70ea287000 r--s 00000000 fc:00 106                            /system/fonts/NotoSerifDevanagari-Regular.ttf
+70ea287000-70ea29e000 r-xp 00000000 fc:00 2938                           /system/lib64/libpiex.so
+70ea29e000-70ea2b6000 ---p 00000000 00:00 0 
+70ea2b6000-70ea2b7000 r--p 0001f000 fc:00 2938                           /system/lib64/libpiex.so
+70ea2b7000-70ea2b8000 rw-p 00020000 fc:00 2938                           /system/lib64/libpiex.so
+70ea2b8000-70ea2c0000 r--s 00000000 fc:00 113                            /system/fonts/NotoSansGurmukhi-Regular.ttf
+70ea2c0000-70ea2c6000 r--s 00000000 fc:00 263                            /system/fonts/NotoSerifGeorgian-Bold.ttf
+70ea2c6000-70ea2cc000 r--s 00000000 fc:00 249                            /system/fonts/NotoSerifGeorgian-Regular.ttf
+70ea2cc000-70ea9b4000 r-xp 00000000 fc:00 2532                           /system/lib64/libhwui.so
+70ea9b4000-70ea9d3000 ---p 00000000 00:00 0 
+70ea9d3000-70eaa0b000 r--p 006e8000 fc:00 2532                           /system/lib64/libhwui.so
+70eaa0b000-70eaa0c000 rw-p 00720000 fc:00 2532                           /system/lib64/libhwui.so
+70eaa0c000-70eaa11000 rw-p 00000000 00:00 0                              [anon:.bss]
+70eaa11000-70eaa12000 r--s 00000000 fc:00 1110                           /system/usr/hyphen-data/hyph-la.hyb
+70eaa12000-70eaa16000 r--s 00000000 fc:00 87                             /system/fonts/NotoSansThaana-Regular.ttf
+70eaa16000-70eaa1b000 r--s 00000000 fc:00 218                            /system/fonts/NotoSansGeorgian-Bold.ttf
+70eaa1b000-70eaa20000 r--s 00000000 fc:00 125                            /system/fonts/NotoSansGeorgian-Regular.ttf
+70eaa20000-70eaa40000 rw-p 00000000 00:05 10271007                       /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70eaa40000-70eaaa0000 r-xp 00000000 fc:00 2384                           /system/lib64/libhidltransport.so
+70eaaa0000-70eaabe000 ---p 00000000 00:00 0 
+70eaabe000-70eaac6000 r--p 00068000 fc:00 2384                           /system/lib64/libhidltransport.so
+70eaac6000-70eaac7000 rw-p 00070000 fc:00 2384                           /system/lib64/libhidltransport.so
+70eaac7000-70eaacb000 r--s 00000000 fc:00 192                            /system/fonts/NotoSerifArmenian-Bold.ttf
+70eaacb000-70eaad0000 r--s 00000000 fc:00 210                            /system/fonts/NotoSansThaiUI-Bold.ttf
+70eaad0000-70eaaf0000 rw-p 00000000 00:05 10271006                       /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70eaaf0000-70eab10000 rw-p 00000000 00:05 10271005                       /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70eab10000-70eab57000 r-xp 00000000 fc:00 2546                           /system/lib64/libmedia_omx.so
+70eab57000-70eab6d000 ---p 00000000 00:00 0 
+70eab6d000-70eab7a000 r--p 00053000 fc:00 2546                           /system/lib64/libmedia_omx.so
+70eab7a000-70eab7f000 rw-p 00060000 fc:00 2546                           /system/lib64/libmedia_omx.so
+70eab7f000-70eab80000 r--s 00000000 fc:00 1119                           /system/usr/hyphen-data/hyph-kn.hyb
+70eab80000-70eab86000 r--s 00000000 fc:00 224                            /system/fonts/NotoSansThaiUI-Regular.ttf
+70eab86000-70eab8b000 r--s 00000000 fc:00 300                            /system/fonts/NotoSerifThai-Bold.ttf
+70eab8b000-70eabab000 rw-p 00000000 00:05 10271004                       /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70eabab000-70eac21000 r-xp 00000000 fc:00 2385                           /system/lib64/libvintf.so
+70eac21000-70eac31000 ---p 00000000 00:00 0 
+70eac31000-70eac36000 r--p 0007b000 fc:00 2385                           /system/lib64/libvintf.so
+70eac36000-70eac37000 rw-p 00080000 fc:00 2385                           /system/lib64/libvintf.so
+70eac37000-70eac39000 rw-p 00000000 00:00 0                              [anon:.bss]
+70eac39000-70eac3a000 r--s 00000000 fc:00 1104                           /system/usr/hyphen-data/hyph-hy.hyb
+70eac3a000-70eac3f000 r--s 00000000 fc:00 212                            /system/fonts/NotoSerifThai-Regular.ttf
+70eac3f000-70eac44000 r--s 00000000 fc:00 220                            /system/fonts/NotoSansThai-Bold.ttf
+70eac44000-70eacb2000 r-xp 00000000 fc:00 2606                           /system/lib64/android.hardware.media.omx@1.0.so
+70eacb2000-70eaccf000 ---p 00000000 00:00 0 
+70eaccf000-70eacd8000 r--p 00077000 fc:00 2606                           /system/lib64/android.hardware.media.omx@1.0.so
+70eacd8000-70eacd9000 rw-p 00080000 fc:00 2606                           /system/lib64/android.hardware.media.omx@1.0.so
+70eacd9000-70eacdf000 r--s 00000000 fc:00 169                            /system/fonts/NotoSansThai-Regular.ttf
+70eacdf000-70eace9000 r--s 00000000 fc:00 140                            /system/fonts/CarroisGothicSC-Regular.ttf
+70eace9000-70ead09000 rw-p 00000000 00:05 10271003                       /dev/ashmem/dalvik-CompilerMetadata (deleted)
+70ead09000-70ead22000 r-xp 00000000 fc:00 2539                           /system/lib64/android.hardware.graphics.mapper@2.1.so
+70ead22000-70ead34000 ---p 00000000 00:00 0 
+70ead34000-70ead37000 r--p 0001d000 fc:00 2539                           /system/lib64/android.hardware.graphics.mapper@2.1.so
+70ead37000-70ead38000 rw-p 00020000 fc:00 2539                           /system/lib64/android.hardware.graphics.mapper@2.1.so
+70ead38000-70ead47000 r--s 00000000 fc:00 188                            /system/fonts/ComingSoon.ttf
+70ead47000-70ead5d000 r-xp 00000000 fc:00 2379                           /system/lib64/libselinux.so
+70ead5d000-70ead76000 ---p 00000000 00:00 0 
+70ead76000-70ead77000 r--p 0001f000 fc:00 2379                           /system/lib64/libselinux.so
+70ead77000-70ead78000 rw-p 00020000 fc:00 2379                           /system/lib64/libselinux.so
+70ead78000-70ead79000 rw-p 00000000 00:00 0                              [anon:.bss]
+70ead79000-70ead7d000 r--s 00000000 fc:00 282                            /system/fonts/NotoSerifArmenian-Regular.ttf
+70ead7d000-70ead82000 r--s 00000000 fc:00 288                            /system/fonts/NotoSerifHebrew-Bold.ttf
+70ead82000-70ead83000 r-xp 00000000 fc:00 2680                           /system/lib64/android.hardware.media@1.0.so
+70ead83000-70eada1000 ---p 00000000 00:00 0 
+70eada1000-70eada2000 r--p 0000f000 fc:00 2680                           /system/lib64/android.hardware.media@1.0.so
+70eada2000-70eada3000 rw-p 00010000 fc:00 2680                           /system/lib64/android.hardware.media@1.0.so
+70eada3000-70eada8000 r--s 00000000 fc:00 248                            /system/fonts/NotoSerifHebrew-Regular.ttf
+70eada8000-70eadb9000 r--s 00000000 fc:00 252                            /system/fonts/CutiveMono.ttf
+70eadb9000-70eadd9000 r--s 00000000 00:10 16641                          /dev/__properties__/u:object_r:radio_prop:s0
+70eadd9000-70eadda000 r-xp 00000000 fc:00 2533                           /system/lib64/android.hardware.graphics.common@1.0.so
+70eadda000-70eadf8000 ---p 00000000 00:00 0 
+70eadf8000-70eadf9000 r--p 0000f000 fc:00 2533                           /system/lib64/android.hardware.graphics.common@1.0.so
+70eadf9000-70eadfa000 rw-p 00010000 fc:00 2533                           /system/lib64/android.hardware.graphics.common@1.0.so
+70eadfa000-70eadfb000 r--s 00000000 fc:00 1126                           /system/usr/hyphen-data/hyph-hr.hyb
+70eadfb000-70eadfd000 r--s 00000000 fc:00 194                            /system/fonts/NotoSansLisu-Regular.ttf
+70eadfd000-70eae18000 r--s 00000000 fc:00 201                            /system/fonts/DroidSansMono.ttf
+70eae18000-70eae3b000 r-xp 00000000 fc:00 2925                           /system/lib64/liblzma.so
+70eae3b000-70eae57000 ---p 00000000 00:00 0 
+70eae57000-70eae58000 r--p 0002f000 fc:00 2925                           /system/lib64/liblzma.so
+70eae58000-70eae59000 rw-p 00030000 fc:00 2925                           /system/lib64/liblzma.so
+70eae59000-70eae5f000 rw-p 00000000 00:00 0                              [anon:.bss]
+70eae5f000-70eae62000 r--s 00000000 fc:00 103                            /system/fonts/NotoSansLimbu-Regular.ttf
+70eae62000-70eae67000 r--s 00000000 fc:00 236                            /system/fonts/NotoSansHebrew-Bold.ttf
+70eae67000-70eae84000 r--s 001c2000 fc:00 990                            /system/framework/ext.jar
+70eae84000-70eaea4000 rw-p 00000000 00:05 10269720                       /dev/ashmem/dalvik-LinearAlloc (deleted)
+70eaea4000-70eaede000 r-xp 00000000 fc:00 2924                           /system/lib64/libwilhelm.so
+70eaede000-70eaefa000 ---p 00000000 00:00 0 
+70eaefa000-70eaeff000 r--p 0003b000 fc:00 2924                           /system/lib64/libwilhelm.so
+70eaeff000-70eaf00000 rw-p 00040000 fc:00 2924                           /system/lib64/libwilhelm.so
+70eaf00000-70eaf03000 r--s 00000000 fc:00 242                            /system/fonts/NotoSansElbasan-Regular.otf
+70eaf03000-70eaf21000 r-xp 00000000 fc:00 2415                           /system/lib64/libdrmframework.so
+70eaf21000-70eaf38000 ---p 00000000 00:00 0 
+70eaf38000-70eaf3d000 r--p 0002b000 fc:00 2415                           /system/lib64/libdrmframework.so
+70eaf3d000-70eaf3e000 rw-p 00030000 fc:00 2415                           /system/lib64/libdrmframework.so
+70eaf3e000-70eaf43000 r--s 00000000 fc:00 70                             /system/fonts/NotoSansHebrew-Regular.ttf
+70eaf43000-70eaf44000 ---p 00000000 00:00 0                              [anon:thread signal stack guard]
+70eaf44000-70eaf48000 rw-p 00000000 00:00 0                              [anon:thread signal stack]
+70eaf48000-70eaf49000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70eaf49000-70eaf4c000 rw-p 00000000 00:00 0                              [anon:bionic TLS]
+70eaf4c000-70eaf4d000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70eaf4d000-70eaf4e000 ---p 00000000 00:00 0                              [anon:thread signal stack guard]
+70eaf4e000-70eaf52000 rw-p 00000000 00:00 0                              [anon:thread signal stack]
+70eaf52000-70eaf98000 r-xp 00000000 fc:00 2426                           /system/lib64/libunwindstack.so
+70eaf98000-70eafb6000 ---p 00000000 00:00 0 
+70eafb6000-70eafbd000 r--p 00049000 fc:00 2426                           /system/lib64/libunwindstack.so
+70eafbd000-70eafbe000 rw-p 00050000 fc:00 2426                           /system/lib64/libunwindstack.so
+70eafbe000-70eafc0000 r--s 00000000 fc:00 162                            /system/fonts/NotoSansKayahLi-Regular.ttf
+70eafc0000-70eafe4000 r-xp 00000000 fc:00 2944                           /system/lib64/libvulkan.so
+70eafe4000-70eaffc000 ---p 00000000 00:00 0 
+70eaffc000-70eaffe000 r--p 0002e000 fc:00 2944                           /system/lib64/libvulkan.so
+70eaffe000-70eafff000 rw-p 00030000 fc:00 2944                           /system/lib64/libvulkan.so
+70eafff000-70eb001000 r--s 00000000 fc:00 180                            /system/fonts/NotoSansInscriptionalParthian-Regular.ttf
+70eb001000-70eb01d000 r-xp 00000000 fc:00 2400                           /system/lib64/libbufferhubqueue.so
+70eb01d000-70eb030000 ---p 00000000 00:00 0 
+70eb030000-70eb031000 r--p 0001f000 fc:00 2400                           /system/lib64/libbufferhubqueue.so
+70eb031000-70eb032000 rw-p 00020000 fc:00 2400                           /system/lib64/libbufferhubqueue.so
+70eb032000-70eb036000 r--s 00000000 fc:00 269                            /system/fonts/NotoSansArmenian-Bold.ttf
+70eb036000-70eb037000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70eb037000-70eb03a000 rw-p 00000000 00:00 0                              [anon:bionic TLS]
+70eb03a000-70eb03b000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70eb03b000-70eb03c000 ---p 00000000 00:00 0                              [anon:thread signal stack guard]
+70eb03c000-70eb040000 rw-p 00000000 00:00 0                              [anon:thread signal stack]
+70eb040000-70eb042000 r-xp 00000000 fc:00 2935                           /system/lib64/libhardware.so
+70eb042000-70eb05f000 ---p 00000000 00:00 0 
+70eb05f000-70eb060000 r--p 0000f000 fc:00 2935                           /system/lib64/libhardware.so
+70eb060000-70eb061000 rw-p 00010000 fc:00 2935                           /system/lib64/libhardware.so
+70eb061000-70eb063000 r--s 00000000 fc:00 171                            /system/fonts/NotoSansInscriptionalPahlavi-Regular.ttf
+70eb063000-70eb064000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70eb064000-70eb067000 rw-p 00000000 00:00 0                              [anon:bionic TLS]
+70eb067000-70eb068000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70eb068000-70eb069000 ---p 00000000 00:00 0                              [anon:thread signal stack guard]
+70eb069000-70eb06d000 rw-p 00000000 00:00 0                              [anon:thread signal stack]
+70eb06d000-70eb06e000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70eb06e000-70eb071000 rw-p 00000000 00:00 0                              [anon:bionic TLS]
+70eb071000-70eb072000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70eb072000-70eb073000 ---p 00000000 00:00 0                              [anon:thread signal stack guard]
+70eb073000-70eb077000 rw-p 00000000 00:00 0                              [anon:thread signal stack]
+70eb077000-70eb078000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70eb078000-70eb07b000 rw-p 00000000 00:00 0                              [anon:bionic TLS]
+70eb07b000-70eb07c000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70eb07c000-70eb07d000 ---p 00000000 00:00 0                              [anon:thread signal stack guard]
+70eb07d000-70eb081000 rw-p 00000000 00:00 0                              [anon:thread signal stack]
+70eb081000-70eb082000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70eb082000-70eb085000 rw-p 00000000 00:00 0                              [anon:bionic TLS]
+70eb085000-70eb086000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70eb086000-70eb09d000 r-xp 00000000 fc:00 2604                           /system/lib64/libz.so
+70eb09d000-70eb0b5000 ---p 00000000 00:00 0 
+70eb0b5000-70eb0b6000 r--p 0001f000 fc:00 2604                           /system/lib64/libz.so
+70eb0b6000-70eb0b7000 rw-p 00020000 fc:00 2604                           /system/lib64/libz.so
+70eb0b7000-70eb0bb000 r--s 00000000 fc:00 289                            /system/fonts/NotoSansArmenian-Regular.ttf
+70eb0bb000-70eb0bc000 ---p 00000000 00:00 0                              [anon:thread signal stack guard]
+70eb0bc000-70eb0c0000 rw-p 00000000 00:00 0                              [anon:thread signal stack]
+70eb0c0000-70eb0c1000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70eb0c1000-70eb0c4000 rw-p 00000000 00:00 0                              [anon:bionic TLS]
+70eb0c4000-70eb0c5000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70eb0c5000-70eb0c6000 ---p 00000000 00:00 0                              [anon:thread signal stack guard]
+70eb0c6000-70eb0ca000 rw-p 00000000 00:00 0                              [anon:thread signal stack]
+70eb0ca000-70eb0cb000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70eb0cb000-70eb0ce000 rw-p 00000000 00:00 0                              [anon:bionic TLS]
+70eb0ce000-70eb0cf000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70eb0cf000-70eb0ef000 rw-p 00000000 00:05 10270988                       /dev/ashmem/dalvik-LinearAlloc (deleted)
+70eb0ef000-70eb5bb000 r-xp 00000000 fc:00 2374                           /system/lib64/libpdfium.so
+70eb5bb000-70eb5cf000 ---p 00000000 00:00 0 
+70eb5cf000-70eb5e6000 r--p 004d9000 fc:00 2374                           /system/lib64/libpdfium.so
+70eb5e6000-70eb5ea000 rw-p 004f0000 fc:00 2374                           /system/lib64/libpdfium.so
+70eb5ea000-70eb5f1000 rw-p 00000000 00:00 0                              [anon:.bss]
+70eb5f1000-70eb5f2000 r--s 00000000 fc:00 1094                           /system/usr/hyphen-data/hyph-hi.hyb
+70eb5f2000-70eb5f6000 rw-p 00000000 00:05 10270982                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb5f6000-70eb5fa000 rw-p 00000000 00:05 10270981                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb5fa000-70eb5fe000 rw-p 00000000 00:05 10270980                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb5fe000-70eb602000 rw-p 00000000 00:05 10270979                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb602000-70eb606000 rw-p 00000000 00:05 10270978                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb606000-70eb60a000 rw-p 00000000 00:05 10270977                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb60a000-70eb60e000 rw-p 00000000 00:05 10270976                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb60e000-70eb612000 rw-p 00000000 00:05 10270975                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb612000-70eb616000 rw-p 00000000 00:05 10270974                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb616000-70eb61a000 r-xp 00000000 fc:00 2479                           /system/lib64/libspeexresampler.so
+70eb61a000-70eb635000 ---p 00000000 00:00 0 
+70eb635000-70eb636000 r--p 0000f000 fc:00 2479                           /system/lib64/libspeexresampler.so
+70eb636000-70eb637000 rw-p 00010000 fc:00 2479                           /system/lib64/libspeexresampler.so
+70eb637000-70eb639000 r--s 00000000 fc:00 299                            /system/fonts/NotoSansImperialAramaic-Regular.ttf
+70eb639000-70eb63d000 rw-p 00000000 00:05 10270973                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb63d000-70eb641000 rw-p 00000000 00:05 10270972                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb641000-70eb645000 rw-p 00000000 00:05 10270971                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb645000-70eb649000 rw-p 00000000 00:05 10270970                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb649000-70eb64d000 rw-p 00000000 00:05 10270969                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb64d000-70eb651000 rw-p 00000000 00:05 10270968                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb651000-70eb655000 rw-p 00000000 00:05 10270967                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb655000-70eb659000 rw-p 00000000 00:05 10270966                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb659000-70eb65d000 rw-p 00000000 00:05 10270965                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb65d000-70eb661000 rw-p 00000000 00:05 10270964                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb661000-70eb6c5000 r-xp 00000000 fc:00 2461                           /system/lib64/libhidl-gen-utils.so
+70eb6c5000-70eb6df000 ---p 00000000 00:00 0 
+70eb6df000-70eb6e1000 r--p 0006e000 fc:00 2461                           /system/lib64/libhidl-gen-utils.so
+70eb6e1000-70eb6e2000 rw-p 00070000 fc:00 2461                           /system/lib64/libhidl-gen-utils.so
+70eb6e2000-70eb6e6000 rw-p 00000000 00:05 10270963                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb6e6000-70eb6ea000 rw-p 00000000 00:05 10270962                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb6ea000-70eb6ee000 rw-p 00000000 00:05 10270961                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb6ee000-70eb6f2000 rw-p 00000000 00:05 10270960                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb6f2000-70eb6f6000 rw-p 00000000 00:05 10270959                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb6f6000-70eb6fa000 rw-p 00000000 00:05 10270958                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb6fa000-70eb6fe000 rw-p 00000000 00:05 10270957                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb6fe000-70eb702000 rw-p 00000000 00:05 10270956                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb702000-70eb706000 rw-p 00000000 00:05 10270955                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb706000-70eb70a000 rw-p 00000000 00:05 10270954                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb70a000-70eb70e000 rw-p 00000000 00:05 10270953                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb70e000-70eb712000 rw-p 00000000 00:05 10270952                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb712000-70eb71a000 r-xp 00000000 fc:00 2652                           /system/lib64/libcamera_metadata.so
+70eb71a000-70eb72f000 ---p 00000000 00:00 0 
+70eb72f000-70eb730000 r--p 0000f000 fc:00 2652                           /system/lib64/libcamera_metadata.so
+70eb730000-70eb732000 rw-p 00010000 fc:00 2652                           /system/lib64/libcamera_metadata.so
+70eb732000-70eb734000 r--s 00000000 fc:00 131                            /system/fonts/NotoSansHanunoo-Regular.ttf
+70eb734000-70eb738000 rw-p 00000000 00:05 10270951                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb738000-70eb73c000 rw-p 00000000 00:05 10270950                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb73c000-70eb740000 rw-p 00000000 00:05 10270949                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb740000-70eb744000 rw-p 00000000 00:05 10270948                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb744000-70eb748000 rw-p 00000000 00:05 10270947                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb748000-70eb74c000 rw-p 00000000 00:05 10270946                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb74c000-70eb750000 rw-p 00000000 00:05 10270945                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb750000-70eb754000 rw-p 00000000 00:05 10270944                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb754000-70eb758000 rw-p 00000000 00:05 10270943                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb758000-70eb75c000 rw-p 00000000 00:05 10270942                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb75c000-70eb760000 rw-p 00000000 00:05 10270941                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb760000-70eb764000 rw-p 00000000 00:05 10270940                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb764000-70eb767000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70eb767000-70eb768000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70eb768000-70eb76c000 rw-p 00000000 00:05 10270939                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb76c000-70eb770000 rw-p 00000000 00:05 10270938                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb770000-70eb771000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70eb771000-70eb774000 r--s 00000000 fc:00 231                            /system/fonts/NotoSansDeseret-Regular.ttf
+70eb774000-70eb778000 rw-p 00000000 00:05 10270937                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb778000-70eb77c000 rw-p 00000000 00:05 10270936                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb77c000-70eb780000 rw-p 00000000 00:05 10270935                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb780000-70eb784000 rw-p 00000000 00:05 10270934                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb784000-70eb788000 rw-p 00000000 00:05 10270933                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb788000-70eb78c000 rw-p 00000000 00:05 10270932                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb78c000-70eb790000 rw-p 00000000 00:05 10270931                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb790000-70eb794000 rw-p 00000000 00:05 10270930                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb794000-70eb798000 rw-p 00000000 00:05 10270929                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb798000-70eb79c000 rw-p 00000000 00:05 10270928                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb79c000-70eb7a0000 rw-p 00000000 00:05 10270927                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7a0000-70eb7a1000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70eb7a1000-70eb7a3000 r--s 00000000 fc:00 176                            /system/fonts/NotoSansGothic-Regular.ttf
+70eb7a3000-70eb7a7000 rw-p 00000000 00:05 10270926                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7a7000-70eb7a8000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70eb7a8000-70eb7a9000 r--s 00000000 fc:00 1109                           /system/usr/hyphen-data/hyph-gu.hyb
+70eb7a9000-70eb7ad000 rw-p 00000000 00:05 10270925                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7ad000-70eb7ae000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70eb7ae000-70eb7af000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70eb7af000-70eb7b0000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70eb7b0000-70eb7b2000 r--s 00000000 fc:00 191                            /system/fonts/NotoSansCypriot-Regular.ttf
+70eb7b2000-70eb7b6000 rw-p 00000000 00:05 10270924                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7b6000-70eb7ba000 rw-p 00000000 00:05 10270923                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7ba000-70eb7be000 rw-p 00000000 00:05 10270922                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7be000-70eb7c2000 rw-p 00000000 00:05 10270921                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7c2000-70eb7c6000 rw-p 00000000 00:05 10270920                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7c6000-70eb7ca000 rw-p 00000000 00:05 10270919                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7ca000-70eb7ce000 rw-p 00000000 00:05 10270918                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7ce000-70eb7d2000 rw-p 00000000 00:05 10270917                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7d2000-70eb7d6000 rw-p 00000000 00:05 10270916                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7d6000-70eb7d7000 rw-p 00000000 00:00 0                              [anon:linker_alloc_small_objects]
+70eb7d7000-70eb7db000 rw-p 00000000 00:05 10270915                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7db000-70eb7df000 rw-p 00000000 00:05 10270914                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7df000-70eb7e3000 rw-p 00000000 00:05 10270913                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7e3000-70eb7e7000 rw-p 00000000 00:05 10270912                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7e7000-70eb7e8000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70eb7e8000-70eb7ea000 r--s 00000000 fc:00 174                            /system/fonts/NotoSansCarian-Regular.ttf
+70eb7ea000-70eb7ee000 rw-p 00000000 00:05 10270911                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7ee000-70eb7f2000 rw-p 00000000 00:05 10270910                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7f2000-70eb7f6000 rw-p 00000000 00:05 10270909                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7f6000-70eb7f7000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70eb7f7000-70eb7f8000 r--s 00000000 fc:00 1096                           /system/usr/hyphen-data/hyph-eu.hyb
+70eb7f8000-70eb7fc000 rw-p 00000000 00:05 10270908                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb7fc000-70eb800000 rw-p 00000000 00:05 10270907                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb800000-70eb804000 rw-p 00000000 00:05 10270906                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb804000-70eb808000 rw-p 00000000 00:05 10270905                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb808000-70eb80c000 rw-p 00000000 00:05 10270904                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb80c000-70eb810000 rw-p 00000000 00:05 10270903                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb810000-70eb814000 rw-p 00000000 00:05 10270902                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb814000-70eb815000 rw-p 00000000 00:00 0                              [anon:linker_alloc_vector]
+70eb815000-70eb819000 rw-p 00000000 00:05 10270901                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb819000-70eb81d000 rw-p 00000000 00:05 10270900                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb81d000-70eb81e000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70eb81e000-70eb822000 rw-p 00000000 00:05 10270899                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb822000-70eb826000 rw-p 00000000 00:05 10270898                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb826000-70eb82a000 rw-p 00000000 00:05 10270897                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb82a000-70eb82e000 rw-p 00000000 00:05 10270896                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb82e000-70eb832000 rw-p 00000000 00:05 10270895                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb832000-70eb836000 rw-p 00000000 00:05 10270894                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb836000-70eb837000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70eb837000-70eb83b000 rw-p 00000000 00:05 10270893                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb83b000-70eb83f000 rw-p 00000000 00:05 10270892                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb83f000-70eb843000 rw-p 00000000 00:05 10270891                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb843000-70eb847000 rw-p 00000000 00:05 10270890                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb847000-70eb84b000 rw-p 00000000 00:05 10270889                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb84b000-70eb84f000 rw-p 00000000 00:05 10270888                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb84f000-70eb850000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70eb850000-70eb854000 rw-p 00000000 00:05 10270887                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb854000-70eb858000 rw-p 00000000 00:05 10270886                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb858000-70eb85c000 rw-p 00000000 00:05 10270885                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb85c000-70eb860000 rw-p 00000000 00:05 10270884                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb860000-70eb864000 rw-p 00000000 00:05 10270883                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb864000-70eb868000 rw-p 00000000 00:05 10270882                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb868000-70eb869000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70eb869000-70eb86d000 rw-p 00000000 00:05 10270881                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb86d000-70eb871000 rw-p 00000000 00:05 10270880                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb871000-70eb875000 rw-p 00000000 00:05 10270879                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb875000-70eb879000 rw-p 00000000 00:05 10270878                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb879000-70eb87d000 rw-p 00000000 00:05 10270877                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb87d000-70eb881000 rw-p 00000000 00:05 10270876                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb881000-70eb885000 rw-p 00000000 00:05 10270875                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb885000-70eb889000 rw-p 00000000 00:05 10270874                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb889000-70eb88d000 rw-p 00000000 00:05 10270873                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb88d000-70eb891000 rw-p 00000000 00:05 10270872                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb891000-70eb892000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70eb892000-70eb896000 rw-p 00000000 00:05 10270871                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb896000-70eb89a000 rw-p 00000000 00:05 10270870                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb89a000-70eb89b000 rw-p 00000000 00:00 0                              [anon:linker_alloc_vector]
+70eb89b000-70eb89c000 rw-p 00000000 00:00 0                              [anon:linker_alloc_small_objects]
+70eb89c000-70eb8a0000 rw-p 00000000 00:05 10270869                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8a0000-70eb8a4000 rw-p 00000000 00:05 10270868                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8a4000-70eb8a5000 r--p 00000000 00:00 0                              [anon:atexit handlers]
+70eb8a5000-70eb8a9000 rw-p 00000000 00:05 10270867                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8a9000-70eb8ad000 rw-p 00000000 00:05 10270866                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8ad000-70eb8b1000 rw-p 00000000 00:05 10270865                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8b1000-70eb8b5000 rw-p 00000000 00:05 10270864                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8b5000-70eb8b9000 rw-p 00000000 00:05 10270863                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8b9000-70eb8bd000 rw-p 00000000 00:05 10270862                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8bd000-70eb8be000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70eb8be000-70eb8c1000 r--s 00000000 fc:00 168                            /system/fonts/NotoSansAvestan-Regular.ttf
+70eb8c1000-70eb8c5000 rw-p 00000000 00:05 10270861                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8c5000-70eb8c9000 rw-p 00000000 00:05 10270860                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8c9000-70eb8cd000 rw-p 00000000 00:05 10270859                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8cd000-70eb8d1000 rw-p 00000000 00:05 10270858                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8d1000-70eb8d5000 rw-p 00000000 00:05 10270857                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8d5000-70eb8d7000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70eb8d7000-70eb8db000 rw-p 00000000 00:05 10270856                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8db000-70eb8df000 rw-p 00000000 00:05 10270855                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8df000-70eb8e3000 rw-p 00000000 00:05 10270854                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8e3000-70eb8e7000 rw-p 00000000 00:05 10270853                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8e7000-70eb8eb000 rw-p 00000000 00:05 10270852                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8eb000-70eb8ec000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70eb8ec000-70eb8ed000 r--s 00000000 fc:00 1099                           /system/usr/hyphen-data/hyph-bn.hyb
+70eb8ed000-70eb8f1000 rw-p 00000000 00:05 10270851                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8f1000-70eb8f5000 rw-p 00000000 00:05 10270850                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8f5000-70eb8f9000 rw-p 00000000 00:05 10270849                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8f9000-70eb8fd000 rw-p 00000000 00:05 10270848                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb8fd000-70eb901000 rw-p 00000000 00:05 10270847                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb901000-70eb905000 rw-p 00000000 00:05 10270846                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb905000-70eb909000 rw-p 00000000 00:05 10270845                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb909000-70eb90d000 rw-p 00000000 00:05 10270844                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb90d000-70eb911000 rw-p 00000000 00:05 10270843                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb911000-70eb915000 rw-p 00000000 00:05 10270842                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb915000-70eb916000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70eb916000-70eb917000 r--s 00000000 fc:00 1114                           /system/usr/hyphen-data/hyph-bg.hyb
+70eb917000-70eb91b000 rw-p 00000000 00:05 10270841                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb91b000-70eb91c000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70eb91c000-70eb91d000 r--s 00000000 fc:00 1133                           /system/usr/hyphen-data/hyph-as.hyb
+70eb91d000-70eb921000 rw-p 00000000 00:05 10270840                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb921000-70eb925000 rw-p 00000000 00:05 10270839                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb925000-70eb926000 rw-p 00000000 00:00 0                              [anon:linker_alloc_small_objects]
+70eb926000-70eb927000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70eb927000-70eb929000 r--s 00000000 fc:00 203                            /system/fonts/NotoSansBuhid-Regular.ttf
+70eb929000-70eb92d000 rw-p 00000000 00:05 10270838                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb92d000-70eb931000 rw-p 00000000 00:05 10270837                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb931000-70eb935000 rw-p 00000000 00:05 10270836                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb935000-70eb939000 rw-p 00000000 00:05 10270835                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb939000-70eb93d000 rw-p 00000000 00:05 10270834                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb93d000-70eb941000 rw-p 00000000 00:05 10270833                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb941000-70eb945000 rw-p 00000000 00:05 10270832                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb945000-70eb949000 rw-p 00000000 00:05 10270831                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb949000-70eb94d000 rw-p 00000000 00:05 10270830                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb94d000-70eb951000 rw-p 00000000 00:05 10270829                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb951000-70eb991000 rw-p 00000000 00:05 10270722                       /dev/ashmem/dalvik-mark stack (deleted)
+70eb991000-70eb992000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70eb992000-70eb996000 rw-p 00000000 00:05 10270828                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb996000-70eb99a000 rw-p 00000000 00:05 10270827                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb99a000-70eb99e000 rw-p 00000000 00:05 10270826                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb99e000-70eb9a2000 rw-p 00000000 00:05 10270825                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9a2000-70eb9a4000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70eb9a4000-70eb9a8000 rw-p 00000000 00:05 10270824                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9a8000-70eb9ac000 rw-p 00000000 00:05 10270823                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9ac000-70eb9b0000 rw-p 00000000 00:05 10270822                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9b0000-70eb9b1000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70eb9b1000-70eb9b2000 r--s 00021000 fc:01 1180                           /vendor/overlay/framework-res__auto_generated_rro.apk
+70eb9b2000-70eb9b6000 rw-p 00000000 00:05 10270821                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9b6000-70eb9ba000 rw-p 00000000 00:05 10270820                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9ba000-70eb9be000 rw-p 00000000 00:05 10270819                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9be000-70eb9c2000 rw-p 00000000 00:05 10270818                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9c2000-70eb9c6000 rw-p 00000000 00:05 10270817                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9c6000-70eb9ca000 rw-p 00000000 00:05 10270816                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9ca000-70eb9ce000 rw-p 00000000 00:05 10270815                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9ce000-70eb9cf000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70eb9cf000-70eb9d1000 r--s 00000000 fc:00 213                            /system/fonts/NotoSansBuginese-Regular.ttf
+70eb9d1000-70eb9d5000 rw-p 00000000 00:05 10270814                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9d5000-70eb9d9000 rw-p 00000000 00:05 10270813                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9d9000-70eb9dd000 rw-p 00000000 00:05 10270812                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9dd000-70eb9e1000 rw-p 00000000 00:05 10270811                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9e1000-70eb9e5000 rw-p 00000000 00:05 10270810                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9e5000-70eb9e9000 rw-p 00000000 00:05 10270809                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9e9000-70eb9ed000 rw-p 00000000 00:05 10270808                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9ed000-70eb9f1000 rw-p 00000000 00:05 10270807                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9f1000-70eb9f5000 rw-p 00000000 00:05 10270806                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9f5000-70eb9f6000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70eb9f6000-70eb9f8000 rw-p 00000000 00:05 10271002                       /dev/ashmem/dalvik-indirect ref table (deleted)
+70eb9f8000-70eb9fc000 rw-p 00000000 00:05 10270805                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eb9fc000-70eb9fd000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70eb9fd000-70eb9ff000 rw-p 00000000 00:05 10270999                       /dev/ashmem/dalvik-indirect ref table (deleted)
+70eb9ff000-70eba00000 r--s 00000000 fc:00 983                            /system/framework/com.google.vr.platform.jar
+70eba00000-70eba04000 rw-p 00000000 00:05 10270804                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba04000-70eba08000 rw-p 00000000 00:05 10270803                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba08000-70eba0c000 rw-p 00000000 00:05 10270802                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba0c000-70eba10000 rw-p 00000000 00:05 10270801                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba10000-70eba14000 rw-p 00000000 00:05 10270800                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba14000-70eba18000 rw-p 00000000 00:05 10270799                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba18000-70eba1c000 rw-p 00000000 00:05 10270798                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba1c000-70eba20000 rw-p 00000000 00:05 10270797                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba20000-70eba24000 rw-p 00000000 00:05 10270796                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba24000-70eba28000 rw-p 00000000 00:05 10270795                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba28000-70eba2c000 rw-p 00000000 00:05 10270794                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba2c000-70eba2d000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70eba2d000-70eba2e000 r--s 00000000 fc:00 881                            /system/framework/android.test.base.jar
+70eba2e000-70eba2f000 r--s 00000000 fc:00 707                            /system/framework/framework-oahl-backward-compatibility.jar
+70eba2f000-70eba30000 r--s 00000000 fc:00 705                            /system/framework/android.hidl.manager-V1.0-java.jar
+70eba30000-70eba34000 rw-p 00000000 00:05 10270793                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba34000-70eba38000 rw-p 00000000 00:05 10270792                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba38000-70eba3c000 rw-p 00000000 00:05 10270791                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba3c000-70eba40000 rw-p 00000000 00:05 10270790                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba40000-70eba44000 rw-p 00000000 00:05 10270789                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba44000-70eba48000 rw-p 00000000 00:05 10270788                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba48000-70eba4c000 rw-p 00000000 00:05 10270787                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba4c000-70eba50000 rw-p 00000000 00:05 10270786                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba50000-70eba52000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70eba52000-70eba53000 r--s 00000000 fc:00 971                            /system/framework/android.hidl.base-V1.0-java.jar
+70eba53000-70eba57000 rw-p 00000000 00:05 10270785                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba57000-70eba5b000 rw-p 00000000 00:05 10270784                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba5b000-70eba5f000 rw-p 00000000 00:05 10270783                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba5f000-70eba63000 rw-p 00000000 00:05 10270782                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba63000-70eba64000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70eba64000-70eba65000 r--s 00000000 fc:00 889                            /system/framework/ims-common.jar
+70eba65000-70eba69000 rw-p 00000000 00:05 10270781                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba69000-70eba6d000 rw-p 00000000 00:05 10270780                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba6d000-70eba71000 rw-p 00000000 00:05 10270779                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba71000-70eba75000 rw-p 00000000 00:05 10270778                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70eba75000-70eba95000 rw-p 00000000 00:05 10267647                       /dev/ashmem/dalvik-large marked objects (deleted)
+70eba95000-70ebab5000 rw-p 00000000 00:05 10267646                       /dev/ashmem/dalvik-large live objects (deleted)
+70ebab5000-70ebab6000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70ebab6000-70ebab7000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70ebab7000-70ebabb000 rw-p 00000000 00:05 10270777                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebabb000-70ebadb000 r--s 00000000 00:10 16603                          /dev/__properties__/u:object_r:exported_fingerprint_prop:s0
+70ebadb000-70ebadc000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70ebadc000-70ebadd000 r--s 00000000 fc:00 878                            /system/framework/voip-common.jar
+70ebadd000-70ebadf000 rw-p 00000000 00:05 10270995                       /dev/ashmem/dalvik-indirect ref table (deleted)
+70ebadf000-70ebae3000 rw-p 00000000 00:05 10270776                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebae3000-70ebae7000 rw-p 00000000 00:05 10270775                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebae7000-70ebaeb000 rw-p 00000000 00:05 10270774                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebaeb000-70ebaef000 rw-p 00000000 00:05 10270773                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebaef000-70ebb0f000 r--s 00000000 00:10 16582                          /dev/__properties__/u:object_r:debug_prop:s0
+70ebb0f000-70ebb10000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70ebb10000-70ebb11000 r--s 00000000 fc:00 703                            /system/framework/telephony-common.jar
+70ebb11000-70ebb13000 rw-p 00000000 00:05 10270994                       /dev/ashmem/dalvik-indirect ref table (deleted)
+70ebb13000-70ebb17000 rw-p 00000000 00:05 10270772                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebb17000-70ebb19000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70ebb19000-70ebb1d000 rw-p 00000000 00:05 10270771                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebb1d000-70ebb3d000 r--s 00000000 00:10 16600                          /dev/__properties__/u:object_r:exported_default_prop:s0
+70ebb3d000-70ebb5d000 r--s 00000000 00:10 16650                          /dev/__properties__/u:object_r:system_prop:s0
+70ebb5d000-70ebb7d000 r--s 00000000 00:10 16610                          /dev/__properties__/u:object_r:exported_vold_prop:s0
+70ebb7d000-70ebb9d000 r--s 00000000 00:10 16598                          /dev/__properties__/u:object_r:exported_config_prop:s0
+70ebb9d000-70ebb9e000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70ebb9e000-70ebba2000 rw-p 00000000 00:05 10270770                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebba2000-70ebba6000 rw-p 00000000 00:05 10270769                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebba6000-70ebba7000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70ebba7000-70ebba8000 r--s 00000000 fc:00 1004                           /system/framework/framework.jar
+70ebba8000-70ebbac000 rw-p 00000000 00:05 10270768                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebbac000-70ebbb0000 rw-p 00000000 00:05 10270767                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebbb0000-70ebbb4000 rw-p 00000000 00:05 10270766                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebbb4000-70ebbb8000 rw-p 00000000 00:05 10270765                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebbb8000-70ebbbc000 rw-p 00000000 00:05 10270764                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebbbc000-70ebbc0000 rw-p 00000000 00:05 10270763                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebbc0000-70ebbc4000 rw-p 00000000 00:05 10270762                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebbc4000-70ebbe4000 r--s 00000000 00:10 16581                          /dev/__properties__/u:object_r:dalvik_prop:s0
+70ebbe4000-70ebbe5000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70ebbe5000-70ebbe6000 r--s 00004000 fc:00 877                            /system/framework/apache-xml.jar
+70ebbe6000-70ebbe8000 rw-p 00000000 00:05 10270993                       /dev/ashmem/dalvik-indirect ref table (deleted)
+70ebbe8000-70ebbec000 rw-p 00000000 00:05 10270761                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebbec000-70ebbf0000 rw-p 00000000 00:05 10270760                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebbf0000-70ebbf4000 rw-p 00000000 00:05 10270759                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebbf4000-70ebbf8000 rw-p 00000000 00:05 10270758                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebbf8000-70ebbf9000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70ebbf9000-70ebbfa000 r--s 00000000 fc:00 968                            /system/framework/bouncycastle.jar
+70ebbfa000-70ebbfc000 rw-p 00000000 00:05 10270992                       /dev/ashmem/dalvik-indirect ref table (deleted)
+70ebbfc000-70ebc00000 rw-p 00000000 00:05 10270757                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc00000-70ebc04000 rw-p 00000000 00:05 10270756                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc04000-70ebc08000 rw-p 00000000 00:05 10270755                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc08000-70ebc0c000 rw-p 00000000 00:05 10270754                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc0c000-70ebc10000 rw-p 00000000 00:05 10270753                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc10000-70ebc14000 rw-p 00000000 00:05 10270752                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc14000-70ebc15000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70ebc15000-70ebc16000 r--s 00000000 fc:00 960                            /system/framework/okhttp.jar
+70ebc16000-70ebc1a000 rw-p 00000000 00:05 10270751                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc1a000-70ebc1e000 rw-p 00000000 00:05 10270750                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc1e000-70ebc3e000 r--s 00000000 00:10 16584                          /dev/__properties__/u:object_r:default_prop:s0
+70ebc3e000-70ebc3f000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70ebc3f000-70ebc40000 r--s 00000000 fc:00 974                            /system/framework/conscrypt.jar
+70ebc40000-70ebc42000 rw-p 00000000 00:05 10269719                       /dev/ashmem/dalvik-indirect ref table (deleted)
+70ebc42000-70ebc46000 rw-p 00000000 00:05 10270749                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc46000-70ebc4a000 rw-p 00000000 00:05 10270748                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc4a000-70ebc4e000 rw-p 00000000 00:05 10270747                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc4e000-70ebc4f000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70ebc4f000-70ebc51000 rw-p 00000000 00:05 10269718                       /dev/ashmem/dalvik-indirect ref table (deleted)
+70ebc51000-70ebc55000 rw-p 00000000 00:05 10270746                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc55000-70ebc59000 rw-p 00000000 00:05 10270745                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc59000-70ebc5d000 rw-p 00000000 00:05 10270744                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc5d000-70ebc7d000 r--s 00000000 00:10 16599                          /dev/__properties__/u:object_r:exported_dalvik_prop:s0
+70ebc7d000-70ebc7e000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70ebc7e000-70ebc7f000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70ebc7f000-70ebc80000 r--s 00004000 fc:00 963                            /system/framework/core-libart.jar
+70ebc80000-70ebc81000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70ebc81000-70ebc85000 rw-p 00000000 00:05 10270743                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc85000-70ebc89000 rw-p 00000000 00:05 10270742                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc89000-70ebc8a000 rw-p 00000000 00:00 0                              [anon:linker_alloc_small_objects]
+70ebc8a000-70ebc8c000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70ebc8c000-70ebc8d000 r--s 0001e000 fc:00 699                            /system/framework/core-oj.jar
+70ebc8d000-70ebc91000 rw-p 00000000 00:05 10270741                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc91000-70ebc95000 rw-p 00000000 00:05 10270740                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc95000-70ebc99000 rw-p 00000000 00:05 10270739                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebc99000-70ebc9b000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70ebc9b000-70ebc9c000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70ebc9c000-70ebca0000 rw-p 00000000 00:05 10270738                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebca0000-70ebca4000 rw-p 00000000 00:05 10270737                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebca4000-70ebca8000 rw-p 00000000 00:05 10270736                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebca8000-70ebcac000 rw-p 00000000 00:05 10270735                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebcac000-70ebcb0000 rw-p 00000000 00:05 10270734                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebcb0000-70ebcd0000 r--s 00000000 00:10 16592                          /dev/__properties__/u:object_r:exported2_system_prop:s0
+70ebcd0000-70ebcd1000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70ebcd1000-70ebcd5000 rw-p 00000000 00:05 10270733                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebcd5000-70ebcd9000 rw-p 00000000 00:05 10270732                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebcd9000-70ebcdd000 rw-p 00000000 00:05 10270731                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebcdd000-70ebce1000 rw-p 00000000 00:05 10270730                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebce1000-70ebce5000 rw-p 00000000 00:05 10270729                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebce5000-70ebce9000 rw-p 00000000 00:05 10270728                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebce9000-70ebcea000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70ebcea000-70ebcec000 rw-p 00000000 00:05 10270987                       /dev/ashmem/dalvik-indirect ref table (deleted)
+70ebcec000-70ebcf9000 r--p 00646000 103:1d 639532                        /data/dalvik-cache/arm64/system@framework@boot-framework.art
+70ebcf9000-70ebd19000 r--s 00000000 00:10 16620                          /dev/__properties__/u:object_r:log_tag_prop:s0
+70ebd19000-70ebd39000 r--s 00000000 00:10 16621                          /dev/__properties__/u:object_r:logd_prop:s0
+70ebd39000-70ebd3a000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70ebd3a000-70ebd3b000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70ebd3b000-70ebd3f000 rw-p 00000000 00:05 10270727                       /dev/ashmem/dalvik-thread local mark stack (deleted)
+70ebd3f000-70ebd40000 r--p 00002000 103:1d 639556                        /data/dalvik-cache/arm64/system@framework@boot-com.google.vr.platform.art
+70ebd40000-70ebd41000 r--p 00005000 103:1d 639553                        /data/dalvik-cache/arm64/system@framework@boot-android.test.base.art
+70ebd41000-70ebd42000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70ebd42000-70ebd43000 r--p 00001000 103:1d 639550                        /data/dalvik-cache/arm64/system@framework@boot-framework-oahl-backward-compatibility.art
+70ebd43000-70ebd44000 r--p 00005000 103:1d 639547                        /data/dalvik-cache/arm64/system@framework@boot-android.hidl.manager-V1.0-java.art
+70ebd44000-70ebd45000 r--p 00003000 103:1d 639544                        /data/dalvik-cache/arm64/system@framework@boot-android.hidl.base-V1.0-java.art
+70ebd45000-70ebd46000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70ebd46000-70ebd47000 r--p 0000f000 103:1d 639541                        /data/dalvik-cache/arm64/system@framework@boot-ims-common.art
+70ebd47000-70ebd48000 r--p 0000d000 103:1d 639538                        /data/dalvik-cache/arm64/system@framework@boot-voip-common.art
+70ebd48000-70ebd4a000 r--p 0005e000 103:1d 639535                        /data/dalvik-cache/arm64/system@framework@boot-telephony-common.art
+70ebd4a000-70ebd4b000 r--p 00040000 103:1d 639529                        /data/dalvik-cache/arm64/system@framework@boot-ext.art
+70ebd4b000-70ebd4c000 r--p 0004a000 103:1d 639526                        /data/dalvik-cache/arm64/system@framework@boot-apache-xml.art
+70ebd4c000-70ebd4d000 r--p 00046000 103:1d 639523                        /data/dalvik-cache/arm64/system@framework@boot-bouncycastle.art
+70ebd4d000-70ebd4e000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70ebd4e000-70ebd53000 r--p 00225000 103:1d 639511                        /data/dalvik-cache/arm64/system@framework@boot.art
+70ebd53000-70ebd5a000 rw-p 00000000 fc:00 583                            /system/etc/event-log-tags
+70ebd5a000-70ebd5b000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70ebd5b000-70ebd5c000 r--p 0002e000 103:1d 639520                        /data/dalvik-cache/arm64/system@framework@boot-okhttp.art
+70ebd5c000-70ebd5d000 r--p 00035000 103:1d 639517                        /data/dalvik-cache/arm64/system@framework@boot-conscrypt.art
+70ebd5d000-70ebd5f000 r--p 000d0000 103:1d 639514                        /data/dalvik-cache/arm64/system@framework@boot-core-libart.art
+70ebd5f000-70ebd62000 r--p 00000000 00:00 0                              [anon:atexit handlers]
+70ebd62000-70ebd63000 rw-p 00000000 00:00 0 
+70ebd63000-70ebd83000 r--s 00000000 00:10 16590                          /dev/__properties__/u:object_r:exported2_default_prop:s0
+70ebd83000-70ebd84000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70ebd84000-70ebd89000 rw-p 00000000 00:00 0 
+70ebd89000-70ebda9000 r--s 00000000 00:10 16669                          /dev/__properties__/properties_serial
+70ebda9000-70ebdb3000 r--s 00000000 00:10 16560                          /dev/__properties__/property_info
+70ebdb3000-70ebdb4000 rw-p 00000000 00:00 0                              [anon:linker_alloc_vector]
+70ebdb4000-70ebdb5000 rw-p 00000000 00:00 0                              [anon:linker_alloc_small_objects]
+70ebdb5000-70ebdb7000 rw-p 00000000 00:00 0                              [anon:System property context nodes]
+70ebdb7000-70ebdb8000 rw-p 00000000 00:00 0                              [anon:linker_alloc_vector]
+70ebdb8000-70ebdba000 rw-p 00000000 00:00 0                              [anon:linker_alloc_small_objects]
+70ebdba000-70ebdbb000 rw-p 00000000 00:00 0                              [anon:linker_alloc]
+70ebdbb000-70ebdbd000 rw-p 00000000 00:00 0                              [anon:linker_alloc_small_objects]
+70ebdbd000-70ebdbe000 r--p 00000000 00:00 0                              [anon:atexit handlers]
+70ebdbe000-70ebdbf000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70ebdbf000-70ebdc0000 rw-p 00000000 00:00 0                              [anon:linker_alloc_small_objects]
+70ebdc0000-70ebdc1000 rw-p 00000000 00:00 0                              [anon:linker_alloc_vector]
+70ebdc1000-70ebdc2000 rw-p 00000000 00:00 0                              [anon:linker_alloc_small_objects]
+70ebdc2000-70ebdc3000 rw-p 00000000 00:00 0                              [anon:linker_alloc_vector]
+70ebdc3000-70ebdc5000 rw-p 00000000 00:00 0                              [anon:linker_alloc_small_objects]
+70ebdc5000-70ebde5000 r--s 00000000 00:10 16600                          /dev/__properties__/u:object_r:exported_default_prop:s0
+70ebde5000-70ebde6000 rw-p 00000000 00:00 0                              [anon:linker_alloc_small_objects]
+70ebde6000-70ebde8000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70ebde8000-70ebe08000 r--s 00000000 00:10 16582                          /dev/__properties__/u:object_r:debug_prop:s0
+70ebe08000-70ebe09000 ---p 00000000 00:00 0 
+70ebe09000-70ebe0a000 rw-p 00000000 00:00 0 
+70ebe0a000-70ebe0b000 ---p 00000000 00:00 0 
+70ebe0b000-70ebe2b000 r--s 00000000 00:10 16669                          /dev/__properties__/properties_serial
+70ebe2b000-70ebe2d000 rw-p 00000000 00:00 0                              [anon:System property context nodes]
+70ebe2d000-70ebf55000 r-xp 00000000 fc:00 3184                           /system/bin/linker64
+70ebf55000-70ebf5f000 r--s 00000000 00:10 16560                          /dev/__properties__/property_info
+70ebf5f000-70ebf60000 r--p 00000000 00:00 0                              [anon:linker_alloc]
+70ebf60000-70ebf61000 rw-p 00000000 00:00 0                              [anon:linker_alloc_vector]
+70ebf61000-70ebf62000 rw-p 00000000 00:00 0                              [anon:linker_alloc_small_objects]
+70ebf62000-70ebf63000 rw-p 00000000 00:00 0                              [anon:arc4random data]
+70ebf63000-70ebf64000 rw-p 00000000 00:00 0                              [anon:linker_alloc_small_objects]
+70ebf64000-70ebf65000 r--p 00000000 00:00 0                              [anon:atexit handlers]
+70ebf65000-70ebf66000 ---p 00000000 00:00 0                              [anon:thread signal stack guard]
+70ebf66000-70ebf6a000 rw-p 00000000 00:00 0                              [anon:thread signal stack]
+70ebf6a000-70ebf6b000 rw-p 00000000 00:00 0                              [anon:arc4random data]
+70ebf6b000-70ebf6c000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70ebf6c000-70ebf6f000 rw-p 00000000 00:00 0                              [anon:bionic TLS]
+70ebf6f000-70ebf70000 ---p 00000000 00:00 0                              [anon:bionic TLS guard]
+70ebf70000-70ebf71000 r--p 00000000 00:00 0                              [vvar]
+70ebf71000-70ebf72000 r-xp 00000000 00:00 0                              [vdso]
+70ebf72000-70ebf7d000 r--p 00135000 fc:00 3184                           /system/bin/linker64
+70ebf7d000-70ebf7e000 rw-p 00140000 fc:00 3184                           /system/bin/linker64
+70ebf7e000-70ebf81000 rw-p 00000000 00:00 0 
+70ebf81000-70ebf82000 r--p 00000000 00:00 0 
+70ebf82000-70ebf89000 rw-p 00000000 00:00 0 
+7fc7df1000-7fc7df2000 ---p 00000000 00:00 0 
+7fc7df2000-7fc85f1000 rw-p 00000000 00:00 0                              [stack]
diff --git a/libsparse/include/sparse/sparse.h b/libsparse/include/sparse/sparse.h
index 356f65f..1b91ead 100644
--- a/libsparse/include/sparse/sparse.h
+++ b/libsparse/include/sparse/sparse.h
@@ -18,6 +18,7 @@
 #define _LIBSPARSE_SPARSE_H_
 
 #include <stdbool.h>
+#include <stddef.h>
 #include <stdint.h>
 
 #ifdef	__cplusplus
@@ -26,6 +27,11 @@
 
 struct sparse_file;
 
+// The callbacks in sparse_file_callback() and sparse_file_foreach_chunk() take
+// size_t as the length type (was `int` in past). This allows clients to keep
+// their codes compatibile with both versions as needed.
+#define	SPARSE_CALLBACK_USES_SIZE_T
+
 /**
  * sparse_file_new - create a new sparse file cookie
  *
@@ -201,7 +207,7 @@
  * Returns 0 on success, negative errno on error.
  */
 int sparse_file_callback(struct sparse_file *s, bool sparse, bool crc,
-		int (*write)(void *priv, const void *data, int len), void *priv);
+		int (*write)(void *priv, const void *data, size_t len), void *priv);
 
 /**
  * sparse_file_foreach_chunk - call a callback for data blocks in sparse file
@@ -218,7 +224,7 @@
  * Returns 0 on success, negative errno on error.
  */
 int sparse_file_foreach_chunk(struct sparse_file *s, bool sparse, bool crc,
-	int (*write)(void *priv, const void *data, int len, unsigned int block,
+	int (*write)(void *priv, const void *data, size_t len, unsigned int block,
 		     unsigned int nr_blocks),
 	void *priv);
 /**
diff --git a/libsparse/output_file.c b/libsparse/output_file.c
index 51e60ef..002ad27 100644
--- a/libsparse/output_file.c
+++ b/libsparse/output_file.c
@@ -109,7 +109,7 @@
 struct output_file_callback {
 	struct output_file out;
 	void *priv;
-	int (*write)(void *priv, const void *buf, int len);
+	int (*write)(void *priv, const void *buf, size_t len);
 };
 
 #define to_output_file_callback(_o) \
@@ -634,7 +634,8 @@
 	return &outn->out;
 }
 
-struct output_file *output_file_open_callback(int (*write)(void *, const void *, int),
+struct output_file *output_file_open_callback(
+		int (*write)(void *, const void *, size_t),
 		void *priv, unsigned int block_size, int64_t len,
 		int gz __unused, int sparse, int chunks, int crc)
 {
diff --git a/libsparse/output_file.h b/libsparse/output_file.h
index b67e94e..690f610 100644
--- a/libsparse/output_file.h
+++ b/libsparse/output_file.h
@@ -27,7 +27,8 @@
 
 struct output_file *output_file_open_fd(int fd, unsigned int block_size, int64_t len,
 		int gz, int sparse, int chunks, int crc);
-struct output_file *output_file_open_callback(int (*write)(void *, const void *, int),
+struct output_file *output_file_open_callback(
+		int (*write)(void *, const void *, size_t),
 		void *priv, unsigned int block_size, int64_t len, int gz, int sparse,
 		int chunks, int crc);
 int write_data_chunk(struct output_file *out, unsigned int len, void *data);
diff --git a/libsparse/sparse.c b/libsparse/sparse.c
index b175860..466435f 100644
--- a/libsparse/sparse.c
+++ b/libsparse/sparse.c
@@ -179,7 +179,7 @@
 }
 
 int sparse_file_callback(struct sparse_file *s, bool sparse, bool crc,
-		int (*write)(void *priv, const void *data, int len), void *priv)
+		int (*write)(void *priv, const void *data, size_t len), void *priv)
 {
 	int ret;
 	int chunks;
@@ -203,11 +203,11 @@
 	void		*priv;
 	unsigned int	block;
 	unsigned int	nr_blocks;
-	int (*write)(void *priv, const void *data, int len, unsigned int block,
-		     unsigned int nr_blocks);
+	int (*write)(void *priv, const void *data, size_t len,
+		     unsigned int block, unsigned int nr_blocks);
 };
 
-static int foreach_chunk_write(void *priv, const void *data, int len)
+static int foreach_chunk_write(void *priv, const void *data, size_t len)
 {
 	struct chunk_data *chk = priv;
 
@@ -215,7 +215,7 @@
 }
 
 int sparse_file_foreach_chunk(struct sparse_file *s, bool sparse, bool crc,
-	int (*write)(void *priv, const void *data, int len, unsigned int block,
+	int (*write)(void *priv, const void *data, size_t len, unsigned int block,
 		     unsigned int nr_blocks),
 	void *priv)
 {
@@ -250,7 +250,7 @@
 	return ret;
 }
 
-static int out_counter_write(void *priv, const void *data __unused, int len)
+static int out_counter_write(void *priv, const void *data __unused, size_t len)
 {
 	int64_t *count = priv;
 	*count += len;
diff --git a/libsync/include/ndk/sync.h b/libsync/include/ndk/sync.h
index 3c55783..a786d3e 100644
--- a/libsync/include/ndk/sync.h
+++ b/libsync/include/ndk/sync.h
@@ -14,6 +14,15 @@
  *  limitations under the License.
  */
 
+/**
+ * @addtogroup Sync
+ * @{
+ */
+
+/**
+ * @file sync.h
+ */
+
 #ifndef ANDROID_SYNC_H
 #define ANDROID_SYNC_H
 
@@ -86,3 +95,5 @@
 __END_DECLS
 
 #endif /* ANDROID_SYNC_H */
+
+/** @} */
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 7b8111c..82f2e73 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -47,6 +47,8 @@
 
     srcs: [
         "ArmExidx.cpp",
+        "DexFile.cpp",
+        "DexFiles.cpp",
         "DwarfCfa.cpp",
         "DwarfEhFrameWithHdr.cpp",
         "DwarfMemory.cpp",
@@ -85,11 +87,13 @@
         },
         vendor: {
             cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
-            exclude_static_libs: ["libunwindstack_dex"],
+            exclude_srcs: [
+                "DexFile.cpp",
+                "DexFiles.cpp",
+            ],
             exclude_shared_libs: ["libdexfile"],
         },
     },
-    whole_static_libs: ["libunwindstack_dex"],
 
     arch: {
         x86: {
@@ -106,6 +110,10 @@
         },
     },
 
+    static_libs: [
+        "libprocinfo",
+    ],
+
     shared_libs: [
         "libbase",
         "libdexfile",
@@ -114,79 +122,9 @@
     ],
 }
 
-// Isolate the dex file processing into a separate library. Currently,
-// it is necessary to add art include directories directly, which also
-// adds the art elf.h file in the include path, overriding the system one.
-// Work to isolate libdexfile is b/72216369.
-cc_library_static {
-    name: "libunwindstack_dex",
-    vendor_available: false,
-    defaults: ["libunwindstack_flags"],
-
-    cflags: [
-        "-Wexit-time-destructors",
-    ],
-
-    srcs: [
-        "DexFile.cpp",
-        "DexFiles.cpp",
-    ],
-    target: {
-        // Always disable optimizations for host to make it easier to debug.
-        host: {
-            cflags: [
-                "-O0",
-                "-g",
-            ],
-        },
-    },
-
-    shared_libs: [
-        "libbase",
-        "libdexfile",
-    ],
-    local_include_dirs: ["include"],
-    allow_undefined_symbols: true,
-
-    // libdexfile will eventually properly export headers, for now include
-    // these directly.
-    include_dirs: [
-        "art/runtime",
-    ],
-}
-
 //-------------------------------------------------------------------------
 // Unit Tests
 //-------------------------------------------------------------------------
-cc_test_library {
-    name: "libunwindstack_dex_test",
-    vendor_available: false,
-    defaults: ["libunwindstack_flags"],
-
-    shared: {
-        enabled: false,
-    },
-
-    srcs: [
-        "tests/DexFileTest.cpp",
-        "tests/DexFilesTest.cpp",
-    ],
-    local_include_dirs: ["include"],
-    allow_undefined_symbols: true,
-
-    shared_libs: [
-        "libbase",
-        "libunwindstack",
-        "libdexfile",
-    ],
-
-    // libdexfile will eventually properly export headers, for now include
-    // these directly.
-    include_dirs: [
-        "art/runtime",
-    ],
-}
-
 cc_test {
     name: "libunwindstack_test",
     defaults: ["libunwindstack_flags"],
@@ -194,6 +132,8 @@
     srcs: [
         "tests/ArmExidxDecodeTest.cpp",
         "tests/ArmExidxExtractTest.cpp",
+        "tests/DexFileTest.cpp",
+        "tests/DexFilesTest.cpp",
         "tests/DwarfCfaLogTest.cpp",
         "tests/DwarfCfaTest.cpp",
         "tests/DwarfDebugFrameTest.cpp",
@@ -243,14 +183,14 @@
         "liblog",
         "liblzma",
         "libunwindstack",
+        "libdexfile",
     ],
 
     static_libs: [
         "libgmock",
     ],
 
-    whole_static_libs: ["libunwindstack_dex_test"],
-
+    test_suites: ["device-tests"],
     data: [
         "tests/files/elf32.xz",
         "tests/files/elf64.xz",
@@ -260,7 +200,9 @@
         "tests/files/offline/eh_frame_hdr_begin_x86_64/*",
         "tests/files/offline/jit_debug_arm/*",
         "tests/files/offline/jit_debug_x86/*",
+        "tests/files/offline/jit_map_arm/*",
         "tests/files/offline/gnu_debugdata_arm/*",
+        "tests/files/offline/offset_arm/*",
         "tests/files/offline/straddle_arm/*",
         "tests/files/offline/straddle_arm64/*",
     ],
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 02f8a9a..3762107 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -160,14 +160,14 @@
 }
 
 // The relative pc is always relative to the start of the map from which it comes.
-bool Elf::Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, uint64_t elf_offset, Regs* regs,
-               Memory* process_memory, bool* finished) {
+bool Elf::Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, Regs* regs, Memory* process_memory,
+               bool* finished) {
   if (!valid_) {
     return false;
   }
 
   // The relative pc expectd by StepIfSignalHandler is relative to the start of the elf.
-  if (regs->StepIfSignalHandler(rel_pc + elf_offset, this, process_memory)) {
+  if (regs->StepIfSignalHandler(rel_pc, this, process_memory)) {
     *finished = false;
     return true;
   }
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 10afe33..4c05a1b 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -87,8 +87,8 @@
 
   ISzAlloc alloc;
   CXzUnpacker state;
-  alloc.Alloc = [](void*, size_t size) { return malloc(size); };
-  alloc.Free = [](void*, void* ptr) { return free(ptr); };
+  alloc.Alloc = [](ISzAllocPtr, size_t size) { return malloc(size); };
+  alloc.Free = [](ISzAllocPtr, void* ptr) { return free(ptr); };
 
   XzUnpacker_Construct(&state, &alloc);
 
@@ -106,7 +106,7 @@
       dst_remaining += 2 * gnu_debugdata_size_;
     }
     return_val = XzUnpacker_Code(&state, dst->GetPtr(dst_offset), &dst_remaining, &src[src_offset],
-                                 &src_remaining, CODER_FINISH_ANY, &status);
+                                 &src_remaining, true, CODER_FINISH_ANY, &status);
     src_offset += src_remaining;
     dst_offset += dst_remaining;
   } while (return_val == SZ_OK && status == CODER_STATUS_NOT_FINISHED);
diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp
index 4c16212..bb682ea 100644
--- a/libunwindstack/Maps.cpp
+++ b/libunwindstack/Maps.cpp
@@ -24,7 +24,9 @@
 #include <unistd.h>
 
 #include <android-base/unique_fd.h>
+#include <procinfo/process_map.h>
 
+#include <algorithm>
 #include <cctype>
 #include <memory>
 #include <string>
@@ -56,150 +58,16 @@
   return nullptr;
 }
 
-// Assumes that line does not end in '\n'.
-static MapInfo* InternalParseLine(const char* line) {
-  // Do not use a sscanf implementation since it is not performant.
-
-  // Example linux /proc/<pid>/maps lines:
-  // 6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /system/lib/libcomposer.so
-  char* str;
-  const char* old_str = line;
-  uint64_t start = strtoull(old_str, &str, 16);
-  if (old_str == str || *str++ != '-') {
-    return nullptr;
-  }
-
-  old_str = str;
-  uint64_t end = strtoull(old_str, &str, 16);
-  if (old_str == str || !std::isspace(*str++)) {
-    return nullptr;
-  }
-
-  while (std::isspace(*str)) {
-    str++;
-  }
-
-  // Parse permissions data.
-  if (*str == '\0') {
-    return nullptr;
-  }
-  uint16_t flags = 0;
-  if (*str == 'r') {
-    flags |= PROT_READ;
-  } else if (*str != '-') {
-    return nullptr;
-  }
-  str++;
-  if (*str == 'w') {
-    flags |= PROT_WRITE;
-  } else if (*str != '-') {
-    return nullptr;
-  }
-  str++;
-  if (*str == 'x') {
-    flags |= PROT_EXEC;
-  } else if (*str != '-') {
-    return nullptr;
-  }
-  str++;
-  if (*str != 'p' && *str != 's') {
-    return nullptr;
-  }
-  str++;
-
-  if (!std::isspace(*str++)) {
-    return nullptr;
-  }
-
-  old_str = str;
-  uint64_t offset = strtoull(old_str, &str, 16);
-  if (old_str == str || !std::isspace(*str)) {
-    return nullptr;
-  }
-
-  // Ignore the 00:00 values.
-  old_str = str;
-  (void)strtoull(old_str, &str, 16);
-  if (old_str == str || *str++ != ':') {
-    return nullptr;
-  }
-  if (std::isspace(*str)) {
-    return nullptr;
-  }
-
-  // Skip the inode.
-  old_str = str;
-  (void)strtoull(str, &str, 16);
-  if (old_str == str || !std::isspace(*str++)) {
-    return nullptr;
-  }
-
-  // Skip decimal digit.
-  old_str = str;
-  (void)strtoull(old_str, &str, 10);
-  if (old_str == str || (!std::isspace(*str) && *str != '\0')) {
-    return nullptr;
-  }
-
-  while (std::isspace(*str)) {
-    str++;
-  }
-  if (*str == '\0') {
-    return new MapInfo(start, end, offset, flags, "");
-  }
-
-  // Save the name data.
-  std::string name(str);
-
-  // Mark a device map in /dev/ and not in /dev/ashmem/ specially.
-  if (name.substr(0, 5) == "/dev/" && name.substr(5, 7) != "ashmem/") {
-    flags |= MAPS_FLAGS_DEVICE_MAP;
-  }
-  return new MapInfo(start, end, offset, flags, name);
-}
-
 bool Maps::Parse() {
-  int fd = open(GetMapsFile().c_str(), O_RDONLY | O_CLOEXEC);
-  if (fd == -1) {
-    return false;
-  }
-
-  bool return_value = true;
-  char buffer[2048];
-  size_t leftover = 0;
-  while (true) {
-    ssize_t bytes = read(fd, &buffer[leftover], 2048 - leftover);
-    if (bytes == -1) {
-      return_value = false;
-      break;
-    }
-    if (bytes == 0) {
-      break;
-    }
-    bytes += leftover;
-    char* line = buffer;
-    while (bytes > 0) {
-      char* newline = static_cast<char*>(memchr(line, '\n', bytes));
-      if (newline == nullptr) {
-        memmove(buffer, line, bytes);
-        break;
-      }
-      *newline = '\0';
-
-      MapInfo* map_info = InternalParseLine(line);
-      if (map_info == nullptr) {
-        return_value = false;
-        break;
-      }
-      maps_.push_back(map_info);
-
-      bytes -= newline - line + 1;
-      line = newline + 1;
-    }
-    leftover = bytes;
-  }
-  close(fd);
-  return return_value;
+  return android::procinfo::ReadMapFile(
+      GetMapsFile(),
+      [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, const char* name) {
+        // Mark a device map in /dev/ and not in /dev/ashmem/ specially.
+        if (strncmp(name, "/dev/", 5) == 0 && strncmp(name + 5, "ashmem/", 7) != 0) {
+          flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
+        }
+        maps_.push_back(new MapInfo(start, end, pgoff, flags, name));
+      });
 }
 
 void Maps::Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
@@ -209,6 +77,11 @@
   maps_.push_back(map_info);
 }
 
+void Maps::Sort() {
+  std::sort(maps_.begin(), maps_.end(),
+            [](const MapInfo* a, const MapInfo* b) { return a->start < b->start; });
+}
+
 Maps::~Maps() {
   for (auto& map : maps_) {
     delete map;
@@ -216,26 +89,16 @@
 }
 
 bool BufferMaps::Parse() {
-  const char* start_of_line = buffer_;
-  do {
-    std::string line;
-    const char* end_of_line = strchr(start_of_line, '\n');
-    if (end_of_line == nullptr) {
-      line = start_of_line;
-    } else {
-      line = std::string(start_of_line, end_of_line - start_of_line);
-      end_of_line++;
-    }
-
-    MapInfo* map_info = InternalParseLine(line.c_str());
-    if (map_info == nullptr) {
-      return false;
-    }
-    maps_.push_back(map_info);
-
-    start_of_line = end_of_line;
-  } while (start_of_line != nullptr && *start_of_line != '\0');
-  return true;
+  std::string content(buffer_);
+  return android::procinfo::ReadMapFileContent(
+      &content[0],
+      [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, const char* name) {
+        // Mark a device map in /dev/ and not in /dev/ashmem/ specially.
+        if (strncmp(name, "/dev/", 5) == 0 && strncmp(name + 5, "ashmem/", 7) != 0) {
+          flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
+        }
+        maps_.push_back(new MapInfo(start, end, pgoff, flags, name));
+      });
 }
 
 const std::string RemoteMaps::GetMapsFile() const {
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 94edb1c..099cc9e 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -29,6 +29,7 @@
 #include <unwindstack/Elf.h>
 #include <unwindstack/JitDebug.h>
 #include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
 #include <unwindstack/Unwinder.h>
 
 #if !defined(NO_LIBDEXFILE_SUPPORT)
@@ -61,7 +62,9 @@
     frame->map_offset = info->offset;
     frame->map_load_bias = info->load_bias;
     frame->map_flags = info->flags;
-    frame->map_name = info->name;
+    if (resolve_names_) {
+      frame->map_name = info->name;
+    }
     frame->rel_pc = dex_pc - info->start;
   } else {
     frame->rel_pc = dex_pc;
@@ -96,7 +99,9 @@
     return;
   }
 
-  frame->map_name = map_info->name;
+  if (resolve_names_) {
+    frame->map_name = map_info->name;
+  }
   frame->map_offset = map_info->offset;
   frame->map_start = map_info->start;
   frame->map_end = map_info->end;
@@ -138,26 +143,31 @@
     uint64_t cur_sp = regs_->sp();
 
     MapInfo* map_info = maps_->Find(regs_->pc());
-    uint64_t rel_pc;
     uint64_t pc_adjustment = 0;
     uint64_t step_pc;
+    uint64_t rel_pc;
     Elf* elf;
     if (map_info == nullptr) {
-      rel_pc = regs_->pc();
-      step_pc = rel_pc;
+      step_pc = regs_->pc();
+      rel_pc = step_pc;
       last_error_.code = ERROR_INVALID_MAP;
     } else {
       if (ShouldStop(map_suffixes_to_ignore, map_info->name)) {
         break;
       }
       elf = map_info->GetElf(process_memory_, true);
-      rel_pc = elf->GetRelPc(regs_->pc(), map_info);
+      step_pc = regs_->pc();
+      rel_pc = elf->GetRelPc(step_pc, map_info);
+      // Everyone except elf data in gdb jit debug maps uses the relative pc.
+      if (!(map_info->flags & MAPS_FLAGS_JIT_SYMFILE_MAP)) {
+        step_pc = rel_pc;
+      }
       if (adjust_pc) {
         pc_adjustment = regs_->GetPcAdjustment(rel_pc, elf);
       } else {
         pc_adjustment = 0;
       }
-      step_pc = rel_pc - pc_adjustment;
+      step_pc -= pc_adjustment;
 
       // If the pc is in an invalid elf file, try and get an Elf object
       // using the jit debug information.
@@ -210,8 +220,7 @@
           in_device_map = true;
         } else {
           bool finished;
-          stepped = elf->Step(rel_pc, step_pc, map_info->elf_offset, regs_, process_memory_.get(),
-                              &finished);
+          stepped = elf->Step(rel_pc, step_pc, regs_, process_memory_.get(), &finished);
           elf->GetLastError(&last_error_);
           if (stepped && finished) {
             break;
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index 385973e..f4cdbda 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -65,8 +65,8 @@
 
   uint64_t GetRelPc(uint64_t pc, const MapInfo* map_info);
 
-  bool Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, uint64_t elf_offset, Regs* regs,
-            Memory* process_memory, bool* finished);
+  bool Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, Regs* regs, Memory* process_memory,
+            bool* finished);
 
   ElfInterface* CreateInterfaceFromMemory(Memory* memory);
 
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index a57fe68..ac0df41 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -34,6 +34,13 @@
 struct MapInfo {
   MapInfo() = default;
   MapInfo(uint64_t start, uint64_t end) : start(start), end(end) {}
+  MapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const char* name)
+      : start(start),
+        end(end),
+        offset(offset),
+        flags(flags),
+        name(name),
+        load_bias(static_cast<uint64_t>(-1)) {}
   MapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const std::string& name)
       : start(start),
         end(end),
diff --git a/libunwindstack/include/unwindstack/Maps.h b/libunwindstack/include/unwindstack/Maps.h
index 17a2d28..74e5c47 100644
--- a/libunwindstack/include/unwindstack/Maps.h
+++ b/libunwindstack/include/unwindstack/Maps.h
@@ -30,6 +30,10 @@
 // Special flag to indicate a map is in /dev/. However, a map in
 // /dev/ashmem/... does not set this flag.
 static constexpr int MAPS_FLAGS_DEVICE_MAP = 0x8000;
+// Special flag to indicate that this map represents an elf file
+// created by ART for use with the gdb jit debug interface.
+// This should only ever appear in offline maps data.
+static constexpr int MAPS_FLAGS_JIT_SYMFILE_MAP = 0x4000;
 
 class Maps {
  public:
@@ -45,6 +49,8 @@
   void Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const std::string& name,
            uint64_t load_bias);
 
+  void Sort();
+
   typedef std::vector<MapInfo*>::iterator iterator;
   iterator begin() { return maps_.begin(); }
   iterator end() { return maps_.end(); }
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index f9028c4..aecbf6d 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -133,7 +133,7 @@
   ASSERT_FALSE(elf.GetFunctionName(0, &name, &func_offset));
 
   bool finished;
-  ASSERT_FALSE(elf.Step(0, 0, 0, nullptr, nullptr, &finished));
+  ASSERT_FALSE(elf.Step(0, 0, nullptr, nullptr, &finished));
 }
 
 TEST_F(ElfTest, elf32_invalid_machine) {
@@ -330,7 +330,7 @@
   elf.FakeSetValid(true);
   elf.FakeSetLoadBias(0);
   bool finished;
-  ASSERT_TRUE(elf.Step(0x1000, 0x1000, 0x2000, &regs, &process_memory, &finished));
+  ASSERT_TRUE(elf.Step(0x3000, 0x1000, &regs, &process_memory, &finished));
   EXPECT_FALSE(finished);
   EXPECT_EQ(15U, regs.pc());
   EXPECT_EQ(13U, regs.sp());
@@ -370,7 +370,7 @@
   EXPECT_CALL(*interface, Step(0x1000, 0, &regs, &process_memory, &finished))
       .WillOnce(::testing::Return(true));
 
-  ASSERT_TRUE(elf.Step(0x1004, 0x1000, 0x2000, &regs, &process_memory, &finished));
+  ASSERT_TRUE(elf.Step(0x1004, 0x1000, &regs, &process_memory, &finished));
 }
 
 TEST_F(ElfTest, step_in_interface_non_zero_load_bias) {
@@ -388,7 +388,7 @@
   EXPECT_CALL(*interface, Step(0x7300, 0x4000, &regs, &process_memory, &finished))
       .WillOnce(::testing::Return(true));
 
-  ASSERT_TRUE(elf.Step(0x7304, 0x7300, 0x2000, &regs, &process_memory, &finished));
+  ASSERT_TRUE(elf.Step(0x7304, 0x7300, &regs, &process_memory, &finished));
 }
 
 TEST_F(ElfTest, get_global_invalid_elf) {
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index 8cb640f..285fc9e 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -18,6 +18,7 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/mman.h>
 #include <unistd.h>
 
 #include <gtest/gtest.h>
@@ -45,6 +46,12 @@
 
 namespace unwindstack {
 
+static void AddMemory(std::string file_name, MemoryOfflineParts* parts) {
+  MemoryOffline* memory = new MemoryOffline;
+  ASSERT_TRUE(memory->Init(file_name.c_str(), 0));
+  parts->Add(memory);
+}
+
 class UnwindOfflineTest : public ::testing::Test {
  protected:
   void TearDown() override {
@@ -63,9 +70,24 @@
     maps_.reset(new BufferMaps(data.c_str()));
     ASSERT_TRUE(maps_->Parse());
 
-    std::unique_ptr<MemoryOffline> stack_memory(new MemoryOffline);
-    ASSERT_TRUE(stack_memory->Init((dir_ + "stack.data").c_str(), 0));
-    process_memory_.reset(stack_memory.release());
+    std::string stack_name(dir_ + "stack.data");
+    struct stat st;
+    if (stat(stack_name.c_str(), &st) == 0 && S_ISREG(st.st_mode)) {
+      std::unique_ptr<MemoryOffline> stack_memory(new MemoryOffline);
+      ASSERT_TRUE(stack_memory->Init((dir_ + "stack.data").c_str(), 0));
+      process_memory_.reset(stack_memory.release());
+    } else {
+      std::unique_ptr<MemoryOfflineParts> stack_memory(new MemoryOfflineParts);
+      for (size_t i = 0;; i++) {
+        stack_name = dir_ + "stack" + std::to_string(i) + ".data";
+        if (stat(stack_name.c_str(), &st) == -1 || !S_ISREG(st.st_mode)) {
+          ASSERT_TRUE(i != 0) << "No stack data files found.";
+          break;
+        }
+        AddMemory(stack_name, stack_memory.get());
+      }
+      process_memory_.reset(stack_memory.release());
+    }
 
     switch (arch) {
       case ARCH_ARM: {
@@ -179,7 +201,7 @@
 }
 
 TEST_F(UnwindOfflineTest, pc_straddle_arm) {
-  Init("straddle_arm/", ARCH_ARM);
+  ASSERT_NO_FATAL_FAILURE(Init("straddle_arm/", ARCH_ARM));
 
   Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
   unwinder.Unwind();
@@ -203,7 +225,7 @@
 }
 
 TEST_F(UnwindOfflineTest, pc_in_gnu_debugdata_arm) {
-  Init("gnu_debugdata_arm/", ARCH_ARM);
+  ASSERT_NO_FATAL_FAILURE(Init("gnu_debugdata_arm/", ARCH_ARM));
 
   Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
   unwinder.Unwind();
@@ -223,7 +245,7 @@
 }
 
 TEST_F(UnwindOfflineTest, pc_straddle_arm64) {
-  Init("straddle_arm64/", ARCH_ARM64);
+  ASSERT_NO_FATAL_FAILURE(Init("straddle_arm64/", ARCH_ARM64));
 
   Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
   unwinder.Unwind();
@@ -254,14 +276,8 @@
   EXPECT_EQ(0x7fe0d84110U, unwinder.frames()[5].sp);
 }
 
-static void AddMemory(std::string file_name, MemoryOfflineParts* parts) {
-  MemoryOffline* memory = new MemoryOffline;
-  ASSERT_TRUE(memory->Init(file_name.c_str(), 0));
-  parts->Add(memory);
-}
-
 TEST_F(UnwindOfflineTest, jit_debug_x86) {
-  Init("jit_debug_x86/", ARCH_X86);
+  ASSERT_NO_FATAL_FAILURE(Init("jit_debug_x86/", ARCH_X86));
 
   MemoryOfflineParts* memory = new MemoryOfflineParts;
   AddMemory(dir_ + "descriptor.data", memory);
@@ -554,7 +570,7 @@
 }
 
 TEST_F(UnwindOfflineTest, jit_debug_arm) {
-  Init("jit_debug_arm/", ARCH_ARM);
+  ASSERT_NO_FATAL_FAILURE(Init("jit_debug_arm/", ARCH_ARM));
 
   MemoryOfflineParts* memory = new MemoryOfflineParts;
   AddMemory(dir_ + "descriptor.data", memory);
@@ -872,7 +888,7 @@
 // fallback to iterating over the cies/fdes and ignore the eh_frame_hdr.
 // No .gnu_debugdata section in the elf file, so no symbols.
 TEST_F(UnwindOfflineTest, bad_eh_frame_hdr_arm64) {
-  Init("bad_eh_frame_hdr_arm64/", ARCH_ARM64);
+  ASSERT_NO_FATAL_FAILURE(Init("bad_eh_frame_hdr_arm64/", ARCH_ARM64));
 
   Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
   unwinder.Unwind();
@@ -901,7 +917,7 @@
 // The elf has bad eh_frame unwind information for the pcs. If eh_frame
 // is used first, the unwind will not match the expected output.
 TEST_F(UnwindOfflineTest, debug_frame_first_x86) {
-  Init("debug_frame_first_x86/", ARCH_X86);
+  ASSERT_NO_FATAL_FAILURE(Init("debug_frame_first_x86/", ARCH_X86));
 
   Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
   unwinder.Unwind();
@@ -929,7 +945,7 @@
 
 // Make sure that a pc that is at the beginning of an fde unwinds correctly.
 TEST_F(UnwindOfflineTest, eh_frame_hdr_begin_x86_64) {
-  Init("eh_frame_hdr_begin_x86_64/", ARCH_X86_64);
+  ASSERT_NO_FATAL_FAILURE(Init("eh_frame_hdr_begin_x86_64/", ARCH_X86_64));
 
   Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
   unwinder.Unwind();
@@ -956,7 +972,7 @@
 }
 
 TEST_F(UnwindOfflineTest, art_quick_osr_stub_arm) {
-  Init("art_quick_osr_stub_arm/", ARCH_ARM);
+  ASSERT_NO_FATAL_FAILURE(Init("art_quick_osr_stub_arm/", ARCH_ARM));
 
   MemoryOfflineParts* memory = new MemoryOfflineParts;
   AddMemory(dir_ + "descriptor.data", memory);
@@ -1070,4 +1086,118 @@
   EXPECT_EQ(0xcd4ff960U, unwinder.frames()[24].sp);
 }
 
+TEST_F(UnwindOfflineTest, jit_map_arm) {
+  ASSERT_NO_FATAL_FAILURE(Init("jit_map_arm/", ARCH_ARM));
+
+  maps_->Add(0xd025c788, 0xd025c9f0, 0, PROT_READ | PROT_EXEC | MAPS_FLAGS_JIT_SYMFILE_MAP,
+             "jit_map0.so", 0);
+  maps_->Add(0xd025cd98, 0xd025cff4, 0, PROT_READ | PROT_EXEC | MAPS_FLAGS_JIT_SYMFILE_MAP,
+             "jit_map1.so", 0);
+  maps_->Sort();
+
+  Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+  unwinder.Unwind();
+
+  std::string frame_info(DumpFrames(unwinder));
+  ASSERT_EQ(6U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+  EXPECT_EQ(
+      "  #00 pc 00000000  jit_map0.so "
+      "(com.example.simpleperf.simpleperfexamplewithnative.MixActivity.access$000)\n"
+      "  #01 pc 0000003d  jit_map1.so "
+      "(com.example.simpleperf.simpleperfexamplewithnative.MixActivity$1.run+60)\n"
+      "  #02 pc 004135bb  libart.so (art_quick_osr_stub+42)\n"
+
+      "  #03 pc 003851dd  libart.so (_ZN3art6Thread14CreateCallbackEPv+868)\n"
+      "  #04 pc 00062925  libc.so (_ZL15__pthread_startPv+22)\n"
+      "  #05 pc 0001de39  libc.so (__start_thread+24)\n",
+      frame_info);
+
+  EXPECT_EQ(0xd025c788U, unwinder.frames()[0].pc);
+  EXPECT_EQ(0xcd4ff140U, unwinder.frames()[0].sp);
+  EXPECT_EQ(0xd025cdd5U, unwinder.frames()[1].pc);
+  EXPECT_EQ(0xcd4ff140U, unwinder.frames()[1].sp);
+  EXPECT_EQ(0xe4a755bbU, unwinder.frames()[2].pc);
+  EXPECT_EQ(0xcd4ff160U, unwinder.frames()[2].sp);
+  EXPECT_EQ(0xe49e71ddU, unwinder.frames()[3].pc);
+  EXPECT_EQ(0xcd4ff8e8U, unwinder.frames()[3].sp);
+  EXPECT_EQ(0xe7df3925U, unwinder.frames()[4].pc);
+  EXPECT_EQ(0xcd4ff958U, unwinder.frames()[4].sp);
+  EXPECT_EQ(0xe7daee39U, unwinder.frames()[5].pc);
+  EXPECT_EQ(0xcd4ff960U, unwinder.frames()[5].sp);
+}
+
+TEST_F(UnwindOfflineTest, offset_arm) {
+  ASSERT_NO_FATAL_FAILURE(Init("offset_arm/", ARCH_ARM));
+
+  Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+  unwinder.Unwind();
+
+  std::string frame_info(DumpFrames(unwinder));
+  ASSERT_EQ(19U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+  EXPECT_EQ(
+      "  #00 pc 0032bfa0 (offset 0x42000)  libunwindstack_test (SignalInnerFunction+40)\n"
+      "  #01 pc 0032bfeb (offset 0x42000)  libunwindstack_test (SignalMiddleFunction+2)\n"
+      "  #02 pc 0032bff3 (offset 0x42000)  libunwindstack_test (SignalOuterFunction+2)\n"
+      "  #03 pc 0032fed3 (offset 0x42000)  libunwindstack_test "
+      "(_ZN11unwindstackL19SignalCallerHandlerEiP7siginfoPv+26)\n"
+      "  #04 pc 00026528 (offset 0x25000)  libc.so\n"
+      "  #05 pc 00000000  <unknown>\n"
+      "  #06 pc 0032c2d9 (offset 0x42000)  libunwindstack_test (InnerFunction+736)\n"
+      "  #07 pc 0032cc4f (offset 0x42000)  libunwindstack_test (MiddleFunction+42)\n"
+      "  #08 pc 0032cc81 (offset 0x42000)  libunwindstack_test (OuterFunction+42)\n"
+      "  #09 pc 0032e547 (offset 0x42000)  libunwindstack_test "
+      "(_ZN11unwindstackL19RemoteThroughSignalEij+270)\n"
+      "  #10 pc 0032ed99 (offset 0x42000)  libunwindstack_test "
+      "(_ZN11unwindstack55UnwindTest_remote_through_signal_with_invalid_func_Test8TestBodyEv+16)\n"
+      "  #11 pc 00354453 (offset 0x42000)  libunwindstack_test (_ZN7testing4Test3RunEv+154)\n"
+      "  #12 pc 00354de7 (offset 0x42000)  libunwindstack_test (_ZN7testing8TestInfo3RunEv+194)\n"
+      "  #13 pc 00355105 (offset 0x42000)  libunwindstack_test (_ZN7testing8TestCase3RunEv+180)\n"
+      "  #14 pc 0035a215 (offset 0x42000)  libunwindstack_test "
+      "(_ZN7testing8internal12UnitTestImpl11RunAllTestsEv+664)\n"
+      "  #15 pc 00359f4f (offset 0x42000)  libunwindstack_test (_ZN7testing8UnitTest3RunEv+110)\n"
+      "  #16 pc 0034d3db (offset 0x42000)  libunwindstack_test (main+38)\n"
+      "  #17 pc 00092c0d (offset 0x25000)  libc.so (__libc_init+48)\n"
+      "  #18 pc 0004202f (offset 0x42000)  libunwindstack_test (_start_main+38)\n",
+      frame_info);
+
+  EXPECT_EQ(0x2e55fa0U, unwinder.frames()[0].pc);
+  EXPECT_EQ(0xf43d2cccU, unwinder.frames()[0].sp);
+  EXPECT_EQ(0x2e55febU, unwinder.frames()[1].pc);
+  EXPECT_EQ(0xf43d2ce0U, unwinder.frames()[1].sp);
+  EXPECT_EQ(0x2e55ff3U, unwinder.frames()[2].pc);
+  EXPECT_EQ(0xf43d2ce8U, unwinder.frames()[2].sp);
+  EXPECT_EQ(0x2e59ed3U, unwinder.frames()[3].pc);
+  EXPECT_EQ(0xf43d2cf0U, unwinder.frames()[3].sp);
+  EXPECT_EQ(0xf4136528U, unwinder.frames()[4].pc);
+  EXPECT_EQ(0xf43d2d10U, unwinder.frames()[4].sp);
+  EXPECT_EQ(0U, unwinder.frames()[5].pc);
+  EXPECT_EQ(0xffcc0ee0U, unwinder.frames()[5].sp);
+  EXPECT_EQ(0x2e562d9U, unwinder.frames()[6].pc);
+  EXPECT_EQ(0xffcc0ee0U, unwinder.frames()[6].sp);
+  EXPECT_EQ(0x2e56c4fU, unwinder.frames()[7].pc);
+  EXPECT_EQ(0xffcc1060U, unwinder.frames()[7].sp);
+  EXPECT_EQ(0x2e56c81U, unwinder.frames()[8].pc);
+  EXPECT_EQ(0xffcc1078U, unwinder.frames()[8].sp);
+  EXPECT_EQ(0x2e58547U, unwinder.frames()[9].pc);
+  EXPECT_EQ(0xffcc1090U, unwinder.frames()[9].sp);
+  EXPECT_EQ(0x2e58d99U, unwinder.frames()[10].pc);
+  EXPECT_EQ(0xffcc1438U, unwinder.frames()[10].sp);
+  EXPECT_EQ(0x2e7e453U, unwinder.frames()[11].pc);
+  EXPECT_EQ(0xffcc1448U, unwinder.frames()[11].sp);
+  EXPECT_EQ(0x2e7ede7U, unwinder.frames()[12].pc);
+  EXPECT_EQ(0xffcc1458U, unwinder.frames()[12].sp);
+  EXPECT_EQ(0x2e7f105U, unwinder.frames()[13].pc);
+  EXPECT_EQ(0xffcc1490U, unwinder.frames()[13].sp);
+  EXPECT_EQ(0x2e84215U, unwinder.frames()[14].pc);
+  EXPECT_EQ(0xffcc14c0U, unwinder.frames()[14].sp);
+  EXPECT_EQ(0x2e83f4fU, unwinder.frames()[15].pc);
+  EXPECT_EQ(0xffcc1510U, unwinder.frames()[15].sp);
+  EXPECT_EQ(0x2e773dbU, unwinder.frames()[16].pc);
+  EXPECT_EQ(0xffcc1528U, unwinder.frames()[16].sp);
+  EXPECT_EQ(0xf41a2c0dU, unwinder.frames()[17].pc);
+  EXPECT_EQ(0xffcc1540U, unwinder.frames()[17].sp);
+  EXPECT_EQ(0x2b6c02fU, unwinder.frames()[18].pc);
+  EXPECT_EQ(0xffcc1558U, unwinder.frames()[18].sp);
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index b38fb5f..2428f68 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -221,7 +221,7 @@
   EXPECT_EQ(0x10000U, frame->sp);
   EXPECT_EQ("", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
-  EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+  EXPECT_EQ("", frame->map_name);
   EXPECT_EQ(0U, frame->map_offset);
   EXPECT_EQ(0x1000U, frame->map_start);
   EXPECT_EQ(0x8000U, frame->map_end);
@@ -235,7 +235,7 @@
   EXPECT_EQ(0x10010U, frame->sp);
   EXPECT_EQ("", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
-  EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+  EXPECT_EQ("", frame->map_name);
   EXPECT_EQ(0U, frame->map_offset);
   EXPECT_EQ(0x1000U, frame->map_start);
   EXPECT_EQ(0x8000U, frame->map_end);
@@ -249,7 +249,7 @@
   EXPECT_EQ(0x10020U, frame->sp);
   EXPECT_EQ("", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
-  EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+  EXPECT_EQ("", frame->map_name);
   EXPECT_EQ(0U, frame->map_offset);
   EXPECT_EQ(0x1000U, frame->map_start);
   EXPECT_EQ(0x8000U, frame->map_end);
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/jit_map0.so b/libunwindstack/tests/files/offline/jit_map_arm/jit_map0.so
new file mode 100644
index 0000000..e667883
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_map_arm/jit_map0.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/jit_map1.so b/libunwindstack/tests/files/offline/jit_map_arm/jit_map1.so
new file mode 100644
index 0000000..9a1d714
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_map_arm/jit_map1.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/libart.so b/libunwindstack/tests/files/offline/jit_map_arm/libart.so
new file mode 100644
index 0000000..09ba495
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_map_arm/libart.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/libc.so b/libunwindstack/tests/files/offline/jit_map_arm/libc.so
new file mode 100644
index 0000000..39c9025
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_map_arm/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/maps.txt b/libunwindstack/tests/files/offline/jit_map_arm/maps.txt
new file mode 100644
index 0000000..5aaec54
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_map_arm/maps.txt
@@ -0,0 +1,2 @@
+e466e000-e4ae8000 r-xp 0 00:00 0 libart.so
+e7d91000-e7e31000 r-xp 0 00:00 0 libc.so
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/regs.txt b/libunwindstack/tests/files/offline/jit_map_arm/regs.txt
new file mode 100644
index 0000000..0b51814
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_map_arm/regs.txt
@@ -0,0 +1,16 @@
+r0: e814103c
+r1: 12dcf218
+r2: 1a90df75
+r3: ffffffbf
+r4: 0
+r5: 12dc0800
+r6: 12dcf218
+r7: 1a90df75
+r8: 0
+r9: dd23cc00
+r10: 1c
+r11: cd4ff16c
+ip: 0
+sp: cd4ff140
+lr: d025cdd7
+pc: d025c788
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/stack.data b/libunwindstack/tests/files/offline/jit_map_arm/stack.data
new file mode 100644
index 0000000..fb8feeb
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_map_arm/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/offset_arm/libc.so b/libunwindstack/tests/files/offline/offset_arm/libc.so
new file mode 100644
index 0000000..9f5c8ca
--- /dev/null
+++ b/libunwindstack/tests/files/offline/offset_arm/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/offset_arm/libunwindstack_test b/libunwindstack/tests/files/offline/offset_arm/libunwindstack_test
new file mode 100644
index 0000000..7a30bfa
--- /dev/null
+++ b/libunwindstack/tests/files/offline/offset_arm/libunwindstack_test
Binary files differ
diff --git a/libunwindstack/tests/files/offline/offset_arm/maps.txt b/libunwindstack/tests/files/offline/offset_arm/maps.txt
new file mode 100644
index 0000000..6224464
--- /dev/null
+++ b/libunwindstack/tests/files/offline/offset_arm/maps.txt
@@ -0,0 +1,2 @@
+2b6c000-2e92000 r-xp 42000 00:00 0   libunwindstack_test
+f4135000-f41a9000 r-xp 25000 00:00 0   libc.so
diff --git a/libunwindstack/tests/files/offline/offset_arm/regs.txt b/libunwindstack/tests/files/offline/offset_arm/regs.txt
new file mode 100644
index 0000000..1f4ac8f
--- /dev/null
+++ b/libunwindstack/tests/files/offline/offset_arm/regs.txt
@@ -0,0 +1,16 @@
+r0: 5
+r1: 5
+r2: 4
+r3: 1
+r4: 73804b6b
+r5: f3c9c000
+r6: 2ea09ac
+r7: 10624dd3
+r8: f41b5d8c
+r9: f3c9c000
+r10: 6f17
+r11: f3c94048
+ip: 2ea0807
+sp: f43d2ccc
+lr: 2e55fef
+pc: 2e55fa0
diff --git a/libunwindstack/tests/files/offline/offset_arm/stack0.data b/libunwindstack/tests/files/offline/offset_arm/stack0.data
new file mode 100644
index 0000000..23a9874
--- /dev/null
+++ b/libunwindstack/tests/files/offline/offset_arm/stack0.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/offset_arm/stack1.data b/libunwindstack/tests/files/offline/offset_arm/stack1.data
new file mode 100644
index 0000000..49bdd1e
--- /dev/null
+++ b/libunwindstack/tests/files/offline/offset_arm/stack1.data
Binary files differ
diff --git a/libunwindstack/tools/unwind_for_offline.cpp b/libunwindstack/tools/unwind_for_offline.cpp
index 74868d4..589731d 100644
--- a/libunwindstack/tools/unwind_for_offline.cpp
+++ b/libunwindstack/tools/unwind_for_offline.cpp
@@ -30,6 +30,7 @@
 #include <memory>
 #include <string>
 #include <unordered_map>
+#include <utility>
 #include <vector>
 
 #include <unwindstack/Elf.h>
@@ -78,30 +79,44 @@
   return true;
 }
 
-bool SaveStack(pid_t pid, uint64_t sp_start, uint64_t sp_end) {
-  std::unique_ptr<FILE, decltype(&fclose)> fp(fopen("stack.data", "w+"), &fclose);
-  if (fp == nullptr) {
-    printf("Failed to create stack.data.\n");
-    return false;
-  }
+bool SaveStack(pid_t pid, const std::vector<std::pair<uint64_t, uint64_t>>& stacks) {
+  for (size_t i = 0; i < stacks.size(); i++) {
+    std::string file_name;
+    if (stacks.size() != 1) {
+      file_name = "stack" + std::to_string(i) + ".data";
+    } else {
+      file_name = "stack.data";
+    }
 
-  size_t bytes = fwrite(&sp_start, 1, sizeof(sp_start), fp.get());
-  if (bytes != sizeof(sp_start)) {
-    perror("Failed to write all data.");
-    return false;
-  }
+    // Do this first, so if it fails, we don't create the file.
+    uint64_t sp_start = stacks[i].first;
+    uint64_t sp_end = stacks[i].second;
+    std::vector<uint8_t> buffer(sp_end - sp_start);
+    auto process_memory = unwindstack::Memory::CreateProcessMemory(pid);
+    if (!process_memory->Read(sp_start, buffer.data(), buffer.size())) {
+      printf("Unable to read stack data.\n");
+      return false;
+    }
 
-  std::vector<uint8_t> buffer(sp_end - sp_start);
-  auto process_memory = unwindstack::Memory::CreateProcessMemory(pid);
-  if (!process_memory->Read(sp_start, buffer.data(), buffer.size())) {
-    printf("Unable to read stack data.\n");
-    return false;
-  }
+    printf("Saving the stack 0x%" PRIx64 "-0x%" PRIx64 "\n", sp_start, sp_end);
 
-  bytes = fwrite(buffer.data(), 1, buffer.size(), fp.get());
-  if (bytes != buffer.size()) {
-    printf("Failed to write all stack data: stack size %zu, written %zu\n", buffer.size(), bytes);
-    return 1;
+    std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(file_name.c_str(), "w+"), &fclose);
+    if (fp == nullptr) {
+      printf("Failed to create stack.data.\n");
+      return false;
+    }
+
+    size_t bytes = fwrite(&sp_start, 1, sizeof(sp_start), fp.get());
+    if (bytes != sizeof(sp_start)) {
+      perror("Failed to write all data.");
+      return false;
+    }
+
+    bytes = fwrite(buffer.data(), 1, buffer.size(), fp.get());
+    if (bytes != buffer.size()) {
+      printf("Failed to write all stack data: stack size %zu, written %zu\n", buffer.size(), bytes);
+      return false;
+    }
   }
 
   return true;
@@ -110,17 +125,11 @@
 bool CreateElfFromMemory(std::shared_ptr<unwindstack::Memory>& memory, map_info_t* info) {
   std::string cur_name;
   if (info->name.empty()) {
-    cur_name = android::base::StringPrintf("anonymous:%" PRIx64, info->start);
+    cur_name = android::base::StringPrintf("anonymous_%" PRIx64, info->start);
   } else {
-    cur_name = basename(info->name.c_str());
-    cur_name = android::base::StringPrintf("%s:%" PRIx64, basename(info->name.c_str()), info->start);
+    cur_name = android::base::StringPrintf("%s_%" PRIx64, basename(info->name.c_str()), info->start);
   }
 
-  std::unique_ptr<FILE, decltype(&fclose)> output(fopen(cur_name.c_str(), "w+"), &fclose);
-  if (output == nullptr) {
-    printf("Cannot create %s\n", cur_name.c_str());
-    return false;
-  }
   std::vector<uint8_t> buffer(info->end - info->start);
   // If this is a mapped in file, it might not be possible to read the entire
   // map, so read all that is readable.
@@ -129,6 +138,13 @@
     printf("Cannot read data from address %" PRIx64 " length %zu\n", info->start, buffer.size());
     return false;
   }
+
+  std::unique_ptr<FILE, decltype(&fclose)> output(fopen(cur_name.c_str(), "w+"), &fclose);
+  if (output == nullptr) {
+    printf("Cannot create %s\n", cur_name.c_str());
+    return false;
+  }
+
   size_t bytes_written = fwrite(buffer.data(), 1, bytes, output.get());
   if (bytes_written != bytes) {
     printf("Failed to write all data to file: bytes read %zu, written %zu\n", bytes, bytes_written);
@@ -198,9 +214,21 @@
   unwinder.Unwind();
 
   std::unordered_map<uint64_t, map_info_t> maps_by_start;
-  uint64_t last_sp;
+  std::vector<std::pair<uint64_t, uint64_t>> stacks;
+  uint64_t sp_map_start = 0;
+  unwindstack::MapInfo* map_info = maps.Find(sp);
+  if (map_info != nullptr) {
+    stacks.emplace_back(std::make_pair(sp, map_info->end));
+    sp_map_start = map_info->start;
+  }
+
   for (auto frame : unwinder.frames()) {
-    last_sp = frame.sp;
+    map_info = maps.Find(frame.sp);
+    if (map_info != nullptr && sp_map_start != map_info->start) {
+      stacks.emplace_back(std::make_pair(frame.sp, map_info->end));
+      sp_map_start = map_info->start;
+    }
+
     if (maps_by_start.count(frame.map_start) == 0) {
       auto info = &maps_by_start[frame.map_start];
       info->start = frame.map_start;
@@ -211,7 +239,12 @@
         // Try to create the elf from memory, this will handle cases where
         // the data only exists in memory such as vdso data on x86.
         if (!CreateElfFromMemory(process_memory, info)) {
-          return 1;
+          printf("Ignoring map ");
+          if (!info->name.empty()) {
+            printf("%s\n", info->name.c_str());
+          } else {
+            printf("anonymous:%" PRIx64 "\n", info->start);
+          }
         }
       }
     }
@@ -221,7 +254,7 @@
     printf("%s\n", unwinder.FormatFrame(i).c_str());
   }
 
-  if (!SaveStack(pid, sp, last_sp)) {
+  if (!SaveStack(pid, stacks)) {
     return 1;
   }
 
diff --git a/libutils/Android.bp b/libutils/Android.bp
index a4fc4b4..0d7925a 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -129,7 +129,6 @@
         "PropertyMap.cpp",
         "RefBase.cpp",
         "SharedBuffer.cpp",
-        "Static.cpp",
         "StopWatch.cpp",
         "String8.cpp",
         "String16.cpp",
diff --git a/libutils/SharedBuffer.h b/libutils/SharedBuffer.h
index 48358cd..81cadff 100644
--- a/libutils/SharedBuffer.h
+++ b/libutils/SharedBuffer.h
@@ -139,7 +139,7 @@
     return (mRefs.load(std::memory_order_acquire) == 1);
 }
 
-}; // namespace android
+}  // namespace android
 
 // ---------------------------------------------------------------------------
 
diff --git a/libutils/Static.cpp b/libutils/Static.cpp
deleted file mode 100644
index 3ed07a1..0000000
--- a/libutils/Static.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// All static variables go here, to control initialization and
-// destruction order in the library.
-
-namespace android {
-
-// For String8.cpp
-extern void initialize_string8();
-extern void terminate_string8();
-
-// For String16.cpp
-extern void initialize_string16();
-extern void terminate_string16();
-
-class LibUtilsFirstStatics
-{
-public:
-    LibUtilsFirstStatics()
-    {
-        initialize_string8();
-        initialize_string16();
-    }
-    
-    ~LibUtilsFirstStatics()
-    {
-        terminate_string16();
-        terminate_string8();
-    }
-};
-
-static LibUtilsFirstStatics gFirstStatics;
-int gDarwinCantLoadAllObjects = 1;
-
-}   // namespace android
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index e8f1c51..230e970 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -24,29 +24,16 @@
 
 namespace android {
 
-static SharedBuffer* gEmptyStringBuf = NULL;
-static char16_t* gEmptyString = NULL;
+static inline char16_t* getEmptyString() {
+    static SharedBuffer* gEmptyStringBuf = [] {
+        SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t));
+        char16_t* str = static_cast<char16_t*>(buf->data());
+        *str = 0;
+        return buf;
+    }();
 
-static inline char16_t* getEmptyString()
-{
     gEmptyStringBuf->acquire();
-   return gEmptyString;
-}
-
-void initialize_string16()
-{
-    SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t));
-    char16_t* str = (char16_t*)buf->data();
-    *str = 0;
-    gEmptyStringBuf = buf;
-    gEmptyString = str;
-}
-
-void terminate_string16()
-{
-    SharedBuffer::bufferFromData(gEmptyString)->release();
-    gEmptyStringBuf = NULL;
-    gEmptyString = NULL;
+    return static_cast<char16_t*>(gEmptyStringBuf->data());
 }
 
 // ---------------------------------------------------------------------------
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index ad0e72e..580e870 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -40,40 +40,16 @@
 // to OS_PATH_SEPARATOR.
 #define RES_PATH_SEPARATOR '/'
 
-static SharedBuffer* gEmptyStringBuf = NULL;
-static char* gEmptyString = NULL;
+static inline char* getEmptyString() {
+    static SharedBuffer* gEmptyStringBuf = [] {
+        SharedBuffer* buf = SharedBuffer::alloc(1);
+        char* str = static_cast<char*>(buf->data());
+        *str = 0;
+        return buf;
+    }();
 
-extern int gDarwinCantLoadAllObjects;
-int gDarwinIsReallyAnnoying;
-
-void initialize_string8();
-
-static inline char* getEmptyString()
-{
     gEmptyStringBuf->acquire();
-    return gEmptyString;
-}
-
-void initialize_string8()
-{
-    // HACK: This dummy dependency forces linking libutils Static.cpp,
-    // which is needed to initialize String8/String16 classes.
-    // These variables are named for Darwin, but are needed elsewhere too,
-    // including static linking on any platform.
-    gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects;
-
-    SharedBuffer* buf = SharedBuffer::alloc(1);
-    char* str = (char*)buf->data();
-    *str = 0;
-    gEmptyStringBuf = buf;
-    gEmptyString = str;
-}
-
-void terminate_string8()
-{
-    SharedBuffer::bufferFromData(gEmptyString)->release();
-    gEmptyStringBuf = NULL;
-    gEmptyString = NULL;
+    return static_cast<char*>(gEmptyStringBuf->data());
 }
 
 // ---------------------------------------------------------------------------
diff --git a/libutils/include/utils/AndroidThreads.h b/libutils/include/utils/AndroidThreads.h
index 4c2dd49..dab888d 100644
--- a/libutils/include/utils/AndroidThreads.h
+++ b/libutils/include/utils/AndroidThreads.h
@@ -118,7 +118,7 @@
 }
 
 // ----------------------------------------------------------------------------
-}; // namespace android
+}  // namespace android
 #endif  // __cplusplus
 // ----------------------------------------------------------------------------
 
diff --git a/libutils/include/utils/CallStack.h b/libutils/include/utils/CallStack.h
index 27e89f4..9622142 100644
--- a/libutils/include/utils/CallStack.h
+++ b/libutils/include/utils/CallStack.h
@@ -67,6 +67,6 @@
     Vector<String8> mFrameLines;
 };
 
-}; // namespace android
+}  // namespace android
 
 #endif // ANDROID_CALLSTACK_H
diff --git a/libutils/include/utils/Condition.h b/libutils/include/utils/Condition.h
index 9bf82eb..c8da67c 100644
--- a/libutils/include/utils/Condition.h
+++ b/libutils/include/utils/Condition.h
@@ -159,7 +159,7 @@
 #endif // !defined(_WIN32)
 
 // ---------------------------------------------------------------------------
-}; // namespace android
+}  // namespace android
 // ---------------------------------------------------------------------------
 
 #endif // _LIBS_UTILS_CONDITON_H
diff --git a/libutils/include/utils/Debug.h b/libutils/include/utils/Debug.h
index 4cbb462..96bd70e 100644
--- a/libutils/include/utils/Debug.h
+++ b/libutils/include/utils/Debug.h
@@ -35,6 +35,6 @@
     CompileTimeAssert<( _exp )>();
 
 // ---------------------------------------------------------------------------
-}; // namespace android
+}  // namespace android
 
 #endif // ANDROID_UTILS_DEBUG_H
diff --git a/libutils/include/utils/Errors.h b/libutils/include/utils/Errors.h
index 16e1fa2..7093a20 100644
--- a/libutils/include/utils/Errors.h
+++ b/libutils/include/utils/Errors.h
@@ -81,8 +81,8 @@
 # define NO_ERROR 0L
 #endif
 
-}; // namespace android
-    
+}  // namespace android
+
 // ---------------------------------------------------------------------------
     
 #endif // ANDROID_ERRORS_H
diff --git a/libutils/include/utils/FileMap.h b/libutils/include/utils/FileMap.h
index 7d372e1..8d402a3 100644
--- a/libutils/include/utils/FileMap.h
+++ b/libutils/include/utils/FileMap.h
@@ -124,6 +124,6 @@
     static long mPageSize;
 };
 
-}; // namespace android
+}  // namespace android
 
 #endif // __LIBS_FILE_MAP_H
diff --git a/libutils/include/utils/Flattenable.h b/libutils/include/utils/Flattenable.h
index 675e211..0a19019 100644
--- a/libutils/include/utils/Flattenable.h
+++ b/libutils/include/utils/Flattenable.h
@@ -198,8 +198,6 @@
     }
 };
 
-
-}; // namespace android
-
+}  // namespace android
 
 #endif /* ANDROID_UTILS_FLATTENABLE_H */
diff --git a/libutils/include/utils/Functor.h b/libutils/include/utils/Functor.h
index 3182a9c..c0c8d57 100644
--- a/libutils/include/utils/Functor.h
+++ b/libutils/include/utils/Functor.h
@@ -32,6 +32,6 @@
     virtual status_t operator ()(int /*what*/, void* /*data*/) { return NO_ERROR; }
 };
 
-}; // namespace android
+}  // namespace android
 
 #endif // ANDROID_FUNCTOR_H
diff --git a/libutils/include/utils/KeyedVector.h b/libutils/include/utils/KeyedVector.h
index 03bfe27..7bda99b 100644
--- a/libutils/include/utils/KeyedVector.h
+++ b/libutils/include/utils/KeyedVector.h
@@ -211,7 +211,7 @@
     return i >= 0 ? KeyedVector<KEY,VALUE>::valueAt(i) : mDefault;
 }
 
-}; // namespace android
+}  // namespace android
 
 // ---------------------------------------------------------------------------
 
diff --git a/libutils/include/utils/LightRefBase.h b/libutils/include/utils/LightRefBase.h
index 65257ed..e488e60 100644
--- a/libutils/include/utils/LightRefBase.h
+++ b/libutils/include/utils/LightRefBase.h
@@ -69,4 +69,4 @@
     virtual ~VirtualLightRefBase() = default;
 };
 
-}; // namespace android
+}  // namespace android
diff --git a/libutils/include/utils/List.h b/libutils/include/utils/List.h
index daca016..25b56fd 100644
--- a/libutils/include/utils/List.h
+++ b/libutils/include/utils/List.h
@@ -329,6 +329,6 @@
     return *this;
 }
 
-}; // namespace android
+}  // namespace android
 
 #endif // _LIBS_UTILS_LIST_H
diff --git a/libutils/include/utils/Mutex.h b/libutils/include/utils/Mutex.h
index af6076c..1228df4 100644
--- a/libutils/include/utils/Mutex.h
+++ b/libutils/include/utils/Mutex.h
@@ -212,7 +212,7 @@
 typedef Mutex::Autolock AutoMutex;
 
 // ---------------------------------------------------------------------------
-}; // namespace android
+}  // namespace android
 // ---------------------------------------------------------------------------
 
 #endif // _LIBS_UTILS_MUTEX_H
diff --git a/libutils/include/utils/Printer.h b/libutils/include/utils/Printer.h
index bb66287..a6f6928 100644
--- a/libutils/include/utils/Printer.h
+++ b/libutils/include/utils/Printer.h
@@ -114,6 +114,6 @@
     const char* mPrefix;
 };
 
-}; // namespace android
+}  // namespace android
 
 #endif // ANDROID_PRINTER_H
diff --git a/libutils/include/utils/ProcessCallStack.h b/libutils/include/utils/ProcessCallStack.h
index 32458b8..b5f2edc 100644
--- a/libutils/include/utils/ProcessCallStack.h
+++ b/libutils/include/utils/ProcessCallStack.h
@@ -74,6 +74,6 @@
     struct tm mTimeUpdated;
 };
 
-}; // namespace android
+}  // namespace android
 
 #endif // ANDROID_PROCESS_CALLSTACK_H
diff --git a/libutils/include/utils/RWLock.h b/libutils/include/utils/RWLock.h
index d5b81d3..7d43e69 100644
--- a/libutils/include/utils/RWLock.h
+++ b/libutils/include/utils/RWLock.h
@@ -120,7 +120,7 @@
 #endif // !defined(_WIN32)
 
 // ---------------------------------------------------------------------------
-}; // namespace android
+}  // namespace android
 // ---------------------------------------------------------------------------
 
 #endif // _LIBS_UTILS_RWLOCK_H
diff --git a/libutils/include/utils/RefBase.h b/libutils/include/utils/RefBase.h
index 223b666..e817ee4 100644
--- a/libutils/include/utils/RefBase.h
+++ b/libutils/include/utils/RefBase.h
@@ -683,7 +683,7 @@
     ReferenceMover::move_references(d, s, n);
 }
 
-}; // namespace android
+}  // namespace android
 
 // ---------------------------------------------------------------------------
 
diff --git a/libutils/include/utils/Singleton.h b/libutils/include/utils/Singleton.h
index bc47a5c..2dd5a47 100644
--- a/libutils/include/utils/Singleton.h
+++ b/libutils/include/utils/Singleton.h
@@ -95,7 +95,7 @@
 
 
 // ---------------------------------------------------------------------------
-}; // namespace android
+}  // namespace android
 
 #endif // ANDROID_UTILS_SINGLETON_H
 
diff --git a/libutils/include/utils/SortedVector.h b/libutils/include/utils/SortedVector.h
index 47c1376..394db12 100644
--- a/libutils/include/utils/SortedVector.h
+++ b/libutils/include/utils/SortedVector.h
@@ -288,8 +288,7 @@
     return compare_type( *reinterpret_cast<const TYPE*>(lhs), *reinterpret_cast<const TYPE*>(rhs) );
 }
 
-}; // namespace android
-
+}  // namespace android
 
 // ---------------------------------------------------------------------------
 
diff --git a/libutils/include/utils/StopWatch.h b/libutils/include/utils/StopWatch.h
index 76d78d0..9b14ac8 100644
--- a/libutils/include/utils/StopWatch.h
+++ b/libutils/include/utils/StopWatch.h
@@ -52,9 +52,7 @@
     int             mNumLaps;
 };
 
-
-}; // namespace android
-
+}  // namespace android
 
 // ---------------------------------------------------------------------------
 
diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h
index 5f0ce06..afbc2ed 100644
--- a/libutils/include/utils/String16.h
+++ b/libutils/include/utils/String16.h
@@ -243,7 +243,7 @@
     return mString;
 }
 
-}; // namespace android
+}  // namespace android
 
 // ---------------------------------------------------------------------------
 
diff --git a/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h
index ae6d9c8..9cd278f1 100644
--- a/libutils/include/utils/StrongPointer.h
+++ b/libutils/include/utils/StrongPointer.h
@@ -239,7 +239,7 @@
     m_ptr = ptr;
 }
 
-}; // namespace android
+}  // namespace android
 
 // ---------------------------------------------------------------------------
 
diff --git a/libutils/include/utils/SystemClock.h b/libutils/include/utils/SystemClock.h
index 01db340..f816fba 100644
--- a/libutils/include/utils/SystemClock.h
+++ b/libutils/include/utils/SystemClock.h
@@ -26,7 +26,7 @@
 int64_t elapsedRealtime();
 int64_t elapsedRealtimeNano();
 
-}; // namespace android
+}  // namespace android
 
 #endif // ANDROID_UTILS_SYSTEMCLOCK_H
 
diff --git a/libutils/include/utils/Thread.h b/libutils/include/utils/Thread.h
index 598298d..3525138 100644
--- a/libutils/include/utils/Thread.h
+++ b/libutils/include/utils/Thread.h
@@ -110,8 +110,7 @@
 #endif
 };
 
-
-}; // namespace android
+}  // namespace android
 
 // ---------------------------------------------------------------------------
 #endif // _LIBS_UTILS_THREAD_H
diff --git a/libutils/include/utils/ThreadDefs.h b/libutils/include/utils/ThreadDefs.h
index ae091e4..8eb3d1c 100644
--- a/libutils/include/utils/ThreadDefs.h
+++ b/libutils/include/utils/ThreadDefs.h
@@ -66,9 +66,8 @@
 };
 
 // ---------------------------------------------------------------------------
-}; // namespace android
+}  // namespace android
 #endif  // __cplusplus
 // ---------------------------------------------------------------------------
 
-
 #endif // _LIBS_UTILS_THREAD_DEFS_H
diff --git a/libutils/include/utils/Trace.h b/libutils/include/utils/Trace.h
index 5e9229c..4b9c91e 100644
--- a/libutils/include/utils/Trace.h
+++ b/libutils/include/utils/Trace.h
@@ -49,7 +49,7 @@
     uint64_t mTag;
 };
 
-}; // namespace android
+}  // namespace android
 
 #else // !__ANDROID__
 
diff --git a/libutils/include/utils/TypeHelpers.h b/libutils/include/utils/TypeHelpers.h
index 28fbca5..1554f52 100644
--- a/libutils/include/utils/TypeHelpers.h
+++ b/libutils/include/utils/TypeHelpers.h
@@ -329,7 +329,7 @@
     return hash_type(uintptr_t(value));
 }
 
-}; // namespace android
+}  // namespace android
 
 // ---------------------------------------------------------------------------
 
diff --git a/libutils/include/utils/Vector.h b/libutils/include/utils/Vector.h
index a1a0234..ddf71de 100644
--- a/libutils/include/utils/Vector.h
+++ b/libutils/include/utils/Vector.h
@@ -425,8 +425,7 @@
     move_backward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
 }
 
-}; // namespace android
-
+}  // namespace android
 
 // ---------------------------------------------------------------------------
 
diff --git a/libutils/include/utils/VectorImpl.h b/libutils/include/utils/VectorImpl.h
index 4dd91fd..55d5d98 100644
--- a/libutils/include/utils/VectorImpl.h
+++ b/libutils/include/utils/VectorImpl.h
@@ -175,8 +175,7 @@
             ssize_t         replaceAt(const void* item, size_t index);
 };
 
-}; // namespace android
-
+}  // namespace android
 
 // ---------------------------------------------------------------------------
 
diff --git a/libutils/include/utils/misc.h b/libutils/include/utils/misc.h
index af5ea02..32615b3 100644
--- a/libutils/include/utils/misc.h
+++ b/libutils/include/utils/misc.h
@@ -35,6 +35,6 @@
 void add_sysprop_change_callback(sysprop_change_callback cb, int priority);
 void report_sysprop_change();
 
-}; // namespace android
+}  // namespace android
 
 #endif // _LIBS_UTILS_MISC_H
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 075fb86..6c06618 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -61,6 +61,7 @@
     vndk: {
         enabled: true,
     },
+    double_loadable: true,
 
     defaults: [
         "libziparchive_defaults",
@@ -92,6 +93,10 @@
     host_supported: true,
     defaults: ["libziparchive_flags"],
 
+    data: [
+        "testdata/**/*",
+    ],
+
     srcs: [
         "entry_name_utils_test.cc",
         "zip_archive_test.cc",
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index ff73eb2..23dd5dc 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -34,7 +34,7 @@
 #include <ziparchive/zip_archive.h>
 #include <ziparchive/zip_archive_stream_entry.h>
 
-static std::string test_data_dir;
+static std::string test_data_dir = android::base::GetExecutableDirectory() + "/testdata";
 
 static const std::string kMissingZip = "missing.zip";
 static const std::string kValidZip = "valid.zip";
@@ -778,41 +778,3 @@
     ASSERT_EQ(0u, writer.GetOutput().size());
   }
 }
-
-int main(int argc, char** argv) {
-  ::testing::InitGoogleTest(&argc, argv);
-
-  static struct option options[] = {{"test_data_dir", required_argument, nullptr, 't'},
-                                    {nullptr, 0, nullptr, 0}};
-
-  while (true) {
-    int option_index;
-    const int c = getopt_long_only(argc, argv, "", options, &option_index);
-    if (c == -1) {
-      break;
-    }
-
-    if (c == 't') {
-      test_data_dir = optarg;
-    }
-  }
-
-  if (test_data_dir.size() == 0) {
-    printf("Test data flag (--test_data_dir) required\n\n");
-    return -1;
-  }
-
-  if (test_data_dir[0] != '/') {
-    std::vector<char> cwd_buffer(1024);
-    const char* cwd = getcwd(cwd_buffer.data(), cwd_buffer.size() - 1);
-    if (cwd == nullptr) {
-      printf("Cannot get current working directory, use an absolute path instead, was %s\n\n",
-             test_data_dir.c_str());
-      return -2;
-    }
-    test_data_dir = '/' + test_data_dir;
-    test_data_dir = cwd + test_data_dir;
-  }
-
-  return RUN_ALL_TESTS();
-}
diff --git a/llkd/Android.bp b/llkd/Android.bp
new file mode 100644
index 0000000..a6edd26
--- /dev/null
+++ b/llkd/Android.bp
@@ -0,0 +1,42 @@
+cc_library_headers {
+    name: "llkd_headers",
+
+    export_include_dirs: ["include"],
+}
+
+cc_library_static {
+    name: "libllkd",
+
+    srcs: [
+        "libllkd.cpp",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+    ],
+
+    export_include_dirs: ["include"],
+
+    cflags: ["-Werror"],
+}
+
+cc_binary {
+    name: "llkd",
+
+    srcs: [
+        "llkd.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+    ],
+    static_libs: [
+        "libllkd",
+    ],
+    cflags: ["-Werror"],
+
+    init_rc: ["llkd.rc"],
+}
diff --git a/llkd/OWNERS b/llkd/OWNERS
new file mode 100644
index 0000000..b6af537
--- /dev/null
+++ b/llkd/OWNERS
@@ -0,0 +1,2 @@
+salyzyn@google.com
+surenb@google.com
diff --git a/llkd/README.md b/llkd/README.md
new file mode 100644
index 0000000..b2ba2a2
--- /dev/null
+++ b/llkd/README.md
@@ -0,0 +1,117 @@
+Android Live-LocK Daemon
+========================
+
+Introduction
+------------
+
+Android Live-LocK Daemon (llkd) is used to catch kernel deadlocks and mitigate.
+
+Code is structured to allow integration into another service as either as part
+of the main loop, or spun off as a thread should that be necessary.  A default
+standalone implementation is provided by llkd component.
+
+The 'C' interface from libllkd component is thus:
+
+    #include "llkd.h"
+    bool llkInit(const char* threadname) /* return true if enabled */
+    unsigned llkCheckMillseconds(void)   /* ms to sleep for next check */
+
+If a threadname is provided, a thread will be automatically spawned, otherwise
+caller must call llkCheckMilliseconds in its main loop.  Function will return
+the period of time before the next expected call to this handler.
+
+Operations
+----------
+
+If a thread is in D or Z state with no forward progress for longer than
+ro.llk.timeout_ms, or ro.llk.[D|Z].timeout_ms, kill the process or parent
+process respectively.  If another scan shows the same process continues to
+exist, then have a confirmed live-lock condition and need to panic.  Panic
+the kernel in a manner to provide the greatest bugreporting details as to the
+condition.  Add a alarm self watchdog should llkd ever get locked up that is
+double the expected time to flow through the mainloop.  Sampling is every
+ro.llk_sample_ms.
+
+Default will not monitor init, or [kthreadd] and all that [kthreadd] spawns.
+This reduces the effectiveness of llkd by limiting its coverage.  If there is
+value in covering [kthreadd] spawned threads, the requirement will be that
+the drivers not remain in a persistent 'D' state, or that they have mechanisms
+to recover the thread should it be killed externally (this is good driver
+coding hygiene, a common request to add such to publicly reviewed kernel.org
+maintained drivers).  For instance use wait_event_interruptible() instead of
+wait_event().  The blacklists can be adjusted accordingly if these
+conditions are met to cover kernel components.
+
+An accompanying gTest set have been added, and will setup a persistent D or Z
+process, with and without forward progress, but not in a live-lock state
+because that would require a buggy kernel, or a module or kernel modification
+to stimulate.  The test will check that llkd will mitigate first by killing
+the appropriate process.  D state is setup by vfork() waiting for exec() in
+child process.  Z state is setup by fork() and an un-waited for child process.
+Should be noted that both of these conditions should never happen on Android
+on purpose, and llkd effectively sweeps up processes that create these
+conditions.  If the test can, it will reconfigure llkd to expedite the test
+duration by adjusting the ro.llk.* Android properties.  Tests run the D state
+with some scheduling progress to ensure that ABA checking prevents false
+triggers. If 100% reliable ABA on platform, then ro.llk.killtest can be
+set to false; however this will result in some of the unit tests to panic
+kernel instead of deal with more graceful kill operation.
+
+Android Properties
+------------------
+
+Android Properties llkd respond to (<prop>_ms parms are in milliseconds):
+
+#### ro.config.low_ram
+default false, if true do not sysrq t (dump all threads).
+
+#### ro.llk.enable
+default false, allow live-lock daemon to be enabled.
+
+#### llk.enable
+default ro.llk.enable, and evaluated for eng.
+
+#### ro.khungtask.enable
+default false, allow [khungtask] daemon to be enabled.
+
+#### khungtask.enable
+default ro.khungtask.enable and evaluated for eng.
+
+#### ro.llk.mlockall
+default false, enable call to mlockall().
+
+#### ro.khungtask.timeout
+default value 12 minutes, [khungtask] maximum timelimit.
+
+#### ro.llk.timeout_ms
+default 10 minutes, D or Z maximum timelimit, double this value and it sets
+the alarm watchdog for llkd.
+
+#### ro.llk.D.timeout_ms
+default ro.llk.timeout_ms, D maximum timelimit.
+
+#### ro.llk.Z.timeout_ms
+default ro.llk.timeout_ms, Z maximum timelimit.
+
+#### ro.llk.check_ms
+default 2 minutes samples of threads for D or Z.
+
+#### ro.llk.blacklist.process
+default 0,1,2 (kernel, init and [kthreadd]) plus process names
+init,[kthreadd],[khungtaskd],lmkd,lmkd.llkd,llkd,watchdogd,
+[watchdogd],[watchdogd/0],...,[watchdogd/<get_nprocs-1>].
+
+#### ro.llk.blacklist.parent
+default 0,2 (kernel and [kthreadd]).
+
+#### ro.llk.blacklist.uid
+default <empty>, comma separated list of uid numbers or names.
+
+Architectural Concerns
+----------------------
+
+- Create kernel module and associated gTest to actually test panic.
+- Create gTest to test out blacklist (ro.llk.blacklist.<properties> generally
+  not be inputs).  Could require more test-only interfaces to libllkd.
+- Speed up gTest using something else than ro.llk.<properties>, which should
+  not be inputs.
diff --git a/llkd/include/llkd.h b/llkd/include/llkd.h
new file mode 100644
index 0000000..e3ae4bb
--- /dev/null
+++ b/llkd/include/llkd.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LLKD_H_
+#define _LLKD_H_
+
+#ifndef LOG_TAG
+#define LOG_TAG "livelock"
+#endif
+
+#include <stdbool.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+bool llkInit(const char* threadname); /* threadname NULL, not spawned */
+unsigned llkCheckMilliseconds(void);
+
+/* clang-format off */
+#define LLK_ENABLE_WRITEABLE_PROPERTY  "llk.enable"
+#define LLK_ENABLE_PROPERTY            "ro." LLK_ENABLE_WRITEABLE_PROPERTY
+#define LLK_ENABLE_DEFAULT             false /* "eng" and userdebug true */
+#define KHT_ENABLE_WRITEABLE_PROPERTY  "khungtask.enable"
+#define KHT_ENABLE_PROPERTY            "ro." KHT_ENABLE_WRITEABLE_PROPERTY
+#define LLK_MLOCKALL_PROPERTY          "ro.llk.mlockall"
+#define LLK_MLOCKALL_DEFAULT           true
+#define LLK_KILLTEST_PROPERTY          "ro.llk.killtest"
+#define LLK_KILLTEST_DEFAULT           true
+#define LLK_TIMEOUT_MS_PROPERTY        "ro.llk.timeout_ms"
+#define KHT_TIMEOUT_PROPERTY           "ro.khungtask.timeout"
+#define LLK_D_TIMEOUT_MS_PROPERTY      "ro.llk.D.timeout_ms"
+#define LLK_Z_TIMEOUT_MS_PROPERTY      "ro.llk.Z.timeout_ms"
+#define LLK_CHECK_MS_PROPERTY          "ro.llk.check_ms"
+/* LLK_CHECK_MS_DEFAULT = actual timeout_ms / LLK_CHECKS_PER_TIMEOUT_DEFAULT */
+#define LLK_CHECKS_PER_TIMEOUT_DEFAULT 5
+#define LLK_BLACKLIST_PROCESS_PROPERTY "ro.llk.blacklist.process"
+#define LLK_BLACKLIST_PROCESS_DEFAULT  \
+    "0,1,2,init,[kthreadd],[khungtaskd],lmkd,lmkd.llkd,llkd,watchdogd,[watchdogd],[watchdogd/0]"
+#define LLK_BLACKLIST_PARENT_PROPERTY  "ro.llk.blacklist.parent"
+#define LLK_BLACKLIST_PARENT_DEFAULT   "0,2,[kthreadd]"
+#define LLK_BLACKLIST_UID_PROPERTY     "ro.llk.blacklist.uid"
+#define LLK_BLACKLIST_UID_DEFAULT      ""
+/* clang-format on */
+
+__END_DECLS
+
+#ifdef __cplusplus
+extern "C++" { /* In case this included wrapped with __BEGIN_DECLS */
+
+#include <chrono>
+
+__BEGIN_DECLS
+/* C++ code allowed to not specify threadname argument for this C linkage */
+bool llkInit(const char* threadname = nullptr);
+__END_DECLS
+std::chrono::milliseconds llkCheck(bool checkRunning = false);
+
+/* clang-format off */
+#define LLK_TIMEOUT_MS_DEFAULT  std::chrono::duration_cast<milliseconds>(std::chrono::minutes(10))
+#define LLK_TIMEOUT_MS_MINIMUM  std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::seconds(10))
+#define LLK_CHECK_MS_MINIMUM    std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::seconds(1))
+/* clang-format on */
+
+} /* extern "C++" */
+#endif /* __cplusplus */
+
+#endif /* _LLKD_H_ */
diff --git a/llkd/libllkd.cpp b/llkd/libllkd.cpp
new file mode 100644
index 0000000..f357cc2
--- /dev/null
+++ b/llkd/libllkd.cpp
@@ -0,0 +1,1168 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "llkd.h"
+
+#include <ctype.h>
+#include <dirent.h>  // opendir() and readdir()
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <pwd.h>  // getpwuid()
+#include <signal.h>
+#include <stdint.h>
+#include <sys/cdefs.h>  // ___STRING, __predict_true() and _predict_false()
+#include <sys/mman.h>   // mlockall()
+#include <sys/prctl.h>
+#include <sys/stat.h>     // lstat()
+#include <sys/syscall.h>  // __NR_getdents64
+#include <sys/sysinfo.h>  // get_nprocs_conf()
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <chrono>
+#include <ios>
+#include <sstream>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#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 <cutils/android_get_control_file.h>
+#include <log/log_main.h>
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+
+#define TASK_COMM_LEN 16  // internal kernel, not uapi, from .../linux/include/linux/sched.h
+
+using namespace std::chrono_literals;
+using namespace std::chrono;
+
+namespace {
+
+constexpr pid_t kernelPid = 0;
+constexpr pid_t initPid = 1;
+constexpr pid_t kthreaddPid = 2;
+
+constexpr char procdir[] = "/proc/";
+
+// Configuration
+milliseconds llkUpdate;                              // last check ms signature
+milliseconds llkCycle;                               // ms to next thread check
+bool llkEnable = LLK_ENABLE_DEFAULT;                 // llk daemon enabled
+bool llkRunning = false;                             // thread is running
+bool llkMlockall = LLK_MLOCKALL_DEFAULT;             // run mlocked
+bool llkTestWithKill = LLK_KILLTEST_DEFAULT;         // issue test kills
+milliseconds llkTimeoutMs = LLK_TIMEOUT_MS_DEFAULT;  // default timeout
+enum { llkStateD, llkStateZ, llkNumStates };         // state indexes
+milliseconds llkStateTimeoutMs[llkNumStates];        // timeout override for each detection state
+milliseconds llkCheckMs;                             // checking interval to inspect any
+                                                     // persistent live-locked states
+bool llkLowRam;                                      // ro.config.low_ram
+bool khtEnable = LLK_ENABLE_DEFAULT;                 // [khungtaskd] panic
+// [khungtaskd] should have a timeout beyond the granularity of llkTimeoutMs.
+// Provides a wide angle of margin b/c khtTimeout is also its granularity.
+seconds khtTimeout = duration_cast<seconds>(llkTimeoutMs * (1 + LLK_CHECKS_PER_TIMEOUT_DEFAULT) /
+                                            LLK_CHECKS_PER_TIMEOUT_DEFAULT);
+
+// Blacklist variables, initialized with comma separated lists of high false
+// positive and/or dangerous references, e.g. without self restart, for pid,
+// ppid, name and uid:
+
+// list of pids, or tids or names to skip. kernel pid (0), init pid (1),
+// [kthreadd] pid (2), ourselves, "init", "[kthreadd]", "lmkd", "llkd" or
+// combinations of watchdogd in kernel and user space.
+std::unordered_set<std::string> llkBlacklistProcess;
+// list of parent pids, comm or cmdline names to skip. default:
+// kernel pid (0), [kthreadd] (2), or ourselves, enforced and implied
+std::unordered_set<std::string> llkBlacklistParent;
+// list of uids, and uid names, to skip, default nothing
+std::unordered_set<std::string> llkBlacklistUid;
+
+class dir {
+  public:
+    enum level { proc, task, numLevels };
+
+  private:
+    int fd;
+    size_t available_bytes;
+    dirent* next;
+    // each directory level picked to be just north of 4K in size
+    static constexpr size_t buffEntries = 15;
+    static dirent buff[numLevels][buffEntries];
+
+    bool fill(enum level index) {
+        if (index >= numLevels) return false;
+        if (available_bytes != 0) return true;
+        if (__predict_false(fd < 0)) return false;
+        // getdents64 has no libc wrapper
+        auto rc = TEMP_FAILURE_RETRY(syscall(__NR_getdents64, fd, buff[index], sizeof(buff[0]), 0));
+        if (rc <= 0) return false;
+        available_bytes = rc;
+        next = buff[index];
+        return true;
+    }
+
+  public:
+    dir() : fd(-1), available_bytes(0), next(nullptr) {}
+
+    explicit dir(const char* directory)
+        : fd(__predict_true(directory != nullptr)
+                 ? ::open(directory, O_CLOEXEC | O_DIRECTORY | O_RDONLY)
+                 : -1),
+          available_bytes(0),
+          next(nullptr) {}
+
+    explicit dir(const std::string&& directory)
+        : fd(::open(directory.c_str(), O_CLOEXEC | O_DIRECTORY | O_RDONLY)),
+          available_bytes(0),
+          next(nullptr) {}
+
+    explicit dir(const std::string& directory)
+        : fd(::open(directory.c_str(), O_CLOEXEC | O_DIRECTORY | O_RDONLY)),
+          available_bytes(0),
+          next(nullptr) {}
+
+    // Don't need any copy or move constructors.
+    explicit dir(const dir& c) = delete;
+    explicit dir(dir& c) = delete;
+    explicit dir(dir&& c) = delete;
+
+    ~dir() {
+        if (fd >= 0) {
+            ::close(fd);
+        }
+    }
+
+    operator bool() const { return fd >= 0; }
+
+    void reset(void) {
+        if (fd >= 0) {
+            ::close(fd);
+            fd = -1;
+            available_bytes = 0;
+            next = nullptr;
+        }
+    }
+
+    dir& reset(const char* directory) {
+        reset();
+        // available_bytes will _always_ be zero here as its value is
+        // intimately tied to fd < 0 or not.
+        fd = ::open(directory, O_CLOEXEC | O_DIRECTORY | O_RDONLY);
+        return *this;
+    }
+
+    void rewind(void) {
+        if (fd >= 0) {
+            ::lseek(fd, off_t(0), SEEK_SET);
+            available_bytes = 0;
+            next = nullptr;
+        }
+    }
+
+    dirent* read(enum level index = proc, dirent* def = nullptr) {
+        if (!fill(index)) return def;
+        auto ret = next;
+        available_bytes -= next->d_reclen;
+        next = reinterpret_cast<dirent*>(reinterpret_cast<char*>(next) + next->d_reclen);
+        return ret;
+    }
+} llkTopDirectory;
+
+dirent dir::buff[dir::numLevels][dir::buffEntries];
+
+// helper functions
+
+bool llkIsMissingExeLink(pid_t tid) {
+    char c;
+    // CAP_SYS_PTRACE is required to prevent ret == -1, but ENOENT is signal
+    auto ret = ::readlink((procdir + std::to_string(tid) + "/exe").c_str(), &c, sizeof(c));
+    return (ret == -1) && (errno == ENOENT);
+}
+
+// Common routine where caller accepts empty content as error/passthrough.
+// Reduces the churn of reporting read errors in the callers.
+std::string ReadFile(std::string&& path) {
+    std::string content;
+    if (!android::base::ReadFileToString(path, &content)) {
+        PLOG(DEBUG) << "Read " << path << " failed";
+        content = "";
+    }
+    return content;
+}
+
+std::string llkProcGetName(pid_t tid, const char* node = "/cmdline") {
+    std::string content = ReadFile(procdir + std::to_string(tid) + node);
+    static constexpr char needles[] = " \t\r\n";  // including trailing nul
+    auto pos = content.find_first_of(needles, 0, sizeof(needles));
+    if (pos != std::string::npos) {
+        content.erase(pos);
+    }
+    return content;
+}
+
+uid_t llkProcGetUid(pid_t tid) {
+    // Get the process' uid.  The following read from /status is admittedly
+    // racy, prone to corruption due to shape-changes.  The consequences are
+    // not catastrophic as we sample a few times before taking action.
+    //
+    // If /loginuid worked on reliably, or on Android (all tasks report -1)...
+    // Android lmkd causes /cgroup to contain memory:/<dom>/uid_<uid>/pid_<pid>
+    // which is tighter, but also not reliable.
+    std::string content = ReadFile(procdir + std::to_string(tid) + "/status");
+    static constexpr char Uid[] = "\nUid:";
+    auto pos = content.find(Uid);
+    if (pos == std::string::npos) {
+        return -1;
+    }
+    pos += ::strlen(Uid);
+    while ((pos < content.size()) && ::isblank(content[pos])) {
+        ++pos;
+    }
+    content.erase(0, pos);
+    for (pos = 0; (pos < content.size()) && ::isdigit(content[pos]); ++pos) {
+        ;
+    }
+    // Content of form 'Uid:	0	0	0	0', newline is error
+    if ((pos >= content.size()) || !::isblank(content[pos])) {
+        return -1;
+    }
+    content.erase(pos);
+    uid_t ret;
+    if (!android::base::ParseInt(content, &ret, uid_t(0))) {
+        return -1;
+    }
+    return ret;
+}
+
+struct proc {
+    pid_t tid;                     // monitored thread id (in Z or D state).
+    nanoseconds schedUpdate;       // /proc/<tid>/sched "se.avg.lastUpdateTime",
+    uint64_t nrSwitches;           // /proc/<tid>/sched "nr_switches" for
+                                   // refined ABA problem detection, determine
+                                   // forward scheduling progress.
+    milliseconds update;           // llkUpdate millisecond signature of last.
+    milliseconds count;            // duration in state.
+    pid_t pid;                     // /proc/<pid> before iterating through
+                                   // /proc/<pid>/task/<tid> for threads.
+    pid_t ppid;                    // /proc/<tid>/stat field 4 parent pid.
+    uid_t uid;                     // /proc/<tid>/status Uid: field.
+    unsigned time;                 // sum of /proc/<tid>/stat field 14 utime &
+                                   // 15 stime for coarse ABA problem detection.
+    std::string cmdline;           // cached /cmdline content
+    char state;                    // /proc/<tid>/stat field 3: Z or D
+                                   // (others we do not monitor: S, R, T or ?)
+    char comm[TASK_COMM_LEN + 3];  // space for adding '[' and ']'
+    bool exeMissingValid;          // exeMissing has been cached
+    bool cmdlineValid;             // cmdline has been cached
+    bool updated;                  // cleared before monitoring pass.
+    bool killed;                   // sent a kill to this thread, next panic...
+
+    void setComm(const char* _comm) { strncpy(comm + 1, _comm, sizeof(comm) - 2); }
+
+    proc(pid_t tid, pid_t pid, pid_t ppid, const char* _comm, int time, char state)
+        : tid(tid),
+          schedUpdate(0),
+          nrSwitches(0),
+          update(llkUpdate),
+          count(0),
+          pid(pid),
+          ppid(ppid),
+          uid(-1),
+          time(time),
+          state(state),
+          exeMissingValid(false),
+          cmdlineValid(false),
+          updated(true),
+          killed(!llkTestWithKill) {
+        memset(comm, '\0', sizeof(comm));
+        setComm(_comm);
+    }
+
+    const char* getComm(void) {
+        if (comm[1] == '\0') {  // comm Valid?
+            strncpy(comm + 1, llkProcGetName(tid, "/comm").c_str(), sizeof(comm) - 2);
+        }
+        if (!exeMissingValid) {
+            if (llkIsMissingExeLink(tid)) {
+                comm[0] = '[';
+            }
+            exeMissingValid = true;
+        }
+        size_t len = strlen(comm + 1);
+        if (__predict_true(len < (sizeof(comm) - 1))) {
+            if (comm[0] == '[') {
+                if ((comm[len] != ']') && __predict_true(len < (sizeof(comm) - 2))) {
+                    comm[++len] = ']';
+                    comm[++len] = '\0';
+                }
+            } else {
+                if (comm[len] == ']') {
+                    comm[len] = '\0';
+                }
+            }
+        }
+        return &comm[comm[0] != '['];
+    }
+
+    const char* getCmdline(void) {
+        if (!cmdlineValid) {
+            cmdline = llkProcGetName(tid);
+            cmdlineValid = true;
+        }
+        return cmdline.c_str();
+    }
+
+    uid_t getUid(void) {
+        if (uid <= 0) {  // Churn on root user, because most likely to setuid()
+            uid = llkProcGetUid(tid);
+        }
+        return uid;
+    }
+
+    void reset(void) {  // reset cache, if we detected pid rollover
+        uid = -1;
+        state = '?';
+        cmdline = "";
+        comm[0] = '\0';
+        exeMissingValid = false;
+        cmdlineValid = false;
+    }
+};
+
+std::unordered_map<pid_t, proc> tids;
+
+// Check range and setup defaults, in order of propagation:
+//     llkTimeoutMs
+//     llkCheckMs
+//     ...
+// KISS to keep it all self-contained, and called multiple times as parameters
+// are interpreted so that defaults, llkCheckMs and llkCycle make sense.
+void llkValidate() {
+    if (llkTimeoutMs == 0ms) {
+        llkTimeoutMs = LLK_TIMEOUT_MS_DEFAULT;
+    }
+    llkTimeoutMs = std::max(llkTimeoutMs, LLK_TIMEOUT_MS_MINIMUM);
+    if (llkCheckMs == 0ms) {
+        llkCheckMs = llkTimeoutMs / LLK_CHECKS_PER_TIMEOUT_DEFAULT;
+    }
+    llkCheckMs = std::min(llkCheckMs, llkTimeoutMs);
+
+    for (size_t state = 0; state < ARRAY_SIZE(llkStateTimeoutMs); ++state) {
+        if (llkStateTimeoutMs[state] == 0ms) {
+            llkStateTimeoutMs[state] = llkTimeoutMs;
+        }
+        llkStateTimeoutMs[state] =
+            std::min(std::max(llkStateTimeoutMs[state], LLK_TIMEOUT_MS_MINIMUM), llkTimeoutMs);
+        llkCheckMs = std::min(llkCheckMs, llkStateTimeoutMs[state]);
+    }
+
+    llkCheckMs = std::max(llkCheckMs, LLK_CHECK_MS_MINIMUM);
+    if (llkCycle == 0ms) {
+        llkCycle = llkCheckMs;
+    }
+    llkCycle = std::min(llkCycle, llkCheckMs);
+}
+
+milliseconds llkGetTimespecDiffMs(timespec* from, timespec* to) {
+    return duration_cast<milliseconds>(seconds(to->tv_sec - from->tv_sec)) +
+           duration_cast<milliseconds>(nanoseconds(to->tv_nsec - from->tv_nsec));
+}
+
+std::string llkProcGetName(pid_t tid, const char* comm, const char* cmdline) {
+    if ((cmdline != nullptr) && (*cmdline != '\0')) {
+        return cmdline;
+    }
+    if ((comm != nullptr) && (*comm != '\0')) {
+        return comm;
+    }
+
+    // UNLIKELY! Here because killed before we kill it?
+    // Assume change is afoot, do not call llkTidAlloc
+
+    // cmdline ?
+    std::string content = llkProcGetName(tid);
+    if (content.size() != 0) {
+        return content;
+    }
+    // Comm instead?
+    content = llkProcGetName(tid, "/comm");
+    if (llkIsMissingExeLink(tid) && (content.size() != 0)) {
+        return '[' + content + ']';
+    }
+    return content;
+}
+
+int llkKillOneProcess(pid_t pid, char state, pid_t tid, const char* tcomm = nullptr,
+                      const char* tcmdline = nullptr, const char* pcomm = nullptr,
+                      const char* pcmdline = nullptr) {
+    std::string forTid;
+    if (tid != pid) {
+        forTid = " for '" + llkProcGetName(tid, tcomm, tcmdline) + "' (" + std::to_string(tid) + ")";
+    }
+    LOG(INFO) << "Killing '" << llkProcGetName(pid, pcomm, pcmdline) << "' (" << pid
+              << ") to check forward scheduling progress in " << state << " state" << forTid;
+    // CAP_KILL required
+    errno = 0;
+    auto r = ::kill(pid, SIGKILL);
+    if (r) {
+        PLOG(ERROR) << "kill(" << pid << ")=" << r << ' ';
+    }
+
+    return r;
+}
+
+// Kill one process
+int llkKillOneProcess(pid_t pid, proc* tprocp) {
+    return llkKillOneProcess(pid, tprocp->state, tprocp->tid, tprocp->getComm(),
+                             tprocp->getCmdline());
+}
+
+// Kill one process specified by kprocp
+int llkKillOneProcess(proc* kprocp, proc* tprocp) {
+    if (kprocp == nullptr) {
+        return -2;
+    }
+
+    return llkKillOneProcess(kprocp->tid, tprocp->state, tprocp->tid, tprocp->getComm(),
+                             tprocp->getCmdline(), kprocp->getComm(), kprocp->getCmdline());
+}
+
+// Acquire file descriptor from environment, or open and cache it.
+// NB: cache is unnecessary in our current context, pedantically
+//     required to prevent leakage of file descriptors in the future.
+int llkFileToWriteFd(const std::string& file) {
+    static std::unordered_map<std::string, int> cache;
+    auto search = cache.find(file);
+    if (search != cache.end()) return search->second;
+    auto fd = android_get_control_file(file.c_str());
+    if (fd >= 0) return fd;
+    fd = TEMP_FAILURE_RETRY(::open(file.c_str(), O_WRONLY | O_CLOEXEC));
+    if (fd >= 0) cache.emplace(std::make_pair(file, fd));
+    return fd;
+}
+
+// Wrap android::base::WriteStringToFile to use android_get_control_file.
+bool llkWriteStringToFile(const std::string& string, const std::string& file) {
+    auto fd = llkFileToWriteFd(file);
+    if (fd < 0) return false;
+    return android::base::WriteStringToFd(string, fd);
+}
+
+bool llkWriteStringToFileConfirm(const std::string& string, const std::string& file) {
+    auto fd = llkFileToWriteFd(file);
+    auto ret = (fd < 0) ? false : android::base::WriteStringToFd(string, fd);
+    std::string content;
+    if (!android::base::ReadFileToString(file, &content)) return ret;
+    return android::base::Trim(content) == string;
+}
+
+void llkPanicKernel(bool dump, pid_t tid, const char* state) __noreturn;
+void llkPanicKernel(bool dump, pid_t tid, const char* state) {
+    auto sysrqTriggerFd = llkFileToWriteFd("/proc/sysrq-trigger");
+    if (sysrqTriggerFd < 0) {
+        // DYB
+        llkKillOneProcess(initPid, 'R', tid);
+        // The answer to life, the universe and everything
+        ::exit(42);
+        // NOTREACHED
+    }
+    ::sync();
+    if (dump) {
+        // Show all locks that are held
+        android::base::WriteStringToFd("d", sysrqTriggerFd);
+        // This can trigger hardware watchdog, that is somewhat _ok_.
+        // But useless if pstore configured for <256KB, low ram devices ...
+        if (!llkLowRam) {
+            android::base::WriteStringToFd("t", sysrqTriggerFd);
+        }
+        ::usleep(200000);  // let everything settle
+    }
+    llkWriteStringToFile(std::string("SysRq : Trigger a crash : 'livelock,") + state + "'\n",
+                         "/dev/kmsg");
+    android::base::WriteStringToFd("c", sysrqTriggerFd);
+    // NOTREACHED
+    // DYB
+    llkKillOneProcess(initPid, 'R', tid);
+    // I sat at my desk, stared into the garden and thought '42 will do'.
+    // I typed it out. End of story
+    ::exit(42);
+    // NOTREACHED
+}
+
+void llkAlarmHandler(int) {
+    llkPanicKernel(false, ::getpid(), "alarm");
+}
+
+milliseconds GetUintProperty(const std::string& key, milliseconds def) {
+    return milliseconds(android::base::GetUintProperty(key, static_cast<uint64_t>(def.count()),
+                                                       static_cast<uint64_t>(def.max().count())));
+}
+
+seconds GetUintProperty(const std::string& key, seconds def) {
+    return seconds(android::base::GetUintProperty(key, static_cast<uint64_t>(def.count()),
+                                                  static_cast<uint64_t>(def.max().count())));
+}
+
+proc* llkTidLookup(pid_t tid) {
+    auto search = tids.find(tid);
+    if (search == tids.end()) {
+        return nullptr;
+    }
+    return &search->second;
+}
+
+void llkTidRemove(pid_t tid) {
+    tids.erase(tid);
+}
+
+proc* llkTidAlloc(pid_t tid, pid_t pid, pid_t ppid, const char* comm, int time, char state) {
+    auto it = tids.emplace(std::make_pair(tid, proc(tid, pid, ppid, comm, time, state)));
+    return &it.first->second;
+}
+
+std::string llkFormat(milliseconds ms) {
+    auto sec = duration_cast<seconds>(ms);
+    std::ostringstream s;
+    s << sec.count() << '.';
+    auto f = s.fill('0');
+    auto w = s.width(3);
+    s << std::right << (ms - sec).count();
+    s.width(w);
+    s.fill(f);
+    s << 's';
+    return s.str();
+}
+
+std::string llkFormat(seconds s) {
+    return std::to_string(s.count()) + 's';
+}
+
+std::string llkFormat(bool flag) {
+    return flag ? "true" : "false";
+}
+
+std::string llkFormat(const std::unordered_set<std::string>& blacklist) {
+    std::string ret;
+    for (auto entry : blacklist) {
+        if (ret.size()) {
+            ret += ",";
+        }
+        ret += entry;
+    }
+    return ret;
+}
+
+// We only officially support comma separators, but wetware being what they
+// are will take some liberty and I do not believe they should be punished.
+std::unordered_set<std::string> llkSplit(const std::string& s,
+                                         const std::string& delimiters = ", \t:") {
+    std::unordered_set<std::string> result;
+
+    size_t base = 0;
+    size_t found;
+    while (true) {
+        found = s.find_first_of(delimiters, base);
+        result.emplace(s.substr(base, found - base));
+        if (found == s.npos) break;
+        base = found + 1;
+    }
+    return result;
+}
+
+bool llkSkipName(const std::string& name,
+                 const std::unordered_set<std::string>& blacklist = llkBlacklistProcess) {
+    if ((name.size() == 0) || (blacklist.size() == 0)) {
+        return false;
+    }
+
+    return blacklist.find(name) != blacklist.end();
+}
+
+bool llkSkipPid(pid_t pid) {
+    return llkSkipName(std::to_string(pid), llkBlacklistProcess);
+}
+
+bool llkSkipPpid(pid_t ppid) {
+    return llkSkipName(std::to_string(ppid), llkBlacklistParent);
+}
+
+bool llkSkipUid(uid_t uid) {
+    // Match by number?
+    if (llkSkipName(std::to_string(uid), llkBlacklistUid)) {
+        return true;
+    }
+
+    // Match by name?
+    auto pwd = ::getpwuid(uid);
+    return (pwd != nullptr) && __predict_true(pwd->pw_name != nullptr) &&
+           __predict_true(pwd->pw_name[0] != '\0') && llkSkipName(pwd->pw_name, llkBlacklistUid);
+}
+
+bool getValidTidDir(dirent* dp, std::string* piddir) {
+    if (!::isdigit(dp->d_name[0])) {
+        return false;
+    }
+
+    // Corner case can not happen in reality b/c of above ::isdigit check
+    if (__predict_false(dp->d_type != DT_DIR)) {
+        if (__predict_false(dp->d_type == DT_UNKNOWN)) {  // can't b/c procfs
+            struct stat st;
+            *piddir = procdir;
+            *piddir += dp->d_name;
+            return (lstat(piddir->c_str(), &st) == 0) && (st.st_mode & S_IFDIR);
+        }
+        return false;
+    }
+
+    *piddir = procdir;
+    *piddir += dp->d_name;
+    return true;
+}
+
+bool llkIsMonitorState(char state) {
+    return (state == 'Z') || (state == 'D');
+}
+
+// returns -1 if not found
+long long getSchedValue(const std::string& schedString, const char* key) {
+    auto pos = schedString.find(key);
+    if (pos == std::string::npos) {
+        return -1;
+    }
+    pos = schedString.find(':', pos);
+    if (__predict_false(pos == std::string::npos)) {
+        return -1;
+    }
+    while ((++pos < schedString.size()) && ::isblank(schedString[pos])) {
+        ;
+    }
+    long long ret;
+    if (!android::base::ParseInt(schedString.substr(pos), &ret, static_cast<long long>(0))) {
+        return -1;
+    }
+    return ret;
+}
+
+// Primary ABA mitigation watching last time schedule activity happened
+void llkCheckSchedUpdate(proc* procp, const std::string& piddir) {
+    // Audit finds /proc/<tid>/sched is just over 1K, and
+    // is rarely larger than 2K, even less on Android.
+    // For example, the "se.avg.lastUpdateTime" field we are
+    // interested in typically within the primary set in
+    // the first 1K.
+    //
+    // Proc entries can not be read >1K atomically via libbase,
+    // but if there are problems we assume at least a few
+    // samples of reads occur before we take any real action.
+    std::string schedString = ReadFile(piddir + "/sched");
+    if (schedString.size() == 0) {
+        // /schedstat is not as standardized, but in 3.1+
+        // Android devices, the third field is nr_switches
+        // from /sched:
+        schedString = ReadFile(piddir + "/schedstat");
+        if (schedString.size() == 0) {
+            return;
+        }
+        auto val = static_cast<unsigned long long>(-1);
+        if (((::sscanf(schedString.c_str(), "%*d %*d %llu", &val)) == 1) &&
+            (val != static_cast<unsigned long long>(-1)) && (val != 0) &&
+            (val != procp->nrSwitches)) {
+            procp->nrSwitches = val;
+            procp->count = 0ms;
+            procp->killed = !llkTestWithKill;
+        }
+        return;
+    }
+
+    auto val = getSchedValue(schedString, "\nse.avg.lastUpdateTime");
+    if (val == -1) {
+        val = getSchedValue(schedString, "\nse.svg.last_update_time");
+    }
+    if (val != -1) {
+        auto schedUpdate = nanoseconds(val);
+        if (schedUpdate != procp->schedUpdate) {
+            procp->schedUpdate = schedUpdate;
+            procp->count = 0ms;
+            procp->killed = !llkTestWithKill;
+        }
+    }
+
+    val = getSchedValue(schedString, "\nnr_switches");
+    if (val != -1) {
+        if (static_cast<uint64_t>(val) != procp->nrSwitches) {
+            procp->nrSwitches = val;
+            procp->count = 0ms;
+            procp->killed = !llkTestWithKill;
+        }
+    }
+}
+
+void llkLogConfig(void) {
+    LOG(INFO) << "ro.config.low_ram=" << llkFormat(llkLowRam) << "\n"
+              << LLK_ENABLE_PROPERTY "=" << llkFormat(llkEnable) << "\n"
+              << KHT_ENABLE_PROPERTY "=" << llkFormat(khtEnable) << "\n"
+              << LLK_MLOCKALL_PROPERTY "=" << llkFormat(llkMlockall) << "\n"
+              << LLK_KILLTEST_PROPERTY "=" << llkFormat(llkTestWithKill) << "\n"
+              << KHT_TIMEOUT_PROPERTY "=" << llkFormat(khtTimeout) << "\n"
+              << LLK_TIMEOUT_MS_PROPERTY "=" << llkFormat(llkTimeoutMs) << "\n"
+              << LLK_D_TIMEOUT_MS_PROPERTY "=" << llkFormat(llkStateTimeoutMs[llkStateD]) << "\n"
+              << LLK_Z_TIMEOUT_MS_PROPERTY "=" << llkFormat(llkStateTimeoutMs[llkStateZ]) << "\n"
+              << LLK_CHECK_MS_PROPERTY "=" << llkFormat(llkCheckMs) << "\n"
+              << LLK_BLACKLIST_PROCESS_PROPERTY "=" << llkFormat(llkBlacklistProcess) << "\n"
+              << LLK_BLACKLIST_PARENT_PROPERTY "=" << llkFormat(llkBlacklistParent) << "\n"
+              << LLK_BLACKLIST_UID_PROPERTY "=" << llkFormat(llkBlacklistUid);
+}
+
+void* llkThread(void* obj) {
+    LOG(INFO) << "started";
+
+    std::string name = std::to_string(::gettid());
+    if (!llkSkipName(name)) {
+        llkBlacklistProcess.emplace(name);
+    }
+    name = static_cast<const char*>(obj);
+    prctl(PR_SET_NAME, name.c_str());
+    if (__predict_false(!llkSkipName(name))) {
+        llkBlacklistProcess.insert(name);
+    }
+    // No longer modifying llkBlacklistProcess.
+    llkRunning = true;
+    llkLogConfig();
+    while (llkRunning) {
+        ::usleep(duration_cast<microseconds>(llkCheck(true)).count());
+    }
+    // NOTREACHED
+    LOG(INFO) << "exiting";
+    return nullptr;
+}
+
+}  // namespace
+
+milliseconds llkCheck(bool checkRunning) {
+    if (!llkEnable || (checkRunning != llkRunning)) {
+        return milliseconds::max();
+    }
+
+    // Reset internal watchdog, which is a healthy engineering margin of
+    // double the maximum wait or cycle time for the mainloop that calls us.
+    //
+    // This alarm is effectively the live lock detection of llkd, as
+    // we understandably can not monitor ourselves otherwise.
+    ::alarm(duration_cast<seconds>(llkTimeoutMs * 2).count());
+
+    // kernel jiffy precision fastest acquisition
+    static timespec last;
+    timespec now;
+    ::clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
+    auto ms = llkGetTimespecDiffMs(&last, &now);
+    if (ms < llkCycle) {
+        return llkCycle - ms;
+    }
+    last = now;
+
+    LOG(VERBOSE) << "opendir(\"" << procdir << "\")";
+    if (__predict_false(!llkTopDirectory)) {
+        // gid containing AID_READPROC required
+        llkTopDirectory.reset(procdir);
+        if (__predict_false(!llkTopDirectory)) {
+            // Most likely reason we could be here is a resource limit.
+            // Keep our processing down to a minimum, but not so low that
+            // we do not recover in a timely manner should the issue be
+            // transitory.
+            LOG(DEBUG) << "opendir(\"" << procdir << "\") failed";
+            return llkTimeoutMs;
+        }
+    }
+
+    for (auto& it : tids) {
+        it.second.updated = false;
+    }
+
+    auto prevUpdate = llkUpdate;
+    llkUpdate += ms;
+    ms -= llkCycle;
+    auto myPid = ::getpid();
+    auto myTid = ::gettid();
+    for (auto dp = llkTopDirectory.read(); dp != nullptr; dp = llkTopDirectory.read()) {
+        std::string piddir;
+
+        if (!getValidTidDir(dp, &piddir)) {
+            continue;
+        }
+
+        // Get the process tasks
+        std::string taskdir = piddir + "/task/";
+        int pid = -1;
+        LOG(VERBOSE) << "+opendir(\"" << taskdir << "\")";
+        dir taskDirectory(taskdir);
+        if (__predict_false(!taskDirectory)) {
+            LOG(DEBUG) << "+opendir(\"" << taskdir << "\") failed";
+        }
+        for (auto tp = taskDirectory.read(dir::task, dp); tp != nullptr;
+             tp = taskDirectory.read(dir::task)) {
+            if (!getValidTidDir(tp, &piddir)) {
+                continue;
+            }
+
+            // Get the process stat
+            std::string stat = ReadFile(piddir + "/stat");
+            if (stat.size() == 0) {
+                continue;
+            }
+            unsigned tid = -1;
+            char pdir[TASK_COMM_LEN + 1];
+            char state = '?';
+            unsigned ppid = -1;
+            unsigned utime = -1;
+            unsigned stime = -1;
+            int dummy;
+            pdir[0] = '\0';
+            // tid should not change value
+            auto match = ::sscanf(
+                stat.c_str(),
+                "%u (%" ___STRING(
+                    TASK_COMM_LEN) "[^)]) %c %u %*d %*d %*d %*d %*d %*d %*d %*d %*d %u %u %d",
+                &tid, pdir, &state, &ppid, &utime, &stime, &dummy);
+            if (pid == -1) {
+                pid = tid;
+            }
+            LOG(VERBOSE) << "match " << match << ' ' << tid << " (" << pdir << ") " << state << ' '
+                         << ppid << " ... " << utime << ' ' << stime << ' ' << dummy;
+            if (match != 7) {
+                continue;
+            }
+
+            auto procp = llkTidLookup(tid);
+            if (procp == nullptr) {
+                procp = llkTidAlloc(tid, pid, ppid, pdir, utime + stime, state);
+            } else {
+                // comm can change ...
+                procp->setComm(pdir);
+                procp->updated = true;
+                // pid/ppid/tid wrap?
+                if (((procp->update != prevUpdate) && (procp->update != llkUpdate)) ||
+                    (procp->ppid != ppid) || (procp->pid != pid)) {
+                    procp->reset();
+                } else if (procp->time != (utime + stime)) {  // secondary ABA.
+                    // watching utime+stime granularity jiffy
+                    procp->state = '?';
+                }
+                procp->update = llkUpdate;
+                procp->pid = pid;
+                procp->ppid = ppid;
+                procp->time = utime + stime;
+                if (procp->state != state) {
+                    procp->count = 0ms;
+                    procp->killed = !llkTestWithKill;
+                    procp->state = state;
+                } else {
+                    procp->count += llkCycle;
+                }
+            }
+
+            // Filter checks in intuitive order of CPU cost to evaluate
+            // If tid unique continue, if ppid or pid unique break
+
+            if (pid == myPid) {
+                break;
+            }
+            if (!llkIsMonitorState(state)) {
+                continue;
+            }
+            if ((tid == myTid) || llkSkipPid(tid)) {
+                continue;
+            }
+            if (llkSkipPpid(ppid)) {
+                break;
+            }
+
+            if (llkSkipName(procp->getComm())) {
+                continue;
+            }
+            if (llkSkipName(procp->getCmdline())) {
+                break;
+            }
+
+            auto pprocp = llkTidLookup(ppid);
+            if (pprocp == nullptr) {
+                pprocp = llkTidAlloc(ppid, ppid, 0, "", 0, '?');
+            }
+            if ((pprocp != nullptr) && (llkSkipName(pprocp->getComm(), llkBlacklistParent) ||
+                                        llkSkipName(pprocp->getCmdline(), llkBlacklistParent))) {
+                break;
+            }
+
+            if ((llkBlacklistUid.size() != 0) && llkSkipUid(procp->getUid())) {
+                continue;
+            }
+
+            // ABA mitigation watching last time schedule activity happened
+            llkCheckSchedUpdate(procp, piddir);
+
+            // Can only fall through to here if registered D or Z state !!!
+            if (procp->count < llkStateTimeoutMs[(state == 'Z') ? llkStateZ : llkStateD]) {
+                LOG(VERBOSE) << state << ' ' << llkFormat(procp->count) << ' ' << ppid << "->"
+                             << pid << "->" << tid << ' ' << procp->getComm();
+                continue;
+            }
+
+            // We have to kill it to determine difference between live lock
+            // and persistent state blocked on a resource.  Is there something
+            // wrong with a process that has no forward scheduling progress in
+            // Z or D?  Yes, generally means improper accounting in the
+            // process, but not always ...
+            //
+            // Whomever we hit with a test kill must accept the Android
+            // Aphorism that everything can be burned to the ground and
+            // must survive.
+            if (procp->killed == false) {
+                procp->killed = true;
+                // confirm: re-read uid before committing to a panic.
+                procp->uid = -1;
+                switch (state) {
+                    case 'Z':  // kill ppid to free up a Zombie
+                        // Killing init will kernel panic without diagnostics
+                        // so skip right to controlled kernel panic with
+                        // diagnostics.
+                        if (ppid == initPid) {
+                            break;
+                        }
+                        LOG(WARNING) << "Z " << llkFormat(procp->count) << ' ' << ppid << "->"
+                                     << pid << "->" << tid << ' ' << procp->getComm() << " [kill]";
+                        if ((llkKillOneProcess(pprocp, procp) >= 0) ||
+                            (llkKillOneProcess(ppid, procp) >= 0)) {
+                            continue;
+                        }
+                        break;
+
+                    case 'D':  // kill tid to free up an uninterruptible D
+                        // If ABA is doing its job, we would not need or
+                        // want the following.  Test kill is a Hail Mary
+                        // to make absolutely sure there is no forward
+                        // scheduling progress.  The cost when ABA is
+                        // not working is we kill a process that likes to
+                        // stay in 'D' state, instead of panicing the
+                        // kernel (worse).
+                        LOG(WARNING) << "D " << llkFormat(procp->count) << ' ' << pid << "->" << tid
+                                     << ' ' << procp->getComm() << " [kill]";
+                        if ((llkKillOneProcess(llkTidLookup(pid), procp) >= 0) ||
+                            (llkKillOneProcess(pid, 'D', tid) >= 0) ||
+                            (llkKillOneProcess(procp, procp) >= 0) ||
+                            (llkKillOneProcess(tid, 'D', tid) >= 0)) {
+                            continue;
+                        }
+                        break;
+                }
+            }
+            // We are here because we have confirmed kernel live-lock
+            LOG(ERROR) << state << ' ' << llkFormat(procp->count) << ' ' << ppid << "->" << pid
+                       << "->" << tid << ' ' << procp->getComm() << " [panic]";
+            llkPanicKernel(true, tid, (state == 'Z') ? "zombie" : "driver");
+        }
+        LOG(VERBOSE) << "+closedir()";
+    }
+    llkTopDirectory.rewind();
+    LOG(VERBOSE) << "closedir()";
+
+    // garbage collection of old process references
+    for (auto p = tids.begin(); p != tids.end();) {
+        if (!p->second.updated) {
+            IF_ALOG(LOG_VERBOSE, LOG_TAG) {
+                std::string ppidCmdline = llkProcGetName(p->second.ppid, nullptr, nullptr);
+                if (ppidCmdline.size()) {
+                    ppidCmdline = "(" + ppidCmdline + ")";
+                }
+                std::string pidCmdline;
+                if (p->second.pid != p->second.tid) {
+                    pidCmdline = llkProcGetName(p->second.pid, nullptr, p->second.getCmdline());
+                    if (pidCmdline.size()) {
+                        pidCmdline = "(" + pidCmdline + ")";
+                    }
+                }
+                std::string tidCmdline =
+                    llkProcGetName(p->second.tid, p->second.getComm(), p->second.getCmdline());
+                if (tidCmdline.size()) {
+                    tidCmdline = "(" + tidCmdline + ")";
+                }
+                LOG(VERBOSE) << "thread " << p->second.ppid << ppidCmdline << "->" << p->second.pid
+                             << pidCmdline << "->" << p->second.tid << tidCmdline << " removed";
+            }
+            p = tids.erase(p);
+        } else {
+            ++p;
+        }
+    }
+    if (__predict_false(tids.empty())) {
+        llkTopDirectory.reset();
+    }
+
+    llkCycle = llkCheckMs;
+
+    timespec end;
+    ::clock_gettime(CLOCK_MONOTONIC_COARSE, &end);
+    auto milli = llkGetTimespecDiffMs(&now, &end);
+    LOG((milli > 10s) ? ERROR : (milli > 1s) ? WARNING : VERBOSE) << "sample " << llkFormat(milli);
+
+    // cap to minimum sleep for 1 second since last cycle
+    if (llkCycle < (ms + 1s)) {
+        return 1s;
+    }
+    return llkCycle - ms;
+}
+
+unsigned llkCheckMilliseconds() {
+    return duration_cast<milliseconds>(llkCheck()).count();
+}
+
+bool llkInit(const char* threadname) {
+    llkLowRam = android::base::GetBoolProperty("ro.config.low_ram", false);
+    if (!LLK_ENABLE_DEFAULT && android::base::GetBoolProperty("ro.debuggable", false)) {
+        llkEnable = android::base::GetProperty(LLK_ENABLE_PROPERTY, "eng") == "eng";
+        khtEnable = android::base::GetProperty(KHT_ENABLE_PROPERTY, "eng") == "eng";
+    }
+    llkEnable = android::base::GetBoolProperty(LLK_ENABLE_PROPERTY, llkEnable);
+    if (llkEnable && !llkTopDirectory.reset(procdir)) {
+        // Most likely reason we could be here is llkd was started
+        // incorrectly without the readproc permissions.  Keep our
+        // processing down to a minimum.
+        llkEnable = false;
+    }
+    khtEnable = android::base::GetBoolProperty(KHT_ENABLE_PROPERTY, khtEnable);
+    llkMlockall = android::base::GetBoolProperty(LLK_MLOCKALL_PROPERTY, llkMlockall);
+    llkTestWithKill = android::base::GetBoolProperty(LLK_KILLTEST_PROPERTY, llkTestWithKill);
+    // if LLK_TIMOUT_MS_PROPERTY was not set, we will use a set
+    // KHT_TIMEOUT_PROPERTY as co-operative guidance for the default value.
+    khtTimeout = GetUintProperty(KHT_TIMEOUT_PROPERTY, khtTimeout);
+    if (khtTimeout == 0s) {
+        khtTimeout = duration_cast<seconds>(llkTimeoutMs * (1 + LLK_CHECKS_PER_TIMEOUT_DEFAULT) /
+                                            LLK_CHECKS_PER_TIMEOUT_DEFAULT);
+    }
+    llkTimeoutMs =
+        khtTimeout * LLK_CHECKS_PER_TIMEOUT_DEFAULT / (1 + LLK_CHECKS_PER_TIMEOUT_DEFAULT);
+    llkTimeoutMs = GetUintProperty(LLK_TIMEOUT_MS_PROPERTY, llkTimeoutMs);
+    llkValidate();  // validate llkTimeoutMs, llkCheckMs and llkCycle
+    llkStateTimeoutMs[llkStateD] = GetUintProperty(LLK_D_TIMEOUT_MS_PROPERTY, llkTimeoutMs);
+    llkStateTimeoutMs[llkStateZ] = GetUintProperty(LLK_Z_TIMEOUT_MS_PROPERTY, llkTimeoutMs);
+    llkCheckMs = GetUintProperty(LLK_CHECK_MS_PROPERTY, llkCheckMs);
+    llkValidate();  // validate all (effectively minus llkTimeoutMs)
+    std::string defaultBlacklistProcess(
+        std::to_string(kernelPid) + "," + std::to_string(initPid) + "," +
+        std::to_string(kthreaddPid) + "," + std::to_string(::getpid()) + "," +
+        std::to_string(::gettid()) + "," LLK_BLACKLIST_PROCESS_DEFAULT);
+    if (threadname) {
+        defaultBlacklistProcess += std::string(",") + threadname;
+    }
+    for (int cpu = 1; cpu < get_nprocs_conf(); ++cpu) {
+        defaultBlacklistProcess += ",[watchdog/" + std::to_string(cpu) + "]";
+    }
+    defaultBlacklistProcess =
+        android::base::GetProperty(LLK_BLACKLIST_PROCESS_PROPERTY, defaultBlacklistProcess);
+    llkBlacklistProcess = llkSplit(defaultBlacklistProcess);
+    if (!llkSkipName("[khungtaskd]")) {  // ALWAYS ignore as special
+        llkBlacklistProcess.emplace("[khungtaskd]");
+    }
+    llkBlacklistParent = llkSplit(android::base::GetProperty(
+        LLK_BLACKLIST_PARENT_PROPERTY, std::to_string(kernelPid) + "," + std::to_string(kthreaddPid) +
+                                           "," LLK_BLACKLIST_PARENT_DEFAULT));
+    llkBlacklistUid =
+        llkSplit(android::base::GetProperty(LLK_BLACKLIST_UID_PROPERTY, LLK_BLACKLIST_UID_DEFAULT));
+
+    // internal watchdog
+    ::signal(SIGALRM, llkAlarmHandler);
+
+    // kernel hung task configuration? Otherwise leave it as-is
+    if (khtEnable) {
+        // EUID must be AID_ROOT to write to /proc/sys/kernel/ nodes, there
+        // are no capability overrides.  For security reasons we do not want
+        // to run as AID_ROOT.  We may not be able to write them successfully,
+        // we will try, but the least we can do is read the values back to
+        // confirm expectations and report whether configured or not.
+        auto configured = llkWriteStringToFileConfirm(std::to_string(khtTimeout.count()),
+                                                      "/proc/sys/kernel/hung_task_timeout_secs");
+        if (configured) {
+            llkWriteStringToFile("65535", "/proc/sys/kernel/hung_task_warnings");
+            llkWriteStringToFile("65535", "/proc/sys/kernel/hung_task_check_count");
+            configured = llkWriteStringToFileConfirm("1", "/proc/sys/kernel/hung_task_panic");
+        }
+        if (configured) {
+            LOG(INFO) << "[khungtaskd] configured";
+        } else {
+            LOG(WARNING) << "[khungtaskd] not configurable";
+        }
+    }
+
+    bool logConfig = true;
+    if (llkEnable) {
+        if (llkMlockall &&
+            // MCL_ONFAULT pins pages as they fault instead of loading
+            // everything immediately all at once. (Which would be bad,
+            // because as of this writing, we have a lot of mapped pages we
+            // never use.) Old kernels will see MCL_ONFAULT and fail with
+            // EINVAL; we ignore this failure.
+            //
+            // N.B. read the man page for mlockall. MCL_CURRENT | MCL_ONFAULT
+            // pins ⊆ MCL_CURRENT, converging to just MCL_CURRENT as we fault
+            // in pages.
+
+            // CAP_IPC_LOCK required
+            mlockall(MCL_CURRENT | MCL_FUTURE | MCL_ONFAULT) && (errno != EINVAL)) {
+            PLOG(WARNING) << "mlockall failed ";
+        }
+
+        if (threadname) {
+            pthread_attr_t attr;
+
+            if (!pthread_attr_init(&attr)) {
+                sched_param param;
+
+                memset(&param, 0, sizeof(param));
+                pthread_attr_setschedparam(&attr, &param);
+                pthread_attr_setschedpolicy(&attr, SCHED_BATCH);
+                if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
+                    pthread_t thread;
+                    if (!pthread_create(&thread, &attr, llkThread, const_cast<char*>(threadname))) {
+                        // wait a second for thread to start
+                        for (auto retry = 50; retry && !llkRunning; --retry) {
+                            ::usleep(20000);
+                        }
+                        logConfig = !llkRunning;  // printed in llkd context?
+                    } else {
+                        LOG(ERROR) << "failed to spawn llkd thread";
+                    }
+                } else {
+                    LOG(ERROR) << "failed to detach llkd thread";
+                }
+                pthread_attr_destroy(&attr);
+            } else {
+                LOG(ERROR) << "failed to allocate attibutes for llkd thread";
+            }
+        }
+    } else {
+        LOG(DEBUG) << "[khungtaskd] left unconfigured";
+    }
+    if (logConfig) {
+        llkLogConfig();
+    }
+
+    return llkEnable;
+}
diff --git a/llkd/llkd.cpp b/llkd/llkd.cpp
new file mode 100644
index 0000000..f10253d
--- /dev/null
+++ b/llkd/llkd.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "llkd.h"
+
+#include <sched.h>
+#include <unistd.h>
+
+#include <chrono>
+
+#include <android-base/logging.h>
+
+using namespace std::chrono;
+
+int main(int, char**) {
+    LOG(INFO) << "started";
+
+    bool enabled = llkInit();
+
+    // Would like this policy to be automatic as part of libllkd,
+    // but that would be presumptuous and bad side-effect.
+    struct sched_param param;
+    memset(&param, 0, sizeof(param));
+    sched_setscheduler(0, SCHED_BATCH, &param);
+
+    while (true) {
+        if (enabled) {
+            ::usleep(duration_cast<microseconds>(llkCheck()).count());
+        } else {
+            ::pause();
+        }
+    }
+    // NOTREACHED
+
+    LOG(INFO) << "exiting";
+    return 0;
+}
diff --git a/llkd/llkd.rc b/llkd/llkd.rc
new file mode 100644
index 0000000..e538cdb
--- /dev/null
+++ b/llkd/llkd.rc
@@ -0,0 +1,49 @@
+# eng default for ro.llk.enable and ro.khungtask.enable
+on property:ro.debuggable=*
+    setprop llk.enable ${ro.llk.enable:-0}
+    setprop khungtask.enable ${ro.khungtask.enable:-0}
+
+on property:ro.debuggable=1
+    setprop llk.enable ${ro.llk.enable:-1}
+    setprop khungtask.enable ${ro.khungtask.enable:-1}
+
+on property:ro.llk.enable=eng
+    setprop llk.enable ${ro.debuggable:-0}
+
+on property:ro.khungtask.enable=eng
+    setprop khungtask.enable ${ro.debuggable:-0}
+
+on property:llk.enable=1
+    setprop llk.enable true
+
+on property:llk.enable=0
+    setprop llk.enable false
+
+on property:khungtask.enable=1
+    setprop khungtask.enable true
+
+on property:khungtask.enable=0
+    setprop khungtask.enable false
+
+# Configure [khungtaskd]
+on property:khungtask.enable=true
+    write /proc/sys/kernel/hung_task_timeout_secs ${ro.khungtask.timeout:-720}
+    write /proc/sys/kernel/hung_task_warnings 65535
+    write /proc/sys/kernel/hung_task_check_count 65535
+    write /proc/sys/kernel/hung_task_panic 1
+
+on property:khungtask.enable=false
+    write /proc/sys/kernel/hung_task_panic 0
+
+on property:llk.enable=true
+    start llkd
+
+service llkd /system/bin/llkd
+    class late_start
+    disabled
+    user llkd
+    group llkd readproc
+    capabilities KILL IPC_LOCK
+    file /dev/kmsg w
+    file /proc/sysrq-trigger w
+    writepid /dev/cpuset/system-background/tasks
diff --git a/llkd/tests/Android.bp b/llkd/tests/Android.bp
new file mode 100644
index 0000000..6dd5938
--- /dev/null
+++ b/llkd/tests/Android.bp
@@ -0,0 +1,41 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "llkd_unit_test",
+
+    shared_libs: [
+        "libbase",
+        "liblog",
+    ],
+    header_libs: [
+        "llkd_headers",
+    ],
+
+    target: {
+        android: {
+            srcs: [
+                "llkd_test.cpp",
+            ],
+        },
+    },
+
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+
+    compile_multilib: "first",
+}
diff --git a/llkd/tests/llkd_test.cpp b/llkd/tests/llkd_test.cpp
new file mode 100644
index 0000000..3a15ff1
--- /dev/null
+++ b/llkd/tests/llkd_test.cpp
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <signal.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <chrono>
+#include <iostream>
+#include <string>
+
+#include <android-base/properties.h>
+#include <gtest/gtest.h>
+#include <log/log_time.h>  // for MS_PER_SEC and US_PER_SEC
+
+#include "llkd.h"
+
+using namespace std::chrono;
+using namespace std::chrono_literals;
+
+namespace {
+
+milliseconds GetUintProperty(const std::string& key, milliseconds def) {
+    return milliseconds(android::base::GetUintProperty(key, static_cast<uint64_t>(def.count()),
+                                                       static_cast<uint64_t>(def.max().count())));
+}
+
+seconds GetUintProperty(const std::string& key, seconds def) {
+    return seconds(android::base::GetUintProperty(key, static_cast<uint64_t>(def.count()),
+                                                  static_cast<uint64_t>(def.max().count())));
+}
+
+// GTEST_LOG_(WARNING) output is fugly, this has much less noise
+// ToDo: look into fixing googletest to produce output that matches style of
+//       all the other status messages, and can switch off __line__ and
+//       __function__ noise
+#define GTEST_LOG_WARNING std::cerr << "[ WARNING  ] "
+#define GTEST_LOG_INFO std::cerr << "[   INFO   ] "
+
+// Properties is _not_ a high performance ABI!
+void rest() {
+    usleep(200000);
+}
+
+void execute(const char* command) {
+    if (getuid() || system(command)) {
+        system((std::string("su root ") + command).c_str());
+    }
+}
+
+seconds llkdSleepPeriod(char state) {
+    auto default_eng = android::base::GetProperty(LLK_ENABLE_PROPERTY, "eng") == "eng";
+    auto default_enable = LLK_ENABLE_DEFAULT;
+    if (!LLK_ENABLE_DEFAULT && default_eng &&
+        android::base::GetBoolProperty("ro.debuggable", false)) {
+        default_enable = true;
+    }
+    default_enable = android::base::GetBoolProperty(LLK_ENABLE_PROPERTY, default_enable);
+    if (default_eng) {
+        GTEST_LOG_INFO << LLK_ENABLE_PROPERTY " defaults to \"eng\" thus "
+                       << (default_enable ? "true" : "false") << "\n";
+    }
+    // Hail Mary hope is unconfigured.
+    if ((GetUintProperty(LLK_TIMEOUT_MS_PROPERTY, LLK_TIMEOUT_MS_DEFAULT) !=
+         duration_cast<milliseconds>(120s)) ||
+        (GetUintProperty(LLK_CHECK_MS_PROPERTY,
+                         LLK_TIMEOUT_MS_DEFAULT / LLK_CHECKS_PER_TIMEOUT_DEFAULT) !=
+         duration_cast<milliseconds>(10s))) {
+        execute("stop llkd");
+        rest();
+        std::string setprop("setprop ");
+        execute((setprop + LLK_ENABLE_WRITEABLE_PROPERTY + " false").c_str());
+        rest();
+        execute((setprop + LLK_TIMEOUT_MS_PROPERTY + " 120000").c_str());
+        rest();
+        execute((setprop + KHT_TIMEOUT_PROPERTY + " 130").c_str());
+        rest();
+        execute((setprop + LLK_CHECK_MS_PROPERTY + " 10000").c_str());
+        rest();
+        execute((setprop + LLK_ENABLE_PROPERTY + " true").c_str());
+        rest();
+        execute((setprop + LLK_ENABLE_WRITEABLE_PROPERTY + " true").c_str());
+        rest();
+    }
+    default_enable = LLK_ENABLE_DEFAULT;
+    if (!LLK_ENABLE_DEFAULT && (android::base::GetProperty(LLK_ENABLE_PROPERTY, "eng") == "eng") &&
+        android::base::GetBoolProperty("ro.debuggable", false)) {
+        default_enable = true;
+    }
+    default_enable = android::base::GetBoolProperty(LLK_ENABLE_PROPERTY, default_enable);
+    if (default_enable) {
+        execute("start llkd");
+        rest();
+        GTEST_LOG_INFO << "llkd enabled\n";
+    } else {
+        GTEST_LOG_WARNING << "llkd disabled\n";
+    }
+
+    /* KISS follows llk_init() */
+    milliseconds llkTimeoutMs = LLK_TIMEOUT_MS_DEFAULT;
+    seconds khtTimeout = duration_cast<seconds>(
+        llkTimeoutMs * (1 + LLK_CHECKS_PER_TIMEOUT_DEFAULT) / LLK_CHECKS_PER_TIMEOUT_DEFAULT);
+    khtTimeout = GetUintProperty(KHT_TIMEOUT_PROPERTY, khtTimeout);
+    llkTimeoutMs =
+        khtTimeout * LLK_CHECKS_PER_TIMEOUT_DEFAULT / (1 + LLK_CHECKS_PER_TIMEOUT_DEFAULT);
+    llkTimeoutMs = GetUintProperty(LLK_TIMEOUT_MS_PROPERTY, llkTimeoutMs);
+    if (llkTimeoutMs < LLK_TIMEOUT_MS_MINIMUM) {
+        llkTimeoutMs = LLK_TIMEOUT_MS_MINIMUM;
+    }
+    milliseconds llkCheckMs = llkTimeoutMs / LLK_CHECKS_PER_TIMEOUT_DEFAULT;
+    auto timeout = GetUintProperty(
+        (state == 'Z') ? LLK_Z_TIMEOUT_MS_PROPERTY : LLK_D_TIMEOUT_MS_PROPERTY, llkTimeoutMs);
+    if (timeout < LLK_TIMEOUT_MS_MINIMUM) {
+        timeout = LLK_TIMEOUT_MS_MINIMUM;
+    }
+
+    if (llkCheckMs > timeout) {
+        llkCheckMs = timeout;
+    }
+    llkCheckMs = GetUintProperty(LLK_CHECK_MS_PROPERTY, llkCheckMs);
+    timeout += llkCheckMs;
+    auto sec = duration_cast<seconds>(timeout);
+    if (sec == 0s) {
+        ++sec;
+    } else if (sec > 59s) {
+        GTEST_LOG_WARNING << "llkd is configured for about " << duration_cast<minutes>(sec).count()
+                          << " minutes to react\n";
+    }
+
+    // 33% margin for the test to naturally timeout waiting for llkd to respond
+    return (sec * 4 + 2s) / 3;
+}
+
+inline void waitForPid(pid_t child_pid) {
+    int wstatus;
+    ASSERT_LE(0, waitpid(child_pid, &wstatus, 0));
+    EXPECT_FALSE(WIFEXITED(wstatus)) << "[   INFO   ] exit=" << WEXITSTATUS(wstatus);
+    ASSERT_TRUE(WIFSIGNALED(wstatus));
+    ASSERT_EQ(WTERMSIG(wstatus), SIGKILL);
+}
+
+bool checkKill(const char* reason) {
+    if (android::base::GetBoolProperty(LLK_KILLTEST_PROPERTY, LLK_KILLTEST_DEFAULT)) {
+        return false;
+    }
+    auto bootreason = android::base::GetProperty("sys.boot.reason", "nothing");
+    if (bootreason == reason) {
+        GTEST_LOG_INFO << "Expected test result confirmed " << reason << "\n";
+        return true;
+    }
+    GTEST_LOG_WARNING << "Expected test result is " << reason << "\n";
+
+    // apct adjustment if needed (set LLK_KILLTEST_PROPERTY to "off" to allow test)
+    //
+    // if (android::base::GetProperty(LLK_KILLTEST_PROPERTY, "") == "false") {
+    //     GTEST_LOG_WARNING << "Bypassing test\n";
+    //     return true;
+    // }
+
+    return false;
+}
+
+}  // namespace
+
+// The tests that use this helper are to simulate processes stuck in 'D'
+// state that are experiencing forward scheduled progress. As such the
+// expectation is that llkd will _not_ perform any mitigations. The sleepfor
+// argument helps us set the amount of forward scheduler progress.
+static void llkd_driver_ABA(const microseconds sleepfor) {
+    const auto period = llkdSleepPeriod('D');
+    if (period <= sleepfor) {
+        GTEST_LOG_WARNING << "llkd configuration too short for "
+                          << duration_cast<milliseconds>(sleepfor).count() << "ms work cycle\n";
+        return;
+    }
+
+    auto child_pid = fork();
+    ASSERT_LE(0, child_pid);
+    int wstatus;
+    if (!child_pid) {
+        auto ratio = period / sleepfor;
+        ASSERT_LT(0, ratio);
+        // vfork() parent is uninterruptable D state waiting for child to exec()
+        while (--ratio > 0) {
+            auto driver_pid = vfork();
+            ASSERT_LE(0, driver_pid);
+            if (driver_pid) {  // parent
+                waitpid(driver_pid, &wstatus, 0);
+                if (!WIFEXITED(wstatus)) {
+                    exit(42);
+                }
+                if (WEXITSTATUS(wstatus) != 42) {
+                    exit(42);
+                }
+            } else {
+                usleep(sleepfor.count());
+                exit(42);
+            }
+        }
+        exit(0);
+    }
+    ASSERT_LE(0, waitpid(child_pid, &wstatus, 0));
+    EXPECT_TRUE(WIFEXITED(wstatus));
+    if (WIFEXITED(wstatus)) {
+        EXPECT_EQ(0, WEXITSTATUS(wstatus));
+    }
+    ASSERT_FALSE(WIFSIGNALED(wstatus)) << "[   INFO   ] signo=" << WTERMSIG(wstatus);
+}
+
+TEST(llkd, driver_ABA_fast) {
+    llkd_driver_ABA(5ms);
+}
+
+TEST(llkd, driver_ABA_slow) {
+    llkd_driver_ABA(1s);
+}
+
+TEST(llkd, driver_ABA_glacial) {
+    llkd_driver_ABA(1min);
+}
+
+// Following tests must be last in this file to capture possible errant
+// kernel_panic mitigation failure.
+
+// The following tests simulate processes stick in 'Z' or 'D' state with
+// no forward scheduling progress, but interruptible. As such the expectation
+// is that llkd will perform kill mitigation and not progress to kernel_panic.
+
+TEST(llkd, zombie) {
+    if (checkKill("kernel_panic,sysrq,livelock,zombie")) {
+        return;
+    }
+
+    const auto period = llkdSleepPeriod('Z');
+
+    /* Create a Persistent Zombie Process */
+    pid_t child_pid = fork();
+    ASSERT_LE(0, child_pid);
+    if (!child_pid) {
+        auto zombie_pid = fork();
+        ASSERT_LE(0, zombie_pid);
+        if (!zombie_pid) {
+            sleep(1);
+            exit(0);
+        }
+        sleep(period.count());
+        exit(42);
+    }
+
+    waitForPid(child_pid);
+}
+
+TEST(llkd, driver) {
+    if (checkKill("kernel_panic,sysrq,livelock,driver")) {
+        return;
+    }
+
+    const auto period = llkdSleepPeriod('D');
+
+    /* Create a Persistent Device Process */
+    auto child_pid = fork();
+    ASSERT_LE(0, child_pid);
+    if (!child_pid) {
+        // vfork() parent is uninterruptable D state waiting for child to exec()
+        auto driver_pid = vfork();
+        ASSERT_LE(0, driver_pid);
+        sleep(period.count());
+        exit(driver_pid ? 42 : 0);
+    }
+
+    waitForPid(child_pid);
+}
diff --git a/lmkd/Android.bp b/lmkd/Android.bp
index 0474ff5..1369b8b 100644
--- a/lmkd/Android.bp
+++ b/lmkd/Android.bp
@@ -3,8 +3,8 @@
 
     srcs: ["lmkd.c"],
     shared_libs: [
-        "liblog",
         "libcutils",
+        "liblog",
     ],
     static_libs: [
         "libstatslogc",
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 76344b9..c8416f9 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -18,8 +18,10 @@
 
 #include <errno.h>
 #include <inttypes.h>
+#include <pwd.h>
 #include <sched.h>
 #include <signal.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/cdefs.h>
@@ -27,8 +29,8 @@
 #include <sys/eventfd.h>
 #include <sys/mman.h>
 #include <sys/socket.h>
-#include <sys/types.h>
 #include <sys/sysinfo.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #include <cutils/properties.h>
@@ -70,17 +72,18 @@
 #define MEMINFO_PATH "/proc/meminfo"
 #define LINE_MAX 128
 
+/* gid containing AID_SYSTEM required */
 #define INKERNEL_MINFREE_PATH "/sys/module/lowmemorykiller/parameters/minfree"
 #define INKERNEL_ADJ_PATH "/sys/module/lowmemorykiller/parameters/adj"
 
 #define ARRAY_SIZE(x)   (sizeof(x) / sizeof(*(x)))
 #define EIGHT_MEGA (1 << 23)
 
-#define STRINGIFY(x) STRINGIFY_INTERNAL(x)
-#define STRINGIFY_INTERNAL(x) #x
+/* Defined as ProcessList.SYSTEM_ADJ in ProcessList.java */
+#define SYSTEM_ADJ (-900)
 
 /* default to old in-kernel interface if no memory pressure events */
-static int use_inkernel_interface = 1;
+static bool use_inkernel_interface = true;
 static bool has_inkernel_module;
 
 /* memory pressure levels */
@@ -417,24 +420,32 @@
     return 0;
 }
 
-static void writefilestring(const char *path, char *s) {
+/*
+ * Write a string to a file.
+ * Returns false if the file does not exist.
+ */
+static bool writefilestring(const char *path, const char *s,
+                            bool err_if_missing) {
     int fd = open(path, O_WRONLY | O_CLOEXEC);
-    int len = strlen(s);
-    int ret;
+    ssize_t len = strlen(s);
+    ssize_t ret;
 
     if (fd < 0) {
-        ALOGE("Error opening %s; errno=%d", path, errno);
-        return;
+        if (err_if_missing) {
+            ALOGE("Error opening %s; errno=%d", path, errno);
+        }
+        return false;
     }
 
-    ret = write(fd, s, len);
+    ret = TEMP_FAILURE_RETRY(write(fd, s, len));
     if (ret < 0) {
         ALOGE("Error writing %s; errno=%d", path, errno);
     } else if (ret < len) {
-        ALOGE("Short write on %s; length=%d", path, ret);
+        ALOGE("Short write on %s; length=%zd", path, ret);
     }
 
     close(fd);
+    return true;
 }
 
 static void cmd_procprio(LMKD_CTRL_PACKET packet) {
@@ -443,6 +454,8 @@
     char val[20];
     int soft_limit_mult;
     struct lmk_procprio params;
+    bool is_system_server;
+    struct passwd *pwdrec;
 
     lmkd_pack_get_procprio(packet, &params);
 
@@ -452,12 +465,21 @@
         return;
     }
 
+    /* gid containing AID_READPROC required */
+    /* CAP_SYS_RESOURCE required */
+    /* CAP_DAC_OVERRIDE required */
     snprintf(path, sizeof(path), "/proc/%d/oom_score_adj", params.pid);
     snprintf(val, sizeof(val), "%d", params.oomadj);
-    writefilestring(path, val);
-
-    if (use_inkernel_interface)
+    if (!writefilestring(path, val, false)) {
+        ALOGW("Failed to open %s; errno=%d: process %d might have been killed",
+              path, errno, params.pid);
+        /* If this file does not exist the process is dead. */
         return;
+    }
+
+    if (use_inkernel_interface) {
+        return;
+    }
 
     if (params.oomadj >= 900) {
         soft_limit_mult = 0;
@@ -487,11 +509,18 @@
         soft_limit_mult = 64;
     }
 
-    snprintf(path, sizeof(path),
-             "/dev/memcg/apps/uid_%d/pid_%d/memory.soft_limit_in_bytes",
+    snprintf(path, sizeof(path), MEMCG_SYSFS_PATH "apps/uid_%d/pid_%d/memory.soft_limit_in_bytes",
              params.uid, params.pid);
     snprintf(val, sizeof(val), "%d", soft_limit_mult * EIGHT_MEGA);
-    writefilestring(path, val);
+
+    /*
+     * system_server process has no memcg under /dev/memcg/apps but should be
+     * registered with lmkd. This is the best way so far to identify it.
+     */
+    is_system_server = (params.oomadj == SYSTEM_ADJ &&
+                        (pwdrec = getpwnam("system")) != NULL &&
+                        params.uid == pwdrec->pw_uid);
+    writefilestring(path, val, !is_system_server);
 
     procp = pid_lookup(params.pid);
     if (!procp) {
@@ -515,8 +544,9 @@
 static void cmd_procremove(LMKD_CTRL_PACKET packet) {
     struct lmk_procremove params;
 
-    if (use_inkernel_interface)
+    if (use_inkernel_interface) {
         return;
+    }
 
     lmkd_pack_get_procremove(packet, &params);
     pid_remove(params.pid);
@@ -558,8 +588,8 @@
             strlcat(killpriostr, val, sizeof(killpriostr));
         }
 
-        writefilestring(INKERNEL_MINFREE_PATH, minfreestr);
-        writefilestring(INKERNEL_ADJ_PATH, killpriostr);
+        writefilestring(INKERNEL_MINFREE_PATH, minfreestr, true);
+        writefilestring(INKERNEL_ADJ_PATH, killpriostr, true);
     }
 }
 
@@ -696,10 +726,10 @@
 
 #ifdef LMKD_LOG_STATS
 static void memory_stat_parse_line(char *line, struct memory_stat *mem_st) {
-    char key[LINE_MAX + 1];
+    char key[LINE_MAX];
     int64_t value;
 
-    sscanf(line, "%" STRINGIFY(LINE_MAX) "s  %" SCNd64 "", key, &value);
+    sscanf(line,"%s  %" SCNd64 "", key, &value);
 
     if (strcmp(key, "total_") < 0) {
         return;
@@ -886,6 +916,7 @@
     int total;
     ssize_t ret;
 
+    /* gid containing AID_READPROC required */
     snprintf(path, PATH_MAX, "/proc/%d/statm", pid);
     fd = open(path, O_RDONLY | O_CLOEXEC);
     if (fd == -1)
@@ -909,6 +940,7 @@
     char *cp;
     ssize_t ret;
 
+    /* gid containing AID_READPROC required */
     snprintf(path, PATH_MAX, "/proc/%d/cmdline", pid);
     fd = open(path, O_RDONLY | O_CLOEXEC);
     if (fd == -1)
@@ -987,10 +1019,11 @@
 
     TRACE_KILL_START(pid);
 
+    /* CAP_KILL required */
     r = kill(pid, SIGKILL);
     ALOGI(
         "Killing '%s' (%d), uid %d, adj %d\n"
-        "   to free %ldkB because system is under %s memory pressure oom_adj %d\n",
+        "   to free %ldkB because system is under %s memory pressure (min_oom_adj=%d)\n",
         taskname, pid, uid, procp->oomadj, tasksize * page_k,
         level_name[level], min_score_adj);
     pid_remove(pid);
@@ -1336,6 +1369,7 @@
     int level_idx = (int)level;
     const char *levelstr = level_name[level_idx];
 
+    /* gid containing AID_SYSTEM required */
     mpfd = open(MEMCG_SYSFS_PATH "memory.pressure_level", O_RDONLY | O_CLOEXEC);
     if (mpfd < 0) {
         ALOGI("No kernel memory.pressure_level support (errno=%d)", errno);
@@ -1538,21 +1572,32 @@
     statslog_init(&log_ctx, &enable_stats_log);
 #endif
 
-    // MCL_ONFAULT pins pages as they fault instead of loading
-    // everything immediately all at once. (Which would be bad,
-    // because as of this writing, we have a lot of mapped pages we
-    // never use.) Old kernels will see MCL_ONFAULT and fail with
-    // EINVAL; we ignore this failure.
-    //
-    // N.B. read the man page for mlockall. MCL_CURRENT | MCL_ONFAULT
-    // pins ⊆ MCL_CURRENT, converging to just MCL_CURRENT as we fault
-    // in pages.
-    if (mlockall(MCL_CURRENT | MCL_FUTURE | MCL_ONFAULT) && errno != EINVAL)
-        ALOGW("mlockall failed: errno=%d", errno);
+    if (!init()) {
+        if (!use_inkernel_interface) {
+            /*
+             * MCL_ONFAULT pins pages as they fault instead of loading
+             * everything immediately all at once. (Which would be bad,
+             * because as of this writing, we have a lot of mapped pages we
+             * never use.) Old kernels will see MCL_ONFAULT and fail with
+             * EINVAL; we ignore this failure.
+             *
+             * N.B. read the man page for mlockall. MCL_CURRENT | MCL_ONFAULT
+             * pins ⊆ MCL_CURRENT, converging to just MCL_CURRENT as we fault
+             * in pages.
+             */
+            /* CAP_IPC_LOCK required */
+            if (mlockall(MCL_CURRENT | MCL_FUTURE | MCL_ONFAULT) && (errno != EINVAL)) {
+                ALOGW("mlockall failed %s", strerror(errno));
+            }
 
-    sched_setscheduler(0, SCHED_FIFO, &param);
-    if (!init())
+            /* CAP_NICE required */
+            if (sched_setscheduler(0, SCHED_FIFO, &param)) {
+                ALOGW("set SCHED_FIFO failed %s", strerror(errno));
+            }
+        }
+
         mainloop();
+    }
 
 #ifdef LMKD_LOG_STATS
     statslog_destroy(&log_ctx);
diff --git a/lmkd/lmkd.rc b/lmkd/lmkd.rc
index 3bb84ab..76b6055 100644
--- a/lmkd/lmkd.rc
+++ b/lmkd/lmkd.rc
@@ -1,6 +1,8 @@
 service lmkd /system/bin/lmkd
     class core
-    group root readproc
+    user lmkd
+    group lmkd system readproc
+    capabilities DAC_OVERRIDE KILL IPC_LOCK SYS_NICE SYS_RESOURCE
     critical
     socket lmkd seqpacket 0660 system system
     writepid /dev/cpuset/system-background/tasks
diff --git a/lmkd/tests/lmkd_test.cpp b/lmkd/tests/lmkd_test.cpp
index 4afaeb8..1996bae 100644
--- a/lmkd/tests/lmkd_test.cpp
+++ b/lmkd/tests/lmkd_test.cpp
@@ -215,6 +215,13 @@
     pid_t pid;
     uid_t uid = getuid();
 
+    // check if in-kernel LMK driver is present
+    if (!access(INKERNEL_MINFREE_PATH, W_OK)) {
+        GTEST_LOG_(INFO) << "Must not have kernel lowmemorykiller driver,"
+                         << " terminating test";
+        return;
+    }
+
     ASSERT_FALSE((sock = lmkd_connect()) < 0)
         << "Failed to connect to lmkd process, err=" << strerror(errno);
 
@@ -287,12 +294,6 @@
         GTEST_LOG_(INFO) << "Must be userdebug build, terminating test";
         return;
     }
-    // check if in-kernel LMK driver is present
-    if (!access(INKERNEL_MINFREE_PATH, W_OK)) {
-        GTEST_LOG_(INFO) << "Must not have kernel lowmemorykiller driver,"
-                         << " terminating test";
-        return;
-    }
 
     // if respawned test process then run the test and exit (no analysis)
     if (getenv(LMKDTEST_RESPAWN_FLAG) != NULL) {
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 269db2f..27cd9a8 100755
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -112,7 +112,7 @@
 std::map<std::string, std::string> LogAudit::populateDenialMap() {
     std::ifstream bug_file("/system/etc/selinux/selinux_denial_metadata");
     std::string line;
-    // allocate a map for the static map pointer in logParse to keep track of,
+    // allocate a map for the static map pointer in auditParse to keep track of,
     // this function only runs once
     std::map<std::string, std::string> denial_to_bug;
     if (bug_file.good()) {
@@ -140,7 +140,8 @@
     return "";
 }
 
-void LogAudit::logParse(const std::string& string, std::string* bug_num) {
+void LogAudit::auditParse(const std::string& string, uid_t uid,
+                          std::string* bug_num) {
     if (!__android_log_is_debuggable()) {
         bug_num->assign("");
         return;
@@ -162,6 +163,11 @@
     } else {
         bug_num->assign("");
     }
+
+    if (uid >= AID_APP_START && uid <= AID_APP_END) {
+        bug_num->append(" app=");
+        bug_num->append(android::uidToName(uid));
+    }
 }
 
 int LogAudit::logPrint(const char* fmt, ...) {
@@ -190,8 +196,27 @@
     while ((cp = strstr(str, "  "))) {
         memmove(cp, cp + 1, strlen(cp + 1) + 1);
     }
+    pid_t pid = getpid();
+    pid_t tid = gettid();
+    uid_t uid = AID_LOGD;
+    static const char pid_str[] = " pid=";
+    char* pidptr = strstr(str, pid_str);
+    if (pidptr && isdigit(pidptr[sizeof(pid_str) - 1])) {
+        cp = pidptr + sizeof(pid_str) - 1;
+        pid = 0;
+        while (isdigit(*cp)) {
+            pid = (pid * 10) + (*cp - '0');
+            ++cp;
+        }
+        tid = pid;
+        logbuf->wrlock();
+        uid = logbuf->pidToUid(pid);
+        logbuf->unlock();
+        memmove(pidptr, cp, strlen(cp) + 1);
+    }
+
     bool info = strstr(str, " permissive=1") || strstr(str, " policy loaded ");
-    static std::string bug_metadata;
+    static std::string denial_metadata;
     if ((fdDmesg >= 0) && initialized) {
         struct iovec iov[4];
         static const char log_info[] = { KMSG_PRIORITY(LOG_INFO) };
@@ -228,8 +253,8 @@
                     last_info ? sizeof(log_info) : sizeof(log_warning);
                 iov[1].iov_base = last_str;
                 iov[1].iov_len = strlen(last_str);
-                iov[2].iov_base = const_cast<char*>(bug_metadata.c_str());
-                iov[2].iov_len = bug_metadata.length();
+                iov[2].iov_base = const_cast<char*>(denial_metadata.c_str());
+                iov[2].iov_len = denial_metadata.length();
                 if (count > 1) {
                     iov[3].iov_base = const_cast<char*>(resume);
                     iov[3].iov_len = strlen(resume);
@@ -249,14 +274,14 @@
             last_info = info;
         }
         if (count == 0) {
-            logParse(str, &bug_metadata);
+            auditParse(str, uid, &denial_metadata);
             iov[0].iov_base = info ? const_cast<char*>(log_info)
                                    : const_cast<char*>(log_warning);
             iov[0].iov_len = info ? sizeof(log_info) : sizeof(log_warning);
             iov[1].iov_base = str;
             iov[1].iov_len = strlen(str);
-            iov[2].iov_base = const_cast<char*>(bug_metadata.c_str());
-            iov[2].iov_len = bug_metadata.length();
+            iov[2].iov_base = const_cast<char*>(denial_metadata.c_str());
+            iov[2].iov_len = denial_metadata.length();
             iov[3].iov_base = const_cast<char*>(newline);
             iov[3].iov_len = strlen(newline);
 
@@ -269,9 +294,6 @@
         return 0;
     }
 
-    pid_t pid = getpid();
-    pid_t tid = gettid();
-    uid_t uid = AID_LOGD;
     log_time now;
 
     static const char audit_str[] = " audit(";
@@ -296,29 +318,13 @@
         now = log_time(CLOCK_REALTIME);
     }
 
-    static const char pid_str[] = " pid=";
-    char* pidptr = strstr(str, pid_str);
-    if (pidptr && isdigit(pidptr[sizeof(pid_str) - 1])) {
-        cp = pidptr + sizeof(pid_str) - 1;
-        pid = 0;
-        while (isdigit(*cp)) {
-            pid = (pid * 10) + (*cp - '0');
-            ++cp;
-        }
-        tid = pid;
-        logbuf->wrlock();
-        uid = logbuf->pidToUid(pid);
-        logbuf->unlock();
-        memmove(pidptr, cp, strlen(cp) + 1);
-    }
-
     // log to events
 
     size_t str_len = strnlen(str, LOGGER_ENTRY_MAX_PAYLOAD);
     if (((fdDmesg < 0) || !initialized) && !hasMetadata(str, str_len))
-        logParse(str, &bug_metadata);
-    str_len = (str_len + bug_metadata.length() <= LOGGER_ENTRY_MAX_PAYLOAD)
-                  ? str_len + bug_metadata.length()
+        auditParse(str, uid, &denial_metadata);
+    str_len = (str_len + denial_metadata.length() <= LOGGER_ENTRY_MAX_PAYLOAD)
+                  ? str_len + denial_metadata.length()
                   : LOGGER_ENTRY_MAX_PAYLOAD;
     size_t message_len = str_len + sizeof(android_log_event_string_t);
 
@@ -332,9 +338,9 @@
         event->header.tag = htole32(AUDITD_LOG_TAG);
         event->type = EVENT_TYPE_STRING;
         event->length = htole32(str_len);
-        memcpy(event->data, str, str_len - bug_metadata.length());
-        memcpy(event->data + str_len - bug_metadata.length(),
-               bug_metadata.c_str(), bug_metadata.length());
+        memcpy(event->data, str, str_len - denial_metadata.length());
+        memcpy(event->data + str_len - denial_metadata.length(),
+               denial_metadata.c_str(), denial_metadata.length());
 
         rc = logbuf->log(
             LOG_ID_EVENTS, now, uid, pid, tid, reinterpret_cast<char*>(event),
@@ -380,7 +386,8 @@
         prefix_len = LOGGER_ENTRY_MAX_PAYLOAD;
     }
     size_t suffix_len = strnlen(ecomm, LOGGER_ENTRY_MAX_PAYLOAD - prefix_len);
-    message_len = str_len + prefix_len + suffix_len + bug_metadata.length() + 2;
+    message_len =
+        str_len + prefix_len + suffix_len + denial_metadata.length() + 2;
 
     if (main) {  // begin scope for main buffer
         char newstr[message_len];
@@ -390,7 +397,7 @@
         strncpy(newstr + 1 + str_len, str, prefix_len);
         strncpy(newstr + 1 + str_len + prefix_len, ecomm, suffix_len);
         strncpy(newstr + 1 + str_len + prefix_len + suffix_len,
-                bug_metadata.c_str(), bug_metadata.length());
+                denial_metadata.c_str(), denial_metadata.length());
 
         rc = logbuf->log(LOG_ID_MAIN, now, uid, pid, tid, newstr,
                          (message_len <= USHRT_MAX) ? (unsigned short)message_len
diff --git a/logd/LogAudit.h b/logd/LogAudit.h
index 5904966..c3d7a3e 100644
--- a/logd/LogAudit.h
+++ b/logd/LogAudit.h
@@ -48,7 +48,7 @@
     std::map<std::string, std::string> populateDenialMap();
     std::string denialParse(const std::string& denial, char terminator,
                             const std::string& search_term);
-    void logParse(const std::string& string, std::string* bug_num);
+    void auditParse(const std::string& string, uid_t uid, std::string* bug_num);
     int logPrint(const char* fmt, ...)
         __attribute__((__format__(__printf__, 2, 3)));
 };
diff --git a/logd/main.cpp b/logd/main.cpp
index 4af0d21..606aa63 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -33,7 +33,6 @@
 #include <syslog.h>
 #include <unistd.h>
 
-#include <cstdbool>
 #include <memory>
 
 #include <android-base/macros.h>
diff --git a/logwrapper/Android.bp b/logwrapper/Android.bp
index 54506dc..d4ba4f4 100644
--- a/logwrapper/Android.bp
+++ b/logwrapper/Android.bp
@@ -41,14 +41,11 @@
     defaults: ["logwrapper_common"],
 }
 
-// Build vendor logwrapper.
-// TODO: Add vendor_available to "logwrapper" module and remove "logwrapper_vendor" module
-//       when vendor_available is fully supported.
 cc_binary {
     name: "logwrapper_vendor",
+    defaults: ["logwrapper_common"],
     stem: "logwrapper",
     vendor: true,
-    defaults: ["logwrapper_common"],
 }
 
 // ========================================================
diff --git a/mkbootimg/OWNERS b/mkbootimg/OWNERS
new file mode 100644
index 0000000..39448cf
--- /dev/null
+++ b/mkbootimg/OWNERS
@@ -0,0 +1 @@
+tbao@google.com
diff --git a/mkbootimg/include/bootimg/bootimg.h b/mkbootimg/include/bootimg/bootimg.h
index 4311b46..406e208 100644
--- a/mkbootimg/include/bootimg/bootimg.h
+++ b/mkbootimg/include/bootimg/bootimg.h
@@ -1,37 +1,33 @@
-/* tools/mkbootimg/bootimg.h
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
 
 #include <stdint.h>
 
-#ifndef _BOOT_IMAGE_H_
-#define _BOOT_IMAGE_H_
-
 #define BOOT_MAGIC "ANDROID!"
 #define BOOT_MAGIC_SIZE 8
 #define BOOT_NAME_SIZE 16
 #define BOOT_ARGS_SIZE 512
 #define BOOT_EXTRA_ARGS_SIZE 1024
 
-#define BOOT_HEADER_VERSION_ZERO 0
-/*
- *  Bootloader expects the structure of boot_img_hdr with header version
- *  BOOT_HEADER_VERSION_ZERO to be as follows:
- */
+// The bootloader expects the structure of boot_img_hdr with header
+// version 0 to be as follows:
 struct boot_img_hdr_v0 {
+    // Must be BOOT_MAGIC.
     uint8_t magic[BOOT_MAGIC_SIZE];
 
     uint32_t kernel_size; /* size in bytes */
@@ -45,26 +41,36 @@
 
     uint32_t tags_addr; /* physical addr for kernel tags */
     uint32_t page_size; /* flash page size we assume */
-    /*
-     * version for the boot image header.
-     */
+
+    // Version of the boot image header.
     uint32_t header_version;
 
-    /* operating system version and security patch level; for
-     * version "A.B.C" and patch level "Y-M-D":
-     * ver = A << 14 | B << 7 | C         (7 bits for each of A, B, C)
-     * lvl = ((Y - 2000) & 127) << 4 | M  (7 bits for Y, 4 bits for M)
-     * os_version = ver << 11 | lvl */
+    // Operating system version and security patch level.
+    // For version "A.B.C" and patch level "Y-M-D":
+    //   (7 bits for each of A, B, C; 7 bits for (Y-2000), 4 bits for M)
+    //   os_version = A[31:25] B[24:18] C[17:11] (Y-2000)[10:4] M[3:0]
     uint32_t os_version;
 
+#if __cplusplus
+    void SetOsVersion(unsigned major, unsigned minor, unsigned patch) {
+        os_version &= ((1 << 11) - 1);
+        os_version |= (((major & 0x7f) << 25) | ((minor & 0x7f) << 18) | ((patch & 0x7f) << 11));
+    }
+
+    void SetOsPatchLevel(unsigned year, unsigned month) {
+        os_version &= ~((1 << 11) - 1);
+        os_version |= (((year - 2000) & 0x7f) << 4) | ((month & 0xf) << 0);
+    }
+#endif
+
     uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */
 
     uint8_t cmdline[BOOT_ARGS_SIZE];
 
     uint32_t id[8]; /* timestamp / checksum / sha1 / etc */
 
-    /* Supplemental command line data; kept here to maintain
-     * binary compatibility with older versions of mkbootimg */
+    // Supplemental command line data; kept here to maintain
+    // binary compatibility with older versions of mkbootimg.
     uint8_t extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
 } __attribute__((packed));
 
@@ -74,7 +80,7 @@
  */
 typedef struct boot_img_hdr_v0 boot_img_hdr;
 
-/* When a boot header is of version BOOT_HEADER_VERSION_ZERO, the structure of boot image is as
+/* When a boot header is of version 0, the structure of boot image is as
  * follows:
  *
  * +-----------------+
@@ -103,15 +109,13 @@
  *    else: jump to kernel_addr
  */
 
-#define BOOT_HEADER_VERSION_ONE 1
-
 struct boot_img_hdr_v1 : public boot_img_hdr_v0 {
     uint32_t recovery_dtbo_size;   /* size in bytes for recovery DTBO image */
     uint64_t recovery_dtbo_offset; /* physical load addr */
     uint32_t header_size;
 } __attribute__((packed));
 
-/* When the boot image header has a version of BOOT_HEADER_VERSION_ONE, the structure of the boot
+/* When the boot image header has a version of 1, the structure of the boot
  * image is as follows:
  *
  * +-----------------+
@@ -142,23 +146,3 @@
  * 7. if second_size != 0: jump to second_addr
  *    else: jump to kernel_addr
  */
-
-#if 0
-typedef struct ptentry ptentry;
-
-struct ptentry {
-    char name[16];      /* asciiz partition name    */
-    unsigned start;     /* starting block number    */
-    unsigned length;    /* length in blocks         */
-    unsigned flags;     /* set to zero              */
-};
-
-/* MSM Partition Table ATAG
-**
-** length: 2 + 7 * n
-** atag:   0x4d534d70
-**         <ptentry> x n
-*/
-#endif
-
-#endif
diff --git a/property_service/libpropertyinfoserializer/Android.bp b/property_service/libpropertyinfoserializer/Android.bp
index 72ae19a..3c4bdc3 100644
--- a/property_service/libpropertyinfoserializer/Android.bp
+++ b/property_service/libpropertyinfoserializer/Android.bp
@@ -35,4 +35,5 @@
         "property_info_serializer_test.cpp",
     ],
     static_libs: ["libpropertyinfoserializer"],
+    test_suites: ["device-tests"],
 }
diff --git a/rootdir/etc/public.libraries.iot.txt b/rootdir/etc/public.libraries.iot.txt
new file mode 100644
index 0000000..ff0813d
--- /dev/null
+++ b/rootdir/etc/public.libraries.iot.txt
@@ -0,0 +1,27 @@
+# See https://android.googlesource.com/platform/ndk/+/master/docs/PlatformApis.md
+libandroid.so
+libandroidthings.so
+libaaudio.so
+libc.so
+libcamera2ndk.so
+libdl.so
+libEGL.so
+libGLESv1_CM.so
+libGLESv2.so
+libGLESv3.so
+libicui18n.so
+libicuuc.so
+libjnigraphics.so
+liblog.so
+libmediandk.so
+libm.so
+libnativewindow.so
+libneuralnetworks.so
+libOpenMAXAL.so
+libOpenSLES.so
+libRS.so
+libstdc++.so
+libsync.so
+libvulkan.so
+libwebviewchromium_plat_support.so
+libz.so
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 4cc6693..f21490f 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -31,6 +31,9 @@
     # root memory control cgroup, used by lmkd
     mkdir /dev/memcg 0700 root system
     mount cgroup none /dev/memcg nodev noexec nosuid memory
+    # memory.pressure_level used by lmkd
+    chown root system /dev/memcg/memory.pressure_level
+    chmod 0040 /dev/memcg/memory.pressure_level
     # app mem cgroups, used by activity manager, lmkd and zygote
     mkdir /dev/memcg/apps/ 0755 system system
     # cgroup for system_server and surfaceflinger
@@ -429,6 +432,7 @@
     mkdir /data/misc/radio 0770 system radio
     mkdir /data/misc/sms 0770 system radio
     mkdir /data/misc/carrierid 0770 system radio
+    mkdir /data/misc/apns 0770 system radio
     mkdir /data/misc/zoneinfo 0775 system system
     mkdir /data/misc/network_watchlist 0774 system system
     mkdir /data/misc/textclassifier 0771 system system
@@ -519,6 +523,7 @@
     mkdir /data/ss 0700 system system
 
     mkdir /data/system 0775 system system
+    mkdir /data/system/dropbox 0700 system system
     mkdir /data/system/heapdump 0700 system system
     mkdir /data/system/users 0775 system system
 
diff --git a/shell_and_utilities/README.md b/shell_and_utilities/README.md
index c423c69..678b853 100644
--- a/shell_and_utilities/README.md
+++ b/shell_and_utilities/README.md
@@ -179,15 +179,41 @@
 
 toybox: acpi base64 basename blockdev cal cat chcon chgrp chmod chown
 chroot chrt cksum clear cmp comm cp cpio cut date df diff dirname dmesg
-dos2unix du echo env expand expr fallocate false file find flock free
+dos2unix du echo env expand expr fallocate false file find flock fmt free
 getenforce groups gunzip gzip head hostname hwclock id ifconfig inotifyd
-insmod ionice iorenice kill killall ln load\_policy log logname losetup
-ls lsmod lsof lspci lsusb md5sum microcom mkdir mkfifo mknod mkswap
-mktemp modinfo modprobe more mount mountpoint mv netstat nice nl nohup
-od paste patch pgrep pidof pkill pmap printenv printf ps pwd readlink
-realpath renice restorecon rm rmdir rmmod runcon sed sendevent seq
-setenforce setprop setsid sha1sum sha224sum sha256sum sha384sum
-sha512sum sleep sort split start stat stop strings swapoff swapon sync
-sysctl tac tail tar taskset tee time timeout top touch tr true truncate
-tty ulimit umount uname uniq unix2dos uptime usleep uudecode uuencode
-vmstat wc which whoami xargs xxd yes zcat
+insmod ionice iorenice kill killall ln load\_policy log logname losetup ls
+lsmod lsof lspci lsusb md5sum microcom mkdir mkfifo mknod mkswap mktemp
+modinfo modprobe more mount mountpoint mv netstat nice nl nohup od paste
+patch pgrep pidof pkill pmap printenv printf ps pwd readlink realpath
+renice restorecon rm rmdir rmmod runcon sed sendevent seq setenforce
+setprop setsid sha1sum sha224sum sha256sum sha384sum sha512sum sleep
+sort split start stat stop strings stty swapoff swapon sync sysctl tac
+tail tar taskset tee time timeout top touch tr true truncate tty ulimit
+umount uname uniq unix2dos uptime usleep uudecode uuencode vmstat wc
+which whoami xargs xxd yes zcat
+
+Android Q
+---------
+
+bzip2: bzcat bzip2 bunzip2
+
+one-true-awk: awk
+
+PCRE: egrep fgrep grep
+
+toolbox: getevent getprop newfs\_msdos
+
+toybox: acpi base64 basename blockdev cal cat chcon chgrp chmod chown
+chroot chrt cksum clear cmp comm cp cpio cut date dd df diff dirname
+dmesg dos2unix du echo env expand expr fallocate false file find flock
+fmt free getenforce groups gunzip gzip head hostname hwclock id ifconfig
+inotifyd insmod ionice iorenice kill killall ln load\_policy log logname
+losetup ls lsmod lsof lspci lsusb md5sum microcom mkdir mkfifo mknod
+mkswap mktemp modinfo modprobe more mount mountpoint mv nc netcat netstat
+nice nl nohup nsenter od paste patch pgrep pidof pkill pmap printenv
+printf ps pwd readlink realpath renice restorecon rm rmdir rmmod runcon
+sed sendevent seq setenforce setprop setsid sha1sum sha224sum sha256sum
+sha384sum sha512sum sleep sort split start stat stop strings stty swapoff
+swapon sync sysctl tac tail tar taskset tee time timeout top touch tr
+true truncate tty ulimit umount uname uniq unix2dos unshare uptime usleep
+uudecode uuencode vmstat wc which whoami xargs xxd yes zcat
diff --git a/storaged/OWNERS b/storaged/OWNERS
index 7445270..d033f00 100644
--- a/storaged/OWNERS
+++ b/storaged/OWNERS
@@ -1 +1,2 @@
-jinqian@google.com
+salyzyn@google.com
+dvander@google.com
diff --git a/storaged/main.cpp b/storaged/main.cpp
index b3f1281..3817fb5 100644
--- a/storaged/main.cpp
+++ b/storaged/main.cpp
@@ -21,9 +21,6 @@
 #include <getopt.h>
 #include <pthread.h>
 #include <stdio.h>
-#include <sys/capability.h>
-#include <sys/prctl.h>
-#include <sys/resource.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <vector>
diff --git a/toolbox/Android.bp b/toolbox/Android.bp
index ddd95b2..077f542 100644
--- a/toolbox/Android.bp
+++ b/toolbox/Android.bp
@@ -5,32 +5,8 @@
         "-Werror",
         "-Wno-unused-parameter",
         "-Wno-unused-const-variable",
-        "-include bsd-compatibility.h",
         "-D_FILE_OFFSET_BITS=64",
-    ],
-    local_include_dirs: ["upstream-netbsd/include/"],
-}
-
-cc_library_static {
-    name: "libtoolbox_dd",
-    defaults: ["toolbox_defaults"],
-    vendor_available: true,
-    srcs: [
-        "upstream-netbsd/bin/dd/args.c",
-        "upstream-netbsd/bin/dd/conv.c",
-        "upstream-netbsd/bin/dd/dd.c",
-        "upstream-netbsd/bin/dd/dd_hostops.c",
-        "upstream-netbsd/bin/dd/misc.c",
-        "upstream-netbsd/bin/dd/position.c",
-        "upstream-netbsd/lib/libc/gen/getbsize.c",
-        "upstream-netbsd/lib/libc/gen/humanize_number.c",
-        "upstream-netbsd/lib/libc/stdlib/strsuftoll.c",
-        "upstream-netbsd/lib/libc/string/swab.c",
-        "upstream-netbsd/lib/libutil/raise_default_signal.c",
-    ],
-    cflags: [
-        "-Dmain=dd_main",
-        "-DNO_CONV",
+        "-DWITHOUT_NLS",
     ],
 }
 
@@ -55,15 +31,12 @@
     generated_headers: [
         "toolbox_input_labels",
     ],
-    whole_static_libs: ["libtoolbox_dd"],
     shared_libs: [
         "libbase",
-        "libcutils",
     ],
     static_libs: ["libpropertyinfoparser"],
 
     symlinks: [
-        "dd",
         "getevent",
         "getprop",
         "newfs_msdos",
@@ -89,38 +62,9 @@
     srcs: ["r.c"],
 }
 
-// We build BSD grep separately, so it can provide egrep and fgrep too.
-cc_defaults {
-    name: "grep_common",
+cc_binary_host {
+    name: "newfs_msdos",
     defaults: ["toolbox_defaults"],
-    srcs: [
-        "upstream-netbsd/usr.bin/grep/fastgrep.c",
-        "upstream-netbsd/usr.bin/grep/file.c",
-        "upstream-netbsd/usr.bin/grep/grep.c",
-        "upstream-netbsd/usr.bin/grep/queue.c",
-        "upstream-netbsd/usr.bin/grep/util.c",
-    ],
-    symlinks: [
-        "egrep",
-        "fgrep",
-    ],
-
-    sanitize: {
-        integer_overflow: false,
-    },
-}
-
-cc_binary {
-    name: "grep",
-    defaults: ["grep_common"],
-}
-
-// Build vendor grep.
-// TODO: Add vendor_available to "grep" module and remove "grep_vendor" module
-//       when vendor_available is fully supported.
-cc_binary {
-    name: "grep_vendor",
-    stem: "grep",
-    vendor: true,
-    defaults: ["grep_common"],
+    srcs: ["newfs_msdos.c"],
+    cflags: ["-Dnewfs_msdos_main=main"]
 }
diff --git a/toolbox/bsd-compatibility.h b/toolbox/bsd-compatibility.h
deleted file mode 100644
index 7c3ddd4..0000000
--- a/toolbox/bsd-compatibility.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2014, The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdbool.h>
-#include <sys/types.h>
-
-/* We want chown to support user.group as well as user:group. */
-#define SUPPORT_DOT
-
-/* We don't localize /system/bin! */
-#define WITHOUT_NLS
-
-// NetBSD uses _DIAGASSERT to null-check arguments and the like.
-#include <assert.h>
-#define _DIAGASSERT(e) ((e) ? (void) 0 : __assert2(__FILE__, __LINE__, __func__, #e))
-
-// TODO: update our <sys/cdefs.h> to support this properly.
-#define __type_fit(t, a) (0 == 0)
-
-// TODO: should this be in our <sys/cdefs.h>?
-#define __arraycount(a) (sizeof(a) / sizeof((a)[0]))
-
-// This at least matches GNU dd(1) behavior.
-#define SIGINFO SIGUSR1
-
-#define S_ISWHT(x) false
-
-__BEGIN_DECLS
-
-/* From NetBSD <stdlib.h>. */
-#define HN_DECIMAL              0x01
-#define HN_NOSPACE              0x02
-#define HN_B                    0x04
-#define HN_DIVISOR_1000         0x08
-#define HN_GETSCALE             0x10
-#define HN_AUTOSCALE            0x20
-int	humanize_number(char *, size_t, int64_t, const char *, int, int);
-int	dehumanize_number(const char *, int64_t *);
-char	*getbsize(int *, long *);
-long long strsuftoll(const char *, const char *, long long, long long);
-long long strsuftollx(const char *, const char *, long long, long long,
-			char *, size_t);
-
-/* From NetBSD <string.h>. */
-void strmode(mode_t, char*);
-
-/* From NetBSD <sys/param.h>. */
-#define MAXBSIZE 65536
-
-/* From NetBSD <sys/stat.h>. */
-#define DEFFILEMODE (S_IRUSR | S_IWUSR)
-
-/* From NetBSD <unistd.h>. */
-void	swab(const void * __restrict, void * __restrict, ssize_t);
-
-/* From NetBSD <util.h>. */
-int		raise_default_signal(int);
-
-__END_DECLS
diff --git a/toolbox/newfs_msdos.c b/toolbox/newfs_msdos.c
index d7047e2..5fc8b02 100644
--- a/toolbox/newfs_msdos.c
+++ b/toolbox/newfs_msdos.c
@@ -32,15 +32,17 @@
 
 #include <sys/param.h>
 
-#ifndef ANDROID
+#ifdef __APPLE__
+#elif defined(ANDROID)
+#include <linux/fs.h>
+#include <linux/hdreg.h>
+#include <stdarg.h>
+#include <sys/ioctl.h>
+#else
 #include <sys/fdcio.h>
 #include <sys/disk.h>
 #include <sys/disklabel.h>
 #include <sys/mount.h>
-#else
-#include <stdarg.h>
-#include <linux/fs.h>
-#include <linux/hdreg.h>
 #endif
 
 #include <sys/stat.h>
@@ -58,6 +60,10 @@
 #include <time.h>
 #include <unistd.h>
 
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
+
 #define MAXU16   0xffff     /* maximum unsigned 16-bit quantity */
 #define BPN      4          /* bits per nibble */
 #define NPB      2          /* nibbles per byte */
@@ -794,7 +800,10 @@
  * Get disk slice, partition, and geometry information.
  */
 
-#ifdef ANDROID
+#ifdef __APPLE__
+static void getdiskinfo(__unused int fd, __unused const char* fname, __unused const char* dtype,
+                        __unused int oflag, __unused struct bpb* bpb) {}
+#elif ANDROID
 static void getdiskinfo(int fd, const char *fname, const char *dtype,
                         __unused int oflag,struct bpb *bpb)
 {
diff --git a/toolbox/tools.h b/toolbox/tools.h
index 505f528..3d4bc3e 100644
--- a/toolbox/tools.h
+++ b/toolbox/tools.h
@@ -1,4 +1,3 @@
-TOOL(dd)
 TOOL(getevent)
 TOOL(getprop)
 TOOL(newfs_msdos)
diff --git a/toolbox/upstream-netbsd/bin/dd/args.c b/toolbox/upstream-netbsd/bin/dd/args.c
deleted file mode 100644
index 207e300..0000000
--- a/toolbox/upstream-netbsd/bin/dd/args.c
+++ /dev/null
@@ -1,391 +0,0 @@
-/*	$NetBSD: args.c,v 1.38 2013/07/17 12:55:48 christos Exp $	*/
-
-/*-
- * Copyright (c) 1991, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego and Lance
- * Visser of Convex Computer Corporation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)args.c	8.3 (Berkeley) 4/2/94";
-#else
-__RCSID("$NetBSD: args.c,v 1.38 2013/07/17 12:55:48 christos Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/types.h>
-#include <sys/time.h>
-
-#include <err.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "dd.h"
-#include "extern.h"
-
-static int	c_arg(const void *, const void *);
-
-#ifdef NO_MSGFMT
-static void	f_msgfmt(char *) __dead;
-#else
-static void	f_msgfmt(char *);
-#endif /* NO_MSGFMT */
-
-#ifdef NO_CONV
-static void	f_conv(char *) __dead;
-#else
-static void	f_conv(char *);
-static int	c_conv(const void *, const void *);
-#endif /* NO_CONV */
-
-static void	f_bs(char *);
-static void	f_cbs(char *);
-static void	f_count(char *);
-static void	f_files(char *);
-static void	f_ibs(char *);
-static void	f_if(char *);
-static void	f_obs(char *);
-static void	f_of(char *);
-static void	f_seek(char *);
-static void	f_skip(char *);
-static void	f_progress(char *);
-
-static const struct arg {
-	const char *name;
-	void (*f)(char *);
-	u_int set, noset;
-} args[] = {
-     /* the array needs to be sorted by the first column so
-	bsearch() can be used to find commands quickly */
-	{ "bs",		f_bs,		C_BS,	 C_BS|C_IBS|C_OBS|C_OSYNC },
-	{ "cbs",	f_cbs,		C_CBS,	 C_CBS },
-	{ "conv",	f_conv,		0,	 0 },
-	{ "count",	f_count,	C_COUNT, C_COUNT },
-	{ "files",	f_files,	C_FILES, C_FILES },
-	{ "ibs",	f_ibs,		C_IBS,	 C_BS|C_IBS },
-	{ "if",		f_if,		C_IF,	 C_IF },
-	{ "iseek",	f_skip,		C_SKIP,	 C_SKIP },
-	{ "msgfmt",	f_msgfmt,	0,	 0 },
-	{ "obs",	f_obs,		C_OBS,	 C_BS|C_OBS },
-	{ "of",		f_of,		C_OF,	 C_OF },
-	{ "oseek",	f_seek,		C_SEEK,	 C_SEEK },
-	{ "progress",	f_progress,	0,	 0 },
-	{ "seek",	f_seek,		C_SEEK,	 C_SEEK },
-	{ "skip",	f_skip,		C_SKIP,	 C_SKIP },
-};
-
-/*
- * args -- parse JCL syntax of dd.
- */
-void
-jcl(char **argv)
-{
-	struct arg *ap, tmp;
-	char *oper, *arg;
-
-	in.dbsz = out.dbsz = 512;
-
-	while ((oper = *++argv) != NULL) {
-		if ((oper = strdup(oper)) == NULL) {
-			errx(EXIT_FAILURE,
-			    "unable to allocate space for the argument %s",
-			    *argv);
-			/* NOTREACHED */
-		}
-		if ((arg = strchr(oper, '=')) == NULL) {
-			errx(EXIT_FAILURE, "unknown operand %s", oper);
-			/* NOTREACHED */
-		}
-		*arg++ = '\0';
-		if (!*arg) {
-			errx(EXIT_FAILURE, "no value specified for %s", oper);
-			/* NOTREACHED */
-		}
-		tmp.name = oper;
-		if (!(ap = bsearch(&tmp, args,
-		    __arraycount(args), sizeof(*args), c_arg))) {
-			errx(EXIT_FAILURE, "unknown operand %s", tmp.name);
-			/* NOTREACHED */
-		}
-		if (ddflags & ap->noset) {
-			errx(EXIT_FAILURE,
-			    "%s: illegal argument combination or already set",
-			    tmp.name);
-			/* NOTREACHED */
-		}
-		ddflags |= ap->set;
-		ap->f(arg);
-	}
-
-	/* Final sanity checks. */
-
-	if (ddflags & C_BS) {
-		/*
-		 * Bs is turned off by any conversion -- we assume the user
-		 * just wanted to set both the input and output block sizes
-		 * and didn't want the bs semantics, so we don't warn.
-		 */
-		if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE |
-		    C_UNBLOCK | C_OSYNC | C_ASCII | C_EBCDIC | C_SPARSE)) {
-			ddflags &= ~C_BS;
-			ddflags |= C_IBS|C_OBS;
-		}
-
-		/* Bs supersedes ibs and obs. */
-		if (ddflags & C_BS && ddflags & (C_IBS|C_OBS))
-			warnx("bs supersedes ibs and obs");
-	}
-
-	/*
-	 * Ascii/ebcdic and cbs implies block/unblock.
-	 * Block/unblock requires cbs and vice-versa.
-	 */
-	if (ddflags & (C_BLOCK|C_UNBLOCK)) {
-		if (!(ddflags & C_CBS)) {
-			errx(EXIT_FAILURE, "record operations require cbs");
-			/* NOTREACHED */
-		}
-		cfunc = ddflags & C_BLOCK ? block : unblock;
-	} else if (ddflags & C_CBS) {
-		if (ddflags & (C_ASCII|C_EBCDIC)) {
-			if (ddflags & C_ASCII) {
-				ddflags |= C_UNBLOCK;
-				cfunc = unblock;
-			} else {
-				ddflags |= C_BLOCK;
-				cfunc = block;
-			}
-		} else {
-			errx(EXIT_FAILURE,
-			    "cbs meaningless if not doing record operations");
-			/* NOTREACHED */
-		}
-	} else
-		cfunc = def;
-
-	/* Read, write and seek calls take off_t as arguments.
-	 *
-	 * The following check is not done because an off_t is a quad
-	 *  for current NetBSD implementations.
-	 *
-	 * if (in.offset > INT_MAX/in.dbsz || out.offset > INT_MAX/out.dbsz)
-	 *	errx(1, "seek offsets cannot be larger than %d", INT_MAX);
-	 */
-}
-
-static int
-c_arg(const void *a, const void *b)
-{
-
-	return (strcmp(((const struct arg *)a)->name,
-	    ((const struct arg *)b)->name));
-}
-
-static void
-f_bs(char *arg)
-{
-
-	in.dbsz = out.dbsz = strsuftoll("block size", arg, 1, UINT_MAX);
-}
-
-static void
-f_cbs(char *arg)
-{
-
-	cbsz = strsuftoll("conversion record size", arg, 1, UINT_MAX);
-}
-
-static void
-f_count(char *arg)
-{
-
-	cpy_cnt = strsuftoll("block count", arg, 0, LLONG_MAX);
-	if (!cpy_cnt)
-		terminate(0);
-}
-
-static void
-f_files(char *arg)
-{
-
-	files_cnt = (u_int)strsuftoll("file count", arg, 0, UINT_MAX);
-	if (!files_cnt)
-		terminate(0);
-}
-
-static void
-f_ibs(char *arg)
-{
-
-	if (!(ddflags & C_BS))
-		in.dbsz = strsuftoll("input block size", arg, 1, UINT_MAX);
-}
-
-static void
-f_if(char *arg)
-{
-
-	in.name = arg;
-}
-
-#ifdef NO_MSGFMT
-/* Build a small version (i.e. for a ramdisk root) */
-static void
-f_msgfmt(char *arg)
-{
-
-	errx(EXIT_FAILURE, "msgfmt option disabled");
-	/* NOTREACHED */
-}
-#else	/* NO_MSGFMT */
-static void
-f_msgfmt(char *arg)
-{
-
-	/*
-	 * If the format string is not valid, dd_write_msg() will print
-	 * an error and exit.
-	 */
-	dd_write_msg(arg, 0);
-
-	msgfmt = arg;
-}
-#endif	/* NO_MSGFMT */
-
-static void
-f_obs(char *arg)
-{
-
-	if (!(ddflags & C_BS))
-		out.dbsz = strsuftoll("output block size", arg, 1, UINT_MAX);
-}
-
-static void
-f_of(char *arg)
-{
-
-	out.name = arg;
-}
-
-static void
-f_seek(char *arg)
-{
-
-	out.offset = strsuftoll("seek blocks", arg, 0, LLONG_MAX);
-}
-
-static void
-f_skip(char *arg)
-{
-
-	in.offset = strsuftoll("skip blocks", arg, 0, LLONG_MAX);
-}
-
-static void
-f_progress(char *arg)
-{
-
-	progress = strsuftoll("progress blocks", arg, 0, LLONG_MAX);
-}
-
-#ifdef	NO_CONV
-/* Build a small version (i.e. for a ramdisk root) */
-static void
-f_conv(char *arg)
-{
-
-	errx(EXIT_FAILURE, "conv option disabled");
-	/* NOTREACHED */
-}
-#else	/* NO_CONV */
-
-static const struct conv {
-	const char *name;
-	u_int set, noset;
-	const u_char *ctab;
-} clist[] = {
-	{ "ascii",	C_ASCII,	C_EBCDIC,	e2a_POSIX },
-	{ "block",	C_BLOCK,	C_UNBLOCK,	NULL },
-	{ "ebcdic",	C_EBCDIC,	C_ASCII,	a2e_POSIX },
-	{ "ibm",	C_EBCDIC,	C_ASCII,	a2ibm_POSIX },
-	{ "lcase",	C_LCASE,	C_UCASE,	NULL },
-	{ "noerror",	C_NOERROR,	0,		NULL },
-	{ "notrunc",	C_NOTRUNC,	0,		NULL },
-	{ "oldascii",	C_ASCII,	C_EBCDIC,	e2a_32V },
-	{ "oldebcdic",	C_EBCDIC,	C_ASCII,	a2e_32V },
-	{ "oldibm",	C_EBCDIC,	C_ASCII,	a2ibm_32V },
-	{ "osync",	C_OSYNC,	C_BS,		NULL },
-	{ "sparse",	C_SPARSE,	0,		NULL },
-	{ "swab",	C_SWAB,		0,		NULL },
-	{ "sync",	C_SYNC,		0,		NULL },
-	{ "ucase",	C_UCASE,	C_LCASE,	NULL },
-	{ "unblock",	C_UNBLOCK,	C_BLOCK,	NULL },
-	/* If you add items to this table, be sure to add the
-	 * conversions to the C_BS check in the jcl routine above.
-	 */
-};
-
-static void
-f_conv(char *arg)
-{
-	struct conv *cp, tmp;
-
-	while (arg != NULL) {
-		tmp.name = strsep(&arg, ",");
-		if (!(cp = bsearch(&tmp, clist,
-		    __arraycount(clist), sizeof(*clist), c_conv))) {
-			errx(EXIT_FAILURE, "unknown conversion %s", tmp.name);
-			/* NOTREACHED */
-		}
-		if (ddflags & cp->noset) {
-			errx(EXIT_FAILURE,
-			    "%s: illegal conversion combination", tmp.name);
-			/* NOTREACHED */
-		}
-		ddflags |= cp->set;
-		if (cp->ctab)
-			ctab = cp->ctab;
-	}
-}
-
-static int
-c_conv(const void *a, const void *b)
-{
-
-	return (strcmp(((const struct conv *)a)->name,
-	    ((const struct conv *)b)->name));
-}
-
-#endif	/* NO_CONV */
diff --git a/toolbox/upstream-netbsd/bin/dd/conv.c b/toolbox/upstream-netbsd/bin/dd/conv.c
deleted file mode 100644
index d4a8a09..0000000
--- a/toolbox/upstream-netbsd/bin/dd/conv.c
+++ /dev/null
@@ -1,283 +0,0 @@
-/*	$NetBSD: conv.c,v 1.17 2003/08/07 09:05:10 agc Exp $	*/
-
-/*-
- * Copyright (c) 1991, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego and Lance
- * Visser of Convex Computer Corporation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)conv.c	8.3 (Berkeley) 4/2/94";
-#else
-__RCSID("$NetBSD: conv.c,v 1.17 2003/08/07 09:05:10 agc Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/param.h>
-#include <sys/time.h>
-
-#include <err.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "dd.h"
-#include "extern.h"
-
-/*
- * def --
- * Copy input to output.  Input is buffered until reaches obs, and then
- * output until less than obs remains.  Only a single buffer is used.
- * Worst case buffer calculation is (ibs + obs - 1).
- */
-void
-def(void)
-{
-	uint64_t cnt;
-	u_char *inp;
-	const u_char *t;
-
-	if ((t = ctab) != NULL)
-		for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp)
-			*inp = t[*inp];
-
-	/* Make the output buffer look right. */
-	out.dbp = in.dbp;
-	out.dbcnt = in.dbcnt;
-
-	if (in.dbcnt >= out.dbsz) {
-		/* If the output buffer is full, write it. */
-		dd_out(0);
-
-		/*
-		 * Ddout copies the leftover output to the beginning of
-		 * the buffer and resets the output buffer.  Reset the
-		 * input buffer to match it.
-	 	 */
-		in.dbp = out.dbp;
-		in.dbcnt = out.dbcnt;
-	}
-}
-
-void
-def_close(void)
-{
-
-	/* Just update the count, everything is already in the buffer. */
-	if (in.dbcnt)
-		out.dbcnt = in.dbcnt;
-}
-
-#ifdef	NO_CONV
-/* Build a smaller version (i.e. for a miniroot) */
-/* These can not be called, but just in case...  */
-static const char no_block[] = "unblock and -DNO_CONV?";
-void block(void)		{ errx(EXIT_FAILURE, "%s", no_block + 2); }
-void block_close(void)		{ errx(EXIT_FAILURE, "%s", no_block + 2); }
-void unblock(void)		{ errx(EXIT_FAILURE, "%s", no_block); }
-void unblock_close(void)	{ errx(EXIT_FAILURE, "%s", no_block); }
-#else	/* NO_CONV */
-
-/*
- * Copy variable length newline terminated records with a max size cbsz
- * bytes to output.  Records less than cbs are padded with spaces.
- *
- * max in buffer:  MAX(ibs, cbsz)
- * max out buffer: obs + cbsz
- */
-void
-block(void)
-{
-	static int intrunc;
-	int ch = 0;	/* pacify gcc */
-	uint64_t cnt, maxlen;
-	u_char *inp, *outp;
-	const u_char *t;
-
-	/*
-	 * Record truncation can cross block boundaries.  If currently in a
-	 * truncation state, keep tossing characters until reach a newline.
-	 * Start at the beginning of the buffer, as the input buffer is always
-	 * left empty.
-	 */
-	if (intrunc) {
-		for (inp = in.db, cnt = in.dbrcnt;
-		    cnt && *inp++ != '\n'; --cnt);
-		if (!cnt) {
-			in.dbcnt = 0;
-			in.dbp = in.db;
-			return;
-		}
-		intrunc = 0;
-		/* Adjust the input buffer numbers. */
-		in.dbcnt = cnt - 1;
-		in.dbp = inp + cnt - 1;
-	}
-
-	/*
-	 * Copy records (max cbsz size chunks) into the output buffer.  The
-	 * translation is done as we copy into the output buffer.
-	 */
-	for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) {
-		maxlen = MIN(cbsz, in.dbcnt);
-		if ((t = ctab) != NULL)
-			for (cnt = 0;
-			    cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
-				*outp++ = t[ch];
-		else
-			for (cnt = 0;
-			    cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
-				*outp++ = ch;
-		/*
-		 * Check for short record without a newline.  Reassemble the
-		 * input block.
-		 */
-		if (ch != '\n' && in.dbcnt < cbsz) {
-			(void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
-			break;
-		}
-
-		/* Adjust the input buffer numbers. */
-		in.dbcnt -= cnt;
-		if (ch == '\n')
-			--in.dbcnt;
-
-		/* Pad short records with spaces. */
-		if (cnt < cbsz)
-			(void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt);
-		else {
-			/*
-			 * If the next character wouldn't have ended the
-			 * block, it's a truncation.
-			 */
-			if (!in.dbcnt || *inp != '\n')
-				++st.trunc;
-
-			/* Toss characters to a newline. */
-			for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt);
-			if (!in.dbcnt)
-				intrunc = 1;
-			else
-				--in.dbcnt;
-		}
-
-		/* Adjust output buffer numbers. */
-		out.dbp += cbsz;
-		if ((out.dbcnt += cbsz) >= out.dbsz)
-			dd_out(0);
-		outp = out.dbp;
-	}
-	in.dbp = in.db + in.dbcnt;
-}
-
-void
-block_close(void)
-{
-
-	/*
-	 * Copy any remaining data into the output buffer and pad to a record.
-	 * Don't worry about truncation or translation, the input buffer is
-	 * always empty when truncating, and no characters have been added for
-	 * translation.  The bottom line is that anything left in the input
-	 * buffer is a truncated record.  Anything left in the output buffer
-	 * just wasn't big enough.
-	 */
-	if (in.dbcnt) {
-		++st.trunc;
-		(void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt);
-		(void)memset(out.dbp + in.dbcnt,
-		    ctab ? ctab[' '] : ' ', cbsz - in.dbcnt);
-		out.dbcnt += cbsz;
-	}
-}
-
-/*
- * Convert fixed length (cbsz) records to variable length.  Deletes any
- * trailing blanks and appends a newline.
- *
- * max in buffer:  MAX(ibs, cbsz) + cbsz
- * max out buffer: obs + cbsz
- */
-void
-unblock(void)
-{
-	uint64_t cnt;
-	u_char *inp;
-	const u_char *t;
-
-	/* Translation and case conversion. */
-	if ((t = ctab) != NULL)
-		for (cnt = in.dbrcnt, inp = in.dbp - 1; cnt--; inp--)
-			*inp = t[*inp];
-	/*
-	 * Copy records (max cbsz size chunks) into the output buffer.  The
-	 * translation has to already be done or we might not recognize the
-	 * spaces.
-	 */
-	for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) {
-		for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t);
-		if (t >= inp) {
-			cnt = t - inp + 1;
-			(void)memmove(out.dbp, inp, cnt);
-			out.dbp += cnt;
-			out.dbcnt += cnt;
-		}
-		++out.dbcnt;
-		*out.dbp++ = '\n';
-		if (out.dbcnt >= out.dbsz)
-			dd_out(0);
-	}
-	if (in.dbcnt)
-		(void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
-	in.dbp = in.db + in.dbcnt;
-}
-
-void
-unblock_close(void)
-{
-	uint64_t cnt;
-	u_char *t;
-
-	if (in.dbcnt) {
-		warnx("%s: short input record", in.name);
-		for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t);
-		if (t >= in.db) {
-			cnt = t - in.db + 1;
-			(void)memmove(out.dbp, in.db, cnt);
-			out.dbp += cnt;
-			out.dbcnt += cnt;
-		}
-		++out.dbcnt;
-		*out.dbp++ = '\n';
-	}
-}
-
-#endif	/* NO_CONV */
diff --git a/toolbox/upstream-netbsd/bin/dd/dd.c b/toolbox/upstream-netbsd/bin/dd/dd.c
deleted file mode 100644
index 03d080c..0000000
--- a/toolbox/upstream-netbsd/bin/dd/dd.c
+++ /dev/null
@@ -1,598 +0,0 @@
-/*	$NetBSD: dd.c,v 1.49 2012/02/21 01:49:01 matt Exp $	*/
-
-/*-
- * Copyright (c) 1991, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego and Lance
- * Visser of Convex Computer Corporation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-__COPYRIGHT("@(#) Copyright (c) 1991, 1993, 1994\
- The Regents of the University of California.  All rights reserved.");
-#endif /* not lint */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)dd.c	8.5 (Berkeley) 4/2/94";
-#else
-__RCSID("$NetBSD: dd.c,v 1.49 2012/02/21 01:49:01 matt Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/mtio.h>
-#include <sys/time.h>
-
-#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <locale.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "dd.h"
-#include "extern.h"
-
-static void dd_close(void);
-static void dd_in(void);
-static void getfdtype(IO *);
-static void redup_clean_fd(IO *);
-static void setup(void);
-
-int main(int, char *[]);
-
-IO		in, out;		/* input/output state */
-STAT		st;			/* statistics */
-void		(*cfunc)(void);		/* conversion function */
-uint64_t	cpy_cnt;		/* # of blocks to copy */
-static off_t	pending = 0;		/* pending seek if sparse */
-u_int		ddflags;		/* conversion options */
-uint64_t	cbsz;			/* conversion block size */
-u_int		files_cnt = 1;		/* # of files to copy */
-uint64_t	progress = 0;		/* display sign of life */
-const u_char	*ctab;			/* conversion table */
-sigset_t	infoset;		/* a set blocking SIGINFO */
-const char	*msgfmt = "posix";	/* default summary() message format */
-
-/*
- * Ops for stdin/stdout and crunch'd dd.  These are always host ops.
- */
-static const struct ddfops ddfops_stdfd = {
-	.op_open = open,
-	.op_close = close,
-	.op_fcntl = fcntl,
-	.op_ioctl = ioctl,
-	.op_fstat = fstat,
-	.op_fsync = fsync,
-	.op_ftruncate = ftruncate,
-	.op_lseek = lseek,
-	.op_read = read,
-	.op_write = write,
-};
-extern const struct ddfops ddfops_prog;
-
-int
-main(int argc, char *argv[])
-{
-	int ch;
-
-	setprogname(argv[0]);
-	(void)setlocale(LC_ALL, "");
-
-	while ((ch = getopt(argc, argv, "")) != -1) {
-		switch (ch) {
-		default:
-			errx(EXIT_FAILURE, "usage: dd [operand ...]");
-			/* NOTREACHED */
-		}
-	}
-	argc -= (optind - 1);
-	argv += (optind - 1);
-
-	jcl(argv);
-#ifndef CRUNCHOPS
-	if (ddfops_prog.op_init && ddfops_prog.op_init() == -1)
-		err(1, "prog init");
-#endif
-	setup();
-
-	(void)signal(SIGINFO, summaryx);
-	(void)signal(SIGINT, terminate);
-	(void)sigemptyset(&infoset);
-	(void)sigaddset(&infoset, SIGINFO);
-
-	(void)atexit(summary);
-
-	while (files_cnt--)
-		dd_in();
-
-	dd_close();
-	exit(0);
-	/* NOTREACHED */
-}
-
-static void
-setup(void)
-{
-#ifdef CRUNCHOPS
-	const struct ddfops *prog_ops = &ddfops_stdfd;
-#else
-	const struct ddfops *prog_ops = &ddfops_prog;
-#endif
-
-	if (in.name == NULL) {
-		in.name = "stdin";
-		in.fd = STDIN_FILENO;
-		in.ops = &ddfops_stdfd;
-	} else {
-		in.ops = prog_ops;
-		in.fd = ddop_open(in, in.name, O_RDONLY, 0);
-		if (in.fd < 0)
-			err(EXIT_FAILURE, "%s", in.name);
-			/* NOTREACHED */
-
-		/* Ensure in.fd is outside the stdio descriptor range */
-		redup_clean_fd(&in);
-	}
-
-	getfdtype(&in);
-
-	if (files_cnt > 1 && !(in.flags & ISTAPE)) {
-		errx(EXIT_FAILURE, "files is not supported for non-tape devices");
-		/* NOTREACHED */
-	}
-
-	if (out.name == NULL) {
-		/* No way to check for read access here. */
-		out.fd = STDOUT_FILENO;
-		out.name = "stdout";
-		out.ops = &ddfops_stdfd;
-	} else {
-		out.ops = prog_ops;
-#define	OFLAGS \
-    (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
-		out.fd = ddop_open(out, out.name, O_RDWR | OFLAGS, DEFFILEMODE);
-		/*
-		 * May not have read access, so try again with write only.
-		 * Without read we may have a problem if output also does
-		 * not support seeks.
-		 */
-		if (out.fd < 0) {
-			out.fd = ddop_open(out, out.name, O_WRONLY | OFLAGS,
-			    DEFFILEMODE);
-			out.flags |= NOREAD;
-		}
-		if (out.fd < 0) {
-			err(EXIT_FAILURE, "%s", out.name);
-			/* NOTREACHED */
-		}
-
-		/* Ensure out.fd is outside the stdio descriptor range */
-		redup_clean_fd(&out);
-	}
-
-	getfdtype(&out);
-
-	/*
-	 * Allocate space for the input and output buffers.  If not doing
-	 * record oriented I/O, only need a single buffer.
-	 */
-	if (!(ddflags & (C_BLOCK|C_UNBLOCK))) {
-		size_t dbsz = out.dbsz;
-		if (!(ddflags & C_BS))
-			dbsz += in.dbsz - 1;
-		if ((in.db = malloc(dbsz)) == NULL) {
-			err(EXIT_FAILURE, NULL);
-			/* NOTREACHED */
-		}
-		out.db = in.db;
-	} else if ((in.db =
-	    malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL ||
-	    (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL) {
-		err(EXIT_FAILURE, NULL);
-		/* NOTREACHED */
-	}
-	in.dbp = in.db;
-	out.dbp = out.db;
-
-	/* Position the input/output streams. */
-	if (in.offset)
-		pos_in();
-	if (out.offset)
-		pos_out();
-
-	/*
-	 * Truncate the output file; ignore errors because it fails on some
-	 * kinds of output files, tapes, for example.
-	 */
-	if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK))
-		(void)ddop_ftruncate(out, out.fd, (off_t)out.offset * out.dbsz);
-
-	/*
-	 * If converting case at the same time as another conversion, build a
-	 * table that does both at once.  If just converting case, use the
-	 * built-in tables.
-	 */
-	if (ddflags & (C_LCASE|C_UCASE)) {
-#ifdef	NO_CONV
-		/* Should not get here, but just in case... */
-		errx(EXIT_FAILURE, "case conv and -DNO_CONV");
-		/* NOTREACHED */
-#else	/* NO_CONV */
-		u_int cnt;
-
-		if (ddflags & C_ASCII || ddflags & C_EBCDIC) {
-			if (ddflags & C_LCASE) {
-				for (cnt = 0; cnt < 256; ++cnt)
-					casetab[cnt] = tolower(ctab[cnt]);
-			} else {
-				for (cnt = 0; cnt < 256; ++cnt)
-					casetab[cnt] = toupper(ctab[cnt]);
-			}
-		} else {
-			if (ddflags & C_LCASE) {
-				for (cnt = 0; cnt < 256; ++cnt)
-					casetab[cnt] = tolower(cnt);
-			} else {
-				for (cnt = 0; cnt < 256; ++cnt)
-					casetab[cnt] = toupper(cnt);
-			}
-		}
-
-		ctab = casetab;
-#endif	/* NO_CONV */
-	}
-
-	(void)gettimeofday(&st.start, NULL);	/* Statistics timestamp. */
-}
-
-static void
-getfdtype(IO *io)
-{
-	struct mtget mt;
-	struct stat sb;
-
-	if (io->ops->op_fstat(io->fd, &sb)) {
-		err(EXIT_FAILURE, "%s", io->name);
-		/* NOTREACHED */
-	}
-	if (S_ISCHR(sb.st_mode))
-		io->flags |= io->ops->op_ioctl(io->fd, MTIOCGET, &mt)
-		    ? ISCHR : ISTAPE;
-	else if (io->ops->op_lseek(io->fd, (off_t)0, SEEK_CUR) == -1
-	    && errno == ESPIPE)
-		io->flags |= ISPIPE;		/* XXX fixed in 4.4BSD */
-}
-
-/*
- * Move the parameter file descriptor to a descriptor that is outside the
- * stdio descriptor range, if necessary.  This is required to avoid
- * accidentally outputting completion or error messages into the
- * output file that were intended for the tty.
- */
-static void
-redup_clean_fd(IO *io)
-{
-	int fd = io->fd;
-	int newfd;
-
-	if (fd != STDIN_FILENO && fd != STDOUT_FILENO &&
-	    fd != STDERR_FILENO)
-		/* File descriptor is ok, return immediately. */
-		return;
-
-	/*
-	 * 3 is the first descriptor greater than STD*_FILENO.  Any
-	 * free descriptor valued 3 or above is acceptable...
-	 */
-	newfd = io->ops->op_fcntl(fd, F_DUPFD, 3);
-	if (newfd < 0) {
-		err(EXIT_FAILURE, "dupfd IO");
-		/* NOTREACHED */
-	}
-
-	io->ops->op_close(fd);
-	io->fd = newfd;
-}
-
-static void
-dd_in(void)
-{
-	int flags;
-	int64_t n;
-
-	for (flags = ddflags;;) {
-		if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt)
-			return;
-
-		/*
-		 * Clear the buffer first if doing "sync" on input.
-		 * If doing block operations use spaces.  This will
-		 * affect not only the C_NOERROR case, but also the
-		 * last partial input block which should be padded
-		 * with zero and not garbage.
-		 */
-		if (flags & C_SYNC) {
-			if (flags & (C_BLOCK|C_UNBLOCK))
-				(void)memset(in.dbp, ' ', in.dbsz);
-			else
-				(void)memset(in.dbp, 0, in.dbsz);
-		}
-
-		n = ddop_read(in, in.fd, in.dbp, in.dbsz);
-		if (n == 0) {
-			in.dbrcnt = 0;
-			return;
-		}
-
-		/* Read error. */
-		if (n < 0) {
-
-			/*
-			 * If noerror not specified, die.  POSIX requires that
-			 * the warning message be followed by an I/O display.
-			 */
-			if (!(flags & C_NOERROR)) {
-				err(EXIT_FAILURE, "%s", in.name);
-				/* NOTREACHED */
-			}
-			warn("%s", in.name);
-			summary();
-
-			/*
-			 * If it's not a tape drive or a pipe, seek past the
-			 * error.  If your OS doesn't do the right thing for
-			 * raw disks this section should be modified to re-read
-			 * in sector size chunks.
-			 */
-			if (!(in.flags & (ISPIPE|ISTAPE)) &&
-			    ddop_lseek(in, in.fd, (off_t)in.dbsz, SEEK_CUR))
-				warn("%s", in.name);
-
-			/* If sync not specified, omit block and continue. */
-			if (!(ddflags & C_SYNC))
-				continue;
-
-			/* Read errors count as full blocks. */
-			in.dbcnt += in.dbrcnt = in.dbsz;
-			++st.in_full;
-
-		/* Handle full input blocks. */
-		} else if ((uint64_t)n == in.dbsz) {
-			in.dbcnt += in.dbrcnt = n;
-			++st.in_full;
-
-		/* Handle partial input blocks. */
-		} else {
-			/* If sync, use the entire block. */
-			if (ddflags & C_SYNC)
-				in.dbcnt += in.dbrcnt = in.dbsz;
-			else
-				in.dbcnt += in.dbrcnt = n;
-			++st.in_part;
-		}
-
-		/*
-		 * POSIX states that if bs is set and no other conversions
-		 * than noerror, notrunc or sync are specified, the block
-		 * is output without buffering as it is read.
-		 */
-		if (ddflags & C_BS) {
-			out.dbcnt = in.dbcnt;
-			dd_out(1);
-			in.dbcnt = 0;
-			continue;
-		}
-
-		if (ddflags & C_SWAB) {
-			if ((n = in.dbrcnt) & 1) {
-				++st.swab;
-				--n;
-			}
-			swab(in.dbp, in.dbp, n);
-		}
-
-		in.dbp += in.dbrcnt;
-		(*cfunc)();
-	}
-}
-
-/*
- * Cleanup any remaining I/O and flush output.  If necessary, output file
- * is truncated.
- */
-static void
-dd_close(void)
-{
-
-	if (cfunc == def)
-		def_close();
-	else if (cfunc == block)
-		block_close();
-	else if (cfunc == unblock)
-		unblock_close();
-	if (ddflags & C_OSYNC && out.dbcnt < out.dbsz) {
-		(void)memset(out.dbp, 0, out.dbsz - out.dbcnt);
-		out.dbcnt = out.dbsz;
-	}
-	/* If there are pending sparse blocks, make sure
-	 * to write out the final block un-sparse
-	 */
-	if ((out.dbcnt == 0) && pending) {
-		memset(out.db, 0, out.dbsz);
-		out.dbcnt = out.dbsz;
-		out.dbp = out.db + out.dbcnt;
-		pending -= out.dbsz;
-	}
-	if (out.dbcnt)
-		dd_out(1);
-
-	/*
-	 * Reporting nfs write error may be deferred until next
-	 * write(2) or close(2) system call.  So, we need to do an
-	 * extra check.  If an output is stdout, the file structure
-	 * may be shared with other processes and close(2) just
-	 * decreases the reference count.
-	 */
-	if (out.fd == STDOUT_FILENO && ddop_fsync(out, out.fd) == -1
-	    && errno != EINVAL) {
-		err(EXIT_FAILURE, "fsync stdout");
-		/* NOTREACHED */
-	}
-	if (ddop_close(out, out.fd) == -1) {
-		err(EXIT_FAILURE, "close");
-		/* NOTREACHED */
-	}
-}
-
-void
-dd_out(int force)
-{
-	static int warned;
-	int64_t cnt, n, nw;
-	u_char *outp;
-
-	/*
-	 * Write one or more blocks out.  The common case is writing a full
-	 * output block in a single write; increment the full block stats.
-	 * Otherwise, we're into partial block writes.  If a partial write,
-	 * and it's a character device, just warn.  If a tape device, quit.
-	 *
-	 * The partial writes represent two cases.  1: Where the input block
-	 * was less than expected so the output block was less than expected.
-	 * 2: Where the input block was the right size but we were forced to
-	 * write the block in multiple chunks.  The original versions of dd(1)
-	 * never wrote a block in more than a single write, so the latter case
-	 * never happened.
-	 *
-	 * One special case is if we're forced to do the write -- in that case
-	 * we play games with the buffer size, and it's usually a partial write.
-	 */
-	outp = out.db;
-	for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) {
-		for (cnt = n;; cnt -= nw) {
-
-			if (!force && ddflags & C_SPARSE) {
-				int sparse, i;
-				sparse = 1;	/* Is buffer sparse? */
-				for (i = 0; i < cnt; i++)
-					if (outp[i] != 0) {
-						sparse = 0;
-						break;
-					}
-				if (sparse) {
-					pending += cnt;
-					outp += cnt;
-					nw = 0;
-					break;
-				}
-			}
-			if (pending != 0) {
-				if (ddop_lseek(out,
-				    out.fd, pending, SEEK_CUR) == -1)
-					err(EXIT_FAILURE, "%s: seek error creating sparse file",
-					    out.name);
-			}
-			nw = bwrite(&out, outp, cnt);
-			if (nw <= 0) {
-				if (nw == 0)
-					errx(EXIT_FAILURE,
-						"%s: end of device", out.name);
-					/* NOTREACHED */
-				if (errno != EINTR)
-					err(EXIT_FAILURE, "%s", out.name);
-					/* NOTREACHED */
-				nw = 0;
-			}
-			if (pending) {
-				st.bytes += pending;
-				st.sparse += pending/out.dbsz;
-				st.out_full += pending/out.dbsz;
-				pending = 0;
-			}
-			outp += nw;
-			st.bytes += nw;
-			if (nw == n) {
-				if ((uint64_t)n != out.dbsz)
-					++st.out_part;
-				else
-					++st.out_full;
-				break;
-			}
-			++st.out_part;
-			if (nw == cnt)
-				break;
-			if (out.flags & ISCHR && !warned) {
-				warned = 1;
-				warnx("%s: short write on character device", out.name);
-			}
-			if (out.flags & ISTAPE)
-				errx(EXIT_FAILURE,
-					"%s: short write on tape device", out.name);
-				/* NOTREACHED */
-
-		}
-		if ((out.dbcnt -= n) < out.dbsz)
-			break;
-	}
-
-	/* Reassemble the output block. */
-	if (out.dbcnt)
-		(void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt);
-	out.dbp = out.db + out.dbcnt;
-
-	if (progress && (st.out_full + st.out_part) % progress == 0)
-		(void)write(STDERR_FILENO, ".", 1);
-}
-
-/*
- * A protected against SIGINFO write
- */
-ssize_t
-bwrite(IO *io, const void *buf, size_t len)
-{
-	sigset_t oset;
-	ssize_t rv;
-	int oerrno;
-
-	(void)sigprocmask(SIG_BLOCK, &infoset, &oset);
-	rv = io->ops->op_write(io->fd, buf, len);
-	oerrno = errno;
-	(void)sigprocmask(SIG_SETMASK, &oset, NULL);
-	errno = oerrno;
-	return (rv);
-}
diff --git a/toolbox/upstream-netbsd/bin/dd/dd.h b/toolbox/upstream-netbsd/bin/dd/dd.h
deleted file mode 100644
index b01c7b3..0000000
--- a/toolbox/upstream-netbsd/bin/dd/dd.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/*	$NetBSD: dd.h,v 1.15 2011/02/04 19:42:12 pooka Exp $	*/
-
-/*-
- * Copyright (c) 1991, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego and Lance
- * Visser of Convex Computer Corporation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)dd.h	8.3 (Berkeley) 4/2/94
- */
-
-#include <sys/stat.h>
-
-struct ddfops {
-	int (*op_init)(void);
-
-	int (*op_open)(const char *, int, ...);
-	int (*op_close)(int);
-
-	int (*op_fcntl)(int, int, ...);
-#ifdef __ANDROID__
-	int (*op_ioctl)(int, int, ...);
-#else
-	int (*op_ioctl)(int, unsigned long, ...);
-#endif
-
-	int (*op_fstat)(int, struct stat *);
-	int (*op_fsync)(int);
-	int (*op_ftruncate)(int, off_t);
-
-	off_t (*op_lseek)(int, off_t, int);
-
-	ssize_t (*op_read)(int, void *, size_t);
-	ssize_t (*op_write)(int, const void *, size_t);
-};
-
-#define ddop_open(dir, a1, a2, ...)	dir.ops->op_open(a1, a2, __VA_ARGS__)
-#define ddop_close(dir, a1)		dir.ops->op_close(a1)
-#define ddop_fcntl(dir, a1, a2, ...)	dir.ops->op_fcntl(a1, a2, __VA_ARGS__)
-#define ddop_ioctl(dir, a1, a2, ...)	dir.ops->op_ioctl(a1, a2, __VA_ARGS__)
-#define ddop_fsync(dir, a1)		dir.ops->op_fsync(a1)
-#define ddop_ftruncate(dir, a1, a2)	dir.ops->op_ftruncate(a1, a2)
-#define ddop_lseek(dir, a1, a2, a3)	dir.ops->op_lseek(a1, a2, a3)
-#define ddop_read(dir, a1, a2, a3)	dir.ops->op_read(a1, a2, a3)
-#define ddop_write(dir, a1, a2, a3)	dir.ops->op_write(a1, a2, a3)
-
-/* Input/output stream state. */
-typedef struct {
-	u_char		*db;		/* buffer address */
-	u_char		*dbp;		/* current buffer I/O address */
-	uint64_t	dbcnt;		/* current buffer byte count */
-	int64_t		dbrcnt;		/* last read byte count */
-	uint64_t	dbsz;		/* buffer size */
-
-#define	ISCHR		0x01		/* character device (warn on short) */
-#define	ISPIPE		0x02		/* pipe (not truncatable) */
-#define	ISTAPE		0x04		/* tape (not seekable) */
-#define	NOREAD		0x08		/* not readable */
-	u_int		flags;
-
-	const char  	*name;		/* name */
-	int		fd;		/* file descriptor */
-	uint64_t	offset;		/* # of blocks to skip */
-	struct ddfops	const *ops;	/* ops to use with fd */
-} IO;
-
-typedef struct {
-	uint64_t	in_full;	/* # of full input blocks */
-	uint64_t	in_part;	/* # of partial input blocks */
-	uint64_t	out_full;	/* # of full output blocks */
-	uint64_t	out_part;	/* # of partial output blocks */
-	uint64_t	trunc;		/* # of truncated records */
-	uint64_t	swab;		/* # of odd-length swab blocks */
-	uint64_t	sparse;		/* # of sparse output blocks */
-	uint64_t	bytes;		/* # of bytes written */
-	struct timeval	start;		/* start time of dd */
-} STAT;
-
-/* Flags (in ddflags). */
-#define	C_ASCII		0x00001
-#define	C_BLOCK		0x00002
-#define	C_BS		0x00004
-#define	C_CBS		0x00008
-#define	C_COUNT		0x00010
-#define	C_EBCDIC	0x00020
-#define	C_FILES		0x00040
-#define	C_IBS		0x00080
-#define	C_IF		0x00100
-#define	C_LCASE		0x00200
-#define	C_NOERROR	0x00400
-#define	C_NOTRUNC	0x00800
-#define	C_OBS		0x01000
-#define	C_OF		0x02000
-#define	C_SEEK		0x04000
-#define	C_SKIP		0x08000
-#define	C_SWAB		0x10000
-#define	C_SYNC		0x20000
-#define	C_UCASE		0x40000
-#define	C_UNBLOCK	0x80000
-#define	C_OSYNC		0x100000
-#define	C_SPARSE	0x200000
diff --git a/toolbox/upstream-netbsd/bin/dd/dd_hostops.c b/toolbox/upstream-netbsd/bin/dd/dd_hostops.c
deleted file mode 100644
index d6e7a89..0000000
--- a/toolbox/upstream-netbsd/bin/dd/dd_hostops.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*      $NetBSD: dd_hostops.c,v 1.1 2011/02/04 19:42:12 pooka Exp $	*/
-
-/*-
- * Copyright (c) 2010 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-__RCSID("$NetBSD: dd_hostops.c,v 1.1 2011/02/04 19:42:12 pooka Exp $");
-#endif /* !lint */
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-
-#include <fcntl.h>
-#include <unistd.h>
-
-#include "dd.h"
-
-const struct ddfops ddfops_prog = {
-	.op_open = open,
-	.op_close = close,
-	.op_fcntl = fcntl,
-	.op_ioctl = ioctl,
-	.op_fstat = fstat,
-	.op_fsync = fsync,
-	.op_ftruncate = ftruncate,
-	.op_lseek = lseek,
-	.op_read = read,
-	.op_write = write,
-};
diff --git a/toolbox/upstream-netbsd/bin/dd/extern.h b/toolbox/upstream-netbsd/bin/dd/extern.h
deleted file mode 100644
index 9c59021..0000000
--- a/toolbox/upstream-netbsd/bin/dd/extern.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*	$NetBSD: extern.h,v 1.22 2011/11/07 22:24:23 jym Exp $	*/
-
-/*-
- * Copyright (c) 1991, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego and Lance
- * Visser of Convex Computer Corporation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)extern.h	8.3 (Berkeley) 4/2/94
- */
-
-#include <sys/cdefs.h>
-
-#ifdef NO_CONV
-__dead void block(void);
-__dead void block_close(void);
-__dead void unblock(void);
-__dead void unblock_close(void);
-#else
-void block(void);
-void block_close(void);
-void unblock(void);
-void unblock_close(void);
-#endif
-
-#ifndef NO_MSGFMT
-int dd_write_msg(const char *, int);
-#endif
-
-void dd_out(int);
-void def(void);
-void def_close(void);
-void jcl(char **);
-void pos_in(void);
-void pos_out(void);
-void summary(void);
-void summaryx(int);
-__dead void terminate(int);
-void unblock(void);
-void unblock_close(void);
-ssize_t bwrite(IO *, const void *, size_t);
-
-extern IO		in, out;
-extern STAT		st;
-extern void		(*cfunc)(void);
-extern uint64_t		cpy_cnt;
-extern uint64_t		cbsz;
-extern u_int		ddflags;
-extern u_int		files_cnt;
-extern uint64_t		progress;
-extern const u_char	*ctab;
-extern const u_char	a2e_32V[], a2e_POSIX[];
-extern const u_char	e2a_32V[], e2a_POSIX[];
-extern const u_char	a2ibm_32V[], a2ibm_POSIX[];
-extern u_char		casetab[];
-extern const char	*msgfmt;
diff --git a/toolbox/upstream-netbsd/bin/dd/misc.c b/toolbox/upstream-netbsd/bin/dd/misc.c
deleted file mode 100644
index 0fac98b..0000000
--- a/toolbox/upstream-netbsd/bin/dd/misc.c
+++ /dev/null
@@ -1,342 +0,0 @@
-/*	$NetBSD: misc.c,v 1.23 2011/11/07 22:24:23 jym Exp $	*/
-
-/*-
- * Copyright (c) 1991, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego and Lance
- * Visser of Convex Computer Corporation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)misc.c	8.3 (Berkeley) 4/2/94";
-#else
-__RCSID("$NetBSD: misc.c,v 1.23 2011/11/07 22:24:23 jym Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/time.h>
-
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <util.h>
-#include <inttypes.h>
-
-#include "dd.h"
-#include "extern.h"
-
-#define	tv2mS(tv) ((tv).tv_sec * 1000LL + ((tv).tv_usec + 500) / 1000)
-
-static void posix_summary(void);
-#ifndef NO_MSGFMT
-static void custom_summary(void);
-static void human_summary(void);
-static void quiet_summary(void);
-
-static void buffer_write(const char *, size_t, int);
-#endif /* NO_MSGFMT */
-
-void
-summary(void)
-{
-
-	if (progress)
-		(void)write(STDERR_FILENO, "\n", 1);
-
-#ifdef NO_MSGFMT
-	return posix_summary();
-#else /* NO_MSGFMT */
-	if (strncmp(msgfmt, "human", sizeof("human")) == 0)
-		return human_summary();
-
-	if (strncmp(msgfmt, "posix", sizeof("posix")) == 0)
-		return posix_summary();
-
-	if (strncmp(msgfmt, "quiet", sizeof("quiet")) == 0)
-		return quiet_summary();
-
-	return custom_summary();
-#endif /* NO_MSGFMT */
-}
-
-static void
-posix_summary(void)
-{
-	char buf[100];
-	int64_t mS;
-	struct timeval tv;
-
-	if (progress)
-		(void)write(STDERR_FILENO, "\n", 1);
-
-	(void)gettimeofday(&tv, NULL);
-	mS = tv2mS(tv) - tv2mS(st.start);
-	if (mS == 0)
-		mS = 1;
-
-	/* Use snprintf(3) so that we don't reenter stdio(3). */
-	(void)snprintf(buf, sizeof(buf),
-	    "%llu+%llu records in\n%llu+%llu records out\n",
-	    (unsigned long long)st.in_full,  (unsigned long long)st.in_part,
-	    (unsigned long long)st.out_full, (unsigned long long)st.out_part);
-	(void)write(STDERR_FILENO, buf, strlen(buf));
-	if (st.swab) {
-		(void)snprintf(buf, sizeof(buf), "%llu odd length swab %s\n",
-		    (unsigned long long)st.swab,
-		    (st.swab == 1) ? "block" : "blocks");
-		(void)write(STDERR_FILENO, buf, strlen(buf));
-	}
-	if (st.trunc) {
-		(void)snprintf(buf, sizeof(buf), "%llu truncated %s\n",
-		    (unsigned long long)st.trunc,
-		    (st.trunc == 1) ? "block" : "blocks");
-		(void)write(STDERR_FILENO, buf, strlen(buf));
-	}
-	if (st.sparse) {
-		(void)snprintf(buf, sizeof(buf), "%llu sparse output %s\n",
-		    (unsigned long long)st.sparse,
-		    (st.sparse == 1) ? "block" : "blocks");
-		(void)write(STDERR_FILENO, buf, strlen(buf));
-	}
-	(void)snprintf(buf, sizeof(buf),
-	    "%llu bytes transferred in %lu.%03d secs (%llu bytes/sec)\n",
-	    (unsigned long long) st.bytes,
-	    (long) (mS / 1000),
-	    (int) (mS % 1000),
-	    (unsigned long long) (st.bytes * 1000LL / mS));
-	(void)write(STDERR_FILENO, buf, strlen(buf));
-}
-
-/* ARGSUSED */
-void
-summaryx(int notused)
-{
-
-	summary();
-}
-
-/* ARGSUSED */
-void
-terminate(int signo)
-{
-
-	summary();
-	(void)raise_default_signal(signo);
-	_exit(127);
-}
-
-#ifndef NO_MSGFMT
-/*
- * Buffer write(2) calls
- */
-static void
-buffer_write(const char *str, size_t size, int flush)
-{
-	static char wbuf[128];
-	static size_t cnt = 0; /* Internal counter to allow wbuf to wrap */
-	
-	unsigned int i;
-
-	for (i = 0; i < size; i++) {
-		if (str != NULL) {
-			wbuf[cnt++] = str[i];
-		}
-		if (cnt >= sizeof(wbuf)) {
-			(void)write(STDERR_FILENO, wbuf, cnt);
-			cnt = 0;
-		}
-	}
-
-	if (flush != 0) {
-		(void)write(STDERR_FILENO, wbuf, cnt);
-		cnt = 0;
-	}
-}
-
-/*
- * Write summary to stderr according to format 'fmt'. If 'enable' is 0, it
- * will not attempt to write anything. Can be used to validate the
- * correctness of the 'fmt' string.
- */
-int
-dd_write_msg(const char *fmt, int enable)
-{
-	char hbuf[7], nbuf[32];
-	const char *ptr;
-	int64_t mS;
-	struct timeval tv;
-
-	(void)gettimeofday(&tv, NULL);
-	mS = tv2mS(tv) - tv2mS(st.start);
-	if (mS == 0)
-		mS = 1;
-
-#define ADDC(c) do { if (enable != 0) buffer_write(&c, 1, 0); } \
-	while (/*CONSTCOND*/0)
-#define ADDS(p) do { if (enable != 0) buffer_write(p, strlen(p), 0); } \
-	while (/*CONSTCOND*/0)
-
-	for (ptr = fmt; *ptr; ptr++) {
-		if (*ptr != '%') {
-			ADDC(*ptr);
-			continue;
-		}
-
- 		switch (*++ptr) {
-		case 'b':
-			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
-			    (unsigned long long)st.bytes);
-			ADDS(nbuf);
-			break;
-		case 'B':
-			if (humanize_number(hbuf, sizeof(hbuf),
-			    st.bytes, "B",
-			    HN_AUTOSCALE, HN_DECIMAL) == -1)
-				warnx("humanize_number (bytes transferred)");
-			ADDS(hbuf);
-			break;
-		case 'e':
-			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
-			    (unsigned long long) (st.bytes * 1000LL / mS));
-			ADDS(nbuf);
-			break;
-		case 'E':
-			if (humanize_number(hbuf, sizeof(hbuf),
-			    st.bytes * 1000LL / mS, "B",
-			    HN_AUTOSCALE, HN_DECIMAL) == -1)
-				warnx("humanize_number (bytes per second)");
-			ADDS(hbuf); ADDS("/sec");
-			break;
-		case 'i':
-			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
-			    (unsigned long long)st.in_part);
-			ADDS(nbuf);
-			break;
-		case 'I':
-			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
-			    (unsigned long long)st.in_full);
-			ADDS(nbuf);
-			break;
-		case 'o':
-			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
-			    (unsigned long long)st.out_part);
-			ADDS(nbuf);
-			break;
-		case 'O':
-			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
-			    (unsigned long long)st.out_full);
-			ADDS(nbuf);
-			break;
-		case 's':
-			(void)snprintf(nbuf, sizeof(nbuf), "%li.%03d",
-			    (long) (mS / 1000), (int) (mS % 1000));
-			ADDS(nbuf);
-			break;
-		case 'p':
-			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
-			    (unsigned long long)st.sparse);
-			ADDS(nbuf);
-			break;
-		case 't':
-			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
-			    (unsigned long long)st.trunc);
-			ADDS(nbuf);
-			break;
-		case 'w':
-			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
-			    (unsigned long long)st.swab);
-			ADDS(nbuf);
-			break;
-		case 'P':
-			ADDS("block");
-			if (st.sparse != 1) ADDS("s");
-			break;
-		case 'T':
-			ADDS("block");
-			if (st.trunc != 1) ADDS("s");
-			break;
-		case 'W':
-			ADDS("block");
-			if (st.swab != 1) ADDS("s");
-			break;
-		case '%':
-			ADDC(*ptr);
-			break;
-		default:
-			if (*ptr == '\0')
-				goto done;
-			errx(EXIT_FAILURE, "unknown specifier '%c' in "
-			    "msgfmt string", *ptr);
-			/* NOTREACHED */
-		}
-	}
-
-done:
-	/* flush buffer */
-	buffer_write(NULL, 0, 1);
-	return 0;
-}
-
-static void
-custom_summary(void)
-{
-
-	dd_write_msg(msgfmt, 1);
-}
-
-static void
-human_summary(void)
-{
-	(void)dd_write_msg("%I+%i records in\n%O+%o records out\n", 1);
-	if (st.swab) {
-		(void)dd_write_msg("%w odd length swab %W\n", 1);
-	}
-	if (st.trunc) {
-		(void)dd_write_msg("%t truncated %T\n", 1);
-	}
-	if (st.sparse) {
-		(void)dd_write_msg("%p sparse output %P\n", 1);
-	}
-	(void)dd_write_msg("%b bytes (%B) transferred in %s secs "
-	    "(%e bytes/sec - %E)\n", 1);
-}
-
-static void
-quiet_summary(void)
-{
-
-	/* stay quiet */
-}
-#endif /* NO_MSGFMT */
diff --git a/toolbox/upstream-netbsd/bin/dd/position.c b/toolbox/upstream-netbsd/bin/dd/position.c
deleted file mode 100644
index 36dd580..0000000
--- a/toolbox/upstream-netbsd/bin/dd/position.c
+++ /dev/null
@@ -1,185 +0,0 @@
-/*	$NetBSD: position.c,v 1.18 2010/11/22 21:04:28 pooka Exp $	*/
-
-/*-
- * Copyright (c) 1991, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego and Lance
- * Visser of Convex Computer Corporation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)position.c	8.3 (Berkeley) 4/2/94";
-#else
-__RCSID("$NetBSD: position.c,v 1.18 2010/11/22 21:04:28 pooka Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/mtio.h>
-#include <sys/time.h>
-
-#include <err.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "dd.h"
-#include "extern.h"
-
-/*
- * Position input/output data streams before starting the copy.  Device type
- * dependent.  Seekable devices use lseek, and the rest position by reading.
- * Seeking past the end of file can cause null blocks to be written to the
- * output.
- */
-void
-pos_in(void)
-{
-	int bcnt, cnt, nr, warned;
-
-	/* If not a pipe or tape device, try to seek on it. */
-	if (!(in.flags & (ISPIPE|ISTAPE))) {
-		if (ddop_lseek(in, in.fd,
-		    (off_t)in.offset * (off_t)in.dbsz, SEEK_CUR) == -1) {
-			err(EXIT_FAILURE, "%s", in.name);
-			/* NOTREACHED */
-		}
-		return;
-		/* NOTREACHED */
-	}
-
-	/*
-	 * Read the data.  If a pipe, read until satisfy the number of bytes
-	 * being skipped.  No differentiation for reading complete and partial
-	 * blocks for other devices.
-	 */
-	for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) {
-		if ((nr = ddop_read(in, in.fd, in.db, bcnt)) > 0) {
-			if (in.flags & ISPIPE) {
-				if (!(bcnt -= nr)) {
-					bcnt = in.dbsz;
-					--cnt;
-				}
-			} else
-				--cnt;
-			continue;
-		}
-
-		if (nr == 0) {
-			if (files_cnt > 1) {
-				--files_cnt;
-				continue;
-			}
-			errx(EXIT_FAILURE, "skip reached end of input");
-			/* NOTREACHED */
-		}
-
-		/*
-		 * Input error -- either EOF with no more files, or I/O error.
-		 * If noerror not set die.  POSIX requires that the warning
-		 * message be followed by an I/O display.
-		 */
-		if (ddflags & C_NOERROR) {
-			if (!warned) {
-
-				warn("%s", in.name);
-				warned = 1;
-				summary();
-			}
-			continue;
-		}
-		err(EXIT_FAILURE, "%s", in.name);
-		/* NOTREACHED */
-	}
-}
-
-void
-pos_out(void)
-{
-	struct mtop t_op;
-	int n;
-	uint64_t cnt;
-
-	/*
-	 * If not a tape, try seeking on the file.  Seeking on a pipe is
-	 * going to fail, but don't protect the user -- they shouldn't
-	 * have specified the seek operand.
-	 */
-	if (!(out.flags & ISTAPE)) {
-		if (ddop_lseek(out, out.fd,
-		    (off_t)out.offset * (off_t)out.dbsz, SEEK_SET) == -1)
-			err(EXIT_FAILURE, "%s", out.name);
-			/* NOTREACHED */
-		return;
-	}
-
-	/* If no read access, try using mtio. */
-	if (out.flags & NOREAD) {
-		t_op.mt_op = MTFSR;
-		t_op.mt_count = out.offset;
-
-		if (ddop_ioctl(out, out.fd, MTIOCTOP, &t_op) < 0)
-			err(EXIT_FAILURE, "%s", out.name);
-			/* NOTREACHED */
-		return;
-	}
-
-	/* Read it. */
-	for (cnt = 0; cnt < out.offset; ++cnt) {
-		if ((n = ddop_read(out, out.fd, out.db, out.dbsz)) > 0)
-			continue;
-
-		if (n < 0)
-			err(EXIT_FAILURE, "%s", out.name);
-			/* NOTREACHED */
-
-		/*
-		 * If reach EOF, fill with NUL characters; first, back up over
-		 * the EOF mark.  Note, cnt has not yet been incremented, so
-		 * the EOF read does not count as a seek'd block.
-		 */
-		t_op.mt_op = MTBSR;
-		t_op.mt_count = 1;
-		if (ddop_ioctl(out, out.fd, MTIOCTOP, &t_op) == -1)
-			err(EXIT_FAILURE, "%s", out.name);
-			/* NOTREACHED */
-
-		while (cnt++ < out.offset)
-			if ((uint64_t)(n = bwrite(&out,
-			    out.db, out.dbsz)) != out.dbsz)
-				err(EXIT_FAILURE, "%s", out.name);
-				/* NOTREACHED */
-		break;
-	}
-}
diff --git a/toolbox/upstream-netbsd/include/namespace.h b/toolbox/upstream-netbsd/include/namespace.h
deleted file mode 100644
index e69de29..0000000
--- a/toolbox/upstream-netbsd/include/namespace.h
+++ /dev/null
diff --git a/toolbox/upstream-netbsd/include/sys/extattr.h b/toolbox/upstream-netbsd/include/sys/extattr.h
deleted file mode 100644
index e69de29..0000000
--- a/toolbox/upstream-netbsd/include/sys/extattr.h
+++ /dev/null
diff --git a/toolbox/upstream-netbsd/include/util.h b/toolbox/upstream-netbsd/include/util.h
deleted file mode 100644
index e69de29..0000000
--- a/toolbox/upstream-netbsd/include/util.h
+++ /dev/null
diff --git a/toolbox/upstream-netbsd/lib/libc/gen/getbsize.c b/toolbox/upstream-netbsd/lib/libc/gen/getbsize.c
deleted file mode 100644
index a9ce2c1..0000000
--- a/toolbox/upstream-netbsd/lib/libc/gen/getbsize.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*	$NetBSD: getbsize.c,v 1.17 2012/06/25 22:32:43 abs Exp $	*/
-
-/*-
- * Copyright (c) 1991, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-#if 0
-static char sccsid[] = "@(#)getbsize.c	8.1 (Berkeley) 6/4/93";
-#else
-__RCSID("$NetBSD: getbsize.c,v 1.17 2012/06/25 22:32:43 abs Exp $");
-#endif
-#endif /* not lint */
-
-#include "namespace.h"
-
-#include <assert.h>
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef __weak_alias
-__weak_alias(getbsize,_getbsize)
-#endif
-
-char *
-getbsize(int *headerlenp, long *blocksizep)
-{
-	static char header[20];
-	long n, max, mul, blocksize;
-	char *ep, *p;
-	const char *form;
-
-#define	KB	(1024L)
-#define	MB	(1024L * 1024L)
-#define	GB	(1024L * 1024L * 1024L)
-#define	MAXB	GB		/* No tera, peta, nor exa. */
-	form = "";
-	if ((p = getenv("BLOCKSIZE")) != NULL && *p != '\0') {
-		if ((n = strtol(p, &ep, 10)) < 0)
-			goto underflow;
-		if (n == 0)
-			n = 1;
-		if (*ep && ep[1])
-			goto fmterr;
-		switch (*ep) {
-		case 'G': case 'g':
-			form = "G";
-			max = MAXB / GB;
-			mul = GB;
-			break;
-		case 'K': case 'k':
-			form = "K";
-			max = MAXB / KB;
-			mul = KB;
-			break;
-		case 'M': case 'm':
-			form = "M";
-			max = MAXB / MB;
-			mul = MB;
-			break;
-		case '\0':
-			max = MAXB;
-			mul = 1;
-			break;
-		default:
-fmterr:			warnx("%s: unknown blocksize", p);
-			n = 512;
-			mul = 1;
-			max = 0;
-			break;
-		}
-		if (n > max) {
-			warnx("maximum blocksize is %ldG", MAXB / GB);
-			n = max;
-		}
-		if ((blocksize = n * mul) < 512) {
-underflow:		warnx("%s: minimum blocksize is 512", p);
-			form = "";
-			blocksize = n = 512;
-		}
-	} else
-		blocksize = n = 512;
-
-	if (headerlenp)
-		*headerlenp =
-		    snprintf(header, sizeof(header), "%ld%s-blocks", n, form);
-	if (blocksizep)
-		*blocksizep = blocksize;
-	return (header);
-}
diff --git a/toolbox/upstream-netbsd/lib/libc/gen/humanize_number.c b/toolbox/upstream-netbsd/lib/libc/gen/humanize_number.c
deleted file mode 100644
index 533560f..0000000
--- a/toolbox/upstream-netbsd/lib/libc/gen/humanize_number.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*	$NetBSD: humanize_number.c,v 1.16 2012/03/17 20:01:14 christos Exp $	*/
-
-/*
- * Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
- * NASA Ames Research Center, by Luke Mewburn and by Tomas Svensson.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: humanize_number.c,v 1.16 2012/03/17 20:01:14 christos Exp $");
-#endif /* LIBC_SCCS and not lint */
-
-#include "namespace.h"
-#include <assert.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <locale.h>
-
-int
-humanize_number(char *buf, size_t len, int64_t bytes,
-    const char *suffix, int scale, int flags)
-{
-	const char *prefixes, *sep;
-	int	b, r, s1, s2, sign;
-	int64_t	divisor, max, post = 1;
-	size_t	i, baselen, maxscale;
-
-	_DIAGASSERT(buf != NULL);
-	_DIAGASSERT(suffix != NULL);
-	_DIAGASSERT(scale >= 0);
-
-	if (flags & HN_DIVISOR_1000) {
-		/* SI for decimal multiplies */
-		divisor = 1000;
-		if (flags & HN_B)
-			prefixes = "B\0k\0M\0G\0T\0P\0E";
-		else
-			prefixes = "\0\0k\0M\0G\0T\0P\0E";
-	} else {
-		/*
-		 * binary multiplies
-		 * XXX IEC 60027-2 recommends Ki, Mi, Gi...
-		 */
-		divisor = 1024;
-		if (flags & HN_B)
-			prefixes = "B\0K\0M\0G\0T\0P\0E";
-		else
-			prefixes = "\0\0K\0M\0G\0T\0P\0E";
-	}
-
-#define	SCALE2PREFIX(scale)	(&prefixes[(scale) << 1])
-	maxscale = 7;
-
-	if ((size_t)scale >= maxscale &&
-	    (scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0)
-		return (-1);
-
-	if (buf == NULL || suffix == NULL)
-		return (-1);
-
-	if (len > 0)
-		buf[0] = '\0';
-	if (bytes < 0) {
-		sign = -1;
-		baselen = 3;		/* sign, digit, prefix */
-		if (-bytes < INT64_MAX / 100)
-			bytes *= -100;
-		else {
-			bytes = -bytes;
-			post = 100;
-			baselen += 2;
-		}
-	} else {
-		sign = 1;
-		baselen = 2;		/* digit, prefix */
-		if (bytes < INT64_MAX / 100)
-			bytes *= 100;
-		else {
-			post = 100;
-			baselen += 2;
-		}
-	}
-	if (flags & HN_NOSPACE)
-		sep = "";
-	else {
-		sep = " ";
-		baselen++;
-	}
-	baselen += strlen(suffix);
-
-	/* Check if enough room for `x y' + suffix + `\0' */
-	if (len < baselen + 1)
-		return (-1);
-
-	if (scale & (HN_AUTOSCALE | HN_GETSCALE)) {
-		/* See if there is additional columns can be used. */
-		for (max = 100, i = len - baselen; i-- > 0;)
-			max *= 10;
-
-		/*
-		 * Divide the number until it fits the given column.
-		 * If there will be an overflow by the rounding below,
-		 * divide once more.
-		 */
-		for (i = 0; bytes >= max - 50 && i < maxscale; i++)
-			bytes /= divisor;
-
-		if (scale & HN_GETSCALE) {
-			_DIAGASSERT(__type_fit(int, i));
-			return (int)i;
-		}
-	} else
-		for (i = 0; i < (size_t)scale && i < maxscale; i++)
-			bytes /= divisor;
-	bytes *= post;
-
-	/* If a value <= 9.9 after rounding and ... */
-	if (bytes < 995 && i > 0 && flags & HN_DECIMAL) {
-		/* baselen + \0 + .N */
-		if (len < baselen + 1 + 2)
-			return (-1);
-		b = ((int)bytes + 5) / 10;
-		s1 = b / 10;
-		s2 = b % 10;
-		r = snprintf(buf, len, "%d%s%d%s%s%s",
-		    sign * s1, localeconv()->decimal_point, s2,
-		    sep, SCALE2PREFIX(i), suffix);
-	} else
-		r = snprintf(buf, len, "%" PRId64 "%s%s%s",
-		    sign * ((bytes + 50) / 100),
-		    sep, SCALE2PREFIX(i), suffix);
-
-	return (r);
-}
diff --git a/toolbox/upstream-netbsd/lib/libc/stdlib/strsuftoll.c b/toolbox/upstream-netbsd/lib/libc/stdlib/strsuftoll.c
deleted file mode 100644
index 80fc52f..0000000
--- a/toolbox/upstream-netbsd/lib/libc/stdlib/strsuftoll.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/*	$NetBSD: strsuftoll.c,v 1.9 2011/10/22 22:08:47 christos Exp $	*/
-/*-
- * Copyright (c) 2001-2002,2004 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Luke Mewburn.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-/*-
- * Copyright (c) 1991, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego and Lance
- * Visser of Convex Computer Corporation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if HAVE_NBTOOL_CONFIG_H
-#include "nbtool_config.h"
-#endif
-
-#include <sys/cdefs.h>
-
-#if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: strsuftoll.c,v 1.9 2011/10/22 22:08:47 christos Exp $");
-#endif /* LIBC_SCCS and not lint */
-
-#ifdef _LIBC
-#include "namespace.h"
-#endif
-
-#if !HAVE_STRSUFTOLL
-
-#include <sys/types.h>
-#include <sys/time.h>
-
-#include <assert.h>
-#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef _LIBC
-# ifdef __weak_alias
-__weak_alias(strsuftoll, _strsuftoll)
-__weak_alias(strsuftollx, _strsuftollx)
-# endif
-#endif /* LIBC */
-
-/*
- * Convert an expression of the following forms to a (u)int64_t.
- * 	1) A positive decimal number.
- *	2) A positive decimal number followed by a b (mult by 512).
- *	3) A positive decimal number followed by a k (mult by 1024).
- *	4) A positive decimal number followed by a m (mult by 1048576).
- *	5) A positive decimal number followed by a g (mult by 1073741824).
- *	6) A positive decimal number followed by a t (mult by 1099511627776).
- *	7) A positive decimal number followed by a w (mult by sizeof int)
- *	8) Two or more positive decimal numbers (with/without k,b or w).
- *	   separated by x (also * for backwards compatibility), specifying
- *	   the product of the indicated values.
- * Returns the result upon successful conversion, or exits with an
- * appropriate error.
- * 
- */
-/* LONGLONG */
-long long
-strsuftoll(const char *desc, const char *val,
-    long long min, long long max)
-{
-	long long result;
-	char	errbuf[100];
-
-	result = strsuftollx(desc, val, min, max, errbuf, sizeof(errbuf));
-	if (*errbuf != '\0')
-		errx(EXIT_FAILURE, "%s", errbuf);
-	return result;
-}
-
-/*
- * As strsuftoll(), but returns the error message into the provided buffer
- * rather than exiting with it.
- */
-/* LONGLONG */
-static long long
-__strsuftollx(const char *desc, const char *val,
-    long long min, long long max, char *ebuf, size_t ebuflen, size_t depth)
-{
-	long long num, t;
-	char	*expr;
-
-	_DIAGASSERT(desc != NULL);
-	_DIAGASSERT(val != NULL);
-	_DIAGASSERT(ebuf != NULL);
-
-	if (depth > 16) {
-		snprintf(ebuf, ebuflen, "%s: Recursion limit exceeded", desc);
-		return 0;
-	}
-
-	while (isspace((unsigned char)*val))	/* Skip leading space */
-		val++;
-
-	errno = 0;
-	num = strtoll(val, &expr, 10);
-	if (errno == ERANGE)
-		goto erange;			/* Overflow */
-
-	if (expr == val)			/* No digits */
-		goto badnum;
-
-	switch (*expr) {
-	case 'b':
-		t = num;
-		num *= 512;			/* 1 block */
-		if (t > num)
-			goto erange;
-		++expr;
-		break;
-	case 'k':
-		t = num;
-		num *= 1024;			/* 1 kibibyte */
-		if (t > num)
-			goto erange;
-		++expr;
-		break;
-	case 'm':
-		t = num;
-		num *= 1048576;			/* 1 mebibyte */
-		if (t > num)
-			goto erange;
-		++expr;
-		break;
-	case 'g':
-		t = num;
-		num *= 1073741824;		/* 1 gibibyte */
-		if (t > num)
-			goto erange;
-		++expr;
-		break;
-	case 't':
-		t = num;
-		num *= 1099511627776LL;		/* 1 tebibyte */
-		if (t > num)
-			goto erange;
-		++expr;
-		break;
-	case 'w':
-		t = num;
-		num *= sizeof(int);		/* 1 word */
-		if (t > num)
-			goto erange;
-		++expr;
-		break;
-	}
-
-	switch (*expr) {
-	case '\0':
-		break;
-	case '*':				/* Backward compatible */
-	case 'x':
-		t = num;
-		num *= __strsuftollx(desc, expr + 1, min, max, ebuf, ebuflen,
-			depth + 1);
-		if (*ebuf != '\0')
-			return 0;
-		if (t > num) {
- erange:	 	
-			errno = ERANGE;
-			snprintf(ebuf, ebuflen, "%s: %s", desc, strerror(errno));
-			return 0;
-		}
-		break;
-	default:
- badnum:
-		snprintf(ebuf, ebuflen, "%s `%s': illegal number", desc, val);
-		return 0;
-	}
-	if (num < min) {
-		/* LONGLONG */
-		snprintf(ebuf, ebuflen, "%s %lld is less than %lld.",
-		    desc, (long long)num, (long long)min);
-		return 0;
-	}
-	if (num > max) {
-		/* LONGLONG */
-		snprintf(ebuf, ebuflen, "%s %lld is greater than %lld.",
-		    desc, (long long)num, (long long)max);
-		return 0;
-	}
-	*ebuf = '\0';
-	return num;
-}
-
-long long
-strsuftollx(const char *desc, const char *val,
-    long long min, long long max, char *ebuf, size_t ebuflen)
-{
-	return __strsuftollx(desc, val, min, max, ebuf, ebuflen, 0);
-}
-#endif /* !HAVE_STRSUFTOLL */
diff --git a/toolbox/upstream-netbsd/lib/libc/string/swab.c b/toolbox/upstream-netbsd/lib/libc/string/swab.c
deleted file mode 100644
index 392b186..0000000
--- a/toolbox/upstream-netbsd/lib/libc/string/swab.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*	$NetBSD: swab.c,v 1.18 2011/01/04 17:14:07 martin Exp $	*/
-
-/*
- * Copyright (c) 1988, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Jeffrey Mogul.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-#if 0
-static char sccsid[] = "@(#)swab.c	8.1 (Berkeley) 6/4/93";
-#else
-__RCSID("$NetBSD: swab.c,v 1.18 2011/01/04 17:14:07 martin Exp $");
-#endif
-#endif /* LIBC_SCCS and not lint */
-
-#include <assert.h>
-#include <unistd.h>
-
-void
-swab(const void * __restrict from, void * __restrict to, ssize_t len)
-{
-	char temp;
-	const char *fp;
-	char *tp;
-
-	if (len <= 1)
-		return;
-
-	_DIAGASSERT(from != NULL);
-	_DIAGASSERT(to != NULL);
-
-	len /= 2;
-	fp = (const char *)from;
-	tp = (char *)to;
-#define	STEP	temp = *fp++,*tp++ = *fp++,*tp++ = temp
-
-	if (__predict_false(len == 1)) {
-		STEP;
-		return;
-	}
-
-	/* round to multiple of 8 */
-	while ((--len % 8) != 0)
-		STEP;
-	len /= 8;
-	if (len == 0)
-		return;
-	while (len-- != 0) {
-		STEP; STEP; STEP; STEP;
-		STEP; STEP; STEP; STEP;
-	}
-}
diff --git a/toolbox/upstream-netbsd/lib/libutil/raise_default_signal.c b/toolbox/upstream-netbsd/lib/libutil/raise_default_signal.c
deleted file mode 100644
index 50cffd4..0000000
--- a/toolbox/upstream-netbsd/lib/libutil/raise_default_signal.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*	$NetBSD: raise_default_signal.c,v 1.3 2008/04/28 20:23:03 martin Exp $	 */
-
-/*-
- * Copyright (c) 2007 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Luke Mewburn.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#if HAVE_NBTOOL_CONFIG_H
-#include "nbtool_config.h"
-#endif
-
-#include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: raise_default_signal.c,v 1.3 2008/04/28 20:23:03 martin Exp $");
-#endif
-
-#include <errno.h>
-#include <signal.h>
-#include <stdio.h>
-#include <string.h>
-#include <util.h>
-
-#if ! HAVE_RAISE_DEFAULT_SIGNAL
-/*
- * raise_default_signal sig
- *	Raise the default signal handler for sig, by
- *	- block all signals
- *	- set the signal handler to SIG_DFL
- *	- raise the signal
- *	- unblock the signal to deliver it
- *
- *	The original signal mask and signal handler is restored on exit
- *	(whether successful or not).
- *
- *	Returns 0 on success, or -1 on failure with errno set to
- *	on of the values for sigemptyset(), sigaddset(), sigprocmask(),
- *	sigaction(), or raise().
- */
-int
-raise_default_signal(int sig)
-{
-	struct sigaction origact, act;
-	sigset_t origmask, fullmask, mask;
-	int retval, oerrno;
-
-	retval = -1;
-
-		/* Setup data structures */
-		/* XXX memset(3) isn't async-safe according to signal(7) */
-	(void)memset(&act, 0, sizeof(act));
-	act.sa_handler = SIG_DFL;
-	act.sa_flags = 0;
-	if ((sigemptyset(&act.sa_mask) == -1) ||
-	    (sigfillset(&fullmask) == -1) ||
-	    (sigemptyset(&mask) == -1) ||
-	    (sigaddset(&mask, sig) == -1))
-		goto restore_none;
-
-		/* Block all signals */
-	if (sigprocmask(SIG_BLOCK, &fullmask, &origmask) == -1)
-		goto restore_none;
-		/* (use 'goto restore_mask' to restore state) */
-
-		/* Enable the SIG_DFL handler */
-	if (sigaction(sig, &act, &origact) == -1)
-		goto restore_mask;
-		/* (use 'goto restore_act' to restore state) */
-
-		/* Raise the signal, and unblock the signal to deliver it */
-	if ((raise(sig) == -1) ||
-	    (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1))
-		goto restore_act;
-
-		/* Flag successful raise() */
-	retval = 0;
-
-		/* Restore the original handler */
- restore_act:
-	oerrno = errno;
-	(void)sigaction(sig, &origact, NULL);
-	errno = oerrno;
-
-		/* Restore the original mask */
- restore_mask:
-	oerrno = errno;
-	(void)sigprocmask(SIG_SETMASK, &origmask, NULL);
-	errno = oerrno;
-
- restore_none:
-	return retval;
-}
-
-#endif	/* ! HAVE_RAISE_DEFAULT_SIGNAL */
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/fastgrep.c b/toolbox/upstream-netbsd/usr.bin/grep/fastgrep.c
deleted file mode 100644
index 2fcd864..0000000
--- a/toolbox/upstream-netbsd/usr.bin/grep/fastgrep.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/*	$OpenBSD: util.c,v 1.36 2007/10/02 17:59:18 otto Exp $	*/
-/*	$FreeBSD: head/usr.bin/grep/fastgrep.c 211496 2010-08-19 09:28:59Z des $ */
-
-/*-
- * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
- * Copyright (C) 2008 Gabor Kovesdan <gabor@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * XXX: This file is a speed up for grep to cover the defects of the
- * regex library.  These optimizations should practically be implemented
- * there keeping this code clean.  This is a future TODO, but for the
- * meantime, we need to use this workaround.
- */
-
-#if HAVE_NBTOOL_CONFIG_H
-#include "nbtool_config.h"
-#endif
-
-#include <sys/cdefs.h>
-__RCSID("$NetBSD: fastgrep.c,v 1.5 2011/04/18 03:27:40 joerg Exp $");
-
-#include <limits.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <wchar.h>
-#include <wctype.h>
-
-#include "grep.h"
-
-static inline int	grep_cmp(const unsigned char *, const unsigned char *, size_t);
-static inline void	grep_revstr(unsigned char *, int);
-
-void
-fgrepcomp(fastgrep_t *fg, const char *pat)
-{
-	unsigned int i;
-
-	/* Initialize. */
-	fg->len = strlen(pat);
-	fg->bol = false;
-	fg->eol = false;
-	fg->reversed = false;
-
-	fg->pattern = (unsigned char *)grep_strdup(pat);
-
-	/* Preprocess pattern. */
-	for (i = 0; i <= UCHAR_MAX; i++)
-		fg->qsBc[i] = fg->len;
-	for (i = 1; i < fg->len; i++)
-		fg->qsBc[fg->pattern[i]] = fg->len - i;
-}
-
-/*
- * Returns: -1 on failure, 0 on success
- */
-int
-fastcomp(fastgrep_t *fg, const char *pat)
-{
-	unsigned int i;
-	int firstHalfDot = -1;
-	int firstLastHalfDot = -1;
-	int hasDot = 0;
-	int lastHalfDot = 0;
-	int shiftPatternLen;
-
-	/* Initialize. */
-	fg->len = strlen(pat);
-	fg->bol = false;
-	fg->eol = false;
-	fg->reversed = false;
-	fg->word = wflag;
-
-	/* Remove end-of-line character ('$'). */
-	if (fg->len > 0 && pat[fg->len - 1] == '$') {
-		fg->eol = true;
-		fg->len--;
-	}
-
-	/* Remove beginning-of-line character ('^'). */
-	if (pat[0] == '^') {
-		fg->bol = true;
-		fg->len--;
-		pat++;
-	}
-
-	if (fg->len >= 14 &&
-	    memcmp(pat, "[[:<:]]", 7) == 0 &&
-	    memcmp(pat + fg->len - 7, "[[:>:]]", 7) == 0) {
-		fg->len -= 14;
-		pat += 7;
-		/* Word boundary is handled separately in util.c */
-		fg->word = true;
-	}
-
-	/*
-	 * pat has been adjusted earlier to not include '^', '$' or
-	 * the word match character classes at the beginning and ending
-	 * of the string respectively.
-	 */
-	fg->pattern = grep_malloc(fg->len + 1);
-	memcpy(fg->pattern, pat, fg->len);
-	fg->pattern[fg->len] = '\0';
-
-	/* Look for ways to cheat...er...avoid the full regex engine. */
-	for (i = 0; i < fg->len; i++) {
-		/* Can still cheat? */
-		if (fg->pattern[i] == '.') {
-			hasDot = i;
-			if (i < fg->len / 2) {
-				if (firstHalfDot < 0)
-					/* Closest dot to the beginning */
-					firstHalfDot = i;
-			} else {
-				/* Closest dot to the end of the pattern. */
-				lastHalfDot = i;
-				if (firstLastHalfDot < 0)
-					firstLastHalfDot = i;
-			}
-		} else {
-			/* Free memory and let others know this is empty. */
-			free(fg->pattern);
-			fg->pattern = NULL;
-			return (-1);
-		}
-	}
-
-	/*
-	 * Determine if a reverse search would be faster based on the placement
-	 * of the dots.
-	 */
-	if ((!(lflag || cflag)) && ((!(fg->bol || fg->eol)) &&
-	    ((lastHalfDot) && ((firstHalfDot < 0) ||
-	    ((fg->len - (lastHalfDot + 1)) < (size_t)firstHalfDot)))) &&
-	    !oflag && !color) {
-		fg->reversed = true;
-		hasDot = fg->len - (firstHalfDot < 0 ?
-		    firstLastHalfDot : firstHalfDot) - 1;
-		grep_revstr(fg->pattern, fg->len);
-	}
-
-	/*
-	 * Normal Quick Search would require a shift based on the position the
-	 * next character after the comparison is within the pattern.  With
-	 * wildcards, the position of the last dot effects the maximum shift
-	 * distance.
-	 * The closer to the end the wild card is the slower the search.  A
-	 * reverse version of this algorithm would be useful for wildcards near
-	 * the end of the string.
-	 *
-	 * Examples:
-	 * Pattern	Max shift
-	 * -------	---------
-	 * this		5
-	 * .his		4
-	 * t.is		3
-	 * th.s		2
-	 * thi.		1
-	 */
-
-	/* Adjust the shift based on location of the last dot ('.'). */
-	shiftPatternLen = fg->len - hasDot;
-
-	/* Preprocess pattern. */
-	for (i = 0; i <= (signed)UCHAR_MAX; i++)
-		fg->qsBc[i] = shiftPatternLen;
-	for (i = hasDot + 1; i < fg->len; i++) {
-		fg->qsBc[fg->pattern[i]] = fg->len - i;
-	}
-
-	/*
-	 * Put pattern back to normal after pre-processing to allow for easy
-	 * comparisons later.
-	 */
-	if (fg->reversed)
-		grep_revstr(fg->pattern, fg->len);
-
-	return (0);
-}
-
-int
-grep_search(fastgrep_t *fg, const unsigned char *data, size_t len, regmatch_t *pmatch)
-{
-	unsigned int j;
-	int ret = REG_NOMATCH;
-
-	if (pmatch->rm_so == (ssize_t)len)
-		return (ret);
-
-	if (fg->bol && pmatch->rm_so != 0) {
-		pmatch->rm_so = len;
-		pmatch->rm_eo = len;
-		return (ret);
-	}
-
-	/* No point in going farther if we do not have enough data. */
-	if (len < fg->len)
-		return (ret);
-
-	/* Only try once at the beginning or ending of the line. */
-	if (fg->bol || fg->eol) {
-		/* Simple text comparison. */
-		/* Verify data is >= pattern length before searching on it. */
-		if (len >= fg->len) {
-			/* Determine where in data to start search at. */
-			j = fg->eol ? len - fg->len : 0;
-			if (!((fg->bol && fg->eol) && (len != fg->len)))
-				if (grep_cmp(fg->pattern, data + j,
-				    fg->len) == -1) {
-					pmatch->rm_so = j;
-					pmatch->rm_eo = j + fg->len;
-						ret = 0;
-				}
-		}
-	} else if (fg->reversed) {
-		/* Quick Search algorithm. */
-		j = len;
-		do {
-			if (grep_cmp(fg->pattern, data + j - fg->len,
-				fg->len) == -1) {
-				pmatch->rm_so = j - fg->len;
-				pmatch->rm_eo = j;
-				ret = 0;
-				break;
-			}
-			/* Shift if within bounds, otherwise, we are done. */
-			if (j == fg->len)
-				break;
-			j -= fg->qsBc[data[j - fg->len - 1]];
-		} while (j >= fg->len);
-	} else {
-		/* Quick Search algorithm. */
-		j = pmatch->rm_so;
-		do {
-			if (grep_cmp(fg->pattern, data + j, fg->len) == -1) {
-				pmatch->rm_so = j;
-				pmatch->rm_eo = j + fg->len;
-				ret = 0;
-				break;
-			}
-
-			/* Shift if within bounds, otherwise, we are done. */
-			if (j + fg->len == len)
-				break;
-			else
-				j += fg->qsBc[data[j + fg->len]];
-		} while (j <= (len - fg->len));
-	}
-
-	return (ret);
-}
-
-/*
- * Returns:	i >= 0 on failure (position that it failed)
- *		-1 on success
- */
-static inline int
-grep_cmp(const unsigned char *pat, const unsigned char *data, size_t len)
-{
-	size_t size;
-	wchar_t *wdata, *wpat;
-	unsigned int i;
-
-	if (iflag) {
-		if ((size = mbstowcs(NULL, (const char *)data, 0)) ==
-		    ((size_t) - 1))
-			return (-1);
-
-		wdata = grep_malloc(size * sizeof(wint_t));
-
-		if (mbstowcs(wdata, (const char *)data, size) ==
-		    ((size_t) - 1))
-			return (-1);
-
-		if ((size = mbstowcs(NULL, (const char *)pat, 0)) ==
-		    ((size_t) - 1))
-			return (-1);
-
-		wpat = grep_malloc(size * sizeof(wint_t));
-
-		if (mbstowcs(wpat, (const char *)pat, size) == ((size_t) - 1))
-			return (-1);
-		for (i = 0; i < len; i++) {
-			if ((towlower(wpat[i]) == towlower(wdata[i])) ||
-			    ((grepbehave != GREP_FIXED) && wpat[i] == L'.'))
-				continue;
-			free(wpat);
-			free(wdata);
-				return (i);
-		}
-	} else {
-		for (i = 0; i < len; i++) {
-			if ((pat[i] == data[i]) || ((grepbehave != GREP_FIXED) &&
-			    pat[i] == '.'))
-				continue;
-			return (i);
-		}
-	}
-	return (-1);
-}
-
-static inline void
-grep_revstr(unsigned char *str, int len)
-{
-	int i;
-	char c;
-
-	for (i = 0; i < len / 2; i++) {
-		c = str[i];
-		str[i] = str[len - i - 1];
-		str[len - i - 1] = c;
-	}
-}
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/file.c b/toolbox/upstream-netbsd/usr.bin/grep/file.c
deleted file mode 100644
index cf4a0fa..0000000
--- a/toolbox/upstream-netbsd/usr.bin/grep/file.c
+++ /dev/null
@@ -1,271 +0,0 @@
-/*	$NetBSD: file.c,v 1.7 2011/04/18 22:46:48 joerg 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 $	*/
-
-/*-
- * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
- * Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org>
- * Copyright (C) 2010 Dimitry Andric <dimitry@andric.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if HAVE_NBTOOL_CONFIG_H
-#include "nbtool_config.h"
-#endif
-
-#include <sys/cdefs.h>
-__RCSID("$NetBSD: file.c,v 1.7 2011/04/18 22:46:48 joerg 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>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#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__
-static gzFile gzbufdesc;
-static BZFILE* bzbufdesc;
-#endif
-
-static unsigned char buffer[MAXBUFSIZ];
-static unsigned char *bufpos;
-static size_t bufrem;
-
-static unsigned char *lnbuf;
-static size_t lnbuflen;
-
-static inline int
-grep_refill(struct file *f)
-{
-	ssize_t nr;
-#ifndef __ANDROID__
-	int bzerr;
-#endif
-
-	bufpos = buffer;
-	bufrem = 0;
-
-#ifndef __ANDROID__
-	if (filebehave == FILE_GZIP)
-		nr = gzread(gzbufdesc, buffer, MAXBUFSIZ);
-	else if (filebehave == FILE_BZIP && bzbufdesc != NULL) {
-		nr = BZ2_bzRead(&bzerr, bzbufdesc, buffer, MAXBUFSIZ);
-		switch (bzerr) {
-		case BZ_OK:
-		case BZ_STREAM_END:
-			/* No problem, nr will be okay */
-			break;
-		case BZ_DATA_ERROR_MAGIC:
-			/*
-			 * As opposed to gzread(), which simply returns the
-			 * plain file data, if it is not in the correct
-			 * compressed format, BZ2_bzRead() instead aborts.
-			 *
-			 * So, just restart at the beginning of the file again,
-			 * and use plain reads from now on.
-			 */
-			BZ2_bzReadClose(&bzerr, bzbufdesc);
-			bzbufdesc = NULL;
-			if (lseek(f->fd, 0, SEEK_SET) == -1)
-				return (-1);
-			nr = read(f->fd, buffer, MAXBUFSIZ);
-			break;
-		default:
-			/* Make sure we exit with an error */
-			nr = -1;
-		}
-	} else
-#endif
-		nr = read(f->fd, buffer, MAXBUFSIZ);
-
-	if (nr < 0)
-		return (-1);
-
-	bufrem = nr;
-	return (0);
-}
-
-static inline int
-grep_lnbufgrow(size_t newlen)
-{
-
-	if (lnbuflen < newlen) {
-		lnbuf = grep_realloc(lnbuf, newlen);
-		lnbuflen = newlen;
-	}
-
-	return (0);
-}
-
-char *
-grep_fgetln(struct file *f, size_t *lenp)
-{
-	unsigned char *p;
-	char *ret;
-	size_t len;
-	size_t off;
-	ptrdiff_t diff;
-
-	/* Fill the buffer, if necessary */
-	if (bufrem == 0 && grep_refill(f) != 0)
-		goto error;
-
-	if (bufrem == 0) {
-		/* Return zero length to indicate EOF */
-		*lenp = 0;
-		return ((char *)bufpos);
-	}
-
-	/* Look for a newline in the remaining part of the buffer */
-	if ((p = memchr(bufpos, line_sep, bufrem)) != NULL) {
-		++p; /* advance over newline */
-		ret = (char *)bufpos;
-		len = p - bufpos;
-		bufrem -= len;
-		bufpos = p;
-		*lenp = len;
-		return (ret);
-	}
-
-	/* We have to copy the current buffered data to the line buffer */
-	for (len = bufrem, off = 0; ; len += bufrem) {
-		/* Make sure there is room for more data */
-		if (grep_lnbufgrow(len + LNBUFBUMP))
-			goto error;
-		memcpy(lnbuf + off, bufpos, len - off);
-		off = len;
-		if (grep_refill(f) != 0)
-			goto error;
-		if (bufrem == 0)
-			/* EOF: return partial line */
-			break;
-		if ((p = memchr(bufpos, line_sep, bufrem)) == NULL)
-			continue;
-		/* got it: finish up the line (like code above) */
-		++p;
-		diff = p - bufpos;
-		len += diff;
-		if (grep_lnbufgrow(len))
-		    goto error;
-		memcpy(lnbuf + off, bufpos, diff);
-		bufrem -= diff;
-		bufpos = p;
-		break;
-	}
-	*lenp = len;
-	return ((char *)lnbuf);
-
-error:
-	*lenp = 0;
-	return (NULL);
-}
-
-static inline struct file *
-grep_file_init(struct file *f)
-{
-
-#ifndef __ANDROID__
-	if (filebehave == FILE_GZIP &&
-	    (gzbufdesc = gzdopen(f->fd, "r")) == NULL)
-		goto error;
-
-	if (filebehave == FILE_BZIP &&
-	    (bzbufdesc = BZ2_bzdopen(f->fd, "r")) == NULL)
-		goto error;
-#endif
-
-	/* Fill read buffer, also catches errors early */
-	if (grep_refill(f) != 0)
-		goto error;
-
-	/* Check for binary stuff, if necessary */
-	if (!nulldataflag && binbehave != BINFILE_TEXT &&
-	    memchr(bufpos, '\0', bufrem) != NULL)
-		f->binary = true;
-
-	return (f);
-error:
-	close(f->fd);
-	free(f);
-	return (NULL);
-}
-
-/*
- * Opens a file for processing.
- */
-struct file *
-grep_open(const char *path)
-{
-	struct file *f;
-
-	f = grep_malloc(sizeof *f);
-	memset(f, 0, sizeof *f);
-	if (path == NULL) {
-		/* Processing stdin implies --line-buffered. */
-		lbflag = true;
-		f->fd = STDIN_FILENO;
-	} else if ((f->fd = open(path, O_RDONLY)) == -1) {
-		free(f);
-		return (NULL);
-	}
-
-	return (grep_file_init(f));
-}
-
-/*
- * Closes a file.
- */
-void
-grep_close(struct file *f)
-{
-
-	close(f->fd);
-
-	/* Reset read buffer and line buffer */
-	bufpos = buffer;
-	bufrem = 0;
-
-	free(lnbuf);
-	lnbuf = NULL;
-	lnbuflen = 0;
-}
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/grep.c b/toolbox/upstream-netbsd/usr.bin/grep/grep.c
deleted file mode 100644
index 1ea6ed3..0000000
--- a/toolbox/upstream-netbsd/usr.bin/grep/grep.c
+++ /dev/null
@@ -1,707 +0,0 @@
-/*	$NetBSD: grep.c,v 1.12 2014/07/11 16:30:45 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 $	*/
-
-/*-
- * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
- * Copyright (C) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if HAVE_NBTOOL_CONFIG_H
-#include "nbtool_config.h"
-#endif
-
-#include <sys/cdefs.h>
-__RCSID("$NetBSD: grep.c,v 1.12 2014/07/11 16:30:45 christos Exp $");
-
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <getopt.h>
-#include <limits.h>
-#include <libgen.h>
-#include <locale.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "grep.h"
-
-#ifndef WITHOUT_NLS
-#include <nl_types.h>
-nl_catd	 catalog;
-#endif
-
-/*
- * Default messags to use when NLS is disabled or no catalogue
- * is found.
- */
-const char	*errstr[] = {
-	"",
-/* 1*/	"(standard input)",
-/* 2*/	"cannot read bzip2 compressed file",
-/* 3*/	"unknown %s option",
-/* 4*/	"usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A num] [-B num] [-C[num]]\n",
-/* 5*/	"\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n",
-/* 6*/	"\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n",
-/* 7*/	"\t[pattern] [file ...]\n",
-/* 8*/	"Binary file %s matches\n",
-/* 9*/	"%s (BSD grep) %s\n",
-};
-
-/* Flags passed to regcomp() and regexec() */
-int		 cflags = 0;
-int		 eflags = REG_STARTEND;
-
-/* Searching patterns */
-unsigned int	 patterns, pattern_sz;
-char		**pattern;
-regex_t		*r_pattern;
-fastgrep_t	*fg_pattern;
-
-/* Filename exclusion/inclusion patterns */
-unsigned int	 fpatterns, fpattern_sz;
-unsigned int	 dpatterns, dpattern_sz;
-struct epat	*dpattern, *fpattern;
-
-/* For regex errors  */
-char	 re_error[RE_ERROR_BUF + 1];
-
-/* Command-line flags */
-unsigned long long Aflag;	/* -A x: print x lines trailing each match */
-unsigned long long Bflag;	/* -B x: print x lines leading each match */
-bool	 Hflag;		/* -H: always print file name */
-bool	 Lflag;		/* -L: only show names of files with no matches */
-bool	 bflag;		/* -b: show block numbers for each match */
-bool	 cflag;		/* -c: only show a count of matching lines */
-bool	 hflag;		/* -h: don't print filename headers */
-bool	 iflag;		/* -i: ignore case */
-bool	 lflag;		/* -l: only show names of files with matches */
-bool	 mflag;		/* -m x: stop reading the files after x matches */
-unsigned long long mcount;	/* count for -m */
-bool	 nflag;		/* -n: show line numbers in front of matching lines */
-bool	 oflag;		/* -o: print only matching part */
-bool	 qflag;		/* -q: quiet mode (don't output anything) */
-bool	 sflag;		/* -s: silent mode (ignore errors) */
-bool	 vflag;		/* -v: only show non-matching lines */
-bool	 wflag;		/* -w: pattern must start and end on word boundaries */
-bool	 xflag;		/* -x: pattern must match entire line */
-bool	 lbflag;	/* --line-buffered */
-bool	 nullflag;	/* --null */
-bool	 nulldataflag;	/* --null-data */
-unsigned char line_sep = '\n';	/* 0 for --null-data */
-char	*label;		/* --label */
-const char *color;	/* --color */
-int	 grepbehave = GREP_BASIC;	/* -EFGP: type of the regex */
-int	 binbehave = BINFILE_BIN;	/* -aIU: handling of binary files */
-int	 filebehave = FILE_STDIO;	/* -JZ: normal, gzip or bzip2 file */
-int	 devbehave = DEV_READ;		/* -D: handling of devices */
-int	 dirbehave = DIR_READ;		/* -dRr: handling of directories */
-int	 linkbehave = LINK_READ;	/* -OpS: handling of symlinks */
-
-bool	 dexclude, dinclude;	/* --exclude-dir and --include-dir */
-bool	 fexclude, finclude;	/* --exclude and --include */
-
-enum {
-	BIN_OPT = CHAR_MAX + 1,
-	COLOR_OPT,
-	DECOMPRESS_OPT,
-	HELP_OPT,
-	MMAP_OPT,
-	LINEBUF_OPT,
-	LABEL_OPT,
-	R_EXCLUDE_OPT,
-	R_INCLUDE_OPT,
-	R_DEXCLUDE_OPT,
-	R_DINCLUDE_OPT
-};
-
-static inline const char	*init_color(const char *);
-
-/* Housekeeping */
-int	 tail;		/* lines left to print */
-bool	 notfound;	/* file not found */
-
-extern char	*__progname;
-
-/*
- * Prints usage information and returns 2.
- */
-__dead static void
-usage(void)
-{
-	fprintf(stderr, getstr(4), __progname);
-	fprintf(stderr, "%s", getstr(5));
-	fprintf(stderr, "%s", getstr(6));
-	fprintf(stderr, "%s", getstr(7));
-	exit(2);
-}
-
-static const char optstr[] =
-    "0123456789A:B:C:D:EFGHIJLOPSRUVZabcd:e:f:hilm:nopqrsuvwxyz";
-
-struct option long_options[] =
-{
-	{"binary-files",	required_argument,	NULL, BIN_OPT},
-	{"decompress",          no_argument,            NULL, DECOMPRESS_OPT},
-	{"help",		no_argument,		NULL, HELP_OPT},
-	{"mmap",		no_argument,		NULL, MMAP_OPT},
-	{"line-buffered",	no_argument,		NULL, LINEBUF_OPT},
-	{"label",		required_argument,	NULL, LABEL_OPT},
-	{"color",		optional_argument,	NULL, COLOR_OPT},
-	{"colour",		optional_argument,	NULL, COLOR_OPT},
-	{"exclude",		required_argument,	NULL, R_EXCLUDE_OPT},
-	{"include",		required_argument,	NULL, R_INCLUDE_OPT},
-	{"exclude-dir",		required_argument,	NULL, R_DEXCLUDE_OPT},
-	{"include-dir",		required_argument,	NULL, R_DINCLUDE_OPT},
-	{"after-context",	required_argument,	NULL, 'A'},
-	{"text",		no_argument,		NULL, 'a'},
-	{"before-context",	required_argument,	NULL, 'B'},
-	{"byte-offset",		no_argument,		NULL, 'b'},
-	{"context",		optional_argument,	NULL, 'C'},
-	{"count",		no_argument,		NULL, 'c'},
-	{"devices",		required_argument,	NULL, 'D'},
-        {"directories",		required_argument,	NULL, 'd'},
-	{"extended-regexp",	no_argument,		NULL, 'E'},
-	{"regexp",		required_argument,	NULL, 'e'},
-	{"fixed-strings",	no_argument,		NULL, 'F'},
-	{"file",		required_argument,	NULL, 'f'},
-	{"basic-regexp",	no_argument,		NULL, 'G'},
-	{"no-filename",		no_argument,		NULL, 'h'},
-	{"with-filename",	no_argument,		NULL, 'H'},
-	{"ignore-case",		no_argument,		NULL, 'i'},
-	{"bz2decompress",	no_argument,		NULL, 'J'},
-	{"files-with-matches",	no_argument,		NULL, 'l'},
-	{"files-without-match", no_argument,            NULL, 'L'},
-	{"max-count",		required_argument,	NULL, 'm'},
-	{"line-number",		no_argument,		NULL, 'n'},
-	{"only-matching",	no_argument,		NULL, 'o'},
-	{"quiet",		no_argument,		NULL, 'q'},
-	{"silent",		no_argument,		NULL, 'q'},
-	{"recursive",		no_argument,		NULL, 'r'},
-	{"no-messages",		no_argument,		NULL, 's'},
-	{"binary",		no_argument,		NULL, 'U'},
-	{"unix-byte-offsets",	no_argument,		NULL, 'u'},
-	{"invert-match",	no_argument,		NULL, 'v'},
-	{"version",		no_argument,		NULL, 'V'},
-	{"word-regexp",		no_argument,		NULL, 'w'},
-	{"line-regexp",		no_argument,		NULL, 'x'},
-	{"null",		no_argument,		NULL, 'Z'},
-	{"null-data",		no_argument,		NULL, 'z'},
-	{NULL,			no_argument,		NULL, 0}
-};
-
-/*
- * Adds a searching pattern to the internal array.
- */
-static void
-add_pattern(char *pat, size_t len)
-{
-
-	/* TODO: Check for empty patterns and shortcut */
-
-	/* Increase size if necessary */
-	if (patterns == pattern_sz) {
-		pattern_sz *= 2;
-		pattern = grep_realloc(pattern, ++pattern_sz *
-		    sizeof(*pattern));
-	}
-	if (len > 0 && pat[len - 1] == '\n')
-		--len;
-	/* pat may not be NUL-terminated */
-	pattern[patterns] = grep_malloc(len + 1);
-	memcpy(pattern[patterns], pat, len);
-	pattern[patterns][len] = '\0';
-	++patterns;
-}
-
-/*
- * Adds a file include/exclude pattern to the internal array.
- */
-static void
-add_fpattern(const char *pat, int mode)
-{
-
-	/* Increase size if necessary */
-	if (fpatterns == fpattern_sz) {
-		fpattern_sz *= 2;
-		fpattern = grep_realloc(fpattern, ++fpattern_sz *
-		    sizeof(struct epat));
-	}
-	fpattern[fpatterns].pat = grep_strdup(pat);
-	fpattern[fpatterns].mode = mode;
-	++fpatterns;
-}
-
-/*
- * Adds a directory include/exclude pattern to the internal array.
- */
-static void
-add_dpattern(const char *pat, int mode)
-{
-
-	/* Increase size if necessary */
-	if (dpatterns == dpattern_sz) {
-		dpattern_sz *= 2;
-		dpattern = grep_realloc(dpattern, ++dpattern_sz *
-		    sizeof(struct epat));
-	}
-	dpattern[dpatterns].pat = grep_strdup(pat);
-	dpattern[dpatterns].mode = mode;
-	++dpatterns;
-}
-
-/*
- * Reads searching patterns from a file and adds them with add_pattern().
- */
-static void
-read_patterns(const char *fn)
-{
-	FILE *f;
-	char *line;
-	size_t len;
-	ssize_t rlen;
-
-	if ((f = fopen(fn, "r")) == NULL)
-		err(2, "%s", fn);
-	line = NULL;
-	len = 0;
-	while ((rlen = getline(&line, &len, f)) != -1)
-		add_pattern(line, *line == '\n' ? 0 : (size_t)rlen);
-	free(line);
-	if (ferror(f))
-		err(2, "%s", fn);
-	fclose(f);
-}
-
-static inline const char *
-init_color(const char *d)
-{
-	char *c;
-
-	c = getenv("GREP_COLOR");
-	return (c != NULL ? c : d);
-}
-
-int
-main(int argc, char *argv[])
-{
-	char **aargv, **eargv, *eopts;
-	char *ep;
-	unsigned long long l;
-	unsigned int aargc, eargc, i, j;
-	int c, lastc, needpattern, newarg, prevoptind;
-
-	setlocale(LC_ALL, "");
-
-#ifndef WITHOUT_NLS
-	catalog = catopen("grep", NL_CAT_LOCALE);
-#endif
-
-	/* Check what is the program name of the binary.  In this
-	   way we can have all the funcionalities in one binary
-	   without the need of scripting and using ugly hacks. */
-	switch (__progname[0]) {
-	case 'e':
-		grepbehave = GREP_EXTENDED;
-		break;
-	case 'f':
-		grepbehave = GREP_FIXED;
-		break;
-	case 'g':
-		grepbehave = GREP_BASIC;
-		break;
-	case 'z':
-		filebehave = FILE_GZIP;
-		switch(__progname[1]) {
-		case 'e':
-			grepbehave = GREP_EXTENDED;
-			break;
-		case 'f':
-			grepbehave = GREP_FIXED;
-			break;
-		case 'g':
-			grepbehave = GREP_BASIC;
-			break;
-		}
-		break;
-	}
-
-	lastc = '\0';
-	newarg = 1;
-	prevoptind = 1;
-	needpattern = 1;
-
-	eopts = getenv("GREP_OPTIONS");
-
-	/* support for extra arguments in GREP_OPTIONS */
-	eargc = 0;
-	if (eopts != NULL) {
-		char *str;
-
-		/* make an estimation of how many extra arguments we have */
-		for (j = 0; j < strlen(eopts); j++)
-			if (eopts[j] == ' ')
-				eargc++;
-
-		eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1));
-
-		eargc = 0;
-		/* parse extra arguments */
-		while ((str = strsep(&eopts, " ")) != NULL)
-			eargv[eargc++] = grep_strdup(str);
-
-		aargv = (char **)grep_calloc(eargc + argc + 1,
-		    sizeof(char *));
-
-		aargv[0] = argv[0];
-		for (i = 0; i < eargc; i++)
-			aargv[i + 1] = eargv[i];
-		for (j = 1; j < (unsigned int)argc; j++, i++)
-			aargv[i + 1] = argv[j];
-
-		aargc = eargc + argc;
-	} else {
-		aargv = argv;
-		aargc = argc;
-	}
-
-	while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) !=
-	    -1)) {
-		switch (c) {
-		case '0': case '1': case '2': case '3': case '4':
-		case '5': case '6': case '7': case '8': case '9':
-			if (newarg || !isdigit(lastc))
-				Aflag = 0;
-			else if (Aflag > LLONG_MAX / 10) {
-				errno = ERANGE;
-				err(2, NULL);
-			}
-			Aflag = Bflag = (Aflag * 10) + (c - '0');
-			break;
-		case 'C':
-			if (optarg == NULL) {
-				Aflag = Bflag = 2;
-				break;
-			}
-			/* FALLTHROUGH */
-		case 'A':
-			/* FALLTHROUGH */
-		case 'B':
-			errno = 0;
-			l = strtoull(optarg, &ep, 10);
-			if (((errno == ERANGE) && (l == ULLONG_MAX)) ||
-			    ((errno == EINVAL) && (l == 0)))
-				err(2, NULL);
-			else if (ep[0] != '\0') {
-				errno = EINVAL;
-				err(2, NULL);
-			}
-			if (c == 'A')
-				Aflag = l;
-			else if (c == 'B')
-				Bflag = l;
-			else
-				Aflag = Bflag = l;
-			break;
-		case 'a':
-			binbehave = BINFILE_TEXT;
-			break;
-		case 'b':
-			bflag = true;
-			break;
-		case 'c':
-			cflag = true;
-			break;
-		case 'D':
-			if (strcasecmp(optarg, "skip") == 0)
-				devbehave = DEV_SKIP;
-			else if (strcasecmp(optarg, "read") == 0)
-				devbehave = DEV_READ;
-			else
-				errx(2, getstr(3), "--devices");
-			break;
-		case 'd':
-			if (strcasecmp("recurse", optarg) == 0) {
-				Hflag = true;
-				dirbehave = DIR_RECURSE;
-			} else if (strcasecmp("skip", optarg) == 0)
-				dirbehave = DIR_SKIP;
-			else if (strcasecmp("read", optarg) == 0)
-				dirbehave = DIR_READ;
-			else
-				errx(2, getstr(3), "--directories");
-			break;
-		case 'E':
-			grepbehave = GREP_EXTENDED;
-			break;
-		case 'e':
-			add_pattern(optarg, strlen(optarg));
-			needpattern = 0;
-			break;
-		case 'F':
-			grepbehave = GREP_FIXED;
-			break;
-		case 'f':
-			read_patterns(optarg);
-			needpattern = 0;
-			break;
-		case 'G':
-			grepbehave = GREP_BASIC;
-			break;
-		case 'H':
-			Hflag = true;
-			break;
-		case 'h':
-			Hflag = false;
-			hflag = true;
-			break;
-		case 'I':
-			binbehave = BINFILE_SKIP;
-			break;
-		case 'i':
-		case 'y':
-			iflag =  true;
-			cflags |= REG_ICASE;
-			break;
-		case 'J':
-			filebehave = FILE_BZIP;
-			break;
-		case 'L':
-			lflag = false;
-			Lflag = true;
-			break;
-		case 'l':
-			Lflag = false;
-			lflag = true;
-			break;
-		case 'm':
-			mflag = true;
-			errno = 0;
-			mcount = strtoull(optarg, &ep, 10);
-			if (((errno == ERANGE) && (mcount == ULLONG_MAX)) ||
-			    ((errno == EINVAL) && (mcount == 0)))
-				err(2, NULL);
-			else if (ep[0] != '\0') {
-				errno = EINVAL;
-				err(2, NULL);
-			}
-			break;
-		case 'n':
-			nflag = true;
-			break;
-		case 'O':
-			linkbehave = LINK_EXPLICIT;
-			break;
-		case 'o':
-			oflag = true;
-			break;
-		case 'p':
-			linkbehave = LINK_SKIP;
-			break;
-		case 'q':
-			qflag = true;
-			break;
-		case 'S':
-			linkbehave = LINK_READ;
-			break;
-		case 'R':
-		case 'r':
-			dirbehave = DIR_RECURSE;
-			Hflag = true;
-			break;
-		case 's':
-			sflag = true;
-			break;
-		case 'U':
-			binbehave = BINFILE_BIN;
-			break;
-		case 'u':
-		case MMAP_OPT:
-			/* noop, compatibility */
-			break;
-		case 'V':
-			printf(getstr(9), __progname, VERSION);
-			exit(0);
-		case 'v':
-			vflag = true;
-			break;
-		case 'w':
-			wflag = true;
-			break;
-		case 'x':
-			xflag = true;
-			break;
-		case 'Z':
-			nullflag = true;
-			break;
-		case 'z':
-			nulldataflag = true;
-			line_sep = '\0';
-			break;
-		case BIN_OPT:
-			if (strcasecmp("binary", optarg) == 0)
-				binbehave = BINFILE_BIN;
-			else if (strcasecmp("without-match", optarg) == 0)
-				binbehave = BINFILE_SKIP;
-			else if (strcasecmp("text", optarg) == 0)
-				binbehave = BINFILE_TEXT;
-			else
-				errx(2, getstr(3), "--binary-files");
-			break;
-		case COLOR_OPT:
-			color = NULL;
-			if (optarg == NULL || strcasecmp("auto", optarg) == 0 ||
-			    strcasecmp("tty", optarg) == 0 ||
-			    strcasecmp("if-tty", optarg) == 0) {
-				char *term;
-
-				term = getenv("TERM");
-				if (isatty(STDOUT_FILENO) && term != NULL &&
-				    strcasecmp(term, "dumb") != 0)
-					color = init_color("01;31");
-			} else if (strcasecmp("always", optarg) == 0 ||
-			    strcasecmp("yes", optarg) == 0 ||
-			    strcasecmp("force", optarg) == 0) {
-				color = init_color("01;31");
-			} else if (strcasecmp("never", optarg) != 0 &&
-			    strcasecmp("none", optarg) != 0 &&
-			    strcasecmp("no", optarg) != 0)
-				errx(2, getstr(3), "--color");
-			break;
-		case DECOMPRESS_OPT:
-			filebehave = FILE_GZIP;
-			break;
-		case LABEL_OPT:
-			label = optarg;
-			break;
-		case LINEBUF_OPT:
-			lbflag = true;
-			break;
-		case R_INCLUDE_OPT:
-			finclude = true;
-			add_fpattern(optarg, INCL_PAT);
-			break;
-		case R_EXCLUDE_OPT:
-			fexclude = true;
-			add_fpattern(optarg, EXCL_PAT);
-			break;
-		case R_DINCLUDE_OPT:
-			dinclude = true;
-			add_dpattern(optarg, INCL_PAT);
-			break;
-		case R_DEXCLUDE_OPT:
-			dexclude = true;
-			add_dpattern(optarg, EXCL_PAT);
-			break;
-		case HELP_OPT:
-		default:
-			usage();
-		}
-		lastc = c;
-		newarg = optind != prevoptind;
-		prevoptind = optind;
-	}
-	aargc -= optind;
-	aargv += optind;
-
-	/* Fail if we don't have any pattern */
-	if (aargc == 0 && needpattern)
-		usage();
-
-	/* Process patterns from command line */
-	if (aargc != 0 && needpattern) {
-		add_pattern(*aargv, strlen(*aargv));
-		--aargc;
-		++aargv;
-	}
-
-	switch (grepbehave) {
-	case GREP_FIXED:
-	case GREP_BASIC:
-		break;
-	case GREP_EXTENDED:
-		cflags |= REG_EXTENDED;
-		break;
-	default:
-		/* NOTREACHED */
-		usage();
-	}
-
-	fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern));
-	r_pattern = grep_calloc(patterns, sizeof(*r_pattern));
-/*
- * XXX: fgrepcomp() and fastcomp() are workarounds for regexec() performance.
- * Optimizations should be done there.
- */
-		/* Check if cheating is allowed (always is for fgrep). */
-	if (grepbehave == GREP_FIXED) {
-		for (i = 0; i < patterns; ++i)
-			fgrepcomp(&fg_pattern[i], pattern[i]);
-	} else {
-		for (i = 0; i < patterns; ++i) {
-			if (fastcomp(&fg_pattern[i], pattern[i])) {
-				/* Fall back to full regex library */
-				c = regcomp(&r_pattern[i], pattern[i], cflags);
-				if (c != 0) {
-					regerror(c, &r_pattern[i], re_error,
-					    RE_ERROR_BUF);
-					errx(2, "%s", re_error);
-				}
-			}
-		}
-	}
-
-	if (lbflag)
-		setlinebuf(stdout);
-
-	if ((aargc == 0 || aargc == 1) && !Hflag)
-		hflag = true;
-
-	if (aargc == 0)
-		exit(!procfile("-"));
-
-	if (dirbehave == DIR_RECURSE)
-		c = grep_tree(aargv);
-	else
-		for (c = 0; aargc--; ++aargv) {
-			if ((finclude || fexclude) && !file_matching(*aargv))
-				continue;
-			c+= procfile(*aargv);
-		}
-
-#ifndef WITHOUT_NLS
-	catclose(catalog);
-#endif
-
-	/* Find out the correct return value according to the
-	   results and the command line option. */
-	exit(c ? (notfound ? (qflag ? 0 : 2) : 0) : (notfound ? 2 : 1));
-}
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/grep.h b/toolbox/upstream-netbsd/usr.bin/grep/grep.h
deleted file mode 100644
index fa2a3e3..0000000
--- a/toolbox/upstream-netbsd/usr.bin/grep/grep.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/*	$NetBSD: grep.h,v 1.8 2012/05/06 22:27:00 joerg 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 $	*/
-
-/*-
- * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
- * Copyright (c) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef __ANDROID__
-#include <bzlib.h>
-#endif
-#include <limits.h>
-#include <regex.h>
-#include <stdbool.h>
-#include <stdio.h>
-#ifndef __ANDROID__
-#include <zlib.h>
-#endif
-
-#ifdef WITHOUT_NLS
-#define getstr(n)	 errstr[n]
-#else
-#include <nl_types.h>
-
-extern nl_catd		 catalog;
-#define getstr(n)	 catgets(catalog, 1, n, errstr[n])
-#endif
-
-extern const char		*errstr[];
-
-#define VERSION		"2.5.1-FreeBSD"
-
-#define GREP_FIXED	0
-#define GREP_BASIC	1
-#define GREP_EXTENDED	2
-
-#define BINFILE_BIN	0
-#define BINFILE_SKIP	1
-#define BINFILE_TEXT	2
-
-#define FILE_STDIO	0
-#define FILE_GZIP	1
-#define FILE_BZIP	2
-
-#define DIR_READ	0
-#define DIR_SKIP	1
-#define DIR_RECURSE	2
-
-#define DEV_READ	0
-#define DEV_SKIP	1
-
-#define LINK_READ	0
-#define LINK_EXPLICIT	1
-#define LINK_SKIP	2
-
-#define EXCL_PAT	0
-#define INCL_PAT	1
-
-#define MAX_LINE_MATCHES	32
-
-struct file {
-	int		 fd;
-	bool		 binary;
-};
-
-struct str {
-	off_t		 off;
-	size_t		 len;
-	char		*dat;
-	char		*file;
-	int		 line_no;
-};
-
-struct epat {
-	char		*pat;
-	int		 mode;
-};
-
-typedef struct {
-	size_t		 len;
-	unsigned char	*pattern;
-	int		 qsBc[UCHAR_MAX + 1];
-	/* flags */
-	bool		 bol;
-	bool		 eol;
-	bool		 reversed;
-	bool		 word;
-} fastgrep_t;
-
-/* Flags passed to regcomp() and regexec() */
-extern int	 cflags, eflags;
-
-/* Command line flags */
-extern bool	 Eflag, Fflag, Gflag, Hflag, Lflag,
-		 bflag, cflag, hflag, iflag, lflag, mflag, nflag, oflag,
-		 qflag, sflag, vflag, wflag, xflag;
-extern bool	 dexclude, dinclude, fexclude, finclude, lbflag, nullflag, nulldataflag;
-extern unsigned char line_sep;
-extern unsigned long long Aflag, Bflag, mcount;
-extern char	*label;
-extern const char *color;
-extern int	 binbehave, devbehave, dirbehave, filebehave, grepbehave, linkbehave;
-
-extern bool	 notfound;
-extern int	 tail;
-extern unsigned int dpatterns, fpatterns, patterns;
-extern char    **pattern;
-extern struct epat *dpattern, *fpattern;
-extern regex_t	*er_pattern, *r_pattern;
-extern fastgrep_t *fg_pattern;
-
-/* For regex errors  */
-#define RE_ERROR_BUF	512
-extern char	 re_error[RE_ERROR_BUF + 1];	/* Seems big enough */
-
-/* util.c */
-bool	 file_matching(const char *fname);
-int	 procfile(const char *fn);
-int	 grep_tree(char **argv);
-void	*grep_malloc(size_t size);
-void	*grep_calloc(size_t nmemb, size_t size);
-void	*grep_realloc(void *ptr, size_t size);
-char	*grep_strdup(const char *str);
-void	 printline(struct str *line, int sep, regmatch_t *matches, int m);
-
-/* queue.c */
-void	 enqueue(struct str *x);
-void	 printqueue(void);
-void	 clearqueue(void);
-
-/* file.c */
-void		 grep_close(struct file *f);
-struct file	*grep_open(const char *path);
-char		*grep_fgetln(struct file *f, size_t *len);
-
-/* fastgrep.c */
-int		 fastcomp(fastgrep_t *, const char *);
-void		 fgrepcomp(fastgrep_t *, const char *);
-int		 grep_search(fastgrep_t *, const unsigned char *, size_t, regmatch_t *);
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/queue.c b/toolbox/upstream-netbsd/usr.bin/grep/queue.c
deleted file mode 100644
index e3c6be1..0000000
--- a/toolbox/upstream-netbsd/usr.bin/grep/queue.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*	$NetBSD: queue.c,v 1.5 2011/08/31 16:24:57 plunky Exp $	*/
-/*	$FreeBSD: head/usr.bin/grep/queue.c 211496 2010-08-19 09:28:59Z des $	*/
-/*-
- * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * A really poor man's queue.  It does only what it has to and gets out of
- * Dodge.  It is used in place of <sys/queue.h> to get a better performance.
- */
-
-#if HAVE_NBTOOL_CONFIG_H
-#include "nbtool_config.h"
-#endif
-
-#include <sys/cdefs.h>
-__RCSID("$NetBSD: queue.c,v 1.5 2011/08/31 16:24:57 plunky Exp $");
-
-#include <sys/param.h>
-#include <sys/queue.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "grep.h"
-
-struct qentry {
-	STAILQ_ENTRY(qentry)	list;
-	struct str	 	data;
-};
-
-static STAILQ_HEAD(, qentry)	queue = STAILQ_HEAD_INITIALIZER(queue);
-static unsigned long long	count;
-
-static struct qentry	*dequeue(void);
-
-void
-enqueue(struct str *x)
-{
-	struct qentry *item;
-
-	item = grep_malloc(sizeof(struct qentry));
-	item->data.dat = grep_malloc(sizeof(char) * x->len);
-	item->data.len = x->len;
-	item->data.line_no = x->line_no;
-	item->data.off = x->off;
-	memcpy(item->data.dat, x->dat, x->len);
-	item->data.file = x->file;
-
-	STAILQ_INSERT_TAIL(&queue, item, list);
-
-	if (++count > Bflag) {
-		item = dequeue();
-		free(item->data.dat);
-		free(item);
-	}
-}
-
-static struct qentry *
-dequeue(void)
-{
-	struct qentry *item;
-
-	item = STAILQ_FIRST(&queue);
-	if (item == NULL)
-		return (NULL);
-
-	STAILQ_REMOVE_HEAD(&queue, list);
-	--count;
-	return (item);
-}
-
-void
-printqueue(void)
-{
-	struct qentry *item;
-
-	while ((item = dequeue()) != NULL) {
-		printline(&item->data, '-', NULL, 0);
-		free(item->data.dat);
-		free(item);
-	}
-}
-
-void
-clearqueue(void)
-{
-	struct qentry *item;
-
-	while ((item = dequeue()) != NULL) {
-		free(item->data.dat);
-		free(item);
-	}
-}
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/util.c b/toolbox/upstream-netbsd/usr.bin/grep/util.c
deleted file mode 100644
index ecd948d..0000000
--- a/toolbox/upstream-netbsd/usr.bin/grep/util.c
+++ /dev/null
@@ -1,499 +0,0 @@
-/*	$NetBSD: util.c,v 1.17 2013/01/21 03:24:43 msaitoh 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 $	*/
-
-/*-
- * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
- * Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if HAVE_NBTOOL_CONFIG_H
-#include "nbtool_config.h"
-#endif
-
-#include <sys/cdefs.h>
-__RCSID("$NetBSD: util.c,v 1.17 2013/01/21 03:24:43 msaitoh Exp $");
-
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <fnmatch.h>
-#include <fts.h>
-#include <libgen.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <wchar.h>
-#include <wctype.h>
-
-#include "grep.h"
-
-static bool	 first, first_global = true;
-static unsigned long long since_printed;
-
-static int	 procline(struct str *l, int);
-
-bool
-file_matching(const char *fname)
-{
-	char *fname_base, *fname_copy;
-	unsigned int i;
-	bool ret;
-
-	ret = finclude ? false : true;
-	fname_copy = grep_strdup(fname);
-	fname_base = basename(fname_copy);
-
-	for (i = 0; i < fpatterns; ++i) {
-		if (fnmatch(fpattern[i].pat, fname, 0) == 0 ||
-		    fnmatch(fpattern[i].pat, fname_base, 0) == 0) {
-			if (fpattern[i].mode == EXCL_PAT) {
-				free(fname_copy);
-				return (false);
-			} else
-				ret = true;
-		}
-	}
-	free(fname_copy);
-	return (ret);
-}
-
-static inline bool
-dir_matching(const char *dname)
-{
-	unsigned int i;
-	bool ret;
-
-	ret = dinclude ? false : true;
-
-	for (i = 0; i < dpatterns; ++i) {
-		if (dname != NULL &&
-		    fnmatch(dname, dpattern[i].pat, 0) == 0) {
-			if (dpattern[i].mode == EXCL_PAT)
-				return (false);
-			else
-				ret = true;
-		}
-	}
-	return (ret);
-}
-
-/*
- * Processes a directory when a recursive search is performed with
- * the -R option.  Each appropriate file is passed to procfile().
- */
-int
-grep_tree(char **argv)
-{
-	FTS *fts;
-	FTSENT *p;
-	char *d, *dir = NULL;
-	int c, fts_flags;
-	bool ok;
-
-	c = fts_flags = 0;
-
-	switch(linkbehave) {
-	case LINK_EXPLICIT:
-		fts_flags = FTS_COMFOLLOW;
-		break;
-	case LINK_SKIP:
-		fts_flags = FTS_PHYSICAL;
-		break;
-	default:
-		fts_flags = FTS_LOGICAL;
-			
-	}
-
-	fts_flags |= FTS_NOSTAT | FTS_NOCHDIR;
-
-	if (!(fts = fts_open(argv, fts_flags, NULL)))
-		err(2, "fts_open");
-	while ((p = fts_read(fts)) != NULL) {
-		switch (p->fts_info) {
-		case FTS_DNR:
-			/* FALLTHROUGH */
-		case FTS_ERR:
-			errx(2, "%s: %s", p->fts_path, strerror(p->fts_errno));
-			break;
-		case FTS_D:
-			/* FALLTHROUGH */
-		case FTS_DP:
-			break;
-		case FTS_DC:
-			/* Print a warning for recursive directory loop */
-			warnx("warning: %s: recursive directory loop",
-				p->fts_path);
-			break;
-		default:
-			/* Check for file exclusion/inclusion */
-			ok = true;
-			if (dexclude || dinclude) {
-				if ((d = strrchr(p->fts_path, '/')) != NULL) {
-					dir = grep_malloc(sizeof(char) *
-					    (d - p->fts_path + 1));
-					memcpy(dir, p->fts_path,
-					    d - p->fts_path);
-					dir[d - p->fts_path] = '\0';
-				}
-				ok = dir_matching(dir);
-				free(dir);
-				dir = NULL;
-			}
-			if (fexclude || finclude)
-				ok &= file_matching(p->fts_path);
-
-			if (ok)
-				c += procfile(p->fts_path);
-			break;
-		}
-	}
-
-	fts_close(fts);
-	return (c);
-}
-
-/*
- * Opens a file and processes it.  Each file is processed line-by-line
- * passing the lines to procline().
- */
-int
-procfile(const char *fn)
-{
-	struct file *f;
-	struct stat sb;
-	struct str ln;
-	mode_t s;
-	int c, t;
-
-	if (mflag && (mcount <= 0))
-		return (0);
-
-	if (strcmp(fn, "-") == 0) {
-		fn = label != NULL ? label : getstr(1);
-		f = grep_open(NULL);
-	} else {
-		if (!stat(fn, &sb)) {
-			/* Check if we need to process the file */
-			s = sb.st_mode & S_IFMT;
-			if (s == S_IFDIR && dirbehave == DIR_SKIP)
-				return (0);
-			if ((s == S_IFIFO || s == S_IFCHR || s == S_IFBLK
-				|| s == S_IFSOCK) && devbehave == DEV_SKIP)
-					return (0);
-		}
-		f = grep_open(fn);
-	}
-	if (f == NULL) {
-		if (!sflag)
-			warn("%s", fn);
-		if (errno == ENOENT)
-			notfound = true;
-		return (0);
-	}
-
-	ln.file = grep_malloc(strlen(fn) + 1);
-	strcpy(ln.file, fn);
-	ln.line_no = 0;
-	ln.len = 0;
-	tail = 0;
-	ln.off = -1;
-
-	for (first = true, c = 0;  c == 0 || !(lflag || qflag); ) {
-		ln.off += ln.len + 1;
-		if ((ln.dat = grep_fgetln(f, &ln.len)) == NULL || ln.len == 0)
-			break;
-		if (ln.len > 0 && ln.dat[ln.len - 1] == line_sep)
-			--ln.len;
-		ln.line_no++;
-
-		/* Return if we need to skip a binary file */
-		if (f->binary && binbehave == BINFILE_SKIP) {
-			grep_close(f);
-			free(ln.file);
-			free(f);
-			return (0);
-		}
-		/* Process the file line-by-line */
-		t = procline(&ln, f->binary);
-		c += t;
-
-		/* Count the matches if we have a match limit */
-		if (mflag) {
-			mcount -= t;
-			if (mcount <= 0)
-				break;
-		}
-	}
-	if (Bflag > 0)
-		clearqueue();
-	grep_close(f);
-
-	if (cflag) {
-		if (!hflag)
-			printf("%s:", ln.file);
-		printf("%u%c", c, line_sep);
-	}
-	if (lflag && !qflag && c != 0)
-		printf("%s%c", fn, line_sep);
-	if (Lflag && !qflag && c == 0)
-		printf("%s%c", fn, line_sep);
-	if (c && !cflag && !lflag && !Lflag &&
-	    binbehave == BINFILE_BIN && f->binary && !qflag)
-		printf(getstr(8), fn);
-
-	free(ln.file);
-	free(f);
-	return (c);
-}
-
-#define iswword(x)	(iswalnum((x)) || (x) == L'_')
-
-/*
- * Processes a line comparing it with the specified patterns.  Each pattern
- * is looped to be compared along with the full string, saving each and every
- * match, which is necessary to colorize the output and to count the
- * matches.  The matching lines are passed to printline() to display the
- * appropriate output.
- */
-static int
-procline(struct str *l, int nottext)
-{
-	regmatch_t matches[MAX_LINE_MATCHES];
-	regmatch_t pmatch;
-	size_t st = 0;
-	unsigned int i;
-	int c = 0, m = 0, r = 0;
-
-	/* Loop to process the whole line */
-	while (st <= l->len) {
-		pmatch.rm_so = st;
-		pmatch.rm_eo = l->len;
-
-		/* Loop to compare with all the patterns */
-		for (i = 0; i < patterns; i++) {
-/*
- * XXX: grep_search() is a workaround for speed up and should be
- * removed in the future.  See fastgrep.c.
- */
-			if (fg_pattern[i].pattern) {
-				r = grep_search(&fg_pattern[i],
-				    (unsigned char *)l->dat,
-				    l->len, &pmatch);
-				r = (r == 0) ? 0 : REG_NOMATCH;
-				st = pmatch.rm_eo;
-			} else {
-				r = regexec(&r_pattern[i], l->dat, 1,
-				    &pmatch, eflags);
-				r = (r == 0) ? 0 : REG_NOMATCH;
-				st = pmatch.rm_eo;
-			}
-			if (r == REG_NOMATCH)
-				continue;
-			/* Check for full match */
-			if (xflag &&
-			    (pmatch.rm_so != 0 ||
-			     (size_t)pmatch.rm_eo != l->len))
-				continue;
-			/* Check for whole word match */
-			if (fg_pattern[i].word && pmatch.rm_so != 0) {
-				wchar_t wbegin, wend;
-
-				wbegin = wend = L' ';
-				if (pmatch.rm_so != 0 &&
-				    sscanf(&l->dat[pmatch.rm_so - 1],
-				    "%lc", &wbegin) != 1)
-					continue;
-				if ((size_t)pmatch.rm_eo != l->len &&
-				    sscanf(&l->dat[pmatch.rm_eo],
-				    "%lc", &wend) != 1)
-					continue;
-				if (iswword(wbegin) || iswword(wend))
-					continue;
-			}
-			c = 1;
-			if (m < MAX_LINE_MATCHES)
-				matches[m++] = pmatch;
-			/* matches - skip further patterns */
-			if ((color != NULL && !oflag) || qflag || lflag)
-				break;
-		}
-
-		if (vflag) {
-			c = !c;
-			break;
-		}
-		/* One pass if we are not recording matches */
-		if ((color != NULL && !oflag) || qflag || lflag)
-			break;
-
-		if (st == (size_t)pmatch.rm_so)
-			break; 	/* No matches */
-	}
-
-	if (c && binbehave == BINFILE_BIN && nottext)
-		return (c); /* Binary file */
-
-	/* Dealing with the context */
-	if ((tail || c) && !cflag && !qflag && !lflag && !Lflag) {
-		if (c) {
-			if ((Aflag || Bflag) && !first_global &&
-			    (first || since_printed > Bflag))
-				printf("--\n");
-			tail = Aflag;
-			if (Bflag > 0)
-				printqueue();
-			printline(l, ':', matches, m);
-		} else {
-			printline(l, '-', matches, m);
-			tail--;
-		}
-		first = false;
-		first_global = false;
-		since_printed = 0;
-	} else {
-		if (Bflag)
-			enqueue(l);
-		since_printed++;
-	}
-	return (c);
-}
-
-/*
- * Safe malloc() for internal use.
- */
-void *
-grep_malloc(size_t size)
-{
-	void *ptr;
-
-	if ((ptr = malloc(size)) == NULL)
-		err(2, "malloc");
-	return (ptr);
-}
-
-/*
- * Safe calloc() for internal use.
- */
-void *
-grep_calloc(size_t nmemb, size_t size)
-{
-	void *ptr;
-
-	if ((ptr = calloc(nmemb, size)) == NULL)
-		err(2, "calloc");
-	return (ptr);
-}
-
-/*
- * Safe realloc() for internal use.
- */
-void *
-grep_realloc(void *ptr, size_t size)
-{
-
-	if ((ptr = realloc(ptr, size)) == NULL)
-		err(2, "realloc");
-	return (ptr);
-}
-
-/*
- * Safe strdup() for internal use.
- */
-char *
-grep_strdup(const char *str)
-{
-	char *ret;
-
-	if ((ret = strdup(str)) == NULL)
-		err(2, "strdup");
-	return (ret);
-}
-
-/*
- * Prints a matching line according to the command line options.
- */
-void
-printline(struct str *line, int sep, regmatch_t *matches, int m)
-{
-	size_t a = 0;
-	int i, n = 0;
-
-	if (!hflag) {
-		if (nullflag == 0)
-			fputs(line->file, stdout);
-		else {
-			printf("%s", line->file);
-			putchar(0);
-		}
-		++n;
-	}
-	if (nflag) {
-		if (n > 0)
-			putchar(sep);
-		printf("%d", line->line_no);
-		++n;
-	}
-	if (bflag) {
-		if (n > 0)
-			putchar(sep);
-		printf("%lld", (long long)line->off);
-		++n;
-	}
-	if (n)
-		putchar(sep);
-	/* --color and -o */
-	if ((oflag || color) && m > 0) {
-		for (i = 0; i < m; i++) {
-			if (!oflag)
-				fwrite(line->dat + a, matches[i].rm_so - a, 1,
-				    stdout);
-			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);
-			if (color) 
-				fprintf(stdout, "\33[m\33[K");
-			a = matches[i].rm_eo;
-			if (oflag)
-				putchar('\n');
-		}
-		if (!oflag) {
-			if (line->len - a > 0)
-				fwrite(line->dat + a, line->len - a, 1, stdout);
-			putchar(line_sep);
-		}
-	} else {
-		fwrite(line->dat, line->len, 1, stdout);
-		putchar(line_sep);
-	}
-}