Allow vendor-init-actionable for vold-related properties
am: 65ce3b2cd8

Change-Id: I42838c531f79d01283538fe2cd4f68368947368f
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..46bc02b 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",
+    tags: ["debug"],
+
+    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",
+    ],
+}
+
 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 c4df5c4..65fa2e7 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, ...) {
@@ -135,8 +136,16 @@
 
 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
@@ -317,10 +326,7 @@
 }
 
 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);
@@ -349,19 +355,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;
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 100%
rename from adb/adb_auth_host.cpp
rename to adb/client/auth.cpp
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/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 98%
rename from adb/jdwp_service.cpp
rename to adb/daemon/jdwp_service.cpp
index 6f5396a..9761558 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) {
@@ -511,7 +511,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;
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 100%
rename from adb/remount_service.cpp
rename to adb/daemon/remount_service.cpp
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 97%
rename from adb/shell_service.cpp
rename to adb/daemon/shell_service.cpp
index 17c7eba..401c99c 100644
--- a/adb/shell_service.cpp
+++ b/adb/daemon/shell_service.cpp
@@ -334,8 +334,18 @@
         // processes, so we need to manually reset back to SIG_DFL here (http://b/35209888).
         signal(SIGPIPE, SIG_DFL);
 
+        // Increase oom_score_adj from -1000, so that the child is visible to the OOM-killer.
+        // Don't treat failure as an error, because old Android kernels explicitly disabled this.
+        int oom_score_adj_fd = adb_open("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC);
+        if (oom_score_adj_fd != -1) {
+            const char* oom_score_adj_value = "-950";
+            TEMP_FAILURE_RETRY(
+                adb_write(oom_score_adj_fd, oom_score_adj_value, strlen(oom_score_adj_value)));
+        }
+
         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..263303f 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -269,7 +269,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,18 +300,20 @@
         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;
     }
 
+    memset(&h->read_aiob.ctx, 0, sizeof(h->read_aiob.ctx));
+    memset(&h->write_aiob.ctx, 0, sizeof(h->write_aiob.ctx));
     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);
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/socket_test.cpp b/adb/socket_test.cpp
index 6b40056..6c4a8b2 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) {
+            std::string 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 e05a3db..0887e6f 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -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.
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_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..7d35fb6 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -529,6 +529,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 +550,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 +566,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;
diff --git a/adb/test_adb.py b/adb/test_adb.py
index e771106..3bb433d 100644
--- a/adb/test_adb.py
+++ b/adb/test_adb.py
@@ -162,15 +162,14 @@
 
         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:
             # 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.
@@ -233,6 +232,24 @@
                 output.strip(), 'connected to localhost:{}'.format(port))
             s.close()
 
+    def test_already_connected(self):
+        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        s.bind(('127.0.0.1', 0))
+        s.listen(2)
+
+        port = s.getsockname()[1]
+        output = subprocess.check_output(
+            ['adb', 'connect', 'localhost:{}'.format(port)])
+
+        self.assertEqual(
+            output.strip(), 'connected to localhost:{}'.format(port))
+
+        # b/31250450: this always returns 0 but probably shouldn't.
+        output = subprocess.check_output(
+            ['adb', 'connect', 'localhost:{}'.format(port)])
+
+        self.assertEqual(
+            output.strip(), 'already connected to localhost:{}'.format(port))
 
 def main():
     random.seed(0)
diff --git a/adb/test_device.py b/adb/test_device.py
index 72e1c67..b1ad043 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -1187,7 +1187,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..2867d38 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,6 +30,7 @@
 #include <unistd.h>
 
 #include <algorithm>
+#include <deque>
 #include <list>
 #include <mutex>
 #include <thread>
@@ -38,12 +41,13 @@
 #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);
@@ -65,6 +69,113 @@
     return next++;
 }
 
+BlockingConnectionAdapter::BlockingConnectionAdapter(std::unique_ptr<BlockingConnection> connection)
+    : underlying_(std::move(connection)) {}
+
+BlockingConnectionAdapter::~BlockingConnectionAdapter() {
+    LOG(INFO) << "BlockingConnectionAdapter(" << this->transport_name_ << "): destructing";
+    Stop();
+}
+
+static void AssumeLocked(std::mutex& mutex) ASSERT_CAPABILITY(mutex) {}
+
+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_);
+            cv_.wait(lock, [this]() REQUIRES(mutex_) {
+                return this->stopped_ || !this->write_queue_.empty();
+            });
+
+            AssumeLocked(mutex_);
+
+            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 +254,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 +263,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,
@@ -559,9 +465,10 @@
     return 0;
 }
 
-static void transport_registration_func(int _fd, unsigned ev, void* data) {
+static void remove_transport(atransport*);
+
+static void transport_registration_func(int _fd, unsigned ev, void*) {
     tmsg m;
-    int s[2];
     atransport* t;
 
     if (!(ev & FDE_READ)) {
@@ -575,13 +482,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);
@@ -603,23 +504,33 @@
     /* don't create transport threads for inaccessible devices */
     if (t->GetConnectionState() != kCsNoPerm) {
         /* initial references are the two threads */
-        t->ref_count = 2;
+        t->ref_count = 1;
+        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
     }
 
     {
@@ -685,7 +596,7 @@
     t->ref_count--;
     if (t->ref_count == 0) {
         D("transport: %s unref (kicking and closing)", t->serial);
-        t->connection->Close();
+        t->connection->Stop();
         remove_transport(t);
     } else {
         D("transport: %s unref (count=%zu)", t->serial, t->ref_count);
@@ -736,9 +647,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;
         }
 
@@ -813,14 +722,14 @@
 }
 
 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();
+        this->connection->Stop();
     }
 }
 
@@ -833,7 +742,7 @@
     connection_state_ = state;
 }
 
-const std::string atransport::connection_state_name() const {
+std::string atransport::connection_state_name() const {
     ConnectionState state = GetConnectionState();
     switch (state) {
         case kCsOffline:
diff --git a/adb/transport.h b/adb/transport.h
index 9700f44..d18c362 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -20,14 +20,17 @@
 #include <sys/types.h>
 
 #include <atomic>
+#include <condition_variable>
 #include <deque>
 #include <functional>
 #include <list>
 #include <memory>
 #include <mutex>
 #include <string>
+#include <thread>
 #include <unordered_set>
 
+#include <android-base/thread_annotations.h>
 #include <openssl/rsa.h>
 
 #include "adb.h"
@@ -57,15 +60,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 +112,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 +148,7 @@
     unique_fd fd_;
 };
 
-struct UsbConnection : public Connection {
+struct UsbConnection : public BlockingConnection {
     explicit UsbConnection(usb_handle* handle) : handle_(handle) {}
     ~UsbConnection();
 
@@ -110,7 +169,6 @@
 
     atransport(ConnectionState state = kCsOffline)
         : id(NextTransportId()), connection_state_(state) {
-        transport_fde = {};
         // Initialize protocol to min version for compatibility with older versions.
         // Version will be updated post-connect.
         protocol_version = A_VERSION_MIN;
@@ -126,11 +184,7 @@
     void SetConnectionState(ConnectionState state);
 
     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;
 
@@ -152,8 +206,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;
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..c09fcb7 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
 
@@ -445,13 +446,13 @@
     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->connection = 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 +471,7 @@
 #endif
 
     // Regular tcp connection.
-    t->connection.reset(new FdConnection(std::move(fd)));
+    auto fd_connection = std::make_unique<FdConnection>(std::move(fd));
+    t->connection = std::make_unique<BlockingConnectionAdapter>(std::move(fd_connection));
     return fail;
 }
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index d7565f6..e9a75cd 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->connection = std::make_unique<BlockingConnectionAdapter>(std::move(connection));
     t->type = kTransportUsb;
 }
 
diff --git a/base/Android.bp b/base/Android.bp
index 5d70d47..12b3969 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",
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/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/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..b194bbe 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...
@@ -407,29 +421,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}
 }
@@ -792,6 +808,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
@@ -1051,12 +1124,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 d8ee899..bf82cb7 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>
@@ -139,7 +141,7 @@
 // values.
 const std::map<std::string, int32_t> kBootReasonMap = {
     {"empty", kEmptyBootReason},
-    {"unknown", kUnknownBootReason},
+    {"__BOOTSTAT_UNKNOWN__", kUnknownBootReason},
     {"normal", 2},
     {"recovery", 3},
     {"reboot", 4},
@@ -192,12 +194,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},
@@ -228,7 +232,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},
+    // {"usb", 90},  // Duplicate of enum 80 above. Immediate reuse possible.
     {"charge", 91},
     {"oem_tz_crash", 92},
     {"uvlo", 93},
@@ -286,6 +290,19 @@
     {"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},
 };
 
 // Converts a string value representing the reason the system booted to an
@@ -462,11 +479,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);
@@ -484,20 +503,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;
@@ -507,32 +721,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
@@ -567,26 +761,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;
       }
     }
@@ -625,28 +829,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.
@@ -684,7 +867,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/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..9bd0628 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,49 +57,50 @@
     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)
+#
+# Package fastboot-related executables.
+#
+
+my_dist_files := $(HOST_OUT_EXECUTABLES)/fastboot
 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)
@@ -90,38 +112,29 @@
 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 23443ec..feacaa1 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);
     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 0ce3855..3a3503e 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -76,9 +76,8 @@
 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.
@@ -86,12 +85,9 @@
 static int64_t sparse_limit = -1;
 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]             Use sparse files above this limit (0 to disable).\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,12 +407,14 @@
         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);
+        }
         uint32_t header_version_existing =
                 reinterpret_cast<boot_img_hdr_v1*>(kdata)->header_version;
-        if (header_version != header_version_existing) {
+        if (g_boot_img_hdr.header_version != header_version_existing) {
             die("header version mismatch, expected: %" PRIu32 " found %" PRIu32 "",
-                header_version, header_version_existing);
+                g_boot_img_hdr.header_version, header_version_existing);
         }
 
         if (!ramdisk.empty()) die("cannot boot a boot.img *and* ramdisk");
@@ -485,16 +438,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;
 }
@@ -548,7 +497,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());
 }
@@ -564,18 +513,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;
@@ -585,16 +532,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;
@@ -615,10 +557,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;
@@ -779,8 +718,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;
     }
 
@@ -792,9 +731,7 @@
         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;
 }
 
@@ -823,17 +760,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) {
@@ -885,10 +811,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)) {
@@ -950,46 +873,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;
 }
 
@@ -1019,8 +914,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";
@@ -1132,25 +1025,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));
@@ -1208,9 +1095,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
@@ -1243,7 +1127,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();
 
@@ -1290,9 +1174,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);
@@ -1312,18 +1193,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");
 
@@ -1497,45 +1366,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
@@ -1544,100 +1414,83 @@
 
     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':
+                    sparse_limit = parse_num(optarg);
+                    if (sparse_limit < 0) die("invalid sparse limit");
+                    break;
+                case 'v':
+                    set_verbose();
+                    break;
+                case 'w':
+                    wants_wipe = true;
+                    break;
+                case '?':
+                    return 1;
+                default:
+                    abort();
+            }
         }
     }
 
@@ -1662,9 +1515,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);
 
@@ -1721,9 +1571,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);
@@ -1742,9 +1589,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());
                 }
@@ -1762,7 +1606,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") {
@@ -1777,9 +1621,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);
@@ -1791,7 +1632,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);
             };
@@ -1799,9 +1640,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") {
@@ -1813,20 +1654,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);
@@ -1847,12 +1678,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());
             }
@@ -1862,14 +1689,10 @@
     }
 
     if (wants_wipe) {
-        fprintf(stderr, "wiping userdata...\n");
         fb_queue_erase("userdata");
         if (set_fbe_marker) {
-            fprintf(stderr, "setting FBE marker...\n");
+            fprintf(stderr, "setting FBE marker on initial userdata...\n");
             std::string initial_userdata_dir = create_fbemarker_tmpdir();
-            if (initial_userdata_dir.empty()) {
-                return 1;
-            }
             fb_perform_format(transport, "userdata", 1, "", "", initial_userdata_dir);
             delete_fbemarker_tmpdir(initial_userdata_dir);
         } else {
@@ -1878,7 +1701,6 @@
 
         std::string cache_type;
         if (fb_getvar(transport, "partition-type:cache", &cache_type) && !cache_type.empty()) {
-            fprintf(stderr, "wiping cache...\n");
             fb_queue_erase("cache");
             fb_perform_format(transport, "cache", 1, "", "", "");
         }
@@ -1892,12 +1714,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..a089567 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));
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/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 9d504d6..3fbef9f 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 {
@@ -443,6 +445,10 @@
             LERROR << "dt_fstab: Failed to find device for partition " << dp->d_name;
             return {};
         }
+        if (!StartsWith(value, "/dev")) {
+            LERROR << "dt_fstab: Invalid device node for partition " << dp->d_name;
+            return {};
+        }
         fstab_entry.push_back(value);
 
         std::string mount_point;
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/init/README.md b/init/README.md
index 5c2352b..59ddd77 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
@@ -176,9 +195,93 @@
 > This service will not automatically start with its class.
   It must be explicitly started by name.
 
+`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.
+
 `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 +290,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 +306,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
 --------
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 8130e73..694e5e7 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -446,8 +446,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 << "'";
     }
 
@@ -678,29 +678,29 @@
         {"console",     {0,     1,    &Service::ParseConsole}},
         {"critical",    {0,     0,    &Service::ParseCritical}},
         {"disabled",    {0,     0,    &Service::ParseDisabled}},
+        {"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}},
         {"socket",      {3,     6,    &Service::ParseSocket}},
-        {"file",        {2,     2,    &Service::ParseFile}},
         {"user",        {1,     1,    &Service::ParseUser}},
         {"writepid",    {1,     kMax, &Service::ParseWritepid}},
     };
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/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index 473d195..c94cad1 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;
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/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/libmemunreachable/Android.bp b/libmemunreachable/Android.bp
index caca377..f872d0f 100644
--- a/libmemunreachable/Android.bp
+++ b/libmemunreachable/Android.bp
@@ -88,7 +88,6 @@
 cc_test {
     name: "memunreachable_binder_test",
     defaults: ["libmemunreachable_defaults"],
-    test_suites: ["vts"],
     srcs: [
         "tests/Binder_test.cpp",
     ],
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 7b8111c..6868f18 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: {
@@ -114,79 +118,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 +128,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 +179,13 @@
         "liblog",
         "liblzma",
         "libunwindstack",
+        "libdexfile",
     ],
 
     static_libs: [
         "libgmock",
     ],
 
-    whole_static_libs: ["libunwindstack_dex_test"],
-
     data: [
         "tests/files/elf32.xz",
         "tests/files/elf64.xz",
@@ -260,6 +195,7 @@
         "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/straddle_arm/*",
         "tests/files/offline/straddle_arm64/*",
diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp
index 4c16212..e1a1a71 100644
--- a/libunwindstack/Maps.cpp
+++ b/libunwindstack/Maps.cpp
@@ -25,6 +25,7 @@
 
 #include <android-base/unique_fd.h>
 
+#include <algorithm>
 #include <cctype>
 #include <memory>
 #include <string>
@@ -209,6 +210,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;
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 94edb1c..9a6c6df 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.
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/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index 8cb640f..2b8f0c2 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>
@@ -1070,4 +1071,44 @@
   EXPECT_EQ(0xcd4ff960U, unwinder.frames()[24].sp);
 }
 
+TEST_F(UnwindOfflineTest, jit_map_arm) {
+  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);
+}
+
 }  // 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/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/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/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/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/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/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/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/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/lmkd/Android.bp b/lmkd/Android.bp
index 58647f2..c7cc41b 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 ee2f343..1f16758 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>
@@ -75,11 +77,11 @@
 #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 */
@@ -279,24 +281,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) {
@@ -305,6 +315,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);
 
@@ -316,10 +328,16 @@
 
     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;
@@ -353,7 +371,15 @@
              "/dev/memcg/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) {
@@ -377,8 +403,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);
@@ -420,8 +447,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);
     }
 }
 
@@ -558,10 +585,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;
@@ -725,7 +752,7 @@
     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);
@@ -1207,21 +1234,28 @@
     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.
+             */
+            if (mlockall(MCL_CURRENT | MCL_FUTURE | MCL_ONFAULT) && (errno != EINVAL)) {
+                ALOGW("mlockall failed %s", strerror(errno));
+            }
 
-    sched_setscheduler(0, SCHED_FIFO, &param);
-    if (!init())
+            sched_setscheduler(0, SCHED_FIFO, &param);
+        }
+
         mainloop();
+    }
 
 #ifdef LMKD_LOG_STATS
     statslog_destroy(&log_ctx);
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/logwrapper/Android.bp b/logwrapper/Android.bp
index f163f57..54506dc 100644
--- a/logwrapper/Android.bp
+++ b/logwrapper/Android.bp
@@ -1,10 +1,17 @@
-
+cc_defaults {
+    name: "logwrapper_defaults",
+    cflags: [
+        "-Werror",
+    ],
+}
 
 // ========================================================
 // Static and shared library
 // ========================================================
+
 cc_library {
     name: "liblogwrap",
+    defaults: ["logwrapper_defaults"],
     srcs: ["logwrap.c"],
     shared_libs: [
         "libcutils",
@@ -12,32 +19,45 @@
     ],
     export_include_dirs: ["include"],
     local_include_dirs: ["include"],
-    cflags: [
-        "-Werror",
-    ],
 }
 
 // ========================================================
 // Executable
 // ========================================================
+
+cc_defaults {
+    name: "logwrapper_common",
+    defaults: ["logwrapper_defaults"],
+    local_include_dirs: ["include"],
+    srcs: [
+        "logwrap.c",
+        "logwrapper.c",
+    ],
+    shared_libs: ["libcutils", "liblog"],
+}
+
 cc_binary {
     name: "logwrapper",
-    srcs: ["logwrapper.c"],
-    static_libs: [
-        "liblog",
-        "liblogwrap",
-        "libcutils",
-    ],
-    cflags: [
-        "-Werror",
-    ],
+    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",
+    stem: "logwrapper",
+    vendor: true,
+    defaults: ["logwrapper_common"],
 }
 
 // ========================================================
 // Benchmark
 // ========================================================
+
 cc_benchmark {
     name: "android_fork_execvp_ext_benchmark",
+    defaults: ["logwrapper_defaults"],
     srcs: [
         "android_fork_execvp_ext_benchmark.cpp",
     ],
@@ -47,7 +67,4 @@
         "liblog",
         "liblogwrap",
     ],
-    cflags: [
-        "-Werror",
-    ],
 }
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index 7076078..8621993 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -31,7 +31,6 @@
 #include <cutils/klog.h>
 #include <log/log.h>
 #include <logwrap/logwrap.h>
-#include <private/android_filesystem_config.h>
 
 #define ARRAY_SIZE(x)   (sizeof(x) / sizeof(*(x)))
 #define MIN(a,b) (((a)<(b))?(a):(b))
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/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp
index 3ccb92f..2e42b70 100644
--- a/shell_and_utilities/Android.bp
+++ b/shell_and_utilities/Android.bp
@@ -6,6 +6,8 @@
         "bzip2",
         "grep",
         "grep_vendor",
+        "logwrapper",
+        "logwrapper_vendor",
         "mkshrc",
         "mkshrc_vendor",
         "reboot",
diff --git a/storaged/OWNERS b/storaged/OWNERS
index 7445270..c6feee8 100644
--- a/storaged/OWNERS
+++ b/storaged/OWNERS
@@ -1 +1,2 @@
 jinqian@google.com
+salyzyn@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>