Merge "Tolerate RTM_DELADDR messages from deleted interfaces." into nyc-dev
am: 8bb06b6493

* commit '8bb06b6493bf7c999a8749aa0e0e17345ce513d2':
  Tolerate RTM_DELADDR messages from deleted interfaces.
diff --git a/adb/Android.mk b/adb/Android.mk
index d629223..b792bd4 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -58,6 +58,7 @@
 LIBADB_TEST_SRCS := \
     adb_io_test.cpp \
     adb_utils_test.cpp \
+    sysdeps_test.cpp \
     transport_test.cpp \
 
 LIBADB_CFLAGS := \
@@ -157,7 +158,7 @@
 
 LOCAL_SANITIZE := $(adb_target_sanitize)
 LOCAL_STATIC_LIBRARIES := libadbd
-LOCAL_SHARED_LIBRARIES := libbase libcutils
+LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
 include $(BUILD_NATIVE_TEST)
 
 # libdiagnose_usb
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 58ccd0a..cb54d04 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -883,8 +883,6 @@
             fprintf(stderr, "ADB server didn't ACK\n" );
             return -1;
         }
-
-        setsid();
     }
 #endif /* !defined(_WIN32) */
     return 0;
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 474d1b4..8a16e51 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -134,7 +134,7 @@
   return result;
 }
 
-// Given a relative or absolute filepath, create the parent directory hierarchy
+// Given a relative or absolute filepath, create the directory hierarchy
 // as needed. Returns true if the hierarchy is/was setup.
 bool mkdirs(const std::string& path) {
   // TODO: all the callers do unlink && mkdirs && adb_creat ---
@@ -157,12 +157,12 @@
     return true;
   }
 
+  const std::string parent(adb_dirname(path));
+
   // If dirname returned the same path as what we passed in, don't go recursive.
   // This can happen on Windows when walking up the directory hierarchy and not
   // finding anything that already exists (unlike POSIX that will eventually
   // find . or /).
-  const std::string parent(adb_dirname(path));
-
   if (parent == path) {
     errno = ENOENT;
     return false;
@@ -174,14 +174,14 @@
   }
 
   // Now that the parent directory hierarchy of 'path' has been ensured,
-  // create parent itself.
+  // create path itself.
   if (adb_mkdir(path, 0775) == -1) {
-    // Can't just check for errno == EEXIST because it might be a file that
-    // exists.
     const int saved_errno = errno;
-    if (directory_exists(parent)) {
+    // If someone else created the directory, that is ok.
+    if (directory_exists(path)) {
       return true;
     }
+    // There might be a pre-existing file at 'path', or there might have been some other error.
     errno = saved_errno;
     return false;
   }
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index 794dce6..f1ebaa1 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -112,20 +112,26 @@
 }
 
 void test_mkdirs(const std::string basepath) {
+  // Test creating a directory hierarchy.
   EXPECT_TRUE(mkdirs(basepath));
-  EXPECT_NE(-1, adb_creat(basepath.c_str(), 0600));
-  EXPECT_FALSE(mkdirs(basepath + "/subdir/"));
+  // Test finding an existing directory hierarchy.
+  EXPECT_TRUE(mkdirs(basepath));
+  const std::string filepath = basepath + "/file";
+  // Verify that the hierarchy was created by trying to create a file in it.
+  EXPECT_NE(-1, adb_creat(filepath.c_str(), 0600));
+  // If a file exists where we want a directory, the operation should fail.
+  EXPECT_FALSE(mkdirs(filepath));
 }
 
 TEST(adb_utils, mkdirs) {
   TemporaryDir td;
 
   // Absolute paths.
-  test_mkdirs(std::string(td.path) + "/dir/subdir/file");
+  test_mkdirs(std::string(td.path) + "/dir/subdir");
 
   // Relative paths.
   ASSERT_EQ(0, chdir(td.path)) << strerror(errno);
-  test_mkdirs(std::string("relative/subrel/file"));
+  test_mkdirs(std::string("relative/subrel"));
 }
 
 #if !defined(_WIN32)
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index b7b30c5..27b7109 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -21,6 +21,7 @@
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <unistd.h>
 
 // We only build the affinity WAR code for Linux.
 #if defined(__linux__)
@@ -125,6 +126,15 @@
         close_stdin();
         setup_daemon_logging();
 
+#if !defined(_WIN32)
+        // Start a new session for the daemon. Do this here instead of after the fork so
+        // that a ctrl-c between the "starting server" and "done starting server" messages
+        // gets a chance to terminate the server.
+        if (setsid() == -1) {
+            fatal("setsid() failed: %s", strerror(errno));
+        }
+#endif
+
         // Any error output written to stderr now goes to adb.log. We could
         // keep around a copy of the stderr fd and use that to write any errors
         // encountered by the following code, but that is probably overkill.
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 85ab4d1..8e76168 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -482,7 +482,7 @@
 // Loops to read from stdin and push the data to the given FD.
 // The argument should be a pointer to a StdinReadArgs object. This function
 // will take ownership of the object and delete it when finished.
-static void* stdin_read_thread_loop(void* x) {
+static void stdin_read_thread_loop(void* x) {
     std::unique_ptr<StdinReadArgs> args(reinterpret_cast<StdinReadArgs*>(x));
 
 #if !defined(_WIN32)
@@ -586,8 +586,6 @@
             }
         }
     }
-
-    return nullptr;
 }
 
 // Returns a shell service string with the indicated arguments and command.
diff --git a/adb/services.cpp b/adb/services.cpp
index 9cbf787..75cbe5d 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -57,13 +57,11 @@
     void *cookie;
 };
 
-void *service_bootstrap_func(void *x)
-{
+static void service_bootstrap_func(void* x) {
     stinfo* sti = reinterpret_cast<stinfo*>(x);
     adb_thread_setname(android::base::StringPrintf("service %d", sti->fd));
     sti->func(sti->fd, sti->cookie);
     free(sti);
-    return 0;
 }
 
 #if !ADB_HOST
diff --git a/adb/shell_service.cpp b/adb/shell_service.cpp
index d080e09..f84447f 100644
--- a/adb/shell_service.cpp
+++ b/adb/shell_service.cpp
@@ -198,7 +198,7 @@
     // Opens the file at |pts_name|.
     int OpenPtyChildFd(const char* pts_name, ScopedFd* error_sfd);
 
-    static void* ThreadHandler(void* userdata);
+    static void ThreadHandler(void* userdata);
     void PassDataStreams();
     void WaitForExit();
 
@@ -465,7 +465,7 @@
     return child_fd;
 }
 
-void* Subprocess::ThreadHandler(void* userdata) {
+void Subprocess::ThreadHandler(void* userdata) {
     Subprocess* subprocess = reinterpret_cast<Subprocess*>(userdata);
 
     adb_thread_setname(android::base::StringPrintf(
@@ -475,8 +475,6 @@
 
     D("deleting Subprocess for PID %d", subprocess->pid());
     delete subprocess;
-
-    return nullptr;
 }
 
 void Subprocess::PassDataStreams() {
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 16796cd..3bae09e 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -30,6 +30,7 @@
 #include <vector>
 
 // Include this before open/unlink are defined as macros below.
+#include <android-base/errors.h>
 #include <android-base/utf8.h>
 
 /*
@@ -114,13 +115,62 @@
     LeaveCriticalSection( lock );
 }
 
-typedef  void*  (*adb_thread_func_t)(void*  arg);
+typedef void (*adb_thread_func_t)(void* arg);
+typedef HANDLE adb_thread_t;
 
-typedef  void (*win_thread_func_t)(void*  arg);
+struct adb_winthread_args {
+    adb_thread_func_t func;
+    void* arg;
+};
 
-static __inline__ bool adb_thread_create(adb_thread_func_t func, void* arg) {
-    uintptr_t tid = _beginthread((win_thread_func_t)func, 0, arg);
-    return (tid != static_cast<uintptr_t>(-1L));
+static unsigned __stdcall adb_winthread_wrapper(void* heap_args) {
+    // Move the arguments from the heap onto the thread's stack.
+    adb_winthread_args thread_args = *static_cast<adb_winthread_args*>(heap_args);
+    delete static_cast<adb_winthread_args*>(heap_args);
+    thread_args.func(thread_args.arg);
+    return 0;
+}
+
+static __inline__ bool adb_thread_create(adb_thread_func_t func, void* arg,
+                                         adb_thread_t* thread = nullptr) {
+    adb_winthread_args* args = new adb_winthread_args{.func = func, .arg = arg};
+    uintptr_t handle = _beginthreadex(nullptr, 0, adb_winthread_wrapper, args, 0, nullptr);
+    if (handle != static_cast<uintptr_t>(0)) {
+        if (thread) {
+            *thread = reinterpret_cast<HANDLE>(handle);
+        } else {
+            CloseHandle(thread);
+        }
+        return true;
+    }
+    return false;
+}
+
+static __inline__ bool adb_thread_join(adb_thread_t thread) {
+    switch (WaitForSingleObject(thread, INFINITE)) {
+        case WAIT_OBJECT_0:
+            CloseHandle(thread);
+            return true;
+
+        case WAIT_FAILED:
+            fprintf(stderr, "adb_thread_join failed: %s\n",
+                    android::base::SystemErrorCodeToString(GetLastError()).c_str());
+            break;
+
+        default:
+            abort();
+    }
+
+    return false;
+}
+
+static __inline__ bool adb_thread_detach(adb_thread_t thread) {
+    CloseHandle(thread);
+    return true;
+}
+
+static __inline__ void __attribute__((noreturn)) adb_thread_exit() {
+    _endthreadex(0);
 }
 
 static __inline__ int adb_thread_setname(const std::string& name) {
@@ -656,16 +706,53 @@
 #define  unix_write  adb_write
 #define  unix_close  adb_close
 
-typedef void*  (*adb_thread_func_t)( void*  arg );
+// Win32 is limited to DWORDs for thread return values; limit the POSIX systems to this as well to
+// ensure compatibility.
+typedef void (*adb_thread_func_t)(void* arg);
+typedef pthread_t adb_thread_t;
 
-static __inline__ bool adb_thread_create(adb_thread_func_t start, void* arg) {
+struct adb_pthread_args {
+    adb_thread_func_t func;
+    void* arg;
+};
+
+static void* adb_pthread_wrapper(void* heap_args) {
+    // Move the arguments from the heap onto the thread's stack.
+    adb_pthread_args thread_args = *reinterpret_cast<adb_pthread_args*>(heap_args);
+    delete static_cast<adb_pthread_args*>(heap_args);
+    thread_args.func(thread_args.arg);
+    return nullptr;
+}
+
+static __inline__ bool adb_thread_create(adb_thread_func_t start, void* arg,
+                                         adb_thread_t* thread = nullptr) {
+    pthread_t temp;
     pthread_attr_t attr;
     pthread_attr_init(&attr);
-    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+    pthread_attr_setdetachstate(&attr, thread ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED);
+    auto* pthread_args = new adb_pthread_args{.func = start, .arg = arg};
+    errno = pthread_create(&temp, &attr, adb_pthread_wrapper, pthread_args);
+    if (errno == 0) {
+        if (thread) {
+            *thread = temp;
+        }
+        return true;
+    }
+    return false;
+}
 
-    pthread_t thread;
-    errno = pthread_create(&thread, &attr, start, arg);
-    return (errno == 0);
+static __inline__ bool adb_thread_join(adb_thread_t thread) {
+    errno = pthread_join(thread, nullptr);
+    return errno == 0;
+}
+
+static __inline__ bool adb_thread_detach(adb_thread_t thread) {
+    errno = pthread_detach(thread);
+    return errno == 0;
+}
+
+static __inline__ void __attribute__((noreturn)) adb_thread_exit() {
+    pthread_exit(nullptr);
 }
 
 static __inline__ int adb_thread_setname(const std::string& name) {
diff --git a/adb/sysdeps_test.cpp b/adb/sysdeps_test.cpp
new file mode 100644
index 0000000..360eaa7
--- /dev/null
+++ b/adb/sysdeps_test.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 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 <gtest/gtest.h>
+#include <unistd.h>
+#include <atomic>
+
+#include "sysdeps.h"
+
+static void increment_atomic_int(void* c) {
+    sleep(1);
+    reinterpret_cast<std::atomic<int>*>(c)->fetch_add(1);
+}
+
+TEST(sysdeps_thread, smoke) {
+    std::atomic<int> counter(0);
+
+    for (int i = 0; i < 100; ++i) {
+        ASSERT_TRUE(adb_thread_create(increment_atomic_int, &counter));
+    }
+
+    sleep(2);
+    ASSERT_EQ(100, counter.load());
+}
+
+TEST(sysdeps_thread, join) {
+    std::atomic<int> counter(0);
+    std::vector<adb_thread_t> threads(500);
+    for (size_t i = 0; i < threads.size(); ++i) {
+        ASSERT_TRUE(adb_thread_create(increment_atomic_int, &counter, &threads[i]));
+    }
+
+    int current = counter.load();
+    ASSERT_GE(current, 0);
+    // Make sure that adb_thread_create actually creates threads, and doesn't do something silly
+    // like synchronously run the function passed in. The sleep in increment_atomic_int should be
+    // enough to keep this from being flakey.
+    ASSERT_LT(current, 500);
+
+    for (const auto& thread : threads) {
+        ASSERT_TRUE(adb_thread_join(thread));
+    }
+
+    ASSERT_EQ(500, counter.load());
+}
+
+TEST(sysdeps_thread, exit) {
+    adb_thread_t thread;
+    ASSERT_TRUE(adb_thread_create(
+        [](void*) {
+            adb_thread_exit();
+            for (;;) continue;
+        },
+        nullptr, &thread));
+    ASSERT_TRUE(adb_thread_join(thread));
+}
diff --git a/adb/sysdeps_win32_test.cpp b/adb/sysdeps_win32_test.cpp
index 8f610cf..c3a3fd7 100755
--- a/adb/sysdeps_win32_test.cpp
+++ b/adb/sysdeps_win32_test.cpp
@@ -87,8 +87,12 @@
     TestAdbStrError(-1, "Unknown error");
     // Test very big, positive unknown error.
     TestAdbStrError(1000000, "Unknown error");
+
     // Test success case.
-    TestAdbStrError(0, "No error");
+    // Wine returns "Success" for strerror(0), Windows returns "No error", so accept both.
+    std::string success = adb_strerror(0);
+    EXPECT_TRUE(success == "Success" || success == "No error") << "strerror(0) = " << success;
+
     // Test error that regular strerror() should have a string for.
     TestAdbStrError(EPERM, "Operation not permitted");
     // Test error that regular strerror() doesn't have a string for, but that
diff --git a/adb/transport.cpp b/adb/transport.cpp
index f8c8c61..8ca1e49 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -190,8 +190,7 @@
 //
 // read_transport thread reads data from a transport (representing a usb/tcp connection),
 // and makes the main thread call handle_packet().
-static void *read_transport_thread(void *_t)
-{
+static void read_transport_thread(void* _t) {
     atransport *t = reinterpret_cast<atransport*>(_t);
     apacket *p;
 
@@ -244,13 +243,11 @@
     D("%s: read_transport thread is exiting", t->serial);
     kick_transport(t);
     transport_unref(t);
-    return 0;
 }
 
 // write_transport thread gets packets sent by the main thread (through send_packet()),
 // and writes to a transport (representing a usb/tcp connection).
-static void *write_transport_thread(void *_t)
-{
+static void write_transport_thread(void* _t) {
     atransport *t = reinterpret_cast<atransport*>(_t);
     apacket *p;
     int active = 0;
@@ -295,7 +292,6 @@
     D("%s: write_transport thread is exiting, fd %d", t->serial, t->fd);
     kick_transport(t);
     transport_unref(t);
-    return 0;
 }
 
 static void kick_transport_locked(atransport* t) {
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index d2a375a..e6e699b 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -121,8 +121,7 @@
 }
 
 #if ADB_HOST
-static void *client_socket_thread(void *x)
-{
+static void client_socket_thread(void* x) {
     adb_thread_setname("client_socket_thread");
     D("transport: client_socket_thread() starting");
     while (true) {
@@ -135,13 +134,11 @@
         }
         sleep(1);
     }
-    return 0;
 }
 
 #else // ADB_HOST
 
-static void *server_socket_thread(void * arg)
-{
+static void server_socket_thread(void* arg) {
     int serverfd, fd;
     sockaddr_storage ss;
     sockaddr *addrp = reinterpret_cast<sockaddr*>(&ss);
@@ -174,7 +171,6 @@
         }
     }
     D("transport: server_socket_thread() exiting");
-    return 0;
 }
 
 /* This is relevant only for ADB daemon running inside the emulator. */
@@ -220,14 +216,13 @@
  *   the transport registration is completed. That's why we need to send the
  *   'start' request after the transport is registered.
  */
-static void *qemu_socket_thread(void * arg)
-{
-/* 'accept' request to the adb QEMUD service. */
-static const char _accept_req[] = "accept";
-/* 'start' request to the adb QEMUD service. */
-static const char _start_req[]  = "start";
-/* 'ok' reply from the adb QEMUD service. */
-static const char _ok_resp[]    = "ok";
+static void qemu_socket_thread(void* arg) {
+    /* 'accept' request to the adb QEMUD service. */
+    static const char _accept_req[] = "accept";
+    /* 'start' request to the adb QEMUD service. */
+    static const char _start_req[] = "start";
+    /* 'ok' reply from the adb QEMUD service. */
+    static const char _ok_resp[] = "ok";
 
     const int port = (int) (uintptr_t) arg;
     int res, fd;
@@ -247,7 +242,7 @@
          * implement adb QEMUD service. Fall back to the old TCP way. */
         D("adb service is not available. Falling back to TCP socket.");
         adb_thread_create(server_socket_thread, arg);
-        return 0;
+        return;
     }
 
     for(;;) {
@@ -275,21 +270,21 @@
             fd = qemu_pipe_open(con_name);
             if (fd < 0) {
                 D("adb service become unavailable.");
-                return 0;
+                return;
             }
         } else {
             D("Unable to send the '%s' request to ADB service.", _accept_req);
-            return 0;
+            return;
         }
     }
     D("transport: qemu_socket_thread() exiting");
-    return 0;
+    return;
 }
 #endif  // !ADB_HOST
 
 void local_init(int port)
 {
-    void* (*func)(void *);
+    adb_thread_func_t func;
     const char* debug_name = "";
 
 #if ADB_HOST
diff --git a/adb/usb_linux.cpp b/adb/usb_linux.cpp
index ed5d2d67..500898a 100644
--- a/adb/usb_linux.cpp
+++ b/adb/usb_linux.cpp
@@ -571,7 +571,7 @@
     register_usb_transport(done_usb, serial.c_str(), dev_path, done_usb->writeable);
 }
 
-static void* device_poll_thread(void* unused) {
+static void device_poll_thread(void*) {
     adb_thread_setname("device poll");
     D("Created device thread");
     while (true) {
@@ -580,7 +580,6 @@
         kick_disconnected_devices();
         sleep(1);
     }
-    return nullptr;
 }
 
 void usb_init() {
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index a4f1a70..c863ed2 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -232,10 +232,7 @@
     },
 };
 
-
-
-static void *usb_adb_open_thread(void *x)
-{
+static void usb_adb_open_thread(void* x) {
     struct usb_handle *usb = (struct usb_handle *)x;
     int fd;
 
@@ -270,7 +267,7 @@
     }
 
     // never gets here
-    return 0;
+    abort();
 }
 
 static int usb_adb_write(usb_handle *h, const void *data, int len)
@@ -434,8 +431,7 @@
     return;
 }
 
-static void *usb_ffs_open_thread(void *x)
-{
+static void usb_ffs_open_thread(void* x) {
     struct usb_handle *usb = (struct usb_handle *)x;
 
     adb_thread_setname("usb ffs open");
@@ -462,7 +458,7 @@
     }
 
     // never gets here
-    return 0;
+    abort();
 }
 
 static int usb_ffs_write(usb_handle* h, const void* data, int len) {
diff --git a/adb/usb_osx.cpp b/adb/usb_osx.cpp
index 148be1d..54d4c6c 100644
--- a/adb/usb_osx.cpp
+++ b/adb/usb_osx.cpp
@@ -400,9 +400,7 @@
     return NULL;
 }
 
-
-void* RunLoopThread(void* unused)
-{
+static void RunLoopThread(void* unused) {
     adb_thread_setname("RunLoop");
     InitUSB();
 
@@ -420,7 +418,6 @@
     IONotificationPortDestroy(notificationPort);
 
     LOG(DEBUG) << "RunLoopThread done";
-    return NULL;
 }
 
 static void usb_cleanup() {
diff --git a/adb/usb_windows.cpp b/adb/usb_windows.cpp
index e79008f..8ecca37 100644
--- a/adb/usb_windows.cpp
+++ b/adb/usb_windows.cpp
@@ -97,7 +97,7 @@
 
 /// Entry point for thread that polls (every second) for new usb interfaces.
 /// This routine calls find_devices in infinite loop.
-void* device_poll_thread(void* unused);
+static void device_poll_thread(void*);
 
 /// Initializes this module
 void usb_init();
@@ -172,7 +172,7 @@
   return 1;
 }
 
-void* device_poll_thread(void* unused) {
+void device_poll_thread(void*) {
   adb_thread_setname("Device Poll");
   D("Created device thread");
 
@@ -180,8 +180,6 @@
     find_devices();
     adb_sleep_ms(1000);
   }
-
-  return NULL;
 }
 
 static LRESULT CALLBACK _power_window_proc(HWND hwnd, UINT uMsg, WPARAM wParam,
@@ -203,7 +201,7 @@
   return DefWindowProcW(hwnd, uMsg, wParam, lParam);
 }
 
-static void* _power_notification_thread(void* unused) {
+static void _power_notification_thread(void*) {
   // This uses a thread with its own window message pump to get power
   // notifications. If adb runs from a non-interactive service account, this
   // might not work (not sure). If that happens to not work, we could use
@@ -255,8 +253,6 @@
   // shutting down. Not a big deal since the whole process will be going away
   // soon anyway.
   D("Power notification thread exiting");
-
-  return NULL;
 }
 
 void usb_init() {
diff --git a/base/file.cpp b/base/file.cpp
index bcdfc5e..da1adba 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -29,10 +29,6 @@
 #include "cutils/log.h"
 #include "utils/Compat.h"
 
-#if !defined(_WIN32)
-#define O_BINARY 0
-#endif
-
 namespace android {
 namespace base {
 
diff --git a/base/include/android-base/file.h b/base/include/android-base/file.h
index 486befc..5342d98 100644
--- a/base/include/android-base/file.h
+++ b/base/include/android-base/file.h
@@ -20,6 +20,10 @@
 #include <sys/stat.h>
 #include <string>
 
+#if !defined(_WIN32) && !defined(O_BINARY)
+#define O_BINARY 0
+#endif
+
 namespace android {
 namespace base {
 
diff --git a/base/logging.cpp b/base/logging.cpp
index a385902..1741871 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -68,7 +68,13 @@
 #include <windows.h>
 #endif
 
-static pid_t GetThreadId() {
+#if defined(_WIN32)
+typedef uint32_t thread_id;
+#else
+typedef pid_t thread_id;
+#endif
+
+static thread_id GetThreadId() {
 #if defined(__BIONIC__)
   return gettid();
 #elif defined(__APPLE__)
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index e0f7c73..a326f55 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -32,6 +32,7 @@
     protocol.cpp \
     socket.cpp \
     tcp.cpp \
+    udp.cpp \
     util.cpp \
 
 LOCAL_MODULE := fastboot
@@ -114,6 +115,8 @@
     socket_test.cpp \
     tcp.cpp \
     tcp_test.cpp \
+    udp.cpp \
+    udp_test.cpp \
 
 LOCAL_STATIC_LIBRARIES := libbase libcutils
 
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 7c7d417..636092e 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -59,6 +59,7 @@
 #include "fs.h"
 #include "tcp.h"
 #include "transport.h"
+#include "udp.h"
 #include "usb.h"
 
 #ifndef O_BINARY
@@ -245,22 +246,41 @@
         return transport;
     }
 
+    Socket::Protocol protocol = Socket::Protocol::kTcp;
     std::string host;
-    int port = tcp::kDefaultPort;
-    if (serial != nullptr && android::base::StartsWith(serial, "tcp:")) {
-        std::string error;
-        const char* address = serial + strlen("tcp:");
+    int port = 0;
+    if (serial != nullptr) {
+        const char* net_address = nullptr;
 
-        if (!android::base::ParseNetAddress(address, &host, &port, nullptr, &error)) {
-            fprintf(stderr, "error: Invalid network address '%s': %s\n", address, error.c_str());
-            return nullptr;
+        if (android::base::StartsWith(serial, "tcp:")) {
+            protocol = Socket::Protocol::kTcp;
+            port = tcp::kDefaultPort;
+            net_address = serial + strlen("tcp:");
+        } else if (android::base::StartsWith(serial, "udp:")) {
+            protocol = Socket::Protocol::kUdp;
+            port = udp::kDefaultPort;
+            net_address = serial + strlen("udp:");
+        }
+
+        if (net_address != nullptr) {
+            std::string error;
+            if (!android::base::ParseNetAddress(net_address, &host, &port, nullptr, &error)) {
+                fprintf(stderr, "error: Invalid network address '%s': %s\n", net_address,
+                        error.c_str());
+                return nullptr;
+            }
         }
     }
 
     while (true) {
         if (!host.empty()) {
             std::string error;
-            transport = tcp::Connect(host, port, &error).release();
+            if (protocol == Socket::Protocol::kTcp) {
+                transport = tcp::Connect(host, port, &error).release();
+            } else if (protocol == Socket::Protocol::kUdp) {
+                transport = udp::Connect(host, port, &error).release();
+            }
+
             if (transport == nullptr && announce) {
                 fprintf(stderr, "error: %s\n", error.c_str());
             }
@@ -337,8 +357,9 @@
             "                                           formatting.\n"
             "  -s <specific device>                     Specify a device. For USB, provide either\n"
             "                                           a serial number or path to device port.\n"
-            "                                           For TCP, provide an address in the form\n"
-            "                                           tcp:<hostname>[:port].\n"
+            "                                           For ethernet, provide an address in the"
+            "                                           form <protocol>:<hostname>[:port] where"
+            "                                           <protocol> is either tcp or udp.\n"
             "  -p <product>                             Specify product name.\n"
             "  -c <cmdline>                             Override kernel commandline.\n"
             "  -i <vendor id>                           Specify a custom USB vendor id.\n"
diff --git a/fastboot/fastboot_protocol.txt b/fastboot/fastboot_protocol.txt
index 4aa48b1..2801703 100644
--- a/fastboot/fastboot_protocol.txt
+++ b/fastboot/fastboot_protocol.txt
@@ -17,9 +17,9 @@
   * The protocol is entirely host-driven and synchronous (unlike the
     multi-channel, bi-directional, asynchronous ADB protocol)
 
-* TCP
+* TCP or UDP
   * Device must be reachable via IP.
-  * Device will act as the TCP server, fastboot will be the client.
+  * Device will act as the server, fastboot will be the client.
   * Fastboot data is wrapped in a simple protocol; see below for details.
 
 
@@ -217,3 +217,226 @@
 Host    [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x0B]getvar:none
 Device  [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x04]OKAY
 Host    <disconnect>
+
+
+UDP Protocol v1
+---------------
+
+The UDP protocol is more complex than TCP since we must implement reliability
+to ensure no packets are lost, but the general concept of wrapping the fastboot
+protocol is the same.
+
+Overview:
+  1. As with TCP, the device will listen on UDP port 5554.
+  2. Maximum UDP packet size is negotiated during initialization.
+  3. The host drives all communication; the device may only send a packet as a
+     response to a host packet.
+  4. If the host does not receive a response in 500ms it will re-transmit.
+
+-- UDP Packet format --
+  +----------+----+-------+-------+--------------------+
+  | Byte #   | 0  |   1   | 2 - 3 |  4+                |
+  +----------+----+-------+-------+--------------------+
+  | Contents | ID | Flags | Seq # | Data               |
+  +----------+----+-------+-------+--------------------+
+
+  ID      Packet ID:
+            0x00: Error.
+            0x01: Query.
+            0x02: Initialization.
+            0x03: Fastboot.
+
+          Packet types are described in more detail below.
+
+  Flags   Packet flags: 0 0 0 0 0 0 0 C
+            C=1 indicates a continuation packet; the data is too large and will
+                continue in the next packet.
+
+            Remaining bits are reserved for future use and must be set to 0.
+
+  Seq #   2-byte packet sequence number (big-endian). The host will increment
+          this by 1 with each new packet, and the device must provide the
+          corresponding sequence number in the response packets.
+
+  Data    Packet data, not present in all packets.
+
+-- Packet Types --
+Query     The host sends a query packet once on startup to sync with the device.
+          The host will not know the current sequence number, so the device must
+          respond to all query packets regardless of sequence number.
+
+          The response data field should contain a 2-byte big-endian value
+          giving the next expected sequence number.
+
+Init      The host sends an init packet once the query response is returned. The
+          device must abort any in-progress operation and prepare for a new
+          fastboot session. This message is meant to allow recovery if a
+          previous session failed, e.g. due to network error or user Ctrl+C.
+
+          The data field contains two big-endian 2-byte values, a protocol
+          version and the max UDP packet size (including the 4-byte header).
+          Both the host and device will send these values, and in each case
+          the minimum of the sent values must be used.
+
+Fastboot  These packets wrap the fastboot protocol. To write, the host will
+          send a packet with fastboot data, and the device will reply with an
+          empty packet as an ACK. To read, the host will send an empty packet,
+          and the device will reply with fastboot data. The device may not give
+          any data in the ACK packet.
+
+Error     The device may respond to any packet with an error packet to indicate
+          a UDP protocol error. The data field should contain an ASCII string
+          describing the error. This is the only case where a device is allowed
+          to return a packet ID other than the one sent by the host.
+
+-- Packet Size --
+The maximum packet size is negotiated by the host and device in the Init packet.
+Devices must support at least 512-byte packets, but packet size has a direct
+correlation with download speed, so devices are strongly suggested to support at
+least 1024-byte packets. On a local network with 0.5ms round-trip time this will
+provide transfer rates of ~2MB/s. Over WiFi it will likely be significantly
+less.
+
+Query and Initialization packets, which are sent before size negotiation is
+complete, must always be 512 bytes or less.
+
+-- Packet Re-Transmission --
+The host will re-transmit any packet that does not receive a response. The
+requirement of exactly one device response packet per host packet is how we
+achieve reliability and in-order delivery of packets.
+
+For simplicity of implementation, there is no windowing of multiple
+unacknowledged packets in this version of the protocol. The host will continue
+to send the same packet until a response is received. Windowing functionality
+may be implemented in future versions if necessary to increase performance.
+
+The first Query packet will only be attempted a small number of times, but
+subsequent packets will attempt to retransmit for at least 1 minute before
+giving up. This means a device may safely ignore host UDP packets for up to 1
+minute during long operations, e.g. writing to flash.
+
+-- Continuation Packets --
+Any packet may set the continuation flag to indicate that the data is
+incomplete. Large data such as downloading an image may require many
+continuation packets. The receiver should respond to a continuation packet with
+an empty packet to acknowledge receipt. See examples below.
+
+-- Summary --
+The host starts with a Query packet, then an Initialization packet, after
+which only Fastboot packets are sent. Fastboot packets may contain data from
+the host for writes, or from the device for reads, but not both.
+
+Given a next expected sequence number S and a received packet P, the device
+behavior should be:
+  if P is a Query packet:
+    * respond with a Query packet with S in the data field
+  else if P has sequence == S:
+    * process P and take any required action
+    * create a response packet R with the same ID and sequence as P, containing
+      any response data required.
+    * transmit R and save it in case of re-transmission
+    * increment S
+  else if P has sequence == S - 1:
+    * re-transmit the saved response packet R from above
+  else:
+    * ignore the packet
+
+-- Examples --
+In the examples below, S indicates the starting client sequence number.
+
+Host                                    Client
+======================================================================
+[Initialization, S = 0x55AA]
+[Host: version 1, 2048-byte packets. Client: version 2, 1024-byte packets.]
+[Resulting values to use: version = 1, max packet size = 1024]
+ID   Flag SeqH SeqL Data                ID   Flag SeqH SeqL Data
+----------------------------------------------------------------------
+0x01 0x00 0x00 0x00
+                                        0x01 0x00 0x00 0x00 0x55 0xAA
+0x02 0x00 0x55 0xAA 0x00 0x01 0x08 0x00
+                                        0x02 0x00 0x55 0xAA 0x00 0x02 0x04 0x00
+
+----------------------------------------------------------------------
+[fastboot "getvar" commands, S = 0x0001]
+ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
+----------------------------------------------------------------------
+0x03  0x00  0x00  0x01  getvar:version
+                                        0x03  0x00  0x00  0x01
+0x03  0x00  0x00  0x02
+                                        0x03  0x00  0x00  0x02  OKAY0.4
+0x03  0x00  0x00  0x03  getvar:foo
+                                        0x03  0x00  0x00  0x03
+0x03  0x00  0x00  0x04
+                                        0x03  0x00  0x00  0x04  OKAY
+
+----------------------------------------------------------------------
+[fastboot "INFO" responses, S = 0x0000]
+ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
+----------------------------------------------------------------------
+0x03  0x00  0x00  0x00  <command>
+                                        0x03  0x00  0x00  0x00
+0x03  0x00  0x00  0x01
+                                        0x03  0x00  0x00  0x01  INFOWait1
+0x03  0x00  0x00  0x02
+                                        0x03  0x00  0x00  0x02  INFOWait2
+0x03  0x00  0x00  0x03
+                                        0x03  0x00  0x00  0x03  OKAY
+
+----------------------------------------------------------------------
+[Chunking 2100 bytes of data, max packet size = 1024, S = 0xFFFF]
+ID   Flag SeqH SeqL Data                ID   Flag SeqH SeqL Data
+----------------------------------------------------------------------
+0x03 0x00 0xFF 0xFF download:0000834
+                                        0x03 0x00 0xFF 0xFF
+0x03 0x00 0x00 0x00
+                                        0x03 0x00 0x00 0x00 DATA0000834
+0x03 0x01 0x00 0x01 <1020 bytes>
+                                        0x03 0x00 0x00 0x01
+0x03 0x01 0x00 0x02 <1020 bytes>
+                                        0x03 0x00 0x00 0x02
+0x03 0x00 0x00 0x03 <60 bytes>
+                                        0x03 0x00 0x00 0x03
+0x03 0x00 0x00 0x04
+                                        0x03 0x00 0x00 0x04 OKAY
+
+----------------------------------------------------------------------
+[Unknown ID error, S = 0x0000]
+ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
+----------------------------------------------------------------------
+0x10  0x00  0x00  0x00
+                                        0x00  0x00  0x00  0x00  <error message>
+
+----------------------------------------------------------------------
+[Host packet loss and retransmission, S = 0x0000]
+ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
+----------------------------------------------------------------------
+0x03  0x00  0x00  0x00  getvar:version [lost]
+0x03  0x00  0x00  0x00  getvar:version [lost]
+0x03  0x00  0x00  0x00  getvar:version
+                                        0x03  0x00  0x00  0x00
+0x03  0x00  0x00  0x01
+                                        0x03  0x00  0x00  0x01  OKAY0.4
+
+----------------------------------------------------------------------
+[Client packet loss and retransmission, S = 0x0000]
+ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
+----------------------------------------------------------------------
+0x03  0x00  0x00  0x00  getvar:version
+                                        0x03  0x00  0x00  0x00 [lost]
+0x03  0x00  0x00  0x00  getvar:version
+                                        0x03  0x00  0x00  0x00 [lost]
+0x03  0x00  0x00  0x00  getvar:version
+                                        0x03  0x00  0x00  0x00
+0x03  0x00  0x00  0x01
+                                        0x03  0x00  0x00  0x01  OKAY0.4
+
+----------------------------------------------------------------------
+[Host packet delayed, S = 0x0000]
+ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
+----------------------------------------------------------------------
+0x03  0x00  0x00  0x00  getvar:version [delayed]
+0x03  0x00  0x00  0x00  getvar:version
+                                        0x03  0x00  0x00  0x00
+0x03  0x00  0x00  0x01
+                                        0x03  0x00  0x00  0x01  OKAY0.4
+0x03  0x00  0x00  0x00  getvar:version [arrives late with old seq#, is ignored]
diff --git a/fastboot/socket.cpp b/fastboot/socket.cpp
index d49f47f..14ecd93 100644
--- a/fastboot/socket.cpp
+++ b/fastboot/socket.cpp
@@ -48,18 +48,6 @@
     return ret;
 }
 
-bool Socket::SetReceiveTimeout(int timeout_ms) {
-    if (timeout_ms != receive_timeout_ms_) {
-        if (socket_set_receive_timeout(sock_, timeout_ms) == 0) {
-            receive_timeout_ms_ = timeout_ms;
-            return true;
-        }
-        return false;
-    }
-
-    return true;
-}
-
 ssize_t Socket::ReceiveAll(void* data, size_t length, int timeout_ms) {
     size_t total = 0;
 
@@ -82,6 +70,40 @@
     return socket_get_local_port(sock_);
 }
 
+// According to Windows setsockopt() documentation, if a Windows socket times out during send() or
+// recv() the state is indeterminate and should not be used. Our UDP protocol relies on being able
+// to re-send after a timeout, so we must use select() rather than SO_RCVTIMEO.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms740476(v=vs.85).aspx.
+bool Socket::WaitForRecv(int timeout_ms) {
+    receive_timed_out_ = false;
+
+    // In our usage |timeout_ms| <= 0 means block forever, so just return true immediately and let
+    // the subsequent recv() do the blocking.
+    if (timeout_ms <= 0) {
+        return true;
+    }
+
+    // select() doesn't always check this case and will block for |timeout_ms| if we let it.
+    if (sock_ == INVALID_SOCKET) {
+        return false;
+    }
+
+    fd_set read_set;
+    FD_ZERO(&read_set);
+    FD_SET(sock_, &read_set);
+
+    timeval timeout;
+    timeout.tv_sec = timeout_ms / 1000;
+    timeout.tv_usec = (timeout_ms % 1000) * 1000;
+
+    int result = TEMP_FAILURE_RETRY(select(sock_ + 1, &read_set, nullptr, nullptr, &timeout));
+
+    if (result == 0) {
+        receive_timed_out_ = true;
+    }
+    return result == 1;
+}
+
 // Implements the Socket interface for UDP.
 class UdpSocket : public Socket {
   public:
@@ -127,7 +149,7 @@
 }
 
 ssize_t UdpSocket::Receive(void* data, size_t length, int timeout_ms) {
-    if (!SetReceiveTimeout(timeout_ms)) {
+    if (!WaitForRecv(timeout_ms)) {
         return -1;
     }
 
@@ -206,7 +228,7 @@
 }
 
 ssize_t TcpSocket::Receive(void* data, size_t length, int timeout_ms) {
-    if (!SetReceiveTimeout(timeout_ms)) {
+    if (!WaitForRecv(timeout_ms)) {
         return -1;
     }
 
diff --git a/fastboot/socket.h b/fastboot/socket.h
index c0bd7c9..de543db 100644
--- a/fastboot/socket.h
+++ b/fastboot/socket.h
@@ -81,13 +81,17 @@
     virtual bool Send(std::vector<cutils_socket_buffer_t> buffers) = 0;
 
     // Waits up to |timeout_ms| to receive up to |length| bytes of data. |timout_ms| of 0 will
-    // block forever. Returns the number of bytes received or -1 on error/timeout. On timeout
-    // errno will be set to EAGAIN or EWOULDBLOCK.
+    // block forever. Returns the number of bytes received or -1 on error/timeout; see
+    // ReceiveTimedOut() to distinguish between the two.
     virtual ssize_t Receive(void* data, size_t length, int timeout_ms) = 0;
 
     // Calls Receive() until exactly |length| bytes have been received or an error occurs.
     virtual ssize_t ReceiveAll(void* data, size_t length, int timeout_ms);
 
+    // Returns true if the last Receive() call timed out normally and can be retried; fatal errors
+    // or successful reads will return false.
+    bool ReceiveTimedOut() { return receive_timed_out_; }
+
     // Closes the socket. Returns 0 on success, -1 on error.
     virtual int Close();
 
@@ -102,10 +106,13 @@
     // Protected constructor to force factory function use.
     Socket(cutils_socket_t sock);
 
-    // Update the socket receive timeout if necessary.
-    bool SetReceiveTimeout(int timeout_ms);
+    // Blocks up to |timeout_ms| until a read is possible on |sock_|, and sets |receive_timed_out_|
+    // as appropriate to help distinguish between normal timeouts and fatal errors. Returns true if
+    // a subsequent recv() on |sock_| will complete without blocking or if |timeout_ms| <= 0.
+    bool WaitForRecv(int timeout_ms);
 
     cutils_socket_t sock_ = INVALID_SOCKET;
+    bool receive_timed_out_ = false;
 
     // Non-class functions we want to override during tests to verify functionality. Implementation
     // should call this rather than using socket_send_buffers() directly.
@@ -113,8 +120,6 @@
             socket_send_buffers_function_ = &socket_send_buffers;
 
   private:
-    int receive_timeout_ms_ = 0;
-
     FRIEND_TEST(SocketTest, TestTcpSendBuffers);
     FRIEND_TEST(SocketTest, TestUdpSendBuffers);
 
diff --git a/fastboot/socket_mock.cpp b/fastboot/socket_mock.cpp
index c962f30..2531b53 100644
--- a/fastboot/socket_mock.cpp
+++ b/fastboot/socket_mock.cpp
@@ -55,7 +55,7 @@
         return false;
     }
 
-    bool return_value = events_.front().return_value;
+    bool return_value = events_.front().status;
     events_.pop();
     return return_value;
 }
@@ -76,21 +76,28 @@
         return -1;
     }
 
-    if (events_.front().type != EventType::kReceive) {
+    const Event& event = events_.front();
+    if (event.type != EventType::kReceive) {
         ADD_FAILURE() << "Receive() was called out-of-order";
         return -1;
     }
 
-    if (events_.front().return_value > static_cast<ssize_t>(length)) {
-        ADD_FAILURE() << "Receive(): not enough bytes (" << length << ") for "
-                      << events_.front().message;
+    const std::string& message = event.message;
+    if (message.length() > length) {
+        ADD_FAILURE() << "Receive(): not enough bytes (" << length << ") for " << message;
         return -1;
     }
 
-    ssize_t return_value = events_.front().return_value;
-    if (return_value > 0) {
-        memcpy(data, events_.front().message.data(), return_value);
+    receive_timed_out_ = event.status;
+    ssize_t return_value = message.length();
+
+    // Empty message indicates failure.
+    if (message.empty()) {
+        return_value = -1;
+    } else {
+        memcpy(data, message.data(), message.length());
     }
+
     events_.pop();
     return return_value;
 }
@@ -124,18 +131,21 @@
 }
 
 void SocketMock::AddReceive(std::string message) {
-    ssize_t return_value = message.length();
-    events_.push(Event(EventType::kReceive, std::move(message), return_value, nullptr));
+    events_.push(Event(EventType::kReceive, std::move(message), false, nullptr));
+}
+
+void SocketMock::AddReceiveTimeout() {
+    events_.push(Event(EventType::kReceive, "", true, nullptr));
 }
 
 void SocketMock::AddReceiveFailure() {
-    events_.push(Event(EventType::kReceive, "", -1, nullptr));
+    events_.push(Event(EventType::kReceive, "", false, nullptr));
 }
 
 void SocketMock::AddAccept(std::unique_ptr<Socket> sock) {
-    events_.push(Event(EventType::kAccept, "", 0, std::move(sock)));
+    events_.push(Event(EventType::kAccept, "", false, std::move(sock)));
 }
 
-SocketMock::Event::Event(EventType _type, std::string _message, ssize_t _return_value,
+SocketMock::Event::Event(EventType _type, std::string _message, ssize_t _status,
                          std::unique_ptr<Socket> _sock)
-        : type(_type), message(_message), return_value(_return_value), sock(std::move(_sock)) {}
+        : type(_type), message(_message), status(_status), sock(std::move(_sock)) {}
diff --git a/fastboot/socket_mock.h b/fastboot/socket_mock.h
index 41fe06d..eacd6bb 100644
--- a/fastboot/socket_mock.h
+++ b/fastboot/socket_mock.h
@@ -71,7 +71,10 @@
     // Adds data to provide for Receive().
     void AddReceive(std::string message);
 
-    // Adds a Receive() failure.
+    // Adds a Receive() timeout after which ReceiveTimedOut() will return true.
+    void AddReceiveTimeout();
+
+    // Adds a Receive() failure after which ReceiveTimedOut() will return false.
     void AddReceiveFailure();
 
     // Adds a Socket to return from Accept().
@@ -81,12 +84,12 @@
     enum class EventType { kSend, kReceive, kAccept };
 
     struct Event {
-        Event(EventType _type, std::string _message, ssize_t _return_value,
+        Event(EventType _type, std::string _message, ssize_t _status,
               std::unique_ptr<Socket> _sock);
 
         EventType type;
         std::string message;
-        ssize_t return_value;
+        bool status;  // Return value for Send() or timeout status for Receive().
         std::unique_ptr<Socket> sock;
     };
 
diff --git a/fastboot/socket_test.cpp b/fastboot/socket_test.cpp
index cc71075..affbdfd 100644
--- a/fastboot/socket_test.cpp
+++ b/fastboot/socket_test.cpp
@@ -28,7 +28,8 @@
 #include <gtest/gtest-spi.h>
 #include <gtest/gtest.h>
 
-enum { kTestTimeoutMs = 3000 };
+static constexpr int kShortTimeoutMs = 10;
+static constexpr int kTestTimeoutMs = 3000;
 
 // Creates connected sockets |server| and |client|. Returns true on success.
 bool MakeConnectedSockets(Socket::Protocol protocol, std::unique_ptr<Socket>* server,
@@ -87,6 +88,50 @@
     }
 }
 
+TEST(SocketTest, TestReceiveTimeout) {
+    std::unique_ptr<Socket> server, client;
+    char buffer[16];
+
+    for (Socket::Protocol protocol : {Socket::Protocol::kUdp, Socket::Protocol::kTcp}) {
+        ASSERT_TRUE(MakeConnectedSockets(protocol, &server, &client));
+
+        EXPECT_EQ(-1, server->Receive(buffer, sizeof(buffer), kShortTimeoutMs));
+        EXPECT_TRUE(server->ReceiveTimedOut());
+
+        EXPECT_EQ(-1, client->Receive(buffer, sizeof(buffer), kShortTimeoutMs));
+        EXPECT_TRUE(client->ReceiveTimedOut());
+    }
+
+    // UDP will wait for timeout if the other side closes.
+    ASSERT_TRUE(MakeConnectedSockets(Socket::Protocol::kUdp, &server, &client));
+    EXPECT_EQ(0, server->Close());
+    EXPECT_EQ(-1, client->Receive(buffer, sizeof(buffer), kShortTimeoutMs));
+    EXPECT_TRUE(client->ReceiveTimedOut());
+}
+
+TEST(SocketTest, TestReceiveFailure) {
+    std::unique_ptr<Socket> server, client;
+    char buffer[16];
+
+    for (Socket::Protocol protocol : {Socket::Protocol::kUdp, Socket::Protocol::kTcp}) {
+        ASSERT_TRUE(MakeConnectedSockets(protocol, &server, &client));
+
+        EXPECT_EQ(0, server->Close());
+        EXPECT_EQ(-1, server->Receive(buffer, sizeof(buffer), kTestTimeoutMs));
+        EXPECT_FALSE(server->ReceiveTimedOut());
+
+        EXPECT_EQ(0, client->Close());
+        EXPECT_EQ(-1, client->Receive(buffer, sizeof(buffer), kTestTimeoutMs));
+        EXPECT_FALSE(client->ReceiveTimedOut());
+    }
+
+    // TCP knows right away when the other side closes and returns 0 to indicate EOF.
+    ASSERT_TRUE(MakeConnectedSockets(Socket::Protocol::kTcp, &server, &client));
+    EXPECT_EQ(0, server->Close());
+    EXPECT_EQ(0, client->Receive(buffer, sizeof(buffer), kTestTimeoutMs));
+    EXPECT_FALSE(client->ReceiveTimedOut());
+}
+
 // Tests sending and receiving large packets.
 TEST(SocketTest, TestLargePackets) {
     std::string message(1024, '\0');
@@ -290,6 +335,11 @@
 
     mock->AddReceiveFailure();
     EXPECT_FALSE(ReceiveString(mock, "foo"));
+    EXPECT_FALSE(mock->ReceiveTimedOut());
+
+    mock->AddReceiveTimeout();
+    EXPECT_FALSE(ReceiveString(mock, "foo"));
+    EXPECT_TRUE(mock->ReceiveTimedOut());
 
     mock->AddReceive("foo");
     mock->AddReceiveFailure();
diff --git a/fastboot/udp.cpp b/fastboot/udp.cpp
new file mode 100644
index 0000000..b36bd60
--- /dev/null
+++ b/fastboot/udp.cpp
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+// This file implements the fastboot UDP protocol; see fastboot_protocol.txt for documentation.
+
+#include "udp.h"
+
+#include <errno.h>
+#include <stdio.h>
+
+#include <list>
+#include <memory>
+#include <vector>
+
+#include <android-base/macros.h>
+#include <android-base/stringprintf.h>
+
+#include "socket.h"
+
+namespace udp {
+
+using namespace internal;
+
+constexpr size_t kMinPacketSize = 512;
+constexpr size_t kHeaderSize = 4;
+
+enum Index {
+    kIndexId = 0,
+    kIndexFlags = 1,
+    kIndexSeqH = 2,
+    kIndexSeqL = 3,
+};
+
+// Extracts a big-endian uint16_t from a byte array.
+static uint16_t ExtractUint16(const uint8_t* bytes) {
+    return (static_cast<uint16_t>(bytes[0]) << 8) | bytes[1];
+}
+
+// Packet header handling.
+class Header {
+  public:
+    Header();
+    ~Header() = default;
+
+    uint8_t id() const { return bytes_[kIndexId]; }
+    const uint8_t* bytes() const { return bytes_; }
+
+    void Set(uint8_t id, uint16_t sequence, Flag flag);
+
+    // Checks whether |response| is a match for this header.
+    bool Matches(const uint8_t* response);
+
+  private:
+    uint8_t bytes_[kHeaderSize];
+};
+
+Header::Header() {
+    Set(kIdError, 0, kFlagNone);
+}
+
+void Header::Set(uint8_t id, uint16_t sequence, Flag flag) {
+    bytes_[kIndexId] = id;
+    bytes_[kIndexFlags] = flag;
+    bytes_[kIndexSeqH] = sequence >> 8;
+    bytes_[kIndexSeqL] = sequence;
+}
+
+bool Header::Matches(const uint8_t* response) {
+    // Sequence numbers must be the same to match, but the response ID can either be the same
+    // or an error response which is always accepted.
+    return bytes_[kIndexSeqH] == response[kIndexSeqH] &&
+           bytes_[kIndexSeqL] == response[kIndexSeqL] &&
+           (bytes_[kIndexId] == response[kIndexId] || response[kIndexId] == kIdError);
+}
+
+// Implements the Transport interface to work with the fastboot engine.
+class UdpTransport : public Transport {
+  public:
+    // Factory function so we can return nullptr if initialization fails.
+    static std::unique_ptr<UdpTransport> NewTransport(std::unique_ptr<Socket> socket,
+                                                      std::string* error);
+    ~UdpTransport() override = default;
+
+    ssize_t Read(void* data, size_t length) override;
+    ssize_t Write(const void* data, size_t length) override;
+    int Close() override;
+
+  private:
+    UdpTransport(std::unique_ptr<Socket> socket) : socket_(std::move(socket)) {}
+
+    // Performs the UDP initialization procedure. Returns true on success.
+    bool InitializeProtocol(std::string* error);
+
+    // Sends |length| bytes from |data| and waits for the response packet up to |attempts| times.
+    // Continuation packets are handled automatically and any return data is written to |rx_data|.
+    // Excess bytes that cannot fit in |rx_data| are dropped.
+    // On success, returns the number of response data bytes received, which may be greater than
+    // |rx_length|. On failure, returns -1 and fills |error| on failure.
+    ssize_t SendData(Id id, const uint8_t* tx_data, size_t tx_length, uint8_t* rx_data,
+                     size_t rx_length, int attempts, std::string* error);
+
+    // Helper for SendData(); sends a single packet and handles the response. |header| specifies
+    // the initial outgoing packet information but may be modified by this function.
+    ssize_t SendSinglePacketHelper(Header* header, const uint8_t* tx_data, size_t tx_length,
+                                   uint8_t* rx_data, size_t rx_length, int attempts,
+                                   std::string* error);
+
+    std::unique_ptr<Socket> socket_;
+    int sequence_ = -1;
+    size_t max_data_length_ = kMinPacketSize - kHeaderSize;
+    std::vector<uint8_t> rx_packet_;
+
+    DISALLOW_COPY_AND_ASSIGN(UdpTransport);
+};
+
+std::unique_ptr<UdpTransport> UdpTransport::NewTransport(std::unique_ptr<Socket> socket,
+                                                         std::string* error) {
+    std::unique_ptr<UdpTransport> transport(new UdpTransport(std::move(socket)));
+
+    if (!transport->InitializeProtocol(error)) {
+        return nullptr;
+    }
+
+    return transport;
+}
+
+bool UdpTransport::InitializeProtocol(std::string* error) {
+    uint8_t rx_data[4];
+
+    sequence_ = 0;
+    rx_packet_.resize(kMinPacketSize);
+
+    // First send the query packet to sync with the target. Only attempt this a small number of
+    // times so we can fail out quickly if the target isn't available.
+    ssize_t rx_bytes = SendData(kIdDeviceQuery, nullptr, 0, rx_data, sizeof(rx_data),
+                                kMaxConnectAttempts, error);
+    if (rx_bytes == -1) {
+        return false;
+    } else if (rx_bytes < 2) {
+        *error = "invalid query response from target";
+        return false;
+    }
+    // The first two bytes contain the next expected sequence number.
+    sequence_ = ExtractUint16(rx_data);
+
+    // Now send the initialization packet with our version and maximum packet size.
+    uint8_t init_data[] = {kProtocolVersion >> 8, kProtocolVersion & 0xFF,
+                           kHostMaxPacketSize >> 8, kHostMaxPacketSize & 0xFF};
+    rx_bytes = SendData(kIdInitialization, init_data, sizeof(init_data), rx_data, sizeof(rx_data),
+                        kMaxTransmissionAttempts, error);
+    if (rx_bytes == -1) {
+        return false;
+    } else if (rx_bytes < 4) {
+        *error = "invalid initialization response from target";
+        return false;
+    }
+
+    // The first two data bytes contain the version, the second two bytes contain the target max
+    // supported packet size, which must be at least 512 bytes.
+    uint16_t version = ExtractUint16(rx_data);
+    if (version < kProtocolVersion) {
+        *error = android::base::StringPrintf("target reported invalid protocol version %d",
+                                             version);
+        return false;
+    }
+    uint16_t packet_size = ExtractUint16(rx_data + 2);
+    if (packet_size < kMinPacketSize) {
+        *error = android::base::StringPrintf("target reported invalid packet size %d", packet_size);
+        return false;
+    }
+
+    packet_size = std::min(kHostMaxPacketSize, packet_size);
+    max_data_length_ = packet_size - kHeaderSize;
+    rx_packet_.resize(packet_size);
+
+    return true;
+}
+
+// SendData() is just responsible for chunking |data| into packets until it's all been sent.
+// Per-packet timeout/retransmission logic is done in SendSinglePacketHelper().
+ssize_t UdpTransport::SendData(Id id, const uint8_t* tx_data, size_t tx_length, uint8_t* rx_data,
+                               size_t rx_length, int attempts, std::string* error) {
+    if (socket_ == nullptr) {
+        *error = "socket is closed";
+        return -1;
+    }
+
+    Header header;
+    size_t packet_data_length;
+    ssize_t ret = 0;
+    // We often send header-only packets with no data as part of the protocol, so always send at
+    // least once even if |length| == 0, then repeat until we've sent all of |data|.
+    do {
+        // Set the continuation flag and truncate packet data if needed.
+        if (tx_length > max_data_length_) {
+            packet_data_length = max_data_length_;
+            header.Set(id, sequence_, kFlagContinuation);
+        } else {
+            packet_data_length = tx_length;
+            header.Set(id, sequence_, kFlagNone);
+        }
+
+        ssize_t bytes = SendSinglePacketHelper(&header, tx_data, packet_data_length, rx_data,
+                                               rx_length, attempts, error);
+
+        // Advance our read and write buffers for the next packet. Keep going even if we run out
+        // of receive buffer space so we can detect overflows.
+        if (bytes == -1) {
+            return -1;
+        } else if (static_cast<size_t>(bytes) < rx_length) {
+            rx_data += bytes;
+            rx_length -= bytes;
+        } else {
+            rx_data = nullptr;
+            rx_length = 0;
+        }
+
+        tx_length -= packet_data_length;
+        tx_data += packet_data_length;
+
+        ret += bytes;
+    } while (tx_length > 0);
+
+    return ret;
+}
+
+ssize_t UdpTransport::SendSinglePacketHelper(
+        Header* header, const uint8_t* tx_data, size_t tx_length, uint8_t* rx_data,
+        size_t rx_length, const int attempts, std::string* error) {
+    ssize_t total_data_bytes = 0;
+    error->clear();
+
+    int attempts_left = attempts;
+    while (attempts_left > 0) {
+        if (!socket_->Send({{header->bytes(), kHeaderSize}, {tx_data, tx_length}})) {
+            *error = Socket::GetErrorMessage();
+            return -1;
+        }
+
+        // Keep receiving until we get a matching response or we timeout.
+        ssize_t bytes = 0;
+        do {
+            bytes = socket_->Receive(rx_packet_.data(), rx_packet_.size(), kResponseTimeoutMs);
+            if (bytes == -1) {
+                if (socket_->ReceiveTimedOut()) {
+                    break;
+                }
+                *error = Socket::GetErrorMessage();
+                return -1;
+            } else if (bytes < static_cast<ssize_t>(kHeaderSize)) {
+                *error = "protocol error: incomplete header";
+                return -1;
+            }
+        } while (!header->Matches(rx_packet_.data()));
+
+        if (socket_->ReceiveTimedOut()) {
+            --attempts_left;
+            continue;
+        }
+        ++sequence_;
+
+        // Save to |error| or |rx_data| as appropriate.
+        if (rx_packet_[kIndexId] == kIdError) {
+            error->append(rx_packet_.data() + kHeaderSize, rx_packet_.data() + bytes);
+        } else {
+            total_data_bytes += bytes - kHeaderSize;
+            size_t rx_data_bytes = std::min<size_t>(bytes - kHeaderSize, rx_length);
+            if (rx_data_bytes > 0) {
+                memcpy(rx_data, rx_packet_.data() + kHeaderSize, rx_data_bytes);
+                rx_data += rx_data_bytes;
+                rx_length -= rx_data_bytes;
+            }
+        }
+
+        // If the response has a continuation flag we need to prompt for more data by sending
+        // an empty packet.
+        if (rx_packet_[kIndexFlags] & kFlagContinuation) {
+            // We got a valid response so reset our attempt counter.
+            attempts_left = attempts;
+            header->Set(rx_packet_[kIndexId], sequence_, kFlagNone);
+            tx_data = nullptr;
+            tx_length = 0;
+            continue;
+        }
+
+        break;
+    }
+
+    if (attempts_left <= 0) {
+        *error = "no response from target";
+        return -1;
+    }
+
+    if (rx_packet_[kIndexId] == kIdError) {
+        *error = "target reported error: " + *error;
+        return -1;
+    }
+
+    return total_data_bytes;
+}
+
+ssize_t UdpTransport::Read(void* data, size_t length) {
+    // Read from the target by sending an empty packet.
+    std::string error;
+    ssize_t bytes = SendData(kIdFastboot, nullptr, 0, reinterpret_cast<uint8_t*>(data), length,
+                             kMaxTransmissionAttempts, &error);
+
+    if (bytes == -1) {
+        fprintf(stderr, "UDP error: %s\n", error.c_str());
+        return -1;
+    } else if (static_cast<size_t>(bytes) > length) {
+        // Fastboot protocol error: the target sent more data than our fastboot engine was prepared
+        // to receive.
+        fprintf(stderr, "UDP error: receive overflow, target sent too much fastboot data\n");
+        return -1;
+    }
+
+    return bytes;
+}
+
+ssize_t UdpTransport::Write(const void* data, size_t length) {
+    std::string error;
+    ssize_t bytes = SendData(kIdFastboot, reinterpret_cast<const uint8_t*>(data), length, nullptr,
+                             0, kMaxTransmissionAttempts, &error);
+
+    if (bytes == -1) {
+        fprintf(stderr, "UDP error: %s\n", error.c_str());
+        return -1;
+    } else if (bytes > 0) {
+        // UDP protocol error: only empty ACK packets are allowed when writing to a device.
+        fprintf(stderr, "UDP error: target sent fastboot data out-of-turn\n");
+        return -1;
+    }
+
+    return length;
+}
+
+int UdpTransport::Close() {
+    if (socket_ == nullptr) {
+        return 0;
+    }
+
+    int result = socket_->Close();
+    socket_.reset();
+    return result;
+}
+
+std::unique_ptr<Transport> Connect(const std::string& hostname, int port, std::string* error) {
+    return internal::Connect(Socket::NewClient(Socket::Protocol::kUdp, hostname, port, error),
+                             error);
+}
+
+namespace internal {
+
+std::unique_ptr<Transport> Connect(std::unique_ptr<Socket> sock, std::string* error) {
+    if (sock == nullptr) {
+        // If Socket creation failed |error| is already set.
+        return nullptr;
+    }
+
+    return UdpTransport::NewTransport(std::move(sock), error);
+}
+
+}  // namespace internal
+
+}  // namespace udp
diff --git a/fastboot/udp.h b/fastboot/udp.h
new file mode 100644
index 0000000..14f5b35
--- /dev/null
+++ b/fastboot/udp.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef UDP_H_
+#define UDP_H_
+
+#include <memory>
+#include <string>
+
+#include "socket.h"
+#include "transport.h"
+
+namespace udp {
+
+constexpr int kDefaultPort = 5554;
+
+// Returns a newly allocated Transport object connected to |hostname|:|port|. On failure, |error| is
+// filled and nullptr is returned.
+std::unique_ptr<Transport> Connect(const std::string& hostname, int port, std::string* error);
+
+// Internal namespace for test use only.
+namespace internal {
+
+constexpr uint16_t kProtocolVersion = 1;
+
+// This will be negotiated with the device so may end up being smaller.
+constexpr uint16_t kHostMaxPacketSize = 8192;
+
+// Retransmission constants. Retransmission timeout must be at least 500ms, and the host must
+// attempt to send packets for at least 1 minute once the device has connected. See
+// fastboot_protocol.txt for more information.
+constexpr int kResponseTimeoutMs = 500;
+constexpr int kMaxConnectAttempts = 4;
+constexpr int kMaxTransmissionAttempts = 60 * 1000 / kResponseTimeoutMs;
+
+enum Id : uint8_t {
+    kIdError = 0x00,
+    kIdDeviceQuery = 0x01,
+    kIdInitialization = 0x02,
+    kIdFastboot = 0x03
+};
+
+enum Flag : uint8_t {
+    kFlagNone = 0x00,
+    kFlagContinuation = 0x01
+};
+
+// Creates a UDP Transport object using a given Socket. Used for unit tests to create a Transport
+// object that uses a SocketMock.
+std::unique_ptr<Transport> Connect(std::unique_ptr<Socket> sock, std::string* error);
+
+}  // namespace internal
+
+}  // namespace udp
+
+#endif  // UDP_H_
diff --git a/fastboot/udp_test.cpp b/fastboot/udp_test.cpp
new file mode 100644
index 0000000..ff8cf0f
--- /dev/null
+++ b/fastboot/udp_test.cpp
@@ -0,0 +1,531 @@
+/*
+ * 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 "udp.h"
+
+#include <gtest/gtest.h>
+
+#include "socket.h"
+#include "socket_mock.h"
+
+using namespace udp;
+using namespace udp::internal;
+
+// Some possible corner case sequence numbers we want to check.
+static const uint16_t kTestSequenceNumbers[] = {0x0000, 0x0001, 0x00FF, 0x0100,
+                                                0x7FFF, 0x8000, 0xFFFF};
+
+// Converts |value| to a binary big-endian string.
+static std::string PacketValue(uint16_t value) {
+    return std::string{static_cast<char>(value >> 8), static_cast<char>(value)};
+}
+
+// Returns an Error packet.
+static std::string ErrorPacket(uint16_t sequence, const std::string& message = "",
+                               char flags = kFlagNone) {
+    return std::string{kIdError, flags} + PacketValue(sequence) + message;
+}
+
+// Returns a Query packet with no data.
+static std::string QueryPacket(uint16_t sequence) {
+    return std::string{kIdDeviceQuery, kFlagNone} + PacketValue(sequence);
+}
+
+// Returns a Query packet with a 2-byte |new_sequence|.
+static std::string QueryPacket(uint16_t sequence, uint16_t new_sequence) {
+    return std::string{kIdDeviceQuery, kFlagNone} + PacketValue(sequence) +
+           PacketValue(new_sequence);
+}
+
+// Returns an Init packet with a 2-byte |version| and |max_packet_size|.
+static std::string InitPacket(uint16_t sequence, uint16_t version, uint16_t max_packet_size) {
+    return std::string{kIdInitialization, kFlagNone} + PacketValue(sequence) +
+           PacketValue(version) + PacketValue(max_packet_size);
+}
+
+// Returns a Fastboot packet with |data|.
+static std::string FastbootPacket(uint16_t sequence, const std::string& data = "",
+                                  char flags = kFlagNone) {
+    return std::string{kIdFastboot, flags} + PacketValue(sequence) + data;
+}
+
+// Fixture class to test protocol initialization. Usage is to set up the expected calls to the
+// SocketMock object then call UdpConnect() and check the result.
+class UdpConnectTest : public ::testing::Test {
+  public:
+    UdpConnectTest() : mock_socket_(new SocketMock) {}
+
+    // Run the initialization, return whether it was successful or not. This passes ownership of
+    // the current |mock_socket_| but allocates a new one for re-use.
+    bool UdpConnect(std::string* error = nullptr) {
+        std::string local_error;
+        if (error == nullptr) {
+            error = &local_error;
+        }
+        std::unique_ptr<Transport> transport(Connect(std::move(mock_socket_), error));
+        mock_socket_.reset(new SocketMock);
+        return transport != nullptr && error->empty();
+    }
+
+  protected:
+    std::unique_ptr<SocketMock> mock_socket_;
+};
+
+// Tests a successful protocol initialization with various starting sequence numbers.
+TEST_F(UdpConnectTest, InitializationSuccess) {
+    for (uint16_t seq : kTestSequenceNumbers) {
+        mock_socket_->ExpectSend(QueryPacket(0));
+        mock_socket_->AddReceive(QueryPacket(0, seq));
+        mock_socket_->ExpectSend(InitPacket(seq, kProtocolVersion, kHostMaxPacketSize));
+        mock_socket_->AddReceive(InitPacket(seq, kProtocolVersion, 1024));
+
+        EXPECT_TRUE(UdpConnect());
+    }
+}
+
+// Tests continuation packets during initialization.
+TEST_F(UdpConnectTest, InitializationContinuationSuccess) {
+    mock_socket_->ExpectSend(QueryPacket(0));
+    mock_socket_->AddReceive(std::string{kIdDeviceQuery, kFlagContinuation, 0, 0, 0x44});
+    mock_socket_->ExpectSend(std::string{kIdDeviceQuery, kFlagNone, 0, 1});
+    mock_socket_->AddReceive(std::string{kIdDeviceQuery, kFlagNone, 0, 1, 0x55});
+
+    mock_socket_->ExpectSend(InitPacket(0x4455, kProtocolVersion, kHostMaxPacketSize));
+    mock_socket_->AddReceive(std::string{kIdInitialization, kFlagContinuation, 0x44, 0x55, 0});
+    mock_socket_->ExpectSend(std::string{kIdInitialization, kFlagNone, 0x44, 0x56});
+    mock_socket_->AddReceive(std::string{kIdInitialization, kFlagContinuation, 0x44, 0x56, 1});
+    mock_socket_->ExpectSend(std::string{kIdInitialization, kFlagNone, 0x44, 0x57});
+    mock_socket_->AddReceive(std::string{kIdInitialization, kFlagContinuation, 0x44, 0x57, 2});
+    mock_socket_->ExpectSend(std::string{kIdInitialization, kFlagNone, 0x44, 0x58});
+    mock_socket_->AddReceive(std::string{kIdInitialization, kFlagNone, 0x44, 0x58, 0});
+
+    EXPECT_TRUE(UdpConnect());
+}
+
+
+// Tests a mismatched version number; as long as the minimum of the two versions is supported
+// we should allow the connection.
+TEST_F(UdpConnectTest, InitializationVersionMismatch) {
+    mock_socket_->ExpectSend(QueryPacket(0));
+    mock_socket_->AddReceive(QueryPacket(0, 0));
+    mock_socket_->ExpectSend(InitPacket(0, kProtocolVersion, kHostMaxPacketSize));
+    mock_socket_->AddReceive(InitPacket(0, 2, 1024));
+
+    EXPECT_TRUE(UdpConnect());
+
+    mock_socket_->ExpectSend(QueryPacket(0));
+    mock_socket_->AddReceive(QueryPacket(0, 0));
+    mock_socket_->ExpectSend(InitPacket(0, kProtocolVersion, kHostMaxPacketSize));
+    mock_socket_->AddReceive(InitPacket(0, 0, 1024));
+
+    EXPECT_FALSE(UdpConnect());
+}
+
+TEST_F(UdpConnectTest, QueryResponseTimeoutFailure) {
+    for (int i = 0; i < kMaxConnectAttempts; ++i) {
+        mock_socket_->ExpectSend(QueryPacket(0));
+        mock_socket_->AddReceiveTimeout();
+    }
+
+    EXPECT_FALSE(UdpConnect());
+}
+
+TEST_F(UdpConnectTest, QueryResponseReceiveFailure) {
+    mock_socket_->ExpectSend(QueryPacket(0));
+    mock_socket_->AddReceiveFailure();
+
+    EXPECT_FALSE(UdpConnect());
+}
+
+TEST_F(UdpConnectTest, InitResponseTimeoutFailure) {
+    mock_socket_->ExpectSend(QueryPacket(0));
+    mock_socket_->AddReceive(QueryPacket(0, 0));
+    for (int i = 0; i < kMaxTransmissionAttempts; ++i) {
+        mock_socket_->ExpectSend(InitPacket(0, kProtocolVersion, kHostMaxPacketSize));
+        mock_socket_->AddReceiveTimeout();
+    }
+
+    EXPECT_FALSE(UdpConnect());
+}
+
+TEST_F(UdpConnectTest, InitResponseReceiveFailure) {
+    mock_socket_->ExpectSend(QueryPacket(0));
+    mock_socket_->AddReceive(QueryPacket(0, 0));
+    mock_socket_->ExpectSend(InitPacket(0, kProtocolVersion, kHostMaxPacketSize));
+    mock_socket_->AddReceiveFailure();
+
+    EXPECT_FALSE(UdpConnect());
+}
+
+// Tests that we can recover up to the maximum number of allowed retries.
+TEST_F(UdpConnectTest, ResponseRecovery) {
+    // The device query packet can recover from up to (kMaxConnectAttempts - 1) timeouts.
+    for (int i = 0; i < kMaxConnectAttempts - 1; ++i) {
+        mock_socket_->ExpectSend(QueryPacket(0));
+        mock_socket_->AddReceiveTimeout();
+    }
+    mock_socket_->ExpectSend(QueryPacket(0));
+    mock_socket_->AddReceive(QueryPacket(0, 0));
+
+    // Subsequent packets try up to (kMaxTransmissionAttempts - 1) times.
+    for (int i = 0; i < kMaxTransmissionAttempts - 1; ++i) {
+        mock_socket_->ExpectSend(InitPacket(0, kProtocolVersion, kHostMaxPacketSize));
+        mock_socket_->AddReceiveTimeout();
+    }
+    mock_socket_->ExpectSend(InitPacket(0, kProtocolVersion, kHostMaxPacketSize));
+    mock_socket_->AddReceive(InitPacket(0, kProtocolVersion, 1024));
+
+    EXPECT_TRUE(UdpConnect());
+}
+
+// Tests that the host can handle receiving additional bytes for forward compatibility.
+TEST_F(UdpConnectTest, ExtraResponseDataSuccess) {
+    mock_socket_->ExpectSend(QueryPacket(0));
+    mock_socket_->AddReceive(QueryPacket(0, 0) + "foo");
+    mock_socket_->ExpectSend(InitPacket(0, kProtocolVersion, kHostMaxPacketSize));
+    mock_socket_->AddReceive(InitPacket(0, kProtocolVersion, 1024) + "bar");
+
+    EXPECT_TRUE(UdpConnect());
+}
+
+// Tests mismatched response sequence numbers. A wrong sequence number is interpreted as a previous
+// retransmission and just ignored so we should be able to recover.
+TEST_F(UdpConnectTest, WrongSequenceRecovery) {
+    mock_socket_->ExpectSend(QueryPacket(0));
+    mock_socket_->AddReceive(QueryPacket(1, 0));
+    mock_socket_->AddReceive(QueryPacket(0, 0));
+
+    mock_socket_->ExpectSend(InitPacket(0, kProtocolVersion, kHostMaxPacketSize));
+    mock_socket_->AddReceive(InitPacket(1, kProtocolVersion, 1024));
+    mock_socket_->AddReceive(InitPacket(0, kProtocolVersion, 1024));
+
+    EXPECT_TRUE(UdpConnect());
+}
+
+// Tests mismatched response IDs. This should also be interpreted as a retransmission and ignored.
+TEST_F(UdpConnectTest, WrongIdRecovery) {
+    mock_socket_->ExpectSend(QueryPacket(0));
+    mock_socket_->AddReceive(FastbootPacket(0));
+    mock_socket_->AddReceive(QueryPacket(0, 0));
+
+    mock_socket_->ExpectSend(InitPacket(0, kProtocolVersion, kHostMaxPacketSize));
+    mock_socket_->AddReceive(FastbootPacket(0));
+    mock_socket_->AddReceive(InitPacket(0, kProtocolVersion, 1024));
+
+    EXPECT_TRUE(UdpConnect());
+}
+
+// Tests an invalid query response. Query responses must have at least 2 bytes of data.
+TEST_F(UdpConnectTest, InvalidQueryResponseFailure) {
+    std::string error;
+
+    mock_socket_->ExpectSend(QueryPacket(0));
+    mock_socket_->AddReceive(QueryPacket(0));
+
+    EXPECT_FALSE(UdpConnect(&error));
+    EXPECT_EQ("invalid query response from target", error);
+
+    mock_socket_->ExpectSend(QueryPacket(0));
+    mock_socket_->AddReceive(QueryPacket(0) + std::string{0x00});
+
+    EXPECT_FALSE(UdpConnect(&error));
+    EXPECT_EQ("invalid query response from target", error);
+}
+
+// Tests an invalid initialization response. Max packet size must be at least 512 bytes.
+TEST_F(UdpConnectTest, InvalidInitResponseFailure) {
+    std::string error;
+
+    mock_socket_->ExpectSend(QueryPacket(0));
+    mock_socket_->AddReceive(QueryPacket(0, 0));
+    mock_socket_->ExpectSend(InitPacket(0, kProtocolVersion, kHostMaxPacketSize));
+    mock_socket_->AddReceive(InitPacket(0, kProtocolVersion, 511));
+
+    EXPECT_FALSE(UdpConnect(&error));
+    EXPECT_EQ("target reported invalid packet size 511", error);
+
+    mock_socket_->ExpectSend(QueryPacket(0));
+    mock_socket_->AddReceive(QueryPacket(0, 0));
+    mock_socket_->ExpectSend(InitPacket(0, kProtocolVersion, kHostMaxPacketSize));
+    mock_socket_->AddReceive(InitPacket(0, 0, 1024));
+
+    EXPECT_FALSE(UdpConnect(&error));
+    EXPECT_EQ("target reported invalid protocol version 0", error);
+}
+
+TEST_F(UdpConnectTest, ErrorResponseFailure) {
+    std::string error;
+
+    mock_socket_->ExpectSend(QueryPacket(0));
+    mock_socket_->AddReceive(ErrorPacket(0, "error1"));
+
+    EXPECT_FALSE(UdpConnect(&error));
+    EXPECT_NE(std::string::npos, error.find("error1"));
+
+    mock_socket_->ExpectSend(QueryPacket(0));
+    mock_socket_->AddReceive(QueryPacket(0, 0));
+    mock_socket_->ExpectSend(InitPacket(0, kProtocolVersion, kHostMaxPacketSize));
+    mock_socket_->AddReceive(ErrorPacket(0, "error2"));
+
+    EXPECT_FALSE(UdpConnect(&error));
+    EXPECT_NE(std::string::npos, error.find("error2"));
+}
+
+// Tests an error response with continuation flag.
+TEST_F(UdpConnectTest, ErrorContinuationFailure) {
+    std::string error;
+
+    mock_socket_->ExpectSend(QueryPacket(0));
+    mock_socket_->AddReceive(ErrorPacket(0, "error1", kFlagContinuation));
+    mock_socket_->ExpectSend(ErrorPacket(1));
+    mock_socket_->AddReceive(ErrorPacket(1, " ", kFlagContinuation));
+    mock_socket_->ExpectSend(ErrorPacket(2));
+    mock_socket_->AddReceive(ErrorPacket(2, "error2"));
+
+    EXPECT_FALSE(UdpConnect(&error));
+    EXPECT_NE(std::string::npos, error.find("error1 error2"));
+}
+
+// Fixture class to test UDP Transport read/write functionality.
+class UdpTest : public ::testing::Test {
+  public:
+    void SetUp() override {
+        // Create |transport_| starting at sequence 0 with 512 byte max packet size. Tests can call
+        // InitializeTransport() again to change settings.
+        ASSERT_TRUE(InitializeTransport(0, 512));
+    }
+
+    // Sets up |mock_socket_| to correctly initialize the protocol and creates |transport_|. This
+    // can be called multiple times in a test if needed.
+    bool InitializeTransport(uint16_t starting_sequence, int device_max_packet_size = 512) {
+        mock_socket_ = new SocketMock;
+        mock_socket_->ExpectSend(QueryPacket(0));
+        mock_socket_->AddReceive(QueryPacket(0, starting_sequence));
+        mock_socket_->ExpectSend(
+                InitPacket(starting_sequence, kProtocolVersion, kHostMaxPacketSize));
+        mock_socket_->AddReceive(
+                InitPacket(starting_sequence, kProtocolVersion, device_max_packet_size));
+
+        std::string error;
+        transport_ = Connect(std::unique_ptr<Socket>(mock_socket_), &error);
+        return transport_ != nullptr && error.empty();
+    }
+
+    // Writes |message| to |transport_|, returns true on success.
+    bool Write(const std::string& message) {
+        return transport_->Write(message.data(), message.length()) ==
+                static_cast<ssize_t>(message.length());
+    }
+
+    // Reads from |transport_|, returns true if it matches |message|.
+    bool Read(const std::string& message) {
+        std::string buffer(message.length(), '\0');
+        return transport_->Read(&buffer[0], buffer.length()) ==
+                static_cast<ssize_t>(message.length()) && buffer == message;
+    }
+
+  protected:
+    // |mock_socket_| is a raw pointer here because we transfer ownership to |transport_| but we
+    // need to retain a pointer to set send and receive expectations.
+    SocketMock* mock_socket_ = nullptr;
+    std::unique_ptr<Transport> transport_;
+};
+
+// Tests sequence behavior with various starting sequence numbers.
+TEST_F(UdpTest, SequenceIncrementCheck) {
+    for (uint16_t seq : kTestSequenceNumbers) {
+        ASSERT_TRUE(InitializeTransport(seq));
+
+        for (int i = 0; i < 10; ++i) {
+            mock_socket_->ExpectSend(FastbootPacket(++seq, "foo"));
+            mock_socket_->AddReceive(FastbootPacket(seq, ""));
+            mock_socket_->ExpectSend(FastbootPacket(++seq, ""));
+            mock_socket_->AddReceive(FastbootPacket(seq, "bar"));
+
+            EXPECT_TRUE(Write("foo"));
+            EXPECT_TRUE(Read("bar"));
+        }
+    }
+}
+
+// Tests sending and receiving a few small packets.
+TEST_F(UdpTest, ReadAndWriteSmallPackets) {
+    mock_socket_->ExpectSend(FastbootPacket(1, "foo"));
+    mock_socket_->AddReceive(FastbootPacket(1, ""));
+    mock_socket_->ExpectSend(FastbootPacket(2, ""));
+    mock_socket_->AddReceive(FastbootPacket(2, "bar"));
+
+    EXPECT_TRUE(Write("foo"));
+    EXPECT_TRUE(Read("bar"));
+
+    mock_socket_->ExpectSend(FastbootPacket(3, "12345 67890"));
+    mock_socket_->AddReceive(FastbootPacket(3));
+    mock_socket_->ExpectSend(FastbootPacket(4, "\x01\x02\x03\x04\x05"));
+    mock_socket_->AddReceive(FastbootPacket(4));
+
+    EXPECT_TRUE(Write("12345 67890"));
+    EXPECT_TRUE(Write("\x01\x02\x03\x04\x05"));
+
+    // Reads are done by sending empty packets.
+    mock_socket_->ExpectSend(FastbootPacket(5));
+    mock_socket_->AddReceive(FastbootPacket(5, "foo bar baz"));
+    mock_socket_->ExpectSend(FastbootPacket(6));
+    mock_socket_->AddReceive(FastbootPacket(6, "\x01\x02\x03\x04\x05"));
+
+    EXPECT_TRUE(Read("foo bar baz"));
+    EXPECT_TRUE(Read("\x01\x02\x03\x04\x05"));
+}
+
+TEST_F(UdpTest, ResponseTimeoutFailure) {
+    for (int i = 0; i < kMaxTransmissionAttempts; ++i) {
+        mock_socket_->ExpectSend(FastbootPacket(1, "foo"));
+        mock_socket_->AddReceiveTimeout();
+    }
+
+    EXPECT_FALSE(Write("foo"));
+}
+
+TEST_F(UdpTest, ResponseReceiveFailure) {
+    mock_socket_->ExpectSend(FastbootPacket(1, "foo"));
+    mock_socket_->AddReceiveFailure();
+
+    EXPECT_FALSE(Write("foo"));
+}
+
+TEST_F(UdpTest, ResponseTimeoutRecovery) {
+    for (int i = 0; i < kMaxTransmissionAttempts - 1; ++i) {
+        mock_socket_->ExpectSend(FastbootPacket(1, "foo"));
+        mock_socket_->AddReceiveTimeout();
+    }
+    mock_socket_->ExpectSend(FastbootPacket(1, "foo"));
+    mock_socket_->AddReceive(FastbootPacket(1, ""));
+
+    EXPECT_TRUE(Write("foo"));
+}
+
+// Tests continuation packets for various max packet sizes.
+// The important part of this test is that regardless of what kind of packet fragmentation happens
+// at the socket layer, a single call to Transport::Read() and Transport::Write() is all the
+// fastboot code needs to do.
+TEST_F(UdpTest, ContinuationPackets) {
+    for (uint16_t max_packet_size : {512, 1024, 1200}) {
+        ASSERT_TRUE(InitializeTransport(0, max_packet_size));
+
+        // Initialize the data we want to send. Use (size - 4) to leave room for the header.
+        size_t max_data_size = max_packet_size - 4;
+        std::string data(max_data_size * 3, '\0');
+        for (size_t i = 0; i < data.length(); ++i) {
+            data[i] = i;
+        }
+        std::string chunks[] = {data.substr(0, max_data_size),
+                                data.substr(max_data_size, max_data_size),
+                                data.substr(max_data_size * 2, max_data_size)};
+
+        // Write data: split into 3 UDP packets, each of which will be ACKed.
+        mock_socket_->ExpectSend(FastbootPacket(1, chunks[0], kFlagContinuation));
+        mock_socket_->AddReceive(FastbootPacket(1));
+        mock_socket_->ExpectSend(FastbootPacket(2, chunks[1], kFlagContinuation));
+        mock_socket_->AddReceive(FastbootPacket(2));
+        mock_socket_->ExpectSend(FastbootPacket(3, chunks[2]));
+        mock_socket_->AddReceive(FastbootPacket(3));
+        EXPECT_TRUE(Write(data));
+
+        // Same thing for reading the data.
+        mock_socket_->ExpectSend(FastbootPacket(4));
+        mock_socket_->AddReceive(FastbootPacket(4, chunks[0], kFlagContinuation));
+        mock_socket_->ExpectSend(FastbootPacket(5));
+        mock_socket_->AddReceive(FastbootPacket(5, chunks[1], kFlagContinuation));
+        mock_socket_->ExpectSend(FastbootPacket(6));
+        mock_socket_->AddReceive(FastbootPacket(6, chunks[2]));
+        EXPECT_TRUE(Read(data));
+    }
+}
+
+// Tests that the continuation bit is respected even if the packet isn't max size.
+TEST_F(UdpTest, SmallContinuationPackets) {
+    mock_socket_->ExpectSend(FastbootPacket(1));
+    mock_socket_->AddReceive(FastbootPacket(1, "foo", kFlagContinuation));
+    mock_socket_->ExpectSend(FastbootPacket(2));
+    mock_socket_->AddReceive(FastbootPacket(2, "bar"));
+
+    EXPECT_TRUE(Read("foobar"));
+}
+
+// Tests receiving an error packet mid-continuation.
+TEST_F(UdpTest, ContinuationPacketError) {
+    mock_socket_->ExpectSend(FastbootPacket(1));
+    mock_socket_->AddReceive(FastbootPacket(1, "foo", kFlagContinuation));
+    mock_socket_->ExpectSend(FastbootPacket(2));
+    mock_socket_->AddReceive(ErrorPacket(2, "test error"));
+
+    EXPECT_FALSE(Read("foo"));
+}
+
+// Tests timeout during a continuation sequence.
+TEST_F(UdpTest, ContinuationTimeoutRecovery) {
+    mock_socket_->ExpectSend(FastbootPacket(1));
+    mock_socket_->AddReceive(FastbootPacket(1, "foo", kFlagContinuation));
+    mock_socket_->ExpectSend(FastbootPacket(2));
+    mock_socket_->AddReceiveTimeout();
+    mock_socket_->ExpectSend(FastbootPacket(2));
+    mock_socket_->AddReceive(FastbootPacket(2, "bar"));
+
+    EXPECT_TRUE(Read("foobar"));
+}
+
+// Tests read overflow returns -1 to indicate the failure.
+TEST_F(UdpTest, MultipleReadPacket) {
+    mock_socket_->ExpectSend(FastbootPacket(1));
+    mock_socket_->AddReceive(FastbootPacket(1, "foobarbaz"));
+
+    char buffer[3];
+    EXPECT_EQ(-1, transport_->Read(buffer, 3));
+}
+
+// Tests that packets arriving out-of-order are ignored.
+TEST_F(UdpTest, IgnoreOutOfOrderPackets) {
+    mock_socket_->ExpectSend(FastbootPacket(1));
+    mock_socket_->AddReceive(FastbootPacket(0, "sequence too low"));
+    mock_socket_->AddReceive(FastbootPacket(2, "sequence too high"));
+    mock_socket_->AddReceive(QueryPacket(1));
+    mock_socket_->AddReceive(FastbootPacket(1, "correct"));
+
+    EXPECT_TRUE(Read("correct"));
+}
+
+// Tests that an error response with the correct sequence number causes immediate failure.
+TEST_F(UdpTest, ErrorResponse) {
+    // Error packets with the wrong sequence number should be ignored like any other packet.
+    mock_socket_->ExpectSend(FastbootPacket(1, "foo"));
+    mock_socket_->AddReceive(ErrorPacket(0, "ignored error"));
+    mock_socket_->AddReceive(FastbootPacket(1));
+
+    EXPECT_TRUE(Write("foo"));
+
+    // Error packets with the correct sequence should abort immediately without retransmission.
+    mock_socket_->ExpectSend(FastbootPacket(2, "foo"));
+    mock_socket_->AddReceive(ErrorPacket(2, "test error"));
+
+    EXPECT_FALSE(Write("foo"));
+}
+
+// Tests that attempting to use a closed transport returns -1 without making any socket calls.
+TEST_F(UdpTest, CloseTransport) {
+    char buffer[32];
+    EXPECT_EQ(0, transport_->Close());
+    EXPECT_EQ(-1, transport_->Write("foo", 3));
+    EXPECT_EQ(-1, transport_->Read(buffer, sizeof(buffer)));
+}
diff --git a/fs_mgr/fs_mgr_format.c b/fs_mgr/fs_mgr_format.c
index c73045d..853bf0b 100644
--- a/fs_mgr/fs_mgr_format.c
+++ b/fs_mgr/fs_mgr_format.c
@@ -33,7 +33,7 @@
 
 static int format_ext4(char *fs_blkdev, char *fs_mnt_point)
 {
-    unsigned int nr_sec;
+    uint64_t dev_sz;
     int fd, rc = 0;
 
     if ((fd = open(fs_blkdev, O_WRONLY, 0644)) < 0) {
@@ -41,7 +41,7 @@
         return -1;
     }
 
-    if ((ioctl(fd, BLKGETSIZE, &nr_sec)) == -1) {
+    if ((ioctl(fd, BLKGETSIZE64, &dev_sz)) == -1) {
         ERROR("Cannot get block device size.  %s\n", strerror(errno));
         close(fd);
         return -1;
@@ -49,7 +49,7 @@
 
     /* Format the partition using the calculated length */
     reset_ext4fs_info();
-    info.len = ((off64_t)nr_sec * 512);
+    info.len = (off64_t)dev_sz;
 
     /* Use make_ext4fs_internal to avoid wiping an already-wiped partition. */
     rc = make_ext4fs_internal(fd, NULL, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
diff --git a/include/utils/String16.h b/include/utils/String16.h
index 9a67c7a..50ac6d0 100644
--- a/include/utils/String16.h
+++ b/include/utils/String16.h
@@ -62,9 +62,9 @@
     explicit                    String16(const char* o, size_t len);
 
                                 ~String16();
-    
+
     inline  const char16_t*     string() const;
-    
+
             size_t              size() const;
             void                setTo(const String16& other);
             status_t            setTo(const char16_t* other);
@@ -72,12 +72,12 @@
             status_t            setTo(const String16& other,
                                       size_t len,
                                       size_t begin=0);
-    
+
             status_t            append(const String16& other);
             status_t            append(const char16_t* other, size_t len);
-            
+
     inline  String16&           operator=(const String16& other);
-    
+
     inline  String16&           operator+=(const String16& other);
     inline  String16            operator+(const String16& other) const;
 
@@ -90,7 +90,7 @@
 
             bool                startsWith(const String16& prefix) const;
             bool                startsWith(const char16_t* prefix) const;
-            
+
             status_t            makeLower();
 
             status_t            replaceAll(char16_t replaceThis,
@@ -106,16 +106,16 @@
     inline  bool                operator!=(const String16& other) const;
     inline  bool                operator>=(const String16& other) const;
     inline  bool                operator>(const String16& other) const;
-    
+
     inline  bool                operator<(const char16_t* other) const;
     inline  bool                operator<=(const char16_t* other) const;
     inline  bool                operator==(const char16_t* other) const;
     inline  bool                operator!=(const char16_t* other) const;
     inline  bool                operator>=(const char16_t* other) const;
     inline  bool                operator>(const char16_t* other) const;
-    
+
     inline                      operator const char16_t*() const;
-    
+
 private:
             const char16_t*     mString;
 };
diff --git a/include/utils/ThreadDefs.h b/include/utils/ThreadDefs.h
index 9711c13..ae091e4 100644
--- a/include/utils/ThreadDefs.h
+++ b/include/utils/ThreadDefs.h
@@ -29,7 +29,11 @@
 extern "C" {
 #endif
 
+#ifdef _WIN32
+typedef uint32_t android_thread_id_t;
+#else
 typedef void* android_thread_id_t;
+#endif
 
 typedef int (*android_thread_func_t)(void*);
 
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index ee56a5e..397dfda 100644
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -71,14 +71,22 @@
 build_type := host
 libbacktrace_multilib := both
 include $(LOCAL_PATH)/Android.build.mk
+
+libbacktrace_shared_libraries :=
+
 libbacktrace_static_libraries := \
 	libbase \
 	liblog \
 	libunwind \
+	liblzma \
 
+module := libbacktrace
+build_type := target
 build_target := STATIC_LIBRARY
 include $(LOCAL_PATH)/Android.build.mk
-libbacktrace_static_libraries :=
+build_type := host
+libbacktrace_multilib := both
+include $(LOCAL_PATH)/Android.build.mk
 
 #-------------------------------------------------------------------------
 # The libbacktrace_offline shared library.
@@ -106,7 +114,6 @@
 	libLLVMSupport \
 
 module := libbacktrace_offline
-module_tag := optional
 build_type := target
 build_target := SHARED_LIBRARY
 include $(LOCAL_PATH)/Android.build.mk
@@ -114,6 +121,26 @@
 libbacktrace_multilib := both
 include $(LOCAL_PATH)/Android.build.mk
 
+libbacktrace_offline_shared_libraries :=
+libbacktrace_offline_static_libraries := \
+	libbacktrace \
+	libbase \
+	libcutils \
+	liblog \
+	libunwind \
+	liblzma \
+	libLLVMObject \
+	libLLVMBitReader \
+	libLLVMMC \
+	libLLVMMCParser \
+	libLLVMCore \
+	libLLVMSupport \
+
+module := libbacktrace_offline
+build_type := target
+build_target := STATIC_LIBRARY
+include $(LOCAL_PATH)/Android.build.mk
+
 #-------------------------------------------------------------------------
 # The libbacktrace_test library needed by backtrace_test.
 #-------------------------------------------------------------------------
diff --git a/libdiskconfig/Android.mk b/libdiskconfig/Android.mk
index 624e385..a49ce58 100644
--- a/libdiskconfig/Android.mk
+++ b/libdiskconfig/Android.mk
@@ -13,6 +13,8 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_SYSTEM_SHARED_LIBRARIES := libcutils liblog libc
 LOCAL_CFLAGS := -Werror
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 include $(BUILD_SHARED_LIBRARY)
 
 ifeq ($(HOST_OS),linux)
@@ -21,5 +23,7 @@
 LOCAL_MODULE := libdiskconfig_host
 LOCAL_MODULE_TAGS := optional
 LOCAL_CFLAGS := -O2 -g -W -Wall -Werror -D_LARGEFILE64_SOURCE
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 include $(BUILD_HOST_STATIC_LIBRARY)
 endif # HOST_OS == linux
diff --git a/include/diskconfig/diskconfig.h b/libdiskconfig/include/diskconfig/diskconfig.h
similarity index 100%
rename from include/diskconfig/diskconfig.h
rename to libdiskconfig/include/diskconfig/diskconfig.h
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index cb80ee6..a6d9a34 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -367,7 +367,11 @@
     char prefixBuf[128], suffixBuf[128];
     char priChar;
     time_t when;
+#if !defined(_WIN32)
     pid_t pid, tid;
+#else
+    uint32_t pid, tid;
+#endif
 
     TRACE("LOG %d: %s %s", logPrio, tag, msg);
 
@@ -685,6 +689,17 @@
     return redirectOpen(pathName, flags);
 }
 
+/*
+ * The logger API has no means or need to 'stop' or 'close' using the logs,
+ * and as such, there is no way for that 'stop' or 'close' to translate into
+ * a close operation to the fake log handler. fakeLogClose is provided for
+ * completeness only.
+ *
+ * We have no intention of adding a log close operation as it would complicate
+ * every user of the logging API with no gain since the only valid place to
+ * call is in the exit handler. Logging can continue in the exit handler to
+ * help debug HOST tools ...
+ */
 int fakeLogClose(int fd)
 {
     /* Assume that open() was called first. */
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 8517c9f..f8d4c4c 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -173,7 +173,7 @@
     return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
 }
 
-TEST(liblog, __android_log_bswrite) {
+static void bswrite_test(const char *message) {
     struct logger_list *logger_list;
 
     pid_t pid = getpid();
@@ -181,10 +181,30 @@
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
         LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
-    static const char buffer[] = "Hello World";
     log_time ts(android_log_clockid());
 
-    ASSERT_LT(0, __android_log_bswrite(0, buffer));
+    ASSERT_LT(0, __android_log_bswrite(0, message));
+    size_t num_lines = 1, size = 0, length = 0, total = 0;
+    const char *cp = message;
+    while (*cp) {
+        if (*cp == '\n') {
+            if (cp[1]) {
+                ++num_lines;
+            }
+        } else {
+            ++size;
+        }
+        ++cp;
+        ++total;
+        ++length;
+        if ((LOGGER_ENTRY_MAX_PAYLOAD - 4 - 1 - 4) <= length) {
+            break;
+        }
+    }
+    while (*cp) {
+        ++cp;
+        ++total;
+    }
     usleep(1000000);
 
     int count = 0;
@@ -199,7 +219,7 @@
 
         if ((log_msg.entry.sec < (ts.tv_sec - 1))
          || ((ts.tv_sec + 1) < log_msg.entry.sec)
-         || (log_msg.entry.len != (4 + 1 + 4 + sizeof(buffer) - 1))
+         || ((size_t)log_msg.entry.len != (4 + 1 + 4 + length))
          || (log_msg.id() != LOG_ID_EVENTS)) {
             continue;
         }
@@ -210,21 +230,22 @@
             continue;
         }
 
-        int len = get4LE(eventData + 4 + 1);
-        if (len == (sizeof(buffer) - 1)) {
+        size_t len = get4LE(eventData + 4 + 1);
+        if (len == total) {
             ++count;
 
             AndroidLogFormat *logformat = android_log_format_new();
             EXPECT_TRUE(NULL != logformat);
             AndroidLogEntry entry;
             char msgBuf[1024];
-            EXPECT_EQ(0, android_log_processBinaryLogBuffer(&log_msg.entry_v1,
-                                                            &entry,
-                                                            NULL,
-                                                            msgBuf,
-                                                            sizeof(msgBuf)));
-            fflush(stderr);
-            EXPECT_EQ(31, android_log_printLogLine(logformat, fileno(stderr), &entry));
+            int processBinaryLogBuffer = android_log_processBinaryLogBuffer(
+                &log_msg.entry_v1, &entry, NULL, msgBuf, sizeof(msgBuf));
+            EXPECT_EQ((length == total) ? 0 : -1, processBinaryLogBuffer);
+            if (processBinaryLogBuffer == 0) {
+                fflush(stderr);
+                EXPECT_EQ((int)((20 * num_lines) + size),
+                    android_log_printLogLine(logformat, fileno(stderr), &entry));
+            }
             android_log_format_free(logformat);
         }
     }
@@ -234,18 +255,55 @@
     android_logger_list_close(logger_list);
 }
 
-TEST(liblog, __android_log_bswrite__empty_string) {
+TEST(liblog, __android_log_bswrite_and_print) {
+    bswrite_test("Hello World");
+}
+
+TEST(liblog, __android_log_bswrite_and_print__empty_string) {
+    bswrite_test("");
+}
+
+TEST(liblog, __android_log_bswrite_and_print__newline_prefix) {
+    bswrite_test("\nHello World\n");
+}
+
+TEST(liblog, __android_log_bswrite_and_print__newline_space_prefix) {
+    bswrite_test("\n Hello World \n");
+}
+
+TEST(liblog, __android_log_bswrite_and_print__multiple_newline) {
+    bswrite_test("one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten");
+}
+
+static void buf_write_test(const char *message) {
     struct logger_list *logger_list;
 
     pid_t pid = getpid();
 
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+        LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
-    static const char buffer[] = "";
+    static const char tag[] = "TEST__android_log_buf_write";
     log_time ts(android_log_clockid());
 
-    ASSERT_LT(0, __android_log_bswrite(0, buffer));
+    EXPECT_LT(0, __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_INFO,
+                                         tag, message));
+    size_t num_lines = 1, size = 0, length = 0;
+    const char *cp = message;
+    while (*cp) {
+        if (*cp == '\n') {
+            if (cp[1]) {
+                ++num_lines;
+            }
+        } else {
+            ++size;
+        }
+        ++length;
+        if ((LOGGER_ENTRY_MAX_PAYLOAD - 2 - sizeof(tag)) <= length) {
+            break;
+        }
+        ++cp;
+    }
     usleep(1000000);
 
     int count = 0;
@@ -260,34 +318,25 @@
 
         if ((log_msg.entry.sec < (ts.tv_sec - 1))
          || ((ts.tv_sec + 1) < log_msg.entry.sec)
-         || (log_msg.entry.len != (4 + 1 + 4))
-         || (log_msg.id() != LOG_ID_EVENTS)) {
+         || ((size_t)log_msg.entry.len != (sizeof(tag) + length + 2))
+         || (log_msg.id() != LOG_ID_MAIN)) {
             continue;
         }
 
-        char *eventData = log_msg.msg();
+        ++count;
 
-        if (eventData[4] != EVENT_TYPE_STRING) {
-            continue;
-        }
-
-        int len = get4LE(eventData + 4 + 1);
-        if (len == 0) {
-            ++count;
-
-            AndroidLogFormat *logformat = android_log_format_new();
-            EXPECT_TRUE(NULL != logformat);
-            AndroidLogEntry entry;
-            char msgBuf[1024];
-            EXPECT_EQ(0, android_log_processBinaryLogBuffer(&log_msg.entry_v1,
-                                                            &entry,
-                                                            NULL,
-                                                            msgBuf,
-                                                            sizeof(msgBuf)));
+        AndroidLogFormat *logformat = android_log_format_new();
+        EXPECT_TRUE(NULL != logformat);
+        AndroidLogEntry entry;
+        int processLogBuffer = android_log_processLogBuffer(&log_msg.entry_v1,
+                                                            &entry);
+        EXPECT_EQ(0, processLogBuffer);
+        if (processLogBuffer == 0) {
             fflush(stderr);
-            EXPECT_EQ(20, android_log_printLogLine(logformat, fileno(stderr), &entry));
-            android_log_format_free(logformat);
+            EXPECT_EQ((int)(((11 + sizeof(tag)) * num_lines) + size),
+                android_log_printLogLine(logformat, fileno(stderr), &entry));
         }
+        android_log_format_free(logformat);
     }
 
     EXPECT_EQ(1, count);
@@ -295,6 +344,18 @@
     android_logger_list_close(logger_list);
 }
 
+TEST(liblog, __android_log_buf_write_and_print__empty) {
+    buf_write_test("");
+}
+
+TEST(liblog, __android_log_buf_write_and_print__newline_prefix) {
+    buf_write_test("\nHello World\n");
+}
+
+TEST(liblog, __android_log_buf_write_and_print__newline_space_prefix) {
+    buf_write_test("\n Hello World \n");
+}
+
 TEST(liblog, __security) {
     static const char persist_key[] = "persist.logd.security";
     static const char readonly_key[] = "ro.device_owner";
@@ -609,7 +670,7 @@
     EXPECT_GT(one_percent_ticks, user_ticks + system_ticks);
 }
 
-static const char max_payload_tag[] = "TEST_max_payload_XXXX";
+static const char max_payload_tag[] = "TEST_max_payload_and_longish_tag_XXXX";
 #define SIZEOF_MAX_PAYLOAD_BUF (LOGGER_ENTRY_MAX_PAYLOAD - \
                                 sizeof(max_payload_tag) - 1)
 static const char max_payload_buf[] = "LEONATO\n\
@@ -1576,6 +1637,14 @@
     android_logger_list_close(logger_list);
 }
 
+TEST(liblog, __android_log_bswrite_and_print___max) {
+    bswrite_test(max_payload_buf);
+}
+
+TEST(liblog, __android_log_buf_write_and_print__max) {
+    buf_write_test(max_payload_buf);
+}
+
 TEST(liblog, android_errorWriteLog__android_logger_list_read__success) {
     const int TAG = 123456785;
     const char SUBTAG[] = "test-subtag";
diff --git a/libmemtrack/Android.mk b/libmemtrack/Android.mk
index 7b170f5..ffc7244 100644
--- a/libmemtrack/Android.mk
+++ b/libmemtrack/Android.mk
@@ -5,6 +5,8 @@
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := memtrack.c
 LOCAL_MODULE := libmemtrack
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
 LOCAL_C_INCLUDES += hardware/libhardware/include
 LOCAL_SHARED_LIBRARIES := libhardware liblog
 LOCAL_CFLAGS := -Wall -Werror
diff --git a/include/memtrack/memtrack.h b/libmemtrack/include/memtrack/memtrack.h
similarity index 98%
rename from include/memtrack/memtrack.h
rename to libmemtrack/include/memtrack/memtrack.h
index 3917300..8c0ab89 100644
--- a/include/memtrack/memtrack.h
+++ b/libmemtrack/include/memtrack/memtrack.h
@@ -19,7 +19,6 @@
 
 #include <sys/types.h>
 #include <stddef.h>
-#include <cutils/compiler.h>
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/libnativeloader/Android.mk b/libnativeloader/Android.mk
index 5e65c4c..6c064c7 100644
--- a/libnativeloader/Android.mk
+++ b/libnativeloader/Android.mk
@@ -17,7 +17,8 @@
 LOCAL_CPPFLAGS := -std=gnu++14 -fvisibility=hidden
 LOCAL_LDFLAGS := -ldl
 LOCAL_MULTILIB := both
-
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 include $(BUILD_SHARED_LIBRARY)
 
 # Shared library for host
@@ -34,7 +35,8 @@
 LOCAL_CPPFLAGS := -std=gnu++14 -fvisibility=hidden
 LOCAL_LDFLAGS := -ldl
 LOCAL_MULTILIB := both
-
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 include $(BUILD_HOST_SHARED_LIBRARY)
 
 # Static library for host
@@ -50,5 +52,6 @@
 LOCAL_CPPFLAGS := -std=gnu++14 -fvisibility=hidden
 LOCAL_LDFLAGS := -ldl
 LOCAL_MULTILIB := both
-
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/include/nativeloader/native_loader.h b/libnativeloader/include/nativeloader/native_loader.h
similarity index 100%
rename from include/nativeloader/native_loader.h
rename to libnativeloader/include/nativeloader/native_loader.h
diff --git a/libnetutils/Android.mk b/libnetutils/Android.mk
index 2060df4..281b6c8 100644
--- a/libnetutils/Android.mk
+++ b/libnetutils/Android.mk
@@ -16,6 +16,9 @@
 
 LOCAL_CFLAGS := -Werror
 
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+
 include $(BUILD_SHARED_LIBRARY)
 
 include $(CLEAR_VARS)
diff --git a/include/netutils/dhcp.h b/libnetutils/include/netutils/dhcp.h
similarity index 100%
rename from include/netutils/dhcp.h
rename to libnetutils/include/netutils/dhcp.h
diff --git a/include/netutils/ifc.h b/libnetutils/include/netutils/ifc.h
similarity index 100%
rename from include/netutils/ifc.h
rename to libnetutils/include/netutils/ifc.h
diff --git a/libutils/Android.mk b/libutils/Android.mk
index 8c4fd15..9e0d0ac 100644
--- a/libutils/Android.mk
+++ b/libutils/Android.mk
@@ -22,7 +22,6 @@
 	Log.cpp \
 	NativeHandle.cpp \
 	Printer.cpp \
-	ProcessCallStack.cpp \
 	PropertyMap.cpp \
 	RefBase.cpp \
 	SharedBuffer.cpp \
@@ -44,7 +43,7 @@
 # =====================================================
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES:= $(commonSources)
-LOCAL_SRC_FILES_linux := Looper.cpp
+LOCAL_SRC_FILES_linux := Looper.cpp ProcessCallStack.cpp
 LOCAL_CFLAGS_darwin := -Wno-unused-parameter
 LOCAL_MODULE:= libutils
 LOCAL_STATIC_LIBRARIES := liblog
@@ -67,6 +66,7 @@
 	$(commonSources) \
 	BlobCache.cpp \
 	Looper.cpp \
+	ProcessCallStack.cpp \
 	Trace.cpp
 
 ifeq ($(TARGET_ARCH),mips)
diff --git a/libutils/ProcessCallStack.cpp b/libutils/ProcessCallStack.cpp
index 011c302..cdb586d 100644
--- a/libutils/ProcessCallStack.cpp
+++ b/libutils/ProcessCallStack.cpp
@@ -146,7 +146,6 @@
     clear();
 
     // Get current time.
-#ifndef USE_MINGW
     {
         time_t t = time(NULL);
         struct tm tm;
@@ -199,7 +198,6 @@
         ALOGE("%s: Failed to readdir from %s: %s",
               __FUNCTION__, PATH_SELF_TASK, strerror(code));
     }
-#endif
 
     closedir(dp);
 }
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index 6a5273f..449fb20 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -77,7 +77,7 @@
         //printf("Created UTF-16 string from UTF-8 \"%s\":", in);
         //printHexData(1, str, buf->size(), 16, 1);
         //printf("\n");
-        
+
         return u16str;
     }
 
@@ -127,7 +127,7 @@
         mString = str;
         return;
     }
-    
+
     mString = getEmptyString();
 }
 
@@ -142,7 +142,7 @@
         mString = str;
         return;
     }
-    
+
     mString = getEmptyString();
 }
 
@@ -228,7 +228,7 @@
     } else if (otherLen == 0) {
         return NO_ERROR;
     }
-    
+
     SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
         ->editResize((myLen+otherLen+1)*sizeof(char16_t));
     if (buf) {
@@ -249,7 +249,7 @@
     } else if (otherLen == 0) {
         return NO_ERROR;
     }
-    
+
     SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
         ->editResize((myLen+otherLen+1)*sizeof(char16_t));
     if (buf) {
diff --git a/libziparchive/Android.mk b/libziparchive/Android.mk
index 056b3e1..3cd8b87 100644
--- a/libziparchive/Android.mk
+++ b/libziparchive/Android.mk
@@ -95,13 +95,12 @@
 LOCAL_CFLAGS := $(libziparchive_common_c_flags)
 LOCAL_CPPFLAGS := -Wno-unnamed-type-template-args $(libziparchive_common_cpp_flags)
 LOCAL_SRC_FILES := $(libziparchive_test_files)
-LOCAL_SHARED_LIBRARIES := \
-    libziparchive-host \
-    liblog \
-    libbase \
-
 LOCAL_STATIC_LIBRARIES := \
-    libutils \
+    libziparchive-host \
     libz \
+    libbase \
+    libutils \
+    liblog \
 
+LOCAL_MODULE_HOST_OS := darwin linux windows
 include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 3b1e972..a2d6fcc 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -224,9 +224,7 @@
           strerror(errno));
     return kIoError;
   }
-  ssize_t actual = TEMP_FAILURE_RETRY(
-      read(fd, scan_buffer, static_cast<size_t>(read_amount)));
-  if (actual != static_cast<ssize_t>(read_amount)) {
+  if (!android::base::ReadFully(fd, scan_buffer, static_cast<size_t>(read_amount))) {
     ALOGW("Zip: read %" PRId64 " failed: %s", static_cast<int64_t>(read_amount),
           strerror(errno));
     return kIoError;
@@ -481,8 +479,7 @@
 static int32_t UpdateEntryFromDataDescriptor(int fd,
                                              ZipEntry *entry) {
   uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)];
-  ssize_t actual = TEMP_FAILURE_RETRY(read(fd, ddBuf, sizeof(ddBuf)));
-  if (actual != sizeof(ddBuf)) {
+  if (!android::base::ReadFully(fd, ddBuf, sizeof(ddBuf))) {
     return kIoError;
   }
 
@@ -498,26 +495,14 @@
 }
 
 // Attempts to read |len| bytes into |buf| at offset |off|.
-//
-// This method uses pread64 on platforms that support it and
-// lseek64 + read on platforms that don't. This implies that
-// callers should not rely on the |fd| offset being incremented
+// Callers should not rely on the |fd| offset being incremented
 // as a side effect of this call.
-static inline ssize_t ReadAtOffset(int fd, uint8_t* buf, size_t len,
-                                   off64_t off) {
-#if !defined(_WIN32)
-  return TEMP_FAILURE_RETRY(pread64(fd, buf, len, off));
-#else
-  // The only supported platform that doesn't support pread at the moment
-  // is Windows. Only recent versions of windows support unix like forks,
-  // and even there the semantics are quite different.
+static inline bool ReadAtOffset(int fd, uint8_t* buf, size_t len, off64_t off) {
   if (lseek64(fd, off, SEEK_SET) != off) {
     ALOGW("Zip: failed seek to offset %" PRId64, off);
-    return kIoError;
+    return false;
   }
-
-  return TEMP_FAILURE_RETRY(read(fd, buf, len));
-#endif
+  return android::base::ReadFully(fd, buf, len);
 }
 
 static int32_t FindEntry(const ZipArchive* archive, const int ent,
@@ -567,9 +552,7 @@
   }
 
   uint8_t lfh_buf[sizeof(LocalFileHeader)];
-  ssize_t actual = ReadAtOffset(archive->fd, lfh_buf, sizeof(lfh_buf),
-                                 local_header_offset);
-  if (actual != sizeof(lfh_buf)) {
+  if (!ReadAtOffset(archive->fd, lfh_buf, sizeof(lfh_buf), local_header_offset)) {
     ALOGW("Zip: failed reading lfh name from offset %" PRId64,
         static_cast<int64_t>(local_header_offset));
     return kIoError;
@@ -610,10 +593,7 @@
     }
 
     uint8_t* name_buf = reinterpret_cast<uint8_t*>(malloc(nameLen));
-    ssize_t actual = ReadAtOffset(archive->fd, name_buf, nameLen,
-                                  name_offset);
-
-    if (actual != nameLen) {
+    if (!ReadAtOffset(archive->fd, name_buf, nameLen, name_offset)) {
       ALOGW("Zip: failed reading lfh name from offset %" PRId64, static_cast<int64_t>(name_offset));
       free(name_buf);
       return kIoError;
@@ -942,10 +922,9 @@
   do {
     /* read as much as we can */
     if (zstream.avail_in == 0) {
-      const ZD_TYPE getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
-      const ZD_TYPE actual = TEMP_FAILURE_RETRY(read(fd, &read_buf[0], getSize));
-      if (actual != getSize) {
-        ALOGW("Zip: inflate read failed (" ZD " vs " ZD ")", actual, getSize);
+      const size_t getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
+      if (!android::base::ReadFully(fd, read_buf.data(), getSize)) {
+        ALOGW("Zip: inflate read failed, getSize = %zu: %s", getSize, strerror(errno));
         return kIoError;
       }
 
@@ -1005,11 +984,9 @@
 
     // Safe conversion because kBufSize is narrow enough for a 32 bit signed
     // value.
-    const ssize_t block_size = (remaining > kBufSize) ? kBufSize : remaining;
-    const ssize_t actual = TEMP_FAILURE_RETRY(read(fd, &buf[0], block_size));
-
-    if (actual != block_size) {
-      ALOGW("CopyFileToFile: copy read failed (" ZD " vs " ZD ")", actual, block_size);
+    const size_t block_size = (remaining > kBufSize) ? kBufSize : remaining;
+    if (!android::base::ReadFully(fd, buf.data(), block_size)) {
+      ALOGW("CopyFileToFile: copy read failed, block_size = %zu: %s", block_size, strerror(errno));
       return kIoError;
     }
 
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index d426dc4..6aee1bb 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -21,9 +21,11 @@
 #include <string.h>
 #include <unistd.h>
 
+#include <memory>
 #include <vector>
 
 #include <android-base/file.h>
+#include <android-base/test_utils.h>
 #include <gtest/gtest.h>
 #include <ziparchive/zip_archive.h>
 #include <ziparchive/zip_archive_stream_entry.h>
@@ -91,7 +93,7 @@
 }
 
 TEST(ziparchive, OpenAssumeFdOwnership) {
-  int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY);
+  int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
   ASSERT_NE(-1, fd);
   ZipArchiveHandle handle;
   ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle));
@@ -101,7 +103,7 @@
 }
 
 TEST(ziparchive, OpenDoNotAssumeFdOwnership) {
-  int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY);
+  int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
   ASSERT_NE(-1, fd);
   ZipArchiveHandle handle;
   ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle, false));
@@ -373,30 +375,13 @@
 static const std::string kAbTxtName("ab.txt");
 static const size_t kAbUncompressedSize = 270216;
 
-static int make_temporary_file(const char* file_name_pattern) {
-  char full_path[1024];
-  // Account for differences between the host and the target.
-  //
-  // TODO: Maybe reuse bionic/tests/TemporaryFile.h.
-  snprintf(full_path, sizeof(full_path), "/data/local/tmp/%s", file_name_pattern);
-  int fd = mkstemp(full_path);
-  if (fd == -1) {
-    snprintf(full_path, sizeof(full_path), "/tmp/%s", file_name_pattern);
-    fd = mkstemp(full_path);
-  }
-
-  return fd;
-}
-
 TEST(ziparchive, EmptyEntries) {
-  char temp_file_pattern[] = "empty_entries_test_XXXXXX";
-  int fd = make_temporary_file(temp_file_pattern);
-  ASSERT_NE(-1, fd);
-  const ssize_t file_size = sizeof(kEmptyEntriesZip);
-  ASSERT_EQ(file_size, TEMP_FAILURE_RETRY(write(fd, kEmptyEntriesZip, file_size)));
+  TemporaryFile tmp_file;
+  ASSERT_NE(-1, tmp_file.fd);
+  ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, kEmptyEntriesZip, sizeof(kEmptyEntriesZip)));
 
   ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveFd(fd, "EmptyEntriesTest", &handle));
+  ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle));
 
   ZipEntry entry;
   ZipString empty_name;
@@ -406,27 +391,23 @@
   uint8_t buffer[1];
   ASSERT_EQ(0, ExtractToMemory(handle, &entry, buffer, 1));
 
-  char output_file_pattern[] = "empty_entries_output_XXXXXX";
-  int output_fd = make_temporary_file(output_file_pattern);
-  ASSERT_NE(-1, output_fd);
-  ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, output_fd));
+
+  TemporaryFile tmp_output_file;
+  ASSERT_NE(-1, tmp_output_file.fd);
+  ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_output_file.fd));
 
   struct stat stat_buf;
-  ASSERT_EQ(0, fstat(output_fd, &stat_buf));
+  ASSERT_EQ(0, fstat(tmp_output_file.fd, &stat_buf));
   ASSERT_EQ(0, stat_buf.st_size);
-
-  close(fd);
-  close(output_fd);
 }
 
 TEST(ziparchive, EntryLargerThan32K) {
-  char temp_file_pattern[] = "entry_larger_than_32k_test_XXXXXX";
-  int fd = make_temporary_file(temp_file_pattern);
-  ASSERT_NE(-1, fd);
-  ASSERT_TRUE(android::base::WriteFully(fd, reinterpret_cast<const uint8_t*>(kAbZip),
+  TemporaryFile tmp_file;
+  ASSERT_NE(-1, tmp_file.fd);
+  ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, reinterpret_cast<const uint8_t*>(kAbZip),
                          sizeof(kAbZip) - 1));
   ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveFd(fd, "EntryLargerThan32KTest", &handle));
+  ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EntryLargerThan32KTest", &handle));
 
   ZipEntry entry;
   ZipString ab_name;
@@ -439,21 +420,21 @@
   ASSERT_EQ(0, ExtractToMemory(handle, &entry, &buffer[0], buffer.size()));
 
   // Extract the entry to a file.
-  char output_file_pattern[] = "entry_larger_than_32k_test_output_XXXXXX";
-  int output_fd = make_temporary_file(output_file_pattern);
-  ASSERT_NE(-1, output_fd);
-  ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, output_fd));
+  TemporaryFile tmp_output_file;
+  ASSERT_NE(-1, tmp_output_file.fd);
+  ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_output_file.fd));
 
   // Make sure the extracted file size is as expected.
   struct stat stat_buf;
-  ASSERT_EQ(0, fstat(output_fd, &stat_buf));
+  ASSERT_EQ(0, fstat(tmp_output_file.fd, &stat_buf));
   ASSERT_EQ(kAbUncompressedSize, static_cast<size_t>(stat_buf.st_size));
 
   // Read the file back to a buffer and make sure the contents are
   // the same as the memory buffer we extracted directly to.
   std::vector<uint8_t> file_contents(kAbUncompressedSize);
-  ASSERT_EQ(0, lseek64(output_fd, 0, SEEK_SET));
-  ASSERT_TRUE(android::base::ReadFully(output_fd, &file_contents[0], file_contents.size()));
+  ASSERT_EQ(0, lseek64(tmp_output_file.fd, 0, SEEK_SET));
+  ASSERT_TRUE(android::base::ReadFully(tmp_output_file.fd, &file_contents[0],
+                                       file_contents.size()));
   ASSERT_EQ(file_contents, buffer);
 
   for (int i = 0; i < 90072; ++i) {
@@ -462,35 +443,28 @@
     ASSERT_EQ('b', line[1]);
     ASSERT_EQ('\n', line[2]);
   }
-
-  close(fd);
-  close(output_fd);
 }
 
 TEST(ziparchive, TrailerAfterEOCD) {
-  char temp_file_pattern[] = "trailer_after_eocd_test_XXXXXX";
-  int fd = make_temporary_file(temp_file_pattern);
-  ASSERT_NE(-1, fd);
+  TemporaryFile tmp_file;
+  ASSERT_NE(-1, tmp_file.fd);
 
   // Create a file with 8 bytes of random garbage.
   static const uint8_t trailer[] = { 'A' ,'n', 'd', 'r', 'o', 'i', 'd', 'z' };
-  const ssize_t file_size = sizeof(kEmptyEntriesZip);
-  const ssize_t trailer_size = sizeof(trailer);
-  ASSERT_EQ(file_size, TEMP_FAILURE_RETRY(write(fd, kEmptyEntriesZip, file_size)));
-  ASSERT_EQ(trailer_size, TEMP_FAILURE_RETRY(write(fd, trailer, trailer_size)));
+  ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, kEmptyEntriesZip, sizeof(kEmptyEntriesZip)));
+  ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, trailer, sizeof(trailer)));
 
   ZipArchiveHandle handle;
-  ASSERT_GT(0, OpenArchiveFd(fd, "EmptyEntriesTest", &handle));
+  ASSERT_GT(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle));
 }
 
 TEST(ziparchive, ExtractToFile) {
-  char kTempFilePattern[] = "zip_archive_input_XXXXXX";
-  int fd = make_temporary_file(kTempFilePattern);
-  ASSERT_NE(-1, fd);
+  TemporaryFile tmp_file;
+  ASSERT_NE(-1, tmp_file.fd);
   const uint8_t data[8] = { '1', '2', '3', '4', '5', '6', '7', '8' };
-  const ssize_t data_size = sizeof(data);
+  const size_t data_size = sizeof(data);
 
-  ASSERT_EQ(data_size, TEMP_FAILURE_RETRY(write(fd, data, data_size)));
+  ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, data, data_size));
 
   ZipArchiveHandle handle;
   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
@@ -499,28 +473,25 @@
   ZipString name;
   SetZipString(&name, kATxtName);
   ASSERT_EQ(0, FindEntry(handle, name, &entry));
-  ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, fd));
+  ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_file.fd));
 
 
   // Assert that the first 8 bytes of the file haven't been clobbered.
   uint8_t read_buffer[data_size];
-  ASSERT_EQ(0, lseek64(fd, 0, SEEK_SET));
-  ASSERT_EQ(data_size, TEMP_FAILURE_RETRY(read(fd, read_buffer, data_size)));
+  ASSERT_EQ(0, lseek64(tmp_file.fd, 0, SEEK_SET));
+  ASSERT_TRUE(android::base::ReadFully(tmp_file.fd, read_buffer, data_size));
   ASSERT_EQ(0, memcmp(read_buffer, data, data_size));
 
   // Assert that the remainder of the file contains the incompressed data.
   std::vector<uint8_t> uncompressed_data(entry.uncompressed_length);
-  ASSERT_EQ(static_cast<ssize_t>(entry.uncompressed_length),
-            TEMP_FAILURE_RETRY(
-                read(fd, &uncompressed_data[0], entry.uncompressed_length)));
+  ASSERT_TRUE(android::base::ReadFully(tmp_file.fd, uncompressed_data.data(),
+                                       entry.uncompressed_length));
   ASSERT_EQ(0, memcmp(&uncompressed_data[0], kATxtContents.data(),
                       kATxtContents.size()));
 
   // Assert that the total length of the file is sane
-  ASSERT_EQ(data_size + static_cast<ssize_t>(kATxtContents.size()),
-            lseek64(fd, 0, SEEK_END));
-
-  close(fd);
+  ASSERT_EQ(static_cast<ssize_t>(data_size + kATxtContents.size()),
+            lseek64(tmp_file.fd, 0, SEEK_END));
 }
 
 static void ZipArchiveStreamTest(
diff --git a/libziparchive/zip_writer_test.cc b/libziparchive/zip_writer_test.cc
index fe0846d..16a574d 100644
--- a/libziparchive/zip_writer_test.cc
+++ b/libziparchive/zip_writer_test.cc
@@ -154,12 +154,22 @@
   tm->tm_mday = (zip_time >> 16) & 0x1f;
 }
 
+static struct tm MakeTm() {
+  struct tm tm;
+  memset(&tm, 0, sizeof(struct tm));
+  tm.tm_year = 2001 - 1900;
+  tm.tm_mon = 1;
+  tm.tm_mday = 12;
+  tm.tm_hour = 18;
+  tm.tm_min = 30;
+  tm.tm_sec = 20;
+  return tm;
+}
+
 TEST_F(zipwriter, WriteUncompressedZipFileWithAlignedFlagAndTime) {
   ZipWriter writer(file_);
 
-  struct tm tm;
-  memset(&tm, 0, sizeof(struct tm));
-  ASSERT_TRUE(strptime("18:30:20 1/12/2001", "%H:%M:%S %d/%m/%Y", &tm) != nullptr);
+  struct tm tm = MakeTm();
   time_t time = mktime(&tm);
   ASSERT_EQ(0, writer.StartEntryWithTime("align.txt", ZipWriter::kAlign32, time));
   ASSERT_EQ(0, writer.WriteBytes("he", 2));
@@ -210,9 +220,7 @@
 TEST_F(zipwriter, WriteUncompressedZipFileWithAlignedValueAndTime) {
   ZipWriter writer(file_);
 
-  struct tm tm;
-  memset(&tm, 0, sizeof(struct tm));
-  ASSERT_TRUE(strptime("18:30:20 1/12/2001", "%H:%M:%S %d/%m/%Y", &tm) != nullptr);
+  struct tm tm = MakeTm();
   time_t time = mktime(&tm);
   ASSERT_EQ(0, writer.StartAlignedEntryWithTime("align.txt", 0, time, 4096));
   ASSERT_EQ(0, writer.WriteBytes("he", 2));
diff --git a/logcat/logpersist b/logcat/logpersist
index dab466d..8762ff1 100755
--- a/logcat/logpersist
+++ b/logcat/logpersist
@@ -1,8 +1,8 @@
 #! /system/bin/sh
 # logpersist cat start and stop handlers
 progname="${0##*/}"
-case `getprop ro.build.type` in
-userdebug|eng) ;;
+case `getprop ro.debuggable` in
+1) ;;
 *) echo "${progname} - Permission denied"
    exit 1
    ;;
diff --git a/logd/Android.mk b/logd/Android.mk
index feca8d5..203943c 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -42,6 +42,10 @@
 
 LOCAL_CFLAGS := -Werror $(event_flag)
 
+ifeq ($(TARGET_BUILD_VARIANT),user)
+LOCAL_CFLAGS += -DAUDITD_ENFORCE_INTEGRITY=true
+endif
+
 include $(BUILD_EXECUTABLE)
 
 include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 143fb04..fffc9ba 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -24,6 +24,7 @@
 #include <sys/uio.h>
 #include <syslog.h>
 
+#include <cutils/properties.h>
 #include <log/logger.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
@@ -32,6 +33,10 @@
 #include "LogAudit.h"
 #include "LogKlog.h"
 
+#ifndef AUDITD_ENFORCE_INTEGRITY
+#define AUDITD_ENFORCE_INTEGRITY false
+#endif
+
 #define KMSG_PRIORITY(PRI)                          \
     '<',                                            \
     '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) / 10, \
@@ -43,11 +48,10 @@
         logbuf(buf),
         reader(reader),
         fdDmesg(fdDmesg),
+        policyLoaded(false),
+        rebootToSafeMode(false),
         initialized(false) {
-    static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO),
-        'l', 'o', 'g', 'd', '.', 'a', 'u', 'd', 'i', 't', 'd', ':',
-        ' ', 's', 't', 'a', 'r', 't', '\n' };
-    write(fdDmesg, auditd_message, sizeof(auditd_message));
+    logToDmesg("start");
 }
 
 bool LogAudit::onDataAvailable(SocketClient *cli) {
@@ -73,6 +77,46 @@
     return true;
 }
 
+void LogAudit::logToDmesg(const std::string& str)
+{
+    static const char prefix[] = { KMSG_PRIORITY(LOG_INFO),
+        'l', 'o', 'g', 'd', '.', 'a', 'u', 'd', 'i', 't', 'd', ':',
+        ' ', '\0' };
+    std::string message = prefix + str + "\n";
+    write(fdDmesg, message.c_str(), message.length());
+}
+
+std::string LogAudit::getProperty(const std::string& name)
+{
+    char value[PROP_VALUE_MAX] = {0};
+    property_get(name.c_str(), value, "");
+    return value;
+}
+
+void LogAudit::enforceIntegrity() {
+    if (!AUDITD_ENFORCE_INTEGRITY) {
+        logToDmesg("integrity enforcement suppressed; not rebooting");
+    } else if (rebootToSafeMode) {
+        if (getProperty("persist.sys.safemode") == "1") {
+            logToDmesg("integrity enforcement suppressed; in safe mode");
+            return;
+        }
+
+        logToDmesg("enforcing integrity; rebooting to safe mode");
+        property_set("persist.sys.safemode", "1");
+
+        std::string buildDate = getProperty("ro.build.date.utc");
+        if (!buildDate.empty()) {
+            property_set("persist.sys.audit_safemode", buildDate.c_str());
+        }
+
+        property_set("sys.powerctl", "reboot");
+    } else {
+        logToDmesg("enforcing integrity: rebooting to recovery");
+        property_set("sys.powerctl", "reboot,recovery");
+    }
+}
+
 int LogAudit::logPrint(const char *fmt, ...) {
     if (fmt == NULL) {
         return -EINVAL;
@@ -94,7 +138,27 @@
         memmove(cp, cp + 1, strlen(cp + 1) + 1);
     }
 
-    bool info = strstr(str, " permissive=1") || strstr(str, " policy loaded ");
+    bool loaded = strstr(str, " policy loaded ");
+
+    if (loaded) {
+        if (policyLoaded) {
+            // SELinux policy changes are not allowed
+            enforceIntegrity();
+        } else {
+            logToDmesg("policy loaded");
+            policyLoaded = true;
+        }
+    }
+
+    bool permissive = strstr(str, " enforcing=0") ||
+                      strstr(str, " permissive=1");
+
+    if (permissive) {
+        // SELinux in permissive mode is not allowed
+        enforceIntegrity();
+    }
+
+    bool info = loaded || permissive;
     if ((fdDmesg >= 0) && initialized) {
         struct iovec iov[3];
         static const char log_info[] = { KMSG_PRIORITY(LOG_INFO) };
diff --git a/logd/LogAudit.h b/logd/LogAudit.h
index 8a82630..455ed58 100644
--- a/logd/LogAudit.h
+++ b/logd/LogAudit.h
@@ -24,12 +24,15 @@
     LogBuffer *logbuf;
     LogReader *reader;
     int fdDmesg;
+    bool policyLoaded;
+    bool rebootToSafeMode;
     bool initialized;
 
 public:
     LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg);
     int log(char *buf, size_t len);
     bool isMonotonic() { return logbuf->isMonotonic(); }
+    void allowSafeMode(bool allow = true) { rebootToSafeMode = allow; }
 
 protected:
     virtual bool onDataAvailable(SocketClient *cli);
@@ -38,6 +41,9 @@
     static int getLogSocket();
     int logPrint(const char *fmt, ...)
         __attribute__ ((__format__ (__printf__, 2, 3)));
+    void logToDmesg(const std::string& str);
+    std::string getProperty(const std::string& name);
+    void enforceIntegrity();
 };
 
 #endif
diff --git a/logd/LogUtils.h b/logd/LogUtils.h
index fd4800e..aa4b6e1 100644
--- a/logd/LogUtils.h
+++ b/logd/LogUtils.h
@@ -17,6 +17,7 @@
 #ifndef _LOGD_LOG_UTILS_H__
 #define _LOGD_LOG_UTILS_H__
 
+#include <sys/cdefs.h>
 #include <sys/types.h>
 
 #include <log/log.h>
@@ -29,6 +30,7 @@
 
 // Furnished in main.cpp. Caller must own and free returned value
 char *uidToName(uid_t uid);
+void prdebug(const char *fmt, ...) __printflike(1, 2);
 
 // Furnished in LogStatistics.cpp. Caller must own and free returned value
 char *pidToName(pid_t pid);
diff --git a/logd/README.property b/logd/README.property
index 22f86b9..4bc5541 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -1,14 +1,13 @@
 The properties that logd responds to are:
 
 name                       type default  description
-ro.logd.auditd             bool   true   Enable selinux audit daemon
 ro.logd.auditd.dmesg       bool   true   selinux audit messages duplicated and
                                          sent on to dmesg log
 persist.logd.security      bool   false  Enable security buffer.
 ro.device_owner            bool   false  Override persist.logd.security to false
 ro.logd.kernel             bool+ svelte+ Enable klogd daemon
 ro.logd.statistics         bool+ svelte+ Enable logcat -S statistics.
-ro.build.type              string        if user, logd.statistics &
+ro.debuggable              number        if not "1", logd.statistics &
                                          ro.logd.kernel default false.
 persist.logd.logpersistd   string        Enable logpersist daemon, "logcatd"
                                          turns on logcat -f in logd context
@@ -46,10 +45,10 @@
 
 NB:
 - bool+ - "true", "false" and comma separated list of "eng" (forced false if
-  ro.build.type is "user") or "svelte" (forced false if ro.config.low_ram is
+  ro.debuggable is not "1") or "svelte" (forced false if ro.config.low_ram is
   true).
 - svelte - see ro.config.low_ram for details.
-- svelte+ - see ro.config.low_ram and ro.build.type for details.
+- svelte+ - see ro.config.low_ram and ro.debuggable for details.
 - ro - <base property> temporary override, ro.<base property> platform default.
 - persist - <base property> override, persist.<base property> platform default.
 - build - VERBOSE for native, DEBUG for jvm isLoggable, or developer option.
diff --git a/logd/main.cpp b/logd/main.cpp
index ba56e57..f4d7464 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -202,8 +202,8 @@
         return false;
     }
     if (flag & BOOL_DEFAULT_FLAG_ENG) {
-        property_get("ro.build.type", property, "");
-        if (!strcmp(property, "user")) {
+        property_get("ro.debuggable", property, "");
+        if (strcmp(property, "1")) {
             return false;
         }
     }
@@ -211,10 +211,32 @@
     return (flag & BOOL_DEFAULT_FLAG_TRUE_FALSE) != BOOL_DEFAULT_FALSE;
 }
 
-// Remove the static, and use this variable
-// globally for debugging if necessary. eg:
-//   write(fdDmesg, "I am here\n", 10);
 static int fdDmesg = -1;
+void inline android::prdebug(const char *fmt, ...) {
+    if (fdDmesg < 0) {
+        return;
+    }
+
+    static const char message[] = {
+        KMSG_PRIORITY(LOG_DEBUG), 'l', 'o', 'g', 'd', ':', ' '
+    };
+    char buffer[256];
+    memcpy(buffer, message, sizeof(message));
+
+    va_list ap;
+    va_start(ap, fmt);
+    int n = vsnprintf(buffer + sizeof(message),
+                      sizeof(buffer) - sizeof(message), fmt, ap);
+    va_end(ap);
+    if (n > 0) {
+        buffer[sizeof(buffer) - 1] = '\0';
+        if (!strchr(buffer, '\n')) {
+            buffer[sizeof(buffer) - 2] = '\0';
+            strlcat(buffer, "\n", sizeof(buffer));
+        }
+        write(fdDmesg, buffer, strlen(buffer));
+    }
+}
 
 static sem_t uidName;
 static uid_t uid;
@@ -223,6 +245,7 @@
 static sem_t reinit;
 static bool reinit_running = false;
 static LogBuffer *logBuf = NULL;
+static LogAudit *logAudit = NULL;
 
 static bool package_list_parser_cb(pkg_info *info, void * /* userdata */) {
 
@@ -270,6 +293,10 @@
             logBuf->init();
             logBuf->initPrune(NULL);
         }
+
+        if (logAudit) {
+            logAudit->allowSafeMode();
+        }
     }
 
     return NULL;
@@ -490,25 +517,19 @@
     // initiated log messages. New log entries are added to LogBuffer
     // and LogReader is notified to send updates to connected clients.
 
-    bool auditd = property_get_bool("logd.auditd",
-                                    BOOL_DEFAULT_TRUE |
-                                    BOOL_DEFAULT_FLAG_PERSIST);
-    LogAudit *al = NULL;
-    if (auditd) {
-        al = new LogAudit(logBuf, reader,
-                          property_get_bool("logd.auditd.dmesg",
-                                            BOOL_DEFAULT_TRUE |
-                                            BOOL_DEFAULT_FLAG_PERSIST)
-                              ? fdDmesg
-                              : -1);
-    }
+    logAudit = new LogAudit(logBuf, reader,
+                            property_get_bool("logd.auditd.dmesg",
+                                              BOOL_DEFAULT_TRUE |
+                                              BOOL_DEFAULT_FLAG_PERSIST)
+                                ? fdDmesg
+                                : -1);
 
     LogKlog *kl = NULL;
     if (klogd) {
-        kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, al != NULL);
+        kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, logAudit != NULL);
     }
 
-    readDmesg(al, kl);
+    readDmesg(logAudit, kl);
 
     // failure is an option ... messages are in dmesg (required by standard)
 
@@ -516,8 +537,9 @@
         delete kl;
     }
 
-    if (al && al->startListener()) {
-        delete al;
+    if (logAudit && logAudit->startListener()) {
+        delete logAudit;
+        logAudit = NULL;
     }
 
     TEMP_FAILURE_RETRY(pause());
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index 28d6de7..ccbe0bf 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -408,7 +408,7 @@
         if (poll_fds[0].revents & POLLHUP) {
             int ret;
 
-            ret = waitpid(pid, &status, WNOHANG);
+            ret = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
             if (ret < 0) {
                 rc = errno;
                 ALOG(LOG_ERROR, "logwrap", "waitpid failed with %s\n", strerror(errno));
diff --git a/metricsd/.clang-format b/metricsd/.clang-format
deleted file mode 100644
index c98efc2..0000000
--- a/metricsd/.clang-format
+++ /dev/null
@@ -1,10 +0,0 @@
-BasedOnStyle: Google
-AllowShortFunctionsOnASingleLine: Inline
-AllowShortIfStatementsOnASingleLine: false
-AllowShortLoopsOnASingleLine: false
-BinPackArguments: false
-BinPackParameters: false
-CommentPragmas: NOLINT:.*
-DerivePointerAlignment: false
-PointerAlignment: Left
-TabWidth: 2
diff --git a/metricsd/.clang-format b/metricsd/.clang-format
new file mode 120000
index 0000000..f9066d4
--- /dev/null
+++ b/metricsd/.clang-format
@@ -0,0 +1 @@
+../../../build/tools/brillo-clang-format
\ No newline at end of file
diff --git a/metricsd/uploader/upload_service_test.cc b/metricsd/uploader/upload_service_test.cc
index 70112f4..0f77fe4 100644
--- a/metricsd/uploader/upload_service_test.cc
+++ b/metricsd/uploader/upload_service_test.cc
@@ -304,6 +304,8 @@
   upload_service_->PersistToDisk();
   EXPECT_EQ(
       1, upload_service_->current_log_->uma_proto()->histogram_event().size());
+  // Destroy the old service before creating a new one.
+  upload_service_.reset();
   upload_service_.reset(new UploadService(
       "", base::TimeDelta(), base::TimeDelta(), private_dir_, shared_dir_));
   upload_service_->InitForTest(nullptr);
@@ -325,6 +327,8 @@
   // Write a bogus saved log.
   EXPECT_EQ(5, base::WriteFile(upload_service_->saved_log_path_, "hello", 5));
 
+  // Destroy the old service before creating a new one.
+  upload_service_.reset();
   upload_service_.reset(new UploadService(
       "", base::TimeDelta(), base::TimeDelta(), private_dir_, shared_dir_));
 
diff --git a/sdcard/Android.mk b/sdcard/Android.mk
index c5f3d1d..2d04a7f 100644
--- a/sdcard/Android.mk
+++ b/sdcard/Android.mk
@@ -5,6 +5,6 @@
 LOCAL_SRC_FILES := sdcard.c
 LOCAL_MODULE := sdcard
 LOCAL_CFLAGS := -Wall -Wno-unused-parameter -Werror
-LOCAL_SHARED_LIBRARIES := libcutils libpackagelistparser
+LOCAL_SHARED_LIBRARIES := liblog libcutils libpackagelistparser
 
 include $(BUILD_EXECUTABLE)
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 9ade759..fc2898e 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -55,6 +55,7 @@
 LOCAL_CONLYFLAGS += -std=gnu99
 
 LOCAL_SHARED_LIBRARIES := \
+    liblog \
     libcutils \
     libselinux \