Merge "Create lookup table of DEX symbols."
diff --git a/.clang-format-2 b/.clang-format-2
index 41591ce..ede5d7e 100644
--- a/.clang-format-2
+++ b/.clang-format-2
@@ -7,4 +7,3 @@
 PointerAlignment: Left
 TabWidth: 2
 UseTab: Never
-PenaltyExcessCharacter: 32
diff --git a/.clang-format-4 b/.clang-format-4
index 9127163..55773a2 100644
--- a/.clang-format-4
+++ b/.clang-format-4
@@ -9,4 +9,3 @@
 PointerAlignment: Left
 TabWidth: 4
 UseTab: Never
-PenaltyExcessCharacter: 32
diff --git a/adb/Android.bp b/adb/Android.bp
index c0e4c57..2a9a579 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -299,6 +299,10 @@
         "libqemu_pipe",
         "libbase",
     ],
+
+    export_include_dirs: [
+        "daemon/include",
+    ],
 }
 
 cc_binary {
diff --git a/adb/adb.bash b/adb/adb.bash
index d36bec3..b1b3957 100644
--- a/adb/adb.bash
+++ b/adb/adb.bash
@@ -16,11 +16,11 @@
 #
 
 _adb() {
-    if ! type -t "$1" >/dev/null; then
+    if ! check_type "$1" >/dev/null; then
         return
     fi
 
-    if type -t _init_completion >/dev/null; then
+    if check_type _init_completion >/dev/null; then
         _init_completion || return
     fi
 
@@ -435,7 +435,7 @@
     fi
 
     # Since we're probably doing file completion here, don't add a space after.
-    if [[ $(type -t compopt) = "builtin" ]]; then
+    if [[ $(check_type compopt) == "builtin" ]]; then
         compopt -o nospace
     fi
 
@@ -451,7 +451,7 @@
     xspec=$2
 
     # Since we're probably doing file completion here, don't add a space after.
-    if [[ $(type -t compopt) = "builtin" ]]; then
+    if [[ $(check_type compopt) == "builtin" ]]; then
         compopt -o plusdirs
         if [[ "${xspec}" == "" ]]; then
             COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") )
@@ -492,7 +492,7 @@
 }
 
 
-if [[ $(type -t compopt) = "builtin" ]]; then
+if [[ $(check_type compopt) == "builtin" ]]; then
     complete -F _adb adb
 else
     complete -o nospace -F _adb adb
diff --git a/adb/adb.cpp b/adb/adb.cpp
index f8a54c6..19300f6 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -264,15 +264,6 @@
     send_packet(cp, t);
 }
 
-// qual_overwrite is used to overwrite a qualifier string.  dst is a
-// pointer to a char pointer.  It is assumed that if *dst is non-NULL, it
-// was malloc'ed and needs to freed.  *dst will be set to a dup of src.
-// TODO: switch to std::string for these atransport fields instead.
-static void qual_overwrite(char** dst, const std::string& src) {
-    free(*dst);
-    *dst = strdup(src.c_str());
-}
-
 void parse_banner(const std::string& banner, atransport* t) {
     D("parse_banner: %s", banner.c_str());
 
@@ -296,11 +287,11 @@
             const std::string& key = key_value[0];
             const std::string& value = key_value[1];
             if (key == "ro.product.name") {
-                qual_overwrite(&t->product, value);
+                t->product = value;
             } else if (key == "ro.product.model") {
-                qual_overwrite(&t->model, value);
+                t->model = value;
             } else if (key == "ro.product.device") {
-                qual_overwrite(&t->device, value);
+                t->device = value;
             } else if (key == "features") {
                 t->SetFeatures(value);
             }
@@ -415,7 +406,7 @@
         if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
             asocket* s = find_local_socket(p->msg.arg1, 0);
             if (s) {
-                if(s->peer == 0) {
+                if(s->peer == nullptr) {
                     /* On first READY message, create the connection. */
                     s->peer = create_remote_socket(p->msg.arg0, t);
                     s->peer->peer = s;
@@ -424,8 +415,8 @@
                     /* Other READY messages must use the same local-id */
                     s->ready(s);
                 } else {
-                    D("Invalid A_OKAY(%d,%d), expected A_OKAY(%d,%d) on transport %s",
-                      p->msg.arg0, p->msg.arg1, s->peer->id, p->msg.arg1, t->serial);
+                    D("Invalid A_OKAY(%d,%d), expected A_OKAY(%d,%d) on transport %s", p->msg.arg0,
+                      p->msg.arg1, s->peer->id, p->msg.arg1, t->serial.c_str());
                 }
             } else {
                 // When receiving A_OKAY from device for A_OPEN request, the host server may
@@ -451,8 +442,8 @@
                  * socket has a peer on the same transport.
                  */
                 if (p->msg.arg0 == 0 && s->peer && s->peer->transport != t) {
-                    D("Invalid A_CLSE(0, %u) from transport %s, expected transport %s",
-                      p->msg.arg1, t->serial, s->peer->transport->serial);
+                    D("Invalid A_CLSE(0, %u) from transport %s, expected transport %s", p->msg.arg1,
+                      t->serial.c_str(), s->peer->transport->serial.c_str());
                 } else {
                     s->close(s);
                 }
@@ -933,25 +924,6 @@
 // This returns 1 on success, 0 on failure, and -1 to indicate this is not
 // a forwarding-related request.
 int handle_forward_request(const char* service, atransport* transport, int reply_fd) {
-    if (!strcmp(service, "list-forward")) {
-        // Create the list of forward redirections.
-        std::string listeners = format_listeners();
-#if ADB_HOST
-        SendOkay(reply_fd);
-#endif
-        return SendProtocolString(reply_fd, listeners);
-    }
-
-    if (!strcmp(service, "killforward-all")) {
-        remove_all_listeners();
-#if ADB_HOST
-        /* On the host: 1st OKAY is connect, 2nd OKAY is status */
-        SendOkay(reply_fd);
-#endif
-        SendOkay(reply_fd);
-        return 1;
-    }
-
     if (!strncmp(service, "forward:", 8) || !strncmp(service, "killforward:", 12)) {
         // killforward:local
         // forward:(norebind:)?local;remote
@@ -1171,7 +1143,7 @@
         std::string error;
         atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &error);
         if (t) {
-            return SendOkay(reply_fd, t->serial ? t->serial : "unknown");
+            return SendOkay(reply_fd, !t->serial.empty() ? t->serial : "unknown");
         } else {
             return SendFail(reply_fd, error);
         }
@@ -1180,7 +1152,7 @@
         std::string error;
         atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &error);
         if (t) {
-            return SendOkay(reply_fd, t->devpath ? t->devpath : "unknown");
+            return SendOkay(reply_fd, !t->devpath.empty() ? t->devpath : "unknown");
         } else {
             return SendFail(reply_fd, error);
         }
@@ -1214,10 +1186,30 @@
         return SendOkay(reply_fd, response);
     }
 
+    if (!strcmp(service, "list-forward")) {
+        // Create the list of forward redirections.
+        std::string listeners = format_listeners();
+#if ADB_HOST
+        SendOkay(reply_fd);
+#endif
+        return SendProtocolString(reply_fd, listeners);
+    }
+
+    if (!strcmp(service, "killforward-all")) {
+        remove_all_listeners();
+#if ADB_HOST
+        /* On the host: 1st OKAY is connect, 2nd OKAY is status */
+        SendOkay(reply_fd);
+#endif
+        SendOkay(reply_fd);
+        return 1;
+    }
+
     std::string error;
     atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &error);
     if (!t) {
-        return -1;
+        SendFail(reply_fd, error);
+        return 1;
     }
 
     int ret = handle_forward_request(service, t, reply_fd);
diff --git a/adb/adb.h b/adb/adb.h
index c884166..7e9af9e 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -156,11 +156,6 @@
 
 int handle_forward_request(const char* service, atransport* transport, int reply_fd);
 
-#if !ADB_HOST
-void framebuffer_service(int fd, void* cookie);
-void set_verity_enabled_state_service(int fd, void* cookie);
-#endif
-
 /* packet allocator */
 apacket* get_apacket(void);
 void put_apacket(apacket* p);
diff --git a/adb/adb_io.cpp b/adb/adb_io.cpp
index 38e3116..6cc274b 100644
--- a/adb/adb_io.cpp
+++ b/adb/adb_io.cpp
@@ -49,7 +49,7 @@
     }
     buf[4] = 0;
 
-    unsigned long len = strtoul(buf, 0, 16);
+    unsigned long len = strtoul(buf, nullptr, 16);
     s->resize(len, '\0');
     if (!ReadFdExactly(fd, &(*s)[0], len)) {
         *error = perror_str("protocol fault (couldn't read status message)");
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index ea5a44e..f4a92e3 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -136,9 +136,10 @@
         }
         //  <device-serial> " " <local-name> " " <remote-name> "\n"
         // Entries from "adb reverse" have no serial.
-        android::base::StringAppendF(&result, "%s %s %s\n",
-                                     l->transport->serial ? l->transport->serial : "(reverse)",
-                                     l->local_name.c_str(), l->connect_to.c_str());
+        android::base::StringAppendF(
+                &result, "%s %s %s\n",
+                !l->transport->serial.empty() ? l->transport->serial.c_str() : "(reverse)",
+                l->local_name.c_str(), l->connect_to.c_str());
     }
     return result;
 }
diff --git a/adb/client/adb_client.cpp b/adb/client/adb_client.cpp
index 849a6e7..1959258 100644
--- a/adb/client/adb_client.cpp
+++ b/adb/client/adb_client.cpp
@@ -46,7 +46,7 @@
 #include "sysdeps/chrono.h"
 
 static TransportType __adb_transport = kTransportAny;
-static const char* __adb_serial = NULL;
+static const char* __adb_serial = nullptr;
 static TransportId __adb_transport_id = 0;
 
 static const char* __adb_server_socket_spec;
diff --git a/adb/client/auth.cpp b/adb/client/auth.cpp
index 0f4dd33..5fbef09 100644
--- a/adb/client/auth.cpp
+++ b/adb/client/auth.cpp
@@ -109,7 +109,7 @@
     LOG(INFO) << "generate_key(" << file << ")...";
 
     mode_t old_mask;
-    FILE *f = NULL;
+    FILE *f = nullptr;
     int ret = 0;
 
     EVP_PKEY* pkey = EVP_PKEY_new();
@@ -121,7 +121,7 @@
     }
 
     BN_set_word(exponent, RSA_F4);
-    RSA_generate_key_ex(rsa, 2048, exponent, NULL);
+    RSA_generate_key_ex(rsa, 2048, exponent, nullptr);
     EVP_PKEY_set1_RSA(pkey, rsa);
 
     old_mask = umask(077);
@@ -135,7 +135,7 @@
 
     umask(old_mask);
 
-    if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL)) {
+    if (!PEM_write_PrivateKey(f, pkey, nullptr, nullptr, 0, nullptr, nullptr)) {
         D("Failed to write key");
         goto out;
     }
@@ -302,7 +302,7 @@
 static std::string adb_auth_sign(RSA* key, const char* token, size_t token_size) {
     if (token_size != TOKEN_SIZE) {
         D("Unexpected token size %zd", token_size);
-        return 0;
+        return nullptr;
     }
 
     std::string result;
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index e07dba7..7791895 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -362,9 +362,8 @@
 }
 
 static void copy_to_file(int inFd, int outFd) {
-    const size_t BUFSIZE = 32 * 1024;
-    char* buf = (char*) malloc(BUFSIZE);
-    if (buf == nullptr) fatal("couldn't allocate buffer for copy_to_file");
+    constexpr size_t BUFSIZE = 32 * 1024;
+    std::vector<char> buf(BUFSIZE);
     int len;
     long total = 0;
     int old_stdin_mode = -1;
@@ -376,9 +375,9 @@
 
     while (true) {
         if (inFd == STDIN_FILENO) {
-            len = unix_read(inFd, buf, BUFSIZE);
+            len = unix_read(inFd, buf.data(), BUFSIZE);
         } else {
-            len = adb_read(inFd, buf, BUFSIZE);
+            len = adb_read(inFd, buf.data(), BUFSIZE);
         }
         if (len == 0) {
             D("copy_to_file() : read 0 bytes; exiting");
@@ -389,10 +388,10 @@
             break;
         }
         if (outFd == STDOUT_FILENO) {
-            fwrite(buf, 1, len, stdout);
+            fwrite(buf.data(), 1, len, stdout);
             fflush(stdout);
         } else {
-            adb_write(outFd, buf, len);
+            adb_write(outFd, buf.data(), len);
         }
         total += len;
     }
@@ -400,7 +399,6 @@
     stdinout_raw_epilogue(inFd, outFd, old_stdin_mode, old_stdout_mode);
 
     D("copy_to_file() finished after %lu bytes", total);
-    free(buf);
 }
 
 static void send_window_size_change(int fd, std::unique_ptr<ShellProtocol>& shell) {
@@ -885,7 +883,7 @@
             return 0;
         }
 
-        int block = strtol(buf, NULL, 10);
+        int block = strtol(buf, nullptr, 10);
 
         size_t offset = block * SIDELOAD_HOST_BLOCK_SIZE;
         if (offset >= static_cast<size_t>(sb.st_size)) {
@@ -968,7 +966,7 @@
             //argv[2] and beyond become ppp_args[1] and beyond
             ppp_args[i - 1] = argv[i];
         }
-        ppp_args[i-1] = NULL;
+        ppp_args[i-1] = nullptr;
 
         // child side
 
@@ -1142,24 +1140,22 @@
 static void write_zeros(int bytes, int fd) {
     int old_stdin_mode = -1;
     int old_stdout_mode = -1;
-    char* buf = (char*) calloc(1, bytes);
-    if (buf == nullptr) fatal("couldn't allocate buffer for write_zeros");
+    std::vector<char> buf(bytes);
 
     D("write_zeros(%d) -> %d", bytes, fd);
 
     stdinout_raw_prologue(-1, fd, old_stdin_mode, old_stdout_mode);
 
     if (fd == STDOUT_FILENO) {
-        fwrite(buf, 1, bytes, stdout);
+        fwrite(buf.data(), 1, bytes, stdout);
         fflush(stdout);
     } else {
-        adb_write(fd, buf, bytes);
+        adb_write(fd, buf.data(), bytes);
     }
 
     stdinout_raw_prologue(-1, fd, old_stdin_mode, old_stdout_mode);
 
     D("write_zeros() finished");
-    free(buf);
 }
 
 static int backup(int argc, const char** argv) {
@@ -1174,7 +1170,7 @@
                 argv[i++] = argv[j++];
             }
             argc -= 2;
-            argv[argc] = NULL;
+            argv[argc] = nullptr;
         }
     }
 
@@ -1969,7 +1965,7 @@
         char* end = strrchr(buf, ']');
         if (start && end) {
             *end = '\0';
-            session_id = strtol(start + 1, NULL, 10);
+            session_id = strtol(start + 1, nullptr, 10);
         }
     }
     if (session_id < 0) {
diff --git a/adb/client/line_printer.cpp b/adb/client/line_printer.cpp
index 64d10b6..9758526 100644
--- a/adb/client/line_printer.cpp
+++ b/adb/client/line_printer.cpp
@@ -52,7 +52,7 @@
   // MSDN says: "For some systems, [_IOLBF] provides line
   // buffering. However, for Win32, the behavior is the same as _IOFBF
   // - Full Buffering."
-  setvbuf(stdout, NULL, _IONBF, 0);
+  setvbuf(stdout, nullptr, _IONBF, 0);
   console_ = GetStdHandle(STD_OUTPUT_HANDLE);
   CONSOLE_SCREEN_BUFFER_INFO csbi;
   smart_terminal_ = GetConsoleScreenBufferInfo(console_, &csbi);
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 44ed3a2..de6c723 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -89,10 +89,10 @@
     // unbuffer stdout and stderr just like if we were run at the console.
     // This also keeps stderr unbuffered when it is redirected to adb.log.
     if (is_daemon) {
-        if (setvbuf(stdout, NULL, _IONBF, 0) == -1) {
+        if (setvbuf(stdout, nullptr, _IONBF, 0) == -1) {
             fatal("cannot make stdout unbuffered: %s", strerror(errno));
         }
-        if (setvbuf(stderr, NULL, _IONBF, 0) == -1) {
+        if (setvbuf(stderr, nullptr, _IONBF, 0) == -1) {
             fatal("cannot make stderr unbuffered: %s", strerror(errno));
         }
     }
diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp
index 46c3f58..10b6090 100644
--- a/adb/client/usb_libusb.cpp
+++ b/adb/client/usb_libusb.cpp
@@ -589,7 +589,7 @@
 
     int rc = perform_usb_transfer(h, info, std::move(lock));
     LOG(DEBUG) << "usb_write(" << len << ") = " << rc;
-    return rc;
+    return info->transfer->actual_length;
 }
 
 int usb_read(usb_handle* h, void* d, int len) {
diff --git a/adb/client/usb_linux.cpp b/adb/client/usb_linux.cpp
index 1f376a4..869e858 100644
--- a/adb/client/usb_linux.cpp
+++ b/adb/client/usb_linux.cpp
@@ -128,7 +128,7 @@
     if (!bus_dir) return;
 
     dirent* de;
-    while ((de = readdir(bus_dir.get())) != 0) {
+    while ((de = readdir(bus_dir.get())) != nullptr) {
         if (contains_non_digit(de->d_name)) continue;
 
         std::string bus_name = base + "/" + de->d_name;
@@ -418,11 +418,11 @@
     if (h->zero_mask && !(len & h->zero_mask)) {
         // If we need 0-markers and our transfer is an even multiple of the packet size,
         // then send a zero marker.
-        return usb_bulk_write(h, _data, 0);
+        return usb_bulk_write(h, _data, 0) == 0 ? n : -1;
     }
 
     D("-- usb_write --");
-    return 0;
+    return n;
 }
 
 int usb_read(usb_handle *h, void *_data, int len)
diff --git a/adb/client/usb_osx.cpp b/adb/client/usb_osx.cpp
index 8a95a19..49baf36 100644
--- a/adb/client/usb_osx.cpp
+++ b/adb/client/usb_osx.cpp
@@ -497,8 +497,8 @@
         }
     }
 
-    if (0 == result)
-        return 0;
+    if (!result)
+        return len;
 
     LOG(ERROR) << "usb_write failed with status: " << std::hex << result;
     return -1;
diff --git a/adb/client/usb_windows.cpp b/adb/client/usb_windows.cpp
index f529e8f..e928377 100644
--- a/adb/client/usb_windows.cpp
+++ b/adb/client/usb_windows.cpp
@@ -126,11 +126,11 @@
 int usb_close(usb_handle* handle);
 
 int known_device_locked(const wchar_t* dev_name) {
-    if (NULL != dev_name) {
+    if (nullptr != dev_name) {
         // Iterate through the list looking for the name match.
         for (usb_handle* usb : handle_list) {
             // In Windows names are not case sensetive!
-            if ((NULL != usb->interface_name) && (0 == wcsicmp(usb->interface_name, dev_name))) {
+            if ((nullptr != usb->interface_name) && (0 == wcsicmp(usb->interface_name, dev_name))) {
                 return 1;
             }
         }
@@ -142,7 +142,7 @@
 int known_device(const wchar_t* dev_name) {
     int ret = 0;
 
-    if (NULL != dev_name) {
+    if (nullptr != dev_name) {
         std::lock_guard<std::mutex> lock(usb_lock);
         ret = known_device_locked(dev_name);
     }
@@ -151,7 +151,7 @@
 }
 
 int register_new_device(usb_handle* handle) {
-    if (NULL == handle) return 0;
+    if (nullptr == handle) return 0;
 
     std::lock_guard<std::mutex> lock(usb_lock);
 
@@ -209,7 +209,7 @@
 
     // Get the HINSTANCE corresponding to the module that _power_window_proc
     // is in (the main module).
-    const HINSTANCE instance = GetModuleHandleW(NULL);
+    const HINSTANCE instance = GetModuleHandleW(nullptr);
     if (!instance) {
         // This is such a common API call that this should never fail.
         fatal("GetModuleHandleW failed: %s",
@@ -228,14 +228,14 @@
     }
 
     if (!CreateWindowExW(WS_EX_NOACTIVATE, kPowerNotificationWindowClassName,
-                         L"ADB Power Notification Window", WS_POPUP, 0, 0, 0, 0, NULL, NULL,
-                         instance, NULL)) {
+                         L"ADB Power Notification Window", WS_POPUP, 0, 0, 0, 0, nullptr, nullptr,
+                         instance, nullptr)) {
         fatal("CreateWindowExW failed: %s",
               android::base::SystemErrorCodeToString(GetLastError()).c_str());
     }
 
     MSG msg;
-    while (GetMessageW(&msg, NULL, 0, 0)) {
+    while (GetMessageW(&msg, nullptr, 0, 0)) {
         TranslateMessage(&msg);
         DispatchMessageW(&msg);
     }
@@ -259,14 +259,14 @@
 
     // Allocate our handle
     usb_handle* ret = (usb_handle*)calloc(1, sizeof(usb_handle));
-    if (NULL == ret) {
+    if (nullptr == ret) {
         D("Could not allocate %u bytes for usb_handle: %s", sizeof(usb_handle), strerror(errno));
         goto fail;
     }
 
     // Create interface.
     ret->adb_interface = AdbCreateInterfaceByName(interface_name);
-    if (NULL == ret->adb_interface) {
+    if (nullptr == ret->adb_interface) {
         D("AdbCreateInterfaceByName failed: %s",
           android::base::SystemErrorCodeToString(GetLastError()).c_str());
         goto fail;
@@ -275,7 +275,7 @@
     // Open read pipe (endpoint)
     ret->adb_read_pipe = AdbOpenDefaultBulkReadEndpoint(
         ret->adb_interface, AdbOpenAccessTypeReadWrite, AdbOpenSharingModeReadWrite);
-    if (NULL == ret->adb_read_pipe) {
+    if (nullptr == ret->adb_read_pipe) {
         D("AdbOpenDefaultBulkReadEndpoint failed: %s",
           android::base::SystemErrorCodeToString(GetLastError()).c_str());
         goto fail;
@@ -284,7 +284,7 @@
     // Open write pipe (endpoint)
     ret->adb_write_pipe = AdbOpenDefaultBulkWriteEndpoint(
         ret->adb_interface, AdbOpenAccessTypeReadWrite, AdbOpenSharingModeReadWrite);
-    if (NULL == ret->adb_write_pipe) {
+    if (nullptr == ret->adb_write_pipe) {
         D("AdbOpenDefaultBulkWriteEndpoint failed: %s",
           android::base::SystemErrorCodeToString(GetLastError()).c_str());
         goto fail;
@@ -292,7 +292,7 @@
 
     // Save interface name
     // First get expected name length
-    AdbGetInterfaceName(ret->adb_interface, NULL, &name_len, false);
+    AdbGetInterfaceName(ret->adb_interface, nullptr, &name_len, false);
     if (0 == name_len) {
         D("AdbGetInterfaceName returned name length of zero: %s",
           android::base::SystemErrorCodeToString(GetLastError()).c_str());
@@ -300,7 +300,7 @@
     }
 
     ret->interface_name = (wchar_t*)malloc(name_len * sizeof(ret->interface_name[0]));
-    if (NULL == ret->interface_name) {
+    if (nullptr == ret->interface_name) {
         D("Could not allocate %lu characters for interface_name: %s", name_len, strerror(errno));
         goto fail;
     }
@@ -316,12 +316,12 @@
     return ret;
 
 fail:
-    if (NULL != ret) {
+    if (nullptr != ret) {
         usb_cleanup_handle(ret);
         free(ret);
     }
 
-    return NULL;
+    return nullptr;
 }
 
 int usb_write(usb_handle* handle, const void* data, int len) {
@@ -330,7 +330,7 @@
     int err = 0;
 
     D("usb_write %d", len);
-    if (NULL == handle) {
+    if (nullptr == handle) {
         D("usb_write was passed NULL handle");
         err = EINVAL;
         goto fail;
@@ -365,12 +365,12 @@
         }
     }
 
-    return 0;
+    return written;
 
 fail:
     // Any failure should cause us to kick the device instead of leaving it a
     // zombie state with potential to hang.
-    if (NULL != handle) {
+    if (nullptr != handle) {
         D("Kicking device due to error in usb_write");
         usb_kick(handle);
     }
@@ -387,7 +387,7 @@
     int orig_len = len;
 
     D("usb_read %d", len);
-    if (NULL == handle) {
+    if (nullptr == handle) {
         D("usb_read was passed NULL handle");
         err = EINVAL;
         goto fail;
@@ -411,7 +411,7 @@
 fail:
     // Any failure should cause us to kick the device instead of leaving it a
     // zombie state with potential to hang.
-    if (NULL != handle) {
+    if (nullptr != handle) {
         D("Kicking device due to error in usb_read");
         usb_kick(handle);
     }
@@ -431,19 +431,19 @@
 
 void usb_cleanup_handle(usb_handle* handle) {
     D("usb_cleanup_handle");
-    if (NULL != handle) {
-        if (NULL != handle->interface_name) free(handle->interface_name);
+    if (nullptr != handle) {
+        if (nullptr != handle->interface_name) free(handle->interface_name);
         // AdbCloseHandle(pipe) will break any threads out of pending IO calls and
         // wait until the pipe no longer uses the interface. Then we can
         // AdbCloseHandle() the interface.
-        if (NULL != handle->adb_write_pipe) _adb_close_handle(handle->adb_write_pipe);
-        if (NULL != handle->adb_read_pipe) _adb_close_handle(handle->adb_read_pipe);
-        if (NULL != handle->adb_interface) _adb_close_handle(handle->adb_interface);
+        if (nullptr != handle->adb_write_pipe) _adb_close_handle(handle->adb_write_pipe);
+        if (nullptr != handle->adb_read_pipe) _adb_close_handle(handle->adb_read_pipe);
+        if (nullptr != handle->adb_interface) _adb_close_handle(handle->adb_interface);
 
-        handle->interface_name = NULL;
-        handle->adb_write_pipe = NULL;
-        handle->adb_read_pipe = NULL;
-        handle->adb_interface = NULL;
+        handle->interface_name = nullptr;
+        handle->adb_write_pipe = nullptr;
+        handle->adb_read_pipe = nullptr;
+        handle->adb_interface = nullptr;
     }
 }
 
@@ -455,7 +455,7 @@
 
 void usb_kick(usb_handle* handle) {
     D("usb_kick");
-    if (NULL != handle) {
+    if (nullptr != handle) {
         std::lock_guard<std::mutex> lock(usb_lock);
         usb_kick_locked(handle);
     } else {
@@ -466,7 +466,7 @@
 int usb_close(usb_handle* handle) {
     D("usb_close");
 
-    if (NULL != handle) {
+    if (nullptr != handle) {
         // Remove handle from the list
         {
             std::lock_guard<std::mutex> lock(usb_lock);
@@ -487,7 +487,7 @@
 }
 
 int recognized_device(usb_handle* handle) {
-    if (NULL == handle) return 0;
+    if (nullptr == handle) return 0;
 
     // Check vendor and product id first
     USB_DEVICE_DESCRIPTOR device_desc;
@@ -532,7 +532,7 @@
 }
 
 void find_devices() {
-    usb_handle* handle = NULL;
+    usb_handle* handle = nullptr;
     char entry_buffer[2048];
     AdbInterfaceInfo* next_interface = (AdbInterfaceInfo*)(&entry_buffer[0]);
     unsigned long entry_buffer_size = sizeof(entry_buffer);
@@ -540,7 +540,7 @@
     // Enumerate all present and active interfaces.
     ADBAPIHANDLE enum_handle = AdbEnumInterfaces(usb_class_id, true, true, true);
 
-    if (NULL == enum_handle) {
+    if (nullptr == enum_handle) {
         D("AdbEnumInterfaces failed: %s",
           android::base::SystemErrorCodeToString(GetLastError()).c_str());
         return;
@@ -551,7 +551,7 @@
         if (!known_device(next_interface->device_name)) {
             // This seems to be a new device. Open it!
             handle = do_usb_open(next_interface->device_name);
-            if (NULL != handle) {
+            if (nullptr != handle) {
                 // Lets see if this interface (device) belongs to us
                 if (recognized_device(handle)) {
                     D("adding a new device %ls", next_interface->device_name);
@@ -569,7 +569,7 @@
                                            true)) {
                         // Lets make sure that we don't duplicate this device
                         if (register_new_device(handle)) {
-                            register_usb_transport(handle, serial_number, NULL, 1);
+                            register_usb_transport(handle, serial_number, nullptr, 1);
                         } else {
                             D("register_new_device failed for %ls", next_interface->device_name);
                             usb_cleanup_handle(handle);
diff --git a/adb/daemon/auth.cpp b/adb/daemon/auth.cpp
index f0c3629..180df8f 100644
--- a/adb/daemon/auth.cpp
+++ b/adb/daemon/auth.cpp
@@ -100,7 +100,7 @@
 
 static void usb_disconnected(void* unused, atransport* t) {
     LOG(INFO) << "USB disconnect";
-    usb_transport = NULL;
+    usb_transport = nullptr;
     needs_retry = false;
 }
 
@@ -200,7 +200,7 @@
         return;
     }
 
-    listener_fde = fdevent_create(fd, adbd_auth_listener, NULL);
+    listener_fde = fdevent_create(fd, adbd_auth_listener, nullptr);
     fdevent_add(listener_fde, FDE_READ);
 }
 
diff --git a/adb/daemon/file_sync_service.cpp b/adb/daemon/file_sync_service.cpp
index f7be8f9..0b71363 100644
--- a/adb/daemon/file_sync_service.cpp
+++ b/adb/daemon/file_sync_service.cpp
@@ -525,12 +525,11 @@
     return true;
 }
 
-void file_sync_service(int fd, void*) {
+void file_sync_service(android::base::unique_fd fd) {
     std::vector<char> buffer(SYNC_DATA_MAX);
 
-    while (handle_sync_command(fd, buffer)) {
+    while (handle_sync_command(fd.get(), buffer)) {
     }
 
     D("sync: done");
-    adb_close(fd);
 }
diff --git a/adb/daemon/framebuffer_service.cpp b/adb/daemon/framebuffer_service.cpp
index 6c3a225..9a620ab 100644
--- a/adb/daemon/framebuffer_service.cpp
+++ b/adb/daemon/framebuffer_service.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "framebuffer_service.h"
+
 #include <errno.h>
 #include <fcntl.h>
 #include <linux/fb.h>
@@ -55,8 +57,7 @@
     unsigned int alpha_length;
 } __attribute__((packed));
 
-void framebuffer_service(int fd, void *cookie)
-{
+void framebuffer_service(android::base::unique_fd fd) {
     struct fbinfo fbinfo;
     unsigned int i, bsize;
     char buf[640];
@@ -65,7 +66,7 @@
     int fds[2];
     pid_t pid;
 
-    if (pipe2(fds, O_CLOEXEC) < 0) goto pipefail;
+    if (pipe2(fds, O_CLOEXEC) < 0) return;
 
     pid = fork();
     if (pid < 0) goto done;
@@ -75,7 +76,7 @@
         adb_close(fds[0]);
         adb_close(fds[1]);
         const char* command = "screencap";
-        const char *args[2] = {command, NULL};
+        const char *args[2] = {command, nullptr};
         execvp(command, (char**)args);
         exit(1);
     }
@@ -168,7 +169,7 @@
     }
 
     /* write header */
-    if(!WriteFdExactly(fd, &fbinfo, sizeof(fbinfo))) goto done;
+    if (!WriteFdExactly(fd.get(), &fbinfo, sizeof(fbinfo))) goto done;
 
     /* write data */
     for(i = 0; i < fbinfo.size; i += bsize) {
@@ -176,13 +177,11 @@
       if (i + bsize > fbinfo.size)
         bsize = fbinfo.size - i;
       if(!ReadFdExactly(fd_screencap, buf, bsize)) goto done;
-      if(!WriteFdExactly(fd, buf, bsize)) goto done;
+      if (!WriteFdExactly(fd.get(), buf, bsize)) goto done;
     }
 
 done:
     adb_close(fds[0]);
 
-    TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0));
-pipefail:
-    adb_close(fd);
+    TEMP_FAILURE_RETRY(waitpid(pid, nullptr, 0));
 }
diff --git a/init/init_first_stage.h b/adb/daemon/framebuffer_service.h
similarity index 67%
copy from init/init_first_stage.h
copy to adb/daemon/framebuffer_service.h
index c7a3867..d99c6fe 100644
--- a/init/init_first_stage.h
+++ b/adb/daemon/framebuffer_service.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 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,16 +14,11 @@
  * limitations under the License.
  */
 
-#ifndef _INIT_FIRST_STAGE_H
-#define _INIT_FIRST_STAGE_H
+#ifndef _DAEMON_FRAMEBUFFER_SERVICE_H_
+#define _DAEMON_FRAMEBUFFER_SERVICE_H_
 
-namespace android {
-namespace init {
+#include <android-base/unique_fd.h>
 
-bool DoFirstStageMount();
-void SetInitAvbVersionInRecovery();
+void framebuffer_service(android::base::unique_fd fd);
 
-}  // namespace init
-}  // namespace android
-
-#endif
+#endif  // _DAEMON_FRAMEBUFFER_SERVICE_H_
diff --git a/adb/daemon/usb.h b/adb/daemon/include/adbd/usb.h
similarity index 92%
rename from adb/daemon/usb.h
rename to adb/daemon/include/adbd/usb.h
index 15a7f65..7905d9d 100644
--- a/adb/daemon/usb.h
+++ b/adb/daemon/include/adbd/usb.h
@@ -19,6 +19,7 @@
 #include <atomic>
 #include <condition_variable>
 #include <mutex>
+#include <vector>
 
 #include <asyncio/AsyncIO.h>
 
@@ -54,5 +55,9 @@
     // read and write threads.
     struct aio_block read_aiob;
     struct aio_block write_aiob;
+
+    bool reads_zero_packets;
+    size_t io_size;
 };
 
+usb_handle *create_usb_handle(unsigned num_bufs, unsigned io_size);
diff --git a/adb/daemon/jdwp_service.cpp b/adb/daemon/jdwp_service.cpp
index 367695d..175e82e 100644
--- a/adb/daemon/jdwp_service.cpp
+++ b/adb/daemon/jdwp_service.cpp
@@ -264,7 +264,7 @@
 
             iov.iov_base = &dummy;
             iov.iov_len = 1;
-            msg.msg_name = NULL;
+            msg.msg_name = nullptr;
             msg.msg_namelen = 0;
             msg.msg_iov = &iov;
             msg.msg_iovlen = 1;
@@ -393,7 +393,7 @@
     control->listen_socket = s;
 
     control->fde = fdevent_create(s, jdwp_control_event, control);
-    if (control->fde == NULL) {
+    if (control->fde == nullptr) {
         D("could not create fdevent for jdwp control socket");
         adb_close(s);
         return -1;
diff --git a/adb/daemon/remount_service.cpp b/adb/daemon/remount_service.cpp
index 830b35d..1bb2fbb 100644
--- a/adb/daemon/remount_service.cpp
+++ b/adb/daemon/remount_service.cpp
@@ -26,6 +26,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/mount.h>
+#include <sys/statvfs.h>
 #include <sys/vfs.h>
 #include <unistd.h>
 
@@ -43,6 +44,7 @@
 #include "adb_unique_fd.h"
 #include "adb_utils.h"
 #include "fs_mgr.h"
+#include "set_verity_enable_state_service.h"
 
 // Returns the device used to mount a directory in /proc/mounts.
 static std::string find_proc_mount(const char* dir) {
@@ -145,6 +147,17 @@
     return true;
 }
 
+static unsigned long get_mount_flags(int fd, const char* dir) {
+    struct statvfs st_vfs;
+    if (statvfs(dir, &st_vfs) == -1) {
+        // Even though we could not get the original mount flags, assume that
+        // the mount was originally read-only.
+        WriteFdFmt(fd, "statvfs of the %s mount failed: %s.\n", dir, strerror(errno));
+        return MS_RDONLY;
+    }
+    return st_vfs.f_flag;
+}
+
 static bool remount_partition(int fd, const char* dir) {
     if (!directory_exists(dir)) {
         return true;
@@ -163,7 +176,12 @@
                    dir, dev.c_str(), strerror(errno));
         return false;
     }
-    if (mount(dev.c_str(), dir, "none", MS_REMOUNT | MS_BIND, nullptr) == -1) {
+
+    unsigned long remount_flags = get_mount_flags(fd, dir);
+    remount_flags &= ~MS_RDONLY;
+    remount_flags |= MS_REMOUNT;
+
+    if (mount(dev.c_str(), dir, "none", remount_flags | MS_BIND, nullptr) == -1) {
         // This is useful for cases where the superblock is already marked as
         // read-write, but the mount itself is read-only, such as containers
         // where the remount with just MS_REMOUNT is forbidden by the kernel.
@@ -197,14 +215,11 @@
     android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_cmd.c_str());
 }
 
-void remount_service(int fd, void* cookie) {
-    unique_fd close_fd(fd);
-
-    const char* cmd = reinterpret_cast<const char*>(cookie);
-    bool user_requested_reboot = cmd && !strcmp(cmd, "-R");
+void remount_service(android::base::unique_fd fd, const std::string& cmd) {
+    bool user_requested_reboot = cmd != "-R";
 
     if (getuid() != 0) {
-        WriteFdExactly(fd, "Not running as root. Try \"adb root\" first.\n");
+        WriteFdExactly(fd.get(), "Not running as root. Try \"adb root\" first.\n");
         return;
     }
 
@@ -225,7 +240,7 @@
         if (dev.empty() || !fs_has_shared_blocks(dev.c_str())) {
             continue;
         }
-        if (can_unshare_blocks(fd, dev.c_str())) {
+        if (can_unshare_blocks(fd.get(), dev.c_str())) {
             dedup.emplace(partition);
         }
     }
@@ -236,12 +251,12 @@
     if (user_requested_reboot) {
         if (!dedup.empty() || verity_enabled) {
             if (verity_enabled) {
-                set_verity_enabled_state_service(fd, nullptr);
+                set_verity_enabled_state_service(android::base::unique_fd(dup(fd.get())), false);
             }
-            reboot_for_remount(fd, !dedup.empty());
+            reboot_for_remount(fd.get(), !dedup.empty());
             return;
         }
-        WriteFdExactly(fd, "No reboot needed, skipping -R.\n");
+        WriteFdExactly(fd.get(), "No reboot needed, skipping -R.\n");
     }
 
     // If we need to disable-verity, but we also need to perform a recovery
@@ -250,17 +265,14 @@
     if (verity_enabled && dedup.empty()) {
         // Allow remount but warn of likely bad effects
         bool both = system_verified && vendor_verified;
-        WriteFdFmt(fd,
-                   "dm_verity is enabled on the %s%s%s partition%s.\n",
-                   system_verified ? "system" : "",
-                   both ? " and " : "",
-                   vendor_verified ? "vendor" : "",
-                   both ? "s" : "");
-        WriteFdExactly(fd,
+        WriteFdFmt(fd.get(), "dm_verity is enabled on the %s%s%s partition%s.\n",
+                   system_verified ? "system" : "", both ? " and " : "",
+                   vendor_verified ? "vendor" : "", both ? "s" : "");
+        WriteFdExactly(fd.get(),
                        "Use \"adb disable-verity\" to disable verity.\n"
                        "If you do not, remount may succeed, however, you will still "
                        "not be able to write to these volumes.\n");
-        WriteFdExactly(fd,
+        WriteFdExactly(fd.get(),
                        "Alternately, use \"adb remount -R\" to disable verity "
                        "and automatically reboot.\n");
     }
@@ -271,29 +283,29 @@
         if (dedup.count(partition)) {
             continue;
         }
-        success &= remount_partition(fd, partition.c_str());
+        success &= remount_partition(fd.get(), partition.c_str());
     }
 
     if (!dedup.empty()) {
-        WriteFdExactly(fd,
+        WriteFdExactly(fd.get(),
                        "The following partitions are deduplicated and cannot "
                        "yet be remounted:\n");
         for (const std::string& name : dedup) {
-            WriteFdFmt(fd, "  %s\n", name.c_str());
+            WriteFdFmt(fd.get(), "  %s\n", name.c_str());
         }
 
-        WriteFdExactly(fd,
+        WriteFdExactly(fd.get(),
                        "To reboot and un-deduplicate the listed partitions, "
                        "please retry with adb remount -R.\n");
         if (system_verified || vendor_verified) {
-            WriteFdExactly(fd, "Note: verity will be automatically disabled after reboot.\n");
+            WriteFdExactly(fd.get(), "Note: verity will be automatically disabled after reboot.\n");
         }
         return;
     }
 
     if (!success) {
-        WriteFdExactly(fd, "remount failed\n");
+        WriteFdExactly(fd.get(), "remount failed\n");
     } else {
-        WriteFdExactly(fd, "remount succeeded\n");
+        WriteFdExactly(fd.get(), "remount succeeded\n");
     }
 }
diff --git a/adb/daemon/set_verity_enable_state_service.cpp b/adb/daemon/set_verity_enable_state_service.cpp
index 0fcf89b..0f804e9 100644
--- a/adb/daemon/set_verity_enable_state_service.cpp
+++ b/adb/daemon/set_verity_enable_state_service.cpp
@@ -16,6 +16,7 @@
 
 #define TRACE_TAG ADB
 
+#include "set_verity_enable_state_service.h"
 #include "sysdeps.h"
 
 #include <fcntl.h>
@@ -25,8 +26,8 @@
 #include <stdio.h>
 #include <sys/stat.h>
 
-#include "android-base/properties.h"
-#include "android-base/stringprintf.h"
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
 #include <log/log_properties.h>
 
 #include "adb.h"
@@ -131,12 +132,9 @@
     return true;
 }
 
-void set_verity_enabled_state_service(int fd, void* cookie) {
-    unique_fd closer(fd);
+void set_verity_enabled_state_service(android::base::unique_fd fd, bool enable) {
     bool any_changed = false;
 
-    bool enable = (cookie != NULL);
-
     // Figure out if we're using VB1.0 or VB2.0 (aka AVB) - by
     // contract, androidboot.vbmeta.digest is set by the bootloader
     // when using AVB).
@@ -147,12 +145,12 @@
     // VB1.0 dm-verity is only enabled on certain builds.
     if (!using_avb) {
         if (!kAllowDisableVerity) {
-            WriteFdFmt(fd, "%s-verity only works for userdebug builds\n",
+            WriteFdFmt(fd.get(), "%s-verity only works for userdebug builds\n",
                        enable ? "enable" : "disable");
         }
 
         if (!android::base::GetBoolProperty("ro.secure", false)) {
-            WriteFdFmt(fd, "verity not enabled - ENG build\n");
+            WriteFdFmt(fd.get(), "verity not enabled - ENG build\n");
             return;
         }
     }
@@ -160,7 +158,7 @@
     // Should never be possible to disable dm-verity on a USER build
     // regardless of using AVB or VB1.0.
     if (!__android_log_is_debuggable()) {
-        WriteFdFmt(fd, "verity cannot be disabled/enabled - USER build\n");
+        WriteFdFmt(fd.get(), "verity cannot be disabled/enabled - USER build\n");
         return;
     }
 
@@ -168,10 +166,10 @@
         // Yep, the system is using AVB.
         AvbOps* ops = avb_ops_user_new();
         if (ops == nullptr) {
-            WriteFdFmt(fd, "Error getting AVB ops\n");
+            WriteFdFmt(fd.get(), "Error getting AVB ops\n");
             return;
         }
-        if (set_avb_verity_enabled_state(fd, ops, enable)) {
+        if (set_avb_verity_enabled_state(fd.get(), ops, enable)) {
             any_changed = true;
         }
         avb_ops_user_free(ops);
@@ -181,14 +179,14 @@
         // read all fstab entries at once from all sources
         fstab = fs_mgr_read_fstab_default();
         if (!fstab) {
-            WriteFdFmt(fd, "Failed to read fstab\nMaybe run adb root?\n");
+            WriteFdFmt(fd.get(), "Failed to read fstab\nMaybe run adb root?\n");
             return;
         }
 
         // Loop through entries looking for ones that vold manages.
         for (int i = 0; i < fstab->num_entries; i++) {
             if (fs_mgr_is_verified(&fstab->recs[i])) {
-                if (set_verity_enabled_state(fd, fstab->recs[i].blk_device,
+                if (set_verity_enabled_state(fd.get(), fstab->recs[i].blk_device,
                                              fstab->recs[i].mount_point, enable)) {
                     any_changed = true;
                 }
@@ -197,6 +195,6 @@
     }
 
     if (any_changed) {
-        WriteFdFmt(fd, "Now reboot your device for settings to take effect\n");
+        WriteFdFmt(fd.get(), "Now reboot your device for settings to take effect\n");
     }
 }
diff --git a/init/init_first_stage.h b/adb/daemon/set_verity_enable_state_service.h
similarity index 62%
copy from init/init_first_stage.h
copy to adb/daemon/set_verity_enable_state_service.h
index c7a3867..9f84f35 100644
--- a/init/init_first_stage.h
+++ b/adb/daemon/set_verity_enable_state_service.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 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,16 +14,11 @@
  * limitations under the License.
  */
 
-#ifndef _INIT_FIRST_STAGE_H
-#define _INIT_FIRST_STAGE_H
+#ifndef _DAEMON_SET_VERITY_ENABLED_STATE_SERVICE_H_
+#define _DAEMON_SET_VERITY_ENABLED_STATE_SERVICE_H_
 
-namespace android {
-namespace init {
+#include <android-base/unique_fd.h>
 
-bool DoFirstStageMount();
-void SetInitAvbVersionInRecovery();
+void set_verity_enabled_state_service(android::base::unique_fd fd, bool enable);
 
-}  // namespace init
-}  // namespace android
-
-#endif
+#endif  // _DAEMON_SET_VERITY_ENABLED_STATE_SERVICE_H_
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index c724b11..c79d6fc 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -41,7 +41,7 @@
 #include <android-base/properties.h>
 
 #include "adb.h"
-#include "daemon/usb.h"
+#include "adbd/usb.h"
 #include "transport.h"
 
 using namespace std::chrono_literals;
@@ -53,7 +53,7 @@
 #define USB_FFS_BULK_SIZE 16384
 
 // Number of buffers needed to fit MAX_PAYLOAD, with an extra for ZLPs.
-#define USB_FFS_NUM_BUFS ((MAX_PAYLOAD / USB_FFS_BULK_SIZE) + 1)
+#define USB_FFS_NUM_BUFS ((4 * MAX_PAYLOAD / USB_FFS_BULK_SIZE) + 1)
 
 #define cpu_to_le16(x) htole16(x)
 #define cpu_to_le32(x) htole32(x)
@@ -226,16 +226,16 @@
     },
 };
 
-static void aio_block_init(aio_block* aiob) {
-    aiob->iocb.resize(USB_FFS_NUM_BUFS);
-    aiob->iocbs.resize(USB_FFS_NUM_BUFS);
-    aiob->events.resize(USB_FFS_NUM_BUFS);
+static void aio_block_init(aio_block* aiob, unsigned num_bufs) {
+    aiob->iocb.resize(num_bufs);
+    aiob->iocbs.resize(num_bufs);
+    aiob->events.resize(num_bufs);
     aiob->num_submitted = 0;
-    for (unsigned i = 0; i < USB_FFS_NUM_BUFS; i++) {
+    for (unsigned i = 0; i < num_bufs; i++) {
         aiob->iocbs[i] = &aiob->iocb[i];
     }
     memset(&aiob->ctx, 0, sizeof(aiob->ctx));
-    if (io_setup(USB_FFS_NUM_BUFS, &aiob->ctx)) {
+    if (io_setup(num_bufs, &aiob->ctx)) {
         D("[ aio: got error on io_setup (%d) ]", errno);
     }
 }
@@ -250,7 +250,7 @@
     }
 }
 
-bool init_functionfs(struct usb_handle* h) {
+static bool init_functionfs(struct usb_handle* h) {
     LOG(INFO) << "initializing functionfs";
 
     ssize_t ret;
@@ -318,6 +318,7 @@
 
     h->read_aiob.fd = h->bulk_out;
     h->write_aiob.fd = h->bulk_in;
+    h->reads_zero_packets = true;
     return true;
 
 err:
@@ -336,9 +337,7 @@
     return false;
 }
 
-static void usb_ffs_open_thread(void* x) {
-    struct usb_handle* usb = (struct usb_handle*)x;
-
+static void usb_ffs_open_thread(usb_handle *usb) {
     adb_thread_setname("usb ffs open");
 
     while (true) {
@@ -359,7 +358,7 @@
         }
 
         LOG(INFO) << "registering usb transport";
-        register_usb_transport(usb, 0, 0, 1);
+        register_usb_transport(usb, nullptr, nullptr, 1);
     }
 
     // never gets here
@@ -370,6 +369,7 @@
     D("about to write (fd=%d, len=%d)", h->bulk_in, len);
 
     const char* buf = static_cast<const char*>(data);
+    int orig_len = len;
     while (len > 0) {
         int write_len = std::min(USB_FFS_BULK_SIZE, len);
         int n = adb_write(h->bulk_in, buf, write_len);
@@ -382,13 +382,14 @@
     }
 
     D("[ done fd=%d ]", h->bulk_in);
-    return 0;
+    return orig_len;
 }
 
 static int usb_ffs_read(usb_handle* h, void* data, int len) {
     D("about to read (fd=%d, len=%d)", h->bulk_out, len);
 
     char* buf = static_cast<char*>(data);
+    int orig_len = len;
     while (len > 0) {
         int read_len = std::min(USB_FFS_BULK_SIZE, len);
         int n = adb_read(h->bulk_out, buf, read_len);
@@ -401,14 +402,14 @@
     }
 
     D("[ done fd=%d ]", h->bulk_out);
-    return 0;
+    return orig_len;
 }
 
 static int usb_ffs_do_aio(usb_handle* h, const void* data, int len, bool read) {
     aio_block* aiob = read ? &h->read_aiob : &h->write_aiob;
     bool zero_packet = false;
 
-    int num_bufs = len / USB_FFS_BULK_SIZE + (len % USB_FFS_BULK_SIZE == 0 ? 0 : 1);
+    int num_bufs = len / h->io_size + (len % h->io_size == 0 ? 0 : 1);
     const char* cur_data = reinterpret_cast<const char*>(data);
     int packet_size = getMaxPacketSize(aiob->fd);
 
@@ -418,7 +419,7 @@
     }
 
     for (int i = 0; i < num_bufs; i++) {
-        int buf_len = std::min(len, USB_FFS_BULK_SIZE);
+        int buf_len = std::min(len, static_cast<int>(h->io_size));
         io_prep(&aiob->iocb[i], aiob->fd, cur_data, buf_len, 0, read);
 
         len -= buf_len;
@@ -427,7 +428,7 @@
         if (len == 0 && buf_len % packet_size == 0 && read) {
             // adb does not expect the device to send a zero packet after data transfer,
             // but the host *does* send a zero packet for the device to read.
-            zero_packet = true;
+            zero_packet = h->reads_zero_packets;
         }
     }
     if (zero_packet) {
@@ -449,6 +450,7 @@
         if (num_bufs == 1 && aiob->events[0].res == -EINTR) {
             continue;
         }
+        int ret = 0;
         for (int i = 0; i < num_bufs; i++) {
             if (aiob->events[i].res < 0) {
                 errno = -aiob->events[i].res;
@@ -456,8 +458,9 @@
                             << " total bufs " << num_bufs;
                 return -1;
             }
+            ret += aiob->events[i].res;
         }
-        return 0;
+        return ret;
     }
 }
 
@@ -505,9 +508,7 @@
     h->notify.notify_one();
 }
 
-static void usb_ffs_init() {
-    D("[ usb_init - using FunctionFS ]");
-
+usb_handle *create_usb_handle(unsigned num_bufs, unsigned io_size) {
     usb_handle* h = new usb_handle();
 
     if (android::base::GetBoolProperty("sys.usb.ffs.aio_compat", false)) {
@@ -518,20 +519,21 @@
     } else {
         h->write = usb_ffs_aio_write;
         h->read = usb_ffs_aio_read;
-        aio_block_init(&h->read_aiob);
-        aio_block_init(&h->write_aiob);
+        aio_block_init(&h->read_aiob, num_bufs);
+        aio_block_init(&h->write_aiob, num_bufs);
     }
+    h->io_size = io_size;
     h->kick = usb_ffs_kick;
     h->close = usb_ffs_close;
-
-    D("[ usb_init - starting thread ]");
-    std::thread(usb_ffs_open_thread, h).detach();
+    return h;
 }
 
 void usb_init() {
+    D("[ usb_init - using FunctionFS ]");
     dummy_fd = adb_open("/dev/null", O_WRONLY);
     CHECK_NE(dummy_fd, -1);
-    usb_ffs_init();
+
+    std::thread(usb_ffs_open_thread, create_usb_handle(USB_FFS_NUM_BUFS, USB_FFS_BULK_SIZE)).detach();
 }
 
 int usb_write(usb_handle* h, const void* data, int len) {
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 098a39d..dee87bd 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -149,7 +149,7 @@
 
 void fdevent_destroy(fdevent* fde) {
     check_main_thread();
-    if (fde == 0) return;
+    if (fde == nullptr) return;
     if (!(fde->state & FDE_CREATED)) {
         LOG(FATAL) << "destroying fde not created by fdevent_create(): " << dump_fde(fde);
     }
diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h
index 6606efd..608b3ad 100644
--- a/adb/file_sync_service.h
+++ b/adb/file_sync_service.h
@@ -20,6 +20,8 @@
 #include <string>
 #include <vector>
 
+#include <android-base/unique_fd.h>
+
 #define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
 
 #define ID_LSTAT_V1 MKID('S','T','A','T')
@@ -79,7 +81,7 @@
     } status;
 };
 
-void file_sync_service(int fd, void* cookie);
+void file_sync_service(android::base::unique_fd fd);
 bool do_sync_ls(const char* path);
 bool do_sync_push(const std::vector<const char*>& srcs, const char* dst, bool sync);
 bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
diff --git a/adb/remount_service.h b/adb/remount_service.h
index 7bda1be..45821ee 100644
--- a/adb/remount_service.h
+++ b/adb/remount_service.h
@@ -19,7 +19,9 @@
 
 #include <string>
 
+#include <android-base/unique_fd.h>
+
 bool make_block_device_writable(const std::string&);
-void remount_service(int, void*);
+void remount_service(android::base::unique_fd, const std::string&);
 
 #endif
diff --git a/adb/services.cpp b/adb/services.cpp
index a757d90..3d418cb 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -37,6 +37,7 @@
 #include <android-base/parsenetaddress.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <android-base/unique_fd.h>
 #include <cutils/sockets.h>
 
 #if !ADB_HOST
@@ -49,6 +50,10 @@
 #include "adb.h"
 #include "adb_io.h"
 #include "adb_utils.h"
+#if !ADB_HOST
+#include "daemon/framebuffer_service.h"
+#include "daemon/set_verity_enable_state_service.h"
+#endif
 #include "file_sync_service.h"
 #include "remount_service.h"
 #include "services.h"
@@ -57,81 +62,67 @@
 #include "sysdeps.h"
 #include "transport.h"
 
-struct stinfo {
-    const char* service_name;
-    void (*func)(int fd, void *cookie);
-    int fd;
-    void *cookie;
-};
+namespace {
 
-static void service_bootstrap_func(void* x) {
-    stinfo* sti = reinterpret_cast<stinfo*>(x);
-    adb_thread_setname(android::base::StringPrintf("%s svc %d", sti->service_name, sti->fd));
-    sti->func(sti->fd, sti->cookie);
-    free(sti);
+void service_bootstrap_func(std::string service_name,
+                            std::function<void(android::base::unique_fd)> func,
+                            android::base::unique_fd fd) {
+    adb_thread_setname(android::base::StringPrintf("%s svc %d", service_name.c_str(), fd.get()));
+    func(std::move(fd));
 }
 
 #if !ADB_HOST
 
-void restart_root_service(int fd, void *cookie) {
+void restart_root_service(android::base::unique_fd fd) {
     if (getuid() == 0) {
-        WriteFdExactly(fd, "adbd is already running as root\n");
-        adb_close(fd);
-    } else {
-        if (!__android_log_is_debuggable()) {
-            WriteFdExactly(fd, "adbd cannot run as root in production builds\n");
-            adb_close(fd);
-            return;
-        }
-
-        android::base::SetProperty("service.adb.root", "1");
-        WriteFdExactly(fd, "restarting adbd as root\n");
-        adb_close(fd);
+        WriteFdExactly(fd.get(), "adbd is already running as root\n");
+        return;
     }
+    if (!__android_log_is_debuggable()) {
+        WriteFdExactly(fd.get(), "adbd cannot run as root in production builds\n");
+        return;
+    }
+
+    android::base::SetProperty("service.adb.root", "1");
+    WriteFdExactly(fd.get(), "restarting adbd as root\n");
 }
 
-void restart_unroot_service(int fd, void *cookie) {
+void restart_unroot_service(android::base::unique_fd fd) {
     if (getuid() != 0) {
-        WriteFdExactly(fd, "adbd not running as root\n");
-        adb_close(fd);
-    } else {
-        android::base::SetProperty("service.adb.root", "0");
-        WriteFdExactly(fd, "restarting adbd as non root\n");
-        adb_close(fd);
+        WriteFdExactly(fd.get(), "adbd not running as root\n");
+        return;
     }
+    android::base::SetProperty("service.adb.root", "0");
+    WriteFdExactly(fd.get(), "restarting adbd as non root\n");
 }
 
-void restart_tcp_service(int fd, void *cookie) {
-    int port = (int) (uintptr_t) cookie;
+void restart_tcp_service(android::base::unique_fd fd, int port) {
     if (port <= 0) {
-        WriteFdFmt(fd, "invalid port %d\n", port);
-        adb_close(fd);
+        WriteFdFmt(fd.get(), "invalid port %d\n", port);
         return;
     }
 
     android::base::SetProperty("service.adb.tcp.port", android::base::StringPrintf("%d", port));
-    WriteFdFmt(fd, "restarting in TCP mode port: %d\n", port);
-    adb_close(fd);
+    WriteFdFmt(fd.get(), "restarting in TCP mode port: %d\n", port);
 }
 
-void restart_usb_service(int fd, void *cookie) {
+void restart_usb_service(android::base::unique_fd fd) {
     android::base::SetProperty("service.adb.tcp.port", "0");
-    WriteFdExactly(fd, "restarting in USB mode\n");
-    adb_close(fd);
+    WriteFdExactly(fd.get(), "restarting in USB mode\n");
 }
 
-static bool reboot_service_impl(int fd, const char* arg) {
-    const char* reboot_arg = arg;
+bool reboot_service_impl(android::base::unique_fd fd, const std::string& arg) {
+    std::string reboot_arg = arg;
     bool auto_reboot = false;
 
-    if (strcmp(reboot_arg, "sideload-auto-reboot") == 0) {
+    if (reboot_arg == "sideload-auto-reboot") {
         auto_reboot = true;
         reboot_arg = "sideload";
     }
 
     // It reboots into sideload mode by setting "--sideload" or "--sideload_auto_reboot"
     // in the command file.
-    if (strcmp(reboot_arg, "sideload") == 0) {
+    if (reboot_arg == "sideload") {
         if (getuid() != 0) {
             WriteFdExactly(fd, "'adb root' is required for 'adb reboot sideload'.\n");
             return false;
@@ -151,8 +142,8 @@
 
     sync();
 
-    if (!reboot_arg || !reboot_arg[0]) reboot_arg = "adb";
-    std::string reboot_string = android::base::StringPrintf("reboot,%s", reboot_arg);
+    if (reboot_arg.empty()) reboot_arg = "adb";
+    std::string reboot_string = android::base::StringPrintf("reboot,%s", reboot_arg.c_str());
     if (!android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_string)) {
         WriteFdFmt(fd, "reboot (%s) failed\n", reboot_string.c_str());
         return false;
@@ -161,23 +152,19 @@
     return true;
 }
 
-void reboot_service(int fd, void* arg) {
-    if (reboot_service_impl(fd, static_cast<const char*>(arg))) {
-        // Don't return early. Give the reboot command time to take effect
-        // to avoid messing up scripts which do "adb reboot && adb wait-for-device"
-        while (true) {
-            pause();
-        }
+void reboot_service(android::base::unique_fd fd, const std::string& arg) {
+    if (!reboot_service_impl(std::move(fd), arg)) {
+        return;
     }
-
-    free(arg);
-    adb_close(fd);
+    // Don't return early. Give the reboot command time to take effect
+    // to avoid messing up scripts which do "adb reboot && adb wait-for-device"
+    while (true) {
+        pause();
+    }
 }
 
-static void reconnect_service(int fd, void* arg) {
+void reconnect_service(android::base::unique_fd fd, atransport* t) {
     WriteFdExactly(fd, "done");
-    adb_close(fd);
-    atransport* t = static_cast<atransport*>(arg);
     kick_transport(t);
 }
 
@@ -197,7 +184,7 @@
 
 // Shell service string can look like:
 //   shell[,arg1,arg2,...]:[command]
-static int ShellService(const std::string& args, const atransport* transport) {
+int ShellService(const std::string& args, const atransport* transport) {
     size_t delimiter_index = args.find(':');
     if (delimiter_index == std::string::npos) {
         LOG(ERROR) << "No ':' found in shell service arguments: " << args;
@@ -236,16 +223,17 @@
 
 #endif  // !ADB_HOST
 
-static int create_service_thread(const char* service_name, void (*func)(int, void*), void* cookie) {
+android::base::unique_fd create_service_thread(const char* service_name,
+                                               std::function<void(android::base::unique_fd)> func) {
     int s[2];
     if (adb_socketpair(s)) {
         printf("cannot create service socket pair\n");
-        return -1;
+        return android::base::unique_fd();
     }
     D("socketpair: (%d,%d)", s[0], s[1]);
 
 #if !ADB_HOST
-    if (func == &file_sync_service) {
+    if (strcmp(service_name, "sync") == 0) {
         // Set file sync service socket to maximum size
         int max_buf = LINUX_MAX_SOCKET_SIZE;
         adb_setsockopt(s[0], SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(max_buf));
@@ -253,21 +241,14 @@
     }
 #endif // !ADB_HOST
 
-    stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo)));
-    if (sti == nullptr) {
-        fatal("cannot allocate stinfo");
-    }
-    sti->service_name = service_name;
-    sti->func = func;
-    sti->cookie = cookie;
-    sti->fd = s[1];
-
-    std::thread(service_bootstrap_func, sti).detach();
+    std::thread(service_bootstrap_func, service_name, func, android::base::unique_fd(s[1])).detach();
 
     D("service thread started, %d:%d",s[0], s[1]);
-    return s[0];
+    return android::base::unique_fd(s[0]);
 }
 
+}  // namespace
+
 int service_to_fd(const char* name, atransport* transport) {
     int ret = -1;
 
@@ -280,54 +261,60 @@
 #if !ADB_HOST
     } else if(!strncmp("dev:", name, 4)) {
         ret = unix_open(name + 4, O_RDWR | O_CLOEXEC);
-    } else if(!strncmp(name, "framebuffer:", 12)) {
-        ret = create_service_thread("fb", framebuffer_service, nullptr);
+    } else if (!strncmp(name, "framebuffer:", 12)) {
+        ret = create_service_thread("fb", framebuffer_service).release();
     } else if (!strncmp(name, "jdwp:", 5)) {
-        ret = create_jdwp_connection_fd(atoi(name+5));
-    } else if(!strncmp(name, "shell", 5)) {
+        ret = create_jdwp_connection_fd(atoi(name + 5));
+    } else if (!strncmp(name, "shell", 5)) {
         ret = ShellService(name + 5, transport);
-    } else if(!strncmp(name, "exec:", 5)) {
+    } else if (!strncmp(name, "exec:", 5)) {
         ret = StartSubprocess(name + 5, nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone);
-    } else if(!strncmp(name, "sync:", 5)) {
-        ret = create_service_thread("sync", file_sync_service, nullptr);
-    } else if(!strncmp(name, "remount:", 8)) {
-        const char* options = name + strlen("remount:");
-        void* cookie = const_cast<void*>(reinterpret_cast<const void*>(options));
-        ret = create_service_thread("remount", remount_service, cookie);
-    } else if(!strncmp(name, "reboot:", 7)) {
-        void* arg = strdup(name + 7);
-        if (arg == NULL) return -1;
-        ret = create_service_thread("reboot", reboot_service, arg);
-        if (ret < 0) free(arg);
-    } else if(!strncmp(name, "root:", 5)) {
-        ret = create_service_thread("root", restart_root_service, nullptr);
-    } else if(!strncmp(name, "unroot:", 7)) {
-        ret = create_service_thread("unroot", restart_unroot_service, nullptr);
-    } else if(!strncmp(name, "backup:", 7)) {
-        ret = StartSubprocess(android::base::StringPrintf("/system/bin/bu backup %s",
-                                                          (name + 7)).c_str(),
-                              nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone);
-    } else if(!strncmp(name, "restore:", 8)) {
+    } else if (!strncmp(name, "sync:", 5)) {
+        ret = create_service_thread("sync", file_sync_service).release();
+    } else if (!strncmp(name, "remount:", 8)) {
+        std::string options(name + strlen("remount:"));
+        ret = create_service_thread("remount",
+                                    std::bind(remount_service, std::placeholders::_1, options))
+                      .release();
+    } else if (!strncmp(name, "reboot:", 7)) {
+        std::string arg(name + strlen("reboot:"));
+        ret = create_service_thread("reboot", std::bind(reboot_service, std::placeholders::_1, arg))
+                      .release();
+    } else if (!strncmp(name, "root:", 5)) {
+        ret = create_service_thread("root", restart_root_service).release();
+    } else if (!strncmp(name, "unroot:", 7)) {
+        ret = create_service_thread("unroot", restart_unroot_service).release();
+    } else if (!strncmp(name, "backup:", 7)) {
+        ret = StartSubprocess(
+                android::base::StringPrintf("/system/bin/bu backup %s", (name + 7)).c_str(),
+                nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone);
+    } else if (!strncmp(name, "restore:", 8)) {
         ret = StartSubprocess("/system/bin/bu restore", nullptr, SubprocessType::kRaw,
                               SubprocessProtocol::kNone);
-    } else if(!strncmp(name, "tcpip:", 6)) {
+    } else if (!strncmp(name, "tcpip:", 6)) {
         int port;
         if (sscanf(name + 6, "%d", &port) != 1) {
             return -1;
         }
-        ret = create_service_thread("tcp", restart_tcp_service, reinterpret_cast<void*>(port));
-    } else if(!strncmp(name, "usb:", 4)) {
-        ret = create_service_thread("usb", restart_usb_service, nullptr);
+        ret = create_service_thread("tcp",
+                                    std::bind(restart_tcp_service, std::placeholders::_1, port))
+                      .release();
+    } else if (!strncmp(name, "usb:", 4)) {
+        ret = create_service_thread("usb", restart_usb_service).release();
     } else if (!strncmp(name, "reverse:", 8)) {
         ret = reverse_service(name + 8, transport);
-    } else if(!strncmp(name, "disable-verity:", 15)) {
-        ret = create_service_thread("verity-on", set_verity_enabled_state_service,
-                                    reinterpret_cast<void*>(0));
-    } else if(!strncmp(name, "enable-verity:", 15)) {
-        ret = create_service_thread("verity-off", set_verity_enabled_state_service,
-                                    reinterpret_cast<void*>(1));
+    } else if (!strncmp(name, "disable-verity:", 15)) {
+        ret = create_service_thread("verity-on", std::bind(set_verity_enabled_state_service,
+                                                           std::placeholders::_1, false))
+                      .release();
+    } else if (!strncmp(name, "enable-verity:", 15)) {
+        ret = create_service_thread("verity-off", std::bind(set_verity_enabled_state_service,
+                                                            std::placeholders::_1, true))
+                      .release();
     } else if (!strcmp(name, "reconnect")) {
-        ret = create_service_thread("reconnect", reconnect_service, transport);
+        ret = create_service_thread("reconnect",
+                                    std::bind(reconnect_service, std::placeholders::_1, transport))
+                      .release();
 #endif
     }
     if (ret >= 0) {
@@ -352,7 +339,7 @@
     while (true) {
         bool is_ambiguous = false;
         std::string error = "unknown error";
-        const char* serial = sinfo->serial.length() ? sinfo->serial.c_str() : NULL;
+        const char* serial = sinfo->serial.length() ? sinfo->serial.c_str() : nullptr;
         atransport* t = acquire_one_transport(sinfo->transport_type, serial, sinfo->transport_id,
                                               &is_ambiguous, &error);
         if (t != nullptr && (sinfo->state == kCsAny || sinfo->state == t->GetConnectionState())) {
@@ -389,8 +376,8 @@
         return;
     }
 
-    int console_port = strtol(pieces[0].c_str(), NULL, 0);
-    int adb_port = strtol(pieces[1].c_str(), NULL, 0);
+    int console_port = strtol(pieces[0].c_str(), nullptr, 0);
+    int adb_port = strtol(pieces[1].c_str(), nullptr, 0);
     if (console_port <= 0 || adb_port <= 0) {
         *response = android::base::StringPrintf("Invalid port numbers: %s", port_spec.c_str());
         return;
@@ -420,19 +407,16 @@
     }
 }
 
-static void connect_service(int fd, void* data) {
-    char* host = reinterpret_cast<char*>(data);
+static void connect_service(android::base::unique_fd fd, std::string host) {
     std::string response;
-    if (!strncmp(host, "emu:", 4)) {
-        connect_emulator(host + 4, &response);
+    if (!strncmp(host.c_str(), "emu:", 4)) {
+        connect_emulator(host.c_str() + 4, &response);
     } else {
-        connect_device(host, &response);
+        connect_device(host.c_str(), &response);
     }
-    free(host);
 
     // Send response for emulator and device
-    SendProtocolString(fd, response);
-    adb_close(fd);
+    SendProtocolString(fd.get(), response);
 }
 #endif
 
@@ -445,7 +429,7 @@
     } else if (android::base::StartsWith(name, "wait-for-")) {
         name += strlen("wait-for-");
 
-        std::unique_ptr<state_info> sinfo(new state_info);
+        std::unique_ptr<state_info> sinfo = std::make_unique<state_info>();
         if (sinfo == nullptr) {
             fprintf(stderr, "couldn't allocate state_info: %s", strerror(errno));
             return nullptr;
@@ -481,19 +465,20 @@
             return nullptr;
         }
 
-        int fd = create_service_thread("wait", wait_for_state, sinfo.get());
+        int fd = create_service_thread(
+                         "wait", std::bind(wait_for_state, std::placeholders::_1, sinfo.get()))
+                         .release();
         if (fd != -1) {
             sinfo.release();
         }
         return create_local_socket(fd);
     } else if (!strncmp(name, "connect:", 8)) {
-        char* host = strdup(name + 8);
-        int fd = create_service_thread("connect", connect_service, host);
-        if (fd == -1) {
-            free(host);
-        }
+        std::string host(name + strlen("connect:"));
+        int fd = create_service_thread("connect",
+                                       std::bind(connect_service, std::placeholders::_1, host))
+                         .release();
         return create_local_socket(fd);
     }
-    return NULL;
+    return nullptr;
 }
 #endif /* ADB_HOST */
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index de3215d..69b5180 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -337,7 +337,7 @@
     s->fd = fd;
     s->enqueue = local_socket_enqueue;
     s->ready = local_socket_ready;
-    s->shutdown = NULL;
+    s->shutdown = nullptr;
     s->close = local_socket_close;
     install_local_socket(s);
 
@@ -383,7 +383,7 @@
 
     s = host_service_to_socket(name, serial, transport_id);
 
-    if (s != NULL) {
+    if (s != nullptr) {
         D("LS(%d) bound to '%s'", s->id, name);
         return s;
     }
@@ -435,7 +435,7 @@
 
 static void remote_socket_close(asocket* s) {
     if (s->peer) {
-        s->peer->peer = 0;
+        s->peer->peer = nullptr;
         D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
         s->peer->close(s->peer);
     }
@@ -488,7 +488,7 @@
    send the go-ahead message when they connect */
 static void local_socket_ready_notify(asocket* s) {
     s->ready = local_socket_ready;
-    s->shutdown = NULL;
+    s->shutdown = nullptr;
     s->close = local_socket_close;
     SendOkay(s->fd);
     s->ready(s);
@@ -499,7 +499,7 @@
    connected (to avoid closing them without a status message) */
 static void local_socket_close_notify(asocket* s) {
     s->ready = local_socket_ready;
-    s->shutdown = NULL;
+    s->shutdown = nullptr;
     s->close = local_socket_close;
     SendFail(s->fd, "closed");
     s->close(s);
@@ -706,7 +706,7 @@
         ** and tear down here.
         */
         s2 = create_host_service_socket(service, serial, transport_id);
-        if (s2 == 0) {
+        if (s2 == nullptr) {
             D("SS(%d): couldn't create host service '%s'", s->id, service);
             SendFail(s->peer->fd, "unknown host service");
             goto fail;
@@ -726,7 +726,7 @@
         s->peer->close = local_socket_close;
         s->peer->peer = s2;
         s2->peer = s->peer;
-        s->peer = 0;
+        s->peer = nullptr;
         D("SS(%d): okay", s->id);
         s->close(s);
 
@@ -764,12 +764,12 @@
     s->peer->ready = local_socket_ready_notify;
     s->peer->shutdown = nullptr;
     s->peer->close = local_socket_close_notify;
-    s->peer->peer = 0;
+    s->peer->peer = nullptr;
     /* give him our transport and upref it */
     s->peer->transport = s->transport;
 
     connect_to_remote(s->peer, s->smart_socket_data.data() + 4);
-    s->peer = 0;
+    s->peer = nullptr;
     s->close(s);
     return 1;
 
@@ -789,9 +789,9 @@
 static void smart_socket_close(asocket* s) {
     D("SS(%d): closed", s->id);
     if (s->peer) {
-        s->peer->peer = 0;
+        s->peer->peer = nullptr;
         s->peer->close(s->peer);
-        s->peer = 0;
+        s->peer = nullptr;
     }
     delete s;
 }
@@ -801,7 +801,7 @@
     asocket* s = new asocket();
     s->enqueue = smart_socket_enqueue;
     s->ready = smart_socket_ready;
-    s->shutdown = NULL;
+    s->shutdown = nullptr;
     s->close = smart_socket_close;
 
     D("SS(%d)", s->id);
diff --git a/adb/sysdeps/memory.h b/adb/sysdeps/memory.h
index 0e4c509..4108aff 100644
--- a/adb/sysdeps/memory.h
+++ b/adb/sysdeps/memory.h
@@ -23,6 +23,23 @@
 // We don't have C++14 on Windows yet.
 // Reimplement std::make_unique ourselves until we do.
 
+namespace internal {
+
+template <typename T>
+struct array_known_bounds;
+
+template <typename T>
+struct array_known_bounds<T[]> {
+    constexpr static bool value = false;
+};
+
+template <typename T, size_t N>
+struct array_known_bounds<T[N]> {
+    constexpr static bool value = true;
+};
+
+}  // namespace internal
+
 namespace std {
 
 template <typename T, typename... Args>
@@ -31,6 +48,18 @@
     return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
 }
 
+template <typename T>
+typename std::enable_if<std::is_array<T>::value && !internal::array_known_bounds<T>::value,
+                        std::unique_ptr<T>>::type
+make_unique(std::size_t size) {
+    return std::unique_ptr<T>(new typename std::remove_extent<T>::type[size]());
+}
+
+template <typename T, typename... Args>
+typename std::enable_if<std::is_array<T>::value && internal::array_known_bounds<T>::value,
+                        std::unique_ptr<T>>::type
+make_unique(Args&&... args) = delete;
+
 }  // namespace std
 
 #endif
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index 52f586c..c94d13f 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -158,7 +158,7 @@
         D( "_fh_from_int: invalid fd %d passed to %s", fd + WIN32_FH_BASE,
            func );
         errno = EBADF;
-        return NULL;
+        return nullptr;
     }
 
     f = &_win32_fhs[fd];
@@ -167,7 +167,7 @@
         D( "_fh_from_int: invalid fd %d passed to %s", fd + WIN32_FH_BASE,
            func );
         errno = EBADF;
-        return NULL;
+        return nullptr;
     }
 
     return f;
@@ -186,12 +186,12 @@
 static FH
 _fh_alloc( FHClass  clazz )
 {
-    FH   f = NULL;
+    FH   f = nullptr;
 
     std::lock_guard<std::mutex> lock(_win32_lock);
 
     for (int i = _win32_fh_next; i < WIN32_MAX_FHS; ++i) {
-        if (_win32_fhs[i].clazz == NULL) {
+        if (_win32_fhs[i].clazz == nullptr) {
             f = &_win32_fhs[i];
             _win32_fh_next = i + 1;
             f->clazz = clazz;
@@ -226,7 +226,7 @@
         f->name[0] = '\0';
         f->eof     = 0;
         f->used    = 0;
-        f->clazz   = NULL;
+        f->clazz   = nullptr;
     }
     return 0;
 }
@@ -269,7 +269,7 @@
 static int _fh_file_read(FH f, void* buf, int len) {
     DWORD read_bytes;
 
-    if (!ReadFile(f->fh_handle, buf, (DWORD)len, &read_bytes, NULL)) {
+    if (!ReadFile(f->fh_handle, buf, (DWORD)len, &read_bytes, nullptr)) {
         D("adb_read: could not read %d bytes from %s", len, f->name);
         errno = EIO;
         return -1;
@@ -282,7 +282,7 @@
 static int _fh_file_write(FH f, const void* buf, int len) {
     DWORD wrote_bytes;
 
-    if (!WriteFile(f->fh_handle, buf, (DWORD)len, &wrote_bytes, NULL)) {
+    if (!WriteFile(f->fh_handle, buf, (DWORD)len, &wrote_bytes, nullptr)) {
         D("adb_file_write: could not write %d bytes from %s", len, f->name);
         errno = EIO;
         return -1;
@@ -337,7 +337,7 @@
             return -1;
     }
 
-    result = SetFilePointer(f->fh_handle, pos, NULL, method);
+    result = SetFilePointer(f->fh_handle, pos, nullptr, method);
     if (result == INVALID_SET_FILE_POINTER) {
         errno = EIO;
         return -1;
@@ -387,7 +387,7 @@
         return -1;
     }
     f->fh_handle =
-        CreateFileW(path_wide.c_str(), desiredAccess, shareMode, NULL, OPEN_EXISTING, 0, NULL);
+        CreateFileW(path_wide.c_str(), desiredAccess, shareMode, nullptr, OPEN_EXISTING, 0, nullptr);
 
     if (f->fh_handle == INVALID_HANDLE_VALUE) {
         const DWORD err = GetLastError();
@@ -430,7 +430,7 @@
         return -1;
     }
     f->fh_handle = CreateFileW(path_wide.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
-                               NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+                               nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
 
     if (f->fh_handle == INVALID_HANDLE_VALUE) {
         const DWORD err = GetLastError();
@@ -461,7 +461,7 @@
 int adb_read(int fd, void* buf, int len) {
     FH f = _fh_from_int(fd, __func__);
 
-    if (f == NULL) {
+    if (f == nullptr) {
         errno = EBADF;
         return -1;
     }
@@ -472,7 +472,7 @@
 int adb_write(int fd, const void* buf, int len) {
     FH f = _fh_from_int(fd, __func__);
 
-    if (f == NULL) {
+    if (f == nullptr) {
         errno = EBADF;
         return -1;
     }
@@ -483,7 +483,7 @@
 ssize_t adb_writev(int fd, const adb_iovec* iov, int iovcnt) {
     FH f = _fh_from_int(fd, __func__);
 
-    if (f == NULL) {
+    if (f == nullptr) {
         errno = EBADF;
         return -1;
     }
@@ -1700,7 +1700,7 @@
 
         // The following emulation code should write the output sequence to
         // either seqstr or to seqbuf and seqbuflen.
-        const char* seqstr = NULL;  // NULL terminated C-string
+        const char* seqstr = nullptr;  // NULL terminated C-string
         // Enough space for max sequence string below, plus modifiers and/or
         // escape prefix.
         char seqbuf[16];
@@ -1998,7 +1998,7 @@
         // * seqstr is set (and strlen can be used to determine the length).
         // * seqbuf and seqbuflen are set
         // Fallback to ch from Windows.
-        if (seqstr != NULL) {
+        if (seqstr != nullptr) {
             out = seqstr;
             outlen = strlen(seqstr);
         } else if (seqbuflen > 0) {
@@ -2068,9 +2068,9 @@
 }
 
 void stdin_raw_restore() {
-    if (_console_handle != NULL) {
+    if (_console_handle != nullptr) {
         const HANDLE in = _console_handle;
-        _console_handle = NULL;  // clear state
+        _console_handle = nullptr;  // clear state
 
         if (!SetConsoleMode(in, _old_console_mode)) {
             // This really should not fail.
@@ -2082,7 +2082,7 @@
 
 // Called by 'adb shell' and 'adb exec-in' (via unix_read()) to read from stdin.
 int unix_read_interruptible(int fd, void* buf, size_t len) {
-    if ((fd == STDIN_FILENO) && (_console_handle != NULL)) {
+    if ((fd == STDIN_FILENO) && (_console_handle != nullptr)) {
         // If it is a request to read from stdin, and stdin_raw_init() has been
         // called, and it successfully configured the console, then read from
         // the console using Win32 console APIs and partially emulate a unix
@@ -2442,7 +2442,7 @@
 
     // Write UTF-16 to the console.
     DWORD written = 0;
-    if (!WriteConsoleW(console, utf16.c_str(), utf16.length(), &written, NULL)) {
+    if (!WriteConsoleW(console, utf16.c_str(), utf16.length(), &written, nullptr)) {
         errno = EIO;
         return -1;
     }
@@ -2486,7 +2486,7 @@
 
     // If there is an associated Win32 console, write to it specially,
     // otherwise defer to the regular C Runtime, passing it UTF-8.
-    if (console != NULL) {
+    if (console != nullptr) {
         return _console_vfprintf(console, stream, format, ap);
     } else {
         // If vfprintf is a macro, undefine it, so we can call the real
@@ -2577,7 +2577,7 @@
 
     // If there is an associated Win32 console, write to it specially,
     // otherwise defer to the regular C Runtime, passing it UTF-8.
-    if (console != NULL) {
+    if (console != nullptr) {
         return _console_fwrite(ptr, size, nmemb, stream, console);
     } else {
         // If fwrite is a macro, undefine it, so we can call the real
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 7db9bf2..638940c 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -173,18 +173,18 @@
             attempt = reconnect_queue_.front();
             reconnect_queue_.pop();
             if (attempt.transport->kicked()) {
-                D("transport %s was kicked. giving up on it.", attempt.transport->serial);
+                D("transport %s was kicked. giving up on it.", attempt.transport->serial.c_str());
                 remove_transport(attempt.transport);
                 continue;
             }
         }
-        D("attempting to reconnect %s", attempt.transport->serial);
+        D("attempting to reconnect %s", attempt.transport->serial.c_str());
 
         if (!attempt.transport->Reconnect()) {
-            D("attempting to reconnect %s failed.", attempt.transport->serial);
+            D("attempting to reconnect %s failed.", attempt.transport->serial.c_str());
             if (attempt.attempts_left == 0) {
                 D("transport %s exceeded the number of retry attempts. giving up on it.",
-                  attempt.transport->serial);
+                  attempt.transport->serial.c_str());
                 remove_transport(attempt.transport);
                 continue;
             }
@@ -197,7 +197,7 @@
             continue;
         }
 
-        D("reconnection to %s succeeded.", attempt.transport->serial);
+        D("reconnection to %s succeeded.", attempt.transport->serial.c_str());
         register_transport(attempt.transport);
     }
 }
@@ -402,14 +402,14 @@
         p->msg.data_check = calculate_apacket_checksum(p);
     }
 
-    VLOG(TRANSPORT) << dump_packet(t->serial, "to remote", p);
+    VLOG(TRANSPORT) << dump_packet(t->serial.c_str(), "to remote", p);
 
-    if (t == NULL) {
+    if (t == nullptr) {
         fatal("Transport is null");
     }
 
     if (t->Write(p) != 0) {
-        D("%s: failed to enqueue packet, closing transport", t->serial);
+        D("%s: failed to enqueue packet, closing transport", t->serial.c_str());
         t->Kick();
     }
 }
@@ -467,7 +467,7 @@
 
     D("device tracker %p removed", tracker);
     if (peer) {
-        peer->peer = NULL;
+        peer->peer = nullptr;
         peer->close(peer);
     }
     device_tracker_remove(tracker);
@@ -619,19 +619,13 @@
     t = m.transport;
 
     if (m.action == 0) {
-        D("transport: %s deleting", t->serial);
+        D("transport: %s deleting", t->serial.c_str());
 
         {
             std::lock_guard<std::recursive_mutex> lock(transport_lock);
             transport_list.remove(t);
         }
 
-        if (t->product) free(t->product);
-        if (t->serial) free(t->serial);
-        if (t->model) free(t->model);
-        if (t->device) free(t->device);
-        if (t->devpath) free(t->devpath);
-
         delete t;
 
         update_transports();
@@ -646,11 +640,11 @@
         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);
+                D("%s: remote read: bad header", t->serial.c_str());
                 return false;
             }
 
-            VLOG(TRANSPORT) << dump_packet(t->serial, "from remote", p.get());
+            VLOG(TRANSPORT) << dump_packet(t->serial.c_str(), "from remote", p.get());
             apacket* packet = p.release();
 
             // TODO: Does this need to run on the main thread?
@@ -658,7 +652,7 @@
             return true;
         });
         t->connection()->SetErrorCallback([t](Connection*, const std::string& error) {
-            D("%s: connection terminated: %s", t->serial, error.c_str());
+            D("%s: connection terminated: %s", t->serial.c_str(), error.c_str());
             fdevent_run_on_main_thread([t]() {
                 handle_offline(t);
                 transport_unref(t);
@@ -699,7 +693,7 @@
     transport_registration_recv = s[1];
 
     transport_registration_fde =
-        fdevent_create(transport_registration_recv, transport_registration_func, 0);
+        fdevent_create(transport_registration_recv, transport_registration_func, nullptr);
     fdevent_set(transport_registration_fde, FDE_READ);
 }
 
@@ -717,7 +711,7 @@
     tmsg m;
     m.transport = transport;
     m.action = 1;
-    D("transport: %s registered", transport->serial);
+    D("transport: %s registered", transport->serial.c_str());
     if (transport_write_action(transport_registration_send, &m)) {
         fatal_errno("cannot write transport registration socket\n");
     }
@@ -727,7 +721,7 @@
     tmsg m;
     m.transport = transport;
     m.action = 0;
-    D("transport: %s removed", transport->serial);
+    D("transport: %s removed", transport->serial.c_str());
     if (transport_write_action(transport_registration_send, &m)) {
         fatal_errno("cannot write transport registration socket\n");
     }
@@ -743,38 +737,38 @@
     if (t->ref_count == 0) {
         t->connection()->Stop();
         if (t->IsTcpDevice() && !t->kicked()) {
-            D("transport: %s unref (attempting reconnection) %d", t->serial, t->kicked());
+            D("transport: %s unref (attempting reconnection) %d", t->serial.c_str(), t->kicked());
             reconnect_handler.TrackTransport(t);
         } else {
-            D("transport: %s unref (kicking and closing)", t->serial);
+            D("transport: %s unref (kicking and closing)", t->serial.c_str());
             remove_transport(t);
         }
     } else {
-        D("transport: %s unref (count=%zu)", t->serial, t->ref_count);
+        D("transport: %s unref (count=%zu)", t->serial.c_str(), t->ref_count);
     }
 }
 
-static int qual_match(const char* to_test, const char* prefix, const char* qual,
+static int qual_match(const std::string& to_test, const char* prefix, const std::string& qual,
                       bool sanitize_qual) {
-    if (!to_test || !*to_test) /* Return true if both the qual and to_test are null strings. */
-        return !qual || !*qual;
+    if (to_test.empty()) /* Return true if both the qual and to_test are empty strings. */
+        return qual.empty();
 
-    if (!qual) return 0;
+    if (qual.empty()) return 0;
 
+    const char* ptr = to_test.c_str();
     if (prefix) {
         while (*prefix) {
-            if (*prefix++ != *to_test++) return 0;
+            if (*prefix++ != *ptr++) return 0;
         }
     }
 
-    while (*qual) {
-        char ch = *qual++;
+    for (char ch : qual) {
         if (sanitize_qual && !isalnum(ch)) ch = '_';
-        if (ch != *to_test++) return 0;
+        if (ch != *ptr++) return 0;
     }
 
-    /* Everything matched so far.  Return true if *to_test is a NUL. */
-    return !*to_test;
+    /* Everything matched so far.  Return true if *ptr is a NUL. */
+    return !*ptr;
 }
 
 atransport* acquire_one_transport(TransportType type, const char* serial, TransportId transport_id,
@@ -921,7 +915,7 @@
 
 void atransport::Kick() {
     if (!kicked_.exchange(true)) {
-        D("kicking transport %p %s", this, this->serial);
+        D("kicking transport %p %s", this, this->serial.c_str());
         this->connection()->Stop();
     }
 }
@@ -1040,7 +1034,7 @@
 }
 
 bool atransport::MatchesTarget(const std::string& target) const {
-    if (serial) {
+    if (!serial.empty()) {
         if (target == serial) {
             return true;
         } else if (type == kTransportLocal) {
@@ -1069,10 +1063,9 @@
         }
     }
 
-    return (devpath && target == devpath) ||
-           qual_match(target.c_str(), "product:", product, false) ||
-           qual_match(target.c_str(), "model:", model, true) ||
-           qual_match(target.c_str(), "device:", device, false);
+    return (target == devpath) || qual_match(target, "product:", product, false) ||
+           qual_match(target, "model:", model, true) ||
+           qual_match(target, "device:", device, false);
 }
 
 void atransport::SetConnectionEstablished(bool success) {
@@ -1093,9 +1086,9 @@
     return str;
 }
 
-static void append_transport_info(std::string* result, const char* key, const char* value,
+static void append_transport_info(std::string* result, const char* key, const std::string& value,
                                   bool alphanumeric) {
-    if (value == nullptr || *value == '\0') {
+    if (value.empty()) {
         return;
     }
 
@@ -1105,8 +1098,8 @@
 }
 
 static void append_transport(const atransport* t, std::string* result, bool long_listing) {
-    const char* serial = t->serial;
-    if (!serial || !serial[0]) {
+    std::string serial = t->serial;
+    if (serial.empty()) {
         serial = "(no serial number)";
     }
 
@@ -1115,7 +1108,8 @@
         *result += '\t';
         *result += t->connection_state_name();
     } else {
-        android::base::StringAppendF(result, "%-22s %s", serial, t->connection_state_name().c_str());
+        android::base::StringAppendF(result, "%-22s %s", serial.c_str(),
+                                     t->connection_state_name().c_str());
 
         append_transport_info(result, "", t->devpath, false);
         append_transport_info(result, "product:", t->product, false);
@@ -1138,7 +1132,7 @@
         if (x->type != y->type) {
             return x->type < y->type;
         }
-        return strcmp(x->serial, y->serial) < 0;
+        return x->serial < y->serial;
     });
 
     std::string result;
@@ -1181,7 +1175,7 @@
 
     std::unique_lock<std::recursive_mutex> lock(transport_lock);
     for (const auto& transport : pending_list) {
-        if (transport->serial && strcmp(serial, transport->serial) == 0) {
+        if (strcmp(serial, transport->serial.c_str()) == 0) {
             VLOG(TRANSPORT) << "socket transport " << transport->serial
                             << " is already in pending_list and fails to register";
             delete t;
@@ -1190,7 +1184,7 @@
     }
 
     for (const auto& transport : transport_list) {
-        if (transport->serial && strcmp(serial, transport->serial) == 0) {
+        if (strcmp(serial, transport->serial.c_str()) == 0) {
             VLOG(TRANSPORT) << "socket transport " << transport->serial
                             << " is already in transport_list and fails to register";
             delete t;
@@ -1199,7 +1193,7 @@
     }
 
     pending_list.push_front(t);
-    t->serial = strdup(serial);
+    t->serial = serial;
 
     lock.unlock();
 
@@ -1220,7 +1214,7 @@
 
     std::lock_guard<std::recursive_mutex> lock(transport_lock);
     for (auto& t : transport_list) {
-        if (t->serial && strcmp(serial, t->serial) == 0) {
+        if (strcmp(serial, t->serial.c_str()) == 0) {
             result = t;
             break;
         }
@@ -1251,11 +1245,11 @@
     D("transport: %p init'ing for usb_handle %p (sn='%s')", t, usb, serial ? serial : "");
     init_usb_transport(t, usb);
     if (serial) {
-        t->serial = strdup(serial);
+        t->serial = serial;
     }
 
     if (devpath) {
-        t->devpath = strdup(devpath);
+        t->devpath = devpath;
     }
 
     {
diff --git a/adb/transport.h b/adb/transport.h
index cb20615..e9c9d37 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -238,11 +238,11 @@
     TransportType type = kTransportAny;
 
     // Used to identify transports for clients.
-    char* serial = nullptr;
-    char* product = nullptr;
-    char* model = nullptr;
-    char* device = nullptr;
-    char* devpath = nullptr;
+    std::string serial;
+    std::string product;
+    std::string model;
+    std::string device;
+    std::string devpath;
 
     bool IsTcpDevice() const { return type == kTransportLocal; }
 
@@ -253,7 +253,7 @@
     char token[TOKEN_SIZE] = {};
     size_t failed_auth_attempts = 0;
 
-    std::string serial_name() const { return serial ? serial : "<unknown>"; }
+    std::string serial_name() const { return !serial.empty() ? serial : "<unknown>"; }
     std::string connection_state_name() const;
 
     void update_version(int version, size_t payload);
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 181d666..fa38238 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -490,7 +490,7 @@
             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) {
+        if (existing_transport != nullptr) {
             D("local transport for port %d already registered (%p)?", adb_port, existing_transport);
             fail = -1;
         } else if (local_transports.size() >= ADB_LOCAL_TRANSPORT_MAX) {
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index d987d4f..8c628d8 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -86,9 +86,9 @@
     ASSERT_EQ(0U, t.features().size());
     ASSERT_EQ(kCsHost, t.GetConnectionState());
 
-    ASSERT_EQ(nullptr, t.product);
-    ASSERT_EQ(nullptr, t.model);
-    ASSERT_EQ(nullptr, t.device);
+    ASSERT_EQ(std::string(), t.product);
+    ASSERT_EQ(std::string(), t.model);
+    ASSERT_EQ(std::string(), t.device);
 }
 
 TEST(transport, parse_banner_product_features) {
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index 94b2e37..602970c 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -122,7 +122,7 @@
 // On Android devices, we rely on the kernel to provide buffered read.
 // So we can recover automatically from EOVERFLOW.
 static int remote_read(apacket* p, usb_handle* usb) {
-    if (usb_read(usb, &p->msg, sizeof(amessage))) {
+    if (usb_read(usb, &p->msg, sizeof(amessage)) != sizeof(amessage)) {
         PLOG(ERROR) << "remote usb: read terminated (message)";
         return -1;
     }
@@ -134,7 +134,8 @@
         }
 
         p->payload.resize(p->msg.data_length);
-        if (usb_read(usb, &p->payload[0], p->payload.size())) {
+        if (usb_read(usb, &p->payload[0], p->payload.size())
+                != static_cast<int>(p->payload.size())) {
             PLOG(ERROR) << "remote usb: terminated (data)";
             return -1;
         }
@@ -154,14 +155,14 @@
 }
 
 bool UsbConnection::Write(apacket* packet) {
-    unsigned size = packet->msg.data_length;
+    int size = packet->msg.data_length;
 
-    if (usb_write(handle_, &packet->msg, sizeof(packet->msg)) != 0) {
+    if (usb_write(handle_, &packet->msg, sizeof(packet->msg)) != sizeof(packet->msg)) {
         PLOG(ERROR) << "remote usb: 1 - write terminated";
         return false;
     }
 
-    if (packet->msg.data_length != 0 && usb_write(handle_, packet->payload.data(), size) != 0) {
+    if (packet->msg.data_length != 0 && usb_write(handle_, packet->payload.data(), size) != size) {
         PLOG(ERROR) << "remote usb: 2 - write terminated";
         return false;
     }
diff --git a/adb/types.h b/adb/types.h
index c6b3f07..a3e5d48 100644
--- a/adb/types.h
+++ b/adb/types.h
@@ -18,6 +18,7 @@
 
 #include <algorithm>
 #include <deque>
+#include <memory>
 #include <type_traits>
 #include <utility>
 #include <vector>
@@ -37,7 +38,7 @@
 
     template <typename Iterator>
     Block(Iterator begin, Iterator end) : Block(end - begin) {
-        std::copy(begin, end, data_);
+        std::copy(begin, end, data_.get());
     }
 
     Block(const Block& copy) = delete;
@@ -73,11 +74,11 @@
     void assign(InputIt begin, InputIt end) {
         clear();
         allocate(end - begin);
-        std::copy(begin, end, data_);
+        std::copy(begin, end, data_.get());
     }
 
     void clear() {
-        free(data_);
+        data_.reset();
         capacity_ = 0;
         size_ = 0;
     }
@@ -86,11 +87,11 @@
     size_t size() const { return size_; }
     bool empty() const { return size() == 0; }
 
-    char* data() { return data_; }
-    const char* data() const { return data_; }
+    char* data() { return data_.get(); }
+    const char* data() const { return data_.get(); }
 
-    char* begin() { return data_; }
-    const char* begin() const { return data_; }
+    char* begin() { return data_.get(); }
+    const char* begin() const { return data_.get(); }
 
     char* end() { return data() + size_; }
     const char* end() const { return data() + size_; }
@@ -108,13 +109,13 @@
         CHECK_EQ(0ULL, capacity_);
         CHECK_EQ(0ULL, size_);
         if (size != 0) {
-            data_ = static_cast<char*>(malloc(size));
+            data_ = std::make_unique<char[]>(size);
             capacity_ = size;
             size_ = size;
         }
     }
 
-    char* data_ = nullptr;
+    std::unique_ptr<char[]> data_;
     size_t capacity_ = 0;
     size_t size_ = 0;
 };
diff --git a/base/Android.bp b/base/Android.bp
index 3d80d97..46a0233 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -135,6 +135,7 @@
         "strings_test.cpp",
         "test_main.cpp",
         "test_utils_test.cpp",
+        "unique_fd_test.cpp",
     ],
     target: {
         android: {
diff --git a/base/include/android-base/parseint.h b/base/include/android-base/parseint.h
index fc68d56..bb54c99 100644
--- a/base/include/android-base/parseint.h
+++ b/base/include/android-base/parseint.h
@@ -47,7 +47,9 @@
   if (max < result) {
     return false;
   }
-  *out = static_cast<T>(result);
+  if (out != nullptr) {
+    *out = static_cast<T>(result);
+  }
   return true;
 }
 
@@ -87,7 +89,9 @@
   if (result < min || max < result) {
     return false;
   }
-  *out = static_cast<T>(result);
+  if (out != nullptr) {
+    *out = static_cast<T>(result);
+  }
   return true;
 }
 
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index 6cfcd3f..c6936f1 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -42,10 +42,35 @@
 //
 // unique_fd is also known as ScopedFd/ScopedFD/scoped_fd; mentioned here to help
 // you find this class if you're searching for one of those names.
+
+#if defined(__BIONIC__)
+#include <android/fdsan.h>
+#endif
+
 namespace android {
 namespace base {
 
 struct DefaultCloser {
+#if defined(__BIONIC__)
+  static void Tag(int fd, void* old_addr, void* new_addr) {
+    if (android_fdsan_exchange_owner_tag) {
+      uint64_t old_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
+                                                        reinterpret_cast<uint64_t>(old_addr));
+      uint64_t new_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
+                                                        reinterpret_cast<uint64_t>(new_addr));
+      android_fdsan_exchange_owner_tag(fd, old_tag, new_tag);
+    }
+  }
+  static void Close(int fd, void* addr) {
+    if (android_fdsan_close_with_tag) {
+      uint64_t tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
+                                                    reinterpret_cast<uint64_t>(addr));
+      android_fdsan_close_with_tag(fd, tag);
+    } else {
+      close(fd);
+    }
+  }
+#else
   static void Close(int fd) {
     // Even if close(2) fails with EINTR, the fd will have been closed.
     // Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone
@@ -53,40 +78,75 @@
     // http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
     ::close(fd);
   }
+#endif
 };
 
 template <typename Closer>
 class unique_fd_impl final {
  public:
-  unique_fd_impl() : value_(-1) {}
+  unique_fd_impl() {}
 
-  explicit unique_fd_impl(int value) : value_(value) {}
+  explicit unique_fd_impl(int fd) { reset(fd); }
   ~unique_fd_impl() { reset(); }
 
-  unique_fd_impl(unique_fd_impl&& other) : value_(other.release()) {}
+  unique_fd_impl(unique_fd_impl&& other) { reset(other.release()); }
   unique_fd_impl& operator=(unique_fd_impl&& s) {
-    reset(s.release());
+    int fd = s.fd_;
+    s.fd_ = -1;
+    reset(fd, &s);
     return *this;
   }
 
-  void reset(int new_value = -1) {
-    if (value_ != -1) {
-      Closer::Close(value_);
-    }
-    value_ = new_value;
-  }
+  void reset(int new_value = -1) { reset(new_value, nullptr); }
 
-  int get() const { return value_; }
+  int get() const { return fd_; }
   operator int() const { return get(); }
 
   int release() __attribute__((warn_unused_result)) {
-    int ret = value_;
-    value_ = -1;
+    tag(fd_, this, nullptr);
+    int ret = fd_;
+    fd_ = -1;
     return ret;
   }
 
  private:
-  int value_;
+  void reset(int new_value, void* previous_tag) {
+    if (fd_ != -1) {
+      close(fd_, this);
+    }
+
+    fd_ = new_value;
+    if (new_value != -1) {
+      tag(new_value, previous_tag, this);
+    }
+  }
+
+  int fd_ = -1;
+
+  // Template magic to use Closer::Tag if available, and do nothing if not.
+  // If Closer::Tag exists, this implementation is preferred, because int is a better match.
+  // If not, this implementation is SFINAEd away, and the no-op below is the only one that exists.
+  template <typename T = Closer>
+  static auto tag(int fd, void* old_tag, void* new_tag)
+      -> decltype(T::Tag(fd, old_tag, new_tag), void()) {
+    T::Tag(fd, old_tag, new_tag);
+  }
+
+  template <typename T = Closer>
+  static void tag(long, void*, void*) {
+    // No-op.
+  }
+
+  // Same as above, to select between Closer::Close(int) and Closer::Close(int, void*).
+  template <typename T = Closer>
+  static auto close(int fd, void* tag_value) -> decltype(T::Close(fd, tag_value), void()) {
+    T::Close(fd, tag_value);
+  }
+
+  template <typename T = Closer>
+  static auto close(int fd, void*) -> decltype(T::Close(fd), void()) {
+    T::Close(fd);
+  }
 
   unique_fd_impl(const unique_fd_impl&);
   void operator=(const unique_fd_impl&);
@@ -97,7 +157,8 @@
 #if !defined(_WIN32)
 
 // Inline functions, so that they can be used header-only.
-inline bool Pipe(unique_fd* read, unique_fd* write) {
+template <typename Closer>
+inline bool Pipe(unique_fd_impl<Closer>* read, unique_fd_impl<Closer>* write) {
   int pipefd[2];
 
 #if defined(__linux__)
@@ -121,7 +182,9 @@
   return true;
 }
 
-inline bool Socketpair(int domain, int type, int protocol, unique_fd* left, unique_fd* right) {
+template <typename Closer>
+inline bool Socketpair(int domain, int type, int protocol, unique_fd_impl<Closer>* left,
+                       unique_fd_impl<Closer>* right) {
   int sockfd[2];
   if (socketpair(domain, type, protocol, sockfd) != 0) {
     return false;
@@ -131,7 +194,8 @@
   return true;
 }
 
-inline bool Socketpair(int type, unique_fd* left, unique_fd* right) {
+template <typename Closer>
+inline bool Socketpair(int type, unique_fd_impl<Closer>* left, unique_fd_impl<Closer>* right) {
   return Socketpair(AF_UNIX, type, 0, left, right);
 }
 
diff --git a/base/parseint_test.cpp b/base/parseint_test.cpp
index fb1c339..8f9ed77 100644
--- a/base/parseint_test.cpp
+++ b/base/parseint_test.cpp
@@ -36,6 +36,10 @@
   ASSERT_EQ(12, i);
   ASSERT_FALSE(android::base::ParseInt("-12", &i, 0, 15));
   ASSERT_FALSE(android::base::ParseInt("16", &i, 0, 15));
+
+  ASSERT_FALSE(android::base::ParseInt<int>("x", nullptr));
+  ASSERT_FALSE(android::base::ParseInt<int>("123x", nullptr));
+  ASSERT_TRUE(android::base::ParseInt<int>("1234", nullptr));
 }
 
 TEST(parseint, unsigned_smoke) {
@@ -55,6 +59,10 @@
   ASSERT_EQ(12u, i);
   ASSERT_FALSE(android::base::ParseUint("-12", &i, 15u));
   ASSERT_FALSE(android::base::ParseUint("16", &i, 15u));
+
+  ASSERT_FALSE(android::base::ParseUint<unsigned short>("x", nullptr));
+  ASSERT_FALSE(android::base::ParseUint<unsigned short>("123x", nullptr));
+  ASSERT_TRUE(android::base::ParseUint<unsigned short>("1234", nullptr));
 }
 
 TEST(parseint, no_implicit_octal) {
diff --git a/base/unique_fd_test.cpp b/base/unique_fd_test.cpp
new file mode 100644
index 0000000..3fdf12a
--- /dev/null
+++ b/base/unique_fd_test.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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/unique_fd.h"
+
+#include <gtest/gtest.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+using android::base::unique_fd;
+
+TEST(unique_fd, unowned_close) {
+#if defined(__BIONIC__)
+  unique_fd fd(open("/dev/null", O_RDONLY));
+  EXPECT_DEATH(close(fd.get()), "incorrect tag");
+#endif
+}
+
+TEST(unique_fd, untag_on_release) {
+  unique_fd fd(open("/dev/null", O_RDONLY));
+  close(fd.release());
+}
+
+TEST(unique_fd, move) {
+  unique_fd fd(open("/dev/null", O_RDONLY));
+  unique_fd fd_moved = std::move(fd);
+  ASSERT_EQ(-1, fd.get());
+  ASSERT_GT(fd_moved.get(), -1);
+}
+
+TEST(unique_fd, unowned_close_after_move) {
+#if defined(__BIONIC__)
+  unique_fd fd(open("/dev/null", O_RDONLY));
+  unique_fd fd_moved = std::move(fd);
+  ASSERT_EQ(-1, fd.get());
+  ASSERT_GT(fd_moved.get(), -1);
+  EXPECT_DEATH(close(fd_moved.get()), "incorrect tag");
+#endif
+}
diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp
index f31337d..f0fe1d0 100644
--- a/debuggerd/crasher/crasher.cpp
+++ b/debuggerd/crasher/crasher.cpp
@@ -183,6 +183,8 @@
     fprintf(stderr, "  exit                  call exit(1)\n");
     fprintf(stderr, "\n");
     fprintf(stderr, "  fortify               fail a _FORTIFY_SOURCE check\n");
+    fprintf(stderr, "  fdsan_file            close a file descriptor that's owned by a FILE*\n");
+    fprintf(stderr, "  fdsan_dir             close a file descriptor that's owned by a DIR*\n");
     fprintf(stderr, "  seccomp               fail a seccomp check\n");
 #if defined(__arm__)
     fprintf(stderr, "  kuser_helper_version  call kuser_helper_version\n");
@@ -236,39 +238,45 @@
 
     // Actions.
     if (!strcasecmp(arg, "SIGSEGV-non-null")) {
-        sigsegv_non_null();
+      sigsegv_non_null();
     } else if (!strcasecmp(arg, "smash-stack")) {
-        volatile int len = 128;
-        return smash_stack(&len);
+      volatile int len = 128;
+      return smash_stack(&len);
     } else if (!strcasecmp(arg, "stack-overflow")) {
-        overflow_stack(nullptr);
+      overflow_stack(nullptr);
     } else if (!strcasecmp(arg, "nostack")) {
-        crashnostack();
+      crashnostack();
     } else if (!strcasecmp(arg, "exit")) {
-        exit(1);
+      exit(1);
     } else if (!strcasecmp(arg, "call-null")) {
       return crash_null();
     } else if (!strcasecmp(arg, "crash") || !strcmp(arg, "SIGSEGV")) {
-        return crash(42);
+      return crash(42);
     } else if (!strcasecmp(arg, "abort")) {
-        maybe_abort();
+      maybe_abort();
     } else if (!strcasecmp(arg, "assert")) {
-        __assert("some_file.c", 123, "false");
+      __assert("some_file.c", 123, "false");
     } else if (!strcasecmp(arg, "assert2")) {
-        __assert2("some_file.c", 123, "some_function", "false");
+      __assert2("some_file.c", 123, "some_function", "false");
     } else if (!strcasecmp(arg, "fortify")) {
-        char buf[10];
-        __read_chk(-1, buf, 32, 10);
-        while (true) pause();
+      char buf[10];
+      __read_chk(-1, buf, 32, 10);
+      while (true) pause();
+    } else if (!strcasecmp(arg, "fdsan_file")) {
+      FILE* f = fopen("/dev/null", "r");
+      close(fileno(f));
+    } else if (!strcasecmp(arg, "fdsan_dir")) {
+      DIR* d = opendir("/dev/");
+      close(dirfd(d));
     } else if (!strcasecmp(arg, "LOG(FATAL)")) {
-        LOG(FATAL) << "hello " << 123;
+      LOG(FATAL) << "hello " << 123;
     } else if (!strcasecmp(arg, "LOG_ALWAYS_FATAL")) {
-        LOG_ALWAYS_FATAL("hello %s", "world");
+      LOG_ALWAYS_FATAL("hello %s", "world");
     } else if (!strcasecmp(arg, "LOG_ALWAYS_FATAL_IF")) {
-        LOG_ALWAYS_FATAL_IF(true, "hello %s", "world");
+      LOG_ALWAYS_FATAL_IF(true, "hello %s", "world");
     } else if (!strcasecmp(arg, "SIGFPE")) {
-        raise(SIGFPE);
-        return EXIT_SUCCESS;
+      raise(SIGFPE);
+      return EXIT_SUCCESS;
     } else if (!strcasecmp(arg, "SIGILL")) {
 #if defined(__aarch64__)
       __asm__ volatile(".word 0\n");
@@ -280,28 +288,28 @@
 #error
 #endif
     } else if (!strcasecmp(arg, "SIGTRAP")) {
-        raise(SIGTRAP);
-        return EXIT_SUCCESS;
+      raise(SIGTRAP);
+      return EXIT_SUCCESS;
     } else if (!strcasecmp(arg, "fprintf-NULL")) {
-        fprintf_null();
+      fprintf_null();
     } else if (!strcasecmp(arg, "readdir-NULL")) {
-        readdir_null();
+      readdir_null();
     } else if (!strcasecmp(arg, "strlen-NULL")) {
-        return strlen_null();
+      return strlen_null();
     } else if (!strcasecmp(arg, "pthread_join-NULL")) {
-        return pthread_join(0, nullptr);
+      return pthread_join(0, nullptr);
     } else if (!strcasecmp(arg, "heap-usage")) {
-        abuse_heap();
+      abuse_heap();
     } else if (!strcasecmp(arg, "leak")) {
-        leak();
+      leak();
     } else if (!strcasecmp(arg, "SIGSEGV-unmapped")) {
-        char* map = reinterpret_cast<char*>(mmap(nullptr, sizeof(int), PROT_READ | PROT_WRITE,
-                                                 MAP_SHARED | MAP_ANONYMOUS, -1, 0));
-        munmap(map, sizeof(int));
-        map[0] = '8';
+      char* map = reinterpret_cast<char*>(
+          mmap(nullptr, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0));
+      munmap(map, sizeof(int));
+      map[0] = '8';
     } else if (!strcasecmp(arg, "seccomp")) {
-        set_system_seccomp_filter();
-        syscall(99999);
+      set_system_seccomp_filter();
+      syscall(99999);
 #if defined(__arm__)
     } else if (!strcasecmp(arg, "kuser_helper_version")) {
         return __kuser_helper_version;
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index c07a34a..615fb46 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -59,7 +59,16 @@
 #include "protocol.h"
 
 using android::base::Pipe;
-using android::base::unique_fd;
+
+// We muck with our fds in a 'thread' that doesn't share the same fd table.
+// Close fds in that thread with a raw close syscall instead of going through libc.
+struct FdsanBypassCloser {
+  static void Close(int fd) {
+    syscall(__NR_close, fd);
+  }
+};
+
+using unique_fd = android::base::unique_fd_impl<FdsanBypassCloser>;
 
 // see man(2) prctl, specifically the section about PR_GET_NAME
 #define MAX_TASK_NAME_LEN (16)
@@ -299,7 +308,8 @@
   debugger_thread_info* thread_info = static_cast<debugger_thread_info*>(arg);
 
   for (int i = 0; i < 1024; ++i) {
-    close(i);
+    // Don't use close to avoid bionic's file descriptor ownership checks.
+    syscall(__NR_close, i);
   }
 
   int devnull = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 433bb46..0b8a936 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -474,7 +474,7 @@
 
 static void dump_log_file(log_t* log, pid_t pid, const char* filename, unsigned int tail) {
   bool first = true;
-  struct logger_list* logger_list;
+  logger_list* logger_list;
 
   if (!log->should_retrieve_logcat) {
     return;
@@ -488,11 +488,9 @@
     return;
   }
 
-  struct log_msg log_entry;
-
   while (true) {
+    log_msg log_entry;
     ssize_t actual = android_logger_list_read(logger_list, &log_entry);
-    struct logger_entry* entry;
 
     if (actual < 0) {
       if (actual == -EINTR) {
@@ -515,8 +513,6 @@
     // high-frequency debug diagnostics should just be written to
     // the tombstone file.
 
-    entry = &log_entry.entry_v1;
-
     if (first) {
       _LOG(log, logtype::LOGS, "--------- %slog %s\n",
         tail ? "tail end of " : "", filename);
@@ -527,19 +523,8 @@
     //
     // We want to display it in the same format as "logcat -v threadtime"
     // (although in this case the pid is redundant).
-    static const char* kPrioChars = "!.VDIWEFS";
-    unsigned hdr_size = log_entry.entry.hdr_size;
-    if (!hdr_size) {
-      hdr_size = sizeof(log_entry.entry_v1);
-    }
-    if ((hdr_size < sizeof(log_entry.entry_v1)) ||
-        (hdr_size > sizeof(log_entry.entry))) {
-      continue;
-    }
-    char* msg = reinterpret_cast<char*>(log_entry.buf) + hdr_size;
-
     char timeBuf[32];
-    time_t sec = static_cast<time_t>(entry->sec);
+    time_t sec = static_cast<time_t>(log_entry.entry.sec);
     struct tm tmBuf;
     struct tm* ptm;
     ptm = localtime_r(&sec, &tmBuf);
@@ -547,17 +532,23 @@
 
     if (log_entry.id() == LOG_ID_EVENTS) {
       if (!g_eventTagMap) {
-        g_eventTagMap = android_openEventTagMap(NULL);
+        g_eventTagMap = android_openEventTagMap(nullptr);
       }
       AndroidLogEntry e;
       char buf[512];
-      android_log_processBinaryLogBuffer(entry, &e, g_eventTagMap, buf, sizeof(buf));
-      _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8.*s: %s\n",
-         timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
-         'I', (int)e.tagLen, e.tag, e.message);
+      if (android_log_processBinaryLogBuffer(&log_entry.entry_v1, &e, g_eventTagMap, buf,
+                                             sizeof(buf)) == 0) {
+        _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8.*s: %s\n", timeBuf,
+             log_entry.entry.nsec / 1000000, log_entry.entry.pid, log_entry.entry.tid, 'I',
+             (int)e.tagLen, e.tag, e.message);
+      }
       continue;
     }
 
+    char* msg = log_entry.msg();
+    if (msg == nullptr) {
+      continue;
+    }
     unsigned char prio = msg[0];
     char* tag = msg + 1;
     msg = tag + strlen(tag) + 1;
@@ -568,20 +559,21 @@
       *nl-- = '\0';
     }
 
+    static const char* kPrioChars = "!.VDIWEFS";
     char prioChar = (prio < strlen(kPrioChars) ? kPrioChars[prio] : '?');
 
     // Look for line breaks ('\n') and display each text line
     // on a separate line, prefixed with the header, like logcat does.
     do {
       nl = strchr(msg, '\n');
-      if (nl) {
+      if (nl != nullptr) {
         *nl = '\0';
         ++nl;
       }
 
-      _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8s: %s\n",
-         timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
-         prioChar, tag, msg);
+      _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8s: %s\n", timeBuf,
+           log_entry.entry.nsec / 1000000, log_entry.entry.pid, log_entry.entry.tid, prioChar, tag,
+           msg);
     } while ((msg = nl));
   }
 
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
new file mode 100644
index 0000000..2b4a954
--- /dev/null
+++ b/fastboot/Android.bp
@@ -0,0 +1,56 @@
+cc_library_host_static {
+    name: "libfastboot2",
+
+    //host_supported: true,
+
+    compile_multilib: "first",
+    srcs: [
+      "bootimg_utils.cpp",
+      "fs.cpp",
+      "socket.cpp",
+      "tcp.cpp",
+      "udp.cpp",
+      "util.cpp",
+      "fastboot_driver.cpp",
+    ],
+
+    static_libs: [
+      "libziparchive",
+      "libsparse",
+      "libutils",
+      "liblog",
+      "libz",
+      "libdiagnose_usb",
+      "libbase",
+      "libcutils",
+      "libgtest",
+      "libgtest_main",
+      "libbase",
+      "libadb_host"
+    ],
+
+    header_libs: [
+      "bootimg_headers"
+    ],
+
+    export_header_lib_headers: [
+      "bootimg_headers"
+    ],
+
+
+    target: {
+      linux: {
+        srcs: ["usb_linux.cpp"],
+      },
+    },
+
+    cflags: [
+      "-Wall",
+      "-Wextra",
+      "-Werror",
+      "-Wunreachable-code",
+    ],
+
+    export_include_dirs: ["."],
+
+}
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 983e195..60c338c 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -50,12 +50,12 @@
     bootimg_utils.cpp \
     engine.cpp \
     fastboot.cpp \
-    fs.cpp\
-    protocol.cpp \
+    fs.cpp \
     socket.cpp \
     tcp.cpp \
     udp.cpp \
     util.cpp \
+    fastboot_driver.cpp \
 
 LOCAL_SRC_FILES_darwin := usb_osx.cpp
 LOCAL_SRC_FILES_linux := usb_linux.cpp
diff --git a/fastboot/OWNERS b/fastboot/OWNERS
index 2d12d50..2088ae3 100644
--- a/fastboot/OWNERS
+++ b/fastboot/OWNERS
@@ -1,3 +1,4 @@
 dpursell@google.com
 enh@google.com
 jmgao@google.com
+tomcherry@google.com
diff --git a/fastboot/bootimg_utils.cpp b/fastboot/bootimg_utils.cpp
index c9814e4..1152007 100644
--- a/fastboot/bootimg_utils.cpp
+++ b/fastboot/bootimg_utils.cpp
@@ -28,7 +28,7 @@
 
 #include "bootimg_utils.h"
 
-#include "fastboot.h"
+#include "util.h"
 
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index 1087573..63ee2af 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -25,8 +25,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-
-#include "fastboot.h"
+#include "engine.h"
 
 #include <errno.h>
 #include <stdarg.h>
@@ -78,17 +77,20 @@
 };
 
 static std::vector<std::unique_ptr<Action>> action_list;
+static fastboot::FastBootDriver* fb = nullptr;
 
-bool fb_getvar(Transport* transport, const std::string& key, std::string* value) {
-    std::string cmd = FB_CMD_GETVAR ":" + key;
+void fb_init(fastboot::FastBootDriver& fbi) {
+    fb = &fbi;
+    auto cb = [](std::string& info) { fprintf(stderr, "(bootloader) %s\n", info.c_str()); };
+    fb->SetInfoCallback(cb);
+}
 
-    char buf[FB_RESPONSE_SZ + 1];
-    memset(buf, 0, sizeof(buf));
-    if (fb_command_response(transport, cmd, buf)) {
-        return false;
-    }
-    *value = buf;
-    return true;
+const std::string fb_get_error() {
+    return fb->Error();
+}
+
+bool fb_getvar(const std::string& key, std::string* value) {
+    return !fb->GetVar(key, value);
 }
 
 static int cb_default(Action& a, int status, const char* resp) {
@@ -310,7 +312,7 @@
     queue_action(OP_WAIT_FOR_DISCONNECT, "");
 }
 
-int64_t fb_execute_queue(Transport* transport) {
+int64_t fb_execute_queue() {
     int64_t status = 0;
     for (auto& a : action_list) {
         a->start = now();
@@ -319,33 +321,34 @@
             verbose("\n");
         }
         if (a->op == OP_DOWNLOAD) {
-            status = fb_download_data(transport, a->data, a->size);
+            char* cbuf = static_cast<char*>(a->data);
+            status = fb->Download(cbuf, a->size);
             status = a->func(*a, status, status ? fb_get_error().c_str() : "");
             if (status) break;
         } else if (a->op == OP_DOWNLOAD_FD) {
-            status = fb_download_data_fd(transport, a->fd, a->size);
+            status = fb->Download(a->fd, a->size);
             status = a->func(*a, status, status ? fb_get_error().c_str() : "");
             if (status) break;
         } else if (a->op == OP_COMMAND) {
-            status = fb_command(transport, a->cmd);
+            status = fb->RawCommand(a->cmd);
             status = a->func(*a, status, status ? fb_get_error().c_str() : "");
             if (status) break;
         } else if (a->op == OP_QUERY) {
-            char resp[FB_RESPONSE_SZ + 1] = {};
-            status = fb_command_response(transport, a->cmd, resp);
-            status = a->func(*a, status, status ? fb_get_error().c_str() : resp);
+            std::string resp;
+            status = fb->RawCommand(a->cmd, &resp);
+            status = a->func(*a, status, status ? fb_get_error().c_str() : resp.c_str());
             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 = fb->Download(reinterpret_cast<sparse_file*>(a->data));
             status = a->func(*a, status, status ? fb_get_error().c_str() : "");
             if (status) break;
         } else if (a->op == OP_WAIT_FOR_DISCONNECT) {
-            transport->WaitForDisconnect();
+            fb->WaitForDisconnect();
         } else if (a->op == OP_UPLOAD) {
-            status = fb_upload_data(transport, reinterpret_cast<char*>(a->data));
+            status = fb->Upload(reinterpret_cast<const char*>(a->data));
             status = a->func(*a, status, status ? fb_get_error().c_str() : "");
         } else {
             die("unknown action: %d", a->op);
diff --git a/fastboot/fastboot.h b/fastboot/engine.h
similarity index 74%
rename from fastboot/fastboot.h
rename to fastboot/engine.h
index a93c0ac..74aaa6a 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/engine.h
@@ -34,23 +34,24 @@
 #include <string>
 
 #include <bootimg.h>
+#include "fastboot_driver.h"
+#include "util.h"
 
 #include "constants.h"
 
 class Transport;
 struct sparse_file;
 
-/* protocol.c - fastboot protocol */
-int fb_command(Transport* transport, const std::string& cmd);
-int fb_command_response(Transport* transport, const std::string& cmd, char* response);
-int64_t fb_download_data(Transport* transport, const void* data, uint32_t size);
-int64_t fb_download_data_fd(Transport* transport, int fd, uint32_t size);
-int fb_download_data_sparse(Transport* transport, struct sparse_file* s);
-int64_t fb_upload_data(Transport* transport, const char* outfile);
 const std::string fb_get_error();
 
+//#define FB_COMMAND_SZ (fastboot::FB_COMMAND_SZ)
+//#define FB_RESPONSE_SZ (fastboot::FB_RESPONSE_SZ)
+
 /* engine.c - high level command queue engine */
-bool fb_getvar(Transport* transport, const std::string& key, std::string* value);
+
+void fb_init(fastboot::FastBootDriver& fbi);
+
+bool fb_getvar(const std::string& key, std::string* value);
 void fb_queue_flash(const std::string& partition, void* data, uint32_t sz);
 void fb_queue_flash_fd(const std::string& partition, int fd, uint32_t sz);
 void fb_queue_flash_sparse(const std::string& partition, struct sparse_file* s, uint32_t sz,
@@ -68,24 +69,13 @@
 void fb_queue_upload(const std::string& outfile);
 void fb_queue_notice(const std::string& notice);
 void fb_queue_wait_for_disconnect(void);
-int64_t fb_execute_queue(Transport* transport);
+int64_t fb_execute_queue();
 void fb_set_active(const std::string& slot);
 
-/* 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.
-void die(const char* fmt, ...) __attribute__((__noreturn__))
-__attribute__((__format__(__printf__, 1, 2)));
-void verbose(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2)));
-
 /* Current product */
 extern char cur_product[FB_RESPONSE_SZ + 1];
 
-class FastBoot {
+class FastBootTool {
   public:
     int Main(int argc, char* argv[]);
 
diff --git a/fastboot/fastboot.bash b/fastboot/fastboot.bash
index dca3b4e..cb1d354 100644
--- a/fastboot/fastboot.bash
+++ b/fastboot/fastboot.bash
@@ -16,11 +16,11 @@
 #
 
 _fastboot() {
-    if ! type -t "$1" >/dev/null; then
+    if ! check_type "$1" >/dev/null; then
         return
     fi
 
-    if type -t _init_completion >/dev/null; then
+    if check_type _init_completion >/dev/null; then
         _init_completion || return
     fi
 
@@ -135,7 +135,7 @@
     xspec=$2
 
     # Since we're probably doing file completion here, don't add a space after.
-    if [[ $(type -t compopt) = "builtin" ]]; then
+    if [[ $(check_type compopt) == "builtin" ]]; then
         compopt -o plusdirs
         if [[ "${xspec}" == "" ]]; then
             COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") )
@@ -175,7 +175,7 @@
     fi
 }
 
-if [[ $(type -t compopt) = "builtin" ]]; then
+if [[ $(check_type compopt) == "builtin" ]]; then
     complete -F _fastboot fastboot
 else
     complete -o nospace -F _fastboot fastboot
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 5aa87d9..263ea17 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -60,7 +60,7 @@
 
 #include "bootimg_utils.h"
 #include "diagnose_usb.h"
-#include "fastboot.h"
+#include "engine.h"
 #include "fs.h"
 #include "tcp.h"
 #include "transport.h"
@@ -592,7 +592,7 @@
 }
 
 #define MAX_OPTIONS 32
-static void check_requirement(Transport* transport, char* line) {
+static void check_requirement(char* line) {
     char *val[MAX_OPTIONS];
     unsigned count;
     char *x;
@@ -635,7 +635,7 @@
     if (!strcmp(name, "partition-exists")) {
         const char* partition_name = val[0];
         std::string has_slot;
-        if (!fb_getvar(transport, std::string("has-slot:") + partition_name, &has_slot) ||
+        if (!fb_getvar(std::string("has-slot:") + partition_name, &has_slot) ||
             (has_slot != "yes" && has_slot != "no")) {
             die("device doesn't have required partition %s!", partition_name);
         }
@@ -674,18 +674,18 @@
     fb_queue_require(product, var, invert, count, out);
 }
 
-static void check_requirements(Transport* transport, char* data, int64_t sz) {
+static void check_requirements(char* data, int64_t sz) {
     char* s = data;
     while (sz-- > 0) {
         if (*s == '\n') {
             *s++ = 0;
-            check_requirement(transport, data);
+            check_requirement(data);
             data = s;
         } else {
             s++;
         }
     }
-    if (fb_execute_queue(transport)) die("requirements not met!");
+    if (fb_execute_queue()) die("requirements not met!");
 }
 
 static void queue_info_dump() {
@@ -716,9 +716,9 @@
     return out_s;
 }
 
-static int64_t get_target_sparse_limit(Transport* transport) {
+static int64_t get_target_sparse_limit() {
     std::string max_download_size;
-    if (!fb_getvar(transport, "max-download-size", &max_download_size) ||
+    if (!fb_getvar("max-download-size", &max_download_size) ||
         max_download_size.empty()) {
         verbose("target didn't report max-download-size");
         return 0;
@@ -736,13 +736,13 @@
     return limit;
 }
 
-static int64_t get_sparse_limit(Transport* transport, int64_t size) {
+static int64_t get_sparse_limit(int64_t size) {
     int64_t limit = sparse_limit;
     if (limit == 0) {
         // Unlimited, so see what the target device's limit is.
         // TODO: shouldn't we apply this limit even if you've used -S?
         if (target_sparse_limit == -1) {
-            target_sparse_limit = get_target_sparse_limit(transport);
+            target_sparse_limit = get_target_sparse_limit();
         }
         if (target_sparse_limit > 0) {
             limit = target_sparse_limit;
@@ -758,14 +758,14 @@
     return 0;
 }
 
-static bool load_buf_fd(Transport* transport, int fd, struct fastboot_buffer* buf) {
+static bool load_buf_fd(int fd, struct fastboot_buffer* buf) {
     int64_t sz = get_file_size(fd);
     if (sz == -1) {
         return false;
     }
 
     lseek64(fd, 0, SEEK_SET);
-    int64_t limit = get_sparse_limit(transport, sz);
+    int64_t limit = get_sparse_limit(sz);
     if (limit) {
         sparse_file** s = load_sparse_files(fd, limit);
         if (s == nullptr) {
@@ -783,7 +783,7 @@
     return true;
 }
 
-static bool load_buf(Transport* transport, const char* fname, struct fastboot_buffer* buf) {
+static bool load_buf(const char* fname, struct fastboot_buffer* buf) {
     unique_fd fd(TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_BINARY)));
 
     if (fd == -1) {
@@ -799,7 +799,7 @@
         return false;
     }
 
-    return load_buf_fd(transport, fd.release(), buf);
+    return load_buf_fd(fd.release(), buf);
 }
 
 static void rewrite_vbmeta_buffer(struct fastboot_buffer* buf) {
@@ -871,23 +871,23 @@
     }
 }
 
-static std::string get_current_slot(Transport* transport) {
+static std::string get_current_slot() {
     std::string current_slot;
-    if (!fb_getvar(transport, "current-slot", &current_slot)) return "";
+    if (!fb_getvar("current-slot", &current_slot)) return "";
     return current_slot;
 }
 
-static int get_slot_count(Transport* transport) {
+static int get_slot_count() {
     std::string var;
     int count = 0;
-    if (!fb_getvar(transport, "slot-count", &var) || !android::base::ParseInt(var, &count)) {
+    if (!fb_getvar("slot-count", &var) || !android::base::ParseInt(var, &count)) {
         return 0;
     }
     return count;
 }
 
-static bool supports_AB(Transport* transport) {
-  return get_slot_count(transport) >= 2;
+static bool supports_AB() {
+  return get_slot_count() >= 2;
 }
 
 // Given a current slot, this returns what the 'other' slot is.
@@ -898,25 +898,25 @@
     return std::string(1, next);
 }
 
-static std::string get_other_slot(Transport* transport, const std::string& current_slot) {
-    return get_other_slot(current_slot, get_slot_count(transport));
+static std::string get_other_slot(const std::string& current_slot) {
+    return get_other_slot(current_slot, get_slot_count());
 }
 
-static std::string get_other_slot(Transport* transport, int count) {
-    return get_other_slot(get_current_slot(transport), count);
+static std::string get_other_slot(int count) {
+    return get_other_slot(get_current_slot(), count);
 }
 
-static std::string get_other_slot(Transport* transport) {
-    return get_other_slot(get_current_slot(transport), get_slot_count(transport));
+static std::string get_other_slot() {
+    return get_other_slot(get_current_slot(), get_slot_count());
 }
 
-static std::string verify_slot(Transport* transport, const std::string& slot_name, bool allow_all) {
+static std::string verify_slot(const std::string& slot_name, bool allow_all) {
     std::string slot = slot_name;
     if (slot == "all") {
         if (allow_all) {
             return "all";
         } else {
-            int count = get_slot_count(transport);
+            int count = get_slot_count();
             if (count > 0) {
                 return "a";
             } else {
@@ -925,11 +925,11 @@
         }
     }
 
-    int count = get_slot_count(transport);
+    int count = get_slot_count();
     if (count == 0) die("Device does not support slots");
 
     if (slot == "other") {
-        std::string other = get_other_slot(transport, count);
+        std::string other = get_other_slot( count);
         if (other == "") {
            die("No known slots");
         }
@@ -946,22 +946,22 @@
     exit(1);
 }
 
-static std::string verify_slot(Transport* transport, const std::string& slot) {
-   return verify_slot(transport, slot, true);
+static std::string verify_slot(const std::string& slot) {
+   return verify_slot(slot, true);
 }
 
-static void do_for_partition(Transport* transport, const std::string& part, const std::string& slot,
+static void do_for_partition(const std::string& part, const std::string& slot,
                              const std::function<void(const std::string&)>& func, bool force_slot) {
     std::string has_slot;
     std::string current_slot;
 
-    if (!fb_getvar(transport, "has-slot:" + part, &has_slot)) {
+    if (!fb_getvar("has-slot:" + part, &has_slot)) {
         /* If has-slot is not supported, the answer is no. */
         has_slot = "no";
     }
     if (has_slot == "yes") {
         if (slot == "") {
-            current_slot = get_current_slot(transport);
+            current_slot = get_current_slot();
             if (current_slot == "") {
                 die("Failed to identify current slot");
             }
@@ -983,30 +983,30 @@
  * partition names. If force_slot is true, it will fail if a slot is specified, and the given
  * partition does not support slots.
  */
-static void do_for_partitions(Transport* transport, const std::string& part, const std::string& slot,
+static void do_for_partitions(const std::string& part, const std::string& slot,
                               const std::function<void(const std::string&)>& func, bool force_slot) {
     std::string has_slot;
 
     if (slot == "all") {
-        if (!fb_getvar(transport, "has-slot:" + part, &has_slot)) {
+        if (!fb_getvar("has-slot:" + part, &has_slot)) {
             die("Could not check if partition %s has slot %s", part.c_str(), slot.c_str());
         }
         if (has_slot == "yes") {
-            for (int i=0; i < get_slot_count(transport); i++) {
-                do_for_partition(transport, part, std::string(1, (char)(i + 'a')), func, force_slot);
+            for (int i=0; i < get_slot_count(); i++) {
+                do_for_partition(part, std::string(1, (char)(i + 'a')), func, force_slot);
             }
         } else {
-            do_for_partition(transport, part, "", func, force_slot);
+            do_for_partition(part, "", func, force_slot);
         }
     } else {
-        do_for_partition(transport, part, slot, func, force_slot);
+        do_for_partition(part, slot, func, force_slot);
     }
 }
 
-static void do_flash(Transport* transport, const char* pname, const char* fname) {
+static void do_flash(const char* pname, const char* fname) {
     struct fastboot_buffer buf;
 
-    if (!load_buf(transport, fname, &buf)) {
+    if (!load_buf(fname, &buf)) {
         die("cannot load '%s': %s", fname, strerror(errno));
     }
     flash_buf(pname, &buf);
@@ -1022,20 +1022,20 @@
 
 // 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) {
-    if (!supports_AB(transport)) return;
+static void set_active(const std::string& slot_override) {
+    if (!supports_AB()) return;
 
     if (slot_override != "") {
         fb_set_active(slot_override);
     } else {
-        std::string current_slot = get_current_slot(transport);
+        std::string current_slot = get_current_slot();
         if (current_slot != "") {
             fb_set_active(current_slot);
         }
     }
 }
 
-static void do_update(Transport* transport, const char* filename, const std::string& slot_override, bool skip_secondary) {
+static void do_update(const char* filename, const std::string& slot_override, bool skip_secondary) {
     queue_info_dump();
 
     fb_queue_query_save("product", cur_product, sizeof(cur_product));
@@ -1052,17 +1052,17 @@
         die("update package '%s' has no android-info.txt", filename);
     }
 
-    check_requirements(transport, reinterpret_cast<char*>(data), sz);
+    check_requirements(reinterpret_cast<char*>(data), sz);
 
     std::string secondary;
     if (!skip_secondary) {
         if (slot_override != "") {
-            secondary = get_other_slot(transport, slot_override);
+            secondary = get_other_slot(slot_override);
         } else {
-            secondary = get_other_slot(transport);
+            secondary = get_other_slot();
         }
         if (secondary == "") {
-            if (supports_AB(transport)) {
+            if (supports_AB()) {
                 fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n");
             }
             skip_secondary = true;
@@ -1087,7 +1087,7 @@
         }
 
         fastboot_buffer buf;
-        if (!load_buf_fd(transport, fd, &buf)) {
+        if (!load_buf_fd(fd, &buf)) {
             die("cannot load %s from flash: %s", images[i].img_name, strerror(errno));
         }
 
@@ -1099,13 +1099,13 @@
              * program exits.
              */
         };
-        do_for_partitions(transport, images[i].part_name, slot, update, false);
+        do_for_partitions(images[i].part_name, slot, update, false);
     }
 
     if (slot_override == "all") {
-        set_active(transport, "a");
+        set_active("a");
     } else {
-        set_active(transport, slot_override);
+        set_active(slot_override);
     }
 
     CloseArchive(zip);
@@ -1125,7 +1125,7 @@
     fb_queue_command("signature", "installing signature");
 }
 
-static void do_flashall(Transport* transport, const std::string& slot_override, bool skip_secondary) {
+static void do_flashall(const std::string& slot_override, bool skip_secondary) {
     std::string fname;
     queue_info_dump();
 
@@ -1138,17 +1138,17 @@
     void* data = load_file(fname.c_str(), &sz);
     if (data == nullptr) die("could not load android-info.txt: %s", strerror(errno));
 
-    check_requirements(transport, reinterpret_cast<char*>(data), sz);
+    check_requirements(reinterpret_cast<char*>(data), sz);
 
     std::string secondary;
     if (!skip_secondary) {
         if (slot_override != "") {
-            secondary = get_other_slot(transport, slot_override);
+            secondary = get_other_slot(slot_override);
         } else {
-            secondary = get_other_slot(transport);
+            secondary = get_other_slot();
         }
         if (secondary == "") {
-            if (supports_AB(transport)) {
+            if (supports_AB()) {
                 fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n");
             }
             skip_secondary = true;
@@ -1165,7 +1165,7 @@
         if (!slot) continue;
         fname = find_item_given_name(images[i].img_name);
         fastboot_buffer buf;
-        if (!load_buf(transport, fname.c_str(), &buf)) {
+        if (!load_buf(fname.c_str(), &buf)) {
             if (images[i].is_optional) continue;
             die("could not load '%s': %s", images[i].img_name, strerror(errno));
         }
@@ -1174,13 +1174,13 @@
             do_send_signature(fname.c_str());
             flash_buf(partition.c_str(), &buf);
         };
-        do_for_partitions(transport, images[i].part_name, slot, flashall, false);
+        do_for_partitions(images[i].part_name, slot, flashall, false);
     }
 
     if (slot_override == "all") {
-        set_active(transport, "a");
+        set_active("a");
     } else {
-        set_active(transport, slot_override);
+        set_active(slot_override);
     }
 }
 
@@ -1210,9 +1210,9 @@
     return var;
 }
 
-static unsigned fb_get_flash_block_size(Transport* transport, std::string name) {
+static unsigned fb_get_flash_block_size(std::string name) {
     std::string sizeString;
-    if (!fb_getvar(transport, name, &sizeString) || sizeString.empty()) {
+    if (!fb_getvar(name, &sizeString) || sizeString.empty()) {
         // This device does not report flash block sizes, so return 0.
         return 0;
     }
@@ -1230,7 +1230,7 @@
     return size;
 }
 
-static void fb_perform_format(Transport* transport,
+static void fb_perform_format(
                               const std::string& partition, int skip_if_not_supported,
                               const std::string& type_override, const std::string& size_override,
                               const std::string& initial_dir) {
@@ -1250,7 +1250,7 @@
         limit = sparse_limit;
     }
 
-    if (!fb_getvar(transport, "partition-type:" + partition, &partition_type)) {
+    if (!fb_getvar("partition-type:" + partition, &partition_type)) {
         errMsg = "Can't determine partition type.\n";
         goto failed;
     }
@@ -1262,7 +1262,7 @@
         partition_type = type_override;
     }
 
-    if (!fb_getvar(transport, "partition-size:" + partition, &partition_size)) {
+    if (!fb_getvar("partition-size:" + partition, &partition_size)) {
         errMsg = "Unable to get partition size\n";
         goto failed;
     }
@@ -1294,8 +1294,8 @@
     }
 
     unsigned eraseBlkSize, logicalBlkSize;
-    eraseBlkSize = fb_get_flash_block_size(transport, "erase-block-size");
-    logicalBlkSize = fb_get_flash_block_size(transport, "logical-block-size");
+    eraseBlkSize = fb_get_flash_block_size("erase-block-size");
+    logicalBlkSize = fb_get_flash_block_size("logical-block-size");
 
     if (fs_generator_generate(gen, output.path, size, initial_dir,
             eraseBlkSize, logicalBlkSize)) {
@@ -1308,7 +1308,7 @@
         fprintf(stderr, "Cannot open generated image: %s\n", strerror(errno));
         return;
     }
-    if (!load_buf_fd(transport, fd.release(), &buf)) {
+    if (!load_buf_fd(fd.release(), &buf)) {
         fprintf(stderr, "Cannot read image: %s\n", strerror(errno));
         return;
     }
@@ -1323,7 +1323,7 @@
     fprintf(stderr, "FAILED (%s)\n", fb_get_error().c_str());
 }
 
-int FastBoot::Main(int argc, char* argv[]) {
+int FastBootTool::Main(int argc, char* argv[]) {
     bool wants_wipe = false;
     bool wants_reboot = false;
     bool wants_reboot_bootloader = false;
@@ -1470,23 +1470,25 @@
     if (transport == nullptr) {
         return 1;
     }
+    fastboot::FastBootDriver fb(transport);
+    fb_init(fb);
 
     const double start = now();
 
-    if (slot_override != "") slot_override = verify_slot(transport, slot_override);
-    if (next_active != "") next_active = verify_slot(transport, next_active, false);
+    if (slot_override != "") slot_override = verify_slot(slot_override);
+    if (next_active != "") next_active = verify_slot(next_active, false);
 
     if (wants_set_active) {
         if (next_active == "") {
             if (slot_override == "") {
                 std::string current_slot;
-                if (fb_getvar(transport, "current-slot", &current_slot)) {
-                    next_active = verify_slot(transport, current_slot, false);
+                if (fb_getvar("current-slot", &current_slot)) {
+                    next_active = verify_slot(current_slot, false);
                 } else {
                     wants_set_active = false;
                 }
             } else {
-                next_active = verify_slot(transport, slot_override, false);
+                next_active = verify_slot(slot_override, false);
             }
         }
     }
@@ -1502,7 +1504,7 @@
             std::string partition = next_arg(&args);
             auto erase = [&](const std::string& partition) {
                 std::string partition_type;
-                if (fb_getvar(transport, std::string("partition-type:") + partition,
+                if (fb_getvar(std::string("partition-type:") + partition,
                               &partition_type) &&
                     fs_get_generator(partition_type) != nullptr) {
                     fprintf(stderr, "******** Did you mean to fastboot format this %s partition?\n",
@@ -1511,7 +1513,7 @@
 
                 fb_queue_erase(partition);
             };
-            do_for_partitions(transport, partition, slot_override, erase, true);
+            do_for_partitions(partition, slot_override, erase, true);
         } else if (android::base::StartsWith(command, "format")) {
             // Parsing for: "format[:[type][:[size]]]"
             // Some valid things:
@@ -1529,9 +1531,9 @@
             std::string partition = next_arg(&args);
 
             auto format = [&](const std::string& partition) {
-                fb_perform_format(transport, partition, 0, type_override, size_override, "");
+                fb_perform_format(partition, 0, type_override, size_override, "");
             };
-            do_for_partitions(transport, partition.c_str(), slot_override, format, true);
+            do_for_partitions(partition.c_str(), slot_override, format, true);
         } else if (command == "signature") {
             std::string filename = next_arg(&args);
             data = load_file(filename.c_str(), &sz);
@@ -1579,9 +1581,9 @@
             if (fname.empty()) die("cannot determine image filename for '%s'", pname.c_str());
 
             auto flash = [&](const std::string &partition) {
-                do_flash(transport, partition.c_str(), fname.c_str());
+                do_flash(partition.c_str(), fname.c_str());
             };
-            do_for_partitions(transport, pname.c_str(), slot_override, flash, true);
+            do_for_partitions(pname.c_str(), slot_override, flash, true);
         } else if (command == "flash:raw") {
             std::string partition = next_arg(&args);
             std::string kernel = next_arg(&args);
@@ -1594,13 +1596,13 @@
             auto flashraw = [&](const std::string& partition) {
                 fb_queue_flash(partition, data, sz);
             };
-            do_for_partitions(transport, partition, slot_override, flashraw, true);
+            do_for_partitions(partition, slot_override, flashraw, true);
         } 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, true);
+                do_flashall(slot_override, true);
             } else {
-                do_flashall(transport, slot_override, skip_secondary);
+                do_flashall(slot_override, skip_secondary);
             }
             wants_reboot = true;
         } else if (command == "update") {
@@ -1612,16 +1614,16 @@
             if (!args.empty()) {
                 filename = next_arg(&args);
             }
-            do_update(transport, filename.c_str(), slot_override, skip_secondary || slot_all);
+            do_update(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);
+            std::string slot = verify_slot(next_arg(&args), false);
             fb_set_active(slot);
         } else if (command == "stage") {
             std::string filename = next_arg(&args);
 
             struct fastboot_buffer buf;
-            if (!load_buf(transport, filename.c_str(), &buf) || buf.type != FB_BUFFER_FD) {
+            if (!load_buf(filename.c_str(), &buf) || buf.type != FB_BUFFER_FD) {
                 die("cannot load '%s'", filename.c_str());
             }
             fb_queue_download_fd(filename, buf.fd, buf.sz);
@@ -1650,16 +1652,16 @@
         std::vector<std::string> partitions = { "userdata", "cache", "metadata" };
         for (const auto& partition : partitions) {
             std::string partition_type;
-            if (!fb_getvar(transport, std::string{"partition-type:"} + partition, &partition_type)) continue;
+            if (!fb_getvar(std::string{"partition-type:"} + partition, &partition_type)) continue;
             if (partition_type.empty()) continue;
             fb_queue_erase(partition);
             if (partition == "userdata" && set_fbe_marker) {
                 fprintf(stderr, "setting FBE marker on initial userdata...\n");
                 std::string initial_userdata_dir = create_fbemarker_tmpdir();
-                fb_perform_format(transport, partition, 1, "", "", initial_userdata_dir);
+                fb_perform_format(partition, 1, "", "", initial_userdata_dir);
                 delete_fbemarker_tmpdir(initial_userdata_dir);
             } else {
-                fb_perform_format(transport, partition, 1, "", "", "");
+                fb_perform_format(partition, 1, "", "", "");
             }
         }
     }
@@ -1674,12 +1676,12 @@
         fb_queue_wait_for_disconnect();
     }
 
-    int status = fb_execute_queue(transport) ? EXIT_FAILURE : EXIT_SUCCESS;
+    int status = fb_execute_queue() ? 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) {
+void FastBootTool::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);
@@ -1689,7 +1691,7 @@
     hdr->SetOsPatchLevel(year, month);
 }
 
-void FastBoot::ParseOsVersion(boot_img_hdr_v1* hdr, const char* arg) {
+void FastBootTool::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 ||
diff --git a/fastboot/fastboot_driver.cpp b/fastboot/fastboot_driver.cpp
new file mode 100644
index 0000000..c308420
--- /dev/null
+++ b/fastboot/fastboot_driver.cpp
@@ -0,0 +1,533 @@
+/*
+ * Copyright (C) 2018 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_driver.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <algorithm>
+#include <chrono>
+#include <fstream>
+#include <memory>
+#include <regex>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <utils/FileMap.h>
+#include "fastboot_driver.h"
+#include "transport.h"
+
+namespace fastboot {
+
+/*************************** PUBLIC *******************************/
+FastBootDriver::FastBootDriver(Transport* transport, std::function<void(std::string&)> info,
+                               bool no_checks)
+    : transport(transport) {
+    info_cb_ = info;
+    disable_checks_ = no_checks;
+}
+
+RetCode FastBootDriver::Boot(std::string* response, std::vector<std::string>* info) {
+    return RawCommand(Commands::BOOT, response, info);
+}
+
+RetCode FastBootDriver::Continue(std::string* response, std::vector<std::string>* info) {
+    return RawCommand(Commands::CONTINUE, response, info);
+}
+
+RetCode FastBootDriver::Erase(const std::string& part, std::string* response,
+                              std::vector<std::string>* info) {
+    return RawCommand(Commands::ERASE + part, response, info);
+}
+
+RetCode FastBootDriver::Flash(const std::string& part, std::string* response,
+                              std::vector<std::string>* info) {
+    return RawCommand(Commands::FLASH + part, response, info);
+}
+
+RetCode FastBootDriver::GetVar(const std::string& key, std::string* val,
+                               std::vector<std::string>* info) {
+    return RawCommand(Commands::GET_VAR + key, val, info);
+}
+
+RetCode FastBootDriver::GetVarAll(std::vector<std::string>* response) {
+    std::string tmp;
+    return GetVar("all", &tmp, response);
+}
+
+RetCode FastBootDriver::Powerdown(std::string* response, std::vector<std::string>* info) {
+    return RawCommand(Commands::POWERDOWN, response, info);
+}
+
+RetCode FastBootDriver::Reboot(std::string* response, std::vector<std::string>* info) {
+    return RawCommand(Commands::REBOOT, response, info);
+}
+
+RetCode FastBootDriver::SetActive(const std::string& part, std::string* response,
+                                  std::vector<std::string>* info) {
+    return RawCommand(Commands::SET_ACTIVE + part, response, info);
+}
+
+RetCode FastBootDriver::Verify(uint32_t num, std::string* response, std::vector<std::string>* info) {
+    std::string cmd = android::base::StringPrintf("%s%08" PRIx32, Commands::VERIFY.c_str(), num);
+    return RawCommand(cmd, response, info);
+}
+
+RetCode FastBootDriver::FlashPartition(const std::string& part, const std::vector<char>& data) {
+    RetCode ret;
+    if ((ret = Download(data))) {
+        return ret;
+    }
+    return RawCommand(Commands::FLASH + part);
+}
+
+RetCode FastBootDriver::FlashPartition(const std::string& part, int fd, uint32_t sz) {
+    RetCode ret;
+    if ((ret = Download(fd, sz))) {
+        return ret;
+    }
+    return RawCommand(Commands::FLASH + part);
+}
+
+RetCode FastBootDriver::FlashPartition(const std::string& part, sparse_file* s) {
+    RetCode ret;
+    if ((ret = Download(s))) {
+        return ret;
+    }
+    return RawCommand(Commands::FLASH + part);
+}
+
+RetCode FastBootDriver::Partitions(std::vector<std::tuple<std::string, uint32_t>>* parts) {
+    std::vector<std::string> all;
+    RetCode ret;
+    if ((ret = GetVarAll(&all))) {
+        return ret;
+    }
+
+    std::regex reg("partition-size[[:s:]]*:[[:s:]]*([[:w:]]+)[[:s:]]*:[[:s:]]*0x([[:d:]]+)");
+    std::smatch sm;
+
+    for (auto& s : all) {
+        if (std::regex_match(s, sm, reg)) {
+            std::string m1(sm[1]);
+            std::string m2(sm[2]);
+            uint32_t tmp = strtol(m2.c_str(), 0, 16);
+            parts->push_back(std::make_tuple(m1, tmp));
+        }
+    }
+    return SUCCESS;
+}
+
+RetCode FastBootDriver::Require(const std::string& var, const std::vector<std::string>& allowed,
+                                bool* reqmet, bool invert) {
+    *reqmet = invert;
+    RetCode ret;
+    std::string response;
+    if ((ret = GetVar(var, &response))) {
+        return ret;
+    }
+
+    // Now check if we have a match
+    for (const auto s : allowed) {
+        // If it ends in *, and starting substring match
+        if (response == s || (s.length() && s.back() == '*' &&
+                              !response.compare(0, s.length() - 1, s, 0, s.length() - 1))) {
+            *reqmet = !invert;
+            break;
+        }
+    }
+
+    return SUCCESS;
+}
+
+RetCode FastBootDriver::Download(int fd, size_t size, std::string* response,
+                                 std::vector<std::string>* info) {
+    RetCode ret;
+
+    if ((size <= 0 || size > MAX_DOWNLOAD_SIZE) && !disable_checks_) {
+        error_ = "File is too large to download";
+        return BAD_ARG;
+    }
+
+    uint32_t u32size = static_cast<uint32_t>(size);
+    if ((ret = DownloadCommand(u32size, response, info))) {
+        return ret;
+    }
+
+    // Write the buffer
+    if ((ret = SendBuffer(fd, size))) {
+        return ret;
+    }
+
+    // Wait for response
+    return HandleResponse(response, info);
+}
+
+RetCode FastBootDriver::Download(const std::vector<char>& buf, std::string* response,
+                                 std::vector<std::string>* info) {
+    return Download(buf.data(), buf.size(), response, info);
+}
+
+RetCode FastBootDriver::Download(const char* buf, uint32_t size, std::string* response,
+                                 std::vector<std::string>* info) {
+    RetCode ret;
+    error_ = "";
+    if ((size == 0 || size > MAX_DOWNLOAD_SIZE) && !disable_checks_) {
+        error_ = "Buffer is too large or 0 bytes";
+        return BAD_ARG;
+    }
+
+    if ((ret = DownloadCommand(size, response, info))) {
+        return ret;
+    }
+
+    // Write the buffer
+    if ((ret = SendBuffer(buf, size))) {
+        return ret;
+    }
+
+    // Wait for response
+    return HandleResponse(response, info);
+}
+
+RetCode FastBootDriver::Download(sparse_file* s, std::string* response,
+                                 std::vector<std::string>* info) {
+    error_ = "";
+    int64_t size = sparse_file_len(s, true, false);
+    if (size <= 0 || size > MAX_DOWNLOAD_SIZE) {
+        error_ = "Sparse file is too large or invalid";
+        return BAD_ARG;
+    }
+
+    RetCode ret;
+    uint32_t u32size = static_cast<uint32_t>(size);
+    if ((ret = DownloadCommand(u32size, response, info))) {
+        return ret;
+    }
+
+    struct SparseCBPrivate {
+        FastBootDriver* self;
+        std::vector<char> tpbuf;
+    } cb_priv;
+    cb_priv.self = this;
+
+    auto cb = [](void* priv, const void* buf, size_t len) -> int {
+        SparseCBPrivate* data = static_cast<SparseCBPrivate*>(priv);
+        const char* cbuf = static_cast<const char*>(buf);
+        return data->self->SparseWriteCallback(data->tpbuf, cbuf, len);
+    };
+
+    if (sparse_file_callback(s, true, false, cb, &cb_priv) < 0) {
+        error_ = "Error reading sparse file";
+        return IO_ERROR;
+    }
+
+    // Now flush
+    if (cb_priv.tpbuf.size() && (ret = SendBuffer(cb_priv.tpbuf))) {
+        return ret;
+    }
+
+    return HandleResponse(response, info);
+}
+
+RetCode FastBootDriver::Upload(const std::string& outfile, std::string* response,
+                               std::vector<std::string>* info) {
+    RetCode ret;
+    int dsize;
+    if ((ret = RawCommand(Commands::UPLOAD, response, info, &dsize)) || dsize == 0) {
+        error_ = "Upload request failed";
+        return ret;
+    }
+
+    std::vector<char> data;
+    data.resize(dsize);
+
+    if ((ret = ReadBuffer(data))) {
+        return ret;
+    }
+
+    std::ofstream ofs;
+    ofs.open(outfile, std::ofstream::out | std::ofstream::binary);
+    if (ofs.fail()) {
+        error_ = android::base::StringPrintf("Failed to open '%s'", outfile.c_str());
+        return IO_ERROR;
+    }
+    ofs.write(data.data(), data.size());
+    if (ofs.fail() || ofs.bad()) {
+        error_ = android::base::StringPrintf("Writing to '%s' failed", outfile.c_str());
+        return IO_ERROR;
+    }
+    ofs.close();
+
+    return HandleResponse(response, info);
+}
+
+// Helpers
+void FastBootDriver::SetInfoCallback(std::function<void(std::string&)> info) {
+    info_cb_ = info;
+}
+
+const std::string FastBootDriver::RCString(RetCode rc) {
+    switch (rc) {
+        case SUCCESS:
+            return std::string("Success");
+
+        case BAD_ARG:
+            return std::string("Invalid Argument");
+
+        case IO_ERROR:
+            return std::string("I/O Error");
+
+        case BAD_DEV_RESP:
+            return std::string("Invalid Device Response");
+
+        case DEVICE_FAIL:
+            return std::string("Device Error");
+
+        case TIMEOUT:
+            return std::string("Timeout");
+
+        default:
+            return std::string("Unknown Error");
+    }
+}
+
+std::string FastBootDriver::Error() {
+    return error_;
+}
+
+RetCode FastBootDriver::WaitForDisconnect() {
+    return transport->WaitForDisconnect() ? IO_ERROR : SUCCESS;
+}
+
+/****************************** PROTECTED *************************************/
+RetCode FastBootDriver::RawCommand(const std::string& cmd, std::string* response,
+                                   std::vector<std::string>* info, int* dsize) {
+    error_ = "";  // Clear any pending error
+    if (cmd.size() > FB_COMMAND_SZ && !disable_checks_) {
+        error_ = "Command length to RawCommand() is too long";
+        return BAD_ARG;
+    }
+
+    if (transport->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) {
+        error_ = ErrnoStr("Write to device failed");
+        return IO_ERROR;
+    }
+
+    // Read the response
+    return HandleResponse(response, info, dsize);
+}
+
+RetCode FastBootDriver::DownloadCommand(uint32_t size, std::string* response,
+                                        std::vector<std::string>* info) {
+    std::string cmd(android::base::StringPrintf("%s%08" PRIx32, Commands::DOWNLOAD.c_str(), size));
+    RetCode ret;
+    if ((ret = RawCommand(cmd, response, info))) {
+        return ret;
+    }
+    return SUCCESS;
+}
+
+RetCode FastBootDriver::HandleResponse(std::string* response, std::vector<std::string>* info,
+                                       int* dsize) {
+    char status[FB_RESPONSE_SZ + 1];
+    auto start = std::chrono::system_clock::now();
+
+    auto set_response = [response](std::string s) {
+        if (response) *response = std::move(s);
+    };
+    auto add_info = [info](std::string s) {
+        if (info) info->push_back(std::move(s));
+    };
+
+    // erase response
+    set_response("");
+    while ((std::chrono::system_clock::now() - start) < std::chrono::seconds(RESP_TIMEOUT)) {
+        int r = transport->Read(status, FB_RESPONSE_SZ);
+        if (r < 0) {
+            error_ = ErrnoStr("Status read failed");
+            return IO_ERROR;
+        }
+
+        status[r] = '\0';  // Need the null terminator
+        std::string input(status);
+        if (android::base::StartsWith(input, "INFO")) {
+            std::string tmp = input.substr(strlen("INFO"));
+            info_cb_(tmp);
+            add_info(std::move(tmp));
+        } else if (android::base::StartsWith(input, "OKAY")) {
+            set_response(input.substr(strlen("OKAY")));
+            return SUCCESS;
+        } else if (android::base::StartsWith(input, "FAIL")) {
+            error_ = android::base::StringPrintf("remote: '%s'", status + strlen("FAIL"));
+            set_response(input.substr(strlen("FAIL")));
+            return DEVICE_FAIL;
+        } else if (android::base::StartsWith(input, "DATA")) {
+            std::string tmp = input.substr(strlen("DATA"));
+            uint32_t num = strtol(tmp.c_str(), 0, 16);
+            if (num > MAX_DOWNLOAD_SIZE) {
+                error_ = android::base::StringPrintf("Data size too large (%d)", num);
+                return BAD_DEV_RESP;
+            }
+            if (dsize) *dsize = num;
+            set_response(std::move(tmp));
+            return SUCCESS;
+        } else {
+            error_ = android::base::StringPrintf("Device sent unknown status code: %s", status);
+            return BAD_DEV_RESP;
+        }
+
+    }  // End of while loop
+
+    return TIMEOUT;
+}
+
+std::string FastBootDriver::ErrnoStr(const std::string& msg) {
+    return android::base::StringPrintf("%s (%s)", msg.c_str(), strerror(errno));
+}
+
+const std::string FastBootDriver::Commands::BOOT = "boot";
+const std::string FastBootDriver::Commands::CONTINUE = "continue";
+const std::string FastBootDriver::Commands::DOWNLOAD = "download:";
+const std::string FastBootDriver::Commands::ERASE = "erase:";
+const std::string FastBootDriver::Commands::FLASH = "flash:";
+const std::string FastBootDriver::Commands::GET_VAR = "getvar:";
+const std::string FastBootDriver::Commands::POWERDOWN = "powerdown";
+const std::string FastBootDriver::Commands::REBOOT = "reboot";
+const std::string FastBootDriver::Commands::SET_ACTIVE = "set_active:";
+const std::string FastBootDriver::Commands::UPLOAD = "upload";
+const std::string FastBootDriver::Commands::VERIFY = "verify:";
+
+/******************************* PRIVATE **************************************/
+RetCode FastBootDriver::SendBuffer(int fd, size_t size) {
+    static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;
+    off64_t offset = 0;
+    uint32_t remaining = size;
+    RetCode ret;
+
+    while (remaining) {
+        // Memory map the file
+        android::FileMap filemap;
+        size_t len = std::min(remaining, MAX_MAP_SIZE);
+
+        if (!filemap.create(NULL, fd, offset, len, true)) {
+            error_ = "Creating filemap failed";
+            return IO_ERROR;
+        }
+
+        if ((ret = SendBuffer(filemap.getDataPtr(), len))) {
+            return ret;
+        }
+
+        remaining -= len;
+        offset += len;
+    }
+
+    return SUCCESS;
+}
+
+RetCode FastBootDriver::SendBuffer(const std::vector<char>& buf) {
+    // Write the buffer
+    return SendBuffer(buf.data(), buf.size());
+}
+
+RetCode FastBootDriver::SendBuffer(const void* buf, size_t size) {
+    // Write the buffer
+    ssize_t tmp = transport->Write(buf, size);
+
+    if (tmp < 0) {
+        error_ = ErrnoStr("Write to device failed in SendBuffer()");
+        return IO_ERROR;
+    } else if (static_cast<size_t>(tmp) != size) {
+        error_ = android::base::StringPrintf("Failed to write all %zu bytes", size);
+
+        return IO_ERROR;
+    }
+
+    return SUCCESS;
+}
+
+RetCode FastBootDriver::ReadBuffer(std::vector<char>& buf) {
+    // Read the buffer
+    return ReadBuffer(buf.data(), buf.size());
+}
+
+RetCode FastBootDriver::ReadBuffer(void* buf, size_t size) {
+    // Read the buffer
+    ssize_t tmp = transport->Read(buf, size);
+
+    if (tmp < 0) {
+        error_ = ErrnoStr("Read from device failed in ReadBuffer()");
+        return IO_ERROR;
+    } else if (static_cast<size_t>(tmp) != size) {
+        error_ = android::base::StringPrintf("Failed to read all %zu bytes", size);
+        return IO_ERROR;
+    }
+
+    return SUCCESS;
+}
+
+int FastBootDriver::SparseWriteCallback(std::vector<char>& tpbuf, const char* data, size_t len) {
+    size_t total = 0;
+    size_t to_write = std::min(TRANSPORT_CHUNK_SIZE - tpbuf.size(), len);
+
+    // Handle the residual
+    tpbuf.insert(tpbuf.end(), data, data + to_write);
+    if (tpbuf.size() < TRANSPORT_CHUNK_SIZE) {  // Nothing enough to send rn
+        return 0;
+    }
+
+    if (SendBuffer(tpbuf)) {
+        error_ = ErrnoStr("Send failed in SparseWriteCallback()");
+        return -1;
+    }
+    tpbuf.clear();
+    total += to_write;
+
+    // Now we need to send a multiple of chunk size
+    size_t nchunks = (len - total) / TRANSPORT_CHUNK_SIZE;
+    size_t nbytes = TRANSPORT_CHUNK_SIZE * nchunks;
+    if (SendBuffer(data + total, nbytes)) {
+        error_ = ErrnoStr("Send failed in SparseWriteCallback()");
+        return -1;
+    }
+    total += nbytes;
+
+    if (len - total > 0) {  // We have residual data to save for next time
+        tpbuf.assign(data + total, data + len);
+    }
+
+    return 0;
+}
+
+}  // End namespace fastboot
diff --git a/fastboot/fastboot_driver.h b/fastboot/fastboot_driver.h
new file mode 100644
index 0000000..9fdd317
--- /dev/null
+++ b/fastboot/fastboot_driver.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+#pragma once
+#include <cstdlib>
+#include <deque>
+#include <limits>
+#include <string>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <bootimg.h>
+#include <inttypes.h>
+#include <sparse/sparse.h>
+#include "transport.h"
+
+class Transport;
+
+namespace fastboot {
+
+static constexpr int FB_COMMAND_SZ = 64;
+static constexpr int FB_RESPONSE_SZ = 64;
+
+enum RetCode : int {
+    SUCCESS = 0,
+    BAD_ARG,
+    IO_ERROR,
+    BAD_DEV_RESP,
+    DEVICE_FAIL,
+    TIMEOUT,
+};
+
+class FastBootDriver {
+  public:
+    static constexpr int RESP_TIMEOUT = 10;  // 10 seconds
+    static constexpr uint32_t MAX_DOWNLOAD_SIZE = std::numeric_limits<uint32_t>::max();
+    static constexpr size_t TRANSPORT_CHUNK_SIZE = 1024;
+
+    FastBootDriver(Transport* transport,
+                   std::function<void(std::string&)> info = [](std::string&) {},
+                   bool no_checks = false);
+
+    RetCode Boot(std::string* response = nullptr, std::vector<std::string>* info = nullptr);
+    RetCode Continue(std::string* response = nullptr, std::vector<std::string>* info = nullptr);
+    RetCode Download(int fd, size_t size, std::string* response = nullptr,
+                     std::vector<std::string>* info = nullptr);
+    RetCode Download(const std::vector<char>& buf, std::string* response = nullptr,
+                     std::vector<std::string>* info = nullptr);
+    // This will be removed after fastboot is modified to use a vector
+    RetCode Download(const char* buf, uint32_t size, std::string* response = nullptr,
+                     std::vector<std::string>* info = nullptr);
+    RetCode Download(sparse_file* s, std::string* response = nullptr,
+                     std::vector<std::string>* info = nullptr);
+    RetCode Erase(const std::string& part, std::string* response = nullptr,
+                  std::vector<std::string>* info = nullptr);
+    RetCode Flash(const std::string& part, std::string* response = nullptr,
+                  std::vector<std::string>* info = nullptr);
+    RetCode GetVar(const std::string& key, std::string* val,
+                   std::vector<std::string>* info = nullptr);
+    RetCode GetVarAll(std::vector<std::string>* response);
+    RetCode Powerdown(std::string* response = nullptr, std::vector<std::string>* info = nullptr);
+    RetCode Reboot(std::string* response = nullptr, std::vector<std::string>* info = nullptr);
+    RetCode SetActive(const std::string& part, std::string* response = nullptr,
+                      std::vector<std::string>* info = nullptr);
+    RetCode Upload(const std::string& outfile, std::string* response = nullptr,
+                   std::vector<std::string>* info = nullptr);
+    RetCode Verify(uint32_t num, std::string* response = nullptr,
+                   std::vector<std::string>* info = nullptr);
+
+    /* HIGHER LEVEL COMMANDS -- Composed of the commands above */
+    RetCode FlashPartition(const std::string& part, const std::vector<char>& data);
+    RetCode FlashPartition(const std::string& part, int fd, uint32_t sz);
+    RetCode FlashPartition(const std::string& part, sparse_file* s);
+
+    RetCode Partitions(std::vector<std::tuple<std::string, uint32_t>>* parts);
+    RetCode Require(const std::string& var, const std::vector<std::string>& allowed, bool* reqmet,
+                    bool invert = false);
+
+    /* HELPERS */
+    void SetInfoCallback(std::function<void(std::string&)> info);
+    const std::string RCString(RetCode rc);
+    std::string Error();
+    RetCode WaitForDisconnect();
+
+    // This is temporarily public for engine.cpp
+    RetCode RawCommand(const std::string& cmd, std::string* response = nullptr,
+                       std::vector<std::string>* info = nullptr, int* dsize = nullptr);
+
+  protected:
+    RetCode DownloadCommand(uint32_t size, std::string* response = nullptr,
+                            std::vector<std::string>* info = nullptr);
+    RetCode HandleResponse(std::string* response = nullptr,
+                           std::vector<std::string>* info = nullptr, int* dsize = nullptr);
+
+    std::string ErrnoStr(const std::string& msg);
+
+    // More like a namespace...
+    struct Commands {
+        static const std::string BOOT;
+        static const std::string CONTINUE;
+        static const std::string DOWNLOAD;
+        static const std::string ERASE;
+        static const std::string FLASH;
+        static const std::string GET_VAR;
+        static const std::string POWERDOWN;
+        static const std::string REBOOT;
+        static const std::string SET_ACTIVE;
+        static const std::string UPLOAD;
+        static const std::string VERIFY;
+    };
+
+    Transport* const transport;
+
+  private:
+    RetCode SendBuffer(int fd, size_t size);
+    RetCode SendBuffer(const std::vector<char>& buf);
+    RetCode SendBuffer(const void* buf, size_t size);
+
+    RetCode ReadBuffer(std::vector<char>& buf);
+    RetCode ReadBuffer(void* buf, size_t size);
+
+    int SparseWriteCallback(std::vector<char>& tpbuf, const char* data, size_t len);
+
+    std::string error_;
+    std::function<void(std::string&)> info_cb_;
+    bool disable_checks_;
+};
+
+}  // namespace fastboot
diff --git a/fastboot/fastboot_test.cpp b/fastboot/fastboot_test.cpp
index 1681427..43201fa 100644
--- a/fastboot/fastboot_test.cpp
+++ b/fastboot/fastboot_test.cpp
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-#include "fastboot.h"
+#include "engine.h"
 
 #include <gtest/gtest.h>
 
 TEST(FastBoot, ParseOsPatchLevel) {
-    FastBoot fb;
+    FastBootTool fb;
     boot_img_hdr_v1 hdr;
 
     hdr = {};
@@ -34,7 +34,7 @@
 }
 
 TEST(FastBoot, ParseOsVersion) {
-    FastBoot fb;
+    FastBootTool fb;
     boot_img_hdr_v1 hdr;
 
     hdr = {};
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index 14dabaa..cc1714f 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -1,6 +1,5 @@
 #include "fs.h"
 
-#include "fastboot.h"
 
 #include <errno.h>
 #include <fcntl.h>
diff --git a/fastboot/main.cpp b/fastboot/main.cpp
index f1c8afb..c3683f7 100644
--- a/fastboot/main.cpp
+++ b/fastboot/main.cpp
@@ -26,9 +26,9 @@
  * SUCH DAMAGE.
  */
 
-#include "fastboot.h"
+#include "engine.h"
 
 int main(int argc, char* argv[]) {
-    FastBoot fb;
+    FastBootTool fb;
     return fb.Main(argc, argv);
 }
diff --git a/fastboot/protocol.cpp b/fastboot/protocol.cpp
deleted file mode 100644
index e625095..0000000
--- a/fastboot/protocol.cpp
+++ /dev/null
@@ -1,370 +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.
- */
-
-#define round_down(a, b) \
-    ({ typeof(a) _a = (a); typeof(b) _b = (b); _a - (_a % _b); })
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include <algorithm>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <android-base/unique_fd.h>
-#include <sparse/sparse.h>
-#include <utils/FileMap.h>
-
-#include "constants.h"
-#include "fastboot.h"
-#include "transport.h"
-
-static std::string g_error;
-
-using android::base::unique_fd;
-using android::base::WriteStringToFile;
-
-const std::string fb_get_error() {
-    return g_error;
-}
-
-static int64_t check_response(Transport* transport, uint32_t size, char* response) {
-    char status[FB_RESPONSE_SZ + 1];
-
-    while (true) {
-        int r = transport->Read(status, FB_RESPONSE_SZ);
-        if (r < 0) {
-            g_error = android::base::StringPrintf("status read failed (%s)", strerror(errno));
-            transport->Close();
-            return -1;
-        }
-        status[r] = 0;
-
-        if (static_cast<size_t>(r) < strlen(RESPONSE_OKAY)) {
-            g_error = android::base::StringPrintf("status malformed (%d bytes)", r);
-            transport->Close();
-            return -1;
-        }
-
-        if (!memcmp(status, RESPONSE_INFO, strlen(RESPONSE_INFO))) {
-            verbose("received INFO \"%s\"", status + strlen(RESPONSE_INFO));
-            fprintf(stderr, "(bootloader) %s\n", status + strlen(RESPONSE_INFO));
-            continue;
-        }
-
-        if (!memcmp(status, RESPONSE_OKAY, strlen(RESPONSE_OKAY))) {
-            verbose("received OKAY \"%s\"", status + strlen(RESPONSE_OKAY));
-            if (response) {
-                strcpy(response, status + strlen(RESPONSE_OKAY));
-            }
-            return 0;
-        }
-
-        if (!memcmp(status, RESPONSE_FAIL, strlen(RESPONSE_FAIL))) {
-            verbose("received FAIL \"%s\"", status + strlen(RESPONSE_FAIL));
-            if (static_cast<size_t>(r) > strlen(RESPONSE_FAIL)) {
-                g_error = android::base::StringPrintf("remote: %s", status + strlen(RESPONSE_FAIL));
-            } else {
-                g_error = "remote failure";
-            }
-            return -1;
-        }
-
-        if (!memcmp(status, RESPONSE_DATA, strlen(RESPONSE_DATA)) && size > 0){
-            verbose("received DATA %s", status + strlen(RESPONSE_DATA));
-            uint32_t dsize = strtol(status + strlen(RESPONSE_DATA), 0, 16);
-            if (dsize > size) {
-                g_error = android::base::StringPrintf("data size too large (%d)", dsize);
-                transport->Close();
-                return -1;
-            }
-            return dsize;
-        }
-
-        verbose("received unknown status code \"%4.4s\"", status);
-        g_error = "unknown status code";
-        transport->Close();
-        break;
-    }
-
-    return -1;
-}
-
-static int64_t _command_start(Transport* transport, const std::string& cmd, uint32_t size,
-                              char* response) {
-    if (cmd.size() > FB_COMMAND_SZ) {
-        g_error = android::base::StringPrintf("command too large (%zu)", cmd.size());
-        return -1;
-    }
-
-    if (response) {
-        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();
-        return -1;
-    }
-
-    return check_response(transport, size, response);
-}
-
-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));
-        transport->Close();
-        return -1;
-    }
-    if (r != static_cast<int64_t>(size)) {
-        g_error = "data write failure (short transfer)";
-        transport->Close();
-        return -1;
-    }
-    return r;
-}
-
-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));
-        transport->Close();
-        return -1;
-    }
-    if (r != (static_cast<int64_t>(size))) {
-        g_error = "data read failure (short transfer)";
-        transport->Close();
-        return -1;
-    }
-    return r;
-}
-
-static int64_t _command_end(Transport* transport) {
-    return check_response(transport, 0, 0) < 0 ? -1 : 0;
-}
-
-static int64_t _command_send(Transport* transport, const std::string& cmd, const void* data,
-                             uint32_t size, char* response) {
-    if (size == 0) {
-        return -1;
-    }
-
-    int64_t r = _command_start(transport, cmd, size, response);
-    if (r < 0) {
-        return -1;
-    }
-    r = _command_write_data(transport, data, size);
-    if (r < 0) {
-        return -1;
-    }
-
-    r = _command_end(transport);
-    if (r < 0) {
-        return -1;
-    }
-
-    return size;
-}
-
-static int64_t _command_send_fd(Transport* transport, const std::string& cmd, int fd, uint32_t size,
-                                char* response) {
-    static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;
-    off64_t offset = 0;
-    uint32_t remaining = size;
-
-    if (_command_start(transport, cmd, size, response) < 0) {
-        return -1;
-    }
-
-    while (remaining) {
-        android::FileMap filemap;
-        size_t len = std::min(remaining, MAX_MAP_SIZE);
-
-        if (!filemap.create(NULL, fd, offset, len, true)) {
-            return -1;
-        }
-
-        if (_command_write_data(transport, filemap.getDataPtr(), len) < 0) {
-            return -1;
-        }
-
-        remaining -= len;
-        offset += len;
-    }
-
-    if (_command_end(transport) < 0) {
-        return -1;
-    }
-
-    return size;
-}
-
-static int _command_send_no_data(Transport* transport, const std::string& cmd, char* response) {
-    return _command_start(transport, cmd, 0, response);
-}
-
-int fb_command(Transport* transport, const std::string& cmd) {
-    return _command_send_no_data(transport, cmd, 0);
-}
-
-int fb_command_response(Transport* transport, const std::string& cmd, char* response) {
-    return _command_send_no_data(transport, cmd, response);
-}
-
-int64_t fb_download_data(Transport* transport, const void* data, uint32_t size) {
-    std::string cmd(android::base::StringPrintf(
-                FB_CMD_DOWNLOAD ":" "%08x", size));
-    return _command_send(transport, cmd.c_str(), data, size, 0) < 0 ? -1 : 0;
-}
-
-int64_t fb_download_data_fd(Transport* transport, int fd, uint32_t size) {
-    std::string cmd(android::base::StringPrintf(
-                FB_CMD_DOWNLOAD ":" "%08x", size));
-    return _command_send_fd(transport, cmd.c_str(), fd, size, 0) < 0 ? -1 : 0;
-}
-
-int64_t fb_upload_data(Transport* transport, const char* outfile) {
-    // positive return value is the upload size sent by the device
-    int64_t r = _command_start(transport, FB_CMD_UPLOAD,
-            std::numeric_limits<int32_t>::max(), nullptr);
-    if (r <= 0) {
-        g_error = android::base::StringPrintf("command start failed (%s)", strerror(errno));
-        return r;
-    }
-
-    std::string data;
-    data.resize(r);
-    if ((r = _command_read_data(transport, &data[0], data.size())) == -1) {
-        return r;
-    }
-
-    if (!WriteStringToFile(data, outfile, true)) {
-        g_error = android::base::StringPrintf("write to '%s' failed", outfile);
-        return -1;
-    }
-
-    return _command_end(transport);
-}
-
-static constexpr size_t TRANSPORT_BUF_SIZE = 1024;
-static char transport_buf[TRANSPORT_BUF_SIZE];
-static size_t transport_buf_len;
-
-static int fb_download_data_sparse_write(void* priv, const void* data, size_t len) {
-    const char* ptr = static_cast<const char*>(data);
-    if (transport_buf_len) {
-        size_t to_write = std::min(TRANSPORT_BUF_SIZE - transport_buf_len, len);
-
-        memcpy(transport_buf + transport_buf_len, ptr, to_write);
-        transport_buf_len += to_write;
-        ptr += to_write;
-        len -= to_write;
-    }
-
-    Transport* transport = static_cast<Transport*>(priv);
-    if (transport_buf_len == TRANSPORT_BUF_SIZE) {
-        int64_t r = _command_write_data(transport, transport_buf, TRANSPORT_BUF_SIZE);
-        if (r != static_cast<int64_t>(TRANSPORT_BUF_SIZE)) {
-            return -1;
-        }
-        transport_buf_len = 0;
-    }
-
-    if (len > TRANSPORT_BUF_SIZE) {
-        if (transport_buf_len > 0) {
-            g_error = "internal error: transport_buf not empty";
-            return -1;
-        }
-        size_t to_write = round_down(len, TRANSPORT_BUF_SIZE);
-        int64_t r = _command_write_data(transport, ptr, to_write);
-        if (r != static_cast<int64_t>(to_write)) {
-            return -1;
-        }
-        ptr += to_write;
-        len -= to_write;
-    }
-
-    if (len > 0) {
-        if (len > TRANSPORT_BUF_SIZE) {
-            g_error = "internal error: too much left for transport_buf";
-            return -1;
-        }
-        memcpy(transport_buf, ptr, len);
-        transport_buf_len = len;
-    }
-
-    return 0;
-}
-
-static int fb_download_data_sparse_flush(Transport* transport) {
-    if (transport_buf_len > 0) {
-        int64_t r = _command_write_data(transport, transport_buf, transport_buf_len);
-        if (r != static_cast<int64_t>(transport_buf_len)) {
-            return -1;
-        }
-        transport_buf_len = 0;
-    }
-    return 0;
-}
-
-int fb_download_data_sparse(Transport* transport, struct sparse_file* s) {
-    int64_t size = sparse_file_len(s, true, false);
-    if (size <= 0 || size > std::numeric_limits<uint32_t>::max()) {
-        return -1;
-    }
-
-    std::string cmd(android::base::StringPrintf(
-                FB_CMD_DOWNLOAD ":" "%08" PRIx64, size));
-    int r = _command_start(transport, cmd, size, 0);
-    if (r < 0) {
-        return -1;
-    }
-
-    r = sparse_file_callback(s, true, false, fb_download_data_sparse_write, transport);
-    if (r < 0) {
-        return -1;
-    }
-
-    r = fb_download_data_sparse_flush(transport);
-    if (r < 0) {
-        return -1;
-    }
-
-    return _command_end(transport);
-}
diff --git a/fastboot/usb.h b/fastboot/usb.h
index 5b44468..7ca44c4 100644
--- a/fastboot/usb.h
+++ b/fastboot/usb.h
@@ -52,6 +52,14 @@
     char device_path[256];
 };
 
+class UsbTransport : public Transport {
+    // Resets the underlying transport.  Returns 0 on success.
+    // This effectively simulates unplugging and replugging
+  public:
+    virtual int Reset() = 0;
+};
+
 typedef int (*ifc_match_func)(usb_ifc_info *ifc);
 
-Transport* usb_open(ifc_match_func callback);
+// 0 is non blocking
+UsbTransport* usb_open(ifc_match_func callback, uint32_t timeout_ms = 0);
diff --git a/fastboot/usb_linux.cpp b/fastboot/usb_linux.cpp
index cdab4f1..9b779dd 100644
--- a/fastboot/usb_linux.cpp
+++ b/fastboot/usb_linux.cpp
@@ -47,12 +47,12 @@
 #include <memory>
 #include <thread>
 
-#include "fastboot.h"
 #include "usb.h"
+#include "util.h"
 
 using namespace std::chrono_literals;
 
-#define MAX_RETRIES 5
+#define MAX_RETRIES 2
 
 /* Timeout in seconds for usb_wait_for_disconnect.
  * It doesn't usually take long for a device to disconnect (almost always
@@ -91,18 +91,21 @@
     unsigned char ep_out;
 };
 
-class LinuxUsbTransport : public Transport {
+class LinuxUsbTransport : public UsbTransport {
   public:
-    explicit LinuxUsbTransport(std::unique_ptr<usb_handle> handle) : handle_(std::move(handle)) {}
+    explicit LinuxUsbTransport(std::unique_ptr<usb_handle> handle, uint32_t ms_timeout = 0)
+        : handle_(std::move(handle)), ms_timeout_(ms_timeout) {}
     ~LinuxUsbTransport() override = default;
 
     ssize_t Read(void* data, size_t len) override;
     ssize_t Write(const void* data, size_t len) override;
     int Close() override;
+    int Reset() override;
     int WaitForDisconnect() override;
 
   private:
     std::unique_ptr<usb_handle> handle_;
+    const uint32_t ms_timeout_;
 
     DISALLOW_COPY_AND_ASSIGN(LinuxUsbTransport);
 };
@@ -402,7 +405,7 @@
         bulk.ep = handle_->ep_out;
         bulk.len = xfer;
         bulk.data = data;
-        bulk.timeout = 0;
+        bulk.timeout = ms_timeout_;
 
         n = ioctl(handle_->desc, USBDEVFS_BULK, &bulk);
         if(n != xfer) {
@@ -436,7 +439,7 @@
         bulk.ep = handle_->ep_in;
         bulk.len = xfer;
         bulk.data = data;
-        bulk.timeout = 0;
+        bulk.timeout = ms_timeout_;
         retry = 0;
 
         do {
@@ -447,7 +450,7 @@
             if (n < 0) {
                 DBG1("ERROR: n = %d, errno = %d (%s)\n",n, errno, strerror(errno));
                 if (++retry > MAX_RETRIES) return -1;
-                std::this_thread::sleep_for(1s);
+                std::this_thread::sleep_for(100ms);
             }
         } while (n < 0);
 
@@ -477,10 +480,19 @@
     return 0;
 }
 
-Transport* usb_open(ifc_match_func callback)
-{
+int LinuxUsbTransport::Reset() {
+    int ret = 0;
+    // We reset the USB connection
+    if ((ret = ioctl(handle_->desc, USBDEVFS_RESET, 0))) {
+        return ret;
+    }
+
+    return 0;
+}
+
+UsbTransport* usb_open(ifc_match_func callback, uint32_t timeout_ms) {
     std::unique_ptr<usb_handle> handle = find_usb_device("/sys/bus/usb/devices", callback);
-    return handle ? new LinuxUsbTransport(std::move(handle)) : nullptr;
+    return handle ? new LinuxUsbTransport(std::move(handle), timeout_ms) : nullptr;
 }
 
 /* Wait for the system to notice the device is gone, so that a subsequent
diff --git a/fastboot/usb_osx.cpp b/fastboot/usb_osx.cpp
index e95b049..4d48f6e 100644
--- a/fastboot/usb_osx.cpp
+++ b/fastboot/usb_osx.cpp
@@ -65,17 +65,21 @@
     unsigned int zero_mask;
 };
 
-class OsxUsbTransport : public Transport {
+class OsxUsbTransport : public UsbTransport {
   public:
-    OsxUsbTransport(std::unique_ptr<usb_handle> handle) : handle_(std::move(handle)) {}
+    // A timeout of 0 is blocking
+    OsxUsbTransport(std::unique_ptr<usb_handle> handle, uint32_t ms_timeout = 0)
+        : handle_(std::move(handle)), ms_timeout_(ms_timeout) {}
     ~OsxUsbTransport() override = default;
 
     ssize_t Read(void* data, size_t len) override;
     ssize_t Write(const void* data, size_t len) override;
     int Close() override;
+    int Reset() override;
 
   private:
     std::unique_ptr<usb_handle> handle_;
+    const uint32_t ms_timeout_;
 
     DISALLOW_COPY_AND_ASSIGN(OsxUsbTransport);
 };
@@ -456,7 +460,7 @@
  * Definitions of this file's public functions.
  */
 
-Transport* usb_open(ifc_match_func callback) {
+UsbTransport* usb_open(ifc_match_func callback, uint32_t timeout_ms) {
     std::unique_ptr<usb_handle> handle;
 
     if (init_usb(callback, &handle) < 0) {
@@ -464,7 +468,7 @@
         return nullptr;
     }
 
-    return new OsxUsbTransport(std::move(handle));
+    return new OsxUsbTransport(std::move(handle), timeout_ms);
 }
 
 int OsxUsbTransport::Close() {
@@ -472,6 +476,19 @@
     return 0;
 }
 
+/*
+  TODO: this SHOULD be easy to do with ResetDevice() from IOUSBDeviceInterface.
+  However to perform operations that manipulate the state of the device, you must
+  claim ownership of the device with USBDeviceOpenSeize(). However, this operation
+  always fails with kIOReturnExclusiveAccess.
+  It seems that the kext com.apple.driver.usb.AppleUSBHostCompositeDevice
+  always loads and claims ownership of the device and refuses to give it up.
+*/
+int OsxUsbTransport::Reset() {
+    ERR("USB reset is currently unsupported on osx\n");
+    return -1;
+}
+
 ssize_t OsxUsbTransport::Read(void* data, size_t len) {
     IOReturn result;
     UInt32 numBytes = len;
@@ -494,7 +511,14 @@
         return -1;
     }
 
-    result = (*handle_->interface)->ReadPipe(handle_->interface, handle_->bulkIn, data, &numBytes);
+    if (!ms_timeout_) {
+        result = (*handle_->interface)
+                         ->ReadPipe(handle_->interface, handle_->bulkIn, data, &numBytes);
+    } else {
+        result = (*handle_->interface)
+                         ->ReadPipeTO(handle_->interface, handle_->bulkIn, data, &numBytes,
+                                      ms_timeout_, ms_timeout_);
+    }
 
     if (result == 0) {
         return (int) numBytes;
@@ -541,8 +565,16 @@
         int lenToSend = lenRemaining > maxLenToSend
             ? maxLenToSend : lenRemaining;
 
-        result = (*handle_->interface)->WritePipe(
-                handle_->interface, handle_->bulkOut, (void *)data, lenToSend);
+        if (!ms_timeout_) {  // blocking
+            result = (*handle_->interface)
+                             ->WritePipe(handle_->interface, handle_->bulkOut, (void*)data,
+                                         lenToSend);
+        } else {
+            result = (*handle_->interface)
+                             ->WritePipeTO(handle_->interface, handle_->bulkOut, (void*)data,
+                                           lenToSend, ms_timeout_, ms_timeout_);
+        }
+
         if (result != 0) break;
 
         lenRemaining -= lenToSend;
diff --git a/fastboot/usb_windows.cpp b/fastboot/usb_windows.cpp
index 3dab5ac..8c60a71 100644
--- a/fastboot/usb_windows.cpp
+++ b/fastboot/usb_windows.cpp
@@ -66,7 +66,7 @@
     std::string interface_name;
 };
 
-class WindowsUsbTransport : public Transport {
+class WindowsUsbTransport : public UsbTransport {
   public:
     WindowsUsbTransport(std::unique_ptr<usb_handle> handle) : handle_(std::move(handle)) {}
     ~WindowsUsbTransport() override = default;
@@ -74,6 +74,7 @@
     ssize_t Read(void* data, size_t len) override;
     ssize_t Write(const void* data, size_t len) override;
     int Close() override;
+    int Reset() override;
 
   private:
     std::unique_ptr<usb_handle> handle_;
@@ -106,6 +107,7 @@
 
     if (nullptr == ret->adb_interface) {
         errno = GetLastError();
+        DBG("failed to open interface %S\n", interface_name);
         return nullptr;
     }
 
@@ -157,7 +159,7 @@
     unsigned count = 0;
     int ret;
 
-    DBG("usb_write %d\n", len);
+    DBG("usb_write %zu\n", len);
     if (nullptr != handle_) {
         // Perform write
         while(len > 0) {
@@ -195,7 +197,7 @@
     unsigned long read = 0;
     int ret;
 
-    DBG("usb_read %d\n", len);
+    DBG("usb_read %zu\n", len);
     if (nullptr != handle_) {
         while (1) {
             int xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
@@ -260,6 +262,12 @@
     return 0;
 }
 
+int WindowsUsbTransport::Reset() {
+    DBG("usb_reset currently unsupported\n\n");
+    // TODO, this is a bit complicated since it is using ADB
+    return -1;
+}
+
 int recognized_device(usb_handle* handle, ifc_match_func callback) {
     struct usb_ifc_info info;
     USB_DEVICE_DESCRIPTOR device_desc;
@@ -269,19 +277,22 @@
         return 0;
 
     // Check vendor and product id first
-    if (!AdbGetUsbDeviceDescriptor(handle->adb_interface,
-                                 &device_desc)) {
+    if (!AdbGetUsbDeviceDescriptor(handle->adb_interface, &device_desc)) {
+        DBG("skipping device %x:%x\n", device_desc.idVendor, device_desc.idProduct);
         return 0;
     }
 
     // Then check interface properties
-    if (!AdbGetUsbInterfaceDescriptor(handle->adb_interface,
-                                    &interf_desc)) {
+    if (!AdbGetUsbInterfaceDescriptor(handle->adb_interface, &interf_desc)) {
+        DBG("skipping device %x:%x, failed to find interface\n", device_desc.idVendor,
+            device_desc.idProduct);
         return 0;
     }
 
     // Must have two endpoints
     if (2 != interf_desc.bNumEndpoints) {
+        DBG("skipping device %x:%x, incorrect number of endpoints\n", device_desc.idVendor,
+            device_desc.idProduct);
         return 0;
     }
 
@@ -305,9 +316,13 @@
     info.device_path[0] = 0;
 
     if (callback(&info) == 0) {
+        DBG("skipping device %x:%x, not selected by callback\n", device_desc.idVendor,
+            device_desc.idProduct);
         return 1;
     }
 
+    DBG("found device %x:%x (%s)\n", device_desc.idVendor, device_desc.idProduct,
+        info.serial_number);
     return 0;
 }
 
@@ -338,6 +353,7 @@
         }
         *copy_name = '\0';
 
+        DBG("attempting to open interface %S\n", next_interface->device_name);
         handle = do_usb_open(next_interface->device_name);
         if (NULL != handle) {
             // Lets see if this interface (device) belongs to us
@@ -357,8 +373,7 @@
     return handle;
 }
 
-Transport* usb_open(ifc_match_func callback)
-{
+UsbTransport* usb_open(ifc_match_func callback, uint32_t) {
     std::unique_ptr<usb_handle> handle = find_usb_device(callback);
     return handle ? new WindowsUsbTransport(std::move(handle)) : nullptr;
 }
diff --git a/fastboot/util.cpp b/fastboot/util.cpp
index 140270f..8f6e52a 100644
--- a/fastboot/util.cpp
+++ b/fastboot/util.cpp
@@ -33,7 +33,7 @@
 
 #include <sys/time.h>
 
-#include "fastboot.h"
+#include "util.h"
 
 static bool g_verbose = false;
 
diff --git a/fastboot/util.h b/fastboot/util.h
new file mode 100644
index 0000000..9033f93
--- /dev/null
+++ b/fastboot/util.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include <string>
+
+#include <bootimg.h>
+
+/* 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.
+void die(const char* fmt, ...) __attribute__((__noreturn__))
+__attribute__((__format__(__printf__, 1, 2)));
+void verbose(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2)));
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index a3ce879..bf69096 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -30,7 +30,7 @@
     ],
 }
 
-cc_library_static {
+cc_library {
     name: "libfs_mgr",
     defaults: ["fs_mgr_defaults"],
     recovery_available: true,
@@ -44,15 +44,20 @@
         "fs_mgr_avb_ops.cpp",
         "fs_mgr_dm_linear.cpp",
     ],
-    static_libs: [
+    shared_libs: [
         "libfec",
         "libfec_rs",
         "libbase",
         "libcrypto_utils",
         "libcrypto",
+        "libcutils",
         "libext4_utils",
+        "libkeyutils",
+        "liblog",
         "libsquashfs_utils",
         "libselinux",
+    ],
+    static_libs: [
         "libavb",
         "libfstab",
         "libdm",
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
index 5159b4c..05e03e1 100644
--- a/fs_mgr/fs_mgr_dm_linear.cpp
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -50,33 +50,6 @@
 using DmTargetZero = android::dm::DmTargetZero;
 using DmTargetLinear = android::dm::DmTargetLinear;
 
-static bool CreateDmDeviceForPartition(DeviceMapper& dm, const LogicalPartition& partition) {
-    DmTable table;
-    for (const auto& extent : partition.extents) {
-        table.AddTarget(std::make_unique<DmTargetLinear>(extent));
-    }
-    if (!dm.CreateDevice(partition.name, table)) {
-        return false;
-    }
-    LINFO << "Created device-mapper device: " << partition.name;
-    return true;
-}
-
-bool CreateLogicalPartitions(const LogicalPartitionTable& table) {
-    DeviceMapper& dm = DeviceMapper::Instance();
-    for (const auto& partition : table.partitions) {
-        if (!CreateDmDeviceForPartition(dm, partition)) {
-            LOG(ERROR) << "could not create dm-linear device for partition: " << partition.name;
-            return false;
-        }
-    }
-    return true;
-}
-
-std::unique_ptr<LogicalPartitionTable> LoadPartitionsFromDeviceTree() {
-    return nullptr;
-}
-
 static bool CreateDmTable(const std::string& block_device, const LpMetadata& metadata,
                           const LpMetadataPartition& partition, DmTable* table) {
     uint64_t sector = 0;
@@ -106,6 +79,25 @@
     return true;
 }
 
+static bool CreateLogicalPartition(const std::string& block_device, const LpMetadata& metadata,
+                                   const LpMetadataPartition& partition, std::string* path) {
+    DeviceMapper& dm = DeviceMapper::Instance();
+
+    DmTable table;
+    if (!CreateDmTable(block_device, metadata, partition, &table)) {
+        return false;
+    }
+    std::string name = GetPartitionName(partition);
+    if (!dm.CreateDevice(name, table)) {
+        return false;
+    }
+    if (!dm.GetDmDevicePathByName(name, path)) {
+        return false;
+    }
+    LINFO << "Created logical partition " << name << " on device " << *path;
+    return true;
+}
+
 bool CreateLogicalPartitions(const std::string& block_device) {
     uint32_t slot = SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix());
     auto metadata = ReadMetadata(block_device.c_str(), slot);
@@ -113,23 +105,36 @@
         LOG(ERROR) << "Could not read partition table.";
         return true;
     }
-
-    DeviceMapper& dm = DeviceMapper::Instance();
     for (const auto& partition : metadata->partitions) {
-        DmTable table;
-        if (!CreateDmTable(block_device, *metadata.get(), partition, &table)) {
-            return false;
-        }
-        std::string name = GetPartitionName(partition);
-        if (!dm.CreateDevice(name, table)) {
-            return false;
-        }
         std::string path;
-        dm.GetDmDevicePathByName(partition.name, &path);
-        LINFO << "Created logical partition " << name << " on device " << path;
+        if (!CreateLogicalPartition(block_device, *metadata.get(), partition, &path)) {
+            LERROR << "Could not create logical partition: " << GetPartitionName(partition);
+            return false;
+        }
     }
     return true;
 }
 
+bool CreateLogicalPartition(const std::string& block_device, uint32_t metadata_slot,
+                            const std::string& partition_name, std::string* path) {
+    auto metadata = ReadMetadata(block_device.c_str(), metadata_slot);
+    if (!metadata) {
+        LOG(ERROR) << "Could not read partition table.";
+        return true;
+    }
+    for (const auto& partition : metadata->partitions) {
+        if (GetPartitionName(partition) == partition_name) {
+            return CreateLogicalPartition(block_device, *metadata.get(), partition, path);
+        }
+    }
+    LERROR << "Could not find any partition with name: " << partition_name;
+    return false;
+}
+
+bool DestroyLogicalPartition(const std::string& name) {
+    DeviceMapper& dm = DeviceMapper::Instance();
+    return dm.DeleteDevice(name);
+}
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/include/fs_mgr_dm_linear.h b/fs_mgr/include/fs_mgr_dm_linear.h
index 3b0c791..cac475c 100644
--- a/fs_mgr/include/fs_mgr_dm_linear.h
+++ b/fs_mgr/include/fs_mgr_dm_linear.h
@@ -37,30 +37,17 @@
 namespace android {
 namespace fs_mgr {
 
-struct LogicalPartition {
-    std::string name;
-    std::vector<android::dm::DmTargetLinear> extents;
-};
-
-struct LogicalPartitionTable {
-    // List of partitions in the partition table.
-    std::vector<LogicalPartition> partitions;
-};
-
-// Load a dm-linear table from the device tree if one is available; otherwise,
-// return null.
-std::unique_ptr<LogicalPartitionTable> LoadPartitionsFromDeviceTree();
-
-// Create device-mapper devices for the given partition table.
-//
-// On success, two devices nodes will be created for each partition, both
-// pointing to the same device:
-//   /dev/block/dm-<N> where N is a sequential ID assigned by device-mapper.
-//   /dev/block/dm-<name> where |name| is the partition name.
-//
-bool CreateLogicalPartitions(const LogicalPartitionTable& table);
 bool CreateLogicalPartitions(const std::string& block_device);
 
+// Create a block device for a single logical partition, given metadata and
+// the partition name. On success, a path to the partition's block device is
+// returned.
+bool CreateLogicalPartition(const std::string& block_device, uint32_t metadata_slot,
+                            const std::string& partition_name, std::string* path);
+
+// Destroy the block device for a logical partition, by name.
+bool DestroyLogicalPartition(const std::string& name);
+
 }  // namespace fs_mgr
 }  // namespace android
 
diff --git a/fs_mgr/libdm/dm_target.cpp b/fs_mgr/libdm/dm_target.cpp
index 20b26df..7c18267 100644
--- a/fs_mgr/libdm/dm_target.cpp
+++ b/fs_mgr/libdm/dm_target.cpp
@@ -111,5 +111,9 @@
     return base + " " + std::to_string(optional_args_.size()) + " " + optional;
 }
 
+std::string DmTargetAndroidVerity::GetParameterString() const {
+    return keyid_ + " " + block_device_;
+}
+
 }  // namespace dm
 }  // namespace android
diff --git a/fs_mgr/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index d5974f4..31863c8 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -128,6 +128,20 @@
     bool valid_;
 };
 
+class DmTargetAndroidVerity final : public DmTarget {
+  public:
+    DmTargetAndroidVerity(uint64_t start, uint64_t length, const std::string& block_device,
+                          const std::string& keyid)
+        : DmTarget(start, length), keyid_(keyid), block_device_(block_device) {}
+
+    std::string name() const override { return "android-verity"; }
+    std::string GetParameterString() const override;
+
+  private:
+    std::string keyid_;
+    std::string block_device_;
+};
+
 // This is the same as DmTargetVerity, but the table may be specified as a raw
 // string. This code exists only for fs_mgr_verity and should be avoided. Use
 // DmTargetVerity for new code instead.
diff --git a/fs_mgr/liblp/images.cpp b/fs_mgr/liblp/images.cpp
index 93c5618..a361a5d 100644
--- a/fs_mgr/liblp/images.cpp
+++ b/fs_mgr/liblp/images.cpp
@@ -57,10 +57,9 @@
 
 bool WriteToImageFile(int fd, const LpMetadata& input) {
     std::string geometry = SerializeGeometry(input.geometry);
-    std::string padding(LP_METADATA_GEOMETRY_SIZE - geometry.size(), '\0');
     std::string metadata = SerializeMetadata(input);
 
-    std::string everything = geometry + padding + metadata;
+    std::string everything = geometry + metadata;
 
     if (!android::base::WriteFully(fd, everything.data(), everything.size())) {
         PERROR << __PRETTY_FUNCTION__ << "write " << everything.size() << " bytes failed";
@@ -83,26 +82,36 @@
 // to do this when the data pointers are all in one place.
 class SparseBuilder {
   public:
-    explicit SparseBuilder(const LpMetadata& metadata);
+    SparseBuilder(const LpMetadata& metadata, uint32_t block_size,
+                  const std::map<std::string, std::string>& images);
 
     bool Build();
     bool Export(const char* file);
     bool IsValid() const { return file_ != nullptr; }
 
   private:
-    bool AddData(const std::string& blob, uint32_t block);
+    bool AddData(const std::string& blob, uint64_t sector);
+    bool AddPartitionImage(const LpMetadataPartition& partition, const std::string& file);
+    int OpenImageFile(const std::string& file);
+    bool SectorToBlock(uint64_t sector, uint32_t* block);
 
     const LpMetadata& metadata_;
     const LpMetadataGeometry& geometry_;
+    uint32_t block_size_;
     std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)> file_;
-    std::string geometry_blob_;
-    std::string metadata_blob_;
+    std::string primary_blob_;
+    std::string backup_blob_;
+    std::map<std::string, std::string> images_;
+    std::vector<android::base::unique_fd> temp_fds_;
 };
 
-SparseBuilder::SparseBuilder(const LpMetadata& metadata)
+SparseBuilder::SparseBuilder(const LpMetadata& metadata, uint32_t block_size,
+                             const std::map<std::string, std::string>& images)
     : metadata_(metadata),
       geometry_(metadata.geometry),
-      file_(sparse_file_new(LP_SECTOR_SIZE, geometry_.block_device_size), sparse_file_destroy) {}
+      block_size_(block_size),
+      file_(sparse_file_new(block_size_, geometry_.block_device_size), sparse_file_destroy),
+      images_(images) {}
 
 bool SparseBuilder::Export(const char* file) {
     android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644));
@@ -119,7 +128,11 @@
     return true;
 }
 
-bool SparseBuilder::AddData(const std::string& blob, uint32_t block) {
+bool SparseBuilder::AddData(const std::string& blob, uint64_t sector) {
+    uint32_t block;
+    if (!SectorToBlock(sector, &block)) {
+        return false;
+    }
     void* data = const_cast<char*>(blob.data());
     int ret = sparse_file_add_data(file_.get(), data, blob.size(), block);
     if (ret != 0) {
@@ -129,22 +142,53 @@
     return true;
 }
 
-bool SparseBuilder::Build() {
-    geometry_blob_ = SerializeGeometry(geometry_);
-    geometry_blob_.resize(LP_METADATA_GEOMETRY_SIZE);
-    if (!AddData(geometry_blob_, 0)) {
+bool SparseBuilder::SectorToBlock(uint64_t sector, uint32_t* block) {
+    // The caller must ensure that the metadata has an alignment that is a
+    // multiple of the block size. liblp will take care of the rest, ensuring
+    // that all partitions are on an aligned boundary. Therefore all writes
+    // should be block-aligned, and if they are not, the table was misconfigured.
+    // Note that the default alignment is 1MiB, which is a multiple of the
+    // default block size (4096).
+    if ((sector * LP_SECTOR_SIZE) % block_size_ != 0) {
+        LERROR << "sector " << sector << " is not aligned to block size " << block_size_;
         return false;
     }
+    *block = (sector * LP_SECTOR_SIZE) / block_size_;
+    return true;
+}
+
+bool SparseBuilder::Build() {
+    std::string geometry_blob = SerializeGeometry(geometry_);
+    std::string metadata_blob = SerializeMetadata(metadata_);
+    metadata_blob.resize(geometry_.metadata_max_size);
+
+    std::string all_metadata;
+    for (size_t i = 0; i < geometry_.metadata_slot_count; i++) {
+        all_metadata += metadata_blob;
+    }
 
     // Metadata immediately follows geometry, and we write the same metadata
-    // to all slots.
-    uint32_t metadata_block = LP_METADATA_GEOMETRY_SIZE / LP_SECTOR_SIZE;
-    metadata_blob_ = SerializeMetadata(metadata_);
-    for (size_t i = 0; i < geometry_.metadata_slot_count; i++) {
-        if (!AddData(metadata_blob_, metadata_block)) {
+    // to all slots. Note that we don't bother trying to write skip chunks
+    // here since it's a small amount of data.
+    primary_blob_ = geometry_blob + all_metadata;
+    if (!AddData(primary_blob_, 0)) {
+        return false;
+    }
+
+    for (const auto& partition : metadata_.partitions) {
+        auto iter = images_.find(GetPartitionName(partition));
+        if (iter == images_.end()) {
+            continue;
+        }
+        if (!AddPartitionImage(partition, iter->second)) {
             return false;
         }
-        metadata_block += geometry_.metadata_max_size / LP_SECTOR_SIZE;
+        images_.erase(iter);
+    }
+
+    if (!images_.empty()) {
+        LERROR << "Partition image was specified but no partition was found.";
+        return false;
     }
 
     // The backup area contains all metadata slots, and then geometry. Similar
@@ -152,31 +196,151 @@
     int64_t backup_offset = GetBackupMetadataOffset(geometry_, 0);
     uint64_t backups_start = geometry_.block_device_size + backup_offset;
     uint64_t backup_sector = backups_start / LP_SECTOR_SIZE;
-    for (size_t i = 0; i < geometry_.metadata_slot_count; i++) {
-        if (!AddData(metadata_blob_, backup_sector)) {
-            return false;
-        }
-        backup_sector += geometry_.metadata_max_size / LP_SECTOR_SIZE;
-    }
-    if (!AddData(geometry_blob_, backup_sector)) {
+
+    backup_blob_ = all_metadata + geometry_blob;
+    if (!AddData(backup_blob_, backup_sector)) {
         return false;
     }
     return true;
 }
 
-bool WriteToSparseFile(const char* file, const LpMetadata& metadata) {
-    uint64_t num_blocks =
-            AlignTo(metadata.geometry.block_device_size, LP_SECTOR_SIZE) / LP_SECTOR_SIZE;
+static inline bool HasFillValue(uint32_t* buffer, size_t count) {
+    uint32_t fill_value = buffer[0];
+    for (size_t i = 1; i < count; i++) {
+        if (fill_value != buffer[i]) {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool SparseBuilder::AddPartitionImage(const LpMetadataPartition& partition,
+                                      const std::string& file) {
+    if (partition.num_extents != 1) {
+        LERROR << "Partition for new tables should not have more than one extent: "
+               << GetPartitionName(partition);
+        return false;
+    }
+
+    const LpMetadataExtent& extent = metadata_.extents[partition.first_extent_index];
+    if (extent.target_type != LP_TARGET_TYPE_LINEAR) {
+        LERROR << "Partition should only have linear extents: " << GetPartitionName(partition);
+        return false;
+    }
+
+    int fd = OpenImageFile(file);
+    if (fd < 0) {
+        LERROR << "Could not open image for partition: " << GetPartitionName(partition);
+        return false;
+    }
+
+    // Make sure the image does not exceed the partition size.
+    uint64_t file_length;
+    if (!GetDescriptorSize(fd, &file_length)) {
+        LERROR << "Could not compute image size";
+        return false;
+    }
+    if (file_length > extent.num_sectors * LP_SECTOR_SIZE) {
+        LERROR << "Image for partition '" << GetPartitionName(partition)
+               << "' is greater than its size";
+        return false;
+    }
+    if (SeekFile64(fd, 0, SEEK_SET)) {
+        PERROR << "lseek failed";
+        return false;
+    }
+
+    uint32_t output_block;
+    if (!SectorToBlock(extent.target_data, &output_block)) {
+        return false;
+    }
+
+    uint64_t pos = 0;
+    uint64_t remaining = file_length;
+    while (remaining) {
+        uint32_t buffer[block_size_ / sizeof(uint32_t)];
+        size_t read_size = remaining >= sizeof(buffer) ? sizeof(buffer) : size_t(remaining);
+        if (!android::base::ReadFully(fd, buffer, sizeof(buffer))) {
+            PERROR << "read failed";
+            return false;
+        }
+        if (read_size != sizeof(buffer) || !HasFillValue(buffer, read_size / sizeof(uint32_t))) {
+            int rv = sparse_file_add_fd(file_.get(), fd, pos, read_size, output_block);
+            if (rv) {
+                LERROR << "sparse_file_add_fd failed with code: " << rv;
+                return false;
+            }
+        } else {
+            int rv = sparse_file_add_fill(file_.get(), buffer[0], read_size, output_block);
+            if (rv) {
+                LERROR << "sparse_file_add_fill failed with code: " << rv;
+                return false;
+            }
+        }
+        pos += read_size;
+        remaining -= read_size;
+        output_block++;
+    }
+
+    return true;
+}
+
+int SparseBuilder::OpenImageFile(const std::string& file) {
+    android::base::unique_fd source_fd(open(file.c_str(), O_RDONLY));
+    if (source_fd < 0) {
+        PERROR << "open image file failed: " << file;
+        return -1;
+    }
+
+    std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)> source(
+            sparse_file_import(source_fd, true, true), sparse_file_destroy);
+    if (!source) {
+        int fd = source_fd.get();
+        temp_fds_.push_back(std::move(source_fd));
+        return fd;
+    }
+
+    char temp_file[PATH_MAX];
+    snprintf(temp_file, sizeof(temp_file), "%s/imageXXXXXX", P_tmpdir);
+    android::base::unique_fd temp_fd(mkstemp(temp_file));
+    if (temp_fd < 0) {
+        PERROR << "mkstemp failed";
+        return -1;
+    }
+    if (unlink(temp_file) < 0) {
+        PERROR << "unlink failed";
+        return -1;
+    }
+
+    // We temporarily unsparse the file, rather than try to merge its chunks.
+    int rv = sparse_file_write(source.get(), temp_fd, false, false, false);
+    if (rv) {
+        LERROR << "sparse_file_write failed with code: " << rv;
+        return -1;
+    }
+    temp_fds_.push_back(std::move(temp_fd));
+    return temp_fds_.back().get();
+}
+
+bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size,
+                       const std::map<std::string, std::string>& images) {
+    if (block_size % LP_SECTOR_SIZE != 0) {
+        LERROR << "Block size must be a multiple of the sector size, " << LP_SECTOR_SIZE;
+        return false;
+    }
+    if (metadata.geometry.block_device_size % block_size != 0) {
+        LERROR << "Device size must be a multiple of the block size, " << block_size;
+        return false;
+    }
+    uint64_t num_blocks = metadata.geometry.block_device_size % block_size;
     if (num_blocks >= UINT_MAX) {
-        // libsparse counts blocks in unsigned 32-bit integers, but our block
-        // size is rather low (512 bytes), since we operate in sectors.
-        // Therefore the maximum block device size we can represent with a
-        // sparse file is 2TB for now.
+        // libsparse counts blocks in unsigned 32-bit integers, so we check to
+        // make sure we're not going to overflow.
         LERROR << "Block device is too large to encode with libsparse.";
         return false;
     }
 
-    SparseBuilder builder(metadata);
+    SparseBuilder builder(metadata, block_size, images);
     if (!builder.IsValid()) {
         LERROR << "Could not allocate sparse file of size " << metadata.geometry.block_device_size;
         return false;
@@ -184,7 +348,6 @@
     if (!builder.Build()) {
         return false;
     }
-
     return builder.Export(file);
 }
 
diff --git a/fs_mgr/liblp/include/liblp/liblp.h b/fs_mgr/liblp/include/liblp/liblp.h
index c8d34d9..627aa8c 100644
--- a/fs_mgr/liblp/include/liblp/liblp.h
+++ b/fs_mgr/liblp/include/liblp/liblp.h
@@ -20,6 +20,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <map>
 #include <memory>
 #include <string>
 
@@ -59,7 +60,8 @@
 
 // Read/Write logical partition metadata to an image file, for diagnostics or
 // flashing.
-bool WriteToSparseFile(const char* file, const LpMetadata& metadata);
+bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size,
+                       const std::map<std::string, std::string>& images);
 bool WriteToImageFile(const char* file, const LpMetadata& metadata);
 std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file);
 
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index 74c03bf..156319b 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -34,7 +34,10 @@
     LpMetadataGeometry geometry = input;
     memset(geometry.checksum, 0, sizeof(geometry.checksum));
     SHA256(&geometry, sizeof(geometry), geometry.checksum);
-    return std::string(reinterpret_cast<const char*>(&geometry), sizeof(geometry));
+
+    std::string blob(reinterpret_cast<const char*>(&geometry), sizeof(geometry));
+    blob.resize(LP_METADATA_GEOMETRY_SIZE);
+    return blob;
 }
 
 static bool CompareGeometry(const LpMetadataGeometry& g1, const LpMetadataGeometry& g2) {
diff --git a/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp
index 5e11c84..45a81af 100644
--- a/fs_mgr/tools/dmctl.cpp
+++ b/fs_mgr/tools/dmctl.cpp
@@ -40,6 +40,7 @@
 using DmTarget = ::android::dm::DmTarget;
 using DmTargetLinear = ::android::dm::DmTargetLinear;
 using DmTargetZero = ::android::dm::DmTargetZero;
+using DmTargetAndroidVerity = ::android::dm::DmTargetAndroidVerity;
 using DmTargetTypeInfo = ::android::dm::DmTargetTypeInfo;
 using DmBlockDevice = ::android::dm::DeviceMapper::DmBlockDevice;
 
@@ -96,6 +97,16 @@
             }
             return std::make_unique<DmTargetLinear>(start_sector, num_sectors, block_device,
                                                     physical_sector);
+        } else if (target_type == "android-verity") {
+            if (!HasArgs(2)) {
+                std::cerr << "Expected \"android-verity\" <public-key-id> <block_device>"
+                          << std::endl;
+                return nullptr;
+            }
+            std::string keyid = NextArg();
+            std::string block_device = NextArg();
+            return std::make_unique<DmTargetAndroidVerity>(start_sector, num_sectors, keyid,
+                                                           block_device);
         } else {
             std::cerr << "Unrecognized target type: " << target_type << std::endl;
             return nullptr;
@@ -132,11 +143,11 @@
     while (arg_index < argc && argv[arg_index][0] == '-') {
         if (strcmp(argv[arg_index], "-ro") == 0) {
             table.set_readonly(true);
+            arg_index++;
         } else {
             std::cerr << "Unrecognized option: " << argv[arg_index] << std::endl;
             return -EINVAL;
         }
-        arg_index++;
     }
 
     // Parse everything else as target information.
diff --git a/gatekeeperd/OWNERS b/gatekeeperd/OWNERS
new file mode 100644
index 0000000..9c99c6e
--- /dev/null
+++ b/gatekeeperd/OWNERS
@@ -0,0 +1,2 @@
+swillden@google.com
+jdanis@google.com
diff --git a/init/Android.bp b/init/Android.bp
index 625fb94..c02b8d1 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -104,11 +104,10 @@
         "devices.cpp",
         "epoll.cpp",
         "firmware_handler.cpp",
+        "first_stage_mount.cpp",
         "import_parser.cpp",
         "init.cpp",
-        "init_first_stage.cpp",
         "keychords.cpp",
-        "log.cpp",
         "parser.cpp",
         "persistent_properties.cpp",
         "persistent_properties.proto",
@@ -180,6 +179,7 @@
         "service_test.cpp",
         "subcontext_test.cpp",
         "tokenizer_test.cpp",
+        "ueventd_parser_test.cpp",
         "ueventd_test.cpp",
         "util_test.cpp",
     ],
diff --git a/init/action_parser.cpp b/init/action_parser.cpp
index 8a4b518..1481162 100644
--- a/init/action_parser.cpp
+++ b/init/action_parser.cpp
@@ -60,7 +60,7 @@
     prop_name.erase(equal_pos);
 
     if (!IsActionableProperty(subcontext, prop_name)) {
-        return Error() << "unexported property tigger found: " << prop_name;
+        return Error() << "unexported property trigger found: " << prop_name;
     }
 
     if (auto [it, inserted] = property_triggers->emplace(prop_name, prop_value); !inserted) {
diff --git a/init/devices.cpp b/init/devices.cpp
index ada1e28..ed4a739 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -31,7 +31,6 @@
 #include <selinux/selinux.h>
 
 #include "selinux.h"
-#include "ueventd.h"
 #include "util.h"
 
 #ifdef _INIT_INIT_H
diff --git a/init/devices.h b/init/devices.h
index 9224fcd..0be660f 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -35,6 +35,8 @@
 
 class Permissions {
   public:
+    friend void TestPermissions(const Permissions& expected, const Permissions& test);
+
     Permissions(const std::string& name, mode_t perm, uid_t uid, gid_t gid);
 
     bool Match(const std::string& path) const;
@@ -57,6 +59,8 @@
 
 class SysfsPermissions : public Permissions {
   public:
+    friend void TestSysfsPermissions(const SysfsPermissions& expected, const SysfsPermissions& test);
+
     SysfsPermissions(const std::string& name, const std::string& attribute, mode_t perm, uid_t uid,
                      gid_t gid)
         : Permissions(name, perm, uid, gid), attribute_(attribute) {}
@@ -71,16 +75,24 @@
 class Subsystem {
   public:
     friend class SubsystemParser;
+    friend void TestSubsystems(const Subsystem& expected, const Subsystem& test);
+
+    enum DevnameSource {
+        DEVNAME_UEVENT_DEVNAME,
+        DEVNAME_UEVENT_DEVPATH,
+    };
 
     Subsystem() {}
-    Subsystem(std::string name) : name_(std::move(name)) {}
+    Subsystem(const std::string& name) : name_(name) {}
+    Subsystem(const std::string& name, DevnameSource source, const std::string& dir_name)
+        : name_(name), devname_source_(source), dir_name_(dir_name) {}
 
     // Returns the full path for a uevent of a device that is a member of this subsystem,
     // according to the rules parsed from ueventd.rc
     std::string ParseDevPath(const Uevent& uevent) const {
-        std::string devname = devname_source_ == DevnameSource::DEVNAME_UEVENT_DEVNAME
-                                  ? uevent.device_name
-                                  : android::base::Basename(uevent.path);
+        std::string devname = devname_source_ == DEVNAME_UEVENT_DEVNAME
+                                      ? uevent.device_name
+                                      : android::base::Basename(uevent.path);
 
         return dir_name_ + "/" + devname;
     }
@@ -88,14 +100,9 @@
     bool operator==(const std::string& string_name) const { return name_ == string_name; }
 
   private:
-    enum class DevnameSource {
-        DEVNAME_UEVENT_DEVNAME,
-        DEVNAME_UEVENT_DEVPATH,
-    };
-
     std::string name_;
+    DevnameSource devname_source_ = DEVNAME_UEVENT_DEVNAME;
     std::string dir_name_ = "/dev";
-    DevnameSource devname_source_;
 };
 
 class DeviceHandler {
diff --git a/init/init_first_stage.cpp b/init/first_stage_mount.cpp
similarity index 92%
rename from init/init_first_stage.cpp
rename to init/first_stage_mount.cpp
index 2bc9f3a..8ded873 100644
--- a/init/init_first_stage.cpp
+++ b/init/first_stage_mount.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "init_first_stage.h"
+#include "first_stage_mount.h"
 
 #include <stdlib.h>
 #include <unistd.h>
@@ -40,7 +40,6 @@
 #include "util.h"
 
 using android::base::Timer;
-using android::fs_mgr::LogicalPartitionTable;
 
 namespace android {
 namespace init {
@@ -75,7 +74,6 @@
     bool need_dm_verity_;
 
     std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> device_tree_fstab_;
-    std::unique_ptr<LogicalPartitionTable> dm_linear_table_;
     std::string lp_metadata_partition_;
     std::vector<fstab_rec*> mount_fstab_recs_;
     std::set<std::string> required_devices_partition_names_;
@@ -127,11 +125,12 @@
     if (checked) {
         return enabled;
     }
-    import_kernel_cmdline(false, [](const std::string& key, const std::string& value, bool in_qemu) {
-        if (key == "androidboot.logical_partitions" && value == "1") {
-            enabled = true;
-        }
-    });
+    import_kernel_cmdline(false,
+                          [](const std::string& key, const std::string& value, bool in_qemu) {
+                              if (key == "androidboot.logical_partitions" && value == "1") {
+                                  enabled = true;
+                              }
+                          });
     checked = true;
     return enabled;
 }
@@ -150,14 +149,10 @@
         LOG(INFO) << "Failed to read fstab from device tree";
     }
 
-    if (IsDmLinearEnabled()) {
-        dm_linear_table_ = android::fs_mgr::LoadPartitionsFromDeviceTree();
-    }
-
     auto boot_devices = fs_mgr_get_boot_devices();
-    device_handler_ =
-        std::make_unique<DeviceHandler>(std::vector<Permissions>{}, std::vector<SysfsPermissions>{},
-                                        std::vector<Subsystem>{}, std::move(boot_devices), false);
+    device_handler_ = std::make_unique<DeviceHandler>(
+            std::vector<Permissions>{}, std::vector<SysfsPermissions>{}, std::vector<Subsystem>{},
+            std::move(boot_devices), false);
 }
 
 std::unique_ptr<FirstStageMount> FirstStageMount::Create() {
@@ -195,15 +190,6 @@
     }
 
     required_devices_partition_names_.emplace(LP_METADATA_PARTITION_NAME);
-
-    if (dm_linear_table_) {
-        for (const auto& partition : dm_linear_table_->partitions) {
-            for (const auto& extent : partition.extents) {
-                const std::string& partition_name = android::base::Basename(extent.block_device());
-                required_devices_partition_names_.emplace(partition_name);
-            }
-        }
-    }
     return true;
 }
 
@@ -272,11 +258,6 @@
                    << LP_METADATA_PARTITION_NAME;
         return false;
     }
-    if (dm_linear_table_) {
-        if (!android::fs_mgr::CreateLogicalPartitions(*dm_linear_table_.get())) {
-            return false;
-        }
-    }
     return android::fs_mgr::CreateLogicalPartitions(lp_metadata_partition_);
 }
 
@@ -456,12 +437,19 @@
 bool FirstStageMountVBootV2::GetDmVerityDevices() {
     need_dm_verity_ = false;
 
+    std::set<std::string> logical_partitions;
+
     // fstab_rec->blk_device has A/B suffix.
     for (auto fstab_rec : mount_fstab_recs_) {
         if (fs_mgr_is_avb(fstab_rec)) {
             need_dm_verity_ = true;
         }
-        required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
+        if (fs_mgr_is_logical(fstab_rec)) {
+            // Don't try to find logical partitions via uevent regeneration.
+            logical_partitions.emplace(basename(fstab_rec->blk_device));
+        } else {
+            required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
+        }
     }
 
     // libavb verifies AVB metadata on all verified partitions at once.
@@ -476,11 +464,15 @@
         std::vector<std::string> partitions = android::base::Split(device_tree_vbmeta_parts_, ",");
         std::string ab_suffix = fs_mgr_get_slot_suffix();
         for (const auto& partition : partitions) {
+            std::string partition_name = partition + ab_suffix;
+            if (logical_partitions.count(partition_name)) {
+                continue;
+            }
             // required_devices_partition_names_ is of type std::set so it's not an issue
             // to emplace a partition twice. e.g., /vendor might be in both places:
             //   - device_tree_vbmeta_parts_ = "vbmeta,boot,system,vendor"
             //   - mount_fstab_recs_: /vendor_a
-            required_devices_partition_names_.emplace(partition + ab_suffix);
+            required_devices_partition_names_.emplace(partition_name);
         }
     }
     return true;
@@ -493,7 +485,7 @@
     // as it finds them, so this must happen first.
     if (!uevent.partition_name.empty() &&
         required_devices_partition_names_.find(uevent.partition_name) !=
-            required_devices_partition_names_.end()) {
+                required_devices_partition_names_.end()) {
         // GetBlockDeviceSymlinks() will return three symlinks at most, depending on
         // the content of uevent. by-name symlink will be at [0] if uevent->partition_name
         // is not empty. e.g.,
@@ -501,7 +493,7 @@
         //   - /dev/block/platform/soc.0/f9824900.sdhci/mmcblk0p1
         std::vector<std::string> links = device_handler_->GetBlockDeviceSymlinks(uevent);
         if (!links.empty()) {
-            auto[it, inserted] = by_name_symlink_map_.emplace(uevent.partition_name, links[0]);
+            auto [it, inserted] = by_name_symlink_map_.emplace(uevent.partition_name, links[0]);
             if (!inserted) {
                 LOG(ERROR) << "Partition '" << uevent.partition_name
                            << "' already existed in the by-name symlink map with a value of '"
@@ -517,7 +509,7 @@
     if (fs_mgr_is_avb(fstab_rec)) {
         if (!InitAvbHandle()) return false;
         SetUpAvbHashtreeResult hashtree_result =
-            avb_handle_->SetUpAvbHashtree(fstab_rec, false /* wait_for_verity_dev */);
+                avb_handle_->SetUpAvbHashtree(fstab_rec, false /* wait_for_verity_dev */);
         switch (hashtree_result) {
             case SetUpAvbHashtreeResult::kDisabled:
                 return true;  // Returns true to mount the partition.
@@ -594,7 +586,7 @@
     }
 
     FsManagerAvbUniquePtr avb_handle =
-        FsManagerAvbHandle::Open(std::move(avb_first_mount.by_name_symlink_map_));
+            FsManagerAvbHandle::Open(std::move(avb_first_mount.by_name_symlink_map_));
     if (!avb_handle) {
         PLOG(ERROR) << "Failed to open FsManagerAvbHandle for INIT_AVB_VERSION";
         return;
diff --git a/init/init_first_stage.h b/init/first_stage_mount.h
similarity index 91%
rename from init/init_first_stage.h
rename to init/first_stage_mount.h
index c7a3867..21d87fd 100644
--- a/init/init_first_stage.h
+++ b/init/first_stage_mount.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef _INIT_FIRST_STAGE_H
-#define _INIT_FIRST_STAGE_H
+#pragma once
 
 namespace android {
 namespace init {
@@ -25,5 +24,3 @@
 
 }  // namespace init
 }  // namespace android
-
-#endif
diff --git a/init/init.cpp b/init/init.cpp
index 686cd6e..6569871 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -48,10 +48,9 @@
 
 #include "action_parser.h"
 #include "epoll.h"
+#include "first_stage_mount.h"
 #include "import_parser.h"
-#include "init_first_stage.h"
 #include "keychords.h"
-#include "log.h"
 #include "property_service.h"
 #include "reboot.h"
 #include "security.h"
@@ -582,6 +581,34 @@
     }
 }
 
+static void InitAborter(const char* abort_message) {
+    // When init forks, it continues to use this aborter for LOG(FATAL), but we want children to
+    // simply abort instead of trying to reboot the system.
+    if (getpid() != 1) {
+        android::base::DefaultAborter(abort_message);
+        return;
+    }
+
+    RebootSystem(ANDROID_RB_RESTART2, "bootloader");
+}
+
+static void InitKernelLogging(char* argv[]) {
+    // Make stdin/stdout/stderr all point to /dev/null.
+    int fd = open("/sys/fs/selinux/null", O_RDWR);
+    if (fd == -1) {
+        int saved_errno = errno;
+        android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
+        errno = saved_errno;
+        PLOG(FATAL) << "Couldn't open /sys/fs/selinux/null";
+    }
+    dup2(fd, 0);
+    dup2(fd, 1);
+    dup2(fd, 2);
+    if (fd > 2) close(fd);
+
+    android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
+}
+
 int main(int argc, char** argv) {
     if (!strcmp(basename(argv[0]), "ueventd")) {
         return ueventd_main(argc, argv);
@@ -592,7 +619,7 @@
     }
 
     if (argc > 1 && !strcmp(argv[1], "subcontext")) {
-        InitKernelLogging(argv);
+        android::base::InitLogging(argv, &android::base::KernelLogger);
         const BuiltinFunctionMap function_map;
         return SubcontextMain(argc, argv, &function_map);
     }
diff --git a/init/log.cpp b/init/log.cpp
deleted file mode 100644
index 6198fc2..0000000
--- a/init/log.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "log.h"
-
-#include <fcntl.h>
-#include <linux/audit.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <android-base/logging.h>
-#include <cutils/android_reboot.h>
-#include <selinux/selinux.h>
-
-#include "reboot.h"
-
-namespace android {
-namespace init {
-
-static void InitAborter(const char* abort_message) {
-    // When init forks, it continues to use this aborter for LOG(FATAL), but we want children to
-    // simply abort instead of trying to reboot the system.
-    if (getpid() != 1) {
-        android::base::DefaultAborter(abort_message);
-        return;
-    }
-
-    // DoReboot() does a lot to try to shutdown the system cleanly.  If something happens to call
-    // LOG(FATAL) in the shutdown path, we want to catch this and immediately use the syscall to
-    // reboot instead of recursing here.
-    static bool has_aborted = false;
-    if (!has_aborted) {
-        has_aborted = true;
-        // Do not queue "shutdown" trigger since we want to shutdown immediately and it's not likely
-        // that we can even run the ActionQueue at this point.
-        DoReboot(ANDROID_RB_RESTART2, "reboot", "bootloader", false);
-    } else {
-        RebootSystem(ANDROID_RB_RESTART2, "bootloader");
-    }
-}
-
-void InitKernelLogging(char* argv[]) {
-    // Make stdin/stdout/stderr all point to /dev/null.
-    int fd = open("/sys/fs/selinux/null", O_RDWR);
-    if (fd == -1) {
-        int saved_errno = errno;
-        android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
-        errno = saved_errno;
-        PLOG(FATAL) << "Couldn't open /sys/fs/selinux/null";
-    }
-    dup2(fd, 0);
-    dup2(fd, 1);
-    dup2(fd, 2);
-    if (fd > 2) close(fd);
-
-    android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
-}
-
-int selinux_klog_callback(int type, const char *fmt, ...) {
-    android::base::LogSeverity severity = android::base::ERROR;
-    if (type == SELINUX_WARNING) {
-        severity = android::base::WARNING;
-    } else if (type == SELINUX_INFO) {
-        severity = android::base::INFO;
-    }
-    char buf[1024];
-    va_list ap;
-    va_start(ap, fmt);
-    vsnprintf(buf, sizeof(buf), fmt, ap);
-    va_end(ap);
-    android::base::KernelLogger(android::base::MAIN, severity, "selinux", nullptr, 0, buf);
-    return 0;
-}
-
-}  // namespace init
-}  // namespace android
diff --git a/init/log.h b/init/log.h
deleted file mode 100644
index 5a4eba6..0000000
--- a/init/log.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _INIT_LOG_H_
-#define _INIT_LOG_H_
-
-#include <sys/cdefs.h>
-
-namespace android {
-namespace init {
-
-void InitKernelLogging(char* argv[]);
-
-int selinux_klog_callback(int level, const char* fmt, ...) __printflike(2, 3);
-
-}  // namespace init
-}  // namespace android
-
-#endif
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 0ba5c4a..94f206e 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -59,7 +59,6 @@
 #include <android-base/unique_fd.h>
 #include <selinux/android.h>
 
-#include "log.h"
 #include "util.h"
 
 using android::base::ParseInt;
@@ -448,10 +447,26 @@
     selinux_android_restorecon("/sbin/sload.f2fs", 0);
 }
 
+int SelinuxKlogCallback(int type, const char* fmt, ...) {
+    android::base::LogSeverity severity = android::base::ERROR;
+    if (type == SELINUX_WARNING) {
+        severity = android::base::WARNING;
+    } else if (type == SELINUX_INFO) {
+        severity = android::base::INFO;
+    }
+    char buf[1024];
+    va_list ap;
+    va_start(ap, fmt);
+    vsnprintf(buf, sizeof(buf), fmt, ap);
+    va_end(ap);
+    android::base::KernelLogger(android::base::MAIN, severity, "selinux", nullptr, 0, buf);
+    return 0;
+}
+
 // This function sets up SELinux logging to be written to kmsg, to match init's logging.
 void SelinuxSetupKernelLogging() {
     selinux_callback cb;
-    cb.func_log = selinux_klog_callback;
+    cb.func_log = SelinuxKlogCallback;
     selinux_set_callback(SELINUX_CB_LOG, cb);
 }
 
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index 6809445..cd45a3f 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -36,7 +36,6 @@
 
 #include "devices.h"
 #include "firmware_handler.h"
-#include "log.h"
 #include "selinux.h"
 #include "uevent_listener.h"
 #include "ueventd_parser.h"
@@ -223,7 +222,7 @@
      */
     umask(000);
 
-    InitKernelLogging(argv);
+    android::base::InitLogging(argv, &android::base::KernelLogger);
 
     LOG(INFO) << "ueventd started!";
 
@@ -240,7 +239,8 @@
         auto hardware = android::base::GetProperty("ro.hardware", "");
 
         auto ueventd_configuration =
-                ParseConfig({"/ueventd.rc", "/vendor/ueventd.rc", "/odm/ueventd.rc", hardware});
+                ParseConfig({"/ueventd.rc", "/vendor/ueventd.rc", "/odm/ueventd.rc",
+                             "/ueventd." + hardware + ".rc"});
 
         device_handler = DeviceHandler{std::move(ueventd_configuration.dev_permissions),
                                        std::move(ueventd_configuration.sysfs_permissions),
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index c114ec7..54b0d16 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -117,11 +117,11 @@
 
 Result<Success> SubsystemParser::ParseDevName(std::vector<std::string>&& args) {
     if (args[1] == "uevent_devname") {
-        subsystem_.devname_source_ = Subsystem::DevnameSource::DEVNAME_UEVENT_DEVNAME;
+        subsystem_.devname_source_ = Subsystem::DEVNAME_UEVENT_DEVNAME;
         return Success();
     }
     if (args[1] == "uevent_devpath") {
-        subsystem_.devname_source_ = Subsystem::DevnameSource::DEVNAME_UEVENT_DEVPATH;
+        subsystem_.devname_source_ = Subsystem::DEVNAME_UEVENT_DEVPATH;
         return Success();
     }
 
diff --git a/init/ueventd_parser_test.cpp b/init/ueventd_parser_test.cpp
new file mode 100644
index 0000000..31208b9
--- /dev/null
+++ b/init/ueventd_parser_test.cpp
@@ -0,0 +1,224 @@
+/*
+ * 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 "ueventd_parser.h"
+
+#include <android-base/test_utils.h>
+#include <gtest/gtest.h>
+#include <private/android_filesystem_config.h>
+
+namespace android {
+namespace init {
+
+void TestSubsystems(const Subsystem& expected, const Subsystem& test) {
+    EXPECT_EQ(expected.name_, test.name_);
+    EXPECT_EQ(expected.devname_source_, test.devname_source_) << expected.name_;
+    EXPECT_EQ(expected.dir_name_, test.dir_name_) << expected.name_;
+}
+
+void TestPermissions(const Permissions& expected, const Permissions& test) {
+    EXPECT_EQ(expected.name_, test.name_);
+    EXPECT_EQ(expected.perm_, test.perm_) << expected.name_;
+    EXPECT_EQ(expected.uid_, test.uid_) << expected.name_;
+    EXPECT_EQ(expected.gid_, test.gid_) << expected.name_;
+    EXPECT_EQ(expected.prefix_, test.prefix_) << expected.name_;
+    EXPECT_EQ(expected.wildcard_, test.wildcard_) << expected.name_;
+}
+
+void TestSysfsPermissions(const SysfsPermissions& expected, const SysfsPermissions& test) {
+    TestPermissions(expected, test);
+    EXPECT_EQ(expected.attribute_, test.attribute_);
+}
+
+template <typename T, typename F>
+void TestVector(const T& expected, const T& test, F function) {
+    ASSERT_EQ(expected.size(), test.size());
+    auto expected_it = expected.begin();
+    auto test_it = test.begin();
+
+    for (; expected_it != expected.end(); ++expected_it, ++test_it) {
+        function(*expected_it, *test_it);
+    }
+}
+
+void TestUeventdFile(const std::string& content, const UeventdConfiguration& expected) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    ASSERT_TRUE(android::base::WriteStringToFd(content, tf.fd));
+
+    auto result = ParseConfig({tf.path});
+
+    TestVector(expected.subsystems, result.subsystems, TestSubsystems);
+    TestVector(expected.sysfs_permissions, result.sysfs_permissions, TestSysfsPermissions);
+    TestVector(expected.dev_permissions, result.dev_permissions, TestPermissions);
+    EXPECT_EQ(expected.firmware_directories, result.firmware_directories);
+}
+
+TEST(ueventd_parser, EmptyFile) {
+    TestUeventdFile("", {});
+}
+
+TEST(ueventd_parser, Subsystems) {
+    auto ueventd_file = R"(
+subsystem test_devname
+    devname uevent_devname
+
+subsystem test_devpath_no_dirname
+    devname uevent_devpath
+
+subsystem test_devname2
+    devname uevent_devname
+
+subsystem test_devpath_dirname
+    devname uevent_devpath
+    dirname /dev/graphics
+)";
+
+    auto subsystems = std::vector<Subsystem>{
+            {"test_devname", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"},
+            {"test_devpath_no_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev"},
+            {"test_devname2", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"},
+            {"test_devpath_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev/graphics"}};
+
+    TestUeventdFile(ueventd_file, {subsystems, {}, {}, {}});
+}
+
+TEST(ueventd_parser, Permissions) {
+    auto ueventd_file = R"(
+/dev/rtc0                 0640   system     system
+/dev/graphics/*           0660   root       graphics
+/dev/*/test               0660   root       system
+
+/sys/devices/platform/trusty.*      trusty_version        0440  root   log
+/sys/devices/virtual/input/input   enable      0660  root   input
+/sys/devices/virtual/*/input   poll_delay  0660  root   input
+)";
+
+    auto permissions = std::vector<Permissions>{
+            {"/dev/rtc0", 0640, AID_SYSTEM, AID_SYSTEM},
+            {"/dev/graphics/*", 0660, AID_ROOT, AID_GRAPHICS},
+            {"/dev/*/test", 0660, AID_ROOT, AID_SYSTEM},
+    };
+
+    auto sysfs_permissions = std::vector<SysfsPermissions>{
+            {"/sys/devices/platform/trusty.*", "trusty_version", 0440, AID_ROOT, AID_LOG},
+            {"/sys/devices/virtual/input/input", "enable", 0660, AID_ROOT, AID_INPUT},
+            {"/sys/devices/virtual/*/input", "poll_delay", 0660, AID_ROOT, AID_INPUT},
+    };
+
+    TestUeventdFile(ueventd_file, {{}, sysfs_permissions, permissions, {}});
+}
+
+TEST(ueventd_parser, FirmwareDirectories) {
+    auto ueventd_file = R"(
+firmware_directories /first/ /second /third
+firmware_directories /more
+)";
+
+    auto firmware_directories = std::vector<std::string>{
+            "/first/",
+            "/second",
+            "/third",
+            "/more",
+    };
+
+    TestUeventdFile(ueventd_file, {{}, {}, {}, firmware_directories});
+}
+
+TEST(ueventd_parser, AllTogether) {
+    auto ueventd_file = R"(
+
+/dev/rtc0                 0640   system     system
+firmware_directories /first/ /second /third
+/sys/devices/platform/trusty.*      trusty_version        0440  root   log
+
+subsystem test_devname
+    devname uevent_devname
+
+/dev/graphics/*           0660   root       graphics
+
+subsystem test_devpath_no_dirname
+    devname uevent_devpath
+
+/sys/devices/virtual/input/input   enable      0660  root   input
+
+## this is a comment
+
+subsystem test_devname2
+## another comment
+    devname uevent_devname
+
+subsystem test_devpath_dirname
+    devname uevent_devpath
+    dirname /dev/graphics
+
+/dev/*/test               0660   root       system
+/sys/devices/virtual/*/input   poll_delay  0660  root   input
+firmware_directories /more
+
+#ending comment
+)";
+
+    auto subsystems = std::vector<Subsystem>{
+            {"test_devname", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"},
+            {"test_devpath_no_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev"},
+            {"test_devname2", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"},
+            {"test_devpath_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev/graphics"}};
+
+    auto permissions = std::vector<Permissions>{
+            {"/dev/rtc0", 0640, AID_SYSTEM, AID_SYSTEM},
+            {"/dev/graphics/*", 0660, AID_ROOT, AID_GRAPHICS},
+            {"/dev/*/test", 0660, AID_ROOT, AID_SYSTEM},
+    };
+
+    auto sysfs_permissions = std::vector<SysfsPermissions>{
+            {"/sys/devices/platform/trusty.*", "trusty_version", 0440, AID_ROOT, AID_LOG},
+            {"/sys/devices/virtual/input/input", "enable", 0660, AID_ROOT, AID_INPUT},
+            {"/sys/devices/virtual/*/input", "poll_delay", 0660, AID_ROOT, AID_INPUT},
+    };
+
+    auto firmware_directories = std::vector<std::string>{
+            "/first/",
+            "/second",
+            "/third",
+            "/more",
+    };
+
+    TestUeventdFile(ueventd_file,
+                    {subsystems, sysfs_permissions, permissions, firmware_directories});
+}
+
+// All of these lines are ill-formed, so test that there is 0 output.
+TEST(ueventd_parser, ParseErrors) {
+    auto ueventd_file = R"(
+
+/dev/rtc0                 badmode   baduidbad     system
+/dev/rtc0                 0640   baduidbad     system
+/dev/rtc0                 0640   system     baduidbad
+firmware_directories #no directory listed
+/sys/devices/platform/trusty.*      trusty_version        badmode  root   log
+/sys/devices/platform/trusty.*      trusty_version        0440  baduidbad   log
+/sys/devices/platform/trusty.*      trusty_version        0440  root   baduidbad
+
+subsystem #no name
+
+)";
+
+    TestUeventdFile(ueventd_file, {});
+}
+
+}  // namespace init
+}  // namespace android
diff --git a/init/util.cpp b/init/util.cpp
index 5f2b87d..7735717 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -37,12 +37,9 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
-#include <cutils/android_reboot.h>
 #include <cutils/sockets.h>
 #include <selinux/android.h>
 
-#include "reboot.h"
-
 #if defined(__ANDROID__)
 #include "selinux.h"
 #else
diff --git a/init/watchdogd.cpp b/init/watchdogd.cpp
index e0164b4..e03a2c3 100644
--- a/init/watchdogd.cpp
+++ b/init/watchdogd.cpp
@@ -23,8 +23,6 @@
 
 #include <android-base/logging.h>
 
-#include "log.h"
-
 #ifdef _INIT_INIT_H
 #error "Do not include init.h in files used by ueventd or watchdogd; it will expose init's globals"
 #endif
@@ -35,7 +33,7 @@
 namespace init {
 
 int watchdogd_main(int argc, char **argv) {
-    InitKernelLogging(argv);
+    android::base::InitLogging(argv, &android::base::KernelLogger);
 
     int interval = 10;
     if (argc >= 2) interval = atoi(argv[1]);
diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
index 735a2f3..10e790b 100644
--- a/libbacktrace/include/backtrace/Backtrace.h
+++ b/libbacktrace/include/backtrace/Backtrace.h
@@ -122,7 +122,7 @@
   // Tracing a thread in a different process is not supported.
   // If map is NULL, then create the map and manage it internally.
   // If map is not NULL, the map is still owned by the caller.
-  static Backtrace* Create(pid_t pid, pid_t tid, BacktraceMap* map = NULL);
+  static Backtrace* Create(pid_t pid, pid_t tid, BacktraceMap* map = nullptr);
 
   // Create an offline Backtrace object that can be used to do an unwind without a process
   // that is still running. By default, information is only cached in the map
@@ -145,7 +145,7 @@
   virtual ~Backtrace();
 
   // Get the current stack trace and store in the backtrace_ structure.
-  virtual bool Unwind(size_t num_ignore_frames, void* context = NULL) = 0;
+  virtual bool Unwind(size_t num_ignore_frames, void* context = nullptr) = 0;
 
   static bool Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
                      std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames,
@@ -160,7 +160,7 @@
   // If the string is empty, then no valid function name was found,
   // or the pc is not in any valid map.
   virtual std::string GetFunctionName(uint64_t pc, uint64_t* offset,
-                                      const backtrace_map_t* map = NULL);
+                                      const backtrace_map_t* map = nullptr);
 
   // Fill in the map data associated with the given pc.
   virtual void FillInMap(uint64_t pc, backtrace_map_t* map);
@@ -185,7 +185,7 @@
 
   const backtrace_frame_data_t* GetFrame(size_t frame_num) {
     if (frame_num >= frames_.size()) {
-      return NULL;
+      return nullptr;
     }
     return &frames_[frame_num];
   }
diff --git a/libcutils/ashmem-dev.cpp b/libcutils/ashmem-dev.cpp
index 15ace0e..0cc4fc0 100644
--- a/libcutils/ashmem-dev.cpp
+++ b/libcutils/ashmem-dev.cpp
@@ -90,7 +90,7 @@
     dev_t rdev;
     struct stat st;
 
-    if (TEMP_FAILURE_RETRY(fstat(fd, &st)) < 0) {
+    if (fstat(fd, &st) < 0) {
         return -1;
     }
 
@@ -135,6 +135,12 @@
     return -1;
 }
 
+static int __ashmem_check_failure(int fd, int result)
+{
+    if (result == -1 && errno == ENOTTY) __ashmem_is_ashmem(fd, 1);
+    return result;
+}
+
 int ashmem_valid(int fd)
 {
     return __ashmem_is_ashmem(fd, 0) >= 0;
@@ -182,12 +188,7 @@
 
 int ashmem_set_prot_region(int fd, int prot)
 {
-    int ret = __ashmem_is_ashmem(fd, 1);
-    if (ret < 0) {
-        return ret;
-    }
-
-    return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_PROT_MASK, prot));
+    return __ashmem_check_failure(fd, TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_PROT_MASK, prot)));
 }
 
 int ashmem_pin_region(int fd, size_t offset, size_t len)
@@ -195,12 +196,7 @@
     // TODO: should LP64 reject too-large offset/len?
     ashmem_pin pin = { static_cast<uint32_t>(offset), static_cast<uint32_t>(len) };
 
-    int ret = __ashmem_is_ashmem(fd, 1);
-    if (ret < 0) {
-        return ret;
-    }
-
-    return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_PIN, &pin));
+    return __ashmem_check_failure(fd, TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_PIN, &pin)));
 }
 
 int ashmem_unpin_region(int fd, size_t offset, size_t len)
@@ -208,20 +204,10 @@
     // TODO: should LP64 reject too-large offset/len?
     ashmem_pin pin = { static_cast<uint32_t>(offset), static_cast<uint32_t>(len) };
 
-    int ret = __ashmem_is_ashmem(fd, 1);
-    if (ret < 0) {
-        return ret;
-    }
-
-    return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_UNPIN, &pin));
+    return __ashmem_check_failure(fd, TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_UNPIN, &pin)));
 }
 
 int ashmem_get_size_region(int fd)
 {
-    int ret = __ashmem_is_ashmem(fd, 1);
-    if (ret < 0) {
-        return ret;
-    }
-
-    return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_GET_SIZE, NULL));
+    return __ashmem_check_failure(fd, TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_GET_SIZE, NULL)));
 }
diff --git a/liblog/include/log/log_main.h b/liblog/include/log/log_main.h
index 21fc7cc..1314330 100644
--- a/liblog/include/log/log_main.h
+++ b/liblog/include/log/log_main.h
@@ -40,6 +40,19 @@
 #endif
 #endif
 
+/*
+ * Use __VA_ARGS__ if running a static analyzer,
+ * to avoid warnings of unused variables in __VA_ARGS__.
+ * __FAKE_USE_VA_ARGS is undefined at link time,
+ * so don't link with __clang_analyzer__ defined.
+ */
+#ifdef __clang_analyzer__
+extern void __fake_use_va_args(int, ...);
+#define __FAKE_USE_VA_ARGS(...) __fake_use_va_args(0, ##__VA_ARGS__)
+#else
+#define __FAKE_USE_VA_ARGS(...) ((void)(0))
+#endif
+
 /* --------------------------------------------------------------------- */
 
 /*
@@ -112,7 +125,7 @@
 #define LOG_ALWAYS_FATAL_IF(cond, ...)                              \
   ((__predict_false(cond))                                          \
        ? ((void)android_printAssert(#cond, LOG_TAG, ##__VA_ARGS__)) \
-       : (void)0)
+       : __FAKE_USE_VA_ARGS(__VA_ARGS__))
 #endif
 
 #ifndef LOG_ALWAYS_FATAL
@@ -128,10 +141,10 @@
 #if LOG_NDEBUG
 
 #ifndef LOG_FATAL_IF
-#define LOG_FATAL_IF(cond, ...) ((void)0)
+#define LOG_FATAL_IF(cond, ...) __FAKE_USE_VA_ARGS(__VA_ARGS__)
 #endif
 #ifndef LOG_FATAL
-#define LOG_FATAL(...) ((void)0)
+#define LOG_FATAL(...) __FAKE_USE_VA_ARGS(__VA_ARGS__)
 #endif
 
 #else
@@ -175,11 +188,12 @@
 #ifndef ALOGV
 #define __ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
 #if LOG_NDEBUG
-#define ALOGV(...)          \
-  do {                      \
-    if (false) {            \
-      __ALOGV(__VA_ARGS__); \
-    }                       \
+#define ALOGV(...)                   \
+  do {                               \
+    __FAKE_USE_VA_ARGS(__VA_ARGS__); \
+    if (false) {                     \
+      __ALOGV(__VA_ARGS__);          \
+    }                                \
   } while (false)
 #else
 #define ALOGV(...) __ALOGV(__VA_ARGS__)
@@ -188,11 +202,11 @@
 
 #ifndef ALOGV_IF
 #if LOG_NDEBUG
-#define ALOGV_IF(cond, ...) ((void)0)
+#define ALOGV_IF(cond, ...) __FAKE_USE_VA_ARGS(__VA_ARGS__)
 #else
 #define ALOGV_IF(cond, ...)                                                  \
   ((__predict_false(cond)) ? ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
-                           : (void)0)
+                           : __FAKE_USE_VA_ARGS(__VA_ARGS__))
 #endif
 #endif
 
@@ -206,7 +220,7 @@
 #ifndef ALOGD_IF
 #define ALOGD_IF(cond, ...)                                                \
   ((__predict_false(cond)) ? ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
-                           : (void)0)
+                           : __FAKE_USE_VA_ARGS(__VA_ARGS__))
 #endif
 
 /*
@@ -219,7 +233,7 @@
 #ifndef ALOGI_IF
 #define ALOGI_IF(cond, ...)                                               \
   ((__predict_false(cond)) ? ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \
-                           : (void)0)
+                           : __FAKE_USE_VA_ARGS(__VA_ARGS__))
 #endif
 
 /*
@@ -232,7 +246,7 @@
 #ifndef ALOGW_IF
 #define ALOGW_IF(cond, ...)                                               \
   ((__predict_false(cond)) ? ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \
-                           : (void)0)
+                           : __FAKE_USE_VA_ARGS(__VA_ARGS__))
 #endif
 
 /*
@@ -245,7 +259,7 @@
 #ifndef ALOGE_IF
 #define ALOGE_IF(cond, ...)                                                \
   ((__predict_false(cond)) ? ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
-                           : (void)0)
+                           : __FAKE_USE_VA_ARGS(__VA_ARGS__))
 #endif
 
 /* --------------------------------------------------------------------- */
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index b0bc497..c38279d 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -2,6 +2,7 @@
     srcs: ["processgroup.cpp"],
     name: "libprocessgroup",
     host_supported: true,
+    recovery_available: true,
     shared_libs: ["libbase"],
     export_include_dirs: ["include"],
     cflags: [
diff --git a/libprocinfo/include/procinfo/process.h b/libprocinfo/include/procinfo/process.h
index db56fc1..9278e18 100644
--- a/libprocinfo/include/procinfo/process.h
+++ b/libprocinfo/include/procinfo/process.h
@@ -56,23 +56,25 @@
 };
 
 // Parse the contents of /proc/<tid>/status into |process_info|.
-bool GetProcessInfo(pid_t tid, ProcessInfo* process_info);
+bool GetProcessInfo(pid_t tid, ProcessInfo* process_info, std::string* error = nullptr);
 
 // Parse the contents of <fd>/status into |process_info|.
 // |fd| should be an fd pointing at a /proc/<pid> directory.
-bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info);
+bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info, std::string* error = nullptr);
 
 // Fetch the list of threads from a given process's /proc/<pid> directory.
 // |fd| should be an fd pointing at a /proc/<pid> directory.
 template <typename Collection>
-auto GetProcessTidsFromProcPidFd(int fd, Collection* out) ->
+auto GetProcessTidsFromProcPidFd(int fd, Collection* out, std::string* error = nullptr) ->
     typename std::enable_if<sizeof(typename Collection::value_type) >= sizeof(pid_t), bool>::type {
   out->clear();
 
   int task_fd = openat(fd, "task", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
   std::unique_ptr<DIR, int (*)(DIR*)> dir(fdopendir(task_fd), closedir);
   if (!dir) {
-    PLOG(ERROR) << "failed to open task directory";
+    if (error != nullptr) {
+      *error = "failed to open task directory";
+    }
     return false;
   }
 
@@ -81,7 +83,9 @@
     if (strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0) {
       pid_t tid;
       if (!android::base::ParseInt(dent->d_name, &tid, 1, std::numeric_limits<pid_t>::max())) {
-        LOG(ERROR) << "failed to parse task id: " << dent->d_name;
+        if (error != nullptr) {
+          *error = std::string("failed to parse task id: ") + dent->d_name;
+        }
         return false;
       }
 
@@ -93,21 +97,25 @@
 }
 
 template <typename Collection>
-auto GetProcessTids(pid_t pid, Collection* out) ->
+auto GetProcessTids(pid_t pid, Collection* out, std::string* error = nullptr) ->
     typename std::enable_if<sizeof(typename Collection::value_type) >= sizeof(pid_t), bool>::type {
   char task_path[PATH_MAX];
   if (snprintf(task_path, PATH_MAX, "/proc/%d", pid) >= PATH_MAX) {
-    LOG(ERROR) << "task path overflow (pid = " << pid << ")";
+    if (error != nullptr) {
+      *error = "task path overflow (pid = " + std::to_string(pid) + ")";
+    }
     return false;
   }
 
   android::base::unique_fd fd(open(task_path, O_DIRECTORY | O_RDONLY | O_CLOEXEC));
   if (fd == -1) {
-    PLOG(ERROR) << "failed to open " << task_path;
+    if (error != nullptr) {
+      *error = std::string("failed to open ") + task_path;
+    }
     return false;
   }
 
-  return GetProcessTidsFromProcPidFd(fd.get(), out);
+  return GetProcessTidsFromProcPidFd(fd.get(), out, error);
 }
 
 #endif
diff --git a/libprocinfo/process.cpp b/libprocinfo/process.cpp
index 6e5be6e..9194cf3 100644
--- a/libprocinfo/process.cpp
+++ b/libprocinfo/process.cpp
@@ -31,17 +31,19 @@
 namespace android {
 namespace procinfo {
 
-bool GetProcessInfo(pid_t tid, ProcessInfo* process_info) {
+bool GetProcessInfo(pid_t tid, ProcessInfo* process_info, std::string* error) {
   char path[PATH_MAX];
   snprintf(path, sizeof(path), "/proc/%d", tid);
 
   unique_fd dirfd(open(path, O_DIRECTORY | O_RDONLY));
   if (dirfd == -1) {
-    PLOG(ERROR) << "failed to open " << path;
+    if (error != nullptr) {
+      *error = std::string("failed to open ") + path;
+    }
     return false;
   }
 
-  return GetProcessInfoFromProcPidFd(dirfd.get(), process_info);
+  return GetProcessInfoFromProcPidFd(dirfd.get(), process_info, error);
 }
 
 static ProcessState parse_state(const char* state) {
@@ -62,17 +64,21 @@
   }
 }
 
-bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info) {
+bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info, std::string* error) {
   int status_fd = openat(fd, "status", O_RDONLY | O_CLOEXEC);
 
   if (status_fd == -1) {
-    PLOG(ERROR) << "failed to open status fd in GetProcessInfoFromProcPidFd";
+    if (error != nullptr) {
+      *error = "failed to open status fd in GetProcessInfoFromProcPidFd";
+    }
     return false;
   }
 
   std::unique_ptr<FILE, decltype(&fclose)> fp(fdopen(status_fd, "r"), fclose);
   if (!fp) {
-    PLOG(ERROR) << "failed to open status file in GetProcessInfoFromProcPidFd";
+    if (error != nullptr) {
+      *error = "failed to open status file in GetProcessInfoFromProcPidFd";
+    }
     close(status_fd);
     return false;
   }
diff --git a/libsparse/backed_block.cpp b/libsparse/backed_block.cpp
index 7f5632e..f3d8022 100644
--- a/libsparse/backed_block.cpp
+++ b/libsparse/backed_block.cpp
@@ -133,7 +133,7 @@
                             struct backed_block* start, struct backed_block* end) {
   struct backed_block* bb;
 
-  if (start == NULL) {
+  if (start == nullptr) {
     start = from->data_blocks;
   }
 
@@ -142,12 +142,12 @@
       ;
   }
 
-  if (start == NULL || end == NULL) {
+  if (start == nullptr || end == nullptr) {
     return;
   }
 
-  from->last_used = NULL;
-  to->last_used = NULL;
+  from->last_used = nullptr;
+  to->last_used = nullptr;
   if (from->data_blocks == start) {
     from->data_blocks = end->next;
   } else {
@@ -161,7 +161,7 @@
 
   if (!to->data_blocks) {
     to->data_blocks = start;
-    end->next = NULL;
+    end->next = nullptr;
   } else {
     for (bb = to->data_blocks; bb; bb = bb->next) {
       if (!bb->next || bb->next->block > start->block) {
@@ -230,7 +230,7 @@
 static int queue_bb(struct backed_block_list* bbl, struct backed_block* new_bb) {
   struct backed_block* bb;
 
-  if (bbl->data_blocks == NULL) {
+  if (bbl->data_blocks == nullptr) {
     bbl->data_blocks = new_bb;
     return 0;
   }
@@ -253,7 +253,7 @@
   for (; bb->next && bb->next->block < new_bb->block; bb = bb->next)
     ;
 
-  if (bb->next == NULL) {
+  if (bb->next == nullptr) {
     bb->next = new_bb;
   } else {
     new_bb->next = bb->next;
@@ -273,7 +273,7 @@
 int backed_block_add_fill(struct backed_block_list* bbl, unsigned int fill_val, unsigned int len,
                           unsigned int block) {
   struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
-  if (bb == NULL) {
+  if (bb == nullptr) {
     return -ENOMEM;
   }
 
@@ -281,7 +281,7 @@
   bb->len = len;
   bb->type = BACKED_BLOCK_FILL;
   bb->fill.val = fill_val;
-  bb->next = NULL;
+  bb->next = nullptr;
 
   return queue_bb(bbl, bb);
 }
@@ -290,7 +290,7 @@
 int backed_block_add_data(struct backed_block_list* bbl, void* data, unsigned int len,
                           unsigned int block) {
   struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
-  if (bb == NULL) {
+  if (bb == nullptr) {
     return -ENOMEM;
   }
 
@@ -298,7 +298,7 @@
   bb->len = len;
   bb->type = BACKED_BLOCK_DATA;
   bb->data.data = data;
-  bb->next = NULL;
+  bb->next = nullptr;
 
   return queue_bb(bbl, bb);
 }
@@ -307,7 +307,7 @@
 int backed_block_add_file(struct backed_block_list* bbl, const char* filename, int64_t offset,
                           unsigned int len, unsigned int block) {
   struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
-  if (bb == NULL) {
+  if (bb == nullptr) {
     return -ENOMEM;
   }
 
@@ -316,7 +316,7 @@
   bb->type = BACKED_BLOCK_FILE;
   bb->file.filename = strdup(filename);
   bb->file.offset = offset;
-  bb->next = NULL;
+  bb->next = nullptr;
 
   return queue_bb(bbl, bb);
 }
@@ -325,7 +325,7 @@
 int backed_block_add_fd(struct backed_block_list* bbl, int fd, int64_t offset, unsigned int len,
                         unsigned int block) {
   struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
-  if (bb == NULL) {
+  if (bb == nullptr) {
     return -ENOMEM;
   }
 
@@ -334,7 +334,7 @@
   bb->type = BACKED_BLOCK_FD;
   bb->fd.fd = fd;
   bb->fd.offset = offset;
-  bb->next = NULL;
+  bb->next = nullptr;
 
   return queue_bb(bbl, bb);
 }
@@ -350,7 +350,7 @@
   }
 
   new_bb = reinterpret_cast<backed_block*>(malloc(sizeof(struct backed_block)));
-  if (new_bb == NULL) {
+  if (new_bb == nullptr) {
     return -ENOMEM;
   }
 
diff --git a/libsparse/output_file.cpp b/libsparse/output_file.cpp
index 5388e77..fe314b3 100644
--- a/libsparse/output_file.cpp
+++ b/libsparse/output_file.cpp
@@ -233,7 +233,7 @@
   while (len > 0) {
     ret = gzwrite(outgz->gz_fd, data, min(len, (unsigned int)INT_MAX));
     if (ret == 0) {
-      error("gzwrite %s", gzerror(outgz->gz_fd, NULL));
+      error("gzwrite %s", gzerror(outgz->gz_fd, nullptr));
       return -1;
     }
     len -= ret;
@@ -269,7 +269,7 @@
 
   while (off > 0) {
     to_write = min(off, (int64_t)INT_MAX);
-    ret = outc->write(outc->priv, NULL, to_write);
+    ret = outc->write(outc->priv, nullptr, to_write);
     if (ret < 0) {
       return ret;
     }
@@ -568,7 +568,7 @@
       reinterpret_cast<struct output_file_gz*>(calloc(1, sizeof(struct output_file_gz)));
   if (!outgz) {
     error_errno("malloc struct outgz");
-    return NULL;
+    return nullptr;
   }
 
   outgz->out.ops = &gz_file_ops;
@@ -581,7 +581,7 @@
       reinterpret_cast<struct output_file_normal*>(calloc(1, sizeof(struct output_file_normal)));
   if (!outn) {
     error_errno("malloc struct outn");
-    return NULL;
+    return nullptr;
   }
 
   outn->out.ops = &file_ops;
@@ -599,7 +599,7 @@
       reinterpret_cast<struct output_file_callback*>(calloc(1, sizeof(struct output_file_callback)));
   if (!outc) {
     error_errno("malloc struct outc");
-    return NULL;
+    return nullptr;
   }
 
   outc->out.ops = &callback_file_ops;
@@ -609,7 +609,7 @@
   ret = output_file_init(&outc->out, block_size, len, sparse, chunks, crc);
   if (ret < 0) {
     free(outc);
-    return NULL;
+    return nullptr;
   }
 
   return &outc->out;
@@ -626,7 +626,7 @@
     out = output_file_new_normal();
   }
   if (!out) {
-    return NULL;
+    return nullptr;
   }
 
   out->ops->open(out, fd);
@@ -634,7 +634,7 @@
   ret = output_file_init(out, block_size, len, sparse, chunks, crc);
   if (ret < 0) {
     free(out);
-    return NULL;
+    return nullptr;
   }
 
   return out;
@@ -664,7 +664,7 @@
 #ifndef _WIN32
   if (buffer_size > SIZE_MAX) return -E2BIG;
   char* data =
-      reinterpret_cast<char*>(mmap64(NULL, buffer_size, PROT_READ, MAP_SHARED, fd, aligned_offset));
+      reinterpret_cast<char*>(mmap64(nullptr, buffer_size, PROT_READ, MAP_SHARED, fd, aligned_offset));
   if (data == MAP_FAILED) {
     return -errno;
   }
diff --git a/libsparse/simg2simg.cpp b/libsparse/simg2simg.cpp
index 7e65701..a2c296e 100644
--- a/libsparse/simg2simg.cpp
+++ b/libsparse/simg2simg.cpp
@@ -66,7 +66,7 @@
     exit(-1);
   }
 
-  files = sparse_file_resparse(s, max_size, NULL, 0);
+  files = sparse_file_resparse(s, max_size, nullptr, 0);
   if (files < 0) {
     fprintf(stderr, "Failed to resparse\n");
     exit(-1);
diff --git a/libsparse/sparse.cpp b/libsparse/sparse.cpp
index 6ff97b6..cb288c5 100644
--- a/libsparse/sparse.cpp
+++ b/libsparse/sparse.cpp
@@ -30,13 +30,13 @@
 struct sparse_file* sparse_file_new(unsigned int block_size, int64_t len) {
   struct sparse_file* s = reinterpret_cast<sparse_file*>(calloc(sizeof(struct sparse_file), 1));
   if (!s) {
-    return NULL;
+    return nullptr;
   }
 
   s->backed_block_list = backed_block_list_new(block_size);
   if (!s->backed_block_list) {
     free(s);
-    return NULL;
+    return nullptr;
   }
 
   s->block_size = block_size;
@@ -252,7 +252,7 @@
                                                   unsigned int len) {
   int64_t count = 0;
   struct output_file* out_counter;
-  struct backed_block* last_bb = NULL;
+  struct backed_block* last_bb = nullptr;
   struct backed_block* bb;
   struct backed_block* start;
   unsigned int last_block = 0;
@@ -270,7 +270,7 @@
   out_counter = output_file_open_callback(out_counter_write, &count, to->block_size, to->len, false,
                                           true, 0, false);
   if (!out_counter) {
-    return NULL;
+    return nullptr;
   }
 
   for (bb = start; bb; bb = backed_block_iter_next(bb)) {
@@ -281,7 +281,7 @@
     /* will call out_counter_write to update count */
     ret = sparse_file_write_block(out_counter, bb);
     if (ret) {
-      bb = NULL;
+      bb = nullptr;
       goto out;
     }
     if (file_len + count > len) {
@@ -330,13 +330,13 @@
     if (c < out_s_count) {
       out_s[c] = s;
     } else {
-      backed_block_list_move(s->backed_block_list, tmp->backed_block_list, NULL, NULL);
+      backed_block_list_move(s->backed_block_list, tmp->backed_block_list, nullptr, nullptr);
       sparse_file_destroy(s);
     }
     c++;
   } while (bb);
 
-  backed_block_list_move(tmp->backed_block_list, in_s->backed_block_list, NULL, NULL);
+  backed_block_list_move(tmp->backed_block_list, in_s->backed_block_list, nullptr, nullptr);
 
   sparse_file_destroy(tmp);
 
diff --git a/libsparse/sparse_read.cpp b/libsparse/sparse_read.cpp
index 56e2c9a..c4c1823 100644
--- a/libsparse/sparse_read.cpp
+++ b/libsparse/sparse_read.cpp
@@ -276,7 +276,7 @@
     return ret;
   }
 
-  if (crc32 != NULL && file_crc32 != *crc32) {
+  if (crc32 != nullptr && file_crc32 != *crc32) {
     return -EINVAL;
   }
 
@@ -339,7 +339,7 @@
   sparse_header_t sparse_header;
   chunk_header_t chunk_header;
   uint32_t crc32 = 0;
-  uint32_t* crc_ptr = 0;
+  uint32_t* crc_ptr = nullptr;
   unsigned int cur_block = 0;
 
   if (!copybuf) {
@@ -489,39 +489,39 @@
   ret = source->ReadValue(&sparse_header, sizeof(sparse_header));
   if (ret < 0) {
     verbose_error(verbose, ret, "header");
-    return NULL;
+    return nullptr;
   }
 
   if (sparse_header.magic != SPARSE_HEADER_MAGIC) {
     verbose_error(verbose, -EINVAL, "header magic");
-    return NULL;
+    return nullptr;
   }
 
   if (sparse_header.major_version != SPARSE_HEADER_MAJOR_VER) {
     verbose_error(verbose, -EINVAL, "header major version");
-    return NULL;
+    return nullptr;
   }
 
   if (sparse_header.file_hdr_sz < SPARSE_HEADER_LEN) {
-    return NULL;
+    return nullptr;
   }
 
   if (sparse_header.chunk_hdr_sz < sizeof(chunk_header_t)) {
-    return NULL;
+    return nullptr;
   }
 
   len = (int64_t)sparse_header.total_blks * sparse_header.blk_sz;
   s = sparse_file_new(sparse_header.blk_sz, len);
   if (!s) {
-    verbose_error(verbose, -EINVAL, NULL);
-    return NULL;
+    verbose_error(verbose, -EINVAL, nullptr);
+    return nullptr;
   }
 
   ret = source->SetOffset(0);
   if (ret < 0) {
     verbose_error(verbose, ret, "seeking");
     sparse_file_destroy(s);
-    return NULL;
+    return nullptr;
   }
 
   s->verbose = verbose;
@@ -529,7 +529,7 @@
   ret = sparse_file_read_sparse(s, source, crc);
   if (ret < 0) {
     sparse_file_destroy(s);
-    return NULL;
+    return nullptr;
   }
 
   return s;
@@ -557,20 +557,20 @@
 
   len = lseek64(fd, 0, SEEK_END);
   if (len < 0) {
-    return NULL;
+    return nullptr;
   }
 
   lseek64(fd, 0, SEEK_SET);
 
   s = sparse_file_new(4096, len);
   if (!s) {
-    return NULL;
+    return nullptr;
   }
 
   ret = sparse_file_read_normal(s, fd);
   if (ret < 0) {
     sparse_file_destroy(s);
-    return NULL;
+    return nullptr;
   }
 
   return s;
diff --git a/libsync/include/ndk/sync.h b/libsync/include/ndk/sync.h
index 49f01e1..ba7d8c4 100644
--- a/libsync/include/ndk/sync.h
+++ b/libsync/include/ndk/sync.h
@@ -27,11 +27,14 @@
 #define ANDROID_SYNC_H
 
 #include <stdint.h>
+#include <sys/cdefs.h>
 
 #include <linux/sync_file.h>
 
 __BEGIN_DECLS
 
+#if __ANDROID_API__ >= 26
+
 /* Fences indicate the status of an asynchronous task. They are initially
  * in unsignaled state (0), and make a one-time transition to either signaled
  * (1) or error (< 0) state. A sync file is a collection of one or more fences;
@@ -88,6 +91,8 @@
 /** Free a struct sync_file_info structure */
 void sync_file_info_free(struct sync_file_info* info) __INTRODUCED_IN(26);
 
+#endif /* __ANDROID_API__ >= 26 */
+
 __END_DECLS
 
 #endif /* ANDROID_SYNC_H */
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index 87e2684..835e226 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -42,7 +42,7 @@
 
 FrameworkListener::FrameworkListener(int sock) :
                             SocketListener(sock, true) {
-    init(NULL, false);
+    init(nullptr, false);
 }
 
 void FrameworkListener::init(const char *socketName UNUSED, bool withSeq) {
@@ -154,7 +154,7 @@
             if (!haveCmdNum) {
                 char *endptr;
                 int cmdNum = (int)strtol(tmp, &endptr, 0);
-                if (endptr == NULL || *endptr != '\0') {
+                if (endptr == nullptr || *endptr != '\0') {
                     cli->sendMsg(500, "Invalid sequence number", false);
                     goto out;
                 }
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index f0c66ec..24ea7aa 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -45,8 +45,8 @@
 NetlinkEvent::NetlinkEvent() {
     mAction = Action::kUnknown;
     memset(mParams, 0, sizeof(mParams));
-    mPath = NULL;
-    mSubsystem = NULL;
+    mPath = nullptr;
+    mSubsystem = nullptr;
 }
 
 NetlinkEvent::~NetlinkEvent() {
@@ -89,7 +89,7 @@
         NL_EVENT_RTM_NAME(LOCAL_QLOG_NL_EVENT);
         NL_EVENT_RTM_NAME(LOCAL_NFLOG_PACKET);
         default:
-            return NULL;
+            return nullptr;
     }
 #undef NL_EVENT_RTM_NAME
 }
@@ -158,7 +158,7 @@
  */
 bool NetlinkEvent::parseIfAddrMessage(const struct nlmsghdr *nh) {
     struct ifaddrmsg *ifaddr = (struct ifaddrmsg *) NLMSG_DATA(nh);
-    struct ifa_cacheinfo *cacheinfo = NULL;
+    struct ifa_cacheinfo *cacheinfo = nullptr;
     char addrstr[INET6_ADDRSTRLEN] = "";
     char ifname[IFNAMSIZ] = "";
 
@@ -286,7 +286,7 @@
 bool NetlinkEvent::parseNfPacketMessage(struct nlmsghdr *nh) {
     int uid = -1;
     int len = 0;
-    char* raw = NULL;
+    char* raw = nullptr;
 
     struct nlattr* uid_attr = findNlAttr(nh, sizeof(struct genlmsghdr), NFULA_UID);
     if (uid_attr) {
@@ -584,7 +584,7 @@
         (prefixlen == 0 || !memcmp(str, prefix, prefixlen))) {
         return str + prefixlen;
     } else {
-        return NULL;
+        return nullptr;
     }
 }
 
@@ -625,16 +625,16 @@
             first = 0;
         } else {
             const char* a;
-            if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) {
+            if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != nullptr) {
                 if (!strcmp(a, "add"))
                     mAction = Action::kAdd;
                 else if (!strcmp(a, "remove"))
                     mAction = Action::kRemove;
                 else if (!strcmp(a, "change"))
                     mAction = Action::kChange;
-            } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) {
+            } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != nullptr) {
                 mSeq = atoi(a);
-            } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) {
+            } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != nullptr) {
                 mSubsystem = strdup(a);
             } else if (param_idx < NL_PARAMS_MAX) {
                 mParams[param_idx++] = strdup(s);
@@ -656,14 +656,14 @@
 
 const char *NetlinkEvent::findParam(const char *paramName) {
     size_t len = strlen(paramName);
-    for (int i = 0; i < NL_PARAMS_MAX && mParams[i] != NULL; ++i) {
+    for (int i = 0; i < NL_PARAMS_MAX && mParams[i] != nullptr; ++i) {
         const char *ptr = mParams[i] + len;
         if (!strncmp(mParams[i], paramName, len) && *ptr == '=')
             return ++ptr;
     }
 
     SLOGE("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName);
-    return NULL;
+    return nullptr;
 }
 
 nlattr* NetlinkEvent::findNlAttr(const nlmsghdr* nh, size_t hdrlen, uint16_t attr) {
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
index 971f908..0625db7 100644
--- a/libsysutils/src/SocketClient.cpp
+++ b/libsysutils/src/SocketClient.cpp
@@ -42,8 +42,8 @@
     mSocket = socket;
     mSocketOwned = owned;
     mUseCmdNum = useCmdNum;
-    pthread_mutex_init(&mWriteMutex, NULL);
-    pthread_mutex_init(&mRefCountMutex, NULL);
+    pthread_mutex_init(&mWriteMutex, nullptr);
+    pthread_mutex_init(&mRefCountMutex, nullptr);
     mPid = -1;
     mUid = -1;
     mGid = -1;
@@ -135,9 +135,9 @@
     const char *end = arg + len;
     char *oldresult;
 
-    if(result == NULL) {
+    if(result == nullptr) {
         SLOGW("malloc error (%s)", strerror(errno));
-        return NULL;
+        return nullptr;
     }
 
     *(current++) = '"';
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 3f8f3db..0c8a688 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -39,7 +39,7 @@
 }
 
 SocketListener::SocketListener(int socketFd, bool listen) {
-    init(NULL, socketFd, listen, false);
+    init(nullptr, socketFd, listen, false);
 }
 
 SocketListener::SocketListener(const char *socketName, bool listen, bool useCmdNum) {
@@ -51,7 +51,7 @@
     mSocketName = socketName;
     mSock = socketFd;
     mUseCmdNum = useCmdNum;
-    pthread_mutex_init(&mClientsLock, NULL);
+    pthread_mutex_init(&mClientsLock, nullptr);
     mClients = new SocketClientCollection();
 }
 
@@ -102,7 +102,7 @@
         return -1;
     }
 
-    if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
+    if (pthread_create(&mThread, nullptr, SocketListener::threadStart, this)) {
         SLOGE("pthread_create (%s)", strerror(errno));
         return -1;
     }
@@ -147,8 +147,8 @@
     SocketListener *me = reinterpret_cast<SocketListener *>(obj);
 
     me->runListener();
-    pthread_exit(NULL);
-    return NULL;
+    pthread_exit(nullptr);
+    return nullptr;
 }
 
 void SocketListener::runListener() {
@@ -183,7 +183,7 @@
         }
         pthread_mutex_unlock(&mClientsLock);
         SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName);
-        if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
+        if ((rc = select(max + 1, &read_fds, nullptr, nullptr, nullptr)) < 0) {
             if (errno == EINTR)
                 continue;
             SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max);
diff --git a/libutils/Android.bp b/libutils/Android.bp
index bbfa9d8..d635e65 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -155,6 +155,7 @@
             ],
         },
         linux: {
+            shared_libs: ["libbase"],
             srcs: [
                 "Looper.cpp",
             ],
diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp
index 3c4d81c..583c6b9 100644
--- a/libutils/FileMap.cpp
+++ b/libutils/FileMap.cpp
@@ -48,10 +48,10 @@
 
 // Constructor.  Create an empty object.
 FileMap::FileMap(void)
-    : mFileName(NULL),
-      mBasePtr(NULL),
+    : mFileName(nullptr),
+      mBasePtr(nullptr),
       mBaseLength(0),
-      mDataPtr(NULL),
+      mDataPtr(nullptr),
       mDataLength(0)
 #if defined(__MINGW32__)
       ,
@@ -69,9 +69,9 @@
       , mFileHandle(other.mFileHandle), mFileMapping(other.mFileMapping)
 #endif
 {
-    other.mFileName = NULL;
-    other.mBasePtr = NULL;
-    other.mDataPtr = NULL;
+    other.mFileName = nullptr;
+    other.mBasePtr = nullptr;
+    other.mDataPtr = nullptr;
 #if defined(__MINGW32__)
     other.mFileHandle = INVALID_HANDLE_VALUE;
     other.mFileMapping = NULL;
@@ -86,9 +86,9 @@
     mDataOffset = other.mDataOffset;
     mDataPtr = other.mDataPtr;
     mDataLength = other.mDataLength;
-    other.mFileName = NULL;
-    other.mBasePtr = NULL;
-    other.mDataPtr = NULL;
+    other.mFileName = nullptr;
+    other.mBasePtr = nullptr;
+    other.mDataPtr = nullptr;
 #if defined(__MINGW32__)
     mFileHandle = other.mFileHandle;
     mFileMapping = other.mFileMapping;
@@ -101,7 +101,7 @@
 // Destructor.
 FileMap::~FileMap(void)
 {
-    if (mFileName != NULL) {
+    if (mFileName != nullptr) {
         free(mFileName);
     }
 #if defined(__MINGW32__)
@@ -196,7 +196,7 @@
     if (!readOnly)
         prot |= PROT_WRITE;
 
-    ptr = mmap(NULL, adjLength, prot, flags, fd, adjOffset);
+    ptr = mmap(nullptr, adjLength, prot, flags, fd, adjOffset);
     if (ptr == MAP_FAILED) {
         ALOGE("mmap(%lld,%zu) failed: %s\n",
             (long long)adjOffset, adjLength, strerror(errno));
@@ -205,7 +205,7 @@
     mBasePtr = ptr;
 #endif // !defined(__MINGW32__)
 
-    mFileName = origFileName != NULL ? strdup(origFileName) : NULL;
+    mFileName = origFileName != nullptr ? strdup(origFileName) : nullptr;
     mBaseLength = adjLength;
     mDataOffset = offset;
     mDataPtr = (char*) mBasePtr + adjust;
diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp
index 6c57b2e..102fdf0 100644
--- a/libutils/Looper.cpp
+++ b/libutils/Looper.cpp
@@ -29,7 +29,7 @@
 
 void WeakMessageHandler::handleMessage(const Message& message) {
     sp<MessageHandler> handler = mHandler.promote();
-    if (handler != NULL) {
+    if (handler != nullptr) {
         handler->handleMessage(message);
     }
 }
@@ -60,24 +60,22 @@
 static pthread_once_t gTLSOnce = PTHREAD_ONCE_INIT;
 static pthread_key_t gTLSKey = 0;
 
-Looper::Looper(bool allowNonCallbacks) :
-        mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
-        mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false),
-        mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
-    mWakeEventFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
-    LOG_ALWAYS_FATAL_IF(mWakeEventFd < 0, "Could not make wake event fd: %s",
-                        strerror(errno));
+Looper::Looper(bool allowNonCallbacks)
+    : mAllowNonCallbacks(allowNonCallbacks),
+      mSendingMessage(false),
+      mPolling(false),
+      mEpollRebuildRequired(false),
+      mNextRequestSeq(0),
+      mResponseIndex(0),
+      mNextMessageUptime(LLONG_MAX) {
+    mWakeEventFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
+    LOG_ALWAYS_FATAL_IF(mWakeEventFd.get() < 0, "Could not make wake event fd: %s", strerror(errno));
 
     AutoMutex _l(mLock);
     rebuildEpollLocked();
 }
 
 Looper::~Looper() {
-    close(mWakeEventFd);
-    mWakeEventFd = -1;
-    if (mEpollFd >= 0) {
-        close(mEpollFd);
-    }
 }
 
 void Looper::initTLSKey() {
@@ -87,7 +85,7 @@
 
 void Looper::threadDestructor(void *st) {
     Looper* const self = static_cast<Looper*>(st);
-    if (self != NULL) {
+    if (self != nullptr) {
         self->decStrong((void*)threadDestructor);
     }
 }
@@ -95,13 +93,13 @@
 void Looper::setForThread(const sp<Looper>& looper) {
     sp<Looper> old = getForThread(); // also has side-effect of initializing TLS
 
-    if (looper != NULL) {
+    if (looper != nullptr) {
         looper->incStrong((void*)threadDestructor);
     }
 
     pthread_setspecific(gTLSKey, looper.get());
 
-    if (old != NULL) {
+    if (old != nullptr) {
         old->decStrong((void*)threadDestructor);
     }
 }
@@ -116,7 +114,7 @@
 sp<Looper> Looper::prepare(int opts) {
     bool allowNonCallbacks = opts & PREPARE_ALLOW_NON_CALLBACKS;
     sp<Looper> looper = Looper::getForThread();
-    if (looper == NULL) {
+    if (looper == nullptr) {
         looper = new Looper(allowNonCallbacks);
         Looper::setForThread(looper);
     }
@@ -137,18 +135,18 @@
 #if DEBUG_CALLBACKS
         ALOGD("%p ~ rebuildEpollLocked - rebuilding epoll set", this);
 #endif
-        close(mEpollFd);
+        mEpollFd.reset();
     }
 
     // Allocate the new epoll instance and register the wake pipe.
-    mEpollFd = epoll_create(EPOLL_SIZE_HINT);
+    mEpollFd.reset(epoll_create(EPOLL_SIZE_HINT));
     LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
 
     struct epoll_event eventItem;
     memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
     eventItem.events = EPOLLIN;
-    eventItem.data.fd = mWakeEventFd;
-    int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);
+    eventItem.data.fd = mWakeEventFd.get();
+    int result = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mWakeEventFd.get(), &eventItem);
     LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake event fd to epoll instance: %s",
                         strerror(errno));
 
@@ -157,7 +155,7 @@
         struct epoll_event eventItem;
         request.initEventItem(&eventItem);
 
-        int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, request.fd, & eventItem);
+        int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, request.fd, &eventItem);
         if (epollResult < 0) {
             ALOGE("Error adding epoll events for fd %d while rebuilding epoll set: %s",
                   request.fd, strerror(errno));
@@ -190,9 +188,9 @@
                         "fd=%d, events=0x%x, data=%p",
                         this, ident, fd, events, data);
 #endif
-                if (outFd != NULL) *outFd = fd;
-                if (outEvents != NULL) *outEvents = events;
-                if (outData != NULL) *outData = data;
+                if (outFd != nullptr) *outFd = fd;
+                if (outEvents != nullptr) *outEvents = events;
+                if (outData != nullptr) *outData = data;
                 return ident;
             }
         }
@@ -201,9 +199,9 @@
 #if DEBUG_POLL_AND_WAKE
             ALOGD("%p ~ pollOnce - returning result %d", this, result);
 #endif
-            if (outFd != NULL) *outFd = 0;
-            if (outEvents != NULL) *outEvents = 0;
-            if (outData != NULL) *outData = NULL;
+            if (outFd != nullptr) *outFd = 0;
+            if (outEvents != nullptr) *outEvents = 0;
+            if (outData != nullptr) *outData = nullptr;
             return result;
         }
 
@@ -239,7 +237,7 @@
     mPolling = true;
 
     struct epoll_event eventItems[EPOLL_MAX_EVENTS];
-    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
+    int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
 
     // No longer idling.
     mPolling = false;
@@ -281,7 +279,7 @@
     for (int i = 0; i < eventCount; i++) {
         int fd = eventItems[i].data.fd;
         uint32_t epollEvents = eventItems[i].events;
-        if (fd == mWakeEventFd) {
+        if (fd == mWakeEventFd.get()) {
             if (epollEvents & EPOLLIN) {
                 awoken();
             } else {
@@ -401,11 +399,11 @@
 #endif
 
     uint64_t inc = 1;
-    ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
+    ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd.get(), &inc, sizeof(uint64_t)));
     if (nWrite != sizeof(uint64_t)) {
         if (errno != EAGAIN) {
-            LOG_ALWAYS_FATAL("Could not write wake signal to fd %d: %s",
-                    mWakeEventFd, strerror(errno));
+            LOG_ALWAYS_FATAL("Could not write wake signal to fd %d: %s", mWakeEventFd.get(),
+                             strerror(errno));
         }
     }
 }
@@ -416,7 +414,7 @@
 #endif
 
     uint64_t counter;
-    TEMP_FAILURE_RETRY(read(mWakeEventFd, &counter, sizeof(uint64_t)));
+    TEMP_FAILURE_RETRY(read(mWakeEventFd.get(), &counter, sizeof(uint64_t)));
 }
 
 void Looper::pushResponse(int events, const Request& request) {
@@ -427,7 +425,7 @@
 }
 
 int Looper::addFd(int fd, int ident, int events, Looper_callbackFunc callback, void* data) {
-    return addFd(fd, ident, events, callback ? new SimpleLooperCallback(callback) : NULL, data);
+    return addFd(fd, ident, events, callback ? new SimpleLooperCallback(callback) : nullptr, data);
 }
 
 int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {
@@ -467,14 +465,14 @@
 
         ssize_t requestIndex = mRequests.indexOfKey(fd);
         if (requestIndex < 0) {
-            int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
+            int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, fd, &eventItem);
             if (epollResult < 0) {
                 ALOGE("Error adding epoll events for fd %d: %s", fd, strerror(errno));
                 return -1;
             }
             mRequests.add(fd, request);
         } else {
-            int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
+            int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_MOD, fd, &eventItem);
             if (epollResult < 0) {
                 if (errno == ENOENT) {
                     // Tolerate ENOENT because it means that an older file descriptor was
@@ -495,7 +493,7 @@
                             "being recycled, falling back on EPOLL_CTL_ADD: %s",
                             this, strerror(errno));
 #endif
-                    epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
+                    epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, fd, &eventItem);
                     if (epollResult < 0) {
                         ALOGE("Error modifying or adding epoll events for fd %d: %s",
                                 fd, strerror(errno));
@@ -542,7 +540,7 @@
         // updating the epoll set so that we avoid accidentally leaking callbacks.
         mRequests.removeItemsAt(requestIndex);
 
-        int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL);
+        int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_DEL, fd, nullptr);
         if (epollResult < 0) {
             if (seq != -1 && (errno == EBADF || errno == ENOENT)) {
                 // Tolerate EBADF or ENOENT when the sequence number is known because it
diff --git a/libutils/NativeHandle.cpp b/libutils/NativeHandle.cpp
index 97d06b8..d437a9f 100644
--- a/libutils/NativeHandle.cpp
+++ b/libutils/NativeHandle.cpp
@@ -20,7 +20,7 @@
 namespace android {
 
 sp<NativeHandle> NativeHandle::create(native_handle_t* handle, bool ownsHandle) {
-    return handle ? new NativeHandle(handle, ownsHandle) : NULL;
+    return handle ? new NativeHandle(handle, ownsHandle) : nullptr;
 }
 
 NativeHandle::NativeHandle(native_handle_t* handle, bool ownsHandle)
diff --git a/libutils/Printer.cpp b/libutils/Printer.cpp
index cbf042e..c9ae210 100644
--- a/libutils/Printer.cpp
+++ b/libutils/Printer.cpp
@@ -73,7 +73,7 @@
 }
 
 void LogPrinter::printLine(const char* string) {
-    if (string == NULL) {
+    if (string == nullptr) {
         ALOGW("%s: NULL string passed in", __FUNCTION__);
         return;
     }
@@ -107,7 +107,7 @@
 }
 
 void FdPrinter::printLine(const char* string) {
-    if (string == NULL) {
+    if (string == nullptr) {
         ALOGW("%s: NULL string passed in", __FUNCTION__);
         return;
     } else if (mFd < 0) {
@@ -127,16 +127,16 @@
         mTarget(target),
         mPrefix(prefix ?: "") {
 
-    if (target == NULL) {
+    if (target == nullptr) {
         ALOGW("%s: Target string was NULL", __FUNCTION__);
     }
 }
 
 void String8Printer::printLine(const char* string) {
-    if (string == NULL) {
+    if (string == nullptr) {
         ALOGW("%s: NULL string passed in", __FUNCTION__);
         return;
-    } else if (mTarget == NULL) {
+    } else if (mTarget == nullptr) {
         ALOGW("%s: Target string was NULL", __FUNCTION__);
         return;
     }
diff --git a/libutils/ProcessCallStack.cpp b/libutils/ProcessCallStack.cpp
index b8fb6dc..f054de9 100644
--- a/libutils/ProcessCallStack.cpp
+++ b/libutils/ProcessCallStack.cpp
@@ -42,14 +42,14 @@
 static const char* PATH_SELF_TASK = "/proc/self/task";
 
 static void dumpProcessHeader(Printer& printer, pid_t pid, const char* timeStr) {
-    if (timeStr == NULL) {
+    if (timeStr == nullptr) {
         ALOGW("%s: timeStr was NULL", __FUNCTION__);
         return;
     }
 
     char path[PATH_MAX];
     char procNameBuf[MAX_PROC_PATH];
-    char* procName = NULL;
+    char* procName = nullptr;
     FILE* fp;
 
     snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
@@ -76,7 +76,7 @@
 
 static String8 getThreadName(pid_t tid) {
     char path[PATH_MAX];
-    char* procName = NULL;
+    char* procName = nullptr;
     char procNameBuf[MAX_PROC_PATH];
     FILE* fp;
 
@@ -88,7 +88,7 @@
         ALOGE("%s: Failed to open %s", __FUNCTION__, path);
     }
 
-    if (procName == NULL) {
+    if (procName == nullptr) {
         // Reading /proc/self/task/%d/comm failed due to a race
         return String8::format("[err-unknown-tid-%d]", tid);
     }
@@ -128,7 +128,7 @@
 
 void ProcessCallStack::update() {
     std::unique_ptr<DIR, decltype(&closedir)> dp(opendir(PATH_SELF_TASK), closedir);
-    if (dp == NULL) {
+    if (dp == nullptr) {
         ALOGE("%s: Failed to update the process's call stacks: %s",
               __FUNCTION__, strerror(errno));
         return;
@@ -140,7 +140,7 @@
 
     // Get current time.
     {
-        time_t t = time(NULL);
+        time_t t = time(nullptr);
         struct tm tm;
         localtime_r(&t, &tm);
 
@@ -152,7 +152,7 @@
      * - Read every file in directory => get every tid
      */
     dirent* ep;
-    while ((ep = readdir(dp.get())) != NULL) {
+    while ((ep = readdir(dp.get())) != nullptr) {
         pid_t tid = -1;
         sscanf(ep->d_name, "%d", &tid);
 
diff --git a/libutils/PropertyMap.cpp b/libutils/PropertyMap.cpp
index 4bcdd0f..b8c065d 100644
--- a/libutils/PropertyMap.cpp
+++ b/libutils/PropertyMap.cpp
@@ -112,7 +112,7 @@
 }
 
 status_t PropertyMap::load(const String8& filename, PropertyMap** outMap) {
-    *outMap = NULL;
+    *outMap = nullptr;
 
     Tokenizer* tokenizer;
     status_t status = Tokenizer::open(filename, &tokenizer);
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index 8bccb0f..9074850 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -712,7 +712,7 @@
         delete mRefs;
     }
     // For debugging purposes, clear mRefs.  Ineffective against outstanding wp's.
-    const_cast<weakref_impl*&>(mRefs) = NULL;
+    const_cast<weakref_impl*&>(mRefs) = nullptr;
 }
 
 void RefBase::extendObjectLifetime(int32_t mode)
diff --git a/libutils/SharedBuffer.cpp b/libutils/SharedBuffer.cpp
index bad98b2..7910c6e 100644
--- a/libutils/SharedBuffer.cpp
+++ b/libutils/SharedBuffer.cpp
@@ -75,7 +75,7 @@
                             "Invalid buffer size %zu", newSize);
 
         buf = (SharedBuffer*)realloc(buf, sizeof(SharedBuffer) + newSize);
-        if (buf != NULL) {
+        if (buf != nullptr) {
             buf->mSize = newSize;
             return buf;
         }
@@ -94,7 +94,7 @@
     if (onlyOwner()) {
         return const_cast<SharedBuffer*>(this);
     }
-    return 0;
+    return nullptr;
 }
 
 SharedBuffer* SharedBuffer::reset(size_t new_size) const
diff --git a/libutils/SharedBuffer.h b/libutils/SharedBuffer.h
index 81cadff..fdf13a9 100644
--- a/libutils/SharedBuffer.h
+++ b/libutils/SharedBuffer.h
@@ -124,11 +124,11 @@
 }
 
 SharedBuffer* SharedBuffer::bufferFromData(void* data) {
-    return data ? static_cast<SharedBuffer *>(data)-1 : 0;
+    return data ? static_cast<SharedBuffer *>(data)-1 : nullptr;
 }
     
 const SharedBuffer* SharedBuffer::bufferFromData(const void* data) {
-    return data ? static_cast<const SharedBuffer *>(data)-1 : 0;
+    return data ? static_cast<const SharedBuffer *>(data)-1 : nullptr;
 }
 
 size_t SharedBuffer::sizeFromData(const void* data) {
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index 84d53dd..f820b8b 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -74,7 +74,7 @@
 }
 
 String16::String16(StaticLinkage)
-    : mString(0)
+    : mString(nullptr)
 {
     // this constructor is used when we can't rely on the static-initializers
     // having run. In this case we always allocate an empty string. It's less
@@ -336,7 +336,7 @@
 {
     const size_t N = size();
     const char16_t* str = string();
-    char16_t* edit = NULL;
+    char16_t* edit = nullptr;
     for (size_t i=0; i<N; i++) {
         const char16_t v = str[i];
         if (v >= 'A' && v <= 'Z') {
@@ -358,7 +358,7 @@
 {
     const size_t N = size();
     const char16_t* str = string();
-    char16_t* edit = NULL;
+    char16_t* edit = nullptr;
     for (size_t i=0; i<N; i++) {
         if (str[i] == replaceThis) {
             if (!edit) {
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 580e870..8d318f7 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -58,7 +58,7 @@
 {
     if (len > 0) {
         if (len == SIZE_MAX) {
-            return NULL;
+            return nullptr;
         }
         SharedBuffer* buf = SharedBuffer::alloc(len+1);
         ALOG_ASSERT(buf, "Unable to allocate shared buffer");
@@ -68,7 +68,7 @@
             str[len] = 0;
             return str;
         }
-        return NULL;
+        return nullptr;
     }
 
     return getEmptyString();
@@ -126,7 +126,7 @@
 }
 
 String8::String8(StaticLinkage)
-    : mString(0)
+    : mString(nullptr)
 {
     // this constructor is used when we can't rely on the static-initializers
     // having run. In this case we always allocate an empty string. It's less
@@ -147,7 +147,7 @@
 String8::String8(const char* o)
     : mString(allocFromUTF8(o, strlen(o)))
 {
-    if (mString == NULL) {
+    if (mString == nullptr) {
         mString = getEmptyString();
     }
 }
@@ -155,7 +155,7 @@
 String8::String8(const char* o, size_t len)
     : mString(allocFromUTF8(o, len))
 {
-    if (mString == NULL) {
+    if (mString == nullptr) {
         mString = getEmptyString();
     }
 }
@@ -319,7 +319,7 @@
      * second vsnprintf access undefined args.
      */
     va_copy(tmp_args, args);
-    n = vsnprintf(NULL, 0, fmt, tmp_args);
+    n = vsnprintf(nullptr, 0, fmt, tmp_args);
     va_end(tmp_args);
 
     if (n != 0) {
@@ -360,7 +360,7 @@
         mString = str;
         return str;
     }
-    return NULL;
+    return nullptr;
 }
 
 void String8::unlockBuffer()
@@ -512,7 +512,7 @@
     const char*const buf = mString;
 
     cp = strrchr(buf, OS_PATH_SEPARATOR);
-    if (cp == NULL)
+    if (cp == nullptr)
         return String8(*this);
     else
         return String8(cp+1);
@@ -524,7 +524,7 @@
     const char*const str = mString;
 
     cp = strrchr(str, OS_PATH_SEPARATOR);
-    if (cp == NULL)
+    if (cp == nullptr)
         return String8("");
     else
         return String8(str, cp - str);
@@ -543,7 +543,7 @@
         cp = strchr(buf, OS_PATH_SEPARATOR);
     }
 
-    if (cp == NULL) {
+    if (cp == nullptr) {
         String8 res = buf != str ? String8(buf) : *this;
         if (outRemains) *outRemains = String8("");
         return res;
@@ -567,15 +567,15 @@
 
     // only look at the filename
     lastSlash = strrchr(str, OS_PATH_SEPARATOR);
-    if (lastSlash == NULL)
+    if (lastSlash == nullptr)
         lastSlash = str;
     else
         lastSlash++;
 
     // find the last dot
     lastDot = strrchr(lastSlash, '.');
-    if (lastDot == NULL)
-        return NULL;
+    if (lastDot == nullptr)
+        return nullptr;
 
     // looks good, ship it
     return const_cast<char*>(lastDot);
@@ -586,7 +586,7 @@
     char* ext;
 
     ext = find_extension();
-    if (ext != NULL)
+    if (ext != nullptr)
         return String8(ext);
     else
         return String8("");
@@ -598,7 +598,7 @@
     const char* const str = mString;
 
     ext = find_extension();
-    if (ext == NULL)
+    if (ext == nullptr)
         return String8(*this);
     else
         return String8(str, ext - str);
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index 7d7f0e2..43ec6c1 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -163,7 +163,7 @@
     // Note that *threadID is directly available to the parent only, as it is
     // assigned after the child starts.  Use memory barrier / lock if the child
     // or other threads also need access.
-    if (threadId != NULL) {
+    if (threadId != nullptr) {
         *threadId = (android_thread_id_t)thread; // XXX: this is not portable
     }
     return 1;
@@ -768,7 +768,7 @@
         strong.clear();
         // And immediately, re-acquire a strong reference for the next loop
         strong = weak.promote();
-    } while(strong != 0);
+    } while(strong != nullptr);
 
     return 0;
 }
diff --git a/libutils/Timers.cpp b/libutils/Timers.cpp
index b2df9a5..c3641ef 100644
--- a/libutils/Timers.cpp
+++ b/libutils/Timers.cpp
@@ -45,7 +45,7 @@
     // is windows.
     struct timeval t;
     t.tv_sec = t.tv_usec = 0;
-    gettimeofday(&t, NULL);
+    gettimeofday(&t, nullptr);
     return nsecs_t(t.tv_sec)*1000000000LL + nsecs_t(t.tv_usec)*1000LL;
 }
 #endif
diff --git a/libutils/Tokenizer.cpp b/libutils/Tokenizer.cpp
index b68a2cf..f73d699 100644
--- a/libutils/Tokenizer.cpp
+++ b/libutils/Tokenizer.cpp
@@ -28,7 +28,7 @@
 namespace android {
 
 static inline bool isDelimiter(char ch, const char* delimiters) {
-    return strchr(delimiters, ch) != NULL;
+    return strchr(delimiters, ch) != nullptr;
 }
 
 Tokenizer::Tokenizer(const String8& filename, FileMap* fileMap, char* buffer,
@@ -46,7 +46,7 @@
 }
 
 status_t Tokenizer::open(const String8& filename, Tokenizer** outTokenizer) {
-    *outTokenizer = NULL;
+    *outTokenizer = nullptr;
 
     int result = NO_ERROR;
     int fd = ::open(filename.string(), O_RDONLY);
@@ -64,12 +64,12 @@
             FileMap* fileMap = new FileMap();
             bool ownBuffer = false;
             char* buffer;
-            if (fileMap->create(NULL, fd, 0, length, true)) {
+            if (fileMap->create(nullptr, fd, 0, length, true)) {
                 fileMap->advise(FileMap::SEQUENTIAL);
                 buffer = static_cast<char*>(fileMap->getDataPtr());
             } else {
                 delete fileMap;
-                fileMap = NULL;
+                fileMap = nullptr;
 
                 // Fall back to reading into a buffer since we can't mmap files in sysfs.
                 // The length we obtained from stat is wrong too (it will always be 4096)
@@ -81,7 +81,7 @@
                     result = -errno;
                     ALOGE("Error reading file '%s': %s", filename.string(), strerror(errno));
                     delete[] buffer;
-                    buffer = NULL;
+                    buffer = nullptr;
                 } else {
                     length = size_t(nrd);
                 }
@@ -98,7 +98,7 @@
 
 status_t Tokenizer::fromContents(const String8& filename,
         const char* contents, Tokenizer** outTokenizer) {
-    *outTokenizer = new Tokenizer(filename, NULL,
+    *outTokenizer = new Tokenizer(filename, nullptr,
             const_cast<char*>(contents), false, strlen(contents));
     return OK;
 }
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index 1086831..e00fb81 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -159,7 +159,7 @@
         return -1;
     }
     size_t dummy_index;
-    if (next_index == NULL) {
+    if (next_index == nullptr) {
         next_index = &dummy_index;
     }
     size_t num_read;
@@ -173,7 +173,7 @@
 
 ssize_t utf32_to_utf8_length(const char32_t *src, size_t src_len)
 {
-    if (src == NULL || src_len == 0) {
+    if (src == nullptr || src_len == 0) {
         return -1;
     }
 
@@ -195,7 +195,7 @@
 
 void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst, size_t dst_len)
 {
-    if (src == NULL || src_len == 0 || dst == NULL) {
+    if (src == nullptr || src_len == 0 || dst == nullptr) {
         return;
     }
 
@@ -363,7 +363,7 @@
 
 void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst, size_t dst_len)
 {
-    if (src == NULL || src_len == 0 || dst == NULL) {
+    if (src == nullptr || src_len == 0 || dst == nullptr) {
         return;
     }
 
@@ -440,7 +440,7 @@
 
 ssize_t utf16_to_utf8_length(const char16_t *src, size_t src_len)
 {
-    if (src == NULL || src_len == 0) {
+    if (src == nullptr || src_len == 0) {
         return -1;
     }
 
@@ -490,7 +490,7 @@
 
 size_t utf8_to_utf32_length(const char *src, size_t src_len)
 {
-    if (src == NULL || src_len == 0) {
+    if (src == nullptr || src_len == 0) {
         return 0;
     }
     size_t ret = 0;
@@ -515,7 +515,7 @@
 
 void utf8_to_utf32(const char* src, size_t src_len, char32_t* dst)
 {
-    if (src == NULL || src_len == 0 || dst == NULL) {
+    if (src == nullptr || src_len == 0 || dst == nullptr) {
         return;
     }
 
diff --git a/libutils/VectorImpl.cpp b/libutils/VectorImpl.cpp
index ef3277f..00a904d 100644
--- a/libutils/VectorImpl.cpp
+++ b/libutils/VectorImpl.cpp
@@ -44,7 +44,7 @@
 // ----------------------------------------------------------------------------
 
 VectorImpl::VectorImpl(size_t itemSize, uint32_t flags)
-    : mStorage(0), mCount(0), mFlags(flags), mItemSize(itemSize)
+    : mStorage(nullptr), mCount(0), mFlags(flags), mItemSize(itemSize)
 {
 }
 
@@ -77,7 +77,7 @@
             mCount = rhs.mCount;
             SharedBuffer::bufferFromData(mStorage)->acquire();
         } else {
-            mStorage = 0;
+            mStorage = nullptr;
             mCount = 0;
         }
     }
@@ -89,14 +89,14 @@
     if (mStorage) {
         const SharedBuffer* sb = SharedBuffer::bufferFromData(mStorage);
         SharedBuffer* editable = sb->attemptEdit();
-        if (editable == 0) {
+        if (editable == nullptr) {
             // If we're here, we're not the only owner of the buffer.
             // We must make a copy of it.
             editable = SharedBuffer::alloc(sb->size());
             // Fail instead of returning a pointer to storage that's not
             // editable. Otherwise we'd be editing the contents of a buffer
             // for which we're not the only owner, which is undefined behaviour.
-            LOG_ALWAYS_FATAL_IF(editable == NULL);
+            LOG_ALWAYS_FATAL_IF(editable == nullptr);
             _do_copy(editable->data(), mStorage, mCount);
             release_storage();
             mStorage = editable->data();
@@ -141,7 +141,7 @@
 
 ssize_t VectorImpl::insertAt(size_t index, size_t numItems)
 {
-    return insertAt(0, index, numItems);
+    return insertAt(nullptr, index, numItems);
 }
 
 ssize_t VectorImpl::insertAt(const void* item, size_t index, size_t numItems)
@@ -177,7 +177,7 @@
     const ssize_t count = size();
     if (count > 1) {
         void* array = const_cast<void*>(arrayImpl());
-        void* temp = 0;
+        void* temp = nullptr;
         ssize_t i = 1;
         while (i < count) {
             void* item = reinterpret_cast<char*>(array) + mItemSize*(i);
@@ -205,7 +205,7 @@
                     _do_copy(next, curr, 1);
                     next = curr;
                     --j;
-                    curr = NULL;
+                    curr = nullptr;
                     if (j >= 0) {
                         curr = reinterpret_cast<char*>(array) + mItemSize*(j);
                     }
@@ -233,7 +233,7 @@
 
 void VectorImpl::push()
 {
-    push(0);
+    push(nullptr);
 }
 
 void VectorImpl::push(const void* item)
@@ -243,7 +243,7 @@
 
 ssize_t VectorImpl::add()
 {
-    return add(0);
+    return add(nullptr);
 }
 
 ssize_t VectorImpl::add(const void* item)
@@ -253,7 +253,7 @@
 
 ssize_t VectorImpl::replaceAt(size_t index)
 {
-    return replaceAt(0, index);
+    return replaceAt(nullptr, index);
 }
 
 ssize_t VectorImpl::replaceAt(const void* prototype, size_t index)
@@ -267,10 +267,10 @@
 
     void* item = editItemLocation(index);
     if (item != prototype) {
-        if (item == 0)
+        if (item == nullptr)
             return NO_MEMORY;
         _do_destroy(item, 1);
-        if (prototype == 0) {
+        if (prototype == nullptr) {
             _do_construct(item, 1);
         } else {
             _do_copy(item, prototype, 1);
@@ -294,7 +294,7 @@
 void VectorImpl::finish_vector()
 {
     release_storage();
-    mStorage = 0;
+    mStorage = nullptr;
     mCount = 0;
 }
 
@@ -315,7 +315,7 @@
             return reinterpret_cast<char*>(buffer) + index*mItemSize;
         }
     }
-    return 0;
+    return nullptr;
 }
 
 const void* VectorImpl::itemLocation(size_t index) const
@@ -330,7 +330,7 @@
             return reinterpret_cast<const char*>(buffer) + index*mItemSize;
         }
     }
-    return 0;
+    return nullptr;
 }
 
 ssize_t VectorImpl::setCapacity(size_t new_capacity)
@@ -418,7 +418,7 @@
             if (sb) {
                 mStorage = sb->data();
             } else {
-                return NULL;
+                return nullptr;
             }
         } else {
             SharedBuffer* sb = SharedBuffer::alloc(new_alloc_size);
@@ -435,7 +435,7 @@
                 release_storage();
                 mStorage = const_cast<void*>(array);
             } else {
-                return NULL;
+                return nullptr;
             }
         }
     } else {
diff --git a/libutils/include/utils/Condition.h b/libutils/include/utils/Condition.h
index c8da67c..540ed82 100644
--- a/libutils/include/utils/Condition.h
+++ b/libutils/include/utils/Condition.h
@@ -124,7 +124,7 @@
 #else // __APPLE__
     // Apple doesn't support POSIX clocks.
     struct timeval t;
-    gettimeofday(&t, NULL);
+    gettimeofday(&t, nullptr);
     ts.tv_sec = t.tv_sec;
     ts.tv_nsec = t.tv_usec*1000;
 #endif
diff --git a/libutils/include/utils/Looper.h b/libutils/include/utils/Looper.h
index 4509d75..c439c5c 100644
--- a/libutils/include/utils/Looper.h
+++ b/libutils/include/utils/Looper.h
@@ -24,6 +24,8 @@
 
 #include <sys/epoll.h>
 
+#include <android-base/unique_fd.h>
+
 namespace android {
 
 /*
@@ -447,7 +449,7 @@
 
     const bool mAllowNonCallbacks; // immutable
 
-    int mWakeEventFd;  // immutable
+    android::base::unique_fd mWakeEventFd;  // immutable
     Mutex mLock;
 
     Vector<MessageEnvelope> mMessageEnvelopes; // guarded by mLock
@@ -457,7 +459,7 @@
     // any use of it is racy anyway.
     volatile bool mPolling;
 
-    int mEpollFd; // guarded by mLock but only modified on the looper thread
+    android::base::unique_fd mEpollFd;  // guarded by mLock but only modified on the looper thread
     bool mEpollRebuildRequired; // guarded by mLock
 
     // Locked list of file descriptor monitoring requests.
diff --git a/libutils/include/utils/LruCache.h b/libutils/include/utils/LruCache.h
index 89dccd6..36775d0 100644
--- a/libutils/include/utils/LruCache.h
+++ b/libutils/include/utils/LruCache.h
@@ -71,7 +71,7 @@
         Entry* parent;
         Entry* child;
 
-        Entry(TKey _key, TValue _value) : key(_key), value(_value), parent(NULL), child(NULL) {
+        Entry(TKey _key, TValue _value) : key(_key), value(_value), parent(nullptr), child(nullptr) {
         }
         const TKey& getKey() const final { return key; }
     };
@@ -162,9 +162,9 @@
 template <typename TKey, typename TValue>
 LruCache<TKey, TValue>::LruCache(uint32_t maxCapacity)
     : mSet(new LruCacheSet())
-    , mListener(NULL)
-    , mOldest(NULL)
-    , mYoungest(NULL)
+    , mListener(nullptr)
+    , mOldest(nullptr)
+    , mYoungest(nullptr)
     , mMaxCapacity(maxCapacity)
     , mNullValue(0) {
     mSet->max_load_factor(1.0);
@@ -236,7 +236,7 @@
 
 template <typename TKey, typename TValue>
 bool LruCache<TKey, TValue>::removeOldest() {
-    if (mOldest != NULL) {
+    if (mOldest != nullptr) {
         return remove(mOldest->key);
         // TODO: should probably abort if false
     }
@@ -254,12 +254,12 @@
 template <typename TKey, typename TValue>
 void LruCache<TKey, TValue>::clear() {
     if (mListener) {
-        for (Entry* p = mOldest; p != NULL; p = p->child) {
+        for (Entry* p = mOldest; p != nullptr; p = p->child) {
             (*mListener)(p->key, p->value);
         }
     }
-    mYoungest = NULL;
-    mOldest = NULL;
+    mYoungest = nullptr;
+    mOldest = nullptr;
     for (auto entry : *mSet.get()) {
         delete entry;
     }
@@ -268,7 +268,7 @@
 
 template <typename TKey, typename TValue>
 void LruCache<TKey, TValue>::attachToCache(Entry& entry) {
-    if (mYoungest == NULL) {
+    if (mYoungest == nullptr) {
         mYoungest = mOldest = &entry;
     } else {
         entry.parent = mYoungest;
@@ -279,19 +279,19 @@
 
 template <typename TKey, typename TValue>
 void LruCache<TKey, TValue>::detachFromCache(Entry& entry) {
-    if (entry.parent != NULL) {
+    if (entry.parent != nullptr) {
         entry.parent->child = entry.child;
     } else {
         mOldest = entry.child;
     }
-    if (entry.child != NULL) {
+    if (entry.child != nullptr) {
         entry.child->parent = entry.parent;
     } else {
         mYoungest = entry.parent;
     }
 
-    entry.parent = NULL;
-    entry.child = NULL;
+    entry.parent = nullptr;
+    entry.child = nullptr;
 }
 
 }
diff --git a/libutils/include/utils/Printer.h b/libutils/include/utils/Printer.h
index a6f6928..7465927 100644
--- a/libutils/include/utils/Printer.h
+++ b/libutils/include/utils/Printer.h
@@ -45,7 +45,7 @@
     // (Note that the default ALOG behavior is to ignore blank lines)
     LogPrinter(const char* logtag,
                android_LogPriority priority = ANDROID_LOG_DEBUG,
-               const char* prefix = 0,
+               const char* prefix = nullptr,
                bool ignoreBlankLines = false);
 
     // Print the specified line to logcat. No \n at the end is necessary.
@@ -66,7 +66,7 @@
     // Create a printer using the specified file descriptor.
     // - Each line will be prefixed with 'indent' number of blank spaces.
     // - In addition, each line will be prefixed with the 'prefix' string.
-    FdPrinter(int fd, unsigned int indent = 0, const char* prefix = 0);
+    FdPrinter(int fd, unsigned int indent = 0, const char* prefix = nullptr);
 
     // Print the specified line to the file descriptor. \n is appended automatically.
     virtual void printLine(const char* string);
@@ -90,7 +90,7 @@
     // Create a printer using the specified String8 as the target.
     // - In addition, each line will be prefixed with the 'prefix' string.
     // - target's memory lifetime must be a superset of this String8Printer.
-    String8Printer(String8* target, const char* prefix = 0);
+    String8Printer(String8* target, const char* prefix = nullptr);
 
     // Append the specified line to the String8. \n is appended automatically.
     virtual void printLine(const char* string);
diff --git a/libutils/include/utils/ProcessCallStack.h b/libutils/include/utils/ProcessCallStack.h
index b5f2edc..7e06086 100644
--- a/libutils/include/utils/ProcessCallStack.h
+++ b/libutils/include/utils/ProcessCallStack.h
@@ -43,13 +43,13 @@
 
     // Print all stack traces to the log using the supplied logtag.
     void log(const char* logtag, android_LogPriority priority = ANDROID_LOG_DEBUG,
-             const char* prefix = 0) const;
+             const char* prefix = nullptr) const;
 
     // Dump all stack traces to the specified file descriptor.
-    void dump(int fd, int indent = 0, const char* prefix = 0) const;
+    void dump(int fd, int indent = 0, const char* prefix = nullptr) const;
 
     // Return a string (possibly very long) containing all the stack traces.
-    String8 toString(const char* prefix = 0) const;
+    String8 toString(const char* prefix = nullptr) const;
 
     // Dump a serialized representation of all the stack traces to the specified printer.
     void print(Printer& printer) const;
diff --git a/libutils/include/utils/RefBase.h b/libutils/include/utils/RefBase.h
index 13b6a2b..1780cf2 100644
--- a/libutils/include/utils/RefBase.h
+++ b/libutils/include/utils/RefBase.h
@@ -563,7 +563,7 @@
 wp<T>& wp<T>::operator = (const sp<U>& other)
 {
     weakref_type* newRefs =
-        other != NULL ? other->createWeak(this) : 0;
+        other != nullptr ? other->createWeak(this) : 0;
     U* otherPtr(other.m_ptr);
     if (m_ptr) m_refs->decWeak(this);
     m_ptr = otherPtr;
diff --git a/libutils/misc.cpp b/libutils/misc.cpp
index f074341..f77e189 100644
--- a/libutils/misc.cpp
+++ b/libutils/misc.cpp
@@ -41,13 +41,13 @@
 
 #if !defined(_WIN32)
 static pthread_mutex_t gSyspropMutex = PTHREAD_MUTEX_INITIALIZER;
-static Vector<sysprop_change_callback_info>* gSyspropList = NULL;
+static Vector<sysprop_change_callback_info>* gSyspropList = nullptr;
 #endif
 
 #if !defined(_WIN32)
 void add_sysprop_change_callback(sysprop_change_callback cb, int priority) {
     pthread_mutex_lock(&gSyspropMutex);
-    if (gSyspropList == NULL) {
+    if (gSyspropList == nullptr) {
         gSyspropList = new Vector<sysprop_change_callback_info>();
     }
     sysprop_change_callback_info info;
@@ -103,7 +103,7 @@
 #if !defined(_WIN32)
     pthread_mutex_lock(&gSyspropMutex);
     Vector<sysprop_change_callback_info> listeners;
-    if (gSyspropList != NULL) {
+    if (gSyspropList != nullptr) {
         listeners = *gSyspropList;
     }
     pthread_mutex_unlock(&gSyspropMutex);
diff --git a/libutils/tests/Looper_test.cpp b/libutils/tests/Looper_test.cpp
index 8ebcfaf..2282ced 100644
--- a/libutils/tests/Looper_test.cpp
+++ b/libutils/tests/Looper_test.cpp
@@ -339,7 +339,7 @@
     Pipe pipe;
 
     pipe.writeSignal();
-    mLooper->addFd(pipe.receiveFd, expectedIdent, Looper::EVENT_INPUT, NULL, expectedData);
+    mLooper->addFd(pipe.receiveFd, expectedIdent, Looper::EVENT_INPUT, nullptr, expectedData);
 
     StopWatch stopWatch("pollOnce");
     int fd;
@@ -364,7 +364,7 @@
 
 TEST_F(LooperTest, AddFd_WhenCallbackAdded_ReturnsOne) {
     Pipe pipe;
-    int result = mLooper->addFd(pipe.receiveFd, 0, Looper::EVENT_INPUT, NULL, NULL);
+    int result = mLooper->addFd(pipe.receiveFd, 0, Looper::EVENT_INPUT, nullptr, nullptr);
 
     EXPECT_EQ(1, result)
             << "addFd should return 1 because FD was added";
@@ -372,7 +372,7 @@
 
 TEST_F(LooperTest, AddFd_WhenIdentIsNegativeAndCallbackIsNull_ReturnsError) {
     Pipe pipe;
-    int result = mLooper->addFd(pipe.receiveFd, -1, Looper::EVENT_INPUT, NULL, NULL);
+    int result = mLooper->addFd(pipe.receiveFd, -1, Looper::EVENT_INPUT, nullptr, nullptr);
 
     EXPECT_EQ(-1, result)
             << "addFd should return -1 because arguments were invalid";
@@ -381,7 +381,7 @@
 TEST_F(LooperTest, AddFd_WhenNoCallbackAndAllowNonCallbacksIsFalse_ReturnsError) {
     Pipe pipe;
     sp<Looper> looper = new Looper(false /*allowNonCallbacks*/);
-    int result = looper->addFd(pipe.receiveFd, 0, 0, NULL, NULL);
+    int result = looper->addFd(pipe.receiveFd, 0, 0, nullptr, nullptr);
 
     EXPECT_EQ(-1, result)
             << "addFd should return -1 because arguments were invalid";
diff --git a/libutils/tests/LruCache_test.cpp b/libutils/tests/LruCache_test.cpp
index 4e885bb..c4d917b 100644
--- a/libutils/tests/LruCache_test.cpp
+++ b/libutils/tests/LruCache_test.cpp
@@ -110,7 +110,7 @@
 
 class EntryRemovedCallback : public OnEntryRemoved<SimpleKey, StringValue> {
 public:
-    EntryRemovedCallback() : callbackCount(0), lastKey(-1), lastValue(NULL) { }
+    EntryRemovedCallback() : callbackCount(0), lastKey(-1), lastValue(nullptr) { }
     ~EntryRemovedCallback() {}
     void operator()(SimpleKey& k, StringValue& v) {
         callbackCount += 1;
@@ -153,7 +153,7 @@
 TEST_F(LruCacheTest, Empty) {
     LruCache<SimpleKey, StringValue> cache(100);
 
-    EXPECT_EQ(NULL, cache.get(0));
+    EXPECT_EQ(nullptr, cache.get(0));
     EXPECT_EQ(0u, cache.size());
 }
 
@@ -175,7 +175,7 @@
     cache.put(1, "one");
     cache.put(2, "two");
     cache.put(3, "three");
-    EXPECT_EQ(NULL, cache.get(1));
+    EXPECT_EQ(nullptr, cache.get(1));
     EXPECT_STREQ("two", cache.get(2));
     EXPECT_STREQ("three", cache.get(3));
     EXPECT_EQ(2u, cache.size());
@@ -188,7 +188,7 @@
     cache.put(2, "two");
     cache.put(3, "three");
     cache.removeOldest();
-    EXPECT_EQ(NULL, cache.get(1));
+    EXPECT_EQ(nullptr, cache.get(1));
     EXPECT_STREQ("two", cache.get(2));
     EXPECT_STREQ("three", cache.get(3));
     EXPECT_EQ(2u, cache.size());
@@ -203,7 +203,7 @@
     EXPECT_STREQ("one", cache.get(1));
     cache.removeOldest();
     EXPECT_STREQ("one", cache.get(1));
-    EXPECT_EQ(NULL, cache.get(2));
+    EXPECT_EQ(nullptr, cache.get(2));
     EXPECT_STREQ("three", cache.get(3));
     EXPECT_EQ(2u, cache.size());
 }
@@ -230,7 +230,7 @@
         int index = random() % kNumKeys;
         uint32_t key = hash_int(index);
         const char *val = cache.get(key);
-        if (val != NULL) {
+        if (val != nullptr) {
             EXPECT_EQ(strings[index], val);
             hitCount++;
         } else {
diff --git a/libutils/tests/Vector_test.cpp b/libutils/tests/Vector_test.cpp
index e074a92..5336c40 100644
--- a/libutils/tests/Vector_test.cpp
+++ b/libutils/tests/Vector_test.cpp
@@ -98,7 +98,7 @@
 
   // Checks that the size calculation (not the capacity calculation) doesn't
   // overflow : the size here will be (1 + SIZE_MAX).
-  EXPECT_DEATH(vector.insertArrayAt(NULL, 0, SIZE_MAX), "new_size overflow");
+  EXPECT_DEATH(vector.insertArrayAt(nullptr, 0, SIZE_MAX), "new_size overflow");
 }
 
 TEST_F(VectorTest, _grow_OverflowCapacityDoubling) {
@@ -106,14 +106,14 @@
 
   // This should fail because the calculated capacity will overflow even though
   // the size of the vector doesn't.
-  EXPECT_DEATH(vector.insertArrayAt(NULL, 0, (SIZE_MAX - 1)), "new_capacity overflow");
+  EXPECT_DEATH(vector.insertArrayAt(nullptr, 0, (SIZE_MAX - 1)), "new_capacity overflow");
 }
 
 TEST_F(VectorTest, _grow_OverflowBufferAlloc) {
   Vector<int> vector;
   // This should fail because the capacity * sizeof(int) overflows, even
   // though the capacity itself doesn't.
-  EXPECT_DEATH(vector.insertArrayAt(NULL, 0, (SIZE_MAX / 2)), "new_alloc_size overflow");
+  EXPECT_DEATH(vector.insertArrayAt(nullptr, 0, (SIZE_MAX / 2)), "new_alloc_size overflow");
 }
 
 TEST_F(VectorTest, editArray_Shared) {
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 5e5e7af..9536fc7 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -33,6 +33,10 @@
 #include <memory>
 #include <vector>
 
+#if defined(__BIONIC__)
+#include <android/fdsan.h>
+#endif
+
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/macros.h>  // TEMP_FAILURE_RETRY may or may not be in unistd
@@ -165,6 +169,44 @@
   return 0;
 }
 
+ZipArchive::ZipArchive(const int fd, bool assume_ownership)
+    : mapped_zip(fd),
+      close_file(assume_ownership),
+      directory_offset(0),
+      central_directory(),
+      directory_map(new android::FileMap()),
+      num_entries(0),
+      hash_table_size(0),
+      hash_table(nullptr) {
+#if defined(__BIONIC__)
+  if (assume_ownership) {
+    android_fdsan_exchange_owner_tag(fd, 0, reinterpret_cast<uint64_t>(this));
+  }
+#endif
+}
+
+ZipArchive::ZipArchive(void* address, size_t length)
+    : mapped_zip(address, length),
+      close_file(false),
+      directory_offset(0),
+      central_directory(),
+      directory_map(new android::FileMap()),
+      num_entries(0),
+      hash_table_size(0),
+      hash_table(nullptr) {}
+
+ZipArchive::~ZipArchive() {
+  if (close_file && mapped_zip.GetFileDescriptor() >= 0) {
+#if defined(__BIONIC__)
+    android_fdsan_close_with_tag(mapped_zip.GetFileDescriptor(), reinterpret_cast<uint64_t>(this));
+#else
+    close(mapped_zip.GetFileDescriptor());
+#endif
+  }
+
+  free(hash_table);
+}
+
 static int32_t MapCentralDirectory0(const char* debug_file_name, ZipArchive* archive,
                                     off64_t file_length, off64_t read_amount, uint8_t* scan_buffer) {
   const off64_t search_start = file_length - read_amount;
diff --git a/libziparchive/zip_archive_private.h b/libziparchive/zip_archive_private.h
index 18e0229..0a73300 100644
--- a/libziparchive/zip_archive_private.h
+++ b/libziparchive/zip_archive_private.h
@@ -156,33 +156,9 @@
   uint32_t hash_table_size;
   ZipString* hash_table;
 
-  ZipArchive(const int fd, bool assume_ownership)
-      : mapped_zip(fd),
-        close_file(assume_ownership),
-        directory_offset(0),
-        central_directory(),
-        directory_map(new android::FileMap()),
-        num_entries(0),
-        hash_table_size(0),
-        hash_table(nullptr) {}
-
-  ZipArchive(void* address, size_t length)
-      : mapped_zip(address, length),
-        close_file(false),
-        directory_offset(0),
-        central_directory(),
-        directory_map(new android::FileMap()),
-        num_entries(0),
-        hash_table_size(0),
-        hash_table(nullptr) {}
-
-  ~ZipArchive() {
-    if (close_file && mapped_zip.GetFileDescriptor() >= 0) {
-      close(mapped_zip.GetFileDescriptor());
-    }
-
-    free(hash_table);
-  }
+  ZipArchive(const int fd, bool assume_ownership);
+  ZipArchive(void* address, size_t length);
+  ~ZipArchive();
 
   bool InitializeCentralDirectory(const char* debug_file_name, off64_t cd_start_offset,
                                   size_t cd_size);
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 1cfef34..c2487d6 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -332,7 +332,7 @@
         data->fd = -1;
         return -1;
     }
-    ALOG_ASSERT((size_t)size < buf_size - 1, data->filename " too large");
+    ALOG_ASSERT((size_t)size < buf_size - 1, "%s too large", data->filename);
     buf[size] = 0;
 
     return 0;
diff --git a/mkbootimg/Android.bp b/mkbootimg/Android.bp
index b494346..576a677 100644
--- a/mkbootimg/Android.bp
+++ b/mkbootimg/Android.bp
@@ -9,6 +9,7 @@
 cc_library_headers {
     name: "bootimg_headers",
     vendor_available: true,
+    recovery_available: true,
     export_include_dirs: ["include/bootimg"],
     host_supported: true,
     target: {
diff --git a/property_service/libpropertyinfoserializer/Android.bp b/property_service/libpropertyinfoserializer/Android.bp
index 3c4bdc3..51c1226 100644
--- a/property_service/libpropertyinfoserializer/Android.bp
+++ b/property_service/libpropertyinfoserializer/Android.bp
@@ -17,6 +17,7 @@
 cc_library_static {
     name: "libpropertyinfoserializer",
     defaults: ["propertyinfoserializer_defaults"],
+    recovery_available: true,
     srcs: [
         "property_info_file.cpp",
         "property_info_serializer.cpp",
diff --git a/trusty/OWNERS b/trusty/OWNERS
index 357b4f4..e807d71 100644
--- a/trusty/OWNERS
+++ b/trusty/OWNERS
@@ -1,3 +1,7 @@
-bohr@google.com
-swillden@google.com
+arve@google.com
 dkrahn@google.com
+drewry@google.com
+gmar@google.com
+ncbray@google.com
+rpere@google.com
+swillden@google.com
diff --git a/trusty/libtrusty/tipc-test/tipc_test.c b/trusty/libtrusty/tipc-test/tipc_test.c
index 1fb34c9..d20d4ee 100644
--- a/trusty/libtrusty/tipc-test/tipc_test.c
+++ b/trusty/libtrusty/tipc-test/tipc_test.c
@@ -587,8 +587,15 @@
 
 static int ta2ta_ipc_test(void)
 {
+	enum test_message_header {
+		TEST_PASSED = 0,
+		TEST_FAILED = 1,
+		TEST_MESSAGE = 2,
+	};
+
 	int fd;
-	char rx_buf[64];
+	int ret;
+	unsigned char rx_buf[256];
 
 	if (!opt_silent) {
 		printf("%s:\n", __func__);
@@ -601,12 +608,31 @@
 		return fd;
 	}
 
-	/* wait for test to complete */
-	(void) read(fd, rx_buf, sizeof(rx_buf));
+	/* Wait for tests to complete and read status */
+	while (true) {
+		ret = read(fd, rx_buf, sizeof(rx_buf));
+		if (ret <= 0 || ret >= (int)sizeof(rx_buf)) {
+			fprintf(stderr, "%s: Read failed: %d\n", __func__, ret);
+			tipc_close(fd);
+			return -1;
+		}
+
+		if (rx_buf[0] == TEST_PASSED) {
+			break;
+		} else if (rx_buf[0] == TEST_FAILED) {
+			break;
+		} else if (rx_buf[0] == TEST_MESSAGE) {
+			write(STDOUT_FILENO, rx_buf + 1, ret - 1);
+		} else {
+			fprintf(stderr, "%s: Bad message header: %d\n",
+			        __func__, rx_buf[0]);
+			break;
+		}
+	}
 
 	tipc_close(fd);
 
-	return 0;
+	return rx_buf[0] == TEST_PASSED ? 0 : -1;
 }
 
 typedef struct uuid