Merge "libcutils: abort for invalid fd"
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 35e5945..58ccd0a 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -509,14 +509,60 @@
     return true;
 }
 
-// Read from a pipe (that we take ownership of) and write what is returned to
-// GetStdHandle(nStdHandle). Return on error or when the pipe is closed.
+// Read from a pipe (that we take ownership of) and write the result to stdout/stderr. Return on
+// error or when the pipe is closed. Internally makes inheritable handles, so this should not be
+// called if subprocesses may be started concurrently.
 static unsigned _redirect_pipe_thread(HANDLE h, DWORD nStdHandle) {
     // Take ownership of the HANDLE and close when we're done.
     unique_handle   read_pipe(h);
-    const HANDLE    write_handle = GetStdHandle(nStdHandle);
-    const char*     output_name = nStdHandle == STD_OUTPUT_HANDLE ?
-                                      "stdout" : "stderr";
+    const char*     output_name = nStdHandle == STD_OUTPUT_HANDLE ? "stdout" : "stderr";
+    const int       original_fd = fileno(nStdHandle == STD_OUTPUT_HANDLE ? stdout : stderr);
+    std::unique_ptr<FILE, decltype(&fclose)> stream(nullptr, fclose);
+
+    if (original_fd == -1) {
+        fprintf(stderr, "Failed to get file descriptor for %s: %s\n", output_name, strerror(errno));
+        return EXIT_FAILURE;
+    }
+
+    // If fileno() is -2, stdout/stderr is not associated with an output stream, so we should read,
+    // but don't write. Otherwise, make a FILE* identical to stdout/stderr except that it is in
+    // binary mode with no CR/LR translation since we're reading raw.
+    if (original_fd >= 0) {
+        // This internally makes a duplicate file handle that is inheritable, so callers should not
+        // call this function if subprocesses may be started concurrently.
+        const int fd = dup(original_fd);
+        if (fd == -1) {
+            fprintf(stderr, "Failed to duplicate file descriptor for %s: %s\n", output_name,
+                    strerror(errno));
+            return EXIT_FAILURE;
+        }
+
+        // Note that although we call fdopen() below with a binary flag, it may not adhere to that
+        // flag, so we have to set the mode manually.
+        if (_setmode(fd, _O_BINARY) == -1) {
+            fprintf(stderr, "Failed to set binary mode for duplicate of %s: %s\n", output_name,
+                    strerror(errno));
+            unix_close(fd);
+            return EXIT_FAILURE;
+        }
+
+        stream.reset(fdopen(fd, "wb"));
+        if (stream.get() == nullptr) {
+            fprintf(stderr, "Failed to open duplicate stream for %s: %s\n", output_name,
+                    strerror(errno));
+            unix_close(fd);
+            return EXIT_FAILURE;
+        }
+
+        // Unbuffer the stream because it will be buffered by default and we want subprocess output
+        // to be shown immediately.
+        if (setvbuf(stream.get(), NULL, _IONBF, 0) == -1) {
+            fprintf(stderr, "Failed to unbuffer %s: %s\n", output_name, strerror(errno));
+            return EXIT_FAILURE;
+        }
+
+        // fd will be closed when stream is closed.
+    }
 
     while (true) {
         char    buf[64 * 1024];
@@ -534,20 +580,13 @@
             }
         }
 
-        // Don't try to write if our stdout/stderr was not setup by the
-        // parent process.
-        if (write_handle != NULL && write_handle != INVALID_HANDLE_VALUE) {
-            DWORD   bytes_written = 0;
-            if (!WriteFile(write_handle, buf, bytes_read, &bytes_written,
-                           NULL)) {
-                fprintf(stderr, "Failed to write to %s: %s\n", output_name,
-                        android::base::SystemErrorCodeToString(GetLastError()).c_str());
-                return EXIT_FAILURE;
-            }
-
+        // Don't try to write if our stdout/stderr was not setup by the parent process.
+        if (stream) {
+            // fwrite() actually calls adb_fwrite() which can write UTF-8 to the console.
+            const size_t bytes_written = fwrite(buf, 1, bytes_read, stream.get());
             if (bytes_written != bytes_read) {
-                fprintf(stderr, "Only wrote %lu of %lu bytes to %s\n",
-                        bytes_written, bytes_read, output_name);
+                fprintf(stderr, "Only wrote %zu of %lu bytes to %s\n", bytes_written, bytes_read,
+                        output_name);
                 return EXIT_FAILURE;
             }
         }
@@ -596,7 +635,10 @@
         return -1;
     }
 
-    // create pipes with non-inheritable read handle, inheritable write handle
+    // Create pipes with non-inheritable read handle, inheritable write handle. We need to connect
+    // the subprocess to pipes instead of just letting the subprocess inherit our existing
+    // stdout/stderr handles because a DETACHED_PROCESS cannot write to a console that it is not
+    // attached to.
     unique_handle   ack_read, ack_write;
     if (!_create_anonymous_pipe(&ack_read, &ack_write, &sa)) {
         return -1;
@@ -704,8 +746,9 @@
     stdout_write.reset();
     stderr_write.reset();
 
-    // Start threads to read from subprocess stdout/stderr and write to ours
-    // to make subprocess errors easier to diagnose.
+    // Start threads to read from subprocess stdout/stderr and write to ours to make subprocess
+    // errors easier to diagnose. Note that the threads internally create inheritable handles, but
+    // that is ok because we've already spawned the subprocess.
 
     // In the past, reading from a pipe before the child process's C Runtime
     // started up and called GetFileType() caused a hang: http://blogs.msdn.com/b/oldnewthing/archive/2011/12/02/10243553.aspx#10244216
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 0fa5917..51fc143 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -753,8 +753,11 @@
         if (dst_isdir) {
             // If we're copying a local file to a remote directory,
             // we really want to copy to remote_dir + "/" + local_filename.
-            path_holder = android::base::StringPrintf(
-                "%s/%s", dst_path, adb_basename(src_path).c_str());
+            path_holder = dst_path;
+            if (path_holder.back() != '/') {
+                path_holder.push_back('/');
+            }
+            path_holder += adb_basename(src_path);
             dst_path = path_holder.c_str();
         }
         sc.SetExpectedTotalBytes(st.st_size);
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index ef0418e..29c6629 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -130,6 +130,9 @@
     return WriteFdExactly(s, &msg.dent, sizeof(msg.dent));
 }
 
+// Make sure that SendFail from adb_io.cpp isn't accidentally used in this file.
+#pragma GCC poison SendFail
+
 static bool SendSyncFail(int fd, const std::string& reason) {
     D("sync: failure: %s", reason.c_str());
 
@@ -265,7 +268,7 @@
         msg.status.msglen = 0;
         if (!WriteFdExactly(s, &msg.status, sizeof(msg.status))) return false;
     } else {
-        SendFail(s, "invalid data message: expected ID_DONE");
+        SendSyncFail(s, "invalid data message: expected ID_DONE");
         return false;
     }
 
@@ -277,7 +280,7 @@
     // 'spec' is of the form "/some/path,0755". Break it up.
     size_t comma = spec.find_last_of(',');
     if (comma == std::string::npos) {
-        SendFail(s, "missing , in ID_SEND");
+        SendSyncFail(s, "missing , in ID_SEND");
         return false;
     }
 
@@ -286,7 +289,7 @@
     errno = 0;
     mode_t mode = strtoul(spec.substr(comma + 1).c_str(), nullptr, 0);
     if (errno != 0) {
-        SendFail(s, "bad mode");
+        SendSyncFail(s, "bad mode");
         return false;
     }
 
diff --git a/adb/shell_service.cpp b/adb/shell_service.cpp
index 491bb68..d080e09 100644
--- a/adb/shell_service.cpp
+++ b/adb/shell_service.cpp
@@ -192,7 +192,7 @@
 
     // Sets up FDs, forks a subprocess, starts the subprocess manager thread,
     // and exec's the child. Returns false on failure.
-    bool ForkAndExec();
+    bool ForkAndExec(std::string* _Nonnull error);
 
   private:
     // Opens the file at |pts_name|.
@@ -250,7 +250,7 @@
     WaitForExit();
 }
 
-bool Subprocess::ForkAndExec() {
+bool Subprocess::ForkAndExec(std::string* error) {
     ScopedFd child_stdinout_sfd, child_stderr_sfd;
     ScopedFd parent_error_sfd, child_error_sfd;
     char pts_name[PATH_MAX];
@@ -265,7 +265,9 @@
     // use threads, logging directly from the child might deadlock due to locks held in another
     // thread during the fork.
     if (!CreateSocketpair(&parent_error_sfd, &child_error_sfd)) {
-        LOG(ERROR) << "failed to create pipe for subprocess error reporting";
+        *error = android::base::StringPrintf(
+            "failed to create pipe for subprocess error reporting: %s", strerror(errno));
+        return false;
     }
 
     // Construct the environment for the child before we fork.
@@ -316,18 +318,22 @@
         stdinout_sfd_.Reset(fd);
     } else {
         if (!CreateSocketpair(&stdinout_sfd_, &child_stdinout_sfd)) {
+            *error = android::base::StringPrintf("failed to create socketpair for stdin/out: %s",
+                                                 strerror(errno));
             return false;
         }
         // Raw subprocess + shell protocol allows for splitting stderr.
         if (protocol_ == SubprocessProtocol::kShell &&
                 !CreateSocketpair(&stderr_sfd_, &child_stderr_sfd)) {
+            *error = android::base::StringPrintf("failed to create socketpair for stderr: %s",
+                                                 strerror(errno));
             return false;
         }
         pid_ = fork();
     }
 
     if (pid_ == -1) {
-        PLOG(ERROR) << "fork failed";
+        *error = android::base::StringPrintf("fork failed: %s", strerror(errno));
         return false;
     }
 
@@ -357,7 +363,8 @@
         } else {
             execle(_PATH_BSHELL, _PATH_BSHELL, "-c", command_.c_str(), nullptr, cenv.data());
         }
-        WriteFdExactly(child_error_sfd.fd(), "exec '" _PATH_BSHELL "' failed");
+        WriteFdExactly(child_error_sfd.fd(), "exec '" _PATH_BSHELL "' failed: ");
+        WriteFdExactly(child_error_sfd.fd(), strerror(errno));
         child_error_sfd.Reset();
         _Exit(1);
     }
@@ -370,7 +377,7 @@
     child_error_sfd.Reset();
     std::string error_message = ReadAll(parent_error_sfd.fd());
     if (!error_message.empty()) {
-        LOG(ERROR) << error_message;
+        *error = error_message;
         return false;
     }
 
@@ -382,6 +389,9 @@
     } else {
         // Shell protocol: create another socketpair to intercept data.
         if (!CreateSocketpair(&protocol_sfd_, &local_socket_sfd_)) {
+            *error = android::base::StringPrintf(
+                "failed to create socketpair to intercept data: %s", strerror(errno));
+            kill(pid_, SIGKILL);
             return false;
         }
         D("protocol FD = %d", protocol_sfd_.fd());
@@ -389,7 +399,8 @@
         input_.reset(new ShellProtocol(protocol_sfd_.fd()));
         output_.reset(new ShellProtocol(protocol_sfd_.fd()));
         if (!input_ || !output_) {
-            LOG(ERROR) << "failed to allocate shell protocol objects";
+            *error = "failed to allocate shell protocol objects";
+            kill(pid_, SIGKILL);
             return false;
         }
 
@@ -400,7 +411,9 @@
         for (int fd : {stdinout_sfd_.fd(), stderr_sfd_.fd()}) {
             if (fd >= 0) {
                 if (!set_file_block_mode(fd, false)) {
-                    LOG(ERROR) << "failed to set non-blocking mode for fd " << fd;
+                    *error = android::base::StringPrintf(
+                        "failed to set non-blocking mode for fd %d", fd);
+                    kill(pid_, SIGKILL);
                     return false;
                 }
             }
@@ -408,7 +421,9 @@
     }
 
     if (!adb_thread_create(ThreadHandler, this)) {
-        PLOG(ERROR) << "failed to create subprocess thread";
+        *error =
+            android::base::StringPrintf("failed to create subprocess thread: %s", strerror(errno));
+        kill(pid_, SIGKILL);
         return false;
     }
 
@@ -710,6 +725,37 @@
 
 }  // namespace
 
+// Create a pipe containing the error.
+static int ReportError(SubprocessProtocol protocol, const std::string& message) {
+    int pipefd[2];
+    if (pipe(pipefd) != 0) {
+        LOG(ERROR) << "failed to create pipe to report error";
+        return -1;
+    }
+
+    std::string buf = android::base::StringPrintf("error: %s\n", message.c_str());
+    if (protocol == SubprocessProtocol::kShell) {
+        ShellProtocol::Id id = ShellProtocol::kIdStderr;
+        uint32_t length = buf.length();
+        WriteFdExactly(pipefd[1], &id, sizeof(id));
+        WriteFdExactly(pipefd[1], &length, sizeof(length));
+    }
+
+    WriteFdExactly(pipefd[1], buf.data(), buf.length());
+
+    if (protocol == SubprocessProtocol::kShell) {
+        ShellProtocol::Id id = ShellProtocol::kIdExit;
+        uint32_t length = 1;
+        char exit_code = 126;
+        WriteFdExactly(pipefd[1], &id, sizeof(id));
+        WriteFdExactly(pipefd[1], &length, sizeof(length));
+        WriteFdExactly(pipefd[1], &exit_code, sizeof(exit_code));
+    }
+
+    adb_close(pipefd[1]);
+    return pipefd[0];
+}
+
 int StartSubprocess(const char* name, const char* terminal_type,
                     SubprocessType type, SubprocessProtocol protocol) {
     D("starting %s subprocess (protocol=%s, TERM=%s): '%s'",
@@ -720,13 +766,14 @@
     Subprocess* subprocess = new Subprocess(name, terminal_type, type, protocol);
     if (!subprocess) {
         LOG(ERROR) << "failed to allocate new subprocess";
-        return -1;
+        return ReportError(protocol, "failed to allocate new subprocess");
     }
 
-    if (!subprocess->ForkAndExec()) {
-        LOG(ERROR) << "failed to start subprocess";
+    std::string error;
+    if (!subprocess->ForkAndExec(&error)) {
+        LOG(ERROR) << "failed to start subprocess: " << error;
         delete subprocess;
-        return -1;
+        return ReportError(protocol, error);
     }
 
     D("subprocess creation successful: local_socket_fd=%d, pid=%d",
diff --git a/crash_reporter/Android.mk b/crash_reporter/Android.mk
index fa564b2..ce9dc73 100644
--- a/crash_reporter/Android.mk
+++ b/crash_reporter/Android.mk
@@ -136,7 +136,7 @@
 LOCAL_MODULE := crash_reporter_tests
 LOCAL_CPP_EXTENSION := $(crash_reporter_cpp_extension)
 ifdef BRILLO
-LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE_TAGS := eng
 endif
 LOCAL_SHARED_LIBRARIES := libchrome \
     libbrillo \
diff --git a/crash_reporter/crash_reporter.cc b/crash_reporter/crash_reporter.cc
index b69492a..16e70d8 100644
--- a/crash_reporter/crash_reporter.cc
+++ b/crash_reporter/crash_reporter.cc
@@ -43,7 +43,8 @@
 #endif
 
 static const char kCrashCounterHistogram[] = "Logging.CrashCounter";
-static const char kKernelCrashDetected[] = "/var/run/kernel-crash-detected";
+static const char kKernelCrashDetected[] =
+    "/data/misc/crash_reporter/run/kernel-crash-detected";
 static const char kUncleanShutdownDetected[] =
     "/var/run/unclean-shutdown-detected";
 static const char kGUIDFileName[] = "/data/misc/crash_reporter/guid";
diff --git a/crash_reporter/crash_reporter.rc b/crash_reporter/crash_reporter.rc
index 57c1d40..e6d1ec5 100644
--- a/crash_reporter/crash_reporter.rc
+++ b/crash_reporter/crash_reporter.rc
@@ -13,6 +13,10 @@
     # Remove any previous orphaned locks.
     rmdir /data/misc/crash_reporter/lock/crash_sender
 
+    # Remove any previous run files.
+    rm /data/misc/crash_reporter/run/kernel-crash-detected
+    rmdir /data/misc/crash_reporter/run
+
     # Create crash directories.
     # These directories are group-writable by root so that crash_reporter can
     # still access them when it switches users.
diff --git a/crash_reporter/kernel_collector.cc b/crash_reporter/kernel_collector.cc
index cb3a315..68f2d9e 100644
--- a/crash_reporter/kernel_collector.cc
+++ b/crash_reporter/kernel_collector.cc
@@ -30,8 +30,8 @@
 namespace {
 
 const char kDefaultKernelStackSignature[] = "kernel-UnspecifiedStackSignature";
-const char kDumpParentPath[] = "/dev";
-const char kDumpPath[] = "/dev/pstore";
+const char kDumpParentPath[] = "/sys/fs";
+const char kDumpPath[] = "/sys/fs/pstore";
 const char kDumpFormat[] = "dmesg-ramoops-%zu";
 const char kKernelExecName[] = "kernel";
 // Maximum number of records to examine in the kDumpPath.
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index dda6677..7cf2ffc 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -134,8 +134,15 @@
       switch (code) {
         case SEGV_MAPERR: return "SEGV_MAPERR";
         case SEGV_ACCERR: return "SEGV_ACCERR";
+#if defined(SEGV_BNDERR)
+        case SEGV_BNDERR: return "SEGV_BNDERR";
+#endif
       }
+#if defined(SEGV_BNDERR)
+      static_assert(NSIGSEGV == SEGV_BNDERR, "missing SEGV_* si_code");
+#else
       static_assert(NSIGSEGV == SEGV_ACCERR, "missing SEGV_* si_code");
+#endif
       break;
     case SIGTRAP:
       switch (code) {
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 11d769b..e0f7c73 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -31,6 +31,7 @@
     fs.cpp\
     protocol.cpp \
     socket.cpp \
+    tcp.cpp \
     util.cpp \
 
 LOCAL_MODULE := fastboot
@@ -111,6 +112,8 @@
     socket.cpp \
     socket_mock.cpp \
     socket_test.cpp \
+    tcp.cpp \
+    tcp_test.cpp \
 
 LOCAL_STATIC_LIBRARIES := libbase libcutils
 
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 4573da0..b219564 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -42,22 +42,22 @@
 #include <sys/time.h>
 #include <sys/types.h>
 #include <unistd.h>
+
 #include <functional>
 #include <utility>
 #include <vector>
 
 #include <android-base/parseint.h>
+#include <android-base/parsenetaddress.h>
 #include <android-base/strings.h>
 #include <sparse/sparse.h>
 #include <ziparchive/zip_archive.h>
 
-#include <android-base/strings.h>
-#include <android-base/parseint.h>
-
 #include "bootimg_utils.h"
 #include "diagnose_usb.h"
 #include "fastboot.h"
 #include "fs.h"
+#include "tcp.h"
 #include "transport.h"
 #include "usb.h"
 
@@ -69,9 +69,9 @@
 
 char cur_product[FB_RESPONSE_SZ + 1];
 
-static const char *serial = 0;
-static const char *product = 0;
-static const char *cmdline = 0;
+static const char* serial = nullptr;
+static const char* product = nullptr;
+static const char* cmdline = nullptr;
 static unsigned short vendor_id = 0;
 static int long_listing = 0;
 static int64_t sparse_limit = -1;
@@ -227,17 +227,51 @@
     return -1;
 }
 
+// Opens a new Transport connected to a device. If |serial| is non-null it will be used to identify
+// a specific device, otherwise the first USB device found will be used.
+//
+// If |serial| is non-null but invalid, this prints an error message to stderr and returns nullptr.
+// Otherwise it blocks until the target is available.
+//
+// The returned Transport is a singleton, so multiple calls to this function will return the same
+// object, and the caller should not attempt to delete the returned Transport.
 static Transport* open_device() {
     static Transport* transport = nullptr;
-    int announce = 1;
+    bool announce = true;
 
-    if (transport) return transport;
+    if (transport != nullptr) {
+        return transport;
+    }
 
-    for (;;) {
-        transport = usb_open(match_fastboot);
-        if (transport) return transport;
+    std::string host;
+    int port = tcp::kDefaultPort;
+    if (serial != nullptr && android::base::StartsWith(serial, "tcp:")) {
+        std::string error;
+        const char* address = serial + strlen("tcp:");
+
+        if (!android::base::ParseNetAddress(address, &host, &port, nullptr, &error)) {
+            fprintf(stderr, "error: Invalid network address '%s': %s\n", address, error.c_str());
+            return nullptr;
+        }
+    }
+
+    while (true) {
+        if (!host.empty()) {
+            std::string error;
+            transport = tcp::Connect(host, port, &error).release();
+            if (transport == nullptr && announce) {
+                fprintf(stderr, "error: %s\n", error.c_str());
+            }
+        } else {
+            transport = usb_open(match_fastboot);
+        }
+
+        if (transport != nullptr) {
+            return transport;
+        }
+
         if (announce) {
-            announce = 0;
+            announce = false;
             fprintf(stderr, "< waiting for %s >\n", serial ? serial : "any device");
         }
         usleep(1000);
@@ -299,8 +333,10 @@
             "                                           if supported by partition type).\n"
             "  -u                                       Do not erase partition before\n"
             "                                           formatting.\n"
-            "  -s <specific device>                     Specify device serial number\n"
-            "                                           or path to device port.\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"
             "  -p <product>                             Specify product name.\n"
             "  -c <cmdline>                             Override kernel commandline.\n"
             "  -i <vendor id>                           Specify a custom USB vendor id.\n"
@@ -1263,6 +1299,10 @@
     }
 
     Transport* transport = open_device();
+    if (transport == nullptr) {
+        return 1;
+    }
+
     if (slot_override != "")
         slot_override = verify_slot(transport, slot_override.c_str());
     if (next_active != "")
diff --git a/fastboot/fastboot_protocol.txt b/fastboot/fastboot_protocol.txt
index bb73d8a..4aa48b1 100644
--- a/fastboot/fastboot_protocol.txt
+++ b/fastboot/fastboot_protocol.txt
@@ -1,21 +1,26 @@
-
 FastBoot  Version  0.4
 ----------------------
 
 The fastboot protocol is a mechanism for communicating with bootloaders
-over USB.  It is designed to be very straightforward to implement, to
-allow it to be used across a wide range of devices and from hosts running
+over USB or ethernet.  It is designed to be very straightforward to implement,
+to allow it to be used across a wide range of devices and from hosts running
 Linux, Windows, or OSX.
 
 
 Basic Requirements
 ------------------
 
-* Two bulk endpoints (in, out) are required
-* Max packet size must be 64 bytes for full-speed, 512 bytes for
-  high-speed and 1024 bytes for Super Speed USB.
-* The protocol is entirely host-driven and synchronous (unlike the
-  multi-channel, bi-directional, asynchronous ADB protocol)
+* USB
+  * Two bulk endpoints (in, out) are required
+  * Max packet size must be 64 bytes for full-speed, 512 bytes for
+    high-speed and 1024 bytes for Super Speed USB.
+  * The protocol is entirely host-driven and synchronous (unlike the
+    multi-channel, bi-directional, asynchronous ADB protocol)
+
+* TCP
+  * Device must be reachable via IP.
+  * Device will act as the TCP server, fastboot will be the client.
+  * Fastboot data is wrapped in a simple protocol; see below for details.
 
 
 Transport and Framing
@@ -152,7 +157,7 @@
 The various currently defined names are:
 
   version             Version of FastBoot protocol supported.
-                      It should be "0.3" for this document.
+                      It should be "0.4" for this document.
 
   version-bootloader  Version string for the Bootloader.
 
@@ -171,3 +176,44 @@
 characters.
 
 
+TCP Protocol v1
+---------------
+
+The TCP protocol is designed to be a simple way to use the fastboot protocol
+over ethernet if USB is not available.
+
+The device will open a TCP server on port 5554 and wait for a fastboot client
+to connect.
+
+-- Handshake --
+Upon connecting, both sides will send a 4-byte handshake message to ensure they
+are speaking the same protocol. This consists of the ASCII characters "FB"
+followed by a 2-digit base-10 ASCII version number. For example, the version 1
+handshake message will be [FB01].
+
+If either side detects a malformed handshake, it should disconnect.
+
+The protocol version to use must be the minimum of the versions sent by each
+side; if either side cannot speak this protocol version, it should disconnect.
+
+-- Fastboot Data --
+Once the handshake is complete, fastboot data will be sent as follows:
+
+  [data_size][data]
+
+Where data_size is an unsigned 8-byte big-endian binary value, and data is the
+fastboot packet. The 8-byte length is intended to provide future-proofing even
+though currently fastboot packets have a 4-byte maximum length.
+
+-- Example --
+In this example the fastboot host queries the device for two variables,
+"version" and "none".
+
+Host    <connect to the device on port 5555>
+Host    FB01
+Device  FB01
+Host    [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x0E]getvar:version
+Device  [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x07]OKAY0.4
+Host    [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x0B]getvar:none
+Device  [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x04]OKAY
+Host    <disconnect>
diff --git a/fastboot/tcp.cpp b/fastboot/tcp.cpp
new file mode 100644
index 0000000..da2880a
--- /dev/null
+++ b/fastboot/tcp.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "tcp.h"
+
+#include <android-base/stringprintf.h>
+
+namespace tcp {
+
+static constexpr int kProtocolVersion = 1;
+static constexpr size_t kHandshakeLength = 4;
+static constexpr int kHandshakeTimeoutMs = 2000;
+
+// Extract the big-endian 8-byte message length into a 64-bit number.
+static uint64_t ExtractMessageLength(const void* buffer) {
+    uint64_t ret = 0;
+    for (int i = 0; i < 8; ++i) {
+        ret |= uint64_t{reinterpret_cast<const uint8_t*>(buffer)[i]} << (56 - i * 8);
+    }
+    return ret;
+}
+
+// Encode the 64-bit number into a big-endian 8-byte message length.
+static void EncodeMessageLength(uint64_t length, void* buffer) {
+    for (int i = 0; i < 8; ++i) {
+        reinterpret_cast<uint8_t*>(buffer)[i] = length >> (56 - i * 8);
+    }
+}
+
+class TcpTransport : public Transport {
+  public:
+    // Factory function so we can return nullptr if initialization fails.
+    static std::unique_ptr<TcpTransport> NewTransport(std::unique_ptr<Socket> socket,
+                                                      std::string* error);
+
+    ~TcpTransport() 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:
+    TcpTransport(std::unique_ptr<Socket> sock) : socket_(std::move(sock)) {}
+
+    // Connects to the device and performs the initial handshake. Returns false and fills |error|
+    // on failure.
+    bool InitializeProtocol(std::string* error);
+
+    std::unique_ptr<Socket> socket_;
+    uint64_t message_bytes_left_ = 0;
+
+    DISALLOW_COPY_AND_ASSIGN(TcpTransport);
+};
+
+std::unique_ptr<TcpTransport> TcpTransport::NewTransport(std::unique_ptr<Socket> socket,
+                                                         std::string* error) {
+    std::unique_ptr<TcpTransport> transport(new TcpTransport(std::move(socket)));
+
+    if (!transport->InitializeProtocol(error)) {
+        return nullptr;
+    }
+
+    return transport;
+}
+
+// These error strings are checked in tcp_test.cpp and should be kept in sync.
+bool TcpTransport::InitializeProtocol(std::string* error) {
+    std::string handshake_message(android::base::StringPrintf("FB%02d", kProtocolVersion));
+
+    if (!socket_->Send(handshake_message.c_str(), kHandshakeLength)) {
+        *error = android::base::StringPrintf("Failed to send initialization message (%s)",
+                                             Socket::GetErrorMessage().c_str());
+        return false;
+    }
+
+    char buffer[kHandshakeLength];
+    if (socket_->ReceiveAll(buffer, kHandshakeLength, kHandshakeTimeoutMs) != kHandshakeLength) {
+        *error = android::base::StringPrintf(
+                "No initialization message received (%s). Target may not support TCP fastboot",
+                Socket::GetErrorMessage().c_str());
+        return false;
+    }
+
+    if (memcmp(buffer, "FB", 2) != 0) {
+        *error = "Unrecognized initialization message. Target may not support TCP fastboot";
+        return false;
+    }
+
+    if (memcmp(buffer + 2, "01", 2) != 0) {
+        *error = android::base::StringPrintf("Unknown TCP protocol version %s (host version %02d)",
+                                             std::string(buffer + 2, 2).c_str(), kProtocolVersion);
+        return false;
+    }
+
+    error->clear();
+    return true;
+}
+
+ssize_t TcpTransport::Read(void* data, size_t length) {
+    if (socket_ == nullptr) {
+        return -1;
+    }
+
+    // Unless we're mid-message, read the next 8-byte message length.
+    if (message_bytes_left_ == 0) {
+        char buffer[8];
+        if (socket_->ReceiveAll(buffer, 8, 0) != 8) {
+            Close();
+            return -1;
+        }
+        message_bytes_left_ = ExtractMessageLength(buffer);
+    }
+
+    // Now read the message (up to |length| bytes).
+    if (length > message_bytes_left_) {
+        length = message_bytes_left_;
+    }
+    ssize_t bytes_read = socket_->ReceiveAll(data, length, 0);
+    if (bytes_read == -1) {
+        Close();
+    } else {
+        message_bytes_left_ -= bytes_read;
+    }
+    return bytes_read;
+}
+
+ssize_t TcpTransport::Write(const void* data, size_t length) {
+    if (socket_ == nullptr) {
+        return -1;
+    }
+
+    // Use multi-buffer writes for better performance.
+    char header[8];
+    EncodeMessageLength(length, header);
+    if (!socket_->Send(std::vector<cutils_socket_buffer_t>{{header, 8}, {data, length}})) {
+        Close();
+        return -1;
+    }
+
+    return length;
+}
+
+int TcpTransport::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::kTcp, 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 TcpTransport::NewTransport(std::move(sock), error);
+}
+
+}  // namespace internal
+
+}  // namespace tcp
diff --git a/fastboot/tcp.h b/fastboot/tcp.h
new file mode 100644
index 0000000..aa3ef13
--- /dev/null
+++ b/fastboot/tcp.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 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 TCP_H_
+#define TCP_H_
+
+#include <memory>
+#include <string>
+
+#include <android-base/macros.h>
+
+#include "socket.h"
+#include "transport.h"
+
+namespace tcp {
+
+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 {
+
+// Creates a TCP Transport object but using a given Socket instead of connecting to a hostname.
+// 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 tcp
+
+#endif  // TCP_H_
diff --git a/fastboot/tcp_test.cpp b/fastboot/tcp_test.cpp
new file mode 100644
index 0000000..7d80d76
--- /dev/null
+++ b/fastboot/tcp_test.cpp
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "tcp.h"
+
+#include <gtest/gtest.h>
+
+#include "socket_mock.h"
+
+TEST(TcpConnectTest, TestSuccess) {
+    std::unique_ptr<SocketMock> mock(new SocketMock);
+    mock->ExpectSend("FB01");
+    mock->AddReceive("FB01");
+
+    std::string error;
+    EXPECT_NE(nullptr, tcp::internal::Connect(std::move(mock), &error));
+    EXPECT_EQ("", error);
+}
+
+TEST(TcpConnectTest, TestSendFailure) {
+    std::unique_ptr<SocketMock> mock(new SocketMock);
+    mock->ExpectSendFailure("FB01");
+
+    std::string error;
+    EXPECT_EQ(nullptr, tcp::internal::Connect(std::move(mock), &error));
+    EXPECT_NE(std::string::npos, error.find("Failed to send initialization message"));
+}
+
+TEST(TcpConnectTest, TestNoResponseFailure) {
+    std::unique_ptr<SocketMock> mock(new SocketMock);
+    mock->ExpectSend("FB01");
+    mock->AddReceiveFailure();
+
+    std::string error;
+    EXPECT_EQ(nullptr, tcp::internal::Connect(std::move(mock), &error));
+    EXPECT_NE(std::string::npos, error.find("No initialization message received"));
+}
+
+TEST(TcpConnectTest, TestBadResponseFailure) {
+    std::unique_ptr<SocketMock> mock(new SocketMock);
+    mock->ExpectSend("FB01");
+    mock->AddReceive("XX01");
+
+    std::string error;
+    EXPECT_EQ(nullptr, tcp::internal::Connect(std::move(mock), &error));
+    EXPECT_NE(std::string::npos, error.find("Unrecognized initialization message"));
+}
+
+TEST(TcpConnectTest, TestUnknownVersionFailure) {
+    std::unique_ptr<SocketMock> mock(new SocketMock);
+    mock->ExpectSend("FB01");
+    mock->AddReceive("FB02");
+
+    std::string error;
+    EXPECT_EQ(nullptr, tcp::internal::Connect(std::move(mock), &error));
+    EXPECT_EQ("Unknown TCP protocol version 02 (host version 01)", error);
+}
+
+// Fixture to configure a SocketMock for a successful TCP connection.
+class TcpTest : public ::testing::Test {
+  protected:
+    void SetUp() override {
+        mock_ = new SocketMock;
+        mock_->ExpectSend("FB01");
+        mock_->AddReceive("FB01");
+
+        std::string error;
+        transport_ = tcp::internal::Connect(std::unique_ptr<Socket>(mock_), &error);
+        ASSERT_NE(nullptr, transport_);
+        ASSERT_EQ("", error);
+    };
+
+    // 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;
+    }
+
+    // Use a raw SocketMock* here because we pass ownership to the Transport object, but we still
+    // need access to configure mock expectations.
+    SocketMock* mock_ = nullptr;
+    std::unique_ptr<Transport> transport_;
+};
+
+TEST_F(TcpTest, TestWriteSuccess) {
+    mock_->ExpectSend(std::string{0, 0, 0, 0, 0, 0, 0, 3} + "foo");
+
+    EXPECT_TRUE(Write("foo"));
+}
+
+TEST_F(TcpTest, TestReadSuccess) {
+    mock_->AddReceive(std::string{0, 0, 0, 0, 0, 0, 0, 3});
+    mock_->AddReceive("foo");
+
+    EXPECT_TRUE(Read("foo"));
+}
+
+// Tests that fragmented TCP reads are handled properly.
+TEST_F(TcpTest, TestReadFragmentSuccess) {
+    mock_->AddReceive(std::string{0, 0, 0, 0});
+    mock_->AddReceive(std::string{0, 0, 0, 3});
+    mock_->AddReceive("f");
+    mock_->AddReceive("o");
+    mock_->AddReceive("o");
+
+    EXPECT_TRUE(Read("foo"));
+}
+
+TEST_F(TcpTest, TestLargeWriteSuccess) {
+    // 0x100000 = 1MiB.
+    std::string data(0x100000, '\0');
+    for (size_t i = 0; i < data.length(); ++i) {
+        data[i] = i;
+    }
+    mock_->ExpectSend(std::string{0, 0, 0, 0, 0, 0x10, 0, 0} + data);
+
+    EXPECT_TRUE(Write(data));
+}
+
+TEST_F(TcpTest, TestLargeReadSuccess) {
+    // 0x100000 = 1MiB.
+    std::string data(0x100000, '\0');
+    for (size_t i = 0; i < data.length(); ++i) {
+        data[i] = i;
+    }
+    mock_->AddReceive(std::string{0, 0, 0, 0, 0, 0x10, 0, 0});
+    mock_->AddReceive(data);
+
+    EXPECT_TRUE(Read(data));
+}
+
+// Tests a few sample fastboot protocol commands.
+TEST_F(TcpTest, TestFastbootProtocolSuccess) {
+    mock_->ExpectSend(std::string{0, 0, 0, 0, 0, 0, 0, 14} + "getvar:version");
+    mock_->AddReceive(std::string{0, 0, 0, 0, 0, 0, 0, 7});
+    mock_->AddReceive("OKAY0.4");
+
+    mock_->ExpectSend(std::string{0, 0, 0, 0, 0, 0, 0, 10} + "getvar:all");
+    mock_->AddReceive(std::string{0, 0, 0, 0, 0, 0, 0, 16});
+    mock_->AddReceive("INFOversion: 0.4");
+    mock_->AddReceive(std::string{0, 0, 0, 0, 0, 0, 0, 12});
+    mock_->AddReceive("INFOfoo: bar");
+    mock_->AddReceive(std::string{0, 0, 0, 0, 0, 0, 0, 4});
+    mock_->AddReceive("OKAY");
+
+    EXPECT_TRUE(Write("getvar:version"));
+    EXPECT_TRUE(Read("OKAY0.4"));
+
+    EXPECT_TRUE(Write("getvar:all"));
+    EXPECT_TRUE(Read("INFOversion: 0.4"));
+    EXPECT_TRUE(Read("INFOfoo: bar"));
+    EXPECT_TRUE(Read("OKAY"));
+}
+
+TEST_F(TcpTest, TestReadLengthFailure) {
+    mock_->AddReceiveFailure();
+
+    char buffer[16];
+    EXPECT_EQ(-1, transport_->Read(buffer, sizeof(buffer)));
+}
+
+TEST_F(TcpTest, TestReadDataFailure) {
+    mock_->AddReceive(std::string{0, 0, 0, 0, 0, 0, 0, 3});
+    mock_->AddReceiveFailure();
+
+    char buffer[16];
+    EXPECT_EQ(-1, transport_->Read(buffer, sizeof(buffer)));
+}
+
+TEST_F(TcpTest, TestWriteFailure) {
+    mock_->ExpectSendFailure(std::string{0, 0, 0, 0, 0, 0, 0, 3} + "foo");
+
+    EXPECT_EQ(-1, transport_->Write("foo", 3));
+}
+
+TEST_F(TcpTest, TestTransportClose) {
+    EXPECT_EQ(0, transport_->Close());
+
+    // After closing, Transport Read()/Write() should return -1 without actually attempting any
+    // network operations.
+    char buffer[16];
+    EXPECT_EQ(-1, transport_->Read(buffer, sizeof(buffer)));
+    EXPECT_EQ(-1, transport_->Write("foo", 3));
+}
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index cdfe9c5..8f98f17 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -134,6 +134,7 @@
             { "Mains", ANDROID_POWER_SUPPLY_TYPE_AC },
             { "USB", ANDROID_POWER_SUPPLY_TYPE_USB },
             { "USB_DCP", ANDROID_POWER_SUPPLY_TYPE_AC },
+            { "USB_HVDCP", ANDROID_POWER_SUPPLY_TYPE_AC },
             { "USB_CDP", ANDROID_POWER_SUPPLY_TYPE_AC },
             { "USB_ACA", ANDROID_POWER_SUPPLY_TYPE_AC },
             { "USB_C", ANDROID_POWER_SUPPLY_TYPE_AC },
@@ -147,8 +148,10 @@
         return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
 
     ret = (BatteryMonitor::PowerSupplyType)mapSysfsString(buf, supplyTypeMap);
-    if (ret < 0)
+    if (ret < 0) {
+        KLOG_WARNING(LOG_TAG, "Unknown power supply type '%s'\n", buf);
         ret = ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
+    }
 
     return ret;
 }
diff --git a/libcutils/str_parms.c b/libcutils/str_parms.c
index 4f23d09..8dafded 100644
--- a/libcutils/str_parms.c
+++ b/libcutils/str_parms.c
@@ -31,6 +31,20 @@
 
 #define UNUSED __attribute__((unused))
 
+/* When an object is allocated but not freed in a function,
+ * because its ownership is released to other object like a hashmap,
+ * call RELEASE_OWNERSHIP to tell the clang analyzer and avoid
+ * false warnings about potential memory leak.
+ * For now, a "temporary" assignment to global variables
+ * is enough to confuse the clang static analyzer.
+ */
+#ifdef __clang_analyzer__
+static void *released_pointer;
+#define RELEASE_OWNERSHIP(x) { released_pointer = x; released_pointer = 0; }
+#else
+#define RELEASE_OWNERSHIP(x)
+#endif
+
 struct str_parms {
     Hashmap *map;
 };
@@ -170,9 +184,12 @@
 
         /* if we replaced a value, free it */
         old_val = hashmapPut(str_parms->map, key, value);
+        RELEASE_OWNERSHIP(value);
         if (old_val) {
             free(old_val);
             free(key);
+        } else {
+            RELEASE_OWNERSHIP(key);
         }
 
         items++;
@@ -222,10 +239,13 @@
             goto clean_up;
         }
         // For new keys, hashmap takes ownership of tmp_key and tmp_val.
+        RELEASE_OWNERSHIP(tmp_key);
+        RELEASE_OWNERSHIP(tmp_val);
         tmp_key = tmp_val = NULL;
     } else {
         // For existing keys, hashmap takes ownership of tmp_val.
         // (It also gives up ownership of old_val.)
+        RELEASE_OWNERSHIP(tmp_val);
         tmp_val = NULL;
     }
 
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
index 0f81efc..2f8f886 100644
--- a/liblog/log_is_loggable.c
+++ b/liblog/log_is_loggable.c
@@ -110,7 +110,7 @@
      * Where the missing tag matches all tags and becomes the
      * system global default. We do not support ro.log.tag* .
      */
-    static char *last_tag;
+    static char last_tag[PROP_NAME_MAX];
     static uint32_t global_serial;
     /* some compilers erroneously see uninitialized use. !not_locked */
     uint32_t current_global_serial = 0;
@@ -149,20 +149,19 @@
     if (taglen) {
         int local_change_detected = change_detected;
         if (!not_locked) {
-            if (!last_tag
+            if (!last_tag[0]
                     || (last_tag[0] != tag[0])
-                    || strcmp(last_tag + 1, tag + 1)) {
+                    || strncmp(last_tag + 1, tag + 1, sizeof(last_tag) - 1)) {
                 /* invalidate log.tag.<tag> cache */
                 for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
                     tag_cache[i].pinfo = NULL;
                     tag_cache[i].c = '\0';
                 }
-                free(last_tag);
-                last_tag = NULL;
+                last_tag[0] = '\0';
                 local_change_detected = 1;
             }
-            if (!last_tag) {
-                last_tag = strdup(tag);
+            if (!last_tag[0]) {
+                strncpy(last_tag, tag, sizeof(last_tag));
             }
         }
         strcpy(key + sizeof(log_namespace) - 1, tag);
diff --git a/logcat/Android.mk b/logcat/Android.mk
index c4a9550..b828a9f 100644
--- a/logcat/Android.mk
+++ b/logcat/Android.mk
@@ -11,8 +11,6 @@
 
 LOCAL_CFLAGS := -Werror
 
-LOCAL_INIT_RC := logcatd.rc
-
 include $(BUILD_EXECUTABLE)
 
 include $(CLEAR_VARS)
@@ -20,6 +18,7 @@
 LOCAL_MODULE := logpersist.start
 LOCAL_MODULE_TAGS := debug
 LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_INIT_RC := logcatd.rc
 LOCAL_MODULE_PATH := $(bin_dir)
 LOCAL_SRC_FILES := logpersist
 ALL_TOOLS := logpersist.start logpersist.stop logpersist.cat
diff --git a/metricsd/Android.mk b/metricsd/Android.mk
index e140c62..bb262b4 100644
--- a/metricsd/Android.mk
+++ b/metricsd/Android.mk
@@ -200,7 +200,7 @@
 LOCAL_SRC_FILES := $(metricsd_tests_sources) $(metricsd_common)
 LOCAL_STATIC_LIBRARIES := libBionicGtestMain libgmock metricsd_protos metricsd_binder_proxy
 ifdef BRILLO
-LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE_TAGS := eng
 endif
 include $(BUILD_NATIVE_TEST)
 
@@ -218,7 +218,7 @@
 LOCAL_STATIC_LIBRARIES := libBionicGtestMain libgmock metricsd_binder_proxy \
   $(metrics_collector_static_libraries)
 ifdef BRILLO
-LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE_TAGS := eng
 endif
 include $(BUILD_NATIVE_TEST)
 
diff --git a/metricsd/metrics_collector.cc b/metricsd/metrics_collector.cc
index c3f42dc..45ae0a4 100644
--- a/metricsd/metrics_collector.cc
+++ b/metricsd/metrics_collector.cc
@@ -59,7 +59,8 @@
 // Interval between calls to UpdateStats().
 const uint32_t kUpdateStatsIntervalMs = 300000;
 
-const char kKernelCrashDetectedFile[] = "/var/run/kernel-crash-detected";
+const char kKernelCrashDetectedFile[] =
+    "/data/misc/crash_reporter/run/kernel-crash-detected";
 const char kUncleanShutdownDetectedFile[] =
     "/var/run/unclean-shutdown-detected";
 
diff --git a/metricsd/uploader/metricsd_service_runner.cc b/metricsd/uploader/metricsd_service_runner.cc
index 5a759d3..4361cac 100644
--- a/metricsd/uploader/metricsd_service_runner.cc
+++ b/metricsd/uploader/metricsd_service_runner.cc
@@ -20,6 +20,7 @@
 
 #include <binder/IServiceManager.h>
 #include <brillo/binder_watcher.h>
+#include <brillo/message_loops/base_message_loop.h>
 #include <utils/Errors.h>
 
 #include "uploader/bn_metricsd_impl.h"
@@ -40,15 +41,17 @@
   CHECK(status == android::OK) << "Metricsd service registration failed";
 
   message_loop_for_io_.reset(new base::MessageLoopForIO);
+  message_loop_.reset(new brillo::BaseMessageLoop(message_loop_for_io_.get()));
 
-  brillo::BinderWatcher watcher;
+  brillo::BinderWatcher watcher(message_loop_.get());
   CHECK(watcher.Init()) << "failed to initialize the binder file descriptor "
                         << "watcher";
 
-  message_loop_for_io_->Run();
+  message_loop_->Run();
 
   // Delete the message loop here as it needs to be deconstructed in the thread
   // it is attached to.
+  message_loop_.reset();
   message_loop_for_io_.reset();
 }
 
diff --git a/metricsd/uploader/metricsd_service_runner.h b/metricsd/uploader/metricsd_service_runner.h
index 1715de0..f5dad21 100644
--- a/metricsd/uploader/metricsd_service_runner.h
+++ b/metricsd/uploader/metricsd_service_runner.h
@@ -21,6 +21,7 @@
 #include <thread>
 
 #include <base/message_loop/message_loop.h>
+#include <brillo/message_loops/message_loop.h>
 
 #include "uploader/crash_counters.h"
 
@@ -39,6 +40,7 @@
   void Run();
 
   std::unique_ptr<base::MessageLoopForIO> message_loop_for_io_;
+  std::unique_ptr<brillo::MessageLoop> message_loop_;
 
   std::unique_ptr<std::thread> thread_;
   std::shared_ptr<CrashCounters> counters_;
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 895a25d..d90f988 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -12,6 +12,18 @@
 include $(BUILD_PREBUILT)
 
 #######################################
+# init-debug.rc
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := init-debug.rc
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/init
+
+include $(BUILD_PREBUILT)
+
+#######################################
 # asan.options
 ifneq ($(filter address,$(SANITIZE_TARGET)),)
 include $(CLEAR_VARS)
diff --git a/rootdir/init-debug.rc b/rootdir/init-debug.rc
new file mode 100644
index 0000000..435d4cb
--- /dev/null
+++ b/rootdir/init-debug.rc
@@ -0,0 +1,8 @@
+on property:persist.mmc.max_read_speed=*
+    write /sys/block/mmcblk0/max_read_speed ${persist.mmc.max_read_speed}
+
+on property:persist.mmc.max_write_speed=*
+    write /sys/block/mmcblk0/max_write_speed ${persist.mmc.max_write_speed}
+
+on property:persist.mmc.cache_size=*
+    write /sys/block/mmcblk0/cache_size ${persist.mmc.cache_size}