resolve merge conflicts of 1f1a6fd to nyc-mr1-dev-plus-aosp

Change-Id: Ic07b6db6f47d2157aef0d04d025ba747d0a4247d
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 5d335b5..5b5eff4 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -56,4 +56,7 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/lmkd_intermediates/import_includes)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libsysutils_intermediates/import_includes)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/grep $(PRODUCT_OUT)/system/bin/toolbox)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/hw/gatekeeper.$(TARGET_DEVICE).so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/hw/gatekeeper.$(TARGET_DEVICE).so)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/vendor)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/init.rc)
diff --git a/adb/Android.mk b/adb/Android.mk
index 8f56d74..be04cfa 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -18,11 +18,9 @@
     -DADB_REVISION='"$(adb_version)"' \
 
 ADB_COMMON_linux_CFLAGS := \
-    -std=c++14 \
     -Wexit-time-destructors \
 
 ADB_COMMON_darwin_CFLAGS := \
-    -std=c++14 \
     -Wexit-time-destructors \
 
 # Define windows.h and tchar.h Unicode preprocessor symbols so that
@@ -45,21 +43,23 @@
 # get enough of adb in here that we no longer need minadb. https://b/17626262
 LIBADB_SRC_FILES := \
     adb.cpp \
-    adb_auth.cpp \
     adb_io.cpp \
     adb_listeners.cpp \
     adb_trace.cpp \
     adb_utils.cpp \
     fdevent.cpp \
     sockets.cpp \
+    socket_spec.cpp \
     transport.cpp \
     transport_local.cpp \
     transport_usb.cpp \
 
 LIBADB_TEST_SRCS := \
     adb_io_test.cpp \
+    adb_listeners_test.cpp \
     adb_utils_test.cpp \
     fdevent_test.cpp \
+    socket_spec_test.cpp \
     socket_test.cpp \
     sysdeps_test.cpp \
     sysdeps/stat_test.cpp \
@@ -79,12 +79,10 @@
     $(ADB_COMMON_windows_CFLAGS) \
 
 LIBADB_darwin_SRC_FILES := \
-    get_my_path_darwin.cpp \
     sysdeps_unix.cpp \
     usb_osx.cpp \
 
 LIBADB_linux_SRC_FILES := \
-    get_my_path_linux.cpp \
     sysdeps_unix.cpp \
     usb_linux.cpp \
 
@@ -102,7 +100,7 @@
 LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=0
 LOCAL_SRC_FILES := \
     $(LIBADB_SRC_FILES) \
-    adb_auth_client.cpp \
+    adbd_auth.cpp \
     jdwp_service.cpp \
     usb_linux_client.cpp \
 
@@ -110,7 +108,7 @@
 
 # Even though we're building a static library (and thus there's no link step for
 # this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libbase
+LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libbase
 
 include $(BUILD_STATIC_LIBRARY)
 
@@ -133,7 +131,7 @@
 
 # Even though we're building a static library (and thus there's no link step for
 # this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libcrypto_static libbase
+LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libbase
 
 LOCAL_C_INCLUDES_windows := development/host/windows/usb/api/
 LOCAL_MULTILIB := first
@@ -153,7 +151,7 @@
     shell_service_test.cpp \
 
 LOCAL_SANITIZE := $(adb_target_sanitize)
-LOCAL_STATIC_LIBRARIES := libadbd
+LOCAL_STATIC_LIBRARIES := libadbd libcrypto_utils libcrypto
 LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
 include $(BUILD_NATIVE_TEST)
 
@@ -197,7 +195,8 @@
 LOCAL_SHARED_LIBRARIES := libbase
 LOCAL_STATIC_LIBRARIES := \
     libadb \
-    libcrypto_static \
+    libcrypto_utils \
+    libcrypto \
     libcutils \
     libdiagnose_usb \
     libgmock_host \
@@ -213,24 +212,6 @@
 
 include $(BUILD_HOST_NATIVE_TEST)
 
-# adb device tracker (used by ddms) test tool
-# =========================================================
-
-ifeq ($(HOST_OS),linux)
-include $(CLEAR_VARS)
-LOCAL_MODULE := adb_device_tracker_test
-LOCAL_CFLAGS := -DADB_HOST=1 $(LIBADB_CFLAGS)
-LOCAL_CFLAGS_windows := $(LIBADB_windows_CFLAGS)
-LOCAL_CFLAGS_linux := $(LIBADB_linux_CFLAGS)
-LOCAL_CFLAGS_darwin := $(LIBADB_darwin_CFLAGS)
-LOCAL_SRC_FILES := test_track_devices.cpp
-LOCAL_SANITIZE := $(adb_host_sanitize)
-LOCAL_SHARED_LIBRARIES := libbase
-LOCAL_STATIC_LIBRARIES := libadb libcrypto_static libcutils
-LOCAL_LDLIBS += -lrt -ldl -lpthread
-include $(BUILD_HOST_EXECUTABLE)
-endif
-
 # adb host tool
 # =========================================================
 include $(CLEAR_VARS)
@@ -279,7 +260,8 @@
 LOCAL_STATIC_LIBRARIES := \
     libadb \
     libbase \
-    libcrypto_static \
+    libcrypto_utils \
+    libcrypto \
     libdiagnose_usb \
     liblog \
 
@@ -339,9 +321,9 @@
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
-LOCAL_C_INCLUDES += system/extras/ext4_utils
 
 LOCAL_SANITIZE := $(adb_target_sanitize)
+LOCAL_STRIP_MODULE := keep_symbols
 LOCAL_STATIC_LIBRARIES := \
     libadbd \
     libbase \
@@ -350,12 +332,13 @@
     libfec_rs \
     libselinux \
     liblog \
-    libmincrypt \
     libext4_utils_static \
     libsquashfs_utils \
     libcutils \
     libbase \
-    libcrypto_static \
-    libminijail
+    libcrypto_utils \
+    libcrypto \
+    libminijail \
+    libdebuggerd_client \
 
 include $(BUILD_EXECUTABLE)
diff --git a/adb/adb.cpp b/adb/adb.cpp
index e0c0503..3cd50ba 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -30,10 +30,13 @@
 #include <sys/time.h>
 #include <time.h>
 
+#include <chrono>
 #include <string>
+#include <thread>
 #include <vector>
 
 #include <android-base/errors.h>
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/macros.h>
 #include <android-base/parsenetaddress.h>
@@ -46,12 +49,11 @@
 #include "adb_utils.h"
 #include "transport.h"
 
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-
 #if !ADB_HOST
-#include <cutils/properties.h>
 #include <sys/capability.h>
 #include <sys/mount.h>
+#include <android-base/properties.h>
+using namespace std::chrono_literals;
 #endif
 
 std::string adb_version() {
@@ -65,21 +67,46 @@
 void fatal(const char *fmt, ...) {
     va_list ap;
     va_start(ap, fmt);
-    fprintf(stderr, "error: ");
-    vfprintf(stderr, fmt, ap);
-    fprintf(stderr, "\n");
+    char buf[1024];
+    vsnprintf(buf, sizeof(buf), fmt, ap);
+
+#if ADB_HOST
+    fprintf(stderr, "error: %s\n", buf);
+#else
+    LOG(ERROR) << "error: " << buf;
+#endif
+
     va_end(ap);
-    exit(-1);
+    abort();
 }
 
 void fatal_errno(const char* fmt, ...) {
+    int err = errno;
     va_list ap;
     va_start(ap, fmt);
-    fprintf(stderr, "error: %s: ", strerror(errno));
-    vfprintf(stderr, fmt, ap);
-    fprintf(stderr, "\n");
+    char buf[1024];
+    vsnprintf(buf, sizeof(buf), fmt, ap);
+
+#if ADB_HOST
+    fprintf(stderr, "error: %s: %s\n", buf, strerror(err));
+#else
+    LOG(ERROR) << "error: " << buf << ": " << strerror(err);
+#endif
+
     va_end(ap);
-    exit(-1);
+    abort();
+}
+
+uint32_t calculate_apacket_checksum(const apacket* p) {
+    const unsigned char* x = reinterpret_cast<const unsigned char*>(p->data);
+    uint32_t sum = 0;
+    size_t count = p->msg.data_length;
+
+    while (count-- > 0) {
+        sum += *x++;
+    }
+
+    return sum;
 }
 
 apacket* get_apacket(void)
@@ -188,11 +215,9 @@
         "ro.product.device",
     };
 
-    for (const auto& prop_name : cnxn_props) {
-        char value[PROPERTY_VALUE_MAX];
-        property_get(prop_name, value, "");
-        connection_properties.push_back(
-            android::base::StringPrintf("%s=%s", prop_name, value));
+    for (const auto& prop : cnxn_props) {
+        std::string value = std::string(prop) + "=" + android::base::GetProperty(prop, "");
+        connection_properties.push_back(value);
     }
 #endif
 
@@ -316,8 +341,6 @@
 
 void handle_packet(apacket *p, atransport *t)
 {
-    asocket *s;
-
     D("handle_packet() %c%c%c%c", ((char*) (&(p->msg.command)))[0],
             ((char*) (&(p->msg.command)))[1],
             ((char*) (&(p->msg.command)))[2],
@@ -326,7 +349,7 @@
 
     switch(p->msg.command){
     case A_SYNC:
-        if(p->msg.arg0){
+        if (p->msg.arg0){
             send_packet(p, t);
 #if ADB_HOST
             send_connect(t);
@@ -343,26 +366,31 @@
         break;
 
     case A_AUTH:
-        if (p->msg.arg0 == ADB_AUTH_TOKEN) {
-            t->connection_state = kCsUnauthorized;
-            t->key = adb_auth_nextkey(t->key);
-            if (t->key) {
+        switch (p->msg.arg0) {
+#if ADB_HOST
+            case ADB_AUTH_TOKEN:
+                t->connection_state = kCsUnauthorized;
                 send_auth_response(p->data, p->msg.data_length, t);
-            } else {
-                /* No more private keys to try, send the public key */
-                send_auth_publickey(t);
-            }
-        } else if (p->msg.arg0 == ADB_AUTH_SIGNATURE) {
-            if (adb_auth_verify(t->token, p->data, p->msg.data_length)) {
-                adb_auth_verified(t);
-                t->failed_auth_attempts = 0;
-            } else {
-                if (t->failed_auth_attempts++ > 10)
-                    adb_sleep_ms(1000);
-                send_auth_request(t);
-            }
-        } else if (p->msg.arg0 == ADB_AUTH_RSAPUBLICKEY) {
-            adb_auth_confirm_key(p->data, p->msg.data_length, t);
+                break;
+#else
+            case ADB_AUTH_SIGNATURE:
+                if (adbd_auth_verify(t->token, sizeof(t->token), p->data, p->msg.data_length)) {
+                    adbd_auth_verified(t);
+                    t->failed_auth_attempts = 0;
+                } else {
+                    if (t->failed_auth_attempts++ > 256) std::this_thread::sleep_for(1s);
+                    send_auth_request(t);
+                }
+                break;
+
+            case ADB_AUTH_RSAPUBLICKEY:
+                adbd_auth_confirm_key(p->data, p->msg.data_length, t);
+                break;
+#endif
+            default:
+                t->connection_state = kCsOffline;
+                handle_offline(t);
+                break;
         }
         break;
 
@@ -370,8 +398,8 @@
         if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) {
             char *name = (char*) p->data;
             name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
-            s = create_local_service_socket(name, t);
-            if(s == 0) {
+            asocket* s = create_local_service_socket(name, t);
+            if (s == nullptr) {
                 send_close(0, p->msg.arg0, t);
             } else {
                 s->peer = create_remote_socket(p->msg.arg0, t);
@@ -384,7 +412,8 @@
 
     case A_OKAY: /* READY(local-id, remote-id, "") */
         if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
-            if((s = find_local_socket(p->msg.arg1, 0))) {
+            asocket* s = find_local_socket(p->msg.arg1, 0);
+            if (s) {
                 if(s->peer == 0) {
                     /* On first READY message, create the connection. */
                     s->peer = create_remote_socket(p->msg.arg0, t);
@@ -408,7 +437,8 @@
 
     case A_CLSE: /* CLOSE(local-id, remote-id, "") or CLOSE(0, remote-id, "") */
         if (t->online && p->msg.arg1 != 0) {
-            if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
+            asocket* s = find_local_socket(p->msg.arg1, p->msg.arg0);
+            if (s) {
                 /* According to protocol.txt, p->msg.arg0 might be 0 to indicate
                  * a failed OPEN only. However, due to a bug in previous ADB
                  * versions, CLOSE(0, remote-id, "") was also used for normal
@@ -431,11 +461,12 @@
 
     case A_WRTE: /* WRITE(local-id, remote-id, <data>) */
         if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
-            if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
+            asocket* s = find_local_socket(p->msg.arg1, p->msg.arg0);
+            if (s) {
                 unsigned rid = p->msg.arg0;
                 p->len = p->msg.data_length;
 
-                if(s->enqueue(s, p) == 0) {
+                if (s->enqueue(s, p) == 0) {
                     D("Enqueue the socket");
                     send_ready(s->id, rid, t);
                 }
@@ -605,8 +636,7 @@
 
 #endif
 
-int launch_server(int server_port)
-{
+int launch_server(const std::string& socket_spec) {
 #if defined(_WIN32)
     /* we need to start the server in the background                    */
     /* we create a PIPE that will be used to wait for the server's "OK" */
@@ -709,9 +739,8 @@
     }
 
     WCHAR   args[64];
-    snwprintf(args, arraysize(args),
-              L"adb -P %d fork-server server --reply-fd %d", server_port,
-              ack_write_as_int);
+    snwprintf(args, arraysize(args), L"adb -L %s fork-server server --reply-fd %d",
+              socket_spec.c_str(), ack_write_as_int);
 
     PROCESS_INFORMATION   pinfo;
     ZeroMemory(&pinfo, sizeof(pinfo));
@@ -838,30 +867,29 @@
         return -1;
     }
 #else /* !defined(_WIN32) */
-    char    path[PATH_MAX];
-    int     fd[2];
-
     // set up a pipe so the child can tell us when it is ready.
     // fd[0] will be parent's end, and the child will write on fd[1]
+    int fd[2];
     if (pipe(fd)) {
         fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno);
         return -1;
     }
-    get_my_path(path, PATH_MAX);
+
+    std::string path = android::base::GetExecutablePath();
+
     pid_t pid = fork();
-    if(pid < 0) return -1;
+    if (pid < 0) return -1;
 
     if (pid == 0) {
         // child side of the fork
 
         adb_close(fd[0]);
 
-        char str_port[30];
-        snprintf(str_port, sizeof(str_port), "%d", server_port);
         char reply_fd[30];
         snprintf(reply_fd, sizeof(reply_fd), "%d", fd[1]);
         // child process
-        int result = execl(path, "adb", "-P", str_port, "fork-server", "server", "--reply-fd", reply_fd, NULL);
+        int result = execl(path.c_str(), "adb", "-L", socket_spec.c_str(), "fork-server", "server",
+                           "--reply-fd", reply_fd, NULL);
         // this should not return
         fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
     } else  {
@@ -954,18 +982,25 @@
 
         std::string error;
         InstallStatus r;
+        int resolved_tcp_port = 0;
         if (kill_forward) {
             r = remove_listener(pieces[0].c_str(), transport);
         } else {
-            r = install_listener(pieces[0], pieces[1].c_str(), transport,
-                                 no_rebind, &error);
+            r = install_listener(pieces[0], pieces[1].c_str(), transport, no_rebind,
+                                 &resolved_tcp_port, &error);
         }
         if (r == INSTALL_STATUS_OK) {
 #if ADB_HOST
-            /* On the host: 1st OKAY is connect, 2nd OKAY is status */
+            // On the host: 1st OKAY is connect, 2nd OKAY is status.
             SendOkay(reply_fd);
 #endif
             SendOkay(reply_fd);
+
+            // If a TCP port was resolved, send the actual port number back.
+            if (resolved_tcp_port != 0) {
+                SendProtocolString(reply_fd, android::base::StringPrintf("%d", resolved_tcp_port));
+            }
+
             return 1;
         }
 
@@ -1057,6 +1092,31 @@
         return 1;
     }
 
+    if (!strcmp(service, "reconnect-offline")) {
+        std::string response;
+        close_usb_devices([&response](const atransport* transport) {
+            switch (transport->connection_state) {
+                case kCsOffline:
+                case kCsUnauthorized:
+                    response += "reconnecting ";
+                    if (transport->serial) {
+                        response += transport->serial;
+                    } else {
+                        response += "<unknown>";
+                    }
+                    response += "\n";
+                    return true;
+                default:
+                    return false;
+            }
+        });
+        if (!response.empty()) {
+            response.resize(response.size() - 1);
+        }
+        SendOkay(reply_fd, response);
+        return 0;
+    }
+
     if (!strcmp(service, "features")) {
         std::string error;
         atransport* t = acquire_one_transport(type, serial, nullptr, &error);
diff --git a/adb/adb.h b/adb/adb.h
index b1d9896..df59aaa 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -18,6 +18,7 @@
 #define __ADB_H
 
 #include <limits.h>
+#include <stdint.h>
 #include <sys/types.h>
 
 #include <string>
@@ -50,31 +51,33 @@
 std::string adb_version();
 
 // Increment this when we want to force users to start a new adb server.
-#define ADB_SERVER_VERSION 36
+#define ADB_SERVER_VERSION 37
 
 class atransport;
 struct usb_handle;
 
 struct amessage {
-    unsigned command;       /* command identifier constant      */
-    unsigned arg0;          /* first argument                   */
-    unsigned arg1;          /* second argument                  */
-    unsigned data_length;   /* length of payload (0 is allowed) */
-    unsigned data_check;    /* checksum of data payload         */
-    unsigned magic;         /* command ^ 0xffffffff             */
+    uint32_t command;     /* command identifier constant      */
+    uint32_t arg0;        /* first argument                   */
+    uint32_t arg1;        /* second argument                  */
+    uint32_t data_length; /* length of payload (0 is allowed) */
+    uint32_t data_check;  /* checksum of data payload         */
+    uint32_t magic;       /* command ^ 0xffffffff             */
 };
 
 struct apacket
 {
     apacket *next;
 
-    unsigned len;
-    unsigned char *ptr;
+    size_t len;
+    char* ptr;
 
     amessage msg;
-    unsigned char data[MAX_PAYLOAD];
+    char data[MAX_PAYLOAD];
 };
 
+uint32_t calculate_apacket_checksum(const apacket* packet);
+
 /* the adisconnect structure is used to record a callback that
 ** will be called whenever a transport is disconnected (e.g. by the user)
 ** this should be used to cleanup objects that depend on the
@@ -116,29 +119,6 @@
     kCsUnauthorized,
 };
 
-/* A listener is an entity which binds to a local port
-** and, upon receiving a connection on that port, creates
-** an asocket to connect the new local connection to a
-** specific remote service.
-**
-** TODO: some listeners read from the new connection to
-** determine what exact service to connect to on the far
-** side.
-*/
-struct alistener
-{
-    alistener *next;
-    alistener *prev;
-
-    fdevent fde;
-    int fd;
-
-    char *local_name;
-    char *connect_to;
-    atransport *transport;
-    adisconnect  disconnect;
-};
-
 
 void print_packet(const char *label, apacket *p);
 
@@ -149,9 +129,8 @@
 
 void handle_packet(apacket *p, atransport *t);
 
-void get_my_path(char *s, size_t maxLen);
-int launch_server(int server_port);
-int adb_server_main(int is_daemon, int server_port, int ack_reply_fd);
+int launch_server(const std::string& socket_spec);
+int adb_server_main(int is_daemon, const std::string& socket_spec, int ack_reply_fd);
 
 /* initialize a transport object's func pointers and state */
 #if ADB_HOST
@@ -213,7 +192,7 @@
 
 
 void local_init(int port);
-void local_connect(int port);
+bool local_connect(int port);
 int  local_connect_arbitrary_ports(int console_port, int adb_port, std::string* error);
 
 // USB host/client interface.
@@ -225,7 +204,7 @@
 
 // USB device detection.
 #if ADB_HOST
-int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol);
+int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol);
 #endif
 
 ConnectionState connection_state(atransport *t);
diff --git a/adb/adb_auth.cpp b/adb/adb_auth.cpp
deleted file mode 100644
index 1ffab09..0000000
--- a/adb/adb_auth.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define TRACE_TAG ADB
-
-#include "sysdeps.h"
-#include "adb_auth.h"
-
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "adb.h"
-#include "transport.h"
-
-bool auth_required = true;
-
-void send_auth_request(atransport *t)
-{
-    D("Calling send_auth_request");
-    apacket *p;
-    int ret;
-
-    ret = adb_auth_generate_token(t->token, sizeof(t->token));
-    if (ret != sizeof(t->token)) {
-        D("Error generating token ret=%d", ret);
-        return;
-    }
-
-    p = get_apacket();
-    memcpy(p->data, t->token, ret);
-    p->msg.command = A_AUTH;
-    p->msg.arg0 = ADB_AUTH_TOKEN;
-    p->msg.data_length = ret;
-    send_packet(p, t);
-}
-
-void send_auth_response(uint8_t *token, size_t token_size, atransport *t)
-{
-    D("Calling send_auth_response");
-    apacket *p = get_apacket();
-    int ret;
-
-    ret = adb_auth_sign(t->key, token, token_size, p->data);
-    if (!ret) {
-        D("Error signing the token");
-        put_apacket(p);
-        return;
-    }
-
-    p->msg.command = A_AUTH;
-    p->msg.arg0 = ADB_AUTH_SIGNATURE;
-    p->msg.data_length = ret;
-    send_packet(p, t);
-}
-
-void send_auth_publickey(atransport *t)
-{
-    D("Calling send_auth_publickey");
-    apacket *p = get_apacket();
-    int ret;
-
-    ret = adb_auth_get_userkey(p->data, MAX_PAYLOAD_V1);
-    if (!ret) {
-        D("Failed to get user public key");
-        put_apacket(p);
-        return;
-    }
-
-    p->msg.command = A_AUTH;
-    p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
-    p->msg.data_length = ret;
-    send_packet(p, t);
-}
-
-void adb_auth_verified(atransport *t)
-{
-    handle_online(t);
-    send_connect(t);
-}
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
index a13604a..a6f224f 100644
--- a/adb/adb_auth.h
+++ b/adb/adb_auth.h
@@ -19,14 +19,10 @@
 
 #include "adb.h"
 
-extern bool auth_required;
+#include <deque>
+#include <memory>
 
-int adb_auth_keygen(const char* filename);
-void adb_auth_verified(atransport *t);
-
-void send_auth_request(atransport *t);
-void send_auth_response(uint8_t *token, size_t token_size, atransport *t);
-void send_auth_publickey(atransport *t);
+#include <openssl/rsa.h>
 
 /* AUTH packets first argument */
 /* Request */
@@ -37,30 +33,26 @@
 
 #if ADB_HOST
 
-void adb_auth_init(void);
-int adb_auth_sign(void *key, const unsigned char* token, size_t token_size,
-                  unsigned char* sig);
-void *adb_auth_nextkey(void *current);
-int adb_auth_get_userkey(unsigned char *data, size_t len);
+void adb_auth_init();
 
-static inline int adb_auth_generate_token(void *token, size_t token_size) { return 0; }
-static inline int adb_auth_verify(void *token, void *sig, int siglen) { return 0; }
-static inline void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t) { }
+int adb_auth_keygen(const char* filename);
+std::string adb_auth_get_userkey();
+std::deque<std::shared_ptr<RSA>> adb_auth_get_private_keys();
+
+void send_auth_response(const char* token, size_t token_size, atransport* t);
 
 #else // !ADB_HOST
 
-static inline int adb_auth_sign(void* key, const unsigned char* token,
-                                size_t token_size, unsigned char* sig) {
-    return 0;
-}
-static inline void *adb_auth_nextkey(void *current) { return NULL; }
-static inline int adb_auth_get_userkey(unsigned char *data, size_t len) { return 0; }
+extern bool auth_required;
 
 void adbd_auth_init(void);
+void adbd_auth_verified(atransport *t);
+
 void adbd_cloexec_auth_socket();
-int adb_auth_generate_token(void *token, size_t token_size);
-int adb_auth_verify(uint8_t* token, uint8_t* sig, int siglen);
-void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t);
+bool adbd_auth_verify(const char* token, size_t token_size, const char* sig, int sig_len);
+void adbd_auth_confirm_key(const char* data, size_t len, atransport* t);
+
+void send_auth_request(atransport *t);
 
 #endif // ADB_HOST
 
diff --git a/adb/adb_auth_client.cpp b/adb/adb_auth_client.cpp
deleted file mode 100644
index 128c3df..0000000
--- a/adb/adb_auth_client.cpp
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#define TRACE_TAG AUTH
-
-#include "sysdeps.h"
-#include "adb_auth.h"
-
-#include <resolv.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "cutils/list.h"
-#include "cutils/sockets.h"
-#include "mincrypt/rsa.h"
-#include "mincrypt/sha.h"
-
-#include "adb.h"
-#include "fdevent.h"
-#include "transport.h"
-
-struct adb_public_key {
-    struct listnode node;
-    RSAPublicKey key;
-};
-
-static const char *key_paths[] = {
-    "/adb_keys",
-    "/data/misc/adb/adb_keys",
-    NULL
-};
-
-static fdevent listener_fde;
-static fdevent framework_fde;
-static int framework_fd = -1;
-
-static void usb_disconnected(void* unused, atransport* t);
-static struct adisconnect usb_disconnect = { usb_disconnected, nullptr};
-static atransport* usb_transport;
-static bool needs_retry = false;
-
-static void read_keys(const char *file, struct listnode *list)
-{
-    FILE *f;
-    char buf[MAX_PAYLOAD_V1];
-    char *sep;
-    int ret;
-
-    f = fopen(file, "re");
-    if (!f) {
-        D("Can't open '%s'", file);
-        return;
-    }
-
-    while (fgets(buf, sizeof(buf), f)) {
-        /* Allocate 4 extra bytes to decode the base64 data in-place */
-        auto key = reinterpret_cast<adb_public_key*>(
-            calloc(1, sizeof(adb_public_key) + 4));
-        if (key == nullptr) {
-            D("Can't malloc key");
-            break;
-        }
-
-        sep = strpbrk(buf, " \t");
-        if (sep)
-            *sep = '\0';
-
-        ret = __b64_pton(buf, (u_char *)&key->key, sizeof(key->key) + 4);
-        if (ret != sizeof(key->key)) {
-            D("%s: Invalid base64 data ret=%d", file, ret);
-            free(key);
-            continue;
-        }
-
-        if (key->key.len != RSANUMWORDS) {
-            D("%s: Invalid key len %d", file, key->key.len);
-            free(key);
-            continue;
-        }
-
-        list_add_tail(list, &key->node);
-    }
-
-    fclose(f);
-}
-
-static void free_keys(struct listnode *list)
-{
-    struct listnode *item;
-
-    while (!list_empty(list)) {
-        item = list_head(list);
-        list_remove(item);
-        free(node_to_item(item, struct adb_public_key, node));
-    }
-}
-
-static void load_keys(struct listnode *list)
-{
-    const char* path;
-    const char** paths = key_paths;
-    struct stat buf;
-
-    list_init(list);
-
-    while ((path = *paths++)) {
-        if (!stat(path, &buf)) {
-            D("Loading keys from '%s'", path);
-            read_keys(path, list);
-        }
-    }
-}
-
-int adb_auth_generate_token(void *token, size_t token_size)
-{
-    FILE *f;
-    int ret;
-
-    f = fopen("/dev/urandom", "re");
-    if (!f)
-        return 0;
-
-    ret = fread(token, token_size, 1, f);
-
-    fclose(f);
-    return ret * token_size;
-}
-
-int adb_auth_verify(uint8_t* token, uint8_t* sig, int siglen)
-{
-    struct listnode *item;
-    struct listnode key_list;
-    int ret = 0;
-
-    if (siglen != RSANUMBYTES)
-        return 0;
-
-    load_keys(&key_list);
-
-    list_for_each(item, &key_list) {
-        adb_public_key* key = node_to_item(item, struct adb_public_key, node);
-        ret = RSA_verify(&key->key, sig, siglen, token, SHA_DIGEST_SIZE);
-        if (ret)
-            break;
-    }
-
-    free_keys(&key_list);
-
-    return ret;
-}
-
-static void usb_disconnected(void* unused, atransport* t) {
-    D("USB disconnect");
-    usb_transport = NULL;
-    needs_retry = false;
-}
-
-static void framework_disconnected() {
-    D("Framework disconnect");
-    fdevent_remove(&framework_fde);
-    framework_fd = -1;
-}
-
-static void adb_auth_event(int fd, unsigned events, void*) {
-    char response[2];
-    int ret;
-
-    if (events & FDE_READ) {
-        ret = unix_read(fd, response, sizeof(response));
-        if (ret <= 0) {
-            framework_disconnected();
-        } else if (ret == 2 && response[0] == 'O' && response[1] == 'K') {
-            if (usb_transport) {
-                adb_auth_verified(usb_transport);
-            }
-        }
-    }
-}
-
-void adb_auth_confirm_key(unsigned char *key, size_t len, atransport *t)
-{
-    char msg[MAX_PAYLOAD_V1];
-    int ret;
-
-    if (!usb_transport) {
-        usb_transport = t;
-        t->AddDisconnect(&usb_disconnect);
-    }
-
-    if (framework_fd < 0) {
-        D("Client not connected");
-        needs_retry = true;
-        return;
-    }
-
-    if (key[len - 1] != '\0') {
-        D("Key must be a null-terminated string");
-        return;
-    }
-
-    ret = snprintf(msg, sizeof(msg), "PK%s", key);
-    if (ret >= (signed)sizeof(msg)) {
-        D("Key too long. ret=%d", ret);
-        return;
-    }
-    D("Sending '%s'", msg);
-
-    ret = unix_write(framework_fd, msg, ret);
-    if (ret < 0) {
-        D("Failed to write PK, errno=%d", errno);
-        return;
-    }
-}
-
-static void adb_auth_listener(int fd, unsigned events, void* data) {
-    sockaddr_storage addr;
-    socklen_t alen;
-    int s;
-
-    alen = sizeof(addr);
-
-    s = adb_socket_accept(fd, reinterpret_cast<sockaddr*>(&addr), &alen);
-    if (s < 0) {
-        D("Failed to accept: errno=%d", errno);
-        return;
-    }
-
-    if (framework_fd >= 0) {
-        LOG(WARNING) << "adb received framework auth socket connection again";
-        framework_disconnected();
-    }
-
-    framework_fd = s;
-    fdevent_install(&framework_fde, framework_fd, adb_auth_event, nullptr);
-    fdevent_add(&framework_fde, FDE_READ);
-
-    if (needs_retry) {
-        needs_retry = false;
-        send_auth_request(usb_transport);
-    }
-}
-
-void adbd_cloexec_auth_socket() {
-    int fd = android_get_control_socket("adbd");
-    if (fd == -1) {
-        D("Failed to get adbd socket");
-        return;
-    }
-    fcntl(fd, F_SETFD, FD_CLOEXEC);
-}
-
-void adbd_auth_init(void) {
-    int fd = android_get_control_socket("adbd");
-    if (fd == -1) {
-        D("Failed to get adbd socket");
-        return;
-    }
-
-    if (listen(fd, 4) == -1) {
-        D("Failed to listen on '%d'", fd);
-        return;
-    }
-
-    fdevent_install(&listener_fde, fd, adb_auth_listener, NULL);
-    fdevent_add(&listener_fde, FDE_READ);
-}
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index 7b6671d..ff2d76d 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -16,211 +16,106 @@
 
 #define TRACE_TAG AUTH
 
-#include "sysdeps.h"
-#include "adb_auth.h"
-#include "adb_utils.h"
-
+#include <dirent.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#if defined(__linux__)
+#include <sys/inotify.h>
+#endif
 
-#include "adb.h"
-
-/* HACK: we need the RSAPublicKey struct
- * but RSA_verify conflits with openssl */
-#define RSA_verify RSA_verify_mincrypt
-#include "mincrypt/rsa.h"
-#undef RSA_verify
+#include <map>
+#include <mutex>
+#include <set>
+#include <string>
 
 #include <android-base/errors.h>
+#include <android-base/file.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <cutils/list.h>
-
+#include <crypto_utils/android_pubkey.h>
+#include <openssl/base64.h>
 #include <openssl/evp.h>
 #include <openssl/objects.h>
 #include <openssl/pem.h>
 #include <openssl/rsa.h>
 #include <openssl/sha.h>
 
-#if defined(OPENSSL_IS_BORINGSSL)
-#include <openssl/base64.h>
+#include "adb.h"
+#include "adb_auth.h"
+#include "adb_utils.h"
+#include "sysdeps.h"
+#include "transport.h"
+
+static std::mutex& g_keys_mutex = *new std::mutex;
+static std::map<std::string, std::shared_ptr<RSA>>& g_keys =
+    *new std::map<std::string, std::shared_ptr<RSA>>;
+static std::map<int, std::string>& g_monitored_paths = *new std::map<int, std::string>;
+
+static std::string get_user_info() {
+    LOG(INFO) << "get_user_info...";
+
+    std::string hostname;
+    if (getenv("HOSTNAME")) hostname = getenv("HOSTNAME");
+#if !defined(_WIN32)
+    char buf[64];
+    if (hostname.empty() && gethostname(buf, sizeof(buf)) != -1) hostname = buf;
 #endif
+    if (hostname.empty()) hostname = "unknown";
 
-#define ANDROID_PATH   ".android"
-#define ADB_KEY_FILE   "adbkey"
-
-struct adb_private_key {
-    struct listnode node;
-    RSA *rsa;
-};
-
-static struct listnode key_list;
-
-
-/* Convert OpenSSL RSA private key to android pre-computed RSAPublicKey format */
-static int RSA_to_RSAPublicKey(RSA *rsa, RSAPublicKey *pkey)
-{
-    int ret = 1;
-    unsigned int i;
-
-    BN_CTX* ctx = BN_CTX_new();
-    BIGNUM* r32 = BN_new();
-    BIGNUM* rr = BN_new();
-    BIGNUM* r = BN_new();
-    BIGNUM* rem = BN_new();
-    BIGNUM* n = BN_new();
-    BIGNUM* n0inv = BN_new();
-
-    if (RSA_size(rsa) != RSANUMBYTES) {
-        ret = 0;
-        goto out;
-    }
-
-    BN_set_bit(r32, 32);
-    BN_copy(n, rsa->n);
-    BN_set_bit(r, RSANUMWORDS * 32);
-    BN_mod_sqr(rr, r, n, ctx);
-    BN_div(NULL, rem, n, r32, ctx);
-    BN_mod_inverse(n0inv, rem, r32, ctx);
-
-    pkey->len = RSANUMWORDS;
-    pkey->n0inv = 0 - BN_get_word(n0inv);
-    for (i = 0; i < RSANUMWORDS; i++) {
-        BN_div(rr, rem, rr, r32, ctx);
-        pkey->rr[i] = BN_get_word(rem);
-        BN_div(n, rem, n, r32, ctx);
-        pkey->n[i] = BN_get_word(rem);
-    }
-    pkey->exponent = BN_get_word(rsa->e);
-
-out:
-    BN_free(n0inv);
-    BN_free(n);
-    BN_free(rem);
-    BN_free(r);
-    BN_free(rr);
-    BN_free(r32);
-    BN_CTX_free(ctx);
-
-    return ret;
-}
-
-static void get_user_info(char *buf, size_t len)
-{
-    char hostname[1024], username[1024];
-    int ret = -1;
-
-    if (getenv("HOSTNAME") != NULL) {
-        strncpy(hostname, getenv("HOSTNAME"), sizeof(hostname));
-        hostname[sizeof(hostname)-1] = '\0';
-        ret = 0;
-    }
-
-#ifndef _WIN32
-    if (ret < 0)
-        ret = gethostname(hostname, sizeof(hostname));
-#endif
-    if (ret < 0)
-        strcpy(hostname, "unknown");
-
-    ret = -1;
-
-    if (getenv("LOGNAME") != NULL) {
-        strncpy(username, getenv("LOGNAME"), sizeof(username));
-        username[sizeof(username)-1] = '\0';
-        ret = 0;
-    }
-
+    std::string username;
+    if (getenv("LOGNAME")) username = getenv("LOGNAME");
 #if !defined _WIN32 && !defined ADB_HOST_ON_TARGET
-    if (ret < 0)
-        ret = getlogin_r(username, sizeof(username));
+    if (username.empty() && getlogin()) username = getlogin();
 #endif
-    if (ret < 0)
-        strcpy(username, "unknown");
+    if (username.empty()) hostname = "unknown";
 
-    ret = snprintf(buf, len, " %s@%s", username, hostname);
-    if (ret >= (signed)len)
-        buf[len - 1] = '\0';
+    return " " + username + "@" + hostname;
 }
 
-static int write_public_keyfile(RSA *private_key, const char *private_key_path)
-{
-    RSAPublicKey pkey;
-    FILE *outfile = NULL;
-    char path[PATH_MAX], info[MAX_PAYLOAD_V1];
-    uint8_t* encoded = nullptr;
-    size_t encoded_length;
-    int ret = 0;
+static bool write_public_keyfile(RSA* private_key, const std::string& private_key_path) {
+    LOG(INFO) << "write_public_keyfile...";
 
-    if (snprintf(path, sizeof(path), "%s.pub", private_key_path) >=
-        (int)sizeof(path)) {
-        D("Path too long while writing public key");
-        return 0;
+    uint8_t binary_key_data[ANDROID_PUBKEY_ENCODED_SIZE];
+    if (!android_pubkey_encode(private_key, binary_key_data, sizeof(binary_key_data))) {
+        LOG(ERROR) << "Failed to convert to public key";
+        return false;
     }
 
-    if (!RSA_to_RSAPublicKey(private_key, &pkey)) {
-        D("Failed to convert to publickey");
-        return 0;
+    size_t base64_key_length;
+    if (!EVP_EncodedLength(&base64_key_length, sizeof(binary_key_data))) {
+        LOG(ERROR) << "Public key too large to base64 encode";
+        return false;
     }
 
-    outfile = fopen(path, "w");
-    if (!outfile) {
-        D("Failed to open '%s'", path);
-        return 0;
+    std::string content;
+    content.resize(base64_key_length);
+    base64_key_length = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(&content[0]), binary_key_data,
+                                        sizeof(binary_key_data));
+
+    content += get_user_info();
+
+    std::string path(private_key_path + ".pub");
+    if (!android::base::WriteStringToFile(content, path)) {
+        PLOG(ERROR) << "Failed to write public key to '" << path << "'";
+        return false;
     }
 
-    D("Writing public key to '%s'", path);
-
-#if defined(OPENSSL_IS_BORINGSSL)
-    if (!EVP_EncodedLength(&encoded_length, sizeof(pkey))) {
-        D("Public key too large to base64 encode");
-        goto out;
-    }
-#else
-    /* While we switch from OpenSSL to BoringSSL we have to implement
-     * |EVP_EncodedLength| here. */
-    encoded_length = 1 + ((sizeof(pkey) + 2) / 3 * 4);
-#endif
-
-    encoded = new uint8_t[encoded_length];
-    if (encoded == nullptr) {
-        D("Allocation failure");
-        goto out;
-    }
-
-    encoded_length = EVP_EncodeBlock(encoded, (uint8_t*) &pkey, sizeof(pkey));
-    get_user_info(info, sizeof(info));
-
-    if (fwrite(encoded, encoded_length, 1, outfile) != 1 ||
-        fwrite(info, strlen(info), 1, outfile) != 1) {
-        D("Write error while writing public key");
-        goto out;
-    }
-
-    ret = 1;
-
- out:
-    if (outfile != NULL) {
-        fclose(outfile);
-    }
-    delete[] encoded;
-    return ret;
+    return true;
 }
 
-static int generate_key(const char *file)
-{
-    EVP_PKEY* pkey = EVP_PKEY_new();
-    BIGNUM* exponent = BN_new();
-    RSA* rsa = RSA_new();
+static int generate_key(const std::string& file) {
+    LOG(INFO) << "generate_key(" << file << ")...";
+
     mode_t old_mask;
     FILE *f = NULL;
     int ret = 0;
 
-    D("generate_key '%s'", file);
-
+    EVP_PKEY* pkey = EVP_PKEY_new();
+    BIGNUM* exponent = BN_new();
+    RSA* rsa = RSA_new();
     if (!pkey || !exponent || !rsa) {
-        D("Failed to allocate key");
+        LOG(ERROR) << "Failed to allocate key";
         goto out;
     }
 
@@ -230,9 +125,9 @@
 
     old_mask = umask(077);
 
-    f = fopen(file, "w");
+    f = fopen(file.c_str(), "w");
     if (!f) {
-        D("Failed to open '%s'", file);
+        PLOG(ERROR) << "Failed to open " << file;
         umask(old_mask);
         goto out;
     }
@@ -252,110 +147,166 @@
     ret = 1;
 
 out:
-    if (f)
-        fclose(f);
+    if (f) fclose(f);
     EVP_PKEY_free(pkey);
     RSA_free(rsa);
     BN_free(exponent);
     return ret;
 }
 
-static int read_key(const char *file, struct listnode *list)
-{
-    D("read_key '%s'", file);
+static std::string hash_key(RSA* key) {
+    unsigned char* pubkey = nullptr;
+    int len = i2d_RSA_PUBKEY(key, &pubkey);
+    if (len < 0) {
+        LOG(ERROR) << "failed to encode RSA public key";
+        return std::string();
+    }
 
-    FILE* fp = fopen(file, "r");
+    std::string result;
+    result.resize(SHA256_DIGEST_LENGTH);
+    SHA256(pubkey, len, reinterpret_cast<unsigned char*>(&result[0]));
+    OPENSSL_free(pubkey);
+    return result;
+}
+
+static bool read_key_file(const std::string& file) {
+    LOG(INFO) << "read_key_file '" << file << "'...";
+
+    std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(file.c_str(), "r"), fclose);
     if (!fp) {
-        D("Failed to open '%s': %s", file, strerror(errno));
-        return 0;
+        PLOG(ERROR) << "Failed to open '" << file << "'";
+        return false;
     }
 
-    adb_private_key* key = new adb_private_key;
-    key->rsa = RSA_new();
-
-    if (!PEM_read_RSAPrivateKey(fp, &key->rsa, NULL, NULL)) {
-        D("Failed to read key");
-        fclose(fp);
-        RSA_free(key->rsa);
-        delete key;
-        return 0;
+    RSA* key = RSA_new();
+    if (!PEM_read_RSAPrivateKey(fp.get(), &key, nullptr, nullptr)) {
+        LOG(ERROR) << "Failed to read key";
+        RSA_free(key);
+        return false;
     }
 
-    fclose(fp);
-    list_add_tail(list, &key->node);
-    return 1;
+    std::lock_guard<std::mutex> lock(g_keys_mutex);
+    std::string fingerprint = hash_key(key);
+    if (g_keys.find(fingerprint) != g_keys.end()) {
+        LOG(INFO) << "ignoring already-loaded key: " << file;
+        RSA_free(key);
+    } else {
+        g_keys[fingerprint] = std::shared_ptr<RSA>(key, RSA_free);
+    }
+
+    return true;
 }
 
-static int get_user_keyfilepath(char *filename, size_t len)
-{
-    const std::string home = adb_get_homedir_path(true);
-    D("home '%s'", home.c_str());
+static bool read_keys(const std::string& path, bool allow_dir = true) {
+    LOG(INFO) << "read_keys '" << path << "'...";
 
-    const std::string android_dir =
-            android::base::StringPrintf("%s%c%s", home.c_str(),
-                                        OS_PATH_SEPARATOR, ANDROID_PATH);
+    struct stat st;
+    if (stat(path.c_str(), &st) != 0) {
+        PLOG(ERROR) << "failed to stat '" << path << "'";
+        return false;
+    }
 
-    struct stat buf;
-    if (stat(android_dir.c_str(), &buf)) {
-        if (adb_mkdir(android_dir.c_str(), 0750) < 0) {
-            D("Cannot mkdir '%s'", android_dir.c_str());
-            return -1;
+    if (S_ISREG(st.st_mode)) {
+        if (!android::base::EndsWith(path, ".adb_key")) {
+            LOG(INFO) << "skipping non-adb_key '" << path << "'";
+            return false;
         }
+
+        return read_key_file(path);
+    } else if (S_ISDIR(st.st_mode)) {
+        if (!allow_dir) {
+            // inotify isn't recursive. It would break expectations to load keys in nested
+            // directories but not monitor them for new keys.
+            LOG(WARNING) << "refusing to recurse into directory '" << path << "'";
+            return false;
+        }
+
+        std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
+        if (!dir) {
+            PLOG(ERROR) << "failed to open directory '" << path << "'";
+            return false;
+        }
+
+        bool result = false;
+        while (struct dirent* dent = readdir(dir.get())) {
+            std::string name = dent->d_name;
+
+            // We can't use dent->d_type here because it's not available on Windows.
+            if (name == "." || name == "..") {
+                continue;
+            }
+
+            result |= read_keys((path + OS_PATH_SEPARATOR + name).c_str(), false);
+        }
+        return result;
     }
 
-    return snprintf(filename, len, "%s%c%s",
-                    android_dir.c_str(), OS_PATH_SEPARATOR, ADB_KEY_FILE);
+    LOG(ERROR) << "unexpected type for '" << path << "': 0x" << std::hex << st.st_mode;
+    return false;
 }
 
-static int get_user_key(struct listnode *list)
-{
-    struct stat buf;
-    char path[PATH_MAX];
-    int ret;
+static std::string get_user_key_path() {
+    return adb_get_android_dir_path() + OS_PATH_SEPARATOR + "adbkey";
+}
 
-    ret = get_user_keyfilepath(path, sizeof(path));
-    if (ret < 0 || ret >= (signed)sizeof(path)) {
-        D("Error getting user key filename");
-        return 0;
+static bool get_user_key() {
+    std::string path = get_user_key_path();
+    if (path.empty()) {
+        PLOG(ERROR) << "Error getting user key filename";
+        return false;
     }
 
-    D("user key '%s'", path);
-
-    if (stat(path, &buf) == -1) {
+    struct stat buf;
+    if (stat(path.c_str(), &buf) == -1) {
+        LOG(INFO) << "User key '" << path << "' does not exist...";
         if (!generate_key(path)) {
-            D("Failed to generate new key");
-            return 0;
+            LOG(ERROR) << "Failed to generate new key";
+            return false;
         }
     }
 
-    return read_key(path, list);
+    return read_key_file(path);
 }
 
-static void get_vendor_keys(struct listnode* key_list) {
+static std::set<std::string> get_vendor_keys() {
     const char* adb_keys_path = getenv("ADB_VENDOR_KEYS");
     if (adb_keys_path == nullptr) {
-        return;
+        return std::set<std::string>();
     }
 
+    std::set<std::string> result;
     for (const auto& path : android::base::Split(adb_keys_path, ENV_PATH_SEPARATOR_STR)) {
-        if (!read_key(path.c_str(), key_list)) {
-            D("Failed to read '%s'", path.c_str());
-        }
+        result.emplace(path);
     }
+    return result;
 }
 
-int adb_auth_sign(void *node, const unsigned char* token, size_t token_size,
-                  unsigned char* sig)
-{
-    unsigned int len;
-    struct adb_private_key *key = node_to_item(node, struct adb_private_key, node);
+std::deque<std::shared_ptr<RSA>> adb_auth_get_private_keys() {
+    std::deque<std::shared_ptr<RSA>> result;
 
+    // Copy all the currently known keys.
+    std::lock_guard<std::mutex> lock(g_keys_mutex);
+    for (const auto& it : g_keys) {
+        result.push_back(it.second);
+    }
+
+    // Add a sentinel to the list. Our caller uses this to mean "out of private keys,
+    // but try using the public key" (the empty deque could otherwise mean this _or_
+    // that this function hasn't been called yet to request the keys).
+    result.push_back(nullptr);
+
+    return result;
+}
+
+static int adb_auth_sign(RSA* key, const char* token, size_t token_size, char* sig) {
     if (token_size != TOKEN_SIZE) {
         D("Unexpected token size %zd", token_size);
         return 0;
     }
 
-    if (!RSA_sign(NID_sha1, token, token_size, sig, &len, key->rsa)) {
+    unsigned int len;
+    if (!RSA_sign(NID_sha1, reinterpret_cast<const uint8_t*>(token), token_size,
+                  reinterpret_cast<uint8_t*>(sig), &len, key)) {
         return 0;
     }
 
@@ -363,80 +314,161 @@
     return (int)len;
 }
 
-void *adb_auth_nextkey(void *current)
-{
-    struct listnode *item;
-
-    if (list_empty(&key_list))
-        return NULL;
-
-    if (!current)
-        return list_head(&key_list);
-
-    list_for_each(item, &key_list) {
-        if (item == current) {
-            /* current is the last item, we tried all the keys */
-            if (item->next == &key_list)
-                return NULL;
-            return item->next;
-        }
+std::string adb_auth_get_userkey() {
+    std::string path = get_user_key_path();
+    if (path.empty()) {
+        PLOG(ERROR) << "Error getting user key filename";
+        return "";
     }
+    path += ".pub";
 
-    return NULL;
-}
-
-int adb_auth_get_userkey(unsigned char *data, size_t len)
-{
-    char path[PATH_MAX];
-    int ret = get_user_keyfilepath(path, sizeof(path) - 4);
-    if (ret < 0 || ret >= (signed)(sizeof(path) - 4)) {
-        D("Error getting user key filename");
-        return 0;
+    std::string content;
+    if (!android::base::ReadFileToString(path, &content)) {
+        PLOG(ERROR) << "Can't load '" << path << "'";
+        return "";
     }
-    strcat(path, ".pub");
-
-    // TODO(danalbert): ReadFileToString
-    // Note that on Windows, load_file() does not do CR/LF translation, but
-    // ReadFileToString() uses the C Runtime which uses CR/LF translation by
-    // default (by is overridable with _setmode()).
-    unsigned size;
-    char* file_data = reinterpret_cast<char*>(load_file(path, &size));
-    if (file_data == nullptr) {
-        D("Can't load '%s'", path);
-        return 0;
-    }
-
-    if (len < (size_t)(size + 1)) {
-        D("%s: Content too large ret=%d", path, size);
-        free(file_data);
-        return 0;
-    }
-
-    memcpy(data, file_data, size);
-    free(file_data);
-    file_data = nullptr;
-    data[size] = '\0';
-
-    return size + 1;
+    return content;
 }
 
 int adb_auth_keygen(const char* filename) {
     return (generate_key(filename) == 0);
 }
 
-void adb_auth_init(void)
-{
-    int ret;
-
-    D("adb_auth_init");
-
-    list_init(&key_list);
-
-    ret = get_user_key(&key_list);
-    if (!ret) {
-        D("Failed to get user key");
+#if defined(__linux__)
+static void adb_auth_inotify_update(int fd, unsigned fd_event, void*) {
+    LOG(INFO) << "adb_auth_inotify_update called";
+    if (!(fd_event & FDE_READ)) {
         return;
     }
 
-    get_vendor_keys(&key_list);
+    char buf[sizeof(struct inotify_event) + NAME_MAX + 1];
+    while (true) {
+        ssize_t rc = TEMP_FAILURE_RETRY(unix_read(fd, buf, sizeof(buf)));
+        if (rc == -1) {
+            if (errno == EAGAIN) {
+                LOG(INFO) << "done reading inotify fd";
+                break;
+            }
+            PLOG(FATAL) << "read of inotify event failed";
+        }
+
+        // The read potentially returned multiple events.
+        char* start = buf;
+        char* end = buf + rc;
+
+        while (start < end) {
+            inotify_event* event = reinterpret_cast<inotify_event*>(start);
+            auto root_it = g_monitored_paths.find(event->wd);
+            if (root_it == g_monitored_paths.end()) {
+                LOG(FATAL) << "observed inotify event for unmonitored path, wd = " << event->wd;
+            }
+
+            std::string path = root_it->second;
+            if (event->len > 0) {
+                path += '/';
+                path += event->name;
+            }
+
+            if (event->mask & (IN_CREATE | IN_MOVED_TO)) {
+                if (event->mask & IN_ISDIR) {
+                    LOG(INFO) << "ignoring new directory at '" << path << "'";
+                } else {
+                    LOG(INFO) << "observed new file at '" << path << "'";
+                    read_keys(path, false);
+                }
+            } else {
+                LOG(WARNING) << "unmonitored event for " << path << ": 0x" << std::hex
+                             << event->mask;
+            }
+
+            start += sizeof(struct inotify_event) + event->len;
+        }
+    }
+}
+
+static void adb_auth_inotify_init(const std::set<std::string>& paths) {
+    LOG(INFO) << "adb_auth_inotify_init...";
+    int infd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK);
+    for (const std::string& path : paths) {
+        int wd = inotify_add_watch(infd, path.c_str(), IN_CREATE | IN_MOVED_TO);
+        if (wd < 0) {
+            PLOG(ERROR) << "failed to inotify_add_watch on path '" << path;
+            continue;
+        }
+
+        g_monitored_paths[wd] = path;
+        LOG(INFO) << "watch descriptor " << wd << " registered for " << path;
+    }
+
+    fdevent* event = fdevent_create(infd, adb_auth_inotify_update, nullptr);
+    fdevent_add(event, FDE_READ);
+}
+#endif
+
+void adb_auth_init() {
+    LOG(INFO) << "adb_auth_init...";
+
+    if (!get_user_key()) {
+        LOG(ERROR) << "Failed to get user key";
+        return;
+    }
+
+    const auto& key_paths = get_vendor_keys();
+
+#if defined(__linux__)
+    adb_auth_inotify_init(key_paths);
+#endif
+
+    for (const std::string& path : key_paths) {
+        read_keys(path.c_str());
+    }
+}
+
+static void send_auth_publickey(atransport* t) {
+    LOG(INFO) << "Calling send_auth_publickey";
+
+    std::string key = adb_auth_get_userkey();
+    if (key.empty()) {
+        D("Failed to get user public key");
+        return;
+    }
+
+    if (key.size() >= MAX_PAYLOAD_V1) {
+        D("User public key too large (%zu B)", key.size());
+        return;
+    }
+
+    apacket* p = get_apacket();
+    memcpy(p->data, key.c_str(), key.size() + 1);
+
+    p->msg.command = A_AUTH;
+    p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
+
+    // adbd expects a null-terminated string.
+    p->msg.data_length = key.size() + 1;
+    send_packet(p, t);
+}
+
+void send_auth_response(const char* token, size_t token_size, atransport* t) {
+    std::shared_ptr<RSA> key = t->NextKey();
+    if (key == nullptr) {
+        // No more private keys to try, send the public key.
+        send_auth_publickey(t);
+        return;
+    }
+
+    LOG(INFO) << "Calling send_auth_response";
+    apacket* p = get_apacket();
+
+    int ret = adb_auth_sign(key.get(), token, token_size, p->data);
+    if (!ret) {
+        D("Error signing the token");
+        put_apacket(p);
+        return;
+    }
+
+    p->msg.command = A_AUTH;
+    p->msg.arg0 = ADB_AUTH_SIGNATURE;
+    p->msg.data_length = ret;
+    send_packet(p, t);
 }
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index a27dd47..0b1ba32 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -29,6 +29,7 @@
 #include <sys/types.h>
 
 #include <string>
+#include <thread>
 #include <vector>
 
 #include <android-base/stringprintf.h>
@@ -37,12 +38,13 @@
 
 #include "adb_io.h"
 #include "adb_utils.h"
+#include "socket_spec.h"
+#include "sysdeps/chrono.h"
 
 static TransportType __adb_transport = kTransportAny;
 static const char* __adb_serial = NULL;
 
-static int __adb_server_port = DEFAULT_ADB_PORT;
-static const char* __adb_server_name = NULL;
+static const char* __adb_server_socket_spec;
 
 void adb_set_transport(TransportType type, const char* serial)
 {
@@ -59,14 +61,11 @@
     }
 }
 
-void adb_set_tcp_specifics(int server_port)
-{
-    __adb_server_port = server_port;
-}
-
-void adb_set_tcp_name(const char* hostname)
-{
-    __adb_server_name = hostname;
+void adb_set_socket_spec(const char* socket_spec) {
+    if (__adb_server_socket_spec) {
+        LOG(FATAL) << "attempted to reinitialize adb_server_socket_spec " << socket_spec << " (was " << __adb_server_socket_spec << ")";
+    }
+    __adb_server_socket_spec = socket_spec;
 }
 
 static int switch_socket_transport(int fd, std::string* error) {
@@ -139,23 +138,12 @@
         return -1;
     }
 
-    int fd;
     std::string reason;
-    if (__adb_server_name) {
-        fd = network_connect(__adb_server_name, __adb_server_port, SOCK_STREAM, 0, &reason);
-        if (fd == -1) {
-            *error = android::base::StringPrintf("can't connect to %s:%d: %s",
-                                                 __adb_server_name, __adb_server_port,
-                                                 reason.c_str());
-            return -2;
-        }
-    } else {
-        fd = network_loopback_client(__adb_server_port, SOCK_STREAM, &reason);
-        if (fd == -1) {
-            *error = android::base::StringPrintf("cannot connect to daemon: %s",
-                                                 reason.c_str());
-            return -2;
-        }
+    int fd = socket_spec_connect(__adb_server_socket_spec, &reason);
+    if (fd < 0) {
+        *error = android::base::StringPrintf("cannot connect to daemon at %s: %s",
+                                             __adb_server_socket_spec, reason.c_str());
+        return -2;
     }
 
     if ((memcmp(&service[0],"host",4) != 0 || service == "host:reconnect") &&
@@ -185,15 +173,14 @@
     int fd = _adb_connect("host:version", error);
 
     D("adb_connect: service %s", service.c_str());
-    if (fd == -2 && __adb_server_name) {
+    if (fd == -2 && !is_local_socket_spec(__adb_server_socket_spec)) {
         fprintf(stderr,"** Cannot start server on remote host\n");
         // error is the original network connection error
         return fd;
     } else if (fd == -2) {
-        fprintf(stdout,"* daemon not running. starting it now on port %d *\n",
-                __adb_server_port);
+        fprintf(stdout, "* daemon not running. starting it now at %s *\n", __adb_server_socket_spec);
     start_server:
-        if (launch_server(__adb_server_port)) {
+        if (launch_server(__adb_server_socket_spec)) {
             fprintf(stderr,"* failed to start daemon *\n");
             // launch_server() has already printed detailed error info, so just
             // return a generic error string about the overall adb_connect()
@@ -203,8 +190,8 @@
         } else {
             fprintf(stdout,"* daemon started successfully *\n");
         }
-        /* give the server some time to start properly and detect devices */
-        adb_sleep_ms(3000);
+        // Give the server some time to start properly and detect devices.
+        std::this_thread::sleep_for(3s);
         // fall through to _adb_connect
     } else {
         // If a server is already running, check its version matches.
@@ -249,7 +236,7 @@
             }
 
             /* XXX can we better detect its death? */
-            adb_sleep_ms(2000);
+            std::this_thread::sleep_for(2s);
             goto start_server;
         }
     }
diff --git a/adb/adb_client.h b/adb/adb_client.h
index 9f9eb1f..d35d705 100644
--- a/adb/adb_client.h
+++ b/adb/adb_client.h
@@ -43,11 +43,9 @@
 // Get the preferred transport to connect to.
 void adb_get_transport(TransportType* _Nullable type, const char* _Nullable* _Nullable serial);
 
-// Set TCP specifics of the transport to use.
-void adb_set_tcp_specifics(int server_port);
-
-// Set TCP Hostname of the transport to use.
-void adb_set_tcp_name(const char* _Nullable hostname);
+// Set the socket specification for the adb server.
+// This function can only be called once, and the argument must live to the end of the process.
+void adb_set_socket_spec(const char* _Nonnull socket_spec);
 
 // Send commands to the current emulator instance. Will fail if there is not
 // exactly one emulator connected (or if you use -s <serial> with a <serial>
diff --git a/adb/adb_io.cpp b/adb/adb_io.cpp
index ae16834..ca8729e 100644
--- a/adb/adb_io.cpp
+++ b/adb/adb_io.cpp
@@ -20,6 +20,8 @@
 
 #include <unistd.h>
 
+#include <thread>
+
 #include <android-base/stringprintf.h>
 
 #include "adb.h"
@@ -104,7 +106,7 @@
         if (r == -1) {
             D("writex: fd=%d error %d: %s", fd, errno, strerror(errno));
             if (errno == EAGAIN) {
-                adb_sleep_ms(1); // just yield some cpu time
+                std::this_thread::yield();
                 continue;
             } else if (errno == EPIPE) {
                 D("writex: fd=%d disconnected", fd);
diff --git a/adb/adb_io_test.cpp b/adb/adb_io_test.cpp
index 21a82e8..611b239 100644
--- a/adb/adb_io_test.cpp
+++ b/adb/adb_io_test.cpp
@@ -37,7 +37,13 @@
 // fds far from the range that open() returns. But all of that might defeat the
 // purpose of the tests.
 
-TEST(io, ReadFdExactly_whole) {
+#if defined(_WIN32)
+#define POSIX_TEST(x,y) TEST(DISABLED_ ## x,y)
+#else
+#define POSIX_TEST TEST
+#endif
+
+POSIX_TEST(io, ReadFdExactly_whole) {
   const char expected[] = "Foobar";
   TemporaryFile tf;
   ASSERT_NE(-1, tf.fd);
@@ -51,7 +57,7 @@
   EXPECT_STREQ(expected, buf);
 }
 
-TEST(io, ReadFdExactly_eof) {
+POSIX_TEST(io, ReadFdExactly_eof) {
   const char expected[] = "Foobar";
   TemporaryFile tf;
   ASSERT_NE(-1, tf.fd);
@@ -65,7 +71,7 @@
   EXPECT_EQ(0, errno) << strerror(errno);
 }
 
-TEST(io, ReadFdExactly_partial) {
+POSIX_TEST(io, ReadFdExactly_partial) {
   const char input[] = "Foobar";
   TemporaryFile tf;
   ASSERT_NE(-1, tf.fd);
@@ -82,7 +88,7 @@
   EXPECT_STREQ(expected.c_str(), buf);
 }
 
-TEST(io, WriteFdExactly_whole) {
+POSIX_TEST(io, WriteFdExactly_whole) {
   const char expected[] = "Foobar";
   TemporaryFile tf;
   ASSERT_NE(-1, tf.fd);
@@ -97,7 +103,7 @@
   EXPECT_STREQ(expected, s.c_str());
 }
 
-TEST(io, WriteFdExactly_partial) {
+POSIX_TEST(io, WriteFdExactly_partial) {
   const char buf[] = "Foobar";
   TemporaryFile tf;
   ASSERT_NE(-1, tf.fd);
@@ -114,7 +120,7 @@
   EXPECT_EQ(expected, s);
 }
 
-TEST(io, WriteFdExactly_ENOSPC) {
+POSIX_TEST(io, WriteFdExactly_ENOSPC) {
     int fd = open("/dev/full", O_WRONLY);
     ASSERT_NE(-1, fd);
 
@@ -123,7 +129,7 @@
     ASSERT_EQ(ENOSPC, errno);
 }
 
-TEST(io, WriteFdExactly_string) {
+POSIX_TEST(io, WriteFdExactly_string) {
   const char str[] = "Foobar";
   TemporaryFile tf;
   ASSERT_NE(-1, tf.fd);
@@ -137,7 +143,7 @@
   EXPECT_STREQ(str, s.c_str());
 }
 
-TEST(io, WriteFdFmt) {
+POSIX_TEST(io, WriteFdFmt) {
     TemporaryFile tf;
     ASSERT_NE(-1, tf.fd);
 
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index e8c2338..18b1492 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -20,24 +20,56 @@
 #include <stdlib.h>
 
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <cutils/sockets.h>
 
+#include "socket_spec.h"
 #include "sysdeps.h"
 #include "transport.h"
 
-int gListenAll = 0; /* Not static because it is used in commandline.c. */
+// A listener is an entity which binds to a local port and, upon receiving a connection on that
+// port, creates an asocket to connect the new local connection to a specific remote service.
+//
+// TODO: some listeners read from the new connection to determine what exact service to connect to
+// on the far side.
+class alistener {
+  public:
+    alistener(const std::string& _local_name, const std::string& _connect_to);
+    ~alistener();
 
-static alistener listener_list = {
-    .next = &listener_list,
-    .prev = &listener_list,
+    fdevent fde;
+    int fd = -1;
+
+    std::string local_name;
+    std::string connect_to;
+    atransport* transport = nullptr;
+    adisconnect disconnect;
+
+  private:
+    DISALLOW_COPY_AND_ASSIGN(alistener);
 };
 
+alistener::alistener(const std::string& _local_name, const std::string& _connect_to)
+    : local_name(_local_name), connect_to(_connect_to) {
+}
+
+alistener::~alistener() {
+    // Closes the corresponding fd.
+    fdevent_remove(&fde);
+
+    if (transport) {
+        transport->RemoveDisconnect(&disconnect);
+    }
+}
+
+// listener_list retains ownership of all created alistener objects. Removing an alistener from
+// this list will cause it to be deleted.
+typedef std::list<std::unique_ptr<alistener>> ListenerList;
+static ListenerList& listener_list = *new ListenerList();
+
 static void ss_listener_event_func(int _fd, unsigned ev, void *_l) {
     if (ev & FDE_READ) {
-        sockaddr_storage ss;
-        sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);
-        socklen_t alen = sizeof(ss);
-        int fd = adb_socket_accept(_fd, addrp, &alen);
+        int fd = adb_socket_accept(_fd, nullptr, nullptr);
         if (fd < 0) return;
 
         int rcv_buf_size = CHUNK_SIZE;
@@ -59,13 +91,7 @@
     asocket *s;
 
     if (ev & FDE_READ) {
-        sockaddr_storage ss;
-        sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);
-        socklen_t alen;
-        int fd;
-
-        alen = sizeof(ss);
-        fd = adb_socket_accept(_fd, addrp, &alen);
+        int fd = adb_socket_accept(_fd, nullptr, nullptr);
         if (fd < 0) {
             return;
         }
@@ -73,7 +99,7 @@
         s = create_local_socket(fd);
         if (s) {
             s->transport = listener->transport;
-            connect_to_remote(s, listener->connect_to);
+            connect_to_remote(s, listener->connect_to.c_str());
             return;
         }
 
@@ -81,66 +107,21 @@
     }
 }
 
-static void free_listener(alistener*  l)
-{
-    if (l->next) {
-        l->next->prev = l->prev;
-        l->prev->next = l->next;
-        l->next = l->prev = l;
-    }
-
-    // closes the corresponding fd
-    fdevent_remove(&l->fde);
-
-    if (l->local_name)
-        free((char*)l->local_name);
-
-    if (l->connect_to)
-        free((char*)l->connect_to);
-
-    if (l->transport) {
-        l->transport->RemoveDisconnect(&l->disconnect);
-    }
-    free(l);
-}
-
+// Called as a transport disconnect function. |arg| is the raw alistener*.
 static void listener_disconnect(void* arg, atransport*) {
-    alistener* listener = reinterpret_cast<alistener*>(arg);
-    listener->transport = nullptr;
-    free_listener(listener);
-}
-
-static int local_name_to_fd(const char* name, std::string* error) {
-    if (!strncmp("tcp:", name, 4)) {
-        int port = atoi(name + 4);
-        if (gListenAll > 0) {
-            return network_inaddr_any_server(port, SOCK_STREAM, error);
-        } else {
-            return network_loopback_server(port, SOCK_STREAM, error);
+    for (auto iter = listener_list.begin(); iter != listener_list.end(); ++iter) {
+        if (iter->get() == arg) {
+            (*iter)->transport = nullptr;
+            listener_list.erase(iter);
+            return;
         }
     }
-#if !defined(_WIN32)  // No Unix-domain sockets on Windows.
-    // It's nonsensical to support the "reserved" space on the adb host side
-    if (!strncmp(name, "local:", 6)) {
-        return network_local_server(name + 6,
-                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM, error);
-    } else if (!strncmp(name, "localabstract:", 14)) {
-        return network_local_server(name + 14,
-                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM, error);
-    } else if (!strncmp(name, "localfilesystem:", 16)) {
-        return network_local_server(name + 16,
-                ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM, error);
-    }
-
-#endif
-    *error = android::base::StringPrintf("unknown local portname '%s'", name);
-    return -1;
 }
 
 // Write the list of current listeners (network redirections) into a string.
 std::string format_listeners() {
     std::string result;
-    for (alistener* l = listener_list.next; l != &listener_list; l = l->next) {
+    for (auto& l : listener_list) {
         // Ignore special listeners like those for *smartsocket*
         if (l->connect_to[0] == '*') {
             continue;
@@ -149,65 +130,51 @@
         // Entries from "adb reverse" have no serial.
         android::base::StringAppendF(&result, "%s %s %s\n",
                                      l->transport->serial ? l->transport->serial : "(reverse)",
-                                     l->local_name, l->connect_to);
+                                     l->local_name.c_str(), l->connect_to.c_str());
     }
     return result;
 }
 
-InstallStatus remove_listener(const char *local_name, atransport* transport) {
-    alistener *l;
-
-    for (l = listener_list.next; l != &listener_list; l = l->next) {
-        if (!strcmp(local_name, l->local_name)) {
-            free_listener(l);
+InstallStatus remove_listener(const char* local_name, atransport* transport) {
+    for (auto iter = listener_list.begin(); iter != listener_list.end(); ++iter) {
+        if (local_name == (*iter)->local_name) {
+            listener_list.erase(iter);
             return INSTALL_STATUS_OK;
         }
     }
     return INSTALL_STATUS_LISTENER_NOT_FOUND;
 }
 
-void remove_all_listeners(void)
-{
-    alistener *l, *l_next;
-    for (l = listener_list.next; l != &listener_list; l = l_next) {
-        l_next = l->next;
+void remove_all_listeners() {
+    auto iter = listener_list.begin();
+    while (iter != listener_list.end()) {
         // Never remove smart sockets.
-        if (l->connect_to[0] == '*')
-            continue;
-        free_listener(l);
+        if ((*iter)->connect_to[0] == '*') {
+            ++iter;
+        } else {
+            iter = listener_list.erase(iter);
+        }
     }
 }
 
-InstallStatus install_listener(const std::string& local_name,
-                                  const char *connect_to,
-                                  atransport* transport,
-                                  int no_rebind,
-                                  std::string* error)
-{
-    for (alistener* l = listener_list.next; l != &listener_list; l = l->next) {
+InstallStatus install_listener(const std::string& local_name, const char* connect_to,
+                               atransport* transport, int no_rebind, int* resolved_tcp_port,
+                               std::string* error) {
+    for (auto& l : listener_list) {
         if (local_name == l->local_name) {
-            char* cto;
-
-            /* can't repurpose a smartsocket */
+            // Can't repurpose a smartsocket.
             if(l->connect_to[0] == '*') {
                 *error = "cannot repurpose smartsocket";
                 return INSTALL_STATUS_INTERNAL_ERROR;
             }
 
-            /* can't repurpose a listener if 'no_rebind' is true */
+            // Can't repurpose a listener if 'no_rebind' is true.
             if (no_rebind) {
                 *error = "cannot rebind";
                 return INSTALL_STATUS_CANNOT_REBIND;
             }
 
-            cto = strdup(connect_to);
-            if(cto == 0) {
-                *error = "cannot duplicate string";
-                return INSTALL_STATUS_INTERNAL_ERROR;
-            }
-
-            free((void*) l->connect_to);
-            l->connect_to = cto;
+            l->connect_to = connect_to;
             if (l->transport != transport) {
                 l->transport->RemoveDisconnect(&l->disconnect);
                 l->transport = transport;
@@ -217,54 +184,38 @@
         }
     }
 
-    alistener* listener = reinterpret_cast<alistener*>(
-        calloc(1, sizeof(alistener)));
-    if (listener == nullptr) {
-        goto nomem;
-    }
+    std::unique_ptr<alistener> listener(new alistener(local_name, connect_to));
 
-    listener->local_name = strdup(local_name.c_str());
-    if (listener->local_name == nullptr) {
-        goto nomem;
-    }
-
-    listener->connect_to = strdup(connect_to);
-    if (listener->connect_to == nullptr) {
-        goto nomem;
-    }
-
-    listener->fd = local_name_to_fd(listener->local_name, error);
+    int resolved = 0;
+    listener->fd = socket_spec_listen(listener->local_name, error, &resolved);
     if (listener->fd < 0) {
-        free(listener->local_name);
-        free(listener->connect_to);
-        free(listener);
         return INSTALL_STATUS_CANNOT_BIND;
     }
 
+    // If the caller requested port 0, update the listener name with the resolved port.
+    if (resolved != 0) {
+        listener->local_name = android::base::StringPrintf("tcp:%d", resolved);
+        if (resolved_tcp_port) {
+            *resolved_tcp_port = resolved;
+        }
+    }
+
     close_on_exec(listener->fd);
-    if (!strcmp(listener->connect_to, "*smartsocket*")) {
-        fdevent_install(&listener->fde, listener->fd, ss_listener_event_func,
-                        listener);
+    if (listener->connect_to == "*smartsocket*") {
+        fdevent_install(&listener->fde, listener->fd, ss_listener_event_func, listener.get());
     } else {
-        fdevent_install(&listener->fde, listener->fd, listener_event_func,
-                        listener);
+        fdevent_install(&listener->fde, listener->fd, listener_event_func, listener.get());
     }
     fdevent_set(&listener->fde, FDE_READ);
 
-    listener->next = &listener_list;
-    listener->prev = listener_list.prev;
-    listener->next->prev = listener;
-    listener->prev->next = listener;
     listener->transport = transport;
 
     if (transport) {
-        listener->disconnect.opaque = listener;
+        listener->disconnect.opaque = listener.get();
         listener->disconnect.func   = listener_disconnect;
         transport->AddDisconnect(&listener->disconnect);
     }
-    return INSTALL_STATUS_OK;
 
-nomem:
-    fatal("cannot allocate listener");
-    return INSTALL_STATUS_INTERNAL_ERROR;
+    listener_list.push_back(std::move(listener));
+    return INSTALL_STATUS_OK;
 }
diff --git a/adb/adb_listeners.h b/adb/adb_listeners.h
index fa98eed..8eba00a 100644
--- a/adb/adb_listeners.h
+++ b/adb/adb_listeners.h
@@ -21,6 +21,8 @@
 
 #include <string>
 
+#include <android-base/macros.h>
+
 // error/status codes for install_listener.
 enum InstallStatus {
   INSTALL_STATUS_OK = 0,
@@ -30,10 +32,8 @@
   INSTALL_STATUS_LISTENER_NOT_FOUND = -4,
 };
 
-InstallStatus install_listener(const std::string& local_name,
-                               const char* connect_to,
-                               atransport* transport,
-                               int no_rebind,
+InstallStatus install_listener(const std::string& local_name, const char* connect_to,
+                               atransport* transport, int no_rebind, int* resolved_tcp_port,
                                std::string* error);
 
 std::string format_listeners();
diff --git a/adb/adb_listeners_test.cpp b/adb/adb_listeners_test.cpp
new file mode 100644
index 0000000..b697769
--- /dev/null
+++ b/adb/adb_listeners_test.cpp
@@ -0,0 +1,166 @@
+/*
+ * 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 "adb_listeners.h"
+
+#include <gtest/gtest.h>
+
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+#include "fdevent.h"
+#include "sysdeps.h"
+#include "transport.h"
+
+// Returns true if the given listener is present in format_listeners(). Empty parameters will
+// be ignored.
+static bool listener_is_installed(const std::string& serial, const std::string& source,
+                                  const std::string& dest) {
+    // format_listeners() gives lines of "<serial> <source> <dest>\n".
+    for (const std::string& line : android::base::Split(format_listeners(), "\n")) {
+        std::vector<std::string> info = android::base::Split(line, " ");
+        if (info.size() == 3 &&
+                (serial.empty() || info[0] == serial) &&
+                (source.empty() || info[1] == source) &&
+                (dest.empty() || info[2] == dest)) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+class AdbListenersTest : public ::testing::Test {
+  public:
+    void SetUp() override {
+        // We don't need an fdevent loop, but adding/removing listeners must be done from the
+        // fdevent thread if one exists. Since previously run tests may have created an fdevent
+        // thread, we need to reset to prevent the thread check.
+        fdevent_reset();
+    }
+
+    void TearDown() override {
+        // Clean up any listeners that may have been installed.
+        remove_all_listeners();
+
+        // Make sure we didn't leave any dangling events.
+        ASSERT_EQ(0u, fdevent_installed_count());
+    }
+
+  protected:
+    atransport transport_;
+};
+
+TEST_F(AdbListenersTest, test_install_listener) {
+    std::string error;
+
+    ASSERT_EQ(INSTALL_STATUS_OK,
+              install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+    ASSERT_TRUE(error.empty());
+
+    ASSERT_TRUE(listener_is_installed("", "tcp:9000", "tcp:9000"));
+}
+
+TEST_F(AdbListenersTest, test_install_listener_rebind) {
+    std::string error;
+
+    ASSERT_EQ(INSTALL_STATUS_OK,
+              install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+    ASSERT_TRUE(error.empty());
+
+    ASSERT_EQ(INSTALL_STATUS_OK,
+              install_listener("tcp:9000", "tcp:9001", &transport_, false, nullptr, &error));
+    ASSERT_TRUE(error.empty());
+
+    ASSERT_TRUE(listener_is_installed("", "tcp:9000", "tcp:9001"));
+}
+
+TEST_F(AdbListenersTest, test_install_listener_no_rebind) {
+    std::string error;
+
+    ASSERT_EQ(INSTALL_STATUS_OK,
+              install_listener("tcp:9000", "tcp:9000", &transport_, true, nullptr, &error));
+    ASSERT_TRUE(error.empty());
+
+    ASSERT_EQ(INSTALL_STATUS_CANNOT_REBIND,
+              install_listener("tcp:9000", "tcp:9001", &transport_, true, nullptr, &error));
+    ASSERT_FALSE(error.empty());
+
+    ASSERT_TRUE(listener_is_installed("", "tcp:9000", "tcp:9000"));
+}
+
+TEST_F(AdbListenersTest, test_install_listener_tcp_port_0) {
+    int port = 0;
+    std::string error;
+
+    ASSERT_EQ(INSTALL_STATUS_OK,
+              install_listener("tcp:0", "tcp:9000", &transport_, true, &port, &error));
+    ASSERT_TRUE(error.empty());
+
+    ASSERT_TRUE(listener_is_installed("", android::base::StringPrintf("tcp:%d", port), "tcp:9000"));
+}
+
+TEST_F(AdbListenersTest, test_remove_listener) {
+    std::string error;
+
+    ASSERT_EQ(INSTALL_STATUS_OK,
+              install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+    ASSERT_TRUE(error.empty());
+
+    ASSERT_EQ(INSTALL_STATUS_OK, remove_listener("tcp:9000", &transport_));
+    ASSERT_TRUE(format_listeners().empty());
+}
+
+TEST_F(AdbListenersTest, test_remove_nonexistent_listener) {
+    std::string error;
+
+    ASSERT_EQ(INSTALL_STATUS_OK,
+              install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+    ASSERT_TRUE(error.empty());
+
+    ASSERT_EQ(INSTALL_STATUS_LISTENER_NOT_FOUND, remove_listener("tcp:1", &transport_));
+    ASSERT_TRUE(listener_is_installed("", "tcp:9000", "tcp:9000"));
+}
+
+TEST_F(AdbListenersTest, test_remove_all_listeners) {
+    std::string error;
+
+    ASSERT_EQ(INSTALL_STATUS_OK,
+              install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+    ASSERT_TRUE(error.empty());
+
+    ASSERT_EQ(INSTALL_STATUS_OK,
+              install_listener("tcp:9001", "tcp:9001", &transport_, false, nullptr, &error));
+    ASSERT_TRUE(error.empty());
+
+    remove_all_listeners();
+    ASSERT_TRUE(format_listeners().empty());
+}
+
+TEST_F(AdbListenersTest, test_transport_disconnect) {
+    std::string error;
+
+    ASSERT_EQ(INSTALL_STATUS_OK,
+              install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+    ASSERT_TRUE(error.empty());
+
+    ASSERT_EQ(INSTALL_STATUS_OK,
+              install_listener("tcp:9001", "tcp:9001", &transport_, false, nullptr, &error));
+    ASSERT_TRUE(error.empty());
+
+    transport_.RunDisconnects();
+    ASSERT_TRUE(format_listeners().empty());
+}
diff --git a/adb/adb_trace.cpp b/adb/adb_trace.cpp
index 62900c0..002d061 100644
--- a/adb/adb_trace.cpp
+++ b/adb/adb_trace.cpp
@@ -27,7 +27,7 @@
 #include "adb.h"
 
 #if !ADB_HOST
-#include <cutils/properties.h>
+#include <android-base/properties.h>
 #endif
 
 #if !ADB_HOST
@@ -88,19 +88,11 @@
     return std::string(setting);
 }
 
-#if !ADB_HOST
-std::string get_trace_setting_from_prop() {
-    char buf[PROPERTY_VALUE_MAX];
-    property_get("persist.adb.trace_mask", buf, "");
-    return std::string(buf);
-}
-#endif
-
 std::string get_trace_setting() {
 #if ADB_HOST
     return get_trace_setting_from_env();
 #else
-    return get_trace_setting_from_prop();
+    return android::base::GetProperty("persist.adb.trace_mask", "");
 #endif
 }
 
@@ -163,7 +155,24 @@
     }
 #endif
 
+#if !defined(_WIN32)
+    // adb historically ignored $ANDROID_LOG_TAGS but passed it through to logcat.
+    // If set, move it out of the way so that libbase logging doesn't try to parse it.
+    std::string log_tags;
+    char* ANDROID_LOG_TAGS = getenv("ANDROID_LOG_TAGS");
+    if (ANDROID_LOG_TAGS) {
+        log_tags = ANDROID_LOG_TAGS;
+        unsetenv("ANDROID_LOG_TAGS");
+    }
+#endif
+
     android::base::InitLogging(argv, &AdbLogger);
+
+#if !defined(_WIN32)
+    // Put $ANDROID_LOG_TAGS back so we can pass it to logcat.
+    if (!log_tags.empty()) setenv("ANDROID_LOG_TAGS", log_tags.c_str(), 1);
+#endif
+
     setup_trace_mask();
 
     VLOG(ADB) << adb_version();
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
index d50f947..5206a99 100644
--- a/adb/adb_trace.h
+++ b/adb/adb_trace.h
@@ -41,7 +41,7 @@
 };
 
 #define VLOG_IS_ON(TAG) \
-    ((adb_trace_mask & (1 << TAG)) != 0)
+    ((adb_trace_mask & (1 << (TAG))) != 0)
 
 #define VLOG(TAG)         \
     if (LIKELY(!VLOG_IS_ON(TAG))) \
diff --git a/crash_reporter/warn_collector_test.c b/adb/adb_unique_fd.h
similarity index 66%
rename from crash_reporter/warn_collector_test.c
rename to adb/adb_unique_fd.h
index 7ebe0a8..34c1bbc 100644
--- a/crash_reporter/warn_collector_test.c
+++ b/adb/adb_unique_fd.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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.
@@ -14,12 +14,13 @@
  * limitations under the License.
  */
 
-/*
- * Test driver for the warn_collector daemon.
- */
-#include <stdlib.h>
+#pragma once
 
-int main(int ac, char **av) {
-  int status = system("exec \"${SRC}\"/warn_collector_test.sh");
-  return status < 0 ? EXIT_FAILURE : WEXITSTATUS(status);
-}
+#include <android-base/unique_fd.h>
+
+// Helper to automatically close an FD when it goes out of scope.
+struct AdbCloser {
+    static void Close(int fd);
+};
+
+using unique_fd = android::base::unique_fd_impl<AdbCloser>;
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 0645122..5a3b401 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -17,6 +17,7 @@
 #define TRACE_TAG ADB
 
 #include "adb_utils.h"
+#include "adb_unique_fd.h"
 
 #include <libgen.h>
 #include <stdlib.h>
@@ -25,8 +26,11 @@
 #include <unistd.h>
 
 #include <algorithm>
+#include <mutex>
+#include <vector>
 
 #include <android-base/logging.h>
+#include <android-base/parseint.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 
@@ -40,10 +44,10 @@
 #  endif
 #  include "windows.h"
 #  include "shlobj.h"
+#else
+#include <pwd.h>
 #endif
 
-ADB_MUTEX_DEFINE(basename_lock);
-ADB_MUTEX_DEFINE(dirname_lock);
 
 #if defined(_WIN32)
 constexpr char kNullFileName[] = "NUL";
@@ -97,13 +101,15 @@
 }
 
 std::string adb_basename(const std::string& path) {
+  static std::mutex& basename_lock = *new std::mutex();
+
   // Copy path because basename may modify the string passed in.
   std::string result(path);
 
   // Use lock because basename() may write to a process global and return a
   // pointer to that. Note that this locking strategy only works if all other
-  // callers to dirname in the process also grab this same lock.
-  adb_mutex_lock(&basename_lock);
+  // callers to basename in the process also grab this same lock.
+  std::lock_guard<std::mutex> lock(basename_lock);
 
   // Note that if std::string uses copy-on-write strings, &str[0] will cause
   // the copy to be made, so there is no chance of us accidentally writing to
@@ -114,19 +120,19 @@
   // before leaving the lock.
   result.assign(name);
 
-  adb_mutex_unlock(&basename_lock);
-
   return result;
 }
 
 std::string adb_dirname(const std::string& path) {
+  static std::mutex& dirname_lock = *new std::mutex();
+
   // Copy path because dirname may modify the string passed in.
   std::string result(path);
 
   // Use lock because dirname() may write to a process global and return a
   // pointer to that. Note that this locking strategy only works if all other
   // callers to dirname in the process also grab this same lock.
-  adb_mutex_lock(&dirname_lock);
+  std::lock_guard<std::mutex> lock(dirname_lock);
 
   // Note that if std::string uses copy-on-write strings, &str[0] will cause
   // the copy to be made, so there is no chance of us accidentally writing to
@@ -137,8 +143,6 @@
   // before leaving the lock.
   result.assign(parent);
 
-  adb_mutex_unlock(&dirname_lock);
-
   return result;
 }
 
@@ -239,14 +243,31 @@
 }
 #endif
 
-std::string adb_get_homedir_path(bool check_env_first) {
-#ifdef _WIN32
-    if (check_env_first) {
-        if (const char* const home = getenv("ANDROID_SDK_HOME")) {
-            return home;
+bool forward_targets_are_valid(const std::string& source, const std::string& dest,
+                               std::string* error) {
+    if (android::base::StartsWith(source, "tcp:")) {
+        // The source port may be 0 to allow the system to select an open port.
+        int port;
+        if (!android::base::ParseInt(&source[4], &port) || port < 0) {
+            *error = android::base::StringPrintf("Invalid source port: '%s'", &source[4]);
+            return false;
         }
     }
 
+    if (android::base::StartsWith(dest, "tcp:")) {
+        // The destination port must be > 0.
+        int port;
+        if (!android::base::ParseInt(&dest[4], &port) || port <= 0) {
+            *error = android::base::StringPrintf("Invalid destination port: '%s'", &dest[4]);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+std::string adb_get_homedir_path() {
+#ifdef _WIN32
     WCHAR path[MAX_PATH];
     const HRESULT hr = SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, path);
     if (FAILED(hr)) {
@@ -262,7 +283,33 @@
     if (const char* const home = getenv("HOME")) {
         return home;
     }
+
+    struct passwd pwent;
+    struct passwd* result;
+    int pwent_max = sysconf(_SC_GETPW_R_SIZE_MAX);
+    std::vector<char> buf(pwent_max);
+    int rc = getpwuid_r(getuid(), &pwent, buf.data(), buf.size(), &result);
+    if (rc == 0 && result) {
+        return result->pw_dir;
+    }
+
+    LOG(FATAL) << "failed to get user home directory";
     return {};
 #endif
 }
 
+std::string adb_get_android_dir_path() {
+    std::string user_dir = adb_get_homedir_path();
+    std::string android_dir = user_dir + OS_PATH_SEPARATOR + ".android";
+    struct stat buf;
+    if (stat(android_dir.c_str(), &buf) == -1) {
+        if (adb_mkdir(android_dir.c_str(), 0750) == -1) {
+            PLOG(FATAL) << "Cannot mkdir '" << android_dir << "'";
+        }
+    }
+    return android_dir;
+}
+
+void AdbCloser::Close(int fd) {
+    adb_close(fd);
+}
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index cd6717d..16317e0 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -20,7 +20,6 @@
 #include <string>
 
 #include <android-base/macros.h>
-#include <android-base/unique_fd.h>
 
 void close_stdin();
 
@@ -33,10 +32,10 @@
 std::string adb_dirname(const std::string& path);
 
 // Return the user's home directory.
-// |check_env_first| - if true, on Windows check the ANDROID_SDK_HOME
-// environment variable before trying the WinAPI call (useful when looking for
-// the .android directory)
-std::string adb_get_homedir_path(bool check_env_first);
+std::string adb_get_homedir_path();
+
+// Return the adb user directory.
+std::string adb_get_android_dir_path();
 
 bool mkdirs(const std::string& path);
 
@@ -50,51 +49,11 @@
 
 extern int adb_close(int fd);
 
-// Helper to automatically close an FD when it goes out of scope.
-struct AdbCloser {
-    static void Close(int fd) {
-        adb_close(fd);
-    }
-};
-
-using unique_fd = android::base::unique_fd_impl<AdbCloser>;
-
-class ScopedFd {
-  public:
-    ScopedFd() {
-    }
-
-    ~ScopedFd() {
-        Reset();
-    }
-
-    void Reset(int fd = -1) {
-        if (fd != fd_) {
-            if (valid()) {
-                adb_close(fd_);
-            }
-            fd_ = fd;
-        }
-    }
-
-    int Release() {
-        int temp = fd_;
-        fd_ = -1;
-        return temp;
-    }
-
-    bool valid() const {
-        return fd_ >= 0;
-    }
-
-    int fd() const {
-        return fd_;
-    }
-
-  private:
-    int fd_ = -1;
-
-    DISALLOW_COPY_AND_ASSIGN(ScopedFd);
-};
+// Given forward/reverse targets, returns true if they look sane. If an error is found, fills
+// |error| and returns false.
+// Currently this only checks "tcp:" targets. Additional checking could be added for other targets
+// if needed.
+bool forward_targets_are_valid(const std::string& source, const std::string& dest,
+                               std::string* error);
 
 #endif
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index a78f8d3..4cac485 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -121,7 +121,7 @@
   EXPECT_EQ("/system/bin", adb_dirname("/system/bin/sh/"));
 }
 
-void test_mkdirs(const std::string basepath) {
+void test_mkdirs(const std::string& basepath) {
   // Test creating a directory hierarchy.
   ASSERT_TRUE(mkdirs(basepath));
   // Test finding an existing directory hierarchy.
@@ -165,3 +165,24 @@
   ASSERT_EQ(0, adb_close(fd));
 }
 #endif
+
+TEST(adb_utils, test_forward_targets_are_valid) {
+    std::string error;
+
+    // Source port can be >= 0.
+    EXPECT_FALSE(forward_targets_are_valid("tcp:-1", "tcp:9000", &error));
+    EXPECT_TRUE(forward_targets_are_valid("tcp:0", "tcp:9000", &error));
+    EXPECT_TRUE(forward_targets_are_valid("tcp:8000", "tcp:9000", &error));
+
+    // Destination port must be >0.
+    EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:-1", &error));
+    EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:0", &error));
+
+    // Port must be a number.
+    EXPECT_FALSE(forward_targets_are_valid("tcp:", "tcp:9000", &error));
+    EXPECT_FALSE(forward_targets_are_valid("tcp:a", "tcp:9000", &error));
+    EXPECT_FALSE(forward_targets_are_valid("tcp:22x", "tcp:9000", &error));
+    EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:", &error));
+    EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:a", &error));
+    EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:22x", &error));
+}
diff --git a/adb/adbd_auth.cpp b/adb/adbd_auth.cpp
new file mode 100644
index 0000000..b5f87be
--- /dev/null
+++ b/adb/adbd_auth.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#define TRACE_TAG AUTH
+
+#include "adb.h"
+#include "adb_auth.h"
+#include "fdevent.h"
+#include "sysdeps.h"
+#include "transport.h"
+
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <memory>
+
+#include <android-base/file.h>
+#include <android-base/strings.h>
+#include <crypto_utils/android_pubkey.h>
+#include <openssl/obj_mac.h>
+#include <openssl/rsa.h>
+#include <openssl/sha.h>
+
+static fdevent listener_fde;
+static fdevent framework_fde;
+static int framework_fd = -1;
+
+static void usb_disconnected(void* unused, atransport* t);
+static struct adisconnect usb_disconnect = { usb_disconnected, nullptr};
+static atransport* usb_transport;
+static bool needs_retry = false;
+
+bool auth_required = true;
+
+bool adbd_auth_verify(const char* token, size_t token_size, const char* sig, int sig_len) {
+    static constexpr const char* key_paths[] = { "/adb_keys", "/data/misc/adb/adb_keys", nullptr };
+
+    for (const auto& path : key_paths) {
+        if (access(path, R_OK) == 0) {
+            LOG(INFO) << "Loading keys from " << path;
+
+            std::string content;
+            if (!android::base::ReadFileToString(path, &content)) {
+                PLOG(ERROR) << "Couldn't read " << path;
+                continue;
+            }
+
+            for (const auto& line : android::base::Split(content, "\n")) {
+                // TODO: do we really have to support both ' ' and '\t'?
+                char* sep = strpbrk(const_cast<char*>(line.c_str()), " \t");
+                if (sep) *sep = '\0';
+
+                // b64_pton requires one additional byte in the target buffer for
+                // decoding to succeed. See http://b/28035006 for details.
+                uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1];
+                if (__b64_pton(line.c_str(), keybuf, sizeof(keybuf)) != ANDROID_PUBKEY_ENCODED_SIZE) {
+                    LOG(ERROR) << "Invalid base64 key " << line.c_str() << " in " << path;
+                    continue;
+                }
+
+                RSA* key = nullptr;
+                if (!android_pubkey_decode(keybuf, ANDROID_PUBKEY_ENCODED_SIZE, &key)) {
+                    LOG(ERROR) << "Failed to parse key " << line.c_str() << " in " << path;
+                    continue;
+                }
+
+                bool verified =
+                    (RSA_verify(NID_sha1, reinterpret_cast<const uint8_t*>(token), token_size,
+                                reinterpret_cast<const uint8_t*>(sig), sig_len, key) == 1);
+                RSA_free(key);
+                if (verified) return true;
+            }
+        }
+    }
+    return false;
+}
+
+static bool adbd_auth_generate_token(void* token, size_t token_size) {
+    FILE* fp = fopen("/dev/urandom", "re");
+    if (!fp) return false;
+    bool okay = (fread(token, token_size, 1, fp) == 1);
+    fclose(fp);
+    return okay;
+}
+
+static void usb_disconnected(void* unused, atransport* t) {
+    LOG(INFO) << "USB disconnect";
+    usb_transport = NULL;
+    needs_retry = false;
+}
+
+static void framework_disconnected() {
+    LOG(INFO) << "Framework disconnect";
+    fdevent_remove(&framework_fde);
+    framework_fd = -1;
+}
+
+static void adbd_auth_event(int fd, unsigned events, void*) {
+    if (events & FDE_READ) {
+        char response[2];
+        int ret = unix_read(fd, response, sizeof(response));
+        if (ret <= 0) {
+            framework_disconnected();
+        } else if (ret == 2 && response[0] == 'O' && response[1] == 'K') {
+            if (usb_transport) {
+                adbd_auth_verified(usb_transport);
+            }
+        }
+    }
+}
+
+void adbd_auth_confirm_key(const char* key, size_t len, atransport* t) {
+    if (!usb_transport) {
+        usb_transport = t;
+        t->AddDisconnect(&usb_disconnect);
+    }
+
+    if (framework_fd < 0) {
+        LOG(ERROR) << "Client not connected";
+        needs_retry = true;
+        return;
+    }
+
+    if (key[len - 1] != '\0') {
+        LOG(ERROR) << "Key must be a null-terminated string";
+        return;
+    }
+
+    char msg[MAX_PAYLOAD_V1];
+    int msg_len = snprintf(msg, sizeof(msg), "PK%s", key);
+    if (msg_len >= static_cast<int>(sizeof(msg))) {
+        LOG(ERROR) << "Key too long (" << msg_len << ")";
+        return;
+    }
+    LOG(DEBUG) << "Sending '" << msg << "'";
+
+    if (unix_write(framework_fd, msg, msg_len) == -1) {
+        PLOG(ERROR) << "Failed to write PK";
+        return;
+    }
+}
+
+static void adbd_auth_listener(int fd, unsigned events, void* data) {
+    int s = adb_socket_accept(fd, nullptr, nullptr);
+    if (s < 0) {
+        PLOG(ERROR) << "Failed to accept";
+        return;
+    }
+
+    if (framework_fd >= 0) {
+        LOG(WARNING) << "adb received framework auth socket connection again";
+        framework_disconnected();
+    }
+
+    framework_fd = s;
+    fdevent_install(&framework_fde, framework_fd, adbd_auth_event, nullptr);
+    fdevent_add(&framework_fde, FDE_READ);
+
+    if (needs_retry) {
+        needs_retry = false;
+        send_auth_request(usb_transport);
+    }
+}
+
+void adbd_cloexec_auth_socket() {
+    int fd = android_get_control_socket("adbd");
+    if (fd == -1) {
+        PLOG(ERROR) << "Failed to get adbd socket";
+        return;
+    }
+    fcntl(fd, F_SETFD, FD_CLOEXEC);
+}
+
+void adbd_auth_init(void) {
+    int fd = android_get_control_socket("adbd");
+    if (fd == -1) {
+        PLOG(ERROR) << "Failed to get adbd socket";
+        return;
+    }
+
+    if (listen(fd, 4) == -1) {
+        PLOG(ERROR) << "Failed to listen on '" << fd << "'";
+        return;
+    }
+
+    fdevent_install(&listener_fde, fd, adbd_auth_listener, NULL);
+    fdevent_add(&listener_fde, FDE_READ);
+}
+
+void send_auth_request(atransport* t) {
+    LOG(INFO) << "Calling send_auth_request...";
+
+    if (!adbd_auth_generate_token(t->token, sizeof(t->token))) {
+        PLOG(ERROR) << "Error generating token";
+        return;
+    }
+
+    apacket* p = get_apacket();
+    memcpy(p->data, t->token, sizeof(t->token));
+    p->msg.command = A_AUTH;
+    p->msg.arg0 = ADB_AUTH_TOKEN;
+    p->msg.data_length = sizeof(t->token);
+    send_packet(p, t);
+}
+
+void adbd_auth_verified(atransport *t)
+{
+    handle_online(t);
+    send_connect(t);
+}
diff --git a/adb/bugreport.cpp b/adb/bugreport.cpp
index c348dd5..9b59d05 100644
--- a/adb/bugreport.cpp
+++ b/adb/bugreport.cpp
@@ -237,8 +237,7 @@
         // Uses a default value until device provides the proper name
         dest_file = "bugreport.zip";
     } else {
-        if (!android::base::EndsWith(dest_file, ".zip")) {
-            // TODO: use a case-insensitive comparison (like EndsWithIgnoreCase
+        if (!android::base::EndsWithIgnoreCase(dest_file, ".zip")) {
             dest_file += ".zip";
         }
     }
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index ba4737f..4ec0fc2 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -88,7 +88,7 @@
 }
 #endif
 
-int adb_server_main(int is_daemon, int server_port, int ack_reply_fd) {
+int adb_server_main(int is_daemon, const std::string& socket_spec, int ack_reply_fd) {
 #if defined(_WIN32)
     // adb start-server starts us up with stdout and stderr hooked up to
     // anonymous pipes. When the C Runtime sees this, it makes stderr and
@@ -111,28 +111,33 @@
 
     usb_init();
     local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
-    adb_auth_init();
 
     std::string error;
-    std::string local_name = android::base::StringPrintf("tcp:%d", server_port);
-    if (install_listener(local_name, "*smartsocket*", nullptr, 0, &error)) {
+    if (install_listener(socket_spec, "*smartsocket*", nullptr, 0, nullptr, &error)) {
         fatal("could not install *smartsocket* listener: %s", error.c_str());
     }
 
-    // Inform our parent that we are up and running.
     if (is_daemon) {
         close_stdin();
         setup_daemon_logging();
+    }
 
+    adb_auth_init();
+
+    if (is_daemon) {
 #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) {
+        // setsid will fail with EPERM if it's already been a lead process of new session.
+        // Ignore such error.
+        if (setsid() == -1 && errno != EPERM) {
             fatal("setsid() failed: %s", strerror(errno));
         }
 #endif
 
+        // Inform our parent that we are up and running.
+
         // 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.
@@ -167,7 +172,6 @@
 }
 
 int main(int argc, char** argv) {
-    adb_sysdeps_init();
     adb_trace_init(argv);
     return adb_commandline(argc - 1, const_cast<const char**>(argv + 1));
 }
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 51d828a..a064de2 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -33,9 +33,12 @@
 
 #include <memory>
 #include <string>
+#include <thread>
 #include <vector>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/parseint.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 
@@ -50,12 +53,14 @@
 #include "adb_auth.h"
 #include "adb_client.h"
 #include "adb_io.h"
+#include "adb_unique_fd.h"
 #include "adb_utils.h"
 #include "bugreport.h"
 #include "commandline.h"
 #include "file_sync_service.h"
 #include "services.h"
 #include "shell_service.h"
+#include "sysdeps/chrono.h"
 
 static int install_app(TransportType t, const char* serial, int argc, const char** argv);
 static int install_multiple_app(TransportType t, const char* serial, int argc, const char** argv);
@@ -80,179 +85,149 @@
 }
 
 static void help() {
-    fprintf(stderr, "%s\n", adb_version().c_str());
+    fprintf(stdout, "%s\n", adb_version().c_str());
     // clang-format off
-    fprintf(stderr,
-        " -a                            - directs adb to listen on all interfaces for a connection\n"
-        " -d                            - directs command to the only connected USB device\n"
-        "                                 returns an error if more than one USB device is present.\n"
-        " -e                            - directs command to the only running emulator.\n"
-        "                                 returns an error if more than one emulator is running.\n"
-        " -s <specific device>          - directs command to the device or emulator with the given\n"
-        "                                 serial number or qualifier. Overrides ANDROID_SERIAL\n"
-        "                                 environment variable.\n"
-        " -p <product name or path>     - simple product name like 'sooner', or\n"
-        "                                 a relative/absolute path to a product\n"
-        "                                 out directory like 'out/target/product/sooner'.\n"
-        "                                 If -p is not specified, the ANDROID_PRODUCT_OUT\n"
-        "                                 environment variable is used, which must\n"
-        "                                 be an absolute path.\n"
-        " -H                            - Name of adb server host (default: localhost)\n"
-        " -P                            - Port of adb server (default: 5037)\n"
-        " devices [-l]                  - list all connected devices\n"
-        "                                 ('-l' will also list device qualifiers)\n"
-        " connect <host>[:<port>]       - connect to a device via TCP/IP\n"
-        "                                 Port 5555 is used by default if no port number is specified.\n"
-        " disconnect [<host>[:<port>]]  - disconnect from a TCP/IP device.\n"
-        "                                 Port 5555 is used by default if no port number is specified.\n"
-        "                                 Using this command with no additional arguments\n"
-        "                                 will disconnect from all connected TCP/IP devices.\n"
+    fprintf(stdout,
+        "global options:\n"
+        " -a         listen on all network interfaces, not just localhost\n"
+        " -d         use USB device (error if multiple devices connected)\n"
+        " -e         use emulator (error if multiple emulators running)\n"
+        " -s SERIAL\n"
+        "     use device/emulator with given serial number (overrides $ANDROID_SERIAL)\n"
+        " -p PRODUCT\n"
+        "     name or path ('angler'/'out/target/product/angler');\n"
+        "     default $ANDROID_PRODUCT_OUT\n"
+        " -H         name of adb server host [default=localhost]\n"
+        " -P         port of adb server [default=5037]\n"
+        " -L SOCKET  listen on given socket for adb server [default=tcp:localhost:5037]\n"
         "\n"
-        "device commands:\n"
-        "  adb push <local>... <remote>\n"
-        "                               - copy files/dirs to device\n"
-        "  adb pull [-a] <remote>... <local>\n"
-        "                               - copy files/dirs from device\n"
-        "                                 (-a preserves file timestamp and mode)\n"
-        "  adb sync [ <directory> ]     - copy host->device only if changed\n"
-        "                                 (-l means list but don't copy)\n"
-        "  adb shell [-e escape] [-n] [-Tt] [-x] [command]\n"
-        "                               - run remote shell command (interactive shell if no command given)\n"
-        "                                 (-e: choose escape character, or \"none\"; default '~')\n"
-        "                                 (-n: don't read from stdin)\n"
-        "                                 (-T: disable PTY allocation)\n"
-        "                                 (-t: force PTY allocation)\n"
-        "                                 (-x: disable remote exit codes and stdout/stderr separation)\n"
-        "  adb emu <command>            - run emulator console command\n"
-        "  adb logcat [ <filter-spec> ] - View device log\n"
-        "  adb forward --list           - list all forward socket connections.\n"
-        "                                 the format is a list of lines with the following format:\n"
-        "                                    <serial> \" \" <local> \" \" <remote> \"\\n\"\n"
-        "  adb forward <local> <remote> - forward socket connections\n"
-        "                                 forward specs are one of: \n"
-        "                                   tcp:<port>\n"
-        "                                   localabstract:<unix domain socket name>\n"
-        "                                   localreserved:<unix domain socket name>\n"
-        "                                   localfilesystem:<unix domain socket name>\n"
-        "                                   dev:<character device name>\n"
-        "                                   jdwp:<process pid> (remote only)\n"
-        "  adb forward --no-rebind <local> <remote>\n"
-        "                               - same as 'adb forward <local> <remote>' but fails\n"
-        "                                 if <local> is already forwarded\n"
-        "  adb forward --remove <local> - remove a specific forward socket connection\n"
-        "  adb forward --remove-all     - remove all forward socket connections\n"
-        "  adb reverse --list           - list all reverse socket connections from device\n"
-        "  adb reverse <remote> <local> - reverse socket connections\n"
-        "                                 reverse specs are one of:\n"
-        "                                   tcp:<port>\n"
-        "                                   localabstract:<unix domain socket name>\n"
-        "                                   localreserved:<unix domain socket name>\n"
-        "                                   localfilesystem:<unix domain socket name>\n"
-        "  adb reverse --no-rebind <remote> <local>\n"
-        "                               - same as 'adb reverse <remote> <local>' but fails\n"
-        "                                 if <remote> is already reversed.\n"
-        "  adb reverse --remove <remote>\n"
-        "                               - remove a specific reversed socket connection\n"
-        "  adb reverse --remove-all     - remove all reversed socket connections from device\n"
-        "  adb jdwp                     - list PIDs of processes hosting a JDWP transport\n"
-        "  adb install [-lrtsdg] <file>\n"
-        "                               - push this package file to the device and install it\n"
-        "                                 (-l: forward lock application)\n"
-        "                                 (-r: replace existing application)\n"
-        "                                 (-t: allow test packages)\n"
-        "                                 (-s: install application on sdcard)\n"
-        "                                 (-d: allow version code downgrade (debuggable packages only))\n"
-        "                                 (-g: grant all runtime permissions)\n"
-        "  adb install-multiple [-lrtsdpg] <file...>\n"
-        "                               - push this package file to the device and install it\n"
-        "                                 (-l: forward lock application)\n"
-        "                                 (-r: replace existing application)\n"
-        "                                 (-t: allow test packages)\n"
-        "                                 (-s: install application on sdcard)\n"
-        "                                 (-d: allow version code downgrade (debuggable packages only))\n"
-        "                                 (-p: partial application install)\n"
-        "                                 (-g: grant all runtime permissions)\n"
-        "  adb uninstall [-k] <package> - remove this app package from the device\n"
-        "                                 ('-k' means keep the data and cache directories)\n"
-        "  adb bugreport [<path>]       - return all information from the device that should be included in a zipped bug report.\n"
-        "                                 If <path> is a file, the bug report will be saved as that file.\n"
-        "                                 If <path> is a directory, the bug report will be saved in that directory with the name provided by the device.\n"
-        "                                 If <path> is omitted, the bug report will be saved in the current directory with the name provided by the device.\n"
-        "                                 NOTE: if the device does not support zipped bug reports, the bug report will be output on stdout.\n"
-        "  adb backup [-f <file>] [-apk|-noapk] [-obb|-noobb] [-shared|-noshared] [-all] [-system|-nosystem] [<packages...>]\n"
-        "                               - write an archive of the device's data to <file>.\n"
-        "                                 If no -f option is supplied then the data is written\n"
-        "                                 to \"backup.ab\" in the current directory.\n"
-        "                                 (-apk|-noapk enable/disable backup of the .apks themselves\n"
-        "                                    in the archive; the default is noapk.)\n"
-        "                                 (-obb|-noobb enable/disable backup of any installed apk expansion\n"
-        "                                    (aka .obb) files associated with each application; the default\n"
-        "                                    is noobb.)\n"
-        "                                 (-shared|-noshared enable/disable backup of the device's\n"
-        "                                    shared storage / SD card contents; the default is noshared.)\n"
-        "                                 (-all means to back up all installed applications)\n"
-        "                                 (-system|-nosystem toggles whether -all automatically includes\n"
-        "                                    system applications; the default is to include system apps)\n"
-        "                                 (<packages...> is the list of applications to be backed up.  If\n"
-        "                                    the -all or -shared flags are passed, then the package\n"
-        "                                    list is optional.  Applications explicitly given on the\n"
-        "                                    command line will be included even if -nosystem would\n"
-        "                                    ordinarily cause them to be omitted.)\n"
-        "\n"
-        "  adb restore <file>           - restore device contents from the <file> backup archive\n"
-        "\n"
-        "  adb disable-verity           - disable dm-verity checking on USERDEBUG builds\n"
-        "  adb enable-verity            - re-enable dm-verity checking on USERDEBUG builds\n"
-        "  adb keygen <file>            - generate adb public/private key. The private key is stored in <file>,\n"
-        "                                 and the public key is stored in <file>.pub. Any existing files\n"
-        "                                 are overwritten.\n"
-        "  adb help                     - show this help message\n"
-        "  adb version                  - show version num\n"
-        "\n"
-        "scripting:\n"
-        "  adb wait-for[-<transport>]-<state>\n"
-        "                               - wait for device to be in the given state:\n"
-        "                                 device, recovery, sideload, or bootloader\n"
-        "                                 Transport is: usb, local or any [default=any]\n"
-        "  adb start-server             - ensure that there is a server running\n"
-        "  adb kill-server              - kill the server if it is running\n"
-        "  adb get-state                - prints: offline | bootloader | device\n"
-        "  adb get-serialno             - prints: <serial-number>\n"
-        "  adb get-devpath              - prints: <device-path>\n"
-        "  adb remount                  - remounts the /system, /vendor (if present) and /oem (if present) partitions on the device read-write\n"
-        "  adb reboot [bootloader|recovery]\n"
-        "                               - reboots the device, optionally into the bootloader or recovery program.\n"
-        "  adb reboot sideload          - reboots the device into the sideload mode in recovery program (adb root required).\n"
-        "  adb reboot sideload-auto-reboot\n"
-        "                               - reboots into the sideload mode, then reboots automatically after the sideload regardless of the result.\n"
-        "  adb sideload <file>          - sideloads the given package\n"
-        "  adb root                     - restarts the adbd daemon with root permissions\n"
-        "  adb unroot                   - restarts the adbd daemon without root permissions\n"
-        "  adb usb                      - restarts the adbd daemon listening on USB\n"
-        "  adb tcpip <port>             - restarts the adbd daemon listening on TCP on the specified port\n"
+        "general commands:\n"
+        " devices [-l]             list connected devices (-l for long output)\n"
+        " help                     show this help message\n"
+        " version                  show version num\n"
         "\n"
         "networking:\n"
-        "  adb ppp <tty> [parameters]   - Run PPP over USB.\n"
-        " Note: you should not automatically start a PPP connection.\n"
-        " <tty> refers to the tty for PPP stream. Eg. dev:/dev/omap_csmi_tty1\n"
-        " [parameters] - Eg. defaultroute debug dump local notty usepeerdns\n"
+        " connect HOST[:PORT]      connect to a device via TCP/IP [default port=5555]\n"
+        " disconnect [HOST[:PORT]]\n"
+        "     disconnect from given TCP/IP device [default port=5555], or all\n"
+        " forward --list           list all forward socket connections\n"
+        " forward [--no-rebind] LOCAL REMOTE\n"
+        "     forward socket connection using:\n"
+        "       tcp:<port> (<local> may be \"tcp:0\" to pick any open port)\n"
+        "       localabstract:<unix domain socket name>\n"
+        "       localreserved:<unix domain socket name>\n"
+        "       localfilesystem:<unix domain socket name>\n"
+        "       dev:<character device name>\n"
+        "       jdwp:<process pid> (remote only)\n"
+        " forward --remove LOCAL   remove specific forward socket connection\n"
+        " forward --remove-all     remove all forward socket connections\n"
+        " ppp TTY [PARAMETER...]   run PPP over USB\n"
+        " reverse --list           list all reverse socket connections from device\n"
+        " reverse [--no-rebind] REMOTE LOCAL\n"
+        "     reverse socket connection using:\n"
+        "       tcp:<port> (<remote> may be \"tcp:0\" to pick any open port)\n"
+        "       localabstract:<unix domain socket name>\n"
+        "       localreserved:<unix domain socket name>\n"
+        "       localfilesystem:<unix domain socket name>\n"
+        " reverse --remove REMOTE  remove specific reverse socket connection\n"
+        " reverse --remove-all     remove all reverse socket connections from device\n"
         "\n"
-        "adb sync notes: adb sync [ <directory> ]\n"
-        "  <localdir> can be interpreted in several ways:\n"
+        "file transfer:\n"
+        " push LOCAL... REMOTE\n"
+        "     copy local files/directories to device\n"
+        " pull [-a] REMOTE... LOCAL\n"
+        "     copy files/dirs from device\n"
+        "     -a: preserve file timestamp and mode\n"
+        " sync [DIR]\n"
+        "     copy all changed files to device; if DIR is \"system\", \"vendor\", \"oem\",\n"
+        "     or \"data\", only sync that partition (default all)\n"
+        "     -l: list but don't copy\n"
         "\n"
-        "  - If <directory> is not specified, /system, /vendor (if present), /oem (if present) and /data partitions will be updated.\n"
+        "shell:\n"
+        " shell [-e ESCAPE] [-n] [-Tt] [-x] [COMMAND...]\n"
+        "     run remote shell command (interactive shell if no command given)\n"
+        "     -e: choose escape character, or \"none\"; default '~'\n"
+        "     -n: don't read from stdin\n"
+        "     -T: disable PTY allocation\n"
+        "     -t: force PTY allocation\n"
+        "     -x: disable remote exit codes and stdout/stderr separation\n"
+        " emu COMMAND              run emulator console command\n"
         "\n"
-        "  - If it is \"system\", \"vendor\", \"oem\" or \"data\", only the corresponding partition\n"
-        "    is updated.\n"
+        "app installation:\n"
+        " install [-lrtsdg] PACKAGE\n"
+        " install-multiple [-lrtsdpg] PACKAGE...\n"
+        "     push package(s) to the device and install them\n"
+        "     -l: forward lock application\n"
+        "     -r: replace existing application\n"
+        "     -t: allow test packages\n"
+        "     -s: install application on sdcard\n"
+        "     -d: allow version code downgrade (debuggable packages only)\n"
+        "     -p: partial application install (install-multiple only)\n"
+        "     -g: grant all runtime permissions\n"
+        " uninstall [-k] PACKAGE\n"
+        "     remove this app package from the device\n"
+        "     '-k': keep the data and cache directories\n"
+        "\n"
+        "backup/restore:\n"
+        " backup [-f FILE] [-apk|-noapk] [-obb|-noobb] [-shared|-noshared] [-all] [-system|-nosystem] [PACKAGE...]\n"
+        "     write an archive of the device's data to FILE [default=backup.adb]\n"
+        "     package list optional if -all/-shared are supplied\n"
+        "     -apk/-noapk: do/don't back up .apk files (default -noapk)\n"
+        "     -obb/-noobb: do/don't back up .obb files (default -noobb)\n"
+        "     -shared|-noshared: do/don't back up shared storage (default -noshared)\n"
+        "     -all: back up all installed applications\n"
+        "     -system|-nosystem: include system apps in -all (default -system)\n"
+        " restore FILE             restore device contents from FILE\n"
+        "\n"
+        "debugging:\n"
+        " bugreport [PATH]\n"
+        "     write bugreport to given PATH [default=bugreport.zip];\n"
+        "     if PATH is a directory, the bug report is saved in that directory.\n"
+        "     devices that don't support zipped bug reports output to stdout.\n"
+        " jdwp                     list pids of processes hosting a JDWP transport\n"
+        " logcat                   show device log (logcat --help for more)\n"
+        "\n"
+        "security:\n"
+        " disable-verity           disable dm-verity checking on userdebug builds\n"
+        " enable-verity            re-enable dm-verity checking on userdebug builds\n"
+        " keygen FILE\n"
+        "     generate adb public/private key; private key stored in FILE,\n"
+        "     public key stored in FILE.pub (existing files overwritten)\n"
+        "\n"
+        "scripting:\n"
+        " wait-for[-TRANSPORT]-STATE\n"
+        "     wait for device to be in the given state\n"
+        "     State: device, recovery, sideload, or bootloader\n"
+        "     Transport: usb, local, or any [default=any]\n"
+        " get-state                print offline | bootloader | device\n"
+        " get-serialno             print <serial-number>\n"
+        " get-devpath              print <device-path>\n"
+        " remount\n"
+        "     remount /system, /vendor, and /oem partitions read-write\n"
+        " reboot [bootloader|recovery|sideload|sideload-auto-reboot]\n"
+        "     reboot the device; defaults to booting system image but\n"
+        "     supports bootloader and recovery too. sideload reboots\n"
+        "     into recovery and automatically starts sideload mode,\n"
+        "     sideload-auto-reboot is the same but reboots after sideloading.\n"
+        " sideload OTAPACKAGE      sideload the given full OTA package\n"
+        " root                     restart adbd with root permissions\n"
+        " unroot                   restart adbd without root permissions\n"
+        " usb                      restart adb server listening on USB\n"
+        " tcpip PORT               restart adb server listening on TCP on PORT\n"
         "\n"
         "internal debugging:\n"
-        "  adb reconnect                  Kick current connection from host side and make it reconnect.\n"
-        "  adb reconnect device           Kick current connection from device side and make it reconnect.\n"
+        " start-server             ensure that there is a server running\n"
+        " kill-server              kill the server if it is running\n"
+        " reconnect                kick connection from host side to force reconnect\n"
+        " reconnect device         kick connection from device side to force reconnect\n"
+        "\n"
         "environment variables:\n"
-        "  ADB_TRACE                    - Print debug information. A comma separated list of the following values\n"
-        "                                 1 or all, adb, sockets, packets, rwx, usb, sync, sysdeps, transport, jdwp\n"
-        "  ANDROID_SERIAL               - The serial number to connect to. -s takes priority over this if given.\n"
-        "  ANDROID_LOG_TAGS             - When used with the logcat option, only these debug tags are printed.\n");
+        " $ADB_TRACE\n"
+        "     comma-separated list of debug info to log:\n"
+        "     all,adb,sockets,packets,rwx,usb,sync,sysdeps,transport,jdwp\n"
+        " $ADB_VENDOR_KEYS         colon-separated list of keys (files or directories)\n"
+        " $ANDROID_SERIAL          serial number to connect to (see -s)\n"
+        " $ANDROID_LOG_TAGS        tags to be used by logcat (see logcat --help)\n");
     // clang-format on
 }
 
@@ -713,100 +688,100 @@
 static int adb_shell(int argc, const char** argv) {
     FeatureSet features;
     std::string error;
-
     if (!adb_get_feature_set(&features, &error)) {
         fprintf(stderr, "error: %s\n", error.c_str());
         return 1;
     }
 
-    bool use_shell_protocol = CanUseFeature(features, kFeatureShell2);
-    if (!use_shell_protocol) {
-        D("shell protocol not supported, using raw data transfer");
-    } else {
-        D("using shell protocol");
-    }
+    enum PtyAllocationMode { kPtyAuto, kPtyNo, kPtyYes, kPtyDefinitely };
+
+    // Defaults.
+    char escape_char = '~'; // -e
+    bool use_shell_protocol = CanUseFeature(features, kFeatureShell2); // -x
+    PtyAllocationMode tty = use_shell_protocol ? kPtyAuto : kPtyDefinitely; // -t/-T
 
     // Parse shell-specific command-line options.
-    // argv[0] is always "shell".
-    --argc;
-    ++argv;
-    int t_arg_count = 0;
-    char escape_char = '~';
-    while (argc) {
-        if (!strcmp(argv[0], "-e")) {
-            if (argc < 2 || !(strlen(argv[1]) == 1 || strcmp(argv[1], "none") == 0)) {
-                fprintf(stderr, "error: -e requires a single-character argument or 'none'\n");
+    argv[0] = "adb shell"; // So getopt(3) error messages start "adb shell".
+    optind = 1; // argv[0] is always "shell", so set `optind` appropriately.
+    int opt;
+    while ((opt = getopt(argc, const_cast<char**>(argv), "+e:ntTx")) != -1) {
+        switch (opt) {
+            case 'e':
+                if (!(strlen(optarg) == 1 || strcmp(optarg, "none") == 0)) {
+                    fprintf(stderr, "error: -e requires a single-character argument or 'none'\n");
+                    return 1;
+                }
+                escape_char = (strcmp(optarg, "none") == 0) ? 0 : optarg[0];
+                break;
+            case 'n':
+                close_stdin();
+                break;
+            case 'x':
+                // This option basically asks for historical behavior, so set options that
+                // correspond to the historical defaults. This is slightly weird in that -Tx
+                // is fine (because we'll undo the -T) but -xT isn't, but that does seem to
+                // be our least worst choice...
+                use_shell_protocol = false;
+                tty = kPtyDefinitely;
+                escape_char = '~';
+                break;
+            case 't':
+                // Like ssh, -t arguments are cumulative so that multiple -t's
+                // are needed to force a PTY.
+                tty = (tty >= kPtyYes) ? kPtyDefinitely : kPtyYes;
+                break;
+            case 'T':
+                tty = kPtyNo;
+                break;
+            default:
+                // getopt(3) already printed an error message for us.
                 return 1;
-            }
-            escape_char = (strcmp(argv[1], "none") == 0) ? 0 : argv[1][0];
-            argc -= 2;
-            argv += 2;
-        } else if (!strcmp(argv[0], "-T") || !strcmp(argv[0], "-t")) {
-            // Like ssh, -t arguments are cumulative so that multiple -t's
-            // are needed to force a PTY.
-            if (argv[0][1] == 't') {
-                ++t_arg_count;
-            } else {
-                t_arg_count = -1;
-            }
-            --argc;
-            ++argv;
-        } else if (!strcmp(argv[0], "-x")) {
-            use_shell_protocol = false;
-            --argc;
-            ++argv;
-        } else if (!strcmp(argv[0], "-n")) {
-            close_stdin();
-
-            --argc;
-            ++argv;
-        } else {
-            break;
         }
     }
 
-    // Legacy shell protocol requires a remote PTY to close the subprocess properly which creates
-    // some weird interactions with -tT.
-    if (!use_shell_protocol && t_arg_count != 0) {
-        if (!CanUseFeature(features, kFeatureShell2)) {
-            fprintf(stderr, "error: target doesn't support PTY args -Tt\n");
-        } else {
-            fprintf(stderr, "error: PTY args -Tt cannot be used with -x\n");
-        }
-        return 1;
-    }
+    bool is_interactive = (optind == argc);
 
-    std::string shell_type_arg;
-    if (CanUseFeature(features, kFeatureShell2)) {
-        if (t_arg_count < 0) {
+    std::string shell_type_arg = kShellServiceArgPty;
+    if (tty == kPtyNo) {
+        shell_type_arg = kShellServiceArgRaw;
+    } else if (tty == kPtyAuto) {
+        // If stdin isn't a TTY, default to a raw shell; this lets
+        // things like `adb shell < my_script.sh` work as expected.
+        // Non-interactive shells should also not have a pty.
+        if (!unix_isatty(STDIN_FILENO) || !is_interactive) {
             shell_type_arg = kShellServiceArgRaw;
-        } else if (t_arg_count == 0) {
-            // If stdin isn't a TTY, default to a raw shell; this lets
-            // things like `adb shell < my_script.sh` work as expected.
-            // Otherwise leave |shell_type_arg| blank which uses PTY for
-            // interactive shells and raw for non-interactive.
-            if (!unix_isatty(STDIN_FILENO)) {
-                shell_type_arg = kShellServiceArgRaw;
-            }
-        } else if (t_arg_count == 1) {
-            // A single -t arg isn't enough to override implicit -T.
-            if (!unix_isatty(STDIN_FILENO)) {
-                fprintf(stderr,
-                        "Remote PTY will not be allocated because stdin is not a terminal.\n"
-                        "Use multiple -t options to force remote PTY allocation.\n");
-                shell_type_arg = kShellServiceArgRaw;
-            } else {
-                shell_type_arg = kShellServiceArgPty;
-            }
+        }
+    } else if (tty == kPtyYes) {
+        // A single -t arg isn't enough to override implicit -T.
+        if (!unix_isatty(STDIN_FILENO)) {
+            fprintf(stderr,
+                    "Remote PTY will not be allocated because stdin is not a terminal.\n"
+                    "Use multiple -t options to force remote PTY allocation.\n");
+            shell_type_arg = kShellServiceArgRaw;
+        }
+    }
+
+    D("shell -e 0x%x t=%d use_shell_protocol=%s shell_type_arg=%s\n",
+      escape_char, tty,
+      use_shell_protocol ? "true" : "false",
+      (shell_type_arg == kShellServiceArgPty) ? "pty" : "raw");
+
+    // Raw mode is only supported when talking to a new device *and* using the shell protocol.
+    if (!use_shell_protocol) {
+        if (shell_type_arg != kShellServiceArgPty) {
+            fprintf(stderr, "error: %s only supports allocating a pty\n",
+                    !CanUseFeature(features, kFeatureShell2) ? "device" : "-x");
+            return 1;
         } else {
-            shell_type_arg = kShellServiceArgPty;
+            // If we're not using the shell protocol, the type argument must be empty.
+            shell_type_arg = "";
         }
     }
 
     std::string command;
-    if (argc) {
+    if (optind < argc) {
         // We don't escape here, just like ssh(1). http://b/20564385.
-        command = android::base::Join(std::vector<const char*>(argv, argv + argc), ' ');
+        command = android::base::Join(std::vector<const char*>(argv + optind, argv + argc), ' ');
     }
 
     return RemoteShell(use_shell_protocol, shell_type_arg, escape_char, command);
@@ -885,47 +860,46 @@
  *   we hang up.
  */
 static int adb_sideload_host(const char* fn) {
-    unsigned sz;
-    size_t xfer = 0;
-    int status;
-    int last_percent = -1;
-    int opt = SIDELOAD_HOST_BLOCK_SIZE;
+    fprintf(stderr, "loading: '%s'...\n", fn);
 
-    printf("loading: '%s'", fn);
-    fflush(stdout);
-    uint8_t* data = reinterpret_cast<uint8_t*>(load_file(fn, &sz));
-    if (data == 0) {
-        printf("\n");
-        fprintf(stderr, "* cannot read '%s' *\n", fn);
+    std::string content;
+    if (!android::base::ReadFileToString(fn, &content)) {
+        fprintf(stderr, "failed: %s\n", strerror(errno));
         return -1;
     }
 
+    const uint8_t* data = reinterpret_cast<const uint8_t*>(content.data());
+    unsigned sz = content.size();
+
+    fprintf(stderr, "connecting...\n");
     std::string service =
             android::base::StringPrintf("sideload-host:%d:%d", sz, SIDELOAD_HOST_BLOCK_SIZE);
     std::string error;
-    int fd = adb_connect(service, &error);
+    unique_fd fd(adb_connect(service, &error));
     if (fd < 0) {
         // Try falling back to the older sideload method.  Maybe this
         // is an older device that doesn't support sideload-host.
-        printf("\n");
-        status = adb_download_buffer("sideload", fn, data, sz, true);
-        goto done;
+        fprintf(stderr, "falling back to older sideload method...\n");
+        return adb_download_buffer("sideload", fn, data, sz, true);
     }
 
-    opt = adb_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
+    int opt = SIDELOAD_HOST_BLOCK_SIZE;
+    adb_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt));
 
+    size_t xfer = 0;
+    int last_percent = -1;
     while (true) {
         char buf[9];
         if (!ReadFdExactly(fd, buf, 8)) {
             fprintf(stderr, "* failed to read command: %s\n", strerror(errno));
-            status = -1;
-            goto done;
+            return -1;
         }
         buf[8] = '\0';
 
         if (strcmp("DONEDONE", buf) == 0) {
-            status = 0;
-            break;
+            printf("\rTotal xfer: %.2fx%*s\n",
+                   (double)xfer / (sz ? sz : 1), (int)strlen(fn)+10, "");
+            return 0;
         }
 
         int block = strtol(buf, NULL, 10);
@@ -933,21 +907,19 @@
         size_t offset = block * SIDELOAD_HOST_BLOCK_SIZE;
         if (offset >= sz) {
             fprintf(stderr, "* attempt to read block %d past end\n", block);
-            status = -1;
-            goto done;
+            return -1;
         }
-        uint8_t* start = data + offset;
+        const uint8_t* start = data + offset;
         size_t offset_end = offset + SIDELOAD_HOST_BLOCK_SIZE;
         size_t to_write = SIDELOAD_HOST_BLOCK_SIZE;
         if (offset_end > sz) {
             to_write = sz - offset;
         }
 
-        if(!WriteFdExactly(fd, start, to_write)) {
+        if (!WriteFdExactly(fd, start, to_write)) {
             adb_status(fd, &error);
             fprintf(stderr,"* failed to write data '%s' *\n", error.c_str());
-            status = -1;
-            goto done;
+            return -1;
         }
         xfer += to_write;
 
@@ -964,13 +936,6 @@
             last_percent = percent;
         }
     }
-
-    printf("\rTotal xfer: %.2fx%*s\n", (double)xfer / (sz ? sz : 1), (int)strlen(fn)+10, "");
-
-  done:
-    if (fd >= 0) adb_close(fd);
-    free(data);
-    return status;
 }
 
 /**
@@ -1081,10 +1046,9 @@
 
 static bool adb_root(const char* command) {
     std::string error;
-    ScopedFd fd;
 
-    fd.Reset(adb_connect(android::base::StringPrintf("%s:", command), &error));
-    if (!fd.valid()) {
+    unique_fd fd(adb_connect(android::base::StringPrintf("%s:", command), &error));
+    if (fd < 0) {
         fprintf(stderr, "adb: unable to connect for %s: %s\n", command, error.c_str());
         return false;
     }
@@ -1094,7 +1058,7 @@
     char* cur = buf;
     ssize_t bytes_left = sizeof(buf);
     while (bytes_left > 0) {
-        ssize_t bytes_read = adb_read(fd.fd(), cur, bytes_left);
+        ssize_t bytes_read = adb_read(fd, cur, bytes_left);
         if (bytes_read == 0) {
             break;
         } else if (bytes_read < 0) {
@@ -1116,12 +1080,10 @@
         return true;
     }
 
-    // Give adbd 500ms to kill itself, then wait-for-device for it to come back up.
-    adb_sleep_ms(500);
-    TransportType type;
-    const char* serial;
-    adb_get_transport(&type, &serial);
-    return wait_for_device("wait-for-any", type, serial);
+    // Give adbd some time to kill itself and come back up.
+    // We can't use wait-for-device because devices (e.g. adb over network) might not come back.
+    std::this_thread::sleep_for(3s);
+    return true;
 }
 
 int send_shell_command(TransportType transport_type, const char* serial, const std::string& command,
@@ -1325,9 +1287,10 @@
         return hint;
     }
 
-    // If there are any slashes in it, assume it's a relative path;
+    // If any of the OS_PATH_SEPARATORS is found, assume it's a relative path;
     // make it absolute.
-    if (hint.find_first_of(OS_PATH_SEPARATORS) != std::string::npos) {
+    // NOLINT: Do not complain if OS_PATH_SEPARATORS has only one character.
+    if (hint.find_first_of(OS_PATH_SEPARATORS) != std::string::npos) {  // NOLINT
         std::string cwd;
         if (!getcwd(&cwd)) {
             perror("adb: getcwd failed");
@@ -1440,7 +1403,7 @@
     return !CanUseFeature(features, kFeatureCmd);
 }
 
-int adb_commandline(int argc, const char **argv) {
+int adb_commandline(int argc, const char** argv) {
     int no_daemon = 0;
     int is_daemon = 0;
     int is_server = 0;
@@ -1464,18 +1427,9 @@
     }
     // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
 
-    /* Validate and assign the server port */
-    const char* server_port_str = getenv("ANDROID_ADB_SERVER_PORT");
-    int server_port = DEFAULT_ADB_PORT;
-    if (server_port_str && strlen(server_port_str) > 0) {
-        server_port = strtol(server_port_str, nullptr, 0);
-        if (server_port <= 0 || server_port > 65535) {
-            fprintf(stderr,
-                    "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive number less than 65536. Got \"%s\"\n",
-                    server_port_str);
-            return usage();
-        }
-    }
+    const char* server_host_str = nullptr;
+    const char* server_port_str = nullptr;
+    const char* server_socket_str = nullptr;
 
     // We need to check for -d and -e before we look at $ANDROID_SERIAL.
     const char* serial = nullptr;
@@ -1529,17 +1483,14 @@
         } else if (!strcmp(argv[0],"-a")) {
             gListenAll = 1;
         } else if (!strncmp(argv[0], "-H", 2)) {
-            const char *hostname = NULL;
             if (argv[0][2] == '\0') {
                 if (argc < 2) return usage();
-                hostname = argv[1];
+                server_host_str = argv[1];
                 argc--;
                 argv++;
             } else {
-                hostname = argv[0] + 2;
+                server_host_str = argv[0] + 2;
             }
-            adb_set_tcp_name(hostname);
-
         } else if (!strncmp(argv[0], "-P", 2)) {
             if (argv[0][2] == '\0') {
                 if (argc < 2) return usage();
@@ -1549,34 +1500,67 @@
             } else {
                 server_port_str = argv[0] + 2;
             }
-            if (strlen(server_port_str) > 0) {
-                server_port = (int) strtol(server_port_str, NULL, 0);
-                if (server_port <= 0 || server_port > 65535) {
-                    fprintf(stderr,
-                            "adb: port number must be a positive number less than 65536. Got \"%s\"\n",
-                            server_port_str);
-                    return usage();
-                }
-            } else {
-                fprintf(stderr,
-                "adb: port number must be a positive number less than 65536. Got empty string.\n");
-                return usage();
-            }
+        } else if (!strcmp(argv[0], "-L")) {
+            if (argc < 2) return usage();
+            server_socket_str = argv[1];
+            argc--;
+            argv++;
         } else {
-                /* out of recognized modifiers and flags */
+            /* out of recognized modifiers and flags */
             break;
         }
         argc--;
         argv++;
     }
 
+    if ((server_host_str || server_port_str) && server_socket_str) {
+        fprintf(stderr, "adb: -L is incompatible with -H or -P\n");
+        exit(1);
+    }
+
+    // If -L, -H, or -P are specified, ignore environment variables.
+    // Otherwise, prefer ADB_SERVER_SOCKET over ANDROID_ADB_SERVER_ADDRESS/PORT.
+    if (!server_host_str && !server_port_str && !server_socket_str) {
+        server_socket_str = getenv("ADB_SERVER_SOCKET");
+    }
+
+    if (!server_socket_str) {
+        // tcp:1234 and tcp:localhost:1234 are different with -a, so don't default to localhost
+        server_host_str = server_host_str ? server_host_str : getenv("ANDROID_ADB_SERVER_ADDRESS");
+
+        int server_port = DEFAULT_ADB_PORT;
+        server_port_str = server_port_str ? server_port_str : getenv("ANDROID_ADB_SERVER_PORT");
+        if (server_port_str && strlen(server_port_str) > 0) {
+            if (!android::base::ParseInt(server_port_str, &server_port, 1, 65535)) {
+                fprintf(stderr,
+                        "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive"
+                        " number less than 65535. Got \"%s\"\n",
+                        server_port_str);
+                exit(1);
+            }
+        }
+
+        int rc;
+        char* temp;
+        if (server_host_str) {
+            rc = asprintf(&temp, "tcp:%s:%d", server_host_str, server_port);
+        } else {
+            rc = asprintf(&temp, "tcp:%d", server_port);
+        }
+        if (rc < 0) {
+            fatal("failed to allocate server socket specification");
+        }
+        server_socket_str = temp;
+    }
+
+    adb_set_socket_spec(server_socket_str);
+
     // If none of -d, -e, or -s were specified, try $ANDROID_SERIAL.
     if (transport_type == kTransportAny && serial == nullptr) {
         serial = getenv("ANDROID_SERIAL");
     }
 
     adb_set_transport(transport_type, serial);
-    adb_set_tcp_specifics(server_port);
 
     if (is_server) {
         if (no_daemon || is_daemon) {
@@ -1584,9 +1568,9 @@
                 fprintf(stderr, "reply fd for adb server to client communication not specified.\n");
                 return usage();
             }
-            r = adb_server_main(is_daemon, server_port, ack_reply_fd);
+            r = adb_server_main(is_daemon, server_socket_str, ack_reply_fd);
         } else {
-            r = launch_server(server_port);
+            r = launch_server(server_socket_str);
         }
         if (r) {
             fprintf(stderr,"* could not start server *\n");
@@ -1661,6 +1645,11 @@
     else if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {
         int exec_in = !strcmp(argv[0], "exec-in");
 
+        if (argc < 2) {
+            fprintf(stderr, "Usage: adb %s command\n", argv[0]);
+            return 1;
+        }
+
         std::string cmd = "exec:";
         cmd += argv[1];
         argc -= 2;
@@ -1759,7 +1748,7 @@
             }
         }
 
-        std::string cmd;
+        std::string cmd, error;
         if (strcmp(argv[0], "--list") == 0) {
             if (argc != 1) return usage();
             return adb_query_command(host_prefix + ":list-forward");
@@ -1773,14 +1762,37 @@
         } else if (strcmp(argv[0], "--no-rebind") == 0) {
             // forward --no-rebind <local> <remote>
             if (argc != 3) return usage();
-            cmd = host_prefix + ":forward:norebind:" + argv[1] + ";" + argv[2];
+            if (forward_targets_are_valid(argv[1], argv[2], &error)) {
+                cmd = host_prefix + ":forward:norebind:" + argv[1] + ";" + argv[2];
+            }
         } else {
             // forward <local> <remote>
             if (argc != 2) return usage();
-            cmd = host_prefix + ":forward:" + argv[0] + ";" + argv[1];
+            if (forward_targets_are_valid(argv[0], argv[1], &error)) {
+                cmd = host_prefix + ":forward:" + argv[0] + ";" + argv[1];
+            }
         }
 
-        return adb_command(cmd) ? 0 : 1;
+        if (!error.empty()) {
+            fprintf(stderr, "error: %s\n", error.c_str());
+            return 1;
+        }
+
+        int fd = adb_connect(cmd, &error);
+        if (fd < 0 || !adb_status(fd, &error)) {
+            adb_close(fd);
+            fprintf(stderr, "error: %s\n", error.c_str());
+            return 1;
+        }
+
+        // Server or device may optionally return a resolved TCP port number.
+        std::string resolved_port;
+        if (ReadProtocolString(fd, &resolved_port, &error) && !resolved_port.empty()) {
+            printf("%s\n", resolved_port.c_str());
+        }
+
+        ReadOrderlyShutdown(fd);
+        return 0;
     }
     /* do_sync_*() commands */
     else if (!strcmp(argv[0], "ls")) {
@@ -1905,6 +1917,14 @@
     else if (!strcmp(argv[0], "jdwp")) {
         return adb_connect_command("jdwp");
     }
+    else if (!strcmp(argv[0], "track-jdwp")) {
+        return adb_connect_command("track-jdwp");
+    }
+    else if (!strcmp(argv[0], "track-devices")) {
+        return adb_connect_command("host:track-devices");
+    }
+
+
     /* "adb /?" is a common idiom under Windows */
     else if (!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
         help();
@@ -1932,10 +1952,17 @@
     } else if (!strcmp(argv[0], "reconnect")) {
         if (argc == 1) {
             return adb_query_command("host:reconnect");
-        } else if (argc == 2 && !strcmp(argv[1], "device")) {
-            std::string err;
-            adb_connect("reconnect", &err);
-            return 0;
+        } else if (argc == 2) {
+            if (!strcmp(argv[1], "device")) {
+                std::string err;
+                adb_connect("reconnect", &err);
+                return 0;
+            } else if (!strcmp(argv[1], "offline")) {
+                std::string err;
+                return adb_query_command("host:reconnect-offline");
+            } else {
+                return usage();
+            }
         }
     }
 
@@ -1965,20 +1992,15 @@
 static int install_app(TransportType transport, const char* serial, int argc, const char** argv) {
     // The last argument must be the APK file
     const char* file = argv[argc - 1];
-    const char* dot = strrchr(file, '.');
-    bool found_apk = false;
-    struct stat sb;
-    if (dot && !strcasecmp(dot, ".apk")) {
-        if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
-            fprintf(stderr, "Invalid APK file: %s\n", file);
-            return EXIT_FAILURE;
-        }
-        found_apk = true;
+    if (!android::base::EndsWithIgnoreCase(file, ".apk")) {
+        fprintf(stderr, "Filename doesn't end .apk: %s\n", file);
+        return EXIT_FAILURE;
     }
 
-    if (!found_apk) {
-        fprintf(stderr, "Missing APK file\n");
-        return EXIT_FAILURE;
+    struct stat sb;
+    if (stat(file, &sb) == -1) {
+        fprintf(stderr, "Failed to stat %s: %s\n", file, strerror(errno));
+        return 1;
     }
 
     int localFd = adb_open(file, O_RDONLY);
@@ -2024,22 +2046,16 @@
 static int install_multiple_app(TransportType transport, const char* serial, int argc,
                                 const char** argv)
 {
-    int i;
-    struct stat sb;
-    uint64_t total_size = 0;
     // Find all APK arguments starting at end.
     // All other arguments passed through verbatim.
     int first_apk = -1;
-    for (i = argc - 1; i >= 0; i--) {
+    uint64_t total_size = 0;
+    for (int i = argc - 1; i >= 0; i--) {
         const char* file = argv[i];
-        const char* dot = strrchr(file, '.');
-        if (dot && !strcasecmp(dot, ".apk")) {
-            if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
-                fprintf(stderr, "Invalid APK file: %s\n", file);
-                return EXIT_FAILURE;
-            }
 
-            total_size += sb.st_size;
+        if (android::base::EndsWithIgnoreCase(file, ".apk")) {
+            struct stat sb;
+            if (stat(file, &sb) != -1) total_size += sb.st_size;
             first_apk = i;
         } else {
             break;
@@ -2047,7 +2063,7 @@
     }
 
     if (first_apk == -1) {
-        fprintf(stderr, "Missing APK file\n");
+        fprintf(stderr, "No APK file on command line\n");
         return 1;
     }
 
@@ -2059,7 +2075,7 @@
     }
 
     std::string cmd = android::base::StringPrintf("%s install-create -S %" PRIu64, install_cmd.c_str(), total_size);
-    for (i = 1; i < first_apk; i++) {
+    for (int i = 1; i < first_apk; i++) {
         cmd += " " + escape_arg(argv[i]);
     }
 
@@ -2091,10 +2107,11 @@
 
     // Valid session, now stream the APKs
     int success = 1;
-    for (i = first_apk; i < argc; i++) {
+    for (int i = first_apk; i < argc; i++) {
         const char* file = argv[i];
+        struct stat sb;
         if (stat(file, &sb) == -1) {
-            fprintf(stderr, "Failed to stat %s\n", file);
+            fprintf(stderr, "Failed to stat %s: %s\n", file, strerror(errno));
             success = 0;
             goto finalize_session;
         }
@@ -2194,10 +2211,8 @@
     static const char *const DATA_DEST = "/data/local/tmp/%s";
     static const char *const SD_DEST = "/sdcard/tmp/%s";
     const char* where = DATA_DEST;
-    int i;
-    struct stat sb;
 
-    for (i = 1; i < argc; i++) {
+    for (int i = 1; i < argc; i++) {
         if (!strcmp(argv[i], "-s")) {
             where = SD_DEST;
         }
@@ -2206,22 +2221,15 @@
     // Find last APK argument.
     // All other arguments passed through verbatim.
     int last_apk = -1;
-    for (i = argc - 1; i >= 0; i--) {
-        const char* file = argv[i];
-        const char* dot = strrchr(file, '.');
-        if (dot && !strcasecmp(dot, ".apk")) {
-            if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
-                fprintf(stderr, "Invalid APK file: %s\n", file);
-                return EXIT_FAILURE;
-            }
-
+    for (int i = argc - 1; i >= 0; i--) {
+        if (android::base::EndsWithIgnoreCase(argv[i], ".apk")) {
             last_apk = i;
             break;
         }
     }
 
     if (last_apk == -1) {
-        fprintf(stderr, "Missing APK file\n");
+        fprintf(stderr, "No APK file on command line\n");
         return EXIT_FAILURE;
     }
 
diff --git a/adb/console.cpp b/adb/console.cpp
index e9b90a5..9563eac 100644
--- a/adb/console.cpp
+++ b/adb/console.cpp
@@ -32,7 +32,7 @@
 static std::string adb_construct_auth_command() {
     static const char auth_token_filename[] = ".emulator_console_auth_token";
 
-    std::string auth_token_path = adb_get_homedir_path(false);
+    std::string auth_token_path = adb_get_homedir_path();
     auth_token_path += OS_PATH_SEPARATOR;
     auth_token_path += auth_token_filename;
 
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 4721e2f..78434a0 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -28,11 +28,15 @@
 #include <memory>
 
 #include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <libminijail.h>
+#include <scoped_minijail.h>
 
-#include "cutils/properties.h"
-#include "private/android_filesystem_config.h"
+#include "debuggerd/client.h"
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
 #include "selinux/android.h"
 
 #include "adb.h"
@@ -43,30 +47,17 @@
 
 static const char* root_seclabel = nullptr;
 
-static void drop_capabilities_bounding_set_if_needed() {
-#ifdef ALLOW_ADBD_ROOT
-    char value[PROPERTY_VALUE_MAX];
-    property_get("ro.debuggable", value, "");
-    if (strcmp(value, "1") == 0) {
+static void drop_capabilities_bounding_set_if_needed(struct minijail *j) {
+#if defined(ALLOW_ADBD_ROOT)
+    if (__android_log_is_debuggable()) {
         return;
     }
 #endif
-    for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
-        if (i == CAP_SETUID || i == CAP_SETGID) {
-            // CAP_SETUID CAP_SETGID needed by /system/bin/run-as
-            continue;
-        }
-
-        if (prctl(PR_CAPBSET_DROP, i, 0, 0, 0) == -1) {
-            PLOG(FATAL) << "Could not drop capabilities";
-        }
-    }
+    minijail_capbset_drop(j, CAP_TO_MASK(CAP_SETUID) | CAP_TO_MASK(CAP_SETGID));
 }
 
 static bool should_drop_privileges() {
 #if defined(ALLOW_ADBD_ROOT)
-    char value[PROPERTY_VALUE_MAX];
-
     // The properties that affect `adb root` and `adb unroot` are ro.secure and
     // ro.debuggable. In this context the names don't make the expected behavior
     // particularly obvious.
@@ -77,24 +68,19 @@
     //
     // ro.secure:
     //   Drop privileges by default. Set to 1 on userdebug and user builds.
-    property_get("ro.secure", value, "1");
-    bool ro_secure = (strcmp(value, "1") == 0);
-
-    property_get("ro.debuggable", value, "");
-    bool ro_debuggable = (strcmp(value, "1") == 0);
+    bool ro_secure = android::base::GetBoolProperty("ro.secure", true);
+    bool ro_debuggable = __android_log_is_debuggable();
 
     // Drop privileges if ro.secure is set...
     bool drop = ro_secure;
 
-    property_get("service.adb.root", value, "");
-    bool adb_root = (strcmp(value, "1") == 0);
-    bool adb_unroot = (strcmp(value, "0") == 0);
-
     // ... except "adb root" lets you keep privileges in a debuggable build.
+    std::string prop = android::base::GetProperty("service.adb.root", "");
+    bool adb_root = (prop == "1");
+    bool adb_unroot = (prop == "0");
     if (ro_debuggable && adb_root) {
         drop = false;
     }
-
     // ... and "adb unroot" lets you explicitly drop privileges.
     if (adb_unroot) {
         drop = true;
@@ -107,8 +93,7 @@
 }
 
 static void drop_privileges(int server_port) {
-    std::unique_ptr<minijail, void (*)(minijail*)> jail(minijail_new(),
-                                                        &minijail_destroy);
+    ScopedMinijail jail(minijail_new());
 
     // Add extra groups:
     // AID_ADB to access the USB driver
@@ -124,14 +109,12 @@
                       AID_INET,     AID_NET_BT,    AID_NET_BT_ADMIN,
                       AID_SDCARD_R, AID_SDCARD_RW, AID_NET_BW_STATS,
                       AID_READPROC};
-    minijail_set_supplementary_gids(jail.get(),
-                                    sizeof(groups) / sizeof(groups[0]),
-                                    groups);
+    minijail_set_supplementary_gids(jail.get(), arraysize(groups), groups);
 
     // Don't listen on a port (default 5037) if running in secure mode.
     // Don't run as root if running in secure mode.
     if (should_drop_privileges()) {
-        drop_capabilities_bounding_set_if_needed();
+        drop_capabilities_bounding_set_if_needed(jail.get());
 
         minijail_change_gid(jail.get(), AID_SHELL);
         minijail_change_uid(jail.get(), AID_SHELL);
@@ -151,10 +134,8 @@
         std::string error;
         std::string local_name =
             android::base::StringPrintf("tcp:%d", server_port);
-        if (install_listener(local_name, "*smartsocket*", nullptr, 0,
-                             &error)) {
-            LOG(FATAL) << "Could not install *smartsocket* listener: "
-                       << error;
+        if (install_listener(local_name, "*smartsocket*", nullptr, 0, nullptr, &error)) {
+            LOG(FATAL) << "Could not install *smartsocket* listener: " << error;
         }
     }
 }
@@ -170,7 +151,7 @@
     // descriptor will always be open.
     adbd_cloexec_auth_socket();
 
-    if (ALLOW_ADBD_NO_AUTH && property_get_bool("ro.adb.secure", 0) == 0) {
+    if (ALLOW_ADBD_NO_AUTH && !android::base::GetBoolProperty("ro.adb.secure", false)) {
         auth_required = false;
     }
 
@@ -198,14 +179,13 @@
     // If one of these properties is set, also listen on that port.
     // If one of the properties isn't set and we couldn't listen on usb, listen
     // on the default port.
-    char prop_port[PROPERTY_VALUE_MAX];
-    property_get("service.adb.tcp.port", prop_port, "");
-    if (prop_port[0] == '\0') {
-        property_get("persist.adb.tcp.port", prop_port, "");
+    std::string prop_port = android::base::GetProperty("service.adb.tcp.port", "");
+    if (prop_port.empty()) {
+        prop_port = android::base::GetProperty("persist.adb.tcp.port", "");
     }
 
     int port;
-    if (sscanf(prop_port, "%d", &port) == 1 && port > 0) {
+    if (sscanf(prop_port.c_str(), "%d", &port) == 1 && port > 0) {
         D("using port=%d", port);
         // Listen on TCP port specified by service.adb.tcp.port property.
         local_init(port);
@@ -258,6 +238,7 @@
 
     close_stdin();
 
+    debuggerd_init(nullptr);
     adb_trace_init(argv);
 
     D("Handling main()");
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 902548e..04cd865 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -55,7 +55,7 @@
   fdevent* fde;
   adb_pollfd pollfd;
 
-  PollNode(fdevent* fde) : fde(fde) {
+  explicit PollNode(fdevent* fde) : fde(fde) {
       memset(&pollfd, 0, sizeof(pollfd));
       pollfd.fd = fde->fd;
 
diff --git a/adb/fdevent_test.h b/adb/fdevent_test.h
index c853bce..ef65b74 100644
--- a/adb/fdevent_test.h
+++ b/adb/fdevent_test.h
@@ -49,6 +49,16 @@
         dummy = dummy_fds[0];
     }
 
+    size_t GetAdditionalLocalSocketCount() {
+#if ADB_HOST
+        // dummy socket installed in PrepareThread()
+        return 1;
+#else
+        // dummy socket and one more socket installed in fdevent_subproc_setup()
+        return 2;
+#endif
+    }
+
     void TerminateThread(adb_thread_t thread) {
         fdevent_terminate_loop();
         ASSERT_TRUE(WriteFdExactly(dummy, "", 1));
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 651e8ca..115095c 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -28,8 +28,11 @@
 #include <unistd.h>
 #include <utime.h>
 
+#include <chrono>
 #include <functional>
 #include <memory>
+#include <sstream>
+#include <string>
 #include <vector>
 
 #include "sysdeps.h"
@@ -94,14 +97,112 @@
     }
 };
 
+enum class TransferDirection {
+    push,
+    pull,
+};
+
+struct TransferLedger {
+    std::chrono::steady_clock::time_point start_time;
+    uint64_t files_transferred;
+    uint64_t files_skipped;
+    uint64_t bytes_transferred;
+    uint64_t bytes_expected;
+    bool expect_multiple_files;
+
+    TransferLedger() {
+        Reset();
+    }
+
+    bool operator==(const TransferLedger& other) const {
+        return files_transferred == other.files_transferred &&
+               files_skipped == other.files_skipped && bytes_transferred == other.bytes_transferred;
+    }
+
+    bool operator!=(const TransferLedger& other) const {
+        return !(*this == other);
+    }
+
+    void Reset() {
+        start_time = std::chrono::steady_clock::now();
+        files_transferred = 0;
+        files_skipped = 0;
+        bytes_transferred = 0;
+        bytes_expected = 0;
+    }
+
+    std::string TransferRate() {
+        if (bytes_transferred == 0) return "";
+
+        std::chrono::duration<double> duration;
+        duration = std::chrono::steady_clock::now() - start_time;
+
+        double s = duration.count();
+        if (s == 0) {
+            return "";
+        }
+        double rate = (static_cast<double>(bytes_transferred) / s) / (1024 * 1024);
+        return android::base::StringPrintf(" %.1f MB/s (%" PRIu64 " bytes in %.3fs)", rate,
+                                           bytes_transferred, s);
+    }
+
+    void ReportProgress(LinePrinter& lp, const std::string& file, uint64_t file_copied_bytes,
+                        uint64_t file_total_bytes) {
+        char overall_percentage_str[5] = "?";
+        if (bytes_expected != 0 && bytes_transferred <= bytes_expected) {
+            int overall_percentage = static_cast<int>(bytes_transferred * 100 / bytes_expected);
+            // If we're pulling symbolic links, we'll pull the target of the link rather than
+            // just create a local link, and that will cause us to go over 100%.
+            if (overall_percentage <= 100) {
+                snprintf(overall_percentage_str, sizeof(overall_percentage_str), "%d%%",
+                         overall_percentage);
+            }
+        }
+
+        std::string output;
+        if (file_copied_bytes > file_total_bytes || file_total_bytes == 0) {
+            // This case can happen if we're racing against something that wrote to the file
+            // between our stat and our read, or if we're reading a magic file that lies about
+            // its size. Just show how much we've copied.
+            output = android::base::StringPrintf("[%4s] %s: %" PRId64 "/?", overall_percentage_str,
+                                                 file.c_str(), file_copied_bytes);
+        } else {
+            // If we're transferring multiple files, we want to know how far through the current
+            // file we are, as well as the overall percentage.
+            if (expect_multiple_files) {
+                int file_percentage = static_cast<int>(file_copied_bytes * 100 / file_total_bytes);
+                output = android::base::StringPrintf("[%4s] %s: %d%%", overall_percentage_str,
+                                                     file.c_str(), file_percentage);
+            } else {
+                output =
+                    android::base::StringPrintf("[%4s] %s", overall_percentage_str, file.c_str());
+            }
+        }
+        lp.Print(output, LinePrinter::LineType::INFO);
+    }
+
+    void ReportTransferRate(LinePrinter& lp, const std::string& name, TransferDirection direction) {
+        const char* direction_str = (direction == TransferDirection::push) ? "pushed" : "pulled";
+        std::stringstream ss;
+        if (!name.empty()) {
+            ss << name << ": ";
+        }
+        ss << files_transferred << " file" << ((files_transferred == 1) ? "" : "s") << " "
+           << direction_str << ".";
+        if (files_skipped > 0) {
+            ss << " " << files_skipped << " file" << ((files_skipped == 1) ? "" : "s")
+               << " skipped.";
+        }
+        ss << TransferRate();
+
+        lp.Print(ss.str(), LinePrinter::LineType::INFO);
+        lp.KeepInfoLine();
+    }
+};
+
 class SyncConnection {
   public:
-    SyncConnection()
-            : total_bytes_(0),
-              start_time_ms_(CurrentTimeMs()),
-              expected_total_bytes_(0),
-              expect_multiple_files_(false),
-              expect_done_(false) {
+    SyncConnection() : expect_done_(false) {
         max = SYNC_DATA_MAX; // TODO: decide at runtime.
 
         std::string error;
@@ -140,6 +241,40 @@
         return rc != 0;
     }
 
+    void NewTransfer() {
+        current_ledger_.Reset();
+    }
+
+    void RecordBytesTransferred(size_t bytes) {
+        current_ledger_.bytes_transferred += bytes;
+        global_ledger_.bytes_transferred += bytes;
+    }
+
+    void RecordFilesTransferred(size_t files) {
+        current_ledger_.files_transferred += files;
+        global_ledger_.files_transferred += files;
+    }
+
+    void RecordFilesSkipped(size_t files) {
+        current_ledger_.files_skipped += files;
+        global_ledger_.files_skipped += files;
+    }
+
+    void ReportProgress(const std::string& file, uint64_t file_copied_bytes,
+                        uint64_t file_total_bytes) {
+        current_ledger_.ReportProgress(line_printer_, file, file_copied_bytes, file_total_bytes);
+    }
+
+    void ReportTransferRate(const std::string& file, TransferDirection direction) {
+        current_ledger_.ReportTransferRate(line_printer_, file, direction);
+    }
+
+    void ReportOverallTransferRate(TransferDirection direction) {
+        if (current_ledger_ != global_ledger_) {
+            global_ledger_.ReportTransferRate(line_printer_, "", direction);
+        }
+    }
+
     bool SendRequest(int id, const char* path_and_mode) {
         size_t path_length = strlen(path_and_mode);
         if (path_length > 1024) {
@@ -199,7 +334,9 @@
 
         WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0]));
         expect_done_ = true;
-        total_bytes_ += data_length;
+
+        // RecordFilesTransferred gets called in CopyDone.
+        RecordBytesTransferred(data_length);
         ReportProgress(rpath, data_length, data_length);
         return true;
     }
@@ -242,7 +379,7 @@
             sbuf.size = bytes_read;
             WriteOrDie(lpath, rpath, &sbuf, sizeof(SyncRequest) + bytes_read);
 
-            total_bytes_ += bytes_read;
+            RecordBytesTransferred(bytes_read);
             bytes_copied += bytes_read;
 
             // Check to see if we've received an error from the other side.
@@ -259,6 +396,8 @@
         msg.data.id = ID_DONE;
         msg.data.size = mtime;
         expect_done_ = true;
+
+        // RecordFilesTransferred gets called in CopyDone.
         return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
     }
 
@@ -271,6 +410,7 @@
         if (msg.status.id == ID_OKAY) {
             if (expect_done_) {
                 expect_done_ = false;
+                RecordFilesTransferred(1);
                 return true;
             } else {
                 Error("failed to copy '%s' to '%s': received premature success", from, to);
@@ -296,44 +436,6 @@
         return false;
     }
 
-    std::string TransferRate() {
-        uint64_t ms = CurrentTimeMs() - start_time_ms_;
-        if (total_bytes_ == 0 || ms == 0) return "";
-
-        double s = static_cast<double>(ms) / 1000LL;
-        double rate = (static_cast<double>(total_bytes_) / s) / (1024*1024);
-        return android::base::StringPrintf(" %.1f MB/s (%" PRId64 " bytes in %.3fs)",
-                                           rate, total_bytes_, s);
-    }
-
-    void ReportProgress(const char* file, uint64_t file_copied_bytes, uint64_t file_total_bytes) {
-        char overall_percentage_str[5] = "?";
-        if (expected_total_bytes_ != 0) {
-            int overall_percentage = static_cast<int>(total_bytes_ * 100 / expected_total_bytes_);
-            // If we're pulling symbolic links, we'll pull the target of the link rather than
-            // just create a local link, and that will cause us to go over 100%.
-            if (overall_percentage <= 100) {
-                snprintf(overall_percentage_str, sizeof(overall_percentage_str), "%d%%",
-                         overall_percentage);
-            }
-        }
-
-        if (file_copied_bytes > file_total_bytes || file_total_bytes == 0) {
-            // This case can happen if we're racing against something that wrote to the file
-            // between our stat and our read, or if we're reading a magic file that lies about
-            // its size. Just show how much we've copied.
-            Printf("[%4s] %s: %" PRId64 "/?", overall_percentage_str, file, file_copied_bytes);
-        } else {
-            // If we're transferring multiple files, we want to know how far through the current
-            // file we are, as well as the overall percentage.
-            if (expect_multiple_files_) {
-                int file_percentage = static_cast<int>(file_copied_bytes * 100 / file_total_bytes);
-                Printf("[%4s] %s: %d%%", overall_percentage_str, file, file_percentage);
-            } else {
-                Printf("[%4s] %s", overall_percentage_str, file);
-            }
-        }
-    }
 
     void Printf(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
         std::string s;
@@ -346,6 +448,18 @@
         line_printer_.Print(s, LinePrinter::INFO);
     }
 
+    void Println(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
+        std::string s;
+
+        va_list ap;
+        va_start(ap, fmt);
+        android::base::StringAppendV(&s, fmt, ap);
+        va_end(ap);
+
+        line_printer_.Print(s, LinePrinter::INFO);
+        line_printer_.KeepInfoLine();
+    }
+
     void Error(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
         std::string s = "adb: error: ";
 
@@ -369,33 +483,29 @@
     }
 
     void ComputeExpectedTotalBytes(const std::vector<copyinfo>& file_list) {
-        expected_total_bytes_ = 0;
+        current_ledger_.bytes_expected = 0;
         for (const copyinfo& ci : file_list) {
             // Unfortunately, this doesn't work for symbolic links, because we'll copy the
             // target of the link rather than just creating a link. (But ci.size is the link size.)
-            if (!ci.skip) expected_total_bytes_ += ci.size;
+            if (!ci.skip) current_ledger_.bytes_expected += ci.size;
         }
-        expect_multiple_files_ = true;
+        current_ledger_.expect_multiple_files = true;
     }
 
     void SetExpectedTotalBytes(uint64_t expected_total_bytes) {
-        expected_total_bytes_ = expected_total_bytes;
-        expect_multiple_files_ = false;
+        current_ledger_.bytes_expected = expected_total_bytes;
+        current_ledger_.expect_multiple_files = false;
     }
 
-    uint64_t total_bytes_;
-
     // TODO: add a char[max] buffer here, to replace syncsendbuf...
     int fd;
     size_t max;
 
   private:
-    uint64_t start_time_ms_;
-
-    uint64_t expected_total_bytes_;
-    bool expect_multiple_files_;
     bool expect_done_;
 
+    TransferLedger global_ledger_;
+    TransferLedger current_ledger_;
     LinePrinter line_printer_;
 
     bool SendQuit() {
@@ -422,18 +532,12 @@
         }
         return true;
     }
-
-    static uint64_t CurrentTimeMs() {
-        struct timeval tv;
-        gettimeofday(&tv, 0); // (Not clock_gettime because of Mac/Windows.)
-        return static_cast<uint64_t>(tv.tv_sec) * 1000 + tv.tv_usec / 1000;
-    }
 };
 
 typedef void (sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name);
 
 static bool sync_ls(SyncConnection& sc, const char* path,
-                    std::function<sync_ls_cb> func) {
+                    const std::function<sync_ls_cb>& func) {
     if (!sc.SendRequest(ID_LIST, path)) return false;
 
     while (true) {
@@ -502,7 +606,7 @@
     }
     if (st.st_size < SYNC_DATA_MAX) {
         std::string data;
-        if (!android::base::ReadFileToString(lpath, &data)) {
+        if (!android::base::ReadFileToString(lpath, &data, true)) {
             sc.Error("failed to read all of '%s': %s", lpath, strerror(errno));
             return false;
         }
@@ -571,13 +675,13 @@
             return false;
         }
 
-        sc.total_bytes_ += msg.data.size;
-
         bytes_copied += msg.data.size;
 
+        sc.RecordBytesTransferred(msg.data.size);
         sc.ReportProgress(name != nullptr ? name : rpath, bytes_copied, size);
     }
 
+    sc.RecordFilesTransferred(1);
     adb_close(lfd);
     return true;
 }
@@ -662,13 +766,14 @@
 static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath,
                                   std::string rpath, bool check_timestamps,
                                   bool list_only) {
+    sc.NewTransfer();
+
     // Make sure that both directory paths end in a slash.
     // Both paths are known to be nonempty, so we don't need to check.
     ensure_trailing_separators(lpath, rpath);
 
     // Recursively build the list of files to copy.
     std::vector<copyinfo> file_list;
-    int pushed = 0;
     int skipped = 0;
     if (!local_build_list(sc, &file_list, lpath, rpath)) {
         return false;
@@ -700,21 +805,19 @@
     for (const copyinfo& ci : file_list) {
         if (!ci.skip) {
             if (list_only) {
-                sc.Error("would push: %s -> %s", ci.lpath.c_str(), ci.rpath.c_str());
+                sc.Println("would push: %s -> %s", ci.lpath.c_str(), ci.rpath.c_str());
             } else {
                 if (!sync_send(sc, ci.lpath.c_str(), ci.rpath.c_str(), ci.time, ci.mode)) {
                     return false;
                 }
             }
-            pushed++;
         } else {
             skipped++;
         }
     }
 
-    sc.Printf("%s: %d file%s pushed. %d file%s skipped.%s", rpath.c_str(),
-              pushed, (pushed == 1) ? "" : "s", skipped,
-              (skipped == 1) ? "" : "s", sc.TransferRate().c_str());
+    sc.RecordFilesSkipped(skipped);
+    sc.ReportTransferRate(lpath, TransferDirection::push);
     return true;
 }
 
@@ -790,10 +893,14 @@
             path_holder += adb_basename(src_path);
             dst_path = path_holder.c_str();
         }
+
+        sc.NewTransfer();
         sc.SetExpectedTotalBytes(st.st_size);
         success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode);
+        sc.ReportTransferRate(src_path, TransferDirection::push);
     }
 
+    sc.ReportOverallTransferRate(TransferDirection::push);
     return success;
 }
 
@@ -879,6 +986,8 @@
 
 static bool copy_remote_dir_local(SyncConnection& sc, std::string rpath,
                                   std::string lpath, bool copy_attrs) {
+    sc.NewTransfer();
+
     // Make sure that both directory paths end in a slash.
     // Both paths are known to be nonempty, so we don't need to check.
     ensure_trailing_separators(lpath, rpath);
@@ -892,7 +1001,6 @@
 
     sc.ComputeExpectedTotalBytes(file_list);
 
-    int pulled = 0;
     int skipped = 0;
     for (const copyinfo &ci : file_list) {
         if (!ci.skip) {
@@ -904,7 +1012,6 @@
                              ci.lpath.c_str(), strerror(errno));
                     return false;
                 }
-                pulled++;
                 continue;
             }
 
@@ -915,15 +1022,13 @@
             if (copy_attrs && set_time_and_mode(ci.lpath, ci.time, ci.mode)) {
                 return false;
             }
-            pulled++;
         } else {
             skipped++;
         }
     }
 
-    sc.Printf("%s: %d file%s pulled. %d file%s skipped.%s", rpath.c_str(),
-              pulled, (pulled == 1) ? "" : "s", skipped,
-              (skipped == 1) ? "" : "s", sc.TransferRate().c_str());
+    sc.RecordFilesSkipped(skipped);
+    sc.ReportTransferRate(rpath, TransferDirection::pull);
     return true;
 }
 
@@ -1022,6 +1127,7 @@
             dst_path = path_holder.c_str();
         }
 
+        sc.NewTransfer();
         sc.SetExpectedTotalBytes(src_size);
         if (!sync_recv(sc, src_path, dst_path, name)) {
             success = false;
@@ -1032,8 +1138,10 @@
             success = false;
             continue;
         }
+        sc.ReportTransferRate(src_path, TransferDirection::pull);
     }
 
+    sc.ReportOverallTransferRate(TransferDirection::pull);
     return success;
 }
 
@@ -1041,5 +1149,9 @@
     SyncConnection sc;
     if (!sc.IsValid()) return false;
 
-    return copy_local_dir_remote(sc, lpath, rpath, true, list_only);
+    bool success = copy_local_dir_remote(sc, lpath, rpath, true, list_only);
+    if (!list_only) {
+        sc.ReportOverallTransferRate(TransferDirection::push);
+    }
+    return success;
 }
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index 926dbcf..7a92d2e 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -21,25 +21,27 @@
 
 #include <dirent.h>
 #include <errno.h>
-#include <log/log.h>
-#include <selinux/android.h>
+#include <linux/xattr.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/xattr.h>
 #include <unistd.h>
 #include <utime.h>
 
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
+#include <selinux/android.h>
+
 #include "adb.h"
 #include "adb_io.h"
 #include "adb_utils.h"
-#include "private/android_filesystem_config.h"
 #include "security_log_tags.h"
 
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
 static bool should_use_fs_config(const std::string& path) {
     // TODO: use fs_config to configure permissions on /data.
     return android::base::StartsWith(path, "/system/") ||
@@ -47,11 +49,27 @@
            android::base::StartsWith(path, "/oem/");
 }
 
+static bool update_capabilities(const char* path, uint64_t capabilities) {
+    if (capabilities == 0) {
+        // Ensure we clean up in case the capabilities weren't 0 in the past.
+        removexattr(path, XATTR_NAME_CAPS);
+        return true;
+    }
+
+    vfs_cap_data cap_data = {};
+    cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE;
+    cap_data.data[0].permitted = (capabilities & 0xffffffff);
+    cap_data.data[0].inheritable = 0;
+    cap_data.data[1].permitted = (capabilities >> 32);
+    cap_data.data[1].inheritable = 0;
+    return setxattr(path, XATTR_NAME_CAPS, &cap_data, sizeof(cap_data), 0) != -1;
+}
+
 static bool secure_mkdirs(const std::string& path) {
     uid_t uid = -1;
     gid_t gid = -1;
     unsigned int mode = 0775;
-    uint64_t cap = 0;
+    uint64_t capabilities = 0;
 
     if (path[0] != '/') return false;
 
@@ -62,18 +80,19 @@
         partial_path += path_component;
 
         if (should_use_fs_config(partial_path)) {
-            fs_config(partial_path.c_str(), 1, nullptr, &uid, &gid, &mode, &cap);
+            fs_config(partial_path.c_str(), 1, nullptr, &uid, &gid, &mode, &capabilities);
         }
         if (adb_mkdir(partial_path.c_str(), mode) == -1) {
             if (errno != EEXIST) {
                 return false;
             }
         } else {
-            if (chown(partial_path.c_str(), uid, gid) == -1) {
-                return false;
-            }
+            if (chown(partial_path.c_str(), uid, gid) == -1) return false;
+
             // Not all filesystems support setting SELinux labels. http://b/23530370.
             selinux_android_restorecon(partial_path.c_str(), 0);
+
+            if (!update_capabilities(partial_path.c_str(), capabilities)) return false;
         }
     }
     return true;
@@ -83,8 +102,7 @@
     syncmsg msg;
     msg.stat.id = ID_STAT;
 
-    struct stat st;
-    memset(&st, 0, sizeof(st));
+    struct stat st = {};
     // TODO: add a way to report that the stat failed!
     lstat(path, &st);
     msg.stat.mode = st.st_mode;
@@ -146,8 +164,8 @@
     return SendSyncFail(fd, android::base::StringPrintf("%s: %s", reason.c_str(), strerror(errno)));
 }
 
-static bool handle_send_file(int s, const char* path, uid_t uid,
-                             gid_t gid, mode_t mode, std::vector<char>& buffer, bool do_unlink) {
+static bool handle_send_file(int s, const char* path, uid_t uid, gid_t gid, uint64_t capabilities,
+                             mode_t mode, std::vector<char>& buffer, bool do_unlink) {
     syncmsg msg;
     unsigned int timestamp = 0;
 
@@ -178,7 +196,7 @@
 
         // fchown clears the setuid bit - restore it if present.
         // Ignore the result of calling fchmod. It's not supported
-        // by all filesystems. b/12441485
+        // by all filesystems, so we don't check for success. b/12441485
         fchmod(fd, mode);
     }
 
@@ -209,6 +227,11 @@
 
     adb_close(fd);
 
+    if (!update_capabilities(path, capabilities)) {
+        SendSyncFailErrno(s, "update_capabilities failed");
+        goto fail;
+    }
+
     utimbuf u;
     u.actime = timestamp;
     u.modtime = timestamp;
@@ -338,13 +361,13 @@
 
     uid_t uid = -1;
     gid_t gid = -1;
-    uint64_t cap = 0;
+    uint64_t capabilities = 0;
     if (should_use_fs_config(path)) {
         unsigned int broken_api_hack = mode;
-        fs_config(path.c_str(), 0, nullptr, &uid, &gid, &broken_api_hack, &cap);
+        fs_config(path.c_str(), 0, nullptr, &uid, &gid, &broken_api_hack, &capabilities);
         mode = broken_api_hack;
     }
-    return handle_send_file(s, path.c_str(), uid, gid, mode, buffer, do_unlink);
+    return handle_send_file(s, path.c_str(), uid, gid, capabilities, mode, buffer, do_unlink);
 }
 
 static bool do_recv(int s, const char* path, std::vector<char>& buffer) {
diff --git a/adb/get_my_path_darwin.cpp b/adb/get_my_path_darwin.cpp
deleted file mode 100644
index b0c962e..0000000
--- a/adb/get_my_path_darwin.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#import <Carbon/Carbon.h>
-#include <unistd.h>
-
-#include "adb.h"
-
-void get_my_path(char *s, size_t maxLen)
-{
-    CFBundleRef mainBundle = CFBundleGetMainBundle();
-    CFURLRef executableURL = CFBundleCopyExecutableURL(mainBundle);
-    CFStringRef executablePathString = CFURLCopyFileSystemPath(executableURL, kCFURLPOSIXPathStyle);
-    CFRelease(executableURL);
-
-    CFStringGetFileSystemRepresentation(executablePathString, s, maxLen);
-    CFRelease(executablePathString);
-}
-
diff --git a/adb/get_my_path_linux.cpp b/adb/get_my_path_linux.cpp
deleted file mode 100644
index 11c0b21..0000000
--- a/adb/get_my_path_linux.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <limits.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "adb.h"
-
-void get_my_path(char *exe, size_t maxLen)
-{
-    char proc[64];
-    snprintf(proc, sizeof proc, "/proc/%d/exe", getpid());
-    int err = readlink(proc, exe, maxLen - 1);
-    if(err > 0) {
-        exe[err] = '\0';
-    } else {
-        exe[0] = '\0';
-    }
-}
-
diff --git a/adb/jdwp_service.cpp b/adb/jdwp_service.cpp
index 3c812cc..3135aa4 100644
--- a/adb/jdwp_service.cpp
+++ b/adb/jdwp_service.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-/* implement the "debug-ports" and "track-debug-ports" device services */
+#if !ADB_HOST
 
 #define TRACE_TAG JDWP
 
@@ -24,22 +24,30 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
 #include <unistd.h>
 
+#include <list>
+#include <memory>
+#include <vector>
+
 #include "adb.h"
+#include "adb_io.h"
+#include "adb_unique_fd.h"
 #include "adb_utils.h"
 
 /* here's how these things work.
 
    when adbd starts, it creates a unix server socket
-   named @vm-debug-control (@ is a shortcut for "first byte is zero"
+   named @jdwp-control (@ is a shortcut for "first byte is zero"
    to use the private namespace instead of the file system)
 
    when a new JDWP daemon thread starts in a new VM process, it creates
-   a connection to @vm-debug-control to announce its availability.
+   a connection to @jdwp-control to announce its availability.
 
 
-     JDWP thread                             @vm-debug-control
+     JDWP thread                             @jdwp-control
          |                                         |
          |------------------------------->         |
          | hello I'm in process <pid>              |
@@ -72,7 +80,7 @@
         to the JDWP process with the help of sendmsg()
 
 
-     JDWP thread                             @vm-debug-control
+     JDWP thread                             @jdwp-control
          |                                         |
          |                  <----------------------|
          |           OK, try this file descriptor  |
@@ -116,249 +124,191 @@
  ** for each JDWP process, we record its pid and its connected socket
  **/
 
-#define  MAX_OUT_FDS   4
+// PIDs are transmitted as 4 hex digits in ascii.
+static constexpr size_t PID_LEN = 4;
 
-#if !ADB_HOST
+static void jdwp_process_event(int socket, unsigned events, void* _proc);
+static void jdwp_process_list_updated(void);
 
-#include <sys/socket.h>
-#include <sys/un.h>
+struct JdwpProcess;
+static std::list<std::unique_ptr<JdwpProcess>> _jdwp_list;
 
 struct JdwpProcess {
-    JdwpProcess*  next;
-    JdwpProcess*  prev;
-    int           pid;
-    int           socket;
-    fdevent*      fde;
+    explicit JdwpProcess(int socket) {
+        this->socket = socket;
+        this->fde = fdevent_create(socket, jdwp_process_event, this);
 
-    char          in_buff[4];  /* input character to read PID */
-    int           in_len;      /* number from JDWP process    */
+        if (!this->fde) {
+            fatal("could not create fdevent for new JDWP process");
+        }
 
-    int           out_fds[MAX_OUT_FDS]; /* output array of file descriptors */
-    int           out_count;            /* to send to the JDWP process      */
+        this->fde->state |= FDE_DONT_CLOSE;
+
+        /* start by waiting for the PID */
+        fdevent_add(this->fde, FDE_READ);
+    }
+
+    ~JdwpProcess() {
+        if (this->socket >= 0) {
+            adb_shutdown(this->socket);
+            adb_close(this->socket);
+            this->socket = -1;
+        }
+
+        if (this->fde) {
+            fdevent_destroy(this->fde);
+            this->fde = nullptr;
+        }
+
+        out_fds.clear();
+    }
+
+    void RemoveFromList() {
+        if (this->pid >= 0) {
+            D("removing pid %d from jdwp process list", this->pid);
+        } else {
+            D("removing transient JdwpProcess from list");
+        }
+
+        auto pred = [this](const auto& proc) { return proc.get() == this; };
+        _jdwp_list.remove_if(pred);
+    }
+
+    int pid = -1;
+    int socket = -1;
+    fdevent* fde = nullptr;
+
+    std::vector<unique_fd> out_fds;
+    char in_buf[PID_LEN + 1];
+    ssize_t in_len = 0;
 };
 
-static JdwpProcess  _jdwp_list;
+static size_t jdwp_process_list(char* buffer, size_t bufferlen) {
+    std::string temp;
 
-static int
-jdwp_process_list( char*  buffer, int  bufferlen )
-{
-    char*         end  = buffer + bufferlen;
-    char*         p    = buffer;
-    JdwpProcess*  proc = _jdwp_list.next;
-
-    for ( ; proc != &_jdwp_list; proc = proc->next ) {
-        int  len;
-
+    for (auto& proc : _jdwp_list) {
         /* skip transient connections */
-        if (proc->pid < 0)
+        if (proc->pid < 0) {
             continue;
+        }
 
-        len = snprintf(p, end-p, "%d\n", proc->pid);
-        if (p + len >= end)
+        std::string next = std::to_string(proc->pid) + "\n";
+        if (temp.length() + next.length() > bufferlen) {
+            D("truncating JDWP process list (max len = %zu)", bufferlen);
             break;
-        p += len;
-    }
-    p[0] = 0;
-    return (p - buffer);
-}
-
-
-static int
-jdwp_process_list_msg( char*  buffer, int  bufferlen )
-{
-    char  head[5];
-    int   len = jdwp_process_list( buffer+4, bufferlen-4 );
-    snprintf(head, sizeof head, "%04x", len);
-    memcpy(buffer, head, 4);
-    return len + 4;
-}
-
-
-static void  jdwp_process_list_updated(void);
-
-static void
-jdwp_process_free( JdwpProcess*  proc )
-{
-    if (proc) {
-        int  n;
-
-        proc->prev->next = proc->next;
-        proc->next->prev = proc->prev;
-
-        if (proc->socket >= 0) {
-            adb_shutdown(proc->socket);
-            adb_close(proc->socket);
-            proc->socket = -1;
         }
-
-        if (proc->fde != NULL) {
-            fdevent_destroy(proc->fde);
-            proc->fde = NULL;
-        }
-        proc->pid = -1;
-
-        for (n = 0; n < proc->out_count; n++) {
-            adb_close(proc->out_fds[n]);
-        }
-        proc->out_count = 0;
-
-        free(proc);
-
-        jdwp_process_list_updated();
+        temp.append(next);
     }
+
+    memcpy(buffer, temp.data(), temp.length());
+    return temp.length();
 }
 
-
-static void  jdwp_process_event(int, unsigned, void*);  /* forward */
-
-
-static JdwpProcess*
-jdwp_process_alloc( int  socket )
-{
-    JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(
-        calloc(1, sizeof(*proc)));
-
-    if (proc == NULL) {
-        D("not enough memory to create new JDWP process");
-        return NULL;
+static size_t jdwp_process_list_msg(char* buffer, size_t bufferlen) {
+    // Message is length-prefixed with 4 hex digits in ASCII.
+    static constexpr size_t header_len = 4;
+    if (bufferlen < header_len) {
+        fatal("invalid JDWP process list buffer size: %zu", bufferlen);
     }
 
-    proc->socket = socket;
-    proc->pid    = -1;
-    proc->next   = proc;
-    proc->prev   = proc;
-
-    proc->fde = fdevent_create( socket, jdwp_process_event, proc );
-    if (proc->fde == NULL) {
-        D("could not create fdevent for new JDWP process" );
-        free(proc);
-        return NULL;
-    }
-
-    proc->fde->state |= FDE_DONT_CLOSE;
-    proc->in_len      = 0;
-    proc->out_count   = 0;
-
-    /* append to list */
-    proc->next = &_jdwp_list;
-    proc->prev = proc->next->prev;
-
-    proc->prev->next = proc;
-    proc->next->prev = proc;
-
-    /* start by waiting for the PID */
-    fdevent_add(proc->fde, FDE_READ);
-
-    return proc;
+    char head[header_len + 1];
+    size_t len = jdwp_process_list(buffer + header_len, bufferlen - header_len);
+    snprintf(head, sizeof head, "%04zx", len);
+    memcpy(buffer, head, header_len);
+    return len + header_len;
 }
 
-
-static void
-jdwp_process_event( int  socket, unsigned  events, void*  _proc )
-{
-    JdwpProcess*  proc = reinterpret_cast<JdwpProcess*>(_proc);
+static void jdwp_process_event(int socket, unsigned events, void* _proc) {
+    JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(_proc);
 
     if (events & FDE_READ) {
         if (proc->pid < 0) {
             /* read the PID as a 4-hexchar string */
-            char*  p    = proc->in_buff + proc->in_len;
-            int    size = 4 - proc->in_len;
-            char   temp[5];
-            while (size > 0) {
-                int  len = recv( socket, p, size, 0 );
-                if (len < 0) {
-                    if (errno == EINTR)
-                        continue;
-                    if (errno == EAGAIN)
-                        return;
-                    /* this can fail here if the JDWP process crashes very fast */
-                    D("weird unknown JDWP process failure: %s",
-                      strerror(errno));
-
-                    goto CloseProcess;
-                }
-                if (len == 0) {  /* end of stream ? */
-                    D("weird end-of-stream from unknown JDWP process");
-                    goto CloseProcess;
-                }
-                p            += len;
-                proc->in_len += len;
-                size         -= len;
+            if (proc->in_len < 0) {
+                fatal("attempting to read JDWP pid again?");
             }
-            /* we have read 4 characters, now decode the pid */
-            memcpy(temp, proc->in_buff, 4);
-            temp[4] = 0;
 
-            if (sscanf( temp, "%04x", &proc->pid ) != 1) {
-                D("could not decode JDWP %p PID number: '%s'", proc, temp);
+            char* p = proc->in_buf + proc->in_len;
+            size_t size = PID_LEN - proc->in_len;
+
+            ssize_t rc = TEMP_FAILURE_RETRY(recv(socket, p, size, 0));
+            if (rc < 0) {
+                if (errno == EAGAIN) {
+                    return;
+                }
+
+                D("failed to read jdwp pid: %s", strerror(errno));
+                goto CloseProcess;
+            }
+
+            proc->in_len += rc;
+            if (proc->in_len != PID_LEN) {
+                return;
+            }
+
+            proc->in_buf[PID_LEN] = '\0';
+            proc->in_len = -1;
+
+            if (sscanf(proc->in_buf, "%04x", &proc->pid) != 1) {
+                D("could not decode JDWP %p PID number: '%s'", proc, p);
                 goto CloseProcess;
             }
 
             /* all is well, keep reading to detect connection closure */
             D("Adding pid %d to jdwp process list", proc->pid);
             jdwp_process_list_updated();
-        }
-        else
-        {
+        } else {
             /* the pid was read, if we get there it's probably because the connection
              * was closed (e.g. the JDWP process exited or crashed) */
-            char  buf[32];
+            char buf[32];
 
-            for (;;) {
-                int  len = recv(socket, buf, sizeof(buf), 0);
+            while (true) {
+                int len = TEMP_FAILURE_RETRY(recv(socket, buf, sizeof(buf), 0));
 
-                if (len <= 0) {
-                    if (len < 0 && errno == EINTR)
-                        continue;
-                    if (len < 0 && errno == EAGAIN)
+                if (len == 0) {
+                    D("terminating JDWP %d connection: EOF", proc->pid);
+                    break;
+                } else if (len < 0) {
+                    if (len < 0 && errno == EAGAIN) {
                         return;
-                    else {
-                        D("terminating JDWP %d connection: %s", proc->pid,
-                          strerror(errno));
-                        break;
                     }
-                }
-                else {
-                    D( "ignoring unexpected JDWP %d control socket activity (%d bytes)",
-                       proc->pid, len );
+
+                    D("terminating JDWP %d connection: EOF", proc->pid);
+                    break;
+                } else {
+                    D("ignoring unexpected JDWP %d control socket activity (%d bytes)", proc->pid,
+                      len);
                 }
             }
 
-        CloseProcess:
-            if (proc->pid >= 0) {
-                D( "remove pid %d to jdwp process list", proc->pid );
-            }
-            jdwp_process_free(proc);
-            return;
+            goto CloseProcess;
         }
     }
 
     if (events & FDE_WRITE) {
-        D("trying to write to JDWP pid controli (count=%d first=%d) %d",
-          proc->pid, proc->out_count, proc->out_fds[0]);
-        if (proc->out_count > 0) {
-            int  fd = proc->out_fds[0];
-            int  n, ret;
-            struct cmsghdr*  cmsg;
-            struct msghdr    msg;
-            struct iovec     iov;
-            char             dummy = '!';
-            char             buffer[sizeof(struct cmsghdr) + sizeof(int)];
+        D("trying to send fd to JDWP process (count = %zu)", proc->out_fds.size());
+        if (!proc->out_fds.empty()) {
+            int fd = proc->out_fds.back().get();
+            struct cmsghdr* cmsg;
+            struct msghdr msg;
+            struct iovec iov;
+            char dummy = '!';
+            char buffer[sizeof(struct cmsghdr) + sizeof(int)];
 
-            iov.iov_base       = &dummy;
-            iov.iov_len        = 1;
-            msg.msg_name       = NULL;
-            msg.msg_namelen    = 0;
-            msg.msg_iov        = &iov;
-            msg.msg_iovlen     = 1;
-            msg.msg_flags      = 0;
-            msg.msg_control    = buffer;
+            iov.iov_base = &dummy;
+            iov.iov_len = 1;
+            msg.msg_name = NULL;
+            msg.msg_namelen = 0;
+            msg.msg_iov = &iov;
+            msg.msg_iovlen = 1;
+            msg.msg_flags = 0;
+            msg.msg_control = buffer;
             msg.msg_controllen = sizeof(buffer);
 
             cmsg = CMSG_FIRSTHDR(&msg);
-            cmsg->cmsg_len   = msg.msg_controllen;
+            cmsg->cmsg_len = msg.msg_controllen;
             cmsg->cmsg_level = SOL_SOCKET;
-            cmsg->cmsg_type  = SCM_RIGHTS;
+            cmsg->cmsg_type = SCM_RIGHTS;
             ((int*)CMSG_DATA(cmsg))[0] = fd;
 
             if (!set_file_block_mode(proc->socket, true)) {
@@ -366,74 +316,59 @@
                 goto CloseProcess;
             }
 
-            for (;;) {
-                ret = sendmsg(proc->socket, &msg, 0);
-                if (ret >= 0) {
-                    adb_close(fd);
-                    break;
-                }
-                if (errno == EINTR)
-                    continue;
-                D("sending new file descriptor to JDWP %d failed: %s",
-                  proc->pid, strerror(errno));
+            int ret = TEMP_FAILURE_RETRY(sendmsg(proc->socket, &msg, 0));
+            if (ret < 0) {
+                D("sending new file descriptor to JDWP %d failed: %s", proc->pid, strerror(errno));
                 goto CloseProcess;
             }
 
-            D("sent file descriptor %d to JDWP process %d",
-              fd, proc->pid);
+            adb_close(fd);
 
-            for (n = 1; n < proc->out_count; n++)
-                proc->out_fds[n-1] = proc->out_fds[n];
+            D("sent file descriptor %d to JDWP process %d", fd, proc->pid);
+
+            proc->out_fds.pop_back();
 
             if (!set_file_block_mode(proc->socket, false)) {
                 VLOG(JDWP) << "failed to set non-blocking mode for fd " << proc->socket;
                 goto CloseProcess;
             }
 
-            if (--proc->out_count == 0)
-                fdevent_del( proc->fde, FDE_WRITE );
+            if (proc->out_fds.empty()) {
+                fdevent_del(proc->fde, FDE_WRITE);
+            }
         }
     }
+
+    return;
+
+CloseProcess:
+    proc->RemoveFromList();
+    jdwp_process_list_updated();
 }
 
-
-int
-create_jdwp_connection_fd(int  pid)
-{
-    JdwpProcess*  proc = _jdwp_list.next;
-
+int create_jdwp_connection_fd(int pid) {
     D("looking for pid %d in JDWP process list", pid);
-    for ( ; proc != &_jdwp_list; proc = proc->next ) {
+
+    for (auto& proc : _jdwp_list) {
         if (proc->pid == pid) {
-            goto FoundIt;
+            int fds[2];
+
+            if (adb_socketpair(fds) < 0) {
+                D("%s: socket pair creation failed: %s", __FUNCTION__, strerror(errno));
+                return -1;
+            }
+            D("socketpair: (%d,%d)", fds[0], fds[1]);
+
+            proc->out_fds.emplace_back(fds[1]);
+            if (proc->out_fds.size() == 1) {
+                fdevent_add(proc->fde, FDE_WRITE);
+            }
+
+            return fds[0];
         }
     }
     D("search failed !!");
     return -1;
-
-FoundIt:
-    {
-        int  fds[2];
-
-        if (proc->out_count >= MAX_OUT_FDS) {
-            D("%s: too many pending JDWP connection for pid %d",
-              __FUNCTION__, pid);
-            return -1;
-        }
-
-        if (adb_socketpair(fds) < 0) {
-            D("%s: socket pair creation failed: %s",
-              __FUNCTION__, strerror(errno));
-            return -1;
-        }
-        D("socketpair: (%d,%d)", fds[0], fds[1]);
-
-        proc->out_fds[ proc->out_count ] = fds[1];
-        if (++proc->out_count == 1)
-            fdevent_add( proc->fde, FDE_WRITE );
-
-        return fds[0];
-    }
 }
 
 /**  VM DEBUG CONTROL SOCKET
@@ -442,33 +377,27 @@
  **/
 
 /* name of the debug control Unix socket */
-#define  JDWP_CONTROL_NAME      "\0jdwp-control"
-#define  JDWP_CONTROL_NAME_LEN  (sizeof(JDWP_CONTROL_NAME)-1)
+#define JDWP_CONTROL_NAME "\0jdwp-control"
+#define JDWP_CONTROL_NAME_LEN (sizeof(JDWP_CONTROL_NAME) - 1)
 
 struct JdwpControl {
-    int       listen_socket;
-    fdevent*  fde;
+    int listen_socket;
+    fdevent* fde;
 };
 
+static JdwpControl _jdwp_control;
 
-static void
-jdwp_control_event(int  s, unsigned events, void*  user);
+static void jdwp_control_event(int s, unsigned events, void* user);
 
-
-static int
-jdwp_control_init( JdwpControl*  control,
-                   const char*   sockname,
-                   int           socknamelen )
-{
-    sockaddr_un   addr;
-    socklen_t     addrlen;
-    int           s;
-    int           maxpath = sizeof(addr.sun_path);
-    int           pathlen = socknamelen;
+static int jdwp_control_init(JdwpControl* control, const char* sockname, int socknamelen) {
+    sockaddr_un addr;
+    socklen_t addrlen;
+    int s;
+    int maxpath = sizeof(addr.sun_path);
+    int pathlen = socknamelen;
 
     if (pathlen >= maxpath) {
-        D( "vm debug control socket name too long (%d extra chars)",
-           pathlen+1-maxpath );
+        D("vm debug control socket name too long (%d extra chars)", pathlen + 1 - maxpath);
         return -1;
     }
 
@@ -476,25 +405,22 @@
     addr.sun_family = AF_UNIX;
     memcpy(addr.sun_path, sockname, socknamelen);
 
-    s = socket( AF_UNIX, SOCK_STREAM, 0 );
+    s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
     if (s < 0) {
-        D( "could not create vm debug control socket. %d: %s",
-           errno, strerror(errno));
+        D("could not create vm debug control socket. %d: %s", errno, strerror(errno));
         return -1;
     }
 
-    addrlen = (pathlen + sizeof(addr.sun_family));
+    addrlen = pathlen + sizeof(addr.sun_family);
 
     if (bind(s, reinterpret_cast<sockaddr*>(&addr), addrlen) < 0) {
-        D( "could not bind vm debug control socket: %d: %s",
-           errno, strerror(errno) );
+        D("could not bind vm debug control socket: %d: %s", errno, strerror(errno));
         adb_close(s);
         return -1;
     }
 
-    if ( listen(s, 4) < 0 ) {
-        D("listen failed in jdwp control socket: %d: %s",
-          errno, strerror(errno));
+    if (listen(s, 4) < 0) {
+        D("listen failed in jdwp control socket: %d: %s", errno, strerror(errno));
         adb_close(s);
         return -1;
     }
@@ -503,128 +429,106 @@
 
     control->fde = fdevent_create(s, jdwp_control_event, control);
     if (control->fde == NULL) {
-        D( "could not create fdevent for jdwp control socket" );
+        D("could not create fdevent for jdwp control socket");
         adb_close(s);
         return -1;
     }
 
     /* only wait for incoming connections */
     fdevent_add(control->fde, FDE_READ);
-    close_on_exec(s);
 
     D("jdwp control socket started (%d)", control->listen_socket);
     return 0;
 }
 
-
-static void
-jdwp_control_event( int  s, unsigned  events, void*  _control )
-{
-    JdwpControl*  control = (JdwpControl*) _control;
+static void jdwp_control_event(int s, unsigned events, void* _control) {
+    JdwpControl* control = (JdwpControl*)_control;
 
     if (events & FDE_READ) {
-        sockaddr_storage   ss;
-        sockaddr*          addrp = reinterpret_cast<sockaddr*>(&ss);
-        socklen_t          addrlen = sizeof(ss);
-        int                s = -1;
-        JdwpProcess*       proc;
-
-        do {
-            s = adb_socket_accept(control->listen_socket, addrp, &addrlen);
-            if (s < 0) {
-                if (errno == EINTR)
-                    continue;
-                if (errno == ECONNABORTED) {
-                    /* oops, the JDWP process died really quick */
-                    D("oops, the JDWP process died really quick");
-                    return;
-                }
+        int s = adb_socket_accept(control->listen_socket, nullptr, nullptr);
+        if (s < 0) {
+            if (errno == ECONNABORTED) {
+                /* oops, the JDWP process died really quick */
+                D("oops, the JDWP process died really quick");
+                return;
+            } else {
                 /* the socket is probably closed ? */
-                D( "weird accept() failed on jdwp control socket: %s",
-                   strerror(errno) );
+                D("weird accept() failed on jdwp control socket: %s", strerror(errno));
                 return;
             }
         }
-        while (s < 0);
 
-        proc = jdwp_process_alloc( s );
-        if (proc == NULL)
-            return;
+        auto proc = std::make_unique<JdwpProcess>(s);
+        if (!proc) {
+            fatal("failed to allocate JdwpProcess");
+        }
+
+        _jdwp_list.emplace_back(std::move(proc));
     }
 }
 
-
-static JdwpControl   _jdwp_control;
-
 /** "jdwp" local service implementation
  ** this simply returns the list of known JDWP process pids
  **/
 
-struct JdwpSocket {
-    asocket  socket;
-    int      pass;
+struct JdwpSocket : public asocket {
+    bool pass;
 };
 
-static void
-jdwp_socket_close( asocket*  s )
-{
-    asocket*  peer = s->peer;
+static void jdwp_socket_close(asocket* s) {
+    D("LS(%d): closing jdwp socket", s->id);
+
+    if (s->peer) {
+        D("LS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
+        s->peer->peer = nullptr;
+        s->peer->close(s->peer);
+        s->peer = nullptr;
+    }
 
     remove_socket(s);
-
-    if (peer) {
-        peer->peer = NULL;
-        peer->close(peer);
-    }
     free(s);
 }
 
-static int
-jdwp_socket_enqueue( asocket*  s, apacket*  p )
-{
+static int jdwp_socket_enqueue(asocket* s, apacket* p) {
     /* you can't write to this asocket */
+    D("LS(%d): JDWP socket received data?", s->id);
     put_apacket(p);
     s->peer->close(s->peer);
     return -1;
 }
 
+static void jdwp_socket_ready(asocket* s) {
+    JdwpSocket* jdwp = (JdwpSocket*)s;
+    asocket* peer = jdwp->peer;
 
-static void
-jdwp_socket_ready( asocket*  s )
-{
-    JdwpSocket*  jdwp = (JdwpSocket*)s;
-    asocket*     peer = jdwp->socket.peer;
-
-   /* on the first call, send the list of pids,
-    * on the second one, close the connection
-    */
-    if (jdwp->pass == 0) {
-        apacket*  p = get_apacket();
+    /* on the first call, send the list of pids,
+     * on the second one, close the connection
+     */
+    if (!jdwp->pass) {
+        apacket* p = get_apacket();
         p->len = jdwp_process_list((char*)p->data, s->get_max_payload());
         peer->enqueue(peer, p);
-        jdwp->pass = 1;
-    }
-    else {
+        jdwp->pass = true;
+    } else {
         peer->close(peer);
     }
 }
 
-asocket*
-create_jdwp_service_socket( void )
-{
+asocket* create_jdwp_service_socket(void) {
     JdwpSocket* s = reinterpret_cast<JdwpSocket*>(calloc(sizeof(*s), 1));
 
-    if (s == NULL)
-        return NULL;
+    if (!s) {
+        fatal("failed to allocate JdwpSocket");
+    }
 
-    install_local_socket(&s->socket);
+    install_local_socket(s);
 
-    s->socket.ready   = jdwp_socket_ready;
-    s->socket.enqueue = jdwp_socket_enqueue;
-    s->socket.close   = jdwp_socket_close;
-    s->pass           = 0;
+    s->ready = jdwp_socket_ready;
+    s->enqueue = jdwp_socket_enqueue;
+    s->close = jdwp_socket_close;
+    s->pass = false;
 
-    return &s->socket;
+    return s;
 }
 
 /** "track-jdwp" local service implementation
@@ -632,113 +536,88 @@
  ** to the client...
  **/
 
-struct JdwpTracker {
-    asocket       socket;
-    JdwpTracker*  next;
-    JdwpTracker*  prev;
-    int           need_update;
+struct JdwpTracker : public asocket {
+    bool need_initial;
 };
 
-static JdwpTracker   _jdwp_trackers_list;
+static std::vector<std::unique_ptr<JdwpTracker>> _jdwp_trackers;
 
+static void jdwp_process_list_updated(void) {
+    char buffer[1024];
+    int len = jdwp_process_list_msg(buffer, sizeof(buffer));
 
-static void
-jdwp_process_list_updated(void)
-{
-    char             buffer[1024];
-    int              len;
-    JdwpTracker*  t = _jdwp_trackers_list.next;
-
-    len = jdwp_process_list_msg(buffer, sizeof(buffer));
-
-    for ( ; t != &_jdwp_trackers_list; t = t->next ) {
-        apacket*  p    = get_apacket();
-        asocket*  peer = t->socket.peer;
+    for (auto& t : _jdwp_trackers) {
+        apacket* p = get_apacket();
         memcpy(p->data, buffer, len);
         p->len = len;
-        peer->enqueue( peer, p );
+
+        if (t->peer) {
+            // The tracker might not have been connected yet.
+            t->peer->enqueue(t->peer, p);
+        }
     }
 }
 
-static void
-jdwp_tracker_close( asocket*  s )
-{
-    JdwpTracker*  tracker = (JdwpTracker*) s;
-    asocket*      peer    = s->peer;
+static void jdwp_tracker_close(asocket* s) {
+    D("LS(%d): destroying jdwp tracker service", s->id);
 
-    if (peer) {
-        peer->peer = NULL;
-        peer->close(peer);
+    if (s->peer) {
+        D("LS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
+        s->peer->peer = nullptr;
+        s->peer->close(s->peer);
+        s->peer = nullptr;
     }
 
     remove_socket(s);
 
-    tracker->prev->next = tracker->next;
-    tracker->next->prev = tracker->prev;
-
-    free(s);
+    auto pred = [s](const auto& tracker) { return tracker.get() == s; };
+    std::remove_if(_jdwp_trackers.begin(), _jdwp_trackers.end(), pred);
 }
 
-static void
-jdwp_tracker_ready( asocket*  s )
-{
-    JdwpTracker*  t = (JdwpTracker*) s;
+static void jdwp_tracker_ready(asocket* s) {
+    JdwpTracker* t = (JdwpTracker*)s;
 
-    if (t->need_update) {
-        apacket*  p = get_apacket();
-        t->need_update = 0;
+    if (t->need_initial) {
+        apacket* p = get_apacket();
+        t->need_initial = false;
         p->len = jdwp_process_list_msg((char*)p->data, s->get_max_payload());
         s->peer->enqueue(s->peer, p);
     }
 }
 
-static int
-jdwp_tracker_enqueue( asocket*  s, apacket*  p )
-{
+static int jdwp_tracker_enqueue(asocket* s, apacket* p) {
     /* you can't write to this socket */
+    D("LS(%d): JDWP tracker received data?", s->id);
     put_apacket(p);
     s->peer->close(s->peer);
     return -1;
 }
 
+asocket* create_jdwp_tracker_service_socket(void) {
+    auto t = std::make_unique<JdwpTracker>();
+    if (!t) {
+        fatal("failed to allocate JdwpTracker");
+    }
 
-asocket*
-create_jdwp_tracker_service_socket( void )
-{
-    JdwpTracker* t = reinterpret_cast<JdwpTracker*>(calloc(sizeof(*t), 1));
+    memset(t.get(), 0, sizeof(asocket));
 
-    if (t == NULL)
-        return NULL;
+    install_local_socket(t.get());
+    D("LS(%d): created new jdwp tracker service", t->id);
 
-    t->next = &_jdwp_trackers_list;
-    t->prev = t->next->prev;
+    t->ready = jdwp_tracker_ready;
+    t->enqueue = jdwp_tracker_enqueue;
+    t->close = jdwp_tracker_close;
+    t->need_initial = true;
 
-    t->next->prev = t;
-    t->prev->next = t;
+    asocket* result = t.get();
 
-    install_local_socket(&t->socket);
+    _jdwp_trackers.emplace_back(std::move(t));
 
-    t->socket.ready   = jdwp_tracker_ready;
-    t->socket.enqueue = jdwp_tracker_enqueue;
-    t->socket.close   = jdwp_tracker_close;
-    t->need_update    = 1;
-
-    return &t->socket;
+    return result;
 }
 
-
-int
-init_jdwp(void)
-{
-    _jdwp_list.next = &_jdwp_list;
-    _jdwp_list.prev = &_jdwp_list;
-
-    _jdwp_trackers_list.next = &_jdwp_trackers_list;
-    _jdwp_trackers_list.prev = &_jdwp_trackers_list;
-
-    return jdwp_control_init( &_jdwp_control,
-                              JDWP_CONTROL_NAME,
-                              JDWP_CONTROL_NAME_LEN );
+int init_jdwp(void) {
+    return jdwp_control_init(&_jdwp_control, JDWP_CONTROL_NAME, JDWP_CONTROL_NAME_LEN);
 }
 
 #endif /* !ADB_HOST */
diff --git a/adb/line_printer.cpp b/adb/line_printer.cpp
index 4ec8979..64d10b6 100644
--- a/adb/line_printer.cpp
+++ b/adb/line_printer.cpp
@@ -124,4 +124,5 @@
 
 void LinePrinter::KeepInfoLine() {
   if (!have_blank_line_) Out("\n");
+  have_blank_line_ = true;
 }
diff --git a/adb/mutex_list.h b/adb/mutex_list.h
deleted file mode 100644
index 4a188ee..0000000
--- a/adb/mutex_list.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/* the list of mutexes used by adb */
-/* #ifndef __MUTEX_LIST_H
- * Do not use an include-guard. This file is included once to declare the locks
- * and once in win32 to actually do the runtime initialization.
- */
-#ifndef ADB_MUTEX
-#error ADB_MUTEX not defined when including this file
-#endif
-ADB_MUTEX(basename_lock)
-ADB_MUTEX(dirname_lock)
-ADB_MUTEX(transport_lock)
-#if ADB_HOST
-ADB_MUTEX(local_transports_lock)
-#endif
-ADB_MUTEX(usb_lock)
-
-#undef ADB_MUTEX
diff --git a/adb/protocol.txt b/adb/protocol.txt
index 5c7c6ba..55ea87f 100644
--- a/adb/protocol.txt
+++ b/adb/protocol.txt
@@ -29,12 +29,12 @@
 32 bit words which are sent across the wire in little endian format.
 
 struct message {
-    unsigned command;       /* command identifier constant      */
-    unsigned arg0;          /* first argument                   */
-    unsigned arg1;          /* second argument                  */
-    unsigned data_length;   /* length of payload (0 is allowed) */
-    unsigned data_crc32;    /* crc32 of data payload            */
-    unsigned magic;         /* command ^ 0xffffffff             */
+    unsigned command;       /* command identifier constant (A_CNXN, ...) */
+    unsigned arg0;          /* first argument                            */
+    unsigned arg1;          /* second argument                           */
+    unsigned data_length;   /* length of payload (0 is allowed)          */
+    unsigned data_crc32;    /* crc32 of data payload                     */
+    unsigned magic;         /* command ^ 0xffffffff                      */
 };
 
 Receipt of an invalid message header, corrupt message payload, or an
@@ -55,6 +55,8 @@
 
 --- CONNECT(version, maxdata, "system-identity-string") ----------------
 
+Command constant: A_CNXN
+
 The CONNECT message establishes the presence of a remote system.
 The version is used to ensure protocol compatibility and maxdata
 declares the maximum message body size that the remote system
@@ -80,6 +82,8 @@
 
 --- AUTH(type, 0, "data") ----------------------------------------------
 
+Command constant: A_AUTH
+
 The AUTH message informs the recipient that authentication is required to
 connect to the sender. If type is TOKEN(1), data is a random token that
 the recipient can sign with a private key. The recipient replies with an
@@ -98,6 +102,8 @@
 
 --- OPEN(local-id, 0, "destination") -----------------------------------
 
+Command constant: A_OPEN
+
 The OPEN message informs the recipient that the sender has a stream
 identified by local-id that it wishes to connect to the named
 destination in the message payload.  The local-id may not be zero.
@@ -120,11 +126,13 @@
 
 --- READY(local-id, remote-id, "") -------------------------------------
 
+Command constant: A_OKAY
+
 The READY message informs the recipient that the sender's stream
 identified by local-id is ready for write messages and that it is
 connected to the recipient's stream identified by remote-id.
 
-Neither the local-id nor the remote-id may be zero. 
+Neither the local-id nor the remote-id may be zero.
 
 A READY message containing a remote-id which does not map to an open
 stream on the recipient's side is ignored.  The stream may have been
@@ -135,9 +143,10 @@
 not change on later READY messages sent to the same stream.
 
 
-
 --- WRITE(local-id, remote-id, "data") ---------------------------------
 
+Command constant: A_WRTE
+
 The WRITE message sends data to the recipient's stream identified by
 remote-id.  The payload MUST be <= maxdata in length.
 
@@ -154,6 +163,8 @@
 
 --- CLOSE(local-id, remote-id, "") -------------------------------------
 
+Command constant: A_CLSE
+
 The CLOSE message informs recipient that the connection between the
 sender's stream (local-id) and the recipient's stream (remote-id) is
 broken.  The remote-id MUST not be zero, but the local-id MAY be zero
@@ -170,12 +181,14 @@
 
 --- SYNC(online, sequence, "") -----------------------------------------
 
+Command constant: A_SYNC
+
 The SYNC message is used by the io pump to make sure that stale
 outbound messages are discarded when the connection to the remote side
 is broken.  It is only used internally to the bridge and never valid
-to send across the wire.  
+to send across the wire.
 
-* when the connection to the remote side goes offline, the io pump 
+* when the connection to the remote side goes offline, the io pump
   sends a SYNC(0, 0) and starts discarding all messages
 * when the connection to the remote side is established, the io pump
   sends a SYNC(1, token) and continues to discard messages
diff --git a/adb/remount_service.cpp b/adb/remount_service.cpp
index 8f1c9b0..5ca73cc 100644
--- a/adb/remount_service.cpp
+++ b/adb/remount_service.cpp
@@ -29,10 +29,11 @@
 
 #include <string>
 
+#include <android-base/properties.h>
+
 #include "adb.h"
 #include "adb_io.h"
 #include "adb_utils.h"
-#include "cutils/properties.h"
 #include "fs_mgr.h"
 
 // Returns the device used to mount a directory in /proc/mounts.
@@ -53,10 +54,7 @@
 
 // Returns the device used to mount a directory in the fstab.
 static std::string find_fstab_mount(const char* dir) {
-    char propbuf[PROPERTY_VALUE_MAX];
-
-    property_get("ro.hardware", propbuf, "");
-    std::string fstab_filename = std::string("/fstab.") + propbuf;
+    std::string fstab_filename = "/fstab." + android::base::GetProperty("ro.hardware", "");
     struct fstab* fstab = fs_mgr_read_fstab(fstab_filename.c_str());
     struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab, dir);
     std::string dev = rec ? std::string(rec->blk_device) : "";
@@ -113,12 +111,8 @@
         return;
     }
 
-    char prop_buf[PROPERTY_VALUE_MAX];
-    property_get("partition.system.verified", prop_buf, "");
-    bool system_verified = (strlen(prop_buf) > 0);
-
-    property_get("partition.vendor.verified", prop_buf, "");
-    bool vendor_verified = (strlen(prop_buf) > 0);
+    bool system_verified = !(android::base::GetProperty("partition.system.verified", "").empty());
+    bool vendor_verified = !(android::base::GetProperty("partition.vendor.verified", "").empty());
 
     if (system_verified || vendor_verified) {
         // Allow remount but warn of likely bad effects
@@ -136,9 +130,7 @@
     }
 
     bool success = true;
-    property_get("ro.build.system_root_image", prop_buf, "");
-    bool system_root = !strcmp(prop_buf, "true");
-    if (system_root) {
+    if (android::base::GetBoolProperty("ro.build.system_root_image", false)) {
         success &= remount_partition(fd, "/");
     } else {
         success &= remount_partition(fd, "/system");
diff --git a/adb/services.cpp b/adb/services.cpp
index 3b212e9..2fbc15a 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -38,8 +38,9 @@
 #include <cutils/sockets.h>
 
 #if !ADB_HOST
-#include "cutils/android_reboot.h"
-#include "cutils/properties.h"
+#include <android-base/properties.h>
+#include <cutils/android_reboot.h>
+#include <private/android_logger.h>
 #endif
 
 #include "adb.h"
@@ -49,6 +50,7 @@
 #include "remount_service.h"
 #include "services.h"
 #include "shell_service.h"
+#include "socket_spec.h"
 #include "sysdeps.h"
 #include "transport.h"
 
@@ -72,15 +74,13 @@
         WriteFdExactly(fd, "adbd is already running as root\n");
         adb_close(fd);
     } else {
-        char value[PROPERTY_VALUE_MAX];
-        property_get("ro.debuggable", value, "");
-        if (strcmp(value, "1") != 0) {
+        if (!__android_log_is_debuggable()) {
             WriteFdExactly(fd, "adbd cannot run as root in production builds\n");
             adb_close(fd);
             return;
         }
 
-        property_set("service.adb.root", "1");
+        android::base::SetProperty("service.adb.root", "1");
         WriteFdExactly(fd, "restarting adbd as root\n");
         adb_close(fd);
     }
@@ -91,7 +91,7 @@
         WriteFdExactly(fd, "adbd not running as root\n");
         adb_close(fd);
     } else {
-        property_set("service.adb.root", "0");
+        android::base::SetProperty("service.adb.root", "0");
         WriteFdExactly(fd, "restarting adbd as non root\n");
         adb_close(fd);
     }
@@ -105,15 +105,13 @@
         return;
     }
 
-    char value[PROPERTY_VALUE_MAX];
-    snprintf(value, sizeof(value), "%d", port);
-    property_set("service.adb.tcp.port", value);
+    android::base::SetProperty("service.adb.tcp.port", android::base::StringPrintf("%d", port));
     WriteFdFmt(fd, "restarting in TCP mode port: %d\n", port);
     adb_close(fd);
 }
 
 void restart_usb_service(int fd, void *cookie) {
-    property_set("service.adb.tcp.port", "0");
+    android::base::SetProperty("service.adb.tcp.port", "0");
     WriteFdExactly(fd, "restarting in USB mode\n");
     adb_close(fd);
 }
@@ -154,16 +152,9 @@
 
     sync();
 
-    char property_val[PROPERTY_VALUE_MAX];
-    int ret = snprintf(property_val, sizeof(property_val), "reboot,%s", reboot_arg);
-    if (ret >= static_cast<int>(sizeof(property_val))) {
-        WriteFdFmt(fd, "reboot string too long: %d\n", ret);
-        return false;
-    }
-
-    ret = property_set(ANDROID_RB_PROPERTY, property_val);
-    if (ret < 0) {
-        WriteFdFmt(fd, "reboot failed: %d\n", ret);
+    std::string reboot_string = android::base::StringPrintf("reboot,%s", reboot_arg);
+    if (!android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_string)) {
+        WriteFdFmt(fd, "reboot (%s) failed\n", reboot_string.c_str());
         return false;
     }
 
@@ -278,36 +269,12 @@
 int service_to_fd(const char* name, const atransport* transport) {
     int ret = -1;
 
-    if(!strncmp(name, "tcp:", 4)) {
-        int port = atoi(name + 4);
-        name = strchr(name + 4, ':');
-        if(name == 0) {
-            std::string error;
-            ret = network_loopback_client(port, SOCK_STREAM, &error);
-            if (ret >= 0)
-                disable_tcp_nagle(ret);
-        } else {
-#if ADB_HOST
-            std::string error;
-            ret = network_connect(name + 1, port, SOCK_STREAM, 0, &error);
-#else
-            return -1;
-#endif
+    if (is_socket_spec(name)) {
+        std::string error;
+        ret = socket_spec_connect(name, &error);
+        if (ret < 0) {
+            LOG(ERROR) << "failed to connect to socket '" << name << "': " << error;
         }
-#if !defined(_WIN32)   /* winsock doesn't implement unix domain sockets */
-    } else if(!strncmp(name, "local:", 6)) {
-        ret = socket_local_client(name + 6,
-                ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
-    } else if(!strncmp(name, "localreserved:", 14)) {
-        ret = socket_local_client(name + 14,
-                ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
-    } else if(!strncmp(name, "localabstract:", 14)) {
-        ret = socket_local_client(name + 14,
-                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
-    } else if(!strncmp(name, "localfilesystem:", 16)) {
-        ret = socket_local_client(name + 16,
-                ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
-#endif
 #if !ADB_HOST
     } else if(!strncmp("dev:", name, 4)) {
         ret = unix_open(name + 4, O_RDWR | O_CLOEXEC);
diff --git a/adb/set_verity_enable_state_service.cpp b/adb/set_verity_enable_state_service.cpp
index f5188e9..f9e028b 100644
--- a/adb/set_verity_enable_state_service.cpp
+++ b/adb/set_verity_enable_state_service.cpp
@@ -24,16 +24,18 @@
 #include <stdio.h>
 #include <sys/stat.h>
 
-#include "cutils/properties.h"
+#include "android-base/properties.h"
+#include "android-base/stringprintf.h"
+#include <private/android_logger.h>
 
 #include "adb.h"
 #include "adb_io.h"
+#include "adb_unique_fd.h"
 #include "fs_mgr.h"
 #include "remount_service.h"
 
 #include "fec/io.h"
 
-#define FSTAB_PREFIX "/fstab."
 struct fstab *fstab;
 
 #ifdef ALLOW_ADBD_DISABLE_VERITY
@@ -88,56 +90,45 @@
     return 0;
 }
 
-void set_verity_enabled_state_service(int fd, void* cookie)
-{
+void set_verity_enabled_state_service(int fd, void* cookie) {
+    unique_fd closer(fd);
+
     bool enable = (cookie != NULL);
-    if (kAllowDisableVerity) {
-        char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
-        char propbuf[PROPERTY_VALUE_MAX];
-        int i;
-        bool any_changed = false;
-
-        property_get("ro.secure", propbuf, "0");
-        if (strcmp(propbuf, "1")) {
-            WriteFdFmt(fd, "verity not enabled - ENG build\n");
-            goto errout;
-        }
-
-        property_get("ro.debuggable", propbuf, "0");
-        if (strcmp(propbuf, "1")) {
-            WriteFdFmt(fd, "verity cannot be disabled/enabled - USER build\n");
-            goto errout;
-        }
-
-        property_get("ro.hardware", propbuf, "");
-        snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s",
-                 propbuf);
-
-        fstab = fs_mgr_read_fstab(fstab_filename);
-        if (!fstab) {
-            WriteFdFmt(fd, "Failed to open %s\nMaybe run adb root?\n", fstab_filename);
-            goto errout;
-        }
-
-        /* Loop through entries looking for ones that vold manages */
-        for (i = 0; i < fstab->num_entries; i++) {
-            if(fs_mgr_is_verified(&fstab->recs[i])) {
-                if (!set_verity_enabled_state(fd, fstab->recs[i].blk_device,
-                                              fstab->recs[i].mount_point,
-                                              enable)) {
-                    any_changed = true;
-                }
-           }
-        }
-
-        if (any_changed) {
-            WriteFdFmt(fd, "Now reboot your device for settings to take effect\n");
-        }
-    } else {
+    if (!kAllowDisableVerity) {
         WriteFdFmt(fd, "%s-verity only works for userdebug builds\n",
                    enable ? "enable" : "disable");
     }
 
-errout:
-    adb_close(fd);
+    if (!android::base::GetBoolProperty("ro.secure", false)) {
+        WriteFdFmt(fd, "verity not enabled - ENG build\n");
+        return;
+    }
+    if (!__android_log_is_debuggable()) {
+        WriteFdFmt(fd, "verity cannot be disabled/enabled - USER build\n");
+        return;
+    }
+
+    std::string fstab_filename = "/fstab." + android::base::GetProperty("ro.hardware", "");
+
+    fstab = fs_mgr_read_fstab(fstab_filename.c_str());
+    if (!fstab) {
+        WriteFdFmt(fd, "Failed to open %s\nMaybe run adb root?\n", fstab_filename.c_str());
+        return;
+    }
+
+    // Loop through entries looking for ones that vold manages.
+    bool any_changed = false;
+    for (int i = 0; i < fstab->num_entries; i++) {
+        if (fs_mgr_is_verified(&fstab->recs[i])) {
+            if (!set_verity_enabled_state(fd, fstab->recs[i].blk_device,
+                                          fstab->recs[i].mount_point,
+                                          enable)) {
+                any_changed = true;
+            }
+        }
+    }
+
+    if (any_changed) {
+        WriteFdFmt(fd, "Now reboot your device for settings to take effect\n");
+    }
 }
diff --git a/adb/shell_service.cpp b/adb/shell_service.cpp
index 104f399..4975fab 100644
--- a/adb/shell_service.cpp
+++ b/adb/shell_service.cpp
@@ -82,6 +82,7 @@
 #include "shell_service.h"
 
 #include <errno.h>
+#include <paths.h>
 #include <pty.h>
 #include <pwd.h>
 #include <sys/select.h>
@@ -94,31 +95,17 @@
 
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
-#include <paths.h>
-#include <log/log.h>
+#include <private/android_logger.h>
 
 #include "adb.h"
 #include "adb_io.h"
 #include "adb_trace.h"
+#include "adb_unique_fd.h"
 #include "adb_utils.h"
 #include "security_log_tags.h"
 
 namespace {
 
-void init_subproc_child()
-{
-    setsid();
-
-    // Set OOM score adjustment to prevent killing
-    int fd = adb_open("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC);
-    if (fd >= 0) {
-        adb_write(fd, "0", 1);
-        adb_close(fd);
-    } else {
-       D("adb: unable to update oom_score_adj");
-    }
-}
-
 // Reads from |fd| until close or failure.
 std::string ReadAll(int fd) {
     char buffer[512];
@@ -136,14 +123,14 @@
 }
 
 // Creates a socketpair and saves the endpoints to |fd1| and |fd2|.
-bool CreateSocketpair(ScopedFd* fd1, ScopedFd* fd2) {
+bool CreateSocketpair(unique_fd* fd1, unique_fd* fd2) {
     int sockets[2];
     if (adb_socketpair(sockets) < 0) {
         PLOG(ERROR) << "cannot create socket pair";
         return false;
     }
-    fd1->Reset(sockets[0]);
-    fd2->Reset(sockets[1]);
+    fd1->reset(sockets[0]);
+    fd2->reset(sockets[1]);
     return true;
 }
 
@@ -155,7 +142,7 @@
 
     const std::string& command() const { return command_; }
 
-    int ReleaseLocalSocket() { return local_socket_sfd_.Release(); }
+    int ReleaseLocalSocket() { return local_socket_sfd_.release(); }
 
     pid_t pid() const { return pid_; }
 
@@ -170,19 +157,19 @@
 
   private:
     // Opens the file at |pts_name|.
-    int OpenPtyChildFd(const char* pts_name, ScopedFd* error_sfd);
+    int OpenPtyChildFd(const char* pts_name, unique_fd* error_sfd);
 
     static void ThreadHandler(void* userdata);
     void PassDataStreams();
     void WaitForExit();
 
-    ScopedFd* SelectLoop(fd_set* master_read_set_ptr,
-                         fd_set* master_write_set_ptr);
+    unique_fd* SelectLoop(fd_set* master_read_set_ptr,
+                          fd_set* master_write_set_ptr);
 
     // Input/output stream handlers. Success returns nullptr, failure returns
     // a pointer to the failed FD.
-    ScopedFd* PassInput();
-    ScopedFd* PassOutput(ScopedFd* sfd, ShellProtocol::Id id);
+    unique_fd* PassInput();
+    unique_fd* PassOutput(unique_fd* sfd, ShellProtocol::Id id);
 
     const std::string command_;
     const std::string terminal_type_;
@@ -190,10 +177,10 @@
     SubprocessType type_;
     SubprocessProtocol protocol_;
     pid_t pid_ = -1;
-    ScopedFd local_socket_sfd_;
+    unique_fd local_socket_sfd_;
 
     // Shell protocol variables.
-    ScopedFd stdinout_sfd_, stderr_sfd_, protocol_sfd_;
+    unique_fd stdinout_sfd_, stderr_sfd_, protocol_sfd_;
     std::unique_ptr<ShellProtocol> input_, output_;
     size_t input_bytes_left_ = 0;
 
@@ -225,8 +212,8 @@
 }
 
 bool Subprocess::ForkAndExec(std::string* error) {
-    ScopedFd child_stdinout_sfd, child_stderr_sfd;
-    ScopedFd parent_error_sfd, child_error_sfd;
+    unique_fd child_stdinout_sfd, child_stderr_sfd;
+    unique_fd parent_error_sfd, child_error_sfd;
     char pts_name[PATH_MAX];
 
     if (command_.empty()) {
@@ -251,7 +238,7 @@
         char** current = environ;
         while (char* env_cstr = *current++) {
             std::string env_string = env_cstr;
-            char* delimiter = strchr(env_string.c_str(), '=');
+            char* delimiter = strchr(&env_string[0], '=');
 
             // Drop any values that don't contain '='.
             if (delimiter) {
@@ -290,7 +277,7 @@
         int fd;
         pid_ = forkpty(&fd, pts_name, nullptr, nullptr);
         if (pid_ > 0) {
-          stdinout_sfd_.Reset(fd);
+          stdinout_sfd_.reset(fd);
         }
     } else {
         if (!CreateSocketpair(&stdinout_sfd_, &child_stdinout_sfd)) {
@@ -315,43 +302,42 @@
 
     if (pid_ == 0) {
         // Subprocess child.
-        init_subproc_child();
+        setsid();
 
         if (type_ == SubprocessType::kPty) {
-            child_stdinout_sfd.Reset(OpenPtyChildFd(pts_name, &child_error_sfd));
+            child_stdinout_sfd.reset(OpenPtyChildFd(pts_name, &child_error_sfd));
         }
 
-        dup2(child_stdinout_sfd.fd(), STDIN_FILENO);
-        dup2(child_stdinout_sfd.fd(), STDOUT_FILENO);
-        dup2(child_stderr_sfd.valid() ? child_stderr_sfd.fd() : child_stdinout_sfd.fd(),
-             STDERR_FILENO);
+        dup2(child_stdinout_sfd, STDIN_FILENO);
+        dup2(child_stdinout_sfd, STDOUT_FILENO);
+        dup2(child_stderr_sfd != -1 ? child_stderr_sfd : child_stdinout_sfd, STDERR_FILENO);
 
         // exec doesn't trigger destructors, close the FDs manually.
-        stdinout_sfd_.Reset();
-        stderr_sfd_.Reset();
-        child_stdinout_sfd.Reset();
-        child_stderr_sfd.Reset();
-        parent_error_sfd.Reset();
-        close_on_exec(child_error_sfd.fd());
+        stdinout_sfd_.reset(-1);
+        stderr_sfd_.reset(-1);
+        child_stdinout_sfd.reset(-1);
+        child_stderr_sfd.reset(-1);
+        parent_error_sfd.reset(-1);
+        close_on_exec(child_error_sfd);
 
         if (command_.empty()) {
             execle(_PATH_BSHELL, _PATH_BSHELL, "-", nullptr, cenv.data());
         } 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(), strerror(errno));
-        child_error_sfd.Reset();
+        WriteFdExactly(child_error_sfd, "exec '" _PATH_BSHELL "' failed: ");
+        WriteFdExactly(child_error_sfd, strerror(errno));
+        child_error_sfd.reset(-1);
         _Exit(1);
     }
 
     // Subprocess parent.
     D("subprocess parent: stdin/stdout FD = %d, stderr FD = %d",
-      stdinout_sfd_.fd(), stderr_sfd_.fd());
+      stdinout_sfd_.get(), stderr_sfd_.get());
 
     // Wait to make sure the subprocess exec'd without error.
-    child_error_sfd.Reset();
-    std::string error_message = ReadAll(parent_error_sfd.fd());
+    child_error_sfd.reset(-1);
+    std::string error_message = ReadAll(parent_error_sfd);
     if (!error_message.empty()) {
         *error = error_message;
         return false;
@@ -361,7 +347,7 @@
     if (protocol_ == SubprocessProtocol::kNone) {
         // No protocol: all streams pass through the stdinout FD and hook
         // directly into the local socket for raw data transfer.
-        local_socket_sfd_.Reset(stdinout_sfd_.Release());
+        local_socket_sfd_.reset(stdinout_sfd_.release());
     } else {
         // Shell protocol: create another socketpair to intercept data.
         if (!CreateSocketpair(&protocol_sfd_, &local_socket_sfd_)) {
@@ -370,10 +356,10 @@
             kill(pid_, SIGKILL);
             return false;
         }
-        D("protocol FD = %d", protocol_sfd_.fd());
+        D("protocol FD = %d", protocol_sfd_.get());
 
-        input_.reset(new ShellProtocol(protocol_sfd_.fd()));
-        output_.reset(new ShellProtocol(protocol_sfd_.fd()));
+        input_.reset(new ShellProtocol(protocol_sfd_));
+        output_.reset(new ShellProtocol(protocol_sfd_));
         if (!input_ || !output_) {
             *error = "failed to allocate shell protocol objects";
             kill(pid_, SIGKILL);
@@ -384,7 +370,7 @@
         // likely but could happen under unusual circumstances, such as if we
         // write a ton of data to stdin but the subprocess never reads it and
         // the pipe fills up.
-        for (int fd : {stdinout_sfd_.fd(), stderr_sfd_.fd()}) {
+        for (int fd : {stdinout_sfd_.get(), stderr_sfd_.get()}) {
             if (fd >= 0) {
                 if (!set_file_block_mode(fd, false)) {
                     *error = android::base::StringPrintf(
@@ -412,7 +398,7 @@
     return true;
 }
 
-int Subprocess::OpenPtyChildFd(const char* pts_name, ScopedFd* error_sfd) {
+int Subprocess::OpenPtyChildFd(const char* pts_name, unique_fd* error_sfd) {
     int child_fd = adb_open(pts_name, O_RDWR | O_CLOEXEC);
     if (child_fd == -1) {
         // Don't use WriteFdFmt; since we're in the fork() child we don't want
@@ -420,26 +406,26 @@
         const char* messages[] = {"child failed to open pseudo-term slave ",
                                   pts_name, ": ", strerror(errno)};
         for (const char* message : messages) {
-            WriteFdExactly(error_sfd->fd(), message);
+            WriteFdExactly(*error_sfd, message);
         }
-        exit(-1);
+        abort();
     }
 
     if (make_pty_raw_) {
         termios tattr;
         if (tcgetattr(child_fd, &tattr) == -1) {
             int saved_errno = errno;
-            WriteFdExactly(error_sfd->fd(), "tcgetattr failed: ");
-            WriteFdExactly(error_sfd->fd(), strerror(saved_errno));
-            exit(-1);
+            WriteFdExactly(*error_sfd, "tcgetattr failed: ");
+            WriteFdExactly(*error_sfd, strerror(saved_errno));
+            abort();
         }
 
         cfmakeraw(&tattr);
         if (tcsetattr(child_fd, TCSADRAIN, &tattr) == -1) {
             int saved_errno = errno;
-            WriteFdExactly(error_sfd->fd(), "tcsetattr failed: ");
-            WriteFdExactly(error_sfd->fd(), strerror(saved_errno));
-            exit(-1);
+            WriteFdExactly(*error_sfd, "tcsetattr failed: ");
+            WriteFdExactly(*error_sfd, strerror(saved_errno));
+            abort();
         }
     }
 
@@ -460,7 +446,7 @@
 }
 
 void Subprocess::PassDataStreams() {
-    if (!protocol_sfd_.valid()) {
+    if (protocol_sfd_ == -1) {
         return;
     }
 
@@ -468,21 +454,20 @@
     fd_set master_read_set, master_write_set;
     FD_ZERO(&master_read_set);
     FD_ZERO(&master_write_set);
-    for (ScopedFd* sfd : {&protocol_sfd_, &stdinout_sfd_, &stderr_sfd_}) {
-        if (sfd->valid()) {
-            FD_SET(sfd->fd(), &master_read_set);
+    for (unique_fd* sfd : {&protocol_sfd_, &stdinout_sfd_, &stderr_sfd_}) {
+        if (*sfd != -1) {
+            FD_SET(*sfd, &master_read_set);
         }
     }
 
     // Pass data until the protocol FD or both the subprocess pipes die, at
     // which point we can't pass any more data.
-    while (protocol_sfd_.valid() &&
-            (stdinout_sfd_.valid() || stderr_sfd_.valid())) {
-        ScopedFd* dead_sfd = SelectLoop(&master_read_set, &master_write_set);
+    while (protocol_sfd_ != -1 && (stdinout_sfd_ != -1 || stderr_sfd_ != -1)) {
+        unique_fd* dead_sfd = SelectLoop(&master_read_set, &master_write_set);
         if (dead_sfd) {
-            D("closing FD %d", dead_sfd->fd());
-            FD_CLR(dead_sfd->fd(), &master_read_set);
-            FD_CLR(dead_sfd->fd(), &master_write_set);
+            D("closing FD %d", dead_sfd->get());
+            FD_CLR(*dead_sfd, &master_read_set);
+            FD_CLR(*dead_sfd, &master_write_set);
             if (dead_sfd == &protocol_sfd_) {
                 // Using SIGHUP is a decent general way to indicate that the
                 // controlling process is going away. If specific signals are
@@ -494,28 +479,27 @@
                 // We also need to close the pipes connected to the child process
                 // so that if it ignores SIGHUP and continues to write data it
                 // won't fill up the pipe and block.
-                stdinout_sfd_.Reset();
-                stderr_sfd_.Reset();
+                stdinout_sfd_.reset();
+                stderr_sfd_.reset();
             }
-            dead_sfd->Reset();
+            dead_sfd->reset();
         }
     }
 }
 
 namespace {
 
-inline bool ValidAndInSet(const ScopedFd& sfd, fd_set* set) {
-    return sfd.valid() && FD_ISSET(sfd.fd(), set);
+inline bool ValidAndInSet(const unique_fd& sfd, fd_set* set) {
+    return sfd != -1 && FD_ISSET(sfd, set);
 }
 
 }   // namespace
 
-ScopedFd* Subprocess::SelectLoop(fd_set* master_read_set_ptr,
-                                 fd_set* master_write_set_ptr) {
+unique_fd* Subprocess::SelectLoop(fd_set* master_read_set_ptr,
+                                  fd_set* master_write_set_ptr) {
     fd_set read_set, write_set;
-    int select_n = std::max(std::max(protocol_sfd_.fd(), stdinout_sfd_.fd()),
-                            stderr_sfd_.fd()) + 1;
-    ScopedFd* dead_sfd = nullptr;
+    int select_n = std::max(std::max(protocol_sfd_, stdinout_sfd_), stderr_sfd_) + 1;
+    unique_fd* dead_sfd = nullptr;
 
     // Keep calling select() and passing data until an FD closes/errors.
     while (!dead_sfd) {
@@ -526,8 +510,8 @@
                 continue;
             } else {
                 PLOG(ERROR) << "select failed, closing subprocess pipes";
-                stdinout_sfd_.Reset();
-                stderr_sfd_.Reset();
+                stdinout_sfd_.reset(-1);
+                stderr_sfd_.reset(-1);
                 return nullptr;
             }
         }
@@ -547,8 +531,8 @@
             dead_sfd = PassInput();
             // If we didn't finish writing, block on stdin write.
             if (input_bytes_left_) {
-                FD_CLR(protocol_sfd_.fd(), master_read_set_ptr);
-                FD_SET(stdinout_sfd_.fd(), master_write_set_ptr);
+                FD_CLR(protocol_sfd_, master_read_set_ptr);
+                FD_SET(stdinout_sfd_, master_write_set_ptr);
             }
         }
 
@@ -557,8 +541,8 @@
             dead_sfd = PassInput();
             // If we finished writing, go back to blocking on protocol read.
             if (!input_bytes_left_) {
-                FD_SET(protocol_sfd_.fd(), master_read_set_ptr);
-                FD_CLR(stdinout_sfd_.fd(), master_write_set_ptr);
+                FD_SET(protocol_sfd_, master_read_set_ptr);
+                FD_CLR(stdinout_sfd_, master_write_set_ptr);
             }
         }
     }  // while (!dead_sfd)
@@ -566,19 +550,18 @@
     return dead_sfd;
 }
 
-ScopedFd* Subprocess::PassInput() {
+unique_fd* Subprocess::PassInput() {
     // Only read a new packet if we've finished writing the last one.
     if (!input_bytes_left_) {
         if (!input_->Read()) {
             // Read() uses ReadFdExactly() which sets errno to 0 on EOF.
             if (errno != 0) {
-                PLOG(ERROR) << "error reading protocol FD "
-                            << protocol_sfd_.fd();
+                PLOG(ERROR) << "error reading protocol FD " << protocol_sfd_;
             }
             return &protocol_sfd_;
         }
 
-        if (stdinout_sfd_.valid()) {
+        if (stdinout_sfd_ != -1) {
             switch (input_->id()) {
                 case ShellProtocol::kIdWindowSizeChange:
                     int rows, cols, x_pixels, y_pixels;
@@ -589,7 +572,7 @@
                         ws.ws_col = cols;
                         ws.ws_xpixel = x_pixels;
                         ws.ws_ypixel = y_pixels;
-                        ioctl(stdinout_sfd_.fd(), TIOCSWINSZ, &ws);
+                        ioctl(stdinout_sfd_, TIOCSWINSZ, &ws);
                     }
                     break;
                 case ShellProtocol::kIdStdin:
@@ -597,11 +580,11 @@
                     break;
                 case ShellProtocol::kIdCloseStdin:
                     if (type_ == SubprocessType::kRaw) {
-                        if (adb_shutdown(stdinout_sfd_.fd(), SHUT_WR) == 0) {
+                        if (adb_shutdown(stdinout_sfd_, SHUT_WR) == 0) {
                             return nullptr;
                         }
                         PLOG(ERROR) << "failed to shutdown writes to FD "
-                                    << stdinout_sfd_.fd();
+                                    << stdinout_sfd_;
                         return &stdinout_sfd_;
                     } else {
                         // PTYs can't close just input, so rather than close the
@@ -610,7 +593,7 @@
                         // non-interactively which is rare and unsupported.
                         // If necessary, the client can manually close the shell
                         // with `exit` or by killing the adb client process.
-                        D("can't close input for PTY FD %d", stdinout_sfd_.fd());
+                        D("can't close input for PTY FD %d", stdinout_sfd_.get());
                     }
                     break;
             }
@@ -619,11 +602,10 @@
 
     if (input_bytes_left_ > 0) {
         int index = input_->data_length() - input_bytes_left_;
-        int bytes = adb_write(stdinout_sfd_.fd(), input_->data() + index,
-                              input_bytes_left_);
+        int bytes = adb_write(stdinout_sfd_, input_->data() + index, input_bytes_left_);
         if (bytes == 0 || (bytes < 0 && errno != EAGAIN)) {
             if (bytes < 0) {
-                PLOG(ERROR) << "error reading stdin FD " << stdinout_sfd_.fd();
+                PLOG(ERROR) << "error reading stdin FD " << stdinout_sfd_;
             }
             // stdin is done, mark this packet as finished and we'll just start
             // dumping any further data received from the protocol FD.
@@ -637,20 +619,20 @@
     return nullptr;
 }
 
-ScopedFd* Subprocess::PassOutput(ScopedFd* sfd, ShellProtocol::Id id) {
-    int bytes = adb_read(sfd->fd(), output_->data(), output_->data_capacity());
+unique_fd* Subprocess::PassOutput(unique_fd* sfd, ShellProtocol::Id id) {
+    int bytes = adb_read(*sfd, output_->data(), output_->data_capacity());
     if (bytes == 0 || (bytes < 0 && errno != EAGAIN)) {
         // read() returns EIO if a PTY closes; don't report this as an error,
         // it just means the subprocess completed.
         if (bytes < 0 && !(type_ == SubprocessType::kPty && errno == EIO)) {
-            PLOG(ERROR) << "error reading output FD " << sfd->fd();
+            PLOG(ERROR) << "error reading output FD " << *sfd;
         }
         return sfd;
     }
 
     if (bytes > 0 && !output_->Write(id, bytes)) {
         if (errno != 0) {
-            PLOG(ERROR) << "error reading protocol FD " << protocol_sfd_.fd();
+            PLOG(ERROR) << "error reading protocol FD " << protocol_sfd_;
         }
         return &protocol_sfd_;
     }
@@ -682,25 +664,25 @@
     }
 
     // If we have an open protocol FD send an exit packet.
-    if (protocol_sfd_.valid()) {
+    if (protocol_sfd_ != -1) {
         output_->data()[0] = exit_code;
         if (output_->Write(ShellProtocol::kIdExit, 1)) {
             D("wrote the exit code packet: %d", exit_code);
         } else {
             PLOG(ERROR) << "failed to write the exit code packet";
         }
-        protocol_sfd_.Reset();
+        protocol_sfd_.reset(-1);
     }
 
     // Pass the local socket FD to the shell cleanup fdevent.
     if (SHELL_EXIT_NOTIFY_FD >= 0) {
-        int fd = local_socket_sfd_.fd();
+        int fd = local_socket_sfd_;
         if (WriteFdExactly(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd))) {
             D("passed fd %d to SHELL_EXIT_NOTIFY_FD (%d) for pid %d",
               fd, SHELL_EXIT_NOTIFY_FD, pid_);
             // The shell exit fdevent now owns the FD and will close it once
             // the last bit of data flushes through.
-            local_socket_sfd_.Release();
+            static_cast<void>(local_socket_sfd_.release());
         } else {
             PLOG(ERROR) << "failed to write fd " << fd
                         << " to SHELL_EXIT_NOTIFY_FD (" << SHELL_EXIT_NOTIFY_FD
@@ -761,13 +743,14 @@
         return ReportError(protocol, error);
     }
 
-    int local_socket = subprocess->ReleaseLocalSocket();
-    D("subprocess creation successful: local_socket_fd=%d, pid=%d", local_socket, subprocess->pid());
+    unique_fd local_socket(subprocess->ReleaseLocalSocket());
+    D("subprocess creation successful: local_socket_fd=%d, pid=%d", local_socket.get(),
+      subprocess->pid());
 
     if (!Subprocess::StartThread(std::move(subprocess), &error)) {
         LOG(ERROR) << "failed to start subprocess management thread: " << error;
         return ReportError(protocol, error);
     }
 
-    return local_socket;
+    return local_socket.release();
 }
diff --git a/adb/shell_service_protocol_test.cpp b/adb/shell_service_protocol_test.cpp
index a826035..b0fa3ed 100644
--- a/adb/shell_service_protocol_test.cpp
+++ b/adb/shell_service_protocol_test.cpp
@@ -86,9 +86,10 @@
 
 namespace {
 
-// Returns true if the packet contains the given values.
+// Returns true if the packet contains the given values. `data` can't be null.
 bool PacketEquals(const ShellProtocol* protocol, ShellProtocol::Id id,
                     const void* data, size_t data_length) {
+    // Note that passing memcmp null is bad, even if data_length is 0.
     return (protocol->id() == id &&
             protocol->data_length() == data_length &&
             !memcmp(data, protocol->data(), data_length));
@@ -130,7 +131,8 @@
 
     ASSERT_TRUE(write_protocol_->Write(id, 0));
     ASSERT_TRUE(read_protocol_->Read());
-    ASSERT_TRUE(PacketEquals(read_protocol_, id, nullptr, 0));
+    char buf[1];
+    ASSERT_TRUE(PacketEquals(read_protocol_, id, buf, 0));
 }
 
 // Tests exit code packets.
diff --git a/adb/socket.h b/adb/socket.h
index 9eb1b19..4acdf4a 100644
--- a/adb/socket.h
+++ b/adb/socket.h
@@ -118,7 +118,7 @@
 namespace internal {
 
 #if ADB_HOST
-char* skip_host_serial(const char* service);
+char* skip_host_serial(char* service);
 #endif
 
 }  // namespace internal
diff --git a/adb/socket_spec.cpp b/adb/socket_spec.cpp
new file mode 100644
index 0000000..14eb16b
--- /dev/null
+++ b/adb/socket_spec.cpp
@@ -0,0 +1,230 @@
+/*
+ * 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 "socket_spec.h"
+
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <android-base/parseint.h>
+#include <android-base/parsenetaddress.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <cutils/sockets.h>
+
+#include "adb.h"
+#include "sysdeps.h"
+
+using android::base::StartsWith;
+using android::base::StringPrintf;
+
+#if defined(__linux__)
+#define ADB_LINUX 1
+#else
+#define ADB_LINUX 0
+#endif
+
+#if defined(_WIN32)
+#define ADB_WINDOWS 1
+#else
+#define ADB_WINDOWS 0
+#endif
+
+// Not static because it is used in commandline.c.
+int gListenAll = 0;
+
+struct LocalSocketType {
+    int socket_namespace;
+    bool available;
+};
+
+static auto& kLocalSocketTypes = *new std::unordered_map<std::string, LocalSocketType>({
+#if ADB_HOST
+    { "local", { ANDROID_SOCKET_NAMESPACE_FILESYSTEM, !ADB_WINDOWS } },
+#else
+    { "local", { ANDROID_SOCKET_NAMESPACE_RESERVED, !ADB_WINDOWS } },
+#endif
+
+    { "localreserved", { ANDROID_SOCKET_NAMESPACE_RESERVED, !ADB_HOST } },
+    { "localabstract", { ANDROID_SOCKET_NAMESPACE_ABSTRACT, ADB_LINUX } },
+    { "localfilesystem", { ANDROID_SOCKET_NAMESPACE_FILESYSTEM, !ADB_WINDOWS } },
+});
+
+bool parse_tcp_socket_spec(const std::string& spec, std::string* hostname, int* port,
+                           std::string* error) {
+    if (!StartsWith(spec, "tcp:")) {
+        *error = StringPrintf("specification is not tcp: '%s'", spec.c_str());
+        return false;
+    }
+
+    std::string hostname_value;
+    int port_value;
+
+    // If the spec is tcp:<port>, parse it ourselves.
+    // Otherwise, delegate to android::base::ParseNetAddress.
+    if (android::base::ParseInt(&spec[4], &port_value)) {
+        // Do the range checking ourselves, because ParseInt rejects 'tcp:65536' and 'tcp:foo:1234'
+        // identically.
+        if (port_value < 0 || port_value > 65535) {
+            *error = StringPrintf("bad port number '%d'", port_value);
+            return false;
+        }
+    } else {
+        std::string addr = spec.substr(4);
+        port_value = -1;
+
+        // FIXME: ParseNetAddress rejects port 0. This currently doesn't hurt, because listening
+        //        on an address that isn't 'localhost' is unsupported.
+        if (!android::base::ParseNetAddress(addr, &hostname_value, &port_value, nullptr, error)) {
+            return false;
+        }
+
+        if (port_value == -1) {
+            *error = StringPrintf("missing port in specification: '%s'", spec.c_str());
+            return false;
+        }
+    }
+
+    if (hostname) {
+        *hostname = std::move(hostname_value);
+    }
+
+    if (port) {
+        *port = port_value;
+    }
+
+    return true;
+}
+
+static bool tcp_host_is_local(const std::string& hostname) {
+    // FIXME
+    return hostname.empty() || hostname == "localhost";
+}
+
+bool is_socket_spec(const std::string& spec) {
+    for (const auto& it : kLocalSocketTypes) {
+        std::string prefix = it.first + ":";
+        if (StartsWith(spec, prefix.c_str())) {
+            return true;
+        }
+    }
+    return StartsWith(spec, "tcp:");
+}
+
+bool is_local_socket_spec(const std::string& spec) {
+    for (const auto& it : kLocalSocketTypes) {
+        std::string prefix = it.first + ":";
+        if (StartsWith(spec, prefix.c_str())) {
+            return true;
+        }
+    }
+
+    std::string error;
+    std::string hostname;
+    if (!parse_tcp_socket_spec(spec, &hostname, nullptr, &error)) {
+        return false;
+    }
+    return tcp_host_is_local(hostname);
+}
+
+int socket_spec_connect(const std::string& spec, std::string* error) {
+    if (StartsWith(spec, "tcp:")) {
+        std::string hostname;
+        int port;
+        if (!parse_tcp_socket_spec(spec, &hostname, &port, error)) {
+            return -1;
+        }
+
+        int result;
+        if (tcp_host_is_local(hostname)) {
+            result = network_loopback_client(port, SOCK_STREAM, error);
+        } else {
+#if ADB_HOST
+            result = network_connect(hostname, port, SOCK_STREAM, 0, error);
+#else
+            // Disallow arbitrary connections in adbd.
+            *error = "adbd does not support arbitrary tcp connections";
+            return -1;
+#endif
+        }
+
+        if (result >= 0) {
+            disable_tcp_nagle(result);
+        }
+        return result;
+    }
+
+    for (const auto& it : kLocalSocketTypes) {
+        std::string prefix = it.first + ":";
+        if (StartsWith(spec, prefix.c_str())) {
+            if (!it.second.available) {
+                *error = StringPrintf("socket type %s is unavailable on this platform",
+                                      it.first.c_str());
+                return -1;
+            }
+
+            return network_local_client(&spec[prefix.length()], it.second.socket_namespace,
+                                        SOCK_STREAM, error);
+        }
+    }
+
+    *error = StringPrintf("unknown socket specification '%s'", spec.c_str());
+    return -1;
+}
+
+int socket_spec_listen(const std::string& spec, std::string* error, int* resolved_tcp_port) {
+    if (StartsWith(spec, "tcp:")) {
+        std::string hostname;
+        int port;
+        if (!parse_tcp_socket_spec(spec, &hostname, &port, error)) {
+            return -1;
+        }
+
+        int result;
+        if (hostname.empty() && gListenAll) {
+            result = network_inaddr_any_server(port, SOCK_STREAM, error);
+        } else if (tcp_host_is_local(hostname)) {
+            result = network_loopback_server(port, SOCK_STREAM, error);
+        } else {
+            // TODO: Implement me.
+            *error = "listening on specified hostname currently unsupported";
+            return -1;
+        }
+
+        if (result >= 0 && port == 0 && resolved_tcp_port) {
+            *resolved_tcp_port = adb_socket_get_local_port(result);
+        }
+        return result;
+    }
+
+    for (const auto& it : kLocalSocketTypes) {
+        std::string prefix = it.first + ":";
+        if (StartsWith(spec, prefix.c_str())) {
+            if (!it.second.available) {
+                *error = StringPrintf("attempted to listen on unavailable socket type: '%s'",
+                                      spec.c_str());
+                return -1;
+            }
+
+            return network_local_server(&spec[prefix.length()], it.second.socket_namespace,
+                                        SOCK_STREAM, error);
+        }
+    }
+
+    *error = StringPrintf("unknown socket specification '%s'", spec.c_str());
+    return -1;
+}
diff --git a/adb/socket_spec.h b/adb/socket_spec.h
new file mode 100644
index 0000000..6920e91
--- /dev/null
+++ b/adb/socket_spec.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <string>
+
+// Returns true if the argument starts with a plausible socket prefix.
+bool is_socket_spec(const std::string& spec);
+bool is_local_socket_spec(const std::string& spec);
+
+int socket_spec_connect(const std::string& spec, std::string* error);
+int socket_spec_listen(const std::string& spec, std::string* error,
+                       int* resolved_tcp_port = nullptr);
+
+// Exposed for testing.
+bool parse_tcp_socket_spec(const std::string& spec, std::string* hostname, int* port,
+                           std::string* error);
diff --git a/adb/socket_spec_test.cpp b/adb/socket_spec_test.cpp
new file mode 100644
index 0000000..40ce21c
--- /dev/null
+++ b/adb/socket_spec_test.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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 "socket_spec.h"
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+TEST(socket_spec, parse_tcp_socket_spec) {
+    std::string hostname, error;
+    int port;
+    EXPECT_TRUE(parse_tcp_socket_spec("tcp:5037", &hostname, &port, &error));
+    EXPECT_EQ("", hostname);
+    EXPECT_EQ(5037, port);
+
+    // Bad ports:
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:", &hostname, &port, &error));
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:-1", &hostname, &port, &error));
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:65536", &hostname, &port, &error));
+
+    EXPECT_TRUE(parse_tcp_socket_spec("tcp:localhost:1234", &hostname, &port, &error));
+    EXPECT_EQ("localhost", hostname);
+    EXPECT_EQ(1234, port);
+
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost", &hostname, &port, &error));
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:", &hostname, &port, &error));
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:-1", &hostname, &port, &error));
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:65536", &hostname, &port, &error));
+
+    // IPv6:
+    EXPECT_TRUE(parse_tcp_socket_spec("tcp:[::1]:1234", &hostname, &port, &error));
+    EXPECT_EQ("::1", hostname);
+    EXPECT_EQ(1234, port);
+
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]", &hostname, &port, &error));
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]:", &hostname, &port, &error));
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]:-1", &hostname, &port, &error));
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:::1", &hostname, &port, &error));
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:::1:1234", &hostname, &port, &error));
+}
diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp
index 5cbef6d..f56f7f7 100644
--- a/adb/socket_test.cpp
+++ b/adb/socket_test.cpp
@@ -22,6 +22,7 @@
 #include <limits>
 #include <queue>
 #include <string>
+#include <thread>
 #include <vector>
 
 #include <unistd.h>
@@ -31,6 +32,7 @@
 #include "fdevent_test.h"
 #include "socket.h"
 #include "sysdeps.h"
+#include "sysdeps/chrono.h"
 
 struct ThreadArg {
     int first_read_fd;
@@ -44,6 +46,8 @@
     fdevent_loop();
 }
 
+constexpr auto SLEEP_FOR_FDEVENT = 100ms;
+
 TEST_F(LocalSocketTest, smoke) {
     // Join two socketpairs with a chain of intermediate socketpairs.
     int first[2];
@@ -99,7 +103,8 @@
     ASSERT_EQ(0, adb_close(last[1]));
 
     // Wait until the local sockets are closed.
-    adb_sleep_ms(100);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+    ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
     TerminateThread(thread);
 }
 
@@ -151,12 +156,13 @@
     ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(CloseWithPacketThreadFunc),
                                   &arg, &thread));
     // Wait until the fdevent_loop() starts.
-    adb_sleep_ms(100);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     ASSERT_EQ(0, adb_close(cause_close_fd[0]));
-    adb_sleep_ms(100);
-    EXPECT_EQ(2u, fdevent_installed_count());
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+    EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
     ASSERT_EQ(0, adb_close(socket_fd[0]));
-
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+    ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
     TerminateThread(thread);
 }
 
@@ -175,10 +181,10 @@
     ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(CloseWithPacketThreadFunc),
                                   &arg, &thread));
     // Wait until the fdevent_loop() starts.
-    adb_sleep_ms(100);
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
     ASSERT_EQ(0, adb_close(cause_close_fd[0]));
-    adb_sleep_ms(100);
-    EXPECT_EQ(2u, fdevent_installed_count());
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+    EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
 
     // Verify if we can read successfully.
     std::vector<char> buf(arg.bytes_written);
@@ -186,6 +192,8 @@
     ASSERT_EQ(true, ReadFdExactly(socket_fd[0], buf.data(), buf.size()));
     ASSERT_EQ(0, adb_close(socket_fd[0]));
 
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+    ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
     TerminateThread(thread);
 }
 
@@ -208,10 +216,12 @@
                                   &arg, &thread));
 
     // Wait until the fdevent_loop() starts.
-    adb_sleep_ms(100);
-    EXPECT_EQ(3u, fdevent_installed_count());
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+    EXPECT_EQ(2u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
     ASSERT_EQ(0, adb_close(socket_fd[0]));
 
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+    ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
     TerminateThread(thread);
 }
 
@@ -221,7 +231,7 @@
     std::string error;
     int fd = network_loopback_client(5038, SOCK_STREAM, &error);
     ASSERT_GE(fd, 0) << error;
-    adb_sleep_ms(200);
+    std::this_thread::sleep_for(200ms);
     ASSERT_EQ(0, adb_close(fd));
 }
 
@@ -246,10 +256,7 @@
     ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(ClientThreadFunc), nullptr,
                                   &client_thread));
 
-    struct sockaddr addr;
-    socklen_t alen;
-    alen = sizeof(addr);
-    int accept_fd = adb_socket_accept(listen_fd, &addr, &alen);
+    int accept_fd = adb_socket_accept(listen_fd, nullptr, nullptr);
     ASSERT_GE(accept_fd, 0);
     CloseRdHupSocketArg arg;
     arg.socket_fd = accept_fd;
@@ -260,12 +267,14 @@
                                   &arg, &thread));
 
     // Wait until the fdevent_loop() starts.
-    adb_sleep_ms(100);
-    EXPECT_EQ(2u, fdevent_installed_count());
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+    EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
 
     // Wait until the client closes its socket.
     ASSERT_TRUE(adb_thread_join(client_thread));
 
+    std::this_thread::sleep_for(SLEEP_FOR_FDEVENT);
+    ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
     TerminateThread(thread);
 }
 
@@ -275,8 +284,8 @@
 
 // Checks that skip_host_serial(serial) returns a pointer to the part of |serial| which matches
 // |expected|, otherwise logs the failure to gtest.
-void VerifySkipHostSerial(const std::string& serial, const char* expected) {
-    const char* result = internal::skip_host_serial(serial.c_str());
+void VerifySkipHostSerial(std::string serial, const char* expected) {
+    char* result = internal::skip_host_serial(&serial[0]);
     if (expected == nullptr) {
         EXPECT_EQ(nullptr, result);
     } else {
@@ -300,6 +309,17 @@
         // Don't register a port unless it's all numbers and ends with ':'.
         VerifySkipHostSerial(protocol + "foo:123", ":123");
         VerifySkipHostSerial(protocol + "foo:123bar:baz", ":123bar:baz");
+
+        VerifySkipHostSerial(protocol + "100.100.100.100:5555:foo", ":foo");
+        VerifySkipHostSerial(protocol + "[0123:4567:89ab:CDEF:0:9:a:f]:5555:foo", ":foo");
+        VerifySkipHostSerial(protocol + "[::1]:5555:foo", ":foo");
+
+        // If we can't find both [] then treat it as a normal serial with [ in it.
+        VerifySkipHostSerial(protocol + "[0123:foo", ":foo");
+
+        // Don't be fooled by random IPv6 addresses in the command string.
+        VerifySkipHostSerial(protocol + "foo:ping [0123:4567:89ab:CDEF:0:9:a:f]:5555",
+                             ":ping [0123:4567:89ab:CDEF:0:9:a:f]:5555");
     }
 }
 
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 63b7df6..c05903f 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -31,12 +31,12 @@
 #include <vector>
 
 #if !ADB_HOST
-#include "cutils/properties.h"
+#include <android-base/properties.h>
+#include <private/android_logger.h>
 #endif
 
 #include "adb.h"
 #include "adb_io.h"
-#include "sysdeps/mutex.h"
 #include "transport.h"
 
 static std::recursive_mutex& local_socket_list_lock = *new std::recursive_mutex();
@@ -123,7 +123,7 @@
 }
 
 static int local_socket_enqueue(asocket* s, apacket* p) {
-    D("LS(%d): enqueue %d", s->id, p->len);
+    D("LS(%d): enqueue %zu", s->id, p->len);
 
     p->ptr = p->data;
 
@@ -196,7 +196,7 @@
 
     /* dispose of any unwritten data */
     for (p = s->pkt_first; p; p = n) {
-        D("LS(%d): discarding %d bytes", s->id, p->len);
+        D("LS(%d): discarding %zu bytes", s->id, p->len);
         n = p->next;
         put_apacket(p);
     }
@@ -306,7 +306,7 @@
 
     if (ev & FDE_READ) {
         apacket* p = get_apacket();
-        unsigned char* x = p->data;
+        char* x = p->data;
         const size_t max_payload = s->get_max_payload();
         size_t avail = max_payload;
         int r = 0;
@@ -410,19 +410,14 @@
 #endif
     int fd = service_to_fd(name, transport);
     if (fd < 0) {
-        return 0;
+        return nullptr;
     }
 
     asocket* s = create_local_socket(fd);
     D("LS(%d): bound to '%s' via %d", s->id, name, fd);
 
 #if !ADB_HOST
-    char debug[PROPERTY_VALUE_MAX];
-    if (!strncmp(name, "root:", 5)) {
-        property_get("ro.debuggable", debug, "");
-    }
-
-    if ((!strncmp(name, "root:", 5) && getuid() != 0 && strcmp(debug, "1") == 0) ||
+    if ((!strncmp(name, "root:", 5) && getuid() != 0 && __android_log_is_debuggable()) ||
         (!strncmp(name, "unroot:", 7) && getuid() == 0) ||
         !strncmp(name, "usb:", 4) ||
         !strncmp(name, "tcpip:", 6)) {
@@ -554,7 +549,7 @@
     s->close(s);
 }
 
-static unsigned unhex(unsigned char* s, int len) {
+static unsigned unhex(char* s, int len) {
     unsigned n = 0, c;
 
     while (len-- > 0) {
@@ -608,7 +603,7 @@
 // Where <port> must be a base-10 number and <prefix> may be any of {usb,product,model,device}.
 //
 // The returned pointer will point to the ':' just before <command>, or nullptr if not found.
-char* skip_host_serial(const char* service) {
+char* skip_host_serial(char* service) {
     static const std::vector<std::string>& prefixes =
         *(new std::vector<std::string>{"usb:", "product:", "model:", "device:"});
 
@@ -623,21 +618,32 @@
         service += 4;
     }
 
-    char* first_colon = strchr(service, ':');
-    if (!first_colon) {
+    // Check for an IPv6 address. `adb connect` creates the serial number from the canonical
+    // network address so it will always have the [] delimiters.
+    if (service[0] == '[') {
+        char* ipv6_end = strchr(service, ']');
+        if (ipv6_end != nullptr) {
+            service = ipv6_end;
+        }
+    }
+
+    // The next colon we find must either begin the port field or the command field.
+    char* colon_ptr = strchr(service, ':');
+    if (!colon_ptr) {
         // No colon in service string.
         return nullptr;
     }
 
-    char* serial_end = first_colon;
+    // If the next field is only decimal digits and ends with another colon, it's a port.
+    char* serial_end = colon_ptr;
     if (isdigit(serial_end[1])) {
         serial_end++;
         while (*serial_end && isdigit(*serial_end)) {
             serial_end++;
         }
         if (*serial_end != ':') {
-            // Something other than numbers was found, reset the end.
-            serial_end = first_colon;
+            // Something other than "<port>:" was found, this must be the command field instead.
+            serial_end = colon_ptr;
         }
     }
     return serial_end;
@@ -655,7 +661,7 @@
     TransportType type = kTransportAny;
 #endif
 
-    D("SS(%d): enqueue %d", s->id, p->len);
+    D("SS(%d): enqueue %zu", s->id, p->len);
 
     if (s->pkt_first == 0) {
         s->pkt_first = p;
@@ -688,7 +694,7 @@
     D("SS(%d): len is %d", s->id, len);
     /* can't do anything until we have the full header */
     if ((len + 4) > p->len) {
-        D("SS(%d): waiting for %d more bytes", s->id, len + 4 - p->len);
+        D("SS(%d): waiting for %zu more bytes", s->id, len + 4 - p->len);
         return 0;
     }
 
@@ -785,11 +791,14 @@
     }
 #endif
 
-    if (!(s->transport) || (s->transport->connection_state == kCsOffline)) {
+    if (!s->transport) {
+        SendFail(s->peer->fd, "device offline (no transport)");
+        goto fail;
+    } else if (s->transport->connection_state == kCsOffline) {
         /* if there's no remote we fail the connection
          ** right here and terminate it
          */
-        SendFail(s->peer->fd, "device offline (x)");
+        SendFail(s->peer->fd, "device offline (transport offline)");
         goto fail;
     }
 
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index bd19f88..0489d09 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -97,27 +97,6 @@
     return c == '\\' || c == '/';
 }
 
-typedef CRITICAL_SECTION          adb_mutex_t;
-
-#define  ADB_MUTEX_DEFINE(x)     adb_mutex_t   x
-
-/* declare all mutexes */
-/* For win32, adb_sysdeps_init() will do the mutex runtime initialization. */
-#define  ADB_MUTEX(x)   extern adb_mutex_t  x;
-#include "mutex_list.h"
-
-extern void  adb_sysdeps_init(void);
-
-static __inline__ void adb_mutex_lock( adb_mutex_t*  lock )
-{
-    EnterCriticalSection( lock );
-}
-
-static __inline__ void  adb_mutex_unlock( adb_mutex_t*  lock )
-{
-    LeaveCriticalSection( lock );
-}
-
 typedef void (*adb_thread_func_t)(void* arg);
 typedef HANDLE adb_thread_t;
 
@@ -269,17 +248,18 @@
 int unix_isatty(int fd);
 #define  isatty  ___xxx_isatty
 
-/* normally provided by <cutils/misc.h> */
-extern void*  load_file(const char*  pathname, unsigned*  psize);
-
-static __inline__ void  adb_sleep_ms( int  mseconds )
-{
-    Sleep( mseconds );
-}
-
 int network_loopback_client(int port, int type, std::string* error);
 int network_loopback_server(int port, int type, std::string* error);
 int network_inaddr_any_server(int port, int type, std::string* error);
+
+inline int network_local_client(const char* name, int namespace_id, int type, std::string* error) {
+    abort();
+}
+
+inline int network_local_server(const char* name, int namespace_id, int type, std::string* error) {
+    abort();
+}
+
 int network_connect(const std::string& host, int port, int type, int timeout,
                     std::string* error);
 
@@ -288,6 +268,13 @@
 #undef   accept
 #define  accept  ___xxx_accept
 
+int adb_getsockname(int fd, struct sockaddr* sockaddr, socklen_t* optlen);
+#undef getsockname
+#define getsockname(...) ___xxx_getsockname(__VA__ARGS__)
+
+// Returns the local port number of a bound socket, or -1 on failure.
+int adb_socket_get_local_port(int fd);
+
 extern int  adb_setsockopt(int  fd, int  level, int  optname, const void*  optval, socklen_t  optlen);
 
 #undef   setsockopt
@@ -434,7 +421,6 @@
 
 #else /* !_WIN32 a.k.a. Unix */
 
-#include <cutils/misc.h>
 #include <cutils/sockets.h>
 #include <cutils/threads.h>
 #include <fcntl.h>
@@ -464,27 +450,6 @@
     return c == '/';
 }
 
-typedef  pthread_mutex_t          adb_mutex_t;
-
-#define  ADB_MUTEX_INITIALIZER    PTHREAD_MUTEX_INITIALIZER
-#define  adb_mutex_init           pthread_mutex_init
-#define  adb_mutex_lock           pthread_mutex_lock
-#define  adb_mutex_unlock         pthread_mutex_unlock
-#define  adb_mutex_destroy        pthread_mutex_destroy
-
-#define  ADB_MUTEX_DEFINE(m)      adb_mutex_t   m = PTHREAD_MUTEX_INITIALIZER
-
-#define  adb_cond_t               pthread_cond_t
-#define  adb_cond_init            pthread_cond_init
-#define  adb_cond_wait            pthread_cond_wait
-#define  adb_cond_broadcast       pthread_cond_broadcast
-#define  adb_cond_signal          pthread_cond_signal
-#define  adb_cond_destroy         pthread_cond_destroy
-
-/* declare all mutexes */
-#define  ADB_MUTEX(x)   extern adb_mutex_t  x;
-#include "mutex_list.h"
-
 static __inline__ void  close_on_exec(int  fd)
 {
     fcntl( fd, F_SETFD, FD_CLOEXEC );
@@ -624,21 +589,26 @@
 }
 
 inline int network_loopback_client(int port, int type, std::string* error) {
-  return _fd_set_error_str(socket_loopback_client(port, type), error);
+  return _fd_set_error_str(socket_network_client("localhost", port, type), error);
 }
 
 inline int network_loopback_server(int port, int type, std::string* error) {
-  return _fd_set_error_str(socket_loopback_server(port, type), error);
+  int fd = socket_loopback_server(port, type);
+  if (fd < 0 && errno == EAFNOSUPPORT)
+      return _fd_set_error_str(socket_loopback_server6(port, type), error);
+  return _fd_set_error_str(fd, error);
 }
 
 inline int network_inaddr_any_server(int port, int type, std::string* error) {
   return _fd_set_error_str(socket_inaddr_any_server(port, type), error);
 }
 
-inline int network_local_server(const char *name, int namespace_id, int type,
-                                std::string* error) {
-  return _fd_set_error_str(socket_local_server(name, namespace_id, type),
-                           error);
+inline int network_local_client(const char* name, int namespace_id, int type, std::string* error) {
+    return _fd_set_error_str(socket_local_client(name, namespace_id, type), error);
+}
+
+inline int network_local_server(const char* name, int namespace_id, int type, std::string* error) {
+    return _fd_set_error_str(socket_local_server(name, namespace_id, type), error);
 }
 
 inline int network_connect(const std::string& host, int port, int type,
@@ -671,6 +641,10 @@
 #undef   accept
 #define  accept  ___xxx_accept
 
+inline int adb_socket_get_local_port(int fd) {
+    return socket_get_local_port(fd);
+}
+
 // Operate on a file descriptor returned from unix_open() or a well-known file
 // descriptor such as STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO.
 //
@@ -787,11 +761,6 @@
 
 #define poll ___xxx_poll
 
-static __inline__ void  adb_sleep_ms( int  mseconds )
-{
-    usleep( mseconds*1000 );
-}
-
 static __inline__ int  adb_mkdir(const std::string& path, int mode)
 {
     return mkdir(path.c_str(), mode);
@@ -800,10 +769,6 @@
 #undef   mkdir
 #define  mkdir  ___xxx_mkdir
 
-static __inline__ void  adb_sysdeps_init(void)
-{
-}
-
 static __inline__ int adb_is_absolute_host_path(const char* path) {
     return path[0] == '/';
 }
@@ -825,4 +790,9 @@
 // configured to drop after 10 missed keepalives. Returns true on success.
 bool set_tcp_keepalive(int fd, int interval_sec);
 
+#if defined(_WIN32)
+// Win32 defines ERROR, which we don't need, but which conflicts with google3 logging.
+#undef ERROR
+#endif
+
 #endif /* _ADB_SYSDEPS_H */
diff --git a/adb/sysdeps/chrono.h b/adb/sysdeps/chrono.h
new file mode 100644
index 0000000..c73a638
--- /dev/null
+++ b/adb/sysdeps/chrono.h
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <chrono>
+
+#if defined(_WIN32)
+// We don't have C++14 on Windows yet.
+// Reimplement std::chrono_literals ourselves until we do.
+
+// Silence the following warning (which gets promoted to an error):
+// error: literal operator suffixes not preceded by ‘_’ are reserved for future standardization
+#pragma GCC system_header
+
+constexpr std::chrono::seconds operator"" s(unsigned long long s) {
+    return std::chrono::seconds(s);
+}
+
+constexpr std::chrono::duration<long double> operator"" s(long double s) {
+    return std::chrono::duration<long double>(s);
+}
+
+constexpr std::chrono::milliseconds operator"" ms(unsigned long long ms) {
+    return std::chrono::milliseconds(ms);
+}
+
+constexpr std::chrono::duration<long double, std::milli> operator"" ms(long double ms) {
+    return std::chrono::duration<long double, std::milli>(ms);
+}
+#else
+using namespace std::chrono_literals;
+#endif
diff --git a/adb/sysdeps/mutex.h b/adb/sysdeps/mutex.h
deleted file mode 100644
index 73c9e6e..0000000
--- a/adb/sysdeps/mutex.h
+++ /dev/null
@@ -1,107 +0,0 @@
-#pragma once
-
-/*
- * 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.
- */
-
-#if defined(_WIN32)
-
-#include <windows.h>
-
-#include <android-base/macros.h>
-
-#include "adb.h"
-
-// The prebuilt version of mingw we use doesn't support mutex or recursive_mutex.
-// Therefore, implement our own using the Windows primitives.
-// Put them directly into the std namespace, so that when they're actually available, the build
-// breaks until they're removed.
-
-#include <mutex>
-namespace std {
-
-// CRITICAL_SECTION is recursive, so just wrap it in a Mutex-compatible class.
-class recursive_mutex {
-  public:
-    recursive_mutex() {
-        InitializeCriticalSection(&mutex_);
-    }
-
-    ~recursive_mutex() {
-        DeleteCriticalSection(&mutex_);
-    }
-
-    void lock() {
-        EnterCriticalSection(&mutex_);
-    }
-
-    bool try_lock() {
-        return TryEnterCriticalSection(&mutex_);
-    }
-
-    void unlock() {
-        LeaveCriticalSection(&mutex_);
-    }
-
-  private:
-    CRITICAL_SECTION mutex_;
-
-    DISALLOW_COPY_AND_ASSIGN(recursive_mutex);
-};
-
-class mutex {
-  public:
-    mutex() {
-    }
-
-    ~mutex() {
-    }
-
-    void lock() {
-        mutex_.lock();
-        if (++lock_count_ != 1) {
-            fatal("non-recursive mutex locked reentrantly");
-        }
-    }
-
-    void unlock() {
-        if (--lock_count_ != 0) {
-            fatal("non-recursive mutex unlock resulted in unexpected lock count: %d", lock_count_);
-        }
-        mutex_.unlock();
-    }
-
-    bool try_lock() {
-        if (!mutex_.try_lock()) {
-            return false;
-        }
-
-        if (lock_count_ != 0) {
-            mutex_.unlock();
-            return false;
-        }
-
-        ++lock_count_;
-        return true;
-    }
-
-  private:
-    recursive_mutex mutex_;
-    size_t lock_count_ = 0;
-};
-
-}
-
-#endif
diff --git a/adb/sysdeps_test.cpp b/adb/sysdeps_test.cpp
index 5ac8f82..9007e75 100644
--- a/adb/sysdeps_test.cpp
+++ b/adb/sysdeps_test.cpp
@@ -16,13 +16,17 @@
 
 #include <gtest/gtest.h>
 #include <unistd.h>
+
 #include <atomic>
+#include <condition_variable>
+#include <thread>
 
 #include "adb_io.h"
 #include "sysdeps.h"
+#include "sysdeps/chrono.h"
 
 static void increment_atomic_int(void* c) {
-    sleep(1);
+    std::this_thread::sleep_for(1s);
     reinterpret_cast<std::atomic<int>*>(c)->fetch_add(1);
 }
 
@@ -33,7 +37,7 @@
         ASSERT_TRUE(adb_thread_create(increment_atomic_int, &counter));
     }
 
-    sleep(2);
+    std::this_thread::sleep_for(2s);
     ASSERT_EQ(100, counter.load());
 }
 
@@ -218,7 +222,7 @@
 
 TEST_F(sysdeps_poll, fd_count) {
     // https://code.google.com/p/android/issues/detail?id=12141
-    static constexpr int num_sockets = 512;
+    static constexpr int num_sockets = 256;
     std::vector<int> sockets;
     std::vector<adb_pollfd> pfds;
     sockets.resize(num_sockets * 2);
@@ -245,7 +249,6 @@
     }
 }
 
-#include "sysdeps/mutex.h"
 TEST(sysdeps_mutex, mutex_smoke) {
     static std::atomic<bool> finished(false);
     static std::mutex &m = *new std::mutex();
@@ -255,31 +258,20 @@
         ASSERT_FALSE(m.try_lock());
         m.lock();
         finished.store(true);
-        adb_sleep_ms(200);
+        std::this_thread::sleep_for(200ms);
         m.unlock();
     }, nullptr);
 
     ASSERT_FALSE(finished.load());
-    adb_sleep_ms(100);
+    std::this_thread::sleep_for(100ms);
     ASSERT_FALSE(finished.load());
     m.unlock();
-    adb_sleep_ms(100);
+    std::this_thread::sleep_for(100ms);
     m.lock();
     ASSERT_TRUE(finished.load());
     m.unlock();
 }
 
-// Our implementation on Windows aborts on double lock.
-#if defined(_WIN32)
-TEST(sysdeps_mutex, mutex_reentrant_lock) {
-    std::mutex &m = *new std::mutex();
-
-    m.lock();
-    ASSERT_FALSE(m.try_lock());
-    EXPECT_DEATH(m.lock(), "non-recursive mutex locked reentrantly");
-}
-#endif
-
 TEST(sysdeps_mutex, recursive_mutex_smoke) {
     static std::recursive_mutex &m = *new std::recursive_mutex();
 
@@ -290,14 +282,32 @@
     adb_thread_create([](void*) {
         ASSERT_FALSE(m.try_lock());
         m.lock();
-        adb_sleep_ms(500);
+        std::this_thread::sleep_for(500ms);
         m.unlock();
     }, nullptr);
 
-    adb_sleep_ms(100);
+    std::this_thread::sleep_for(100ms);
     m.unlock();
-    adb_sleep_ms(100);
+    std::this_thread::sleep_for(100ms);
     ASSERT_FALSE(m.try_lock());
     m.lock();
     m.unlock();
 }
+
+TEST(sysdeps_condition_variable, smoke) {
+    static std::mutex &m = *new std::mutex;
+    static std::condition_variable &cond = *new std::condition_variable;
+    static volatile bool flag = false;
+
+    std::unique_lock<std::mutex> lock(m);
+    adb_thread_create([](void*) {
+        m.lock();
+        flag = true;
+        cond.notify_one();
+        m.unlock();
+    }, nullptr);
+
+    while (!flag) {
+        cond.wait(lock);
+    }
+}
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index e641680..4dd549d 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -27,6 +27,7 @@
 
 #include <algorithm>
 #include <memory>
+#include <mutex>
 #include <string>
 #include <unordered_map>
 #include <vector>
@@ -110,62 +111,6 @@
 /**************************************************************************/
 /**************************************************************************/
 /*****                                                                *****/
-/*****      replaces libs/cutils/load_file.c                          *****/
-/*****                                                                *****/
-/**************************************************************************/
-/**************************************************************************/
-
-void *load_file(const char *fn, unsigned *_sz)
-{
-    HANDLE    file;
-    char     *data;
-    DWORD     file_size;
-
-    std::wstring fn_wide;
-    if (!android::base::UTF8ToWide(fn, &fn_wide))
-        return NULL;
-
-    file = CreateFileW( fn_wide.c_str(),
-                        GENERIC_READ,
-                        FILE_SHARE_READ,
-                        NULL,
-                        OPEN_EXISTING,
-                        0,
-                        NULL );
-
-    if (file == INVALID_HANDLE_VALUE)
-        return NULL;
-
-    file_size = GetFileSize( file, NULL );
-    data      = NULL;
-
-    if (file_size > 0) {
-        data = (char*) malloc( file_size + 1 );
-        if (data == NULL) {
-            D("load_file: could not allocate %ld bytes", file_size );
-            file_size = 0;
-        } else {
-            DWORD  out_bytes;
-
-            if ( !ReadFile( file, data, file_size, &out_bytes, NULL ) ||
-                 out_bytes != file_size )
-            {
-                D("load_file: could not read %ld bytes from '%s'", file_size, fn);
-                free(data);
-                data      = NULL;
-                file_size = 0;
-            }
-        }
-    }
-    CloseHandle( file );
-
-    *_sz = (unsigned) file_size;
-    return  data;
-}
-
-/**************************************************************************/
-/**************************************************************************/
-/*****                                                                *****/
 /*****    common file descriptor handling                             *****/
 /*****                                                                *****/
 /**************************************************************************/
@@ -193,7 +138,7 @@
 #define  WIN32_FH_BASE    2048
 #define  WIN32_MAX_FHS    2048
 
-static adb_mutex_t   _win32_lock;
+static  std::mutex&  _win32_lock = *new std::mutex();
 static  FHRec        _win32_fhs[ WIN32_MAX_FHS ];
 static  int          _win32_fh_next;  // where to start search for free FHRec
 
@@ -238,27 +183,24 @@
 {
     FH   f = NULL;
 
-    adb_mutex_lock( &_win32_lock );
+    std::lock_guard<std::mutex> lock(_win32_lock);
 
     for (int i = _win32_fh_next; i < WIN32_MAX_FHS; ++i) {
         if (_win32_fhs[i].clazz == NULL) {
             f = &_win32_fhs[i];
             _win32_fh_next = i + 1;
-            goto Exit;
+            f->clazz = clazz;
+            f->used = 1;
+            f->eof = 0;
+            f->name[0] = '\0';
+            clazz->_fh_init(f);
+            return f;
         }
     }
-    D( "_fh_alloc: no more free file descriptors" );
-    errno = EMFILE;   // Too many open files
-Exit:
-    if (f) {
-        f->clazz   = clazz;
-        f->used    = 1;
-        f->eof     = 0;
-        f->name[0] = '\0';
-        clazz->_fh_init(f);
-    }
-    adb_mutex_unlock( &_win32_lock );
-    return f;
+
+    D("_fh_alloc: no more free file descriptors");
+    errno = EMFILE;  // Too many open files
+    return nullptr;
 }
 
 
@@ -267,7 +209,7 @@
 {
     // Use lock so that closing only happens once and so that _fh_alloc can't
     // allocate a FH that we're in the middle of closing.
-    adb_mutex_lock(&_win32_lock);
+    std::lock_guard<std::mutex> lock(_win32_lock);
 
     int offset = f - _win32_fhs;
     if (_win32_fh_next > offset) {
@@ -281,7 +223,6 @@
         f->used    = 0;
         f->clazz   = NULL;
     }
-    adb_mutex_unlock(&_win32_lock);
     return 0;
 }
 
@@ -1008,7 +949,7 @@
         _socket_set_errno(err);
         return -1;
     }
-    std::unique_ptr<struct addrinfo, decltype(freeaddrinfo)*> addrinfo(addrinfo_ptr, freeaddrinfo);
+    std::unique_ptr<struct addrinfo, decltype(&freeaddrinfo)> addrinfo(addrinfo_ptr, freeaddrinfo);
     addrinfo_ptr = nullptr;
 
     // TODO: Try all the addresses if there's more than one? This just uses
@@ -1117,7 +1058,7 @@
         return -1;
     }
 
-    int result = getsockname(fh->fh_socket, sockaddr, optlen);
+    int result = (getsockname)(fh->fh_socket, sockaddr, optlen);
     if (result == SOCKET_ERROR) {
         const DWORD err = WSAGetLastError();
         D("adb_getsockname: setsockopt on fd %d failed: %s\n", fd,
@@ -1128,6 +1069,24 @@
     return result;
 }
 
+int adb_socket_get_local_port(int fd) {
+    sockaddr_storage addr_storage;
+    socklen_t addr_len = sizeof(addr_storage);
+
+    if (adb_getsockname(fd, reinterpret_cast<sockaddr*>(&addr_storage), &addr_len) < 0) {
+        D("adb_socket_get_local_port: adb_getsockname failed: %s", strerror(errno));
+        return -1;
+    }
+
+    if (!(addr_storage.ss_family == AF_INET || addr_storage.ss_family == AF_INET6)) {
+        D("adb_socket_get_local_port: unknown address family received: %d", addr_storage.ss_family);
+        errno = ECONNABORTED;
+        return -1;
+    }
+
+    return ntohs(reinterpret_cast<sockaddr_in*>(&addr_storage)->sin_port);
+}
+
 int  adb_shutdown(int  fd)
 {
     FH   f = _fh_from_int(fd, __func__);
@@ -1154,42 +1113,59 @@
     int server = -1;
     int client = -1;
     int accepted = -1;
-    sockaddr_storage addr_storage;
-    socklen_t addr_len = sizeof(addr_storage);
-    sockaddr_in* addr = nullptr;
+    int local_port = -1;
     std::string error;
 
+    struct sockaddr_storage peer_addr = {};
+    struct sockaddr_storage client_addr = {};
+    socklen_t peer_socklen = sizeof(peer_addr);
+    socklen_t client_socklen = sizeof(client_addr);
+
     server = network_loopback_server(0, SOCK_STREAM, &error);
     if (server < 0) {
         D("adb_socketpair: failed to create server: %s", error.c_str());
         goto fail;
     }
 
-    if (adb_getsockname(server, reinterpret_cast<sockaddr*>(&addr_storage), &addr_len) < 0) {
-        D("adb_socketpair: adb_getsockname failed: %s", strerror(errno));
+    local_port = adb_socket_get_local_port(server);
+    if (local_port < 0) {
+        D("adb_socketpair: failed to get server port number: %s", error.c_str());
         goto fail;
     }
+    D("adb_socketpair: bound on port %d", local_port);
 
-    if (addr_storage.ss_family != AF_INET) {
-        D("adb_socketpair: unknown address family received: %d", addr_storage.ss_family);
-        errno = ECONNABORTED;
-        goto fail;
-    }
-
-    addr = reinterpret_cast<sockaddr_in*>(&addr_storage);
-    D("adb_socketpair: bound on port %d", ntohs(addr->sin_port));
-    client = network_loopback_client(ntohs(addr->sin_port), SOCK_STREAM, &error);
+    client = network_loopback_client(local_port, SOCK_STREAM, &error);
     if (client < 0) {
         D("adb_socketpair: failed to connect client: %s", error.c_str());
         goto fail;
     }
 
-    accepted = adb_socket_accept(server, nullptr, nullptr);
+    // Make sure that the peer that connected to us and the client are the same.
+    accepted = adb_socket_accept(server, reinterpret_cast<sockaddr*>(&peer_addr), &peer_socklen);
     if (accepted < 0) {
         D("adb_socketpair: failed to accept: %s", strerror(errno));
         goto fail;
     }
+
+    if (adb_getsockname(client, reinterpret_cast<sockaddr*>(&client_addr), &client_socklen) != 0) {
+        D("adb_socketpair: failed to getpeername: %s", strerror(errno));
+        goto fail;
+    }
+
+    if (peer_socklen != client_socklen) {
+        D("adb_socketpair: client and peer sockaddrs have different lengths");
+        errno = EIO;
+        goto fail;
+    }
+
+    if (memcmp(&peer_addr, &client_addr, peer_socklen) != 0) {
+        D("adb_socketpair: client and peer sockaddrs don't match");
+        errno = EIO;
+        goto fail;
+    }
+
     adb_close(server);
+
     sv[0] = client;
     sv[1] = accepted;
     return 0;
@@ -1255,17 +1231,6 @@
     return true;
 }
 
-static adb_mutex_t g_console_output_buffer_lock;
-
-void
-adb_sysdeps_init( void )
-{
-#define  ADB_MUTEX(x)  InitializeCriticalSection( & x );
-#include "mutex_list.h"
-    InitializeCriticalSection( &_win32_lock );
-    InitializeCriticalSection( &g_console_output_buffer_lock );
-}
-
 /**************************************************************************/
 /**************************************************************************/
 /*****                                                                *****/
@@ -2458,12 +2423,13 @@
 // Bytes that have not yet been output to the console because they are incomplete UTF-8 sequences.
 // Note that we use only one buffer even though stderr and stdout are logically separate streams.
 // This matches the behavior of Linux.
-// Protected by g_console_output_buffer_lock.
-static auto& g_console_output_buffer = *new std::vector<char>();
 
 // Internal helper function to write UTF-8 bytes to a console. Returns -1 on error.
 static int _console_write_utf8(const char* const buf, const size_t buf_size, FILE* stream,
                                HANDLE console) {
+    static std::mutex& console_output_buffer_lock = *new std::mutex();
+    static auto& console_output_buffer = *new std::vector<char>();
+
     const int saved_errno = errno;
     std::vector<char> combined_buffer;
 
@@ -2471,24 +2437,25 @@
     const char* utf8;
     size_t utf8_size;
 
-    adb_mutex_lock(&g_console_output_buffer_lock);
-    if (g_console_output_buffer.empty()) {
-        // If g_console_output_buffer doesn't have a buffered up incomplete UTF-8 sequence (the
-        // common case with plain ASCII), parse buf directly.
-        utf8 = buf;
-        utf8_size = internal::ParseCompleteUTF8(buf, buf + buf_size, &g_console_output_buffer);
-    } else {
-        // If g_console_output_buffer has a buffered up incomplete UTF-8 sequence, move it to
-        // combined_buffer (and effectively clear g_console_output_buffer) and append buf to
-        // combined_buffer, then parse it all together.
-        combined_buffer.swap(g_console_output_buffer);
-        combined_buffer.insert(combined_buffer.end(), buf, buf + buf_size);
+    {
+        std::lock_guard<std::mutex> lock(console_output_buffer_lock);
+        if (console_output_buffer.empty()) {
+            // If console_output_buffer doesn't have a buffered up incomplete UTF-8 sequence (the
+            // common case with plain ASCII), parse buf directly.
+            utf8 = buf;
+            utf8_size = internal::ParseCompleteUTF8(buf, buf + buf_size, &console_output_buffer);
+        } else {
+            // If console_output_buffer has a buffered up incomplete UTF-8 sequence, move it to
+            // combined_buffer (and effectively clear console_output_buffer) and append buf to
+            // combined_buffer, then parse it all together.
+            combined_buffer.swap(console_output_buffer);
+            combined_buffer.insert(combined_buffer.end(), buf, buf + buf_size);
 
-        utf8 = combined_buffer.data();
-        utf8_size = internal::ParseCompleteUTF8(utf8, utf8 + combined_buffer.size(),
-                                                &g_console_output_buffer);
+            utf8 = combined_buffer.data();
+            utf8_size = internal::ParseCompleteUTF8(utf8, utf8 + combined_buffer.size(),
+                                                    &console_output_buffer);
+        }
     }
-    adb_mutex_unlock(&g_console_output_buffer_lock);
 
     std::wstring utf16;
 
diff --git a/adb/test_adb.py b/adb/test_adb.py
index 0f1b034..cb3e0d8 100644
--- a/adb/test_adb.py
+++ b/adb/test_adb.py
@@ -207,6 +207,28 @@
             # reading the response from the adb emu kill command (on Windows).
             self.assertEqual(0, p.returncode)
 
+    def test_connect_ipv4_ipv6(self):
+        """Ensure that `adb connect localhost:1234` will try both IPv4 and IPv6.
+
+        Bug: http://b/30313466
+        """
+        ipv4 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        ipv4.bind(('127.0.0.1', 0))
+        ipv4.listen(1)
+
+        ipv6 = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
+        ipv6.bind(('::1', ipv4.getsockname()[1] + 1))
+        ipv6.listen(1)
+
+        for s in (ipv4, ipv6):
+            port = s.getsockname()[1]
+            output = subprocess.check_output(
+                ['adb', 'connect', 'localhost:{}'.format(port)])
+
+            self.assertEqual(
+                output.strip(), 'connected to localhost:{}'.format(port))
+            s.close()
+
 
 def main():
     random.seed(0)
diff --git a/adb/test_device.py b/adb/test_device.py
index 9dab3ae..02a16e4 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -31,6 +31,7 @@
 import subprocess
 import sys
 import tempfile
+import time
 import unittest
 
 import mock
@@ -191,6 +192,22 @@
         msg = self.device.forward_list()
         self.assertEqual('', msg.strip())
 
+    def test_forward_tcp_port_0(self):
+        self.assertEqual('', self.device.forward_list().strip(),
+                         'Forwarding list must be empty to run this test.')
+
+        try:
+            # If resolving TCP port 0 is supported, `adb forward` will print
+            # the actual port number.
+            port = self.device.forward('tcp:0', 'tcp:8888').strip()
+            if not port:
+                raise unittest.SkipTest('Forwarding tcp:0 is not available.')
+
+            self.assertTrue(re.search(r'tcp:{}.+tcp:8888'.format(port),
+                                      self.device.forward_list()))
+        finally:
+            self.device.forward_remove_all()
+
     def test_reverse(self):
         msg = self.device.reverse_list()
         self.assertEqual('', msg.strip(),
@@ -210,6 +227,22 @@
         msg = self.device.reverse_list()
         self.assertEqual('', msg.strip())
 
+    def test_reverse_tcp_port_0(self):
+        self.assertEqual('', self.device.reverse_list().strip(),
+                         'Reverse list must be empty to run this test.')
+
+        try:
+            # If resolving TCP port 0 is supported, `adb reverse` will print
+            # the actual port number.
+            port = self.device.reverse('tcp:0', 'tcp:8888').strip()
+            if not port:
+                raise unittest.SkipTest('Reversing tcp:0 is not available.')
+
+            self.assertTrue(re.search(r'tcp:{}.+tcp:8888'.format(port),
+                                      self.device.reverse_list()))
+        finally:
+            self.device.reverse_remove_all()
+
     # Note: If you run this test when adb connect'd to a physical device over
     # TCP, it will fail in adb reverse due to https://code.google.com/p/android/issues/detail?id=189821
     def test_forward_reverse_echo(self):
@@ -279,7 +312,7 @@
         Raises:
           unittest.SkipTest: The device doesn't support exit codes.
         """
-        if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+        if not self.device.has_shell_protocol():
             raise unittest.SkipTest('exit codes are unavailable on this device')
 
         proc = subprocess.Popen(
@@ -338,15 +371,8 @@
     def test_pty_logic(self):
         """Tests that a PTY is allocated when it should be.
 
-        PTY allocation behavior should match ssh; some behavior requires
-        a terminal stdin to test so this test will be skipped if stdin
-        is not a terminal.
+        PTY allocation behavior should match ssh.
         """
-        if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
-            raise unittest.SkipTest('PTY arguments unsupported on this device')
-        if not os.isatty(sys.stdin.fileno()):
-            raise unittest.SkipTest('PTY tests require stdin terminal')
-
         def check_pty(args):
             """Checks adb shell PTY allocation.
 
@@ -376,16 +402,34 @@
         # -T: never allocate PTY.
         self.assertEqual((False, False), check_pty(['-T']))
 
-        # No args: PTY only if stdin is a terminal and shell is interactive,
-        # which is difficult to reliably test from a script.
-        self.assertEqual((False, False), check_pty([]))
+        # These tests require a new device.
+        if self.device.has_shell_protocol() and os.isatty(sys.stdin.fileno()):
+            # No args: PTY only if stdin is a terminal and shell is interactive,
+            # which is difficult to reliably test from a script.
+            self.assertEqual((False, False), check_pty([]))
 
-        # -t: PTY if stdin is a terminal.
-        self.assertEqual((True, False), check_pty(['-t']))
+            # -t: PTY if stdin is a terminal.
+            self.assertEqual((True, False), check_pty(['-t']))
 
         # -t -t: always allocate PTY.
         self.assertEqual((True, True), check_pty(['-t', '-t']))
 
+        # -tt: always allocate PTY, POSIX style (http://b/32216152).
+        self.assertEqual((True, True), check_pty(['-tt']))
+
+        # -ttt: ssh has weird even/odd behavior with multiple -t flags, but
+        # we follow the man page instead.
+        self.assertEqual((True, True), check_pty(['-ttt']))
+
+        # -ttx: -x and -tt aren't incompatible (though -Tx would be an error).
+        self.assertEqual((True, True), check_pty(['-ttx']))
+
+        # -Ttt: -tt cancels out -T.
+        self.assertEqual((True, True), check_pty(['-Ttt']))
+
+        # -ttT: -T cancels out -tt.
+        self.assertEqual((False, False), check_pty(['-ttT']))
+
     def test_shell_protocol(self):
         """Tests the shell protocol on the device.
 
@@ -394,7 +438,7 @@
 
         Bug: http://b/19734861
         """
-        if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+        if not self.device.has_shell_protocol():
             raise unittest.SkipTest('shell protocol unsupported on this device')
 
         # Shell protocol should be used by default.
@@ -424,7 +468,7 @@
 
         Bug: http://b/23825725
         """
-        if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+        if not self.device.has_shell_protocol():
             raise unittest.SkipTest('shell protocol unsupported on this device')
 
         # Start a long-running process.
@@ -440,12 +484,16 @@
         self.device.shell(proc_query)
         os.kill(sleep_proc.pid, signal.SIGINT)
         sleep_proc.communicate()
-        self.assertEqual(1, self.device.shell_nocheck(proc_query)[0],
-                         'subprocess failed to terminate')
+
+        # It can take some time for the process to receive the signal and die.
+        end_time = time.time() + 3
+        while self.device.shell_nocheck(proc_query)[0] != 1:
+            self.assertFalse(time.time() > end_time,
+                             'subprocess failed to terminate in time')
 
     def test_non_interactive_stdin(self):
         """Tests that non-interactive shells send stdin."""
-        if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+        if not self.device.has_shell_protocol():
             raise unittest.SkipTest('non-interactive stdin unsupported '
                                     'on this device')
 
@@ -463,6 +511,37 @@
             self.assertEqual(input.splitlines(), stdout.splitlines())
             self.assertEqual('', stderr)
 
+    def test_sighup(self):
+        """Ensure that SIGHUP gets sent upon non-interactive ctrl-c"""
+        log_path = "/data/local/tmp/adb_signal_test.log"
+
+        # Clear the output file.
+        self.device.shell_nocheck(["echo", ">", log_path])
+
+        script = """
+            trap "echo SIGINT > {path}; exit 0" SIGINT
+            trap "echo SIGHUP > {path}; exit 0" SIGHUP
+            echo Waiting
+            read
+        """.format(path=log_path)
+
+        script = ";".join([x.strip() for x in script.strip().splitlines()])
+
+        process = self.device.shell_popen([script], kill_atexit=False,
+                                          stdin=subprocess.PIPE,
+                                          stdout=subprocess.PIPE)
+
+        self.assertEqual("Waiting\n", process.stdout.readline())
+        process.send_signal(signal.SIGINT)
+        process.wait()
+
+        # Waiting for the local adb to finish is insufficient, since it hangs
+        # up immediately.
+        time.sleep(1)
+
+        stdout, _ = self.device.shell(["cat", log_path])
+        self.assertEqual(stdout.strip(), "SIGHUP")
+
 
 class ArgumentEscapingTest(DeviceTest):
     def test_shell_escaping(self):
@@ -724,6 +803,36 @@
             if host_dir is not None:
                 shutil.rmtree(host_dir)
 
+    @unittest.skipIf(sys.platform == "win32", "symlinks require elevated privileges on windows")
+    def test_push_symlink(self):
+        """Push a symlink.
+
+        Bug: http://b/31491920
+        """
+        try:
+            host_dir = tempfile.mkdtemp()
+
+            # Make sure the temp directory isn't setuid, or else adb will
+            # complain.
+            os.chmod(host_dir, 0o700)
+
+            with open(os.path.join(host_dir, 'foo'), 'w') as f:
+                f.write('foo')
+
+            symlink_path = os.path.join(host_dir, 'symlink')
+            os.symlink('foo', symlink_path)
+
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+            self.device.shell(['mkdir', self.DEVICE_TEMP_DIR])
+            self.device.push(symlink_path, self.DEVICE_TEMP_DIR)
+            rc, out, _ = self.device.shell_nocheck(
+                ['cat', posixpath.join(self.DEVICE_TEMP_DIR, 'symlink')])
+            self.assertEqual(0, rc)
+            self.assertEqual(out.strip(), 'foo')
+        finally:
+            if host_dir is not None:
+                shutil.rmtree(host_dir)
+
     def test_multiple_push(self):
         """Push multiple files to the device in one adb push command.
 
diff --git a/adb/test_track_devices.cpp b/adb/test_track_devices.cpp
deleted file mode 100644
index b10f8ee..0000000
--- a/adb/test_track_devices.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-// TODO: replace this with a shell/python script.
-
-/* a simple test program, connects to ADB server, and opens a track-devices session */
-#include <errno.h>
-#include <memory.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <android-base/file.h>
-
-static void
-panic( const char*  msg )
-{
-    fprintf(stderr, "PANIC: %s: %s\n", msg, strerror(errno));
-    exit(1);
-}
-
-int main(int argc, char* argv[]) {
-    const char* request = "host:track-devices";
-
-    if (argv[1] && strcmp(argv[1], "--jdwp") == 0) {
-        request = "track-jdwp";
-    }
-
-    int                  ret;
-    struct sockaddr_in   server;
-    char                 buffer[1024];
-
-    memset( &server, 0, sizeof(server) );
-    server.sin_family      = AF_INET;
-    server.sin_port        = htons(5037);
-    server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
-    int s = socket( PF_INET, SOCK_STREAM, 0 );
-    ret = connect( s, (struct sockaddr*) &server, sizeof(server) );
-    if (ret < 0) panic( "could not connect to server" );
-
-    /* send the request */
-    int len = snprintf(buffer, sizeof(buffer), "%04zx%s", strlen(request), request);
-    if (!android::base::WriteFully(s, buffer, len))
-        panic( "could not send request" );
-
-    /* read the OKAY answer */
-    if (!android::base::ReadFully(s, buffer, 4))
-        panic( "could not read request" );
-
-    printf( "server answer: %.*s\n", 4, buffer );
-
-    /* now loop */
-    while (true) {
-        char  head[5] = "0000";
-
-        if (!android::base::ReadFully(s, head, 4))
-            panic("could not read length");
-
-        int len;
-        if (sscanf(head, "%04x", &len) != 1 )
-            panic("could not decode length");
-
-        if (!android::base::ReadFully(s, buffer, len))
-            panic("could not read data");
-
-        printf( "received header %.*s (%d bytes):\n%.*s----\n", 4, head, len, len, buffer );
-    }
-    close(s);
-}
diff --git a/adb/transport.cpp b/adb/transport.cpp
index c31f655..132702d 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -28,6 +28,7 @@
 
 #include <algorithm>
 #include <list>
+#include <mutex>
 
 #include <android-base/logging.h>
 #include <android-base/parsenetaddress.h>
@@ -35,6 +36,7 @@
 #include <android-base/strings.h>
 
 #include "adb.h"
+#include "adb_auth.h"
 #include "adb_utils.h"
 #include "diagnose_usb.h"
 
@@ -43,7 +45,7 @@
 static auto& transport_list = *new std::list<atransport*>();
 static auto& pending_list = *new std::list<atransport*>();
 
-ADB_MUTEX_DEFINE( transport_lock );
+static std::mutex& transport_lock = *new std::mutex();
 
 const char* const kFeatureShell2 = "shell_v2";
 const char* const kFeatureCmd = "cmd";
@@ -148,32 +150,17 @@
     }
 }
 
-void send_packet(apacket *p, atransport *t)
-{
-    unsigned char *x;
-    unsigned sum;
-    unsigned count;
-
+void send_packet(apacket* p, atransport* t) {
     p->msg.magic = p->msg.command ^ 0xffffffff;
-
-    count = p->msg.data_length;
-    x = (unsigned char *) p->data;
-    sum = 0;
-    while(count-- > 0){
-        sum += *x++;
-    }
-    p->msg.data_check = sum;
+    p->msg.data_check = calculate_apacket_checksum(p);
 
     print_packet("send", p);
 
     if (t == NULL) {
-        D("Transport is null");
-        // Zap errno because print_packet() and other stuff have errno effect.
-        errno = 0;
-        fatal_errno("Transport is null");
+        fatal("Transport is null");
     }
 
-    if(write_packet(t->transport_socket, t->serial, &p)){
+    if (write_packet(t->transport_socket, t->serial, &p)) {
         fatal_errno("cannot enqueue packet on transport socket");
     }
 }
@@ -296,13 +283,12 @@
 }
 
 void kick_transport(atransport* t) {
-    adb_mutex_lock(&transport_lock);
+    std::lock_guard<std::mutex> lock(transport_lock);
     // As kick_transport() can be called from threads without guarantee that t is valid,
     // check if the transport is in transport_list first.
     if (std::find(transport_list.begin(), transport_list.end(), t) != transport_list.end()) {
         t->Kick();
     }
-    adb_mutex_unlock(&transport_lock);
 }
 
 static int transport_registration_send = -1;
@@ -332,7 +318,7 @@
     device_tracker**  pnode = &device_tracker_list;
     device_tracker*   node  = *pnode;
 
-    adb_mutex_lock( &transport_lock );
+    std::lock_guard<std::mutex> lock(transport_lock);
     while (node) {
         if (node == tracker) {
             *pnode = node->next;
@@ -341,7 +327,6 @@
         pnode = &node->next;
         node  = *pnode;
     }
-    adb_mutex_unlock( &transport_lock );
 }
 
 static void
@@ -503,9 +488,10 @@
         fdevent_remove(&(t->transport_fde));
         adb_close(t->fd);
 
-        adb_mutex_lock(&transport_lock);
-        transport_list.remove(t);
-        adb_mutex_unlock(&transport_lock);
+        {
+            std::lock_guard<std::mutex> lock(transport_lock);
+            transport_list.remove(t);
+        }
 
         if (t->product)
             free(t->product);
@@ -554,10 +540,11 @@
         }
     }
 
-    adb_mutex_lock(&transport_lock);
-    pending_list.remove(t);
-    transport_list.push_front(t);
-    adb_mutex_unlock(&transport_lock);
+    {
+        std::lock_guard<std::mutex> lock(transport_lock);
+        pending_list.remove(t);
+        transport_list.push_front(t);
+    }
 
     update_transports();
 }
@@ -608,7 +595,8 @@
 
 static void transport_unref(atransport* t) {
     CHECK(t != nullptr);
-    adb_mutex_lock(&transport_lock);
+
+    std::lock_guard<std::mutex> lock(transport_lock);
     CHECK_GT(t->ref_count, 0u);
     t->ref_count--;
     if (t->ref_count == 0) {
@@ -618,7 +606,6 @@
     } else {
         D("transport: %s unref (count=%zu)", t->serial, t->ref_count);
     }
-    adb_mutex_unlock(&transport_lock);
 }
 
 static int qual_match(const char *to_test,
@@ -664,7 +651,7 @@
         *error_out = "no devices found";
     }
 
-    adb_mutex_lock(&transport_lock);
+    std::unique_lock<std::mutex> lock(transport_lock);
     for (const auto& t : transport_list) {
         if (t->connection_state == kCsNoPerm) {
 #if ADB_HOST
@@ -712,7 +699,7 @@
             }
         }
     }
-    adb_mutex_unlock(&transport_lock);
+    lock.unlock();
 
     // Don't return unauthorized devices; the caller can't do anything with them.
     if (result && result->connection_state == kCsUnauthorized) {
@@ -913,21 +900,26 @@
 
 std::string list_transports(bool long_listing) {
     std::string result;
-    adb_mutex_lock(&transport_lock);
+
+    std::lock_guard<std::mutex> lock(transport_lock);
     for (const auto& t : transport_list) {
         append_transport(t, &result, long_listing);
     }
-    adb_mutex_unlock(&transport_lock);
     return result;
 }
 
+void close_usb_devices(std::function<bool(const atransport*)> predicate) {
+    std::lock_guard<std::mutex> lock(transport_lock);
+    for (auto& t : transport_list) {
+        if (predicate(t)) {
+            t->Kick();
+        }
+    }
+}
+
 /* hack for osx */
 void close_usb_devices() {
-    adb_mutex_lock(&transport_lock);
-    for (const auto& t : transport_list) {
-        t->Kick();
-    }
-    adb_mutex_unlock(&transport_lock);
+    close_usb_devices([](const atransport*) { return true; });
 }
 #endif // ADB_HOST
 
@@ -946,10 +938,11 @@
         return -1;
     }
 
-    adb_mutex_lock(&transport_lock);
+    std::unique_lock<std::mutex> lock(transport_lock);
     for (const auto& transport : pending_list) {
         if (transport->serial && strcmp(serial, transport->serial) == 0) {
-            adb_mutex_unlock(&transport_lock);
+            VLOG(TRANSPORT) << "socket transport " << transport->serial
+                << " is already in pending_list and fails to register";
             delete t;
             return -1;
         }
@@ -957,7 +950,8 @@
 
     for (const auto& transport : transport_list) {
         if (transport->serial && strcmp(serial, transport->serial) == 0) {
-            adb_mutex_unlock(&transport_lock);
+            VLOG(TRANSPORT) << "socket transport " << transport->serial
+                << " is already in transport_list and fails to register";
             delete t;
             return -1;
         }
@@ -965,7 +959,8 @@
 
     pending_list.push_front(t);
     t->serial = strdup(serial);
-    adb_mutex_unlock(&transport_lock);
+
+    lock.unlock();
 
     register_transport(t);
     return 0;
@@ -975,23 +970,21 @@
 atransport *find_transport(const char *serial) {
     atransport* result = nullptr;
 
-    adb_mutex_lock(&transport_lock);
+    std::lock_guard<std::mutex> lock(transport_lock);
     for (auto& t : transport_list) {
         if (t->serial && strcmp(serial, t->serial) == 0) {
             result = t;
             break;
         }
     }
-    adb_mutex_unlock(&transport_lock);
 
     return result;
 }
 
 void kick_all_tcp_devices() {
-    adb_mutex_lock(&transport_lock);
+    std::lock_guard<std::mutex> lock(transport_lock);
     for (auto& t : transport_list) {
-        // TCP/IP devices have adb_port == 0.
-        if (t->type == kTransportLocal && t->adb_port == 0) {
+        if (t->IsTcpDevice()) {
             // Kicking breaks the read_transport thread of this transport out of any read, then
             // the read_transport thread will notify the main thread to make this transport
             // offline. Then the main thread will notify the write_transport thread to exit.
@@ -999,7 +992,6 @@
             t->Kick();
         }
     }
-    adb_mutex_unlock(&transport_lock);
 }
 
 #endif
@@ -1019,20 +1011,20 @@
         t->devpath = strdup(devpath);
     }
 
-    adb_mutex_lock(&transport_lock);
-    pending_list.push_front(t);
-    adb_mutex_unlock(&transport_lock);
+    {
+        std::lock_guard<std::mutex> lock(transport_lock);
+        pending_list.push_front(t);
+    }
 
     register_transport(t);
 }
 
 // This should only be used for transports with connection_state == kCsNoPerm.
 void unregister_usb_transport(usb_handle *usb) {
-    adb_mutex_lock(&transport_lock);
+    std::lock_guard<std::mutex> lock(transport_lock);
     transport_list.remove_if([usb](atransport* t) {
         return t->usb == usb && t->connection_state == kCsNoPerm;
     });
-    adb_mutex_unlock(&transport_lock);
 }
 
 int check_header(apacket *p, atransport *t)
@@ -1051,21 +1043,19 @@
     return 0;
 }
 
-int check_data(apacket *p)
-{
-    unsigned count, sum;
-    unsigned char *x;
-
-    count = p->msg.data_length;
-    x = p->data;
-    sum = 0;
-    while(count-- > 0) {
-        sum += *x++;
-    }
-
-    if(sum != p->msg.data_check) {
+int check_data(apacket* p) {
+    if (calculate_apacket_checksum(p) != p->msg.data_check) {
         return -1;
-    } else {
-        return 0;
     }
+    return 0;
 }
+
+#if ADB_HOST
+std::shared_ptr<RSA> atransport::NextKey() {
+    if (keys_.empty()) keys_ = adb_auth_get_private_keys();
+
+    std::shared_ptr<RSA> result = keys_[0];
+    keys_.pop_front();
+    return result;
+}
+#endif
diff --git a/adb/transport.h b/adb/transport.h
index 35d7b50..b2df838 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -19,12 +19,17 @@
 
 #include <sys/types.h>
 
+#include <deque>
+#include <functional>
 #include <list>
+#include <memory>
 #include <string>
 #include <unordered_set>
 
 #include "adb.h"
 
+#include <openssl/rsa.h>
+
 typedef std::unordered_set<std::string> FeatureSet;
 
 const FeatureSet& supported_features();
@@ -87,10 +92,28 @@
     char* model = nullptr;
     char* device = nullptr;
     char* devpath = nullptr;
-    int adb_port = -1;  // Use for emulators (local transport)
+    void SetLocalPortForEmulator(int port) {
+        CHECK_EQ(local_port_for_emulator_, -1);
+        local_port_for_emulator_ = port;
+    }
 
-    void* key = nullptr;
-    unsigned char token[TOKEN_SIZE] = {};
+    bool GetLocalPortForEmulator(int* port) const {
+        if (type == kTransportLocal && local_port_for_emulator_ != -1) {
+            *port = local_port_for_emulator_;
+            return true;
+        }
+        return false;
+    }
+
+    bool IsTcpDevice() const {
+        return type == kTransportLocal && local_port_for_emulator_ == -1;
+    }
+
+#if ADB_HOST
+    std::shared_ptr<RSA> NextKey();
+#endif
+
+    char token[TOKEN_SIZE] = {};
     size_t failed_auth_attempts = 0;
 
     const std::string connection_state_name() const;
@@ -128,6 +151,7 @@
     bool MatchesTarget(const std::string& target) const;
 
 private:
+    int local_port_for_emulator_ = -1;
     bool kicked_ = false;
     void (*kick_func_)(atransport*) = nullptr;
 
@@ -140,6 +164,10 @@
     // A list of adisconnect callbacks called when the transport is kicked.
     std::list<adisconnect*> disconnects_;
 
+#if ADB_HOST
+    std::deque<std::shared_ptr<RSA>> keys_;
+#endif
+
     DISALLOW_COPY_AND_ASSIGN(atransport);
 };
 
@@ -172,8 +200,8 @@
 int check_header(apacket* p, atransport* t);
 int check_data(apacket* p);
 
-/* for MacOS X cleanup */
 void close_usb_devices();
+void close_usb_devices(std::function<bool(const atransport*)> predicate);
 
 void send_packet(apacket* p, atransport* t);
 
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 1f5a258..c17f869 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -25,16 +25,22 @@
 #include <string.h>
 #include <sys/types.h>
 
+#include <condition_variable>
+#include <mutex>
+#include <thread>
+#include <vector>
+
 #include <android-base/stringprintf.h>
 #include <cutils/sockets.h>
 
 #if !ADB_HOST
-#include "cutils/properties.h"
+#include <android-base/properties.h>
 #endif
 
 #include "adb.h"
 #include "adb_io.h"
 #include "adb_utils.h"
+#include "sysdeps/chrono.h"
 
 #if ADB_HOST
 
@@ -44,7 +50,7 @@
 // connected.
 #define ADB_LOCAL_TRANSPORT_MAX 16
 
-ADB_MUTEX_DEFINE(local_transports_lock);
+static std::mutex& local_transports_lock = *new std::mutex();
 
 /* we keep a list of opened transports. The atransport struct knows to which
  * local transport it is connected. The list is used to detect when we're
@@ -90,9 +96,9 @@
     return 0;
 }
 
-void local_connect(int port) {
+bool local_connect(int port) {
     std::string dummy;
-    local_connect_arbitrary_ports(port-1, port, &dummy);
+    return local_connect_arbitrary_ports(port-1, port, &dummy) == 0;
 }
 
 int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* error) {
@@ -127,18 +133,71 @@
 }
 
 #if ADB_HOST
+
+static void PollAllLocalPortsForEmulator() {
+    int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
+    int count = ADB_LOCAL_TRANSPORT_MAX;
+
+    // Try to connect to any number of running emulator instances.
+    for ( ; count > 0; count--, port += 2 ) {
+        local_connect(port);
+    }
+}
+
+// Retry the disconnected local port for 60 times, and sleep 1 second between two retries.
+constexpr uint32_t LOCAL_PORT_RETRY_COUNT = 60;
+constexpr auto LOCAL_PORT_RETRY_INTERVAL = 1s;
+
+struct RetryPort {
+    int port;
+    uint32_t retry_count;
+};
+
+// Retry emulators just kicked.
+static std::vector<RetryPort>& retry_ports = *new std::vector<RetryPort>;
+std::mutex &retry_ports_lock = *new std::mutex;
+std::condition_variable &retry_ports_cond = *new std::condition_variable;
+
 static void client_socket_thread(void* x) {
     adb_thread_setname("client_socket_thread");
     D("transport: client_socket_thread() starting");
+    PollAllLocalPortsForEmulator();
     while (true) {
-        int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
-        int count = ADB_LOCAL_TRANSPORT_MAX;
-
-        // Try to connect to any number of running emulator instances.
-        for ( ; count > 0; count--, port += 2 ) {
-            local_connect(port);
+        std::vector<RetryPort> ports;
+        // Collect retry ports.
+        {
+            std::unique_lock<std::mutex> lock(retry_ports_lock);
+            while (retry_ports.empty()) {
+                retry_ports_cond.wait(lock);
+            }
+            retry_ports.swap(ports);
         }
-        sleep(1);
+        // Sleep here instead of the end of loop, because if we immediately try to reconnect
+        // the emulator just kicked, the adbd on the emulator may not have time to remove the
+        // just kicked transport.
+        std::this_thread::sleep_for(LOCAL_PORT_RETRY_INTERVAL);
+
+        // Try connecting retry ports.
+        std::vector<RetryPort> next_ports;
+        for (auto& port : ports) {
+            VLOG(TRANSPORT) << "retry port " << port.port << ", last retry_count "
+                << port.retry_count;
+            if (local_connect(port.port)) {
+                VLOG(TRANSPORT) << "retry port " << port.port << " successfully";
+                continue;
+            }
+            if (--port.retry_count > 0) {
+                next_ports.push_back(port);
+            } else {
+                VLOG(TRANSPORT) << "stop retrying port " << port.port;
+            }
+        }
+
+        // Copy back left retry ports.
+        {
+            std::unique_lock<std::mutex> lock(retry_ports_lock);
+            retry_ports.insert(retry_ports.end(), next_ports.begin(), next_ports.end());
+        }
     }
 }
 
@@ -146,9 +205,6 @@
 
 static void server_socket_thread(void* arg) {
     int serverfd, fd;
-    sockaddr_storage ss;
-    sockaddr *addrp = reinterpret_cast<sockaddr*>(&ss);
-    socklen_t alen;
     int port = (int) (uintptr_t) arg;
 
     adb_thread_setname("server socket");
@@ -160,20 +216,22 @@
             serverfd = network_inaddr_any_server(port, SOCK_STREAM, &error);
             if(serverfd < 0) {
                 D("server: cannot bind socket yet: %s", error.c_str());
-                adb_sleep_ms(1000);
+                std::this_thread::sleep_for(1s);
                 continue;
             }
             close_on_exec(serverfd);
         }
 
-        alen = sizeof(ss);
         D("server: trying to get new connection from %d", port);
-        fd = adb_socket_accept(serverfd, addrp, &alen);
+        fd = adb_socket_accept(serverfd, nullptr, nullptr);
         if(fd >= 0) {
             D("server: new connection on fd %d", fd);
             close_on_exec(fd);
             disable_tcp_nagle(fd);
-            register_socket_transport(fd, "host", port, 1);
+            std::string serial = android::base::StringPrintf("host-%d", fd);
+            if (register_socket_transport(fd, serial.c_str(), port, 1) != 0) {
+                adb_close(fd);
+            }
         }
     }
     D("transport: server_socket_thread() exiting");
@@ -182,16 +240,20 @@
 /* This is relevant only for ADB daemon running inside the emulator. */
 /*
  * Redefine open and write for qemu_pipe.h that contains inlined references
- * to those routines. We will redifine them back after qemu_pipe.h inclusion.
+ * to those routines. We will redefine them back after qemu_pipe.h inclusion.
  */
 #undef open
+#undef read
 #undef write
 #define open    adb_open
+#define read    adb_read
 #define write   adb_write
-#include <hardware/qemu_pipe.h>
+#include <system/qemu_pipe.h>
 #undef open
+#undef read
 #undef write
 #define open    ___xxx_open
+#define read    ___xxx_read
 #define write   ___xxx_write
 
 /* A worker thread that monitors host connections, and registers a transport for
@@ -239,7 +301,7 @@
     D("transport: qemu_socket_thread() starting");
 
     /* adb QEMUD service connection request. */
-    snprintf(con_name, sizeof(con_name), "qemud:adb:%d", port);
+    snprintf(con_name, sizeof(con_name), "pipe:qemud:adb:%d", port);
 
     /* Connect to the adb QEMUD service. */
     fd = qemu_pipe_open(con_name);
@@ -267,8 +329,8 @@
                 /* Host is connected. Register the transport, and start the
                  * exchange. */
                 std::string serial = android::base::StringPrintf("host-%d", fd);
-                register_socket_transport(fd, serial.c_str(), port, 1);
-                if (!WriteFdExactly(fd, _start_req, strlen(_start_req))) {
+                if (register_socket_transport(fd, serial.c_str(), port, 1) != 0 ||
+                    !WriteFdExactly(fd, _start_req, strlen(_start_req))) {
                     adb_close(fd);
                 }
             }
@@ -298,15 +360,13 @@
     func = client_socket_thread;
     debug_name = "client";
 #else
-    /* For the adbd daemon in the system image we need to distinguish
-     * between the device, and the emulator. */
-    char is_qemu[PROPERTY_VALUE_MAX];
-    property_get("ro.kernel.qemu", is_qemu, "");
-    if (!strcmp(is_qemu, "1")) {
-        /* Running inside the emulator: use QEMUD pipe as the transport. */
+    // For the adbd daemon in the system image we need to distinguish
+    // between the device, and the emulator.
+    if (android::base::GetBoolProperty("ro.kernel.qemu", false)) {
+        // Running inside the emulator: use QEMUD pipe as the transport.
         func = qemu_socket_thread;
     } else {
-        /* Running inside the device: use TCP socket as the transport. */
+        // Running inside the device: use TCP socket as the transport.
         func = server_socket_thread;
     }
     debug_name = "server";
@@ -327,14 +387,13 @@
 
 #if ADB_HOST
     int  nn;
-    adb_mutex_lock( &local_transports_lock );
+    std::lock_guard<std::mutex> lock(local_transports_lock);
     for (nn = 0; nn < ADB_LOCAL_TRANSPORT_MAX; nn++) {
         if (local_transports[nn] == t) {
             local_transports[nn] = NULL;
             break;
         }
     }
-    adb_mutex_unlock( &local_transports_lock );
 #endif
 }
 
@@ -345,17 +404,32 @@
         t->sfd = -1;
         adb_close(fd);
     }
+#if ADB_HOST
+    int local_port;
+    if (t->GetLocalPortForEmulator(&local_port)) {
+        VLOG(TRANSPORT) << "remote_close, local_port = " << local_port;
+        std::unique_lock<std::mutex> lock(retry_ports_lock);
+        RetryPort port;
+        port.port = local_port;
+        port.retry_count = LOCAL_PORT_RETRY_COUNT;
+        retry_ports.push_back(port);
+        retry_ports_cond.notify_one();
+    }
+#endif
 }
 
 
 #if ADB_HOST
 /* Only call this function if you already hold local_transports_lock. */
-atransport* find_emulator_transport_by_adb_port_locked(int adb_port)
+static atransport* find_emulator_transport_by_adb_port_locked(int adb_port)
 {
     int i;
     for (i = 0; i < ADB_LOCAL_TRANSPORT_MAX; i++) {
-        if (local_transports[i] && local_transports[i]->adb_port == adb_port) {
-            return local_transports[i];
+        int local_port;
+        if (local_transports[i] && local_transports[i]->GetLocalPortForEmulator(&local_port)) {
+            if (local_port == adb_port) {
+                return local_transports[i];
+            }
         }
     }
     return NULL;
@@ -368,9 +442,8 @@
 
 atransport* find_emulator_transport_by_adb_port(int adb_port)
 {
-    adb_mutex_lock( &local_transports_lock );
+    std::lock_guard<std::mutex> lock(local_transports_lock);
     atransport* result = find_emulator_transport_by_adb_port_locked(adb_port);
-    adb_mutex_unlock( &local_transports_lock );
     return result;
 }
 
@@ -394,9 +467,8 @@
 
 int get_available_local_transport_index()
 {
-    adb_mutex_lock( &local_transports_lock );
+    std::lock_guard<std::mutex> lock(local_transports_lock);
     int result = get_available_local_transport_index_locked();
-    adb_mutex_unlock( &local_transports_lock );
     return result;
 }
 #endif
@@ -413,30 +485,23 @@
     t->sync_token = 1;
     t->connection_state = kCsOffline;
     t->type = kTransportLocal;
-    t->adb_port = 0;
 
 #if ADB_HOST
     if (local) {
-        adb_mutex_lock( &local_transports_lock );
-        {
-            t->adb_port = adb_port;
-            atransport* existing_transport =
-                    find_emulator_transport_by_adb_port_locked(adb_port);
-            int index = get_available_local_transport_index_locked();
-            if (existing_transport != NULL) {
-                D("local transport for port %d already registered (%p)?",
-                adb_port, existing_transport);
-                fail = -1;
-            } else if (index < 0) {
-                // Too many emulators.
-                D("cannot register more emulators. Maximum is %d",
-                        ADB_LOCAL_TRANSPORT_MAX);
-                fail = -1;
-            } else {
-                local_transports[index] = t;
-            }
-       }
-       adb_mutex_unlock( &local_transports_lock );
+        std::lock_guard<std::mutex> lock(local_transports_lock);
+        t->SetLocalPortForEmulator(adb_port);
+        atransport* existing_transport = find_emulator_transport_by_adb_port_locked(adb_port);
+        int index = get_available_local_transport_index_locked();
+        if (existing_transport != NULL) {
+            D("local transport for port %d already registered (%p)?", adb_port, existing_transport);
+            fail = -1;
+        } else if (index < 0) {
+            // Too many emulators.
+            D("cannot register more emulators. Maximum is %d", ADB_LOCAL_TRANSPORT_MAX);
+            fail = -1;
+        } else {
+            local_transports[index] = t;
+        }
     }
 #endif
     return fail;
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index a6db07a..8b38e03 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -20,27 +20,6 @@
 
 #include "adb.h"
 
-class TransportSetup {
-public:
-  TransportSetup() {
-#ifdef _WIN32
-    // Use extern instead of including sysdeps.h which brings in various macros
-    // that conflict with APIs used in this file.
-    extern void adb_sysdeps_init(void);
-    adb_sysdeps_init();
-#else
-    // adb_sysdeps_init() is an inline function that we cannot link against.
-#endif
-  }
-};
-
-// Static initializer will call adb_sysdeps_init() before main() to initialize
-// the transport mutex before it is used in the tests. Alternatives would be to
-// use __attribute__((constructor)) here or to use that or a static initializer
-// for adb_sysdeps_init() itself in sysdeps_win32.cpp (caveats of unclear
-// init order), or to use a test fixture whose SetUp() could do the init once.
-static TransportSetup g_TransportSetup;
-
 TEST(transport, kick_transport) {
   atransport t;
   static size_t kick_count;
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index d05d928..d054601 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -94,7 +94,7 @@
 }
 
 #if ADB_HOST
-int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol)
+int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol)
 {
     return (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && usb_protocol == ADB_PROTOCOL);
 }
diff --git a/adb/usb_linux.cpp b/adb/usb_linux.cpp
index 500898a..e7f1338 100644
--- a/adb/usb_linux.cpp
+++ b/adb/usb_linux.cpp
@@ -38,6 +38,7 @@
 #include <list>
 #include <mutex>
 #include <string>
+#include <thread>
 
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
@@ -46,6 +47,7 @@
 #include "adb.h"
 #include "transport.h"
 
+using namespace std::chrono_literals;
 using namespace std::literals;
 
 /* usb scan debugging is waaaay too verbose */
@@ -205,9 +207,8 @@
                          interface->bInterfaceProtocol, interface->bNumEndpoints);
 
                     if (interface->bNumEndpoints == 2 &&
-                            is_adb_interface(vid, pid, interface->bInterfaceClass,
-                            interface->bInterfaceSubClass, interface->bInterfaceProtocol))  {
-
+                        is_adb_interface(interface->bInterfaceClass, interface->bInterfaceSubClass,
+                                         interface->bInterfaceProtocol)) {
                         struct stat st;
                         char pathbuf[128];
                         char link[256];
@@ -578,7 +579,7 @@
         // TODO: Use inotify.
         find_usb_device("/dev/bus/usb", register_device);
         kick_disconnected_devices();
-        sleep(1);
+        std::this_thread::sleep_for(1s);
     }
 }
 
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index 0ba6b4b..1cc7f68 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -18,7 +18,6 @@
 
 #include "sysdeps.h"
 
-#include <cutils/properties.h>
 #include <dirent.h>
 #include <errno.h>
 #include <linux/usb/ch9.h>
@@ -32,12 +31,19 @@
 
 #include <algorithm>
 #include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+#include <thread>
 
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 
 #include "adb.h"
 #include "transport.h"
 
+using namespace std::chrono_literals;
+
 #define MAX_PACKET_SIZE_FS	64
 #define MAX_PACKET_SIZE_HS	512
 #define MAX_PACKET_SIZE_SS	1024
@@ -54,12 +60,14 @@
 
 static int dummy_fd = -1;
 
-struct usb_handle
-{
-    adb_cond_t notify;
-    adb_mutex_t lock;
-    bool open_new_connection;
+struct usb_handle {
+    usb_handle() : kicked(false) {
+    }
+
+    std::condition_variable notify;
+    std::mutex lock;
     std::atomic<bool> kicked;
+    bool open_new_connection = true;
 
     int (*write)(usb_handle *h, const void *data, int len);
     int (*read)(usb_handle *h, void *data, int len);
@@ -67,12 +75,12 @@
     void (*close)(usb_handle *h);
 
     // Legacy f_adb
-    int fd;
+    int fd = -1;
 
     // FunctionFS
-    int control;
-    int bulk_out; /* "out" from the host's perspective => source for adbd */
-    int bulk_in;  /* "in" from the host's perspective => sink for adbd */
+    int control = -1;
+    int bulk_out = -1; /* "out" from the host's perspective => source for adbd */
+    int bulk_in = -1;  /* "in" from the host's perspective => sink for adbd */
 };
 
 struct func_desc {
@@ -248,12 +256,12 @@
 
     while (true) {
         // wait until the USB device needs opening
-        adb_mutex_lock(&usb->lock);
+        std::unique_lock<std::mutex> lock(usb->lock);
         while (!usb->open_new_connection) {
-            adb_cond_wait(&usb->notify, &usb->lock);
+            usb->notify.wait(lock);
         }
         usb->open_new_connection = false;
-        adb_mutex_unlock(&usb->lock);
+        lock.unlock();
 
         D("[ usb_thread - opening device ]");
         do {
@@ -264,7 +272,7 @@
                 fd = unix_open("/dev/android", O_RDWR);
             }
             if (fd < 0) {
-                adb_sleep_ms(1000);
+                std::this_thread::sleep_for(1s);
             }
         } while (fd < 0);
         D("[ opening device succeeded ]");
@@ -339,27 +347,20 @@
     h->kicked = false;
     adb_close(h->fd);
     // Notify usb_adb_open_thread to open a new connection.
-    adb_mutex_lock(&h->lock);
+    h->lock.lock();
     h->open_new_connection = true;
-    adb_cond_signal(&h->notify);
-    adb_mutex_unlock(&h->lock);
+    h->lock.unlock();
+    h->notify.notify_one();
 }
 
 static void usb_adb_init()
 {
-    usb_handle* h = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
-    if (h == nullptr) fatal("couldn't allocate usb_handle");
+    usb_handle* h = new usb_handle();
 
     h->write = usb_adb_write;
     h->read = usb_adb_read;
     h->kick = usb_adb_kick;
     h->close = usb_adb_close;
-    h->kicked = false;
-    h->fd = -1;
-
-    h->open_new_connection = true;
-    adb_cond_init(&h->notify, 0);
-    adb_mutex_init(&h->lock, 0);
 
     // Open the file /dev/android_adb_enable to trigger
     // the enabling of the adb USB function in the kernel.
@@ -468,20 +469,20 @@
 
     while (true) {
         // wait until the USB device needs opening
-        adb_mutex_lock(&usb->lock);
+        std::unique_lock<std::mutex> lock(usb->lock);
         while (!usb->open_new_connection) {
-            adb_cond_wait(&usb->notify, &usb->lock);
+            usb->notify.wait(lock);
         }
         usb->open_new_connection = false;
-        adb_mutex_unlock(&usb->lock);
+        lock.unlock();
 
         while (true) {
             if (init_functionfs(usb)) {
                 break;
             }
-            adb_sleep_ms(1000);
+            std::this_thread::sleep_for(1s);
         }
-        property_set("sys.usb.ffs.ready", "1");
+        android::base::SetProperty("sys.usb.ffs.ready", "1");
 
         D("[ usb_thread - registering device ]");
         register_usb_transport(usb, 0, 0, 1);
@@ -557,31 +558,22 @@
     adb_close(h->bulk_out);
     adb_close(h->bulk_in);
     // Notify usb_adb_open_thread to open a new connection.
-    adb_mutex_lock(&h->lock);
+    h->lock.lock();
     h->open_new_connection = true;
-    adb_cond_signal(&h->notify);
-    adb_mutex_unlock(&h->lock);
+    h->lock.unlock();
+    h->notify.notify_one();
 }
 
 static void usb_ffs_init()
 {
     D("[ usb_init - using FunctionFS ]");
 
-    usb_handle* h = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
-    if (h == nullptr) fatal("couldn't allocate usb_handle");
+    usb_handle* h = new usb_handle();
 
     h->write = usb_ffs_write;
     h->read = usb_ffs_read;
     h->kick = usb_ffs_kick;
     h->close = usb_ffs_close;
-    h->kicked = false;
-    h->control = -1;
-    h->bulk_out = -1;
-    h->bulk_out = -1;
-
-    h->open_new_connection = true;
-    adb_cond_init(&h->notify, 0);
-    adb_mutex_init(&h->lock, 0);
 
     D("[ usb_init - starting thread ]");
     if (!adb_thread_create(usb_ffs_open_thread, h)) {
@@ -608,6 +600,7 @@
 {
     return h->read(h, data, len);
 }
+
 int usb_close(usb_handle *h)
 {
     h->close(h);
diff --git a/adb/usb_osx.cpp b/adb/usb_osx.cpp
index ddde454..e541f6e 100644
--- a/adb/usb_osx.cpp
+++ b/adb/usb_osx.cpp
@@ -30,8 +30,10 @@
 #include <stdio.h>
 
 #include <atomic>
+#include <chrono>
 #include <memory>
 #include <mutex>
+#include <thread>
 #include <vector>
 
 #include <android-base/logging.h>
@@ -40,6 +42,8 @@
 #include "adb.h"
 #include "transport.h"
 
+using namespace std::chrono_literals;
+
 struct usb_handle
 {
     UInt8 bulkIn;
@@ -177,6 +181,7 @@
         kr = (*iface)->GetDevice(iface, &usbDevice);
         if (kIOReturnSuccess != kr || !usbDevice) {
             LOG(ERROR) << "Couldn't grab device from interface (" << std::hex << kr << ")";
+            (*iface)->Release(iface);
             continue;
         }
 
@@ -191,6 +196,7 @@
         (void)IOObjectRelease(usbDevice);
         if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
             LOG(ERROR) << "Unable to create a device plug-in (" << std::hex << kr << ")";
+            (*iface)->Release(iface);
             continue;
         }
 
@@ -200,6 +206,7 @@
         (*plugInInterface)->Release(plugInInterface);
         if (result || !dev) {
             LOG(ERROR) << "Couldn't create a device interface (" << std::hex << result << ")";
+            (*iface)->Release(iface);
             continue;
         }
 
@@ -211,6 +218,8 @@
         if (kr == KERN_SUCCESS) {
             devpath = android::base::StringPrintf("usb:%" PRIu32 "X", locationId);
             if (IsKnownDevice(devpath)) {
+                (*dev)->Release(dev);
+                (*iface)->Release(iface);
                 continue;
             }
         }
@@ -340,7 +349,7 @@
 
     //* check to make sure interface class, subclass and protocol match ADB
     //* avoid opening mass storage endpoints
-    if (!is_adb_interface(vendor, product, interfaceClass, interfaceSubClass, interfaceProtocol)) {
+    if (!is_adb_interface(interfaceClass, interfaceSubClass, interfaceProtocol)) {
         goto err_bad_adb_interface;
     }
 
@@ -406,7 +415,7 @@
         }
         // Signal the parent that we are running
         usb_inited_flag = true;
-        adb_sleep_ms(1000);
+        std::this_thread::sleep_for(1s);
     }
     VLOG(USB) << "RunLoopThread done";
 }
@@ -431,7 +440,7 @@
 
         // Wait for initialization to finish
         while (!usb_inited_flag) {
-            adb_sleep_ms(100);
+            std::this_thread::sleep_for(100ms);
         }
 
         initialized = true;
diff --git a/adb/usb_windows.cpp b/adb/usb_windows.cpp
index 8ecca37..640e91e 100644
--- a/adb/usb_windows.cpp
+++ b/adb/usb_windows.cpp
@@ -19,17 +19,23 @@
 #include "sysdeps.h"
 
 #include <winsock2.h>  // winsock.h *must* be included before windows.h.
-#include <adb_api.h>
+#include <windows.h>
+#include <usb100.h>
+#include <winerror.h>
+
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <usb100.h>
-#include <windows.h>
-#include <winerror.h>
+
+#include <mutex>
+#include <thread>
+
+#include <adb_api.h>
 
 #include <android-base/errors.h>
 
 #include "adb.h"
+#include "sysdeps/chrono.h"
 #include "transport.h"
 
 /** Structure usb_handle describes our connection to the usb device via
@@ -73,7 +79,7 @@
 };
 
 /// Locker for the list of opened usb handles
-ADB_MUTEX_DEFINE( usb_lock );
+static std::mutex& usb_lock = *new std::mutex();
 
 /// Checks if there is opened usb handle in handle_list for this device.
 int known_device(const wchar_t* dev_name);
@@ -141,9 +147,8 @@
   int ret = 0;
 
   if (NULL != dev_name) {
-    adb_mutex_lock(&usb_lock);
+    std::lock_guard<std::mutex> lock(usb_lock);
     ret = known_device_locked(dev_name);
-    adb_mutex_unlock(&usb_lock);
   }
 
   return ret;
@@ -153,11 +158,10 @@
   if (NULL == handle)
     return 0;
 
-  adb_mutex_lock(&usb_lock);
+  std::lock_guard<std::mutex> lock(usb_lock);
 
   // Check if device is already in the list
   if (known_device_locked(handle->interface_name)) {
-    adb_mutex_unlock(&usb_lock);
     return 0;
   }
 
@@ -167,8 +171,6 @@
   handle->prev->next = handle;
   handle->next->prev = handle;
 
-  adb_mutex_unlock(&usb_lock);
-
   return 1;
 }
 
@@ -176,9 +178,9 @@
   adb_thread_setname("Device Poll");
   D("Created device thread");
 
-  while(1) {
+  while (true) {
     find_devices();
-    adb_sleep_ms(1000);
+    std::this_thread::sleep_for(1s);
   }
 }
 
@@ -493,11 +495,8 @@
 void usb_kick(usb_handle* handle) {
   D("usb_kick");
   if (NULL != handle) {
-    adb_mutex_lock(&usb_lock);
-
+    std::lock_guard<std::mutex> lock(usb_lock);
     usb_kick_locked(handle);
-
-    adb_mutex_unlock(&usb_lock);
   } else {
     errno = EINVAL;
   }
@@ -508,17 +507,17 @@
 
   if (NULL != handle) {
     // Remove handle from the list
-    adb_mutex_lock(&usb_lock);
+    {
+      std::lock_guard<std::mutex> lock(usb_lock);
 
-    if ((handle->next != handle) && (handle->prev != handle)) {
-      handle->next->prev = handle->prev;
-      handle->prev->next = handle->next;
-      handle->prev = handle;
-      handle->next = handle;
+      if ((handle->next != handle) && (handle->prev != handle)) {
+        handle->next->prev = handle->prev;
+        handle->prev->next = handle->next;
+        handle->prev = handle;
+        handle->next = handle;
+      }
     }
 
-    adb_mutex_unlock(&usb_lock);
-
     // Cleanup handle
     usb_cleanup_handle(handle);
     free(handle);
@@ -556,10 +555,9 @@
     return 0;
   }
 
-  if (is_adb_interface(device_desc.idVendor, device_desc.idProduct,
-      interf_desc.bInterfaceClass, interf_desc.bInterfaceSubClass, interf_desc.bInterfaceProtocol)) {
-
-    if(interf_desc.bInterfaceProtocol == 0x01) {
+  if (is_adb_interface(interf_desc.bInterfaceClass, interf_desc.bInterfaceSubClass,
+                       interf_desc.bInterfaceProtocol)) {
+    if (interf_desc.bInterfaceProtocol == 0x01) {
       AdbEndpointInformation endpoint_info;
       // assuming zero is a valid bulk endpoint ID
       if (AdbGetEndpointInformation(handle->adb_interface, 0, &endpoint_info)) {
@@ -651,9 +649,8 @@
 static void kick_devices() {
   // Need to acquire lock to safely walk the list which might be modified
   // by another thread.
-  adb_mutex_lock(&usb_lock);
+  std::lock_guard<std::mutex> lock(usb_lock);
   for (usb_handle* usb = handle_list.next; usb != &handle_list; usb = usb->next) {
     usb_kick_locked(usb);
   }
-  adb_mutex_unlock(&usb_lock);
 }
diff --git a/adf/Android.bp b/adf/Android.bp
new file mode 100644
index 0000000..b44c296
--- /dev/null
+++ b/adf/Android.bp
@@ -0,0 +1 @@
+subdirs = ["*"]
diff --git a/adf/libadf/Android.bp b/adf/libadf/Android.bp
new file mode 100644
index 0000000..2b5461e
--- /dev/null
+++ b/adf/libadf/Android.bp
@@ -0,0 +1,21 @@
+// Copyright (C) 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_static {
+    name: "libadf",
+    srcs: ["adf.c"],
+    cflags: ["-Werror"],
+    local_include_dirs: ["include"],
+    export_include_dirs: ["include"],
+}
diff --git a/adf/libadf/tests/Android.bp b/adf/libadf/tests/Android.bp
new file mode 100644
index 0000000..7b33300
--- /dev/null
+++ b/adf/libadf/tests/Android.bp
@@ -0,0 +1,22 @@
+//
+// Copyright (C) 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "adf-unit-tests",
+    srcs: ["adf_test.cpp"],
+    static_libs: ["libadf"],
+    cflags: ["-Werror"],
+}
diff --git a/adf/libadf/tests/Android.mk b/adf/libadf/tests/Android.mk
deleted file mode 100644
index 68e5817..0000000
--- a/adf/libadf/tests/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-#
-# Copyright (C) 2013 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.
-#
-LOCAL_PATH := $(my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := adf_test.cpp
-LOCAL_MODULE := adf-unit-tests
-LOCAL_STATIC_LIBRARIES := libadf
-LOCAL_CFLAGS += -Werror
-include $(BUILD_NATIVE_TEST)
diff --git a/adf/libadfhwc/Android.bp b/adf/libadfhwc/Android.bp
new file mode 100644
index 0000000..57a8d76
--- /dev/null
+++ b/adf/libadfhwc/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_static {
+    name: "libadfhwc",
+    srcs: ["adfhwc.cpp"],
+    static_libs: [
+        "libadf",
+        "liblog",
+        "libutils",
+    ],
+    cflags: [
+        "-DLOG_TAG=\"adfhwc\"",
+        "-Werror",
+    ],
+    local_include_dirs: ["include"],
+    export_include_dirs: ["include"],
+}
diff --git a/adf/libadfhwc/adfhwc.cpp b/adf/libadfhwc/adfhwc.cpp
index 21f245e..7d5b555 100644
--- a/adf/libadfhwc/adfhwc.cpp
+++ b/adf/libadfhwc/adfhwc.cpp
@@ -20,12 +20,12 @@
 #include <pthread.h>
 #include <sys/resource.h>
 
+#include <android/log.h>
+#include <utils/Vector.h>
+
 #include <adf/adf.h>
 #include <adfhwc/adfhwc.h>
 
-#include <cutils/log.h>
-#include <utils/Vector.h>
-
 struct adf_hwc_helper {
     adf_hwc_event_callbacks const *event_cb;
     void *event_cb_data;
diff --git a/base/Android.bp b/base/Android.bp
new file mode 100644
index 0000000..e6ad15b
--- /dev/null
+++ b/base/Android.bp
@@ -0,0 +1,105 @@
+//
+// 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.
+//
+
+libbase_cppflags = [
+    "-Wall",
+    "-Wextra",
+    "-Werror",
+]
+
+cc_library {
+    name: "libbase",
+    clang: true,
+    host_supported: true,
+    srcs: [
+        "file.cpp",
+        "logging.cpp",
+        "parsenetaddress.cpp",
+        "quick_exit.cpp",
+        "stringprintf.cpp",
+        "strings.cpp",
+        "test_utils.cpp",
+    ],
+    local_include_dirs: ["include"],
+    cppflags: libbase_cppflags,
+    export_include_dirs: ["include"],
+    shared_libs: ["liblog"],
+    target: {
+        android: {
+            srcs: [
+                "errors_unix.cpp",
+                "properties.cpp",
+            ],
+            cppflags: ["-Wexit-time-destructors"],
+        },
+        darwin: {
+            srcs: ["errors_unix.cpp"],
+            cppflags: ["-Wexit-time-destructors"],
+        },
+        linux: {
+            srcs: ["errors_unix.cpp"],
+            cppflags: ["-Wexit-time-destructors"],
+        },
+        windows: {
+            srcs: [
+                "errors_windows.cpp",
+                "utf8.cpp",
+            ],
+            enabled: true,
+        },
+    },
+}
+
+// Tests
+// ------------------------------------------------------------------------------
+cc_test {
+    name: "libbase_test",
+    host_supported: true,
+    clang: true,
+    srcs: [
+        "errors_test.cpp",
+        "file_test.cpp",
+        "logging_test.cpp",
+        "parsedouble_test.cpp",
+        "parseint_test.cpp",
+        "parsenetaddress_test.cpp",
+        "quick_exit_test.cpp",
+        "stringprintf_test.cpp",
+        "strings_test.cpp",
+        "test_main.cpp",
+    ],
+    target: {
+        android: {
+            srcs: ["properties_test.cpp"],
+        },
+        windows: {
+            srcs: ["utf8_test.cpp"],
+            enabled: true,
+        },
+    },
+    local_include_dirs: ["."],
+    cppflags: libbase_cppflags,
+    shared_libs: ["libbase"],
+    compile_multilib: "both",
+    multilib: {
+        lib32: {
+            suffix: "32",
+        },
+        lib64: {
+            suffix: "64",
+        },
+    },
+}
diff --git a/base/Android.mk b/base/Android.mk
deleted file mode 100644
index 1693e74..0000000
--- a/base/Android.mk
+++ /dev/null
@@ -1,140 +0,0 @@
-#
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-libbase_src_files := \
-    file.cpp \
-    logging.cpp \
-    parsenetaddress.cpp \
-    stringprintf.cpp \
-    strings.cpp \
-    test_utils.cpp \
-
-libbase_linux_src_files := \
-    errors_unix.cpp \
-
-libbase_darwin_src_files := \
-    errors_unix.cpp \
-
-libbase_windows_src_files := \
-    errors_windows.cpp \
-    utf8.cpp \
-
-libbase_test_src_files := \
-    errors_test.cpp \
-    file_test.cpp \
-    logging_test.cpp \
-    parseint_test.cpp \
-    parsenetaddress_test.cpp \
-    stringprintf_test.cpp \
-    strings_test.cpp \
-    test_main.cpp \
-
-libbase_test_windows_src_files := \
-    utf8_test.cpp \
-
-libbase_cppflags := \
-    -Wall \
-    -Wextra \
-    -Werror \
-
-libbase_linux_cppflags := \
-    -Wexit-time-destructors \
-
-libbase_darwin_cppflags := \
-    -Wexit-time-destructors \
-
-# Device
-# ------------------------------------------------------------------------------
-include $(CLEAR_VARS)
-LOCAL_MODULE := libbase
-LOCAL_CLANG := true
-LOCAL_SRC_FILES := $(libbase_src_files) $(libbase_linux_src_files)
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CPPFLAGS := $(libbase_cppflags) $(libbase_linux_cppflags)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_MULTILIB := both
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libbase
-LOCAL_CLANG := true
-LOCAL_WHOLE_STATIC_LIBRARIES := libbase
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_MULTILIB := both
-include $(BUILD_SHARED_LIBRARY)
-
-# Host
-# ------------------------------------------------------------------------------
-include $(CLEAR_VARS)
-LOCAL_MODULE := libbase
-LOCAL_SRC_FILES := $(libbase_src_files)
-LOCAL_SRC_FILES_darwin := $(libbase_darwin_src_files)
-LOCAL_SRC_FILES_linux := $(libbase_linux_src_files)
-LOCAL_SRC_FILES_windows := $(libbase_windows_src_files)
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CPPFLAGS := $(libbase_cppflags)
-LOCAL_CPPFLAGS_darwin := $(libbase_darwin_cppflags)
-LOCAL_CPPFLAGS_linux := $(libbase_linux_cppflags)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_MULTILIB := both
-LOCAL_MODULE_HOST_OS := darwin linux windows
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libbase
-LOCAL_WHOLE_STATIC_LIBRARIES := libbase
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_MULTILIB := both
-LOCAL_MODULE_HOST_OS := darwin linux windows
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-# Tests
-# ------------------------------------------------------------------------------
-include $(CLEAR_VARS)
-LOCAL_MODULE := libbase_test
-LOCAL_CLANG := true
-LOCAL_SRC_FILES := $(libbase_test_src_files)
-LOCAL_SRC_FILES_darwin := $(libbase_test_darwin_src_files)
-LOCAL_SRC_FILES_linux := $(libbase_test_linux_src_files)
-LOCAL_SRC_FILES_windows := $(libbase_test_windows_src_files)
-LOCAL_C_INCLUDES := $(LOCAL_PATH)
-LOCAL_CPPFLAGS := $(libbase_cppflags)
-LOCAL_SHARED_LIBRARIES := libbase
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libbase_test
-LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_SRC_FILES := $(libbase_test_src_files)
-LOCAL_SRC_FILES_darwin := $(libbase_test_darwin_src_files)
-LOCAL_SRC_FILES_linux := $(libbase_test_linux_src_files)
-LOCAL_SRC_FILES_windows := $(libbase_test_windows_src_files)
-LOCAL_C_INCLUDES := $(LOCAL_PATH)
-LOCAL_CPPFLAGS := $(libbase_cppflags)
-LOCAL_SHARED_LIBRARIES := libbase
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-include $(BUILD_HOST_NATIVE_TEST)
diff --git a/base/file.cpp b/base/file.cpp
index da1adba..6284b04 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -20,15 +20,24 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <unistd.h>
 
+#include <memory>
 #include <string>
+#include <vector>
 
 #include "android-base/macros.h"  // For TEMP_FAILURE_RETRY on Darwin.
+#include "android-base/logging.h"
 #include "android-base/utf8.h"
-#define LOG_TAG "base.file"
-#include "cutils/log.h"
 #include "utils/Compat.h"
 
+#if defined(__APPLE__)
+#include <mach-o/dyld.h>
+#endif
+#if defined(_WIN32)
+#include <windows.h>
+#endif
+
 namespace android {
 namespace base {
 
@@ -46,10 +55,11 @@
   return (n == 0) ? true : false;
 }
 
-bool ReadFileToString(const std::string& path, std::string* content) {
+bool ReadFileToString(const std::string& path, std::string* content, bool follow_symlinks) {
   content->clear();
 
-  int fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_BINARY));
+  int flags = O_RDONLY | O_CLOEXEC | O_BINARY | (follow_symlinks ? 0 : O_NOFOLLOW);
+  int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags));
   if (fd == -1) {
     return false;
   }
@@ -82,26 +92,28 @@
 
 #if !defined(_WIN32)
 bool WriteStringToFile(const std::string& content, const std::string& path,
-                       mode_t mode, uid_t owner, gid_t group) {
-  int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
+                       mode_t mode, uid_t owner, gid_t group,
+                       bool follow_symlinks) {
+  int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY |
+              (follow_symlinks ? 0 : O_NOFOLLOW);
   int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
   if (fd == -1) {
-    ALOGE("android::WriteStringToFile open failed: %s", strerror(errno));
+    PLOG(ERROR) << "android::WriteStringToFile open failed";
     return false;
   }
 
   // We do an explicit fchmod here because we assume that the caller really
   // meant what they said and doesn't want the umask-influenced mode.
   if (fchmod(fd, mode) == -1) {
-    ALOGE("android::WriteStringToFile fchmod failed: %s", strerror(errno));
+    PLOG(ERROR) << "android::WriteStringToFile fchmod failed";
     return CleanUpAfterFailedWrite(path);
   }
   if (fchown(fd, owner, group) == -1) {
-    ALOGE("android::WriteStringToFile fchown failed: %s", strerror(errno));
+    PLOG(ERROR) << "android::WriteStringToFile fchown failed";
     return CleanUpAfterFailedWrite(path);
   }
   if (!WriteStringToFd(content, fd)) {
-    ALOGE("android::WriteStringToFile write failed: %s", strerror(errno));
+    PLOG(ERROR) << "android::WriteStringToFile write failed";
     return CleanUpAfterFailedWrite(path);
   }
   close(fd);
@@ -109,8 +121,10 @@
 }
 #endif
 
-bool WriteStringToFile(const std::string& content, const std::string& path) {
-  int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
+bool WriteStringToFile(const std::string& content, const std::string& path,
+                       bool follow_symlinks) {
+  int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY |
+              (follow_symlinks ? 0 : O_NOFOLLOW);
   int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, DEFFILEMODE));
   if (fd == -1) {
     return false;
@@ -172,5 +186,55 @@
   return true;
 }
 
+#if !defined(_WIN32)
+bool Readlink(const std::string& path, std::string* result) {
+  result->clear();
+
+  // Most Linux file systems (ext2 and ext4, say) limit symbolic links to
+  // 4095 bytes. Since we'll copy out into the string anyway, it doesn't
+  // waste memory to just start there. We add 1 so that we can recognize
+  // whether it actually fit (rather than being truncated to 4095).
+  std::vector<char> buf(4095 + 1);
+  while (true) {
+    ssize_t size = readlink(path.c_str(), &buf[0], buf.size());
+    // Unrecoverable error?
+    if (size == -1) return false;
+    // It fit! (If size == buf.size(), it may have been truncated.)
+    if (static_cast<size_t>(size) < buf.size()) {
+      result->assign(&buf[0], size);
+      return true;
+    }
+    // Double our buffer and try again.
+    buf.resize(buf.size() * 2);
+  }
+}
+#endif
+
+std::string GetExecutablePath() {
+#if defined(__linux__)
+  std::string path;
+  android::base::Readlink("/proc/self/exe", &path);
+  return path;
+#elif defined(__APPLE__)
+  char path[PATH_MAX + 1];
+  uint32_t path_len = sizeof(path);
+  int rc = _NSGetExecutablePath(path, &path_len);
+  if (rc < 0) {
+    std::unique_ptr<char> path_buf(new char[path_len]);
+    _NSGetExecutablePath(path_buf.get(), &path_len);
+    return path_buf.get();
+  }
+  return path;
+#elif defined(_WIN32)
+  char path[PATH_MAX + 1];
+  DWORD result = GetModuleFileName(NULL, path, sizeof(path) - 1);
+  if (result == 0 || result == sizeof(path) - 1) return "";
+  path[PATH_MAX - 1] = 0;
+  return path;
+#else
+#error unknown OS
+#endif
+}
+
 }  // namespace base
 }  // namespace android
diff --git a/base/file_test.cpp b/base/file_test.cpp
index 17755bf..f741d89 100644
--- a/base/file_test.cpp
+++ b/base/file_test.cpp
@@ -45,6 +45,24 @@
   EXPECT_EQ("abc", s);
 }
 
+// symlinks require elevated privileges on Windows.
+#if !defined(_WIN32)
+TEST(file, ReadFileToString_WriteStringToFile_symlink) {
+  TemporaryFile target, link;
+  ASSERT_EQ(0, unlink(link.path));
+  ASSERT_EQ(0, symlink(target.path, link.path));
+  ASSERT_FALSE(android::base::WriteStringToFile("foo", link.path, false));
+  ASSERT_EQ(ELOOP, errno);
+  ASSERT_TRUE(android::base::WriteStringToFile("foo", link.path, true));
+
+  std::string s;
+  ASSERT_FALSE(android::base::ReadFileToString(link.path, &s));
+  ASSERT_EQ(ELOOP, errno);
+  ASSERT_TRUE(android::base::ReadFileToString(link.path, &s, true));
+  ASSERT_EQ("foo", s);
+}
+#endif
+
 // WriteStringToFile2 is explicitly for setting Unix permissions, which make no
 // sense on Windows.
 #if !defined(_WIN32)
@@ -110,3 +128,33 @@
   ASSERT_FALSE(android::base::RemoveFileIfExists(td.path, &err));
   ASSERT_EQ("is not a regular or symbol link file", err);
 }
+
+TEST(file, Readlink) {
+#if !defined(_WIN32)
+  // Linux doesn't allow empty symbolic links.
+  std::string min("x");
+  // ext2 and ext4 both have PAGE_SIZE limits.
+  std::string max(static_cast<size_t>(4096 - 1), 'x');
+
+  TemporaryDir td;
+  std::string min_path{std::string(td.path) + "/" + "min"};
+  std::string max_path{std::string(td.path) + "/" + "max"};
+
+  ASSERT_EQ(0, symlink(min.c_str(), min_path.c_str()));
+  ASSERT_EQ(0, symlink(max.c_str(), max_path.c_str()));
+
+  std::string result;
+
+  result = "wrong";
+  ASSERT_TRUE(android::base::Readlink(min_path, &result));
+  ASSERT_EQ(min, result);
+
+  result = "wrong";
+  ASSERT_TRUE(android::base::Readlink(max_path, &result));
+  ASSERT_EQ(max, result);
+#endif
+}
+
+TEST(file, GetExecutablePath) {
+  ASSERT_NE("", android::base::GetExecutablePath());
+}
diff --git a/base/include/android-base/file.h b/base/include/android-base/file.h
index aa18ea7..cd64262 100644
--- a/base/include/android-base/file.h
+++ b/base/include/android-base/file.h
@@ -28,14 +28,17 @@
 namespace base {
 
 bool ReadFdToString(int fd, std::string* content);
-bool ReadFileToString(const std::string& path, std::string* content);
+bool ReadFileToString(const std::string& path, std::string* content,
+                      bool follow_symlinks = false);
 
-bool WriteStringToFile(const std::string& content, const std::string& path);
+bool WriteStringToFile(const std::string& content, const std::string& path,
+                       bool follow_symlinks = false);
 bool WriteStringToFd(const std::string& content, int fd);
 
 #if !defined(_WIN32)
 bool WriteStringToFile(const std::string& content, const std::string& path,
-                       mode_t mode, uid_t owner, gid_t group);
+                       mode_t mode, uid_t owner, gid_t group,
+                       bool follow_symlinks = false);
 #endif
 
 bool ReadFully(int fd, void* data, size_t byte_count);
@@ -43,6 +46,12 @@
 
 bool RemoveFileIfExists(const std::string& path, std::string* err = nullptr);
 
+#if !defined(_WIN32)
+bool Readlink(const std::string& path, std::string* result);
+#endif
+
+std::string GetExecutablePath();
+
 }  // namespace base
 }  // namespace android
 
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index d3f9d0c..50677a3 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -41,6 +41,7 @@
   INFO,
   WARNING,
   ERROR,
+  FATAL_WITHOUT_ABORT,
   FATAL,
 };
 
@@ -50,11 +51,14 @@
   SYSTEM,
 };
 
-typedef std::function<void(LogId, LogSeverity, const char*, const char*,
-                           unsigned int, const char*)> LogFunction;
+using LogFunction = std::function<void(LogId, LogSeverity, const char*, const char*,
+                                       unsigned int, const char*)>;
+using AbortFunction = std::function<void(const char*)>;
 
-extern void StderrLogger(LogId, LogSeverity, const char*, const char*,
-                         unsigned int, const char*);
+void KernelLogger(LogId, LogSeverity, const char*, const char*, unsigned int, const char*);
+void StderrLogger(LogId, LogSeverity, const char*, const char*, unsigned int, const char*);
+
+void DefaultAborter(const char* abort_message);
 
 #ifdef __ANDROID__
 // We expose this even though it is the default because a user that wants to
@@ -79,17 +83,21 @@
 // The tag (or '*' for the global level) comes first, followed by a colon and a
 // letter indicating the minimum priority level we're expected to log.  This can
 // be used to reveal or conceal logs with specific tags.
-extern void InitLogging(char* argv[], LogFunction&& logger);
-
-// Configures logging using the default logger (logd for the device, stderr for
-// the host).
-extern void InitLogging(char* argv[]);
+#ifdef __ANDROID__
+#define INIT_LOGGING_DEFAULT_LOGGER LogdLogger()
+#else
+#define INIT_LOGGING_DEFAULT_LOGGER StderrLogger
+#endif
+void InitLogging(char* argv[],
+                 LogFunction&& logger = INIT_LOGGING_DEFAULT_LOGGER,
+                 AbortFunction&& aborter = DefaultAborter);
+#undef INIT_LOGGING_DEFAULT_LOGGER
 
 // Replace the current logger.
-extern void SetLogger(LogFunction&& logger);
+void SetLogger(LogFunction&& logger);
 
-// Get the minimum severity level for logging.
-extern LogSeverity GetMinimumLogSeverity();
+// Replace the current aborter.
+void SetAborter(AbortFunction&& aborter);
 
 class ErrnoRestorer {
  public:
@@ -112,6 +120,39 @@
   DISALLOW_COPY_AND_ASSIGN(ErrnoRestorer);
 };
 
+// A helper macro that produces an expression that accepts both a qualified name and an
+// unqualified name for a LogSeverity, and returns a LogSeverity value.
+// Note: DO NOT USE DIRECTLY. This is an implementation detail.
+#define SEVERITY_LAMBDA(severity) ([&]() {    \
+  using ::android::base::VERBOSE;             \
+  using ::android::base::DEBUG;               \
+  using ::android::base::INFO;                \
+  using ::android::base::WARNING;             \
+  using ::android::base::ERROR;               \
+  using ::android::base::FATAL_WITHOUT_ABORT; \
+  using ::android::base::FATAL;               \
+  return (severity); }())
+
+// Defines whether the given severity will be logged or silently swallowed.
+#define WOULD_LOG(severity) \
+  UNLIKELY((SEVERITY_LAMBDA(severity)) >= ::android::base::GetMinimumLogSeverity())
+
+// Get an ostream that can be used for logging at the given severity and to the default
+// destination.
+//
+// Notes:
+// 1) This will not check whether the severity is high enough. One should use WOULD_LOG to filter
+//    usage manually.
+// 2) This does not save and restore errno.
+#define LOG_STREAM(severity) LOG_STREAM_TO(DEFAULT, severity)
+
+// Get an ostream that can be used for logging at the given severity and to the
+// given destination. The same notes as for LOG_STREAM apply.
+#define LOG_STREAM_TO(dest, severity)                                   \
+  ::android::base::LogMessage(__FILE__, __LINE__,                       \
+                              ::android::base::dest,                    \
+                              SEVERITY_LAMBDA(severity), -1).stream()
+
 // Logs a message to logcat on Android otherwise to stderr. If the severity is
 // FATAL it also causes an abort. For example:
 //
@@ -124,29 +165,36 @@
 // else statement after LOG() macro, it won't bind to the if statement in the macro.
 // do-while(0) statement doesn't work here. Because we need to support << operator
 // following the macro, like "LOG(DEBUG) << xxx;".
-#define LOG_TO(dest, severity)                                                        \
-  UNLIKELY(::android::base::severity >= ::android::base::GetMinimumLogSeverity()) &&  \
-    ::android::base::ErrnoRestorer() &&                                               \
-      ::android::base::LogMessage(__FILE__, __LINE__,                                 \
-          ::android::base::dest,                                                      \
-          ::android::base::severity, -1).stream()
+
+#define LOG_TO(dest, severity) \
+  WOULD_LOG(severity) &&                   \
+    ::android::base::ErrnoRestorer() &&    \
+      LOG_STREAM_TO(dest, severity)
 
 // A variant of LOG that also logs the current errno value. To be used when
 // library calls fail.
 #define PLOG(severity) PLOG_TO(DEFAULT, severity)
 
 // Behaves like PLOG, but logs to the specified log ID.
-#define PLOG_TO(dest, severity)                                                      \
-  UNLIKELY(::android::base::severity >= ::android::base::GetMinimumLogSeverity()) && \
-    ::android::base::ErrnoRestorer() &&                                              \
-      ::android::base::LogMessage(__FILE__, __LINE__,                                \
-          ::android::base::dest,                                                     \
-          ::android::base::severity, errno).stream()
+#define PLOG_TO(dest, severity)                         \
+  WOULD_LOG(SEVERITY_LAMBDA(severity)) &&               \
+    ::android::base::ErrnoRestorer() &&                 \
+      ::android::base::LogMessage(__FILE__, __LINE__,   \
+          ::android::base::dest,                        \
+          SEVERITY_LAMBDA(severity), errno).stream()
 
 // Marker that code is yet to be implemented.
 #define UNIMPLEMENTED(level) \
   LOG(level) << __PRETTY_FUNCTION__ << " unimplemented "
 
+#ifdef __clang_analyzer__
+// ClangL static analyzer does not see the conditional statement inside
+// LogMessage's destructor that will abort on FATAL severity.
+#define ABORT_AFTER_LOG_FATAL for (;;abort())
+#else
+#define ABORT_AFTER_LOG_FATAL
+#endif
+
 // Check whether condition x holds and LOG(FATAL) if not. The value of the
 // expression x is only evaluated once. Extra logging can be appended using <<
 // after. For example:
@@ -155,6 +203,7 @@
 //       "Check failed: false == true".
 #define CHECK(x)                                                              \
   LIKELY((x)) ||                                                              \
+    ABORT_AFTER_LOG_FATAL                                                     \
     ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
                                 ::android::base::FATAL, -1).stream()          \
         << "Check failed: " #x << " "
@@ -164,6 +213,7 @@
   for (auto _values = ::android::base::MakeEagerEvaluator(LHS, RHS);        \
        UNLIKELY(!(_values.lhs OP _values.rhs));                             \
        /* empty */)                                                         \
+  ABORT_AFTER_LOG_FATAL                                                     \
   ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
                               ::android::base::FATAL, -1).stream()          \
       << "Check failed: " << #LHS << " " << #OP << " " << #RHS              \
@@ -183,13 +233,13 @@
 #define CHECK_GT(x, y) CHECK_OP(x, y, > )
 
 // Helper for CHECK_STRxx(s1,s2) macros.
-#define CHECK_STROP(s1, s2, sense)                                         \
-  if (LIKELY((strcmp(s1, s2) == 0) == sense))                              \
-    ;                                                                      \
-  else                                                                     \
-    LOG(FATAL) << "Check failed: "                                         \
-               << "\"" << s1 << "\""                                       \
-               << (sense ? " == " : " != ") << "\"" << s2 << "\""
+#define CHECK_STROP(s1, s2, sense)                                             \
+  while (UNLIKELY((strcmp(s1, s2) == 0) != (sense)))                           \
+    ABORT_AFTER_LOG_FATAL                                                      \
+    ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT,  \
+                                ::android::base::FATAL, -1).stream()           \
+        << "Check failed: " << "\"" << (s1) << "\""                            \
+        << ((sense) ? " == " : " != ") << "\"" << (s2) << "\""
 
 // Check for string (const char*) equality between s1 and s2, LOG(FATAL) if not.
 #define CHECK_STREQ(s1, s2) CHECK_STROP(s1, s2, true)
@@ -201,7 +251,8 @@
     int rc = call args;                                                \
     if (rc != 0) {                                                     \
       errno = rc;                                                      \
-      PLOG(FATAL) << #call << " failed for " << what; \
+      ABORT_AFTER_LOG_FATAL                                            \
+      PLOG(FATAL) << #call << " failed for " << (what);                \
     }                                                                  \
   } while (false)
 
@@ -256,7 +307,7 @@
 // MakeEagerEvaluator to infer the types of LHS and RHS.
 template <typename LHS, typename RHS>
 struct EagerEvaluator {
-  EagerEvaluator(LHS l, RHS r) : lhs(l), rhs(r) {
+  constexpr EagerEvaluator(LHS l, RHS r) : lhs(l), rhs(r) {
   }
   LHS lhs;
   RHS rhs;
@@ -264,7 +315,7 @@
 
 // Helper function for CHECK_xx.
 template <typename LHS, typename RHS>
-static inline EagerEvaluator<LHS, RHS> MakeEagerEvaluator(LHS lhs, RHS rhs) {
+constexpr EagerEvaluator<LHS, RHS> MakeEagerEvaluator(LHS lhs, RHS rhs) {
   return EagerEvaluator<LHS, RHS>(lhs, rhs);
 }
 
@@ -322,6 +373,12 @@
   DISALLOW_COPY_AND_ASSIGN(LogMessage);
 };
 
+// Get the minimum severity level for logging.
+LogSeverity GetMinimumLogSeverity();
+
+// Set the minimum severity level for logging, returning the old severity.
+LogSeverity SetMinimumLogSeverity(LogSeverity new_severity);
+
 // Allows to temporarily change the minimum severity level for logging.
 class ScopedLogSeverity {
  public:
diff --git a/base/include/android-base/macros.h b/base/include/android-base/macros.h
index 913a9a0..88bbe8a 100644
--- a/base/include/android-base/macros.h
+++ b/base/include/android-base/macros.h
@@ -41,18 +41,9 @@
 // Note, that most uses of DISALLOW_ASSIGN and DISALLOW_COPY are broken
 // semantically, one should either use disallow both or neither. Try to
 // avoid these in new code.
-//
-// When building with C++11 toolchains, just use the language support
-// for explicitly deleted methods.
-#if __cplusplus >= 201103L
 #define DISALLOW_COPY_AND_ASSIGN(TypeName) \
   TypeName(const TypeName&) = delete;      \
   void operator=(const TypeName&) = delete
-#else
-#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
-  TypeName(const TypeName&);               \
-  void operator=(const TypeName&)
-#endif
 
 // A macro to disallow all the implicit constructors, namely the
 // default constructor, copy constructor and operator= functions.
@@ -61,7 +52,7 @@
 // that wants to prevent anyone from instantiating it. This is
 // especially useful for classes containing only static methods.
 #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
-  TypeName();                                    \
+  TypeName() = delete;                           \
   DISALLOW_COPY_AND_ASSIGN(TypeName)
 
 // The arraysize(arr) macro returns the # of elements in an array arr.
@@ -123,8 +114,11 @@
   ((sizeof(a) / sizeof(*(a))) / \
     static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
 
-#define LIKELY(x) __builtin_expect((x), true)
-#define UNLIKELY(x) __builtin_expect((x), false)
+// Changing this definition will cause you a lot of pain.  A majority of
+// vendor code defines LIKELY and UNLIKELY this way, and includes
+// this header through an indirect path.
+#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
+#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
 
 #define WARN_UNUSED __attribute__((warn_unused_result))
 
@@ -162,10 +156,10 @@
 //  only if there are no statements on the execution path between it and the
 //  next switch label.
 //
-//  When compiled with clang in C++11 mode, the FALLTHROUGH_INTENDED macro is
-//  expanded to [[clang::fallthrough]] attribute, which is analysed when
-//  performing switch labels fall-through diagnostic ('-Wimplicit-fallthrough').
-//  See clang documentation on language extensions for details:
+//  When compiled with clang, the FALLTHROUGH_INTENDED macro is expanded to
+//  [[clang::fallthrough]] attribute, which is analysed when performing switch
+//  labels fall-through diagnostic ('-Wimplicit-fallthrough'). See clang
+//  documentation on language extensions for details:
 //  http://clang.llvm.org/docs/LanguageExtensions.html#clang__fallthrough
 //
 //  When used with unsupported compilers, the FALLTHROUGH_INTENDED macro has no
@@ -173,7 +167,7 @@
 //
 //  In either case this macro has no effect on runtime behavior and performance
 //  of code.
-#if defined(__clang__) && __cplusplus >= 201103L && defined(__has_warning)
+#if defined(__clang__) && defined(__has_warning)
 #if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
 #define FALLTHROUGH_INTENDED [[clang::fallthrough]]  // NOLINT
 #endif
diff --git a/base/include/android-base/parsedouble.h b/base/include/android-base/parsedouble.h
new file mode 100644
index 0000000..daa6902
--- /dev/null
+++ b/base/include/android-base/parsedouble.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_BASE_PARSEDOUBLE_H
+#define ANDROID_BASE_PARSEDOUBLE_H
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <limits>
+
+namespace android {
+namespace base {
+
+// Parse double value in the string 's' and sets 'out' to that value.
+// Optionally allows the caller to define a 'min' and 'max' beyond which
+// otherwise valid values will be rejected. Returns boolean success.
+static inline bool ParseDouble(const char* s, double* out,
+                               double min = std::numeric_limits<double>::lowest(),
+                               double max = std::numeric_limits<double>::max()) {
+  errno = 0;
+  char* end;
+  double result = strtod(s, &end);
+  if (errno != 0 || s == end || *end != '\0') {
+    return false;
+  }
+  if (result < min || max < result) {
+    return false;
+  }
+  *out = result;
+  return true;
+}
+
+}  // namespace base
+}  // namespace android
+
+#endif  // ANDROID_BASE_PARSEDOUBLE_H
diff --git a/base/include/android-base/parseint.h b/base/include/android-base/parseint.h
index ed75e2d..2c8570e 100644
--- a/base/include/android-base/parseint.h
+++ b/base/include/android-base/parseint.h
@@ -21,17 +21,19 @@
 #include <stdlib.h>
 
 #include <limits>
+#include <string>
 
 namespace android {
 namespace base {
 
 // Parses the unsigned decimal integer in the string 's' and sets 'out' to
 // that value. Optionally allows the caller to define a 'max' beyond which
-// otherwise valid values will be rejected. Returns boolean success.
+// otherwise valid values will be rejected. Returns boolean success; 'out'
+// is untouched if parsing fails.
 template <typename T>
 bool ParseUint(const char* s, T* out,
                T max = std::numeric_limits<T>::max()) {
-  int base = (s[0] == '0' && s[1] == 'x') ? 16 : 10;
+  int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
   errno = 0;
   char* end;
   unsigned long long int result = strtoull(s, &end, base);
@@ -45,15 +47,22 @@
   return true;
 }
 
+// TODO: string_view
+template <typename T>
+bool ParseUint(const std::string& s, T* out,
+               T max = std::numeric_limits<T>::max()) {
+  return ParseUint(s.c_str(), out, max);
+}
+
 // Parses the signed decimal integer in the string 's' and sets 'out' to
 // that value. Optionally allows the caller to define a 'min' and 'max
 // beyond which otherwise valid values will be rejected. Returns boolean
-// success.
+// success; 'out' is untouched if parsing fails.
 template <typename T>
 bool ParseInt(const char* s, T* out,
               T min = std::numeric_limits<T>::min(),
               T max = std::numeric_limits<T>::max()) {
-  int base = (s[0] == '0' && s[1] == 'x') ? 16 : 10;
+  int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
   errno = 0;
   char* end;
   long long int result = strtoll(s, &end, base);
@@ -67,6 +76,14 @@
   return true;
 }
 
+// TODO: string_view
+template <typename T>
+bool ParseInt(const std::string& s, T* out,
+              T min = std::numeric_limits<T>::min(),
+              T max = std::numeric_limits<T>::max()) {
+  return ParseInt(s.c_str(), out, min, max);
+}
+
 }  // namespace base
 }  // namespace android
 
diff --git a/base/include/android-base/properties.h b/base/include/android-base/properties.h
new file mode 100644
index 0000000..95d1b6a
--- /dev/null
+++ b/base/include/android-base/properties.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_BASE_PROPERTIES_H
+#define ANDROID_BASE_PROPERTIES_H
+
+#include <sys/cdefs.h>
+
+#if !defined(__BIONIC__)
+#error Only bionic supports system properties.
+#endif
+
+#include <limits>
+#include <string>
+
+namespace android {
+namespace base {
+
+// Returns the current value of the system property `key`,
+// or `default_value` if the property is empty or doesn't exist.
+std::string GetProperty(const std::string& key, const std::string& default_value);
+
+// Returns true if the system property `key` has the value "1", "y", "yes", "on", or "true",
+// false for "0", "n", "no", "off", or "false", or `default_value` otherwise.
+bool GetBoolProperty(const std::string& key, bool default_value);
+
+// Returns the signed integer corresponding to the system property `key`.
+// If the property is empty, doesn't exist, doesn't have an integer value, or is outside
+// the optional bounds, returns `default_value`.
+template <typename T> T GetIntProperty(const std::string& key,
+                                       T default_value,
+                                       T min = std::numeric_limits<T>::min(),
+                                       T max = std::numeric_limits<T>::max());
+
+// Returns the unsigned integer corresponding to the system property `key`.
+// If the property is empty, doesn't exist, doesn't have an integer value, or is outside
+// the optional bound, returns `default_value`.
+template <typename T> T GetUintProperty(const std::string& key,
+                                        T default_value,
+                                        T max = std::numeric_limits<T>::max());
+
+// Sets the system property `key` to `value`.
+// Note that system property setting is inherently asynchronous so a return value of `true`
+// isn't particularly meaningful, and immediately reading back the value won't necessarily
+// tell you whether or not your call succeeded. A `false` return value definitely means failure.
+bool SetProperty(const std::string& key, const std::string& value);
+
+} // namespace base
+} // namespace android
+
+#endif  // ANDROID_BASE_MEMORY_H
diff --git a/base/include/android-base/quick_exit.h b/base/include/android-base/quick_exit.h
new file mode 100644
index 0000000..a03b14f
--- /dev/null
+++ b/base/include/android-base/quick_exit.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <stdlib.h>
+
+// Provide emulation for at_quick_exit/quick_exit on platforms that don't have it.
+namespace android {
+namespace base {
+
+// Bionic and glibc have quick_exit, Darwin and Windows don't.
+#if !defined(__linux__)
+  void quick_exit(int exit_code) __attribute__((noreturn));
+  int at_quick_exit(void (*func)());
+#else
+  using ::at_quick_exit;
+  using ::quick_exit;
+#endif
+}
+}
diff --git a/base/include/android-base/strings.h b/base/include/android-base/strings.h
index 69781cd..b8a9289 100644
--- a/base/include/android-base/strings.h
+++ b/base/include/android-base/strings.h
@@ -58,9 +58,11 @@
 
 // Tests whether 's' starts with 'prefix'.
 bool StartsWith(const std::string& s, const char* prefix);
+bool StartsWithIgnoreCase(const std::string& s, const char* prefix);
 
 // Tests whether 's' ends with 'suffix'.
 bool EndsWith(const std::string& s, const char* suffix);
+bool EndsWithIgnoreCase(const std::string& s, const char* suffix);
 
 }  // namespace base
 }  // namespace android
diff --git a/base/include/android-base/test_utils.h b/base/include/android-base/test_utils.h
index 4ea3c8e..c0bf0c1 100644
--- a/base/include/android-base/test_utils.h
+++ b/base/include/android-base/test_utils.h
@@ -48,4 +48,21 @@
   DISALLOW_COPY_AND_ASSIGN(TemporaryDir);
 };
 
+class CapturedStderr {
+ public:
+  CapturedStderr();
+  ~CapturedStderr();
+
+  int fd() const;
+
+ private:
+  void init();
+  void reset();
+
+  TemporaryFile temp_file_;
+  int old_stderr_;
+
+  DISALLOW_COPY_AND_ASSIGN(CapturedStderr);
+};
+
 #endif  // ANDROID_BASE_TEST_UTILS_H
diff --git a/base/include/android-base/thread_annotations.h b/base/include/android-base/thread_annotations.h
index 2422102..fbb5923 100644
--- a/base/include/android-base/thread_annotations.h
+++ b/base/include/android-base/thread_annotations.h
@@ -29,6 +29,9 @@
 #define SCOPED_CAPABILITY \
       THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
 
+#define SHARED_CAPABILITY(...) \
+      THREAD_ANNOTATION_ATTRIBUTE__(shared_capability(__VA_ARGS__))
+
 #define GUARDED_BY(x) \
       THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
 
@@ -77,6 +80,27 @@
 #define RETURN_CAPABILITY(x) \
       THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
 
+#define EXCLUSIVE_LOCK_FUNCTION(...) \
+      THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
+
+#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \
+      THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
+
+#define SHARED_LOCK_FUNCTION(...) \
+      THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
+
+#define SHARED_TRYLOCK_FUNCTION(...) \
+      THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
+
+#define UNLOCK_FUNCTION(...) \
+      THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
+
+#define SCOPED_LOCKABLE \
+      THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
+
+#define LOCK_RETURNED(x) \
+      THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
+
 #define NO_THREAD_SAFETY_ANALYSIS \
       THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
 
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index 869e60f..6cfcfcd 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -55,7 +55,7 @@
   unique_fd_impl() : value_(-1) {}
 
   explicit unique_fd_impl(int value) : value_(value) {}
-  ~unique_fd_impl() { clear(); }
+  ~unique_fd_impl() { reset(); }
 
   unique_fd_impl(unique_fd_impl&& other) : value_(other.release()) {}
   unique_fd_impl& operator=(unique_fd_impl&& s) {
@@ -63,17 +63,13 @@
     return *this;
   }
 
-  void reset(int new_value) {
+  void reset(int new_value = -1) {
     if (value_ != -1) {
       Closer::Close(value_);
     }
     value_ = new_value;
   }
 
-  void clear() {
-    reset(-1);
-  }
-
   int get() const { return value_; }
   operator int() const { return get(); }
 
@@ -95,4 +91,14 @@
 }  // namespace base
 }  // namespace android
 
+template <typename T>
+int close(const android::base::unique_fd_impl<T>&)
+#if defined(__clang__)
+  __attribute__((__unavailable__(
+#else
+  __attribute__((__error__(
+#endif
+    "close called on unique_fd"
+  )));
+
 #endif  // ANDROID_BASE_UNIQUE_FD_H
diff --git a/base/logging.cpp b/base/logging.cpp
index 1741871..cbc3c8a 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -14,13 +14,15 @@
  * limitations under the License.
  */
 
-#ifdef _WIN32
+#if defined(_WIN32)
 #include <windows.h>
 #endif
 
 #include "android-base/logging.h"
 
+#include <fcntl.h>
 #include <libgen.h>
+#include <time.h>
 
 // For getprogname(3) or program_invocation_short_name.
 #if defined(__ANDROID__) || defined(__APPLE__)
@@ -29,30 +31,30 @@
 #include <errno.h>
 #endif
 
+#if defined(__linux__)
+#include <sys/uio.h>
+#endif
+
 #include <iostream>
 #include <limits>
+#include <mutex>
 #include <sstream>
 #include <string>
 #include <utility>
 #include <vector>
 
-#ifndef _WIN32
-#include <mutex>
-#endif
-
-#include "android-base/macros.h"
-#include "android-base/strings.h"
-#include "cutils/threads.h"
-
 // Headers for LogMessage::LogLine.
 #ifdef __ANDROID__
+#include <log/log.h>
 #include <android/set_abort_message.h>
-#include "cutils/log.h"
 #else
 #include <sys/types.h>
 #include <unistd.h>
 #endif
 
+#include <android-base/macros.h>
+#include <android-base/strings.h>
+
 // For gettid.
 #if defined(__APPLE__)
 #include "AvailabilityMacros.h"  // For MAC_OS_X_VERSION_MAX_ALLOWED
@@ -87,17 +89,11 @@
 }
 
 namespace {
-#ifndef _WIN32
-using std::mutex;
-using std::lock_guard;
-
 #if defined(__GLIBC__)
 const char* getprogname() {
   return program_invocation_short_name;
 }
-#endif
-
-#else
+#elif defined(_WIN32)
 const char* getprogname() {
   static bool first = true;
   static char progname[MAX_PATH] = {};
@@ -116,51 +112,13 @@
 
   return progname;
 }
-
-class mutex {
- public:
-  mutex() {
-    InitializeCriticalSection(&critical_section_);
-  }
-  ~mutex() {
-    DeleteCriticalSection(&critical_section_);
-  }
-
-  void lock() {
-    EnterCriticalSection(&critical_section_);
-  }
-
-  void unlock() {
-    LeaveCriticalSection(&critical_section_);
-  }
-
- private:
-  CRITICAL_SECTION critical_section_;
-};
-
-template <typename LockT>
-class lock_guard {
- public:
-  explicit lock_guard(LockT& lock) : lock_(lock) {
-    lock_.lock();
-  }
-
-  ~lock_guard() {
-    lock_.unlock();
-  }
-
- private:
-  LockT& lock_;
-
-  DISALLOW_COPY_AND_ASSIGN(lock_guard);
-};
 #endif
 } // namespace
 
 namespace android {
 namespace base {
 
-static auto& logging_lock = *new mutex();
+static auto& logging_lock = *new std::mutex();
 
 #ifdef __ANDROID__
 static auto& gLogger = *new LogFunction(LogdLogger());
@@ -168,14 +126,12 @@
 static auto& gLogger = *new LogFunction(StderrLogger);
 #endif
 
+static auto& gAborter = *new AbortFunction(DefaultAborter);
+
 static bool gInitialized = false;
 static LogSeverity gMinimumLogSeverity = INFO;
 static auto& gProgramInvocationName = *new std::unique_ptr<std::string>();
 
-LogSeverity GetMinimumLogSeverity() {
-  return gMinimumLogSeverity;
-}
-
 static const char* ProgramInvocationName() {
   if (gProgramInvocationName == nullptr) {
     gProgramInvocationName.reset(new std::string(getprogname()));
@@ -184,14 +140,75 @@
   return gProgramInvocationName->c_str();
 }
 
+#if defined(__linux__)
+void KernelLogger(android::base::LogId, android::base::LogSeverity severity,
+                  const char* tag, const char*, unsigned int, const char* msg) {
+  // clang-format off
+  static constexpr int kLogSeverityToKernelLogLevel[] = {
+      [android::base::VERBOSE] = 7,              // KERN_DEBUG (there is no verbose kernel log
+                                                 //             level)
+      [android::base::DEBUG] = 7,                // KERN_DEBUG
+      [android::base::INFO] = 6,                 // KERN_INFO
+      [android::base::WARNING] = 4,              // KERN_WARNING
+      [android::base::ERROR] = 3,                // KERN_ERROR
+      [android::base::FATAL_WITHOUT_ABORT] = 2,  // KERN_CRIT
+      [android::base::FATAL] = 2,                // KERN_CRIT
+  };
+  // clang-format on
+  static_assert(arraysize(kLogSeverityToKernelLogLevel) == android::base::FATAL + 1,
+                "Mismatch in size of kLogSeverityToKernelLogLevel and values in LogSeverity");
+
+  static int klog_fd = TEMP_FAILURE_RETRY(open("/dev/kmsg", O_WRONLY | O_CLOEXEC));
+  if (klog_fd == -1) return;
+
+  int level = kLogSeverityToKernelLogLevel[severity];
+
+  // The kernel's printk buffer is only 1024 bytes.
+  // TODO: should we automatically break up long lines into multiple lines?
+  // Or we could log but with something like "..." at the end?
+  char buf[1024];
+  size_t size = snprintf(buf, sizeof(buf), "<%d>%s: %s\n", level, tag, msg);
+  if (size > sizeof(buf)) {
+    size = snprintf(buf, sizeof(buf), "<%d>%s: %zu-byte message too long for printk\n",
+                    level, tag, size);
+  }
+
+  iovec iov[1];
+  iov[0].iov_base = buf;
+  iov[0].iov_len = size;
+  TEMP_FAILURE_RETRY(writev(klog_fd, iov, 1));
+}
+#endif
+
 void StderrLogger(LogId, LogSeverity severity, const char*, const char* file,
                   unsigned int line, const char* message) {
-  static const char log_characters[] = "VDIWEF";
+  struct tm now;
+  time_t t = time(nullptr);
+
+#if defined(_WIN32)
+  localtime_s(&now, &t);
+#else
+  localtime_r(&t, &now);
+#endif
+
+  char timestamp[32];
+  strftime(timestamp, sizeof(timestamp), "%m-%d %H:%M:%S", &now);
+
+  static const char log_characters[] = "VDIWEFF";
   static_assert(arraysize(log_characters) - 1 == FATAL + 1,
                 "Mismatch in size of log_characters and values in LogSeverity");
   char severity_char = log_characters[severity];
-  fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationName(),
-          severity_char, getpid(), GetThreadId(), file, line, message);
+  fprintf(stderr, "%s %c %s %5d %5d %s:%u] %s\n", ProgramInvocationName(),
+          severity_char, timestamp, getpid(), GetThreadId(), file, line, message);
+}
+
+void DefaultAborter(const char* abort_message) {
+#ifdef __ANDROID__
+  android_set_abort_message(abort_message);
+#else
+  UNUSED(abort_message);
+#endif
+  abort();
 }
 
 
@@ -199,28 +216,27 @@
 LogdLogger::LogdLogger(LogId default_log_id) : default_log_id_(default_log_id) {
 }
 
-static const android_LogPriority kLogSeverityToAndroidLogPriority[] = {
-    ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO,
-    ANDROID_LOG_WARN,    ANDROID_LOG_ERROR, ANDROID_LOG_FATAL,
-};
-static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1,
-              "Mismatch in size of kLogSeverityToAndroidLogPriority and values "
-              "in LogSeverity");
-
-static const log_id kLogIdToAndroidLogId[] = {
-    LOG_ID_MAX, LOG_ID_MAIN, LOG_ID_SYSTEM,
-};
-static_assert(arraysize(kLogIdToAndroidLogId) == SYSTEM + 1,
-              "Mismatch in size of kLogIdToAndroidLogId and values in LogId");
-
 void LogdLogger::operator()(LogId id, LogSeverity severity, const char* tag,
                             const char* file, unsigned int line,
                             const char* message) {
+  static constexpr android_LogPriority kLogSeverityToAndroidLogPriority[] = {
+      ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO,
+      ANDROID_LOG_WARN,    ANDROID_LOG_ERROR, ANDROID_LOG_FATAL,
+      ANDROID_LOG_FATAL,
+  };
+  static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1,
+                "Mismatch in size of kLogSeverityToAndroidLogPriority and values in LogSeverity");
+
   int priority = kLogSeverityToAndroidLogPriority[severity];
   if (id == DEFAULT) {
     id = default_log_id_;
   }
 
+  static constexpr log_id kLogIdToAndroidLogId[] = {
+    LOG_ID_MAX, LOG_ID_MAIN, LOG_ID_SYSTEM,
+  };
+  static_assert(arraysize(kLogIdToAndroidLogId) == SYSTEM + 1,
+                "Mismatch in size of kLogIdToAndroidLogId and values in LogId");
   log_id lg_id = kLogIdToAndroidLogId[id];
 
   if (priority == ANDROID_LOG_FATAL) {
@@ -232,12 +248,10 @@
 }
 #endif
 
-void InitLogging(char* argv[], LogFunction&& logger) {
+void InitLogging(char* argv[], LogFunction&& logger, AbortFunction&& aborter) {
   SetLogger(std::forward<LogFunction>(logger));
-  InitLogging(argv);
-}
+  SetAborter(std::forward<AbortFunction>(aborter));
 
-void InitLogging(char* argv[]) {
   if (gInitialized) {
     return;
   }
@@ -278,12 +292,12 @@
           gMinimumLogSeverity = ERROR;
           continue;
         case 'f':
-          gMinimumLogSeverity = FATAL;
+          gMinimumLogSeverity = FATAL_WITHOUT_ABORT;
           continue;
         // liblog will even suppress FATAL if you say 's' for silent, but that's
         // crazy!
         case 's':
-          gMinimumLogSeverity = FATAL;
+          gMinimumLogSeverity = FATAL_WITHOUT_ABORT;
           continue;
       }
     }
@@ -293,10 +307,15 @@
 }
 
 void SetLogger(LogFunction&& logger) {
-  lock_guard<mutex> lock(logging_lock);
+  std::lock_guard<std::mutex> lock(logging_lock);
   gLogger = std::move(logger);
 }
 
+void SetAborter(AbortFunction&& aborter) {
+  std::lock_guard<std::mutex> lock(logging_lock);
+  gAborter = std::move(aborter);
+}
+
 static const char* GetFileBasename(const char* file) {
   // We can't use basename(3) even on Unix because the Mac doesn't
   // have a non-modifying basename.
@@ -371,6 +390,11 @@
 }
 
 LogMessage::~LogMessage() {
+  // Check severity again. This is duplicate work wrt/ LOG macros, but not LOG_STREAM.
+  if (!WOULD_LOG(data_->GetSeverity())) {
+    return;
+  }
+
   // Finish constructing the message.
   if (data_->GetError() != -1) {
     data_->GetBuffer() << ": " << strerror(data_->GetError());
@@ -379,7 +403,7 @@
 
   {
     // Do the actual logging with the lock held.
-    lock_guard<mutex> lock(logging_lock);
+    std::lock_guard<std::mutex> lock(logging_lock);
     if (msg.find('\n') == std::string::npos) {
       LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(),
               data_->GetSeverity(), msg.c_str());
@@ -391,6 +415,8 @@
         msg[nl] = '\0';
         LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(),
                 data_->GetSeverity(), &msg[i]);
+        // Undo the zero-termination so we can give the complete message to the aborter.
+        msg[nl] = '\n';
         i = nl + 1;
       }
     }
@@ -398,10 +424,7 @@
 
   // Abort if necessary.
   if (data_->GetSeverity() == FATAL) {
-#ifdef __ANDROID__
-    android_set_abort_message(msg.c_str());
-#endif
-    abort();
+    gAborter(msg.c_str());
   }
 }
 
@@ -415,13 +438,22 @@
   gLogger(id, severity, tag, file, line, message);
 }
 
-ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) {
-  old_ = gMinimumLogSeverity;
-  gMinimumLogSeverity = level;
+LogSeverity GetMinimumLogSeverity() {
+    return gMinimumLogSeverity;
+}
+
+LogSeverity SetMinimumLogSeverity(LogSeverity new_severity) {
+  LogSeverity old_severity = gMinimumLogSeverity;
+  gMinimumLogSeverity = new_severity;
+  return old_severity;
+}
+
+ScopedLogSeverity::ScopedLogSeverity(LogSeverity new_severity) {
+  old_ = SetMinimumLogSeverity(new_severity);
 }
 
 ScopedLogSeverity::~ScopedLogSeverity() {
-  gMinimumLogSeverity = old_;
+  SetMinimumLogSeverity(old_);
 }
 
 }  // namespace base
diff --git a/base/logging_test.cpp b/base/logging_test.cpp
index 3de42b7..2d9c2ba 100644
--- a/base/logging_test.cpp
+++ b/base/logging_test.cpp
@@ -37,42 +37,6 @@
 #define HOST_TEST(suite, name) TEST(suite, name)
 #endif
 
-class CapturedStderr {
- public:
-  CapturedStderr() : old_stderr_(-1) {
-    init();
-  }
-
-  ~CapturedStderr() {
-    reset();
-  }
-
-  int fd() const {
-    return temp_file_.fd;
-  }
-
- private:
-  void init() {
-#if defined(_WIN32)
-    // On Windows, stderr is often buffered, so make sure it is unbuffered so
-    // that we can immediately read back what was written to stderr.
-    ASSERT_EQ(0, setvbuf(stderr, NULL, _IONBF, 0));
-#endif
-    old_stderr_ = dup(STDERR_FILENO);
-    ASSERT_NE(-1, old_stderr_);
-    ASSERT_NE(-1, dup2(fd(), STDERR_FILENO));
-  }
-
-  void reset() {
-    ASSERT_NE(-1, dup2(old_stderr_, STDERR_FILENO));
-    ASSERT_EQ(0, close(old_stderr_));
-    // Note: cannot restore prior setvbuf() setting.
-  }
-
-  TemporaryFile temp_file_;
-  int old_stderr_;
-};
-
 #if defined(_WIN32)
 static void ExitSignalAbortHandler(int) {
   _exit(3);
@@ -120,162 +84,513 @@
   EXPECT_FALSE(flag) << "CHECK_STREQ probably has a dangling if with no else";
 }
 
-std::string make_log_pattern(android::base::LogSeverity severity,
-                             const char* message) {
-  static const char* log_characters = "VDIWEF";
+TEST(logging, DCHECK) {
+  if (android::base::kEnableDChecks) {
+    ASSERT_DEATH({SuppressAbortUI(); DCHECK(false);}, "DCheck failed: false ");
+  }
+  DCHECK(true);
+
+  if (android::base::kEnableDChecks) {
+    ASSERT_DEATH({SuppressAbortUI(); DCHECK_EQ(0, 1);}, "DCheck failed: 0 == 1 ");
+  }
+  DCHECK_EQ(0, 0);
+
+  if (android::base::kEnableDChecks) {
+    ASSERT_DEATH({SuppressAbortUI(); DCHECK_STREQ("foo", "bar");},
+                 R"(DCheck failed: "foo" == "bar")");
+  }
+  DCHECK_STREQ("foo", "foo");
+
+  // No testing whether we have a dangling else, possibly. That's inherent to the if (constexpr)
+  // setup we intentionally chose to force type-checks of debug code even in release builds (so
+  // we don't get more bit-rot).
+}
+
+
+#define CHECK_WOULD_LOG_DISABLED(severity)                                               \
+  static_assert(android::base::severity < android::base::FATAL, "Bad input");            \
+  for (size_t i = static_cast<size_t>(android::base::severity) + 1;                      \
+       i <= static_cast<size_t>(android::base::FATAL);                                   \
+       ++i) {                                                                            \
+    {                                                                                    \
+      android::base::ScopedLogSeverity sls2(static_cast<android::base::LogSeverity>(i)); \
+      EXPECT_FALSE(WOULD_LOG(severity)) << i;                                            \
+    }                                                                                    \
+    {                                                                                    \
+      android::base::ScopedLogSeverity sls2(static_cast<android::base::LogSeverity>(i)); \
+      EXPECT_FALSE(WOULD_LOG(::android::base::severity)) << i;                           \
+    }                                                                                    \
+  }                                                                                      \
+
+#define CHECK_WOULD_LOG_ENABLED(severity)                                                \
+  for (size_t i = static_cast<size_t>(android::base::VERBOSE);                           \
+       i <= static_cast<size_t>(android::base::severity);                                \
+       ++i) {                                                                            \
+    {                                                                                    \
+      android::base::ScopedLogSeverity sls2(static_cast<android::base::LogSeverity>(i)); \
+      EXPECT_TRUE(WOULD_LOG(severity)) << i;                                             \
+    }                                                                                    \
+    {                                                                                    \
+      android::base::ScopedLogSeverity sls2(static_cast<android::base::LogSeverity>(i)); \
+      EXPECT_TRUE(WOULD_LOG(::android::base::severity)) << i;                            \
+    }                                                                                    \
+  }                                                                                      \
+
+TEST(logging, WOULD_LOG_FATAL) {
+  CHECK_WOULD_LOG_ENABLED(FATAL);
+}
+
+TEST(logging, WOULD_LOG_FATAL_WITHOUT_ABORT_disabled) {
+  CHECK_WOULD_LOG_DISABLED(FATAL_WITHOUT_ABORT);
+}
+
+TEST(logging, WOULD_LOG_FATAL_WITHOUT_ABORT_enabled) {
+  CHECK_WOULD_LOG_ENABLED(FATAL_WITHOUT_ABORT);
+}
+
+TEST(logging, WOULD_LOG_ERROR_disabled) {
+  CHECK_WOULD_LOG_DISABLED(ERROR);
+}
+
+TEST(logging, WOULD_LOG_ERROR_enabled) {
+  CHECK_WOULD_LOG_ENABLED(ERROR);
+}
+
+TEST(logging, WOULD_LOG_WARNING_disabled) {
+  CHECK_WOULD_LOG_DISABLED(WARNING);
+}
+
+TEST(logging, WOULD_LOG_WARNING_enabled) {
+  CHECK_WOULD_LOG_ENABLED(WARNING);
+}
+
+TEST(logging, WOULD_LOG_INFO_disabled) {
+  CHECK_WOULD_LOG_DISABLED(INFO);
+}
+
+TEST(logging, WOULD_LOG_INFO_enabled) {
+  CHECK_WOULD_LOG_ENABLED(INFO);
+}
+
+TEST(logging, WOULD_LOG_DEBUG_disabled) {
+  CHECK_WOULD_LOG_DISABLED(DEBUG);
+}
+
+TEST(logging, WOULD_LOG_DEBUG_enabled) {
+  CHECK_WOULD_LOG_ENABLED(DEBUG);
+}
+
+TEST(logging, WOULD_LOG_VERBOSE_disabled) {
+  CHECK_WOULD_LOG_DISABLED(VERBOSE);
+}
+
+TEST(logging, WOULD_LOG_VERBOSE_enabled) {
+  CHECK_WOULD_LOG_ENABLED(VERBOSE);
+}
+
+#undef CHECK_WOULD_LOG_DISABLED
+#undef CHECK_WOULD_LOG_ENABLED
+
+
+static std::string make_log_pattern(android::base::LogSeverity severity,
+                                    const char* message) {
+  static const char log_characters[] = "VDIWEFF";
+  static_assert(arraysize(log_characters) - 1 == android::base::FATAL + 1,
+                "Mismatch in size of log_characters and values in LogSeverity");
   char log_char = log_characters[severity];
   std::string holder(__FILE__);
   return android::base::StringPrintf(
-      "%c[[:space:]]+[[:digit:]]+[[:space:]]+[[:digit:]]+ %s:[[:digit:]]+] %s",
+      "%c \\d+-\\d+ \\d+:\\d+:\\d+ \\s*\\d+ \\s*\\d+ %s:\\d+] %s",
       log_char, basename(&holder[0]), message);
 }
 
-TEST(logging, LOG) {
-  ASSERT_DEATH({SuppressAbortUI(); LOG(FATAL) << "foobar";}, "foobar");
+static void CheckMessage(const CapturedStderr& cap,
+                         android::base::LogSeverity severity, const char* expected) {
+  std::string output;
+  ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
+  android::base::ReadFdToString(cap.fd(), &output);
 
   // We can't usefully check the output of any of these on Windows because we
   // don't have std::regex, but we can at least make sure we printed at least as
   // many characters are in the log message.
-  {
-    CapturedStderr cap;
-    LOG(WARNING) << "foobar";
-    ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
-
-    std::string output;
-    android::base::ReadFdToString(cap.fd(), &output);
-    ASSERT_GT(output.length(), strlen("foobar"));
+  ASSERT_GT(output.length(), strlen(expected));
+  ASSERT_NE(nullptr, strstr(output.c_str(), expected)) << output;
 
 #if !defined(_WIN32)
-    std::regex message_regex(
-        make_log_pattern(android::base::WARNING, "foobar"));
-    ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
+  std::regex message_regex(make_log_pattern(severity, expected));
+  ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
 #endif
+}
+
+
+#define CHECK_LOG_STREAM_DISABLED(severity) \
+  { \
+    android::base::ScopedLogSeverity sls1(android::base::FATAL); \
+    CapturedStderr cap1; \
+    LOG_STREAM(severity) << "foo bar"; \
+    ASSERT_EQ(0, lseek(cap1.fd(), 0, SEEK_CUR)); \
+  } \
+  { \
+    android::base::ScopedLogSeverity sls1(android::base::FATAL); \
+    CapturedStderr cap1; \
+    LOG_STREAM(::android::base::severity) << "foo bar"; \
+    ASSERT_EQ(0, lseek(cap1.fd(), 0, SEEK_CUR)); \
+  } \
+
+#define CHECK_LOG_STREAM_ENABLED(severity) \
+  { \
+    android::base::ScopedLogSeverity sls2(android::base::severity); \
+    CapturedStderr cap2; \
+    LOG_STREAM(severity) << "foobar"; \
+    CheckMessage(cap2, android::base::severity, "foobar"); \
+  } \
+  { \
+    android::base::ScopedLogSeverity sls2(android::base::severity); \
+    CapturedStderr cap2; \
+    LOG_STREAM(::android::base::severity) << "foobar"; \
+    CheckMessage(cap2, android::base::severity, "foobar"); \
+  } \
+
+TEST(logging, LOG_STREAM_FATAL_WITHOUT_ABORT_disabled) {
+  CHECK_LOG_STREAM_DISABLED(FATAL_WITHOUT_ABORT);
+}
+
+TEST(logging, LOG_STREAM_FATAL_WITHOUT_ABORT_enabled) {
+  CHECK_LOG_STREAM_ENABLED(FATAL_WITHOUT_ABORT);
+}
+
+TEST(logging, LOG_STREAM_ERROR_disabled) {
+  CHECK_LOG_STREAM_DISABLED(ERROR);
+}
+
+TEST(logging, LOG_STREAM_ERROR_enabled) {
+  CHECK_LOG_STREAM_ENABLED(ERROR);
+}
+
+TEST(logging, LOG_STREAM_WARNING_disabled) {
+  CHECK_LOG_STREAM_DISABLED(WARNING);
+}
+
+TEST(logging, LOG_STREAM_WARNING_enabled) {
+  CHECK_LOG_STREAM_ENABLED(WARNING);
+}
+
+TEST(logging, LOG_STREAM_INFO_disabled) {
+  CHECK_LOG_STREAM_DISABLED(INFO);
+}
+
+TEST(logging, LOG_STREAM_INFO_enabled) {
+  CHECK_LOG_STREAM_ENABLED(INFO);
+}
+
+TEST(logging, LOG_STREAM_DEBUG_disabled) {
+  CHECK_LOG_STREAM_DISABLED(DEBUG);
+}
+
+TEST(logging, LOG_STREAM_DEBUG_enabled) {
+  CHECK_LOG_STREAM_ENABLED(DEBUG);
+}
+
+TEST(logging, LOG_STREAM_VERBOSE_disabled) {
+  CHECK_LOG_STREAM_DISABLED(VERBOSE);
+}
+
+TEST(logging, LOG_STREAM_VERBOSE_enabled) {
+  CHECK_LOG_STREAM_ENABLED(VERBOSE);
+}
+
+#undef CHECK_LOG_STREAM_DISABLED
+#undef CHECK_LOG_STREAM_ENABLED
+
+
+#define CHECK_LOG_DISABLED(severity) \
+  { \
+    android::base::ScopedLogSeverity sls1(android::base::FATAL); \
+    CapturedStderr cap1; \
+    LOG(severity) << "foo bar"; \
+    ASSERT_EQ(0, lseek(cap1.fd(), 0, SEEK_CUR)); \
+  } \
+  { \
+    android::base::ScopedLogSeverity sls1(android::base::FATAL); \
+    CapturedStderr cap1; \
+    LOG(::android::base::severity) << "foo bar"; \
+    ASSERT_EQ(0, lseek(cap1.fd(), 0, SEEK_CUR)); \
+  } \
+
+#define CHECK_LOG_ENABLED(severity) \
+  { \
+    android::base::ScopedLogSeverity sls2(android::base::severity); \
+    CapturedStderr cap2; \
+    LOG(severity) << "foobar"; \
+    CheckMessage(cap2, android::base::severity, "foobar"); \
+  } \
+  { \
+    android::base::ScopedLogSeverity sls2(android::base::severity); \
+    CapturedStderr cap2; \
+    LOG(::android::base::severity) << "foobar"; \
+    CheckMessage(cap2, android::base::severity, "foobar"); \
+  } \
+
+TEST(logging, LOG_FATAL) {
+  ASSERT_DEATH({SuppressAbortUI(); LOG(FATAL) << "foobar";}, "foobar");
+  ASSERT_DEATH({SuppressAbortUI(); LOG(::android::base::FATAL) << "foobar";}, "foobar");
+}
+
+TEST(logging, LOG_FATAL_WITHOUT_ABORT_disabled) {
+  CHECK_LOG_DISABLED(FATAL_WITHOUT_ABORT);
+}
+
+TEST(logging, LOG_FATAL_WITHOUT_ABORT_enabled) {
+  CHECK_LOG_ENABLED(FATAL_WITHOUT_ABORT);
+}
+
+TEST(logging, LOG_ERROR_disabled) {
+  CHECK_LOG_DISABLED(ERROR);
+}
+
+TEST(logging, LOG_ERROR_enabled) {
+  CHECK_LOG_ENABLED(ERROR);
+}
+
+TEST(logging, LOG_WARNING_disabled) {
+  CHECK_LOG_DISABLED(WARNING);
+}
+
+TEST(logging, LOG_WARNING_enabled) {
+  CHECK_LOG_ENABLED(WARNING);
+}
+
+TEST(logging, LOG_INFO_disabled) {
+  CHECK_LOG_DISABLED(INFO);
+}
+
+TEST(logging, LOG_INFO_enabled) {
+  CHECK_LOG_ENABLED(INFO);
+}
+
+TEST(logging, LOG_DEBUG_disabled) {
+  CHECK_LOG_DISABLED(DEBUG);
+}
+
+TEST(logging, LOG_DEBUG_enabled) {
+  CHECK_LOG_ENABLED(DEBUG);
+}
+
+TEST(logging, LOG_VERBOSE_disabled) {
+  CHECK_LOG_DISABLED(VERBOSE);
+}
+
+TEST(logging, LOG_VERBOSE_enabled) {
+  CHECK_LOG_ENABLED(VERBOSE);
+}
+
+#undef CHECK_LOG_DISABLED
+#undef CHECK_LOG_ENABLED
+
+
+TEST(logging, LOG_complex_param) {
+#define CHECK_LOG_COMBINATION(use_scoped_log_severity_info, use_logging_severity_info)             \
+  {                                                                                                \
+    android::base::ScopedLogSeverity sls(                                                          \
+        (use_scoped_log_severity_info) ? ::android::base::INFO : ::android::base::WARNING);        \
+    CapturedStderr cap;                                                                            \
+    LOG((use_logging_severity_info) ? ::android::base::INFO : ::android::base::WARNING)            \
+        << "foobar";                                                                               \
+    if ((use_scoped_log_severity_info) || !(use_logging_severity_info)) {                          \
+      CheckMessage(cap,                                                                            \
+                   (use_logging_severity_info) ? ::android::base::INFO : ::android::base::WARNING, \
+                   "foobar");                                                                      \
+    } else {                                                                                       \
+      ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_CUR));                                                  \
+    }                                                                                              \
   }
 
-  {
-    CapturedStderr cap;
+  CHECK_LOG_COMBINATION(false,false);
+  CHECK_LOG_COMBINATION(false,true);
+  CHECK_LOG_COMBINATION(true,false);
+  CHECK_LOG_COMBINATION(true,true);
+
+#undef CHECK_LOG_COMBINATION
+}
+
+
+TEST(logging, LOG_does_not_clobber_errno) {
+  CapturedStderr cap;
+  errno = 12345;
+  LOG(INFO) << (errno = 67890);
+  EXPECT_EQ(12345, errno) << "errno was not restored";
+
+  CheckMessage(cap, android::base::INFO, "67890");
+}
+
+TEST(logging, PLOG_does_not_clobber_errno) {
+  CapturedStderr cap;
+  errno = 12345;
+  PLOG(INFO) << (errno = 67890);
+  EXPECT_EQ(12345, errno) << "errno was not restored";
+
+  CheckMessage(cap, android::base::INFO, "67890");
+}
+
+TEST(logging, LOG_does_not_have_dangling_if) {
+  CapturedStderr cap; // So the logging below has no side-effects.
+
+  // Do the test two ways: once where we hypothesize that LOG()'s if
+  // will evaluate to true (when severity is high enough) and once when we
+  // expect it to evaluate to false (when severity is not high enough).
+  bool flag = false;
+  if (true)
     LOG(INFO) << "foobar";
-    ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
+  else
+    flag = true;
 
-    std::string output;
-    android::base::ReadFdToString(cap.fd(), &output);
-    ASSERT_GT(output.length(), strlen("foobar"));
+  EXPECT_FALSE(flag) << "LOG macro probably has a dangling if with no else";
 
-#if !defined(_WIN32)
-    std::regex message_regex(
-        make_log_pattern(android::base::INFO, "foobar"));
-    ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
-#endif
-  }
+  flag = false;
+  if (true)
+    LOG(VERBOSE) << "foobar";
+  else
+    flag = true;
 
-  {
-    CapturedStderr cap;
-    LOG(DEBUG) << "foobar";
-    ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
-
-    std::string output;
-    android::base::ReadFdToString(cap.fd(), &output);
-    ASSERT_TRUE(output.empty());
-  }
-
-  {
-    android::base::ScopedLogSeverity severity(android::base::DEBUG);
-    CapturedStderr cap;
-    LOG(DEBUG) << "foobar";
-    ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
-
-    std::string output;
-    android::base::ReadFdToString(cap.fd(), &output);
-    ASSERT_GT(output.length(), strlen("foobar"));
-
-#if !defined(_WIN32)
-    std::regex message_regex(
-        make_log_pattern(android::base::DEBUG, "foobar"));
-    ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
-#endif
-  }
-
-  // Test whether LOG() saves and restores errno.
-  {
-    CapturedStderr cap;
-    errno = 12345;
-    LOG(INFO) << (errno = 67890);
-    EXPECT_EQ(12345, errno) << "errno was not restored";
-
-    ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
-
-    std::string output;
-    android::base::ReadFdToString(cap.fd(), &output);
-    EXPECT_NE(nullptr, strstr(output.c_str(), "67890")) << output;
-
-#if !defined(_WIN32)
-    std::regex message_regex(
-        make_log_pattern(android::base::INFO, "67890"));
-    ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
-#endif
-  }
-
-  // Test whether LOG() has a dangling if with no else.
-  {
-    CapturedStderr cap;
-
-    // Do the test two ways: once where we hypothesize that LOG()'s if
-    // will evaluate to true (when severity is high enough) and once when we
-    // expect it to evaluate to false (when severity is not high enough).
-    bool flag = false;
-    if (true)
-      LOG(INFO) << "foobar";
-    else
-      flag = true;
-
-    EXPECT_FALSE(flag) << "LOG macro probably has a dangling if with no else";
-
-    flag = false;
-    if (true)
-      LOG(VERBOSE) << "foobar";
-    else
-      flag = true;
-
-    EXPECT_FALSE(flag) << "LOG macro probably has a dangling if with no else";
-  }
+  EXPECT_FALSE(flag) << "LOG macro probably has a dangling if with no else";
 }
 
-TEST(logging, PLOG) {
-  {
-    CapturedStderr cap;
-    errno = ENOENT;
-    PLOG(INFO) << "foobar";
-    ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
+#define CHECK_PLOG_DISABLED(severity) \
+  { \
+    android::base::ScopedLogSeverity sls1(android::base::FATAL); \
+    CapturedStderr cap1; \
+    PLOG(severity) << "foo bar"; \
+    ASSERT_EQ(0, lseek(cap1.fd(), 0, SEEK_CUR)); \
+  } \
+  { \
+    android::base::ScopedLogSeverity sls1(android::base::FATAL); \
+    CapturedStderr cap1; \
+    PLOG(severity) << "foo bar"; \
+    ASSERT_EQ(0, lseek(cap1.fd(), 0, SEEK_CUR)); \
+  } \
 
-    std::string output;
-    android::base::ReadFdToString(cap.fd(), &output);
-    ASSERT_GT(output.length(), strlen("foobar"));
+#define CHECK_PLOG_ENABLED(severity) \
+  { \
+    android::base::ScopedLogSeverity sls2(android::base::severity); \
+    CapturedStderr cap2; \
+    errno = ENOENT; \
+    PLOG(severity) << "foobar"; \
+    CheckMessage(cap2, android::base::severity, "foobar: No such file or directory"); \
+  } \
+  { \
+    android::base::ScopedLogSeverity sls2(android::base::severity); \
+    CapturedStderr cap2; \
+    errno = ENOENT; \
+    PLOG(severity) << "foobar"; \
+    CheckMessage(cap2, android::base::severity, "foobar: No such file or directory"); \
+  } \
 
-#if !defined(_WIN32)
-    std::regex message_regex(make_log_pattern(
-        android::base::INFO, "foobar: No such file or directory"));
-    ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
-#endif
-  }
+TEST(logging, PLOG_FATAL) {
+  ASSERT_DEATH({SuppressAbortUI(); PLOG(FATAL) << "foobar";}, "foobar");
+  ASSERT_DEATH({SuppressAbortUI(); PLOG(::android::base::FATAL) << "foobar";}, "foobar");
 }
 
+TEST(logging, PLOG_FATAL_WITHOUT_ABORT_disabled) {
+  CHECK_PLOG_DISABLED(FATAL_WITHOUT_ABORT);
+}
+
+TEST(logging, PLOG_FATAL_WITHOUT_ABORT_enabled) {
+  CHECK_PLOG_ENABLED(FATAL_WITHOUT_ABORT);
+}
+
+TEST(logging, PLOG_ERROR_disabled) {
+  CHECK_PLOG_DISABLED(ERROR);
+}
+
+TEST(logging, PLOG_ERROR_enabled) {
+  CHECK_PLOG_ENABLED(ERROR);
+}
+
+TEST(logging, PLOG_WARNING_disabled) {
+  CHECK_PLOG_DISABLED(WARNING);
+}
+
+TEST(logging, PLOG_WARNING_enabled) {
+  CHECK_PLOG_ENABLED(WARNING);
+}
+
+TEST(logging, PLOG_INFO_disabled) {
+  CHECK_PLOG_DISABLED(INFO);
+}
+
+TEST(logging, PLOG_INFO_enabled) {
+  CHECK_PLOG_ENABLED(INFO);
+}
+
+TEST(logging, PLOG_DEBUG_disabled) {
+  CHECK_PLOG_DISABLED(DEBUG);
+}
+
+TEST(logging, PLOG_DEBUG_enabled) {
+  CHECK_PLOG_ENABLED(DEBUG);
+}
+
+TEST(logging, PLOG_VERBOSE_disabled) {
+  CHECK_PLOG_DISABLED(VERBOSE);
+}
+
+TEST(logging, PLOG_VERBOSE_enabled) {
+  CHECK_PLOG_ENABLED(VERBOSE);
+}
+
+#undef CHECK_PLOG_DISABLED
+#undef CHECK_PLOG_ENABLED
+
+
 TEST(logging, UNIMPLEMENTED) {
+  std::string expected = android::base::StringPrintf("%s unimplemented ", __PRETTY_FUNCTION__);
+
+  CapturedStderr cap;
+  errno = ENOENT;
+  UNIMPLEMENTED(ERROR);
+  CheckMessage(cap, android::base::ERROR, expected.c_str());
+}
+
+static void NoopAborter(const char* msg ATTRIBUTE_UNUSED) {
+  LOG(ERROR) << "called noop";
+}
+
+TEST(logging, LOG_FATAL_NOOP_ABORTER) {
   {
+    android::base::SetAborter(NoopAborter);
+
+    android::base::ScopedLogSeverity sls(android::base::ERROR);
     CapturedStderr cap;
-    errno = ENOENT;
-    UNIMPLEMENTED(ERROR);
-    ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
+    LOG(FATAL) << "foobar";
+    CheckMessage(cap, android::base::FATAL, "foobar");
+    CheckMessage(cap, android::base::ERROR, "called noop");
 
-    std::string output;
-    android::base::ReadFdToString(cap.fd(), &output);
-    ASSERT_GT(output.length(), strlen("unimplemented"));
-
-#if !defined(_WIN32)
-    std::string expected_message =
-        android::base::StringPrintf("%s unimplemented ", __PRETTY_FUNCTION__);
-    std::regex message_regex(
-        make_log_pattern(android::base::ERROR, expected_message.c_str()));
-    ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
-#endif
+    android::base::SetAborter(android::base::DefaultAborter);
   }
+
+  ASSERT_DEATH({SuppressAbortUI(); LOG(FATAL) << "foobar";}, "foobar");
+}
+
+struct CountLineAborter {
+  static void CountLineAborterFunction(const char* msg) {
+    while (*msg != 0) {
+      if (*msg == '\n') {
+        newline_count++;
+      }
+      msg++;
+    }
+  }
+  static size_t newline_count;
+};
+size_t CountLineAborter::newline_count = 0;
+
+TEST(logging, LOG_FATAL_ABORTER_MESSAGE) {
+  CountLineAborter::newline_count = 0;
+  android::base::SetAborter(CountLineAborter::CountLineAborterFunction);
+
+  android::base::ScopedLogSeverity sls(android::base::ERROR);
+  CapturedStderr cap;
+  LOG(FATAL) << "foo\nbar";
+
+  EXPECT_EQ(CountLineAborter::newline_count, 1U + 1U);  // +1 for final '\n'.
 }
diff --git a/base/parsedouble_test.cpp b/base/parsedouble_test.cpp
new file mode 100644
index 0000000..8734c42
--- /dev/null
+++ b/base/parsedouble_test.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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 "android-base/parsedouble.h"
+
+#include <gtest/gtest.h>
+
+TEST(parsedouble, smoke) {
+  double d;
+  ASSERT_FALSE(android::base::ParseDouble("", &d));
+  ASSERT_FALSE(android::base::ParseDouble("x", &d));
+  ASSERT_FALSE(android::base::ParseDouble("123.4x", &d));
+
+  ASSERT_TRUE(android::base::ParseDouble("123.4", &d));
+  ASSERT_DOUBLE_EQ(123.4, d);
+  ASSERT_TRUE(android::base::ParseDouble("-123.4", &d));
+  ASSERT_DOUBLE_EQ(-123.4, d);
+
+  ASSERT_TRUE(android::base::ParseDouble("0", &d, 0.0));
+  ASSERT_DOUBLE_EQ(0.0, d);
+  ASSERT_FALSE(android::base::ParseDouble("0", &d, 1e-9));
+  ASSERT_FALSE(android::base::ParseDouble("3.0", &d, -1.0, 2.0));
+  ASSERT_TRUE(android::base::ParseDouble("1.0", &d, 0.0, 2.0));
+  ASSERT_DOUBLE_EQ(1.0, d);
+}
diff --git a/base/parseint_test.cpp b/base/parseint_test.cpp
index 6a3ba31..483b1d3 100644
--- a/base/parseint_test.cpp
+++ b/base/parseint_test.cpp
@@ -19,7 +19,7 @@
 #include <gtest/gtest.h>
 
 TEST(parseint, signed_smoke) {
-  int i;
+  int i = 0;
   ASSERT_FALSE(android::base::ParseInt("x", &i));
   ASSERT_FALSE(android::base::ParseInt("123x", &i));
 
@@ -28,7 +28,7 @@
   ASSERT_TRUE(android::base::ParseInt("-123", &i));
   ASSERT_EQ(-123, i);
 
-  short s;
+  short s = 0;
   ASSERT_TRUE(android::base::ParseInt("1234", &s));
   ASSERT_EQ(1234, s);
 
@@ -39,7 +39,7 @@
 }
 
 TEST(parseint, unsigned_smoke) {
-  unsigned int i;
+  unsigned int i = 0u;
   ASSERT_FALSE(android::base::ParseUint("x", &i));
   ASSERT_FALSE(android::base::ParseUint("123x", &i));
 
@@ -47,7 +47,7 @@
   ASSERT_EQ(123u, i);
   ASSERT_FALSE(android::base::ParseUint("-123", &i));
 
-  unsigned short s;
+  unsigned short s = 0u;
   ASSERT_TRUE(android::base::ParseUint("1234", &s));
   ASSERT_EQ(1234u, s);
 
@@ -58,21 +58,41 @@
 }
 
 TEST(parseint, no_implicit_octal) {
-  int i;
+  int i = 0;
   ASSERT_TRUE(android::base::ParseInt("0123", &i));
   ASSERT_EQ(123, i);
 
-  unsigned int u;
+  unsigned int u = 0u;
   ASSERT_TRUE(android::base::ParseUint("0123", &u));
   ASSERT_EQ(123u, u);
 }
 
 TEST(parseint, explicit_hex) {
-  int i;
+  int i = 0;
   ASSERT_TRUE(android::base::ParseInt("0x123", &i));
   ASSERT_EQ(0x123, i);
 
-  unsigned int u;
+  unsigned int u = 0u;
   ASSERT_TRUE(android::base::ParseUint("0x123", &u));
   ASSERT_EQ(0x123u, u);
 }
+
+TEST(parseint, string) {
+  int i = 0;
+  ASSERT_TRUE(android::base::ParseInt(std::string("123"), &i));
+  ASSERT_EQ(123, i);
+
+  unsigned int u = 0u;
+  ASSERT_TRUE(android::base::ParseUint(std::string("123"), &u));
+  ASSERT_EQ(123u, u);
+}
+
+TEST(parseint, untouched_on_failure) {
+  int i = 123;
+  ASSERT_FALSE(android::base::ParseInt("456x", &i));
+  ASSERT_EQ(123, i);
+
+  unsigned int u = 123u;
+  ASSERT_FALSE(android::base::ParseInt("456x", &u));
+  ASSERT_EQ(123u, u);
+}
diff --git a/base/properties.cpp b/base/properties.cpp
new file mode 100644
index 0000000..37daf9a
--- /dev/null
+++ b/base/properties.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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 "android-base/properties.h"
+
+#include <sys/system_properties.h>
+
+#include <string>
+
+#include <android-base/parseint.h>
+
+namespace android {
+namespace base {
+
+std::string GetProperty(const std::string& key, const std::string& default_value) {
+  const prop_info* pi = __system_property_find(key.c_str());
+  if (pi == nullptr) return default_value;
+
+  char buf[PROP_VALUE_MAX];
+  if (__system_property_read(pi, nullptr, buf) > 0) return buf;
+
+  // If the property exists but is empty, also return the default value.
+  // Since we can't remove system properties, "empty" is traditionally
+  // the same as "missing" (this was true for cutils' property_get).
+  return default_value;
+}
+
+bool GetBoolProperty(const std::string& key, bool default_value) {
+  std::string value = GetProperty(key, "");
+  if (value == "1" || value == "y" || value == "yes" || value == "on" || value == "true") {
+    return true;
+  } else if (value == "0" || value == "n" || value == "no" || value == "off" || value == "false") {
+    return false;
+  }
+  return default_value;
+}
+
+template <typename T>
+T GetIntProperty(const std::string& key, T default_value, T min, T max) {
+  T result;
+  std::string value = GetProperty(key, "");
+  if (!value.empty() && android::base::ParseInt(value, &result, min, max)) return result;
+  return default_value;
+}
+
+template <typename T>
+T GetUintProperty(const std::string& key, T default_value, T max) {
+  T result;
+  std::string value = GetProperty(key, "");
+  if (!value.empty() && android::base::ParseUint(value, &result, max)) return result;
+  return default_value;
+}
+
+template int8_t GetIntProperty(const std::string&, int8_t, int8_t, int8_t);
+template int16_t GetIntProperty(const std::string&, int16_t, int16_t, int16_t);
+template int32_t GetIntProperty(const std::string&, int32_t, int32_t, int32_t);
+template int64_t GetIntProperty(const std::string&, int64_t, int64_t, int64_t);
+
+template uint8_t GetUintProperty(const std::string&, uint8_t, uint8_t);
+template uint16_t GetUintProperty(const std::string&, uint16_t, uint16_t);
+template uint32_t GetUintProperty(const std::string&, uint32_t, uint32_t);
+template uint64_t GetUintProperty(const std::string&, uint64_t, uint64_t);
+
+bool SetProperty(const std::string& key, const std::string& value) {
+  return (__system_property_set(key.c_str(), value.c_str()) == 0);
+}
+
+}  // namespace base
+}  // namespace android
diff --git a/base/properties_test.cpp b/base/properties_test.cpp
new file mode 100644
index 0000000..da89ec5
--- /dev/null
+++ b/base/properties_test.cpp
@@ -0,0 +1,121 @@
+/*
+ * 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 "android-base/properties.h"
+
+#include <gtest/gtest.h>
+
+#include <string>
+
+TEST(properties, smoke) {
+  android::base::SetProperty("debug.libbase.property_test", "hello");
+
+  std::string s = android::base::GetProperty("debug.libbase.property_test", "");
+  ASSERT_EQ("hello", s);
+
+  android::base::SetProperty("debug.libbase.property_test", "world");
+  s = android::base::GetProperty("debug.libbase.property_test", "");
+  ASSERT_EQ("world", s);
+
+  s = android::base::GetProperty("this.property.does.not.exist", "");
+  ASSERT_EQ("", s);
+
+  s = android::base::GetProperty("this.property.does.not.exist", "default");
+  ASSERT_EQ("default", s);
+}
+
+TEST(properties, empty) {
+  // Because you can't delete a property, people "delete" them by
+  // setting them to the empty string. In that case we'd want to
+  // keep the default value (like cutils' property_get did).
+  android::base::SetProperty("debug.libbase.property_test", "");
+  std::string s = android::base::GetProperty("debug.libbase.property_test", "default");
+  ASSERT_EQ("default", s);
+}
+
+static void CheckGetBoolProperty(bool expected, const std::string& value, bool default_value) {
+  android::base::SetProperty("debug.libbase.property_test", value.c_str());
+  ASSERT_EQ(expected, android::base::GetBoolProperty("debug.libbase.property_test", default_value));
+}
+
+TEST(properties, GetBoolProperty_true) {
+  CheckGetBoolProperty(true, "1", false);
+  CheckGetBoolProperty(true, "y", false);
+  CheckGetBoolProperty(true, "yes", false);
+  CheckGetBoolProperty(true, "on", false);
+  CheckGetBoolProperty(true, "true", false);
+}
+
+TEST(properties, GetBoolProperty_false) {
+  CheckGetBoolProperty(false, "0", true);
+  CheckGetBoolProperty(false, "n", true);
+  CheckGetBoolProperty(false, "no", true);
+  CheckGetBoolProperty(false, "off", true);
+  CheckGetBoolProperty(false, "false", true);
+}
+
+TEST(properties, GetBoolProperty_default) {
+  CheckGetBoolProperty(true, "burp", true);
+  CheckGetBoolProperty(false, "burp", false);
+}
+
+template <typename T> void CheckGetIntProperty() {
+  // Positive and negative.
+  android::base::SetProperty("debug.libbase.property_test", "-12");
+  EXPECT_EQ(T(-12), android::base::GetIntProperty<T>("debug.libbase.property_test", 45));
+  android::base::SetProperty("debug.libbase.property_test", "12");
+  EXPECT_EQ(T(12), android::base::GetIntProperty<T>("debug.libbase.property_test", 45));
+
+  // Default value.
+  android::base::SetProperty("debug.libbase.property_test", "");
+  EXPECT_EQ(T(45), android::base::GetIntProperty<T>("debug.libbase.property_test", 45));
+
+  // Bounds checks.
+  android::base::SetProperty("debug.libbase.property_test", "0");
+  EXPECT_EQ(T(45), android::base::GetIntProperty<T>("debug.libbase.property_test", 45, 1, 2));
+  android::base::SetProperty("debug.libbase.property_test", "1");
+  EXPECT_EQ(T(1), android::base::GetIntProperty<T>("debug.libbase.property_test", 45, 1, 2));
+  android::base::SetProperty("debug.libbase.property_test", "2");
+  EXPECT_EQ(T(2), android::base::GetIntProperty<T>("debug.libbase.property_test", 45, 1, 2));
+  android::base::SetProperty("debug.libbase.property_test", "3");
+  EXPECT_EQ(T(45), android::base::GetIntProperty<T>("debug.libbase.property_test", 45, 1, 2));
+}
+
+template <typename T> void CheckGetUintProperty() {
+  // Positive.
+  android::base::SetProperty("debug.libbase.property_test", "12");
+  EXPECT_EQ(T(12), android::base::GetUintProperty<T>("debug.libbase.property_test", 45));
+
+  // Default value.
+  android::base::SetProperty("debug.libbase.property_test", "");
+  EXPECT_EQ(T(45), android::base::GetUintProperty<T>("debug.libbase.property_test", 45));
+
+  // Bounds checks.
+  android::base::SetProperty("debug.libbase.property_test", "12");
+  EXPECT_EQ(T(12), android::base::GetUintProperty<T>("debug.libbase.property_test", 33, 22));
+  android::base::SetProperty("debug.libbase.property_test", "12");
+  EXPECT_EQ(T(5), android::base::GetUintProperty<T>("debug.libbase.property_test", 5, 10));
+}
+
+TEST(properties, GetIntProperty_int8_t) { CheckGetIntProperty<int8_t>(); }
+TEST(properties, GetIntProperty_int16_t) { CheckGetIntProperty<int16_t>(); }
+TEST(properties, GetIntProperty_int32_t) { CheckGetIntProperty<int32_t>(); }
+TEST(properties, GetIntProperty_int64_t) { CheckGetIntProperty<int64_t>(); }
+
+TEST(properties, GetUintProperty_uint8_t) { CheckGetUintProperty<uint8_t>(); }
+TEST(properties, GetUintProperty_uint16_t) { CheckGetUintProperty<uint16_t>(); }
+TEST(properties, GetUintProperty_uint32_t) { CheckGetUintProperty<uint32_t>(); }
+TEST(properties, GetUintProperty_uint64_t) { CheckGetUintProperty<uint64_t>(); }
diff --git a/base/quick_exit.cpp b/base/quick_exit.cpp
new file mode 100644
index 0000000..e4dd62b
--- /dev/null
+++ b/base/quick_exit.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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 "android-base/quick_exit.h"
+
+#if !defined(__linux__)
+
+#include <mutex>
+#include <vector>
+
+namespace android {
+namespace base {
+
+static auto& quick_exit_mutex = *new std::mutex();
+static auto& quick_exit_handlers = *new std::vector<void (*)()>();
+
+void quick_exit(int exit_code) {
+  std::lock_guard<std::mutex> lock(quick_exit_mutex);
+  for (auto it = quick_exit_handlers.rbegin(); it != quick_exit_handlers.rend(); ++it) {
+    (*it)();
+  }
+  _Exit(exit_code);
+}
+
+int at_quick_exit(void (*func)()) {
+  std::lock_guard<std::mutex> lock(quick_exit_mutex);
+  quick_exit_handlers.push_back(func);
+  return 0;
+}
+
+}  // namespace base
+}  // namespace android
+#endif
diff --git a/base/quick_exit_test.cpp b/base/quick_exit_test.cpp
new file mode 100644
index 0000000..7ca8156
--- /dev/null
+++ b/base/quick_exit_test.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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 "android-base/quick_exit.h"
+
+#include <gtest/gtest.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "android-base/test_utils.h"
+
+// These tests are a bit sketchy, since each test run adds global state that affects subsequent
+// tests (including ones not in this file!). Exit with 0 in Exiter and stick the at_quick_exit test
+// at the end to hack around this.
+struct Exiter {
+  ~Exiter() {
+    _Exit(0);
+  }
+};
+
+TEST(quick_exit, smoke) {
+  ASSERT_EXIT(android::base::quick_exit(123), testing::ExitedWithCode(123), "");
+}
+
+TEST(quick_exit, skip_static_destructors) {
+  static Exiter exiter;
+  ASSERT_EXIT(android::base::quick_exit(123), testing::ExitedWithCode(123), "");
+}
+
+TEST(quick_exit, at_quick_exit) {
+  static int counter = 4;
+  // "Functions passed to at_quick_exit are called in reverse order of their registration."
+  ASSERT_EQ(0, android::base::at_quick_exit([]() { _exit(counter); }));
+  ASSERT_EQ(0, android::base::at_quick_exit([]() { counter += 2; }));
+  ASSERT_EQ(0, android::base::at_quick_exit([]() { counter *= 10; }));
+  ASSERT_EXIT(android::base::quick_exit(123), testing::ExitedWithCode(42), "");
+}
diff --git a/base/strings.cpp b/base/strings.cpp
index b8775df..7a94ad7 100644
--- a/base/strings.cpp
+++ b/base/strings.cpp
@@ -87,17 +87,29 @@
 template std::string Join(const std::vector<const char*>&, const std::string&);
 
 bool StartsWith(const std::string& s, const char* prefix) {
-  return s.compare(0, strlen(prefix), prefix) == 0;
+  return strncmp(s.c_str(), prefix, strlen(prefix)) == 0;
 }
 
-bool EndsWith(const std::string& s, const char* suffix) {
+bool StartsWithIgnoreCase(const std::string& s, const char* prefix) {
+  return strncasecmp(s.c_str(), prefix, strlen(prefix)) == 0;
+}
+
+static bool EndsWith(const std::string& s, const char* suffix, bool case_sensitive) {
   size_t suffix_length = strlen(suffix);
   size_t string_length = s.size();
   if (suffix_length > string_length) {
     return false;
   }
   size_t offset = string_length - suffix_length;
-  return s.compare(offset, suffix_length, suffix) == 0;
+  return (case_sensitive ? strncmp : strncasecmp)(s.c_str() + offset, suffix, suffix_length) == 0;
+}
+
+bool EndsWith(const std::string& s, const char* suffix) {
+  return EndsWith(s, suffix, true);
+}
+
+bool EndsWithIgnoreCase(const std::string& s, const char* suffix) {
+  return EndsWith(s, suffix, false);
 }
 
 }  // namespace base
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
index 30ae29e..5fb21dd 100644
--- a/base/strings_test.cpp
+++ b/base/strings_test.cpp
@@ -134,44 +134,113 @@
               "2,1" == android::base::Join(list, ','));
 }
 
-TEST(strings, startswith_empty) {
+TEST(strings, StartsWith_empty) {
   ASSERT_FALSE(android::base::StartsWith("", "foo"));
   ASSERT_TRUE(android::base::StartsWith("", ""));
 }
 
-TEST(strings, startswith_simple) {
+TEST(strings, StartsWithIgnoreCase_empty) {
+  ASSERT_FALSE(android::base::StartsWithIgnoreCase("", "foo"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("", ""));
+}
+
+TEST(strings, StartsWith_simple) {
   ASSERT_TRUE(android::base::StartsWith("foo", ""));
   ASSERT_TRUE(android::base::StartsWith("foo", "f"));
   ASSERT_TRUE(android::base::StartsWith("foo", "fo"));
   ASSERT_TRUE(android::base::StartsWith("foo", "foo"));
 }
 
-TEST(strings, startswith_prefix_too_long) {
+TEST(strings, StartsWithIgnoreCase_simple) {
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", ""));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "f"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "F"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fo"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fO"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "Fo"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FO"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "foo"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "foO"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fOo"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fOO"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "Foo"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FoO"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FOo"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FOO"));
+}
+
+TEST(strings, StartsWith_prefix_too_long) {
   ASSERT_FALSE(android::base::StartsWith("foo", "foobar"));
 }
 
-TEST(strings, startswith_contains_prefix) {
+TEST(strings, StartsWithIgnoreCase_prefix_too_long) {
+  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foo", "foobar"));
+  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foo", "FOOBAR"));
+}
+
+TEST(strings, StartsWith_contains_prefix) {
   ASSERT_FALSE(android::base::StartsWith("foobar", "oba"));
   ASSERT_FALSE(android::base::StartsWith("foobar", "bar"));
 }
 
-TEST(strings, endswith_empty) {
+TEST(strings, StartsWithIgnoreCase_contains_prefix) {
+  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "oba"));
+  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "OBA"));
+  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "bar"));
+  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "BAR"));
+}
+
+TEST(strings, EndsWith_empty) {
   ASSERT_FALSE(android::base::EndsWith("", "foo"));
   ASSERT_TRUE(android::base::EndsWith("", ""));
 }
 
-TEST(strings, endswith_simple) {
+TEST(strings, EndsWithIgnoreCase_empty) {
+  ASSERT_FALSE(android::base::EndsWithIgnoreCase("", "foo"));
+  ASSERT_FALSE(android::base::EndsWithIgnoreCase("", "FOO"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("", ""));
+}
+
+TEST(strings, EndsWith_simple) {
   ASSERT_TRUE(android::base::EndsWith("foo", ""));
   ASSERT_TRUE(android::base::EndsWith("foo", "o"));
   ASSERT_TRUE(android::base::EndsWith("foo", "oo"));
   ASSERT_TRUE(android::base::EndsWith("foo", "foo"));
 }
 
-TEST(strings, endswith_prefix_too_long) {
+TEST(strings, EndsWithIgnoreCase_simple) {
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", ""));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "o"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "O"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "oo"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "oO"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "Oo"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "OO"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "foo"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "foO"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "fOo"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "fOO"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "Foo"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "FoO"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "FOo"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "FOO"));
+}
+
+TEST(strings, EndsWith_prefix_too_long) {
   ASSERT_FALSE(android::base::EndsWith("foo", "foobar"));
 }
 
-TEST(strings, endswith_contains_prefix) {
+TEST(strings, EndsWithIgnoreCase_prefix_too_long) {
+  ASSERT_FALSE(android::base::EndsWithIgnoreCase("foo", "foobar"));
+  ASSERT_FALSE(android::base::EndsWithIgnoreCase("foo", "FOOBAR"));
+}
+
+TEST(strings, EndsWith_contains_prefix) {
   ASSERT_FALSE(android::base::EndsWith("foobar", "oba"));
   ASSERT_FALSE(android::base::EndsWith("foobar", "foo"));
 }
+
+TEST(strings, EndsWithIgnoreCase_contains_prefix) {
+  ASSERT_FALSE(android::base::EndsWithIgnoreCase("foobar", "OBA"));
+  ASSERT_FALSE(android::base::EndsWithIgnoreCase("foobar", "FOO"));
+}
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
index 337ba7c..3b3d698 100644
--- a/base/test_utils.cpp
+++ b/base/test_utils.cpp
@@ -16,7 +16,6 @@
 
 #include "android-base/logging.h"
 #include "android-base/test_utils.h"
-#include "utils/Compat.h" // For OS_PATH_SEPARATOR.
 
 #include <fcntl.h>
 #include <stdio.h>
@@ -27,6 +26,9 @@
 #if defined(_WIN32)
 #include <windows.h>
 #include <direct.h>
+#define OS_PATH_SEPARATOR '\\'
+#else
+#define OS_PATH_SEPARATOR '/'
 #endif
 
 #include <string>
@@ -100,3 +102,32 @@
            OS_PATH_SEPARATOR);
   return (mkdtemp(path) != nullptr);
 }
+
+CapturedStderr::CapturedStderr() : old_stderr_(-1) {
+  init();
+}
+
+CapturedStderr::~CapturedStderr() {
+  reset();
+}
+
+int CapturedStderr::fd() const {
+  return temp_file_.fd;
+}
+
+void CapturedStderr::init() {
+#if defined(_WIN32)
+  // On Windows, stderr is often buffered, so make sure it is unbuffered so
+  // that we can immediately read back what was written to stderr.
+  CHECK_EQ(0, setvbuf(stderr, NULL, _IONBF, 0));
+#endif
+  old_stderr_ = dup(STDERR_FILENO);
+  CHECK_NE(-1, old_stderr_);
+  CHECK_NE(-1, dup2(fd(), STDERR_FILENO));
+}
+
+void CapturedStderr::reset() {
+  CHECK_NE(-1, dup2(old_stderr_, STDERR_FILENO));
+  CHECK_EQ(0, close(old_stderr_));
+  // Note: cannot restore prior setvbuf() setting.
+}
diff --git a/bootstat/Android.bp b/bootstat/Android.bp
new file mode 100644
index 0000000..d98a9d7
--- /dev/null
+++ b/bootstat/Android.bp
@@ -0,0 +1,92 @@
+//
+// 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.
+//
+
+bootstat_lib_src_files = [
+    "boot_event_record_store.cpp",
+    "histogram_logger.cpp",
+    "uptime_parser.cpp",
+]
+
+cc_defaults {
+    name: "bootstat_defaults",
+
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+
+        // 524291 corresponds to sysui_histogram, from
+        // frameworks/base/core/java/com/android/internal/logging/EventLogTags.logtags
+        "-DHISTOGRAM_LOG_TAG=524291",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+    ],
+    whole_static_libs: ["libgtest_prod"],
+    // Clang is required because of C++14
+    clang: true,
+}
+
+// bootstat static library
+// -----------------------------------------------------------------------------
+cc_library_static {
+    name: "libbootstat",
+    defaults: ["bootstat_defaults"],
+    srcs: bootstat_lib_src_files,
+}
+
+// bootstat static library, debug
+// -----------------------------------------------------------------------------
+cc_library_static {
+    name: "libbootstat_debug",
+    defaults: ["bootstat_defaults"],
+    host_supported: true,
+    srcs: bootstat_lib_src_files,
+
+    target: {
+        host: {
+            cflags: ["-UNDEBUG"],
+        },
+    },
+}
+
+// bootstat binary
+// -----------------------------------------------------------------------------
+cc_binary {
+    name: "bootstat",
+    defaults: ["bootstat_defaults"],
+    static_libs: ["libbootstat"],
+    init_rc: ["bootstat.rc"],
+    srcs: ["bootstat.cpp"],
+}
+
+// Native tests
+// -----------------------------------------------------------------------------
+cc_test {
+    name: "bootstat_tests",
+    defaults: ["bootstat_defaults"],
+    host_supported: true,
+    static_libs: [
+        "libbootstat_debug",
+        "libgmock",
+    ],
+    srcs: [
+        "boot_event_record_store_test.cpp",
+        "testrunner.cpp",
+    ],
+}
diff --git a/bootstat/Android.mk b/bootstat/Android.mk
deleted file mode 100644
index 6300941..0000000
--- a/bootstat/Android.mk
+++ /dev/null
@@ -1,143 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-bootstat_c_includes := external/gtest/include
-
-bootstat_lib_src_files := \
-        boot_event_record_store.cpp \
-        event_log_list_builder.cpp \
-        histogram_logger.cpp \
-        uptime_parser.cpp \
-
-bootstat_src_files := \
-        bootstat.cpp \
-
-bootstat_test_src_files := \
-        boot_event_record_store_test.cpp \
-        event_log_list_builder_test.cpp \
-        testrunner.cpp \
-
-bootstat_shared_libs := \
-        libbase \
-        libcutils \
-        liblog \
-
-bootstat_cflags := \
-        -Wall \
-        -Wextra \
-        -Werror \
-
-# 524291 corresponds to sysui_histogram, from
-# frameworks/base/core/java/com/android/internal/logging/EventLogTags.logtags
-bootstat_cflags += -DHISTOGRAM_LOG_TAG=524291
-
-bootstat_debug_cflags := \
-        $(bootstat_cflags) \
-        -UNDEBUG \
-
-# bootstat static library
-# -----------------------------------------------------------------------------
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libbootstat
-LOCAL_CFLAGS := $(bootstat_cflags)
-LOCAL_C_INCLUDES := $(bootstat_c_includes)
-LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
-LOCAL_SRC_FILES := $(bootstat_lib_src_files)
-# Clang is required because of C++14
-LOCAL_CLANG := true
-
-include $(BUILD_STATIC_LIBRARY)
-
-# bootstat static library, debug
-# -----------------------------------------------------------------------------
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libbootstat_debug
-LOCAL_CFLAGS := $(bootstat_cflags)
-LOCAL_C_INCLUDES := $(bootstat_c_includes)
-LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
-LOCAL_SRC_FILES := $(bootstat_lib_src_files)
-# Clang is required because of C++14
-LOCAL_CLANG := true
-
-include $(BUILD_STATIC_LIBRARY)
-
-# bootstat host static library, debug
-# -----------------------------------------------------------------------------
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libbootstat_host_debug
-LOCAL_CFLAGS := $(bootstat_debug_cflags)
-LOCAL_C_INCLUDES := $(bootstat_c_includes)
-LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
-LOCAL_SRC_FILES := $(bootstat_lib_src_files)
-# Clang is required because of C++14
-LOCAL_CLANG := true
-
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-# bootstat binary
-# -----------------------------------------------------------------------------
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := bootstat
-LOCAL_CFLAGS := $(bootstat_cflags)
-LOCAL_C_INCLUDES := $(bootstat_c_includes)
-LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
-LOCAL_STATIC_LIBRARIES := libbootstat
-LOCAL_INIT_RC := bootstat.rc
-LOCAL_SRC_FILES := $(bootstat_src_files)
-# Clang is required because of C++14
-LOCAL_CLANG := true
-
-include $(BUILD_EXECUTABLE)
-
-# Native tests
-# -----------------------------------------------------------------------------
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := bootstat_tests
-LOCAL_CFLAGS := $(bootstat_tests_cflags)
-LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
-LOCAL_STATIC_LIBRARIES := libbootstat_debug libgmock
-LOCAL_SRC_FILES := $(bootstat_test_src_files)
-# Clang is required because of C++14
-LOCAL_CLANG := true
-
-include $(BUILD_NATIVE_TEST)
-
-# Host native tests
-# -----------------------------------------------------------------------------
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := bootstat_tests
-LOCAL_CFLAGS := $(bootstat_tests_cflags)
-LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
-LOCAL_STATIC_LIBRARIES := libbootstat_host_debug libgmock_host
-LOCAL_SRC_FILES := $(bootstat_test_src_files)
-# Clang is required because of C++14
-LOCAL_CLANG := true
-
-include $(BUILD_HOST_NATIVE_TEST)
diff --git a/bootstat/boot_event_record_store.cpp b/bootstat/boot_event_record_store.cpp
index 346eada..78be944 100644
--- a/bootstat/boot_event_record_store.cpp
+++ b/bootstat/boot_event_record_store.cpp
@@ -59,7 +59,7 @@
   // Ignore existing bootstat records (which do not contain file content).
   if (!content.empty()) {
     int32_t value;
-    if (android::base::ParseInt(content.c_str(), &value)) {
+    if (android::base::ParseInt(content, &value)) {
       bootstat::LogHistogram("bootstat_mtime_matches_content", value == *uptime);
     }
   }
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index d547c19..7c0e85d 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -20,6 +20,7 @@
 
 #include <getopt.h>
 #include <unistd.h>
+
 #include <cmath>
 #include <cstddef>
 #include <cstdio>
@@ -27,12 +28,13 @@
 #include <map>
 #include <memory>
 #include <string>
+
+#include <android/log.h>
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
 #include <cutils/properties.h>
-#include <log/log.h>
+
 #include "boot_event_record_store.h"
-#include "event_log_list_builder.h"
 #include "histogram_logger.h"
 #include "uptime_parser.h"
 
@@ -49,6 +51,22 @@
   }
 }
 
+// Records the named boot |event| to the record store. If |value| is non-empty
+// and is a proper string representation of an integer value, the converted
+// integer value is associated with the boot event.
+void RecordBootEventFromCommandLine(
+    const std::string& event, const std::string& value_str) {
+  BootEventRecordStore boot_event_store;
+  if (!value_str.empty()) {
+    int32_t value = 0;
+    if (android::base::ParseInt(value_str, &value)) {
+      boot_event_store.AddBootEventWithValue(event, value);
+    }
+  } else {
+    boot_event_store.AddBootEvent(event);
+  }
+}
+
 void PrintBootEvents() {
   printf("Boot events:\n");
   printf("------------\n");
@@ -68,6 +86,7 @@
           "  -l, --log             Log all metrics to logstorage\n"
           "  -p, --print           Dump the boot event records to the console\n"
           "  -r, --record          Record the timestamp of a named boot event\n"
+          "  --value               Optional value to associate with the boot event\n"
           "  --record_boot_reason  Record the reason why the device booted\n"
           "  --record_time_since_factory_reset Record the time since the device was reset\n");
 }
@@ -122,6 +141,30 @@
   {"Reboot", 18},
   {"rtc", 19},
   {"edl", 20},
+  {"oem_pon1", 21},
+  {"oem_powerkey", 22},
+  {"oem_unknown_reset", 23},
+  {"srto: HWWDT reset SC", 24},
+  {"srto: HWWDT reset platform", 25},
+  {"srto: bootloader", 26},
+  {"srto: kernel panic", 27},
+  {"srto: kernel watchdog reset", 28},
+  {"srto: normal", 29},
+  {"srto: reboot", 30},
+  {"srto: reboot-bootloader", 31},
+  {"srto: security watchdog reset", 32},
+  {"srto: wakesrc", 33},
+  {"srto: watchdog", 34},
+  {"srto:1-1", 35},
+  {"srto:omap_hsmm", 36},
+  {"srto:phy0", 37},
+  {"srto:rtc0", 38},
+  {"srto:touchpad", 39},
+  {"watchdog", 40},
+  {"watchdogr", 41},
+  {"wdog_bark", 42},
+  {"wdog_bite", 43},
+  {"wdog_reset", 44},
 };
 
 // Converts a string value representing the reason the system booted to an
@@ -149,7 +192,7 @@
 
   std::string build_date_str = GetProperty("ro.build.date.utc");
   int32_t build_date;
-  if (!android::base::ParseInt(build_date_str.c_str(), &build_date)) {
+  if (!android::base::ParseInt(build_date_str, &build_date)) {
     return std::string();
   }
 
@@ -286,6 +329,7 @@
   LOG(INFO) << "Service started: " << cmd_line;
 
   int option_index = 0;
+  static const char value_str[] = "value";
   static const char boot_complete_str[] = "record_boot_complete";
   static const char boot_reason_str[] = "record_boot_reason";
   static const char factory_reset_str[] = "record_time_since_factory_reset";
@@ -294,19 +338,26 @@
     { "log",             no_argument,       NULL,   'l' },
     { "print",           no_argument,       NULL,   'p' },
     { "record",          required_argument, NULL,   'r' },
+    { value_str,         required_argument, NULL,   0 },
     { boot_complete_str, no_argument,       NULL,   0 },
     { boot_reason_str,   no_argument,       NULL,   0 },
     { factory_reset_str, no_argument,       NULL,   0 },
     { NULL,              0,                 NULL,   0 }
   };
 
+  std::string boot_event;
+  std::string value;
   int opt = 0;
   while ((opt = getopt_long(argc, argv, "hlpr:", long_options, &option_index)) != -1) {
     switch (opt) {
       // This case handles long options which have no single-character mapping.
       case 0: {
         const std::string option_name = long_options[option_index].name;
-        if (option_name == boot_complete_str) {
+        if (option_name == value_str) {
+          // |optarg| is an external variable set by getopt representing
+          // the option argument.
+          value = optarg;
+        } else if (option_name == boot_complete_str) {
           RecordBootComplete();
         } else if (option_name == boot_reason_str) {
           RecordBootReason();
@@ -336,10 +387,7 @@
       case 'r': {
         // |optarg| is an external variable set by getopt representing
         // the option argument.
-        const char* event = optarg;
-
-        BootEventRecordStore boot_event_store;
-        boot_event_store.AddBootEvent(event);
+        boot_event = optarg;
         break;
       }
 
@@ -355,5 +403,9 @@
     }
   }
 
+  if (!boot_event.empty()) {
+    RecordBootEventFromCommandLine(boot_event, value);
+  }
+
   return 0;
 }
diff --git a/bootstat/event_log_list_builder.cpp b/bootstat/event_log_list_builder.cpp
deleted file mode 100644
index 241e3d5..0000000
--- a/bootstat/event_log_list_builder.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * 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 "event_log_list_builder.h"
-
-#include <cinttypes>
-#include <memory>
-#include <string>
-#include <android-base/logging.h>
-#include <log/log.h>
-
-namespace {
-
-const size_t MAX_EVENT_PAYLOAD_SIZE = 512 - 1;  // Leave room for final '\n'.
-const size_t EVENT_TYPE_SIZE = 1;  // Size in bytes of the event type marker.
-
-}  // namespace
-
-EventLogListBuilder::EventLogListBuilder()
-    : payload_count_(0),
-      payload_size_(0),
-      payload_(std::make_unique<uint8_t[]>(MAX_EVENT_PAYLOAD_SIZE)) {
-  memset(payload_.get(), 0, MAX_EVENT_PAYLOAD_SIZE);
-
-  // Set up the top-level EventLog data type.
-  AppendByte(EVENT_TYPE_LIST);
-
-  // Skip over the byte prepresenting the number of items in the list. This
-  // value is set in Release().
-  payload_size_++;
-}
-
-bool EventLogListBuilder::Append(int value) {
-  DCHECK_NE(static_cast<uint8_t*>(nullptr), payload_.get());
-
-  if (!IsSpaceAvailable(sizeof(value) + EVENT_TYPE_SIZE)) {
-    return false;
-  }
-
-  AppendByte(EVENT_TYPE_INT);
-  AppendData(&value, sizeof(value));
-
-  payload_count_++;
-  return true;
-}
-
-bool EventLogListBuilder::Append(const std::string& value) {
-  DCHECK_NE(static_cast<uint8_t*>(nullptr), payload_.get());
-
-  int len = value.length();
-  if (!IsSpaceAvailable(sizeof(len) + len)) {
-    return false;
-  }
-
-  AppendByte(EVENT_TYPE_STRING);
-  AppendData(&len, sizeof(len));
-  AppendData(value.c_str(), len);
-
-  payload_count_++;
-  return true;
-}
-
-void EventLogListBuilder::Release(std::unique_ptr<uint8_t[]>* log,
-                                  size_t* size) {
-  // Finalize the log payload.
-  payload_[1] = payload_count_;
-
-  // Return the log payload.
-  *size = payload_size_;
-  *log = std::move(payload_);
-}
-
-void EventLogListBuilder::AppendData(const void* data, size_t size) {
-  DCHECK_LT(payload_size_ + size, MAX_EVENT_PAYLOAD_SIZE);
-  memcpy(&payload_[payload_size_], data, size);
-  payload_size_ += size;
-}
-
-void EventLogListBuilder::AppendByte(uint8_t byte) {
-  DCHECK_LT(payload_size_ + sizeof(byte), MAX_EVENT_PAYLOAD_SIZE);
-  payload_[payload_size_++] = byte;
-}
-
-bool EventLogListBuilder::IsSpaceAvailable(size_t value_size) {
-  size_t space_needed = value_size + EVENT_TYPE_SIZE;
-  if (payload_size_ + space_needed > MAX_EVENT_PAYLOAD_SIZE) {
-    size_t remaining = MAX_EVENT_PAYLOAD_SIZE - payload_size_;
-    LOG(WARNING) << "Not enough space for value. remain=" <<
-        remaining << "; needed=" << space_needed;
-    return false;
-  }
-
-  return true;
-}
diff --git a/bootstat/event_log_list_builder.h b/bootstat/event_log_list_builder.h
deleted file mode 100644
index 4e29b01..0000000
--- a/bootstat/event_log_list_builder.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef EVENT_LOG_LIST_BUILDER_H_
-#define EVENT_LOG_LIST_BUILDER_H_
-
-#include <cstdint>
-#include <memory>
-
-#include <android-base/macros.h>
-
-// EventLogListBuilder provides a mechanism to build an EventLog list
-// consisting of int and string EventLog values.
-//
-// NOTE: This class does not provide the ability to append an embedded list,
-// i.e., a list containing a list.
-class EventLogListBuilder {
- public:
-  EventLogListBuilder();
-
-  // Append a single value of a specified type.
-  bool Append(int value);
-  bool Append(const std::string& value);
-
-  // Finalizes construction of the EventLog list and releases the data
-  // to the caller. Caller takes ownership of the payload. No further calls
-  // to append* may be made once the payload is acquired by the caller.
-  void Release(std::unique_ptr<uint8_t[]>* log, size_t* size);
-
- private:
-  // Appends |data| of the given |size| to the payload.
-  void AppendData(const void* data, size_t size);
-
-  // Appends a single byte to the payload.
-  void AppendByte(uint8_t byte);
-
-  // Returns true iff the remaining capacity in |payload_| is large enough to
-  // accommodate |value_size| bytes. The space required to log the event type
-  // is included in the internal calculation so must not be passed in to
-  // |value_size|.
-  bool IsSpaceAvailable(size_t value_size);
-
-  // The number of items in the EventLog list.
-  size_t payload_count_;
-
-  // The size of the data stored in |payload_|. Used to track where to insert
-  // new data.
-  size_t payload_size_;
-
-  // The payload constructed by calls to log*. The payload may only contain
-  // MAX_EVENT_PAYLOAD (512) bytes.
-  std::unique_ptr<uint8_t[]> payload_;
-
-  DISALLOW_COPY_AND_ASSIGN(EventLogListBuilder);
-};
-
- #endif  // EVENT_LOG_LIST_BUILDER_H_
diff --git a/bootstat/event_log_list_builder_test.cpp b/bootstat/event_log_list_builder_test.cpp
deleted file mode 100644
index affb4bf..0000000
--- a/bootstat/event_log_list_builder_test.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * 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 "event_log_list_builder.h"
-
-#include <inttypes.h>
-#include <gtest/gtest.h>
-#include <gmock/gmock.h>
-#include <log/log.h>
-
-using testing::ElementsAreArray;
-
-TEST(EventLogListBuilder, Empty) {
-  EventLogListBuilder builder;
-
-  const uint8_t EXPECTED_LOG[] = {
-    EVENT_TYPE_LIST,
-    0,  // Number of items in the list.
-  };
-
-  std::unique_ptr<uint8_t[]> log;
-  size_t size;
-  builder.Release(&log, &size);
-  EXPECT_EQ(2U, size);
-
-  uint8_t* log_data = log.get();
-  EXPECT_THAT(std::vector<uint8_t>(log_data, log_data + size),
-              ElementsAreArray(EXPECTED_LOG));
-}
-
-TEST(EventLogListBuilder, SingleInt) {
-  EventLogListBuilder builder;
-
-  const uint8_t EXPECTED_LOG[] = {
-    EVENT_TYPE_LIST,
-    1,                // Number of items in the list.
-    EVENT_TYPE_INT,
-    42, 0, 0, 0,      // 4 byte integer value.
-  };
-
-  builder.Append(42);
-
-  std::unique_ptr<uint8_t[]> log;
-  size_t size;
-  builder.Release(&log, &size);
-  EXPECT_EQ(7U, size);
-
-  uint8_t* log_data = log.get();
-  EXPECT_THAT(std::vector<uint8_t>(log_data, log_data + size),
-              ElementsAreArray(EXPECTED_LOG));
-}
-
-TEST(EventLogListBuilder, SingleString) {
-  EventLogListBuilder builder;
-
-  const uint8_t EXPECTED_LOG[] = {
-    EVENT_TYPE_LIST,
-    1,                        // Number of items in the list.
-    EVENT_TYPE_STRING,
-    5, 0, 0, 0,               // 4 byte length of the string.
-    'D', 'r', 'o', 'i', 'd',
-  };
-
-  builder.Append("Droid");
-
-  std::unique_ptr<uint8_t[]> log;
-  size_t size;
-  builder.Release(&log, &size);
-  EXPECT_EQ(12U, size);
-
-  uint8_t* log_data = log.get();
-  EXPECT_THAT(std::vector<uint8_t>(log_data, log_data + size),
-              ElementsAreArray(EXPECTED_LOG));
-}
-
-TEST(EventLogListBuilder, IntThenString) {
-  EventLogListBuilder builder;
-
-  const uint8_t EXPECTED_LOG[] = {
-    EVENT_TYPE_LIST,
-    2,                        // Number of items in the list.
-    EVENT_TYPE_INT,
-    42, 0, 0, 0,              // 4 byte integer value.
-    EVENT_TYPE_STRING,
-    5, 0, 0, 0,               // 4 byte length of the string.
-    'D', 'r', 'o', 'i', 'd',
-  };
-
-  builder.Append(42);
-  builder.Append("Droid");
-
-  std::unique_ptr<uint8_t[]> log;
-  size_t size;
-  builder.Release(&log, &size);
-  EXPECT_EQ(17U, size);
-
-  uint8_t* log_data = log.get();
-  EXPECT_THAT(std::vector<uint8_t>(log_data, log_data + size),
-              ElementsAreArray(EXPECTED_LOG));
-}
diff --git a/bootstat/histogram_logger.cpp b/bootstat/histogram_logger.cpp
index e3aad28..73f3295 100644
--- a/bootstat/histogram_logger.cpp
+++ b/bootstat/histogram_logger.cpp
@@ -17,25 +17,16 @@
 #include "histogram_logger.h"
 
 #include <cstdlib>
-#include <memory>
+
 #include <android-base/logging.h>
-#include <log/log.h>
-#include "event_log_list_builder.h"
+#include <log/log_event_list.h>
 
 namespace bootstat {
 
 void LogHistogram(const std::string& event, int32_t data) {
   LOG(INFO) << "Logging histogram: " << event << " " << data;
-
-  EventLogListBuilder log_builder;
-  log_builder.Append(event);
-  log_builder.Append(data);
-
-  std::unique_ptr<uint8_t[]> log;
-  size_t size;
-  log_builder.Release(&log, &size);
-
-  android_bWriteLog(HISTOGRAM_LOG_TAG, log.get(), size);
+  android_log_event_list log(HISTOGRAM_LOG_TAG);
+  log << event << data << LOG_ID_EVENTS;
 }
 
-}  // namespace bootstat
\ No newline at end of file
+}  // namespace bootstat
diff --git a/cpio/mkbootfs.c b/cpio/mkbootfs.c
index 0e35323..b89c395 100644
--- a/cpio/mkbootfs.c
+++ b/cpio/mkbootfs.c
@@ -51,6 +51,8 @@
 #define CANNED_LINE_LENGTH  (1024)
 #endif
 
+#define TRAILER "TRAILER!!!"
+
 static int verbose = 0;
 static int total_size = 0;
 
@@ -80,8 +82,8 @@
     } else {
         // Use the compiled-in fs_config() function.
         unsigned st_mode = s->st_mode;
-        fs_config(path, S_ISDIR(s->st_mode), target_out_path,
-                       &s->st_uid, &s->st_gid, &st_mode, &capabilities);
+        int is_dir = S_ISDIR(s->st_mode) || strcmp(path, TRAILER) == 0;
+        fs_config(path, is_dir, target_out_path, &s->st_uid, &s->st_gid, &st_mode, &capabilities);
         s->st_mode = (typeof(s->st_mode)) st_mode;
     }
 }
@@ -140,7 +142,7 @@
 {
     struct stat s;
     memset(&s, 0, sizeof(s));
-    _eject(&s, "TRAILER!!!", 10, 0, 0);
+    _eject(&s, TRAILER, 10, 0, 0);
 
     while(total_size & 0xff) {
         total_size++;
diff --git a/crash_reporter/.project_alias b/crash_reporter/.project_alias
deleted file mode 100644
index 0bc3798..0000000
--- a/crash_reporter/.project_alias
+++ /dev/null
@@ -1 +0,0 @@
-crash
diff --git a/crash_reporter/99-crash-reporter.rules b/crash_reporter/99-crash-reporter.rules
deleted file mode 100644
index aea5b1c..0000000
--- a/crash_reporter/99-crash-reporter.rules
+++ /dev/null
@@ -1,6 +0,0 @@
-ACTION=="change", SUBSYSTEM=="drm", KERNEL=="card0", ENV{ERROR}=="1", RUN+="/sbin/crash_reporter --udev=KERNEL=card0:SUBSYSTEM=drm:ACTION=change"
-# For detecting cypress trackpad issue. Passing into crash_reporter SUBSYSTEM=i2c-cyapa since crash_reporter does not handle DRIVER string.
-ACTION=="change", SUBSYSTEM=="i2c", DRIVER=="cyapa", ENV{ERROR}=="1", RUN+="/sbin/crash_reporter --udev=SUBSYSTEM=i2c-cyapa:ACTION=change"
-# For detecting Atmel trackpad/touchscreen issue. Passing into crash_reporter SUBSYSTEM=i2c-atmel_mxt_ts since crash_reporter does not handle DRIVER string.
-ACTION=="change", SUBSYSTEM=="i2c", DRIVER=="atmel_mxt_ts", ENV{ERROR}=="1", RUN+="/sbin/crash_reporter --udev=SUBSYSTEM=i2c-atmel_mxt_ts:ACTION=change"
-ACTION=="add", SUBSYSTEM=="devcoredump", RUN+="/sbin/crash_reporter --udev=SUBSYSTEM=devcoredump:ACTION=add:KERNEL_NUMBER=%n"
diff --git a/crash_reporter/Android.mk b/crash_reporter/Android.mk
deleted file mode 100644
index ce9dc73..0000000
--- a/crash_reporter/Android.mk
+++ /dev/null
@@ -1,147 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-crash_reporter_cpp_extension := .cc
-
-crash_reporter_src := crash_collector.cc \
-    kernel_collector.cc \
-    kernel_warning_collector.cc \
-    unclean_shutdown_collector.cc \
-    user_collector.cc
-
-crash_reporter_includes := external/gtest/include
-
-crash_reporter_test_src := crash_collector_test.cc \
-    crash_reporter_logs_test.cc \
-    kernel_collector_test.cc \
-    testrunner.cc \
-    unclean_shutdown_collector_test.cc \
-    user_collector_test.cc
-
-warn_collector_src := warn_collector.l
-
-# Crash reporter static library.
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := libcrash
-LOCAL_CPP_EXTENSION := $(crash_reporter_cpp_extension)
-LOCAL_C_INCLUDES := $(crash_reporter_includes)
-LOCAL_SHARED_LIBRARIES := libchrome \
-    libbinder \
-    libbrillo \
-    libcutils \
-    libmetrics \
-    libpcrecpp
-LOCAL_STATIC_LIBRARIES := libmetricscollectorservice
-LOCAL_SRC_FILES := $(crash_reporter_src)
-include $(BUILD_STATIC_LIBRARY)
-
-# Crash reporter client.
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := crash_reporter
-LOCAL_CPP_EXTENSION := $(crash_reporter_cpp_extension)
-LOCAL_C_INCLUDES := $(crash_reporter_includes)
-LOCAL_REQUIRED_MODULES := core2md \
-    crash_reporter_logs.conf \
-    crash_sender \
-    crash_server
-LOCAL_INIT_RC := crash_reporter.rc
-LOCAL_SHARED_LIBRARIES := libchrome \
-    libbinder \
-    libbrillo \
-    libcutils \
-    libmetrics \
-    libpcrecpp \
-    libutils
-LOCAL_SRC_FILES := crash_reporter.cc
-LOCAL_STATIC_LIBRARIES := libcrash \
-    libmetricscollectorservice
-include $(BUILD_EXECUTABLE)
-
-# Crash sender script.
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := crash_sender
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)
-LOCAL_REQUIRED_MODULES := curl grep periodic_scheduler
-LOCAL_SRC_FILES := crash_sender
-include $(BUILD_PREBUILT)
-
-# Warn collector client.
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := warn_collector
-LOCAL_CPP_EXTENSION := $(crash_reporter_cpp_extension)
-LOCAL_SHARED_LIBRARIES := libmetrics
-LOCAL_SRC_FILES := $(warn_collector_src)
-include $(BUILD_EXECUTABLE)
-
-# /etc/os-release.d/crash_server configuration file.
-# ========================================================
-ifdef OSRELEASED_DIRECTORY
-include $(CLEAR_VARS)
-LOCAL_MODULE := crash_server
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/$(OSRELEASED_DIRECTORY)
-include $(BUILD_SYSTEM)/base_rules.mk
-
-# Optionally populate the BRILLO_CRASH_SERVER variable from a product
-# configuration file: brillo/crash_server.
-LOADED_BRILLO_CRASH_SERVER := $(call cfgtree-get-if-exists,brillo/crash_server)
-
-# If the crash server isn't set, use a blank value.  crash_sender
-# will log it as a configuration error.
-$(LOCAL_BUILT_MODULE): BRILLO_CRASH_SERVER ?= "$(LOADED_BRILLO_CRASH_SERVER)"
-$(LOCAL_BUILT_MODULE):
-	$(hide)mkdir -p $(dir $@)
-	echo $(BRILLO_CRASH_SERVER) > $@
-endif
-
-# Crash reporter logs conf file.
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := crash_reporter_logs.conf
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/etc
-LOCAL_SRC_FILES := crash_reporter_logs.conf
-include $(BUILD_PREBUILT)
-
-# Periodic Scheduler.
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := periodic_scheduler
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)
-LOCAL_SRC_FILES := periodic_scheduler
-include $(BUILD_PREBUILT)
-
-# Crash reporter tests.
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := crash_reporter_tests
-LOCAL_CPP_EXTENSION := $(crash_reporter_cpp_extension)
-ifdef BRILLO
-LOCAL_MODULE_TAGS := eng
-endif
-LOCAL_SHARED_LIBRARIES := libchrome \
-    libbrillo \
-    libcutils \
-    libpcrecpp
-LOCAL_SRC_FILES := $(crash_reporter_test_src)
-LOCAL_STATIC_LIBRARIES := libcrash libgmock
-include $(BUILD_NATIVE_TEST)
diff --git a/crash_reporter/OWNERS b/crash_reporter/OWNERS
deleted file mode 100644
index 96ea5b2..0000000
--- a/crash_reporter/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-set noparent
-vapier@chromium.org
diff --git a/crash_reporter/README.md b/crash_reporter/README.md
deleted file mode 100644
index 9ac0a86..0000000
--- a/crash_reporter/README.md
+++ /dev/null
@@ -1,61 +0,0 @@
-# crash_reporter
-
-`crash_reporter` is a deamon running on the device that saves the call stack of
-crashing programs. It makes use of the
-[Breakpad](https://chromium.googlesource.com/breakpad/breakpad/) library.
-
-During a build, Breakpad symbol files are generated for all binaries.  They are
-packaged into a zip file when running `m dist`, so that a developer can upload
-them to the crash server.
-
-On a device, if the user has opted in to metrics and crash reporting, a
-Breakpad minidump is generated when an executable crashes, which is then
-uploaded to the crash server.
-
-On the crash server, it compares the minidump's signature to the symbol files
-that the developer has uploaded, and extracts and symbolizes the stack trace
-from the minidump.
-
-## SELinux policies
-
-In order to correctly generate a minidump, `crash_reporter` needs to be given
-the proper SELinux permissions for accessing the domain of the crashing
-executable.  By default, `crash_reporter` has only been given access to a select
-number of system domains, such as `metricsd`, `weave`, and `update_engine`.  If
-a developer wants their executable's crashes to be caught by `crash_reporter`,
-they will have to set their SELinux policies in their .te file to allow
-`crash_reporter` access to their domain.  This can be done through a simple
-[macro](https://android.googlesource.com/device/generic/brillo/+/master/sepolicy/te_macros):
-
-    allow_crash_reporter(domain_name)
-
-Replace *domain_name* with whatever domain is assigned to the executable in
-the `file_contexts` file.
-
-## Configuration
-
-`crash_reporter` has a few different configuration options that have to be set.
-
-- Crashes are only handled and uploaded if analytics reporting is enabled,
-  either via the weave call to set `_metrics.enableAnalyticsReporting` or by
-  manually creating the file `/data/misc/metrics/enabled` (for testing only).
-- The `BRILLO_CRASH_SERVER` make variable should be set in the `product.mk`
-  file to the URL of the crash server.  For Brillo builds, it is set
-  automatically through the product configuration.  Setting this variable will
-  populate the `/etc/os-release.d/crash_server` file on the device, which is
-  read by `crash_sender`.
-- The `BRILLO_PRODUCT_ID` make variable should be set in the `product.mk` file
-  to the product's ID.  For Brillo builds, it is set automatically through the
-  product configuration.  Setting this variable will populate the
-  `/etc/os-release.d/product_id`, which is read by `crash_sender`.
-
-## Uploading crash reports in *eng* builds
-
-By default, crash reports are only uploaded to the server for production
-*user* and *userdebug* images.  In *eng* builds, with crash reporting enabled
-the device will generate minidumps for any crashing executables but will not
-send them to the crash server.  If a developer does want to force an upload,
-they can do so by issuing the command `SECONDS_SEND_SPREAD=5 FORCE_OFFICIAL=1
-crash_sender` from an ADB shell.  This will send the report to the server, with
-the *image_type* field set to *force-official* so that these reports can be
-differentiated from normal reports.
diff --git a/crash_reporter/TEST_WARNING b/crash_reporter/TEST_WARNING
deleted file mode 100644
index 64ad2e9..0000000
--- a/crash_reporter/TEST_WARNING
+++ /dev/null
@@ -1,31 +0,0 @@
-Apr 31 25:25:25 localhost kernel: [117959.226729]  [<ffffffff810e16bf>] do_vfs_ioctl+0x469/0x4b3
-Apr 31 25:25:25 localhost kernel: [117959.226738]  [<ffffffff810d3117>] ? fsnotify_access+0x58/0x60
-Apr 31 25:25:25 localhost kernel: [117959.226747]  [<ffffffff810d3791>] ? vfs_read+0xad/0xd7
-Apr 31 25:25:25 localhost kernel: [117959.226756]  [<ffffffff810e175f>] sys_ioctl+0x56/0x7b
-Apr 31 25:25:25 localhost kernel: [117959.226765]  [<ffffffff810d37fe>] ? sys_read+0x43/0x73
-Apr 31 25:25:25 localhost kernel: [117959.226774]  [<ffffffff8146b7d2>] system_call_fastpath+0x16/0x1b
-Apr 31 25:25:25 localhost kernel: [117959.226782] ---[ end trace f16822cad7406cec ]---
-Apr 31 25:25:25 localhost kernel: [117959.231085] ------------[ cut here ]------------
-Apr 31 25:25:25 localhost kernel: [117959.231100] WARNING: at /mnt/host/source/src/third_party/kernel/files/drivers/gpu/drm/i915/intel_dp.c:351 intel_dp_check_edp+0x6b/0xb9()
-Apr 31 25:25:25 localhost kernel: [117959.231113] Hardware name: Link
-Apr 31 25:25:25 localhost kernel: [117959.231117] eDP powered off while attempting aux channel communication.
-Apr 31 25:25:25 localhost kernel: [117959.231240] Pid: 10508, comm: X Tainted: G        WC   3.4.0 #1
-Apr 31 25:25:25 localhost kernel: [117959.231247] Call Trace:
-Apr 31 25:25:25 localhost kernel: [117959.231393]  [<ffffffff810d3117>] ? fsnotify_access+0x58/0x60
-Apr 31 25:25:25 localhost kernel: [117959.231402]  [<ffffffff810d3791>] ? vfs_read+0xad/0xd7
-Apr 31 25:25:25 localhost kernel: [117959.231411]  [<ffffffff810e175f>] sys_ioctl+0x56/0x7b
-Apr 31 25:25:25 localhost kernel: [117959.231420]  [<ffffffff810d37fe>] ? sys_read+0x43/0x73
-Apr 31 25:25:25 localhost kernel: [117959.231431]  [<ffffffff8146b7d2>] system_call_fastpath+0x16/0x1b
-Apr 31 25:25:25 localhost kernel: [117959.231439] ---[ end trace f16822cad7406ced ]---
-Apr 31 25:25:25 localhost kernel: [117959.231450] ------------[ cut here ]------------
-Apr 31 25:25:25 localhost kernel: [117959.231458] BARNING: at /mnt/host/source/src/third_party/kernel/files/drivers/gpu/drm/i915/intel_dp.c:351 intel_dp_check_edp+0x6b/0xb9()
-Apr 31 25:25:25 localhost kernel: [117959.231458] ("BARNING" above is intentional)
-Apr 31 25:25:25 localhost kernel: [117959.231471] Hardware name: Link
-Apr 31 25:25:25 localhost kernel: [117959.231475] eDP powered off while attempting aux channel communication.
-Apr 31 25:25:25 localhost kernel: [117959.231482] Modules linked in: nls_iso8859_1 nls_cp437 vfat fat rfcomm i2c_dev ath9k_btcoex snd_hda_codec_hdmi snd_hda_codec_ca0132 mac80211 snd_hda_intel ath9k_common_btcoex snd_hda_codec ath9k_hw_btcoex aesni_intel cryptd snd_hwdep ath snd_pcm aes_x86_64 isl29018(C) memconsole snd_timer snd_page_alloc industrialio(C) cfg80211 rtc_cmos nm10_gpio zram(C) zsmalloc(C) lzo_decompress lzo_compress fuse nf_conntrack_ipv6 nf_defrag_ipv6 ip6table_filter ip6_tables xt_mark option usb_wwan cdc_ether usbnet ath3k btusb bluetooth uvcvideo videobuf2_core videodev videobuf2_vmalloc videobuf2_memops joydev
-Apr 31 25:25:25 localhost kernel: [117959.231588] Pid: 10508, comm: X Tainted: G        WC   3.4.0 #1
-Apr 31 25:25:25 localhost kernel: [117959.231595] Call Trace:
-Apr 31 25:25:25 localhost kernel: [117959.231601]  [<ffffffff8102a931>] warn_slowpath_common+0x83/0x9c
-Apr 31 25:25:25 localhost kernel: [117959.231610]  [<ffffffff8102a9ed>] warn_slowpath_fmt+0x46/0x48
-Apr 31 25:25:25 localhost kernel: [117959.231620]  [<ffffffff812af495>] intel_dp_check_edp+0x6b/0xb9
-Apr 31 25:25:25 localhost kernel: [117959.231629]  [<ffffffff8102a9ed>] ? warn_slowpath_fmt+
diff --git a/crash_reporter/crash_collector.cc b/crash_reporter/crash_collector.cc
deleted file mode 100644
index b3fdcb4..0000000
--- a/crash_reporter/crash_collector.cc
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * Copyright (C) 2012 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 "crash_collector.h"
-
-#include <dirent.h>
-#include <fcntl.h>  // For file creation modes.
-#include <inttypes.h>
-#include <linux/limits.h>  // PATH_MAX
-#include <pwd.h>  // For struct passwd.
-#include <sys/types.h>  // for mode_t.
-#include <sys/wait.h>  // For waitpid.
-#include <unistd.h>  // For execv and fork.
-
-#include <set>
-#include <utility>
-#include <vector>
-
-#include <base/files/file_util.h>
-#include <base/logging.h>
-#include <base/posix/eintr_wrapper.h>
-#include <base/strings/string_split.h>
-#include <base/strings/string_util.h>
-#include <base/strings/stringprintf.h>
-#include <brillo/key_value_store.h>
-#include <brillo/process.h>
-
-namespace {
-
-const char kCollectChromeFile[] =
-    "/mnt/stateful_partition/etc/collect_chrome_crashes";
-const char kCrashTestInProgressPath[] =
-    "/data/misc/crash_reporter/tmp/crash-test-in-progress";
-const char kDefaultLogConfig[] = "/etc/crash_reporter_logs.conf";
-const char kDefaultUserName[] = "chronos";
-const char kLeaveCoreFile[] = "/data/misc/crash_reporter/.leave_core";
-const char kShellPath[] = "/system/bin/sh";
-const char kSystemCrashPath[] = "/data/misc/crash_reporter/crash";
-const char kUploadVarPrefix[] = "upload_var_";
-const char kUploadFilePrefix[] = "upload_file_";
-
-// Normally this path is not used.  Unfortunately, there are a few edge cases
-// where we need this.  Any process that runs as kDefaultUserName that crashes
-// is consider a "user crash".  That includes the initial Chrome browser that
-// runs the login screen.  If that blows up, there is no logged in user yet,
-// so there is no per-user dir for us to stash things in.  Instead we fallback
-// to this path as it is at least encrypted on a per-system basis.
-//
-// This also comes up when running autotests.  The GUI is sitting at the login
-// screen while tests are sshing in, changing users, and triggering crashes as
-// the user (purposefully).
-const char kFallbackUserCrashPath[] = "/home/chronos/crash";
-
-// Directory mode of the user crash spool directory.
-const mode_t kUserCrashPathMode = 0755;
-
-// Directory mode of the system crash spool directory.
-const mode_t kSystemCrashPathMode = 01755;
-
-const uid_t kRootOwner = 0;
-const uid_t kRootGroup = 0;
-
-}  // namespace
-
-// Maximum crash reports per crash spool directory.  Note that this is
-// a separate maximum from the maximum rate at which we upload these
-// diagnostics.  The higher this rate is, the more space we allow for
-// core files, minidumps, and kcrash logs, and equivalently the more
-// processor and I/O bandwidth we dedicate to handling these crashes when
-// many occur at once.  Also note that if core files are configured to
-// be left on the file system, we stop adding crashes when either the
-// number of core files or minidumps reaches this number.
-const int CrashCollector::kMaxCrashDirectorySize = 32;
-
-using base::FilePath;
-using base::StringPrintf;
-
-CrashCollector::CrashCollector()
-    : log_config_path_(kDefaultLogConfig) {
-}
-
-CrashCollector::~CrashCollector() {
-}
-
-void CrashCollector::Initialize(
-    CrashCollector::CountCrashFunction count_crash_function,
-    CrashCollector::IsFeedbackAllowedFunction is_feedback_allowed_function) {
-  CHECK(count_crash_function);
-  CHECK(is_feedback_allowed_function);
-
-  count_crash_function_ = count_crash_function;
-  is_feedback_allowed_function_ = is_feedback_allowed_function;
-}
-
-int CrashCollector::WriteNewFile(const FilePath &filename,
-                                 const char *data,
-                                 int size) {
-  int fd = HANDLE_EINTR(open(filename.value().c_str(),
-                             O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0666));
-  if (fd < 0) {
-    return -1;
-  }
-
-  int rv = base::WriteFileDescriptor(fd, data, size) ? size : -1;
-  IGNORE_EINTR(close(fd));
-  return rv;
-}
-
-std::string CrashCollector::Sanitize(const std::string &name) {
-  // Make sure the sanitized name does not include any periods.
-  // The logic in crash_sender relies on this.
-  std::string result = name;
-  for (size_t i = 0; i < name.size(); ++i) {
-    if (!isalnum(result[i]) && result[i] != '_')
-      result[i] = '_';
-  }
-  return result;
-}
-
-std::string CrashCollector::FormatDumpBasename(const std::string &exec_name,
-                                               time_t timestamp,
-                                               pid_t pid) {
-  struct tm tm;
-  localtime_r(&timestamp, &tm);
-  std::string sanitized_exec_name = Sanitize(exec_name);
-  return StringPrintf("%s.%04d%02d%02d.%02d%02d%02d.%d",
-                      sanitized_exec_name.c_str(),
-                      tm.tm_year + 1900,
-                      tm.tm_mon + 1,
-                      tm.tm_mday,
-                      tm.tm_hour,
-                      tm.tm_min,
-                      tm.tm_sec,
-                      pid);
-}
-
-FilePath CrashCollector::GetCrashPath(const FilePath &crash_directory,
-                                      const std::string &basename,
-                                      const std::string &extension) {
-  return crash_directory.Append(StringPrintf("%s.%s",
-                                             basename.c_str(),
-                                             extension.c_str()));
-}
-
-FilePath CrashCollector::GetCrashDirectoryInfo(
-    mode_t *mode,
-    uid_t *directory_owner,
-    gid_t *directory_group) {
-  *mode = kSystemCrashPathMode;
-  *directory_owner = kRootOwner;
-  *directory_group = kRootGroup;
-  return FilePath(kSystemCrashPath);
-}
-
-bool CrashCollector::GetUserInfoFromName(const std::string &name,
-                                         uid_t *uid,
-                                         gid_t *gid) {
-  char storage[256];
-  struct passwd passwd_storage;
-  struct passwd *passwd_result = nullptr;
-
-  if (getpwnam_r(name.c_str(), &passwd_storage, storage, sizeof(storage),
-                 &passwd_result) != 0 || passwd_result == nullptr) {
-    LOG(ERROR) << "Cannot find user named " << name;
-    return false;
-  }
-
-  *uid = passwd_result->pw_uid;
-  *gid = passwd_result->pw_gid;
-  return true;
-}
-
-bool CrashCollector::GetCreatedCrashDirectoryByEuid(uid_t euid,
-                                                    FilePath *crash_directory,
-                                                    bool *out_of_capacity) {
-  if (out_of_capacity) *out_of_capacity = false;
-
-  // For testing.
-  if (!forced_crash_directory_.empty()) {
-    *crash_directory = forced_crash_directory_;
-    return true;
-  }
-
-  mode_t directory_mode;
-  uid_t directory_owner;
-  gid_t directory_group;
-  *crash_directory =
-      GetCrashDirectoryInfo(&directory_mode,
-                            &directory_owner,
-                            &directory_group);
-
-  if (!base::PathExists(*crash_directory)) {
-    // Create the spool directory with the appropriate mode (regardless of
-    // umask) and ownership.
-    mode_t old_mask = umask(0);
-    if (mkdir(crash_directory->value().c_str(), directory_mode) < 0 ||
-        chown(crash_directory->value().c_str(),
-              directory_owner,
-              directory_group) < 0) {
-      LOG(ERROR) << "Unable to create appropriate crash directory";
-      return false;
-    }
-    umask(old_mask);
-  }
-
-  if (!base::PathExists(*crash_directory)) {
-    LOG(ERROR) << "Unable to create crash directory "
-               << crash_directory->value().c_str();
-    return false;
-  }
-
-  if (!CheckHasCapacity(*crash_directory)) {
-    if (out_of_capacity) *out_of_capacity = true;
-    LOG(ERROR) << "Directory " << crash_directory->value()
-               << " is out of capacity.";
-    return false;
-  }
-
-  return true;
-}
-
-FilePath CrashCollector::GetProcessPath(pid_t pid) {
-  return FilePath(StringPrintf("/proc/%d", pid));
-}
-
-bool CrashCollector::GetSymlinkTarget(const FilePath &symlink,
-                                      FilePath *target) {
-  ssize_t max_size = 64;
-  std::vector<char> buffer;
-
-  while (true) {
-    buffer.resize(max_size + 1);
-    ssize_t size = readlink(symlink.value().c_str(), buffer.data(), max_size);
-    if (size < 0) {
-      int saved_errno = errno;
-      LOG(ERROR) << "Readlink failed on " << symlink.value() << " with "
-                 << saved_errno;
-      return false;
-    }
-
-    buffer[size] = 0;
-    if (size == max_size) {
-      max_size *= 2;
-      if (max_size > PATH_MAX) {
-        return false;
-      }
-      continue;
-    }
-    break;
-  }
-
-  *target = FilePath(buffer.data());
-  return true;
-}
-
-bool CrashCollector::GetExecutableBaseNameFromPid(pid_t pid,
-                                                 std::string *base_name) {
-  FilePath target;
-  FilePath process_path = GetProcessPath(pid);
-  FilePath exe_path = process_path.Append("exe");
-  if (!GetSymlinkTarget(exe_path, &target)) {
-    LOG(INFO) << "GetSymlinkTarget failed - Path " << process_path.value()
-              << " DirectoryExists: "
-              << base::DirectoryExists(process_path);
-    // Try to further diagnose exe readlink failure cause.
-    struct stat buf;
-    int stat_result = stat(exe_path.value().c_str(), &buf);
-    int saved_errno = errno;
-    if (stat_result < 0) {
-      LOG(INFO) << "stat " << exe_path.value() << " failed: " << stat_result
-                << " " << saved_errno;
-    } else {
-      LOG(INFO) << "stat " << exe_path.value() << " succeeded: st_mode="
-                << buf.st_mode;
-    }
-    return false;
-  }
-  *base_name = target.BaseName().value();
-  return true;
-}
-
-// Return true if the given crash directory has not already reached
-// maximum capacity.
-bool CrashCollector::CheckHasCapacity(const FilePath &crash_directory) {
-  DIR* dir = opendir(crash_directory.value().c_str());
-  if (!dir) {
-    LOG(WARNING) << "Unable to open crash directory "
-                 << crash_directory.value();
-    return false;
-  }
-  struct dirent ent_buf;
-  struct dirent* ent;
-  bool full = false;
-  std::set<std::string> basenames;
-  while (readdir_r(dir, &ent_buf, &ent) == 0 && ent) {
-    if ((strcmp(ent->d_name, ".") == 0) ||
-        (strcmp(ent->d_name, "..") == 0))
-      continue;
-
-    std::string filename(ent->d_name);
-    size_t last_dot = filename.rfind(".");
-    std::string basename;
-    // If there is a valid looking extension, use the base part of the
-    // name.  If the only dot is the first byte (aka a dot file), treat
-    // it as unique to avoid allowing a directory full of dot files
-    // from accumulating.
-    if (last_dot != std::string::npos && last_dot != 0)
-      basename = filename.substr(0, last_dot);
-    else
-      basename = filename;
-    basenames.insert(basename);
-
-    if (basenames.size() >= static_cast<size_t>(kMaxCrashDirectorySize)) {
-      LOG(WARNING) << "Crash directory " << crash_directory.value()
-                   << " already full with " << kMaxCrashDirectorySize
-                   << " pending reports";
-      full = true;
-      break;
-    }
-  }
-  closedir(dir);
-  return !full;
-}
-
-bool CrashCollector::GetLogContents(const FilePath &config_path,
-                                    const std::string &exec_name,
-                                    const FilePath &output_file) {
-  brillo::KeyValueStore store;
-  if (!store.Load(config_path)) {
-    LOG(INFO) << "Unable to read log configuration file "
-              << config_path.value();
-    return false;
-  }
-
-  std::string command;
-  if (!store.GetString(exec_name, &command))
-    return false;
-
-  brillo::ProcessImpl diag_process;
-  diag_process.AddArg(kShellPath);
-  diag_process.AddStringOption("-c", command);
-  diag_process.RedirectOutput(output_file.value());
-
-  const int result = diag_process.Run();
-  if (result != 0) {
-    LOG(INFO) << "Log command \"" << command << "\" exited with " << result;
-    return false;
-  }
-  return true;
-}
-
-void CrashCollector::AddCrashMetaData(const std::string &key,
-                                      const std::string &value) {
-  extra_metadata_.append(StringPrintf("%s=%s\n", key.c_str(), value.c_str()));
-}
-
-void CrashCollector::AddCrashMetaUploadFile(const std::string &key,
-                                            const std::string &path) {
-  if (!path.empty())
-    AddCrashMetaData(kUploadFilePrefix + key, path);
-}
-
-void CrashCollector::AddCrashMetaUploadData(const std::string &key,
-                                            const std::string &value) {
-  if (!value.empty())
-    AddCrashMetaData(kUploadVarPrefix + key, value);
-}
-
-void CrashCollector::WriteCrashMetaData(const FilePath &meta_path,
-                                        const std::string &exec_name,
-                                        const std::string &payload_path) {
-  int64_t payload_size = -1;
-  base::GetFileSize(FilePath(payload_path), &payload_size);
-  std::string meta_data = StringPrintf("%sexec_name=%s\n"
-                                       "payload=%s\n"
-                                       "payload_size=%" PRId64 "\n"
-                                       "done=1\n",
-                                       extra_metadata_.c_str(),
-                                       exec_name.c_str(),
-                                       payload_path.c_str(),
-                                       payload_size);
-  // We must use WriteNewFile instead of base::WriteFile as we
-  // do not want to write with root access to a symlink that an attacker
-  // might have created.
-  if (WriteNewFile(meta_path, meta_data.c_str(), meta_data.size()) < 0) {
-    LOG(ERROR) << "Unable to write " << meta_path.value();
-  }
-}
-
-bool CrashCollector::IsCrashTestInProgress() {
-  return base::PathExists(FilePath(kCrashTestInProgressPath));
-}
-
-bool CrashCollector::IsDeveloperImage() {
-  // If we're testing crash reporter itself, we don't want to special-case
-  // for developer images.
-  if (IsCrashTestInProgress())
-    return false;
-  return base::PathExists(FilePath(kLeaveCoreFile));
-}
diff --git a/crash_reporter/crash_collector.h b/crash_reporter/crash_collector.h
deleted file mode 100644
index 24cbfb3..0000000
--- a/crash_reporter/crash_collector.h
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CRASH_REPORTER_CRASH_COLLECTOR_H_
-#define CRASH_REPORTER_CRASH_COLLECTOR_H_
-
-#include <sys/stat.h>
-
-#include <map>
-#include <string>
-
-#include <base/files/file_path.h>
-#include <base/macros.h>
-#include <gtest/gtest_prod.h>  // for FRIEND_TEST
-
-// User crash collector.
-class CrashCollector {
- public:
-  typedef void (*CountCrashFunction)();
-  typedef bool (*IsFeedbackAllowedFunction)();
-
-  CrashCollector();
-
-  virtual ~CrashCollector();
-
-  // Initialize the crash collector for detection of crashes, given a
-  // crash counting function, and metrics collection enabled oracle.
-  void Initialize(CountCrashFunction count_crash,
-                  IsFeedbackAllowedFunction is_metrics_allowed);
-
- protected:
-  friend class CrashCollectorTest;
-  FRIEND_TEST(ChromeCollectorTest, HandleCrash);
-  FRIEND_TEST(CrashCollectorTest, CheckHasCapacityCorrectBasename);
-  FRIEND_TEST(CrashCollectorTest, CheckHasCapacityStrangeNames);
-  FRIEND_TEST(CrashCollectorTest, CheckHasCapacityUsual);
-  FRIEND_TEST(CrashCollectorTest, GetCrashDirectoryInfo);
-  FRIEND_TEST(CrashCollectorTest, GetCrashPath);
-  FRIEND_TEST(CrashCollectorTest, GetLogContents);
-  FRIEND_TEST(CrashCollectorTest, ForkExecAndPipe);
-  FRIEND_TEST(CrashCollectorTest, FormatDumpBasename);
-  FRIEND_TEST(CrashCollectorTest, Initialize);
-  FRIEND_TEST(CrashCollectorTest, MetaData);
-  FRIEND_TEST(CrashCollectorTest, Sanitize);
-  FRIEND_TEST(CrashCollectorTest, WriteNewFile);
-  FRIEND_TEST(ForkExecAndPipeTest, Basic);
-  FRIEND_TEST(ForkExecAndPipeTest, NonZeroReturnValue);
-  FRIEND_TEST(ForkExecAndPipeTest, BadOutputFile);
-  FRIEND_TEST(ForkExecAndPipeTest, ExistingOutputFile);
-  FRIEND_TEST(ForkExecAndPipeTest, BadExecutable);
-  FRIEND_TEST(ForkExecAndPipeTest, StderrCaptured);
-  FRIEND_TEST(ForkExecAndPipeTest, NULLParam);
-  FRIEND_TEST(ForkExecAndPipeTest, NoParams);
-  FRIEND_TEST(ForkExecAndPipeTest, SegFaultHandling);
-
-  // Set maximum enqueued crashes in a crash directory.
-  static const int kMaxCrashDirectorySize;
-
-  // Writes |data| of |size| to |filename|, which must be a new file.
-  // If the file already exists or writing fails, return a negative value.
-  // Otherwise returns the number of bytes written.
-  int WriteNewFile(const base::FilePath &filename, const char *data, int size);
-
-  // Return a filename that has only [a-z0-1_] characters by mapping
-  // all others into '_'.
-  std::string Sanitize(const std::string &name);
-
-  // For testing, set the directory always returned by
-  // GetCreatedCrashDirectoryByEuid.
-  void ForceCrashDirectory(const base::FilePath &forced_directory) {
-    forced_crash_directory_ = forced_directory;
-  }
-
-  base::FilePath GetCrashDirectoryInfo(mode_t *mode,
-                                       uid_t *directory_owner,
-                                       gid_t *directory_group);
-  bool GetUserInfoFromName(const std::string &name,
-                           uid_t *uid,
-                           gid_t *gid);
-
-  // Determines the crash directory for given euid, and creates the
-  // directory if necessary with appropriate permissions.  If
-  // |out_of_capacity| is not nullptr, it is set to indicate if the call
-  // failed due to not having capacity in the crash directory. Returns
-  // true whether or not directory needed to be created, false on any
-  // failure.  If the crash directory is at capacity, returns false.
-  bool GetCreatedCrashDirectoryByEuid(uid_t euid,
-                                      base::FilePath *crash_file_path,
-                                      bool *out_of_capacity);
-
-  // Format crash name based on components.
-  std::string FormatDumpBasename(const std::string &exec_name,
-                                 time_t timestamp,
-                                 pid_t pid);
-
-  // Create a file path to a file in |crash_directory| with the given
-  // |basename| and |extension|.
-  base::FilePath GetCrashPath(const base::FilePath &crash_directory,
-                              const std::string &basename,
-                              const std::string &extension);
-
-  base::FilePath GetProcessPath(pid_t pid);
-  bool GetSymlinkTarget(const base::FilePath &symlink,
-                        base::FilePath *target);
-  bool GetExecutableBaseNameFromPid(pid_t pid,
-                                    std::string *base_name);
-
-  // Check given crash directory still has remaining capacity for another
-  // crash.
-  bool CheckHasCapacity(const base::FilePath &crash_directory);
-
-  // Write a log applicable to |exec_name| to |output_file| based on the
-  // log configuration file at |config_path|.
-  bool GetLogContents(const base::FilePath &config_path,
-                      const std::string &exec_name,
-                      const base::FilePath &output_file);
-
-  // Add non-standard meta data to the crash metadata file.  Call
-  // before calling WriteCrashMetaData.  Key must not contain "=" or
-  // "\n" characters.  Value must not contain "\n" characters.
-  void AddCrashMetaData(const std::string &key, const std::string &value);
-
-  // Add a file to be uploaded to the crash reporter server. The file must
-  // persist until the crash report is sent; ideally it should live in the same
-  // place as the .meta file, so it can be cleaned up automatically.
-  void AddCrashMetaUploadFile(const std::string &key, const std::string &path);
-
-  // Add non-standard meta data to the crash metadata file.
-  // Data added though this call will be uploaded to the crash reporter server,
-  // appearing as a form field.
-  void AddCrashMetaUploadData(const std::string &key, const std::string &value);
-
-  // Write a file of metadata about crash.
-  void WriteCrashMetaData(const base::FilePath &meta_path,
-                          const std::string &exec_name,
-                          const std::string &payload_path);
-
-  // Returns true if the a crash test is currently running.
-  bool IsCrashTestInProgress();
-  // Returns true if we should consider ourselves to be running on a
-  // developer image.
-  bool IsDeveloperImage();
-
-  CountCrashFunction count_crash_function_;
-  IsFeedbackAllowedFunction is_feedback_allowed_function_;
-  std::string extra_metadata_;
-  base::FilePath forced_crash_directory_;
-  base::FilePath log_config_path_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(CrashCollector);
-};
-
-#endif  // CRASH_REPORTER_CRASH_COLLECTOR_H_
diff --git a/crash_reporter/crash_collector_test.cc b/crash_reporter/crash_collector_test.cc
deleted file mode 100644
index 11c8c0d..0000000
--- a/crash_reporter/crash_collector_test.cc
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2012 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 "crash_collector_test.h"
-
-#include <unistd.h>
-#include <utility>
-
-#include <base/files/file_util.h>
-#include <base/files/scoped_temp_dir.h>
-#include <base/strings/string_util.h>
-#include <base/strings/stringprintf.h>
-#include <brillo/syslog_logging.h>
-#include <gtest/gtest.h>
-
-#include "crash_collector.h"
-
-using base::FilePath;
-using base::StringPrintf;
-using brillo::FindLog;
-using ::testing::Invoke;
-using ::testing::Return;
-
-namespace {
-
-void CountCrash() {
-  ADD_FAILURE();
-}
-
-bool IsMetrics() {
-  ADD_FAILURE();
-  return false;
-}
-
-}  // namespace
-
-class CrashCollectorTest : public ::testing::Test {
- public:
-  void SetUp() {
-    EXPECT_CALL(collector_, SetUpDBus()).WillRepeatedly(Return());
-
-    collector_.Initialize(CountCrash, IsMetrics);
-    EXPECT_TRUE(test_dir_.CreateUniqueTempDir());
-    brillo::ClearLog();
-  }
-
-  bool CheckHasCapacity();
-
- protected:
-  CrashCollectorMock collector_;
-
-  // Temporary directory used for tests.
-  base::ScopedTempDir test_dir_;
-};
-
-TEST_F(CrashCollectorTest, Initialize) {
-  ASSERT_TRUE(CountCrash == collector_.count_crash_function_);
-  ASSERT_TRUE(IsMetrics == collector_.is_feedback_allowed_function_);
-}
-
-TEST_F(CrashCollectorTest, WriteNewFile) {
-  FilePath test_file = test_dir_.path().Append("test_new");
-  const char kBuffer[] = "buffer";
-  EXPECT_EQ(strlen(kBuffer),
-            collector_.WriteNewFile(test_file,
-                                    kBuffer,
-                                    strlen(kBuffer)));
-  EXPECT_LT(collector_.WriteNewFile(test_file,
-                                    kBuffer,
-                                    strlen(kBuffer)), 0);
-}
-
-TEST_F(CrashCollectorTest, Sanitize) {
-  EXPECT_EQ("chrome", collector_.Sanitize("chrome"));
-  EXPECT_EQ("CHROME", collector_.Sanitize("CHROME"));
-  EXPECT_EQ("1chrome2", collector_.Sanitize("1chrome2"));
-  EXPECT_EQ("chrome__deleted_", collector_.Sanitize("chrome (deleted)"));
-  EXPECT_EQ("foo_bar", collector_.Sanitize("foo.bar"));
-  EXPECT_EQ("", collector_.Sanitize(""));
-  EXPECT_EQ("_", collector_.Sanitize(" "));
-}
-
-TEST_F(CrashCollectorTest, FormatDumpBasename) {
-  struct tm tm = {0};
-  tm.tm_sec = 15;
-  tm.tm_min = 50;
-  tm.tm_hour = 13;
-  tm.tm_mday = 23;
-  tm.tm_mon = 4;
-  tm.tm_year = 110;
-  tm.tm_isdst = -1;
-  std::string basename =
-      collector_.FormatDumpBasename("foo", mktime(&tm), 100);
-  ASSERT_EQ("foo.20100523.135015.100", basename);
-}
-
-TEST_F(CrashCollectorTest, GetCrashPath) {
-  EXPECT_EQ("/var/spool/crash/myprog.20100101.1200.1234.core",
-            collector_.GetCrashPath(FilePath("/var/spool/crash"),
-                                    "myprog.20100101.1200.1234",
-                                    "core").value());
-  EXPECT_EQ("/home/chronos/user/crash/chrome.20100101.1200.1234.dmp",
-            collector_.GetCrashPath(FilePath("/home/chronos/user/crash"),
-                                    "chrome.20100101.1200.1234",
-                                    "dmp").value());
-}
-
-
-bool CrashCollectorTest::CheckHasCapacity() {
-  const char* kFullMessage =
-      StringPrintf("Crash directory %s already full",
-                   test_dir_.path().value().c_str()).c_str();
-  bool has_capacity = collector_.CheckHasCapacity(test_dir_.path());
-  bool has_message = FindLog(kFullMessage);
-  EXPECT_EQ(has_message, !has_capacity);
-  return has_capacity;
-}
-
-TEST_F(CrashCollectorTest, CheckHasCapacityUsual) {
-  // Test kMaxCrashDirectorySize - 1 non-meta files can be added.
-  for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 1; ++i) {
-    base::WriteFile(test_dir_.path().Append(StringPrintf("file%d.core", i)),
-                    "", 0);
-    EXPECT_TRUE(CheckHasCapacity());
-  }
-
-  // Test an additional kMaxCrashDirectorySize - 1 meta files fit.
-  for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 1; ++i) {
-    base::WriteFile(test_dir_.path().Append(StringPrintf("file%d.meta", i)),
-                    "", 0);
-    EXPECT_TRUE(CheckHasCapacity());
-  }
-
-  // Test an additional kMaxCrashDirectorySize meta files don't fit.
-  for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize; ++i) {
-    base::WriteFile(test_dir_.path().Append(StringPrintf("overage%d.meta", i)),
-                    "", 0);
-    EXPECT_FALSE(CheckHasCapacity());
-  }
-}
-
-TEST_F(CrashCollectorTest, CheckHasCapacityCorrectBasename) {
-  // Test kMaxCrashDirectorySize - 1 files can be added.
-  for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 1; ++i) {
-    base::WriteFile(test_dir_.path().Append(StringPrintf("file.%d.core", i)),
-                    "", 0);
-    EXPECT_TRUE(CheckHasCapacity());
-  }
-  base::WriteFile(test_dir_.path().Append("file.last.core"), "", 0);
-  EXPECT_FALSE(CheckHasCapacity());
-}
-
-TEST_F(CrashCollectorTest, CheckHasCapacityStrangeNames) {
-  // Test many files with different extensions and same base fit.
-  for (int i = 0; i < 5 * CrashCollector::kMaxCrashDirectorySize; ++i) {
-    base::WriteFile(test_dir_.path().Append(StringPrintf("a.%d", i)), "", 0);
-    EXPECT_TRUE(CheckHasCapacity());
-  }
-  // Test dot files are treated as individual files.
-  for (int i = 0; i < CrashCollector::kMaxCrashDirectorySize - 2; ++i) {
-    base::WriteFile(test_dir_.path().Append(StringPrintf(".file%d", i)), "", 0);
-    EXPECT_TRUE(CheckHasCapacity());
-  }
-  base::WriteFile(test_dir_.path().Append("normal.meta"), "", 0);
-  EXPECT_FALSE(CheckHasCapacity());
-}
-
-TEST_F(CrashCollectorTest, MetaData) {
-  const char kMetaFileBasename[] = "generated.meta";
-  FilePath meta_file = test_dir_.path().Append(kMetaFileBasename);
-  FilePath payload_file = test_dir_.path().Append("payload-file");
-  std::string contents;
-  const char kPayload[] = "foo";
-  ASSERT_TRUE(base::WriteFile(payload_file, kPayload, strlen(kPayload)));
-  collector_.AddCrashMetaData("foo", "bar");
-  collector_.WriteCrashMetaData(meta_file, "kernel", payload_file.value());
-  EXPECT_TRUE(base::ReadFileToString(meta_file, &contents));
-  const std::string kExpectedMeta =
-      StringPrintf("foo=bar\n"
-          "exec_name=kernel\n"
-          "payload=%s\n"
-          "payload_size=3\n"
-          "done=1\n",
-          test_dir_.path().Append("payload-file").value().c_str());
-  EXPECT_EQ(kExpectedMeta, contents);
-
-  // Test target of symlink is not overwritten.
-  payload_file = test_dir_.path().Append("payload2-file");
-  ASSERT_TRUE(base::WriteFile(payload_file, kPayload, strlen(kPayload)));
-  FilePath meta_symlink_path = test_dir_.path().Append("symlink.meta");
-  ASSERT_EQ(0,
-            symlink(kMetaFileBasename,
-                    meta_symlink_path.value().c_str()));
-  ASSERT_TRUE(base::PathExists(meta_symlink_path));
-  brillo::ClearLog();
-  collector_.WriteCrashMetaData(meta_symlink_path,
-                                "kernel",
-                                payload_file.value());
-  // Target metadata contents should have stayed the same.
-  contents.clear();
-  EXPECT_TRUE(base::ReadFileToString(meta_file, &contents));
-  EXPECT_EQ(kExpectedMeta, contents);
-  EXPECT_TRUE(FindLog("Unable to write"));
-
-  // Test target of dangling symlink is not created.
-  base::DeleteFile(meta_file, false);
-  ASSERT_FALSE(base::PathExists(meta_file));
-  brillo::ClearLog();
-  collector_.WriteCrashMetaData(meta_symlink_path, "kernel",
-                                payload_file.value());
-  EXPECT_FALSE(base::PathExists(meta_file));
-  EXPECT_TRUE(FindLog("Unable to write"));
-}
-
-TEST_F(CrashCollectorTest, GetLogContents) {
-  FilePath config_file = test_dir_.path().Append("crash_config");
-  FilePath output_file = test_dir_.path().Append("crash_log");
-  const char kConfigContents[] =
-      "foobar=echo hello there | \\\n  sed -e \"s/there/world/\"";
-  ASSERT_TRUE(
-      base::WriteFile(config_file, kConfigContents, strlen(kConfigContents)));
-  base::DeleteFile(FilePath(output_file), false);
-  EXPECT_FALSE(collector_.GetLogContents(config_file,
-                                         "barfoo",
-                                         output_file));
-  EXPECT_FALSE(base::PathExists(output_file));
-  base::DeleteFile(FilePath(output_file), false);
-  EXPECT_TRUE(collector_.GetLogContents(config_file,
-                                        "foobar",
-                                        output_file));
-  ASSERT_TRUE(base::PathExists(output_file));
-  std::string contents;
-  EXPECT_TRUE(base::ReadFileToString(output_file, &contents));
-  EXPECT_EQ("hello world\n", contents);
-}
diff --git a/crash_reporter/crash_collector_test.h b/crash_reporter/crash_collector_test.h
deleted file mode 100644
index cfbb97b..0000000
--- a/crash_reporter/crash_collector_test.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CRASH_REPORTER_CRASH_COLLECTOR_TEST_H_
-#define CRASH_REPORTER_CRASH_COLLECTOR_TEST_H_
-
-#include "crash_collector.h"
-
-#include <map>
-#include <string>
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-class CrashCollectorMock : public CrashCollector {
- public:
-  MOCK_METHOD0(SetUpDBus, void());
-  MOCK_METHOD1(GetActiveUserSessions,
-               bool(std::map<std::string, std::string> *sessions));
-};
-
-#endif  // CRASH_REPORTER_CRASH_COLLECTOR_TEST_H_
diff --git a/crash_reporter/crash_reporter.cc b/crash_reporter/crash_reporter.cc
deleted file mode 100644
index 16e70d8..0000000
--- a/crash_reporter/crash_reporter.cc
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * Copyright (C) 2012 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 <fcntl.h>  // for open
-
-#include <string>
-#include <vector>
-
-#include <base/files/file_util.h>
-#include <base/guid.h>
-#include <base/logging.h>
-#include <base/strings/string_split.h>
-#include <base/strings/string_util.h>
-#include <base/strings/stringprintf.h>
-#include <binder/IServiceManager.h>
-#include <brillo/flag_helper.h>
-#include <brillo/syslog_logging.h>
-#include <metrics/metrics_collector_service_client.h>
-#include <metrics/metrics_library.h>
-#include <utils/String16.h>
-
-
-#include "kernel_collector.h"
-#include "kernel_warning_collector.h"
-#include "unclean_shutdown_collector.h"
-#include "user_collector.h"
-
-#if !defined(__ANDROID__)
-#include "udev_collector.h"
-#endif
-
-static const char kCrashCounterHistogram[] = "Logging.CrashCounter";
-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";
-
-// Enumeration of kinds of crashes to be used in the CrashCounter histogram.
-enum CrashKinds {
-  kCrashKindUncleanShutdown = 1,
-  kCrashKindUser = 2,
-  kCrashKindKernel = 3,
-  kCrashKindUdev = 4,
-  kCrashKindKernelWarning = 5,
-  kCrashKindMax
-};
-
-static MetricsLibrary s_metrics_lib;
-
-using android::brillo::metrics::IMetricsCollectorService;
-using base::FilePath;
-using base::StringPrintf;
-
-static bool IsFeedbackAllowed() {
-  return s_metrics_lib.AreMetricsEnabled();
-}
-
-static bool TouchFile(const FilePath &file_path) {
-  return base::WriteFile(file_path, "", 0) == 0;
-}
-
-static void SendCrashMetrics(CrashKinds type, const char* name) {
-  // TODO(kmixter): We can remove this histogram as part of
-  // crosbug.com/11163.
-  s_metrics_lib.SendEnumToUMA(kCrashCounterHistogram, type, kCrashKindMax);
-  s_metrics_lib.SendCrashToUMA(name);
-}
-
-static void CountKernelCrash() {
-  SendCrashMetrics(kCrashKindKernel, "kernel");
-}
-
-static void CountUdevCrash() {
-  SendCrashMetrics(kCrashKindUdev, "udevcrash");
-}
-
-static void CountUncleanShutdown() {
-  SendCrashMetrics(kCrashKindUncleanShutdown, "uncleanshutdown");
-}
-
-static void CountUserCrash() {
-  SendCrashMetrics(kCrashKindUser, "user");
-  // Tell the metrics collector about the user crash, in order to log active
-  // use time between crashes.
-  MetricsCollectorServiceClient metrics_collector_service;
-
-  if (metrics_collector_service.Init())
-    metrics_collector_service.notifyUserCrash();
-  else
-    LOG(ERROR) << "Failed to send user crash notification to metrics_collector";
-}
-
-
-static int Initialize(KernelCollector *kernel_collector,
-                      UserCollector *user_collector,
-                      UncleanShutdownCollector *unclean_shutdown_collector,
-                      const bool unclean_check,
-                      const bool clean_shutdown) {
-  CHECK(!clean_shutdown) << "Incompatible options";
-
-  // Try to read the GUID from kGUIDFileName.  If the file doesn't exist, is
-  // blank, or the read fails, generate a new GUID and write it to the file.
-  std::string guid;
-  base::FilePath filepath(kGUIDFileName);
-  if (!base::ReadFileToString(filepath, &guid) || guid.empty()) {
-    guid = base::GenerateGUID();
-    // If we can't read or write the file, log an error.  However it is not
-    // a fatal error, as the crash server will assign a random GUID based
-    // on a hash of the IP address if one is not provided in the report.
-    if (base::WriteFile(filepath, guid.c_str(), guid.size()) <= 0) {
-      LOG(ERROR) << "Could not write guid " << guid << " to file "
-                 << filepath.value();
-    }
-  }
-
-  bool was_kernel_crash = false;
-  bool was_unclean_shutdown = false;
-  kernel_collector->Enable();
-  if (kernel_collector->is_enabled()) {
-    was_kernel_crash = kernel_collector->Collect();
-  }
-
-  if (unclean_check) {
-    was_unclean_shutdown = unclean_shutdown_collector->Collect();
-  }
-
-  // Touch a file to notify the metrics daemon that a kernel
-  // crash has been detected so that it can log the time since
-  // the last kernel crash.
-  if (IsFeedbackAllowed()) {
-    if (was_kernel_crash) {
-      TouchFile(FilePath(kKernelCrashDetected));
-    } else if (was_unclean_shutdown) {
-      // We only count an unclean shutdown if it did not come with
-      // an associated kernel crash.
-      TouchFile(FilePath(kUncleanShutdownDetected));
-    }
-  }
-
-  // Must enable the unclean shutdown collector *after* collecting.
-  unclean_shutdown_collector->Enable();
-  user_collector->Enable();
-
-  return 0;
-}
-
-static int HandleUserCrash(UserCollector *user_collector,
-                           const std::string& user, const bool crash_test) {
-  // Handle a specific user space crash.
-  CHECK(!user.empty()) << "--user= must be set";
-
-  // Make it possible to test what happens when we crash while
-  // handling a crash.
-  if (crash_test) {
-    *(volatile char *)0 = 0;
-    return 0;
-  }
-
-  // Accumulate logs to help in diagnosing failures during user collection.
-  brillo::LogToString(true);
-  // Handle the crash, get the name of the process from procfs.
-  bool handled = user_collector->HandleCrash(user, nullptr);
-  brillo::LogToString(false);
-  if (!handled)
-    return 1;
-  return 0;
-}
-
-#if !defined(__ANDROID__)
-static int HandleUdevCrash(UdevCollector *udev_collector,
-                           const std::string& udev_event) {
-  // Handle a crash indicated by a udev event.
-  CHECK(!udev_event.empty()) << "--udev= must be set";
-
-  // Accumulate logs to help in diagnosing failures during user collection.
-  brillo::LogToString(true);
-  bool handled = udev_collector->HandleCrash(udev_event);
-  brillo::LogToString(false);
-  if (!handled)
-    return 1;
-  return 0;
-}
-#endif
-
-static int HandleKernelWarning(KernelWarningCollector
-                               *kernel_warning_collector) {
-  // Accumulate logs to help in diagnosing failures during collection.
-  brillo::LogToString(true);
-  bool handled = kernel_warning_collector->Collect();
-  brillo::LogToString(false);
-  if (!handled)
-    return 1;
-  return 0;
-}
-
-// Interactive/diagnostics mode for generating kernel crash signatures.
-static int GenerateKernelSignature(KernelCollector *kernel_collector,
-                                   const std::string& kernel_signature_file) {
-  std::string kcrash_contents;
-  std::string signature;
-  if (!base::ReadFileToString(FilePath(kernel_signature_file),
-                              &kcrash_contents)) {
-    fprintf(stderr, "Could not read file.\n");
-    return 1;
-  }
-  if (!kernel_collector->ComputeKernelStackSignature(
-          kcrash_contents,
-          &signature,
-          true)) {
-    fprintf(stderr, "Signature could not be generated.\n");
-    return 1;
-  }
-  printf("Kernel crash signature is \"%s\".\n", signature.c_str());
-  return 0;
-}
-
-// Ensure stdout, stdin, and stderr are open file descriptors.  If
-// they are not, any code which writes to stderr/stdout may write out
-// to files opened during execution.  In particular, when
-// crash_reporter is run by the kernel coredump pipe handler (via
-// kthread_create/kernel_execve), it will not have file table entries
-// 1 and 2 (stdout and stderr) populated.  We populate them here.
-static void OpenStandardFileDescriptors() {
-  int new_fd = -1;
-  // We open /dev/null to fill in any of the standard [0, 2] file
-  // descriptors.  We leave these open for the duration of the
-  // process.  This works because open returns the lowest numbered
-  // invalid fd.
-  do {
-    new_fd = open("/dev/null", 0);
-    CHECK_GE(new_fd, 0) << "Unable to open /dev/null";
-  } while (new_fd >= 0 && new_fd <= 2);
-  close(new_fd);
-}
-
-int main(int argc, char *argv[]) {
-  DEFINE_bool(init, false, "Initialize crash logging");
-  DEFINE_bool(clean_shutdown, false, "Signal clean shutdown");
-  DEFINE_string(generate_kernel_signature, "",
-                "Generate signature from given kcrash file");
-  DEFINE_bool(crash_test, false, "Crash test");
-  DEFINE_string(user, "", "User crash info (pid:signal:exec_name)");
-  DEFINE_bool(unclean_check, true, "Check for unclean shutdown");
-
-#if !defined(__ANDROID__)
-  DEFINE_string(udev, "", "Udev event description (type:device:subsystem)");
-#endif
-
-  DEFINE_bool(kernel_warning, false, "Report collected kernel warning");
-  DEFINE_string(pid, "", "PID of crashing process");
-  DEFINE_string(uid, "", "UID of crashing process");
-  DEFINE_string(exe, "", "Executable name of crashing process");
-  DEFINE_bool(core2md_failure, false, "Core2md failure test");
-  DEFINE_bool(directory_failure, false, "Spool directory failure test");
-  DEFINE_string(filter_in, "",
-                "Ignore all crashes but this for testing");
-
-  OpenStandardFileDescriptors();
-  FilePath my_path = base::MakeAbsoluteFilePath(FilePath(argv[0]));
-  s_metrics_lib.Init();
-  brillo::FlagHelper::Init(argc, argv, "Chromium OS Crash Reporter");
-  brillo::OpenLog(my_path.BaseName().value().c_str(), true);
-  brillo::InitLog(brillo::kLogToSyslog);
-
-  KernelCollector kernel_collector;
-  kernel_collector.Initialize(CountKernelCrash, IsFeedbackAllowed);
-  UserCollector user_collector;
-  user_collector.Initialize(CountUserCrash,
-                            my_path.value(),
-                            IsFeedbackAllowed,
-                            true,  // generate_diagnostics
-                            FLAGS_core2md_failure,
-                            FLAGS_directory_failure,
-                            FLAGS_filter_in);
-  UncleanShutdownCollector unclean_shutdown_collector;
-  unclean_shutdown_collector.Initialize(CountUncleanShutdown,
-                                        IsFeedbackAllowed);
-
-#if !defined(__ANDROID__)
-  UdevCollector udev_collector;
-  udev_collector.Initialize(CountUdevCrash, IsFeedbackAllowed);
-#endif
-
-  KernelWarningCollector kernel_warning_collector;
-  kernel_warning_collector.Initialize(CountUdevCrash, IsFeedbackAllowed);
-
-  if (FLAGS_init) {
-    return Initialize(&kernel_collector,
-                      &user_collector,
-                      &unclean_shutdown_collector,
-                      FLAGS_unclean_check,
-                      FLAGS_clean_shutdown);
-  }
-
-  if (FLAGS_clean_shutdown) {
-    unclean_shutdown_collector.Disable();
-    user_collector.Disable();
-    return 0;
-  }
-
-  if (!FLAGS_generate_kernel_signature.empty()) {
-    return GenerateKernelSignature(&kernel_collector,
-                                   FLAGS_generate_kernel_signature);
-  }
-
-#if !defined(__ANDROID__)
-  if (!FLAGS_udev.empty()) {
-    return HandleUdevCrash(&udev_collector, FLAGS_udev);
-  }
-#endif
-
-  if (FLAGS_kernel_warning) {
-    return HandleKernelWarning(&kernel_warning_collector);
-  }
-
-  return HandleUserCrash(&user_collector, FLAGS_user, FLAGS_crash_test);
-}
diff --git a/crash_reporter/crash_reporter.rc b/crash_reporter/crash_reporter.rc
deleted file mode 100644
index e6d1ec5..0000000
--- a/crash_reporter/crash_reporter.rc
+++ /dev/null
@@ -1,37 +0,0 @@
-on property:crash_reporter.coredump.enabled=1
-    write /proc/sys/kernel/core_pattern \
-          "|/system/bin/crash_reporter --user=%P:%s:%u:%g:%e"
-
-on property:crash_reporter.coredump.enabled=0
-    write /proc/sys/kernel/core_pattern "core"
-
-on post-fs-data
-    # Allow catching multiple unrelated concurrent crashes, but use a finite
-    # number to prevent infinitely recursing on crash handling.
-    write /proc/sys/kernel/core_pipe_limit 4
-
-    # 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.
-    mkdir /data/misc/crash_reporter 0770 root root
-    mkdir /data/misc/crash_reporter/crash 0770 root root
-    mkdir /data/misc/crash_reporter/lock 0700 root root
-    mkdir /data/misc/crash_reporter/log 0700 root root
-    mkdir /data/misc/crash_reporter/run 0700 root root
-    mkdir /data/misc/crash_reporter/tmp 0770 root root
-
-service crash_reporter /system/bin/crash_reporter --init
-    class late_start
-    oneshot
-
-service crash_sender /system/bin/periodic_scheduler 3600 14400 crash_sender \
-    /system/bin/crash_sender
-    class late_start
-    group system
diff --git a/crash_reporter/crash_reporter_logs.conf b/crash_reporter/crash_reporter_logs.conf
deleted file mode 100644
index 7db308c..0000000
--- a/crash_reporter/crash_reporter_logs.conf
+++ /dev/null
@@ -1,122 +0,0 @@
-# Copyright (C) 2012 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.
-
-# This file is parsed by chromeos::KeyValueStore. It has the format:
-#
-# <basename>=<shell command>\n
-#
-# Commands may be split across multiple lines using trailing backslashes.
-#
-# When an executable named <basename> crashes, the corresponding command is
-# executed and its standard output and standard error are attached to the crash
-# report.
-#
-# Use caution in modifying this file. Only run common Unix commands here, as
-# these commands will be run when a crash has recently occurred and we should
-# avoid running anything that might cause another crash. Similarly, these
-# commands block notification of the crash to parent processes, so commands
-# should execute quickly.
-
-update_engine=cat $(ls -1tr /var/log/update_engine | tail -5 | \
-  sed s.^./var/log/update_engine/.) | tail -c 50000
-
-# The cros_installer output is logged into the update engine log file,
-# so it is handled in the same way as update_engine.
-cros_installer=cat $(ls -1tr /var/log/update_engine | tail -5 | \
-  sed s.^./var/log/update_engine/.) | tail -c 50000
-
-# Dump the last 20 lines of the last two files in Chrome's system and user log
-# directories, along with the last 20 messages from the session manager.
-chrome=\
-  for f in $(ls -1rt /var/log/chrome/chrome_[0-9]* | tail -2) \
-    $(ls -1rt /home/chronos/u-*/log/chrome_[0-9]* 2>/dev/null | tail -2); do \
-    echo "===$f (tail)==="; \
-    tail -20 $f; \
-    echo EOF; \
-    echo; \
-  done; \
-  echo "===session_manager (tail)==="; \
-  awk '$3 ~ "^session_manager\[" { print }' /var/log/messages | tail -20; \
-  echo EOF
-
-# The following rule is used for generating additional diagnostics when
-# collection of user crashes fails.  This output should not be too large
-# as it is stored in memory.  The output format specified for 'ps' is the
-# same as with the "u" ("user-oriented") option, except it doesn't show
-# the commands' arguments (i.e. "comm" instead of "command").
-crash_reporter-user-collection=\
-  echo "===ps output==="; \
-  ps axw -o user,pid,%cpu,%mem,vsz,rss,tname,stat,start_time,bsdtime,comm | \
-    tail -c 25000; \
-  echo "===meminfo==="; \
-  cat /proc/meminfo
-
-# This rule is similar to the crash_reporter-user-collection rule, except it is
-# run for kernel errors reported through udev events.
-crash_reporter-udev-collection-change-card0-drm=\
-  for dri in /sys/kernel/debug/dri/*; do \
-    echo "===$dri/i915_error_state==="; \
-    cat $dri/i915_error_state; \
-  done
-
-# When trackpad driver cyapa detects some abnormal behavior, we collect
-# additional logs from kernel messages.
-crash_reporter-udev-collection-change--i2c-cyapa=\
-  /usr/sbin/kernel_log_collector.sh cyapa 30
-# When trackpad/touchscreen driver atmel_mxt_ts detects some abnormal behavior,
-# we collect additional logs from kernel messages.
-crash_reporter-udev-collection-change--i2c-atmel_mxt_ts=\
-  /usr/sbin/kernel_log_collector.sh atmel 30
-# When touch device noise are detected, we collect relevant logs.
-# (crosbug.com/p/16788)
-crash_reporter-udev-collection---TouchNoise=cat /var/log/touch_noise.log
-# Periodically collect touch event log for debugging (crosbug.com/p/17244)
-crash_reporter-udev-collection---TouchEvent=cat /var/log/touch_event.log
-
-# Collect the last 50 lines of /var/log/messages and /var/log/net.log for
-# intel wifi driver (iwlwifi) for debugging purpose.
-crash_reporter-udev-collection-devcoredump-iwlwifi=\
-  echo "===/var/log/messages==="; \
-  tail -n 50 /var/log/messages; \
-  echo "===/var/log/net.log==="; \
-  tail -n 50 /var/log/net.log; \
-  echo EOF
-
-# Dump the last 50 lines of the last two powerd log files -- if the job has
-# already restarted, we want to see the end of the previous instance's logs.
-powerd=\
-  for f in $(ls -1tr /var/log/power_manager/powerd.[0-9]* | tail -2); do \
-    echo "===$(basename $f) (tail)==="; \
-    tail -50 $f; \
-    echo EOF; \
-  done
-# If power_supply_info aborts (due to e.g. a bad battery), its failure message
-# could end up in various places depending on which process was running it.
-# Attach the end of powerd's log since it might've also logged the underlying
-# problem.
-power_supply_info=\
-  echo "===powerd.LATEST (tail)==="; \
-  tail -50 /var/log/power_manager/powerd.LATEST; \
-  echo EOF
-# powerd_setuid_helper gets run by powerd, so its stdout/stderr will be mixed in
-# with powerd's stdout/stderr.
-powerd_setuid_helper=\
-  echo "===powerd.OUT (tail)==="; \
-  tail -50 /var/log/powerd.out; \
-  echo EOF
-
-# The following rules are only for testing purposes.
-crash_log_test=echo hello world
-crash_log_recursion_test=sleep 1 && \
-  /usr/local/autotest/tests/crash_log_recursion_test
diff --git a/crash_reporter/crash_reporter_logs_test.cc b/crash_reporter/crash_reporter_logs_test.cc
deleted file mode 100644
index 77f5a7f..0000000
--- a/crash_reporter/crash_reporter_logs_test.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <string>
-
-#include <base/files/file_path.h>
-#include <brillo/key_value_store.h>
-#include <gtest/gtest.h>
-
-namespace {
-
-// Name of the checked-in configuration file containing log-collection commands.
-const char kConfigFile[] = "/system/etc/crash_reporter_logs.conf";
-
-// Signature name for crash_reporter user collection.
-// kConfigFile is expected to contain this entry.
-const char kUserCollectorSignature[] = "crash_reporter-user-collection";
-
-}  // namespace
-
-// Tests that the config file is parsable and that Chrome is listed.
-TEST(CrashReporterLogsTest, ReadConfig) {
-  brillo::KeyValueStore store;
-  ASSERT_TRUE(store.Load(base::FilePath(kConfigFile)));
-  std::string command;
-  EXPECT_TRUE(store.GetString(kUserCollectorSignature, &command));
-  EXPECT_FALSE(command.empty());
-}
diff --git a/crash_reporter/crash_sender b/crash_reporter/crash_sender
deleted file mode 100755
index a430ab5..0000000
--- a/crash_reporter/crash_sender
+++ /dev/null
@@ -1,719 +0,0 @@
-#!/system/bin/sh
-
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-set -e
-
-# Default product ID in crash report (used if GOOGLE_CRASH_* is undefined).
-BRILLO_PRODUCT=Brillo
-
-# Base directory that contains any crash reporter state files.
-CRASH_STATE_DIR="/data/misc/crash_reporter"
-
-# File containing crash_reporter's anonymized guid.
-GUID_FILE="${CRASH_STATE_DIR}/guid"
-
-# Crash sender lock in case the sender is already running.
-CRASH_SENDER_LOCK="${CRASH_STATE_DIR}/lock/crash_sender"
-
-# Path to file that indicates a crash test is currently running.
-CRASH_TEST_IN_PROGRESS_FILE="${CRASH_STATE_DIR}/tmp/crash-test-in-progress"
-
-# Set this to 1 in the environment to allow uploading crash reports
-# for unofficial versions.
-FORCE_OFFICIAL=${FORCE_OFFICIAL:-0}
-
-# Path to hardware class description.
-HWCLASS_PATH="/sys/devices/platform/chromeos_acpi/HWID"
-
-# Path to file that indicates this is a developer image.
-LEAVE_CORE_FILE="${CRASH_STATE_DIR}/.leave_core"
-
-# Path to list_proxies.
-LIST_PROXIES="list_proxies"
-
-# Maximum crashes to send per day.
-MAX_CRASH_RATE=${MAX_CRASH_RATE:-32}
-
-# File whose existence mocks crash sending.  If empty we pretend the
-# crash sending was successful, otherwise unsuccessful.
-MOCK_CRASH_SENDING="${CRASH_STATE_DIR}/tmp/mock-crash-sending"
-
-# Set this to 1 in the environment to pretend to have booted in developer
-# mode.  This is used by autotests.
-MOCK_DEVELOPER_MODE=${MOCK_DEVELOPER_MODE:-0}
-
-# Ignore PAUSE_CRASH_SENDING file if set.
-OVERRIDE_PAUSE_SENDING=${OVERRIDE_PAUSE_SENDING:-0}
-
-# File whose existence causes crash sending to be delayed (for testing).
-# Must be stateful to enable testing kernel crashes.
-PAUSE_CRASH_SENDING="${CRASH_STATE_DIR}/lock/crash_sender_paused"
-
-# Path to a directory of restricted certificates which includes
-# a certificate for the crash server.
-RESTRICTED_CERTIFICATES_PATH="/system/etc/security/cacerts"
-RESTRICTED_CERTIFICATES_PATH_GOOGLE="/system/etc/security/cacerts_google"
-
-# File whose existence implies we're running and not to start again.
-RUN_FILE="${CRASH_STATE_DIR}/run/crash_sender.pid"
-
-# Maximum time to sleep between sends.
-SECONDS_SEND_SPREAD=${SECONDS_SEND_SPREAD:-600}
-
-# Set this to 1 to allow uploading of device coredumps.
-DEVCOREDUMP_UPLOAD_FLAG_FILE="${CRASH_STATE_DIR}/device_coredump_upload_allowed"
-
-# The weave configuration file.
-WEAVE_CONF_FILE="/etc/weaved/weaved.conf"
-
-# The os-release.d folder.
-OSRELEASED_FOLDER="/etc/os-release.d"
-
-# The syslog tag for all logging we emit.
-TAG="$(basename $0)[$$]"
-
-# Directory to store timestamp files indicating the uploads in the past 24
-# hours.
-TIMESTAMPS_DIR="${CRASH_STATE_DIR}/crash_sender"
-
-# Temp directory for this process.
-TMP_DIR=""
-
-# Crash report log file.
-CRASH_LOG="${CRASH_STATE_DIR}/log/uploads.log"
-
-lecho() {
-  log -t "${TAG}" "$@"
-}
-
-lwarn() {
-  lecho -psyslog.warn "$@"
-}
-
-# Returns true if mock is enabled.
-is_mock() {
-  [ -f "${MOCK_CRASH_SENDING}" ] && return 0
-  return 1
-}
-
-is_mock_successful() {
-  local mock_in=$(cat "${MOCK_CRASH_SENDING}")
-  [ "${mock_in}" = "" ] && return 0  # empty file means success
-  return 1
-}
-
-cleanup() {
-  if [ -n "${TMP_DIR}" ]; then
-    rm -rf "${TMP_DIR}"
-  fi
-  rm -f "${RUN_FILE}"
-  if [ -n "${CRASH_SENDER_LOCK}" ]; then
-    rm -rf "${CRASH_SENDER_LOCK}"
-  fi
-  crash_done
-}
-
-crash_done() {
-  if is_mock; then
-    # For testing purposes, emit a message to log so that we
-    # know when the test has received all the messages from this run.
-    lecho "crash_sender done."
-  fi
-}
-
-is_official_image() {
-  [ ${FORCE_OFFICIAL} -ne 0 ] && return 0
-  if [ "$(getprop ro.secure)" = "1" ]; then
-    return 0
-  else
-    return 1
-  fi
-}
-
-# Returns 0 if the a crash test is currently running.  NOTE: Mirrors
-# crash_collector.cc:CrashCollector::IsCrashTestInProgress().
-is_crash_test_in_progress() {
-  [ -f "${CRASH_TEST_IN_PROGRESS_FILE}" ] && return 0
-  return 1
-}
-
-# Returns 0 if we should consider ourselves to be running on a developer
-# image.  NOTE: Mirrors crash_collector.cc:CrashCollector::IsDeveloperImage().
-is_developer_image() {
-  # If we're testing crash reporter itself, we don't want to special-case
-  # for developer images.
-  is_crash_test_in_progress && return 1
-  [ -f "${LEAVE_CORE_FILE}" ] && return 0
-  return 1
-}
-
-# Returns 0 if we should consider ourselves to be running on a test image.
-is_test_image() {
-  # If we're testing crash reporter itself, we don't want to special-case
-  # for test images.
-  is_crash_test_in_progress && return 1
-  case $(get_channel) in
-  test*) return 0;;
-  esac
-  return 1
-}
-
-# Returns 0 if the machine booted up in developer mode.
-is_developer_mode() {
-  [ ${MOCK_DEVELOPER_MODE} -ne 0 ] && return 0
-  # If we're testing crash reporter itself, we don't want to special-case
-  # for developer mode.
-  is_crash_test_in_progress && return 1
-  if [ "$(getprop ro.debuggable)" = "1" ]; then
-    return 0
-  else
-    return 1
-  fi
-}
-
-# Returns the path of the certificates directory to be used when sending
-# reports to the crash server.
-# If crash_reporter.full_certs=1, return the full certificates path.
-# Otherwise return the Google-specific certificates path.
-get_certificates_path() {
-  if [ "$(getprop crash_reporter.full_certs)" = "1" ]; then
-    echo "${RESTRICTED_CERTIFICATES_PATH}"
-  else
-    echo "${RESTRICTED_CERTIFICATES_PATH_GOOGLE}"
-  fi
-}
-
-# Return 0 if the uploading of device coredumps is allowed.
-is_device_coredump_upload_allowed() {
-  [ -f "${DEVCOREDUMP_UPLOAD_FLAG_FILE}" ] && return 0
-  return 1
-}
-
-# Generate a uniform random number in 0..max-1.
-# POSIX arithmetic expansion requires support of at least signed long integers.
-# On 32-bit systems, that may mean 32-bit signed integers, in which case the
-# 32-bit random number read from /dev/urandom may be interpreted as negative
-# when used inside an arithmetic expansion (since the high bit might be set).
-# mksh at least is known to behave this way.
-# For this case, simply take the absolute value, which will still give a
-# roughly uniform random distribution for the modulo (as we are merely ignoring
-# the high/sign bit).
-# See corresponding Arithmetic Expansion and Arithmetic Expression sections:
-# POSIX: http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_04
-# mksh: http://linux.die.net/man/1/mksh
-generate_uniform_random() {
-  local max=$1
-  local random="$(od -An -N4 -tu /dev/urandom)"
-  echo $(((random < 0 ? -random : random) % max))
-}
-
-# Check if sending a crash now does not exceed the maximum 24hr rate and
-# commit to doing so, if not.
-check_rate() {
-  mkdir -p ${TIMESTAMPS_DIR}
-  # Only consider minidumps written in the past 24 hours by removing all older.
-  find "${TIMESTAMPS_DIR}" -mindepth 1 -mtime +1 \
-      -exec rm -- '{}' ';'
-  local sends_in_24hrs=$(echo "${TIMESTAMPS_DIR}"/* | wc -w)
-  lecho "Current send rate: ${sends_in_24hrs}sends/24hrs"
-  if [ ${sends_in_24hrs} -ge ${MAX_CRASH_RATE} ]; then
-    lecho "Cannot send more crashes:"
-    lecho "  current ${sends_in_24hrs}send/24hrs >= " \
-          "max ${MAX_CRASH_RATE}send/24hrs"
-    return 1
-  fi
-  mktemp "${TIMESTAMPS_DIR}"/XXXXXX > /dev/null
-  return 0
-}
-
-# Gets the base part of a crash report file, such as name.01234.5678.9012 from
-# name.01234.5678.9012.meta or name.01234.5678.9012.log.tar.xz.  We make sure
-# "name" is sanitized in CrashCollector::Sanitize to not include any periods.
-get_base() {
-  echo "$1" | cut -d. -f-4
-}
-
-get_extension() {
-  local extension="${1##*.}"
-  local filename="${1%.*}"
-  # For gzipped file, we ignore .gz and get the real extension
-  if [ "${extension}" = "gz" ]; then
-    echo "${filename##*.}"
-  else
-    echo "${extension}"
-  fi
-}
-
-# Return which kind of report the given metadata file relates to
-get_kind() {
-  local payload="$(get_key_value "$1" "payload")"
-  if [ ! -r "${payload}" ]; then
-    lecho "Missing payload: ${payload}"
-    echo "undefined"
-    return
-  fi
-  local kind="$(get_extension "${payload}")"
-  if [ "${kind}" = "dmp" ]; then
-    echo "minidump"
-    return
-  fi
-  echo "${kind}"
-}
-
-get_key_value() {
-  local file="$1" key="$2" value
-
-  if [ -f "${file}/${key}" ]; then
-    # Get the value from a folder where each key is its own file.  The key
-    # file's entire contents is the value.
-    value=$(cat "${file}/${key}")
-  elif [ -f "${file}" ]; then
-    # Get the value from a file that has multiple key=value combinations.
-    # Return the first entry.  There shouldn't be more than one anyways.
-    # Substr at length($1) + 2 skips past the key and following = sign (awk
-    # uses 1-based indexes), but preserves embedded = characters.
-    value=$(sed -n "/^${key}[[:space:]]*=/{s:^[^=]*=::p;q}" "${file}")
-  fi
-
-  echo "${value:-undefined}"
-}
-
-get_keys() {
-  local file="$1" regex="$2"
-
-  cut -d '=' -f1 "${file}" | grep --color=never "${regex}"
-}
-
-# Return the channel name (sans "-channel" suffix).
-get_channel() {
-  getprop ro.product.channel | sed 's:-channel$::'
-}
-
-# Return the hardware class or "undefined".
-get_hardware_class() {
-  if [ -r "${HWCLASS_PATH}" ]; then
-    cat "${HWCLASS_PATH}"
-  else
-    echo "undefined"
-  fi
-}
-
-# Return the log string filtered with only JSON-safe white-listed characters.
-filter_log_string() {
-  echo "$1" | tr -cd '[:alnum:]_.\-:;'
-}
-
-send_crash() {
-  local meta_path="$1"
-  local report_payload="$(get_key_value "${meta_path}" "payload")"
-  local kind="$(get_kind "${meta_path}")"
-  local exec_name="$(get_key_value "${meta_path}" "exec_name")"
-  local url="$(get_key_value "${OSRELEASED_FOLDER}" "crash_server")"
-  local bdk_version="$(get_key_value "${meta_path}" "bdk_version")"
-  local hwclass="$(get_hardware_class)"
-  local write_payload_size="$(get_key_value "${meta_path}" "payload_size")"
-  local log="$(get_key_value "${meta_path}" "log")"
-  local sig="$(get_key_value "${meta_path}" "sig")"
-  local send_payload_size="$(stat -c "%s" "${report_payload}" 2>/dev/null)"
-  local product="$(get_key_value "${meta_path}" "product_id")"
-  local version="$(get_key_value "${meta_path}" "product_version")"
-  local upload_prefix="$(get_key_value "${meta_path}" "upload_prefix")"
-  local guid
-  local model_manifest_id="$(get_key_value "${WEAVE_CONF_FILE}" "model_id")"
-
-  # If crash_reporter.server is not set return with an error.
-  if [ -z "${url}" ]; then
-    lecho "Configuration error: crash_reporter.server not set."
-    return 1
-  fi
-
-  set -- \
-    -F "write_payload_size=${write_payload_size}" \
-    -F "send_payload_size=${send_payload_size}"
-  if [ "${sig}" != "undefined" ]; then
-    set -- "$@" \
-      -F "sig=${sig}" \
-      -F "sig2=${sig}"
-  fi
-  if [ -r "${report_payload}" ]; then
-    set -- "$@" \
-      -F "upload_file_${kind}=@${report_payload}"
-  fi
-  if [ "${log}" != "undefined" -a -r "${log}" ]; then
-    set -- "$@" \
-      -F "log=@${log}"
-  fi
-
-  if [ "${upload_prefix}" = "undefined" ]; then
-    upload_prefix=""
-  fi
-
-  # Grab any variable that begins with upload_.
-  local v
-  for k in $(get_keys "${meta_path}" "^upload_"); do
-    v="$(get_key_value "${meta_path}" "${k}")"
-    case ${k} in
-      # Product & version are handled separately.
-      upload_var_prod) ;;
-      upload_var_ver) ;;
-      upload_var_*)
-        set -- "$@" -F "${upload_prefix}${k#upload_var_}=${v}"
-        ;;
-      upload_file_*)
-        if [ -r "${v}" ]; then
-          set -- "$@" -F "${upload_prefix}${k#upload_file_}=@${v}"
-        fi
-        ;;
-    esac
-  done
-
-  # If ID or VERSION_ID is undefined, we use the default product name
-  # and bdk_version from /etc/os-release.d.
-  if [ "${product}" = "undefined" ]; then
-    product="${BRILLO_PRODUCT}"
-  fi
-  if [ "${version}" = "undefined" ]; then
-    version="${bdk_version}"
-  fi
-
-  local image_type
-  if is_test_image; then
-    image_type="test"
-  elif is_developer_image; then
-    image_type="dev"
-  elif [ ${FORCE_OFFICIAL} -ne 0 ]; then
-    image_type="force-official"
-  elif is_mock && ! is_mock_successful; then
-    image_type="mock-fail"
-  fi
-
-  local boot_mode
-  if is_developer_mode; then
-    boot_mode="dev"
-  fi
-
-  # Need to strip dashes ourselves as Chrome preserves it in the file
-  # nowadays.  This is also what the Chrome breakpad client does.
-  guid=$(tr -d '-' < "${GUID_FILE}")
-
-  local error_type="$(get_key_value "${meta_path}" "error_type")"
-  [ "${error_type}" = "undefined" ] && error_type=
-
-  lecho "Sending crash:"
-  if [ "${product}" != "${BRILLO_PRODUCT}" ]; then
-    lecho "  Sending crash report on behalf of ${product}"
-  fi
-  lecho "  Metadata: ${meta_path} (${kind})"
-  lecho "  Payload: ${report_payload}"
-  lecho "  Version: ${version}"
-  lecho "  Bdk Version: ${bdk_version}"
-  [ -n "${image_type}" ] && lecho "  Image type: ${image_type}"
-  [ -n "${boot_mode}" ] && lecho "  Boot mode: ${boot_mode}"
-  if is_mock; then
-    lecho "  Product: ${product}"
-    lecho "  URL: ${url}"
-    lecho "  HWClass: ${hwclass}"
-    lecho "  write_payload_size: ${write_payload_size}"
-    lecho "  send_payload_size: ${send_payload_size}"
-    if [ "${log}" != "undefined" ]; then
-      lecho "  log: @${log}"
-    fi
-    if [ "${sig}" != "undefined" ]; then
-      lecho "  sig: ${sig}"
-    fi
-  fi
-  lecho "  Exec name: ${exec_name}"
-  [ -n "${error_type}" ] && lecho "  Error type: ${error_type}"
-  if is_mock; then
-    if ! is_mock_successful; then
-      lecho "Mocking unsuccessful send"
-      return 1
-    fi
-    lecho "Mocking successful send"
-    return 0
-  fi
-
-  # Read in the first proxy, if any, for a given URL.  NOTE: The
-  # double-quotes are necessary due to a bug in dash with the "local"
-  # builtin command and values that have spaces in them (see
-  # "https://bugs.launchpad.net/ubuntu/+source/dash/+bug/139097").
-  if [ -f "${LIST_PROXIES}" ]; then
-    local proxy ret
-    proxy=$("${LIST_PROXIES}" --quiet "${url}")
-    ret=$?
-    if [ ${ret} -ne 0 ]; then
-      proxy=''
-      lwarn "Listing proxies failed with exit code ${ret}"
-    else
-      proxy=$(echo "${proxy}" | head -1)
-    fi
-  fi
-  # if a direct connection should be used, unset the proxy variable.
-  [ "${proxy}" = "direct://" ] && proxy=
-  local report_id="${TMP_DIR}/report_id"
-  local curl_stderr="${TMP_DIR}/curl_stderr"
-
-  set +e
-  curl "${url}" -f -v ${proxy:+--proxy "$proxy"} \
-    --capath "$(get_certificates_path)" --ciphers HIGH \
-    -F "prod=${product}" \
-    -F "ver=${version}" \
-    -F "bdk_version=${bdk_version}" \
-    -F "hwclass=${hwclass}" \
-    -F "exec_name=${exec_name}" \
-    -F "model_manifest_id=${model_manifest_id}" \
-    ${image_type:+-F "image_type=${image_type}"} \
-    ${boot_mode:+-F "boot_mode=${boot_mode}"} \
-    ${error_type:+-F "error_type=${error_type}"} \
-    -F "guid=${guid}" \
-    -o "${report_id}" \
-    "$@" \
-    2>"${curl_stderr}"
-  curl_result=$?
-  set -e
-
-  if [ ${curl_result} -eq 0 ]; then
-    local id="$(cat "${report_id}")"
-    local timestamp="$(date +%s)"
-    local filter_prod="$(filter_log_string "${product}")"
-    local filter_exec="$(filter_log_string "${exec_name}")"
-    if [ "${filter_prod}" != "${product}" ]; then
-      lwarn "Product name filtered to: ${filter_prod}."
-    fi
-    if [ "${filter_exec}" != "${exec_name}" ]; then
-      lwarn "Exec name filtered to: ${filter_exec}."
-    fi
-    printf "{'time':%s,'id':'%s','product':'%s','exec_name':'%s'}\n" \
-      "${timestamp}" "${id}" "${filter_prod}" "${filter_exec}" >> "${CRASH_LOG}"
-    lecho "Crash report receipt ID ${id}"
-  else
-    lecho "Crash sending failed with exit code ${curl_result}: " \
-      "$(cat "${curl_stderr}")"
-  fi
-
-  rm -f "${report_id}"
-
-  return ${curl_result}
-}
-
-# *.meta files always end with done=1 so we can tell if they are complete.
-is_complete_metadata() {
-  grep -q "done=1" "$1"
-}
-
-# Remove the given report path.
-remove_report() {
-  local base="${1%.*}"
-  rm -f -- "${base}".*
-}
-
-# Send all crashes from the given directory.  This applies even when we're on a
-# 3G connection (see crosbug.com/3304 for discussion).
-send_crashes() {
-  local dir="$1"
-  lecho "Sending crashes for ${dir}"
-
-  if [ ! -d "${dir}" ]; then
-    return
-  fi
-
-  # Consider any old files which still have no corresponding meta file
-  # as orphaned, and remove them.
-  for old_file in $(find "${dir}" -mindepth 1 \
-                    -mtime +1 -type f); do
-    if [ ! -e "$(get_base "${old_file}").meta" ]; then
-      lecho "Removing old orphaned file: ${old_file}."
-      rm -f -- "${old_file}"
-    fi
-  done
-
-  # Look through all metadata (*.meta) files, oldest first.  That way, the rate
-  # limit does not stall old crashes if there's a high amount of new crashes
-  # coming in.
-  # For each crash report, first evaluate conditions that might lead to its
-  # removal to honor user choice and to free disk space as soon as possible,
-  # then decide whether it should be sent right now or kept for later sending.
-  for meta_path in $(ls -1tr "${dir}"/*.meta 2>/dev/null); do
-    lecho "Considering metadata ${meta_path}."
-
-    local kind=$(get_kind "${meta_path}")
-    if [ "${kind}" != "minidump" ] && \
-       [ "${kind}" != "kcrash" ] && \
-       [ "${kind}" != "log" ] &&
-       [ "${kind}" != "devcore" ]; then
-      lecho "Unknown report kind ${kind}.  Removing report."
-      remove_report "${meta_path}"
-      continue
-    fi
-
-    if ! is_complete_metadata "${meta_path}"; then
-      # This report is incomplete, so if it's old, just remove it.
-      local old_meta=$(find "${dir}" -mindepth 1 -name \
-        $(basename "${meta_path}") -mtime +1 -type f)
-      if [ -n "${old_meta}" ]; then
-        lecho "Removing old incomplete metadata."
-        remove_report "${meta_path}"
-      else
-        lecho "Ignoring recent incomplete metadata."
-      fi
-      continue
-    fi
-
-    # Ignore device coredump if device coredump uploading is not allowed.
-    if [ "${kind}" = "devcore" ] && ! is_device_coredump_upload_allowed; then
-      lecho "Ignoring device coredump. Device coredump upload not allowed."
-      continue
-    fi
-
-    if ! is_mock && ! is_official_image; then
-      lecho "Not an official OS version.  Removing crash."
-      remove_report "${meta_path}"
-      continue
-    fi
-
-    # Remove existing crashes in case user consent has not (yet) been given or
-    # has been revoked.  This must come after the guest mode check because
-    # metrics_client always returns "not consented" in guest mode.
-    if ! metrics_client -c; then
-      lecho "Crash reporting is disabled.  Removing crash."
-      remove_report "${meta_path}"
-      continue
-    fi
-
-    # Skip report if the upload rate is exceeded.  (Don't exit right now because
-    # subsequent reports may be candidates for deletion.)
-    if ! check_rate; then
-      lecho "Sending ${meta_path} would exceed rate.  Leaving for later."
-      continue
-    fi
-
-    # The .meta file should be written *after* all to-be-uploaded files that it
-    # references.  Nevertheless, as a safeguard, a hold-off time of thirty
-    # seconds after writing the .meta file is ensured.  Also, sending of crash
-    # reports is spread out randomly by up to SECONDS_SEND_SPREAD.  Thus, for
-    # the sleep call the greater of the two delays is used.
-    local now=$(date +%s)
-    local holdoff_time=$(($(stat -c "%Y" "${meta_path}") + 30 - ${now}))
-    local spread_time=$(generate_uniform_random "${SECONDS_SEND_SPREAD}")
-    local sleep_time
-    if [ ${spread_time} -gt ${holdoff_time} ]; then
-      sleep_time="${spread_time}"
-    else
-      sleep_time="${holdoff_time}"
-    fi
-    lecho "Scheduled to send in ${sleep_time}s."
-    if ! is_mock; then
-      if ! sleep "${sleep_time}"; then
-          lecho "Sleep failed"
-          return 1
-      fi
-    fi
-
-    # Try to upload.
-    if ! send_crash "${meta_path}"; then
-      lecho "Problem sending ${meta_path}, not removing."
-      continue
-    fi
-
-    # Send was successful, now remove.
-    lecho "Successfully sent crash ${meta_path} and removing."
-    remove_report "${meta_path}"
-  done
-}
-
-usage() {
-  cat <<EOF
-Usage: crash_sender [options]
-
-Options:
- -e <var>=<val>     Set env |var| to |val| (only some vars)
-EOF
-  exit ${1:-1}
-}
-
-parseargs() {
-  # Parse the command line arguments.
-  while [ $# -gt 0 ]; do
-    case $1 in
-    -e)
-      shift
-      case $1 in
-      FORCE_OFFICIAL=*|\
-      MAX_CRASH_RATE=*|\
-      MOCK_DEVELOPER_MODE=*|\
-      OVERRIDE_PAUSE_SENDING=*|\
-      SECONDS_SEND_SPREAD=*)
-        export "$1"
-        ;;
-      *)
-        lecho "Unknown var passed to -e: $1"
-        exit 1
-        ;;
-      esac
-      ;;
-    -h)
-      usage 0
-      ;;
-    *)
-      lecho "Unknown options: $*"
-      exit 1
-      ;;
-    esac
-    shift
-  done
-}
-
-main() {
-  parseargs "$@"
-
-  if [ -e "${PAUSE_CRASH_SENDING}" ] && \
-     [ ${OVERRIDE_PAUSE_SENDING} -eq 0 ]; then
-    lecho "Exiting early due to ${PAUSE_CRASH_SENDING}."
-    exit 1
-  fi
-
-  if is_test_image; then
-    lecho "Exiting early due to test image."
-    exit 1
-  fi
-
-  # We don't perform checks on this because we have a master lock with the
-  # CRASH_SENDER_LOCK file.  This pid file is for the system to keep track
-  # (like with autotests) that we're still running.
-  echo $$ > "${RUN_FILE}"
-
-  for dependency in "$(get_certificates_path)"; do
-    if [ ! -x "${dependency}" ]; then
-      lecho "Fatal: Crash sending disabled: ${dependency} not found."
-      exit 1
-    fi
-  done
-
-  TMP_DIR="$(mktemp -d "${CRASH_STATE_DIR}/tmp/crash_sender.XXXXXX")"
-
-  # Send system-wide crashes
-  send_crashes "${CRASH_STATE_DIR}/crash"
-}
-
-trap cleanup EXIT INT TERM
-
-#TODO(http://b/23937249): Change the locking logic back to using flock.
-if ! mkdir "${CRASH_SENDER_LOCK}" 2>/dev/null; then
-  lecho "Already running; quitting."
-  crash_done
-  exit 1
-fi
-main "$@"
diff --git a/crash_reporter/dbus_bindings/org.chromium.LibCrosService.xml b/crash_reporter/dbus_bindings/org.chromium.LibCrosService.xml
deleted file mode 100644
index 64b8b84..0000000
--- a/crash_reporter/dbus_bindings/org.chromium.LibCrosService.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-
-<node name="/org/chromium/LibCrosService"
-      xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
-  <interface name="org.chromium.LibCrosServiceInterface">
-    <method name="ResolveNetworkProxy">
-      <arg name="source_url" type="s" direction="in"/>
-      <arg name="signal_interface" type="s" direction="in"/>
-      <arg name="signal_name" type="s" direction="in"/>
-      <annotation name="org.chromium.DBus.Method.Kind" value="simple"/>
-    </method>
-  </interface>
-  <interface name="org.chromium.CrashReporterLibcrosProxyResolvedInterface">
-    <signal name="ProxyResolved">
-      <arg name="source_url" type="s" direction="out"/>
-      <arg name="proxy_info" type="s" direction="out"/>
-      <arg name="error_message" type="s" direction="out"/>
-    </signal>
-  </interface>
-</node>
diff --git a/crash_reporter/init/crash-reporter.conf b/crash_reporter/init/crash-reporter.conf
deleted file mode 100644
index 19f2cdb..0000000
--- a/crash_reporter/init/crash-reporter.conf
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-description     "Initialize crash reporting services"
-author          "chromium-os-dev@chromium.org"
-
-# This job merely initializes its service and then terminates; the
-# actual checking and reporting of crash dumps is triggered by an
-# hourly cron job.
-start on starting system-services
-
-pre-start script
-  mkdir -p /var/spool
-
-  # Only allow device coredumps on a "developer system".
-  if ! is_developer_end_user; then
-    # consumer end-user - disable device coredumps, if driver exists.
-    echo 1 > /sys/class/devcoredump/disabled || true
-  fi
-end script
-
-# crash_reporter uses argv[0] as part of the command line for
-# /proc/sys/kernel/core_pattern.  That command line is invoked by
-# the kernel, and can't rely on PATH, so argv[0] must be a full
-# path; we invoke it as such here.
-exec /sbin/crash_reporter --init
diff --git a/crash_reporter/init/crash-sender.conf b/crash_reporter/init/crash-sender.conf
deleted file mode 100644
index 892186f..0000000
--- a/crash_reporter/init/crash-sender.conf
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-description     "Run the crash sender periodically"
-author          "chromium-os-dev@chromium.org"
-
-start on starting system-services
-stop on stopping system-services
-
-exec periodic_scheduler 3600 14400 crash_sender /sbin/crash_sender
diff --git a/crash_reporter/init/warn-collector.conf b/crash_reporter/init/warn-collector.conf
deleted file mode 100644
index 3be80da..0000000
--- a/crash_reporter/init/warn-collector.conf
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-description "Runs a daemon which collects and reports kernel warnings"
-author      "chromium-os-dev@chromium.org"
-
-start on started system-services
-stop on stopping system-services
-respawn
-
-exec warn_collector
diff --git a/crash_reporter/kernel_collector.cc b/crash_reporter/kernel_collector.cc
deleted file mode 100644
index 68f2d9e..0000000
--- a/crash_reporter/kernel_collector.cc
+++ /dev/null
@@ -1,603 +0,0 @@
-/*
- * Copyright (C) 2012 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 "kernel_collector.h"
-
-#include <map>
-#include <sys/stat.h>
-
-#include <base/files/file_util.h>
-#include <base/logging.h>
-#include <base/strings/string_util.h>
-#include <base/strings/stringprintf.h>
-
-using base::FilePath;
-using base::StringPrintf;
-
-namespace {
-
-const char kDefaultKernelStackSignature[] = "kernel-UnspecifiedStackSignature";
-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.
-const size_t kMaxDumpRecords = 100;
-const pid_t kKernelPid = 0;
-const char kKernelSignatureKey[] = "sig";
-// Byte length of maximum human readable portion of a kernel crash signature.
-const int kMaxHumanStringLength = 40;
-const uid_t kRootUid = 0;
-// Time in seconds from the final kernel log message for a call stack
-// to count towards the signature of the kcrash.
-const int kSignatureTimestampWindow = 2;
-// Kernel log timestamp regular expression.
-const char kTimestampRegex[] = "^<.*>\\[\\s*(\\d+\\.\\d+)\\]";
-
-//
-// These regular expressions enable to us capture the PC in a backtrace.
-// The backtrace is obtained through dmesg or the kernel's preserved/kcrashmem
-// feature.
-//
-// For ARM we see:
-//   "<5>[   39.458982] PC is at write_breakme+0xd0/0x1b4"
-// For MIPS we see:
-//   "<5>[ 3378.552000] epc   : 804010f0 lkdtm_do_action+0x68/0x3f8"
-// For x86:
-//   "<0>[   37.474699] EIP: [<790ed488>] write_breakme+0x80/0x108
-//    SS:ESP 0068:e9dd3efc"
-//
-const char* const kPCRegex[] = {
-  0,
-  " PC is at ([^\\+ ]+).*",
-  " epc\\s+:\\s+\\S+\\s+([^\\+ ]+).*",  // MIPS has an exception program counter
-  " EIP: \\[<.*>\\] ([^\\+ ]+).*",  // X86 uses EIP for the program counter
-  " RIP  \\[<.*>\\] ([^\\+ ]+).*",  // X86_64 uses RIP for the program counter
-};
-
-static_assert(arraysize(kPCRegex) == KernelCollector::kArchCount,
-              "Missing Arch PC regexp");
-
-}  // namespace
-
-KernelCollector::KernelCollector()
-    : is_enabled_(false),
-      ramoops_dump_path_(kDumpPath),
-      records_(0),
-      // We expect crash dumps in the format of architecture we are built for.
-      arch_(GetCompilerArch()) {
-}
-
-KernelCollector::~KernelCollector() {
-}
-
-void KernelCollector::OverridePreservedDumpPath(const FilePath &file_path) {
-  ramoops_dump_path_ = file_path;
-}
-
-bool KernelCollector::ReadRecordToString(std::string *contents,
-                                         size_t current_record,
-                                         bool *record_found) {
-  // A record is a ramoops dump. It has an associated size of "record_size".
-  std::string record;
-  std::string captured;
-
-  // Ramoops appends a header to a crash which contains ==== followed by a
-  // timestamp. Ignore the header.
-  pcrecpp::RE record_re(
-      "====\\d+\\.\\d+\n(.*)",
-      pcrecpp::RE_Options().set_multiline(true).set_dotall(true));
-
-  pcrecpp::RE sanity_check_re("\n<\\d+>\\[\\s*(\\d+\\.\\d+)\\]");
-
-  FilePath ramoops_record;
-  GetRamoopsRecordPath(&ramoops_record, current_record);
-  if (!base::ReadFileToString(ramoops_record, &record)) {
-    LOG(ERROR) << "Unable to open " << ramoops_record.value();
-    return false;
-  }
-
-  *record_found = false;
-  if (record_re.FullMatch(record, &captured)) {
-    // Found a ramoops header, so strip the header and append the rest.
-    contents->append(captured);
-    *record_found = true;
-  } else if (sanity_check_re.PartialMatch(record.substr(0, 1024))) {
-    // pstore compression has been added since kernel 3.12. In order to
-    // decompress dmesg correctly, ramoops driver has to strip the header
-    // before handing over the record to the pstore driver, so we don't
-    // need to do it here anymore. However, the sanity check is needed because
-    // sometimes a pstore record is just a chunk of uninitialized memory which
-    // is not the result of a kernel crash. See crbug.com/443764
-    contents->append(record);
-    *record_found = true;
-  } else {
-    LOG(WARNING) << "Found invalid record at " << ramoops_record.value();
-  }
-
-  // Remove the record from pstore after it's found.
-  if (*record_found)
-    base::DeleteFile(ramoops_record, false);
-
-  return true;
-}
-
-void KernelCollector::GetRamoopsRecordPath(FilePath *path,
-                                           size_t record) {
-  // Disable error "format not a string literal, argument types not checked"
-  // because this is valid, but GNU apparently doesn't bother checking a const
-  // format string.
-  #pragma GCC diagnostic push
-  #pragma GCC diagnostic ignored "-Wformat-nonliteral"
-  *path = ramoops_dump_path_.Append(StringPrintf(kDumpFormat, record));
-  #pragma GCC diagnostic pop
-}
-
-bool KernelCollector::LoadParameters() {
-  // Discover how many ramoops records are being exported by the driver.
-  size_t count;
-
-  for (count = 0; count < kMaxDumpRecords; ++count) {
-    FilePath ramoops_record;
-    GetRamoopsRecordPath(&ramoops_record, count);
-
-    if (!base::PathExists(ramoops_record))
-      break;
-  }
-
-  records_ = count;
-  return (records_ > 0);
-}
-
-bool KernelCollector::LoadPreservedDump(std::string *contents) {
-  // Load dumps from the preserved memory and save them in contents.
-  // Since the system is set to restart on oops we won't actually ever have
-  // multiple records (only 0 or 1), but check in case we don't restart on
-  // oops in the future.
-  bool any_records_found = false;
-  bool record_found = false;
-  // clear contents since ReadFileToString actually appends to the string.
-  contents->clear();
-
-  for (size_t i = 0; i < records_; ++i) {
-    if (!ReadRecordToString(contents, i, &record_found)) {
-      break;
-    }
-    if (record_found) {
-      any_records_found = true;
-    }
-  }
-
-  if (!any_records_found) {
-    LOG(ERROR) << "No valid records found in " << ramoops_dump_path_.value();
-    return false;
-  }
-
-  return true;
-}
-
-void KernelCollector::StripSensitiveData(std::string *kernel_dump) {
-  // Strip any data that the user might not want sent up to the crash servers.
-  // We'll read in from kernel_dump and also place our output there.
-  //
-  // At the moment, the only sensitive data we strip is MAC addresses.
-
-  // Get rid of things that look like MAC addresses, since they could possibly
-  // give information about where someone has been.  This is strings that look
-  // like this: 11:22:33:44:55:66
-  // Complications:
-  // - Within a given kernel_dump, want to be able to tell when the same MAC
-  //   was used more than once.  Thus, we'll consistently replace the first
-  //   MAC found with 00:00:00:00:00:01, the second with ...:02, etc.
-  // - ACPI commands look like MAC addresses.  We'll specifically avoid getting
-  //   rid of those.
-  std::ostringstream result;
-  std::string pre_mac_str;
-  std::string mac_str;
-  std::map<std::string, std::string> mac_map;
-  pcrecpp::StringPiece input(*kernel_dump);
-
-  // This RE will find the next MAC address and can return us the data preceding
-  // the MAC and the MAC itself.
-  pcrecpp::RE mac_re("(.*?)("
-                     "[0-9a-fA-F][0-9a-fA-F]:"
-                     "[0-9a-fA-F][0-9a-fA-F]:"
-                     "[0-9a-fA-F][0-9a-fA-F]:"
-                     "[0-9a-fA-F][0-9a-fA-F]:"
-                     "[0-9a-fA-F][0-9a-fA-F]:"
-                     "[0-9a-fA-F][0-9a-fA-F])",
-                     pcrecpp::RE_Options()
-                       .set_multiline(true)
-                       .set_dotall(true));
-
-  // This RE will identify when the 'pre_mac_str' shows that the MAC address
-  // was really an ACPI cmd.  The full string looks like this:
-  //   ata1.00: ACPI cmd ef/10:03:00:00:00:a0 (SET FEATURES) filtered out
-  pcrecpp::RE acpi_re("ACPI cmd ef/$",
-                      pcrecpp::RE_Options()
-                        .set_multiline(true)
-                        .set_dotall(true));
-
-  // Keep consuming, building up a result string as we go.
-  while (mac_re.Consume(&input, &pre_mac_str, &mac_str)) {
-    if (acpi_re.PartialMatch(pre_mac_str)) {
-      // We really saw an ACPI command; add to result w/ no stripping.
-      result << pre_mac_str << mac_str;
-    } else {
-      // Found a MAC address; look up in our hash for the mapping.
-      std::string replacement_mac = mac_map[mac_str];
-      if (replacement_mac == "") {
-        // It wasn't present, so build up a replacement string.
-        int mac_id = mac_map.size();
-
-        // Handle up to 2^32 unique MAC address; overkill, but doesn't hurt.
-        replacement_mac = StringPrintf("00:00:%02x:%02x:%02x:%02x",
-                                       (mac_id & 0xff000000) >> 24,
-                                       (mac_id & 0x00ff0000) >> 16,
-                                       (mac_id & 0x0000ff00) >> 8,
-                                       (mac_id & 0x000000ff));
-        mac_map[mac_str] = replacement_mac;
-      }
-
-      // Dump the string before the MAC and the fake MAC address into result.
-      result << pre_mac_str << replacement_mac;
-    }
-  }
-
-  // One last bit of data might still be in the input.
-  result << input;
-
-  // We'll just assign right back to kernel_dump.
-  *kernel_dump = result.str();
-}
-
-bool KernelCollector::DumpDirMounted() {
-  struct stat st_parent;
-  if (stat(kDumpParentPath, &st_parent)) {
-    PLOG(WARNING) << "Could not stat " << kDumpParentPath;
-    return false;
-  }
-
-  struct stat st_dump;
-  if (stat(kDumpPath, &st_dump)) {
-    PLOG(WARNING) << "Could not stat " << kDumpPath;
-    return false;
-  }
-
-  if (st_parent.st_dev == st_dump.st_dev) {
-    LOG(WARNING) << "Dump dir " << kDumpPath << " not mounted";
-    return false;
-  }
-
-  return true;
-}
-
-bool KernelCollector::Enable() {
-  if (arch_ == kArchUnknown || arch_ >= kArchCount ||
-      kPCRegex[arch_] == nullptr) {
-    LOG(WARNING) << "KernelCollector does not understand this architecture";
-    return false;
-  }
-
-  if (!DumpDirMounted()) {
-    LOG(WARNING) << "Kernel does not support crash dumping";
-    return false;
-  }
-
-  // To enable crashes, we will eventually need to set
-  // the chnv bit in BIOS, but it does not yet work.
-  LOG(INFO) << "Enabling kernel crash handling";
-  is_enabled_ = true;
-  return true;
-}
-
-// Hash a string to a number.  We define our own hash function to not
-// be dependent on a C++ library that might change.  This function
-// uses basically the same approach as tr1/functional_hash.h but with
-// a larger prime number (16127 vs 131).
-static unsigned HashString(const std::string &input) {
-  unsigned hash = 0;
-  for (size_t i = 0; i < input.length(); ++i)
-    hash = hash * 16127 + input[i];
-  return hash;
-}
-
-void KernelCollector::ProcessStackTrace(
-    pcrecpp::StringPiece kernel_dump,
-    bool print_diagnostics,
-    unsigned *hash,
-    float *last_stack_timestamp,
-    bool *is_watchdog_crash) {
-  pcrecpp::RE line_re("(.+)", pcrecpp::MULTILINE());
-  pcrecpp::RE stack_trace_start_re(std::string(kTimestampRegex) +
-        " (Call Trace|Backtrace):$");
-
-  // Match lines such as the following and grab out "function_name".
-  // The ? may or may not be present.
-  //
-  // For ARM:
-  // <4>[ 3498.731164] [<c0057220>] ? (function_name+0x20/0x2c) from
-  // [<c018062c>] (foo_bar+0xdc/0x1bc)
-  //
-  // For MIPS:
-  // <5>[ 3378.656000] [<804010f0>] lkdtm_do_action+0x68/0x3f8
-  //
-  // For X86:
-  // <4>[ 6066.849504]  [<7937bcee>] ? function_name+0x66/0x6c
-  //
-  pcrecpp::RE stack_entry_re(std::string(kTimestampRegex) +
-    "\\s+\\[<[[:xdigit:]]+>\\]"      // Matches "  [<7937bcee>]"
-    "([\\s\\?(]+)"                   // Matches " ? (" (ARM) or " ? " (X86)
-    "([^\\+ )]+)");                  // Matches until delimiter reached
-  std::string line;
-  std::string hashable;
-  std::string previous_hashable;
-  bool is_watchdog = false;
-
-  *hash = 0;
-  *last_stack_timestamp = 0;
-
-  // Find the last and second-to-last stack traces.  The latter is used when
-  // the panic is from a watchdog timeout.
-  while (line_re.FindAndConsume(&kernel_dump, &line)) {
-    std::string certainty;
-    std::string function_name;
-    if (stack_trace_start_re.PartialMatch(line, last_stack_timestamp)) {
-      if (print_diagnostics) {
-        printf("Stack trace starting.%s\n",
-               hashable.empty() ? "" : "  Saving prior trace.");
-      }
-      previous_hashable = hashable;
-      hashable.clear();
-      is_watchdog = false;
-    } else if (stack_entry_re.PartialMatch(line,
-                                           last_stack_timestamp,
-                                           &certainty,
-                                           &function_name)) {
-      bool is_certain = certainty.find('?') == std::string::npos;
-      if (print_diagnostics) {
-        printf("@%f: stack entry for %s (%s)\n",
-               *last_stack_timestamp,
-               function_name.c_str(),
-               is_certain ? "certain" : "uncertain");
-      }
-      // Do not include any uncertain (prefixed by '?') frames in our hash.
-      if (!is_certain)
-        continue;
-      if (!hashable.empty())
-        hashable.append("|");
-      if (function_name == "watchdog_timer_fn" ||
-          function_name == "watchdog") {
-        is_watchdog = true;
-      }
-      hashable.append(function_name);
-    }
-  }
-
-  // If the last stack trace contains a watchdog function we assume the panic
-  // is from the watchdog timer, and we hash the previous stack trace rather
-  // than the last one, assuming that the previous stack is that of the hung
-  // thread.
-  //
-  // In addition, if the hashable is empty (meaning all frames are uncertain,
-  // for whatever reason) also use the previous frame, as it cannot be any
-  // worse.
-  if (is_watchdog || hashable.empty()) {
-    hashable = previous_hashable;
-  }
-
-  *hash = HashString(hashable);
-  *is_watchdog_crash = is_watchdog;
-
-  if (print_diagnostics) {
-    printf("Hash based on stack trace: \"%s\" at %f.\n",
-           hashable.c_str(), *last_stack_timestamp);
-  }
-}
-
-// static
-KernelCollector::ArchKind KernelCollector::GetCompilerArch() {
-#if defined(COMPILER_GCC) && defined(ARCH_CPU_ARM_FAMILY)
-  return kArchArm;
-#elif defined(COMPILER_GCC) && defined(ARCH_CPU_MIPS_FAMILY)
-  return kArchMips;
-#elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_64)
-  return kArchX86_64;
-#elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_FAMILY)
-  return kArchX86;
-#else
-  return kArchUnknown;
-#endif
-}
-
-bool KernelCollector::FindCrashingFunction(
-  pcrecpp::StringPiece kernel_dump,
-  bool print_diagnostics,
-  float stack_trace_timestamp,
-  std::string *crashing_function) {
-  float timestamp = 0;
-
-  // Use the correct regex for this architecture.
-  pcrecpp::RE eip_re(std::string(kTimestampRegex) + kPCRegex[arch_],
-                     pcrecpp::MULTILINE());
-
-  while (eip_re.FindAndConsume(&kernel_dump, &timestamp, crashing_function)) {
-    if (print_diagnostics) {
-      printf("@%f: found crashing function %s\n",
-             timestamp,
-             crashing_function->c_str());
-    }
-  }
-  if (timestamp == 0) {
-    if (print_diagnostics) {
-      printf("Found no crashing function.\n");
-    }
-    return false;
-  }
-  if (stack_trace_timestamp != 0 &&
-      abs(static_cast<int>(stack_trace_timestamp - timestamp))
-        > kSignatureTimestampWindow) {
-    if (print_diagnostics) {
-      printf("Found crashing function but not within window.\n");
-    }
-    return false;
-  }
-  if (print_diagnostics) {
-    printf("Found crashing function %s\n", crashing_function->c_str());
-  }
-  return true;
-}
-
-bool KernelCollector::FindPanicMessage(pcrecpp::StringPiece kernel_dump,
-                                       bool print_diagnostics,
-                                       std::string *panic_message) {
-  // Match lines such as the following and grab out "Fatal exception"
-  // <0>[  342.841135] Kernel panic - not syncing: Fatal exception
-  pcrecpp::RE kernel_panic_re(std::string(kTimestampRegex) +
-                              " Kernel panic[^\\:]*\\:\\s*(.*)",
-                              pcrecpp::MULTILINE());
-  float timestamp = 0;
-  while (kernel_panic_re.FindAndConsume(&kernel_dump,
-                                        &timestamp,
-                                        panic_message)) {
-    if (print_diagnostics) {
-      printf("@%f: panic message %s\n",
-             timestamp,
-             panic_message->c_str());
-    }
-  }
-  if (timestamp == 0) {
-    if (print_diagnostics) {
-      printf("Found no panic message.\n");
-    }
-    return false;
-  }
-  return true;
-}
-
-bool KernelCollector::ComputeKernelStackSignature(
-    const std::string &kernel_dump,
-    std::string *kernel_signature,
-    bool print_diagnostics) {
-  unsigned stack_hash = 0;
-  float last_stack_timestamp = 0;
-  std::string human_string;
-  bool is_watchdog_crash;
-
-  ProcessStackTrace(kernel_dump,
-                    print_diagnostics,
-                    &stack_hash,
-                    &last_stack_timestamp,
-                    &is_watchdog_crash);
-
-  if (!FindCrashingFunction(kernel_dump,
-                            print_diagnostics,
-                            last_stack_timestamp,
-                            &human_string)) {
-    if (!FindPanicMessage(kernel_dump, print_diagnostics, &human_string)) {
-      if (print_diagnostics) {
-        printf("Found no human readable string, using empty string.\n");
-      }
-      human_string.clear();
-    }
-  }
-
-  if (human_string.empty() && stack_hash == 0) {
-    if (print_diagnostics) {
-      printf("Found neither a stack nor a human readable string, failing.\n");
-    }
-    return false;
-  }
-
-  human_string = human_string.substr(0, kMaxHumanStringLength);
-  *kernel_signature = StringPrintf("%s-%s%s-%08X",
-                                   kKernelExecName,
-                                   (is_watchdog_crash ? "(HANG)-" : ""),
-                                   human_string.c_str(),
-                                   stack_hash);
-  return true;
-}
-
-bool KernelCollector::Collect() {
-  std::string kernel_dump;
-  FilePath root_crash_directory;
-
-  if (!LoadParameters()) {
-    return false;
-  }
-  if (!LoadPreservedDump(&kernel_dump)) {
-    return false;
-  }
-  StripSensitiveData(&kernel_dump);
-  if (kernel_dump.empty()) {
-    return false;
-  }
-  std::string signature;
-  if (!ComputeKernelStackSignature(kernel_dump, &signature, false)) {
-    signature = kDefaultKernelStackSignature;
-  }
-
-  std::string reason = "handling";
-  bool feedback = true;
-  if (IsDeveloperImage()) {
-    reason = "developer build - always dumping";
-    feedback = true;
-  } else if (!is_feedback_allowed_function_()) {
-    reason = "ignoring - no consent";
-    feedback = false;
-  }
-
-  LOG(INFO) << "Received prior crash notification from "
-            << "kernel (signature " << signature << ") (" << reason << ")";
-
-  if (feedback) {
-    count_crash_function_();
-
-    if (!GetCreatedCrashDirectoryByEuid(kRootUid,
-                                        &root_crash_directory,
-                                        nullptr)) {
-      return true;
-    }
-
-    std::string dump_basename =
-        FormatDumpBasename(kKernelExecName, time(nullptr), kKernelPid);
-    FilePath kernel_crash_path = root_crash_directory.Append(
-        StringPrintf("%s.kcrash", dump_basename.c_str()));
-
-    // We must use WriteNewFile instead of base::WriteFile as we
-    // do not want to write with root access to a symlink that an attacker
-    // might have created.
-    if (WriteNewFile(kernel_crash_path,
-                     kernel_dump.data(),
-                     kernel_dump.length()) !=
-        static_cast<int>(kernel_dump.length())) {
-      LOG(INFO) << "Failed to write kernel dump to "
-                << kernel_crash_path.value().c_str();
-      return true;
-    }
-
-    AddCrashMetaData(kKernelSignatureKey, signature);
-    WriteCrashMetaData(
-        root_crash_directory.Append(
-            StringPrintf("%s.meta", dump_basename.c_str())),
-        kKernelExecName,
-        kernel_crash_path.value());
-
-    LOG(INFO) << "Stored kcrash to " << kernel_crash_path.value();
-  }
-
-  return true;
-}
diff --git a/crash_reporter/kernel_collector.h b/crash_reporter/kernel_collector.h
deleted file mode 100644
index 206ee26..0000000
--- a/crash_reporter/kernel_collector.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CRASH_REPORTER_KERNEL_COLLECTOR_H_
-#define CRASH_REPORTER_KERNEL_COLLECTOR_H_
-
-#include <pcrecpp.h>
-
-#include <string>
-
-#include <base/files/file_path.h>
-#include <base/macros.h>
-#include <gtest/gtest_prod.h>  // for FRIEND_TEST
-
-#include "crash_collector.h"
-
-// Kernel crash collector.
-class KernelCollector : public CrashCollector {
- public:
-  // Enumeration to specify architecture type.
-  enum ArchKind {
-    kArchUnknown,
-    kArchArm,
-    kArchMips,
-    kArchX86,
-    kArchX86_64,
-
-    kArchCount  // Number of architectures.
-  };
-
-  KernelCollector();
-
-  ~KernelCollector() override;
-
-  void OverridePreservedDumpPath(const base::FilePath &file_path);
-
-  // Enable collection.
-  bool Enable();
-
-  // Returns true if the kernel collection currently enabled.
-  bool is_enabled() const { return is_enabled_; }
-
-  // Collect any preserved kernel crash dump. Returns true if there was
-  // a dump (even if there were problems storing the dump), false otherwise.
-  bool Collect();
-
-  // Compute a stack signature string from a kernel dump.
-  bool ComputeKernelStackSignature(const std::string &kernel_dump,
-                                   std::string *kernel_signature,
-                                   bool print_diagnostics);
-
-  // Set the architecture of the crash dumps we are looking at.
-  void set_arch(ArchKind arch) { arch_ = arch; }
-  ArchKind arch() const { return arch_; }
-
- private:
-  friend class KernelCollectorTest;
-  FRIEND_TEST(KernelCollectorTest, LoadPreservedDump);
-  FRIEND_TEST(KernelCollectorTest, StripSensitiveDataBasic);
-  FRIEND_TEST(KernelCollectorTest, StripSensitiveDataBulk);
-  FRIEND_TEST(KernelCollectorTest, StripSensitiveDataSample);
-  FRIEND_TEST(KernelCollectorTest, CollectOK);
-
-  virtual bool DumpDirMounted();
-
-  bool LoadPreservedDump(std::string *contents);
-  void StripSensitiveData(std::string *kernel_dump);
-
-  void GetRamoopsRecordPath(base::FilePath *path, size_t record);
-  bool LoadParameters();
-  bool HasMoreRecords();
-
-  // Read a record to string, modified from file_utils since that didn't
-  // provide a way to restrict the read length.
-  // Return value indicates (only) error state:
-  //  * false when we get an error (can't read from dump location).
-  //  * true if no error occured.
-  // Not finding a valid record is not an error state and is signaled by the
-  // record_found output parameter.
-  bool ReadRecordToString(std::string *contents,
-                          size_t current_record,
-                          bool *record_found);
-
-  void ProcessStackTrace(pcrecpp::StringPiece kernel_dump,
-                         bool print_diagnostics,
-                         unsigned *hash,
-                         float *last_stack_timestamp,
-                         bool *is_watchdog_crash);
-  bool FindCrashingFunction(pcrecpp::StringPiece kernel_dump,
-                            bool print_diagnostics,
-                            float stack_trace_timestamp,
-                            std::string *crashing_function);
-  bool FindPanicMessage(pcrecpp::StringPiece kernel_dump,
-                        bool print_diagnostics,
-                        std::string *panic_message);
-
-  // Returns the architecture kind for which we are built.
-  static ArchKind GetCompilerArch();
-
-  bool is_enabled_;
-  base::FilePath ramoops_dump_path_;
-  size_t records_;
-
-  // The architecture of kernel dump strings we are working with.
-  ArchKind arch_;
-
-  DISALLOW_COPY_AND_ASSIGN(KernelCollector);
-};
-
-#endif  // CRASH_REPORTER_KERNEL_COLLECTOR_H_
diff --git a/crash_reporter/kernel_collector_test.cc b/crash_reporter/kernel_collector_test.cc
deleted file mode 100644
index 015f624..0000000
--- a/crash_reporter/kernel_collector_test.cc
+++ /dev/null
@@ -1,677 +0,0 @@
-/*
- * Copyright (C) 2012 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 "kernel_collector_test.h"
-
-#include <unistd.h>
-
-#include <base/files/file_util.h>
-#include <base/files/scoped_temp_dir.h>
-#include <base/strings/string_util.h>
-#include <base/strings/stringprintf.h>
-#include <brillo/syslog_logging.h>
-#include <gtest/gtest.h>
-
-using base::FilePath;
-using base::StringPrintf;
-using brillo::FindLog;
-using brillo::GetLog;
-
-namespace {
-
-int s_crashes = 0;
-bool s_metrics = false;
-
-void CountCrash() {
-  ++s_crashes;
-}
-
-bool IsMetrics() {
-  return s_metrics;
-}
-
-}  // namespace
-
-class KernelCollectorTest : public ::testing::Test {
- protected:
-  void WriteStringToFile(const FilePath &file_path,
-                         const char *data) {
-    ASSERT_EQ(strlen(data), base::WriteFile(file_path, data, strlen(data)));
-  }
-
-  void SetUpSuccessfulCollect();
-  void ComputeKernelStackSignatureCommon();
-
-  const FilePath &kcrash_file() const { return test_kcrash_; }
-  const FilePath &test_crash_directory() const { return test_crash_directory_; }
-
-  KernelCollectorMock collector_;
-
- private:
-  void SetUp() override {
-    s_crashes = 0;
-    s_metrics = true;
-
-    EXPECT_CALL(collector_, SetUpDBus()).WillRepeatedly(testing::Return());
-
-    collector_.Initialize(CountCrash, IsMetrics);
-    ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
-    test_kcrash_ = scoped_temp_dir_.path().Append("kcrash");
-    ASSERT_TRUE(base::CreateDirectory(test_kcrash_));
-    collector_.OverridePreservedDumpPath(test_kcrash_);
-
-    test_kcrash_ = test_kcrash_.Append("dmesg-ramoops-0");
-    ASSERT_FALSE(base::PathExists(test_kcrash_));
-
-    test_crash_directory_ = scoped_temp_dir_.path().Append("crash_directory");
-    ASSERT_TRUE(base::CreateDirectory(test_crash_directory_));
-    brillo::ClearLog();
-  }
-
-  FilePath test_kcrash_;
-  FilePath test_crash_directory_;
-  base::ScopedTempDir scoped_temp_dir_;
-};
-
-TEST_F(KernelCollectorTest, ComputeKernelStackSignatureBase) {
-  // Make sure the normal build architecture is detected
-  EXPECT_NE(KernelCollector::kArchUnknown, collector_.arch());
-}
-
-TEST_F(KernelCollectorTest, LoadPreservedDump) {
-  ASSERT_FALSE(base::PathExists(kcrash_file()));
-  std::string dump;
-  dump.clear();
-
-  WriteStringToFile(kcrash_file(),
-      "CrashRecordWithoutRamoopsHeader\n<6>[    0.078852]");
-  ASSERT_TRUE(collector_.LoadParameters());
-  ASSERT_TRUE(collector_.LoadPreservedDump(&dump));
-  ASSERT_EQ("CrashRecordWithoutRamoopsHeader\n<6>[    0.078852]", dump);
-
-  WriteStringToFile(kcrash_file(), "====1.1\nsomething");
-  ASSERT_TRUE(collector_.LoadParameters());
-  ASSERT_TRUE(collector_.LoadPreservedDump(&dump));
-  ASSERT_EQ("something", dump);
-
-  WriteStringToFile(kcrash_file(), "\x01\x02\xfe\xff random blob");
-  ASSERT_TRUE(collector_.LoadParameters());
-  ASSERT_FALSE(collector_.LoadPreservedDump(&dump));
-  ASSERT_EQ("", dump);
-}
-
-TEST_F(KernelCollectorTest, EnableMissingKernel) {
-  ASSERT_FALSE(collector_.Enable());
-  ASSERT_FALSE(collector_.is_enabled());
-  ASSERT_TRUE(FindLog(
-      "Kernel does not support crash dumping"));
-  ASSERT_EQ(s_crashes, 0);
-}
-
-TEST_F(KernelCollectorTest, EnableOK) {
-  WriteStringToFile(kcrash_file(), "");
-  EXPECT_CALL(collector_, DumpDirMounted()).WillOnce(::testing::Return(true));
-  ASSERT_TRUE(collector_.Enable());
-  ASSERT_TRUE(collector_.is_enabled());
-  ASSERT_TRUE(FindLog("Enabling kernel crash handling"));
-  ASSERT_EQ(s_crashes, 0);
-}
-
-TEST_F(KernelCollectorTest, StripSensitiveDataBasic) {
-  // Basic tests of StripSensitiveData...
-
-  // Make sure we work OK with a string w/ no MAC addresses.
-  const std::string kCrashWithNoMacsOrig =
-      "<7>[111566.131728] PM: Entering mem sleep\n";
-  std::string crash_with_no_macs(kCrashWithNoMacsOrig);
-  collector_.StripSensitiveData(&crash_with_no_macs);
-  EXPECT_EQ(kCrashWithNoMacsOrig, crash_with_no_macs);
-
-  // Make sure that we handle the case where there's nothing before/after the
-  // MAC address.
-  const std::string kJustAMacOrig =
-      "11:22:33:44:55:66";
-  const std::string kJustAMacStripped =
-      "00:00:00:00:00:01";
-  std::string just_a_mac(kJustAMacOrig);
-  collector_.StripSensitiveData(&just_a_mac);
-  EXPECT_EQ(kJustAMacStripped, just_a_mac);
-
-  // Test MAC addresses crammed together to make sure it gets both of them.
-  //
-  // I'm not sure that the code does ideal on these two test cases (they don't
-  // look like two MAC addresses to me), but since we don't see them I think
-  // it's OK to behave as shown here.
-  const std::string kCrammedMacs1Orig =
-      "11:22:33:44:55:66:11:22:33:44:55:66";
-  const std::string kCrammedMacs1Stripped =
-      "00:00:00:00:00:01:00:00:00:00:00:01";
-  std::string crammed_macs_1(kCrammedMacs1Orig);
-  collector_.StripSensitiveData(&crammed_macs_1);
-  EXPECT_EQ(kCrammedMacs1Stripped, crammed_macs_1);
-
-  const std::string kCrammedMacs2Orig =
-      "11:22:33:44:55:6611:22:33:44:55:66";
-  const std::string kCrammedMacs2Stripped =
-      "00:00:00:00:00:0100:00:00:00:00:01";
-  std::string crammed_macs_2(kCrammedMacs2Orig);
-  collector_.StripSensitiveData(&crammed_macs_2);
-  EXPECT_EQ(kCrammedMacs2Stripped, crammed_macs_2);
-
-  // Test case-sensitiveness (we shouldn't be case-senstive).
-  const std::string kCapsMacOrig =
-      "AA:BB:CC:DD:EE:FF";
-  const std::string kCapsMacStripped =
-      "00:00:00:00:00:01";
-  std::string caps_mac(kCapsMacOrig);
-  collector_.StripSensitiveData(&caps_mac);
-  EXPECT_EQ(kCapsMacStripped, caps_mac);
-
-  const std::string kLowerMacOrig =
-      "aa:bb:cc:dd:ee:ff";
-  const std::string kLowerMacStripped =
-      "00:00:00:00:00:01";
-  std::string lower_mac(kLowerMacOrig);
-  collector_.StripSensitiveData(&lower_mac);
-  EXPECT_EQ(kLowerMacStripped, lower_mac);
-}
-
-TEST_F(KernelCollectorTest, StripSensitiveDataBulk) {
-  // Test calling StripSensitiveData w/ lots of MAC addresses in the "log".
-
-  // Test that stripping code handles more than 256 unique MAC addresses, since
-  // that overflows past the last byte...
-  // We'll write up some code that generates 258 unique MAC addresses.  Sorta
-  // cheating since the code is very similar to the current code in
-  // StripSensitiveData(), but would catch if someone changed that later.
-  std::string lotsa_macs_orig;
-  std::string lotsa_macs_stripped;
-  int i;
-  for (i = 0; i < 258; i++) {
-    lotsa_macs_orig += StringPrintf(" 11:11:11:11:%02X:%02x",
-                                  (i & 0xff00) >> 8, i & 0x00ff);
-    lotsa_macs_stripped += StringPrintf(" 00:00:00:00:%02X:%02x",
-                                     ((i+1) & 0xff00) >> 8, (i+1) & 0x00ff);
-  }
-  std::string lotsa_macs(lotsa_macs_orig);
-  collector_.StripSensitiveData(&lotsa_macs);
-  EXPECT_EQ(lotsa_macs_stripped, lotsa_macs);
-}
-
-TEST_F(KernelCollectorTest, StripSensitiveDataSample) {
-  // Test calling StripSensitiveData w/ some actual lines from a real crash;
-  // included two MAC addresses (though replaced them with some bogusness).
-  const std::string kCrashWithMacsOrig =
-      "<6>[111567.195339] ata1.00: ACPI cmd ef/10:03:00:00:00:a0 (SET FEATURES)"
-        " filtered out\n"
-      "<7>[108539.540144] wlan0: authenticate with 11:22:33:44:55:66 (try 1)\n"
-      "<7>[108539.554973] wlan0: associate with 11:22:33:44:55:66 (try 1)\n"
-      "<6>[110136.587583] usb0: register 'QCUSBNet2k' at usb-0000:00:1d.7-2,"
-        " QCUSBNet Ethernet Device, 99:88:77:66:55:44\n"
-      "<7>[110964.314648] wlan0: deauthenticated from 11:22:33:44:55:66"
-        " (Reason: 6)\n"
-      "<7>[110964.325057] phy0: Removed STA 11:22:33:44:55:66\n"
-      "<7>[110964.325115] phy0: Destroyed STA 11:22:33:44:55:66\n"
-      "<6>[110969.219172] usb0: register 'QCUSBNet2k' at usb-0000:00:1d.7-2,"
-        " QCUSBNet Ethernet Device, 99:88:77:66:55:44\n"
-      "<7>[111566.131728] PM: Entering mem sleep\n";
-  const std::string kCrashWithMacsStripped =
-      "<6>[111567.195339] ata1.00: ACPI cmd ef/10:03:00:00:00:a0 (SET FEATURES)"
-        " filtered out\n"
-      "<7>[108539.540144] wlan0: authenticate with 00:00:00:00:00:01 (try 1)\n"
-      "<7>[108539.554973] wlan0: associate with 00:00:00:00:00:01 (try 1)\n"
-      "<6>[110136.587583] usb0: register 'QCUSBNet2k' at usb-0000:00:1d.7-2,"
-        " QCUSBNet Ethernet Device, 00:00:00:00:00:02\n"
-      "<7>[110964.314648] wlan0: deauthenticated from 00:00:00:00:00:01"
-        " (Reason: 6)\n"
-      "<7>[110964.325057] phy0: Removed STA 00:00:00:00:00:01\n"
-      "<7>[110964.325115] phy0: Destroyed STA 00:00:00:00:00:01\n"
-      "<6>[110969.219172] usb0: register 'QCUSBNet2k' at usb-0000:00:1d.7-2,"
-        " QCUSBNet Ethernet Device, 00:00:00:00:00:02\n"
-      "<7>[111566.131728] PM: Entering mem sleep\n";
-  std::string crash_with_macs(kCrashWithMacsOrig);
-  collector_.StripSensitiveData(&crash_with_macs);
-  EXPECT_EQ(kCrashWithMacsStripped, crash_with_macs);
-}
-
-TEST_F(KernelCollectorTest, CollectPreservedFileMissing) {
-  ASSERT_FALSE(collector_.Collect());
-  ASSERT_FALSE(FindLog("Stored kcrash to "));
-  ASSERT_EQ(0, s_crashes);
-}
-
-void KernelCollectorTest::SetUpSuccessfulCollect() {
-  collector_.ForceCrashDirectory(test_crash_directory());
-  WriteStringToFile(kcrash_file(), "====1.1\nsomething");
-  ASSERT_EQ(0, s_crashes);
-}
-
-TEST_F(KernelCollectorTest, CollectOptedOut) {
-  SetUpSuccessfulCollect();
-  s_metrics = false;
-  ASSERT_TRUE(collector_.Collect());
-  ASSERT_TRUE(FindLog("(ignoring - no consent)"));
-  ASSERT_EQ(0, s_crashes);
-}
-
-TEST_F(KernelCollectorTest, CollectOK) {
-  SetUpSuccessfulCollect();
-  ASSERT_TRUE(collector_.Collect());
-  ASSERT_EQ(1, s_crashes);
-  ASSERT_TRUE(FindLog("(handling)"));
-  static const char kNamePrefix[] = "Stored kcrash to ";
-  std::string log = brillo::GetLog();
-  size_t pos = log.find(kNamePrefix);
-  ASSERT_NE(std::string::npos, pos)
-      << "Did not find string \"" << kNamePrefix << "\" in log: {\n"
-      << log << "}";
-  pos += strlen(kNamePrefix);
-  std::string filename = log.substr(pos, std::string::npos);
-  // Take the name up until \n
-  size_t end_pos = filename.find_first_of("\n");
-  ASSERT_NE(std::string::npos, end_pos);
-  filename = filename.substr(0, end_pos);
-  ASSERT_EQ(0, filename.find(test_crash_directory().value()));
-  ASSERT_TRUE(base::PathExists(FilePath(filename)));
-  std::string contents;
-  ASSERT_TRUE(base::ReadFileToString(FilePath(filename), &contents));
-  ASSERT_EQ("something", contents);
-}
-
-// Perform tests which are common across architectures
-void KernelCollectorTest::ComputeKernelStackSignatureCommon() {
-  std::string signature;
-
-  const char kStackButNoPC[] =
-      "<4>[ 6066.829029]  [<790340af>] __do_softirq+0xa6/0x143\n";
-  EXPECT_TRUE(
-      collector_.ComputeKernelStackSignature(kStackButNoPC, &signature, false));
-  EXPECT_EQ("kernel--83615F0A", signature);
-
-  const char kMissingEverything[] =
-      "<4>[ 6066.829029]  [<790340af>] ? __do_softirq+0xa6/0x143\n";
-  EXPECT_FALSE(
-      collector_.ComputeKernelStackSignature(kMissingEverything,
-                                             &signature,
-                                             false));
-
-  // Long message.
-  const char kTruncatedMessage[] =
-      "<0>[   87.485611] Kernel panic - not syncing: 01234567890123456789"
-          "01234567890123456789X\n";
-  EXPECT_TRUE(
-      collector_.ComputeKernelStackSignature(kTruncatedMessage,
-                                             &signature,
-                                             false));
-  EXPECT_EQ("kernel-0123456789012345678901234567890123456789-00000000",
-            signature);
-}
-
-TEST_F(KernelCollectorTest, ComputeKernelStackSignatureARM) {
-  const char kBugToPanic[] =
-      "<5>[  123.412524] Modules linked in:\n"
-      "<5>[  123.412534] CPU: 0    Tainted: G        W    "
-          "(2.6.37-01030-g51cee64 #153)\n"
-      "<5>[  123.412552] PC is at write_breakme+0xd0/0x1b4\n"
-      "<5>[  123.412560] LR is at write_breakme+0xc8/0x1b4\n"
-      "<5>[  123.412569] pc : [<c0058220>]    lr : [<c005821c>]    "
-          "psr: 60000013\n"
-      "<5>[  123.412574] sp : f4e0ded8  ip : c04d104c  fp : 000e45e0\n"
-      "<5>[  123.412581] r10: 400ff000  r9 : f4e0c000  r8 : 00000004\n"
-      "<5>[  123.412589] r7 : f4e0df80  r6 : f4820c80  r5 : 00000004  "
-          "r4 : f4e0dee8\n"
-      "<5>[  123.412598] r3 : 00000000  r2 : f4e0decc  r1 : c05f88a9  "
-          "r0 : 00000039\n"
-      "<5>[  123.412608] Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA "
-          "ARM  Segment user\n"
-      "<5>[  123.412617] Control: 10c53c7d  Table: 34dcc04a  DAC: 00000015\n"
-      "<0>[  123.412626] Process bash (pid: 1014, stack limit = 0xf4e0c2f8)\n"
-      "<0>[  123.412634] Stack: (0xf4e0ded8 to 0xf4e0e000)\n"
-      "<0>[  123.412641] dec0:                                              "
-          "         f4e0dee8 c0183678\n"
-      "<0>[  123.412654] dee0: 00000000 00000000 00677562 0000081f c06a6a78 "
-          "400ff000 f4e0dfb0 00000000\n"
-      "<0>[  123.412666] df00: bec7ab44 000b1719 bec7ab0c c004f498 bec7a314 "
-          "c024acc8 00000001 c018359c\n"
-      "<0>[  123.412679] df20: f4e0df34 c04d10fc f5803c80 271beb39 000e45e0 "
-          "f5803c80 c018359c c017bfe0\n"
-      "<0>[  123.412691] df40: 00000004 f4820c80 400ff000 f4e0df80 00000004 "
-          "f4e0c000 00000000 c01383e4\n"
-      "<0>[  123.412703] df60: f4820c80 400ff000 f4820c80 400ff000 00000000 "
-          "00000000 00000004 c0138578\n"
-      "<0>[  123.412715] df80: 00000000 00000000 00000004 00000000 00000004 "
-          "402f95d0 00000004 00000004\n"
-      "<0>[  123.412727] dfa0: c0054984 c00547c0 00000004 402f95d0 00000001 "
-          "400ff000 00000004 00000000\n"
-      "<0>[  123.412739] dfc0: 00000004 402f95d0 00000004 00000004 400ff000 "
-          "000c194c bec7ab58 000e45e0\n"
-      "<0>[  123.412751] dfe0: 00000000 bec7aad8 40232520 40284e9c 60000010 "
-          "00000001 00000000 00000000\n"
-      "<5>[   39.496577] Backtrace:\n"
-      "<5>[  123.412782] [<c0058220>] (__bug+0x20/0x2c) from [<c0183678>] "
-          "(write_breakme+0xdc/0x1bc)\n"
-      "<5>[  123.412798] [<c0183678>] (write_breakme+0xdc/0x1bc) from "
-          "[<c017bfe0>] (proc_reg_write+0x88/0x9c)\n";
-  std::string signature;
-
-  collector_.set_arch(KernelCollector::kArchArm);
-  EXPECT_TRUE(
-      collector_.ComputeKernelStackSignature(kBugToPanic, &signature, false));
-  EXPECT_EQ("kernel-write_breakme-97D3E92F", signature);
-
-  ComputeKernelStackSignatureCommon();
-}
-
-TEST_F(KernelCollectorTest, ComputeKernelStackSignatureMIPS) {
-  const char kBugToPanic[] =
-      "<5>[ 3378.472000] lkdtm: Performing direct entry BUG\n"
-      "<5>[ 3378.476000] Kernel bug detected[#1]:\n"
-      "<5>[ 3378.484000] CPU: 0 PID: 185 Comm: dash Not tainted 3.14.0 #1\n"
-      "<5>[ 3378.488000] task: 8fed5220 ti: 8ec4a000 task.ti: 8ec4a000\n"
-      "<5>[ 3378.496000] $ 0   : 00000000 804018b8 804010f0 7785b507\n"
-      "<5>[ 3378.500000] $ 4   : 8061ab64 81204478 81205b20 00000000\n"
-      "<5>[ 3378.508000] $ 8   : 80830000 20746365 72746e65 55422079\n"
-      "<5>[ 3378.512000] $12   : 8ec4be94 000000fc 00000000 00000048\n"
-      "<5>[ 3378.520000] $16   : 00000004 8ef54000 80710000 00000002\n"
-      "<5>[ 3378.528000] $20   : 7765b6d4 00000004 7fffffff 00000002\n"
-      "<5>[ 3378.532000] $24   : 00000001 803dc0dc                  \n"
-      "<5>[ 3378.540000] $28   : 8ec4a000 8ec4be20 7775438d 804018b8\n"
-      "<5>[ 3378.544000] Hi    : 00000000\n"
-      "<5>[ 3378.548000] Lo    : 49bf8080\n"
-      "<5>[ 3378.552000] epc   : 804010f0 lkdtm_do_action+0x68/0x3f8\n"
-      "<5>[ 3378.560000]     Not tainted\n"
-      "<5>[ 3378.564000] ra    : 804018b8 direct_entry+0x110/0x154\n"
-      "<5>[ 3378.568000] Status: 3100dc03 KERNEL EXL IE \n"
-      "<5>[ 3378.572000] Cause : 10800024\n"
-      "<5>[ 3378.576000] PrId  : 0001a120 (MIPS interAptiv (multi))\n"
-      "<5>[ 3378.580000] Modules linked in: uinput cfg80211 nf_conntrack_ipv6 "
-          "nf_defrag_ipv6 ip6table_filter ip6_tables pcnet32 mii fuse "
-          "ppp_async ppp_generic slhc tun\n"
-      "<5>[ 3378.600000] Process dash (pid: 185, threadinfo=8ec4a000, "
-          "task=8fed5220, tls=77632490)\n"
-      "<5>[ 3378.608000] Stack : 00000006 ffffff9c 00000000 00000000 00000000 "
-          "00000000 8083454a 00000022\n"
-      "<5>          7765baa1 00001fee 80710000 8ef54000 8ec4bf08 00000002 "
-          "7765b6d4 00000004\n"
-      "<5>          7fffffff 00000002 7775438d 805e5158 7fffffff 00000002 "
-          "00000000 7785b507\n"
-      "<5>          806a96bc 00000004 8ef54000 8ec4bf08 00000002 804018b8 "
-          "80710000 806a98bc\n"
-      "<5>          00000002 00000020 00000004 8d515600 77756450 00000004 "
-          "8ec4bf08 802377e4\n"
-      "<5>          ...\n"
-      "<5>[ 3378.652000] Call Trace:\n"
-      "<5>[ 3378.656000] [<804010f0>] lkdtm_do_action+0x68/0x3f8\n"
-      "<5>[ 3378.660000] [<804018b8>] direct_entry+0x110/0x154\n"
-      "<5>[ 3378.664000] [<802377e4>] vfs_write+0xe0/0x1bc\n"
-      "<5>[ 3378.672000] [<80237f90>] SyS_write+0x78/0xf8\n"
-      "<5>[ 3378.676000] [<80111888>] handle_sys+0x128/0x14c\n"
-      "<5>[ 3378.680000] \n"
-      "<5>[ 3378.684000] \n"
-      "<5>Code: 3c04806b  0c1793aa  248494f0 <000c000d> 3c04806b  248494fc  "
-          "0c04cc7f  2405017a  08100514 \n"
-      "<5>[ 3378.696000] ---[ end trace 75067432f24bbc93 ]---\n";
-  std::string signature;
-
-  collector_.set_arch(KernelCollector::kArchMips);
-  EXPECT_TRUE(
-      collector_.ComputeKernelStackSignature(kBugToPanic, &signature, false));
-  EXPECT_EQ("kernel-lkdtm_do_action-5E600A6B", signature);
-
-  ComputeKernelStackSignatureCommon();
-}
-
-TEST_F(KernelCollectorTest, ComputeKernelStackSignatureX86) {
-  const char kBugToPanic[] =
-      "<4>[ 6066.829029]  [<79039d16>] ? run_timer_softirq+0x165/0x1e6\n"
-      "<4>[ 6066.829029]  [<790340af>] ignore_old_stack+0xa6/0x143\n"
-      "<0>[ 6066.829029] EIP: [<b82d7c15>] ieee80211_stop_tx_ba_session+"
-          "0xa3/0xb5 [mac80211] SS:ESP 0068:7951febc\n"
-      "<0>[ 6066.829029] CR2: 00000000323038a7\n"
-      "<4>[ 6066.845422] ---[ end trace 12b058bb46c43500 ]---\n"
-      "<0>[ 6066.845747] Kernel panic - not syncing: Fatal exception "
-          "in interrupt\n"
-      "<0>[ 6066.846902] Call Trace:\n"
-      "<4>[ 6066.846902]  [<7937a07b>] ? printk+0x14/0x19\n"
-      "<4>[ 6066.949779]  [<79379fc1>] panic+0x3e/0xe4\n"
-      "<4>[ 6066.949971]  [<7937c5c5>] oops_end+0x73/0x81\n"
-      "<4>[ 6066.950208]  [<7901b260>] no_context+0x10d/0x117\n";
-  std::string signature;
-
-  collector_.set_arch(KernelCollector::kArchX86);
-  EXPECT_TRUE(
-      collector_.ComputeKernelStackSignature(kBugToPanic, &signature, false));
-  EXPECT_EQ("kernel-ieee80211_stop_tx_ba_session-DE253569", signature);
-
-  const char kPCButNoStack[] =
-      "<0>[ 6066.829029] EIP: [<b82d7c15>] ieee80211_stop_tx_ba_session+";
-  EXPECT_TRUE(
-      collector_.ComputeKernelStackSignature(kPCButNoStack, &signature, false));
-  EXPECT_EQ("kernel-ieee80211_stop_tx_ba_session-00000000", signature);
-
-  const char kBreakmeBug[] =
-      "<4>[  180.492137]  [<790970c6>] ? handle_mm_fault+0x67f/0x96d\n"
-      "<4>[  180.492137]  [<790dcdfe>] ? proc_reg_write+0x5f/0x73\n"
-      "<4>[  180.492137]  [<790e2224>] ? write_breakme+0x0/0x108\n"
-      "<4>[  180.492137]  [<790dcd9f>] ? proc_reg_write+0x0/0x73\n"
-      "<4>[  180.492137]  [<790ac0aa>] vfs_write+0x85/0xe4\n"
-      "<0>[  180.492137] Code: c6 44 05 b2 00 89 d8 e8 0c ef 09 00 85 c0 75 "
-      "0b c7 00 00 00 00 00 e9 8e 00 00 00 ba e6 75 4b 79 89 d8 e8 f1 ee 09 "
-      "00 85 c0 75 04 <0f> 0b eb fe ba 58 47 49 79 89 d8 e8 dd ee 09 00 85 "
-      "c0 75 0a 68\n"
-      "<0>[  180.492137] EIP: [<790e22a4>] write_breakme+0x80/0x108 SS:ESP "
-          "0068:aa3e9efc\n"
-      "<4>[  180.501800] ---[ end trace 2a6b72965e1b1523 ]---\n"
-      "<0>[  180.502026] Kernel panic - not syncing: Fatal exception\n"
-      "<4>[  180.502026] Call Trace:\n"
-      "<4>[  180.502806]  [<79379aba>] ? printk+0x14/0x1a\n"
-      "<4>[  180.503033]  [<79379a00>] panic+0x3e/0xe4\n"
-      "<4>[  180.503287]  [<7937c005>] oops_end+0x73/0x81\n"
-      "<4>[  180.503520]  [<790055dd>] die+0x58/0x5e\n"
-      "<4>[  180.503538]  [<7937b96c>] do_trap+0x8e/0xa7\n"
-      "<4>[  180.503555]  [<79003d70>] ? do_invalid_op+0x0/0x80\n";
-
-  EXPECT_TRUE(
-      collector_.ComputeKernelStackSignature(kBreakmeBug, &signature, false));
-  EXPECT_EQ("kernel-write_breakme-122AB3CD", signature);
-
-  const char kPCLineTooOld[] =
-      "<4>[  174.492137]  [<790970c6>] ignored_function+0x67f/0x96d\n"
-      "<4>[  175.492137]  [<790970c6>] ignored_function2+0x67f/0x96d\n"
-      "<0>[  174.492137] EIP: [<790e22a4>] write_breakme+0x80/0x108 SS:ESP "
-          "0068:aa3e9efc\n"
-      "<4>[  180.501800] ---[ end trace 2a6b72965e1b1523 ]---\n"
-      "<4>[  180.502026] Call Trace:\n"
-      "<0>[  180.502026] Kernel panic - not syncing: Fatal exception\n"
-      "<4>[  180.502806]  [<79379aba>] printk+0x14/0x1a\n";
-
-  EXPECT_TRUE(
-      collector_.ComputeKernelStackSignature(kPCLineTooOld, &signature, false));
-  EXPECT_EQ("kernel-Fatal exception-ED4C84FE", signature);
-
-  // Panic without EIP line.
-  const char kExamplePanicOnly[] =
-      "<0>[   87.485611] Kernel panic - not syncing: Testing panic\n"
-      "<4>[   87.485630] Pid: 2825, comm: bash Tainted: G         "
-          "C 2.6.32.23+drm33.10 #1\n"
-      "<4>[   87.485639] Call Trace:\n"
-      "<4>[   87.485660]  [<8133f71d>] ? printk+0x14/0x17\n"
-      "<4>[   87.485674]  [<8133f663>] panic+0x3e/0xe4\n"
-      "<4>[   87.485689]  [<810d062e>] write_breakme+0xaa/0x124\n";
-  EXPECT_TRUE(
-      collector_.ComputeKernelStackSignature(kExamplePanicOnly,
-                                             &signature,
-                                             false));
-  EXPECT_EQ("kernel-Testing panic-E0FC3552", signature);
-
-  // Panic from hung task.
-  const char kHungTaskBreakMe[] =
-      "<3>[  720.459157] INFO: task bash:2287 blocked blah blah\n"
-      "<5>[  720.459282] Call Trace:\n"
-      "<5>[  720.459307]  [<810a457b>] ? __dentry_open+0x186/0x23e\n"
-      "<5>[  720.459323]  [<810b9c71>] ? mntput_no_expire+0x29/0xe2\n"
-      "<5>[  720.459336]  [<810b9d48>] ? mntput+0x1e/0x20\n"
-      "<5>[  720.459350]  [<810ad135>] ? path_put+0x1a/0x1d\n"
-      "<5>[  720.459366]  [<8137cacc>] schedule+0x4d/0x4f\n"
-      "<5>[  720.459379]  [<8137ccfb>] schedule_timeout+0x26/0xaf\n"
-      "<5>[  720.459394]  [<8102127e>] ? should_resched+0xd/0x27\n"
-      "<5>[  720.459409]  [<81174d1f>] ? _copy_from_user+0x3c/0x50\n"
-      "<5>[  720.459423]  [<8137cd9e>] "
-      "schedule_timeout_uninterruptible+0x1a/0x1c\n"
-      "<5>[  720.459438]  [<810dee63>] write_breakme+0xb3/0x178\n"
-      "<5>[  720.459453]  [<810dedb0>] ? meminfo_proc_show+0x2f2/0x2f2\n"
-      "<5>[  720.459467]  [<810d94ae>] proc_reg_write+0x6d/0x87\n"
-      "<5>[  720.459481]  [<810d9441>] ? proc_reg_poll+0x76/0x76\n"
-      "<5>[  720.459493]  [<810a5e9e>] vfs_write+0x79/0xa5\n"
-      "<5>[  720.459505]  [<810a6011>] sys_write+0x40/0x65\n"
-      "<5>[  720.459519]  [<8137e677>] sysenter_do_call+0x12/0x26\n"
-      "<0>[  720.459530] Kernel panic - not syncing: hung_task: blocked tasks\n"
-      "<5>[  720.459768] Pid: 31, comm: khungtaskd Tainted: "
-      "G         C  3.0.8 #1\n"
-      "<5>[  720.459998] Call Trace:\n"
-      "<5>[  720.460140]  [<81378a35>] panic+0x53/0x14a\n"
-      "<5>[  720.460312]  [<8105f875>] watchdog+0x15b/0x1a0\n"
-      "<5>[  720.460495]  [<8105f71a>] ? hung_task_panic+0x16/0x16\n"
-      "<5>[  720.460693]  [<81043af3>] kthread+0x67/0x6c\n"
-      "<5>[  720.460862]  [<81043a8c>] ? __init_kthread_worker+0x2d/0x2d\n"
-      "<5>[  720.461106]  [<8137eb9e>] kernel_thread_helper+0x6/0x10\n";
-
-  EXPECT_TRUE(
-      collector_.ComputeKernelStackSignature(kHungTaskBreakMe,
-                                             &signature,
-                                             false));
-
-  EXPECT_EQ("kernel-(HANG)-hung_task: blocked tasks-600B37EA", signature);
-
-  // Panic with all question marks in the last stack trace.
-  const char kUncertainStackTrace[] =
-      "<0>[56279.689669] ------------[ cut here ]------------\n"
-      "<2>[56279.689677] kernel BUG at /build/x86-alex/tmp/portage/"
-      "sys-kernel/chromeos-kernel-0.0.1-r516/work/chromeos-kernel-0.0.1/"
-      "kernel/timer.c:844!\n"
-      "<0>[56279.689683] invalid opcode: 0000 [#1] SMP \n"
-      "<0>[56279.689688] last sysfs file: /sys/power/state\n"
-      "<5>[56279.689692] Modules linked in: nls_iso8859_1 nls_cp437 vfat fat "
-      "gobi usbnet tsl2583(C) industrialio(C) snd_hda_codec_realtek "
-      "snd_hda_intel i2c_dev snd_hda_codec snd_hwdep qcserial snd_pcm usb_wwan "
-      "i2c_i801 snd_timer nm10_gpio snd_page_alloc rtc_cmos fuse "
-      "nf_conntrack_ipv6 nf_defrag_ipv6 uvcvideo videodev ip6table_filter "
-      "ath9k ip6_tables ipv6 mac80211 ath9k_common ath9k_hw ath cfg80211 "
-      "xt_mark\n"
-      "<5>[56279.689731] \n"
-      "<5>[56279.689738] Pid: 24607, comm: powerd_suspend Tainted: G        "
-      "WC  2.6.38.3+ #1 SAMSUNG ELECTRONICS CO., LTD. Alex/G100          \n"
-      "<5>[56279.689748] EIP: 0060:[<8103e3ea>] EFLAGS: 00210286 CPU: 3\n"
-      "<5>[56279.689758] EIP is at add_timer+0xd/0x1b\n"
-      "<5>[56279.689762] EAX: f5e00684 EBX: f5e003c0 ECX: 00000002 EDX: "
-      "00200246\n"
-      "<5>[56279.689767] ESI: f5e003c0 EDI: d28bc03c EBP: d2be5e40 ESP: "
-      "d2be5e40\n"
-      "<5>[56279.689772]  DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068\n"
-      "<0>[56279.689778] Process powerd_suspend (pid: 24607, ti=d2be4000 "
-      "task=f5dc9b60 task.ti=d2be4000)\n"
-      "<0>[56279.689782] Stack:\n"
-      "<5>[56279.689785]  d2be5e4c f8dccced f4ac02c0 d2be5e70 f8ddc752 "
-      "f5e003c0 f4ac0458 f4ac092c\n"
-      "<5>[56279.689797]  f4ac043c f4ac02c0 f4ac0000 f4ac007c d2be5e7c "
-      "f8dd4a33 f4ac0164 d2be5e94\n"
-      "<5>[56279.689809]  f87e0304 f69ff0cc f4ac0164 f87e02a4 f4ac0164 "
-      "d2be5eb0 81248968 00000000\n"
-      "<0>[56279.689821] Call Trace:\n"
-      "<5>[56279.689840]  [<f8dccced>] ieee80211_sta_restart+0x25/0x8c "
-      "[mac80211]\n"
-      "<5>[56279.689854]  [<f8ddc752>] ieee80211_reconfig+0x2e9/0x339 "
-      "[mac80211]\n"
-      "<5>[56279.689869]  [<f8dd4a33>] ieee80211_aes_cmac+0x182d/0x184e "
-      "[mac80211]\n"
-      "<5>[56279.689883]  [<f87e0304>] cfg80211_get_dev_from_info+0x29b/0x2c0 "
-      "[cfg80211]\n"
-      "<5>[56279.689895]  [<f87e02a4>] ? "
-      "cfg80211_get_dev_from_info+0x23b/0x2c0 [cfg80211]\n"
-      "<5>[56279.689904]  [<81248968>] legacy_resume+0x25/0x5d\n"
-      "<5>[56279.689910]  [<812490ae>] device_resume+0xdd/0x110\n"
-      "<5>[56279.689917]  [<812491c2>] dpm_resume_end+0xe1/0x271\n"
-      "<5>[56279.689925]  [<81060481>] suspend_devices_and_enter+0x18b/0x1de\n"
-      "<5>[56279.689932]  [<810605ba>] enter_state+0xe6/0x132\n"
-      "<5>[56279.689939]  [<8105fd4b>] state_store+0x91/0x9d\n"
-      "<5>[56279.689945]  [<8105fcba>] ? state_store+0x0/0x9d\n"
-      "<5>[56279.689953]  [<81178fb1>] kobj_attr_store+0x16/0x22\n"
-      "<5>[56279.689961]  [<810eea5e>] sysfs_write_file+0xc1/0xec\n"
-      "<5>[56279.689969]  [<810af443>] vfs_write+0x8f/0x101\n"
-      "<5>[56279.689975]  [<810ee99d>] ? sysfs_write_file+0x0/0xec\n"
-      "<5>[56279.689982]  [<810af556>] sys_write+0x40/0x65\n"
-      "<5>[56279.689989]  [<81002d57>] sysenter_do_call+0x12/0x26\n"
-      "<0>[56279.689993] Code: c1 d3 e2 4a 89 55 f4 f7 d2 21 f2 6a 00 31 c9 89 "
-      "d8 e8 6e fd ff ff 5a 8d 65 f8 5b 5e 5d c3 55 89 e5 3e 8d 74 26 00 83 38 "
-      "00 74 04 <0f> 0b eb fe 8b 50 08 e8 6f ff ff ff 5d c3 55 89 e5 3e 8d 74 "
-      "26 \n"
-      "<0>[56279.690009] EIP: [<8103e3ea>] add_timer+0xd/0x1b SS:ESP "
-      "0068:d2be5e40\n"
-      "<4>[56279.690113] ---[ end trace b71141bb67c6032a ]---\n"
-      "<7>[56279.694069] wlan0: deauthenticated from 00:00:00:00:00:01 "
-      "(Reason: 6)\n"
-      "<0>[56279.703465] Kernel panic - not syncing: Fatal exception\n"
-      "<5>[56279.703471] Pid: 24607, comm: powerd_suspend Tainted: G      D "
-      "WC  2.6.38.3+ #1\n"
-      "<5>[56279.703475] Call Trace:\n"
-      "<5>[56279.703483]  [<8136648c>] ? panic+0x55/0x152\n"
-      "<5>[56279.703491]  [<810057fa>] ? oops_end+0x73/0x81\n"
-      "<5>[56279.703497]  [<81005a44>] ? die+0xed/0xf5\n"
-      "<5>[56279.703503]  [<810033cb>] ? do_trap+0x7a/0x80\n"
-      "<5>[56279.703509]  [<8100369b>] ? do_invalid_op+0x0/0x80\n"
-      "<5>[56279.703515]  [<81003711>] ? do_invalid_op+0x76/0x80\n"
-      "<5>[56279.703522]  [<8103e3ea>] ? add_timer+0xd/0x1b\n"
-      "<5>[56279.703529]  [<81025e23>] ? check_preempt_curr+0x2e/0x69\n"
-      "<5>[56279.703536]  [<8102ef28>] ? ttwu_post_activation+0x5a/0x11b\n"
-      "<5>[56279.703543]  [<8102fa8d>] ? try_to_wake_up+0x213/0x21d\n"
-      "<5>[56279.703550]  [<81368b7f>] ? error_code+0x67/0x6c\n"
-      "<5>[56279.703557]  [<8103e3ea>] ? add_timer+0xd/0x1b\n"
-      "<5>[56279.703577]  [<f8dccced>] ? ieee80211_sta_restart+0x25/0x8c "
-      "[mac80211]\n"
-      "<5>[56279.703591]  [<f8ddc752>] ? ieee80211_reconfig+0x2e9/0x339 "
-      "[mac80211]\n"
-      "<5>[56279.703605]  [<f8dd4a33>] ? ieee80211_aes_cmac+0x182d/0x184e "
-      "[mac80211]\n"
-      "<5>[56279.703618]  [<f87e0304>] ? "
-      "cfg80211_get_dev_from_info+0x29b/0x2c0 [cfg80211]\n"
-      "<5>[56279.703630]  [<f87e02a4>] ? "
-      "cfg80211_get_dev_from_info+0x23b/0x2c0 [cfg80211]\n"
-      "<5>[56279.703637]  [<81248968>] ? legacy_resume+0x25/0x5d\n"
-      "<5>[56279.703643]  [<812490ae>] ? device_resume+0xdd/0x110\n"
-      "<5>[56279.703649]  [<812491c2>] ? dpm_resume_end+0xe1/0x271\n"
-      "<5>[56279.703657]  [<81060481>] ? "
-      "suspend_devices_and_enter+0x18b/0x1de\n"
-      "<5>[56279.703663]  [<810605ba>] ? enter_state+0xe6/0x132\n"
-      "<5>[56279.703670]  [<8105fd4b>] ? state_store+0x91/0x9d\n"
-      "<5>[56279.703676]  [<8105fcba>] ? state_store+0x0/0x9d\n"
-      "<5>[56279.703683]  [<81178fb1>] ? kobj_attr_store+0x16/0x22\n"
-      "<5>[56279.703690]  [<810eea5e>] ? sysfs_write_file+0xc1/0xec\n"
-      "<5>[56279.703697]  [<810af443>] ? vfs_write+0x8f/0x101\n"
-      "<5>[56279.703703]  [<810ee99d>] ? sysfs_write_file+0x0/0xec\n"
-      "<5>[56279.703709]  [<810af556>] ? sys_write+0x40/0x65\n"
-      "<5>[56279.703716]  [<81002d57>] ? sysenter_do_call+0x12/0x26\n";
-
-  EXPECT_TRUE(
-      collector_.ComputeKernelStackSignature(kUncertainStackTrace,
-                                             &signature,
-                                             false));
-  // The first trace contains only uncertain entries and its hash is 00000000,
-  // so, if we used that, the signature would be kernel-add_timer-00000000.
-  // Instead we use the second-to-last trace for the hash.
-  EXPECT_EQ("kernel-add_timer-B5178878", signature);
-
-  ComputeKernelStackSignatureCommon();
-}
diff --git a/crash_reporter/kernel_collector_test.h b/crash_reporter/kernel_collector_test.h
deleted file mode 100644
index f689e7d..0000000
--- a/crash_reporter/kernel_collector_test.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CRASH_REPORTER_KERNEL_COLLECTOR_TEST_H_
-#define CRASH_REPORTER_KERNEL_COLLECTOR_TEST_H_
-
-#include "kernel_collector.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-class KernelCollectorMock : public KernelCollector {
- public:
-  MOCK_METHOD0(DumpDirMounted, bool());
-  MOCK_METHOD0(SetUpDBus, void());
-};
-
-#endif  // CRASH_REPORTER_KERNEL_COLLECTOR_TEST_H_
diff --git a/crash_reporter/kernel_log_collector.sh b/crash_reporter/kernel_log_collector.sh
deleted file mode 100644
index 82512c2..0000000
--- a/crash_reporter/kernel_log_collector.sh
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/bin/sh
-
-# Copyright (C) 2013 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.
-
-# Usage example: "kernel_log_collector.sh XXX YYY"
-# This script searches logs in the /var/log/messages which have the keyword XXX.
-# And only those logs which are within the last YYY seconds of the latest log
-# that has the keyword XXX are printed.
-
-# Kernel log has the possible formats:
-# 2013-06-14T16:31:40.514513-07:00 localhost kernel: [    2.682472] MSG MSG ...
-# 2013-06-19T20:38:58.661826+00:00 localhost kernel: [    1.668092] MSG MSG ...
-
-search_key=$1
-time_duration=$2
-msg_pattern="^[0-9-]*T[0-9:.+-]* localhost kernel"
-
-die() {
-  echo "kernel_log_collector: $*" >&2
-  exit 1
-}
-
-get_timestamp() {
-  timestamp="$(echo $1 | cut -d " " -f 1)"
-  timestamp="$(date -d "${timestamp}" +%s)" || exit $?
-  echo "${timestamp}"
-}
-
-last_line=$(grep "${msg_pattern}" /var/log/messages | grep -- "${search_key}" | tail -n 1)
-
-if [ -n "${last_line}" ]; then
-  if ! allowed_timestamp=$(get_timestamp "${last_line}"); then
-    die "coule not get timestamp from: ${last_line}"
-  fi
-  : $(( allowed_timestamp -= ${time_duration} ))
-  grep "${msg_pattern}" /var/log/messages | grep -- "${search_key}" | while read line; do
-    if ! timestamp=$(get_timestamp "${line}"); then
-      die "could not get timestamp from: ${line}"
-    fi
-    if [ ${timestamp} -gt ${allowed_timestamp} ]; then
-      echo "${line}"
-    fi
-  done
-fi
-
-echo "END-OF-LOG"
-
diff --git a/crash_reporter/kernel_warning_collector.cc b/crash_reporter/kernel_warning_collector.cc
deleted file mode 100644
index e28e8fd..0000000
--- a/crash_reporter/kernel_warning_collector.cc
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2012 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 "kernel_warning_collector.h"
-
-#include <base/files/file_util.h>
-#include <base/logging.h>
-#include <base/strings/string_number_conversions.h>
-#include <base/strings/string_util.h>
-#include <base/strings/stringprintf.h>
-
-namespace {
-const char kExecName[] = "kernel-warning";
-const char kKernelWarningSignatureKey[] = "sig";
-const char kKernelWarningPath[] = "/var/run/kwarn/warning";
-const pid_t kKernelPid = 0;
-const uid_t kRootUid = 0;
-}  // namespace
-
-using base::FilePath;
-using base::StringPrintf;
-
-KernelWarningCollector::KernelWarningCollector() {
-}
-
-KernelWarningCollector::~KernelWarningCollector() {
-}
-
-bool KernelWarningCollector::LoadKernelWarning(std::string *content,
-                                               std::string *signature) {
-  FilePath kernel_warning_path(kKernelWarningPath);
-  if (!base::ReadFileToString(kernel_warning_path, content)) {
-    LOG(ERROR) << "Could not open " << kKernelWarningPath;
-    return false;
-  }
-  // The signature is in the first line.
-  std::string::size_type end_position = content->find('\n');
-  if (end_position == std::string::npos) {
-    LOG(ERROR) << "unexpected kernel warning format";
-    return false;
-  }
-  *signature = content->substr(0, end_position);
-  return true;
-}
-
-bool KernelWarningCollector::Collect() {
-  std::string reason = "normal collection";
-  bool feedback = true;
-  if (IsDeveloperImage()) {
-    reason = "always collect from developer builds";
-    feedback = true;
-  } else if (!is_feedback_allowed_function_()) {
-    reason = "no user consent";
-    feedback = false;
-  }
-
-  LOG(INFO) << "Processing kernel warning: " << reason;
-
-  if (!feedback) {
-    return true;
-  }
-
-  std::string kernel_warning;
-  std::string warning_signature;
-  if (!LoadKernelWarning(&kernel_warning, &warning_signature)) {
-    return true;
-  }
-
-  FilePath root_crash_directory;
-  if (!GetCreatedCrashDirectoryByEuid(kRootUid, &root_crash_directory,
-                                      nullptr)) {
-    return true;
-  }
-
-  std::string dump_basename =
-      FormatDumpBasename(kExecName, time(nullptr), kKernelPid);
-  FilePath kernel_crash_path = root_crash_directory.Append(
-      StringPrintf("%s.kcrash", dump_basename.c_str()));
-
-  // We must use WriteNewFile instead of base::WriteFile as we
-  // do not want to write with root access to a symlink that an attacker
-  // might have created.
-  if (WriteNewFile(kernel_crash_path,
-                   kernel_warning.data(),
-                   kernel_warning.length()) !=
-      static_cast<int>(kernel_warning.length())) {
-    LOG(INFO) << "Failed to write kernel warning to "
-              << kernel_crash_path.value().c_str();
-    return true;
-  }
-
-  AddCrashMetaData(kKernelWarningSignatureKey, warning_signature);
-  WriteCrashMetaData(
-      root_crash_directory.Append(
-          StringPrintf("%s.meta", dump_basename.c_str())),
-    kExecName, kernel_crash_path.value());
-
-  LOG(INFO) << "Stored kernel warning into " << kernel_crash_path.value();
-  return true;
-}
diff --git a/crash_reporter/kernel_warning_collector.h b/crash_reporter/kernel_warning_collector.h
deleted file mode 100644
index 5ccb780..0000000
--- a/crash_reporter/kernel_warning_collector.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CRASH_REPORTER_KERNEL_WARNING_COLLECTOR_H_
-#define CRASH_REPORTER_KERNEL_WARNING_COLLECTOR_H_
-
-#include <string>
-
-#include <base/macros.h>
-#include <gtest/gtest_prod.h>  // for FRIEND_TEST
-
-#include "crash_collector.h"
-
-// Kernel warning collector.
-class KernelWarningCollector : public CrashCollector {
- public:
-  KernelWarningCollector();
-
-  ~KernelWarningCollector() override;
-
-  // Collects warning.
-  bool Collect();
-
- private:
-  friend class KernelWarningCollectorTest;
-  FRIEND_TEST(KernelWarningCollectorTest, CollectOK);
-
-  // Reads the full content of the kernel warn dump and its signature.
-  bool LoadKernelWarning(std::string *content, std::string *signature);
-
-  DISALLOW_COPY_AND_ASSIGN(KernelWarningCollector);
-};
-
-#endif  // CRASH_REPORTER_KERNEL_WARNING_COLLECTOR_H_
diff --git a/crash_reporter/list_proxies.cc b/crash_reporter/list_proxies.cc
deleted file mode 100644
index 3374b5f..0000000
--- a/crash_reporter/list_proxies.cc
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <sysexits.h>
-#include <unistd.h>  // for isatty()
-
-#include <string>
-#include <vector>
-
-#include <base/cancelable_callback.h>
-#include <base/command_line.h>
-#include <base/files/file_util.h>
-#include <base/memory/weak_ptr.h>
-#include <base/strings/string_number_conversions.h>
-#include <base/strings/string_tokenizer.h>
-#include <base/strings/string_util.h>
-#include <base/values.h>
-#include <brillo/daemons/dbus_daemon.h>
-#include <brillo/syslog_logging.h>
-
-#include "libcrosservice/dbus-proxies.h"
-
-using std::unique_ptr;
-
-namespace {
-
-const char kLibCrosProxyResolvedSignalInterface[] =
-    "org.chromium.CrashReporterLibcrosProxyResolvedInterface";
-const char kLibCrosProxyResolvedName[] = "ProxyResolved";
-const char kLibCrosServiceName[] = "org.chromium.LibCrosService";
-const char kNoProxy[] = "direct://";
-
-const int kTimeoutDefaultSeconds = 5;
-
-const char kHelp[] = "help";
-const char kQuiet[] = "quiet";
-const char kTimeout[] = "timeout";
-const char kVerbose[] = "verbose";
-// Help message to show when the --help command line switch is specified.
-const char kHelpMessage[] =
-    "Chromium OS Crash helper: proxy lister\n"
-    "\n"
-    "Available Switches:\n"
-    "  --quiet      Only print the proxies\n"
-    "  --verbose    Print additional messages even when not run from a TTY\n"
-    "  --timeout=N  Set timeout for browser resolving proxies (default is 5)\n"
-    "  --help       Show this help.\n";
-
-// Copied from src/update_engine/chrome_browser_proxy_resolver.cc
-// Parses the browser's answer for resolved proxies.  It returns a
-// list of strings, each of which is a resolved proxy.
-std::vector<std::string> ParseProxyString(const std::string& input) {
-  std::vector<std::string> ret;
-  // Some of this code taken from
-  // http://src.chromium.org/svn/trunk/src/net/proxy/proxy_server.cc and
-  // http://src.chromium.org/svn/trunk/src/net/proxy/proxy_list.cc
-  base::StringTokenizer entry_tok(input, ";");
-  while (entry_tok.GetNext()) {
-    std::string token = entry_tok.token();
-    base::TrimWhitespaceASCII(token, base::TRIM_ALL, &token);
-
-    // Start by finding the first space (if any).
-    std::string::iterator space;
-    for (space = token.begin(); space != token.end(); ++space) {
-      if (base::IsAsciiWhitespace(*space)) {
-        break;
-      }
-    }
-
-    std::string scheme = base::ToLowerASCII(std::string(token.begin(), space));
-    // Chrome uses "socks" to mean socks4 and "proxy" to mean http.
-    if (scheme == "socks")
-      scheme += "4";
-    else if (scheme == "proxy")
-      scheme = "http";
-    else if (scheme != "https" &&
-             scheme != "socks4" &&
-             scheme != "socks5" &&
-             scheme != "direct")
-      continue;  // Invalid proxy scheme
-
-    std::string host_and_port = std::string(space, token.end());
-    base::TrimWhitespaceASCII(host_and_port, base::TRIM_ALL, &host_and_port);
-    if (scheme != "direct" && host_and_port.empty())
-      continue;  // Must supply host/port when non-direct proxy used.
-    ret.push_back(scheme + "://" + host_and_port);
-  }
-  if (ret.empty() || *ret.rbegin() != kNoProxy)
-    ret.push_back(kNoProxy);
-  return ret;
-}
-
-// A class for interfacing with Chrome to resolve proxies for a given source
-// url.  The class is initialized with the given source url to check, the
-// signal interface and name that Chrome will reply to, and how long to wait
-// for the resolve request to timeout.  Once initialized, the Run() function
-// must be called, which blocks on the D-Bus call to Chrome.  The call returns
-// after either the timeout or the proxy has been resolved.  The resolved
-// proxies can then be accessed through the proxies() function.
-class ProxyResolver : public brillo::DBusDaemon {
- public:
-  ProxyResolver(const std::string& source_url,
-                const std::string& signal_interface,
-                const std::string& signal_name,
-                base::TimeDelta timeout)
-      : source_url_(source_url),
-        signal_interface_(signal_interface),
-        signal_name_(signal_name),
-        timeout_(timeout),
-        weak_ptr_factory_(this),
-        timeout_callback_(base::Bind(&ProxyResolver::HandleBrowserTimeout,
-                                     weak_ptr_factory_.GetWeakPtr())) {}
-
-  ~ProxyResolver() override {}
-
-  const std::vector<std::string>& proxies() {
-    return proxies_;
-  }
-
-  int Run() override {
-    // Add task for if the browser proxy call times out.
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        timeout_callback_.callback(),
-        timeout_);
-
-    return brillo::DBusDaemon::Run();
-  }
-
- protected:
-  // If the browser times out, quit the run loop.
-  void HandleBrowserTimeout() {
-    LOG(ERROR) << "Timeout while waiting for browser to resolve proxy";
-    Quit();
-  }
-
-  // If the signal handler connects successfully, call the browser's
-  // ResolveNetworkProxy D-Bus method.  Otherwise, don't do anything and let
-  // the timeout task quit the run loop.
-  void HandleDBusSignalConnected(const std::string& interface,
-                                 const std::string& signal,
-                                 bool success) {
-    if (!success) {
-      LOG(ERROR) << "Could not connect to signal " << interface << "."
-                 << signal;
-      timeout_callback_.Cancel();
-      Quit();
-      return;
-    }
-
-    brillo::ErrorPtr error;
-    call_proxy_->ResolveNetworkProxy(source_url_,
-                                     signal_interface_,
-                                     signal_name_,
-                                     &error);
-
-    if (error) {
-      LOG(ERROR) << "Call to ResolveNetworkProxy failed: "
-                 << error->GetMessage();
-      timeout_callback_.Cancel();
-      Quit();
-    }
-  }
-
-  // Handle incoming ProxyResolved signal.
-  void HandleProxyResolvedSignal(const std::string& source_url,
-                                 const std::string& proxy_info,
-                                 const std::string& error_message) {
-    timeout_callback_.Cancel();
-    proxies_ = ParseProxyString(proxy_info);
-    LOG(INFO) << "Found proxies via browser signal: "
-              << base::JoinString(proxies_, "x");
-
-    Quit();
-  }
-
-  int OnInit() override {
-    int return_code = brillo::DBusDaemon::OnInit();
-    if (return_code != EX_OK)
-      return return_code;
-
-    // Initialize D-Bus proxies.
-    call_proxy_.reset(
-        new org::chromium::LibCrosServiceInterfaceProxy(bus_,
-                                                        kLibCrosServiceName));
-    signal_proxy_.reset(
-        new org::chromium::CrashReporterLibcrosProxyResolvedInterfaceProxy(
-            bus_,
-            kLibCrosServiceName));
-
-    // Set up the D-Bus signal handler.
-    // TODO(crbug.com/446115): Update ResolveNetworkProxy call to use an
-    //     asynchronous return value rather than a return signal.
-    signal_proxy_->RegisterProxyResolvedSignalHandler(
-        base::Bind(&ProxyResolver::HandleProxyResolvedSignal,
-                   weak_ptr_factory_.GetWeakPtr()),
-        base::Bind(&ProxyResolver::HandleDBusSignalConnected,
-                   weak_ptr_factory_.GetWeakPtr()));
-
-    return EX_OK;
-  }
-
- private:
-  unique_ptr<org::chromium::LibCrosServiceInterfaceProxy> call_proxy_;
-  unique_ptr<org::chromium::CrashReporterLibcrosProxyResolvedInterfaceProxy>
-      signal_proxy_;
-
-  const std::string source_url_;
-  const std::string signal_interface_;
-  const std::string signal_name_;
-  base::TimeDelta timeout_;
-
-  std::vector<std::string> proxies_;
-  base::WeakPtrFactory<ProxyResolver> weak_ptr_factory_;
-
-  base::CancelableClosure timeout_callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(ProxyResolver);
-};
-
-static bool ShowBrowserProxies(std::string url, base::TimeDelta timeout) {
-  // Initialize and run the proxy resolver to watch for signals.
-  ProxyResolver resolver(url,
-                         kLibCrosProxyResolvedSignalInterface,
-                         kLibCrosProxyResolvedName,
-                         timeout);
-  resolver.Run();
-
-  std::vector<std::string> proxies = resolver.proxies();
-
-  // If proxies is empty, then the timeout was reached waiting for the proxy
-  // resolved signal.  If no proxies are defined, proxies will be populated
-  // with "direct://".
-  if (proxies.empty())
-    return false;
-
-  for (const auto& proxy : proxies) {
-    printf("%s\n", proxy.c_str());
-  }
-  return true;
-}
-
-}  // namespace
-
-int main(int argc, char *argv[]) {
-  base::CommandLine::Init(argc, argv);
-  base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
-
-  if (cl->HasSwitch(kHelp)) {
-    LOG(INFO) << kHelpMessage;
-    return 0;
-  }
-
-  bool quiet = cl->HasSwitch(kQuiet);
-  bool verbose = cl->HasSwitch(kVerbose);
-
-  int timeout = kTimeoutDefaultSeconds;
-  std::string str_timeout = cl->GetSwitchValueASCII(kTimeout);
-  if (!str_timeout.empty() && !base::StringToInt(str_timeout, &timeout)) {
-    LOG(ERROR) << "Invalid timeout value: " << str_timeout;
-    return 1;
-  }
-
-  // Default to logging to syslog.
-  int init_flags = brillo::kLogToSyslog;
-  // Log to stderr if a TTY (and "-quiet" wasn't passed), or if "-verbose"
-  // was passed.
-
-  if ((!quiet && isatty(STDERR_FILENO)) || verbose)
-    init_flags |= brillo::kLogToStderr;
-  brillo::InitLog(init_flags);
-
-  std::string url;
-  base::CommandLine::StringVector urls = cl->GetArgs();
-  if (!urls.empty()) {
-    url = urls[0];
-    LOG(INFO) << "Resolving proxies for URL: " << url;
-  } else {
-    LOG(INFO) << "Resolving proxies without URL";
-  }
-
-  if (!ShowBrowserProxies(url, base::TimeDelta::FromSeconds(timeout))) {
-    LOG(ERROR) << "Error resolving proxies via the browser";
-    LOG(INFO) << "Assuming direct proxy";
-    printf("%s\n", kNoProxy);
-  }
-
-  return 0;
-}
diff --git a/crash_reporter/periodic_scheduler b/crash_reporter/periodic_scheduler
deleted file mode 100755
index 5408da7..0000000
--- a/crash_reporter/periodic_scheduler
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/system/bin/sh
-
-# Copyright (C) 2014 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.
-
-# Run tasks periodically.
-# Usage: $0 <delay_seconds> <timeout_seconds> <task_name> <task_binary>
-#
-# Executes task <task_name> by running <task_binary> every <delay_seconds>.
-
-set -e -u
-
-SCRIPT_NAME="$(basename "$0")"
-CHECK_DELAY=300  # Check every 5 minutes.
-KILL_DELAY=10    # How long to let the job clean up after a timeout.
-# Let the unittests override.
-: ${SPOOL_DIR:=/data/misc/crash_reporter/spool/cron-lite}
-
-loginfo() {
-  log -p i -t "${SCRIPT_NAME}" "$@"
-}
-
-trap "loginfo 'exiting'" EXIT
-
-check_and_fix_spool_paths() {
-  # Avoid weird spool paths if possible.
-  rm -f "$(dirname "${SPOOL_DIR}")" "${SPOOL_DIR}" 2>/dev/null || :
-  mkdir -p "${SPOOL_DIR}"
-  if [ ! -O "${SPOOL_DIR}" -o ! -d "${SPOOL_DIR}" ]; then
-    loginfo "Spool directory is damaged. Aborting!"
-    exit 1
-  fi
-}
-
-main() {
-  local delay="$1"
-  local timeout="$2"
-  local name="$3"
-  local spool_file="${SPOOL_DIR}/${name}"
-  shift 3
-
-  [ -z "${delay}" ] && exit 1
-  [ -z "${timeout}" ] && exit 1
-  [ -z "${name}" ] && exit 1
-  [ $# -eq 0 ] && exit 1
-  check_and_fix_spool_paths
-
-  while true; do
-    # Allow the sleep to be killed manually without terminating the handler.
-    # Send stderr to /dev/null to suppress the shell's "Terminated" message.
-    sleep $(( CHECK_DELAY + KILL_DELAY )) 2>/dev/null || true
-
-    [ ! -e "${spool_file}" ] && touch "${spool_file}"
-
-    local last_rotation="$(stat -c "%Y" "${spool_file}" 2>/dev/null || echo 0)"
-    local now="$(date +%s)"
-    local time_diff=$((now - last_rotation))
-
-    if [ ${time_diff} -gt ${delay} ]; then
-      rm "${spool_file}" || true
-      touch "${spool_file}"
-      loginfo "${name}: running $*"
-      timeout -k ${KILL_DELAY} ${timeout} "$@" || true
-      loginfo "${name}: job completed"
-    fi
-  done
-}
-
-main "$@"
diff --git a/crash_reporter/testrunner.cc b/crash_reporter/testrunner.cc
deleted file mode 100644
index 744cf10..0000000
--- a/crash_reporter/testrunner.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <brillo/test_helpers.h>
-#include <gtest/gtest.h>
-
-int main(int argc, char** argv) {
-  SetUpTests(&argc, argv, true);
-  return RUN_ALL_TESTS();
-}
diff --git a/crash_reporter/udev_collector.cc b/crash_reporter/udev_collector.cc
deleted file mode 100644
index 1e018db..0000000
--- a/crash_reporter/udev_collector.cc
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright (C) 2012 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 "udev_collector.h"
-
-#include <map>
-#include <utility>
-#include <vector>
-
-#include <base/files/file_enumerator.h>
-#include <base/files/file_util.h>
-#include <base/logging.h>
-#include <base/strings/string_number_conversions.h>
-#include <base/strings/string_split.h>
-#include <base/strings/string_util.h>
-#include <base/strings/stringprintf.h>
-#include <brillo/process.h>
-
-using base::FilePath;
-
-namespace {
-
-const char kCollectUdevSignature[] = "crash_reporter-udev-collection";
-const char kGzipPath[] = "/bin/gzip";
-const char kUdevExecName[] = "udev";
-const char kUdevSignatureKey[] = "sig";
-const char kUdevSubsystemDevCoredump[] = "devcoredump";
-const char kDefaultDevCoredumpDirectory[] = "/sys/class/devcoredump";
-const char kDevCoredumpFilePrefixFormat[] = "devcoredump_%s";
-
-}  // namespace
-
-UdevCollector::UdevCollector()
-    : dev_coredump_directory_(kDefaultDevCoredumpDirectory) {}
-
-UdevCollector::~UdevCollector() {}
-
-bool UdevCollector::HandleCrash(const std::string &udev_event) {
-  if (IsDeveloperImage()) {
-    LOG(INFO) << "developer image - collect udev crash info.";
-  } else if (is_feedback_allowed_function_()) {
-    LOG(INFO) << "Consent given - collect udev crash info.";
-  } else {
-    LOG(INFO) << "Ignoring - Non-developer image and no consent given.";
-    return false;
-  }
-
-  // Process the udev event string.
-  // First get all the key-value pairs.
-  std::vector<std::pair<std::string, std::string>> udev_event_keyval;
-  base::SplitStringIntoKeyValuePairs(udev_event, '=', ':', &udev_event_keyval);
-  std::vector<std::pair<std::string, std::string>>::const_iterator iter;
-  std::map<std::string, std::string> udev_event_map;
-  for (iter = udev_event_keyval.begin();
-       iter != udev_event_keyval.end();
-       ++iter) {
-    udev_event_map[iter->first] = iter->second;
-  }
-
-  // Make sure the crash directory exists, or create it if it doesn't.
-  FilePath crash_directory;
-  if (!GetCreatedCrashDirectoryByEuid(0, &crash_directory, nullptr)) {
-    LOG(ERROR) << "Could not get crash directory.";
-    return false;
-  }
-
-  if (udev_event_map["SUBSYSTEM"] == kUdevSubsystemDevCoredump) {
-    int instance_number;
-    if (!base::StringToInt(udev_event_map["KERNEL_NUMBER"], &instance_number)) {
-      LOG(ERROR) << "Invalid kernel number: "
-                 << udev_event_map["KERNEL_NUMBER"];
-      return false;
-    }
-    return ProcessDevCoredump(crash_directory, instance_number);
-  }
-
-  return ProcessUdevCrashLogs(crash_directory,
-                              udev_event_map["ACTION"],
-                              udev_event_map["KERNEL"],
-                              udev_event_map["SUBSYSTEM"]);
-}
-
-bool UdevCollector::ProcessUdevCrashLogs(const FilePath& crash_directory,
-                                         const std::string& action,
-                                         const std::string& kernel,
-                                         const std::string& subsystem) {
-  // Construct the basename string for crash_reporter_logs.conf:
-  //   "crash_reporter-udev-collection-[action]-[name]-[subsystem]"
-  // If a udev field is not provided, "" is used in its place, e.g.:
-  //   "crash_reporter-udev-collection-[action]--[subsystem]"
-  // Hence, "" is used as a wildcard name string.
-  // TODO(sque, crosbug.com/32238): Implement wildcard checking.
-  std::string basename = action + "-" + kernel + "-" + subsystem;
-  std::string udev_log_name = std::string(kCollectUdevSignature) + '-' +
-                              basename;
-
-  // Create the destination path.
-  std::string log_file_name =
-      FormatDumpBasename(basename, time(nullptr), 0);
-  FilePath crash_path = GetCrashPath(crash_directory, log_file_name, "log");
-
-  // Handle the crash.
-  bool result = GetLogContents(log_config_path_, udev_log_name, crash_path);
-  if (!result) {
-    LOG(ERROR) << "Error reading udev log info " << udev_log_name;
-    return false;
-  }
-
-  // Compress the output using gzip.
-  brillo::ProcessImpl gzip_process;
-  gzip_process.AddArg(kGzipPath);
-  gzip_process.AddArg(crash_path.value());
-  int process_result = gzip_process.Run();
-  FilePath crash_path_zipped = FilePath(crash_path.value() + ".gz");
-  // If the zip file was not created, use the uncompressed file.
-  if (process_result != 0 || !base::PathExists(crash_path_zipped))
-    LOG(ERROR) << "Could not create zip file " << crash_path_zipped.value();
-  else
-    crash_path = crash_path_zipped;
-
-  std::string exec_name = std::string(kUdevExecName) + "-" + subsystem;
-  AddCrashMetaData(kUdevSignatureKey, udev_log_name);
-  WriteCrashMetaData(GetCrashPath(crash_directory, log_file_name, "meta"),
-                     exec_name, crash_path.value());
-  return true;
-}
-
-bool UdevCollector::ProcessDevCoredump(const FilePath& crash_directory,
-                                       int instance_number) {
-  FilePath coredump_path =
-      FilePath(base::StringPrintf("%s/devcd%d/data",
-                                  dev_coredump_directory_.c_str(),
-                                  instance_number));
-  if (!base::PathExists(coredump_path)) {
-    LOG(ERROR) << "Device coredump file " << coredump_path.value()
-               << " does not exist";
-    return false;
-  }
-
-  // Add coredump file to the crash directory.
-  if (!AppendDevCoredump(crash_directory, coredump_path, instance_number)) {
-    ClearDevCoredump(coredump_path);
-    return false;
-  }
-
-  // Clear the coredump data to allow generation of future device coredumps
-  // without having to wait for the 5-minutes timeout.
-  return ClearDevCoredump(coredump_path);
-}
-
-bool UdevCollector::AppendDevCoredump(const FilePath& crash_directory,
-                                      const FilePath& coredump_path,
-                                      int instance_number) {
-  // Retrieve the driver name of the failing device.
-  std::string driver_name = GetFailingDeviceDriverName(instance_number);
-  if (driver_name.empty()) {
-    LOG(ERROR) << "Failed to obtain driver name for instance: "
-               << instance_number;
-    return false;
-  }
-
-  std::string coredump_prefix =
-      base::StringPrintf(kDevCoredumpFilePrefixFormat, driver_name.c_str());
-
-  std::string dump_basename = FormatDumpBasename(coredump_prefix,
-                                                 time(nullptr),
-                                                 instance_number);
-  FilePath core_path = GetCrashPath(crash_directory, dump_basename, "devcore");
-  FilePath log_path = GetCrashPath(crash_directory, dump_basename, "log");
-  FilePath meta_path = GetCrashPath(crash_directory, dump_basename, "meta");
-
-  // Collect coredump data.
-  if (!base::CopyFile(coredump_path, core_path)) {
-    LOG(ERROR) << "Failed to copy device coredumpm file from "
-               << coredump_path.value() << " to " << core_path.value();
-    return false;
-  }
-
-  // Collect additional logs if one is specified in the config file.
-  std::string udev_log_name = std::string(kCollectUdevSignature) + '-' +
-      kUdevSubsystemDevCoredump + '-' + driver_name;
-  bool result = GetLogContents(log_config_path_, udev_log_name, log_path);
-  if (result) {
-    AddCrashMetaUploadFile("logs", log_path.value());
-  }
-
-  WriteCrashMetaData(meta_path, coredump_prefix, core_path.value());
-
-  return true;
-}
-
-bool UdevCollector::ClearDevCoredump(const FilePath& coredump_path) {
-  if (!base::WriteFile(coredump_path, "0", 1)) {
-    LOG(ERROR) << "Failed to delete the coredump data file "
-               << coredump_path.value();
-    return false;
-  }
-  return true;
-}
-
-std::string UdevCollector::GetFailingDeviceDriverName(int instance_number) {
-  FilePath failing_uevent_path =
-      FilePath(base::StringPrintf("%s/devcd%d/failing_device/uevent",
-                                  dev_coredump_directory_.c_str(),
-                                  instance_number));
-  if (!base::PathExists(failing_uevent_path)) {
-    LOG(ERROR) << "Failing uevent path " << failing_uevent_path.value()
-               << " does not exist";
-    return "";
-  }
-
-  std::string uevent_content;
-  if (!base::ReadFileToString(failing_uevent_path, &uevent_content)) {
-    LOG(ERROR) << "Failed to read uevent file " << failing_uevent_path.value();
-    return "";
-  }
-
-  // Parse uevent file contents as key-value pairs.
-  std::vector<std::pair<std::string, std::string>> uevent_keyval;
-  base::SplitStringIntoKeyValuePairs(uevent_content, '=', '\n', &uevent_keyval);
-  std::vector<std::pair<std::string, std::string>>::const_iterator iter;
-  for (iter = uevent_keyval.begin();
-       iter != uevent_keyval.end();
-       ++iter) {
-    if (iter->first == "DRIVER") {
-      return iter->second;
-    }
-  }
-
-  return "";
-}
diff --git a/crash_reporter/udev_collector.h b/crash_reporter/udev_collector.h
deleted file mode 100644
index e267b75..0000000
--- a/crash_reporter/udev_collector.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CRASH_REPORTER_UDEV_COLLECTOR_H_
-#define CRASH_REPORTER_UDEV_COLLECTOR_H_
-
-#include <string>
-
-#include <base/files/file_path.h>
-#include <base/macros.h>
-#include <gtest/gtest_prod.h>  // for FRIEND_TEST
-
-#include "crash_collector.h"
-
-// Udev crash collector.
-class UdevCollector : public CrashCollector {
- public:
-  UdevCollector();
-
-  ~UdevCollector() override;
-
-  // The udev event string should be formatted as follows:
-  //   "ACTION=[action]:KERNEL=[name]:SUBSYSTEM=[subsystem]"
-  // The values don't have to be in any particular order. One or more of them
-  // could be omitted, in which case it would be treated as a wildcard (*).
-  bool HandleCrash(const std::string& udev_event);
-
- protected:
-  std::string dev_coredump_directory_;
-
- private:
-  friend class UdevCollectorTest;
-
-  // Process udev crash logs, collecting log files according to the config
-  // file (crash_reporter_logs.conf).
-  bool ProcessUdevCrashLogs(const base::FilePath& crash_directory,
-                            const std::string& action,
-                            const std::string& kernel,
-                            const std::string& subsystem);
-  // Process device coredump, collecting device coredump file.
-  // |instance_number| is the kernel number of the virtual device for the device
-  // coredump instance.
-  bool ProcessDevCoredump(const base::FilePath& crash_directory,
-                          int instance_number);
-  // Copy device coredump file to crash directory, and perform necessary
-  // coredump file management.
-  bool AppendDevCoredump(const base::FilePath& crash_directory,
-                         const base::FilePath& coredump_path,
-                         int instance_number);
-  // Clear the device coredump file by performing a dummy write to it.
-  bool ClearDevCoredump(const base::FilePath& coredump_path);
-  // Return the driver name of the device that generates the coredump.
-  std::string GetFailingDeviceDriverName(int instance_number);
-
-  // Mutator for unit testing.
-  void set_log_config_path(const std::string& path) {
-    log_config_path_ = base::FilePath(path);
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(UdevCollector);
-};
-
-#endif  // CRASH_REPORTER_UDEV_COLLECTOR_H_
diff --git a/crash_reporter/udev_collector_test.cc b/crash_reporter/udev_collector_test.cc
deleted file mode 100644
index 5474f48..0000000
--- a/crash_reporter/udev_collector_test.cc
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2012 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 <base/files/file_enumerator.h>
-#include <base/files/file_util.h>
-#include <base/files/scoped_temp_dir.h>
-#include <base/strings/stringprintf.h>
-#include <brillo/syslog_logging.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include "udev_collector.h"
-
-using base::FilePath;
-
-namespace {
-
-// Dummy log config file name.
-const char kLogConfigFileName[] = "log_config_file";
-
-// Dummy directory for storing device coredumps.
-const char kDevCoredumpDirectory[] = "devcoredump";
-
-// A bunch of random rules to put into the dummy log config file.
-const char kLogConfigFileContents[] =
-    "crash_reporter-udev-collection-change-card0-drm=echo change card0 drm\n"
-    "crash_reporter-udev-collection-add-state0-cpu=echo change state0 cpu\n"
-    "crash_reporter-udev-collection-devcoredump-iwlwifi=echo devcoredump\n"
-    "cros_installer=echo not for udev";
-
-const char kCrashLogFilePattern[] = "*.log.gz";
-const char kDevCoredumpFilePattern[] = "*.devcore";
-
-// Dummy content for device coredump data file.
-const char kDevCoredumpDataContents[] = "coredump";
-
-// Content for failing device's uevent file.
-const char kFailingDeviceUeventContents[] = "DRIVER=iwlwifi\n";
-
-void CountCrash() {}
-
-bool s_consent_given = true;
-
-bool IsMetrics() {
-  return s_consent_given;
-}
-
-// Returns the number of files found in the given path that matches the
-// specified file name pattern.
-int GetNumFiles(const FilePath& path, const std::string& file_pattern) {
-  base::FileEnumerator enumerator(path, false, base::FileEnumerator::FILES,
-                                  file_pattern);
-  int num_files = 0;
-  for (FilePath file_path = enumerator.Next();
-       !file_path.value().empty();
-       file_path = enumerator.Next()) {
-    num_files++;
-  }
-  return num_files;
-}
-
-}  // namespace
-
-class UdevCollectorMock : public UdevCollector {
- public:
-  MOCK_METHOD0(SetUpDBus, void());
-};
-
-class UdevCollectorTest : public ::testing::Test {
- protected:
-  base::ScopedTempDir temp_dir_generator_;
-
-  void HandleCrash(const std::string &udev_event) {
-    collector_.HandleCrash(udev_event);
-  }
-
-  void GenerateDevCoredump(const std::string& device_name) {
-    // Generate coredump data file.
-    ASSERT_TRUE(CreateDirectory(
-        FilePath(base::StringPrintf("%s/%s",
-                                    collector_.dev_coredump_directory_.c_str(),
-                                    device_name.c_str()))));
-    FilePath data_path =
-        FilePath(base::StringPrintf("%s/%s/data",
-                                    collector_.dev_coredump_directory_.c_str(),
-                                    device_name.c_str()));
-    ASSERT_EQ(strlen(kDevCoredumpDataContents),
-              base::WriteFile(data_path,
-                              kDevCoredumpDataContents,
-                              strlen(kDevCoredumpDataContents)));
-    // Generate uevent file for failing device.
-    ASSERT_TRUE(CreateDirectory(
-        FilePath(base::StringPrintf("%s/%s/failing_device",
-                                    collector_.dev_coredump_directory_.c_str(),
-                                    device_name.c_str()))));
-    FilePath uevent_path =
-        FilePath(base::StringPrintf("%s/%s/failing_device/uevent",
-                                    collector_.dev_coredump_directory_.c_str(),
-                                    device_name.c_str()));
-    ASSERT_EQ(strlen(kFailingDeviceUeventContents),
-              base::WriteFile(uevent_path,
-                              kFailingDeviceUeventContents,
-                              strlen(kFailingDeviceUeventContents)));
-  }
-
- private:
-  void SetUp() override {
-    s_consent_given = true;
-
-    EXPECT_CALL(collector_, SetUpDBus()).WillRepeatedly(testing::Return());
-
-    collector_.Initialize(CountCrash, IsMetrics);
-
-    ASSERT_TRUE(temp_dir_generator_.CreateUniqueTempDir());
-
-    FilePath log_config_path =
-        temp_dir_generator_.path().Append(kLogConfigFileName);
-    collector_.log_config_path_ = log_config_path;
-    collector_.ForceCrashDirectory(temp_dir_generator_.path());
-
-    FilePath dev_coredump_path =
-        temp_dir_generator_.path().Append(kDevCoredumpDirectory);
-    collector_.dev_coredump_directory_ = dev_coredump_path.value();
-
-    // Write to a dummy log config file.
-    ASSERT_EQ(strlen(kLogConfigFileContents),
-              base::WriteFile(log_config_path,
-                              kLogConfigFileContents,
-                              strlen(kLogConfigFileContents)));
-
-    brillo::ClearLog();
-  }
-
-  UdevCollectorMock collector_;
-};
-
-TEST_F(UdevCollectorTest, TestNoConsent) {
-  s_consent_given = false;
-  HandleCrash("ACTION=change:KERNEL=card0:SUBSYSTEM=drm");
-  EXPECT_EQ(0, GetNumFiles(temp_dir_generator_.path(), kCrashLogFilePattern));
-}
-
-TEST_F(UdevCollectorTest, TestNoMatch) {
-  // No rule should match this.
-  HandleCrash("ACTION=change:KERNEL=foo:SUBSYSTEM=bar");
-  EXPECT_EQ(0, GetNumFiles(temp_dir_generator_.path(), kCrashLogFilePattern));
-}
-
-TEST_F(UdevCollectorTest, TestMatches) {
-  // Try multiple udev events in sequence.  The number of log files generated
-  // should increase.
-  HandleCrash("ACTION=change:KERNEL=card0:SUBSYSTEM=drm");
-  EXPECT_EQ(1, GetNumFiles(temp_dir_generator_.path(), kCrashLogFilePattern));
-  HandleCrash("ACTION=add:KERNEL=state0:SUBSYSTEM=cpu");
-  EXPECT_EQ(2, GetNumFiles(temp_dir_generator_.path(), kCrashLogFilePattern));
-}
-
-TEST_F(UdevCollectorTest, TestDevCoredump) {
-  GenerateDevCoredump("devcd0");
-  HandleCrash("ACTION=add:KERNEL_NUMBER=0:SUBSYSTEM=devcoredump");
-  EXPECT_EQ(1, GetNumFiles(temp_dir_generator_.path(),
-                           kDevCoredumpFilePattern));
-  GenerateDevCoredump("devcd1");
-  HandleCrash("ACTION=add:KERNEL_NUMBER=1:SUBSYSTEM=devcoredump");
-  EXPECT_EQ(2, GetNumFiles(temp_dir_generator_.path(),
-                           kDevCoredumpFilePattern));
-}
-
-// TODO(sque, crosbug.com/32238) - test wildcard cases, multiple identical udev
-// events.
diff --git a/crash_reporter/unclean_shutdown_collector.cc b/crash_reporter/unclean_shutdown_collector.cc
deleted file mode 100644
index 8a092ec..0000000
--- a/crash_reporter/unclean_shutdown_collector.cc
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "unclean_shutdown_collector.h"
-
-#include <base/files/file_util.h>
-#include <base/logging.h>
-
-static const char kUncleanShutdownFile[] =
-    "/var/lib/crash_reporter/pending_clean_shutdown";
-
-// Files created by power manager used for crash reporting.
-static const char kPowerdTracePath[] = "/var/lib/power_manager";
-// Presence of this file indicates that the system was suspended
-static const char kPowerdSuspended[] = "powerd_suspended";
-
-using base::FilePath;
-
-UncleanShutdownCollector::UncleanShutdownCollector()
-    : unclean_shutdown_file_(kUncleanShutdownFile),
-      powerd_trace_path_(kPowerdTracePath),
-      powerd_suspended_file_(powerd_trace_path_.Append(kPowerdSuspended)) {
-}
-
-UncleanShutdownCollector::~UncleanShutdownCollector() {
-}
-
-bool UncleanShutdownCollector::Enable() {
-  FilePath file_path(unclean_shutdown_file_);
-  base::CreateDirectory(file_path.DirName());
-  if (base::WriteFile(file_path, "", 0) != 0) {
-    LOG(ERROR) << "Unable to create shutdown check file";
-    return false;
-  }
-  return true;
-}
-
-bool UncleanShutdownCollector::DeleteUncleanShutdownFiles() {
-  if (!base::DeleteFile(FilePath(unclean_shutdown_file_), false)) {
-    LOG(ERROR) << "Failed to delete unclean shutdown file "
-               << unclean_shutdown_file_;
-    return false;
-  }
-  // Delete power manager state file if it exists.
-  base::DeleteFile(powerd_suspended_file_, false);
-  return true;
-}
-
-bool UncleanShutdownCollector::Collect() {
-  FilePath unclean_file_path(unclean_shutdown_file_);
-  if (!base::PathExists(unclean_file_path)) {
-    return false;
-  }
-  LOG(WARNING) << "Last shutdown was not clean";
-  if (DeadBatteryCausedUncleanShutdown()) {
-    DeleteUncleanShutdownFiles();
-    return false;
-  }
-  DeleteUncleanShutdownFiles();
-
-  if (is_feedback_allowed_function_()) {
-    count_crash_function_();
-  }
-  return true;
-}
-
-bool UncleanShutdownCollector::Disable() {
-  LOG(INFO) << "Clean shutdown signalled";
-  return DeleteUncleanShutdownFiles();
-}
-
-bool UncleanShutdownCollector::DeadBatteryCausedUncleanShutdown() {
-  // Check for case of battery running out while suspended.
-  if (base::PathExists(powerd_suspended_file_)) {
-    LOG(INFO) << "Unclean shutdown occurred while suspended. Not counting "
-              << "toward unclean shutdown statistic.";
-    return true;
-  }
-  return false;
-}
diff --git a/crash_reporter/unclean_shutdown_collector.h b/crash_reporter/unclean_shutdown_collector.h
deleted file mode 100644
index 5bc9968..0000000
--- a/crash_reporter/unclean_shutdown_collector.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CRASH_REPORTER_UNCLEAN_SHUTDOWN_COLLECTOR_H_
-#define CRASH_REPORTER_UNCLEAN_SHUTDOWN_COLLECTOR_H_
-
-#include <string>
-
-#include <base/files/file_path.h>
-#include <base/macros.h>
-#include <gtest/gtest_prod.h>  // for FRIEND_TEST
-
-#include "crash_collector.h"
-
-// Unclean shutdown collector.
-class UncleanShutdownCollector : public CrashCollector {
- public:
-  UncleanShutdownCollector();
-  ~UncleanShutdownCollector() override;
-
-  // Enable collection - signal that a boot has started.
-  bool Enable();
-
-  // Collect if there is was an unclean shutdown. Returns true if
-  // there was, false otherwise.
-  bool Collect();
-
-  // Disable collection - signal that the system has been shutdown cleanly.
-  bool Disable();
-
- private:
-  friend class UncleanShutdownCollectorTest;
-  FRIEND_TEST(UncleanShutdownCollectorTest, EnableCannotWrite);
-  FRIEND_TEST(UncleanShutdownCollectorTest, CollectDeadBatterySuspended);
-
-  bool DeleteUncleanShutdownFiles();
-
-  // Check for unclean shutdown due to battery running out by analyzing powerd
-  // trace files.
-  bool DeadBatteryCausedUncleanShutdown();
-
-  const char *unclean_shutdown_file_;
-  base::FilePath powerd_trace_path_;
-  base::FilePath powerd_suspended_file_;
-
-  DISALLOW_COPY_AND_ASSIGN(UncleanShutdownCollector);
-};
-
-#endif  // CRASH_REPORTER_UNCLEAN_SHUTDOWN_COLLECTOR_H_
diff --git a/crash_reporter/unclean_shutdown_collector_test.cc b/crash_reporter/unclean_shutdown_collector_test.cc
deleted file mode 100644
index 56d2704..0000000
--- a/crash_reporter/unclean_shutdown_collector_test.cc
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "unclean_shutdown_collector.h"
-
-#include <unistd.h>
-
-#include <base/files/file_util.h>
-#include <base/files/scoped_temp_dir.h>
-#include <base/strings/string_util.h>
-#include <brillo/syslog_logging.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-using base::FilePath;
-using ::brillo::FindLog;
-
-namespace {
-
-int s_crashes = 0;
-bool s_metrics = true;
-
-void CountCrash() {
-  ++s_crashes;
-}
-
-bool IsMetrics() {
-  return s_metrics;
-}
-
-}  // namespace
-
-class UncleanShutdownCollectorMock : public UncleanShutdownCollector {
- public:
-  MOCK_METHOD0(SetUpDBus, void());
-};
-
-class UncleanShutdownCollectorTest : public ::testing::Test {
-  void SetUp() {
-    s_crashes = 0;
-
-    EXPECT_CALL(collector_, SetUpDBus()).WillRepeatedly(testing::Return());
-
-    collector_.Initialize(CountCrash,
-                          IsMetrics);
-
-    EXPECT_TRUE(test_dir_.CreateUniqueTempDir());
-
-    test_directory_ = test_dir_.path().Append("test");
-    test_unclean_ = test_dir_.path().Append("test/unclean");
-
-    collector_.unclean_shutdown_file_ = test_unclean_.value().c_str();
-    base::DeleteFile(test_unclean_, true);
-    // Set up an alternate power manager state file as well
-    collector_.powerd_suspended_file_ =
-        test_dir_.path().Append("test/suspended");
-    brillo::ClearLog();
-  }
-
- protected:
-  void WriteStringToFile(const FilePath &file_path,
-                         const char *data) {
-    ASSERT_EQ(strlen(data), base::WriteFile(file_path, data, strlen(data)));
-  }
-
-  UncleanShutdownCollectorMock collector_;
-
-  // Temporary directory used for tests.
-  base::ScopedTempDir test_dir_;
-  FilePath test_directory_;
-  FilePath test_unclean_;
-};
-
-TEST_F(UncleanShutdownCollectorTest, EnableWithoutParent) {
-  ASSERT_TRUE(collector_.Enable());
-  ASSERT_TRUE(base::PathExists(test_unclean_));
-}
-
-TEST_F(UncleanShutdownCollectorTest, EnableWithParent) {
-  mkdir(test_directory_.value().c_str(), 0777);
-  ASSERT_TRUE(collector_.Enable());
-  ASSERT_TRUE(base::PathExists(test_unclean_));
-}
-
-TEST_F(UncleanShutdownCollectorTest, EnableCannotWrite) {
-  collector_.unclean_shutdown_file_ = "/bad/path";
-  ASSERT_FALSE(collector_.Enable());
-  ASSERT_TRUE(FindLog("Unable to create shutdown check file"));
-}
-
-TEST_F(UncleanShutdownCollectorTest, CollectTrue) {
-  ASSERT_TRUE(collector_.Enable());
-  ASSERT_TRUE(base::PathExists(test_unclean_));
-  ASSERT_TRUE(collector_.Collect());
-  ASSERT_FALSE(base::PathExists(test_unclean_));
-  ASSERT_EQ(1, s_crashes);
-  ASSERT_TRUE(FindLog("Last shutdown was not clean"));
-}
-
-TEST_F(UncleanShutdownCollectorTest, CollectFalse) {
-  ASSERT_FALSE(collector_.Collect());
-  ASSERT_EQ(0, s_crashes);
-}
-
-TEST_F(UncleanShutdownCollectorTest, CollectDeadBatterySuspended) {
-  ASSERT_TRUE(collector_.Enable());
-  ASSERT_TRUE(base::PathExists(test_unclean_));
-  base::WriteFile(collector_.powerd_suspended_file_, "", 0);
-  ASSERT_FALSE(collector_.Collect());
-  ASSERT_FALSE(base::PathExists(test_unclean_));
-  ASSERT_FALSE(base::PathExists(collector_.powerd_suspended_file_));
-  ASSERT_EQ(0, s_crashes);
-  ASSERT_TRUE(FindLog("Unclean shutdown occurred while suspended."));
-}
-
-TEST_F(UncleanShutdownCollectorTest, Disable) {
-  ASSERT_TRUE(collector_.Enable());
-  ASSERT_TRUE(base::PathExists(test_unclean_));
-  ASSERT_TRUE(collector_.Disable());
-  ASSERT_FALSE(base::PathExists(test_unclean_));
-  ASSERT_FALSE(collector_.Collect());
-}
-
-TEST_F(UncleanShutdownCollectorTest, DisableWhenNotEnabled) {
-  ASSERT_TRUE(collector_.Disable());
-}
-
-TEST_F(UncleanShutdownCollectorTest, CantDisable) {
-  mkdir(test_directory_.value().c_str(), 0700);
-  if (mkdir(test_unclean_.value().c_str(), 0700)) {
-    ASSERT_EQ(EEXIST, errno)
-        << "Error while creating directory '" << test_unclean_.value()
-        << "': " << strerror(errno);
-  }
-  ASSERT_EQ(0, base::WriteFile(test_unclean_.Append("foo"), "", 0))
-      << "Error while creating empty file '"
-      << test_unclean_.Append("foo").value() << "': " << strerror(errno);
-  ASSERT_FALSE(collector_.Disable());
-  rmdir(test_unclean_.value().c_str());
-}
diff --git a/crash_reporter/user_collector.cc b/crash_reporter/user_collector.cc
deleted file mode 100644
index 98d7448..0000000
--- a/crash_reporter/user_collector.cc
+++ /dev/null
@@ -1,669 +0,0 @@
-/*
- * Copyright (C) 2012 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 "user_collector.h"
-
-#include <elf.h>
-#include <fcntl.h>
-#include <grp.h>  // For struct group.
-#include <pcrecpp.h>
-#include <pwd.h>  // For struct passwd.
-#include <stdint.h>
-#include <sys/cdefs.h>  // For __WORDSIZE
-#include <sys/fsuid.h>
-#include <sys/types.h>  // For getpwuid_r, getgrnam_r, WEXITSTATUS.
-#include <unistd.h>  // For setgroups
-
-#include <iostream>  // For std::oct
-#include <string>
-#include <vector>
-
-#include <base/files/file_util.h>
-#include <base/logging.h>
-#include <base/posix/eintr_wrapper.h>
-#include <base/strings/string_split.h>
-#include <base/strings/string_util.h>
-#include <base/strings/stringprintf.h>
-#include <brillo/osrelease_reader.h>
-#include <brillo/process.h>
-#include <brillo/syslog_logging.h>
-#include <cutils/properties.h>
-#include <private/android_filesystem_config.h>
-
-static const char kCollectionErrorSignature[] =
-    "crash_reporter-user-collection";
-static const char kCorePatternProperty[] = "crash_reporter.coredump.enabled";
-static const char kCoreToMinidumpConverterPath[] = "/system/bin/core2md";
-
-static const char kStatePrefix[] = "State:\t";
-
-static const char kCoreTempFolder[] = "/data/misc/crash_reporter/tmp";
-
-// Define an otherwise invalid value that represents an unknown UID and GID.
-static const uid_t kUnknownUid = -1;
-static const gid_t kUnknownGid = -1;
-
-const char *UserCollector::kUserId = "Uid:\t";
-const char *UserCollector::kGroupId = "Gid:\t";
-
-// Product information keys in the /etc/os-release.d folder.
-static const char kBdkVersionKey[] = "bdk_version";
-static const char kProductIDKey[] = "product_id";
-static const char kProductVersionKey[] = "product_version";
-
-
-using base::FilePath;
-using base::StringPrintf;
-
-UserCollector::UserCollector()
-    : generate_diagnostics_(false),
-      initialized_(false) {
-}
-
-void UserCollector::Initialize(
-    UserCollector::CountCrashFunction count_crash_function,
-    const std::string &our_path,
-    UserCollector::IsFeedbackAllowedFunction is_feedback_allowed_function,
-    bool generate_diagnostics,
-    bool core2md_failure,
-    bool directory_failure,
-    const std::string &filter_in) {
-  CrashCollector::Initialize(count_crash_function,
-                             is_feedback_allowed_function);
-  our_path_ = our_path;
-  initialized_ = true;
-  generate_diagnostics_ = generate_diagnostics;
-  core2md_failure_ = core2md_failure;
-  directory_failure_ = directory_failure;
-  filter_in_ = filter_in;
-
-  gid_t groups[] = { AID_ROOT, AID_SYSTEM, AID_DBUS, AID_READPROC };
-  if (setgroups(arraysize(groups), groups) != 0) {
-    PLOG(FATAL) << "Unable to set groups to root, system, dbus, and readproc";
-  }
-}
-
-UserCollector::~UserCollector() {
-}
-
-std::string UserCollector::GetErrorTypeSignature(ErrorType error_type) const {
-  switch (error_type) {
-    case kErrorSystemIssue:
-      return "system-issue";
-    case kErrorReadCoreData:
-      return "read-core-data";
-    case kErrorUnusableProcFiles:
-      return "unusable-proc-files";
-    case kErrorInvalidCoreFile:
-      return "invalid-core-file";
-    case kErrorUnsupported32BitCoreFile:
-      return "unsupported-32bit-core-file";
-    case kErrorCore2MinidumpConversion:
-      return "core2md-conversion";
-    default:
-      return "";
-  }
-}
-
-bool UserCollector::SetUpInternal(bool enabled) {
-  CHECK(initialized_);
-  LOG(INFO) << (enabled ? "Enabling" : "Disabling") << " user crash handling";
-
-  property_set(kCorePatternProperty, enabled ? "1" : "0");
-
-  return true;
-}
-
-bool UserCollector::GetFirstLineWithPrefix(
-    const std::vector<std::string> &lines,
-    const char *prefix, std::string *line) {
-  std::vector<std::string>::const_iterator line_iterator;
-  for (line_iterator = lines.begin(); line_iterator != lines.end();
-       ++line_iterator) {
-    if (line_iterator->find(prefix) == 0) {
-      *line = *line_iterator;
-      return true;
-    }
-  }
-  return false;
-}
-
-bool UserCollector::GetIdFromStatus(
-    const char *prefix, IdKind kind,
-    const std::vector<std::string> &status_lines, int *id) {
-  // From fs/proc/array.c:task_state(), this file contains:
-  // \nUid:\t<uid>\t<euid>\t<suid>\t<fsuid>\n
-  std::string id_line;
-  if (!GetFirstLineWithPrefix(status_lines, prefix, &id_line)) {
-    return false;
-  }
-  std::string id_substring = id_line.substr(strlen(prefix), std::string::npos);
-  std::vector<std::string> ids = base::SplitString(
-      id_substring, "\t", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-  if (ids.size() != kIdMax || kind < 0 || kind >= kIdMax) {
-    return false;
-  }
-  const char *number = ids[kind].c_str();
-  char *end_number = nullptr;
-  *id = strtol(number, &end_number, 10);
-  if (*end_number != '\0') {
-    return false;
-  }
-  return true;
-}
-
-bool UserCollector::GetStateFromStatus(
-    const std::vector<std::string> &status_lines, std::string *state) {
-  std::string state_line;
-  if (!GetFirstLineWithPrefix(status_lines, kStatePrefix, &state_line)) {
-    return false;
-  }
-  *state = state_line.substr(strlen(kStatePrefix), std::string::npos);
-  return true;
-}
-
-void UserCollector::EnqueueCollectionErrorLog(pid_t pid,
-                                              ErrorType error_type,
-                                              const std::string &exec) {
-  FilePath crash_path;
-  LOG(INFO) << "Writing conversion problems as separate crash report.";
-  if (!GetCreatedCrashDirectoryByEuid(0, &crash_path, nullptr)) {
-    LOG(ERROR) << "Could not even get log directory; out of space?";
-    return;
-  }
-  AddCrashMetaData("sig", kCollectionErrorSignature);
-  AddCrashMetaData("error_type", GetErrorTypeSignature(error_type));
-  std::string dump_basename = FormatDumpBasename(exec, time(nullptr), pid);
-  std::string error_log = brillo::GetLog();
-  FilePath diag_log_path = GetCrashPath(crash_path, dump_basename, "diaglog");
-  if (GetLogContents(FilePath(log_config_path_), kCollectionErrorSignature,
-                     diag_log_path)) {
-    // We load the contents of diag_log into memory and append it to
-    // the error log.  We cannot just append to files because we need
-    // to always create new files to prevent attack.
-    std::string diag_log_contents;
-    base::ReadFileToString(diag_log_path, &diag_log_contents);
-    error_log.append(diag_log_contents);
-    base::DeleteFile(diag_log_path, false);
-  }
-  FilePath log_path = GetCrashPath(crash_path, dump_basename, "log");
-  FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta");
-  // We must use WriteNewFile instead of base::WriteFile as we do
-  // not want to write with root access to a symlink that an attacker
-  // might have created.
-  if (WriteNewFile(log_path, error_log.data(), error_log.length()) < 0) {
-    LOG(ERROR) << "Error writing new file " << log_path.value();
-    return;
-  }
-  WriteCrashMetaData(meta_path, exec, log_path.value());
-}
-
-bool UserCollector::CopyOffProcFiles(pid_t pid,
-                                     const FilePath &container_dir) {
-  if (!base::CreateDirectory(container_dir)) {
-    PLOG(ERROR) << "Could not create " << container_dir.value();
-    return false;
-  }
-  int dir_mask = base::FILE_PERMISSION_READ_BY_USER
-                 | base::FILE_PERMISSION_WRITE_BY_USER
-                 | base::FILE_PERMISSION_EXECUTE_BY_USER
-                 | base::FILE_PERMISSION_READ_BY_GROUP
-                 | base::FILE_PERMISSION_WRITE_BY_GROUP;
-  if (!base::SetPosixFilePermissions(container_dir,
-                                     base::FILE_PERMISSION_MASK & dir_mask)) {
-    PLOG(ERROR) << "Could not set permissions for " << container_dir.value()
-                << " to " << std::oct
-                << (base::FILE_PERMISSION_MASK & dir_mask);
-    return false;
-  }
-  FilePath process_path = GetProcessPath(pid);
-  if (!base::PathExists(process_path)) {
-    LOG(ERROR) << "Path " << process_path.value() << " does not exist";
-    return false;
-  }
-  static const char *proc_files[] = {
-    "auxv",
-    "cmdline",
-    "environ",
-    "maps",
-    "status"
-  };
-  for (unsigned i = 0; i < arraysize(proc_files); ++i) {
-    if (!base::CopyFile(process_path.Append(proc_files[i]),
-                        container_dir.Append(proc_files[i]))) {
-      LOG(ERROR) << "Could not copy " << proc_files[i] << " file";
-      return false;
-    }
-  }
-  return true;
-}
-
-bool UserCollector::ValidateProcFiles(const FilePath &container_dir) const {
-  // Check if the maps file is empty, which could be due to the crashed
-  // process being reaped by the kernel before finishing a core dump.
-  int64_t file_size = 0;
-  if (!base::GetFileSize(container_dir.Append("maps"), &file_size)) {
-    LOG(ERROR) << "Could not get the size of maps file";
-    return false;
-  }
-  if (file_size == 0) {
-    LOG(ERROR) << "maps file is empty";
-    return false;
-  }
-  return true;
-}
-
-UserCollector::ErrorType UserCollector::ValidateCoreFile(
-    const FilePath &core_path) const {
-  int fd = HANDLE_EINTR(open(core_path.value().c_str(), O_RDONLY));
-  if (fd < 0) {
-    PLOG(ERROR) << "Could not open core file " << core_path.value();
-    return kErrorInvalidCoreFile;
-  }
-
-  char e_ident[EI_NIDENT];
-  bool read_ok = base::ReadFromFD(fd, e_ident, sizeof(e_ident));
-  IGNORE_EINTR(close(fd));
-  if (!read_ok) {
-    LOG(ERROR) << "Could not read header of core file";
-    return kErrorInvalidCoreFile;
-  }
-
-  if (e_ident[EI_MAG0] != ELFMAG0 || e_ident[EI_MAG1] != ELFMAG1 ||
-      e_ident[EI_MAG2] != ELFMAG2 || e_ident[EI_MAG3] != ELFMAG3) {
-    LOG(ERROR) << "Invalid core file";
-    return kErrorInvalidCoreFile;
-  }
-
-#if __WORDSIZE == 64
-  // TODO(benchan, mkrebs): Remove this check once core2md can
-  // handles both 32-bit and 64-bit ELF on a 64-bit platform.
-  if (e_ident[EI_CLASS] == ELFCLASS32) {
-    LOG(ERROR) << "Conversion of 32-bit core file on 64-bit platform is "
-               << "currently not supported";
-    return kErrorUnsupported32BitCoreFile;
-  }
-#endif
-
-  return kErrorNone;
-}
-
-bool UserCollector::GetCreatedCrashDirectory(pid_t pid, uid_t supplied_ruid,
-                                             FilePath *crash_file_path,
-                                             bool *out_of_capacity) {
-  FilePath process_path = GetProcessPath(pid);
-  std::string status;
-  if (directory_failure_) {
-    LOG(ERROR) << "Purposefully failing to create spool directory";
-    return false;
-  }
-
-  uid_t uid;
-  if (base::ReadFileToString(process_path.Append("status"), &status)) {
-    std::vector<std::string> status_lines = base::SplitString(
-        status, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-
-    std::string process_state;
-    if (!GetStateFromStatus(status_lines, &process_state)) {
-      LOG(ERROR) << "Could not find process state in status file";
-      return false;
-    }
-    LOG(INFO) << "State of crashed process [" << pid << "]: " << process_state;
-
-    // Get effective UID of crashing process.
-    int id;
-    if (!GetIdFromStatus(kUserId, kIdEffective, status_lines, &id)) {
-      LOG(ERROR) << "Could not find euid in status file";
-      return false;
-    }
-    uid = id;
-  } else if (supplied_ruid != kUnknownUid) {
-    LOG(INFO) << "Using supplied UID " << supplied_ruid
-              << " for crashed process [" << pid
-              << "] due to error reading status file";
-    uid = supplied_ruid;
-  } else {
-    LOG(ERROR) << "Could not read status file and kernel did not supply UID";
-    LOG(INFO) << "Path " << process_path.value() << " DirectoryExists: "
-              << base::DirectoryExists(process_path);
-    return false;
-  }
-
-  if (!GetCreatedCrashDirectoryByEuid(uid, crash_file_path, out_of_capacity)) {
-    LOG(ERROR) << "Could not create crash directory";
-    return false;
-  }
-  return true;
-}
-
-bool UserCollector::CopyStdinToCoreFile(const FilePath &core_path) {
-  // Copy off all stdin to a core file.
-  FilePath stdin_path("/proc/self/fd/0");
-  if (base::CopyFile(stdin_path, core_path)) {
-    return true;
-  }
-
-  PLOG(ERROR) << "Could not write core file";
-  // If the file system was full, make sure we remove any remnants.
-  base::DeleteFile(core_path, false);
-  return false;
-}
-
-bool UserCollector::RunCoreToMinidump(const FilePath &core_path,
-                                      const FilePath &procfs_directory,
-                                      const FilePath &minidump_path,
-                                      const FilePath &temp_directory) {
-  FilePath output_path = temp_directory.Append("output");
-  brillo::ProcessImpl core2md;
-  core2md.RedirectOutput(output_path.value());
-  core2md.AddArg(kCoreToMinidumpConverterPath);
-  core2md.AddArg(core_path.value());
-  core2md.AddArg(procfs_directory.value());
-
-  if (!core2md_failure_) {
-    core2md.AddArg(minidump_path.value());
-  } else {
-    // To test how core2md errors are propagaged, cause an error
-    // by forgetting a required argument.
-  }
-
-  int errorlevel = core2md.Run();
-
-  std::string output;
-  base::ReadFileToString(output_path, &output);
-  if (errorlevel != 0) {
-    LOG(ERROR) << "Problem during " << kCoreToMinidumpConverterPath
-               << " [result=" << errorlevel << "]: " << output;
-    return false;
-  }
-
-  if (!base::PathExists(minidump_path)) {
-    LOG(ERROR) << "Minidump file " << minidump_path.value()
-               << " was not created";
-    return false;
-  }
-  return true;
-}
-
-UserCollector::ErrorType UserCollector::ConvertCoreToMinidump(
-    pid_t pid,
-    const FilePath &container_dir,
-    const FilePath &core_path,
-    const FilePath &minidump_path) {
-  // If proc files are unuable, we continue to read the core file from stdin,
-  // but only skip the core-to-minidump conversion, so that we may still use
-  // the core file for debugging.
-  bool proc_files_usable =
-      CopyOffProcFiles(pid, container_dir) && ValidateProcFiles(container_dir);
-
-  // Switch back to the original UID/GID.
-  gid_t rgid, egid, sgid;
-  if (getresgid(&rgid, &egid, &sgid) != 0) {
-    PLOG(FATAL) << "Unable to read saved gid";
-  }
-  if (setresgid(sgid, sgid, -1) != 0) {
-    PLOG(FATAL) << "Unable to set real group ID back to saved gid";
-  } else {
-    if (getresgid(&rgid, &egid, &sgid) != 0) {
-      // If the groups cannot be read at this point, the rgid variable will
-      // contain the previously read group ID from before changing it.  This
-      // will cause the chown call below to set the incorrect group for
-      // non-root crashes.  But do not treat this as a fatal error, so that
-      // the rest of the collection will continue for potential manual
-      // collection by a developer.
-      PLOG(ERROR) << "Unable to read real group ID after setting it";
-    }
-  }
-
-  uid_t ruid, euid, suid;
-  if (getresuid(&ruid, &euid, &suid) != 0) {
-    PLOG(FATAL) << "Unable to read saved uid";
-  }
-  if (setresuid(suid, suid, -1) != 0) {
-    PLOG(FATAL) << "Unable to set real user ID back to saved uid";
-  } else {
-    if (getresuid(&ruid, &euid, &suid) != 0) {
-      // If the user ID cannot be read at this point, the ruid variable will
-      // contain the previously read user ID from before changing it.  This
-      // will cause the chown call below to set the incorrect user for
-      // non-root crashes.  But do not treat this as a fatal error, so that
-      // the rest of the collection will continue for potential manual
-      // collection by a developer.
-      PLOG(ERROR) << "Unable to read real user ID after setting it";
-    }
-  }
-
-  if (!CopyStdinToCoreFile(core_path)) {
-    return kErrorReadCoreData;
-  }
-
-  if (!proc_files_usable) {
-    LOG(INFO) << "Skipped converting core file to minidump due to "
-              << "unusable proc files";
-    return kErrorUnusableProcFiles;
-  }
-
-  ErrorType error = ValidateCoreFile(core_path);
-  if (error != kErrorNone) {
-    return error;
-  }
-
-  // Chown the temp container directory back to the original user/group that
-  // crash_reporter is run as, so that additional files can be written to
-  // the temp folder.
-  if (chown(container_dir.value().c_str(), ruid, rgid) < 0) {
-    PLOG(ERROR) << "Could not set owner for " << container_dir.value();
-  }
-
-  if (!RunCoreToMinidump(core_path,
-                         container_dir,  // procfs directory
-                         minidump_path,
-                         container_dir)) {  // temporary directory
-    return kErrorCore2MinidumpConversion;
-  }
-
-  LOG(INFO) << "Stored minidump to " << minidump_path.value();
-  return kErrorNone;
-}
-
-UserCollector::ErrorType UserCollector::ConvertAndEnqueueCrash(
-    pid_t pid, const std::string &exec, uid_t supplied_ruid,
-    bool *out_of_capacity) {
-  FilePath crash_path;
-  if (!GetCreatedCrashDirectory(pid, supplied_ruid, &crash_path,
-      out_of_capacity)) {
-    LOG(ERROR) << "Unable to find/create process-specific crash path";
-    return kErrorSystemIssue;
-  }
-
-  // Directory like /tmp/crash_reporter/1234 which contains the
-  // procfs entries and other temporary files used during conversion.
-  FilePath container_dir(StringPrintf("%s/%d", kCoreTempFolder, pid));
-  // Delete a pre-existing directory from crash reporter that may have
-  // been left around for diagnostics from a failed conversion attempt.
-  // If we don't, existing files can cause forking to fail.
-  base::DeleteFile(container_dir, true);
-  std::string dump_basename = FormatDumpBasename(exec, time(nullptr), pid);
-  FilePath core_path = GetCrashPath(crash_path, dump_basename, "core");
-  FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta");
-  FilePath minidump_path = GetCrashPath(crash_path, dump_basename, "dmp");
-  FilePath log_path = GetCrashPath(crash_path, dump_basename, "log");
-
-  if (GetLogContents(FilePath(log_config_path_), exec, log_path))
-    AddCrashMetaData("log", log_path.value());
-
-  brillo::OsReleaseReader reader;
-  reader.Load();
-  std::string value = "undefined";
-  if (!reader.GetString(kBdkVersionKey, &value)) {
-    LOG(ERROR) << "Could not read " << kBdkVersionKey
-               << " from /etc/os-release.d/";
-  }
-  AddCrashMetaData(kBdkVersionKey, value);
-
-  value = "undefined";
-  if (!reader.GetString(kProductIDKey, &value)) {
-    LOG(ERROR) << "Could not read " << kProductIDKey
-               << " from /etc/os-release.d/";
-  }
-  AddCrashMetaData(kProductIDKey, value);
-
-  value = "undefined";
-  if (!reader.GetString(kProductVersionKey, &value)) {
-    LOG(ERROR) << "Could not read " << kProductVersionKey
-               << " from /etc/os-release.d/";
-  }
-  AddCrashMetaData(kProductVersionKey, value);
-
-  ErrorType error_type =
-      ConvertCoreToMinidump(pid, container_dir, core_path, minidump_path);
-  if (error_type != kErrorNone) {
-    LOG(INFO) << "Leaving core file at " << core_path.value()
-              << " due to conversion error";
-    return error_type;
-  }
-
-  // Here we commit to sending this file.  We must not return false
-  // after this point or we will generate a log report as well as a
-  // crash report.
-  WriteCrashMetaData(meta_path,
-                     exec,
-                     minidump_path.value());
-
-  if (!IsDeveloperImage()) {
-    base::DeleteFile(core_path, false);
-  } else {
-    LOG(INFO) << "Leaving core file at " << core_path.value()
-              << " due to developer image";
-  }
-
-  base::DeleteFile(container_dir, true);
-  return kErrorNone;
-}
-
-bool UserCollector::ParseCrashAttributes(const std::string &crash_attributes,
-                                         pid_t *pid, int *signal, uid_t *uid,
-                                         gid_t *gid,
-                                         std::string *kernel_supplied_name) {
-  pcrecpp::RE re("(\\d+):(\\d+):(\\d+):(\\d+):(.*)");
-  if (re.FullMatch(crash_attributes, pid, signal, uid, gid,
-                   kernel_supplied_name))
-    return true;
-
-  LOG(INFO) << "Falling back to parsing crash attributes '"
-            << crash_attributes << "' without UID and GID";
-  pcrecpp::RE re_without_uid("(\\d+):(\\d+):(.*)");
-  *uid = kUnknownUid;
-  *gid = kUnknownGid;
-  return re_without_uid.FullMatch(crash_attributes, pid, signal,
-      kernel_supplied_name);
-}
-
-bool UserCollector::ShouldDump(bool has_owner_consent,
-                               bool is_developer,
-                               std::string *reason) {
-  reason->clear();
-
-  // For developer builds, we always want to keep the crash reports unless
-  // we're testing the crash facilities themselves.  This overrides
-  // feedback.  Crash sending still obeys consent.
-  if (is_developer) {
-    *reason = "developer build - not testing - always dumping";
-    return true;
-  }
-
-  if (!has_owner_consent) {
-    *reason = "ignoring - no consent";
-    return false;
-  }
-
-  *reason = "handling";
-  return true;
-}
-
-bool UserCollector::HandleCrash(const std::string &crash_attributes,
-                                const char *force_exec) {
-  CHECK(initialized_);
-  pid_t pid = 0;
-  int signal = 0;
-  uid_t supplied_ruid = kUnknownUid;
-  gid_t supplied_rgid = kUnknownGid;
-  std::string kernel_supplied_name;
-
-  if (!ParseCrashAttributes(crash_attributes, &pid, &signal, &supplied_ruid,
-                            &supplied_rgid, &kernel_supplied_name)) {
-    LOG(ERROR) << "Invalid parameter: --user=" <<  crash_attributes;
-    return false;
-  }
-
-  // Switch to the group and user that ran the crashing binary in order to
-  // access their /proc files.  Do not set suid/sgid, so that we can switch
-  // back after copying the necessary files.
-  if (setresgid(supplied_rgid, supplied_rgid, -1) != 0) {
-    PLOG(FATAL) << "Unable to set real group ID to access process files";
-  }
-  if (setresuid(supplied_ruid, supplied_ruid, -1) != 0) {
-    PLOG(FATAL) << "Unable to set real user ID to access process files";
-  }
-
-  std::string exec;
-  if (force_exec) {
-    exec.assign(force_exec);
-  } else if (!GetExecutableBaseNameFromPid(pid, &exec)) {
-    // If we cannot find the exec name, use the kernel supplied name.
-    // We don't always use the kernel's since it truncates the name to
-    // 16 characters.
-    exec = StringPrintf("supplied_%s", kernel_supplied_name.c_str());
-  }
-
-  // Allow us to test the crash reporting mechanism successfully even if
-  // other parts of the system crash.
-  if (!filter_in_.empty() &&
-      (filter_in_ == "none" ||
-       filter_in_ != exec)) {
-    // We use a different format message to make it more obvious in tests
-    // which crashes are test generated and which are real.
-    LOG(WARNING) << "Ignoring crash from " << exec << "[" << pid << "] while "
-                 << "filter_in=" << filter_in_ << ".";
-    return true;
-  }
-
-  std::string reason;
-  bool dump = ShouldDump(is_feedback_allowed_function_(),
-                         IsDeveloperImage(),
-                         &reason);
-
-  LOG(WARNING) << "Received crash notification for " << exec << "[" << pid
-               << "] sig " << signal << ", user " << supplied_ruid
-               << " (" << reason << ")";
-
-  if (dump) {
-    count_crash_function_();
-
-    if (generate_diagnostics_) {
-      bool out_of_capacity = false;
-      ErrorType error_type =
-          ConvertAndEnqueueCrash(pid, exec, supplied_ruid, &out_of_capacity);
-      if (error_type != kErrorNone) {
-        if (!out_of_capacity)
-          EnqueueCollectionErrorLog(pid, error_type, exec);
-        return false;
-      }
-    }
-  }
-
-  return true;
-}
diff --git a/crash_reporter/user_collector.h b/crash_reporter/user_collector.h
deleted file mode 100644
index 7261ed4..0000000
--- a/crash_reporter/user_collector.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CRASH_REPORTER_USER_COLLECTOR_H_
-#define CRASH_REPORTER_USER_COLLECTOR_H_
-
-#include <string>
-#include <vector>
-
-#include <base/files/file_path.h>
-#include <base/macros.h>
-#include <gtest/gtest_prod.h>  // for FRIEND_TEST
-
-#include "crash_collector.h"
-
-class SystemLogging;
-
-// User crash collector.
-class UserCollector : public CrashCollector {
- public:
-  UserCollector();
-
-  // Initialize the user crash collector for detection of crashes,
-  // given a crash counting function, the path to this executable,
-  // metrics collection enabled oracle, and system logger facility.
-  // Crash detection/reporting is not enabled until Enable is called.
-  // |generate_diagnostics| is used to indicate whether or not to try
-  // to generate a minidump from crashes.
-  void Initialize(CountCrashFunction count_crash,
-                  const std::string &our_path,
-                  IsFeedbackAllowedFunction is_metrics_allowed,
-                  bool generate_diagnostics,
-                  bool core2md_failure,
-                  bool directory_failure,
-                  const std::string &filter_in);
-
-  ~UserCollector() override;
-
-  // Enable collection.
-  bool Enable() { return SetUpInternal(true); }
-
-  // Disable collection.
-  bool Disable() { return SetUpInternal(false); }
-
-  // Handle a specific user crash.  Returns true on success.
-  bool HandleCrash(const std::string &crash_attributes,
-                   const char *force_exec);
-
- private:
-  friend class UserCollectorTest;
-  FRIEND_TEST(UserCollectorTest, CopyOffProcFilesBadPath);
-  FRIEND_TEST(UserCollectorTest, CopyOffProcFilesBadPid);
-  FRIEND_TEST(UserCollectorTest, CopyOffProcFilesOK);
-  FRIEND_TEST(UserCollectorTest, GetExecutableBaseNameFromPid);
-  FRIEND_TEST(UserCollectorTest, GetFirstLineWithPrefix);
-  FRIEND_TEST(UserCollectorTest, GetIdFromStatus);
-  FRIEND_TEST(UserCollectorTest, GetStateFromStatus);
-  FRIEND_TEST(UserCollectorTest, GetProcessPath);
-  FRIEND_TEST(UserCollectorTest, GetSymlinkTarget);
-  FRIEND_TEST(UserCollectorTest, GetUserInfoFromName);
-  FRIEND_TEST(UserCollectorTest, ParseCrashAttributes);
-  FRIEND_TEST(UserCollectorTest, ShouldDumpChromeOverridesDeveloperImage);
-  FRIEND_TEST(UserCollectorTest, ShouldDumpDeveloperImageOverridesConsent);
-  FRIEND_TEST(UserCollectorTest, ShouldDumpUseConsentProductionImage);
-  FRIEND_TEST(UserCollectorTest, ValidateProcFiles);
-  FRIEND_TEST(UserCollectorTest, ValidateCoreFile);
-
-  // Enumeration to pass to GetIdFromStatus.  Must match the order
-  // that the kernel lists IDs in the status file.
-  enum IdKind {
-    kIdReal = 0,  // uid and gid
-    kIdEffective = 1,  // euid and egid
-    kIdSet = 2,  // suid and sgid
-    kIdFileSystem = 3,  // fsuid and fsgid
-    kIdMax
-  };
-
-  enum ErrorType {
-    kErrorNone,
-    kErrorSystemIssue,
-    kErrorReadCoreData,
-    kErrorUnusableProcFiles,
-    kErrorInvalidCoreFile,
-    kErrorUnsupported32BitCoreFile,
-    kErrorCore2MinidumpConversion,
-  };
-
-  static const int kForkProblem = 255;
-
-  // Returns an error type signature for a given |error_type| value,
-  // which is reported to the crash server along with the
-  // crash_reporter-user-collection signature.
-  std::string GetErrorTypeSignature(ErrorType error_type) const;
-
-  bool SetUpInternal(bool enabled);
-
-  // Returns, via |line|, the first line in |lines| that starts with |prefix|.
-  // Returns true if a line is found, or false otherwise.
-  bool GetFirstLineWithPrefix(const std::vector<std::string> &lines,
-                              const char *prefix, std::string *line);
-
-  // Returns the identifier of |kind|, via |id|, found in |status_lines| on
-  // the line starting with |prefix|. |status_lines| contains the lines in
-  // the status file. Returns true if the identifier can be determined.
-  bool GetIdFromStatus(const char *prefix,
-                       IdKind kind,
-                       const std::vector<std::string> &status_lines,
-                       int *id);
-
-  // Returns the process state, via |state|, found in |status_lines|, which
-  // contains the lines in the status file. Returns true if the process state
-  // can be determined.
-  bool GetStateFromStatus(const std::vector<std::string> &status_lines,
-                          std::string *state);
-
-  void LogCollectionError(const std::string &error_message);
-  void EnqueueCollectionErrorLog(pid_t pid, ErrorType error_type,
-                                 const std::string &exec_name);
-
-  bool CopyOffProcFiles(pid_t pid, const base::FilePath &container_dir);
-
-  // Validates the proc files at |container_dir| and returns true if they
-  // are usable for the core-to-minidump conversion later. For instance, if
-  // a process is reaped by the kernel before the copying of its proc files
-  // takes place, some proc files like /proc/<pid>/maps may contain nothing
-  // and thus become unusable.
-  bool ValidateProcFiles(const base::FilePath &container_dir) const;
-
-  // Validates the core file at |core_path| and returns kErrorNone if
-  // the file contains the ELF magic bytes and an ELF class that matches the
-  // platform (i.e. 32-bit ELF on a 32-bit platform or 64-bit ELF on a 64-bit
-  // platform), which is due to the limitation in core2md. It returns an error
-  // type otherwise.
-  ErrorType ValidateCoreFile(const base::FilePath &core_path) const;
-
-  // Determines the crash directory for given pid based on pid's owner,
-  // and creates the directory if necessary with appropriate permissions.
-  // Returns true whether or not directory needed to be created, false on
-  // any failure.
-  bool GetCreatedCrashDirectory(pid_t pid, uid_t supplied_ruid,
-                                base::FilePath *crash_file_path,
-                                bool *out_of_capacity);
-  bool CopyStdinToCoreFile(const base::FilePath &core_path);
-  bool RunCoreToMinidump(const base::FilePath &core_path,
-                         const base::FilePath &procfs_directory,
-                         const base::FilePath &minidump_path,
-                         const base::FilePath &temp_directory);
-  ErrorType ConvertCoreToMinidump(pid_t pid,
-                                  const base::FilePath &container_dir,
-                                  const base::FilePath &core_path,
-                                  const base::FilePath &minidump_path);
-  ErrorType ConvertAndEnqueueCrash(pid_t pid, const std::string &exec_name,
-                                   uid_t supplied_ruid, bool *out_of_capacity);
-  bool ParseCrashAttributes(const std::string &crash_attributes,
-                            pid_t *pid, int *signal, uid_t *uid, gid_t *gid,
-                            std::string *kernel_supplied_name);
-
-  bool ShouldDump(bool has_owner_consent,
-                  bool is_developer,
-                  std::string *reason);
-
-  bool generate_diagnostics_;
-  std::string our_path_;
-  bool initialized_;
-
-  bool core2md_failure_;
-  bool directory_failure_;
-  std::string filter_in_;
-
-  static const char *kUserId;
-  static const char *kGroupId;
-
-  DISALLOW_COPY_AND_ASSIGN(UserCollector);
-};
-
-#endif  // CRASH_REPORTER_USER_COLLECTOR_H_
diff --git a/crash_reporter/user_collector_test.cc b/crash_reporter/user_collector_test.cc
deleted file mode 100644
index d9c9a5b..0000000
--- a/crash_reporter/user_collector_test.cc
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * Copyright (C) 2012 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 "user_collector.h"
-
-#include <elf.h>
-#include <sys/cdefs.h>  // For __WORDSIZE
-#include <unistd.h>
-
-#include <base/files/file_util.h>
-#include <base/files/scoped_temp_dir.h>
-#include <base/strings/string_split.h>
-#include <brillo/syslog_logging.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-using base::FilePath;
-using brillo::FindLog;
-
-namespace {
-
-int s_crashes = 0;
-bool s_metrics = false;
-
-const char kFilePath[] = "/my/path";
-
-void CountCrash() {
-  ++s_crashes;
-}
-
-bool IsMetrics() {
-  return s_metrics;
-}
-
-}  // namespace
-
-class UserCollectorMock : public UserCollector {
- public:
-  MOCK_METHOD0(SetUpDBus, void());
-};
-
-class UserCollectorTest : public ::testing::Test {
-  void SetUp() {
-    s_crashes = 0;
-
-    EXPECT_CALL(collector_, SetUpDBus()).WillRepeatedly(testing::Return());
-
-    collector_.Initialize(CountCrash,
-                          kFilePath,
-                          IsMetrics,
-                          false,
-                          false,
-                          false,
-                          "");
-
-    EXPECT_TRUE(test_dir_.CreateUniqueTempDir());
-
-    mkdir(test_dir_.path().Append("test").value().c_str(), 0777);
-    pid_ = getpid();
-    brillo::ClearLog();
-  }
-
- protected:
-  void ExpectFileEquals(const char *golden,
-                        const FilePath &file_path) {
-    std::string contents;
-    EXPECT_TRUE(base::ReadFileToString(file_path, &contents));
-    EXPECT_EQ(golden, contents);
-  }
-
-  std::vector<std::string> SplitLines(const std::string &lines) const {
-    return base::SplitString(lines, "\n", base::TRIM_WHITESPACE,
-                             base::SPLIT_WANT_ALL);
-  }
-
-  UserCollectorMock collector_;
-  pid_t pid_;
-  base::ScopedTempDir test_dir_;
-};
-
-TEST_F(UserCollectorTest, ParseCrashAttributes) {
-  pid_t pid;
-  int signal;
-  uid_t uid;
-  gid_t gid;
-  std::string exec_name;
-  EXPECT_TRUE(collector_.ParseCrashAttributes("123456:11:1000:2000:foobar",
-      &pid, &signal, &uid, &gid, &exec_name));
-  EXPECT_EQ(123456, pid);
-  EXPECT_EQ(11, signal);
-  EXPECT_EQ(1000, uid);
-  EXPECT_EQ(2000, gid);
-  EXPECT_EQ("foobar", exec_name);
-  EXPECT_TRUE(collector_.ParseCrashAttributes("4321:6:barfoo",
-      &pid, &signal, &uid, &gid, &exec_name));
-  EXPECT_EQ(4321, pid);
-  EXPECT_EQ(6, signal);
-  EXPECT_EQ(-1, uid);
-  EXPECT_EQ(-1, gid);
-  EXPECT_EQ("barfoo", exec_name);
-
-  EXPECT_FALSE(collector_.ParseCrashAttributes("123456:11",
-      &pid, &signal, &uid, &gid, &exec_name));
-
-  EXPECT_TRUE(collector_.ParseCrashAttributes("123456:11:exec:extra",
-      &pid, &signal, &uid, &gid, &exec_name));
-  EXPECT_EQ("exec:extra", exec_name);
-
-  EXPECT_FALSE(collector_.ParseCrashAttributes("12345p:11:foobar",
-      &pid, &signal, &uid, &gid, &exec_name));
-
-  EXPECT_FALSE(collector_.ParseCrashAttributes("123456:1 :foobar",
-      &pid, &signal, &uid, &gid, &exec_name));
-
-  EXPECT_FALSE(collector_.ParseCrashAttributes("123456::foobar",
-      &pid, &signal, &uid, &gid, &exec_name));
-}
-
-TEST_F(UserCollectorTest, ShouldDumpDeveloperImageOverridesConsent) {
-  std::string reason;
-  EXPECT_TRUE(collector_.ShouldDump(false, true, &reason));
-  EXPECT_EQ("developer build - not testing - always dumping", reason);
-
-  // When running a crash test, behave as normal.
-  EXPECT_FALSE(collector_.ShouldDump(false, false, &reason));
-  EXPECT_EQ("ignoring - no consent", reason);
-}
-
-TEST_F(UserCollectorTest, ShouldDumpUseConsentProductionImage) {
-  std::string result;
-  EXPECT_FALSE(collector_.ShouldDump(false, false, &result));
-  EXPECT_EQ("ignoring - no consent", result);
-
-  EXPECT_TRUE(collector_.ShouldDump(true, false, &result));
-  EXPECT_EQ("handling", result);
-}
-
-TEST_F(UserCollectorTest, HandleCrashWithoutConsent) {
-  s_metrics = false;
-  collector_.HandleCrash("20:10:ignored", "foobar");
-  EXPECT_TRUE(FindLog(
-      "Received crash notification for foobar[20] sig 10"));
-  ASSERT_EQ(s_crashes, 0);
-}
-
-TEST_F(UserCollectorTest, HandleNonChromeCrashWithConsent) {
-  s_metrics = true;
-  collector_.HandleCrash("5:2:ignored", "chromeos-wm");
-  EXPECT_TRUE(FindLog(
-      "Received crash notification for chromeos-wm[5] sig 2"));
-  ASSERT_EQ(s_crashes, 1);
-}
-
-TEST_F(UserCollectorTest, GetProcessPath) {
-  FilePath path = collector_.GetProcessPath(100);
-  ASSERT_EQ("/proc/100", path.value());
-}
-
-TEST_F(UserCollectorTest, GetSymlinkTarget) {
-  FilePath result;
-  ASSERT_FALSE(collector_.GetSymlinkTarget(FilePath("/does_not_exist"),
-                                           &result));
-  ASSERT_TRUE(FindLog(
-      "Readlink failed on /does_not_exist with 2"));
-  std::string long_link = test_dir_.path().value();
-  for (int i = 0; i < 50; ++i)
-    long_link += "0123456789";
-  long_link += "/gold";
-
-  for (size_t len = 1; len <= long_link.size(); ++len) {
-    std::string this_link;
-    static const char* kLink =
-        test_dir_.path().Append("test/this_link").value().c_str();
-    this_link.assign(long_link.c_str(), len);
-    ASSERT_EQ(len, this_link.size());
-    unlink(kLink);
-    ASSERT_EQ(0, symlink(this_link.c_str(), kLink));
-    ASSERT_TRUE(collector_.GetSymlinkTarget(FilePath(kLink), &result));
-    ASSERT_EQ(this_link, result.value());
-  }
-}
-
-TEST_F(UserCollectorTest, GetExecutableBaseNameFromPid) {
-  std::string base_name;
-  EXPECT_FALSE(collector_.GetExecutableBaseNameFromPid(0, &base_name));
-  EXPECT_TRUE(FindLog(
-      "Readlink failed on /proc/0/exe with 2"));
-  EXPECT_TRUE(FindLog(
-      "GetSymlinkTarget failed - Path /proc/0 DirectoryExists: 0"));
-  EXPECT_TRUE(FindLog("stat /proc/0/exe failed: -1 2"));
-
-  brillo::ClearLog();
-  pid_t my_pid = getpid();
-  EXPECT_TRUE(collector_.GetExecutableBaseNameFromPid(my_pid, &base_name));
-  EXPECT_FALSE(FindLog("Readlink failed"));
-  EXPECT_EQ("crash_reporter_tests", base_name);
-}
-
-TEST_F(UserCollectorTest, GetFirstLineWithPrefix) {
-  std::vector<std::string> lines;
-  std::string line;
-
-  EXPECT_FALSE(collector_.GetFirstLineWithPrefix(lines, "Name:", &line));
-  EXPECT_EQ("", line);
-
-  lines.push_back("Name:\tls");
-  lines.push_back("State:\tR (running)");
-  lines.push_back(" Foo:\t1000");
-
-  line.clear();
-  EXPECT_TRUE(collector_.GetFirstLineWithPrefix(lines, "Name:", &line));
-  EXPECT_EQ(lines[0], line);
-
-  line.clear();
-  EXPECT_TRUE(collector_.GetFirstLineWithPrefix(lines, "State:", &line));
-  EXPECT_EQ(lines[1], line);
-
-  line.clear();
-  EXPECT_FALSE(collector_.GetFirstLineWithPrefix(lines, "Foo:", &line));
-  EXPECT_EQ("", line);
-
-  line.clear();
-  EXPECT_TRUE(collector_.GetFirstLineWithPrefix(lines, " Foo:", &line));
-  EXPECT_EQ(lines[2], line);
-
-  line.clear();
-  EXPECT_FALSE(collector_.GetFirstLineWithPrefix(lines, "Bar:", &line));
-  EXPECT_EQ("", line);
-}
-
-TEST_F(UserCollectorTest, GetIdFromStatus) {
-  int id = 1;
-  EXPECT_FALSE(collector_.GetIdFromStatus(UserCollector::kUserId,
-                                          UserCollector::kIdEffective,
-                                          SplitLines("nothing here"),
-                                          &id));
-  EXPECT_EQ(id, 1);
-
-  // Not enough parameters.
-  EXPECT_FALSE(collector_.GetIdFromStatus(UserCollector::kUserId,
-                                          UserCollector::kIdReal,
-                                          SplitLines("line 1\nUid:\t1\n"),
-                                          &id));
-
-  const std::vector<std::string> valid_contents =
-      SplitLines("\nUid:\t1\t2\t3\t4\nGid:\t5\t6\t7\t8\n");
-  EXPECT_TRUE(collector_.GetIdFromStatus(UserCollector::kUserId,
-                                         UserCollector::kIdReal,
-                                         valid_contents,
-                                         &id));
-  EXPECT_EQ(1, id);
-
-  EXPECT_TRUE(collector_.GetIdFromStatus(UserCollector::kUserId,
-                                         UserCollector::kIdEffective,
-                                         valid_contents,
-                                         &id));
-  EXPECT_EQ(2, id);
-
-  EXPECT_TRUE(collector_.GetIdFromStatus(UserCollector::kUserId,
-                                         UserCollector::kIdFileSystem,
-                                         valid_contents,
-                                         &id));
-  EXPECT_EQ(4, id);
-
-  EXPECT_TRUE(collector_.GetIdFromStatus(UserCollector::kGroupId,
-                                         UserCollector::kIdEffective,
-                                         valid_contents,
-                                         &id));
-  EXPECT_EQ(6, id);
-
-  EXPECT_TRUE(collector_.GetIdFromStatus(UserCollector::kGroupId,
-                                         UserCollector::kIdSet,
-                                         valid_contents,
-                                         &id));
-  EXPECT_EQ(7, id);
-
-  EXPECT_FALSE(collector_.GetIdFromStatus(UserCollector::kGroupId,
-                                          UserCollector::IdKind(5),
-                                          valid_contents,
-                                          &id));
-  EXPECT_FALSE(collector_.GetIdFromStatus(UserCollector::kGroupId,
-                                          UserCollector::IdKind(-1),
-                                          valid_contents,
-                                          &id));
-
-  // Fail if junk after number
-  EXPECT_FALSE(collector_.GetIdFromStatus(UserCollector::kUserId,
-                                          UserCollector::kIdReal,
-                                          SplitLines("Uid:\t1f\t2\t3\t4\n"),
-                                          &id));
-  EXPECT_TRUE(collector_.GetIdFromStatus(UserCollector::kUserId,
-                                         UserCollector::kIdReal,
-                                         SplitLines("Uid:\t1\t2\t3\t4\n"),
-                                         &id));
-  EXPECT_EQ(1, id);
-
-  // Fail if more than 4 numbers.
-  EXPECT_FALSE(collector_.GetIdFromStatus(UserCollector::kUserId,
-                                          UserCollector::kIdReal,
-                                          SplitLines("Uid:\t1\t2\t3\t4\t5\n"),
-                                          &id));
-}
-
-TEST_F(UserCollectorTest, GetStateFromStatus) {
-  std::string state;
-  EXPECT_FALSE(collector_.GetStateFromStatus(SplitLines("nothing here"),
-                                             &state));
-  EXPECT_EQ("", state);
-
-  EXPECT_TRUE(collector_.GetStateFromStatus(SplitLines("State:\tR (running)"),
-                                            &state));
-  EXPECT_EQ("R (running)", state);
-
-  EXPECT_TRUE(collector_.GetStateFromStatus(
-      SplitLines("Name:\tls\nState:\tZ (zombie)\n"), &state));
-  EXPECT_EQ("Z (zombie)", state);
-}
-
-TEST_F(UserCollectorTest, GetUserInfoFromName) {
-  gid_t gid = 100;
-  uid_t uid = 100;
-  EXPECT_TRUE(collector_.GetUserInfoFromName("root", &uid, &gid));
-  EXPECT_EQ(0, uid);
-  EXPECT_EQ(0, gid);
-}
-
-TEST_F(UserCollectorTest, CopyOffProcFilesBadPath) {
-  // Try a path that is not writable.
-  ASSERT_FALSE(collector_.CopyOffProcFiles(pid_, FilePath("/bad/path")));
-  EXPECT_TRUE(FindLog("Could not create /bad/path"));
-}
-
-TEST_F(UserCollectorTest, CopyOffProcFilesBadPid) {
-  FilePath container_path(test_dir_.path().Append("test/container"));
-  ASSERT_FALSE(collector_.CopyOffProcFiles(0, container_path));
-  EXPECT_TRUE(FindLog("Path /proc/0 does not exist"));
-}
-
-TEST_F(UserCollectorTest, CopyOffProcFilesOK) {
-  FilePath container_path(test_dir_.path().Append("test/container"));
-  ASSERT_TRUE(collector_.CopyOffProcFiles(pid_, container_path));
-  EXPECT_FALSE(FindLog("Could not copy"));
-  static struct {
-    const char *name;
-    bool exists;
-  } expectations[] = {
-    { "auxv", true },
-    { "cmdline", true },
-    { "environ", true },
-    { "maps", true },
-    { "mem", false },
-    { "mounts", false },
-    { "sched", false },
-    { "status", true }
-  };
-  for (unsigned i = 0; i < sizeof(expectations)/sizeof(expectations[0]); ++i) {
-    EXPECT_EQ(expectations[i].exists,
-              base::PathExists(
-                  container_path.Append(expectations[i].name)));
-  }
-}
-
-TEST_F(UserCollectorTest, ValidateProcFiles) {
-  FilePath container_dir = test_dir_.path();
-
-  // maps file not exists (i.e. GetFileSize fails)
-  EXPECT_FALSE(collector_.ValidateProcFiles(container_dir));
-
-  // maps file is empty
-  FilePath maps_file = container_dir.Append("maps");
-  ASSERT_EQ(0, base::WriteFile(maps_file, nullptr, 0));
-  ASSERT_TRUE(base::PathExists(maps_file));
-  EXPECT_FALSE(collector_.ValidateProcFiles(container_dir));
-
-  // maps file is not empty
-  const char data[] = "test data";
-  ASSERT_EQ(sizeof(data), base::WriteFile(maps_file, data, sizeof(data)));
-  ASSERT_TRUE(base::PathExists(maps_file));
-  EXPECT_TRUE(collector_.ValidateProcFiles(container_dir));
-}
-
-TEST_F(UserCollectorTest, ValidateCoreFile) {
-  FilePath container_dir = test_dir_.path();
-  FilePath core_file = container_dir.Append("core");
-
-  // Core file does not exist
-  EXPECT_EQ(UserCollector::kErrorInvalidCoreFile,
-            collector_.ValidateCoreFile(core_file));
-  char e_ident[EI_NIDENT];
-  e_ident[EI_MAG0] = ELFMAG0;
-  e_ident[EI_MAG1] = ELFMAG1;
-  e_ident[EI_MAG2] = ELFMAG2;
-  e_ident[EI_MAG3] = ELFMAG3;
-#if __WORDSIZE == 32
-  e_ident[EI_CLASS] = ELFCLASS32;
-#elif __WORDSIZE == 64
-  e_ident[EI_CLASS] = ELFCLASS64;
-#else
-#error Unknown/unsupported value of __WORDSIZE.
-#endif
-
-  // Core file has the expected header
-  ASSERT_TRUE(base::WriteFile(core_file, e_ident, sizeof(e_ident)));
-  EXPECT_EQ(UserCollector::kErrorNone,
-            collector_.ValidateCoreFile(core_file));
-
-#if __WORDSIZE == 64
-  // 32-bit core file on 64-bit platform
-  e_ident[EI_CLASS] = ELFCLASS32;
-  ASSERT_TRUE(base::WriteFile(core_file, e_ident, sizeof(e_ident)));
-  EXPECT_EQ(UserCollector::kErrorUnsupported32BitCoreFile,
-            collector_.ValidateCoreFile(core_file));
-  e_ident[EI_CLASS] = ELFCLASS64;
-#endif
-
-  // Invalid core files
-  ASSERT_TRUE(base::WriteFile(core_file, e_ident, sizeof(e_ident) - 1));
-  EXPECT_EQ(UserCollector::kErrorInvalidCoreFile,
-            collector_.ValidateCoreFile(core_file));
-
-  e_ident[EI_MAG0] = 0;
-  ASSERT_TRUE(base::WriteFile(core_file, e_ident, sizeof(e_ident)));
-  EXPECT_EQ(UserCollector::kErrorInvalidCoreFile,
-            collector_.ValidateCoreFile(core_file));
-}
diff --git a/crash_reporter/warn_collector.l b/crash_reporter/warn_collector.l
deleted file mode 100644
index 70ab25c..0000000
--- a/crash_reporter/warn_collector.l
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- *
- * This flex program reads /var/log/messages as it grows and saves kernel
- * warnings to files.  It keeps track of warnings it has seen (based on
- * file/line only, ignoring differences in the stack trace), and reports only
- * the first warning of each kind, but maintains a count of all warnings by
- * using their hashes as buckets in a UMA sparse histogram.  It also invokes
- * the crash collector, which collects the warnings and prepares them for later
- * shipment to the crash server.
- */
-
-%option noyywrap
-
-%{
-#include <fcntl.h>
-#include <inttypes.h>
-#include <pwd.h>
-#include <stdarg.h>
-#include <sys/inotify.h>
-#include <sys/select.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "metrics/c_metrics_library.h"
-
-int WarnStart(void);
-void WarnEnd(void);
-void WarnInput(char *buf, yy_size_t *result, size_t max_size);
-
-#define YY_INPUT(buf, result, max_size) WarnInput(buf, &result, max_size)
-
-%}
-
-/* Define a few useful regular expressions. */
-
-D               [0-9]
-PREFIX          .*" kernel: [ "*{D}+"."{D}+"]"
-CUT_HERE        {PREFIX}" ------------[ cut here".*
-WARNING         {PREFIX}" WARNING: at "
-END_TRACE       {PREFIX}" ---[ end trace".*
-
-/* Use exclusive start conditions. */
-%x PRE_WARN WARN
-
-%%
- /* The scanner itself. */
-
-^{CUT_HERE}\n{WARNING}          BEGIN(PRE_WARN);
-.|\n                            /* ignore all other input in state 0 */
-<PRE_WARN>[^ ]+.[^ ]+\n         if (WarnStart()) {
-                                  /* yytext is
-                                     "file:line func+offset/offset()\n" */
-                                  BEGIN(WARN); ECHO;
-                                } else {
-                                  BEGIN(0);
-                                }
-
- /* Assume the warning ends at the "end trace" line */
-<WARN>^{END_TRACE}\n            ECHO; BEGIN(0); WarnEnd();
-<WARN>^.*\n                     ECHO;
-
-%%
-
-#define HASH_BITMAP_SIZE        (1 << 15)  /* size in bits */
-#define HASH_BITMAP_MASK        (HASH_BITMAP_SIZE - 1)
-
-const char warn_hist_name[] = "Platform.KernelWarningHashes";
-uint32_t hash_bitmap[HASH_BITMAP_SIZE / 32];
-CMetricsLibrary metrics_library;
-
-const char *prog_name;          /* the name of this program */
-int yyin_fd;                    /* instead of FILE *yyin to avoid buffering */
-int i_fd;                       /* for inotify, to detect file changes */
-int testing;                    /* 1 if running test */
-int filter;                     /* 1 when using as filter (for development) */
-int fifo;                       /* 1 when reading from fifo (for devel) */
-int draining;                   /* 1 when draining renamed log file */
-
-const char *msg_path = "/var/log/messages";
-const char warn_dump_dir[]  = "/var/run/kwarn";
-const char *warn_dump_path = "/var/run/kwarn/warning";
-const char *crash_reporter_command;
-
-__attribute__((__format__(__printf__, 1, 2)))
-static void Die(const char *format, ...) {
-  va_list ap;
-  va_start(ap, format);
-  fprintf(stderr, "%s: ", prog_name);
-  vfprintf(stderr, format, ap);
-  exit(1);
-}
-
-static void RunCrashReporter(void) {
-  int status = system(crash_reporter_command);
-  if (status != 0)
-    Die("%s exited with status %d\n", crash_reporter_command, status);
-}
-
-static uint32_t StringHash(const char *string) {
-  uint32_t hash = 0;
-  while (*string != '\0') {
-    hash = (hash << 5) + hash + *string++;
-  }
-  return hash;
-}
-
-/* We expect only a handful of different warnings per boot session, so the
- * probability of a collision is very low, and statistically it won't matter
- * (unless warnings with the same hash also happens in tandem, which is even
- * rarer).
- */
-static int HashSeen(uint32_t hash) {
-  int word_index = (hash & HASH_BITMAP_MASK) / 32;
-  int bit_index = (hash & HASH_BITMAP_MASK) % 32;
-  return hash_bitmap[word_index] & 1 << bit_index;
-}
-
-static void SetHashSeen(uint32_t hash) {
-  int word_index = (hash & HASH_BITMAP_MASK) / 32;
-  int bit_index = (hash & HASH_BITMAP_MASK) % 32;
-  hash_bitmap[word_index] |= 1 << bit_index;
-}
-
-#pragma GCC diagnostic ignored "-Wwrite-strings"
-int WarnStart(void) {
-  uint32_t hash;
-  char *spacep;
-
-  if (filter)
-    return 1;
-
-  hash = StringHash(yytext);
-  if (!(testing || fifo || filter)) {
-    CMetricsLibrarySendSparseToUMA(metrics_library, warn_hist_name, (int) hash);
-  }
-  if (HashSeen(hash))
-    return 0;
-  SetHashSeen(hash);
-
-  yyout = fopen(warn_dump_path, "w");
-  if (yyout == NULL)
-    Die("fopen %s failed: %s\n", warn_dump_path, strerror(errno));
-  spacep = strchr(yytext, ' ');
-  if (spacep == NULL || spacep[1] == '\0')
-    spacep = "unknown-function";
-  fprintf(yyout, "%08x-%s\n", hash, spacep + 1);
-  return 1;
-}
-
-void WarnEnd(void) {
-  if (filter)
-    return;
-  fclose(yyout);
-  yyout = stdout;               /* for debugging */
-  RunCrashReporter();
-}
-
-static void WarnOpenInput(const char *path) {
-  yyin_fd = open(path, O_RDONLY);
-  if (yyin_fd < 0)
-    Die("could not open %s: %s\n", path, strerror(errno));
-  if (!fifo) {
-    /* Go directly to the end of the file.  We don't want to parse the same
-     * warnings multiple times on reboot/restart.  We might miss some
-     * warnings, but so be it---it's too hard to keep track reliably of the
-     * last parsed position in the syslog.
-     */
-    if (lseek(yyin_fd, 0, SEEK_END) < 0)
-      Die("could not lseek %s: %s\n", path, strerror(errno));
-    /* Set up notification of file growth and rename. */
-    i_fd = inotify_init();
-    if (i_fd < 0)
-      Die("inotify_init: %s\n", strerror(errno));
-    if (inotify_add_watch(i_fd, path, IN_MODIFY | IN_MOVE_SELF) < 0)
-      Die("inotify_add_watch: %s\n", strerror(errno));
-  }
-}
-
-/* We replace the default YY_INPUT() for the following reasons:
- *
- * 1.  We want to read data as soon as it becomes available, but the default
- * YY_INPUT() uses buffered I/O.
- *
- * 2.  We want to block on end of input and wait for the file to grow.
- *
- * 3.  We want to detect log rotation, and reopen the input file as needed.
- */
-void WarnInput(char *buf, yy_size_t *result, size_t max_size) {
-  while (1) {
-    ssize_t ret = read(yyin_fd, buf, max_size);
-    if (ret < 0)
-      Die("read: %s", strerror(errno));
-    *result = ret;
-    if (*result > 0 || fifo || filter)
-      return;
-    if (draining) {
-      /* Assume we're done with this log, and move to next
-       * log.  Rsyslogd may keep writing to the old log file
-       * for a while, but we don't care since we don't have
-       * to be exact.
-       */
-      close(yyin_fd);
-      if (YYSTATE == WARN) {
-        /* Be conservative in case we lose the warn
-         * terminator during the switch---or we may
-         * collect personally identifiable information.
-         */
-        WarnEnd();
-      }
-      BEGIN(0);        /* see above comment */
-      sleep(1);        /* avoid race with log rotator */
-      WarnOpenInput(msg_path);
-      draining = 0;
-      continue;
-    }
-    /* Nothing left to read, so we must wait. */
-    struct inotify_event event;
-    while (1) {
-      int n = read(i_fd, &event, sizeof(event));
-      if (n <= 0) {
-        if (errno == EINTR)
-          continue;
-        else
-          Die("inotify: %s\n", strerror(errno));
-      } else
-        break;
-    }
-    if (event.mask & IN_MOVE_SELF) {
-      /* The file has been renamed.  Before switching
-       * to the new one, we process any remaining
-       * content of this file.
-       */
-      draining = 1;
-    }
-  }
-}
-
-int main(int argc, char **argv) {
-  int result;
-  struct passwd *user;
-  prog_name = argv[0];
-
-  if (argc == 2 && strcmp(argv[1], "--test") == 0)
-    testing = 1;
-  else if (argc == 2 && strcmp(argv[1], "--filter") == 0)
-    filter = 1;
-  else if (argc == 2 && strcmp(argv[1], "--fifo") == 0) {
-    fifo = 1;
-  } else if (argc != 1) {
-    fprintf(stderr,
-            "usage: %s [single-flag]\n"
-            "flags (for testing only):\n"
-            "--fifo\tinput is fifo \"fifo\", output is stdout\n"
-            "--filter\tinput is stdin, output is stdout\n"
-            "--test\trun self-test\n",
-            prog_name);
-    exit(1);
-  }
-
-  metrics_library = CMetricsLibraryNew();
-  CMetricsLibraryInit(metrics_library);
-
-  crash_reporter_command = testing ?
-    "./warn_collector_test_reporter.sh" :
-    "/sbin/crash_reporter --kernel_warning";
-
-  /* When filtering with --filter (for development) use stdin for input.
-   * Otherwise read input from a file or a fifo.
-   */
-  yyin_fd = fileno(stdin);
-  if (testing) {
-    msg_path = "messages";
-    warn_dump_path = "warning";
-  }
-  if (fifo) {
-    msg_path = "fifo";
-  }
-  if (!filter) {
-    WarnOpenInput(msg_path);
-  }
-
-  /* Create directory for dump file.  Still need to be root here. */
-  unlink(warn_dump_path);
-  if (!testing && !fifo && !filter) {
-    rmdir(warn_dump_dir);
-    result = mkdir(warn_dump_dir, 0755);
-    if (result < 0)
-      Die("could not create %s: %s\n",
-          warn_dump_dir, strerror(errno));
-  }
-
-  if (0) {
-    /* TODO(semenzato): put this back in once we decide it's safe
-     * to make /var/spool/crash rwxrwxrwx root, or use a different
-     * owner and setuid for the crash reporter as well.
-     */
-
-    /* Get low privilege uid, gid. */
-    user = getpwnam("chronos");
-    if (user == NULL)
-      Die("getpwnam failed\n");
-
-    /* Change dump directory ownership. */
-    if (chown(warn_dump_dir, user->pw_uid, user->pw_gid) < 0)
-      Die("chown: %s\n", strerror(errno));
-
-    /* Drop privileges. */
-    if (setuid(user->pw_uid) < 0) {
-      Die("setuid: %s\n", strerror(errno));
-    }
-  }
-
-  /* Go! */
-  return yylex();
-}
-
-/* Flex should really know not to generate these functions.
- */
-void UnusedFunctionWarningSuppressor(void) {
-  yyunput(0, 0);
-}
diff --git a/crash_reporter/warn_collector_test.sh b/crash_reporter/warn_collector_test.sh
deleted file mode 100755
index a5af16c..0000000
--- a/crash_reporter/warn_collector_test.sh
+++ /dev/null
@@ -1,90 +0,0 @@
-#! /bin/bash
-
-# Copyright (C) 2013 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.
-
-# Test for warn_collector.  Run the warn collector in the background, emulate
-# the kernel by appending lines to the log file "messages", and observe the log
-# of the (fake) crash reporter each time is run by the warn collector daemon.
-
-set -e
-
-fail() {
-  printf '[ FAIL ] %b\n' "$*"
-  exit 1
-}
-
-if [[ -z ${SYSROOT} ]]; then
-  fail "SYSROOT must be set for this test to work"
-fi
-: ${OUT:=${PWD}}
-cd "${OUT}"
-PATH=${OUT}:${PATH}
-TESTLOG="${OUT}/warn-test-log"
-
-echo "Testing: $(which warn_collector)"
-
-cleanup() {
-  # Kill daemon (if started) on exit
-  kill %
-}
-
-check_log() {
-  local n_expected=$1
-  if [[ ! -f ${TESTLOG} ]]; then
-    fail "${TESTLOG} was not created"
-  fi
-  if [[ $(wc -l < "${TESTLOG}") -ne ${n_expected} ]]; then
-    fail "expected ${n_expected} lines in ${TESTLOG}, found this instead:
-$(<"${TESTLOG}")"
-  fi
-  if egrep -qv '^[0-9a-f]{8}' "${TESTLOG}"; then
-    fail "found bad lines in ${TESTLOG}:
-$(<"${TESTLOG}")"
-  fi
-}
-
-rm -f "${TESTLOG}"
-cp "${SRC}/warn_collector_test_reporter.sh" .
-cp "${SRC}/TEST_WARNING" .
-cp TEST_WARNING messages
-
-# Start the collector daemon.  With the --test option, the daemon reads input
-# from ./messages, writes the warning into ./warning, and invokes
-# ./warn_collector_test_reporter.sh to report the warning.
-warn_collector --test &
-trap cleanup EXIT
-
-# After a while, check that the first warning has been collected.
-sleep 1
-check_log 1
-
-# Add the same warning to messages, verify that it is NOT collected
-cat TEST_WARNING >> messages
-sleep 1
-check_log 1
-
-# Add a slightly different warning to messages, check that it is collected.
-sed s/intel_dp.c/intel_xx.c/ < TEST_WARNING >> messages
-sleep 1
-check_log 2
-
-# Emulate log rotation, add a warning, and check.
-mv messages messages.1
-sed s/intel_dp.c/intel_xy.c/ < TEST_WARNING > messages
-sleep 2
-check_log 3
-
-# Success!
-exit 0
diff --git a/crash_reporter/warn_collector_test_reporter.sh b/crash_reporter/warn_collector_test_reporter.sh
deleted file mode 100755
index b6096ed..0000000
--- a/crash_reporter/warn_collector_test_reporter.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#! /bin/sh
-
-# Copyright (C) 2013 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.
-
-# Replacement for the crash reporter, for testing.  Log the first line of the
-# "warning" file, which by convention contains the warning hash, and remove the
-# file.
-
-set -e
-
-exec 1>> warn-test-log
-exec 2>> warn-test-log
-
-head -1 warning
-rm warning
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
new file mode 100644
index 0000000..f0131b8
--- /dev/null
+++ b/debuggerd/Android.bp
@@ -0,0 +1,25 @@
+cc_library_static {
+  name: "libdebuggerd_client",
+  srcs: ["client/debuggerd_client.cpp"],
+
+  cflags: [
+    "-Wall",
+    "-Wextra",
+    "-Werror",
+    "-Os",
+  ],
+
+  target: {
+    android64: {
+      cflags: ["-DTARGET_IS_64_BIT"],
+    },
+  },
+
+  local_include_dirs: ["include"],
+  export_include_dirs: ["include"],
+
+  // libdebuggerd_client gets async signal safe logging via libc_logging,
+  // which defines its interface in bionic private headers.
+  include_dirs: ["bionic/libc"],
+  static_libs: ["libc_logging"],
+}
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 6469db4..155b309 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -1,13 +1,16 @@
 LOCAL_PATH := $(call my-dir)
 
 common_cppflags := \
-    -std=gnu++11 \
     -W \
     -Wall \
     -Wextra \
     -Wunused \
     -Werror \
 
+ifeq ($(TARGET_IS_64_BIT),true)
+common_cppflags += -DTARGET_IS_64_BIT
+endif
+
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
@@ -26,15 +29,12 @@
 LOCAL_SRC_FILES_x86    := x86/machine.cpp
 LOCAL_SRC_FILES_x86_64 := x86_64/machine.cpp
 
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 LOCAL_CPPFLAGS := $(common_cppflags)
 
 LOCAL_INIT_RC_32 := debuggerd.rc
 LOCAL_INIT_RC_64 := debuggerd64.rc
 
-ifeq ($(TARGET_IS_64_BIT),true)
-LOCAL_CPPFLAGS += -DTARGET_IS_64_BIT
-endif
-
 LOCAL_SHARED_LIBRARIES := \
     libbacktrace \
     libbase \
@@ -51,10 +51,10 @@
 
 include $(BUILD_EXECUTABLE)
 
-
+crasher_cppflags := $(common_cppflags) -fstack-protector-all -Wno-free-nonheap-object -Wno-date-time
 
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES := crasher.c
+LOCAL_SRC_FILES := crasher.cpp
 LOCAL_SRC_FILES_arm    := arm/crashglue.S
 LOCAL_SRC_FILES_arm64  := arm64/crashglue.S
 LOCAL_SRC_FILES_mips   := mips/crashglue.S
@@ -63,9 +63,8 @@
 LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS += -fstack-protector-all -Werror -Wno-free-nonheap-object -Wno-date-time
-#LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_SHARED_LIBRARIES := libcutils liblog libc
+LOCAL_CPPFLAGS := $(crasher_cppflags)
+LOCAL_SHARED_LIBRARIES := libcutils liblog
 
 # The arm emulator has VFP but not VFPv3-D32.
 ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
@@ -79,6 +78,34 @@
 
 include $(BUILD_EXECUTABLE)
 
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := crasher.cpp
+LOCAL_SRC_FILES_arm    := arm/crashglue.S
+LOCAL_SRC_FILES_arm64  := arm64/crashglue.S
+LOCAL_SRC_FILES_mips   := mips/crashglue.S
+LOCAL_SRC_FILES_mips64 := mips64/crashglue.S
+LOCAL_SRC_FILES_x86    := x86/crashglue.S
+LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := optional
+LOCAL_CPPFLAGS := $(crasher_cppflags) -DSTATIC_CRASHER
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_SHARED_LIBRARIES := libcutils liblog
+
+# The arm emulator has VFP but not VFPv3-D32.
+ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
+LOCAL_ASFLAGS_arm += -DHAS_VFP_D32
+endif
+
+LOCAL_MODULE := static_crasher
+LOCAL_MODULE_STEM_32 := static_crasher
+LOCAL_MODULE_STEM_64 := static_crasher64
+LOCAL_MULTILIB := both
+
+LOCAL_STATIC_LIBRARIES := libdebuggerd_client libcutils liblog
+
+include $(BUILD_EXECUTABLE)
+
 debuggerd_test_src_files := \
     utility.cpp \
     test/dump_memory_test.cpp \
@@ -93,6 +120,7 @@
     libbacktrace \
     libbase \
     libcutils \
+    liblog
 
 debuggerd_c_includes := \
     $(LOCAL_PATH)/test \
@@ -102,6 +130,9 @@
     -Wno-missing-field-initializers \
     -fno-rtti \
 
+# Bug: http://b/29823425 Disable -Wvarargs for Clang update to r271374
+debuggerd_cpp_flags += -Wno-varargs
+
 # Only build the host tests on linux.
 ifeq ($(HOST_OS),linux)
 
diff --git a/debuggerd/arm/machine.cpp b/debuggerd/arm/machine.cpp
index 78c2306..292edcb 100644
--- a/debuggerd/arm/machine.cpp
+++ b/debuggerd/arm/machine.cpp
@@ -22,8 +22,8 @@
 #include <string.h>
 #include <sys/ptrace.h>
 
+#include <android/log.h>
 #include <backtrace/Backtrace.h>
-#include <log/log.h>
 
 #include "machine.h"
 #include "utility.h"
diff --git a/debuggerd/arm64/machine.cpp b/debuggerd/arm64/machine.cpp
index e7bf79a..cd1bd52 100644
--- a/debuggerd/arm64/machine.cpp
+++ b/debuggerd/arm64/machine.cpp
@@ -24,8 +24,8 @@
 #include <sys/ptrace.h>
 #include <sys/uio.h>
 
+#include <android/log.h>
 #include <backtrace/Backtrace.h>
-#include <log/log.h>
 
 #include "machine.h"
 #include "utility.h"
diff --git a/debuggerd/backtrace.cpp b/debuggerd/backtrace.cpp
index 8f4a53f..06c1efe 100644
--- a/debuggerd/backtrace.cpp
+++ b/debuggerd/backtrace.cpp
@@ -16,25 +16,24 @@
 
 #define LOG_TAG "DEBUG"
 
+#include <errno.h>
+#include <dirent.h>
+#include <limits.h>
 #include <stddef.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <stdio.h>
-#include <time.h>
-#include <errno.h>
-#include <limits.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <sys/types.h>
 #include <sys/ptrace.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
 
 #include <memory>
 #include <string>
 
+#include <android/log.h>
 #include <backtrace/Backtrace.h>
 
-#include <log/log.h>
-
 #include "backtrace.h"
 
 #include "utility.h"
diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp
new file mode 100644
index 0000000..c67d747
--- /dev/null
+++ b/debuggerd/client/debuggerd_client.cpp
@@ -0,0 +1,379 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "debuggerd/client.h"
+
+#include <errno.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "private/libc_logging.h"
+
+#if defined(TARGET_IS_64_BIT) && !defined(__LP64__)
+#define SOCKET_NAME "android:debuggerd32"
+#else
+#define SOCKET_NAME "android:debuggerd"
+#endif
+
+// see man(2) prctl, specifically the section about PR_GET_NAME
+#define MAX_TASK_NAME_LEN (16)
+
+static debuggerd_callbacks_t g_callbacks;
+
+// Don't use __libc_fatal because it exits via abort, which might put us back into a signal handler.
+#define fatal(...)                                             \
+  do {                                                         \
+    __libc_format_log(ANDROID_LOG_FATAL, "libc", __VA_ARGS__); \
+    _exit(1);                                                  \
+  } while (0)
+
+static int socket_abstract_client(const char* name, int type) {
+  sockaddr_un addr;
+
+  // Test with length +1 for the *initial* '\0'.
+  size_t namelen = strlen(name);
+  if ((namelen + 1) > sizeof(addr.sun_path)) {
+    errno = EINVAL;
+    return -1;
+  }
+
+  // This is used for abstract socket namespace, we need
+  // an initial '\0' at the start of the Unix socket path.
+  //
+  // Note: The path in this case is *not* supposed to be
+  // '\0'-terminated. ("man 7 unix" for the gory details.)
+  memset(&addr, 0, sizeof(addr));
+  addr.sun_family = AF_LOCAL;
+  addr.sun_path[0] = 0;
+  memcpy(addr.sun_path + 1, name, namelen);
+
+  socklen_t alen = namelen + offsetof(sockaddr_un, sun_path) + 1;
+
+  int s = socket(AF_LOCAL, type, 0);
+  if (s == -1) {
+    return -1;
+  }
+
+  int rc = TEMP_FAILURE_RETRY(connect(s, reinterpret_cast<sockaddr*>(&addr), alen));
+  if (rc == -1) {
+    close(s);
+    return -1;
+  }
+
+  return s;
+}
+
+/*
+ * Writes a summary of the signal to the log file.  We do this so that, if
+ * for some reason we're not able to contact debuggerd, there is still some
+ * indication of the failure in the log.
+ *
+ * We could be here as a result of native heap corruption, or while a
+ * mutex is being held, so we don't want to use any libc functions that
+ * could allocate memory or hold a lock.
+ */
+static void log_signal_summary(int signum, const siginfo_t* info) {
+  const char* signal_name = "???";
+  bool has_address = false;
+  switch (signum) {
+    case SIGABRT:
+      signal_name = "SIGABRT";
+      break;
+    case SIGBUS:
+      signal_name = "SIGBUS";
+      has_address = true;
+      break;
+    case SIGFPE:
+      signal_name = "SIGFPE";
+      has_address = true;
+      break;
+    case SIGILL:
+      signal_name = "SIGILL";
+      has_address = true;
+      break;
+    case SIGSEGV:
+      signal_name = "SIGSEGV";
+      has_address = true;
+      break;
+#if defined(SIGSTKFLT)
+    case SIGSTKFLT:
+      signal_name = "SIGSTKFLT";
+      break;
+#endif
+    case SIGSYS:
+      signal_name = "SIGSYS";
+      break;
+    case SIGTRAP:
+      signal_name = "SIGTRAP";
+      break;
+  }
+
+  char thread_name[MAX_TASK_NAME_LEN + 1];  // one more for termination
+  if (prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(thread_name), 0, 0, 0) != 0) {
+    strcpy(thread_name, "<name unknown>");
+  } else {
+    // short names are null terminated by prctl, but the man page
+    // implies that 16 byte names are not.
+    thread_name[MAX_TASK_NAME_LEN] = 0;
+  }
+
+  // "info" will be null if the siginfo_t information was not available.
+  // Many signals don't have an address or a code.
+  char code_desc[32];  // ", code -6"
+  char addr_desc[32];  // ", fault addr 0x1234"
+  addr_desc[0] = code_desc[0] = 0;
+  if (info != nullptr) {
+    // For a rethrown signal, this si_code will be right and the one debuggerd shows will
+    // always be SI_TKILL.
+    __libc_format_buffer(code_desc, sizeof(code_desc), ", code %d", info->si_code);
+    if (has_address) {
+      __libc_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr);
+    }
+  }
+  __libc_format_log(ANDROID_LOG_FATAL, "libc", "Fatal signal %d (%s)%s%s in tid %d (%s)", signum,
+                    signal_name, code_desc, addr_desc, gettid(), thread_name);
+}
+
+/*
+ * Returns true if the handler for signal "signum" has SA_SIGINFO set.
+ */
+static bool have_siginfo(int signum) {
+  struct sigaction old_action, new_action;
+
+  memset(&new_action, 0, sizeof(new_action));
+  new_action.sa_handler = SIG_DFL;
+  new_action.sa_flags = SA_RESTART;
+  sigemptyset(&new_action.sa_mask);
+
+  if (sigaction(signum, &new_action, &old_action) < 0) {
+    __libc_format_log(ANDROID_LOG_WARN, "libc", "Failed testing for SA_SIGINFO: %s",
+                      strerror(errno));
+    return false;
+  }
+  bool result = (old_action.sa_flags & SA_SIGINFO) != 0;
+
+  if (sigaction(signum, &old_action, nullptr) == -1) {
+    __libc_format_log(ANDROID_LOG_WARN, "libc", "Restore failed in test for SA_SIGINFO: %s",
+                      strerror(errno));
+  }
+  return result;
+}
+
+static void send_debuggerd_packet(pid_t crashing_tid, pid_t pseudothread_tid) {
+  // Mutex to prevent multiple crashing threads from trying to talk
+  // to debuggerd at the same time.
+  static pthread_mutex_t crash_mutex = PTHREAD_MUTEX_INITIALIZER;
+  int ret = pthread_mutex_trylock(&crash_mutex);
+  if (ret != 0) {
+    if (ret == EBUSY) {
+      __libc_format_log(ANDROID_LOG_INFO, "libc",
+                        "Another thread contacted debuggerd first; not contacting debuggerd.");
+      // This will never complete since the lock is never released.
+      pthread_mutex_lock(&crash_mutex);
+    } else {
+      __libc_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_trylock failed: %s", strerror(ret));
+    }
+    return;
+  }
+
+  int s = socket_abstract_client(SOCKET_NAME, SOCK_STREAM | SOCK_CLOEXEC);
+  if (s == -1) {
+    __libc_format_log(ANDROID_LOG_FATAL, "libc", "Unable to open connection to debuggerd: %s",
+                      strerror(errno));
+    return;
+  }
+
+  // debuggerd knows our pid from the credentials on the
+  // local socket but we need to tell it the tid of the crashing thread.
+  // debuggerd will be paranoid and verify that we sent a tid
+  // that's actually in our process.
+  debugger_msg_t msg;
+  msg.action = DEBUGGER_ACTION_CRASH;
+  msg.tid = crashing_tid;
+  msg.ignore_tid = pseudothread_tid;
+  msg.abort_msg_address = 0;
+
+  if (g_callbacks.get_abort_message) {
+    msg.abort_msg_address = reinterpret_cast<uintptr_t>(g_callbacks.get_abort_message());
+  }
+
+  ret = TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg)));
+  if (ret == sizeof(msg)) {
+    char debuggerd_ack;
+    ret = TEMP_FAILURE_RETRY(read(s, &debuggerd_ack, 1));
+    if (g_callbacks.post_dump) {
+      g_callbacks.post_dump();
+    }
+  } else {
+    // read or write failed -- broken connection?
+    __libc_format_log(ANDROID_LOG_FATAL, "libc", "Failed while talking to debuggerd: %s",
+                      strerror(errno));
+  }
+
+  close(s);
+}
+
+struct debugger_thread_info {
+  pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+  pid_t crashing_tid;
+  pid_t pseudothread_tid;
+  int signal_number;
+  siginfo_t* info;
+};
+
+// Logging and contacting debuggerd requires free file descriptors, which we might not have.
+// Work around this by spawning a "thread" that shares its parent's address space, but not its file
+// descriptor table, so that we can close random file descriptors without affecting the original
+// process. Note that this doesn't go through pthread_create, so TLS is shared with the spawning
+// process.
+static void* pseudothread_stack;
+static int debuggerd_dispatch_pseudothread(void* arg) {
+  debugger_thread_info* thread_info = static_cast<debugger_thread_info*>(arg);
+
+  for (int i = 3; i < 1024; ++i) {
+    close(i);
+  }
+
+  log_signal_summary(thread_info->signal_number, thread_info->info);
+  send_debuggerd_packet(thread_info->crashing_tid, thread_info->pseudothread_tid);
+  pthread_mutex_unlock(&thread_info->mutex);
+  return 0;
+}
+
+/*
+ * Catches fatal signals so we can ask debuggerd to ptrace us before
+ * we crash.
+ */
+static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*) {
+  // It's possible somebody cleared the SA_SIGINFO flag, which would mean
+  // our "info" arg holds an undefined value.
+  if (!have_siginfo(signal_number)) {
+    info = nullptr;
+  }
+
+  debugger_thread_info thread_info = {
+    .crashing_tid = gettid(),
+    .signal_number = signal_number,
+    .info = info
+  };
+
+  pthread_mutex_lock(&thread_info.mutex);
+  pid_t child_pid = clone(debuggerd_dispatch_pseudothread, pseudothread_stack,
+                          CLONE_THREAD | CLONE_SIGHAND | CLONE_VM | CLONE_CHILD_SETTID,
+                          &thread_info, nullptr, nullptr, &thread_info.pseudothread_tid);
+
+  if (child_pid == -1) {
+    fatal("failed to spawn debuggerd dispatch thread: %s", strerror(errno));
+  }
+
+  // Wait for the child to finish and unlock the mutex.
+  // This relies on bionic behavior that isn't guaranteed by the standard.
+  pthread_mutex_lock(&thread_info.mutex);
+
+
+  // We need to return from the signal handler so that debuggerd can dump the
+  // thread that crashed, but returning here does not guarantee that the signal
+  // will be thrown again, even for SIGSEGV and friends, since the signal could
+  // have been sent manually. Resend the signal with rt_tgsigqueueinfo(2) to
+  // preserve the SA_SIGINFO contents.
+  signal(signal_number, SIG_DFL);
+
+  struct siginfo si;
+  if (!info) {
+    memset(&si, 0, sizeof(si));
+    si.si_code = SI_USER;
+    si.si_pid = getpid();
+    si.si_uid = getuid();
+    info = &si;
+  } else if (info->si_code >= 0 || info->si_code == SI_TKILL) {
+    // rt_tgsigqueueinfo(2)'s documentation appears to be incorrect on kernels
+    // that contain commit 66dd34a (3.9+). The manpage claims to only allow
+    // negative si_code values that are not SI_TKILL, but 66dd34a changed the
+    // check to allow all si_code values in calls coming from inside the house.
+  }
+
+  int rc = syscall(SYS_rt_tgsigqueueinfo, getpid(), gettid(), signal_number, info);
+  if (rc != 0) {
+    fatal("failed to resend signal during crash: %s", strerror(errno));
+  }
+}
+
+void debuggerd_init(debuggerd_callbacks_t* callbacks) {
+  if (callbacks) {
+    g_callbacks = *callbacks;
+  }
+
+  void* thread_stack_allocation =
+    mmap(nullptr, PAGE_SIZE * 3, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+  if (thread_stack_allocation == MAP_FAILED) {
+    fatal("failed to allocate debuggerd thread stack");
+  }
+
+  char* stack = static_cast<char*>(thread_stack_allocation) + PAGE_SIZE;
+  if (mprotect(stack, PAGE_SIZE, PROT_READ | PROT_WRITE) != 0) {
+    fatal("failed to mprotect debuggerd thread stack");
+  }
+
+  // Stack grows negatively, set it to the last byte in the page...
+  stack = (stack + PAGE_SIZE - 1);
+  // and align it.
+  stack -= 15;
+  pseudothread_stack = stack;
+
+  struct sigaction action;
+  memset(&action, 0, sizeof(action));
+  sigemptyset(&action.sa_mask);
+  action.sa_sigaction = debuggerd_signal_handler;
+  action.sa_flags = SA_RESTART | SA_SIGINFO;
+
+  // Use the alternate signal stack if available so we can catch stack overflows.
+  action.sa_flags |= SA_ONSTACK;
+
+  sigaction(SIGABRT, &action, nullptr);
+  sigaction(SIGBUS, &action, nullptr);
+  sigaction(SIGFPE, &action, nullptr);
+  sigaction(SIGILL, &action, nullptr);
+  sigaction(SIGSEGV, &action, nullptr);
+#if defined(SIGSTKFLT)
+  sigaction(SIGSTKFLT, &action, nullptr);
+#endif
+  sigaction(SIGTRAP, &action, nullptr);
+}
diff --git a/debuggerd/crasher.c b/debuggerd/crasher.cpp
similarity index 70%
rename from debuggerd/crasher.c
rename to debuggerd/crasher.cpp
index 75f070b..b0e8b17 100644
--- a/debuggerd/crasher.c
+++ b/debuggerd/crasher.cpp
@@ -1,5 +1,24 @@
+/*
+ * Copyright 2006, 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.
+ */
+
+#define LOG_TAG "crasher"
+
 #include <assert.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <pthread.h>
 #include <sched.h>
 #include <signal.h>
@@ -13,8 +32,12 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include <android/log.h>
 #include <cutils/sockets.h>
-#include <log/log.h>
+
+#if defined(STATIC_CRASHER)
+#include "debuggerd/client.h"
+#endif
 
 #ifndef __unused
 #define __unused __attribute__((__unused__))
@@ -22,8 +45,9 @@
 
 extern const char* __progname;
 
-void crash1(void);
-void crashnostack(void);
+extern "C" void crash1(void);
+extern "C" void crashnostack(void);
+
 static int do_action(const char* arg);
 
 static void maybe_abort() {
@@ -42,7 +66,7 @@
 // Assign local array address to global variable to force stack guards.
 // Use another noinline function to corrupt the stack.
 __attribute__ ((noinline)) static int smash_stack(volatile int* plen) {
-    printf("crasher: deliberately corrupting stack...\n");
+    printf("%s: deliberately corrupting stack...\n", __progname);
 
     char buf[128];
     smash_stack_dummy_buf = buf;
@@ -134,9 +158,19 @@
 
 static int do_action(const char* arg)
 {
-    fprintf(stderr,"crasher: init pid=%d tid=%d\n", getpid(), gettid());
+    fprintf(stderr, "%s: init pid=%d tid=%d\n", __progname, getpid(), gettid());
 
-    if (!strncmp(arg, "thread-", strlen("thread-"))) {
+    if (!strncmp(arg, "wait-", strlen("wait-"))) {
+      char buf[1];
+      TEMP_FAILURE_RETRY(read(STDIN_FILENO, buf, sizeof(buf)));
+      return do_action(arg + strlen("wait-"));
+    } else if (!strncmp(arg, "exhaustfd-", strlen("exhaustfd-"))) {
+      errno = 0;
+      while (errno != EMFILE) {
+        open("/dev/null", O_RDONLY);
+      }
+      return do_action(arg + strlen("exhaustfd-"));
+    } else if (!strncmp(arg, "thread-", strlen("thread-"))) {
         return do_action_on_thread(arg + strlen("thread-"));
     } else if (!strcmp(arg, "SIGSEGV-non-null")) {
         sigsegv_non_null();
@@ -159,6 +193,10 @@
         __assert("some_file.c", 123, "false");
     } else if (!strcmp(arg, "assert2")) {
         __assert2("some_file.c", 123, "some_function", "false");
+    } else if (!strcmp(arg, "fortify")) {
+        char buf[10];
+        __read_chk(-1, buf, 32, 10);
+        while (true) pause();
     } else if (!strcmp(arg, "LOG_ALWAYS_FATAL")) {
         LOG_ALWAYS_FATAL("hello %s", "world");
     } else if (!strcmp(arg, "LOG_ALWAYS_FATAL_IF")) {
@@ -172,7 +210,7 @@
     } else if (!strcmp(arg, "heap-usage")) {
         abuse_heap();
     } else if (!strcmp(arg, "SIGSEGV-unmapped")) {
-        char* map = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+        char* map = reinterpret_cast<char*>(mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0));
         munmap(map, sizeof(int));
         map[0] = '8';
     }
@@ -189,6 +227,7 @@
     fprintf(stderr, "  abort                 call abort()\n");
     fprintf(stderr, "  assert                call assert() without a function\n");
     fprintf(stderr, "  assert2               call assert() with a function\n");
+    fprintf(stderr, "  fortify               fail a _FORTIFY_SOURCE check\n");
     fprintf(stderr, "  LOG_ALWAYS_FATAL      call LOG_ALWAYS_FATAL\n");
     fprintf(stderr, "  LOG_ALWAYS_FATAL_IF   call LOG_ALWAYS_FATAL\n");
     fprintf(stderr, "  SIGFPE                cause a SIGFPE\n");
@@ -198,14 +237,35 @@
     fprintf(stderr, "  SIGTRAP               cause a SIGTRAP\n");
     fprintf(stderr, "prefix any of the above with 'thread-' to not run\n");
     fprintf(stderr, "on the process' main thread.\n");
+    fprintf(stderr, "prefix any of the above with 'exhaustfd-' to exhaust\n");
+    fprintf(stderr, "all available file descriptors before crashing.\n");
+    fprintf(stderr, "prefix any of the above with 'wait-' to wait until input is received on stdin\n");
+
     return EXIT_SUCCESS;
 }
 
 int main(int argc, char **argv)
 {
-    fprintf(stderr,"crasher: built at " __TIME__ "!@\n");
+    fprintf(stderr, "%s: built at " __TIME__ "!@\n", __progname);
 
-    if(argc > 1) {
+#if defined(STATIC_CRASHER)
+    debuggerd_callbacks_t callbacks = {
+      .get_abort_message = []() {
+        static struct {
+          size_t size;
+          char msg[32];
+        } msg;
+
+        msg.size = strlen("dummy abort message");
+        memcpy(msg.msg, "dummy abort message", strlen("dummy abort message"));
+        return reinterpret_cast<abort_msg_t*>(&msg);
+      },
+      .post_dump = nullptr
+    };
+    debuggerd_init(&callbacks);
+#endif
+
+    if (argc > 1) {
         return do_action(argv[1]);
     } else {
         crash1();
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 7b57c20..867fd29 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -14,11 +14,14 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "debuggerd"
+
 #include <arpa/inet.h>
 #include <dirent.h>
 #include <elf.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <linux/input.h>
 #include <pthread.h>
 #include <signal.h>
 #include <stdarg.h>
@@ -39,19 +42,17 @@
 
 #include <selinux/android.h>
 
-#include <log/logger.h>
-
+#include <android/log.h>
 #include <android-base/file.h>
 #include <android-base/unique_fd.h>
 #include <cutils/debugger.h>
 #include <cutils/properties.h>
 #include <cutils/sockets.h>
-#include <nativehelper/ScopedFd.h>
-
-#include <linux/input.h>
 
 #include <private/android_filesystem_config.h>
 
+#include <debuggerd/client.h>
+
 #include "backtrace.h"
 #include "getevent.h"
 #include "signal_sender.h"
@@ -70,8 +71,8 @@
   debugger_action_t action;
   pid_t pid, tid;
   uid_t uid, gid;
+  pid_t ignore_tid;
   uintptr_t abort_msg_address;
-  int32_t original_si_code;
 };
 
 static void wait_for_user_action(const debugger_request_t& request) {
@@ -203,8 +204,6 @@
   }
 
   ALOGV("reading tid");
-  fcntl(fd, F_SETFL, O_NONBLOCK);
-
   pollfd pollfds[1];
   pollfds[0].fd = fd;
   pollfds[0].events = POLLIN;
@@ -229,11 +228,11 @@
 
   out_request->action = static_cast<debugger_action_t>(msg.action);
   out_request->tid = msg.tid;
+  out_request->ignore_tid = msg.ignore_tid;
   out_request->pid = cr.pid;
   out_request->uid = cr.uid;
   out_request->gid = cr.gid;
   out_request->abort_msg_address = msg.abort_msg_address;
-  out_request->original_si_code = msg.original_si_code;
 
   if (msg.action == DEBUGGER_ACTION_CRASH) {
     // Ensure that the tid reported by the crashing process is valid.
@@ -438,7 +437,7 @@
   return true;
 }
 
-static void ptrace_siblings(pid_t pid, pid_t main_tid, std::set<pid_t>& tids) {
+static void ptrace_siblings(pid_t pid, pid_t main_tid, pid_t ignore_tid, std::set<pid_t>& tids) {
   char task_path[PATH_MAX];
 
   if (snprintf(task_path, PATH_MAX, "/proc/%d/task", pid) >= PATH_MAX) {
@@ -467,7 +466,7 @@
       continue;
     }
 
-    if (tid == main_tid) {
+    if (tid == main_tid || tid == ignore_tid) {
       continue;
     }
 
@@ -488,9 +487,10 @@
     return false;
   }
 
-  int total_sleep_time_usec = 0;
   while (true) {
-    int signal = wait_for_signal(request.tid, &total_sleep_time_usec);
+    // wait_for_signal waits for forever, but the watchdog process will kill us
+    // if it takes too long.
+    int signal = wait_for_signal(request.tid);
     switch (signal) {
       case -1:
         ALOGE("debuggerd: timed out waiting for signal");
@@ -499,8 +499,8 @@
       case SIGSTOP:
         if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
           ALOGV("debuggerd: stopped -- dumping to tombstone");
-          engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings, signal,
-                            request.original_si_code, request.abort_msg_address, amfd_data);
+          engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings,
+                            request.abort_msg_address, amfd_data);
         } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
           ALOGV("debuggerd: stopped -- dumping to fd");
           dump_backtrace(fd, backtrace_map, request.pid, request.tid, siblings, nullptr);
@@ -526,8 +526,8 @@
       case SIGTRAP:
         ALOGV("stopped -- fatal signal\n");
         *crash_signal = signal;
-        engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings, signal,
-                          request.original_si_code, request.abort_msg_address, amfd_data);
+        engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings,
+                          request.abort_msg_address, amfd_data);
         break;
 
       default:
@@ -592,7 +592,7 @@
   // won't necessarily have stopped by the time ptrace() returns.  (We
   // currently assume it does.)  We write to the file descriptor to
   // ensure that it can run as soon as we call PTRACE_CONT below.
-  // See details in bionic/libc/linker/debugger.c, in function
+  // See details in client/debuggerd_client.cpp, in function
   // debugger_signal_handler().
 
   // Attach to the target process.
@@ -637,7 +637,7 @@
 
   std::set<pid_t> siblings;
   if (!attach_gdb) {
-    ptrace_siblings(request.pid, request.tid, siblings);
+    ptrace_siblings(request.pid, request.tid, request.ignore_tid, siblings);
   }
 
   // Generate the backtrace map before dropping privileges.
@@ -801,7 +801,7 @@
 static void handle_request(int fd) {
   ALOGV("handle_request(%d)\n", fd);
 
-  ScopedFd closer(fd);
+  android::base::unique_fd closer(fd);
   debugger_request_t request;
   memset(&request, 0, sizeof(request));
   int status = read_request(fd, &request);
@@ -874,12 +874,8 @@
   ALOGI("debuggerd: starting\n");
 
   for (;;) {
-    sockaddr_storage ss;
-    sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);
-    socklen_t alen = sizeof(ss);
-
     ALOGV("waiting for connection\n");
-    int fd = accept4(s, addrp, &alen, SOCK_CLOEXEC);
+    int fd = accept4(s, nullptr, nullptr, SOCK_CLOEXEC | SOCK_NONBLOCK);
     if (fd == -1) {
       ALOGE("accept failed: %s\n", strerror(errno));
       continue;
@@ -891,18 +887,19 @@
 }
 
 static int do_explicit_dump(pid_t tid, bool dump_backtrace) {
-  fprintf(stdout, "Sending request to dump task %d.\n", tid);
+  fprintf(stdout, "Sending request to dump task %d...\n", tid);
+  fflush(stdout);
 
+  // TODO: we could have better error reporting if debuggerd sent an error string back.
   if (dump_backtrace) {
-    fflush(stdout);
     if (dump_backtrace_to_file(tid, fileno(stdout)) < 0) {
-      fputs("Error dumping backtrace.\n", stderr);
+      fputs("Error dumping backtrace (check logcat).\n", stderr);
       return 1;
     }
   } else {
     char tombstone_path[PATH_MAX];
     if (dump_tombstone(tid, tombstone_path, sizeof(tombstone_path)) < 0) {
-      fputs("Error dumping tombstone.\n", stderr);
+      fputs("Error dumping tombstone (check logcat).\n", stderr);
       return 1;
     }
     fprintf(stderr, "Tombstone written to: %s\n", tombstone_path);
@@ -910,12 +907,14 @@
   return 0;
 }
 
-static void usage() {
-  fputs("Usage: -b [<tid>]\n"
-        "  -b dump backtrace to console, otherwise dump full tombstone file\n"
+static int usage() {
+  fputs("usage: debuggerd [-b] [<tid>]\n"
         "\n"
-        "If tid specified, sends a request to debuggerd to dump that task.\n"
-        "Otherwise, starts the debuggerd server.\n", stderr);
+        "Given a thread id, sends a request to debuggerd to dump that thread.\n"
+        "Otherwise, starts the debuggerd server.\n"
+        "\n"
+        "-b\tdump backtrace to console, otherwise generate tombstone\n", stderr);
+  return EXIT_FAILURE;
 }
 
 int main(int argc, char** argv) {
@@ -929,22 +928,15 @@
   }
 
   bool dump_backtrace = false;
-  bool have_tid = false;
   pid_t tid = 0;
   for (int i = 1; i < argc; i++) {
     if (!strcmp(argv[i], "-b")) {
       dump_backtrace = true;
-    } else if (!have_tid) {
-      tid = atoi(argv[i]);
-      have_tid = true;
-    } else {
-      usage();
-      return 1;
+    } else if (tid != 0 || (tid = atoi(argv[i])) == 0) {
+      // Only one tid is allowed. (And 0 isn't a valid tid.)
+      // atoi(3) returns 0 on failure to parse, so this catches anything else too.
+      return usage();
     }
   }
-  if (!have_tid) {
-    usage();
-    return 1;
-  }
-  return do_explicit_dump(tid, dump_backtrace);
+  return (tid != 0) ? do_explicit_dump(tid, dump_backtrace) : usage();
 }
diff --git a/debuggerd/elf_utils.cpp b/debuggerd/elf_utils.cpp
index 9959f2e..d760a37 100644
--- a/debuggerd/elf_utils.cpp
+++ b/debuggerd/elf_utils.cpp
@@ -23,13 +23,13 @@
 
 #include <string>
 
-#include <backtrace/Backtrace.h>
+#include <android/log.h>
 #include <android-base/stringprintf.h>
-#include <log/log.h>
+#include <backtrace/Backtrace.h>
 
 #include "elf_utils.h"
 
-#define NOTE_ALIGN(size)  ((size + 3) & ~3)
+#define NOTE_ALIGN(size)  (((size) + 3) & ~3)
 
 template <typename HdrType, typename PhdrType, typename NhdrType>
 static bool get_build_id(
diff --git a/debuggerd/getevent.cpp b/debuggerd/getevent.cpp
index 751c4fb..dbb878a 100644
--- a/debuggerd/getevent.cpp
+++ b/debuggerd/getevent.cpp
@@ -14,19 +14,23 @@
  * limitations under the License.
  */
 
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/input.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <stdint.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
 #include <sys/inotify.h>
+#include <sys/ioctl.h>
 #include <sys/limits.h>
 #include <sys/poll.h>
-#include <linux/input.h>
-#include <errno.h>
-#include <cutils/log.h>
+#include <unistd.h>
+
+#include <memory>
+
+#include <android/log.h>
 
 static struct pollfd* ufds;
 static char** device_names;
@@ -143,22 +147,20 @@
 static int scan_dir(const char* dirname) {
   char devname[PATH_MAX];
   char* filename;
-  DIR* dir;
   struct dirent* de;
-  dir = opendir(dirname);
+  std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirname), closedir);
   if (dir == NULL)
     return -1;
   strcpy(devname, dirname);
   filename = devname + strlen(devname);
   *filename++ = '/';
-  while ((de = readdir(dir))) {
+  while ((de = readdir(dir.get()))) {
     if ((de->d_name[0] == '.' && de->d_name[1] == '\0') ||
         (de->d_name[1] == '.' && de->d_name[2] == '\0'))
       continue;
     strcpy(filename, de->d_name);
     open_device(devname);
   }
-  closedir(dir);
   return 0;
 }
 
diff --git a/debuggerd/include/debuggerd/client.h b/debuggerd/include/debuggerd/client.h
new file mode 100644
index 0000000..aeb723b
--- /dev/null
+++ b/debuggerd/include/debuggerd/client.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+// On 32-bit devices, DEBUGGER_SOCKET_NAME is a 32-bit debuggerd.
+// On 64-bit devices, DEBUGGER_SOCKET_NAME is a 64-bit debuggerd.
+#define DEBUGGER_SOCKET_NAME "android:debuggerd"
+
+// Used only on 64-bit devices for debuggerd32.
+#define DEBUGGER32_SOCKET_NAME "android:debuggerd32"
+
+__BEGIN_DECLS
+
+typedef enum {
+  // dump a crash
+  DEBUGGER_ACTION_CRASH,
+  // dump a tombstone file
+  DEBUGGER_ACTION_DUMP_TOMBSTONE,
+  // dump a backtrace only back to the socket
+  DEBUGGER_ACTION_DUMP_BACKTRACE,
+} debugger_action_t;
+
+// Make sure that all values have a fixed size so that this structure
+// is the same for 32 bit and 64 bit processes.
+typedef struct __attribute__((packed)) {
+  int32_t action;
+  pid_t tid;
+  pid_t ignore_tid;
+  uint64_t abort_msg_address;
+} debugger_msg_t;
+
+// These callbacks are called in a signal handler, and thus must be async signal safe.
+// If null, the callbacks will not be called.
+typedef struct {
+  struct abort_msg_t* (*get_abort_message)();
+  void (*post_dump)();
+} debuggerd_callbacks_t;
+
+void debuggerd_init(debuggerd_callbacks_t* callbacks);
+
+__END_DECLS
diff --git a/debuggerd/mips/machine.cpp b/debuggerd/mips/machine.cpp
index cbf272a..99a9d65 100644
--- a/debuggerd/mips/machine.cpp
+++ b/debuggerd/mips/machine.cpp
@@ -22,8 +22,8 @@
 #include <string.h>
 #include <sys/ptrace.h>
 
+#include <android/log.h>
 #include <backtrace/Backtrace.h>
-#include <log/log.h>
 
 #include "machine.h"
 #include "utility.h"
diff --git a/debuggerd/mips64/machine.cpp b/debuggerd/mips64/machine.cpp
index 0a8d532..ecd1ca2 100644
--- a/debuggerd/mips64/machine.cpp
+++ b/debuggerd/mips64/machine.cpp
@@ -22,8 +22,8 @@
 #include <string.h>
 #include <sys/ptrace.h>
 
+#include <android/log.h>
 #include <backtrace/Backtrace.h>
-#include <log/log.h>
 
 #include "machine.h"
 #include "utility.h"
diff --git a/debuggerd/signal_sender.cpp b/debuggerd/signal_sender.cpp
index 4be7e6e..7fe4dee 100644
--- a/debuggerd/signal_sender.cpp
+++ b/debuggerd/signal_sender.cpp
@@ -14,7 +14,10 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "debuggerd-signal"
+
 #include <errno.h>
+#include <pthread.h>
 #include <signal.h>
 #include <stdlib.h>
 #include <string.h>
@@ -24,7 +27,7 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
-#include <log/logger.h>
+#include <android/log.h>
 
 #include "signal_sender.h"
 
diff --git a/debuggerd/test/BacktraceMock.h b/debuggerd/test/BacktraceMock.h
index f75534e..6104f7e 100644
--- a/debuggerd/test/BacktraceMock.h
+++ b/debuggerd/test/BacktraceMock.h
@@ -41,7 +41,7 @@
 
 class BacktraceMock : public Backtrace {
  public:
-  BacktraceMock(BacktraceMapMock* map) : Backtrace(0, 0, map) {
+  explicit BacktraceMock(BacktraceMapMock* map) : Backtrace(0, 0, map) {
     if (map_ == nullptr) {
       abort();
     }
diff --git a/debuggerd/test/host_signal_fixup.h b/debuggerd/test/host_signal_fixup.h
index c7796ef..762bae5 100644
--- a/debuggerd/test/host_signal_fixup.h
+++ b/debuggerd/test/host_signal_fixup.h
@@ -57,7 +57,7 @@
 #endif
 
 #if !defined(SI_DETHREAD)
-#define SI_DETHREAD -7
+#define SI_DETHREAD (-7)
 #endif
 
 #endif
diff --git a/debuggerd/test/log_fake.cpp b/debuggerd/test/log_fake.cpp
index e27e9f6..3336bcb 100644
--- a/debuggerd/test/log_fake.cpp
+++ b/debuggerd/test/log_fake.cpp
@@ -21,7 +21,6 @@
 
 #include <android-base/stringprintf.h>
 #include <log/log.h>
-#include <log/logger.h>
 
 // Forward declarations.
 class Backtrace;
diff --git a/debuggerd/test/tombstone_test.cpp b/debuggerd/test/tombstone_test.cpp
index 58d640e..5ee07cd 100644
--- a/debuggerd/test/tombstone_test.cpp
+++ b/debuggerd/test/tombstone_test.cpp
@@ -595,7 +595,7 @@
   si.si_signo = 0;
   ptrace_set_fake_getsiginfo(si);
 
-  dump_signal_info(&log_, 123, SIGSEGV, 10);
+  dump_signal_info(&log_, 123);
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index dfdf29c..1e47483 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -25,23 +25,21 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <time.h>
 #include <sys/ptrace.h>
 #include <sys/stat.h>
+#include <time.h>
 
 #include <memory>
 #include <string>
 
-#include <private/android_filesystem_config.h>
-
 #include <android-base/stringprintf.h>
-#include <cutils/properties.h>
-#include <log/log.h>
-#include <log/logger.h>
-#include <log/logprint.h>
-
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
+#include <cutils/properties.h>
+#include <log/log.h>
+#include <log/logprint.h>
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
 
 #include <selinux/android.h>
 
@@ -56,8 +54,13 @@
 #define TOMBSTONE_DIR   "/data/tombstones"
 #define TOMBSTONE_TEMPLATE (TOMBSTONE_DIR"/tombstone_%02d")
 
-static bool signal_has_si_addr(int sig) {
-  switch (sig) {
+static bool signal_has_si_addr(int si_signo, int si_code) {
+  // Manually sent signals won't have si_addr.
+  if (si_code == SI_USER || si_code == SI_QUEUE || si_code == SI_TKILL) {
+    return false;
+  }
+
+  switch (si_signo) {
     case SIGBUS:
     case SIGFPE:
     case SIGILL:
@@ -80,6 +83,7 @@
     case SIGSTKFLT: return "SIGSTKFLT";
 #endif
     case SIGSTOP: return "SIGSTOP";
+    case SIGSYS: return "SIGSYS";
     case SIGTRAP: return "SIGTRAP";
     default: return "?";
   }
@@ -131,13 +135,26 @@
 #if defined(SEGV_BNDERR)
         case SEGV_BNDERR: return "SEGV_BNDERR";
 #endif
+#if defined(SEGV_PKUERR)
+        case SEGV_PKUERR: return "SEGV_PKUERR";
+#endif
       }
-#if defined(SEGV_BNDERR)
+#if defined(SEGV_PKUERR)
+      static_assert(NSIGSEGV == SEGV_PKUERR, "missing SEGV_* si_code");
+#elif defined(SEGV_BNDERR)
       static_assert(NSIGSEGV == SEGV_BNDERR, "missing SEGV_* si_code");
 #else
       static_assert(NSIGSEGV == SEGV_ACCERR, "missing SEGV_* si_code");
 #endif
       break;
+#if defined(SYS_SECCOMP) // Our glibc is too old, and we build this for the host too.
+    case SIGSYS:
+      switch (code) {
+        case SYS_SECCOMP: return "SYS_SECCOMP";
+      }
+      static_assert(NSIGSYS == SYS_SECCOMP, "missing SYS_* si_code");
+      break;
+#endif
     case SIGTRAP:
       switch (code) {
         case TRAP_BRKPT: return "TRAP_BRKPT";
@@ -176,7 +193,7 @@
   _LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING);
 }
 
-static void dump_signal_info(log_t* log, pid_t tid, int signal, int si_code) {
+static void dump_signal_info(log_t* log, pid_t tid) {
   siginfo_t si;
   memset(&si, 0, sizeof(si));
   if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si) == -1) {
@@ -184,18 +201,15 @@
     return;
   }
 
-  // bionic has to re-raise some signals, which overwrites the si_code with SI_TKILL.
-  si.si_code = si_code;
-
   char addr_desc[32]; // ", fault addr 0x1234"
-  if (signal_has_si_addr(signal)) {
+  if (signal_has_si_addr(si.si_signo, si.si_code)) {
     snprintf(addr_desc, sizeof(addr_desc), "%p", si.si_addr);
   } else {
     snprintf(addr_desc, sizeof(addr_desc), "--------");
   }
 
-  _LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s), fault addr %s\n",
-       signal, get_signame(signal), si.si_code, get_sigcode(signal, si.si_code), addr_desc);
+  _LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s), fault addr %s\n", si.si_signo,
+       get_signame(si.si_signo), si.si_code, get_sigcode(si.si_signo, si.si_code), addr_desc);
 }
 
 static void dump_thread_info(log_t* log, pid_t pid, pid_t tid) {
@@ -362,7 +376,7 @@
   siginfo_t si;
   memset(&si, 0, sizeof(si));
   if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si) != -1) {
-    print_fault_address_marker = signal_has_si_addr(si.si_signo);
+    print_fault_address_marker = signal_has_si_addr(si.si_signo, si.si_code);
     addr = reinterpret_cast<uintptr_t>(si.si_addr);
   } else {
     ALOGE("Cannot get siginfo for %d: %s\n", tid, strerror(errno));
@@ -445,17 +459,14 @@
   }
 }
 
-static void dump_thread(log_t* log, pid_t pid, pid_t tid, BacktraceMap* map, int signal,
-                        int si_code, uintptr_t abort_msg_address, bool primary_thread) {
+static void dump_thread(log_t* log, pid_t pid, pid_t tid, BacktraceMap* map,
+                        uintptr_t abort_msg_address, bool primary_thread) {
   log->current_tid = tid;
   if (!primary_thread) {
     _LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
   }
   dump_thread_info(log, pid, tid);
-
-  if (signal) {
-    dump_signal_info(log, tid, signal, si_code);
-  }
+  dump_signal_info(log, tid);
 
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map));
   if (primary_thread) {
@@ -545,6 +556,10 @@
     if (!hdr_size) {
       hdr_size = sizeof(log_entry.entry_v1);
     }
+    if ((hdr_size < sizeof(log_entry.entry_v1)) ||
+        (hdr_size > sizeof(log_entry.entry))) {
+      continue;
+    }
     char* msg = reinterpret_cast<char*>(log_entry.buf) + hdr_size;
 
     char timeBuf[32];
@@ -561,9 +576,9 @@
       AndroidLogEntry e;
       char buf[512];
       android_log_processBinaryLogBuffer(entry, &e, g_eventTagMap, buf, sizeof(buf));
-      _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8s: %s\n",
+      _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8.*s: %s\n",
          timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
-         'I', e.tag, e.message);
+         'I', (int)e.tagLen, e.tag, e.message);
       continue;
     }
 
@@ -606,24 +621,21 @@
 
 // Dumps all information about the specified pid to the tombstone.
 static void dump_crash(log_t* log, BacktraceMap* map, pid_t pid, pid_t tid,
-                       const std::set<pid_t>& siblings, int signal, int si_code,
-                       uintptr_t abort_msg_address) {
+                       const std::set<pid_t>& siblings, uintptr_t abort_msg_address) {
   // don't copy log messages to tombstone unless this is a dev device
-  char value[PROPERTY_VALUE_MAX];
-  property_get("ro.debuggable", value, "0");
-  bool want_logs = (value[0] == '1');
+  bool want_logs = __android_log_is_debuggable();
 
   _LOG(log, logtype::HEADER,
        "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
   dump_header_info(log);
-  dump_thread(log, pid, tid, map, signal, si_code, abort_msg_address, true);
+  dump_thread(log, pid, tid, map, abort_msg_address, true);
   if (want_logs) {
     dump_logs(log, pid, 5);
   }
 
   if (!siblings.empty()) {
     for (pid_t sibling : siblings) {
-      dump_thread(log, pid, sibling, map, 0, 0, 0, false);
+      dump_thread(log, pid, sibling, map, 0, false);
     }
   }
 
@@ -686,8 +698,8 @@
 }
 
 void engrave_tombstone(int tombstone_fd, BacktraceMap* map, pid_t pid, pid_t tid,
-                       const std::set<pid_t>& siblings, int signal, int original_si_code,
-                       uintptr_t abort_msg_address, std::string* amfd_data) {
+                       const std::set<pid_t>& siblings, uintptr_t abort_msg_address,
+                       std::string* amfd_data) {
   log_t log;
   log.current_tid = tid;
   log.crashed_tid = tid;
@@ -699,5 +711,5 @@
 
   log.tfd = tombstone_fd;
   log.amfd_data = amfd_data;
-  dump_crash(&log, map, pid, tid, siblings, signal, original_si_code, abort_msg_address);
+  dump_crash(&log, map, pid, tid, siblings, abort_msg_address);
 }
diff --git a/debuggerd/tombstone.h b/debuggerd/tombstone.h
index 487d950..e1c39c5 100644
--- a/debuggerd/tombstone.h
+++ b/debuggerd/tombstone.h
@@ -33,7 +33,7 @@
 
 /* Creates a tombstone file and writes the crash dump to it. */
 void engrave_tombstone(int tombstone_fd, BacktraceMap* map, pid_t pid, pid_t tid,
-                       const std::set<pid_t>& siblings, int signal, int original_si_code,
-                       uintptr_t abort_msg_address, std::string* amfd_data);
+                       const std::set<pid_t>& siblings, uintptr_t abort_msg_address,
+                       std::string* amfd_data);
 
 #endif // _DEBUGGERD_TOMBSTONE_H
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index bd06095..419d36c 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -21,9 +21,9 @@
 #include <errno.h>
 #include <signal.h>
 #include <string.h>
-#include <unistd.h>
 #include <sys/ptrace.h>
 #include <sys/wait.h>
+#include <unistd.h>
 
 #include <string>
 
@@ -31,9 +31,6 @@
 #include <backtrace/Backtrace.h>
 #include <log/log.h>
 
-constexpr int SLEEP_TIME_USEC = 50000;          // 0.05 seconds
-constexpr int MAX_TOTAL_SLEEP_USEC = 10000000;  // 10 seconds
-
 // Whitelist output desired in the logcat output.
 bool is_allowed_in_logcat(enum logtype ltype) {
   if ((ltype == HEADER)
@@ -74,10 +71,10 @@
   }
 }
 
-int wait_for_signal(pid_t tid, int* total_sleep_time_usec) {
+int wait_for_signal(pid_t tid) {
   while (true) {
     int status;
-    pid_t n = TEMP_FAILURE_RETRY(waitpid(tid, &status, __WALL | WNOHANG));
+    pid_t n = TEMP_FAILURE_RETRY(waitpid(tid, &status, __WALL));
     if (n == -1) {
       ALOGE("waitpid failed: tid %d, %s", tid, strerror(errno));
       return -1;
@@ -91,14 +88,6 @@
         return -1;
       }
     }
-
-    if (*total_sleep_time_usec > MAX_TOTAL_SLEEP_USEC) {
-      ALOGE("timed out waiting for stop signal: tid=%d", tid);
-      return -1;
-    }
-
-    usleep(SLEEP_TIME_USEC);
-    *total_sleep_time_usec += SLEEP_TIME_USEC;
   }
 }
 
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index cd01188..d820f0f 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -77,7 +77,7 @@
 void _LOG(log_t* log, logtype ltype, const char *fmt, ...)
         __attribute__ ((format(printf, 3, 4)));
 
-int wait_for_signal(pid_t tid, int* total_sleep_time_usec);
+int wait_for_signal(pid_t tid);
 
 void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* fmt, ...);
 
diff --git a/debuggerd/x86/machine.cpp b/debuggerd/x86/machine.cpp
index af10817..a6f21e1 100644
--- a/debuggerd/x86/machine.cpp
+++ b/debuggerd/x86/machine.cpp
@@ -21,8 +21,8 @@
 #include <string.h>
 #include <sys/ptrace.h>
 
+#include <android/log.h>
 #include <backtrace/Backtrace.h>
-#include <log/log.h>
 
 #include "machine.h"
 #include "utility.h"
diff --git a/debuggerd/x86_64/machine.cpp b/debuggerd/x86_64/machine.cpp
index fc86bc2..705e12d 100644
--- a/debuggerd/x86_64/machine.cpp
+++ b/debuggerd/x86_64/machine.cpp
@@ -22,8 +22,8 @@
 #include <string.h>
 #include <sys/user.h>
 
+#include <android/log.h>
 #include <backtrace/Backtrace.h>
-#include <log/log.h>
 
 #include "machine.h"
 #include "utility.h"
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 1b4ecbe..286de5b 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -21,7 +21,6 @@
 LOCAL_C_INCLUDES := \
   $(LOCAL_PATH)/../adb \
   $(LOCAL_PATH)/../mkbootimg \
-  $(LOCAL_PATH)/../../extras/ext4_utils \
   $(LOCAL_PATH)/../../extras/f2fs_utils \
 
 LOCAL_SRC_FILES := \
@@ -38,27 +37,26 @@
 LOCAL_MODULE := fastboot
 LOCAL_MODULE_TAGS := debug
 LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_CONLYFLAGS += -std=gnu99
 LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
 
 LOCAL_CFLAGS += -DFASTBOOT_REVISION='"$(fastboot_version)"'
 
-LOCAL_SRC_FILES_linux := usb_linux.cpp util_linux.cpp
+LOCAL_SRC_FILES_linux := usb_linux.cpp
 LOCAL_STATIC_LIBRARIES_linux := libselinux
 
-LOCAL_SRC_FILES_darwin := usb_osx.cpp util_osx.cpp
+LOCAL_SRC_FILES_darwin := usb_osx.cpp
 LOCAL_STATIC_LIBRARIES_darwin := libselinux
 LOCAL_LDLIBS_darwin := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
 LOCAL_CFLAGS_darwin := -Wno-unused-parameter
 
-LOCAL_SRC_FILES_windows := usb_windows.cpp util_windows.cpp
+LOCAL_SRC_FILES_windows := usb_windows.cpp
 LOCAL_STATIC_LIBRARIES_windows := AdbWinApi
 LOCAL_REQUIRED_MODULES_windows := AdbWinApi
 LOCAL_LDLIBS_windows := -lws2_32
 LOCAL_C_INCLUDES_windows := development/host/windows/usb/api
 
 LOCAL_STATIC_LIBRARIES := \
-    libziparchive-host \
+    libziparchive \
     libext4_utils_host \
     libsparse_host \
     libutils \
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index 47567c0..728dcb8 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -38,8 +38,6 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#define ARRAY_SIZE(x)           (sizeof(x)/sizeof(x[0]))
-
 #define OP_DOWNLOAD   1
 #define OP_COMMAND    2
 #define OP_QUERY      3
@@ -351,21 +349,21 @@
         }
         if (a->op == OP_DOWNLOAD) {
             status = fb_download_data(transport, a->data, a->size);
-            status = a->func(a, status, status ? fb_get_error() : "");
+            status = a->func(a, status, status ? fb_get_error().c_str() : "");
             if (status) break;
         } else if (a->op == OP_COMMAND) {
             status = fb_command(transport, a->cmd);
-            status = a->func(a, status, status ? fb_get_error() : "");
+            status = a->func(a, status, status ? fb_get_error().c_str() : "");
             if (status) break;
         } else if (a->op == OP_QUERY) {
             status = fb_command_response(transport, a->cmd, resp);
-            status = a->func(a, status, status ? fb_get_error() : resp);
+            status = a->func(a, status, status ? fb_get_error().c_str() : resp);
             if (status) break;
         } else if (a->op == OP_NOTICE) {
             fprintf(stderr,"%s\n",(char*)a->data);
         } else if (a->op == OP_DOWNLOAD_SPARSE) {
             status = fb_download_data_sparse(transport, reinterpret_cast<sparse_file*>(a->data));
-            status = a->func(a, status, status ? fb_get_error() : "");
+            status = a->func(a, status, status ? fb_get_error().c_str() : "");
             if (status) break;
         } else if (a->op == OP_WAIT_FOR_DISCONNECT) {
             transport->WaitForDisconnect();
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 2b6cad1..7f4a0dd 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -43,10 +43,14 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <chrono>
 #include <functional>
+#include <thread>
 #include <utility>
 #include <vector>
 
+#include <android-base/file.h>
+#include <android-base/macros.h>
 #include <android-base/parseint.h>
 #include <android-base/parsenetaddress.h>
 #include <android-base/stringprintf.h>
@@ -67,8 +71,6 @@
 #define O_BINARY 0
 #endif
 
-#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
-
 char cur_product[FB_RESPONSE_SZ + 1];
 
 static const char* serial = nullptr;
@@ -116,11 +118,8 @@
 };
 
 static std::string find_item_given_name(const char* img_name, const char* product) {
-    char path_c_str[PATH_MAX + 128];
-
     if(product) {
-        get_my_path(path_c_str);
-        std::string path = path_c_str;
+        std::string path = android::base::GetExecutablePath();
         path.erase(path.find_last_of('/'));
         return android::base::StringPrintf("%s/../../../target/product/%s/%s",
                                            path.c_str(), product, img_name);
@@ -137,7 +136,7 @@
 std::string find_item(const char* item, const char* product) {
     const char *fn;
 
-    if(!strcmp(item,"boot")) {
+    if (!strcmp(item,"boot")) {
         fn = "boot.img";
     } else if(!strcmp(item,"recovery")) {
         fn = "recovery.img";
@@ -189,8 +188,8 @@
     return 0;
 }
 
-static void* load_file(const char* fn, int64_t* sz) {
-    int fd = open(fn, O_RDONLY | O_BINARY);
+static void* load_file(const std::string& path, int64_t* sz) {
+    int fd = open(path.c_str(), O_RDONLY | O_BINARY);
     if (fd == -1) return nullptr;
     return load_fd(fd, sz);
 }
@@ -304,7 +303,7 @@
             announce = false;
             fprintf(stderr, "< waiting for %s >\n", serial ? serial : "any device");
         }
-        usleep(1000);
+        std::this_thread::sleep_for(std::chrono::milliseconds(1));
     }
 }
 
@@ -400,12 +399,14 @@
             "  -a, --set-active[=<slot>]                Sets the active slot. If no slot is\n"
             "                                           provided, this will default to the value\n"
             "                                           given by --slot. If slots are not\n"
-            "                                           supported, this sets the current slot\n"
-            "                                           to be active. This will run after all\n"
-            "                                           non-reboot commands.\n"
+            "                                           supported, this does nothing. This will\n"
+            "                                           run after all non-reboot commands.\n"
             "  --skip-secondary                         Will not flash secondary slots when\n"
             "                                           performing a flashall or update. This\n"
             "                                           will preserve data on other slots.\n"
+            "  --skip-reboot                            Will not reboot the device when\n"
+            "                                           performing commands that normally\n"
+            "                                           trigger a reboot.\n"
 #if !defined(_WIN32)
             "  --wipe-and-use-fbe                       On devices which support it,\n"
             "                                           erase userdata and cache, and\n"
@@ -602,6 +603,7 @@
     ZipEntry zip_entry;
     if (FindEntry(zip, zip_entry_name, &zip_entry) != 0) {
         fprintf(stderr, "archive does not contain '%s'\n", entry_name);
+        fclose(fp);
         return -1;
     }
 
@@ -609,10 +611,12 @@
     int error = ExtractEntryToFile(zip, &zip_entry, fd);
     if (error != 0) {
         fprintf(stderr, "failed to extract '%s': %s\n", entry_name, ErrorCodeString(error));
+        fclose(fp);
         return -1;
     }
 
     lseek(fd, 0, SEEK_SET);
+    // TODO: We're leaking 'fp' here.
     return fd;
 }
 
@@ -753,7 +757,7 @@
     max_download_size = android::base::Trim(max_download_size);
 
     uint64_t limit;
-    if (!android::base::ParseUint(max_download_size.c_str(), &limit)) {
+    if (!android::base::ParseUint(max_download_size, &limit)) {
         fprintf(stderr, "couldn't parse max-download-size '%s'\n", max_download_size.c_str());
         return 0;
     }
@@ -799,10 +803,10 @@
     return partition_type == "ext4";
 }
 
-static int load_buf_fd(Transport* transport, int fd, struct fastboot_buffer* buf) {
+static bool load_buf_fd(Transport* transport, int fd, struct fastboot_buffer* buf) {
     int64_t sz = get_file_size(fd);
     if (sz == -1) {
-        return -1;
+        return false;
     }
 
     lseek64(fd, 0, SEEK_SET);
@@ -810,7 +814,7 @@
     if (limit) {
         sparse_file** s = load_sparse_files(fd, limit);
         if (s == nullptr) {
-            return -1;
+            return false;
         }
         buf->type = FB_BUFFER_SPARSE;
         buf->data = s;
@@ -822,18 +826,14 @@
         buf->sz = sz;
     }
 
-    return 0;
+    return true;
 }
 
-static int load_buf(Transport* transport, const char *fname, struct fastboot_buffer *buf)
-{
-    int fd;
-
-    fd = open(fname, O_RDONLY | O_BINARY);
-    if (fd < 0) {
-        return -1;
+static bool load_buf(Transport* transport, const char* fname, struct fastboot_buffer* buf) {
+    int fd = open(fname, O_RDONLY | O_BINARY);
+    if (fd == -1) {
+        return false;
     }
-
     return load_buf_fd(transport, fd, buf);
 }
 
@@ -905,7 +905,7 @@
     if (!fb_getvar(transport, "slot-count", &var)) {
         if (supports_AB_obsolete(transport)) return 2; // Legacy support
     }
-    if (!android::base::ParseInt(var.c_str(), &count)) return 0;
+    if (!android::base::ParseInt(var, &count)) return 0;
     return count;
 }
 
@@ -976,7 +976,7 @@
 }
 
 static void do_for_partition(Transport* transport, const std::string& part, const std::string& slot,
-                             std::function<void(const std::string&)> func, bool force_slot) {
+                             const std::function<void(const std::string&)>& func, bool force_slot) {
     std::string has_slot;
     std::string current_slot;
 
@@ -1009,7 +1009,7 @@
  * partition does not support slots.
  */
 static void do_for_partitions(Transport* transport, const std::string& part, const std::string& slot,
-                              std::function<void(const std::string&)> func, bool force_slot) {
+                              const std::function<void(const std::string&)>& func, bool force_slot) {
     std::string has_slot;
 
     if (slot == "all") {
@@ -1031,8 +1031,8 @@
 static void do_flash(Transport* transport, const char* pname, const char* fname) {
     struct fastboot_buffer buf;
 
-    if (load_buf(transport, fname, &buf)) {
-        die("cannot load '%s'", fname);
+    if (!load_buf(transport, fname, &buf)) {
+        die("cannot load '%s': %s", fname, strerror(errno));
     }
     flash_buf(pname, &buf);
 }
@@ -1101,7 +1101,7 @@
             skip_secondary = true;
         }
     }
-    for (size_t i = 0; i < ARRAY_SIZE(images); ++i) {
+    for (size_t i = 0; i < arraysize(images); ++i) {
         const char* slot = slot_override.c_str();
         if (images[i].is_secondary) {
             if (!skip_secondary) {
@@ -1120,8 +1120,9 @@
             exit(1); // unzip_to_file already explained why.
         }
         fastboot_buffer buf;
-        int rc = load_buf_fd(transport, fd, &buf);
-        if (rc) die("cannot load %s from flash", images[i].img_name);
+        if (!load_buf_fd(transport, fd, &buf)) {
+            die("cannot load %s from flash: %s", images[i].img_name, strerror(errno));
+        }
 
         auto update = [&](const std::string &partition) {
             do_update_signature(zip, images[i].sig_name);
@@ -1154,6 +1155,7 @@
     int64_t sz;
     void* data = load_file(fs_sig.c_str(), &sz);
     if (data == nullptr) return;
+
     fb_queue_download("signature", data, sz);
     fb_queue_command("signature", "installing signature");
 }
@@ -1165,7 +1167,7 @@
     fb_queue_query_save("product", cur_product, sizeof(cur_product));
 
     fname = find_item("info", product);
-    if (fname == "") die("cannot find android-info.txt");
+    if (fname.empty()) die("cannot find android-info.txt");
 
     int64_t sz;
     void* data = load_file(fname.c_str(), &sz);
@@ -1188,7 +1190,7 @@
         }
     }
 
-    for (size_t i = 0; i < ARRAY_SIZE(images); i++) {
+    for (size_t i = 0; i < arraysize(images); i++) {
         const char* slot = NULL;
         if (images[i].is_secondary) {
             if (!skip_secondary) slot = secondary.c_str();
@@ -1198,13 +1200,13 @@
         if (!slot) continue;
         fname = find_item_given_name(images[i].img_name, product);
         fastboot_buffer buf;
-        if (load_buf(transport, fname.c_str(), &buf)) {
+        if (!load_buf(transport, fname.c_str(), &buf)) {
             if (images[i].is_optional) continue;
-            die("could not load %s\n", images[i].img_name);
+            die("could not load '%s': %s\n", images[i].img_name, strerror(errno));
         }
 
         auto flashall = [&](const std::string &partition) {
-            do_send_signature(fname);
+            do_send_signature(fname.c_str());
             if (erase_first && needs_erase(transport, partition.c_str())) {
                 fb_queue_erase(partition.c_str());
             }
@@ -1362,7 +1364,7 @@
     }
 
     int64_t size;
-    if (!android::base::ParseInt(partition_size.c_str(), &size)) {
+    if (!android::base::ParseInt(partition_size, &size)) {
         fprintf(stderr, "Couldn't parse partition size '%s'.\n", partition_size.c_str());
         return;
     }
@@ -1374,7 +1376,7 @@
         return;
     }
 
-    if (load_buf_fd(transport, fd, &buf)) {
+    if (!load_buf_fd(transport, fd, &buf)) {
         fprintf(stderr, "Cannot read image: %s\n", strerror(errno));
         close(fd);
         return;
@@ -1387,7 +1389,7 @@
         fprintf(stderr, "Erase successful, but not automatically formatting.\n");
         if (errMsg) fprintf(stderr, "%s", errMsg);
     }
-    fprintf(stderr,"FAILED (%s)\n", fb_get_error());
+    fprintf(stderr, "FAILED (%s)\n", fb_get_error().c_str());
 }
 
 int main(int argc, char **argv)
@@ -1395,6 +1397,7 @@
     bool wants_wipe = false;
     bool wants_reboot = false;
     bool wants_reboot_bootloader = false;
+    bool skip_reboot = false;
     bool wants_set_active = false;
     bool skip_secondary = false;
     bool erase_first = true;
@@ -1422,6 +1425,7 @@
         {"set_active", optional_argument, 0, 'a'},
         {"set-active", optional_argument, 0, 'a'},
         {"skip-secondary", no_argument, 0, 0},
+        {"skip-reboot", no_argument, 0, 0},
 #if !defined(_WIN32)
         {"wipe-and-use-fbe", no_argument, 0, 0},
 #endif
@@ -1508,6 +1512,8 @@
                 slot_override = std::string(optarg);
             } else if (strcmp("skip-secondary", longopts[longindex].name) == 0 ) {
                 skip_secondary = true;
+            } else if (strcmp("skip-reboot", longopts[longindex].name) == 0 ) {
+                skip_reboot = true;
 #if !defined(_WIN32)
             } else if (strcmp("wipe-and-use-fbe", longopts[longindex].name) == 0) {
                 wants_wipe = true;
@@ -1672,7 +1678,7 @@
             fb_queue_download("boot.img", data, sz);
             fb_queue_command("boot", "booting");
         } else if(!strcmp(*argv, "flash")) {
-            char *pname = argv[1];
+            char* pname = argv[1];
             std::string fname;
             require(2);
             if (argc > 2) {
@@ -1682,7 +1688,7 @@
                 fname = find_item(pname, product);
                 skip(2);
             }
-            if (fname == "") die("cannot determine image filename for '%s'", pname);
+            if (fname.empty()) die("cannot determine image filename for '%s'", pname);
 
             auto flash = [&](const std::string &partition) {
                 if (erase_first && needs_erase(transport, partition.c_str())) {
@@ -1732,7 +1738,7 @@
                 do_update(transport, "update.zip", slot_override, erase_first, skip_secondary || slot_all);
                 skip(1);
             }
-            wants_reboot = 1;
+            wants_reboot = true;
         } else if(!strcmp(*argv, "set_active")) {
             require(2);
             std::string slot = verify_slot(transport, std::string(argv[1]), false);
@@ -1787,7 +1793,7 @@
     if (wants_set_active) {
         fb_set_active(next_active.c_str());
     }
-    if (wants_reboot) {
+    if (wants_reboot && !skip_reboot) {
         fb_queue_reboot();
         fb_queue_wait_for_disconnect();
     } else if (wants_reboot_bootloader) {
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index 1932bab..6699b6a 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -43,7 +43,7 @@
 int fb_command_response(Transport* transport, const char* cmd, char* response);
 int fb_download_data(Transport* transport, const void* data, uint32_t size);
 int fb_download_data_sparse(Transport* transport, struct sparse_file* s);
-char *fb_get_error(void);
+const std::string fb_get_error();
 
 #define FB_COMMAND_SZ 64
 #define FB_RESPONSE_SZ 64
@@ -72,8 +72,6 @@
 char *mkmsg(const char *fmt, ...);
 __attribute__((__noreturn__)) void die(const char *fmt, ...);
 
-void get_my_path(char *path);
-
 /* Current product */
 extern char cur_product[FB_RESPONSE_SZ + 1];
 
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index 8539e23..9b73165 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -1,7 +1,6 @@
 #include "fs.h"
 
 #include "fastboot.h"
-#include "make_ext4fs.h"
 #include "make_f2fs.h"
 
 #include <errno.h>
@@ -12,6 +11,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <ext4_utils/make_ext4fs.h>
 #include <sparse/sparse.h>
 
 static int generate_ext4_image(int fd, long long partSize, const std::string& initial_dir)
diff --git a/fastboot/protocol.cpp b/fastboot/protocol.cpp
index 4850b4a..bfa83b0 100644
--- a/fastboot/protocol.cpp
+++ b/fastboot/protocol.cpp
@@ -36,16 +36,16 @@
 
 #include <algorithm>
 
+#include <android-base/stringprintf.h>
 #include <sparse/sparse.h>
 
 #include "fastboot.h"
 #include "transport.h"
 
-static char ERROR[128];
+static std::string g_error;
 
-char *fb_get_error(void)
-{
-    return ERROR;
+const std::string fb_get_error() {
+    return g_error;
 }
 
 static int check_response(Transport* transport, uint32_t size, char* response) {
@@ -54,14 +54,14 @@
     while (true) {
         int r = transport->Read(status, 64);
         if (r < 0) {
-            sprintf(ERROR, "status read failed (%s)", strerror(errno));
+            g_error = android::base::StringPrintf("status read failed (%s)", strerror(errno));
             transport->Close();
             return -1;
         }
         status[r] = 0;
 
         if (r < 4) {
-            sprintf(ERROR, "status malformed (%d bytes)", r);
+            g_error = android::base::StringPrintf("status malformed (%d bytes)", r);
             transport->Close();
             return -1;
         }
@@ -80,9 +80,9 @@
 
         if (!memcmp(status, "FAIL", 4)) {
             if (r > 4) {
-                sprintf(ERROR, "remote: %s", status + 4);
+                g_error = android::base::StringPrintf("remote: %s", status + 4);
             } else {
-                strcpy(ERROR, "remote failure");
+                g_error = "remote failure";
             }
             return -1;
         }
@@ -90,14 +90,14 @@
         if (!memcmp(status, "DATA", 4) && size > 0){
             uint32_t dsize = strtol(status + 4, 0, 16);
             if (dsize > size) {
-                strcpy(ERROR, "data size too large");
+                g_error = android::base::StringPrintf("data size too large (%d)", dsize);
                 transport->Close();
                 return -1;
             }
             return dsize;
         }
 
-        strcpy(ERROR,"unknown status code");
+        g_error = "unknown status code";
         transport->Close();
         break;
     }
@@ -108,7 +108,7 @@
 static int _command_start(Transport* transport, const char* cmd, uint32_t size, char* response) {
     size_t cmdsize = strlen(cmd);
     if (cmdsize > 64) {
-        sprintf(ERROR, "command too large");
+        g_error = android::base::StringPrintf("command too large (%zu)", cmdsize);
         return -1;
     }
 
@@ -117,7 +117,7 @@
     }
 
     if (transport->Write(cmd, cmdsize) != static_cast<int>(cmdsize)) {
-        sprintf(ERROR, "command write failed (%s)", strerror(errno));
+        g_error = android::base::StringPrintf("command write failed (%s)", strerror(errno));
         transport->Close();
         return -1;
     }
@@ -128,12 +128,12 @@
 static int _command_data(Transport* transport, const void* data, uint32_t size) {
     int r = transport->Write(data, size);
     if (r < 0) {
-        sprintf(ERROR, "data transfer failure (%s)", strerror(errno));
+        g_error = android::base::StringPrintf("data transfer failure (%s)", strerror(errno));
         transport->Close();
         return -1;
     }
     if (r != ((int) size)) {
-        sprintf(ERROR, "data transfer failure (short transfer)");
+        g_error = "data transfer failure (short transfer)";
         transport->Close();
         return -1;
     }
@@ -182,7 +182,7 @@
 
 int fb_download_data(Transport* transport, const void* data, uint32_t size) {
     char cmd[64];
-    sprintf(cmd, "download:%08x", size);
+    snprintf(cmd, sizeof(cmd), "download:%08x", size);
     return _command_send(transport, cmd, data, size, 0) < 0 ? -1 : 0;
 }
 
@@ -216,7 +216,7 @@
 
     if (len > TRANSPORT_BUF_SIZE) {
         if (transport_buf_len > 0) {
-            sprintf(ERROR, "internal error: transport_buf not empty\n");
+            g_error = "internal error: transport_buf not empty";
             return -1;
         }
         to_write = round_down(len, TRANSPORT_BUF_SIZE);
@@ -230,7 +230,7 @@
 
     if (len > 0) {
         if (len > TRANSPORT_BUF_SIZE) {
-            sprintf(ERROR, "internal error: too much left for transport_buf\n");
+            g_error = "internal error: too much left for transport_buf";
             return -1;
         }
         memcpy(transport_buf, ptr, len);
@@ -257,7 +257,7 @@
     }
 
     char cmd[64];
-    sprintf(cmd, "download:%08x", size);
+    snprintf(cmd, sizeof(cmd), "download:%08x", size);
     int r = _command_start(transport, cmd, size, 0);
     if (r < 0) {
         return -1;
diff --git a/fastboot/socket.cpp b/fastboot/socket.cpp
index 14ecd93..e56ffcf 100644
--- a/fastboot/socket.cpp
+++ b/fastboot/socket.cpp
@@ -167,7 +167,7 @@
 // Implements the Socket interface for TCP.
 class TcpSocket : public Socket {
   public:
-    TcpSocket(cutils_socket_t sock) : Socket(sock) {}
+    explicit TcpSocket(cutils_socket_t sock) : Socket(sock) {}
 
     bool Send(const void* data, size_t length) override;
     bool Send(std::vector<cutils_socket_buffer_t> buffers) override;
diff --git a/fastboot/socket.h b/fastboot/socket.h
index de543db..7eaa0ab 100644
--- a/fastboot/socket.h
+++ b/fastboot/socket.h
@@ -104,7 +104,7 @@
 
   protected:
     // Protected constructor to force factory function use.
-    Socket(cutils_socket_t sock);
+    explicit Socket(cutils_socket_t sock);
 
     // 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
diff --git a/fastboot/socket_test.cpp b/fastboot/socket_test.cpp
index affbdfd..373abc3 100644
--- a/fastboot/socket_test.cpp
+++ b/fastboot/socket_test.cpp
@@ -34,7 +34,7 @@
 // Creates connected sockets |server| and |client|. Returns true on success.
 bool MakeConnectedSockets(Socket::Protocol protocol, std::unique_ptr<Socket>* server,
                           std::unique_ptr<Socket>* client,
-                          const std::string hostname = "localhost") {
+                          const std::string& hostname = "localhost") {
     *server = Socket::NewServer(protocol, 0);
     if (*server == nullptr) {
         ADD_FAILURE() << "Failed to create server.";
diff --git a/fastboot/tcp.cpp b/fastboot/tcp.cpp
index e42c4e1..dd6fbf8 100644
--- a/fastboot/tcp.cpp
+++ b/fastboot/tcp.cpp
@@ -66,7 +66,7 @@
     int Close() override;
 
   private:
-    TcpTransport(std::unique_ptr<Socket> sock) : socket_(std::move(sock)) {}
+    explicit 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.
diff --git a/fastboot/udp.cpp b/fastboot/udp.cpp
index b36bd60..53fb347 100644
--- a/fastboot/udp.cpp
+++ b/fastboot/udp.cpp
@@ -111,7 +111,7 @@
     int Close() override;
 
   private:
-    UdpTransport(std::unique_ptr<Socket> socket) : socket_(std::move(socket)) {}
+    explicit UdpTransport(std::unique_ptr<Socket> socket) : socket_(std::move(socket)) {}
 
     // Performs the UDP initialization procedure. Returns true on success.
     bool InitializeProtocol(std::string* error);
diff --git a/fastboot/usb_linux.cpp b/fastboot/usb_linux.cpp
index 02ffcd9..cdab4f1 100644
--- a/fastboot/usb_linux.cpp
+++ b/fastboot/usb_linux.cpp
@@ -43,11 +43,15 @@
 #include <linux/version.h>
 #include <linux/usb/ch9.h>
 
+#include <chrono>
 #include <memory>
+#include <thread>
 
 #include "fastboot.h"
 #include "usb.h"
 
+using namespace std::chrono_literals;
+
 #define MAX_RETRIES 5
 
 /* Timeout in seconds for usb_wait_for_disconnect.
@@ -89,7 +93,7 @@
 
 class LinuxUsbTransport : public Transport {
   public:
-    LinuxUsbTransport(std::unique_ptr<usb_handle> handle) : handle_(std::move(handle)) {}
+    explicit LinuxUsbTransport(std::unique_ptr<usb_handle> handle) : handle_(std::move(handle)) {}
     ~LinuxUsbTransport() override = default;
 
     ssize_t Read(void* data, size_t len) override;
@@ -145,7 +149,7 @@
     int in, out;
     unsigned i;
     unsigned e;
-    
+
     if (check(ptr, len, USB_DT_DEVICE, USB_DT_DEVICE_SIZE))
         return -1;
     dev = (struct usb_device_descriptor *)ptr;
@@ -333,15 +337,14 @@
     char desc[1024];
     int n, in, out, ifc;
 
-    DIR *busdir;
     struct dirent *de;
     int fd;
     int writable;
 
-    busdir = opendir(base);
+    std::unique_ptr<DIR, decltype(&closedir)> busdir(opendir(base), closedir);
     if (busdir == 0) return 0;
 
-    while ((de = readdir(busdir)) && (usb == nullptr)) {
+    while ((de = readdir(busdir.get())) && (usb == nullptr)) {
         if (badname(de->d_name)) continue;
 
         if (!convert_to_devfs_name(de->d_name, devname, sizeof(devname))) {
@@ -377,7 +380,6 @@
             }
         }
     }
-    closedir(busdir);
 
     return usb;
 }
@@ -428,7 +430,7 @@
         return -1;
     }
 
-    while(len > 0) {
+    while (len > 0) {
         int xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
 
         bulk.ep = handle_->ep_in;
@@ -437,18 +439,17 @@
         bulk.timeout = 0;
         retry = 0;
 
-        do{
-           DBG("[ usb read %d fd = %d], fname=%s\n", xfer, handle_->desc, handle_->fname);
-           n = ioctl(handle_->desc, USBDEVFS_BULK, &bulk);
-           DBG("[ usb read %d ] = %d, fname=%s, Retry %d \n", xfer, n, handle_->fname, retry);
+        do {
+            DBG("[ usb read %d fd = %d], fname=%s\n", xfer, handle_->desc, handle_->fname);
+            n = ioctl(handle_->desc, USBDEVFS_BULK, &bulk);
+            DBG("[ usb read %d ] = %d, fname=%s, Retry %d \n", xfer, n, handle_->fname, retry);
 
-           if( n < 0 ) {
-            DBG1("ERROR: n = %d, errno = %d (%s)\n",n, errno, strerror(errno));
-            if ( ++retry > MAX_RETRIES ) return -1;
-            sleep( 1 );
-           }
-        }
-        while( n < 0 );
+            if (n < 0) {
+                DBG1("ERROR: n = %d, errno = %d (%s)\n",n, errno, strerror(errno));
+                if (++retry > MAX_RETRIES) return -1;
+                std::this_thread::sleep_for(1s);
+            }
+        } while (n < 0);
 
         count += n;
         len -= n;
@@ -490,9 +491,8 @@
 {
   double deadline = now() + WAIT_FOR_DISCONNECT_TIMEOUT;
   while (now() < deadline) {
-    if (access(handle_->fname, F_OK))
-      return 0;
-    usleep(50000);
+    if (access(handle_->fname, F_OK)) return 0;
+    std::this_thread::sleep_for(50ms);
   }
   return -1;
 }
diff --git a/fastboot/usb_windows.cpp b/fastboot/usb_windows.cpp
index 1cdeb32..3dab5ac 100644
--- a/fastboot/usb_windows.cpp
+++ b/fastboot/usb_windows.cpp
@@ -362,9 +362,3 @@
     std::unique_ptr<usb_handle> handle = find_usb_device(callback);
     return handle ? new WindowsUsbTransport(std::move(handle)) : nullptr;
 }
-
-// called from fastboot.c
-void sleep(int seconds)
-{
-    Sleep(seconds * 1000);
-}
diff --git a/fastboot/util_linux.cpp b/fastboot/util_linux.cpp
deleted file mode 100644
index b788199..0000000
--- a/fastboot/util_linux.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "fastboot.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <limits.h>
-
-void get_my_path(char *path)
-{
-    char proc[64];
-    char *x;
-
-    sprintf(proc, "/proc/%d/exe", getpid());
-    int err = readlink(proc, path, PATH_MAX - 1);
-
-    if(err <= 0) {
-        path[0] = 0;
-    } else {
-        path[err] = 0;
-        x = strrchr(path,'/');
-        if(x) x[1] = 0;
-    }
-}
diff --git a/fastboot/util_osx.cpp b/fastboot/util_osx.cpp
deleted file mode 100644
index ae0b024..0000000
--- a/fastboot/util_osx.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "fastboot.h"
-
-#import <Carbon/Carbon.h>
-#include <unistd.h>
-
-void get_my_path(char s[PATH_MAX])
-{
-    CFBundleRef mainBundle = CFBundleGetMainBundle();
-    CFURLRef executableURL = CFBundleCopyExecutableURL(mainBundle);
-    CFStringRef executablePathString = CFURLCopyFileSystemPath(executableURL, kCFURLPOSIXPathStyle);
-    CFRelease(executableURL);
-
-    CFStringGetFileSystemRepresentation(executablePathString, s, PATH_MAX-1);
-    CFRelease(executablePathString);
-
-	char *x;
-    x = strrchr(s, '/');
-    if(x) x[1] = 0;
-}
-
-
diff --git a/fastboot/util_windows.cpp b/fastboot/util_windows.cpp
deleted file mode 100644
index ec52f39..0000000
--- a/fastboot/util_windows.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "fastboot.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <limits.h>
-
-#include <windows.h>
-
-void get_my_path(char exe[PATH_MAX])
-{
-	char*  r;
-
-	GetModuleFileName( NULL, exe, PATH_MAX-1 );
-	exe[PATH_MAX-1] = 0;
-	r = strrchr( exe, '\\' );
-	if (r)
-		*r = 0;
-}
-
diff --git a/fingerprintd/IFingerprintDaemonCallback.cpp b/fingerprintd/IFingerprintDaemonCallback.cpp
index 19838c9..1d75aa7 100644
--- a/fingerprintd/IFingerprintDaemonCallback.cpp
+++ b/fingerprintd/IFingerprintDaemonCallback.cpp
@@ -27,7 +27,7 @@
 class BpFingerprintDaemonCallback : public BpInterface<IFingerprintDaemonCallback>
 {
 public:
-    BpFingerprintDaemonCallback(const sp<IBinder>& impl) :
+    explicit BpFingerprintDaemonCallback(const sp<IBinder>& impl) :
             BpInterface<IFingerprintDaemonCallback>(impl) {
     }
     virtual status_t onEnrollResult(int64_t devId, int32_t fpId, int32_t gpId, int32_t rem) {
diff --git a/fingerprintd/fingerprintd.cpp b/fingerprintd/fingerprintd.cpp
index 8fa7ed1..05109b7 100644
--- a/fingerprintd/fingerprintd.cpp
+++ b/fingerprintd/fingerprintd.cpp
@@ -16,20 +16,17 @@
 
 #define LOG_TAG "fingerprintd"
 
-#include <cutils/log.h>
-#include <utils/Log.h>
-
+#include <android/log.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <binder/PermissionCache.h>
-#include <utils/String16.h>
-
-#include <keystore/IKeystoreService.h>
-#include <keystore/keystore.h> // for error codes
-
 #include <hardware/hardware.h>
 #include <hardware/fingerprint.h>
 #include <hardware/hw_auth_token.h>
+#include <keystore/IKeystoreService.h>
+#include <keystore/keystore.h> // for error codes
+#include <utils/Log.h>
+#include <utils/String16.h>
 
 #include "FingerprintDaemonProxy.h"
 
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 28fff3f..d6b699b 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -7,10 +7,11 @@
     libfec \
     libfec_rs \
     libbase \
-    libmincrypt \
-    libcrypto_static \
+    libcrypto_utils \
+    libcrypto \
     libext4_utils_static \
-    libsquashfs_utils
+    libsquashfs_utils \
+    libselinux
 
 include $(CLEAR_VARS)
 LOCAL_CLANG := true
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 387f708..c9876fd 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -14,38 +14,36 @@
  * limitations under the License.
  */
 
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <ctype.h>
+#include <sys/ioctl.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
-#include <errno.h>
+#include <sys/swap.h>
 #include <sys/types.h>
 #include <sys/wait.h>
-#include <libgen.h>
 #include <time.h>
-#include <sys/swap.h>
-#include <dirent.h>
-#include <ext4.h>
-#include <ext4_sb.h>
-#include <ext4_crypt_init_extensions.h>
+#include <unistd.h>
 
-#include <linux/loop.h>
-#include <private/android_filesystem_config.h>
 #include <cutils/android_reboot.h>
 #include <cutils/partition_utils.h>
 #include <cutils/properties.h>
+#include <ext4_utils/ext4.h>
+#include <ext4_utils/ext4_crypt_init_extensions.h>
+#include <ext4_utils/ext4_sb.h>
+#include <ext4_utils/ext4_utils.h>
+#include <ext4_utils/wipe.h>
+#include <linux/fs.h>
+#include <linux/loop.h>
 #include <logwrap/logwrap.h>
-
-#include "mincrypt/rsa.h"
-#include "mincrypt/sha.h"
-#include "mincrypt/sha256.h"
-
-#include "ext4_utils.h"
-#include "wipe.h"
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
 
 #include "fs_mgr_priv.h"
 #include "fs_mgr_priv_verity.h"
@@ -54,12 +52,14 @@
 #define KEY_IN_FOOTER  "footer"
 
 #define E2FSCK_BIN      "/system/bin/e2fsck"
-#define F2FS_FSCK_BIN  "/system/bin/fsck.f2fs"
+#define F2FS_FSCK_BIN   "/system/bin/fsck.f2fs"
 #define MKSWAP_BIN      "/system/bin/mkswap"
+#define TUNE2FS_BIN     "/system/bin/tune2fs"
 
 #define FSCK_LOG_FILE   "/dev/fscklogs/log"
 
 #define ZRAM_CONF_DEV   "/sys/block/zram0/disksize"
+#define ZRAM_CONF_MCS   "/sys/block/zram0/max_comp_streams"
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 
@@ -183,6 +183,99 @@
     return;
 }
 
+/* Function to read the primary superblock */
+static int read_super_block(int fd, struct ext4_super_block *sb)
+{
+    off64_t ret;
+
+    ret = lseek64(fd, 1024, SEEK_SET);
+    if (ret < 0)
+        return ret;
+
+    ret = read(fd, sb, sizeof(*sb));
+    if (ret < 0)
+        return ret;
+    if (ret != sizeof(*sb))
+        return ret;
+
+    return 0;
+}
+
+static ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es)
+{
+    return ((ext4_fsblk_t)le32_to_cpu(es->s_blocks_count_hi) << 32) |
+            le32_to_cpu(es->s_blocks_count_lo);
+}
+
+static ext4_fsblk_t ext4_r_blocks_count(struct ext4_super_block *es)
+{
+    return ((ext4_fsblk_t)le32_to_cpu(es->s_r_blocks_count_hi) << 32) |
+            le32_to_cpu(es->s_r_blocks_count_lo);
+}
+
+static void do_reserved_size(char *blk_device, char *fs_type, struct fstab_rec *rec)
+{
+    /* Check for the types of filesystems we know how to check */
+    if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) {
+        /*
+         * Some system images do not have tune2fs for licensing reasons
+         * Detect these and skip reserve blocks.
+         */
+        if (access(TUNE2FS_BIN, X_OK)) {
+            ERROR("Not running %s on %s (executable not in system image)\n",
+                  TUNE2FS_BIN, blk_device);
+        } else {
+            INFO("Running %s on %s\n", TUNE2FS_BIN, blk_device);
+
+            int status = 0;
+            int ret = 0;
+            unsigned long reserved_blocks = 0;
+            int fd = TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC));
+            if (fd >= 0) {
+                struct ext4_super_block sb;
+                ret = read_super_block(fd, &sb);
+                if (ret < 0) {
+                    ERROR("Can't read '%s' super block: %s\n", blk_device, strerror(errno));
+                    goto out;
+                }
+                reserved_blocks = rec->reserved_size / EXT4_BLOCK_SIZE(&sb);
+                unsigned long reserved_threshold = ext4_blocks_count(&sb) * 0.02;
+                if (reserved_threshold < reserved_blocks) {
+                    WARNING("Reserved blocks %lu is too large\n", reserved_blocks);
+                    reserved_blocks = reserved_threshold;
+                }
+
+                if (ext4_r_blocks_count(&sb) == reserved_blocks) {
+                    INFO("Have reserved same blocks\n");
+                    goto out;
+                }
+            } else {
+                ERROR("Failed to open '%s': %s\n", blk_device, strerror(errno));
+                return;
+            }
+
+            char buf[16] = {0};
+            snprintf(buf, sizeof (buf), "-r %lu", reserved_blocks);
+            char *tune2fs_argv[] = {
+                TUNE2FS_BIN,
+                buf,
+                blk_device,
+            };
+
+            ret = android_fork_execvp_ext(ARRAY_SIZE(tune2fs_argv), tune2fs_argv,
+                                          &status, true, LOG_KLOG | LOG_FILE,
+                                          true, NULL, NULL, 0);
+
+            if (ret < 0) {
+                /* No need to check for error in fork, we can't really handle it now */
+                ERROR("Failed trying to run %s\n", TUNE2FS_BIN);
+            }
+      out:
+            close(fd);
+        }
+    }
+}
+
 static void remove_trailing_slashes(char *n)
 {
     int len;
@@ -265,15 +358,6 @@
     return ret;
 }
 
-static int device_is_debuggable() {
-    int ret = -1;
-    char value[PROP_VALUE_MAX];
-    ret = __system_property_get("ro.debuggable", value);
-    if (ret < 0)
-        return ret;
-    return strcmp(value, "1") ? 0 : 1;
-}
-
 static int device_is_secure() {
     int ret = -1;
     char value[PROP_VALUE_MAX];
@@ -337,6 +421,12 @@
                 check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
                          fstab->recs[i].mount_point);
             }
+
+            if (fstab->recs[i].fs_mgr_flags & MF_RESERVEDSIZE) {
+                do_reserved_size(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
+                                 &fstab->recs[i]);
+            }
+
             if (!__mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point, &fstab->recs[i])) {
                 *attempted_idx = i;
                 mounted = 1;
@@ -542,7 +632,7 @@
 
         if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
             int rc = fs_mgr_setup_verity(&fstab->recs[i]);
-            if (device_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
+            if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
                 INFO("Verity disabled");
             } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
                 ERROR("Could not set up verified partition, skipping!\n");
@@ -579,6 +669,7 @@
 
         /* mount(2) returned an error, handle the encryptable/formattable case */
         bool wiped = partition_wiped(fstab->recs[top_idx].blk_device);
+        bool crypt_footer = false;
         if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
             fs_mgr_is_formattable(&fstab->recs[top_idx]) && wiped) {
             /* top_idx and attempted_idx point at the same partition, but sometimes
@@ -590,7 +681,7 @@
                   fstab->recs[top_idx].fs_type);
             if (fs_mgr_is_encryptable(&fstab->recs[top_idx]) &&
                 strcmp(fstab->recs[top_idx].key_loc, KEY_IN_FOOTER)) {
-                int fd = open(fstab->recs[top_idx].key_loc, O_WRONLY, 0644);
+                int fd = open(fstab->recs[top_idx].key_loc, O_WRONLY);
                 if (fd >= 0) {
                     INFO("%s(): also wipe %s\n", __func__, fstab->recs[top_idx].key_loc);
                     wipe_block_device(fd, get_file_size(fd));
@@ -599,8 +690,11 @@
                     ERROR("%s(): %s wouldn't open (%s)\n", __func__,
                           fstab->recs[top_idx].key_loc, strerror(errno));
                 }
+            } else if (fs_mgr_is_encryptable(&fstab->recs[top_idx]) &&
+                !strcmp(fstab->recs[top_idx].key_loc, KEY_IN_FOOTER)) {
+                crypt_footer = true;
             }
-            if (fs_mgr_do_format(&fstab->recs[top_idx]) == 0) {
+            if (fs_mgr_do_format(&fstab->recs[top_idx], crypt_footer) == 0) {
                 /* Let's replay the mount actions. */
                 i = top_idx - 1;
                 continue;
@@ -698,9 +792,13 @@
                      fstab->recs[i].mount_point);
         }
 
+        if (fstab->recs[i].fs_mgr_flags & MF_RESERVEDSIZE) {
+            do_reserved_size(n_blk_device, fstab->recs[i].fs_type, &fstab->recs[i]);
+        }
+
         if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
             int rc = fs_mgr_setup_verity(&fstab->recs[i]);
-            if (device_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
+            if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
                 INFO("Verity disabled");
             } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
                 ERROR("Could not set up verified partition, skipping!\n");
@@ -811,6 +909,18 @@
              * we can assume the device number is 0.
              */
             FILE *zram_fp;
+            FILE *zram_mcs_fp;
+
+            if (fstab->recs[i].max_comp_streams >= 0) {
+               zram_mcs_fp = fopen(ZRAM_CONF_MCS, "r+");
+              if (zram_mcs_fp == NULL) {
+                ERROR("Unable to open zram conf comp device %s\n", ZRAM_CONF_MCS);
+                ret = -1;
+                continue;
+              }
+              fprintf(zram_mcs_fp, "%d\n", fstab->recs[i].max_comp_streams);
+              fclose(zram_mcs_fp);
+            }
 
             zram_fp = fopen(ZRAM_CONF_DEV, "r+");
             if (zram_fp == NULL) {
@@ -899,3 +1009,22 @@
 
     return 0;
 }
+
+int fs_mgr_early_setup_verity(struct fstab_rec *fstab_rec)
+{
+    if ((fstab_rec->fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
+        int rc = fs_mgr_setup_verity(fstab_rec);
+        if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
+            INFO("Verity disabled");
+            return FS_MGR_EARLY_SETUP_VERITY_NO_VERITY;
+        } else if (rc == FS_MGR_SETUP_VERITY_SUCCESS) {
+            return FS_MGR_EARLY_SETUP_VERITY_SUCCESS;
+        } else {
+            return FS_MGR_EARLY_SETUP_VERITY_FAIL;
+        }
+    } else if (device_is_secure()) {
+        ERROR("Verity must be enabled for early mounted partitions on secured devices.\n");
+        return FS_MGR_EARLY_SETUP_VERITY_FAIL;
+    }
+    return FS_MGR_EARLY_SETUP_VERITY_NO_VERITY;
+}
diff --git a/fs_mgr/fs_mgr_format.c b/fs_mgr/fs_mgr_format.c
index f8df081..7c3b1ed 100644
--- a/fs_mgr/fs_mgr_format.c
+++ b/fs_mgr/fs_mgr_format.c
@@ -23,41 +23,62 @@
 #include <errno.h>
 #include <cutils/partition_utils.h>
 #include <sys/mount.h>
-#include "ext4_utils.h"
-#include "ext4.h"
-#include "make_ext4fs.h"
+
+#include <ext4_utils/ext4_utils.h>
+#include <ext4_utils/ext4.h>
+#include <ext4_utils/make_ext4fs.h>
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#include <selinux/android.h>
+
 #include "fs_mgr_priv.h"
+#include "cryptfs.h"
 
 extern struct fs_info info;     /* magic global from ext4_utils */
 extern void reset_ext4fs_info();
 
-static int format_ext4(char *fs_blkdev, char *fs_mnt_point)
+static int format_ext4(char *fs_blkdev, char *fs_mnt_point, bool crypt_footer)
 {
-    unsigned int nr_sec;
+    uint64_t dev_sz;
     int fd, rc = 0;
 
-    if ((fd = open(fs_blkdev, O_WRONLY, 0644)) < 0) {
+    if ((fd = open(fs_blkdev, O_WRONLY)) < 0) {
         ERROR("Cannot open block device.  %s\n", strerror(errno));
         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;
     }
 
+    struct selabel_handle *sehandle = selinux_android_file_context_handle();
+    if (!sehandle) {
+        /* libselinux logs specific error */
+        ERROR("Cannot initialize android file_contexts");
+        close(fd);
+        return -1;
+    }
+
     /* Format the partition using the calculated length */
     reset_ext4fs_info();
-    info.len = ((off64_t)nr_sec * 512);
+    info.len = (off64_t)dev_sz;
+    if (crypt_footer) {
+        info.len -= CRYPT_FOOTER_OFFSET;
+    }
 
     /* 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, NULL, NULL);
+    rc = make_ext4fs_internal(fd, NULL, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, sehandle, 0, 0, NULL, NULL, NULL);
     if (rc) {
         ERROR("make_ext4fs returned %d.\n", rc);
     }
     close(fd);
 
+    if (sehandle) {
+        selabel_close(sehandle);
+    }
+
     return rc;
 }
 
@@ -101,7 +122,7 @@
     return rc;
 }
 
-int fs_mgr_do_format(struct fstab_rec *fstab)
+int fs_mgr_do_format(struct fstab_rec *fstab, bool crypt_footer)
 {
     int rc = -EINVAL;
 
@@ -110,7 +131,7 @@
     if (!strncmp(fstab->fs_type, "f2fs", 4)) {
         rc = format_f2fs(fstab->blk_device);
     } else if (!strncmp(fstab->fs_type, "ext4", 4)) {
-        rc = format_ext4(fstab->blk_device, fstab->mount_point);
+        rc = format_ext4(fstab->blk_device, fstab->mount_point, crypt_footer);
     } else {
         ERROR("File system type '%s' is not supported\n", fstab->fs_type);
     }
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index 21b4c74..90c7435 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -31,7 +31,9 @@
     char *label;
     int partnum;
     int swap_prio;
+    int max_comp_streams;
     unsigned int zram_size;
+    uint64_t reserved_size;
     unsigned int file_encryption_mode;
 };
 
@@ -72,6 +74,7 @@
     { "recoveryonly",MF_RECOVERYONLY },
     { "swapprio=",   MF_SWAPPRIO },
     { "zramsize=",   MF_ZRAMSIZE },
+    { "max_comp_streams=",   MF_MAX_COMP_STREAMS },
     { "verify",      MF_VERIFY },
     { "noemulatedsd", MF_NOEMULATEDSD },
     { "notrim",       MF_NOTRIM },
@@ -79,6 +82,7 @@
     { "slotselect",  MF_SLOTSELECT },
     { "nofail",      MF_NOFAIL },
     { "latemount",   MF_LATEMOUNT },
+    { "reservedsize=", MF_RESERVEDSIZE },
     { "defaults",    0 },
     { 0,             0 },
 };
@@ -105,6 +109,20 @@
     return total;
 }
 
+static uint64_t parse_size(const char *arg)
+{
+    char *endptr;
+    uint64_t size = strtoull(arg, &endptr, 10);
+    if (*endptr == 'k' || *endptr == 'K')
+        size *= 1024LL;
+    else if (*endptr == 'm' || *endptr == 'M')
+        size *= 1024LL * 1024LL;
+    else if (*endptr == 'g' || *endptr == 'G')
+        size *= 1024LL * 1024LL * 1024LL;
+
+    return size;
+}
+
 static int parse_flags(char *flags, struct flag_list *fl,
                        struct fs_mgr_flag_values *flag_vals,
                        char *fs_options, int fs_options_len)
@@ -205,6 +223,8 @@
                     }
                 } else if ((fl[i].flag == MF_SWAPPRIO) && flag_vals) {
                     flag_vals->swap_prio = strtoll(strchr(p, '=') + 1, NULL, 0);
+                } else if ((fl[i].flag == MF_MAX_COMP_STREAMS) && flag_vals) {
+                    flag_vals->max_comp_streams = strtoll(strchr(p, '=') + 1, NULL, 0);
                 } else if ((fl[i].flag == MF_ZRAMSIZE) && flag_vals) {
                     int is_percent = !!strrchr(p, '%');
                     unsigned int val = strtoll(strchr(p, '=') + 1, NULL, 0);
@@ -212,6 +232,11 @@
                         flag_vals->zram_size = calculate_zram_size(val);
                     else
                         flag_vals->zram_size = val;
+                } else if ((fl[i].flag == MF_RESERVEDSIZE) && flag_vals) {
+                    /* The reserved flag is followed by an = and the
+                     * reserved size of the partition.  Get it and return it.
+                     */
+                    flag_vals->reserved_size = parse_size(strchr(p, '=') + 1);
                 }
                 break;
             }
@@ -242,9 +267,8 @@
     return f;
 }
 
-struct fstab *fs_mgr_read_fstab(const char *fstab_path)
+struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file)
 {
-    FILE *fstab_file;
     int cnt, entries;
     ssize_t len;
     size_t alloc_len = 0;
@@ -256,12 +280,6 @@
 #define FS_OPTIONS_LEN 1024
     char tmp_fs_options[FS_OPTIONS_LEN];
 
-    fstab_file = fopen(fstab_path, "r");
-    if (!fstab_file) {
-        ERROR("Cannot open file %s\n", fstab_path);
-        return 0;
-    }
-
     entries = 0;
     while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
         /* if the last character is a newline, shorten the string by 1 byte */
@@ -287,7 +305,6 @@
     /* Allocate and init the fstab structure */
     fstab = calloc(1, sizeof(struct fstab));
     fstab->num_entries = entries;
-    fstab->fstab_filename = strdup(fstab_path);
     fstab->recs = calloc(fstab->num_entries, sizeof(struct fstab_rec));
 
     fseek(fstab_file, 0, SEEK_SET);
@@ -362,7 +379,9 @@
         fstab->recs[cnt].label = flag_vals.label;
         fstab->recs[cnt].partnum = flag_vals.partnum;
         fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
+        fstab->recs[cnt].max_comp_streams = flag_vals.max_comp_streams;
         fstab->recs[cnt].zram_size = flag_vals.zram_size;
+        fstab->recs[cnt].reserved_size = flag_vals.reserved_size;
         fstab->recs[cnt].file_encryption_mode = flag_vals.file_encryption_mode;
         cnt++;
     }
@@ -371,18 +390,34 @@
         ERROR("Error updating for slotselect\n");
         goto err;
     }
-    fclose(fstab_file);
     free(line);
     return fstab;
 
 err:
-    fclose(fstab_file);
     free(line);
     if (fstab)
         fs_mgr_free_fstab(fstab);
     return NULL;
 }
 
+struct fstab *fs_mgr_read_fstab(const char *fstab_path)
+{
+    FILE *fstab_file;
+    struct fstab *fstab;
+
+    fstab_file = fopen(fstab_path, "r");
+    if (!fstab_file) {
+        ERROR("Cannot open file %s\n", fstab_path);
+        return NULL;
+    }
+    fstab = fs_mgr_read_fstab_file(fstab_file);
+    if (fstab) {
+        fstab->fstab_filename = strdup(fstab_path);
+    }
+    fclose(fstab_file);
+    return fstab;
+}
+
 void fs_mgr_free_fstab(struct fstab *fstab)
 {
     int i;
diff --git a/fs_mgr/fs_mgr_main.c b/fs_mgr/fs_mgr_main.c
index 776c13e..33a7496 100644
--- a/fs_mgr/fs_mgr_main.c
+++ b/fs_mgr/fs_mgr_main.c
@@ -85,7 +85,6 @@
     char *fstab_file=NULL;
     struct fstab *fstab=NULL;
 
-    klog_init();
     klog_set_level(6);
 
     parse_options(argc, argv, &a_flag, &u_flag, &n_flag, &n_name, &n_blk_dev);
@@ -111,4 +110,3 @@
     /* Should not get here */
     exit(1);
 }
-
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 6d9492b..23c97e4 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -85,6 +85,8 @@
 #define MF_FORCEFDEORFBE 0x10000
 #define MF_LATEMOUNT    0x20000
 #define MF_NOFAIL       0x40000
+#define MF_MAX_COMP_STREAMS 0x100000
+#define MF_RESERVEDSIZE 0x200000
 
 #define DM_BUF_SIZE 4096
 
diff --git a/fs_mgr/fs_mgr_priv_verity.h b/fs_mgr/fs_mgr_priv_verity.h
index cd673f3..d9e17bb 100644
--- a/fs_mgr/fs_mgr_priv_verity.h
+++ b/fs_mgr/fs_mgr_priv_verity.h
@@ -16,8 +16,8 @@
 
 #include <sys/cdefs.h>
 
-#define FS_MGR_SETUP_VERITY_DISABLED -2
-#define FS_MGR_SETUP_VERITY_FAIL -1
+#define FS_MGR_SETUP_VERITY_DISABLED (-2)
+#define FS_MGR_SETUP_VERITY_FAIL (-1)
 #define FS_MGR_SETUP_VERITY_SUCCESS 0
 
 __BEGIN_DECLS
diff --git a/fs_mgr/fs_mgr_slotselect.c b/fs_mgr/fs_mgr_slotselect.c
index ca07b18..0f59115 100644
--- a/fs_mgr/fs_mgr_slotselect.c
+++ b/fs_mgr/fs_mgr_slotselect.c
@@ -41,7 +41,7 @@
     int n;
     int misc_fd;
     ssize_t num_read;
-    struct bootloader_message msg;
+    struct bootloader_message_ab msg;
 
     misc_fd = -1;
     for (n = 0; n < fstab->num_entries; n++) {
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 83f42a09..031b042 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -14,29 +14,30 @@
  * limitations under the License.
  */
 
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
 #include <inttypes.h>
+#include <libgen.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <ctype.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
-#include <errno.h>
 #include <sys/types.h>
 #include <sys/wait.h>
-#include <libgen.h>
 #include <time.h>
+#include <unistd.h>
 
 #include <android-base/file.h>
 #include <android-base/strings.h>
+#include <crypto_utils/android_pubkey.h>
 #include <cutils/properties.h>
 #include <logwrap/logwrap.h>
-
-#include "mincrypt/rsa.h"
-#include "mincrypt/sha.h"
-#include "mincrypt/sha256.h"
+#include <openssl/obj_mac.h>
+#include <openssl/rsa.h>
+#include <openssl/sha.h>
+#include <private/android_filesystem_config.h>
 
 #include "fec/io.h"
 
@@ -83,48 +84,42 @@
 
 extern struct fs_info info;
 
-static RSAPublicKey *load_key(const char *path)
+static RSA *load_key(const char *path)
 {
-    RSAPublicKey* key = static_cast<RSAPublicKey*>(malloc(sizeof(RSAPublicKey)));
-    if (!key) {
-        ERROR("Can't malloc key\n");
-        return NULL;
-    }
+    uint8_t key_data[ANDROID_PUBKEY_ENCODED_SIZE];
 
     FILE* f = fopen(path, "r");
     if (!f) {
         ERROR("Can't open '%s'\n", path);
-        free(key);
         return NULL;
     }
 
-    if (!fread(key, sizeof(*key), 1, f)) {
+    if (!fread(key_data, sizeof(key_data), 1, f)) {
         ERROR("Could not read key!\n");
         fclose(f);
-        free(key);
-        return NULL;
-    }
-
-    if (key->len != RSANUMWORDS) {
-        ERROR("Invalid key length %d\n", key->len);
-        fclose(f);
-        free(key);
         return NULL;
     }
 
     fclose(f);
+
+    RSA* key = NULL;
+    if (!android_pubkey_decode(key_data, sizeof(key_data), &key)) {
+        ERROR("Could not parse key!\n");
+        return NULL;
+    }
+
     return key;
 }
 
-static int verify_table(const uint8_t *signature, const char *table,
-        uint32_t table_length)
+static int verify_table(const uint8_t *signature, size_t signature_size,
+        const char *table, uint32_t table_length)
 {
-    RSAPublicKey *key;
-    uint8_t hash_buf[SHA256_DIGEST_SIZE];
+    RSA *key;
+    uint8_t hash_buf[SHA256_DIGEST_LENGTH];
     int retval = -1;
 
     // Hash the table
-    SHA256_hash((uint8_t*)table, table_length, hash_buf);
+    SHA256((uint8_t*)table, table_length, hash_buf);
 
     // Now get the public key from the keyfile
     key = load_key(VERITY_TABLE_RSA_KEY);
@@ -134,11 +129,8 @@
     }
 
     // verify the result
-    if (!RSA_verify(key,
-                    signature,
-                    RSANUMBYTES,
-                    (uint8_t*) hash_buf,
-                    SHA256_DIGEST_SIZE)) {
+    if (!RSA_verify(NID_sha256, hash_buf, sizeof(hash_buf), signature,
+                    signature_size, key)) {
         ERROR("Couldn't verify table\n");
         goto out;
     }
@@ -146,16 +138,16 @@
     retval = 0;
 
 out:
-    free(key);
+    RSA_free(key);
     return retval;
 }
 
 static int verify_verity_signature(const struct fec_verity_metadata& verity)
 {
-    if (verify_table(verity.signature, verity.table,
-            verity.table_length) == 0 ||
-        verify_table(verity.ecc_signature, verity.table,
-            verity.table_length) == 0) {
+    if (verify_table(verity.signature, sizeof(verity.signature),
+            verity.table, verity.table_length) == 0 ||
+        verify_table(verity.ecc_signature, sizeof(verity.ecc_signature),
+            verity.table, verity.table_length) == 0) {
         return 0;
     }
 
@@ -622,8 +614,8 @@
     off64_t offset = 0;
     struct fec_handle *f = NULL;
     struct fec_verity_metadata verity;
-    uint8_t curr[SHA256_DIGEST_SIZE];
-    uint8_t prev[SHA256_DIGEST_SIZE];
+    uint8_t curr[SHA256_DIGEST_LENGTH];
+    uint8_t prev[SHA256_DIGEST_LENGTH];
 
     *match = 1;
 
@@ -641,7 +633,7 @@
         goto out;
     }
 
-    SHA256_hash(verity.signature, RSANUMBYTES, curr);
+    SHA256(verity.signature, sizeof(verity.signature), curr);
 
     if (snprintf(tag, sizeof(tag), VERITY_LASTSIG_TAG "_%s",
             basename(fstab->mount_point)) >= (int)sizeof(tag)) {
@@ -649,7 +641,7 @@
         goto out;
     }
 
-    if (metadata_find(fstab->verity_loc, tag, SHA256_DIGEST_SIZE,
+    if (metadata_find(fstab->verity_loc, tag, SHA256_DIGEST_LENGTH,
             &offset) < 0) {
         goto out;
     }
@@ -668,7 +660,7 @@
         goto out;
     }
 
-    *match = !memcmp(curr, prev, SHA256_DIGEST_SIZE);
+    *match = !memcmp(curr, prev, SHA256_DIGEST_LENGTH);
 
     if (!*match) {
         /* update current signature hash */
@@ -877,7 +869,7 @@
     std::string result, word;
     auto tokens = android::base::Split(*table, " ");
 
-    for (const auto token : tokens) {
+    for (const auto& token : tokens) {
         if (android::base::StartsWith(token, "/dev/block/") &&
             android::base::StartsWith(blk_device, token.c_str())) {
             word = blk_device;
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 7565965..ed22e90 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -17,7 +17,9 @@
 #ifndef __CORE_FS_MGR_H
 #define __CORE_FS_MGR_H
 
+#include <stdio.h>
 #include <stdint.h>
+#include <stdbool.h>
 #include <linux/dm-ioctl.h>
 
 // Magic number at start of verity metadata
@@ -71,7 +73,9 @@
     char *label;
     int partnum;
     int swap_prio;
+    int max_comp_streams;
     unsigned int zram_size;
+    uint64_t reserved_size;
     unsigned int file_encryption_mode;
 };
 
@@ -79,6 +83,7 @@
 typedef void (*fs_mgr_verity_state_callback)(struct fstab_rec *fstab,
         const char *mount_point, int mode, int status);
 
+struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file);
 struct fstab *fs_mgr_read_fstab(const char *fstab_path);
 void fs_mgr_free_fstab(struct fstab *fstab);
 
@@ -88,11 +93,11 @@
 #define FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED 2
 #define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 1
 #define FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE 0
-#define FS_MGR_MNTALL_FAIL -1
+#define FS_MGR_MNTALL_FAIL (-1)
 int fs_mgr_mount_all(struct fstab *fstab, int mount_mode);
 
-#define FS_MGR_DOMNT_FAILED -1
-#define FS_MGR_DOMNT_BUSY -2
+#define FS_MGR_DOMNT_FAILED (-1)
+#define FS_MGR_DOMNT_BUSY (-2)
 
 int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
                     char *tmp_mount_point);
@@ -120,7 +125,12 @@
 int fs_mgr_is_latemount(struct fstab_rec *fstab);
 int fs_mgr_swapon_all(struct fstab *fstab);
 
-int fs_mgr_do_format(struct fstab_rec *fstab);
+int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer);
+
+#define FS_MGR_EARLY_SETUP_VERITY_NO_VERITY -2
+#define FS_MGR_EARLY_SETUP_VERITY_FAIL -1
+#define FS_MGR_EARLY_SETUP_VERITY_SUCCESS 0
+int fs_mgr_early_setup_verity(struct fstab_rec *fstab);
 
 #ifdef __cplusplus
 }
diff --git a/gatekeeperd/IUserManager.cpp b/gatekeeperd/IUserManager.cpp
index 8645fc2..8167d19 100644
--- a/gatekeeperd/IUserManager.cpp
+++ b/gatekeeperd/IUserManager.cpp
@@ -27,7 +27,7 @@
 class BpUserManager : public BpInterface<IUserManager>
 {
 public:
-    BpUserManager(const sp<IBinder>& impl) :
+    explicit BpUserManager(const sp<IBinder>& impl) :
             BpInterface<IUserManager>(impl) {
     }
     virtual int32_t getCredentialOwnerProfile(int32_t user_id) {
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index b4fdab0..4107f55 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -19,25 +19,22 @@
 #include "IGateKeeperService.h"
 
 #include <errno.h>
-#include <stdint.h>
-#include <inttypes.h>
 #include <fcntl.h>
+#include <inttypes.h>
+#include <stdint.h>
 #include <unistd.h>
 
-#include <cutils/log.h>
-#include <utils/Log.h>
-
+#include <android/log.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <binder/PermissionCache.h>
-#include <utils/String16.h>
-#include <utils/Log.h>
-
-#include <keystore/IKeystoreService.h>
-#include <keystore/keystore.h> // For error code
 #include <gatekeeper/password_handle.h> // for password_handle_t
 #include <hardware/gatekeeper.h>
 #include <hardware/hw_auth_token.h>
+#include <keystore/IKeystoreService.h>
+#include <keystore/keystore.h> // For error code
+#include <utils/Log.h>
+#include <utils/String16.h>
 
 #include "SoftGateKeeperDevice.h"
 #include "IUserManager.h"
@@ -76,7 +73,7 @@
 
     void store_sid(uint32_t uid, uint64_t sid) {
         char filename[21];
-        sprintf(filename, "%u", uid);
+        snprintf(filename, sizeof(filename), "%u", uid);
         int fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
         if (fd < 0) {
             ALOGE("could not open file: %s: %s", filename, strerror(errno));
@@ -102,7 +99,7 @@
 
     void maybe_store_sid(uint32_t uid, uint64_t sid) {
         char filename[21];
-        sprintf(filename, "%u", uid);
+        snprintf(filename, sizeof(filename), "%u", uid);
         if (access(filename, F_OK) == -1) {
             store_sid(uid, sid);
         }
@@ -111,7 +108,7 @@
     uint64_t read_sid(uint32_t uid) {
         char filename[21];
         uint64_t sid;
-        sprintf(filename, "%u", uid);
+        snprintf(filename, sizeof(filename), "%u", uid);
         int fd = open(filename, O_RDONLY);
         if (fd < 0) return 0;
         read(fd, &sid, sizeof(sid));
@@ -121,7 +118,7 @@
 
     void clear_sid(uint32_t uid) {
         char filename[21];
-        sprintf(filename, "%u", uid);
+        snprintf(filename, sizeof(filename), "%u", uid);
         if (remove(filename) < 0) {
             ALOGE("%s: could not remove file [%s], attempting 0 write", __func__, strerror(errno));
             store_sid(uid, 0);
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 9bff767..1c130dc 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -8,6 +8,8 @@
 LOCAL_CFLAGS := -Werror
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_STATIC_LIBRARIES := libbinder
+LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := libbinder
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -15,7 +17,7 @@
 LOCAL_MODULE := libbatterymonitor
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_STATIC_LIBRARIES := libutils
+LOCAL_STATIC_LIBRARIES := libutils libbase libbinder
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -50,8 +52,21 @@
 
 include $(CLEAR_VARS)
 
+ifeq ($(strip $(BOARD_CHARGER_NO_UI)),true)
+LOCAL_CHARGER_NO_UI := true
+endif
+ifdef BRILLO
+LOCAL_CHARGER_NO_UI := true
+endif
+
 LOCAL_SRC_FILES := \
-    healthd.cpp \
+	healthd.cpp \
+	healthd_mode_android.cpp \
+	BatteryPropertiesRegistrar.cpp \
+
+ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
+LOCAL_SRC_FILES += healthd_mode_charger.cpp
+endif
 
 LOCAL_MODULE := healthd
 LOCAL_MODULE_TAGS := optional
@@ -69,6 +84,12 @@
 LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND
 endif
 
+ifeq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
+LOCAL_CFLAGS += -DCHARGER_NO_UI
+endif
+
+LOCAL_C_INCLUDES := bootable/recovery $(LOCAL_PATH)/include
+
 ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_FAST),)
 LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_FAST=$(BOARD_PERIODIC_CHORES_INTERVAL_FAST)
 endif
@@ -77,22 +98,28 @@
 LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_SLOW=$(BOARD_PERIODIC_CHORES_INTERVAL_SLOW)
 endif
 
-LOCAL_C_INCLUDES := bootable/recovery
-
 LOCAL_STATIC_LIBRARIES := \
     libhealthd_internal \
     libbatterymonitor \
     libbatteryservice \
     libbinder \
-    libminui \
-    libpng \
-    libz \
-    libutils \
     libbase \
+
+ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
+LOCAL_STATIC_LIBRARIES += \
+   libminui \
+   libpng \
+   libz \
+
+endif
+
+
+LOCAL_STATIC_LIBRARIES += \
+    libutils \
     libcutils \
     liblog \
     libm \
-    libc
+    libc \
 
 ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
 LOCAL_STATIC_LIBRARIES += libsuspend
@@ -107,6 +134,7 @@
 include $(BUILD_EXECUTABLE)
 
 
+ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
 define _add-charger-image
 include $$(CLEAR_VARS)
 LOCAL_MODULE := system_core_charger_res_images_$(notdir $(1))
@@ -132,3 +160,4 @@
 
 _add-charger-image :=
 _img_modules :=
+endif # LOCAL_CHARGER_NO_UI
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 54d45e6..0c90a54 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -26,7 +26,11 @@
 #include <stdlib.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <memory>
 
+#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
 #include <batteryservice/BatteryService.h>
 #include <cutils/klog.h>
 #include <cutils/properties.h>
@@ -124,34 +128,15 @@
     return ret;
 }
 
-int BatteryMonitor::readFromFile(const String8& path, char* buf, size_t size) {
-    char *cp = NULL;
-
-    if (path.isEmpty())
-        return -1;
-    int fd = open(path.string(), O_RDONLY, 0);
-    if (fd == -1) {
-        KLOG_ERROR(LOG_TAG, "Could not open '%s'\n", path.string());
-        return -1;
+int BatteryMonitor::readFromFile(const String8& path, std::string* buf) {
+    if (android::base::ReadFileToString(String8::std_string(path), buf)) {
+        *buf = android::base::Trim(*buf);
     }
-
-    ssize_t count = TEMP_FAILURE_RETRY(read(fd, buf, size));
-    if (count > 0)
-            cp = (char *)memrchr(buf, '\n', count);
-
-    if (cp)
-        *cp = '\0';
-    else
-        buf[0] = '\0';
-
-    close(fd);
-    return count;
+    return buf->length();
 }
 
 BatteryMonitor::PowerSupplyType BatteryMonitor::readPowerSupplyType(const String8& path) {
-    const int SIZE = 128;
-    char buf[SIZE];
-    int length = readFromFile(path, buf, SIZE);
+    std::string buf;
     BatteryMonitor::PowerSupplyType ret;
     struct sysfsStringEnumMap supplyTypeMap[] = {
             { "Unknown", ANDROID_POWER_SUPPLY_TYPE_UNKNOWN },
@@ -170,12 +155,12 @@
             { NULL, 0 },
     };
 
-    if (length <= 0)
+    if (readFromFile(path, &buf) <= 0)
         return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
 
-    ret = (BatteryMonitor::PowerSupplyType)mapSysfsString(buf, supplyTypeMap);
+    ret = (BatteryMonitor::PowerSupplyType)mapSysfsString(buf.c_str(), supplyTypeMap);
     if (ret < 0) {
-        KLOG_WARNING(LOG_TAG, "Unknown power supply type '%s'\n", buf);
+        KLOG_WARNING(LOG_TAG, "Unknown power supply type '%s'\n", buf.c_str());
         ret = ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
     }
 
@@ -183,27 +168,23 @@
 }
 
 bool BatteryMonitor::getBooleanField(const String8& path) {
-    const int SIZE = 16;
-    char buf[SIZE];
-
+    std::string buf;
     bool value = false;
-    if (readFromFile(path, buf, SIZE) > 0) {
-        if (buf[0] != '0') {
+
+    if (readFromFile(path, &buf) > 0)
+        if (buf[0] != '0')
             value = true;
-        }
-    }
 
     return value;
 }
 
 int BatteryMonitor::getIntField(const String8& path) {
-    const int SIZE = 128;
-    char buf[SIZE];
-
+    std::string buf;
     int value = 0;
-    if (readFromFile(path, buf, SIZE) > 0) {
-        value = strtol(buf, NULL, 0);
-    }
+
+    if (readFromFile(path, &buf) > 0)
+        android::base::ParseInt(buf, &value);
+
     return value;
 }
 
@@ -247,18 +228,16 @@
         props.batteryHealth = BATTERY_HEALTH_GOOD;
     }
 
-    const int SIZE = 128;
-    char buf[SIZE];
-    String8 btech;
+    std::string buf;
 
-    if (readFromFile(mHealthdConfig->batteryStatusPath, buf, SIZE) > 0)
-        props.batteryStatus = getBatteryStatus(buf);
+    if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
+        props.batteryStatus = getBatteryStatus(buf.c_str());
 
-    if (readFromFile(mHealthdConfig->batteryHealthPath, buf, SIZE) > 0)
-        props.batteryHealth = getBatteryHealth(buf);
+    if (readFromFile(mHealthdConfig->batteryHealthPath, &buf) > 0)
+        props.batteryHealth = getBatteryHealth(buf.c_str());
 
-    if (readFromFile(mHealthdConfig->batteryTechnologyPath, buf, SIZE) > 0)
-        props.batteryTechnology = String8(buf);
+    if (readFromFile(mHealthdConfig->batteryTechnologyPath, &buf) > 0)
+        props.batteryTechnology = String8(buf.c_str());
 
     unsigned int i;
     double MaxPower = 0;
@@ -267,47 +246,44 @@
         String8 path;
         path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH,
                           mChargerNames[i].string());
-
-        if (readFromFile(path, buf, SIZE) > 0) {
-            if (buf[0] != '0') {
-                path.clear();
-                path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
-                                  mChargerNames[i].string());
-                switch(readPowerSupplyType(path)) {
-                case ANDROID_POWER_SUPPLY_TYPE_AC:
-                    props.chargerAcOnline = true;
-                    break;
-                case ANDROID_POWER_SUPPLY_TYPE_USB:
-                    props.chargerUsbOnline = true;
-                    break;
-                case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
-                    props.chargerWirelessOnline = true;
-                    break;
-                default:
-                    KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
-                                 mChargerNames[i].string());
-                }
-                path.clear();
-                path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
-                                  mChargerNames[i].string());
-                int ChargingCurrent =
+        if (getIntField(path)) {
+            path.clear();
+            path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
+                              mChargerNames[i].string());
+            switch(readPowerSupplyType(path)) {
+            case ANDROID_POWER_SUPPLY_TYPE_AC:
+                props.chargerAcOnline = true;
+                break;
+            case ANDROID_POWER_SUPPLY_TYPE_USB:
+                props.chargerUsbOnline = true;
+                break;
+            case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
+                props.chargerWirelessOnline = true;
+                break;
+            default:
+                KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
+                             mChargerNames[i].string());
+            }
+            path.clear();
+            path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
+                              mChargerNames[i].string());
+            int ChargingCurrent =
                     (access(path.string(), R_OK) == 0) ? getIntField(path) : 0;
 
-                path.clear();
-                path.appendFormat("%s/%s/voltage_max", POWER_SUPPLY_SYSFS_PATH,
-                                  mChargerNames[i].string());
+            path.clear();
+            path.appendFormat("%s/%s/voltage_max", POWER_SUPPLY_SYSFS_PATH,
+                              mChargerNames[i].string());
 
-                int ChargingVoltage =
-                    (access(path.string(), R_OK) == 0) ? getIntField(path) :
-                    DEFAULT_VBUS_VOLTAGE;
+            int ChargingVoltage =
+                (access(path.string(), R_OK) == 0) ? getIntField(path) :
+                DEFAULT_VBUS_VOLTAGE;
 
-                double power = ((double)ChargingCurrent / MILLION) *
-                        ((double)ChargingVoltage / MILLION);
-                if (MaxPower < power) {
-                    props.maxChargingCurrent = ChargingCurrent;
-                    props.maxChargingVoltage = ChargingVoltage;
-                    MaxPower = power;
-                }
+            double power = ((double)ChargingCurrent / MILLION) *
+                           ((double)ChargingVoltage / MILLION);
+            if (MaxPower < power) {
+                props.maxChargingCurrent = ChargingCurrent;
+                props.maxChargingVoltage = ChargingVoltage;
+                MaxPower = power;
             }
         }
     }
@@ -342,11 +318,10 @@
                                 " cc=%d", props.batteryCycleCount);
             }
         } else {
-            snprintf(dmesgline, sizeof(dmesgline),
+            len = snprintf(dmesgline, sizeof(dmesgline),
                  "battery none");
         }
 
-        len = strlen(dmesgline);
         snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s",
                  props.chargerAcOnline ? "a" : "",
                  props.chargerUsbOnline ? "u" : "",
@@ -363,10 +338,9 @@
 int BatteryMonitor::getChargeStatus() {
     int result = BATTERY_STATUS_UNKNOWN;
     if (!mHealthdConfig->batteryStatusPath.isEmpty()) {
-        char buf[128];
-        if (readFromFile(mHealthdConfig->batteryStatusPath, buf, sizeof(buf)) > 0) {
-            result = getBatteryStatus(buf);
-        }
+        std::string buf;
+        if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
+            result = getBatteryStatus(buf.c_str());
     }
     return result;
 }
@@ -488,13 +462,13 @@
     char pval[PROPERTY_VALUE_MAX];
 
     mHealthdConfig = hc;
-    DIR* dir = opendir(POWER_SUPPLY_SYSFS_PATH);
+    std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(POWER_SUPPLY_SYSFS_PATH), closedir);
     if (dir == NULL) {
         KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH);
     } else {
         struct dirent* entry;
 
-        while ((entry = readdir(dir))) {
+        while ((entry = readdir(dir.get()))) {
             const char* name = entry->d_name;
 
             if (!strcmp(name, ".") || !strcmp(name, ".."))
@@ -632,7 +606,6 @@
                 break;
             }
         }
-        closedir(dir);
     }
 
     // Typically the case for devices which do not have a battery and
diff --git a/healthd/BatteryPropertiesRegistrar.cpp b/healthd/BatteryPropertiesRegistrar.cpp
index 5d1fa52..d28ba41 100644
--- a/healthd/BatteryPropertiesRegistrar.cpp
+++ b/healthd/BatteryPropertiesRegistrar.cpp
@@ -35,7 +35,7 @@
     defaultServiceManager()->addService(String16("batteryproperties"), service);
 }
 
-void BatteryPropertiesRegistrar::notifyListeners(struct BatteryProperties props) {
+void BatteryPropertiesRegistrar::notifyListeners(const struct BatteryProperties& props) {
     Mutex::Autolock _l(mRegistrationLock);
     for (size_t i = 0; i < mListeners.size(); i++) {
         mListeners[i]->batteryPropertiesChanged(props);
diff --git a/healthd/BatteryPropertiesRegistrar.h b/healthd/BatteryPropertiesRegistrar.h
index d17e4a3..095f3d3 100644
--- a/healthd/BatteryPropertiesRegistrar.h
+++ b/healthd/BatteryPropertiesRegistrar.h
@@ -31,7 +31,7 @@
                                    public IBinder::DeathRecipient {
 public:
     void publish(const sp<BatteryPropertiesRegistrar>& service);
-    void notifyListeners(struct BatteryProperties props);
+    void notifyListeners(const struct BatteryProperties& props);
 
 private:
     Mutex mRegistrationLock;
diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
index a7be29f..3f0e047 100644
--- a/healthd/healthd.cpp
+++ b/healthd/healthd.cpp
@@ -119,10 +119,17 @@
 };
 
 static struct healthd_mode_ops charger_ops = {
+#ifdef CHARGER_NO_UI
+    .init = healthd_mode_nop_init,
+    .preparetowait = healthd_mode_nop_preparetowait,
+    .heartbeat = healthd_mode_nop_heartbeat,
+    .battery_update = healthd_mode_nop_battery_update,
+#else
     .init = healthd_mode_charger_init,
     .preparetowait = healthd_mode_charger_preparetowait,
     .heartbeat = healthd_mode_charger_heartbeat,
     .battery_update = healthd_mode_charger_battery_update,
+#endif
 };
 
 static struct healthd_mode_ops recovery_ops = {
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 6551cc7..243cbea 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -65,7 +65,7 @@
 #define min(a,b) ((a) < (b) ? (a) : (b))
 #endif
 
-#define ARRAY_SIZE(x)           (sizeof(x)/sizeof(x[0]))
+#define ARRAY_SIZE(x)           (sizeof(x)/sizeof((x)[0]))
 
 #define MSEC_PER_SEC            (1000LL)
 #define NSEC_PER_MSEC           (1000000LL)
diff --git a/healthd/include/healthd/BatteryMonitor.h b/healthd/include/healthd/BatteryMonitor.h
index 440f2e4..8865a7d 100644
--- a/healthd/include/healthd/BatteryMonitor.h
+++ b/healthd/include/healthd/BatteryMonitor.h
@@ -55,7 +55,7 @@
 
     int getBatteryStatus(const char* status);
     int getBatteryHealth(const char* status);
-    int readFromFile(const String8& path, char* buf, size_t size);
+    int readFromFile(const String8& path, std::string* buf);
     PowerSupplyType readPowerSupplyType(const String8& path);
     bool getBooleanField(const String8& path);
     int getIntField(const String8& path);
diff --git a/include/android/log.h b/include/android/log.h
index 391c826..5673357 100644
--- a/include/android/log.h
+++ b/include/android/log.h
@@ -74,8 +74,48 @@
 #endif
 
 /*
+ * This file uses ", ## __VA_ARGS__" zero-argument token pasting to
+ * work around issues with debug-only syntax errors in assertions
+ * that are missing format strings.  See commit
+ * 19299904343daf191267564fe32e6cd5c165cd42
+ */
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
+#endif
+
+#ifndef __predict_false
+#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
+#endif
+
+/*
+ * LOG_TAG is the local tag used for the following simplified
+ * logging macros.  You must set this preprocessor definition,
+ * or more tenuously supply a variable definition, before using
+ * the macros.
+ */
+
+/*
+ * Normally we strip the effects of ALOGV (VERBOSE messages),
+ * LOG_FATAL and LOG_FATAL_IF (FATAL assert messages) from the
+ * release builds be defining NDEBUG.  You can modify this (for
+ * example with "#define LOG_NDEBUG 0" at the top of your source
+ * file) to change that behavior.
+ */
+
+#ifndef LOG_NDEBUG
+#ifdef NDEBUG
+#define LOG_NDEBUG 1
+#else
+#define LOG_NDEBUG 0
+#endif
+#endif
+
+/*
  * Android log priority values, in ascending priority order.
  */
+#ifndef __android_LogPriority_defined
+#define __android_LogPriority_defined
 typedef enum android_LogPriority {
     ANDROID_LOG_UNKNOWN = 0,
     ANDROID_LOG_DEFAULT,    /* only for SetMinPriority() */
@@ -87,21 +127,20 @@
     ANDROID_LOG_FATAL,
     ANDROID_LOG_SILENT,     /* only for SetMinPriority(); must be last */
 } android_LogPriority;
-
-/*
- * Release any logger resources (a new log write will immediately re-acquire)
- */
-void __android_log_close();
+#endif
 
 /*
  * Send a simple string to the log.
  */
-int __android_log_write(int prio, const char *tag, const char *text);
+int __android_log_write(int prio, const char* tag, const char* text);
+
+#define android_writeLog(prio, tag, text) \
+    __android_log_write(prio, tag, text)
 
 /*
  * Send a formatted string to the log, used like printf(fmt,...)
  */
-int __android_log_print(int prio, const char *tag,  const char *fmt, ...)
+int __android_log_print(int prio, const char* tag,  const char* fmt, ...)
 #if defined(__GNUC__)
 #ifdef __USE_MINGW_ANSI_STDIO
 #if __USE_MINGW_ANSI_STDIO
@@ -115,21 +154,55 @@
 #endif
     ;
 
+#define android_printLog(prio, tag, ...) \
+    __android_log_print(prio, tag, __VA_ARGS__)
+
+/*
+ * Log macro that allows you to specify a number for the priority.
+ */
+#ifndef LOG_PRI
+#define LOG_PRI(priority, tag, ...) \
+    android_printLog(priority, tag, __VA_ARGS__)
+#endif
+
 /*
  * A variant of __android_log_print() that takes a va_list to list
  * additional parameters.
  */
-int __android_log_vprint(int prio, const char *tag,
-                         const char *fmt, va_list ap);
+int __android_log_vprint(int prio, const char* tag,
+                         const char* fmt, va_list ap)
+#if defined(__GNUC__)
+#ifdef __USE_MINGW_ANSI_STDIO
+#if __USE_MINGW_ANSI_STDIO
+    __attribute__ ((format(gnu_printf, 3, 0)))
+#else
+    __attribute__ ((format(printf, 3, 0)))
+#endif
+#else
+    __attribute__ ((format(printf, 3, 0)))
+#endif
+#endif
+    ;
+
+#define android_vprintLog(prio, cond, tag, ...) \
+    __android_log_vprint(prio, tag, __VA_ARGS__)
+
+/*
+ * Log macro that allows you to pass in a varargs ("args" is a va_list).
+ */
+#ifndef LOG_PRI_VA
+#define LOG_PRI_VA(priority, tag, fmt, args) \
+    android_vprintLog(priority, NULL, tag, fmt, args)
+#endif
 
 /*
  * Log an assertion failure and abort the process to have a chance
  * to inspect it if a debugger is attached. This uses the FATAL priority.
  */
-void __android_log_assert(const char *cond, const char *tag,
-                          const char *fmt, ...)
+void __android_log_assert(const char* cond, const char* tag,
+                          const char* fmt, ...)
 #if defined(__GNUC__)
-    __attribute__ ((noreturn))
+    __attribute__ ((__noreturn__))
 #ifdef __USE_MINGW_ANSI_STDIO
 #if __USE_MINGW_ANSI_STDIO
     __attribute__ ((format(gnu_printf, 3, 4)))
@@ -142,6 +215,311 @@
 #endif
     ;
 
+/* XXX Macros to work around syntax errors in places where format string
+ * arg is not passed to ALOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF
+ * (happens only in debug builds).
+ */
+
+/* Returns 2nd arg.  Used to substitute default value if caller's vararg list
+ * is empty.
+ */
+#define __android_second(dummy, second, ...)     second
+
+/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise
+ * returns nothing.
+ */
+#define __android_rest(first, ...)               , ## __VA_ARGS__
+
+#define android_printAssert(cond, tag, ...) \
+    __android_log_assert(cond, tag, \
+        __android_second(0, ## __VA_ARGS__, NULL) __android_rest(__VA_ARGS__))
+
+/*
+ * Log a fatal error.  If the given condition fails, this stops program
+ * execution like a normal assertion, but also generating the given message.
+ * It is NOT stripped from release builds.  Note that the condition test
+ * is -inverted- from the normal assert() semantics.
+ */
+#ifndef LOG_ALWAYS_FATAL_IF
+#define LOG_ALWAYS_FATAL_IF(cond, ...) \
+    ( (__predict_false(cond)) \
+    ? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+#ifndef LOG_ALWAYS_FATAL
+#define LOG_ALWAYS_FATAL(...) \
+    ( ((void)android_printAssert(NULL, LOG_TAG, ## __VA_ARGS__)) )
+#endif
+
+/*
+ * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that
+ * are stripped out of release builds.
+ */
+
+#if LOG_NDEBUG
+
+#ifndef LOG_FATAL_IF
+#define LOG_FATAL_IF(cond, ...) ((void)0)
+#endif
+#ifndef LOG_FATAL
+#define LOG_FATAL(...) ((void)0)
+#endif
+
+#else
+
+#ifndef LOG_FATAL_IF
+#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ## __VA_ARGS__)
+#endif
+#ifndef LOG_FATAL
+#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
+#endif
+
+#endif
+
+/*
+ * Assertion that generates a log message when the assertion fails.
+ * Stripped out of release builds.  Uses the current LOG_TAG.
+ */
+#ifndef ALOG_ASSERT
+#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__)
+#endif
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * C/C++ logging functions.  See the logging documentation for API details.
+ *
+ * We'd like these to be available from C code (in case we import some from
+ * somewhere), so this has a C interface.
+ *
+ * The output will be correct when the log file is shared between multiple
+ * threads and/or multiple processes so long as the operating system
+ * supports O_APPEND.  These calls have mutex-protected data structures
+ * and so are NOT reentrant.  Do not use LOG in a signal handler.
+ */
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Simplified macro to send a verbose log message using the current LOG_TAG.
+ */
+#ifndef ALOGV
+#define __ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#if LOG_NDEBUG
+#define ALOGV(...) do { if (0) { __ALOGV(__VA_ARGS__); } } while (0)
+#else
+#define ALOGV(...) __ALOGV(__VA_ARGS__)
+#endif
+#endif
+
+#ifndef ALOGV_IF
+#if LOG_NDEBUG
+#define ALOGV_IF(cond, ...)   ((void)0)
+#else
+#define ALOGV_IF(cond, ...) \
+    ( (__predict_false(cond)) \
+    ? ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+#endif
+
+/*
+ * Simplified macro to send a debug log message using the current LOG_TAG.
+ */
+#ifndef ALOGD
+#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef ALOGD_IF
+#define ALOGD_IF(cond, ...) \
+    ( (__predict_false(cond)) \
+    ? ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an info log message using the current LOG_TAG.
+ */
+#ifndef ALOGI
+#define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef ALOGI_IF
+#define ALOGI_IF(cond, ...) \
+    ( (__predict_false(cond)) \
+    ? ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send a warning log message using the current LOG_TAG.
+ */
+#ifndef ALOGW
+#define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef ALOGW_IF
+#define ALOGW_IF(cond, ...) \
+    ( (__predict_false(cond)) \
+    ? ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an error log message using the current LOG_TAG.
+ */
+#ifndef ALOGE
+#define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef ALOGE_IF
+#define ALOGE_IF(cond, ...) \
+    ( (__predict_false(cond)) \
+    ? ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * verbose priority.
+ */
+#ifndef IF_ALOGV
+#if LOG_NDEBUG
+#define IF_ALOGV() if (false)
+#else
+#define IF_ALOGV() IF_ALOG(LOG_VERBOSE, LOG_TAG)
+#endif
+#endif
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * debug priority.
+ */
+#ifndef IF_ALOGD
+#define IF_ALOGD() IF_ALOG(LOG_DEBUG, LOG_TAG)
+#endif
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * info priority.
+ */
+#ifndef IF_ALOGI
+#define IF_ALOGI() IF_ALOG(LOG_INFO, LOG_TAG)
+#endif
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * warn priority.
+ */
+#ifndef IF_ALOGW
+#define IF_ALOGW() IF_ALOG(LOG_WARN, LOG_TAG)
+#endif
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * error priority.
+ */
+#ifndef IF_ALOGE
+#define IF_ALOGE() IF_ALOG(LOG_ERROR, LOG_TAG)
+#endif
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Basic log message macro.
+ *
+ * Example:
+ *  ALOG(LOG_WARN, NULL, "Failed with error %d", errno);
+ *
+ * The second argument may be NULL or "" to indicate the "global" tag.
+ */
+#ifndef ALOG
+#define ALOG(priority, tag, ...) \
+    LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
+#endif
+
+/*
+ * Conditional given a desired logging priority and tag.
+ */
+#ifndef IF_ALOG
+#define IF_ALOG(priority, tag) \
+    if (android_testLog(ANDROID_##priority, tag))
+#endif
+
+/* --------------------------------------------------------------------- */
+
+/*
+ *    IF_ALOG uses android_testLog, but IF_ALOG can be overridden.
+ *    android_testLog will remain constant in its purpose as a wrapper
+ *        for Android logging filter policy, and can be subject to
+ *        change. It can be reused by the developers that override
+ *        IF_ALOG as a convenient means to reimplement their policy
+ *        over Android.
+ */
+
+#ifndef __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE 2
+#elif __ANDROID_API__ > 24 /* > Nougat */
+#define __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE 2
+#elif __ANDROID_API__ > 22 /* > Lollipop */
+#define __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE
+
+/*
+ * Use the per-tag properties "log.tag.<tagname>" to generate a runtime
+ * result of non-zero to expose a log. prio is ANDROID_LOG_VERBOSE to
+ * ANDROID_LOG_FATAL. default_prio if no property. Undefined behavior if
+ * any other value.
+ */
+int __android_log_is_loggable(int prio, const char* tag, int default_prio);
+
+#if __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE > 1
+#include <sys/types.h>
+
+int __android_log_is_loggable_len(int prio, const char* tag, size_t len,
+                                  int default_prio);
+
+#if LOG_NDEBUG /* Production */
+#define android_testLog(prio, tag) \
+    (__android_log_is_loggable_len(prio, tag, (tag && *tag) ? strlen(tag) : 0, \
+                                   ANDROID_LOG_DEBUG) != 0)
+#else
+#define android_testLog(prio, tag) \
+    (__android_log_is_loggable_len(prio, tag, (tag && *tag) ? strlen(tag) : 0, \
+                                   ANDROID_LOG_VERBOSE) != 0)
+#endif
+
+#else
+
+#if LOG_NDEBUG /* Production */
+#define android_testLog(prio, tag) \
+    (__android_log_is_loggable(prio, tag, ANDROID_LOG_DEBUG) != 0)
+#else
+#define android_testLog(prio, tag) \
+    (__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE) != 0)
+#endif
+
+#endif
+
+#else /* __ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE */
+
+#define android_testLog(prio, tag) (1)
+
+#endif /* !__ANDROID_USE_LIBLOG_LOGGABLE_INTERFACE */
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/backtrace/BacktraceMap.h b/include/backtrace/BacktraceMap.h
index b80045f..df48dfe 100644
--- a/include/backtrace/BacktraceMap.h
+++ b/include/backtrace/BacktraceMap.h
@@ -19,7 +19,7 @@
 
 #include <stdint.h>
 #include <sys/types.h>
-#ifdef USE_MINGW
+#ifdef _WIN32
 // MINGW does not define these constants.
 #define PROT_NONE 0
 #define PROT_READ 0x1
diff --git a/include/cutils/android_get_control_file.h b/include/cutils/android_get_control_file.h
new file mode 100644
index 0000000..ed8fbf8
--- /dev/null
+++ b/include/cutils/android_get_control_file.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#ifndef __CUTILS_ANDROID_GET_CONTROL_FILE_H
+#define __CUTILS_ANDROID_GET_CONTROL_FILE_H
+
+#define ANDROID_FILE_ENV_PREFIX "ANDROID_FILE_"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * android_get_control_file - simple helper function to get the file
+ * descriptor of our init-managed file. `path' is the filename path as
+ * given in init.rc. Returns -1 on error.
+ */
+int android_get_control_file(const char* path);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_ANDROID_GET_CONTROL_FILE_H */
diff --git a/include/cutils/ashmem.h b/include/cutils/ashmem.h
index 25b233e..d80caa6 100644
--- a/include/cutils/ashmem.h
+++ b/include/cutils/ashmem.h
@@ -12,10 +12,15 @@
 
 #include <stddef.h>
 
+#if defined(__BIONIC__)
+#include <linux/ashmem.h>
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+int ashmem_valid(int fd);
 int ashmem_create_region(const char *name, size_t size);
 int ashmem_set_prot_region(int fd, int prot);
 int ashmem_pin_region(int fd, size_t offset, size_t len);
@@ -26,20 +31,4 @@
 }
 #endif
 
-#ifndef __ASHMEMIOC	/* in case someone included <linux/ashmem.h> too */
-
-#define ASHMEM_NAME_LEN		256
-
-#define ASHMEM_NAME_DEF		"dev/ashmem"
-
-/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */
-#define ASHMEM_NOT_PURGED	0
-#define ASHMEM_WAS_PURGED	1
-
-/* Return values from ASHMEM_UNPIN: Is the mapping now pinned or unpinned? */
-#define ASHMEM_IS_UNPINNED	0
-#define ASHMEM_IS_PINNED	1
-
-#endif	/* ! __ASHMEMIOC */
-
 #endif	/* _CUTILS_ASHMEM_H */
diff --git a/include/cutils/atomic.h b/include/cutils/atomic.h
index ded972a..0c88bfe 100644
--- a/include/cutils/atomic.h
+++ b/include/cutils/atomic.h
@@ -71,6 +71,15 @@
  * If they are not, atomicity is not guaranteed.
  */
 
+ANDROID_ATOMIC_INLINE
+volatile atomic_int_least32_t* to_atomic_int_least32_t(volatile const int32_t* addr) {
+#ifdef __cplusplus
+    return reinterpret_cast<volatile atomic_int_least32_t*>(const_cast<volatile int32_t*>(addr));
+#else
+    return (volatile atomic_int_least32_t*)addr;
+#endif
+}
+
 /*
  * Basic arithmetic and bitwise operations.  These all provide a
  * barrier with "release" ordering, and return the previous value.
@@ -81,7 +90,7 @@
 ANDROID_ATOMIC_INLINE
 int32_t android_atomic_inc(volatile int32_t* addr)
 {
-    volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr;
+    volatile atomic_int_least32_t* a = to_atomic_int_least32_t(addr);
         /* Int32_t, if it exists, is the same as int_least32_t. */
     return atomic_fetch_add_explicit(a, 1, memory_order_release);
 }
@@ -89,28 +98,28 @@
 ANDROID_ATOMIC_INLINE
 int32_t android_atomic_dec(volatile int32_t* addr)
 {
-    volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr;
+    volatile atomic_int_least32_t* a = to_atomic_int_least32_t(addr);
     return atomic_fetch_sub_explicit(a, 1, memory_order_release);
 }
 
 ANDROID_ATOMIC_INLINE
 int32_t android_atomic_add(int32_t value, volatile int32_t* addr)
 {
-    volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr;
+    volatile atomic_int_least32_t* a = to_atomic_int_least32_t(addr);
     return atomic_fetch_add_explicit(a, value, memory_order_release);
 }
 
 ANDROID_ATOMIC_INLINE
 int32_t android_atomic_and(int32_t value, volatile int32_t* addr)
 {
-    volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr;
+    volatile atomic_int_least32_t* a = to_atomic_int_least32_t(addr);
     return atomic_fetch_and_explicit(a, value, memory_order_release);
 }
 
 ANDROID_ATOMIC_INLINE
 int32_t android_atomic_or(int32_t value, volatile int32_t* addr)
 {
-    volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr;
+    volatile atomic_int_least32_t* a = to_atomic_int_least32_t(addr);
     return atomic_fetch_or_explicit(a, value, memory_order_release);
 }
 
@@ -131,14 +140,14 @@
 ANDROID_ATOMIC_INLINE
 int32_t android_atomic_acquire_load(volatile const int32_t* addr)
 {
-    volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr;
+    volatile atomic_int_least32_t* a = to_atomic_int_least32_t(addr);
     return atomic_load_explicit(a, memory_order_acquire);
 }
 
 ANDROID_ATOMIC_INLINE
 int32_t android_atomic_release_load(volatile const int32_t* addr)
 {
-    volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr;
+    volatile atomic_int_least32_t* a = to_atomic_int_least32_t(addr);
     atomic_thread_fence(memory_order_seq_cst);
     /* Any reasonable clients of this interface would probably prefer   */
     /* something weaker.  But some remaining clients seem to be         */
@@ -162,7 +171,7 @@
 ANDROID_ATOMIC_INLINE
 void android_atomic_acquire_store(int32_t value, volatile int32_t* addr)
 {
-    volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr;
+    volatile atomic_int_least32_t* a = to_atomic_int_least32_t(addr);
     atomic_store_explicit(a, value, memory_order_relaxed);
     atomic_thread_fence(memory_order_seq_cst);
     /* Again overly conservative to accomodate weird clients.   */
@@ -171,7 +180,7 @@
 ANDROID_ATOMIC_INLINE
 void android_atomic_release_store(int32_t value, volatile int32_t* addr)
 {
-    volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr;
+    volatile atomic_int_least32_t* a = to_atomic_int_least32_t(addr);
     atomic_store_explicit(a, value, memory_order_release);
 }
 
@@ -191,22 +200,22 @@
 int android_atomic_acquire_cas(int32_t oldvalue, int32_t newvalue,
                            volatile int32_t* addr)
 {
-    volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr;
-    return (int)(!atomic_compare_exchange_strong_explicit(
+    volatile atomic_int_least32_t* a = to_atomic_int_least32_t(addr);
+    return !atomic_compare_exchange_strong_explicit(
                                           a, &oldvalue, newvalue,
                                           memory_order_acquire,
-                                          memory_order_acquire));
+                                          memory_order_acquire);
 }
 
 ANDROID_ATOMIC_INLINE
 int android_atomic_release_cas(int32_t oldvalue, int32_t newvalue,
                                volatile int32_t* addr)
 {
-    volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr;
-    return (int)(!atomic_compare_exchange_strong_explicit(
+    volatile atomic_int_least32_t* a = to_atomic_int_least32_t(addr);
+    return !atomic_compare_exchange_strong_explicit(
                                           a, &oldvalue, newvalue,
                                           memory_order_release,
-                                          memory_order_relaxed));
+                                          memory_order_relaxed);
 }
 
 /*
diff --git a/include/cutils/debugger.h b/include/cutils/debugger.h
index 285e1af..20e8796 100644
--- a/include/cutils/debugger.h
+++ b/include/cutils/debugger.h
@@ -20,32 +20,10 @@
 #include <sys/cdefs.h>
 #include <sys/types.h>
 
+#include "debuggerd/client.h"
+
 __BEGIN_DECLS
 
-#define DEBUGGER_SOCKET_NAME "android:debuggerd"
-#define DEBUGGER32_SOCKET_NAME "android:debuggerd32"
-#define DEBUGGER64_SOCKET_NAME DEBUGGER_SOCKET_NAME
-
-typedef enum {
-    // dump a crash
-    DEBUGGER_ACTION_CRASH,
-    // dump a tombstone file
-    DEBUGGER_ACTION_DUMP_TOMBSTONE,
-    // dump a backtrace only back to the socket
-    DEBUGGER_ACTION_DUMP_BACKTRACE,
-} debugger_action_t;
-
-// Make sure that all values have a fixed size so that this structure
-// is the same for 32 bit and 64 bit processes.
-// NOTE: Any changes to this structure must also be reflected in
-//       bionic/linker/debugger.cpp.
-typedef struct __attribute__((packed)) {
-    int32_t action;
-    pid_t tid;
-    uint64_t abort_msg_address;
-    int32_t original_si_code;
-} debugger_msg_t;
-
 /* Dumps a process backtrace, registers, and stack to a tombstone file (requires root).
  * Stores the tombstone path in the provided buffer.
  * Returns 0 on success, -1 on error.
diff --git a/include/cutils/klog.h b/include/cutils/klog.h
index 295d62b..c837edb 100644
--- a/include/cutils/klog.h
+++ b/include/cutils/klog.h
@@ -23,10 +23,8 @@
 
 __BEGIN_DECLS
 
-void klog_init(void);
 int  klog_get_level(void);
 void klog_set_level(int level);
-/* TODO: void klog_close(void); - and make klog_fd users thread safe. */
 
 void klog_write(int level, const char *fmt, ...)
     __attribute__ ((format(printf, 2, 3)));
diff --git a/include/cutils/native_handle.h b/include/cutils/native_handle.h
index 268c5d3..7d6a988 100644
--- a/include/cutils/native_handle.h
+++ b/include/cutils/native_handle.h
@@ -17,16 +17,30 @@
 #ifndef NATIVE_HANDLE_H_
 #define NATIVE_HANDLE_H_
 
+#include <stdalign.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+/* Declare a char array for use with native_handle_init */
+#define NATIVE_HANDLE_DECLARE_STORAGE(name, maxFds, maxInts) \
+    alignas(native_handle_t) char name[                            \
+      sizeof(native_handle_t) + sizeof(int) * (maxFds + maxInts)]
+
 typedef struct native_handle
 {
     int version;        /* sizeof(native_handle_t) */
     int numFds;         /* number of file-descriptors at &data[0] */
     int numInts;        /* number of ints at &data[numFds] */
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wzero-length-array"
+#endif
     int data[0];        /* numFds + numInts ints */
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
 } native_handle_t;
 
 /*
@@ -39,6 +53,14 @@
  */
 int native_handle_close(const native_handle_t* h);
 
+/*
+ * native_handle_init
+ *
+ * Initializes a native_handle_t from storage.  storage must be declared with
+ * NATIVE_HANDLE_DECLARE_STORAGE.  numFds and numInts must not respectively
+ * exceed maxFds and maxInts used to declare the storage.
+ */
+native_handle_t* native_handle_init(char* storage, int numFds, int numInts);
 
 /*
  * native_handle_create
@@ -50,6 +72,15 @@
 native_handle_t* native_handle_create(int numFds, int numInts);
 
 /*
+ * native_handle_clone
+ *
+ * creates a native_handle_t and initializes it from another native_handle_t.
+ * Must be destroyed with native_handle_delete().
+ *
+ */
+native_handle_t* native_handle_clone(const native_handle_t* handle);
+
+/*
  * native_handle_delete
  * 
  * frees a native_handle_t allocated with native_handle_create().
diff --git a/include/cutils/process_name.h b/include/cutils/process_name.h
deleted file mode 100644
index 1e72e5c..0000000
--- a/include/cutils/process_name.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Gives the current process a name.
- */
-
-#ifndef __PROCESS_NAME_H
-#define __PROCESS_NAME_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Sets the current process name.
- *
- * Warning: This leaks a string every time you call it. Use judiciously!
- */
-void set_process_name(const char* process_name);
-
-/** Gets the current process name. */
-const char* get_process_name(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __PROCESS_NAME_H */ 
diff --git a/include/cutils/properties.h b/include/cutils/properties.h
index 24aa224..adf670b 100644
--- a/include/cutils/properties.h
+++ b/include/cutils/properties.h
@@ -109,7 +109,7 @@
     
 int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie);    
 
-#if defined(__BIONIC_FORTIFY)
+#if defined(__BIONIC_FORTIFY) && !defined(__clang__)
 
 extern int __property_get_real(const char *, char *, const char *)
     __asm__(__USER_LABEL_PREFIX__ "property_get");
diff --git a/include/cutils/sockets.h b/include/cutils/sockets.h
index 783bd0b..d724dd6 100644
--- a/include/cutils/sockets.h
+++ b/include/cutils/sockets.h
@@ -18,6 +18,7 @@
 #define __CUTILS_SOCKETS_H
 
 #include <errno.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -34,6 +35,7 @@
 #else
 
 #include <sys/socket.h>
+#include <netinet/in.h>
 
 typedef int cutils_socket_t;
 #define INVALID_SOCKET (-1)
@@ -51,28 +53,8 @@
  * android_get_control_socket - simple helper function to get the file
  * descriptor of our init-managed Unix domain socket. `name' is the name of the
  * socket, as given in init.rc. Returns -1 on error.
- *
- * This is inline and not in libcutils proper because we want to use this in
- * third-party daemons with minimal modification.
  */
-static inline int android_get_control_socket(const char* name)
-{
-	char key[64];
-	snprintf(key, sizeof(key), ANDROID_SOCKET_ENV_PREFIX "%s", name);
-
-	const char* val = getenv(key);
-	if (!val) {
-		return -1;
-	}
-
-	errno = 0;
-	int fd = strtol(val, NULL, 10);
-	if (errno) {
-		return -1;
-	}
-
-	return fd;
-}
+int android_get_control_socket(const char* name);
 
 /*
  * See also android.os.LocalSocketAddress.Namespace
@@ -103,11 +85,11 @@
  *
  * These functions return INVALID_SOCKET (-1) on failure for all platforms.
  */
-int socket_loopback_client(int port, int type);
 cutils_socket_t socket_network_client(const char* host, int port, int type);
 int socket_network_client_timeout(const char* host, int port, int type,
                                   int timeout, int* getaddrinfo_error);
 int socket_loopback_server(int port, int type);
+int socket_loopback_server6(int port, int type);
 int socket_local_server(const char* name, int namespaceId, int type);
 int socket_local_server_bind(int s, const char* name, int namespaceId);
 int socket_local_client_connect(int fd, const char *name, int namespaceId,
diff --git a/include/cutils/trace.h b/include/cutils/trace.h
index 19313af..0f00417 100644
--- a/include/cutils/trace.h
+++ b/include/cutils/trace.h
@@ -189,8 +189,8 @@
 static inline void atrace_end(uint64_t tag)
 {
     if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
-        char c = 'E';
-        write(atrace_marker_fd, &c, 1);
+        void atrace_end_body();
+        atrace_end_body();
     }
 }
 
diff --git a/include/log/event_tag_map.h b/include/log/event_tag_map.h
index 1653c61..22e62ec 100644
--- a/include/log/event_tag_map.h
+++ b/include/log/event_tag_map.h
@@ -41,7 +41,22 @@
 /*
  * Look up a tag by index.  Returns the tag string, or NULL if not found.
  */
-const char* android_lookupEventTag(const EventTagMap* map, int tag);
+const char* android_lookupEventTag(const EventTagMap* map, unsigned int tag)
+    __attribute__((deprecated("use android_lookupEventTag_len() instead to minimize MAP_PRIVATE copy-on-write memory impact")));
+
+/*
+ * Look up a tag by index.  Returns the tag string & string length, or NULL if
+ * not found.  Returned string is not guaranteed to be nul terminated.
+ */
+const char* android_lookupEventTag_len(const EventTagMap* map,
+                                       size_t* len, unsigned int tag);
+
+/*
+ * Look up a format by index. Returns the format string & string length,
+ * or NULL if not found. Returned string is not guaranteed to be nul terminated.
+ */
+const char* android_lookupEventFormat_len(const EventTagMap* map,
+                                          size_t* len, unsigned int tag);
 
 #ifdef __cplusplus
 }
diff --git a/include/log/log.h b/include/log/log.h
index e606a84..d6f0eb5 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -14,206 +14,61 @@
  * limitations under the License.
  */
 
-//
-// C/C++ logging functions.  See the logging documentation for API details.
-//
-// We'd like these to be available from C code (in case we import some from
-// somewhere), so this has a C interface.
-//
-// The output will be correct when the log file is shared between multiple
-// threads and/or multiple processes so long as the operating system
-// supports O_APPEND.  These calls have mutex-protected data structures
-// and so are NOT reentrant.  Do not use LOG in a signal handler.
-//
 #ifndef _LIBS_LOG_LOG_H
 #define _LIBS_LOG_LOG_H
 
-#include <stdarg.h>
+/* Too many in the ecosystem assume these are included */
+#if !defined(_WIN32)
+#include <pthread.h>
+#endif
+#include <stdint.h>  /* uint16_t, int32_t */
 #include <stdio.h>
 #include <sys/types.h>
-#include <time.h>
+#include <time.h>    /* clock_gettime */
 #include <unistd.h>
 
-#include <log/logd.h>
-#include <log/uio.h>
+#include <android/log.h>
+#include <log/uio.h> /* helper to define iovec for portability */
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-// ---------------------------------------------------------------------
-
 /*
- * Normally we strip ALOGV (VERBOSE messages) from release builds.
- * You can modify this (for example with "#define LOG_NDEBUG 0"
- * at the top of your source file) to change that behavior.
- */
-#ifndef LOG_NDEBUG
-#ifdef NDEBUG
-#define LOG_NDEBUG 1
-#else
-#define LOG_NDEBUG 0
-#endif
-#endif
-
-/*
- * This is the local tag used for the following simplified
+ * LOG_TAG is the local tag used for the following simplified
  * logging macros.  You can change this preprocessor definition
  * before using the other macros to change the tag.
  */
+
 #ifndef LOG_TAG
 #define LOG_TAG NULL
 #endif
 
-// ---------------------------------------------------------------------
-
-#ifndef __predict_false
-#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
-#endif
+/* --------------------------------------------------------------------- */
 
 /*
- *      -DLINT_RLOG in sources that you want to enforce that all logging
- * goes to the radio log buffer. If any logging goes to any of the other
- * log buffers, there will be a compile or link error to highlight the
- * problem. This is not a replacement for a full audit of the code since
- * this only catches compiled code, not ifdef'd debug code. Options to
- * defining this, either temporarily to do a spot check, or permanently
- * to enforce, in all the communications trees; We have hopes to ensure
- * that by supplying just the radio log buffer that the communications
- * teams will have their one-stop shop for triaging issues.
+ * This file uses ", ## __VA_ARGS__" zero-argument token pasting to
+ * work around issues with debug-only syntax errors in assertions
+ * that are missing format strings.  See commit
+ * 19299904343daf191267564fe32e6cd5c165cd42
  */
-#ifndef LINT_RLOG
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
+#endif
 
 /*
- * Simplified macro to send a verbose log message using the current LOG_TAG.
+ * Send a simple string to the log.
  */
-#ifndef ALOGV
-#define __ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
-#if LOG_NDEBUG
-#define ALOGV(...) do { if (0) { __ALOGV(__VA_ARGS__); } } while (0)
-#else
-#define ALOGV(...) __ALOGV(__VA_ARGS__)
+int __android_log_buf_write(int bufID, int prio, const char* tag, const char* text);
+int __android_log_buf_print(int bufID, int prio, const char* tag, const char* fmt, ...)
+#if defined(__GNUC__)
+    __attribute__((__format__(printf, 4, 5)))
 #endif
-#endif
-
-#ifndef ALOGV_IF
-#if LOG_NDEBUG
-#define ALOGV_IF(cond, ...)   ((void)0)
-#else
-#define ALOGV_IF(cond, ...) \
-    ( (__predict_false(cond)) \
-    ? ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-#endif
+    ;
 
 /*
- * Simplified macro to send a debug log message using the current LOG_TAG.
- */
-#ifndef ALOGD
-#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef ALOGD_IF
-#define ALOGD_IF(cond, ...) \
-    ( (__predict_false(cond)) \
-    ? ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-/*
- * Simplified macro to send an info log message using the current LOG_TAG.
- */
-#ifndef ALOGI
-#define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef ALOGI_IF
-#define ALOGI_IF(cond, ...) \
-    ( (__predict_false(cond)) \
-    ? ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-/*
- * Simplified macro to send a warning log message using the current LOG_TAG.
- */
-#ifndef ALOGW
-#define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef ALOGW_IF
-#define ALOGW_IF(cond, ...) \
-    ( (__predict_false(cond)) \
-    ? ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-/*
- * Simplified macro to send an error log message using the current LOG_TAG.
- */
-#ifndef ALOGE
-#define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef ALOGE_IF
-#define ALOGE_IF(cond, ...) \
-    ( (__predict_false(cond)) \
-    ? ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-// ---------------------------------------------------------------------
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * verbose priority.
- */
-#ifndef IF_ALOGV
-#if LOG_NDEBUG
-#define IF_ALOGV() if (false)
-#else
-#define IF_ALOGV() IF_ALOG(LOG_VERBOSE, LOG_TAG)
-#endif
-#endif
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * debug priority.
- */
-#ifndef IF_ALOGD
-#define IF_ALOGD() IF_ALOG(LOG_DEBUG, LOG_TAG)
-#endif
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * info priority.
- */
-#ifndef IF_ALOGI
-#define IF_ALOGI() IF_ALOG(LOG_INFO, LOG_TAG)
-#endif
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * warn priority.
- */
-#ifndef IF_ALOGW
-#define IF_ALOGW() IF_ALOG(LOG_WARN, LOG_TAG)
-#endif
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * error priority.
- */
-#ifndef IF_ALOGE
-#define IF_ALOGE() IF_ALOG(LOG_ERROR, LOG_TAG)
-#endif
-
-
-// ---------------------------------------------------------------------
-
-/*
- * Simplified macro to send a verbose system log message using the current LOG_TAG.
+ * Simplified macro to send a verbose system log message using current LOG_TAG.
  */
 #ifndef SLOGV
 #define __SLOGV(...) \
@@ -237,7 +92,7 @@
 #endif
 
 /*
- * Simplified macro to send a debug system log message using the current LOG_TAG.
+ * Simplified macro to send a debug system log message using current LOG_TAG.
  */
 #ifndef SLOGD
 #define SLOGD(...) \
@@ -252,7 +107,7 @@
 #endif
 
 /*
- * Simplified macro to send an info system log message using the current LOG_TAG.
+ * Simplified macro to send an info system log message using current LOG_TAG.
  */
 #ifndef SLOGI
 #define SLOGI(...) \
@@ -267,7 +122,7 @@
 #endif
 
 /*
- * Simplified macro to send a warning system log message using the current LOG_TAG.
+ * Simplified macro to send a warning system log message using current LOG_TAG.
  */
 #ifndef SLOGW
 #define SLOGW(...) \
@@ -282,7 +137,7 @@
 #endif
 
 /*
- * Simplified macro to send an error system log message using the current LOG_TAG.
+ * Simplified macro to send an error system log message using current LOG_TAG.
  */
 #ifndef SLOGE
 #define SLOGE(...) \
@@ -296,12 +151,10 @@
     : (void)0 )
 #endif
 
-#endif /* !LINT_RLOG */
-
-// ---------------------------------------------------------------------
+/* --------------------------------------------------------------------- */
 
 /*
- * Simplified macro to send a verbose radio log message using the current LOG_TAG.
+ * Simplified macro to send a verbose radio log message using current LOG_TAG.
  */
 #ifndef RLOGV
 #define __RLOGV(...) \
@@ -325,7 +178,7 @@
 #endif
 
 /*
- * Simplified macro to send a debug radio log message using the current LOG_TAG.
+ * Simplified macro to send a debug radio log message using  current LOG_TAG.
  */
 #ifndef RLOGD
 #define RLOGD(...) \
@@ -340,7 +193,7 @@
 #endif
 
 /*
- * Simplified macro to send an info radio log message using the current LOG_TAG.
+ * Simplified macro to send an info radio log message using  current LOG_TAG.
  */
 #ifndef RLOGI
 #define RLOGI(...) \
@@ -355,7 +208,7 @@
 #endif
 
 /*
- * Simplified macro to send a warning radio log message using the current LOG_TAG.
+ * Simplified macro to send a warning radio log message using current LOG_TAG.
  */
 #ifndef RLOGW
 #define RLOGW(...) \
@@ -370,7 +223,7 @@
 #endif
 
 /*
- * Simplified macro to send an error radio log message using the current LOG_TAG.
+ * Simplified macro to send an error radio log message using current LOG_TAG.
  */
 #ifndef RLOGE
 #define RLOGE(...) \
@@ -384,120 +237,44 @@
     : (void)0 )
 #endif
 
-
-// ---------------------------------------------------------------------
-
-/*
- * Log a fatal error.  If the given condition fails, this stops program
- * execution like a normal assertion, but also generating the given message.
- * It is NOT stripped from release builds.  Note that the condition test
- * is -inverted- from the normal assert() semantics.
- */
-#ifndef LOG_ALWAYS_FATAL_IF
-#define LOG_ALWAYS_FATAL_IF(cond, ...) \
-    ( (__predict_false(cond)) \
-    ? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-#ifndef LOG_ALWAYS_FATAL
-#define LOG_ALWAYS_FATAL(...) \
-    ( ((void)android_printAssert(NULL, LOG_TAG, ## __VA_ARGS__)) )
-#endif
-
-/*
- * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that
- * are stripped out of release builds.
- */
-#if LOG_NDEBUG
-
-#ifndef LOG_FATAL_IF
-#define LOG_FATAL_IF(cond, ...) ((void)0)
-#endif
-#ifndef LOG_FATAL
-#define LOG_FATAL(...) ((void)0)
-#endif
-
-#else
-
-#ifndef LOG_FATAL_IF
-#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ## __VA_ARGS__)
-#endif
-#ifndef LOG_FATAL
-#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
-#endif
-
-#endif
-
-/*
- * Assertion that generates a log message when the assertion fails.
- * Stripped out of release builds.  Uses the current LOG_TAG.
- */
-#ifndef ALOG_ASSERT
-#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__)
-//#define ALOG_ASSERT(cond) LOG_FATAL_IF(!(cond), "Assertion failed: " #cond)
-#endif
-
-// ---------------------------------------------------------------------
-
-/*
- * Basic log message macro.
- *
- * Example:
- *  ALOG(LOG_WARN, NULL, "Failed with error %d", errno);
- *
- * The second argument may be NULL or "" to indicate the "global" tag.
- */
-#ifndef ALOG
-#define ALOG(priority, tag, ...) \
-    LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
-#endif
-
-/*
- * Log macro that allows you to specify a number for the priority.
- */
-#ifndef LOG_PRI
-#define LOG_PRI(priority, tag, ...) \
-    android_printLog(priority, tag, __VA_ARGS__)
-#endif
-
-/*
- * Log macro that allows you to pass in a varargs ("args" is a va_list).
- */
-#ifndef LOG_PRI_VA
-#define LOG_PRI_VA(priority, tag, fmt, args) \
-    android_vprintLog(priority, NULL, tag, fmt, args)
-#endif
-
-/*
- * Conditional given a desired logging priority and tag.
- */
-#ifndef IF_ALOG
-#define IF_ALOG(priority, tag) \
-    if (android_testLog(ANDROID_##priority, tag))
-#endif
-
-// ---------------------------------------------------------------------
+/* --------------------------------------------------------------------- */
 
 /*
  * Event logging.
  */
 
 /*
+ * The following should not be used directly.
+ */
+
+int __android_log_bwrite(int32_t tag, const void* payload, size_t len);
+int __android_log_btwrite(int32_t tag, char type, const void* payload,
+                          size_t len);
+int __android_log_bswrite(int32_t tag, const char* payload);
+
+#define android_bWriteLog(tag, payload, len) \
+    __android_log_bwrite(tag, payload, len)
+#define android_btWriteLog(tag, type, payload, len) \
+    __android_log_btwrite(tag, type, payload, len)
+
+/*
  * Event log entry types.
  */
+#ifndef __AndroidEventLogType_defined
+#define __AndroidEventLogType_defined
 typedef enum {
     /* Special markers for android_log_list_element type */
     EVENT_TYPE_LIST_STOP = '\n', /* declare end of list  */
     EVENT_TYPE_UNKNOWN   = '?',  /* protocol error       */
 
     /* must match with declaration in java/android/android/util/EventLog.java */
-    EVENT_TYPE_INT       = 0,    /* uint32_t */
-    EVENT_TYPE_LONG      = 1,    /* uint64_t */
+    EVENT_TYPE_INT       = 0,    /* int32_t */
+    EVENT_TYPE_LONG      = 1,    /* int64_t */
     EVENT_TYPE_STRING    = 2,
     EVENT_TYPE_LIST      = 3,
     EVENT_TYPE_FLOAT     = 4,
 } AndroidEventLogType;
+#endif
 #define sizeof_AndroidEventLogType sizeof(typeof_AndroidEventLogType)
 #define typeof_AndroidEventLogType unsigned char
 
@@ -527,125 +304,480 @@
         (void) __android_log_bswrite(_tag, _value);
 #endif
 
+#ifndef log_id_t_defined
+#define log_id_t_defined
 typedef enum log_id {
     LOG_ID_MIN = 0,
 
-#ifndef LINT_RLOG
     LOG_ID_MAIN = 0,
-#endif
     LOG_ID_RADIO = 1,
-#ifndef LINT_RLOG
     LOG_ID_EVENTS = 2,
     LOG_ID_SYSTEM = 3,
     LOG_ID_CRASH = 4,
     LOG_ID_SECURITY = 5,
     LOG_ID_KERNEL = 6, /* place last, third-parties can not use it */
-#endif
 
     LOG_ID_MAX
 } log_id_t;
+#endif
 #define sizeof_log_id_t sizeof(typeof_log_id_t)
 #define typeof_log_id_t unsigned char
 
-/* For manipulating lists of events. */
-
-#define ANDROID_MAX_LIST_NEST_DEPTH 8
+/* --------------------------------------------------------------------- */
 
 /*
- * The opaque context used to manipulate lists of events.
- */
-typedef struct android_log_context_internal *android_log_context;
-
-/*
- * Elements returned when reading a list of events.
- */
-typedef struct {
-    AndroidEventLogType type;
-    uint16_t complete;
-    uint16_t len;
-    union {
-        int32_t int32;
-        int64_t int64;
-        char *string;
-        float float32;
-    } data;
-} android_log_list_element;
-
-/*
- * Creates a context associated with an event tag to write elements to
- * the list of events.
- */
-android_log_context create_android_logger(uint32_t tag);
-
-/* All lists must be braced by a begin and end call */
-/*
- * NB: If the first level braces are missing when specifying multiple
- *     elements, we will manufacturer a list to embrace it for your API
- *     convenience. For a single element, it will remain solitary.
- */
-int android_log_write_list_begin(android_log_context ctx);
-int android_log_write_list_end(android_log_context ctx);
-
-int android_log_write_int32(android_log_context ctx, int32_t value);
-int android_log_write_int64(android_log_context ctx, int64_t value);
-int android_log_write_string8(android_log_context ctx, const char *value);
-int android_log_write_string8_len(android_log_context ctx,
-                                  const char *value, size_t maxlen);
-int android_log_write_float32(android_log_context ctx, float value);
-
-/* Submit the composed list context to the specified logger id */
-/* NB: LOG_ID_EVENTS and LOG_ID_SECURITY only valid binary buffers */
-int android_log_write_list(android_log_context ctx, log_id_t id);
-
-/*
- * Creates a context from a raw buffer representing a list of events to be read.
- */
-android_log_context create_android_log_parser(const char *msg, size_t len);
-
-android_log_list_element android_log_read_next(android_log_context ctx);
-android_log_list_element android_log_peek_next(android_log_context ctx);
-
-/* Finished with reader or writer context */
-int android_log_destroy(android_log_context *ctx);
-
-/*
- * ===========================================================================
+ * Native log reading interface section. See logcat for sample code.
  *
- * The stuff in the rest of this file should not be used directly.
+ * The preferred API is an exec of logcat. Likely uses of this interface
+ * are if native code suffers from exec or filtration being too costly,
+ * access to raw information, or parsing is an issue.
  */
 
-#define android_printLog(prio, tag, fmt...) \
-    __android_log_print(prio, tag, fmt)
-
-#define android_vprintLog(prio, cond, tag, fmt...) \
-    __android_log_vprint(prio, tag, fmt)
-
-/* XXX Macros to work around syntax errors in places where format string
- * arg is not passed to ALOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF
- * (happens only in debug builds).
+/*
+ * The userspace structure for version 1 of the logger_entry ABI.
  */
+#ifndef __struct_logger_entry_defined
+#define __struct_logger_entry_defined
+struct logger_entry {
+    uint16_t    len;    /* length of the payload */
+    uint16_t    __pad;  /* no matter what, we get 2 bytes of padding */
+    int32_t     pid;    /* generating process's pid */
+    int32_t     tid;    /* generating process's tid */
+    int32_t     sec;    /* seconds since Epoch */
+    int32_t     nsec;   /* nanoseconds */
+#ifndef __cplusplus
+    char        msg[0]; /* the entry's payload */
+#endif
+};
+#endif
 
-/* Returns 2nd arg.  Used to substitute default value if caller's vararg list
- * is empty.
+/*
+ * The userspace structure for version 2 of the logger_entry ABI.
  */
-#define __android_second(dummy, second, ...)     second
+#ifndef __struct_logger_entry_v2_defined
+#define __struct_logger_entry_v2_defined
+struct logger_entry_v2 {
+    uint16_t    len;       /* length of the payload */
+    uint16_t    hdr_size;  /* sizeof(struct logger_entry_v2) */
+    int32_t     pid;       /* generating process's pid */
+    int32_t     tid;       /* generating process's tid */
+    int32_t     sec;       /* seconds since Epoch */
+    int32_t     nsec;      /* nanoseconds */
+    uint32_t    euid;      /* effective UID of logger */
+#ifndef __cplusplus
+    char        msg[0];    /* the entry's payload */
+#endif
+} __attribute__((__packed__));
+#endif
 
-/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise
- * returns nothing.
+/*
+ * The userspace structure for version 3 of the logger_entry ABI.
  */
-#define __android_rest(first, ...)               , ## __VA_ARGS__
+#ifndef __struct_logger_entry_v3_defined
+#define __struct_logger_entry_v3_defined
+struct logger_entry_v3 {
+    uint16_t    len;       /* length of the payload */
+    uint16_t    hdr_size;  /* sizeof(struct logger_entry_v3) */
+    int32_t     pid;       /* generating process's pid */
+    int32_t     tid;       /* generating process's tid */
+    int32_t     sec;       /* seconds since Epoch */
+    int32_t     nsec;      /* nanoseconds */
+    uint32_t    lid;       /* log id of the payload */
+#ifndef __cplusplus
+    char        msg[0];    /* the entry's payload */
+#endif
+} __attribute__((__packed__));
+#endif
 
-#define android_printAssert(cond, tag, fmt...) \
-    __android_log_assert(cond, tag, \
-        __android_second(0, ## fmt, NULL) __android_rest(fmt))
+/*
+ * The userspace structure for version 4 of the logger_entry ABI.
+ */
+#ifndef __struct_logger_entry_v4_defined
+#define __struct_logger_entry_v4_defined
+struct logger_entry_v4 {
+    uint16_t    len;       /* length of the payload */
+    uint16_t    hdr_size;  /* sizeof(struct logger_entry_v4) */
+    int32_t     pid;       /* generating process's pid */
+    uint32_t    tid;       /* generating process's tid */
+    uint32_t    sec;       /* seconds since Epoch */
+    uint32_t    nsec;      /* nanoseconds */
+    uint32_t    lid;       /* log id of the payload, bottom 4 bits currently */
+    uint32_t    uid;       /* generating process's uid */
+#ifndef __cplusplus
+    char        msg[0];    /* the entry's payload */
+#endif
+};
+#endif
 
-#define android_writeLog(prio, tag, text) \
-    __android_log_write(prio, tag, text)
+/* struct log_time is a wire-format variant of struct timespec */
+#define NS_PER_SEC 1000000000ULL
 
-#define android_bWriteLog(tag, payload, len) \
-    __android_log_bwrite(tag, payload, len)
-#define android_btWriteLog(tag, type, payload, len) \
-    __android_log_btwrite(tag, type, payload, len)
+#ifndef __struct_log_time_defined
+#define __struct_log_time_defined
+#ifdef __cplusplus
+
+/*
+ * NB: we did NOT define a copy constructor. This will result in structure
+ * no longer being compatible with pass-by-value which is desired
+ * efficient behavior. Also, pass-by-reference breaks C/C++ ABI.
+ */
+struct log_time {
+public:
+    uint32_t tv_sec; /* good to Feb 5 2106 */
+    uint32_t tv_nsec;
+
+    static const uint32_t tv_sec_max = 0xFFFFFFFFUL;
+    static const uint32_t tv_nsec_max = 999999999UL;
+
+    log_time(const timespec& T)
+    {
+        tv_sec = static_cast<uint32_t>(T.tv_sec);
+        tv_nsec = static_cast<uint32_t>(T.tv_nsec);
+    }
+    log_time(uint32_t sec, uint32_t nsec)
+    {
+        tv_sec = sec;
+        tv_nsec = nsec;
+    }
+#ifdef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
+#define __struct_log_time_private_defined
+    static const timespec EPOCH;
+#endif
+    log_time()
+    {
+    }
+#ifdef __linux__
+    log_time(clockid_t id)
+    {
+        timespec T;
+        clock_gettime(id, &T);
+        tv_sec = static_cast<uint32_t>(T.tv_sec);
+        tv_nsec = static_cast<uint32_t>(T.tv_nsec);
+    }
+#endif
+    log_time(const char* T)
+    {
+        const uint8_t* c = reinterpret_cast<const uint8_t*>(T);
+        tv_sec = c[0] |
+                 (static_cast<uint32_t>(c[1]) << 8) |
+                 (static_cast<uint32_t>(c[2]) << 16) |
+                 (static_cast<uint32_t>(c[3]) << 24);
+        tv_nsec = c[4] |
+                  (static_cast<uint32_t>(c[5]) << 8) |
+                  (static_cast<uint32_t>(c[6]) << 16) |
+                  (static_cast<uint32_t>(c[7]) << 24);
+    }
+
+    /* timespec */
+    bool operator== (const timespec& T) const
+    {
+        return (tv_sec == static_cast<uint32_t>(T.tv_sec))
+            && (tv_nsec == static_cast<uint32_t>(T.tv_nsec));
+    }
+    bool operator!= (const timespec& T) const
+    {
+        return !(*this == T);
+    }
+    bool operator< (const timespec& T) const
+    {
+        return (tv_sec < static_cast<uint32_t>(T.tv_sec))
+            || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
+                && (tv_nsec < static_cast<uint32_t>(T.tv_nsec)));
+    }
+    bool operator>= (const timespec& T) const
+    {
+        return !(*this < T);
+    }
+    bool operator> (const timespec& T) const
+    {
+        return (tv_sec > static_cast<uint32_t>(T.tv_sec))
+            || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
+                && (tv_nsec > static_cast<uint32_t>(T.tv_nsec)));
+    }
+    bool operator<= (const timespec& T) const
+    {
+        return !(*this > T);
+    }
+
+#ifdef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
+    log_time operator-= (const timespec& T);
+    log_time operator- (const timespec& T) const
+    {
+        log_time local(*this);
+        return local -= T;
+    }
+    log_time operator+= (const timespec& T);
+    log_time operator+ (const timespec& T) const
+    {
+        log_time local(*this);
+        return local += T;
+    }
+#endif
+
+    /* log_time */
+    bool operator== (const log_time& T) const
+    {
+        return (tv_sec == T.tv_sec) && (tv_nsec == T.tv_nsec);
+    }
+    bool operator!= (const log_time& T) const
+    {
+        return !(*this == T);
+    }
+    bool operator< (const log_time& T) const
+    {
+        return (tv_sec < T.tv_sec)
+            || ((tv_sec == T.tv_sec) && (tv_nsec < T.tv_nsec));
+    }
+    bool operator>= (const log_time& T) const
+    {
+        return !(*this < T);
+    }
+    bool operator> (const log_time& T) const
+    {
+        return (tv_sec > T.tv_sec)
+            || ((tv_sec == T.tv_sec) && (tv_nsec > T.tv_nsec));
+    }
+    bool operator<= (const log_time& T) const
+    {
+        return !(*this > T);
+    }
+
+#ifdef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
+    log_time operator-= (const log_time& T);
+    log_time operator- (const log_time& T) const
+    {
+        log_time local(*this);
+        return local -= T;
+    }
+    log_time operator+= (const log_time& T);
+    log_time operator+ (const log_time& T) const
+    {
+        log_time local(*this);
+        return local += T;
+    }
+#endif
+
+    uint64_t nsec() const
+    {
+        return static_cast<uint64_t>(tv_sec) * NS_PER_SEC + tv_nsec;
+    }
+
+#ifdef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
+    static const char default_format[];
+
+    /* Add %#q for the fraction of a second to the standard library functions */
+    char* strptime(const char* s, const char* format = default_format);
+#endif
+} __attribute__((__packed__));
+
+#else
+
+typedef struct log_time {
+    uint32_t tv_sec;
+    uint32_t tv_nsec;
+} __attribute__((__packed__)) log_time;
+
+#endif
+#endif
+
+/*
+ * The maximum size of the log entry payload that can be
+ * written to the logger. An attempt to write more than
+ * this amount will result in a truncated log entry.
+ */
+#define LOGGER_ENTRY_MAX_PAYLOAD 4068
+
+/*
+ * The maximum size of a log entry which can be read from the
+ * kernel logger driver. An attempt to read less than this amount
+ * may result in read() returning EINVAL.
+ */
+#define LOGGER_ENTRY_MAX_LEN    (5*1024)
+
+#ifndef __struct_log_msg_defined
+#define __struct_log_msg_defined
+struct log_msg {
+    union {
+        unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
+        struct logger_entry_v4 entry;
+        struct logger_entry_v4 entry_v4;
+        struct logger_entry_v3 entry_v3;
+        struct logger_entry_v2 entry_v2;
+        struct logger_entry    entry_v1;
+    } __attribute__((aligned(4)));
+#ifdef __cplusplus
+    /* Matching log_time operators */
+    bool operator== (const log_msg& T) const
+    {
+        return (entry.sec == T.entry.sec) && (entry.nsec == T.entry.nsec);
+    }
+    bool operator!= (const log_msg& T) const
+    {
+        return !(*this == T);
+    }
+    bool operator< (const log_msg& T) const
+    {
+        return (entry.sec < T.entry.sec)
+            || ((entry.sec == T.entry.sec)
+             && (entry.nsec < T.entry.nsec));
+    }
+    bool operator>= (const log_msg& T) const
+    {
+        return !(*this < T);
+    }
+    bool operator> (const log_msg& T) const
+    {
+        return (entry.sec > T.entry.sec)
+            || ((entry.sec == T.entry.sec)
+             && (entry.nsec > T.entry.nsec));
+    }
+    bool operator<= (const log_msg& T) const
+    {
+        return !(*this > T);
+    }
+    uint64_t nsec() const
+    {
+        return static_cast<uint64_t>(entry.sec) * NS_PER_SEC + entry.nsec;
+    }
+
+    /* packet methods */
+    log_id_t id()
+    {
+        return static_cast<log_id_t>(entry.lid);
+    }
+    char* msg()
+    {
+        unsigned short hdr_size = entry.hdr_size;
+        if (!hdr_size) {
+            hdr_size = sizeof(entry_v1);
+        }
+        if ((hdr_size < sizeof(entry_v1)) || (hdr_size > sizeof(entry))) {
+            return NULL;
+        }
+        return reinterpret_cast<char*>(buf) + hdr_size;
+    }
+    unsigned int len()
+    {
+        return (entry.hdr_size ?
+                    entry.hdr_size :
+                    static_cast<uint16_t>(sizeof(entry_v1))) +
+               entry.len;
+    }
+#endif
+};
+#endif
+
+#ifndef __ANDROID_USE_LIBLOG_READER_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_READER_INTERFACE 3
+#elif __ANDROID_API__ > 23 /* > Marshmallow */
+#define __ANDROID_USE_LIBLOG_READER_INTERFACE 3
+#elif __ANDROID_API__ > 22 /* > Lollipop */
+#define __ANDROID_USE_LIBLOG_READER_INTERFACE 2
+#elif __ANDROID_API__ > 19 /* > KitKat */
+#define __ANDROID_USE_LIBLOG_READER_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_READER_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_READER_INTERFACE
+
+struct logger;
+
+log_id_t android_logger_get_id(struct logger* logger);
+
+int android_logger_clear(struct logger* logger);
+long android_logger_get_log_size(struct logger* logger);
+int android_logger_set_log_size(struct logger* logger, unsigned long size);
+long android_logger_get_log_readable_size(struct logger* logger);
+int android_logger_get_log_version(struct logger* logger);
+
+struct logger_list;
+
+#if __ANDROID_USE_LIBLOG_READER_INTERFACE > 1
+ssize_t android_logger_get_statistics(struct logger_list* logger_list,
+                                      char* buf, size_t len);
+ssize_t android_logger_get_prune_list(struct logger_list* logger_list,
+                                      char* buf, size_t len);
+int android_logger_set_prune_list(struct logger_list* logger_list,
+                                  char* buf, size_t len);
+#endif
+
+#define ANDROID_LOG_RDONLY   O_RDONLY
+#define ANDROID_LOG_WRONLY   O_WRONLY
+#define ANDROID_LOG_RDWR     O_RDWR
+#define ANDROID_LOG_ACCMODE  O_ACCMODE
+#define ANDROID_LOG_NONBLOCK O_NONBLOCK
+#if __ANDROID_USE_LIBLOG_READER_INTERFACE > 2
+#define ANDROID_LOG_WRAP     0x40000000 /* Block until buffer about to wrap */
+#define ANDROID_LOG_WRAP_DEFAULT_TIMEOUT 7200 /* 2 hour default */
+#endif
+#if __ANDROID_USE_LIBLOG_READER_INTERFACE > 1
+#define ANDROID_LOG_PSTORE   0x80000000
+#endif
+
+struct logger_list* android_logger_list_alloc(int mode,
+                                              unsigned int tail,
+                                              pid_t pid);
+struct logger_list* android_logger_list_alloc_time(int mode,
+                                                   log_time start,
+                                                   pid_t pid);
+void android_logger_list_free(struct logger_list* logger_list);
+/* In the purest sense, the following two are orthogonal interfaces */
+int android_logger_list_read(struct logger_list* logger_list,
+                             struct log_msg* log_msg);
+
+/* Multiple log_id_t opens */
+struct logger* android_logger_open(struct logger_list* logger_list,
+                                   log_id_t id);
+#define android_logger_close android_logger_free
+/* Single log_id_t open */
+struct logger_list* android_logger_list_open(log_id_t id,
+                                             int mode,
+                                             unsigned int tail,
+                                             pid_t pid);
+#define android_logger_list_close android_logger_list_free
+
+#endif /* __ANDROID_USE_LIBLOG_READER_INTERFACE */
+
+#ifdef __linux__
+
+#ifndef __ANDROID_USE_LIBLOG_CLOCK_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_CLOCK_INTERFACE 1
+#elif __ANDROID_API__ > 22 /* > Lollipop */
+#define __ANDROID_USE_LIBLOG_CLOCK_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_CLOCK_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_CLOCK_INTERFACE
+clockid_t android_log_clockid();
+#endif
+
+#endif /* __linux__ */
+
+/*
+ * log_id_t helpers
+ */
+log_id_t android_name_to_log_id(const char* logName);
+const char* android_log_id_to_name(log_id_t log_id);
+
+/* --------------------------------------------------------------------- */
+
+#ifndef _ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE 1
+#elif __ANDROID_API__ > 22 /* > Lollipop */
+#define __ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE
 
 #define android_errorWriteLog(tag, subTag) \
     __android_log_error_write(tag, subTag, -1, NULL, 0)
@@ -653,44 +785,36 @@
 #define android_errorWriteWithInfoLog(tag, subTag, uid, data, dataLen) \
     __android_log_error_write(tag, subTag, uid, data, dataLen)
 
-/*
- *    IF_ALOG uses android_testLog, but IF_ALOG can be overridden.
- *    android_testLog will remain constant in its purpose as a wrapper
- *        for Android logging filter policy, and can be subject to
- *        change. It can be reused by the developers that override
- *        IF_ALOG as a convenient means to reimplement their policy
- *        over Android.
- */
-#if LOG_NDEBUG /* Production */
-#define android_testLog(prio, tag) \
-    (__android_log_is_loggable(prio, tag, ANDROID_LOG_DEBUG) != 0)
+int __android_log_error_write(int tag, const char* subTag, int32_t uid,
+                              const char* data, uint32_t dataLen);
+
+#endif /* __ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE */
+
+/* --------------------------------------------------------------------- */
+
+#ifndef __ANDROID_USE_LIBLOG_CLOSE_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_CLOSE_INTERFACE 1
+#elif __ANDROID_API__ > 18 /* > JellyBean */
+#define __ANDROID_USE_LIBLOG_CLOSE_INTERFACE 1
 #else
-#define android_testLog(prio, tag) \
-    (__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE) != 0)
+#define __ANDROID_USE_LIBLOG_CLOSE_INTERFACE 0
+#endif
 #endif
 
+#if __ANDROID_USE_LIBLOG_CLOSE_INTERFACE
 /*
- * Use the per-tag properties "log.tag.<tagname>" to generate a runtime
- * result of non-zero to expose a log. prio is ANDROID_LOG_VERBOSE to
- * ANDROID_LOG_FATAL. default_prio if no property. Undefined behavior if
- * any other value.
+ * Release any logger resources (a new log write will immediately re-acquire)
+ *
+ * May be used to clean up File descriptors after a Fork, the resources are
+ * all O_CLOEXEC so wil self clean on exec().
  */
-int __android_log_is_loggable(int prio, const char *tag, int default_prio);
-
-int __android_log_security(); /* Device Owner is present */
-
-int __android_log_error_write(int tag, const char *subTag, int32_t uid, const char *data,
-                              uint32_t dataLen);
-
-/*
- * Send a simple string to the log.
- */
-int __android_log_buf_write(int bufID, int prio, const char *tag, const char *text);
-int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...)
-#if defined(__GNUC__)
-    __attribute__((__format__(printf, 4, 5)))
+void __android_log_close();
 #endif
-    ;
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
 
 #ifdef __cplusplus
 }
diff --git a/include/log/log_event_list.h b/include/log/log_event_list.h
new file mode 100644
index 0000000..31d49b2
--- /dev/null
+++ b/include/log/log_event_list.h
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2005-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.
+ */
+
+#ifndef _LIBS_LOG_EVENT_LIST_H
+#define _LIBS_LOG_EVENT_LIST_H
+
+#include <stdint.h>
+
+#if (defined(__cplusplus) && defined(_USING_LIBCXX))
+extern "C++" {
+#include <string>
+}
+#endif
+
+#include <log/log.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef __ANDROID_USE_LIBLOG_EVENT_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 1
+#elif __ANDROID_API__ > 23 /* > Marshmallow */
+#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_EVENT_INTERFACE
+
+/* For manipulating lists of events. */
+
+#define ANDROID_MAX_LIST_NEST_DEPTH 8
+
+/*
+ * The opaque context used to manipulate lists of events.
+ */
+#ifndef __android_log_context_defined
+#define __android_log_context_defined
+typedef struct android_log_context_internal* android_log_context;
+#endif
+
+/*
+ * Elements returned when reading a list of events.
+ */
+#ifndef __android_log_list_element_defined
+#define __android_log_list_element_defined
+typedef struct {
+    AndroidEventLogType type;
+    uint16_t complete;
+    uint16_t len;
+    union {
+        int32_t int32;
+        int64_t int64;
+        char* string;
+        float float32;
+    } data;
+} android_log_list_element;
+#endif
+
+/*
+ * Creates a context associated with an event tag to write elements to
+ * the list of events.
+ */
+android_log_context create_android_logger(uint32_t tag);
+
+/* All lists must be braced by a begin and end call */
+/*
+ * NB: If the first level braces are missing when specifying multiple
+ *     elements, we will manufacturer a list to embrace it for your API
+ *     convenience. For a single element, it will remain solitary.
+ */
+int android_log_write_list_begin(android_log_context ctx);
+int android_log_write_list_end(android_log_context ctx);
+
+int android_log_write_int32(android_log_context ctx, int32_t value);
+int android_log_write_int64(android_log_context ctx, int64_t value);
+int android_log_write_string8(android_log_context ctx, const char* value);
+int android_log_write_string8_len(android_log_context ctx,
+                                  const char* value, size_t maxlen);
+int android_log_write_float32(android_log_context ctx, float value);
+
+/* Submit the composed list context to the specified logger id */
+/* NB: LOG_ID_EVENTS and LOG_ID_SECURITY only valid binary buffers */
+int android_log_write_list(android_log_context ctx, log_id_t id);
+
+/*
+ * Creates a context from a raw buffer representing a list of events to be read.
+ */
+android_log_context create_android_log_parser(const char* msg, size_t len);
+
+android_log_list_element android_log_read_next(android_log_context ctx);
+android_log_list_element android_log_peek_next(android_log_context ctx);
+
+/* Finished with reader or writer context */
+int android_log_destroy(android_log_context* ctx);
+
+#ifdef __cplusplus
+#ifndef __class_android_log_event_list_defined
+#define __class_android_log_event_list_defined
+/* android_log_list C++ helpers */
+extern "C++" {
+class android_log_event_list {
+friend class __android_log_event_list;
+
+private:
+    android_log_context ctx;
+    int ret;
+
+    android_log_event_list(const android_log_event_list&) = delete;
+    void operator =(const android_log_event_list&) = delete;
+
+public:
+    explicit android_log_event_list(int tag) : ret(0) {
+        ctx = create_android_logger(static_cast<uint32_t>(tag));
+    }
+    explicit android_log_event_list(log_msg& log_msg) : ret(0) {
+        ctx = create_android_log_parser(log_msg.msg() + sizeof(uint32_t),
+                                        log_msg.entry.len - sizeof(uint32_t));
+    }
+    ~android_log_event_list() { android_log_destroy(&ctx); }
+
+    int close() {
+        int retval = android_log_destroy(&ctx);
+        if (retval < 0) ret = retval;
+        return retval;
+    }
+
+    /* To allow above C calls to use this class as parameter */
+    operator android_log_context() const { return ctx; }
+
+    int status() const { return ret; }
+
+    int begin() {
+        int retval = android_log_write_list_begin(ctx);
+        if (retval < 0) ret = retval;
+        return ret;
+    }
+    int end() {
+        int retval = android_log_write_list_end(ctx);
+        if (retval < 0) ret = retval;
+        return ret;
+    }
+
+    android_log_event_list& operator <<(int32_t value) {
+        int retval = android_log_write_int32(ctx, value);
+        if (retval < 0) ret = retval;
+        return *this;
+    }
+
+    android_log_event_list& operator <<(uint32_t value) {
+        int retval = android_log_write_int32(ctx, static_cast<int32_t>(value));
+        if (retval < 0) ret = retval;
+        return *this;
+    }
+
+    android_log_event_list& operator <<(int64_t value) {
+        int retval = android_log_write_int64(ctx, value);
+        if (retval < 0) ret = retval;
+        return *this;
+    }
+
+    android_log_event_list& operator <<(uint64_t value) {
+        int retval = android_log_write_int64(ctx, static_cast<int64_t>(value));
+        if (retval < 0) ret = retval;
+        return *this;
+    }
+
+    android_log_event_list& operator <<(const char* value) {
+        int retval = android_log_write_string8(ctx, value);
+        if (retval < 0) ret = retval;
+        return *this;
+    }
+
+#if defined(_USING_LIBCXX)
+    android_log_event_list& operator <<(const std::string& value) {
+        int retval = android_log_write_string8_len(ctx,
+                                                   value.data(),
+                                                   value.length());
+        if (retval < 0) ret = retval;
+        return *this;
+    }
+#endif
+
+    android_log_event_list& operator <<(float value) {
+        int retval = android_log_write_float32(ctx, value);
+        if (retval < 0) ret = retval;
+        return *this;
+    }
+
+    int write(log_id_t id = LOG_ID_EVENTS) {
+        int retval = android_log_write_list(ctx, id);
+        if (retval < 0) ret = retval;
+        return ret;
+    }
+
+    int operator <<(log_id_t id) {
+        int retval = android_log_write_list(ctx, id);
+        if (retval < 0) ret = retval;
+        android_log_destroy(&ctx);
+        return ret;
+    }
+
+    /*
+     * Append<Type> methods removes any integer promotion
+     * confusion, and adds access to string with length.
+     * Append methods are also added for all types for
+     * convenience.
+     */
+
+    bool AppendInt(int32_t value) {
+        int retval = android_log_write_int32(ctx, value);
+        if (retval < 0) ret = retval;
+        return ret >= 0;
+    }
+
+    bool AppendLong(int64_t value) {
+        int retval = android_log_write_int64(ctx, value);
+        if (retval < 0) ret = retval;
+        return ret >= 0;
+    }
+
+    bool AppendString(const char* value) {
+        int retval = android_log_write_string8(ctx, value);
+        if (retval < 0) ret = retval;
+        return ret >= 0;
+    }
+
+    bool AppendString(const char* value, size_t len) {
+        int retval = android_log_write_string8_len(ctx, value, len);
+        if (retval < 0) ret = retval;
+        return ret >= 0;
+    }
+
+#if defined(_USING_LIBCXX)
+    bool AppendString(const std::string& value) {
+        int retval = android_log_write_string8_len(ctx,
+                                                   value.data(),
+                                                   value.length());
+        if (retval < 0) ret = retval;
+        return ret;
+    }
+
+    bool Append(const std::string& value) {
+        int retval = android_log_write_string8_len(ctx,
+                                                   value.data(),
+                                                   value.length());
+        if (retval < 0) ret = retval;
+        return ret;
+    }
+#endif
+
+    bool AppendFloat(float value) {
+        int retval = android_log_write_float32(ctx, value);
+        if (retval < 0) ret = retval;
+        return ret >= 0;
+    }
+
+    template <typename Tvalue>
+    bool Append(Tvalue value) { *this << value; return ret >= 0; }
+
+    bool Append(const char* value, size_t len) {
+        int retval = android_log_write_string8_len(ctx, value, len);
+        if (retval < 0) ret = retval;
+        return ret >= 0;
+    }
+
+    android_log_list_element read() { return android_log_read_next(ctx); }
+    android_log_list_element peek() { return android_log_peek_next(ctx); }
+
+};
+}
+#endif
+#endif
+
+#endif /* __ANDROID_USE_LIBLOG_EVENT_INTERFACE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBS_LOG_EVENT_LIST_H */
diff --git a/include/log/log_read.h b/include/log/log_read.h
deleted file mode 100644
index 1b70aff..0000000
--- a/include/log/log_read.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2013-2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBS_LOG_LOG_READ_H
-#define _LIBS_LOG_LOG_READ_H
-
-#include <stdint.h>
-#include <time.h>
-
-/* struct log_time is a wire-format variant of struct timespec */
-#define NS_PER_SEC 1000000000ULL
-
-#ifdef __cplusplus
-
-// NB: do NOT define a copy constructor. This will result in structure
-// no longer being compatible with pass-by-value which is desired
-// efficient behavior. Also, pass-by-reference breaks C/C++ ABI.
-struct log_time {
-public:
-    uint32_t tv_sec; // good to Feb 5 2106
-    uint32_t tv_nsec;
-
-    static const uint32_t tv_sec_max = 0xFFFFFFFFUL;
-    static const uint32_t tv_nsec_max = 999999999UL;
-
-    log_time(const timespec &T)
-    {
-        tv_sec = T.tv_sec;
-        tv_nsec = T.tv_nsec;
-    }
-    log_time(uint32_t sec, uint32_t nsec)
-    {
-        tv_sec = sec;
-        tv_nsec = nsec;
-    }
-    static const timespec EPOCH;
-    log_time()
-    {
-    }
-    log_time(clockid_t id)
-    {
-        timespec T;
-        clock_gettime(id, &T);
-        tv_sec = T.tv_sec;
-        tv_nsec = T.tv_nsec;
-    }
-    log_time(const char *T)
-    {
-        const uint8_t *c = (const uint8_t *) T;
-        tv_sec = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
-        tv_nsec = c[4] | (c[5] << 8) | (c[6] << 16) | (c[7] << 24);
-    }
-
-    // timespec
-    bool operator== (const timespec &T) const
-    {
-        return (tv_sec == static_cast<uint32_t>(T.tv_sec))
-            && (tv_nsec == static_cast<uint32_t>(T.tv_nsec));
-    }
-    bool operator!= (const timespec &T) const
-    {
-        return !(*this == T);
-    }
-    bool operator< (const timespec &T) const
-    {
-        return (tv_sec < static_cast<uint32_t>(T.tv_sec))
-            || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
-                && (tv_nsec < static_cast<uint32_t>(T.tv_nsec)));
-    }
-    bool operator>= (const timespec &T) const
-    {
-        return !(*this < T);
-    }
-    bool operator> (const timespec &T) const
-    {
-        return (tv_sec > static_cast<uint32_t>(T.tv_sec))
-            || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
-                && (tv_nsec > static_cast<uint32_t>(T.tv_nsec)));
-    }
-    bool operator<= (const timespec &T) const
-    {
-        return !(*this > T);
-    }
-    log_time operator-= (const timespec &T);
-    log_time operator- (const timespec &T) const
-    {
-        log_time local(*this);
-        return local -= T;
-    }
-    log_time operator+= (const timespec &T);
-    log_time operator+ (const timespec &T) const
-    {
-        log_time local(*this);
-        return local += T;
-    }
-
-    // log_time
-    bool operator== (const log_time &T) const
-    {
-        return (tv_sec == T.tv_sec) && (tv_nsec == T.tv_nsec);
-    }
-    bool operator!= (const log_time &T) const
-    {
-        return !(*this == T);
-    }
-    bool operator< (const log_time &T) const
-    {
-        return (tv_sec < T.tv_sec)
-            || ((tv_sec == T.tv_sec) && (tv_nsec < T.tv_nsec));
-    }
-    bool operator>= (const log_time &T) const
-    {
-        return !(*this < T);
-    }
-    bool operator> (const log_time &T) const
-    {
-        return (tv_sec > T.tv_sec)
-            || ((tv_sec == T.tv_sec) && (tv_nsec > T.tv_nsec));
-    }
-    bool operator<= (const log_time &T) const
-    {
-        return !(*this > T);
-    }
-    log_time operator-= (const log_time &T);
-    log_time operator- (const log_time &T) const
-    {
-        log_time local(*this);
-        return local -= T;
-    }
-    log_time operator+= (const log_time &T);
-    log_time operator+ (const log_time &T) const
-    {
-        log_time local(*this);
-        return local += T;
-    }
-
-    uint64_t nsec() const
-    {
-        return static_cast<uint64_t>(tv_sec) * NS_PER_SEC + tv_nsec;
-    }
-
-    static const char default_format[];
-
-    // Add %#q for the fraction of a second to the standard library functions
-    char *strptime(const char *s, const char *format = default_format);
-} __attribute__((__packed__));
-
-#else
-
-typedef struct log_time {
-    uint32_t tv_sec;
-    uint32_t tv_nsec;
-} __attribute__((__packed__)) log_time;
-
-#endif
-
-#endif /* define _LIBS_LOG_LOG_READ_H */
diff --git a/include/log/logd.h b/include/log/logd.h
index b271602..0e0248e 100644
--- a/include/log/logd.h
+++ b/include/log/logd.h
@@ -1,54 +1 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _ANDROID_CUTILS_LOGD_H
-#define _ANDROID_CUTILS_LOGD_H
-
-/* the stable/frozen log-related definitions have been
- * moved to this header, which is exposed by the NDK
- */
-#include <android/log.h>
-
-/* the rest is only used internally by the system */
-#if !defined(_WIN32)
-#include <pthread.h>
-#endif
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <log/uio.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int __android_log_bwrite(int32_t tag, const void *payload, size_t len);
-int __android_log_btwrite(int32_t tag, char type, const void *payload,
-    size_t len);
-int __android_log_bswrite(int32_t tag, const char *payload);
-
-int __android_log_security_bwrite(int32_t tag, const void *payload, size_t len);
-int __android_log_security_bswrite(int32_t tag, const char *payload);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _LOGD_H */
+#include <log/log.h>
diff --git a/include/log/logger.h b/include/log/logger.h
index 60d47a2..0e0248e 100644
--- a/include/log/logger.h
+++ b/include/log/logger.h
@@ -1,219 +1 @@
-/*
-**
-** Copyright 2007-2014, The Android Open Source Project
-**
-** This file is dual licensed.  It may be redistributed and/or modified
-** under the terms of the Apache 2.0 License OR version 2 of the GNU
-** General Public License.
-*/
-
-#ifndef _LIBS_LOG_LOGGER_H
-#define _LIBS_LOG_LOGGER_H
-
-#include <stdint.h>
-#ifdef __linux__
-#include <time.h> /* clockid_t definition */
-#endif
-
 #include <log/log.h>
-#include <log/log_read.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * The userspace structure for version 1 of the logger_entry ABI.
- * This structure is returned to userspace by the kernel logger
- * driver unless an upgrade to a newer ABI version is requested.
- */
-struct logger_entry {
-    uint16_t    len;    /* length of the payload */
-    uint16_t    __pad;  /* no matter what, we get 2 bytes of padding */
-    int32_t     pid;    /* generating process's pid */
-    int32_t     tid;    /* generating process's tid */
-    int32_t     sec;    /* seconds since Epoch */
-    int32_t     nsec;   /* nanoseconds */
-    char        msg[0]; /* the entry's payload */
-} __attribute__((__packed__));
-
-/*
- * The userspace structure for version 2 of the logger_entry ABI.
- * This structure is returned to userspace if ioctl(LOGGER_SET_VERSION)
- * is called with version==2; or used with the user space log daemon.
- */
-struct logger_entry_v2 {
-    uint16_t    len;       /* length of the payload */
-    uint16_t    hdr_size;  /* sizeof(struct logger_entry_v2) */
-    int32_t     pid;       /* generating process's pid */
-    int32_t     tid;       /* generating process's tid */
-    int32_t     sec;       /* seconds since Epoch */
-    int32_t     nsec;      /* nanoseconds */
-    uint32_t    euid;      /* effective UID of logger */
-    char        msg[0];    /* the entry's payload */
-} __attribute__((__packed__));
-
-struct logger_entry_v3 {
-    uint16_t    len;       /* length of the payload */
-    uint16_t    hdr_size;  /* sizeof(struct logger_entry_v3) */
-    int32_t     pid;       /* generating process's pid */
-    int32_t     tid;       /* generating process's tid */
-    int32_t     sec;       /* seconds since Epoch */
-    int32_t     nsec;      /* nanoseconds */
-    uint32_t    lid;       /* log id of the payload */
-    char        msg[0];    /* the entry's payload */
-} __attribute__((__packed__));
-
-struct logger_entry_v4 {
-    uint16_t    len;       /* length of the payload */
-    uint16_t    hdr_size;  /* sizeof(struct logger_entry_v4) */
-    int32_t     pid;       /* generating process's pid */
-    uint32_t    tid;       /* generating process's tid */
-    uint32_t    sec;       /* seconds since Epoch */
-    uint32_t    nsec;      /* nanoseconds */
-    uint32_t    lid;       /* log id of the payload, bottom 4 bits currently */
-    uint32_t    uid;       /* generating process's uid */
-    char        msg[0];    /* the entry's payload */
-} __attribute__((__packed__));
-
-/*
- * The maximum size of the log entry payload that can be
- * written to the logger. An attempt to write more than
- * this amount will result in a truncated log entry.
- */
-#define LOGGER_ENTRY_MAX_PAYLOAD	4068
-
-/*
- * The maximum size of a log entry which can be read from the
- * kernel logger driver. An attempt to read less than this amount
- * may result in read() returning EINVAL.
- */
-#define LOGGER_ENTRY_MAX_LEN		(5*1024)
-
-#define NS_PER_SEC 1000000000ULL
-
-struct log_msg {
-    union {
-        unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
-        struct logger_entry_v4 entry;
-        struct logger_entry_v4 entry_v4;
-        struct logger_entry_v3 entry_v3;
-        struct logger_entry_v2 entry_v2;
-        struct logger_entry    entry_v1;
-    } __attribute__((aligned(4)));
-#ifdef __cplusplus
-    /* Matching log_time operators */
-    bool operator== (const log_msg &T) const
-    {
-        return (entry.sec == T.entry.sec) && (entry.nsec == T.entry.nsec);
-    }
-    bool operator!= (const log_msg &T) const
-    {
-        return !(*this == T);
-    }
-    bool operator< (const log_msg &T) const
-    {
-        return (entry.sec < T.entry.sec)
-            || ((entry.sec == T.entry.sec)
-             && (entry.nsec < T.entry.nsec));
-    }
-    bool operator>= (const log_msg &T) const
-    {
-        return !(*this < T);
-    }
-    bool operator> (const log_msg &T) const
-    {
-        return (entry.sec > T.entry.sec)
-            || ((entry.sec == T.entry.sec)
-             && (entry.nsec > T.entry.nsec));
-    }
-    bool operator<= (const log_msg &T) const
-    {
-        return !(*this > T);
-    }
-    uint64_t nsec() const
-    {
-        return static_cast<uint64_t>(entry.sec) * NS_PER_SEC + entry.nsec;
-    }
-
-    /* packet methods */
-    log_id_t id()
-    {
-        return (log_id_t) entry.lid;
-    }
-    char *msg()
-    {
-        return entry.hdr_size ? (char *) buf + entry.hdr_size : entry_v1.msg;
-    }
-    unsigned int len()
-    {
-        return (entry.hdr_size ? entry.hdr_size : sizeof(entry_v1)) + entry.len;
-    }
-#endif
-};
-
-struct logger;
-
-log_id_t android_logger_get_id(struct logger *logger);
-
-int android_logger_clear(struct logger *logger);
-long android_logger_get_log_size(struct logger *logger);
-int android_logger_set_log_size(struct logger *logger, unsigned long size);
-long android_logger_get_log_readable_size(struct logger *logger);
-int android_logger_get_log_version(struct logger *logger);
-
-struct logger_list;
-
-ssize_t android_logger_get_statistics(struct logger_list *logger_list,
-                                      char *buf, size_t len);
-ssize_t android_logger_get_prune_list(struct logger_list *logger_list,
-                                      char *buf, size_t len);
-int android_logger_set_prune_list(struct logger_list *logger_list,
-                                  char *buf, size_t len);
-
-#define ANDROID_LOG_RDONLY   O_RDONLY
-#define ANDROID_LOG_WRONLY   O_WRONLY
-#define ANDROID_LOG_RDWR     O_RDWR
-#define ANDROID_LOG_ACCMODE  O_ACCMODE
-#define ANDROID_LOG_NONBLOCK O_NONBLOCK
-#define ANDROID_LOG_WRAP     0x40000000 /* Block until buffer about to wrap */
-#define ANDROID_LOG_WRAP_DEFAULT_TIMEOUT 7200 /* 2 hour default */
-#define ANDROID_LOG_PSTORE   0x80000000
-
-struct logger_list *android_logger_list_alloc(int mode,
-                                              unsigned int tail,
-                                              pid_t pid);
-struct logger_list *android_logger_list_alloc_time(int mode,
-                                                   log_time start,
-                                                   pid_t pid);
-void android_logger_list_free(struct logger_list *logger_list);
-/* In the purest sense, the following two are orthogonal interfaces */
-int android_logger_list_read(struct logger_list *logger_list,
-                             struct log_msg *log_msg);
-
-/* Multiple log_id_t opens */
-struct logger *android_logger_open(struct logger_list *logger_list,
-                                   log_id_t id);
-#define android_logger_close android_logger_free
-/* Single log_id_t open */
-struct logger_list *android_logger_list_open(log_id_t id,
-                                             int mode,
-                                             unsigned int tail,
-                                             pid_t pid);
-#define android_logger_list_close android_logger_list_free
-
-#ifdef __linux__
-clockid_t android_log_clockid();
-#endif
-
-/*
- * log_id_t helpers
- */
-log_id_t android_name_to_log_id(const char *logName);
-const char *android_log_id_to_name(log_id_t log_id);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _LIBS_LOG_LOGGER_H */
diff --git a/include/log/logprint.h b/include/log/logprint.h
index 539d1dc..3509e7f 100644
--- a/include/log/logprint.h
+++ b/include/log/logprint.h
@@ -17,16 +17,17 @@
 #ifndef _LOGPRINT_H
 #define _LOGPRINT_H
 
-#include <log/log.h>
-#include <log/logger.h>
-#include <log/event_tag_map.h>
 #include <pthread.h>
 
+#include <android/log.h>
+#include <log/event_tag_map.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 typedef enum {
+    /* Verbs */
     FORMAT_OFF = 0,
     FORMAT_BRIEF,
     FORMAT_PROCESS,
@@ -36,7 +37,7 @@
     FORMAT_TIME,
     FORMAT_THREADTIME,
     FORMAT_LONG,
-    /* The following are modifiers to above formats */
+    /* Adverbs. The following are modifiers to above format verbs */
     FORMAT_MODIFIER_COLOR,     /* converts priority to color */
     FORMAT_MODIFIER_TIME_USEC, /* switches from msec to usec time precision */
     FORMAT_MODIFIER_PRINTABLE, /* converts non-printable to printable escapes */
@@ -45,6 +46,7 @@
     FORMAT_MODIFIER_EPOCH,     /* Print time as seconds since Jan 1 1970 */
     FORMAT_MODIFIER_MONOTONIC, /* Print cpu time as seconds since start */
     FORMAT_MODIFIER_UID,       /* Adds uid */
+    FORMAT_MODIFIER_DESCRIPT,  /* Adds descriptive */
 } AndroidLogPrintFormat;
 
 typedef struct AndroidLogFormat_t AndroidLogFormat;
@@ -56,23 +58,24 @@
     int32_t uid;
     int32_t pid;
     int32_t tid;
-    const char * tag;
+    const char* tag;
+    size_t tagLen;
     size_t messageLen;
-    const char * message;
+    const char* message;
 } AndroidLogEntry;
 
-AndroidLogFormat *android_log_format_new();
+AndroidLogFormat* android_log_format_new();
 
-void android_log_format_free(AndroidLogFormat *p_format);
+void android_log_format_free(AndroidLogFormat* p_format);
 
 /* currently returns 0 if format is a modifier, 1 if not */
-int android_log_setPrintFormat(AndroidLogFormat *p_format,
+int android_log_setPrintFormat(AndroidLogFormat* p_format,
         AndroidLogPrintFormat format);
 
 /**
  * Returns FORMAT_OFF on invalid string
  */
-AndroidLogPrintFormat android_log_formatFromString(const char *s);
+AndroidLogPrintFormat android_log_formatFromString(const char* s);
 
 /**
  * filterExpression: a single filter expression
@@ -84,9 +87,8 @@
  *
  */
 
-int android_log_addFilterRule(AndroidLogFormat *p_format,
-        const char *filterExpression);
-
+int android_log_addFilterRule(AndroidLogFormat* p_format,
+        const char* filterExpression);
 
 /**
  * filterString: a whitespace-separated set of filter expressions
@@ -98,17 +100,15 @@
  *
  */
 
-int android_log_addFilterString(AndroidLogFormat *p_format,
-        const char *filterString);
-
+int android_log_addFilterString(AndroidLogFormat* p_format,
+        const char* filterString);
 
 /**
  * returns 1 if this log line should be printed based on its priority
  * and tag, and 0 if it should not
  */
 int android_log_shouldPrintLine (
-        AndroidLogFormat *p_format, const char *tag, android_LogPriority pri);
-
+        AndroidLogFormat* p_format, const char* tag, android_LogPriority pri);
 
 /**
  * Splits a wire-format buffer into an AndroidLogEntry
@@ -117,8 +117,8 @@
  * Returns 0 on success and -1 on invalid wire format (entry will be
  * in unspecified state)
  */
-int android_log_processLogBuffer(struct logger_entry *buf,
-                                 AndroidLogEntry *entry);
+int android_log_processLogBuffer(struct logger_entry* buf,
+                                 AndroidLogEntry* entry);
 
 /**
  * Like android_log_processLogBuffer, but for binary logs.
@@ -126,11 +126,10 @@
  * If "map" is non-NULL, it will be used to convert the log tag number
  * into a string.
  */
-int android_log_processBinaryLogBuffer(struct logger_entry *buf,
-    AndroidLogEntry *entry, const EventTagMap* map, char* messageBuf,
+int android_log_processBinaryLogBuffer(struct logger_entry* buf,
+    AndroidLogEntry* entry, const EventTagMap* map, char* messageBuf,
     int messageBufLen);
 
-
 /**
  * Formats a log message into a buffer
  *
@@ -139,13 +138,12 @@
  * Returns NULL on malloc error
  */
 
-char *android_log_formatLogLine (
-    AndroidLogFormat *p_format,
-    char *defaultBuffer,
+char* android_log_formatLogLine (
+    AndroidLogFormat* p_format,
+    char* defaultBuffer,
     size_t defaultBufferSize,
-    const AndroidLogEntry *p_line,
-    size_t *p_outLength);
-
+    const AndroidLogEntry* p_line,
+    size_t* p_outLength);
 
 /**
  * Either print or do not print log line, based on filter
@@ -154,14 +152,12 @@
  *
  */
 int android_log_printLogLine(
-    AndroidLogFormat *p_format,
+    AndroidLogFormat* p_format,
     int fd,
-    const AndroidLogEntry *entry);
-
+    const AndroidLogEntry* entry);
 
 #ifdef __cplusplus
 }
 #endif
 
-
 #endif /*_LOGPRINT_H*/
diff --git a/include/mincrypt/dsa_sig.h b/include/mincrypt/dsa_sig.h
deleted file mode 100644
index b0d91cd..0000000
--- a/include/mincrypt/dsa_sig.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * 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.
- *     * Neither the name of Google Inc. nor the names of its contributors may
- *       be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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 SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_
-#define SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_
-
-#include "mincrypt/p256.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Returns 0 if input sig is not a valid ASN.1 sequence
-int dsa_sig_unpack(unsigned char* sig, int sig_len, p256_int* r_int, p256_int* s_int);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_ */
diff --git a/include/mincrypt/hash-internal.h b/include/mincrypt/hash-internal.h
deleted file mode 100644
index c813b44..0000000
--- a/include/mincrypt/hash-internal.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * 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.
- *     * Neither the name of Google Inc. nor the names of its contributors may
- *       be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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 SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
-#define SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif  // __cplusplus
-
-struct HASH_CTX;  // forward decl
-
-typedef struct HASH_VTAB {
-  void (* const init)(struct HASH_CTX*);
-  void (* const update)(struct HASH_CTX*, const void*, int);
-  const uint8_t* (* const final)(struct HASH_CTX*);
-  const uint8_t* (* const hash)(const void*, int, uint8_t*);
-  int size;
-} HASH_VTAB;
-
-typedef struct HASH_CTX {
-  const HASH_VTAB * f;
-  uint64_t count;
-  uint8_t buf[64];
-  uint32_t state[8];  // upto SHA2
-} HASH_CTX;
-
-#define HASH_init(ctx) (ctx)->f->init(ctx)
-#define HASH_update(ctx, data, len) (ctx)->f->update(ctx, data, len)
-#define HASH_final(ctx) (ctx)->f->final(ctx)
-#define HASH_hash(data, len, digest) (ctx)->f->hash(data, len, digest)
-#define HASH_size(ctx) (ctx)->f->size
-
-#ifdef __cplusplus
-}
-#endif  // __cplusplus
-
-#endif  // SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
diff --git a/include/mincrypt/p256.h b/include/mincrypt/p256.h
deleted file mode 100644
index 465a1b9..0000000
--- a/include/mincrypt/p256.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * 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.
- *     * Neither the name of Google Inc. nor the names of its contributors may
- *       be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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 SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_
-#define SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_
-
-// Collection of routines manipulating 256 bit unsigned integers.
-// Just enough to implement ecdsa-p256 and related algorithms.
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define P256_BITSPERDIGIT 32
-#define P256_NDIGITS 8
-#define P256_NBYTES 32
-
-typedef int p256_err;
-typedef uint32_t p256_digit;
-typedef int32_t p256_sdigit;
-typedef uint64_t p256_ddigit;
-typedef int64_t p256_sddigit;
-
-// Defining p256_int as struct to leverage struct assigment.
-typedef struct {
-  p256_digit a[P256_NDIGITS];
-} p256_int;
-
-extern const p256_int SECP256r1_n;  // Curve order
-extern const p256_int SECP256r1_p;  // Curve prime
-extern const p256_int SECP256r1_b;  // Curve param
-
-// Initialize a p256_int to zero.
-void p256_init(p256_int* a);
-
-// Clear a p256_int to zero.
-void p256_clear(p256_int* a);
-
-// Return bit. Index 0 is least significant.
-int p256_get_bit(const p256_int* a, int index);
-
-// b := a % MOD
-void p256_mod(
-    const p256_int* MOD,
-    const p256_int* a,
-    p256_int* b);
-
-// c := a * (top_b | b) % MOD
-void p256_modmul(
-    const p256_int* MOD,
-    const p256_int* a,
-    const p256_digit top_b,
-    const p256_int* b,
-    p256_int* c);
-
-// b := 1 / a % MOD
-// MOD best be SECP256r1_n
-void p256_modinv(
-    const p256_int* MOD,
-    const p256_int* a,
-    p256_int* b);
-
-// b := 1 / a % MOD
-// MOD best be SECP256r1_n
-// Faster than p256_modinv()
-void p256_modinv_vartime(
-    const p256_int* MOD,
-    const p256_int* a,
-    p256_int* b);
-
-// b := a << (n % P256_BITSPERDIGIT)
-// Returns the bits shifted out of most significant digit.
-p256_digit p256_shl(const p256_int* a, int n, p256_int* b);
-
-// b := a >> (n % P256_BITSPERDIGIT)
-void p256_shr(const p256_int* a, int n, p256_int* b);
-
-int p256_is_zero(const p256_int* a);
-int p256_is_odd(const p256_int* a);
-int p256_is_even(const p256_int* a);
-
-// Returns -1, 0 or 1.
-int p256_cmp(const p256_int* a, const p256_int *b);
-
-// c: = a - b
-// Returns -1 on borrow.
-int p256_sub(const p256_int* a, const p256_int* b, p256_int* c);
-
-// c := a + b
-// Returns 1 on carry.
-int p256_add(const p256_int* a, const p256_int* b, p256_int* c);
-
-// c := a + (single digit)b
-// Returns carry 1 on carry.
-int p256_add_d(const p256_int* a, p256_digit b, p256_int* c);
-
-// ec routines.
-
-// {out_x,out_y} := nG
-void p256_base_point_mul(const p256_int *n,
-                         p256_int *out_x,
-                         p256_int *out_y);
-
-// {out_x,out_y} := n{in_x,in_y}
-void p256_point_mul(const p256_int *n,
-                    const p256_int *in_x,
-                    const p256_int *in_y,
-                    p256_int *out_x,
-                    p256_int *out_y);
-
-// {out_x,out_y} := n1G + n2{in_x,in_y}
-void p256_points_mul_vartime(
-    const p256_int *n1, const p256_int *n2,
-    const p256_int *in_x, const p256_int *in_y,
-    p256_int *out_x, p256_int *out_y);
-
-// Return whether point {x,y} is on curve.
-int p256_is_valid_point(const p256_int* x, const p256_int* y);
-
-// Outputs big-endian binary form. No leading zero skips.
-void p256_to_bin(const p256_int* src, uint8_t dst[P256_NBYTES]);
-
-// Reads from big-endian binary form,
-// thus pre-pad with leading zeros if short.
-void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int* dst);
-
-#define P256_DIGITS(x) ((x)->a)
-#define P256_DIGIT(x,y) ((x)->a[y])
-
-#define P256_ZERO {{0}}
-#define P256_ONE {{1}}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif  // SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_
diff --git a/include/mincrypt/p256_ecdsa.h b/include/mincrypt/p256_ecdsa.h
deleted file mode 100644
index da339fa..0000000
--- a/include/mincrypt/p256_ecdsa.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * 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.
- *     * Neither the name of Google Inc. nor the names of its contributors may
- *       be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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 SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_
-#define SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_
-
-// Using current directory as relative include path here since
-// this code typically gets lifted into a variety of build systems
-// and directory structures.
-#include "p256.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Returns 0 if {r,s} is not a signature on message for
-// public key {key_x,key_y}.
-//
-// Note: message is a p256_int.
-// Convert from a binary string using p256_from_bin().
-int p256_ecdsa_verify(const p256_int* key_x,
-                      const p256_int* key_y,
-                      const p256_int* message,
-                      const p256_int* r, const p256_int* s);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif  // SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_
diff --git a/include/mincrypt/rsa.h b/include/mincrypt/rsa.h
deleted file mode 100644
index 3d0556b..0000000
--- a/include/mincrypt/rsa.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* rsa.h
-**
-** Copyright 2008, The Android Open Source Project
-**
-** 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.
-**     * Neither the name of Google Inc. nor the names of its contributors may
-**       be used to endorse or promote products derived from this software
-**       without specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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 SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
-#define SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
-
-#include <inttypes.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define RSANUMBYTES 256           /* 2048 bit key length */
-#define RSANUMWORDS (RSANUMBYTES / sizeof(uint32_t))
-
-typedef struct RSAPublicKey {
-    int len;                  /* Length of n[] in number of uint32_t */
-    uint32_t n0inv;           /* -1 / n[0] mod 2^32 */
-    uint32_t n[RSANUMWORDS];  /* modulus as little endian array */
-    uint32_t rr[RSANUMWORDS]; /* R^2 as little endian array */
-    int exponent;             /* 3 or 65537 */
-} RSAPublicKey;
-
-int RSA_verify(const RSAPublicKey *key,
-               const uint8_t* signature,
-               const int len,
-               const uint8_t* hash,
-               const int hash_len);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
diff --git a/include/mincrypt/sha.h b/include/mincrypt/sha.h
deleted file mode 100644
index ef60aab..0000000
--- a/include/mincrypt/sha.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2005 The Android Open Source Project
- *
- * 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.
- *     * Neither the name of Google Inc. nor the names of its contributors may
- *       be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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 SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
-#define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
-
-#include <stdint.h>
-#include "hash-internal.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif // __cplusplus
-
-typedef HASH_CTX SHA_CTX;
-
-void SHA_init(SHA_CTX* ctx);
-void SHA_update(SHA_CTX* ctx, const void* data, int len);
-const uint8_t* SHA_final(SHA_CTX* ctx);
-
-// Convenience method. Returns digest address.
-// NOTE: *digest needs to hold SHA_DIGEST_SIZE bytes.
-const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest);
-
-#define SHA_DIGEST_SIZE 20
-
-#ifdef __cplusplus
-}
-#endif // __cplusplus
-
-#endif  // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
diff --git a/include/mincrypt/sha256.h b/include/mincrypt/sha256.h
deleted file mode 100644
index 3a87c31..0000000
--- a/include/mincrypt/sha256.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2011 The Android Open Source Project
- *
- * 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.
- *     * Neither the name of Google Inc. nor the names of its contributors may
- *       be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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 SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
-#define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
-
-#include <stdint.h>
-#include "hash-internal.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif // __cplusplus
-
-typedef HASH_CTX SHA256_CTX;
-
-void SHA256_init(SHA256_CTX* ctx);
-void SHA256_update(SHA256_CTX* ctx, const void* data, int len);
-const uint8_t* SHA256_final(SHA256_CTX* ctx);
-
-// Convenience method. Returns digest address.
-const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest);
-
-#define SHA256_DIGEST_SIZE 32
-
-#ifdef __cplusplus
-}
-#endif // __cplusplus
-
-#endif  // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
diff --git a/include/nativebridge/native_bridge.h b/include/nativebridge/native_bridge.h
index 18300bc..45266de 100644
--- a/include/nativebridge/native_bridge.h
+++ b/include/nativebridge/native_bridge.h
@@ -62,12 +62,19 @@
 bool NativeBridgeInitialized();
 
 // Load a shared library that is supported by the native bridge.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Use NativeBridgeLoadLibraryExt() instead in namespace scenario.
 void* NativeBridgeLoadLibrary(const char* libpath, int flag);
 
 // Get a native bridge trampoline for specified native method.
 void* NativeBridgeGetTrampoline(void* handle, const char* name, const char* shorty, uint32_t len);
 
-// True if native library is valid and is for an ABI that is supported by native bridge.
+// True if native library paths are valid and is for an ABI that is supported by native bridge.
+// The *libpath* must point to a library.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Use NativeBridgeIsPathSupported() instead in namespace scenario.
 bool NativeBridgeIsSupported(const char* libpath);
 
 // Returns the version number of the native bridge. This information is available after a
@@ -91,6 +98,48 @@
 // This functionality is exposed mainly for testing.
 bool NativeBridgeNameAcceptable(const char* native_bridge_library_filename);
 
+// Decrements the reference count on the dynamic library handler. If the reference count drops
+// to zero then the dynamic library is unloaded.
+int NativeBridgeUnloadLibrary(void* handle);
+
+// Get last error message of native bridge when fail to load library or search symbol.
+// This is reflection of dlerror() for native bridge.
+const char* NativeBridgeGetError();
+
+struct native_bridge_namespace_t;
+
+// True if native library paths are valid and is for an ABI that is supported by native bridge.
+// Different from NativeBridgeIsSupported(), the *path* here must be a directory containing
+// libraries of an ABI.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Use NativeBridgeIsSupported() instead in non-namespace scenario.
+bool NativeBridgeIsPathSupported(const char* path);
+
+// Initializes public and anonymous namespace at native bridge side.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Should not use in non-namespace scenario.
+bool NativeBridgeInitNamespace(const char* public_ns_sonames,
+                               const char* anon_ns_library_path);
+
+// Create a namespace and pass the key of related namespaces to native bridge.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Should not use in non-namespace scenario.
+native_bridge_namespace_t* NativeBridgeCreateNamespace(const char* name,
+                                                       const char* ld_library_path,
+                                                       const char* default_library_path,
+                                                       uint64_t type,
+                                                       const char* permitted_when_isolated_path,
+                                                       native_bridge_namespace_t* parent_ns);
+
+// Load a shared library with namespace key that is supported by the native bridge.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Use NativeBridgeLoadLibrary() instead in non-namespace scenario.
+void* NativeBridgeLoadLibraryExt(const char* libpath, int flag, native_bridge_namespace_t* ns);
+
 // Native bridge interfaces to runtime.
 struct NativeBridgeCallbacks {
   // Version number of the interface.
@@ -114,6 +163,9 @@
   //   flag [IN] the stardard RTLD_XXX defined in bionic dlfcn.h
   // Returns:
   //   The opaque handle of the shared library if sucessful, otherwise NULL
+  //
+  // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+  // Use loadLibraryExt instead in namespace scenario.
   void* (*loadLibrary)(const char* libpath, int flag);
 
   // Get a native bridge trampoline for specified native method. The trampoline has same
@@ -133,6 +185,9 @@
   //   libpath [IN] path to the shared library
   // Returns:
   //   TRUE if library is supported by native bridge, FALSE otherwise
+  //
+  // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+  // Use isPathSupported instead in namespace scenario.
   bool (*isSupported)(const char* libpath);
 
   // Provide environment values required by the app running with native bridge according to the
@@ -169,6 +224,88 @@
   //     runtime.
   //     Otherwise, a pointer to the signal handler.
   NativeBridgeSignalHandlerFn (*getSignalHandler)(int signal);
+
+  // Added callbacks in version 3.
+
+  // Decrements the reference count on the dynamic library handler. If the reference count drops
+  // to zero then the dynamic library is unloaded.
+  //
+  // Parameters:
+  //     handle [IN] the handler of a dynamic library.
+  //
+  // Returns:
+  //   0 on success, and nonzero on error.
+  int (*unloadLibrary)(void* handle);
+
+  // Dump the last failure message of native bridge when fail to load library or search symbol.
+  //
+  // Parameters:
+  //
+  // Returns:
+  //   A string describing the most recent error that occurred when load library
+  //   or lookup symbol via native bridge.
+  const char* (*getError)();
+
+  // Check whether library paths are supported by native bridge.
+  //
+  // Parameters:
+  //   library_path [IN] search paths for native libraries (directories separated by ':')
+  // Returns:
+  //   TRUE if libraries within search paths are supported by native bridge, FALSE otherwise
+  //
+  // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+  // Use isSupported instead in non-namespace scenario.
+  bool (*isPathSupported)(const char* library_path);
+
+  // Initializes anonymous namespace at native bridge side and pass the key of
+  // two namespaces(default and anonymous) owned by dynamic linker to native bridge.
+  //
+  // Parameters:
+  //     public_ns_sonames [IN] the name of "public" libraries.
+  //     anon_ns_library_path [IN] the library search path of (anonymous) namespace.
+  // Returns:
+  //     true if the pass is ok.
+  //     Otherwise, false.
+  //
+  // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+  // Should not use in non-namespace scenario.
+  bool (*initNamespace)(const char* public_ns_sonames,
+                        const char* anon_ns_library_path);
+
+
+  // Create a namespace and pass the key of releated namespaces to native bridge.
+  //
+  // Parameters:
+  //     name [IN] the name of the namespace.
+  //     ld_library_path [IN] the first set of library search paths of the namespace.
+  //     default_library_path [IN] the second set of library search path of the namespace.
+  //     type [IN] the attribute of the namespace.
+  //     permitted_when_isolated_path [IN] the permitted path for isolated namespace(if it is).
+  //     parent_ns [IN] the pointer of the parent namespace to be inherited from.
+  // Returns:
+  //     native_bridge_namespace_t* for created namespace or nullptr in the case of error.
+  //
+  // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+  // Should not use in non-namespace scenario.
+  native_bridge_namespace_t* (*createNamespace)(const char* name,
+                                                const char* ld_library_path,
+                                                const char* default_library_path,
+                                                uint64_t type,
+                                                const char* permitted_when_isolated_path,
+                                                native_bridge_namespace_t* parent_ns);
+
+  // Load a shared library within a namespace.
+  //
+  // Parameters:
+  //   libpath [IN] path to the shared library
+  //   flag [IN] the stardard RTLD_XXX defined in bionic dlfcn.h
+  //   ns [IN] the pointer of the namespace in which the library should be loaded.
+  // Returns:
+  //   The opaque handle of the shared library if sucessful, otherwise NULL
+  //
+  // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+  // Use loadLibrary instead in non-namespace scenario.
+  void* (*loadLibraryExt)(const char* libpath, int flag, native_bridge_namespace_t* ns);
 };
 
 // Runtime interfaces to native bridge.
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 5ccd80e..c364317 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -94,6 +94,8 @@
 #define AID_NVRAM         1050  /* Access-controlled NVRAM */
 #define AID_DNS           1051  /* DNS resolution daemon (system: netd) */
 #define AID_DNS_TETHER    1052  /* DNS resolution daemon (tether: dnsmasq) */
+#define AID_WEBVIEW_ZYGOTE 1053 /* WebView zygote process */
+#define AID_VEHICLE_NETWORK 1054 /* Vehicle network service */
 /* Changes to this file must be made in AOSP, *not* in internal branches. */
 
 #define AID_SHELL         2000  /* adb and debug shell user */
@@ -114,7 +116,6 @@
 #define AID_NET_ADMIN     3005  /* can configure interfaces and routing tables. */
 #define AID_NET_BW_STATS  3006  /* read bandwidth statistics */
 #define AID_NET_BW_ACCT   3007  /* change bandwidth statistics accounting */
-#define AID_NET_BT_STACK  3008  /* bluetooth: access config files */
 #define AID_READPROC      3009  /* Allow /proc read access */
 #define AID_WAKELOCK      3010  /* Allow system wakelock read/write access */
 
@@ -207,6 +208,8 @@
     { "nvram",         AID_NVRAM, },
     { "dns",           AID_DNS, },
     { "dns_tether",    AID_DNS_TETHER, },
+    { "webview_zygote", AID_WEBVIEW_ZYGOTE, },
+    { "vehicle_network", AID_VEHICLE_NETWORK, },
 
     { "shell",         AID_SHELL, },
     { "cache",         AID_CACHE, },
@@ -219,7 +222,6 @@
     { "net_admin",     AID_NET_ADMIN, },
     { "net_bw_stats",  AID_NET_BW_STATS, },
     { "net_bw_acct",   AID_NET_BW_ACCT, },
-    { "net_bt_stack",  AID_NET_BT_STACK, },
     { "readproc",      AID_READPROC, },
     { "wakelock",      AID_WAKELOCK, },
 
diff --git a/include/private/android_logger.h b/include/private/android_logger.h
index c3ea1ed..9f81b1f 100644
--- a/include/private/android_logger.h
+++ b/include/private/android_logger.h
@@ -21,14 +21,25 @@
 
 /* Android private interfaces */
 
+#include <stdbool.h>
 #include <stdint.h>
 #include <sys/types.h>
 
+#if (defined(__cplusplus) && defined(_USING_LIBCXX))
+extern "C++" {
+#include <string>
+}
+#endif
+
+#include <log/log_event_list.h>
 #include <log/log.h>
-#include <log/log_read.h>
 
 #define LOGGER_MAGIC 'l'
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 /* Header Structure to pstore */
 typedef struct __attribute__((__packed__)) {
     uint8_t magic;
@@ -84,6 +95,7 @@
  * in C++.
  * http://stackoverflow.com/questions/4412749/are-flexible-array-members-valid-in-c
  */
+
 typedef struct __attribute__((__packed__)) {
     int8_t type;    // EVENT_TYPE_STRING;
     int32_t length; // Little Endian Order
@@ -98,18 +110,14 @@
     char data[];
 } android_log_event_string_t;
 
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
 #define ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE 256 /* 1MB file */
 #define ANDROID_LOG_PMSG_FILE_SEQUENCE     1000
 
 ssize_t __android_log_pmsg_file_write(
         log_id_t logId,
         char prio,
-        const char *filename,
-        const char *buf, size_t len);
+        const char* filename,
+        const char* buf, size_t len);
 
 #define LOG_ID_ANY      ((log_id_t)-1)
 #define ANDROID_LOG_ANY ANDROID_LOG_UNKNOWN
@@ -118,12 +126,66 @@
 typedef ssize_t (*__android_log_pmsg_file_read_fn)(
         log_id_t logId,
         char prio,
-        const char *filename,
-        const char *buf, size_t len, void *arg);
+        const char* filename,
+        const char* buf, size_t len, void* arg);
 
 ssize_t __android_log_pmsg_file_read(
-        log_id_t logId, char prio, const char *prefix,
-        __android_log_pmsg_file_read_fn fn, void *arg);
+        log_id_t logId, char prio, const char* prefix,
+        __android_log_pmsg_file_read_fn fn, void* arg);
+
+int __android_log_security_bwrite(int32_t tag, const void* payload, size_t len);
+int __android_log_security_bswrite(int32_t tag, const char* payload);
+int __android_log_security(); /* Device Owner is present */
+
+int __android_log_is_debuggable();
+
+#define BOOL_DEFAULT_FLAG_TRUE_FALSE 0x1
+#define BOOL_DEFAULT_FALSE       0x0     /* false if property not present   */
+#define BOOL_DEFAULT_TRUE        0x1     /* true if property not present    */
+#define BOOL_DEFAULT_FLAG_PERSIST    0x2 /* <key>, persist.<key>, ro.<key>  */
+#define BOOL_DEFAULT_FLAG_ENG        0x4 /* off for user                    */
+#define BOOL_DEFAULT_FLAG_SVELTE     0x8 /* off for low_ram                 */
+bool __android_logger_property_get_bool(const char* key, int flag);
+
+#define LOG_BUFFER_SIZE (256 * 1024) /* Tuned with ro.logd.size per-platform */
+#define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
+#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
+unsigned long __android_logger_get_buffer_size(log_id_t logId);
+bool __android_logger_valid_buffer_size(unsigned long value);
+
+/* Retrieve the composed event buffer */
+int android_log_write_list_buffer(android_log_context ctx, const char** msg);
+
+#ifdef __cplusplus
+#ifdef __class_android_log_event_list_defined
+#ifndef __class_android_log_event_list_private_defined
+#define __class_android_log_event_list_private_defined
+/* android_log_context C++ helpers */
+extern "C++" {
+class __android_log_event_list : public android_log_event_list {
+    __android_log_event_list(const android_log_event_list&) = delete;
+    void operator =(const __android_log_event_list&) = delete;
+
+public:
+    explicit __android_log_event_list(int tag) : android_log_event_list(tag) { }
+    explicit __android_log_event_list(log_msg& log_msg) : android_log_event_list(log_msg) { }
+
+#if defined(_USING_LIBCXX)
+    operator std::string() {
+        if (ret) return std::string("");
+        const char* cp = NULL;
+        ssize_t len = android_log_write_list_buffer(ctx, &cp);
+        if (len < 0) ret = len;
+        if (!cp || (len <= 0)) return std::string("");
+        return std::string(cp, len);
+    }
+#endif
+
+};
+}
+#endif
+#endif
+#endif
 
 #if defined(__cplusplus)
 }
diff --git a/include/system/graphics.h b/include/system/graphics.h
index 529a562..ae10fa0 100644
--- a/include/system/graphics.h
+++ b/include/system/graphics.h
@@ -452,15 +452,15 @@
  *
  * Buffers must have a 8 bit depth.
  *
- * @y, @cb, and @cr point to the first byte of their respective planes.
+ * y, cb, and cr point to the first byte of their respective planes.
  *
  * Stride describes the distance in bytes from the first value of one row of
  * the image to the first value of the next row.  It includes the width of the
  * image plus padding.
- * @ystride is the stride of the luma plane.
- * @cstride is the stride of the chroma planes.
+ * ystride is the stride of the luma plane.
+ * cstride is the stride of the chroma planes.
  *
- * @chroma_step is the distance in bytes from one chroma pixel value to the
+ * chroma_step is the distance in bytes from one chroma pixel value to the
  * next.  This is 2 bytes for semiplanar (because chroma values are interleaved
  * and each chroma value is one byte) and 1 for planar.
  */
@@ -585,9 +585,9 @@
  * measurement is correct. It is between 0.f and 1.f, inclusive, with 1.f ==
  * 100% confidence.
  *
- * @num_points is the number of points in the list
+ * num_points is the number of points in the list
  *
- * @xyz_points is the flexible array of floating-point values.
+ * xyz_points is the flexible array of floating-point values.
  *   It contains (num_points) * 4 floats.
  *
  *   For example:
@@ -612,7 +612,14 @@
     /** reserved for future use, set to 0 by gralloc's (*lock)() */
     uint32_t reserved[8];
 
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc99-extensions"
+#endif
     float xyzc_points[];
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
 };
 
 /**
diff --git a/include/system/qemu_pipe.h b/include/system/qemu_pipe.h
new file mode 100644
index 0000000..af25079
--- /dev/null
+++ b/include/system/qemu_pipe.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_INCLUDE_SYSTEM_QEMU_PIPE_H
+#define ANDROID_INCLUDE_SYSTEM_QEMU_PIPE_H
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+// Define QEMU_PIPE_DEBUG if you want to print error messages when an error
+// occurs during pipe operations. The macro should simply take a printf-style
+// formatting string followed by optional arguments.
+#ifndef QEMU_PIPE_DEBUG
+#  define  QEMU_PIPE_DEBUG(...)   (void)0
+#endif
+
+// Try to open a new Qemu fast-pipe. This function returns a file descriptor
+// that can be used to communicate with a named service managed by the
+// emulator.
+//
+// This file descriptor can be used as a standard pipe/socket descriptor.
+//
+// 'pipeName' is the name of the emulator service you want to connect to,
+// and must begin with 'pipe:' (e.g. 'pipe:camera' or 'pipe:opengles').
+//
+// On success, return a valid file descriptor, or -1/errno on failure. E.g.:
+//
+// EINVAL  -> unknown/unsupported pipeName
+// ENOSYS  -> fast pipes not available in this system.
+//
+// ENOSYS should never happen, except if you're trying to run within a
+// misconfigured emulator.
+//
+// You should be able to open several pipes to the same pipe service,
+// except for a few special cases (e.g. GSM modem), where EBUSY will be
+// returned if more than one client tries to connect to it.
+static __inline__ int qemu_pipe_open(const char* pipeName) {
+    // Sanity check.
+    if (!pipeName || memcmp(pipeName, "pipe:", 5) != 0) {
+        errno = EINVAL;
+        return -1;
+    }
+
+    int fd = TEMP_FAILURE_RETRY(open("/dev/qemu_pipe", O_RDWR));
+    if (fd < 0) {
+        QEMU_PIPE_DEBUG("%s: Could not open /dev/qemu_pipe: %s", __FUNCTION__,
+                        strerror(errno));
+        return -1;
+    }
+
+    // Write the pipe name, *including* the trailing zero which is necessary.
+    size_t pipeNameLen = strlen(pipeName);
+    ssize_t ret = TEMP_FAILURE_RETRY(write(fd, pipeName, pipeNameLen + 1U));
+    if (ret != (ssize_t)pipeNameLen + 1) {
+        QEMU_PIPE_DEBUG("%s: Could not connect to %s pipe service: %s",
+                        __FUNCTION__, pipeName, strerror(errno));
+        if (ret == 0) {
+            errno = ECONNRESET;
+        } else if (ret > 0) {
+            errno = EINVAL;
+        }
+        return -1;
+    }
+    return fd;
+}
+
+// Send a framed message |buff| of |len| bytes through the |fd| descriptor.
+// This really adds a 4-hexchar prefix describing the payload size.
+// Returns 0 on success, and -1 on error.
+static int __inline__ qemu_pipe_frame_send(int fd,
+                                           const void* buff,
+                                           size_t len) {
+    char header[5];
+    snprintf(header, sizeof(header), "%04zx", len);
+    ssize_t ret = TEMP_FAILURE_RETRY(write(fd, header, 4));
+    if (ret != 4) {
+        QEMU_PIPE_DEBUG("Can't write qemud frame header: %s", strerror(errno));
+        return -1;
+    }
+    ret = TEMP_FAILURE_RETRY(write(fd, buff, len));
+    if (ret != (ssize_t)len) {
+        QEMU_PIPE_DEBUG("Can't write qemud frame payload: %s", strerror(errno));
+        return -1;
+    }
+    return 0;
+}
+
+// Read a frame message from |fd|, and store it into |buff| of |len| bytes.
+// If the framed message is larger than |len|, then this returns -1 and the
+// content is lost. Otherwise, this returns the size of the message. NOTE:
+// empty messages are possible in a framed wire protocol and do not mean
+// end-of-stream.
+static int __inline__ qemu_pipe_frame_recv(int fd, void* buff, size_t len) {
+    char header[5];
+    ssize_t ret = TEMP_FAILURE_RETRY(read(fd, header, 4));
+    if (ret != 4) {
+        QEMU_PIPE_DEBUG("Can't read qemud frame header: %s", strerror(errno));
+        return -1;
+    }
+    header[4] = '\0';
+    size_t size;
+    if (sscanf(header, "%04zx", &size) != 1) {
+        QEMU_PIPE_DEBUG("Malformed qemud frame header: [%.*s]", 4, header);
+        return -1;
+    }
+    if (size > len) {
+        QEMU_PIPE_DEBUG("Oversized qemud frame (% bytes, expected <= %)", size,
+                        len);
+        return -1;
+    }
+    ret = TEMP_FAILURE_RETRY(read(fd, buff, size));
+    if (ret != (ssize_t)size) {
+        QEMU_PIPE_DEBUG("Could not read qemud frame payload: %s",
+                        strerror(errno));
+        return -1;
+    }
+    return size;
+}
+
+#endif /* ANDROID_INCLUDE_HARDWARE_QEMUD_PIPE_H */
diff --git a/include/system/radio.h b/include/system/radio.h
index 9e291c8..d73d3ae 100644
--- a/include/system/radio.h
+++ b/include/system/radio.h
@@ -218,7 +218,8 @@
 } radio_event_t;
 
 
-static radio_rds_t radio_rds_for_region(bool rds, radio_region_t region) {
+static inline
+radio_rds_t radio_rds_for_region(bool rds, radio_region_t region) {
     if (!rds)
         return RADIO_RDS_NONE;
     switch(region) {
@@ -234,7 +235,8 @@
     }
 }
 
-static radio_deemphasis_t radio_demephasis_for_region(radio_region_t region) {
+static inline
+radio_deemphasis_t radio_demephasis_for_region(radio_region_t region) {
     switch(region) {
         case RADIO_REGION_KOREA:
         case RADIO_REGION_ITU_2:
diff --git a/include/system/window.h b/include/system/window.h
index 33b7c3d..f439705 100644
--- a/include/system/window.h
+++ b/include/system/window.h
@@ -38,8 +38,17 @@
 
 /*****************************************************************************/
 
+#ifdef __cplusplus
+#define ANDROID_NATIVE_UNSIGNED_CAST(x) static_cast<unsigned int>(x)
+#else
+#define ANDROID_NATIVE_UNSIGNED_CAST(x) ((unsigned int)(x))
+#endif
+
 #define ANDROID_NATIVE_MAKE_CONSTANT(a,b,c,d) \
-    (((unsigned)(a)<<24)|((unsigned)(b)<<16)|((unsigned)(c)<<8)|(unsigned)(d))
+    ((ANDROID_NATIVE_UNSIGNED_CAST(a) << 24) | \
+     (ANDROID_NATIVE_UNSIGNED_CAST(b) << 16) | \
+     (ANDROID_NATIVE_UNSIGNED_CAST(c) << 8) | \
+     (ANDROID_NATIVE_UNSIGNED_CAST(d)))
 
 #define ANDROID_NATIVE_WINDOW_MAGIC \
     ANDROID_NATIVE_MAKE_CONSTANT('_','w','n','d')
diff --git a/include/utils/Compat.h b/include/utils/Compat.h
index b2ba55e..2709e3b 100644
--- a/include/utils/Compat.h
+++ b/include/utils/Compat.h
@@ -45,13 +45,8 @@
 #define DEFFILEMODE 0666
 #endif /* _WIN32 */
 
-#if defined(_WIN32)
-#define ZD "%ld"
-#define ZD_TYPE long
-#else
 #define ZD "%zd"
 #define ZD_TYPE ssize_t
-#endif
 
 /*
  * Needed for cases where something should be constexpr if possible, but not
diff --git a/include/utils/Condition.h b/include/utils/Condition.h
index 5a72519..25a53aa 100644
--- a/include/utils/Condition.h
+++ b/include/utils/Condition.h
@@ -17,6 +17,7 @@
 #ifndef _LIBS_UTILS_CONDITION_H
 #define _LIBS_UTILS_CONDITION_H
 
+#include <limits.h>
 #include <stdint.h>
 #include <sys/types.h>
 #include <time.h>
@@ -54,7 +55,7 @@
     };
 
     Condition();
-    Condition(int type);
+    explicit Condition(int type);
     ~Condition();
     // Wait on the condition variable.  Lock the mutex before calling.
     status_t wait(Mutex& mutex);
@@ -106,30 +107,36 @@
     return -pthread_cond_wait(&mCond, &mutex.mMutex);
 }
 inline status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) {
-#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)
-    struct timespec ts;
-    ts.tv_sec  = reltime/1000000000;
-    ts.tv_nsec = reltime%1000000000;
-    return -pthread_cond_timedwait_relative_np(&mCond, &mutex.mMutex, &ts);
-#else // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
     struct timespec ts;
 #if defined(__linux__)
     clock_gettime(CLOCK_REALTIME, &ts);
 #else // __APPLE__
-    // we don't support the clocks here.
+    // Apple doesn't support POSIX clocks.
     struct timeval t;
     gettimeofday(&t, NULL);
     ts.tv_sec = t.tv_sec;
-    ts.tv_nsec= t.tv_usec*1000;
+    ts.tv_nsec = t.tv_usec*1000;
 #endif
-    ts.tv_sec += reltime/1000000000;
-    ts.tv_nsec+= reltime%1000000000;
-    if (ts.tv_nsec >= 1000000000) {
+
+    // On 32-bit devices, tv_sec is 32-bit, but `reltime` is 64-bit.
+    int64_t reltime_sec = reltime/1000000000;
+
+    ts.tv_nsec += static_cast<long>(reltime%1000000000);
+    if (reltime_sec < INT64_MAX && ts.tv_nsec >= 1000000000) {
         ts.tv_nsec -= 1000000000;
-        ts.tv_sec  += 1;
+        ++reltime_sec;
     }
+
+    int64_t time_sec = ts.tv_sec;
+    if (time_sec > INT64_MAX - reltime_sec) {
+        time_sec = INT64_MAX;
+    } else {
+        time_sec += reltime_sec;
+    }
+
+    ts.tv_sec = (time_sec > LONG_MAX) ? LONG_MAX : static_cast<long>(time_sec);
+
     return -pthread_cond_timedwait(&mCond, &mutex.mMutex, &ts);
-#endif // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
 }
 inline void Condition::signal() {
     /*
diff --git a/include/utils/Flattenable.h b/include/utils/Flattenable.h
index 882a8b2..22b811a 100644
--- a/include/utils/Flattenable.h
+++ b/include/utils/Flattenable.h
@@ -19,55 +19,62 @@
 
 
 #include <stdint.h>
+#include <string.h>
 #include <sys/types.h>
 #include <utils/Errors.h>
 #include <utils/Debug.h>
 
+#include <type_traits>
+
 namespace android {
 
 
 class FlattenableUtils {
 public:
-    template<int N>
+    template<size_t N>
     static size_t align(size_t size) {
         COMPILE_TIME_ASSERT_FUNCTION_SCOPE( !(N & (N-1)) );
         return (size + (N-1)) & ~(N-1);
     }
 
-    template<int N>
+    template<size_t N>
     static size_t align(void const*& buffer) {
         COMPILE_TIME_ASSERT_FUNCTION_SCOPE( !(N & (N-1)) );
-        intptr_t b = intptr_t(buffer);
-        buffer = (void*)((intptr_t(buffer) + (N-1)) & ~(N-1));
-        return size_t(intptr_t(buffer) - b);
+        uintptr_t b = uintptr_t(buffer);
+        buffer = reinterpret_cast<void*>((uintptr_t(buffer) + (N-1)) & ~(N-1));
+        return size_t(uintptr_t(buffer) - b);
     }
 
-    template<int N>
+    template<size_t N>
     static size_t align(void*& buffer) {
         return align<N>( const_cast<void const*&>(buffer) );
     }
 
     static void advance(void*& buffer, size_t& size, size_t offset) {
-        buffer = reinterpret_cast<void*>( intptr_t(buffer) + offset );
+        buffer = reinterpret_cast<void*>( uintptr_t(buffer) + offset );
         size -= offset;
     }
 
     static void advance(void const*& buffer, size_t& size, size_t offset) {
-        buffer = reinterpret_cast<void const*>( intptr_t(buffer) + offset );
+        buffer = reinterpret_cast<void const*>( uintptr_t(buffer) + offset );
         size -= offset;
     }
 
     // write a POD structure
     template<typename T>
     static void write(void*& buffer, size_t& size, const T& value) {
-        *static_cast<T*>(buffer) = value;
+        static_assert(std::is_trivially_copyable<T>::value,
+                      "Cannot flatten a non-trivially-copyable type");
+        memcpy(buffer, &value, sizeof(T));
         advance(buffer, size, sizeof(T));
     }
 
     // read a POD structure
     template<typename T>
     static void read(void const*& buffer, size_t& size, T& value) {
-        value = *static_cast<T const*>(buffer);
+        static_assert(std::is_trivially_copyable<T>::value,
+                      "Cannot unflatten a non-trivially-copyable type");
+        memcpy(&value, buffer, sizeof(T));
         advance(buffer, size, sizeof(T));
     }
 };
diff --git a/include/utils/KeyedVector.h b/include/utils/KeyedVector.h
index c4faae0..42de401 100644
--- a/include/utils/KeyedVector.h
+++ b/include/utils/KeyedVector.h
@@ -21,11 +21,10 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <cutils/log.h>
-
+#include <android/log.h>
+#include <utils/Errors.h>
 #include <utils/SortedVector.h>
 #include <utils/TypeHelpers.h>
-#include <utils/Errors.h>
 
 // ---------------------------------------------------------------------------
 
@@ -97,13 +96,6 @@
             SortedVector< key_value_pair_t<KEY, VALUE> >    mVector;
 };
 
-// KeyedVector<KEY, VALUE> can be trivially moved using memcpy() because its
-// underlying SortedVector can be trivially moved.
-template<typename KEY, typename VALUE> struct trait_trivial_move<KeyedVector<KEY, VALUE> > {
-    enum { value = trait_trivial_move<SortedVector< key_value_pair_t<KEY, VALUE> > >::value };
-};
-
-
 // ---------------------------------------------------------------------------
 
 /**
@@ -164,7 +156,7 @@
 VALUE& KeyedVector<KEY,VALUE>::editValueFor(const KEY& key) {
     ssize_t i = this->indexOfKey(key);
     LOG_ALWAYS_FATAL_IF(i<0, "%s: key not found", __PRETTY_FUNCTION__);
-    return mVector.editItemAt(i).value;
+    return mVector.editItemAt(static_cast<size_t>(i)).value;
 }
 
 template<typename KEY, typename VALUE> inline
@@ -188,7 +180,7 @@
 ssize_t KeyedVector<KEY,VALUE>::replaceValueAt(size_t index, const VALUE& item) {
     if (index<size()) {
         mVector.editItemAt(index).value = item;
-        return index;
+        return static_cast<ssize_t>(index);
     }
     return BAD_INDEX;
 }
diff --git a/include/utils/Log.h b/include/utils/Log.h
index 4259c86..5276a49 100644
--- a/include/utils/Log.h
+++ b/include/utils/Log.h
@@ -28,9 +28,10 @@
 #ifndef _LIBS_UTILS_LOG_H
 #define _LIBS_UTILS_LOG_H
 
-#include <cutils/log.h>
 #include <sys/types.h>
 
+#include <log/log.h>
+
 #ifdef __cplusplus
 
 namespace android {
diff --git a/include/utils/Looper.h b/include/utils/Looper.h
index da2d5f2..a62e67f 100644
--- a/include/utils/Looper.h
+++ b/include/utils/Looper.h
@@ -49,7 +49,7 @@
  */
 struct Message {
     Message() : what(0) { }
-    Message(int what) : what(what) { }
+    Message(int w) : what(w) { }
 
     /* The message type. (interpretation is left up to the handler) */
     int what;
@@ -66,7 +66,7 @@
  */
 class MessageHandler : public virtual RefBase {
 protected:
-    virtual ~MessageHandler() { }
+    virtual ~MessageHandler();
 
 public:
     /**
@@ -97,7 +97,7 @@
  */
 class LooperCallback : public virtual RefBase {
 protected:
-    virtual ~LooperCallback() { }
+    virtual ~LooperCallback();
 
 public:
     /**
@@ -436,8 +436,8 @@
     struct MessageEnvelope {
         MessageEnvelope() : uptime(0) { }
 
-        MessageEnvelope(nsecs_t uptime, const sp<MessageHandler> handler,
-                const Message& message) : uptime(uptime), handler(handler), message(message) {
+        MessageEnvelope(nsecs_t u, const sp<MessageHandler> h,
+                const Message& m) : uptime(u), handler(h), message(m) {
         }
 
         nsecs_t uptime;
diff --git a/include/utils/LruCache.h b/include/utils/LruCache.h
index ed96fe4..89dccd6 100644
--- a/include/utils/LruCache.h
+++ b/include/utils/LruCache.h
@@ -56,36 +56,55 @@
 private:
     LruCache(const LruCache& that);  // disallow copy constructor
 
-    struct Entry {
+    // Super class so that we can have entries having only a key reference, for searches.
+    class KeyedEntry {
+    public:
+        virtual const TKey& getKey() const = 0;
+        // Make sure the right destructor is executed so that keys and values are deleted.
+        virtual ~KeyedEntry() {}
+    };
+
+    class Entry final : public KeyedEntry {
+    public:
         TKey key;
         TValue value;
         Entry* parent;
         Entry* child;
 
-        Entry(TKey key_, TValue value_) : key(key_), value(value_), parent(NULL), child(NULL) {
+        Entry(TKey _key, TValue _value) : key(_key), value(_value), parent(NULL), child(NULL) {
         }
-        const TKey& getKey() const { return key; }
+        const TKey& getKey() const final { return key; }
     };
 
-    struct HashForEntry : public std::unary_function<Entry*, hash_t> {
-        size_t operator() (const Entry* entry) const {
-            return hash_type(entry->key);
+    class EntryForSearch : public KeyedEntry {
+    public:
+        const TKey& key;
+        EntryForSearch(const TKey& key_) : key(key_) {
+        }
+        const TKey& getKey() const final { return key; }
+    };
+
+    struct HashForEntry : public std::unary_function<KeyedEntry*, hash_t> {
+        size_t operator() (const KeyedEntry* entry) const {
+            return hash_type(entry->getKey());
         };
     };
 
-    struct EqualityForHashedEntries : public std::unary_function<Entry*, hash_t> {
-        bool operator() (const Entry* lhs, const Entry* rhs) const {
-            return lhs->key == rhs->key;
+    struct EqualityForHashedEntries : public std::unary_function<KeyedEntry*, hash_t> {
+        bool operator() (const KeyedEntry* lhs, const KeyedEntry* rhs) const {
+            return lhs->getKey() == rhs->getKey();
         };
     };
 
-    typedef std::unordered_set<Entry*, HashForEntry, EqualityForHashedEntries> LruCacheSet;
+    // All entries in the set will be Entry*. Using the weaker KeyedEntry as to allow entries
+    // that have only a key reference, for searching.
+    typedef std::unordered_set<KeyedEntry*, HashForEntry, EqualityForHashedEntries> LruCacheSet;
 
     void attachToCache(Entry& entry);
     void detachFromCache(Entry& entry);
 
     typename LruCacheSet::iterator findByKey(const TKey& key) {
-        Entry entryForSearch(key, mNullValue);
+        EntryForSearch entryForSearch(key);
         typename LruCacheSet::iterator result = mSet->find(&entryForSearch);
         return result;
     }
@@ -124,11 +143,13 @@
         }
 
         const TValue& value() const {
-            return (*mIterator)->value;
+            // All the elements in the set are of type Entry. See comment in the definition
+            // of LruCacheSet above.
+            return reinterpret_cast<Entry *>(*mIterator)->value;
         }
 
         const TKey& key() const {
-            return (*mIterator)->key;
+            return (*mIterator)->getKey();
         }
     private:
         const LruCache<TKey, TValue>& mCache;
@@ -145,7 +166,7 @@
     , mOldest(NULL)
     , mYoungest(NULL)
     , mMaxCapacity(maxCapacity)
-    , mNullValue(NULL) {
+    , mNullValue(0) {
     mSet->max_load_factor(1.0);
 };
 
@@ -171,7 +192,9 @@
     if (find_result == mSet->end()) {
         return mNullValue;
     }
-    Entry *entry = *find_result;
+    // All the elements in the set are of type Entry. See comment in the definition
+    // of LruCacheSet above.
+    Entry *entry = reinterpret_cast<Entry*>(*find_result);
     detachFromCache(*entry);
     attachToCache(*entry);
     return entry->value;
@@ -199,7 +222,9 @@
     if (find_result == mSet->end()) {
         return false;
     }
-    Entry* entry = *find_result;
+    // All the elements in the set are of type Entry. See comment in the definition
+    // of LruCacheSet above.
+    Entry* entry = reinterpret_cast<Entry*>(*find_result);
     mSet->erase(entry);
     if (mListener) {
         (*mListener)(entry->key, entry->value);
diff --git a/include/utils/Mutex.h b/include/utils/Mutex.h
index 848a600..d106185 100644
--- a/include/utils/Mutex.h
+++ b/include/utils/Mutex.h
@@ -52,8 +52,8 @@
     };
 
                 Mutex();
-                Mutex(const char* name);
-                Mutex(int type, const char* name = NULL);
+    explicit    Mutex(const char* name);
+    explicit    Mutex(int type, const char* name = NULL);
                 ~Mutex();
 
     // lock or unlock the mutex
@@ -82,8 +82,8 @@
     // constructed and released when Autolock goes out of scope.
     class Autolock {
     public:
-        inline Autolock(Mutex& mutex) : mLock(mutex)  { mLock.lock(); }
-        inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
+        inline explicit Autolock(Mutex& mutex) : mLock(mutex)  { mLock.lock(); }
+        inline explicit Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
         inline ~Autolock() { mLock.unlock(); }
     private:
         Mutex& mLock;
diff --git a/include/utils/RWLock.h b/include/utils/RWLock.h
index e743b1c..d5b81d3 100644
--- a/include/utils/RWLock.h
+++ b/include/utils/RWLock.h
@@ -47,8 +47,8 @@
     };
 
                 RWLock();
-                RWLock(const char* name);
-                RWLock(int type, const char* name = NULL);
+    explicit    RWLock(const char* name);
+    explicit    RWLock(int type, const char* name = NULL);
                 ~RWLock();
 
     status_t    readLock();
@@ -59,7 +59,7 @@
 
     class AutoRLock {
     public:
-        inline AutoRLock(RWLock& rwlock) : mLock(rwlock)  { mLock.readLock(); }
+        inline explicit AutoRLock(RWLock& rwlock) : mLock(rwlock)  { mLock.readLock(); }
         inline ~AutoRLock() { mLock.unlock(); }
     private:
         RWLock& mLock;
@@ -67,7 +67,7 @@
 
     class AutoWLock {
     public:
-        inline AutoWLock(RWLock& rwlock) : mLock(rwlock)  { mLock.writeLock(); }
+        inline explicit AutoWLock(RWLock& rwlock) : mLock(rwlock)  { mLock.writeLock(); }
         inline ~AutoWLock() { mLock.unlock(); }
     private:
         RWLock& mLock;
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index 14d9cb1..36016cd 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005 The Android Open Source Project
+ * 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.
@@ -14,6 +14,159 @@
  * limitations under the License.
  */
 
+
+// SOME COMMENTS ABOUT USAGE:
+
+// This provides primarily wp<> weak pointer types and RefBase, which work
+// together with sp<> from <StrongPointer.h>.
+
+// sp<> (and wp<>) are a type of smart pointer that use a well defined protocol
+// to operate. As long as the object they are templated with implements that
+// protocol, these smart pointers work. In several places the platform
+// instantiates sp<> with non-RefBase objects; the two are not tied to each
+// other.
+
+// RefBase is such an implementation and it supports strong pointers, weak
+// pointers and some magic features for the binder.
+
+// So, when using RefBase objects, you have the ability to use strong and weak
+// pointers through sp<> and wp<>.
+
+// Normally, when the last strong pointer goes away, the object is destroyed,
+// i.e. it's destructor is called. HOWEVER, parts of its associated memory is not
+// freed until the last weak pointer is released.
+
+// Weak pointers are essentially "safe" pointers. They are always safe to
+// access through promote(). They may return nullptr if the object was
+// destroyed because it ran out of strong pointers. This makes them good candidates
+// for keys in a cache for instance.
+
+// Weak pointers remain valid for comparison purposes even after the underlying
+// object has been destroyed. Even if object A is destroyed and its memory reused
+// for B, A remaining weak pointer to A will not compare equal to one to B.
+// This again makes them attractive for use as keys.
+
+// How is this supposed / intended to be used?
+
+// Our recommendation is to use strong references (sp<>) when there is an
+// ownership relation. e.g. when an object "owns" another one, use a strong
+// ref. And of course use strong refs as arguments of functions (it's extremely
+// rare that a function will take a wp<>).
+
+// Typically a newly allocated object will immediately be used to initialize
+// a strong pointer, which may then be used to construct or assign to other
+// strong and weak pointers.
+
+// Use weak references when there are no ownership relation. e.g. the keys in a
+// cache (you cannot use plain pointers because there is no safe way to acquire
+// a strong reference from a vanilla pointer).
+
+// This implies that two objects should never (or very rarely) have sp<> on
+// each other, because they can't both own each other.
+
+
+// Caveats with reference counting
+
+// Obviously, circular strong references are a big problem; this creates leaks
+// and it's hard to debug -- except it's in fact really easy because RefBase has
+// tons of debugging code for that. It can basically tell you exactly where the
+// leak is.
+
+// Another problem has to do with destructors with side effects. You must
+// assume that the destructor of reference counted objects can be called AT ANY
+// TIME. For instance code as simple as this:
+
+// void setStuff(const sp<Stuff>& stuff) {
+//   std::lock_guard<std::mutex> lock(mMutex);
+//   mStuff = stuff;
+// }
+
+// is very dangerous. This code WILL deadlock one day or another.
+
+// What isn't obvious is that ~Stuff() can be called as a result of the
+// assignment. And it gets called with the lock held. First of all, the lock is
+// protecting mStuff, not ~Stuff(). Secondly, if ~Stuff() uses its own internal
+// mutex, now you have mutex ordering issues.  Even worse, if ~Stuff() is
+// virtual, now you're calling into "user" code (potentially), by that, I mean,
+// code you didn't even write.
+
+// A correct way to write this code is something like:
+
+// void setStuff(const sp<Stuff>& stuff) {
+//   std::unique_lock<std::mutex> lock(mMutex);
+//   sp<Stuff> hold = mStuff;
+//   mStuff = stuff;
+//   lock.unlock();
+// }
+
+// More importantly, reference counted objects should do as little work as
+// possible in their destructor, or at least be mindful that their destructor
+// could be called from very weird and unintended places.
+
+// Other more specific restrictions for wp<> and sp<>:
+
+// Do not construct a strong pointer to "this" in an object's constructor.
+// The onFirstRef() callback would be made on an incompletely constructed
+// object.
+// Construction of a weak pointer to "this" in an object's constructor is also
+// discouraged. But the implementation was recently changed so that, in the
+// absence of extendObjectLifetime() calls, weak pointers no longer impact
+// object lifetime, and hence this no longer risks premature deallocation,
+// and hence usually works correctly.
+
+// Such strong or weak pointers can be safely created in the RefBase onFirstRef()
+// callback.
+
+// Use of wp::unsafe_get() for any purpose other than debugging is almost
+// always wrong.  Unless you somehow know that there is a longer-lived sp<> to
+// the same object, it may well return a pointer to a deallocated object that
+// has since been reallocated for a different purpose. (And if you know there
+// is a longer-lived sp<>, why not use an sp<> directly?) A wp<> should only be
+// dereferenced by using promote().
+
+// Any object inheriting from RefBase should always be destroyed as the result
+// of a reference count decrement, not via any other means.  Such objects
+// should never be stack allocated, or appear directly as data members in other
+// objects. Objects inheriting from RefBase should have their strong reference
+// count incremented as soon as possible after construction. Usually this
+// will be done via construction of an sp<> to the object, but may instead
+// involve other means of calling RefBase::incStrong().
+// Explicitly deleting or otherwise destroying a RefBase object with outstanding
+// wp<> or sp<> pointers to it will result in an abort or heap corruption.
+
+// It is particularly important not to mix sp<> and direct storage management
+// since the sp from raw pointer constructor is implicit. Thus if a RefBase-
+// -derived object of type T is managed without ever incrementing its strong
+// count, and accidentally passed to f(sp<T>), a strong pointer to the object
+// will be temporarily constructed and destroyed, prematurely deallocating the
+// object, and resulting in heap corruption. None of this would be easily
+// visible in the source.
+
+// Extra Features:
+
+// RefBase::extendObjectLifetime() can be used to prevent destruction of the
+// object while there are still weak references. This is really special purpose
+// functionality to support Binder.
+
+// Wp::promote(), implemented via the attemptIncStrong() member function, is
+// used to try to convert a weak pointer back to a strong pointer.  It's the
+// normal way to try to access the fields of an object referenced only through
+// a wp<>.  Binder code also sometimes uses attemptIncStrong() directly.
+
+// RefBase provides a number of additional callbacks for certain reference count
+// events, as well as some debugging facilities.
+
+// Debugging support can be enabled by turning on DEBUG_REFS in RefBase.cpp.
+// Otherwise little checking is provided.
+
+// Thread safety:
+
+// Like std::shared_ptr, sp<> and wp<> allow concurrent accesses to DIFFERENT
+// sp<> and wp<> instances that happen to refer to the same underlying object.
+// They do NOT support concurrent access (where at least one access is a write)
+// to THE SAME sp<> or wp<>.  In effect, their thread-safety properties are
+// exactly like those of T*, NOT atomic<T*>.
+
 #ifndef ANDROID_REF_BASE_H
 #define ANDROID_REF_BASE_H
 
@@ -53,6 +206,14 @@
 
 // ---------------------------------------------------------------------------
 
+// RefererenceRenamer is pure abstract, there is no virtual method
+// implementation to put in a translation unit in order to silence the
+// weak vtables warning.
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#endif
+
 class ReferenceRenamer {
 protected:
     // destructor is purposedly not virtual so we avoid code overhead from
@@ -64,6 +225,10 @@
     virtual void operator()(size_t i) const = 0;
 };
 
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
 // ---------------------------------------------------------------------------
 
 class RefBase
@@ -142,9 +307,19 @@
         FIRST_INC_STRONG = 0x0001
     };
     
+    // Invoked after creation of initial strong pointer/reference.
     virtual void            onFirstRef();
+    // Invoked when either the last strong reference goes away, or we need to undo
+    // the effect of an unnecessary onIncStrongAttempted.
     virtual void            onLastStrongRef(const void* id);
+    // Only called in OBJECT_LIFETIME_WEAK case.  Returns true if OK to promote to
+    // strong reference. May have side effects if it returns true.
+    // The first flags argument is always FIRST_INC_STRONG.
+    // TODO: Remove initial flag argument.
     virtual bool            onIncStrongAttempted(uint32_t flags, const void* id);
+    // Invoked in the OBJECT_LIFETIME_WEAK case when the last reference of either
+    // kind goes away.  Unused.
+    // TODO: Remove.
     virtual void            onLastWeakRef(const void* id);
 
 private:
@@ -196,9 +371,10 @@
 
 private:
     friend class ReferenceMover;
-    inline static void renameRefs(size_t n, const ReferenceRenamer& renamer) { }
-    inline static void renameRefId(T* ref,
-            const void* old_id, const void* new_id) { }
+    inline static void renameRefs(size_t /*n*/,
+            const ReferenceRenamer& /*renamer*/) { }
+    inline static void renameRefId(T* /*ref*/,
+            const void* /*old_id*/ , const void* /*new_id*/) { }
 
 private:
     mutable std::atomic<int32_t> mCount;
@@ -208,7 +384,7 @@
 // destructor to eliminate the template requirement of LightRefBase
 class VirtualLightRefBase : public LightRefBase<VirtualLightRefBase> {
 public:
-    virtual ~VirtualLightRefBase() {}
+    virtual ~VirtualLightRefBase();
 };
 
 // ---------------------------------------------------------------------------
@@ -221,12 +397,12 @@
     
     inline wp() : m_ptr(0) { }
 
-    wp(T* other);
+    wp(T* other);  // NOLINT(implicit)
     wp(const wp<T>& other);
-    wp(const sp<T>& other);
-    template<typename U> wp(U* other);
-    template<typename U> wp(const sp<U>& other);
-    template<typename U> wp(const wp<U>& other);
+    explicit wp(const sp<T>& other);
+    template<typename U> wp(U* other);  // NOLINT(implicit)
+    template<typename U> wp(const sp<U>& other);  // NOLINT(implicit)
+    template<typename U> wp(const wp<U>& other);  // NOLINT(implicit)
 
     ~wp();
     
@@ -482,42 +658,42 @@
     // a template<typename TYPE inherits RefBase> template...
 
     template<typename TYPE> static inline
-    void move_references(sp<TYPE>* d, sp<TYPE> const* s, size_t n) {
+    void move_references(sp<TYPE>* dest, sp<TYPE> const* src, size_t n) {
 
         class Renamer : public ReferenceRenamer {
-            sp<TYPE>* d;
-            sp<TYPE> const* s;
+            sp<TYPE>* d_;
+            sp<TYPE> const* s_;
             virtual void operator()(size_t i) const {
                 // The id are known to be the sp<>'s this pointer
-                TYPE::renameRefId(d[i].get(), &s[i], &d[i]);
+                TYPE::renameRefId(d_[i].get(), &s_[i], &d_[i]);
             }
         public:
-            Renamer(sp<TYPE>* d, sp<TYPE> const* s) : d(d), s(s) { }
+            Renamer(sp<TYPE>* d, sp<TYPE> const* s) : d_(d), s_(s) { }
             virtual ~Renamer() { }
         };
 
-        memmove(d, s, n*sizeof(sp<TYPE>));
-        TYPE::renameRefs(n, Renamer(d, s));
+        memmove(dest, src, n*sizeof(sp<TYPE>));
+        TYPE::renameRefs(n, Renamer(dest, src));
     }
 
 
     template<typename TYPE> static inline
-    void move_references(wp<TYPE>* d, wp<TYPE> const* s, size_t n) {
+    void move_references(wp<TYPE>* dest, wp<TYPE> const* src, size_t n) {
 
         class Renamer : public ReferenceRenamer {
-            wp<TYPE>* d;
-            wp<TYPE> const* s;
+            wp<TYPE>* d_;
+            wp<TYPE> const* s_;
             virtual void operator()(size_t i) const {
                 // The id are known to be the wp<>'s this pointer
-                TYPE::renameRefId(d[i].get_refs(), &s[i], &d[i]);
+                TYPE::renameRefId(d_[i].get_refs(), &s_[i], &d_[i]);
             }
         public:
-            Renamer(wp<TYPE>* d, wp<TYPE> const* s) : d(d), s(s) { }
+            Renamer(wp<TYPE>* rd, wp<TYPE> const* rs) : d_(rd), s_(rs) { }
             virtual ~Renamer() { }
         };
 
-        memmove(d, s, n*sizeof(wp<TYPE>));
-        TYPE::renameRefs(n, Renamer(d, s));
+        memmove(dest, src, n*sizeof(wp<TYPE>));
+        TYPE::renameRefs(n, Renamer(dest, src));
     }
 };
 
@@ -548,7 +724,6 @@
     ReferenceMover::move_references(d, s, n);
 }
 
-
 }; // namespace android
 
 // ---------------------------------------------------------------------------
diff --git a/include/utils/Singleton.h b/include/utils/Singleton.h
index ffc03cb..7cc4c18 100644
--- a/include/utils/Singleton.h
+++ b/include/utils/Singleton.h
@@ -19,6 +19,7 @@
 
 #include <stdint.h>
 #include <sys/types.h>
+#include <utils/Mutex.h>
 #include <utils/threads.h>
 #include <cutils/compiler.h>
 
@@ -45,8 +46,8 @@
     }
     
 protected:
-    ~Singleton() { };
-    Singleton() { };
+    ~Singleton() { }
+    Singleton() { }
 
 private:
     Singleton(const Singleton&);
@@ -55,6 +56,12 @@
     static TYPE* sInstance;
 };
 
+template <typename TYPE>
+Mutex Singleton<TYPE>::sLock;
+
+template <typename TYPE>
+TYPE* Singleton<TYPE>::sInstance;
+
 /*
  * use ANDROID_SINGLETON_STATIC_INSTANCE(TYPE) in your implementation file
  * (eg: <TYPE>.cpp) to create the static instance of Singleton<>'s attributes,
diff --git a/include/utils/SortedVector.h b/include/utils/SortedVector.h
index 2d3e82a..86f3496 100644
--- a/include/utils/SortedVector.h
+++ b/include/utils/SortedVector.h
@@ -21,11 +21,10 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <cutils/log.h>
-
+#include <log/log.h>
+#include <utils/TypeHelpers.h>
 #include <utils/Vector.h>
 #include <utils/VectorImpl.h>
-#include <utils/TypeHelpers.h>
 
 // ---------------------------------------------------------------------------
 
@@ -133,10 +132,6 @@
     virtual int     do_compare(const void* lhs, const void* rhs) const;
 };
 
-// SortedVector<T> can be trivially moved using memcpy() because moving does not
-// require any change to the underlying SharedBuffer contents or reference count.
-template<typename T> struct trait_trivial_move<SortedVector<T> > { enum { value = true }; };
-
 // ---------------------------------------------------------------------------
 // No user serviceable parts from here...
 // ---------------------------------------------------------------------------
diff --git a/include/utils/String16.h b/include/utils/String16.h
index 9bb6f0d..07c4de7 100644
--- a/include/utils/String16.h
+++ b/include/utils/String16.h
@@ -17,8 +17,10 @@
 #ifndef ANDROID_STRING16_H
 #define ANDROID_STRING16_H
 
+#include <string> // for std::string
+
 #include <utils/Errors.h>
-#include <utils/Unicode.h>
+#include <utils/String8.h>
 #include <utils/TypeHelpers.h>
 
 // ---------------------------------------------------------------------------
@@ -62,9 +64,10 @@
     explicit                    String16(const char* o, size_t len);
 
                                 ~String16();
-    
+
     inline  const char16_t*     string() const;
-    
+
+    static inline std::string   std_string(const String16& str);
             size_t              size() const;
             void                setTo(const String16& other);
             status_t            setTo(const char16_t* other);
@@ -72,12 +75,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;
 
@@ -108,16 +111,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;
 };
@@ -144,6 +147,11 @@
     return mString;
 }
 
+inline std::string String16::std_string(const String16& str)
+{
+    return std::string(String8(str).string());
+}
+
 inline String16& String16::operator=(const String16& other)
 {
     setTo(other);
diff --git a/include/utils/String8.h b/include/utils/String8.h
index 2a75b98..1d12994 100644
--- a/include/utils/String8.h
+++ b/include/utils/String8.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_STRING8_H
 #define ANDROID_STRING8_H
 
+#include <string> // for std::string
+
 #include <utils/Errors.h>
 #include <utils/Unicode.h>
 #include <utils/TypeHelpers.h>
@@ -49,7 +51,7 @@
                                 String8(const String8& o);
     explicit                    String8(const char* o);
     explicit                    String8(const char* o, size_t numChars);
-    
+
     explicit                    String8(const String16& o);
     explicit                    String8(const char16_t* o);
     explicit                    String8(const char16_t* o, size_t numChars);
@@ -63,12 +65,13 @@
     static String8              formatV(const char* fmt, va_list args);
 
     inline  const char*         string() const;
+    static inline std::string   std_string(const String8& str);
     inline  size_t              size() const;
     inline  size_t              bytes() const;
     inline  bool                isEmpty() const;
-    
+
             size_t              length() const;
-    
+
             void                clear();
 
             void                setTo(const String8& other);
@@ -95,10 +98,10 @@
 
     inline  String8&            operator=(const String8& other);
     inline  String8&            operator=(const char* other);
-    
+
     inline  String8&            operator+=(const String8& other);
     inline  String8             operator+(const String8& other) const;
-    
+
     inline  String8&            operator+=(const char* other);
     inline  String8             operator+(const char* other) const;
 
@@ -110,20 +113,20 @@
     inline  bool                operator!=(const String8& other) const;
     inline  bool                operator>=(const String8& other) const;
     inline  bool                operator>(const String8& other) const;
-    
+
     inline  bool                operator<(const char* other) const;
     inline  bool                operator<=(const char* other) const;
     inline  bool                operator==(const char* other) const;
     inline  bool                operator!=(const char* other) const;
     inline  bool                operator>=(const char* other) const;
     inline  bool                operator>(const char* other) const;
-    
+
     inline                      operator const char*() const;
-    
+
             char*               lockBuffer(size_t size);
             void                unlockBuffer();
             status_t            unlockBuffer(size_t size);
-            
+
             // return the index of the first byte of other in this at or after
             // start, or -1 if not found
             ssize_t             find(const char* other, size_t start = 0) const;
@@ -261,6 +264,11 @@
     return mString;
 }
 
+inline std::string String8::std_string(const String8& str)
+{
+    return std::string(str.string());
+}
+
 inline size_t String8::size() const
 {
     return length();
diff --git a/include/utils/StrongPointer.h b/include/utils/StrongPointer.h
index 50fde35..294e6b6 100644
--- a/include/utils/StrongPointer.h
+++ b/include/utils/StrongPointer.h
@@ -60,12 +60,12 @@
 public:
     inline sp() : m_ptr(0) { }
 
-    sp(T* other);
+    sp(T* other);  // NOLINT(implicit)
     sp(const sp<T>& other);
     sp(sp<T>&& other);
-    template<typename U> sp(U* other);
-    template<typename U> sp(const sp<U>& other);
-    template<typename U> sp(sp<U>&& other);
+    template<typename U> sp(U* other);  // NOLINT(implicit)
+    template<typename U> sp(const sp<U>& other);  // NOLINT(implicit)
+    template<typename U> sp(sp<U>&& other);  // NOLINT(implicit)
 
     ~sp();
 
@@ -137,7 +137,7 @@
 sp<T>::sp(U* other)
         : m_ptr(other) {
     if (other)
-        ((T*) other)->incStrong(this);
+        (static_cast<T*>(other))->incStrong(this);
 }
 
 template<typename T> template<typename U>
@@ -212,7 +212,7 @@
 template<typename T> template<typename U>
 sp<T>& sp<T>::operator =(U* other) {
     if (other)
-        ((T*) other)->incStrong(this);
+        (static_cast<T*>(other))->incStrong(this);
     if (m_ptr)
         m_ptr->decStrong(this);
     m_ptr = other;
diff --git a/include/utils/Thread.h b/include/utils/Thread.h
index 3792db7..a261fc8 100644
--- a/include/utils/Thread.h
+++ b/include/utils/Thread.h
@@ -41,7 +41,7 @@
 public:
     // Create a Thread object, but doesn't create or start the associated
     // thread. See the run() method.
-                        Thread(bool canCallJava = true);
+    explicit            Thread(bool canCallJava = true);
     virtual             ~Thread();
 
     // Start the thread in threadLoop() which needs to be implemented.
diff --git a/include/utils/TypeHelpers.h b/include/utils/TypeHelpers.h
index 61d618e..2a25227 100644
--- a/include/utils/TypeHelpers.h
+++ b/include/utils/TypeHelpers.h
@@ -18,6 +18,8 @@
 #define ANDROID_TYPE_HELPERS_H
 
 #include <new>
+#include <type_traits>
+
 #include <stdint.h>
 #include <string.h>
 #include <sys/types.h>
@@ -149,16 +151,21 @@
     }
 }
 
-template<typename TYPE> inline
-void copy_type(TYPE* d, const TYPE* s, size_t n) {
-    if (!traits<TYPE>::has_trivial_copy) {
-        while (n > 0) {
-            n--;
-            new(d) TYPE(*s);
-            d++, s++;
-        }
-    } else {
-        memcpy(d,s,n*sizeof(TYPE));
+template<typename TYPE>
+typename std::enable_if<traits<TYPE>::has_trivial_copy>::type
+inline
+copy_type(TYPE* d, const TYPE* s, size_t n) {
+    memcpy(d,s,n*sizeof(TYPE));
+}
+
+template<typename TYPE>
+typename std::enable_if<!traits<TYPE>::has_trivial_copy>::type
+inline
+copy_type(TYPE* d, const TYPE* s, size_t n) {
+    while (n > 0) {
+        n--;
+        new(d) TYPE(*s);
+        d++, s++;
     }
 }
 
@@ -178,49 +185,61 @@
     }
 }
 
-template<typename TYPE> inline
-void move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) {
-    if ((traits<TYPE>::has_trivial_dtor && traits<TYPE>::has_trivial_copy) 
-            || traits<TYPE>::has_trivial_move) 
-    {
-        memmove(d,s,n*sizeof(TYPE));
-    } else {
-        d += n;
-        s += n;
-        while (n > 0) {
-            n--;
-            --d, --s;
-            if (!traits<TYPE>::has_trivial_copy) {
-                new(d) TYPE(*s);
-            } else {
-                *d = *s;   
-            }
-            if (!traits<TYPE>::has_trivial_dtor) {
-                s->~TYPE();
-            }
+template<typename TYPE>
+struct use_trivial_move : public std::integral_constant<bool,
+    (traits<TYPE>::has_trivial_dtor && traits<TYPE>::has_trivial_copy)
+    || traits<TYPE>::has_trivial_move
+> {};
+
+template<typename TYPE>
+typename std::enable_if<use_trivial_move<TYPE>::value>::type
+inline
+move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) {
+    memmove(d, s, n*sizeof(TYPE));
+}
+
+template<typename TYPE>
+typename std::enable_if<!use_trivial_move<TYPE>::value>::type
+inline
+move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) {
+    d += n;
+    s += n;
+    while (n > 0) {
+        n--;
+        --d, --s;
+        if (!traits<TYPE>::has_trivial_copy) {
+            new(d) TYPE(*s);
+        } else {
+            *d = *s;
+        }
+        if (!traits<TYPE>::has_trivial_dtor) {
+            s->~TYPE();
         }
     }
 }
 
-template<typename TYPE> inline
-void move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) {
-    if ((traits<TYPE>::has_trivial_dtor && traits<TYPE>::has_trivial_copy) 
-            || traits<TYPE>::has_trivial_move) 
-    {
-        memmove(d,s,n*sizeof(TYPE));
-    } else {
-        while (n > 0) {
-            n--;
-            if (!traits<TYPE>::has_trivial_copy) {
-                new(d) TYPE(*s);
-            } else {
-                *d = *s;   
-            }
-            if (!traits<TYPE>::has_trivial_dtor) {
-                s->~TYPE();
-            }
-            d++, s++;
+template<typename TYPE>
+typename std::enable_if<use_trivial_move<TYPE>::value>::type
+inline
+move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) {
+    memmove(d, s, n*sizeof(TYPE));
+}
+
+template<typename TYPE>
+typename std::enable_if<!use_trivial_move<TYPE>::value>::type
+inline
+move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) {
+    while (n > 0) {
+        n--;
+        if (!traits<TYPE>::has_trivial_copy) {
+            new(d) TYPE(*s);
+        } else {
+            *d = *s;
         }
+        if (!traits<TYPE>::has_trivial_dtor) {
+            s->~TYPE();
+        }
+        d++, s++;
     }
 }
 
@@ -239,8 +258,13 @@
     VALUE   value;
     key_value_pair_t() { }
     key_value_pair_t(const key_value_pair_t& o) : key(o.key), value(o.value) { }
+    key_value_pair_t& operator=(const key_value_pair_t& o) {
+        key = o.key;
+        value = o.value;
+        return *this;
+    }
     key_value_pair_t(const KEY& k, const VALUE& v) : key(k), value(v)  { }
-    key_value_pair_t(const KEY& k) : key(k) { }
+    explicit key_value_pair_t(const KEY& k) : key(k) { }
     inline bool operator < (const key_value_pair_t& o) const {
         return strictly_order_type(key, o.key);
     }
@@ -275,8 +299,7 @@
 template <typename TKey>
 hash_t hash_type(const TKey& key);
 
-/* Built-in hash code specializations.
- * Assumes pointers are 32bit. */
+/* Built-in hash code specializations */
 #define ANDROID_INT32_HASH(T) \
         template <> inline hash_t hash_type(const T& value) { return hash_t(value); }
 #define ANDROID_INT64_HASH(T) \
@@ -284,7 +307,11 @@
                 return hash_t((value >> 32) ^ value); }
 #define ANDROID_REINTERPRET_HASH(T, R) \
         template <> inline hash_t hash_type(const T& value) { \
-                return hash_type(*reinterpret_cast<const R*>(&value)); }
+            R newValue; \
+            static_assert(sizeof(newValue) == sizeof(value), "size mismatch"); \
+            memcpy(&newValue, &value, sizeof(newValue)); \
+            return hash_type(newValue); \
+        }
 
 ANDROID_INT32_HASH(bool)
 ANDROID_INT32_HASH(int8_t)
diff --git a/include/utils/Unicode.h b/include/utils/Unicode.h
index cddbab4..666b70f 100644
--- a/include/utils/Unicode.h
+++ b/include/utils/Unicode.h
@@ -31,7 +31,7 @@
 char16_t *strncpy16(char16_t *, const char16_t *, size_t);
 char16_t *strstr16(const char16_t*, const char16_t*);
 
-// Version of comparison that supports embedded nulls.
+// Version of comparison that supports embedded NULs.
 // This is different than strncmp() because we don't stop
 // at a nul character and consider the strings to be different
 // if the lengths are different (thus we need to supply the
@@ -58,8 +58,9 @@
  * large enough to store the string, the part of the "src" string is stored
  * into "dst" as much as possible. See the examples for more detail.
  * Returns the size actually used for storing the string.
- * dst" is not null-terminated when dst_len is fully used (like strncpy).
+ * dst" is not nul-terminated when dst_len is fully used (like strncpy).
  *
+ * \code
  * Example 1
  * "src" == \u3042\u3044 (\xE3\x81\x82\xE3\x81\x84)
  * "src_len" == 2
@@ -67,7 +68,7 @@
  * ->
  * Returned value == 6
  * "dst" becomes \xE3\x81\x82\xE3\x81\x84\0
- * (note that "dst" is null-terminated)
+ * (note that "dst" is nul-terminated)
  *
  * Example 2
  * "src" == \u3042\u3044 (\xE3\x81\x82\xE3\x81\x84)
@@ -76,7 +77,7 @@
  * ->
  * Returned value == 3
  * "dst" becomes \xE3\x81\x82\0
- * (note that "dst" is null-terminated, but \u3044 is not stored in "dst"
+ * (note that "dst" is nul-terminated, but \u3044 is not stored in "dst"
  * since "dst" does not have enough size to store the character)
  *
  * Example 3
@@ -86,7 +87,8 @@
  * ->
  * Returned value == 6
  * "dst" becomes \xE3\x81\x82\xE3\x81\x84
- * (note that "dst" is NOT null-terminated, like strncpy)
+ * (note that "dst" is NOT nul-terminated, like strncpy)
+ * \endcode
  */
 void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst, size_t dst_len);
 
@@ -108,7 +110,7 @@
 /**
  * Converts a UTF-16 string to UTF-8. The destination buffer must be large
  * enough to fit the UTF-16 as measured by utf16_to_utf8_length with an added
- * NULL terminator.
+ * NUL terminator.
  */
 void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst, size_t dst_len);
 
@@ -118,7 +120,7 @@
  * is an invalid string.
  *
  * This function should be used to determine whether "src" is valid UTF-8
- * characters with valid unicode codepoints. "src" must be null-terminated.
+ * characters with valid unicode codepoints. "src" must be nul-terminated.
  *
  * If you are going to use other utf8_to_... functions defined in this header
  * with string which may not be valid UTF-8 with valid codepoint (form 0 to
@@ -138,35 +140,38 @@
 /**
  * Stores a UTF-32 string converted from "src" in "dst". "dst" must be large
  * enough to store the entire converted string as measured by
- * utf8_to_utf32_length plus space for a NULL terminator.
+ * utf8_to_utf32_length plus space for a NUL terminator.
  */
 void utf8_to_utf32(const char* src, size_t src_len, char32_t* dst);
 
 /**
- * Returns the UTF-16 length of UTF-8 string "src".
+ * Returns the UTF-16 length of UTF-8 string "src". Returns -1 in case
+ * it's invalid utf8. No buffer over-read occurs because of bound checks. Using overreadIsFatal you
+ * can ask to log a message and fail in case the invalid utf8 could have caused an override if no
+ * bound checks were used (otherwise -1 is returned).
  */
-ssize_t utf8_to_utf16_length(const uint8_t* src, size_t srcLen);
+ssize_t utf8_to_utf16_length(const uint8_t* src, size_t srcLen, bool overreadIsFatal = false);
 
 /**
  * Convert UTF-8 to UTF-16 including surrogate pairs.
- * Returns a pointer to the end of the string (where a null terminator might go
- * if you wanted to add one).
+ * Returns a pointer to the end of the string (where a NUL terminator might go
+ * if you wanted to add one). At most dstLen characters are written; it won't emit half a surrogate
+ * pair. If dstLen == 0 nothing is written and dst is returned. If dstLen > SSIZE_MAX it aborts
+ * (this being probably a negative number returned as an error and casted to unsigned).
  */
-char16_t* utf8_to_utf16_no_null_terminator(const uint8_t* src, size_t srcLen, char16_t* dst);
+char16_t* utf8_to_utf16_no_null_terminator(
+        const uint8_t* src, size_t srcLen, char16_t* dst, size_t dstLen);
 
 /**
- * Convert UTF-8 to UTF-16 including surrogate pairs. The destination buffer
- * must be large enough to hold the result as measured by utf8_to_utf16_length
- * plus an added NULL terminator.
+ * Convert UTF-8 to UTF-16 including surrogate pairs. At most dstLen - 1
+ * characters are written; it won't emit half a surrogate pair; and a NUL terminator is appended
+ * after. dstLen - 1 can be measured beforehand using utf8_to_utf16_length. Aborts if dstLen == 0
+ * (at least one character is needed for the NUL terminator) or dstLen > SSIZE_MAX (the latter
+ * case being likely a negative number returned as an error and casted to unsigned) . Returns a
+ * pointer to the NUL terminator.
  */
-void utf8_to_utf16(const uint8_t* src, size_t srcLen, char16_t* dst);
-
-/**
- * Like utf8_to_utf16_no_null_terminator, but you can supply a maximum length of the
- * decoded string.  The decoded string will fill up to that length; if it is longer
- * the returned pointer will be to the character after dstLen.
- */
-char16_t* utf8_to_utf16_n(const uint8_t* src, size_t srcLen, char16_t* dst, size_t dstLen);
+char16_t *utf8_to_utf16(
+        const uint8_t* src, size_t srcLen, char16_t* dst, size_t dstLen);
 
 }
 
diff --git a/include/utils/Vector.h b/include/utils/Vector.h
index ed7b725..28a77b8 100644
--- a/include/utils/Vector.h
+++ b/include/utils/Vector.h
@@ -17,14 +17,14 @@
 #ifndef ANDROID_VECTOR_H
 #define ANDROID_VECTOR_H
 
-#include <new>
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <cutils/log.h>
+#include <new>
 
-#include <utils/VectorImpl.h>
+#include <log/log.h>
 #include <utils/TypeHelpers.h>
+#include <utils/VectorImpl.h>
 
 // ---------------------------------------------------------------------------
 
@@ -194,7 +194,7 @@
      inline void push_back(const TYPE& item)  { insertAt(item, size(), 1); }
      inline void push_front(const TYPE& item) { insertAt(item, 0, 1); }
      inline iterator erase(iterator pos) {
-         ssize_t index = removeItemsAt(pos-array());
+         ssize_t index = removeItemsAt(static_cast<size_t>(pos-array()));
          return begin() + index;
      }
 
@@ -207,10 +207,6 @@
     virtual void    do_move_backward(void* dest, const void* from, size_t num) const;
 };
 
-// Vector<T> can be trivially moved using memcpy() because moving does not
-// require any change to the underlying SharedBuffer contents or reference count.
-template<typename T> struct trait_trivial_move<Vector<T> > { enum { value = true }; };
-
 // ---------------------------------------------------------------------------
 // No user serviceable parts from here...
 // ---------------------------------------------------------------------------
@@ -375,12 +371,12 @@
 
 template<class TYPE> inline
 status_t Vector<TYPE>::sort(Vector<TYPE>::compar_t cmp) {
-    return VectorImpl::sort((VectorImpl::compar_t)cmp);
+    return VectorImpl::sort(reinterpret_cast<VectorImpl::compar_t>(cmp));
 }
 
 template<class TYPE> inline
 status_t Vector<TYPE>::sort(Vector<TYPE>::compar_r_t cmp, void* state) {
-    return VectorImpl::sort((VectorImpl::compar_r_t)cmp, state);
+    return VectorImpl::sort(reinterpret_cast<VectorImpl::compar_r_t>(cmp), state);
 }
 
 // ---------------------------------------------------------------------------
diff --git a/include/utils/VectorImpl.h b/include/utils/VectorImpl.h
index 21ad71c..4dd91fd 100644
--- a/include/utils/VectorImpl.h
+++ b/include/utils/VectorImpl.h
@@ -132,7 +132,7 @@
 {
 public:
                             SortedVectorImpl(size_t itemSize, uint32_t flags);
-                            SortedVectorImpl(const VectorImpl& rhs);
+    explicit                SortedVectorImpl(const VectorImpl& rhs);
     virtual                 ~SortedVectorImpl();
     
     SortedVectorImpl&     operator = (const SortedVectorImpl& rhs);    
diff --git a/include/utils/ashmem.h b/include/utils/ashmem.h
deleted file mode 100644
index 0854775..0000000
--- a/include/utils/ashmem.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* utils/ashmem.h
- **
- ** Copyright 2008 The Android Open Source Project
- **
- ** This file is dual licensed.  It may be redistributed and/or modified
- ** under the terms of the Apache 2.0 License OR version 2 of the GNU
- ** General Public License.
- */
-
-#ifndef _UTILS_ASHMEM_H
-#define _UTILS_ASHMEM_H
-
-#include <linux/limits.h>
-#include <linux/ioctl.h>
-
-#define ASHMEM_NAME_LEN		256
-
-#define ASHMEM_NAME_DEF		"dev/ashmem"
-
-/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */
-#define ASHMEM_NOT_REAPED	0
-#define ASHMEM_WAS_REAPED	1
-
-/* Return values from ASHMEM_UNPIN: Is the mapping now pinned or unpinned? */
-#define ASHMEM_NOW_UNPINNED	0
-#define ASHMEM_NOW_PINNED	1
-
-#define __ASHMEMIOC		0x77
-
-#define ASHMEM_SET_NAME		_IOW(__ASHMEMIOC, 1, char[ASHMEM_NAME_LEN])
-#define ASHMEM_GET_NAME		_IOR(__ASHMEMIOC, 2, char[ASHMEM_NAME_LEN])
-#define ASHMEM_SET_SIZE		_IOW(__ASHMEMIOC, 3, size_t)
-#define ASHMEM_GET_SIZE		_IO(__ASHMEMIOC, 4)
-#define ASHMEM_SET_PROT_MASK	_IOW(__ASHMEMIOC, 5, unsigned long)
-#define ASHMEM_GET_PROT_MASK	_IO(__ASHMEMIOC, 6)
-#define ASHMEM_PIN		_IO(__ASHMEMIOC, 7)
-#define ASHMEM_UNPIN		_IO(__ASHMEMIOC, 8)
-#define ASHMEM_ISPINNED		_IO(__ASHMEMIOC, 9)
-#define ASHMEM_PURGE_ALL_CACHES	_IO(__ASHMEMIOC, 10)
-
-#endif	/* _UTILS_ASHMEM_H */
diff --git a/include/ziparchive/zip_archive.h b/include/ziparchive/zip_archive.h
index 7dc60ae..54946fc 100644
--- a/include/ziparchive/zip_archive.h
+++ b/include/ziparchive/zip_archive.h
@@ -43,8 +43,7 @@
   /*
    * entry_name has to be an c-style string with only ASCII characters.
    */
-  explicit ZipString(const char* entry_name)
-      : name(reinterpret_cast<const uint8_t*>(entry_name)), name_length(strlen(entry_name)) {}
+  explicit ZipString(const char* entry_name);
 
   bool operator==(const ZipString& rhs) const {
     return name && (name_length == rhs.name_length) &&
@@ -131,6 +130,8 @@
 int32_t OpenArchiveFd(const int fd, const char* debugFileName,
                       ZipArchiveHandle *handle, bool assume_ownership = true);
 
+int32_t OpenArchiveFromMemory(void* address, size_t length, const char* debugFileName,
+                              ZipArchiveHandle *handle);
 /*
  * Close archive, releasing resources associated with it. This will
  * unmap the central directory of the zipfile and free all internal
@@ -194,7 +195,8 @@
  * Uncompress and write an entry to an open file identified by |fd|.
  * |entry->uncompressed_length| bytes will be written to the file at
  * its current offset, and the file will be truncated at the end of
- * the uncompressed data.
+ * the uncompressed data (no truncation if |fd| references a block
+ * device).
  *
  * Returns 0 on success and negative values on failure.
  */
@@ -215,6 +217,17 @@
 
 const char* ErrorCodeString(int32_t error_code);
 
+#if !defined(_WIN32)
+typedef bool (*ProcessZipEntryFunction)(const uint8_t* buf, size_t buf_size, void* cookie);
+
+/*
+ * Stream the uncompressed data through the supplied function,
+ * passing cookie to it each time it gets called.
+*/
+int32_t ProcessZipEntryContents(ZipArchiveHandle handle, ZipEntry* entry,
+        ProcessZipEntryFunction func, void* cookie);
+#endif
+
 __END_DECLS
 
 #endif  // LIBZIPARCHIVE_ZIPARCHIVE_H_
diff --git a/init/Android.mk b/init/Android.mk
index 67541b8..442a5f3 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -45,6 +45,8 @@
 LOCAL_CPPFLAGS := $(init_cflags)
 LOCAL_SRC_FILES:= \
     action.cpp \
+    capabilities.cpp \
+    descriptors.cpp \
     import_parser.cpp \
     init_parser.cpp \
     log.cpp \
@@ -52,7 +54,8 @@
     service.cpp \
     util.cpp \
 
-LOCAL_STATIC_LIBRARIES := libbase libselinux
+LOCAL_STATIC_LIBRARIES := libbase libselinux liblog libprocessgroup
+LOCAL_WHOLE_STATIC_LIBRARIES := libcap
 LOCAL_MODULE := libinit
 LOCAL_SANITIZE := integer
 LOCAL_CLANG := true
@@ -74,7 +77,6 @@
 
 LOCAL_MODULE:= init
 LOCAL_C_INCLUDES += \
-    system/extras/ext4_utils \
     system/core/mkbootimg
 
 LOCAL_FORCE_STATIC_EXECUTABLE := true
@@ -92,18 +94,18 @@
     libcutils \
     libext4_utils_static \
     libbase \
-    libutils \
     libc \
     libselinux \
     liblog \
-    libmincrypt \
-    libcrypto_static \
+    libcrypto_utils \
+    libcrypto \
     libc++_static \
     libdl \
     libsparse_static \
-    libz
+    libz \
+    libprocessgroup
 
-# Create symlinks
+# Create symlinks.
 LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
     ln -sf ../init $(TARGET_ROOT_OUT)/sbin/ueventd; \
     ln -sf ../init $(TARGET_ROOT_OUT)/sbin/watchdogd
@@ -113,8 +115,8 @@
 include $(BUILD_EXECUTABLE)
 
 
-
-
+# Unit tests.
+# =========================================================
 include $(CLEAR_VARS)
 LOCAL_MODULE := init_tests
 LOCAL_SRC_FILES := \
@@ -124,8 +126,10 @@
 LOCAL_SHARED_LIBRARIES += \
     libcutils \
     libbase \
+    libselinux \
 
 LOCAL_STATIC_LIBRARIES := libinit
 LOCAL_SANITIZE := integer
 LOCAL_CLANG := true
+LOCAL_CPPFLAGS := -Wall -Wextra -Werror
 include $(BUILD_NATIVE_TEST)
diff --git a/init/action.cpp b/init/action.cpp
index 510ea89..0ea7e14 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -42,7 +42,7 @@
     expanded_args[0] = args_[0];
     for (std::size_t i = 1; i < args_.size(); ++i) {
         if (!expand_props(args_[i], &expanded_args[i])) {
-            ERROR("%s: cannot expand '%s'\n", args_[0].c_str(), args_[i].c_str());
+            LOG(ERROR) << args_[0] << ": cannot expand '" << args_[i] << "'";
             return -EINVAL;
         }
     }
@@ -105,7 +105,10 @@
 }
 
 void Action::ExecuteOneCommand(std::size_t command) const {
-    ExecuteCommand(commands_[command]);
+    // We need a copy here since some Command execution may result in
+    // changing commands_ vector by importing .rc files through parser
+    Command cmd = commands_[command];
+    ExecuteCommand(cmd);
 }
 
 void Action::ExecuteAllCommands() const {
@@ -118,14 +121,16 @@
     Timer t;
     int result = command.InvokeFunc();
 
-    if (klog_get_level() >= KLOG_INFO_LEVEL) {
+    double duration_ms = t.duration() * 1000;
+    // Any action longer than 50ms will be warned to user as slow operation
+    if (duration_ms > 50.0 ||
+        android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
         std::string trigger_name = BuildTriggersString();
         std::string cmd_str = command.BuildCommandString();
         std::string source = command.BuildSourceString();
 
-        INFO("Command '%s' action=%s%s returned %d took %.2fs\n",
-             cmd_str.c_str(), trigger_name.c_str(), source.c_str(),
-             result, t.duration());
+        LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << source
+                  << " returned " << result << " took " << duration_ms << "ms.";
     }
 }
 
@@ -152,6 +157,11 @@
 bool Action::InitTriggers(const std::vector<std::string>& args, std::string* err) {
     const static std::string prop_str("property:");
     for (std::size_t i = 0; i < args.size(); ++i) {
+        if (args[i].empty()) {
+            *err = "empty trigger is not valid";
+            return false;
+        }
+
         if (i % 2) {
             if (args[i] != "&&") {
                 *err = "&& is the only symbol allowed to concatenate actions";
@@ -181,7 +191,11 @@
 bool Action::InitSingleTrigger(const std::string& trigger) {
     std::vector<std::string> name_vector{trigger};
     std::string err;
-    return InitTriggers(name_vector, &err);
+    bool ret = InitTriggers(name_vector, &err);
+    if (!ret) {
+        LOG(ERROR) << "InitSingleTrigger failed due to: " << err;
+    }
+    return ret;
 }
 
 // This function checks that all property triggers are satisfied, that is
@@ -253,18 +267,17 @@
 
 void Action::DumpState() const {
     std::string trigger_name = BuildTriggersString();
-    INFO("on %s\n", trigger_name.c_str());
+    LOG(INFO) << "on " << trigger_name;
 
     for (const auto& c : commands_) {
         std::string cmd_str = c.BuildCommandString();
-        INFO(" %s\n", cmd_str.c_str());
+        LOG(INFO) << "  %s" << cmd_str;
     }
-    INFO("\n");
 }
 
 class EventTrigger : public Trigger {
 public:
-    EventTrigger(const std::string& trigger) : trigger_(trigger) {
+    explicit EventTrigger(const std::string& trigger) : trigger_(trigger) {
     }
     bool CheckTriggers(const Action& action) const override {
         return action.CheckEventTrigger(trigger_);
@@ -288,7 +301,7 @@
 
 class BuiltinTrigger : public Trigger {
 public:
-    BuiltinTrigger(Action* action) : action_(action) {
+    explicit BuiltinTrigger(Action* action) : action_(action) {
     }
     bool CheckTriggers(const Action& action) const override {
         return action_ == &action;
@@ -366,7 +379,7 @@
 
     if (current_command_ == 0) {
         std::string trigger_name = action->BuildTriggersString();
-        INFO("processing action (%s)\n", trigger_name.c_str());
+        LOG(INFO) << "processing action (" << trigger_name << ")";
     }
 
     action->ExecuteOneCommand(current_command_);
@@ -395,7 +408,6 @@
     for (const auto& a : actions_) {
         a->DumpState();
     }
-    INFO("\n");
 }
 
 bool ActionParser::ParseSection(const std::vector<std::string>& args,
diff --git a/init/action.h b/init/action.h
index 6dee2d0..0bae9f0 100644
--- a/init/action.h
+++ b/init/action.h
@@ -44,7 +44,7 @@
 
 class Action {
 public:
-    Action(bool oneshot = false);
+    explicit Action(bool oneshot = false);
 
     bool AddCommand(const std::vector<std::string>& args,
                     const std::string& filename, int line, std::string* err);
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
index 5704d28..8fb55f0 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -206,12 +206,12 @@
 int do_bootchart_init(const std::vector<std::string>& args) {
     g_remaining_samples = bootchart_init();
     if (g_remaining_samples < 0) {
-        ERROR("Bootcharting init failure: %s\n", strerror(errno));
+        PLOG(ERROR) << "Bootcharting initialization failed";
     } else if (g_remaining_samples > 0) {
-        NOTICE("Bootcharting started (will run for %d s).\n",
-               (g_remaining_samples * BOOTCHART_POLLING_MS) / 1000);
+        LOG(INFO) << "Bootcharting started (will run for "
+                  << ((g_remaining_samples * BOOTCHART_POLLING_MS) / 1000) << " s).";
     } else {
-        NOTICE("Not bootcharting.\n");
+        LOG(VERBOSE) << "Not bootcharting.";
     }
     return 0;
 }
@@ -241,6 +241,7 @@
     fclose(log_disks);
     fclose(log_procs);
     acct(NULL);
+    LOG(INFO) << "Bootcharting finished";
 }
 
 void bootchart_sample(int* timeout) {
@@ -253,12 +254,12 @@
     int elapsed_time = current_time - g_last_bootchart_time;
 
     if (elapsed_time >= BOOTCHART_POLLING_MS) {
-        /* count missed samples */
+        // Count missed samples.
         while (elapsed_time >= BOOTCHART_POLLING_MS) {
             elapsed_time -= BOOTCHART_POLLING_MS;
             g_remaining_samples--;
         }
-        /* count may be negative, take a sample anyway */
+        // Count may be negative, take a sample anyway.
         g_last_bootchart_time = current_time;
         if (bootchart_step() < 0 || g_remaining_samples <= 0) {
             bootchart_finish();
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 44217f0..42ae5e6 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -36,21 +36,25 @@
 #include <sys/wait.h>
 #include <unistd.h>
 #include <linux/loop.h>
-#include <ext4_crypt.h>
-#include <ext4_crypt_init_extensions.h>
+#include <linux/module.h>
 
+#include <thread>
+
+#include <selinux/android.h>
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 
 #include <fs_mgr.h>
 #include <android-base/file.h>
 #include <android-base/parseint.h>
+#include <android-base/strings.h>
 #include <android-base/stringprintf.h>
 #include <bootloader_message/bootloader_message.h>
 #include <cutils/partition_utils.h>
 #include <cutils/android_reboot.h>
+#include <ext4_utils/ext4_crypt.h>
+#include <ext4_utils/ext4_crypt_init_extensions.h>
 #include <logwrap/logwrap.h>
-#include <private/android_filesystem_config.h>
 
 #include "action.h"
 #include "bootchart.h"
@@ -64,20 +68,19 @@
 #include "util.h"
 
 #define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW
-#define UNMOUNT_CHECK_MS 5000
 #define UNMOUNT_CHECK_TIMES 10
 
-static const int kTerminateServiceDelayMicroSeconds = 50000;
+static constexpr std::chrono::nanoseconds kCommandRetryTimeout = 5s;
 
-static int insmod(const char *filename, const char *options) {
+static int insmod(const char *filename, const char *options, int flags) {
     int fd = open(filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
     if (fd == -1) {
-        ERROR("insmod: open(\"%s\") failed: %s", filename, strerror(errno));
+        PLOG(ERROR) << "insmod: open(\"" << filename << "\") failed";
         return -1;
     }
-    int rc = syscall(__NR_finit_module, fd, options, 0);
+    int rc = syscall(__NR_finit_module, fd, options, flags);
     if (rc == -1) {
-        ERROR("finit_module for \"%s\" failed: %s", filename, strerror(errno));
+        PLOG(ERROR) << "finit_module for \"" << filename << "\" failed";
     }
     close(fd);
     return rc;
@@ -140,7 +143,7 @@
     const std::vector<std::string> options = {"--wipe_data", std::string() + "--reason=" + reason};
     std::string err;
     if (!write_bootloader_message(options, &err)) {
-        ERROR("failed to set bootloader message: %s", err.c_str());
+        LOG(ERROR) << "failed to set bootloader message: " << err;
         return -1;
     }
     android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
@@ -191,11 +194,9 @@
             close(fd);
             break;
         } else if (errno == EBUSY) {
-            /* Some processes using |entry->mnt_dir| are still alive. Wait for a
-             * while then retry.
-             */
-            TEMP_FAILURE_RETRY(
-                usleep(UNMOUNT_CHECK_MS * 1000 / UNMOUNT_CHECK_TIMES));
+            // Some processes using |entry->mnt_dir| are still alive. Wait for a
+            // while then retry.
+            std::this_thread::sleep_for(5000ms / UNMOUNT_CHECK_TIMES);
             continue;
         } else {
             /* Cannot open the device. Give up. */
@@ -213,13 +214,13 @@
         const char *f2fs_argv[] = {
             "/system/bin/fsck.f2fs", "-f", entry->mnt_fsname,
         };
-        android_fork_execvp_ext(ARRAY_SIZE(f2fs_argv), (char **)f2fs_argv,
+        android_fork_execvp_ext(arraysize(f2fs_argv), (char **)f2fs_argv,
                                 &st, true, LOG_KLOG, true, NULL, NULL, 0);
     } else if (!strcmp(entry->mnt_type, "ext4")) {
         const char *ext4_argv[] = {
             "/system/bin/e2fsck", "-f", "-y", entry->mnt_fsname,
         };
-        android_fork_execvp_ext(ARRAY_SIZE(ext4_argv), (char **)ext4_argv,
+        android_fork_execvp_ext(arraysize(ext4_argv), (char **)ext4_argv,
                                 &st, true, LOG_KLOG, true, NULL, NULL, 0);
     }
 }
@@ -283,17 +284,17 @@
 }
 
 static int do_insmod(const std::vector<std::string>& args) {
-    std::string options;
+    int flags = 0;
+    auto it = args.begin() + 1;
 
-    if (args.size() > 2) {
-        options += args[2];
-        for (std::size_t i = 3; i < args.size(); ++i) {
-            options += ' ';
-            options += args[i];
-        }
+    if (!(*it).compare("-f")) {
+        flags = MODULE_INIT_IGNORE_VERMAGIC | MODULE_INIT_IGNORE_MODVERSIONS;
+        it++;
     }
 
-    return insmod(args[1].c_str(), options.c_str());
+    std::string filename = *it++;
+    std::string options = android::base::Join(std::vector<std::string>(it, args.end()), ' ');
+    return insmod(filename.c_str(), options.c_str(), flags);
 }
 
 static int do_mkdir(const std::vector<std::string>& args) {
@@ -303,7 +304,7 @@
     /* mkdir <path> [mode] [owner] [group] */
 
     if (args.size() >= 3) {
-        mode = std::stoul(args[2], 0, 8);
+        mode = std::strtoul(args[2].c_str(), 0, 8);
     }
 
     ret = make_dir(args[1].c_str(), mode);
@@ -405,22 +406,7 @@
     source = args[2].c_str();
     target = args[3].c_str();
 
-    if (!strncmp(source, "mtd@", 4)) {
-        n = mtd_name_to_number(source + 4);
-        if (n < 0) {
-            return -1;
-        }
-
-        snprintf(tmp, sizeof(tmp), "/dev/block/mtdblock%d", n);
-
-        if (wait)
-            wait_for_file(tmp, COMMAND_RETRY_TIMEOUT);
-        if (mount(tmp, target, system, flags, options) < 0) {
-            return -1;
-        }
-
-        goto exit_success;
-    } else if (!strncmp(source, "loop@", 5)) {
+    if (!strncmp(source, "loop@", 5)) {
         int mode, loop, fd;
         struct loop_info info;
 
@@ -459,11 +445,11 @@
         }
 
         close(fd);
-        ERROR("out of loopback devices");
+        LOG(ERROR) << "out of loopback devices";
         return -1;
     } else {
         if (wait)
-            wait_for_file(source, COMMAND_RETRY_TIMEOUT);
+            wait_for_file(source, kCommandRetryTimeout);
         if (mount(source, target, system, flags, options) < 0) {
             return -1;
         }
@@ -504,11 +490,7 @@
  *  Call fs_mgr_mount_all() to mount the given fstab
  */
 static int mount_fstab(const char* fstabfile, int mount_mode) {
-    pid_t pid;
     int ret = -1;
-    int child_ret = -1;
-    int status;
-    struct fstab *fstab;
 
     /*
      * Call fs_mgr_mount_all() to mount all filesystems.  We fork(2) and
@@ -516,13 +498,14 @@
      * process if anything goes wrong (crash or memory leak), and wait for
      * the child to finish in the parent.
      */
-    pid = fork();
+    pid_t pid = fork();
     if (pid > 0) {
         /* Parent.  Wait for the child to return */
+        int status;
         int wp_ret = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
-        if (wp_ret < 0) {
-            /* Unexpected error code. We will continue anyway. */
-            NOTICE("waitpid failed rc=%d: %s\n", wp_ret, strerror(errno));
+        if (wp_ret == -1) {
+            // Unexpected error code. We will continue anyway.
+            PLOG(WARNING) << "waitpid failed";
         }
 
         if (WIFEXITED(status)) {
@@ -532,12 +515,16 @@
         }
     } else if (pid == 0) {
         /* child, call fs_mgr_mount_all() */
-        klog_set_level(6);  /* So we can see what fs_mgr_mount_all() does */
-        fstab = fs_mgr_read_fstab(fstabfile);
-        child_ret = fs_mgr_mount_all(fstab, mount_mode);
+
+        // So we can always see what fs_mgr_mount_all() does.
+        // Only needed if someone explicitly changes the default log level in their init.rc.
+        android::base::ScopedLogSeverity info(android::base::INFO);
+
+        struct fstab* fstab = fs_mgr_read_fstab(fstabfile);
+        int child_ret = fs_mgr_mount_all(fstab, mount_mode);
         fs_mgr_free_fstab(fstab);
         if (child_ret == -1) {
-            ERROR("fs_mgr_mount_all returned an error\n");
+            PLOG(ERROR) << "fs_mgr_mount_all returned an error";
         }
         _exit(child_ret);
     } else {
@@ -572,7 +559,7 @@
         ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
     } else if (code == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
         /* Setup a wipe via recovery, and reboot into recovery */
-        ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n");
+        PLOG(ERROR) << "fs_mgr_mount_all suggested recovery, so wiping data via recovery.";
         ret = wipe_data_via_recovery("wipe_data_via_recovery");
         /* If reboot worked, there is no return. */
     } else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
@@ -586,7 +573,7 @@
         // do anything different from the nonencrypted case.
         ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
     } else if (code > 0) {
-        ERROR("fs_mgr_mount_all returned unexpected error %d\n", code);
+        PLOG(ERROR) << "fs_mgr_mount_all returned unexpected error " << code;
     }
     /* else ... < 0: error */
 
@@ -608,9 +595,9 @@
 
     for (na = args.size() - 1; na > 1; --na) {
         if (args[na] == "--early") {
-             path_arg_end = na;
-             queue_event = false;
-             mount_mode = MOUNT_MODE_EARLY;
+            path_arg_end = na;
+            queue_event = false;
+            mount_mode = MOUNT_MODE_EARLY;
         } else if (args[na] == "--late") {
             path_arg_end = na;
             import_rc = false;
@@ -655,16 +642,19 @@
 static int do_setrlimit(const std::vector<std::string>& args) {
     struct rlimit limit;
     int resource;
-    resource = std::stoi(args[1]);
-    limit.rlim_cur = std::stoi(args[2]);
-    limit.rlim_max = std::stoi(args[3]);
-    return setrlimit(resource, &limit);
+    if (android::base::ParseInt(args[1], &resource) &&
+        android::base::ParseUint(args[2], &limit.rlim_cur) &&
+        android::base::ParseUint(args[3], &limit.rlim_max)) {
+        return setrlimit(resource, &limit);
+    }
+    LOG(WARNING) << "ignoring setrlimit " << args[1] << " " << args[2] << " " << args[3];
+    return -1;
 }
 
 static int do_start(const std::vector<std::string>& args) {
     Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
     if (!svc) {
-        ERROR("do_start: Service %s not found\n", args[1].c_str());
+        LOG(ERROR) << "do_start: Service " << args[1] << " not found";
         return -1;
     }
     if (!svc->Start())
@@ -675,7 +665,7 @@
 static int do_stop(const std::vector<std::string>& args) {
     Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
     if (!svc) {
-        ERROR("do_stop: Service %s not found\n", args[1].c_str());
+        LOG(ERROR) << "do_stop: Service " << args[1] << " not found";
         return -1;
     }
     svc->Stop();
@@ -685,7 +675,7 @@
 static int do_restart(const std::vector<std::string>& args) {
     Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
     if (!svc) {
-        ERROR("do_restart: Service %s not found\n", args[1].c_str());
+        LOG(ERROR) << "do_restart: Service " << args[1] << " not found";
         return -1;
     }
     svc->Restart();
@@ -706,7 +696,7 @@
         cmd = ANDROID_RB_RESTART2;
         len = 6;
     } else {
-        ERROR("powerctl: unrecognized command '%s'\n", command);
+        LOG(ERROR) << "powerctl: unrecognized command '" << command << "'";
         return -EINVAL;
     }
 
@@ -718,16 +708,25 @@
             callback_on_ro_remount = unmount_and_fsck;
         } else if (cmd == ANDROID_RB_RESTART2) {
             reboot_target = &command[len + 1];
+            // When rebooting to the bootloader notify the bootloader writing
+            // also the BCB.
+            if (strcmp(reboot_target, "bootloader") == 0) {
+                std::string err;
+                if (!write_reboot_bootloader(&err)) {
+                    LOG(ERROR) << "reboot-bootloader: Error writing "
+                                  "bootloader_message: " << err;
+                }
+            }
         }
     } else if (command[len] != '\0') {
-        ERROR("powerctl: unrecognized reboot target '%s'\n", &command[len]);
+        LOG(ERROR) << "powerctl: unrecognized reboot target '" << &command[len] << "'";
         return -EINVAL;
     }
 
     std::string timeout = property_get("ro.build.shutdown_timeout");
     unsigned int delay = 0;
 
-    if (android::base::ParseUint(timeout.c_str(), &delay) && delay > 0) {
+    if (android::base::ParseUint(timeout, &delay) && delay > 0) {
         Timer t;
         // Ask all services to terminate.
         ServiceManager::GetInstance().ForEachService(
@@ -755,9 +754,9 @@
             }
 
             // Wait a bit before recounting the number or running services.
-            usleep(kTerminateServiceDelayMicroSeconds);
+            std::this_thread::sleep_for(50ms);
         }
-        NOTICE("Terminating running services took %.02f seconds", t.duration());
+        LOG(VERBOSE) << "Terminating running services took " << t.duration() << " seconds";
     }
 
     return android_reboot_with_callback(cmd, 0, reboot_target,
@@ -782,13 +781,11 @@
 }
 
 static int do_sysclktz(const std::vector<std::string>& args) {
-    struct timezone tz;
-
-    memset(&tz, 0, sizeof(tz));
-    tz.tz_minuteswest = std::stoi(args[1]);
-    if (settimeofday(NULL, &tz))
-        return -1;
-    return 0;
+    struct timezone tz = {};
+    if (android::base::ParseInt(args[1], &tz.tz_minuteswest) && settimeofday(NULL, &tz) != -1) {
+        return 0;
+    }
+    return -1;
 }
 
 static int do_verity_load_state(const std::vector<std::string>& args) {
@@ -913,34 +910,70 @@
 static int do_restorecon(const std::vector<std::string>& args) {
     int ret = 0;
 
-    for (auto it = std::next(args.begin()); it != args.end(); ++it) {
-        if (restorecon(it->c_str()) < 0)
-            ret = -errno;
-    }
-    return ret;
-}
+    struct flag_type {const char* name; int value;};
+    static const flag_type flags[] = {
+        {"--recursive", SELINUX_ANDROID_RESTORECON_RECURSE},
+        {"--skip-ce", SELINUX_ANDROID_RESTORECON_SKIPCE},
+        {"--cross-filesystems", SELINUX_ANDROID_RESTORECON_CROSS_FILESYSTEMS},
+        {0, 0}
+    };
 
-static int do_restorecon_recursive(const std::vector<std::string>& args) {
-    int ret = 0;
+    int flag = 0;
 
-    for (auto it = std::next(args.begin()); it != args.end(); ++it) {
-        /* The contents of CE paths are encrypted on FBE devices until user
-         * credentials are presented (filenames inside are mangled), so we need
-         * to delay restorecon of those until vold explicitly requests it. */
-        if (restorecon_recursive_skipce(it->c_str()) < 0) {
-            ret = -errno;
+    bool in_flags = true;
+    for (size_t i = 1; i < args.size(); ++i) {
+        if (android::base::StartsWith(args[i], "--")) {
+            if (!in_flags) {
+                LOG(ERROR) << "restorecon - flags must precede paths";
+                return -1;
+            }
+            bool found = false;
+            for (size_t j = 0; flags[j].name; ++j) {
+                if (args[i] == flags[j].name) {
+                    flag |= flags[j].value;
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                LOG(ERROR) << "restorecon - bad flag " << args[i];
+                return -1;
+            }
+        } else {
+            in_flags = false;
+            if (restorecon(args[i].c_str(), flag) < 0) {
+                ret = -errno;
+            }
         }
     }
     return ret;
 }
 
+static int do_restorecon_recursive(const std::vector<std::string>& args) {
+    std::vector<std::string> non_const_args(args);
+    non_const_args.insert(std::next(non_const_args.begin()), "--recursive");
+    return do_restorecon(non_const_args);
+}
+
 static int do_loglevel(const std::vector<std::string>& args) {
-    int log_level = std::stoi(args[1]);
-    if (log_level < KLOG_ERROR_LEVEL || log_level > KLOG_DEBUG_LEVEL) {
-        ERROR("loglevel: invalid log level'%d'\n", log_level);
-        return -EINVAL;
+    // TODO: support names instead/as well?
+    int log_level = -1;
+    android::base::ParseInt(args[1], &log_level);
+    android::base::LogSeverity severity;
+    switch (log_level) {
+        case 7: severity = android::base::DEBUG; break;
+        case 6: severity = android::base::INFO; break;
+        case 5:
+        case 4: severity = android::base::WARNING; break;
+        case 3: severity = android::base::ERROR; break;
+        case 2:
+        case 1:
+        case 0: severity = android::base::FATAL; break;
+        default:
+            LOG(ERROR) << "loglevel: invalid log level " << log_level;
+            return -EINVAL;
     }
-    klog_set_level(log_level);
+    android::base::SetMinimumLogSeverity(severity);
     return 0;
 }
 
@@ -956,11 +989,14 @@
 
 static int do_wait(const std::vector<std::string>& args) {
     if (args.size() == 2) {
-        return wait_for_file(args[1].c_str(), COMMAND_RETRY_TIMEOUT);
+        return wait_for_file(args[1].c_str(), kCommandRetryTimeout);
     } else if (args.size() == 3) {
-        return wait_for_file(args[1].c_str(), std::stoi(args[2]));
-    } else
-        return -1;
+        int timeout;
+        if (android::base::ParseInt(args[2], &timeout)) {
+            return wait_for_file(args[1].c_str(), std::chrono::seconds(timeout));
+        }
+    }
+    return -1;
 }
 
 /*
diff --git a/init/capabilities.cpp b/init/capabilities.cpp
new file mode 100644
index 0000000..4592adc
--- /dev/null
+++ b/init/capabilities.cpp
@@ -0,0 +1,166 @@
+// 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 "capabilities.h"
+
+#include <sys/capability.h>
+#include <sys/prctl.h>
+
+#include <map>
+#include <memory>
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+
+#define CAP_MAP_ENTRY(cap) { #cap, CAP_##cap }
+
+namespace {
+const std::map<std::string, int> cap_map = {
+    CAP_MAP_ENTRY(CHOWN),
+    CAP_MAP_ENTRY(DAC_OVERRIDE),
+    CAP_MAP_ENTRY(DAC_READ_SEARCH),
+    CAP_MAP_ENTRY(FOWNER),
+    CAP_MAP_ENTRY(FSETID),
+    CAP_MAP_ENTRY(KILL),
+    CAP_MAP_ENTRY(SETGID),
+    CAP_MAP_ENTRY(SETUID),
+    CAP_MAP_ENTRY(SETPCAP),
+    CAP_MAP_ENTRY(LINUX_IMMUTABLE),
+    CAP_MAP_ENTRY(NET_BIND_SERVICE),
+    CAP_MAP_ENTRY(NET_BROADCAST),
+    CAP_MAP_ENTRY(NET_ADMIN),
+    CAP_MAP_ENTRY(NET_RAW),
+    CAP_MAP_ENTRY(IPC_LOCK),
+    CAP_MAP_ENTRY(IPC_OWNER),
+    CAP_MAP_ENTRY(SYS_MODULE),
+    CAP_MAP_ENTRY(SYS_RAWIO),
+    CAP_MAP_ENTRY(SYS_CHROOT),
+    CAP_MAP_ENTRY(SYS_PTRACE),
+    CAP_MAP_ENTRY(SYS_PACCT),
+    CAP_MAP_ENTRY(SYS_ADMIN),
+    CAP_MAP_ENTRY(SYS_BOOT),
+    CAP_MAP_ENTRY(SYS_NICE),
+    CAP_MAP_ENTRY(SYS_RESOURCE),
+    CAP_MAP_ENTRY(SYS_TIME),
+    CAP_MAP_ENTRY(SYS_TTY_CONFIG),
+    CAP_MAP_ENTRY(MKNOD),
+    CAP_MAP_ENTRY(LEASE),
+    CAP_MAP_ENTRY(AUDIT_WRITE),
+    CAP_MAP_ENTRY(AUDIT_CONTROL),
+    CAP_MAP_ENTRY(SETFCAP),
+    CAP_MAP_ENTRY(MAC_OVERRIDE),
+    CAP_MAP_ENTRY(MAC_ADMIN),
+    CAP_MAP_ENTRY(SYSLOG),
+    CAP_MAP_ENTRY(WAKE_ALARM),
+    CAP_MAP_ENTRY(BLOCK_SUSPEND),
+    CAP_MAP_ENTRY(AUDIT_READ),
+};
+
+static_assert(CAP_LAST_CAP == CAP_AUDIT_READ, "CAP_LAST_CAP is not CAP_AUDIT_READ");
+
+bool DropBoundingSet(const CapSet& to_keep) {
+    for (size_t cap = 0; cap < to_keep.size(); ++cap) {
+        if (to_keep.test(cap)) {
+            // No need to drop this capability.
+            continue;
+        }
+        if (cap_drop_bound(cap) == -1) {
+            PLOG(ERROR) << "cap_drop_bound(" << cap << ") failed";
+            return false;
+        }
+    }
+    return true;
+}
+
+bool SetProcCaps(const CapSet& to_keep, bool add_setpcap) {
+    cap_t caps = cap_init();
+    auto deleter = [](cap_t* p) { cap_free(*p); };
+    std::unique_ptr<cap_t, decltype(deleter)> ptr_caps(&caps, deleter);
+
+    cap_clear(caps);
+    cap_value_t value[1];
+    for (size_t cap = 0; cap <= to_keep.size(); ++cap) {
+        if (to_keep.test(cap)) {
+            value[0] = cap;
+            if (cap_set_flag(caps, CAP_INHERITABLE, arraysize(value), value, CAP_SET) != 0 ||
+                cap_set_flag(caps, CAP_PERMITTED, arraysize(value), value, CAP_SET) != 0) {
+                PLOG(ERROR) << "cap_set_flag(INHERITABLE|PERMITTED, " << cap << ") failed";
+                return false;
+            }
+        }
+    }
+
+    if (add_setpcap) {
+        value[0] = CAP_SETPCAP;
+        if (cap_set_flag(caps, CAP_PERMITTED, arraysize(value), value, CAP_SET) != 0 ||
+            cap_set_flag(caps, CAP_EFFECTIVE, arraysize(value), value, CAP_SET) != 0) {
+            PLOG(ERROR) << "cap_set_flag(PERMITTED|EFFECTIVE, " << CAP_SETPCAP << ") failed";
+            return false;
+        }
+    }
+
+    if (cap_set_proc(caps) != 0) {
+        PLOG(ERROR) << "cap_set_proc(" << to_keep.to_ulong() << ") failed";
+        return false;
+    }
+    return true;
+}
+
+bool SetAmbientCaps(const CapSet& to_raise) {
+    for (size_t cap = 0; cap < to_raise.size(); ++cap) {
+        if (to_raise.test(cap)) {
+            if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0) != 0) {
+                PLOG(ERROR) << "prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, " << cap << ") failed";
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+}  // namespace anonymous
+
+int LookupCap(const std::string& cap_name) {
+    auto e = cap_map.find(cap_name);
+    if (e != cap_map.end()) {
+        return e->second;
+    } else {
+        return -1;
+    }
+}
+
+bool SetCapsForExec(const CapSet& to_keep) {
+    // Need to keep SETPCAP to drop bounding set below.
+    bool add_setpcap = true;
+    if (!SetProcCaps(to_keep, add_setpcap)) {
+        LOG(ERROR) << "failed to apply initial capset";
+        return false;
+    }
+
+    if (!DropBoundingSet(to_keep)) {
+        return false;
+    }
+
+    // If SETPCAP wasn't specifically requested, drop it now.
+    add_setpcap = false;
+    if (!SetProcCaps(to_keep, add_setpcap)) {
+        LOG(ERROR) << "failed to apply final capset";
+        return false;
+    }
+
+    // Add the capabilities to the ambient set so that they are preserved across
+    // execve(2).
+    // See http://man7.org/linux/man-pages/man7/capabilities.7.html.
+    return SetAmbientCaps(to_keep);
+}
diff --git a/init/capabilities.h b/init/capabilities.h
new file mode 100644
index 0000000..368178d
--- /dev/null
+++ b/init/capabilities.h
@@ -0,0 +1,23 @@
+// 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 <linux/capability.h>
+
+#include <bitset>
+#include <string>
+
+using CapSet = std::bitset<CAP_LAST_CAP + 1>;
+
+int LookupCap(const std::string& cap_name);
+bool SetCapsForExec(const CapSet& to_keep);
diff --git a/init/descriptors.cpp b/init/descriptors.cpp
new file mode 100644
index 0000000..429a76e
--- /dev/null
+++ b/init/descriptors.cpp
@@ -0,0 +1,104 @@
+/*
+ * 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 "descriptors.h"
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android-base/stringprintf.h>
+#include <cutils/android_get_control_file.h>
+#include <cutils/sockets.h>
+
+#include "init.h"
+#include "log.h"
+#include "util.h"
+
+DescriptorInfo::DescriptorInfo(const std::string& name, const std::string& type, uid_t uid,
+                               gid_t gid, int perm, const std::string& context)
+        : name_(name), type_(type), uid_(uid), gid_(gid), perm_(perm), context_(context) {
+}
+
+DescriptorInfo::~DescriptorInfo() {
+}
+
+std::ostream& operator<<(std::ostream& os, const DescriptorInfo& info) {
+  return os << "  descriptors " << info.name_ << " " << info.type_ << " " << std::oct << info.perm_;
+}
+
+bool DescriptorInfo::operator==(const DescriptorInfo& other) const {
+  return name_ == other.name_ && type_ == other.type_ && key() == other.key();
+}
+
+void DescriptorInfo::CreateAndPublish(const std::string& globalContext) const {
+  // Create
+  const std::string& contextStr = context_.empty() ? globalContext : context_;
+  int fd = Create(contextStr);
+  if (fd < 0) return;
+
+  // Publish
+  std::string publishedName = key() + name_;
+  std::for_each(publishedName.begin(), publishedName.end(),
+                [] (char& c) { c = isalnum(c) ? c : '_'; });
+
+  std::string val = android::base::StringPrintf("%d", fd);
+  add_environment(publishedName.c_str(), val.c_str());
+
+  // make sure we don't close on exec
+  fcntl(fd, F_SETFD, 0);
+}
+
+void DescriptorInfo::Clean() const {
+}
+
+SocketInfo::SocketInfo(const std::string& name, const std::string& type, uid_t uid,
+                       gid_t gid, int perm, const std::string& context)
+        : DescriptorInfo(name, type, uid, gid, perm, context) {
+}
+
+void SocketInfo::Clean() const {
+  unlink(android::base::StringPrintf(ANDROID_SOCKET_DIR "/%s", name().c_str()).c_str());
+}
+
+int SocketInfo::Create(const std::string& context) const {
+  int flags = ((type() == "stream" ? SOCK_STREAM :
+                (type() == "dgram" ? SOCK_DGRAM :
+                 SOCK_SEQPACKET)));
+  return create_socket(name().c_str(), flags, perm(), uid(), gid(), context.c_str());
+}
+
+const std::string SocketInfo::key() const {
+  return ANDROID_SOCKET_ENV_PREFIX;
+}
+
+FileInfo::FileInfo(const std::string& name, const std::string& type, uid_t uid,
+                   gid_t gid, int perm, const std::string& context)
+        : DescriptorInfo(name, type, uid, gid, perm, context) {
+}
+
+int FileInfo::Create(const std::string& context) const {
+  int flags = ((type() == "r" ? O_RDONLY :
+                (type() == "w" ? (O_WRONLY | O_CREAT) :
+                 (O_RDWR | O_CREAT))));
+  return create_file(name().c_str(), flags, perm(), uid(), gid(), context.c_str());
+}
+
+const std::string FileInfo::key() const {
+  return ANDROID_FILE_ENV_PREFIX;
+}
diff --git a/init/descriptors.h b/init/descriptors.h
new file mode 100644
index 0000000..ff276fb
--- /dev/null
+++ b/init/descriptors.h
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+
+#ifndef _INIT_DESCRIPTORS_H
+#define _INIT_DESCRIPTORS_H
+
+#include <sys/types.h>
+
+#include <string>
+
+class DescriptorInfo {
+ public:
+  DescriptorInfo(const std::string& name, const std::string& type, uid_t uid,
+                 gid_t gid, int perm, const std::string& context);
+  virtual ~DescriptorInfo();
+
+  friend std::ostream& operator<<(std::ostream& os, const class DescriptorInfo& info);
+  bool operator==(const DescriptorInfo& other) const;
+
+  void CreateAndPublish(const std::string& globalContext) const;
+  virtual void Clean() const;
+
+ protected:
+  const std::string& name() const { return name_; }
+  const std::string& type() const { return type_; }
+  uid_t uid() const { return uid_; }
+  gid_t gid() const { return gid_; }
+  int perm() const { return perm_; }
+  const std::string& context() const { return context_; }
+
+ private:
+  std::string name_;
+  std::string type_;
+  uid_t uid_;
+  gid_t gid_;
+  int perm_;
+  std::string context_;
+
+  virtual int Create(const std::string& globalContext) const = 0;
+  virtual const std::string key() const = 0;
+};
+
+std::ostream& operator<<(std::ostream& os, const DescriptorInfo& info);
+
+class SocketInfo : public DescriptorInfo {
+ public:
+  SocketInfo(const std::string& name, const std::string& type, uid_t uid,
+             gid_t gid, int perm, const std::string& context);
+  void Clean() const override;
+ private:
+  virtual int Create(const std::string& context) const override;
+  virtual const std::string key() const override;
+};
+
+class FileInfo : public DescriptorInfo {
+ public:
+  FileInfo(const std::string& name, const std::string& type, uid_t uid,
+           gid_t gid, int perm, const std::string& context);
+ private:
+  virtual int Create(const std::string& context) const override;
+  virtual const std::string key() const override;
+};
+
+#endif
diff --git a/init/devices.cpp b/init/devices.cpp
index cffc561..2db24b7 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -14,33 +14,39 @@
  * limitations under the License.
  */
 
+#include <dirent.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <fnmatch.h>
+#include <libgen.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <fcntl.h>
-#include <dirent.h>
-#include <unistd.h>
 #include <string.h>
-
+#include <sys/sendfile.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
 #include <sys/un.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
 #include <linux/netlink.h>
 
+#include <memory>
+#include <thread>
+
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 #include <selinux/android.h>
 #include <selinux/avc.h>
 
 #include <private/android_filesystem_config.h>
-#include <sys/time.h>
-#include <sys/wait.h>
 
 #include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
 #include <cutils/list.h>
 #include <cutils/uevent.h>
 
@@ -105,13 +111,18 @@
         return -ENOMEM;
 
     node->dp.name = strdup(name);
-    if (!node->dp.name)
+    if (!node->dp.name) {
+        free(node);
         return -ENOMEM;
+    }
 
     if (attr) {
         node->dp.attr = strdup(attr);
-        if (!node->dp.attr)
+        if (!node->dp.attr) {
+            free(node->dp.name);
+            free(node);
             return -ENOMEM;
+        }
     }
 
     node->dp.perm = perm;
@@ -128,49 +139,6 @@
     return 0;
 }
 
-void fixup_sys_perms(const char *upath)
-{
-    char buf[512];
-    struct listnode *node;
-    struct perms_ *dp;
-
-    /* upaths omit the "/sys" that paths in this list
-     * contain, so we add 4 when comparing...
-     */
-    list_for_each(node, &sys_perms) {
-        dp = &(node_to_item(node, struct perm_node, plist))->dp;
-        if (dp->prefix) {
-            if (strncmp(upath, dp->name + 4, strlen(dp->name + 4)))
-                continue;
-        } else if (dp->wildcard) {
-            if (fnmatch(dp->name + 4, upath, FNM_PATHNAME) != 0)
-                continue;
-        } else {
-            if (strcmp(upath, dp->name + 4))
-                continue;
-        }
-
-        if ((strlen(upath) + strlen(dp->attr) + 6) > sizeof(buf))
-            break;
-
-        snprintf(buf, sizeof(buf), "/sys%s/%s", upath, dp->attr);
-        INFO("fixup %s %d %d 0%o\n", buf, dp->uid, dp->gid, dp->perm);
-        chown(buf, dp->uid, dp->gid);
-        chmod(buf, dp->perm);
-    }
-
-    // Now fixup SELinux file labels
-    int len = snprintf(buf, sizeof(buf), "/sys%s", upath);
-    if ((len < 0) || ((size_t) len >= sizeof(buf))) {
-        // Overflow
-        return;
-    }
-    if (access(buf, F_OK) == 0) {
-        INFO("restorecon_recursive: %s\n", buf);
-        restorecon_recursive(buf);
-    }
-}
-
 static bool perm_path_matches(const char *path, struct perms_ *dp)
 {
     if (dp->prefix) {
@@ -187,6 +155,45 @@
     return false;
 }
 
+static bool match_subsystem(perms_* dp, const char* pattern,
+                            const char* path, const char* subsystem) {
+    if (!pattern || !subsystem || strstr(dp->name, subsystem) == NULL) {
+        return false;
+    }
+
+    std::string subsys_path = android::base::StringPrintf(pattern, subsystem, basename(path));
+    return perm_path_matches(subsys_path.c_str(), dp);
+}
+
+static void fixup_sys_perms(const char* upath, const char* subsystem) {
+    // upaths omit the "/sys" that paths in this list
+    // contain, so we prepend it...
+    std::string path = std::string(SYSFS_PREFIX) + upath;
+
+    listnode* node;
+    list_for_each(node, &sys_perms) {
+        perms_* dp = &(node_to_item(node, perm_node, plist))->dp;
+        if (match_subsystem(dp, SYSFS_PREFIX "/class/%s/%s", path.c_str(), subsystem)) {
+            ; // matched
+        } else if (match_subsystem(dp, SYSFS_PREFIX "/bus/%s/devices/%s", path.c_str(), subsystem)) {
+            ; // matched
+        } else if (!perm_path_matches(path.c_str(), dp)) {
+            continue;
+        }
+
+        std::string attr_file = path + "/" + dp->attr;
+        LOG(INFO) << "fixup " << attr_file
+                  << " " << dp->uid << " " << dp->gid << " " << std::oct << dp->perm;
+        chown(attr_file.c_str(), dp->uid, dp->gid);
+        chmod(attr_file.c_str(), dp->perm);
+    }
+
+    if (access(path.c_str(), F_OK) == 0) {
+        LOG(VERBOSE) << "restorecon_recursive: " << path;
+        restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
+    }
+}
+
 static mode_t get_device_perm(const char *path, const char **links,
                 unsigned *uid, unsigned *gid)
 {
@@ -243,8 +250,7 @@
     mode = get_device_perm(path, links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
 
     if (selabel_lookup_best_match(sehandle, &secontext, path, links, mode)) {
-        ERROR("Device '%s' not created; cannot find SELinux label (%s)\n",
-                path, strerror(errno));
+        PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
         return;
     }
     setfscreatecon(secontext);
@@ -259,11 +265,23 @@
     /* If the node already exists update its SELinux label to handle cases when
      * it was created with the wrong context during coldboot procedure. */
     if (mknod(path, mode, dev) && (errno == EEXIST)) {
-        if (lsetfilecon(path, secontext)) {
-            ERROR("Cannot set '%s' SELinux label on '%s' device (%s)\n",
-                    secontext, path, strerror(errno));
+
+        char* fcon = nullptr;
+        int rc = lgetfilecon(path, &fcon);
+        if (rc < 0) {
+            PLOG(ERROR) << "Cannot get SELinux label on '" << path << "' device";
+            goto out;
+        }
+
+        bool different = strcmp(fcon, secontext) != 0;
+        freecon(fcon);
+
+        if (different && lsetfilecon(path, secontext)) {
+            PLOG(ERROR) << "Cannot set '" << secontext << "' SELinux label on '" << path << "' device";
         }
     }
+
+out:
     chown(path, uid, -1);
     setegid(AID_ROOT);
 
@@ -283,7 +301,7 @@
             name += 9;
     }
 
-    INFO("adding platform device %s (%s)\n", name, path);
+    LOG(VERBOSE) << "adding platform device " << name << " (" << path << ")";
 
     bus = (platform_node*) calloc(1, sizeof(struct platform_node));
     bus->path = strdup(path);
@@ -322,7 +340,7 @@
     list_for_each_reverse(node, &platform_names) {
         bus = node_to_item(node, struct platform_node, list);
         if (!strcmp(path, bus->path)) {
-            INFO("removing platform device %s\n", bus->name);
+            LOG(INFO) << "removing platform device " << bus->name;
             free(bus->path);
             list_remove(node);
             free(bus);
@@ -411,16 +429,16 @@
     }
 
     if (LOG_UEVENTS) {
-        INFO("event { '%s', '%s', '%s', '%s', %d, %d }\n",
-             uevent->action, uevent->path, uevent->subsystem,
-             uevent->firmware, uevent->major, uevent->minor);
+        LOG(INFO) << android::base::StringPrintf("event { '%s', '%s', '%s', '%s', %d, %d }",
+                                                 uevent->action, uevent->path, uevent->subsystem,
+                                                 uevent->firmware, uevent->major, uevent->minor);
     }
 }
 
 static char **get_character_device_symlinks(struct uevent *uevent)
 {
     const char *parent;
-    char *slash;
+    const char *slash;
     char **links;
     int link_num = 0;
     int width;
@@ -474,7 +492,7 @@
 {
     const char *device;
     struct platform_node *pdev;
-    char *slash;
+    const char *slash;
     const char *type;
     char buf[256];
     char link_path[256];
@@ -497,15 +515,16 @@
         return NULL;
     memset(links, 0, sizeof(char *) * 4);
 
-    INFO("found %s device %s\n", type, device);
+    LOG(INFO) << "found " << type << " device " << device;
 
     snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device);
 
     if (uevent->partition_name) {
         p = strdup(uevent->partition_name);
         sanitize(p);
-        if (strcmp(uevent->partition_name, p))
-            NOTICE("Linking partition '%s' as '%s'\n", uevent->partition_name, p);
+        if (strcmp(uevent->partition_name, p)) {
+            LOG(VERBOSE) << "Linking partition '" << uevent->partition_name << "' as '" << p << "'";
+        }
         if (asprintf(&links[link_num], "%s/by-name/%s", link_path, p) > 0)
             link_num++;
         else
@@ -529,30 +548,49 @@
     return links;
 }
 
+static void make_link_init(const char* oldpath, const char* newpath) {
+  const char* slash = strrchr(newpath, '/');
+  if (!slash) return;
+
+  if (mkdir_recursive(dirname(newpath), 0755)) {
+    PLOG(ERROR) << "Failed to create directory " << dirname(newpath);
+  }
+
+  if (symlink(oldpath, newpath) && errno != EEXIST) {
+    PLOG(ERROR) << "Failed to symlink " << oldpath << " to " << newpath;
+  }
+}
+
+static void remove_link(const char* oldpath, const char* newpath) {
+  std::string path;
+  if (android::base::Readlink(newpath, &path) && path == oldpath) unlink(newpath);
+}
+
 static void handle_device(const char *action, const char *devpath,
         const char *path, int block, int major, int minor, char **links)
 {
-    int i;
-
     if(!strcmp(action, "add")) {
         make_device(devpath, path, block, major, minor, (const char **)links);
         if (links) {
-            for (i = 0; links[i]; i++)
+            for (int i = 0; links[i]; i++) {
                 make_link_init(devpath, links[i]);
+            }
         }
     }
 
     if(!strcmp(action, "remove")) {
         if (links) {
-            for (i = 0; links[i]; i++)
+            for (int i = 0; links[i]; i++) {
                 remove_link(devpath, links[i]);
+            }
         }
         unlink(devpath);
     }
 
     if (links) {
-        for (i = 0; links[i]; i++)
+        for (int i = 0; links[i]; i++) {
             free(links[i]);
+        }
         free(links);
     }
 }
@@ -583,22 +621,24 @@
 
     /* too-long names would overrun our buffer */
     if(strlen(name) > len) {
-        ERROR("DEVPATH=%s exceeds %u-character limit on filename; ignoring event\n",
-                name, len);
+        LOG(ERROR) << "DEVPATH=" << name << " exceeds " << len << "-character limit on filename; ignoring event";
         return NULL;
     }
 
     return name;
 }
 
+#define DEVPATH_LEN 96
+#define MAX_DEV_NAME 64
+
 static void handle_block_device_event(struct uevent *uevent)
 {
     const char *base = "/dev/block/";
     const char *name;
-    char devpath[96];
+    char devpath[DEVPATH_LEN];
     char **links = NULL;
 
-    name = parse_device_name(uevent, 64);
+    name = parse_device_name(uevent, MAX_DEV_NAME);
     if (!name)
         return;
 
@@ -612,19 +652,16 @@
             uevent->major, uevent->minor, links);
 }
 
-#define DEVPATH_LEN 96
-
 static bool assemble_devpath(char *devpath, const char *dirname,
         const char *devname)
 {
     int s = snprintf(devpath, DEVPATH_LEN, "%s/%s", dirname, devname);
     if (s < 0) {
-        ERROR("failed to assemble device path (%s); ignoring event\n",
-                strerror(errno));
+        PLOG(ERROR) << "failed to assemble device path; ignoring event";
         return false;
     } else if (s >= DEVPATH_LEN) {
-        ERROR("%s/%s exceeds %u-character limit on path; ignoring event\n",
-                dirname, devname, DEVPATH_LEN);
+        LOG(ERROR) << dirname << "/" << devname
+                   << " exceeds " << DEVPATH_LEN << "-character limit on path; ignoring event";
         return false;
     }
     return true;
@@ -648,7 +685,7 @@
     char devpath[DEVPATH_LEN] = {0};
     char **links = NULL;
 
-    name = parse_device_name(uevent, 64);
+    name = parse_device_name(uevent, MAX_DEV_NAME);
     if (!name)
         return;
 
@@ -668,8 +705,7 @@
             break;
 
         default:
-            ERROR("%s subsystem's devpath option is not set; ignoring event\n",
-                    uevent->subsystem);
+            LOG(ERROR) << uevent->subsystem << " subsystem's devpath option is not set; ignoring event";
             return;
         }
 
@@ -725,9 +761,8 @@
      } else if(!strncmp(uevent->subsystem, "sound", 5)) {
          base = "/dev/snd/";
          make_dir(base, 0755);
-     } else if(!strncmp(uevent->subsystem, "misc", 4) &&
-                 !strncmp(name, "log_", 4)) {
-         INFO("kernel logger is deprecated\n");
+     } else if(!strncmp(uevent->subsystem, "misc", 4) && !strncmp(name, "log_", 4)) {
+         LOG(INFO) << "kernel logger is deprecated";
          base = "/dev/log/";
          make_dir(base, 0755);
          name += 4;
@@ -745,7 +780,7 @@
 static void handle_device_event(struct uevent *uevent)
 {
     if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change") || !strcmp(uevent->action, "online"))
-        fixup_sys_perms(uevent->path);
+        fixup_sys_perms(uevent->path, uevent->subsystem);
 
     if (!strncmp(uevent->subsystem, "block", 5)) {
         handle_block_device_event(uevent);
@@ -756,144 +791,93 @@
     }
 }
 
-static int load_firmware(int fw_fd, int loading_fd, int data_fd)
-{
-    struct stat st;
-    long len_to_copy;
-    int ret = 0;
+static void load_firmware(uevent* uevent, const std::string& root,
+                          int fw_fd, size_t fw_size,
+                          int loading_fd, int data_fd) {
+    // Start transfer.
+    android::base::WriteFully(loading_fd, "1", 1);
 
-    if(fstat(fw_fd, &st) < 0)
-        return -1;
-    len_to_copy = st.st_size;
-
-    write(loading_fd, "1", 1);  /* start transfer */
-
-    while (len_to_copy > 0) {
-        char buf[PAGE_SIZE];
-        ssize_t nr;
-
-        nr = read(fw_fd, buf, sizeof(buf));
-        if(!nr)
-            break;
-        if(nr < 0) {
-            ret = -1;
-            break;
-        }
-        if (!android::base::WriteFully(data_fd, buf, nr)) {
-            ret = -1;
-            break;
-        }
-        len_to_copy -= nr;
+    // Copy the firmware.
+    int rc = sendfile(data_fd, fw_fd, nullptr, fw_size);
+    if (rc == -1) {
+        PLOG(ERROR) << "firmware: sendfile failed { '" << root << "', '" << uevent->firmware << "' }";
     }
 
-    if(!ret)
-        write(loading_fd, "0", 1);  /* successful end of transfer */
-    else
-        write(loading_fd, "-1", 2); /* abort transfer */
-
-    return ret;
+    // Tell the firmware whether to abort or commit.
+    const char* response = (rc != -1) ? "0" : "-1";
+    android::base::WriteFully(loading_fd, response, strlen(response));
 }
 
-static int is_booting(void)
-{
+static int is_booting() {
     return access("/dev/.booting", F_OK) == 0;
 }
 
-static void process_firmware_event(struct uevent *uevent)
-{
-    char *root, *loading, *data;
-    int l, loading_fd, data_fd, fw_fd;
-    size_t i;
+static void process_firmware_event(uevent* uevent) {
     int booting = is_booting();
 
-    INFO("firmware: loading '%s' for '%s'\n",
-         uevent->firmware, uevent->path);
+    LOG(INFO) << "firmware: loading '" << uevent->firmware << "' for '" << uevent->path << "'";
 
-    l = asprintf(&root, SYSFS_PREFIX"%s/", uevent->path);
-    if (l == -1)
+    std::string root = android::base::StringPrintf("/sys%s", uevent->path);
+    std::string loading = root + "/loading";
+    std::string data = root + "/data";
+
+    android::base::unique_fd loading_fd(open(loading.c_str(), O_WRONLY|O_CLOEXEC));
+    if (loading_fd == -1) {
+        PLOG(ERROR) << "couldn't open firmware loading fd for " << uevent->firmware;
         return;
+    }
 
-    l = asprintf(&loading, "%sloading", root);
-    if (l == -1)
-        goto root_free_out;
-
-    l = asprintf(&data, "%sdata", root);
-    if (l == -1)
-        goto loading_free_out;
-
-    loading_fd = open(loading, O_WRONLY|O_CLOEXEC);
-    if(loading_fd < 0)
-        goto data_free_out;
-
-    data_fd = open(data, O_WRONLY|O_CLOEXEC);
-    if(data_fd < 0)
-        goto loading_close_out;
+    android::base::unique_fd data_fd(open(data.c_str(), O_WRONLY|O_CLOEXEC));
+    if (data_fd == -1) {
+        PLOG(ERROR) << "couldn't open firmware data fd for " << uevent->firmware;
+        return;
+    }
 
 try_loading_again:
-    for (i = 0; i < ARRAY_SIZE(firmware_dirs); i++) {
-        char *file = NULL;
-        l = asprintf(&file, "%s/%s", firmware_dirs[i], uevent->firmware);
-        if (l == -1)
-            goto data_free_out;
-        fw_fd = open(file, O_RDONLY|O_CLOEXEC);
-        free(file);
-        if (fw_fd >= 0) {
-            if(!load_firmware(fw_fd, loading_fd, data_fd))
-                INFO("firmware: copy success { '%s', '%s' }\n", root, uevent->firmware);
-            else
-                INFO("firmware: copy failure { '%s', '%s' }\n", root, uevent->firmware);
-            break;
+    for (size_t i = 0; i < arraysize(firmware_dirs); i++) {
+        std::string file = android::base::StringPrintf("%s/%s", firmware_dirs[i], uevent->firmware);
+        android::base::unique_fd fw_fd(open(file.c_str(), O_RDONLY|O_CLOEXEC));
+        struct stat sb;
+        if (fw_fd != -1 && fstat(fw_fd, &sb) != -1) {
+            load_firmware(uevent, root, fw_fd, sb.st_size, loading_fd, data_fd);
+            return;
         }
     }
-    if (fw_fd < 0) {
-        if (booting) {
-            /* If we're not fully booted, we may be missing
-             * filesystems needed for firmware, wait and retry.
-             */
-            usleep(100000);
-            booting = is_booting();
-            goto try_loading_again;
-        }
-        INFO("firmware: could not open '%s': %s\n", uevent->firmware, strerror(errno));
-        write(loading_fd, "-1", 2);
-        goto data_close_out;
-    }
 
-    close(fw_fd);
-data_close_out:
-    close(data_fd);
-loading_close_out:
-    close(loading_fd);
-data_free_out:
-    free(data);
-loading_free_out:
-    free(loading);
-root_free_out:
-    free(root);
+    if (booting) {
+        // If we're not fully booted, we may be missing
+        // filesystems needed for firmware, wait and retry.
+        std::this_thread::sleep_for(100ms);
+        booting = is_booting();
+        goto try_loading_again;
+    }
+
+    LOG(ERROR) << "firmware: could not find firmware for " << uevent->firmware;
+
+    // Write "-1" as our response to the kernel's firmware request, since we have nothing for it.
+    write(loading_fd, "-1", 2);
 }
 
-static void handle_firmware_event(struct uevent *uevent)
-{
-    pid_t pid;
+static void handle_firmware_event(uevent* uevent) {
+    if (strcmp(uevent->subsystem, "firmware")) return;
+    if (strcmp(uevent->action, "add")) return;
 
-    if(strcmp(uevent->subsystem, "firmware"))
-        return;
-
-    if(strcmp(uevent->action, "add"))
-        return;
-
-    /* we fork, to avoid making large memory allocations in init proper */
-    pid = fork();
-    if (!pid) {
+    // Loading the firmware in a child means we can do that in parallel...
+    // (We ignore SIGCHLD rather than wait for our children.)
+    pid_t pid = fork();
+    if (pid == 0) {
+        Timer t;
         process_firmware_event(uevent);
+        LOG(INFO) << "loading " << uevent->path << " took " << t.duration() << "s";
         _exit(EXIT_SUCCESS);
-    } else if (pid < 0) {
-        ERROR("could not fork to process firmware event: %s\n", strerror(errno));
+    } else if (pid == -1) {
+        PLOG(ERROR) << "could not fork to process firmware event for " << uevent->firmware;
     }
 }
 
 #define UEVENT_MSG_LEN  2048
-void handle_device_fd()
+
+static inline void handle_device_fd_with(void (handle_uevent)(struct uevent*))
 {
     char msg[UEVENT_MSG_LEN+2];
     int n;
@@ -906,21 +890,28 @@
 
         struct uevent uevent;
         parse_event(msg, &uevent);
-
-        if (selinux_status_updated() > 0) {
-            struct selabel_handle *sehandle2;
-            sehandle2 = selinux_android_file_context_handle();
-            if (sehandle2) {
-                selabel_close(sehandle);
-                sehandle = sehandle2;
-            }
-        }
-
-        handle_device_event(&uevent);
-        handle_firmware_event(&uevent);
+        handle_uevent(&uevent);
     }
 }
 
+void handle_device_fd()
+{
+    handle_device_fd_with(
+        [](struct uevent *uevent) {
+            if (selinux_status_updated() > 0) {
+                struct selabel_handle *sehandle2;
+                sehandle2 = selinux_android_file_context_handle();
+                if (sehandle2) {
+                    selabel_close(sehandle);
+                    sehandle = sehandle2;
+                }
+            }
+
+            handle_device_event(uevent);
+            handle_firmware_event(uevent);
+        });
+}
+
 /* Coldboot walks parts of the /sys tree and pokes the uevent files
 ** to cause the kernel to regenerate device add events that happened
 ** before init's device manager was started
@@ -966,13 +957,71 @@
 
 static void coldboot(const char *path)
 {
-    DIR *d = opendir(path);
+    std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path), closedir);
     if(d) {
-        do_coldboot(d);
-        closedir(d);
+        do_coldboot(d.get());
     }
 }
 
+static void early_uevent_handler(struct uevent *uevent, const char *base, bool is_block)
+{
+    const char *name;
+    char devpath[DEVPATH_LEN];
+
+    if (is_block && strncmp(uevent->subsystem, "block", 5))
+        return;
+
+    name = parse_device_name(uevent, MAX_DEV_NAME);
+    if (!name) {
+        LOG(ERROR) << "Failed to parse dev name from uevent: " << uevent->action
+                   << " " << uevent->partition_name << " " << uevent->partition_num
+                   << " " << uevent->major << ":" << uevent->minor;
+        return;
+    }
+
+    snprintf(devpath, sizeof(devpath), "%s%s", base, name);
+    make_dir(base, 0755);
+
+    dev_t dev = makedev(uevent->major, uevent->minor);
+    mode_t mode = 0600 | (is_block ? S_IFBLK : S_IFCHR);
+    mknod(devpath, mode, dev);
+}
+
+void early_create_dev(const std::string& syspath, early_device_type dev_type)
+{
+    android::base::unique_fd dfd(open(syspath.c_str(), O_RDONLY));
+    if (dfd < 0) {
+        LOG(ERROR) << "Failed to open " << syspath;
+        return;
+    }
+
+    android::base::unique_fd fd(openat(dfd, "uevent", O_WRONLY));
+    if (fd < 0) {
+        LOG(ERROR) << "Failed to open " << syspath << "/uevent";
+        return;
+    }
+
+    fcntl(device_fd, F_SETFL, O_NONBLOCK);
+
+    write(fd, "add\n", 4);
+    handle_device_fd_with(dev_type == EARLY_BLOCK_DEV ?
+        [](struct uevent *uevent) {
+            early_uevent_handler(uevent, "/dev/block/", true);
+        } :
+        [](struct uevent *uevent) {
+            early_uevent_handler(uevent, "/dev/", false);
+        });
+}
+
+int early_device_socket_open() {
+    device_fd = uevent_open_socket(256*1024, true);
+    return device_fd < 0;
+}
+
+void early_device_socket_close() {
+    close(device_fd);
+}
+
 void device_init() {
     sehandle = selinux_android_file_context_handle();
     selinux_status_open(true);
@@ -985,7 +1034,7 @@
     fcntl(device_fd, F_SETFL, O_NONBLOCK);
 
     if (access(COLDBOOT_DONE, F_OK) == 0) {
-        NOTICE("Skipping coldboot, already done!\n");
+        LOG(VERBOSE) << "Skipping coldboot, already done!";
         return;
     }
 
@@ -994,10 +1043,9 @@
     coldboot("/sys/block");
     coldboot("/sys/devices");
     close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
-    NOTICE("Coldboot took %.2fs.\n", t.duration());
+    LOG(INFO) << "Coldboot took " << t.duration() << "s.";
 }
 
-int get_device_fd()
-{
+int get_device_fd() {
     return device_fd;
 }
diff --git a/init/devices.h b/init/devices.h
index 6cb0a77..8e9ab7d 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -21,6 +21,13 @@
 
 extern void handle_device_fd();
 extern void device_init(void);
+
+enum early_device_type { EARLY_BLOCK_DEV, EARLY_CHAR_DEV };
+
+extern int early_device_socket_open();
+extern void early_device_socket_close();
+extern void early_create_dev(const std::string& syspath, early_device_type dev_type);
+
 extern int add_dev_perms(const char *name, const char *attr,
                          mode_t perm, unsigned int uid,
                          unsigned int gid, unsigned short prefix,
diff --git a/init/import_parser.cpp b/init/import_parser.cpp
index e2a0f83..d52247b 100644
--- a/init/import_parser.cpp
+++ b/init/import_parser.cpp
@@ -38,7 +38,7 @@
         return false;
     }
 
-    INFO("Added '%s' to import list\n", conf_file.c_str());
+    LOG(INFO) << "Added '" << conf_file << "' to import list";
     imports_.emplace_back(std::move(conf_file));
     return true;
 }
@@ -48,8 +48,7 @@
     imports_.clear();
     for (const auto& s : current_imports) {
         if (!Parser::GetInstance().ParseConfig(s)) {
-            ERROR("could not import file '%s' from '%s': %s\n",
-                  s.c_str(), filename.c_str(), strerror(errno));
+            PLOG(ERROR) << "could not import file '" << s << "' from '" << filename << "'";
         }
     }
 }
diff --git a/init/init.cpp b/init/init.cpp
index 84da2b9..734f129 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -18,7 +18,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <fstream>
+#include <inttypes.h>
 #include <libgen.h>
 #include <paths.h>
 #include <signal.h>
@@ -30,13 +30,12 @@
 #include <sys/mount.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
+#include <sys/sysmacros.h>
 #include <sys/types.h>
 #include <sys/un.h>
 #include <sys/wait.h>
 #include <unistd.h>
 
-#include <mtd/mtd-user.h>
-
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 #include <selinux/android.h>
@@ -56,6 +55,7 @@
 #include "action.h"
 #include "bootchart.h"
 #include "devices.h"
+#include "fs_mgr.h"
 #include "import_parser.h"
 #include "init.h"
 #include "init_parser.h"
@@ -68,6 +68,8 @@
 #include "util.h"
 #include "watchdogd.h"
 
+using android::base::StringPrintf;
+
 struct selabel_handle *sehandle;
 struct selabel_handle *sehandle_prop;
 
@@ -75,9 +77,8 @@
 
 static char qemu[32];
 
-int have_console;
-std::string console_name = "/dev/console";
-static time_t process_needs_restart;
+std::string default_console = "/dev/console";
+static time_t process_needs_restart_at;
 
 const char *ENV[32];
 
@@ -90,7 +91,7 @@
     ev.events = EPOLLIN;
     ev.data.ptr = reinterpret_cast<void*>(fn);
     if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
-        ERROR("epoll_ctl failed: %s\n", strerror(errno));
+        PLOG(ERROR) << "epoll_ctl failed";
     }
 }
 
@@ -101,7 +102,7 @@
     size_t key_len = strlen(key);
 
     /* The last environment entry is reserved to terminate the list */
-    for (n = 0; n < (ARRAY_SIZE(ENV) - 1); n++) {
+    for (n = 0; n < (arraysize(ENV) - 1); n++) {
 
         /* Delete any existing entry for this key */
         if (ENV[n] != NULL) {
@@ -121,7 +122,7 @@
         }
     }
 
-    ERROR("No env. room to store: '%s':'%s'\n", key, val);
+    LOG(ERROR) << "No env. room to store: '" << key << "':'" << val << "'";
 
     return -1;
 }
@@ -134,17 +135,16 @@
 
 static void restart_processes()
 {
-    process_needs_restart = 0;
-    ServiceManager::GetInstance().
-        ForEachServiceWithFlags(SVC_RESTARTING, [] (Service* s) {
-                s->RestartIfNeeded(process_needs_restart);
-            });
+    process_needs_restart_at = 0;
+    ServiceManager::GetInstance().ForEachServiceWithFlags(SVC_RESTARTING, [](Service* s) {
+        s->RestartIfNeeded(&process_needs_restart_at);
+    });
 }
 
 void handle_control_message(const std::string& msg, const std::string& name) {
     Service* svc = ServiceManager::GetInstance().FindServiceByName(name);
     if (svc == nullptr) {
-        ERROR("no such service '%s'\n", name.c_str());
+        LOG(ERROR) << "no such service '" << name << "'";
         return;
     }
 
@@ -155,22 +155,22 @@
     } else if (msg == "restart") {
         svc->Restart();
     } else {
-        ERROR("unknown control msg '%s'\n", msg.c_str());
+        LOG(ERROR) << "unknown control msg '" << msg << "'";
     }
 }
 
 static int wait_for_coldboot_done_action(const std::vector<std::string>& args) {
     Timer t;
 
-    NOTICE("Waiting for %s...\n", COLDBOOT_DONE);
+    LOG(VERBOSE) << "Waiting for " COLDBOOT_DONE "...";
     // Any longer than 1s is an unreasonable length of time to delay booting.
     // If you're hitting this timeout, check that you didn't make your
     // sepolicy regular expressions too expensive (http://b/19899875).
-    if (wait_for_file(COLDBOOT_DONE, 1)) {
-        ERROR("Timed out waiting for %s\n", COLDBOOT_DONE);
+    if (wait_for_file(COLDBOOT_DONE, 1s)) {
+        LOG(ERROR) << "Timed out waiting for " COLDBOOT_DONE;
     }
 
-    NOTICE("Waiting for %s took %.2fs.\n", COLDBOOT_DONE, t.duration());
+    LOG(VERBOSE) << "Waiting for " COLDBOOT_DONE " took " << t.duration() << "s.";
     return 0;
 }
 
@@ -202,11 +202,11 @@
             open("/dev/hw_random", O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
     if (hwrandom_fd == -1) {
         if (errno == ENOENT) {
-          ERROR("/dev/hw_random not found\n");
-          /* It's not an error to not have a Hardware RNG. */
-          result = 0;
+            LOG(ERROR) << "/dev/hw_random not found";
+            // It's not an error to not have a Hardware RNG.
+            result = 0;
         } else {
-          ERROR("Failed to open /dev/hw_random: %s\n", strerror(errno));
+            PLOG(ERROR) << "Failed to open /dev/hw_random";
         }
         goto ret;
     }
@@ -214,7 +214,7 @@
     urandom_fd = TEMP_FAILURE_RETRY(
             open("/dev/urandom", O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
     if (urandom_fd == -1) {
-        ERROR("Failed to open /dev/urandom: %s\n", strerror(errno));
+        PLOG(ERROR) << "Failed to open /dev/urandom";
         goto ret;
     }
 
@@ -222,23 +222,22 @@
         chunk_size = TEMP_FAILURE_RETRY(
                 read(hwrandom_fd, buf, sizeof(buf) - total_bytes_written));
         if (chunk_size == -1) {
-            ERROR("Failed to read from /dev/hw_random: %s\n", strerror(errno));
+            PLOG(ERROR) << "Failed to read from /dev/hw_random";
             goto ret;
         } else if (chunk_size == 0) {
-            ERROR("Failed to read from /dev/hw_random: EOF\n");
+            LOG(ERROR) << "Failed to read from /dev/hw_random: EOF";
             goto ret;
         }
 
         chunk_size = TEMP_FAILURE_RETRY(write(urandom_fd, buf, chunk_size));
         if (chunk_size == -1) {
-            ERROR("Failed to write to /dev/urandom: %s\n", strerror(errno));
+            PLOG(ERROR) << "Failed to write to /dev/urandom";
             goto ret;
         }
         total_bytes_written += chunk_size;
     }
 
-    INFO("Mixed %zu bytes from /dev/hw_random into /dev/urandom",
-                total_bytes_written);
+    LOG(INFO) << "Mixed " << total_bytes_written << " bytes from /dev/hw_random into /dev/urandom";
     result = 0;
 
 ret:
@@ -251,100 +250,6 @@
     return result;
 }
 
-static void security_failure() {
-    ERROR("Security failure; rebooting into recovery mode...\n");
-    android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
-    while (true) { pause(); }  // never reached
-}
-
-#define MMAP_RND_PATH "/proc/sys/vm/mmap_rnd_bits"
-#define MMAP_RND_COMPAT_PATH "/proc/sys/vm/mmap_rnd_compat_bits"
-
-/* __attribute__((unused)) due to lack of mips support: see mips block
- * in set_mmap_rnd_bits_action */
-static bool __attribute__((unused)) set_mmap_rnd_bits_min(int start, int min, bool compat) {
-    std::string path;
-    if (compat) {
-        path = MMAP_RND_COMPAT_PATH;
-    } else {
-        path = MMAP_RND_PATH;
-    }
-    std::ifstream inf(path, std::fstream::in);
-    if (!inf) {
-        return false;
-    }
-    while (start >= min) {
-        // try to write out new value
-        std::string str_val = std::to_string(start);
-        std::ofstream of(path, std::fstream::out);
-        if (!of) {
-            return false;
-        }
-        of << str_val << std::endl;
-        of.close();
-
-        // check to make sure it was recorded
-        inf.seekg(0);
-        std::string str_rec;
-        inf >> str_rec;
-        if (str_val.compare(str_rec) == 0) {
-            break;
-        }
-        start--;
-    }
-    inf.close();
-    return (start >= min);
-}
-
-/*
- * Set /proc/sys/vm/mmap_rnd_bits and potentially
- * /proc/sys/vm/mmap_rnd_compat_bits to the maximum supported values.
- * Returns -1 if unable to set these to an acceptable value.  Apply
- * upstream patch-sets https://lkml.org/lkml/2015/12/21/337 and
- * https://lkml.org/lkml/2016/2/4/831 to enable this.
- */
-static int set_mmap_rnd_bits_action(const std::vector<std::string>& args)
-{
-    int ret = -1;
-
-    /* values are arch-dependent */
-#if defined(__aarch64__)
-    /* arm64 supports 18 - 33 bits depending on pagesize and VA_SIZE */
-    if (set_mmap_rnd_bits_min(33, 24, false)
-            && set_mmap_rnd_bits_min(16, 16, true)) {
-        ret = 0;
-    }
-#elif defined(__x86_64__)
-    /* x86_64 supports 28 - 32 bits */
-    if (set_mmap_rnd_bits_min(32, 32, false)
-            && set_mmap_rnd_bits_min(16, 16, true)) {
-        ret = 0;
-    }
-#elif defined(__arm__) || defined(__i386__)
-    /* check to see if we're running on 64-bit kernel */
-    bool h64 = !access(MMAP_RND_COMPAT_PATH, F_OK);
-    /* supported 32-bit architecture must have 16 bits set */
-    if (set_mmap_rnd_bits_min(16, 16, h64)) {
-        ret = 0;
-    }
-#elif defined(__mips__) || defined(__mips64__)
-    // TODO: add mips support b/27788820
-    ret = 0;
-#else
-    ERROR("Unknown architecture\n");
-#endif
-
-#ifdef __BRILLO__
-    // TODO: b/27794137
-    ret = 0;
-#endif
-    if (ret == -1) {
-        ERROR("Unable to set adequate mmap entropy value!\n");
-        security_failure();
-    }
-    return ret;
-}
-
 static int keychord_init_action(const std::vector<std::string>& args)
 {
     keychord_init();
@@ -355,36 +260,8 @@
 {
     std::string console = property_get("ro.boot.console");
     if (!console.empty()) {
-        console_name = "/dev/" + console;
+        default_console = "/dev/" + console;
     }
-
-    int fd = open(console_name.c_str(), O_RDWR | O_CLOEXEC);
-    if (fd >= 0)
-        have_console = 1;
-    close(fd);
-
-    fd = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
-    if (fd >= 0) {
-        const char *msg;
-            msg = "\n"
-        "\n"
-        "\n"
-        "\n"
-        "\n"
-        "\n"
-        "\n"  // console is 40 cols x 30 lines
-        "\n"
-        "\n"
-        "\n"
-        "\n"
-        "\n"
-        "\n"
-        "\n"
-        "             A N D R O I D ";
-        write(fd, msg, strlen(msg));
-        close(fd);
-    }
-
     return 0;
 }
 
@@ -393,15 +270,14 @@
 
     if (for_emulator) {
         // In the emulator, export any kernel option with the "ro.kernel." prefix.
-        property_set(android::base::StringPrintf("ro.kernel.%s", key.c_str()).c_str(), value.c_str());
+        property_set(StringPrintf("ro.kernel.%s", key.c_str()).c_str(), value.c_str());
         return;
     }
 
     if (key == "qemu") {
         strlcpy(qemu, value.c_str(), sizeof(qemu));
     } else if (android::base::StartsWith(key, "androidboot.")) {
-        property_set(android::base::StringPrintf("ro.boot.%s", key.c_str() + 12).c_str(),
-                     value.c_str());
+        property_set(StringPrintf("ro.boot.%s", key.c_str() + 12).c_str(), value.c_str());
     }
 }
 
@@ -430,7 +306,7 @@
         { "ro.boot.hardware",   "ro.hardware",   "unknown", },
         { "ro.boot.revision",   "ro.revision",   "0", },
     };
-    for (size_t i = 0; i < ARRAY_SIZE(prop_map); i++) {
+    for (size_t i = 0; i < arraysize(prop_map); i++) {
         std::string value = property_get(prop_map[i].src_prop);
         property_set(prop_map[i].dst_prop, (!value.empty()) ? value.c_str() : prop_map[i].default_value);
     }
@@ -439,12 +315,12 @@
 static void process_kernel_dt() {
     static const char android_dir[] = "/proc/device-tree/firmware/android";
 
-    std::string file_name = android::base::StringPrintf("%s/compatible", android_dir);
+    std::string file_name = StringPrintf("%s/compatible", android_dir);
 
     std::string dt_file;
     android::base::ReadFileToString(file_name, &dt_file);
     if (!dt_file.compare("android,firmware")) {
-        ERROR("firmware/android is not compatible with 'android,firmware'\n");
+        LOG(ERROR) << "firmware/android is not compatible with 'android,firmware'";
         return;
     }
 
@@ -457,20 +333,17 @@
             continue;
         }
 
-        file_name = android::base::StringPrintf("%s/%s", android_dir, dp->d_name);
+        file_name = StringPrintf("%s/%s", android_dir, dp->d_name);
 
         android::base::ReadFileToString(file_name, &dt_file);
         std::replace(dt_file.begin(), dt_file.end(), ',', '.');
 
-        std::string property_name = android::base::StringPrintf("ro.boot.%s", dp->d_name);
+        std::string property_name = StringPrintf("ro.boot.%s", dp->d_name);
         property_set(property_name.c_str(), dt_file.c_str());
     }
 }
 
 static void process_kernel_cmdline() {
-    // Don't expose the raw commandline to unprivileged processes.
-    chmod("/proc/cmdline", 0440);
-
     // The first pass does the common stuff, and finds if we are in qemu.
     // The second pass is only necessary for qemu to export all kernel params
     // as properties.
@@ -515,30 +388,12 @@
     return true;
 }
 
-int selinux_reload_policy(void)
-{
-    INFO("SELinux: Attempting to reload policy files\n");
-
-    if (selinux_android_reload_policy() == -1) {
-        return -1;
-    }
-
-    if (sehandle)
-        selabel_close(sehandle);
-
-    if (sehandle_prop)
-        selabel_close(sehandle_prop);
-
-    selinux_init_all_handles();
-    return 0;
-}
-
 static int audit_callback(void *data, security_class_t /*cls*/, char *buf, size_t len) {
 
     property_audit_data *d = reinterpret_cast<property_audit_data*>(data);
 
     if (!d || !d->name || !d->cr) {
-        ERROR("audit_callback invoked with null data arguments!");
+        LOG(ERROR) << "audit_callback invoked with null data arguments!";
         return 0;
     }
 
@@ -547,6 +402,12 @@
     return 0;
 }
 
+static void security_failure() {
+    LOG(ERROR) << "Security failure; rebooting into recovery mode...";
+    android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
+    while (true) { pause(); }  // never reached
+}
+
 static void selinux_initialize(bool in_kernel_domain) {
     Timer t;
 
@@ -557,9 +418,9 @@
     selinux_set_callback(SELINUX_CB_AUDIT, cb);
 
     if (in_kernel_domain) {
-        INFO("Loading SELinux policy...\n");
+        LOG(INFO) << "Loading SELinux policy...";
         if (selinux_android_load_policy() < 0) {
-            ERROR("failed to load policy: %s\n", strerror(errno));
+            PLOG(ERROR) << "failed to load policy";
             security_failure();
         }
 
@@ -567,8 +428,7 @@
         bool is_enforcing = selinux_is_enforcing();
         if (kernel_enforcing != is_enforcing) {
             if (security_setenforce(is_enforcing)) {
-                ERROR("security_setenforce(%s) failed: %s\n",
-                      is_enforcing ? "true" : "false", strerror(errno));
+                PLOG(ERROR) << "security_setenforce(%s) failed" << (is_enforcing ? "true" : "false");
                 security_failure();
             }
         }
@@ -577,13 +437,127 @@
             security_failure();
         }
 
-        NOTICE("(Initializing SELinux %s took %.2fs.)\n",
-               is_enforcing ? "enforcing" : "non-enforcing", t.duration());
+        LOG(INFO) << "(Initializing SELinux " << (is_enforcing ? "enforcing" : "non-enforcing")
+                  << " took " << t.duration() << "s.)";
     } else {
         selinux_init_all_handles();
     }
 }
 
+// Set the UDC controller for the ConfigFS USB Gadgets.
+// Read the UDC controller in use from "/sys/class/udc".
+// In case of multiple UDC controllers select the first one.
+static void set_usb_controller() {
+    std::unique_ptr<DIR, decltype(&closedir)>dir(opendir("/sys/class/udc"), closedir);
+    if (!dir) return;
+
+    dirent* dp;
+    while ((dp = readdir(dir.get())) != nullptr) {
+        if (dp->d_name[0] == '.') continue;
+
+        property_set("sys.usb.controller", dp->d_name);
+        break;
+    }
+}
+
+/* Returns a new path consisting of base_path and the file name in reference_path. */
+static std::string get_path(const std::string& base_path, const std::string& reference_path) {
+    std::string::size_type pos = reference_path.rfind('/');
+    if (pos == std::string::npos) {
+        return base_path + '/' + reference_path;
+    } else {
+        return base_path + reference_path.substr(pos);
+    }
+}
+
+/* Imports the fstab info from cmdline. */
+static std::string import_cmdline_fstab() {
+    std::string prefix, fstab, fstab_full;
+
+    import_kernel_cmdline(false,
+        [&](const std::string& key, const std::string& value, bool in_qemu __attribute__((__unused__))) {
+            if (key == "android.early.prefix") {
+                prefix = value;
+            } else if (key == "android.early.fstab") {
+                fstab = value;
+            }
+        });
+    if (!fstab.empty()) {
+        // Convert "mmcblk0p09+/odm+ext4+ro+verify" to "mmcblk0p09 /odm ext4 ro verify"
+        std::replace(fstab.begin(), fstab.end(), '+', ' ');
+        for (const auto& entry : android::base::Split(fstab, "\n")) {
+            fstab_full += prefix + entry + '\n';
+        }
+    }
+    return fstab_full;
+}
+
+/* Early mount vendor and ODM partitions. The fstab info is read from kernel cmdline. */
+static void early_mount() {
+    std::string fstab_string = import_cmdline_fstab();
+    if (fstab_string.empty()) {
+        LOG(INFO) << "Failed to load vendor fstab from kernel cmdline";
+        return;
+    }
+    FILE *fstab_file = fmemopen((void *)fstab_string.c_str(), fstab_string.length(), "r");
+    if (!fstab_file) {
+        PLOG(ERROR) << "Failed to open fstab string as FILE";
+        return;
+    }
+    std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_file(fstab_file), fs_mgr_free_fstab);
+    fclose(fstab_file);
+    if (!fstab) {
+        LOG(ERROR) << "Failed to parse fstab string: " << fstab_string;
+        return;
+    }
+    LOG(INFO) << "Loaded vendor fstab from cmdline";
+
+    if (early_device_socket_open()) {
+        LOG(ERROR) << "Failed to open device uevent socket";
+        return;
+    }
+
+    /* Create /dev/device-mapper for dm-verity */
+    early_create_dev("/sys/devices/virtual/misc/device-mapper", EARLY_CHAR_DEV);
+
+    for (int i = 0; i < fstab->num_entries; ++i) {
+        struct fstab_rec *rec = &fstab->recs[i];
+        std::string mount_point = rec->mount_point;
+        std::string syspath = rec->blk_device;
+
+        if (mount_point != "/vendor" && mount_point != "/odm")
+            continue;
+
+        /* Create mount target under /dev/block/ from sysfs via uevent */
+        LOG(INFO) << "Mounting " << mount_point << " from " << syspath << "...";
+        char *devpath = strdup(get_path("/dev/block", syspath).c_str());
+        if (!devpath) {
+            PLOG(ERROR) << "Failed to strdup dev path in early mount " << syspath;
+            continue;
+        }
+        rec->blk_device = devpath;
+        early_create_dev(syspath, EARLY_BLOCK_DEV);
+
+        int rc = fs_mgr_early_setup_verity(rec);
+        if (rc == FS_MGR_EARLY_SETUP_VERITY_SUCCESS) {
+            /* Mount target is changed to /dev/block/dm-<n>; initiate its creation from sysfs counterpart */
+            early_create_dev(get_path("/sys/devices/virtual/block", rec->blk_device), EARLY_BLOCK_DEV);
+        } else if (rc == FS_MGR_EARLY_SETUP_VERITY_FAIL) {
+            LOG(ERROR) << "Failed to set up dm-verity on " << rec->blk_device;
+            continue;
+        } else { /* FS_MGR_EARLY_SETUP_VERITY_NO_VERITY */
+            LOG(INFO) << "dm-verity disabled on debuggable device; mount directly on " << rec->blk_device;
+        }
+
+        mkdir(mount_point.c_str(), 0755);
+        rc = mount(rec->blk_device, mount_point.c_str(), rec->fs_type, rec->flags, rec->fs_options);
+        if (rc) {
+            PLOG(ERROR) << "Failed to mount on " << rec->blk_device;
+        }
+    }
+    early_device_socket_close();
+}
+
 int main(int argc, char** argv) {
     if (!strcmp(basename(argv[0]), "ueventd")) {
         return ueventd_main(argc, argv);
@@ -593,12 +567,17 @@
         return watchdogd_main(argc, argv);
     }
 
+    boot_clock::time_point start_time = boot_clock::now();
+
     // Clear the umask.
     umask(0);
 
     add_environment("PATH", _PATH_DEFPATH);
 
-    bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);
+    bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
+
+    // Don't expose the raw commandline to unprivileged processes.
+    chmod("/proc/cmdline", 0440);
 
     // Get the basic filesystem setup we need put together in the initramdisk
     // on / and then we'll let the rc file figure out the rest.
@@ -609,20 +588,47 @@
         mount("devpts", "/dev/pts", "devpts", 0, NULL);
         #define MAKE_STR(x) __STRING(x)
         mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
+        gid_t groups[] = { AID_READPROC };
+        setgroups(arraysize(groups), groups);
         mount("sysfs", "/sys", "sysfs", 0, NULL);
+        mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
+        mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
+        mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
+        mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));
     }
 
-    // We must have some place other than / to create the device nodes for
-    // kmsg and null, otherwise we won't be able to remount / read-only
-    // later on. Now that tmpfs is mounted on /dev, we can actually talk
-    // to the outside world.
-    open_devnull_stdio();
-    klog_init();
-    klog_set_level(KLOG_NOTICE_LEVEL);
+    // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
+    // talk to the outside world...
+    InitKernelLogging(argv);
 
-    NOTICE("init %s started!\n", is_first_stage ? "first stage" : "second stage");
+    LOG(INFO) << "init " << (is_first_stage ? "first" : "second") << " stage started!";
 
-    if (!is_first_stage) {
+    if (is_first_stage) {
+        // Mount devices defined in android.early.* kernel commandline
+        early_mount();
+
+        // Set up SELinux, loading the SELinux policy.
+        selinux_initialize(true);
+
+        // We're in the kernel domain, so re-exec init to transition to the init domain now
+        // that the SELinux policy has been loaded.
+        if (restorecon("/init") == -1) {
+            PLOG(ERROR) << "restorecon failed";
+            security_failure();
+        }
+
+        setenv("INIT_SECOND_STAGE", "true", 1);
+
+        uint64_t start_ns = start_time.time_since_epoch().count();
+        setenv("INIT_STARTED_AT", StringPrintf("%" PRIu64, start_ns).c_str(), 1);
+
+        char* path = argv[0];
+        char* args[] = { path, nullptr };
+        if (execv(path, args) == -1) {
+            PLOG(ERROR) << "execv(\"" << path << "\") failed";
+            security_failure();
+        }
+    } else {
         // Indicate that booting is in progress to background fw loaders, etc.
         close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
 
@@ -636,39 +642,32 @@
         // Propagate the kernel variables to internal variables
         // used by init as well as the current required properties.
         export_kernel_boot_props();
-    }
 
-    // Set up SELinux, including loading the SELinux policy if we're in the kernel domain.
-    selinux_initialize(is_first_stage);
+        // Make the time that init started available for bootstat to log.
+        property_set("init.start", getenv("INIT_STARTED_AT"));
 
-    // If we're in the kernel domain, re-exec init to transition to the init domain now
-    // that the SELinux policy has been loaded.
-    if (is_first_stage) {
-        if (restorecon("/init") == -1) {
-            ERROR("restorecon failed: %s\n", strerror(errno));
-            security_failure();
-        }
-        char* path = argv[0];
-        char* args[] = { path, const_cast<char*>("--second-stage"), nullptr };
-        if (execv(path, args) == -1) {
-            ERROR("execv(\"%s\") failed: %s\n", path, strerror(errno));
-            security_failure();
-        }
+        // Now set up SELinux for second stage.
+        selinux_initialize(false);
     }
 
     // These directories were necessarily created before initial policy load
     // and therefore need their security context restored to the proper value.
     // This must happen before /dev is populated by ueventd.
-    NOTICE("Running restorecon...\n");
+    LOG(INFO) << "Running restorecon...";
     restorecon("/dev");
+    restorecon("/dev/kmsg");
     restorecon("/dev/socket");
+    restorecon("/dev/random");
+    restorecon("/dev/urandom");
     restorecon("/dev/__properties__");
     restorecon("/property_contexts");
-    restorecon_recursive("/sys");
+    restorecon("/sys", SELINUX_ANDROID_RESTORECON_RECURSE);
+    restorecon("/dev/block", SELINUX_ANDROID_RESTORECON_RECURSE);
+    restorecon("/dev/device-mapper");
 
     epoll_fd = epoll_create1(EPOLL_CLOEXEC);
     if (epoll_fd == -1) {
-        ERROR("epoll_create1 failed: %s\n", strerror(errno));
+        PLOG(ERROR) << "epoll_create1 failed";
         exit(1);
     }
 
@@ -677,6 +676,7 @@
     property_load_boot_defaults();
     export_oem_lock_status();
     start_property_service();
+    set_usb_controller();
 
     const BuiltinFunctionMap function_map;
     Action::set_function_map(&function_map);
@@ -695,7 +695,6 @@
     am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
     // ... so that we can start queuing up actions that require stuff from /dev.
     am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
-    am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");
     am.QueueBuiltinAction(keychord_init_action, "keychord_init");
     am.QueueBuiltinAction(console_init_action, "console_init");
 
@@ -723,23 +722,24 @@
             restart_processes();
         }
 
-        int timeout = -1;
-        if (process_needs_restart) {
-            timeout = (process_needs_restart - gettime()) * 1000;
-            if (timeout < 0)
-                timeout = 0;
+        // By default, sleep until something happens.
+        int epoll_timeout_ms = -1;
+
+        // If there's more work to do, wake up again immediately.
+        if (am.HasMoreCommands()) epoll_timeout_ms = 0;
+
+        // If there's a process that needs restarting, wake up in time for that.
+        if (process_needs_restart_at != 0) {
+            epoll_timeout_ms = (process_needs_restart_at - time(nullptr)) * 1000;
+            if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
         }
 
-        if (am.HasMoreCommands()) {
-            timeout = 0;
-        }
-
-        bootchart_sample(&timeout);
+        bootchart_sample(&epoll_timeout_ms);
 
         epoll_event ev;
-        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
+        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms));
         if (nr == -1) {
-            ERROR("epoll_wait failed: %s\n", strerror(errno));
+            PLOG(ERROR) << "epoll_wait failed";
         } else if (nr == 1) {
             ((void (*)()) ev.data.ptr)();
         }
diff --git a/init/init.h b/init/init.h
index 345d442..cfb3139 100644
--- a/init/init.h
+++ b/init/init.h
@@ -22,12 +22,9 @@
 class Action;
 class Service;
 
-#define COMMAND_RETRY_TIMEOUT 5
-
 extern const char *ENV[32];
 extern bool waiting_for_exec;
-extern int have_console;
-extern std::string console_name;
+extern std::string default_console;
 extern struct selabel_handle *sehandle;
 extern struct selabel_handle *sehandle_prop;
 
@@ -35,8 +32,6 @@
 
 void property_changed(const char *name, const char *value);
 
-int selinux_reload_policy(void);
-
 void register_epoll_handler(int fd, void (*fn)());
 
 int add_environment(const char* key, const char* val);
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index f2e5d6d..d017390 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -93,7 +93,7 @@
 }
 
 bool Parser::ParseConfigFile(const std::string& path) {
-    INFO("Parsing file %s...\n", path.c_str());
+    LOG(INFO) << "Parsing file " << path << "...";
     Timer t;
     std::string data;
     if (!read_file(path.c_str(), &data)) {
@@ -110,15 +110,15 @@
     // Nexus 9 boot time, so it's disabled by default.
     if (false) DumpState();
 
-    NOTICE("(Parsing %s took %.2fs.)\n", path.c_str(), t.duration());
+    LOG(VERBOSE) << "(Parsing " << path << " took " << t.duration() << "s.)";
     return true;
 }
 
 bool Parser::ParseConfigDir(const std::string& path) {
-    INFO("Parsing directory %s...\n", path.c_str());
+    LOG(INFO) << "Parsing directory " << path << "...";
     std::unique_ptr<DIR, int(*)(DIR*)> config_dir(opendir(path.c_str()), closedir);
     if (!config_dir) {
-        ERROR("Could not import directory '%s'\n", path.c_str());
+        PLOG(ERROR) << "Could not import directory '" << path << "'";
         return false;
     }
     dirent* current_file;
@@ -135,7 +135,7 @@
     std::sort(files.begin(), files.end());
     for (const auto& file : files) {
         if (!ParseConfigFile(file)) {
-            ERROR("Could not import file '%s'\n", file.c_str());
+            LOG(ERROR) << "could not import file '" << file << "'";
         }
     }
     return true;
diff --git a/init/keychords.cpp b/init/keychords.cpp
index 1468c57..3dbb2f0 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -43,7 +43,7 @@
         size = sizeof(*keychord) + svc->keycodes().size() * sizeof(keychord->keycodes[0]);
         keychords = (input_keychord*) realloc(keychords, keychords_length + size);
         if (!keychords) {
-            ERROR("could not allocate keychords\n");
+            PLOG(ERROR) << "could not allocate keychords";
             keychords_length = 0;
             keychords_count = 0;
             return;
@@ -69,7 +69,7 @@
 
     ret = read(keychord_fd, &id, sizeof(id));
     if (ret != sizeof(id)) {
-        ERROR("could not read keychord id\n");
+        PLOG(ERROR) << "could not read keychord id";
         return;
     }
 
@@ -78,13 +78,13 @@
     if (adb_enabled == "running") {
         Service* svc = ServiceManager::GetInstance().FindServiceByKeychord(id);
         if (svc) {
-            NOTICE("Starting service '%s' from keychord %d\n", svc->name().c_str(), id);
+            LOG(INFO) << "Starting service " << svc->name() << " from keychord " << id;
             svc->Start();
         } else {
-            ERROR("Service for keychord %d not found\n", id);
+            LOG(ERROR) << "Service for keychord " << id << " not found";
         }
     } else {
-        WARNING("Not starting service for keychord %d because ADB is disabled\n", id);
+        LOG(WARNING) << "Not starting service for keychord " << id << " because ADB is disabled";
     }
 }
 
@@ -98,13 +98,13 @@
 
     keychord_fd = TEMP_FAILURE_RETRY(open("/dev/keychord", O_RDWR | O_CLOEXEC));
     if (keychord_fd == -1) {
-        ERROR("could not open /dev/keychord: %s\n", strerror(errno));
+        PLOG(ERROR) << "could not open /dev/keychord";
         return;
     }
 
     int ret = write(keychord_fd, keychords, keychords_length);
     if (ret != keychords_length) {
-        ERROR("could not configure /dev/keychord %d: %s\n", ret, strerror(errno));
+        PLOG(ERROR) << "could not configure /dev/keychord " << ret;
         close(keychord_fd);
     }
 
diff --git a/init/log.cpp b/init/log.cpp
index ace9fd7..8618340 100644
--- a/init/log.cpp
+++ b/init/log.cpp
@@ -16,54 +16,40 @@
 
 #include "log.h"
 
-#include <stdlib.h>
+#include <fcntl.h>
 #include <string.h>
-#include <sys/uio.h>
 
 #include <selinux/selinux.h>
 
-#include <android-base/stringprintf.h>
-
-static void init_klog_vwrite(int level, const char* fmt, va_list ap) {
-    static const char* tag = basename(getprogname());
-
-    if (level > klog_get_level()) return;
-
-    // The kernel's printk buffer is only 1024 bytes.
-    // TODO: should we automatically break up long lines into multiple lines?
-    // Or we could log but with something like "..." at the end?
-    char buf[1024];
-    size_t prefix_size = snprintf(buf, sizeof(buf), "<%d>%s: ", level, tag);
-    size_t msg_size = vsnprintf(buf + prefix_size, sizeof(buf) - prefix_size, fmt, ap);
-    if (msg_size >= sizeof(buf) - prefix_size) {
-        msg_size = snprintf(buf + prefix_size, sizeof(buf) - prefix_size,
-                            "(%zu-byte message too long for printk)\n", msg_size);
+void InitKernelLogging(char* argv[]) {
+    // Make stdin/stdout/stderr all point to /dev/null.
+    int fd = open("/sys/fs/selinux/null", O_RDWR);
+    if (fd == -1) {
+        int saved_errno = errno;
+        android::base::InitLogging(argv, &android::base::KernelLogger);
+        errno = saved_errno;
+        PLOG(FATAL) << "Couldn't open /sys/fs/selinux/null";
     }
+    dup2(fd, 0);
+    dup2(fd, 1);
+    dup2(fd, 2);
+    if (fd > 2) close(fd);
 
-    iovec iov[1];
-    iov[0].iov_base = buf;
-    iov[0].iov_len = prefix_size + msg_size;
-
-    klog_writev(level, iov, 1);
-}
-
-void init_klog_write(int level, const char* fmt, ...) {
-    va_list ap;
-    va_start(ap, fmt);
-    init_klog_vwrite(level, fmt, ap);
-    va_end(ap);
+    android::base::InitLogging(argv, &android::base::KernelLogger);
 }
 
 int selinux_klog_callback(int type, const char *fmt, ...) {
-    int level = KLOG_ERROR_LEVEL;
+    android::base::LogSeverity severity = android::base::ERROR;
     if (type == SELINUX_WARNING) {
-        level = KLOG_WARNING_LEVEL;
+        severity = android::base::WARNING;
     } else if (type == SELINUX_INFO) {
-        level = KLOG_INFO_LEVEL;
+        severity = android::base::INFO;
     }
+    char buf[1024];
     va_list ap;
     va_start(ap, fmt);
-    init_klog_vwrite(level, fmt, ap);
+    vsnprintf(buf, sizeof(buf), fmt, ap);
     va_end(ap);
+    android::base::KernelLogger(android::base::MAIN, severity, "selinux", nullptr, 0, buf);
     return 0;
 }
diff --git a/init/log.h b/init/log.h
index c5c30af..8fa6d74 100644
--- a/init/log.h
+++ b/init/log.h
@@ -17,16 +17,10 @@
 #ifndef _INIT_LOG_H_
 #define _INIT_LOG_H_
 
-#include <cutils/klog.h>
+#include <android-base/logging.h>
 
-#define ERROR(x...)   init_klog_write(KLOG_ERROR_LEVEL, x)
-#define WARNING(x...) init_klog_write(KLOG_WARNING_LEVEL, x)
-#define NOTICE(x...)  init_klog_write(KLOG_NOTICE_LEVEL, x)
-#define INFO(x...)    init_klog_write(KLOG_INFO_LEVEL, x)
-#define DEBUG(x...)   init_klog_write(KLOG_DEBUG_LEVEL, x)
-#define VERBOSE(x...) init_klog_write(KLOG_DEBUG_LEVEL, x)
+void InitKernelLogging(char* argv[]);
 
-void init_klog_write(int level, const char* fmt, ...) __printflike(2, 3);
 int selinux_klog_callback(int level, const char* fmt, ...) __printflike(2, 3);
 
 #endif
diff --git a/init/parser.cpp b/init/parser.cpp
index 8193729..45862b7 100644
--- a/init/parser.cpp
+++ b/init/parser.cpp
@@ -12,7 +12,7 @@
     char buf[128];
     int off;
 
-    snprintf(buf, 128, "%s: %d: ", state->filename, state->line);
+    snprintf(buf, sizeof(buf), "%s: %d: ", state->filename, state->line);
     buf[127] = 0;
     off = strlen(buf);
 
@@ -20,7 +20,7 @@
     vsnprintf(buf + off, 128 - off, fmt, ap);
     va_end(ap);
     buf[127] = 0;
-    ERROR("%s", buf);
+    LOG(ERROR) << buf;
 }
 
 int next_token(struct parse_state *state)
diff --git a/init/parser/tokenizer.h b/init/parser/tokenizer.h
index 8312a08..ade8f73 100644
--- a/init/parser/tokenizer.h
+++ b/init/parser/tokenizer.h
@@ -36,7 +36,7 @@
 // a TOK_NEWLINE will not be generated for that line.
 class Tokenizer {
  public:
-  Tokenizer(const std::string& data);
+  explicit Tokenizer(const std::string& data);
   ~Tokenizer();
 
   enum TokenType { TOK_START, TOK_END, TOK_NEWLINE, TOK_TEXT };
diff --git a/init/perfboot.py b/init/perfboot.py
index 91e6c2b..713290b 100755
--- a/init/perfboot.py
+++ b/init/perfboot.py
@@ -191,9 +191,9 @@
 
 def init_perf(device, output, record_list, tags):
     device.wait()
-    build_type = device.get_prop('ro.build.type')
+    debuggable = device.get_prop('ro.debuggable')
     original_dropbox_max_files = None
-    if build_type != 'user':
+    if debuggable == '1':
         # Workaround for Dropbox issue (http://b/20890386).
         original_dropbox_max_files = disable_dropbox(device)
 
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 5c1ae79..e198297 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -41,8 +41,8 @@
 #include <sys/types.h>
 #include <netinet/in.h>
 #include <sys/mman.h>
-#include <private/android_filesystem_config.h>
 
+#include <selinux/android.h>
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 
@@ -65,7 +65,7 @@
 
 void property_init() {
     if (__system_property_area_init()) {
-        ERROR("Failed to initialize property area\n");
+        LOG(ERROR) << "Failed to initialize property area";
         exit(1);
     }
 }
@@ -128,7 +128,7 @@
     snprintf(tempPath, sizeof(tempPath), "%s/.temp.XXXXXX", PERSISTENT_PROPERTY_DIR);
     fd = mkstemp(tempPath);
     if (fd < 0) {
-        ERROR("Unable to write persistent property to temp file %s: %s\n", tempPath, strerror(errno));
+        PLOG(ERROR) << "Unable to write persistent property to temp file " << tempPath;
         return;
     }
     write(fd, value, strlen(value));
@@ -137,28 +137,29 @@
 
     snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name);
     if (rename(tempPath, path)) {
+        PLOG(ERROR) << "Unable to rename persistent property file " << tempPath << " to " << path;
         unlink(tempPath);
-        ERROR("Unable to rename persistent property file %s to %s\n", tempPath, path);
     }
 }
 
-static bool is_legal_property_name(const char* name, size_t namelen)
+bool is_legal_property_name(const std::string &name)
 {
-    size_t i;
+    size_t namelen = name.size();
+
     if (namelen >= PROP_NAME_MAX) return false;
     if (namelen < 1) return false;
     if (name[0] == '.') return false;
     if (name[namelen - 1] == '.') return false;
 
-    /* Only allow alphanumeric, plus '.', '-', or '_' */
+    /* Only allow alphanumeric, plus '.', '-', '@', or '_' */
     /* Don't allow ".." to appear in a property name */
-    for (i = 0; i < namelen; i++) {
+    for (size_t i = 0; i < namelen; i++) {
         if (name[i] == '.') {
             // i=0 is guaranteed to never have a dot. See above.
             if (name[i-1] == '.') return false;
             continue;
         }
-        if (name[i] == '_' || name[i] == '-') continue;
+        if (name[i] == '_' || name[i] == '-' || name[i] == '@') continue;
         if (name[i] >= 'a' && name[i] <= 'z') continue;
         if (name[i] >= 'A' && name[i] <= 'Z') continue;
         if (name[i] >= '0' && name[i] <= '9') continue;
@@ -169,19 +170,14 @@
 }
 
 static int property_set_impl(const char* name, const char* value) {
-    size_t namelen = strlen(name);
     size_t valuelen = strlen(value);
 
-    if (!is_legal_property_name(name, namelen)) return -1;
+    if (!is_legal_property_name(name)) return -1;
     if (valuelen >= PROP_VALUE_MAX) return -1;
 
-    if (strcmp("selinux.reload_policy", name) == 0 && strcmp("1", value) == 0) {
-        if (selinux_reload_policy() != 0) {
-            ERROR("Failed to reload policy\n");
-        }
-    } else if (strcmp("selinux.restorecon_recursive", name) == 0 && valuelen > 0) {
-        if (restorecon_recursive(value) != 0) {
-            ERROR("Failed to restorecon_recursive %s\n", value);
+    if (strcmp("selinux.restorecon_recursive", name) == 0 && valuelen > 0) {
+        if (restorecon(value, SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
+            LOG(ERROR) << "Failed to restorecon_recursive " << value;
         }
     }
 
@@ -193,7 +189,7 @@
 
         __system_property_update(pi, value, valuelen);
     } else {
-        int rc = __system_property_add(name, namelen, value, valuelen);
+        int rc = __system_property_add(name, strlen(name), value, valuelen);
         if (rc < 0) {
             return rc;
         }
@@ -224,7 +220,7 @@
 int property_set(const char* name, const char* value) {
     int rc = property_set_impl(name, value);
     if (rc == -1) {
-        ERROR("property_set(\"%s\", \"%s\") failed\n", name, value);
+        LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed";
     }
     return rc;
 }
@@ -232,46 +228,42 @@
 static void handle_property_set_fd()
 {
     prop_msg msg;
-    int s;
     int r;
-    struct ucred cr;
-    struct sockaddr_un addr;
-    socklen_t addr_size = sizeof(addr);
-    socklen_t cr_size = sizeof(cr);
     char * source_ctx = NULL;
-    struct pollfd ufds[1];
-    const int timeout_ms = 2 * 1000;  /* Default 2 sec timeout for caller to send property. */
-    int nr;
 
-    if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
+    int s = accept(property_set_fd, nullptr, nullptr);
+    if (s == -1) {
         return;
     }
 
     /* Check socket options here */
+    struct ucred cr;
+    socklen_t cr_size = sizeof(cr);
     if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
         close(s);
-        ERROR("Unable to receive socket options\n");
+        PLOG(ERROR) << "Unable to receive socket options";
         return;
     }
 
+    static constexpr int timeout_ms = 2 * 1000;  /* Default 2 sec timeout for caller to send property. */
+    struct pollfd ufds[1];
     ufds[0].fd = s;
     ufds[0].events = POLLIN;
     ufds[0].revents = 0;
-    nr = TEMP_FAILURE_RETRY(poll(ufds, 1, timeout_ms));
+    int nr = TEMP_FAILURE_RETRY(poll(ufds, 1, timeout_ms));
     if (nr == 0) {
-        ERROR("sys_prop: timeout waiting for uid=%d to send property message.\n", cr.uid);
+        LOG(ERROR) << "sys_prop: timeout waiting for uid " << cr.uid << " to send property message.";
         close(s);
         return;
     } else if (nr < 0) {
-        ERROR("sys_prop: error waiting for uid=%d to send property message: %s\n", cr.uid, strerror(errno));
+        PLOG(ERROR) << "sys_prop: error waiting for uid " << cr.uid << " to send property message";
         close(s);
         return;
     }
 
     r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT));
     if(r != sizeof(prop_msg)) {
-        ERROR("sys_prop: mis-match msg size received: %d expected: %zu: %s\n",
-              r, sizeof(prop_msg), strerror(errno));
+        PLOG(ERROR) << "sys_prop: mis-match msg size received: " << r << " expected: " << sizeof(prop_msg);
         close(s);
         return;
     }
@@ -281,8 +273,8 @@
         msg.name[PROP_NAME_MAX-1] = 0;
         msg.value[PROP_VALUE_MAX-1] = 0;
 
-        if (!is_legal_property_name(msg.name, strlen(msg.name))) {
-            ERROR("sys_prop: illegal property name. Got: \"%s\"\n", msg.name);
+        if (!is_legal_property_name(msg.name)) {
+            LOG(ERROR) << "sys_prop: illegal property name \"" << msg.name << "\"";
             close(s);
             return;
         }
@@ -296,15 +288,17 @@
             if (check_control_mac_perms(msg.value, source_ctx, &cr)) {
                 handle_control_message((char*) msg.name + 4, (char*) msg.value);
             } else {
-                ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n",
-                        msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);
+                LOG(ERROR) << "sys_prop: Unable to " << (msg.name + 4)
+                           << " service ctl [" << msg.value << "]"
+                           << " uid:" << cr.uid
+                           << " gid:" << cr.gid
+                           << " pid:" << cr.pid;
             }
         } else {
             if (check_mac_perms(msg.name, source_ctx, &cr)) {
                 property_set((char*) msg.name, (char*) msg.value);
             } else {
-                ERROR("sys_prop: permission denied uid:%d  name:%s\n",
-                      cr.uid, msg.name);
+                LOG(ERROR) << "sys_prop: permission denied uid:" << cr.uid << " name:" << msg.name;
             }
 
             // Note: bionic's property client code assumes that the
@@ -383,18 +377,18 @@
     }
 }
 
-/*
- * Filter is used to decide which properties to load: NULL loads all keys,
- * "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match.
- */
+// Filter is used to decide which properties to load: NULL loads all keys,
+// "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match.
 static void load_properties_from_file(const char* filename, const char* filter) {
     Timer t;
     std::string data;
-    if (read_file(filename, &data)) {
-        data.push_back('\n');
-        load_properties(&data[0], filter);
+    if (!read_file(filename, &data)) {
+        PLOG(WARNING) << "Couldn't load properties from " << filename;
+        return;
     }
-    NOTICE("(Loading properties from %s took %.2fs.)\n", filename, t.duration());
+    data.push_back('\n');
+    load_properties(&data[0], filter);
+    LOG(VERBOSE) << "(Loading properties from " << filename << " took " << t.duration() << "s.)";
 }
 
 static void load_persistent_properties() {
@@ -402,8 +396,8 @@
 
     std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(PERSISTENT_PROPERTY_DIR), closedir);
     if (!dir) {
-        ERROR("Unable to open persistent property directory \"%s\": %s\n",
-              PERSISTENT_PROPERTY_DIR, strerror(errno));
+        PLOG(ERROR) << "Unable to open persistent property directory \""
+                    << PERSISTENT_PROPERTY_DIR << "\"";
         return;
     }
 
@@ -419,25 +413,23 @@
         // Open the file and read the property value.
         int fd = openat(dirfd(dir.get()), entry->d_name, O_RDONLY | O_NOFOLLOW);
         if (fd == -1) {
-            ERROR("Unable to open persistent property file \"%s\": %s\n",
-                  entry->d_name, strerror(errno));
+            PLOG(ERROR) << "Unable to open persistent property file \"" << entry->d_name << "\"";
             continue;
         }
 
         struct stat sb;
         if (fstat(fd, &sb) == -1) {
-            ERROR("fstat on property file \"%s\" failed: %s\n", entry->d_name, strerror(errno));
+            PLOG(ERROR) << "fstat on property file \"" << entry->d_name << "\" failed";
             close(fd);
             continue;
         }
 
         // File must not be accessible to others, be owned by root/root, and
         // not be a hard link to any other file.
-        if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0) || (sb.st_uid != 0) || (sb.st_gid != 0) ||
-                (sb.st_nlink != 1)) {
-            ERROR("skipping insecure property file %s (uid=%u gid=%u nlink=%u mode=%o)\n",
-                  entry->d_name, (unsigned int)sb.st_uid, (unsigned int)sb.st_gid,
-                  (unsigned int)sb.st_nlink, sb.st_mode);
+        if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0) || sb.st_uid != 0 || sb.st_gid != 0 || sb.st_nlink != 1) {
+            PLOG(ERROR) << "skipping insecure property file " << entry->d_name
+                        << " (uid=" << sb.st_uid << " gid=" << sb.st_gid
+                        << " nlink=" << sb.st_nlink << " mode=" << std::oct << sb.st_mode << ")";
             close(fd);
             continue;
         }
@@ -448,8 +440,7 @@
             value[length] = 0;
             property_set(entry->d_name, value);
         } else {
-            ERROR("Unable to read persistent property file %s: %s\n",
-                  entry->d_name, strerror(errno));
+            PLOG(ERROR) << "Unable to read persistent property file " << entry->d_name;
         }
         close(fd);
     }
@@ -482,27 +473,27 @@
 void load_recovery_id_prop() {
     std::string ro_hardware = property_get("ro.hardware");
     if (ro_hardware.empty()) {
-        ERROR("ro.hardware not set - unable to load recovery id\n");
+        LOG(ERROR) << "ro.hardware not set - unable to load recovery id";
         return;
     }
     std::string fstab_filename = FSTAB_PREFIX + ro_hardware;
 
     std::unique_ptr<fstab, void(*)(fstab*)> tab(fs_mgr_read_fstab(fstab_filename.c_str()),
-            fs_mgr_free_fstab);
+                                                fs_mgr_free_fstab);
     if (!tab) {
-        ERROR("unable to read fstab %s: %s\n", fstab_filename.c_str(), strerror(errno));
+        PLOG(ERROR) << "unable to read fstab " << fstab_filename;
         return;
     }
 
     fstab_rec* rec = fs_mgr_get_entry_for_mount_point(tab.get(), RECOVERY_MOUNT_POINT);
     if (rec == NULL) {
-        ERROR("/recovery not specified in fstab\n");
+        LOG(ERROR) << "/recovery not specified in fstab";
         return;
     }
 
     int fd = open(rec->blk_device, O_RDONLY);
     if (fd == -1) {
-        ERROR("error opening block device %s: %s\n", rec->blk_device, strerror(errno));
+        PLOG(ERROR) << "error opening block device " << rec->blk_device;
         return;
     }
 
@@ -511,7 +502,7 @@
         std::string hex = bytes_to_hex(reinterpret_cast<uint8_t*>(hdr.id), sizeof(hdr.id));
         property_set("ro.recovery_id", hex.c_str());
     } else {
-        ERROR("error reading /recovery: %s\n", strerror(errno));
+        PLOG(ERROR) << "error reading /recovery";
     }
 
     close(fd);
@@ -528,7 +519,7 @@
     property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
                                     0666, 0, 0, NULL);
     if (property_set_fd == -1) {
-        ERROR("start_property_service socket creation failed: %s\n", strerror(errno));
+        PLOG(ERROR) << "start_property_service socket creation failed";
         exit(1);
     }
 
diff --git a/init/property_service.h b/init/property_service.h
index dbaed34..e3a2acb 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -34,6 +34,7 @@
 extern void start_property_service(void);
 std::string property_get(const char* name);
 extern int property_set(const char *name, const char *value);
+extern bool is_legal_property_name(const std::string &name);
 
 
 #endif  /* _INIT_PROPERTY_H */
diff --git a/init/readme.txt b/init/readme.txt
index dad7e06..3cfdc4e 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -122,6 +122,13 @@
 Options are modifiers to services.  They affect how and when init
 runs the service.
 
+console [<console>]
+  This service needs a console. The optional second parameter chooses a
+  specific console instead of the default. The default "/dev/console" can
+  be changed by setting the "androidboot.console" kernel parameter. In
+  all cases the leading "/dev/" should be omitted, so "/dev/tty0" would be
+  specified as just "console tty0".
+
 critical
   This is a device-critical service. If it exits more than four times in
   four minutes, the device will reboot into recovery mode.
@@ -134,33 +141,49 @@
   Set the environment variable <name> to <value> in the launched process.
 
 socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]
-  Create a unix domain socket named /dev/socket/<name> and pass
-  its fd to the launched process.  <type> must be "dgram", "stream" or "seqpacket".
-  User and group default to 0.
-  'seclabel' is the SELinux security context for the socket.
-  It defaults to the service security context, as specified by seclabel or
-  computed based on the service executable file security context.
+  Create a unix domain socket named /dev/socket/<name> and pass its fd to the
+  launched process.  <type> must be "dgram", "stream" or "seqpacket".  User and
+  group default to 0.  'seclabel' is the SELinux security context for the
+  socket.  It defaults to the service security context, as specified by
+  seclabel or computed based on the service executable file security context.
+  For native executables see libcutils android_get_control_socket().
+
+file <path> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]
+  Open/Create a file path and pass its fd to the launched process.  <type> must
+  be "r", "w" or "rw".  User and group default to 0.  'seclabel' is the SELinux
+  security context for the file if it must be created.  It defaults to the
+  service security context, as specified by seclabel or computed based on the
+  service executable file security context.  For native executables see
+  libcutils android_get_control_file().
 
 user <username>
-  Change to username before exec'ing this service.
+  Change to 'username' before exec'ing this service.
   Currently defaults to root.  (??? probably should default to nobody)
   As of Android M, processes should use this option even if they
-  require linux capabilities.  Previously, to acquire linux
+  require Linux capabilities.  Previously, to acquire Linux
   capabilities, a process would need to run as root, request the
   capabilities, then drop to its desired uid.  There is a new
   mechanism through fs_config that allows device manufacturers to add
-  linux capabilities to specific binaries on a file system that should
+  Linux capabilities to specific binaries on a file system that should
   be used instead. This mechanism is described on
   http://source.android.com/devices/tech/config/filesystem.html.  When
   using this new mechanism, processes can use the user option to
   select their desired uid without ever running as root.
+  As of Android O, processes can also request capabilities directly in their .rc
+  files. See the "capabilities" option below.
 
 group <groupname> [ <groupname> ]*
-  Change to groupname before exec'ing this service.  Additional
+  Change to 'groupname' before exec'ing this service.  Additional
   groupnames beyond the (required) first one are used to set the
   supplemental groups of the process (via setgroups()).
   Currently defaults to root.  (??? probably should default to nobody)
 
+capabilities <capability> [ <capability> ]*
+  Set capabilities when exec'ing this service. 'capability' should be a Linux
+  capability without the "CAP_" prefix, like "NET_ADMIN" or "SETPCAP". See
+  http://man7.org/linux/man-pages/man7/capabilities.7.html for a list of Linux
+  capabilities.
+
 seclabel <seclabel>
   Change to 'seclabel' before exec'ing this service.
   Primarily for use by services run from the rootfs, e.g. ueventd, adbd.
@@ -184,6 +207,17 @@
   Write the child's pid to the given files when it forks. Meant for
   cgroup/cpuset usage.
 
+priority <priority>
+  Scheduling priority of the service process. This value has to be in range
+  -20 to 19. Default priority is 0. Priority is set via setpriority().
+
+namespace <pid|mnt>
+  Enter a new PID or mount namespace when forking the service.
+
+oom_score_adjust <value>
+   Sets the child's /proc/self/oom_score_adj to the specified value,
+   which must range from -1000 to 1000.
+
 
 Triggers
 --------
@@ -278,8 +312,11 @@
 ifup <interface>
    Bring the network interface <interface> online.
 
-insmod <path>
-   Install the module at <path>
+insmod [-f] <path> [<options>]
+   Install the module at <path> with the specified options.
+   -f
+   Force installation of the module even if the version of the running kernel
+   and the version of the kernel for which the module was compiled do not match.
 
 load_all_props
    Loads properties from /system, /vendor, et cetera.
@@ -306,8 +343,6 @@
 
 mount <type> <device> <dir> [ <flag> ]* [<options>]
    Attempt to mount the named device at the directory <dir>
-   <device> may be of the form mtd@name to specify a mtd block
-   device by name.
    <flag>s include "ro", "rw", "remount", "noatime", ...
    <options> include "barrier=1", "noauto_da_alloc", "discard", ... as
    a comma separated string, eg: barrier=1,noauto_da_alloc
@@ -408,8 +443,16 @@
 Init provides information about the services that it is responsible
 for via the below properties.
 
+init.start
+  Time after boot in ns (via the CLOCK_BOOTTIME clock) at which the first
+  stage of init started.
+
 init.svc.<name>
-   State of a named service ("stopped", "stopping", "running", "restarting")
+  State of a named service ("stopped", "stopping", "running", "restarting")
+
+init.svc.<name>.start
+  Time after boot in ns (via the CLOCK_BOOTTIME clock) that the service was
+  most recently started.
 
 
 Bootcharting
@@ -505,15 +548,12 @@
 
 For quicker turnaround when working on init itself, use:
 
-  mm -j
-  m ramdisk-nodeps
-  m bootimage-nodeps
-  adb reboot bootloader
+  mm -j &&
+  m ramdisk-nodeps &&
+  m bootimage-nodeps &&
+  adb reboot bootloader &&
   fastboot boot $ANDROID_PRODUCT_OUT/boot.img
 
 Alternatively, use the emulator:
 
   emulator -partition-size 1024 -verbose -show-kernel -no-window
-
-You might want to call klog_set_level(6) after the klog_init() call
-so you see the kernel logging in dmesg (or the emulator output).
diff --git a/init/service.cpp b/init/service.cpp
index 3149f8e..1f53a1b 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -17,7 +17,14 @@
 #include "service.h"
 
 #include <fcntl.h>
+#include <inttypes.h>
+#include <linux/securebits.h>
+#include <sched.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
 #include <sys/stat.h>
+#include <sys/time.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <termios.h>
@@ -26,9 +33,13 @@
 #include <selinux/selinux.h>
 
 #include <android-base/file.h>
+#include <android-base/parseint.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <cutils/android_reboot.h>
-#include <cutils/sockets.h>
+#include <system/thread_defs.h>
+
+#include <processgroup/processgroup.h>
 
 #include "action.h"
 #include "init.h"
@@ -37,18 +48,98 @@
 #include "property_service.h"
 #include "util.h"
 
+using android::base::ParseInt;
 using android::base::StringPrintf;
 using android::base::WriteStringToFile;
 
-#define CRITICAL_CRASH_THRESHOLD    4       // if we crash >4 times ...
-#define CRITICAL_CRASH_WINDOW       (4*60)  // ... in 4 minutes, goto recovery
+static std::string ComputeContextFromExecutable(std::string& service_name,
+                                                const std::string& service_path) {
+    std::string computed_context;
 
-SocketInfo::SocketInfo() : uid(0), gid(0), perm(0) {
+    char* raw_con = nullptr;
+    char* raw_filecon = nullptr;
+
+    if (getcon(&raw_con) == -1) {
+        LOG(ERROR) << "could not get context while starting '" << service_name << "'";
+        return "";
+    }
+    std::unique_ptr<char> mycon(raw_con);
+
+    if (getfilecon(service_path.c_str(), &raw_filecon) == -1) {
+        LOG(ERROR) << "could not get file context while starting '" << service_name << "'";
+        return "";
+    }
+    std::unique_ptr<char> filecon(raw_filecon);
+
+    char* new_con = nullptr;
+    int rc = security_compute_create(mycon.get(), filecon.get(),
+                                     string_to_security_class("process"), &new_con);
+    if (rc == 0) {
+        computed_context = new_con;
+        free(new_con);
+    }
+    if (rc == 0 && computed_context == mycon.get()) {
+        LOG(ERROR) << "service " << service_name << " does not have a SELinux domain defined";
+        return "";
+    }
+    if (rc < 0) {
+        LOG(ERROR) << "could not get context while starting '" << service_name << "'";
+        return "";
+    }
+    return computed_context;
 }
 
-SocketInfo::SocketInfo(const std::string& name, const std::string& type, uid_t uid,
-                       gid_t gid, int perm, const std::string& socketcon)
-    : name(name), type(type), uid(uid), gid(gid), perm(perm), socketcon(socketcon) {
+static void SetUpPidNamespace(const std::string& service_name) {
+    constexpr unsigned int kSafeFlags = MS_NODEV | MS_NOEXEC | MS_NOSUID;
+
+    // It's OK to LOG(FATAL) in this function since it's running in the first
+    // child process.
+    if (mount("", "/proc", "proc", kSafeFlags | MS_REMOUNT, "") == -1) {
+        PLOG(FATAL) << "couldn't remount(/proc) for " << service_name;
+    }
+
+    if (prctl(PR_SET_NAME, service_name.c_str()) == -1) {
+        PLOG(FATAL) << "couldn't set name for " << service_name;
+    }
+
+    pid_t child_pid = fork();
+    if (child_pid == -1) {
+        PLOG(FATAL) << "couldn't fork init inside the PID namespace for " << service_name;
+    }
+
+    if (child_pid > 0) {
+        // So that we exit with the right status.
+        static int init_exitstatus = 0;
+        signal(SIGTERM, [](int) { _exit(init_exitstatus); });
+
+        pid_t waited_pid;
+        int status;
+        while ((waited_pid = wait(&status)) > 0) {
+             // This loop will end when there are no processes left inside the
+             // PID namespace or when the init process inside the PID namespace
+             // gets a signal.
+            if (waited_pid == child_pid) {
+                init_exitstatus = status;
+            }
+        }
+        if (!WIFEXITED(init_exitstatus)) {
+            _exit(EXIT_FAILURE);
+        }
+        _exit(WEXITSTATUS(init_exitstatus));
+    }
+}
+
+static void ExpandArgs(const std::vector<std::string>& args, std::vector<char*>* strs) {
+    std::vector<std::string> expanded_args;
+    expanded_args.resize(args.size());
+    strs->push_back(const_cast<char*>(args[0].c_str()));
+    for (std::size_t i = 1; i < args.size(); ++i) {
+        if (!expand_props(args[i], &expanded_args[i])) {
+            LOG(FATAL) << args[0] << ": cannot expand '" << args[i] << "'";
+        }
+        strs->push_back(const_cast<char*>(expanded_args[i].c_str()));
+    }
+    strs->push_back(nullptr);
 }
 
 ServiceEnvironmentInfo::ServiceEnvironmentInfo() {
@@ -61,18 +152,25 @@
 
 Service::Service(const std::string& name, const std::string& classname,
                  const std::vector<std::string>& args)
-    : name_(name), classname_(classname), flags_(0), pid_(0), time_started_(0),
-      time_crashed_(0), nr_crashed_(0), uid_(0), gid_(0), seclabel_(""),
-      ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), args_(args) {
+    : name_(name), classname_(classname), flags_(0), pid_(0),
+      crash_count_(0), uid_(0), gid_(0), namespace_flags_(0),
+      seclabel_(""), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0),
+      priority_(0), oom_score_adjust_(-1000), args_(args) {
     onrestart_.InitSingleTrigger("onrestart");
 }
 
 Service::Service(const std::string& name, const std::string& classname,
-                 unsigned flags, uid_t uid, gid_t gid, const std::vector<gid_t>& supp_gids,
-                 const std::string& seclabel,  const std::vector<std::string>& args)
-    : name_(name), classname_(classname), flags_(flags), pid_(0), time_started_(0),
-      time_crashed_(0), nr_crashed_(0), uid_(uid), gid_(gid), supp_gids_(supp_gids),
-      seclabel_(seclabel), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), args_(args) {
+                 unsigned flags, uid_t uid, gid_t gid,
+                 const std::vector<gid_t>& supp_gids,
+                 const CapSet& capabilities, unsigned namespace_flags,
+                 const std::string& seclabel,
+                 const std::vector<std::string>& args)
+    : name_(name), classname_(classname), flags_(flags), pid_(0),
+      crash_count_(0), uid_(uid), gid_(gid),
+      supp_gids_(supp_gids), capabilities_(capabilities),
+      namespace_flags_(namespace_flags), seclabel_(seclabel),
+      ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), priority_(0),
+      oom_score_adjust_(-1000), args_(args) {
     onrestart_.InitSingleTrigger("onrestart");
 }
 
@@ -85,29 +183,83 @@
     std::string prop_name = StringPrintf("init.svc.%s", name_.c_str());
     if (prop_name.length() >= PROP_NAME_MAX) {
         // If the property name would be too long, we can't set it.
-        ERROR("Property name \"init.svc.%s\" too long; not setting to %s\n",
-              name_.c_str(), new_state.c_str());
+        LOG(ERROR) << "Property name \"init.svc." << name_ << "\" too long; not setting to " << new_state;
         return;
     }
 
     property_set(prop_name.c_str(), new_state.c_str());
+
+    if (new_state == "running") {
+        prop_name += ".start";
+        uint64_t start_ns = time_started_.time_since_epoch().count();
+        property_set(prop_name.c_str(), StringPrintf("%" PRIu64, start_ns).c_str());
+    }
+}
+
+void Service::KillProcessGroup(int signal) {
+    LOG(INFO) << "Sending signal " << signal
+              << " to service '" << name_
+              << "' (pid " << pid_ << ") process group...";
+    if (killProcessGroup(uid_, pid_, signal) == -1) {
+        PLOG(ERROR) << "killProcessGroup(" << uid_ << ", " << pid_ << ", " << signal << ") failed";
+    }
+    if (kill(-pid_, signal) == -1) {
+        PLOG(ERROR) << "kill(" << pid_ << ", " << signal << ") failed";
+    }
+}
+
+void Service::SetProcessAttributes() {
+    // Keep capabilites on uid change.
+    if (capabilities_.any() && uid_) {
+        if (prctl(PR_SET_SECUREBITS, SECBIT_KEEP_CAPS | SECBIT_KEEP_CAPS_LOCKED) != 0) {
+            PLOG(FATAL) << "prtcl(PR_SET_KEEPCAPS) failed for " << name_;
+        }
+    }
+
+    // TODO: work out why this fails for `console` then upgrade to FATAL.
+    if (setpgid(0, getpid()) == -1) PLOG(ERROR) << "setpgid failed for " << name_;
+
+    if (gid_) {
+        if (setgid(gid_) != 0) {
+            PLOG(FATAL) << "setgid failed for " << name_;
+        }
+    }
+    if (setgroups(supp_gids_.size(), &supp_gids_[0]) != 0) {
+        PLOG(FATAL) << "setgroups failed for " << name_;
+    }
+    if (uid_) {
+        if (setuid(uid_) != 0) {
+            PLOG(FATAL) << "setuid failed for " << name_;
+        }
+    }
+    if (!seclabel_.empty()) {
+        if (setexeccon(seclabel_.c_str()) < 0) {
+            PLOG(FATAL) << "cannot setexeccon('" << seclabel_ << "') for " << name_;
+        }
+    }
+    if (priority_ != 0) {
+        if (setpriority(PRIO_PROCESS, 0, priority_) != 0) {
+            PLOG(FATAL) << "setpriority failed for " << name_;
+        }
+    }
+    if (capabilities_.any()) {
+        if (!SetCapsForExec(capabilities_)) {
+            LOG(FATAL) << "cannot set capabilities for " << name_;
+        }
+    }
 }
 
 bool Service::Reap() {
     if (!(flags_ & SVC_ONESHOT) || (flags_ & SVC_RESTART)) {
-        NOTICE("Service '%s' (pid %d) killing any children in process group\n",
-               name_.c_str(), pid_);
-        kill(-pid_, SIGKILL);
+        KillProcessGroup(SIGKILL);
     }
 
-    // Remove any sockets we may have created.
-    for (const auto& si : sockets_) {
-        std::string tmp = StringPrintf(ANDROID_SOCKET_DIR "/%s", si.name.c_str());
-        unlink(tmp.c_str());
-    }
+    // Remove any descriptor resources we may have created.
+    std::for_each(descriptors_.begin(), descriptors_.end(),
+                  std::bind(&DescriptorInfo::Clean, std::placeholders::_1));
 
     if (flags_ & SVC_EXEC) {
-        INFO("SVC_EXEC pid %d finished...\n", pid_);
+        LOG(INFO) << "SVC_EXEC pid " << pid_ << " finished...";
         return true;
     }
 
@@ -126,19 +278,19 @@
         return false;
     }
 
-    time_t now = gettime();
+    // If we crash > 4 times in 4 minutes, reboot into recovery.
+    boot_clock::time_point now = boot_clock::now();
     if ((flags_ & SVC_CRITICAL) && !(flags_ & SVC_RESTART)) {
-        if (time_crashed_ + CRITICAL_CRASH_WINDOW >= now) {
-            if (++nr_crashed_ > CRITICAL_CRASH_THRESHOLD) {
-                ERROR("critical process '%s' exited %d times in %d minutes; "
-                      "rebooting into recovery mode\n", name_.c_str(),
-                      CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);
+        if (now < time_crashed_ + 4min) {
+            if (++crash_count_ > 4) {
+                LOG(ERROR) << "critical process '" << name_ << "' exited 4 times in 4 minutes; "
+                           << "rebooting into recovery mode";
                 android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
                 return false;
             }
         } else {
             time_crashed_ = now;
-            nr_crashed_ = 1;
+            crash_count_ = 1;
         }
     }
 
@@ -153,40 +305,51 @@
 }
 
 void Service::DumpState() const {
-    INFO("service %s\n", name_.c_str());
-    INFO("  class '%s'\n", classname_.c_str());
-    INFO("  exec");
-    for (const auto& s : args_) {
-        INFO(" '%s'", s.c_str());
-    }
-    INFO("\n");
-    for (const auto& si : sockets_) {
-        INFO("  socket %s %s 0%o\n", si.name.c_str(), si.type.c_str(), si.perm);
-    }
+    LOG(INFO) << "service " << name_;
+    LOG(INFO) << "  class '" << classname_ << "'";
+    LOG(INFO) << "  exec "<< android::base::Join(args_, " ");
+    std::for_each(descriptors_.begin(), descriptors_.end(),
+                  [] (const auto& info) { LOG(INFO) << *info; });
 }
 
-bool Service::HandleClass(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseCapabilities(const std::vector<std::string>& args, std::string* err) {
+    capabilities_ = 0;
+
+    for (size_t i = 1; i < args.size(); i++) {
+        const std::string& arg = args[i];
+        int cap = LookupCap(arg);
+        if (cap == -1) {
+            *err = StringPrintf("invalid capability '%s'", arg.c_str());
+            return false;
+        }
+        capabilities_[cap] = true;
+    }
+    return true;
+}
+
+bool Service::ParseClass(const std::vector<std::string>& args, std::string* err) {
     classname_ = args[1];
     return true;
 }
 
-bool Service::HandleConsole(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseConsole(const std::vector<std::string>& args, std::string* err) {
     flags_ |= SVC_CONSOLE;
+    console_ = args.size() > 1 ? "/dev/" + args[1] : "";
     return true;
 }
 
-bool Service::HandleCritical(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseCritical(const std::vector<std::string>& args, std::string* err) {
     flags_ |= SVC_CRITICAL;
     return true;
 }
 
-bool Service::HandleDisabled(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseDisabled(const std::vector<std::string>& args, std::string* err) {
     flags_ |= SVC_DISABLED;
     flags_ |= SVC_RC_DISABLED;
     return true;
 }
 
-bool Service::HandleGroup(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseGroup(const std::vector<std::string>& args, std::string* err) {
     gid_ = decode_uid(args[1].c_str());
     for (std::size_t n = 2; n < args.size(); n++) {
         supp_gids_.emplace_back(decode_uid(args[n].c_str()));
@@ -194,10 +357,20 @@
     return true;
 }
 
-bool Service::HandleIoprio(const std::vector<std::string>& args, std::string* err) {
-    ioprio_pri_ = std::stoul(args[2], 0, 8);
+bool Service::ParsePriority(const std::vector<std::string>& args, std::string* err) {
+    priority_ = 0;
+    if (!ParseInt(args[1], &priority_,
+                  static_cast<int>(ANDROID_PRIORITY_HIGHEST), // highest is negative
+                  static_cast<int>(ANDROID_PRIORITY_LOWEST))) {
+        *err = StringPrintf("process priority value must be range %d - %d",
+                ANDROID_PRIORITY_HIGHEST, ANDROID_PRIORITY_LOWEST);
+        return false;
+    }
+    return true;
+}
 
-    if (ioprio_pri_ < 0 || ioprio_pri_ > 7) {
+bool Service::ParseIoprio(const std::vector<std::string>& args, std::string* err) {
+    if (!ParseInt(args[2], &ioprio_pri_, 0, 7)) {
         *err = "priority value must be range 0 - 7";
         return false;
     }
@@ -216,110 +389,173 @@
     return true;
 }
 
-bool Service::HandleKeycodes(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseKeycodes(const std::vector<std::string>& args, std::string* err) {
     for (std::size_t i = 1; i < args.size(); i++) {
-        keycodes_.emplace_back(std::stoi(args[i]));
+        int code;
+        if (ParseInt(args[i], &code)) {
+            keycodes_.emplace_back(code);
+        } else {
+            LOG(WARNING) << "ignoring invalid keycode: " << args[i];
+        }
     }
     return true;
 }
 
-bool Service::HandleOneshot(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseOneshot(const std::vector<std::string>& args, std::string* err) {
     flags_ |= SVC_ONESHOT;
     return true;
 }
 
-bool Service::HandleOnrestart(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseOnrestart(const std::vector<std::string>& args, std::string* err) {
     std::vector<std::string> str_args(args.begin() + 1, args.end());
     onrestart_.AddCommand(str_args, "", 0, err);
     return true;
 }
 
-bool Service::HandleSeclabel(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseNamespace(const std::vector<std::string>& args, std::string* err) {
+    for (size_t i = 1; i < args.size(); i++) {
+        if (args[i] == "pid") {
+            namespace_flags_ |= CLONE_NEWPID;
+            // PID namespaces require mount namespaces.
+            namespace_flags_ |= CLONE_NEWNS;
+        } else if (args[i] == "mnt") {
+            namespace_flags_ |= CLONE_NEWNS;
+        } else {
+            *err = "namespace must be 'pid' or 'mnt'";
+            return false;
+        }
+    }
+    return true;
+}
+
+bool Service::ParseOomScoreAdjust(const std::vector<std::string>& args, std::string* err) {
+    if (!ParseInt(args[1], &oom_score_adjust_, -1000, 1000)) {
+        *err = "oom_score_adjust value must be in range -1000 - +1000";
+        return false;
+    }
+    return true;
+}
+
+bool Service::ParseSeclabel(const std::vector<std::string>& args, std::string* err) {
     seclabel_ = args[1];
     return true;
 }
 
-bool Service::HandleSetenv(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseSetenv(const std::vector<std::string>& args, std::string* err) {
     envvars_.emplace_back(args[1], args[2]);
     return true;
 }
 
-/* name type perm [ uid gid context ] */
-bool Service::HandleSocket(const std::vector<std::string>& args, std::string* err) {
+template <typename T>
+bool Service::AddDescriptor(const std::vector<std::string>& args, std::string* err) {
+    int perm = args.size() > 3 ? std::strtoul(args[3].c_str(), 0, 8) : -1;
+    uid_t uid = args.size() > 4 ? decode_uid(args[4].c_str()) : 0;
+    gid_t gid = args.size() > 5 ? decode_uid(args[5].c_str()) : 0;
+    std::string context = args.size() > 6 ? args[6] : "";
+
+    auto descriptor = std::make_unique<T>(args[1], args[2], uid, gid, perm, context);
+
+    auto old =
+        std::find_if(descriptors_.begin(), descriptors_.end(),
+                     [&descriptor] (const auto& other) { return descriptor.get() == other.get(); });
+
+    if (old != descriptors_.end()) {
+        *err = "duplicate descriptor " + args[1] + " " + args[2];
+        return false;
+    }
+
+    descriptors_.emplace_back(std::move(descriptor));
+    return true;
+}
+
+// name type perm [ uid gid context ]
+bool Service::ParseSocket(const std::vector<std::string>& args, std::string* err) {
     if (args[2] != "dgram" && args[2] != "stream" && args[2] != "seqpacket") {
         *err = "socket type must be 'dgram', 'stream' or 'seqpacket'";
         return false;
     }
-
-    int perm = std::stoul(args[3], 0, 8);
-    uid_t uid = args.size() > 4 ? decode_uid(args[4].c_str()) : 0;
-    gid_t gid = args.size() > 5 ? decode_uid(args[5].c_str()) : 0;
-    std::string socketcon = args.size() > 6 ? args[6] : "";
-
-    sockets_.emplace_back(args[1], args[2], uid, gid, perm, socketcon);
-    return true;
+    return AddDescriptor<SocketInfo>(args, err);
 }
 
-bool Service::HandleUser(const std::vector<std::string>& args, std::string* err) {
+// name type perm [ uid gid context ]
+bool Service::ParseFile(const std::vector<std::string>& args, std::string* err) {
+    if (args[2] != "r" && args[2] != "w" && args[2] != "rw") {
+        *err = "file type must be 'r', 'w' or 'rw'";
+        return false;
+    }
+    if ((args[1][0] != '/') || (args[1].find("../") != std::string::npos)) {
+        *err = "file name must not be relative";
+        return false;
+    }
+    return AddDescriptor<FileInfo>(args, err);
+}
+
+bool Service::ParseUser(const std::vector<std::string>& args, std::string* err) {
     uid_ = decode_uid(args[1].c_str());
     return true;
 }
 
-bool Service::HandleWritepid(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseWritepid(const std::vector<std::string>& args, std::string* err) {
     writepid_files_.assign(args.begin() + 1, args.end());
     return true;
 }
 
-class Service::OptionHandlerMap : public KeywordMap<OptionHandler> {
+class Service::OptionParserMap : public KeywordMap<OptionParser> {
 public:
-    OptionHandlerMap() {
+    OptionParserMap() {
     }
 private:
     Map& map() const override;
 };
 
-Service::OptionHandlerMap::Map& Service::OptionHandlerMap::map() const {
+Service::OptionParserMap::Map& Service::OptionParserMap::map() const {
     constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
-    static const Map option_handlers = {
-        {"class",       {1,     1,    &Service::HandleClass}},
-        {"console",     {0,     0,    &Service::HandleConsole}},
-        {"critical",    {0,     0,    &Service::HandleCritical}},
-        {"disabled",    {0,     0,    &Service::HandleDisabled}},
-        {"group",       {1,     NR_SVC_SUPP_GIDS + 1, &Service::HandleGroup}},
-        {"ioprio",      {2,     2,    &Service::HandleIoprio}},
-        {"keycodes",    {1,     kMax, &Service::HandleKeycodes}},
-        {"oneshot",     {0,     0,    &Service::HandleOneshot}},
-        {"onrestart",   {1,     kMax, &Service::HandleOnrestart}},
-        {"seclabel",    {1,     1,    &Service::HandleSeclabel}},
-        {"setenv",      {2,     2,    &Service::HandleSetenv}},
-        {"socket",      {3,     6,    &Service::HandleSocket}},
-        {"user",        {1,     1,    &Service::HandleUser}},
-        {"writepid",    {1,     kMax, &Service::HandleWritepid}},
+    static const Map option_parsers = {
+        {"capabilities",
+                        {1,     kMax, &Service::ParseCapabilities}},
+        {"class",       {1,     1,    &Service::ParseClass}},
+        {"console",     {0,     1,    &Service::ParseConsole}},
+        {"critical",    {0,     0,    &Service::ParseCritical}},
+        {"disabled",    {0,     0,    &Service::ParseDisabled}},
+        {"group",       {1,     NR_SVC_SUPP_GIDS + 1, &Service::ParseGroup}},
+        {"ioprio",      {2,     2,    &Service::ParseIoprio}},
+        {"priority",    {1,     1,    &Service::ParsePriority}},
+        {"keycodes",    {1,     kMax, &Service::ParseKeycodes}},
+        {"oneshot",     {0,     0,    &Service::ParseOneshot}},
+        {"onrestart",   {1,     kMax, &Service::ParseOnrestart}},
+        {"oom_score_adjust",
+                        {1,     1,    &Service::ParseOomScoreAdjust}},
+        {"namespace",   {1,     2,    &Service::ParseNamespace}},
+        {"seclabel",    {1,     1,    &Service::ParseSeclabel}},
+        {"setenv",      {2,     2,    &Service::ParseSetenv}},
+        {"socket",      {3,     6,    &Service::ParseSocket}},
+        {"file",        {2,     6,    &Service::ParseFile}},
+        {"user",        {1,     1,    &Service::ParseUser}},
+        {"writepid",    {1,     kMax, &Service::ParseWritepid}},
     };
-    return option_handlers;
+    return option_parsers;
 }
 
-bool Service::HandleLine(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseLine(const std::vector<std::string>& args, std::string* err) {
     if (args.empty()) {
         *err = "option needed, but not provided";
         return false;
     }
 
-    static const OptionHandlerMap handler_map;
-    auto handler = handler_map.FindFunction(args[0], args.size() - 1, err);
+    static const OptionParserMap parser_map;
+    auto parser = parser_map.FindFunction(args[0], args.size() - 1, err);
 
-    if (!handler) {
+    if (!parser) {
         return false;
     }
 
-    return (this->*handler)(args, err);
+    return (this->*parser)(args, err);
 }
 
 bool Service::Start() {
     // Starting a service removes it from the disabled or reset state and
     // immediately takes it out of the restarting state if it was in there.
     flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
-    time_started_ = 0;
 
     // Running processes require no additional work --- if they're in the
     // process of exiting, we've ensured that they will immediately restart
@@ -329,16 +565,22 @@
     }
 
     bool needs_console = (flags_ & SVC_CONSOLE);
-    if (needs_console && !have_console) {
-        ERROR("service '%s' requires console\n", name_.c_str());
-        flags_ |= SVC_DISABLED;
-        return false;
+    if (needs_console) {
+        if (console_.empty()) {
+            console_ = default_console;
+        }
+
+        bool have_console = (open(console_.c_str(), O_RDWR | O_CLOEXEC) != -1);
+        if (!have_console) {
+            PLOG(ERROR) << "service '" << name_ << "' couldn't open console '" << console_ << "'";
+            flags_ |= SVC_DISABLED;
+            return false;
+        }
     }
 
     struct stat sb;
     if (stat(args_[0].c_str(), &sb) == -1) {
-        ERROR("cannot find '%s' (%s), disabling '%s'\n",
-              args_[0].c_str(), strerror(errno), name_.c_str());
+        PLOG(ERROR) << "cannot find '" << args_[0] << "', disabling '" << name_ << "'";
         flags_ |= SVC_DISABLED;
         return false;
     }
@@ -347,80 +589,49 @@
     if (!seclabel_.empty()) {
         scon = seclabel_;
     } else {
-        char* mycon = nullptr;
-        char* fcon = nullptr;
-
-        INFO("computing context for service '%s'\n", args_[0].c_str());
-        int rc = getcon(&mycon);
-        if (rc < 0) {
-            ERROR("could not get context while starting '%s'\n", name_.c_str());
-            return false;
-        }
-
-        rc = getfilecon(args_[0].c_str(), &fcon);
-        if (rc < 0) {
-            ERROR("could not get context while starting '%s'\n", name_.c_str());
-            free(mycon);
-            return false;
-        }
-
-        char* ret_scon = nullptr;
-        rc = security_compute_create(mycon, fcon, string_to_security_class("process"),
-                                     &ret_scon);
-        if (rc == 0) {
-            scon = ret_scon;
-            free(ret_scon);
-        }
-        if (rc == 0 && scon == mycon) {
-            ERROR("Service %s does not have a SELinux domain defined.\n", name_.c_str());
-            free(mycon);
-            free(fcon);
-            return false;
-        }
-        free(mycon);
-        free(fcon);
-        if (rc < 0) {
-            ERROR("could not get context while starting '%s'\n", name_.c_str());
+        LOG(INFO) << "computing context for service '" << name_ << "'";
+        scon = ComputeContextFromExecutable(name_, args_[0]);
+        if (scon == "") {
             return false;
         }
     }
 
-    NOTICE("Starting service '%s'...\n", name_.c_str());
+    LOG(INFO) << "starting service '" << name_ << "'...";
 
-    pid_t pid = fork();
+    pid_t pid = -1;
+    if (namespace_flags_) {
+        pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);
+    } else {
+        pid = fork();
+    }
+
     if (pid == 0) {
         umask(077);
 
+        if (namespace_flags_ & CLONE_NEWPID) {
+            // This will fork again to run an init process inside the PID
+            // namespace.
+            SetUpPidNamespace(name_);
+        }
+
         for (const auto& ei : envvars_) {
             add_environment(ei.name.c_str(), ei.value.c_str());
         }
 
-        for (const auto& si : sockets_) {
-            int socket_type = ((si.type == "stream" ? SOCK_STREAM :
-                                (si.type == "dgram" ? SOCK_DGRAM :
-                                 SOCK_SEQPACKET)));
-            const char* socketcon =
-                !si.socketcon.empty() ? si.socketcon.c_str() : scon.c_str();
-
-            int s = create_socket(si.name.c_str(), socket_type, si.perm,
-                                  si.uid, si.gid, socketcon);
-            if (s >= 0) {
-                PublishSocket(si.name, s);
-            }
-        }
+        std::for_each(descriptors_.begin(), descriptors_.end(),
+                      std::bind(&DescriptorInfo::CreateAndPublish, std::placeholders::_1, scon));
 
         std::string pid_str = StringPrintf("%d", getpid());
         for (const auto& file : writepid_files_) {
             if (!WriteStringToFile(pid_str, file)) {
-                ERROR("couldn't write %s to %s: %s\n",
-                      pid_str.c_str(), file.c_str(), strerror(errno));
+                PLOG(ERROR) << "couldn't write " << pid_str << " to " << file;
             }
         }
 
         if (ioprio_class_ != IoSchedClass_NONE) {
             if (android_set_ioprio(getpid(), ioprio_class_, ioprio_pri_)) {
-                ERROR("Failed to set pid %d ioprio = %d,%d: %s\n",
-                      getpid(), ioprio_class_, ioprio_pri_, strerror(errno));
+                PLOG(ERROR) << "failed to set pid " << getpid()
+                            << " ioprio=" << ioprio_class_ << "," << ioprio_pri_;
             }
         }
 
@@ -431,69 +642,47 @@
             ZapStdio();
         }
 
-        setpgid(0, getpid());
+        // As requested, set our gid, supplemental gids, uid, context, and
+        // priority. Aborts on failure.
+        SetProcessAttributes();
 
-        // As requested, set our gid, supplemental gids, and uid.
-        if (gid_) {
-            if (setgid(gid_) != 0) {
-                ERROR("setgid failed: %s\n", strerror(errno));
-                _exit(127);
-            }
-        }
-        if (!supp_gids_.empty()) {
-            if (setgroups(supp_gids_.size(), &supp_gids_[0]) != 0) {
-                ERROR("setgroups failed: %s\n", strerror(errno));
-                _exit(127);
-            }
-        }
-        if (uid_) {
-            if (setuid(uid_) != 0) {
-                ERROR("setuid failed: %s\n", strerror(errno));
-                _exit(127);
-            }
-        }
-        if (!seclabel_.empty()) {
-            if (setexeccon(seclabel_.c_str()) < 0) {
-                ERROR("cannot setexeccon('%s'): %s\n",
-                      seclabel_.c_str(), strerror(errno));
-                _exit(127);
-            }
-        }
-
-        std::vector<std::string> expanded_args;
         std::vector<char*> strs;
-        expanded_args.resize(args_.size());
-        strs.push_back(const_cast<char*>(args_[0].c_str()));
-        for (std::size_t i = 1; i < args_.size(); ++i) {
-            if (!expand_props(args_[i], &expanded_args[i])) {
-                ERROR("%s: cannot expand '%s'\n", args_[0].c_str(), args_[i].c_str());
-                _exit(127);
-            }
-            strs.push_back(const_cast<char*>(expanded_args[i].c_str()));
-        }
-        strs.push_back(nullptr);
-
+        ExpandArgs(args_, &strs);
         if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) {
-            ERROR("cannot execve('%s'): %s\n", strs[0], strerror(errno));
+            PLOG(ERROR) << "cannot execve('" << strs[0] << "')";
         }
 
         _exit(127);
     }
 
     if (pid < 0) {
-        ERROR("failed to start '%s'\n", name_.c_str());
+        PLOG(ERROR) << "failed to fork for '" << name_ << "'";
         pid_ = 0;
         return false;
     }
 
-    time_started_ = gettime();
+    if (oom_score_adjust_ != -1000) {
+        std::string oom_str = StringPrintf("%d", oom_score_adjust_);
+        std::string oom_file = StringPrintf("/proc/%d/oom_score_adj", pid);
+        if (!WriteStringToFile(oom_str, oom_file)) {
+            PLOG(ERROR) << "couldn't write oom_score_adj: " << strerror(errno);
+        }
+    }
+
+    time_started_ = boot_clock::now();
     pid_ = pid;
     flags_ |= SVC_RUNNING;
 
+    errno = -createProcessGroup(uid_, pid_);
+    if (errno != 0) {
+        PLOG(ERROR) << "createProcessGroup(" << uid_ << ", " << pid_ << ") failed for service '"
+                    << name_ << "'";
+    }
+
     if ((flags_ & SVC_EXEC) != 0) {
-        INFO("SVC_EXEC pid %d (uid %d gid %d+%zu context %s) started; waiting...\n",
-             pid_, uid_, gid_, supp_gids_.size(),
-             !seclabel_.empty() ? seclabel_.c_str() : "default");
+        LOG(INFO) << android::base::StringPrintf(
+            "SVC_EXEC pid %d (uid %d gid %d+%zu context %s) started; waiting...", pid_, uid_, gid_,
+            supp_gids_.size(), !seclabel_.empty() ? seclabel_.c_str() : "default");
     }
 
     NotifyStateChange("running");
@@ -529,9 +718,7 @@
     flags_ &= ~(SVC_RESTARTING | SVC_DISABLED_START);
     flags_ |= SVC_DISABLED;
     if (pid_) {
-        NOTICE("Sending SIGTERM to service '%s' (pid %d)...\n", name_.c_str(),
-               pid_);
-        kill(-pid_, SIGTERM);
+        KillProcessGroup(SIGTERM);
         NotifyStateChange("stopping");
     }
 }
@@ -546,34 +733,34 @@
     } /* else: Service is restarting anyways. */
 }
 
-void Service::RestartIfNeeded(time_t& process_needs_restart) {
-    time_t next_start_time = time_started_ + 5;
-
-    if (next_start_time <= gettime()) {
+void Service::RestartIfNeeded(time_t* process_needs_restart_at) {
+    boot_clock::time_point now = boot_clock::now();
+    boot_clock::time_point next_start = time_started_ + 5s;
+    if (now > next_start) {
         flags_ &= (~SVC_RESTARTING);
         Start();
         return;
     }
 
-    if ((next_start_time < process_needs_restart) ||
-        (process_needs_restart == 0)) {
-        process_needs_restart = next_start_time;
+    time_t next_start_time_t = time(nullptr) +
+        time_t(std::chrono::duration_cast<std::chrono::seconds>(next_start - now).count());
+    if (next_start_time_t < *process_needs_restart_at || *process_needs_restart_at == 0) {
+        *process_needs_restart_at = next_start_time_t;
     }
 }
 
-/* The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART */
+// The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART.
 void Service::StopOrReset(int how) {
-    /* The service is still SVC_RUNNING until its process exits, but if it has
-     * already exited it shoudn't attempt a restart yet. */
+    // The service is still SVC_RUNNING until its process exits, but if it has
+    // already exited it shoudn't attempt a restart yet.
     flags_ &= ~(SVC_RESTARTING | SVC_DISABLED_START);
 
     if ((how != SVC_DISABLED) && (how != SVC_RESET) && (how != SVC_RESTART)) {
-        /* Hrm, an illegal flag.  Default to SVC_DISABLED */
+        // An illegal flag: default to SVC_DISABLED.
         how = SVC_DISABLED;
     }
-        /* if the service has not yet started, prevent
-         * it from auto-starting with its class
-         */
+
+    // If the service has not yet started, prevent it from auto-starting with its class.
     if (how == SVC_RESET) {
         flags_ |= (flags_ & SVC_RC_DISABLED) ? SVC_DISABLED : SVC_RESET;
     } else {
@@ -581,8 +768,7 @@
     }
 
     if (pid_) {
-        NOTICE("Service '%s' is being killed...\n", name_.c_str());
-        kill(-pid_, SIGKILL);
+        KillProcessGroup(SIGKILL);
         NotifyStateChange("stopping");
     } else {
         NotifyStateChange("stopped");
@@ -599,10 +785,8 @@
 }
 
 void Service::OpenConsole() const {
-    int fd;
-    if ((fd = open(console_name.c_str(), O_RDWR)) < 0) {
-        fd = open("/dev/null", O_RDWR);
-    }
+    int fd = open(console_.c_str(), O_RDWR);
+    if (fd == -1) fd = open("/dev/null", O_RDWR);
     ioctl(fd, TIOCSCTTY, 0);
     dup2(fd, 0);
     dup2(fd, 1);
@@ -610,15 +794,6 @@
     close(fd);
 }
 
-void Service::PublishSocket(const std::string& name, int fd) const {
-    std::string key = StringPrintf(ANDROID_SOCKET_ENV_PREFIX "%s", name.c_str());
-    std::string val = StringPrintf("%d", fd);
-    add_environment(key.c_str(), val.c_str());
-
-    /* make sure we don't close-on-exec */
-    fcntl(fd, F_SETFD, 0);
-}
-
 int ServiceManager::exec_count_ = 0;
 
 ServiceManager::ServiceManager() {
@@ -632,8 +807,7 @@
 void ServiceManager::AddService(std::unique_ptr<Service> service) {
     Service* old_service = FindServiceByName(service->name());
     if (old_service) {
-        ERROR("ignored duplicate definition of service '%s'",
-              service->name().c_str());
+        LOG(ERROR) << "ignored duplicate definition of service '" << service->name() << "'";
         return;
     }
     services_.emplace_back(std::move(service));
@@ -650,12 +824,12 @@
         }
     }
     if (command_arg > 4 + NR_SVC_SUPP_GIDS) {
-        ERROR("exec called with too many supplementary group ids\n");
+        LOG(ERROR) << "exec called with too many supplementary group ids";
         return nullptr;
     }
 
     if (command_arg >= args.size()) {
-        ERROR("exec called without command\n");
+        LOG(ERROR) << "exec called without command";
         return nullptr;
     }
     std::vector<std::string> str_args(args.begin() + command_arg, args.end());
@@ -663,6 +837,8 @@
     exec_count_++;
     std::string name = StringPrintf("exec %d (%s)", exec_count_, str_args[0].c_str());
     unsigned flags = SVC_EXEC | SVC_ONESHOT;
+    CapSet no_capabilities;
+    unsigned namespace_flags = 0;
 
     std::string seclabel = "";
     if (command_arg > 2 && args[1] != "-") {
@@ -682,11 +858,11 @@
         }
     }
 
-    std::unique_ptr<Service> svc_p(new Service(name, "default", flags, uid, gid,
-                                               supp_gids, seclabel, str_args));
+    std::unique_ptr<Service> svc_p(new Service(name, "default", flags, uid, gid, supp_gids,
+                                               no_capabilities, namespace_flags, seclabel,
+                                               str_args));
     if (!svc_p) {
-        ERROR("Couldn't allocate service for exec of '%s'",
-              str_args[0].c_str());
+        LOG(ERROR) << "Couldn't allocate service for exec of '" << str_args[0] << "'";
         return nullptr;
     }
     Service* svc = svc_p.get();
@@ -729,7 +905,7 @@
     return nullptr;
 }
 
-void ServiceManager::ForEachService(std::function<void(Service*)> callback) const {
+void ServiceManager::ForEachService(const std::function<void(Service*)>& callback) const {
     for (const auto& s : services_) {
         callback(s.get());
     }
@@ -769,7 +945,6 @@
     for (const auto& s : services_) {
         s->DumpState();
     }
-    INFO("\n");
 }
 
 bool ServiceManager::ReapOneProcess() {
@@ -778,7 +953,7 @@
     if (pid == 0) {
         return false;
     } else if (pid == -1) {
-        ERROR("waitpid failed: %s\n", strerror(errno));
+        PLOG(ERROR) << "waitpid failed";
         return false;
     }
 
@@ -793,13 +968,13 @@
     }
 
     if (WIFEXITED(status)) {
-        NOTICE("%s exited with status %d\n", name.c_str(), WEXITSTATUS(status));
+        LOG(INFO) << name << " exited with status " << WEXITSTATUS(status);
     } else if (WIFSIGNALED(status)) {
-        NOTICE("%s killed by signal %d\n", name.c_str(), WTERMSIG(status));
+        LOG(INFO) << name << " killed by signal " << WTERMSIG(status);
     } else if (WIFSTOPPED(status)) {
-        NOTICE("%s stopped by signal %d\n", name.c_str(), WSTOPSIG(status));
+        LOG(INFO) << name << " stopped by signal " << WSTOPSIG(status);
     } else {
-        NOTICE("%s state changed", name.c_str());
+        LOG(INFO) << name << " state changed";
     }
 
     if (!svc) {
@@ -840,7 +1015,7 @@
 bool ServiceParser::ParseLineSection(const std::vector<std::string>& args,
                                      const std::string& filename, int line,
                                      std::string* err) const {
-    return service_ ? service_->HandleLine(args, err) : false;
+    return service_ ? service_->ParseLine(args, err) : false;
 }
 
 void ServiceParser::EndSection() {
@@ -850,13 +1025,5 @@
 }
 
 bool ServiceParser::IsValidName(const std::string& name) const {
-    if (name.size() > 16) {
-        return false;
-    }
-    for (const auto& c : name) {
-        if (!isalnum(c) && (c != '_') && (c != '-')) {
-            return false;
-        }
-    }
-    return true;
+    return is_legal_property_name("init.svc." + name);
 }
diff --git a/init/service.h b/init/service.h
index d9d18ef..013e65f 100644
--- a/init/service.h
+++ b/init/service.h
@@ -26,8 +26,11 @@
 #include <vector>
 
 #include "action.h"
+#include "capabilities.h"
+#include "descriptors.h"
 #include "init_parser.h"
 #include "keyword_map.h"
+#include "util.h"
 
 #define SVC_DISABLED       0x001  // do not autostart with class
 #define SVC_ONESHOT        0x002  // do not restart on exit
@@ -47,18 +50,6 @@
 class Action;
 class ServiceManager;
 
-struct SocketInfo {
-    SocketInfo();
-    SocketInfo(const std::string& name, const std::string& type, uid_t uid,
-                       gid_t gid, int perm, const std::string& socketcon);
-    std::string name;
-    std::string type;
-    uid_t uid;
-    gid_t gid;
-    int perm;
-    std::string socketcon;
-};
-
 struct ServiceEnvironmentInfo {
     ServiceEnvironmentInfo();
     ServiceEnvironmentInfo(const std::string& name, const std::string& value);
@@ -72,10 +63,12 @@
             const std::vector<std::string>& args);
 
     Service(const std::string& name, const std::string& classname,
-            unsigned flags, uid_t uid, gid_t gid, const std::vector<gid_t>& supp_gids,
-            const std::string& seclabel,  const std::vector<std::string>& args);
+            unsigned flags, uid_t uid, gid_t gid,
+            const std::vector<gid_t>& supp_gids, const CapSet& capabilities,
+            unsigned namespace_flags, const std::string& seclabel,
+            const std::vector<std::string>& args);
 
-    bool HandleLine(const std::vector<std::string>& args, std::string* err);
+    bool ParseLine(const std::vector<std::string>& args, std::string* err);
     bool Start();
     bool StartIfNotDisabled();
     bool Enable();
@@ -83,7 +76,7 @@
     void Stop();
     void Terminate();
     void Restart();
-    void RestartIfNeeded(time_t& process_needs_restart);
+    void RestartIfNeeded(time_t* process_needs_restart_at);
     bool Reap();
     void DumpState() const;
 
@@ -93,6 +86,7 @@
     pid_t pid() const { return pid_; }
     uid_t uid() const { return uid_; }
     gid_t gid() const { return gid_; }
+    int priority() const { return priority_; }
     const std::vector<gid_t>& supp_gids() const { return supp_gids_; }
     const std::string& seclabel() const { return seclabel_; }
     const std::vector<int>& keycodes() const { return keycodes_; }
@@ -101,47 +95,59 @@
     const std::vector<std::string>& args() const { return args_; }
 
 private:
-    using OptionHandler = bool (Service::*) (const std::vector<std::string>& args,
-                                             std::string* err);
-    class OptionHandlerMap;
+    using OptionParser = bool (Service::*) (const std::vector<std::string>& args,
+                                            std::string* err);
+    class OptionParserMap;
 
     void NotifyStateChange(const std::string& new_state) const;
     void StopOrReset(int how);
     void ZapStdio() const;
     void OpenConsole() const;
-    void PublishSocket(const std::string& name, int fd) const;
+    void KillProcessGroup(int signal);
+    void SetProcessAttributes();
 
-    bool HandleClass(const std::vector<std::string>& args, std::string* err);
-    bool HandleConsole(const std::vector<std::string>& args, std::string* err);
-    bool HandleCritical(const std::vector<std::string>& args, std::string* err);
-    bool HandleDisabled(const std::vector<std::string>& args, std::string* err);
-    bool HandleGroup(const std::vector<std::string>& args, std::string* err);
-    bool HandleIoprio(const std::vector<std::string>& args, std::string* err);
-    bool HandleKeycodes(const std::vector<std::string>& args, std::string* err);
-    bool HandleOneshot(const std::vector<std::string>& args, std::string* err);
-    bool HandleOnrestart(const std::vector<std::string>& args, std::string* err);
-    bool HandleSeclabel(const std::vector<std::string>& args, std::string* err);
-    bool HandleSetenv(const std::vector<std::string>& args, std::string* err);
-    bool HandleSocket(const std::vector<std::string>& args, std::string* err);
-    bool HandleUser(const std::vector<std::string>& args, std::string* err);
-    bool HandleWritepid(const std::vector<std::string>& args, std::string* err);
+    bool ParseCapabilities(const std::vector<std::string>& args, std::string *err);
+    bool ParseClass(const std::vector<std::string>& args, std::string* err);
+    bool ParseConsole(const std::vector<std::string>& args, std::string* err);
+    bool ParseCritical(const std::vector<std::string>& args, std::string* err);
+    bool ParseDisabled(const std::vector<std::string>& args, std::string* err);
+    bool ParseGroup(const std::vector<std::string>& args, std::string* err);
+    bool ParsePriority(const std::vector<std::string>& args, std::string* err);
+    bool ParseIoprio(const std::vector<std::string>& args, std::string* err);
+    bool ParseKeycodes(const std::vector<std::string>& args, std::string* err);
+    bool ParseOneshot(const std::vector<std::string>& args, std::string* err);
+    bool ParseOnrestart(const std::vector<std::string>& args, std::string* err);
+    bool ParseOomScoreAdjust(const std::vector<std::string>& args, std::string* err);
+    bool ParseNamespace(const std::vector<std::string>& args, std::string* err);
+    bool ParseSeclabel(const std::vector<std::string>& args, std::string* err);
+    bool ParseSetenv(const std::vector<std::string>& args, std::string* err);
+    bool ParseSocket(const std::vector<std::string>& args, std::string* err);
+    bool ParseFile(const std::vector<std::string>& args, std::string* err);
+    bool ParseUser(const std::vector<std::string>& args, std::string* err);
+    bool ParseWritepid(const std::vector<std::string>& args, std::string* err);
+
+    template <typename T>
+    bool AddDescriptor(const std::vector<std::string>& args, std::string* err);
 
     std::string name_;
     std::string classname_;
+    std::string console_;
 
     unsigned flags_;
     pid_t pid_;
-    time_t time_started_;    // time of last start
-    time_t time_crashed_;    // first crash within inspection window
-    int nr_crashed_;         // number of times crashed within window
+    boot_clock::time_point time_started_; // time of last start
+    boot_clock::time_point time_crashed_; // first crash within inspection window
+    int crash_count_;                     // number of times crashed within window
 
     uid_t uid_;
     gid_t gid_;
     std::vector<gid_t> supp_gids_;
+    CapSet capabilities_;
+    unsigned namespace_flags_;
 
     std::string seclabel_;
 
-    std::vector<SocketInfo> sockets_;
+    std::vector<std::unique_ptr<DescriptorInfo>> descriptors_;
     std::vector<ServiceEnvironmentInfo> envvars_;
 
     Action onrestart_;  // Commands to execute on restart.
@@ -154,6 +160,9 @@
 
     IoSchedClass ioprio_class_;
     int ioprio_pri_;
+    int priority_;
+
+    int oom_score_adjust_;
 
     std::vector<std::string> args_;
 };
@@ -167,7 +176,7 @@
     Service* FindServiceByName(const std::string& name) const;
     Service* FindServiceByPid(pid_t pid) const;
     Service* FindServiceByKeychord(int keychord_id) const;
-    void ForEachService(std::function<void(Service*)> callback) const;
+    void ForEachService(const std::function<void(Service*)>& callback) const;
     void ForEachServiceInClass(const std::string& classname,
                                void (*func)(Service* svc)) const;
     void ForEachServiceWithFlags(unsigned matchflags,
diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp
index ea483d4..0dea3e0 100644
--- a/init/signal_handler.cpp
+++ b/init/signal_handler.cpp
@@ -47,7 +47,7 @@
 
 static void SIGCHLD_handler(int) {
     if (TEMP_FAILURE_RETRY(write(signal_write_fd, "1", 1)) == -1) {
-        ERROR("write(signal_write_fd) failed: %s\n", strerror(errno));
+        PLOG(ERROR) << "write(signal_write_fd) failed";
     }
 }
 
@@ -55,7 +55,7 @@
     // Create a signalling mechanism for SIGCHLD.
     int s[2];
     if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {
-        ERROR("socketpair failed: %s\n", strerror(errno));
+        PLOG(ERROR) << "socketpair failed";
         exit(1);
     }
 
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index 249739b..361b925 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -16,14 +16,17 @@
 
 #include <ctype.h>
 #include <fcntl.h>
+#include <grp.h>
 #include <poll.h>
+#include <pwd.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
+#include <sys/types.h>
+
 #include <android-base/stringprintf.h>
-#include <private/android_filesystem_config.h>
 #include <selinux/selinux.h>
 
 #include "ueventd.h"
@@ -49,11 +52,9 @@
      */
     signal(SIGCHLD, SIG_IGN);
 
-    open_devnull_stdio();
-    klog_init();
-    klog_set_level(KLOG_NOTICE_LEVEL);
+    InitKernelLogging(argv);
 
-    NOTICE("ueventd started!\n");
+    LOG(INFO) << "ueventd started!";
 
     selinux_callback cb;
     cb.func_log = selinux_klog_callback;
@@ -84,15 +85,6 @@
     return 0;
 }
 
-static int get_android_id(const char *id)
-{
-    unsigned int i;
-    for (i = 0; i < ARRAY_SIZE(android_ids); i++)
-        if (!strcmp(id, android_ids[i].name))
-            return android_ids[i].aid;
-    return -1;
-}
-
 void set_device_permission(int nargs, char **args)
 {
     char *name;
@@ -103,8 +95,6 @@
     int prefix = 0;
     int wildcard = 0;
     char *endptr;
-    int ret;
-    char *tmp = 0;
 
     if (nargs == 0)
         return;
@@ -115,58 +105,53 @@
     name = args[0];
 
     if (!strncmp(name,"/sys/", 5) && (nargs == 5)) {
-        INFO("/sys/ rule %s %s\n",args[0],args[1]);
+        LOG(INFO) << "/sys/ rule " << args[0] << " " << args[1];
         attr = args[1];
         args++;
         nargs--;
     }
 
     if (nargs != 4) {
-        ERROR("invalid line ueventd.rc line for '%s'\n", args[0]);
+        LOG(ERROR) << "invalid line ueventd.rc line for '" << args[0] << "'";
         return;
     }
 
-    /* If path starts with mtd@ lookup the mount number. */
-    if (!strncmp(name, "mtd@", 4)) {
-        int n = mtd_name_to_number(name + 4);
-        if (n >= 0)
-            asprintf(&tmp, "/dev/mtd/mtd%d", n);
-        name = tmp;
-    } else {
-        int len = strlen(name);
-        char *wildcard_chr = strchr(name, '*');
-        if ((name[len - 1] == '*') &&
-            (wildcard_chr == (name + len - 1))) {
-            prefix = 1;
-            name[len - 1] = '\0';
-        } else if (wildcard_chr) {
-            wildcard = 1;
-        }
+    int len = strlen(name);
+    char *wildcard_chr = strchr(name, '*');
+    if ((name[len - 1] == '*') && (wildcard_chr == (name + len - 1))) {
+        prefix = 1;
+        name[len - 1] = '\0';
+    } else if (wildcard_chr) {
+        wildcard = 1;
     }
 
     perm = strtol(args[1], &endptr, 8);
     if (!endptr || *endptr != '\0') {
-        ERROR("invalid mode '%s'\n", args[1]);
-        free(tmp);
+        LOG(ERROR) << "invalid mode '" << args[1] << "'";
         return;
     }
 
-    ret = get_android_id(args[2]);
-    if (ret < 0) {
-        ERROR("invalid uid '%s'\n", args[2]);
-        free(tmp);
+    struct passwd* pwd = getpwnam(args[2]);
+    if (!pwd) {
+        LOG(ERROR) << "invalid uid '" << args[2] << "'";
         return;
     }
-    uid = ret;
+    uid = pwd->pw_uid;
 
-    ret = get_android_id(args[3]);
-    if (ret < 0) {
-        ERROR("invalid gid '%s'\n", args[3]);
-        free(tmp);
+    struct group* grp = getgrnam(args[3]);
+    if (!grp) {
+        LOG(ERROR) << "invalid gid '" << args[3] << "'";
         return;
     }
-    gid = ret;
+    gid = grp->gr_gid;
 
-    add_dev_perms(name, attr, perm, uid, gid, prefix, wildcard);
-    free(tmp);
+    if (add_dev_perms(name, attr, perm, uid, gid, prefix, wildcard) != 0) {
+        PLOG(ERROR) << "add_dev_perms(name=" << name <<
+                       ", attr=" << attr <<
+                       ", perm=" << std::oct << perm << std::dec <<
+                       ", uid=" << uid << ", gid=" << gid <<
+                       ", prefix=" << prefix << ", wildcard=" << wildcard <<
+                       ")";
+        return;
+    }
 }
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index 09f4638..baff58c 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -38,7 +38,7 @@
 #include "ueventd_keywords.h"
 
 #define KEYWORD(symbol, flags, nargs) \
-    [ K_##symbol ] = { #symbol, nargs + 1, flags, },
+    [ K_##symbol ] = { #symbol, (nargs) + 1, flags, },
 
 static struct {
     const char *name;
diff --git a/init/util.cpp b/init/util.cpp
index 89d3276..5205ea0 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -14,63 +14,54 @@
  * limitations under the License.
  */
 
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ftw.h>
+#include <pwd.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <errno.h>
 #include <time.h>
-#include <ftw.h>
+#include <unistd.h>
 
-#include <selinux/label.h>
 #include <selinux/android.h>
+#include <selinux/label.h>
 
+#include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <sys/socket.h>
 #include <sys/un.h>
 
-#include <android-base/file.h>
-#include <android-base/strings.h>
+#include <thread>
 
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
 /* for ANDROID_SOCKET_* */
 #include <cutils/sockets.h>
-#include <android-base/stringprintf.h>
-
-#include <private/android_filesystem_config.h>
 
 #include "init.h"
 #include "log.h"
 #include "property_service.h"
 #include "util.h"
 
-/*
- * android_name_to_id - returns the integer uid/gid associated with the given
- * name, or UINT_MAX on error.
- */
-static unsigned int android_name_to_id(const char *name)
-{
-    const struct android_id_info *info = android_ids;
-    unsigned int n;
-
-    for (n = 0; n < android_id_count; n++) {
-        if (!strcmp(info[n].name, name))
-            return info[n].aid;
-    }
-
-    return UINT_MAX;
-}
-
 static unsigned int do_decode_uid(const char *s)
 {
     unsigned int v;
 
     if (!s || *s == '\0')
         return UINT_MAX;
-    if (isalpha(s[0]))
-        return android_name_to_id(s);
+
+    if (isalpha(s[0])) {
+        struct passwd* pwd = getpwnam(s);
+        if (!pwd)
+            return UINT_MAX;
+        return pwd->pw_uid;
+    }
 
     errno = 0;
     v = (unsigned int) strtoul(s, 0, 0);
@@ -87,7 +78,7 @@
 unsigned int decode_uid(const char *s) {
     unsigned int v = do_decode_uid(s);
     if (v == UINT_MAX) {
-        ERROR("decode_uid: Unable to find UID for '%s'. Returning UINT_MAX\n", s);
+        LOG(ERROR) << "decode_uid: Unable to find UID for '" << s << "'; returning UINT_MAX";
     }
     return v;
 }
@@ -101,78 +92,135 @@
 int create_socket(const char *name, int type, mode_t perm, uid_t uid,
                   gid_t gid, const char *socketcon)
 {
-    struct sockaddr_un addr;
-    int fd, ret, savederrno;
-    char *filecon;
-
     if (socketcon) {
         if (setsockcreatecon(socketcon) == -1) {
-            ERROR("setsockcreatecon(\"%s\") failed: %s\n", socketcon, strerror(errno));
+            PLOG(ERROR) << "setsockcreatecon(\"" << socketcon << "\") failed";
             return -1;
         }
     }
 
-    fd = socket(PF_UNIX, type, 0);
+    android::base::unique_fd fd(socket(PF_UNIX, type, 0));
     if (fd < 0) {
-        ERROR("Failed to open socket '%s': %s\n", name, strerror(errno));
+        PLOG(ERROR) << "Failed to open socket '" << name << "'";
         return -1;
     }
 
-    if (socketcon)
-        setsockcreatecon(NULL);
+    if (socketcon) setsockcreatecon(NULL);
 
+    struct sockaddr_un addr;
     memset(&addr, 0 , sizeof(addr));
     addr.sun_family = AF_UNIX;
     snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",
              name);
 
-    ret = unlink(addr.sun_path);
-    if (ret != 0 && errno != ENOENT) {
-        ERROR("Failed to unlink old socket '%s': %s\n", name, strerror(errno));
-        goto out_close;
+    if ((unlink(addr.sun_path) != 0) && (errno != ENOENT)) {
+        PLOG(ERROR) << "Failed to unlink old socket '" << name << "'";
+        return -1;
     }
 
-    filecon = NULL;
+    char *filecon = NULL;
     if (sehandle) {
-        ret = selabel_lookup(sehandle, &filecon, addr.sun_path, S_IFSOCK);
-        if (ret == 0)
+        if (selabel_lookup(sehandle, &filecon, addr.sun_path, S_IFSOCK) == 0) {
             setfscreatecon(filecon);
+        }
     }
 
-    ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
-    savederrno = errno;
+    int ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
+    int savederrno = errno;
 
     setfscreatecon(NULL);
     freecon(filecon);
 
     if (ret) {
-        ERROR("Failed to bind socket '%s': %s\n", name, strerror(savederrno));
+        errno = savederrno;
+        PLOG(ERROR) << "Failed to bind socket '" << name << "'";
         goto out_unlink;
     }
 
-    ret = lchown(addr.sun_path, uid, gid);
-    if (ret) {
-        ERROR("Failed to lchown socket '%s': %s\n", addr.sun_path, strerror(errno));
+    if (lchown(addr.sun_path, uid, gid)) {
+        PLOG(ERROR) << "Failed to lchown socket '" << addr.sun_path << "'";
         goto out_unlink;
     }
-    ret = fchmodat(AT_FDCWD, addr.sun_path, perm, AT_SYMLINK_NOFOLLOW);
-    if (ret) {
-        ERROR("Failed to fchmodat socket '%s': %s\n", addr.sun_path, strerror(errno));
+    if (fchmodat(AT_FDCWD, addr.sun_path, perm, AT_SYMLINK_NOFOLLOW)) {
+        PLOG(ERROR) << "Failed to fchmodat socket '" << addr.sun_path << "'";
         goto out_unlink;
     }
 
-    INFO("Created socket '%s' with mode '%o', user '%d', group '%d'\n",
-         addr.sun_path, perm, uid, gid);
+    LOG(INFO) << "Created socket '" << addr.sun_path << "'"
+              << ", mode " << std::oct << perm << std::dec
+              << ", user " << uid
+              << ", group " << gid;
 
-    return fd;
+    return fd.release();
 
 out_unlink:
     unlink(addr.sun_path);
-out_close:
-    close(fd);
     return -1;
 }
 
+/*
+ * create_file - opens and creates a file as dictated in init.rc.
+ * This file is inherited by the daemon. We communicate the file
+ * descriptor's value via the environment variable ANDROID_FILE_<basename>
+ */
+int create_file(const char *path, int flags, mode_t perm, uid_t uid,
+                  gid_t gid, const char *filecon)
+{
+    char *secontext = NULL;
+
+    if (filecon) {
+        if (setsockcreatecon(filecon) == -1) {
+            PLOG(ERROR) << "setsockcreatecon(\"" << filecon << "\") failed";
+            return -1;
+        }
+    } else if (sehandle) {
+        if (selabel_lookup(sehandle, &secontext, path, perm) != -1) {
+            if (setfscreatecon(secontext) == -1) {
+                freecon(secontext); // does not upset errno value
+                PLOG(ERROR) << "setfscreatecon(\"" << secontext << "\") failed";
+                return -1;
+            }
+        }
+    }
+
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path, flags | O_NDELAY, perm)));
+    int savederrno = errno;
+
+    if (filecon) {
+        setsockcreatecon(NULL);
+        lsetfilecon(path, filecon);
+    } else {
+        setfscreatecon(NULL);
+        freecon(secontext);
+    }
+
+    if (fd < 0) {
+        errno = savederrno;
+        PLOG(ERROR) << "Failed to open/create file '" << path << "'";
+        return -1;
+    }
+
+    if (!(flags & O_NDELAY)) fcntl(fd, F_SETFD, flags);
+
+    if (lchown(path, uid, gid)) {
+        PLOG(ERROR) << "Failed to lchown file '" << path << "'";
+        return -1;
+    }
+    if (perm != static_cast<mode_t>(-1)) {
+        if (fchmodat(AT_FDCWD, path, perm, AT_SYMLINK_NOFOLLOW)) {
+            PLOG(ERROR) << "Failed to fchmodat file '" << path << "'";
+            return -1;
+        }
+    }
+
+    LOG(INFO) << "Created file '" << path << "'"
+              << ", mode " << std::oct << perm << std::dec
+              << ", user " << uid
+              << ", group " << gid;
+
+    return fd.release();
+}
+
 bool read_file(const char* path, std::string* content) {
     content->clear();
 
@@ -185,11 +233,11 @@
     // or group-writable files.
     struct stat sb;
     if (fstat(fd, &sb) == -1) {
-        ERROR("fstat failed for '%s': %s\n", path, strerror(errno));
+        PLOG(ERROR) << "fstat failed for '" << path << "'";
         return false;
     }
     if ((sb.st_mode & (S_IWGRP | S_IWOTH)) != 0) {
-        ERROR("skipping insecure file '%s'\n", path);
+        PLOG(ERROR) << "skipping insecure file '" << path << "'";
         return false;
     }
 
@@ -201,99 +249,22 @@
 int write_file(const char* path, const char* content) {
     int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY|O_CREAT|O_NOFOLLOW|O_CLOEXEC, 0600));
     if (fd == -1) {
-        NOTICE("write_file: Unable to open '%s': %s\n", path, strerror(errno));
+        PLOG(ERROR) << "write_file: Unable to open '" << path << "'";
         return -1;
     }
     int result = android::base::WriteStringToFd(content, fd) ? 0 : -1;
     if (result == -1) {
-        NOTICE("write_file: Unable to write to '%s': %s\n", path, strerror(errno));
+        PLOG(ERROR) << "write_file: Unable to write to '" << path << "'";
     }
     close(fd);
     return result;
 }
 
-#define MAX_MTD_PARTITIONS 16
-
-static struct {
-    char name[16];
-    int number;
-} mtd_part_map[MAX_MTD_PARTITIONS];
-
-static int mtd_part_count = -1;
-
-static void find_mtd_partitions(void)
-{
-    int fd;
-    char buf[1024];
-    char *pmtdbufp;
-    ssize_t pmtdsize;
-    int r;
-
-    fd = open("/proc/mtd", O_RDONLY|O_CLOEXEC);
-    if (fd < 0)
-        return;
-
-    buf[sizeof(buf) - 1] = '\0';
-    pmtdsize = read(fd, buf, sizeof(buf) - 1);
-    pmtdbufp = buf;
-    while (pmtdsize > 0) {
-        int mtdnum, mtdsize, mtderasesize;
-        char mtdname[16];
-        mtdname[0] = '\0';
-        mtdnum = -1;
-        r = sscanf(pmtdbufp, "mtd%d: %x %x %15s",
-                   &mtdnum, &mtdsize, &mtderasesize, mtdname);
-        if ((r == 4) && (mtdname[0] == '"')) {
-            char *x = strchr(mtdname + 1, '"');
-            if (x) {
-                *x = 0;
-            }
-            INFO("mtd partition %d, %s\n", mtdnum, mtdname + 1);
-            if (mtd_part_count < MAX_MTD_PARTITIONS) {
-                strcpy(mtd_part_map[mtd_part_count].name, mtdname + 1);
-                mtd_part_map[mtd_part_count].number = mtdnum;
-                mtd_part_count++;
-            } else {
-                ERROR("too many mtd partitions\n");
-            }
-        }
-        while (pmtdsize > 0 && *pmtdbufp != '\n') {
-            pmtdbufp++;
-            pmtdsize--;
-        }
-        if (pmtdsize > 0) {
-            pmtdbufp++;
-            pmtdsize--;
-        }
-    }
-    close(fd);
-}
-
-int mtd_name_to_number(const char *name)
-{
-    int n;
-    if (mtd_part_count < 0) {
-        mtd_part_count = 0;
-        find_mtd_partitions();
-    }
-    for (n = 0; n < mtd_part_count; n++) {
-        if (!strcmp(name, mtd_part_map[n].name)) {
-            return mtd_part_map[n].number;
-        }
-    }
-    return -1;
-}
-
-time_t gettime() {
-    timespec now;
-    clock_gettime(CLOCK_MONOTONIC, &now);
-    return now.tv_sec;
-}
-
-uint64_t gettime_ns() {
-    timespec now;
-    clock_gettime(CLOCK_MONOTONIC, &now);
-    return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_nsec;
+boot_clock::time_point boot_clock::now() {
+  timespec ts;
+  clock_gettime(CLOCK_BOOTTIME, &ts);
+  return boot_clock::time_point(std::chrono::seconds(ts.tv_sec) +
+                                std::chrono::nanoseconds(ts.tv_nsec));
 }
 
 int mkdir_recursive(const char *pathname, mode_t mode)
@@ -313,7 +284,7 @@
         if (width == 0)
             continue;
         if ((unsigned int)width > sizeof(buf) - 1) {
-            ERROR("path too long for mkdir_recursive\n");
+            LOG(ERROR) << "path too long for mkdir_recursive";
             return -1;
         }
         memcpy(buf, pathname, width);
@@ -351,82 +322,19 @@
     }
 }
 
-void make_link_init(const char *oldpath, const char *newpath)
-{
-    int ret;
-    char buf[256];
-    char *slash;
-    int width;
+int wait_for_file(const char* filename, std::chrono::nanoseconds timeout) {
+    boot_clock::time_point timeout_time = boot_clock::now() + timeout;
+    while (boot_clock::now() < timeout_time) {
+        struct stat sb;
+        if (stat(filename, &sb) != -1) return 0;
 
-    slash = strrchr(newpath, '/');
-    if (!slash)
-        return;
-    width = slash - newpath;
-    if (width <= 0 || width > (int)sizeof(buf) - 1)
-        return;
-    memcpy(buf, newpath, width);
-    buf[width] = 0;
-    ret = mkdir_recursive(buf, 0755);
-    if (ret)
-        ERROR("Failed to create directory %s: %s (%d)\n", buf, strerror(errno), errno);
-
-    ret = symlink(oldpath, newpath);
-    if (ret && errno != EEXIST)
-        ERROR("Failed to symlink %s to %s: %s (%d)\n", oldpath, newpath, strerror(errno), errno);
-}
-
-void remove_link(const char *oldpath, const char *newpath)
-{
-    char path[256];
-    ssize_t ret;
-    ret = readlink(newpath, path, sizeof(path) - 1);
-    if (ret <= 0)
-        return;
-    path[ret] = 0;
-    if (!strcmp(path, oldpath))
-        unlink(newpath);
-}
-
-int wait_for_file(const char *filename, int timeout)
-{
-    struct stat info;
-    uint64_t timeout_time_ns = gettime_ns() + timeout * UINT64_C(1000000000);
-    int ret = -1;
-
-    while (gettime_ns() < timeout_time_ns && ((ret = stat(filename, &info)) < 0))
-        usleep(10000);
-
-    return ret;
-}
-
-void open_devnull_stdio(void)
-{
-    // Try to avoid the mknod() call if we can. Since SELinux makes
-    // a /dev/null replacement available for free, let's use it.
-    int fd = open("/sys/fs/selinux/null", O_RDWR);
-    if (fd == -1) {
-        // OOPS, /sys/fs/selinux/null isn't available, likely because
-        // /sys/fs/selinux isn't mounted. Fall back to mknod.
-        static const char *name = "/dev/__null__";
-        if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) {
-            fd = open(name, O_RDWR);
-            unlink(name);
-        }
-        if (fd == -1) {
-            exit(1);
-        }
+        std::this_thread::sleep_for(10ms);
     }
-
-    dup2(fd, 0);
-    dup2(fd, 1);
-    dup2(fd, 2);
-    if (fd > 2) {
-        close(fd);
-    }
+    return -1;
 }
 
 void import_kernel_cmdline(bool in_qemu,
-                           std::function<void(const std::string&, const std::string&, bool)> fn) {
+                           const std::function<void(const std::string&, const std::string&, bool)>& fn) {
     std::string cmdline;
     android::base::ReadFileToString("/proc/cmdline", &cmdline);
 
@@ -461,20 +369,9 @@
     return rc;
 }
 
-int restorecon(const char* pathname)
+int restorecon(const char* pathname, int flags)
 {
-    return selinux_android_restorecon(pathname, 0);
-}
-
-int restorecon_recursive(const char* pathname)
-{
-    return selinux_android_restorecon(pathname, SELINUX_ANDROID_RESTORECON_RECURSE);
-}
-
-int restorecon_recursive_skipce(const char* pathname)
-{
-    return selinux_android_restorecon(pathname,
-            SELINUX_ANDROID_RESTORECON_RECURSE | SELINUX_ANDROID_RESTORECON_SKIPCE);
+    return selinux_android_restorecon(pathname, flags);
 }
 
 /*
@@ -539,7 +436,7 @@
             const char* end = strchr(c, '}');
             if (!end) {
                 // failed to find closing brace, abort.
-                ERROR("unexpected end of string in '%s', looking for }\n", src.c_str());
+                LOG(ERROR) << "unexpected end of string in '" << src << "', looking for }";
                 return false;
             }
             prop_name = std::string(c, end);
@@ -551,21 +448,19 @@
             }
         } else {
             prop_name = c;
-            ERROR("using deprecated syntax for specifying property '%s', use ${name} instead\n",
-                  c);
+            LOG(ERROR) << "using deprecated syntax for specifying property '" << c << "', use ${name} instead";
             c += prop_name.size();
         }
 
         if (prop_name.empty()) {
-            ERROR("invalid zero-length prop name in '%s'\n", src.c_str());
+            LOG(ERROR) << "invalid zero-length property name in '" << src << "'";
             return false;
         }
 
         std::string prop_val = property_get(prop_name.c_str());
         if (prop_val.empty()) {
             if (def_val.empty()) {
-                ERROR("property '%s' doesn't exist while expanding '%s'\n",
-                      prop_name.c_str(), src.c_str());
+                LOG(ERROR) << "property '" << prop_name << "' doesn't exist while expanding '" << src << "'";
                 return false;
             }
             prop_val = def_val;
diff --git a/init/util.h b/init/util.h
index af4b098..d56da39 100644
--- a/init/util.h
+++ b/init/util.h
@@ -20,50 +20,55 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <chrono>
 #include <string>
 #include <functional>
 
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
-
 #define COLDBOOT_DONE "/dev/.coldboot_done"
 
-int mtd_name_to_number(const char *name);
+using namespace std::chrono_literals;
+
 int create_socket(const char *name, int type, mode_t perm,
                   uid_t uid, gid_t gid, const char *socketcon);
+int create_file(const char *path, int mode, mode_t perm,
+                uid_t uid, gid_t gid, const char *filecon);
 
 bool read_file(const char* path, std::string* content);
 int write_file(const char* path, const char* content);
 
-time_t gettime();
-uint64_t gettime_ns();
+// A std::chrono clock based on CLOCK_BOOTTIME.
+class boot_clock {
+ public:
+  typedef std::chrono::nanoseconds duration;
+  typedef std::chrono::time_point<boot_clock, duration> time_point;
+  static constexpr bool is_steady = true;
+
+  static time_point now();
+};
 
 class Timer {
  public:
-  Timer() : t0(gettime_ns()) {
+  Timer() : start_(boot_clock::now()) {
   }
 
   double duration() {
-    return static_cast<double>(gettime_ns() - t0) / 1000000000.0;
+    typedef std::chrono::duration<double> double_duration;
+    return std::chrono::duration_cast<double_duration>(boot_clock::now() - start_).count();
   }
 
  private:
-  uint64_t t0;
+  boot_clock::time_point start_;
 };
 
 unsigned int decode_uid(const char *s);
 
 int mkdir_recursive(const char *pathname, mode_t mode);
 void sanitize(char *p);
-void make_link_init(const char *oldpath, const char *newpath);
-void remove_link(const char *oldpath, const char *newpath);
-int wait_for_file(const char *filename, int timeout);
-void open_devnull_stdio(void);
+int wait_for_file(const char *filename, std::chrono::nanoseconds timeout);
 void import_kernel_cmdline(bool in_qemu,
-                           std::function<void(const std::string&, const std::string&, bool)>);
+                           const std::function<void(const std::string&, const std::string&, bool)>&);
 int make_dir(const char *path, mode_t mode);
-int restorecon(const char *pathname);
-int restorecon_recursive(const char *pathname);
-int restorecon_recursive_skipce(const char *pathname);
+int restorecon(const char *pathname, int flags = 0);
 std::string bytes_to_hex(const uint8_t *bytes, size_t bytes_len);
 bool is_dir(const char* pathname);
 bool expand_props(const std::string& src, std::string* dst);
diff --git a/init/util_test.cpp b/init/util_test.cpp
index 228954b..e9f164d 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -16,8 +16,19 @@
 
 #include "util.h"
 
+#include <ctype.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android-base/stringprintf.h>
+#include <android-base/test_utils.h>
+#include <cutils/android_get_control_file.h>
 #include <gtest/gtest.h>
+#include <selinux/android.h>
 
 TEST(util, read_file_ENOENT) {
   std::string s("hello");
@@ -41,3 +52,54 @@
   EXPECT_EQ(UINT_MAX, decode_uid("toot"));
   EXPECT_EQ(123U, decode_uid("123"));
 }
+
+struct selabel_handle *sehandle;
+
+TEST(util, create_file) {
+  if (!sehandle) sehandle = selinux_android_file_context_handle();
+
+  TemporaryFile tf;
+  close(tf.fd);
+  EXPECT_GE(unlink(tf.path), 0);
+
+  std::string key(ANDROID_FILE_ENV_PREFIX);
+  key += tf.path;
+
+  std::for_each(key.begin(), key.end(), [] (char& c) { c = isalnum(c) ? c : '_'; });
+
+  EXPECT_EQ(unsetenv(key.c_str()), 0);
+
+  uid_t uid = decode_uid("logd");
+  gid_t gid = decode_uid("system");
+  mode_t perms = S_IRWXU | S_IWGRP | S_IRGRP | S_IROTH;
+  static const char context[] = "u:object_r:misc_logd_file:s0";
+  EXPECT_GE(tf.fd = create_file(tf.path, O_RDWR | O_CREAT, perms, uid, gid, context), 0);
+  if (tf.fd < 0) return;
+  static const char hello[] = "hello world\n";
+  static const ssize_t len = strlen(hello);
+  EXPECT_EQ(write(tf.fd, hello, len), len);
+  char buffer[sizeof(hello) + 1];
+  memset(buffer, 0, sizeof(buffer));
+  EXPECT_GE(lseek(tf.fd, 0, SEEK_SET), 0);
+  EXPECT_EQ(read(tf.fd, buffer, sizeof(buffer)), len);
+  EXPECT_EQ(std::string(hello), buffer);
+  EXPECT_EQ(android_get_control_file(tf.path), -1);
+  EXPECT_EQ(setenv(key.c_str(), android::base::StringPrintf("%d", tf.fd).c_str(), true), 0);
+  EXPECT_EQ(android_get_control_file(tf.path), tf.fd);
+  close(tf.fd);
+  EXPECT_EQ(android_get_control_file(tf.path), -1);
+  EXPECT_EQ(unsetenv(key.c_str()), 0);
+  struct stat st;
+  EXPECT_EQ(stat(tf.path, &st), 0);
+  EXPECT_EQ(st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO), perms);
+  EXPECT_EQ(st.st_uid, uid);
+  EXPECT_EQ(st.st_gid, gid);
+  security_context_t con;
+  EXPECT_GE(getfilecon(tf.path, &con), 0);
+  EXPECT_NE(con, static_cast<security_context_t>(NULL));
+  if (con) {
+    EXPECT_EQ(context, std::string(con));
+  }
+  freecon(con);
+  EXPECT_EQ(unlink(tf.path), 0);
+}
diff --git a/init/watchdogd.cpp b/init/watchdogd.cpp
index 0d16db9..b196147 100644
--- a/init/watchdogd.cpp
+++ b/init/watchdogd.cpp
@@ -28,9 +28,7 @@
 #define DEV_NAME "/dev/watchdog"
 
 int watchdogd_main(int argc, char **argv) {
-    open_devnull_stdio();
-    klog_init();
-    klog_set_level(KLOG_NOTICE_LEVEL);
+    InitKernelLogging(argv);
 
     int interval = 10;
     if (argc >= 2) interval = atoi(argv[1]);
@@ -38,30 +36,31 @@
     int margin = 10;
     if (argc >= 3) margin = atoi(argv[2]);
 
-    NOTICE("started (interval %d, margin %d)!\n", interval, margin);
+    LOG(INFO) << "watchdogd started (interval " << interval << ", margin " << margin << ")!";
 
     int fd = open(DEV_NAME, O_RDWR|O_CLOEXEC);
     if (fd == -1) {
-        ERROR("Failed to open %s: %s\n", DEV_NAME, strerror(errno));
+        PLOG(ERROR) << "Failed to open " << DEV_NAME;
         return 1;
     }
 
     int timeout = interval + margin;
     int ret = ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
     if (ret) {
-        ERROR("Failed to set timeout to %d: %s\n", timeout, strerror(errno));
+        PLOG(ERROR) << "Failed to set timeout to " << timeout;
         ret = ioctl(fd, WDIOC_GETTIMEOUT, &timeout);
         if (ret) {
-            ERROR("Failed to get timeout: %s\n", strerror(errno));
+            PLOG(ERROR) << "Failed to get timeout";
         } else {
             if (timeout > margin) {
                 interval = timeout - margin;
             } else {
                 interval = 1;
             }
-            WARNING("Adjusted interval to timeout returned by driver:"
-                    " timeout %d, interval %d, margin %d\n",
-                    timeout, interval, margin);
+            LOG(WARNING) << "Adjusted interval to timeout returned by driver: "
+                         << "timeout " << timeout
+                         << ", interval " << interval
+                         << ", margin " << margin;
         }
     }
 
diff --git a/libappfuse/Android.bp b/libappfuse/Android.bp
new file mode 100644
index 0000000..f729faf
--- /dev/null
+++ b/libappfuse/Android.bp
@@ -0,0 +1,34 @@
+// Copyright 2016 The Android Open Source Project
+
+cc_defaults {
+    name: "libappfuse_defaults",
+    local_include_dirs: ["include"],
+    shared_libs: ["libbase"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    clang: true
+}
+
+cc_library_shared {
+    name: "libappfuse",
+    defaults: ["libappfuse_defaults"],
+    export_include_dirs: ["include"],
+    srcs: [
+        "FuseAppLoop.cc",
+        "FuseBuffer.cc",
+        "FuseBridgeLoop.cc",
+    ]
+}
+
+cc_test {
+    name: "libappfuse_test",
+    defaults: ["libappfuse_defaults"],
+    shared_libs: ["libappfuse"],
+    srcs: [
+        "tests/FuseAppLoopTest.cc",
+        "tests/FuseBridgeLoopTest.cc",
+        "tests/FuseBufferTest.cc",
+    ]
+}
diff --git a/libappfuse/FuseAppLoop.cc b/libappfuse/FuseAppLoop.cc
new file mode 100644
index 0000000..a31880e
--- /dev/null
+++ b/libappfuse/FuseAppLoop.cc
@@ -0,0 +1,221 @@
+/*
+ * 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 specic language governing permissions and
+ * limitations under the License.
+ */
+
+#include "libappfuse/FuseAppLoop.h"
+
+#include <sys/stat.h>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
+namespace android {
+namespace fuse {
+
+namespace {
+
+void HandleLookUp(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+  // AppFuse does not support directory structure now.
+  // It can lookup only files under the mount point.
+  if (buffer->request.header.nodeid != FUSE_ROOT_ID) {
+    LOG(ERROR) << "Nodeid is not FUSE_ROOT_ID.";
+    buffer->response.Reset(0, -ENOENT, buffer->request.header.unique);
+    return;
+  }
+
+  // Ensure that the filename ends with 0.
+  const size_t filename_length =
+      buffer->request.header.len - sizeof(fuse_in_header);
+  if (buffer->request.lookup_name[filename_length - 1] != 0) {
+    LOG(ERROR) << "File name does not end with 0.";
+    buffer->response.Reset(0, -ENOENT, buffer->request.header.unique);
+    return;
+  }
+
+  const uint64_t inode =
+      static_cast<uint64_t>(atol(buffer->request.lookup_name));
+  if (inode == 0 || inode == LONG_MAX) {
+    LOG(ERROR) << "Invalid filename";
+    buffer->response.Reset(0, -ENOENT, buffer->request.header.unique);
+    return;
+  }
+
+  const int64_t size = callback->OnGetSize(inode);
+  if (size < 0) {
+    buffer->response.Reset(0, size, buffer->request.header.unique);
+    return;
+  }
+
+  buffer->response.Reset(sizeof(fuse_entry_out), 0,
+                         buffer->request.header.unique);
+  buffer->response.entry_out.nodeid = inode;
+  buffer->response.entry_out.attr_valid = 10;
+  buffer->response.entry_out.entry_valid = 10;
+  buffer->response.entry_out.attr.ino = inode;
+  buffer->response.entry_out.attr.mode = S_IFREG | 0777;
+  buffer->response.entry_out.attr.size = size;
+}
+
+void HandleGetAttr(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+  const uint64_t nodeid = buffer->request.header.nodeid;
+  int64_t size;
+  uint32_t mode;
+  if (nodeid == FUSE_ROOT_ID) {
+    size = 0;
+    mode = S_IFDIR | 0777;
+  } else {
+    size = callback->OnGetSize(buffer->request.header.nodeid);
+    if (size < 0) {
+      buffer->response.Reset(0, size, buffer->request.header.unique);
+      return;
+    }
+    mode = S_IFREG | 0777;
+  }
+
+  buffer->response.Reset(sizeof(fuse_attr_out), 0,
+                         buffer->request.header.unique);
+  buffer->response.attr_out.attr_valid = 10;
+  buffer->response.attr_out.attr.ino = nodeid;
+  buffer->response.attr_out.attr.mode = mode;
+  buffer->response.attr_out.attr.size = size;
+}
+
+void HandleOpen(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+  const int32_t file_handle = callback->OnOpen(buffer->request.header.nodeid);
+  if (file_handle < 0) {
+    buffer->response.Reset(0, file_handle, buffer->request.header.unique);
+    return;
+  }
+  buffer->response.Reset(sizeof(fuse_open_out), kFuseSuccess,
+                         buffer->request.header.unique);
+  buffer->response.open_out.fh = file_handle;
+}
+
+void HandleFsync(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+  buffer->response.Reset(0, callback->OnFsync(buffer->request.header.nodeid),
+                         buffer->request.header.unique);
+}
+
+void HandleRelease(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+  buffer->response.Reset(0, callback->OnRelease(buffer->request.header.nodeid),
+                         buffer->request.header.unique);
+}
+
+void HandleRead(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+  const uint64_t unique = buffer->request.header.unique;
+  const uint64_t nodeid = buffer->request.header.nodeid;
+  const uint64_t offset = buffer->request.read_in.offset;
+  const uint32_t size = buffer->request.read_in.size;
+
+  if (size > kFuseMaxRead) {
+    buffer->response.Reset(0, -EINVAL, buffer->request.header.unique);
+    return;
+  }
+
+  const int32_t read_size = callback->OnRead(nodeid, offset, size,
+                                             buffer->response.read_data);
+  if (read_size < 0) {
+    buffer->response.Reset(0, read_size, buffer->request.header.unique);
+    return;
+  }
+
+  buffer->response.ResetHeader(read_size, kFuseSuccess, unique);
+}
+
+void HandleWrite(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+  const uint64_t unique = buffer->request.header.unique;
+  const uint64_t nodeid = buffer->request.header.nodeid;
+  const uint64_t offset = buffer->request.write_in.offset;
+  const uint32_t size = buffer->request.write_in.size;
+
+  if (size > kFuseMaxWrite) {
+    buffer->response.Reset(0, -EINVAL, buffer->request.header.unique);
+    return;
+  }
+
+  const int32_t write_size = callback->OnWrite(nodeid, offset, size,
+                                               buffer->request.write_data);
+  if (write_size < 0) {
+    buffer->response.Reset(0, write_size, buffer->request.header.unique);
+    return;
+  }
+
+  buffer->response.Reset(sizeof(fuse_write_out), kFuseSuccess, unique);
+  buffer->response.write_out.size = write_size;
+}
+
+} // namespace
+
+bool StartFuseAppLoop(int raw_fd, FuseAppLoopCallback* callback) {
+  base::unique_fd fd(raw_fd);
+  FuseBuffer buffer;
+
+  LOG(DEBUG) << "Start fuse loop.";
+  while (callback->IsActive()) {
+    if (!buffer.request.Read(fd)) {
+      return false;
+    }
+
+    const uint32_t opcode = buffer.request.header.opcode;
+    LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode;
+    switch (opcode) {
+      case FUSE_FORGET:
+        // Do not reply to FUSE_FORGET.
+        continue;
+
+      case FUSE_LOOKUP:
+        HandleLookUp(&buffer, callback);
+        break;
+
+      case FUSE_GETATTR:
+        HandleGetAttr(&buffer, callback);
+        break;
+
+      case FUSE_OPEN:
+        HandleOpen(&buffer, callback);
+        break;
+
+      case FUSE_READ:
+        HandleRead(&buffer, callback);
+        break;
+
+      case FUSE_WRITE:
+        HandleWrite(&buffer, callback);
+        break;
+
+      case FUSE_RELEASE:
+        HandleRelease(&buffer, callback);
+        break;
+
+      case FUSE_FSYNC:
+        HandleFsync(&buffer, callback);
+        break;
+
+      default:
+        buffer.HandleNotImpl();
+        break;
+    }
+
+    if (!buffer.response.Write(fd)) {
+      LOG(ERROR) << "Failed to write a response to the device.";
+      return false;
+    }
+  }
+
+  return true;
+}
+
+}  // namespace fuse
+}  // namespace android
diff --git a/libappfuse/FuseBridgeLoop.cc b/libappfuse/FuseBridgeLoop.cc
new file mode 100644
index 0000000..2386bf8
--- /dev/null
+++ b/libappfuse/FuseBridgeLoop.cc
@@ -0,0 +1,101 @@
+/*
+ * 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 specic language governing permissions and
+ * limitations under the License.
+ */
+
+#include "libappfuse/FuseBridgeLoop.h"
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
+namespace android {
+namespace fuse {
+
+bool StartFuseBridgeLoop(
+    int raw_dev_fd, int raw_proxy_fd, FuseBridgeLoopCallback* callback) {
+  base::unique_fd dev_fd(raw_dev_fd);
+  base::unique_fd proxy_fd(raw_proxy_fd);
+  FuseBuffer buffer;
+  size_t open_count = 0;
+
+  LOG(DEBUG) << "Start fuse loop.";
+  while (true) {
+    if (!buffer.request.Read(dev_fd)) {
+      return false;
+    }
+
+    const uint32_t opcode = buffer.request.header.opcode;
+    LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode;
+    switch (opcode) {
+      case FUSE_FORGET:
+        // Do not reply to FUSE_FORGET.
+        continue;
+
+      case FUSE_LOOKUP:
+      case FUSE_GETATTR:
+      case FUSE_OPEN:
+      case FUSE_READ:
+      case FUSE_WRITE:
+      case FUSE_RELEASE:
+      case FUSE_FSYNC:
+        if (!buffer.request.Write(proxy_fd)) {
+          LOG(ERROR) << "Failed to write a request to the proxy.";
+          return false;
+        }
+        if (!buffer.response.Read(proxy_fd)) {
+          LOG(ERROR) << "Failed to read a response from the proxy.";
+          return false;
+        }
+        break;
+
+      case FUSE_INIT:
+        buffer.HandleInit();
+        break;
+
+      default:
+        buffer.HandleNotImpl();
+        break;
+    }
+
+    if (!buffer.response.Write(dev_fd)) {
+      LOG(ERROR) << "Failed to write a response to the device.";
+      return false;
+    }
+
+    switch (opcode) {
+      case FUSE_INIT:
+        callback->OnMount();
+        break;
+      case FUSE_OPEN:
+        if (buffer.response.header.error == fuse::kFuseSuccess) {
+          open_count++;
+        }
+        break;
+      case FUSE_RELEASE:
+        if (open_count != 0) {
+            open_count--;
+        } else {
+            LOG(WARNING) << "Unexpected FUSE_RELEASE before opening a file.";
+            break;
+        }
+        if (open_count == 0) {
+          return true;
+        }
+        break;
+    }
+  }
+}
+
+}  // namespace fuse
+}  // namespace android
diff --git a/libappfuse/FuseBuffer.cc b/libappfuse/FuseBuffer.cc
new file mode 100644
index 0000000..3ade31c
--- /dev/null
+++ b/libappfuse/FuseBuffer.cc
@@ -0,0 +1,149 @@
+/*
+ * 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 specic language governing permissions and
+ * limitations under the License.
+ */
+
+#include "libappfuse/FuseBuffer.h"
+
+#include <inttypes.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <type_traits>
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+
+namespace android {
+namespace fuse {
+
+static_assert(
+    std::is_standard_layout<FuseBuffer>::value,
+    "FuseBuffer must be standard layout union.");
+
+template <typename T>
+bool FuseMessage<T>::CheckHeaderLength() const {
+  const auto& header = static_cast<const T*>(this)->header;
+  if (sizeof(header) <= header.len && header.len <= sizeof(T)) {
+    return true;
+  } else {
+    LOG(ERROR) << "Packet size is invalid=" << header.len;
+    return false;
+  }
+}
+
+template <typename T>
+bool FuseMessage<T>::CheckResult(
+    int result, const char* operation_name) const {
+  const auto& header = static_cast<const T*>(this)->header;
+  if (result >= 0 && static_cast<uint32_t>(result) == header.len) {
+    return true;
+  } else {
+    PLOG(ERROR) << "Failed to " << operation_name
+        << " a packet. result=" << result << " header.len="
+        << header.len;
+    return false;
+  }
+}
+
+template <typename T>
+bool FuseMessage<T>::Read(int fd) {
+  const ssize_t result = TEMP_FAILURE_RETRY(::read(fd, this, sizeof(T)));
+  return CheckHeaderLength() && CheckResult(result, "read");
+}
+
+template <typename T>
+bool FuseMessage<T>::Write(int fd) const {
+  const auto& header = static_cast<const T*>(this)->header;
+  if (!CheckHeaderLength()) {
+    return false;
+  }
+  const ssize_t result = TEMP_FAILURE_RETRY(::write(fd, this, header.len));
+  return CheckResult(result, "write");
+}
+
+template class FuseMessage<FuseRequest>;
+template class FuseMessage<FuseResponse>;
+
+void FuseRequest::Reset(
+    uint32_t data_length, uint32_t opcode, uint64_t unique) {
+  memset(this, 0, sizeof(fuse_in_header) + data_length);
+  header.len = sizeof(fuse_in_header) + data_length;
+  header.opcode = opcode;
+  header.unique = unique;
+}
+
+void FuseResponse::ResetHeader(
+    uint32_t data_length, int32_t error, uint64_t unique) {
+  CHECK_LE(error, 0) << "error should be zero or negative.";
+  header.len = sizeof(fuse_out_header) + data_length;
+  header.error = error;
+  header.unique = unique;
+}
+
+void FuseResponse::Reset(uint32_t data_length, int32_t error, uint64_t unique) {
+  memset(this, 0, sizeof(fuse_out_header) + data_length);
+  ResetHeader(data_length, error, unique);
+}
+
+void FuseBuffer::HandleInit() {
+  const fuse_init_in* const in = &request.init_in;
+
+  // Before writing |out|, we need to copy data from |in|.
+  const uint64_t unique = request.header.unique;
+  const uint32_t minor = in->minor;
+  const uint32_t max_readahead = in->max_readahead;
+
+  // Kernel 2.6.16 is the first stable kernel with struct fuse_init_out
+  // defined (fuse version 7.6). The structure is the same from 7.6 through
+  // 7.22. Beginning with 7.23, the structure increased in size and added
+  // new parameters.
+  if (in->major != FUSE_KERNEL_VERSION || in->minor < 6) {
+    LOG(ERROR) << "Fuse kernel version mismatch: Kernel version " << in->major
+        << "." << in->minor << " Expected at least " << FUSE_KERNEL_VERSION
+        << ".6";
+    response.Reset(0, -EPERM, unique);
+    return;
+  }
+
+  // We limit ourselves to minor=15 because we don't handle BATCH_FORGET yet.
+  // Thus we need to use FUSE_COMPAT_22_INIT_OUT_SIZE.
+#if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
+  // FUSE_KERNEL_VERSION >= 23.
+  const size_t response_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
+#else
+  const size_t response_size = sizeof(fuse_init_out);
+#endif
+
+  response.Reset(response_size, kFuseSuccess, unique);
+  fuse_init_out* const out = &response.init_out;
+  out->major = FUSE_KERNEL_VERSION;
+  out->minor = std::min(minor, 15u);
+  out->max_readahead = max_readahead;
+  out->flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
+  out->max_background = 32;
+  out->congestion_threshold = 32;
+  out->max_write = kFuseMaxWrite;
+}
+
+void FuseBuffer::HandleNotImpl() {
+  LOG(VERBOSE) << "NOTIMPL op=" << request.header.opcode << " uniq="
+      << request.header.unique << " nid=" << request.header.nodeid;
+  const uint64_t unique = request.header.unique;
+  response.Reset(0, -ENOSYS, unique);
+}
+
+}  // namespace fuse
+}  // namespace android
diff --git a/libappfuse/include/libappfuse/FuseAppLoop.h b/libappfuse/include/libappfuse/FuseAppLoop.h
new file mode 100644
index 0000000..c3edfcc
--- /dev/null
+++ b/libappfuse/include/libappfuse/FuseAppLoop.h
@@ -0,0 +1,44 @@
+/*
+ * 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 specic language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_LIBAPPFUSE_FUSEAPPLOOP_H_
+#define ANDROID_LIBAPPFUSE_FUSEAPPLOOP_H_
+
+#include "libappfuse/FuseBuffer.h"
+
+namespace android {
+namespace fuse {
+
+class FuseAppLoopCallback {
+ public:
+  virtual bool IsActive() = 0;
+  virtual int64_t OnGetSize(uint64_t inode) = 0;
+  virtual int32_t OnFsync(uint64_t inode) = 0;
+  virtual int32_t OnWrite(
+      uint64_t inode, uint64_t offset, uint32_t size, const void* data) = 0;
+  virtual int32_t OnRead(
+      uint64_t inode, uint64_t offset, uint32_t size, void* data) = 0;
+  virtual int32_t OnOpen(uint64_t inode) = 0;
+  virtual int32_t OnRelease(uint64_t inode) = 0;
+  virtual ~FuseAppLoopCallback() = default;
+};
+
+bool StartFuseAppLoop(int fd, FuseAppLoopCallback* callback);
+
+}  // namespace fuse
+}  // namespace android
+
+#endif  // ANDROID_LIBAPPFUSE_FUSEAPPLOOP_H_
diff --git a/libappfuse/include/libappfuse/FuseBridgeLoop.h b/libappfuse/include/libappfuse/FuseBridgeLoop.h
new file mode 100644
index 0000000..1f71cf2
--- /dev/null
+++ b/libappfuse/include/libappfuse/FuseBridgeLoop.h
@@ -0,0 +1,37 @@
+/*
+ * 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 specic language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_LIBAPPFUSE_FUSEBRIDGELOOP_H_
+#define ANDROID_LIBAPPFUSE_FUSEBRIDGELOOP_H_
+
+#include "libappfuse/FuseBuffer.h"
+
+namespace android {
+namespace fuse {
+
+class FuseBridgeLoopCallback {
+ public:
+  virtual void OnMount() = 0;
+  virtual ~FuseBridgeLoopCallback() = default;
+};
+
+bool StartFuseBridgeLoop(
+    int dev_fd, int proxy_fd, FuseBridgeLoopCallback* callback);
+
+}  // namespace fuse
+}  // namespace android
+
+#endif  // ANDROID_LIBAPPFUSE_FUSEBRIDGELOOP_H_
diff --git a/libappfuse/include/libappfuse/FuseBuffer.h b/libappfuse/include/libappfuse/FuseBuffer.h
new file mode 100644
index 0000000..e7f620c
--- /dev/null
+++ b/libappfuse/include/libappfuse/FuseBuffer.h
@@ -0,0 +1,98 @@
+/*
+ * 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 specic language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_LIBAPPFUSE_FUSEBUFFER_H_
+#define ANDROID_LIBAPPFUSE_FUSEBUFFER_H_
+
+#include <linux/fuse.h>
+
+namespace android {
+namespace fuse {
+
+// The numbers came from sdcard.c.
+// Maximum number of bytes to write/read in one request/one reply.
+constexpr size_t kFuseMaxWrite = 256 * 1024;
+constexpr size_t kFuseMaxRead = 128 * 1024;
+constexpr int32_t kFuseSuccess = 0;
+
+template<typename T>
+class FuseMessage {
+ public:
+  bool Read(int fd);
+  bool Write(int fd) const;
+ private:
+  bool CheckHeaderLength() const;
+  bool CheckResult(int result, const char* operation_name) const;
+};
+
+// FuseRequest represents file operation requests from /dev/fuse. It starts
+// from fuse_in_header. The body layout depends on the operation code.
+struct FuseRequest : public FuseMessage<FuseRequest> {
+  fuse_in_header header;
+  union {
+    // for FUSE_WRITE
+    struct {
+      fuse_write_in write_in;
+      char write_data[kFuseMaxWrite];
+    };
+    // for FUSE_OPEN
+    fuse_open_in open_in;
+    // for FUSE_INIT
+    fuse_init_in init_in;
+    // for FUSE_READ
+    fuse_read_in read_in;
+    // for FUSE_LOOKUP
+    char lookup_name[0];
+  };
+  void Reset(uint32_t data_length, uint32_t opcode, uint64_t unique);
+};
+
+// FuseResponse represents file operation responses to /dev/fuse. It starts
+// from fuse_out_header. The body layout depends on the operation code.
+struct FuseResponse : public FuseMessage<FuseResponse> {
+  fuse_out_header header;
+  union {
+    // for FUSE_INIT
+    fuse_init_out init_out;
+    // for FUSE_LOOKUP
+    fuse_entry_out entry_out;
+    // for FUSE_GETATTR
+    fuse_attr_out attr_out;
+    // for FUSE_OPEN
+    fuse_open_out open_out;
+    // for FUSE_READ
+    char read_data[kFuseMaxRead];
+    // for FUSE_WRITE
+    fuse_write_out write_out;
+  };
+  void Reset(uint32_t data_length, int32_t error, uint64_t unique);
+  void ResetHeader(uint32_t data_length, int32_t error, uint64_t unique);
+};
+
+// To reduce memory usage, FuseBuffer shares the memory region for request and
+// response.
+union FuseBuffer final {
+  FuseRequest request;
+  FuseResponse response;
+
+  void HandleInit();
+  void HandleNotImpl();
+};
+
+}  // namespace fuse
+}  // namespace android
+
+#endif  // ANDROID_LIBAPPFUSE_FUSEBUFFER_H_
diff --git a/libappfuse/tests/FuseAppLoopTest.cc b/libappfuse/tests/FuseAppLoopTest.cc
new file mode 100644
index 0000000..25906cf
--- /dev/null
+++ b/libappfuse/tests/FuseAppLoopTest.cc
@@ -0,0 +1,307 @@
+/*
+ * 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 specic language governing permissions and
+ * limitations under the License.
+ */
+
+#include "libappfuse/FuseAppLoop.h"
+
+#include <sys/socket.h>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <gtest/gtest.h>
+#include <thread>
+
+namespace android {
+namespace fuse {
+namespace {
+
+constexpr unsigned int kTestFileSize = 1024;
+
+struct CallbackRequest {
+  uint32_t code;
+  uint64_t inode;
+};
+
+class Callback : public FuseAppLoopCallback {
+ public:
+  std::vector<CallbackRequest> requests;
+
+  bool IsActive() override {
+    return true;
+  }
+
+  int64_t OnGetSize(uint64_t inode) override {
+    if (inode == FUSE_ROOT_ID) {
+      return 0;
+    } else {
+      return kTestFileSize;
+    }
+  }
+
+  int32_t OnFsync(uint64_t inode) override {
+    requests.push_back({
+      .code = FUSE_FSYNC,
+      .inode = inode
+    });
+    return 0;
+  }
+
+  int32_t OnWrite(uint64_t inode,
+                  uint64_t offset ATTRIBUTE_UNUSED,
+                  uint32_t size ATTRIBUTE_UNUSED,
+                  const void* data ATTRIBUTE_UNUSED) override {
+    requests.push_back({
+      .code = FUSE_WRITE,
+      .inode = inode
+    });
+    return 0;
+  }
+
+  int32_t OnRead(uint64_t inode,
+                 uint64_t offset ATTRIBUTE_UNUSED,
+                 uint32_t size ATTRIBUTE_UNUSED,
+                 void* data ATTRIBUTE_UNUSED) override {
+    requests.push_back({
+      .code = FUSE_READ,
+      .inode = inode
+    });
+    return 0;
+  }
+
+  int32_t OnOpen(uint64_t inode) override {
+    requests.push_back({
+      .code = FUSE_OPEN,
+      .inode = inode
+    });
+    return 0;
+  }
+
+  int32_t OnRelease(uint64_t inode) override {
+    requests.push_back({
+      .code = FUSE_RELEASE,
+      .inode = inode
+    });
+    return 0;
+  }
+};
+
+class FuseAppLoopTest : public ::testing::Test {
+ private:
+  std::thread thread_;
+
+ protected:
+  base::unique_fd sockets_[2];
+  Callback callback_;
+  FuseRequest request_;
+  FuseResponse response_;
+
+  void SetUp() override {
+    base::SetMinimumLogSeverity(base::VERBOSE);
+    int sockets[2];
+    ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets));
+    sockets_[0].reset(sockets[0]);
+    sockets_[1].reset(sockets[1]);
+    thread_ = std::thread([this] {
+      StartFuseAppLoop(sockets_[1].release(), &callback_);
+    });
+  }
+
+  void CheckCallback(
+      size_t data_size, uint32_t code, size_t expected_out_size) {
+    request_.Reset(data_size, code, 1);
+    request_.header.nodeid = 10;
+
+    ASSERT_TRUE(request_.Write(sockets_[0]));
+    ASSERT_TRUE(response_.Read(sockets_[0]));
+
+    Close();
+
+    EXPECT_EQ(kFuseSuccess, response_.header.error);
+    EXPECT_EQ(sizeof(fuse_out_header) + expected_out_size,
+              response_.header.len);
+    EXPECT_EQ(1u, response_.header.unique);
+
+    ASSERT_EQ(1u, callback_.requests.size());
+    EXPECT_EQ(code, callback_.requests[0].code);
+    EXPECT_EQ(10u, callback_.requests[0].inode);
+  }
+
+  void Close() {
+    sockets_[0].reset();
+    sockets_[1].reset();
+    if (thread_.joinable()) {
+      thread_.join();
+    }
+  }
+
+  void TearDown() override {
+    Close();
+  }
+};
+
+}  // namespace
+
+TEST_F(FuseAppLoopTest, LookUp) {
+  request_.Reset(3u, FUSE_LOOKUP, 1);
+  request_.header.nodeid = FUSE_ROOT_ID;
+  strcpy(request_.lookup_name, "10");
+
+  ASSERT_TRUE(request_.Write(sockets_[0].get()));
+  ASSERT_TRUE(response_.Read(sockets_[0].get()));
+
+  EXPECT_EQ(kFuseSuccess, response_.header.error);
+  EXPECT_EQ(sizeof(fuse_out_header) + sizeof(fuse_entry_out),
+            response_.header.len);
+  EXPECT_EQ(1u, response_.header.unique);
+
+  EXPECT_EQ(10u, response_.entry_out.nodeid);
+  EXPECT_EQ(0u, response_.entry_out.generation);
+  EXPECT_EQ(10u, response_.entry_out.entry_valid);
+  EXPECT_EQ(10u, response_.entry_out.attr_valid);
+  EXPECT_EQ(0u, response_.entry_out.entry_valid_nsec);
+  EXPECT_EQ(0u, response_.entry_out.attr_valid_nsec);
+
+  EXPECT_EQ(10u, response_.entry_out.attr.ino);
+  EXPECT_EQ(kTestFileSize, response_.entry_out.attr.size);
+  EXPECT_EQ(0u, response_.entry_out.attr.blocks);
+  EXPECT_EQ(0u, response_.entry_out.attr.atime);
+  EXPECT_EQ(0u, response_.entry_out.attr.mtime);
+  EXPECT_EQ(0u, response_.entry_out.attr.ctime);
+  EXPECT_EQ(0u, response_.entry_out.attr.atimensec);
+  EXPECT_EQ(0u, response_.entry_out.attr.mtimensec);
+  EXPECT_EQ(0u, response_.entry_out.attr.ctimensec);
+  EXPECT_EQ(S_IFREG | 0777u, response_.entry_out.attr.mode);
+  EXPECT_EQ(0u, response_.entry_out.attr.nlink);
+  EXPECT_EQ(0u, response_.entry_out.attr.uid);
+  EXPECT_EQ(0u, response_.entry_out.attr.gid);
+  EXPECT_EQ(0u, response_.entry_out.attr.rdev);
+  EXPECT_EQ(0u, response_.entry_out.attr.blksize);
+  EXPECT_EQ(0u, response_.entry_out.attr.padding);
+}
+
+TEST_F(FuseAppLoopTest, LookUp_InvalidName) {
+  request_.Reset(3u, FUSE_LOOKUP, 1);
+  request_.header.nodeid = FUSE_ROOT_ID;
+  strcpy(request_.lookup_name, "aa");
+
+  ASSERT_TRUE(request_.Write(sockets_[0].get()));
+  ASSERT_TRUE(response_.Read(sockets_[0].get()));
+
+  EXPECT_EQ(sizeof(fuse_out_header), response_.header.len);
+  EXPECT_EQ(-ENOENT, response_.header.error);
+  EXPECT_EQ(1u, response_.header.unique);
+}
+
+TEST_F(FuseAppLoopTest, LookUp_TooLargeName) {
+  request_.Reset(21u, FUSE_LOOKUP, 1);
+  request_.header.nodeid = FUSE_ROOT_ID;
+  strcpy(request_.lookup_name, "18446744073709551616");
+
+  ASSERT_TRUE(request_.Write(sockets_[0].get()));
+  ASSERT_TRUE(response_.Read(sockets_[0].get()));
+
+  EXPECT_EQ(sizeof(fuse_out_header), response_.header.len);
+  EXPECT_EQ(-ENOENT, response_.header.error);
+  EXPECT_EQ(1u, response_.header.unique);
+}
+
+TEST_F(FuseAppLoopTest, GetAttr) {
+  request_.Reset(sizeof(fuse_getattr_in), FUSE_GETATTR, 1);
+  request_.header.nodeid = 10;
+
+  ASSERT_TRUE(request_.Write(sockets_[0].get()));
+  ASSERT_TRUE(response_.Read(sockets_[0].get()));
+
+  EXPECT_EQ(kFuseSuccess, response_.header.error);
+  EXPECT_EQ(sizeof(fuse_out_header) + sizeof(fuse_attr_out),
+            response_.header.len);
+  EXPECT_EQ(1u, response_.header.unique);
+
+  EXPECT_EQ(10u, response_.attr_out.attr_valid);
+  EXPECT_EQ(0u, response_.attr_out.attr_valid_nsec);
+
+  EXPECT_EQ(10u, response_.attr_out.attr.ino);
+  EXPECT_EQ(kTestFileSize, response_.attr_out.attr.size);
+  EXPECT_EQ(0u, response_.attr_out.attr.blocks);
+  EXPECT_EQ(0u, response_.attr_out.attr.atime);
+  EXPECT_EQ(0u, response_.attr_out.attr.mtime);
+  EXPECT_EQ(0u, response_.attr_out.attr.ctime);
+  EXPECT_EQ(0u, response_.attr_out.attr.atimensec);
+  EXPECT_EQ(0u, response_.attr_out.attr.mtimensec);
+  EXPECT_EQ(0u, response_.attr_out.attr.ctimensec);
+  EXPECT_EQ(S_IFREG | 0777u, response_.attr_out.attr.mode);
+  EXPECT_EQ(0u, response_.attr_out.attr.nlink);
+  EXPECT_EQ(0u, response_.attr_out.attr.uid);
+  EXPECT_EQ(0u, response_.attr_out.attr.gid);
+  EXPECT_EQ(0u, response_.attr_out.attr.rdev);
+  EXPECT_EQ(0u, response_.attr_out.attr.blksize);
+  EXPECT_EQ(0u, response_.attr_out.attr.padding);
+}
+
+TEST_F(FuseAppLoopTest, GetAttr_Root) {
+  request_.Reset(sizeof(fuse_getattr_in), FUSE_GETATTR, 1);
+  request_.header.nodeid = FUSE_ROOT_ID;
+
+  ASSERT_TRUE(request_.Write(sockets_[0].get()));
+  ASSERT_TRUE(response_.Read(sockets_[0].get()));
+
+  EXPECT_EQ(kFuseSuccess, response_.header.error);
+  EXPECT_EQ(sizeof(fuse_out_header) + sizeof(fuse_attr_out),
+            response_.header.len);
+  EXPECT_EQ(1u, response_.header.unique);
+
+  EXPECT_EQ(10u, response_.attr_out.attr_valid);
+  EXPECT_EQ(0u, response_.attr_out.attr_valid_nsec);
+
+  EXPECT_EQ(static_cast<unsigned>(FUSE_ROOT_ID), response_.attr_out.attr.ino);
+  EXPECT_EQ(0u, response_.attr_out.attr.size);
+  EXPECT_EQ(0u, response_.attr_out.attr.blocks);
+  EXPECT_EQ(0u, response_.attr_out.attr.atime);
+  EXPECT_EQ(0u, response_.attr_out.attr.mtime);
+  EXPECT_EQ(0u, response_.attr_out.attr.ctime);
+  EXPECT_EQ(0u, response_.attr_out.attr.atimensec);
+  EXPECT_EQ(0u, response_.attr_out.attr.mtimensec);
+  EXPECT_EQ(0u, response_.attr_out.attr.ctimensec);
+  EXPECT_EQ(S_IFDIR | 0777u, response_.attr_out.attr.mode);
+  EXPECT_EQ(0u, response_.attr_out.attr.nlink);
+  EXPECT_EQ(0u, response_.attr_out.attr.uid);
+  EXPECT_EQ(0u, response_.attr_out.attr.gid);
+  EXPECT_EQ(0u, response_.attr_out.attr.rdev);
+  EXPECT_EQ(0u, response_.attr_out.attr.blksize);
+  EXPECT_EQ(0u, response_.attr_out.attr.padding);
+}
+
+TEST_F(FuseAppLoopTest, Open) {
+  CheckCallback(sizeof(fuse_open_in), FUSE_OPEN, sizeof(fuse_open_out));
+}
+
+TEST_F(FuseAppLoopTest, Fsync) {
+  CheckCallback(0u, FUSE_FSYNC, 0u);
+}
+
+TEST_F(FuseAppLoopTest, Release) {
+  CheckCallback(0u, FUSE_RELEASE, 0u);
+}
+
+TEST_F(FuseAppLoopTest, Read) {
+  CheckCallback(sizeof(fuse_read_in), FUSE_READ, 0u);
+}
+
+TEST_F(FuseAppLoopTest, Write) {
+  CheckCallback(sizeof(fuse_write_in), FUSE_WRITE, sizeof(fuse_write_out));
+}
+
+}  // namespace fuse
+}  // namespace android
diff --git a/libappfuse/tests/FuseBridgeLoopTest.cc b/libappfuse/tests/FuseBridgeLoopTest.cc
new file mode 100644
index 0000000..e74d9e7
--- /dev/null
+++ b/libappfuse/tests/FuseBridgeLoopTest.cc
@@ -0,0 +1,216 @@
+/*
+ * 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 specic language governing permissions and
+ * limitations under the License.
+ */
+
+#include "libappfuse/FuseBridgeLoop.h"
+
+#include <sys/socket.h>
+
+#include <sstream>
+#include <thread>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace fuse {
+namespace {
+
+class Callback : public FuseBridgeLoopCallback {
+ public:
+  bool mounted;
+  Callback() : mounted(false) {}
+  void OnMount() override {
+    mounted = true;
+  }
+};
+
+class FuseBridgeLoopTest : public ::testing::Test {
+ protected:
+  base::unique_fd dev_sockets_[2];
+  base::unique_fd proxy_sockets_[2];
+  Callback callback_;
+  std::thread thread_;
+
+  FuseRequest request_;
+  FuseResponse response_;
+
+  void SetUp() override {
+    base::SetMinimumLogSeverity(base::VERBOSE);
+    int dev_sockets[2];
+    int proxy_sockets[2];
+    ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, dev_sockets));
+    ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, proxy_sockets));
+    dev_sockets_[0].reset(dev_sockets[0]);
+    dev_sockets_[1].reset(dev_sockets[1]);
+    proxy_sockets_[0].reset(proxy_sockets[0]);
+    proxy_sockets_[1].reset(proxy_sockets[1]);
+
+    thread_ = std::thread([this] {
+      StartFuseBridgeLoop(
+          dev_sockets_[1].release(), proxy_sockets_[0].release(), &callback_);
+    });
+  }
+
+  void CheckNotImpl(uint32_t opcode) {
+    SCOPED_TRACE((std::ostringstream() << "opcode: " << opcode).str());
+
+    memset(&request_, 0, sizeof(FuseRequest));
+    request_.header.opcode = opcode;
+    request_.header.len = sizeof(fuse_in_header);
+    ASSERT_TRUE(request_.Write(dev_sockets_[0]));
+
+    memset(&response_, 0, sizeof(FuseResponse));
+    ASSERT_TRUE(response_.Read(dev_sockets_[0]));
+    EXPECT_EQ(-ENOSYS, response_.header.error);
+  }
+
+  void CheckProxy(uint32_t opcode) {
+    SCOPED_TRACE((std::ostringstream() << "opcode: " << opcode).str());
+
+    memset(&request_, 0, sizeof(FuseRequest));
+    request_.header.opcode = opcode;
+    request_.header.unique = opcode; // Use opcode as unique.
+    request_.header.len = sizeof(fuse_in_header);
+    ASSERT_TRUE(request_.Write(dev_sockets_[0]));
+
+    memset(&request_, 0, sizeof(FuseRequest));
+    ASSERT_TRUE(request_.Read(proxy_sockets_[1]));
+    EXPECT_EQ(opcode, request_.header.opcode);
+    EXPECT_EQ(opcode, request_.header.unique);
+
+    memset(&response_, 0, sizeof(FuseResponse));
+    response_.header.len = sizeof(fuse_out_header);
+    response_.header.unique = opcode;  // Use opcode as unique.
+    response_.header.error = kFuseSuccess;
+    ASSERT_TRUE(response_.Write(proxy_sockets_[1]));
+
+    memset(&response_, 0, sizeof(FuseResponse));
+    ASSERT_TRUE(response_.Read(dev_sockets_[0]));
+    EXPECT_EQ(opcode, response_.header.unique);
+    EXPECT_EQ(kFuseSuccess, response_.header.error);
+  }
+
+  void SendInitRequest(uint64_t unique) {
+    memset(&request_, 0, sizeof(FuseRequest));
+    request_.header.opcode = FUSE_INIT;
+    request_.header.unique = unique;
+    request_.header.len = sizeof(fuse_in_header) + sizeof(fuse_init_in);
+    request_.init_in.major = FUSE_KERNEL_VERSION;
+    request_.init_in.minor = FUSE_KERNEL_MINOR_VERSION;
+    ASSERT_TRUE(request_.Write(dev_sockets_[0]));
+  }
+
+  void Close() {
+    dev_sockets_[0].reset();
+    dev_sockets_[1].reset();
+    proxy_sockets_[0].reset();
+    proxy_sockets_[1].reset();
+    if (thread_.joinable()) {
+      thread_.join();
+    }
+  }
+
+  void TearDown() override {
+    Close();
+  }
+};
+
+} //  namespace
+
+TEST_F(FuseBridgeLoopTest, FuseInit) {
+  SendInitRequest(1u);
+
+  memset(&response_, 0, sizeof(FuseResponse));
+  ASSERT_TRUE(response_.Read(dev_sockets_[0]));
+  EXPECT_EQ(kFuseSuccess, response_.header.error);
+  EXPECT_EQ(1u, response_.header.unique);
+
+  // Unmount.
+  Close();
+  EXPECT_TRUE(callback_.mounted);
+}
+
+TEST_F(FuseBridgeLoopTest, FuseForget) {
+  memset(&request_, 0, sizeof(FuseRequest));
+  request_.header.opcode = FUSE_FORGET;
+  request_.header.unique = 1u;
+  request_.header.len = sizeof(fuse_in_header) + sizeof(fuse_forget_in);
+  ASSERT_TRUE(request_.Write(dev_sockets_[0]));
+
+  SendInitRequest(2u);
+
+  memset(&response_, 0, sizeof(FuseResponse));
+  ASSERT_TRUE(response_.Read(dev_sockets_[0]));
+  EXPECT_EQ(2u, response_.header.unique) <<
+      "The loop must not respond to FUSE_FORGET";
+}
+
+TEST_F(FuseBridgeLoopTest, FuseNotImpl) {
+  CheckNotImpl(FUSE_SETATTR);
+  CheckNotImpl(FUSE_READLINK);
+  CheckNotImpl(FUSE_SYMLINK);
+  CheckNotImpl(FUSE_MKNOD);
+  CheckNotImpl(FUSE_MKDIR);
+  CheckNotImpl(FUSE_UNLINK);
+  CheckNotImpl(FUSE_RMDIR);
+  CheckNotImpl(FUSE_RENAME);
+  CheckNotImpl(FUSE_LINK);
+  CheckNotImpl(FUSE_STATFS);
+  CheckNotImpl(FUSE_SETXATTR);
+  CheckNotImpl(FUSE_GETXATTR);
+  CheckNotImpl(FUSE_LISTXATTR);
+  CheckNotImpl(FUSE_REMOVEXATTR);
+  CheckNotImpl(FUSE_FLUSH);
+  CheckNotImpl(FUSE_OPENDIR);
+  CheckNotImpl(FUSE_READDIR);
+  CheckNotImpl(FUSE_RELEASEDIR);
+  CheckNotImpl(FUSE_FSYNCDIR);
+  CheckNotImpl(FUSE_GETLK);
+  CheckNotImpl(FUSE_SETLK);
+  CheckNotImpl(FUSE_SETLKW);
+  CheckNotImpl(FUSE_ACCESS);
+  CheckNotImpl(FUSE_CREATE);
+  CheckNotImpl(FUSE_INTERRUPT);
+  CheckNotImpl(FUSE_BMAP);
+  CheckNotImpl(FUSE_DESTROY);
+  CheckNotImpl(FUSE_IOCTL);
+  CheckNotImpl(FUSE_POLL);
+  CheckNotImpl(FUSE_NOTIFY_REPLY);
+  CheckNotImpl(FUSE_BATCH_FORGET);
+  CheckNotImpl(FUSE_FALLOCATE);
+  CheckNotImpl(FUSE_READDIRPLUS);
+  CheckNotImpl(FUSE_RENAME2);
+  CheckNotImpl(FUSE_LSEEK);
+}
+
+TEST_F(FuseBridgeLoopTest, Proxy) {
+  CheckProxy(FUSE_LOOKUP);
+  CheckProxy(FUSE_GETATTR);
+  CheckProxy(FUSE_READ);
+  CheckProxy(FUSE_WRITE);
+  CheckProxy(FUSE_FSYNC);
+
+  // Invoke FUSE_OPEN and FUSE_RELEASE at last as the loop will exit when all files are closed.
+  CheckProxy(FUSE_OPEN);
+  CheckProxy(FUSE_RELEASE);
+
+  // Ensure the loop exits.
+  Close();
+}
+
+}  // namespace fuse
+}  // namespace android
diff --git a/libappfuse/tests/FuseBufferTest.cc b/libappfuse/tests/FuseBufferTest.cc
new file mode 100644
index 0000000..c822135
--- /dev/null
+++ b/libappfuse/tests/FuseBufferTest.cc
@@ -0,0 +1,189 @@
+/*
+ * 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 specic language governing permissions and
+ * limitations under the License.
+ */
+
+#include "libappfuse/FuseBuffer.h"
+
+#include <fcntl.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include <android-base/unique_fd.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace fuse {
+
+constexpr char kTempFile[] = "/data/local/tmp/appfuse_test_dump";
+
+void OpenTempFile(android::base::unique_fd* fd) {
+  fd->reset(open(kTempFile, O_CREAT | O_RDWR));
+  ASSERT_NE(-1, *fd) << strerror(errno);
+  unlink(kTempFile);
+  ASSERT_NE(-1, *fd) << strerror(errno);
+}
+
+void TestReadInvalidLength(size_t headerSize, size_t write_size) {
+  android::base::unique_fd fd;
+  OpenTempFile(&fd);
+
+  char buffer[std::max(headerSize, sizeof(FuseRequest))];
+  FuseRequest* const packet = reinterpret_cast<FuseRequest*>(buffer);
+  packet->header.len = headerSize;
+  ASSERT_NE(-1, write(fd, packet, write_size)) << strerror(errno);
+
+  lseek(fd, 0, SEEK_SET);
+  EXPECT_FALSE(packet->Read(fd));
+}
+
+void TestWriteInvalidLength(size_t size) {
+  android::base::unique_fd fd;
+  OpenTempFile(&fd);
+
+  char buffer[std::max(size, sizeof(FuseRequest))];
+  FuseRequest* const packet = reinterpret_cast<FuseRequest*>(buffer);
+  packet->header.len = size;
+  EXPECT_FALSE(packet->Write(fd));
+}
+
+// Use FuseRequest as a template instance of FuseMessage.
+
+TEST(FuseMessageTest, ReadAndWrite) {
+  android::base::unique_fd fd;
+  OpenTempFile(&fd);
+
+  FuseRequest request;
+  request.header.len = sizeof(FuseRequest);
+  request.header.opcode = 1;
+  request.header.unique = 2;
+  request.header.nodeid = 3;
+  request.header.uid = 4;
+  request.header.gid = 5;
+  request.header.pid = 6;
+  strcpy(request.lookup_name, "test");
+
+  ASSERT_TRUE(request.Write(fd));
+
+  memset(&request, 0, sizeof(FuseRequest));
+  lseek(fd, 0, SEEK_SET);
+
+  ASSERT_TRUE(request.Read(fd));
+  EXPECT_EQ(sizeof(FuseRequest), request.header.len);
+  EXPECT_EQ(1u, request.header.opcode);
+  EXPECT_EQ(2u, request.header.unique);
+  EXPECT_EQ(3u, request.header.nodeid);
+  EXPECT_EQ(4u, request.header.uid);
+  EXPECT_EQ(5u, request.header.gid);
+  EXPECT_EQ(6u, request.header.pid);
+  EXPECT_STREQ("test", request.lookup_name);
+}
+
+TEST(FuseMessageTest, Read_InconsistentLength) {
+  TestReadInvalidLength(sizeof(fuse_in_header), sizeof(fuse_in_header) + 1);
+}
+
+TEST(FuseMessageTest, Read_TooLong) {
+  TestReadInvalidLength(sizeof(FuseRequest) + 1, sizeof(FuseRequest) + 1);
+}
+
+TEST(FuseMessageTest, Read_TooShort) {
+  TestReadInvalidLength(sizeof(fuse_in_header) - 1, sizeof(fuse_in_header) - 1);
+}
+
+TEST(FuseMessageTest, Write_TooLong) {
+  TestWriteInvalidLength(sizeof(FuseRequest) + 1);
+}
+
+TEST(FuseMessageTest, Write_TooShort) {
+  TestWriteInvalidLength(sizeof(fuse_in_header) - 1);
+}
+
+TEST(FuseResponseTest, Reset) {
+  FuseResponse response;
+  // Write 1 to the first ten bytes.
+  memset(response.read_data, 'a', 10);
+
+  response.Reset(0, -1, 2);
+  EXPECT_EQ(sizeof(fuse_out_header), response.header.len);
+  EXPECT_EQ(-1, response.header.error);
+  EXPECT_EQ(2u, response.header.unique);
+  EXPECT_EQ('a', response.read_data[0]);
+  EXPECT_EQ('a', response.read_data[9]);
+
+  response.Reset(5, -4, 3);
+  EXPECT_EQ(sizeof(fuse_out_header) + 5, response.header.len);
+  EXPECT_EQ(-4, response.header.error);
+  EXPECT_EQ(3u, response.header.unique);
+  EXPECT_EQ(0, response.read_data[0]);
+  EXPECT_EQ(0, response.read_data[1]);
+  EXPECT_EQ(0, response.read_data[2]);
+  EXPECT_EQ(0, response.read_data[3]);
+  EXPECT_EQ(0, response.read_data[4]);
+  EXPECT_EQ('a', response.read_data[5]);
+}
+
+TEST(FuseResponseTest, ResetHeader) {
+  FuseResponse response;
+  // Write 1 to the first ten bytes.
+  memset(response.read_data, 'a', 10);
+
+  response.ResetHeader(0, -1, 2);
+  EXPECT_EQ(sizeof(fuse_out_header), response.header.len);
+  EXPECT_EQ(-1, response.header.error);
+  EXPECT_EQ(2u, response.header.unique);
+  EXPECT_EQ('a', response.read_data[0]);
+  EXPECT_EQ('a', response.read_data[9]);
+
+  response.ResetHeader(5, -4, 3);
+  EXPECT_EQ(sizeof(fuse_out_header) + 5, response.header.len);
+  EXPECT_EQ(-4, response.header.error);
+  EXPECT_EQ(3u, response.header.unique);
+  EXPECT_EQ('a', response.read_data[0]);
+  EXPECT_EQ('a', response.read_data[9]);
+}
+
+TEST(FuseBufferTest, HandleInit) {
+  FuseBuffer buffer;
+  memset(&buffer, 0, sizeof(FuseBuffer));
+
+  buffer.request.header.opcode = FUSE_INIT;
+  buffer.request.init_in.major = FUSE_KERNEL_VERSION;
+  buffer.request.init_in.minor = FUSE_KERNEL_MINOR_VERSION;
+
+  buffer.HandleInit();
+
+  ASSERT_EQ(sizeof(fuse_out_header) + FUSE_COMPAT_22_INIT_OUT_SIZE,
+            buffer.response.header.len);
+  EXPECT_EQ(kFuseSuccess, buffer.response.header.error);
+  EXPECT_EQ(static_cast<unsigned int>(FUSE_KERNEL_VERSION),
+            buffer.response.init_out.major);
+  EXPECT_EQ(15u, buffer.response.init_out.minor);
+  EXPECT_EQ(static_cast<unsigned int>(FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES),
+      buffer.response.init_out.flags);
+  EXPECT_EQ(kFuseMaxWrite, buffer.response.init_out.max_write);
+}
+
+TEST(FuseBufferTest, HandleNotImpl) {
+  FuseBuffer buffer;
+  memset(&buffer, 0, sizeof(FuseBuffer));
+
+  buffer.HandleNotImpl();
+
+  ASSERT_EQ(sizeof(fuse_out_header), buffer.response.header.len);
+  EXPECT_EQ(-ENOSYS, buffer.response.header.error);
+}
+
+} // namespace fuse
+} // namespace android
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
new file mode 100644
index 0000000..5c72234
--- /dev/null
+++ b/libbacktrace/Android.bp
@@ -0,0 +1,120 @@
+//
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_defaults {
+    name: "libbacktrace_common",
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    clang_cflags: ["-Wno-inline-asm"],
+
+    // The latest clang (r230699) does not allow SP/PC to be declared in inline asm lists.
+    include_dirs: ["external/libunwind/include/tdep"],
+
+    // TODO: LLVM_DEVICE_BUILD_MK
+    // TODO: LLVM_HOST_BUILD_MK
+
+    target: {
+        host: {
+            // -fno-omit-frame-pointer should be set for host build. Because currently
+            // libunwind can't recognize .debug_frame using dwarf version 4, and it relies
+            // on stack frame pointer to do unwinding on x86.
+            // $(LLVM_HOST_BUILD_MK) overwrites -fno-omit-frame-pointer. so the below line
+            // must be after the include.
+            cflags: [
+                "-Wno-extern-c-compat",
+                "-fno-omit-frame-pointer",
+            ],
+        },
+
+        darwin: {
+            enabled: false,
+        },
+    },
+
+    multilib: {
+        lib32: {
+            suffix: "32",
+        },
+        lib64: {
+            suffix: "64",
+        },
+    }
+}
+
+libbacktrace_sources = [
+    "Backtrace.cpp",
+    "BacktraceCurrent.cpp",
+    "BacktracePtrace.cpp",
+    "thread_utils.c",
+    "ThreadEntry.cpp",
+    "UnwindCurrent.cpp",
+    "UnwindMap.cpp",
+    "UnwindPtrace.cpp",
+]
+
+cc_library {
+    name: "libbacktrace",
+    defaults: ["libbacktrace_common"],
+    host_supported: true,
+
+    srcs: [
+        "BacktraceMap.cpp",
+    ],
+
+    target: {
+        darwin: {
+            enabled: true,
+        },
+        linux: {
+            srcs: libbacktrace_sources,
+
+            shared_libs: [
+                "libbase",
+                "liblog",
+                "libunwind",
+            ],
+
+            static_libs: ["libcutils"],
+            host_ldlibs: ["-lrt"],
+        },
+        android: {
+            srcs: libbacktrace_sources,
+
+            shared_libs: [
+                "libbase",
+                "liblog",
+                "libunwind",
+            ],
+
+            static_libs: ["libcutils"],
+        },
+    },
+}
+
+cc_library_shared {
+    name: "libbacktrace_test",
+    defaults: ["libbacktrace_common"],
+    host_supported: true,
+    strip: {
+        none: true,
+    },
+    cflags: ["-O0"],
+    srcs: ["backtrace_testlib.c"],
+}
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index ee25e08..bb17325 100644
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -20,12 +20,8 @@
 	-Wall \
 	-Werror \
 
-libbacktrace_common_conlyflags := \
-	-std=gnu99 \
-
-libbacktrace_common_cppflags := \
-	-std=gnu++11 \
-	-I external/libunwind/include/tdep \
+libbacktrace_common_c_includes := \
+	external/libunwind/include/tdep \
 
 # The latest clang (r230699) does not allow SP/PC to be declared in inline asm lists.
 libbacktrace_common_clang_cflags += \
@@ -42,45 +38,6 @@
 include $(LLVM_ROOT_PATH)/llvm.mk
 
 #-------------------------------------------------------------------------
-# The libbacktrace library.
-#-------------------------------------------------------------------------
-libbacktrace_src_files := \
-	Backtrace.cpp \
-	BacktraceCurrent.cpp \
-	BacktraceMap.cpp \
-	BacktracePtrace.cpp \
-	thread_utils.c \
-	ThreadEntry.cpp \
-	UnwindCurrent.cpp \
-	UnwindMap.cpp \
-	UnwindPtrace.cpp \
-
-libbacktrace_shared_libraries := \
-	libbase \
-	liblog \
-	libunwind \
-
-libbacktrace_static_libraries := \
-	libcutils
-
-module := libbacktrace
-module_tag := optional
-build_type := target
-build_target := SHARED_LIBRARY
-include $(LOCAL_PATH)/Android.build.mk
-build_type := host
-libbacktrace_multilib := both
-include $(LOCAL_PATH)/Android.build.mk
-libbacktrace_static_libraries := \
-	libbase \
-	liblog \
-	libunwind \
-
-build_target := STATIC_LIBRARY
-include $(LOCAL_PATH)/Android.build.mk
-libbacktrace_static_libraries :=
-
-#-------------------------------------------------------------------------
 # The libbacktrace_offline shared library.
 #-------------------------------------------------------------------------
 libbacktrace_offline_src_files := \
@@ -104,7 +61,7 @@
 libbacktrace_offline_static_libraries_host := \
 	libbacktrace \
 	libunwind \
-	libziparchive-host \
+	libziparchive \
 	libz \
 	libbase \
 	liblog \
@@ -125,26 +82,6 @@
 include $(LOCAL_PATH)/Android.build.mk
 
 #-------------------------------------------------------------------------
-# The libbacktrace_test library needed by backtrace_test.
-#-------------------------------------------------------------------------
-libbacktrace_test_cflags := \
-	-O0 \
-
-libbacktrace_test_src_files := \
-	backtrace_testlib.c \
-
-libbacktrace_test_strip_module := false
-
-module := libbacktrace_test
-module_tag := debug
-build_type := target
-build_target := SHARED_LIBRARY
-libbacktrace_test_multilib := both
-include $(LOCAL_PATH)/Android.build.mk
-build_type := host
-include $(LOCAL_PATH)/Android.build.mk
-
-#-------------------------------------------------------------------------
 # The backtrace_test executable.
 #-------------------------------------------------------------------------
 backtrace_test_cflags := \
@@ -186,7 +123,7 @@
 	libz \
 
 backtrace_test_static_libraries_host := \
-	libziparchive-host \
+	libziparchive \
 	libz \
 	libutils \
 	libLLVMObject \
@@ -209,22 +146,3 @@
 include $(LOCAL_PATH)/Android.build.mk
 build_type := host
 include $(LOCAL_PATH)/Android.build.mk
-
-#----------------------------------------------------------------------------
-# Special truncated libbacktrace library for mac.
-#----------------------------------------------------------------------------
-ifeq ($(HOST_OS),darwin)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libbacktrace
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := \
-	BacktraceMap.cpp \
-
-LOCAL_MULTILIB := both
-
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-endif # HOST_OS-darwin
diff --git a/libbacktrace/BacktraceLog.h b/libbacktrace/BacktraceLog.h
index 5c39f1c..0a27982 100644
--- a/libbacktrace/BacktraceLog.h
+++ b/libbacktrace/BacktraceLog.h
@@ -19,7 +19,7 @@
 
 #define LOG_TAG "libbacktrace"
 
-#include <log/log.h>
+#include <android/log.h>
 
 // Macro to log the function name along with the warning message.
 #define BACK_LOGW(format, ...) \
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index 85f2436..4496375 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -14,14 +14,17 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "backtrace-map"
+
 #include <ctype.h>
+#include <inttypes.h>
 #include <stdint.h>
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <android/log.h>
 #include <backtrace/backtrace_constants.h>
 #include <backtrace/BacktraceMap.h>
-#include <log/log.h>
 
 #include "thread_utils.h"
 
@@ -46,8 +49,8 @@
 }
 
 bool BacktraceMap::ParseLine(const char* line, backtrace_map_t* map) {
-  unsigned long int start;
-  unsigned long int end;
+  uint64_t start;
+  uint64_t end;
   char permissions[5];
   int name_pos;
 
@@ -56,14 +59,14 @@
 // __TEXT                 0009f000-000a1000 [    8K     8K] r-x/rwx SM=COW  /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n
 // 012345678901234567890123456789012345678901234567890123456789
 // 0         1         2         3         4         5
-  if (sscanf(line, "%*21c %lx-%lx [%*13c] %3c/%*3c SM=%*3c  %n",
+  if (sscanf(line, "%*21c %" SCNx64 "-%" SCNx64 " [%*13c] %3c/%*3c SM=%*3c  %n",
              &start, &end, permissions, &name_pos) != 3) {
 #else
 // Linux /proc/<pid>/maps lines:
 // 6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /system/lib/libcomposer.so\n
 // 012345678901234567890123456789012345678901234567890123456789
 // 0         1         2         3         4         5
-  if (sscanf(line, "%lx-%lx %4s %*x %*x:%*x %*d %n",
+  if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %4s %*x %*x:%*x %*d %n",
              &start, &end, permissions, &name_pos) != 3) {
 #endif
     return false;
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
index 9a4f622..a05a6d8 100644
--- a/libbacktrace/BacktraceOffline.cpp
+++ b/libbacktrace/BacktraceOffline.cpp
@@ -665,7 +665,7 @@
 
 class ScopedZiparchiveHandle {
  public:
-  ScopedZiparchiveHandle(ZipArchiveHandle handle) : handle_(handle) {
+  explicit ScopedZiparchiveHandle(ZipArchiveHandle handle) : handle_(handle) {
   }
 
   ~ScopedZiparchiveHandle() {
@@ -719,7 +719,7 @@
   auto binary_or_err = llvm::object::createBinary(buffer_or_err.get()->getMemBufferRef());
   if (!binary_or_err) {
     BACK_LOGW("failed to create binary for %s in %s: %s", elf_file.c_str(), apk_file.c_str(),
-              binary_or_err.getError().message().c_str());
+              llvm::toString(binary_or_err.takeError()).c_str());
     return nothing;
   }
   return llvm::object::OwningBinary<llvm::object::Binary>(std::move(binary_or_err.get()),
diff --git a/libbacktrace/GetPss.cpp b/libbacktrace/GetPss.cpp
index 09a721d..6d750ea 100644
--- a/libbacktrace/GetPss.cpp
+++ b/libbacktrace/GetPss.cpp
@@ -24,7 +24,7 @@
 
 // This is an extremely simplified version of libpagemap.
 
-#define _BITS(x, offset, bits) (((x) >> offset) & ((1LL << (bits)) - 1))
+#define _BITS(x, offset, bits) (((x) >> (offset)) & ((1LL << (bits)) - 1))
 
 #define PAGEMAP_PRESENT(x)     (_BITS(x, 63, 1))
 #define PAGEMAP_SWAPPED(x)     (_BITS(x, 62, 1))
@@ -33,7 +33,7 @@
 #define PAGEMAP_SWAP_OFFSET(x) (_BITS(x, 5, 50))
 #define PAGEMAP_SWAP_TYPE(x)   (_BITS(x, 0,  5))
 
-static bool ReadData(int fd, unsigned long place, uint64_t *data) {
+static bool ReadData(int fd, off_t place, uint64_t *data) {
   if (lseek(fd, place * sizeof(uint64_t), SEEK_SET) < 0) {
     return false;
   }
@@ -71,12 +71,13 @@
       total_pss = 0;
       break;
     }
-    for (size_t page = start/pagesize; page < end/pagesize; page++) {
+    for (off_t page = static_cast<off_t>(start/pagesize);
+         page < static_cast<off_t>(end/pagesize); page++) {
       uint64_t data;
       if (ReadData(pagemap_fd, page, &data)) {
         if (PAGEMAP_PRESENT(data) && !PAGEMAP_SWAPPED(data)) {
           uint64_t count;
-          if (ReadData(pagecount_fd, PAGEMAP_PFN(data), &count)) {
+          if (ReadData(pagecount_fd, static_cast<off_t>(PAGEMAP_PFN(data)), &count)) {
             total_pss += (count >= 1) ? pagesize / count : 0;
           }
         }
diff --git a/libbacktrace/UnwindMap.h b/libbacktrace/UnwindMap.h
index f85b54a..d5bec06 100644
--- a/libbacktrace/UnwindMap.h
+++ b/libbacktrace/UnwindMap.h
@@ -29,7 +29,7 @@
 
 class UnwindMap : public BacktraceMap {
 public:
-  UnwindMap(pid_t pid);
+  explicit UnwindMap(pid_t pid);
 
   unw_map_cursor_t* GetMapCursor() { return &map_cursor_; }
 
@@ -39,7 +39,7 @@
 
 class UnwindMapRemote : public UnwindMap {
 public:
-  UnwindMapRemote(pid_t pid);
+  explicit UnwindMapRemote(pid_t pid);
   virtual ~UnwindMapRemote();
 
   bool Build() override;
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
index 88a3533..d6dc2c9 100644
--- a/libbacktrace/backtrace_offline_test.cpp
+++ b/libbacktrace/backtrace_offline_test.cpp
@@ -73,7 +73,7 @@
   return ucontext;
 }
 
-static void OfflineBacktraceFunctionCall(std::function<int(void (*)(void*), void*)> function,
+static void OfflineBacktraceFunctionCall(const std::function<int(void (*)(void*), void*)>& function,
                                          std::vector<uintptr_t>* pc_values) {
   // Create a thread to generate the needed stack and registers information.
   g_exit_flag = false;
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 913e12d..e25c8e9 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -414,17 +414,16 @@
   char task_path[128];
   snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
 
-  DIR* tasks_dir = opendir(task_path);
+  std::unique_ptr<DIR, decltype(&closedir)> tasks_dir(opendir(task_path), closedir);
   ASSERT_TRUE(tasks_dir != nullptr);
   struct dirent* entry;
-  while ((entry = readdir(tasks_dir)) != nullptr) {
+  while ((entry = readdir(tasks_dir.get())) != nullptr) {
     char* end;
     pid_t tid = strtoul(entry->d_name, &end, 10);
     if (*end == '\0') {
       threads->push_back(tid);
     }
   }
-  closedir(tasks_dir);
 }
 
 TEST(libbacktrace, ptrace_threads) {
@@ -1422,7 +1421,7 @@
 #if defined(ENABLE_PSS_TESTS)
 #include "GetPss.h"
 
-#define MAX_LEAK_BYTES 32*1024UL
+#define MAX_LEAK_BYTES (32*1024UL)
 
 void CheckForLeak(pid_t pid, pid_t tid) {
   // Do a few runs to get the PSS stable.
@@ -1446,9 +1445,9 @@
   }
   size_t new_pss = GetPssBytes();
   ASSERT_TRUE(new_pss != 0);
-  size_t abs_diff = (new_pss > stable_pss) ? new_pss - stable_pss : stable_pss - new_pss;
-  // As long as the new pss is within a certain amount, consider everything okay.
-  ASSERT_LE(abs_diff, MAX_LEAK_BYTES);
+  if (new_pss > stable_pss) {
+    ASSERT_LE(new_pss - stable_pss, MAX_LEAK_BYTES);
+  }
 }
 
 TEST(libbacktrace, check_for_leak_local) {
diff --git a/libbinderwrapper/Android.mk b/libbinderwrapper/Android.mk
index 23c2246..b38d262 100644
--- a/libbinderwrapper/Android.mk
+++ b/libbinderwrapper/Android.mk
@@ -18,8 +18,8 @@
 
 binderwrapperCommonCFlags := -Wall -Werror -Wno-unused-parameter
 binderwrapperCommonCFlags += -Wno-sign-promo  # for libchrome
-binderwrapperCommonExportCIncludeDirs := $(LOCAL_PATH)/../include
-binderwrapperCommonCIncludes := $(LOCAL_PATH)/../include
+binderwrapperCommonExportCIncludeDirs := $(LOCAL_PATH)/include
+binderwrapperCommonCIncludes := $(LOCAL_PATH)/include
 binderwrapperCommonSharedLibraries := \
   libbinder \
   libchrome \
diff --git a/include/binderwrapper/binder_test_base.h b/libbinderwrapper/include/binderwrapper/binder_test_base.h
similarity index 100%
rename from include/binderwrapper/binder_test_base.h
rename to libbinderwrapper/include/binderwrapper/binder_test_base.h
diff --git a/include/binderwrapper/binder_wrapper.h b/libbinderwrapper/include/binderwrapper/binder_wrapper.h
similarity index 98%
rename from include/binderwrapper/binder_wrapper.h
rename to libbinderwrapper/include/binderwrapper/binder_wrapper.h
index ccda825..a104bff 100644
--- a/include/binderwrapper/binder_wrapper.h
+++ b/libbinderwrapper/include/binderwrapper/binder_wrapper.h
@@ -70,7 +70,7 @@
   // is currently registered for |binder|, it will be replaced.
   virtual bool RegisterForDeathNotifications(
       const sp<IBinder>& binder,
-      const base::Closure& callback) = 0;
+      const ::base::Closure& callback) = 0;
 
   // Unregisters the callback, if any, for |binder|.
   virtual bool UnregisterForDeathNotifications(const sp<IBinder>& binder) = 0;
diff --git a/include/binderwrapper/stub_binder_wrapper.h b/libbinderwrapper/include/binderwrapper/stub_binder_wrapper.h
similarity index 96%
rename from include/binderwrapper/stub_binder_wrapper.h
rename to libbinderwrapper/include/binderwrapper/stub_binder_wrapper.h
index 01c9648..9d4578e 100644
--- a/include/binderwrapper/stub_binder_wrapper.h
+++ b/libbinderwrapper/include/binderwrapper/stub_binder_wrapper.h
@@ -98,7 +98,7 @@
                        const sp<IBinder>& binder) override;
   sp<BBinder> CreateLocalBinder() override;
   bool RegisterForDeathNotifications(const sp<IBinder>& binder,
-                                     const base::Closure& callback) override;
+                                     const ::base::Closure& callback) override;
   bool UnregisterForDeathNotifications(const sp<IBinder>& binder) override;
   uid_t GetCallingUid() override;
   pid_t GetCallingPid() override;
@@ -119,7 +119,7 @@
 
   // Map from binder handle to the callback that should be invoked on binder
   // death.
-  std::map<sp<IBinder>, base::Closure> death_callbacks_;
+  std::map<sp<IBinder>, ::base::Closure> death_callbacks_;
 
   // Values to return from GetCallingUid() and GetCallingPid();
   uid_t calling_uid_;
diff --git a/libbinderwrapper/real_binder_wrapper.cc b/libbinderwrapper/real_binder_wrapper.cc
index 1c51822..f93f183 100644
--- a/libbinderwrapper/real_binder_wrapper.cc
+++ b/libbinderwrapper/real_binder_wrapper.cc
@@ -29,7 +29,7 @@
 // be awkward.
 class RealBinderWrapper::DeathRecipient : public IBinder::DeathRecipient {
  public:
-  explicit DeathRecipient(const base::Closure& callback)
+  explicit DeathRecipient(const ::base::Closure& callback)
       : callback_(callback) {}
   ~DeathRecipient() = default;
 
@@ -40,7 +40,7 @@
 
  private:
   // Callback to run in response to binder death.
-  base::Closure callback_;
+  ::base::Closure callback_;
 
   DISALLOW_COPY_AND_ASSIGN(DeathRecipient);
 };
@@ -85,7 +85,7 @@
 
 bool RealBinderWrapper::RegisterForDeathNotifications(
     const sp<IBinder>& binder,
-    const base::Closure& callback) {
+    const ::base::Closure& callback) {
   sp<DeathRecipient> recipient(new DeathRecipient(callback));
   if (binder->linkToDeath(recipient) != OK) {
     LOG(ERROR) << "Failed to register for death notifications on "
diff --git a/libbinderwrapper/real_binder_wrapper.h b/libbinderwrapper/real_binder_wrapper.h
index ea08371..fa05383 100644
--- a/libbinderwrapper/real_binder_wrapper.h
+++ b/libbinderwrapper/real_binder_wrapper.h
@@ -17,6 +17,8 @@
 #ifndef SYSTEM_CORE_LIBBINDERWRAPPER_REAL_BINDER_WRAPPER_H_
 #define SYSTEM_CORE_LIBBINDERWRAPPER_REAL_BINDER_WRAPPER_H_
 
+#include <map>
+
 #include <base/macros.h>
 #include <binderwrapper/binder_wrapper.h>
 
@@ -36,7 +38,7 @@
                        const sp<IBinder>& binder) override;
   sp<BBinder> CreateLocalBinder() override;
   bool RegisterForDeathNotifications(const sp<IBinder>& binder,
-                                     const base::Closure& callback) override;
+                                     const ::base::Closure& callback) override;
   bool UnregisterForDeathNotifications(const sp<IBinder>& binder) override;
   uid_t GetCallingUid() override;
   pid_t GetCallingPid() override;
diff --git a/libbinderwrapper/stub_binder_wrapper.cc b/libbinderwrapper/stub_binder_wrapper.cc
index 87c6ab7..8e75f62 100644
--- a/libbinderwrapper/stub_binder_wrapper.cc
+++ b/libbinderwrapper/stub_binder_wrapper.cc
@@ -64,7 +64,7 @@
 
 bool StubBinderWrapper::RegisterForDeathNotifications(
     const sp<IBinder>& binder,
-    const base::Closure& callback) {
+    const ::base::Closure& callback) {
   death_callbacks_[binder] = callback;
   return true;
 }
diff --git a/libcrypto_utils/Android.bp b/libcrypto_utils/Android.bp
new file mode 100644
index 0000000..f2560e6
--- /dev/null
+++ b/libcrypto_utils/Android.bp
@@ -0,0 +1,36 @@
+//
+// 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.
+//
+
+cc_library {
+    name: "libcrypto_utils",
+    host_supported: true,
+    srcs: [
+        "android_pubkey.c",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    local_include_dirs: ["include"],
+    export_include_dirs: ["include"],
+    shared_libs: ["libcrypto"],
+    target: {
+        windows: {
+            enabled: true,
+        },
+    },
+}
diff --git a/libcrypto_utils/android_pubkey.c b/libcrypto_utils/android_pubkey.c
new file mode 100644
index 0000000..3052e52
--- /dev/null
+++ b/libcrypto_utils/android_pubkey.c
@@ -0,0 +1,169 @@
+/*
+ * 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 <crypto_utils/android_pubkey.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/bn.h>
+
+// Better safe than sorry.
+#if (ANDROID_PUBKEY_MODULUS_SIZE % 4) != 0
+#error RSA modulus size must be multiple of the word size!
+#endif
+
+// Size of the RSA modulus in words.
+#define ANDROID_PUBKEY_MODULUS_SIZE_WORDS (ANDROID_PUBKEY_MODULUS_SIZE / 4)
+
+// This file implements encoding and decoding logic for Android's custom RSA
+// public key binary format. Public keys are stored as a sequence of
+// little-endian 32 bit words. Note that Android only supports little-endian
+// processors, so we don't do any byte order conversions when parsing the binary
+// struct.
+typedef struct RSAPublicKey {
+    // Modulus length. This must be ANDROID_PUBKEY_MODULUS_SIZE.
+    uint32_t modulus_size_words;
+
+    // Precomputed montgomery parameter: -1 / n[0] mod 2^32
+    uint32_t n0inv;
+
+    // RSA modulus as a little-endian array.
+    uint8_t modulus[ANDROID_PUBKEY_MODULUS_SIZE];
+
+    // Montgomery parameter R^2 as a little-endian array of little-endian words.
+    uint8_t rr[ANDROID_PUBKEY_MODULUS_SIZE];
+
+    // RSA modulus: 3 or 65537
+    uint32_t exponent;
+} RSAPublicKey;
+
+// Reverses byte order in |buffer|.
+static void reverse_bytes(uint8_t* buffer, size_t size) {
+  for (size_t i = 0; i < (size + 1) / 2; ++i) {
+    uint8_t tmp = buffer[i];
+    buffer[i] = buffer[size - i - 1];
+    buffer[size - i - 1] = tmp;
+  }
+}
+
+bool android_pubkey_decode(const uint8_t* key_buffer, size_t size, RSA** key) {
+  const RSAPublicKey* key_struct = (RSAPublicKey*)key_buffer;
+  bool ret = false;
+  uint8_t modulus_buffer[ANDROID_PUBKEY_MODULUS_SIZE];
+  RSA* new_key = RSA_new();
+  if (!new_key) {
+    goto cleanup;
+  }
+
+  // Check |size| is large enough and the modulus size is correct.
+  if (size < sizeof(RSAPublicKey)) {
+    goto cleanup;
+  }
+  if (key_struct->modulus_size_words != ANDROID_PUBKEY_MODULUS_SIZE_WORDS) {
+    goto cleanup;
+  }
+
+  // Convert the modulus to big-endian byte order as expected by BN_bin2bn.
+  memcpy(modulus_buffer, key_struct->modulus, sizeof(modulus_buffer));
+  reverse_bytes(modulus_buffer, sizeof(modulus_buffer));
+  new_key->n = BN_bin2bn(modulus_buffer, sizeof(modulus_buffer), NULL);
+  if (!new_key->n) {
+    goto cleanup;
+  }
+
+  // Read the exponent.
+  new_key->e = BN_new();
+  if (!new_key->e || !BN_set_word(new_key->e, key_struct->exponent)) {
+    goto cleanup;
+  }
+
+  // Note that we don't extract the montgomery parameters n0inv and rr from
+  // the RSAPublicKey structure. They assume a word size of 32 bits, but
+  // BoringSSL may use a word size of 64 bits internally, so we're lacking the
+  // top 32 bits of n0inv in general. For now, we just ignore the parameters
+  // and have BoringSSL recompute them internally. More sophisticated logic can
+  // be added here if/when we want the additional speedup from using the
+  // pre-computed montgomery parameters.
+
+  *key = new_key;
+  ret = true;
+
+cleanup:
+  if (!ret && new_key) {
+    RSA_free(new_key);
+  }
+  return ret;
+}
+
+static bool android_pubkey_encode_bignum(const BIGNUM* num, uint8_t* buffer) {
+  if (!BN_bn2bin_padded(buffer, ANDROID_PUBKEY_MODULUS_SIZE, num)) {
+    return false;
+  }
+
+  reverse_bytes(buffer, ANDROID_PUBKEY_MODULUS_SIZE);
+  return true;
+}
+
+bool android_pubkey_encode(const RSA* key, uint8_t* key_buffer, size_t size) {
+  RSAPublicKey* key_struct = (RSAPublicKey*)key_buffer;
+  bool ret = false;
+  BN_CTX* ctx = BN_CTX_new();
+  BIGNUM* r32 = BN_new();
+  BIGNUM* n0inv = BN_new();
+  BIGNUM* rr = BN_new();
+
+  if (sizeof(RSAPublicKey) > size ||
+      RSA_size(key) != ANDROID_PUBKEY_MODULUS_SIZE) {
+    goto cleanup;
+  }
+
+  // Store the modulus size.
+  key_struct->modulus_size_words = ANDROID_PUBKEY_MODULUS_SIZE_WORDS;
+
+  // Compute and store n0inv = -1 / N[0] mod 2^32.
+  if (!ctx || !r32 || !n0inv || !BN_set_bit(r32, 32) ||
+      !BN_mod(n0inv, key->n, r32, ctx) ||
+      !BN_mod_inverse(n0inv, n0inv, r32, ctx) || !BN_sub(n0inv, r32, n0inv)) {
+    goto cleanup;
+  }
+  key_struct->n0inv = (uint32_t)BN_get_word(n0inv);
+
+  // Store the modulus.
+  if (!android_pubkey_encode_bignum(key->n, key_struct->modulus)) {
+    goto cleanup;
+  }
+
+  // Compute and store rr = (2^(rsa_size)) ^ 2 mod N.
+  if (!ctx || !rr || !BN_set_bit(rr, ANDROID_PUBKEY_MODULUS_SIZE * 8) ||
+      !BN_mod_sqr(rr, rr, key->n, ctx) ||
+      !android_pubkey_encode_bignum(rr, key_struct->rr)) {
+    goto cleanup;
+  }
+
+  // Store the exponent.
+  key_struct->exponent = (uint32_t)BN_get_word(key->e);
+
+  ret = true;
+
+cleanup:
+  BN_free(rr);
+  BN_free(n0inv);
+  BN_free(r32);
+  BN_CTX_free(ctx);
+  return ret;
+}
diff --git a/libcrypto_utils/include/crypto_utils/android_pubkey.h b/libcrypto_utils/include/crypto_utils/android_pubkey.h
new file mode 100644
index 0000000..1045eba
--- /dev/null
+++ b/libcrypto_utils/include/crypto_utils/android_pubkey.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#ifndef CRYPTO_UTILS_ANDROID_PUBKEY_H
+#define CRYPTO_UTILS_ANDROID_PUBKEY_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <openssl/rsa.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Size of an RSA modulus such as an encrypted block or a signature.
+#define ANDROID_PUBKEY_MODULUS_SIZE (2048 / 8)
+
+// Size of an encoded RSA key.
+#define ANDROID_PUBKEY_ENCODED_SIZE \
+  (3 * sizeof(uint32_t) + 2 * ANDROID_PUBKEY_MODULUS_SIZE)
+
+/* Allocates a new RSA |key| object, decodes a public RSA key stored in
+ * Android's custom binary format from |key_buffer| and sets the key parameters
+ * in |key|. |size| specifies the size of the key buffer and must be at least
+ * |ANDROID_PUBKEY_ENCODED_SIZE|. The resulting |*key| can be used with the
+ * standard BoringSSL API to perform public operations.
+ *
+ * Returns true if successful, in which case the caller receives ownership of
+ * the |*key| object, i.e. needs to call RSA_free() when done with it. If there
+ * is an error, |key| is left untouched and the return value will be false.
+ */
+bool android_pubkey_decode(const uint8_t* key_buffer, size_t size, RSA** key);
+
+/* Encodes |key| in the Android RSA public key binary format and stores the
+ * bytes in |key_buffer|. |key_buffer| should be of size at least
+ * |ANDROID_PUBKEY_ENCODED_SIZE|.
+ *
+ * Returns true if successful, false on error.
+ */
+bool android_pubkey_encode(const RSA* key, uint8_t* key_buffer, size_t size);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif  // CRYPTO_UTILS_ANDROID_PUBKEY_H
diff --git a/libmincrypt/tools/Android.mk b/libcrypto_utils/tests/Android.mk
similarity index 69%
rename from libmincrypt/tools/Android.mk
rename to libcrypto_utils/tests/Android.mk
index 3154914..ef3d0cf 100644
--- a/libmincrypt/tools/Android.mk
+++ b/libcrypto_utils/tests/Android.mk
@@ -1,4 +1,5 @@
-# Copyright (C) 2008 The Android Open Source Project
+#
+# 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.
@@ -11,12 +12,13 @@
 # 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.
+#
 
 LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := dumpkey
-LOCAL_SRC_FILES := DumpPublicKey.java
-LOCAL_JAR_MANIFEST := DumpPublicKey.mf
-LOCAL_STATIC_JAVA_LIBRARIES := bouncycastle-host
-include $(BUILD_HOST_JAVA_LIBRARY)
+LOCAL_MODULE := libcrypto_utils_test
+LOCAL_SRC_FILES := android_pubkey_test.cpp
+LOCAL_CFLAGS := -Wall -Werror -Wextra
+LOCAL_SHARED_LIBRARIES := libcrypto_utils libcrypto
+include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libcrypto_utils/tests/android_pubkey_test.cpp b/libcrypto_utils/tests/android_pubkey_test.cpp
new file mode 100644
index 0000000..f8c2e0c
--- /dev/null
+++ b/libcrypto_utils/tests/android_pubkey_test.cpp
@@ -0,0 +1,129 @@
+/*
+ * 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 <crypto_utils/android_pubkey.h>
+
+#include <string.h>
+
+#include <memory>
+
+#include <openssl/obj_mac.h>
+#include <openssl/rsa.h>
+
+#include <gtest/gtest.h>
+
+// Test digest to verify.
+const uint8_t kDigest[] = {
+    0x31, 0x5f, 0x5b, 0xdb, 0x76, 0xd0, 0x78, 0xc4, 0x3b, 0x8a, 0xc0,
+    0x06, 0x4e, 0x4a, 0x01, 0x64, 0x61, 0x2b, 0x1f, 0xce, 0x77, 0xc8,
+    0x69, 0x34, 0x5b, 0xfc, 0x94, 0xc7, 0x58, 0x94, 0xed, 0xd3,
+};
+
+// 2048 RSA test key.
+const uint8_t kKey2048[ANDROID_PUBKEY_ENCODED_SIZE] = {
+    0x40, 0x00, 0x00, 0x00, 0x05, 0x75, 0x61, 0xd1, 0x33, 0xf0, 0x2d, 0x12,
+    0x45, 0xfb, 0xae, 0x07, 0x02, 0x15, 0x4f, 0x3a, 0x2b, 0xa3, 0xbc, 0x49,
+    0xbd, 0x14, 0x07, 0xa0, 0xc0, 0x9f, 0x0c, 0x52, 0x60, 0x77, 0x9f, 0xa2,
+    0x31, 0xd0, 0xa7, 0xfb, 0x7e, 0xde, 0xfb, 0xc9, 0x05, 0xc0, 0x97, 0xf7,
+    0x74, 0x99, 0xe6, 0xd1, 0x08, 0xa6, 0xc2, 0x59, 0x5a, 0xd8, 0x37, 0x1d,
+    0xe0, 0x48, 0x5e, 0x63, 0x44, 0x04, 0x8b, 0x05, 0x20, 0xf6, 0x25, 0x67,
+    0x38, 0xb2, 0xb6, 0xf9, 0xbe, 0xb6, 0x1d, 0x7f, 0x1b, 0x71, 0x8a, 0xeb,
+    0xb7, 0xf8, 0x01, 0xc1, 0x5e, 0xf7, 0xfe, 0x48, 0x08, 0x27, 0x0f, 0x27,
+    0x2a, 0x64, 0x1a, 0x43, 0x8d, 0xcf, 0x5a, 0x33, 0x5c, 0x18, 0xc5, 0xf4,
+    0xe7, 0xfe, 0xee, 0xd3, 0x12, 0x62, 0xad, 0x61, 0x78, 0x9a, 0x03, 0xb0,
+    0xaf, 0xab, 0x91, 0x57, 0x46, 0xbf, 0x18, 0xc6, 0xbc, 0x0c, 0x6b, 0x55,
+    0xcd, 0xda, 0xc4, 0xcc, 0x98, 0x46, 0x91, 0x99, 0xbc, 0xa3, 0xca, 0x6c,
+    0x86, 0xa6, 0x1c, 0x8f, 0xca, 0xf8, 0xf6, 0x8a, 0x00, 0x8e, 0x05, 0xd7,
+    0x13, 0x43, 0xe2, 0xf2, 0x1a, 0x13, 0xf3, 0x50, 0x13, 0xa4, 0xf2, 0x4e,
+    0x41, 0xb1, 0x36, 0x78, 0x55, 0x4c, 0x5e, 0x27, 0xc5, 0xc0, 0x4b, 0xd8,
+    0x93, 0xaa, 0x7e, 0xf0, 0x90, 0x08, 0x10, 0x26, 0x72, 0x6d, 0xb9, 0x21,
+    0xae, 0x4d, 0x01, 0x4b, 0x55, 0x1d, 0xe7, 0x1e, 0x5e, 0x31, 0x6e, 0x62,
+    0xd1, 0x33, 0x26, 0xcb, 0xdb, 0xfe, 0x72, 0x98, 0xc8, 0x06, 0x1c, 0x12,
+    0xdf, 0xfc, 0x74, 0xe5, 0x7a, 0x6f, 0xf5, 0xa3, 0x63, 0x08, 0xe3, 0x02,
+    0x68, 0x4d, 0x7c, 0x70, 0x05, 0xec, 0x95, 0x7e, 0x24, 0xa4, 0xbc, 0x4c,
+    0xcd, 0x39, 0x14, 0xb5, 0x2a, 0x8f, 0xc1, 0xe3, 0x4e, 0xfa, 0xf8, 0x70,
+    0x50, 0x8f, 0xd5, 0x8e, 0xc7, 0xb5, 0x32, 0x89, 0x4d, 0xbb, 0x6a, 0xc1,
+    0xc1, 0xa2, 0x42, 0x57, 0x57, 0xbd, 0x2a, 0xdc, 0xa6, 0xfd, 0xc8, 0x86,
+    0x44, 0x6a, 0x03, 0x5d, 0x4d, 0x28, 0xe1, 0xde, 0xb4, 0xa9, 0xa5, 0x03,
+    0x61, 0x7a, 0x5f, 0xb1, 0x09, 0x17, 0x2b, 0x9c, 0xa2, 0x54, 0x28, 0xad,
+    0x34, 0xc9, 0x5f, 0x6c, 0x9f, 0xb8, 0xd2, 0xa9, 0x78, 0xa7, 0xaa, 0xb3,
+    0x11, 0x2f, 0x65, 0x9b, 0x4e, 0x67, 0x0c, 0xcc, 0x20, 0x36, 0xbf, 0x26,
+    0x2b, 0x4e, 0xc0, 0xd4, 0xbd, 0x22, 0x64, 0xc4, 0x1c, 0x56, 0x69, 0xdb,
+    0x5f, 0x89, 0xe1, 0x75, 0x68, 0x8d, 0x0e, 0xab, 0x1c, 0x10, 0x1a, 0xc0,
+    0x12, 0x5d, 0x6f, 0xbd, 0x09, 0xbb, 0x47, 0xcb, 0xe7, 0x34, 0xef, 0x56,
+    0xab, 0xea, 0xc3, 0xe9, 0x7f, 0x9a, 0x3d, 0xe9, 0x2d, 0x14, 0x61, 0x25,
+    0x37, 0x5c, 0x3b, 0x4b, 0xaf, 0x5a, 0x4b, 0xc8, 0x99, 0x1a, 0x32, 0x8f,
+    0x54, 0x07, 0xd3, 0x57, 0x8a, 0x3d, 0x2a, 0xf7, 0x9e, 0x7e, 0x92, 0x2a,
+    0x50, 0xe9, 0xd8, 0xdb, 0xd6, 0x03, 0xd3, 0x8e, 0x54, 0x32, 0xce, 0x87,
+    0x93, 0x92, 0xe7, 0x75, 0xe1, 0x6b, 0x78, 0x1a, 0x85, 0xc2, 0x46, 0xa1,
+    0x31, 0xbb, 0xc7, 0xb9, 0x1d, 0xd1, 0x71, 0xe0, 0xe2, 0x9b, 0x9c, 0x0d,
+    0xa3, 0xcf, 0x93, 0x4d, 0x87, 0x7b, 0x65, 0xd9, 0xda, 0x4c, 0xd9, 0x6a,
+    0xa6, 0x36, 0xc2, 0xc7, 0xe3, 0x33, 0xe2, 0xc3, 0x83, 0xd1, 0x72, 0x54,
+    0x30, 0x81, 0x5e, 0x34, 0x2c, 0x61, 0xee, 0xf4, 0x48, 0x97, 0xb6, 0xaa,
+    0x47, 0x6a, 0x05, 0x09, 0xd8, 0x4d, 0x90, 0xaf, 0xa8, 0x4e, 0x82, 0xe4,
+    0x8e, 0xb5, 0xe2, 0x65, 0x86, 0x67, 0xe9, 0x5b, 0x4b, 0x9a, 0x68, 0x08,
+    0x30, 0xf6, 0x25, 0x8b, 0x20, 0xda, 0x26, 0x6f, 0xbd, 0x0d, 0xa5, 0xd8,
+    0x6a, 0x7b, 0x01, 0x2f, 0xab, 0x7b, 0xb5, 0xfe, 0x62, 0x37, 0x2d, 0x94,
+    0x43, 0x2f, 0x4d, 0x16, 0x01, 0x00, 0x01, 0x00,
+};
+
+// 2048 bit RSA signature.
+const uint8_t kSignature2048[ANDROID_PUBKEY_MODULUS_SIZE] = {
+    0x3a, 0x11, 0x84, 0x40, 0xc1, 0x2f, 0x13, 0x8c, 0xde, 0xb0, 0xc3, 0x89,
+    0x8a, 0x63, 0xb2, 0x50, 0x93, 0x58, 0xc0, 0x0c, 0xb7, 0x08, 0xe7, 0x6c,
+    0x52, 0x87, 0x4e, 0x78, 0x89, 0xa3, 0x9a, 0x47, 0xeb, 0x11, 0x57, 0xbc,
+    0xb3, 0x97, 0xf8, 0x34, 0xf1, 0xf7, 0xbf, 0x3a, 0xfa, 0x1c, 0x6b, 0xdc,
+    0xd1, 0x02, 0xde, 0x9a, 0x0d, 0x72, 0xe7, 0x19, 0x63, 0x81, 0x46, 0x68,
+    0x1e, 0x63, 0x64, 0xc6, 0x59, 0xe7, 0x7c, 0x39, 0xed, 0x32, 0xd2, 0xd1,
+    0xd5, 0x1f, 0x13, 0x9b, 0x52, 0xdf, 0x34, 0xa3, 0xc0, 0xc4, 0x9a, 0x63,
+    0x9b, 0x9c, 0xbe, 0x22, 0xc8, 0xd8, 0x14, 0x2f, 0x4c, 0x78, 0x36, 0xdb,
+    0x16, 0x41, 0x67, 0xc1, 0x21, 0x8a, 0x73, 0xb2, 0xe5, 0xb0, 0xd3, 0x80,
+    0x91, 0x7a, 0xbf, 0xf9, 0x59, 0x4a, 0x4d, 0x78, 0x45, 0x44, 0xa1, 0x52,
+    0x86, 0x29, 0x48, 0x4d, 0xf0, 0x5d, 0xf2, 0x55, 0xa7, 0xcd, 0xc5, 0x2b,
+    0x7b, 0xe0, 0xb1, 0xf6, 0x2a, 0xd5, 0x61, 0xba, 0x1e, 0x1e, 0x3a, 0xf0,
+    0x55, 0xbc, 0x8c, 0x44, 0x41, 0xfc, 0xb8, 0x8c, 0x76, 0xbf, 0x80, 0x58,
+    0x82, 0x35, 0x4b, 0x0c, 0xfd, 0xef, 0xd5, 0x70, 0xd1, 0x64, 0xcb, 0x46,
+    0x58, 0x37, 0xbc, 0xa9, 0x7d, 0xd4, 0x70, 0xac, 0xce, 0xec, 0xca, 0x48,
+    0xcb, 0x0a, 0x40, 0x77, 0x04, 0x59, 0xca, 0x9c, 0x7d, 0x1a, 0x0b, 0xf0,
+    0xb5, 0xdd, 0xde, 0x71, 0x18, 0xb8, 0xef, 0x90, 0x2a, 0x09, 0x42, 0x39,
+    0x74, 0xff, 0x45, 0xa1, 0x39, 0x17, 0x50, 0x89, 0xa6, 0x5f, 0xbc, 0x9c,
+    0x0c, 0x9b, 0x47, 0x25, 0x79, 0x3e, 0xe3, 0xaa, 0xaf, 0xbe, 0x73, 0x6b,
+    0xcb, 0xe7, 0x35, 0xc1, 0x27, 0x09, 0xcd, 0xeb, 0xd7, 0xcf, 0x63, 0x83,
+    0x64, 0x8c, 0x45, 0x1c, 0x1d, 0x58, 0xcc, 0xd2, 0xf8, 0x2b, 0x4c, 0x4e,
+    0x14, 0x89, 0x2d, 0x70,
+};
+
+struct AndroidPubkeyTest : public ::testing::Test {
+  void SetUp() override {
+    RSA* new_key = nullptr;
+    ASSERT_TRUE(android_pubkey_decode(kKey2048, sizeof(kKey2048), &new_key));
+    key_.reset(new_key);
+  }
+
+  std::unique_ptr<RSA, void(*)(RSA*)> key_ = {nullptr, RSA_free};
+};
+
+TEST_F(AndroidPubkeyTest, Decode) {
+  // Make sure the decoded key successfully verifies a valid signature.
+  EXPECT_TRUE(RSA_verify(NID_sha256, kDigest, sizeof(kDigest), kSignature2048,
+                         sizeof(kSignature2048), key_.get()));
+}
+
+TEST_F(AndroidPubkeyTest, Encode) {
+  uint8_t key_data[ANDROID_PUBKEY_ENCODED_SIZE];
+  ASSERT_TRUE(android_pubkey_encode(key_.get(), key_data, sizeof(key_data)));
+  ASSERT_EQ(0, memcmp(kKey2048, key_data, sizeof(kKey2048)));
+}
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
new file mode 100644
index 0000000..39f8aba
--- /dev/null
+++ b/libcutils/Android.bp
@@ -0,0 +1,144 @@
+//
+// Copyright (C) 2008 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// some files must not be compiled when building against Mingw
+// they correspond to features not used by our host development tools
+// which are also hard or even impossible to port to native Win32
+libcutils_nonwindows_sources = [
+    "android_get_control_file.cpp",
+    "fs.c",
+    "multiuser.c",
+    "socket_inaddr_any_server_unix.c",
+    "socket_local_client_unix.c",
+    "socket_local_server_unix.c",
+    "socket_loopback_server_unix.c",
+    "socket_network_client_unix.c",
+    "sockets_unix.cpp",
+    "str_parms.c",
+]
+
+cc_library {
+    name: "libcutils",
+    host_supported: true,
+    srcs: [
+        "config_utils.c",
+        "fs_config.c",
+        "canned_fs_config.c",
+        "hashmap.c",
+        "iosched_policy.c",
+        "load_file.c",
+        "native_handle.c",
+        "open_memstream.c",
+        "record_stream.c",
+        "sched_policy.c",
+        "sockets.cpp",
+        "strdup16to8.c",
+        "strdup8to16.c",
+        "strlcpy.c",
+        "threads.c",
+    ],
+
+    target: {
+        host: {
+            srcs: ["dlmalloc_stubs.c"],
+        },
+        not_windows: {
+            srcs: libcutils_nonwindows_sources + [
+                "ashmem-host.c",
+                "trace-host.c",
+            ],
+        },
+        windows: {
+            srcs: [
+                "socket_inaddr_any_server_windows.c",
+                "socket_network_client_windows.c",
+                "sockets_windows.cpp",
+            ],
+
+            enabled: true,
+            shared: {
+                enabled: false,
+            },
+        },
+
+        android: {
+            srcs: libcutils_nonwindows_sources + [
+                "android_reboot.c",
+                "ashmem-dev.c",
+                "debugger.c",
+                "klog.cpp",
+                "partition_utils.c",
+                "properties.c",
+                "qtaguid.c",
+                "trace-dev.c",
+                "uevent.c",
+            ],
+
+            static_libs: ["libdebuggerd_client"],
+            export_static_lib_headers: ["libdebuggerd_client"],
+        },
+
+        android_arm: {
+            srcs: ["arch-arm/memset32.S"],
+        },
+        android_arm64: {
+            srcs: ["arch-arm64/android_memset.S"],
+        },
+
+        android_mips: {
+            srcs: ["arch-mips/android_memset.c"],
+        },
+        android_mips64: {
+            srcs: ["arch-mips/android_memset.c"],
+        },
+
+        android_x86: {
+            srcs: [
+                "arch-x86/android_memset16.S",
+                "arch-x86/android_memset32.S",
+            ],
+        },
+
+        android_x86_64: {
+            srcs: [
+                "arch-x86_64/android_memset16.S",
+                "arch-x86_64/android_memset32.S",
+            ],
+        },
+    },
+
+    shared_libs: ["liblog"],
+    product_variables: {
+        cpusets: {
+            cflags: ["-DUSE_CPUSETS"],
+        },
+        schedboost: {
+            cflags: ["-DUSE_SCHEDBOOST"],
+        },
+    },
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-Wextra",
+    ],
+
+    clang: true,
+    sanitize: {
+        misc_undefined: ["integer"],
+    },
+}
+
+subdirs = ["tests"]
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
deleted file mode 100644
index 0c6e5a1..0000000
--- a/libcutils/Android.mk
+++ /dev/null
@@ -1,151 +0,0 @@
-#
-# Copyright (C) 2008 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-LOCAL_PATH := $(my-dir)
-include $(CLEAR_VARS)
-
-libcutils_common_sources := \
-        atomic.c.arm \
-        config_utils.c \
-        fs_config.c \
-        canned_fs_config.c \
-        hashmap.c \
-        iosched_policy.c \
-        load_file.c \
-        native_handle.c \
-        open_memstream.c \
-        process_name.c \
-        record_stream.c \
-        sched_policy.c \
-        sockets.cpp \
-        strdup16to8.c \
-        strdup8to16.c \
-        strlcpy.c \
-        threads.c \
-
-# some files must not be compiled when building against Mingw
-# they correspond to features not used by our host development tools
-# which are also hard or even impossible to port to native Win32
-libcutils_nonwindows_sources := \
-        fs.c \
-        multiuser.c \
-        socket_inaddr_any_server_unix.c \
-        socket_local_client_unix.c \
-        socket_local_server_unix.c \
-        socket_loopback_client_unix.c \
-        socket_loopback_server_unix.c \
-        socket_network_client_unix.c \
-        sockets_unix.cpp \
-        str_parms.c \
-
-libcutils_nonwindows_host_sources := \
-        ashmem-host.c \
-        trace-host.c \
-
-libcutils_windows_host_sources := \
-        socket_inaddr_any_server_windows.c \
-        socket_network_client_windows.c \
-        sockets_windows.cpp \
-
-# Shared and static library for host
-# Note: when linking this library on Windows, you must also link to Winsock2
-# using "LOCAL_LDLIBS_windows := -lws2_32".
-# ========================================================
-LOCAL_MODULE := libcutils
-LOCAL_SRC_FILES := $(libcutils_common_sources) dlmalloc_stubs.c
-LOCAL_SRC_FILES_darwin := $(libcutils_nonwindows_sources) $(libcutils_nonwindows_host_sources)
-LOCAL_SRC_FILES_linux := $(libcutils_nonwindows_sources) $(libcutils_nonwindows_host_sources)
-LOCAL_SRC_FILES_windows := $(libcutils_windows_host_sources)
-LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_CFLAGS := -Werror -Wall -Wextra
-LOCAL_MULTILIB := both
-LOCAL_MODULE_HOST_OS := darwin linux windows
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libcutils
-LOCAL_SRC_FILES := $(libcutils_common_sources) dlmalloc_stubs.c
-LOCAL_SRC_FILES_darwin := $(libcutils_nonwindows_sources) $(libcutils_nonwindows_host_sources)
-LOCAL_SRC_FILES_linux := $(libcutils_nonwindows_sources) $(libcutils_nonwindows_host_sources)
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_CFLAGS := -Werror -Wall -Wextra
-LOCAL_MULTILIB := both
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-
-
-# Shared and static library for target
-# ========================================================
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libcutils
-LOCAL_SRC_FILES := $(libcutils_common_sources) \
-        $(libcutils_nonwindows_sources) \
-        android_reboot.c \
-        ashmem-dev.c \
-        debugger.c \
-        klog.c \
-        partition_utils.c \
-        properties.c \
-        qtaguid.c \
-        trace-dev.c \
-        uevent.c \
-
-LOCAL_SRC_FILES_arm += arch-arm/memset32.S
-LOCAL_SRC_FILES_arm64 += arch-arm64/android_memset.S
-
-LOCAL_SRC_FILES_mips += arch-mips/android_memset.c
-LOCAL_SRC_FILES_mips64 += arch-mips/android_memset.c
-
-LOCAL_SRC_FILES_x86 += \
-        arch-x86/android_memset16.S \
-        arch-x86/android_memset32.S \
-
-LOCAL_SRC_FILES_x86_64 += \
-        arch-x86_64/android_memset16.S \
-        arch-x86_64/android_memset32.S \
-
-LOCAL_C_INCLUDES := $(libcutils_c_includes)
-LOCAL_STATIC_LIBRARIES := liblog
-ifneq ($(ENABLE_CPUSETS),)
-LOCAL_CFLAGS += -DUSE_CPUSETS
-endif
-ifneq ($(ENABLE_SCHEDBOOST),)
-LOCAL_CFLAGS += -DUSE_SCHEDBOOST
-endif
-LOCAL_CFLAGS += -Werror -Wall -Wextra -std=gnu90
-LOCAL_CLANG := true
-LOCAL_SANITIZE := integer
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libcutils
-# TODO: remove liblog as whole static library, once we don't have prebuilt that requires
-# liblog symbols present in libcutils.
-LOCAL_WHOLE_STATIC_LIBRARIES := libcutils liblog
-LOCAL_SHARED_LIBRARIES := liblog
-ifneq ($(ENABLE_CPUSETS),)
-LOCAL_CFLAGS += -DUSE_CPUSETS
-endif
-ifneq ($(ENABLE_SCHEDBOOST),)
-LOCAL_CFLAGS += -DUSE_SCHEDBOOST
-endif
-LOCAL_CFLAGS += -Werror -Wall -Wextra
-LOCAL_C_INCLUDES := $(libcutils_c_includes)
-LOCAL_CLANG := true
-LOCAL_SANITIZE := integer
-include $(BUILD_SHARED_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libcutils/android_get_control_env.h b/libcutils/android_get_control_env.h
new file mode 100644
index 0000000..638c831
--- /dev/null
+++ b/libcutils/android_get_control_env.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#ifndef __CUTILS_ANDROID_GET_CONTROL_ENV_H
+#define __CUTILS_ANDROID_GET_CONTROL_ENV_H
+
+/* To declare library function hidden and internal */
+#define LIBCUTILS_HIDDEN __attribute__((visibility("hidden")))
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBCUTILS_HIDDEN int __android_get_control_from_env(const char* prefix,
+                                                    const char* name);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_ANDROID_GET_CONTROL_ENV_H */
diff --git a/libcutils/android_get_control_file.cpp b/libcutils/android_get_control_file.cpp
new file mode 100644
index 0000000..780d9f1
--- /dev/null
+++ b/libcutils/android_get_control_file.cpp
@@ -0,0 +1,113 @@
+/*
+ * 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 <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cutils/android_get_control_file.h>
+
+#include "android_get_control_env.h"
+
+#ifndef TEMP_FAILURE_RETRY
+#define TEMP_FAILURE_RETRY(exp) (exp) // KISS implementation
+#endif
+
+LIBCUTILS_HIDDEN int __android_get_control_from_env(const char* prefix,
+                                                    const char* name) {
+    if (!prefix || !name) return -1;
+
+    char *key = NULL;
+    if (asprintf(&key, "%s%s", prefix, name) < 0) return -1;
+    if (!key) return -1;
+
+    char *cp = key;
+    while (*cp) {
+        if (!isalnum(*cp)) *cp = '_';
+        ++cp;
+    }
+
+    const char* val = getenv(key);
+    free(key);
+    if (!val) return -1;
+
+    errno = 0;
+    long fd = strtol(val, NULL, 10);
+    if (errno) return -1;
+
+    // validity checking
+    if ((fd < 0) || (fd > INT_MAX)) return -1;
+
+    // Since we are inheriting an fd, it could legitimately exceed _SC_OPEN_MAX
+
+    // Still open?
+#if defined(F_GETFD) // Lowest overhead
+    if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD)) < 0) return -1;
+#elif defined(F_GETFL) // Alternate lowest overhead
+    if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL)) < 0) return -1;
+#else // Hail Mary pass
+    struct stat s;
+    if (TEMP_FAILURE_RETRY(fstat(fd, &s)) < 0) return -1;
+#endif
+
+    return static_cast<int>(fd);
+}
+
+int android_get_control_file(const char* path) {
+    int fd = __android_get_control_from_env(ANDROID_FILE_ENV_PREFIX, path);
+
+#if defined(__linux__)
+    // Find file path from /proc and make sure it is correct
+    char *proc = NULL;
+    if (asprintf(&proc, "/proc/self/fd/%d", fd) < 0) return -1;
+    if (!proc) return -1;
+
+    size_t len = strlen(path);
+    // readlink() does not guarantee a nul byte, len+2 so we catch truncation.
+    char *buf = static_cast<char *>(calloc(1, len + 2));
+    if (!buf) {
+        free(proc);
+        return -1;
+    }
+    ssize_t ret = TEMP_FAILURE_RETRY(readlink(proc, buf, len + 1));
+    free(proc);
+    int cmp = (len != static_cast<size_t>(ret)) || strcmp(buf, path);
+    free(buf);
+    if (ret < 0) return -1;
+    if (cmp != 0) return -1;
+    // It is what we think it is
+#endif
+
+    return fd;
+}
diff --git a/libcutils/ashmem-dev.c b/libcutils/ashmem-dev.c
index 4a07d66..db4ed11 100644
--- a/libcutils/ashmem-dev.c
+++ b/libcutils/ashmem-dev.c
@@ -23,6 +23,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <linux/ashmem.h>
 #include <pthread.h>
 #include <string.h>
 #include <sys/ioctl.h>
@@ -30,10 +31,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <linux/ashmem.h>
-
+#include <android/log.h>
 #include <cutils/ashmem.h>
-#include <log/log.h>
 
 #define ASHMEM_DEVICE "/dev/ashmem"
 
@@ -85,7 +84,7 @@
 }
 
 /* Make sure file descriptor references ashmem, negative number means false */
-static int __ashmem_is_ashmem(int fd)
+static int __ashmem_is_ashmem(int fd, int fatal)
 {
     dev_t rdev;
     struct stat st;
@@ -117,22 +116,29 @@
         }
     }
 
-    if (rdev) {
-        LOG_ALWAYS_FATAL("illegal fd=%d mode=0%o rdev=%d:%d expected 0%o %d:%d",
-          fd, st.st_mode, major(st.st_rdev), minor(st.st_rdev),
-          S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IRGRP,
-          major(rdev), minor(rdev));
-    } else {
-        LOG_ALWAYS_FATAL("illegal fd=%d mode=0%o rdev=%d:%d expected 0%o",
-          fd, st.st_mode, major(st.st_rdev), minor(st.st_rdev),
-          S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IRGRP);
+    if (fatal) {
+        if (rdev) {
+            LOG_ALWAYS_FATAL("illegal fd=%d mode=0%o rdev=%d:%d expected 0%o %d:%d",
+              fd, st.st_mode, major(st.st_rdev), minor(st.st_rdev),
+              S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IRGRP,
+              major(rdev), minor(rdev));
+        } else {
+            LOG_ALWAYS_FATAL("illegal fd=%d mode=0%o rdev=%d:%d expected 0%o",
+              fd, st.st_mode, major(st.st_rdev), minor(st.st_rdev),
+              S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IRGRP);
+        }
+        /* NOTREACHED */
     }
-    /* NOTREACHED */
 
     errno = ENOTTY;
     return -1;
 }
 
+int ashmem_valid(int fd)
+{
+    return __ashmem_is_ashmem(fd, 0) >= 0;
+}
+
 /*
  * ashmem_create_region - creates a new ashmem region and returns the file
  * descriptor, or <0 on error
@@ -175,7 +181,7 @@
 
 int ashmem_set_prot_region(int fd, int prot)
 {
-    int ret = __ashmem_is_ashmem(fd);
+    int ret = __ashmem_is_ashmem(fd, 1);
     if (ret < 0) {
         return ret;
     }
@@ -187,7 +193,7 @@
 {
     struct ashmem_pin pin = { offset, len };
 
-    int ret = __ashmem_is_ashmem(fd);
+    int ret = __ashmem_is_ashmem(fd, 1);
     if (ret < 0) {
         return ret;
     }
@@ -199,7 +205,7 @@
 {
     struct ashmem_pin pin = { offset, len };
 
-    int ret = __ashmem_is_ashmem(fd);
+    int ret = __ashmem_is_ashmem(fd, 1);
     if (ret < 0) {
         return ret;
     }
@@ -209,7 +215,7 @@
 
 int ashmem_get_size_region(int fd)
 {
-    int ret = __ashmem_is_ashmem(fd);
+    int ret = __ashmem_is_ashmem(fd, 1);
     if (ret < 0) {
         return ret;
     }
diff --git a/libcutils/ashmem-host.c b/libcutils/ashmem-host.c
index c85f06b..1f9f753 100644
--- a/libcutils/ashmem-host.c
+++ b/libcutils/ashmem-host.c
@@ -62,12 +62,12 @@
 
 int ashmem_pin_region(int fd __unused, size_t offset __unused, size_t len __unused)
 {
-    return ASHMEM_NOT_PURGED;
+    return 0 /*ASHMEM_NOT_PURGED*/;
 }
 
 int ashmem_unpin_region(int fd __unused, size_t offset __unused, size_t len __unused)
 {
-    return ASHMEM_IS_UNPINNED;
+    return 0 /*ASHMEM_IS_UNPINNED*/;
 }
 
 int ashmem_get_size_region(int fd)
diff --git a/libcutils/atomic.c b/libcutils/atomic.c
deleted file mode 100644
index d34aa00..0000000
--- a/libcutils/atomic.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Generate non-inlined versions of android_atomic functions.
- * Nobody should be using these, but some binary blobs currently (late 2014)
- * are.
- * If you read this in 2015 or later, please try to delete this file.
- */
-
-#define ANDROID_ATOMIC_INLINE
-
-#include <cutils/atomic.h>
diff --git a/libcutils/canned_fs_config.c b/libcutils/canned_fs_config.c
index 5800857..e0e6a34 100644
--- a/libcutils/canned_fs_config.c
+++ b/libcutils/canned_fs_config.c
@@ -14,22 +14,22 @@
  * limitations under the License.
  */
 
-#include <inttypes.h>
-#include <stdio.h>
-#include <string.h>
 #include <errno.h>
+#include <inttypes.h>
 #include <limits.h>
+#include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include <private/android_filesystem_config.h>
 #include <private/canned_fs_config.h>
 
 typedef struct {
-	const char* path;
-	unsigned uid;
-	unsigned gid;
-	unsigned mode;
-	uint64_t capabilities;
+    const char* path;
+    unsigned uid;
+    unsigned gid;
+    unsigned mode;
+    uint64_t capabilities;
 } Path;
 
 static Path* canned_data = NULL;
@@ -37,81 +37,87 @@
 static int canned_used = 0;
 
 static int path_compare(const void* a, const void* b) {
-	return strcmp(((Path*)a)->path, ((Path*)b)->path);
+    return strcmp(((Path*)a)->path, ((Path*)b)->path);
 }
 
 int load_canned_fs_config(const char* fn) {
-	FILE* f = fopen(fn, "r");
-	if (f == NULL) {
-		fprintf(stderr, "failed to open %s: %s\n", fn, strerror(errno));
-		return -1;
-	}
+    char line[PATH_MAX + 200];
+    FILE* f;
 
-	char line[PATH_MAX + 200];
-	while (fgets(line, sizeof(line), f)) {
-		while (canned_used >= canned_alloc) {
-			canned_alloc = (canned_alloc+1) * 2;
-			canned_data = (Path*) realloc(canned_data, canned_alloc * sizeof(Path));
-		}
-		Path* p = canned_data + canned_used;
-		p->path = strdup(strtok(line, " "));
-		p->uid = atoi(strtok(NULL, " "));
-		p->gid = atoi(strtok(NULL, " "));
-		p->mode = strtol(strtok(NULL, " "), NULL, 8);   // mode is in octal
-		p->capabilities = 0;
+    f = fopen(fn, "r");
+    if (f == NULL) {
+        fprintf(stderr, "failed to open %s: %s\n", fn, strerror(errno));
+        return -1;
+    }
 
-		char* token = NULL;
-		do {
-			token = strtok(NULL, " ");
-			if (token && strncmp(token, "capabilities=", 13) == 0) {
-				p->capabilities = strtoll(token+13, NULL, 0);
-				break;
-			}
-		} while (token);
+    while (fgets(line, sizeof(line), f)) {
+        Path* p;
+        char* token;
 
-		canned_used++;
-	}
+        while (canned_used >= canned_alloc) {
+            canned_alloc = (canned_alloc+1) * 2;
+            canned_data = (Path*) realloc(canned_data, canned_alloc * sizeof(Path));
+        }
+        p = canned_data + canned_used;
+        p->path = strdup(strtok(line, " "));
+        p->uid = atoi(strtok(NULL, " "));
+        p->gid = atoi(strtok(NULL, " "));
+        p->mode = strtol(strtok(NULL, " "), NULL, 8);   // mode is in octal
+        p->capabilities = 0;
 
-	fclose(f);
+        do {
+            token = strtok(NULL, " ");
+            if (token && strncmp(token, "capabilities=", 13) == 0) {
+                p->capabilities = strtoll(token+13, NULL, 0);
+                break;
+            }
+        } while (token);
 
-	qsort(canned_data, canned_used, sizeof(Path), path_compare);
-	printf("loaded %d fs_config entries\n", canned_used);
+        canned_used++;
+    }
 
-	return 0;
+    fclose(f);
+
+    qsort(canned_data, canned_used, sizeof(Path), path_compare);
+    printf("loaded %d fs_config entries\n", canned_used);
+
+    return 0;
 }
 
 static const int kDebugCannedFsConfig = 0;
 
 void canned_fs_config(const char* path, int dir, const char* target_out_path,
-					  unsigned* uid, unsigned* gid, unsigned* mode, uint64_t* capabilities) {
-	Path key;
+                      unsigned* uid, unsigned* gid, unsigned* mode, uint64_t* capabilities) {
+    Path key, *p;
+
     key.path = path;
-    if (path[0] == '/')
-        key.path++;   // canned paths lack the leading '/'
-	Path* p = (Path*) bsearch(&key, canned_data, canned_used, sizeof(Path), path_compare);
-	if (p == NULL) {
-		fprintf(stderr, "failed to find [%s] in canned fs_config\n", path);
-		exit(1);
-	}
-	*uid = p->uid;
-	*gid = p->gid;
-	*mode = p->mode;
-	*capabilities = p->capabilities;
+    if (path[0] == '/') key.path++; // canned paths lack the leading '/'
+    p = (Path*) bsearch(&key, canned_data, canned_used, sizeof(Path), path_compare);
+    if (p == NULL) {
+        fprintf(stderr, "failed to find [%s] in canned fs_config\n", path);
+        exit(1);
+    }
+    *uid = p->uid;
+    *gid = p->gid;
+    *mode = p->mode;
+    *capabilities = p->capabilities;
 
-	if (kDebugCannedFsConfig) {
-		// for debugging, run the built-in fs_config and compare the results.
+    if (kDebugCannedFsConfig) {
+        // for debugging, run the built-in fs_config and compare the results.
 
-		unsigned c_uid, c_gid, c_mode;
-		uint64_t c_capabilities;
-		fs_config(path, dir, target_out_path, &c_uid, &c_gid, &c_mode, &c_capabilities);
+        unsigned c_uid, c_gid, c_mode;
+        uint64_t c_capabilities;
 
-		if (c_uid != *uid) printf("%s uid %d %d\n", path, *uid, c_uid);
-		if (c_gid != *gid) printf("%s gid %d %d\n", path, *gid, c_gid);
-		if (c_mode != *mode) printf("%s mode 0%o 0%o\n", path, *mode, c_mode);
-		if (c_capabilities != *capabilities)
-			printf("%s capabilities %" PRIx64 " %" PRIx64 "\n",
-				path,
-				*capabilities,
-				c_capabilities);
+        fs_config(path, dir, target_out_path, &c_uid, &c_gid, &c_mode, &c_capabilities);
+
+        if (c_uid != *uid) printf("%s uid %d %d\n", path, *uid, c_uid);
+        if (c_gid != *gid) printf("%s gid %d %d\n", path, *gid, c_gid);
+        if (c_mode != *mode) printf("%s mode 0%o 0%o\n", path, *mode, c_mode);
+        if (c_capabilities != *capabilities) {
+            printf("%s capabilities %" PRIx64 " %" PRIx64 "\n",
+                path,
+                *capabilities,
+                c_capabilities);
         }
+    }
 }
diff --git a/libcutils/debugger.c b/libcutils/debugger.c
index 3407ec3..c6bdd1a 100644
--- a/libcutils/debugger.c
+++ b/libcutils/debugger.c
@@ -14,21 +14,21 @@
  * limitations under the License.
  */
 
-#include <stdbool.h>
+#define LOG_TAG "DEBUG"
+
 #include <fcntl.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/types.h>
 #include <unistd.h>
 
+#include <android/log.h>
 #include <cutils/debugger.h>
 #include <cutils/sockets.h>
 
-#define LOG_TAG "DEBUG"
-#include <log/log.h>
-
 static int send_request(int sock_fd, void* msg_ptr, size_t msg_len) {
   int result = 0;
   if (TEMP_FAILURE_RETRY(write(sock_fd, msg_ptr, msg_len)) != (ssize_t) msg_len) {
diff --git a/libcutils/dlmalloc_stubs.c b/libcutils/dlmalloc_stubs.c
index 2db473d..6c07bed 100644
--- a/libcutils/dlmalloc_stubs.c
+++ b/libcutils/dlmalloc_stubs.c
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
-#include "log/log.h"
+#define LOG_TAG "dlmalloc-stubs"
+
+#include "android/log.h"
 
 #define UNUSED __attribute__((__unused__))
 
diff --git a/libcutils/fs.c b/libcutils/fs.c
index 3f14de7..c49233e 100644
--- a/libcutils/fs.c
+++ b/libcutils/fs.c
@@ -21,18 +21,19 @@
 #define _ATFILE_SOURCE 1
 #define _GNU_SOURCE 1
 
-#include <cutils/fs.h>
-#include <cutils/log.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <limits.h>
-#include <stdlib.h>
 #include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android/log.h>
+#include <cutils/fs.h>
 
 #define ALL_PERMS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
 #define BUF_SIZE 64
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 9acfa58..032e361 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -33,7 +33,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
-#include <log/log.h>
+#include <android/log.h>
 #include <private/android_filesystem_config.h>
 #include <utils/Compat.h>
 
@@ -140,12 +140,39 @@
     { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procmem" },
 
     /* the following files have enhanced capabilities and ARE included in user builds. */
-    { 00750, AID_ROOT,      AID_SHELL,     CAP_MASK_LONG(CAP_SETUID) | CAP_MASK_LONG(CAP_SETGID), "system/bin/run-as" },
-    { 00700, AID_SYSTEM,    AID_SHELL,     CAP_MASK_LONG(CAP_BLOCK_SUSPEND), "system/bin/inputflinger" },
+    { 00550, AID_LOGD,      AID_LOGD,      CAP_MASK_LONG(CAP_SYSLOG) |
+                                           CAP_MASK_LONG(CAP_AUDIT_CONTROL) |
+                                           CAP_MASK_LONG(CAP_SETGID),
+                                              "system/bin/logd" },
+    { 00750, AID_ROOT,      AID_SHELL,     CAP_MASK_LONG(CAP_SETUID) |
+                                           CAP_MASK_LONG(CAP_SETGID),
+                                              "system/bin/run-as" },
+    { 00700, AID_SYSTEM,    AID_SHELL,     CAP_MASK_LONG(CAP_BLOCK_SUSPEND),
+                                              "system/bin/inputflinger" },
 
     /* Support FIFO scheduling mode in SurfaceFlinger. */
     { 00755, AID_SYSTEM,    AID_GRAPHICS,     CAP_MASK_LONG(CAP_SYS_NICE), "system/bin/surfaceflinger" },
 
+    /* Support hostapd administering a network interface. */
+    { 00755, AID_WIFI,      AID_WIFI,      CAP_MASK_LONG(CAP_NET_ADMIN) |
+                                           CAP_MASK_LONG(CAP_NET_RAW),
+                                              "system/bin/hostapd" },
+
+    /* Support wifi_hal_legacy administering a network interface. */
+    { 00755, AID_WIFI,      AID_WIFI,      CAP_MASK_LONG(CAP_NET_ADMIN) |
+                                           CAP_MASK_LONG(CAP_NET_RAW),
+                                              "system/bin/hw/android.hardware.wifi@1.0-service" },
+
+    /* A non-privileged zygote that spawns isolated processes for web rendering. */
+    { 0750,  AID_ROOT,      AID_ROOT,      CAP_MASK_LONG(CAP_SETUID) |
+                                           CAP_MASK_LONG(CAP_SETGID) |
+                                           CAP_MASK_LONG(CAP_SETPCAP),
+                                              "system/bin/webview_zygote32" },
+    { 0750,  AID_ROOT,      AID_ROOT,      CAP_MASK_LONG(CAP_SETUID) |
+                                           CAP_MASK_LONG(CAP_SETGID) |
+                                           CAP_MASK_LONG(CAP_SETPCAP),
+                                              "system/bin/webview_zygote64" },
+
     { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/uncrypt" },
     { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/install-recovery.sh" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/*" },
diff --git a/libcutils/iosched_policy.c b/libcutils/iosched_policy.c
index 71bc94b..13c2ceb 100644
--- a/libcutils/iosched_policy.c
+++ b/libcutils/iosched_policy.c
@@ -24,7 +24,8 @@
 #include <cutils/iosched_policy.h>
 
 #if defined(__ANDROID__)
-#include <linux/ioprio.h>
+#define IOPRIO_WHO_PROCESS (1)
+#define IOPRIO_CLASS_SHIFT (13)
 #include <sys/syscall.h>
 #define __android_unused
 #else
diff --git a/libcutils/klog.c b/libcutils/klog.cpp
similarity index 77%
rename from libcutils/klog.c
rename to libcutils/klog.cpp
index 7402903..4bad28a 100644
--- a/libcutils/klog.c
+++ b/libcutils/klog.cpp
@@ -24,9 +24,9 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <cutils/android_get_control_file.h>
 #include <cutils/klog.h>
 
-static int klog_fd = -1;
 static int klog_level = KLOG_DEFAULT_LEVEL;
 
 int klog_get_level(void) {
@@ -37,32 +37,27 @@
     klog_level = level;
 }
 
-void klog_init(void) {
-    if (klog_fd >= 0) return; /* Already initialized */
+static int __open_klog(void) {
+    static const char kmsg_device[] = "/dev/kmsg";
 
-    klog_fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
-    if (klog_fd >= 0) {
-        return;
-    }
-
-    static const char* name = "/dev/__kmsg__";
-    if (mknod(name, S_IFCHR | 0600, (1 << 8) | 11) == 0) {
-        klog_fd = open(name, O_WRONLY | O_CLOEXEC);
-        unlink(name);
-    }
+    int ret = android_get_control_file(kmsg_device);
+    if (ret >= 0) return ret;
+    return TEMP_FAILURE_RETRY(open(kmsg_device, O_WRONLY | O_CLOEXEC));
 }
 
 #define LOG_BUF_MAX 512
 
 void klog_writev(int level, const struct iovec* iov, int iov_count) {
     if (level > klog_level) return;
-    if (klog_fd < 0) klog_init();
-    if (klog_fd < 0) return;
+
+    static int klog_fd = __open_klog();
+    if (klog_fd == -1) return;
     TEMP_FAILURE_RETRY(writev(klog_fd, iov, iov_count));
 }
 
 void klog_write(int level, const char* fmt, ...) {
     if (level > klog_level) return;
+
     char buf[LOG_BUF_MAX];
     va_list ap;
     va_start(ap, fmt);
diff --git a/libcutils/native_handle.c b/libcutils/native_handle.c
index 61fa38e..9f4840a 100644
--- a/libcutils/native_handle.c
+++ b/libcutils/native_handle.c
@@ -16,18 +16,32 @@
 
 #define LOG_TAG "NativeHandle"
 
-#include <stdint.h>
 #include <errno.h>
-#include <string.h>
+#include <stdint.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
-#include <cutils/log.h>
+#include <android/log.h>
 #include <cutils/native_handle.h>
 
 static const int kMaxNativeFds = 1024;
 static const int kMaxNativeInts = 1024;
 
+native_handle_t* native_handle_init(char* storage, int numFds, int numInts)
+{
+    if ((uintptr_t) storage % alignof(native_handle_t)) {
+        return NULL;
+    }
+
+    native_handle_t* handle = (native_handle_t*) storage;
+    handle->version = sizeof(native_handle_t);
+    handle->numFds = numFds;
+    handle->numInts = numInts;
+
+    return handle;
+}
+
 native_handle_t* native_handle_create(int numFds, int numInts)
 {
     if (numFds < 0 || numInts < 0 || numFds > kMaxNativeFds || numInts > kMaxNativeInts) {
@@ -44,6 +58,27 @@
     return h;
 }
 
+native_handle_t* native_handle_clone(const native_handle_t* handle)
+{
+    native_handle_t* clone = native_handle_create(handle->numFds, handle->numInts);
+    int i;
+
+    for (i = 0; i < handle->numFds; i++) {
+        clone->data[i] = dup(handle->data[i]);
+        if (clone->data[i] < 0) {
+            clone->numFds = i;
+            native_handle_close(clone);
+            native_handle_delete(clone);
+            return NULL;
+        }
+    }
+
+    memcpy(&clone->data[handle->numFds], &handle->data[handle->numFds],
+            sizeof(int) * handle->numInts);
+
+    return clone;
+}
+
 int native_handle_delete(native_handle_t* h)
 {
     if (h) {
diff --git a/libcutils/process_name.c b/libcutils/process_name.c
deleted file mode 100644
index 5d28b6f..0000000
--- a/libcutils/process_name.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#if defined(__linux__)
-#include <sys/prctl.h>
-#endif
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <cutils/process_name.h>
-#if defined(__ANDROID__)
-#include <cutils/properties.h>
-#endif
-
-#define PROCESS_NAME_DEVICE "/sys/qemu_trace/process_name"
-
-static const char* process_name = "unknown";
-#if defined(__ANDROID__)
-static int running_in_emulator = -1;
-#endif
-
-void set_process_name(const char* new_name) {
-#if defined(__ANDROID__)
-    char  propBuf[PROPERTY_VALUE_MAX];
-#endif
-
-    if (new_name == NULL) {
-        return;
-    }
-
-    // We never free the old name. Someone else could be using it.
-    int len = strlen(new_name);
-    char* copy = (char*) malloc(len + 1);
-    strcpy(copy, new_name);
-    process_name = (const char*) copy;
-
-#if defined(__linux__)
-    if (len < 16) {
-        prctl(PR_SET_NAME, (unsigned long) new_name, 0, 0, 0);
-    } else {
-        prctl(PR_SET_NAME, (unsigned long) new_name + len - 15, 0, 0, 0);
-    }
-#endif
-
-#if defined(__ANDROID__)
-    // If we know we are not running in the emulator, then return.
-    if (running_in_emulator == 0) {
-        return;
-    }
-
-    // If the "running_in_emulator" variable has not been initialized,
-    // then do it now.
-    if (running_in_emulator == -1) {
-        property_get("ro.kernel.qemu", propBuf, "");
-        if (propBuf[0] == '1') {
-            running_in_emulator = 1;
-        } else {
-            running_in_emulator = 0;
-            return;
-        }
-    }
-
-    // If the emulator was started with the "-trace file" command line option
-    // then we want to record the process name in the trace even if we are
-    // not currently tracing instructions (so that we will know the process
-    // name when we do start tracing instructions).  We do not need to execute
-    // this code if we are just running in the emulator without the "-trace"
-    // command line option, but we don't know that here and this function
-    // isn't called frequently enough to bother optimizing that case.
-    int fd = open(PROCESS_NAME_DEVICE, O_RDWR);
-    if (fd < 0)
-        return;
-    write(fd, process_name, strlen(process_name) + 1);
-    close(fd);
-#endif
-}
-
-const char* get_process_name(void) {
-    return process_name;
-}
diff --git a/libcutils/properties.c b/libcutils/properties.c
index 4e46e02..5aa6371 100644
--- a/libcutils/properties.c
+++ b/libcutils/properties.c
@@ -17,18 +17,18 @@
 #define LOG_TAG "properties"
 // #define LOG_NDEBUG 0
 
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
-#include <ctype.h>
 #include <unistd.h>
-#include <cutils/sockets.h>
-#include <errno.h>
-#include <assert.h>
 
+#include <android/log.h>
 #include <cutils/properties.h>
-#include <stdbool.h>
-#include <inttypes.h>
-#include <log/log.h>
+#include <cutils/sockets.h>
 
 int8_t property_get_bool(const char *key, int8_t default_value) {
     if (!key) {
diff --git a/libcutils/qtaguid.c b/libcutils/qtaguid.c
index 2fbe02e..ae5a503 100644
--- a/libcutils/qtaguid.c
+++ b/libcutils/qtaguid.c
@@ -26,8 +26,8 @@
 #include <string.h>
 #include <unistd.h>
 
+#include <android/log.h>
 #include <cutils/qtaguid.h>
-#include <log/log.h>
 
 static const char* CTRL_PROCPATH = "/proc/net/xt_qtaguid/ctrl";
 static const int CTRL_MAX_INPUT_LEN = 128;
@@ -47,10 +47,7 @@
 
 /* Only call once per process. */
 void qtaguid_resTrack(void) {
-    resTrackFd = TEMP_FAILURE_RETRY(open("/dev/xt_qtaguid", O_RDONLY));
-    if (resTrackFd >=0) {
-        TEMP_FAILURE_RETRY(fcntl(resTrackFd, F_SETFD, FD_CLOEXEC));
-    }
+    resTrackFd = TEMP_FAILURE_RETRY(open("/dev/xt_qtaguid", O_RDONLY | O_CLOEXEC));
 }
 
 /*
@@ -63,7 +60,7 @@
 
     ALOGV("write_ctrl(%s)", cmd);
 
-    fd = TEMP_FAILURE_RETRY(open(CTRL_PROCPATH, O_WRONLY));
+    fd = TEMP_FAILURE_RETRY(open(CTRL_PROCPATH, O_WRONLY | O_CLOEXEC));
     if (fd < 0) {
         return -errno;
     }
@@ -86,7 +83,7 @@
     int param_fd;
     int res;
 
-    param_fd = TEMP_FAILURE_RETRY(open(param_path, O_WRONLY));
+    param_fd = TEMP_FAILURE_RETRY(open(param_path, O_WRONLY | O_CLOEXEC));
     if (param_fd < 0) {
         return -errno;
     }
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index 05a2048..5c5f3a5 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -23,8 +23,8 @@
 #include <string.h>
 #include <unistd.h>
 
-#include <cutils/sched_policy.h>
 #include <log/log.h>
+#include <cutils/sched_policy.h>
 
 #define UNUSED __attribute__((__unused__))
 
@@ -45,9 +45,6 @@
 
 #define POLICY_DEBUG 0
 
-// This prctl is only available in Android kernels.
-#define PR_SET_TIMERSLACK_PID 41
-
 // timer slack value in nS enforced when the thread moves to background
 #define TIMER_SLACK_BG 40000000
 #define TIMER_SLACK_FG 50000
@@ -55,6 +52,7 @@
 static pthread_once_t the_once = PTHREAD_ONCE_INIT;
 
 static int __sys_supports_schedgroups = -1;
+static int __sys_supports_timerslack = -1;
 
 // File descriptors open to /dev/cpuctl/../tasks, setup by initialize, or -1 on error.
 static int bg_cgroup_fd = -1;
@@ -110,7 +108,7 @@
 
 static void __initialize(void) {
     char* filename;
-    if (!access("/dev/cpuctl/tasks", F_OK)) {
+    if (!access("/dev/cpuctl/tasks", W_OK)) {
         __sys_supports_schedgroups = 1;
 
         filename = "/dev/cpuctl/tasks";
@@ -129,7 +127,7 @@
     }
 
 #ifdef USE_CPUSETS
-    if (!access("/dev/cpuset/tasks", F_OK)) {
+    if (!access("/dev/cpuset/tasks", W_OK)) {
 
         filename = "/dev/cpuset/foreground/tasks";
         fg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
@@ -150,6 +148,10 @@
 #endif
     }
 #endif
+
+    char buf[64];
+    snprintf(buf, sizeof(buf), "/proc/%d/timerslack_ns", getpid());
+    __sys_supports_timerslack = !access(buf, W_OK);
 }
 
 /*
@@ -171,7 +173,7 @@
     FILE *fp;
 
     snprintf(pathBuf, sizeof(pathBuf), "/proc/%d/cgroup", tid);
-    if (!(fp = fopen(pathBuf, "r"))) {
+    if (!(fp = fopen(pathBuf, "re"))) {
         return -1;
     }
 
@@ -329,6 +331,22 @@
 #endif
 }
 
+static void set_timerslack_ns(int tid, unsigned long long slack) {
+    // v4.6+ kernels support the /proc/<tid>/timerslack_ns interface.
+    // TODO: once we've backported this, log if the open(2) fails.
+    char buf[64];
+    snprintf(buf, sizeof(buf), "/proc/%d/timerslack_ns", tid);
+    int fd = open(buf, O_WRONLY | O_CLOEXEC);
+    if (fd != -1) {
+        int len = snprintf(buf, sizeof(buf), "%llu", slack);
+        if (write(fd, buf, len) != len) {
+            SLOGE("set_timerslack_ns write failed: %s\n", strerror(errno));
+        }
+        close(fd);
+        return;
+    }
+}
+
 int set_sched_policy(int tid, SchedPolicy policy)
 {
     if (tid == 0) {
@@ -341,12 +359,11 @@
     char statfile[64];
     char statline[1024];
     char thread_name[255];
-    int fd;
 
-    sprintf(statfile, "/proc/%d/stat", tid);
+    snprintf(statfile, sizeof(statfile), "/proc/%d/stat", tid);
     memset(thread_name, 0, sizeof(thread_name));
 
-    fd = open(statfile, O_RDONLY);
+    int fd = open(statfile, O_RDONLY | O_CLOEXEC);
     if (fd >= 0) {
         int rc = read(fd, statline, 1023);
         close(fd);
@@ -425,8 +442,10 @@
                            &param);
     }
 
-    prctl(PR_SET_TIMERSLACK_PID,
-          policy == SP_BACKGROUND ? TIMER_SLACK_BG : TIMER_SLACK_FG, tid);
+    if (__sys_supports_timerslack) {
+        set_timerslack_ns(tid, policy == SP_BACKGROUND ?
+                               TIMER_SLACK_BG : TIMER_SLACK_FG);
+    }
 
     return 0;
 }
diff --git a/libcutils/socket_loopback_client_unix.c b/libcutils/socket_loopback_client_unix.c
deleted file mode 100644
index e14cffb..0000000
--- a/libcutils/socket_loopback_client_unix.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-** Copyright 2006, 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 <errno.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#if !defined(_WIN32)
-#include <sys/socket.h>
-#include <sys/select.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#endif
-
-#include <cutils/sockets.h>
-
-/* Connect to port on the loopback IP interface. type is
- * SOCK_STREAM or SOCK_DGRAM. 
- * return is a file descriptor or -1 on error
- */
-int socket_loopback_client(int port, int type)
-{
-    struct sockaddr_in addr;
-    int s;
-
-    memset(&addr, 0, sizeof(addr));
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port);
-    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
-    s = socket(AF_INET, type, 0);
-    if(s < 0) return -1;
-
-    if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        close(s);
-        return -1;
-    }
-
-    return s;
-
-}
-
diff --git a/libcutils/socket_loopback_server_unix.c b/libcutils/socket_loopback_server_unix.c
index b600e34..7b92fd6 100644
--- a/libcutils/socket_loopback_server_unix.c
+++ b/libcutils/socket_loopback_server_unix.c
@@ -31,24 +31,18 @@
 
 #include <cutils/sockets.h>
 
-/* open listen() port on loopback interface */
-int socket_loopback_server(int port, int type)
+static int _socket_loopback_server(int family, int type, struct sockaddr * addr, size_t size)
 {
-    struct sockaddr_in addr;
     int s, n;
 
-    memset(&addr, 0, sizeof(addr));
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port);
-    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
-    s = socket(AF_INET, type, 0);
-    if(s < 0) return -1;
+    s = socket(family, type, 0);
+    if(s < 0)
+        return -1;
 
     n = 1;
     setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *) &n, sizeof(n));
 
-    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+    if(bind(s, addr, size) < 0) {
         close(s);
         return -1;
     }
@@ -60,10 +54,35 @@
 
         if (ret < 0) {
             close(s);
-            return -1; 
+            return -1;
         }
     }
 
     return s;
 }
 
+/* open listen() port on loopback IPv6 interface */
+int socket_loopback_server6(int port, int type)
+{
+    struct sockaddr_in6 addr;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin6_family = AF_INET6;
+    addr.sin6_port = htons(port);
+    addr.sin6_addr = in6addr_loopback;
+
+    return _socket_loopback_server(AF_INET6, type, (struct sockaddr *) &addr, sizeof(addr));
+}
+
+/* open listen() port on loopback interface */
+int socket_loopback_server(int port, int type)
+{
+    struct sockaddr_in addr;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+    return _socket_loopback_server(AF_INET, type, (struct sockaddr *) &addr, sizeof(addr));
+}
diff --git a/libcutils/socket_network_client_unix.c b/libcutils/socket_network_client_unix.c
index 3300b8f..37851b1 100644
--- a/libcutils/socket_network_client_unix.c
+++ b/libcutils/socket_network_client_unix.c
@@ -59,64 +59,64 @@
         return -1;
     }
 
-    // TODO: try all the addresses if there's more than one?
-    int family = addrs[0].ai_family;
-    int protocol = addrs[0].ai_protocol;
-    socklen_t addr_len = addrs[0].ai_addrlen;
-    struct sockaddr_storage addr;
-    memcpy(&addr, addrs[0].ai_addr, addr_len);
+    int result = -1;
+    for (struct addrinfo* addr = addrs; addr != NULL; addr = addr->ai_next) {
+        // The Mac doesn't have SOCK_NONBLOCK.
+        int s = socket(addr->ai_family, type, addr->ai_protocol);
+        if (s == -1 || toggle_O_NONBLOCK(s) == -1) return -1;
+
+        int rc = connect(s, addr->ai_addr, addr->ai_addrlen);
+        if (rc == 0) {
+            result = toggle_O_NONBLOCK(s);
+            break;
+        } else if (rc == -1 && errno != EINPROGRESS) {
+            close(s);
+            continue;
+        }
+
+        fd_set r_set;
+        FD_ZERO(&r_set);
+        FD_SET(s, &r_set);
+        fd_set w_set = r_set;
+
+        struct timeval ts;
+        ts.tv_sec = timeout;
+        ts.tv_usec = 0;
+        if ((rc = select(s + 1, &r_set, &w_set, NULL, (timeout != 0) ? &ts : NULL)) == -1) {
+            close(s);
+            break;
+        }
+        if (rc == 0) {  // we had a timeout
+            errno = ETIMEDOUT;
+            close(s);
+            break;
+        }
+
+        int error = 0;
+        socklen_t len = sizeof(error);
+        if (FD_ISSET(s, &r_set) || FD_ISSET(s, &w_set)) {
+            if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
+                close(s);
+                break;
+            }
+        } else {
+            close(s);
+            break;
+        }
+
+        if (error) {  // check if we had a socket error
+            // TODO: Update the timeout.
+            errno = error;
+            close(s);
+            continue;
+        }
+
+        result = toggle_O_NONBLOCK(s);
+        break;
+    }
 
     freeaddrinfo(addrs);
-
-    // The Mac doesn't have SOCK_NONBLOCK.
-    int s = socket(family, type, protocol);
-    if (s == -1 || toggle_O_NONBLOCK(s) == -1) return -1;
-
-    int rc = connect(s, (const struct sockaddr*) &addr, addr_len);
-    if (rc == 0) {
-        return toggle_O_NONBLOCK(s);
-    } else if (rc == -1 && errno != EINPROGRESS) {
-        close(s);
-        return -1;
-    }
-
-    fd_set r_set;
-    FD_ZERO(&r_set);
-    FD_SET(s, &r_set);
-    fd_set w_set = r_set;
-
-    struct timeval ts;
-    ts.tv_sec = timeout;
-    ts.tv_usec = 0;
-    if ((rc = select(s + 1, &r_set, &w_set, NULL, (timeout != 0) ? &ts : NULL)) == -1) {
-        close(s);
-        return -1;
-    }
-    if (rc == 0) {   // we had a timeout
-        errno = ETIMEDOUT;
-        close(s);
-        return -1;
-    }
-
-    int error = 0;
-    socklen_t len = sizeof(error);
-    if (FD_ISSET(s, &r_set) || FD_ISSET(s, &w_set)) {
-        if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
-            close(s);
-            return -1;
-        }
-    } else {
-        close(s);
-        return -1;
-    }
-
-    if (error) {  // check if we had a socket error
-        errno = error;
-        close(s);
-        return -1;
-    }
-
-    return toggle_O_NONBLOCK(s);
+    return result;
 }
 
 int socket_network_client(const char* host, int port, int type) {
diff --git a/libcutils/sockets.cpp b/libcutils/sockets.cpp
index d9ab146..23a447b 100644
--- a/libcutils/sockets.cpp
+++ b/libcutils/sockets.cpp
@@ -31,10 +31,6 @@
 
 #include <cutils/sockets.h>
 
-#if !defined(_WIN32)
-#include <netinet/in.h>
-#endif
-
 int socket_get_local_port(cutils_socket_t sock) {
     sockaddr_storage addr;
     socklen_t addr_size = sizeof(addr);
diff --git a/libcutils/sockets_unix.cpp b/libcutils/sockets_unix.cpp
index 8747d69..5a14a5c 100644
--- a/libcutils/sockets_unix.cpp
+++ b/libcutils/sockets_unix.cpp
@@ -14,11 +14,26 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "socket-unix"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <android/log.h>
+#include <cutils/android_get_control_file.h>
 #include <cutils/sockets.h>
 
-#include <sys/uio.h>
+#include "android_get_control_env.h"
 
-#include <log/log.h>
+#ifndef TEMP_FAILURE_RETRY
+#define TEMP_FAILURE_RETRY(exp) (exp) // KISS implementation
+#endif
 
 #if defined(__ANDROID__)
 /* For the socket trust (credentials) check */
@@ -77,3 +92,24 @@
 
     return writev(sock, iovec_buffers, num_buffers);
 }
+
+int android_get_control_socket(const char* name) {
+    int fd = __android_get_control_from_env(ANDROID_SOCKET_ENV_PREFIX, name);
+
+    if (fd < 0) return fd;
+
+    // Compare to UNIX domain socket name, must match!
+    struct sockaddr_un addr;
+    socklen_t addrlen = sizeof(addr);
+    int ret = TEMP_FAILURE_RETRY(getsockname(fd, (struct sockaddr *)&addr, &addrlen));
+    if (ret < 0) return -1;
+    char *path = NULL;
+    if (asprintf(&path, ANDROID_SOCKET_DIR "/%s", name) < 0) return -1;
+    if (!path) return -1;
+    int cmp = strcmp(addr.sun_path, path);
+    free(path);
+    if (cmp != 0) return -1;
+
+    // It is what we think it is
+    return fd;
+}
diff --git a/libcutils/sockets_windows.cpp b/libcutils/sockets_windows.cpp
index ed6b1a7..3064c70 100644
--- a/libcutils/sockets_windows.cpp
+++ b/libcutils/sockets_windows.cpp
@@ -84,3 +84,7 @@
 
     return -1;
 }
+
+int android_get_control_socket(const char* name) {
+    return -1;
+}
diff --git a/libcutils/str_parms.c b/libcutils/str_parms.c
index 8dafded..6bb7e58 100644
--- a/libcutils/str_parms.c
+++ b/libcutils/str_parms.c
@@ -24,10 +24,10 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <android/log.h>
 #include <cutils/hashmap.h>
 #include <cutils/memory.h>
 #include <cutils/str_parms.h>
-#include <log/log.h>
 
 #define UNUSED __attribute__((unused))
 
diff --git a/libcutils/strdup8to16.c b/libcutils/strdup8to16.c
index 63e5ca4..c23cf8b 100644
--- a/libcutils/strdup8to16.c
+++ b/libcutils/strdup8to16.c
@@ -27,7 +27,7 @@
 #define UTF16_REPLACEMENT_CHAR 0xfffd
 
 /* Clever trick from Dianne that returns 1-4 depending on leading bit sequence*/
-#define UTF8_SEQ_LENGTH(ch) (((0xe5000000 >> ((ch >> 3) & 0x1e)) & 3) + 1)
+#define UTF8_SEQ_LENGTH(ch) (((0xe5000000 >> (((ch) >> 3) & 0x1e)) & 3) + 1)
 
 /* note: macro expands to multiple lines */
 #define UTF8_SHIFT_AND_MASK(unicode, byte)  \
diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp
new file mode 100644
index 0000000..72e2eac
--- /dev/null
+++ b/libcutils/tests/Android.bp
@@ -0,0 +1,78 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_defaults {
+    name: "libcutils_test_default",
+    srcs: ["sockets_test.cpp"],
+
+    target: {
+        android: {
+            srcs: [
+                "AshmemTest.cpp",
+                "MemsetTest.cpp",
+                "PropertiesTest.cpp",
+                "sched_policy_test.cpp",
+                "trace-dev_test.cpp",
+            ],
+        },
+
+        not_windows: {
+            srcs: [
+                "test_str_parms.cpp",
+                "android_get_control_socket_test.cpp",
+                "android_get_control_file_test.cpp"
+            ],
+        },
+    },
+
+    multilib: {
+        lib32: {
+            suffix: "32",
+        },
+        lib64: {
+            suffix: "64",
+        },
+    },
+}
+
+test_libraries = [
+    "libcutils",
+    "liblog",
+    "libbase",
+]
+
+cc_test {
+    name: "libcutils_test",
+    defaults: ["libcutils_test_default"],
+    host_supported: true,
+    shared_libs: test_libraries,
+}
+
+cc_test {
+    name: "libcutils_test_static",
+    defaults: ["libcutils_test_default"],
+    static_libs: ["libc"] + test_libraries,
+    stl: "libc++_static",
+
+    target: {
+        android: {
+            static_executable: true,
+        },
+        windows: {
+            host_ldlibs: ["-lws2_32"],
+
+            enabled: true,
+        },
+    },
+}
diff --git a/libcutils/tests/Android.mk b/libcutils/tests/Android.mk
deleted file mode 100644
index 52cf5f4..0000000
--- a/libcutils/tests/Android.mk
+++ /dev/null
@@ -1,81 +0,0 @@
-# Copyright (C) 2014 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.
-
-LOCAL_PATH := $(call my-dir)
-
-test_src_files := \
-    sockets_test.cpp \
-
-test_src_files_nonwindows := \
-    test_str_parms.cpp \
-
-test_target_only_src_files := \
-    MemsetTest.cpp \
-    PropertiesTest.cpp \
-    trace-dev_test.cpp \
-
-test_libraries := libcutils liblog libbase
-
-
-#
-# Target.
-#
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libcutils_test
-LOCAL_SRC_FILES := $(test_src_files) $(test_target_only_src_files)
-LOCAL_SHARED_LIBRARIES := $(test_libraries)
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libcutils_test_static
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_SRC_FILES := $(test_src_files) $(test_target_only_src_files)
-LOCAL_STATIC_LIBRARIES := libc $(test_libraries)
-LOCAL_CXX_STL := libc++_static
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-include $(BUILD_NATIVE_TEST)
-
-
-#
-# Host.
-#
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libcutils_test
-LOCAL_SRC_FILES := $(test_src_files) $(test_src_files_nonwindows)
-LOCAL_SHARED_LIBRARIES := $(test_libraries)
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-include $(BUILD_HOST_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libcutils_test_static
-LOCAL_SRC_FILES := $(test_src_files)
-LOCAL_SRC_FILES_darwin := $(test_src_files_nonwindows)
-LOCAL_SRC_FILES_linux := $(test_src_files_nonwindows)
-LOCAL_STATIC_LIBRARIES := $(test_libraries)
-LOCAL_LDLIBS_windows := -lws2_32
-LOCAL_CXX_STL := libc++_static
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-LOCAL_MODULE_HOST_OS := darwin linux windows
-include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libcutils/tests/AshmemTest.cpp b/libcutils/tests/AshmemTest.cpp
new file mode 100644
index 0000000..51c679f
--- /dev/null
+++ b/libcutils/tests/AshmemTest.cpp
@@ -0,0 +1,177 @@
+/*
+ * 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 <sys/mman.h>
+#include <cutils/ashmem.h>
+#include <gtest/gtest.h>
+#include <android-base/unique_fd.h>
+
+using android::base::unique_fd;
+
+void TestCreateRegion(size_t size, unique_fd &fd, int prot) {
+    fd = unique_fd(ashmem_create_region(nullptr, size));
+    ASSERT_TRUE(fd >= 0);
+    ASSERT_TRUE(ashmem_valid(fd));
+    ASSERT_EQ(size, static_cast<size_t>(ashmem_get_size_region(fd)));
+    ASSERT_EQ(0, ashmem_set_prot_region(fd, prot));
+}
+
+void TestMmap(const unique_fd &fd, size_t size, int prot, void **region) {
+    *region = mmap(nullptr, size, prot, MAP_SHARED, fd, 0);
+    ASSERT_NE(MAP_FAILED, *region);
+}
+
+void TestProtDenied(const unique_fd &fd, size_t size, int prot) {
+    EXPECT_EQ(MAP_FAILED, mmap(nullptr, size, prot, MAP_SHARED, fd, 0));
+}
+
+void FillData(uint8_t* data, size_t dataLen) {
+    for (size_t i = 0; i < dataLen; i++) {
+        data[i] = i & 0xFF;
+    }
+}
+
+TEST(AshmemTest, BasicTest) {
+    constexpr size_t size = PAGE_SIZE;
+    uint8_t data[size];
+    FillData(data, size);
+
+    unique_fd fd;
+    ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_READ | PROT_WRITE));
+
+    void *region1;
+    ASSERT_NO_FATAL_FAILURE(TestMmap(fd, size, PROT_READ | PROT_WRITE, &region1));
+
+    memcpy(region1, &data, size);
+    ASSERT_EQ(0, memcmp(region1, &data, size));
+
+    EXPECT_EQ(0, munmap(region1, size));
+
+    void *region2;
+    ASSERT_NO_FATAL_FAILURE(TestMmap(fd, size, PROT_READ, &region2));
+    ASSERT_EQ(0, memcmp(region2, &data, size));
+    EXPECT_EQ(0, munmap(region2, size));
+}
+
+TEST(AshmemTest, ForkTest) {
+    constexpr size_t size = PAGE_SIZE;
+    uint8_t data[size];
+    FillData(data, size);
+
+    unique_fd fd;
+    ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_READ | PROT_WRITE));
+
+    void *region1;
+    ASSERT_NO_FATAL_FAILURE(TestMmap(fd, size, PROT_READ | PROT_WRITE, &region1));
+
+    memcpy(region1, &data, size);
+    ASSERT_EQ(0, memcmp(region1, &data, size));
+    EXPECT_EQ(0, munmap(region1, size));
+
+    ASSERT_EXIT({
+        void *region2 = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+        if (region2 == MAP_FAILED) {
+            _exit(1);
+        }
+        if (memcmp(region2, &data, size) != 0) {
+            _exit(2);
+        }
+        memset(region2, 0, size);
+        munmap(region2, size);
+        _exit(0);
+    }, ::testing::ExitedWithCode(0),"");
+
+    memset(&data, 0, size);
+    void *region2;
+    ASSERT_NO_FATAL_FAILURE(TestMmap(fd, size, PROT_READ | PROT_WRITE, &region2));
+    ASSERT_EQ(0, memcmp(region2, &data, size));
+    EXPECT_EQ(0, munmap(region2, size));
+}
+
+TEST(AshmemTest, ProtTest) {
+    unique_fd fd;
+    constexpr size_t size = PAGE_SIZE;
+    void *region;
+
+    ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_READ));
+    TestProtDenied(fd, size, PROT_WRITE);
+    ASSERT_NO_FATAL_FAILURE(TestMmap(fd, size, PROT_READ, &region));
+    EXPECT_EQ(0, munmap(region, size));
+
+    ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_WRITE));
+    TestProtDenied(fd, size, PROT_READ);
+    ASSERT_NO_FATAL_FAILURE(TestMmap(fd, size, PROT_WRITE, &region));
+    EXPECT_EQ(0, munmap(region, size));
+}
+
+TEST(AshmemTest, ForkProtTest) {
+    unique_fd fd;
+    constexpr size_t size = PAGE_SIZE;
+
+    int protFlags[] = { PROT_READ, PROT_WRITE };
+    for (int i = 0; i < 2; i++) {
+        ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_READ | PROT_WRITE));
+        ASSERT_EXIT({
+            if (ashmem_set_prot_region(fd, protFlags[i]) >= 0) {
+                _exit(0);
+            } else {
+                _exit(1);
+            }
+        }, ::testing::ExitedWithCode(0), "");
+        ASSERT_NO_FATAL_FAILURE(TestProtDenied(fd, size, protFlags[1-i]));
+    }
+}
+
+TEST(AshmemTest, ForkMultiRegionTest) {
+    constexpr size_t size = PAGE_SIZE;
+    uint8_t data[size];
+    FillData(data, size);
+
+    constexpr int nRegions = 16;
+    unique_fd fd[nRegions];
+    for (int i = 0; i < nRegions; i++) {
+        ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd[i], PROT_READ | PROT_WRITE));
+        void *region;
+        ASSERT_NO_FATAL_FAILURE(TestMmap(fd[i], size, PROT_READ | PROT_WRITE, &region));
+        memcpy(region, &data, size);
+        ASSERT_EQ(0, memcmp(region, &data, size));
+        EXPECT_EQ(0, munmap(region, size));
+    }
+
+    ASSERT_EXIT({
+        for (int i = 0; i < nRegions; i++) {
+            void *region = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd[i], 0);
+            if (region == MAP_FAILED) {
+                _exit(1);
+            }
+            if (memcmp(region, &data, size) != 0) {
+                munmap(region, size);
+                _exit(2);
+            }
+            memset(region, 0, size);
+            munmap(region, size);
+        }
+        _exit(0);
+    }, ::testing::ExitedWithCode(0), "");
+
+    memset(&data, 0, size);
+    for (int i = 0; i < nRegions; i++) {
+        void *region;
+        ASSERT_NO_FATAL_FAILURE(TestMmap(fd[i], size, PROT_READ | PROT_WRITE, &region));
+        ASSERT_EQ(0, memcmp(region, &data, size));
+        EXPECT_EQ(0, munmap(region, size));
+    }
+}
diff --git a/libcutils/tests/PropertiesTest.cpp b/libcutils/tests/PropertiesTest.cpp
index 659821c..f0cdffd 100644
--- a/libcutils/tests/PropertiesTest.cpp
+++ b/libcutils/tests/PropertiesTest.cpp
@@ -15,20 +15,22 @@
  */
 
 #define LOG_TAG "Properties_test"
-#include <utils/Log.h>
-#include <gtest/gtest.h>
 
-#include <cutils/properties.h>
 #include <limits.h>
-#include <string>
-#include <sstream>
+
 #include <iostream>
+#include <sstream>
+#include <string>
+
+#include <android/log.h>
+#include <android-base/macros.h>
+#include <cutils/properties.h>
+#include <gtest/gtest.h>
 
 namespace android {
 
 #define STRINGIFY_INNER(x) #x
 #define STRINGIFY(x) STRINGIFY_INNER(x)
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
 #define ASSERT_OK(x) ASSERT_EQ(0, (x))
 #define EXPECT_OK(x) EXPECT_EQ(0, (x))
 
@@ -85,7 +87,7 @@
     }
 
     void ResetValue(unsigned char c = 0xFF) {
-        for (size_t i = 0; i < ARRAY_SIZE(mValue); ++i) {
+        for (size_t i = 0; i < arraysize(mValue); ++i) {
             mValue[i] = (char) c;
         }
     }
@@ -106,14 +108,14 @@
         ResetValue();
 
         // Since the value is null, default value will be returned
-        int len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
+        size_t len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
         EXPECT_EQ(strlen(PROPERTY_TEST_VALUE_DEFAULT), len);
         EXPECT_STREQ(PROPERTY_TEST_VALUE_DEFAULT, mValue);
     }
 
     // Trivial case => get returns what was set
     {
-        int len = SetAndGetProperty("hello_world");
+        size_t len = SetAndGetProperty("hello_world");
         EXPECT_EQ(strlen("hello_world"), len) << "hello_world key";
         EXPECT_STREQ("hello_world", mValue);
         ResetValue();
@@ -122,7 +124,7 @@
     // Set to empty string => get returns default always
     {
         const char* EMPTY_STRING_DEFAULT = "EMPTY_STRING";
-        int len = SetAndGetProperty("", EMPTY_STRING_DEFAULT);
+        size_t len = SetAndGetProperty("", EMPTY_STRING_DEFAULT);
         EXPECT_EQ(strlen(EMPTY_STRING_DEFAULT), len) << "empty key";
         EXPECT_STREQ(EMPTY_STRING_DEFAULT, mValue);
         ResetValue();
@@ -147,7 +149,7 @@
 
         // Expect that the value set fails since it's too long
         EXPECT_GT(0, property_set(PROPERTY_TEST_KEY, oneLongerString.c_str()));
-        int len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
+        size_t len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
 
         EXPECT_EQ(strlen(VALID_TEST_VALUE), len) << "set should've failed";
         EXPECT_STREQ(VALID_TEST_VALUE, mValue);
@@ -177,7 +179,7 @@
      * TRUE
      */
     const char *valuesTrue[] = { "1", "true", "y", "yes", "on", };
-    for (size_t i = 0; i < ARRAY_SIZE(valuesTrue); ++i) {
+    for (size_t i = 0; i < arraysize(valuesTrue); ++i) {
         ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesTrue[i]));
         bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/false);
         EXPECT_TRUE(val) << "Property should've been TRUE for value: '" << valuesTrue[i] << "'";
@@ -187,7 +189,7 @@
      * FALSE
      */
     const char *valuesFalse[] = { "0", "false", "n", "no", "off", };
-    for (size_t i = 0; i < ARRAY_SIZE(valuesFalse); ++i) {
+    for (size_t i = 0; i < arraysize(valuesFalse); ++i) {
         ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesFalse[i]));
         bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/true);
         EXPECT_FALSE(val) << "Property shoud've been FALSE For string value: '" << valuesFalse[i] << "'";
@@ -200,7 +202,7 @@
             "+1", "  1  ", "  true", "  true  ", "  y  ", "  yes", "yes  ",
             "+0", "-0", "00", "  00  ", "  false", "false  ",
     };
-    for (size_t i = 0; i < ARRAY_SIZE(valuesNeither); ++i) {
+    for (size_t i = 0; i < arraysize(valuesNeither); ++i) {
         ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesNeither[i]));
 
         // The default value should always be used
@@ -249,9 +251,9 @@
         DEFAULT_VALUE, DEFAULT_VALUE,
     };
 
-    ASSERT_EQ(ARRAY_SIZE(setValues), ARRAY_SIZE(getValues));
+    ASSERT_EQ(arraysize(setValues), arraysize(getValues));
 
-    for (size_t i = 0; i < ARRAY_SIZE(setValues); ++i) {
+    for (size_t i = 0; i < arraysize(setValues); ++i) {
         ASSERT_OK(property_set(PROPERTY_TEST_KEY, setValues[i]));
 
         int64_t val = property_get_int64(PROPERTY_TEST_KEY, DEFAULT_VALUE);
@@ -296,9 +298,9 @@
         DEFAULT_VALUE, DEFAULT_VALUE,
     };
 
-    ASSERT_EQ(ARRAY_SIZE(setValues), ARRAY_SIZE(getValues));
+    ASSERT_EQ(arraysize(setValues), arraysize(getValues));
 
-    for (size_t i = 0; i < ARRAY_SIZE(setValues); ++i) {
+    for (size_t i = 0; i < arraysize(setValues); ++i) {
         ASSERT_OK(property_set(PROPERTY_TEST_KEY, setValues[i]));
 
         int32_t val = property_get_int32(PROPERTY_TEST_KEY, DEFAULT_VALUE);
diff --git a/libcutils/tests/android_get_control_file_test.cpp b/libcutils/tests/android_get_control_file_test.cpp
new file mode 100644
index 0000000..6c6fd2a
--- /dev/null
+++ b/libcutils/tests/android_get_control_file_test.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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 <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include <string>
+
+#include <android-base/stringprintf.h>
+#include <android-base/test_utils.h>
+#include <cutils/android_get_control_file.h>
+#include <gtest/gtest.h>
+
+TEST(FilesTest, android_get_control_file) {
+    TemporaryFile tf;
+    ASSERT_GE(tf.fd, 0);
+
+    std::string key(ANDROID_FILE_ENV_PREFIX);
+    key += tf.path;
+
+    std::for_each(key.begin(), key.end(), [] (char& c) { c = isalnum(c) ? c : '_'; });
+
+    EXPECT_EQ(unsetenv(key.c_str()), 0);
+    EXPECT_EQ(android_get_control_file(tf.path), -1);
+
+    EXPECT_EQ(setenv(key.c_str(), android::base::StringPrintf("%d", tf.fd).c_str(), true), 0);
+
+    EXPECT_EQ(android_get_control_file(tf.path), tf.fd);
+    close(tf.fd);
+    EXPECT_EQ(android_get_control_file(tf.path), -1);
+    EXPECT_EQ(unsetenv(key.c_str()), 0);
+    EXPECT_EQ(android_get_control_file(tf.path), -1);
+}
diff --git a/libcutils/tests/android_get_control_socket_test.cpp b/libcutils/tests/android_get_control_socket_test.cpp
new file mode 100644
index 0000000..e586748
--- /dev/null
+++ b/libcutils/tests/android_get_control_socket_test.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <time.h>
+
+#include <cutils/sockets.h>
+#include <gtest/gtest.h>
+
+#ifndef SOCK_NONBLOCK
+#define SOCK_NONBLOCK 0
+#endif
+
+#ifndef SOCK_CLOEXEC
+#define SOCK_CLOEXEC 0
+#endif
+
+TEST(SocketsTest, android_get_control_socket) {
+    static const char key[] = ANDROID_SOCKET_ENV_PREFIX "SocketsTest_android_get_control_socket";
+    static const char* name = key + strlen(ANDROID_SOCKET_ENV_PREFIX);
+
+    EXPECT_EQ(unsetenv(key), 0);
+    EXPECT_EQ(android_get_control_socket(name), -1);
+
+    int fd;
+    ASSERT_GE(fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0), 0);
+#ifdef F_GETFL
+    int flags;
+    ASSERT_GE(flags = fcntl(fd, F_GETFL), 0);
+    ASSERT_GE(fcntl(fd, F_SETFL, flags | O_NONBLOCK), 0);
+#endif
+    EXPECT_EQ(android_get_control_socket(name), -1);
+
+    struct sockaddr_un addr;
+    memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s", name);
+    unlink(addr.sun_path);
+
+    EXPECT_EQ(bind(fd, (struct sockaddr*)&addr, sizeof(addr)), 0);
+    EXPECT_EQ(android_get_control_socket(name), -1);
+
+    char val[32];
+    snprintf(val, sizeof(val), "%d", fd);
+    EXPECT_EQ(setenv(key, val, true), 0);
+
+    EXPECT_EQ(android_get_control_socket(name), fd);
+    socket_close(fd);
+    EXPECT_EQ(android_get_control_socket(name), -1);
+    EXPECT_EQ(unlink(addr.sun_path), 0);
+    EXPECT_EQ(android_get_control_socket(name), -1);
+    EXPECT_EQ(unsetenv(key), 0);
+    EXPECT_EQ(android_get_control_socket(name), -1);
+}
diff --git a/libcutils/tests/sched_policy_test.cpp b/libcutils/tests/sched_policy_test.cpp
new file mode 100644
index 0000000..173174a
--- /dev/null
+++ b/libcutils/tests/sched_policy_test.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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 <algorithm>
+#include <chrono>
+#include <thread>
+#include <vector>
+
+#include <sys/capability.h>
+
+#include <cutils/sched_policy.h>
+
+#include <gtest/gtest.h>
+
+bool hasCapSysNice() {
+    __user_cap_header_struct header;
+    memset(&header, 0, sizeof(header));
+    header.version = _LINUX_CAPABILITY_VERSION_3;
+
+    __user_cap_data_struct caps[_LINUX_CAPABILITY_U32S_3];
+    if (capget(&header, &caps[0])) {
+        GTEST_LOG_(WARNING) << "failed to get process capabilities";
+        return false;
+    }
+
+    auto nice_idx = CAP_TO_INDEX(CAP_SYS_NICE);
+    auto nice_mask = CAP_TO_MASK(CAP_SYS_NICE);
+    return caps[nice_idx].effective & nice_mask;
+}
+
+long long medianSleepTime() {
+    std::vector<long long> sleepTimes;
+    constexpr size_t numSamples = 100;
+
+    for (size_t i = 0; i < numSamples; i++) {
+        auto start = std::chrono::steady_clock::now();
+        std::this_thread::sleep_for(std::chrono::nanoseconds(1));
+        auto end = std::chrono::steady_clock::now();
+
+        auto diff = end - start;
+        sleepTimes.push_back(diff.count());
+    }
+
+    constexpr auto median = numSamples / 2;
+    std::nth_element(sleepTimes.begin(), sleepTimes.begin() + median,
+            sleepTimes.end());
+    return sleepTimes[median];
+}
+
+TEST(SchedPolicy, set_sched_policy) {
+    if (!hasCapSysNice()) {
+        GTEST_LOG_(INFO) << "skipping test that requires CAP_SYS_NICE";
+        return;
+    }
+
+    // A measureable effect of scheduling policy is that the kernel has 800x
+    // greater slack time in waking up a sleeping background thread.
+    //
+    // Look for 100x difference in how long FB and BG threads actually sleep
+    // when trying to sleep for 1 ns.  This difference is large enough not
+    // to happen by chance, but small enough (compared to 800x) to keep inherent
+    // fuzziness in scheduler behavior from causing false negatives.
+    const unsigned int BG_FG_SLACK_FACTOR = 100;
+
+    ASSERT_EQ(0, set_sched_policy(0, SP_BACKGROUND));
+    auto bgSleepTime = medianSleepTime();
+
+    ASSERT_EQ(0, set_sched_policy(0, SP_FOREGROUND));
+    auto fgSleepTime = medianSleepTime();
+    ASSERT_GT(bgSleepTime, fgSleepTime * BG_FG_SLACK_FACTOR);
+}
+
+TEST(SchedPolicy, get_sched_policy) {
+    SchedPolicy policy;
+    ASSERT_EQ(0, get_sched_policy(0, &policy));
+
+    const char *policyName = get_sched_policy_name(policy);
+    EXPECT_NE(nullptr, policyName);
+    EXPECT_STRNE("error", policyName);
+
+    ASSERT_EQ(0, set_sched_policy(0, SP_BACKGROUND));
+    SchedPolicy newPolicy;
+    ASSERT_EQ(0, get_sched_policy(0, &newPolicy));
+    EXPECT_EQ(SP_BACKGROUND, newPolicy);
+}
diff --git a/libcutils/tests/sockets_test.cpp b/libcutils/tests/sockets_test.cpp
index 0f682a2..0441fb6 100644
--- a/libcutils/tests/sockets_test.cpp
+++ b/libcutils/tests/sockets_test.cpp
@@ -18,10 +18,12 @@
 // IPv6 capabilities. These tests assume that no UDP packets are lost, which
 // should be the case for loopback communication, but is not guaranteed.
 
-#include <cutils/sockets.h>
-
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
 #include <time.h>
 
+#include <cutils/sockets.h>
 #include <gtest/gtest.h>
 
 // Makes sure the passed sockets are valid, sends data between them, and closes
diff --git a/libcutils/trace-dev.c b/libcutils/trace-dev.c
index 778e4f0..113f423 100644
--- a/libcutils/trace-dev.c
+++ b/libcutils/trace-dev.c
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "cutils-trace"
+
 #include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
@@ -23,12 +25,11 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
+
 #include <cutils/compiler.h>
 #include <cutils/properties.h>
 #include <cutils/trace.h>
-
-#define LOG_TAG "cutils-trace"
-#include <log/log.h>
+#include <private/android_logger.h>
 
 /**
  * Maximum size of a message that can be logged to the trace buffer.
@@ -85,16 +86,9 @@
 // Determine whether application-level tracing is enabled for this process.
 static bool atrace_is_app_tracing_enabled()
 {
-    bool sys_debuggable = false;
-    char value[PROPERTY_VALUE_MAX];
+    bool sys_debuggable = __android_log_is_debuggable();
     bool result = false;
 
-    // Check whether the system is debuggable.
-    property_get("ro.debuggable", value, "0");
-    if (value[0] == '1') {
-        sys_debuggable = true;
-    }
-
     if (sys_debuggable || atrace_is_debuggable) {
         // Check whether tracing is enabled for this process.
         FILE * file = fopen("/proc/self/cmdline", "re");
@@ -196,6 +190,12 @@
     write(atrace_marker_fd, buf, len);
 }
 
+void atrace_end_body()
+{
+    char c = 'E';
+    write(atrace_marker_fd, &c, 1);
+}
+
 #define WRITE_MSG(format_begin, format_end, pid, name, value) { \
     char buf[ATRACE_MESSAGE_LENGTH]; \
     int len = snprintf(buf, sizeof(buf), format_begin "%s" format_end, pid, \
diff --git a/libcutils/trace-host.c b/libcutils/trace-host.c
index 6478e3e..05842cd 100644
--- a/libcutils/trace-host.c
+++ b/libcutils/trace-host.c
@@ -29,6 +29,7 @@
 void atrace_update_tags() { }
 void atrace_setup() { }
 void atrace_begin_body(const char* name __unused) { }
+void atrace_end_body() { }
 void atrace_async_begin_body(const char* name __unused, int32_t cookie __unused) { }
 void atrace_async_end_body(const char* name __unused, int32_t cookie __unused) { }
 void atrace_int_body(const char* name __unused, int32_t value __unused) { }
diff --git a/libdiskconfig/Android.bp b/libdiskconfig/Android.bp
new file mode 100644
index 0000000..041fd63
--- /dev/null
+++ b/libdiskconfig/Android.bp
@@ -0,0 +1,32 @@
+cc_library {
+    name: "libdiskconfig",
+    srcs: [
+        "diskconfig.c",
+        "diskutils.c",
+        "write_lst.c",
+        "config_mbr.c",
+    ],
+
+    shared_libs: [
+        "libcutils",
+        "liblog",
+    ],
+    cflags: ["-Werror"],
+    export_include_dirs: ["include"],
+    local_include_dirs: ["include"],
+
+    target: {
+        darwin: {
+            enabled: false,
+        },
+        linux: {
+            cflags: [
+                "-O2",
+                "-g",
+                "-W",
+                "-Wall",
+                "-D_LARGEFILE64_SOURCE",
+            ],
+        },
+    },
+}
diff --git a/libdiskconfig/Android.mk b/libdiskconfig/Android.mk
deleted file mode 100644
index 624e385..0000000
--- a/libdiskconfig/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-commonSources := \
-	diskconfig.c \
-	diskutils.c \
-	write_lst.c \
-	config_mbr.c
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(commonSources)
-LOCAL_MODULE := libdiskconfig
-LOCAL_MODULE_TAGS := optional
-LOCAL_SYSTEM_SHARED_LIBRARIES := libcutils liblog libc
-LOCAL_CFLAGS := -Werror
-include $(BUILD_SHARED_LIBRARY)
-
-ifeq ($(HOST_OS),linux)
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(commonSources)
-LOCAL_MODULE := libdiskconfig_host
-LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := -O2 -g -W -Wall -Werror -D_LARGEFILE64_SOURCE
-include $(BUILD_HOST_STATIC_LIBRARY)
-endif # HOST_OS == linux
diff --git a/libdiskconfig/config_mbr.c b/libdiskconfig/config_mbr.c
index 7b6ca1c..1d3cd20 100644
--- a/libdiskconfig/config_mbr.c
+++ b/libdiskconfig/config_mbr.c
@@ -16,16 +16,15 @@
  */
 
 #define LOG_TAG "config_mbr"
+
 #include <stdint.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <stdio.h>
 
-#include <cutils/log.h>
-
+#include <android/log.h>
 #include <diskconfig/diskconfig.h>
 
-
 /* start and len are in LBA units */
 static void
 cfg_pentry(struct pc_partition *pentry, uint8_t status, uint8_t type,
diff --git a/libdiskconfig/diskconfig.c b/libdiskconfig/diskconfig.c
index 1167d4b..2d59ad9 100644
--- a/libdiskconfig/diskconfig.c
+++ b/libdiskconfig/diskconfig.c
@@ -20,21 +20,19 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
+#include <linux/fs.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
+#include <unistd.h>
 
-#include <linux/fs.h>
-
+#include <android/log.h>
 #include <cutils/config_utils.h>
-#include <log/log.h>
 
 #include <diskconfig/diskconfig.h>
 
-
 static int
 parse_len(const char *str, uint64_t *plen)
 {
diff --git a/libdiskconfig/diskutils.c b/libdiskconfig/diskutils.c
index 5d0ee62..3a27601 100644
--- a/libdiskconfig/diskutils.c
+++ b/libdiskconfig/diskutils.c
@@ -23,10 +23,10 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
 #include <sys/stat.h>
+#include <unistd.h>
 
-#include <log/log.h>
+#include <android/log.h>
 
 #include <diskconfig/diskconfig.h>
 
diff --git a/libdiskconfig/dump_diskconfig.c b/libdiskconfig/dump_diskconfig.c
index 75256f6..c94e7f4 100644
--- a/libdiskconfig/dump_diskconfig.c
+++ b/libdiskconfig/dump_diskconfig.c
@@ -16,9 +16,10 @@
  */
 
 #define LOG_TAG "dump_diskconfig"
+
 #include <stdio.h>
 
-#include <cutils/log.h>
+#include <android/log.h>
 
 #include "diskconfig.h"
 
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/libdiskconfig/write_lst.c b/libdiskconfig/write_lst.c
index 90b1c82..21d4a31 100644
--- a/libdiskconfig/write_lst.c
+++ b/libdiskconfig/write_lst.c
@@ -16,14 +16,14 @@
  */
 
 #define LOG_TAG "write_lst"
-#include <sys/types.h>
+
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/types.h>
 #include <unistd.h>
 
-#include <cutils/log.h>
-
+#include <android/log.h>
 #include <diskconfig/diskconfig.h>
 
 struct write_list *
diff --git a/libion/Android.bp b/libion/Android.bp
new file mode 100644
index 0000000..da98111
--- /dev/null
+++ b/libion/Android.bp
@@ -0,0 +1,25 @@
+
+cc_library {
+    name: "libion",
+    srcs: ["ion.c"],
+    shared_libs: ["liblog"],
+    local_include_dirs: [
+        "include",
+        "kernel-headers",
+    ],
+    export_include_dirs: [
+        "include",
+        "kernel-headers",
+    ],
+    cflags: ["-Werror"],
+}
+
+cc_binary {
+    name: "iontest",
+    srcs: ["ion_test.c"],
+    static_libs: ["libion"],
+    shared_libs: ["liblog"],
+    cflags: ["-Werror"],
+}
+
+subdirs = ["tests"]
diff --git a/libion/Android.mk b/libion/Android.mk
deleted file mode 100644
index 6562cd3..0000000
--- a/libion/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := ion.c
-LOCAL_MODULE := libion
-LOCAL_MODULE_TAGS := optional
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/kernel-headers
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include $(LOCAL_PATH)/kernel-headers
-LOCAL_CFLAGS := -Werror
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := ion.c ion_test.c
-LOCAL_MODULE := iontest
-LOCAL_MODULE_TAGS := optional tests
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/kernel-headers
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_CFLAGS := -Werror
-include $(BUILD_EXECUTABLE)
-
-include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/libion/ion.c b/libion/ion.c
index d1984bd..2db8845 100644
--- a/libion/ion.c
+++ b/libion/ion.c
@@ -19,21 +19,22 @@
  */
 #define LOG_TAG "ion"
 
-#include <cutils/log.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <linux/ion.h>
 #include <stdio.h>
 #include <string.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 #include <sys/types.h>
+#include <unistd.h>
 
-#include <linux/ion.h>
+#include <android/log.h>
 #include <ion/ion.h>
 
 int ion_open()
 {
-    int fd = open("/dev/ion", O_RDWR);
+    int fd = open("/dev/ion", O_RDONLY);
     if (fd < 0)
         ALOGE("open /dev/ion failed!\n");
     return fd;
diff --git a/libion/kernel-headers/linux/ion.h b/libion/kernel-headers/linux/ion.h
index 5af39d0..3c28080 100644
--- a/libion/kernel-headers/linux/ion.h
+++ b/libion/kernel-headers/linux/ion.h
@@ -38,7 +38,7 @@
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT)
 #define ION_HEAP_TYPE_DMA_MASK (1 << ION_HEAP_TYPE_DMA)
-#define ION_NUM_HEAP_IDS sizeof(unsigned int) * 8
+#define ION_NUM_HEAP_IDS (sizeof(unsigned int) * 8)
 #define ION_FLAG_CACHED 1
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define ION_FLAG_CACHED_NEEDS_SYNC 2
diff --git a/libion/tests/Android.bp b/libion/tests/Android.bp
new file mode 100644
index 0000000..4428848
--- /dev/null
+++ b/libion/tests/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "ion-unit-tests",
+    clang: true,
+    cflags: [
+        "-g",
+        "-Wall",
+        "-Werror",
+        "-Wno-missing-field-initializers",
+    ],
+    shared_libs: ["libion"],
+    srcs: [
+        "ion_test_fixture.cpp",
+        "allocate_test.cpp",
+        "formerly_valid_handle_test.cpp",
+        "invalid_values_test.cpp",
+        "map_test.cpp",
+        "device_test.cpp",
+        "exit_test.cpp",
+    ],
+}
diff --git a/libion/tests/Android.mk b/libion/tests/Android.mk
deleted file mode 100644
index 894f90e..0000000
--- a/libion/tests/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-#
-# Copyright (C) 2013 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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := ion-unit-tests
-LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers
-LOCAL_SHARED_LIBRARIES += libion
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/../kernel-headers
-LOCAL_SRC_FILES := \
-	ion_test_fixture.cpp \
-	allocate_test.cpp \
-	formerly_valid_handle_test.cpp \
-	invalid_values_test.cpp \
-	map_test.cpp \
-	device_test.cpp \
-	exit_test.cpp
-include $(BUILD_NATIVE_TEST)
diff --git a/libion/tests/allocate_test.cpp b/libion/tests/allocate_test.cpp
index e26b302..3c4524e 100644
--- a/libion/tests/allocate_test.cpp
+++ b/libion/tests/allocate_test.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <memory>
 #include <sys/mman.h>
 
 #include <gtest/gtest.h>
@@ -90,7 +91,7 @@
 
 TEST_F(Allocate, Zeroed)
 {
-    void *zeroes = calloc(4096, 1);
+    auto zeroes_ptr = std::make_unique<char[]>(4096);
 
     for (unsigned int heapMask : m_allHeaps) {
         SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
@@ -125,14 +126,11 @@
         ptr = mmap(NULL, 4096, PROT_READ, MAP_SHARED, map_fd, 0);
         ASSERT_TRUE(ptr != NULL);
 
-        ASSERT_EQ(0, memcmp(ptr, zeroes, 4096));
+        ASSERT_EQ(0, memcmp(ptr, zeroes_ptr.get(), 4096));
 
         ASSERT_EQ(0, munmap(ptr, 4096));
         ASSERT_EQ(0, close(map_fd));
     }
-
-    free(zeroes);
-
 }
 
 TEST_F(Allocate, Large)
diff --git a/libion/tests/device_test.cpp b/libion/tests/device_test.cpp
index 6f6e1bd..eb3f7b6 100644
--- a/libion/tests/device_test.cpp
+++ b/libion/tests/device_test.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <fcntl.h>
+#include <memory>
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -45,7 +46,7 @@
 void Device::SetUp()
 {
     IonAllHeapsTest::SetUp();
-    m_deviceFd = open("/dev/ion-test", O_RDWR);
+    m_deviceFd = open("/dev/ion-test", O_RDONLY);
     ASSERT_GE(m_deviceFd, 0);
 }
 
@@ -133,8 +134,8 @@
 
 TEST_F(Device, KernelReadCached)
 {
-    void *alloc = malloc(8192 + 1024);
-    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+    auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
 
     for (unsigned int heapMask : m_allHeaps) {
         SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
@@ -161,14 +162,12 @@
         ASSERT_EQ(0, munmap(ptr, 4096));
         ASSERT_EQ(0, close(map_fd));
     }
-
-    free(alloc);
 }
 
 TEST_F(Device, KernelWriteCached)
 {
-    void *alloc = malloc(8192 + 1024);
-    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+    auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
 
     for (int i = 0; i < 4096; i++)
         ((char *)buf)[i] = i;
@@ -195,14 +194,12 @@
         ASSERT_EQ(0, munmap(ptr, 4096));
         ASSERT_EQ(0, close(map_fd));
     }
-
-    free(alloc);
 }
 
 TEST_F(Device, DMAReadCached)
 {
-    void *alloc = malloc(8192 + 1024);
-    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+    auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
 
     for (unsigned int heapMask : m_allHeaps) {
         SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
@@ -227,14 +224,12 @@
         ASSERT_EQ(0, munmap(ptr, 4096));
         ASSERT_EQ(0, close(map_fd));
     }
-
-    free(alloc);
 }
 
 TEST_F(Device, DMAWriteCached)
 {
-    void *alloc = malloc(8192 + 1024);
-    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+    auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
 
     for (int i = 0; i < 4096; i++)
         ((char *)buf)[i] = i;
@@ -261,14 +256,12 @@
         ASSERT_EQ(0, munmap(ptr, 4096));
         ASSERT_EQ(0, close(map_fd));
     }
-
-    free(alloc);
 }
 
 TEST_F(Device, KernelReadCachedNeedsSync)
 {
-    void *alloc = malloc(8192 + 1024);
-    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+    auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
 
     for (unsigned int heapMask : m_allHeaps) {
         SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
@@ -295,14 +288,12 @@
         ASSERT_EQ(0, munmap(ptr, 4096));
         ASSERT_EQ(0, close(map_fd));
     }
-
-    free(alloc);
 }
 
 TEST_F(Device, KernelWriteCachedNeedsSync)
 {
-    void *alloc = malloc(8192 + 1024);
-    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+    auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
 
     for (int i = 0; i < 4096; i++)
         ((char *)buf)[i] = i;
@@ -329,14 +320,12 @@
         ASSERT_EQ(0, munmap(ptr, 4096));
         ASSERT_EQ(0, close(map_fd));
     }
-
-    free(alloc);
 }
 
 TEST_F(Device, DMAReadCachedNeedsSync)
 {
-    void *alloc = malloc(8192 + 1024);
-    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+    auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
 
     for (unsigned int heapMask : m_allHeaps) {
         SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
@@ -363,14 +352,12 @@
         ASSERT_EQ(0, munmap(ptr, 4096));
         ASSERT_EQ(0, close(map_fd));
     }
-
-    free(alloc);
 }
 
 TEST_F(Device, DMAWriteCachedNeedsSync)
 {
-    void *alloc = malloc(8192 + 1024);
-    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+    auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
 
     for (int i = 0; i < 4096; i++)
         ((char *)buf)[i] = i;
@@ -399,13 +386,11 @@
         ASSERT_EQ(0, munmap(ptr, 4096));
         ASSERT_EQ(0, close(map_fd));
     }
-
-    free(alloc);
 }
 TEST_F(Device, KernelRead)
 {
-    void *alloc = malloc(8192 + 1024);
-    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+    auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
 
     for (unsigned int heapMask : m_allHeaps) {
         SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
@@ -432,14 +417,12 @@
         ASSERT_EQ(0, munmap(ptr, 4096));
         ASSERT_EQ(0, close(map_fd));
     }
-
-    free(alloc);
 }
 
 TEST_F(Device, KernelWrite)
 {
-    void *alloc = malloc(8192 + 1024);
-    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+    auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
 
     for (int i = 0; i < 4096; i++)
         ((char *)buf)[i] = i;
@@ -466,14 +449,12 @@
         ASSERT_EQ(0, munmap(ptr, 4096));
         ASSERT_EQ(0, close(map_fd));
     }
-
-    free(alloc);
 }
 
 TEST_F(Device, DMARead)
 {
-    void *alloc = malloc(8192 + 1024);
-    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+    auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
 
     for (unsigned int heapMask : m_allHeaps) {
         SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
@@ -498,14 +479,12 @@
         ASSERT_EQ(0, munmap(ptr, 4096));
         ASSERT_EQ(0, close(map_fd));
     }
-
-    free(alloc);
 }
 
 TEST_F(Device, DMAWrite)
 {
-    void *alloc = malloc(8192 + 1024);
-    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+    auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
 
     for (int i = 0; i < 4096; i++)
         ((char *)buf)[i] = i;
@@ -532,13 +511,12 @@
         ASSERT_EQ(0, munmap(ptr, 4096));
         ASSERT_EQ(0, close(map_fd));
     }
-
-    free(alloc);
 }
 
 TEST_F(Device, IsCached)
 {
-    void *buf = malloc(4096);
+    auto buf_ptr = std::make_unique<char[]>(4096);
+    void *buf = buf_ptr.get();
 
     for (unsigned int heapMask : m_allHeaps) {
         SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 9c68fca..16aa4fa 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -24,7 +24,6 @@
 ]
 liblog_host_sources = [
     "fake_log_device.c",
-    //"event.logtags",
     "fake_writer.c",
 ]
 liblog_target_sources = [
@@ -56,7 +55,9 @@
         android: {
             srcs: liblog_target_sources,
             // AddressSanitizer runtime library depends on liblog.
-            sanitize: ["never"],
+            sanitize: {
+                never: true,
+            },
         },
         android_arm: {
             // TODO: This is to work around b/24465209. Remove after root cause is fixed
@@ -83,9 +84,31 @@
         //       's/^\([0-9]*\)[ \t]*liblog[ \t].*/-DLIBLOG_LOG_TAG=\1/p' \
         //       $(LOCAL_PATH)/event.logtags)
         // so make sure we do not regret hard-coding it as follows:
-        "-DLIBLOG_LOG_TAG=1005",
+        "-DLIBLOG_LOG_TAG=1006",
         "-DSNET_EVENT_LOG_TAG=1397638484",
     ],
+    logtags: ["event.logtags"],
     compile_multilib: "both",
-    stl: "none",
+}
+
+// system/core/android/log.h needs some work before it can be included in the
+// NDK. It defines a *lot* of macros that previously were usable names in NDK
+// sources that used android/log.h. As an example, the following file defines
+// LOG_TAG as a variable, but the variable name gets macro replaced if we use
+// the current android/log.h.
+// https://android.googlesource.com/platform/external/deqp/+/4adc1515f867b26c19c2f7498e9de93a230a234d/framework/platform/android/tcuTestLogParserJNI.cpp#41
+//
+// For now, we keep a copy of the old NDK android/log.h in legacy-ndk-includes.
+ndk_headers {
+    name: "liblog_headers",
+    from: "legacy-ndk-includes",
+    to: "android",
+    srcs: ["legacy-ndk-includes/log.h"],
+    license: "NOTICE",
+}
+
+ndk_library {
+    name: "liblog.ndk",
+    symbol_file: "liblog.map.txt",
+    first_version: "9",
 }
diff --git a/liblog/Android.mk b/liblog/Android.mk
index b24b489..6c4dff5 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -1,85 +1,3 @@
-#
-# Copyright (C) 2008-2014 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.
-#
 LOCAL_PATH := $(my-dir)
-include $(CLEAR_VARS)
-
-# This is what we want to do:
-#  liblog_cflags := $(shell \
-#   sed -n \
-#       's/^\([0-9]*\)[ \t]*liblog[ \t].*/-DLIBLOG_LOG_TAG=\1/p' \
-#       $(LOCAL_PATH)/event.logtags)
-# so make sure we do not regret hard-coding it as follows:
-liblog_cflags := -DLIBLOG_LOG_TAG=1005
-liblog_cflags += -DSNET_EVENT_LOG_TAG=1397638484
-
-liblog_sources := log_event_list.c log_event_write.c logger_write.c
-liblog_sources += config_write.c logger_name.c logger_lock.c
-liblog_host_sources := $(liblog_sources) fake_log_device.c event.logtags
-liblog_host_sources += fake_writer.c
-liblog_target_sources := $(liblog_sources) event_tag_map.c
-liblog_target_sources += config_read.c log_time.cpp log_is_loggable.c logprint.c
-liblog_target_sources += pmsg_reader.c pmsg_writer.c
-liblog_target_sources += logd_reader.c logd_writer.c logger_read.c
-
-# Shared and static library for host
-# ========================================================
-LOCAL_MODULE := liblog
-LOCAL_SRC_FILES := $(liblog_host_sources)
-# some files must not be compiled when building against Mingw
-# they correspond to features not used by our host development tools
-# which are also hard or even impossible to port to native Win32
-LOCAL_SRC_FILES_darwin := event_tag_map.c
-LOCAL_SRC_FILES_linux := event_tag_map.c
-LOCAL_SRC_FILES_windows := uio.c
-LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -Werror -fvisibility=hidden $(liblog_cflags)
-LOCAL_MULTILIB := both
-LOCAL_MODULE_HOST_OS := darwin linux windows
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := liblog
-LOCAL_WHOLE_STATIC_LIBRARIES := liblog
-LOCAL_LDLIBS_linux := -lrt
-LOCAL_MULTILIB := both
-LOCAL_CXX_STL := none
-LOCAL_MODULE_HOST_OS := darwin linux windows
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-
-# Shared and static library for target
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := liblog
-LOCAL_SRC_FILES := $(liblog_target_sources)
-LOCAL_CFLAGS := -Werror -fvisibility=hidden $(liblog_cflags)
-# AddressSanitizer runtime library depends on liblog.
-LOCAL_SANITIZE := never
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := liblog
-LOCAL_WHOLE_STATIC_LIBRARIES := liblog
-LOCAL_CFLAGS := -Werror -fvisibility=hidden $(liblog_cflags)
-
-# TODO: This is to work around b/24465209. Remove after root cause is fixed
-LOCAL_LDFLAGS_arm := -Wl,--hash-style=both
-
-LOCAL_SANITIZE := never
-LOCAL_CXX_STL := none
-
-include $(BUILD_SHARED_LIBRARY)
 
 include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/liblog/README b/liblog/README
index df1e68c..610338c 100644
--- a/liblog/README
+++ b/liblog/README
@@ -1,11 +1,17 @@
-LIBLOG(3)               Android NDK Programming Manual               LIBLOG(3)
+LIBLOG(3)          Android Internal NDK Programming Manual           LIBLOG(3)
 
 
 
 NAME
-       liblog - Android NDK logger interfaces
+       liblog - Android Internal NDK logger interfaces
 
 SYNOPSIS
+       /*
+        * Please limit to 24 characters for runtime is loggable,
+        * 16 characters for persist is loggable, and logcat pretty
+        * alignment with limit of 7 characters.
+        */
+       #define LOG_TAG "yourtag"
        #include <log/log.h>
 
        ALOG(android_priority, tag, format, ...)
@@ -56,9 +62,7 @@
        LOG_EVENT_INT(tag, value)
        LOG_EVENT_LONG(tag, value)
 
-       Link with -llog
-
-       #include <log/logger.h>
+       clockid_t android_log_clockid()
 
        log_id_t android_logger_get_id(struct logger *logger)
        int android_logger_clear(struct logger *logger)
@@ -66,21 +70,44 @@
        int android_logger_get_log_readable_size(struct logger *logger)
        int android_logger_get_log_version(struct logger *logger)
 
-       struct  logger_list  *android_logger_list_alloc(int  mode, unsigned int
-       tail, pid_t pid)
-       struct  logger  *android_logger_open(struct  logger_list  *logger_list,
-       log_id_t id)
-       struct  logger_list  *android_logger_list_open(log_id_t  id,  int mode,
-       unsigned int tail, pid_t pid)
-
-       int android_logger_list_read(struct  logger_list  *logger_list,  struct
-       log_msg *log_msg
-
+       struct logger_list *android_logger_list_alloc(int mode,
+                                                     unsigned int tail,
+                                                     pid_t pid)
+       struct logger *android_logger_open(struct logger_list *logger_list,
+                                          log_id_t id)
+       struct logger_list *android_logger_list_open(log_id_t id, int mode,
+                                                    unsigned int tail,
+                                                    pid_t pid)
+       int android_logger_list_read(struct logger_list *logger_list,
+                                    struct log_msg *log_msg)
        void android_logger_list_free(struct logger_list *logger_list)
 
        log_id_t android_name_to_log_id(const char *logName)
        const char *android_log_id_to_name(log_id_t log_id)
 
+       android_log_context create_android_logger(uint32_t tag)
+
+       int android_log_write_list_begin(android_log_context ctx)
+       int android_log_write_list_end(android_log_context ctx)
+
+       int android_log_write_int32(android_log_context ctx, int32_t value)
+       int android_log_write_int64(android_log_context ctx, int64_t value)
+       int android_log_write_string8(android_log_context ctx,
+                                     const char *value)
+       int android_log_write_string8_len(android_log_context ctx,
+                                         const char *value, size_t maxlen)
+       int android_log_write_float32(android_log_context ctx, float value)
+
+       int android_log_write_list(android_log_context ctx,
+                                  log_id_t id = LOG_ID_EVENTS)
+
+       android_log_context create_android_log_parser(const char *msg,
+                                                     size_t len)
+       android_log_list_element android_log_read_next(android_log_context ctx)
+       android_log_list_element android_log_peek_next(android_log_context ctx)
+
+       int android_log_destroy(android_log_context *ctx)
+
        Link with -llog
 
 DESCRIPTION
@@ -163,8 +190,8 @@
        library retries on EINTR, -EINTR should never be returned.
 
 SEE ALSO
-       syslogd(8)
+       syslogd(8), klogd, auditd(8)
 
 
 
-                                  24 Jan 2014                        LIBLOG(3)
+                                  17 Oct 2016                        LIBLOG(3)
diff --git a/liblog/config_read.h b/liblog/config_read.h
index 67f4c20..49a3b75 100644
--- a/liblog/config_read.h
+++ b/liblog/config_read.h
@@ -27,21 +27,21 @@
 extern LIBLOG_HIDDEN struct listnode __android_log_persist_read;
 
 #define read_transport_for_each(transp, transports)                         \
-    for (transp = node_to_item((transports)->next,                          \
+    for ((transp) = node_to_item((transports)->next,                        \
                                struct android_log_transport_read, node);    \
-         (transp != node_to_item(transports,                                \
+         ((transp) != node_to_item(transports,                              \
                                  struct android_log_transport_read, node)); \
-         transp = node_to_item(transp->node.next,                           \
+         (transp) = node_to_item((transp)->node.next,                       \
                                struct android_log_transport_read, node))    \
 
 #define read_transport_for_each_safe(transp, n, transports)                 \
-    for (transp = node_to_item((transports)->next,                          \
+    for ((transp) = node_to_item((transports)->next,                        \
                                struct android_log_transport_read, node),    \
-         n = transp->node.next;                                             \
-         (transp != node_to_item(transports,                                \
+         (n) = (transp)->node.next;                                         \
+         ((transp) != node_to_item(transports,                              \
                                  struct android_log_transport_read, node)); \
-         transp = node_to_item(n, struct android_log_transport_read, node), \
-         n = transp->node.next)
+         (transp) = node_to_item(n, struct android_log_transport_read, node), \
+         (n) = (transp)->node.next)
 
 LIBLOG_HIDDEN void __android_log_config_read();
 
diff --git a/liblog/config_write.h b/liblog/config_write.h
index 3a02a4e..3b01a9a 100644
--- a/liblog/config_write.h
+++ b/liblog/config_write.h
@@ -27,21 +27,21 @@
 extern LIBLOG_HIDDEN struct listnode __android_log_persist_write;
 
 #define write_transport_for_each(transp, transports)                         \
-    for (transp = node_to_item((transports)->next,                           \
-                               struct android_log_transport_write, node);    \
-         (transp != node_to_item(transports,                                 \
+    for ((transp) = node_to_item((transports)->next,                         \
+                                 struct android_log_transport_write, node);  \
+         ((transp) != node_to_item(transports,                               \
                                  struct android_log_transport_write, node)); \
-         transp = node_to_item(transp->node.next,                            \
-                               struct android_log_transport_write, node))    \
+         (transp) = node_to_item((transp)->node.next,                        \
+                                 struct android_log_transport_write, node))  \
 
 #define write_transport_for_each_safe(transp, n, transports)                 \
-    for (transp = node_to_item((transports)->next,                           \
-                               struct android_log_transport_write, node),    \
-         n = transp->node.next;                                              \
-         (transp != node_to_item(transports,                                 \
-                                 struct android_log_transport_write, node)); \
-         transp = node_to_item(n, struct android_log_transport_write, node), \
-         n = transp->node.next)
+    for ((transp) = node_to_item((transports)->next,                         \
+                                 struct android_log_transport_write, node),  \
+         (n) = (transp)->node.next;                                          \
+         ((transp) != node_to_item(transports,                               \
+                                   struct android_log_transport_write, node)); \
+         (transp) = node_to_item(n, struct android_log_transport_write, node), \
+         (n) = (transp)->node.next)
 
 LIBLOG_HIDDEN void __android_log_config_write();
 
diff --git a/liblog/event.logtags b/liblog/event.logtags
index 72ecab1..301e885 100644
--- a/liblog/event.logtags
+++ b/liblog/event.logtags
@@ -33,4 +33,4 @@
 #
 # TODO: generate ".java" and ".h" files with integer constants from this file.
 
-1005  liblog (dropped|1)
+1006  liblog (dropped|1)
diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c
index 345f0d3..f9cad99 100644
--- a/liblog/event_tag_map.c
+++ b/liblog/event_tag_map.c
@@ -15,14 +15,17 @@
  */
 
 #include <assert.h>
+#include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/mman.h>
 
+#include <android/log.h>
 #include <log/event_tag_map.h>
-#include <log/log.h>
 
 #include "log_portability.h"
 
@@ -32,8 +35,11 @@
  * Single entry.
  */
 typedef struct EventTag {
-    unsigned int    tagIndex;
-    const char*     tagStr;
+    uint32_t tagIndex;
+    char*    tagStr;
+    size_t   tagLen;
+    char*    fmtStr;
+    size_t   fmtLen;
 } EventTag;
 
 /*
@@ -56,7 +62,6 @@
 static int scanTagLine(char** pData, EventTag* tag, int lineNum);
 static int sortTags(EventTagMap* map);
 
-
 /*
  * Open the map file and allocate a structure to manage it.
  *
@@ -67,47 +72,57 @@
 {
     EventTagMap* newTagMap;
     off_t end;
-    int fd = -1;
+    int save_errno;
 
-    newTagMap = calloc(1, sizeof(EventTagMap));
-    if (newTagMap == NULL)
-        return NULL;
-
-    fd = open(fileName, O_RDONLY | O_CLOEXEC);
+    int fd = open(fileName, O_RDONLY | O_CLOEXEC);
     if (fd < 0) {
+        save_errno = errno;
         fprintf(stderr, "%s: unable to open map '%s': %s\n",
-            OUT_TAG, fileName, strerror(errno));
-        goto fail;
+                OUT_TAG, fileName, strerror(save_errno));
+        goto fail_errno;
     }
 
     end = lseek(fd, 0L, SEEK_END);
+    save_errno = errno;
     (void) lseek(fd, 0L, SEEK_SET);
     if (end < 0) {
-        fprintf(stderr, "%s: unable to seek map '%s'\n", OUT_TAG, fileName);
-        goto fail;
+        fprintf(stderr, "%s: unable to seek map '%s' %s\n",
+                OUT_TAG, fileName, strerror(save_errno));
+        goto fail_close;
     }
 
-    newTagMap->mapAddr = mmap(NULL, end, PROT_READ | PROT_WRITE, MAP_PRIVATE,
-                                fd, 0);
-    if (newTagMap->mapAddr == MAP_FAILED) {
-        fprintf(stderr, "%s: mmap(%s) failed: %s\n",
-            OUT_TAG, fileName, strerror(errno));
-        goto fail;
+    newTagMap = (EventTagMap*)calloc(1, sizeof(EventTagMap));
+    if (newTagMap == NULL) {
+        save_errno = errno;
+        goto fail_close;
     }
+
+    newTagMap->mapAddr = mmap(NULL, end, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+    save_errno = errno;
+    close(fd);
+    fd = -1;
+    if ((newTagMap->mapAddr == MAP_FAILED) || (newTagMap->mapAddr == NULL)) {
+        fprintf(stderr, "%s: mmap(%s) failed: %s\n",
+                OUT_TAG, fileName, strerror(save_errno));
+        goto fail_free;
+    }
+
     newTagMap->mapLen = end;
 
-    if (processFile(newTagMap) != 0)
-        goto fail;
-
-    if (fd >= 0)
-      close(fd);
+    if (processFile(newTagMap) != 0) goto fail_unmap;
 
     return newTagMap;
 
+fail_unmap:
+    munmap(newTagMap->mapAddr, newTagMap->mapLen);
+    save_errno = EINVAL;
+fail_free:
+    free(newTagMap);
+fail_close:
+    close(fd);
+fail_errno:
+    errno = save_errno;
 fail:
-    android_closeEventTagMap(newTagMap);
-    if (fd >= 0)
-        close(fd);
     return NULL;
 }
 
@@ -116,10 +131,10 @@
  */
 LIBLOG_ABI_PUBLIC void android_closeEventTagMap(EventTagMap* map)
 {
-    if (map == NULL)
-        return;
+    if (map == NULL) return;
 
     munmap(map->mapAddr, map->mapLen);
+    free(map->tagArray);
     free(map);
 }
 
@@ -128,19 +143,17 @@
  *
  * The entries are sorted by tag number, so we can do a binary search.
  */
-LIBLOG_ABI_PUBLIC const char* android_lookupEventTag(const EventTagMap* map,
-                                                     int tag)
+LIBLOG_ABI_PUBLIC const char* android_lookupEventTag_len(const EventTagMap* map,
+                                                         size_t *len,
+                                                         unsigned int tag)
 {
-    int hi, lo, mid;
-
-    lo = 0;
-    hi = map->numTags-1;
+    int lo = 0;
+    int hi = map->numTags - 1;
 
     while (lo <= hi) {
-        int cmp;
+        int mid = (lo + hi) / 2;
+        int cmp = map->tagArray[mid].tagIndex - tag;
 
-        mid = (lo+hi)/2;
-        cmp = map->tagArray[mid].tagIndex - tag;
         if (cmp < 0) {
             /* tag is bigger */
             lo = mid + 1;
@@ -149,43 +162,69 @@
             hi = mid - 1;
         } else {
             /* found */
+            if (len) *len = map->tagArray[mid].tagLen;
+            /*
+             * b/31456426 to check if gTest can detect copy-on-write issue
+             * add the following line to break us:
+             *     map->tagArray[mid].tagStr[map->tagArray[mid].tagLen] = '\0';
+             * or explicitly use deprecated android_lookupEventTag().
+             */
             return map->tagArray[mid].tagStr;
         }
     }
 
+    errno = ENOENT;
+    if (len) *len = 0;
     return NULL;
 }
 
-
-
 /*
- * Determine whether "c" is a whitespace char.
+ * Look up an entry in the map.
+ *
+ * The entries are sorted by tag number, so we can do a binary search.
  */
-static inline int isCharWhitespace(char c)
+LIBLOG_ABI_PUBLIC const char* android_lookupEventFormat_len(
+    const EventTagMap* map, size_t *len, unsigned int tag)
 {
-    return (c == ' ' || c == '\n' || c == '\r' || c == '\t');
+    int lo = 0;
+    int hi = map->numTags - 1;
+
+    while (lo <= hi) {
+        int mid = (lo + hi) / 2;
+        int cmp = map->tagArray[mid].tagIndex - tag;
+
+        if (cmp < 0) {
+            /* tag is bigger */
+            lo = mid + 1;
+        } else if (cmp > 0) {
+            /* tag is smaller */
+            hi = mid - 1;
+        } else {
+            /* found */
+            if (len) *len = map->tagArray[mid].fmtLen;
+            return map->tagArray[mid].fmtStr;
+        }
+    }
+
+    errno = ENOENT;
+    if (len) *len = 0;
+    return NULL;
 }
 
-/*
- * Determine whether "c" is a valid tag char.
- */
-static inline int isCharValidTag(char c)
+LIBLOG_ABI_PUBLIC const char* android_lookupEventTag(const EventTagMap* map,
+                                                     unsigned int tag)
 {
-    return ((c >= 'A' && c <= 'Z') ||
-            (c >= 'a' && c <= 'z') ||
-            (c >= '0' && c <= '9') ||
-            (c == '_'));
-}
+    size_t len;
+    const char* tagStr = android_lookupEventTag_len(map, &len, tag);
+    char* cp;
 
-/*
- * Determine whether "c" is a valid decimal digit.
- */
-static inline int isCharDigit(char c)
-{
-    return (c >= '0' && c <= '9');
+    if (!tagStr) return tagStr;
+    cp = (char*)tagStr;
+    cp += len;
+    if (*cp) *cp = '\0'; /* Trigger copy on write :-( */
+    return tagStr;
 }
 
-
 /*
  * Crunch through the file, parsing the contents and creating a tag index.
  */
@@ -193,25 +232,20 @@
 {
     /* get a tag count */
     map->numTags = countMapLines(map);
-    if (map->numTags < 0)
-        return -1;
-
-    //printf("+++ found %d tags\n", map->numTags);
-
-    /* allocate storage for the tag index array */
-    map->tagArray = calloc(1, sizeof(EventTag) * map->numTags);
-    if (map->tagArray == NULL)
-        return -1;
-
-    /* parse the file, null-terminating tag strings */
-    if (parseMapLines(map) != 0) {
-        fprintf(stderr, "%s: file parse failed\n", OUT_TAG);
+    if (map->numTags < 0) {
+        errno = ENOENT;
         return -1;
     }
 
+    /* allocate storage for the tag index array */
+    map->tagArray = (EventTag*)calloc(1, sizeof(EventTag) * map->numTags);
+    if (map->tagArray == NULL) return -1;
+
+    /* parse the file, null-terminating tag strings */
+    if (parseMapLines(map) != 0) return -1;
+
     /* sort the tags and check for duplicates */
-    if (sortTags(map) != 0)
-        return -1;
+    if (sortTags(map) != 0) return -1;
 
     return 0;
 }
@@ -228,24 +262,20 @@
  */
 static int countMapLines(const EventTagMap* map)
 {
-    int numTags, unknown;
-    const char* cp;
-    const char* endp;
+    const char* cp = (const char*) map->mapAddr;
+    const char* endp = cp + map->mapLen;
+    int numTags = 0;
+    int unknown = 1;
 
-    cp = (const char*) map->mapAddr;
-    endp = cp + map->mapLen;
-
-    numTags = 0;
-    unknown = 1;
     while (cp < endp) {
         if (*cp == '\n') {
             unknown = 1;
         } else if (unknown) {
-            if (isCharDigit(*cp)) {
+            if (isdigit(*cp)) {
                 /* looks like a tag to me */
                 numTags++;
                 unknown = 0;
-            } else if (isCharWhitespace(*cp)) {
+            } else if (isspace(*cp)) {
                 /* might be leading whitespace before tag num, keep going */
             } else {
                 /* assume comment; second pass can complain in detail */
@@ -266,15 +296,13 @@
 static int parseMapLines(EventTagMap* map)
 {
     int tagNum, lineStart, lineNum;
-    char* cp;
-    char* endp;
-
-    cp = (char*) map->mapAddr;
-    endp = cp + map->mapLen;
+    char* cp = (char*) map->mapAddr;
+    char* endp = cp + map->mapLen;
 
     /* insist on EOL at EOF; simplifies parsing and null-termination */
-    if (*(endp-1) != '\n') {
+    if (*(endp - 1) != '\n') {
         fprintf(stderr, "%s: map file missing EOL on last line\n", OUT_TAG);
+        errno = EINVAL;
         return -1;
     }
 
@@ -282,7 +310,6 @@
     lineStart = 1;
     lineNum = 1;
     while (cp < endp) {
-        //printf("{%02x}", *cp); fflush(stdout);
         if (*cp == '\n') {
             lineStart = 1;
             lineNum++;
@@ -290,24 +317,27 @@
             if (*cp == '#') {
                 /* comment; just scan to end */
                 lineStart = 0;
-            } else if (isCharDigit(*cp)) {
+            } else if (isdigit(*cp)) {
                 /* looks like a tag; scan it out */
                 if (tagNum >= map->numTags) {
                     fprintf(stderr,
                         "%s: more tags than expected (%d)\n", OUT_TAG, tagNum);
+                    errno = EMFILE;
                     return -1;
                 }
-                if (scanTagLine(&cp, &map->tagArray[tagNum], lineNum) != 0)
+                if (scanTagLine(&cp, &map->tagArray[tagNum], lineNum) != 0) {
                     return -1;
+                }
                 tagNum++;
                 lineNum++;      // we eat the '\n'
                 /* leave lineStart==1 */
-            } else if (isCharWhitespace(*cp)) {
+            } else if (isspace(*cp)) {
                 /* looks like leading whitespace; keep scanning */
             } else {
                 fprintf(stderr,
                     "%s: unexpected chars (0x%02x) in tag number on line %d\n",
                     OUT_TAG, *cp, lineNum);
+                errno = EINVAL;
                 return -1;
             }
         } else {
@@ -319,6 +349,7 @@
     if (tagNum != map->numTags) {
         fprintf(stderr, "%s: parsed %d tags, expected %d\n",
             OUT_TAG, tagNum, map->numTags);
+        errno = EINVAL;
         return -1;
     }
 
@@ -336,58 +367,55 @@
  */
 static int scanTagLine(char** pData, EventTag* tag, int lineNum)
 {
-    char* cp = *pData;
-    char* startp;
-    char* endp;
-    unsigned long val;
+    char* cp;
 
-    startp = cp;
-    while (isCharDigit(*++cp))
-        ;
-    *cp = '\0';
-
-    val = strtoul(startp, &endp, 10);
-    assert(endp == cp);
-    if (endp != cp)
-        fprintf(stderr, "ARRRRGH\n");
+    unsigned long val = strtoul(*pData, &cp, 10);
+    if (cp == *pData) {
+        fprintf(stderr, "%s: malformed tag number on line %d\n", OUT_TAG, lineNum);
+        errno = EINVAL;
+        return -1;
+    }
 
     tag->tagIndex = val;
+    if (tag->tagIndex != val) {
+        fprintf(stderr, "%s: tag number too large on line %d\n", OUT_TAG, lineNum);
+        errno = ERANGE;
+        return -1;
+    }
 
-    while (*++cp != '\n' && isCharWhitespace(*cp))
-        ;
+    while ((*++cp != '\n') && isspace(*cp)) {
+    }
 
     if (*cp == '\n') {
-        fprintf(stderr,
-            "%s: missing tag string on line %d\n", OUT_TAG, lineNum);
+        fprintf(stderr, "%s: missing tag string on line %d\n", OUT_TAG, lineNum);
+        errno = EINVAL;
         return -1;
     }
 
     tag->tagStr = cp;
 
-    while (isCharValidTag(*++cp))
-        ;
+    /* Determine whether "c" is a valid tag char. */
+    while (isalnum(*++cp) || (*cp == '_')) {
+    }
+    tag->tagLen = cp - tag->tagStr;
 
-    if (*cp == '\n') {
-        /* null terminate and return */
-        *cp = '\0';
-    } else if (isCharWhitespace(*cp)) {
-        /* CRLF or trailin spaces; zap this char, then scan for the '\n' */
-        *cp = '\0';
-
-        /* just ignore the rest of the line till \n
-        TODO: read the tag description that follows the tag name
-        */
-        while (*++cp != '\n') {
-        }
-    } else {
-        fprintf(stderr,
-            "%s: invalid tag chars on line %d\n", OUT_TAG, lineNum);
+    if (!isspace(*cp)) {
+        fprintf(stderr, "%s: invalid tag chars on line %d\n", OUT_TAG, lineNum);
+        errno = EINVAL;
         return -1;
     }
 
+    while (isspace(*cp) && (*cp != '\n')) ++cp;
+    if (*cp != '#') {
+        tag->fmtStr = cp;
+        while ((*cp != '\n') && (*cp != '#')) ++cp;
+        while ((cp > tag->fmtStr) && isspace(*(cp - 1))) --cp;
+        tag->fmtLen = cp - tag->fmtStr;
+    }
+
+    while (*cp != '\n') ++cp;
     *pData = cp;
 
-    //printf("+++ Line %d: got %d '%s'\n", lineNum, tag->tagIndex, tag->tagStr);
     return 0;
 }
 
@@ -415,11 +443,17 @@
     qsort(map->tagArray, map->numTags, sizeof(EventTag), compareEventTags);
 
     for (i = 1; i < map->numTags; i++) {
-        if (map->tagArray[i].tagIndex == map->tagArray[i-1].tagIndex) {
-            fprintf(stderr, "%s: duplicate tag entries (%d:%s and %d:%s)\n",
+        if (map->tagArray[i].tagIndex == map->tagArray[i - 1].tagIndex) {
+            fprintf(stderr,
+                "%s: duplicate tag entries (%" PRIu32 ":%.*s:%.*s and %" PRIu32 ":%.*s:%.*s)\n",
                 OUT_TAG,
-                map->tagArray[i].tagIndex, map->tagArray[i].tagStr,
-                map->tagArray[i-1].tagIndex, map->tagArray[i-1].tagStr);
+                map->tagArray[i].tagIndex,
+                (int)map->tagArray[i].tagLen, map->tagArray[i].tagStr,
+                (int)map->tagArray[i].fmtLen, map->tagArray[i].fmtStr,
+                map->tagArray[i - 1].tagIndex,
+                (int)map->tagArray[i - 1].tagLen, map->tagArray[i - 1].fmtStr,
+                (int)map->tagArray[i - 1].fmtLen, map->tagArray[i - 1].fmtStr);
+            errno = EMLINK;
             return -1;
         }
     }
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index cc67f3e..4939221 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -25,10 +25,14 @@
 #if !defined(_WIN32)
 #include <pthread.h>
 #endif
+#include <stdint.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <time.h>
 
-#include <log/logd.h>
+#include <android/log.h>
+#include <log/uio.h>
 
 #include "fake_log_device.h"
 #include "log_portability.h"
@@ -718,3 +722,17 @@
     int logLevel = def;
     return logLevel >= 0 && prio >= logLevel;
 }
+
+LIBLOG_ABI_PUBLIC int __android_log_is_loggable_len(int prio,
+                                                    const char *tag __unused,
+                                                    size_t len __unused,
+                                                    int def)
+{
+    int logLevel = def;
+    return logLevel >= 0 && prio >= logLevel;
+}
+
+LIBLOG_ABI_PRIVATE int __android_log_is_debuggable()
+{
+    return 1;
+}
diff --git a/liblog/legacy-ndk-includes/log.h b/liblog/legacy-ndk-includes/log.h
new file mode 100644
index 0000000..0ea4c29
--- /dev/null
+++ b/liblog/legacy-ndk-includes/log.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_LOG_H
+#define _ANDROID_LOG_H
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ *   This file is part of Android's set of stable system headers
+ *   exposed by the Android NDK (Native Development Kit) since
+ *   platform release 1.5
+ *
+ *   Third-party source AND binary code relies on the definitions
+ *   here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ *   - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ *   - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ *   - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ *   - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+/*
+ * Support routines to send messages to the Android in-kernel log buffer,
+ * which can later be accessed through the 'logcat' utility.
+ *
+ * Each log message must have
+ *   - a priority
+ *   - a log tag
+ *   - some text
+ *
+ * The tag normally corresponds to the component that emits the log message,
+ * and should be reasonably small.
+ *
+ * Log message text may be truncated to less than an implementation-specific
+ * limit (e.g. 1023 characters max).
+ *
+ * Note that a newline character ("\n") will be appended automatically to your
+ * log message, if not already there. It is not possible to send several messages
+ * and have them appear on a single line in logcat.
+ *
+ * PLEASE USE LOGS WITH MODERATION:
+ *
+ *  - Sending log messages eats CPU and slow down your application and the
+ *    system.
+ *
+ *  - The circular log buffer is pretty small (<64KB), sending many messages
+ *    might push off other important log messages from the rest of the system.
+ *
+ *  - In release builds, only send log messages to account for exceptional
+ *    conditions.
+ *
+ * NOTE: These functions MUST be implemented by /system/lib/liblog.so
+ */
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Android log priority values, in ascending priority order.
+ */
+typedef enum android_LogPriority {
+    ANDROID_LOG_UNKNOWN = 0,
+    ANDROID_LOG_DEFAULT,    /* only for SetMinPriority() */
+    ANDROID_LOG_VERBOSE,
+    ANDROID_LOG_DEBUG,
+    ANDROID_LOG_INFO,
+    ANDROID_LOG_WARN,
+    ANDROID_LOG_ERROR,
+    ANDROID_LOG_FATAL,
+    ANDROID_LOG_SILENT,     /* only for SetMinPriority(); must be last */
+} android_LogPriority;
+
+/*
+ * Send a simple string to the log.
+ */
+int __android_log_write(int prio, const char *tag, const char *text);
+
+/*
+ * Send a formatted string to the log, used like printf(fmt,...)
+ */
+int __android_log_print(int prio, const char *tag,  const char *fmt, ...)
+#if defined(__GNUC__)
+    __attribute__ ((format(printf, 3, 4)))
+#endif
+    ;
+
+/*
+ * A variant of __android_log_print() that takes a va_list to list
+ * additional parameters.
+ */
+int __android_log_vprint(int prio, const char *tag,
+                         const char *fmt, va_list ap);
+
+/*
+ * Log an assertion failure and SIGTRAP the process to have a chance
+ * to inspect it, if a debugger is attached. This uses the FATAL priority.
+ */
+void __android_log_assert(const char *cond, const char *tag,
+			  const char *fmt, ...)    
+#if defined(__GNUC__)
+    __attribute__ ((noreturn))
+    __attribute__ ((format(printf, 3, 4)))
+#endif
+    ;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ANDROID_LOG_H */
diff --git a/liblog/liblog.map.txt b/liblog/liblog.map.txt
new file mode 100644
index 0000000..599dc90
--- /dev/null
+++ b/liblog/liblog.map.txt
@@ -0,0 +1,19 @@
+LIBLOG {
+  global:
+    __android_log_assert;
+    __android_log_print;
+    __android_log_vprint;
+    __android_log_write;
+  local:
+    *;
+};
+
+LIBLOG_M {
+  global:
+    __android_log_is_loggable;
+};
+
+LIBLOG_O {
+  global:
+    __android_log_is_loggable_len;
+};
diff --git a/liblog/log_event_list.c b/liblog/log_event_list.c
index 64d9024..9ac1d30 100644
--- a/liblog/log_event_list.c
+++ b/liblog/log_event_list.c
@@ -22,8 +22,8 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <log/log.h>
-#include <log/logger.h>
+#include <log/log_event_list.h>
+#include <private/android_logger.h>
 
 #include "log_portability.h"
 
@@ -320,7 +320,7 @@
     context->storage[1] = context->count[0];
     len = context->len = context->pos;
     msg = (const char *)context->storage;
-    /* it'snot a list */
+    /* it's not a list */
     if (context->count[0] <= 1) {
         len -= sizeof(uint8_t) + sizeof(uint8_t);
         if (len < 0) {
@@ -333,6 +333,38 @@
         __android_log_security_bwrite(context->tag, msg, len);
 }
 
+LIBLOG_ABI_PRIVATE int android_log_write_list_buffer(android_log_context ctx,
+                                                     const char **buffer) {
+    android_log_context_internal *context;
+    const char *msg;
+    ssize_t len;
+
+    context = (android_log_context_internal *)ctx;
+    if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+        return -EBADF;
+    }
+    if (context->list_nest_depth) {
+        return -EIO;
+    }
+    if (buffer == NULL) {
+        return -EFAULT;
+    }
+    /* NB: if there was overflow, then log is truncated. Nothing reported */
+    context->storage[1] = context->count[0];
+    len = context->len = context->pos;
+    msg = (const char *)context->storage;
+    /* it's not a list */
+    if (context->count[0] <= 1) {
+        len -= sizeof(uint8_t) + sizeof(uint8_t);
+        if (len < 0) {
+            len = 0;
+        }
+        msg += sizeof(uint8_t) + sizeof(uint8_t);
+    }
+    *buffer = msg;
+    return len;
+}
+
 /*
  * Extract a 4-byte value from a byte stream.
  */
diff --git a/liblog/log_event_write.c b/liblog/log_event_write.c
index b9827a1..14d6482 100644
--- a/liblog/log_event_write.c
+++ b/liblog/log_event_write.c
@@ -15,8 +15,10 @@
  */
 
 #include <errno.h>
+#include <stdint.h>
 
 #include <log/log.h>
+#include <log/log_event_list.h>
 
 #include "log_portability.h"
 
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
index bd8d5af..dda09e0 100644
--- a/liblog/log_is_loggable.c
+++ b/liblog/log_is_loggable.c
@@ -16,12 +16,14 @@
 
 #include <ctype.h>
 #include <pthread.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
 #include <sys/_system_properties.h>
+#include <unistd.h>
 
-#include <android/log.h>
+#include <private/android_logger.h>
 
 #include "log_portability.h"
 
@@ -47,12 +49,16 @@
 }
 
 struct cache {
-    const prop_info *pinfo;
+    const prop_info* pinfo;
     uint32_t serial;
+};
+
+struct cache_char {
+    struct cache cache;
     unsigned char c;
 };
 
-static int check_cache(struct cache *cache)
+static int check_cache(struct cache* cache)
 {
     return cache->pinfo
         && __system_property_serial(cache->pinfo) != cache->serial;
@@ -61,18 +67,18 @@
 #define BOOLEAN_TRUE 0xFF
 #define BOOLEAN_FALSE 0xFE
 
-static void refresh_cache(struct cache *cache, const char *key)
+static void refresh_cache(struct cache_char* cache, const char* key)
 {
     char buf[PROP_VALUE_MAX];
 
-    if (!cache->pinfo) {
-        cache->pinfo = __system_property_find(key);
-        if (!cache->pinfo) {
+    if (!cache->cache.pinfo) {
+        cache->cache.pinfo = __system_property_find(key);
+        if (!cache->cache.pinfo) {
             return;
         }
     }
-    cache->serial = __system_property_serial(cache->pinfo);
-    __system_property_read(cache->pinfo, 0, buf);
+    cache->cache.serial = __system_property_serial(cache->cache.pinfo);
+    __system_property_read(cache->cache.pinfo, 0, buf);
     switch(buf[0]) {
     case 't': case 'T':
         cache->c = strcasecmp(buf + 1, "rue") ? buf[0] : BOOLEAN_TRUE;
@@ -85,16 +91,16 @@
     }
 }
 
-static int __android_log_level(const char *tag, int default_prio)
+static int __android_log_level(const char* tag, size_t len, int default_prio)
 {
     /* sizeof() is used on this array below */
     static const char log_namespace[] = "persist.log.tag.";
     static const size_t base_offset = 8; /* skip "persist." */
     /* calculate the size of our key temporary buffer */
-    const size_t taglen = (tag && *tag) ? strlen(tag) : 0;
+    const size_t taglen = tag ? len : 0;
     /* sizeof(log_namespace) = strlen(log_namespace) + 1 */
-    char key[sizeof(log_namespace) + taglen]; /* may be > PROPERTY_KEY_MAX */
-    char *kp;
+    char key[sizeof(log_namespace) + taglen]; /* may be > PROP_NAME_MAX */
+    char* kp;
     size_t i;
     char c = 0;
     /*
@@ -110,8 +116,8 @@
     static uint32_t global_serial;
     /* some compilers erroneously see uninitialized use. !not_locked */
     uint32_t current_global_serial = 0;
-    static struct cache tag_cache[2];
-    static struct cache global_cache[2];
+    static struct cache_char tag_cache[2];
+    static struct cache_char global_cache[2];
     int change_detected;
     int global_change_detected;
     int not_locked;
@@ -125,12 +131,12 @@
          *  check all known serial numbers to changes.
          */
         for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
-            if (check_cache(&tag_cache[i])) {
+            if (check_cache(&tag_cache[i].cache)) {
                 change_detected = 1;
             }
         }
         for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
-            if (check_cache(&global_cache[i])) {
+            if (check_cache(&global_cache[i].cache)) {
                 global_change_detected = 1;
             }
         }
@@ -147,28 +153,38 @@
         if (!not_locked) {
             if (!last_tag[0]
                     || (last_tag[0] != tag[0])
-                    || strncmp(last_tag + 1, tag + 1, sizeof(last_tag) - 1)) {
+                    || strncmp(last_tag + 1, tag + 1,
+                               (len < sizeof(last_tag)) ?
+                                    (len - 1) :
+                                    (sizeof(last_tag) - 1))
+                    || ((len < sizeof(last_tag)) && last_tag[len])) {
                 /* 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].cache.pinfo = NULL;
                     tag_cache[i].c = '\0';
                 }
                 last_tag[0] = '\0';
                 local_change_detected = 1;
             }
             if (!last_tag[0]) {
-                strncpy(last_tag, tag, sizeof(last_tag));
+                if (len < sizeof(last_tag)) {
+                    strncpy(last_tag, tag, len);
+                    last_tag[len] = '\0';
+                } else {
+                    strncpy(last_tag, tag, sizeof(last_tag));
+                }
             }
         }
-        strcpy(key + sizeof(log_namespace) - 1, tag);
+        strncpy(key + sizeof(log_namespace) - 1, tag, len);
+        key[sizeof(log_namespace) - 1 + len] = '\0';
 
         kp = key;
         for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
-            struct cache *cache = &tag_cache[i];
-            struct cache temp_cache;
+            struct cache_char* cache = &tag_cache[i];
+            struct cache_char temp_cache;
 
             if (not_locked) {
-                temp_cache.pinfo = NULL;
+                temp_cache.cache.pinfo = NULL;
                 temp_cache.c = '\0';
                 cache = &temp_cache;
             }
@@ -202,13 +218,13 @@
 
         kp = key;
         for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
-            struct cache *cache = &global_cache[i];
-            struct cache temp_cache;
+            struct cache_char* cache = &global_cache[i];
+            struct cache_char temp_cache;
 
             if (not_locked) {
                 temp_cache = *cache;
-                if (temp_cache.pinfo != cache->pinfo) { /* check atomic */
-                    temp_cache.pinfo = NULL;
+                if (temp_cache.cache.pinfo != cache->cache.pinfo) { /* check atomic */
+                    temp_cache.cache.pinfo = NULL;
                     temp_cache.c = '\0';
                 }
                 cache = &temp_cache;
@@ -246,28 +262,39 @@
     return default_prio;
 }
 
-LIBLOG_ABI_PUBLIC int __android_log_is_loggable(int prio, const char *tag,
-                                                int default_prio)
+LIBLOG_ABI_PUBLIC int __android_log_is_loggable_len(int prio,
+                                                    const char* tag, size_t len,
+                                                    int default_prio)
 {
-    int logLevel = __android_log_level(tag, default_prio);
+    int logLevel = __android_log_level(tag, len, default_prio);
     return logLevel >= 0 && prio >= logLevel;
 }
 
-LIBLOG_HIDDEN int __android_log_is_debuggable()
+LIBLOG_ABI_PUBLIC int __android_log_is_loggable(int prio,
+                                                const char* tag,
+                                                int default_prio)
+{
+    int logLevel = __android_log_level(tag,
+                                       (tag && *tag) ? strlen(tag) : 0,
+                                       default_prio);
+    return logLevel >= 0 && prio >= logLevel;
+}
+
+LIBLOG_ABI_PRIVATE int __android_log_is_debuggable()
 {
     static uint32_t serial;
-    static struct cache tag_cache;
+    static struct cache_char tag_cache;
     static const char key[] = "ro.debuggable";
     int ret;
 
     if (tag_cache.c) { /* ro property does not change after set */
         ret = tag_cache.c == '1';
     } else if (lock()) {
-        struct cache temp_cache = { NULL, -1, '\0' };
+        struct cache_char temp_cache = { { NULL, -1 }, '\0' };
         refresh_cache(&temp_cache, key);
         ret = temp_cache.c == '1';
     } else {
-        int change_detected = check_cache(&tag_cache);
+        int change_detected = check_cache(&tag_cache.cache);
         uint32_t current_serial = __system_property_area_serial();
         if (current_serial != serial) {
             change_detected = 1;
@@ -289,17 +316,17 @@
  * Since a change is rare, we will accept a trylock failure gracefully.
  * Use a separate lock from is_loggable to keep contention down b/25563384.
  */
-struct cache2 {
+struct cache2_char {
     pthread_mutex_t lock;
     uint32_t serial;
-    const char *key_persist;
-    struct cache cache_persist;
-    const char *key_ro;
-    struct cache cache_ro;
-    unsigned char (*const evaluate)(const struct cache2 *self);
+    const char* key_persist;
+    struct cache_char cache_persist;
+    const char* key_ro;
+    struct cache_char cache_ro;
+    unsigned char (*const evaluate)(const struct cache2_char *self);
 };
 
-static inline unsigned char do_cache2(struct cache2 *self)
+static inline unsigned char do_cache2_char(struct cache2_char *self)
 {
     uint32_t current_serial;
     int change_detected;
@@ -310,8 +337,8 @@
         return self->evaluate(self);
     }
 
-    change_detected = check_cache(&self->cache_persist)
-                   || check_cache(&self->cache_ro);
+    change_detected = check_cache(&self->cache_persist.cache)
+                   || check_cache(&self->cache_ro.cache);
     current_serial = __system_property_area_serial();
     if (current_serial != self->serial) {
         change_detected = 1;
@@ -328,7 +355,7 @@
     return c;
 }
 
-static unsigned char evaluate_persist_ro(const struct cache2 *self)
+static unsigned char evaluate_persist_ro(const struct cache2_char *self)
 {
     unsigned char c = self->cache_persist.c;
 
@@ -345,17 +372,17 @@
  */
 LIBLOG_ABI_PUBLIC clockid_t android_log_clockid()
 {
-    static struct cache2 clockid = {
+    static struct cache2_char clockid = {
         PTHREAD_MUTEX_INITIALIZER,
         0,
         "persist.logd.timestamp",
-        { NULL, -1, '\0' },
+        { { NULL, -1 }, '\0' },
         "ro.logd.timestamp",
-        { NULL, -1, '\0' },
+        { { NULL, -1 }, '\0' },
         evaluate_persist_ro
     };
 
-    return (tolower(do_cache2(&clockid)) == 'm')
+    return (tolower(do_cache2_char(&clockid)) == 'm')
         ? CLOCK_MONOTONIC
         : CLOCK_REALTIME;
 }
@@ -364,7 +391,7 @@
  * Security state generally remains constant, but the DO must be able
  * to turn off logging should it become spammy after an attack is detected.
  */
-static unsigned char evaluate_security(const struct cache2 *self)
+static unsigned char evaluate_security(const struct cache2_char *self)
 {
     unsigned char c = self->cache_ro.c;
 
@@ -373,15 +400,265 @@
 
 LIBLOG_ABI_PUBLIC int __android_log_security()
 {
-    static struct cache2 security = {
+    static struct cache2_char security = {
         PTHREAD_MUTEX_INITIALIZER,
         0,
         "persist.logd.security",
-        { NULL, -1, BOOLEAN_FALSE },
+        { { NULL, -1 }, BOOLEAN_FALSE },
         "ro.device_owner",
-        { NULL, -1, BOOLEAN_FALSE },
+        { { NULL, -1 }, BOOLEAN_FALSE },
         evaluate_security
     };
 
-    return do_cache2(&security);
+    return do_cache2_char(&security);
+}
+
+/*
+ * Interface that represents the logd buffer size determination so that others
+ * need not guess our intentions.
+ */
+
+/* Property helper */
+static bool check_flag(const char* prop, const char* flag) {
+    const char* cp = strcasestr(prop, flag);
+    if (!cp) {
+        return false;
+    }
+    /* We only will document comma (,) */
+    static const char sep[] = ",:;|+ \t\f";
+    if ((cp != prop) && !strchr(sep, cp[-1])) {
+        return false;
+    }
+    cp += strlen(flag);
+    return !*cp || !!strchr(sep, *cp);
+}
+
+/* cache structure */
+struct cache_property {
+    struct cache cache;
+    char property[PROP_VALUE_MAX];
+};
+
+static void refresh_cache_property(struct cache_property* cache, const char* key)
+{
+    if (!cache->cache.pinfo) {
+        cache->cache.pinfo = __system_property_find(key);
+        if (!cache->cache.pinfo) {
+            return;
+        }
+    }
+    cache->cache.serial = __system_property_serial(cache->cache.pinfo);
+    __system_property_read(cache->cache.pinfo, 0, cache->property);
+}
+
+/* get boolean with the logger twist that supports eng adjustments */
+LIBLOG_ABI_PRIVATE bool __android_logger_property_get_bool(const char* key,
+                                                           int flag)
+{
+    struct cache_property property = { { NULL, -1 }, { 0 } };
+    if (flag & BOOL_DEFAULT_FLAG_PERSIST) {
+        char newkey[PROP_NAME_MAX];
+        snprintf(newkey, sizeof(newkey), "ro.%s", key);
+        refresh_cache_property(&property, newkey);
+        property.cache.pinfo = NULL;
+        property.cache.serial = -1;
+        snprintf(newkey, sizeof(newkey), "persist.%s", key);
+        refresh_cache_property(&property, newkey);
+        property.cache.pinfo = NULL;
+        property.cache.serial = -1;
+    }
+
+    refresh_cache_property(&property, key);
+
+    if (check_flag(property.property, "true")) {
+        return true;
+    }
+    if (check_flag(property.property, "false")) {
+        return false;
+    }
+    if (check_flag(property.property, "eng")) {
+       flag |= BOOL_DEFAULT_FLAG_ENG;
+    }
+    /* this is really a "not" flag */
+    if (check_flag(property.property, "svelte")) {
+       flag |= BOOL_DEFAULT_FLAG_SVELTE;
+    }
+
+    /* Sanity Check */
+    if (flag & (BOOL_DEFAULT_FLAG_SVELTE | BOOL_DEFAULT_FLAG_ENG)) {
+        flag &= ~BOOL_DEFAULT_FLAG_TRUE_FALSE;
+        flag |= BOOL_DEFAULT_TRUE;
+    }
+
+    if ((flag & BOOL_DEFAULT_FLAG_SVELTE)
+            && __android_logger_property_get_bool("ro.config.low_ram",
+                                 BOOL_DEFAULT_FALSE)) {
+        return false;
+    }
+    if ((flag & BOOL_DEFAULT_FLAG_ENG) && !__android_log_is_debuggable()) {
+        return false;
+    }
+
+    return (flag & BOOL_DEFAULT_FLAG_TRUE_FALSE) != BOOL_DEFAULT_FALSE;
+}
+
+LIBLOG_ABI_PRIVATE bool __android_logger_valid_buffer_size(unsigned long value)
+{
+    static long pages, pagesize;
+    unsigned long maximum;
+
+    if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
+        return false;
+    }
+
+    if (!pages) {
+        pages = sysconf(_SC_PHYS_PAGES);
+    }
+    if (pages < 1) {
+        return true;
+    }
+
+    if (!pagesize) {
+        pagesize = sysconf(_SC_PAGESIZE);
+        if (pagesize <= 1) {
+            pagesize = PAGE_SIZE;
+        }
+    }
+
+    /* maximum memory impact a somewhat arbitrary ~3% */
+    pages = (pages + 31) / 32;
+    maximum = pages * pagesize;
+
+    if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
+        return true;
+    }
+
+    return value <= maximum;
+}
+
+struct cache2_property_size {
+    pthread_mutex_t lock;
+    uint32_t serial;
+    const char* key_persist;
+    struct cache_property cache_persist;
+    const char* key_ro;
+    struct cache_property cache_ro;
+    unsigned long (*const evaluate)(const struct cache2_property_size* self);
+};
+
+static inline unsigned long do_cache2_property_size(struct cache2_property_size* self)
+{
+    uint32_t current_serial;
+    int change_detected;
+    unsigned long v;
+
+    if (pthread_mutex_trylock(&self->lock)) {
+        /* We are willing to accept some race in this context */
+        return self->evaluate(self);
+    }
+
+    change_detected = check_cache(&self->cache_persist.cache)
+                   || check_cache(&self->cache_ro.cache);
+    current_serial = __system_property_area_serial();
+    if (current_serial != self->serial) {
+        change_detected = 1;
+    }
+    if (change_detected) {
+        refresh_cache_property(&self->cache_persist, self->key_persist);
+        refresh_cache_property(&self->cache_ro, self->key_ro);
+        self->serial = current_serial;
+    }
+    v = self->evaluate(self);
+
+    pthread_mutex_unlock(&self->lock);
+
+    return v;
+}
+
+static unsigned long property_get_size_from_cache(const struct cache_property* cache)
+{
+    char* cp;
+    unsigned long value = strtoul(cache->property, &cp, 10);
+
+    switch(*cp) {
+    case 'm':
+    case 'M':
+        value *= 1024;
+    /* FALLTHRU */
+    case 'k':
+    case 'K':
+        value *= 1024;
+    /* FALLTHRU */
+    case '\0':
+        break;
+
+    default:
+        value = 0;
+    }
+
+    if (!__android_logger_valid_buffer_size(value)) {
+        value = 0;
+    }
+
+    return value;
+}
+
+static unsigned long evaluate_property_get_size(const struct cache2_property_size* self)
+{
+    unsigned long size = property_get_size_from_cache(&self->cache_persist);
+    if (size) {
+        return size;
+    }
+    return property_get_size_from_cache(&self->cache_ro);
+}
+
+LIBLOG_ABI_PRIVATE unsigned long __android_logger_get_buffer_size(log_id_t logId)
+{
+    static const char global_tunable[] = "persist.logd.size"; /* Settings App */
+    static const char global_default[] = "ro.logd.size"; /* BoardConfig.mk */
+    static struct cache2_property_size global = {
+        PTHREAD_MUTEX_INITIALIZER,
+        0,
+        global_tunable,
+        { { NULL, -1 }, {} },
+        global_default,
+        { { NULL, -1 }, {} },
+        evaluate_property_get_size
+    };
+    char key_persist[PROP_NAME_MAX];
+    char key_ro[PROP_NAME_MAX];
+    struct cache2_property_size local = {
+        PTHREAD_MUTEX_INITIALIZER,
+        0,
+        key_persist,
+        { { NULL, -1 }, {} },
+        key_ro,
+        { { NULL, -1 }, {} },
+        evaluate_property_get_size
+    };
+    unsigned long property_size, default_size;
+
+    default_size =  do_cache2_property_size(&global);
+    if (!default_size) {
+        default_size = __android_logger_property_get_bool("ro.config.low_ram",
+                                                          BOOL_DEFAULT_FALSE)
+            ? LOG_BUFFER_MIN_SIZE /* 64K  */
+            : LOG_BUFFER_SIZE;    /* 256K */
+    }
+
+    snprintf(key_persist, sizeof(key_persist), "%s.%s",
+             global_tunable, android_log_id_to_name(logId));
+    snprintf(key_ro, sizeof(key_ro), "%s.%s",
+             global_default, android_log_id_to_name(logId));
+    property_size = do_cache2_property_size(&local);
+
+    if (!property_size) {
+        property_size = default_size;
+    }
+
+    if (!property_size) {
+        property_size = LOG_BUFFER_SIZE;
+    }
+
+    return property_size;
 }
diff --git a/liblog/log_time.cpp b/liblog/log_time.cpp
index d2bf181..dfd2d44 100644
--- a/liblog/log_time.cpp
+++ b/liblog/log_time.cpp
@@ -19,7 +19,7 @@
 #include <stdio.h>
 #include <string.h>
 
-#include <log/log_read.h>
+#include <private/android_logger.h>
 
 #include "log_portability.h"
 
diff --git a/liblog/logd_reader.c b/liblog/logd_reader.c
index b894349..99d7fea 100644
--- a/liblog/logd_reader.c
+++ b/liblog/logd_reader.c
@@ -32,9 +32,6 @@
 #include <unistd.h>
 
 #include <cutils/sockets.h>
-#include <log/logd.h>
-#include <log/logger.h>
-#include <log/log_read.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
@@ -483,17 +480,17 @@
     struct sigaction old_sigaction;
     unsigned int old_alarm = 0;
     char buffer[256], *cp, c;
-    int e, ret, remaining;
-
-    int sock = transp->context.sock;
-    if (sock > 0) {
-        return sock;
-    }
+    int e, ret, remaining, sock;
 
     if (!logger_list) {
         return -EINVAL;
     }
 
+    sock = atomic_load(&transp->context.sock);
+    if (sock > 0) {
+        return sock;
+    }
+
     sock = socket_local_client("logdr",
                                ANDROID_SOCKET_NAMESPACE_RESERVED,
                                SOCK_SEQPACKET);
@@ -588,7 +585,11 @@
         return ret;
     }
 
-    return transp->context.sock = sock;
+    ret = atomic_exchange(&transp->context.sock, sock);
+    if ((ret > 0) && (ret != sock)) {
+        close(ret);
+    }
+    return sock;
 }
 
 /* Read from the selected logs */
@@ -663,8 +664,8 @@
 static void logdClose(struct android_log_logger_list *logger_list __unused,
                       struct android_log_transport_context *transp)
 {
-    if (transp->context.sock > 0) {
-        close (transp->context.sock);
-        transp->context.sock = -1;
+    int sock = atomic_exchange(&transp->context.sock, -1);
+    if (sock > 0) {
+        close (sock);
     }
 }
diff --git a/liblog/logd_writer.c b/liblog/logd_writer.c
index 059f170..8fdfb92 100644
--- a/liblog/logd_writer.c
+++ b/liblog/logd_writer.c
@@ -32,9 +32,6 @@
 #include <unistd.h>
 
 #include <cutils/sockets.h>
-#include <log/logd.h>
-#include <log/logger.h>
-#include <log/log_read.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
@@ -66,13 +63,11 @@
 {
     int i, ret = 0;
 
-    if (logdLoggerWrite.context.sock < 0) {
-        i = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0));
+    i = atomic_load(&logdLoggerWrite.context.sock);
+    if (i < 0) {
+        i = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
         if (i < 0) {
             ret = -errno;
-        } else if (TEMP_FAILURE_RETRY(fcntl(i, F_SETFL, O_NONBLOCK)) < 0) {
-            ret = -errno;
-            close(i);
         } else {
             struct sockaddr_un un;
             memset(&un, 0, sizeof(struct sockaddr_un));
@@ -84,7 +79,11 @@
                 ret = -errno;
                 close(i);
             } else {
-                logdLoggerWrite.context.sock = i;
+                ret = atomic_exchange(&logdLoggerWrite.context.sock, i);
+                if ((ret >= 0) && (ret != i)) {
+                    close(ret);
+                }
+                ret = 0;
             }
         }
     }
@@ -94,9 +93,9 @@
 
 static void logdClose()
 {
-    if (logdLoggerWrite.context.sock >= 0) {
-        close(logdLoggerWrite.context.sock);
-        logdLoggerWrite.context.sock = -1;
+    int sock = atomic_exchange(&logdLoggerWrite.context.sock, -1);
+    if (sock >= 0) {
+        close(sock);
     }
 }
 
@@ -105,7 +104,7 @@
     if (logId > LOG_ID_SECURITY) {
         return -EINVAL;
     }
-    if (logdLoggerWrite.context.sock < 0) {
+    if (atomic_load(&logdLoggerWrite.context.sock) < 0) {
         if (access("/dev/socket/logdw", W_OK) == 0) {
             return 0;
         }
@@ -125,7 +124,7 @@
     static atomic_int_fast32_t dropped;
     static atomic_int_fast32_t droppedSecurity;
 
-    if (logdLoggerWrite.context.sock < 0) {
+    if (atomic_load(&logdLoggerWrite.context.sock) < 0) {
         return -EBADF;
     }
 
@@ -164,7 +163,7 @@
     newVec[0].iov_base = (unsigned char *)&header;
     newVec[0].iov_len  = sizeof(header);
 
-    if (logdLoggerWrite.context.sock > 0) {
+    if (atomic_load(&logdLoggerWrite.context.sock) > 0) {
         int32_t snapshot = atomic_exchange_explicit(&droppedSecurity, 0,
                                                     memory_order_relaxed);
         if (snapshot) {
@@ -178,16 +177,17 @@
             newVec[headerLength].iov_base = &buffer;
             newVec[headerLength].iov_len  = sizeof(buffer);
 
-            ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, 2));
+            ret = TEMP_FAILURE_RETRY(writev(
+                    atomic_load(&logdLoggerWrite.context.sock), newVec, 2));
             if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
                 atomic_fetch_add_explicit(&droppedSecurity, snapshot,
                                           memory_order_relaxed);
             }
         }
         snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
-        if (snapshot && __android_log_is_loggable(ANDROID_LOG_INFO,
-                                                  "liblog",
-                                                  ANDROID_LOG_VERBOSE)) {
+        if (snapshot && __android_log_is_loggable_len(ANDROID_LOG_INFO,
+                                                      "liblog", strlen("liblog"),
+                                                      ANDROID_LOG_VERBOSE)) {
             android_log_event_int_t buffer;
 
             header.id = LOG_ID_EVENTS;
@@ -198,7 +198,8 @@
             newVec[headerLength].iov_base = &buffer;
             newVec[headerLength].iov_len  = sizeof(buffer);
 
-            ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, 2));
+            ret = TEMP_FAILURE_RETRY(writev(
+                      atomic_load(&logdLoggerWrite.context.sock), newVec, 2));
             if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
                 atomic_fetch_add_explicit(&dropped, snapshot,
                                           memory_order_relaxed);
@@ -227,7 +228,8 @@
      * ENOTCONN occurs if logd dies.
      * EAGAIN occurs if logd is overloaded.
      */
-    ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, i));
+    ret = TEMP_FAILURE_RETRY(writev(
+            atomic_load(&logdLoggerWrite.context.sock), newVec, i));
     if (ret < 0) {
         ret = -errno;
         if (ret == -ENOTCONN) {
@@ -240,7 +242,8 @@
                 return ret;
             }
 
-            ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, i));
+            ret = TEMP_FAILURE_RETRY(writev(
+                    atomic_load(&logdLoggerWrite.context.sock), newVec, i));
             if (ret < 0) {
                 ret = -errno;
             }
diff --git a/liblog/logger.h b/liblog/logger.h
index 0964756..50d1cb4 100644
--- a/liblog/logger.h
+++ b/liblog/logger.h
@@ -17,13 +17,12 @@
 #ifndef _LIBLOG_LOGGER_H__
 #define _LIBLOG_LOGGER_H__
 
+#include <stdatomic.h>
 #include <stdbool.h>
-#include <log/uio.h>
 
 #include <cutils/list.h>
 #include <log/log.h>
-#include <log/log_read.h>
-#include <log/logger.h>
+#include <log/uio.h>
 
 #include "log_portability.h"
 
@@ -32,9 +31,10 @@
 /* Union, sock or fd of zero is not allowed unless static initialized */
 union android_log_context {
   void *private;
-  int sock;
-  int fd;
+  atomic_int sock;
+  atomic_int fd;
   struct listnode *node;
+  atomic_uintptr_t atomic_pointer;
 };
 
 struct android_log_transport_write {
@@ -124,23 +124,23 @@
 
 /* assumes caller has structures read-locked, single threaded, or fenced */
 #define transport_context_for_each(transp, logger_list)              \
-  for (transp = node_to_item((logger_list)->transport.next,          \
+  for ((transp) = node_to_item((logger_list)->transport.next,        \
                              struct android_log_transport_context,   \
                              node);                                  \
-       (transp != node_to_item(&(logger_list)->transport,            \
+       ((transp) != node_to_item(&(logger_list)->transport,          \
                                struct android_log_transport_context, \
                                node)) &&                             \
-           (transp->parent == (logger_list));                        \
-       transp = node_to_item(transp->node.next,                      \
+           ((transp)->parent == (logger_list));                      \
+       (transp) = node_to_item((transp)->node.next,                  \
                              struct android_log_transport_context, node))
 
 #define logger_for_each(logp, logger_list)                          \
-    for (logp = node_to_item((logger_list)->logger.next,            \
+    for ((logp) = node_to_item((logger_list)->logger.next,          \
                              struct android_log_logger, node);      \
-         (logp != node_to_item(&(logger_list)->logger,              \
+         ((logp) != node_to_item(&(logger_list)->logger,            \
                                struct android_log_logger, node)) && \
-             (logp->parent == (logger_list));                       \
-         logp = node_to_item((logp)->node.next,                     \
+             ((logp)->parent == (logger_list));                     \
+         (logp) = node_to_item((logp)->node.next,                   \
                              struct android_log_logger, node))
 
 /* OS specific dribs and drabs */
@@ -156,7 +156,6 @@
 LIBLOG_HIDDEN void __android_log_lock();
 LIBLOG_HIDDEN int __android_log_trylock();
 LIBLOG_HIDDEN void __android_log_unlock();
-LIBLOG_HIDDEN int __android_log_is_debuggable();
 
 __END_DECLS
 
diff --git a/liblog/logger_name.c b/liblog/logger_name.c
index b7ccac5..5c4feaf 100644
--- a/liblog/logger_name.c
+++ b/liblog/logger_name.c
@@ -17,7 +17,6 @@
 #include <string.h>
 
 #include <log/log.h>
-#include <log/logger.h>
 
 #include "log_portability.h"
 
diff --git a/liblog/logger_read.c b/liblog/logger_read.c
index 0d6ba08..c3cb7ad 100644
--- a/liblog/logger_read.c
+++ b/liblog/logger_read.c
@@ -23,9 +23,8 @@
 #include <string.h>
 #include <unistd.h>
 
+#include <android/log.h>
 #include <cutils/list.h>
-#include <log/log.h>
-#include <log/logger.h>
 #include <private/android_filesystem_config.h>
 
 #include "config_read.h"
@@ -125,7 +124,7 @@
     ssize_t ret = -EINVAL;                                                    \
     struct android_log_transport_context *transp;                             \
     struct android_log_logger *logger_internal =                              \
-            (struct android_log_logger *)logger;                              \
+            (struct android_log_logger *)(logger);                            \
                                                                               \
     if (!logger_internal) {                                                   \
         return ret;                                                           \
@@ -186,7 +185,7 @@
 #define LOGGER_LIST_FUNCTION(logger_list, def, func, args...)                 \
     struct android_log_transport_context *transp;                             \
     struct android_log_logger_list *logger_list_internal =                    \
-            (struct android_log_logger_list *)logger_list;                    \
+            (struct android_log_logger_list *)(logger_list);                  \
                                                                               \
     ssize_t ret = init_transport_context(logger_list_internal);               \
     if (ret < 0) {                                                            \
@@ -341,6 +340,47 @@
     return logger_list;
 }
 
+/* Validate log_msg packet, read function has already been null checked */
+static int android_transport_read(struct android_log_logger_list *logger_list,
+                                  struct android_log_transport_context *transp,
+                                  struct log_msg *log_msg)
+{
+    int ret = (*transp->transport->read)(logger_list, transp, log_msg);
+
+    if (ret > (int)sizeof(*log_msg)) {
+        ret = sizeof(*log_msg);
+    }
+
+    transp->ret = ret;
+
+    /* propagate errors, or make sure len & hdr_size members visible */
+    if (ret < (int)(sizeof(log_msg->entry.len) +
+                    sizeof(log_msg->entry.hdr_size))) {
+        if (ret >= (int)sizeof(log_msg->entry.len)) {
+            log_msg->entry.len = 0;
+        }
+        return ret;
+    }
+
+    /* hdr_size correction (logger_entry -> logger_entry_v2+ conversion) */
+    if (log_msg->entry_v2.hdr_size == 0) {
+        log_msg->entry_v2.hdr_size = sizeof(struct logger_entry);
+    }
+    if ((log_msg->entry_v2.hdr_size < sizeof(log_msg->entry_v1)) ||
+            (log_msg->entry_v2.hdr_size > sizeof(log_msg->entry))) {
+        return -EINVAL;
+    }
+
+    /* len validation */
+    if (ret <= log_msg->entry_v2.hdr_size) {
+        log_msg->entry.len = 0;
+    } else {
+        log_msg->entry.len = ret - log_msg->entry_v2.hdr_size;
+    }
+
+    return ret;
+}
+
 /* Read from the selected logs */
 LIBLOG_ABI_PUBLIC int android_logger_list_read(struct logger_list *logger_list,
                                                struct log_msg *log_msg)
@@ -378,7 +418,7 @@
                     } else if ((logger_list_internal->mode &
                                 ANDROID_LOG_NONBLOCK) ||
                             !transp->transport->poll) {
-                        retval = transp->ret = (*transp->transport->read)(
+                        retval = android_transport_read(
                                 logger_list_internal,
                                 transp,
                                 &transp->logMsg);
@@ -397,7 +437,7 @@
                             }
                             retval = transp->ret = pollval;
                         } else if (pollval > 0) {
-                            retval = transp->ret = (*transp->transport->read)(
+                            retval = android_transport_read(
                                     logger_list_internal,
                                     transp,
                                     &transp->logMsg);
@@ -434,16 +474,22 @@
         if (!oldest) {
             return ret;
         }
-        memcpy(log_msg, &oldest->logMsg, oldest->logMsg.entry.len +
-                    (oldest->logMsg.entry.hdr_size ?
-                        oldest->logMsg.entry.hdr_size :
-                        sizeof(struct logger_entry)));
+        // ret is a positive value less than sizeof(struct log_msg)
+        ret = oldest->ret;
+        if (ret < oldest->logMsg.entry.hdr_size) {
+            // zero truncated header fields.
+            memset(log_msg, 0,
+                   (oldest->logMsg.entry.hdr_size > sizeof(oldest->logMsg) ?
+                       sizeof(oldest->logMsg) :
+                       oldest->logMsg.entry.hdr_size));
+        }
+        memcpy(log_msg, &oldest->logMsg, ret);
         oldest->logMsg.entry.len = 0; /* Mark it as copied */
-        return oldest->ret;
+        return ret;
     }
 
     /* if only one, no need to copy into transport_context and merge-sort */
-    return (transp->transport->read)(logger_list_internal, transp, log_msg);
+    return android_transport_read(logger_list_internal, transp, log_msg);
 }
 
 /* Close all the logs */
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index c7b5a84..157bd88 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -25,9 +25,6 @@
 #endif
 
 #include <log/event_tag_map.h>
-#include <log/logd.h>
-#include <log/logger.h>
-#include <log/log_read.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
@@ -132,12 +129,20 @@
     }
     return kLogNotAvailable;
 }
+
+#if defined(__BIONIC__)
+static atomic_uintptr_t tagMap;
+#endif
+
 /*
  * Release any logger resources. A new log write will immediately re-acquire.
  */
 LIBLOG_ABI_PUBLIC void __android_log_close()
 {
     struct android_log_transport_write *transport;
+#if defined(__BIONIC__)
+    EventTagMap *m;
+#endif
 
     __android_log_lock();
 
@@ -165,7 +170,28 @@
         }
     }
 
+#if defined(__BIONIC__)
+    /*
+     * Additional risk here somewhat mitigated by immediately unlock flushing
+     * the processor cache. The multi-threaded race that we choose to accept,
+     * to minimize locking, is an atomic_load in a writer picking up a value
+     * just prior to entering this routine. There will be an use after free.
+     *
+     * Again, anyone calling this is doing so to release the logging resources
+     * is most probably going to quiesce then shut down; or to restart after
+     * a fork so the risk should be non-existent. For this reason we
+     * choose a mitigation stance for efficiency instead of incuring the cost
+     * of a lock for every log write.
+     */
+    m = (EventTagMap *)atomic_exchange(&tagMap, (uintptr_t)0);
+#endif
+
     __android_log_unlock();
+
+#if defined(__BIONIC__)
+    if (m != (EventTagMap *)(uintptr_t)-1LL) android_closeEventTagMap(m);
+#endif
+
 }
 
 /* log_init_lock assumed */
@@ -250,8 +276,8 @@
             return -EPERM;
         }
     } else if (log_id == LOG_ID_EVENTS) {
-        static atomic_uintptr_t map;
         const char *tag;
+        size_t len;
         EventTagMap *m, *f;
 
         if (vec[0].iov_len < 4) {
@@ -259,12 +285,13 @@
         }
 
         tag = NULL;
+        len = 0;
         f = NULL;
-        m = (EventTagMap *)atomic_load(&map);
+        m = (EventTagMap *)atomic_load(&tagMap);
 
         if (!m) {
             ret = __android_log_trylock();
-            m = (EventTagMap *)atomic_load(&map); /* trylock flush cache */
+            m = (EventTagMap *)atomic_load(&tagMap); /* trylock flush cache */
             if (!m) {
                 m = android_openEventTagMap(EVENT_TAG_MAP_FILE);
                 if (ret) { /* trylock failed, use local copy, mark for close */
@@ -273,7 +300,7 @@
                     if (!m) { /* One chance to open map file */
                         m = (EventTagMap *)(uintptr_t)-1LL;
                     }
-                    atomic_store(&map, (uintptr_t)m);
+                    atomic_store(&tagMap, (uintptr_t)m);
                 }
             }
             if (!ret) { /* trylock succeeded, unlock */
@@ -281,11 +308,11 @@
             }
         }
         if (m && (m != (EventTagMap *)(uintptr_t)-1LL)) {
-            tag = android_lookupEventTag(m, get4LE(vec[0].iov_base));
+            tag = android_lookupEventTag_len(m, &len, get4LE(vec[0].iov_base));
         }
-        ret = __android_log_is_loggable(ANDROID_LOG_INFO,
-                                        tag,
-                                        ANDROID_LOG_VERBOSE);
+        ret = __android_log_is_loggable_len(ANDROID_LOG_INFO,
+                                            tag, len,
+                                            ANDROID_LOG_VERBOSE);
         if (f) { /* local copy marked for close */
             android_closeEventTagMap(f);
         }
@@ -318,7 +345,9 @@
             tag = NULL;
         }
 
-        if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
+        if (!__android_log_is_loggable_len(prio,
+                                           tag, len - 1,
+                                           ANDROID_LOG_VERBOSE)) {
             return -EPERM;
         }
     }
diff --git a/liblog/logprint.c b/liblog/logprint.c
index c8457f4..da80e36 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -21,18 +21,19 @@
 #include <assert.h>
 #include <ctype.h>
 #include <errno.h>
+#include <inttypes.h>
+#include <pwd.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <inttypes.h>
 #include <sys/param.h>
+#include <sys/types.h>
 
 #include <cutils/list.h>
-#include <log/logd.h>
+#include <log/log.h>
 #include <log/logprint.h>
-#include <private/android_filesystem_config.h>
 
 #include "log_portability.h"
 
@@ -57,9 +58,16 @@
     bool epoch_output;
     bool monotonic_output;
     bool uid_output;
+    bool descriptive_output;
 };
 
 /*
+ * API issues prevent us from exposing "descriptive" in AndroidLogFormat_t
+ * during android_log_processBinaryLogBuffer(), so we break layering.
+ */
+static bool descriptive_output = false;
+
+/*
  *  gnome-terminal color tags
  *    See http://misc.flogisoft.com/bash/tip_colors_and_formatting
  *    for ideas on how to set the forground color of the text for xterm.
@@ -208,6 +216,8 @@
     p_ret->epoch_output = false;
     p_ret->monotonic_output = android_log_clockid() == CLOCK_MONOTONIC;
     p_ret->uid_output = false;
+    p_ret->descriptive_output = false;
+    descriptive_output = false;
 
     return p_ret;
 }
@@ -266,6 +276,10 @@
     case FORMAT_MODIFIER_UID:
         p_format->uid_output = true;
         return 0;
+    case FORMAT_MODIFIER_DESCRIPT:
+        p_format->descriptive_output = true;
+        descriptive_output = true;
+        return 0;
     default:
         break;
     }
@@ -293,6 +307,7 @@
     else if (strcmp(formatString, "threadtime") == 0) format = FORMAT_THREADTIME;
     else if (strcmp(formatString, "long") == 0) format = FORMAT_LONG;
     else if (strcmp(formatString, "color") == 0) format = FORMAT_MODIFIER_COLOR;
+    else if (strcmp(formatString, "colour") == 0) format = FORMAT_MODIFIER_COLOR;
     else if (strcmp(formatString, "usec") == 0) format = FORMAT_MODIFIER_TIME_USEC;
     else if (strcmp(formatString, "printable") == 0) format = FORMAT_MODIFIER_PRINTABLE;
     else if (strcmp(formatString, "year") == 0) format = FORMAT_MODIFIER_YEAR;
@@ -300,6 +315,7 @@
     else if (strcmp(formatString, "epoch") == 0) format = FORMAT_MODIFIER_EPOCH;
     else if (strcmp(formatString, "monotonic") == 0) format = FORMAT_MODIFIER_MONOTONIC;
     else if (strcmp(formatString, "uid") == 0) format = FORMAT_MODIFIER_UID;
+    else if (strcmp(formatString, "descriptive") == 0) format = FORMAT_MODIFIER_DESCRIPT;
     else {
         extern char *tzname[2];
         static const char gmt[] = "GMT";
@@ -495,6 +511,11 @@
     char *msg = buf->msg;
     struct logger_entry_v2 *buf2 = (struct logger_entry_v2 *)buf;
     if (buf2->hdr_size) {
+        if ((buf2->hdr_size < sizeof(((struct log_msg *)NULL)->entry_v1)) ||
+                (buf2->hdr_size > sizeof(((struct log_msg *)NULL)->entry))) {
+            fprintf(stderr, "+++ LOG: entry illegal hdr_size\n");
+            return -1;
+        }
         msg = ((char *)buf2) + buf2->hdr_size;
         if (buf2->hdr_size >= sizeof(struct logger_entry_v4)) {
             entry->uid = ((struct logger_entry_v4 *)buf)->uid;
@@ -533,6 +554,7 @@
 
     entry->priority = msg[0];
     entry->tag = msg + 1;
+    entry->tagLen = msgStart - 1;
     entry->message = msg + msgStart;
     entry->messageLen = (msgEnd < msgStart) ? 0 : (msgEnd - msgStart);
 
@@ -559,6 +581,19 @@
     return ((uint64_t) high << 32) | (uint64_t) low;
 }
 
+static bool findChar(const char** cp, size_t* len, int c) {
+    while (*len && isspace(**cp)) {
+        ++*cp;
+        --*len;
+    }
+    if (c == INT_MAX) return *len;
+    if (*len && (**cp == c)) {
+        ++*cp;
+        --*len;
+        return true;
+    }
+    return false;
+}
 
 /*
  * Recursively convert binary log data to printable form.
@@ -571,63 +606,151 @@
  *
  * Returns 0 on success, 1 on buffer full, -1 on failure.
  */
+enum objectType {
+    TYPE_OBJECTS      = '1',
+    TYPE_BYTES        = '2',
+    TYPE_MILLISECONDS = '3',
+    TYPE_ALLOCATIONS  = '4',
+    TYPE_ID           = '5',
+    TYPE_PERCENT      = '6'
+};
+
 static int android_log_printBinaryEvent(const unsigned char** pEventData,
-    size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen)
+    size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen,
+    const char** fmtStr, size_t* fmtLen)
 {
     const unsigned char* eventData = *pEventData;
     size_t eventDataLen = *pEventDataLen;
     char* outBuf = *pOutBuf;
+    char* outBufSave = outBuf;
     size_t outBufLen = *pOutBufLen;
+    size_t outBufLenSave = outBufLen;
     unsigned char type;
     size_t outCount;
     int result = 0;
+    const char* cp;
+    size_t len;
+    int64_t lval;
 
-    if (eventDataLen < 1)
-        return -1;
+    if (eventDataLen < 1) return -1;
+
     type = *eventData++;
     eventDataLen--;
 
+    cp = NULL;
+    len = 0;
+    if (fmtStr && *fmtStr && fmtLen && *fmtLen && **fmtStr) {
+        cp = *fmtStr;
+        len = *fmtLen;
+    }
+    /*
+     * event.logtag format specification:
+     *
+     * Optionally, after the tag names can be put a description for the value(s)
+     * of the tag. Description are in the format
+     *    (<name>|data type[|data unit])
+     * Multiple values are separated by commas.
+     *
+     * The data type is a number from the following values:
+     * 1: int
+     * 2: long
+     * 3: string
+     * 4: list
+     * 5: float
+     *
+     * The data unit is a number taken from the following list:
+     * 1: Number of objects
+     * 2: Number of bytes
+     * 3: Number of milliseconds
+     * 4: Number of allocations
+     * 5: Id
+     * 6: Percent
+     * Default value for data of type int/long is 2 (bytes).
+     */
+    if (!cp || !findChar(&cp, &len, '(')) {
+        len = 0;
+    } else {
+        char* outBufLastSpace = NULL;
+
+        findChar(&cp, &len, INT_MAX);
+        while (len && *cp && (*cp != '|') && (*cp != ')')) {
+            if (outBufLen <= 0) {
+                /* halt output */
+                goto no_room;
+            }
+            outBufLastSpace = isspace(*cp) ? outBuf : NULL;
+            *outBuf = *cp;
+            ++outBuf;
+            ++cp;
+            --outBufLen;
+            --len;
+        }
+        if (outBufLastSpace) {
+            outBufLen += outBuf - outBufLastSpace;
+            outBuf = outBufLastSpace;
+        }
+        if (outBufLen <= 0) {
+            /* halt output */
+            goto no_room;
+        }
+        if (outBufSave != outBuf) {
+            *outBuf = '=';
+            ++outBuf;
+            --outBufLen;
+        }
+
+        if (findChar(&cp, &len, '|') && findChar(&cp, &len, INT_MAX)) {
+            static const unsigned char typeTable[] = {
+                EVENT_TYPE_INT,
+                EVENT_TYPE_LONG,
+                EVENT_TYPE_STRING,
+                EVENT_TYPE_LIST,
+                EVENT_TYPE_FLOAT
+            };
+
+            if ((*cp >= '1') &&
+                (*cp < (char)('1' + (sizeof(typeTable) / sizeof(typeTable[0])))) &&
+                (type != typeTable[(size_t)(*cp - '1')])) len = 0;
+
+            if (len) {
+                ++cp;
+                --len;
+            } else {
+                /* reset the format */
+                outBuf = outBufSave;
+                outBufLen = outBufLenSave;
+            }
+        }
+    }
+    lval = 0;
     switch (type) {
     case EVENT_TYPE_INT:
         /* 32-bit signed int */
         {
-            int ival;
+            int32_t ival;
 
-            if (eventDataLen < 4)
-                return -1;
+            if (eventDataLen < 4) return -1;
             ival = get4LE(eventData);
             eventData += 4;
             eventDataLen -= 4;
 
-            outCount = snprintf(outBuf, outBufLen, "%d", ival);
-            if (outCount < outBufLen) {
-                outBuf += outCount;
-                outBufLen -= outCount;
-            } else {
-                /* halt output */
-                goto no_room;
-            }
+            lval = ival;
         }
-        break;
+        goto pr_lval;
     case EVENT_TYPE_LONG:
         /* 64-bit signed long */
-        {
-            uint64_t lval;
-
-            if (eventDataLen < 8)
-                return -1;
-            lval = get8LE(eventData);
-            eventData += 8;
-            eventDataLen -= 8;
-
-            outCount = snprintf(outBuf, outBufLen, "%" PRId64, lval);
-            if (outCount < outBufLen) {
-                outBuf += outCount;
-                outBufLen -= outCount;
-            } else {
-                /* halt output */
-                goto no_room;
-            }
+        if (eventDataLen < 8) return -1;
+        lval = get8LE(eventData);
+        eventData += 8;
+        eventDataLen -= 8;
+    pr_lval:
+        outCount = snprintf(outBuf, outBufLen, "%" PRId64, lval);
+        if (outCount < outBufLen) {
+            outBuf += outCount;
+            outBufLen -= outCount;
+        } else {
+            /* halt output */
+            goto no_room;
         }
         break;
     case EVENT_TYPE_FLOAT:
@@ -636,8 +759,7 @@
             uint32_t ival;
             float fval;
 
-            if (eventDataLen < 4)
-                return -1;
+            if (eventDataLen < 4) return -1;
             ival = get4LE(eventData);
             fval = *(float*)&ival;
             eventData += 4;
@@ -658,15 +780,18 @@
         {
             unsigned int strLen;
 
-            if (eventDataLen < 4)
-                return -1;
+            if (eventDataLen < 4) return -1;
             strLen = get4LE(eventData);
             eventData += 4;
             eventDataLen -= 4;
 
-            if (eventDataLen < strLen)
-                return -1;
+            if (eventDataLen < strLen) return -1;
 
+            if (cp && (strLen == 0)) {
+                /* reset the format if no content */
+                outBuf = outBufSave;
+                outBufLen = outBufLenSave;
+            }
             if (strLen < outBufLen) {
                 memcpy(outBuf, eventData, strLen);
                 outBuf += strLen;
@@ -688,53 +813,122 @@
             unsigned char count;
             int i;
 
-            if (eventDataLen < 1)
-                return -1;
+            if (eventDataLen < 1) return -1;
 
             count = *eventData++;
             eventDataLen--;
 
-            if (outBufLen > 0) {
-                *outBuf++ = '[';
-                outBufLen--;
-            } else {
-                goto no_room;
-            }
+            if (outBufLen <= 0) goto no_room;
+
+            *outBuf++ = '[';
+            outBufLen--;
 
             for (i = 0; i < count; i++) {
                 result = android_log_printBinaryEvent(&eventData, &eventDataLen,
-                        &outBuf, &outBufLen);
-                if (result != 0)
-                    goto bail;
+                        &outBuf, &outBufLen, fmtStr, fmtLen);
+                if (result != 0) goto bail;
 
-                if (i < count-1) {
-                    if (outBufLen > 0) {
-                        *outBuf++ = ',';
-                        outBufLen--;
-                    } else {
-                        goto no_room;
-                    }
+                if (i < (count - 1)) {
+                    if (outBufLen <= 0) goto no_room;
+                    *outBuf++ = ',';
+                    outBufLen--;
                 }
             }
 
-            if (outBufLen > 0) {
-                *outBuf++ = ']';
-                outBufLen--;
-            } else {
-                goto no_room;
-            }
+            if (outBufLen <= 0) goto no_room;
+
+            *outBuf++ = ']';
+            outBufLen--;
         }
         break;
     default:
         fprintf(stderr, "Unknown binary event type %d\n", type);
         return -1;
     }
+    if (cp && len) {
+        if (findChar(&cp, &len, '|') && findChar(&cp, &len, INT_MAX)) {
+            switch (*cp) {
+            case TYPE_OBJECTS:
+                outCount = 0;
+                /* outCount = snprintf(outBuf, outBufLen, " objects"); */
+                break;
+            case TYPE_BYTES:
+                if ((lval != 0) && ((lval % 1024) == 0)) {
+                    /* repaint with multiplier */
+                    static const char suffixTable[] = { 'K', 'M', 'G', 'T' };
+                    size_t idx = 0;
+                    outBuf -= outCount;
+                    outBufLen += outCount;
+                    do {
+                        lval /= 1024;
+                        if ((lval % 1024) != 0) break;
+                    } while (++idx < ((sizeof(suffixTable) /
+                                       sizeof(suffixTable[0])) - 1));
+                    outCount = snprintf(outBuf, outBufLen,
+                                        "%" PRId64 "%cB",
+                                        lval, suffixTable[idx]);
+                } else {
+                    outCount = snprintf(outBuf, outBufLen, "B");
+                }
+                break;
+            case TYPE_MILLISECONDS:
+                if (((lval <= -1000) || (1000 <= lval)) &&
+                        (outBufLen || (outBuf[-1] == '0'))) {
+                    /* repaint as (fractional) seconds, possibly saving space */
+                    if (outBufLen) outBuf[0] = outBuf[-1];
+                    outBuf[-1] = outBuf[-2];
+                    outBuf[-2] = outBuf[-3];
+                    outBuf[-3] = '.';
+                    while ((outBufLen == 0) || (*outBuf == '0')) {
+                        --outBuf;
+                        ++outBufLen;
+                    }
+                    if (*outBuf != '.') {
+                       ++outBuf;
+                       --outBufLen;
+                    }
+                    outCount = snprintf(outBuf, outBufLen, "s");
+                } else {
+                    outCount = snprintf(outBuf, outBufLen, "ms");
+                }
+                break;
+            case TYPE_ALLOCATIONS:
+                outCount = 0;
+                /* outCount = snprintf(outBuf, outBufLen, " allocations"); */
+                break;
+            case TYPE_ID:
+                outCount = 0;
+                break;
+            case TYPE_PERCENT:
+                outCount = snprintf(outBuf, outBufLen, "%%");
+                break;
+            default: /* ? */
+                outCount = 0;
+                break;
+            }
+            ++cp;
+            --len;
+            if (outCount < outBufLen) {
+                outBuf += outCount;
+                outBufLen -= outCount;
+            } else if (outCount) {
+                /* halt output */
+                goto no_room;
+            }
+        }
+        if (!findChar(&cp, &len, ')')) len = 0;
+        if (!findChar(&cp, &len, ',')) len = 0;
+    }
 
 bail:
     *pEventData = eventData;
     *pEventDataLen = eventDataLen;
     *pOutBuf = outBuf;
     *pOutBufLen = outBufLen;
+    if (cp) {
+        *fmtStr = cp;
+        *fmtLen = len;
+    }
     return result;
 
 no_room:
@@ -757,7 +951,7 @@
         char *messageBuf, int messageBufLen)
 {
     size_t inCount;
-    unsigned int tagIndex;
+    uint32_t tagIndex;
     const unsigned char* eventData;
 
     entry->tv_sec = buf->sec;
@@ -774,6 +968,11 @@
     eventData = (const unsigned char*) buf->msg;
     struct logger_entry_v2 *buf2 = (struct logger_entry_v2 *)buf;
     if (buf2->hdr_size) {
+        if ((buf2->hdr_size < sizeof(((struct log_msg *)NULL)->entry_v1)) ||
+                (buf2->hdr_size > sizeof(((struct log_msg *)NULL)->entry))) {
+            fprintf(stderr, "+++ LOG: entry illegal hdr_size\n");
+            return -1;
+        }
         eventData = ((unsigned char *)buf2) + buf2->hdr_size;
         if ((buf2->hdr_size >= sizeof(struct logger_entry_v3)) &&
                 (((struct logger_entry_v3 *)buf)->lid == LOG_ID_SECURITY)) {
@@ -784,14 +983,14 @@
         }
     }
     inCount = buf->len;
-    if (inCount < 4)
-        return -1;
+    if (inCount < 4) return -1;
     tagIndex = get4LE(eventData);
     eventData += 4;
     inCount -= 4;
 
+    entry->tagLen = 0;
     if (map != NULL) {
-        entry->tag = android_lookupEventTag(map, tagIndex);
+        entry->tag = android_lookupEventTag_len(map, &entry->tagLen, tagIndex);
     } else {
         entry->tag = NULL;
     }
@@ -802,36 +1001,61 @@
      * shift the buffer pointers down.
      */
     if (entry->tag == NULL) {
-        int tagLen;
+        size_t tagLen;
 
-        tagLen = snprintf(messageBuf, messageBufLen, "[%d]", tagIndex);
+        tagLen = snprintf(messageBuf, messageBufLen, "[%" PRIu32 "]", tagIndex);
+        if (tagLen >= (size_t)messageBufLen) {
+            tagLen = messageBufLen - 1;
+        }
         entry->tag = messageBuf;
-        messageBuf += tagLen+1;
-        messageBufLen -= tagLen+1;
+        entry->tagLen = tagLen;
+        messageBuf += tagLen + 1;
+        messageBufLen -= tagLen + 1;
     }
 
     /*
      * Format the event log data into the buffer.
      */
+    const char* fmtStr = NULL;
+    size_t fmtLen = 0;
+    if (descriptive_output && map) {
+        fmtStr = android_lookupEventFormat_len(map, &fmtLen, tagIndex);
+    }
+
     char* outBuf = messageBuf;
-    size_t outRemaining = messageBufLen-1;      /* leave one for nul byte */
-    int result;
-    result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
-                &outRemaining);
+    size_t outRemaining = messageBufLen - 1; /* leave one for nul byte */
+    int result = 0;
+
+    if ((inCount > 0) || fmtLen) {
+        result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
+                                              &outRemaining, &fmtStr, &fmtLen);
+    }
+    if ((result == 1) && fmtStr) {
+        /* We overflowed :-(, let's repaint the line w/o format dressings */
+        eventData = (const unsigned char*)buf->msg;
+        if (buf2->hdr_size) {
+            eventData = ((unsigned char *)buf2) + buf2->hdr_size;
+        }
+        eventData += 4;
+        outBuf = messageBuf;
+        outRemaining = messageBufLen - 1;
+        result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
+                                              &outRemaining, NULL, NULL);
+    }
     if (result < 0) {
         fprintf(stderr, "Binary log entry conversion failed\n");
-        return -1;
-    } else if (result == 1) {
-        if (outBuf > messageBuf) {
-            /* leave an indicator */
-            *(outBuf-1) = '!';
-        } else {
-            /* no room to output anything at all */
-            *outBuf++ = '!';
-            outRemaining--;
+    }
+    if (result) {
+        if (!outRemaining) {
+            /* make space to leave an indicator */
+            --outBuf;
+            ++outRemaining;
         }
-        /* pretend we ate all the data */
+        *outBuf++ = (result < 0) ? '!' : '^'; /* Error or Truncation? */
+        outRemaining--;
+        /* pretend we ate all the data to prevent log stutter */
         inCount = 0;
+        if (result > 0) result = 0;
     }
 
     /* eat the silly terminating '\n' */
@@ -855,7 +1079,7 @@
 
     entry->message = messageBuf;
 
-    return 0;
+    return result;
 }
 
 /*
@@ -1352,17 +1576,17 @@
     uid[0] = '\0';
     if (p_format->uid_output) {
         if (entry->uid >= 0) {
-            const struct android_id_info *info = android_ids;
-            size_t i;
 
-            for (i = 0; i < android_id_count; ++i) {
-                if (info->aid == (unsigned int)entry->uid) {
-                    break;
-                }
-                ++info;
-            }
-            if ((i < android_id_count) && (strlen(info->name) <= 5)) {
-                 snprintf(uid, sizeof(uid), "%5s:", info->name);
+            /*
+             * This code is Android specific, bionic guarantees that
+             * calls to non-reentrant getpwuid() are thread safe.
+             */
+#ifndef __BIONIC__
+#warning "This code assumes that getpwuid is thread safe, only true with Bionic!"
+#endif
+            struct passwd* pwd = getpwuid(entry->uid);
+            if (pwd && (strlen(pwd->pw_name) <= 5)) {
+                 snprintf(uid, sizeof(uid), "%5s:", pwd->pw_name);
             } else {
                  // Not worth parsing package list, names all longer than 5
                  snprintf(uid, sizeof(uid), "%5d:", entry->uid);
@@ -1375,13 +1599,13 @@
     switch (p_format->format) {
         case FORMAT_TAG:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "%c/%-8s: ", priChar, entry->tag);
+                "%c/%-8.*s: ", priChar, (int)entry->tagLen, entry->tag);
             strcpy(suffixBuf + suffixLen, "\n");
             ++suffixLen;
             break;
         case FORMAT_PROCESS:
             len = snprintf(suffixBuf + suffixLen, sizeof(suffixBuf) - suffixLen,
-                "  (%s)\n", entry->tag);
+                "  (%.*s)\n", (int)entry->tagLen, entry->tag);
             suffixLen += MIN(len, sizeof(suffixBuf) - suffixLen);
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
                 "%c(%s%5d) ", priChar, uid, entry->pid);
@@ -1400,8 +1624,8 @@
             break;
         case FORMAT_TIME:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "%s %c/%-8s(%s%5d): ", timeBuf, priChar, entry->tag,
-                uid, entry->pid);
+                "%s %c/%-8.*s(%s%5d): ", timeBuf, priChar,
+                (int)entry->tagLen, entry->tag, uid, entry->pid);
             strcpy(suffixBuf + suffixLen, "\n");
             ++suffixLen;
             break;
@@ -1411,15 +1635,16 @@
                 *ret = ' ';
             }
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "%s %s%5d %5d %c %-8s: ", timeBuf,
-                uid, entry->pid, entry->tid, priChar, entry->tag);
+                "%s %s%5d %5d %c %-8.*s: ", timeBuf, uid, entry->pid,
+                entry->tid, priChar, (int)entry->tagLen, entry->tag);
             strcpy(suffixBuf + suffixLen, "\n");
             ++suffixLen;
             break;
         case FORMAT_LONG:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "[ %s %s%5d:%5d %c/%-8s ]\n",
-                timeBuf, uid, entry->pid, entry->tid, priChar, entry->tag);
+                "[ %s %s%5d:%5d %c/%-8.*s ]\n",
+                timeBuf, uid, entry->pid, entry->tid, priChar,
+                (int)entry->tagLen, entry->tag);
             strcpy(suffixBuf + suffixLen, "\n\n");
             suffixLen += 2;
             prefixSuffixIsHeaderFooter = 1;
@@ -1427,7 +1652,8 @@
         case FORMAT_BRIEF:
         default:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "%c/%-8s(%s%5d): ", priChar, entry->tag, uid, entry->pid);
+                "%c/%-8.*s(%s%5d): ", priChar, (int)entry->tagLen, entry->tag,
+                uid, entry->pid);
             strcpy(suffixBuf + suffixLen, "\n");
             ++suffixLen;
             break;
@@ -1565,8 +1791,7 @@
     outBuffer = android_log_formatLogLine(p_format, defaultBuffer,
             sizeof(defaultBuffer), entry, &totalLen);
 
-    if (!outBuffer)
-        return -1;
+    if (!outBuffer) return -1;
 
     do {
         ret = write(fd, outBuffer, totalLen);
diff --git a/liblog/pmsg_reader.c b/liblog/pmsg_reader.c
index 2e4fc5d..a0a69c1 100644
--- a/liblog/pmsg_reader.c
+++ b/liblog/pmsg_reader.c
@@ -144,14 +144,15 @@
     struct __attribute__((__packed__)) {
         android_pmsg_log_header_t p;
         android_log_header_t l;
+        uint8_t prio;
     } buf;
     static uint8_t preread_count;
     bool is_system;
 
     memset(log_msg, 0, sizeof(*log_msg));
 
-    if (transp->context.fd <= 0) {
-        int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
+    if (atomic_load(&transp->context.fd) <= 0) {
+        int i, fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
 
         if (fd < 0) {
             return -errno;
@@ -163,13 +164,22 @@
                 return -errno;
             }
         }
-        transp->context.fd = fd;
+        i = atomic_exchange(&transp->context.fd, fd);
+        if ((i > 0) && (i != fd)) {
+            close(i);
+        }
         preread_count = 0;
     }
 
     while(1) {
+        int fd;
+
         if (preread_count < sizeof(buf)) {
-            ret = TEMP_FAILURE_RETRY(read(transp->context.fd,
+            fd = atomic_load(&transp->context.fd);
+            if (fd <= 0) {
+                return -EBADF;
+            }
+            ret = TEMP_FAILURE_RETRY(read(fd,
                                           &buf.p.magic + preread_count,
                                           sizeof(buf) - preread_count));
             if (ret < 0) {
@@ -180,11 +190,16 @@
         if (preread_count != sizeof(buf)) {
             return preread_count ? -EIO : -EAGAIN;
         }
-        if ((buf.p.magic != LOGGER_MAGIC)
-         || (buf.p.len <= sizeof(buf))
-         || (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD))
-         || (buf.l.id >= LOG_ID_MAX)
-         || (buf.l.realtime.tv_nsec >= NS_PER_SEC)) {
+        if ((buf.p.magic != LOGGER_MAGIC) ||
+                (buf.p.len <= sizeof(buf)) ||
+                (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD)) ||
+                (buf.l.id >= LOG_ID_MAX) ||
+                (buf.l.realtime.tv_nsec >= NS_PER_SEC) ||
+                ((buf.l.id != LOG_ID_EVENTS) &&
+                    (buf.l.id != LOG_ID_SECURITY) &&
+                    ((buf.prio == ANDROID_LOG_UNKNOWN) ||
+                        (buf.prio == ANDROID_LOG_DEFAULT) ||
+                        (buf.prio >= ANDROID_LOG_SILENT)))) {
             do {
                 memmove(&buf.p.magic, &buf.p.magic + 1, --preread_count);
             } while (preread_count && (buf.p.magic != LOGGER_MAGIC));
@@ -202,11 +217,17 @@
             uid = get_best_effective_uid();
             is_system = uid_has_log_permission(uid);
             if (is_system || (uid == buf.p.uid)) {
-                ret = TEMP_FAILURE_RETRY(read(transp->context.fd,
-                                          is_system ?
-                                              log_msg->entry_v4.msg :
-                                              log_msg->entry_v3.msg,
-                                          buf.p.len - sizeof(buf)));
+                char *msg = is_system ?
+                    log_msg->entry_v4.msg :
+                    log_msg->entry_v3.msg;
+                *msg = buf.prio;
+                fd = atomic_load(&transp->context.fd);
+                if (fd <= 0) {
+                    return -EBADF;
+                }
+                ret = TEMP_FAILURE_RETRY(read(fd,
+                                              msg + sizeof(buf.prio),
+                                              buf.p.len - sizeof(buf)));
                 if (ret < 0) {
                     return -errno;
                 }
@@ -214,7 +235,7 @@
                     return -EIO;
                 }
 
-                log_msg->entry_v4.len = buf.p.len - sizeof(buf);
+                log_msg->entry_v4.len = buf.p.len - sizeof(buf) + sizeof(buf.prio);
                 log_msg->entry_v4.hdr_size = is_system ?
                     sizeof(log_msg->entry_v4) :
                     sizeof(log_msg->entry_v3);
@@ -227,16 +248,23 @@
                     log_msg->entry_v4.uid = buf.p.uid;
                 }
 
-                return ret + log_msg->entry_v4.hdr_size;
+                return ret + sizeof(buf.prio) + log_msg->entry_v4.hdr_size;
             }
         }
 
-        current = TEMP_FAILURE_RETRY(lseek(transp->context.fd,
-                                           (off_t)0, SEEK_CUR));
+        fd = atomic_load(&transp->context.fd);
+        if (fd <= 0) {
+            return -EBADF;
+        }
+        current = TEMP_FAILURE_RETRY(lseek(fd, (off_t)0, SEEK_CUR));
         if (current < 0) {
             return -errno;
         }
-        next = TEMP_FAILURE_RETRY(lseek(transp->context.fd,
+        fd = atomic_load(&transp->context.fd);
+        if (fd <= 0) {
+            return -EBADF;
+        }
+        next = TEMP_FAILURE_RETRY(lseek(fd,
                                         (off_t)(buf.p.len - sizeof(buf)),
                                         SEEK_CUR));
         if (next < 0) {
@@ -250,10 +278,10 @@
 
 static void pmsgClose(struct android_log_logger_list *logger_list __unused,
                       struct android_log_transport_context *transp) {
-    if (transp->context.fd > 0) {
-        close (transp->context.fd);
+    int fd = atomic_exchange(&transp->context.fd, 0);
+    if (fd > 0) {
+        close (fd);
     }
-    transp->context.fd = 0;
 }
 
 LIBLOG_ABI_PRIVATE ssize_t __android_log_pmsg_file_read(
@@ -335,6 +363,10 @@
         char *msg = (char *)&transp.logMsg + hdr_size;
         char *split = NULL;
 
+        if ((hdr_size < sizeof(transp.logMsg.entry_v1)) ||
+                (hdr_size > sizeof(transp.logMsg.entry))) {
+            continue;
+        }
         /* Check for invalid sequence number */
         if ((transp.logMsg.entry.nsec % ANDROID_LOG_PMSG_FILE_SEQUENCE) ||
                 ((transp.logMsg.entry.nsec / ANDROID_LOG_PMSG_FILE_SEQUENCE) >=
diff --git a/liblog/pmsg_writer.c b/liblog/pmsg_writer.c
index 944feba..c1c068e 100644
--- a/liblog/pmsg_writer.c
+++ b/liblog/pmsg_writer.c
@@ -20,14 +20,12 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
 #include <time.h>
 
-#include <log/log.h>
-#include <log/logger.h>
-
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
@@ -53,18 +51,25 @@
 
 static int pmsgOpen()
 {
-    if (pmsgLoggerWrite.context.fd < 0) {
-        pmsgLoggerWrite.context.fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
+    int fd = atomic_load(&pmsgLoggerWrite.context.fd);
+    if (fd < 0) {
+        int i;
+
+        fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
+        i = atomic_exchange(&pmsgLoggerWrite.context.fd, fd);
+        if ((i >= 0) && (i != fd)) {
+            close(i);
+        }
     }
 
-    return pmsgLoggerWrite.context.fd;
+    return fd;
 }
 
 static void pmsgClose()
 {
-    if (pmsgLoggerWrite.context.fd >= 0) {
-        close(pmsgLoggerWrite.context.fd);
-        pmsgLoggerWrite.context.fd = -1;
+    int fd = atomic_exchange(&pmsgLoggerWrite.context.fd, -1);
+    if (fd >= 0) {
+        close(fd);
     }
 }
 
@@ -78,7 +83,7 @@
             !__android_log_is_debuggable()) {
         return -EINVAL;
     }
-    if (pmsgLoggerWrite.context.fd < 0) {
+    if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
         if (access("/dev/pmsg0", W_OK) == 0) {
             return 0;
         }
@@ -115,7 +120,7 @@
         }
     }
 
-    if (pmsgLoggerWrite.context.fd < 0) {
+    if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
         return -EBADF;
     }
 
@@ -169,7 +174,8 @@
     }
     pmsgHeader.len += payloadSize;
 
-    ret = TEMP_FAILURE_RETRY(writev(pmsgLoggerWrite.context.fd, newVec, i));
+    ret = TEMP_FAILURE_RETRY(writev(atomic_load(&pmsgLoggerWrite.context.fd),
+                                    newVec, i));
     if (ret < 0) {
         ret = errno ? -errno : -ENOTCONN;
     }
@@ -206,7 +212,7 @@
         char prio,
         const char *filename,
         const char *buf, size_t len) {
-    int fd;
+    bool weOpened;
     size_t length, packet_len;
     const char *tag;
     char *cp, *slash;
@@ -228,16 +234,6 @@
         return -ENOMEM;
     }
 
-    fd = pmsgLoggerWrite.context.fd;
-    if (fd < 0) {
-        __android_log_lock();
-        fd = pmsgOpen();
-        __android_log_unlock();
-        if (fd < 0) {
-            return -EBADF;
-        }
-    }
-
     tag = cp;
     slash = strrchr(cp, '/');
     if (slash) {
@@ -256,6 +252,7 @@
     vec[1].iov_base = (unsigned char *)tag;
     vec[1].iov_len  = length;
 
+    weOpened = false;
     for (ts.tv_nsec = 0, length = len;
             length;
             ts.tv_nsec += ANDROID_LOG_PMSG_FILE_SEQUENCE) {
@@ -279,15 +276,36 @@
         vec[2].iov_base = (unsigned char *)buf;
         vec[2].iov_len  = transfer;
 
+        if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
+            if (!weOpened) { /* Impossible for weOpened = true here */
+                __android_log_lock();
+            }
+            weOpened = atomic_load(&pmsgLoggerWrite.context.fd) < 0;
+            if (!weOpened) {
+                __android_log_unlock();
+            } else if (pmsgOpen() < 0) {
+                __android_log_unlock();
+                return -EBADF;
+            }
+        }
+
         ret = pmsgWrite(logId, &ts, vec, sizeof(vec) / sizeof(vec[0]));
 
         if (ret <= 0) {
+            if (weOpened) {
+                pmsgClose();
+                __android_log_unlock();
+            }
             free(cp);
-            return ret;
+            return ret ? ret : (len - length);
         }
         length -= transfer;
         buf += transfer;
     }
+    if (weOpened) {
+        pmsgClose();
+        __android_log_unlock();
+    }
     free(cp);
     return len;
 }
diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk
index 8229859..158987a 100644
--- a/liblog/tests/Android.mk
+++ b/liblog/tests/Android.mk
@@ -28,7 +28,6 @@
     -Wall -Wextra \
     -Werror \
     -fno-builtin \
-    -std=gnu++11
 
 benchmark_src_files := \
     benchmark_main.cpp \
@@ -40,7 +39,7 @@
 LOCAL_MODULE := $(test_module_prefix)benchmarks
 LOCAL_MODULE_TAGS := $(test_tags)
 LOCAL_CFLAGS += $(benchmark_c_flags)
-LOCAL_SHARED_LIBRARIES += liblog libm
+LOCAL_SHARED_LIBRARIES += liblog libm libbase
 LOCAL_SRC_FILES := $(benchmark_src_files)
 include $(BUILD_NATIVE_TEST)
 
@@ -54,7 +53,6 @@
     -Wall -Wextra \
     -Werror \
     -fno-builtin \
-    -std=gnu++11
 
 test_src_files := \
     liblog_test.cpp
@@ -73,6 +71,6 @@
 LOCAL_MODULE := $(test_module_prefix)unit-tests
 LOCAL_MODULE_TAGS := $(test_tags)
 LOCAL_CFLAGS += $(test_c_flags)
-LOCAL_SHARED_LIBRARIES := liblog libcutils
+LOCAL_SHARED_LIBRARIES := liblog libcutils libbase
 LOCAL_SRC_FILES := $(test_src_files)
 include $(BUILD_NATIVE_TEST)
diff --git a/liblog/tests/benchmark.h b/liblog/tests/benchmark.h
index 7f96e6d..e9280f6 100644
--- a/liblog/tests/benchmark.h
+++ b/liblog/tests/benchmark.h
@@ -38,7 +38,7 @@
   Benchmark(const char* name, void (*fn)(int)) : name_(strdup(name)), fn_(fn) {
     BenchmarkRegister(this);
   }
-  Benchmark(const char* name) : name_(strdup(name)), fn_(NULL) {}
+  explicit Benchmark(const char* name) : name_(strdup(name)), fn_(NULL) {}
 
   virtual ~Benchmark() {
     free(name_);
@@ -141,7 +141,7 @@
 void StopBenchmarkTiming(uint64_t);
 
 #define BENCHMARK(f) \
-    static ::testing::Benchmark* _benchmark_##f __attribute__((unused)) = \
-        (::testing::Benchmark*)::testing::BenchmarkFactory(#f, f)
+    static ::testing::Benchmark* _benchmark_##f __attribute__((unused)) = /* NOLINT */ \
+        (::testing::Benchmark*)::testing::BenchmarkFactory(#f, f) /* NOLINT */
 
 #endif // BIONIC_BENCHMARK_H_
diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp
index 9dd6f03..f05a955 100644
--- a/liblog/tests/libc_test.cpp
+++ b/liblog/tests/libc_test.cpp
@@ -14,132 +14,32 @@
  * limitations under the License.
  */
 
-#include <fcntl.h>
-#include <sys/cdefs.h>
-
 #include <gtest/gtest.h>
 
-// Should be in bionic test suite, *but* we are using liblog to confirm
-// end-to-end logging, so let the overly cute oedipus complex begin ...
-#include "../../../../bionic/libc/bionic/libc_logging.cpp" // not Standalone
-#define _ANDROID_LOG_H // Priorities redefined
-#define _LIBS_LOG_LOG_H // log ids redefined
-typedef unsigned char log_id_t; // log_id_t missing as a result
-#define _LIBS_LOG_LOG_READ_H // log_time redefined
-
-#include <log/log.h>
-#include <log/logger.h>
-#include <log/log_read.h>
-
-TEST(libc, __libc_android_log_event_int) {
-    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)));
-
-    struct timespec ts;
-    clock_gettime(CLOCK_MONOTONIC, &ts);
-    int value = ts.tv_nsec;
-
-    __libc_android_log_event_int(0, value);
-    usleep(1000000);
-
-    int count = 0;
-
-    for (;;) {
-        log_msg log_msg;
-        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
-            break;
-        }
-
-        ASSERT_EQ(log_msg.entry.pid, pid);
-
-        if ((log_msg.entry.len != (4 + 1 + 4))
-         || ((int)log_msg.id() != LOG_ID_EVENTS)) {
-            continue;
-        }
-
-        char *eventData = log_msg.msg();
-
-        int incoming = (eventData[0] & 0xFF) |
-                      ((eventData[1] & 0xFF) << 8) |
-                      ((eventData[2] & 0xFF) << 16) |
-                      ((eventData[3] & 0xFF) << 24);
-
-        if (incoming != 0) {
-            continue;
-        }
-
-        if (eventData[4] != EVENT_TYPE_INT) {
-            continue;
-        }
-
-        incoming = (eventData[4 + 1 + 0] & 0xFF) |
-                  ((eventData[4 + 1 + 1] & 0xFF) << 8) |
-                  ((eventData[4 + 1 + 2] & 0xFF) << 16) |
-                  ((eventData[4 + 1 + 3] & 0xFF) << 24);
-
-        if (incoming == value) {
-            ++count;
-        }
-    }
-
-    EXPECT_EQ(1, count);
-
-    android_logger_list_close(logger_list);
-}
-
-TEST(libc, __libc_fatal_no_abort) {
-    struct logger_list *logger_list;
-
-    pid_t pid = getpid();
-
-    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        (log_id_t)LOG_ID_CRASH, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
-
-    char b[80];
-    struct timespec ts;
-    clock_gettime(CLOCK_MONOTONIC, &ts);
-
-    __libc_fatal_no_abort("%u.%09u", (unsigned)ts.tv_sec, (unsigned)ts.tv_nsec);
-    snprintf(b, sizeof(b),"%u.%09u", (unsigned)ts.tv_sec, (unsigned)ts.tv_nsec);
-    usleep(1000000);
-
-    int count = 0;
-
-    for (;;) {
-        log_msg log_msg;
-        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
-            break;
-        }
-
-        ASSERT_EQ(log_msg.entry.pid, pid);
-
-        if ((int)log_msg.id() != LOG_ID_CRASH) {
-            continue;
-        }
-
-        char *data = log_msg.msg();
-
-        if ((*data == ANDROID_LOG_FATAL)
-                && !strcmp(data + 1, "libc")
-                && !strcmp(data + 1 + strlen(data + 1) + 1, b)) {
-            ++count;
-        }
-    }
-
-    EXPECT_EQ(1, count);
-
-    android_logger_list_close(logger_list);
-}
+#include <errno.h>
+#include <stdio.h>
 
 TEST(libc, __pstore_append) {
     FILE *fp;
     ASSERT_TRUE(NULL != (fp = fopen("/dev/pmsg0", "a")));
     static const char message[] = "libc.__pstore_append\n";
     ASSERT_EQ((size_t)1, fwrite(message, sizeof(message), 1, fp));
-    ASSERT_EQ(0, fclose(fp));
-    fprintf(stderr, "Reboot, ensure string libc.__pstore_append is in /sys/fs/pstore/pmsg-ramoops-0\n");
+    int fflushReturn = fflush(fp);
+    int fflushErrno = fflushReturn ? errno : 0;
+    ASSERT_EQ(0, fflushReturn);
+    ASSERT_EQ(0, fflushErrno);
+    int fcloseReturn = fclose(fp);
+    int fcloseErrno = fcloseReturn ? errno : 0;
+    ASSERT_EQ(0, fcloseReturn);
+    ASSERT_EQ(0, fcloseErrno);
+    if ((fcloseErrno == ENOMEM) || (fflushErrno == ENOMEM)) {
+        fprintf(stderr,
+                "Kernel does not have space allocated to pmsg pstore driver configured\n"
+               );
+    }
+    if (!fcloseReturn && !fcloseErrno && !fflushReturn && !fflushReturn) {
+        fprintf(stderr,
+                "Reboot, ensure string libc.__pstore_append is in /sys/fs/pstore/pmsg-ramoops-0\n"
+               );
+    }
 }
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index 01fb50f..44045c3 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -21,9 +21,6 @@
 #include <unistd.h>
 
 #include <cutils/sockets.h>
-#include <log/log.h>
-#include <log/logger.h>
-#include <log/log_read.h>
 #include <private/android_logger.h>
 
 #include "benchmark.h"
@@ -205,7 +202,7 @@
         android_log_header_t header;
         android_log_event_int_t payload;
     };
-    char buf[sizeof(struct packet) + 8] __aligned(8);
+    alignas(8) char buf[sizeof(struct packet) + 8];
     memset(buf, 0, sizeof(buf));
     struct packet *buffer = (struct packet*)(((uintptr_t)buf + 7) & ~7);
     if (((uintptr_t)&buffer->pmsg_header) & 7) {
@@ -281,7 +278,7 @@
         android_log_header_t header;
         android_log_event_int_t payload;
     };
-    char buf[sizeof(struct packet) + 8] __aligned(8);
+    alignas(8) char buf[sizeof(struct packet) + 8];
     memset(buf, 0, sizeof(buf));
     struct packet *buffer = (struct packet*)((((uintptr_t)buf + 7) & ~7) + 1);
     if ((((uintptr_t)&buffer->pmsg_header) & 7) != 1) {
@@ -357,7 +354,7 @@
         android_log_header_t header;
         android_log_event_int_t payload;
     };
-    char buf[sizeof(struct packet) + 8 + LOGGER_ENTRY_MAX_PAYLOAD] __aligned(8);
+    alignas(8) char buf[sizeof(struct packet) + 8 + LOGGER_ENTRY_MAX_PAYLOAD];
     memset(buf, 0, sizeof(buf));
     struct packet *buffer = (struct packet*)(((uintptr_t)buf + 7) & ~7);
     if (((uintptr_t)&buffer->pmsg_header) & 7) {
@@ -430,7 +427,7 @@
         android_log_header_t header;
         android_log_event_int_t payload;
     };
-    char buf[sizeof(struct packet) + 8 + LOGGER_ENTRY_MAX_PAYLOAD] __aligned(8);
+    alignas(8) char buf[sizeof(struct packet) + 8 + LOGGER_ENTRY_MAX_PAYLOAD];
     memset(buf, 0, sizeof(buf));
     struct packet *buffer = (struct packet*)((((uintptr_t)buf + 7) & ~7) + 1);
     if ((((uintptr_t)&buffer->pmsg_header) & 7) != 1) {
@@ -542,7 +539,7 @@
 
             char* eventData = log_msg.msg();
 
-            if (eventData[4] != EVENT_TYPE_LONG) {
+            if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
                 continue;
             }
             log_time tx(eventData + 4 + 1);
@@ -622,7 +619,7 @@
 
             char* eventData = log_msg.msg();
 
-            if (eventData[4] != EVENT_TYPE_LONG) {
+            if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
                 continue;
             }
             log_time tx(eventData + 4 + 1);
@@ -651,10 +648,14 @@
  *	Measure the time it takes for __android_log_is_loggable.
  */
 static void BM_is_loggable(int iters) {
+    static const char logd[] = "logd";
+
     StartBenchmarkTiming();
 
     for (int i = 0; i < iters; ++i) {
-        __android_log_is_loggable(ANDROID_LOG_WARN, "logd", ANDROID_LOG_VERBOSE);
+        __android_log_is_loggable_len(ANDROID_LOG_WARN,
+                                      logd, strlen(logd),
+                                      ANDROID_LOG_VERBOSE);
     }
 
     StopBenchmarkTiming();
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index f0acdf8..02a572d 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -14,20 +14,26 @@
  * limitations under the License.
  */
 
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
 #include <semaphore.h>
 #include <signal.h>
+#include <stdio.h>
 #include <string.h>
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
 #include <cutils/properties.h>
 #include <gtest/gtest.h>
-#include <log/log.h>
-#include <log/logger.h>
-#include <log/log_read.h>
 #include <log/logprint.h>
+#include <log/log_event_list.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
@@ -124,6 +130,70 @@
     ASSERT_LT(0, ret);
 }
 
+std::string popenToString(std::string command) {
+    std::string ret;
+
+    FILE* fp = popen(command.c_str(), "r");
+    if (fp) {
+        if (!android::base::ReadFdToString(fileno(fp), &ret)) ret = "";
+        pclose(fp);
+    }
+    return ret;
+}
+
+static bool isPmsgActive() {
+    pid_t pid = getpid();
+
+    std::string myPidFds = popenToString(android::base::StringPrintf(
+                                             "ls -l /proc/%d/fd", pid));
+    if (myPidFds.length() == 0) return true; // guess it is?
+
+    return std::string::npos != myPidFds.find(" -> /dev/pmsg0");
+}
+
+static bool isLogdwActive() {
+    std::string logdwSignature = popenToString(
+        "grep /dev/socket/logdw /proc/net/unix");
+    size_t beginning = logdwSignature.find(" ");
+    if (beginning == std::string::npos) return true;
+    beginning = logdwSignature.find(" ", beginning + 1);
+    if (beginning == std::string::npos) return true;
+    size_t end = logdwSignature.find(" ", beginning + 1);
+    if (end == std::string::npos) return true;
+    end = logdwSignature.find(" ", end + 1);
+    if (end == std::string::npos) return true;
+    end = logdwSignature.find(" ", end + 1);
+    if (end == std::string::npos) return true;
+    end = logdwSignature.find(" ", end + 1);
+    if (end == std::string::npos) return true;
+    std::string allLogdwEndpoints = popenToString(
+        "grep ' 00000002" +
+        logdwSignature.substr(beginning, end - beginning) +
+        " ' /proc/net/unix | " +
+        "sed -n 's/.* \\([0-9][0-9]*\\)$/ -> socket:[\\1]/p'");
+    if (allLogdwEndpoints.length() == 0) return true;
+
+    // NB: allLogdwEndpoints has some false positives in it, but those
+    // strangers do not overlap with the simplistic activities inside this
+    // test suite.
+
+    pid_t pid = getpid();
+
+    std::string myPidFds = popenToString(android::base::StringPrintf(
+        "ls -l /proc/%d/fd", pid));
+    if (myPidFds.length() == 0) return true;
+
+    // NB: fgrep with multiple strings is broken in Android
+    for (beginning = 0;
+         (end = allLogdwEndpoints.find("\n", beginning)) != std::string::npos;
+         beginning = end + 1) {
+        if (myPidFds.find(allLogdwEndpoints.substr(beginning,
+                                                   end - beginning)) !=
+            std::string::npos) return true;
+    }
+    return false;
+}
+
 TEST(liblog, __android_log_btwrite__android_logger_list_read) {
     struct logger_list *logger_list;
 
@@ -135,10 +205,22 @@
     // Check that we can close and reopen the logger
     log_time ts(CLOCK_MONOTONIC);
     ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
+    bool pmsgActiveAfter__android_log_btwrite = isPmsgActive();
+    bool logdwActiveAfter__android_log_btwrite = isLogdwActive();
+    EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
+    EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
     __android_log_close();
+    bool pmsgActiveAfter__android_log_close = isPmsgActive();
+    bool logdwActiveAfter__android_log_close = isLogdwActive();
+    EXPECT_FALSE(pmsgActiveAfter__android_log_close);
+    EXPECT_FALSE(logdwActiveAfter__android_log_close);
 
     log_time ts1(CLOCK_MONOTONIC);
     ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
+    pmsgActiveAfter__android_log_btwrite = isPmsgActive();
+    logdwActiveAfter__android_log_btwrite = isLogdwActive();
+    EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
+    EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
     usleep(1000000);
 
     int count = 0;
@@ -159,7 +241,7 @@
 
         char *eventData = log_msg.msg();
 
-        if (eventData[4] != EVENT_TYPE_LONG) {
+        if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
             continue;
         }
 
@@ -182,7 +264,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();
@@ -190,10 +272,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;
@@ -208,32 +310,36 @@
 
         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;
         }
 
         char *eventData = log_msg.msg();
 
-        if (eventData[4] != EVENT_TYPE_STRING) {
+        if (!eventData || (eventData[4] != EVENT_TYPE_STRING)) {
             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));
+            if (length != total) {
+                fprintf(stderr, "Expect \"Binary log entry conversion failed\"\n");
+            }
+            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);
         }
     }
@@ -243,18 +349,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;
@@ -269,34 +412,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);
@@ -304,6 +438,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";
@@ -453,7 +599,7 @@
 
         char *eventData = log_msg.msg();
 
-        if (eventData[4] != EVENT_TYPE_LONG) {
+        if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
             continue;
         }
 
@@ -584,7 +730,7 @@
 
         char *eventData = log_msg.msg();
 
-        if (eventData[4] != EVENT_TYPE_LONG) {
+        if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
             continue;
         }
 
@@ -735,7 +881,7 @@
 
         char *eventData = log_msg.msg();
 
-        if (eventData[4] != EVENT_TYPE_LONG) {
+        if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
             continue;
         }
 
@@ -775,7 +921,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\
@@ -937,9 +1083,9 @@
             continue;
         }
 
-        char *data = log_msg.msg() + 1;
+        char *data = log_msg.msg();
 
-        if (strcmp(data, tag)) {
+        if (!data || strcmp(++data, tag)) {
             continue;
         }
 
@@ -1054,9 +1200,9 @@
             continue;
         }
 
-        char *data = log_msg.msg() + 1;
+        char *data = log_msg.msg();
 
-        if (strcmp(data, tag)) {
+        if (!data || strcmp(++data, tag)) {
             continue;
         }
 
@@ -1277,8 +1423,8 @@
                 continue;
             }
             fprintf(stderr, "i=%zu j=%zu\r", i, j);
-            bool android_log_is_loggable = __android_log_is_loggable(
-                levels[i].level, tag, levels[j].level);
+            bool android_log_is_loggable = __android_log_is_loggable_len(
+                levels[i].level, tag, strlen(tag), levels[j].level);
             if ((levels[i].level < levels[j].level)
                     || (levels[j].level == -1)) {
                 if (android_log_is_loggable) {
@@ -1286,8 +1432,8 @@
                 }
                 EXPECT_FALSE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_FALSE(__android_log_is_loggable(
-                        levels[i].level, tag, levels[j].level));
+                    EXPECT_FALSE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), levels[j].level));
                 }
             } else {
                 if (!android_log_is_loggable) {
@@ -1295,8 +1441,8 @@
                 }
                 EXPECT_TRUE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_TRUE(__android_log_is_loggable(
-                        levels[i].level, tag, levels[j].level));
+                    EXPECT_TRUE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), levels[j].level));
                 }
             }
         }
@@ -1315,9 +1461,10 @@
             snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
                     i, j, key, buf);
+            usleep(20000);
             property_set(key, buf);
-            bool android_log_is_loggable = __android_log_is_loggable(
-                levels[i].level, tag, ANDROID_LOG_DEBUG);
+            bool android_log_is_loggable = __android_log_is_loggable_len(
+                levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
             if ((levels[i].level < levels[j].level)
                     || (levels[j].level == -1)
                     || ((levels[i].level < ANDROID_LOG_DEBUG)
@@ -1327,8 +1474,8 @@
                 }
                 EXPECT_FALSE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_FALSE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_FALSE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             } else {
                 if (!android_log_is_loggable) {
@@ -1336,17 +1483,18 @@
                 }
                 EXPECT_TRUE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_TRUE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_TRUE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             }
+            usleep(20000);
             property_set(key, "");
 
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
                     i, j, key + base_offset, buf);
             property_set(key + base_offset, buf);
-            android_log_is_loggable = __android_log_is_loggable(
-                levels[i].level, tag, ANDROID_LOG_DEBUG);
+            android_log_is_loggable = __android_log_is_loggable_len(
+                levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
             if ((levels[i].level < levels[j].level)
                     || (levels[j].level == -1)
                     || ((levels[i].level < ANDROID_LOG_DEBUG)
@@ -1356,8 +1504,8 @@
                 }
                 EXPECT_FALSE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_FALSE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_FALSE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             } else {
                 if (!android_log_is_loggable) {
@@ -1365,10 +1513,11 @@
                 }
                 EXPECT_TRUE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_TRUE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_TRUE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             }
+            usleep(20000);
             property_set(key + base_offset, "");
 
             strcpy(key, log_namespace);
@@ -1376,8 +1525,8 @@
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
                     i, j, key, buf);
             property_set(key, buf);
-            android_log_is_loggable = __android_log_is_loggable(
-                levels[i].level, tag, ANDROID_LOG_DEBUG);
+            android_log_is_loggable = __android_log_is_loggable_len(
+                levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
             if ((levels[i].level < levels[j].level)
                     || (levels[j].level == -1)
                     || ((levels[i].level < ANDROID_LOG_DEBUG)
@@ -1387,8 +1536,8 @@
                 }
                 EXPECT_FALSE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_FALSE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_FALSE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             } else {
                 if (!android_log_is_loggable) {
@@ -1396,17 +1545,18 @@
                 }
                 EXPECT_TRUE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_TRUE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_TRUE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             }
+            usleep(20000);
             property_set(key, "");
 
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
                     i, j, key + base_offset, buf);
             property_set(key + base_offset, buf);
-            android_log_is_loggable = __android_log_is_loggable(
-                levels[i].level, tag, ANDROID_LOG_DEBUG);
+            android_log_is_loggable = __android_log_is_loggable_len(
+                levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
             if ((levels[i].level < levels[j].level)
                     || (levels[j].level == -1)
                     || ((levels[i].level < ANDROID_LOG_DEBUG)
@@ -1416,8 +1566,8 @@
                 }
                 EXPECT_FALSE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_FALSE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_FALSE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             } else {
                 if (!android_log_is_loggable) {
@@ -1425,10 +1575,11 @@
                 }
                 EXPECT_TRUE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_TRUE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_TRUE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             }
+            usleep(20000);
             property_set(key + base_offset, "");
         }
     }
@@ -1436,6 +1587,7 @@
     // All combinations of level and tag properties, but with global set to INFO
     strcpy(key, log_namespace);
     key[sizeof(log_namespace) - 2] = '\0';
+    usleep(20000);
     property_set(key, "I");
     snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
     for(size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
@@ -1449,9 +1601,10 @@
 
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
                     i, j, key, buf);
+            usleep(20000);
             property_set(key, buf);
-            bool android_log_is_loggable = __android_log_is_loggable(
-                levels[i].level, tag, ANDROID_LOG_DEBUG);
+            bool android_log_is_loggable = __android_log_is_loggable_len(
+                levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
             if ((levels[i].level < levels[j].level)
                     || (levels[j].level == -1)
                     || ((levels[i].level < ANDROID_LOG_INFO) // Yes INFO
@@ -1461,8 +1614,8 @@
                 }
                 EXPECT_FALSE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_FALSE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_FALSE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             } else {
                 if (!android_log_is_loggable) {
@@ -1470,17 +1623,18 @@
                 }
                 EXPECT_TRUE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_TRUE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_TRUE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             }
+            usleep(20000);
             property_set(key, "");
 
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
                     i, j, key + base_offset, buf);
             property_set(key + base_offset, buf);
-            android_log_is_loggable = __android_log_is_loggable(
-                levels[i].level, tag, ANDROID_LOG_DEBUG);
+            android_log_is_loggable = __android_log_is_loggable_len(
+                levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
             if ((levels[i].level < levels[j].level)
                     || (levels[j].level == -1)
                     || ((levels[i].level < ANDROID_LOG_INFO) // Yes INFO
@@ -1490,8 +1644,8 @@
                 }
                 EXPECT_FALSE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_FALSE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_FALSE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             } else {
                 if (!android_log_is_loggable) {
@@ -1499,16 +1653,18 @@
                 }
                 EXPECT_TRUE(android_log_is_loggable);
                 for(size_t k = 10; k; --k) {
-                    EXPECT_TRUE(__android_log_is_loggable(
-                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                    EXPECT_TRUE(__android_log_is_loggable_len(
+                        levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
                 }
             }
+            usleep(20000);
             property_set(key + base_offset, "");
         }
     }
 
     // reset parms
     snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
+    usleep(20000);
     property_set(key, hold[0]);
     property_set(key + base_offset, hold[1]);
     strcpy(key, log_namespace);
@@ -1543,6 +1699,9 @@
         }
 
         char *eventData = log_msg.msg();
+        if (!eventData) {
+            continue;
+        }
 
         // Tag
         int tag = get4LE(eventData);
@@ -1624,6 +1783,10 @@
         }
 
         char *eventData = log_msg.msg();
+        if (!eventData) {
+            continue;
+        }
+
         char *original = eventData;
 
         // Tag
@@ -1711,6 +1874,9 @@
         }
 
         char *eventData = log_msg.msg();
+        if (!eventData) {
+            continue;
+        }
 
         // Tag
         int tag = get4LE(eventData);
@@ -1754,6 +1920,9 @@
         }
 
         char *eventData = log_msg.msg();
+        if (!eventData) {
+            continue;
+        }
 
         // Tag
         int tag = get4LE(eventData);
@@ -1810,6 +1979,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";
@@ -1833,6 +2010,9 @@
         }
 
         char *eventData = log_msg.msg();
+        if (!eventData) {
+            continue;
+        }
 
         // Tag
         int tag = get4LE(eventData);
@@ -1890,6 +2070,9 @@
         }
 
         char *eventData = log_msg.msg();
+        if (!eventData) {
+            continue;
+        }
 
         // Tag
         int tag = get4LE(eventData);
@@ -2378,16 +2561,19 @@
         android_log_format_free(logformat);
 
         // test buffer reading API
-        snprintf(msgBuf, sizeof(msgBuf), "I/[%d]", get4LE(eventData));
-        print_barrier();
-        fprintf(stderr, "%-10s(%5u): ", msgBuf, pid);
-        memset(msgBuf, 0, sizeof(msgBuf));
-        int buffer_to_string = android_log_buffer_to_string(
-            eventData + sizeof(uint32_t),
-            log_msg.entry.len - sizeof(uint32_t),
-            msgBuf, sizeof(msgBuf));
-        fprintf(stderr, "%s\n", msgBuf);
-        print_barrier();
+        int buffer_to_string = -1;
+        if (eventData) {
+            snprintf(msgBuf, sizeof(msgBuf), "I/[%d]", get4LE(eventData));
+            print_barrier();
+            fprintf(stderr, "%-10s(%5u): ", msgBuf, pid);
+            memset(msgBuf, 0, sizeof(msgBuf));
+            buffer_to_string = android_log_buffer_to_string(
+                eventData + sizeof(uint32_t),
+                log_msg.entry.len - sizeof(uint32_t),
+                msgBuf, sizeof(msgBuf));
+            fprintf(stderr, "%s\n", msgBuf);
+            print_barrier();
+        }
         EXPECT_EQ(0, buffer_to_string);
         EXPECT_EQ(strlen(expected_string), strlen(msgBuf));
         EXPECT_EQ(0, strcmp(expected_string, msgBuf));
@@ -2465,16 +2651,59 @@
     ASSERT_TRUE(NULL == ctx);
 }
 
+TEST(liblog, android_log_write_list_buffer) {
+    __android_log_event_list ctx(1005);
+    ctx << 1005 << "tag_def" << "(tag|1),(name|3),(format|3)";
+    std::string buffer(ctx);
+    ctx.close();
+
+    char msgBuf[1024];
+    memset(msgBuf, 0, sizeof(msgBuf));
+    EXPECT_EQ(android_log_buffer_to_string(buffer.data(), buffer.length(),
+                                           msgBuf, sizeof(msgBuf)), 0);
+    EXPECT_STREQ(msgBuf, "[1005,tag_def,(tag|1),(name|3),(format|3)]");
+}
+
 static const char __pmsg_file[] =
         "/data/william-shakespeare/MuchAdoAboutNothing.txt";
 
 TEST(liblog, __android_log_pmsg_file_write) {
+    __android_log_close();
+    bool pmsgActiveAfter__android_log_close = isPmsgActive();
+    bool logdwActiveAfter__android_log_close = isLogdwActive();
+    EXPECT_FALSE(pmsgActiveAfter__android_log_close);
+    EXPECT_FALSE(logdwActiveAfter__android_log_close);
+    int return__android_log_pmsg_file_write = __android_log_pmsg_file_write(
+            LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
+            __pmsg_file, max_payload_buf, sizeof(max_payload_buf));
+    EXPECT_LT(0, return__android_log_pmsg_file_write);
+    if (return__android_log_pmsg_file_write == -ENOMEM) {
+        fprintf(stderr,
+                "Kernel does not have space allocated to pmsg pstore driver configured\n"
+               );
+    } else if (!return__android_log_pmsg_file_write) {
+        fprintf(stderr, "Reboot, ensure file %s matches\n"
+                        "with liblog.__android_log_msg_file_read test\n",
+                        __pmsg_file);
+    }
+    bool pmsgActiveAfter__android_pmsg_file_write = isPmsgActive();
+    bool logdwActiveAfter__android_pmsg_file_write = isLogdwActive();
+    EXPECT_FALSE(pmsgActiveAfter__android_pmsg_file_write);
+    EXPECT_FALSE(logdwActiveAfter__android_pmsg_file_write);
+    EXPECT_LT(0, __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
+                                         "TEST__android_log_pmsg_file_write",
+                                         "main"));
+    bool pmsgActiveAfter__android_log_buf_print = isPmsgActive();
+    bool logdwActiveAfter__android_log_buf_print = isLogdwActive();
+    EXPECT_TRUE(pmsgActiveAfter__android_log_buf_print);
+    EXPECT_TRUE(logdwActiveAfter__android_log_buf_print);
     EXPECT_LT(0, __android_log_pmsg_file_write(
             LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
             __pmsg_file, max_payload_buf, sizeof(max_payload_buf)));
-    fprintf(stderr, "Reboot, ensure file %s matches\n"
-                    "with liblog.__android_log_msg_file_read test\n",
-                    __pmsg_file);
+    pmsgActiveAfter__android_pmsg_file_write = isPmsgActive();
+    logdwActiveAfter__android_pmsg_file_write = isLogdwActive();
+    EXPECT_TRUE(pmsgActiveAfter__android_pmsg_file_write);
+    EXPECT_TRUE(logdwActiveAfter__android_pmsg_file_write);
 }
 
 ssize_t __pmsg_fn(log_id_t logId, char prio, const char *filename,
@@ -2491,7 +2720,7 @@
             strcmp(max_payload_buf, buf)) {
         fprintf(stderr, "comparison fails on content \"%s\"\n", buf);
     }
-    return !arg ||
+    return arg ||
            (LOG_ID_CRASH != logId) ||
            (ANDROID_LOG_VERBOSE != prio) ||
            !strstr(__pmsg_file, filename) ||
@@ -2502,10 +2731,21 @@
 TEST(liblog, __android_log_pmsg_file_read) {
     signaled = 0;
 
+    __android_log_close();
+    bool pmsgActiveAfter__android_log_close = isPmsgActive();
+    bool logdwActiveAfter__android_log_close = isLogdwActive();
+    EXPECT_FALSE(pmsgActiveAfter__android_log_close);
+    EXPECT_FALSE(logdwActiveAfter__android_log_close);
+
     ssize_t ret = __android_log_pmsg_file_read(
             LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
             __pmsg_file, __pmsg_fn, NULL);
 
+    bool pmsgActiveAfter__android_log_pmsg_file_read = isPmsgActive();
+    bool logdwActiveAfter__android_log_pmsg_file_read = isLogdwActive();
+    EXPECT_FALSE(pmsgActiveAfter__android_log_pmsg_file_read);
+    EXPECT_FALSE(logdwActiveAfter__android_log_pmsg_file_read);
+
     if (ret == -ENOENT) {
         fprintf(stderr,
             "No pre-boot results of liblog.__android_log_mesg_file_write to "
@@ -2517,3 +2757,83 @@
     EXPECT_LT(0, ret);
     EXPECT_EQ(1U, signaled);
 }
+
+// meant to be handed to ASSERT_TRUE / EXPECT_TRUE only to expand the message
+static testing::AssertionResult IsOk(bool ok, std::string &message) {
+    return ok ?
+        testing::AssertionSuccess() :
+        (testing::AssertionFailure() << message);
+}
+
+static void event_log_tags_test_smap(pid_t pid) {
+    std::string filename = android::base::StringPrintf("/proc/%d/smaps", pid);
+
+    std::string content;
+    if (!android::base::ReadFileToString(filename, &content)) return;
+
+    bool shared_ok = false;
+    bool anonymous_ok = false;
+    bool pass_ok = false;
+
+    static const char event_log_tags[] = "event-log-tags";
+    std::string::size_type pos = 0;
+    while ((pos = content.find(event_log_tags, pos)) != std::string::npos) {
+        pos += strlen(event_log_tags);
+
+        // must not be: 'Shared_Clean: 0 kB'
+        static const char shared_clean[] = "Shared_Clean:";
+        std::string::size_type clean = content.find(shared_clean, pos);
+        bool ok = (clean != std::string::npos) &&
+                  ((clean = content.find_first_not_of(" \t", clean +
+                                strlen(shared_clean))) != std::string::npos) &&
+                  (content.find_first_not_of("123456789", clean) != clean);
+        if (ok && !pass_ok) {
+            shared_ok = true;
+        } else if (!ok) {
+            shared_ok = false;
+        }
+
+        // must be: 'Anonymous: 0 kB'
+        static const char anonymous[] = "Anonymous:";
+        std::string::size_type anon = content.find(anonymous, pos);
+        ok = (anon != std::string::npos) &&
+             ((anon = content.find_first_not_of(" \t", anon +
+                          strlen(anonymous))) != std::string::npos) &&
+             (content.find_first_not_of("0", anon) != anon);
+        if (ok && !pass_ok) {
+            anonymous_ok = true;
+        } else if (!ok) {
+            anonymous_ok = false;
+        }
+
+        pass_ok = true;
+    }
+    content = "";
+
+    if (!pass_ok) return;
+    if (shared_ok && anonymous_ok) return;
+
+    filename = android::base::StringPrintf("/proc/%d/comm", pid);
+    android::base::ReadFileToString(filename, &content);
+    content = android::base::StringPrintf("%d:%s",
+                  pid, content.substr(0, content.find("\n")).c_str());
+
+    EXPECT_TRUE(IsOk(shared_ok, content));
+    EXPECT_TRUE(IsOk(anonymous_ok, content));
+}
+
+TEST(liblog, event_log_tags) {
+    std::unique_ptr<DIR, int(*)(DIR*)> proc_dir(opendir("/proc"), closedir);
+    ASSERT_FALSE(!proc_dir);
+
+    dirent* e;
+    while ((e = readdir(proc_dir.get()))) {
+        if (e->d_type != DT_DIR) continue;
+        if (!isdigit(e->d_name[0])) continue;
+        long long id = atoll(e->d_name);
+        if (id <= 0) continue;
+        pid_t pid = id;
+        if (id != pid) continue;
+        event_log_tags_test_smap(pid);
+    }
+}
diff --git a/libmemtrack/Android.bp b/libmemtrack/Android.bp
new file mode 100644
index 0000000..98413dd
--- /dev/null
+++ b/libmemtrack/Android.bp
@@ -0,0 +1,30 @@
+// Copyright 2013 The Android Open Source Project
+
+cc_library_shared {
+    name: "libmemtrack",
+    srcs: ["memtrack.c"],
+    export_include_dirs: ["include"],
+    local_include_dirs: ["include"],
+    include_dirs: ["hardware/libhardware/include"],
+    shared_libs: [
+        "libhardware",
+        "liblog",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
+
+cc_binary {
+    name: "memtrack_test",
+    srcs: ["memtrack_test.c"],
+    shared_libs: [
+        "libmemtrack",
+        "libpagemap",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
diff --git a/libmemtrack/Android.mk b/libmemtrack/Android.mk
deleted file mode 100644
index 7b170f5..0000000
--- a/libmemtrack/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright 2013 The Android Open Source Project
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := memtrack.c
-LOCAL_MODULE := libmemtrack
-LOCAL_C_INCLUDES += hardware/libhardware/include
-LOCAL_SHARED_LIBRARIES := libhardware liblog
-LOCAL_CFLAGS := -Wall -Werror
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := memtrack_test.c
-LOCAL_MODULE := memtrack_test
-LOCAL_SHARED_LIBRARIES := libmemtrack libpagemap
-LOCAL_CFLAGS := -Wall -Werror
-include $(BUILD_EXECUTABLE)
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/libmemtrack/memtrack.c b/libmemtrack/memtrack.c
index 21d9ebd..29cc92c 100644
--- a/libmemtrack/memtrack.c
+++ b/libmemtrack/memtrack.c
@@ -14,19 +14,18 @@
  * limitations under the License.
  */
 
-#include <memtrack/memtrack.h>
-
 #define LOG_TAG "memtrack"
 
-#include <log/log.h>
+#include <memtrack/memtrack.h>
 
 #include <errno.h>
 #include <malloc.h>
 #include <string.h>
 
+#include <android/log.h>
 #include <hardware/memtrack.h>
 
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
 
 static const memtrack_module_t *module;
 
diff --git a/libmemunreachable/Allocator.cpp b/libmemunreachable/Allocator.cpp
index 68f654c..6fe67a4 100644
--- a/libmemunreachable/Allocator.cpp
+++ b/libmemunreachable/Allocator.cpp
@@ -52,8 +52,6 @@
   return (x + y - 1) / y;
 }
 
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
-
 static constexpr size_t kPageSize = 4096;
 static constexpr size_t kChunkSize = 256 * 1024;
 static constexpr size_t kUsableChunkSize = kChunkSize - kPageSize;
@@ -258,7 +256,7 @@
   unsigned int i = first_free_bitmap_;
   while (free_bitmap_[i] == 0)
     i++;
-  assert(i < ARRAY_SIZE(free_bitmap_));
+  assert(i < arraysize(free_bitmap_));
   unsigned int bit = __builtin_ffs(free_bitmap_[i]) - 1;
   assert(free_bitmap_[i] & (1U << bit));
   free_bitmap_[i] &= ~(1U << bit);
@@ -266,7 +264,7 @@
   assert(n < max_allocations_);
 
   unsigned int page = n * allocation_size_ / kPageSize;
-  assert(page / 32 < ARRAY_SIZE(dirty_pages_));
+  assert(page / 32 < arraysize(dirty_pages_));
   dirty_pages_[page / 32] |= 1U << (page % 32);
 
   free_count_--;
@@ -285,7 +283,7 @@
   unsigned int i = n / 32;
   unsigned int bit = n % 32;
 
-  assert(i < ARRAY_SIZE(free_bitmap_));
+  assert(i < arraysize(free_bitmap_));
   assert(!(free_bitmap_[i] & (1U << bit)));
   free_bitmap_[i] |= 1U << bit;
   free_count_++;
diff --git a/libmemunreachable/Allocator.h b/libmemunreachable/Allocator.h
index a8f579e..5390739 100644
--- a/libmemunreachable/Allocator.h
+++ b/libmemunreachable/Allocator.h
@@ -109,13 +109,13 @@
   }
 
   // Construct an STLAllocator on top of a Heap
-  STLAllocator(const Heap& heap) :
+  STLAllocator(const Heap& heap) :  // NOLINT, implicit
       heap_(heap) {
   }
 
   // Rebind an STLAllocator from an another STLAllocator
   template<typename U>
-  STLAllocator(const STLAllocator<U>& other) :
+  STLAllocator(const STLAllocator<U>& other) :  // NOLINT, implicit
       heap_(other.heap_) {
   }
 
@@ -155,12 +155,12 @@
  public:
   ~Allocator() {}
 
-  Allocator(const Heap& other) :
+  Allocator(const Heap& other) : // NOLINT, implicit
       STLAllocator<T>(other) {
   }
 
   template<typename U>
-  Allocator(const STLAllocator<U>& other) :
+  Allocator(const STLAllocator<U>& other) :  // NOLINT, implicit
       STLAllocator<T>(other) {
   }
 
diff --git a/libmemunreachable/Android.bp b/libmemunreachable/Android.bp
new file mode 100644
index 0000000..4662368
--- /dev/null
+++ b/libmemunreachable/Android.bp
@@ -0,0 +1,79 @@
+cc_defaults {
+    name: "libmemunreachable_defaults",
+
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    clang: true,
+    shared_libs: [
+        "libbase",
+        "liblog",
+    ],
+}
+
+cc_library_shared {
+    name: "libmemunreachable",
+    defaults: ["libmemunreachable_defaults"],
+    srcs: [
+        "Allocator.cpp",
+        "HeapWalker.cpp",
+        "LeakFolding.cpp",
+        "LeakPipe.cpp",
+        "LineBuffer.cpp",
+        "MemUnreachable.cpp",
+        "ProcessMappings.cpp",
+        "PtracerThread.cpp",
+        "ThreadCapture.cpp",
+    ],
+
+    static_libs: [
+        "libc_malloc_debug_backtrace",
+        "libc_logging",
+    ],
+    // Only need this for arm since libc++ uses its own unwind code that
+    // doesn't mix with the other default unwind code.
+    arch: {
+        arm: {
+            static_libs: ["libunwind_llvm"],
+        },
+    },
+    export_include_dirs: ["include"],
+    local_include_dirs: ["include"],
+}
+
+cc_test {
+    name: "memunreachable_test",
+    defaults: ["libmemunreachable_defaults"],
+    host_supported: true,
+    srcs: [
+        "tests/Allocator_test.cpp",
+        "tests/HeapWalker_test.cpp",
+        "tests/LeakFolding_test.cpp",
+    ],
+
+    target: {
+        android: {
+            srcs: [
+                "tests/DisableMalloc_test.cpp",
+                "tests/MemUnreachable_test.cpp",
+                "tests/ThreadCapture_test.cpp",
+            ],
+            shared_libs: [
+                "libmemunreachable",
+            ],
+        },
+        host: {
+            srcs: [
+                "Allocator.cpp",
+                "HeapWalker.cpp",
+                "LeakFolding.cpp",
+                "tests/HostMallocStub.cpp",
+            ],
+        },
+        darwin: {
+            enabled: false,
+        },
+    },
+}
diff --git a/libmemunreachable/Android.mk b/libmemunreachable/Android.mk
deleted file mode 100644
index 7b66d44..0000000
--- a/libmemunreachable/Android.mk
+++ /dev/null
@@ -1,65 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-memunreachable_srcs := \
-   Allocator.cpp \
-   HeapWalker.cpp \
-   LeakFolding.cpp \
-   LeakPipe.cpp \
-   LineBuffer.cpp \
-   MemUnreachable.cpp \
-   ProcessMappings.cpp \
-   PtracerThread.cpp \
-   ThreadCapture.cpp \
-
-memunreachable_test_srcs := \
-   tests/Allocator_test.cpp \
-   tests/DisableMalloc_test.cpp \
-   tests/HeapWalker_test.cpp \
-   tests/LeakFolding_test.cpp \
-   tests/MemUnreachable_test.cpp \
-   tests/ThreadCapture_test.cpp \
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libmemunreachable
-LOCAL_SRC_FILES := $(memunreachable_srcs)
-LOCAL_CFLAGS := -std=c++14 -Wall -Wextra -Werror
-LOCAL_SHARED_LIBRARIES := libbase liblog
-LOCAL_STATIC_LIBRARIES := libc_malloc_debug_backtrace libc_logging
-# Only need this for arm since libc++ uses its own unwind code that
-# doesn't mix with the other default unwind code.
-LOCAL_STATIC_LIBRARIES_arm := libunwind_llvm
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CLANG := true
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := memunreachable_test
-LOCAL_SRC_FILES := $(memunreachable_test_srcs)
-LOCAL_CFLAGS := -std=c++14 -Wall -Wextra -Werror
-LOCAL_CLANG := true
-LOCAL_SHARED_LIBRARIES := libmemunreachable libbase liblog
-
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := memunreachable_test
-LOCAL_SRC_FILES := \
-   Allocator.cpp \
-   HeapWalker.cpp  \
-   LeakFolding.cpp \
-   tests/Allocator_test.cpp \
-   tests/HeapWalker_test.cpp \
-   tests/HostMallocStub.cpp \
-   tests/LeakFolding_test.cpp \
-
-LOCAL_CFLAGS := -std=c++14 -Wall -Wextra -Werror
-LOCAL_CLANG := true
-LOCAL_SHARED_LIBRARIES := libbase liblog
-LOCAL_MODULE_HOST_OS := linux
-
-include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libmemunreachable/HeapWalker.h b/libmemunreachable/HeapWalker.h
index 3c1b513..b25696f 100644
--- a/libmemunreachable/HeapWalker.h
+++ b/libmemunreachable/HeapWalker.h
@@ -48,7 +48,7 @@
 
 class HeapWalker {
  public:
-  HeapWalker(Allocator<HeapWalker> allocator) : allocator_(allocator),
+  explicit HeapWalker(Allocator<HeapWalker> allocator) : allocator_(allocator),
     allocations_(allocator), allocation_bytes_(0),
 	roots_(allocator), root_vals_(allocator),
 	segv_handler_(allocator), walking_ptr_(0) {
diff --git a/libmemunreachable/LeakFolding.h b/libmemunreachable/LeakFolding.h
index 732d3f2..9c6a525 100644
--- a/libmemunreachable/LeakFolding.h
+++ b/libmemunreachable/LeakFolding.h
@@ -54,7 +54,7 @@
     bool dominator;
     SCCInfo* accumulator;
 
-    SCCInfo(Allocator<SCCInfo> allocator) : node(this, allocator),
+    explicit SCCInfo(Allocator<SCCInfo> allocator) : node(this, allocator),
         count(0), size(0), cuumulative_count(0), cuumulative_size(0),
         dominator(false), accumulator(nullptr) {}
    private:
diff --git a/libmemunreachable/LinkedList.h b/libmemunreachable/LinkedList.h
index 3e44035..132842d 100644
--- a/libmemunreachable/LinkedList.h
+++ b/libmemunreachable/LinkedList.h
@@ -21,7 +21,7 @@
 class LinkedList {
 public:
     LinkedList() : next_(this), prev_(this), data_() {}
-    LinkedList(T data) : LinkedList() {
+    explicit LinkedList(T data) : LinkedList() {
         data_ = data;
     }
     ~LinkedList() {}
diff --git a/libmemunreachable/PtracerThread.cpp b/libmemunreachable/PtracerThread.cpp
index aa5b344..4e3c41e 100644
--- a/libmemunreachable/PtracerThread.cpp
+++ b/libmemunreachable/PtracerThread.cpp
@@ -37,7 +37,7 @@
 
 class Stack {
  public:
-  Stack(size_t size) : size_(size) {
+  explicit Stack(size_t size) : size_(size) {
     int prot = PROT_READ | PROT_WRITE;
     int flags = MAP_PRIVATE | MAP_ANONYMOUS;
     page_size_ = sysconf(_SC_PAGE_SIZE);
diff --git a/libmemunreachable/PtracerThread.h b/libmemunreachable/PtracerThread.h
index 4d6ca9a..f88b599 100644
--- a/libmemunreachable/PtracerThread.h
+++ b/libmemunreachable/PtracerThread.h
@@ -32,7 +32,7 @@
 // the parent.
 class PtracerThread {
  public:
-  PtracerThread(const std::function<int()>& func);
+  explicit PtracerThread(const std::function<int()>& func);
   ~PtracerThread();
   bool Start();
   int Join();
diff --git a/libmemunreachable/ScopedDisableMalloc.h b/libmemunreachable/ScopedDisableMalloc.h
index 4f96376..758d317 100644
--- a/libmemunreachable/ScopedDisableMalloc.h
+++ b/libmemunreachable/ScopedDisableMalloc.h
@@ -74,7 +74,7 @@
 
 class ScopedDisableMallocTimeout {
  public:
-  ScopedDisableMallocTimeout(std::chrono::milliseconds timeout = std::chrono::milliseconds(2000)) :
+  explicit ScopedDisableMallocTimeout(std::chrono::milliseconds timeout = std::chrono::milliseconds(2000)) :
     timeout_(timeout), timed_out_(false), disable_malloc_() {
     Disable();
   }
diff --git a/libmemunreachable/ScopedSignalHandler.h b/libmemunreachable/ScopedSignalHandler.h
index e006d43..1fd9d4d 100644
--- a/libmemunreachable/ScopedSignalHandler.h
+++ b/libmemunreachable/ScopedSignalHandler.h
@@ -30,7 +30,7 @@
  public:
   using Fn = std::function<void(ScopedSignalHandler&, int, siginfo_t*, void*)>;
 
-  ScopedSignalHandler(Allocator<Fn> allocator) : allocator_(allocator), signal_(-1) {}
+  explicit ScopedSignalHandler(Allocator<Fn> allocator) : allocator_(allocator), signal_(-1) {}
   ~ScopedSignalHandler() {
     reset();
   }
diff --git a/libmemunreachable/Semaphore.h b/libmemunreachable/Semaphore.h
index 45e8c81..6bcf4ea 100644
--- a/libmemunreachable/Semaphore.h
+++ b/libmemunreachable/Semaphore.h
@@ -24,7 +24,7 @@
 
 class Semaphore {
  public:
-  Semaphore(int count = 0) : count_(count) {}
+  explicit Semaphore(int count = 0) : count_(count) {}
   ~Semaphore() = default;
 
   void Wait(std::chrono::milliseconds ms) {
diff --git a/libmemunreachable/Tarjan.h b/libmemunreachable/Tarjan.h
index d7ecdb9..2546341 100644
--- a/libmemunreachable/Tarjan.h
+++ b/libmemunreachable/Tarjan.h
@@ -19,6 +19,7 @@
 #ifndef LIBMEMUNREACHABLE_TARJAN_H_
 #define LIBMEMUNREACHABLE_TARJAN_H_
 
+#include <assert.h>
 #include <algorithm>
 
 #include "Allocator.h"
@@ -62,7 +63,7 @@
 template<class T>
 class TarjanAlgorithm {
  public:
-  TarjanAlgorithm(Allocator<void> allocator) : index_(0),
+  explicit TarjanAlgorithm(Allocator<void> allocator) : index_(0),
     stack_(allocator), components_(allocator) {}
 
   void Execute(Graph<T>& graph, SCCList<T>& out);
diff --git a/libmemunreachable/log.h b/libmemunreachable/log.h
index cdfbfd9..dd146b6 100644
--- a/libmemunreachable/log.h
+++ b/libmemunreachable/log.h
@@ -19,6 +19,6 @@
 
 #define LOG_TAG "libmemunreachable"
 
-#include <log/log.h>
+#include <android/log.h>
 
 #endif // LIBMEMUNREACHABLE_LOG_H_
diff --git a/libmemunreachable/tests/Allocator_test.cpp b/libmemunreachable/tests/Allocator_test.cpp
index fa76ae0..21c8218 100644
--- a/libmemunreachable/tests/Allocator_test.cpp
+++ b/libmemunreachable/tests/Allocator_test.cpp
@@ -160,7 +160,7 @@
 
   Allocator<int>::shared_ptr ptr = allocator.make_shared(0);
   {
-    auto ptr2 = ptr;
+    auto ptr2 = ptr;  // NOLINT, test copy of ptr
   }
   ASSERT_NE(ptr, nullptr);
 }
diff --git a/libmemunreachable/tests/LeakFolding_test.cpp b/libmemunreachable/tests/LeakFolding_test.cpp
index 879a3a0..e85df5f 100644
--- a/libmemunreachable/tests/LeakFolding_test.cpp
+++ b/libmemunreachable/tests/LeakFolding_test.cpp
@@ -37,10 +37,10 @@
   Heap heap_;
 };
 
-#define buffer_begin(buffer) reinterpret_cast<uintptr_t>(&buffer[0])
-#define buffer_end(buffer) (reinterpret_cast<uintptr_t>(&buffer[0]) + sizeof(buffer))
+#define buffer_begin(buffer) reinterpret_cast<uintptr_t>(&(buffer)[0])
+#define buffer_end(buffer) (reinterpret_cast<uintptr_t>(&(buffer)[0]) + sizeof(buffer))
 #define ALLOCATION(heap_walker, buffer) \
-  ASSERT_EQ(true, heap_walker.Allocation(buffer_begin(buffer), buffer_end(buffer)))
+  ASSERT_EQ(true, (heap_walker).Allocation(buffer_begin(buffer), buffer_end(buffer)))
 
 TEST_F(LeakFoldingTest, one) {
   void* buffer1[1] = {nullptr};
diff --git a/libmemunreachable/tests/MemUnreachable_test.cpp b/libmemunreachable/tests/MemUnreachable_test.cpp
index 0747b12..2ae3db8 100644
--- a/libmemunreachable/tests/MemUnreachable_test.cpp
+++ b/libmemunreachable/tests/MemUnreachable_test.cpp
@@ -27,7 +27,7 @@
 
 class HiddenPointer {
  public:
-  HiddenPointer(size_t size = 256) {
+  explicit HiddenPointer(size_t size = 256) {
     Set(malloc(size));
   }
   ~HiddenPointer() {
diff --git a/libmincrypt/Android.mk b/libmincrypt/Android.mk
deleted file mode 100644
index 7906986..0000000
--- a/libmincrypt/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright 2008 The Android Open Source Project
-#
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libmincrypt
-LOCAL_SRC_FILES := dsa_sig.c p256.c p256_ec.c p256_ecdsa.c rsa.c sha.c sha256.c
-LOCAL_CFLAGS := -Wall -Werror
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libmincrypt
-LOCAL_SRC_FILES := dsa_sig.c p256.c p256_ec.c p256_ecdsa.c rsa.c sha.c sha256.c
-LOCAL_CFLAGS := -Wall -Werror
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-include $(LOCAL_PATH)/tools/Android.mk \
-        $(LOCAL_PATH)/test/Android.mk
diff --git a/libmincrypt/NOTICE b/libmincrypt/NOTICE
deleted file mode 100644
index 430d3d6..0000000
--- a/libmincrypt/NOTICE
+++ /dev/null
@@ -1,23 +0,0 @@
- Copyright 2008, The Android Open Source Project
-
- 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.
-     * Neither the name of Google Inc. nor the names of its contributors may
-       be used to endorse or promote products derived from this software
-       without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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.
diff --git a/libmincrypt/dsa_sig.c b/libmincrypt/dsa_sig.c
deleted file mode 100644
index 101314b..0000000
--- a/libmincrypt/dsa_sig.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * 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.
- *     * Neither the name of Google Inc. nor the names of its contributors may
- *       be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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 <string.h>
-
-#include "mincrypt/dsa_sig.h"
-#include "mincrypt/p256.h"
-
-/**
- * Trims off the leading zero bytes and copy it to a buffer aligning it to the end.
- */
-static inline int trim_to_p256_bytes(unsigned char dst[P256_NBYTES], unsigned char *src,
-        int src_len) {
-    int dst_offset;
-    while (*src == '\0' && src_len > 0) {
-        src++;
-        src_len--;
-    }
-    if (src_len > P256_NBYTES || src_len < 1) {
-        return 0;
-    }
-    dst_offset = P256_NBYTES - src_len;
-    memset(dst, 0, dst_offset);
-    memcpy(dst + dst_offset, src, src_len);
-    return 1;
-}
-
-/**
- * Unpacks the ASN.1 DSA signature sequence.
- */
-int dsa_sig_unpack(unsigned char* sig, int sig_len, p256_int* r_int, p256_int* s_int) {
-    /*
-     * Structure is:
-     *   0x30 0xNN  SEQUENCE + s_length
-     *     0x02 0xNN  INTEGER + r_length
-     *       0xAA 0xBB ..   r_length bytes of "r" (offset 4)
-     *     0x02 0xNN  INTEGER + s_length
-     *       0xMM 0xNN ..   s_length bytes of "s" (offset 6 + r_len)
-     */
-    int seq_len;
-    unsigned char r_bytes[P256_NBYTES];
-    unsigned char s_bytes[P256_NBYTES];
-    int r_len;
-    int s_len;
-
-    memset(r_bytes, 0, sizeof(r_bytes));
-    memset(s_bytes, 0, sizeof(s_bytes));
-
-    /*
-     * Must have at least:
-     * 2 bytes sequence header and length
-     * 2 bytes R integer header and length
-     * 1 byte of R
-     * 2 bytes S integer header and length
-     * 1 byte of S
-     *
-     * 8 bytes total
-     */
-    if (sig_len < 8 || sig[0] != 0x30 || sig[2] != 0x02) {
-        return 0;
-    }
-
-    seq_len = sig[1];
-    if ((seq_len <= 0) || (seq_len + 2 != sig_len)) {
-        return 0;
-    }
-
-    r_len = sig[3];
-    /*
-     * Must have at least:
-     * 2 bytes for R header and length
-     * 2 bytes S integer header and length
-     * 1 byte of S
-     */
-    if ((r_len < 1) || (r_len > seq_len - 5) || (sig[4 + r_len] != 0x02)) {
-        return 0;
-    }
-    s_len = sig[5 + r_len];
-
-    /**
-     * Must have:
-     * 2 bytes for R header and length
-     * r_len bytes for R
-     * 2 bytes S integer header and length
-     */
-    if ((s_len < 1) || (s_len != seq_len - 4 - r_len)) {
-        return 0;
-    }
-
-    /*
-     * ASN.1 encoded integers are zero-padded for positive integers. Make sure we have
-     * a correctly-sized buffer and that the resulting integer isn't too large.
-     */
-    if (!trim_to_p256_bytes(r_bytes, &sig[4], r_len)
-            || !trim_to_p256_bytes(s_bytes, &sig[6 + r_len], s_len)) {
-        return 0;
-    }
-
-    p256_from_bin(r_bytes, r_int);
-    p256_from_bin(s_bytes, s_int);
-
-    return 1;
-}
diff --git a/libmincrypt/p256.c b/libmincrypt/p256.c
deleted file mode 100644
index 555a07a..0000000
--- a/libmincrypt/p256.c
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * 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.
- *     * Neither the name of Google Inc. nor the names of its contributors may
- *       be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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 is an implementation of the P256 elliptic curve group. It's written to
-// be portable 32-bit, although it's still constant-time.
-//
-// WARNING: Implementing these functions in a constant-time manner is far from
-//          obvious. Be careful when touching this code.
-//
-// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background.
-
-#include <assert.h>
-#include <stdint.h>
-#include <string.h>
-#include <stdio.h>
-
-#include "mincrypt/p256.h"
-
-const p256_int SECP256r1_n =  // curve order
-  {{0xfc632551, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, -1, -1, 0, -1}};
-
-const p256_int SECP256r1_p =  // curve field size
-  {{-1, -1, -1, 0, 0, 0, 1, -1 }};
-
-const p256_int SECP256r1_b =  // curve b
-  {{0x27d2604b, 0x3bce3c3e, 0xcc53b0f6, 0x651d06b0,
-    0x769886bc, 0xb3ebbd55, 0xaa3a93e7, 0x5ac635d8}};
-
-void p256_init(p256_int* a) {
-  memset(a, 0, sizeof(*a));
-}
-
-void p256_clear(p256_int* a) { p256_init(a); }
-
-int p256_get_bit(const p256_int* scalar, int bit) {
-  return (P256_DIGIT(scalar, bit / P256_BITSPERDIGIT)
-              >> (bit & (P256_BITSPERDIGIT - 1))) & 1;
-}
-
-int p256_is_zero(const p256_int* a) {
-  int i, result = 0;
-  for (i = 0; i < P256_NDIGITS; ++i) result |= P256_DIGIT(a, i);
-  return !result;
-}
-
-// top, c[] += a[] * b
-// Returns new top
-static p256_digit mulAdd(const p256_int* a,
-                         p256_digit b,
-                         p256_digit top,
-                         p256_digit* c) {
-  int i;
-  p256_ddigit carry = 0;
-
-  for (i = 0; i < P256_NDIGITS; ++i) {
-    carry += *c;
-    carry += (p256_ddigit)P256_DIGIT(a, i) * b;
-    *c++ = (p256_digit)carry;
-    carry >>= P256_BITSPERDIGIT;
-  }
-  return top + (p256_digit)carry;
-}
-
-// top, c[] -= top_a, a[]
-static p256_digit subTop(p256_digit top_a,
-                         const p256_digit* a,
-                         p256_digit top_c,
-                         p256_digit* c) {
-  int i;
-  p256_sddigit borrow = 0;
-
-  for (i = 0; i < P256_NDIGITS; ++i) {
-    borrow += *c;
-    borrow -= *a++;
-    *c++ = (p256_digit)borrow;
-    borrow >>= P256_BITSPERDIGIT;
-  }
-  borrow += top_c;
-  borrow -= top_a;
-  top_c = (p256_digit)borrow;
-  assert((borrow >> P256_BITSPERDIGIT) == 0);
-  return top_c;
-}
-
-// top, c[] -= MOD[] & mask (0 or -1)
-// returns new top.
-static p256_digit subM(const p256_int* MOD,
-                       p256_digit top,
-                       p256_digit* c,
-                       p256_digit mask) {
-  int i;
-  p256_sddigit borrow = 0;
-  for (i = 0; i < P256_NDIGITS; ++i) {
-    borrow += *c;
-    borrow -= P256_DIGIT(MOD, i) & mask;
-    *c++ = (p256_digit)borrow;
-    borrow >>= P256_BITSPERDIGIT;
-  }
-  return top + (p256_digit)borrow;
-}
-
-// top, c[] += MOD[] & mask (0 or -1)
-// returns new top.
-static p256_digit addM(const p256_int* MOD,
-                       p256_digit top,
-                       p256_digit* c,
-                       p256_digit mask) {
-  int i;
-  p256_ddigit carry = 0;
-  for (i = 0; i < P256_NDIGITS; ++i) {
-    carry += *c;
-    carry += P256_DIGIT(MOD, i) & mask;
-    *c++ = (p256_digit)carry;
-    carry >>= P256_BITSPERDIGIT;
-  }
-  return top + (p256_digit)carry;
-}
-
-// c = a * b mod MOD. c can be a and/or b.
-void p256_modmul(const p256_int* MOD,
-                 const p256_int* a,
-                 const p256_digit top_b,
-                 const p256_int* b,
-                 p256_int* c) {
-  p256_digit tmp[P256_NDIGITS * 2 + 1] = { 0 };
-  p256_digit top = 0;
-  int i;
-
-  // Multiply/add into tmp.
-  for (i = 0; i < P256_NDIGITS; ++i) {
-    if (i) tmp[i + P256_NDIGITS - 1] = top;
-    top = mulAdd(a, P256_DIGIT(b, i), 0, tmp + i);
-  }
-
-  // Multiply/add top digit
-  tmp[i + P256_NDIGITS - 1] = top;
-  top = mulAdd(a, top_b, 0, tmp + i);
-
-  // Reduce tmp, digit by digit.
-  for (; i >= 0; --i) {
-    p256_digit reducer[P256_NDIGITS] = { 0 };
-    p256_digit top_reducer;
-
-    // top can be any value at this point.
-    // Guestimate reducer as top * MOD, since msw of MOD is -1.
-    top_reducer = mulAdd(MOD, top, 0, reducer);
-
-    // Subtract reducer from top | tmp.
-    top = subTop(top_reducer, reducer, top, tmp + i);
-
-    // top is now either 0 or 1. Make it 0, fixed-timing.
-    assert(top <= 1);
-
-    top = subM(MOD, top, tmp + i, ~(top - 1));
-
-    assert(top == 0);
-
-    // We have now reduced the top digit off tmp. Fetch new top digit.
-    top = tmp[i + P256_NDIGITS - 1];
-  }
-
-  // tmp might still be larger than MOD, yet same bit length.
-  // Make sure it is less, fixed-timing.
-  addM(MOD, 0, tmp, subM(MOD, 0, tmp, -1));
-
-  memcpy(c, tmp, P256_NBYTES);
-}
-int p256_is_odd(const p256_int* a) { return P256_DIGIT(a, 0) & 1; }
-int p256_is_even(const p256_int* a) { return !(P256_DIGIT(a, 0) & 1); }
-
-p256_digit p256_shl(const p256_int* a, int n, p256_int* b) {
-  int i;
-  p256_digit top = P256_DIGIT(a, P256_NDIGITS - 1);
-
-  n %= P256_BITSPERDIGIT;
-  for (i = P256_NDIGITS - 1; i > 0; --i) {
-    p256_digit accu = (P256_DIGIT(a, i) << n);
-    accu |= (P256_DIGIT(a, i - 1) >> (P256_BITSPERDIGIT - n));
-    P256_DIGIT(b, i) = accu;
-  }
-  P256_DIGIT(b, i) = (P256_DIGIT(a, i) << n);
-
-  top = (p256_digit)((((p256_ddigit)top) << n) >> P256_BITSPERDIGIT);
-
-  return top;
-}
-
-void p256_shr(const p256_int* a, int n, p256_int* b) {
-  int i;
-
-  n %= P256_BITSPERDIGIT;
-  for (i = 0; i < P256_NDIGITS - 1; ++i) {
-    p256_digit accu = (P256_DIGIT(a, i) >> n);
-    accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - n));
-    P256_DIGIT(b, i) = accu;
-  }
-  P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> n);
-}
-
-static void p256_shr1(const p256_int* a, int highbit, p256_int* b) {
-  int i;
-
-  for (i = 0; i < P256_NDIGITS - 1; ++i) {
-    p256_digit accu = (P256_DIGIT(a, i) >> 1);
-    accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - 1));
-    P256_DIGIT(b, i) = accu;
-  }
-  P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> 1) |
-      (highbit << (P256_BITSPERDIGIT - 1));
-}
-
-// Return -1, 0, 1 for a < b, a == b or a > b respectively.
-int p256_cmp(const p256_int* a, const p256_int* b) {
-  int i;
-  p256_sddigit borrow = 0;
-  p256_digit notzero = 0;
-
-  for (i = 0; i < P256_NDIGITS; ++i) {
-    borrow += (p256_sddigit)P256_DIGIT(a, i) - P256_DIGIT(b, i);
-    // Track whether any result digit is ever not zero.
-    // Relies on !!(non-zero) evaluating to 1, e.g., !!(-1) evaluating to 1.
-    notzero |= !!((p256_digit)borrow);
-    borrow >>= P256_BITSPERDIGIT;
-  }
-  return (int)borrow | notzero;
-}
-
-// c = a - b. Returns borrow: 0 or -1.
-int p256_sub(const p256_int* a, const p256_int* b, p256_int* c) {
-  int i;
-  p256_sddigit borrow = 0;
-
-  for (i = 0; i < P256_NDIGITS; ++i) {
-    borrow += (p256_sddigit)P256_DIGIT(a, i) - P256_DIGIT(b, i);
-    if (c) P256_DIGIT(c, i) = (p256_digit)borrow;
-    borrow >>= P256_BITSPERDIGIT;
-  }
-  return (int)borrow;
-}
-
-// c = a + b. Returns carry: 0 or 1.
-int p256_add(const p256_int* a, const p256_int* b, p256_int* c) {
-  int i;
-  p256_ddigit carry = 0;
-
-  for (i = 0; i < P256_NDIGITS; ++i) {
-    carry += (p256_ddigit)P256_DIGIT(a, i) + P256_DIGIT(b, i);
-    if (c) P256_DIGIT(c, i) = (p256_digit)carry;
-    carry >>= P256_BITSPERDIGIT;
-  }
-  return (int)carry;
-}
-
-// b = a + d. Returns carry, 0 or 1.
-int p256_add_d(const p256_int* a, p256_digit d, p256_int* b) {
-  int i;
-  p256_ddigit carry = d;
-
-  for (i = 0; i < P256_NDIGITS; ++i) {
-    carry += (p256_ddigit)P256_DIGIT(a, i);
-    if (b) P256_DIGIT(b, i) = (p256_digit)carry;
-    carry >>= P256_BITSPERDIGIT;
-  }
-  return (int)carry;
-}
-
-// b = 1/a mod MOD, binary euclid.
-void p256_modinv_vartime(const p256_int* MOD,
-                         const p256_int* a,
-                         p256_int* b) {
-  p256_int R = P256_ZERO;
-  p256_int S = P256_ONE;
-  p256_int U = *MOD;
-  p256_int V = *a;
-
-  for (;;) {
-    if (p256_is_even(&U)) {
-      p256_shr1(&U, 0, &U);
-      if (p256_is_even(&R)) {
-        p256_shr1(&R, 0, &R);
-      } else {
-        // R = (R+MOD)/2
-        p256_shr1(&R, p256_add(&R, MOD, &R), &R);
-      }
-    } else if (p256_is_even(&V)) {
-      p256_shr1(&V, 0, &V);
-      if (p256_is_even(&S)) {
-        p256_shr1(&S, 0, &S);
-      } else {
-        // S = (S+MOD)/2
-        p256_shr1(&S, p256_add(&S, MOD, &S) , &S);
-      }
-    } else {  // U,V both odd.
-      if (!p256_sub(&V, &U, NULL)) {
-        p256_sub(&V, &U, &V);
-        if (p256_sub(&S, &R, &S)) p256_add(&S, MOD, &S);
-        if (p256_is_zero(&V)) break;  // done.
-      } else {
-        p256_sub(&U, &V, &U);
-        if (p256_sub(&R, &S, &R)) p256_add(&R, MOD, &R);
-      }
-    }
-  }
-
-  p256_mod(MOD, &R, b);
-}
-
-void p256_mod(const p256_int* MOD,
-              const p256_int* in,
-              p256_int* out) {
-  if (out != in) *out = *in;
-  addM(MOD, 0, P256_DIGITS(out), subM(MOD, 0, P256_DIGITS(out), -1));
-}
-
-// Verify y^2 == x^3 - 3x + b mod p
-// and 0 < x < p and 0 < y < p
-int p256_is_valid_point(const p256_int* x, const p256_int* y) {
-  p256_int y2, x3;
-
-  if (p256_cmp(&SECP256r1_p, x) <= 0 ||
-      p256_cmp(&SECP256r1_p, y) <= 0 ||
-      p256_is_zero(x) ||
-      p256_is_zero(y)) return 0;
-
-  p256_modmul(&SECP256r1_p, y, 0, y, &y2);  // y^2
-
-  p256_modmul(&SECP256r1_p, x, 0, x, &x3);  // x^2
-  p256_modmul(&SECP256r1_p, x, 0, &x3, &x3);  // x^3
-  if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3);  // x^3 - x
-  if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3);  // x^3 - 2x
-  if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3);  // x^3 - 3x
-  if (p256_add(&x3, &SECP256r1_b, &x3))  // x^3 - 3x + b
-    p256_sub(&x3, &SECP256r1_p, &x3);
-
-  return p256_cmp(&y2, &x3) == 0;
-}
-
-void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int* dst) {
-  int i;
-  const uint8_t* p = &src[0];
-
-  for (i = P256_NDIGITS - 1; i >= 0; --i) {
-    P256_DIGIT(dst, i) =
-        (p[0] << 24) |
-        (p[1] << 16) |
-        (p[2] << 8) |
-        p[3];
-    p += 4;
-  }
-}
diff --git a/libmincrypt/p256_ec.c b/libmincrypt/p256_ec.c
deleted file mode 100644
index 90262cc..0000000
--- a/libmincrypt/p256_ec.c
+++ /dev/null
@@ -1,1279 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * 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.
- *     * Neither the name of Google Inc. nor the names of its contributors may
- *       be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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 is an implementation of the P256 elliptic curve group. It's written to
-// be portable 32-bit, although it's still constant-time.
-//
-// WARNING: Implementing these functions in a constant-time manner is far from
-//          obvious. Be careful when touching this code.
-//
-// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background.
-
-#include <stdint.h>
-#include <stdio.h>
-
-#include <string.h>
-#include <stdlib.h>
-
-#include "mincrypt/p256.h"
-
-typedef uint8_t u8;
-typedef uint32_t u32;
-typedef int32_t s32;
-typedef uint64_t u64;
-
-/* Our field elements are represented as nine 32-bit limbs.
- *
- * The value of an felem (field element) is:
- *   x[0] + (x[1] * 2**29) + (x[2] * 2**57) + ... + (x[8] * 2**228)
- *
- * That is, each limb is alternately 29 or 28-bits wide in little-endian
- * order.
- *
- * This means that an felem hits 2**257, rather than 2**256 as we would like. A
- * 28, 29, ... pattern would cause us to hit 2**256, but that causes problems
- * when multiplying as terms end up one bit short of a limb which would require
- * much bit-shifting to correct.
- *
- * Finally, the values stored in an felem are in Montgomery form. So the value
- * |y| is stored as (y*R) mod p, where p is the P-256 prime and R is 2**257.
- */
-typedef u32 limb;
-#define NLIMBS 9
-typedef limb felem[NLIMBS];
-
-static const limb kBottom28Bits = 0xfffffff;
-static const limb kBottom29Bits = 0x1fffffff;
-
-/* kOne is the number 1 as an felem. It's 2**257 mod p split up into 29 and
- * 28-bit words. */
-static const felem kOne = {
-    2, 0, 0, 0xffff800,
-    0x1fffffff, 0xfffffff, 0x1fbfffff, 0x1ffffff,
-    0
-};
-static const felem kZero = {0};
-static const felem kP = {
-    0x1fffffff, 0xfffffff, 0x1fffffff, 0x3ff,
-    0, 0, 0x200000, 0xf000000,
-    0xfffffff
-};
-static const felem k2P = {
-    0x1ffffffe, 0xfffffff, 0x1fffffff, 0x7ff,
-    0, 0, 0x400000, 0xe000000,
-    0x1fffffff
-};
-/* kPrecomputed contains precomputed values to aid the calculation of scalar
- * multiples of the base point, G. It's actually two, equal length, tables
- * concatenated.
- *
- * The first table contains (x,y) felem pairs for 16 multiples of the base
- * point, G.
- *
- *   Index  |  Index (binary) | Value
- *       0  |           0000  | 0G (all zeros, omitted)
- *       1  |           0001  | G
- *       2  |           0010  | 2**64G
- *       3  |           0011  | 2**64G + G
- *       4  |           0100  | 2**128G
- *       5  |           0101  | 2**128G + G
- *       6  |           0110  | 2**128G + 2**64G
- *       7  |           0111  | 2**128G + 2**64G + G
- *       8  |           1000  | 2**192G
- *       9  |           1001  | 2**192G + G
- *      10  |           1010  | 2**192G + 2**64G
- *      11  |           1011  | 2**192G + 2**64G + G
- *      12  |           1100  | 2**192G + 2**128G
- *      13  |           1101  | 2**192G + 2**128G + G
- *      14  |           1110  | 2**192G + 2**128G + 2**64G
- *      15  |           1111  | 2**192G + 2**128G + 2**64G + G
- *
- * The second table follows the same style, but the terms are 2**32G,
- * 2**96G, 2**160G, 2**224G.
- *
- * This is ~2KB of data. */
-static const limb kPrecomputed[NLIMBS * 2 * 15 * 2] = {
-    0x11522878, 0xe730d41, 0xdb60179, 0x4afe2ff, 0x12883add, 0xcaddd88, 0x119e7edc, 0xd4a6eab, 0x3120bee,
-    0x1d2aac15, 0xf25357c, 0x19e45cdd, 0x5c721d0, 0x1992c5a5, 0xa237487, 0x154ba21, 0x14b10bb, 0xae3fe3,
-    0xd41a576, 0x922fc51, 0x234994f, 0x60b60d3, 0x164586ae, 0xce95f18, 0x1fe49073, 0x3fa36cc, 0x5ebcd2c,
-    0xb402f2f, 0x15c70bf, 0x1561925c, 0x5a26704, 0xda91e90, 0xcdc1c7f, 0x1ea12446, 0xe1ade1e, 0xec91f22,
-    0x26f7778, 0x566847e, 0xa0bec9e, 0x234f453, 0x1a31f21a, 0xd85e75c, 0x56c7109, 0xa267a00, 0xb57c050,
-    0x98fb57, 0xaa837cc, 0x60c0792, 0xcfa5e19, 0x61bab9e, 0x589e39b, 0xa324c5, 0x7d6dee7, 0x2976e4b,
-    0x1fc4124a, 0xa8c244b, 0x1ce86762, 0xcd61c7e, 0x1831c8e0, 0x75774e1, 0x1d96a5a9, 0x843a649, 0xc3ab0fa,
-    0x6e2e7d5, 0x7673a2a, 0x178b65e8, 0x4003e9b, 0x1a1f11c2, 0x7816ea, 0xf643e11, 0x58c43df, 0xf423fc2,
-    0x19633ffa, 0x891f2b2, 0x123c231c, 0x46add8c, 0x54700dd, 0x59e2b17, 0x172db40f, 0x83e277d, 0xb0dd609,
-    0xfd1da12, 0x35c6e52, 0x19ede20c, 0xd19e0c0, 0x97d0f40, 0xb015b19, 0x449e3f5, 0xe10c9e, 0x33ab581,
-    0x56a67ab, 0x577734d, 0x1dddc062, 0xc57b10d, 0x149b39d, 0x26a9e7b, 0xc35df9f, 0x48764cd, 0x76dbcca,
-    0xca4b366, 0xe9303ab, 0x1a7480e7, 0x57e9e81, 0x1e13eb50, 0xf466cf3, 0x6f16b20, 0x4ba3173, 0xc168c33,
-    0x15cb5439, 0x6a38e11, 0x73658bd, 0xb29564f, 0x3f6dc5b, 0x53b97e, 0x1322c4c0, 0x65dd7ff, 0x3a1e4f6,
-    0x14e614aa, 0x9246317, 0x1bc83aca, 0xad97eed, 0xd38ce4a, 0xf82b006, 0x341f077, 0xa6add89, 0x4894acd,
-    0x9f162d5, 0xf8410ef, 0x1b266a56, 0xd7f223, 0x3e0cb92, 0xe39b672, 0x6a2901a, 0x69a8556, 0x7e7c0,
-    0x9b7d8d3, 0x309a80, 0x1ad05f7f, 0xc2fb5dd, 0xcbfd41d, 0x9ceb638, 0x1051825c, 0xda0cf5b, 0x812e881,
-    0x6f35669, 0x6a56f2c, 0x1df8d184, 0x345820, 0x1477d477, 0x1645db1, 0xbe80c51, 0xc22be3e, 0xe35e65a,
-    0x1aeb7aa0, 0xc375315, 0xf67bc99, 0x7fdd7b9, 0x191fc1be, 0x61235d, 0x2c184e9, 0x1c5a839, 0x47a1e26,
-    0xb7cb456, 0x93e225d, 0x14f3c6ed, 0xccc1ac9, 0x17fe37f3, 0x4988989, 0x1a90c502, 0x2f32042, 0xa17769b,
-    0xafd8c7c, 0x8191c6e, 0x1dcdb237, 0x16200c0, 0x107b32a1, 0x66c08db, 0x10d06a02, 0x3fc93, 0x5620023,
-    0x16722b27, 0x68b5c59, 0x270fcfc, 0xfad0ecc, 0xe5de1c2, 0xeab466b, 0x2fc513c, 0x407f75c, 0xbaab133,
-    0x9705fe9, 0xb88b8e7, 0x734c993, 0x1e1ff8f, 0x19156970, 0xabd0f00, 0x10469ea7, 0x3293ac0, 0xcdc98aa,
-    0x1d843fd, 0xe14bfe8, 0x15be825f, 0x8b5212, 0xeb3fb67, 0x81cbd29, 0xbc62f16, 0x2b6fcc7, 0xf5a4e29,
-    0x13560b66, 0xc0b6ac2, 0x51ae690, 0xd41e271, 0xf3e9bd4, 0x1d70aab, 0x1029f72, 0x73e1c35, 0xee70fbc,
-    0xad81baf, 0x9ecc49a, 0x86c741e, 0xfe6be30, 0x176752e7, 0x23d416, 0x1f83de85, 0x27de188, 0x66f70b8,
-    0x181cd51f, 0x96b6e4c, 0x188f2335, 0xa5df759, 0x17a77eb6, 0xfeb0e73, 0x154ae914, 0x2f3ec51, 0x3826b59,
-    0xb91f17d, 0x1c72949, 0x1362bf0a, 0xe23fddf, 0xa5614b0, 0xf7d8f, 0x79061, 0x823d9d2, 0x8213f39,
-    0x1128ae0b, 0xd095d05, 0xb85c0c2, 0x1ecb2ef, 0x24ddc84, 0xe35e901, 0x18411a4a, 0xf5ddc3d, 0x3786689,
-    0x52260e8, 0x5ae3564, 0x542b10d, 0x8d93a45, 0x19952aa4, 0x996cc41, 0x1051a729, 0x4be3499, 0x52b23aa,
-    0x109f307e, 0x6f5b6bb, 0x1f84e1e7, 0x77a0cfa, 0x10c4df3f, 0x25a02ea, 0xb048035, 0xe31de66, 0xc6ecaa3,
-    0x28ea335, 0x2886024, 0x1372f020, 0xf55d35, 0x15e4684c, 0xf2a9e17, 0x1a4a7529, 0xcb7beb1, 0xb2a78a1,
-    0x1ab21f1f, 0x6361ccf, 0x6c9179d, 0xb135627, 0x1267b974, 0x4408bad, 0x1cbff658, 0xe3d6511, 0xc7d76f,
-    0x1cc7a69, 0xe7ee31b, 0x54fab4f, 0x2b914f, 0x1ad27a30, 0xcd3579e, 0xc50124c, 0x50daa90, 0xb13f72,
-    0xb06aa75, 0x70f5cc6, 0x1649e5aa, 0x84a5312, 0x329043c, 0x41c4011, 0x13d32411, 0xb04a838, 0xd760d2d,
-    0x1713b532, 0xbaa0c03, 0x84022ab, 0x6bcf5c1, 0x2f45379, 0x18ae070, 0x18c9e11e, 0x20bca9a, 0x66f496b,
-    0x3eef294, 0x67500d2, 0xd7f613c, 0x2dbbeb, 0xb741038, 0xe04133f, 0x1582968d, 0xbe985f7, 0x1acbc1a,
-    0x1a6a939f, 0x33e50f6, 0xd665ed4, 0xb4b7bd6, 0x1e5a3799, 0x6b33847, 0x17fa56ff, 0x65ef930, 0x21dc4a,
-    0x2b37659, 0x450fe17, 0xb357b65, 0xdf5efac, 0x15397bef, 0x9d35a7f, 0x112ac15f, 0x624e62e, 0xa90ae2f,
-    0x107eecd2, 0x1f69bbe, 0x77d6bce, 0x5741394, 0x13c684fc, 0x950c910, 0x725522b, 0xdc78583, 0x40eeabb,
-    0x1fde328a, 0xbd61d96, 0xd28c387, 0x9e77d89, 0x12550c40, 0x759cb7d, 0x367ef34, 0xae2a960, 0x91b8bdc,
-    0x93462a9, 0xf469ef, 0xb2e9aef, 0xd2ca771, 0x54e1f42, 0x7aaa49, 0x6316abb, 0x2413c8e, 0x5425bf9,
-    0x1bed3e3a, 0xf272274, 0x1f5e7326, 0x6416517, 0xea27072, 0x9cedea7, 0x6e7633, 0x7c91952, 0xd806dce,
-    0x8e2a7e1, 0xe421e1a, 0x418c9e1, 0x1dbc890, 0x1b395c36, 0xa1dc175, 0x1dc4ef73, 0x8956f34, 0xe4b5cf2,
-    0x1b0d3a18, 0x3194a36, 0x6c2641f, 0xe44124c, 0xa2f4eaa, 0xa8c25ba, 0xf927ed7, 0x627b614, 0x7371cca,
-    0xba16694, 0x417bc03, 0x7c0a7e3, 0x9c35c19, 0x1168a205, 0x8b6b00d, 0x10e3edc9, 0x9c19bf2, 0x5882229,
-    0x1b2b4162, 0xa5cef1a, 0x1543622b, 0x9bd433e, 0x364e04d, 0x7480792, 0x5c9b5b3, 0xe85ff25, 0x408ef57,
-    0x1814cfa4, 0x121b41b, 0xd248a0f, 0x3b05222, 0x39bb16a, 0xc75966d, 0xa038113, 0xa4a1769, 0x11fbc6c,
-    0x917e50e, 0xeec3da8, 0x169d6eac, 0x10c1699, 0xa416153, 0xf724912, 0x15cd60b7, 0x4acbad9, 0x5efc5fa,
-    0xf150ed7, 0x122b51, 0x1104b40a, 0xcb7f442, 0xfbb28ff, 0x6ac53ca, 0x196142cc, 0x7bf0fa9, 0x957651,
-    0x4e0f215, 0xed439f8, 0x3f46bd5, 0x5ace82f, 0x110916b6, 0x6db078, 0xffd7d57, 0xf2ecaac, 0xca86dec,
-    0x15d6b2da, 0x965ecc9, 0x1c92b4c2, 0x1f3811, 0x1cb080f5, 0x2d8b804, 0x19d1c12d, 0xf20bd46, 0x1951fa7,
-    0xa3656c3, 0x523a425, 0xfcd0692, 0xd44ddc8, 0x131f0f5b, 0xaf80e4a, 0xcd9fc74, 0x99bb618, 0x2db944c,
-    0xa673090, 0x1c210e1, 0x178c8d23, 0x1474383, 0x10b8743d, 0x985a55b, 0x2e74779, 0x576138, 0x9587927,
-    0x133130fa, 0xbe05516, 0x9f4d619, 0xbb62570, 0x99ec591, 0xd9468fe, 0x1d07782d, 0xfc72e0b, 0x701b298,
-    0x1863863b, 0x85954b8, 0x121a0c36, 0x9e7fedf, 0xf64b429, 0x9b9d71e, 0x14e2f5d8, 0xf858d3a, 0x942eea8,
-    0xda5b765, 0x6edafff, 0xa9d18cc, 0xc65e4ba, 0x1c747e86, 0xe4ea915, 0x1981d7a1, 0x8395659, 0x52ed4e2,
-    0x87d43b7, 0x37ab11b, 0x19d292ce, 0xf8d4692, 0x18c3053f, 0x8863e13, 0x4c146c0, 0x6bdf55a, 0x4e4457d,
-    0x16152289, 0xac78ec2, 0x1a59c5a2, 0x2028b97, 0x71c2d01, 0x295851f, 0x404747b, 0x878558d, 0x7d29aa4,
-    0x13d8341f, 0x8daefd7, 0x139c972d, 0x6b7ea75, 0xd4a9dde, 0xff163d8, 0x81d55d7, 0xa5bef68, 0xb7b30d8,
-    0xbe73d6f, 0xaa88141, 0xd976c81, 0x7e7a9cc, 0x18beb771, 0xd773cbd, 0x13f51951, 0x9d0c177, 0x1c49a78,
-};
-
-
-/* Field element operations: */
-
-/* NON_ZERO_TO_ALL_ONES returns:
- *   0xffffffff for 0 < x <= 2**31
- *   0 for x == 0 or x > 2**31.
- *
- * x must be a u32 or an equivalent type such as limb. */
-#define NON_ZERO_TO_ALL_ONES(x) ((((u32)(x) - 1) >> 31) - 1)
-
-/* felem_reduce_carry adds a multiple of p in order to cancel |carry|,
- * which is a term at 2**257.
- *
- * On entry: carry < 2**3, inout[0,2,...] < 2**29, inout[1,3,...] < 2**28.
- * On exit: inout[0,2,..] < 2**30, inout[1,3,...] < 2**29. */
-static void felem_reduce_carry(felem inout, limb carry) {
-  const u32 carry_mask = NON_ZERO_TO_ALL_ONES(carry);
-
-  inout[0] += carry << 1;
-  inout[3] += 0x10000000 & carry_mask;
-  /* carry < 2**3 thus (carry << 11) < 2**14 and we added 2**28 in the
-   * previous line therefore this doesn't underflow. */
-  inout[3] -= carry << 11;
-  inout[4] += (0x20000000 - 1) & carry_mask;
-  inout[5] += (0x10000000 - 1) & carry_mask;
-  inout[6] += (0x20000000 - 1) & carry_mask;
-  inout[6] -= carry << 22;
-  /* This may underflow if carry is non-zero but, if so, we'll fix it in the
-   * next line. */
-  inout[7] -= 1 & carry_mask;
-  inout[7] += carry << 25;
-}
-
-/* felem_sum sets out = in+in2.
- *
- * On entry, in[i]+in2[i] must not overflow a 32-bit word.
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29 */
-static void felem_sum(felem out, const felem in, const felem in2) {
-  limb carry = 0;
-  unsigned i;
-
-  for (i = 0;; i++) {
-    out[i] = in[i] + in2[i];
-    out[i] += carry;
-    carry = out[i] >> 29;
-    out[i] &= kBottom29Bits;
-
-    i++;
-    if (i == NLIMBS)
-      break;
-
-    out[i] = in[i] + in2[i];
-    out[i] += carry;
-    carry = out[i] >> 28;
-    out[i] &= kBottom28Bits;
-  }
-
-  felem_reduce_carry(out, carry);
-}
-
-#define two31m3 (((limb)1) << 31) - (((limb)1) << 3)
-#define two30m2 (((limb)1) << 30) - (((limb)1) << 2)
-#define two30p13m2 (((limb)1) << 30) + (((limb)1) << 13) - (((limb)1) << 2)
-#define two31m2 (((limb)1) << 31) - (((limb)1) << 2)
-#define two31p24m2 (((limb)1) << 31) + (((limb)1) << 24) - (((limb)1) << 2)
-#define two30m27m2 (((limb)1) << 30) - (((limb)1) << 27) - (((limb)1) << 2)
-
-/* zero31 is 0 mod p. */
-static const felem zero31 = { two31m3, two30m2, two31m2, two30p13m2, two31m2, two30m2, two31p24m2, two30m27m2, two31m2 };
-
-/* felem_diff sets out = in-in2.
- *
- * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29 and
- *           in2[0,2,...] < 2**30, in2[1,3,...] < 2**29.
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
-static void felem_diff(felem out, const felem in, const felem in2) {
-  limb carry = 0;
-  unsigned i;
-
-   for (i = 0;; i++) {
-    out[i] = in[i] - in2[i];
-    out[i] += zero31[i];
-    out[i] += carry;
-    carry = out[i] >> 29;
-    out[i] &= kBottom29Bits;
-
-    i++;
-    if (i == NLIMBS)
-      break;
-
-    out[i] = in[i] - in2[i];
-    out[i] += zero31[i];
-    out[i] += carry;
-    carry = out[i] >> 28;
-    out[i] &= kBottom28Bits;
-  }
-
-  felem_reduce_carry(out, carry);
-}
-
-/* felem_reduce_degree sets out = tmp/R mod p where tmp contains 64-bit words
- * with the same 29,28,... bit positions as an felem.
- *
- * The values in felems are in Montgomery form: x*R mod p where R = 2**257.
- * Since we just multiplied two Montgomery values together, the result is
- * x*y*R*R mod p. We wish to divide by R in order for the result also to be
- * in Montgomery form.
- *
- * On entry: tmp[i] < 2**64
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29 */
-static void felem_reduce_degree(felem out, u64 tmp[17]) {
-   /* The following table may be helpful when reading this code:
-    *
-    * Limb number:   0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10...
-    * Width (bits):  29| 28| 29| 28| 29| 28| 29| 28| 29| 28| 29
-    * Start bit:     0 | 29| 57| 86|114|143|171|200|228|257|285
-    *   (odd phase): 0 | 28| 57| 85|114|142|171|199|228|256|285 */
-  limb tmp2[18], carry, x, xMask;
-  unsigned i;
-
-  /* tmp contains 64-bit words with the same 29,28,29-bit positions as an
-   * felem. So the top of an element of tmp might overlap with another
-   * element two positions down. The following loop eliminates this
-   * overlap. */
-  tmp2[0] = (limb)(tmp[0] & kBottom29Bits);
-
-  /* In the following we use "(limb) tmp[x]" and "(limb) (tmp[x]>>32)" to try
-   * and hint to the compiler that it can do a single-word shift by selecting
-   * the right register rather than doing a double-word shift and truncating
-   * afterwards. */
-  tmp2[1] = ((limb) tmp[0]) >> 29;
-  tmp2[1] |= (((limb)(tmp[0] >> 32)) << 3) & kBottom28Bits;
-  tmp2[1] += ((limb) tmp[1]) & kBottom28Bits;
-  carry = tmp2[1] >> 28;
-  tmp2[1] &= kBottom28Bits;
-
-  for (i = 2; i < 17; i++) {
-    tmp2[i] = ((limb)(tmp[i - 2] >> 32)) >> 25;
-    tmp2[i] += ((limb)(tmp[i - 1])) >> 28;
-    tmp2[i] += (((limb)(tmp[i - 1] >> 32)) << 4) & kBottom29Bits;
-    tmp2[i] += ((limb) tmp[i]) & kBottom29Bits;
-    tmp2[i] += carry;
-    carry = tmp2[i] >> 29;
-    tmp2[i] &= kBottom29Bits;
-
-    i++;
-    if (i == 17)
-      break;
-    tmp2[i] = ((limb)(tmp[i - 2] >> 32)) >> 25;
-    tmp2[i] += ((limb)(tmp[i - 1])) >> 29;
-    tmp2[i] += (((limb)(tmp[i - 1] >> 32)) << 3) & kBottom28Bits;
-    tmp2[i] += ((limb) tmp[i]) & kBottom28Bits;
-    tmp2[i] += carry;
-    carry = tmp2[i] >> 28;
-    tmp2[i] &= kBottom28Bits;
-  }
-
-  tmp2[17] = ((limb)(tmp[15] >> 32)) >> 25;
-  tmp2[17] += ((limb)(tmp[16])) >> 29;
-  tmp2[17] += (((limb)(tmp[16] >> 32)) << 3);
-  tmp2[17] += carry;
-
-  /* Montgomery elimination of terms.
-   *
-   * Since R is 2**257, we can divide by R with a bitwise shift if we can
-   * ensure that the right-most 257 bits are all zero. We can make that true by
-   * adding multiplies of p without affecting the value.
-   *
-   * So we eliminate limbs from right to left. Since the bottom 29 bits of p
-   * are all ones, then by adding tmp2[0]*p to tmp2 we'll make tmp2[0] == 0.
-   * We can do that for 8 further limbs and then right shift to eliminate the
-   * extra factor of R. */
-  for (i = 0;; i += 2) {
-    tmp2[i + 1] += tmp2[i] >> 29;
-    x = tmp2[i] & kBottom29Bits;
-    xMask = NON_ZERO_TO_ALL_ONES(x);
-    tmp2[i] = 0;
-
-    /* The bounds calculations for this loop are tricky. Each iteration of
-     * the loop eliminates two words by adding values to words to their
-     * right.
-     *
-     * The following table contains the amounts added to each word (as an
-     * offset from the value of i at the top of the loop). The amounts are
-     * accounted for from the first and second half of the loop separately
-     * and are written as, for example, 28 to mean a value <2**28.
-     *
-     * Word:                   3   4   5   6   7   8   9   10
-     * Added in top half:     28  11      29  21  29  28
-     *                                        28  29
-     *                                            29
-     * Added in bottom half:      29  10      28  21  28   28
-     *                                            29
-     *
-     * The value that is currently offset 7 will be offset 5 for the next
-     * iteration and then offset 3 for the iteration after that. Therefore
-     * the total value added will be the values added at 7, 5 and 3.
-     *
-     * The following table accumulates these values. The sums at the bottom
-     * are written as, for example, 29+28, to mean a value < 2**29+2**28.
-     *
-     * Word:                   3   4   5   6   7   8   9  10  11  12  13
-     *                        28  11  10  29  21  29  28  28  28  28  28
-     *                            29  28  11  28  29  28  29  28  29  28
-     *                                    29  28  21  21  29  21  29  21
-     *                                        10  29  28  21  28  21  28
-     *                                        28  29  28  29  28  29  28
-     *                                            11  10  29  10  29  10
-     *                                            29  28  11  28  11
-     *                                                    29      29
-     *                        --------------------------------------------
-     *                                                30+ 31+ 30+ 31+ 30+
-     *                                                28+ 29+ 28+ 29+ 21+
-     *                                                21+ 28+ 21+ 28+ 10
-     *                                                10  21+ 10  21+
-     *                                                    11      11
-     *
-     * So the greatest amount is added to tmp2[10] and tmp2[12]. If
-     * tmp2[10/12] has an initial value of <2**29, then the maximum value
-     * will be < 2**31 + 2**30 + 2**28 + 2**21 + 2**11, which is < 2**32,
-     * as required. */
-    tmp2[i + 3] += (x << 10) & kBottom28Bits;
-    tmp2[i + 4] += (x >> 18);
-
-    tmp2[i + 6] += (x << 21) & kBottom29Bits;
-    tmp2[i + 7] += x >> 8;
-
-    /* At position 200, which is the starting bit position for word 7, we
-     * have a factor of 0xf000000 = 2**28 - 2**24. */
-    tmp2[i + 7] += 0x10000000 & xMask;
-    /* Word 7 is 28 bits wide, so the 2**28 term exactly hits word 8. */
-    tmp2[i + 8] += (x - 1) & xMask;
-    tmp2[i + 7] -= (x << 24) & kBottom28Bits;
-    tmp2[i + 8] -= x >> 4;
-
-    tmp2[i + 8] += 0x20000000 & xMask;
-    tmp2[i + 8] -= x;
-    tmp2[i + 8] += (x << 28) & kBottom29Bits;
-    tmp2[i + 9] += ((x >> 1) - 1) & xMask;
-
-    if (i+1 == NLIMBS)
-      break;
-    tmp2[i + 2] += tmp2[i + 1] >> 28;
-    x = tmp2[i + 1] & kBottom28Bits;
-    xMask = NON_ZERO_TO_ALL_ONES(x);
-    tmp2[i + 1] = 0;
-
-    tmp2[i + 4] += (x << 11) & kBottom29Bits;
-    tmp2[i + 5] += (x >> 18);
-
-    tmp2[i + 7] += (x << 21) & kBottom28Bits;
-    tmp2[i + 8] += x >> 7;
-
-    /* At position 199, which is the starting bit of the 8th word when
-     * dealing with a context starting on an odd word, we have a factor of
-     * 0x1e000000 = 2**29 - 2**25. Since we have not updated i, the 8th
-     * word from i+1 is i+8. */
-    tmp2[i + 8] += 0x20000000 & xMask;
-    tmp2[i + 9] += (x - 1) & xMask;
-    tmp2[i + 8] -= (x << 25) & kBottom29Bits;
-    tmp2[i + 9] -= x >> 4;
-
-    tmp2[i + 9] += 0x10000000 & xMask;
-    tmp2[i + 9] -= x;
-    tmp2[i + 10] += (x - 1) & xMask;
-  }
-
-  /* We merge the right shift with a carry chain. The words above 2**257 have
-   * widths of 28,29,... which we need to correct when copying them down.  */
-  carry = 0;
-  for (i = 0; i < 8; i++) {
-    /* The maximum value of tmp2[i + 9] occurs on the first iteration and
-     * is < 2**30+2**29+2**28. Adding 2**29 (from tmp2[i + 10]) is
-     * therefore safe. */
-    out[i] = tmp2[i + 9];
-    out[i] += carry;
-    out[i] += (tmp2[i + 10] << 28) & kBottom29Bits;
-    carry = out[i] >> 29;
-    out[i] &= kBottom29Bits;
-
-    i++;
-    out[i] = tmp2[i + 9] >> 1;
-    out[i] += carry;
-    carry = out[i] >> 28;
-    out[i] &= kBottom28Bits;
-  }
-
-  out[8] = tmp2[17];
-  out[8] += carry;
-  carry = out[8] >> 29;
-  out[8] &= kBottom29Bits;
-
-  felem_reduce_carry(out, carry);
-}
-
-/* felem_square sets out=in*in.
- *
- * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29.
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
-static void felem_square(felem out, const felem in) {
-  u64 tmp[17];
-
-  tmp[0] = ((u64) in[0]) * in[0];
-  tmp[1] = ((u64) in[0]) * (in[1] << 1);
-  tmp[2] = ((u64) in[0]) * (in[2] << 1) +
-           ((u64) in[1]) * (in[1] << 1);
-  tmp[3] = ((u64) in[0]) * (in[3] << 1) +
-           ((u64) in[1]) * (in[2] << 1);
-  tmp[4] = ((u64) in[0]) * (in[4] << 1) +
-           ((u64) in[1]) * (in[3] << 2) + ((u64) in[2]) * in[2];
-  tmp[5] = ((u64) in[0]) * (in[5] << 1) + ((u64) in[1]) *
-           (in[4] << 1) + ((u64) in[2]) * (in[3] << 1);
-  tmp[6] = ((u64) in[0]) * (in[6] << 1) + ((u64) in[1]) *
-           (in[5] << 2) + ((u64) in[2]) * (in[4] << 1) +
-           ((u64) in[3]) * (in[3] << 1);
-  tmp[7] = ((u64) in[0]) * (in[7] << 1) + ((u64) in[1]) *
-           (in[6] << 1) + ((u64) in[2]) * (in[5] << 1) +
-           ((u64) in[3]) * (in[4] << 1);
-  /* tmp[8] has the greatest value of 2**61 + 2**60 + 2**61 + 2**60 + 2**60,
-   * which is < 2**64 as required. */
-  tmp[8] = ((u64) in[0]) * (in[8] << 1) + ((u64) in[1]) *
-           (in[7] << 2) + ((u64) in[2]) * (in[6] << 1) +
-           ((u64) in[3]) * (in[5] << 2) + ((u64) in[4]) * in[4];
-  tmp[9] = ((u64) in[1]) * (in[8] << 1) + ((u64) in[2]) *
-           (in[7] << 1) + ((u64) in[3]) * (in[6] << 1) +
-           ((u64) in[4]) * (in[5] << 1);
-  tmp[10] = ((u64) in[2]) * (in[8] << 1) + ((u64) in[3]) *
-            (in[7] << 2) + ((u64) in[4]) * (in[6] << 1) +
-            ((u64) in[5]) * (in[5] << 1);
-  tmp[11] = ((u64) in[3]) * (in[8] << 1) + ((u64) in[4]) *
-            (in[7] << 1) + ((u64) in[5]) * (in[6] << 1);
-  tmp[12] = ((u64) in[4]) * (in[8] << 1) +
-            ((u64) in[5]) * (in[7] << 2) + ((u64) in[6]) * in[6];
-  tmp[13] = ((u64) in[5]) * (in[8] << 1) +
-            ((u64) in[6]) * (in[7] << 1);
-  tmp[14] = ((u64) in[6]) * (in[8] << 1) +
-            ((u64) in[7]) * (in[7] << 1);
-  tmp[15] = ((u64) in[7]) * (in[8] << 1);
-  tmp[16] = ((u64) in[8]) * in[8];
-
-  felem_reduce_degree(out, tmp);
-}
-
-/* felem_mul sets out=in*in2.
- *
- * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29 and
- *           in2[0,2,...] < 2**30, in2[1,3,...] < 2**29.
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
-static void felem_mul(felem out, const felem in, const felem in2) {
-  u64 tmp[17];
-
-  tmp[0] = ((u64) in[0]) * in2[0];
-  tmp[1] = ((u64) in[0]) * (in2[1] << 0) +
-           ((u64) in[1]) * (in2[0] << 0);
-  tmp[2] = ((u64) in[0]) * (in2[2] << 0) + ((u64) in[1]) *
-           (in2[1] << 1) + ((u64) in[2]) * (in2[0] << 0);
-  tmp[3] = ((u64) in[0]) * (in2[3] << 0) + ((u64) in[1]) *
-           (in2[2] << 0) + ((u64) in[2]) * (in2[1] << 0) +
-           ((u64) in[3]) * (in2[0] << 0);
-  tmp[4] = ((u64) in[0]) * (in2[4] << 0) + ((u64) in[1]) *
-           (in2[3] << 1) + ((u64) in[2]) * (in2[2] << 0) +
-           ((u64) in[3]) * (in2[1] << 1) +
-           ((u64) in[4]) * (in2[0] << 0);
-  tmp[5] = ((u64) in[0]) * (in2[5] << 0) + ((u64) in[1]) *
-           (in2[4] << 0) + ((u64) in[2]) * (in2[3] << 0) +
-           ((u64) in[3]) * (in2[2] << 0) + ((u64) in[4]) *
-           (in2[1] << 0) + ((u64) in[5]) * (in2[0] << 0);
-  tmp[6] = ((u64) in[0]) * (in2[6] << 0) + ((u64) in[1]) *
-           (in2[5] << 1) + ((u64) in[2]) * (in2[4] << 0) +
-           ((u64) in[3]) * (in2[3] << 1) + ((u64) in[4]) *
-           (in2[2] << 0) + ((u64) in[5]) * (in2[1] << 1) +
-           ((u64) in[6]) * (in2[0] << 0);
-  tmp[7] = ((u64) in[0]) * (in2[7] << 0) + ((u64) in[1]) *
-           (in2[6] << 0) + ((u64) in[2]) * (in2[5] << 0) +
-           ((u64) in[3]) * (in2[4] << 0) + ((u64) in[4]) *
-           (in2[3] << 0) + ((u64) in[5]) * (in2[2] << 0) +
-           ((u64) in[6]) * (in2[1] << 0) +
-           ((u64) in[7]) * (in2[0] << 0);
-  /* tmp[8] has the greatest value but doesn't overflow. See logic in
-   * felem_square. */
-  tmp[8] = ((u64) in[0]) * (in2[8] << 0) + ((u64) in[1]) *
-           (in2[7] << 1) + ((u64) in[2]) * (in2[6] << 0) +
-           ((u64) in[3]) * (in2[5] << 1) + ((u64) in[4]) *
-           (in2[4] << 0) + ((u64) in[5]) * (in2[3] << 1) +
-           ((u64) in[6]) * (in2[2] << 0) + ((u64) in[7]) *
-           (in2[1] << 1) + ((u64) in[8]) * (in2[0] << 0);
-  tmp[9] = ((u64) in[1]) * (in2[8] << 0) + ((u64) in[2]) *
-           (in2[7] << 0) + ((u64) in[3]) * (in2[6] << 0) +
-           ((u64) in[4]) * (in2[5] << 0) + ((u64) in[5]) *
-           (in2[4] << 0) + ((u64) in[6]) * (in2[3] << 0) +
-           ((u64) in[7]) * (in2[2] << 0) +
-           ((u64) in[8]) * (in2[1] << 0);
-  tmp[10] = ((u64) in[2]) * (in2[8] << 0) + ((u64) in[3]) *
-            (in2[7] << 1) + ((u64) in[4]) * (in2[6] << 0) +
-            ((u64) in[5]) * (in2[5] << 1) + ((u64) in[6]) *
-            (in2[4] << 0) + ((u64) in[7]) * (in2[3] << 1) +
-            ((u64) in[8]) * (in2[2] << 0);
-  tmp[11] = ((u64) in[3]) * (in2[8] << 0) + ((u64) in[4]) *
-            (in2[7] << 0) + ((u64) in[5]) * (in2[6] << 0) +
-            ((u64) in[6]) * (in2[5] << 0) + ((u64) in[7]) *
-            (in2[4] << 0) + ((u64) in[8]) * (in2[3] << 0);
-  tmp[12] = ((u64) in[4]) * (in2[8] << 0) + ((u64) in[5]) *
-            (in2[7] << 1) + ((u64) in[6]) * (in2[6] << 0) +
-            ((u64) in[7]) * (in2[5] << 1) +
-            ((u64) in[8]) * (in2[4] << 0);
-  tmp[13] = ((u64) in[5]) * (in2[8] << 0) + ((u64) in[6]) *
-            (in2[7] << 0) + ((u64) in[7]) * (in2[6] << 0) +
-            ((u64) in[8]) * (in2[5] << 0);
-  tmp[14] = ((u64) in[6]) * (in2[8] << 0) + ((u64) in[7]) *
-            (in2[7] << 1) + ((u64) in[8]) * (in2[6] << 0);
-  tmp[15] = ((u64) in[7]) * (in2[8] << 0) +
-            ((u64) in[8]) * (in2[7] << 0);
-  tmp[16] = ((u64) in[8]) * (in2[8] << 0);
-
-  felem_reduce_degree(out, tmp);
-}
-
-static void felem_assign(felem out, const felem in) {
-  memcpy(out, in, sizeof(felem));
-}
-
-/* felem_inv calculates |out| = |in|^{-1}
- *
- * Based on Fermat's Little Theorem:
- *   a^p = a (mod p)
- *   a^{p-1} = 1 (mod p)
- *   a^{p-2} = a^{-1} (mod p)
- */
-static void felem_inv(felem out, const felem in) {
-  felem ftmp, ftmp2;
-  /* each e_I will hold |in|^{2^I - 1} */
-  felem e2, e4, e8, e16, e32, e64;
-  unsigned i;
-
-  felem_square(ftmp, in); /* 2^1 */
-  felem_mul(ftmp, in, ftmp); /* 2^2 - 2^0 */
-  felem_assign(e2, ftmp);
-  felem_square(ftmp, ftmp); /* 2^3 - 2^1 */
-  felem_square(ftmp, ftmp); /* 2^4 - 2^2 */
-  felem_mul(ftmp, ftmp, e2); /* 2^4 - 2^0 */
-  felem_assign(e4, ftmp);
-  felem_square(ftmp, ftmp); /* 2^5 - 2^1 */
-  felem_square(ftmp, ftmp); /* 2^6 - 2^2 */
-  felem_square(ftmp, ftmp); /* 2^7 - 2^3 */
-  felem_square(ftmp, ftmp); /* 2^8 - 2^4 */
-  felem_mul(ftmp, ftmp, e4); /* 2^8 - 2^0 */
-  felem_assign(e8, ftmp);
-  for (i = 0; i < 8; i++) {
-    felem_square(ftmp, ftmp);
-  } /* 2^16 - 2^8 */
-  felem_mul(ftmp, ftmp, e8); /* 2^16 - 2^0 */
-  felem_assign(e16, ftmp);
-  for (i = 0; i < 16; i++) {
-    felem_square(ftmp, ftmp);
-  } /* 2^32 - 2^16 */
-  felem_mul(ftmp, ftmp, e16); /* 2^32 - 2^0 */
-  felem_assign(e32, ftmp);
-  for (i = 0; i < 32; i++) {
-    felem_square(ftmp, ftmp);
-  } /* 2^64 - 2^32 */
-  felem_assign(e64, ftmp);
-  felem_mul(ftmp, ftmp, in); /* 2^64 - 2^32 + 2^0 */
-  for (i = 0; i < 192; i++) {
-    felem_square(ftmp, ftmp);
-  } /* 2^256 - 2^224 + 2^192 */
-
-  felem_mul(ftmp2, e64, e32); /* 2^64 - 2^0 */
-  for (i = 0; i < 16; i++) {
-    felem_square(ftmp2, ftmp2);
-  } /* 2^80 - 2^16 */
-  felem_mul(ftmp2, ftmp2, e16); /* 2^80 - 2^0 */
-  for (i = 0; i < 8; i++) {
-    felem_square(ftmp2, ftmp2);
-  } /* 2^88 - 2^8 */
-  felem_mul(ftmp2, ftmp2, e8); /* 2^88 - 2^0 */
-  for (i = 0; i < 4; i++) {
-    felem_square(ftmp2, ftmp2);
-  } /* 2^92 - 2^4 */
-  felem_mul(ftmp2, ftmp2, e4); /* 2^92 - 2^0 */
-  felem_square(ftmp2, ftmp2); /* 2^93 - 2^1 */
-  felem_square(ftmp2, ftmp2); /* 2^94 - 2^2 */
-  felem_mul(ftmp2, ftmp2, e2); /* 2^94 - 2^0 */
-  felem_square(ftmp2, ftmp2); /* 2^95 - 2^1 */
-  felem_square(ftmp2, ftmp2); /* 2^96 - 2^2 */
-  felem_mul(ftmp2, ftmp2, in); /* 2^96 - 3 */
-
-  felem_mul(out, ftmp2, ftmp); /* 2^256 - 2^224 + 2^192 + 2^96 - 3 */
-}
-
-/* felem_scalar_3 sets out=3*out.
- *
- * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
-static void felem_scalar_3(felem out) {
-  limb carry = 0;
-  unsigned i;
-
-  for (i = 0;; i++) {
-    out[i] *= 3;
-    out[i] += carry;
-    carry = out[i] >> 29;
-    out[i] &= kBottom29Bits;
-
-    i++;
-    if (i == NLIMBS)
-      break;
-
-    out[i] *= 3;
-    out[i] += carry;
-    carry = out[i] >> 28;
-    out[i] &= kBottom28Bits;
-  }
-
-  felem_reduce_carry(out, carry);
-}
-
-/* felem_scalar_4 sets out=4*out.
- *
- * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
-static void felem_scalar_4(felem out) {
-  limb carry = 0, next_carry;
-  unsigned i;
-
-  for (i = 0;; i++) {
-    next_carry = out[i] >> 27;
-    out[i] <<= 2;
-    out[i] &= kBottom29Bits;
-    out[i] += carry;
-    carry = next_carry + (out[i] >> 29);
-    out[i] &= kBottom29Bits;
-
-    i++;
-    if (i == NLIMBS)
-      break;
-
-    next_carry = out[i] >> 26;
-    out[i] <<= 2;
-    out[i] &= kBottom28Bits;
-    out[i] += carry;
-    carry = next_carry + (out[i] >> 28);
-    out[i] &= kBottom28Bits;
-  }
-
-  felem_reduce_carry(out, carry);
-}
-
-/* felem_scalar_8 sets out=8*out.
- *
- * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
-static void felem_scalar_8(felem out) {
-  limb carry = 0, next_carry;
-  unsigned i;
-
-  for (i = 0;; i++) {
-    next_carry = out[i] >> 26;
-    out[i] <<= 3;
-    out[i] &= kBottom29Bits;
-    out[i] += carry;
-    carry = next_carry + (out[i] >> 29);
-    out[i] &= kBottom29Bits;
-
-    i++;
-    if (i == NLIMBS)
-      break;
-
-    next_carry = out[i] >> 25;
-    out[i] <<= 3;
-    out[i] &= kBottom28Bits;
-    out[i] += carry;
-    carry = next_carry + (out[i] >> 28);
-    out[i] &= kBottom28Bits;
-  }
-
-  felem_reduce_carry(out, carry);
-}
-
-/* felem_is_zero_vartime returns 1 iff |in| == 0. It takes a variable amount of
- * time depending on the value of |in|. */
-static char felem_is_zero_vartime(const felem in) {
-  limb carry;
-  int i;
-  limb tmp[NLIMBS];
-
-  felem_assign(tmp, in);
-
-  /* First, reduce tmp to a minimal form. */
-  do {
-    carry = 0;
-    for (i = 0;; i++) {
-      tmp[i] += carry;
-      carry = tmp[i] >> 29;
-      tmp[i] &= kBottom29Bits;
-
-      i++;
-      if (i == NLIMBS)
-        break;
-
-      tmp[i] += carry;
-      carry = tmp[i] >> 28;
-      tmp[i] &= kBottom28Bits;
-    }
-
-    felem_reduce_carry(tmp, carry);
-  } while (carry);
-
-  /* tmp < 2**257, so the only possible zero values are 0, p and 2p. */
-  return memcmp(tmp, kZero, sizeof(tmp)) == 0 ||
-         memcmp(tmp, kP, sizeof(tmp)) == 0 ||
-         memcmp(tmp, k2P, sizeof(tmp)) == 0;
-}
-
-
-/* Group operations:
- *
- * Elements of the elliptic curve group are represented in Jacobian
- * coordinates: (x, y, z). An affine point (x', y') is x'=x/z**2, y'=y/z**3 in
- * Jacobian form. */
-
-/* point_double sets {x_out,y_out,z_out} = 2*{x,y,z}.
- *
- * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l */
-static void point_double(felem x_out, felem y_out, felem z_out, const felem x,
-                         const felem y, const felem z) {
-  felem delta, gamma, alpha, beta, tmp, tmp2;
-
-  felem_square(delta, z);
-  felem_square(gamma, y);
-  felem_mul(beta, x, gamma);
-
-  felem_sum(tmp, x, delta);
-  felem_diff(tmp2, x, delta);
-  felem_mul(alpha, tmp, tmp2);
-  felem_scalar_3(alpha);
-
-  felem_sum(tmp, y, z);
-  felem_square(tmp, tmp);
-  felem_diff(tmp, tmp, gamma);
-  felem_diff(z_out, tmp, delta);
-
-  felem_scalar_4(beta);
-  felem_square(x_out, alpha);
-  felem_diff(x_out, x_out, beta);
-  felem_diff(x_out, x_out, beta);
-
-  felem_diff(tmp, beta, x_out);
-  felem_mul(tmp, alpha, tmp);
-  felem_square(tmp2, gamma);
-  felem_scalar_8(tmp2);
-  felem_diff(y_out, tmp, tmp2);
-}
-
-/* point_add_mixed sets {x_out,y_out,z_out} = {x1,y1,z1} + {x2,y2,1}.
- * (i.e. the second point is affine.)
- *
- * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
- *
- * Note that this function does not handle P+P, infinity+P nor P+infinity
- * correctly. */
-static void point_add_mixed(felem x_out, felem y_out, felem z_out,
-                            const felem x1, const felem y1, const felem z1,
-                            const felem x2, const felem y2) {
-  felem z1z1, z1z1z1, s2, u2, h, i, j, r, rr, v, tmp;
-
-  felem_square(z1z1, z1);
-  felem_sum(tmp, z1, z1);
-
-  felem_mul(u2, x2, z1z1);
-  felem_mul(z1z1z1, z1, z1z1);
-  felem_mul(s2, y2, z1z1z1);
-  felem_diff(h, u2, x1);
-  felem_sum(i, h, h);
-  felem_square(i, i);
-  felem_mul(j, h, i);
-  felem_diff(r, s2, y1);
-  felem_sum(r, r, r);
-  felem_mul(v, x1, i);
-
-  felem_mul(z_out, tmp, h);
-  felem_square(rr, r);
-  felem_diff(x_out, rr, j);
-  felem_diff(x_out, x_out, v);
-  felem_diff(x_out, x_out, v);
-
-  felem_diff(tmp, v, x_out);
-  felem_mul(y_out, tmp, r);
-  felem_mul(tmp, y1, j);
-  felem_diff(y_out, y_out, tmp);
-  felem_diff(y_out, y_out, tmp);
-}
-
-/* point_add sets {x_out,y_out,z_out} = {x1,y1,z1} + {x2,y2,z2}.
- *
- * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
- *
- * Note that this function does not handle P+P, infinity+P nor P+infinity
- * correctly. */
-static void point_add(felem x_out, felem y_out, felem z_out, const felem x1,
-                      const felem y1, const felem z1, const felem x2,
-                      const felem y2, const felem z2) {
-  felem z1z1, z1z1z1, z2z2, z2z2z2, s1, s2, u1, u2, h, i, j, r, rr, v, tmp;
-
-  felem_square(z1z1, z1);
-  felem_square(z2z2, z2);
-  felem_mul(u1, x1, z2z2);
-
-  felem_sum(tmp, z1, z2);
-  felem_square(tmp, tmp);
-  felem_diff(tmp, tmp, z1z1);
-  felem_diff(tmp, tmp, z2z2);
-
-  felem_mul(z2z2z2, z2, z2z2);
-  felem_mul(s1, y1, z2z2z2);
-
-  felem_mul(u2, x2, z1z1);
-  felem_mul(z1z1z1, z1, z1z1);
-  felem_mul(s2, y2, z1z1z1);
-  felem_diff(h, u2, u1);
-  felem_sum(i, h, h);
-  felem_square(i, i);
-  felem_mul(j, h, i);
-  felem_diff(r, s2, s1);
-  felem_sum(r, r, r);
-  felem_mul(v, u1, i);
-
-  felem_mul(z_out, tmp, h);
-  felem_square(rr, r);
-  felem_diff(x_out, rr, j);
-  felem_diff(x_out, x_out, v);
-  felem_diff(x_out, x_out, v);
-
-  felem_diff(tmp, v, x_out);
-  felem_mul(y_out, tmp, r);
-  felem_mul(tmp, s1, j);
-  felem_diff(y_out, y_out, tmp);
-  felem_diff(y_out, y_out, tmp);
-}
-
-/* point_add_or_double_vartime sets {x_out,y_out,z_out} = {x1,y1,z1} +
- *                                                        {x2,y2,z2}.
- *
- * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
- *
- * This function handles the case where {x1,y1,z1}={x2,y2,z2}. */
-static void point_add_or_double_vartime(
-    felem x_out, felem y_out, felem z_out, const felem x1, const felem y1,
-    const felem z1, const felem x2, const felem y2, const felem z2) {
-  felem z1z1, z1z1z1, z2z2, z2z2z2, s1, s2, u1, u2, h, i, j, r, rr, v, tmp;
-  char x_equal, y_equal;
-
-  felem_square(z1z1, z1);
-  felem_square(z2z2, z2);
-  felem_mul(u1, x1, z2z2);
-
-  felem_sum(tmp, z1, z2);
-  felem_square(tmp, tmp);
-  felem_diff(tmp, tmp, z1z1);
-  felem_diff(tmp, tmp, z2z2);
-
-  felem_mul(z2z2z2, z2, z2z2);
-  felem_mul(s1, y1, z2z2z2);
-
-  felem_mul(u2, x2, z1z1);
-  felem_mul(z1z1z1, z1, z1z1);
-  felem_mul(s2, y2, z1z1z1);
-  felem_diff(h, u2, u1);
-  x_equal = felem_is_zero_vartime(h);
-  felem_sum(i, h, h);
-  felem_square(i, i);
-  felem_mul(j, h, i);
-  felem_diff(r, s2, s1);
-  y_equal = felem_is_zero_vartime(r);
-  if (x_equal && y_equal) {
-    point_double(x_out, y_out, z_out, x1, y1, z1);
-    return;
-  }
-  felem_sum(r, r, r);
-  felem_mul(v, u1, i);
-
-  felem_mul(z_out, tmp, h);
-  felem_square(rr, r);
-  felem_diff(x_out, rr, j);
-  felem_diff(x_out, x_out, v);
-  felem_diff(x_out, x_out, v);
-
-  felem_diff(tmp, v, x_out);
-  felem_mul(y_out, tmp, r);
-  felem_mul(tmp, s1, j);
-  felem_diff(y_out, y_out, tmp);
-  felem_diff(y_out, y_out, tmp);
-}
-
-/* copy_conditional sets out=in if mask = 0xffffffff in constant time.
- *
- * On entry: mask is either 0 or 0xffffffff. */
-static void copy_conditional(felem out, const felem in, limb mask) {
-  int i;
-
-  for (i = 0; i < NLIMBS; i++) {
-    const limb tmp = mask & (in[i] ^ out[i]);
-    out[i] ^= tmp;
-  }
-}
-
-/* select_affine_point sets {out_x,out_y} to the index'th entry of table.
- * On entry: index < 16, table[0] must be zero. */
-static void select_affine_point(felem out_x, felem out_y, const limb* table,
-                                limb index) {
-  limb i, j;
-
-  memset(out_x, 0, sizeof(felem));
-  memset(out_y, 0, sizeof(felem));
-
-  for (i = 1; i < 16; i++) {
-    limb mask = i ^ index;
-    mask |= mask >> 2;
-    mask |= mask >> 1;
-    mask &= 1;
-    mask--;
-    for (j = 0; j < NLIMBS; j++, table++) {
-      out_x[j] |= *table & mask;
-    }
-    for (j = 0; j < NLIMBS; j++, table++) {
-      out_y[j] |= *table & mask;
-    }
-  }
-}
-
-/* select_jacobian_point sets {out_x,out_y,out_z} to the index'th entry of
- * table. On entry: index < 16, table[0] must be zero. */
-static void select_jacobian_point(felem out_x, felem out_y, felem out_z,
-                                  const limb* table, limb index) {
-  limb i, j;
-
-  memset(out_x, 0, sizeof(felem));
-  memset(out_y, 0, sizeof(felem));
-  memset(out_z, 0, sizeof(felem));
-
-  /* The implicit value at index 0 is all zero. We don't need to perform that
-   * iteration of the loop because we already set out_* to zero. */
-  table += 3 * NLIMBS;
-
-  // Hit all entries to obscure cache profiling.
-  for (i = 1; i < 16; i++) {
-    limb mask = i ^ index;
-    mask |= mask >> 2;
-    mask |= mask >> 1;
-    mask &= 1;
-    mask--;
-    for (j = 0; j < NLIMBS; j++, table++) {
-      out_x[j] |= *table & mask;
-    }
-    for (j = 0; j < NLIMBS; j++, table++) {
-      out_y[j] |= *table & mask;
-    }
-    for (j = 0; j < NLIMBS; j++, table++) {
-      out_z[j] |= *table & mask;
-    }
-  }
-}
-
-/* scalar_base_mult sets {nx,ny,nz} = scalar*G where scalar is a little-endian
- * number. Note that the value of scalar must be less than the order of the
- * group. */
-static void scalar_base_mult(felem nx, felem ny, felem nz,
-                             const p256_int* scalar) {
-  int i, j;
-  limb n_is_infinity_mask = -1, p_is_noninfinite_mask, mask;
-  u32 table_offset;
-
-  felem px, py;
-  felem tx, ty, tz;
-
-  memset(nx, 0, sizeof(felem));
-  memset(ny, 0, sizeof(felem));
-  memset(nz, 0, sizeof(felem));
-
-  /* The loop adds bits at positions 0, 64, 128 and 192, followed by
-   * positions 32,96,160 and 224 and does this 32 times. */
-  for (i = 0; i < 32; i++) {
-    if (i) {
-      point_double(nx, ny, nz, nx, ny, nz);
-    }
-    table_offset = 0;
-    for (j = 0; j <= 32; j += 32) {
-      char bit0 = p256_get_bit(scalar, 31 - i + j);
-      char bit1 = p256_get_bit(scalar, 95 - i + j);
-      char bit2 = p256_get_bit(scalar, 159 - i + j);
-      char bit3 = p256_get_bit(scalar, 223 - i + j);
-      limb index = bit0 | (bit1 << 1) | (bit2 << 2) | (bit3 << 3);
-
-      select_affine_point(px, py, kPrecomputed + table_offset, index);
-      table_offset += 30 * NLIMBS;
-
-      /* Since scalar is less than the order of the group, we know that
-       * {nx,ny,nz} != {px,py,1}, unless both are zero, which we handle
-       * below. */
-      point_add_mixed(tx, ty, tz, nx, ny, nz, px, py);
-      /* The result of point_add_mixed is incorrect if {nx,ny,nz} is zero
-       * (a.k.a.  the point at infinity). We handle that situation by
-       * copying the point from the table. */
-      copy_conditional(nx, px, n_is_infinity_mask);
-      copy_conditional(ny, py, n_is_infinity_mask);
-      copy_conditional(nz, kOne, n_is_infinity_mask);
-
-      /* Equally, the result is also wrong if the point from the table is
-       * zero, which happens when the index is zero. We handle that by
-       * only copying from {tx,ty,tz} to {nx,ny,nz} if index != 0. */
-      p_is_noninfinite_mask = NON_ZERO_TO_ALL_ONES(index);
-      mask = p_is_noninfinite_mask & ~n_is_infinity_mask;
-      copy_conditional(nx, tx, mask);
-      copy_conditional(ny, ty, mask);
-      copy_conditional(nz, tz, mask);
-      /* If p was not zero, then n is now non-zero. */
-      n_is_infinity_mask &= ~p_is_noninfinite_mask;
-    }
-  }
-}
-
-/* point_to_affine converts a Jacobian point to an affine point. If the input
- * is the point at infinity then it returns (0, 0) in constant time. */
-static void point_to_affine(felem x_out, felem y_out, const felem nx,
-                            const felem ny, const felem nz) {
-  felem z_inv, z_inv_sq;
-  felem_inv(z_inv, nz);
-  felem_square(z_inv_sq, z_inv);
-  felem_mul(x_out, nx, z_inv_sq);
-  felem_mul(z_inv, z_inv, z_inv_sq);
-  felem_mul(y_out, ny, z_inv);
-}
-
-/* scalar_base_mult sets {nx,ny,nz} = scalar*{x,y}. */
-static void scalar_mult(felem nx, felem ny, felem nz, const felem x,
-                        const felem y, const p256_int* scalar) {
-  int i;
-  felem px, py, pz, tx, ty, tz;
-  felem precomp[16][3];
-  limb n_is_infinity_mask, index, p_is_noninfinite_mask, mask;
-
-  /* We precompute 0,1,2,... times {x,y}. */
-  memset(precomp, 0, sizeof(felem) * 3);
-  memcpy(&precomp[1][0], x, sizeof(felem));
-  memcpy(&precomp[1][1], y, sizeof(felem));
-  memcpy(&precomp[1][2], kOne, sizeof(felem));
-
-  for (i = 2; i < 16; i += 2) {
-    point_double(precomp[i][0], precomp[i][1], precomp[i][2],
-                 precomp[i / 2][0], precomp[i / 2][1], precomp[i / 2][2]);
-
-    point_add_mixed(precomp[i + 1][0], precomp[i + 1][1], precomp[i + 1][2],
-                    precomp[i][0], precomp[i][1], precomp[i][2], x, y);
-  }
-
-  memset(nx, 0, sizeof(felem));
-  memset(ny, 0, sizeof(felem));
-  memset(nz, 0, sizeof(felem));
-  n_is_infinity_mask = -1;
-
-  /* We add in a window of four bits each iteration and do this 64 times. */
-  for (i = 0; i < 256; i += 4) {
-    if (i) {
-      point_double(nx, ny, nz, nx, ny, nz);
-      point_double(nx, ny, nz, nx, ny, nz);
-      point_double(nx, ny, nz, nx, ny, nz);
-      point_double(nx, ny, nz, nx, ny, nz);
-    }
-
-    index = (p256_get_bit(scalar, 255 - i - 0) << 3) |
-            (p256_get_bit(scalar, 255 - i - 1) << 2) |
-            (p256_get_bit(scalar, 255 - i - 2) << 1) |
-            p256_get_bit(scalar, 255 - i - 3);
-
-    /* See the comments in scalar_base_mult about handling infinities. */
-    select_jacobian_point(px, py, pz, precomp[0][0], index);
-    point_add(tx, ty, tz, nx, ny, nz, px, py, pz);
-    copy_conditional(nx, px, n_is_infinity_mask);
-    copy_conditional(ny, py, n_is_infinity_mask);
-    copy_conditional(nz, pz, n_is_infinity_mask);
-
-    p_is_noninfinite_mask = NON_ZERO_TO_ALL_ONES(index);
-    mask = p_is_noninfinite_mask & ~n_is_infinity_mask;
-
-    copy_conditional(nx, tx, mask);
-    copy_conditional(ny, ty, mask);
-    copy_conditional(nz, tz, mask);
-    n_is_infinity_mask &= ~p_is_noninfinite_mask;
-  }
-}
-
-#define kRDigits {2, 0, 0, 0xfffffffe, 0xffffffff, 0xffffffff, 0xfffffffd, 1} // 2^257 mod p256.p
-
-#define kRInvDigits {0x80000000, 1, 0xffffffff, 0, 0x80000001, 0xfffffffe, 1, 0x7fffffff}  // 1 / 2^257 mod p256.p
-
-static const p256_int kR = { kRDigits };
-static const p256_int kRInv = { kRInvDigits };
-
-/* to_montgomery sets out = R*in. */
-static void to_montgomery(felem out, const p256_int* in) {
-  p256_int in_shifted;
-  int i;
-
-  p256_init(&in_shifted);
-  p256_modmul(&SECP256r1_p, in, 0, &kR, &in_shifted);
-
-  for (i = 0; i < NLIMBS; i++) {
-    if ((i & 1) == 0) {
-      out[i] = P256_DIGIT(&in_shifted, 0) & kBottom29Bits;
-      p256_shr(&in_shifted, 29, &in_shifted);
-    } else {
-      out[i] = P256_DIGIT(&in_shifted, 0) & kBottom28Bits;
-      p256_shr(&in_shifted, 28, &in_shifted);
-    }
-  }
-
-  p256_clear(&in_shifted);
-}
-
-/* from_montgomery sets out=in/R. */
-static void from_montgomery(p256_int* out, const felem in) {
-  p256_int result, tmp;
-  int i, top;
-
-  p256_init(&result);
-  p256_init(&tmp);
-
-  p256_add_d(&tmp, in[NLIMBS - 1], &result);
-  for (i = NLIMBS - 2; i >= 0; i--) {
-    if ((i & 1) == 0) {
-      top = p256_shl(&result, 29, &tmp);
-    } else {
-      top = p256_shl(&result, 28, &tmp);
-    }
-    top |= p256_add_d(&tmp, in[i], &result);
-  }
-
-  p256_modmul(&SECP256r1_p, &kRInv, top, &result, out);
-
-  p256_clear(&result);
-  p256_clear(&tmp);
-}
-
-/* p256_base_point_mul sets {out_x,out_y} = nG, where n is < the
- * order of the group. */
-void p256_base_point_mul(const p256_int* n, p256_int* out_x, p256_int* out_y) {
-  felem x, y, z;
-
-  scalar_base_mult(x, y, z, n);
-
-  {
-    felem x_affine, y_affine;
-
-    point_to_affine(x_affine, y_affine, x, y, z);
-    from_montgomery(out_x, x_affine);
-    from_montgomery(out_y, y_affine);
-  }
-}
-
-/* p256_points_mul_vartime sets {out_x,out_y} = n1*G + n2*{in_x,in_y}, where
- * n1 and n2 are < the order of the group.
- *
- * As indicated by the name, this function operates in variable time. This
- * is safe because it's used for signature validation which doesn't deal
- * with secrets. */
-void p256_points_mul_vartime(
-    const p256_int* n1, const p256_int* n2, const p256_int* in_x,
-    const p256_int* in_y, p256_int* out_x, p256_int* out_y) {
-  felem x1, y1, z1, x2, y2, z2, px, py;
-
-  /* If both scalars are zero, then the result is the point at infinity. */
-  if (p256_is_zero(n1) != 0 && p256_is_zero(n2) != 0) {
-    p256_clear(out_x);
-    p256_clear(out_y);
-    return;
-  }
-
-  to_montgomery(px, in_x);
-  to_montgomery(py, in_y);
-  scalar_base_mult(x1, y1, z1, n1);
-  scalar_mult(x2, y2, z2, px, py, n2);
-
-  if (p256_is_zero(n2) != 0) {
-    /* If n2 == 0, then {x2,y2,z2} is zero and the result is just
-         * {x1,y1,z1}. */
-  } else if (p256_is_zero(n1) != 0) {
-    /* If n1 == 0, then {x1,y1,z1} is zero and the result is just
-         * {x2,y2,z2}. */
-    memcpy(x1, x2, sizeof(x2));
-    memcpy(y1, y2, sizeof(y2));
-    memcpy(z1, z2, sizeof(z2));
-  } else {
-    /* This function handles the case where {x1,y1,z1} == {x2,y2,z2}. */
-    point_add_or_double_vartime(x1, y1, z1, x1, y1, z1, x2, y2, z2);
-  }
-
-  point_to_affine(px, py, x1, y1, z1);
-  from_montgomery(out_x, px);
-  from_montgomery(out_y, py);
-}
diff --git a/libmincrypt/p256_ecdsa.c b/libmincrypt/p256_ecdsa.c
deleted file mode 100644
index f2264b0..0000000
--- a/libmincrypt/p256_ecdsa.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * 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.
- *     * Neither the name of Google Inc. nor the names of its contributors may
- *       be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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 <string.h>
-
-#include "mincrypt/p256_ecdsa.h"
-#include "mincrypt/p256.h"
-
-int p256_ecdsa_verify(const p256_int* key_x, const p256_int* key_y,
-                      const p256_int* message,
-                      const p256_int* r, const p256_int* s) {
-  p256_int u, v;
-
-  // Check public key.
-  if (!p256_is_valid_point(key_x, key_y)) return 0;
-
-  // Check r and s are != 0 % n.
-  p256_mod(&SECP256r1_n, r, &u);
-  p256_mod(&SECP256r1_n, s, &v);
-  if (p256_is_zero(&u) || p256_is_zero(&v)) return 0;
-
-  p256_modinv_vartime(&SECP256r1_n, s, &v);
-  p256_modmul(&SECP256r1_n, message, 0, &v, &u);  // message / s % n
-  p256_modmul(&SECP256r1_n, r, 0, &v, &v);  // r / s % n
-
-  p256_points_mul_vartime(&u, &v,
-                          key_x, key_y,
-                          &u, &v);
-
-  p256_mod(&SECP256r1_n, &u, &u);  // (x coord % p) % n
-  return p256_cmp(r, &u) == 0;
-}
-
diff --git a/libmincrypt/rsa.c b/libmincrypt/rsa.c
deleted file mode 100644
index 9061b3a..0000000
--- a/libmincrypt/rsa.c
+++ /dev/null
@@ -1,308 +0,0 @@
-/* rsa.c
-**
-** Copyright 2012, The Android Open Source Project
-**
-** 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.
-**     * Neither the name of Google Inc. nor the names of its contributors may
-**       be used to endorse or promote products derived from this software
-**       without specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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 "mincrypt/rsa.h"
-#include "mincrypt/sha.h"
-#include "mincrypt/sha256.h"
-
-// a[] -= mod
-static void subM(const RSAPublicKey* key,
-                 uint32_t* a) {
-    int64_t A = 0;
-    int i;
-    for (i = 0; i < key->len; ++i) {
-        A += (uint64_t)a[i] - key->n[i];
-        a[i] = (uint32_t)A;
-        A >>= 32;
-    }
-}
-
-// return a[] >= mod
-static int geM(const RSAPublicKey* key,
-               const uint32_t* a) {
-    int i;
-    for (i = key->len; i;) {
-        --i;
-        if (a[i] < key->n[i]) return 0;
-        if (a[i] > key->n[i]) return 1;
-    }
-    return 1;  // equal
-}
-
-// montgomery c[] += a * b[] / R % mod
-static void montMulAdd(const RSAPublicKey* key,
-                       uint32_t* c,
-                       const uint32_t a,
-                       const uint32_t* b) {
-    uint64_t A = (uint64_t)a * b[0] + c[0];
-    uint32_t d0 = (uint32_t)A * key->n0inv;
-    uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A;
-    int i;
-
-    for (i = 1; i < key->len; ++i) {
-        A = (A >> 32) + (uint64_t)a * b[i] + c[i];
-        B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A;
-        c[i - 1] = (uint32_t)B;
-    }
-
-    A = (A >> 32) + (B >> 32);
-
-    c[i - 1] = (uint32_t)A;
-
-    if (A >> 32) {
-        subM(key, c);
-    }
-}
-
-// montgomery c[] = a[] * b[] / R % mod
-static void montMul(const RSAPublicKey* key,
-                    uint32_t* c,
-                    const uint32_t* a,
-                    const uint32_t* b) {
-    int i;
-    for (i = 0; i < key->len; ++i) {
-        c[i] = 0;
-    }
-    for (i = 0; i < key->len; ++i) {
-        montMulAdd(key, c, a[i], b);
-    }
-}
-
-// In-place public exponentiation.
-// Input and output big-endian byte array in inout.
-static void modpow(const RSAPublicKey* key,
-                   uint8_t* inout) {
-    uint32_t a[RSANUMWORDS];
-    uint32_t aR[RSANUMWORDS];
-    uint32_t aaR[RSANUMWORDS];
-    uint32_t* aaa = 0;
-    int i;
-
-    // Convert from big endian byte array to little endian word array.
-    for (i = 0; i < key->len; ++i) {
-        uint32_t tmp =
-            (inout[((key->len - 1 - i) * 4) + 0] << 24) |
-            (inout[((key->len - 1 - i) * 4) + 1] << 16) |
-            (inout[((key->len - 1 - i) * 4) + 2] << 8) |
-            (inout[((key->len - 1 - i) * 4) + 3] << 0);
-        a[i] = tmp;
-    }
-
-    if (key->exponent == 65537) {
-        aaa = aaR;  // Re-use location.
-        montMul(key, aR, a, key->rr);  // aR = a * RR / R mod M
-        for (i = 0; i < 16; i += 2) {
-            montMul(key, aaR, aR, aR);  // aaR = aR * aR / R mod M
-            montMul(key, aR, aaR, aaR);  // aR = aaR * aaR / R mod M
-        }
-        montMul(key, aaa, aR, a);  // aaa = aR * a / R mod M
-    } else if (key->exponent == 3) {
-        aaa = aR;  // Re-use location.
-        montMul(key, aR, a, key->rr);  /* aR = a * RR / R mod M   */
-        montMul(key, aaR, aR, aR);     /* aaR = aR * aR / R mod M */
-        montMul(key, aaa, aaR, a);     /* aaa = aaR * a / R mod M */
-    }
-
-    // Make sure aaa < mod; aaa is at most 1x mod too large.
-    if (geM(key, aaa)) {
-        subM(key, aaa);
-    }
-
-    // Convert to bigendian byte array
-    for (i = key->len - 1; i >= 0; --i) {
-        uint32_t tmp = aaa[i];
-        *inout++ = tmp >> 24;
-        *inout++ = tmp >> 16;
-        *inout++ = tmp >> 8;
-        *inout++ = tmp >> 0;
-    }
-}
-
-// Expected PKCS1.5 signature padding bytes, for a keytool RSA signature.
-// Has the 0-length optional parameter encoded in the ASN1 (as opposed to the
-// other flavor which omits the optional parameter entirely). This code does not
-// accept signatures without the optional parameter.
-
-/*
-static const uint8_t sha_padding[RSANUMBYTES] = {
-    0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x21, 0x30,
-    0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a,
-    0x05, 0x00, 0x04, 0x14,
-
-    // 20 bytes of hash go here.
-    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-};
-*/
-
-// SHA-1 of PKCS1.5 signature sha_padding for 2048 bit, as above.
-// At the location of the bytes of the hash all 00 are hashed.
-static const uint8_t kExpectedPadShaRsa2048[SHA_DIGEST_SIZE] = {
-    0xdc, 0xbd, 0xbe, 0x42, 0xd5, 0xf5, 0xa7, 0x2e,
-    0x6e, 0xfc, 0xf5, 0x5d, 0xaf, 0x9d, 0xea, 0x68,
-    0x7c, 0xfb, 0xf1, 0x67
-};
-
-/*
-static const uint8_t sha256_padding[RSANUMBYTES] = {
-    0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x31, 0x30,
-    0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
-    0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20,
-
-    // 32 bytes of hash go here.
-    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-};
-*/
-
-// SHA-256 of PKCS1.5 signature sha256_padding for 2048 bit, as above.
-// At the location of the bytes of the hash all 00 are hashed.
-static const uint8_t kExpectedPadSha256Rsa2048[SHA256_DIGEST_SIZE] = {
-    0xab, 0x28, 0x8d, 0x8a, 0xd7, 0xd9, 0x59, 0x92,
-    0xba, 0xcc, 0xf8, 0x67, 0x20, 0xe1, 0x15, 0x2e,
-    0x39, 0x8d, 0x80, 0x36, 0xd6, 0x6f, 0xf0, 0xfd,
-    0x90, 0xe8, 0x7d, 0x8b, 0xe1, 0x7c, 0x87, 0x59,
-};
-
-// Verify a 2048-bit RSA PKCS1.5 signature against an expected hash.
-// Both e=3 and e=65537 are supported.  hash_len may be
-// SHA_DIGEST_SIZE (== 20) to indicate a SHA-1 hash, or
-// SHA256_DIGEST_SIZE (== 32) to indicate a SHA-256 hash.  No other
-// values are supported.
-//
-// Returns 1 on successful verification, 0 on failure.
-int RSA_verify(const RSAPublicKey *key,
-               const uint8_t *signature,
-               const int len,
-               const uint8_t *hash,
-               const int hash_len) {
-    uint8_t buf[RSANUMBYTES];
-    int i;
-    const uint8_t* padding_hash;
-
-    if (key->len != RSANUMWORDS) {
-        return 0;  // Wrong key passed in.
-    }
-
-    if (len != sizeof(buf)) {
-        return 0;  // Wrong input length.
-    }
-
-    if (hash_len != SHA_DIGEST_SIZE &&
-        hash_len != SHA256_DIGEST_SIZE) {
-        return 0;  // Unsupported hash.
-    }
-
-    if (key->exponent != 3 && key->exponent != 65537) {
-        return 0;  // Unsupported exponent.
-    }
-
-    for (i = 0; i < len; ++i) {  // Copy input to local workspace.
-        buf[i] = signature[i];
-    }
-
-    modpow(key, buf);  // In-place exponentiation.
-
-    // Xor sha portion, so it all becomes 00 iff equal.
-    for (i = len - hash_len; i < len; ++i) {
-        buf[i] ^= *hash++;
-    }
-
-    // Hash resulting buf, in-place.
-    switch (hash_len) {
-        case SHA_DIGEST_SIZE:
-            padding_hash = kExpectedPadShaRsa2048;
-            SHA_hash(buf, len, buf);
-            break;
-        case SHA256_DIGEST_SIZE:
-            padding_hash = kExpectedPadSha256Rsa2048;
-            SHA256_hash(buf, len, buf);
-            break;
-        default:
-            return 0;
-    }
-
-    // Compare against expected hash value.
-    for (i = 0; i < hash_len; ++i) {
-        if (buf[i] != padding_hash[i]) {
-            return 0;
-        }
-    }
-
-    return 1;  // All checked out OK.
-}
diff --git a/libmincrypt/sha.c b/libmincrypt/sha.c
deleted file mode 100644
index 5bef32e..0000000
--- a/libmincrypt/sha.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/* sha.c
-**
-** Copyright 2013, The Android Open Source Project
-**
-** 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.
-**     * Neither the name of Google Inc. nor the names of its contributors may
-**       be used to endorse or promote products derived from this software
-**       without specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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.
-*/
-
-// Optimized for minimal code size.
-
-#include "mincrypt/sha.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-
-#define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits))))
-
-static void SHA1_Transform(SHA_CTX* ctx) {
-    uint32_t W[80];
-    uint32_t A, B, C, D, E;
-    uint8_t* p = ctx->buf;
-    int t;
-
-    for(t = 0; t < 16; ++t) {
-        uint32_t tmp =  *p++ << 24;
-        tmp |= *p++ << 16;
-        tmp |= *p++ << 8;
-        tmp |= *p++;
-        W[t] = tmp;
-    }
-
-    for(; t < 80; t++) {
-        W[t] = rol(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
-    }
-
-    A = ctx->state[0];
-    B = ctx->state[1];
-    C = ctx->state[2];
-    D = ctx->state[3];
-    E = ctx->state[4];
-
-    for(t = 0; t < 80; t++) {
-        uint32_t tmp = rol(5,A) + E + W[t];
-
-        if (t < 20)
-            tmp += (D^(B&(C^D))) + 0x5A827999;
-        else if ( t < 40)
-            tmp += (B^C^D) + 0x6ED9EBA1;
-        else if ( t < 60)
-            tmp += ((B&C)|(D&(B|C))) + 0x8F1BBCDC;
-        else
-            tmp += (B^C^D) + 0xCA62C1D6;
-
-        E = D;
-        D = C;
-        C = rol(30,B);
-        B = A;
-        A = tmp;
-    }
-
-    ctx->state[0] += A;
-    ctx->state[1] += B;
-    ctx->state[2] += C;
-    ctx->state[3] += D;
-    ctx->state[4] += E;
-}
-
-static const HASH_VTAB SHA_VTAB = {
-    SHA_init,
-    SHA_update,
-    SHA_final,
-    SHA_hash,
-    SHA_DIGEST_SIZE
-};
-
-void SHA_init(SHA_CTX* ctx) {
-    ctx->f = &SHA_VTAB;
-    ctx->state[0] = 0x67452301;
-    ctx->state[1] = 0xEFCDAB89;
-    ctx->state[2] = 0x98BADCFE;
-    ctx->state[3] = 0x10325476;
-    ctx->state[4] = 0xC3D2E1F0;
-    ctx->count = 0;
-}
-
-
-void SHA_update(SHA_CTX* ctx, const void* data, int len) {
-    int i = (int) (ctx->count & 63);
-    const uint8_t* p = (const uint8_t*)data;
-
-    ctx->count += len;
-
-    while (len--) {
-        ctx->buf[i++] = *p++;
-        if (i == 64) {
-            SHA1_Transform(ctx);
-            i = 0;
-        }
-    }
-}
-
-
-const uint8_t* SHA_final(SHA_CTX* ctx) {
-    uint8_t *p = ctx->buf;
-    uint64_t cnt = ctx->count * 8;
-    int i;
-
-    SHA_update(ctx, (uint8_t*)"\x80", 1);
-    while ((ctx->count & 63) != 56) {
-        SHA_update(ctx, (uint8_t*)"\0", 1);
-    }
-    for (i = 0; i < 8; ++i) {
-        uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8));
-        SHA_update(ctx, &tmp, 1);
-    }
-
-    for (i = 0; i < 5; i++) {
-        uint32_t tmp = ctx->state[i];
-        *p++ = tmp >> 24;
-        *p++ = tmp >> 16;
-        *p++ = tmp >> 8;
-        *p++ = tmp >> 0;
-    }
-
-    return ctx->buf;
-}
-
-/* Convenience function */
-const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest) {
-    SHA_CTX ctx;
-    SHA_init(&ctx);
-    SHA_update(&ctx, data, len);
-    memcpy(digest, SHA_final(&ctx), SHA_DIGEST_SIZE);
-    return digest;
-}
diff --git a/libmincrypt/sha256.c b/libmincrypt/sha256.c
deleted file mode 100644
index eb6e308..0000000
--- a/libmincrypt/sha256.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/* sha256.c
-**
-** Copyright 2013, The Android Open Source Project
-**
-** 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.
-**     * Neither the name of Google Inc. nor the names of its contributors may
-**       be used to endorse or promote products derived from this software
-**       without specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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.
-*/
-
-// Optimized for minimal code size.
-
-#include "mincrypt/sha256.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-
-#define ror(value, bits) (((value) >> (bits)) | ((value) << (32 - (bits))))
-#define shr(value, bits) ((value) >> (bits))
-
-static const uint32_t K[64] = {
-    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
-    0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
-    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
-    0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
-    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
-    0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
-    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
-    0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
-    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
-    0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
-    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
-    0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
-    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
-    0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
-    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
-    0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 };
-
-static void SHA256_Transform(SHA256_CTX* ctx) {
-    uint32_t W[64];
-    uint32_t A, B, C, D, E, F, G, H;
-    uint8_t* p = ctx->buf;
-    int t;
-
-    for(t = 0; t < 16; ++t) {
-        uint32_t tmp =  *p++ << 24;
-        tmp |= *p++ << 16;
-        tmp |= *p++ << 8;
-        tmp |= *p++;
-        W[t] = tmp;
-    }
-
-    for(; t < 64; t++) {
-        uint32_t s0 = ror(W[t-15], 7) ^ ror(W[t-15], 18) ^ shr(W[t-15], 3);
-        uint32_t s1 = ror(W[t-2], 17) ^ ror(W[t-2], 19) ^ shr(W[t-2], 10);
-        W[t] = W[t-16] + s0 + W[t-7] + s1;
-    }
-
-    A = ctx->state[0];
-    B = ctx->state[1];
-    C = ctx->state[2];
-    D = ctx->state[3];
-    E = ctx->state[4];
-    F = ctx->state[5];
-    G = ctx->state[6];
-    H = ctx->state[7];
-
-    for(t = 0; t < 64; t++) {
-        uint32_t s0 = ror(A, 2) ^ ror(A, 13) ^ ror(A, 22);
-        uint32_t maj = (A & B) ^ (A & C) ^ (B & C);
-        uint32_t t2 = s0 + maj;
-        uint32_t s1 = ror(E, 6) ^ ror(E, 11) ^ ror(E, 25);
-        uint32_t ch = (E & F) ^ ((~E) & G);
-        uint32_t t1 = H + s1 + ch + K[t] + W[t];
-
-        H = G;
-        G = F;
-        F = E;
-        E = D + t1;
-        D = C;
-        C = B;
-        B = A;
-        A = t1 + t2;
-    }
-
-    ctx->state[0] += A;
-    ctx->state[1] += B;
-    ctx->state[2] += C;
-    ctx->state[3] += D;
-    ctx->state[4] += E;
-    ctx->state[5] += F;
-    ctx->state[6] += G;
-    ctx->state[7] += H;
-}
-
-static const HASH_VTAB SHA256_VTAB = {
-    SHA256_init,
-    SHA256_update,
-    SHA256_final,
-    SHA256_hash,
-    SHA256_DIGEST_SIZE
-};
-
-void SHA256_init(SHA256_CTX* ctx) {
-    ctx->f = &SHA256_VTAB;
-    ctx->state[0] = 0x6a09e667;
-    ctx->state[1] = 0xbb67ae85;
-    ctx->state[2] = 0x3c6ef372;
-    ctx->state[3] = 0xa54ff53a;
-    ctx->state[4] = 0x510e527f;
-    ctx->state[5] = 0x9b05688c;
-    ctx->state[6] = 0x1f83d9ab;
-    ctx->state[7] = 0x5be0cd19;
-    ctx->count = 0;
-}
-
-
-void SHA256_update(SHA256_CTX* ctx, const void* data, int len) {
-    int i = (int) (ctx->count & 63);
-    const uint8_t* p = (const uint8_t*)data;
-
-    ctx->count += len;
-
-    while (len--) {
-        ctx->buf[i++] = *p++;
-        if (i == 64) {
-            SHA256_Transform(ctx);
-            i = 0;
-        }
-    }
-}
-
-
-const uint8_t* SHA256_final(SHA256_CTX* ctx) {
-    uint8_t *p = ctx->buf;
-    uint64_t cnt = ctx->count * 8;
-    int i;
-
-    SHA256_update(ctx, (uint8_t*)"\x80", 1);
-    while ((ctx->count & 63) != 56) {
-        SHA256_update(ctx, (uint8_t*)"\0", 1);
-    }
-    for (i = 0; i < 8; ++i) {
-        uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8));
-        SHA256_update(ctx, &tmp, 1);
-    }
-
-    for (i = 0; i < 8; i++) {
-        uint32_t tmp = ctx->state[i];
-        *p++ = tmp >> 24;
-        *p++ = tmp >> 16;
-        *p++ = tmp >> 8;
-        *p++ = tmp >> 0;
-    }
-
-    return ctx->buf;
-}
-
-/* Convenience function */
-const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest) {
-    SHA256_CTX ctx;
-    SHA256_init(&ctx);
-    SHA256_update(&ctx, data, len);
-    memcpy(digest, SHA256_final(&ctx), SHA256_DIGEST_SIZE);
-    return digest;
-}
diff --git a/libmincrypt/test/Android.mk b/libmincrypt/test/Android.mk
deleted file mode 100644
index 73ff7d0..0000000
--- a/libmincrypt/test/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2013 The Android Open Source Project
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := rsa_test
-LOCAL_SRC_FILES := rsa_test.c
-LOCAL_STATIC_LIBRARIES := libmincrypt
-include $(BUILD_HOST_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := ecdsa_test
-LOCAL_SRC_FILES := ecdsa_test.c
-LOCAL_STATIC_LIBRARIES := libmincrypt
-include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libmincrypt/test/ecdsa_test.c b/libmincrypt/test/ecdsa_test.c
deleted file mode 100644
index 24ec013..0000000
--- a/libmincrypt/test/ecdsa_test.c
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * 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.
- *     * Neither the name of Google Inc. nor the names of its contributors may
- *       be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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 <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/cdefs.h>
-
-#include "mincrypt/dsa_sig.h"
-#include "mincrypt/p256.h"
-#include "mincrypt/p256_ecdsa.h"
-#include "mincrypt/sha256.h"
-
-#ifndef __unused
-#define __unused __attribute__((__unused__))
-#endif
-
-/**
- * Messages signed using:
- *
------BEGIN EC PRIVATE KEY-----
-MHcCAQEEIDw6UiziVMbjlfSpOAIpA2tcL+v1OlznZLnpadO8BGi1oAoGCCqGSM49
-AwEHoUQDQgAEZw7VAOjAXYRFuhZWYBgjahdOvkwcAnjGkxQWytZW+iS1hI3ZGE24
-6XmNka9IGxAgj2n/ip+MuZJMFoJ9DRea3g==
------END EC PRIVATE KEY-----
- */
-
-p256_int key_x = {
-    .a = {0xd656fa24u, 0x931416cau, 0x1c0278c6u, 0x174ebe4cu,
-          0x6018236au, 0x45ba1656u, 0xe8c05d84u, 0x670ed500u}
-};
-p256_int key_y = {
-    .a = {0x0d179adeu, 0x4c16827du, 0x9f8cb992u, 0x8f69ff8au,
-          0x481b1020u, 0x798d91afu, 0x184db8e9u, 0xb5848dd9u}
-};
-
-char* message_1 =
-    "f4 5d 55 f3 55 51 e9 75 d6 a8 dc 7e a9 f4 88 59"
-    "39 40 cc 75 69 4a 27 8f 27 e5 78 a1 63 d8 39 b3"
-    "40 40 84 18 08 cf 9c 58 c9 b8 72 8b f5 f9 ce 8e"
-    "e8 11 ea 91 71 4f 47 ba b9 2d 0f 6d 5a 26 fc fe"
-    "ea 6c d9 3b 91 0c 0a 2c 96 3e 64 eb 18 23 f1 02"
-    "75 3d 41 f0 33 59 10 ad 3a 97 71 04 f1 aa f6 c3"
-    "74 27 16 a9 75 5d 11 b8 ee d6 90 47 7f 44 5c 5d"
-    "27 20 8b 2e 28 43 30 fa 3d 30 14 23 fa 7f 2d 08"
-    "6e 0a d0 b8 92 b9 db 54 4e 45 6d 3f 0d ab 85 d9"
-    "53 c1 2d 34 0a a8 73 ed a7 27 c8 a6 49 db 7f a6"
-    "37 40 e2 5e 9a f1 53 3b 30 7e 61 32 99 93 11 0e"
-    "95 19 4e 03 93 99 c3 82 4d 24 c5 1f 22 b2 6b de"
-    "10 24 cd 39 59 58 a2 df eb 48 16 a6 e8 ad ed b5"
-    "0b 1f 6b 56 d0 b3 06 0f f0 f1 c4 cb 0d 0e 00 1d"
-    "d5 9d 73 be 12";
-
-char* signature_1 =
-    "30 44 02 20 43 18 fc eb 3b a8 3a a8 a3 cf 41 b7"
-    "81 4a f9 01 e1 8b 6e 95 c1 3a 83 25 9e a5 2e 66"
-    "7c 98 25 d9 02 20 54 f3 7f 5a e9 36 9c a2 f0 51"
-    "e0 6e 78 48 60 a3 f9 8a d5 2c 37 5a 0a 29 c9 f7"
-    "ea 57 7e 88 46 12";
-
-// Same as signature 1, but with leading zeroes.
-char* message_2 =
-    "f4 5d 55 f3 55 51 e9 75 d6 a8 dc 7e a9 f4 88 59"
-    "39 40 cc 75 69 4a 27 8f 27 e5 78 a1 63 d8 39 b3"
-    "40 40 84 18 08 cf 9c 58 c9 b8 72 8b f5 f9 ce 8e"
-    "e8 11 ea 91 71 4f 47 ba b9 2d 0f 6d 5a 26 fc fe"
-    "ea 6c d9 3b 91 0c 0a 2c 96 3e 64 eb 18 23 f1 02"
-    "75 3d 41 f0 33 59 10 ad 3a 97 71 04 f1 aa f6 c3"
-    "74 27 16 a9 75 5d 11 b8 ee d6 90 47 7f 44 5c 5d"
-    "27 20 8b 2e 28 43 30 fa 3d 30 14 23 fa 7f 2d 08"
-    "6e 0a d0 b8 92 b9 db 54 4e 45 6d 3f 0d ab 85 d9"
-    "53 c1 2d 34 0a a8 73 ed a7 27 c8 a6 49 db 7f a6"
-    "37 40 e2 5e 9a f1 53 3b 30 7e 61 32 99 93 11 0e"
-    "95 19 4e 03 93 99 c3 82 4d 24 c5 1f 22 b2 6b de"
-    "10 24 cd 39 59 58 a2 df eb 48 16 a6 e8 ad ed b5"
-    "0b 1f 6b 56 d0 b3 06 0f f0 f1 c4 cb 0d 0e 00 1d"
-    "d5 9d 73 be 12";
-
-char* signature_2 =
-    "30 46 02 21 00 43 18 fc eb 3b a8 3a a8 a3 cf 41 b7"
-    "81 4a f9 01 e1 8b 6e 95 c1 3a 83 25 9e a5 2e 66"
-    "7c 98 25 d9 02 21 00 54 f3 7f 5a e9 36 9c a2 f0 51"
-    "e0 6e 78 48 60 a3 f9 8a d5 2c 37 5a 0a 29 c9 f7"
-    "ea 57 7e 88 46 12";
-
-// Excessive zeroes on the signature
-char* message_3 =
-    "f4 5d 55 f3 55 51 e9 75 d6 a8 dc 7e a9 f4 88 59"
-    "39 40 cc 75 69 4a 27 8f 27 e5 78 a1 63 d8 39 b3"
-    "40 40 84 18 08 cf 9c 58 c9 b8 72 8b f5 f9 ce 8e"
-    "e8 11 ea 91 71 4f 47 ba b9 2d 0f 6d 5a 26 fc fe"
-    "ea 6c d9 3b 91 0c 0a 2c 96 3e 64 eb 18 23 f1 02"
-    "75 3d 41 f0 33 59 10 ad 3a 97 71 04 f1 aa f6 c3"
-    "74 27 16 a9 75 5d 11 b8 ee d6 90 47 7f 44 5c 5d"
-    "27 20 8b 2e 28 43 30 fa 3d 30 14 23 fa 7f 2d 08"
-    "6e 0a d0 b8 92 b9 db 54 4e 45 6d 3f 0d ab 85 d9"
-    "53 c1 2d 34 0a a8 73 ed a7 27 c8 a6 49 db 7f a6"
-    "37 40 e2 5e 9a f1 53 3b 30 7e 61 32 99 93 11 0e"
-    "95 19 4e 03 93 99 c3 82 4d 24 c5 1f 22 b2 6b de"
-    "10 24 cd 39 59 58 a2 df eb 48 16 a6 e8 ad ed b5"
-    "0b 1f 6b 56 d0 b3 06 0f f0 f1 c4 cb 0d 0e 00 1d"
-    "d5 9d 73 be 12";
-
-char* signature_3 =
-    "30 4c 02 24 00 00 00 00 43 18 fc eb 3b a8 3a a8 a3 cf 41 b7"
-    "81 4a f9 01 e1 8b 6e 95 c1 3a 83 25 9e a5 2e 66"
-    "7c 98 25 d9 02 24 00 00 00 00 54 f3 7f 5a e9 36 9c a2 f0 51"
-    "e0 6e 78 48 60 a3 f9 8a d5 2c 37 5a 0a 29 c9 f7"
-    "ea 57 7e 88 46 12";
-
-
-char* good_dsa_signature_1 =
-    "30 0D 02 01 01 02 08 00 A5 55 5A 01 FF A5 01";
-p256_int good_dsa_signature_1_r = {
-    .a = {0x00000001U, 0x00000000U, 0x00000000U, 0x00000000U,
-          0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U}
-};
-p256_int good_dsa_signature_1_s = {
-    .a = {0x01FFA501U, 0x00A5555AU, 0x00000000U, 0x00000000U,
-          0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U}
-};
-
-
-char* bad_dsa_signature_1 =
-     "a0 06 02 01 01 02 01 01";
-
-char* bad_dsa_signature_2 =
-     "30 07 02 01 01 02 01 01";
-
-char* bad_dsa_signature_3 =
-     "30 06 82 01 01 02 01 01";
-
-char* bad_dsa_signature_4 =
-     "30 06 02 00 01 02 01 01";
-
-char* bad_dsa_signature_5 =
-     "30 06 02 01 01 82 01 01";
-
-char* bad_dsa_signature_6 =
-     "30 05 02 01 01 02 00";
-
-char* bad_dsa_signature_7 =
-     "30 06 02 01 01 02 00 01";
-
-unsigned char* parsehex(char* str, int* len) {
-    // result can't be longer than input
-    unsigned char* result = malloc(strlen(str));
-
-    unsigned char* p = result;
-    *len = 0;
-
-    while (*str) {
-        int b;
-
-        while (isspace(*str)) str++;
-
-        switch (*str) {
-            case '0': case '1': case '2': case '3': case '4':
-            case '5': case '6': case '7': case '8': case '9':
-                b = (*str - '0') << 4; break;
-            case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
-                b = (*str - 'a' + 10) << 4; break;
-            case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
-                b = (*str - 'A' + 10) << 4; break;
-            case '\0':
-                return result;
-            default:
-                return NULL;
-        }
-        str++;
-
-        while (isspace(*str)) str++;
-
-        switch (*str) {
-            case '0': case '1': case '2': case '3': case '4':
-            case '5': case '6': case '7': case '8': case '9':
-                b |= *str - '0'; break;
-            case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
-                b |= *str - 'a' + 10; break;
-            case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
-                b |= *str - 'A' + 10; break;
-            default:
-                return NULL;
-        }
-        str++;
-
-        *p++ = b;
-        ++*len;
-    }
-
-    return result;
-}
-
-int main(int arg __unused, char** argv __unused) {
-
-    unsigned char hash_buf[SHA256_DIGEST_SIZE];
-
-    unsigned char* message;
-    int mlen;
-    unsigned char* signature;
-    int slen;
-
-    p256_int hash;
-    p256_int r;
-    p256_int s;
-
-    int success = 1;
-
-#define CHECK_DSA_SIG(sig, good) do {\
-    message = parsehex(sig, &mlen); \
-    int result = dsa_sig_unpack(message, mlen, &r, &s); \
-    printf(#sig ": %s\n", result ? "good" : "bad"); \
-    success = success && !(good ^ result); \
-    free(message); \
-    } while(0)
-#define CHECK_GOOD_DSA_SIG(n) do {\
-    CHECK_DSA_SIG(good_dsa_signature_##n, 1); \
-    int result = !memcmp(P256_DIGITS(&good_dsa_signature_##n##_r), P256_DIGITS(&r), \
-                         P256_NBYTES); \
-    success = success && result; \
-    printf("    R value %s\n", result ? "good" : "bad"); \
-    result = !memcmp(P256_DIGITS(&good_dsa_signature_##n##_s), P256_DIGITS(&s), \
-                    P256_NBYTES); \
-    success = success && result; \
-    printf("    S value %s\n", result ? "good" : "bad"); \
-    } while (0)
-#define CHECK_BAD_DSA_SIG(n) \
-    CHECK_DSA_SIG(bad_dsa_signature_##n, 0)
-
-    CHECK_GOOD_DSA_SIG(1);
-
-    CHECK_BAD_DSA_SIG(1);
-    CHECK_BAD_DSA_SIG(2);
-    CHECK_BAD_DSA_SIG(3);
-    CHECK_BAD_DSA_SIG(4);
-    CHECK_BAD_DSA_SIG(5);
-    CHECK_BAD_DSA_SIG(6);
-    CHECK_BAD_DSA_SIG(7);
-
-
-#define TEST_MESSAGE(n) do {\
-    message = parsehex(message_##n, &mlen); \
-    SHA256_hash(message, mlen, hash_buf); \
-    p256_from_bin(hash_buf, &hash); \
-    signature = parsehex(signature_##n, &slen); \
-    int result = dsa_sig_unpack(signature, slen, &r, &s); \
-    if (result) { result = p256_ecdsa_verify(&key_x, &key_y, &hash, &r, &s); } \
-    printf("message %d: %s\n", n, result ? "verified" : "not verified"); \
-    success = success && result; \
-    free(signature); \
-    } while(0)
-
-    TEST_MESSAGE(1);
-    TEST_MESSAGE(2);
-    TEST_MESSAGE(3);
-
-    printf("\n%s\n\n", success ? "PASS" : "FAIL");
-
-    return !success;
-}
diff --git a/libmincrypt/test/rsa_test.c b/libmincrypt/test/rsa_test.c
deleted file mode 100644
index 055138f..0000000
--- a/libmincrypt/test/rsa_test.c
+++ /dev/null
@@ -1,842 +0,0 @@
-/*
-** Copyright 2013, The Android Open Source Project
-**
-** 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.
-**     * Neither the name of Google Inc. nor the names of its contributors may
-**       be used to endorse or promote products derived from this software
-**       without specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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 <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/cdefs.h>
-
-#include "mincrypt/rsa.h"
-#include "mincrypt/sha.h"
-
-#ifndef __unused
-#define __unused __attribute__((unused))
-#endif
-
-// RSA test data taken from:
-//
-//   ftp://ftp.rsa.com/pub/rsalabs/tmp/pkcs1v15sign-vectors.txt
-
-// This is the result (reformatted) of running DumpPublicKey on:
-//
-//   # Example 15: A 2048-bit RSA key pair
-//   # -----------------------------------
-//
-//
-//   # Public key
-//   # ----------
-//
-//   # Modulus:
-//   df 27 1f d2 5f 86 44 49 6b 0c 81 be 4b d5 02 97
-//   ef 09 9b 00 2a 6f d6 77 27 eb 44 9c ea 56 6e d6
-//   a3 98 1a 71 31 2a 14 1c ab c9 81 5c 12 09 e3 20
-//   a2 5b 32 46 4e 99 99 f1 8c a1 3a 9f d3 89 25 58
-//   f9 e0 ad ef dd 36 50 dd 23 a3 f0 36 d6 0f e3 98
-//   84 37 06 a4 0b 0b 84 62 c8 be e3 bc e1 2f 1f 28
-//   60 c2 44 4c dc 6a 44 47 6a 75 ff 4a a2 42 73 cc
-//   be 3b f8 02 48 46 5f 8f f8 c3 a7 f3 36 7d fc 0d
-//   f5 b6 50 9a 4f 82 81 1c ed d8 1c da aa 73 c4 91
-//   da 41 21 70 d5 44 d4 ba 96 b9 7f 0a fc 80 65 49
-//   8d 3a 49 fd 91 09 92 a1 f0 72 5b e2 4f 46 5c fe
-//   7e 0e ab f6 78 99 6c 50 bc 5e 75 24 ab f7 3f 15
-//   e5 be f7 d5 18 39 4e 31 38 ce 49 44 50 6a aa af
-//   3f 9b 23 6d ca b8 fc 00 f8 7a f5 96 fd c3 d9 d6
-//   c7 5c d5 08 36 2f ae 2c be dd cc 4c 74 50 b1 7b
-//   77 6c 07 9e cc a1 f2 56 35 1a 43 b9 7d be 21 53
-//
-//   # Exponent:
-//   01 00 01
-
-RSAPublicKey key_15 = {
-    .len = 64,
-    .n0inv = 0xf0053525,
-    .n = {2109612371u,890913721u,3433165398u,2003568542u,
-          1951445371u,3202206796u,909094444u,3344749832u,
-          4257470934u,4168807830u,3401120768u,1067131757u,
-          1349167791u,953043268u,406408753u,3854497749u,
-          2885107477u,3160306980u,2023320656u,2114890742u,
-          1330011390u,4034026466u,2433323681u,2369407485u,
-          4236272969u,2528739082u,3578057914u,3661701488u,
-          2859713681u,3990363354u,1333952796u,4122366106u,
-          914226189u,4173572083u,1212571535u,3191601154u,
-          2722264012u,1786117962u,3697951815u,1623344204u,
-          3777961768u,3367953340u,185304162u,2218198692u,
-          3591365528u,597946422u,3711324381u,4192251375u,
-          3548980568u,2359376543u,1318689265u,2723885638u,
-          302637856u,2882109788u,824841244u,2744654449u,
-          3931533014u,669729948u,711972471u,4010384128u,
-          1272251031u,1795981758u,1602634825u,3743883218u},
-    .rr = {820482522u,2494434288u,1082168230u,731376296u,
-           1306039452u,3139792975u,2575869288u,3874938710u,
-           3198185181u,153506080u,1236489694u,1061859740u,
-           1174461268u,115279508u,1782749185u,238124145u,
-           3587596076u,2259236093u,1112265915u,4048059865u,
-           3890381098u,999426242u,794481771u,3804065613u,
-           2786019148u,461403875u,3072256692u,4079652654u,
-           3056719901u,1871565394u,212974856u,3359008174u,
-           1397773937u,3796256698u,914342841u,1097174457u,
-           3322220191u,3170814748u,2439215020u,618719336u,
-           3629353460u,496817177u,317052742u,380264245u,
-           1976007217u,2697736152u,312540864u,4291855337u,
-           697006561u,4234182488u,3904590917u,2609582216u,
-           451424084u,1805773827u,776344974u,1064489733u,
-           2633377036u,1954826648u,3202815814u,2240368662u,
-           2618582484u,2211196815u,4107362845u,3640258615u},
-    .exponent = 65537,
-};
-
-// PKCS#1 v1.5 Signature Example 15.1
-
-char* message_1 =
-    "f4 5d 55 f3 55 51 e9 75 d6 a8 dc 7e a9 f4 88 59"
-    "39 40 cc 75 69 4a 27 8f 27 e5 78 a1 63 d8 39 b3"
-    "40 40 84 18 08 cf 9c 58 c9 b8 72 8b f5 f9 ce 8e"
-    "e8 11 ea 91 71 4f 47 ba b9 2d 0f 6d 5a 26 fc fe"
-    "ea 6c d9 3b 91 0c 0a 2c 96 3e 64 eb 18 23 f1 02"
-    "75 3d 41 f0 33 59 10 ad 3a 97 71 04 f1 aa f6 c3"
-    "74 27 16 a9 75 5d 11 b8 ee d6 90 47 7f 44 5c 5d"
-    "27 20 8b 2e 28 43 30 fa 3d 30 14 23 fa 7f 2d 08"
-    "6e 0a d0 b8 92 b9 db 54 4e 45 6d 3f 0d ab 85 d9"
-    "53 c1 2d 34 0a a8 73 ed a7 27 c8 a6 49 db 7f a6"
-    "37 40 e2 5e 9a f1 53 3b 30 7e 61 32 99 93 11 0e"
-    "95 19 4e 03 93 99 c3 82 4d 24 c5 1f 22 b2 6b de"
-    "10 24 cd 39 59 58 a2 df eb 48 16 a6 e8 ad ed b5"
-    "0b 1f 6b 56 d0 b3 06 0f f0 f1 c4 cb 0d 0e 00 1d"
-    "d5 9d 73 be 12";
-
-char* signature_1 =
-    "b7 5a 54 66 b6 5d 0f 30 0e f5 38 33 f2 17 5c 8a"
-    "34 7a 38 04 fc 63 45 1d c9 02 f0 b7 1f 90 83 45"
-    "9e d3 7a 51 79 a3 b7 23 a5 3f 10 51 64 2d 77 37"
-    "4c 4c 6c 8d bb 1c a2 05 25 f5 c9 f3 2d b7 76 95"
-    "35 56 da 31 29 0e 22 19 74 82 ce b6 99 06 c4 6a"
-    "75 8f b0 e7 40 9b a8 01 07 7d 2a 0a 20 ea e7 d1"
-    "d6 d3 92 ab 49 57 e8 6b 76 f0 65 2d 68 b8 39 88"
-    "a7 8f 26 e1 11 72 ea 60 9b f8 49 fb bd 78 ad 7e"
-    "dc e2 1d e6 62 a0 81 36 8c 04 06 07 ce e2 9d b0"
-    "62 72 27 f4 49 63 ad 17 1d 22 93 b6 33 a3 92 e3"
-    "31 dc a5 4f e3 08 27 52 f4 3f 63 c1 61 b4 47 a4"
-    "c6 5a 68 75 67 0d 5f 66 00 fc c8 60 a1 ca eb 0a"
-    "88 f8 fd ec 4e 56 43 98 a5 c4 6c 87 f6 8c e0 70"
-    "01 f6 21 3a be 0a b5 62 5f 87 d1 90 25 f0 8d 81"
-    "da c7 bd 45 86 bc 93 82 19 1f 6d 28 80 f6 22 7e"
-    "5d f3 ee d2 1e 77 92 d2 49 48 04 87 f3 65 52 61";
-
-// PKCS#1 v1.5 Signature Example 15.2
-
-char *message_2 =
-    "c1 4b 4c 60 75 b2 f9 aa d6 61 de f4 ec fd 3c b9 "
-    "33 c6 23 f4 e6 3b f5 34 10 d2 f0 16 d1 ab 98 e2 "
-    "72 9e cc f8 00 6c d8 e0 80 50 73 7d 95 fd bf 29 "
-    "6b 66 f5 b9 79 2a 90 29 36 c4 f7 ac 69 f5 14 53 "
-    "ce 43 69 45 2d c2 2d 96 f0 37 74 81 14 66 20 00 "
-    "dd 9c d3 a5 e1 79 f4 e0 f8 1f a6 a0 31 1c a1 ae "
-    "e6 51 9a 0f 63 ce c7 8d 27 bb 72 63 93 fb 7f 1f "
-    "88 cd e7 c9 7f 8a 66 cd 66 30 12 81 da c3 f3 a4 "
-    "33 24 8c 75 d6 c2 dc d7 08 b6 a9 7b 0a 3f 32 5e "
-    "0b 29 64 f8 a5 81 9e 47 9b ";
-
-char* signature_2 =
-    "af a7 34 34 62 be a1 22 cc 14 9f ca 70 ab da e7"
-    "94 46 67 7d b5 37 36 66 af 7d c3 13 01 5f 4d e7"
-    "86 e6 e3 94 94 6f ad 3c c0 e2 b0 2b ed ba 50 47"
-    "fe 9e 2d 7d 09 97 05 e4 a3 9f 28 68 32 79 cf 0a"
-    "c8 5c 15 30 41 22 42 c0 e9 18 95 3b e0 00 e9 39"
-    "cf 3b f1 82 52 5e 19 93 70 fa 79 07 eb a6 9d 5d"
-    "b4 63 10 17 c0 e3 6d f7 03 79 b5 db 8d 4c 69 5a"
-    "97 9a 8e 61 73 22 40 65 d7 dc 15 13 2e f2 8c d8"
-    "22 79 51 63 06 3b 54 c6 51 14 1b e8 6d 36 e3 67"
-    "35 bc 61 f3 1f ca 57 4e 53 09 f3 a3 bb df 91 ef"
-    "f1 2b 99 e9 cc 17 44 f1 ee 9a 1b d2 2c 5b ad 96"
-    "ad 48 19 29 25 1f 03 43 fd 36 bc f0 ac de 7f 11"
-    "e5 ad 60 97 77 21 20 27 96 fe 06 1f 9a da 1f c4"
-    "c8 e0 0d 60 22 a8 35 75 85 ff e9 fd d5 93 31 a2"
-    "8c 4a a3 12 15 88 fb 6c f6 83 96 d8 ac 05 46 59"
-    "95 00 c9 70 85 00 a5 97 2b d5 4f 72 cf 8d b0 c8";
-
-// PKCS#1 v1.5 Signature Example 15.3
-
-char* message_3 =
-    "d0 23 71 ad 7e e4 8b bf db 27 63 de 7a 84 3b 94 "
-    "08 ce 5e b5 ab f8 47 ca 3d 73 59 86 df 84 e9 06 "
-    "0b db cd d3 a5 5b a5 5d de 20 d4 76 1e 1a 21 d2 "
-    "25 c1 a1 86 f4 ac 4b 30 19 d3 ad f7 8f e6 33 46 "
-    "67 f5 6f 70 c9 01 a0 a2 70 0c 6f 0d 56 ad d7 19 "
-    "59 2d c8 8f 6d 23 06 c7 00 9f 6e 7a 63 5b 4c b3 "
-    "a5 02 df e6 8d dc 58 d0 3b e1 0a 11 70 00 4f e7 "
-    "4d d3 e4 6b 82 59 1f f7 54 14 f0 c4 a0 3e 60 5e "
-    "20 52 4f 24 16 f1 2e ca 58 9f 11 1b 75 d6 39 c6 "
-    "1b aa 80 ca fd 05 cf 35 00 24 4a 21 9e d9 ce d9 "
-    "f0 b1 02 97 18 2b 65 3b 52 6f 40 0f 29 53 ba 21 "
-    "4d 5b cd 47 88 41 32 87 2a e9 0d 4d 6b 1f 42 15 "
-    "39 f9 f3 46 62 a5 6d c0 e7 b4 b9 23 b6 23 1e 30 "
-    "d2 67 67 97 81 7f 7c 33 7b 5a c8 24 ba 93 14 3b "
-    "33 81 fa 3d ce 0e 6a eb d3 8e 67 73 51 87 b1 eb "
-    "d9 5c 02 ";
-
-char* signature_3 =
-    "3b ac 63 f8 6e 3b 70 27 12 03 10 6b 9c 79 aa bd"
-    "9f 47 7c 56 e4 ee 58 a4 fc e5 ba f2 ca b4 96 0f"
-    "88 39 1c 9c 23 69 8b e7 5c 99 ae df 9e 1a bf 17"
-    "05 be 1d ac 33 14 0a db 48 eb 31 f4 50 bb 9e fe"
-    "83 b7 b9 0d b7 f1 57 6d 33 f4 0c 1c ba 4b 8d 6b"
-    "1d 33 23 56 4b 0f 17 74 11 4f a7 c0 8e 6d 1e 20"
-    "dd 8f bb a9 b6 ac 7a d4 1e 26 b4 56 8f 4a 8a ac"
-    "bf d1 78 a8 f8 d2 c9 d5 f5 b8 81 12 93 5a 8b c9"
-    "ae 32 cd a4 0b 8d 20 37 55 10 73 50 96 53 68 18"
-    "ce 2b 2d b7 1a 97 72 c9 b0 dd a0 9a e1 01 52 fa"
-    "11 46 62 18 d0 91 b5 3d 92 54 30 61 b7 29 4a 55"
-    "be 82 ff 35 d5 c3 2f a2 33 f0 5a aa c7 58 50 30"
-    "7e cf 81 38 3c 11 16 74 39 7b 1a 1b 9d 3b f7 61"
-    "2c cb e5 ba cd 2b 38 f0 a9 83 97 b2 4c 83 65 8f"
-    "b6 c0 b4 14 0e f1 19 70 c4 63 0d 44 34 4e 76 ea"
-    "ed 74 dc be e8 11 db f6 57 59 41 f0 8a 65 23 b8";
-
-// PKCS#1 v1.5 Signature Example 15.4
-
-char* message_4 =
-    "29 03 55 84 ab 7e 02 26 a9 ec 4b 02 e8 dc f1 27 "
-    "2d c9 a4 1d 73 e2 82 00 07 b0 f6 e2 1f ec cd 5b "
-    "d9 db b9 ef 88 cd 67 58 76 9e e1 f9 56 da 7a d1 "
-    "84 41 de 6f ab 83 86 db c6 93 ";
-
-char* signature_4 =
-    "28 d8 e3 fc d5 dd db 21 ff bd 8d f1 63 0d 73 77"
-    "aa 26 51 e1 4c ad 1c 0e 43 cc c5 2f 90 7f 94 6d"
-    "66 de 72 54 e2 7a 6c 19 0e b0 22 ee 89 ec f6 22"
-    "4b 09 7b 71 06 8c d6 07 28 a1 ae d6 4b 80 e5 45"
-    "7b d3 10 6d d9 17 06 c9 37 c9 79 5f 2b 36 36 7f"
-    "f1 53 dc 25 19 a8 db 9b df 2c 80 74 30 c4 51 de"
-    "17 bb cd 0c e7 82 b3 e8 f1 02 4d 90 62 4d ea 7f"
-    "1e ed c7 42 0b 7e 7c aa 65 77 ce f4 31 41 a7 26"
-    "42 06 58 0e 44 a1 67 df 5e 41 ee a0 e6 9a 80 54"
-    "54 c4 0e ef c1 3f 48 e4 23 d7 a3 2d 02 ed 42 c0"
-    "ab 03 d0 a7 cf 70 c5 86 0a c9 2e 03 ee 00 5b 60"
-    "ff 35 03 42 4b 98 cc 89 45 68 c7 c5 6a 02 33 55"
-    "1c eb e5 88 cf 8b 01 67 b7 df 13 ad ca d8 28 67"
-    "68 10 49 9c 70 4d a7 ae 23 41 4d 69 e3 c0 d2 db"
-    "5d cb c2 61 3b c1 20 42 1f 9e 36 53 c5 a8 76 72"
-    "97 64 3c 7e 07 40 de 01 63 55 45 3d 6c 95 ae 72";
-
-// PKCS#1 v1.5 Signature Example 15.5
-
-char* message_5 =
-    "bd a3 a1 c7 90 59 ea e5 98 30 8d 3d f6 09 ";
-
-char* signature_5 =
-    "a1 56 17 6c b9 67 77 c7 fb 96 10 5d bd 91 3b c4"
-    "f7 40 54 f6 80 7c 60 08 a1 a9 56 ea 92 c1 f8 1c"
-    "b8 97 dc 4b 92 ef 9f 4e 40 66 8d c7 c5 56 90 1a"
-    "cb 6c f2 69 fe 61 5b 0f b7 2b 30 a5 13 38 69 23"
-    "14 b0 e5 87 8a 88 c2 c7 77 4b d1 69 39 b5 ab d8"
-    "2b 44 29 d6 7b d7 ac 8e 5e a7 fe 92 4e 20 a6 ec"
-    "66 22 91 f2 54 8d 73 4f 66 34 86 8b 03 9a a5 f9"
-    "d4 d9 06 b2 d0 cb 85 85 bf 42 85 47 af c9 1c 6e"
-    "20 52 dd cd 00 1c 3e f8 c8 ee fc 3b 6b 2a 82 b6"
-    "f9 c8 8c 56 f2 e2 c3 cb 0b e4 b8 0d a9 5e ba 37"
-    "1d 8b 5f 60 f9 25 38 74 3d db b5 da 29 72 c7 1f"
-    "e7 b9 f1 b7 90 26 8a 0e 77 0f c5 eb 4d 5d d8 52"
-    "47 d4 8a e2 ec 3f 26 25 5a 39 85 52 02 06 a1 f2"
-    "68 e4 83 e9 db b1 d5 ca b1 90 91 76 06 de 31 e7"
-    "c5 18 2d 8f 15 1b f4 1d fe cc ae d7 cd e6 90 b2"
-    "16 47 10 6b 49 0c 72 9d 54 a8 fe 28 02 a6 d1 26";
-
-// PKCS#1 v1.5 Signature Example 15.6
-
-char* message_6 =
-    "c1 87 91 5e 4e 87 da 81 c0 8e d4 35 6a 0c ce ac "
-    "1c 4f b5 c0 46 b4 52 81 b3 87 ec 28 f1 ab fd 56 "
-    "7e 54 6b 23 6b 37 d0 1a e7 1d 3b 28 34 36 5d 3d "
-    "f3 80 b7 50 61 b7 36 b0 13 0b 07 0b e5 8a e8 a4 "
-    "6d 12 16 63 61 b6 13 db c4 7d fa eb 4c a7 46 45 "
-    "6c 2e 88 83 85 52 5c ca 9d d1 c3 c7 a9 ad a7 6d "
-    "6c ";;
-
-char* signature_6 =
-    "9c ab 74 16 36 08 66 9f 75 55 a3 33 cf 19 6f e3"
-    "a0 e9 e5 eb 1a 32 d3 4b b5 c8 5f f6 89 aa ab 0e"
-    "3e 65 66 8e d3 b1 15 3f 94 eb 3d 8b e3 79 b8 ee"
-    "f0 07 c4 a0 2c 70 71 ce 30 d8 bb 34 1e 58 c6 20"
-    "f7 3d 37 b4 ec bf 48 be 29 4f 6c 9e 0e cb 5e 63"
-    "fe c4 1f 12 0e 55 53 df a0 eb eb bb 72 64 0a 95"
-    "37 ba dc b4 51 33 02 29 d9 f7 10 f6 2e 3e d8 ec"
-    "78 4e 50 ee 1d 92 62 b4 26 71 34 00 11 d7 d0 98"
-    "c6 f2 55 7b 21 31 fa 9b d0 25 46 36 59 7e 88 ec"
-    "b3 5a 24 0e f0 fd 85 95 71 24 df 80 80 fe e1 e1"
-    "49 af 93 99 89 e8 6b 26 c8 5a 58 81 fa e8 67 3d"
-    "9f d4 08 00 dd 13 4e b9 bd b6 41 0f 42 0b 0a a9"
-    "7b 20 ef cf 2e b0 c8 07 fa eb 83 a3 cc d9 b5 1d"
-    "45 53 e4 1d fc 0d f6 ca 80 a1 e8 1d c2 34 bb 83"
-    "89 dd 19 5a 38 b4 2d e4 ed c4 9d 34 64 78 b9 f1"
-    "1f 05 57 20 5f 5b 0b d7 ff e9 c8 50 f3 96 d7 c4";;
-
-// PKCS#1 v1.5 Signature Example 15.7
-
-char* message_7 =
-    "ab fa 2e cb 7d 29 bd 5b cb 99 31 ce 2b ad 2f 74 "
-    "38 3e 95 68 3c ee 11 02 2f 08 e8 e7 d0 b8 fa 05 "
-    "8b f9 eb 7e b5 f9 88 68 b5 bb 1f b5 c3 1c ed a3 "
-    "a6 4f 1a 12 cd f2 0f cd 0e 5a 24 6d 7a 17 73 d8 "
-    "db a0 e3 b2 77 54 5b ab e5 8f 2b 96 e3 f4 ed c1 "
-    "8e ab f5 cd 2a 56 0f ca 75 fe 96 e0 7d 85 9d ef "
-    "b2 56 4f 3a 34 f1 6f 11 e9 1b 3a 71 7b 41 af 53 "
-    "f6 60 53 23 00 1a a4 06 c6 ";
-
-char* signature_7 =
-    "c4 b4 37 bc f7 03 f3 52 e1 fa f7 4e b9 62 20 39"
-    "42 6b 56 72 ca f2 a7 b3 81 c6 c4 f0 19 1e 7e 4a"
-    "98 f0 ee bc d6 f4 17 84 c2 53 7f f0 f9 9e 74 98"
-    "2c 87 20 1b fb c6 5e ae 83 2d b7 1d 16 da ca db"
-    "09 77 e5 c5 04 67 9e 40 be 0f 9d b0 6f fd 84 8d"
-    "d2 e5 c3 8a 7e c0 21 e7 f6 8c 47 df d3 8c c3 54"
-    "49 3d 53 39 b4 59 5a 5b f3 1e 3f 8f 13 81 68 07"
-    "37 3d f6 ad 0d c7 e7 31 e5 1a d1 9e b4 75 4b 13"
-    "44 85 84 2f e7 09 d3 78 44 4d 8e 36 b1 72 4a 4f"
-    "da 21 ca fe e6 53 ab 80 74 7f 79 52 ee 80 4d ea"
-    "b1 03 9d 84 13 99 45 bb f4 be 82 00 87 53 f3 c5"
-    "4c 78 21 a1 d2 41 f4 21 79 c7 94 ef 70 42 bb f9"
-    "95 56 56 22 2e 45 c3 43 69 a3 84 69 7b 6a e7 42"
-    "e1 8f a5 ca 7a ba d2 7d 9f e7 10 52 e3 31 0d 0f"
-    "52 c8 d1 2e a3 3b f0 53 a3 00 f4 af c4 f0 98 df"
-    "4e 6d 88 67 79 d6 45 94 d3 69 15 8f db c1 f6 94";
-
-// PKCS#1 v1.5 Signature Example 15.8
-
-char* message_8 =
-    "df 40 44 a8 9a 83 e9 fc bf 12 62 54 0a e3 03 8b "
-    "bc 90 f2 b2 62 8b f2 a4 46 7a c6 77 22 d8 54 6b "
-    "3a 71 cb 0e a4 16 69 d5 b4 d6 18 59 c1 b4 e4 7c "
-    "ec c5 93 3f 75 7e c8 6d b0 64 4e 31 18 12 d0 0f "
-    "b8 02 f0 34 00 63 9c 0e 36 4d ae 5a eb c5 79 1b "
-    "c6 55 76 23 61 bc 43 c5 3d 3c 78 86 76 8f 79 68 "
-    "c1 c5 44 c6 f7 9f 7b e8 20 c7 e2 bd 2f 9d 73 e6 "
-    "2d ed 6d 2e 93 7e 6a 6d ae f9 0e e3 7a 1a 52 a5 "
-    "4f 00 e3 1a dd d6 48 94 cf 4c 02 e1 60 99 e2 9f "
-    "9e b7 f1 a7 bb 7f 84 c4 7a 2b 59 48 13 be 02 a1 "
-    "7b 7f c4 3b 34 c2 2c 91 92 52 64 12 6c 89 f8 6b "
-    "b4 d8 7f 3e f1 31 29 6c 53 a3 08 e0 33 1d ac 8b "
-    "af 3b 63 42 22 66 ec ef 2b 90 78 15 35 db da 41 "
-    "cb d0 cf 22 a8 cb fb 53 2e c6 8f c6 af b2 ac 06 ";
-
-char* signature_8 =
-    "14 14 b3 85 67 ae 6d 97 3e de 4a 06 84 2d cc 0e"
-    "05 59 b1 9e 65 a4 88 9b db ab d0 fd 02 80 68 29"
-    "13 ba cd 5d c2 f0 1b 30 bb 19 eb 81 0b 7d 9d ed"
-    "32 b2 84 f1 47 bb e7 71 c9 30 c6 05 2a a7 34 13"
-    "90 a8 49 f8 1d a9 cd 11 e5 ec cf 24 6d ba e9 5f"
-    "a9 58 28 e9 ae 0c a3 55 03 25 32 6d ee f9 f4 95"
-    "30 ba 44 1b ed 4a c2 9c 02 9c 9a 27 36 b1 a4 19"
-    "0b 85 08 4a d1 50 42 6b 46 d7 f8 5b d7 02 f4 8d"
-    "ac 5f 71 33 0b c4 23 a7 66 c6 5c c1 dc ab 20 d3"
-    "d3 bb a7 2b 63 b3 ef 82 44 d4 2f 15 7c b7 e3 a8"
-    "ba 5c 05 27 2c 64 cc 1a d2 1a 13 49 3c 39 11 f6"
-    "0b 4e 9f 4e cc 99 00 eb 05 6e e5 9d 6f e4 b8 ff"
-    "6e 80 48 cc c0 f3 8f 28 36 fd 3d fe 91 bf 4a 38"
-    "6e 1e cc 2c 32 83 9f 0c a4 d1 b2 7a 56 8f a9 40"
-    "dd 64 ad 16 bd 01 25 d0 34 8e 38 30 85 f0 88 94"
-    "86 1c a1 89 87 22 7d 37 b4 2b 58 4a 83 57 cb 04";
-
-// PKCS#1 v1.5 Signature Example 15.9
-
-char* message_9 =
-    "ea 94 1f f0 6f 86 c2 26 92 7f cf 0e 3b 11 b0 87 "
-    "26 76 17 0c 1b fc 33 bd a8 e2 65 c7 77 71 f9 d0 "
-    "85 01 64 a5 ee cb cc 5c e8 27 fb fa 07 c8 52 14 "
-    "79 6d 81 27 e8 ca a8 18 94 ea 61 ce b1 44 9e 72 "
-    "fe a0 a4 c9 43 b2 da 6d 9b 10 5f e0 53 b9 03 9a "
-    "9c c5 3d 42 0b 75 39 fa b2 23 9c 6b 51 d1 7e 69 "
-    "4c 95 7d 4b 0f 09 84 46 18 79 a0 75 9c 44 01 be "
-    "ec d4 c6 06 a0 af bd 7a 07 6f 50 a2 df c2 80 7f "
-    "24 f1 91 9b aa 77 46 d3 a6 4e 26 8e d3 f5 f8 e6 "
-    "da 83 a2 a5 c9 15 2f 83 7c b0 78 12 bd 5b a7 d3 "
-    "a0 79 85 de 88 11 3c 17 96 e9 b4 66 ec 29 9c 5a "
-    "c1 05 9e 27 f0 94 15 ";
-
-char* signature_9 =
-    "ce eb 84 cc b4 e9 09 92 65 65 07 21 ee a0 e8 ec"
-    "89 ca 25 bd 35 4d 4f 64 56 49 67 be 9d 4b 08 b3"
-    "f1 c0 18 53 9c 9d 37 1c f8 96 1f 22 91 fb e0 dc"
-    "2f 2f 95 fe a4 7b 63 9f 1e 12 f4 bc 38 1c ef 0c"
-    "2b 7a 7b 95 c3 ad f2 76 05 b7 f6 39 98 c3 cb ad"
-    "54 28 08 c3 82 2e 06 4d 4a d1 40 93 67 9e 6e 01"
-    "41 8a 6d 5c 05 96 84 cd 56 e3 4e d6 5a b6 05 b8"
-    "de 4f cf a6 40 47 4a 54 a8 25 1b bb 73 26 a4 2d"
-    "08 58 5c fc fc 95 67 69 b1 5b 6d 7f df 7d a8 4f"
-    "81 97 6e aa 41 d6 92 38 0f f1 0e ae cf e0 a5 79"
-    "68 29 09 b5 52 1f ad e8 54 d7 97 b8 a0 34 5b 9a"
-    "86 4e 05 88 f6 ca dd bf 65 f1 77 99 8e 18 0d 1f"
-    "10 24 43 e6 dc a5 3a 94 82 3c aa 9c 3b 35 f3 22"
-    "58 3c 70 3a f6 74 76 15 9e c7 ec 93 d1 76 9b 30"
-    "0a f0 e7 15 7d c2 98 c6 cd 2d ee 22 62 f8 cd dc"
-    "10 f1 1e 01 74 14 71 bb fd 65 18 a1 75 73 45 75";
-
-// PKCS#1 v1.5 Signature Example 15.10
-
-char* message_10 =
-    "d8 b8 16 45 c1 3c d7 ec f5 d0 0e d2 c9 1b 9a cd "
-    "46 c1 55 68 e5 30 3c 4a 97 75 ed e7 6b 48 40 3d "
-    "6b e5 6c 05 b6 b1 cf 77 c6 e7 5d e0 96 c5 cb 35 "
-    "51 cb 6f a9 64 f3 c8 79 cf 58 9d 28 e1 da 2f 9d "
-    "ec ";
-
-char* signature_10 =
-    "27 45 07 4c a9 71 75 d9 92 e2 b4 47 91 c3 23 c5"
-    "71 67 16 5c dd 8d a5 79 cd ef 46 86 b9 bb 40 4b"
-    "d3 6a 56 50 4e b1 fd 77 0f 60 bf a1 88 a7 b2 4b"
-    "0c 91 e8 81 c2 4e 35 b0 4d c4 dd 4c e3 85 66 bc"
-    "c9 ce 54 f4 9a 17 5f c9 d0 b2 25 22 d9 57 90 47"
-    "f9 ed 42 ec a8 3f 76 4a 10 16 39 97 94 7e 7d 2b"
-    "52 ff 08 98 0e 7e 7c 22 57 93 7b 23 f3 d2 79 d4"
-    "cd 17 d6 f4 95 54 63 73 d9 83 d5 36 ef d7 d1 b6"
-    "71 81 ca 2c b5 0a c6 16 c5 c7 ab fb b9 26 0b 91"
-    "b1 a3 8e 47 24 20 01 ff 45 2f 8d e1 0c a6 ea ea"
-    "dc af 9e dc 28 95 6f 28 a7 11 29 1f c9 a8 08 78"
-    "b8 ba 4c fe 25 b8 28 1c b8 0b c9 cd 6d 2b d1 82"
-    "52 46 ee be 25 2d 99 57 ef 93 70 73 52 08 4e 6d"
-    "36 d4 23 55 1b f2 66 a8 53 40 fb 4a 6a f3 70 88"
-    "0a ab 07 15 3d 01 f4 8d 08 6d f0 bf be c0 5e 7b"
-    "44 3b 97 e7 17 18 97 0e 2f 4b f6 20 23 e9 5b 67";
-
-// PKCS#1 v1.5 Signature Example 15.11
-
-char* message_11 =
-    "e5 73 9b 6c 14 c9 2d 51 0d 95 b8 26 93 33 37 ff "
-    "0d 24 ef 72 1a c4 ef 64 c2 ba d2 64 be 8b 44 ef "
-    "a1 51 6e 08 a2 7e b6 b6 11 d3 30 1d f0 06 2d ae "
-    "fc 73 a8 c0 d9 2e 2c 52 1f ac bc 7b 26 47 38 76 "
-    "7e a6 fc 97 d5 88 a0 ba f6 ce 50 ad f7 9e 60 0b "
-    "d2 9e 34 5f cb 1d ba 71 ac 5c 02 89 02 3f e4 a8 "
-    "2b 46 a5 40 77 19 19 7d 2e 95 8e 35 31 fd 54 ae "
-    "f9 03 aa bb 43 55 f8 83 18 99 4e d3 c3 dd 62 f4 "
-    "20 a7 ";
-
-char* signature_11 =
-    "be 40 a5 fb 94 f1 13 e1 b3 ef f6 b6 a3 39 86 f2"
-    "02 e3 63 f0 74 83 b7 92 e6 8d fa 55 54 df 04 66"
-    "cc 32 15 09 50 78 3b 4d 96 8b 63 9a 04 fd 2f b9"
-    "7f 6e b9 67 02 1f 5a dc cb 9f ca 95 ac c8 f2 cd"
-    "88 5a 38 0b 0a 4e 82 bc 76 07 64 db ab 88 c1 e6"
-    "c0 25 5c aa 94 f2 32 19 9d 6f 59 7c c9 14 5b 00"
-    "e3 d4 ba 34 6b 55 9a 88 33 ad 15 16 ad 51 63 f0"
-    "16 af 6a 59 83 1c 82 ea 13 c8 22 4d 84 d0 76 5a"
-    "9d 12 38 4d a4 60 a8 53 1b 4c 40 7e 04 f4 f3 50"
-    "70 9e b9 f0 8f 5b 22 0f fb 45 ab f6 b7 5d 15 79"
-    "fd 3f 1e b5 5f c7 5b 00 af 8b a3 b0 87 82 7f e9"
-    "ae 9f b4 f6 c5 fa 63 03 1f e5 82 85 2f e2 83 4f"
-    "9c 89 bf f5 3e 25 52 21 6b c7 c1 d4 a3 d5 dc 2b"
-    "a6 95 5c d9 b1 7d 13 63 e7 fe e8 ed 76 29 75 3f"
-    "f3 12 5e dd 48 52 1a e3 b9 b0 32 17 f4 49 6d 0d"
-    "8e de 57 ac bc 5b d4 de ae 74 a5 6f 86 67 1d e2";
-
-// PKCS#1 v1.5 Signature Example 15.12
-
-char* message_12 =
-    "7a f4 28 35 91 7a 88 d6 b3 c6 71 6b a2 f5 b0 d5 "
-    "b2 0b d4 e2 e6 e5 74 e0 6a f1 ee f7 c8 11 31 be "
-    "22 bf 81 28 b9 cb c6 ec 00 27 5b a8 02 94 a5 d1 "
-    "17 2d 08 24 a7 9e 8f dd 83 01 83 e4 c0 0b 96 78 "
-    "28 67 b1 22 7f ea 24 9a ad 32 ff c5 fe 00 7b c5 "
-    "1f 21 79 2f 72 8d ed a8 b5 70 8a a9 9c ab ab 20 "
-    "a4 aa 78 3e d8 6f 0f 27 b5 d5 63 f4 2e 07 15 8c "
-    "ea 72 d0 97 aa 68 87 ec 41 1d d0 12 91 2a 5e 03 "
-    "2b bf a6 78 50 71 44 bc c9 5f 39 b5 8b e7 bf d1 "
-    "75 9a db 9a 91 fa 1d 6d 82 26 a8 34 3a 8b 84 9d "
-    "ae 76 f7 b9 82 24 d5 9e 28 f7 81 f1 3e ce 60 5f "
-    "84 f6 c9 0b ae 5f 8c f3 78 81 6f 40 20 a7 dd a1 "
-    "be d9 0c 92 a2 36 34 d2 03 fa c3 fc d8 6d 68 d3 "
-    "18 2a 7d 9c ca be 7b 07 95 f5 c6 55 e9 ac c4 e3 "
-    "ec 18 51 40 d1 0c ef 05 34 64 ab 17 5c 83 bd 83 "
-    "93 5e 3d ab af 34 62 ee be 63 d1 5f 57 3d 26 9a ";
-
-char* signature_12 =
-    "4e 78 c5 90 2b 80 79 14 d1 2f a5 37 ae 68 71 c8"
-    "6d b8 02 1e 55 d1 ad b8 eb 0c cf 1b 8f 36 ab 7d"
-    "ad 1f 68 2e 94 7a 62 70 72 f0 3e 62 73 71 78 1d"
-    "33 22 1d 17 4a be 46 0d bd 88 56 0c 22 f6 90 11"
-    "6e 2f bb e6 e9 64 36 3a 3e 52 83 bb 5d 94 6e f1"
-    "c0 04 7e ba 03 8c 75 6c 40 be 79 23 05 58 09 b0"
-    "e9 f3 4a 03 a5 88 15 eb dd e7 67 93 1f 01 8f 6f"
-    "18 78 f2 ef 4f 47 dd 37 40 51 dd 48 68 5d ed 6e"
-    "fb 3e a8 02 1f 44 be 1d 7d 14 93 98 f9 8e a9 c0"
-    "8d 62 88 8e bb 56 19 2d 17 74 7b 6b 8e 17 09 54"
-    "31 f1 25 a8 a8 e9 96 2a a3 1c 28 52 64 e0 8f b2"
-    "1a ac 33 6c e6 c3 8a a3 75 e4 2b c9 2a b0 ab 91"
-    "03 84 31 e1 f9 2c 39 d2 af 5d ed 7e 43 bc 15 1e"
-    "6e be a4 c3 e2 58 3a f3 43 7e 82 c4 3c 5e 3b 5b"
-    "07 cf 03 59 68 3d 22 98 e3 59 48 ed 80 6c 06 3c"
-    "60 6e a1 78 15 0b 1e fc 15 85 69 34 c7 25 5c fe";
-
-// PKCS#1 v1.5 Signature Example 15.13
-
-char* message_13 =
-    "eb ae f3 f9 f2 3b df e5 fa 6b 8a f4 c2 08 c1 89 "
-    "f2 25 1b f3 2f 5f 13 7b 9d e4 40 63 78 68 6b 3f "
-    "07 21 f6 2d 24 cb 86 88 d6 fc 41 a2 7c ba e2 1d "
-    "30 e4 29 fe ac c7 11 19 41 c2 77 ";
-
-char* signature_13 =
-    "c4 8d be f5 07 11 4f 03 c9 5f af be b4 df 1b fa"
-    "88 e0 18 4a 33 cc 4f 8a 9a 10 35 ff 7f 82 2a 5e"
-    "38 cd a1 87 23 91 5f f0 78 24 44 29 e0 f6 08 1c"
-    "14 fd 83 33 1f a6 5c 6b a7 bb 9a 12 db f6 62 23"
-    "74 cd 0c a5 7d e3 77 4e 2b d7 ae 82 36 77 d0 61"
-    "d5 3a e9 c4 04 0d 2d a7 ef 70 14 f3 bb dc 95 a3"
-    "61 a4 38 55 c8 ce 9b 97 ec ab ce 17 4d 92 62 85"
-    "14 2b 53 4a 30 87 f9 f4 ef 74 51 1e c7 42 b0 d5"
-    "68 56 03 fa f4 03 b5 07 2b 98 5d f4 6a df 2d 25"
-    "29 a0 2d 40 71 1e 21 90 91 70 52 37 1b 79 b7 49"
-    "b8 3a bf 0a e2 94 86 c3 f2 f6 24 77 b2 bd 36 2b"
-    "03 9c 01 3c 0c 50 76 ef 52 0d bb 40 5f 42 ce e9"
-    "54 25 c3 73 a9 75 e1 cd d0 32 c4 96 22 c8 50 79"
-    "b0 9e 88 da b2 b1 39 69 ef 7a 72 39 73 78 10 40"
-    "45 9f 57 d5 01 36 38 48 3d e2 d9 1c b3 c4 90 da"
-    "81 c4 6d e6 cd 76 ea 8a 0c 8f 6f e3 31 71 2d 24";
-
-// PKCS#1 v1.5 Signature Example 15.14
-
-char* message_14 =
-    "c5 a2 71 12 78 76 1d fc dd 4f 0c 99 e6 f5 61 9d "
-    "6c 48 b5 d4 c1 a8 09 82 fa a6 b4 cf 1c f7 a6 0f "
-    "f3 27 ab ef 93 c8 01 42 9e fd e0 86 40 85 81 46 "
-    "10 56 ac c3 3f 3d 04 f5 ad a2 12 16 ca cd 5f d1 "
-    "f9 ed 83 20 3e 0e 2f e6 13 8e 3e ae 84 24 e5 91 "
-    "5a 08 3f 3f 7a b7 60 52 c8 be 55 ae 88 2d 6e c1 "
-    "48 2b 1e 45 c5 da e9 f4 10 15 40 53 27 02 2e c3 "
-    "2f 0e a2 42 97 63 b2 55 04 3b 19 58 ee 3c f6 d6 "
-    "39 83 59 6e b3 85 84 4f 85 28 cc 9a 98 65 83 5d "
-    "c5 11 3c 02 b8 0d 0f ca 68 aa 25 e7 2b ca ae b3 "
-    "cf 9d 79 d8 4f 98 4f d4 17 ";
-
-char* signature_14 =
-    "6b d5 25 7a a0 66 11 fb 46 60 08 7c b4 bc 4a 9e"
-    "44 91 59 d3 16 52 bd 98 08 44 da f3 b1 c7 b3 53"
-    "f8 e5 61 42 f7 ea 98 57 43 3b 18 57 3b 4d ee de"
-    "81 8a 93 b0 29 02 97 78 3f 1a 2f 23 cb c7 27 97"
-    "a6 72 53 7f 01 f6 24 84 cd 41 62 c3 21 4b 9a c6"
-    "28 22 4c 5d e0 1f 32 bb 9b 76 b2 73 54 f2 b1 51"
-    "d0 e8 c4 21 3e 46 15 ad 0b c7 1f 51 5e 30 0d 6a"
-    "64 c6 74 34 11 ff fd e8 e5 ff 19 0e 54 92 30 43"
-    "12 6e cf c4 c4 53 90 22 66 8f b6 75 f2 5c 07 e2"
-    "00 99 ee 31 5b 98 d6 af ec 4b 1a 9a 93 dc 33 49"
-    "6a 15 bd 6f de 16 63 a7 d4 9b 9f 1e 63 9d 38 66"
-    "4b 37 a0 10 b1 f3 5e 65 86 82 d9 cd 63 e5 7d e0"
-    "f1 5e 8b dd 09 65 58 f0 7e c0 ca a2 18 a8 c0 6f"
-    "47 88 45 39 40 28 7c 9d 34 b6 d4 0a 3f 09 bf 77"
-    "99 fe 98 ae 4e b4 9f 3f f4 1c 50 40 a5 0c ef c9"
-    "bd f2 39 4b 74 9c f1 64 48 0d f1 ab 68 80 27 3b";
-
-// PKCS#1 v1.5 Signature Example 15.15
-
-char* message_15 =
-    "9b f8 aa 25 3b 87 2e a7 7a 7e 23 47 6b e2 6b 23 "
-    "29 57 8c f6 ac 9e a2 80 5b 35 7f 6f c3 ad 13 0d "
-    "ba eb 3d 86 9a 13 cc e7 a8 08 bb bb c9 69 85 7e "
-    "03 94 5c 7b b6 1d f1 b5 c2 58 9b 8e 04 6c 2a 5d "
-    "7e 40 57 b1 a7 4f 24 c7 11 21 63 64 28 85 29 ec "
-    "95 70 f2 51 97 21 3b e1 f5 c2 e5 96 f8 bf 8b 2c "
-    "f3 cb 38 aa 56 ff e5 e3 1d f7 39 58 20 e9 4e cf "
-    "3b 11 89 a9 65 dc f9 a9 cb 42 98 d3 c8 8b 29 23 "
-    "c1 9f c6 bc 34 aa ce ca d4 e0 93 1a 7c 4e 5d 73 "
-    "dc 86 df a7 98 a8 47 6d 82 46 3e ef aa 90 a8 a9 "
-    "19 2a b0 8b 23 08 8d d5 8e 12 80 f7 d7 2e 45 48 "
-    "39 6b aa c1 12 25 2d d5 c5 34 6a db 20 04 a2 f7 "
-    "10 1c cc 89 9c c7 fa fa e8 bb e2 95 73 88 96 a5 "
-    "b2 01 22 85 01 4e f6 ";
-
-char* signature_15 =
-    "27 f7 f4 da 9b d6 10 10 6e f5 7d 32 38 3a 44 8a"
-    "8a 62 45 c8 3d c1 30 9c 6d 77 0d 35 7b a8 9e 73"
-    "f2 ad 08 32 06 2e b0 fe 0a c9 15 57 5b cd 6b 8b"
-    "ca db 4e 2b a6 fa 9d a7 3a 59 17 51 52 b2 d4 fe"
-    "72 b0 70 c9 b7 37 9e 50 00 0e 55 e6 c2 69 f6 65"
-    "8c 93 79 72 79 7d 3a dd 69 f1 30 e3 4b 85 bd ec"
-    "9f 3a 9b 39 22 02 d6 f3 e4 30 d0 9c ac a8 22 77"
-    "59 ab 82 5f 70 12 d2 ff 4b 5b 62 c8 50 4d ba d8"
-    "55 c0 5e dd 5c ab 5a 4c cc dc 67 f0 1d d6 51 7c"
-    "7d 41 c4 3e 2a 49 57 af f1 9d b6 f1 8b 17 85 9a"
-    "f0 bc 84 ab 67 14 6e c1 a4 a6 0a 17 d7 e0 5f 8b"
-    "4f 9c ed 6a d1 09 08 d8 d7 8f 7f c8 8b 76 ad c8"
-    "29 0f 87 da f2 a7 be 10 ae 40 85 21 39 5d 54 ed"
-    "25 56 fb 76 61 85 4a 73 0c e3 d8 2c 71 a8 d4 93"
-    "ec 49 a3 78 ac 8a 3c 74 43 9f 7c c5 55 ba 13 f8"
-    "59 07 08 90 ee 18 ff 65 8f a4 d7 41 96 9d 70 a5";
-
-// PKCS#1 v1.5 Signature Example 15.16
-
-char* message_16 =
-    "32 47 48 30 e2 20 37 54 c8 bf 06 81 dc 4f 84 2a "
-    "fe 36 09 30 37 86 16 c1 08 e8 33 65 6e 56 40 c8 "
-    "68 56 88 5b b0 5d 1e b9 43 8e fe de 67 92 63 de "
-    "07 cb 39 55 3f 6a 25 e0 06 b0 a5 23 11 a0 63 ca "
-    "08 82 66 d2 56 4f f6 49 0c 46 b5 60 98 18 54 8f "
-    "88 76 4d ad 34 a2 5e 3a 85 d5 75 02 3f 0b 9e 66 "
-    "50 48 a0 3c 35 05 79 a9 d3 24 46 c7 bb 96 cc 92 "
-    "e0 65 ab 94 d3 c8 95 2e 8d f6 8e f0 d9 fa 45 6b "
-    "3a 06 bb 80 e3 bb c4 b2 8e 6a 94 b6 d0 ff 76 96 "
-    "a6 4e fe 05 e7 35 fe a0 25 d7 bd bc 41 39 f3 a3 "
-    "b5 46 07 5c ba 7e fa 94 73 74 d3 f0 ac 80 a6 8d "
-    "76 5f 5d f6 21 0b ca 06 9a 2d 88 64 7a f7 ea 04 "
-    "2d ac 69 0c b5 73 78 ec 07 77 61 4f b8 b6 5f f4 "
-    "53 ca 6b 7d ce 60 98 45 1a 2f 8c 0d a9 bf ec f1 "
-    "fd f3 91 bb aa 4e 2a 91 ca 18 a1 12 1a 75 23 a2 "
-    "ab d4 25 14 f4 89 e8 ";
-
-char* signature_16 =
-    "69 17 43 72 57 c2 2c cb 54 03 29 0c 3d ee 82 d9"
-    "cf 75 50 b3 1b d3 1c 51 bd 57 bf d3 5d 45 2a b4"
-    "db 7c 4b e6 b2 e2 5a c9 a5 9a 1d 2a 7f eb 62 7f"
-    "0a fd 49 76 b3 00 3c c9 cf fd 88 96 50 5e c3 82"
-    "f2 65 10 4d 4c f8 c9 32 fa 9f e8 6e 00 87 07 95"
-    "99 12 38 9d a4 b2 d6 b3 69 b3 6a 5e 72 e2 9d 24"
-    "c9 a9 8c 9d 31 a3 ab 44 e6 43 e6 94 12 66 a4 7a"
-    "45 e3 44 6c e8 77 6a be 24 1a 8f 5f c6 42 3b 24"
-    "b1 ff 25 0d c2 c3 a8 17 23 53 56 10 77 e8 50 a7"
-    "69 b2 5f 03 25 da c8 89 65 a3 b9 b4 72 c4 94 e9"
-    "5f 71 9b 4e ac 33 2c aa 7a 65 c7 df e4 6d 9a a7"
-    "e6 e0 0f 52 5f 30 3d d6 3a b7 91 92 18 90 18 68"
-    "f9 33 7f 8c d2 6a af e6 f3 3b 7f b2 c9 88 10 af"
-    "19 f7 fc b2 82 ba 15 77 91 2c 1d 36 89 75 fd 5d"
-    "44 0b 86 e1 0c 19 97 15 fa 0b 6f 42 50 b5 33 73"
-    "2d 0b ef e1 54 51 50 fc 47 b8 76 de 09 b0 0a 94";
-
-// PKCS#1 v1.5 Signature Example 15.17
-
-char* message_17 =
-    "00 8e 59 50 5e af b5 50 aa e5 e8 45 58 4c eb b0 "
-    "0b 6d e1 73 3e 9f 95 d4 2c 88 2a 5b be b5 ce 1c "
-    "57 e1 19 e7 c0 d4 da ca 9f 1f f7 87 02 17 f7 cf "
-    "d8 a6 b3 73 97 7c ac 9c ab 8e 71 e4 20 ";
-
-char* signature_17 =
-    "92 25 03 b6 73 ee 5f 3e 69 1e 1c a8 5e 9f f4 17"
-    "3c f7 2b 05 ac 2c 13 1d a5 60 35 93 e3 bc 25 9c"
-    "94 c1 f7 d3 a0 6a 5b 98 91 bf 11 3f a3 9e 59 ff"
-    "7c 1e d6 46 5e 90 80 49 cb 89 e4 e1 25 cd 37 d2"
-    "ff d9 22 7a 41 b4 a0 a1 9c 0a 44 fb bf 3d e5 5b"
-    "ab 80 20 87 a3 bb 8d 4f f6 68 ee 6b bb 8a d8 9e"
-    "68 57 a7 9a 9c 72 78 19 90 df cf 92 cd 51 94 04"
-    "c9 50 f1 3d 11 43 c3 18 4f 1d 25 0c 90 e1 7a c6"
-    "ce 36 16 3b 98 95 62 7a d6 ff ec 14 22 44 1f 55"
-    "e4 49 9d ba 9b e8 95 46 ae 8b c6 3c ca 01 dd 08"
-    "46 3a e7 f1 fc e3 d8 93 99 69 38 77 8c 18 12 e6"
-    "74 ad 9c 30 9c 5a cc a3 fd e4 4e 7d d8 69 59 93"
-    "e9 c1 fa 87 ac da 99 ec e5 c8 49 9e 46 89 57 ad"
-    "66 35 9b f1 2a 51 ad be 78 d3 a2 13 b4 49 bf 0b"
-    "5f 8d 4d 49 6a cf 03 d3 03 3b 7c cd 19 6b c2 2f"
-    "68 fb 7b ef 4f 69 7c 5e a2 b3 50 62 f4 8a 36 dd";
-
-// PKCS#1 v1.5 Signature Example 15.18
-
-char* message_18 =
-    "6a bc 54 cf 8d 1d ff 1f 53 b1 7d 81 60 36 88 78 "
-    "a8 78 8c c6 d2 2f a5 c2 25 8c 88 e6 60 b0 9a 89 "
-    "33 f9 f2 c0 50 4d da dc 21 f6 e7 5e 0b 83 3b eb "
-    "55 52 29 de e6 56 b9 04 7b 92 f6 2e 76 b8 ff cc "
-    "60 da b0 6b 80 ";
-
-char* signature_18 =
-    "0b 6d af 42 f7 a8 62 14 7e 41 74 93 c2 c4 01 ef"
-    "ae 32 63 6a b4 cb d4 41 92 bb f5 f1 95 b5 0a e0"
-    "96 a4 75 a1 61 4f 0a 9f a8 f7 a0 26 cb 46 c6 50"
-    "6e 51 8e 33 d8 3e 56 47 7a 87 5a ca 8c 7e 71 4c"
-    "e1 bd bd 61 ef 5d 53 52 39 b3 3f 2b fd d6 17 71"
-    "ba b6 27 76 d7 81 71 a1 42 3c ea 87 31 f8 2e 60"
-    "76 6d 64 54 26 56 20 b1 5f 5c 5a 58 4f 55 f9 5b"
-    "80 2f e7 8c 57 4e d5 da cf c8 31 f3 cf 2b 05 02"
-    "c0 b2 98 f2 5c cf 11 f9 73 b3 1f 85 e4 74 42 19"
-    "85 f3 cf f7 02 df 39 46 ef 0a 66 05 68 21 11 b2"
-    "f5 5b 1f 8a b0 d2 ea 3a 68 3c 69 98 5e ad 93 ed"
-    "44 9e a4 8f 03 58 dd f7 08 02 cb 41 de 2f d8 3f"
-    "3c 80 80 82 d8 49 36 94 8e 0c 84 a1 31 b4 92 78"
-    "27 46 05 27 bb 5c d2 4b fa b7 b4 8e 07 1b 24 17"
-    "19 30 f9 97 63 27 2f 97 97 bc b7 6f 1d 24 81 57"
-    "55 58 fc f2 60 b1 f0 e5 54 eb b3 df 3c fc b9 58";
-
-// PKCS#1 v1.5 Signature Example 15.19
-
-char* message_19 =
-    "af 2d 78 15 2c f1 0e fe 01 d2 74 f2 17 b1 77 f6 "
-    "b0 1b 5e 74 9f 15 67 71 5d a3 24 85 9c d3 dd 88 "
-    "db 84 8e c7 9f 48 db ba 7b 6f 1d 33 11 1e f3 1b "
-    "64 89 9e 73 91 c2 bf fd 69 f4 90 25 cf 20 1f c5 "
-    "85 db d1 54 2c 1c 77 8a 2c e7 a7 ee 10 8a 30 9f "
-    "ec a2 6d 13 3a 5f fe dc 4e 86 9d cd 76 56 59 6a "
-    "c8 42 7e a3 ef 6e 3f d7 8f e9 9d 8d dc 71 d8 39 "
-    "f6 78 6e 0d a6 e7 86 bd 62 b3 a4 f1 9b 89 1a 56 "
-    "15 7a 55 4e c2 a2 b3 9e 25 a1 d7 c7 d3 73 21 c7 "
-    "a1 d9 46 cf 4f be 75 8d 92 76 f0 85 63 44 9d 67 "
-    "41 4a 2c 03 0f 42 51 cf e2 21 3d 04 a5 41 06 37 "
-    "87 ";
-
-char* signature_19 =
-    "20 9c 61 15 78 57 38 7b 71 e2 4b f3 dd 56 41 45"
-    "50 50 3b ec 18 0f f5 3b dd 9b ac 06 2a 2d 49 95"
-    "09 bf 99 12 81 b7 95 27 df 91 36 61 5b 7a 6d 9d"
-    "b3 a1 03 b5 35 e0 20 2a 2c ac a1 97 a7 b7 4e 53"
-    "56 f3 dd 59 5b 49 ac fd 9d 30 04 9a 98 ca 88 f6"
-    "25 bc a1 d5 f2 2a 39 2d 8a 74 9e fb 6e ed 9b 78"
-    "21 d3 11 0a c0 d2 44 19 9e cb 4a a3 d7 35 a8 3a"
-    "2e 88 93 c6 bf 85 81 38 3c ca ee 83 46 35 b7 fa"
-    "1f af fa 45 b1 3d 15 c1 da 33 af 71 e8 93 03 d6"
-    "80 90 ff 62 ee 61 5f df 5a 84 d1 20 71 1d a5 3c"
-    "28 89 19 8a b3 83 17 a9 73 4a b2 7d 67 92 4c ea"
-    "74 15 6f f9 9b ef 98 76 bb 5c 33 9e 93 74 52 83"
-    "e1 b3 4e 07 22 26 b8 80 45 e0 17 e9 f0 5b 2a 8c"
-    "41 67 40 25 8e 22 3b 26 90 02 74 91 73 22 73 f3"
-    "22 9d 9e f2 b1 b3 80 7e 32 10 18 92 0a d3 e5 3d"
-    "ae 47 e6 d9 39 5c 18 4b 93 a3 74 c6 71 fa a2 ce";
-
-// PKCS#1 v1.5 Signature Example 15.20
-
-char* message_20 =
-    "40 ee 99 24 58 d6 f6 14 86 d2 56 76 a9 6d d2 cb "
-    "93 a3 7f 04 b1 78 48 2f 2b 18 6c f8 82 15 27 0d "
-    "ba 29 d7 86 d7 74 b0 c5 e7 8c 7f 6e 56 a9 56 e7 "
-    "f7 39 50 a2 b0 c0 c1 0a 08 db cd 67 e5 b2 10 bb "
-    "21 c5 8e 27 67 d4 4f 7d d4 01 4e 39 66 14 3b f7 "
-    "e3 d6 6f f0 c0 9b e4 c5 5f 93 b3 99 94 b8 51 8d "
-    "9c 1d 76 d5 b4 73 74 de a0 8f 15 7d 57 d7 06 34 "
-    "97 8f 38 56 e0 e5 b4 81 af bb db 5a 3a c4 8d 48 "
-    "4b e9 2c 93 de 22 91 78 35 4c 2d e5 26 e9 c6 5a "
-    "31 ed e1 ef 68 cb 63 98 d7 91 16 84 fe c0 ba bc "
-    "3a 78 1a 66 66 07 83 50 69 74 d0 e1 48 25 10 1c "
-    "3b fa ea ";
-
-char* signature_20 =
-    "92 75 02 b8 24 af c4 25 13 ca 65 70 de 33 8b 8a"
-    "64 c3 a8 5e b8 28 d3 19 36 24 f2 7e 8b 10 29 c5"
-    "5c 11 9c 97 33 b1 8f 58 49 b3 50 09 18 bc c0 05"
-    "51 d9 a8 fd f5 3a 97 74 9f a8 dc 48 0d 6f e9 74"
-    "2a 58 71 f9 73 92 65 28 97 2a 1a f4 9e 39 25 b0"
-    "ad f1 4a 84 27 19 b4 a5 a2 d8 9f a9 c0 b6 60 5d"
-    "21 2b ed 1e 67 23 b9 34 06 ad 30 e8 68 29 a5 c7"
-    "19 b8 90 b3 89 30 6d c5 50 64 86 ee 2f 36 a8 df"
-    "e0 a9 6a f6 78 c9 cb d6 af f3 97 ca 20 0e 3e dc"
-    "1e 36 bd 2f 08 b3 1d 54 0c 0c b2 82 a9 55 9e 4a"
-    "dd 4f c9 e6 49 2e ed 0c cb d3 a6 98 2e 5f aa 2d"
-    "dd 17 be 47 41 7c 80 b4 e5 45 2d 31 f7 24 01 a0"
-    "42 32 51 09 54 4d 95 4c 01 93 90 79 d4 09 a5 c3"
-    "78 d7 51 2d fc 2d 2a 71 ef cc 34 32 a7 65 d1 c6"
-    "a5 2c fc e8 99 cd 79 b1 5b 4f c3 72 36 41 ef 6b"
-    "d0 0a cc 10 40 7e 5d f5 8d d1 c3 c5 c5 59 a5 06";
-
-
-unsigned char* parsehex(char* str, int* len) {
-    // result can't be longer than input
-    unsigned char* result = malloc(strlen(str));
-
-    unsigned char* p = result;
-    *len = 0;
-
-    while (*str) {
-        int b;
-
-        while (isspace(*str)) str++;
-
-        switch (*str) {
-            case '0': case '1': case '2': case '3': case '4':
-            case '5': case '6': case '7': case '8': case '9':
-                b = (*str - '0') << 4; break;
-            case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
-                b = (*str - 'a' + 10) << 4; break;
-            case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
-                b = (*str - 'A' + 10) << 4; break;
-            case '\0':
-                return result;
-            default:
-                return NULL;
-        }
-        str++;
-
-        while (isspace(*str)) str++;
-
-        switch (*str) {
-            case '0': case '1': case '2': case '3': case '4':
-            case '5': case '6': case '7': case '8': case '9':
-                b |= *str - '0'; break;
-            case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
-                b |= *str - 'a' + 10; break;
-            case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
-                b |= *str - 'A' + 10; break;
-            default:
-                return NULL;
-        }
-        str++;
-
-        *p++ = b;
-        ++*len;
-    }
-
-    return result;
-}
-
-
-int main(int arg __unused, char** argv __unused) {
-
-    unsigned char hash[SHA_DIGEST_SIZE];
-
-    unsigned char* message;
-    int mlen;
-    unsigned char* signature;
-    int slen;
-
-#define TEST_MESSAGE(n) do {\
-    message = parsehex(message_##n, &mlen); \
-    SHA_hash(message, mlen, hash); \
-    signature = parsehex(signature_##n, &slen); \
-    int result = RSA_verify(&key_15, signature, slen, hash, sizeof(hash)); \
-    printf("message %d: %s\n", n, result ? "verified" : "not verified"); \
-    success = success && result; \
-    } while(0)
-
-    int success = 1;
-
-    TEST_MESSAGE(1);
-    TEST_MESSAGE(2);
-    TEST_MESSAGE(3);
-    TEST_MESSAGE(4);
-    TEST_MESSAGE(5);
-    TEST_MESSAGE(6);
-    TEST_MESSAGE(7);
-    TEST_MESSAGE(8);
-    TEST_MESSAGE(9);
-    TEST_MESSAGE(10);
-    TEST_MESSAGE(11);
-    TEST_MESSAGE(12);
-    TEST_MESSAGE(13);
-    TEST_MESSAGE(14);
-    TEST_MESSAGE(15);
-    TEST_MESSAGE(16);
-    TEST_MESSAGE(17);
-    TEST_MESSAGE(18);
-    TEST_MESSAGE(19);
-    TEST_MESSAGE(20);
-
-    printf("\n%s\n\n", success ? "PASS" : "FAIL");
-
-    return !success;
-}
diff --git a/libmincrypt/tools/DumpPublicKey.java b/libmincrypt/tools/DumpPublicKey.java
deleted file mode 100644
index 3eb1398..0000000
--- a/libmincrypt/tools/DumpPublicKey.java
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumpkey;
-
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-
-import java.io.FileInputStream;
-import java.math.BigInteger;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-import java.security.KeyStore;
-import java.security.Key;
-import java.security.PublicKey;
-import java.security.Security;
-import java.security.interfaces.ECPublicKey;
-import java.security.interfaces.RSAPublicKey;
-import java.security.spec.ECPoint;
-
-/**
- * Command line tool to extract RSA public keys from X.509 certificates
- * and output source code with data initializers for the keys.
- * @hide
- */
-class DumpPublicKey {
-    /**
-     * @param key to perform sanity checks on
-     * @return version number of key.  Supported versions are:
-     *     1: 2048-bit RSA key with e=3 and SHA-1 hash
-     *     2: 2048-bit RSA key with e=65537 and SHA-1 hash
-     *     3: 2048-bit RSA key with e=3 and SHA-256 hash
-     *     4: 2048-bit RSA key with e=65537 and SHA-256 hash
-     * @throws Exception if the key has the wrong size or public exponent
-     */
-    static int checkRSA(RSAPublicKey key, boolean useSHA256) throws Exception {
-        BigInteger pubexp = key.getPublicExponent();
-        BigInteger modulus = key.getModulus();
-        int version;
-
-        if (pubexp.equals(BigInteger.valueOf(3))) {
-            version = useSHA256 ? 3 : 1;
-        } else if (pubexp.equals(BigInteger.valueOf(65537))) {
-            version = useSHA256 ? 4 : 2;
-        } else {
-            throw new Exception("Public exponent should be 3 or 65537 but is " +
-                                pubexp.toString(10) + ".");
-        }
-
-        if (modulus.bitLength() != 2048) {
-             throw new Exception("Modulus should be 2048 bits long but is " +
-                        modulus.bitLength() + " bits.");
-        }
-
-        return version;
-    }
-
-    /**
-     * @param key to perform sanity checks on
-     * @return version number of key.  Supported versions are:
-     *     5: 256-bit EC key with curve NIST P-256
-     * @throws Exception if the key has the wrong size or public exponent
-     */
-    static int checkEC(ECPublicKey key) throws Exception {
-        if (key.getParams().getCurve().getField().getFieldSize() != 256) {
-            throw new Exception("Curve must be NIST P-256");
-        }
-
-        return 5;
-    }
-
-    /**
-     * Perform sanity check on public key.
-     */
-    static int check(PublicKey key, boolean useSHA256) throws Exception {
-        if (key instanceof RSAPublicKey) {
-            return checkRSA((RSAPublicKey) key, useSHA256);
-        } else if (key instanceof ECPublicKey) {
-            if (!useSHA256) {
-                throw new Exception("Must use SHA-256 with EC keys!");
-            }
-            return checkEC((ECPublicKey) key);
-        } else {
-            throw new Exception("Unsupported key class: " + key.getClass().getName());
-        }
-    }
-
-    /**
-     * @param key to output
-     * @return a String representing this public key.  If the key is a
-     *    version 1 key, the string will be a C initializer; this is
-     *    not true for newer key versions.
-     */
-    static String printRSA(RSAPublicKey key, boolean useSHA256) throws Exception {
-        int version = check(key, useSHA256);
-
-        BigInteger N = key.getModulus();
-
-        StringBuilder result = new StringBuilder();
-
-        int nwords = N.bitLength() / 32;    // # of 32 bit integers in modulus
-
-        if (version > 1) {
-            result.append("v");
-            result.append(Integer.toString(version));
-            result.append(" ");
-        }
-
-        result.append("{");
-        result.append(nwords);
-
-        BigInteger B = BigInteger.valueOf(0x100000000L);  // 2^32
-        BigInteger N0inv = B.subtract(N.modInverse(B));   // -1 / N[0] mod 2^32
-
-        result.append(",0x");
-        result.append(N0inv.toString(16));
-
-        BigInteger R = BigInteger.valueOf(2).pow(N.bitLength());
-        BigInteger RR = R.multiply(R).mod(N);    // 2^4096 mod N
-
-        // Write out modulus as little endian array of integers.
-        result.append(",{");
-        for (int i = 0; i < nwords; ++i) {
-            long n = N.mod(B).longValue();
-            result.append(n);
-
-            if (i != nwords - 1) {
-                result.append(",");
-            }
-
-            N = N.divide(B);
-        }
-        result.append("}");
-
-        // Write R^2 as little endian array of integers.
-        result.append(",{");
-        for (int i = 0; i < nwords; ++i) {
-            long rr = RR.mod(B).longValue();
-            result.append(rr);
-
-            if (i != nwords - 1) {
-                result.append(",");
-            }
-
-            RR = RR.divide(B);
-        }
-        result.append("}");
-
-        result.append("}");
-        return result.toString();
-    }
-
-    /**
-     * @param key to output
-     * @return a String representing this public key.  If the key is a
-     *    version 1 key, the string will be a C initializer; this is
-     *    not true for newer key versions.
-     */
-    static String printEC(ECPublicKey key) throws Exception {
-        int version = checkEC(key);
-
-        StringBuilder result = new StringBuilder();
-
-        result.append("v");
-        result.append(Integer.toString(version));
-        result.append(" ");
-
-        BigInteger X = key.getW().getAffineX();
-        BigInteger Y = key.getW().getAffineY();
-        int nbytes = key.getParams().getCurve().getField().getFieldSize() / 8;    // # of 32 bit integers in X coordinate
-
-        result.append("{");
-        result.append(nbytes);
-
-        BigInteger B = BigInteger.valueOf(0x100L);  // 2^8
-
-        // Write out Y coordinate as array of characters.
-        result.append(",{");
-        for (int i = 0; i < nbytes; ++i) {
-            long n = X.mod(B).longValue();
-            result.append(n);
-
-            if (i != nbytes - 1) {
-                result.append(",");
-            }
-
-            X = X.divide(B);
-        }
-        result.append("}");
-
-        // Write out Y coordinate as array of characters.
-        result.append(",{");
-        for (int i = 0; i < nbytes; ++i) {
-            long n = Y.mod(B).longValue();
-            result.append(n);
-
-            if (i != nbytes - 1) {
-                result.append(",");
-            }
-
-            Y = Y.divide(B);
-        }
-        result.append("}");
-
-        result.append("}");
-        return result.toString();
-    }
-
-    static String print(PublicKey key, boolean useSHA256) throws Exception {
-        if (key instanceof RSAPublicKey) {
-            return printRSA((RSAPublicKey) key, useSHA256);
-        } else if (key instanceof ECPublicKey) {
-            return printEC((ECPublicKey) key);
-        } else {
-            throw new Exception("Unsupported key class: " + key.getClass().getName());
-        }
-    }
-
-    public static void main(String[] args) {
-        if (args.length < 1) {
-            System.err.println("Usage: DumpPublicKey certfile ... > source.c");
-            System.exit(1);
-        }
-        Security.addProvider(new BouncyCastleProvider());
-        try {
-            for (int i = 0; i < args.length; i++) {
-                FileInputStream input = new FileInputStream(args[i]);
-                CertificateFactory cf = CertificateFactory.getInstance("X.509");
-                X509Certificate cert = (X509Certificate) cf.generateCertificate(input);
-
-                boolean useSHA256 = false;
-                String sigAlg = cert.getSigAlgName();
-                if ("SHA1withRSA".equals(sigAlg) || "MD5withRSA".equals(sigAlg)) {
-                    // SignApk has historically accepted "MD5withRSA"
-                    // certificates, but treated them as "SHA1withRSA"
-                    // anyway.  Continue to do so for backwards
-                    // compatibility.
-                  useSHA256 = false;
-                } else if ("SHA256withRSA".equals(sigAlg) || "SHA256withECDSA".equals(sigAlg)) {
-                  useSHA256 = true;
-                } else {
-                  System.err.println(args[i] + ": unsupported signature algorithm \"" +
-                                     sigAlg + "\"");
-                  System.exit(1);
-                }
-
-                PublicKey key = cert.getPublicKey();
-                check(key, useSHA256);
-                System.out.print(print(key, useSHA256));
-                System.out.println(i < args.length - 1 ? "," : "");
-            }
-        } catch (Exception e) {
-            e.printStackTrace();
-            System.exit(1);
-        }
-        System.exit(0);
-    }
-}
diff --git a/libmincrypt/tools/DumpPublicKey.mf b/libmincrypt/tools/DumpPublicKey.mf
deleted file mode 100644
index 7bb3bc8..0000000
--- a/libmincrypt/tools/DumpPublicKey.mf
+++ /dev/null
@@ -1 +0,0 @@
-Main-Class: com.android.dumpkey.DumpPublicKey
diff --git a/libnativebridge/Android.bp b/libnativebridge/Android.bp
new file mode 100644
index 0000000..5fb56f2
--- /dev/null
+++ b/libnativebridge/Android.bp
@@ -0,0 +1,24 @@
+
+cc_library {
+    name: "libnativebridge",
+
+    host_supported: true,
+    srcs: ["native_bridge.cc"],
+    shared_libs: ["liblog"],
+    clang: true,
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+    cppflags: [
+        "-fvisibility=protected",
+    ],
+
+    host_ldlibs: ["-ldl"],
+    target: {
+        android: {
+            shared_libs: ["libdl"],
+        },
+    },
+}
diff --git a/libnativebridge/Android.mk b/libnativebridge/Android.mk
index d20d44c..3887b1b 100644
--- a/libnativebridge/Android.mk
+++ b/libnativebridge/Android.mk
@@ -1,58 +1,3 @@
 LOCAL_PATH:= $(call my-dir)
 
-NATIVE_BRIDGE_COMMON_SRC_FILES := \
-  native_bridge.cc
-
-# Shared library for target
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_CLANG := true
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
-LOCAL_LDFLAGS := -ldl
-LOCAL_MULTILIB := both
-
-include $(BUILD_SHARED_LIBRARY)
-
-# Shared library for host
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_CLANG := true
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
-LOCAL_LDFLAGS := -ldl
-LOCAL_MULTILIB := both
-
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-# Static library for host
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
-LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_CLANG := true
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
-LOCAL_LDFLAGS := -ldl
-LOCAL_MULTILIB := both
-
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-
 include $(LOCAL_PATH)/tests/Android.mk
diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc
index 32a65ea..eafc53d 100644
--- a/libnativebridge/native_bridge.cc
+++ b/libnativebridge/native_bridge.cc
@@ -14,17 +14,21 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "nativebridge"
+
 #include "nativebridge/native_bridge.h"
 
-#include <cstring>
-#include <cutils/log.h>
 #include <dlfcn.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
+#include <unistd.h>
 
+#include <cstring>
+
+#include <android/log.h>
 
 namespace android {
 
@@ -76,6 +80,19 @@
 // Current state of the native bridge.
 static NativeBridgeState state = NativeBridgeState::kNotSetup;
 
+// The version of NativeBridge implementation.
+// Different Nativebridge interface needs the service of different version of
+// Nativebridge implementation.
+// Used by isCompatibleWith() which is introduced in v2.
+enum NativeBridgeImplementationVersion {
+    // first version, not used.
+    DEFAULT_VERSION = 1,
+    // The version which signal semantic is introduced.
+    SIGNAL_VERSION = 2,
+    // The version which namespace semantic is introduced.
+    NAMESPACE_VERSION = 3,
+};
+
 // Whether we had an error at some point.
 static bool had_error = false;
 
@@ -96,8 +113,6 @@
 // and hard code the directory name again here.
 static constexpr const char* kCodeCacheDir = "code_cache";
 
-static constexpr uint32_t kLibNativeBridgeVersion = 2;
-
 // Characters allowed in a native bridge filename. The first character must
 // be in [a-zA-Z] (expected 'l' for "libx"). The rest must be in [a-zA-Z0-9._-].
 static bool CharacterAllowed(char c, bool first) {
@@ -148,19 +163,18 @@
   }
 }
 
-static bool VersionCheck(const NativeBridgeCallbacks* cb) {
+// The policy of invoking Nativebridge changed in v3 with/without namespace.
+// Suggest Nativebridge implementation not maintain backward-compatible.
+static bool isCompatibleWith(const uint32_t version) {
   // Libnativebridge is now designed to be forward-compatible. So only "0" is an unsupported
   // version.
-  if (cb == nullptr || cb->version == 0) {
+  if (callbacks == nullptr || callbacks->version == 0 || version == 0) {
     return false;
   }
 
   // If this is a v2+ bridge, it may not be forwards- or backwards-compatible. Check.
-  if (cb->version >= 2) {
-    if (!callbacks->isCompatibleWith(kLibNativeBridgeVersion)) {
-      // TODO: Scan which version is supported, and fall back to handle it.
-      return false;
-    }
+  if (callbacks->version >= SIGNAL_VERSION) {
+    return callbacks->isCompatibleWith(version);
   }
 
   return true;
@@ -201,7 +215,7 @@
         callbacks = reinterpret_cast<NativeBridgeCallbacks*>(dlsym(handle,
                                                                    kNativeBridgeInterfaceSymbol));
         if (callbacks != nullptr) {
-          if (VersionCheck(callbacks)) {
+          if (isCompatibleWith(NAMESPACE_VERSION)) {
             // Store the handle for later.
             native_bridge_handle = handle;
           } else {
@@ -231,8 +245,10 @@
 static const char* kRuntimeISA = "arm";
 #elif defined(__aarch64__)
 static const char* kRuntimeISA = "arm64";
-#elif defined(__mips__)
+#elif defined(__mips__) && !defined(__LP64__)
 static const char* kRuntimeISA = "mips";
+#elif defined(__mips__) && defined(__LP64__)
+static const char* kRuntimeISA = "mips64";
 #elif defined(__i386__)
 static const char* kRuntimeISA = "x86";
 #elif defined(__x86_64__)
@@ -514,8 +530,91 @@
 }
 
 NativeBridgeSignalHandlerFn NativeBridgeGetSignalHandler(int signal) {
-  if (NativeBridgeInitialized() && callbacks->version >= 2) {
-    return callbacks->getSignalHandler(signal);
+  if (NativeBridgeInitialized()) {
+    if (isCompatibleWith(SIGNAL_VERSION)) {
+      return callbacks->getSignalHandler(signal);
+    } else {
+      ALOGE("not compatible with version %d, cannot get signal handler", SIGNAL_VERSION);
+    }
+  }
+  return nullptr;
+}
+
+int NativeBridgeUnloadLibrary(void* handle) {
+  if (NativeBridgeInitialized()) {
+    if (isCompatibleWith(NAMESPACE_VERSION)) {
+      return callbacks->unloadLibrary(handle);
+    } else {
+      ALOGE("not compatible with version %d, cannot unload library", NAMESPACE_VERSION);
+    }
+  }
+  return -1;
+}
+
+const char* NativeBridgeGetError() {
+  if (NativeBridgeInitialized()) {
+    if (isCompatibleWith(NAMESPACE_VERSION)) {
+      return callbacks->getError();
+    } else {
+      return "native bridge implementation is not compatible with version 3, cannot get message";
+    }
+  }
+  return "native bridge is not initialized";
+}
+
+bool NativeBridgeIsPathSupported(const char* path) {
+  if (NativeBridgeInitialized()) {
+    if (isCompatibleWith(NAMESPACE_VERSION)) {
+      return callbacks->isPathSupported(path);
+    } else {
+      ALOGE("not compatible with version %d, cannot check via library path", NAMESPACE_VERSION);
+    }
+  }
+  return false;
+}
+
+bool NativeBridgeInitNamespace(const char* public_ns_sonames,
+                               const char* anon_ns_library_path) {
+  if (NativeBridgeInitialized()) {
+    if (isCompatibleWith(NAMESPACE_VERSION)) {
+      return callbacks->initNamespace(public_ns_sonames, anon_ns_library_path);
+    } else {
+      ALOGE("not compatible with version %d, cannot init namespace", NAMESPACE_VERSION);
+    }
+  }
+
+  return false;
+}
+
+native_bridge_namespace_t* NativeBridgeCreateNamespace(const char* name,
+                                                       const char* ld_library_path,
+                                                       const char* default_library_path,
+                                                       uint64_t type,
+                                                       const char* permitted_when_isolated_path,
+                                                       native_bridge_namespace_t* parent_ns) {
+  if (NativeBridgeInitialized()) {
+    if (isCompatibleWith(NAMESPACE_VERSION)) {
+      return callbacks->createNamespace(name,
+                                        ld_library_path,
+                                        default_library_path,
+                                        type,
+                                        permitted_when_isolated_path,
+                                        parent_ns);
+    } else {
+      ALOGE("not compatible with version %d, cannot create namespace %s", NAMESPACE_VERSION, name);
+    }
+  }
+
+  return nullptr;
+}
+
+void* NativeBridgeLoadLibraryExt(const char* libpath, int flag, native_bridge_namespace_t* ns) {
+  if (NativeBridgeInitialized()) {
+    if (isCompatibleWith(NAMESPACE_VERSION)) {
+      return callbacks->loadLibraryExt(libpath, flag, ns);
+    } else {
+      ALOGE("not compatible with version %d, cannot load library in namespace", NAMESPACE_VERSION);
+    }
   }
   return nullptr;
 }
diff --git a/libnativebridge/tests/Android.mk b/libnativebridge/tests/Android.mk
index 7265939..4c3e862 100644
--- a/libnativebridge/tests/Android.mk
+++ b/libnativebridge/tests/Android.mk
@@ -20,7 +20,13 @@
     PreInitializeNativeBridgeFail2_test.cpp \
     ReSetupNativeBridge_test.cpp \
     UnavailableNativeBridge_test.cpp \
-    ValidNameNativeBridge_test.cpp
+    ValidNameNativeBridge_test.cpp \
+    NativeBridge3UnloadLibrary_test.cpp \
+    NativeBridge3GetError_test.cpp \
+    NativeBridge3IsPathSupported_test.cpp \
+    NativeBridge3InitNamespace_test.cpp \
+    NativeBridge3CreateNamespace_test.cpp \
+    NativeBridge3LoadLibraryExt_test.cpp
 
 
 shared_libraries := \
@@ -31,7 +37,6 @@
 $(foreach file,$(test_src_files), \
     $(eval include $(CLEAR_VARS)) \
     $(eval LOCAL_CLANG := true) \
-    $(eval LOCAL_CPPFLAGS := -std=gnu++11) \
     $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
     $(eval LOCAL_SRC_FILES := $(file)) \
     $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
@@ -41,7 +46,6 @@
 $(foreach file,$(test_src_files), \
     $(eval include $(CLEAR_VARS)) \
     $(eval LOCAL_CLANG := true) \
-    $(eval LOCAL_CPPFLAGS := -std=gnu++11) \
     $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
     $(eval LOCAL_SRC_FILES := $(file)) \
     $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
diff --git a/libnativebridge/tests/Android.nativebridge-dummy.mk b/libnativebridge/tests/Android.nativebridge-dummy.mk
index 2efc176..2d78be0 100644
--- a/libnativebridge/tests/Android.nativebridge-dummy.mk
+++ b/libnativebridge/tests/Android.nativebridge-dummy.mk
@@ -12,8 +12,8 @@
 LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
 LOCAL_CLANG := true
 LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
-LOCAL_LDFLAGS := -ldl
+LOCAL_CPPFLAGS := -fvisibility=protected
+LOCAL_SHARED_LIBRARIES := libdl
 LOCAL_MULTILIB := both
 
 include $(BUILD_SHARED_LIBRARY)
@@ -27,7 +27,7 @@
 LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
 LOCAL_CLANG := true
 LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
+LOCAL_CPPFLAGS := -fvisibility=protected
 LOCAL_LDFLAGS := -ldl
 LOCAL_MULTILIB := both
 
@@ -48,8 +48,8 @@
 LOCAL_SRC_FILES:= $(NATIVE_BRIDGE2_COMMON_SRC_FILES)
 LOCAL_CLANG := true
 LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
-LOCAL_LDFLAGS := -ldl
+LOCAL_CPPFLAGS := -fvisibility=protected
+LOCAL_SHARED_LIBRARIES := libdl
 LOCAL_MULTILIB := both
 
 include $(BUILD_SHARED_LIBRARY)
@@ -63,8 +63,46 @@
 LOCAL_SRC_FILES:= $(NATIVE_BRIDGE2_COMMON_SRC_FILES)
 LOCAL_CLANG := true
 LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CPPFLAGS := -fvisibility=protected
+LOCAL_LDFLAGS := -ldl
+LOCAL_MULTILIB := both
+
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+
+# v3.
+
+NATIVE_BRIDGE3_COMMON_SRC_FILES := \
+  DummyNativeBridge3.cpp
+
+# Shared library for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libnativebridge3-dummy
+
+LOCAL_SRC_FILES:= $(NATIVE_BRIDGE3_COMMON_SRC_FILES)
+LOCAL_CLANG := true
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
+LOCAL_LDFLAGS := -ldl
+LOCAL_MULTILIB := both
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Shared library for host
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libnativebridge3-dummy
+
+LOCAL_SRC_FILES:= $(NATIVE_BRIDGE3_COMMON_SRC_FILES)
+LOCAL_CLANG := true
+LOCAL_CFLAGS += -Werror -Wall
 LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
 LOCAL_LDFLAGS := -ldl
 LOCAL_MULTILIB := both
 
 include $(BUILD_HOST_SHARED_LIBRARY)
+
+
diff --git a/libnativebridge/tests/DummyNativeBridge3.cpp b/libnativebridge/tests/DummyNativeBridge3.cpp
new file mode 100644
index 0000000..13fce85
--- /dev/null
+++ b/libnativebridge/tests/DummyNativeBridge3.cpp
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+// A dummy implementation of the native-bridge interface.
+
+#include "nativebridge/native_bridge.h"
+
+#include <signal.h>
+
+// NativeBridgeCallbacks implementations
+extern "C" bool native_bridge3_initialize(
+                      const android::NativeBridgeRuntimeCallbacks* /* art_cbs */,
+                      const char* /* app_code_cache_dir */,
+                      const char* /* isa */) {
+  return true;
+}
+
+extern "C" void* native_bridge3_loadLibrary(const char* /* libpath */, int /* flag */) {
+  return nullptr;
+}
+
+extern "C" void* native_bridge3_getTrampoline(void* /* handle */, const char* /* name */,
+                                             const char* /* shorty */, uint32_t /* len */) {
+  return nullptr;
+}
+
+extern "C" bool native_bridge3_isSupported(const char* /* libpath */) {
+  return false;
+}
+
+extern "C" const struct android::NativeBridgeRuntimeValues* native_bridge3_getAppEnv(
+    const char* /* abi */) {
+  return nullptr;
+}
+
+extern "C" bool native_bridge3_isCompatibleWith(uint32_t version) {
+  // For testing, allow 1-3, but disallow 4+.
+  return version <= 3;
+}
+
+static bool native_bridge3_dummy_signal_handler(int, siginfo_t*, void*) {
+  // TODO: Implement something here. We'd either have to have a death test with a log here, or
+  //       we'd have to be able to resume after the faulting instruction...
+  return true;
+}
+
+extern "C" android::NativeBridgeSignalHandlerFn native_bridge3_getSignalHandler(int signal) {
+  if (signal == SIGSEGV) {
+    return &native_bridge3_dummy_signal_handler;
+  }
+  return nullptr;
+}
+
+extern "C" int native_bridge3_unloadLibrary(void* /* handle */) {
+  return 0;
+}
+
+extern "C" const char* native_bridge3_getError() {
+  return nullptr;
+}
+
+extern "C" bool native_bridge3_isPathSupported(const char* /* path */) {
+  return true;
+}
+
+extern "C" bool native_bridge3_initNamespace(const char* /* public_ns_sonames */,
+                                        const char* /* anon_ns_library_path */) {
+  return true;
+}
+
+extern "C" android::native_bridge_namespace_t*
+native_bridge3_createNamespace(const char* /* name */,
+                               const char* /* ld_library_path */,
+                               const char* /* default_library_path */,
+                               uint64_t /* type */,
+                               const char* /* permitted_when_isolated_path */,
+                               android::native_bridge_namespace_t* /* parent_ns */) {
+  return nullptr;
+}
+
+extern "C" void* native_bridge3_loadLibraryExt(const char* /* libpath */,
+                                               int /* flag */,
+                                               android::native_bridge_namespace_t* /* ns */) {
+  return nullptr;
+}
+
+
+android::NativeBridgeCallbacks NativeBridgeItf {
+  // v1
+  .version = 3,
+  .initialize = &native_bridge3_initialize,
+  .loadLibrary = &native_bridge3_loadLibrary,
+  .getTrampoline = &native_bridge3_getTrampoline,
+  .isSupported = &native_bridge3_isSupported,
+  .getAppEnv = &native_bridge3_getAppEnv,
+  // v2
+  .isCompatibleWith = &native_bridge3_isCompatibleWith,
+  .getSignalHandler = &native_bridge3_getSignalHandler,
+  // v3
+  .unloadLibrary = &native_bridge3_unloadLibrary,
+  .getError = &native_bridge3_getError,
+  .isPathSupported  = &native_bridge3_isPathSupported,
+  .initNamespace = &native_bridge3_initNamespace,
+  .createNamespace = &native_bridge3_createNamespace,
+  .loadLibraryExt = &native_bridge3_loadLibraryExt
+};
+
diff --git a/libnativebridge/tests/NativeBridge3CreateNamespace_test.cpp b/libnativebridge/tests/NativeBridge3CreateNamespace_test.cpp
new file mode 100644
index 0000000..668d942
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3CreateNamespace_test.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_CreateNamespace) {
+    // Init
+    ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+
+    ASSERT_EQ(3U, NativeBridgeGetVersion());
+    ASSERT_EQ(nullptr, NativeBridgeCreateNamespace(nullptr, nullptr, nullptr,
+                                                   0, nullptr, nullptr));
+
+    // Clean-up code_cache
+    ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+}  // namespace android
diff --git a/libnativebridge/tests/NativeBridge3GetError_test.cpp b/libnativebridge/tests/NativeBridge3GetError_test.cpp
new file mode 100644
index 0000000..0b9f582
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3GetError_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_GetError) {
+    // Init
+    ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+
+    ASSERT_EQ(3U, NativeBridgeGetVersion());
+    ASSERT_EQ(nullptr, NativeBridgeGetError());
+
+    // Clean-up code_cache
+    ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+}  // namespace android
diff --git a/libnativebridge/tests/NativeBridge3InitNamespace_test.cpp b/libnativebridge/tests/NativeBridge3InitNamespace_test.cpp
new file mode 100644
index 0000000..ae0fd2b
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3InitNamespace_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_InitNamespace) {
+    // Init
+    ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+
+    ASSERT_EQ(3U, NativeBridgeGetVersion());
+    ASSERT_EQ(true, NativeBridgeInitNamespace(nullptr, nullptr));
+
+    // Clean-up code_cache
+    ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+}  // namespace android
diff --git a/libnativebridge/tests/NativeBridge3IsPathSupported_test.cpp b/libnativebridge/tests/NativeBridge3IsPathSupported_test.cpp
new file mode 100644
index 0000000..325e40b
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3IsPathSupported_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_IsPathSupported) {
+    // Init
+    ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+
+    ASSERT_EQ(3U, NativeBridgeGetVersion());
+    ASSERT_EQ(true, NativeBridgeIsPathSupported(nullptr));
+
+    // Clean-up code_cache
+    ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+}  // namespace android
diff --git a/libnativebridge/tests/NativeBridge3LoadLibraryExt_test.cpp b/libnativebridge/tests/NativeBridge3LoadLibraryExt_test.cpp
new file mode 100644
index 0000000..4caeb44
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3LoadLibraryExt_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_LoadLibraryExt) {
+    // Init
+    ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+
+    ASSERT_EQ(3U, NativeBridgeGetVersion());
+    ASSERT_EQ(nullptr, NativeBridgeLoadLibraryExt(nullptr, 0, nullptr));
+
+    // Clean-up code_cache
+    ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+}  // namespace android
diff --git a/libnativebridge/tests/NativeBridge3UnloadLibrary_test.cpp b/libnativebridge/tests/NativeBridge3UnloadLibrary_test.cpp
new file mode 100644
index 0000000..93a979c
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3UnloadLibrary_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_UnloadLibrary) {
+    // Init
+    ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+
+    ASSERT_EQ(3U, NativeBridgeGetVersion());
+    ASSERT_EQ(0, NativeBridgeUnloadLibrary(nullptr));
+
+    // Clean-up code_cache
+    ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+}  // namespace android
diff --git a/libnativebridge/tests/NativeBridgeTest.h b/libnativebridge/tests/NativeBridgeTest.h
index d489420..0f99816 100644
--- a/libnativebridge/tests/NativeBridgeTest.h
+++ b/libnativebridge/tests/NativeBridgeTest.h
@@ -25,6 +25,8 @@
 constexpr const char* kNativeBridgeLibrary = "libnativebridge-dummy.so";
 constexpr const char* kCodeCache = "./code_cache";
 constexpr const char* kCodeCacheStatFail = "./code_cache/temp";
+constexpr const char* kNativeBridgeLibrary2 = "libnativebridge2-dummy.so";
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
 
 namespace android {
 
diff --git a/libnativebridge/tests/NeedsNativeBridge_test.cpp b/libnativebridge/tests/NeedsNativeBridge_test.cpp
index e1c0876..2067ed2 100644
--- a/libnativebridge/tests/NeedsNativeBridge_test.cpp
+++ b/libnativebridge/tests/NeedsNativeBridge_test.cpp
@@ -18,15 +18,17 @@
 
 namespace android {
 
-static const char* kISAs[] = { "arm", "arm64", "mips", "x86", "x86_64", "random", "64arm", "64_x86",
-                               "64_x86_64", "", "reallylongstringabcd", nullptr };
+static const char* kISAs[] = { "arm", "arm64", "mips", "mips64", "x86", "x86_64", "random", "64arm",
+                               "64_x86", "64_x86_64", "", "reallylongstringabcd", nullptr };
 
 #if defined(__arm__)
 static const char* kRuntimeISA = "arm";
 #elif defined(__aarch64__)
 static const char* kRuntimeISA = "arm64";
-#elif defined(__mips__)
+#elif defined(__mips__) && !defined(__LP64__)
 static const char* kRuntimeISA = "mips";
+#elif defined(__mips__) && defined(__LP64__)
+static const char* kRuntimeISA = "mips64";
 #elif defined(__i386__)
 static const char* kRuntimeISA = "x86";
 #elif defined(__x86_64__)
diff --git a/libnativebridge/tests/PreInitializeNativeBridgeFail1_test.cpp b/libnativebridge/tests/PreInitializeNativeBridgeFail1_test.cpp
index 69c30a1..5a2b0a1 100644
--- a/libnativebridge/tests/PreInitializeNativeBridgeFail1_test.cpp
+++ b/libnativebridge/tests/PreInitializeNativeBridgeFail1_test.cpp
@@ -16,9 +16,6 @@
 
 #include "NativeBridgeTest.h"
 
-#include <cstdio>
-#include <cstring>
-#include <cutils/log.h>
 #include <dlfcn.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -26,6 +23,11 @@
 #include <sys/mount.h>
 #include <sys/stat.h>
 
+#include <cstdio>
+#include <cstring>
+
+#include <android/log.h>
+
 namespace android {
 
 TEST_F(NativeBridgeTest, PreInitializeNativeBridgeFail1) {
diff --git a/libnativebridge/tests/PreInitializeNativeBridgeFail2_test.cpp b/libnativebridge/tests/PreInitializeNativeBridgeFail2_test.cpp
index 74e96e0..af976b1 100644
--- a/libnativebridge/tests/PreInitializeNativeBridgeFail2_test.cpp
+++ b/libnativebridge/tests/PreInitializeNativeBridgeFail2_test.cpp
@@ -14,11 +14,6 @@
  * limitations under the License.
  */
 
-#include "NativeBridgeTest.h"
-
-#include <cstdio>
-#include <cstring>
-#include <cutils/log.h>
 #include <dlfcn.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -26,6 +21,13 @@
 #include <sys/mount.h>
 #include <sys/stat.h>
 
+#include <cstdio>
+#include <cstring>
+
+#include <android/log.h>
+
+#include "NativeBridgeTest.h"
+
 namespace android {
 
 TEST_F(NativeBridgeTest, PreInitializeNativeBridgeFail2) {
diff --git a/libnativebridge/tests/PreInitializeNativeBridge_test.cpp b/libnativebridge/tests/PreInitializeNativeBridge_test.cpp
index d3bbebe..f3e5f38 100644
--- a/libnativebridge/tests/PreInitializeNativeBridge_test.cpp
+++ b/libnativebridge/tests/PreInitializeNativeBridge_test.cpp
@@ -14,11 +14,6 @@
  * limitations under the License.
  */
 
-#include "NativeBridgeTest.h"
-
-#include <cstdio>
-#include <cstring>
-#include <cutils/log.h>
 #include <dlfcn.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -26,6 +21,13 @@
 #include <sys/mount.h>
 #include <sys/stat.h>
 
+#include <cstdio>
+#include <cstring>
+
+#include <android/log.h>
+
+#include "NativeBridgeTest.h"
+
 namespace android {
 
 static constexpr const char* kTestData = "PreInitializeNativeBridge test.";
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
new file mode 100644
index 0000000..9d33899
--- /dev/null
+++ b/libnativeloader/Android.bp
@@ -0,0 +1,32 @@
+// Shared library for target
+// ========================================================
+cc_library {
+    name: "libnativeloader",
+    host_supported: true,
+    srcs: ["native_loader.cpp"],
+    shared_libs: [
+        "libnativehelper",
+        "liblog",
+        "libcutils",
+        "libnativebridge",
+    ],
+    static_libs: ["libbase"],
+    target: {
+        android: {
+            shared_libs: ["libdl"],
+        },
+        host: {
+            host_ldlibs: ["-ldl"],
+        },
+    },
+    clang: true,
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+    cppflags: [
+        "-fvisibility=hidden",
+    ],
+    export_include_dirs: ["include"],
+    local_include_dirs: ["include"],
+}
diff --git a/libnativeloader/Android.mk b/libnativeloader/Android.mk
deleted file mode 100644
index 632c6c8..0000000
--- a/libnativeloader/Android.mk
+++ /dev/null
@@ -1,59 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-native_loader_common_src_files := \
-  native_loader.cpp
-
-native_loader_common_cflags := -Werror -Wall
-
-# Shared library for target
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativeloader
-
-LOCAL_SRC_FILES:= $(native_loader_common_src_files)
-LOCAL_SHARED_LIBRARIES := libnativehelper liblog libcutils
-LOCAL_STATIC_LIBRARIES := libbase
-LOCAL_CLANG := true
-LOCAL_CFLAGS := $(native_loader_common_cflags)
-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
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativeloader
-
-LOCAL_SRC_FILES:= $(native_loader_common_src_files)
-LOCAL_SHARED_LIBRARIES := libnativehelper liblog libcutils
-LOCAL_STATIC_LIBRARIES := libbase
-LOCAL_CLANG := true
-LOCAL_CFLAGS := $(native_loader_common_cflags)
-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
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativeloader
-
-LOCAL_SRC_FILES:= $(native_loader_common_src_files)
-LOCAL_STATIC_LIBRARIES := libnativehelper libcutils liblog libbase
-LOCAL_CLANG := true
-LOCAL_CFLAGS := $(native_loader_common_cflags)
-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/libnativeloader/include/nativeloader/native_loader.h b/libnativeloader/include/nativeloader/native_loader.h
index 2a6aaec..99ae3a7 100644
--- a/libnativeloader/include/nativeloader/native_loader.h
+++ b/libnativeloader/include/nativeloader/native_loader.h
@@ -19,6 +19,7 @@
 
 #include "jni.h"
 #include <stdint.h>
+#include <string>
 #if defined(__ANDROID__)
 #include <android/dlext.h>
 #endif
@@ -41,10 +42,12 @@
                         int32_t target_sdk_version,
                         const char* path,
                         jobject class_loader,
-                        jstring library_path);
+                        jstring library_path,
+                        bool* needs_native_bridge,
+                        std::string* error_msg);
 
 __attribute__((visibility("default")))
-bool CloseNativeLibrary(void* handle);
+bool CloseNativeLibrary(void* handle, const bool needs_native_bridge);
 
 #if defined(__ANDROID__)
 // Look up linker namespace by class_loader. Returns nullptr if
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index e35ed60..15fe054 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -20,25 +20,68 @@
 #include <dlfcn.h>
 #ifdef __ANDROID__
 #include "dlext_namespaces.h"
-#include "cutils/properties.h"
 #define LOG_TAG "libnativeloader"
-#include "log/log.h"
+#include "android/log.h"
+#include "cutils/properties.h"
 #endif
+#include "nativebridge/native_bridge.h"
 
 #include <algorithm>
 #include <vector>
 #include <string>
 #include <mutex>
 
-#include "android-base/file.h"
-#include "android-base/macros.h"
-#include "android-base/strings.h"
+#include <android-base/file.h>
+#include <android-base/macros.h>
+#include <android-base/strings.h>
+
+#define CHECK(predicate) LOG_ALWAYS_FATAL_IF(!(predicate),\
+                                             "%s:%d: %s CHECK '" #predicate "' failed.",\
+                                             __FILE__, __LINE__, __FUNCTION__)
 
 namespace android {
 
 #if defined(__ANDROID__)
-static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot = "/etc/public.libraries.txt";
-static constexpr const char* kPublicNativeLibrariesVendorConfig = "/vendor/etc/public.libraries.txt";
+class NativeLoaderNamespace {
+ public:
+  NativeLoaderNamespace()
+      : android_ns_(nullptr), native_bridge_ns_(nullptr) { }
+
+  explicit NativeLoaderNamespace(android_namespace_t* ns)
+      : android_ns_(ns), native_bridge_ns_(nullptr) { }
+
+  explicit NativeLoaderNamespace(native_bridge_namespace_t* ns)
+      : android_ns_(nullptr), native_bridge_ns_(ns) { }
+
+  NativeLoaderNamespace(NativeLoaderNamespace&& that) = default;
+  NativeLoaderNamespace(const NativeLoaderNamespace& that) = default;
+
+  NativeLoaderNamespace& operator=(const NativeLoaderNamespace& that) = default;
+
+  android_namespace_t* get_android_ns() const {
+    CHECK(native_bridge_ns_ == nullptr);
+    return android_ns_;
+  }
+
+  native_bridge_namespace_t* get_native_bridge_ns() const {
+    CHECK(android_ns_ == nullptr);
+    return native_bridge_ns_;
+  }
+
+  bool is_android_namespace() const {
+    return native_bridge_ns_ == nullptr;
+  }
+
+ private:
+  // Only one of them can be not null
+  android_namespace_t* android_ns_;
+  native_bridge_namespace_t* native_bridge_ns_;
+};
+
+static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot =
+                                  "/etc/public.libraries.txt";
+static constexpr const char* kPublicNativeLibrariesVendorConfig =
+                                  "/vendor/etc/public.libraries.txt";
 
 // (http://b/27588281) This is a workaround for apps using custom classloaders and calling
 // System.load() with an absolute path which is outside of the classloader library search path.
@@ -55,11 +98,13 @@
  public:
   LibraryNamespaces() : initialized_(false) { }
 
-  android_namespace_t* Create(JNIEnv* env,
-                              jobject class_loader,
-                              bool is_shared,
-                              jstring java_library_path,
-                              jstring java_permitted_path) {
+  bool Create(JNIEnv* env,
+              jobject class_loader,
+              bool is_shared,
+              jstring java_library_path,
+              jstring java_permitted_path,
+              NativeLoaderNamespace* ns,
+              std::string* error_msg) {
     std::string library_path; // empty string by default.
 
     if (java_library_path != nullptr) {
@@ -82,13 +127,13 @@
       }
     }
 
-    if (!initialized_ && !InitPublicNamespace(library_path.c_str())) {
-      return nullptr;
+    if (!initialized_ && !InitPublicNamespace(library_path.c_str(), error_msg)) {
+      return false;
     }
 
-    android_namespace_t* ns = FindNamespaceByClassLoader(env, class_loader);
+    bool found = FindNamespaceByClassLoader(env, class_loader, nullptr);
 
-    LOG_ALWAYS_FATAL_IF(ns != nullptr,
+    LOG_ALWAYS_FATAL_IF(found,
                         "There is already a namespace associated with this classloader");
 
     uint64_t namespace_type = ANDROID_NAMESPACE_TYPE_ISOLATED;
@@ -96,31 +141,76 @@
       namespace_type |= ANDROID_NAMESPACE_TYPE_SHARED;
     }
 
-    android_namespace_t* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
+    NativeLoaderNamespace parent_ns;
+    bool found_parent_namespace = FindParentNamespaceByClassLoader(env, class_loader, &parent_ns);
 
-    ns = android_create_namespace("classloader-namespace",
-                                  nullptr,
-                                  library_path.c_str(),
-                                  namespace_type,
-                                  permitted_path.c_str(),
-                                  parent_ns);
+    bool is_native_bridge = false;
 
-    if (ns != nullptr) {
-      namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), ns));
+    if (found_parent_namespace) {
+      is_native_bridge = !parent_ns.is_android_namespace();
+    } else if (!library_path.empty()) {
+      is_native_bridge = NativeBridgeIsPathSupported(library_path.c_str());
     }
 
-    return ns;
+    NativeLoaderNamespace native_loader_ns;
+    if (!is_native_bridge) {
+      android_namespace_t* ns = android_create_namespace("classloader-namespace",
+                                                         nullptr,
+                                                         library_path.c_str(),
+                                                         namespace_type,
+                                                         permitted_path.c_str(),
+                                                         parent_ns.get_android_ns());
+      if (ns == nullptr) {
+        *error_msg = dlerror();
+        return false;
+      }
+
+      native_loader_ns = NativeLoaderNamespace(ns);
+    } else {
+      native_bridge_namespace_t* ns = NativeBridgeCreateNamespace("classloader-namespace",
+                                                                  nullptr,
+                                                                  library_path.c_str(),
+                                                                  namespace_type,
+                                                                  permitted_path.c_str(),
+                                                                  parent_ns.get_native_bridge_ns());
+      if (ns == nullptr) {
+        *error_msg = NativeBridgeGetError();
+        return false;
+      }
+
+      native_loader_ns = NativeLoaderNamespace(ns);
+    }
+
+    namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), native_loader_ns));
+
+    *ns = native_loader_ns;
+    return true;
   }
 
-  android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
+  bool FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader, NativeLoaderNamespace* ns) {
     auto it = std::find_if(namespaces_.begin(), namespaces_.end(),
-                [&](const std::pair<jweak, android_namespace_t*>& value) {
+                [&](const std::pair<jweak, NativeLoaderNamespace>& value) {
                   return env->IsSameObject(value.first, class_loader);
                 });
-    return it != namespaces_.end() ? it->second : nullptr;
+    if (it != namespaces_.end()) {
+      if (ns != nullptr) {
+        *ns = it->second;
+      }
+
+      return true;
+    }
+
+    return false;
   }
 
   void Initialize() {
+    // Once public namespace is initialized there is no
+    // point in running this code - it will have no effect
+    // on the current list of public libraries.
+    if (initialized_) {
+      return;
+    }
+
     std::vector<std::string> sonames;
     const char* android_root_env = getenv("ANDROID_ROOT");
     std::string root_dir = android_root_env != nullptr ? android_root_env : "/system";
@@ -210,12 +300,29 @@
     return true;
   }
 
-  bool InitPublicNamespace(const char* library_path) {
+  bool InitPublicNamespace(const char* library_path, std::string* error_msg) {
+    // Ask native bride if this apps library path should be handled by it
+    bool is_native_bridge = NativeBridgeIsPathSupported(library_path);
+
     // (http://b/25844435) - Some apps call dlopen from generated code (mono jited
     // code is one example) unknown to linker in which  case linker uses anonymous
     // namespace. The second argument specifies the search path for the anonymous
     // namespace which is the library_path of the classloader.
-    initialized_ = android_init_namespaces(public_libraries_.c_str(), library_path);
+    initialized_ = android_init_namespaces(public_libraries_.c_str(),
+                                           is_native_bridge ? nullptr : library_path);
+    if (!initialized_) {
+      *error_msg = dlerror();
+      return false;
+    }
+
+    // and now initialize native bridge namespaces if necessary.
+    if (NativeBridgeInitialized()) {
+      initialized_ = NativeBridgeInitNamespace(public_libraries_.c_str(),
+                                               is_native_bridge ? library_path : nullptr);
+      if (!initialized_) {
+        *error_msg = NativeBridgeGetError();
+      }
+    }
 
     return initialized_;
   }
@@ -229,22 +336,24 @@
     return env->CallObjectMethod(class_loader, get_parent);
   }
 
-  android_namespace_t* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
+  bool FindParentNamespaceByClassLoader(JNIEnv* env,
+                                        jobject class_loader,
+                                        NativeLoaderNamespace* ns) {
     jobject parent_class_loader = GetParentClassLoader(env, class_loader);
 
     while (parent_class_loader != nullptr) {
-      android_namespace_t* ns = FindNamespaceByClassLoader(env, parent_class_loader);
-      if (ns != nullptr) {
-        return ns;
+      if (FindNamespaceByClassLoader(env, parent_class_loader, ns)) {
+        return true;
       }
 
       parent_class_loader = GetParentClassLoader(env, parent_class_loader);
     }
-    return nullptr;
+
+    return false;
   }
 
   bool initialized_;
-  std::vector<std::pair<jweak, android_namespace_t*>> namespaces_;
+  std::vector<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
   std::string public_libraries_;
 
 
@@ -278,13 +387,18 @@
 #if defined(__ANDROID__)
   UNUSED(target_sdk_version);
   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
-  android_namespace_t* ns = g_namespaces->Create(env,
-                                                 class_loader,
-                                                 is_shared,
-                                                 library_path,
-                                                 permitted_path);
-  if (ns == nullptr) {
-    return env->NewStringUTF(dlerror());
+
+  std::string error_msg;
+  NativeLoaderNamespace ns;
+  bool success = g_namespaces->Create(env,
+                                      class_loader,
+                                      is_shared,
+                                      library_path,
+                                      permitted_path,
+                                      &ns,
+                                      &error_msg);
+  if (!success) {
+    return env->NewStringUTF(error_msg.c_str());
   }
 #else
   UNUSED(env, target_sdk_version, class_loader, is_shared,
@@ -297,44 +411,83 @@
                         int32_t target_sdk_version,
                         const char* path,
                         jobject class_loader,
-                        jstring library_path) {
+                        jstring library_path,
+                        bool* needs_native_bridge,
+                        std::string* error_msg) {
 #if defined(__ANDROID__)
   UNUSED(target_sdk_version);
   if (class_loader == nullptr) {
+    *needs_native_bridge = false;
     return dlopen(path, RTLD_NOW);
   }
 
   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
-  android_namespace_t* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader);
+  NativeLoaderNamespace ns;
 
-  if (ns == nullptr) {
+  if (!g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
     // This is the case where the classloader was not created by ApplicationLoaders
     // In this case we create an isolated not-shared namespace for it.
-    ns = g_namespaces->Create(env, class_loader, false, library_path, nullptr);
-    if (ns == nullptr) {
+    if (!g_namespaces->Create(env, class_loader, false, library_path, nullptr, &ns, error_msg)) {
       return nullptr;
     }
   }
 
-  android_dlextinfo extinfo;
-  extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
-  extinfo.library_namespace = ns;
+  if (ns.is_android_namespace()) {
+    android_dlextinfo extinfo;
+    extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+    extinfo.library_namespace = ns.get_android_ns();
 
-  return android_dlopen_ext(path, RTLD_NOW, &extinfo);
+    void* handle = android_dlopen_ext(path, RTLD_NOW, &extinfo);
+    if (handle == nullptr) {
+      *error_msg = dlerror();
+    }
+    *needs_native_bridge = false;
+    return handle;
+  } else {
+    void* handle = NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns.get_native_bridge_ns());
+    if (handle == nullptr) {
+      *error_msg = NativeBridgeGetError();
+    }
+    *needs_native_bridge = true;
+    return handle;
+  }
 #else
   UNUSED(env, target_sdk_version, class_loader, library_path);
-  return dlopen(path, RTLD_NOW);
+  *needs_native_bridge = false;
+  void* handle = dlopen(path, RTLD_NOW);
+  if (handle == nullptr) {
+    if (NativeBridgeIsSupported(path)) {
+      *needs_native_bridge = true;
+      handle = NativeBridgeLoadLibrary(path, RTLD_NOW);
+      if (handle == nullptr) {
+        *error_msg = NativeBridgeGetError();
+      }
+    } else {
+      *needs_native_bridge = false;
+      *error_msg = dlerror();
+    }
+  }
+  return handle;
 #endif
 }
 
-bool CloseNativeLibrary(void* handle) {
-  return dlclose(handle) == 0;
+bool CloseNativeLibrary(void* handle, const bool needs_native_bridge) {
+    return needs_native_bridge ? NativeBridgeUnloadLibrary(handle) :
+                                 dlclose(handle);
 }
 
 #if defined(__ANDROID__)
+// native_bridge_namespaces are not supported for callers of this function.
+// This function will return nullptr in the case when application is running
+// on native bridge.
 android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
-  return g_namespaces->FindNamespaceByClassLoader(env, class_loader);
+  NativeLoaderNamespace ns;
+  if (g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
+    return ns.is_android_namespace() ? ns.get_android_ns() : nullptr;
+  }
+
+  return nullptr;
 }
 #endif
 
diff --git a/libnetutils/Android.mk b/libnetutils/Android.mk
index ff899c0..2150279 100644
--- a/libnetutils/Android.mk
+++ b/libnetutils/Android.mk
@@ -15,11 +15,7 @@
 
 LOCAL_CFLAGS := -Werror
 
-include $(BUILD_SHARED_LIBRARY)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := dhcptool.c
-LOCAL_SHARED_LIBRARIES := libnetutils
-LOCAL_MODULE := dhcptool
-LOCAL_MODULE_TAGS := debug
-include $(BUILD_EXECUTABLE)
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libnetutils/dhcpclient.c b/libnetutils/dhcpclient.c
index 240a789..d17bdd3 100644
--- a/libnetutils/dhcpclient.c
+++ b/libnetutils/dhcpclient.c
@@ -14,27 +14,25 @@
  * limitations under the License.
  */
 
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-
-#include <time.h>
-#include <sys/time.h>
-#include <poll.h>
-
-#include <sys/socket.h>
-#include <sys/select.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-
-#include <cutils/properties.h>
 #define LOG_TAG "DHCP"
-#include <cutils/log.h>
 
 #include <dirent.h>
+#include <errno.h>
+#include <poll.h>
+#include <netinet/in.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <android/log.h>
+#include <cutils/properties.h>
 
 #include <netutils/ifc.h>
 #include "dhcpmsg.h"
diff --git a/libnetutils/dhcptool.c b/libnetutils/dhcptool.c
deleted file mode 100644
index d23afd3..0000000
--- a/libnetutils/dhcptool.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 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 <err.h>
-#include <errno.h>
-#include <error.h>
-#include <stdbool.h>
-#include <stdlib.h>
-
-#include <netutils/ifc.h>
-
-extern int do_dhcp(char*);
-
-int main(int argc, char* argv[]) {
-  if (argc != 2) {
-    error(EXIT_FAILURE, 0, "usage: %s INTERFACE", argv[0]);
-  }
-
-  char* interface = argv[1];
-  if (ifc_init()) {
-    err(errno, "dhcptool %s: ifc_init failed", interface);
-    ifc_close();
-    return EXIT_FAILURE;
-  }
-
-  int rc = do_dhcp(interface);
-  if (rc) {
-    err(errno, "dhcptool %s: do_dhcp failed", interface);
-  }
-
-  ifc_close();
-
-  return rc ? EXIT_FAILURE : EXIT_SUCCESS;
-}
diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c
index eae32ce..275327a 100644
--- a/libnetutils/ifc_utils.c
+++ b/libnetutils/ifc_utils.c
@@ -1,34 +1,21 @@
 /*
  * Copyright 2008, The Android Open Source Project
  *
- * Licensed under the Apache License, Version 2.0 (the "License"); 
- * you may not use this file except in compliance with the License. 
- * You may obtain a copy of the License at 
+ * 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 
+ *     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 
+ * 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 <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <pthread.h>
-
-#include <sys/socket.h>
-#include <sys/select.h>
-#include <sys/types.h>
-#include <netinet/in.h>
 #include <arpa/inet.h>
-#include <net/if.h>
-#include <netdb.h>
-
+#include <errno.h>
 #include <linux/if.h>
 #include <linux/if_ether.h>
 #include <linux/if_arp.h>
@@ -37,20 +24,29 @@
 #include <linux/ipv6_route.h>
 #include <linux/rtnetlink.h>
 #include <linux/sockios.h>
-
-#include "netutils/ifc.h"
+#include <net/if.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #ifdef ANDROID
 #define LOG_TAG "NetUtils"
-#include <cutils/log.h>
+#include <android/log.h>
 #include <cutils/properties.h>
 #else
-#include <stdio.h>
-#include <string.h>
 #define ALOGD printf
 #define ALOGW printf
 #endif
 
+#include "netutils/ifc.h"
+
 #if defined(__ANDROID__)
 /* SIOCKILLADDR is an Android extension. */
 #define SIOCKILLADDR 0x8939
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/libnetutils/packet.c b/libnetutils/packet.c
index cd26d05..56168e8 100644
--- a/libnetutils/packet.c
+++ b/libnetutils/packet.c
@@ -1,37 +1,36 @@
 /*
  * Copyright 2008, The Android Open Source Project
  *
- * Licensed under the Apache License, Version 2.0 (the "License"); 
- * you may not use this file except in compliance with the License. 
- * You may obtain a copy of the License at 
+ * 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 
+ *     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 
+ * 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 <errno.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
-#include <sys/uio.h>
 #include <sys/socket.h>
+#include <sys/uio.h>
+#include <linux/if_ether.h>
+#include <linux/if_packet.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
 #include <netinet/udp.h>
-#include <linux/if_packet.h>
-#include <linux/if_ether.h>
-#include <errno.h>
+#include <unistd.h>
 
 #ifdef ANDROID
 #define LOG_TAG "DHCP"
-#include <cutils/log.h>
+#include <android/log.h>
 #else
 #include <stdio.h>
-#include <string.h>
 #define ALOGD printf
 #define ALOGW printf
 #endif
diff --git a/libpackagelistparser/Android.bp b/libpackagelistparser/Android.bp
new file mode 100644
index 0000000..70ff528
--- /dev/null
+++ b/libpackagelistparser/Android.bp
@@ -0,0 +1,13 @@
+cc_library {
+
+    name: "libpackagelistparser",
+    srcs: ["packagelistparser.c"],
+    shared_libs: ["liblog"],
+    local_include_dirs: ["include"],
+    export_include_dirs: ["include"],
+
+    clang: true,
+    sanitize: {
+        misc_undefined: ["integer"],
+    },
+}
diff --git a/libpackagelistparser/Android.mk b/libpackagelistparser/Android.mk
deleted file mode 100644
index c8be050..0000000
--- a/libpackagelistparser/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-#########################
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libpackagelistparser
-LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := packagelistparser.c
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-
-LOCAL_CLANG := true
-LOCAL_SANITIZE := integer
-
-include $(BUILD_SHARED_LIBRARY)
-
-#########################
-include $(CLEAR_VARS)
-
-
-LOCAL_MODULE := libpackagelistparser
-LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := packagelistparser.c
-LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-
-LOCAL_CLANG := true
-LOCAL_SANITIZE := integer
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/libpackagelistparser/packagelistparser.c b/libpackagelistparser/packagelistparser.c
index 16052e2..f74b8b4 100644
--- a/libpackagelistparser/packagelistparser.c
+++ b/libpackagelistparser/packagelistparser.c
@@ -18,17 +18,16 @@
  *
  */
 
+#define LOG_TAG "packagelistparser"
+
 #include <errno.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-
 #include <sys/limits.h>
 
-#define LOG_TAG "packagelistparser"
-#include <utils/Log.h>
-
+#include <android/log.h>
 #include <packagelistparser/packagelistparser.h>
 
 #define CLOGE(fmt, ...) \
diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk
index 9a937f8..55891db 100644
--- a/libpixelflinger/Android.mk
+++ b/libpixelflinger/Android.mk
@@ -74,10 +74,6 @@
 		    external/safe-iop/include
 LOCAL_SHARED_LIBRARIES := libcutils liblog libutils
 
-# Really this should go away entirely or at least not depend on
-# libhardware, but this at least gets us built.
-LOCAL_SHARED_LIBRARIES += libhardware_legacy
-LOCAL_CFLAGS += -DWITH_LIB_HARDWARE
 include $(BUILD_SHARED_LIBRARY)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libpixelflinger/arch-arm64/col32cb16blend.S b/libpixelflinger/arch-arm64/col32cb16blend.S
index 8d9c7c4..84596f9 100644
--- a/libpixelflinger/arch-arm64/col32cb16blend.S
+++ b/libpixelflinger/arch-arm64/col32cb16blend.S
@@ -26,7 +26,7 @@
  * SUCH DAMAGE.
  */
     .text
-    .align 0
+    .balign 0
 
     .global scanline_col32cb16blend_arm64
 
diff --git a/libpixelflinger/arch-arm64/t32cb16blend.S b/libpixelflinger/arch-arm64/t32cb16blend.S
index 230f47b..b1a950d 100644
--- a/libpixelflinger/arch-arm64/t32cb16blend.S
+++ b/libpixelflinger/arch-arm64/t32cb16blend.S
@@ -26,7 +26,7 @@
  * SUCH DAMAGE.
  */
     .text
-    .align 0
+    .balign 0
 
     .global scanline_t32cb16blend_arm64
 
diff --git a/libpixelflinger/arch-mips/col32cb16blend.S b/libpixelflinger/arch-mips/col32cb16blend.S
index 5d18e55..810294c 100644
--- a/libpixelflinger/arch-mips/col32cb16blend.S
+++ b/libpixelflinger/arch-mips/col32cb16blend.S
@@ -59,7 +59,7 @@
        .endm
 
        .text
-       .align
+       .balign 4
 
        .global scanline_col32cb16blend_mips
        .ent    scanline_col32cb16blend_mips
diff --git a/libpixelflinger/arch-mips/t32cb16blend.S b/libpixelflinger/arch-mips/t32cb16blend.S
index 236a2c9..1d2fb8f 100644
--- a/libpixelflinger/arch-mips/t32cb16blend.S
+++ b/libpixelflinger/arch-mips/t32cb16blend.S
@@ -178,7 +178,7 @@
 #endif
 
     .text
-    .align
+    .balign 4
 
     .global scanline_t32cb16blend_mips
     .ent    scanline_t32cb16blend_mips
diff --git a/libpixelflinger/arch-mips64/col32cb16blend.S b/libpixelflinger/arch-mips64/col32cb16blend.S
index fea4491..5baffb1 100644
--- a/libpixelflinger/arch-mips64/col32cb16blend.S
+++ b/libpixelflinger/arch-mips64/col32cb16blend.S
@@ -53,7 +53,7 @@
     .endm
 
     .text
-    .align
+    .balign 4
 
     .global scanline_col32cb16blend_mips64
     .ent    scanline_col32cb16blend_mips64
diff --git a/libpixelflinger/arch-mips64/t32cb16blend.S b/libpixelflinger/arch-mips64/t32cb16blend.S
index d2f4d49..3cb5f93 100644
--- a/libpixelflinger/arch-mips64/t32cb16blend.S
+++ b/libpixelflinger/arch-mips64/t32cb16blend.S
@@ -75,7 +75,7 @@
     .endm
 
     .text
-    .align
+    .balign 4
 
     .global scanline_t32cb16blend_mips64
     .ent    scanline_t32cb16blend_mips64
diff --git a/libpixelflinger/codeflinger/ARMAssembler.cpp b/libpixelflinger/codeflinger/ARMAssembler.cpp
index 92243da..36c1326 100644
--- a/libpixelflinger/codeflinger/ARMAssembler.cpp
+++ b/libpixelflinger/codeflinger/ARMAssembler.cpp
@@ -2,16 +2,16 @@
 **
 ** Copyright 2006, 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 
+** 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 
+**     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 
+** 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.
 */
 
@@ -19,13 +19,9 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <cutils/log.h>
+
+#include <android/log.h>
 #include <cutils/properties.h>
-
-#if defined(WITH_LIB_HARDWARE)
-#include <hardware_legacy/qemu_tracing.h>
-#endif
-
 #include <private/pixelflinger/ggl_context.h>
 
 #include "ARMAssembler.h"
@@ -48,9 +44,6 @@
 {
     mBase = mPC = (uint32_t *)assembly->base();
     mDuration = ggl_system_time();
-#if defined(WITH_LIB_HARDWARE)
-    mQemuTracing = true;
-#endif
 }
 
 ARMAssembler::~ARMAssembler()
@@ -184,13 +177,6 @@
     const char * const format = "generated %s (%d ins) at [%p:%p] in %lld ns\n";
     ALOGI(format, name, int(pc()-base()), base(), pc(), duration);
 
-#if defined(WITH_LIB_HARDWARE)
-    if (__builtin_expect(mQemuTracing, 0)) {
-        int err = qemu_add_mapping(uintptr_t(base()), name);
-        mQemuTracing = (err >= 0);
-    }
-#endif
-
     char value[PROPERTY_VALUE_MAX];
     property_get("debug.pf.disasm", value, "0");
     if (atoi(value) != 0) {
diff --git a/libpixelflinger/codeflinger/ARMAssembler.h b/libpixelflinger/codeflinger/ARMAssembler.h
index e0c7646..76acf7e 100644
--- a/libpixelflinger/codeflinger/ARMAssembler.h
+++ b/libpixelflinger/codeflinger/ARMAssembler.h
@@ -35,7 +35,7 @@
 class ARMAssembler : public ARMAssemblerInterface
 {
 public:
-                ARMAssembler(const sp<Assembly>& assembly);
+    explicit    ARMAssembler(const sp<Assembly>& assembly);
     virtual     ~ARMAssembler();
 
     uint32_t*   base() const;
@@ -167,9 +167,6 @@
     uint32_t*       mPC;
     uint32_t*       mPrologPC;
     int64_t         mDuration;
-#if defined(WITH_LIB_HARDWARE)
-    bool            mQemuTracing;
-#endif
     
     struct branch_target_t {
         inline branch_target_t() : label(0), pc(0) { }
diff --git a/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp b/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
index 5041999..e212f1b 100644
--- a/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
+++ b/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
@@ -2,26 +2,27 @@
 **
 ** Copyright 2006, 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 
+** 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 
+**     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 
+** 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.
 */
-
+#define LOG_TAG "pixelflinger-code"
 
 #include <errno.h>
-#include <stdlib.h>
 #include <stdint.h>
+#include <stdlib.h>
 #include <sys/types.h>
 
-#include <cutils/log.h>
+#include <android/log.h>
+
 #include "ARMAssemblerInterface.h"
 
 namespace android {
diff --git a/libpixelflinger/codeflinger/ARMAssemblerProxy.h b/libpixelflinger/codeflinger/ARMAssemblerProxy.h
index b852794..10d0390 100644
--- a/libpixelflinger/codeflinger/ARMAssemblerProxy.h
+++ b/libpixelflinger/codeflinger/ARMAssemblerProxy.h
@@ -34,7 +34,7 @@
     // ARMAssemblerProxy take ownership of the target
 
                 ARMAssemblerProxy();
-                ARMAssemblerProxy(ARMAssemblerInterface* target);
+    explicit    ARMAssemblerProxy(ARMAssemblerInterface* target);
     virtual     ~ARMAssemblerProxy();
 
     void setTarget(ARMAssemblerInterface* target);
diff --git a/libpixelflinger/codeflinger/Arm64Assembler.cpp b/libpixelflinger/codeflinger/Arm64Assembler.cpp
index bd11818..fb297ec 100644
--- a/libpixelflinger/codeflinger/Arm64Assembler.cpp
+++ b/libpixelflinger/codeflinger/Arm64Assembler.cpp
@@ -32,14 +32,13 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <cutils/log.h>
+#include <android/log.h>
 #include <cutils/properties.h>
 #include <private/pixelflinger/ggl_context.h>
 
 #include "codeflinger/Arm64Assembler.h"
-#include "codeflinger/CodeCache.h"
 #include "codeflinger/Arm64Disassembler.h"
-
+#include "codeflinger/CodeCache.h"
 
 /*
 ** --------------------------------------------
diff --git a/libpixelflinger/codeflinger/Arm64Assembler.h b/libpixelflinger/codeflinger/Arm64Assembler.h
index c9be116..527c757 100644
--- a/libpixelflinger/codeflinger/Arm64Assembler.h
+++ b/libpixelflinger/codeflinger/Arm64Assembler.h
@@ -47,8 +47,8 @@
 class ArmToArm64Assembler : public ARMAssemblerInterface
 {
 public:
-                ArmToArm64Assembler(const sp<Assembly>& assembly);
-                ArmToArm64Assembler(void *base);
+    explicit    ArmToArm64Assembler(const sp<Assembly>& assembly);
+    explicit    ArmToArm64Assembler(void *base);
     virtual     ~ArmToArm64Assembler();
 
     uint32_t*   base() const;
diff --git a/libpixelflinger/codeflinger/CodeCache.cpp b/libpixelflinger/codeflinger/CodeCache.cpp
index 4b498c1..37bd074 100644
--- a/libpixelflinger/codeflinger/CodeCache.cpp
+++ b/libpixelflinger/codeflinger/CodeCache.cpp
@@ -15,18 +15,16 @@
 ** limitations under the License.
 */
 
+#define LOG_TAG "CodeCache"
 
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
 #include <sys/mman.h>
+#include <unistd.h>
 
+#include <android/log.h>
 #include <cutils/ashmem.h>
-#include <cutils/atomic.h>
-#define LOG_TAG "CodeCache"
-#include <cutils/log.h>
-
 
 #include "CodeCache.h"
 
@@ -101,7 +99,7 @@
 }
 
 Assembly::Assembly(size_t size)
-    : mCount(1), mSize(0)
+    : mCount(0), mSize(0)
 {
     mBase = (uint32_t*)mspace_malloc(getMspace(), size);
     LOG_ALWAYS_FATAL_IF(mBase == NULL,
@@ -117,12 +115,12 @@
 
 void Assembly::incStrong(const void*) const
 {
-    android_atomic_inc(&mCount);
+    mCount.fetch_add(1, std::memory_order_relaxed);
 }
 
 void Assembly::decStrong(const void*) const
 {
-    if (android_atomic_dec(&mCount) == 1) {
+    if (mCount.fetch_sub(1, std::memory_order_acq_rel) == 1) {
         delete this;
     }
 }
diff --git a/libpixelflinger/codeflinger/CodeCache.h b/libpixelflinger/codeflinger/CodeCache.h
index 0fb6fd5..9326453 100644
--- a/libpixelflinger/codeflinger/CodeCache.h
+++ b/libpixelflinger/codeflinger/CodeCache.h
@@ -19,6 +19,7 @@
 #ifndef ANDROID_CODECACHE_H
 #define ANDROID_CODECACHE_H
 
+#include <atomic>
 #include <stdint.h>
 #include <pthread.h>
 #include <sys/types.h>
@@ -42,7 +43,7 @@
 class AssemblyKey : public AssemblyKeyBase
 {
 public:
-    AssemblyKey(const T& rhs) : mKey(rhs) { }
+    explicit AssemblyKey(const T& rhs) : mKey(rhs) { }
     virtual int compare_type(const AssemblyKeyBase& key) const {
         const T& rhs = static_cast<const AssemblyKey&>(key).mKey;
         return android::compare_type(mKey, rhs);
@@ -56,7 +57,7 @@
 class Assembly
 {
 public:
-                Assembly(size_t size);
+    explicit    Assembly(size_t size);
     virtual     ~Assembly();
 
     ssize_t     size() const;
@@ -69,7 +70,7 @@
     typedef void    weakref_type;
 
 private:
-    mutable int32_t     mCount;
+    mutable std::atomic<int32_t>     mCount;
             uint32_t*   mBase;
             size_t      mSize;
 };
@@ -80,13 +81,13 @@
 {
 public:
 // pretty simple cache API...
-                CodeCache(size_t size);
-                ~CodeCache();
-    
-            sp<Assembly>        lookup(const AssemblyKeyBase& key) const;
+    explicit            CodeCache(size_t size);
+                        ~CodeCache();
 
-            int                 cache(  const AssemblyKeyBase& key,
-                                        const sp<Assembly>& assembly);
+    sp<Assembly>        lookup(const AssemblyKeyBase& key) const;
+
+    int                 cache(const AssemblyKeyBase& key,
+                              const sp<Assembly>& assembly);
 
 private:
     // nothing to see here...
@@ -105,7 +106,7 @@
         const AssemblyKeyBase* mKey;
     public:
         key_t() { };
-        key_t(const AssemblyKeyBase& k) : mKey(&k)  { }
+        explicit key_t(const AssemblyKeyBase& k) : mKey(&k)  { }
     };
 
     mutable pthread_mutex_t             mLock;
diff --git a/libpixelflinger/codeflinger/GGLAssembler.cpp b/libpixelflinger/codeflinger/GGLAssembler.cpp
index 346779f..0b9b5a4 100644
--- a/libpixelflinger/codeflinger/GGLAssembler.cpp
+++ b/libpixelflinger/codeflinger/GGLAssembler.cpp
@@ -2,16 +2,16 @@
 **
 ** Copyright 2006, 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 
+** 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 
+**     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 
+** 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.
 */
 
@@ -19,10 +19,11 @@
 
 #include <assert.h>
 #include <stdint.h>
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <sys/types.h>
-#include <cutils/log.h>
+
+#include <android/log.h>
 
 #include "GGLAssembler.h"
 
diff --git a/libpixelflinger/codeflinger/GGLAssembler.h b/libpixelflinger/codeflinger/GGLAssembler.h
index 9db20df..47dbf3a 100644
--- a/libpixelflinger/codeflinger/GGLAssembler.h
+++ b/libpixelflinger/codeflinger/GGLAssembler.h
@@ -49,7 +49,7 @@
 public:
     class RegisterFile;
     
-                    RegisterAllocator(int arch);
+                    RegisterAllocator(int arch);  // NOLINT, implicit
     RegisterFile&   registerFile();
     int             reserveReg(int reg);
     int             obtainReg();
@@ -59,7 +59,7 @@
     class RegisterFile
     {
     public:
-                            RegisterFile(int arch);
+                            RegisterFile(int arch);  // NOLINT, implicit
                             RegisterFile(const RegisterFile& rhs, int arch);
                             ~RegisterFile();
 
@@ -101,7 +101,7 @@
     class Scratch
     {
     public:
-            Scratch(RegisterFile& regFile)
+            explicit Scratch(RegisterFile& regFile)
                 : mRegFile(regFile), mScratch(0) { 
             }
             ~Scratch() {
@@ -177,8 +177,8 @@
 {
 public:
 
-                    GGLAssembler(ARMAssemblerInterface* target);
-        virtual     ~GGLAssembler();
+    explicit    GGLAssembler(ARMAssemblerInterface* target);
+    virtual     ~GGLAssembler();
 
     uint32_t*   base() const { return 0; } // XXX
     uint32_t*   pc() const { return 0; } // XXX
@@ -206,7 +206,7 @@
         struct reg_t {
             reg_t() : reg(-1), flags(0) {
             }
-            reg_t(int r, int f=0)
+            reg_t(int r, int f=0)  // NOLINT, implicit
                 : reg(r), flags(f) {
             }
             void setTo(int r, int f=0) {
@@ -219,7 +219,7 @@
         struct integer_t : public reg_t {
             integer_t() : reg_t(), s(0) {
             }
-            integer_t(int r, int sz=32, int f=0)
+            integer_t(int r, int sz=32, int f=0)  // NOLINT, implicit
                 : reg_t(r, f), s(sz) {
             }
             void setTo(int r, int sz=32, int f=0) {
@@ -251,7 +251,7 @@
         struct component_t : public reg_t {
             component_t() : reg_t(), h(0), l(0) {
             }
-            component_t(int r, int f=0)
+            component_t(int r, int f=0)  // NOLINT, implicit
                 : reg_t(r, f), h(0), l(0) {
             }
             component_t(int r, int lo, int hi, int f=0)
@@ -288,6 +288,14 @@
 
 
 private:
+    // GGLAssembler hides RegisterAllocator's and ARMAssemblerProxy's reset
+    // methods by providing a reset method with a different parameter set. The
+    // intent of GGLAssembler's reset method is to wrap the inherited reset
+    // methods, so make these methods private in order to prevent direct calls
+    // to these methods from clients.
+    using RegisterAllocator::reset;
+    using ARMAssemblerProxy::reset;
+
     struct tex_coord_t {
         reg_t       s;
         reg_t       t;
diff --git a/libpixelflinger/codeflinger/MIPS64Assembler.cpp b/libpixelflinger/codeflinger/MIPS64Assembler.cpp
index 672040b..a7bbaf7 100644
--- a/libpixelflinger/codeflinger/MIPS64Assembler.cpp
+++ b/libpixelflinger/codeflinger/MIPS64Assembler.cpp
@@ -25,28 +25,21 @@
 **
 */
 
-
 #define LOG_TAG "MIPS64Assembler"
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <cutils/log.h>
+
+#include <android/log.h>
 #include <cutils/properties.h>
-
-#if defined(WITH_LIB_HARDWARE)
-#include <hardware_legacy/qemu_tracing.h>
-#endif
-
 #include <private/pixelflinger/ggl_context.h>
 
 #include "MIPS64Assembler.h"
 #include "CodeCache.h"
 #include "mips64_disassem.h"
 
-
 #define NOT_IMPLEMENTED()  LOG_ALWAYS_FATAL("Arm instruction %s not yet implemented\n", __func__)
 
-
 // ----------------------------------------------------------------------------
 
 namespace android {
diff --git a/libpixelflinger/codeflinger/MIPSAssembler.cpp b/libpixelflinger/codeflinger/MIPSAssembler.cpp
index 5497fae..4cddcc8 100644
--- a/libpixelflinger/codeflinger/MIPSAssembler.cpp
+++ b/libpixelflinger/codeflinger/MIPSAssembler.cpp
@@ -52,17 +52,13 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <cutils/log.h>
+
+#include <android/log.h>
 #include <cutils/properties.h>
-
-#if defined(WITH_LIB_HARDWARE)
-#include <hardware_legacy/qemu_tracing.h>
-#endif
-
 #include <private/pixelflinger/ggl_context.h>
 
-#include "MIPSAssembler.h"
 #include "CodeCache.h"
+#include "MIPSAssembler.h"
 #include "mips_disassem.h"
 
 // Choose MIPS arch variant following gcc flags
@@ -1411,13 +1407,6 @@
     const char * const format = "generated %s (%d ins) at [%p:%p] in %lld ns\n";
     ALOGI(format, name, int(pc()-base()), base(), pc(), duration);
 
-#if defined(WITH_LIB_HARDWARE)
-    if (__builtin_expect(mQemuTracing, 0)) {
-        int err = qemu_add_mapping(uintptr_t(base()), name);
-        mQemuTracing = (err >= 0);
-    }
-#endif
-
     char value[PROPERTY_VALUE_MAX];
     value[0] = '\0';
 
diff --git a/libpixelflinger/codeflinger/MIPSAssembler.h b/libpixelflinger/codeflinger/MIPSAssembler.h
index b53fefb..c1178b6 100644
--- a/libpixelflinger/codeflinger/MIPSAssembler.h
+++ b/libpixelflinger/codeflinger/MIPSAssembler.h
@@ -410,9 +410,6 @@
     uint32_t*       mPC;
     uint32_t*       mPrologPC;
     int64_t         mDuration;
-#if defined(WITH_LIB_HARDWARE)
-    bool            mQemuTracing;
-#endif
 
     struct branch_target_t {
         inline branch_target_t() : label(0), pc(0) { }
diff --git a/libpixelflinger/codeflinger/blending.cpp b/libpixelflinger/codeflinger/blending.cpp
index b20219c..092f140 100644
--- a/libpixelflinger/codeflinger/blending.cpp
+++ b/libpixelflinger/codeflinger/blending.cpp
@@ -2,30 +2,31 @@
 **
 ** Copyright 2006, 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 
+** 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 
+**     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 
+** 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.
 */
 
+#define LOG_TAG "pixelflinger-code"
+
 #include <assert.h>
 #include <stdint.h>
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <sys/types.h>
 
-#include <cutils/log.h>
+#include <android/log.h>
 
 #include "GGLAssembler.h"
 
-
 namespace android {
 
 void GGLAssembler::build_fog(
diff --git a/libpixelflinger/codeflinger/disassem.c b/libpixelflinger/codeflinger/disassem.c
index 39dd614..5cbd63d 100644
--- a/libpixelflinger/codeflinger/disassem.c
+++ b/libpixelflinger/codeflinger/disassem.c
@@ -279,14 +279,14 @@
 	"4.0", "5.0", "0.5", "10.0"
 };
 
-#define insn_condition(x)	arm32_insn_conditions[(x >> 28) & 0x0f]
-#define insn_blktrans(x)	insn_block_transfers[(x >> 23) & 3]
-#define insn_stkblktrans(x)	insn_stack_block_transfers[(3*((x >> 20)&1))^((x >> 23)&3)]
-#define op2_shift(x)		op_shifts[(x >> 5) & 3]
-#define insn_fparnd(x)		insn_fpa_rounding[(x >> 5) & 0x03]
-#define insn_fpaprec(x)		insn_fpa_precision[(((x >> 18) & 2)|(x >> 7)) & 1]
-#define insn_fpaprect(x)	insn_fpa_precision[(((x >> 21) & 2)|(x >> 15)) & 1]
-#define insn_fpaimm(x)		insn_fpaconstants[x & 0x07]
+#define insn_condition(x)	arm32_insn_conditions[((x) >> 28) & 0x0f]
+#define insn_blktrans(x)	insn_block_transfers[((x) >> 23) & 3]
+#define insn_stkblktrans(x)	insn_stack_block_transfers[(3*(((x) >> 20)&1))^(((x) >> 23)&3)]
+#define op2_shift(x)		op_shifts[((x) >> 5) & 3]
+#define insn_fparnd(x)		insn_fpa_rounding[((x) >> 5) & 0x03]
+#define insn_fpaprec(x)		insn_fpa_precision[((((x) >> 18) & 2)|((x) >> 7)) & 1]
+#define insn_fpaprect(x)	insn_fpa_precision[((((x) >> 21) & 2)|((x) >> 15)) & 1]
+#define insn_fpaimm(x)		insn_fpaconstants[(x) & 0x07]
 
 /* Local prototypes */
 static void disasm_register_shift(const disasm_interface_t *di, u_int insn);
diff --git a/libpixelflinger/codeflinger/load_store.cpp b/libpixelflinger/codeflinger/load_store.cpp
index e5a1ae0..b8a0e55 100644
--- a/libpixelflinger/codeflinger/load_store.cpp
+++ b/libpixelflinger/codeflinger/load_store.cpp
@@ -2,22 +2,26 @@
 **
 ** Copyright 2006, 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 
+** 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 
+**     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 
+** 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.
 */
 
+#define LOG_TAG "pixelflinger-code"
+
 #include <assert.h>
 #include <stdio.h>
-#include <cutils/log.h>
+
+#include <android/log.h>
+
 #include "GGLAssembler.h"
 
 namespace android {
@@ -25,7 +29,7 @@
 // ----------------------------------------------------------------------------
 
 void GGLAssembler::store(const pointer_t& addr, const pixel_t& s, uint32_t flags)
-{    
+{
     const int bits = addr.size;
     const int inc = (flags & WRITE_BACK)?1:0;
     switch (bits) {
@@ -59,8 +63,8 @@
 }
 
 void GGLAssembler::load(const pointer_t& addr, const pixel_t& s, uint32_t flags)
-{    
-    Scratch scratches(registerFile());    
+{
+    Scratch scratches(registerFile());
     int s0;
 
     const int bits = addr.size;
@@ -72,7 +76,7 @@
         break;
     case 24:
         // 24 bits formats are a little special and used only for RGB
-        // R,G,B is packed as 0x00BBGGRR 
+        // R,G,B is packed as 0x00BBGGRR
         s0 = scratches.obtain();
         if (s.reg != addr.reg) {
             LDRB(AL, s.reg, addr.reg, immed12_pre(0));      // R
@@ -90,7 +94,7 @@
         }
         if (inc)
             ADD(AL, 0, addr.reg, addr.reg, imm(3));
-        break;        
+        break;
     case 16:
         if (inc)    LDRH(AL, s.reg, addr.reg, immed8_post(2));
         else        LDRH(AL, s.reg, addr.reg);
@@ -112,7 +116,7 @@
     assert(maskLen<=8);
 #endif
     assert(h);
-    
+
     if (h != bits) {
         const int mask = ((1<<maskLen)-1) << l;
         if (isValidImmediate(mask)) {
@@ -126,12 +130,12 @@
         }
         s = d.reg;
     }
-    
+
     if (l) {
         MOV(AL, 0, d.reg, reg_imm(s, LSR, l));  // component = packed >> l;
         s = d.reg;
     }
-    
+
     if (s != d.reg) {
         MOV(AL, 0, d.reg, s);
     }
@@ -212,12 +216,12 @@
         } while(dbits>0);
         return;
     }
-    
+
     dbits -= sbits;
     do {
         ORR(AL, 0, d, s, reg_imm(s, LSL, sbits));
             // d |= d<<sbits;
-        s = d;        
+        s = d;
         dbits -= sbits;
         if (sbits*2 < dbits) {
             sbits *= 2;
@@ -241,14 +245,14 @@
     int dl = d.format.c[component].l;
     int dbits = dh - dl;
     int dithering = 0;
-    
+
     ALOGE_IF(sbits<dbits, "sbits (%d) < dbits (%d) in downshift", sbits, dbits);
 
     if (sbits>dbits) {
         // see if we need to dither
         dithering = mDithering;
     }
-    
+
     int ireg = d.reg;
     if (!(d.flags & FIRST)) {
         if (s.flags & CORRUPTIBLE)  {
@@ -271,7 +275,7 @@
                 if (isValidImmediate(mask) || isValidImmediate(~mask)) {
                     build_and_immediate(ireg, s.reg, mask, 32);
                     sl = offset;
-                    s.reg = ireg; 
+                    s.reg = ireg;
                     sbits = dbits;
                     maskLoBits = maskHiBits = 0;
                 }
@@ -281,7 +285,7 @@
             const uint32_t mask = ((1<<sbits)-1) << sl;
             if (isValidImmediate(mask) || isValidImmediate(~mask)) {
                 build_and_immediate(ireg, s.reg, mask, 32);
-                s.reg = ireg; 
+                s.reg = ireg;
                 maskLoBits = maskHiBits = 0;
             }
         }
@@ -325,7 +329,7 @@
             MOV(AL, 0, ireg, reg_imm(s.reg, LSR, sl));
             sh -= sl;
             sl = 0;
-            s.reg = ireg; 
+            s.reg = ireg;
         }
         // scaling (V-V>>dbits)
         SUB(AL, 0, ireg, s.reg, reg_imm(s.reg, LSR, dbits));
@@ -333,7 +337,7 @@
         if (shift>0)        ADD(AL, 0, ireg, ireg, reg_imm(dither.reg, LSR, shift));
         else if (shift<0)   ADD(AL, 0, ireg, ireg, reg_imm(dither.reg, LSL,-shift));
         else                ADD(AL, 0, ireg, ireg, dither.reg);
-        s.reg = ireg; 
+        s.reg = ireg;
     }
 
     if ((maskLoBits|dithering) && (sh > dbits)) {
diff --git a/libpixelflinger/codeflinger/mips64_disassem.c b/libpixelflinger/codeflinger/mips64_disassem.c
index 44b7fe7..f28d726 100644
--- a/libpixelflinger/codeflinger/mips64_disassem.c
+++ b/libpixelflinger/codeflinger/mips64_disassem.c
@@ -34,21 +34,20 @@
  *  from: @(#)kadb.c    8.1 (Berkeley) 6/10/93
  */
 
-#include <stdio.h>
-#include <stdint.h>
 #include <stdarg.h>
 #include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
 #include <sys/cdefs.h>
-
 #include <sys/types.h>
-#include "mips_opcode.h"
 
-#include <cutils/log.h>
+#include <android/log.h>
+
+#include "mips_opcode.h"
 
 static char *sprintf_buffer;
 static int sprintf_buf_len;
 
-
 typedef uint64_t db_addr_t;
 static void db_printf(const char* fmt, ...);
 
diff --git a/libpixelflinger/codeflinger/texturing.cpp b/libpixelflinger/codeflinger/texturing.cpp
index 29a3742..f4f4657 100644
--- a/libpixelflinger/codeflinger/texturing.cpp
+++ b/libpixelflinger/codeflinger/texturing.cpp
@@ -2,26 +2,28 @@
 **
 ** Copyright 2006, 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 
+** 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 
+**     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 
+** 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.
 */
 
+#define LOG_TAG "pixelflinger-code"
+
 #include <assert.h>
 #include <stdint.h>
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <sys/types.h>
 
-#include <cutils/log.h>
+#include <android/log.h>
 
 #include "GGLAssembler.h"
 
diff --git a/libpixelflinger/codeflinger/tinyutils/smartpointer.h b/libpixelflinger/codeflinger/tinyutils/smartpointer.h
index 9d0a16e..23a5f7e 100644
--- a/libpixelflinger/codeflinger/tinyutils/smartpointer.h
+++ b/libpixelflinger/codeflinger/tinyutils/smartpointer.h
@@ -51,10 +51,10 @@
 public:
     inline sp() : m_ptr(0) { }
 
-    sp(T* other);
+    sp(T* other);  // NOLINT, implicit
     sp(const sp<T>& other);
-    template<typename U> sp(U* other);
-    template<typename U> sp(const sp<U>& other);
+    template<typename U> sp(U* other);  // NOLINT, implicit
+    template<typename U> sp(const sp<U>& other);  // NOLINT, implicit
 
     ~sp();
     
diff --git a/libpixelflinger/col32cb16blend.S b/libpixelflinger/col32cb16blend.S
index 1831255..39f94e1 100644
--- a/libpixelflinger/col32cb16blend.S
+++ b/libpixelflinger/col32cb16blend.S
@@ -16,7 +16,7 @@
  */
 
     .text
-    .align
+    .balign 4
 
     .global scanline_col32cb16blend_arm
 
diff --git a/libpixelflinger/col32cb16blend_neon.S b/libpixelflinger/col32cb16blend_neon.S
index cbd54d1..7ad34b0 100644
--- a/libpixelflinger/col32cb16blend_neon.S
+++ b/libpixelflinger/col32cb16blend_neon.S
@@ -17,7 +17,7 @@
 
 
     .text
-    .align
+    .balign 4
 
     .global scanline_col32cb16blend_neon
 
diff --git a/libpixelflinger/include/private/pixelflinger/ggl_context.h b/libpixelflinger/include/private/pixelflinger/ggl_context.h
index d45dabc..563b0f1 100644
--- a/libpixelflinger/include/private/pixelflinger/ggl_context.h
+++ b/libpixelflinger/include/private/pixelflinger/ggl_context.h
@@ -120,7 +120,7 @@
 template<bool> struct CTA;
 template<> struct CTA<true> { };
 
-#define GGL_CONTEXT(con, c)         context_t *con = static_cast<context_t *>(c)
+#define GGL_CONTEXT(con, c)         context_t *(con) = static_cast<context_t *>(c) /* NOLINT */
 #define GGL_OFFSETOF(field)         uintptr_t(&(((context_t*)0)->field))
 #define GGL_INIT_PROC(p, f)         p.f = ggl_ ## f;
 #define GGL_BETWEEN(x, L, H)        (uint32_t((x)-(L)) <= ((H)-(L)))
@@ -136,14 +136,14 @@
 // ----------------------------------------------------------------------------
 
 #define GGL_RESERVE_NEEDS(name, l, s)                               \
-    const uint32_t  GGL_NEEDS_##name##_MASK = (((1LU<<(s))-1)<<l);  \
+    const uint32_t  GGL_NEEDS_##name##_MASK = (((1LU<<(s))-1)<<(l));  \
     const uint32_t  GGL_NEEDS_##name##_SHIFT = (l);
 
 #define GGL_BUILD_NEEDS(val, name)                                  \
     (((val)<<(GGL_NEEDS_##name##_SHIFT)) & GGL_NEEDS_##name##_MASK)
 
 #define GGL_READ_NEEDS(name, n)                                     \
-    (uint32_t(n & GGL_NEEDS_##name##_MASK) >> GGL_NEEDS_##name##_SHIFT)
+    (uint32_t((n) & GGL_NEEDS_##name##_MASK) >> GGL_NEEDS_##name##_SHIFT)
 
 #define GGL_NEED_MASK(name)     (uint32_t(GGL_NEEDS_##name##_MASK))
 #define GGL_NEED(name, val)     GGL_BUILD_NEEDS(val, name)
diff --git a/libpixelflinger/rotate90CW_4x4_16v6.S b/libpixelflinger/rotate90CW_4x4_16v6.S
deleted file mode 100644
index 8e3e142..0000000
--- a/libpixelflinger/rotate90CW_4x4_16v6.S
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
-**
-** Copyright 2006, 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.
-*/
-
-
-    .text
-    .align
-    
-    .global rotate90CW_4x4_16v6
-
-// Rotates 90deg CW a 4x4 block of 16bpp pixels using ARMv6
-// src and dst must be 4 pixels-aligned (2-pixels aligned might
-// actually work)
-//
-// The code below is complicated by ARM's little endianness. 
-
-rotate90CW_4x4_16v6:
-    // r0 = dst
-    // r1 = src
-    // r2 = dst stride in pixels
-    // r3 = src stride in pixels
-
-    stmfd   sp!, {r4,r5, r6,r7, r8,r9, r10,r11, lr}
-    add     r14, r3, r3
-    add     r12, r2, r2
-
-    ldrd    r2, r3, [r1], r14
-    ldrd    r4, r5, [r1], r14
-    ldrd    r6, r7, [r1], r14
-    ldrd    r8, r9, [r1]
-
-    pkhbt   r10, r8, r6, lsl #16
-    pkhbt   r11, r4, r2, lsl #16
-    strd    r10, r11, [r0], r12  
-
-    pkhtb   r10, r6, r8, asr #16
-    pkhtb   r11, r2, r4, asr #16
-
-    strd    r10, r11, [r0], r12  
-    pkhbt   r10, r9, r7, lsl #16
-    pkhbt   r11, r5, r3, lsl #16
-
-    strd    r10, r11, [r0], r12  
-
-    pkhtb   r10, r7, r9, asr #16
-    pkhtb   r11, r3, r5, asr #16
-    strd    r10, r11, [r0]
-
-    ldmfd   sp!, {r4,r5, r6,r7, r8,r9, r10,r11, pc}
diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp
index a718b02..1a2f6fb 100644
--- a/libpixelflinger/scanline.cpp
+++ b/libpixelflinger/scanline.cpp
@@ -2,33 +2,28 @@
 **
 ** Copyright 2006-2011, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** 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 
+**     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 
+** 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.
 */
 
-
 #define LOG_TAG "pixelflinger"
 
 #include <assert.h>
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
+#include <android/log.h>
 #include <cutils/memory.h>
-#include <cutils/log.h>
-
-#ifdef __arm__
-#include <machine/cpu-features.h>
-#endif
 
 #include "buffer.h"
 #include "scanline.h"
@@ -965,7 +960,7 @@
  * Use only for one-to-one texture mapping.
  */
 struct horz_iterator32 {
-    horz_iterator32(context_t* c) {
+    explicit horz_iterator32(context_t* c) {
         const int x = c->iterators.xl;
         const int y = c->iterators.y;
         texture_t& tx = c->state.texture[0];
@@ -982,7 +977,7 @@
 
 /* A variant for 16-bit source textures. */
 struct horz_iterator16 {
-    horz_iterator16(context_t* c) {
+    explicit horz_iterator16(context_t* c) {
         const int x = c->iterators.xl;
         const int y = c->iterators.y;
         texture_t& tx = c->state.texture[0];
@@ -1002,7 +997,7 @@
  * texture pixel value.
  */
 struct clamp_iterator {
-    clamp_iterator(context_t* c) {
+    explicit clamp_iterator(context_t* c) {
         const int xs = c->iterators.xl;
         texture_t& tx = c->state.texture[0];
         texture_iterators_t& ti = tx.iterators;
@@ -1112,13 +1107,13 @@
 }
 
 struct horz_clamp_iterator16 : horz_clamp_iterator {
-    horz_clamp_iterator16(const context_t* c) {
+    explicit horz_clamp_iterator16(const context_t* c) {
         init(c,1);
     };
 };
 
 struct horz_clamp_iterator32 : horz_clamp_iterator {
-    horz_clamp_iterator32(context_t* c) {
+    explicit horz_clamp_iterator32(context_t* c) {
         init(c,2);
     };
 };
@@ -1126,7 +1121,7 @@
 /* This is used to perform dithering operations.
  */
 struct ditherer {
-    ditherer(const context_t* c) {
+    explicit ditherer(const context_t* c) {
         const int x = c->iterators.xl;
         const int y = c->iterators.y;
         m_line = &c->ditherMatrix[ ((y & GGL_DITHER_MASK)<<GGL_DITHER_ORDER_SHIFT) ];
@@ -1172,7 +1167,7 @@
  *   blender.blend(<32-bit-src-pixel-value>,<ptr-to-16-bit-dest-pixel>)
  */
 struct blender_32to16 {
-    blender_32to16(context_t* /*c*/) { }
+    explicit blender_32to16(context_t* /*c*/) { }
     void write(uint32_t s, uint16_t* dst) {
         if (s == 0)
             return;
@@ -1229,7 +1224,7 @@
  * where dstFactor=srcA*(1-srcA) srcFactor=srcA
  */
 struct blender_32to16_srcA {
-    blender_32to16_srcA(const context_t* /*c*/) { }
+    explicit blender_32to16_srcA(const context_t* /*c*/) { }
     void write(uint32_t s, uint16_t* dst) {
         if (!s) {
             return;
@@ -1271,7 +1266,7 @@
 /* This blender does a normal blend after modulation.
  */
 struct blender_32to16_modulate : blender_modulate {
-    blender_32to16_modulate(const context_t* c) {
+    explicit blender_32to16_modulate(const context_t* c) {
         init(c);
     }
     void write(uint32_t s, uint16_t* dst) {
@@ -1343,7 +1338,7 @@
 
 /* same as 32to16_modulate, except that the input is xRGB, instead of ARGB */
 struct blender_x32to16_modulate : blender_modulate {
-    blender_x32to16_modulate(const context_t* c) {
+    explicit blender_x32to16_modulate(const context_t* c) {
         init(c);
     }
     void write(uint32_t s, uint16_t* dst) {
@@ -1398,7 +1393,7 @@
 
 /* Same as above, but source is 16bit rgb565 */
 struct blender_16to16_modulate : blender_modulate {
-    blender_16to16_modulate(const context_t* c) {
+    explicit blender_16to16_modulate(const context_t* c) {
         init(c);
     }
     void write(uint16_t s16, uint16_t* dst) {
@@ -1434,7 +1429,7 @@
  *   }
  */
 struct dst_iterator16 {
-    dst_iterator16(const context_t* c) {
+    explicit dst_iterator16(const context_t* c) {
         const int x = c->iterators.xl;
         const int width = c->iterators.xr - x;
         const int32_t y = c->iterators.y;
diff --git a/libpixelflinger/t32cb16blend.S b/libpixelflinger/t32cb16blend.S
index 1d40ad4..5e4995a 100644
--- a/libpixelflinger/t32cb16blend.S
+++ b/libpixelflinger/t32cb16blend.S
@@ -18,7 +18,7 @@
 
 	.text
 	.syntax unified
-	.align
+	.balign 4
 	
 	.global scanline_t32cb16blend_arm
 
diff --git a/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp b/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp
index 5f58797..63642c4 100644
--- a/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp
+++ b/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp
@@ -34,7 +34,6 @@
 
 #include <sys/mman.h>
 #include <cutils/ashmem.h>
-#include <cutils/atomic.h>
 
 #define __STDC_FORMAT_MACROS
 #include <inttypes.h>
diff --git a/libpixelflinger/tests/arch-arm64/assembler/asm_test_jacket.S b/libpixelflinger/tests/arch-arm64/assembler/asm_test_jacket.S
index f44859f..3f900f8 100644
--- a/libpixelflinger/tests/arch-arm64/assembler/asm_test_jacket.S
+++ b/libpixelflinger/tests/arch-arm64/assembler/asm_test_jacket.S
@@ -27,7 +27,7 @@
  */
 
     .text
-    .align 0
+    .balign 0
 
     .global asm_test_jacket
 
diff --git a/libpixelflinger/tests/arch-mips64/assembler/asm_mips_test_jacket.S b/libpixelflinger/tests/arch-mips64/assembler/asm_mips_test_jacket.S
index 8a7f742..705ee9b 100644
--- a/libpixelflinger/tests/arch-mips64/assembler/asm_mips_test_jacket.S
+++ b/libpixelflinger/tests/arch-mips64/assembler/asm_mips_test_jacket.S
@@ -27,7 +27,7 @@
 #  */
 
     .text
-    .align 8
+    .balign 8
 
     .global asm_mips_test_jacket
 
diff --git a/libpixelflinger/tests/arch-mips64/assembler/mips64_assembler_test.cpp b/libpixelflinger/tests/arch-mips64/assembler/mips64_assembler_test.cpp
index b680b60..9fb0a28 100644
--- a/libpixelflinger/tests/arch-mips64/assembler/mips64_assembler_test.cpp
+++ b/libpixelflinger/tests/arch-mips64/assembler/mips64_assembler_test.cpp
@@ -26,22 +26,21 @@
  * SUCH DAMAGE.
  */
 
+#include <errno.h>
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
-#include <errno.h>
-
 #include <sys/mman.h>
-#include <cutils/ashmem.h>
-#include <cutils/atomic.h>
-#include <cutils/log.h>
+#include <unistd.h>
 
-#define __STDC_FORMAT_MACROS
-#include <inttypes.h>
+#include <android/log.h>
+#include <cutils/ashmem.h>
 
 #include "codeflinger/ARMAssemblerInterface.h"
 #include "codeflinger/MIPS64Assembler.h"
+
 using namespace android;
 
 #define TESTS_DATAOP_ENABLE             1
diff --git a/libpixelflinger/trap.cpp b/libpixelflinger/trap.cpp
index ea53625..fa6338a 100644
--- a/libpixelflinger/trap.cpp
+++ b/libpixelflinger/trap.cpp
@@ -2,29 +2,31 @@
 **
 ** Copyright 2006, 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 
+** 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 
+**     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 
+** 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.
 */
 
+#define LOG_TAG "pixelflinger-trap"
+
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 
+#include <android/log.h>
+#include <cutils/memory.h>
+
 #include "trap.h"
 #include "picker.h"
 
-#include <cutils/log.h>
-#include <cutils/memory.h>
-
 namespace android {
 
 // ----------------------------------------------------------------------------
diff --git a/libprocessgroup/Android.mk b/libprocessgroup/Android.mk
index 1885fa5..0bfc391 100644
--- a/libprocessgroup/Android.mk
+++ b/libprocessgroup/Android.mk
@@ -3,7 +3,16 @@
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := processgroup.cpp
 LOCAL_MODULE := libprocessgroup
-LOCAL_SHARED_LIBRARIES := liblog libutils
+LOCAL_STATIC_LIBRARIES := libbase
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Wall -Werror
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := processgroup.cpp
+LOCAL_MODULE := libprocessgroup
+LOCAL_SHARED_LIBRARIES := libbase
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_CFLAGS := -Wall -Werror
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 1bc1659..eb66727 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -22,21 +22,24 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
-#include <mutex>
-#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
-#include <log/log.h>
+#include <chrono>
+#include <memory>
+#include <mutex>
+#include <thread>
+
+#include <android-base/logging.h>
 #include <private/android_filesystem_config.h>
 
-#include <utils/SystemClock.h>
-
 #include <processgroup/processgroup.h>
 
+using namespace std::chrono_literals;
+
 // Uncomment line below use memory cgroups for keeping track of (forked) PIDs
 // #define USE_MEMCG 1
 
@@ -112,7 +115,7 @@
     int fd = open(path, O_RDONLY);
     if (fd < 0) {
         ret = -errno;
-        SLOGW("failed to open %s: %s", path, strerror(errno));
+        PLOG(WARNING) << "failed to open " << path;
         return ret;
     }
 
@@ -121,7 +124,7 @@
     ctx->buf_len = 0;
     ctx->initialized = true;
 
-    SLOGV("Initialized context for %s", path);
+    LOG(VERBOSE) << "Initialized context for " << path;
 
     return 0;
 }
@@ -141,7 +144,7 @@
 
     ctx->buf_len += ret;
     ctx->buf[ctx->buf_len] = 0;
-    SLOGV("Read %zd to buffer: %s", ret, ctx->buf);
+    LOG(VERBOSE) << "Read " << ret << " to buffer: " << ctx->buf;
 
     assert(ctx->buf_len <= sizeof(ctx->buf));
 
@@ -201,11 +204,10 @@
 
 static void removeUidProcessGroups(const char *uid_path)
 {
-    DIR *uid = opendir(uid_path);
+    std::unique_ptr<DIR, decltype(&closedir)> uid(opendir(uid_path), closedir);
     if (uid != NULL) {
-        struct dirent cur;
-        struct dirent *dir;
-        while ((readdir_r(uid, &cur, &dir) == 0) && dir) {
+        dirent* dir;
+        while ((dir = readdir(uid.get())) != nullptr) {
             char path[PROCESSGROUP_MAX_PATH_LEN];
 
             if (dir->d_type != DT_DIR) {
@@ -217,24 +219,22 @@
             }
 
             snprintf(path, sizeof(path), "%s/%s", uid_path, dir->d_name);
-            SLOGV("removing %s\n", path);
-            rmdir(path);
+            LOG(VERBOSE) << "removing " << path;
+            if (rmdir(path) == -1) PLOG(WARNING) << "failed to remove " << path;
         }
-        closedir(uid);
     }
 }
 
 void removeAllProcessGroups()
 {
-    SLOGV("removeAllProcessGroups()");
-    const char *cgroup_root_path = getCgroupRootPath();
-    DIR *root = opendir(cgroup_root_path);
+    LOG(VERBOSE) << "removeAllProcessGroups()";
+    const char* cgroup_root_path = getCgroupRootPath();
+    std::unique_ptr<DIR, decltype(&closedir)> root(opendir(cgroup_root_path), closedir);
     if (root == NULL) {
-        SLOGE("failed to open %s: %s", cgroup_root_path, strerror(errno));
+        PLOG(ERROR) << "failed to open " << cgroup_root_path;
     } else {
-        struct dirent cur;
-        struct dirent *dir;
-        while ((readdir_r(root, &cur, &dir) == 0) && dir) {
+        dirent* dir;
+        while ((dir = readdir(root.get())) != nullptr) {
             char path[PROCESSGROUP_MAX_PATH_LEN];
 
             if (dir->d_type != DT_DIR) {
@@ -246,10 +246,9 @@
 
             snprintf(path, sizeof(path), "%s/%s", cgroup_root_path, dir->d_name);
             removeUidProcessGroups(path);
-            SLOGV("removing %s\n", path);
-            rmdir(path);
+            LOG(VERBOSE) << "removing " << path;
+            if (rmdir(path) == -1) PLOG(WARNING) << "failed to remove " << path;
         }
-        closedir(root);
     }
 }
 
@@ -266,19 +265,13 @@
         if (pid == 0) {
             // Should never happen...  but if it does, trying to kill this
             // will boomerang right back and kill us!  Let's not let that happen.
-            SLOGW("Yikes, we've been told to kill pid 0!  How about we don't do that.");
+            LOG(WARNING) << "Yikes, we've been told to kill pid 0!  How about we don't do that?";
             continue;
         }
-        if (pid != initialPid) {
-            // We want to be noisy about killing processes so we can understand
-            // what is going on in the log; however, don't be noisy about the base
-            // process, since that it something we always kill, and we have already
-            // logged elsewhere about killing it.
-            SLOGI("Killing pid %d in uid %d as part of process group %d", pid, uid, initialPid);
-        }
-        int ret = kill(pid, signal);
-        if (ret == -1) {
-            SLOGW("failed to kill pid %d: %s", pid, strerror(errno));
+        LOG(VERBOSE) << "Killing pid " << pid << " in uid " << uid
+                     << " as part of process group " << initialPid;
+        if (kill(pid, signal) == -1) {
+            PLOG(WARNING) << "kill(" << pid << ", " << signal << ") failed";
         }
     }
 
@@ -291,25 +284,27 @@
 
 int killProcessGroup(uid_t uid, int initialPid, int signal)
 {
-    int processes;
-    const int sleep_us = 5 * 1000;  // 5ms
-    int64_t startTime = android::uptimeMillis();
-    int retry = 40;
+    std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
 
+    int retry = 40;
+    int processes;
     while ((processes = killProcessGroupOnce(uid, initialPid, signal)) > 0) {
-        SLOGV("killed %d processes for processgroup %d\n", processes, initialPid);
+        LOG(VERBOSE) << "killed " << processes << " processes for processgroup " << initialPid;
         if (retry > 0) {
-            usleep(sleep_us);
+            std::this_thread::sleep_for(5ms);
             --retry;
         } else {
-            SLOGE("failed to kill %d processes for processgroup %d\n",
-                    processes, initialPid);
+            LOG(ERROR) << "failed to kill " << processes << " processes for processgroup "
+                       << initialPid;
             break;
         }
     }
 
-    SLOGV("Killed process group uid %d pid %d in %" PRId64 "ms, %d procs remain", uid, initialPid,
-            android::uptimeMillis()-startTime, processes);
+    std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
+
+    auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
+    LOG(VERBOSE) << "Killed process group uid " << uid << " pid " << initialPid << " in "
+                 << static_cast<int>(ms) << "ms, " << processes << " procs remain";
 
     if (processes == 0) {
         return removeProcessGroup(uid, initialPid);
@@ -318,67 +313,58 @@
     }
 }
 
-static int mkdirAndChown(const char *path, mode_t mode, uid_t uid, gid_t gid)
+static bool mkdirAndChown(const char *path, mode_t mode, uid_t uid, gid_t gid)
 {
-    int ret;
-
-    ret = mkdir(path, mode);
-    if (ret < 0 && errno != EEXIST) {
-        return -errno;
+    if (mkdir(path, mode) == -1 && errno != EEXIST) {
+        return false;
     }
 
-    ret = chown(path, uid, gid);
-    if (ret < 0) {
-        ret = -errno;
+    if (chown(path, uid, gid) == -1) {
+        int saved_errno = errno;
         rmdir(path);
-        return ret;
+        errno = saved_errno;
+        return false;
     }
 
-    return 0;
+    return true;
 }
 
 int createProcessGroup(uid_t uid, int initialPid)
 {
     char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
-    int ret;
 
     convertUidToPath(path, sizeof(path), uid);
 
-    ret = mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM);
-    if (ret < 0) {
-        SLOGE("failed to make and chown %s: %s", path, strerror(-ret));
-        return ret;
+    if (!mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM)) {
+        PLOG(ERROR) << "failed to make and chown " << path;
+        return -errno;
     }
 
     convertUidPidToPath(path, sizeof(path), uid, initialPid);
 
-    ret = mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM);
-    if (ret < 0) {
-        SLOGE("failed to make and chown %s: %s", path, strerror(-ret));
-        return ret;
+    if (!mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM)) {
+        PLOG(ERROR) << "failed to make and chown " << path;
+        return -errno;
     }
 
     strlcat(path, PROCESSGROUP_CGROUP_PROCS_FILE, sizeof(path));
 
     int fd = open(path, O_WRONLY);
-    if (fd < 0) {
-        ret = -errno;
-        SLOGE("failed to open %s: %s", path, strerror(errno));
+    if (fd == -1) {
+        int ret = -errno;
+        PLOG(ERROR) << "failed to open " << path;
         return ret;
     }
 
     char pid[PROCESSGROUP_MAX_PID_LEN + 1] = {0};
     int len = snprintf(pid, sizeof(pid), "%d", initialPid);
 
-    ret = write(fd, pid, len);
-    if (ret < 0) {
+    int ret = 0;
+    if (write(fd, pid, len) < 0) {
         ret = -errno;
-        SLOGE("failed to write '%s' to %s: %s", pid, path, strerror(errno));
-    } else {
-        ret = 0;
+        PLOG(ERROR) << "failed to write '" << pid << "' to " << path;
     }
 
     close(fd);
     return ret;
 }
-
diff --git a/libprocinfo/.clang-format b/libprocinfo/.clang-format
new file mode 100644
index 0000000..b8c6428
--- /dev/null
+++ b/libprocinfo/.clang-format
@@ -0,0 +1,14 @@
+BasedOnStyle: Google
+AllowShortBlocksOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 2
+PointerAlignment: Left
+TabWidth: 2
+UseTab: Never
+PenaltyExcessCharacter: 32
+
+Cpp11BracedListStyle: false
diff --git a/libprocinfo/Android.bp b/libprocinfo/Android.bp
new file mode 100644
index 0000000..8e17f1b
--- /dev/null
+++ b/libprocinfo/Android.bp
@@ -0,0 +1,73 @@
+//
+// 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.
+//
+
+libprocinfo_cppflags = [
+    "-Wall",
+    "-Wextra",
+    "-Werror",
+]
+
+cc_library {
+    name: "libprocinfo",
+    host_supported: true,
+    srcs: [
+        "process.cpp",
+    ],
+    cppflags: libprocinfo_cppflags,
+
+    local_include_dirs: ["include"],
+    export_include_dirs: ["include"],
+    shared_libs: ["libbase"],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+        windows: {
+            enabled: false,
+        },
+    },
+}
+
+// Tests
+// ------------------------------------------------------------------------------
+cc_test {
+    name: "libprocinfo_test",
+    host_supported: true,
+    srcs: [
+        "process_test.cpp",
+    ],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+        windows: {
+            enabled: false,
+        },
+    },
+
+    cppflags: libprocinfo_cppflags,
+    shared_libs: ["libbase", "libprocinfo"],
+
+    compile_multilib: "both",
+    multilib: {
+        lib32: {
+            suffix: "32",
+        },
+        lib64: {
+            suffix: "64",
+        },
+    },
+}
diff --git a/libprocinfo/include/procinfo/process.h b/libprocinfo/include/procinfo/process.h
new file mode 100644
index 0000000..fb140ff
--- /dev/null
+++ b/libprocinfo/include/procinfo/process.h
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+#include <string>
+#include <type_traits>
+
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/unique_fd.h>
+
+namespace android {
+namespace procinfo {
+
+#if defined(__linux__)
+
+struct ProcessInfo {
+  std::string name;
+  pid_t tid;
+  pid_t pid;
+  pid_t ppid;
+  pid_t tracer;
+  uid_t uid;
+  uid_t gid;
+};
+
+// Parse the contents of /proc/<tid>/status into |process_info|.
+bool GetProcessInfo(pid_t tid, ProcessInfo* process_info);
+
+// Parse the contents of <fd>/status into |process_info|.
+// |fd| should be an fd pointing at a /proc/<pid> directory.
+bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info);
+
+// Fetch the list of threads from a given process's /proc/<pid> directory.
+// |fd| should be an fd pointing at a /proc/<pid> directory.
+template <typename Collection>
+auto GetProcessTidsFromProcPidFd(int fd, Collection* out) ->
+    typename std::enable_if<sizeof(typename Collection::value_type) >= sizeof(pid_t), bool>::type {
+  out->clear();
+
+  int task_fd = openat(fd, "task", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
+  std::unique_ptr<DIR, int (*)(DIR*)> dir(fdopendir(task_fd), closedir);
+  if (!dir) {
+    PLOG(ERROR) << "failed to open task directory";
+    return false;
+  }
+
+  struct dirent* dent;
+  while ((dent = readdir(dir.get()))) {
+    if (strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0) {
+      pid_t tid;
+      if (!android::base::ParseInt(dent->d_name, &tid, 1, std::numeric_limits<pid_t>::max())) {
+        LOG(ERROR) << "failed to parse task id: " << dent->d_name;
+        return false;
+      }
+
+      out->insert(out->end(), tid);
+    }
+  }
+
+  return true;
+}
+
+template <typename Collection>
+auto GetProcessTids(pid_t pid, Collection* out) ->
+    typename std::enable_if<sizeof(typename Collection::value_type) >= sizeof(pid_t), bool>::type {
+  char task_path[PATH_MAX];
+  if (snprintf(task_path, PATH_MAX, "/proc/%d", pid) >= PATH_MAX) {
+    LOG(ERROR) << "task path overflow (pid = " << pid << ")";
+    return false;
+  }
+
+  android::base::unique_fd fd(open(task_path, O_DIRECTORY | O_RDONLY | O_CLOEXEC));
+  if (fd == -1) {
+    PLOG(ERROR) << "failed to open " << task_path;
+    return false;
+  }
+
+  return GetProcessTidsFromProcPidFd(fd.get(), out);
+}
+
+#endif
+
+} /* namespace procinfo */
+} /* namespace android */
diff --git a/libprocinfo/process.cpp b/libprocinfo/process.cpp
new file mode 100644
index 0000000..c513e16
--- /dev/null
+++ b/libprocinfo/process.cpp
@@ -0,0 +1,109 @@
+/*
+ * 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 <procinfo/process.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <android-base/unique_fd.h>
+
+using android::base::unique_fd;
+
+namespace android {
+namespace procinfo {
+
+bool GetProcessInfo(pid_t tid, ProcessInfo* process_info) {
+  char path[PATH_MAX];
+  snprintf(path, sizeof(path), "/proc/%d", tid);
+
+  unique_fd dirfd(open(path, O_DIRECTORY | O_RDONLY));
+  if (dirfd == -1) {
+    PLOG(ERROR) << "failed to open " << path;
+    return false;
+  }
+
+  return GetProcessInfoFromProcPidFd(dirfd.get(), process_info);
+}
+
+bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info) {
+  int status_fd = openat(fd, "status", O_RDONLY | O_CLOEXEC);
+
+  if (status_fd == -1) {
+    PLOG(ERROR) << "failed to open status fd in GetProcessInfoFromProcPidFd";
+    return false;
+  }
+
+  std::unique_ptr<FILE, decltype(&fclose)> fp(fdopen(status_fd, "r"), fclose);
+  if (!fp) {
+    PLOG(ERROR) << "failed to open status file in GetProcessInfoFromProcPidFd";
+    close(status_fd);
+    return false;
+  }
+
+  int field_bitmap = 0;
+  static constexpr int finished_bitmap = 127;
+  char* line = nullptr;
+  size_t len = 0;
+
+  while (getline(&line, &len, fp.get()) != -1 && field_bitmap != finished_bitmap) {
+    char* tab = strchr(line, '\t');
+    if (tab == nullptr) {
+      continue;
+    }
+
+    size_t header_len = tab - line;
+    std::string header = std::string(line, header_len);
+    if (header == "Name:") {
+      std::string name = line + header_len + 1;
+
+      // line includes the trailing newline.
+      name.pop_back();
+      process_info->name = std::move(name);
+
+      field_bitmap |= 1;
+    } else if (header == "Pid:") {
+      process_info->tid = atoi(tab + 1);
+      field_bitmap |= 2;
+    } else if (header == "Tgid:") {
+      process_info->pid = atoi(tab + 1);
+      field_bitmap |= 4;
+    } else if (header == "PPid:") {
+      process_info->ppid = atoi(tab + 1);
+      field_bitmap |= 8;
+    } else if (header == "TracerPid:") {
+      process_info->tracer = atoi(tab + 1);
+      field_bitmap |= 16;
+    } else if (header == "Uid:") {
+      process_info->uid = atoi(tab + 1);
+      field_bitmap |= 32;
+    } else if (header == "Gid:") {
+      process_info->gid = atoi(tab + 1);
+      field_bitmap |= 64;
+    }
+  }
+
+  free(line);
+  return field_bitmap == finished_bitmap;
+}
+
+} /* namespace procinfo */
+} /* namespace android */
diff --git a/libprocinfo/process_test.cpp b/libprocinfo/process_test.cpp
new file mode 100644
index 0000000..5ffd236
--- /dev/null
+++ b/libprocinfo/process_test.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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 <procinfo/process.h>
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <set>
+#include <thread>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <android-base/stringprintf.h>
+
+#if !defined(__BIONIC__)
+#include <syscall.h>
+static pid_t gettid() {
+  return syscall(__NR_gettid);
+}
+#endif
+
+TEST(process_info, process_info_smoke) {
+  android::procinfo::ProcessInfo self;
+  ASSERT_TRUE(android::procinfo::GetProcessInfo(gettid(), &self));
+  ASSERT_EQ(gettid(), self.tid);
+  ASSERT_EQ(getpid(), self.pid);
+  ASSERT_EQ(getppid(), self.ppid);
+  ASSERT_EQ(getuid(), self.uid);
+  ASSERT_EQ(getgid(), self.gid);
+}
+
+TEST(process_info, process_info_proc_pid_fd_smoke) {
+  android::procinfo::ProcessInfo self;
+  int fd = open(android::base::StringPrintf("/proc/%d", gettid()).c_str(), O_DIRECTORY | O_RDONLY);
+  ASSERT_NE(-1, fd);
+  ASSERT_TRUE(android::procinfo::GetProcessInfoFromProcPidFd(fd, &self));
+
+  // Process name is capped at 15 bytes.
+  ASSERT_EQ("libprocinfo_tes", self.name);
+  ASSERT_EQ(gettid(), self.tid);
+  ASSERT_EQ(getpid(), self.pid);
+  ASSERT_EQ(getppid(), self.ppid);
+  ASSERT_EQ(getuid(), self.uid);
+  ASSERT_EQ(getgid(), self.gid);
+  close(fd);
+}
+
+TEST(process_info, process_tids_smoke) {
+  pid_t main_tid = gettid();
+  std::thread([main_tid]() {
+    pid_t thread_tid = gettid();
+
+    {
+      std::vector<pid_t> vec;
+      ASSERT_TRUE(android::procinfo::GetProcessTids(getpid(), &vec));
+      ASSERT_EQ(1, std::count(vec.begin(), vec.end(), main_tid));
+      ASSERT_EQ(1, std::count(vec.begin(), vec.end(), thread_tid));
+    }
+
+    {
+      std::set<pid_t> set;
+      ASSERT_TRUE(android::procinfo::GetProcessTids(getpid(), &set));
+      ASSERT_EQ(1, std::count(set.begin(), set.end(), main_tid));
+      ASSERT_EQ(1, std::count(set.begin(), set.end(), thread_tid));
+    }
+  }).join();
+}
diff --git a/libsparse/Android.bp b/libsparse/Android.bp
new file mode 100644
index 0000000..7a6ae8a
--- /dev/null
+++ b/libsparse/Android.bp
@@ -0,0 +1,78 @@
+// Copyright 2010 The Android Open Source Project
+
+cc_defaults {
+    name: "libsparse_defaults",
+    srcs: [
+        "backed_block.c",
+        "output_file.c",
+        "sparse.c",
+        "sparse_crc32.c",
+        "sparse_err.c",
+        "sparse_read.c",
+    ],
+    cflags: ["-Werror"],
+    local_include_dirs: ["include"],
+    export_include_dirs: ["include"],
+}
+
+cc_library_host_static {
+    name: "libsparse_host",
+    defaults: ["libsparse_defaults"],
+    static_libs: ["libz"],
+    target: {
+        windows: {
+            enabled: true,
+        },
+    },
+}
+
+cc_library_shared {
+    name: "libsparse",
+    defaults: ["libsparse_defaults"],
+    shared_libs: ["libz"],
+}
+
+cc_library_static {
+    name: "libsparse_static",
+    host_supported: true,
+    defaults: ["libsparse_defaults"],
+    static_libs: ["libz"],
+}
+
+cc_binary {
+    name: "simg2img",
+    host_supported: true,
+    srcs: [
+        "simg2img.c",
+        "sparse_crc32.c",
+    ],
+    static_libs: [
+        "libsparse_static",
+        "libz",
+    ],
+
+    cflags: ["-Werror"],
+}
+
+cc_binary {
+    name: "img2simg",
+    host_supported: true,
+    srcs: ["img2simg.c"],
+    static_libs: [
+        "libsparse_static",
+        "libz",
+    ],
+
+    cflags: ["-Werror"],
+}
+
+cc_binary_host {
+    name: "append2simg",
+    srcs: ["append2simg.c"],
+    static_libs: [
+        "libsparse_static",
+        "libz",
+    ],
+
+    cflags: ["-Werror"],
+}
diff --git a/libsparse/Android.mk b/libsparse/Android.mk
index c77eba9..05e68bc 100644
--- a/libsparse/Android.mk
+++ b/libsparse/Android.mk
@@ -2,106 +2,6 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-libsparse_src_files := \
-        backed_block.c \
-        output_file.c \
-        sparse.c \
-        sparse_crc32.c \
-        sparse_err.c \
-        sparse_read.c
-
-
-include $(CLEAR_VARS)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_SRC_FILES := $(libsparse_src_files)
-LOCAL_MODULE := libsparse_host
-LOCAL_STATIC_LIBRARIES := libz
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Werror
-LOCAL_MODULE_HOST_OS := darwin linux windows
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-
-include $(CLEAR_VARS)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_SRC_FILES := $(libsparse_src_files)
-LOCAL_MODULE := libsparse
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
-LOCAL_SHARED_LIBRARIES := \
-    libz
-LOCAL_CFLAGS := -Werror
-include $(BUILD_SHARED_LIBRARY)
-
-
-include $(CLEAR_VARS)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_SRC_FILES := $(libsparse_src_files)
-LOCAL_MODULE := libsparse_static
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
-LOCAL_STATIC_LIBRARIES := libz
-LOCAL_CFLAGS := -Werror
-include $(BUILD_STATIC_LIBRARY)
-
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := simg2img.c \
-	sparse_crc32.c
-LOCAL_MODULE := simg2img_host
-# Need a unique module name, but exe should still be called simg2img
-LOCAL_MODULE_STEM := simg2img
-LOCAL_STATIC_LIBRARIES := \
-    libsparse_host \
-    libz
-LOCAL_CFLAGS := -Werror
-include $(BUILD_HOST_EXECUTABLE)
-
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := simg2img.c \
-	sparse_crc32.c
-LOCAL_MODULE := simg2img
-LOCAL_STATIC_LIBRARIES := \
-    libsparse_static \
-    libz
-LOCAL_CFLAGS := -Werror
-include $(BUILD_EXECUTABLE)
-
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := img2simg.c
-LOCAL_MODULE := img2simg_host
-# Need a unique module name, but exe should still be called simg2img
-LOCAL_MODULE_STEM := img2simg
-LOCAL_STATIC_LIBRARIES := \
-    libsparse_host \
-    libz
-LOCAL_CFLAGS := -Werror
-include $(BUILD_HOST_EXECUTABLE)
-
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := img2simg.c
-LOCAL_MODULE := img2simg
-LOCAL_STATIC_LIBRARIES := \
-    libsparse_static \
-    libz
-LOCAL_CFLAGS := -Werror
-include $(BUILD_EXECUTABLE)
-
-
-ifneq ($(HOST_OS),windows)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := append2simg.c
-LOCAL_MODULE := append2simg
-LOCAL_STATIC_LIBRARIES := \
-    libsparse_host \
-    libz
-LOCAL_CFLAGS := -Werror
-include $(BUILD_HOST_EXECUTABLE)
-
-endif
-
 include $(CLEAR_VARS)
 LOCAL_MODULE := simg_dump.py
 LOCAL_SRC_FILES := simg_dump.py
diff --git a/libsparse/output_file.c b/libsparse/output_file.c
index cd30800..2115998 100644
--- a/libsparse/output_file.c
+++ b/libsparse/output_file.c
@@ -34,7 +34,7 @@
 #include "sparse_crc32.h"
 #include "sparse_format.h"
 
-#ifndef USE_MINGW
+#ifndef _WIN32
 #include <sys/mman.h>
 #define O_BINARY 0
 #else
@@ -57,13 +57,13 @@
 #define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
 
 #define container_of(inner, outer_t, elem) \
-	((outer_t *)((char *)inner - offsetof(outer_t, elem)))
+	((outer_t *)((char *)(inner) - offsetof(outer_t, elem)))
 
 struct output_file_ops {
 	int (*open)(struct output_file *, int fd);
 	int (*skip)(struct output_file *, int64_t);
 	int (*pad)(struct output_file *, int64_t);
-	int (*write)(struct output_file *, void *, int);
+	int (*write)(struct output_file *, void *, size_t);
 	void (*close)(struct output_file *);
 };
 
@@ -149,18 +149,23 @@
 	return 0;
 }
 
-static int file_write(struct output_file *out, void *data, int len)
+static int file_write(struct output_file *out, void *data, size_t len)
 {
-	int ret;
+	ssize_t ret;
 	struct output_file_normal *outn = to_output_file_normal(out);
 
-	ret = write(outn->fd, data, len);
-	if (ret < 0) {
-		error_errno("write");
-		return -1;
-	} else if (ret < len) {
-		error("incomplete write");
-		return -1;
+	while (len > 0) {
+		ret = write(outn->fd, data, len);
+		if (ret < 0) {
+			if (errno == EINTR) {
+				continue;
+			}
+			error_errno("write");
+			return -1;
+		}
+
+		data = (char *)data + ret;
+		len -= ret;
 	}
 
 	return 0;
@@ -232,18 +237,20 @@
 	return 0;
 }
 
-static int gz_file_write(struct output_file *out, void *data, int len)
+static int gz_file_write(struct output_file *out, void *data, size_t len)
 {
 	int ret;
 	struct output_file_gz *outgz = to_output_file_gz(out);
 
-	ret = gzwrite(outgz->gz_fd, data, len);
-	if (ret < 0) {
-		error_errno("gzwrite");
-		return -1;
-	} else if (ret < len) {
-		error("incomplete gzwrite");
-		return -1;
+	while (len > 0) {
+		ret = gzwrite(outgz->gz_fd, data,
+			      min(len, (unsigned int)INT_MAX));
+		if (ret == 0) {
+			error("gzwrite %s", gzerror(outgz->gz_fd, NULL));
+			return -1;
+		}
+		len -= ret;
+		data = (char *)data + ret;
 	}
 
 	return 0;
@@ -293,7 +300,7 @@
 	return -1;
 }
 
-static int callback_file_write(struct output_file *out, void *data, int len)
+static int callback_file_write(struct output_file *out, void *data, size_t len)
 {
 	struct output_file_callback *outc = to_output_file_callback(out);
 
@@ -698,14 +705,16 @@
 	int ret;
 	int64_t aligned_offset;
 	int aligned_diff;
-	int buffer_size;
+	uint64_t buffer_size;
 	char *ptr;
 
 	aligned_offset = offset & ~(4096 - 1);
 	aligned_diff = offset - aligned_offset;
-	buffer_size = len + aligned_diff;
+	buffer_size = (uint64_t)len + (uint64_t)aligned_diff;
 
-#ifndef USE_MINGW
+#ifndef _WIN32
+	if (buffer_size > SIZE_MAX)
+		return -E2BIG;
 	char *data = mmap64(NULL, buffer_size, PROT_READ, MAP_SHARED, fd,
 			aligned_offset);
 	if (data == MAP_FAILED) {
@@ -733,7 +742,7 @@
 
 	ret = out->sparse_ops->write_data_chunk(out, len, ptr);
 
-#ifndef USE_MINGW
+#ifndef _WIN32
 	munmap(data, buffer_size);
 #else
 	free(data);
diff --git a/libsparse/sparse_read.c b/libsparse/sparse_read.c
index dbb4dab..a188202 100644
--- a/libsparse/sparse_read.c
+++ b/libsparse/sparse_read.c
@@ -79,7 +79,7 @@
 		s = " at ";
 	}
 	if (verbose) {
-#ifndef USE_MINGW
+#ifndef _WIN32
 		if (err == -EOVERFLOW) {
 			sparse_print_verbose("EOF while reading file%s%s\n", s, at);
 		} else
diff --git a/libsuspend/Android.bp b/libsuspend/Android.bp
new file mode 100644
index 0000000..d27ceea
--- /dev/null
+++ b/libsuspend/Android.bp
@@ -0,0 +1,21 @@
+// Copyright 2012 The Android Open Source Project
+
+cc_library {
+    name: "libsuspend",
+    srcs: [
+        "autosuspend.c",
+        "autosuspend_autosleep.c",
+        "autosuspend_earlysuspend.c",
+        "autosuspend_wakeup_count.c",
+    ],
+    export_include_dirs: ["include"],
+    local_include_dirs: ["include"],
+    shared_libs: [
+        "liblog",
+        "libcutils",
+    ],
+    cflags: [
+        "-Werror",
+        // "-DLOG_NDEBUG=0",
+    ],
+}
diff --git a/libsuspend/Android.mk b/libsuspend/Android.mk
deleted file mode 100644
index 1ba2f59..0000000
--- a/libsuspend/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright 2012 The Android Open Source Project
-
-LOCAL_PATH:= $(call my-dir)
-
-libsuspend_src_files := \
-	autosuspend.c \
-	autosuspend_autosleep.c \
-	autosuspend_earlysuspend.c \
-	autosuspend_wakeup_count.c \
-
-libsuspend_libraries := \
-	liblog libcutils
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(libsuspend_src_files)
-LOCAL_MODULE := libsuspend
-LOCAL_MODULE_TAGS := optional
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
-LOCAL_SHARED_LIBRARIES := $(libsuspend_libraries)
-LOCAL_CFLAGS := -Werror
-#LOCAL_CFLAGS += -DLOG_NDEBUG=0
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(libsuspend_src_files)
-LOCAL_MODULE := libsuspend
-LOCAL_MODULE_TAGS := optional
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Werror
-#LOCAL_CFLAGS += -DLOG_NDEBUG=0
-include $(BUILD_STATIC_LIBRARY)
diff --git a/libsuspend/autosuspend.c b/libsuspend/autosuspend.c
index edd1007..64d1bfc 100644
--- a/libsuspend/autosuspend.c
+++ b/libsuspend/autosuspend.c
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "libsuspend"
+
 #include <stdbool.h>
 
-#define LOG_TAG "libsuspend"
-#include <cutils/log.h>
+#include <android/log.h>
 
 #include <suspend/autosuspend.h>
 
diff --git a/libsuspend/autosuspend_autosleep.c b/libsuspend/autosuspend_autosleep.c
index 7262cc7..97109ac 100644
--- a/libsuspend/autosuspend_autosleep.c
+++ b/libsuspend/autosuspend_autosleep.c
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "libsuspend"
+
 #include <errno.h>
 #include <fcntl.h>
 #include <stddef.h>
@@ -22,8 +24,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#define LOG_TAG "libsuspend"
-#include <cutils/log.h>
+#include <android/log.h>
 
 #include "autosuspend_ops.h"
 
diff --git a/libsuspend/autosuspend_earlysuspend.c b/libsuspend/autosuspend_earlysuspend.c
index 3793a69..9519e51 100644
--- a/libsuspend/autosuspend_earlysuspend.c
+++ b/libsuspend/autosuspend_earlysuspend.c
@@ -14,18 +14,19 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "libsuspend"
+
 #include <errno.h>
 #include <fcntl.h>
 #include <pthread.h>
 #include <stdbool.h>
 #include <stddef.h>
 #include <string.h>
-#include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
-#define LOG_TAG "libsuspend"
-#include <cutils/log.h>
+#include <android/log.h>
 
 #include "autosuspend_ops.h"
 
diff --git a/libsuspend/autosuspend_wakeup_count.c b/libsuspend/autosuspend_wakeup_count.c
index 23a0290..d3fb45f 100644
--- a/libsuspend/autosuspend_wakeup_count.c
+++ b/libsuspend/autosuspend_wakeup_count.c
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "libsuspend"
+//#define LOG_NDEBUG 0
+
 #include <errno.h>
 #include <fcntl.h>
 #include <pthread.h>
@@ -25,9 +28,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#define LOG_TAG "libsuspend"
-//#define LOG_NDEBUG 0
-#include <cutils/log.h>
+#include <android/log.h>
 
 #include "autosuspend_ops.h"
 
diff --git a/libsync/Android.bp b/libsync/Android.bp
new file mode 100644
index 0000000..a4e5599
--- /dev/null
+++ b/libsync/Android.bp
@@ -0,0 +1,41 @@
+cc_defaults {
+    name: "libsync_defaults",
+    srcs: ["sync.c"],
+    local_include_dirs: ["include"],
+    export_include_dirs: ["include"],
+    cflags: ["-Werror"],
+}
+
+cc_library_shared {
+    name: "libsync",
+    defaults: ["libsync_defaults"],
+}
+
+// libsync_recovery is only intended for the recovery binary.
+// Future versions of the kernel WILL require an updated libsync, and will break
+// anything statically linked against the current libsync.
+cc_library_static {
+    name: "libsync_recovery",
+    defaults: ["libsync_defaults"],
+}
+
+cc_test {
+    name: "sync_test",
+    defaults: ["libsync_defaults"],
+    gtest: false,
+    srcs: ["sync_test.c"],
+}
+
+cc_test {
+    name: "sync-unit-tests",
+    shared_libs: ["libsync"],
+    srcs: ["tests/sync_test.cpp"],
+    cflags: [
+        "-g",
+        "-Wall",
+        "-Werror",
+        "-Wno-missing-field-initializers",
+        "-Wno-sign-compare",
+    ],
+    clang: true,
+}
diff --git a/libsync/Android.mk b/libsync/Android.mk
deleted file mode 100644
index fd1c88c..0000000
--- a/libsync/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := sync.c
-LOCAL_MODULE := libsync
-LOCAL_MODULE_TAGS := optional
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Werror
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := sync.c sync_test.c
-LOCAL_MODULE := sync_test
-LOCAL_MODULE_TAGS := optional tests
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Werror
-include $(BUILD_EXECUTABLE)
diff --git a/libsync/sync.c b/libsync/sync.c
index d73bb11..169dc36 100644
--- a/libsync/sync.c
+++ b/libsync/sync.c
@@ -21,13 +21,27 @@
 #include <stdint.h>
 #include <string.h>
 
-#include <linux/sync.h>
 #include <linux/sw_sync.h>
 
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <sync/sync.h>
+
+// The sync code is undergoing a major change. Add enough in to get
+// everything to compile wih the latest uapi headers.
+struct sync_merge_data {
+  int32_t fd2;
+  char name[32];
+  int32_t fence;
+};
+
+#define SYNC_IOC_MAGIC '>'
+#define SYNC_IOC_WAIT _IOW(SYNC_IOC_MAGIC, 0, __s32)
+#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 1, struct sync_merge_data)
+#define SYNC_IOC_FENCE_INFO _IOWR(SYNC_IOC_MAGIC, 2, struct sync_fence_info_data)
+
 int sync_wait(int fd, int timeout)
 {
     __s32 to = timeout;
diff --git a/libsync/sync_test.c b/libsync/sync_test.c
index ee9ea3c..9a5f7d8 100644
--- a/libsync/sync_test.c
+++ b/libsync/sync_test.c
@@ -92,7 +92,7 @@
 
         for (j = 0; j < 2; j++) {
             unsigned val = i + j * 3 + 1;
-            sprintf(str, "test_fence%d-%d", i, j);
+            snprintf(str, sizeof(str), "test_fence%d-%d", i, j);
             int fd = sw_sync_fence_create(sync_timeline_fd, str, val);
             if (fd < 0) {
                 printf("can't create sync pt %d: %s", val, strerror(errno));
@@ -106,7 +106,7 @@
 
     sync_data[3].thread_no = 3;
     for (j = 0; j < 2; j++) {
-        sprintf(str, "merged_fence%d", j);
+        snprintf(str, sizeof(str), "merged_fence%d", j);
         sync_data[3].fd[j] = sync_merge(str, sync_data[0].fd[j], sync_data[1].fd[j]);
         if (sync_data[3].fd[j] < 0) {
             printf("can't merge sync pts %d and %d: %s\n",
diff --git a/libsysutils/src/FrameworkClient.cpp b/libsysutils/src/FrameworkClient.cpp
index 2f37055..72b3d0a 100644
--- a/libsysutils/src/FrameworkClient.cpp
+++ b/libsysutils/src/FrameworkClient.cpp
@@ -1,11 +1,27 @@
-#include <alloca.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <pthread.h>
+/*
+ * Copyright (C) 2009-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.
+ */
 
 #define LOG_TAG "FrameworkClient"
-#include <cutils/log.h>
 
+#include <alloca.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/types.h>
+
+#include <android/log.h>
 #include <sysutils/FrameworkClient.h>
 
 FrameworkClient::FrameworkClient(int socket) {
diff --git a/libsysutils/src/FrameworkCommand.cpp b/libsysutils/src/FrameworkCommand.cpp
index 0b95a81..a6c4abc 100644
--- a/libsysutils/src/FrameworkCommand.cpp
+++ b/libsysutils/src/FrameworkCommand.cpp
@@ -13,12 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <errno.h>
 
 #define LOG_TAG "FrameworkCommand"
 
-#include <cutils/log.h>
+#include <errno.h>
 
+#include <log/log.h>
 #include <sysutils/FrameworkCommand.h>
 
 #define UNUSED __attribute__((unused))
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index 579ead9..1b6076f 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -13,16 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
 
 #define LOG_TAG "FrameworkListener"
 
-#include <cutils/log.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
 
-#include <sysutils/FrameworkListener.h>
+#include <log/log.h>
 #include <sysutils/FrameworkCommand.h>
+#include <sysutils/FrameworkListener.h>
 #include <sysutils/SocketClient.h>
 
 static const int CMD_BUF_SIZE = 1024;
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 739fad7..fef801a 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -13,39 +13,36 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <stdlib.h>
-#include <string.h>
 
 #define LOG_TAG "NetlinkEvent"
-#include <cutils/log.h>
 
-#include <sysutils/NetlinkEvent.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/icmp6.h>
 #include <arpa/inet.h>
-#include <net/if.h>
-
 #include <linux/if.h>
 #include <linux/if_addr.h>
 #include <linux/if_link.h>
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_log.h>
 #include <linux/netfilter_ipv4/ipt_ULOG.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/icmp6.h>
+#include <netlink/attr.h>
+#include <netlink/genl/genl.h>
+#include <netlink/handlers.h>
+#include <netlink/msg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
 
 /* From kernel's net/netfilter/xt_quota2.c */
 const int LOCAL_QLOG_NL_EVENT = 112;
 const int LOCAL_NFLOG_PACKET = NFNL_SUBSYS_ULOG << 8 | NFULNL_MSG_PACKET;
 
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-
-#include <netlink/attr.h>
-#include <netlink/genl/genl.h>
-#include <netlink/handlers.h>
-#include <netlink/msg.h>
+#include <log/log.h>
+#include <sysutils/NetlinkEvent.h>
 
 NetlinkEvent::NetlinkEvent() {
     mAction = Action::kUnknown;
diff --git a/libsysutils/src/NetlinkListener.cpp b/libsysutils/src/NetlinkListener.cpp
index 637aa1e..896dad3 100644
--- a/libsysutils/src/NetlinkListener.cpp
+++ b/libsysutils/src/NetlinkListener.cpp
@@ -13,17 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <errno.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <linux/netlink.h>
-#include <string.h>
 
 #define LOG_TAG "NetlinkListener"
-#include <cutils/log.h>
-#include <cutils/uevent.h>
 
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/netlink.h> /* out of order because must follow sys/socket.h */
+
+#include <cutils/uevent.h>
+#include <log/log.h>
 #include <sysutils/NetlinkEvent.h>
 
 #if 1
diff --git a/libsysutils/src/ServiceManager.cpp b/libsysutils/src/ServiceManager.cpp
index 41ac1dd..13bac09 100644
--- a/libsysutils/src/ServiceManager.cpp
+++ b/libsysutils/src/ServiceManager.cpp
@@ -1,11 +1,29 @@
-#include <errno.h>
-#include <string.h>
-
-#include <sysutils/ServiceManager.h>
+/*
+ * Copyright (C) 2009-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.
+ */
 
 #define LOG_TAG "Service"
-#include <cutils/log.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
 #include <cutils/properties.h>
+#include <log/log.h>
+#include <sysutils/ServiceManager.h>
 
 ServiceManager::ServiceManager() {
 }
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
index bb9b6a1..971f908 100644
--- a/libsysutils/src/SocketClient.cpp
+++ b/libsysutils/src/SocketClient.cpp
@@ -1,16 +1,33 @@
+/*
+ * Copyright (C) 2009-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.
+ */
+
+#define LOG_TAG "SocketClient"
+
 #include <alloca.h>
+#include <arpa/inet.h>
 #include <errno.h>
 #include <malloc.h>
 #include <pthread.h>
 #include <signal.h>
 #include <string.h>
-#include <arpa/inet.h>
 #include <sys/socket.h>
 #include <sys/types.h>
+#include <unistd.h>
 
-#define LOG_TAG "SocketClient"
-#include <cutils/log.h>
-
+#include <log/log.h>
 #include <sysutils/SocketClient.h>
 
 SocketClient::SocketClient(int socket, bool owned) {
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 168899c..3f8f3db 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -13,19 +13,21 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <stdio.h>
+
+#define LOG_TAG "SocketListener"
+
 #include <errno.h>
+#include <stdio.h>
 #include <stdlib.h>
-#include <sys/socket.h>
 #include <sys/select.h>
+#include <sys/socket.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/un.h>
+#include <unistd.h>
 
-#define LOG_TAG "SocketListener"
-#include <cutils/log.h>
 #include <cutils/sockets.h>
-
+#include <log/log.h>
 #include <sysutils/SocketListener.h>
 #include <sysutils/SocketClient.h>
 
@@ -199,22 +201,12 @@
             continue;
         }
         if (mListen && FD_ISSET(mSock, &read_fds)) {
-            sockaddr_storage ss;
-            sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);
-            socklen_t alen;
-            int c;
-
-            do {
-                alen = sizeof(ss);
-                c = accept(mSock, addrp, &alen);
-                SLOGV("%s got %d from accept", mSocketName, c);
-            } while (c < 0 && errno == EINTR);
+            int c = TEMP_FAILURE_RETRY(accept4(mSock, nullptr, nullptr, SOCK_CLOEXEC));
             if (c < 0) {
                 SLOGE("accept failed (%s)", strerror(errno));
                 sleep(1);
                 continue;
             }
-            fcntl(c, F_SETFD, FD_CLOEXEC);
             pthread_mutex_lock(&mClientsLock);
             mClients->push_back(new SocketClient(c, true, mUseCmdNum));
             pthread_mutex_unlock(&mClientsLock);
diff --git a/libusbhost/Android.mk b/libusbhost/Android.mk
index 5c12f2c..9439846 100644
--- a/libusbhost/Android.mk
+++ b/libusbhost/Android.mk
@@ -22,11 +22,11 @@
 ifeq ($(HOST_OS),linux)
 
 include $(CLEAR_VARS)
-
 LOCAL_MODULE := libusbhost
 LOCAL_SRC_FILES := usbhost.c
 LOCAL_CFLAGS := -Werror
-
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 endif
@@ -35,24 +35,22 @@
 # ========================================================
 
 include $(CLEAR_VARS)
-
 LOCAL_MODULE := libusbhost
 LOCAL_SRC_FILES := usbhost.c
-
 LOCAL_CFLAGS := -g -DUSE_LIBLOG -Werror
-
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 # needed for logcat
 LOCAL_SHARED_LIBRARIES := libcutils
-
 include $(BUILD_SHARED_LIBRARY)
 
 # Static library for target
 # ========================================================
 
 include $(CLEAR_VARS)
-
 LOCAL_MODULE := libusbhost
 LOCAL_SRC_FILES := usbhost.c
 LOCAL_CFLAGS := -Werror
-
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 include $(BUILD_STATIC_LIBRARY)
diff --git a/include/usbhost/usbhost.h b/libusbhost/include/usbhost/usbhost.h
similarity index 99%
rename from include/usbhost/usbhost.h
rename to libusbhost/include/usbhost/usbhost.h
index 88b5b44..84594c8 100644
--- a/include/usbhost/usbhost.h
+++ b/libusbhost/include/usbhost/usbhost.h
@@ -216,7 +216,7 @@
 int usb_device_bulk_transfer(struct usb_device *device,
                             int endpoint,
                             void* buffer,
-                            int length,
+                            unsigned int length,
                             unsigned int timeout);
 
 /** Reset USB bus for the device */
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index 299fdc4..68aca17 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -600,7 +600,7 @@
 int usb_device_bulk_transfer(struct usb_device *device,
                             int endpoint,
                             void* buffer,
-                            int length,
+                            unsigned int length,
                             unsigned int timeout)
 {
     struct usbdevfs_bulktransfer  ctrl;
diff --git a/libutils/Android.bp b/libutils/Android.bp
new file mode 100644
index 0000000..25c779e
--- /dev/null
+++ b/libutils/Android.bp
@@ -0,0 +1,116 @@
+// Copyright (C) 2008 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library {
+    name: "libutils",
+    host_supported: true,
+
+    srcs: [
+        "CallStack.cpp",
+        "FileMap.cpp",
+        "JenkinsHash.cpp",
+        "LinearTransform.cpp",
+        "Log.cpp",
+        "NativeHandle.cpp",
+        "Printer.cpp",
+        "PropertyMap.cpp",
+        "RefBase.cpp",
+        "SharedBuffer.cpp",
+        "Static.cpp",
+        "StopWatch.cpp",
+        "String8.cpp",
+        "String16.cpp",
+        "SystemClock.cpp",
+        "Threads.cpp",
+        "Timers.cpp",
+        "Tokenizer.cpp",
+        "Unicode.cpp",
+        "VectorImpl.cpp",
+        "misc.cpp",
+    ],
+
+    cflags: ["-Werror"],
+    include_dirs: ["external/safe-iop/include"],
+
+    arch: {
+        mips: {
+            cflags: ["-DALIGN_DOUBLE"],
+        },
+    },
+
+    target: {
+        android: {
+            srcs: [
+                "BlobCache.cpp",
+                "Looper.cpp",
+                "ProcessCallStack.cpp",
+                "Trace.cpp",
+            ],
+
+            cflags: ["-fvisibility=protected"],
+
+            shared_libs: [
+                "libbacktrace",
+                "libcutils",
+                "libdl",
+                "liblog",
+            ],
+
+            sanitize: {
+                misc_undefined: ["integer"],
+            },
+        },
+
+        host: {
+            cflags: ["-DLIBUTILS_NATIVE=1"],
+
+            shared: {
+                enabled: false,
+            },
+        },
+
+        linux: {
+            srcs: [
+                "Looper.cpp",
+                "ProcessCallStack.cpp",
+            ],
+        },
+
+        darwin: {
+            cflags: ["-Wno-unused-parameter"],
+        },
+
+        // Under MinGW, ctype.h doesn't need multi-byte support
+        windows: {
+            cflags: ["-DMB_CUR_MAX=1"],
+
+            enabled: true,
+        },
+    },
+
+    clang: true,
+}
+
+// Include subdirectory makefiles
+// ============================================================
+
+cc_test {
+    name: "SharedBufferTest",
+    host_supported: true,
+    static_libs: ["libutils"],
+    shared_libs: ["liblog"],
+    srcs: ["SharedBufferTest.cpp"],
+}
+
+subdirs = ["tests"]
diff --git a/libutils/Android.mk b/libutils/Android.mk
deleted file mode 100644
index 84bac32..0000000
--- a/libutils/Android.mk
+++ /dev/null
@@ -1,124 +0,0 @@
-# Copyright (C) 2008 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-commonSources:= \
-	CallStack.cpp \
-	FileMap.cpp \
-	JenkinsHash.cpp \
-	LinearTransform.cpp \
-	Log.cpp \
-	NativeHandle.cpp \
-	Printer.cpp \
-	PropertyMap.cpp \
-	RefBase.cpp \
-	SharedBuffer.cpp \
-	Static.cpp \
-	StopWatch.cpp \
-	String8.cpp \
-	String16.cpp \
-	SystemClock.cpp \
-	Threads.cpp \
-	Timers.cpp \
-	Tokenizer.cpp \
-	Unicode.cpp \
-	VectorImpl.cpp \
-	misc.cpp \
-
-host_commonCflags := -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS) -Werror
-
-# For the host
-# =====================================================
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= $(commonSources)
-LOCAL_SRC_FILES_linux := Looper.cpp ProcessCallStack.cpp
-LOCAL_CFLAGS_darwin := -Wno-unused-parameter
-LOCAL_MODULE:= libutils
-LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_CFLAGS += $(host_commonCflags)
-# Under MinGW, ctype.h doesn't need multi-byte support
-LOCAL_CFLAGS_windows := -DMB_CUR_MAX=1
-LOCAL_MULTILIB := both
-LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_C_INCLUDES += external/safe-iop/include
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-
-# For the device, static
-# =====================================================
-include $(CLEAR_VARS)
-
-
-# we have the common sources, plus some device-specific stuff
-LOCAL_SRC_FILES:= \
-	$(commonSources) \
-	BlobCache.cpp \
-	Looper.cpp \
-	ProcessCallStack.cpp \
-	Trace.cpp
-
-ifeq ($(TARGET_ARCH),mips)
-LOCAL_CFLAGS += -DALIGN_DOUBLE
-endif
-LOCAL_CFLAGS += -Werror -fvisibility=protected
-
-LOCAL_STATIC_LIBRARIES := \
-	libcutils \
-	libc
-
-LOCAL_SHARED_LIBRARIES := \
-        libbacktrace \
-        liblog \
-        libdl
-
-LOCAL_MODULE := libutils
-LOCAL_CLANG := true
-LOCAL_SANITIZE := integer
-LOCAL_C_INCLUDES += external/safe-iop/include
-include $(BUILD_STATIC_LIBRARY)
-
-# For the device, shared
-# =====================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE:= libutils
-LOCAL_WHOLE_STATIC_LIBRARIES := libutils
-LOCAL_SHARED_LIBRARIES := \
-        libbacktrace \
-        libcutils \
-        libdl \
-        liblog
-LOCAL_CFLAGS := -Werror
-LOCAL_C_INCLUDES += external/safe-iop/include
-
-LOCAL_CLANG := true
-LOCAL_SANITIZE := integer
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := SharedBufferTest
-LOCAL_STATIC_LIBRARIES := libutils
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_SRC_FILES := SharedBufferTest.cpp
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := SharedBufferTest
-LOCAL_STATIC_LIBRARIES := libutils
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_SRC_FILES := SharedBufferTest.cpp
-include $(BUILD_HOST_NATIVE_TEST)
-
-# Build the tests in the tests/ subdirectory.
-include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp
index 4f4b889..1afa1ec 100644
--- a/libutils/FileMap.cpp
+++ b/libutils/FileMap.cpp
@@ -98,7 +98,7 @@
     }
 #if defined(__MINGW32__)
     if (mBasePtr && UnmapViewOfFile(mBasePtr) == 0) {
-        ALOGD("UnmapViewOfFile(%p) failed, error = %" PRId32 "\n", mBasePtr,
+        ALOGD("UnmapViewOfFile(%p) failed, error = %lu\n", mBasePtr,
               GetLastError() );
     }
     if (mFileMapping != INVALID_HANDLE_VALUE) {
@@ -138,7 +138,7 @@
     mFileHandle  = (HANDLE) _get_osfhandle(fd);
     mFileMapping = CreateFileMapping( mFileHandle, NULL, protect, 0, 0, NULL);
     if (mFileMapping == NULL) {
-        ALOGE("CreateFileMapping(%p, %" PRIx32 ") failed with error %" PRId32 "\n",
+        ALOGE("CreateFileMapping(%p, %lx) failed with error %lu\n",
               mFileHandle, protect, GetLastError() );
         return false;
     }
@@ -153,7 +153,7 @@
                               (DWORD)(adjOffset),
                               adjLength );
     if (mBasePtr == NULL) {
-        ALOGE("MapViewOfFile(%" PRId64 ", %zu) failed with error %" PRId32 "\n",
+        ALOGE("MapViewOfFile(%" PRId64 ", %zu) failed with error %lu\n",
               adjOffset, adjLength, GetLastError() );
         CloseHandle(mFileMapping);
         mFileMapping = INVALID_HANDLE_VALUE;
diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp
index 952c992..26e27cf 100644
--- a/libutils/Looper.cpp
+++ b/libutils/Looper.cpp
@@ -13,18 +13,17 @@
 // Debugs callback registration and invocation.
 #define DEBUG_CALLBACKS 0
 
-#include <cutils/log.h>
-#include <utils/Looper.h>
-#include <utils/Timers.h>
-
 #include <errno.h>
 #include <fcntl.h>
-#include <limits.h>
 #include <inttypes.h>
+#include <limits.h>
 #include <string.h>
 #include <sys/eventfd.h>
 #include <unistd.h>
 
+#include <android/log.h>
+#include <utils/Looper.h>
+#include <utils/Timers.h>
 
 namespace android {
 
@@ -677,4 +676,8 @@
     eventItem->data.fd = fd;
 }
 
+MessageHandler::~MessageHandler() { }
+
+LooperCallback::~LooperCallback() { }
+
 } // namespace android
diff --git a/libutils/Printer.cpp b/libutils/Printer.cpp
index 1dc8632..98cd2c6 100644
--- a/libutils/Printer.cpp
+++ b/libutils/Printer.cpp
@@ -44,7 +44,7 @@
 
     char* formattedString;
 
-#ifndef USE_MINGW
+#ifndef _WIN32
     if (vasprintf(&formattedString, format, arglist) < 0) { // returns -1 on error
         ALOGE("%s: Failed to format string", __FUNCTION__);
         return;
@@ -115,7 +115,7 @@
         return;
     }
 
-#ifndef USE_MINGW
+#ifndef _WIN32
     dprintf(mFd, mFormatString, mPrefix, string);
 #endif
 }
diff --git a/libutils/ProcessCallStack.cpp b/libutils/ProcessCallStack.cpp
index cdb586d..73ed4eb 100644
--- a/libutils/ProcessCallStack.cpp
+++ b/libutils/ProcessCallStack.cpp
@@ -21,6 +21,7 @@
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
+#include <memory>
 
 #include <utils/Log.h>
 #include <utils/Errors.h>
@@ -130,11 +131,7 @@
 }
 
 void ProcessCallStack::update() {
-    DIR *dp;
-    struct dirent *ep;
-    struct dirent entry;
-
-    dp = opendir(PATH_SELF_TASK);
+    std::unique_ptr<DIR, decltype(&closedir)> dp(opendir(PATH_SELF_TASK), closedir);
     if (dp == NULL) {
         ALOGE("%s: Failed to update the process's call stacks: %s",
               __FUNCTION__, strerror(errno));
@@ -158,8 +155,8 @@
      * Each tid is a directory inside of /proc/self/task
      * - Read every file in directory => get every tid
      */
-    int code;
-    while ((code = readdir_r(dp, &entry, &ep)) == 0 && ep != NULL) {
+    dirent* ep;
+    while ((ep = readdir(dp.get())) != NULL) {
         pid_t tid = -1;
         sscanf(ep->d_name, "%d", &tid);
 
@@ -194,12 +191,6 @@
         ALOGV("%s: Got call stack for tid %d (size %zu)",
               __FUNCTION__, tid, threadInfo.callStack.size());
     }
-    if (code != 0) { // returns positive error value on error
-        ALOGE("%s: Failed to readdir from %s: %s",
-              __FUNCTION__, PATH_SELF_TASK, strerror(code));
-    }
-
-    closedir(dp);
 }
 
 void ProcessCallStack::log(const char* logtag, android_LogPriority priority,
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index 4ead19c..1f8395b 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -56,37 +56,44 @@
 
 namespace android {
 
-// Usage, invariants, etc:
+// Observations, invariants, etc:
 
-// It is normally OK just to keep weak pointers to an object.  The object will
-// be deallocated by decWeak when the last weak reference disappears.
-// Once a a strong reference has been created, the object will disappear once
-// the last strong reference does (decStrong).
-// AttemptIncStrong will succeed if the object has a strong reference, or if it
-// has a weak reference and has never had a strong reference.
-// AttemptIncWeak really does succeed only if there is already a WEAK
-// reference, and thus may fail when attemptIncStrong would succeed.
+// By default, obects are destroyed when the last strong reference disappears
+// or, if the object never had a strong reference, when the last weak reference
+// disappears.
+//
 // OBJECT_LIFETIME_WEAK changes this behavior to retain the object
 // unconditionally until the last reference of either kind disappears.  The
 // client ensures that the extendObjectLifetime call happens before the dec
 // call that would otherwise have deallocated the object, or before an
 // attemptIncStrong call that might rely on it.  We do not worry about
 // concurrent changes to the object lifetime.
+//
+// AttemptIncStrong will succeed if the object has a strong reference, or if it
+// has a weak reference and has never had a strong reference.
+// AttemptIncWeak really does succeed only if there is already a WEAK
+// reference, and thus may fail when attemptIncStrong would succeed.
+//
 // mStrong is the strong reference count.  mWeak is the weak reference count.
 // Between calls, and ignoring memory ordering effects, mWeak includes strong
 // references, and is thus >= mStrong.
 //
+// A weakref_impl holds all the information, including both reference counts,
+// required to perform wp<> operations.  Thus these can continue to be performed
+// after the RefBase object has been destroyed.
+//
 // A weakref_impl is allocated as the value of mRefs in a RefBase object on
 // construction.
-// In the OBJECT_LIFETIME_STRONG case, it is deallocated in the RefBase
-// destructor iff the strong reference count was never incremented. The
-// destructor can be invoked either from decStrong, or from decWeak if there
-// was never a strong reference. If the reference count had been incremented,
-// it is deallocated directly in decWeak, and hence still lives as long as
-// the last weak reference.
-// In the OBJECT_LIFETIME_WEAK case, it is always deallocated from the RefBase
-// destructor, which is always invoked by decWeak. DecStrong explicitly avoids
-// the deletion in this case.
+// In the OBJECT_LIFETIME_STRONG case, it is normally deallocated in decWeak,
+// and hence lives as long as the last weak reference. (It can also be
+// deallocated in the RefBase destructor iff the strong reference count was
+// never incremented and the weak count is zero, e.g.  if the RefBase object is
+// explicitly destroyed without decrementing the strong count.  This should be
+// avoided.) In this case, the RefBase destructor should be invoked from
+// decStrong.
+// In the OBJECT_LIFETIME_WEAK case, the weakref_impl is always deallocated in
+// the RefBase destructor, which is always invoked by decWeak. DecStrong
+// explicitly avoids the deletion in this case.
 //
 // Memory ordering:
 // The client must ensure that every inc() call, together with all other
@@ -120,6 +127,19 @@
 
 #define INITIAL_STRONG_VALUE (1<<28)
 
+#define MAX_COUNT 0xfffff
+
+// Test whether the argument is a clearly invalid strong reference count.
+// Used only for error checking on the value before an atomic decrement.
+// Intended to be very cheap.
+// Note that we cannot just check for excess decrements by comparing to zero
+// since the object would be deallocated before that.
+#define BAD_STRONG(c) \
+        ((c) == 0 || ((c) & (~(MAX_COUNT | INITIAL_STRONG_VALUE))) != 0)
+
+// Same for weak counts.
+#define BAD_WEAK(c) ((c) == 0 || ((c) & (~MAX_COUNT)) != 0)
+
 // ---------------------------------------------------------------------------
 
 class RefBase::weakref_impl : public RefBase::weakref_type
@@ -132,7 +152,7 @@
 
 #if !DEBUG_REFS
 
-    weakref_impl(RefBase* base)
+    explicit weakref_impl(RefBase* base)
         : mStrong(INITIAL_STRONG_VALUE)
         , mWeak(0)
         , mBase(base)
@@ -251,17 +271,22 @@
         {
             Mutex::Autolock _l(mMutex);
             char buf[128];
-            sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
+            snprintf(buf, sizeof(buf),
+                     "Strong references on RefBase %p (weakref_type %p):\n",
+                     mBase, this);
             text.append(buf);
             printRefsLocked(&text, mStrongRefs);
-            sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this);
+            snprintf(buf, sizeof(buf),
+                     "Weak references on RefBase %p (weakref_type %p):\n",
+                     mBase, this);
             text.append(buf);
             printRefsLocked(&text, mWeakRefs);
         }
 
         {
             char name[100];
-            snprintf(name, 100, DEBUG_REFS_CALLSTACK_PATH "/%p.stack", this);
+            snprintf(name, sizeof(name), DEBUG_REFS_CALLSTACK_PATH "/%p.stack",
+                     this);
             int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 644);
             if (rc >= 0) {
                 write(rc, text.string(), text.length());
@@ -354,8 +379,8 @@
         char buf[128];
         while (refs) {
             char inc = refs->ref >= 0 ? '+' : '-';
-            sprintf(buf, "\t%c ID %p (ref %d):\n", 
-                    inc, refs->id, refs->ref);
+            snprintf(buf, sizeof(buf), "\t%c ID %p (ref %d):\n",
+                     inc, refs->id, refs->ref);
             out->append(buf);
 #if DEBUG_REFS_CALLSTACK_ENABLED
             out->append(refs->stack.toString("\t\t"));
@@ -410,15 +435,15 @@
 #if PRINT_REFS
     ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
 #endif
-    ALOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
+    LOG_ALWAYS_FATAL_IF(BAD_STRONG(c), "decStrong() called on %p too many times",
+            refs);
     if (c == 1) {
         std::atomic_thread_fence(std::memory_order_acquire);
         refs->mBase->onLastStrongRef(id);
         int32_t flags = refs->mFlags.load(std::memory_order_relaxed);
         if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
             delete this;
-            // Since mStrong had been incremented, the destructor did not
-            // delete refs.
+            // The destructor does not delete refs in this case.
         }
     }
     // Note that even with only strong reference operations, the thread
@@ -481,7 +506,8 @@
     weakref_impl* const impl = static_cast<weakref_impl*>(this);
     impl->removeWeakRef(id);
     const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release);
-    ALOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
+    LOG_ALWAYS_FATAL_IF(BAD_WEAK(c), "decWeak called on %p too many times",
+            this);
     if (c != 1) return;
     atomic_thread_fence(std::memory_order_acquire);
 
@@ -489,13 +515,19 @@
     if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
         // This is the regular lifetime case. The object is destroyed
         // when the last strong reference goes away. Since weakref_impl
-        // outlive the object, it is not destroyed in the dtor, and
+        // outlives the object, it is not destroyed in the dtor, and
         // we'll have to do it here.
         if (impl->mStrong.load(std::memory_order_relaxed)
                 == INITIAL_STRONG_VALUE) {
-            // Special case: we never had a strong reference, so we need to
-            // destroy the object now.
-            delete impl->mBase;
+            // Decrementing a weak count to zero when object never had a strong
+            // reference.  We assume it acquired a weak reference early, e.g.
+            // in the constructor, and will eventually be properly destroyed,
+            // usually via incrementing and decrementing the strong count.
+            // Thus we no longer do anything here.  We log this case, since it
+            // seems to be extremely rare, and should not normally occur. We
+            // used to deallocate mBase here, so this may now indicate a leak.
+            ALOGW("RefBase: Object at %p lost last weak reference "
+                    "before it had a strong reference", impl->mBase);
         } else {
             // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
             delete impl;
@@ -664,24 +696,28 @@
 
 RefBase::~RefBase()
 {
-    if (mRefs->mStrong.load(std::memory_order_relaxed)
-            == INITIAL_STRONG_VALUE) {
-        // we never acquired a strong (and/or weak) reference on this object.
-        delete mRefs;
-    } else {
-        // life-time of this object is extended to WEAK, in
-        // which case weakref_impl doesn't out-live the object and we
-        // can free it now.
-        int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed);
-        if ((flags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
-            // It's possible that the weak count is not 0 if the object
-            // re-acquired a weak reference in its destructor
-            if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
-                delete mRefs;
-            }
+    int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed);
+    // Life-time of this object is extended to WEAK, in
+    // which case weakref_impl doesn't out-live the object and we
+    // can free it now.
+    if ((flags & OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
+        // It's possible that the weak count is not 0 if the object
+        // re-acquired a weak reference in its destructor
+        if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
+            delete mRefs;
         }
+    } else if (mRefs->mStrong.load(std::memory_order_relaxed)
+            == INITIAL_STRONG_VALUE) {
+        // We never acquired a strong reference on this object.
+        LOG_ALWAYS_FATAL_IF(mRefs->mWeak.load() != 0,
+                "RefBase: Explicit destruction with non-zero weak "
+                "reference count");
+        // TODO: Always report if we get here. Currently MediaMetadataRetriever
+        // C++ objects are inconsistently managed and sometimes get here.
+        // There may be other cases, but we believe they should all be fixed.
+        delete mRefs;
     }
-    // for debugging purposes, clear this.
+    // For debugging purposes, clear mRefs.  Ineffective against outstanding wp's.
     const_cast<weakref_impl*&>(mRefs) = NULL;
 }
 
@@ -734,4 +770,6 @@
     ref->mRefs->renameWeakRefId(old_id, new_id);
 }
 
+VirtualLightRefBase::~VirtualLightRefBase() {}
+
 }; // namespace android
diff --git a/libutils/SharedBuffer.cpp b/libutils/SharedBuffer.cpp
index a8a9fb4..269326a 100644
--- a/libutils/SharedBuffer.cpp
+++ b/libutils/SharedBuffer.cpp
@@ -14,10 +14,12 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "sharedbuffer"
+
 #include <stdlib.h>
 #include <string.h>
 
-#include <log/log.h>
+#include <android/log.h>
 
 #include "SharedBuffer.h"
 
@@ -112,8 +114,9 @@
 int32_t SharedBuffer::release(uint32_t flags) const
 {
     int32_t prev = 1;
-    if (onlyOwner() || ((prev = mRefs.fetch_sub(1, std::memory_order_release) == 1)
-            && (atomic_thread_fence(std::memory_order_acquire), true))) {
+    if (onlyOwner()
+            || (((prev = mRefs.fetch_sub(1, std::memory_order_release)) == 1)
+                && (atomic_thread_fence(std::memory_order_acquire), true))) {
         mRefs.store(0, std::memory_order_relaxed);
         if ((flags & eKeepStorage) == 0) {
             free(const_cast<SharedBuffer*>(this));
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index 65396ca..9f5cfea 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -18,7 +18,6 @@
 
 #include <utils/Log.h>
 #include <utils/Unicode.h>
-#include <utils/String8.h>
 #include <utils/threads.h>
 
 #include <memory.h>
@@ -72,12 +71,12 @@
         u8cur = (const uint8_t*) u8str;
         char16_t* u16str = (char16_t*)buf->data();
 
-        utf8_to_utf16(u8cur, u8len, u16str);
+        utf8_to_utf16(u8cur, u8len, u16str, ((size_t) u16len) + 1);
 
         //printf("Created UTF-16 string from UTF-8 \"%s\":", in);
         //printHexData(1, str, buf->size(), 16, 1);
         //printf("\n");
-        
+
         return u16str;
     }
 
@@ -127,7 +126,7 @@
         mString = str;
         return;
     }
-    
+
     mString = getEmptyString();
 }
 
@@ -142,7 +141,7 @@
         mString = str;
         return;
     }
-    
+
     mString = getEmptyString();
 }
 
@@ -228,7 +227,7 @@
     } else if (otherLen == 0) {
         return NO_ERROR;
     }
-    
+
     SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
         ->editResize((myLen+otherLen+1)*sizeof(char16_t));
     if (buf) {
@@ -249,7 +248,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/libutils/String8.cpp b/libutils/String8.cpp
index 755e0d1..cacaf91 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -363,7 +363,7 @@
 status_t String8::real_append(const char* other, size_t otherLen)
 {
     const size_t myLen = bytes();
-    
+
     SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
         ->editResize(myLen+otherLen+1);
     if (buf) {
diff --git a/libutils/SystemClock.cpp b/libutils/SystemClock.cpp
index 1fca2b2..965e32c 100644
--- a/libutils/SystemClock.cpp
+++ b/libutils/SystemClock.cpp
@@ -19,18 +19,13 @@
  * System clock functions.
  */
 
-#if defined(__ANDROID__)
-#include <linux/ioctl.h>
-#include <linux/rtc.h>
-#include <utils/Atomic.h>
-#include <linux/android_alarm.h>
-#endif
-
 #include <sys/time.h>
 #include <limits.h>
 #include <fcntl.h>
 #include <string.h>
+#include <errno.h>
 
+#include <cutils/compiler.h>
 #include <utils/SystemClock.h>
 #include <utils/Timers.h>
 
@@ -56,100 +51,21 @@
 	return nanoseconds_to_milliseconds(elapsedRealtimeNano());
 }
 
-#define METHOD_CLOCK_GETTIME    0
-#define METHOD_IOCTL            1
-#define METHOD_SYSTEMTIME       2
-
-/*
- * To debug/verify the timestamps returned by the kernel, change
- * DEBUG_TIMESTAMP to 1 and call the timestamp routine from a single thread
- * in the test program. b/10899829
- */
-#define DEBUG_TIMESTAMP         0
-
-#if DEBUG_TIMESTAMP && defined(__arm__)
-static inline void checkTimeStamps(int64_t timestamp,
-                                   int64_t volatile *prevTimestampPtr,
-                                   int volatile *prevMethodPtr,
-                                   int curMethod)
-{
-    /*
-     * Disable the check for SDK since the prebuilt toolchain doesn't contain
-     * gettid, and int64_t is different on the ARM platform
-     * (ie long vs long long).
-     */
-    int64_t prevTimestamp = *prevTimestampPtr;
-    int prevMethod = *prevMethodPtr;
-
-    if (timestamp < prevTimestamp) {
-        static const char *gettime_method_names[] = {
-            "clock_gettime",
-            "ioctl",
-            "systemTime",
-        };
-
-        ALOGW("time going backwards: prev %lld(%s) vs now %lld(%s), tid=%d",
-              prevTimestamp, gettime_method_names[prevMethod],
-              timestamp, gettime_method_names[curMethod],
-              gettid());
-    }
-    // NOTE - not atomic and may generate spurious warnings if the 64-bit
-    // write is interrupted or not observed as a whole.
-    *prevTimestampPtr = timestamp;
-    *prevMethodPtr = curMethod;
-}
-#else
-#define checkTimeStamps(timestamp, prevTimestampPtr, prevMethodPtr, curMethod)
-#endif
-
 /*
  * native public static long elapsedRealtimeNano();
  */
 int64_t elapsedRealtimeNano()
 {
-#if defined(__ANDROID__)
+#if defined(__linux__)
     struct timespec ts;
-    int result;
-    int64_t timestamp;
-#if DEBUG_TIMESTAMP
-    static volatile int64_t prevTimestamp;
-    static volatile int prevMethod;
-#endif
-
-    static int s_fd = -1;
-
-    if (s_fd == -1) {
-        int fd = open("/dev/alarm", O_RDONLY);
-        if (android_atomic_cmpxchg(-1, fd, &s_fd)) {
-            close(fd);
-        }
+    int err = clock_gettime(CLOCK_BOOTTIME, &ts);
+    if (CC_UNLIKELY(err)) {
+        // This should never happen, but just in case ...
+        ALOGE("clock_gettime(CLOCK_BOOTTIME) failed: %s", strerror(errno));
+        return 0;
     }
 
-    result = ioctl(s_fd,
-            ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), &ts);
-
-    if (result == 0) {
-        timestamp = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
-        checkTimeStamps(timestamp, &prevTimestamp, &prevMethod, METHOD_IOCTL);
-        return timestamp;
-    }
-
-    // /dev/alarm doesn't exist, fallback to CLOCK_BOOTTIME
-    result = clock_gettime(CLOCK_BOOTTIME, &ts);
-    if (result == 0) {
-        timestamp = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
-        checkTimeStamps(timestamp, &prevTimestamp, &prevMethod,
-                        METHOD_CLOCK_GETTIME);
-        return timestamp;
-    }
-
-    // XXX: there was an error, probably because the driver didn't
-    // exist ... this should return
-    // a real error, like an exception!
-    timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
-    checkTimeStamps(timestamp, &prevTimestamp, &prevMethod,
-                    METHOD_SYSTEMTIME);
-    return timestamp;
+    return seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
 #else
     return systemTime(SYSTEM_TIME_MONOTONIC);
 #endif
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index ba084f6..c32f462 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -14,11 +14,14 @@
  * limitations under the License.
  */
 
-#include <log/log.h>
-#include <utils/Unicode.h>
+#define LOG_TAG "unicode"
 
+#include <limits.h>
 #include <stddef.h>
 
+#include <android/log.h>
+#include <utils/Unicode.h>
+
 #if defined(_WIN32)
 # undef  nhtol
 # undef  htonl
@@ -542,7 +545,7 @@
     //printf("Char at %p: len=%d, utf-16=%p\n", src, length, (void*)result);
 }
 
-ssize_t utf8_to_utf16_length(const uint8_t* u8str, size_t u8len)
+ssize_t utf8_to_utf16_length(const uint8_t* u8str, size_t u8len, bool overreadIsFatal)
 {
     const uint8_t* const u8end = u8str + u8len;
     const uint8_t* u8cur = u8str;
@@ -552,6 +555,20 @@
     while (u8cur < u8end) {
         u16measuredLen++;
         int u8charLen = utf8_codepoint_len(*u8cur);
+        // Malformed utf8, some characters are beyond the end.
+        // Cases:
+        // If u8charLen == 1, this becomes u8cur >= u8end, which cannot happen as u8cur < u8end,
+        // then this condition fail and we continue, as expected.
+        // If u8charLen == 2, this becomes u8cur + 1 >= u8end, which fails only if
+        // u8cur == u8end - 1, that is, there was only one remaining character to read but we need
+        // 2 of them. This condition holds and we return -1, as expected.
+        if (u8cur + u8charLen - 1 >= u8end) {
+            if (overreadIsFatal) {
+                LOG_ALWAYS_FATAL("Attempt to overread computing length of utf8 string");
+            } else {
+                return -1;
+            }
+        }
         uint32_t codepoint = utf8_to_utf32_codepoint(u8cur, u8charLen);
         if (codepoint > 0xFFFF) u16measuredLen++; // this will be a surrogate pair in utf16
         u8cur += u8charLen;
@@ -568,38 +585,21 @@
     return u16measuredLen;
 }
 
-char16_t* utf8_to_utf16_no_null_terminator(const uint8_t* u8str, size_t u8len, char16_t* u16str)
-{
-    const uint8_t* const u8end = u8str + u8len;
-    const uint8_t* u8cur = u8str;
-    char16_t* u16cur = u16str;
-
-    while (u8cur < u8end) {
-        size_t u8len = utf8_codepoint_len(*u8cur);
-        uint32_t codepoint = utf8_to_utf32_codepoint(u8cur, u8len);
-
-        // Convert the UTF32 codepoint to one or more UTF16 codepoints
-        if (codepoint <= 0xFFFF) {
-            // Single UTF16 character
-            *u16cur++ = (char16_t) codepoint;
-        } else {
-            // Multiple UTF16 characters with surrogates
-            codepoint = codepoint - 0x10000;
-            *u16cur++ = (char16_t) ((codepoint >> 10) + 0xD800);
-            *u16cur++ = (char16_t) ((codepoint & 0x3FF) + 0xDC00);
-        }
-
-        u8cur += u8len;
-    }
-    return u16cur;
-}
-
-void utf8_to_utf16(const uint8_t* u8str, size_t u8len, char16_t* u16str) {
-    char16_t* end = utf8_to_utf16_no_null_terminator(u8str, u8len, u16str);
+char16_t* utf8_to_utf16(const uint8_t* u8str, size_t u8len, char16_t* u16str, size_t u16len) {
+    // A value > SSIZE_MAX is probably a negative value returned as an error and casted.
+    LOG_ALWAYS_FATAL_IF(u16len == 0 || u16len > SSIZE_MAX, "u16len is %zu", u16len);
+    char16_t* end = utf8_to_utf16_no_null_terminator(u8str, u8len, u16str, u16len - 1);
     *end = 0;
+    return end;
 }
 
-char16_t* utf8_to_utf16_n(const uint8_t* src, size_t srcLen, char16_t* dst, size_t dstLen) {
+char16_t* utf8_to_utf16_no_null_terminator(
+        const uint8_t* src, size_t srcLen, char16_t* dst, size_t dstLen) {
+    if (dstLen == 0) {
+        return dst;
+    }
+    // A value > SSIZE_MAX is probably a negative value returned as an error and casted.
+    LOG_ALWAYS_FATAL_IF(dstLen > SSIZE_MAX, "dstLen is %zu", dstLen);
     const uint8_t* const u8end = src + srcLen;
     const uint8_t* u8cur = src;
     const char16_t* const u16end = dst + dstLen;
diff --git a/libutils/VectorImpl.cpp b/libutils/VectorImpl.cpp
index e8d40ed..893e4f2 100644
--- a/libutils/VectorImpl.cpp
+++ b/libutils/VectorImpl.cpp
@@ -16,16 +16,16 @@
 
 #define LOG_TAG "Vector"
 
-#include <string.h>
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
-#include <cutils/log.h>
-#include <safe_iop.h>
-
+#include <android/log.h>
 #include <utils/Errors.h>
 #include <utils/VectorImpl.h>
 
+#include <safe_iop.h>
+
 #include "SharedBuffer.h"
 
 /*****************************************************************************/
diff --git a/libutils/tests/Android.bp b/libutils/tests/Android.bp
new file mode 100644
index 0000000..ec6b67f
--- /dev/null
+++ b/libutils/tests/Android.bp
@@ -0,0 +1,50 @@
+//
+// Copyright (C) 2014 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.
+//
+
+// Build the unit tests.
+
+cc_test {
+    name: "libutils_tests",
+
+    srcs: [
+        "BlobCache_test.cpp",
+        "BitSet_test.cpp",
+        "Looper_test.cpp",
+        "LruCache_test.cpp",
+        "RefBase_test.cpp",
+        "String8_test.cpp",
+        "StrongPointer_test.cpp",
+        "SystemClock_test.cpp",
+        "Unicode_test.cpp",
+        "Vector_test.cpp",
+    ],
+
+    shared_libs: [
+        "libz",
+        "liblog",
+        "libcutils",
+        "libutils",
+    ],
+}
+
+cc_test_host {
+    name: "libutils_tests_host",
+    srcs: ["Vector_test.cpp"],
+    static_libs: [
+        "libutils",
+        "liblog",
+    ],
+}
diff --git a/libutils/tests/Android.mk b/libutils/tests/Android.mk
deleted file mode 100644
index 8f07f1a..0000000
--- a/libutils/tests/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-#
-# Copyright (C) 2014 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.
-#
-
-# Build the unit tests.
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libutils_tests
-
-LOCAL_SRC_FILES := \
-    BlobCache_test.cpp \
-    BitSet_test.cpp \
-    Looper_test.cpp \
-    LruCache_test.cpp \
-    String8_test.cpp \
-    StrongPointer_test.cpp \
-    Unicode_test.cpp \
-    Vector_test.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-    libz \
-    liblog \
-    libcutils \
-    libutils \
-
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libutils_tests_host
-LOCAL_SRC_FILES := Vector_test.cpp
-LOCAL_STATIC_LIBRARIES := libutils liblog
-
-include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libutils/tests/BitSet_test.cpp b/libutils/tests/BitSet_test.cpp
index 59d913e..fbcf025 100644
--- a/libutils/tests/BitSet_test.cpp
+++ b/libutils/tests/BitSet_test.cpp
@@ -16,11 +16,12 @@
 
 #define LOG_TAG "BitSet_test"
 
-#include <utils/BitSet.h>
-#include <cutils/log.h>
-#include <gtest/gtest.h>
 #include <unistd.h>
 
+#include <android/log.h>
+#include <gtest/gtest.h>
+#include <utils/BitSet.h>
+
 namespace android {
 
 class BitSet32Test : public testing::Test {
diff --git a/libutils/tests/BlobCache_test.cpp b/libutils/tests/BlobCache_test.cpp
index dac4e2c..1e2ff98 100644
--- a/libutils/tests/BlobCache_test.cpp
+++ b/libutils/tests/BlobCache_test.cpp
@@ -343,7 +343,9 @@
 
     size_t size = mBC->getFlattenedSize() - 1;
     uint8_t* flat = new uint8_t[size];
-    ASSERT_EQ(BAD_VALUE, mBC->flatten(flat, size));
+    // ASSERT_EQ(BAD_VALUE, mBC->flatten(flat, size));
+    // TODO: The above fails. I expect this is so because getFlattenedSize()
+    // overstimates the size by using PROPERTY_VALUE_MAX.
     delete[] flat;
 }
 
@@ -411,7 +413,9 @@
     ASSERT_EQ(OK, mBC->flatten(flat, size));
 
     // A buffer truncation shouldt cause an error
-    ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size-1));
+    // ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size-1));
+    // TODO: The above appears to fail because getFlattenedSize() is
+    // conservative.
     delete[] flat;
 
     // The error should cause the unflatten to result in an empty cache
diff --git a/libutils/tests/Looper_test.cpp b/libutils/tests/Looper_test.cpp
index 17319e0..8ebcfaf 100644
--- a/libutils/tests/Looper_test.cpp
+++ b/libutils/tests/Looper_test.cpp
@@ -76,7 +76,7 @@
     int fd;
     int events;
 
-    StubCallbackHandler(int nextResult) : nextResult(nextResult),
+    explicit StubCallbackHandler(int nextResult) : nextResult(nextResult),
             callbackCount(0), fd(-1), events(-1) {
     }
 
diff --git a/libutils/tests/LruCache_test.cpp b/libutils/tests/LruCache_test.cpp
index dd95c57..4e885bb 100644
--- a/libutils/tests/LruCache_test.cpp
+++ b/libutils/tests/LruCache_test.cpp
@@ -15,10 +15,11 @@
  */
 
 #include <stdlib.h>
+
+#include <android/log.h>
+#include <gtest/gtest.h>
 #include <utils/JenkinsHash.h>
 #include <utils/LruCache.h>
-#include <cutils/log.h>
-#include <gtest/gtest.h>
 
 namespace {
 
@@ -80,6 +81,14 @@
     }
 };
 
+struct KeyFailsOnCopy : public ComplexKey {
+    public:
+    KeyFailsOnCopy(const KeyFailsOnCopy& key) : ComplexKey(key) {
+        ADD_FAILURE();
+    }
+    KeyFailsOnCopy(int key) : ComplexKey(key) { }
+};
+
 } // namespace
 
 
@@ -95,6 +104,10 @@
     return hash_type(*value.ptr);
 }
 
+template<> inline android::hash_t hash_type(const KeyFailsOnCopy& value) {
+    return hash_type<ComplexKey>(value);
+}
+
 class EntryRemovedCallback : public OnEntryRemoved<SimpleKey, StringValue> {
 public:
     EntryRemovedCallback() : callbackCount(0), lastKey(-1), lastValue(NULL) { }
@@ -437,4 +450,10 @@
     EXPECT_EQ(std::unordered_set<int>({ 4, 5, 6 }), returnedValues);
 }
 
+TEST_F(LruCacheTest, DontCopyKeyInGet) {
+    LruCache<KeyFailsOnCopy, KeyFailsOnCopy> cache(1);
+    // Check that get doesn't copy the key
+    cache.get(KeyFailsOnCopy(0));
+}
+
 }
diff --git a/libutils/tests/README.txt b/libutils/tests/README.txt
new file mode 100644
index 0000000..ad54e57
--- /dev/null
+++ b/libutils/tests/README.txt
@@ -0,0 +1,8 @@
+Run device tests:
+
+mma -j<whatever>
+(after adb root; adb disable-verity; adb reboot)
+adb root
+adb remount
+adb sync
+adb shell /data/nativetest/libutils_tests/libutils_tests
diff --git a/libutils/tests/RefBase_test.cpp b/libutils/tests/RefBase_test.cpp
new file mode 100644
index 0000000..2e0cf6e
--- /dev/null
+++ b/libutils/tests/RefBase_test.cpp
@@ -0,0 +1,258 @@
+/*
+ * 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 <utils/StrongPointer.h>
+#include <utils/RefBase.h>
+
+#include <thread>
+#include <atomic>
+#include <sched.h>
+#include <errno.h>
+
+// Enhanced version of StrongPointer_test, but using RefBase underneath.
+
+using namespace android;
+
+static constexpr int NITERS = 1000000;
+
+static constexpr int INITIAL_STRONG_VALUE = 1 << 28;  // Mirroring RefBase definition.
+
+class Foo : public RefBase {
+public:
+    Foo(bool* deleted_check) : mDeleted(deleted_check) {
+        *mDeleted = false;
+    }
+
+    ~Foo() {
+        *mDeleted = true;
+    }
+private:
+    bool* mDeleted;
+};
+
+TEST(RefBase, StrongMoves) {
+    bool isDeleted;
+    Foo* foo = new Foo(&isDeleted);
+    ASSERT_EQ(INITIAL_STRONG_VALUE, foo->getStrongCount());
+    ASSERT_FALSE(isDeleted) << "Already deleted...?";
+    sp<Foo> sp1(foo);
+    wp<Foo> wp1(sp1);
+    ASSERT_EQ(1, foo->getStrongCount());
+    // Weak count includes both strong and weak references.
+    ASSERT_EQ(2, foo->getWeakRefs()->getWeakCount());
+    {
+        sp<Foo> sp2 = std::move(sp1);
+        ASSERT_EQ(1, foo->getStrongCount())
+                << "std::move failed, incremented refcnt";
+        ASSERT_EQ(nullptr, sp1.get()) << "std::move failed, sp1 is still valid";
+        // The strong count isn't increasing, let's double check the old object
+        // is properly reset and doesn't early delete
+        sp1 = std::move(sp2);
+    }
+    ASSERT_FALSE(isDeleted) << "deleted too early! still has a reference!";
+    {
+        // Now let's double check it deletes on time
+        sp<Foo> sp2 = std::move(sp1);
+    }
+    ASSERT_TRUE(isDeleted) << "foo was leaked!";
+    ASSERT_TRUE(wp1.promote().get() == nullptr);
+}
+
+TEST(RefBase, WeakCopies) {
+    bool isDeleted;
+    Foo* foo = new Foo(&isDeleted);
+    EXPECT_EQ(0, foo->getWeakRefs()->getWeakCount());
+    ASSERT_FALSE(isDeleted) << "Foo (weak) already deleted...?";
+    wp<Foo> wp1(foo);
+    EXPECT_EQ(1, foo->getWeakRefs()->getWeakCount());
+    {
+        wp<Foo> wp2 = wp1;
+        ASSERT_EQ(2, foo->getWeakRefs()->getWeakCount());
+    }
+    EXPECT_EQ(1, foo->getWeakRefs()->getWeakCount());
+    ASSERT_FALSE(isDeleted) << "deleted too early! still has a reference!";
+    wp1 = nullptr;
+    ASSERT_FALSE(isDeleted) << "Deletion on wp destruction should no longer occur";
+}
+
+
+// Set up a situation in which we race with visit2AndRremove() to delete
+// 2 strong references.  Bar destructor checks that there are no early
+// deletions and prior updates are visible to destructor.
+class Bar : public RefBase {
+public:
+    Bar(std::atomic<int>* delete_count) : mVisited1(false), mVisited2(false),
+            mDeleteCount(delete_count) {
+    }
+
+    ~Bar() {
+        EXPECT_TRUE(mVisited1);
+        EXPECT_TRUE(mVisited2);
+        (*mDeleteCount)++;
+    }
+    bool mVisited1;
+    bool mVisited2;
+private:
+    std::atomic<int>* mDeleteCount;
+};
+
+static sp<Bar> buffer;
+static std::atomic<bool> bufferFull(false);
+
+// Wait until bufferFull has value val.
+static inline void waitFor(bool val) {
+    while (bufferFull != val) {}
+}
+
+cpu_set_t otherCpus;
+
+// Divide the cpus we're allowed to run on into myCpus and otherCpus.
+// Set origCpus to the processors we were originally allowed to run on.
+// Return false if origCpus doesn't include at least processors 0 and 1.
+static bool setExclusiveCpus(cpu_set_t* origCpus /* out */,
+        cpu_set_t* myCpus /* out */, cpu_set_t* otherCpus) {
+    if (sched_getaffinity(0, sizeof(cpu_set_t), origCpus) != 0) {
+        return false;
+    }
+    if (!CPU_ISSET(0,  origCpus) || !CPU_ISSET(1, origCpus)) {
+        return false;
+    }
+    CPU_ZERO(myCpus);
+    CPU_ZERO(otherCpus);
+    CPU_OR(myCpus, myCpus, origCpus);
+    CPU_OR(otherCpus, otherCpus, origCpus);
+    for (unsigned i = 0; i < CPU_SETSIZE; ++i) {
+        // I get the even cores, the other thread gets the odd ones.
+        if (i & 1) {
+            CPU_CLR(i, myCpus);
+        } else {
+            CPU_CLR(i, otherCpus);
+        }
+    }
+    return true;
+}
+
+static void visit2AndRemove() {
+    if (sched_setaffinity(0, sizeof(cpu_set_t), &otherCpus) != 0) {
+        FAIL() << "setaffinity returned:" << errno;
+    }
+    for (int i = 0; i < NITERS; ++i) {
+        waitFor(true);
+        buffer->mVisited2 = true;
+        buffer = nullptr;
+        bufferFull = false;
+    }
+}
+
+TEST(RefBase, RacingDestructors) {
+    cpu_set_t origCpus;
+    cpu_set_t myCpus;
+    // Restrict us and the helper thread to disjoint cpu sets.
+    // This prevents us from getting scheduled against each other,
+    // which would be atrociously slow.
+    if (setExclusiveCpus(&origCpus, &myCpus, &otherCpus)) {
+        std::thread t(visit2AndRemove);
+        std::atomic<int> deleteCount(0);
+        if (sched_setaffinity(0, sizeof(cpu_set_t), &myCpus) != 0) {
+            FAIL() << "setaffinity returned:" << errno;
+        }
+        for (int i = 0; i < NITERS; ++i) {
+            waitFor(false);
+            Bar* bar = new Bar(&deleteCount);
+            sp<Bar> sp3(bar);
+            buffer = sp3;
+            bufferFull = true;
+            ASSERT_TRUE(bar->getStrongCount() >= 1);
+            // Weak count includes strong count.
+            ASSERT_TRUE(bar->getWeakRefs()->getWeakCount() >= 1);
+            sp3->mVisited1 = true;
+            sp3 = nullptr;
+        }
+        t.join();
+        if (sched_setaffinity(0, sizeof(cpu_set_t), &origCpus) != 0) {
+            FAIL();
+        }
+        ASSERT_EQ(NITERS, deleteCount) << "Deletions missed!";
+    }  // Otherwise this is slow and probably pointless on a uniprocessor.
+}
+
+static wp<Bar> wpBuffer;
+static std::atomic<bool> wpBufferFull(false);
+
+// Wait until wpBufferFull has value val.
+static inline void wpWaitFor(bool val) {
+    while (wpBufferFull != val) {}
+}
+
+static void visit3AndRemove() {
+    if (sched_setaffinity(0, sizeof(cpu_set_t), &otherCpus) != 0) {
+        FAIL() << "setaffinity returned:" << errno;
+    }
+    for (int i = 0; i < NITERS; ++i) {
+        wpWaitFor(true);
+        {
+            sp<Bar> sp1 = wpBuffer.promote();
+            // We implicitly check that sp1 != NULL
+            sp1->mVisited2 = true;
+        }
+        wpBuffer = nullptr;
+        wpBufferFull = false;
+    }
+}
+
+TEST(RefBase, RacingPromotions) {
+    cpu_set_t origCpus;
+    cpu_set_t myCpus;
+    // Restrict us and the helper thread to disjoint cpu sets.
+    // This prevents us from getting scheduled against each other,
+    // which would be atrociously slow.
+    if (setExclusiveCpus(&origCpus, &myCpus, &otherCpus)) {
+        std::thread t(visit3AndRemove);
+        std::atomic<int> deleteCount(0);
+        if (sched_setaffinity(0, sizeof(cpu_set_t), &myCpus) != 0) {
+            FAIL() << "setaffinity returned:" << errno;
+        }
+        for (int i = 0; i < NITERS; ++i) {
+            Bar* bar = new Bar(&deleteCount);
+            wp<Bar> wp1(bar);
+            bar->mVisited1 = true;
+            if (i % (NITERS / 10) == 0) {
+                // Do this rarely, since it generates a log message.
+                wp1 = nullptr;  // No longer destroys the object.
+                wp1 = bar;
+            }
+            wpBuffer = wp1;
+            ASSERT_EQ(bar->getWeakRefs()->getWeakCount(), 2);
+            wpBufferFull = true;
+            // Promotion races with that in visit3AndRemove.
+            // This may or may not succeed, but it shouldn't interfere with
+            // the concurrent one.
+            sp<Bar> sp1 = wp1.promote();
+            wpWaitFor(false);  // Waits for other thread to drop strong pointer.
+            sp1 = nullptr;
+            // No strong pointers here.
+            sp1 = wp1.promote();
+            ASSERT_EQ(sp1.get(), nullptr) << "Dead wp promotion succeeded!";
+        }
+        t.join();
+        if (sched_setaffinity(0, sizeof(cpu_set_t), &origCpus) != 0) {
+            FAIL();
+        }
+        ASSERT_EQ(NITERS, deleteCount) << "Deletions missed!";
+    }  // Otherwise this is slow and probably pointless on a uniprocessor.
+}
diff --git a/libutils/tests/StrongPointer_test.cpp b/libutils/tests/StrongPointer_test.cpp
index f46d6d1..323a6f2 100644
--- a/libutils/tests/StrongPointer_test.cpp
+++ b/libutils/tests/StrongPointer_test.cpp
@@ -23,7 +23,7 @@
 
 class Foo : public LightRefBase<Foo> {
 public:
-    Foo(bool* deleted_check) : mDeleted(deleted_check) {
+    explicit Foo(bool* deleted_check) : mDeleted(deleted_check) {
         *mDeleted = false;
     }
 
diff --git a/libutils/tests/SystemClock_test.cpp b/libutils/tests/SystemClock_test.cpp
new file mode 100644
index 0000000..5ad060b
--- /dev/null
+++ b/libutils/tests/SystemClock_test.cpp
@@ -0,0 +1,74 @@
+/*
+ * 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 <unistd.h>
+#include <utils/SystemClock.h>
+
+#include <gtest/gtest.h>
+
+static const auto MS_IN_NS = 1000000;
+
+static const int64_t SLEEP_MS = 500;
+static const int64_t SLEEP_NS = SLEEP_MS * MS_IN_NS;
+// Conservatively assume that we might be descheduled for up to 50 ms
+static const int64_t SLACK_MS = 50;
+static const int64_t SLACK_NS = SLACK_MS * MS_IN_NS;
+
+TEST(SystemClock, SystemClock) {
+    auto startUptimeMs = android::uptimeMillis();
+    auto startRealtimeMs = android::elapsedRealtime();
+    auto startRealtimeNs = android::elapsedRealtimeNano();
+
+    ASSERT_GT(startUptimeMs, 0)
+            << "uptimeMillis() reported an impossible uptime";
+    ASSERT_GE(startRealtimeMs, startUptimeMs)
+            << "elapsedRealtime() thinks we've suspended for negative time";
+    ASSERT_GE(startRealtimeNs, startUptimeMs * MS_IN_NS)
+            << "elapsedRealtimeNano() thinks we've suspended for negative time";
+
+    ASSERT_GE(startRealtimeNs, startRealtimeMs * MS_IN_NS)
+            << "elapsedRealtime() and elapsedRealtimeNano() are inconsistent";
+    ASSERT_LT(startRealtimeNs, (startRealtimeMs + SLACK_MS) * MS_IN_NS)
+            << "elapsedRealtime() and elapsedRealtimeNano() are inconsistent";
+
+    timespec ts;
+    ts.tv_sec = 0;
+    ts.tv_nsec = SLEEP_MS * MS_IN_NS;
+    auto nanosleepErr = TEMP_FAILURE_RETRY(nanosleep(&ts, nullptr));
+    ASSERT_EQ(nanosleepErr, 0) << "nanosleep() failed: " << strerror(errno);
+
+    auto endUptimeMs = android::uptimeMillis();
+    auto endRealtimeMs = android::elapsedRealtime();
+    auto endRealtimeNs = android::elapsedRealtimeNano();
+
+    EXPECT_GE(endUptimeMs - startUptimeMs, SLEEP_MS)
+            << "uptimeMillis() advanced too little after nanosleep()";
+    EXPECT_LT(endUptimeMs - startUptimeMs, SLEEP_MS + SLACK_MS)
+            << "uptimeMillis() advanced too much after nanosleep()";
+    EXPECT_GE(endRealtimeMs - startRealtimeMs, SLEEP_MS)
+            << "elapsedRealtime() advanced too little after nanosleep()";
+    EXPECT_LT(endRealtimeMs - startRealtimeMs, SLEEP_MS + SLACK_MS)
+            << "elapsedRealtime() advanced too much after nanosleep()";
+    EXPECT_GE(endRealtimeNs - startRealtimeNs, SLEEP_NS)
+            << "elapsedRealtimeNano() advanced too little after nanosleep()";
+    EXPECT_LT(endRealtimeNs - startRealtimeNs, SLEEP_NS + SLACK_NS)
+            << "elapsedRealtimeNano() advanced too much after nanosleep()";
+
+    EXPECT_GE(endRealtimeNs, endRealtimeMs * MS_IN_NS)
+            << "elapsedRealtime() and elapsedRealtimeNano() are inconsistent after nanosleep()";
+    EXPECT_LT(endRealtimeNs, (endRealtimeMs + SLACK_MS) * MS_IN_NS)
+            << "elapsedRealtime() and elapsedRealtimeNano() are inconsistent after nanosleep()";
+}
diff --git a/libutils/tests/TestHelpers.h b/libutils/tests/TestHelpers.h
index d8e985e..6801cd7 100644
--- a/libutils/tests/TestHelpers.h
+++ b/libutils/tests/TestHelpers.h
@@ -60,7 +60,7 @@
     int mDelayMillis;
 
 public:
-    DelayedTask(int delayMillis) : mDelayMillis(delayMillis) { }
+    explicit DelayedTask(int delayMillis) : mDelayMillis(delayMillis) { }
 
 protected:
     virtual ~DelayedTask() { }
diff --git a/libutils/tests/Unicode_test.cpp b/libutils/tests/Unicode_test.cpp
index c263f75..d23e43a 100644
--- a/libutils/tests/Unicode_test.cpp
+++ b/libutils/tests/Unicode_test.cpp
@@ -98,7 +98,7 @@
 
     char16_t output[1 + 1 + 1 + 2 + 1]; // Room for NULL
 
-    utf8_to_utf16(str, sizeof(str), output);
+    utf8_to_utf16(str, sizeof(str), output, sizeof(output) / sizeof(output[0]));
 
     EXPECT_EQ(0x0030, output[0])
             << "should be U+0030";
@@ -147,4 +147,15 @@
     EXPECT_EQ(nullptr, result);
 }
 
+// http://b/29267949
+// Test that overreading in utf8_to_utf16_length is detected
+TEST_F(UnicodeTest, InvalidUtf8OverreadDetected) {
+    // An utf8 char starting with \xc4 is two bytes long.
+    // Add extra zeros so no extra memory is read in case the code doesn't
+    // work as expected.
+    static char utf8[] = "\xc4\x00\x00\x00";
+    ASSERT_DEATH(utf8_to_utf16_length((uint8_t *) utf8, strlen(utf8),
+            true /* overreadIsFatal */), "" /* regex for ASSERT_DEATH */);
+}
+
 }
diff --git a/libutils/tests/Vector_test.cpp b/libutils/tests/Vector_test.cpp
index d9b32f9..671200f 100644
--- a/libutils/tests/Vector_test.cpp
+++ b/libutils/tests/Vector_test.cpp
@@ -18,11 +18,12 @@
 
 #define __STDC_LIMIT_MACROS
 #include <stdint.h>
-#include <utils/Vector.h>
-#include <cutils/log.h>
-#include <gtest/gtest.h>
 #include <unistd.h>
 
+#include <android/log.h>
+#include <gtest/gtest.h>
+#include <utils/Vector.h>
+
 namespace android {
 
 class VectorTest : public testing::Test {
@@ -89,9 +90,9 @@
   vector.add(4);
 
   vector.setCapacity(8);
-  ASSERT_EQ(8, vector.capacity());
+  ASSERT_EQ(8U, vector.capacity());
   vector.setCapacity(2);
-  ASSERT_EQ(8, vector.capacity());
+  ASSERT_EQ(8U, vector.capacity());
 }
 
 // NOTE: All of the tests below are useless because of the "TODO" above.
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
new file mode 100644
index 0000000..5ed0fe8
--- /dev/null
+++ b/libziparchive/Android.bp
@@ -0,0 +1,111 @@
+//
+// Copyright (C) 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_defaults {
+    name: "libziparchive_flags",
+    cflags: [
+        // ZLIB_CONST turns on const for input buffers, which is pretty standard.
+        "-DZLIB_CONST",
+        "-Werror",
+        "-Wall",
+    ],
+    cppflags: [
+        "-Wold-style-cast",
+        // Incorrectly warns when C++11 empty brace {} initializer is used.
+        // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61489
+        "-Wno-missing-field-initializers",
+    ],
+}
+
+cc_defaults {
+    name: "libziparchive_defaults",
+    srcs: [
+        "zip_archive.cc",
+        "zip_archive_stream_entry.cc",
+        "zip_writer.cc",
+    ],
+
+    target: {
+        windows: {
+            cflags: ["-mno-ms-bitfields"],
+
+            enabled: true,
+        },
+    },
+
+    shared_libs: [
+        "libbase",
+        "liblog",
+    ],
+}
+
+
+cc_library {
+    name: "libziparchive",
+    host_supported: true,
+    defaults: ["libziparchive_defaults", "libziparchive_flags"],
+    static_libs: ["libutils"],
+    shared_libs: ["liblog", "libbase"],
+    target: {
+        android: {
+            static_libs: ["libz"],
+        },
+        host: {
+            shared_libs: ["libz-host"],
+        },
+    },
+}
+
+// Also provide libziparchive-host until everything is switched over to using libziparchive
+cc_library {
+    name: "libziparchive-host",
+    host_supported: true,
+    device_supported: false,
+    defaults: ["libziparchive_defaults", "libziparchive_flags"],
+    shared_libs: ["libz-host"],
+    static_libs: ["libutils"],
+}
+
+// Tests.
+cc_test {
+    name: "ziparchive-tests",
+    host_supported: true,
+    defaults: ["libziparchive_flags"],
+
+    srcs: [
+        "entry_name_utils_test.cc",
+        "zip_archive_test.cc",
+        "zip_writer_test.cc",
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+    ],
+
+    static_libs: [
+        "libziparchive",
+        "libz",
+        "libutils",
+    ],
+
+    target: {
+        host: {
+            cppflags: ["-Wno-unnamed-type-template-args"],
+        },
+        windows: {
+            enabled: true,
+        },
+    },
+}
diff --git a/libziparchive/Android.mk b/libziparchive/Android.mk
deleted file mode 100644
index 3cd8b87..0000000
--- a/libziparchive/Android.mk
+++ /dev/null
@@ -1,106 +0,0 @@
-#
-# Copyright (C) 2013 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.
-
-LOCAL_PATH := $(call my-dir)
-
-libziparchive_source_files := \
-    zip_archive.cc \
-    zip_archive_stream_entry.cc \
-    zip_writer.cc \
-
-libziparchive_test_files := \
-    entry_name_utils_test.cc \
-    zip_archive_test.cc \
-    zip_writer_test.cc \
-
-# ZLIB_CONST turns on const for input buffers, which is pretty standard.
-libziparchive_common_c_flags := \
-    -DZLIB_CONST \
-    -Werror \
-    -Wall \
-
-# Incorrectly warns when C++11 empty brace {} initializer is used.
-# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61489
-libziparchive_common_cpp_flags := \
-    -Wold-style-cast \
-    -Wno-missing-field-initializers \
-
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_SRC_FILES := $(libziparchive_source_files)
-LOCAL_STATIC_LIBRARIES := libz
-LOCAL_SHARED_LIBRARIES := libutils libbase
-LOCAL_MODULE:= libziparchive
-LOCAL_CFLAGS := $(libziparchive_common_c_flags)
-LOCAL_CPPFLAGS := $(libziparchive_common_cpp_flags)
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_SRC_FILES := $(libziparchive_source_files)
-LOCAL_STATIC_LIBRARIES := libz libutils libbase
-LOCAL_MODULE:= libziparchive-host
-LOCAL_CFLAGS := $(libziparchive_common_c_flags)
-LOCAL_CFLAGS_windows := -mno-ms-bitfields
-LOCAL_CPPFLAGS := $(libziparchive_common_cpp_flags)
-
-LOCAL_MULTILIB := both
-LOCAL_MODULE_HOST_OS := darwin linux windows
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_SRC_FILES := $(libziparchive_source_files)
-LOCAL_STATIC_LIBRARIES := libutils
-LOCAL_SHARED_LIBRARIES := libz-host liblog libbase
-LOCAL_MODULE:= libziparchive-host
-LOCAL_CFLAGS := $(libziparchive_common_c_flags)
-LOCAL_CPPFLAGS := $(libziparchive_common_cpp_flags)
-LOCAL_MULTILIB := both
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-# Tests.
-include $(CLEAR_VARS)
-LOCAL_MODULE := ziparchive-tests
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_CFLAGS := $(libziparchive_common_c_flags)
-LOCAL_CPPFLAGS := $(libziparchive_common_cpp_flags)
-LOCAL_SRC_FILES := $(libziparchive_test_files)
-LOCAL_SHARED_LIBRARIES := \
-    libbase \
-    liblog \
-
-LOCAL_STATIC_LIBRARIES := \
-    libziparchive \
-    libz \
-    libutils \
-
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := ziparchive-tests-host
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_CFLAGS := $(libziparchive_common_c_flags)
-LOCAL_CPPFLAGS := -Wno-unnamed-type-template-args $(libziparchive_common_cpp_flags)
-LOCAL_SRC_FILES := $(libziparchive_test_files)
-LOCAL_STATIC_LIBRARIES := \
-    libziparchive-host \
-    libz \
-    libbase \
-    libutils \
-    liblog \
-
-LOCAL_MODULE_HOST_OS := darwin linux windows
-include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libziparchive/testdata/dummy-update.zip b/libziparchive/testdata/dummy-update.zip
new file mode 100644
index 0000000..6976bf1
--- /dev/null
+++ b/libziparchive/testdata/dummy-update.zip
Binary files differ
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 986ee72..0ac6f2c 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -18,6 +18,8 @@
  * Read-only access to Zip archives, with minimal heap allocation.
  */
 
+#define LOG_TAG "ziparchive"
+
 #include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -30,12 +32,13 @@
 #include <memory>
 #include <vector>
 
-#include "android-base/file.h"
-#include "android-base/macros.h"  // TEMP_FAILURE_RETRY may or may not be in unistd
-#include "android-base/memory.h"
-#include "log/log.h"
-#include "utils/Compat.h"
-#include "utils/FileMap.h"
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/macros.h>  // TEMP_FAILURE_RETRY may or may not be in unistd
+#include <android-base/memory.h>
+#include <log/log.h>
+#include <utils/Compat.h>
+#include <utils/FileMap.h>
 #include "ziparchive/zip_archive.h"
 #include "zlib.h"
 
@@ -214,19 +217,14 @@
   return 0;
 }
 
-static int32_t MapCentralDirectory0(int fd, const char* debug_file_name,
-                                    ZipArchive* archive, off64_t file_length,
-                                    off64_t read_amount, uint8_t* scan_buffer) {
+static int32_t MapCentralDirectory0(const char* debug_file_name, ZipArchive* archive,
+                                    off64_t file_length, off64_t read_amount,
+                                    uint8_t* scan_buffer) {
   const off64_t search_start = file_length - read_amount;
 
-  if (lseek64(fd, search_start, SEEK_SET) != search_start) {
-    ALOGW("Zip: seek %" PRId64 " failed: %s", static_cast<int64_t>(search_start),
-          strerror(errno));
-    return kIoError;
-  }
-  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));
+  if(!archive->mapped_zip.ReadAtOffset(scan_buffer, read_amount, search_start)) {
+    ALOGE("Zip: read %" PRId64 " from offset %" PRId64 " failed",
+          static_cast<int64_t>(read_amount), static_cast<int64_t>(search_start));
     return kIoError;
   }
 
@@ -291,9 +289,11 @@
    * It all looks good.  Create a mapping for the CD, and set the fields
    * in archive.
    */
-  if (!archive->directory_map.create(debug_file_name, fd,
-          static_cast<off64_t>(eocd->cd_start_offset),
-          static_cast<size_t>(eocd->cd_size), true /* read only */) ) {
+
+  if (!archive->InitializeCentralDirectory(debug_file_name,
+                                           static_cast<off64_t>(eocd->cd_start_offset),
+                                           static_cast<size_t>(eocd->cd_size))) {
+    ALOGE("Zip: failed to intialize central directory.\n");
     return kMmapFailed;
   }
 
@@ -308,18 +308,16 @@
  *
  * On success, returns 0 after populating fields from the EOCD area:
  *   directory_offset
- *   directory_map
+ *   directory_ptr
  *   num_entries
  */
-static int32_t MapCentralDirectory(int fd, const char* debug_file_name,
-                                   ZipArchive* archive) {
+static int32_t MapCentralDirectory(const char* debug_file_name, ZipArchive* archive) {
 
   // Test file length. We use lseek64 to make sure the file
   // is small enough to be a zip file (Its size must be less than
   // 0xffffffff bytes).
-  off64_t file_length = lseek64(fd, 0, SEEK_END);
+  off64_t file_length = archive->mapped_zip.GetFileLength();
   if (file_length == -1) {
-    ALOGV("Zip: lseek on fd %d failed", fd);
     return kInvalidFile;
   }
 
@@ -350,11 +348,9 @@
     read_amount = file_length;
   }
 
-  uint8_t* scan_buffer = reinterpret_cast<uint8_t*>(malloc(read_amount));
-  int32_t result = MapCentralDirectory0(fd, debug_file_name, archive,
-                                        file_length, read_amount, scan_buffer);
-
-  free(scan_buffer);
+  std::vector<uint8_t> scan_buffer(read_amount);
+  int32_t result = MapCentralDirectory0(debug_file_name, archive, file_length, read_amount,
+                                        scan_buffer.data());
   return result;
 }
 
@@ -365,9 +361,8 @@
  * Returns 0 on success.
  */
 static int32_t ParseZipArchive(ZipArchive* archive) {
-  const uint8_t* const cd_ptr =
-      reinterpret_cast<const uint8_t*>(archive->directory_map.getDataPtr());
-  const size_t cd_length = archive->directory_map.getDataLength();
+  const uint8_t* const cd_ptr = archive->central_directory.GetBasePtr();
+  const size_t cd_length = archive->central_directory.GetMapLength();
   const uint16_t num_entries = archive->num_entries;
 
   /*
@@ -441,7 +436,7 @@
 static int32_t OpenArchiveInternal(ZipArchive* archive,
                                    const char* debug_file_name) {
   int32_t result = -1;
-  if ((result = MapCentralDirectory(archive->fd, debug_file_name, archive))) {
+  if ((result = MapCentralDirectory(debug_file_name, archive)) != 0) {
     return result;
   }
 
@@ -472,6 +467,13 @@
   return OpenArchiveInternal(archive, fileName);
 }
 
+int32_t OpenArchiveFromMemory(void* address, size_t length, const char* debug_file_name,
+                              ZipArchiveHandle *handle) {
+  ZipArchive* archive = new ZipArchive(address, length);
+  *handle = archive;
+  return OpenArchiveInternal(archive, debug_file_name);
+}
+
 /*
  * Close a ZipArchive, closing the file and freeing the contents.
  */
@@ -481,10 +483,10 @@
   delete archive;
 }
 
-static int32_t UpdateEntryFromDataDescriptor(int fd,
+static int32_t UpdateEntryFromDataDescriptor(MappedZipFile& mapped_zip,
                                              ZipEntry *entry) {
   uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)];
-  if (!android::base::ReadFully(fd, ddBuf, sizeof(ddBuf))) {
+  if (!mapped_zip.ReadData(ddBuf, sizeof(ddBuf))) {
     return kIoError;
   }
 
@@ -499,23 +501,6 @@
   return 0;
 }
 
-// Attempts to read |len| bytes into |buf| at offset |off|.
-// On non-Windows platforms, callers are guaranteed that the |fd|
-// offset is unchanged and there is no side effect to this call.
-//
-// On Windows platforms this is not thread-safe.
-static inline bool 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
-  if (lseek64(fd, off, SEEK_SET) != off) {
-    ALOGW("Zip: failed seek to offset %" PRId64, off);
-    return false;
-  }
-  return android::base::ReadFully(fd, buf, len);
-#endif
-}
-
 static int32_t FindEntry(const ZipArchive* archive, const int ent,
                          ZipEntry* data) {
   const uint16_t nameLen = archive->hash_table[ent].name_length;
@@ -529,9 +514,8 @@
   // This is the base of our mmapped region, we have to sanity check that
   // the name that's in the hash table is a pointer to a location within
   // this mapped region.
-  const uint8_t* base_ptr = reinterpret_cast<const uint8_t*>(
-    archive->directory_map.getDataPtr());
-  if (ptr < base_ptr || ptr > base_ptr + archive->directory_map.getDataLength()) {
+  const uint8_t* base_ptr = archive->central_directory.GetBasePtr();
+  if (ptr < base_ptr || ptr > base_ptr + archive->central_directory.GetMapLength()) {
     ALOGW("Zip: Invalid entry pointer");
     return kInvalidOffset;
   }
@@ -563,7 +547,7 @@
   }
 
   uint8_t lfh_buf[sizeof(LocalFileHeader)];
-  if (!ReadAtOffset(archive->fd, lfh_buf, sizeof(lfh_buf), local_header_offset)) {
+  if (!archive->mapped_zip.ReadAtOffset(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;
@@ -603,19 +587,16 @@
       return kInvalidOffset;
     }
 
-    uint8_t* name_buf = reinterpret_cast<uint8_t*>(malloc(nameLen));
-    if (!ReadAtOffset(archive->fd, name_buf, nameLen, name_offset)) {
+    std::vector<uint8_t> name_buf(nameLen);
+    if (!archive->mapped_zip.ReadAtOffset(name_buf.data(), nameLen, name_offset)) {
       ALOGW("Zip: failed reading lfh name from offset %" PRId64, static_cast<int64_t>(name_offset));
-      free(name_buf);
       return kIoError;
     }
 
-    if (memcmp(archive->hash_table[ent].name, name_buf, nameLen)) {
-      free(name_buf);
+    if (memcmp(archive->hash_table[ent].name, name_buf.data(), nameLen)) {
       return kInconsistentInformation;
     }
 
-    free(name_buf);
   } else {
     ALOGW("Zip: lfh name did not match central directory.");
     return kInconsistentInformation;
@@ -805,7 +786,8 @@
   // Creates a FileWriter for |fd| and prepare to write |entry| to it,
   // guaranteeing that the file descriptor is valid and that there's enough
   // space on the volume to write out the entry completely and that the file
-  // is truncated to the correct length.
+  // is truncated to the correct length (no truncation if |fd| references a
+  // block device).
   //
   // Returns a valid FileWriter on success, |nullptr| if an error occurred.
   static std::unique_ptr<FileWriter> Create(int fd, const ZipEntry* entry) {
@@ -830,20 +812,30 @@
       // disk does not have enough space.
       result = TEMP_FAILURE_RETRY(fallocate(fd, 0, current_offset, declared_length));
       if (result == -1 && errno == ENOSPC) {
-        ALOGW("Zip: unable to allocate space for file to %" PRId64 ": %s",
-              static_cast<int64_t>(declared_length + current_offset), strerror(errno));
+        ALOGW("Zip: unable to allocate  %" PRId64 " bytes at offset %" PRId64 " : %s",
+              static_cast<int64_t>(declared_length), static_cast<int64_t>(current_offset),
+              strerror(errno));
         return std::unique_ptr<FileWriter>(nullptr);
       }
     }
 #endif  // __linux__
 
-    result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
-    if (result == -1) {
-      ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
-            static_cast<int64_t>(declared_length + current_offset), strerror(errno));
+    struct stat sb;
+    if (fstat(fd, &sb) == -1) {
+      ALOGW("Zip: unable to fstat file: %s", strerror(errno));
       return std::unique_ptr<FileWriter>(nullptr);
     }
 
+    // Block device doesn't support ftruncate(2).
+    if (!S_ISBLK(sb.st_mode)) {
+      result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
+      if (result == -1) {
+        ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
+              static_cast<int64_t>(declared_length + current_offset), strerror(errno));
+        return std::unique_ptr<FileWriter>(nullptr);
+      }
+    }
+
     return std::unique_ptr<FileWriter>(new FileWriter(fd, declared_length));
   }
 
@@ -884,7 +876,7 @@
 }
 #pragma GCC diagnostic pop
 
-static int32_t InflateEntryToWriter(int fd, const ZipEntry* entry,
+static int32_t InflateEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry,
                                     Writer* writer, uint64_t* crc_out) {
   const size_t kBufSize = 32768;
   std::vector<uint8_t> read_buf(kBufSize);
@@ -934,7 +926,7 @@
     /* read as much as we can */
     if (zstream.avail_in == 0) {
       const size_t getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
-      if (!android::base::ReadFully(fd, read_buf.data(), getSize)) {
+      if (!mapped_zip.ReadData(read_buf.data(), getSize)) {
         ALOGW("Zip: inflate read failed, getSize = %zu: %s", getSize, strerror(errno));
         return kIoError;
       }
@@ -982,7 +974,7 @@
   return 0;
 }
 
-static int32_t CopyEntryToWriter(int fd, const ZipEntry* entry, Writer* writer,
+static int32_t CopyEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry, Writer* writer,
                                  uint64_t *crc_out) {
   static const uint32_t kBufSize = 32768;
   std::vector<uint8_t> buf(kBufSize);
@@ -996,7 +988,7 @@
     // Safe conversion because kBufSize is narrow enough for a 32 bit signed
     // value.
     const size_t block_size = (remaining > kBufSize) ? kBufSize : remaining;
-    if (!android::base::ReadFully(fd, buf.data(), block_size)) {
+    if (!mapped_zip.ReadData(buf.data(), block_size)) {
       ALOGW("CopyFileToFile: copy read failed, block_size = %zu: %s", block_size, strerror(errno));
       return kIoError;
     }
@@ -1019,7 +1011,7 @@
   const uint16_t method = entry->method;
   off64_t data_offset = entry->offset;
 
-  if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) {
+  if (!archive->mapped_zip.SeekToOffset(data_offset)) {
     ALOGW("Zip: lseek to data at %" PRId64 " failed", static_cast<int64_t>(data_offset));
     return kIoError;
   }
@@ -1028,13 +1020,13 @@
   int32_t return_value = -1;
   uint64_t crc = 0;
   if (method == kCompressStored) {
-    return_value = CopyEntryToWriter(archive->fd, entry, writer, &crc);
+    return_value = CopyEntryToWriter(archive->mapped_zip, entry, writer, &crc);
   } else if (method == kCompressDeflated) {
-    return_value = InflateEntryToWriter(archive->fd, entry, writer, &crc);
+    return_value = InflateEntryToWriter(archive->mapped_zip, entry, writer, &crc);
   }
 
   if (!return_value && entry->has_data_descriptor) {
-    return_value = UpdateEntryFromDataDescriptor(archive->fd, entry);
+    return_value = UpdateEntryFromDataDescriptor(archive->mapped_zip, entry);
     if (return_value) {
       return return_value;
     }
@@ -1075,5 +1067,152 @@
 }
 
 int GetFileDescriptor(const ZipArchiveHandle handle) {
-  return reinterpret_cast<ZipArchive*>(handle)->fd;
+  return reinterpret_cast<ZipArchive*>(handle)->mapped_zip.GetFileDescriptor();
+}
+
+ZipString::ZipString(const char* entry_name)
+    : name(reinterpret_cast<const uint8_t*>(entry_name)) {
+  size_t len = strlen(entry_name);
+  CHECK_LE(len, static_cast<size_t>(UINT16_MAX));
+  name_length = static_cast<uint16_t>(len);
+}
+
+#if !defined(_WIN32)
+class ProcessWriter : public Writer {
+ public:
+  ProcessWriter(ProcessZipEntryFunction func, void* cookie) : Writer(),
+    proc_function_(func),
+    cookie_(cookie) {
+  }
+
+  virtual bool Append(uint8_t* buf, size_t buf_size) override {
+    return proc_function_(buf, buf_size, cookie_);
+  }
+
+ private:
+  ProcessZipEntryFunction proc_function_;
+  void* cookie_;
+};
+
+int32_t ProcessZipEntryContents(ZipArchiveHandle handle, ZipEntry* entry,
+                                ProcessZipEntryFunction func, void* cookie) {
+  ProcessWriter writer(func, cookie);
+  return ExtractToWriter(handle, entry, &writer);
+}
+
+#endif //!defined(_WIN32)
+
+int MappedZipFile::GetFileDescriptor() const {
+  if (!has_fd_) {
+    ALOGW("Zip: MappedZipFile doesn't have a file descriptor.");
+    return -1;
+  }
+  return fd_;
+}
+
+void* MappedZipFile::GetBasePtr() const {
+  if (has_fd_) {
+    ALOGW("Zip: MappedZipFile doesn't have a base pointer.");
+    return nullptr;
+  }
+  return base_ptr_;
+}
+
+off64_t MappedZipFile::GetFileLength() const {
+  if (has_fd_) {
+    off64_t result = lseek64(fd_, 0, SEEK_END);
+    if (result == -1) {
+      ALOGE("Zip: lseek on fd %d failed: %s", fd_, strerror(errno));
+    }
+    return result;
+  } else {
+    if (base_ptr_ == nullptr) {
+      ALOGE("Zip: invalid file map\n");
+      return -1;
+    }
+    return static_cast<off64_t>(data_length_);
+  }
+}
+
+bool MappedZipFile::SeekToOffset(off64_t offset) {
+  if (has_fd_) {
+    if (lseek64(fd_, offset, SEEK_SET) != offset) {
+      ALOGE("Zip: lseek to %" PRId64 " failed: %s\n", offset, strerror(errno));
+      return false;
+    }
+    return true;
+  } else {
+    if (offset < 0 || offset > static_cast<off64_t>(data_length_)) {
+      ALOGE("Zip: invalid offset: %" PRId64 ", data length: %" PRId64 "\n" , offset,
+            data_length_);
+      return false;
+    }
+
+    read_pos_ = offset;
+    return true;
+  }
+}
+
+bool MappedZipFile::ReadData(uint8_t* buffer, size_t read_amount) {
+  if (has_fd_) {
+    if(!android::base::ReadFully(fd_, buffer, read_amount)) {
+      ALOGE("Zip: read from %d failed\n", fd_);
+      return false;
+    }
+  } else {
+    memcpy(buffer, static_cast<uint8_t*>(base_ptr_) + read_pos_, read_amount);
+    read_pos_ += read_amount;
+  }
+  return true;
+}
+
+// Attempts to read |len| bytes into |buf| at offset |off|.
+bool MappedZipFile::ReadAtOffset(uint8_t* buf, size_t len, off64_t off) {
+#if !defined(_WIN32)
+  if (has_fd_) {
+    if (static_cast<size_t>(TEMP_FAILURE_RETRY(pread64(fd_, buf, len, off))) != len) {
+      ALOGE("Zip: failed to read at offset %" PRId64 "\n", off);
+      return false;
+    }
+    return true;
+  }
+#endif
+  if (!SeekToOffset(off)) {
+    return false;
+  }
+  return ReadData(buf, len);
+
+}
+
+void CentralDirectory::Initialize(void* map_base_ptr, off64_t cd_start_offset, size_t cd_size) {
+  base_ptr_ = static_cast<uint8_t*>(map_base_ptr) + cd_start_offset;
+  length_ = cd_size;
+}
+
+bool ZipArchive::InitializeCentralDirectory(const char* debug_file_name, off64_t cd_start_offset,
+                                            size_t cd_size) {
+  if (mapped_zip.HasFd()) {
+    if (!directory_map->create(debug_file_name, mapped_zip.GetFileDescriptor(),
+                               cd_start_offset, cd_size, true /* read only */)) {
+      return false;
+    }
+
+    CHECK_EQ(directory_map->getDataLength(), cd_size);
+    central_directory.Initialize(directory_map->getDataPtr(), 0/*offset*/, cd_size);
+  } else {
+    if (mapped_zip.GetBasePtr() == nullptr) {
+      ALOGE("Zip: Failed to map central directory, bad mapped_zip base pointer\n");
+      return false;
+    }
+    if (static_cast<off64_t>(cd_start_offset) + static_cast<off64_t>(cd_size) >
+        mapped_zip.GetFileLength()) {
+      ALOGE("Zip: Failed to map central directory, offset exceeds mapped memory region ("
+            "start_offset %"  PRId64 ", cd_size %zu, mapped_region_size %" PRId64 ")",
+            static_cast<int64_t>(cd_start_offset), cd_size, mapped_zip.GetFileLength());
+      return false;
+    }
+
+    central_directory.Initialize(mapped_zip.GetBasePtr(), cd_start_offset, cd_size);
+  }
+  return true;
 }
diff --git a/libziparchive/zip_archive_private.h b/libziparchive/zip_archive_private.h
index ab52368..971db4f 100644
--- a/libziparchive/zip_archive_private.h
+++ b/libziparchive/zip_archive_private.h
@@ -21,17 +21,83 @@
 #include <stdlib.h>
 #include <unistd.h>
 
+#include <memory>
+#include <vector>
+
 #include <utils/FileMap.h>
 #include <ziparchive/zip_archive.h>
 
+class MappedZipFile {
+ public:
+  explicit MappedZipFile(const int fd) :
+    has_fd_(true),
+    fd_(fd),
+    base_ptr_(nullptr),
+    data_length_(0),
+    read_pos_(0) {}
+
+  explicit MappedZipFile(void* address, size_t length) :
+    has_fd_(false),
+    fd_(-1),
+    base_ptr_(address),
+    data_length_(static_cast<off64_t>(length)),
+    read_pos_(0) {}
+
+  bool HasFd() const {return has_fd_;}
+
+  int GetFileDescriptor() const;
+
+  void* GetBasePtr() const;
+
+  off64_t GetFileLength() const;
+
+  bool SeekToOffset(off64_t offset);
+
+  bool ReadData(uint8_t* buffer, size_t read_amount);
+
+  bool ReadAtOffset(uint8_t* buf, size_t len, off64_t off);
+
+ private:
+  // If has_fd_ is true, fd is valid and we'll read contents of a zip archive
+  // from the file. Otherwise, we're opening the archive from a memory mapped
+  // file. In that case, base_ptr_ points to the start of the memory region and
+  // data_length_ defines the file length.
+  const bool has_fd_;
+
+  const int fd_;
+
+  void* const base_ptr_;
+  const off64_t data_length_;
+  // read_pos_ is the offset to the base_ptr_ where we read data from.
+  size_t read_pos_;
+};
+
+class CentralDirectory {
+ public:
+  CentralDirectory(void) :
+    base_ptr_(nullptr),
+    length_(0) {}
+
+  const uint8_t* GetBasePtr() const {return base_ptr_;}
+
+  size_t GetMapLength() const {return length_;}
+
+  void Initialize(void* map_base_ptr, off64_t cd_start_offset, size_t cd_size);
+
+ private:
+  const uint8_t* base_ptr_;
+  size_t length_;
+};
+
 struct ZipArchive {
   // open Zip archive
-  const int fd;
+  mutable MappedZipFile mapped_zip;
   const bool close_file;
 
   // mapped central directory area
   off64_t directory_offset;
-  android::FileMap directory_map;
+  CentralDirectory central_directory;
+  std::unique_ptr<android::FileMap> directory_map;
 
   // number of entries in the Zip archive
   uint16_t num_entries;
@@ -44,20 +110,36 @@
   ZipString* hash_table;
 
   ZipArchive(const int fd, bool assume_ownership) :
-      fd(fd),
-      close_file(assume_ownership),
-      directory_offset(0),
-      num_entries(0),
-      hash_table_size(0),
-      hash_table(NULL) {}
+    mapped_zip(fd),
+    close_file(assume_ownership),
+    directory_offset(0),
+    central_directory(),
+    directory_map(new android::FileMap()),
+    num_entries(0),
+    hash_table_size(0),
+    hash_table(nullptr) {}
+
+  ZipArchive(void* address, size_t length) :
+    mapped_zip(address, length),
+    close_file(false),
+    directory_offset(0),
+    central_directory(),
+    directory_map(new android::FileMap()),
+    num_entries(0),
+    hash_table_size(0),
+    hash_table(nullptr) {}
 
   ~ZipArchive() {
-    if (close_file && fd >= 0) {
-      close(fd);
+    if (close_file && mapped_zip.GetFileDescriptor() >= 0) {
+      close(mapped_zip.GetFileDescriptor());
     }
 
     free(hash_table);
   }
+
+  bool InitializeCentralDirectory(const char* debug_file_name, off64_t cd_start_offset,
+                                  size_t cd_size);
+
 };
 
 #endif  // LIBZIPARCHIVE_ZIPARCHIVE_PRIVATE_H_
diff --git a/libziparchive/zip_archive_stream_entry.cc b/libziparchive/zip_archive_stream_entry.cc
index f618835..64b24c3 100644
--- a/libziparchive/zip_archive_stream_entry.cc
+++ b/libziparchive/zip_archive_stream_entry.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "ZIPARCHIVE"
+
 // Read-only stream access to Zip Archive entries.
 #include <errno.h>
 #include <inttypes.h>
@@ -24,9 +26,8 @@
 #include <memory>
 #include <vector>
 
-#define LOG_TAG "ZIPARCHIVE"
+#include <android/log.h>
 #include <android-base/file.h>
-#include <log/log.h>
 #include <ziparchive/zip_archive.h>
 #include <ziparchive/zip_archive_stream_entry.h>
 #include <zlib.h>
@@ -38,7 +39,7 @@
 bool ZipArchiveStreamEntry::Init(const ZipEntry& entry) {
   ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
   off64_t data_offset = entry.offset;
-  if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) {
+  if (!archive->mapped_zip.SeekToOffset(data_offset)) {
     ALOGW("lseek to data at %" PRId64 " failed: %s", data_offset, strerror(errno));
     return false;
   }
@@ -48,7 +49,8 @@
 
 class ZipArchiveStreamEntryUncompressed : public ZipArchiveStreamEntry {
  public:
-  ZipArchiveStreamEntryUncompressed(ZipArchiveHandle handle) : ZipArchiveStreamEntry(handle) {}
+  explicit ZipArchiveStreamEntryUncompressed(ZipArchiveHandle handle)
+      : ZipArchiveStreamEntry(handle) {}
   virtual ~ZipArchiveStreamEntryUncompressed() {}
 
   const std::vector<uint8_t>* Read() override;
@@ -86,7 +88,7 @@
   size_t bytes = (length_ > data_.size()) ? data_.size() : length_;
   ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
   errno = 0;
-  if (!android::base::ReadFully(archive->fd, data_.data(), bytes)) {
+  if (!archive->mapped_zip.ReadData(data_.data(), bytes)) {
     if (errno != 0) {
       ALOGE("Error reading from archive fd: %s", strerror(errno));
     } else {
@@ -110,7 +112,8 @@
 
 class ZipArchiveStreamEntryCompressed : public ZipArchiveStreamEntry {
  public:
-  ZipArchiveStreamEntryCompressed(ZipArchiveHandle handle) : ZipArchiveStreamEntry(handle) {}
+  explicit ZipArchiveStreamEntryCompressed(ZipArchiveHandle handle)
+      : ZipArchiveStreamEntry(handle) {}
   virtual ~ZipArchiveStreamEntryCompressed();
 
   const std::vector<uint8_t>* Read() override;
@@ -206,7 +209,7 @@
       size_t bytes = (compressed_length_ > in_.size()) ? in_.size() : compressed_length_;
       ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
       errno = 0;
-      if (!android::base::ReadFully(archive->fd, in_.data(), bytes)) {
+      if (!archive->mapped_zip.ReadData(in_.data(), bytes)) {
         if (errno != 0) {
           ALOGE("Error reading from archive fd: %s", strerror(errno));
         } else {
@@ -249,7 +252,7 @@
 
 class ZipArchiveStreamEntryRawCompressed : public ZipArchiveStreamEntryUncompressed {
  public:
-  ZipArchiveStreamEntryRawCompressed(ZipArchiveHandle handle)
+  explicit ZipArchiveStreamEntryRawCompressed(ZipArchiveHandle handle)
       : ZipArchiveStreamEntryUncompressed(handle) {}
   virtual ~ZipArchiveStreamEntryRawCompressed() {}
 
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 6aee1bb..9dd6cc0 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -26,7 +26,9 @@
 
 #include <android-base/file.h>
 #include <android-base/test_utils.h>
+#include <android-base/unique_fd.h>
 #include <gtest/gtest.h>
+#include <utils/FileMap.h>
 #include <ziparchive/zip_archive.h>
 #include <ziparchive/zip_archive_stream_entry.h>
 
@@ -36,6 +38,7 @@
 static const std::string kValidZip = "valid.zip";
 static const std::string kLargeZip = "large.zip";
 static const std::string kBadCrcZip = "bad_crc.zip";
+static const std::string kUpdateZip = "dummy-update.zip";
 
 static const std::vector<uint8_t> kATxtContents {
   'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
@@ -494,6 +497,32 @@
             lseek64(tmp_file.fd, 0, SEEK_END));
 }
 
+#if !defined(_WIN32)
+TEST(ziparchive, OpenFromMemory) {
+  const std::string zip_path = test_data_dir + "/" + kUpdateZip;
+  android::base::unique_fd fd(open(zip_path.c_str(), O_RDONLY | O_BINARY));
+  ASSERT_NE(-1, fd);
+  struct stat sb;
+  ASSERT_EQ(0, fstat(fd, &sb));
+
+  // Memory map the file first and open the archive from the memory region.
+  android::FileMap file_map;
+  file_map.create(zip_path.c_str(), fd, 0/*offset*/, sb.st_size, true);
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveFromMemory(file_map.getDataPtr(), file_map.getDataLength(),
+                                     zip_path.c_str(), &handle));
+
+  // Assert one entry can be found and extracted correctly.
+  std::string BINARY_PATH("META-INF/com/google/android/update-binary");
+  ZipString binary_path(BINARY_PATH.c_str());
+  ZipEntry binary_entry;
+  ASSERT_EQ(0, FindEntry(handle, binary_path, &binary_entry));
+  TemporaryFile tmp_binary;
+  ASSERT_NE(-1, tmp_binary.fd);
+  ASSERT_EQ(0, ExtractEntryToFile(handle, &binary_entry, tmp_binary.fd));
+}
+#endif
+
 static void ZipArchiveStreamTest(
     ZipArchiveHandle& handle, const std::string& entry_name, bool raw,
     bool verified, ZipEntry* entry, std::vector<uint8_t>* read_data) {
diff --git a/libziparchive/zip_writer.cc b/libziparchive/zip_writer.cc
index 1ebed30..b72ed7f 100644
--- a/libziparchive/zip_writer.cc
+++ b/libziparchive/zip_writer.cc
@@ -243,8 +243,12 @@
   // Initialize the z_stream for compression.
   z_stream_ = std::unique_ptr<z_stream, void(*)(z_stream*)>(new z_stream(), DeleteZStream);
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
   int zerr = deflateInit2(z_stream_.get(), Z_BEST_COMPRESSION, Z_DEFLATED, -MAX_WBITS,
                           DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+#pragma GCC diagnostic pop
+
   if (zerr != Z_OK) {
     if (zerr == Z_VERSION_ERROR) {
       ALOGE("Installed zlib is not compatible with linked version (%s)", ZLIB_VERSION);
diff --git a/lmkd/Android.mk b/lmkd/Android.mk
index 8c88661..8980d1c 100644
--- a/lmkd/Android.mk
+++ b/lmkd/Android.mk
@@ -2,7 +2,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := lmkd.c
-LOCAL_SHARED_LIBRARIES := liblog libm libc libprocessgroup
+LOCAL_SHARED_LIBRARIES := liblog libm libc libprocessgroup libcutils
 LOCAL_CFLAGS := -Werror
 
 LOCAL_MODULE := lmkd
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index afc81ed..49746b3 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -18,6 +18,7 @@
 
 #include <arpa/inet.h>
 #include <errno.h>
+#include <sched.h>
 #include <signal.h>
 #include <stdlib.h>
 #include <string.h>
@@ -30,8 +31,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <android/log.h>
 #include <cutils/sockets.h>
-#include <log/log.h>
 #include <processgroup/processgroup.h>
 
 #ifndef __unused
@@ -109,7 +110,7 @@
 static struct proc *pidhash[PIDHASH_SZ];
 #define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
 
-#define ADJTOSLOT(adj) (adj + -OOM_SCORE_ADJ_MIN)
+#define ADJTOSLOT(adj) ((adj) + -OOM_SCORE_ADJ_MIN)
 static struct adjslot_list procadjslot_list[ADJTOSLOT(OOM_SCORE_ADJ_MAX) + 1];
 
 /*
@@ -397,9 +398,6 @@
 }
 
 static void ctrl_connect_handler(uint32_t events __unused) {
-    struct sockaddr_storage ss;
-    struct sockaddr *addrp = (struct sockaddr *)&ss;
-    socklen_t alen;
     struct epoll_event epev;
 
     if (ctrl_dfd >= 0) {
@@ -407,8 +405,7 @@
         ctrl_dfd_reopened = 1;
     }
 
-    alen = sizeof(ss);
-    ctrl_dfd = accept(ctrl_lfd, addrp, &alen);
+    ctrl_dfd = accept(ctrl_lfd, NULL, NULL);
 
     if (ctrl_dfd < 0) {
         ALOGE("lmkd control socket accept failed; errno=%d", errno);
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 33f22dd..41f2280 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -26,16 +26,14 @@
 #include <string>
 
 #include <android-base/file.h>
+#include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <cutils/sched_policy.h>
 #include <cutils/sockets.h>
 #include <log/event_tag_map.h>
-#include <log/log.h>
-#include <log/log_read.h>
-#include <log/logd.h>
-#include <log/logger.h>
 #include <log/logprint.h>
-#include <utils/threads.h>
+#include <private/android_logger.h>
+#include <system/thread_defs.h>
 
 #include <pcrecpp.h>
 
@@ -83,9 +81,16 @@
 static size_t g_maxCount;
 static size_t g_printCount;
 static bool g_printItAnyways;
+static bool g_debug;
+
+enum helpType {
+    HELP_FALSE,
+    HELP_TRUE,
+    HELP_FORMAT
+};
 
 // if showHelp is set, newline required in fmt statement to transition to usage
-__noreturn static void logcat_panic(bool showHelp, const char *fmt, ...) __printflike(2,3);
+__noreturn static void logcat_panic(enum helpType showHelp, const char *fmt, ...) __printflike(2,3);
 
 static int openLogFile (const char *pathname)
 {
@@ -109,35 +114,33 @@
             (g_maxRotatedLogs > 0) ? (int) (floor(log10(g_maxRotatedLogs) + 1)) : 0;
 
     for (int i = g_maxRotatedLogs ; i > 0 ; i--) {
-        char *file0, *file1;
+        std::string file1 = android::base::StringPrintf(
+            "%s.%.*d", g_outputFileName, maxRotationCountDigits, i);
 
-        asprintf(&file1, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i);
-
+        std::string file0;
         if (i - 1 == 0) {
-            asprintf(&file0, "%s", g_outputFileName);
+            file0 = android::base::StringPrintf("%s", g_outputFileName);
         } else {
-            asprintf(&file0, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i - 1);
+            file0 = android::base::StringPrintf(
+                "%s.%.*d", g_outputFileName, maxRotationCountDigits, i - 1);
         }
 
-        if (!file0 || !file1) {
+        if ((file0.length() == 0) || (file1.length() == 0)) {
             perror("while rotating log files");
             break;
         }
 
-        err = rename(file0, file1);
+        err = rename(file0.c_str(), file1.c_str());
 
         if (err < 0 && errno != ENOENT) {
             perror("while rotating log files");
         }
-
-        free(file1);
-        free(file0);
     }
 
     g_outFD = openLogFile(g_outputFileName);
 
     if (g_outFD < 0) {
-        logcat_panic(false, "couldn't open output file");
+        logcat_panic(HELP_FALSE, "couldn't open output file");
     }
 
     g_outByteCount = 0;
@@ -186,11 +189,13 @@
     } else {
         err = android_log_processLogBuffer(&buf->entry_v1, &entry);
     }
-    if (err < 0) {
+    if ((err < 0) && !g_debug) {
         goto error;
     }
 
-    if (android_log_shouldPrintLine(g_logformat, entry.tag, entry.priority)) {
+    if (android_log_shouldPrintLine(g_logformat,
+                                    std::string(entry.tag, entry.tagLen).c_str(),
+                                    entry.priority)) {
         bool match = regexOk(entry);
 
         g_printCount += match;
@@ -198,7 +203,7 @@
             bytesWritten = android_log_printLogLine(g_logformat, g_outFD, &entry);
 
             if (bytesWritten < 0) {
-                logcat_panic(false, "output error");
+                logcat_panic(HELP_FALSE, "output error");
             }
         }
     }
@@ -212,7 +217,6 @@
     }
 
 error:
-    //fprintf (stderr, "Error processing record\n");
     return;
 }
 
@@ -224,20 +228,22 @@
                      dev->printed ? "switch to" : "beginning of",
                      dev->device);
             if (write(g_outFD, buf, strlen(buf)) < 0) {
-                logcat_panic(false, "output error");
+                logcat_panic(HELP_FALSE, "output error");
             }
         }
         dev->printed = true;
     }
 }
 
-static void setupOutput()
-{
-
+static void setupOutputAndSchedulingPolicy(bool blocking) {
     if (g_outputFileName == NULL) {
         g_outFD = STDOUT_FILENO;
+        return;
+    }
 
-    } else {
+    if (blocking) {
+        // Lower priority and set to batch scheduling if we are saving
+        // the logs into files and taking continuous content.
         if (set_sched_policy(0, SP_BACKGROUND) < 0) {
             fprintf(stderr, "failed to set background scheduling policy\n");
         }
@@ -251,26 +257,26 @@
         if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
             fprintf(stderr, "failed set to priority\n");
         }
-
-        g_outFD = openLogFile (g_outputFileName);
-
-        if (g_outFD < 0) {
-            logcat_panic(false, "couldn't open output file");
-        }
-
-        struct stat statbuf;
-        if (fstat(g_outFD, &statbuf) == -1) {
-            close(g_outFD);
-            logcat_panic(false, "couldn't get output file stat\n");
-        }
-
-        if ((size_t) statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
-            close(g_outFD);
-            logcat_panic(false, "invalid output file stat\n");
-        }
-
-        g_outByteCount = statbuf.st_size;
     }
+
+    g_outFD = openLogFile (g_outputFileName);
+
+    if (g_outFD < 0) {
+        logcat_panic(HELP_FALSE, "couldn't open output file");
+    }
+
+    struct stat statbuf;
+    if (fstat(g_outFD, &statbuf) == -1) {
+        close(g_outFD);
+        logcat_panic(HELP_FALSE, "couldn't get output file stat\n");
+    }
+
+    if ((size_t) statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
+        close(g_outFD);
+        logcat_panic(HELP_FALSE, "invalid output file stat\n");
+    }
+
+    g_outByteCount = statbuf.st_size;
 }
 
 static void show_help(const char *cmd)
@@ -284,10 +290,14 @@
                     "                  Rotate log every kbytes. Requires -f option\n"
                     "  -n <count>, --rotate-count=<count>\n"
                     "                  Sets max number of rotated logs to <count>, default 4\n"
+                    "  --id=<id>       If the signature id for logging to file changes, then clear\n"
+                    "                  the fileset and continue\n"
                     "  -v <format>, --format=<format>\n"
-                    "                  Sets the log print format, where <format> is:\n"
-                    "                    brief color epoch long monotonic printable process raw\n"
-                    "                    tag thread threadtime time uid usec UTC year zone\n"
+                    "                  Sets log print format verb and adverbs, where <format> is:\n"
+                    "                    brief help long process raw tag thread threadtime time\n"
+                    "                  and individually flagged modifying adverbs can be added:\n"
+                    "                    color descriptive epoch monotonic printable uid\n"
+                    "                    usec UTC year zone\n"
                     "  -D, --dividers  Print dividers between each log buffer\n"
                     "  -c, --clear     Clear (flush) the entire log and exit\n"
                     "                  if Log to File specified, clear fileset instead\n"
@@ -353,6 +363,40 @@
                    "or defaults to \"threadtime\"\n\n");
 }
 
+static void show_format_help()
+{
+    fprintf(stderr,
+        "-v <format>, --format=<format> options:\n"
+        "  Sets log print format verb and adverbs, where <format> is:\n"
+        "    brief long process raw tag thread threadtime time\n"
+        "  and individually flagged modifying adverbs can be added:\n"
+        "    color descriptive epoch monotonic printable uid usec UTC year zone\n"
+        "\nSingle format verbs:\n"
+        "  brief      — Display priority/tag and PID of the process issuing the message.\n"
+        "  long       — Display all metadata fields, separate messages with blank lines.\n"
+        "  process    — Display PID only.\n"
+        "  raw        — Display the raw log message, with no other metadata fields.\n"
+        "  tag        — Display the priority/tag only.\n"
+        "  threadtime — Display the date, invocation time, priority, tag, and the PID\n"
+        "               and TID of the thread issuing the message. (the default format).\n"
+        "  time       — Display the date, invocation time, priority/tag, and PID of the\n"
+        "             process issuing the message.\n"
+        "\nAdverb modifiers can be used in combination:\n"
+        "  color       — Display in highlighted color to match priority. i.e. \x1B[38;5;231mVERBOSE\n"
+        "                \x1B[38;5;75mDEBUG \x1B[38;5;40mINFO \x1B[38;5;166mWARNING \x1B[38;5;196mERROR FATAL\x1B[0m\n"
+        "  descriptive — events logs only, descriptions from event-log-tags database.\n"
+        "  epoch       — Display time as seconds since Jan 1 1970.\n"
+        "  monotonic   — Display time as cpu seconds since last boot.\n"
+        "  printable   — Ensure that any binary logging content is escaped.\n"
+        "  uid         — If permitted, display the UID or Android ID of logged process.\n"
+        "  usec        — Display time down the microsecond precision.\n"
+        "  UTC         — Display time as UTC.\n"
+        "  year        — Add the year to the displayed time.\n"
+        "  zone        — Add the local timezone to the displayed time.\n"
+        "  \"<zone>\"    — Print using this public named timezone (experimental).\n\n"
+    );
+}
+
 static int setLogFormat(const char * formatString)
 {
     static AndroidLogPrintFormat format;
@@ -392,7 +436,7 @@
 }
 
 /*String to unsigned int, returns -1 if it fails*/
-static bool getSizeTArg(char *ptr, size_t *val, size_t min = 0,
+static bool getSizeTArg(const char *ptr, size_t *val, size_t min = 0,
                         size_t max = SIZE_MAX)
 {
     if (!ptr) {
@@ -415,15 +459,23 @@
     return true;
 }
 
-static void logcat_panic(bool showHelp, const char *fmt, ...)
+static void logcat_panic(enum helpType showHelp, const char *fmt, ...)
 {
     va_list  args;
     va_start(args, fmt);
     vfprintf(stderr, fmt,  args);
     va_end(args);
 
-    if (showHelp) {
+    switch (showHelp) {
+    case HELP_TRUE:
        show_help(getprogname());
+       break;
+    case HELP_FORMAT:
+       show_format_help();
+       break;
+    case HELP_FALSE:
+    default:
+      break;
     }
 
     exit(EXIT_FAILURE);
@@ -442,7 +494,7 @@
     return t.strptime(cp, "%s.%q");
 }
 
-// Find last logged line in gestalt of all matching existing output files
+// Find last logged line in <outputFileName>, or <outputFileName>.1
 static log_time lastLogTime(char *outputFileName) {
     log_time retval(log_time::EPOCH);
     if (!outputFileName) {
@@ -467,24 +519,18 @@
         return retval;
     }
 
-    clockid_t clock_type = android_log_clockid();
-    log_time now(clock_type);
-    bool monotonic = clock_type == CLOCK_MONOTONIC;
+    log_time now(android_log_clockid());
 
     size_t len = strlen(file);
     log_time modulo(0, NS_PER_SEC);
     struct dirent *dp;
 
     while ((dp = readdir(dir.get())) != NULL) {
-        if ((dp->d_type != DT_REG)
-                // If we are using realtime, check all files that match the
-                // basename for latest time. If we are using monotonic time
-                // then only check the main file because time cycles on
-                // every reboot.
-                || strncmp(dp->d_name, file, len + monotonic)
-                || (dp->d_name[len]
-                    && ((dp->d_name[len] != '.')
-                        || !isdigit(dp->d_name[len+1])))) {
+        if ((dp->d_type != DT_REG) ||
+                (strncmp(dp->d_name, file, len) != 0) ||
+                (dp->d_name[len] &&
+                     ((dp->d_name[len] != '.') ||
+                         (strtoll(dp->d_name + 1, NULL, 10) != 1)))) {
             continue;
         }
 
@@ -546,6 +592,7 @@
     unsigned long setLogSize = 0;
     int getPruneList = 0;
     char *setPruneList = NULL;
+    char *setId = NULL;
     int printStatistics = 0;
     int mode = ANDROID_LOG_RDONLY;
     const char *forceFilters = NULL;
@@ -573,6 +620,8 @@
         int option_index = 0;
         // list of long-argument only strings for later comparison
         static const char pid_str[] = "pid";
+        static const char debug_str[] = "debug";
+        static const char id_str[] = "id";
         static const char wrap_str[] = "wrap";
         static const char print_str[] = "print";
         static const struct option long_options[] = {
@@ -580,6 +629,7 @@
           { "buffer",        required_argument, NULL,   'b' },
           { "buffer-size",   optional_argument, NULL,   'g' },
           { "clear",         no_argument,       NULL,   'c' },
+          { debug_str,       no_argument,       NULL,   0 },
           { "dividers",      no_argument,       NULL,   'D' },
           { "file",          required_argument, NULL,   'f' },
           { "format",        required_argument, NULL,   'v' },
@@ -587,6 +637,7 @@
           { "grep",          required_argument, NULL,   'e' },
           // hidden and undocumented reserved alias for --max-count
           { "head",          required_argument, NULL,   'm' },
+          { id_str,          required_argument, NULL,   0 },
           { "last",          no_argument,       NULL,   'L' },
           { "max-count",     required_argument, NULL,   'm' },
           { pid_str,         required_argument, NULL,   0 },
@@ -612,11 +663,11 @@
 
         switch (ret) {
             case 0:
-                // One of the long options
+                // only long options
                 if (long_options[option_index].name == pid_str) {
                     // ToDo: determine runtime PID_MAX?
                     if (!getSizeTArg(optarg, &pid, 1)) {
-                        logcat_panic(true, "%s %s out of range\n",
+                        logcat_panic(HELP_TRUE, "%s %s out of range\n",
                                      long_options[option_index].name, optarg);
                     }
                     break;
@@ -628,7 +679,7 @@
                     // ToDo: implement API that supports setting a wrap timeout
                     size_t dummy = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
                     if (optarg && !getSizeTArg(optarg, &dummy, 1)) {
-                        logcat_panic(true, "%s %s out of range\n",
+                        logcat_panic(HELP_TRUE, "%s %s out of range\n",
                                      long_options[option_index].name, optarg);
                     }
                     if (dummy != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) {
@@ -643,6 +694,14 @@
                     g_printItAnyways = true;
                     break;
                 }
+                if (long_options[option_index].name == debug_str) {
+                    g_debug = true;
+                    break;
+                }
+                if (long_options[option_index].name == id_str) {
+                    setId = optarg && optarg[0] ? optarg : NULL;
+                    break;
+                }
             break;
 
             case 's':
@@ -656,7 +715,7 @@
             break;
 
             case 'L':
-                mode |= ANDROID_LOG_PSTORE;
+                mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK;
             break;
 
             case 'd':
@@ -671,7 +730,8 @@
                 if (strspn(optarg, "0123456789") != strlen(optarg)) {
                     char *cp = parseTime(tail_time, optarg);
                     if (!cp) {
-                        logcat_panic(false, "-%c \"%s\" not in time format\n",
+                        logcat_panic(HELP_FALSE,
+                                     "-%c \"%s\" not in time format\n",
                                      ret, optarg);
                     }
                     if (*cp) {
@@ -703,7 +763,7 @@
             case 'm': {
                 char *end = NULL;
                 if (!getSizeTArg(optarg, &g_maxCount)) {
-                    logcat_panic(false, "-%c \"%s\" isn't an "
+                    logcat_panic(HELP_FALSE, "-%c \"%s\" isn't an "
                                  "integer greater than zero\n", ret, optarg);
                 }
             }
@@ -776,7 +836,8 @@
                         const char *name = android_log_id_to_name(log_id);
 
                         if (strcmp(name, optarg) != 0) {
-                            logcat_panic(true, "unknown buffer %s\n", optarg);
+                            logcat_panic(HELP_TRUE,
+                                         "unknown buffer %s\n", optarg);
                         }
                         idMask |= (1 << log_id);
                     }
@@ -837,20 +898,27 @@
 
             case 'r':
                 if (!getSizeTArg(optarg, &g_logRotateSizeKBytes, 1)) {
-                    logcat_panic(true, "Invalid parameter %s to -r\n", optarg);
+                    logcat_panic(HELP_TRUE,
+                                 "Invalid parameter \"%s\" to -r\n", optarg);
                 }
             break;
 
             case 'n':
                 if (!getSizeTArg(optarg, &g_maxRotatedLogs, 1)) {
-                    logcat_panic(true, "Invalid parameter %s to -n\n", optarg);
+                    logcat_panic(HELP_TRUE,
+                                 "Invalid parameter \"%s\" to -n\n", optarg);
                 }
             break;
 
             case 'v':
-                err = setLogFormat (optarg);
+                if (!strcmp(optarg, "help") || !strcmp(optarg, "--help")) {
+                    show_format_help();
+                    exit(0);
+                }
+                err = setLogFormat(optarg);
                 if (err < 0) {
-                    logcat_panic(true, "Invalid parameter %s to -v\n", optarg);
+                    logcat_panic(HELP_FORMAT,
+                                 "Invalid parameter \"%s\" to -v\n", optarg);
                 }
                 hasSetLogFormat |= err;
             break;
@@ -928,17 +996,20 @@
                 break;
 
             case ':':
-                logcat_panic(true, "Option -%c needs an argument\n", optopt);
+                logcat_panic(HELP_TRUE,
+                             "Option -%c needs an argument\n", optopt);
                 break;
 
             default:
-                logcat_panic(true, "Unrecognized Option %c\n", optopt);
+                logcat_panic(HELP_TRUE,
+                             "Unrecognized Option %c\n", optopt);
                 break;
         }
     }
 
     if (g_maxCount && got_t) {
-        logcat_panic(true, "Cannot use -m (--max-count) and -t together\n");
+        logcat_panic(HELP_TRUE,
+                     "Cannot use -m (--max-count) and -t together\n");
     }
     if (g_printItAnyways && (!g_regex || !g_maxCount)) {
         // One day it would be nice if --print -v color and --regex <expr>
@@ -964,10 +1035,23 @@
     }
 
     if (g_logRotateSizeKBytes != 0 && g_outputFileName == NULL) {
-        logcat_panic(true, "-r requires -f as well\n");
+        logcat_panic(HELP_TRUE, "-r requires -f as well\n");
     }
 
-    setupOutput();
+    if (setId != NULL) {
+        if (g_outputFileName == NULL) {
+            logcat_panic(HELP_TRUE, "--id='%s' requires -f as well\n", setId);
+        }
+
+        std::string file_name = android::base::StringPrintf("%s.id", g_outputFileName);
+        std::string file;
+        bool file_ok = android::base::ReadFileToString(file_name, &file);
+        android::base::WriteStringToFile(setId, file_name,
+                                         S_IRUSR | S_IWUSR, getuid(), getgid());
+        if (!file_ok || (file.compare(setId) == 0)) {
+            setId = NULL;
+        }
+    }
 
     if (hasSetLogFormat == 0) {
         const char* logFormat = getenv("ANDROID_PRINTF_LOG");
@@ -986,7 +1070,8 @@
     if (forceFilters) {
         err = android_log_addFilterString(g_logformat, forceFilters);
         if (err < 0) {
-            logcat_panic(false, "Invalid filter expression in logcat args\n");
+            logcat_panic(HELP_FALSE,
+                         "Invalid filter expression in logcat args\n");
         }
     } else if (argc == optind) {
         // Add from environment variable
@@ -996,7 +1081,7 @@
             err = android_log_addFilterString(g_logformat, env_tags_orig);
 
             if (err < 0) {
-                logcat_panic(true,
+                logcat_panic(HELP_TRUE,
                             "Invalid filter expression in ANDROID_LOG_TAGS\n");
             }
         }
@@ -1006,7 +1091,8 @@
             err = android_log_addFilterString(g_logformat, argv[i]);
 
             if (err < 0) {
-                logcat_panic(true, "Invalid filter expression '%s'\n", argv[i]);
+                logcat_panic(HELP_TRUE,
+                             "Invalid filter expression '%s'\n", argv[i]);
             }
         }
     }
@@ -1033,34 +1119,33 @@
             continue;
         }
 
-        if (clearLog) {
+        if (clearLog || setId) {
             if (g_outputFileName) {
                 int maxRotationCountDigits =
                     (g_maxRotatedLogs > 0) ? (int) (floor(log10(g_maxRotatedLogs) + 1)) : 0;
 
                 for (int i = g_maxRotatedLogs ; i >= 0 ; --i) {
-                    char *file;
+                    std::string file;
 
                     if (i == 0) {
-                        asprintf(&file, "%s", g_outputFileName);
+                        file = android::base::StringPrintf("%s", g_outputFileName);
                     } else {
-                        asprintf(&file, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i);
+                        file = android::base::StringPrintf("%s.%.*d",
+                            g_outputFileName, maxRotationCountDigits, i);
                     }
 
-                    if (!file) {
+                    if (file.length() == 0) {
                         perror("while clearing log files");
                         clearFail = clearFail ?: dev->device;
                         break;
                     }
 
-                    err = unlink(file);
+                    err = unlink(file.c_str());
 
                     if (err < 0 && errno != ENOENT && clearFail == NULL) {
                         perror("while clearing log files");
                         clearFail = dev->device;
                     }
-
-                    free(file);
                 }
             } else if (android_logger_clear(dev->logger)) {
                 clearFail = clearFail ?: dev->device;
@@ -1093,17 +1178,20 @@
     }
     // report any errors in the above loop and exit
     if (openDeviceFail) {
-        logcat_panic(false, "Unable to open log device '%s'\n", openDeviceFail);
+        logcat_panic(HELP_FALSE,
+                     "Unable to open log device '%s'\n", openDeviceFail);
     }
     if (clearFail) {
-        logcat_panic(false, "failed to clear the '%s' log\n", clearFail);
+        logcat_panic(HELP_FALSE,
+                     "failed to clear the '%s' log\n", clearFail);
     }
     if (setSizeFail) {
-        logcat_panic(false, "failed to set the '%s' log size\n", setSizeFail);
+        logcat_panic(HELP_FALSE,
+                     "failed to set the '%s' log size\n", setSizeFail);
     }
     if (getSizeFail) {
-        logcat_panic(false, "failed to get the readable '%s' log size",
-                     getSizeFail);
+        logcat_panic(HELP_FALSE,
+                     "failed to get the readable '%s' log size", getSizeFail);
     }
 
     if (setPruneList) {
@@ -1114,11 +1202,11 @@
         if (asprintf(&buf, "%-*s", (int)(bLen - 1), setPruneList) > 0) {
             buf[len] = '\0';
             if (android_logger_set_prune_list(logger_list, buf, bLen)) {
-                logcat_panic(false, "failed to set the prune list");
+                logcat_panic(HELP_FALSE, "failed to set the prune list");
             }
             free(buf);
         } else {
-            logcat_panic(false, "failed to set the prune list (alloc)");
+            logcat_panic(HELP_FALSE, "failed to set the prune list (alloc)");
         }
     }
 
@@ -1149,7 +1237,7 @@
         }
 
         if (!buf) {
-            logcat_panic(false, "failed to read data");
+            logcat_panic(HELP_FALSE, "failed to read data");
         }
 
         // remove trailing FF
@@ -1176,7 +1264,6 @@
         return EXIT_SUCCESS;
     }
 
-
     if (getLogSize) {
         return EXIT_SUCCESS;
     }
@@ -1187,6 +1274,8 @@
         return EXIT_SUCCESS;
     }
 
+    setupOutputAndSchedulingPolicy((mode & ANDROID_LOG_NONBLOCK) == 0);
+
     //LOG_EVENT_INT(10, 12345);
     //LOG_EVENT_LONG(11, 0x1122334455667788LL);
     //LOG_EVENT_STRING(0, "whassup, doc?");
@@ -1200,7 +1289,7 @@
         int ret = android_logger_list_read(logger_list, &log_msg);
 
         if (ret == 0) {
-            logcat_panic(false, "read: unexpected EOF!\n");
+            logcat_panic(HELP_FALSE, "read: unexpected EOF!\n");
         }
 
         if (ret < 0) {
@@ -1209,12 +1298,12 @@
             }
 
             if (ret == -EIO) {
-                logcat_panic(false, "read: unexpected EOF!\n");
+                logcat_panic(HELP_FALSE, "read: unexpected EOF!\n");
             }
             if (ret == -EINVAL) {
-                logcat_panic(false, "read: unexpected length.\n");
+                logcat_panic(HELP_FALSE, "read: unexpected length.\n");
             }
-            logcat_panic(false, "logcat read failure");
+            logcat_panic(HELP_FALSE, "logcat read failure");
         }
 
         for (d = devices; d; d = d->next) {
diff --git a/logcat/logcatd.rc b/logcat/logcatd.rc
index 4d5c80c..b082a64 100644
--- a/logcat/logcatd.rc
+++ b/logcat/logcatd.rc
@@ -36,7 +36,7 @@
     mkdir /data/misc/logd 0700 logd log
     # logd for write to /data/misc/logd, log group for read from pstore (-L)
     # b/28788401 b/30041146 b/30612424
-    # exec - logd log -- /system/bin/logcat -L -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256}
+    # exec - logd log -- /system/bin/logcat -L -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256} --id=${ro.build.id}
     start logcatd
 
 # stop logcatd service and clear data
@@ -57,7 +57,7 @@
     stop logcatd
 
 # logcatd service
-service logcatd /system/bin/logcat -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256}
+service logcatd /system/bin/logcat -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256} --id=${ro.build.id}
     class late_start
     disabled
     # logd for write to /data/misc/logd, log group for read from log daemon
diff --git a/logcat/logpersist b/logcat/logpersist
index a0e27ce..c09b6b2 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
    ;;
@@ -17,7 +17,9 @@
    ;;
 esac
 
-data=/data/misc/logd
+log_uid=logd
+log_tag_property=persist.log.tag
+data=/data/misc/logd/logcat
 service=logcatd
 size_default=256
 buffer_default=all
@@ -36,7 +38,7 @@
     -b|--buffer) buffer="${2}" ; shift ;;
     -h|--help|*)
       LEAD_SPACE_="`echo ${progname%.*} | tr '[ -~]' ' '`"
-      echo "${progname%.*}.cat             - dump current ${service%d} logs"
+      echo "${progname%.*}.cat             - dump current ${service} logs"
       echo "${progname%.*}.start [--size=<size_in_kb>] [--buffer=<buffers>] [--clear]"
       echo "${LEAD_SPACE_}                 - start ${service} service"
       echo "${progname%.*}.stop [--clear]  - stop ${service} service"
@@ -65,16 +67,20 @@
   exit 1
 fi
 
+log_tag="`getprop ${log_tag_property}`"
+logd_logpersistd="`getprop ${property}`"
+
 case ${progname} in
 *.cat)
   if [ -n "${size}${buffer}" -o "true" = "${clear}" ]; then
     echo WARNING: Can not use --clear, --size or --buffer with ${progname%.*}.cat >&2
   fi
-  su logd ls "${data}" |
+  su ${log_uid} ls "${data%/*}" |
   tr -d '\r' |
   sort -ru |
-  sed "s#^#${data}/#" |
-  su logd xargs cat
+  sed "s#^#${data%/*}/#" |
+  grep "${data}[.]*[0-9]*\$" |
+  su ${log_uid} xargs cat
   ;;
 *.start)
   current_buffer="`getprop ${property#persist.}.buffer`"
@@ -123,13 +129,19 @@
   while [ "clear" = "`getprop ${property#persist.}`" ]; do
     continue
   done
+  # Tell Settings that we are back on again if we turned logging off
+  tag="${log_tag#Settings}"
+  if [ X"${log_tag}" != X"${tag}" ]; then
+    echo "WARNING: enabling logd service" >&2
+    setprop ${log_tag_property} "${tag#,}"
+  fi
   # ${service}.rc does the heavy lifting with the following trigger
   setprop ${property} ${service}
   # 20ms done, to permit process feedback check
   sleep 1
   getprop ${property#persist.}
-  # also generate an error return code if not found running, bonus
-  ps -t | grep "${data##*/}.*${service%d}"
+  # also generate an error return code if not found running
+  pgrep -u ${log_uid} ${service%d}
   ;;
 *.stop)
   if [ -n "${size}${buffer}" ]; then
@@ -158,3 +170,9 @@
   echo "ERROR: Unexpected command ${0##*/} ${args}" >&2
   exit 1
 esac
+
+if [ X"${log_tag}" != X"`getprop ${log_tag_property}`" ] ||
+   [ X"${logd_logpersistd}" != X"`getprop ${property}`" ]; then
+  echo "WARNING: killing Settings application to pull in new values" >&2
+  am force-stop com.android.settings
+fi
diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk
index a28664e..99c2e0a 100644
--- a/logcat/tests/Android.mk
+++ b/logcat/tests/Android.mk
@@ -25,7 +25,6 @@
     -Wall -Wextra \
     -Werror \
     -fno-builtin \
-    -std=gnu++11
 
 # -----------------------------------------------------------------------------
 # Benchmarks (actually a gTest where the result code does not matter)
diff --git a/logcat/tests/logcat_benchmark.cpp b/logcat/tests/logcat_benchmark.cpp
index be815be..dd85164 100644
--- a/logcat/tests/logcat_benchmark.cpp
+++ b/logcat/tests/logcat_benchmark.cpp
@@ -49,7 +49,7 @@
             }
         }
 
-        timestamp(const char *buffer)
+        explicit timestamp(const char *buffer)
         {
             init(buffer);
         }
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index d79fc08..11cffe6 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -20,13 +20,16 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 
+#include <memory>
+#include <string>
+
 #include <gtest/gtest.h>
 #include <log/log.h>
-#include <log/logger.h>
-#include <log/log_read.h>
+#include <log/log_event_list.h>
 
 #define BIG_BUFFER (5 * 1024)
 
@@ -77,6 +80,26 @@
     EXPECT_EQ(4, count);
 }
 
+TEST(logcat, event_tag_filter) {
+    FILE *fp;
+
+    ASSERT_TRUE(NULL != (fp = popen(
+      "logcat -b events -d -s auditd am_proc_start am_pss am_proc_bound dvm_lock_sample am_wtf 2>/dev/null",
+      "r")));
+
+    char buffer[BIG_BUFFER];
+
+    int count = 0;
+
+    while (fgets(buffer, sizeof(buffer), fp)) {
+        ++count;
+    }
+
+    pclose(fp);
+
+    EXPECT_LT(4, count);
+}
+
 TEST(logcat, year) {
 
     if (android_log_clockid() == CLOCK_MONOTONIC) {
@@ -568,6 +591,14 @@
     EXPECT_EQ(1, signals);
 }
 
+// meant to be handed to ASSERT_FALSE / EXPECT_FALSE to expand the message
+static testing::AssertionResult IsFalse(int ret, const char* command) {
+    return ret ?
+        (testing::AssertionSuccess() <<
+            "ret=" << ret << " command=\"" << command << "\"") :
+        testing::AssertionFailure();
+}
+
 TEST(logcat, logrotate) {
     static const char form[] = "/data/local/tmp/logcat.logrotate.XXXXXX";
     char buf[sizeof(form)];
@@ -579,7 +610,7 @@
     snprintf(command, sizeof(command), comm, buf);
 
     int ret;
-    EXPECT_FALSE((ret = system(command)));
+    EXPECT_FALSE(IsFalse(ret = system(command), command));
     if (!ret) {
         snprintf(command, sizeof(command), "ls -s %s 2>/dev/null", buf);
 
@@ -609,7 +640,7 @@
         }
     }
     snprintf(command, sizeof(command), "rm -rf %s", buf);
-    EXPECT_FALSE(system(command));
+    EXPECT_FALSE(IsFalse(system(command), command));
 }
 
 TEST(logcat, logrotate_suffix) {
@@ -623,7 +654,7 @@
     snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir);
 
     int ret;
-    EXPECT_FALSE((ret = system(command)));
+    EXPECT_FALSE(IsFalse(ret = system(command), command));
     if (!ret) {
         snprintf(command, sizeof(command), "ls %s 2>/dev/null", tmp_out_dir);
 
@@ -662,7 +693,7 @@
         EXPECT_EQ(11, log_file_count);
     }
     snprintf(command, sizeof(command), "rm -rf %s", tmp_out_dir);
-    EXPECT_FALSE(system(command));
+    EXPECT_FALSE(IsFalse(system(command), command));
 }
 
 TEST(logcat, logrotate_continue) {
@@ -677,10 +708,10 @@
     snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename);
 
     int ret;
-    EXPECT_FALSE((ret = system(command)));
+    EXPECT_FALSE(IsFalse(ret = system(command), command));
     if (ret) {
         snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
-        EXPECT_FALSE(system(command));
+        EXPECT_FALSE(IsFalse(system(command), command));
         return;
     }
     FILE *fp;
@@ -688,7 +719,7 @@
     EXPECT_TRUE(NULL != ((fp = fopen(command, "r"))));
     if (!fp) {
         snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
-        EXPECT_FALSE(system(command));
+        EXPECT_FALSE(IsFalse(system(command), command));
         return;
     }
     char *line = NULL;
@@ -712,28 +743,28 @@
     EXPECT_TRUE(NULL != second_last_line);
     if (!second_last_line) {
         snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
-        EXPECT_FALSE(system(command));
+        EXPECT_FALSE(IsFalse(system(command), command));
         return;
     }
     // re-run the command, it should only add a few lines more content if it
     // continues where it left off.
     snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename);
-    EXPECT_FALSE((ret = system(command)));
+    EXPECT_FALSE(IsFalse(ret = system(command), command));
     if (ret) {
         snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
-        EXPECT_FALSE(system(command));
+        EXPECT_FALSE(IsFalse(system(command), command));
         return;
     }
-    DIR *dir;
-    EXPECT_TRUE(NULL != (dir = opendir(tmp_out_dir)));
+    std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir);
+    EXPECT_NE(nullptr, dir);
     if (!dir) {
         snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
-        EXPECT_FALSE(system(command));
+        EXPECT_FALSE(IsFalse(system(command), command));
         return;
     }
     struct dirent *entry;
     unsigned count = 0;
-    while ((entry = readdir(dir))) {
+    while ((entry = readdir(dir.get()))) {
         if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
             continue;
         }
@@ -756,7 +787,6 @@
         free(line);
         unlink(command);
     }
-    closedir(dir);
     if (count > 1) {
         char *brk = strpbrk(second_last_line, "\r\n");
         if (!brk) {
@@ -768,7 +798,7 @@
     free(second_last_line);
 
     snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
-    EXPECT_FALSE(system(command));
+    EXPECT_FALSE(IsFalse(system(command), command));
 }
 
 TEST(logcat, logrotate_clear) {
@@ -789,17 +819,17 @@
                  logcat_cmd, tmp_out_dir, log_filename, num_val);
 
         int ret;
-        EXPECT_FALSE((ret = system(command)));
+        EXPECT_FALSE(IsFalse(ret = system(command), command));
         if (ret) {
             snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
-            EXPECT_FALSE(system(command));
+            EXPECT_FALSE(IsFalse(system(command), command));
             return;
         }
         std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir);
         EXPECT_NE(nullptr, dir);
         if (!dir) {
             snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
-            EXPECT_FALSE(system(command));
+            EXPECT_FALSE(IsFalse(system(command), command));
             return;
         }
         struct dirent *entry;
@@ -818,17 +848,18 @@
         strcat(command, clear_cmd);
 
         int ret;
-        EXPECT_FALSE((ret = system(command)));
+        EXPECT_FALSE(IsFalse(ret = system(command), command));
         if (ret) {
             snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
             EXPECT_FALSE(system(command));
+            EXPECT_FALSE(IsFalse(system(command), command));
             return;
         }
         std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir);
         EXPECT_NE(nullptr, dir);
         if (!dir) {
             snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
-            EXPECT_FALSE(system(command));
+            EXPECT_FALSE(IsFalse(system(command), command));
             return;
         }
         struct dirent *entry;
@@ -844,7 +875,76 @@
     }
 
     snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
-    EXPECT_FALSE(system(command));
+    EXPECT_FALSE(IsFalse(system(command), command));
+}
+
+static int logrotate_count_id(const char *logcat_cmd, const char *tmp_out_dir) {
+
+    static const char log_filename[] = "log.txt";
+    char command[strlen(tmp_out_dir) + strlen(logcat_cmd) + strlen(log_filename) + 32];
+
+    snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename);
+
+    int ret;
+    EXPECT_FALSE(IsFalse(ret = system(command), command));
+    if (ret) {
+        return -1;
+    }
+    std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir);
+    EXPECT_NE(nullptr, dir);
+    if (!dir) {
+        return -1;
+    }
+    struct dirent *entry;
+    int count = 0;
+    while ((entry = readdir(dir.get()))) {
+        if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
+            continue;
+        }
+        ++count;
+    }
+    return count;
+}
+
+TEST(logcat, logrotate_id) {
+    static const char logcat_cmd[] = "logcat -b all -d -f %s/%s -n 32 -r 1 --id=test";
+    static const char logcat_short_cmd[] = "logcat -b all -t 10 -f %s/%s -n 32 -r 1 --id=test";
+    static const char tmp_out_dir_form[] = "/data/local/tmp/logcat.logrotate.XXXXXX";
+    static const char log_filename[] = "log.txt";
+    char tmp_out_dir[strlen(tmp_out_dir_form) + 1];
+    ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form)));
+
+    EXPECT_EQ(34, logrotate_count_id(logcat_cmd, tmp_out_dir));
+    EXPECT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir));
+
+    char id_file[strlen(tmp_out_dir_form) + strlen(log_filename) + 5];
+    snprintf(id_file, sizeof(id_file), "%s/%s.id", tmp_out_dir, log_filename);
+    if (getuid() != 0) {
+        chmod(id_file, 0);
+        EXPECT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir));
+    }
+    unlink(id_file);
+    EXPECT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir));
+
+    FILE *fp = fopen(id_file, "w");
+    if (fp) {
+        fprintf(fp, "not_a_test");
+        fclose(fp);
+    }
+    if (getuid() != 0) {
+        chmod(id_file, 0); // API to preserve content even with signature change
+        ASSERT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir));
+        chmod(id_file, 0600);
+    }
+
+    int new_signature;
+    EXPECT_LE(2, (new_signature = logrotate_count_id(logcat_short_cmd, tmp_out_dir)));
+    EXPECT_GT(34, new_signature);
+
+    static const char cleanup_cmd[] = "rm -rf %s";
+    char command[strlen(cleanup_cmd) + strlen(tmp_out_dir_form)];
+    snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
+    EXPECT_FALSE(IsFalse(system(command), command));
 }
 
 TEST(logcat, logrotate_nodir) {
@@ -876,12 +976,14 @@
     ASSERT_TRUE(NULL != (fp = popen(
       "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
       " logcat -b events -c 2>&1 ;"
+      " logcat -b events -g 2>&1 ;"
       " logcat -v brief -b events 2>&1",
       "r")));
 
     char buffer[BIG_BUFFER];
 
     int count = 0;
+    int minus_g = 0;
 
     int signals = 0;
 
@@ -899,6 +1001,50 @@
             break;
         }
 
+        int size, consumed, max, payload;
+        char size_mult[3], consumed_mult[3];
+        size = consumed = max = payload = 0;
+        if (6 == sscanf(buffer, "events: ring buffer is %d%2s (%d%2s consumed),"
+                                " max entry is %db, max payload is %db",
+                                &size, size_mult, &consumed, consumed_mult,
+                                &max, &payload)) {
+            long full_size = size, full_consumed = consumed;
+
+            switch(size_mult[0]) {
+            case 'G':
+                full_size *= 1024;
+                /* FALLTHRU */
+            case 'M':
+                full_size *= 1024;
+                /* FALLTHRU */
+            case 'K':
+                full_size *= 1024;
+                /* FALLTHRU */
+            case 'b':
+                break;
+            }
+            switch(consumed_mult[0]) {
+            case 'G':
+                full_consumed *= 1024;
+                /* FALLTHRU */
+            case 'M':
+                full_consumed *= 1024;
+                /* FALLTHRU */
+            case 'K':
+                full_consumed *= 1024;
+                /* FALLTHRU */
+            case 'b':
+                break;
+            }
+            EXPECT_GT(full_size, full_consumed);
+            EXPECT_GT(full_size, max);
+            EXPECT_GT(max, payload);
+            EXPECT_GT(max, full_consumed);
+
+            ++minus_g;
+            continue;
+        }
+
         ++count;
 
         int p;
@@ -927,6 +1073,7 @@
     pclose(fp);
 
     EXPECT_LE(1, count);
+    EXPECT_EQ(1, minus_g);
 
     EXPECT_EQ(1, signals);
 }
@@ -945,7 +1092,7 @@
     while (fgets(buffer, sizeof(buffer), fp)) {
         char *hold = *list;
         char *buf = buffer;
-	while (isspace(*buf)) {
+        while (isspace(*buf)) {
             ++buf;
         }
         char *end = buf + strlen(buf);
@@ -980,7 +1127,7 @@
 
     while (fgets(buffer, sizeof(buffer), fp)) {
         char *buf = buffer;
-	while (isspace(*buf)) {
+        while (isspace(*buf)) {
             ++buf;
         }
         char *end = buf + strlen(buf);
@@ -1090,3 +1237,175 @@
 
     ASSERT_EQ(3, count);
 }
+
+static bool End_to_End(const char* tag, const char* fmt, ...)
+#if defined(__GNUC__)
+    __attribute__((__format__(printf, 2, 3)))
+#endif
+    ;
+
+static bool End_to_End(const char* tag, const char* fmt, ...) {
+    FILE *fp = popen("logcat -v brief -b events -v descriptive -t 100 2>/dev/null", "r");
+    if (!fp) return false;
+
+    char buffer[BIG_BUFFER];
+    va_list ap;
+
+    va_start(ap, fmt);
+    vsnprintf(buffer, sizeof(buffer), fmt, ap);
+    va_end(ap);
+
+    char *str = NULL;
+    asprintf(&str, "I/%s ( %%d):%%c%s%%c", tag, buffer);
+    std::string expect(str);
+    free(str);
+
+    int count = 0;
+    pid_t pid = getpid();
+    std::string lastMatch;
+    int maxMatch = 1;
+    while (fgets(buffer, sizeof(buffer), fp)) {
+        char space;
+        char newline;
+        int p;
+        int ret = sscanf(buffer, expect.c_str(), &p, &space, &newline);
+        if ((ret == 3) && (p == pid) && (space == ' ') && (newline == '\n')) {
+            ++count;
+        } else if ((ret >= maxMatch) && (p == pid) && (count == 0)) {
+            lastMatch = buffer;
+            maxMatch = ret;
+        }
+    }
+
+    pclose(fp);
+
+    if ((count == 0) && (lastMatch.length() > 0)) {
+        // Help us pinpoint where things went wrong ...
+        fprintf(stderr, "Closest match for\n    %s\n  is\n    %s",
+                expect.c_str(), lastMatch.c_str());
+    }
+
+    return count == 1;
+}
+
+TEST(logcat, descriptive) {
+    struct tag {
+        uint32_t tagNo;
+        const char* tagStr;
+    };
+
+    {
+        static const struct tag hhgtg = { 42, "answer" };
+        android_log_event_list ctx(hhgtg.tagNo);
+        static const char theAnswer[] = "what is five by seven";
+        ctx << theAnswer;
+        ctx.write();
+        EXPECT_TRUE(End_to_End(hhgtg.tagStr,
+                               "to life the universe etc=%s", theAnswer));
+    }
+
+    {
+        static const struct tag sync = { 2720, "sync" };
+        static const char id[] = "logcat.decriptive";
+        {
+            android_log_event_list ctx(sync.tagNo);
+            ctx << id << (int32_t)42 << (int32_t)-1 << (int32_t)0;
+            ctx.write();
+            EXPECT_TRUE(End_to_End(sync.tagStr,
+                                   "[id=%s,event=42,source=-1,account=0]",
+                                   id));
+        }
+
+        // Partial match to description
+        {
+            android_log_event_list ctx(sync.tagNo);
+            ctx << id << (int32_t)43 << (int64_t)-1 << (int32_t)0;
+            ctx.write();
+            EXPECT_TRUE(End_to_End(sync.tagStr,
+                                   "[id=%s,event=43,-1,0]",
+                                   id));
+        }
+
+        // Negative Test of End_to_End, ensure it is working
+        {
+            android_log_event_list ctx(sync.tagNo);
+            ctx << id << (int32_t)44 << (int32_t)-1 << (int64_t)0;
+            ctx.write();
+            fprintf(stderr, "Expect a \"Closest match\" message\n");
+            EXPECT_FALSE(End_to_End(sync.tagStr,
+                                    "[id=%s,event=44,source=-1,account=0]",
+                                    id));
+        }
+    }
+
+    {
+        static const struct tag sync = { 2747, "contacts_aggregation" };
+        {
+            android_log_event_list ctx(sync.tagNo);
+            ctx << (uint64_t)30 << (int32_t)2;
+            ctx.write();
+            EXPECT_TRUE(End_to_End(sync.tagStr,
+                                   "[aggregation time=30ms,count=2]"));
+        }
+
+        {
+            android_log_event_list ctx(sync.tagNo);
+            ctx << (uint64_t)31570 << (int32_t)911;
+            ctx.write();
+            EXPECT_TRUE(End_to_End(sync.tagStr,
+                                   "[aggregation time=31.57s,count=911]"));
+        }
+    }
+
+    {
+        static const struct tag sync = { 75000, "sqlite_mem_alarm_current" };
+        {
+            android_log_event_list ctx(sync.tagNo);
+            ctx << (uint32_t)512;
+            ctx.write();
+            EXPECT_TRUE(End_to_End(sync.tagStr, "current=512B"));
+        }
+
+        {
+            android_log_event_list ctx(sync.tagNo);
+            ctx << (uint32_t)3072;
+            ctx.write();
+            EXPECT_TRUE(End_to_End(sync.tagStr, "current=3KB"));
+        }
+
+        {
+            android_log_event_list ctx(sync.tagNo);
+            ctx << (uint32_t)2097152;
+            ctx.write();
+            EXPECT_TRUE(End_to_End(sync.tagStr, "current=2MB"));
+        }
+
+        {
+            android_log_event_list ctx(sync.tagNo);
+            ctx << (uint32_t)2097153;
+            ctx.write();
+            EXPECT_TRUE(End_to_End(sync.tagStr, "current=2097153B"));
+        }
+
+        {
+            android_log_event_list ctx(sync.tagNo);
+            ctx << (uint32_t)1073741824;
+            ctx.write();
+            EXPECT_TRUE(End_to_End(sync.tagStr, "current=1GB"));
+        }
+
+        {
+            android_log_event_list ctx(sync.tagNo);
+            ctx << (uint32_t)3221225472; // 3MB, but on purpose overflowed
+            ctx.write();
+            EXPECT_TRUE(End_to_End(sync.tagStr, "current=-1GB"));
+        }
+    }
+
+    {
+        static const struct tag sync = { 27501, "notification_panel_hidden" };
+        android_log_event_list ctx(sync.tagNo);
+        ctx.write();
+        EXPECT_TRUE(End_to_End(sync.tagStr, ""));
+    }
+}
diff --git a/logd/Android.mk b/logd/Android.mk
index feca8d5..7fe48d7 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -28,7 +28,8 @@
     liblog \
     libcutils \
     libbase \
-    libpackagelistparser
+    libpackagelistparser \
+    libcap
 
 # This is what we want to do:
 #  event_logtags = $(shell \
@@ -38,7 +39,7 @@
 #  event_flag := $(call event_logtags,auditd)
 #  event_flag += $(call event_logtags,logd)
 # so make sure we do not regret hard-coding it as follows:
-event_flag := -DAUDITD_LOG_TAG=1003 -DLOGD_LOG_TAG=1004
+event_flag := -DAUDITD_LOG_TAG=1003 -DCHATTY_LOG_TAG=1004
 
 LOCAL_CFLAGS := -Werror $(event_flag)
 
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 7394f11..52c6742 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -48,6 +48,7 @@
     registerCmd(new SetPruneListCmd(buf));
     registerCmd(new GetPruneListCmd(buf));
     registerCmd(new ReinitCmd());
+    registerCmd(new ExitCmd(this));
 }
 
 CommandListener::ShutdownCmd::ShutdownCmd(LogReader *reader,
@@ -297,6 +298,21 @@
     return 0;
 }
 
+CommandListener::ExitCmd::ExitCmd(CommandListener *parent) :
+        LogCommand("EXIT"),
+        mParent(*parent) {
+}
+
+int CommandListener::ExitCmd::runCommand(SocketClient * cli,
+                                         int /*argc*/, char ** /*argv*/) {
+    setname();
+
+    cli->sendMsg("success");
+    release(cli);
+
+    return 0;
+}
+
 int CommandListener::getLogSocket() {
     static const char socketName[] = "logd";
     int sock = android_get_control_socket(socketName);
diff --git a/logd/CommandListener.h b/logd/CommandListener.h
index 3877675..5d50177 100644
--- a/logd/CommandListener.h
+++ b/logd/CommandListener.h
@@ -49,25 +49,41 @@
     class name##Cmd : public LogCommand {                        \
         LogBuffer &mBuf;                                         \
     public:                                                      \
-        name##Cmd(LogBuffer *buf);                               \
+        explicit name##Cmd(LogBuffer *buf);                      \
         virtual ~name##Cmd() {}                                  \
         int runCommand(SocketClient *c, int argc, char ** argv); \
-    };
+    }
 
-    LogBufferCmd(Clear)
-    LogBufferCmd(GetBufSize)
-    LogBufferCmd(SetBufSize)
-    LogBufferCmd(GetBufSizeUsed)
-    LogBufferCmd(GetStatistics)
-    LogBufferCmd(GetPruneList)
-    LogBufferCmd(SetPruneList)
+    LogBufferCmd(Clear);
+    LogBufferCmd(GetBufSize);
+    LogBufferCmd(SetBufSize);
+    LogBufferCmd(GetBufSizeUsed);
+    LogBufferCmd(GetStatistics);
+    LogBufferCmd(GetPruneList);
+    LogBufferCmd(SetPruneList);
 
-    class ReinitCmd : public LogCommand {
-    public:
-        ReinitCmd();
-        virtual ~ReinitCmd() {}
-        int runCommand(SocketClient *c, int argc, char ** argv);
-    };
+#define LogCmd(name)                                             \
+    class name##Cmd : public LogCommand {                        \
+    public:                                                      \
+        name##Cmd();                                             \
+        virtual ~name##Cmd() {}                                  \
+        int runCommand(SocketClient *c, int argc, char ** argv); \
+    }
+
+    LogCmd(Reinit);
+
+#define LogParentCmd(name)                                       \
+    class name##Cmd : public LogCommand {                        \
+        CommandListener &mParent;                                \
+    public:                                                      \
+        name##Cmd();                                             \
+        explicit name##Cmd(CommandListener *parent);             \
+        virtual ~name##Cmd() {}                                  \
+        int runCommand(SocketClient *c, int argc, char ** argv); \
+        void release(SocketClient *c) { mParent.release(c); }    \
+    }
+
+    LogParentCmd(Exit);
 
 };
 
diff --git a/logd/FlushCommand.h b/logd/FlushCommand.h
index 9224773..1e7818a 100644
--- a/logd/FlushCommand.h
+++ b/logd/FlushCommand.h
@@ -16,7 +16,7 @@
 #ifndef _FLUSH_COMMAND_H
 #define _FLUSH_COMMAND_H
 
-#include <log/log_read.h>
+#include <android/log.h>
 #include <sysutils/SocketClientCommand.h>
 
 class LogBufferElement;
@@ -35,7 +35,7 @@
     uint64_t mTimeout;
 
 public:
-    FlushCommand(LogReader &mReader,
+    explicit FlushCommand(LogReader &mReader,
                  bool nonBlock = false,
                  unsigned long tail = -1,
                  unsigned int logMask = -1,
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 24c3f52..c3ccd84 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -25,7 +25,7 @@
 #include <sys/uio.h>
 #include <syslog.h>
 
-#include <log/logger.h>
+#include <android-base/macros.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
@@ -102,16 +102,72 @@
         struct iovec iov[3];
         static const char log_info[] = { KMSG_PRIORITY(LOG_INFO) };
         static const char log_warning[] = { KMSG_PRIORITY(LOG_WARNING) };
+        static const char newline[] = "\n";
 
-        iov[0].iov_base = info ? const_cast<char *>(log_info)
-                               : const_cast<char *>(log_warning);
-        iov[0].iov_len = info ? sizeof(log_info) : sizeof(log_warning);
-        iov[1].iov_base = str;
-        iov[1].iov_len = strlen(str);
-        iov[2].iov_base = const_cast<char *>("\n");
-        iov[2].iov_len = 1;
+        // Dedupe messages, checking for identical messages starting with avc:
+        static unsigned count;
+        static char *last_str;
+        static bool last_info;
 
-        writev(fdDmesg, iov, sizeof(iov) / sizeof(iov[0]));
+        if (last_str != NULL) {
+            static const char avc[] = "): avc: ";
+            char *avcl = strstr(last_str, avc);
+            bool skip = false;
+
+            if (avcl) {
+                char *avcr = strstr(str, avc);
+
+                skip = avcr && !strcmp(avcl + strlen(avc), avcr + strlen(avc));
+                if (skip) {
+                    ++count;
+                    free(last_str);
+                    last_str = strdup(str);
+                    last_info = info;
+                }
+            }
+            if (!skip) {
+                static const char resume[] = " duplicate messages suppressed\n";
+
+                iov[0].iov_base = last_info ?
+                    const_cast<char *>(log_info) :
+                    const_cast<char *>(log_warning);
+                iov[0].iov_len = last_info ?
+                    sizeof(log_info) :
+                    sizeof(log_warning);
+                iov[1].iov_base = last_str;
+                iov[1].iov_len = strlen(last_str);
+                if (count > 1) {
+                    iov[2].iov_base = const_cast<char *>(resume);
+                    iov[2].iov_len = strlen(resume);
+                } else {
+                    iov[2].iov_base = const_cast<char *>(newline);
+                    iov[2].iov_len = strlen(newline);
+                }
+
+                writev(fdDmesg, iov, arraysize(iov));
+                free(last_str);
+                last_str = NULL;
+            }
+        }
+        if (last_str == NULL) {
+            count = 0;
+            last_str = strdup(str);
+            last_info = info;
+        }
+        if (count == 0) {
+            iov[0].iov_base = info ?
+                const_cast<char *>(log_info) :
+                const_cast<char *>(log_warning);
+            iov[0].iov_len = info ?
+                sizeof(log_info) :
+                sizeof(log_warning);
+            iov[1].iov_base = str;
+            iov[1].iov_len = strlen(str);
+            iov[2].iov_base = const_cast<char *>(newline);
+            iov[2].iov_len = strlen(newline);
+
+            writev(fdDmesg, iov, arraysize(iov));
+        }
     }
 
     pid_t pid = getpid();
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 79a7e8c..a009433 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -13,11 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+// for manual checking of stale entries during LogBuffer::erase()
+//#define DEBUG_CHECK_FOR_STALE_ENTRIES
 
 #include <ctype.h>
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
+#include <sys/cdefs.h>
 #include <sys/user.h>
 #include <time.h>
 #include <unistd.h>
@@ -25,114 +28,25 @@
 #include <unordered_map>
 
 #include <cutils/properties.h>
-#include <log/logger.h>
+#include <private/android_logger.h>
 
 #include "LogBuffer.h"
 #include "LogKlog.h"
 #include "LogReader.h"
 
+#ifndef __predict_false
+#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
+#endif
+
 // Default
-#define LOG_BUFFER_SIZE (256 * 1024) // Tuned with ro.logd.size per-platform
 #define log_buffer_size(id) mMaxSize[id]
-#define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
-#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
-
-static bool valid_size(unsigned long value) {
-    if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
-        return false;
-    }
-
-    long pages = sysconf(_SC_PHYS_PAGES);
-    if (pages < 1) {
-        return true;
-    }
-
-    long pagesize = sysconf(_SC_PAGESIZE);
-    if (pagesize <= 1) {
-        pagesize = PAGE_SIZE;
-    }
-
-    // maximum memory impact a somewhat arbitrary ~3%
-    pages = (pages + 31) / 32;
-    unsigned long maximum = pages * pagesize;
-
-    if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
-        return true;
-    }
-
-    return value <= maximum;
-}
-
-static unsigned long property_get_size(const char *key) {
-    char property[PROPERTY_VALUE_MAX];
-    property_get(key, property, "");
-
-    char *cp;
-    unsigned long value = strtoul(property, &cp, 10);
-
-    switch(*cp) {
-    case 'm':
-    case 'M':
-        value *= 1024;
-    /* FALLTHRU */
-    case 'k':
-    case 'K':
-        value *= 1024;
-    /* FALLTHRU */
-    case '\0':
-        break;
-
-    default:
-        value = 0;
-    }
-
-    if (!valid_size(value)) {
-        value = 0;
-    }
-
-    return value;
-}
 
 void LogBuffer::init() {
-    static const char global_tuneable[] = "persist.logd.size"; // Settings App
-    static const char global_default[] = "ro.logd.size";       // BoardConfig.mk
-
-    unsigned long default_size = property_get_size(global_tuneable);
-    if (!default_size) {
-        default_size = property_get_size(global_default);
-        if (!default_size) {
-            default_size = property_get_bool("ro.config.low_ram",
-                                             BOOL_DEFAULT_FALSE)
-                ? LOG_BUFFER_MIN_SIZE // 64K
-                : LOG_BUFFER_SIZE;    // 256K
-        }
-    }
-
     log_id_for_each(i) {
         mLastSet[i] = false;
         mLast[i] = mLogElements.begin();
 
-        char key[PROP_NAME_MAX];
-
-        snprintf(key, sizeof(key), "%s.%s",
-                 global_tuneable, android_log_id_to_name(i));
-        unsigned long property_size = property_get_size(key);
-
-        if (!property_size) {
-            snprintf(key, sizeof(key), "%s.%s",
-                     global_default, android_log_id_to_name(i));
-            property_size = property_get_size(key);
-        }
-
-        if (!property_size) {
-            property_size = default_size;
-        }
-
-        if (!property_size) {
-            property_size = LOG_BUFFER_SIZE;
-        }
-
-        if (setSize(i, property_size)) {
+        if (setSize(i, __android_logger_get_buffer_size(i))) {
             setSize(i, LOG_BUFFER_MIN_SIZE);
         }
     }
@@ -211,13 +125,15 @@
     if (log_id != LOG_ID_SECURITY) {
         int prio = ANDROID_LOG_INFO;
         const char *tag = NULL;
+        size_t len = 0;
         if (log_id == LOG_ID_EVENTS) {
-            tag = android::tagToName(elem->getTag());
+            tag = android::tagToName(&len, elem->getTag());
         } else {
             prio = *msg;
             tag = msg + 1;
+            len = strlen(tag);
         }
-        if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
+        if (!__android_log_is_loggable_len(prio, tag, len, ANDROID_LOG_VERBOSE)) {
             // Log traffic received to total
             pthread_mutex_lock(&mLogElementsLock);
             stats.add(elem);
@@ -313,17 +229,22 @@
     LogBufferElement *element = *it;
     log_id_t id = element->getLogId();
 
-    {   // start of scope for uid found iterator
-        LogBufferIteratorMap::iterator found =
-            mLastWorstUid[id].find(element->getUid());
-        if ((found != mLastWorstUid[id].end())
-                && (it == found->second)) {
-            mLastWorstUid[id].erase(found);
+    // Remove iterator references in the various lists that will become stale
+    // after the element is erased from the main logging list.
+
+    {   // start of scope for found iterator
+        int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) ?
+                element->getTag() : element->getUid();
+        LogBufferIteratorMap::iterator found = mLastWorst[id].find(key);
+        if ((found != mLastWorst[id].end()) && (it == found->second)) {
+            mLastWorst[id].erase(found);
         }
     }
 
-    if (element->getUid() == AID_SYSTEM) {
-        // start of scope for pid found iterator
+    {   // start of scope for pid found iterator
+        // element->getUid() may not be AID_SYSTEM for next-best-watermark.
+        // will not assume id != LOG_ID_EVENTS or LOG_ID_SECURITY for KISS and
+        // long term code stability, find() check should be fast for those ids.
         LogBufferPidIteratorMap::iterator found =
             mLastWorstPidOfSystem[id].find(element->getPid());
         if ((found != mLastWorstPidOfSystem[id].end())
@@ -337,18 +258,45 @@
     log_id_for_each(i) {
         doSetLast |= setLast[i] = mLastSet[i] && (it == mLast[i]);
     }
+#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
+    LogBufferElementCollection::iterator bad = it;
+    int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) ?
+            element->getTag() : element->getUid();
+#endif
     it = mLogElements.erase(it);
     if (doSetLast) {
         log_id_for_each(i) {
             if (setLast[i]) {
-                if (it == mLogElements.end()) { // unlikely
+                if (__predict_false(it == mLogElements.end())) { // impossible
                     mLastSet[i] = false;
+                    mLast[i] = mLogElements.begin();
                 } else {
-                    mLast[i] = it;
+                    mLast[i] = it; // push down the road as next-best-watermark
                 }
             }
         }
     }
+#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
+    log_id_for_each(i) {
+        for(auto b : mLastWorst[i]) {
+            if (bad == b.second) {
+                android::prdebug("stale mLastWorst[%d] key=%d mykey=%d\n",
+                                 i, b.first, key);
+            }
+        }
+        for(auto b : mLastWorstPidOfSystem[i]) {
+            if (bad == b.second) {
+                android::prdebug("stale mLastWorstPidOfSystem[%d] pid=%d\n",
+                                 i, b.first);
+            }
+        }
+        if (mLastSet[i] && (bad == mLast[i])) {
+            android::prdebug("stale mLast[%d]\n", i);
+            mLastSet[i] = false;
+            mLast[i] = mLogElements.begin();
+        }
+    }
+#endif
     if (coalesce) {
         stats.erase(element);
     } else {
@@ -380,7 +328,7 @@
             tid(tid),
             padding(0) {
     }
-    LogBufferElementKey(uint64_t key):value(key) { }
+    explicit LogBufferElementKey(uint64_t key):value(key) { }
 
     uint64_t getKey() { return value; }
 };
@@ -507,8 +455,9 @@
 
     LogBufferElementCollection::iterator it;
 
-    if (caller_uid != AID_ROOT) {
-        // Only here if clearAll condition (pruneRows == ULONG_MAX)
+    if (__predict_false(caller_uid != AID_ROOT)) { // unlikely
+        // Only here if clear all request from non system source, so chatty
+        // filter logistics is not required.
         it = mLastSet[id] ? mLast[id] : mLogElements.begin();
         while (it != mLogElements.end()) {
             LogBufferElement *element = *it;
@@ -534,7 +483,9 @@
             }
 
             it = erase(it);
-            pruneRows--;
+            if (--pruneRows == 0) {
+                break;
+            }
         }
         LogTimeEntry::unlock();
         return busy;
@@ -544,48 +495,32 @@
     bool hasBlacklist = (id != LOG_ID_SECURITY) && mPrune.naughty();
     while (!clearAll && (pruneRows > 0)) {
         // recalculate the worst offender on every batched pass
-        uid_t worst = (uid_t) -1;
+        int worst = -1; // not valid for getUid() or getKey()
         size_t worst_sizes = 0;
         size_t second_worst_sizes = 0;
         pid_t worstPid = 0; // POSIX guarantees PID != 0
 
         if (worstUidEnabledForLogid(id) && mPrune.worstUidEnabled()) {
-            {   // begin scope for UID sorted list
-                std::unique_ptr<const UidEntry *[]> sorted = stats.sort(
-                    AID_ROOT, (pid_t)0, 2, id);
+            // Calculate threshold as 12.5% of available storage
+            size_t threshold = log_buffer_size(id) / 8;
 
-                if (sorted.get() && sorted[0] && sorted[1]) {
-                    worst_sizes = sorted[0]->getSizes();
-                    // Calculate threshold as 12.5% of available storage
-                    size_t threshold = log_buffer_size(id) / 8;
-                    if ((worst_sizes > threshold)
-                        // Allow time horizon to extend roughly tenfold, assume
-                        // average entry length is 100 characters.
-                            && (worst_sizes > (10 * sorted[0]->getDropped()))) {
-                        worst = sorted[0]->getKey();
-                        second_worst_sizes = sorted[1]->getSizes();
-                        if (second_worst_sizes < threshold) {
-                            second_worst_sizes = threshold;
-                        }
-                    }
-                }
-            }
+            if ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) {
+                stats.sortTags(AID_ROOT, (pid_t)0, 2, id).findWorst(
+                    worst, worst_sizes, second_worst_sizes, threshold);
+                // per-pid filter for AID_SYSTEM sources is too complex
+            } else {
+                stats.sort(AID_ROOT, (pid_t)0, 2, id).findWorst(
+                    worst, worst_sizes, second_worst_sizes, threshold);
 
-            if ((worst == AID_SYSTEM) && mPrune.worstPidOfSystemEnabled()) {
-                // begin scope of PID sorted list
-                std::unique_ptr<const PidEntry *[]> sorted = stats.sort(
-                    worst, (pid_t)0, 2, id, worst);
-                if (sorted.get() && sorted[0] && sorted[1]) {
-                    worstPid = sorted[0]->getKey();
-                    second_worst_sizes = worst_sizes
-                                       - sorted[0]->getSizes()
-                                       + sorted[1]->getSizes();
+                if ((worst == AID_SYSTEM) && mPrune.worstPidOfSystemEnabled()) {
+                    stats.sortPids(worst, (pid_t)0, 2, id).findWorst(
+                        worstPid, worst_sizes, second_worst_sizes);
                 }
             }
         }
 
         // skip if we have neither worst nor naughty filters
-        if ((worst == (uid_t) -1) && !hasBlacklist) {
+        if ((worst == -1) && !hasBlacklist) {
             break;
         }
 
@@ -597,17 +532,18 @@
         // - coalesce chatty tags
         // - check age-out of preserved logs
         bool gc = pruneRows <= 1;
-        if (!gc && (worst != (uid_t) -1)) {
-            {   // begin scope for uid worst found iterator
-                LogBufferIteratorMap::iterator found = mLastWorstUid[id].find(worst);
-                if ((found != mLastWorstUid[id].end())
+        if (!gc && (worst != -1)) {
+            {   // begin scope for worst found iterator
+                LogBufferIteratorMap::iterator found = mLastWorst[id].find(worst);
+                if ((found != mLastWorst[id].end())
                         && (found->second != mLogElements.end())) {
                     leading = false;
                     it = found->second;
                 }
             }
-            if (worstPid) {
-                // begin scope for pid worst found iterator
+            if (worstPid) { // begin scope for pid worst found iterator
+                // FYI: worstPid only set if !LOG_ID_EVENTS and
+                //      !LOG_ID_SECURITY, not going to make that assumption ...
                 LogBufferPidIteratorMap::iterator found
                     = mLastWorstPidOfSystem[id].find(worstPid);
                 if ((found != mLastWorstPidOfSystem[id].end())
@@ -639,6 +575,7 @@
                 ++it;
                 continue;
             }
+            // below this point element->getLogId() == id
 
             if (leading && (!mLastSet[id] || ((*mLast[id])->getLogId() != id))) {
                 mLast[id] = it;
@@ -658,6 +595,10 @@
                 continue;
             }
 
+            int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) ?
+                    element->getTag() :
+                    element->getUid();
+
             if (hasBlacklist && mPrune.naughty(element)) {
                 last.clear(element);
                 it = erase(it);
@@ -670,7 +611,7 @@
                     break;
                 }
 
-                if (element->getUid() == worst) {
+                if (key == worst) {
                     kick = true;
                     if (worst_sizes < second_worst_sizes) {
                         break;
@@ -689,26 +630,30 @@
                 last.add(element);
                 if (worstPid
                         && ((!gc && (element->getPid() == worstPid))
-                            || (mLastWorstPidOfSystem[id].find(element->getPid())
+                           || (mLastWorstPidOfSystem[id].find(element->getPid())
                                 == mLastWorstPidOfSystem[id].end()))) {
+                    // element->getUid() may not be AID_SYSTEM, next best
+                    // watermark if current one empty. id is not LOG_ID_EVENTS
+                    // or LOG_ID_SECURITY because of worstPid check.
                     mLastWorstPidOfSystem[id][element->getPid()] = it;
                 }
-                if ((!gc && !worstPid && (element->getUid() == worst))
-                        || (mLastWorstUid[id].find(element->getUid())
-                            == mLastWorstUid[id].end())) {
-                    mLastWorstUid[id][element->getUid()] = it;
+                if ((!gc && !worstPid && (key == worst))
+                        || (mLastWorst[id].find(key) == mLastWorst[id].end())) {
+                    mLastWorst[id][key] = it;
                 }
                 ++it;
                 continue;
             }
 
-            if ((element->getUid() != worst)
+            if ((key != worst)
                     || (worstPid && (element->getPid() != worstPid))) {
                 leading = false;
                 last.clear(element);
                 ++it;
                 continue;
             }
+            // key == worst below here
+            // If worstPid set, then element->getPid() == worstPid below here
 
             pruneRows--;
             if (pruneRows == 0) {
@@ -732,11 +677,14 @@
                     if (worstPid && (!gc
                                 || (mLastWorstPidOfSystem[id].find(worstPid)
                                     == mLastWorstPidOfSystem[id].end()))) {
+                        // element->getUid() may not be AID_SYSTEM, next best
+                        // watermark if current one empty. id is not
+                        // LOG_ID_EVENTS or LOG_ID_SECURITY because of worstPid.
                         mLastWorstPidOfSystem[id][worstPid] = it;
                     }
-                    if ((!gc && !worstPid) || (mLastWorstUid[id].find(worst)
-                                == mLastWorstUid[id].end())) {
-                        mLastWorstUid[id][worst] = it;
+                    if ((!gc && !worstPid) ||
+                         (mLastWorst[id].find(worst) == mLastWorst[id].end())) {
+                        mLastWorst[id][worst] = it;
                     }
                     ++it;
                 }
@@ -889,7 +837,7 @@
 // set the total space allocated to "id"
 int LogBuffer::setSize(log_id_t id, unsigned long size) {
     // Reasonable limits ...
-    if (!valid_size(size)) {
+    if (!__android_logger_valid_buffer_size(size)) {
         return -1;
     }
     pthread_mutex_lock(&mLogElementsLock);
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 7e99236..ff9692e 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -22,10 +22,9 @@
 #include <list>
 #include <string>
 
-#include <log/log.h>
-#include <sysutils/SocketClient.h>
-
+#include <android/log.h>
 #include <private/android_filesystem_config.h>
+#include <sysutils/SocketClient.h>
 
 #include "LogBufferElement.h"
 #include "LogTimes.h"
@@ -89,7 +88,7 @@
     typedef std::unordered_map<uid_t,
                                LogBufferElementCollection::iterator>
                 LogBufferIteratorMap;
-    LogBufferIteratorMap mLastWorstUid[LOG_ID_MAX];
+    LogBufferIteratorMap mLastWorst[LOG_ID_MAX];
     // watermark of any worst/chatty pid of system processing
     typedef std::unordered_map<pid_t,
                                LogBufferElementCollection::iterator>
@@ -103,7 +102,7 @@
 public:
     LastLogTimes &mTimes;
 
-    LogBuffer(LastLogTimes *times);
+    explicit LogBuffer(LastLogTimes *times);
     void init();
     bool isMonotonic() { return monotonic; }
 
@@ -119,7 +118,7 @@
     unsigned long getSize(log_id_t id);
     int setSize(log_id_t id, unsigned long size);
     unsigned long getSizeUsed(log_id_t id);
-    // *strp uses malloc, use free to release.
+
     std::string formatStatistics(uid_t uid, pid_t pid, unsigned int logMask);
 
     void enableStatistics() {
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index eb5194c..f5c60c7 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -22,7 +22,6 @@
 #include <time.h>
 #include <unistd.h>
 
-#include <log/logger.h>
 #include <private/android_logger.h>
 
 #include "LogBuffer.h"
@@ -37,29 +36,24 @@
 LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime,
                                    uid_t uid, pid_t pid, pid_t tid,
                                    const char *msg, unsigned short len) :
-        mLogId(log_id),
         mUid(uid),
         mPid(pid),
         mTid(tid),
-        mMsgLen(len),
         mSequence(sequence.fetch_add(1, memory_order_relaxed)),
-        mRealTime(realtime) {
+        mRealTime(realtime),
+        mMsgLen(len),
+        mLogId(log_id) {
     mMsg = new char[len];
     memcpy(mMsg, msg, len);
+    mTag = (isBinary() && (mMsgLen >= sizeof(uint32_t))) ?
+        le32toh(reinterpret_cast<android_event_header_t *>(mMsg)->tag) :
+        0;
 }
 
 LogBufferElement::~LogBufferElement() {
     delete [] mMsg;
 }
 
-uint32_t LogBufferElement::getTag() const {
-    if (((mLogId != LOG_ID_EVENTS) && (mLogId != LOG_ID_SECURITY)) ||
-            !mMsg || (mMsgLen < sizeof(uint32_t))) {
-        return 0;
-    }
-    return le32toh(reinterpret_cast<android_event_header_t *>(mMsg)->tag);
-}
-
 // caller must own and free character string
 char *android::tidToName(pid_t tid) {
     char *retval = NULL;
@@ -110,7 +104,9 @@
         LogBuffer *parent) {
     static const char tag[] = "chatty";
 
-    if (!__android_log_is_loggable(ANDROID_LOG_INFO, tag, ANDROID_LOG_VERBOSE)) {
+    if (!__android_log_is_loggable_len(ANDROID_LOG_INFO,
+                                       tag, strlen(tag),
+                                       ANDROID_LOG_VERBOSE)) {
         return 0;
     }
 
@@ -163,7 +159,7 @@
     size_t hdrLen;
     // LOG_ID_SECURITY not strictly needed since spam filter not activated,
     // but required for accuracy.
-    if ((mLogId == LOG_ID_EVENTS) || (mLogId == LOG_ID_SECURITY)) {
+    if (isBinary()) {
         hdrLen = sizeof(android_log_event_string_t);
     } else {
         hdrLen = 1 + sizeof(tag);
@@ -177,11 +173,11 @@
     }
 
     size_t retval = hdrLen + len;
-    if ((mLogId == LOG_ID_EVENTS) || (mLogId == LOG_ID_SECURITY)) {
+    if (isBinary()) {
         android_log_event_string_t *event =
             reinterpret_cast<android_log_event_string_t *>(buffer);
 
-        event->header.tag = htole32(LOGD_LOG_TAG);
+        event->header.tag = htole32(CHATTY_LOG_TAG);
         event->type = EVENT_TYPE_STRING;
         event->length = htole32(len);
     } else {
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index e7f88b9..fb7fbed 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -21,9 +21,8 @@
 #include <stdlib.h>
 #include <sys/types.h>
 
-#include <sysutils/SocketClient.h>
 #include <log/log.h>
-#include <log/log_read.h>
+#include <sysutils/SocketClient.h>
 
 class LogBuffer;
 
@@ -37,33 +36,40 @@
 
     friend LogBuffer;
 
-    const log_id_t mLogId;
-    const uid_t mUid;
-    const pid_t mPid;
-    const pid_t mTid;
-    char *mMsg;
-    union {
-        const unsigned short mMsgLen; // mMSg != NULL
-        unsigned short mDropped;      // mMsg == NULL
-    };
+    // sized to match reality of incoming log packets
+    uint32_t mTag; // only valid for isBinary()
+    const uint32_t mUid;
+    const uint32_t mPid;
+    const uint32_t mTid;
     const uint64_t mSequence;
     log_time mRealTime;
+    char *mMsg;
+    union {
+        const uint16_t mMsgLen; // mMSg != NULL
+        uint16_t mDropped;      // mMsg == NULL
+    };
+    const uint8_t mLogId;
+
     static atomic_int_fast64_t sequence;
 
     // assumption: mMsg == NULL
     size_t populateDroppedMessage(char *&buffer,
                                   LogBuffer *parent);
-
 public:
     LogBufferElement(log_id_t log_id, log_time realtime,
                      uid_t uid, pid_t pid, pid_t tid,
                      const char *msg, unsigned short len);
     virtual ~LogBufferElement();
 
-    log_id_t getLogId() const { return mLogId; }
+    bool isBinary(void) const {
+        return (mLogId == LOG_ID_EVENTS) || (mLogId == LOG_ID_SECURITY);
+    }
+
+    log_id_t getLogId() const { return static_cast<log_id_t>(mLogId); }
     uid_t getUid(void) const { return mUid; }
     pid_t getPid(void) const { return mPid; }
     pid_t getTid(void) const { return mTid; }
+    uint32_t getTag() const { return mTag; }
     unsigned short getDropped(void) const { return mMsg ? 0 : mDropped; }
     unsigned short setDropped(unsigned short value) {
         if (mMsg) {
@@ -77,8 +83,6 @@
     static uint64_t getCurrentSequence(void) { return sequence.load(memory_order_relaxed); }
     log_time getRealTime(void) const { return mRealTime; }
 
-    uint32_t getTag(void) const;
-
     static const uint64_t FLUSH_ERROR;
     uint64_t flushTo(SocketClient *writer, LogBuffer *parent, bool privileged);
 };
diff --git a/logd/LogCommand.h b/logd/LogCommand.h
index c944478..0adc2a1 100644
--- a/logd/LogCommand.h
+++ b/logd/LogCommand.h
@@ -22,7 +22,7 @@
 
 class LogCommand : public FrameworkCommand {
 public:
-    LogCommand(const char *cmd);
+    explicit LogCommand(const char *cmd);
     virtual ~LogCommand() {}
 };
 
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index c7506ef..7073535 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -25,7 +25,7 @@
 #include <sys/uio.h>
 #include <syslog.h>
 
-#include <log/logger.h>
+#include <private/android_logger.h>
 #include <private/android_filesystem_config.h>
 
 #include "LogBuffer.h"
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
index a4f871e..11d88af 100644
--- a/logd/LogKlog.h
+++ b/logd/LogKlog.h
@@ -17,8 +17,8 @@
 #ifndef _LOGD_LOG_KLOG_H__
 #define _LOGD_LOG_KLOG_H__
 
+#include <private/android_logger.h>
 #include <sysutils/SocketListener.h>
-#include <log/log_read.h>
 
 char *log_strntok_r(char *s, size_t *len, char **saveptr, size_t *sublen);
 
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index 39dd227..4a30e6d 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -23,7 +23,6 @@
 #include <unistd.h>
 
 #include <cutils/sockets.h>
-#include <log/logger.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
@@ -48,7 +47,7 @@
         + LOGGER_ENTRY_MAX_PAYLOAD];
     struct iovec iov = { buffer, sizeof(buffer) };
 
-    char control[CMSG_SPACE(sizeof(struct ucred))] __aligned(4);
+    alignas(4) char control[CMSG_SPACE(sizeof(struct ucred))];
     struct msghdr hdr = {
         NULL,
         0,
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 2c07984..61d4c49 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -21,6 +21,7 @@
 #include <sys/types.h>
 
 #include <cutils/sockets.h>
+#include <private/android_logger.h>
 
 #include "FlushCommand.h"
 #include "LogBuffer.h"
diff --git a/logd/LogReader.h b/logd/LogReader.h
index 98674b8..fdcedf1 100644
--- a/logd/LogReader.h
+++ b/logd/LogReader.h
@@ -27,7 +27,7 @@
     LogBuffer &mLogbuf;
 
 public:
-    LogReader(LogBuffer *logbuf);
+    explicit LogReader(LogBuffer *logbuf);
     void notifyNewLog();
 
     LogBuffer &logbuf(void) const { return mLogbuf; }
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 2b02bc1..d4b48ef 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -15,11 +15,15 @@
  */
 
 #include <fcntl.h>
+#include <pwd.h>
 #include <stdio.h>
 #include <string.h>
+#include <sys/types.h>
 #include <unistd.h>
 
-#include <log/logger.h>
+#include <list>
+
+#include <android/log.h>
 
 #include "LogStatistics.h"
 
@@ -150,6 +154,15 @@
 
     pidTable.drop(element->getPid(), element);
     tidTable.drop(element->getTid(), element);
+
+    uint32_t tag = element->getTag();
+    if (tag) {
+        if (log_id == LOG_ID_SECURITY) {
+            securityTagTable.drop(tag, element);
+        } else {
+            tagTable.drop(tag, element);
+        }
+    }
 }
 
 // caller must own and free character string
@@ -159,14 +172,13 @@
         return strdup("auditd");
     }
 
-    // Android hard coded
-    const struct android_id_info *info = android_ids;
-
-    for (size_t i = 0; i < android_id_count; ++i) {
-        if (info->aid == uid) {
-            return strdup(info->name);
+    // Android system
+    if (uid < AID_APP) {
+        // in bionic, thread safe as long as we copy the results
+        struct passwd *pwd = getpwuid(uid);
+        if (pwd) {
+            return strdup(pwd->pw_name);
         }
-        ++info;
     }
 
     // Parse /data/system/packages.list
@@ -179,6 +191,14 @@
         return name;
     }
 
+    // Android application
+    if (uid >= AID_APP) {
+        struct passwd *pwd = getpwuid(uid);
+        if (pwd) {
+            return strdup(pwd->pw_name);
+        }
+    }
+
     // report uid -> pid(s) -> pidToName if unique
     for(pidTable_t::const_iterator it = pidTable.begin(); it != pidTable.end(); ++it) {
         const PidEntry &entry = it->second;
@@ -275,7 +295,7 @@
             if ((spaces <= 0) && pruned.length()) {
                 spaces = 1;
             }
-            if (spaces > 0) {
+            if ((spaces > 0) && (pruned.length() != 0)) {
                 change += android::base::StringPrintf("%*s", (int)spaces, "");
             }
             pruned = change + pruned;
@@ -418,17 +438,22 @@
         name = android::base::StringPrintf("%7u/%u",
                                            getKey(), uid);
     }
-    const char *nameTmp = getName();
+    size_t len = 0;
+    const char *nameTmp = getName(len);
     if (nameTmp) {
         name += android::base::StringPrintf(
-            "%*s%s", (int)std::max(14 - name.length(), (size_t)1),
-            "", nameTmp);
+            "%*s%.*s", (int)std::max(14 - name.length(), (size_t)1),
+            "", (int)len, nameTmp);
     }
 
     std::string size = android::base::StringPrintf("%zu",
                                                    getSizes());
 
     std::string pruned = "";
+    size_t dropped = getDropped();
+    if (dropped) {
+        pruned = android::base::StringPrintf("%zu", dropped);
+    }
 
     return formatLine(name, size, pruned);
 }
@@ -444,55 +469,87 @@
     short spaces = 1;
 
     log_id_for_each(id) {
-        if (!(logMask & (1 << id))) {
-            continue;
-        }
+        if (!(logMask & (1 << id))) continue;
         oldLength = output.length();
-        if (spaces < 0) {
-            spaces = 0;
-        }
+        if (spaces < 0) spaces = 0;
         output += android::base::StringPrintf("%*s%s", spaces, "",
                                               android_log_id_to_name(id));
         spaces += spaces_total + oldLength - output.length();
     }
+    if (spaces < 0) spaces = 0;
+    output += android::base::StringPrintf("%*sTotal", spaces, "");
 
-    spaces = 4;
-    output += "\nTotal";
+    static const char TotalStr[] = "\nTotal";
+    spaces = 10 - strlen(TotalStr);
+    output += TotalStr;
 
+    size_t totalSize = 0;
+    size_t totalEls = 0;
     log_id_for_each(id) {
-        if (!(logMask & (1 << id))) {
-            continue;
-        }
+        if (!(logMask & (1 << id))) continue;
         oldLength = output.length();
-        if (spaces < 0) {
-            spaces = 0;
-        }
-        output += android::base::StringPrintf("%*s%zu/%zu", spaces, "",
-                                              sizesTotal(id),
-                                              elementsTotal(id));
+        if (spaces < 0) spaces = 0;
+        size_t szs = sizesTotal(id);
+        totalSize += szs;
+        size_t els = elementsTotal(id);
+        totalEls += els;
+        output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
         spaces += spaces_total + oldLength - output.length();
     }
+    if (spaces < 0) spaces = 0;
+    output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize, totalEls);
 
-    spaces = 6;
-    output += "\nNow";
+    static const char NowStr[] = "\nNow";
+    spaces = 10 - strlen(NowStr);
+    output += NowStr;
 
+    totalSize = 0;
+    totalEls = 0;
     log_id_for_each(id) {
-        if (!(logMask & (1 << id))) {
-            continue;
-        }
+        if (!(logMask & (1 << id))) continue;
 
         size_t els = elements(id);
         if (els) {
             oldLength = output.length();
-            if (spaces < 0) {
-                spaces = 0;
-            }
-            output += android::base::StringPrintf("%*s%zu/%zu", spaces, "",
-                                                  sizes(id), els);
+            if (spaces < 0) spaces = 0;
+            size_t szs = sizes(id);
+            totalSize += szs;
+            totalEls += els;
+            output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
             spaces -= output.length() - oldLength;
         }
         spaces += spaces_total;
     }
+    if (spaces < 0) spaces = 0;
+    output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize, totalEls);
+
+    static const char OverheadStr[] = "\nOverhead";
+    spaces = 10 - strlen(OverheadStr);
+    output += OverheadStr;
+
+    totalSize = 0;
+    log_id_for_each(id) {
+        if (!(logMask & (1 << id))) continue;
+
+        size_t els = elements(id);
+        if (els) {
+            oldLength = output.length();
+            if (spaces < 0) spaces = 0;
+            // estimate the std::list overhead.
+            static const size_t overhead =
+                ((sizeof(LogBufferElement) + sizeof(uint64_t) - 1) &
+                    -sizeof(uint64_t)) +
+                sizeof(std::list<LogBufferElement*>);
+            size_t szs = sizes(id) + els * overhead;
+            totalSize += szs;
+            output += android::base::StringPrintf("%*s%zu", spaces, "", szs);
+            spaces -= output.length() - oldLength;
+        }
+        spaces += spaces_total;
+    }
+    totalSize += sizeOf();
+    if (spaces < 0) spaces = 0;
+    output += android::base::StringPrintf("%*s%zu", spaces, "", totalSize);
 
     // Report on Chattiest
 
@@ -500,9 +557,7 @@
 
     // Chattiest by application (UID)
     log_id_for_each(id) {
-        if (!(logMask & (1 << id))) {
-            continue;
-        }
+        if (!(logMask & (1 << id))) continue;
 
         name = (uid == AID_ROOT)
             ? "Chattiest UIDs in %s log buffer:"
@@ -516,27 +571,21 @@
             : "Logging for this PID:";
         output += pidTable.format(*this, uid, pid, name);
         name = "Chattiest TIDs";
-        if (pid) {
-            name += android::base::StringPrintf(" for PID %d", pid);
-        }
+        if (pid) name += android::base::StringPrintf(" for PID %d", pid);
         name += ":";
         output += tidTable.format(*this, uid, pid, name);
     }
 
     if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
         name = "Chattiest events log buffer TAGs";
-        if (pid) {
-            name += android::base::StringPrintf(" for PID %d", pid);
-        }
+        if (pid) name += android::base::StringPrintf(" for PID %d", pid);
         name += ":";
         output += tagTable.format(*this, uid, pid, name, LOG_ID_EVENTS);
     }
 
     if (enable && (logMask & (1 << LOG_ID_SECURITY))) {
         name = "Chattiest security log buffer TAGs";
-        if (pid) {
-            name += android::base::StringPrintf(" for PID %d", pid);
-        }
+        if (pid) name += android::base::StringPrintf(" for PID %d", pid);
         name += ":";
         output += securityTagTable.format(*this, uid, pid, name, LOG_ID_SECURITY);
     }
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 6f7d264..1f598af 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -25,15 +25,15 @@
 #include <string>    // std::string
 #include <unordered_map>
 
+#include <android/log.h>
 #include <android-base/stringprintf.h>
-#include <log/log.h>
 #include <private/android_filesystem_config.h>
 
 #include "LogBufferElement.h"
 #include "LogUtils.h"
 
 #define log_id_for_each(i) \
-    for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t) (i + 1))
+    for (log_id_t i = LOG_ID_MIN; (i) < LOG_ID_MAX; (i) = (log_id_t) ((i) + 1))
 
 class LogStatistics;
 
@@ -42,8 +42,32 @@
 
     std::unordered_map<TKey, TEntry> map;
 
+    size_t bucket_size() const {
+        size_t count = 0;
+        for (size_t idx = 0; idx < map.bucket_count(); ++idx) {
+            size_t bucket_size = map.bucket_size(idx);
+            if (bucket_size == 0) bucket_size = 1;
+            count += bucket_size;
+        }
+        float load_factor = map.max_load_factor();
+        if (load_factor < 1.0) return count;
+        return count * load_factor;
+    }
+
+    static const size_t unordered_map_per_entry_overhead = sizeof(void*);
+    static const size_t unordered_map_bucket_overhead = sizeof(void*);
+
 public:
 
+    size_t size() const { return map.size(); }
+
+    // Estimate unordered_map memory usage.
+    size_t sizeOf() const {
+        return sizeof(*this) +
+               (size() * (sizeof(TEntry) + unordered_map_per_entry_overhead)) +
+               (bucket_size() * sizeof(size_t) + unordered_map_bucket_overhead);
+    }
+
     typedef typename std::unordered_map<TKey, TEntry>::iterator iterator;
     typedef typename std::unordered_map<TKey, TEntry>::const_iterator const_iterator;
 
@@ -155,6 +179,7 @@
         }
         return output;
     }
+
 };
 
 namespace EntryBaseConstants {
@@ -166,7 +191,7 @@
     size_t size;
 
     EntryBase():size(0) { }
-    EntryBase(LogBufferElement *element):size(element->getMsgLen()) { }
+    explicit EntryBase(LogBufferElement *element):size(element->getMsgLen()) { }
 
     size_t getSizes() const { return size; }
 
@@ -201,9 +226,9 @@
     size_t dropped;
 
     EntryBaseDropped():dropped(0) { }
-    EntryBaseDropped(LogBufferElement *element):
+    explicit EntryBaseDropped(LogBufferElement *element):
             EntryBase(element),
-            dropped(element->getDropped()){
+            dropped(element->getDropped()) {
     }
 
     size_t getDropped() const { return dropped; }
@@ -226,7 +251,7 @@
     const uid_t uid;
     pid_t pid;
 
-    UidEntry(LogBufferElement *element):
+    explicit UidEntry(LogBufferElement *element):
             EntryBaseDropped(element),
             uid(element->getUid()),
             pid(element->getPid()) {
@@ -256,13 +281,13 @@
     uid_t uid;
     char *name;
 
-    PidEntry(pid_t pid):
+    explicit PidEntry(pid_t pid):
             EntryBaseDropped(),
             pid(pid),
             uid(android::pidToUid(pid)),
             name(android::pidToName(pid)) {
     }
-    PidEntry(LogBufferElement *element):
+    explicit PidEntry(LogBufferElement *element):
             EntryBaseDropped(element),
             pid(element->getPid()),
             uid(element->getUid()),
@@ -320,7 +345,7 @@
             uid(android::pidToUid(tid)),
             name(android::tidToName(tid)) {
     }
-    TidEntry(LogBufferElement *element):
+    explicit TidEntry(LogBufferElement *element):
             EntryBaseDropped(element),
             tid(element->getTid()),
             pid(element->getPid()),
@@ -370,13 +395,13 @@
     std::string format(const LogStatistics &stat, log_id_t id) const;
 };
 
-struct TagEntry : public EntryBase {
+struct TagEntry : public EntryBaseDropped {
     const uint32_t tag;
     pid_t pid;
     uid_t uid;
 
-    TagEntry(LogBufferElement *element):
-            EntryBase(element),
+    explicit TagEntry(LogBufferElement *element):
+            EntryBaseDropped(element),
             tag(element->getTag()),
             pid(element->getPid()),
             uid(element->getUid()) {
@@ -385,7 +410,7 @@
     const uint32_t&getKey() const { return tag; }
     const pid_t&getPid() const { return pid; }
     const uid_t&getUid() const { return uid; }
-    const char*getName() const { return android::tagToName(tag); }
+    const char*getName(size_t &len) const { return android::tagToName(&len, tag); }
 
     inline void add(LogBufferElement *element) {
         if (uid != element->getUid()) {
@@ -401,6 +426,43 @@
     std::string format(const LogStatistics &stat, log_id_t id) const;
 };
 
+template <typename TEntry>
+class LogFindWorst {
+    std::unique_ptr<const TEntry *[]> sorted;
+
+public:
+
+    explicit LogFindWorst(std::unique_ptr<const TEntry *[]> &&sorted) : sorted(std::move(sorted)) { }
+
+    void findWorst(int &worst,
+                    size_t &worst_sizes, size_t &second_worst_sizes,
+                    size_t threshold) {
+        if (sorted.get() && sorted[0] && sorted[1]) {
+            worst_sizes = sorted[0]->getSizes();
+            if ((worst_sizes > threshold)
+                // Allow time horizon to extend roughly tenfold, assume
+                // average entry length is 100 characters.
+                    && (worst_sizes > (10 * sorted[0]->getDropped()))) {
+                worst = sorted[0]->getKey();
+                second_worst_sizes = sorted[1]->getSizes();
+                if (second_worst_sizes < threshold) {
+                    second_worst_sizes = threshold;
+                }
+            }
+        }
+    }
+
+    void findWorst(int &worst,
+                    size_t worst_sizes, size_t &second_worst_sizes) {
+        if (sorted.get() && sorted[0] && sorted[1]) {
+            worst = sorted[0]->getKey();
+            second_worst_sizes = worst_sizes
+                               - sorted[0]->getSizes()
+                               + sorted[1]->getSizes();
+        }
+    }
+};
+
 // Log Statistics
 class LogStatistics {
     friend UidEntry;
@@ -435,7 +497,30 @@
     // security tag list
     tagTable_t securityTagTable;
 
+    size_t sizeOf() const {
+        size_t size = sizeof(*this) + pidTable.sizeOf() + tidTable.sizeOf() +
+                      tagTable.sizeOf() + securityTagTable.sizeOf() +
+                      (pidTable.size() * sizeof(pidTable_t::iterator)) +
+                      (tagTable.size() * sizeof(tagTable_t::iterator));
+        for(auto it : pidTable) {
+            const char* name = it.second.getName();
+            if (name) size += strlen(name) + 1;
+        }
+        for(auto it : tidTable) {
+            const char* name = it.second.getName();
+            if (name) size += strlen(name) + 1;
+        }
+        log_id_for_each(id) {
+            size += uidTable[id].sizeOf();
+            size += uidTable[id].size() * sizeof(uidTable_t::iterator);
+            size += pidSystemTable[id].sizeOf();
+            size += pidSystemTable[id].size() * sizeof(pidSystemTable_t::iterator);
+        }
+        return size;
+    }
+
 public:
+
     LogStatistics();
 
     void enableStatistics() { enable = true; }
@@ -451,13 +536,14 @@
         --mDroppedElements[log_id];
     }
 
-    std::unique_ptr<const UidEntry *[]> sort(uid_t uid, pid_t pid,
-                                             size_t len, log_id id) {
-        return uidTable[id].sort(uid, pid, len);
+    LogFindWorst<UidEntry> sort(uid_t uid, pid_t pid, size_t len, log_id id) {
+        return LogFindWorst<UidEntry>(uidTable[id].sort(uid, pid, len));
     }
-    std::unique_ptr<const PidEntry *[]> sort(uid_t uid, pid_t pid,
-                                             size_t len, log_id id, uid_t) {
-        return pidSystemTable[id].sort(uid, pid, len);
+    LogFindWorst<PidEntry> sortPids(uid_t uid, pid_t pid, size_t len, log_id id) {
+        return LogFindWorst<PidEntry>(pidSystemTable[id].sort(uid, pid, len));
+    }
+    LogFindWorst<TagEntry> sortTags(uid_t uid, pid_t pid, size_t len, log_id) {
+        return LogFindWorst<TagEntry>(tagTable.sort(uid, pid, len));
     }
 
     // fast track current value by id only
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index b66ff9e..12df994 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -23,8 +23,8 @@
 
 #include <list>
 
-#include <sysutils/SocketClient.h>
 #include <log/log.h>
+#include <sysutils/SocketClient.h>
 
 class LogReader;
 class LogBufferElement;
diff --git a/logd/LogUtils.h b/logd/LogUtils.h
index fd4800e..44ac742 100644
--- a/logd/LogUtils.h
+++ b/logd/LogUtils.h
@@ -17,9 +17,10 @@
 #ifndef _LOGD_LOG_UTILS_H__
 #define _LOGD_LOG_UTILS_H__
 
+#include <sys/cdefs.h>
 #include <sys/types.h>
 
-#include <log/log.h>
+#include <private/android_logger.h>
 #include <sysutils/SocketClient.h>
 
 // Hijack this header as a common include file used by most all sources
@@ -29,13 +30,14 @@
 
 // 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);
 char *tidToName(pid_t tid);
 
 // Furnished in main.cpp. Thread safe.
-const char *tagToName(uint32_t tag);
+const char *tagToName(size_t *len, uint32_t tag);
 
 }
 
@@ -43,18 +45,9 @@
 bool clientHasLogCredentials(uid_t uid, gid_t gid, pid_t pid);
 bool clientHasLogCredentials(SocketClient *cli);
 
-// Furnished in main.cpp
-#define BOOL_DEFAULT_FLAG_TRUE_FALSE 0x1
-#define BOOL_DEFAULT_FALSE       0x0     // false if property not present
-#define BOOL_DEFAULT_TRUE        0x1     // true if property not present
-#define BOOL_DEFAULT_FLAG_PERSIST    0x2 // <key>, persist.<key>, ro.<key>
-#define BOOL_DEFAULT_FLAG_ENG        0x4 // off for user
-#define BOOL_DEFAULT_FLAG_SVELTE     0x8 // off for low_ram
-
-bool property_get_bool(const char *key, int def);
-
 static inline bool worstUidEnabledForLogid(log_id_t id) {
-    return (id == LOG_ID_MAIN) || (id == LOG_ID_SYSTEM) || (id == LOG_ID_RADIO);
+    return (id == LOG_ID_MAIN) || (id == LOG_ID_SYSTEM) ||
+            (id == LOG_ID_RADIO) || (id == LOG_ID_EVENTS);
 }
 
 template <int (*cmp)(const char *l, const char *r, const size_t s)>
diff --git a/logd/README.property b/logd/README.property
index b2708e4..791b1d5 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -8,7 +8,7 @@
 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.
 logd.logpersistd.enable    bool   auto   Safe to start logpersist daemon service
 logd.logpersistd          string persist Enable logpersist daemon, "logcatd"
@@ -55,10 +55,10 @@
 NB:
 - auto - managed by /init
 - 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/event.logtags b/logd/event.logtags
index db8c19b..0d24df0 100644
--- a/logd/event.logtags
+++ b/logd/event.logtags
@@ -34,4 +34,4 @@
 # TODO: generate ".java" and ".h" files with integer constants from this file.
 
 1003  auditd (avc|3)
-1004  logd (dropped|3)
+1004  chatty (dropped|3)
diff --git a/logd/libaudit.c b/logd/libaudit.c
index d00d579..d2b212e 100644
--- a/logd/libaudit.c
+++ b/logd/libaudit.c
@@ -22,21 +22,16 @@
 #include <string.h>
 #include <unistd.h>
 
-#define LOG_TAG "libaudit"
-#include <log/log.h>
-
 #include "libaudit.h"
 
 /**
  * Waits for an ack from the kernel
  * @param fd
  *  The netlink socket fd
- * @param seq
- *  The current sequence number were acking on
  * @return
  *  This function returns 0 on success, else -errno.
  */
-static int get_ack(int fd, int16_t seq)
+static int get_ack(int fd)
 {
     int rc;
     struct audit_message rep;
@@ -59,11 +54,6 @@
         }
     }
 
-    if ((int16_t)rep.nlh.nlmsg_seq != seq) {
-        SLOGW("Expected sequence number between user space and kernel space is out of skew, "
-          "expected %u got %u", seq, rep.nlh.nlmsg_seq);
-    }
-
     return 0;
 }
 
@@ -108,7 +98,6 @@
 
     /* Ensure the message is not too big */
     if (NLMSG_SPACE(size) > MAX_AUDIT_MESSAGE_LENGTH) {
-        SLOGE("netlink message is too large");
         return -EINVAL;
     }
 
@@ -139,7 +128,6 @@
     /* Not all the bytes were sent */
     if (rc < 0) {
         rc = -errno;
-        SLOGE("Error sending data over the netlink socket: %s", strerror(-errno));
         goto out;
     } else if ((uint32_t) rc != req.nlh.nlmsg_len) {
         rc = -EPROTO;
@@ -147,7 +135,7 @@
     }
 
     /* We sent all the bytes, get the ack */
-    rc = get_ack(fd, sequence);
+    rc = get_ack(fd);
 
     /* If the ack failed, return the error, else return the sequence number */
     rc = (rc == 0) ? (int) sequence : rc;
@@ -155,7 +143,6 @@
 out:
     /* Don't let sequence roll to negative */
     if (sequence < 0) {
-        SLOGW("Auditd to Kernel sequence number has rolled over");
         sequence = 0;
     }
 
@@ -182,7 +169,6 @@
     /* Let the kernel know this pid will be registering for audit events */
     rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
     if (rc < 0) {
-        SLOGE("Could net set pid for audit events, error: %s", strerror(-rc));
         return rc;
     }
 
@@ -240,25 +226,21 @@
             /* If request is non blocking and errno is EAGAIN, just return 0 */
             return 0;
         }
-        SLOGE("Error receiving from netlink socket, error: %s", strerror(-rc));
         return rc;
     }
 
     if (nladdrlen != sizeof(nladdr)) {
-        SLOGE("Protocol fault, error: %s", strerror(EPROTO));
         return -EPROTO;
     }
 
     /* Make sure the netlink message was not spoof'd */
     if (nladdr.nl_pid) {
-        SLOGE("Invalid netlink pid received, expected 0 got: %d", nladdr.nl_pid);
         return -EINVAL;
     }
 
     /* Check if the reply from the kernel was ok */
     if (!NLMSG_OK(&rep->nlh, (size_t)len)) {
         rc = (len == sizeof(*rep)) ? -EFBIG : -EBADE;
-        SLOGE("Bad kernel response %s", strerror(-rc));
     }
 
     return rc;
@@ -266,9 +248,5 @@
 
 void audit_close(int fd)
 {
-    int rc = close(fd);
-    if (rc < 0) {
-        SLOGE("Attempting to close invalid fd %d, error: %s", fd, strerror(errno));
-    }
-    return;
+    close(fd);
 }
diff --git a/logd/logd.rc b/logd/logd.rc
index 31ed4df..54349dd 100644
--- a/logd/logd.rc
+++ b/logd/logd.rc
@@ -2,10 +2,15 @@
     socket logd stream 0666 logd logd
     socket logdr seqpacket 0666 logd logd
     socket logdw dgram 0222 logd logd
-    group root system readproc
+    file /proc/kmsg r
+    file /dev/kmsg w
+    user logd
+    group logd system readproc
     writepid /dev/cpuset/system-background/tasks
 
 service logd-reinit /system/bin/logd --reinit
     oneshot
     disabled
+    user logd
+    group logd
     writepid /dev/cpuset/system-background/tasks
diff --git a/logd/main.cpp b/logd/main.cpp
index 8aa1abb..7550c41 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -36,12 +36,15 @@
 #include <cstdbool>
 #include <memory>
 
+#include <android-base/macros.h>
+#include <cutils/android_get_control_file.h>
 #include <cutils/properties.h>
 #include <cutils/sched_policy.h>
 #include <cutils/sockets.h>
 #include <log/event_tag_map.h>
 #include <packagelistparser/packagelistparser.h>
 #include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
 #include <utils/threads.h>
 
 #include "CommandListener.h"
@@ -58,14 +61,14 @@
     '>'
 
 //
-//  The service is designed to be run by init, it does not respond well
+// The service is designed to be run by init, it does not respond well
 // to starting up manually. When starting up manually the sockets will
 // fail to open typically for one of the following reasons:
 //     EADDRINUSE if logger is running.
 //     EACCESS if started without precautions (below)
 //
 // Here is a cookbook procedure for starting up logd manually assuming
-// init is out of the way, pedantically all permissions and selinux
+// init is out of the way, pedantically all permissions and SELinux
 // security is put back in place:
 //
 //    setenforce 0
@@ -86,57 +89,79 @@
 //    logd
 //
 
-static int drop_privs() {
+static int drop_privs(bool klogd, bool auditd) {
+    // Tricky, if ro.build.type is "eng" then this is true because of the
+    // side effect that ro.debuggable == 1 as well, else it is false.
+    bool eng = __android_logger_property_get_bool("ro.build.type", BOOL_DEFAULT_FALSE);
+
     struct sched_param param;
     memset(&param, 0, sizeof(param));
 
     if (set_sched_policy(0, SP_BACKGROUND) < 0) {
-        return -1;
+        android::prdebug("failed to set background scheduling policy");
+        if (!eng) return -1;
     }
 
     if (sched_setscheduler((pid_t) 0, SCHED_BATCH, &param) < 0) {
-        return -1;
+        android::prdebug("failed to set batch scheduler");
+        if (!eng) return -1;
     }
 
     if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
+        android::prdebug("failed to set background cgroup");
+        if (!eng) return -1;
+    }
+
+    if (!eng && (prctl(PR_SET_DUMPABLE, 0) < 0)) {
+        android::prdebug("failed to clear PR_SET_DUMPABLE");
         return -1;
     }
 
     if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
-        return -1;
+        android::prdebug("failed to set PR_SET_KEEPCAPS");
+        if (!eng) return -1;
+    }
+
+    std::unique_ptr<struct _cap_struct, int(*)(void *)> caps(cap_init(), cap_free);
+    if (cap_clear(caps.get()) < 0) return -1;
+    cap_value_t cap_value[] = {
+        CAP_SETGID, // must be first for below
+        klogd ? CAP_SYSLOG : CAP_SETGID,
+        auditd ? CAP_AUDIT_CONTROL : CAP_SETGID
+    };
+    if (cap_set_flag(caps.get(), CAP_PERMITTED,
+                     arraysize(cap_value), cap_value,
+                     CAP_SET) < 0) return -1;
+    if (cap_set_flag(caps.get(), CAP_EFFECTIVE,
+                     arraysize(cap_value), cap_value,
+                     CAP_SET) < 0) return -1;
+    if (cap_set_proc(caps.get()) < 0) {
+        android::prdebug("failed to set CAP_SETGID, CAP_SYSLOG or CAP_AUDIT_CONTROL (%d)", errno);
+        if (!eng) return -1;
     }
 
     gid_t groups[] = { AID_READPROC };
 
-    if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) == -1) {
-        return -1;
+    if (setgroups(arraysize(groups), groups) == -1) {
+        android::prdebug("failed to set AID_READPROC groups");
+        if (!eng) return -1;
     }
 
     if (setgid(AID_LOGD) != 0) {
-        return -1;
+        android::prdebug("failed to set AID_LOGD gid");
+        if (!eng) return -1;
     }
 
     if (setuid(AID_LOGD) != 0) {
-        return -1;
+        android::prdebug("failed to set AID_LOGD uid");
+        if (!eng) return -1;
     }
 
-    struct __user_cap_header_struct capheader;
-    struct __user_cap_data_struct capdata[2];
-    memset(&capheader, 0, sizeof(capheader));
-    memset(&capdata, 0, sizeof(capdata));
-    capheader.version = _LINUX_CAPABILITY_VERSION_3;
-    capheader.pid = 0;
-
-    capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG);
-    capdata[CAP_TO_INDEX(CAP_AUDIT_CONTROL)].permitted |= CAP_TO_MASK(CAP_AUDIT_CONTROL);
-
-    capdata[0].effective = capdata[0].permitted;
-    capdata[1].effective = capdata[1].permitted;
-    capdata[0].inheritable = 0;
-    capdata[1].inheritable = 0;
-
-    if (capset(&capheader, &capdata[0]) < 0) {
-        return -1;
+    if (cap_set_flag(caps.get(), CAP_PERMITTED, 1, cap_value, CAP_CLEAR) < 0) return -1;
+    if (cap_set_flag(caps.get(), CAP_EFFECTIVE, 1, cap_value, CAP_CLEAR) < 0) return -1;
+    if (cap_set_proc(caps.get()) < 0) {
+        android::prdebug("failed to clear CAP_SETGID (%d)", errno);
+        if (!eng) return -1;
     }
 
     return 0;
@@ -157,64 +182,32 @@
     return !*cp || !!strchr(sep, *cp);
 }
 
-bool property_get_bool(const char *key, int flag) {
-    char def[PROPERTY_VALUE_MAX];
-    char property[PROPERTY_VALUE_MAX];
-    def[0] = '\0';
-    if (flag & BOOL_DEFAULT_FLAG_PERSIST) {
-        char newkey[PROPERTY_KEY_MAX];
-        snprintf(newkey, sizeof(newkey), "ro.%s", key);
-        property_get(newkey, property, "");
-        // persist properties set by /data require inoculation with
-        // logd-reinit. They may be set in init.rc early and function, but
-        // otherwise are defunct unless reset. Do not rely on persist
-        // properties for startup-only keys unless you are willing to restart
-        // logd daemon (not advised).
-        snprintf(newkey, sizeof(newkey), "persist.%s", key);
-        property_get(newkey, def, property);
-    }
-
-    property_get(key, property, def);
-
-    if (check_flag(property, "true")) {
-        return true;
-    }
-    if (check_flag(property, "false")) {
-        return false;
-    }
-    if (check_flag(property, "eng")) {
-       flag |= BOOL_DEFAULT_FLAG_ENG;
-    }
-    // this is really a "not" flag
-    if (check_flag(property, "svelte")) {
-       flag |= BOOL_DEFAULT_FLAG_SVELTE;
-    }
-
-    // Sanity Check
-    if (flag & (BOOL_DEFAULT_FLAG_SVELTE | BOOL_DEFAULT_FLAG_ENG)) {
-        flag &= ~BOOL_DEFAULT_FLAG_TRUE_FALSE;
-        flag |= BOOL_DEFAULT_TRUE;
-    }
-
-    if ((flag & BOOL_DEFAULT_FLAG_SVELTE)
-            && property_get_bool("ro.config.low_ram",
-                                 BOOL_DEFAULT_FALSE)) {
-        return false;
-    }
-    if (flag & BOOL_DEFAULT_FLAG_ENG) {
-        property_get("ro.build.type", property, "");
-        if (!strcmp(property, "user")) {
-            return false;
-        }
-    }
-
-    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 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;
@@ -242,11 +235,16 @@
     set_sched_policy(0, SP_BACKGROUND);
     setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND);
 
-    // If we are AID_ROOT, we should drop to AID_SYSTEM, if we are anything
-    // else, we have even lesser privileges and accept our fate. Not worth
-    // checking for error returns setting this thread's privileges.
-    (void)setgid(AID_SYSTEM);
-    (void)setuid(AID_SYSTEM);
+    cap_t caps = cap_init();
+    (void)cap_clear(caps);
+    (void)cap_set_proc(caps);
+    (void)cap_free(caps);
+
+    // If we are AID_ROOT, we should drop to AID_LOGD+AID_SYSTEM, if we are
+    // anything else, we have even lesser privileges and accept our fate. Not
+    // worth checking for error returns setting this thread's privileges.
+    (void)setgid(AID_SYSTEM); // readonly access to /data/system/packages.list
+    (void)setuid(AID_LOGD);   // access to everything logd.
 
     while (reinit_running && !sem_wait(&reinit) && reinit_running) {
 
@@ -307,7 +305,7 @@
 }
 
 // tagToName converts an events tag into a name
-const char *android::tagToName(uint32_t tag) {
+const char *android::tagToName(size_t *len, uint32_t tag) {
     static const EventTagMap *map;
 
     if (!map) {
@@ -317,10 +315,11 @@
         }
         sem_post(&sem_name);
         if (!map) {
+            if (len) len = 0;
             return NULL;
         }
     }
-    return android_lookupEventTag(map, tag);
+    return android_lookupEventTag_len(map, len, tag);
 }
 
 static void readDmesg(LogAudit *al, LogKlog *kl) {
@@ -363,6 +362,39 @@
     }
 }
 
+static int issueReinit() {
+    cap_t caps = cap_init();
+    (void)cap_clear(caps);
+    (void)cap_set_proc(caps);
+    (void)cap_free(caps);
+
+    int sock = TEMP_FAILURE_RETRY(
+        socket_local_client("logd",
+                            ANDROID_SOCKET_NAMESPACE_RESERVED,
+                            SOCK_STREAM));
+    if (sock < 0) return -errno;
+
+    static const char reinitStr[] = "reinit";
+    ssize_t ret = TEMP_FAILURE_RETRY(write(sock, reinitStr, sizeof(reinitStr)));
+    if (ret < 0) return -errno;
+
+    struct pollfd p;
+    memset(&p, 0, sizeof(p));
+    p.fd = sock;
+    p.events = POLLIN;
+    ret = TEMP_FAILURE_RETRY(poll(&p, 1, 1000));
+    if (ret < 0) return -errno;
+    if ((ret == 0) || !(p.revents & POLLIN)) return -ETIME;
+
+    static const char success[] = "success";
+    char buffer[sizeof(success) - 1];
+    memset(buffer, 0, sizeof(buffer));
+    ret = TEMP_FAILURE_RETRY(read(sock, buffer, sizeof(buffer)));
+    if (ret < 0) return -errno;
+
+    return strncmp(buffer, success, sizeof(success) - 1) != 0;
+}
+
 // Foreground waits for exit of the main persistent threads
 // that are started here. The threads are created to manage
 // UNIX domain client sockets for writing, reading and
@@ -370,50 +402,31 @@
 // logging plugins like auditd and restart control. Additional
 // transitory per-client threads are created for each reader.
 int main(int argc, char *argv[]) {
-    int fdPmesg = -1;
-    bool klogd = property_get_bool("logd.kernel",
-                                   BOOL_DEFAULT_TRUE |
-                                   BOOL_DEFAULT_FLAG_PERSIST |
-                                   BOOL_DEFAULT_FLAG_ENG |
-                                   BOOL_DEFAULT_FLAG_SVELTE);
-    if (klogd) {
-        fdPmesg = open("/proc/kmsg", O_RDONLY | O_NDELAY);
-    }
-    fdDmesg = open("/dev/kmsg", O_WRONLY);
-
     // issue reinit command. KISS argument parsing.
     if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) {
-        int sock = TEMP_FAILURE_RETRY(
-            socket_local_client("logd",
-                                ANDROID_SOCKET_NAMESPACE_RESERVED,
-                                SOCK_STREAM));
-        if (sock < 0) {
-            return -errno;
+        return issueReinit();
+    }
+
+    static const char dev_kmsg[] = "/dev/kmsg";
+    fdDmesg = android_get_control_file(dev_kmsg);
+    if (fdDmesg < 0) {
+        fdDmesg = TEMP_FAILURE_RETRY(open(dev_kmsg, O_WRONLY | O_CLOEXEC));
+    }
+
+    int fdPmesg = -1;
+    bool klogd = __android_logger_property_get_bool("logd.kernel",
+                                                    BOOL_DEFAULT_TRUE |
+                                                    BOOL_DEFAULT_FLAG_PERSIST |
+                                                    BOOL_DEFAULT_FLAG_ENG |
+                                                    BOOL_DEFAULT_FLAG_SVELTE);
+    if (klogd) {
+        static const char proc_kmsg[] = "/proc/kmsg";
+        fdPmesg = android_get_control_file(proc_kmsg);
+        if (fdPmesg < 0) {
+            fdPmesg = TEMP_FAILURE_RETRY(open(proc_kmsg,
+                                              O_RDONLY | O_NDELAY | O_CLOEXEC));
         }
-        static const char reinit[] = "reinit";
-        ssize_t ret = TEMP_FAILURE_RETRY(write(sock, reinit, sizeof(reinit)));
-        if (ret < 0) {
-            return -errno;
-        }
-        struct pollfd p;
-        memset(&p, 0, sizeof(p));
-        p.fd = sock;
-        p.events = POLLIN;
-        ret = TEMP_FAILURE_RETRY(poll(&p, 1, 1000));
-        if (ret < 0) {
-            return -errno;
-        }
-        if ((ret == 0) || !(p.revents & POLLIN)) {
-            return -ETIME;
-        }
-        static const char success[] = "success";
-        char buffer[sizeof(success) - 1];
-        memset(buffer, 0, sizeof(buffer));
-        ret = TEMP_FAILURE_RETRY(read(sock, buffer, sizeof(buffer)));
-        if (ret < 0) {
-            return -errno;
-        }
-        return strncmp(buffer, success, sizeof(success) - 1) != 0;
+        if (fdPmesg < 0) android::prdebug("Failed to open %s\n", proc_kmsg);
     }
 
     // Reinit Thread
@@ -438,7 +451,10 @@
         pthread_attr_destroy(&attr);
     }
 
-    if (drop_privs() != 0) {
+    bool auditd = __android_logger_property_get_bool("logd.auditd",
+                                                     BOOL_DEFAULT_TRUE |
+                                                     BOOL_DEFAULT_FLAG_PERSIST);
+    if (drop_privs(klogd, auditd) != 0) {
         return -1;
     }
 
@@ -455,11 +471,11 @@
 
     signal(SIGHUP, reinit_signal_handler);
 
-    if (property_get_bool("logd.statistics",
-                          BOOL_DEFAULT_TRUE |
-                          BOOL_DEFAULT_FLAG_PERSIST |
-                          BOOL_DEFAULT_FLAG_ENG |
-                          BOOL_DEFAULT_FLAG_SVELTE)) {
+    if (__android_logger_property_get_bool("logd.statistics",
+                                           BOOL_DEFAULT_TRUE |
+                                           BOOL_DEFAULT_FLAG_PERSIST |
+                                           BOOL_DEFAULT_FLAG_ENG |
+                                           BOOL_DEFAULT_FLAG_SVELTE)) {
         logBuf->enableStatistics();
     }
 
@@ -493,17 +509,14 @@
     // 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);
+                          __android_logger_property_get_bool(
+                              "logd.auditd.dmesg",
+                              BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST)
+                                  ? fdDmesg
+                                  : -1);
     }
 
     LogKlog *kl = NULL;
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 2014374..254a3f8 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -23,12 +23,11 @@
 
 #include <string>
 
-#include <gtest/gtest.h>
-
+#include <android-base/macros.h>
 #include <android-base/stringprintf.h>
 #include <cutils/sockets.h>
+#include <gtest/gtest.h>
 #include <log/log.h>
-#include <log/logger.h>
 
 #include "../LogReader.h" // pickup LOGD_SNDTIMEO
 
@@ -213,9 +212,15 @@
         version = 1;
         break;
 
-    case sizeof(msg->entry_v2):
+    case sizeof(msg->entry_v2): /* PLUS case sizeof(msg->entry_v3): */
         if (version == 0) {
-            version = 2;
+            version = (msg->entry_v3.lid < LOG_ID_MAX) ? 3 : 2;
+        }
+        break;
+
+    case sizeof(msg->entry_v4):
+        if (version == 0) {
+            version = 4;
         }
         break;
     }
@@ -269,6 +274,11 @@
     unsigned int len = msg->entry.len;
     fprintf(stderr, "msg[%u]={", len);
     unsigned char *cp = reinterpret_cast<unsigned char *>(msg->msg());
+    if (!cp) {
+        static const unsigned char garbage[] = "<INVALID>";
+        cp = const_cast<unsigned char *>(garbage);
+        len = strlen(reinterpret_cast<const char *>(garbage));
+    }
     while(len) {
         unsigned char *p = cp;
         while (*p && (((' ' <= *p) && (*p < 0x7F)) || (*p == '\n'))) {
@@ -342,7 +352,7 @@
         "/dev/log/system", "/dev/log_system",
     };
 
-    for (unsigned int i = 0; i < (sizeof(loggers) / sizeof(loggers[0])); ++i) {
+    for (unsigned int i = 0; i < arraysize(loggers); ++i) {
         fd = open(loggers[i], O_RDONLY);
         if (fd < 0) {
             continue;
@@ -425,12 +435,12 @@
     static const unsigned int log_latency = 4;
     static const unsigned int log_delay = 5;
 
-    unsigned long ns[sizeof(benchmarks) / sizeof(benchmarks[0])];
+    unsigned long ns[arraysize(benchmarks)];
 
     memset(ns, 0, sizeof(ns));
 
     while (fgets(buffer, sizeof(buffer), fp)) {
-        for (unsigned i = 0; i < sizeof(ns) / sizeof(ns[0]); ++i) {
+        for (unsigned i = 0; i < arraysize(ns); ++i) {
             char *cp = strstr(buffer, benchmarks[i]);
             if (!cp) {
                 continue;
@@ -461,7 +471,7 @@
 
     EXPECT_GE(20000000UL, ns[log_delay]); // 10500289 user
 
-    for (unsigned i = 0; i < sizeof(ns) / sizeof(ns[0]); ++i) {
+    for (unsigned i = 0; i < arraysize(ns); ++i) {
         EXPECT_NE(0UL, ns[i]);
     }
 
diff --git a/logwrapper/Android.bp b/logwrapper/Android.bp
new file mode 100644
index 0000000..7ee0464
--- /dev/null
+++ b/logwrapper/Android.bp
@@ -0,0 +1,34 @@
+
+
+// ========================================================
+// Static and shared library
+// ========================================================
+cc_library {
+    name: "liblogwrap",
+    srcs: ["logwrap.c"],
+    shared_libs: [
+        "libcutils",
+        "liblog",
+    ],
+    export_include_dirs: ["include"],
+    local_include_dirs: ["include"],
+    cflags: [
+        "-Werror",
+    ],
+}
+
+// ========================================================
+// Executable
+// ========================================================
+cc_binary {
+    name: "logwrapper",
+    srcs: ["logwrapper.c"],
+    static_libs: [
+        "liblog",
+        "liblogwrap",
+        "libcutils",
+    ],
+    cflags: [
+        "-Werror",
+    ],
+}
diff --git a/logwrapper/Android.mk b/logwrapper/Android.mk
deleted file mode 100644
index ad45b2c..0000000
--- a/logwrapper/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# ========================================================
-# Static library
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := liblogwrap
-LOCAL_SRC_FILES := logwrap.c
-LOCAL_SHARED_LIBRARIES := libcutils liblog
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Werror -std=gnu99
-include $(BUILD_STATIC_LIBRARY)
-
-# ========================================================
-# Shared library
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := liblogwrap
-LOCAL_SHARED_LIBRARIES := libcutils liblog
-LOCAL_WHOLE_STATIC_LIBRARIES := liblogwrap
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Werror -std=gnu99
-include $(BUILD_SHARED_LIBRARY)
-
-# ========================================================
-# Executable
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= logwrapper.c
-LOCAL_MODULE := logwrapper
-LOCAL_STATIC_LIBRARIES := liblog liblogwrap libcutils
-LOCAL_CFLAGS := -Werror -std=gnu99
-include $(BUILD_EXECUTABLE)
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index 28d6de7..1bfecd6 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -14,24 +14,24 @@
  * limitations under the License.
  */
 
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <poll.h>
-#include <sys/wait.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <libgen.h>
-#include <stdbool.h>
+#include <poll.h>
 #include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
 
-#include <logwrap/logwrap.h>
-#include "private/android_filesystem_config.h"
-#include "cutils/log.h"
+#include <android/log.h>
 #include <cutils/klog.h>
+#include <logwrap/logwrap.h>
+#include <private/android_filesystem_config.h>
 
 #define ARRAY_SIZE(x)   (sizeof(x) / sizeof(*(x)))
 #define MIN(a,b) (((a)<(b))?(a):(b))
@@ -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/logwrapper/logwrapper.c b/logwrapper/logwrapper.c
index 55b71c7..28fe530 100644
--- a/logwrapper/logwrapper.c
+++ b/logwrapper/logwrapper.c
@@ -20,10 +20,9 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
-#include <logwrap/logwrap.h>
+#include <android/log.h>
 #include <cutils/klog.h>
-
-#include "cutils/log.h"
+#include <logwrap/logwrap.h>
 
 void fatal(const char *msg) {
     fprintf(stderr, "%s", msg);
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/Android.mk b/metricsd/Android.mk
deleted file mode 100644
index bb262b4..0000000
--- a/metricsd/Android.mk
+++ /dev/null
@@ -1,232 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-metrics_cpp_extension := .cc
-libmetrics_sources := \
-  c_metrics_library.cc \
-  metrics_library.cc \
-  timer.cc
-
-metrics_client_sources := \
-  metrics_client.cc
-
-metrics_collector_common := \
-  collectors/averaged_statistics_collector.cc \
-  collectors/cpu_usage_collector.cc \
-  collectors/disk_usage_collector.cc \
-  metrics_collector.cc \
-  metrics_collector_service_impl.cc \
-  persistent_integer.cc
-
-metricsd_common := \
-  persistent_integer.cc \
-  uploader/bn_metricsd_impl.cc \
-  uploader/crash_counters.cc \
-  uploader/metrics_hashes.cc \
-  uploader/metrics_log_base.cc \
-  uploader/metrics_log.cc \
-  uploader/metricsd_service_runner.cc \
-  uploader/sender_http.cc \
-  uploader/system_profile_cache.cc \
-  uploader/upload_service.cc
-
-metrics_collector_tests_sources := \
-  collectors/averaged_statistics_collector_test.cc \
-  collectors/cpu_usage_collector_test.cc \
-  metrics_collector_test.cc \
-  metrics_library_test.cc \
-  persistent_integer_test.cc \
-  timer_test.cc
-
-metricsd_tests_sources := \
-  uploader/metrics_hashes_unittest.cc \
-  uploader/metrics_log_base_unittest.cc \
-  uploader/mock/sender_mock.cc \
-  uploader/upload_service_test.cc
-
-metrics_CFLAGS := -Wall \
-  -Wno-char-subscripts \
-  -Wno-missing-field-initializers \
-  -Wno-unused-parameter \
-  -Werror \
-  -fvisibility=default
-metrics_CPPFLAGS := -Wno-non-virtual-dtor \
-  -Wno-sign-promo \
-  -Wno-strict-aliasing \
-  -fvisibility=default
-metrics_includes := external/gtest/include \
-  $(LOCAL_PATH)/include
-libmetrics_shared_libraries := libchrome libbinder libbrillo libutils
-metrics_collector_shared_libraries := $(libmetrics_shared_libraries) \
-  libbrillo-binder \
-  libbrillo-http \
-  libmetrics \
-  librootdev \
-  libweaved
-
-metrics_collector_static_libraries := libmetricscollectorservice
-
-metricsd_shared_libraries := \
-  libbinder \
-  libbrillo \
-  libbrillo-binder \
-  libbrillo-http \
-  libchrome \
-  libprotobuf-cpp-lite \
-  libupdate_engine_client \
-  libutils
-
-# Static proxy library for the metricsd binder interface.
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := metricsd_binder_proxy
-LOCAL_SHARED_LIBRARIES := libbinder libutils
-LOCAL_SRC_FILES := aidl/android/brillo/metrics/IMetricsd.aidl
-include $(BUILD_STATIC_LIBRARY)
-
-# Static library for the metrics_collector binder interface.
-# ==========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := libmetricscollectorservice
-LOCAL_CLANG := true
-LOCAL_SHARED_LIBRARIES := libbinder libbrillo-binder libchrome libutils
-LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_SRC_FILES := \
-  aidl/android/brillo/metrics/IMetricsCollectorService.aidl \
-  metrics_collector_service_client.cc
-include $(BUILD_STATIC_LIBRARY)
-
-# Shared library for metrics.
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := libmetrics
-LOCAL_C_INCLUDES := $(metrics_includes)
-LOCAL_CFLAGS := $(metrics_CFLAGS)
-LOCAL_CLANG := true
-LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
-LOCAL_CPPFLAGS := $(metrics_CPPFLAGS)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_SHARED_LIBRARIES := $(libmetrics_shared_libraries)
-LOCAL_SRC_FILES := $(libmetrics_sources)
-LOCAL_STATIC_LIBRARIES := metricsd_binder_proxy
-include $(BUILD_SHARED_LIBRARY)
-
-# CLI client for metrics.
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := metrics_client
-LOCAL_C_INCLUDES := $(metrics_includes)
-LOCAL_CFLAGS := $(metrics_CFLAGS)
-LOCAL_CLANG := true
-LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
-LOCAL_CPPFLAGS := $(metrics_CPPFLAGS)
-LOCAL_SHARED_LIBRARIES := $(libmetrics_shared_libraries) \
-  libmetrics
-LOCAL_SRC_FILES := $(metrics_client_sources)
-LOCAL_STATIC_LIBRARIES := metricsd_binder_proxy
-include $(BUILD_EXECUTABLE)
-
-# Protobuf library for metricsd.
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := metricsd_protos
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-generated_sources_dir := $(call local-generated-sources-dir)
-LOCAL_EXPORT_C_INCLUDE_DIRS += \
-    $(generated_sources_dir)/proto/system/core/metricsd
-LOCAL_SRC_FILES :=  $(call all-proto-files-under,uploader/proto)
-include $(BUILD_STATIC_LIBRARY)
-
-# metrics_collector daemon.
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := metrics_collector
-LOCAL_C_INCLUDES := $(metrics_includes)
-LOCAL_CFLAGS := $(metrics_CFLAGS)
-LOCAL_CLANG := true
-LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
-LOCAL_CPPFLAGS := $(metrics_CPPFLAGS)
-LOCAL_INIT_RC := metrics_collector.rc
-LOCAL_REQUIRED_MODULES := metrics.json
-LOCAL_SHARED_LIBRARIES := $(metrics_collector_shared_libraries)
-LOCAL_SRC_FILES := $(metrics_collector_common) \
-  metrics_collector_main.cc
-LOCAL_STATIC_LIBRARIES := metricsd_binder_proxy \
-  $(metrics_collector_static_libraries)
-include $(BUILD_EXECUTABLE)
-
-# metricsd daemon.
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := metricsd
-LOCAL_C_INCLUDES := $(metrics_includes)
-LOCAL_CFLAGS := $(metrics_CFLAGS)
-LOCAL_CLANG := true
-LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
-LOCAL_CPPFLAGS := $(metrics_CPPFLAGS)
-LOCAL_INIT_RC := metricsd.rc
-LOCAL_REQUIRED_MODULES := \
-  metrics_collector
-LOCAL_SHARED_LIBRARIES := $(metricsd_shared_libraries)
-LOCAL_STATIC_LIBRARIES := metricsd_protos metricsd_binder_proxy
-LOCAL_SRC_FILES := $(metricsd_common) \
-  metricsd_main.cc
-include $(BUILD_EXECUTABLE)
-
-# Unit tests for metricsd.
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := metricsd_tests
-LOCAL_CFLAGS := $(metrics_CFLAGS)
-LOCAL_CLANG := true
-LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
-LOCAL_CPPFLAGS := $(metrics_CPPFLAGS) -Wno-sign-compare
-LOCAL_SHARED_LIBRARIES := $(metricsd_shared_libraries)
-LOCAL_SRC_FILES := $(metricsd_tests_sources) $(metricsd_common)
-LOCAL_STATIC_LIBRARIES := libBionicGtestMain libgmock metricsd_protos metricsd_binder_proxy
-ifdef BRILLO
-LOCAL_MODULE_TAGS := eng
-endif
-include $(BUILD_NATIVE_TEST)
-
-# Unit tests for metrics_collector.
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := metrics_collector_tests
-LOCAL_CFLAGS := $(metrics_CFLAGS)
-LOCAL_CLANG := true
-LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
-LOCAL_CPPFLAGS := $(metrics_CPPFLAGS) -Wno-sign-compare
-LOCAL_SHARED_LIBRARIES := $(metrics_collector_shared_libraries)
-LOCAL_SRC_FILES := $(metrics_collector_tests_sources) \
-  $(metrics_collector_common)
-LOCAL_STATIC_LIBRARIES := libBionicGtestMain libgmock metricsd_binder_proxy \
-  $(metrics_collector_static_libraries)
-ifdef BRILLO
-LOCAL_MODULE_TAGS := eng
-endif
-include $(BUILD_NATIVE_TEST)
-
-# Weave schema files
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := metrics.json
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/weaved/traits
-LOCAL_SRC_FILES := etc/weaved/traits/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
diff --git a/metricsd/OWNERS b/metricsd/OWNERS
deleted file mode 100644
index 7f5e50d..0000000
--- a/metricsd/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-semenzato@chromium.org
-derat@chromium.org
-bsimonnet@chromium.org
diff --git a/metricsd/README.md b/metricsd/README.md
deleted file mode 100644
index 8d4828c..0000000
--- a/metricsd/README.md
+++ /dev/null
@@ -1,124 +0,0 @@
-Metricsd
-========
-
-The metricsd daemon is used to gather metrics from the platform and application,
-aggregate them and upload them periodically to a server.
-The metrics will then be available in their aggregated form to the developer
-for analysis.
-
-Three components are provided to interact with `metricsd`: `libmetrics`,
-`metrics_collector` and `metrics_client`.
-
-The Metrics Library: libmetrics
--------------------------------
-
-`libmetrics` is a small library that implements the basic C++ API for
-metrics collection. All metrics collection is funneled through this library. The
-easiest and recommended way for a client-side module to collect user metrics is
-to link `libmetrics` and use its APIs to send metrics to `metricsd` for transport to
-UMA. In order to use the library in a module, you need to do the following:
-
-- Add a dependency on the shared library in your Android.mk file:
-  `LOCAL_SHARED_LIBRARIES += libmetrics`
-
-- To access the metrics library API in the module, include the
-  <metrics/metrics_library.h> header file.
-
-- The API is documented in `metrics_library.h`. Before using the API methods, a
-  MetricsLibrary object needs to be constructed and initialized through its
-  Init method.
-
-- Samples are uploaded only if the `/data/misc/metrics/enabled` file exists.
-
-
-Server Side
------------
-
-You will be able to see all uploaded metrics on the metrics dashboard,
-accessible via the developer console.
-
-*** note
-It usually takes a day for metrics to be available on the dashboard.
-***
-
-
-The Metrics Client: metrics_client
-----------------------------------
-
-`metrics_client` is a simple shell command-line utility for sending histogram
-samples and querying `metricsd`. It's installed under `/system/bin` on the target
-platform and uses `libmetrics`.
-
-For usage information and command-line options, run `metrics_client` on the
-target platform or look for "Usage:" in `metrics_client.cc`.
-
-
-The Metrics Daemon: metricsd
-----------------------------
-
-`metricsd` is the daemon that listens for metrics logging calls (via Binder),
-aggregates the metrics and uploads them periodically. This daemon should start as
-early as possible so that depending daemons can log at any time.
-
-`metricsd` is made of two threads that work as follows:
-
-* The binder thread listens for one-way Binder calls, aggregates the metrics in
-  memory (via `base::StatisticsRecorder`) and increments the crash counters when a
-  crash is reported. This thread is kept as simple as possible to ensure the
-  maximum throughput possible.
-* The uploader thread takes care of backing up the metrics to disk periodically
-  (to avoid losing metrics on crashes), collecting metadata about the client
-  (version number, channel, etc..) and uploading the metrics periodically to the
-  server.
-
-
-The Metrics Collector: metrics_collector
-----------------------------------------
-
-metrics_collector is a daemon that runs in the background on the target platform,
-gathers health information about the system and maintains long running counters
-(ex: number of crashes per week).
-
-The recommended way to generate metrics data from a module is to link and use
-libmetrics directly. However, we may not want to add a dependency on libmetrics
-to some modules (ex: kernel). In this case, we can add a collector to
-metrics_collector that will, for example, take measurements and report them
-periodically to metricsd (this is the case for the disk utilization histogram).
-
-
-FAQ
----
-
-### What should my histogram's |min| and |max| values be set at?
-
-You should set the values to a range that covers the vast majority of samples
-that would appear in the field. Note that samples below the |min| will still
-be collected in the underflow bucket and samples above the |max| will end up
-in the overflow bucket. Also, the reported mean of the data will be correct
-regardless of the range.
-
-### How many buckets should I use in my histogram?
-
-You should allocate as many buckets as necessary to perform proper analysis
-on the collected data. Note, however, that the memory allocated in metricsd
-for each histogram is proportional to the number of buckets. Therefore, it is
-strongly recommended to keep this number low (e.g., 50 is normal, while 100
-is probably high).
-
-### When should I use an enumeration (linear) histogram vs. a regular (exponential) histogram?
-
-Enumeration histograms should really be used only for sampling enumerated
-events and, in some cases, percentages. Normally, you should use a regular
-histogram with exponential bucket layout that provides higher resolution at
-the low end of the range and lower resolution at the high end. Regular
-histograms are generally used for collecting performance data (e.g., timing,
-memory usage, power) as well as aggregated event counts.
-
-### How can I test that my histogram was reported correctly?
-
-* Make sure no error messages appear in logcat when you log a sample.
-* Run `metrics_client -d` to dump the currently aggregated metrics. Your
-  histogram should appear in the list.
-* Make sure that the aggregated metrics were uploaded to the server successfully
-  (check for an OK message from `metricsd` in logcat).
-* After a day, your histogram should be available on the dashboard.
diff --git a/metricsd/WATCHLISTS b/metricsd/WATCHLISTS
deleted file mode 100644
index a051f35..0000000
--- a/metricsd/WATCHLISTS
+++ /dev/null
@@ -1,16 +0,0 @@
-# See http://dev.chromium.org/developers/contributing-code/watchlists for
-# a description of this file's format.
-# Please keep these keys in alphabetical order.
-
-{
-  'WATCHLIST_DEFINITIONS': {
-    'all': {
-      'filepath': '.',
-    },
-  },
-  'WATCHLISTS': {
-    'all': ['petkov@chromium.org',
-                'semenzato@chromium.org',
-                'sosa@chromium.org']
-  },
-}
diff --git a/metricsd/aidl/android/brillo/metrics/IMetricsd.aidl b/metricsd/aidl/android/brillo/metrics/IMetricsd.aidl
deleted file mode 100644
index aa3cb34..0000000
--- a/metricsd/aidl/android/brillo/metrics/IMetricsd.aidl
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.brillo.metrics;
-
-interface IMetricsd {
-  oneway void recordHistogram(String name, int sample, int min, int max,
-                              int nbuckets);
-  oneway void recordLinearHistogram(String name, int sample, int max);
-  oneway void recordSparseHistogram(String name, int sample);
-  oneway void recordCrash(String type);
-  String getHistogramsDump();
-}
diff --git a/metricsd/c_metrics_library.cc b/metricsd/c_metrics_library.cc
deleted file mode 100644
index 47a543e..0000000
--- a/metricsd/c_metrics_library.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//
-// C wrapper to libmetrics
-//
-
-#include "metrics/c_metrics_library.h"
-
-#include <string>
-
-#include "metrics/metrics_library.h"
-
-extern "C" CMetricsLibrary CMetricsLibraryNew(void) {
-  MetricsLibrary* lib = new MetricsLibrary;
-  return reinterpret_cast<CMetricsLibrary>(lib);
-}
-
-extern "C" void CMetricsLibraryDelete(CMetricsLibrary handle) {
-  MetricsLibrary* lib = reinterpret_cast<MetricsLibrary*>(handle);
-  delete lib;
-}
-
-extern "C" void CMetricsLibraryInit(CMetricsLibrary handle) {
-  MetricsLibrary* lib = reinterpret_cast<MetricsLibrary*>(handle);
-  if (lib != NULL)
-    lib->Init();
-}
-
-extern "C" int CMetricsLibrarySendToUMA(CMetricsLibrary handle,
-                                        const char* name, int sample,
-                                        int min, int max, int nbuckets) {
-  MetricsLibrary* lib = reinterpret_cast<MetricsLibrary*>(handle);
-  if (lib == NULL)
-    return 0;
-  return lib->SendToUMA(std::string(name), sample, min, max, nbuckets);
-}
-
-extern "C" int CMetricsLibrarySendEnumToUMA(CMetricsLibrary handle,
-                                            const char* name, int sample,
-                                            int max) {
-  MetricsLibrary* lib = reinterpret_cast<MetricsLibrary*>(handle);
-  if (lib == NULL)
-    return 0;
-  return lib->SendEnumToUMA(std::string(name), sample, max);
-}
-
-extern "C" int CMetricsLibrarySendSparseToUMA(CMetricsLibrary handle,
-                                              const char* name, int sample) {
-  MetricsLibrary* lib = reinterpret_cast<MetricsLibrary*>(handle);
-  if (lib == NULL)
-    return 0;
-  return lib->SendSparseToUMA(std::string(name), sample);
-}
-
-extern "C" int CMetricsLibrarySendCrashToUMA(CMetricsLibrary handle,
-                                            const char* crash_kind) {
-  MetricsLibrary* lib = reinterpret_cast<MetricsLibrary*>(handle);
-  if (lib == NULL)
-    return 0;
-  return lib->SendCrashToUMA(crash_kind);
-}
-
-extern "C" int CMetricsLibraryAreMetricsEnabled(CMetricsLibrary handle) {
-  MetricsLibrary* lib = reinterpret_cast<MetricsLibrary*>(handle);
-  if (lib == NULL)
-    return 0;
-  return lib->AreMetricsEnabled();
-}
diff --git a/metricsd/collectors/averaged_statistics_collector.cc b/metricsd/collectors/averaged_statistics_collector.cc
deleted file mode 100644
index a3aaa98..0000000
--- a/metricsd/collectors/averaged_statistics_collector.cc
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "averaged_statistics_collector.h"
-
-#include <base/bind.h>
-#include <base/files/file_util.h>
-#include <base/files/file_path.h>
-#include <base/strings/string_number_conversions.h>
-#include <base/strings/string_split.h>
-
-#include "metrics_collector.h"
-
-namespace {
-
-// disk stats metrics
-
-// The {Read,Write}Sectors numbers are in sectors/second.
-// A sector is usually 512 bytes.
-const char kReadSectorsHistogramName[] = "Platform.ReadSectors";
-const char kWriteSectorsHistogramName[] = "Platform.WriteSectors";
-const int kDiskMetricsStatItemCount = 11;
-
-// Assume a max rate of 250Mb/s for reads (worse for writes) and 512 byte
-// sectors.
-const int kSectorsIOMax = 500000;  // sectors/second
-const int kSectorsBuckets = 50;    // buckets
-
-// Page size is 4k, sector size is 0.5k.  We're not interested in page fault
-// rates that the disk cannot sustain.
-const int kPageFaultsMax = kSectorsIOMax / 8;  // Page faults/second
-const int kPageFaultsBuckets = 50;
-
-// Major page faults, i.e. the ones that require data to be read from disk.
-const char kPageFaultsHistogramName[] = "Platform.PageFaults";
-
-// Swap in and Swap out
-const char kSwapInHistogramName[] = "Platform.SwapIn";
-const char kSwapOutHistogramName[] = "Platform.SwapOut";
-
-const int kIntervalBetweenCollection = 60;  // seconds
-const int kCollectionDuration = 1;  // seconds
-
-}  // namespace
-
-AveragedStatisticsCollector::AveragedStatisticsCollector(
-    MetricsLibraryInterface* metrics_library,
-    const std::string& diskstats_path,
-    const std::string& vmstats_path) :
-  metrics_lib_(metrics_library),
-  diskstats_path_(diskstats_path),
-  vmstats_path_(vmstats_path) {
-}
-
-void AveragedStatisticsCollector::ScheduleWait() {
-  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-      base::Bind(&AveragedStatisticsCollector::WaitCallback,
-                 base::Unretained(this)),
-      base::TimeDelta::FromSeconds(
-          kIntervalBetweenCollection - kCollectionDuration));
-}
-
-void AveragedStatisticsCollector::ScheduleCollect() {
-  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-      base::Bind(&AveragedStatisticsCollector::CollectCallback,
-                 base::Unretained(this)),
-      base::TimeDelta::FromSeconds(kCollectionDuration));
-}
-
-void AveragedStatisticsCollector::WaitCallback() {
-  ReadInitialValues();
-  ScheduleCollect();
-}
-
-void AveragedStatisticsCollector::CollectCallback() {
-  Collect();
-  ScheduleWait();
-}
-
-void AveragedStatisticsCollector::ReadInitialValues() {
-  stats_start_time_ = MetricsCollector::GetActiveTime();
-  DiskStatsReadStats(&read_sectors_, &write_sectors_);
-  VmStatsReadStats(&vmstats_);
-}
-
-bool AveragedStatisticsCollector::DiskStatsReadStats(
-    uint64_t* read_sectors, uint64_t* write_sectors) {
-  CHECK(read_sectors);
-  CHECK(write_sectors);
-  std::string line;
-  if (diskstats_path_.empty()) {
-    return false;
-  }
-
-  if (!base::ReadFileToString(base::FilePath(diskstats_path_), &line)) {
-    PLOG(WARNING) << "Could not read disk stats from "
-                  << diskstats_path_.value();
-    return false;
-  }
-
-  std::vector<std::string> parts = base::SplitString(
-      line, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
-  if (parts.size() != kDiskMetricsStatItemCount) {
-    LOG(ERROR) << "Could not parse disk stat correctly. Expected "
-               << kDiskMetricsStatItemCount << " elements but got "
-               << parts.size();
-    return false;
-  }
-  if (!base::StringToUint64(parts[2], read_sectors)) {
-    LOG(ERROR) << "Couldn't convert read sectors " << parts[2] << " to uint64";
-    return false;
-  }
-  if (!base::StringToUint64(parts[6], write_sectors)) {
-    LOG(ERROR) << "Couldn't convert write sectors " << parts[6] << " to uint64";
-    return false;
-  }
-
-  return true;
-}
-
-bool AveragedStatisticsCollector::VmStatsParseStats(
-    const char* stats, struct VmstatRecord* record) {
-  CHECK(stats);
-  CHECK(record);
-  base::StringPairs pairs;
-  base::SplitStringIntoKeyValuePairs(stats, ' ', '\n', &pairs);
-
-  for (base::StringPairs::iterator it = pairs.begin();
-       it != pairs.end(); ++it) {
-    if (it->first == "pgmajfault" &&
-        !base::StringToUint64(it->second, &record->page_faults)) {
-      return false;
-    }
-    if (it->first == "pswpin" &&
-        !base::StringToUint64(it->second, &record->swap_in)) {
-      return false;
-    }
-    if (it->first == "pswpout" &&
-        !base::StringToUint64(it->second, &record->swap_out)) {
-      return false;
-    }
-  }
-  return true;
-}
-
-bool AveragedStatisticsCollector::VmStatsReadStats(struct VmstatRecord* stats) {
-  CHECK(stats);
-  std::string value_string;
-  if (!base::ReadFileToString(vmstats_path_, &value_string)) {
-    LOG(WARNING) << "cannot read " << vmstats_path_.value();
-    return false;
-  }
-  return VmStatsParseStats(value_string.c_str(), stats);
-}
-
-void AveragedStatisticsCollector::Collect() {
-  uint64_t read_sectors_now, write_sectors_now;
-  struct VmstatRecord vmstats_now;
-  double time_now = MetricsCollector::GetActiveTime();
-  double delta_time = time_now - stats_start_time_;
-  bool diskstats_success = DiskStatsReadStats(&read_sectors_now,
-                                              &write_sectors_now);
-
-  int delta_read = read_sectors_now - read_sectors_;
-  int delta_write = write_sectors_now - write_sectors_;
-  int read_sectors_per_second = delta_read / delta_time;
-  int write_sectors_per_second = delta_write / delta_time;
-  bool vmstats_success = VmStatsReadStats(&vmstats_now);
-  uint64_t delta_faults = vmstats_now.page_faults - vmstats_.page_faults;
-  uint64_t delta_swap_in = vmstats_now.swap_in - vmstats_.swap_in;
-  uint64_t delta_swap_out = vmstats_now.swap_out - vmstats_.swap_out;
-  uint64_t page_faults_per_second = delta_faults / delta_time;
-  uint64_t swap_in_per_second = delta_swap_in / delta_time;
-  uint64_t swap_out_per_second = delta_swap_out / delta_time;
-  if (diskstats_success) {
-    metrics_lib_->SendToUMA(kReadSectorsHistogramName,
-                            read_sectors_per_second,
-                            1,
-                            kSectorsIOMax,
-                            kSectorsBuckets);
-    metrics_lib_->SendToUMA(kWriteSectorsHistogramName,
-                            write_sectors_per_second,
-                            1,
-                            kSectorsIOMax,
-                            kSectorsBuckets);
-  }
-  if (vmstats_success) {
-    metrics_lib_->SendToUMA(kPageFaultsHistogramName,
-                            page_faults_per_second,
-                            1,
-                            kPageFaultsMax,
-                            kPageFaultsBuckets);
-    metrics_lib_->SendToUMA(kSwapInHistogramName,
-                            swap_in_per_second,
-                            1,
-                            kPageFaultsMax,
-                            kPageFaultsBuckets);
-    metrics_lib_->SendToUMA(kSwapOutHistogramName,
-                            swap_out_per_second,
-                            1,
-                            kPageFaultsMax,
-                            kPageFaultsBuckets);
-  }
-}
diff --git a/metricsd/collectors/averaged_statistics_collector.h b/metricsd/collectors/averaged_statistics_collector.h
deleted file mode 100644
index 753f70c..0000000
--- a/metricsd/collectors/averaged_statistics_collector.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICSD_COLLECTORS_AVERAGED_STATISTICS_COLLECTOR_H_
-#define METRICSD_COLLECTORS_AVERAGED_STATISTICS_COLLECTOR_H_
-
-#include "metrics/metrics_library.h"
-
-class AveragedStatisticsCollector {
- public:
-  AveragedStatisticsCollector(MetricsLibraryInterface* metrics_library,
-                              const std::string& diskstats_path,
-                              const std::string& vmstat_path);
-
-  // Schedule a wait period.
-  void ScheduleWait();
-
-  // Schedule a collection period.
-  void ScheduleCollect();
-
-  // Callback used by the main loop.
-  void CollectCallback();
-
-  // Callback used by the main loop.
-  void WaitCallback();
-
-  // Read and store the initial values at the beginning of a collection cycle.
-  void ReadInitialValues();
-
-  // Collect the disk usage statistics and report them.
-  void Collect();
-
- private:
-  friend class AveragedStatisticsTest;
-  FRIEND_TEST(AveragedStatisticsTest, ParseDiskStats);
-  FRIEND_TEST(AveragedStatisticsTest, ParseVmStats);
-
-  // Record for retrieving and reporting values from /proc/vmstat
-  struct VmstatRecord {
-    uint64_t page_faults;    // major faults
-    uint64_t swap_in;        // pages swapped in
-    uint64_t swap_out;       // pages swapped out
-  };
-
-  // Read the disk read/write statistics for the main disk.
-  bool DiskStatsReadStats(uint64_t* read_sectors, uint64_t* write_sectors);
-
-  // Parse the content of the vmstats file into |record|.
-  bool VmStatsParseStats(const char* stats, struct VmstatRecord* record);
-
-  // Read the vmstats into |stats|.
-  bool VmStatsReadStats(struct VmstatRecord* stats);
-
-  MetricsLibraryInterface* metrics_lib_;
-  base::FilePath diskstats_path_;
-  base::FilePath vmstats_path_;
-
-  // Values observed at the beginning of the collection period.
-  uint64_t read_sectors_;
-  uint64_t write_sectors_;
-  struct VmstatRecord vmstats_;
-
-  double stats_start_time_;
-};
-
-#endif  // METRICSD_COLLECTORS_AVERAGED_STATISTICS_COLLECTOR_H_
diff --git a/metricsd/collectors/averaged_statistics_collector_test.cc b/metricsd/collectors/averaged_statistics_collector_test.cc
deleted file mode 100644
index 68f9f2f..0000000
--- a/metricsd/collectors/averaged_statistics_collector_test.cc
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "averaged_statistics_collector.h"
-
-#include <memory>
-
-#include <inttypes.h>
-
-#include <base/files/file_util.h>
-#include <base/files/scoped_temp_dir.h>
-#include <base/strings/stringprintf.h>
-#include <gtest/gtest.h>
-
-
-static const char kFakeDiskStatsFormat[] =
-    "    1793     1788    %" PRIu64 "   105580    "
-    "    196      175     %" PRIu64 "    30290    "
-    "    0    44060   135850\n";
-static const uint64_t kFakeReadSectors[] = {80000, 100000};
-static const uint64_t kFakeWriteSectors[] = {3000, 4000};
-
-
-class AveragedStatisticsTest : public testing::Test {
- protected:
-  std::string kFakeDiskStats0;
-  std::string kFakeDiskStats1;
-
-  virtual void SetUp() {
-    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    disk_stats_path_ = temp_dir_.path().Append("disk_stats");
-    collector_.reset(new AveragedStatisticsCollector(
-        &metrics_lib_, disk_stats_path_.value(), ""));
-
-    kFakeDiskStats0 = base::StringPrintf(kFakeDiskStatsFormat,
-                                         kFakeReadSectors[0],
-                                         kFakeWriteSectors[0]);
-    kFakeDiskStats1 = base::StringPrintf(kFakeDiskStatsFormat,
-                                         kFakeReadSectors[1],
-                                         kFakeWriteSectors[1]);
-
-    CreateFakeDiskStatsFile(kFakeDiskStats0);
-  }
-
-  // Creates or overwrites an input file containing fake disk stats.
-  void CreateFakeDiskStatsFile(const std::string& fake_stats) {
-    EXPECT_EQ(base::WriteFile(disk_stats_path_,
-                              fake_stats.data(), fake_stats.size()),
-              fake_stats.size());
-  }
-
-  // Collector used for tests.
-  std::unique_ptr<AveragedStatisticsCollector> collector_;
-
-  // Temporary directory used for tests.
-  base::ScopedTempDir temp_dir_;
-
-  // Path for the fake files.
-  base::FilePath disk_stats_path_;
-
-  MetricsLibrary metrics_lib_;
-};
-
-TEST_F(AveragedStatisticsTest, ParseDiskStats) {
-  uint64_t read_sectors_now, write_sectors_now;
-  CreateFakeDiskStatsFile(kFakeDiskStats0);
-  ASSERT_TRUE(collector_->DiskStatsReadStats(&read_sectors_now,
-                                             &write_sectors_now));
-  EXPECT_EQ(read_sectors_now, kFakeReadSectors[0]);
-  EXPECT_EQ(write_sectors_now, kFakeWriteSectors[0]);
-
-  CreateFakeDiskStatsFile(kFakeDiskStats1);
-  ASSERT_TRUE(collector_->DiskStatsReadStats(&read_sectors_now,
-                                             &write_sectors_now));
-  EXPECT_EQ(read_sectors_now, kFakeReadSectors[1]);
-  EXPECT_EQ(write_sectors_now, kFakeWriteSectors[1]);
-}
-
-TEST_F(AveragedStatisticsTest, ParseVmStats) {
-  static char kVmStats[] = "pswpin 1345\npswpout 8896\n"
-    "foo 100\nbar 200\npgmajfault 42\netcetc 300\n";
-  struct AveragedStatisticsCollector::VmstatRecord stats;
-  EXPECT_TRUE(collector_->VmStatsParseStats(kVmStats, &stats));
-  EXPECT_EQ(stats.page_faults, 42);
-  EXPECT_EQ(stats.swap_in, 1345);
-  EXPECT_EQ(stats.swap_out, 8896);
-}
diff --git a/metricsd/collectors/cpu_usage_collector.cc b/metricsd/collectors/cpu_usage_collector.cc
deleted file mode 100644
index 9b0bb34..0000000
--- a/metricsd/collectors/cpu_usage_collector.cc
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "collectors/cpu_usage_collector.h"
-
-#include <base/bind.h>
-#include <base/files/file_path.h>
-#include <base/files/file_util.h>
-#include <base/message_loop/message_loop.h>
-#include <base/strings/string_number_conversions.h>
-#include <base/strings/string_split.h>
-#include <base/strings/string_util.h>
-#include <base/sys_info.h>
-
-#include "metrics/metrics_library.h"
-
-namespace {
-
-const char kCpuUsagePercent[] = "Platform.CpuUsage.Percent";
-const char kMetricsProcStatFileName[] = "/proc/stat";
-const int kMetricsProcStatFirstLineItemsCount = 11;
-
-// Collect every minute.
-const int kCollectionIntervalSecs = 60;
-
-}  // namespace
-
-using base::TimeDelta;
-
-CpuUsageCollector::CpuUsageCollector(MetricsLibraryInterface* metrics_library) {
-  CHECK(metrics_library);
-  metrics_lib_ = metrics_library;
-  collect_interval_ = TimeDelta::FromSeconds(kCollectionIntervalSecs);
-}
-
-void CpuUsageCollector::Init() {
-  num_cpu_ = base::SysInfo::NumberOfProcessors();
-
-  // Get ticks per second (HZ) on this system.
-  // Sysconf cannot fail, so no sanity checks are needed.
-  ticks_per_second_ = sysconf(_SC_CLK_TCK);
-  CHECK_GT(ticks_per_second_, uint64_t(0))
-      << "Number of ticks per seconds should be positive.";
-
-  latest_cpu_use_ = GetCumulativeCpuUse();
-}
-
-void CpuUsageCollector::CollectCallback() {
-  Collect();
-  Schedule();
-}
-
-void CpuUsageCollector::Schedule() {
-  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-      base::Bind(&CpuUsageCollector::CollectCallback, base::Unretained(this)),
-      collect_interval_);
-}
-
-void CpuUsageCollector::Collect() {
-  TimeDelta cpu_use = GetCumulativeCpuUse();
-  TimeDelta diff_per_cpu = (cpu_use - latest_cpu_use_) / num_cpu_;
-  latest_cpu_use_ = cpu_use;
-
-  // Report the cpu usage as a percentage of the total cpu usage possible.
-  int percent_use = diff_per_cpu.InMilliseconds() * 100 /
-      (kCollectionIntervalSecs * 1000);
-
-  metrics_lib_->SendEnumToUMA(kCpuUsagePercent, percent_use, 101);
-}
-
-TimeDelta CpuUsageCollector::GetCumulativeCpuUse() {
-  base::FilePath proc_stat_path(kMetricsProcStatFileName);
-  std::string proc_stat_string;
-  if (!base::ReadFileToString(proc_stat_path, &proc_stat_string)) {
-    LOG(WARNING) << "cannot open " << kMetricsProcStatFileName;
-    return TimeDelta();
-  }
-
-  uint64_t user_ticks, user_nice_ticks, system_ticks;
-  if (!ParseProcStat(proc_stat_string, &user_ticks, &user_nice_ticks,
-                     &system_ticks)) {
-    return TimeDelta();
-  }
-
-  uint64_t total = user_ticks + user_nice_ticks + system_ticks;
-  return TimeDelta::FromMicroseconds(
-      total * 1000 * 1000 / ticks_per_second_);
-}
-
-bool CpuUsageCollector::ParseProcStat(const std::string& stat_content,
-                                      uint64_t *user_ticks,
-                                      uint64_t *user_nice_ticks,
-                                      uint64_t *system_ticks) {
-  std::vector<std::string> proc_stat_lines = base::SplitString(
-      stat_content, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-  if (proc_stat_lines.empty()) {
-    LOG(WARNING) << "No lines found in " << kMetricsProcStatFileName;
-    return false;
-  }
-  std::vector<std::string> proc_stat_totals =
-      base::SplitString(proc_stat_lines[0], base::kWhitespaceASCII,
-                        base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
-
-  if (proc_stat_totals.size() != kMetricsProcStatFirstLineItemsCount ||
-      proc_stat_totals[0] != "cpu" ||
-      !base::StringToUint64(proc_stat_totals[1], user_ticks) ||
-      !base::StringToUint64(proc_stat_totals[2], user_nice_ticks) ||
-      !base::StringToUint64(proc_stat_totals[3], system_ticks)) {
-    LOG(WARNING) << "cannot parse first line: " << proc_stat_lines[0];
-    return false;
-  }
-  return true;
-}
diff --git a/metricsd/collectors/cpu_usage_collector.h b/metricsd/collectors/cpu_usage_collector.h
deleted file mode 100644
index f81dfcb..0000000
--- a/metricsd/collectors/cpu_usage_collector.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICSD_COLLECTORS_CPU_USAGE_COLLECTOR_H_
-#define METRICSD_COLLECTORS_CPU_USAGE_COLLECTOR_H_
-
-#include <base/time/time.h>
-
-#include "metrics/metrics_library.h"
-
-class CpuUsageCollector {
- public:
-  CpuUsageCollector(MetricsLibraryInterface* metrics_library);
-
-  // Initialize this collector's state.
-  void Init();
-
-  // Schedule a collection interval.
-  void Schedule();
-
-  // Callback called at the end of the collection interval.
-  void CollectCallback();
-
-  // Measure the cpu use and report it.
-  void Collect();
-
-  // Gets the current cumulated Cpu usage.
-  base::TimeDelta GetCumulativeCpuUse();
-
- private:
-  FRIEND_TEST(CpuUsageTest, ParseProcStat);
-  bool ParseProcStat(const std::string& stat_content,
-                     uint64_t *user_ticks,
-                     uint64_t *user_nice_ticks,
-                     uint64_t *system_ticks);
-
-  int num_cpu_;
-  uint32_t ticks_per_second_;
-
-  base::TimeDelta collect_interval_;
-  base::TimeDelta latest_cpu_use_;
-
-  MetricsLibraryInterface* metrics_lib_;
-};
-
-#endif  // METRICSD_COLLECTORS_CPU_USAGE_COLLECTOR_H_
diff --git a/metricsd/collectors/cpu_usage_collector_test.cc b/metricsd/collectors/cpu_usage_collector_test.cc
deleted file mode 100644
index ee5c92b..0000000
--- a/metricsd/collectors/cpu_usage_collector_test.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-
-#include "collectors/cpu_usage_collector.h"
-#include "metrics/metrics_library_mock.h"
-
-
-TEST(CpuUsageTest, ParseProcStat) {
-  MetricsLibraryMock metrics_lib_mock;
-  CpuUsageCollector collector(&metrics_lib_mock);
-  std::vector<std::string> invalid_contents = {
-    "",
-    // First line does not start with cpu.
-    "spu  17191 11 36579 151118 289 0 2 0 0 0\n"
-    "cpu0 1564 2 866 48650 68 0 2 0 0 0\n"
-    "cpu1 14299 0 35116 1844 81 0 0 0 0 0\n",
-    // One of the field is not a number.
-    "cpu  a17191 11 36579 151118 289 0 2 0 0 0",
-    // To many numbers in the first line.
-    "cpu  17191 11 36579 151118 289 0 2 0 0 0 102"
-  };
-
-  uint64_t user, nice, system;
-  for (int i = 0; i < invalid_contents.size(); i++) {
-    ASSERT_FALSE(collector.ParseProcStat(invalid_contents[i], &user, &nice,
-                                         &system));
-  }
-
-  ASSERT_TRUE(collector.ParseProcStat(
-      std::string("cpu  17191 11 36579 151118 289 0 2 0 0 0"),
-      &user, &nice, &system));
-  ASSERT_EQ(17191, user);
-  ASSERT_EQ(11, nice);
-  ASSERT_EQ(36579, system);
-}
diff --git a/metricsd/collectors/disk_usage_collector.cc b/metricsd/collectors/disk_usage_collector.cc
deleted file mode 100644
index 5ab51fb..0000000
--- a/metricsd/collectors/disk_usage_collector.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "collectors/disk_usage_collector.h"
-
-#include <base/bind.h>
-#include <base/bind_helpers.h>
-#include <base/message_loop/message_loop.h>
-#include <sys/statvfs.h>
-
-#include "metrics/metrics_library.h"
-
-namespace {
-
-const char kDiskUsageMB[] = "Platform.DataPartitionUsed.MB";
-const char kDiskUsagePercent[] = "Platform.DataPartitionUsed.Percent";
-const char kDataPartitionPath[] = "/data";
-
-// Collect every 15 minutes.
-const int kDiskUsageCollectorIntervalSeconds = 900;
-
-}  // namespace
-
-DiskUsageCollector::DiskUsageCollector(
-    MetricsLibraryInterface* metrics_library) {
-  collect_interval_ = base::TimeDelta::FromSeconds(
-      kDiskUsageCollectorIntervalSeconds);
-  CHECK(metrics_library);
-  metrics_lib_ = metrics_library;
-}
-
-void DiskUsageCollector::Collect() {
-  struct statvfs buf;
-  int result = statvfs(kDataPartitionPath, &buf);
-  if (result != 0) {
-    PLOG(ERROR) << "Failed to check the available space in "
-                << kDataPartitionPath;
-    return;
-  }
-
-  unsigned long total_space = buf.f_blocks * buf.f_bsize;
-  unsigned long used_space = (buf.f_blocks - buf.f_bfree) * buf.f_bsize;
-  int percent_used = (used_space * 100) / total_space;
-
-  metrics_lib_->SendToUMA(kDiskUsageMB,
-                          used_space / (1024 * 1024),
-                          0,
-                          1024, // up to 1 GB.
-                          100);
-  metrics_lib_->SendEnumToUMA(kDiskUsagePercent, percent_used, 101);
-}
-
-void DiskUsageCollector::CollectCallback() {
-  Collect();
-  Schedule();
-}
-
-void DiskUsageCollector::Schedule() {
-  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-      base::Bind(&DiskUsageCollector::CollectCallback, base::Unretained(this)),
-      collect_interval_);
-}
diff --git a/metricsd/collectors/disk_usage_collector.h b/metricsd/collectors/disk_usage_collector.h
deleted file mode 100644
index c1d4546..0000000
--- a/metricsd/collectors/disk_usage_collector.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICSD_COLLECTORS_DISK_USAGE_COLLECTOR_H_
-#define METRICSD_COLLECTORS_DISK_USAGE_COLLECTOR_H_
-
-#include <base/time/time.h>
-
-#include "metrics/metrics_library.h"
-
-class DiskUsageCollector {
- public:
-  DiskUsageCollector(MetricsLibraryInterface* metrics_library);
-
-  // Schedule the next collection.
-  void Schedule();
-
-  // Callback used by the main loop.
-  void CollectCallback();
-
-  // Collect the disk usage statistics and report them.
-  void Collect();
-
- private:
-  base::TimeDelta collect_interval_;
-  MetricsLibraryInterface* metrics_lib_;
-};
-
-#endif  // METRICSD_COLLECTORS_DISK_USAGE_COLLECTOR_H_
diff --git a/metricsd/constants.h b/metricsd/constants.h
deleted file mode 100644
index b702737..0000000
--- a/metricsd/constants.h
+++ /dev/null
@@ -1,42 +0,0 @@
-//
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-#ifndef METRICS_CONSTANTS_H_
-#define METRICS_CONSTANTS_H_
-
-namespace metrics {
-static const char kSharedMetricsDirectory[] = "/data/misc/metrics/";
-static const char kMetricsdDirectory[] = "/data/misc/metricsd/";
-static const char kMetricsCollectorDirectory[] =
-    "/data/misc/metrics_collector/";
-static const char kMetricsGUIDFileName[] = "Sysinfo.GUID";
-static const char kMetricsServer[] = "https://clients4.google.com/uma/v2";
-static const char kConsentFileName[] = "enabled";
-static const char kStagedLogName[] = "staged_log";
-static const char kSavedLogName[] = "saved_log";
-static const char kFailedUploadCountName[] = "failed_upload_count";
-static const char kDefaultVersion[] = "0.0.0.0";
-
-// Build time properties name.
-static const char kProductId[] = "product_id";
-static const char kProductVersion[] = "product_version";
-
-// Weave configuration.
-static const char kWeaveConfigurationFile[] = "/system/etc/weaved/weaved.conf";
-static const char kModelManifestId[] = "model_id";
-}  // namespace metrics
-
-#endif  // METRICS_CONSTANTS_H_
diff --git a/metricsd/etc/weaved/traits/metrics.json b/metricsd/etc/weaved/traits/metrics.json
deleted file mode 100644
index 7583270..0000000
--- a/metricsd/etc/weaved/traits/metrics.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
-  "_metrics": {
-    "commands": {
-      "enableAnalyticsReporting": {
-        "minimalRole": "manager",
-        "parameters": {}
-      },
-      "disableAnalyticsReporting": {
-        "minimalRole": "manager",
-        "parameters": {}
-      }
-    },
-    "state": {
-      "analyticsReportingState": {
-        "type": "string",
-        "enum": [ "enabled", "disabled" ]
-      }
-    }
-  }
-}
diff --git a/metricsd/include/metrics/c_metrics_library.h b/metricsd/include/metrics/c_metrics_library.h
deleted file mode 100644
index 1e597c2..0000000
--- a/metricsd/include/metrics/c_metrics_library.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICS_C_METRICS_LIBRARY_H_
-#define METRICS_C_METRICS_LIBRARY_H_
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-typedef struct CMetricsLibraryOpaque* CMetricsLibrary;
-
-// C wrapper for MetricsLibrary::MetricsLibrary.
-CMetricsLibrary CMetricsLibraryNew(void);
-
-// C wrapper for MetricsLibrary::~MetricsLibrary.
-void CMetricsLibraryDelete(CMetricsLibrary handle);
-
-// C wrapper for MetricsLibrary::Init.
-void CMetricsLibraryInit(CMetricsLibrary handle);
-
-// C wrapper for MetricsLibrary::SendToUMA.
-int CMetricsLibrarySendToUMA(CMetricsLibrary handle,
-                             const char* name, int sample,
-                             int min, int max, int nbuckets);
-
-// C wrapper for MetricsLibrary::SendEnumToUMA.
-int CMetricsLibrarySendEnumToUMA(CMetricsLibrary handle,
-                                 const char* name, int sample, int max);
-
-// C wrapper for MetricsLibrary::SendSparseToUMA.
-int CMetricsLibrarySendSparseToUMA(CMetricsLibrary handle,
-                                   const char* name, int sample);
-
-// C wrapper for MetricsLibrary::SendCrashToUMA.
-int CMetricsLibrarySendCrashToUMA(CMetricsLibrary handle,
-                                  const char* crash_kind);
-
-// C wrapper for MetricsLibrary::AreMetricsEnabled.
-int CMetricsLibraryAreMetricsEnabled(CMetricsLibrary handle);
-
-#if defined(__cplusplus)
-}
-#endif
-#endif  // METRICS_C_METRICS_LIBRARY_H_
diff --git a/metricsd/include/metrics/metrics_collector_service_client.h b/metricsd/include/metrics/metrics_collector_service_client.h
deleted file mode 100644
index c800eae..0000000
--- a/metricsd/include/metrics/metrics_collector_service_client.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Client interface to IMetricsCollectorService.
-
-#ifndef METRICS_METRICS_COLLECTOR_SERVICE_CLIENT_H_
-#define METRICS_METRICS_COLLECTOR_SERVICE_CLIENT_H_
-
-#include "android/brillo/metrics/IMetricsCollectorService.h"
-
-class MetricsCollectorServiceClient {
- public:
-  MetricsCollectorServiceClient() = default;
-  ~MetricsCollectorServiceClient() = default;
-
-  // Initialize.  Returns true if OK, or false if IMetricsCollectorService
-  // is not registered.
-  bool Init();
-
-  // Called by crash_reporter to report a userspace crash event.  Returns
-  // true if successfully called the IMetricsCollectorService method of the
-  // same name, or false if the service was not registered at Init() time.
-  bool notifyUserCrash();
-
- private:
-  // IMetricsCollectorService binder proxy
-  android::sp<android::brillo::metrics::IMetricsCollectorService>
-      metrics_collector_service_;
-};
-
-#endif  // METRICS_METRICS_COLLECTOR_SERVICE_CLIENT_H_
diff --git a/metricsd/include/metrics/metrics_library.h b/metricsd/include/metrics/metrics_library.h
deleted file mode 100644
index a1bb926..0000000
--- a/metricsd/include/metrics/metrics_library.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICS_METRICS_LIBRARY_H_
-#define METRICS_METRICS_LIBRARY_H_
-
-#include <sys/types.h>
-#include <string>
-#include <unistd.h>
-
-#include <base/compiler_specific.h>
-#include <base/files/file_path.h>
-#include <base/macros.h>
-#include <binder/IServiceManager.h>
-#include <gtest/gtest_prod.h>  // for FRIEND_TEST
-
-namespace android {
-namespace brillo {
-namespace metrics {
-class IMetricsd;
-}  // namespace metrics
-}  // namespace brillo
-}  // namespace android
-
-class MetricsLibraryInterface {
- public:
-  virtual void Init() = 0;
-  virtual bool AreMetricsEnabled() = 0;
-  virtual bool SendToUMA(const std::string& name, int sample,
-                         int min, int max, int nbuckets) = 0;
-  virtual bool SendEnumToUMA(const std::string& name, int sample, int max) = 0;
-  virtual bool SendBoolToUMA(const std::string& name, bool sample) = 0;
-  virtual bool SendSparseToUMA(const std::string& name, int sample) = 0;
-  virtual ~MetricsLibraryInterface() {}
-};
-
-// Library used to send metrics to Chrome/UMA.
-class MetricsLibrary : public MetricsLibraryInterface {
- public:
-  MetricsLibrary();
-  virtual ~MetricsLibrary();
-
-  // Initializes the library.
-  void Init() override;
-
-  // Initializes the library and disables the cache of whether or not the
-  // metrics collection is enabled.
-  // By disabling this, we may have to check for the metrics status more often
-  // but the result will never be stale.
-  void InitWithNoCaching();
-
-  // Returns whether or not the machine is running in guest mode.
-  bool IsGuestMode();
-
-  // Returns whether or not metrics collection is enabled.
-  bool AreMetricsEnabled() override;
-
-  // Sends histogram data to Chrome for transport to UMA and returns
-  // true on success. This method results in the equivalent of an
-  // asynchronous non-blocking RPC to UMA_HISTOGRAM_CUSTOM_COUNTS
-  // inside Chrome (see base/histogram.h).
-  //
-  // |sample| is the sample value to be recorded (|min| <= |sample| < |max|).
-  // |min| is the minimum value of the histogram samples (|min| > 0).
-  // |max| is the maximum value of the histogram samples.
-  // |nbuckets| is the number of histogram buckets.
-  // [0,min) is the implicit underflow bucket.
-  // [|max|,infinity) is the implicit overflow bucket.
-  //
-  // Note that the memory allocated in Chrome for each histogram is
-  // proportional to the number of buckets. Therefore, it is strongly
-  // recommended to keep this number low (e.g., 50 is normal, while
-  // 100 is high).
-  bool SendToUMA(const std::string& name, int sample,
-                 int min, int max, int nbuckets) override;
-
-  // Sends linear histogram data to Chrome for transport to UMA and
-  // returns true on success. This method results in the equivalent of
-  // an asynchronous non-blocking RPC to UMA_HISTOGRAM_ENUMERATION
-  // inside Chrome (see base/histogram.h).
-  //
-  // |sample| is the sample value to be recorded (1 <= |sample| < |max|).
-  // |max| is the maximum value of the histogram samples.
-  // 0 is the implicit underflow bucket.
-  // [|max|,infinity) is the implicit overflow bucket.
-  //
-  // An enumeration histogram requires |max| + 1 number of
-  // buckets. Note that the memory allocated in Chrome for each
-  // histogram is proportional to the number of buckets. Therefore, it
-  // is strongly recommended to keep this number low (e.g., 50 is
-  // normal, while 100 is high).
-  bool SendEnumToUMA(const std::string& name, int sample, int max) override;
-
-  // Specialization of SendEnumToUMA for boolean values.
-  bool SendBoolToUMA(const std::string& name, bool sample) override;
-
-  // Sends sparse histogram sample to Chrome for transport to UMA.  Returns
-  // true on success.
-  //
-  // |sample| is the 32-bit integer value to be recorded.
-  bool SendSparseToUMA(const std::string& name, int sample) override;
-
-  // Sends a signal to UMA that a crash of the given |crash_kind|
-  // has occurred.  Used by UMA to generate stability statistics.
-  bool SendCrashToUMA(const char *crash_kind);
-
-  // Sends a "generic Chrome OS event" to UMA.  This is an event name
-  // that is translated into an enumerated histogram entry.  Event names
-  // are added to metrics_library.cc.  Optionally, they can be added
-  // to histograms.xml---but part of the reason for this is to simplify
-  // the addition of events (at the cost of having to look them up by
-  // number in the histograms dashboard).
-  bool SendCrosEventToUMA(const std::string& event);
-
-  // Debugging only.
-  // Dumps the histograms aggregated since metricsd started into |dump|.
-  // Returns true iff the dump succeeds.
-  bool GetHistogramsDump(std::string* dump);
-
- private:
-  friend class CMetricsLibraryTest;
-  friend class MetricsLibraryTest;
-  friend class UploadServiceTest;
-  FRIEND_TEST(MetricsLibraryTest, AreMetricsEnabled);
-  FRIEND_TEST(MetricsLibraryTest, AreMetricsEnabledNoCaching);
-  FRIEND_TEST(MetricsLibraryTest, FormatChromeMessage);
-  FRIEND_TEST(MetricsLibraryTest, FormatChromeMessageTooLong);
-  FRIEND_TEST(MetricsLibraryTest, IsDeviceMounted);
-  FRIEND_TEST(MetricsLibraryTest, SendMessageToChrome);
-  FRIEND_TEST(MetricsLibraryTest, SendMessageToChromeUMAEventsBadFileLocation);
-
-  void InitForTest(const base::FilePath& metrics_directory);
-
-  // Sets |*result| to whether or not the |mounts_file| indicates that
-  // the |device_name| is currently mounted.  Uses |buffer| of
-  // |buffer_size| to read the file.  Returns false if any error.
-  bool IsDeviceMounted(const char* device_name,
-                       const char* mounts_file,
-                       char* buffer, int buffer_size,
-                       bool* result);
-
-  // Connects to IMetricsd if the proxy does not exist or is not alive.
-  // Don't block if we fail to get the proxy for any reason.
-  bool CheckService();
-
-  // Time at which we last checked if metrics were enabled.
-  time_t cached_enabled_time_;
-
-  // Cached state of whether or not metrics were enabled.
-  bool cached_enabled_;
-
-  // True iff we should cache the enabled/disabled status.
-  bool use_caching_;
-
-  android::sp<android::IServiceManager> manager_;
-  android::sp<android::brillo::metrics::IMetricsd> metricsd_proxy_;
-  base::FilePath consent_file_;
-
-  DISALLOW_COPY_AND_ASSIGN(MetricsLibrary);
-};
-
-#endif  // METRICS_METRICS_LIBRARY_H_
diff --git a/metricsd/include/metrics/metrics_library_mock.h b/metricsd/include/metrics/metrics_library_mock.h
deleted file mode 100644
index 3b0b24d..0000000
--- a/metricsd/include/metrics/metrics_library_mock.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICS_METRICS_LIBRARY_MOCK_H_
-#define METRICS_METRICS_LIBRARY_MOCK_H_
-
-#include <string>
-
-#include "metrics/metrics_library.h"
-
-#include <gmock/gmock.h>
-
-class MetricsLibraryMock : public MetricsLibraryInterface {
- public:
-  bool metrics_enabled_ = true;
-
-  MOCK_METHOD0(Init, void());
-  MOCK_METHOD5(SendToUMA, bool(const std::string& name, int sample,
-                               int min, int max, int nbuckets));
-  MOCK_METHOD3(SendEnumToUMA, bool(const std::string& name, int sample,
-                                   int max));
-  MOCK_METHOD2(SendBoolToUMA, bool(const std::string& name, bool sample));
-  MOCK_METHOD2(SendSparseToUMA, bool(const std::string& name, int sample));
-
-  bool AreMetricsEnabled() override {return metrics_enabled_;};
-};
-
-#endif  // METRICS_METRICS_LIBRARY_MOCK_H_
diff --git a/metricsd/include/metrics/timer.h b/metricsd/include/metrics/timer.h
deleted file mode 100644
index c1b8ede..0000000
--- a/metricsd/include/metrics/timer.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Timer - class that provides timer tracking.
-
-#ifndef METRICS_TIMER_H_
-#define METRICS_TIMER_H_
-
-#include <memory>
-#include <string>
-
-#include <base/macros.h>
-#include <base/time/time.h>
-#include <gtest/gtest_prod.h>  // for FRIEND_TEST
-
-class MetricsLibraryInterface;
-
-namespace chromeos_metrics {
-
-class TimerInterface {
- public:
-  virtual ~TimerInterface() {}
-
-  virtual bool Start() = 0;
-  virtual bool Stop() = 0;
-  virtual bool Reset() = 0;
-  virtual bool HasStarted() const = 0;
-};
-
-// Wrapper for calls to the system clock.
-class ClockWrapper {
- public:
-  ClockWrapper() {}
-  virtual ~ClockWrapper() {}
-
-  // Returns the current time from the system.
-  virtual base::TimeTicks GetCurrentTime() const;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ClockWrapper);
-};
-
-// Implements a Timer.
-class Timer : public TimerInterface {
- public:
-  Timer();
-  virtual ~Timer() {}
-
-  // Starts the timer. If a timer is already running, also resets current
-  // timer. Always returns true.
-  virtual bool Start();
-
-  // Stops the timer and calculates the total time elapsed between now and when
-  // Start() was called. Note that this method needs a prior call to Start().
-  // Otherwise, it fails (returns false).
-  virtual bool Stop();
-
-  // Pauses a timer.  If the timer is stopped, this call starts the timer in
-  // the paused state. Fails (returns false) if the timer is already paused.
-  virtual bool Pause();
-
-  // Restarts a paused timer (or starts a stopped timer). This method fails
-  // (returns false) if the timer is already running; otherwise, returns true.
-  virtual bool Resume();
-
-  // Resets the timer, erasing the current duration being tracked. Always
-  // returns true.
-  virtual bool Reset();
-
-  // Returns whether the timer has started or not.
-  virtual bool HasStarted() const;
-
-  // Stores the current elapsed time in |elapsed_time|. If timer is stopped,
-  // stores the elapsed time from when Stop() was last called. Otherwise,
-  // calculates and stores the elapsed time since the last Start().
-  // Returns false if the timer was never Start()'ed or if called with a null
-  // pointer argument.
-  virtual bool GetElapsedTime(base::TimeDelta* elapsed_time) const;
-
- private:
-  enum TimerState { kTimerStopped, kTimerRunning, kTimerPaused };
-  friend class TimerTest;
-  friend class TimerReporterTest;
-  FRIEND_TEST(TimerReporterTest, StartStopReport);
-  FRIEND_TEST(TimerTest, InvalidElapsedTime);
-  FRIEND_TEST(TimerTest, InvalidStop);
-  FRIEND_TEST(TimerTest, PauseResumeStop);
-  FRIEND_TEST(TimerTest, PauseStartStopResume);
-  FRIEND_TEST(TimerTest, PauseStop);
-  FRIEND_TEST(TimerTest, Reset);
-  FRIEND_TEST(TimerTest, ReStart);
-  FRIEND_TEST(TimerTest, ResumeStartStopPause);
-  FRIEND_TEST(TimerTest, SeparatedTimers);
-  FRIEND_TEST(TimerTest, StartPauseResumePauseResumeStop);
-  FRIEND_TEST(TimerTest, StartPauseResumePauseStop);
-  FRIEND_TEST(TimerTest, StartPauseResumeStop);
-  FRIEND_TEST(TimerTest, StartPauseStop);
-  FRIEND_TEST(TimerTest, StartResumeStop);
-  FRIEND_TEST(TimerTest, StartStop);
-
-  // Elapsed time of the last use of the timer.
-  base::TimeDelta elapsed_time_;
-
-  // Starting time value.
-  base::TimeTicks start_time_;
-
-  // Whether the timer is running, stopped, or paused.
-  TimerState timer_state_;
-
-  // Wrapper for the calls to the system clock.
-  std::unique_ptr<ClockWrapper> clock_wrapper_;
-
-  DISALLOW_COPY_AND_ASSIGN(Timer);
-};
-
-// Extends the Timer class to report the elapsed time in milliseconds through
-// the UMA metrics library.
-class TimerReporter : public Timer {
- public:
-  // Initializes the timer by providing a |histogram_name| to report to with
-  // |min|, |max| and |num_buckets| attributes for the histogram.
-  TimerReporter(const std::string& histogram_name, int min, int max,
-                int num_buckets);
-  virtual ~TimerReporter() {}
-
-  // Sets the metrics library used by all instances of this class.
-  static void set_metrics_lib(MetricsLibraryInterface* metrics_lib) {
-    metrics_lib_ = metrics_lib;
-  }
-
-  // Reports the current duration to UMA, in milliseconds. Returns false if
-  // there is nothing to report, e.g. a metrics library is not set.
-  virtual bool ReportMilliseconds() const;
-
-  // Accessor methods.
-  const std::string& histogram_name() const { return histogram_name_; }
-  int min() const { return min_; }
-  int max() const { return max_; }
-  int num_buckets() const { return num_buckets_; }
-
- private:
-  friend class TimerReporterTest;
-  FRIEND_TEST(TimerReporterTest, StartStopReport);
-  FRIEND_TEST(TimerReporterTest, InvalidReport);
-
-  static MetricsLibraryInterface* metrics_lib_;
-  std::string histogram_name_;
-  int min_;
-  int max_;
-  int num_buckets_;
-
-  DISALLOW_COPY_AND_ASSIGN(TimerReporter);
-};
-
-}  // namespace chromeos_metrics
-
-#endif  // METRICS_TIMER_H_
diff --git a/metricsd/include/metrics/timer_mock.h b/metricsd/include/metrics/timer_mock.h
deleted file mode 100644
index 200ee9a..0000000
--- a/metricsd/include/metrics/timer_mock.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICS_TIMER_MOCK_H_
-#define METRICS_TIMER_MOCK_H_
-
-#include <string>
-
-#include <gmock/gmock.h>
-
-#include "metrics/timer.h"
-
-namespace chromeos_metrics {
-
-class TimerMock : public Timer {
- public:
-  MOCK_METHOD0(Start, bool());
-  MOCK_METHOD0(Stop, bool());
-  MOCK_METHOD0(Reset, bool());
-  MOCK_CONST_METHOD0(HasStarted, bool());
-  MOCK_CONST_METHOD1(GetElapsedTime, bool(base::TimeDelta* elapsed_time));
-};
-
-class TimerReporterMock : public TimerReporter {
- public:
-  TimerReporterMock() : TimerReporter("", 0, 0, 0) {}
-  MOCK_METHOD0(Start, bool());
-  MOCK_METHOD0(Stop, bool());
-  MOCK_METHOD0(Reset, bool());
-  MOCK_CONST_METHOD0(HasStarted, bool());
-  MOCK_CONST_METHOD1(GetElapsedTime, bool(base::TimeDelta* elapsed_time));
-  MOCK_CONST_METHOD0(ReportMilliseconds, bool());
-  MOCK_CONST_METHOD0(histogram_name, std::string&());
-  MOCK_CONST_METHOD0(min, int());
-  MOCK_CONST_METHOD0(max, int());
-  MOCK_CONST_METHOD0(num_buckets, int());
-};
-
-class ClockWrapperMock : public ClockWrapper {
- public:
-  MOCK_CONST_METHOD0(GetCurrentTime, base::TimeTicks());
-};
-
-}  // namespace chromeos_metrics
-
-#endif  // METRICS_TIMER_MOCK_H_
diff --git a/metricsd/libmetrics-369476.gyp b/metricsd/libmetrics-369476.gyp
deleted file mode 100644
index b545d35..0000000
--- a/metricsd/libmetrics-369476.gyp
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  'variables': {
-    'libbase_ver': 369476,
-  },
-  'includes': [
-    'libmetrics.gypi',
-  ],
-}
diff --git a/metricsd/libmetrics.gypi b/metricsd/libmetrics.gypi
deleted file mode 100644
index 3c8fc7c..0000000
--- a/metricsd/libmetrics.gypi
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-  'target_defaults': {
-    'variables': {
-      'deps': [
-        'libbrillo-<(libbase_ver)',
-        'libchrome-<(libbase_ver)',
-      ]
-    },
-    'cflags_cc': [
-      '-fno-exceptions',
-    ],
-  },
-  'targets': [
-    {
-      'target_name': 'libmetrics-<(libbase_ver)',
-      'type': 'shared_library',
-      'cflags': [
-        '-fvisibility=default',
-      ],
-      'libraries+': [
-        '-lpolicy-<(libbase_ver)',
-      ],
-      'sources': [
-        'c_metrics_library.cc',
-        'metrics_library.cc',
-        'serialization/metric_sample.cc',
-        'serialization/serialization_utils.cc',
-        'timer.cc',
-      ],
-      'include_dirs': ['.'],
-    },
-  ],
-}
diff --git a/metricsd/libmetrics.pc.in b/metricsd/libmetrics.pc.in
deleted file mode 100644
index 233f318..0000000
--- a/metricsd/libmetrics.pc.in
+++ /dev/null
@@ -1,7 +0,0 @@
-bslot=@BSLOT@
-
-Name: libmetrics
-Description: Chrome OS metrics library
-Version: ${bslot}
-Requires.private: libchrome-${bslot}
-Libs: -lmetrics-${bslot}
diff --git a/metricsd/metrics.gyp b/metricsd/metrics.gyp
deleted file mode 100644
index c9c02d7..0000000
--- a/metricsd/metrics.gyp
+++ /dev/null
@@ -1,184 +0,0 @@
-{
-  'target_defaults': {
-    'variables': {
-      'deps': [
-        'dbus-1',
-        'libbrillo-<(libbase_ver)',
-        'libchrome-<(libbase_ver)',
-      ]
-    },
-    'cflags_cc': [
-      '-fno-exceptions',
-    ],
-  },
-  'targets': [
-    {
-      'target_name': 'libmetrics_daemon',
-      'type': 'static_library',
-      'dependencies': [
-        '../metrics/libmetrics-<(libbase_ver).gyp:libmetrics-<(libbase_ver)',
-        'libupload_service',
-        'metrics_proto',
-      ],
-      'link_settings': {
-        'libraries': [
-          '-lrootdev',
-        ],
-      },
-      'sources': [
-        'persistent_integer.cc',
-        'metrics_daemon.cc',
-        'metrics_daemon_main.cc',
-      ],
-      'include_dirs': ['.'],
-    },
-    {
-      'target_name': 'metrics_client',
-      'type': 'executable',
-      'dependencies': [
-        '../metrics/libmetrics-<(libbase_ver).gyp:libmetrics-<(libbase_ver)',
-      ],
-      'sources': [
-        'metrics_client.cc',
-      ]
-    },
-    {
-      'target_name': 'libupload_service',
-      'type': 'static_library',
-      'dependencies': [
-        'metrics_proto',
-        '../metrics/libmetrics-<(libbase_ver).gyp:libmetrics-<(libbase_ver)',
-      ],
-      'link_settings': {
-        'libraries': [
-          '-lvboot_host',
-        ],
-      },
-      'variables': {
-        'exported_deps': [
-          'protobuf-lite',
-        ],
-        'deps': [
-          '<@(exported_deps)',
-        ],
-      },
-      'all_dependent_settings': {
-        'variables': {
-          'deps+': [
-            '<@(exported_deps)',
-          ],
-        },
-      },
-      'sources': [
-        'uploader/upload_service.cc',
-        'uploader/metrics_hashes.cc',
-        'uploader/metrics_log.cc',
-        'uploader/metrics_log_base.cc',
-        'uploader/system_profile_cache.cc',
-        'uploader/sender_http.cc',
-      ],
-      'include_dirs': ['.']
-    },
-    {
-      'target_name': 'metrics_proto',
-      'type': 'static_library',
-      'variables': {
-        'proto_in_dir': 'uploader/proto',
-        'proto_out_dir': 'include/metrics/uploader/proto',
-      },
-      'sources': [
-        '<(proto_in_dir)/chrome_user_metrics_extension.proto',
-        '<(proto_in_dir)/histogram_event.proto',
-        '<(proto_in_dir)/system_profile.proto',
-        '<(proto_in_dir)/user_action_event.proto',
-      ],
-      'includes': [
-        '../common-mk/protoc.gypi'
-      ],
-    },
-  ],
-  'conditions': [
-    ['USE_passive_metrics == 1', {
-      'targets': [
-        {
-          'target_name': 'metrics_daemon',
-          'type': 'executable',
-          'dependencies': ['libmetrics_daemon'],
-        },
-      ],
-    }],
-    ['USE_test == 1', {
-      'targets': [
-        {
-          'target_name': 'persistent_integer_test',
-          'type': 'executable',
-          'includes': ['../common-mk/common_test.gypi'],
-          'sources': [
-            'persistent_integer.cc',
-            'persistent_integer_test.cc',
-          ]
-        },
-        {
-          'target_name': 'metrics_library_test',
-          'type': 'executable',
-          'dependencies': [
-            '../metrics/libmetrics-<(libbase_ver).gyp:libmetrics-<(libbase_ver)',
-          ],
-          'includes': ['../common-mk/common_test.gypi'],
-          'sources': [
-            'metrics_library_test.cc',
-            'serialization/serialization_utils_unittest.cc',
-          ],
-          'link_settings': {
-            'libraries': [
-              '-lpolicy-<(libbase_ver)',
-            ]
-          }
-        },
-        {
-          'target_name': 'timer_test',
-          'type': 'executable',
-          'includes': ['../common-mk/common_test.gypi'],
-          'sources': [
-            'timer.cc',
-            'timer_test.cc',
-          ]
-        },
-        {
-          'target_name': 'upload_service_test',
-          'type': 'executable',
-          'sources': [
-            'persistent_integer.cc',
-            'uploader/metrics_hashes_unittest.cc',
-            'uploader/metrics_log_base_unittest.cc',
-            'uploader/mock/sender_mock.cc',
-            'uploader/upload_service_test.cc',
-          ],
-          'dependencies': [
-            'libupload_service',
-          ],
-          'includes':[
-            '../common-mk/common_test.gypi',
-          ],
-          'include_dirs': ['.']
-        },
-      ],
-    }],
-    ['USE_passive_metrics == 1 and USE_test == 1', {
-      'targets': [
-        {
-          'target_name': 'metrics_daemon_test',
-          'type': 'executable',
-          'dependencies': [
-            'libmetrics_daemon',
-          ],
-          'includes': ['../common-mk/common_test.gypi'],
-          'sources': [
-            'metrics_daemon_test.cc',
-          ],
-          'include_dirs': ['.'],
-        },
-      ],
-    }],
-  ]
-}
diff --git a/metricsd/metrics_client.cc b/metricsd/metrics_client.cc
deleted file mode 100644
index c66b975..0000000
--- a/metricsd/metrics_client.cc
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <cstdio>
-#include <cstdlib>
-
-#include "constants.h"
-#include "metrics/metrics_library.h"
-
-enum Mode {
-    kModeDumpHistograms,
-    kModeSendSample,
-    kModeSendEnumSample,
-    kModeSendSparseSample,
-    kModeSendCrosEvent,
-    kModeHasConsent,
-    kModeIsGuestMode,
-};
-
-void ShowUsage() {
-  fprintf(stderr,
-          "Usage:  metrics_client [-t] name sample min max nbuckets\n"
-          "        metrics_client -e   name sample max\n"
-          "        metrics_client -s   name sample\n"
-          "        metrics_client -v   event\n"
-          "        metrics_client [-cdg]\n"
-          "\n"
-          "  default: send metric with integer values \n"
-          "           |min| > 0, |min| <= sample < |max|\n"
-          "  -c: return exit status 0 if user consents to stats, 1 otherwise,\n"
-          "      in guest mode always return 1\n"
-          "  -d: dump the histograms recorded by metricsd to stdout\n"
-          "  -e: send linear/enumeration histogram data\n"
-          "  -g: return exit status 0 if machine in guest mode, 1 otherwise\n"
-          "  -s: send a sparse histogram sample\n"
-          "  -t: convert sample from double seconds to int milliseconds\n"
-          "  -v: send a Platform.CrOSEvent enum histogram sample\n");
-  exit(1);
-}
-
-static int ParseInt(const char *arg) {
-  char *endptr;
-  int value = strtol(arg, &endptr, 0);
-  if (*endptr != '\0') {
-    fprintf(stderr, "metrics client: bad integer \"%s\"\n", arg);
-    ShowUsage();
-  }
-  return value;
-}
-
-static double ParseDouble(const char *arg) {
-  char *endptr;
-  double value = strtod(arg, &endptr);
-  if (*endptr != '\0') {
-    fprintf(stderr, "metrics client: bad double \"%s\"\n", arg);
-    ShowUsage();
-  }
-  return value;
-}
-
-static int DumpHistograms() {
-  MetricsLibrary metrics_lib;
-  metrics_lib.Init();
-
-  std::string dump;
-  if (!metrics_lib.GetHistogramsDump(&dump)) {
-    printf("Failed to dump the histograms.");
-    return 1;
-  }
-
-  printf("%s\n", dump.c_str());
-  return 0;
-}
-
-static int SendStats(char* argv[],
-                     int name_index,
-                     enum Mode mode,
-                     bool secs_to_msecs) {
-  const char* name = argv[name_index];
-  int sample;
-  if (secs_to_msecs) {
-    sample = static_cast<int>(ParseDouble(argv[name_index + 1]) * 1000.0);
-  } else {
-    sample = ParseInt(argv[name_index + 1]);
-  }
-
-  MetricsLibrary metrics_lib;
-  metrics_lib.Init();
-  if (mode == kModeSendSparseSample) {
-    metrics_lib.SendSparseToUMA(name, sample);
-  } else if (mode == kModeSendEnumSample) {
-    int max = ParseInt(argv[name_index + 2]);
-    metrics_lib.SendEnumToUMA(name, sample, max);
-  } else {
-    int min = ParseInt(argv[name_index + 2]);
-    int max = ParseInt(argv[name_index + 3]);
-    int nbuckets = ParseInt(argv[name_index + 4]);
-    metrics_lib.SendToUMA(name, sample, min, max, nbuckets);
-  }
-  return 0;
-}
-
-static int SendCrosEvent(char* argv[], int action_index) {
-  const char* event = argv[action_index];
-  bool result;
-  MetricsLibrary metrics_lib;
-  metrics_lib.Init();
-  result = metrics_lib.SendCrosEventToUMA(event);
-  if (!result) {
-    fprintf(stderr, "metrics_client: could not send event %s\n", event);
-    return 1;
-  }
-  return 0;
-}
-
-static int HasConsent() {
-  MetricsLibrary metrics_lib;
-  metrics_lib.Init();
-  return metrics_lib.AreMetricsEnabled() ? 0 : 1;
-}
-
-static int IsGuestMode() {
-  MetricsLibrary metrics_lib;
-  metrics_lib.Init();
-  return metrics_lib.IsGuestMode() ? 0 : 1;
-}
-
-int main(int argc, char** argv) {
-  enum Mode mode = kModeSendSample;
-  bool secs_to_msecs = false;
-
-  // Parse arguments
-  int flag;
-  while ((flag = getopt(argc, argv, "abcdegstv")) != -1) {
-    switch (flag) {
-      case 'c':
-        mode = kModeHasConsent;
-        break;
-      case 'd':
-        mode = kModeDumpHistograms;
-        break;
-      case 'e':
-        mode = kModeSendEnumSample;
-        break;
-      case 'g':
-        mode = kModeIsGuestMode;
-        break;
-      case 's':
-        mode = kModeSendSparseSample;
-        break;
-      case 't':
-        secs_to_msecs = true;
-        break;
-      case 'v':
-        mode = kModeSendCrosEvent;
-        break;
-      default:
-        ShowUsage();
-        break;
-    }
-  }
-  int arg_index = optind;
-
-  int expected_args = 0;
-  if (mode == kModeSendSample)
-    expected_args = 5;
-  else if (mode == kModeSendEnumSample)
-    expected_args = 3;
-  else if (mode == kModeSendSparseSample)
-    expected_args = 2;
-  else if (mode == kModeSendCrosEvent)
-    expected_args = 1;
-
-  if ((arg_index + expected_args) != argc) {
-    ShowUsage();
-  }
-
-  switch (mode) {
-    case kModeDumpHistograms:
-      return DumpHistograms();
-    case kModeSendSample:
-    case kModeSendEnumSample:
-    case kModeSendSparseSample:
-      if ((mode != kModeSendSample) && secs_to_msecs) {
-        ShowUsage();
-      }
-      return SendStats(argv,
-                       arg_index,
-                       mode,
-                       secs_to_msecs);
-    case kModeSendCrosEvent:
-      return SendCrosEvent(argv, arg_index);
-    case kModeHasConsent:
-      return HasConsent();
-    case kModeIsGuestMode:
-      return IsGuestMode();
-    default:
-      ShowUsage();
-      return 0;
-  }
-}
diff --git a/metricsd/metrics_collector.cc b/metricsd/metrics_collector.cc
deleted file mode 100644
index 45ae0a4..0000000
--- a/metricsd/metrics_collector.cc
+++ /dev/null
@@ -1,756 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "metrics_collector.h"
-
-#include <sysexits.h>
-#include <time.h>
-
-#include <memory>
-
-#include <base/bind.h>
-#include <base/files/file_path.h>
-#include <base/files/file_util.h>
-#include <base/hash.h>
-#include <base/logging.h>
-#include <base/strings/string_number_conversions.h>
-#include <base/strings/string_split.h>
-#include <base/strings/string_util.h>
-#include <base/strings/stringprintf.h>
-#include <brillo/binder_watcher.h>
-#include <brillo/osrelease_reader.h>
-
-#include "constants.h"
-#include "metrics_collector_service_impl.h"
-
-using base::FilePath;
-using base::StringPrintf;
-using base::Time;
-using base::TimeDelta;
-using base::TimeTicks;
-using chromeos_metrics::PersistentInteger;
-using std::map;
-using std::string;
-using std::vector;
-
-namespace {
-
-const int kSecondsPerMinute = 60;
-const int kMinutesPerHour = 60;
-const int kHoursPerDay = 24;
-const int kMinutesPerDay = kHoursPerDay * kMinutesPerHour;
-const int kSecondsPerDay = kSecondsPerMinute * kMinutesPerDay;
-const int kDaysPerWeek = 7;
-const int kSecondsPerWeek = kSecondsPerDay * kDaysPerWeek;
-
-// Interval between calls to UpdateStats().
-const uint32_t kUpdateStatsIntervalMs = 300000;
-
-const char kKernelCrashDetectedFile[] =
-    "/data/misc/crash_reporter/run/kernel-crash-detected";
-const char kUncleanShutdownDetectedFile[] =
-    "/var/run/unclean-shutdown-detected";
-
-const int kMetricMeminfoInterval = 30;    // seconds
-
-const char kMeminfoFileName[] = "/proc/meminfo";
-const char kVmStatFileName[] = "/proc/vmstat";
-
-const char kWeaveComponent[] = "metrics";
-const char kWeaveTrait[] = "_metrics";
-
-}  // namespace
-
-// Zram sysfs entries.
-
-const char MetricsCollector::kComprDataSizeName[] = "compr_data_size";
-const char MetricsCollector::kOrigDataSizeName[] = "orig_data_size";
-const char MetricsCollector::kZeroPagesName[] = "zero_pages";
-
-// Memory use stats collection intervals.  We collect some memory use interval
-// at these intervals after boot, and we stop collecting after the last one,
-// with the assumption that in most cases the memory use won't change much
-// after that.
-static const int kMemuseIntervals[] = {
-  1 * kSecondsPerMinute,    // 1 minute mark
-  4 * kSecondsPerMinute,    // 5 minute mark
-  25 * kSecondsPerMinute,   // 0.5 hour mark
-  120 * kSecondsPerMinute,  // 2.5 hour mark
-  600 * kSecondsPerMinute,  // 12.5 hour mark
-};
-
-MetricsCollector::MetricsCollector()
-    : memuse_final_time_(0),
-      memuse_interval_index_(0) {}
-
-MetricsCollector::~MetricsCollector() {
-}
-
-// static
-double MetricsCollector::GetActiveTime() {
-  struct timespec ts;
-  int r = clock_gettime(CLOCK_MONOTONIC, &ts);
-  if (r < 0) {
-    PLOG(WARNING) << "clock_gettime(CLOCK_MONOTONIC) failed";
-    return 0;
-  } else {
-    return ts.tv_sec + static_cast<double>(ts.tv_nsec) / (1000 * 1000 * 1000);
-  }
-}
-
-int MetricsCollector::Run() {
-  if (CheckSystemCrash(kKernelCrashDetectedFile)) {
-    ProcessKernelCrash();
-  }
-
-  if (CheckSystemCrash(kUncleanShutdownDetectedFile)) {
-    ProcessUncleanShutdown();
-  }
-
-  // On OS version change, clear version stats (which are reported daily).
-  int32_t version = GetOsVersionHash();
-  if (version_cycle_->Get() != version) {
-    version_cycle_->Set(version);
-    kernel_crashes_version_count_->Set(0);
-    version_cumulative_active_use_->Set(0);
-    version_cumulative_cpu_use_->Set(0);
-  }
-
-  // Start metricscollectorservice
-  android::sp<BnMetricsCollectorServiceImpl> metrics_collector_service =
-      new BnMetricsCollectorServiceImpl(this);
-  android::status_t status = android::defaultServiceManager()->addService(
-      metrics_collector_service->getInterfaceDescriptor(),
-      metrics_collector_service);
-  CHECK(status == android::OK)
-      << "failed to register service metricscollectorservice";
-
-  // Watch Binder events in the main loop
-  brillo::BinderWatcher binder_watcher;
-  CHECK(binder_watcher.Init()) << "Binder FD watcher init failed";
-  return brillo::Daemon::Run();
-}
-
-uint32_t MetricsCollector::GetOsVersionHash() {
-  brillo::OsReleaseReader reader;
-  reader.Load();
-  string version;
-  if (!reader.GetString(metrics::kProductVersion, &version)) {
-    LOG(ERROR) << "failed to read the product version.";
-    version = metrics::kDefaultVersion;
-  }
-
-  uint32_t version_hash = base::Hash(version);
-  if (testing_) {
-    version_hash = 42;  // return any plausible value for the hash
-  }
-  return version_hash;
-}
-
-void MetricsCollector::Init(bool testing, MetricsLibraryInterface* metrics_lib,
-                            const string& diskstats_path,
-                            const base::FilePath& private_metrics_directory,
-                            const base::FilePath& shared_metrics_directory) {
-  CHECK(metrics_lib);
-  testing_ = testing;
-  shared_metrics_directory_ = shared_metrics_directory;
-  metrics_lib_ = metrics_lib;
-
-  daily_active_use_.reset(new PersistentInteger("Platform.UseTime.PerDay",
-                                                private_metrics_directory));
-  version_cumulative_active_use_.reset(new PersistentInteger(
-      "Platform.CumulativeUseTime", private_metrics_directory));
-  version_cumulative_cpu_use_.reset(new PersistentInteger(
-      "Platform.CumulativeCpuTime", private_metrics_directory));
-
-  kernel_crash_interval_.reset(new PersistentInteger(
-      "Platform.KernelCrashInterval", private_metrics_directory));
-  unclean_shutdown_interval_.reset(new PersistentInteger(
-      "Platform.UncleanShutdownInterval", private_metrics_directory));
-  user_crash_interval_.reset(new PersistentInteger("Platform.UserCrashInterval",
-                                                   private_metrics_directory));
-
-  any_crashes_daily_count_.reset(new PersistentInteger(
-      "Platform.AnyCrashes.PerDay", private_metrics_directory));
-  any_crashes_weekly_count_.reset(new PersistentInteger(
-      "Platform.AnyCrashes.PerWeek", private_metrics_directory));
-  user_crashes_daily_count_.reset(new PersistentInteger(
-      "Platform.UserCrashes.PerDay", private_metrics_directory));
-  user_crashes_weekly_count_.reset(new PersistentInteger(
-      "Platform.UserCrashes.PerWeek", private_metrics_directory));
-  kernel_crashes_daily_count_.reset(new PersistentInteger(
-      "Platform.KernelCrashes.PerDay", private_metrics_directory));
-  kernel_crashes_weekly_count_.reset(new PersistentInteger(
-      "Platform.KernelCrashes.PerWeek", private_metrics_directory));
-  kernel_crashes_version_count_.reset(new PersistentInteger(
-      "Platform.KernelCrashesSinceUpdate", private_metrics_directory));
-  unclean_shutdowns_daily_count_.reset(new PersistentInteger(
-      "Platform.UncleanShutdown.PerDay", private_metrics_directory));
-  unclean_shutdowns_weekly_count_.reset(new PersistentInteger(
-      "Platform.UncleanShutdowns.PerWeek", private_metrics_directory));
-
-  daily_cycle_.reset(
-      new PersistentInteger("daily.cycle", private_metrics_directory));
-  weekly_cycle_.reset(
-      new PersistentInteger("weekly.cycle", private_metrics_directory));
-  version_cycle_.reset(
-      new PersistentInteger("version.cycle", private_metrics_directory));
-
-  disk_usage_collector_.reset(new DiskUsageCollector(metrics_lib_));
-  averaged_stats_collector_.reset(
-      new AveragedStatisticsCollector(metrics_lib_, diskstats_path,
-                                      kVmStatFileName));
-  cpu_usage_collector_.reset(new CpuUsageCollector(metrics_lib_));
-}
-
-int MetricsCollector::OnInit() {
-  int return_code = brillo::Daemon::OnInit();
-  if (return_code != EX_OK)
-    return return_code;
-
-  StatsReporterInit();
-
-  // Start collecting meminfo stats.
-  ScheduleMeminfoCallback(kMetricMeminfoInterval);
-  memuse_final_time_ = GetActiveTime() + kMemuseIntervals[0];
-  ScheduleMemuseCallback(kMemuseIntervals[0]);
-
-  if (testing_)
-    return EX_OK;
-
-  weave_service_subscription_ = weaved::Service::Connect(
-      brillo::MessageLoop::current(),
-      base::Bind(&MetricsCollector::OnWeaveServiceConnected,
-                 weak_ptr_factory_.GetWeakPtr()));
-
-  latest_cpu_use_microseconds_ = cpu_usage_collector_->GetCumulativeCpuUse();
-  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-      base::Bind(&MetricsCollector::HandleUpdateStatsTimeout,
-                 weak_ptr_factory_.GetWeakPtr()),
-      base::TimeDelta::FromMilliseconds(kUpdateStatsIntervalMs));
-
-  return EX_OK;
-}
-
-void MetricsCollector::OnWeaveServiceConnected(
-    const std::weak_ptr<weaved::Service>& service) {
-  service_ = service;
-  auto weave_service = service_.lock();
-  if (!weave_service)
-    return;
-
-  weave_service->AddComponent(kWeaveComponent, {kWeaveTrait}, nullptr);
-  weave_service->AddCommandHandler(
-      kWeaveComponent, kWeaveTrait, "enableAnalyticsReporting",
-      base::Bind(&MetricsCollector::OnEnableMetrics,
-                 weak_ptr_factory_.GetWeakPtr()));
-  weave_service->AddCommandHandler(
-      kWeaveComponent, kWeaveTrait, "disableAnalyticsReporting",
-      base::Bind(&MetricsCollector::OnDisableMetrics,
-                 weak_ptr_factory_.GetWeakPtr()));
-
-  UpdateWeaveState();
-}
-
-void MetricsCollector::OnEnableMetrics(
-    std::unique_ptr<weaved::Command> command) {
-  if (base::WriteFile(
-          shared_metrics_directory_.Append(metrics::kConsentFileName), "", 0) !=
-      0) {
-    PLOG(ERROR) << "Could not create the consent file.";
-    command->Abort("metrics_error", "Could not create the consent file",
-                   nullptr);
-    return;
-  }
-
-  UpdateWeaveState();
-  command->Complete({}, nullptr);
-}
-
-void MetricsCollector::OnDisableMetrics(
-    std::unique_ptr<weaved::Command> command) {
-  if (!base::DeleteFile(
-          shared_metrics_directory_.Append(metrics::kConsentFileName), false)) {
-    PLOG(ERROR) << "Could not delete the consent file.";
-    command->Abort("metrics_error", "Could not delete the consent file",
-                   nullptr);
-    return;
-  }
-
-  UpdateWeaveState();
-  command->Complete({}, nullptr);
-}
-
-void MetricsCollector::UpdateWeaveState() {
-  auto weave_service = service_.lock();
-  if (!weave_service)
-    return;
-
-  std::string enabled =
-      metrics_lib_->AreMetricsEnabled() ? "enabled" : "disabled";
-
-  if (!weave_service->SetStateProperty(kWeaveComponent, kWeaveTrait,
-                                       "analyticsReportingState",
-                                       *brillo::ToValue(enabled),
-                                       nullptr)) {
-    LOG(ERROR) << "failed to update weave's state";
-  }
-}
-
-void MetricsCollector::ProcessUserCrash() {
-  // Counts the active time up to now.
-  UpdateStats(TimeTicks::Now(), Time::Now());
-
-  // Reports the active use time since the last crash and resets it.
-  SendAndResetCrashIntervalSample(user_crash_interval_);
-
-  any_crashes_daily_count_->Add(1);
-  any_crashes_weekly_count_->Add(1);
-  user_crashes_daily_count_->Add(1);
-  user_crashes_weekly_count_->Add(1);
-}
-
-void MetricsCollector::ProcessKernelCrash() {
-  // Counts the active time up to now.
-  UpdateStats(TimeTicks::Now(), Time::Now());
-
-  // Reports the active use time since the last crash and resets it.
-  SendAndResetCrashIntervalSample(kernel_crash_interval_);
-
-  any_crashes_daily_count_->Add(1);
-  any_crashes_weekly_count_->Add(1);
-  kernel_crashes_daily_count_->Add(1);
-  kernel_crashes_weekly_count_->Add(1);
-
-  kernel_crashes_version_count_->Add(1);
-}
-
-void MetricsCollector::ProcessUncleanShutdown() {
-  // Counts the active time up to now.
-  UpdateStats(TimeTicks::Now(), Time::Now());
-
-  // Reports the active use time since the last crash and resets it.
-  SendAndResetCrashIntervalSample(unclean_shutdown_interval_);
-
-  unclean_shutdowns_daily_count_->Add(1);
-  unclean_shutdowns_weekly_count_->Add(1);
-  any_crashes_daily_count_->Add(1);
-  any_crashes_weekly_count_->Add(1);
-}
-
-bool MetricsCollector::CheckSystemCrash(const string& crash_file) {
-  FilePath crash_detected(crash_file);
-  if (!base::PathExists(crash_detected))
-    return false;
-
-  // Deletes the crash-detected file so that the daemon doesn't report
-  // another kernel crash in case it's restarted.
-  base::DeleteFile(crash_detected, false);  // not recursive
-  return true;
-}
-
-void MetricsCollector::StatsReporterInit() {
-  disk_usage_collector_->Schedule();
-
-  cpu_usage_collector_->Init();
-  cpu_usage_collector_->Schedule();
-
-  // Don't start a collection cycle during the first run to avoid delaying the
-  // boot.
-  averaged_stats_collector_->ScheduleWait();
-}
-
-void MetricsCollector::ScheduleMeminfoCallback(int wait) {
-  if (testing_) {
-    return;
-  }
-  base::TimeDelta waitDelta = base::TimeDelta::FromSeconds(wait);
-  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-      base::Bind(&MetricsCollector::MeminfoCallback,
-                 weak_ptr_factory_.GetWeakPtr(), waitDelta),
-      waitDelta);
-}
-
-void MetricsCollector::MeminfoCallback(base::TimeDelta wait) {
-  string meminfo_raw;
-  const FilePath meminfo_path(kMeminfoFileName);
-  if (!base::ReadFileToString(meminfo_path, &meminfo_raw)) {
-    LOG(WARNING) << "cannot read " << meminfo_path.value().c_str();
-    return;
-  }
-  // Make both calls even if the first one fails.
-  if (ProcessMeminfo(meminfo_raw)) {
-    base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-        base::Bind(&MetricsCollector::MeminfoCallback,
-                   weak_ptr_factory_.GetWeakPtr(), wait),
-        wait);
-  }
-}
-
-// static
-bool MetricsCollector::ReadFileToUint64(const base::FilePath& path,
-                                         uint64_t* value) {
-  std::string content;
-  if (!base::ReadFileToString(path, &content)) {
-    PLOG(WARNING) << "cannot read " << path.MaybeAsASCII();
-    return false;
-  }
-  // Remove final newline.
-  base::TrimWhitespaceASCII(content, base::TRIM_TRAILING, &content);
-  if (!base::StringToUint64(content, value)) {
-    LOG(WARNING) << "invalid integer: " << content;
-    return false;
-  }
-  return true;
-}
-
-bool MetricsCollector::ReportZram(const base::FilePath& zram_dir) {
-  // Data sizes are in bytes.  |zero_pages| is in number of pages.
-  uint64_t compr_data_size, orig_data_size, zero_pages;
-  const size_t page_size = 4096;
-
-  if (!ReadFileToUint64(zram_dir.Append(kComprDataSizeName),
-                        &compr_data_size) ||
-      !ReadFileToUint64(zram_dir.Append(kOrigDataSizeName), &orig_data_size) ||
-      !ReadFileToUint64(zram_dir.Append(kZeroPagesName), &zero_pages)) {
-    return false;
-  }
-
-  // |orig_data_size| does not include zero-filled pages.
-  orig_data_size += zero_pages * page_size;
-
-  const int compr_data_size_mb = compr_data_size >> 20;
-  const int savings_mb = (orig_data_size - compr_data_size) >> 20;
-  const int zero_ratio_percent = zero_pages * page_size * 100 / orig_data_size;
-
-  // Report compressed size in megabytes.  100 MB or less has little impact.
-  SendSample("Platform.ZramCompressedSize", compr_data_size_mb, 100, 4000, 50);
-  SendSample("Platform.ZramSavings", savings_mb, 100, 4000, 50);
-  // The compression ratio is multiplied by 100 for better resolution.  The
-  // ratios of interest are between 1 and 6 (100% and 600% as reported).  We
-  // don't want samples when very little memory is being compressed.
-  if (compr_data_size_mb >= 1) {
-    SendSample("Platform.ZramCompressionRatioPercent",
-               orig_data_size * 100 / compr_data_size, 100, 600, 50);
-  }
-  // The values of interest for zero_pages are between 1MB and 1GB.  The units
-  // are number of pages.
-  SendSample("Platform.ZramZeroPages", zero_pages, 256, 256 * 1024, 50);
-  SendSample("Platform.ZramZeroRatioPercent", zero_ratio_percent, 1, 50, 50);
-
-  return true;
-}
-
-bool MetricsCollector::ProcessMeminfo(const string& meminfo_raw) {
-  static const MeminfoRecord fields_array[] = {
-    { "MemTotal", "MemTotal" },  // SPECIAL CASE: total system memory
-    { "MemFree", "MemFree" },
-    { "Buffers", "Buffers" },
-    { "Cached", "Cached" },
-    // { "SwapCached", "SwapCached" },
-    { "Active", "Active" },
-    { "Inactive", "Inactive" },
-    { "ActiveAnon", "Active(anon)" },
-    { "InactiveAnon", "Inactive(anon)" },
-    { "ActiveFile" , "Active(file)" },
-    { "InactiveFile", "Inactive(file)" },
-    { "Unevictable", "Unevictable", kMeminfoOp_HistLog },
-    // { "Mlocked", "Mlocked" },
-    { "SwapTotal", "SwapTotal", kMeminfoOp_SwapTotal },
-    { "SwapFree", "SwapFree", kMeminfoOp_SwapFree },
-    // { "Dirty", "Dirty" },
-    // { "Writeback", "Writeback" },
-    { "AnonPages", "AnonPages" },
-    { "Mapped", "Mapped" },
-    { "Shmem", "Shmem", kMeminfoOp_HistLog },
-    { "Slab", "Slab", kMeminfoOp_HistLog },
-    // { "SReclaimable", "SReclaimable" },
-    // { "SUnreclaim", "SUnreclaim" },
-  };
-  vector<MeminfoRecord> fields(fields_array,
-                               fields_array + arraysize(fields_array));
-  if (!FillMeminfo(meminfo_raw, &fields)) {
-    return false;
-  }
-  int total_memory = fields[0].value;
-  if (total_memory == 0) {
-    // this "cannot happen"
-    LOG(WARNING) << "borked meminfo parser";
-    return false;
-  }
-  int swap_total = 0;
-  int swap_free = 0;
-  // Send all fields retrieved, except total memory.
-  for (unsigned int i = 1; i < fields.size(); i++) {
-    string metrics_name = base::StringPrintf("Platform.Meminfo%s",
-                                             fields[i].name);
-    int percent;
-    switch (fields[i].op) {
-      case kMeminfoOp_HistPercent:
-        // report value as percent of total memory
-        percent = fields[i].value * 100 / total_memory;
-        SendLinearSample(metrics_name, percent, 100, 101);
-        break;
-      case kMeminfoOp_HistLog:
-        // report value in kbytes, log scale, 4Gb max
-        SendSample(metrics_name, fields[i].value, 1, 4 * 1000 * 1000, 100);
-        break;
-      case kMeminfoOp_SwapTotal:
-        swap_total = fields[i].value;
-      case kMeminfoOp_SwapFree:
-        swap_free = fields[i].value;
-        break;
-    }
-  }
-  if (swap_total > 0) {
-    int swap_used = swap_total - swap_free;
-    int swap_used_percent = swap_used * 100 / swap_total;
-    SendSample("Platform.MeminfoSwapUsed", swap_used, 1, 8 * 1000 * 1000, 100);
-    SendLinearSample("Platform.MeminfoSwapUsed.Percent", swap_used_percent,
-                     100, 101);
-  }
-  return true;
-}
-
-bool MetricsCollector::FillMeminfo(const string& meminfo_raw,
-                                    vector<MeminfoRecord>* fields) {
-  vector<std::string> lines =
-      base::SplitString(meminfo_raw, "\n", base::KEEP_WHITESPACE,
-                        base::SPLIT_WANT_NONEMPTY);
-
-  // Scan meminfo output and collect field values.  Each field name has to
-  // match a meminfo entry (case insensitive) after removing non-alpha
-  // characters from the entry.
-  size_t ifield = 0;
-  for (size_t iline = 0;
-       iline < lines.size() && ifield < fields->size();
-       iline++) {
-    vector<string> tokens =
-        base::SplitString(lines[iline], ": ", base::KEEP_WHITESPACE,
-                          base::SPLIT_WANT_NONEMPTY);
-    if (strcmp((*fields)[ifield].match, tokens[0].c_str()) == 0) {
-      // Name matches. Parse value and save.
-      if (!base::StringToInt(tokens[1], &(*fields)[ifield].value)) {
-        LOG(WARNING) << "Cound not convert " << tokens[1] << " to int";
-        return false;
-      }
-      ifield++;
-    }
-  }
-  if (ifield < fields->size()) {
-    // End of input reached while scanning.
-    LOG(WARNING) << "cannot find field " << (*fields)[ifield].match
-                 << " and following";
-    return false;
-  }
-  return true;
-}
-
-void MetricsCollector::ScheduleMemuseCallback(double interval) {
-  if (testing_) {
-    return;
-  }
-  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-      base::Bind(&MetricsCollector::MemuseCallback,
-                 weak_ptr_factory_.GetWeakPtr()),
-      base::TimeDelta::FromSeconds(interval));
-}
-
-void MetricsCollector::MemuseCallback() {
-  // Since we only care about active time (i.e. uptime minus sleep time) but
-  // the callbacks are driven by real time (uptime), we check if we should
-  // reschedule this callback due to intervening sleep periods.
-  double now = GetActiveTime();
-  // Avoid intervals of less than one second.
-  double remaining_time = ceil(memuse_final_time_ - now);
-  if (remaining_time > 0) {
-    ScheduleMemuseCallback(remaining_time);
-  } else {
-    // Report stats and advance the measurement interval unless there are
-    // errors or we've completed the last interval.
-    if (MemuseCallbackWork() &&
-        memuse_interval_index_ < arraysize(kMemuseIntervals)) {
-      double interval = kMemuseIntervals[memuse_interval_index_++];
-      memuse_final_time_ = now + interval;
-      ScheduleMemuseCallback(interval);
-    }
-  }
-}
-
-bool MetricsCollector::MemuseCallbackWork() {
-  string meminfo_raw;
-  const FilePath meminfo_path(kMeminfoFileName);
-  if (!base::ReadFileToString(meminfo_path, &meminfo_raw)) {
-    LOG(WARNING) << "cannot read " << meminfo_path.value().c_str();
-    return false;
-  }
-  return ProcessMemuse(meminfo_raw);
-}
-
-bool MetricsCollector::ProcessMemuse(const string& meminfo_raw) {
-  static const MeminfoRecord fields_array[] = {
-    { "MemTotal", "MemTotal" },  // SPECIAL CASE: total system memory
-    { "ActiveAnon", "Active(anon)" },
-    { "InactiveAnon", "Inactive(anon)" },
-  };
-  vector<MeminfoRecord> fields(fields_array,
-                               fields_array + arraysize(fields_array));
-  if (!FillMeminfo(meminfo_raw, &fields)) {
-    return false;
-  }
-  int total = fields[0].value;
-  int active_anon = fields[1].value;
-  int inactive_anon = fields[2].value;
-  if (total == 0) {
-    // this "cannot happen"
-    LOG(WARNING) << "borked meminfo parser";
-    return false;
-  }
-  string metrics_name = base::StringPrintf("Platform.MemuseAnon%d",
-                                           memuse_interval_index_);
-  SendLinearSample(metrics_name, (active_anon + inactive_anon) * 100 / total,
-                   100, 101);
-  return true;
-}
-
-void MetricsCollector::SendSample(const string& name, int sample,
-                                   int min, int max, int nbuckets) {
-  metrics_lib_->SendToUMA(name, sample, min, max, nbuckets);
-}
-
-void MetricsCollector::SendKernelCrashesCumulativeCountStats() {
-  // Report the number of crashes for this OS version, but don't clear the
-  // counter.  It is cleared elsewhere on version change.
-  int64_t crashes_count = kernel_crashes_version_count_->Get();
-  SendSample(kernel_crashes_version_count_->Name(),
-             crashes_count,
-             1,                         // value of first bucket
-             500,                       // value of last bucket
-             100);                      // number of buckets
-
-
-  int64_t cpu_use_ms = version_cumulative_cpu_use_->Get();
-  SendSample(version_cumulative_cpu_use_->Name(),
-             cpu_use_ms / 1000,         // stat is in seconds
-             1,                         // device may be used very little...
-             8 * 1000 * 1000,           // ... or a lot (a little over 90 days)
-             100);
-
-  // On the first run after an autoupdate, cpu_use_ms and active_use_seconds
-  // can be zero.  Avoid division by zero.
-  if (cpu_use_ms > 0) {
-    // Send the crash frequency since update in number of crashes per CPU year.
-    SendSample("Logging.KernelCrashesPerCpuYear",
-               crashes_count * kSecondsPerDay * 365 * 1000 / cpu_use_ms,
-               1,
-               1000 * 1000,     // about one crash every 30s of CPU time
-               100);
-  }
-
-  int64_t active_use_seconds = version_cumulative_active_use_->Get();
-  if (active_use_seconds > 0) {
-    SendSample(version_cumulative_active_use_->Name(),
-               active_use_seconds,
-               1,                          // device may be used very little...
-               8 * 1000 * 1000,            // ... or a lot (about 90 days)
-               100);
-    // Same as above, but per year of active time.
-    SendSample("Logging.KernelCrashesPerActiveYear",
-               crashes_count * kSecondsPerDay * 365 / active_use_seconds,
-               1,
-               1000 * 1000,     // about one crash every 30s of active time
-               100);
-  }
-}
-
-void MetricsCollector::SendAndResetDailyUseSample(
-    const unique_ptr<PersistentInteger>& use) {
-  SendSample(use->Name(),
-             use->GetAndClear(),
-             1,                        // value of first bucket
-             kSecondsPerDay,           // value of last bucket
-             50);                      // number of buckets
-}
-
-void MetricsCollector::SendAndResetCrashIntervalSample(
-    const unique_ptr<PersistentInteger>& interval) {
-  SendSample(interval->Name(),
-             interval->GetAndClear(),
-             1,                        // value of first bucket
-             4 * kSecondsPerWeek,      // value of last bucket
-             50);                      // number of buckets
-}
-
-void MetricsCollector::SendAndResetCrashFrequencySample(
-    const unique_ptr<PersistentInteger>& frequency) {
-  SendSample(frequency->Name(),
-             frequency->GetAndClear(),
-             1,                        // value of first bucket
-             100,                      // value of last bucket
-             50);                      // number of buckets
-}
-
-void MetricsCollector::SendLinearSample(const string& name, int sample,
-                                         int max, int nbuckets) {
-  // TODO(semenzato): add a proper linear histogram to the Chrome external
-  // metrics API.
-  LOG_IF(FATAL, nbuckets != max + 1) << "unsupported histogram scale";
-  metrics_lib_->SendEnumToUMA(name, sample, max);
-}
-
-void MetricsCollector::UpdateStats(TimeTicks now_ticks,
-                                    Time now_wall_time) {
-  const int elapsed_seconds = (now_ticks - last_update_stats_time_).InSeconds();
-  daily_active_use_->Add(elapsed_seconds);
-  version_cumulative_active_use_->Add(elapsed_seconds);
-  user_crash_interval_->Add(elapsed_seconds);
-  kernel_crash_interval_->Add(elapsed_seconds);
-  TimeDelta cpu_use = cpu_usage_collector_->GetCumulativeCpuUse();
-  version_cumulative_cpu_use_->Add(
-      (cpu_use - latest_cpu_use_microseconds_).InMilliseconds());
-  latest_cpu_use_microseconds_ = cpu_use;
-  last_update_stats_time_ = now_ticks;
-
-  const TimeDelta since_epoch = now_wall_time - Time::UnixEpoch();
-  const int day = since_epoch.InDays();
-  const int week = day / 7;
-
-  if (daily_cycle_->Get() != day) {
-    daily_cycle_->Set(day);
-    SendAndResetDailyUseSample(daily_active_use_);
-    SendAndResetCrashFrequencySample(any_crashes_daily_count_);
-    SendAndResetCrashFrequencySample(user_crashes_daily_count_);
-    SendAndResetCrashFrequencySample(kernel_crashes_daily_count_);
-    SendAndResetCrashFrequencySample(unclean_shutdowns_daily_count_);
-    SendKernelCrashesCumulativeCountStats();
-  }
-
-  if (weekly_cycle_->Get() != week) {
-    weekly_cycle_->Set(week);
-    SendAndResetCrashFrequencySample(any_crashes_weekly_count_);
-    SendAndResetCrashFrequencySample(user_crashes_weekly_count_);
-    SendAndResetCrashFrequencySample(kernel_crashes_weekly_count_);
-    SendAndResetCrashFrequencySample(unclean_shutdowns_weekly_count_);
-  }
-}
-
-void MetricsCollector::HandleUpdateStatsTimeout() {
-  UpdateStats(TimeTicks::Now(), Time::Now());
-  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-      base::Bind(&MetricsCollector::HandleUpdateStatsTimeout,
-                 weak_ptr_factory_.GetWeakPtr()),
-      base::TimeDelta::FromMilliseconds(kUpdateStatsIntervalMs));
-}
diff --git a/metricsd/metrics_collector.h b/metricsd/metrics_collector.h
deleted file mode 100644
index 30659bd..0000000
--- a/metricsd/metrics_collector.h
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICS_METRICS_COLLECTOR_H_
-#define METRICS_METRICS_COLLECTOR_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <base/files/file_path.h>
-#include <base/memory/weak_ptr.h>
-#include <base/time/time.h>
-#include <brillo/binder_watcher.h>
-#include <brillo/daemons/daemon.h>
-#include <libweaved/command.h>
-#include <libweaved/service.h>
-#include <gtest/gtest_prod.h>  // for FRIEND_TEST
-
-#include "collectors/averaged_statistics_collector.h"
-#include "collectors/cpu_usage_collector.h"
-#include "collectors/disk_usage_collector.h"
-#include "metrics/metrics_library.h"
-#include "persistent_integer.h"
-
-using chromeos_metrics::PersistentInteger;
-using std::unique_ptr;
-
-class MetricsCollector : public brillo::Daemon {
- public:
-  MetricsCollector();
-  ~MetricsCollector();
-
-  // Initializes metrics class variables.
-  void Init(bool testing,
-            MetricsLibraryInterface* metrics_lib,
-            const std::string& diskstats_path,
-            const base::FilePath& private_metrics_directory,
-            const base::FilePath& shared_metrics_directory);
-
-  // Initializes the daemon.
-  int OnInit() override;
-
-  // Does all the work.
-  int Run() override;
-
-  // Returns the active time since boot (uptime minus sleep time) in seconds.
-  static double GetActiveTime();
-
-  // Updates the active use time and logs time between user-space
-  // process crashes.  Called via MetricsCollectorServiceTrampoline.
-  void ProcessUserCrash();
-
- protected:
-  // Used also by the unit tests.
-  static const char kComprDataSizeName[];
-  static const char kOrigDataSizeName[];
-  static const char kZeroPagesName[];
-
- private:
-  friend class MetricsCollectorTest;
-  FRIEND_TEST(MetricsCollectorTest, CheckSystemCrash);
-  FRIEND_TEST(MetricsCollectorTest, ComputeEpochNoCurrent);
-  FRIEND_TEST(MetricsCollectorTest, ComputeEpochNoLast);
-  FRIEND_TEST(MetricsCollectorTest, GetHistogramPath);
-  FRIEND_TEST(MetricsCollectorTest, IsNewEpoch);
-  FRIEND_TEST(MetricsCollectorTest, MessageFilter);
-  FRIEND_TEST(MetricsCollectorTest, ProcessKernelCrash);
-  FRIEND_TEST(MetricsCollectorTest, ProcessMeminfo);
-  FRIEND_TEST(MetricsCollectorTest, ProcessMeminfo2);
-  FRIEND_TEST(MetricsCollectorTest, ProcessUncleanShutdown);
-  FRIEND_TEST(MetricsCollectorTest, ProcessUserCrash);
-  FRIEND_TEST(MetricsCollectorTest, ReportCrashesDailyFrequency);
-  FRIEND_TEST(MetricsCollectorTest, ReportKernelCrashInterval);
-  FRIEND_TEST(MetricsCollectorTest, ReportUncleanShutdownInterval);
-  FRIEND_TEST(MetricsCollectorTest, ReportUserCrashInterval);
-  FRIEND_TEST(MetricsCollectorTest, SendSample);
-  FRIEND_TEST(MetricsCollectorTest, SendZramMetrics);
-
-  // Type of scale to use for meminfo histograms.  For most of them we use
-  // percent of total RAM, but for some we use absolute numbers, usually in
-  // megabytes, on a log scale from 0 to 4000, and 0 to 8000 for compressed
-  // swap (since it can be larger than total RAM).
-  enum MeminfoOp {
-    kMeminfoOp_HistPercent = 0,
-    kMeminfoOp_HistLog,
-    kMeminfoOp_SwapTotal,
-    kMeminfoOp_SwapFree,
-  };
-
-  // Record for retrieving and reporting values from /proc/meminfo.
-  struct MeminfoRecord {
-    const char* name;        // print name
-    const char* match;       // string to match in output of /proc/meminfo
-    MeminfoOp op;            // histogram scale selector, or other operator
-    int value;               // value from /proc/meminfo
-  };
-
-  // Enables metrics reporting.
-  void OnEnableMetrics(std::unique_ptr<weaved::Command> command);
-
-  // Disables metrics reporting.
-  void OnDisableMetrics(std::unique_ptr<weaved::Command> command);
-
-  // Updates the weave device state.
-  void UpdateWeaveState();
-
-  // Updates the active use time and logs time between kernel crashes.
-  void ProcessKernelCrash();
-
-  // Updates the active use time and logs time between unclean shutdowns.
-  void ProcessUncleanShutdown();
-
-  // Checks if a kernel crash has been detected and returns true if
-  // so.  The method assumes that a kernel crash has happened if
-  // |crash_file| exists.  It removes the file immediately if it
-  // exists, so it must not be called more than once.
-  bool CheckSystemCrash(const std::string& crash_file);
-
-  // Sends a regular (exponential) histogram sample to Chrome for
-  // transport to UMA. See MetricsLibrary::SendToUMA in
-  // metrics_library.h for a description of the arguments.
-  void SendSample(const std::string& name, int sample,
-                  int min, int max, int nbuckets);
-
-  // Sends a linear histogram sample to Chrome for transport to UMA. See
-  // MetricsLibrary::SendToUMA in metrics_library.h for a description of the
-  // arguments.
-  void SendLinearSample(const std::string& name, int sample,
-                        int max, int nbuckets);
-
-  // Sends various cumulative kernel crash-related stats, for instance the
-  // total number of kernel crashes since the last version update.
-  void SendKernelCrashesCumulativeCountStats();
-
-  // Sends a sample representing the number of seconds of active use
-  // for a 24-hour period and reset |use|.
-  void SendAndResetDailyUseSample(const unique_ptr<PersistentInteger>& use);
-
-  // Sends a sample representing a time interval between two crashes of the
-  // same type and reset |interval|.
-  void SendAndResetCrashIntervalSample(
-      const unique_ptr<PersistentInteger>& interval);
-
-  // Sends a sample representing a frequency of crashes of some type and reset
-  // |frequency|.
-  void SendAndResetCrashFrequencySample(
-      const unique_ptr<PersistentInteger>& frequency);
-
-  // Initializes vm and disk stats reporting.
-  void StatsReporterInit();
-
-  // Schedules meminfo collection callback.
-  void ScheduleMeminfoCallback(int wait);
-
-  // Reports memory statistics.  Reschedules callback on success.
-  void MeminfoCallback(base::TimeDelta wait);
-
-  // Parses content of /proc/meminfo and sends fields of interest to UMA.
-  // Returns false on errors.  |meminfo_raw| contains the content of
-  // /proc/meminfo.
-  bool ProcessMeminfo(const std::string& meminfo_raw);
-
-  // Parses meminfo data from |meminfo_raw|.  |fields| is a vector containing
-  // the fields of interest.  The order of the fields must be the same in which
-  // /proc/meminfo prints them.  The result of parsing fields[i] is placed in
-  // fields[i].value.
-  bool FillMeminfo(const std::string& meminfo_raw,
-                   std::vector<MeminfoRecord>* fields);
-
-  // Schedule a memory use callback in |interval| seconds.
-  void ScheduleMemuseCallback(double interval);
-
-  // Calls MemuseCallbackWork, and possibly schedules next callback, if enough
-  // active time has passed.  Otherwise reschedules itself to simulate active
-  // time callbacks (i.e. wall clock time minus sleep time).
-  void MemuseCallback();
-
-  // Reads /proc/meminfo and sends total anonymous memory usage to UMA.
-  bool MemuseCallbackWork();
-
-  // Parses meminfo data and sends it to UMA.
-  bool ProcessMemuse(const std::string& meminfo_raw);
-
-  // Reads the current OS version from /etc/lsb-release and hashes it
-  // to a unsigned 32-bit int.
-  uint32_t GetOsVersionHash();
-
-  // Updates stats, additionally sending them to UMA if enough time has elapsed
-  // since the last report.
-  void UpdateStats(base::TimeTicks now_ticks, base::Time now_wall_time);
-
-  // Invoked periodically by |update_stats_timeout_id_| to call UpdateStats().
-  void HandleUpdateStatsTimeout();
-
-  // Reports zram statistics.
-  bool ReportZram(const base::FilePath& zram_dir);
-
-  // Reads a string from a file and converts it to uint64_t.
-  static bool ReadFileToUint64(const base::FilePath& path, uint64_t* value);
-
-  // Callback invoked when a connection to weaved's service is established
-  // over Binder interface.
-  void OnWeaveServiceConnected(const std::weak_ptr<weaved::Service>& service);
-
-  // VARIABLES
-
-  // Test mode.
-  bool testing_;
-
-  // Publicly readable metrics directory.
-  base::FilePath shared_metrics_directory_;
-
-  // The metrics library handle.
-  MetricsLibraryInterface* metrics_lib_;
-
-  // The last time that UpdateStats() was called.
-  base::TimeTicks last_update_stats_time_;
-
-  // End time of current memuse stat collection interval.
-  double memuse_final_time_;
-
-  // Selects the wait time for the next memory use callback.
-  unsigned int memuse_interval_index_;
-
-  // Used internally by GetIncrementalCpuUse() to return the CPU utilization
-  // between calls.
-  base::TimeDelta latest_cpu_use_microseconds_;
-
-  // Persistent values and accumulators for crash statistics.
-  unique_ptr<PersistentInteger> daily_cycle_;
-  unique_ptr<PersistentInteger> weekly_cycle_;
-  unique_ptr<PersistentInteger> version_cycle_;
-
-  // Active use accumulated in a day.
-  unique_ptr<PersistentInteger> daily_active_use_;
-  // Active use accumulated since the latest version update.
-  unique_ptr<PersistentInteger> version_cumulative_active_use_;
-
-  // The CPU time accumulator.  This contains the CPU time, in milliseconds,
-  // used by the system since the most recent OS version update.
-  unique_ptr<PersistentInteger> version_cumulative_cpu_use_;
-
-  unique_ptr<PersistentInteger> user_crash_interval_;
-  unique_ptr<PersistentInteger> kernel_crash_interval_;
-  unique_ptr<PersistentInteger> unclean_shutdown_interval_;
-
-  unique_ptr<PersistentInteger> any_crashes_daily_count_;
-  unique_ptr<PersistentInteger> any_crashes_weekly_count_;
-  unique_ptr<PersistentInteger> user_crashes_daily_count_;
-  unique_ptr<PersistentInteger> user_crashes_weekly_count_;
-  unique_ptr<PersistentInteger> kernel_crashes_daily_count_;
-  unique_ptr<PersistentInteger> kernel_crashes_weekly_count_;
-  unique_ptr<PersistentInteger> kernel_crashes_version_count_;
-  unique_ptr<PersistentInteger> unclean_shutdowns_daily_count_;
-  unique_ptr<PersistentInteger> unclean_shutdowns_weekly_count_;
-
-  unique_ptr<CpuUsageCollector> cpu_usage_collector_;
-  unique_ptr<DiskUsageCollector> disk_usage_collector_;
-  unique_ptr<AveragedStatisticsCollector> averaged_stats_collector_;
-
-  unique_ptr<weaved::Service::Subscription> weave_service_subscription_;
-  std::weak_ptr<weaved::Service> service_;
-
-  base::WeakPtrFactory<MetricsCollector> weak_ptr_factory_{this};
-};
-
-#endif  // METRICS_METRICS_COLLECTOR_H_
diff --git a/metricsd/metrics_collector.rc b/metricsd/metrics_collector.rc
deleted file mode 100644
index 2d7667d..0000000
--- a/metricsd/metrics_collector.rc
+++ /dev/null
@@ -1,4 +0,0 @@
-service metricscollector /system/bin/metrics_collector --foreground --logtosyslog
-    class late_start
-    user metrics_coll
-    group metrics_coll
diff --git a/metricsd/metrics_collector_main.cc b/metricsd/metrics_collector_main.cc
deleted file mode 100644
index 14bb935..0000000
--- a/metricsd/metrics_collector_main.cc
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <base/at_exit.h>
-#include <base/command_line.h>
-#include <base/logging.h>
-#include <base/strings/string_util.h>
-#include <brillo/flag_helper.h>
-#include <brillo/syslog_logging.h>
-#include <rootdev.h>
-
-#include "constants.h"
-#include "metrics_collector.h"
-
-
-// Returns the path to the disk stats in the sysfs.  Returns the null string if
-// it cannot find the disk stats file.
-static
-const std::string MetricsMainDiskStatsPath() {
-  char dev_path_cstr[PATH_MAX];
-  std::string dev_prefix = "/dev/block/";
-  std::string dev_path;
-
-  int ret = rootdev(dev_path_cstr, sizeof(dev_path_cstr), true, true);
-  if (ret != 0) {
-    LOG(WARNING) << "error " << ret << " determining root device";
-    return "";
-  }
-  dev_path = dev_path_cstr;
-  // Check that rootdev begins with "/dev/block/".
-  if (!base::StartsWith(dev_path, dev_prefix,
-                        base::CompareCase::INSENSITIVE_ASCII)) {
-    LOG(WARNING) << "unexpected root device " << dev_path;
-    return "";
-  }
-  return "/sys/class/block/" + dev_path.substr(dev_prefix.length()) + "/stat";
-}
-
-int main(int argc, char** argv) {
-  DEFINE_bool(foreground, false, "Don't daemonize");
-
-  DEFINE_string(private_directory, metrics::kMetricsCollectorDirectory,
-                "Path to the private directory used by metrics_collector "
-                "(testing only)");
-  DEFINE_string(shared_directory, metrics::kSharedMetricsDirectory,
-                "Path to the shared metrics directory, used by "
-                "metrics_collector, metricsd and all metrics clients "
-                "(testing only)");
-
-  DEFINE_bool(logtostderr, false, "Log to standard error");
-  DEFINE_bool(logtosyslog, false, "Log to syslog");
-
-  brillo::FlagHelper::Init(argc, argv, "Chromium OS Metrics Daemon");
-
-  int logging_location = (FLAGS_foreground ? brillo::kLogToStderr
-                          : brillo::kLogToSyslog);
-  if (FLAGS_logtosyslog)
-    logging_location = brillo::kLogToSyslog;
-
-  if (FLAGS_logtostderr)
-    logging_location = brillo::kLogToStderr;
-
-  // Also log to stderr when not running as daemon.
-  brillo::InitLog(logging_location | brillo::kLogHeader);
-
-  if (FLAGS_logtostderr && FLAGS_logtosyslog) {
-    LOG(ERROR) << "only one of --logtosyslog and --logtostderr can be set";
-    return 1;
-  }
-
-  if (!FLAGS_foreground && daemon(0, 0) != 0) {
-    return errno;
-  }
-
-  MetricsLibrary metrics_lib;
-  metrics_lib.InitWithNoCaching();
-  MetricsCollector daemon;
-  daemon.Init(false,
-              &metrics_lib,
-              MetricsMainDiskStatsPath(),
-              base::FilePath(FLAGS_private_directory),
-              base::FilePath(FLAGS_shared_directory));
-
-  daemon.Run();
-}
diff --git a/metricsd/metrics_collector_service_client.cc b/metricsd/metrics_collector_service_client.cc
deleted file mode 100644
index 08aaa4a..0000000
--- a/metricsd/metrics_collector_service_client.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Client interface to IMetricsCollectorService.
-
-#include "metrics/metrics_collector_service_client.h"
-
-#include <base/logging.h>
-#include <binder/IServiceManager.h>
-#include <utils/String16.h>
-
-#include "android/brillo/metrics/IMetricsCollectorService.h"
-
-namespace {
-const char kMetricsCollectorServiceName[] =
-    "android.brillo.metrics.IMetricsCollectorService";
-}
-
-bool MetricsCollectorServiceClient::Init() {
-  const android::String16 name(kMetricsCollectorServiceName);
-  metrics_collector_service_ = android::interface_cast<
-      android::brillo::metrics::IMetricsCollectorService>(
-      android::defaultServiceManager()->checkService(name));
-
-  if (metrics_collector_service_ == nullptr)
-    LOG(ERROR) << "Unable to lookup service " << kMetricsCollectorServiceName;
-
-  return metrics_collector_service_ != nullptr;
-}
-
-bool MetricsCollectorServiceClient::notifyUserCrash() {
-  if (metrics_collector_service_ == nullptr)
-    return false;
-
-  metrics_collector_service_->notifyUserCrash();
-  return true;
-}
diff --git a/metricsd/metrics_collector_service_impl.cc b/metricsd/metrics_collector_service_impl.cc
deleted file mode 100644
index 4d9a05a..0000000
--- a/metricsd/metrics_collector_service_impl.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "metrics_collector_service_impl.h"
-
-#include <binder/IServiceManager.h>
-#include <binder/Status.h>
-#include <utils/Errors.h>
-
-#include "metrics_collector.h"
-
-using namespace android;
-
-BnMetricsCollectorServiceImpl::BnMetricsCollectorServiceImpl(
-    MetricsCollector* metrics_collector)
-    : metrics_collector_(metrics_collector) {
-}
-
-android::binder::Status BnMetricsCollectorServiceImpl::notifyUserCrash() {
-  metrics_collector_->ProcessUserCrash();
-  return android::binder::Status::ok();
-}
diff --git a/metricsd/metrics_collector_service_impl.h b/metricsd/metrics_collector_service_impl.h
deleted file mode 100644
index 8db418a..0000000
--- a/metricsd/metrics_collector_service_impl.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICSD_METRICS_COLLECTOR_SERVICE_IMPL_H_
-#define METRICSD_METRICS_COLLECTOR_SERVICE_IMPL_H_
-
-// metrics_collector binder service implementation.  Constructed by
-// MetricsCollector.
-
-#include "android/brillo/metrics/BnMetricsCollectorService.h"
-
-#include <binder/Status.h>
-
-class MetricsCollector;
-
-class BnMetricsCollectorServiceImpl
-    : public android::brillo::metrics::BnMetricsCollectorService {
- public:
-  // Passed a this pointer from the MetricsCollector object that constructs us.
-  explicit BnMetricsCollectorServiceImpl(
-      MetricsCollector* metrics_collector_service);
-
-  virtual ~BnMetricsCollectorServiceImpl() = default;
-
-  // Called by crash_reporter to report a userspace crash event.  We relay
-  // this to MetricsCollector.
-  android::binder::Status notifyUserCrash();
-
- private:
-  // MetricsCollector object that constructs us, we use this to call back
-  // to it.
-  MetricsCollector* metrics_collector_;
-};
-
-#endif  // METRICSD_METRICS_COLLECTOR_SERVICE_IMPL_H_
diff --git a/metricsd/metrics_collector_test.cc b/metricsd/metrics_collector_test.cc
deleted file mode 100644
index 8dda529..0000000
--- a/metricsd/metrics_collector_test.cc
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <vector>
-
-#include <base/at_exit.h>
-#include <base/files/file_util.h>
-#include <base/files/scoped_temp_dir.h>
-#include <base/strings/string_number_conversions.h>
-#include <brillo/flag_helper.h>
-#include <gtest/gtest.h>
-
-#include "constants.h"
-#include "metrics_collector.h"
-#include "metrics/metrics_library_mock.h"
-#include "persistent_integer_mock.h"
-
-using base::FilePath;
-using base::TimeDelta;
-using std::string;
-using std::vector;
-using ::testing::_;
-using ::testing::AnyNumber;
-using ::testing::AtLeast;
-using ::testing::Return;
-using ::testing::StrictMock;
-using chromeos_metrics::PersistentIntegerMock;
-
-
-class MetricsCollectorTest : public testing::Test {
- protected:
-  virtual void SetUp() {
-    brillo::FlagHelper::Init(0, nullptr, "");
-    EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
-
-    base::FilePath private_dir = temp_dir_.path().Append("private");
-    base::FilePath shared_dir = temp_dir_.path().Append("shared");
-
-    EXPECT_TRUE(base::CreateDirectory(private_dir));
-    EXPECT_TRUE(base::CreateDirectory(shared_dir));
-
-    daemon_.Init(true, &metrics_lib_, "", private_dir, shared_dir);
-  }
-
-  // Adds a metrics library mock expectation that the specified metric
-  // will be generated.
-  void ExpectSample(const std::string& name, int sample) {
-    EXPECT_CALL(metrics_lib_, SendToUMA(name, sample, _, _, _))
-        .Times(1)
-        .WillOnce(Return(true))
-        .RetiresOnSaturation();
-  }
-
-  // Creates or overwrites the file in |path| so that it contains the printable
-  // representation of |value|.
-  void CreateUint64ValueFile(const base::FilePath& path, uint64_t value) {
-    std::string value_string = base::Uint64ToString(value);
-    ASSERT_EQ(value_string.length(),
-              base::WriteFile(path, value_string.c_str(),
-                              value_string.length()));
-  }
-
-  // The MetricsCollector under test.
-  MetricsCollector daemon_;
-
-  // Temporary directory used for tests.
-  base::ScopedTempDir temp_dir_;
-
-  // Mocks. They are strict mock so that all unexpected
-  // calls are marked as failures.
-  StrictMock<MetricsLibraryMock> metrics_lib_;
-};
-
-TEST_F(MetricsCollectorTest, SendSample) {
-  ExpectSample("Dummy.Metric", 3);
-  daemon_.SendSample("Dummy.Metric", /* sample */ 3,
-                     /* min */ 1, /* max */ 100, /* buckets */ 50);
-}
-
-TEST_F(MetricsCollectorTest, ProcessMeminfo) {
-  string meminfo =
-      "MemTotal:        2000000 kB\nMemFree:          500000 kB\n"
-      "Buffers:         1000000 kB\nCached:           213652 kB\n"
-      "SwapCached:            0 kB\nActive:           133400 kB\n"
-      "Inactive:         183396 kB\nActive(anon):      92984 kB\n"
-      "Inactive(anon):    58860 kB\nActive(file):      40416 kB\n"
-      "Inactive(file):   124536 kB\nUnevictable:           0 kB\n"
-      "Mlocked:               0 kB\nSwapTotal:             0 kB\n"
-      "SwapFree:              0 kB\nDirty:                40 kB\n"
-      "Writeback:             0 kB\nAnonPages:         92652 kB\n"
-      "Mapped:            59716 kB\nShmem:             59196 kB\n"
-      "Slab:              16656 kB\nSReclaimable:       6132 kB\n"
-      "SUnreclaim:        10524 kB\nKernelStack:        1648 kB\n"
-      "PageTables:         2780 kB\nNFS_Unstable:          0 kB\n"
-      "Bounce:                0 kB\nWritebackTmp:          0 kB\n"
-      "CommitLimit:      970656 kB\nCommitted_AS:    1260528 kB\n"
-      "VmallocTotal:     122880 kB\nVmallocUsed:       12144 kB\n"
-      "VmallocChunk:     103824 kB\nDirectMap4k:        9636 kB\n"
-      "DirectMap2M:     1955840 kB\n";
-
-  // All enum calls must report percents.
-  EXPECT_CALL(metrics_lib_, SendEnumToUMA(_, _, 100)).Times(AtLeast(1));
-  // Check that MemFree is correctly computed at 25%.
-  EXPECT_CALL(metrics_lib_, SendEnumToUMA("Platform.MeminfoMemFree", 25, 100))
-      .Times(AtLeast(1));
-  // Check that we call SendToUma at least once (log histogram).
-  EXPECT_CALL(metrics_lib_, SendToUMA(_, _, _, _, _))
-      .Times(AtLeast(1));
-  // Make sure we don't report fields not in the list.
-  EXPECT_CALL(metrics_lib_, SendToUMA("Platform.MeminfoMlocked", _, _, _, _))
-      .Times(0);
-  EXPECT_CALL(metrics_lib_, SendEnumToUMA("Platform.MeminfoMlocked", _, _))
-      .Times(0);
-  EXPECT_TRUE(daemon_.ProcessMeminfo(meminfo));
-}
-
-TEST_F(MetricsCollectorTest, ProcessMeminfo2) {
-  string meminfo = "MemTotal:        2000000 kB\nMemFree:         1000000 kB\n";
-  // Not enough fields.
-  EXPECT_FALSE(daemon_.ProcessMeminfo(meminfo));
-}
-
-TEST_F(MetricsCollectorTest, SendZramMetrics) {
-  EXPECT_TRUE(daemon_.testing_);
-
-  // |compr_data_size| is the size in bytes of compressed data.
-  const uint64_t compr_data_size = 50 * 1000 * 1000;
-  // The constant '3' is a realistic but random choice.
-  // |orig_data_size| does not include zero pages.
-  const uint64_t orig_data_size = compr_data_size * 3;
-  const uint64_t page_size = 4096;
-  const uint64_t zero_pages = 10 * 1000 * 1000 / page_size;
-
-  CreateUint64ValueFile(
-      temp_dir_.path().Append(MetricsCollector::kComprDataSizeName),
-      compr_data_size);
-  CreateUint64ValueFile(
-      temp_dir_.path().Append(MetricsCollector::kOrigDataSizeName),
-      orig_data_size);
-  CreateUint64ValueFile(
-      temp_dir_.path().Append(MetricsCollector::kZeroPagesName), zero_pages);
-
-  const uint64_t real_orig_size = orig_data_size + zero_pages * page_size;
-  const uint64_t zero_ratio_percent =
-      zero_pages * page_size * 100 / real_orig_size;
-  // Ratio samples are in percents.
-  const uint64_t actual_ratio_sample = real_orig_size * 100 / compr_data_size;
-
-  EXPECT_CALL(metrics_lib_, SendToUMA(_, compr_data_size >> 20, _, _, _));
-  EXPECT_CALL(metrics_lib_,
-              SendToUMA(_, (real_orig_size - compr_data_size) >> 20, _, _, _));
-  EXPECT_CALL(metrics_lib_, SendToUMA(_, actual_ratio_sample, _, _, _));
-  EXPECT_CALL(metrics_lib_, SendToUMA(_, zero_pages, _, _, _));
-  EXPECT_CALL(metrics_lib_, SendToUMA(_, zero_ratio_percent, _, _, _));
-
-  EXPECT_TRUE(daemon_.ReportZram(temp_dir_.path()));
-}
diff --git a/metricsd/metrics_library.cc b/metricsd/metrics_library.cc
deleted file mode 100644
index d211ab4..0000000
--- a/metricsd/metrics_library.cc
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "metrics/metrics_library.h"
-
-#include <base/logging.h>
-#include <base/strings/stringprintf.h>
-#include <binder/IServiceManager.h>
-#include <errno.h>
-#include <sys/file.h>
-#include <sys/stat.h>
-#include <utils/String16.h>
-
-#include <cstdio>
-#include <cstring>
-
-#include "android/brillo/metrics/IMetricsd.h"
-#include "constants.h"
-
-static const char kCrosEventHistogramName[] = "Platform.CrOSEvent";
-static const int kCrosEventHistogramMax = 100;
-static const char kMetricsServiceName[] = "android.brillo.metrics.IMetricsd";
-
-/* Add new cros events here.
- *
- * The index of the event is sent in the message, so please do not
- * reorder the names.
- */
-static const char *kCrosEventNames[] = {
-  "ModemManagerCommandSendFailure",  // 0
-  "HwWatchdogReboot",  // 1
-  "Cras.NoCodecsFoundAtBoot",  // 2
-  "Chaps.DatabaseCorrupted",  // 3
-  "Chaps.DatabaseRepairFailure",  // 4
-  "Chaps.DatabaseCreateFailure",  // 5
-  "Attestation.OriginSpecificExhausted",  // 6
-  "SpringPowerSupply.Original.High",  // 7
-  "SpringPowerSupply.Other.High",  // 8
-  "SpringPowerSupply.Original.Low",  // 9
-  "SpringPowerSupply.ChargerIdle",  // 10
-  "TPM.NonZeroDictionaryAttackCounter",  // 11
-  "TPM.EarlyResetDuringCommand",  // 12
-};
-
-using android::binder::Status;
-using android::brillo::metrics::IMetricsd;
-using android::String16;
-
-MetricsLibrary::MetricsLibrary() {}
-MetricsLibrary::~MetricsLibrary() {}
-
-// We take buffer and buffer_size as parameters in order to simplify testing
-// of various alignments of the |device_name| with |buffer_size|.
-bool MetricsLibrary::IsDeviceMounted(const char* device_name,
-                                     const char* mounts_file,
-                                     char* buffer,
-                                     int buffer_size,
-                                     bool* result) {
-  if (buffer == nullptr || buffer_size < 1)
-    return false;
-  int mounts_fd = open(mounts_file, O_RDONLY);
-  if (mounts_fd < 0)
-    return false;
-  // match_offset describes:
-  //   -1 -- not beginning of line
-  //   0..strlen(device_name)-1 -- this offset in device_name is next to match
-  //   strlen(device_name) -- matched full name, just need a space.
-  int match_offset = 0;
-  bool match = false;
-  while (!match) {
-    int read_size = read(mounts_fd, buffer, buffer_size);
-    if (read_size <= 0) {
-      if (errno == -EINTR)
-        continue;
-      break;
-    }
-    for (int i = 0; i < read_size; ++i) {
-      if (buffer[i] == '\n') {
-        match_offset = 0;
-        continue;
-      }
-      if (match_offset < 0) {
-        continue;
-      }
-      if (device_name[match_offset] == '\0') {
-        if (buffer[i] == ' ') {
-          match = true;
-          break;
-        }
-        match_offset = -1;
-        continue;
-      }
-
-      if (buffer[i] == device_name[match_offset]) {
-        ++match_offset;
-      } else {
-        match_offset = -1;
-      }
-    }
-  }
-  close(mounts_fd);
-  *result = match;
-  return true;
-}
-
-bool MetricsLibrary::IsGuestMode() {
-  char buffer[256];
-  bool result = false;
-  if (!IsDeviceMounted("guestfs",
-                       "/proc/mounts",
-                       buffer,
-                       sizeof(buffer),
-                       &result)) {
-    return false;
-  }
-  return result && (access("/var/run/state/logged-in", F_OK) == 0);
-}
-
-bool MetricsLibrary::CheckService() {
-  if (metricsd_proxy_.get() &&
-      android::IInterface::asBinder(metricsd_proxy_)->isBinderAlive())
-    return true;
-
-  const String16 name(kMetricsServiceName);
-  metricsd_proxy_ = android::interface_cast<IMetricsd>(
-      android::defaultServiceManager()->checkService(name));
-  return metricsd_proxy_.get();
-}
-
-bool MetricsLibrary::AreMetricsEnabled() {
-  static struct stat stat_buffer;
-  time_t this_check_time = time(nullptr);
-  if (!use_caching_ || this_check_time != cached_enabled_time_) {
-    cached_enabled_time_ = this_check_time;
-    cached_enabled_ = stat(consent_file_.value().data(), &stat_buffer) >= 0;
-  }
-  return cached_enabled_;
-}
-
-void MetricsLibrary::Init() {
-  base::FilePath dir = base::FilePath(metrics::kSharedMetricsDirectory);
-  consent_file_ = dir.Append(metrics::kConsentFileName);
-  cached_enabled_ = false;
-  cached_enabled_time_ = 0;
-  use_caching_ = true;
-}
-
-void MetricsLibrary::InitWithNoCaching() {
-  Init();
-  use_caching_ = false;
-}
-
-void MetricsLibrary::InitForTest(const base::FilePath& metrics_directory) {
-  consent_file_ = metrics_directory.Append(metrics::kConsentFileName);
-  cached_enabled_ = false;
-  cached_enabled_time_ = 0;
-  use_caching_ = true;
-}
-
-bool MetricsLibrary::SendToUMA(
-    const std::string& name, int sample, int min, int max, int nbuckets) {
-  return CheckService() &&
-         metricsd_proxy_->recordHistogram(String16(name.c_str()), sample, min,
-                                          max, nbuckets)
-             .isOk();
-}
-
-bool MetricsLibrary::SendEnumToUMA(const std::string& name,
-                                   int sample,
-                                   int max) {
-  return CheckService() &&
-         metricsd_proxy_->recordLinearHistogram(String16(name.c_str()), sample,
-                                                max)
-             .isOk();
-}
-
-bool MetricsLibrary::SendBoolToUMA(const std::string& name, bool sample) {
-  return CheckService() &&
-         metricsd_proxy_->recordLinearHistogram(String16(name.c_str()),
-                                                sample ? 1 : 0, 2)
-             .isOk();
-}
-
-bool MetricsLibrary::SendSparseToUMA(const std::string& name, int sample) {
-  return CheckService() &&
-         metricsd_proxy_->recordSparseHistogram(String16(name.c_str()), sample)
-             .isOk();
-}
-
-bool MetricsLibrary::SendCrashToUMA(const char* crash_kind) {
-  return CheckService() &&
-         metricsd_proxy_->recordCrash(String16(crash_kind)).isOk();
-}
-
-bool MetricsLibrary::SendCrosEventToUMA(const std::string& event) {
-  for (size_t i = 0; i < arraysize(kCrosEventNames); i++) {
-    if (strcmp(event.c_str(), kCrosEventNames[i]) == 0) {
-      return SendEnumToUMA(kCrosEventHistogramName, i, kCrosEventHistogramMax);
-    }
-  }
-  return false;
-}
-
-bool MetricsLibrary::GetHistogramsDump(std::string* dump) {
-  android::String16 temp_dump;
-  if (!CheckService() ||
-      !metricsd_proxy_->getHistogramsDump(&temp_dump).isOk()) {
-    return false;
-  }
-
-  *dump = android::String8(temp_dump).string();
-  return true;
-}
diff --git a/metricsd/metrics_library_test.cc b/metricsd/metrics_library_test.cc
deleted file mode 100644
index 52fcce3..0000000
--- a/metricsd/metrics_library_test.cc
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#include <base/files/file_util.h>
-#include <base/files/scoped_temp_dir.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include "metrics/c_metrics_library.h"
-#include "metrics/metrics_library.h"
-
-
-class MetricsLibraryTest : public testing::Test {
- protected:
-  virtual void SetUp() {
-    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    lib_.InitForTest(temp_dir_.path());
-    // Defeat metrics enabled caching between tests.
-    lib_.cached_enabled_time_ = 0;
-  }
-
-  void SetMetricsConsent(bool enabled) {
-    if (enabled) {
-      ASSERT_EQ(base::WriteFile(lib_.consent_file_, "", 0), 0);
-    } else {
-      ASSERT_TRUE(base::DeleteFile(lib_.consent_file_, false));
-    }
-  }
-
-  void VerifyEnabledCacheHit(bool to_value);
-  void VerifyEnabledCacheEviction(bool to_value);
-
-  MetricsLibrary lib_;
-  base::ScopedTempDir temp_dir_;
-};
-
-TEST_F(MetricsLibraryTest, AreMetricsEnabledFalse) {
-  SetMetricsConsent(false);
-  EXPECT_FALSE(lib_.AreMetricsEnabled());
-}
-
-TEST_F(MetricsLibraryTest, AreMetricsEnabledTrue) {
-  SetMetricsConsent(true);
-  EXPECT_TRUE(lib_.AreMetricsEnabled());
-}
-
-void MetricsLibraryTest::VerifyEnabledCacheHit(bool to_value) {
-  // We might step from one second to the next one time, but not 100
-  // times in a row.
-  for (int i = 0; i < 100; ++i) {
-    lib_.cached_enabled_time_ = 0;
-    SetMetricsConsent(to_value);
-    lib_.AreMetricsEnabled();
-    // If we check the metrics status twice in a row, we use the cached value
-    // the second time.
-    SetMetricsConsent(!to_value);
-    if (lib_.AreMetricsEnabled() == to_value)
-      return;
-  }
-  ADD_FAILURE() << "Did not see evidence of caching";
-}
-
-void MetricsLibraryTest::VerifyEnabledCacheEviction(bool to_value) {
-  lib_.cached_enabled_time_ = 0;
-  SetMetricsConsent(!to_value);
-  ASSERT_EQ(!to_value, lib_.AreMetricsEnabled());
-
-  SetMetricsConsent(to_value);
-  // Sleep one second (or cheat to be faster) and check that we are not using
-  // the cached value.
-  --lib_.cached_enabled_time_;
-  ASSERT_EQ(to_value, lib_.AreMetricsEnabled());
-}
-
-TEST_F(MetricsLibraryTest, AreMetricsEnabledCaching) {
-  VerifyEnabledCacheHit(false);
-  VerifyEnabledCacheHit(true);
-  VerifyEnabledCacheEviction(false);
-  VerifyEnabledCacheEviction(true);
-}
-
-TEST_F(MetricsLibraryTest, AreMetricsEnabledNoCaching) {
-  // disable caching.
-  lib_.use_caching_ = false;
-
-  // Checking the consent repeatedly should return the right result.
-  for (int i=0; i<100; ++i) {
-    SetMetricsConsent(true);
-    ASSERT_EQ(true, lib_.AreMetricsEnabled());
-    SetMetricsConsent(false);
-    ASSERT_EQ(false, lib_.AreMetricsEnabled());
-  }
-}
diff --git a/metricsd/metricsd.rc b/metricsd/metricsd.rc
deleted file mode 100644
index 3d3e695..0000000
--- a/metricsd/metricsd.rc
+++ /dev/null
@@ -1,9 +0,0 @@
-on post-fs-data
-    mkdir /data/misc/metrics 0750 metrics_coll system
-    mkdir /data/misc/metricsd 0700 metricsd metricsd
-    mkdir /data/misc/metrics_collector 0700 metrics_coll metrics_coll
-
-service metricsd /system/bin/metricsd --foreground --logtosyslog
-    class late_start
-    user metricsd
-    group system inet
diff --git a/metricsd/metricsd_main.cc b/metricsd/metricsd_main.cc
deleted file mode 100644
index 0178342..0000000
--- a/metricsd/metricsd_main.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <base/command_line.h>
-#include <base/files/file_path.h>
-#include <base/logging.h>
-#include <base/time/time.h>
-#include <brillo/flag_helper.h>
-#include <brillo/syslog_logging.h>
-
-#include "constants.h"
-#include "uploader/metricsd_service_runner.h"
-#include "uploader/upload_service.h"
-
-int main(int argc, char** argv) {
-  DEFINE_bool(foreground, false, "Don't daemonize");
-
-  // Upload the metrics once and exit. (used for testing)
-  DEFINE_bool(uploader_test, false, "run the uploader once and exit");
-
-  // Upload Service flags.
-  DEFINE_int32(upload_interval_secs, 1800,
-               "Interval at which metricsd uploads the metrics.");
-  DEFINE_int32(disk_persistence_interval_secs, 300,
-               "Interval at which metricsd saves the aggregated metrics to "
-               "disk to avoid losing them if metricsd stops in between "
-               "two uploads.");
-  DEFINE_string(server, metrics::kMetricsServer,
-                "Server to upload the metrics to.");
-  DEFINE_string(private_directory, metrics::kMetricsdDirectory,
-                "Path to the private directory used by metricsd "
-                "(testing only)");
-  DEFINE_string(shared_directory, metrics::kSharedMetricsDirectory,
-                "Path to the shared metrics directory, used by "
-                "metrics_collector, metricsd and all metrics clients "
-                "(testing only)");
-
-  DEFINE_bool(logtostderr, false, "Log to standard error");
-  DEFINE_bool(logtosyslog, false, "Log to syslog");
-
-  brillo::FlagHelper::Init(argc, argv, "Brillo metrics daemon.");
-
-  int logging_location =
-      (FLAGS_foreground ? brillo::kLogToStderr : brillo::kLogToSyslog);
-  if (FLAGS_logtosyslog)
-    logging_location = brillo::kLogToSyslog;
-
-  if (FLAGS_logtostderr)
-    logging_location = brillo::kLogToStderr;
-
-  // Also log to stderr when not running as daemon.
-  brillo::InitLog(logging_location | brillo::kLogHeader);
-
-  if (FLAGS_logtostderr && FLAGS_logtosyslog) {
-    LOG(ERROR) << "only one of --logtosyslog and --logtostderr can be set";
-    return 1;
-  }
-
-  if (!FLAGS_foreground && daemon(0, 0) != 0) {
-    return errno;
-  }
-
-  UploadService upload_service(
-      FLAGS_server, base::TimeDelta::FromSeconds(FLAGS_upload_interval_secs),
-      base::TimeDelta::FromSeconds(FLAGS_disk_persistence_interval_secs),
-      base::FilePath(FLAGS_private_directory),
-      base::FilePath(FLAGS_shared_directory));
-
-  return upload_service.Run();
-}
diff --git a/metricsd/persistent_integer.cc b/metricsd/persistent_integer.cc
deleted file mode 100644
index 7fe355e..0000000
--- a/metricsd/persistent_integer.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "persistent_integer.h"
-
-#include <fcntl.h>
-
-#include <base/logging.h>
-#include <base/posix/eintr_wrapper.h>
-
-#include "constants.h"
-
-namespace chromeos_metrics {
-
-PersistentInteger::PersistentInteger(const std::string& name,
-                                     const base::FilePath& directory)
-    : value_(0),
-      version_(kVersion),
-      name_(name),
-      backing_file_path_(directory.Append(name_)),
-      synced_(false) {}
-
-PersistentInteger::~PersistentInteger() {}
-
-void PersistentInteger::Set(int64_t value) {
-  value_ = value;
-  Write();
-}
-
-int64_t PersistentInteger::Get() {
-  // If not synced, then read.  If the read fails, it's a good idea to write.
-  if (!synced_ && !Read())
-    Write();
-  return value_;
-}
-
-int64_t PersistentInteger::GetAndClear() {
-  int64_t v = Get();
-  Set(0);
-  return v;
-}
-
-void PersistentInteger::Add(int64_t x) {
-  Set(Get() + x);
-}
-
-void PersistentInteger::Write() {
-  int fd = HANDLE_EINTR(open(backing_file_path_.value().c_str(),
-                             O_WRONLY | O_CREAT | O_TRUNC,
-                             S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH));
-  PCHECK(fd >= 0) << "cannot open " << backing_file_path_.value()
-                  << " for writing";
-  PCHECK((HANDLE_EINTR(write(fd, &version_, sizeof(version_))) ==
-          sizeof(version_)) &&
-         (HANDLE_EINTR(write(fd, &value_, sizeof(value_))) ==
-          sizeof(value_)))
-      << "cannot write to " << backing_file_path_.value();
-  close(fd);
-  synced_ = true;
-}
-
-bool PersistentInteger::Read() {
-  int fd = HANDLE_EINTR(open(backing_file_path_.value().c_str(), O_RDONLY));
-  if (fd < 0) {
-    PLOG(WARNING) << "cannot open " << backing_file_path_.value()
-                  << " for reading";
-    return false;
-  }
-  int32_t version;
-  int64_t value;
-  bool read_succeeded = false;
-  if (HANDLE_EINTR(read(fd, &version, sizeof(version))) == sizeof(version) &&
-      version == version_ &&
-      HANDLE_EINTR(read(fd, &value, sizeof(value))) == sizeof(value)) {
-    value_ = value;
-    read_succeeded = true;
-    synced_ = true;
-  }
-  close(fd);
-  return read_succeeded;
-}
-
-}  // namespace chromeos_metrics
diff --git a/metricsd/persistent_integer.h b/metricsd/persistent_integer.h
deleted file mode 100644
index 96d9fc0..0000000
--- a/metricsd/persistent_integer.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICS_PERSISTENT_INTEGER_H_
-#define METRICS_PERSISTENT_INTEGER_H_
-
-#include <stdint.h>
-
-#include <string>
-
-#include <base/files/file_path.h>
-
-namespace chromeos_metrics {
-
-// PersistentIntegers is a named 64-bit integer value backed by a file.
-// The in-memory value acts as a write-through cache of the file value.
-// If the backing file doesn't exist or has bad content, the value is 0.
-
-class PersistentInteger {
- public:
-  PersistentInteger(const std::string& name, const base::FilePath& directory);
-
-  // Virtual only because of mock.
-  virtual ~PersistentInteger();
-
-  // Sets the value.  This writes through to the backing file.
-  void Set(int64_t v);
-
-  // Gets the value.  May sync from backing file first.
-  int64_t Get();
-
-  // Returns the name of the object.
-  std::string Name() { return name_; }
-
-  // Convenience function for Get() followed by Set(0).
-  int64_t GetAndClear();
-
-  // Convenience function for v = Get, Set(v + x).
-  // Virtual only because of mock.
-  virtual void Add(int64_t x);
-
- private:
-  static const int kVersion = 1001;
-
-  // Writes |value_| to the backing file, creating it if necessary.
-  void Write();
-
-  // Reads the value from the backing file, stores it in |value_|, and returns
-  // true if the backing file is valid.  Returns false otherwise, and creates
-  // a valid backing file as a side effect.
-  bool Read();
-
-  int64_t value_;
-  int32_t version_;
-  std::string name_;
-  base::FilePath backing_file_path_;
-  bool synced_;
-};
-
-}  // namespace chromeos_metrics
-
-#endif  // METRICS_PERSISTENT_INTEGER_H_
diff --git a/metricsd/persistent_integer_mock.h b/metricsd/persistent_integer_mock.h
deleted file mode 100644
index 0be54d4..0000000
--- a/metricsd/persistent_integer_mock.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICS_PERSISTENT_INTEGER_MOCK_H_
-#define METRICS_PERSISTENT_INTEGER_MOCK_H_
-
-#include <string>
-
-#include <gmock/gmock.h>
-
-#include "persistent_integer.h"
-
-namespace chromeos_metrics {
-
-class PersistentIntegerMock : public PersistentInteger {
- public:
-  explicit PersistentIntegerMock(const std::string& name,
-                                 const base::FilePath& directory)
-      : PersistentInteger(name, directory) {}
-  MOCK_METHOD1(Add, void(int64_t count));
-};
-
-}  // namespace chromeos_metrics
-
-#endif  // METRICS_PERSISTENT_INTEGER_MOCK_H_
diff --git a/metricsd/persistent_integer_test.cc b/metricsd/persistent_integer_test.cc
deleted file mode 100644
index bf76261..0000000
--- a/metricsd/persistent_integer_test.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <memory>
-
-#include <base/compiler_specific.h>
-#include <base/files/file_enumerator.h>
-#include <base/files/file_util.h>
-#include <base/files/scoped_temp_dir.h>
-#include <gtest/gtest.h>
-
-#include "persistent_integer.h"
-
-const char kBackingFileName[] = "1.pibakf";
-
-using chromeos_metrics::PersistentInteger;
-
-class PersistentIntegerTest : public testing::Test {
-  void SetUp() override {
-    // Set testing mode.
-    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-  }
-
- protected:
-  base::ScopedTempDir temp_dir_;
-};
-
-TEST_F(PersistentIntegerTest, BasicChecks) {
-  std::unique_ptr<PersistentInteger> pi(
-      new PersistentInteger(kBackingFileName, temp_dir_.path()));
-
-  // Test initialization.
-  EXPECT_EQ(0, pi->Get());
-  EXPECT_EQ(kBackingFileName, pi->Name());  // boring
-
-  // Test set and add.
-  pi->Set(2);
-  pi->Add(3);
-  EXPECT_EQ(5, pi->Get());
-
-  // Test persistence.
-  pi.reset(new PersistentInteger(kBackingFileName, temp_dir_.path()));
-  EXPECT_EQ(5, pi->Get());
-
-  // Test GetAndClear.
-  EXPECT_EQ(5, pi->GetAndClear());
-  EXPECT_EQ(pi->Get(), 0);
-
-  // Another persistence test.
-  pi.reset(new PersistentInteger(kBackingFileName, temp_dir_.path()));
-  EXPECT_EQ(0, pi->Get());
-}
diff --git a/metricsd/timer.cc b/metricsd/timer.cc
deleted file mode 100644
index 06fc336..0000000
--- a/metricsd/timer.cc
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "metrics/timer.h"
-
-#include <string>
-
-#include "metrics/metrics_library.h"
-
-namespace chromeos_metrics {
-
-base::TimeTicks ClockWrapper::GetCurrentTime() const {
-  return base::TimeTicks::Now();
-}
-
-Timer::Timer()
-    : timer_state_(kTimerStopped),
-      clock_wrapper_(new ClockWrapper()) {}
-
-bool Timer::Start() {
-  elapsed_time_ = base::TimeDelta();  // Sets elapsed_time_ to zero.
-  start_time_ = clock_wrapper_->GetCurrentTime();
-  timer_state_ = kTimerRunning;
-  return true;
-}
-
-bool Timer::Stop() {
-  if (timer_state_ == kTimerStopped)
-    return false;
-  if (timer_state_ == kTimerRunning)
-    elapsed_time_ += clock_wrapper_->GetCurrentTime() - start_time_;
-  timer_state_ = kTimerStopped;
-  return true;
-}
-
-bool Timer::Pause() {
-  switch (timer_state_) {
-    case kTimerStopped:
-      if (!Start())
-        return false;
-      timer_state_ = kTimerPaused;
-      return true;
-    case kTimerRunning:
-      timer_state_ = kTimerPaused;
-      elapsed_time_ += clock_wrapper_->GetCurrentTime() - start_time_;
-      return true;
-    default:
-      return false;
-  }
-}
-
-bool Timer::Resume() {
-  switch (timer_state_) {
-    case kTimerStopped:
-      return Start();
-    case kTimerPaused:
-      start_time_ = clock_wrapper_->GetCurrentTime();
-      timer_state_ = kTimerRunning;
-      return true;
-    default:
-      return false;
-  }
-}
-
-bool Timer::Reset() {
-  elapsed_time_ = base::TimeDelta();  // Sets elapsed_time_ to zero.
-  timer_state_ = kTimerStopped;
-  return true;
-}
-
-bool Timer::HasStarted() const {
-  return timer_state_ != kTimerStopped;
-}
-
-bool Timer::GetElapsedTime(base::TimeDelta* elapsed_time) const {
-  if (start_time_.is_null() || !elapsed_time)
-    return false;
-  *elapsed_time = elapsed_time_;
-  if (timer_state_ == kTimerRunning) {
-    *elapsed_time += clock_wrapper_->GetCurrentTime() - start_time_;
-  }
-  return true;
-}
-
-// static
-MetricsLibraryInterface* TimerReporter::metrics_lib_ = nullptr;
-
-TimerReporter::TimerReporter(const std::string& histogram_name, int min,
-                             int max, int num_buckets)
-    : histogram_name_(histogram_name),
-      min_(min),
-      max_(max),
-      num_buckets_(num_buckets) {}
-
-bool TimerReporter::ReportMilliseconds() const {
-  base::TimeDelta elapsed_time;
-  if (!metrics_lib_ || !GetElapsedTime(&elapsed_time)) return false;
-  return metrics_lib_->SendToUMA(histogram_name_,
-                                 elapsed_time.InMilliseconds(),
-                                 min_,
-                                 max_,
-                                 num_buckets_);
-}
-
-}  // namespace chromeos_metrics
diff --git a/metricsd/timer_test.cc b/metricsd/timer_test.cc
deleted file mode 100644
index 7a67e11..0000000
--- a/metricsd/timer_test.cc
+++ /dev/null
@@ -1,464 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <memory>
-
-#include "metrics/metrics_library_mock.h"
-#include "metrics/timer.h"
-#include "metrics/timer_mock.h"
-
-using ::testing::_;
-using ::testing::Return;
-
-namespace chromeos_metrics {
-
-namespace {
-const int64_t kStime1MSec = 1400;
-const int64_t kEtime1MSec = 3000;
-const int64_t kDelta1MSec = 1600;
-
-const int64_t kStime2MSec = 4200;
-const int64_t kEtime2MSec = 5000;
-const int64_t kDelta2MSec = 800;
-
-const int64_t kStime3MSec = 6600;
-const int64_t kEtime3MSec = 6800;
-const int64_t kDelta3MSec = 200;
-}  // namespace
-
-class TimerTest : public testing::Test {
- public:
-  TimerTest() : clock_wrapper_mock_(new ClockWrapperMock()) {}
-
- protected:
-  virtual void SetUp() {
-    EXPECT_EQ(Timer::kTimerStopped, timer_.timer_state_);
-    stime += base::TimeDelta::FromMilliseconds(kStime1MSec);
-    etime += base::TimeDelta::FromMilliseconds(kEtime1MSec);
-    stime2 += base::TimeDelta::FromMilliseconds(kStime2MSec);
-    etime2 += base::TimeDelta::FromMilliseconds(kEtime2MSec);
-    stime3 += base::TimeDelta::FromMilliseconds(kStime3MSec);
-    etime3 += base::TimeDelta::FromMilliseconds(kEtime3MSec);
-  }
-
-  virtual void TearDown() {}
-
-  Timer timer_;
-  std::unique_ptr<ClockWrapperMock> clock_wrapper_mock_;
-  base::TimeTicks stime, etime, stime2, etime2, stime3, etime3;
-};
-
-TEST_F(TimerTest, StartStop) {
-  EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
-      .WillOnce(Return(stime))
-      .WillOnce(Return(etime));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
-  ASSERT_TRUE(timer_.Start());
-  ASSERT_TRUE(timer_.start_time_ == stime);
-  ASSERT_TRUE(timer_.HasStarted());
-  ASSERT_TRUE(timer_.Stop());
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(), kDelta1MSec);
-
-  base::TimeDelta elapsed_time;
-  ASSERT_TRUE(timer_.GetElapsedTime(&elapsed_time));
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(),
-            elapsed_time.InMilliseconds());
-
-  ASSERT_FALSE(timer_.HasStarted());
-}
-
-TEST_F(TimerTest, ReStart) {
-  EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
-      .WillOnce(Return(stime))
-      .WillOnce(Return(etime));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
-  timer_.Start();
-  base::TimeTicks buffer = timer_.start_time_;
-  timer_.Start();
-  ASSERT_FALSE(timer_.start_time_ == buffer);
-}
-
-TEST_F(TimerTest, Reset) {
-  EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
-      .WillOnce(Return(stime));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
-  timer_.Start();
-  ASSERT_TRUE(timer_.Reset());
-  ASSERT_FALSE(timer_.HasStarted());
-}
-
-TEST_F(TimerTest, SeparatedTimers) {
-  EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
-      .WillOnce(Return(stime))
-      .WillOnce(Return(etime))
-      .WillOnce(Return(stime2))
-      .WillOnce(Return(etime2));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
-  ASSERT_TRUE(timer_.Start());
-  ASSERT_TRUE(timer_.Stop());
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(), kDelta1MSec);
-  ASSERT_TRUE(timer_.Start());
-  ASSERT_TRUE(timer_.start_time_ == stime2);
-  ASSERT_TRUE(timer_.Stop());
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(), kDelta2MSec);
-  ASSERT_FALSE(timer_.HasStarted());
-
-  base::TimeDelta elapsed_time;
-  ASSERT_TRUE(timer_.GetElapsedTime(&elapsed_time));
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(),
-            elapsed_time.InMilliseconds());
-}
-
-TEST_F(TimerTest, InvalidStop) {
-  EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
-      .WillOnce(Return(stime))
-      .WillOnce(Return(etime));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
-  ASSERT_FALSE(timer_.Stop());
-  // Now we try it again, but after a valid start/stop.
-  timer_.Start();
-  timer_.Stop();
-  base::TimeDelta elapsed_time = timer_.elapsed_time_;
-  ASSERT_FALSE(timer_.Stop());
-  ASSERT_TRUE(elapsed_time == timer_.elapsed_time_);
-}
-
-TEST_F(TimerTest, InvalidElapsedTime) {
-  base::TimeDelta elapsed_time;
-  ASSERT_FALSE(timer_.GetElapsedTime(&elapsed_time));
-}
-
-TEST_F(TimerTest, PauseStartStopResume) {
-  EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
-      .WillOnce(Return(stime))
-      .WillOnce(Return(stime2))
-      .WillOnce(Return(etime2))
-      .WillOnce(Return(stime3))
-      .WillOnce(Return(etime3));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
-  ASSERT_TRUE(timer_.Pause());  // Starts timer paused.
-  ASSERT_TRUE(timer_.start_time_ == stime);
-  ASSERT_TRUE(timer_.HasStarted());
-
-  ASSERT_TRUE(timer_.Start());  // Restarts timer.
-  ASSERT_TRUE(timer_.start_time_ == stime2);
-  ASSERT_TRUE(timer_.HasStarted());
-
-  ASSERT_TRUE(timer_.Stop());
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(), kDelta2MSec);
-  ASSERT_FALSE(timer_.HasStarted());
-  base::TimeDelta elapsed_time;
-  ASSERT_TRUE(timer_.GetElapsedTime(&elapsed_time));
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(),
-            elapsed_time.InMilliseconds());
-
-  ASSERT_TRUE(timer_.Resume());
-  ASSERT_TRUE(timer_.HasStarted());
-  ASSERT_TRUE(timer_.GetElapsedTime(&elapsed_time));
-  ASSERT_EQ(kDelta3MSec, elapsed_time.InMilliseconds());
-}
-
-TEST_F(TimerTest, ResumeStartStopPause) {
-  EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
-      .WillOnce(Return(stime))
-      .WillOnce(Return(stime2))
-      .WillOnce(Return(etime2))
-      .WillOnce(Return(stime3));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
-  ASSERT_TRUE(timer_.Resume());
-  ASSERT_TRUE(timer_.start_time_ == stime);
-  ASSERT_TRUE(timer_.HasStarted());
-
-  ASSERT_TRUE(timer_.Start());
-  ASSERT_TRUE(timer_.start_time_ == stime2);
-  ASSERT_TRUE(timer_.HasStarted());
-
-  ASSERT_TRUE(timer_.Stop());
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(), kDelta2MSec);
-  ASSERT_FALSE(timer_.HasStarted());
-  base::TimeDelta elapsed_time;
-  ASSERT_TRUE(timer_.GetElapsedTime(&elapsed_time));
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(),
-            elapsed_time.InMilliseconds());
-
-  ASSERT_TRUE(timer_.Pause());
-  ASSERT_TRUE(timer_.HasStarted());
-  ASSERT_TRUE(timer_.GetElapsedTime(&elapsed_time));
-  ASSERT_EQ(0, elapsed_time.InMilliseconds());
-}
-
-TEST_F(TimerTest, StartResumeStop) {
-  EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
-      .WillOnce(Return(stime))
-      .WillOnce(Return(etime));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
-  ASSERT_TRUE(timer_.Start());
-  ASSERT_TRUE(timer_.start_time_ == stime);
-  ASSERT_TRUE(timer_.HasStarted());
-
-  ASSERT_FALSE(timer_.Resume());
-  ASSERT_TRUE(timer_.start_time_ == stime);
-  ASSERT_TRUE(timer_.HasStarted());
-
-  ASSERT_TRUE(timer_.Stop());
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(), kDelta1MSec);
-  ASSERT_FALSE(timer_.HasStarted());
-  base::TimeDelta elapsed_time;
-  ASSERT_TRUE(timer_.GetElapsedTime(&elapsed_time));
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(),
-            elapsed_time.InMilliseconds());
-}
-
-TEST_F(TimerTest, StartPauseStop) {
-  EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
-      .WillOnce(Return(stime))
-      .WillOnce(Return(etime));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
-  ASSERT_TRUE(timer_.Start());
-  ASSERT_TRUE(timer_.start_time_ == stime);
-  ASSERT_TRUE(timer_.HasStarted());
-
-  ASSERT_TRUE(timer_.Pause());
-  ASSERT_TRUE(timer_.HasStarted());
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(), kDelta1MSec);
-  base::TimeDelta elapsed_time;
-  ASSERT_TRUE(timer_.GetElapsedTime(&elapsed_time));
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(),
-            elapsed_time.InMilliseconds());
-
-  ASSERT_TRUE(timer_.Stop());
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(), kDelta1MSec);
-  ASSERT_FALSE(timer_.HasStarted());
-  ASSERT_TRUE(timer_.GetElapsedTime(&elapsed_time));
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(),
-            elapsed_time.InMilliseconds());
-}
-
-TEST_F(TimerTest, StartPauseResumeStop) {
-  EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
-      .WillOnce(Return(stime))
-      .WillOnce(Return(etime))
-      .WillOnce(Return(stime2))
-      .WillOnce(Return(etime2));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
-  ASSERT_TRUE(timer_.Start());
-  ASSERT_TRUE(timer_.start_time_ == stime);
-  ASSERT_TRUE(timer_.HasStarted());
-
-  ASSERT_TRUE(timer_.Pause());
-  ASSERT_TRUE(timer_.HasStarted());
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(), kDelta1MSec);
-  base::TimeDelta elapsed_time;
-  ASSERT_TRUE(timer_.GetElapsedTime(&elapsed_time));
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(),
-            elapsed_time.InMilliseconds());
-
-  ASSERT_TRUE(timer_.Resume());
-  ASSERT_TRUE(timer_.HasStarted());
-
-  ASSERT_TRUE(timer_.Stop());
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(), kDelta1MSec + kDelta2MSec);
-  ASSERT_FALSE(timer_.HasStarted());
-  ASSERT_TRUE(timer_.GetElapsedTime(&elapsed_time));
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(),
-            elapsed_time.InMilliseconds());
-}
-
-TEST_F(TimerTest, PauseStop) {
-  EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
-      .WillOnce(Return(stime));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
-  ASSERT_TRUE(timer_.Pause());
-  ASSERT_TRUE(timer_.start_time_ == stime);
-  ASSERT_TRUE(timer_.HasStarted());
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(), 0);
-
-  ASSERT_TRUE(timer_.Stop());
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(), 0);
-  ASSERT_FALSE(timer_.HasStarted());
-  base::TimeDelta elapsed_time;
-  ASSERT_TRUE(timer_.GetElapsedTime(&elapsed_time));
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(),
-            elapsed_time.InMilliseconds());
-}
-
-TEST_F(TimerTest, PauseResumeStop) {
-  EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
-      .WillOnce(Return(stime))
-      .WillOnce(Return(stime2))
-      .WillOnce(Return(etime2));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
-  ASSERT_TRUE(timer_.Pause());
-  ASSERT_TRUE(timer_.start_time_ == stime);
-  ASSERT_TRUE(timer_.HasStarted());
-
-  ASSERT_TRUE(timer_.Resume());
-  ASSERT_TRUE(timer_.HasStarted());
-
-  ASSERT_TRUE(timer_.Stop());
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(), kDelta2MSec);
-  ASSERT_FALSE(timer_.HasStarted());
-  base::TimeDelta elapsed_time;
-  ASSERT_TRUE(timer_.GetElapsedTime(&elapsed_time));
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(),
-            elapsed_time.InMilliseconds());
-}
-
-TEST_F(TimerTest, StartPauseResumePauseStop) {
-  EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
-      .WillOnce(Return(stime))
-      .WillOnce(Return(etime))
-      .WillOnce(Return(stime2))
-      .WillOnce(Return(stime3))
-      .WillOnce(Return(etime3));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
-  ASSERT_TRUE(timer_.Start());
-  ASSERT_TRUE(timer_.start_time_ == stime);
-  ASSERT_TRUE(timer_.HasStarted());
-
-  ASSERT_TRUE(timer_.Pause());
-  ASSERT_TRUE(timer_.HasStarted());
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(), kDelta1MSec);
-  base::TimeDelta elapsed_time;
-  ASSERT_TRUE(timer_.GetElapsedTime(&elapsed_time));
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(),
-            elapsed_time.InMilliseconds());
-
-  ASSERT_TRUE(timer_.Resume());
-  ASSERT_TRUE(timer_.HasStarted());
-  // Make sure GetElapsedTime works while we're running.
-  ASSERT_TRUE(timer_.GetElapsedTime(&elapsed_time));
-  ASSERT_EQ(kDelta1MSec + kStime3MSec - kStime2MSec,
-            elapsed_time.InMilliseconds());
-
-  ASSERT_TRUE(timer_.Pause());
-  ASSERT_TRUE(timer_.HasStarted());
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(),
-            kDelta1MSec + kEtime3MSec - kStime2MSec);
-  ASSERT_TRUE(timer_.GetElapsedTime(&elapsed_time));
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(),
-            elapsed_time.InMilliseconds());
-
-  ASSERT_TRUE(timer_.Stop());
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(),
-            kDelta1MSec + kEtime3MSec - kStime2MSec);
-  ASSERT_FALSE(timer_.HasStarted());
-  ASSERT_TRUE(timer_.GetElapsedTime(&elapsed_time));
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(),
-            elapsed_time.InMilliseconds());
-}
-
-TEST_F(TimerTest, StartPauseResumePauseResumeStop) {
-  EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
-      .WillOnce(Return(stime))
-      .WillOnce(Return(etime))
-      .WillOnce(Return(stime2))
-      .WillOnce(Return(etime2))
-      .WillOnce(Return(stime3))
-      .WillOnce(Return(etime3));
-  timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
-  ASSERT_TRUE(timer_.Start());
-  ASSERT_TRUE(timer_.start_time_ == stime);
-  ASSERT_TRUE(timer_.HasStarted());
-
-  ASSERT_TRUE(timer_.Pause());
-  ASSERT_TRUE(timer_.HasStarted());
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(), kDelta1MSec);
-  base::TimeDelta elapsed_time;
-  ASSERT_TRUE(timer_.GetElapsedTime(&elapsed_time));
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(),
-            elapsed_time.InMilliseconds());
-
-  ASSERT_TRUE(timer_.Resume());
-  ASSERT_TRUE(timer_.HasStarted());
-
-  ASSERT_TRUE(timer_.Pause());
-  ASSERT_TRUE(timer_.HasStarted());
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(), kDelta1MSec + kDelta2MSec);
-  ASSERT_TRUE(timer_.GetElapsedTime(&elapsed_time));
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(),
-            elapsed_time.InMilliseconds());
-
-  ASSERT_TRUE(timer_.Resume());
-  ASSERT_TRUE(timer_.HasStarted());
-
-  ASSERT_TRUE(timer_.Stop());
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(),
-            kDelta1MSec + kDelta2MSec + kDelta3MSec);
-  ASSERT_FALSE(timer_.HasStarted());
-  ASSERT_TRUE(timer_.GetElapsedTime(&elapsed_time));
-  ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(),
-            elapsed_time.InMilliseconds());
-}
-
-static const char kMetricName[] = "test-timer";
-static const int kMinSample = 0;
-static const int kMaxSample = 120 * 1E6;
-static const int kNumBuckets = 50;
-
-class TimerReporterTest : public testing::Test {
- public:
-  TimerReporterTest() : timer_reporter_(kMetricName, kMinSample, kMaxSample,
-                                        kNumBuckets),
-                        clock_wrapper_mock_(new ClockWrapperMock()) {}
-
- protected:
-  virtual void SetUp() {
-    timer_reporter_.set_metrics_lib(&lib_);
-    EXPECT_EQ(timer_reporter_.histogram_name_, kMetricName);
-    EXPECT_EQ(timer_reporter_.min_, kMinSample);
-    EXPECT_EQ(timer_reporter_.max_, kMaxSample);
-    EXPECT_EQ(timer_reporter_.num_buckets_, kNumBuckets);
-    stime += base::TimeDelta::FromMilliseconds(kStime1MSec);
-    etime += base::TimeDelta::FromMilliseconds(kEtime1MSec);
-  }
-
-  virtual void TearDown() {
-    timer_reporter_.set_metrics_lib(nullptr);
-  }
-
-  TimerReporter timer_reporter_;
-  MetricsLibraryMock lib_;
-  std::unique_ptr<ClockWrapperMock> clock_wrapper_mock_;
-  base::TimeTicks stime, etime;
-};
-
-TEST_F(TimerReporterTest, StartStopReport) {
-  EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
-      .WillOnce(Return(stime))
-      .WillOnce(Return(etime));
-  timer_reporter_.clock_wrapper_.reset(clock_wrapper_mock_.release());
-  EXPECT_CALL(lib_, SendToUMA(kMetricName, kDelta1MSec, kMinSample, kMaxSample,
-                              kNumBuckets)).WillOnce(Return(true));
-  ASSERT_TRUE(timer_reporter_.Start());
-  ASSERT_TRUE(timer_reporter_.Stop());
-  ASSERT_TRUE(timer_reporter_.ReportMilliseconds());
-}
-
-TEST_F(TimerReporterTest, InvalidReport) {
-  ASSERT_FALSE(timer_reporter_.ReportMilliseconds());
-}
-
-}  // namespace chromeos_metrics
-
-int main(int argc, char **argv) {
-  testing::InitGoogleTest(&argc, argv);
-  return RUN_ALL_TESTS();
-}
diff --git a/metricsd/uploader/bn_metricsd_impl.cc b/metricsd/uploader/bn_metricsd_impl.cc
deleted file mode 100644
index 219ed60..0000000
--- a/metricsd/uploader/bn_metricsd_impl.cc
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "uploader/bn_metricsd_impl.h"
-
-#include <base/metrics/histogram.h>
-#include <base/metrics/sparse_histogram.h>
-#include <base/metrics/statistics_recorder.h>
-#include <utils/Errors.h>
-#include <utils/String16.h>
-#include <utils/String8.h>
-
-using android::binder::Status;
-using android::String16;
-
-static const char16_t kCrashTypeKernel[] = u"kernel";
-static const char16_t kCrashTypeUncleanShutdown[] = u"uncleanshutdown";
-static const char16_t kCrashTypeUser[] = u"user";
-
-BnMetricsdImpl::BnMetricsdImpl(const std::shared_ptr<CrashCounters>& counters)
-    : counters_(counters) {
-  CHECK(counters_) << "Invalid counters argument to constructor";
-}
-
-Status BnMetricsdImpl::recordHistogram(
-    const String16& name, int sample, int min, int max, int nbuckets) {
-  base::HistogramBase* histogram = base::Histogram::FactoryGet(
-      android::String8(name).string(), min, max, nbuckets,
-      base::Histogram::kUmaTargetedHistogramFlag);
-  // |histogram| may be null if a client reports two contradicting histograms
-  // with the same name but different limits.
-  // FactoryGet will print a useful message if that is the case.
-  if (histogram) {
-    histogram->Add(sample);
-  }
-  return Status::ok();
-}
-
-Status BnMetricsdImpl::recordLinearHistogram(const String16& name,
-                                             int sample,
-                                             int max) {
-  base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
-      android::String8(name).string(), 1, max, max + 1,
-      base::Histogram::kUmaTargetedHistogramFlag);
-  // |histogram| may be null if a client reports two contradicting histograms
-  // with the same name but different limits.
-  // FactoryGet will print a useful message if that is the case.
-  if (histogram) {
-    histogram->Add(sample);
-  }
-  return Status::ok();
-}
-
-Status BnMetricsdImpl::recordSparseHistogram(const String16& name, int sample) {
-  base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
-      android::String8(name).string(),
-      base::Histogram::kUmaTargetedHistogramFlag);
-  // |histogram| may be null if a client reports two contradicting histograms
-  // with the same name but different limits.
-  // FactoryGet will print a useful message if that is the case.
-  if (histogram) {
-    histogram->Add(sample);
-  }
-  return Status::ok();
-}
-
-Status BnMetricsdImpl::recordCrash(const String16& type) {
-  if (type == kCrashTypeUser) {
-    counters_->IncrementUserCrashCount();
-  } else if (type == kCrashTypeKernel) {
-    counters_->IncrementKernelCrashCount();
-  } else if (type == kCrashTypeUncleanShutdown) {
-    counters_->IncrementUncleanShutdownCount();
-  } else {
-    LOG(ERROR) << "Unknown crash type received: " << type;
-  }
-  return Status::ok();
-}
-
-Status BnMetricsdImpl::getHistogramsDump(String16* dump) {
-  std::string str_dump;
-  base::StatisticsRecorder::WriteGraph(std::string(), &str_dump);
-  *dump = String16(str_dump.c_str());
-  return Status::ok();
-}
diff --git a/metricsd/uploader/bn_metricsd_impl.h b/metricsd/uploader/bn_metricsd_impl.h
deleted file mode 100644
index bf47e80..0000000
--- a/metricsd/uploader/bn_metricsd_impl.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICSD_UPLOADER_BN_METRICSD_IMPL_H_
-#define METRICSD_UPLOADER_BN_METRICSD_IMPL_H_
-
-#include "android/brillo/metrics/BnMetricsd.h"
-#include "uploader/crash_counters.h"
-
-class BnMetricsdImpl : public android::brillo::metrics::BnMetricsd {
- public:
-  explicit BnMetricsdImpl(const std::shared_ptr<CrashCounters>& counters);
-  virtual ~BnMetricsdImpl() = default;
-
-  // Records a histogram.
-  android::binder::Status recordHistogram(const android::String16& name,
-                                          int sample,
-                                          int min,
-                                          int max,
-                                          int nbuckets) override;
-
-  // Records a linear histogram.
-  android::binder::Status recordLinearHistogram(const android::String16& name,
-                                                int sample,
-                                                int max) override;
-
-  // Records a sparse histogram.
-  android::binder::Status recordSparseHistogram(const android::String16& name,
-                                                int sample) override;
-
-  // Records a crash.
-  android::binder::Status recordCrash(const android::String16& type) override;
-
-  // Returns a dump of the histograms aggregated in memory.
-  android::binder::Status getHistogramsDump(android::String16* dump) override;
-
- private:
-  std::shared_ptr<CrashCounters> counters_;
-};
-
-#endif  // METRICSD_UPLOADER_BN_METRICSD_IMPL_H_
diff --git a/metricsd/uploader/crash_counters.cc b/metricsd/uploader/crash_counters.cc
deleted file mode 100644
index 1478b9a..0000000
--- a/metricsd/uploader/crash_counters.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "uploader/crash_counters.h"
-
-CrashCounters::CrashCounters()
-    : kernel_crashes_(0), unclean_shutdowns_(0), user_crashes_(0) {}
-
-void CrashCounters::IncrementKernelCrashCount() {
-  kernel_crashes_++;
-}
-
-unsigned int CrashCounters::GetAndResetKernelCrashCount() {
-  return kernel_crashes_.exchange(0);
-}
-
-void CrashCounters::IncrementUncleanShutdownCount() {
-  unclean_shutdowns_++;
-}
-
-unsigned int CrashCounters::GetAndResetUncleanShutdownCount() {
-  return unclean_shutdowns_.exchange(0);
-}
-
-void CrashCounters::IncrementUserCrashCount() {
-  user_crashes_++;
-}
-
-unsigned int CrashCounters::GetAndResetUserCrashCount() {
-  return user_crashes_.exchange(0);
-}
diff --git a/metricsd/uploader/crash_counters.h b/metricsd/uploader/crash_counters.h
deleted file mode 100644
index 3fdbf3f..0000000
--- a/metricsd/uploader/crash_counters.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICSD_UPLOADER_CRASH_COUNTERS_H_
-#define METRICSD_UPLOADER_CRASH_COUNTERS_H_
-
-#include <atomic>
-
-// This class is used to keep track of the crash counters.
-// An instance of it will be used by both the binder thread (to increment the
-// counters) and the uploader thread (to gather and reset the counters).
-// As such, the internal counters are atomic uints to allow concurrent access.
-class CrashCounters {
- public:
-  CrashCounters();
-
-  void IncrementKernelCrashCount();
-  unsigned int GetAndResetKernelCrashCount();
-
-  void IncrementUserCrashCount();
-  unsigned int GetAndResetUserCrashCount();
-
-  void IncrementUncleanShutdownCount();
-  unsigned int GetAndResetUncleanShutdownCount();
-
- private:
-  std::atomic_uint kernel_crashes_;
-  std::atomic_uint unclean_shutdowns_;
-  std::atomic_uint user_crashes_;
-};
-
-#endif  // METRICSD_UPLOADER_CRASH_COUNTERS_H_
diff --git a/metricsd/uploader/metrics_hashes.cc b/metricsd/uploader/metrics_hashes.cc
deleted file mode 100644
index 208c560..0000000
--- a/metricsd/uploader/metrics_hashes.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "uploader/metrics_hashes.h"
-
-#include "base/logging.h"
-#include "base/md5.h"
-#include "base/sys_byteorder.h"
-
-namespace metrics {
-
-namespace {
-
-// Converts the 8-byte prefix of an MD5 hash into a uint64 value.
-inline uint64_t HashToUInt64(const std::string& hash) {
-  uint64_t value;
-  DCHECK_GE(hash.size(), sizeof(value));
-  memcpy(&value, hash.data(), sizeof(value));
-  return base::HostToNet64(value);
-}
-
-}  // namespace
-
-uint64_t HashMetricName(const std::string& name) {
-  // Create an MD5 hash of the given |name|, represented as a byte buffer
-  // encoded as an std::string.
-  base::MD5Context context;
-  base::MD5Init(&context);
-  base::MD5Update(&context, name);
-
-  base::MD5Digest digest;
-  base::MD5Final(&digest, &context);
-
-  std::string hash_str(reinterpret_cast<char*>(digest.a), arraysize(digest.a));
-  return HashToUInt64(hash_str);
-}
-
-}  // namespace metrics
diff --git a/metricsd/uploader/metrics_hashes.h b/metricsd/uploader/metrics_hashes.h
deleted file mode 100644
index 1082b42..0000000
--- a/metricsd/uploader/metrics_hashes.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICS_UPLOADER_METRICS_HASHES_H_
-#define METRICS_UPLOADER_METRICS_HASHES_H_
-
-#include <string>
-
-namespace metrics {
-
-// Computes a uint64 hash of a given string based on its MD5 hash. Suitable for
-// metric names.
-uint64_t HashMetricName(const std::string& name);
-
-}  // namespace metrics
-
-#endif  // METRICS_UPLOADER_METRICS_HASHES_H_
diff --git a/metricsd/uploader/metrics_hashes_unittest.cc b/metricsd/uploader/metrics_hashes_unittest.cc
deleted file mode 100644
index b8c2575..0000000
--- a/metricsd/uploader/metrics_hashes_unittest.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "uploader/metrics_hashes.h"
-
-#include <base/format_macros.h>
-#include <base/macros.h>
-#include <base/strings/stringprintf.h>
-#include <gtest/gtest.h>
-
-namespace metrics {
-
-// Make sure our ID hashes are the same as what we see on the server side.
-TEST(MetricsUtilTest, HashMetricName) {
-  static const struct {
-    std::string input;
-    std::string output;
-  } cases[] = {
-    {"Back", "0x0557fa923dcee4d0"},
-    {"Forward", "0x67d2f6740a8eaebf"},
-    {"NewTab", "0x290eb683f96572f1"},
-  };
-
-  for (size_t i = 0; i < arraysize(cases); ++i) {
-    uint64_t hash = HashMetricName(cases[i].input);
-    std::string hash_hex = base::StringPrintf("0x%016" PRIx64, hash);
-    EXPECT_EQ(cases[i].output, hash_hex);
-  }
-}
-
-}  // namespace metrics
diff --git a/metricsd/uploader/metrics_log.cc b/metricsd/uploader/metrics_log.cc
deleted file mode 100644
index fcaa8c1..0000000
--- a/metricsd/uploader/metrics_log.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "uploader/metrics_log.h"
-
-#include <string>
-
-#include <base/files/file_util.h>
-
-#include "uploader/proto/system_profile.pb.h"
-#include "uploader/system_profile_setter.h"
-
-// We use default values for the MetricsLogBase constructor as the setter will
-// override them.
-MetricsLog::MetricsLog()
-    : MetricsLogBase("", 0, metrics::MetricsLogBase::ONGOING_LOG, "") {
-}
-
-bool MetricsLog::LoadFromFile(const base::FilePath& saved_log) {
-  std::string encoded_log;
-  if (!base::ReadFileToString(saved_log, &encoded_log)) {
-    LOG(ERROR) << "Failed to read the metrics log backup from "
-               << saved_log.value();
-    return false;
-  }
-
-  if (!uma_proto()->ParseFromString(encoded_log)) {
-    LOG(ERROR) << "Failed to parse log from " << saved_log.value()
-               << ", deleting the log";
-    base::DeleteFile(saved_log, false);
-    uma_proto()->Clear();
-    return false;
-  }
-
-  VLOG(1) << uma_proto()->histogram_event_size() << " histograms loaded from "
-          << saved_log.value();
-
-  return true;
-}
-
-bool MetricsLog::SaveToFile(const base::FilePath& path) {
-  std::string encoded_log;
-  GetEncodedLog(&encoded_log);
-
-  if (static_cast<int>(encoded_log.size()) !=
-      base::WriteFile(path, encoded_log.data(), encoded_log.size())) {
-    LOG(ERROR) << "Failed to persist the current log to " << path.value();
-    return false;
-  }
-  return true;
-}
-
-void MetricsLog::IncrementUserCrashCount(unsigned int count) {
-  metrics::SystemProfileProto::Stability* stability(
-      uma_proto()->mutable_system_profile()->mutable_stability());
-  int current = stability->other_user_crash_count();
-  stability->set_other_user_crash_count(current + count);
-}
-
-void MetricsLog::IncrementKernelCrashCount(unsigned int count) {
-  metrics::SystemProfileProto::Stability* stability(
-      uma_proto()->mutable_system_profile()->mutable_stability());
-  int current = stability->kernel_crash_count();
-  stability->set_kernel_crash_count(current + count);
-}
-
-void MetricsLog::IncrementUncleanShutdownCount(unsigned int count) {
-  metrics::SystemProfileProto::Stability* stability(
-      uma_proto()->mutable_system_profile()->mutable_stability());
-  int current = stability->unclean_system_shutdown_count();
-  stability->set_unclean_system_shutdown_count(current + count);
-}
-
-bool MetricsLog::PopulateSystemProfile(SystemProfileSetter* profile_setter) {
-  CHECK(profile_setter);
-  return profile_setter->Populate(uma_proto());
-}
diff --git a/metricsd/uploader/metrics_log.h b/metricsd/uploader/metrics_log.h
deleted file mode 100644
index 9e60b97..0000000
--- a/metricsd/uploader/metrics_log.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICSD_UPLOADER_METRICS_LOG_H_
-#define METRICSD_UPLOADER_METRICS_LOG_H_
-
-#include <string>
-
-#include <base/files/file_path.h>
-#include <base/macros.h>
-
-#include "uploader/metrics_log_base.h"
-
-// This file defines a set of user experience metrics data recorded by
-// the MetricsService. This is the unit of data that is sent to the server.
-class SystemProfileSetter;
-
-// This class provides base functionality for logging metrics data.
-class MetricsLog : public metrics::MetricsLogBase {
- public:
-  // The constructor doesn't set any metadata. The metadata is only set by a
-  // SystemProfileSetter.
-  MetricsLog();
-
-  // Increment the crash counters in the protobuf.
-  // These methods don't have to be thread safe as metrics logs are only
-  // accessed by the uploader thread.
-  void IncrementUserCrashCount(unsigned int count);
-  void IncrementKernelCrashCount(unsigned int count);
-  void IncrementUncleanShutdownCount(unsigned int count);
-
-  // Populate the system profile with system information using setter.
-  bool PopulateSystemProfile(SystemProfileSetter* setter);
-
-  // Load the log from |path|.
-  bool LoadFromFile(const base::FilePath& path);
-
-  // Save this log to |path|.
-  bool SaveToFile(const base::FilePath& path);
-
- private:
-  friend class UploadServiceTest;
-  FRIEND_TEST(UploadServiceTest, CurrentLogSavedAndResumed);
-  FRIEND_TEST(UploadServiceTest, LogContainsAggregatedValues);
-  FRIEND_TEST(UploadServiceTest, LogContainsCrashCounts);
-  FRIEND_TEST(UploadServiceTest, LogKernelCrash);
-  FRIEND_TEST(UploadServiceTest, LogUncleanShutdown);
-  FRIEND_TEST(UploadServiceTest, LogUserCrash);
-  FRIEND_TEST(UploadServiceTest, UnknownCrashIgnored);
-
-  DISALLOW_COPY_AND_ASSIGN(MetricsLog);
-};
-
-#endif  // METRICSD_UPLOADER_METRICS_LOG_H_
diff --git a/metricsd/uploader/metrics_log_base.cc b/metricsd/uploader/metrics_log_base.cc
deleted file mode 100644
index 1a60b4f..0000000
--- a/metricsd/uploader/metrics_log_base.cc
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "uploader/metrics_log_base.h"
-
-#include "base/build_time.h"
-#include "base/metrics/histogram_base.h"
-#include "base/metrics/histogram_samples.h"
-#include "uploader/metrics_hashes.h"
-#include "uploader/proto/histogram_event.pb.h"
-#include "uploader/proto/system_profile.pb.h"
-#include "uploader/proto/user_action_event.pb.h"
-
-using base::Histogram;
-using base::HistogramBase;
-using base::HistogramSamples;
-using base::SampleCountIterator;
-using base::Time;
-using base::TimeDelta;
-using metrics::HistogramEventProto;
-using metrics::SystemProfileProto;
-using metrics::UserActionEventProto;
-
-namespace metrics {
-namespace {
-
-// Any id less than 16 bytes is considered to be a testing id.
-bool IsTestingID(const std::string& id) {
-  return id.size() < 16;
-}
-
-}  // namespace
-
-MetricsLogBase::MetricsLogBase(const std::string& client_id,
-                               int session_id,
-                               LogType log_type,
-                               const std::string& version_string)
-    : num_events_(0),
-      locked_(false),
-      log_type_(log_type) {
-  DCHECK_NE(NO_LOG, log_type);
-  if (IsTestingID(client_id))
-    uma_proto_.set_client_id(0);
-  else
-    uma_proto_.set_client_id(Hash(client_id));
-
-  uma_proto_.set_session_id(session_id);
-  uma_proto_.mutable_system_profile()->set_build_timestamp(GetBuildTime());
-  uma_proto_.mutable_system_profile()->set_app_version(version_string);
-}
-
-MetricsLogBase::~MetricsLogBase() {}
-
-// static
-uint64_t MetricsLogBase::Hash(const std::string& value) {
-  uint64_t hash = metrics::HashMetricName(value);
-
-  // The following log is VERY helpful when folks add some named histogram into
-  // the code, but forgot to update the descriptive list of histograms.  When
-  // that happens, all we get to see (server side) is a hash of the histogram
-  // name.  We can then use this logging to find out what histogram name was
-  // being hashed to a given MD5 value by just running the version of Chromium
-  // in question with --enable-logging.
-  VLOG(1) << "Metrics: Hash numeric [" << value << "]=[" << hash << "]";
-
-  return hash;
-}
-
-// static
-int64_t MetricsLogBase::GetBuildTime() {
-  static int64_t integral_build_time = 0;
-  if (!integral_build_time) {
-    Time time = base::GetBuildTime();
-    integral_build_time = static_cast<int64_t>(time.ToTimeT());
-  }
-  return integral_build_time;
-}
-
-// static
-int64_t MetricsLogBase::GetCurrentTime() {
-  return (base::TimeTicks::Now() - base::TimeTicks()).InSeconds();
-}
-
-void MetricsLogBase::CloseLog() {
-  DCHECK(!locked_);
-  locked_ = true;
-}
-
-void MetricsLogBase::GetEncodedLog(std::string* encoded_log) {
-  DCHECK(locked_);
-  uma_proto_.SerializeToString(encoded_log);
-}
-
-void MetricsLogBase::RecordUserAction(const std::string& key) {
-  DCHECK(!locked_);
-
-  UserActionEventProto* user_action = uma_proto_.add_user_action_event();
-  user_action->set_name_hash(Hash(key));
-  user_action->set_time(GetCurrentTime());
-
-  ++num_events_;
-}
-
-void MetricsLogBase::RecordHistogramDelta(const std::string& histogram_name,
-                                          const HistogramSamples& snapshot) {
-  DCHECK(!locked_);
-  DCHECK_NE(0, snapshot.TotalCount());
-
-  // We will ignore the MAX_INT/infinite value in the last element of range[].
-
-  HistogramEventProto* histogram_proto = uma_proto_.add_histogram_event();
-  histogram_proto->set_name_hash(Hash(histogram_name));
-  histogram_proto->set_sum(snapshot.sum());
-
-  for (scoped_ptr<SampleCountIterator> it = snapshot.Iterator(); !it->Done();
-       it->Next()) {
-    HistogramBase::Sample min;
-    HistogramBase::Sample max;
-    HistogramBase::Count count;
-    it->Get(&min, &max, &count);
-    HistogramEventProto::Bucket* bucket = histogram_proto->add_bucket();
-    bucket->set_min(min);
-    bucket->set_max(max);
-    bucket->set_count(count);
-  }
-
-  // Omit fields to save space (see rules in histogram_event.proto comments).
-  for (int i = 0; i < histogram_proto->bucket_size(); ++i) {
-    HistogramEventProto::Bucket* bucket = histogram_proto->mutable_bucket(i);
-    if (i + 1 < histogram_proto->bucket_size() &&
-        bucket->max() == histogram_proto->bucket(i + 1).min()) {
-      bucket->clear_max();
-    } else if (bucket->max() == bucket->min() + 1) {
-      bucket->clear_min();
-    }
-  }
-}
-
-}  // namespace metrics
diff --git a/metricsd/uploader/metrics_log_base.h b/metricsd/uploader/metrics_log_base.h
deleted file mode 100644
index f4e1995..0000000
--- a/metricsd/uploader/metrics_log_base.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// This file defines a set of user experience metrics data recorded by
-// the MetricsService.  This is the unit of data that is sent to the server.
-
-#ifndef METRICS_UPLOADER_METRICS_LOG_BASE_H_
-#define METRICS_UPLOADER_METRICS_LOG_BASE_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/metrics/histogram.h"
-#include "base/time/time.h"
-#include "uploader/proto/chrome_user_metrics_extension.pb.h"
-
-namespace base {
-class HistogramSamples;
-}  // namespace base
-
-namespace metrics {
-
-// This class provides base functionality for logging metrics data.
-class MetricsLogBase {
- public:
-  // TODO(asvitkine): Remove the NO_LOG value.
-  enum LogType {
-    INITIAL_STABILITY_LOG,  // The initial log containing stability stats.
-    ONGOING_LOG,            // Subsequent logs in a session.
-    NO_LOG,                 // Placeholder value for when there is no log.
-  };
-
-  // Creates a new metrics log of the specified type.
-  // client_id is the identifier for this profile on this installation
-  // session_id is an integer that's incremented on each application launch
-  MetricsLogBase(const std::string& client_id,
-                 int session_id,
-                 LogType log_type,
-                 const std::string& version_string);
-  virtual ~MetricsLogBase();
-
-  // Computes the MD5 hash of the given string, and returns the first 8 bytes of
-  // the hash.
-  static uint64_t Hash(const std::string& value);
-
-  // Get the GMT buildtime for the current binary, expressed in seconds since
-  // January 1, 1970 GMT.
-  // The value is used to identify when a new build is run, so that previous
-  // reliability stats, from other builds, can be abandoned.
-  static int64_t GetBuildTime();
-
-  // Convenience function to return the current time at a resolution in seconds.
-  // This wraps base::TimeTicks, and hence provides an abstract time that is
-  // always incrementing for use in measuring time durations.
-  static int64_t GetCurrentTime();
-
-  // Records a user-initiated action.
-  void RecordUserAction(const std::string& key);
-
-  // Record any changes in a given histogram for transmission.
-  void RecordHistogramDelta(const std::string& histogram_name,
-                            const base::HistogramSamples& snapshot);
-
-  // Stop writing to this record and generate the encoded representation.
-  // None of the Record* methods can be called after this is called.
-  void CloseLog();
-
-  // Fills |encoded_log| with the serialized protobuf representation of the
-  // record.  Must only be called after CloseLog() has been called.
-  void GetEncodedLog(std::string* encoded_log);
-
-  int num_events() { return num_events_; }
-
-  void set_hardware_class(const std::string& hardware_class) {
-    uma_proto_.mutable_system_profile()->mutable_hardware()->set_hardware_class(
-        hardware_class);
-  }
-
-  LogType log_type() const { return log_type_; }
-
- protected:
-  bool locked() const { return locked_; }
-
-  metrics::ChromeUserMetricsExtension* uma_proto() { return &uma_proto_; }
-  const metrics::ChromeUserMetricsExtension* uma_proto() const {
-    return &uma_proto_;
-  }
-
-  // TODO(isherman): Remove this once the XML pipeline is outta here.
-  int num_events_;  // the number of events recorded in this log
-
- private:
-  // locked_ is true when record has been packed up for sending, and should
-  // no longer be written to.  It is only used for sanity checking and is
-  // not a real lock.
-  bool locked_;
-
-  // The type of the log, i.e. initial or ongoing.
-  const LogType log_type_;
-
-  // Stores the protocol buffer representation for this log.
-  metrics::ChromeUserMetricsExtension uma_proto_;
-
-  DISALLOW_COPY_AND_ASSIGN(MetricsLogBase);
-};
-
-}  // namespace metrics
-
-#endif  // METRICS_UPLOADER_METRICS_LOG_BASE_H_
diff --git a/metricsd/uploader/metrics_log_base_unittest.cc b/metricsd/uploader/metrics_log_base_unittest.cc
deleted file mode 100644
index 980afd5..0000000
--- a/metricsd/uploader/metrics_log_base_unittest.cc
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "uploader/metrics_log_base.h"
-
-#include <string>
-
-#include <base/metrics/bucket_ranges.h>
-#include <base/metrics/sample_vector.h>
-#include <gtest/gtest.h>
-
-#include "uploader/proto/chrome_user_metrics_extension.pb.h"
-
-namespace metrics {
-
-namespace {
-
-class TestMetricsLogBase : public MetricsLogBase {
- public:
-  TestMetricsLogBase()
-      : MetricsLogBase("client_id", 1, MetricsLogBase::ONGOING_LOG, "1.2.3.4") {
-  }
-  virtual ~TestMetricsLogBase() {}
-
-  using MetricsLogBase::uma_proto;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestMetricsLogBase);
-};
-
-}  // namespace
-
-TEST(MetricsLogBaseTest, LogType) {
-  MetricsLogBase log1("id", 0, MetricsLogBase::ONGOING_LOG, "1.2.3");
-  EXPECT_EQ(MetricsLogBase::ONGOING_LOG, log1.log_type());
-
-  MetricsLogBase log2("id", 0, MetricsLogBase::INITIAL_STABILITY_LOG, "1.2.3");
-  EXPECT_EQ(MetricsLogBase::INITIAL_STABILITY_LOG, log2.log_type());
-}
-
-TEST(MetricsLogBaseTest, EmptyRecord) {
-  MetricsLogBase log("totally bogus client ID", 137,
-                     MetricsLogBase::ONGOING_LOG, "bogus version");
-  log.set_hardware_class("sample-class");
-  log.CloseLog();
-
-  std::string encoded;
-  log.GetEncodedLog(&encoded);
-
-  // A couple of fields are hard to mock, so these will be copied over directly
-  // for the expected output.
-  metrics::ChromeUserMetricsExtension parsed;
-  ASSERT_TRUE(parsed.ParseFromString(encoded));
-
-  metrics::ChromeUserMetricsExtension expected;
-  expected.set_client_id(5217101509553811875);  // Hashed bogus client ID
-  expected.set_session_id(137);
-  expected.mutable_system_profile()->set_build_timestamp(
-      parsed.system_profile().build_timestamp());
-  expected.mutable_system_profile()->set_app_version("bogus version");
-  expected.mutable_system_profile()->mutable_hardware()->set_hardware_class(
-      "sample-class");
-
-  EXPECT_EQ(expected.SerializeAsString(), encoded);
-}
-
-TEST(MetricsLogBaseTest, HistogramBucketFields) {
-  // Create buckets: 1-5, 5-7, 7-8, 8-9, 9-10, 10-11, 11-12.
-  base::BucketRanges ranges(8);
-  ranges.set_range(0, 1);
-  ranges.set_range(1, 5);
-  ranges.set_range(2, 7);
-  ranges.set_range(3, 8);
-  ranges.set_range(4, 9);
-  ranges.set_range(5, 10);
-  ranges.set_range(6, 11);
-  ranges.set_range(7, 12);
-
-  base::SampleVector samples(&ranges);
-  samples.Accumulate(3, 1);   // Bucket 1-5.
-  samples.Accumulate(6, 1);   // Bucket 5-7.
-  samples.Accumulate(8, 1);   // Bucket 8-9. (7-8 skipped)
-  samples.Accumulate(10, 1);  // Bucket 10-11. (9-10 skipped)
-  samples.Accumulate(11, 1);  // Bucket 11-12.
-
-  TestMetricsLogBase log;
-  log.RecordHistogramDelta("Test", samples);
-
-  const metrics::ChromeUserMetricsExtension* uma_proto = log.uma_proto();
-  const metrics::HistogramEventProto& histogram_proto =
-      uma_proto->histogram_event(uma_proto->histogram_event_size() - 1);
-
-  // Buckets with samples: 1-5, 5-7, 8-9, 10-11, 11-12.
-  // Should become: 1-/, 5-7, /-9, 10-/, /-12.
-  ASSERT_EQ(5, histogram_proto.bucket_size());
-
-  // 1-5 becomes 1-/ (max is same as next min).
-  EXPECT_TRUE(histogram_proto.bucket(0).has_min());
-  EXPECT_FALSE(histogram_proto.bucket(0).has_max());
-  EXPECT_EQ(1, histogram_proto.bucket(0).min());
-
-  // 5-7 stays 5-7 (no optimization possible).
-  EXPECT_TRUE(histogram_proto.bucket(1).has_min());
-  EXPECT_TRUE(histogram_proto.bucket(1).has_max());
-  EXPECT_EQ(5, histogram_proto.bucket(1).min());
-  EXPECT_EQ(7, histogram_proto.bucket(1).max());
-
-  // 8-9 becomes /-9 (min is same as max - 1).
-  EXPECT_FALSE(histogram_proto.bucket(2).has_min());
-  EXPECT_TRUE(histogram_proto.bucket(2).has_max());
-  EXPECT_EQ(9, histogram_proto.bucket(2).max());
-
-  // 10-11 becomes 10-/ (both optimizations apply, omit max is prioritized).
-  EXPECT_TRUE(histogram_proto.bucket(3).has_min());
-  EXPECT_FALSE(histogram_proto.bucket(3).has_max());
-  EXPECT_EQ(10, histogram_proto.bucket(3).min());
-
-  // 11-12 becomes /-12 (last record must keep max, min is same as max - 1).
-  EXPECT_FALSE(histogram_proto.bucket(4).has_min());
-  EXPECT_TRUE(histogram_proto.bucket(4).has_max());
-  EXPECT_EQ(12, histogram_proto.bucket(4).max());
-}
-
-}  // namespace metrics
diff --git a/metricsd/uploader/metricsd_service_runner.cc b/metricsd/uploader/metricsd_service_runner.cc
deleted file mode 100644
index 4361cac..0000000
--- a/metricsd/uploader/metricsd_service_runner.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "uploader/metricsd_service_runner.h"
-
-#include <thread>
-
-#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"
-
-MetricsdServiceRunner::MetricsdServiceRunner(
-    std::shared_ptr<CrashCounters> counters)
-    : counters_(counters) {}
-
-void MetricsdServiceRunner::Start() {
-  thread_.reset(new std::thread(&MetricsdServiceRunner::Run, this));
-}
-
-void MetricsdServiceRunner::Run() {
-  android::sp<BnMetricsdImpl> metrics_service(new BnMetricsdImpl(counters_));
-
-  android::status_t status = android::defaultServiceManager()->addService(
-      metrics_service->getInterfaceDescriptor(), metrics_service);
-  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(message_loop_.get());
-  CHECK(watcher.Init()) << "failed to initialize the binder file descriptor "
-                        << "watcher";
-
-  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();
-}
-
-void MetricsdServiceRunner::Stop() {
-  message_loop_for_io_->PostTask(FROM_HERE,
-                                 message_loop_for_io_->QuitWhenIdleClosure());
-
-  thread_->join();
-}
diff --git a/metricsd/uploader/metricsd_service_runner.h b/metricsd/uploader/metricsd_service_runner.h
deleted file mode 100644
index f5dad21..0000000
--- a/metricsd/uploader/metricsd_service_runner.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICS_UPLOADER_METRISCD_SERVICE_RUNNER_H_
-#define METRICS_UPLOADER_METRISCD_SERVICE_RUNNER_H_
-
-#include <memory>
-#include <thread>
-
-#include <base/message_loop/message_loop.h>
-#include <brillo/message_loops/message_loop.h>
-
-#include "uploader/crash_counters.h"
-
-class MetricsdServiceRunner {
- public:
-  MetricsdServiceRunner(std::shared_ptr<CrashCounters> counters);
-
-  // Start the Metricsd Binder service in a new thread.
-  void Start();
-
-  // Stop the Metricsd service and wait for its thread to exit.
-  void Stop();
-
- private:
-  // Creates and run the main loop for metricsd's Binder service.
-  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_;
-};
-
-#endif  // METRICS_UPLOADER_METRISCD_SERVICE_RUNNER_H_
diff --git a/metricsd/uploader/mock/mock_system_profile_setter.h b/metricsd/uploader/mock/mock_system_profile_setter.h
deleted file mode 100644
index 9b20291..0000000
--- a/metricsd/uploader/mock/mock_system_profile_setter.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICS_UPLOADER_MOCK_MOCK_SYSTEM_PROFILE_SETTER_H_
-#define METRICS_UPLOADER_MOCK_MOCK_SYSTEM_PROFILE_SETTER_H_
-
-#include "uploader/system_profile_setter.h"
-
-namespace metrics {
-class ChromeUserMetricsExtension;
-}
-
-// Mock profile setter used for testing.
-class MockSystemProfileSetter : public SystemProfileSetter {
- public:
-  bool Populate(metrics::ChromeUserMetricsExtension* profile_proto) override {
-    return true;
-  }
-};
-
-#endif  // METRICS_UPLOADER_MOCK_MOCK_SYSTEM_PROFILE_SETTER_H_
diff --git a/metricsd/uploader/mock/sender_mock.cc b/metricsd/uploader/mock/sender_mock.cc
deleted file mode 100644
index bb4dc7d..0000000
--- a/metricsd/uploader/mock/sender_mock.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "uploader/mock/sender_mock.h"
-
-SenderMock::SenderMock() {
-  Reset();
-}
-
-bool SenderMock::Send(const std::string& content, const std::string& hash) {
-  send_call_count_ += 1;
-  last_message_ = content;
-  is_good_proto_ = last_message_proto_.ParseFromString(content);
-  return should_succeed_;
-}
-
-void SenderMock::Reset() {
-  send_call_count_ = 0;
-  last_message_ = "";
-  should_succeed_ = true;
-  last_message_proto_.Clear();
-  is_good_proto_ = false;
-}
diff --git a/metricsd/uploader/mock/sender_mock.h b/metricsd/uploader/mock/sender_mock.h
deleted file mode 100644
index e79233f..0000000
--- a/metricsd/uploader/mock/sender_mock.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICS_UPLOADER_MOCK_SENDER_MOCK_H_
-#define METRICS_UPLOADER_MOCK_SENDER_MOCK_H_
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "uploader/proto/chrome_user_metrics_extension.pb.h"
-#include "uploader/sender.h"
-
-class SenderMock : public Sender {
- public:
-  SenderMock();
-
-  bool Send(const std::string& content, const std::string& hash) override;
-  void Reset();
-
-  bool is_good_proto() { return is_good_proto_; }
-  int send_call_count() { return send_call_count_; }
-  const std::string last_message() { return last_message_; }
-  metrics::ChromeUserMetricsExtension last_message_proto() {
-    return last_message_proto_;
-  }
-  void set_should_succeed(bool succeed) { should_succeed_ = succeed; }
-
- private:
-  // Is set to true if the proto was parsed successfully.
-  bool is_good_proto_;
-
-  // If set to true, the Send method will return true to simulate a successful
-  // send.
-  bool should_succeed_;
-
-  // Count of how many times Send was called since the last reset.
-  int send_call_count_;
-
-  // Last message received by Send.
-  std::string last_message_;
-
-  // If is_good_proto is true, last_message_proto is the deserialized
-  // representation of last_message.
-  metrics::ChromeUserMetricsExtension last_message_proto_;
-};
-
-#endif  // METRICS_UPLOADER_MOCK_SENDER_MOCK_H_
diff --git a/metricsd/uploader/proto/README b/metricsd/uploader/proto/README
deleted file mode 100644
index 4292a40..0000000
--- a/metricsd/uploader/proto/README
+++ /dev/null
@@ -1,37 +0,0 @@
-Copyright (C) 2015 The Android Open Source Project
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-
-
-
-This directory contains the protocol buffers used by the standalone metrics
-uploader. Those protobuffers are copied from the chromium protobuffers from
-https://chromium.googlesource.com/chromium/src/+/master/components/metrics/proto/
-at 3bfe5f2b4c03d2cac718d137ed14cd2c6354bfed.
-
-Any change to this protobuf must first be made to the backend's protobuf and be
-compatible with the chromium protobuffers.
-
-
-Q: Why fork the chromium protobuffers ?
-A: The standalone metrics uploader needs chromium os fields that are not defined
-by the chromium protobufs. Instead of pushing chromium os specific changes to
-chromium, we can add them only to chromium os (and to the backend of course).
-
-
-Q: What's the difference between those protobuffers and chromium's protobuffers?
-A: When the protobuffers were copied, some chromium specific protobuffers were
-not imported:
-* omnibox related protobuffers.
-* performance profiling protobuffers (not used in chromium os).
diff --git a/metricsd/uploader/proto/chrome_user_metrics_extension.proto b/metricsd/uploader/proto/chrome_user_metrics_extension.proto
deleted file mode 100644
index a07830f..0000000
--- a/metricsd/uploader/proto/chrome_user_metrics_extension.proto
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-//
-// Protocol buffer for Chrome UMA (User Metrics Analysis).
-//
-// Note: this protobuf must be compatible with the one in chromium.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-option java_outer_classname = "ChromeUserMetricsExtensionProtos";
-option java_package = "org.chromium.components.metrics";
-
-package metrics;
-
-import "system/core/metricsd/uploader/proto/histogram_event.proto";
-import "system/core/metricsd/uploader/proto/system_profile.proto";
-import "system/core/metricsd/uploader/proto/user_action_event.proto";
-
-// Next tag: 13
-message ChromeUserMetricsExtension {
-  // The product (i.e. end user application) for a given UMA log.
-  enum Product {
-    // Google Chrome product family.
-    CHROME = 0;
-  }
-  // The product corresponding to this log. The field type is int32 instead of
-  // Product so that downstream users of the Chromium metrics component can
-  // introduce products without needing to make changes to the Chromium code
-  // (though they still need to add the new product to the server-side enum).
-  // Note: The default value is Chrome, so Chrome products will not transmit
-  // this field.
-  optional int32 product = 10 [default = 0];
-
-  // The id of the client install that generated these events.
-  //
-  // For Chrome clients, this id is unique to a top-level (one level above the
-  // "Default" directory) Chrome user data directory [1], and so is shared among
-  // all Chrome user profiles contained in this user data directory.
-  // An id of 0 is reserved for test data (monitoring and internal testing) and
-  // should normally be ignored in analysis of the data.
-  // [1] http://www.chromium.org/user-experience/user-data-directory
-  optional fixed64 client_id = 1;
-
-  // The session id for this user.
-  // Values such as tab ids are only meaningful within a particular session.
-  // The client keeps track of the session id and sends it with each event.
-  // The session id is simply an integer that is incremented each time the user
-  // relaunches Chrome.
-  optional int32 session_id = 2;
-
-  // Information about the user's browser and system configuration.
-  optional SystemProfileProto system_profile = 3;
-
-  // This message will log one or more of the following event types:
-  repeated UserActionEventProto user_action_event = 4;
-  repeated HistogramEventProto histogram_event = 6;
-
-}
diff --git a/metricsd/uploader/proto/histogram_event.proto b/metricsd/uploader/proto/histogram_event.proto
deleted file mode 100644
index 3825063..0000000
--- a/metricsd/uploader/proto/histogram_event.proto
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-//
-// Histogram-collected metrics.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-option java_outer_classname = "HistogramEventProtos";
-option java_package = "org.chromium.components.metrics";
-
-package metrics;
-
-// Next tag: 4
-message HistogramEventProto {
-  // The name of the histogram, hashed.
-  optional fixed64 name_hash = 1;
-
-  // The sum of all the sample values.
-  // Together with the total count of the sample values, this allows us to
-  // compute the average value.  The count of all sample values is just the sum
-  // of the counts of all the buckets.
-  optional int64 sum = 2;
-
-  // The per-bucket data.
-  message Bucket {
-    // Each bucket's range is bounded by min <= x < max.
-    // It is valid to omit one of these two fields in a bucket, but not both.
-    // If the min field is omitted, its value is assumed to be equal to max - 1.
-    // If the max field is omitted, its value is assumed to be equal to the next
-    // bucket's min value (possibly computed per above).  The last bucket in a
-    // histogram should always include the max field.
-    optional int64 min = 1;
-    optional int64 max = 2;
-
-    // The bucket's index in the list of buckets, sorted in ascending order.
-    // This field was intended to provide extra redundancy to detect corrupted
-    // records, but was never used.  As of M31, it is no longer sent by Chrome
-    // clients to reduce the UMA upload size.
-    optional int32 bucket_index = 3 [deprecated = true];
-
-    // The number of entries in this bucket.
-    optional int64 count = 4;
-  }
-  repeated Bucket bucket = 3;
-}
diff --git a/metricsd/uploader/proto/system_profile.proto b/metricsd/uploader/proto/system_profile.proto
deleted file mode 100644
index bac828b..0000000
--- a/metricsd/uploader/proto/system_profile.proto
+++ /dev/null
@@ -1,759 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-//
-// Stores information about the user's brower and system configuration.
-// The system configuration fields are recorded once per client session.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-option java_outer_classname = "SystemProfileProtos";
-option java_package = "org.chromium.components.metrics";
-
-package metrics;
-
-// Next tag: 21
-message SystemProfileProto {
-  // The time when the client was compiled/linked, in seconds since the epoch.
-  optional int64 build_timestamp = 1;
-
-  // A version number string for the application.
-  // Most commonly this is the browser version number found in a user agent
-  // string, and is typically a 4-tuple of numbers separated by periods.  In
-  // cases where the user agent version might be ambiguous (example: Linux 64-
-  // bit build, rather than 32-bit build, or a Windows version used in some
-  // special context, such as ChromeFrame running in IE), then this may include
-  // some additional postfix to provide clarification not available in the UA
-  // string.
-  //
-  // An example of a browser version 4-tuple is "5.0.322.0".  Currently used
-  // postfixes are:
-  //
-  //   "-64": a 64-bit build
-  //   "-F": Chrome is running under control of ChromeFrame
-  //   "-devel": this is not an official build of Chrome
-  //
-  // A full version number string could look similar to:
-  // "5.0.322.0-F-devel".
-  //
-  // This value, when available, is more trustworthy than the UA string
-  // associated with the request; and including the postfix, may be more
-  // specific.
-  optional string app_version = 2;
-
-  // The brand code or distribution tag assigned to a partner, if available.
-  // Brand codes are only available on Windows.  Not every Windows install
-  // though will have a brand code.
-  optional string brand_code = 12;
-
-  // The possible channels for an installation, from least to most stable.
-  enum Channel {
-    CHANNEL_UNKNOWN = 0;  // Unknown channel -- perhaps an unofficial build?
-    CHANNEL_CANARY = 1;
-    CHANNEL_DEV = 2;
-    CHANNEL_BETA = 3;
-    CHANNEL_STABLE = 4;
-  }
-  optional Channel channel = 10;
-
-  // True if Chrome build is ASan-instrumented.
-  optional bool is_asan_build = 20 [default = false];
-
-  // The date the user enabled UMA, in seconds since the epoch.
-  // If the user has toggled the UMA enabled state multiple times, this will
-  // be the most recent date on which UMA was enabled.
-  // For privacy, this is rounded to the nearest hour.
-  optional int64 uma_enabled_date = 3;
-
-  // The time when the client was installed, in seconds since the epoch.
-  // For privacy, this is rounded to the nearest hour.
-  optional int64 install_date = 16;
-
-  // The user's selected application locale, i.e. the user interface language.
-  // The locale includes a language code and, possibly, also a country code,
-  // e.g. "en-US".
-  optional string application_locale = 4;
-
-  message BrilloDeviceData {
-    optional string product_id = 1;
-  }
-  optional BrilloDeviceData brillo = 21;
-
-  // Information on the user's operating system.
-  message OS {
-    // The user's operating system. This should be one of:
-    // - Android
-    // - Windows NT
-    // - Linux (includes ChromeOS)
-    // - iPhone OS
-    // - Mac OS X
-    optional string name = 1;
-
-    // The version of the OS.  The meaning of this field is OS-dependent.
-    optional string version = 2;
-
-    // The fingerprint of the build.  This field is used only on Android.
-    optional string fingerprint = 3;
-
-    // Whether the version of iOS appears to be "jailbroken". This field is
-    // used only on iOS. Chrome for iOS detects whether device contains a
-    // DynamicLibraries/ directory. It's a necessary but insufficient indicator
-    // of whether the operating system has been jailbroken.
-    optional bool is_jailbroken = 4;
-  }
-  optional OS os = 5;
-
-  // Next tag for Hardware: 18
-  // Information on the user's hardware.
-  message Hardware {
-    // The CPU architecture (x86, PowerPC, x86_64, ...)
-    optional string cpu_architecture = 1;
-
-    // The amount of RAM present on the system, in megabytes.
-    optional int64 system_ram_mb = 2;
-
-    // The base memory address that chrome.dll was loaded at.
-    // (Logged only on Windows.)
-    optional int64 dll_base = 3;
-
-    // The Chrome OS device hardware class ID is a unique string associated with
-    // each Chrome OS device product revision generally assigned at hardware
-    // qualification time.  The hardware class effectively identifies the
-    // configured system components such as CPU, WiFi adapter, etc.
-    //
-    // An example of such a hardware class is "IEC MARIO PONY 6101".  An
-    // internal database associates this hardware class with the qualified
-    // device specifications including OEM information, schematics, hardware
-    // qualification reports, test device tags, etc.
-    optional string hardware_class = 4;
-
-    // The number of physical screens.
-    optional int32 screen_count = 5;
-
-    // The screen dimensions of the primary screen, in pixels.
-    optional int32 primary_screen_width = 6;
-    optional int32 primary_screen_height = 7;
-
-    // The device scale factor of the primary screen.
-    optional float primary_screen_scale_factor = 12;
-
-    // Max DPI for any attached screen. (Windows only)
-    optional float max_dpi_x = 9;
-    optional float max_dpi_y = 10;
-
-    // Information on the CPU obtained by CPUID.
-    message CPU {
-      // A 12 character string naming the vendor, e.g. "GeniuneIntel".
-      optional string vendor_name = 1;
-
-      // The signature reported by CPUID (from EAX).
-      optional uint32 signature = 2;
-
-      // Number of logical processors/cores on the current machine.
-      optional uint32 num_cores = 3;
-    }
-    optional CPU cpu = 13;
-
-    // Information on the GPU
-    message Graphics {
-      // The GPU manufacturer's vendor id.
-      optional uint32 vendor_id = 1;
-
-      // The GPU manufacturer's device id for the chip set.
-      optional uint32 device_id = 2;
-
-      // The driver version on the GPU.
-      optional string driver_version = 3;
-
-      // The driver date on the GPU.
-      optional string driver_date = 4;
-
-      // The GL_VENDOR string. An example of a gl_vendor string is
-      // "Imagination Technologies". "" if we are not using OpenGL.
-      optional string gl_vendor = 6;
-
-      // The GL_RENDERER string. An example of a gl_renderer string is
-      // "PowerVR SGX 540". "" if we are not using OpenGL.
-      optional string gl_renderer = 7;
-    }
-    optional Graphics gpu = 8;
-
-    // Information about Bluetooth devices paired with the system.
-    message Bluetooth {
-      // Whether Bluetooth is present on this system.
-      optional bool is_present = 1;
-
-      // Whether Bluetooth is enabled on this system.
-      optional bool is_enabled = 2;
-
-      // Describes a paired device.
-      message PairedDevice {
-        // Assigned class of the device. This is a bitfield according to the
-        // Bluetooth specification available at the following URL:
-        // https://www.bluetooth.org/en-us/specification/assigned-numbers-overview/baseband
-        optional uint32 bluetooth_class = 1;
-
-        // Decoded device type.
-        enum Type {
-          DEVICE_UNKNOWN = 0;
-          DEVICE_COMPUTER = 1;
-          DEVICE_PHONE = 2;
-          DEVICE_MODEM = 3;
-          DEVICE_AUDIO = 4;
-          DEVICE_CAR_AUDIO = 5;
-          DEVICE_VIDEO = 6;
-          DEVICE_PERIPHERAL = 7;
-          DEVICE_JOYSTICK = 8;
-          DEVICE_GAMEPAD = 9;
-          DEVICE_KEYBOARD = 10;
-          DEVICE_MOUSE = 11;
-          DEVICE_TABLET = 12;
-          DEVICE_KEYBOARD_MOUSE_COMBO = 13;
-        }
-        optional Type type = 2;
-
-        // Vendor prefix of the Bluetooth address, these are OUI registered by
-        // the IEEE and are encoded with the first byte in bits 16-23, the
-        // second byte in bits 8-15 and the third byte in bits 0-7.
-        //
-        // ie. Google's OUI (00:1A:11) is encoded as 0x00001A11
-        optional uint32 vendor_prefix = 4;
-
-        // The Vendor ID of a device, returned in vendor_id below, can be
-        // either allocated by the Bluetooth SIG or USB IF, providing two
-        // completely overlapping namespaces for identifiers.
-        //
-        // This field should be read along with vendor_id to correctly
-        // identify the vendor. For example Google is identified by either
-        // vendor_id_source = VENDOR_ID_BLUETOOTH, vendor_id = 0x00E0 or
-        // vendor_id_source = VENDOR_ID_USB, vendor_id = 0x18D1.
-        //
-        // If the device does not support the Device ID specification the
-        // unknown value will be set.
-        enum VendorIDSource {
-          VENDOR_ID_UNKNOWN = 0;
-          VENDOR_ID_BLUETOOTH = 1;
-          VENDOR_ID_USB = 2;
-        }
-        optional VendorIDSource vendor_id_source = 8;
-
-        // Vendor ID of the device, where available.
-        optional uint32 vendor_id = 5;
-
-        // Product ID of the device, where available.
-        optional uint32 product_id = 6;
-
-        // Device ID of the device, generally the release or version number in
-        // BCD format, where available.
-        optional uint32 device_id = 7;
-      }
-      repeated PairedDevice paired_device = 3;
-    }
-    optional Bluetooth bluetooth = 11;
-
-    // Whether the internal display produces touch events. Omitted if unknown.
-    // Logged on ChromeOS only.
-    optional bool internal_display_supports_touch = 14;
-
-    // Vendor ids and product ids of external touchscreens.
-    message TouchScreen {
-      // Touch screen vendor id.
-      optional uint32 vendor_id = 1;
-      // Touch screen product id.
-      optional uint32 product_id = 2;
-    }
-    // Lists vendor and product ids of external touchscreens.
-    // Logged on ChromeOS only.
-    repeated TouchScreen external_touchscreen = 15;
-
-    // Drive messages are currently logged on Windows 7+, iOS, and Android.
-    message Drive {
-      // Whether this drive incurs a time penalty when randomly accessed. This
-      // should be true for spinning disks but false for SSDs or other
-      // flash-based drives.
-      optional bool has_seek_penalty = 1;
-    }
-    // The drive that the application executable was loaded from.
-    optional Drive app_drive = 16;
-    // The drive that the current user data directory was loaded from.
-    optional Drive user_data_drive = 17;
-  }
-  optional Hardware hardware = 6;
-
-  // Information about the network connection.
-  message Network {
-    // Set to true if connection_type changed during the lifetime of the log.
-    optional bool connection_type_is_ambiguous = 1;
-
-    // See net::NetworkChangeNotifier::ConnectionType.
-    enum ConnectionType {
-      CONNECTION_UNKNOWN = 0;
-      CONNECTION_ETHERNET = 1;
-      CONNECTION_WIFI = 2;
-      CONNECTION_2G = 3;
-      CONNECTION_3G = 4;
-      CONNECTION_4G = 5;
-      CONNECTION_BLUETOOTH = 6;
-    }
-    // The connection type according to NetworkChangeNotifier.
-    optional ConnectionType connection_type = 2;
-
-    // Set to true if wifi_phy_layer_protocol changed during the lifetime of the log.
-    optional bool wifi_phy_layer_protocol_is_ambiguous = 3;
-
-    // See net::WifiPHYLayerProtocol.
-    enum WifiPHYLayerProtocol {
-      WIFI_PHY_LAYER_PROTOCOL_NONE = 0;
-      WIFI_PHY_LAYER_PROTOCOL_ANCIENT = 1;
-      WIFI_PHY_LAYER_PROTOCOL_A = 2;
-      WIFI_PHY_LAYER_PROTOCOL_B = 3;
-      WIFI_PHY_LAYER_PROTOCOL_G = 4;
-      WIFI_PHY_LAYER_PROTOCOL_N = 5;
-      WIFI_PHY_LAYER_PROTOCOL_UNKNOWN = 6;
-    }
-    // The physical layer mode of the associated wifi access point, if any.
-    optional WifiPHYLayerProtocol wifi_phy_layer_protocol = 4;
-
-    // Describe wifi access point information.
-    message WifiAccessPoint {
-      // Vendor prefix of the access point's BSSID, these are OUIs
-      // (Organizationally Unique Identifiers) registered by
-      // the IEEE and are encoded with the first byte in bits 16-23, the
-      // second byte in bits 8-15 and the third byte in bits 0-7.
-      optional uint32 vendor_prefix = 1;
-
-      // Access point seurity mode definitions.
-      enum SecurityMode {
-        SECURITY_UNKNOWN = 0;
-        SECURITY_WPA = 1;
-        SECURITY_WEP = 2;
-        SECURITY_RSN = 3;
-        SECURITY_802_1X = 4;
-        SECURITY_PSK = 5;
-        SECURITY_NONE = 6;
-      }
-      // The security mode of the access point.
-      optional SecurityMode security_mode = 2;
-
-      // Vendor specific information.
-      message VendorInformation {
-        // The model number, for example "0".
-        optional string model_number = 1;
-
-        // The model name (sometimes the same as the model_number),
-        // for example "WZR-HP-AG300H".
-        optional string model_name = 2;
-
-        // The device name (sometimes the same as the model_number),
-        // for example "Dummynet"
-        optional string device_name = 3;
-
-        // The list of vendor-specific OUIs (Organziationally Unqiue
-        // Identifiers). These are provided by the vendor through WPS
-        // (Wireless Provisioning Service) information elements, which
-        // identifies the content of the element.
-        repeated uint32 element_identifier = 4;
-      }
-      // The wireless access point vendor information.
-      optional VendorInformation vendor_info = 3;
-    }
-    // Information of the wireless AP that device is connected to.
-    optional WifiAccessPoint access_point_info = 5;
-  }
-  optional Network network = 13;
-
-  // Information on the Google Update install that is managing this client.
-  message GoogleUpdate {
-    // Whether the Google Update install is system-level or user-level.
-    optional bool is_system_install = 1;
-
-    // The date at which Google Update last started performing an automatic
-    // update check, in seconds since the Unix epoch.
-    optional int64 last_automatic_start_timestamp = 2;
-
-    // The date at which Google Update last successfully sent an update check
-    // and recieved an intact response from the server, in seconds since the
-    // Unix epoch. (The updates don't need to be successfully installed.)
-    optional int64 last_update_check_timestamp = 3;
-
-    // Describes a product being managed by Google Update. (This can also
-    // describe Google Update itself.)
-    message ProductInfo {
-      // The current version of the product that is installed.
-      optional string version = 1;
-
-      // The date at which Google Update successfully updated this product,
-      // stored in seconds since the Unix epoch.  This is updated when an update
-      // is successfully applied, or if the server reports that no update
-      // is available.
-      optional int64 last_update_success_timestamp = 2;
-
-      // The result reported by the product updater on its last run.
-      enum InstallResult {
-        INSTALL_RESULT_SUCCESS = 0;
-        INSTALL_RESULT_FAILED_CUSTOM_ERROR = 1;
-        INSTALL_RESULT_FAILED_MSI_ERROR = 2;
-        INSTALL_RESULT_FAILED_SYSTEM_ERROR = 3;
-        INSTALL_RESULT_EXIT_CODE = 4;
-      }
-      optional InstallResult last_result = 3;
-
-      // The error code reported by the product updater on its last run.  This
-      // will typically be a error code specific to the product installer.
-      optional int32 last_error = 4;
-
-      // The extra error code reported by the product updater on its last run.
-      // This will typically be a Win32 error code.
-      optional int32 last_extra_error = 5;
-    }
-    optional ProductInfo google_update_status = 4;
-    optional ProductInfo client_status = 5;
-  }
-  optional GoogleUpdate google_update = 11;
-
-  // Information on all installed plugins.
-  message Plugin {
-    // The plugin's self-reported name and filename (without path).
-    optional string name = 1;
-    optional string filename = 2;
-
-    // The plugin's version.
-    optional string version = 3;
-
-    // True if the plugin is disabled.
-    // If a client has multiple local Chrome user accounts, this is logged based
-    // on the first user account launched during the current session.
-    optional bool is_disabled = 4;
-
-    // True if the plugin is PPAPI.
-    optional bool is_pepper = 5;
-  }
-  repeated Plugin plugin = 7;
-
-  // Figures that can be used to generate application stability metrics.
-  // All values are counts of events since the last time that these
-  // values were reported.
-  // Next tag: 24
-  message Stability {
-    // Total amount of time that the program was running, in seconds,
-    // since the last time a log was recorded, as measured using a client-side
-    // clock implemented via TimeTicks, which guarantees that it is monotonic
-    // and does not jump if the user changes his/her clock.  The TimeTicks
-    // implementation also makes the clock not count time the computer is
-    // suspended.
-    optional int64 incremental_uptime_sec = 1;
-
-    // Total amount of time that the program was running, in seconds,
-    // since startup, as measured using a client-side clock implemented
-    // via TimeTicks, which guarantees that it is monotonic and does not
-    // jump if the user changes his/her clock.  The TimeTicks implementation
-    // also makes the clock not count time the computer is suspended.
-    // This field was added for M-35.
-    optional int64 uptime_sec = 23;
-
-    // Page loads along with renderer crashes and hangs, since page load count
-    // roughly corresponds to usage.
-    optional int32 page_load_count = 2;
-    optional int32 renderer_crash_count = 3;
-    optional int32 renderer_hang_count = 4;
-
-    // Number of renderer crashes that were for extensions. These crashes are
-    // not counted in renderer_crash_count.
-    optional int32 extension_renderer_crash_count = 5;
-
-    // Number of non-renderer child process crashes.
-    optional int32 child_process_crash_count = 6;
-
-    // Number of times the browser has crashed while logged in as the "other
-    // user" (guest) account.
-    // Logged on ChromeOS only.
-    optional int32 other_user_crash_count = 7;
-
-    // Number of times the kernel has crashed.
-    // Logged on ChromeOS only.
-    optional int32 kernel_crash_count = 8;
-
-    // Number of times the system has shut down uncleanly.
-    // Logged on ChromeOS only.
-    optional int32 unclean_system_shutdown_count = 9;
-
-    //
-    // All the remaining fields in the Stability are recorded at most once per
-    // client session.
-    //
-
-    // The number of times the program was launched.
-    // This will typically be equal to 1.  However, it is possible that Chrome
-    // was unable to upload stability metrics for previous launches (e.g. due to
-    // crashing early during startup), and hence this value might be greater
-    // than 1.
-    optional int32 launch_count = 15;
-    // The number of times that it didn't exit cleanly (which we assume to be
-    // mostly crashes).
-    optional int32 crash_count = 16;
-
-    // The number of times the program began, but did not complete, the shutdown
-    // process.  (For example, this may occur when Windows is shutting down, and
-    // it only gives the process a few seconds to clean up.)
-    optional int32 incomplete_shutdown_count = 17;
-
-    // The number of times the program was able register with breakpad crash
-    // services.
-    optional int32 breakpad_registration_success_count = 18;
-
-    // The number of times the program failed to register with breakpad crash
-    // services.  If crash registration fails then when the program crashes no
-    // crash report will be generated.
-    optional int32 breakpad_registration_failure_count = 19;
-
-    // The number of times the program has run under a debugger.  This should
-    // be an exceptional condition.  Running under a debugger prevents crash
-    // dumps from being generated.
-    optional int32 debugger_present_count = 20;
-
-    // The number of times the program has run without a debugger attached.
-    // This should be most common scenario and should be very close to
-    // |launch_count|.
-    optional int32 debugger_not_present_count = 21;
-
-    // Stability information for all installed plugins.
-    message PluginStability {
-      // The relevant plugin's information (name, etc.)
-      optional Plugin plugin = 1;
-
-      // The number of times this plugin's process was launched.
-      optional int32 launch_count = 2;
-
-      // The number of times this plugin was instantiated on a web page.
-      // This will be >= |launch_count|.
-      // (A page load with multiple sections drawn by this plugin will
-      // increase this count multiple times.)
-      optional int32 instance_count = 3;
-
-      // The number of times this plugin process crashed.
-      // This value will be <= |launch_count|.
-      optional int32 crash_count = 4;
-
-      // The number of times this plugin could not be loaded.
-      optional int32 loading_error_count = 5;
-    }
-    repeated PluginStability plugin_stability = 22;
-  }
-  optional Stability stability = 8;
-
-  // Description of a field trial or experiment that the user is currently
-  // enrolled in.
-  // All metrics reported in this upload can potentially be influenced by the
-  // field trial.
-  message FieldTrial {
-    // The name of the field trial, as a 32-bit identifier.
-    // Currently, the identifier is a hash of the field trial's name.
-    optional fixed32 name_id = 1;
-
-    // The user's group within the field trial, as a 32-bit identifier.
-    // Currently, the identifier is a hash of the group's name.
-    optional fixed32 group_id = 2;
-  }
-  repeated FieldTrial field_trial = 9;
-
-  // Information about the A/V output device(s) (typically just a TV).
-  // However, a configuration may have one or more intermediate A/V devices
-  // between the source device and the TV (e.g. an A/V receiver, video
-  // processor, etc.).
-  message ExternalAudioVideoDevice {
-    // The manufacturer name (possibly encoded as a 3-letter code, e.g. "YMH"
-    // for Yamaha).
-    optional string manufacturer_name = 1;
-
-    // The model name (e.g. "RX-V1900"). Some devices may report generic names
-    // like "receiver" or use the full manufacturer name (e.g "PHILIPS").
-    optional string model_name = 2;
-
-    // The product code (e.g. "0218").
-    optional string product_code = 3;
-
-    // The device types. A single device can have multiple types (e.g. a set-top
-    // box could be both a tuner and a player).  The same type may even be
-    // repeated (e.g a device that reports two tuners).
-    enum AVDeviceType {
-      AV_DEVICE_TYPE_UNKNOWN = 0;
-      AV_DEVICE_TYPE_TV = 1;
-      AV_DEVICE_TYPE_RECORDER = 2;
-      AV_DEVICE_TYPE_TUNER = 3;
-      AV_DEVICE_TYPE_PLAYER = 4;
-      AV_DEVICE_TYPE_AUDIO_SYSTEM = 5;
-    }
-    repeated AVDeviceType av_device_type = 4;
-
-    // The year of manufacture.
-    optional int32 manufacture_year = 5;
-
-    // The week of manufacture.
-    // Note: per the Wikipedia EDID article, numbering for this field may not
-    // be consistent between manufacturers.
-    optional int32 manufacture_week = 6;
-
-    // Max horizontal resolution in pixels.
-    optional int32 horizontal_resolution = 7;
-
-    // Max vertical resolution in pixels.
-    optional int32 vertical_resolution = 8;
-
-    // Audio capabilities of the device.
-    // Ref: http://en.wikipedia.org/wiki/Extended_display_identification_data
-    message AudioDescription {
-      // Audio format
-      enum AudioFormat {
-        AUDIO_FORMAT_UNKNOWN = 0;
-        AUDIO_FORMAT_LPCM = 1;
-        AUDIO_FORMAT_AC_3 = 2;
-        AUDIO_FORMAT_MPEG1 = 3;
-        AUDIO_FORMAT_MP3 = 4;
-        AUDIO_FORMAT_MPEG2 = 5;
-        AUDIO_FORMAT_AAC = 6;
-        AUDIO_FORMAT_DTS = 7;
-        AUDIO_FORMAT_ATRAC = 8;
-        AUDIO_FORMAT_ONE_BIT = 9;
-        AUDIO_FORMAT_DD_PLUS = 10;
-        AUDIO_FORMAT_DTS_HD = 11;
-        AUDIO_FORMAT_MLP_DOLBY_TRUEHD = 12;
-        AUDIO_FORMAT_DST_AUDIO = 13;
-        AUDIO_FORMAT_MICROSOFT_WMA_PRO = 14;
-      }
-      optional AudioFormat audio_format = 1;
-
-      // Number of channels (e.g. 1, 2, 8, etc.).
-      optional int32 num_channels = 2;
-
-      // Supported sample frequencies in Hz (e.g. 32000, 44100, etc.).
-      // Multiple frequencies may be specified.
-      repeated int32 sample_frequency_hz = 3;
-
-      // Maximum bit rate in bits/s.
-      optional int32 max_bit_rate_per_second = 4;
-
-      // Bit depth (e.g. 16, 20, 24, etc.).
-      optional int32 bit_depth = 5;
-    }
-    repeated AudioDescription audio_description = 9;
-
-    // The position in AV setup.
-    // A value of 0 means this device is the TV.
-    // A value of 1 means this device is directly connected to one of
-    // the TV's inputs.
-    // Values > 1 indicate there are 1 or more devices between this device
-    // and the TV.
-    optional int32 position_in_setup = 10;
-
-    // Whether this device is in the path to the TV.
-    optional bool is_in_path_to_tv = 11;
-
-    // The CEC version the device supports.
-    // CEC stands for Consumer Electronics Control, a part of the HDMI
-    // specification.  Not all HDMI devices support CEC.
-    // Only devices that support CEC will report a value here.
-    optional int32 cec_version = 12;
-
-    // This message reports CEC commands seen by a device.
-    // After each log is sent, this information is cleared and gathered again.
-    // By collecting CEC status information by opcode we can determine
-    // which CEC features can be supported.
-    message CECCommand {
-      // The CEC command opcode.  CEC supports up to 256 opcodes.
-      // We add only one CECCommand message per unique opcode.  Only opcodes
-      // seen by the device will be reported. The remainder of the message
-      // accumulates status for this opcode (and device).
-      optional int32 opcode = 1;
-
-      // The total number of commands received from the external device.
-      optional int32 num_received_direct = 2;
-
-      // The number of commands received from the external device as part of a
-      // broadcast message.
-      optional int32 num_received_broadcast = 3;
-
-      // The total number of commands sent to the external device.
-      optional int32 num_sent_direct = 4;
-
-      // The number of commands sent to the external device as part of a
-      // broadcast message.
-      optional int32 num_sent_broadcast = 5;
-
-      // The number of aborted commands for unknown reasons.
-      optional int32 num_aborted_unknown_reason = 6;
-
-      // The number of aborted commands because of an unrecognized opcode.
-      optional int32 num_aborted_unrecognized = 7;
-    }
-    repeated CECCommand cec_command = 13;
-  }
-  repeated ExternalAudioVideoDevice external_audio_video_device = 14;
-
-  // Information about the current wireless access point. Collected directly
-  // from the wireless access point via standard apis if the device is
-  // connected to the Internet wirelessly. Introduced for Chrome on TV devices
-  // but also can be collected by ChromeOS, Android or other clients.
-  message ExternalAccessPoint {
-    // The manufacturer name, for example "ASUSTeK Computer Inc.".
-    optional string manufacturer = 1;
-
-    // The model name, for example "Wi-Fi Protected Setup Router".
-    optional string model_name = 2;
-
-    // The model number, for example "RT-N16".
-    optional string model_number = 3;
-
-    // The device name (sometime same as model_number), for example "RT-N16".
-    optional string device_name = 4;
-  }
-  optional ExternalAccessPoint external_access_point = 15;
-
-  // Number of users currently signed into a multiprofile session.
-  // A zero value indicates that the user count changed while the log is open.
-  // Logged only on ChromeOS.
-  optional uint32 multi_profile_user_count = 17;
-
-  // Information about extensions that are installed, masked to provide better
-  // privacy.  Only extensions from a single profile are reported; this will
-  // generally be the profile used when the browser is started.  The profile
-  // reported on will remain consistent at least until the browser is
-  // relaunched (or the profile is deleted by the user).
-  //
-  // Each client first picks a value for client_key derived from its UMA
-  // client_id:
-  //   client_key = client_id % 4096
-  // Then, each installed extension is mapped into a hash bucket according to
-  //   bucket = CityHash64(StringPrintf("%d:%s",
-  //                                    client_key, extension_id)) % 1024
-  // The client reports the set of hash buckets occupied by all installed
-  // extensions.  If multiple extensions map to the same bucket, that bucket is
-  // still only reported once.
-  repeated int32 occupied_extension_bucket = 18;
-
-  // The state of loaded extensions for this system. The system can have either
-  // no applicable extensions, extensions only from the webstore and verified by
-  // the webstore, extensions only from the webstore but not verified, or
-  // extensions not from the store. If there is a single off-store extension,
-  // then HAS_OFFSTORE is reported. This should be kept in sync with the
-  // corresponding enum in chrome/browser/metrics/extensions_metrics_provider.cc
-  enum ExtensionsState {
-    NO_EXTENSIONS = 0;
-    NO_OFFSTORE_VERIFIED = 1;
-    NO_OFFSTORE_UNVERIFIED = 2;
-    HAS_OFFSTORE = 3;
-  }
-  optional ExtensionsState offstore_extensions_state = 19;
-}
diff --git a/metricsd/uploader/proto/user_action_event.proto b/metricsd/uploader/proto/user_action_event.proto
deleted file mode 100644
index 464f3c8..0000000
--- a/metricsd/uploader/proto/user_action_event.proto
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-//
-// Stores information about an event that occurs in response to a user action,
-// e.g. an interaction with a browser UI element.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-option java_outer_classname = "UserActionEventProtos";
-option java_package = "org.chromium.components.metrics";
-
-package metrics;
-
-// Next tag: 3
-message UserActionEventProto {
-  // The name of the action, hashed.
-  optional fixed64 name_hash = 1;
-
-  // The timestamp for the event, in seconds since the epoch.
-  optional int64 time = 2;
-}
diff --git a/metricsd/uploader/sender.h b/metricsd/uploader/sender.h
deleted file mode 100644
index 369c9c2..0000000
--- a/metricsd/uploader/sender.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICS_UPLOADER_SENDER_H_
-#define METRICS_UPLOADER_SENDER_H_
-
-#include <string>
-
-// Abstract class for a Sender that uploads a metrics message.
-class Sender {
- public:
-  virtual ~Sender() {}
-  // Sends a message |content| with its sha1 hash |hash|
-  virtual bool Send(const std::string& content, const std::string& hash) = 0;
-};
-
-#endif  // METRICS_UPLOADER_SENDER_H_
diff --git a/metricsd/uploader/sender_http.cc b/metricsd/uploader/sender_http.cc
deleted file mode 100644
index 4b572a6..0000000
--- a/metricsd/uploader/sender_http.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "uploader/sender_http.h"
-
-#include <string>
-
-#include <base/logging.h>
-#include <base/strings/string_number_conversions.h>
-#include <brillo/http/http_utils.h>
-#include <brillo/mime_utils.h>
-
-HttpSender::HttpSender(const std::string server_url)
-    : server_url_(server_url) {}
-
-bool HttpSender::Send(const std::string& content,
-                      const std::string& content_hash) {
-  const std::string hash =
-      base::HexEncode(content_hash.data(), content_hash.size());
-
-  brillo::http::HeaderList headers = {{"X-Chrome-UMA-Log-SHA1", hash}};
-  brillo::ErrorPtr error;
-  auto response = brillo::http::PostTextAndBlock(
-      server_url_,
-      content,
-      brillo::mime::application::kWwwFormUrlEncoded,
-      headers,
-      brillo::http::Transport::CreateDefault(),
-      &error);
-  if (!response || response->ExtractDataAsString() != "OK") {
-    if (error) {
-      DLOG(ERROR) << "Failed to send data: " << error->GetMessage();
-    }
-    return false;
-  }
-  return true;
-}
diff --git a/metricsd/uploader/sender_http.h b/metricsd/uploader/sender_http.h
deleted file mode 100644
index 4f1c08f..0000000
--- a/metricsd/uploader/sender_http.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICS_UPLOADER_SENDER_HTTP_H_
-#define METRICS_UPLOADER_SENDER_HTTP_H_
-
-#include <string>
-
-#include <base/macros.h>
-
-#include "uploader/sender.h"
-
-// Sender implemented using http_utils from libbrillo
-class HttpSender : public Sender {
- public:
-  explicit HttpSender(std::string server_url);
-  ~HttpSender() override = default;
-  // Sends |content| whose SHA1 hash is |hash| to server_url with a synchronous
-  // POST request to server_url.
-  bool Send(const std::string& content, const std::string& hash) override;
-
- private:
-  const std::string server_url_;
-
-  DISALLOW_COPY_AND_ASSIGN(HttpSender);
-};
-
-#endif  // METRICS_UPLOADER_SENDER_HTTP_H_
diff --git a/metricsd/uploader/system_profile_cache.cc b/metricsd/uploader/system_profile_cache.cc
deleted file mode 100644
index e6f6617..0000000
--- a/metricsd/uploader/system_profile_cache.cc
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "uploader/system_profile_cache.h"
-
-#include <base/files/file_util.h>
-#include <base/guid.h>
-#include <base/logging.h>
-#include <base/strings/string_number_conversions.h>
-#include <base/strings/string_util.h>
-#include <brillo/osrelease_reader.h>
-#include <string>
-#include <update_engine/client.h>
-#include <vector>
-
-#include "constants.h"
-#include "persistent_integer.h"
-#include "uploader/metrics_log_base.h"
-#include "uploader/proto/chrome_user_metrics_extension.pb.h"
-
-namespace {
-
-const char kPersistentSessionIdFilename[] = "Sysinfo.SessionId";
-
-}  // namespace
-
-std::string ChannelToString(
-    const metrics::SystemProfileProto_Channel& channel) {
-  switch (channel) {
-    case metrics::SystemProfileProto::CHANNEL_STABLE:
-    return "STABLE";
-  case metrics::SystemProfileProto::CHANNEL_DEV:
-    return "DEV";
-  case metrics::SystemProfileProto::CHANNEL_BETA:
-    return "BETA";
-  case metrics::SystemProfileProto::CHANNEL_CANARY:
-    return "CANARY";
-  default:
-    return "UNKNOWN";
-  }
-}
-
-SystemProfileCache::SystemProfileCache()
-    : initialized_(false),
-      testing_(false),
-      metrics_directory_(metrics::kMetricsdDirectory),
-      session_id_(new chromeos_metrics::PersistentInteger(
-          kPersistentSessionIdFilename, metrics_directory_)) {}
-
-SystemProfileCache::SystemProfileCache(bool testing,
-                                       const base::FilePath& metrics_directory)
-    : initialized_(false),
-      testing_(testing),
-      metrics_directory_(metrics_directory),
-      session_id_(new chromeos_metrics::PersistentInteger(
-          kPersistentSessionIdFilename, metrics_directory)) {}
-
-bool SystemProfileCache::Initialize() {
-  CHECK(!initialized_)
-      << "this should be called only once in the metrics_daemon lifetime.";
-
-  brillo::OsReleaseReader reader;
-  std::string channel;
-  if (testing_) {
-    reader.LoadTestingOnly(metrics_directory_);
-    channel = "unknown";
-  } else {
-    reader.Load();
-    auto client = update_engine::UpdateEngineClient::CreateInstance();
-    if (!client) {
-      LOG(ERROR) << "failed to create the update engine client";
-      return false;
-    }
-    if (!client->GetChannel(&channel)) {
-      LOG(ERROR) << "failed to read the current channel from update engine.";
-      return false;
-    }
-  }
-
-  if (!reader.GetString(metrics::kProductId, &profile_.product_id)
-      || profile_.product_id.empty()) {
-    LOG(ERROR) << "product_id is not set.";
-    return false;
-  }
-
-  if (!reader.GetString(metrics::kProductVersion, &profile_.version)) {
-    LOG(ERROR) << "failed to read the product version";
-  }
-
-  if (channel.empty() || profile_.version.empty()) {
-    // If the channel or version is missing, the image is not official.
-    // In this case, set the channel to unknown and the version to 0.0.0.0 to
-    // avoid polluting the production data.
-    channel = "";
-    profile_.version = metrics::kDefaultVersion;
-  }
-  std::string guid_path = metrics_directory_.Append(
-      metrics::kMetricsGUIDFileName).value();
-  profile_.client_id = testing_ ?
-      "client_id_test" :
-      GetPersistentGUID(guid_path);
-  profile_.model_manifest_id = "unknown";
-  if (!testing_) {
-    brillo::KeyValueStore weave_config;
-    if (!weave_config.Load(base::FilePath(metrics::kWeaveConfigurationFile))) {
-      LOG(ERROR) << "Failed to load the weave configuration file.";
-    } else if (!weave_config.GetString(metrics::kModelManifestId,
-                                       &profile_.model_manifest_id)) {
-      LOG(ERROR) << "The model manifest id (model_id) is undefined in "
-                 << metrics::kWeaveConfigurationFile;
-    }
-  }
-
-  profile_.channel = ProtoChannelFromString(channel);
-
-  // Increment the session_id everytime we initialize this. If metrics_daemon
-  // does not crash, this should correspond to the number of reboots of the
-  // system.
-  session_id_->Add(1);
-  profile_.session_id = static_cast<int32_t>(session_id_->Get());
-
-  initialized_ = true;
-  return initialized_;
-}
-
-bool SystemProfileCache::InitializeOrCheck() {
-  return initialized_ || Initialize();
-}
-
-bool SystemProfileCache::Populate(
-    metrics::ChromeUserMetricsExtension* metrics_proto) {
-  CHECK(metrics_proto);
-  if (not InitializeOrCheck()) {
-    return false;
-  }
-
-  // The client id is hashed before being sent.
-  metrics_proto->set_client_id(
-      metrics::MetricsLogBase::Hash(profile_.client_id));
-  metrics_proto->set_session_id(profile_.session_id);
-
-  // Sets the product id.
-  metrics_proto->set_product(9);
-
-  metrics::SystemProfileProto* profile_proto =
-      metrics_proto->mutable_system_profile();
-  profile_proto->mutable_hardware()->set_hardware_class(
-      profile_.model_manifest_id);
-  profile_proto->set_app_version(profile_.version);
-  profile_proto->set_channel(profile_.channel);
-  metrics::SystemProfileProto_BrilloDeviceData* device_data =
-      profile_proto->mutable_brillo();
-  device_data->set_product_id(profile_.product_id);
-
-  return true;
-}
-
-std::string SystemProfileCache::GetPersistentGUID(
-    const std::string& filename) {
-  std::string guid;
-  base::FilePath filepath(filename);
-  if (!base::ReadFileToString(filepath, &guid)) {
-    guid = base::GenerateGUID();
-    // If we can't read or write the file, the guid will not be preserved during
-    // the next reboot. Crash.
-    CHECK(base::WriteFile(filepath, guid.c_str(), guid.size()));
-  }
-  return guid;
-}
-
-metrics::SystemProfileProto_Channel SystemProfileCache::ProtoChannelFromString(
-    const std::string& channel) {
-  if (channel == "stable-channel") {
-    return metrics::SystemProfileProto::CHANNEL_STABLE;
-  } else if (channel == "dev-channel") {
-    return metrics::SystemProfileProto::CHANNEL_DEV;
-  } else if (channel == "beta-channel") {
-    return metrics::SystemProfileProto::CHANNEL_BETA;
-  } else if (channel == "canary-channel") {
-    return metrics::SystemProfileProto::CHANNEL_CANARY;
-  }
-
-  DLOG(INFO) << "unknown channel: " << channel;
-  return metrics::SystemProfileProto::CHANNEL_UNKNOWN;
-}
diff --git a/metricsd/uploader/system_profile_cache.h b/metricsd/uploader/system_profile_cache.h
deleted file mode 100644
index f9c484c..0000000
--- a/metricsd/uploader/system_profile_cache.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICS_UPLOADER_SYSTEM_PROFILE_CACHE_H_
-#define METRICS_UPLOADER_SYSTEM_PROFILE_CACHE_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/files/file_path.h"
-#include "base/gtest_prod_util.h"
-#include "persistent_integer.h"
-#include "uploader/proto/system_profile.pb.h"
-#include "uploader/system_profile_setter.h"
-
-namespace metrics {
-class ChromeUserMetricsExtension;
-}
-
-struct SystemProfile {
-  std::string version;
-  std::string model_manifest_id;
-  std::string client_id;
-  int session_id;
-  metrics::SystemProfileProto::Channel channel;
-  std::string product_id;
-};
-
-// Retrieves general system informations needed by the protobuf for context and
-// remembers them to avoid expensive calls.
-//
-// The cache is populated lazily. The only method needed is Populate.
-class SystemProfileCache : public SystemProfileSetter {
- public:
-  SystemProfileCache();
-
-  SystemProfileCache(bool testing, const base::FilePath& metrics_directory);
-
-  // Populates the ProfileSystem protobuf with system information.
-  bool Populate(metrics::ChromeUserMetricsExtension* metrics_proto) override;
-
-  // Converts a string representation of the channel to a
-  // SystemProfileProto_Channel
-  static metrics::SystemProfileProto_Channel ProtoChannelFromString(
-      const std::string& channel);
-
-  // Gets the persistent GUID and create it if it has not been created yet.
-  static std::string GetPersistentGUID(const std::string& filename);
-
- private:
-  friend class UploadServiceTest;
-  FRIEND_TEST(UploadServiceTest, ExtractChannelFromDescription);
-  FRIEND_TEST(UploadServiceTest, ReadKeyValueFromFile);
-  FRIEND_TEST(UploadServiceTest, SessionIdIncrementedAtInitialization);
-  FRIEND_TEST(UploadServiceTest, ValuesInConfigFileAreSent);
-  FRIEND_TEST(UploadServiceTest, ProductIdMandatory);
-
-  // Fetches all informations and populates |profile_|
-  bool Initialize();
-
-  // Initializes |profile_| only if it has not been yet initialized.
-  bool InitializeOrCheck();
-
-  bool initialized_;
-  bool testing_;
-  base::FilePath metrics_directory_;
-  std::unique_ptr<chromeos_metrics::PersistentInteger> session_id_;
-  SystemProfile profile_;
-};
-
-#endif  // METRICS_UPLOADER_SYSTEM_PROFILE_CACHE_H_
diff --git a/metricsd/uploader/system_profile_setter.h b/metricsd/uploader/system_profile_setter.h
deleted file mode 100644
index bd3ff42..0000000
--- a/metricsd/uploader/system_profile_setter.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICS_UPLOADER_SYSTEM_PROFILE_SETTER_H_
-#define METRICS_UPLOADER_SYSTEM_PROFILE_SETTER_H_
-
-namespace metrics {
-class ChromeUserMetricsExtension;
-}
-
-// Abstract class used to delegate populating SystemProfileProto with system
-// information to simplify testing.
-class SystemProfileSetter {
- public:
-  virtual ~SystemProfileSetter() {}
-  // Populates the protobuf with system informations.
-  virtual bool Populate(metrics::ChromeUserMetricsExtension* profile_proto) = 0;
-};
-
-#endif  // METRICS_UPLOADER_SYSTEM_PROFILE_SETTER_H_
diff --git a/metricsd/uploader/upload_service.cc b/metricsd/uploader/upload_service.cc
deleted file mode 100644
index 0dc59a4..0000000
--- a/metricsd/uploader/upload_service.cc
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "uploader/upload_service.h"
-
-#include <sysexits.h>
-
-#include <memory>
-#include <string>
-
-#include <base/bind.h>
-#include <base/files/file_util.h>
-#include <base/logging.h>
-#include <base/memory/scoped_vector.h>
-#include <base/message_loop/message_loop.h>
-#include <base/metrics/histogram.h>
-#include <base/metrics/histogram_base.h>
-#include <base/metrics/histogram_snapshot_manager.h>
-#include <base/metrics/sparse_histogram.h>
-#include <base/metrics/statistics_recorder.h>
-#include <base/sha1.h>
-
-#include "constants.h"
-#include "uploader/metrics_log.h"
-#include "uploader/sender_http.h"
-#include "uploader/system_profile_setter.h"
-
-const int UploadService::kMaxFailedUpload = 10;
-
-UploadService::UploadService(const std::string& server,
-                             const base::TimeDelta& upload_interval,
-                             const base::TimeDelta& disk_persistence_interval,
-                             const base::FilePath& private_metrics_directory,
-                             const base::FilePath& shared_metrics_directory)
-    : brillo::Daemon(),
-      histogram_snapshot_manager_(this),
-      sender_(new HttpSender(server)),
-      failed_upload_count_(metrics::kFailedUploadCountName,
-                           private_metrics_directory),
-      counters_(new CrashCounters),
-      upload_interval_(upload_interval),
-      disk_persistence_interval_(disk_persistence_interval),
-      metricsd_service_runner_(counters_) {
-  staged_log_path_ = private_metrics_directory.Append(metrics::kStagedLogName);
-  saved_log_path_ = private_metrics_directory.Append(metrics::kSavedLogName);
-  consent_file_ = shared_metrics_directory.Append(metrics::kConsentFileName);
-}
-
-void UploadService::LoadSavedLog() {
-  if (base::PathExists(saved_log_path_)) {
-    GetOrCreateCurrentLog()->LoadFromFile(saved_log_path_);
-  }
-}
-
-int UploadService::OnInit() {
-  brillo::Daemon::OnInit();
-
-  base::StatisticsRecorder::Initialize();
-  metricsd_service_runner_.Start();
-
-  system_profile_setter_.reset(new SystemProfileCache());
-
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&UploadService::UploadEventCallback, base::Unretained(this)),
-      upload_interval_);
-
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&UploadService::PersistEventCallback, base::Unretained(this)),
-      disk_persistence_interval_);
-
-  LoadSavedLog();
-
-  return EX_OK;
-}
-
-void UploadService::OnShutdown(int* exit_code) {
-  metricsd_service_runner_.Stop();
-  PersistToDisk();
-}
-
-void UploadService::InitForTest(SystemProfileSetter* setter) {
-  LoadSavedLog();
-  system_profile_setter_.reset(setter);
-}
-
-void UploadService::StartNewLog() {
-  current_log_.reset(new MetricsLog());
-}
-
-void UploadService::UploadEventCallback() {
-  UploadEvent();
-
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&UploadService::UploadEventCallback, base::Unretained(this)),
-      upload_interval_);
-}
-
-void UploadService::PersistEventCallback() {
-  PersistToDisk();
-
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&UploadService::PersistEventCallback, base::Unretained(this)),
-      disk_persistence_interval_);
-}
-
-void UploadService::PersistToDisk() {
-  GatherHistograms();
-  if (current_log_) {
-    current_log_->SaveToFile(saved_log_path_);
-  }
-}
-
-void UploadService::UploadEvent() {
-  // If the system shutdown or crashed while uploading a report, we may not have
-  // deleted an old log.
-  RemoveFailedLog();
-
-  if (HasStagedLog()) {
-    // Previous upload failed, retry sending the logs.
-    SendStagedLog();
-    return;
-  }
-
-  // Previous upload successful, stage another log.
-  GatherHistograms();
-  StageCurrentLog();
-
-  // If a log is available for upload, upload it.
-  if (HasStagedLog()) {
-    SendStagedLog();
-  }
-}
-
-void UploadService::SendStagedLog() {
-  // If metrics are not enabled, discard the log and exit.
-  if (!AreMetricsEnabled()) {
-    LOG(INFO) << "Metrics disabled. Don't upload metrics samples.";
-    base::DeleteFile(staged_log_path_, false);
-    return;
-  }
-
-  std::string staged_log;
-  CHECK(base::ReadFileToString(staged_log_path_, &staged_log));
-
-  // Increase the failed count in case the daemon crashes while sending the log.
-  failed_upload_count_.Add(1);
-
-  if (!sender_->Send(staged_log, base::SHA1HashString(staged_log))) {
-    LOG(WARNING) << "log failed to upload";
-  } else {
-    VLOG(1) << "uploaded " << staged_log.length() << " bytes";
-    base::DeleteFile(staged_log_path_, false);
-  }
-
-  RemoveFailedLog();
-}
-
-void UploadService::Reset() {
-  base::DeleteFile(staged_log_path_, false);
-  current_log_.reset();
-  failed_upload_count_.Set(0);
-}
-
-void UploadService::GatherHistograms() {
-  base::StatisticsRecorder::Histograms histograms;
-  base::StatisticsRecorder::GetHistograms(&histograms);
-
-  histogram_snapshot_manager_.PrepareDeltas(
-      base::Histogram::kNoFlags, base::Histogram::kUmaTargetedHistogramFlag);
-
-  // Gather and reset the crash counters, shared with the binder threads.
-  unsigned int kernel_crashes = counters_->GetAndResetKernelCrashCount();
-  unsigned int unclean_shutdowns = counters_->GetAndResetUncleanShutdownCount();
-  unsigned int user_crashes = counters_->GetAndResetUserCrashCount();
-
-  // Only create a log if the counters have changed.
-  if (kernel_crashes > 0 || unclean_shutdowns > 0 || user_crashes > 0) {
-    GetOrCreateCurrentLog()->IncrementKernelCrashCount(kernel_crashes);
-    GetOrCreateCurrentLog()->IncrementUncleanShutdownCount(unclean_shutdowns);
-    GetOrCreateCurrentLog()->IncrementUserCrashCount(user_crashes);
-  }
-}
-
-void UploadService::RecordDelta(const base::HistogramBase& histogram,
-                                const base::HistogramSamples& snapshot) {
-  GetOrCreateCurrentLog()->RecordHistogramDelta(histogram.histogram_name(),
-                                                snapshot);
-}
-
-void UploadService::StageCurrentLog() {
-  // If we haven't logged anything since the last upload, don't upload an empty
-  // report.
-  if (!current_log_)
-    return;
-
-  std::unique_ptr<MetricsLog> staged_log;
-  staged_log.swap(current_log_);
-  staged_log->CloseLog();
-  if (!staged_log->PopulateSystemProfile(system_profile_setter_.get())) {
-    LOG(WARNING) << "Error while adding metadata to the log. Discarding the "
-                 << "log.";
-    return;
-  }
-
-  if (!base::DeleteFile(saved_log_path_, false)) {
-    // There is a chance that we will upload the same metrics twice but, if we
-    // are lucky, the backup should be overridden before that. In doubt, try not
-    // to lose any metrics.
-    LOG(ERROR) << "failed to delete the last backup of the current log.";
-  }
-
-  failed_upload_count_.Set(0);
-  staged_log->SaveToFile(staged_log_path_);
-}
-
-MetricsLog* UploadService::GetOrCreateCurrentLog() {
-  if (!current_log_) {
-    StartNewLog();
-  }
-  return current_log_.get();
-}
-
-bool UploadService::HasStagedLog() {
-  return base::PathExists(staged_log_path_);
-}
-
-void UploadService::RemoveFailedLog() {
-  if (failed_upload_count_.Get() > kMaxFailedUpload) {
-    LOG(INFO) << "log failed more than " << kMaxFailedUpload << " times.";
-    CHECK(base::DeleteFile(staged_log_path_, false))
-        << "failed to delete staged log at " << staged_log_path_.value();
-    failed_upload_count_.Set(0);
-  }
-}
-
-bool UploadService::AreMetricsEnabled() {
-  return base::PathExists(consent_file_);
-}
diff --git a/metricsd/uploader/upload_service.h b/metricsd/uploader/upload_service.h
deleted file mode 100644
index a1d9d3b..0000000
--- a/metricsd/uploader/upload_service.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICS_UPLOADER_UPLOAD_SERVICE_H_
-#define METRICS_UPLOADER_UPLOAD_SERVICE_H_
-
-#include <memory>
-#include <string>
-
-#include <base/metrics/histogram_base.h>
-#include <base/metrics/histogram_flattener.h>
-#include <base/metrics/histogram_snapshot_manager.h>
-#include <brillo/daemons/daemon.h>
-
-#include "persistent_integer.h"
-#include "uploader/crash_counters.h"
-#include "uploader/metrics_log.h"
-#include "uploader/metricsd_service_runner.h"
-#include "uploader/proto/chrome_user_metrics_extension.pb.h"
-#include "uploader/sender.h"
-#include "uploader/system_profile_cache.h"
-
-class SystemProfileSetter;
-
-// Service responsible for backing up the currently aggregated metrics to disk
-// and uploading them periodically to the server.
-//
-// A given metrics sample can be in one of three locations.
-// * in-memory metrics: in memory aggregated metrics, waiting to be staged for
-//   upload.
-// * saved log: protobuf message, written to disk periodically and on shutdown
-//   to make a backup of metrics data for uploading later.
-// * staged log: protobuf message waiting to be uploaded.
-//
-// The service works as follows:
-// On startup, we create the in-memory metrics from the saved log if it exists.
-//
-// Periodically (every |disk_persistence_interval_| seconds), we take a snapshot
-// of the in-memory metrics and save them to disk.
-//
-// Periodically (every |upload_interval| seconds), we:
-// * take a snapshot of the in-memory metrics and create the staged log
-// * save the staged log to disk to avoid losing it if metricsd or the system
-//   crashes between two uploads.
-// * delete the last saved log: all the metrics contained in it are also in the
-//   newly created staged log.
-//
-// On shutdown (SIGINT or SIGTERM), we save the in-memory metrics to disk.
-//
-// Note: the in-memory metrics can be stored in |current_log_| or
-// base::StatisticsRecorder.
-class UploadService : public base::HistogramFlattener, public brillo::Daemon {
- public:
-  UploadService(const std::string& server,
-                const base::TimeDelta& upload_interval,
-                const base::TimeDelta& disk_persistence_interval,
-                const base::FilePath& private_metrics_directory,
-                const base::FilePath& shared_metrics_directory);
-
-  // Initializes the upload service.
-  int OnInit() override;
-
-  // Cleans up the internal state before exiting.
-  void OnShutdown(int* exit_code) override;
-
-  // Starts a new log. The log needs to be regenerated after each successful
-  // launch as it is destroyed when staging the log.
-  void StartNewLog();
-
-  // Saves the current metrics to a file.
-  void PersistToDisk();
-
-  // Triggers an upload event.
-  void UploadEvent();
-
-  // Sends the staged log.
-  void SendStagedLog();
-
-  // Implements inconsistency detection to match HistogramFlattener's
-  // interface.
-  void InconsistencyDetected(
-      base::HistogramBase::Inconsistency problem) override {}
-  void UniqueInconsistencyDetected(
-      base::HistogramBase::Inconsistency problem) override {}
-  void InconsistencyDetectedInLoggedCount(int amount) override {}
-
- private:
-  friend class UploadServiceTest;
-
-  FRIEND_TEST(UploadServiceTest, CanSendMultipleTimes);
-  FRIEND_TEST(UploadServiceTest, CorruptedSavedLog);
-  FRIEND_TEST(UploadServiceTest, CurrentLogSavedAndResumed);
-  FRIEND_TEST(UploadServiceTest, DiscardLogsAfterTooManyFailedUpload);
-  FRIEND_TEST(UploadServiceTest, EmptyLogsAreNotSent);
-  FRIEND_TEST(UploadServiceTest, FailedSendAreRetried);
-  FRIEND_TEST(UploadServiceTest, LogContainsAggregatedValues);
-  FRIEND_TEST(UploadServiceTest, LogContainsCrashCounts);
-  FRIEND_TEST(UploadServiceTest, LogEmptyAfterUpload);
-  FRIEND_TEST(UploadServiceTest, LogEmptyByDefault);
-  FRIEND_TEST(UploadServiceTest, LogFromTheMetricsLibrary);
-  FRIEND_TEST(UploadServiceTest, LogKernelCrash);
-  FRIEND_TEST(UploadServiceTest, LogUncleanShutdown);
-  FRIEND_TEST(UploadServiceTest, LogUserCrash);
-  FRIEND_TEST(UploadServiceTest, PersistEmptyLog);
-  FRIEND_TEST(UploadServiceTest, UnknownCrashIgnored);
-  FRIEND_TEST(UploadServiceTest, ValuesInConfigFileAreSent);
-
-  // Initializes the upload service for testing.
-  void InitForTest(SystemProfileSetter* setter);
-
-  // If a staged log fails to upload more than kMaxFailedUpload times, it
-  // will be discarded.
-  static const int kMaxFailedUpload;
-
-  // Loads the log saved to disk if it exists.
-  void LoadSavedLog();
-
-  // Resets the internal state.
-  void Reset();
-
-  // Returns true iff metrics reporting is enabled.
-  bool AreMetricsEnabled();
-
-  // Event callback for handling Upload events.
-  void UploadEventCallback();
-
-  // Event callback for handling Persist events.
-  void PersistEventCallback();
-
-  // Aggregates all histogram available in memory and store them in the current
-  // log.
-  void GatherHistograms();
-
-  // Callback for HistogramSnapshotManager to store the histograms.
-  void RecordDelta(const base::HistogramBase& histogram,
-                   const base::HistogramSamples& snapshot) override;
-
-  // Compiles all the samples received into a single protobuf and adds all
-  // system information.
-  void StageCurrentLog();
-
-  // Returns true iff a log is staged.
-  bool HasStagedLog();
-
-  // Remove the staged log iff the upload failed more than |kMaxFailedUpload|.
-  void RemoveFailedLog();
-
-  // Returns the current log. If there is no current log, creates it first.
-  MetricsLog* GetOrCreateCurrentLog();
-
-  std::unique_ptr<SystemProfileSetter> system_profile_setter_;
-  base::HistogramSnapshotManager histogram_snapshot_manager_;
-  std::unique_ptr<Sender> sender_;
-  chromeos_metrics::PersistentInteger failed_upload_count_;
-  std::unique_ptr<MetricsLog> current_log_;
-  std::shared_ptr<CrashCounters> counters_;
-
-  base::TimeDelta upload_interval_;
-  base::TimeDelta disk_persistence_interval_;
-
-  MetricsdServiceRunner metricsd_service_runner_;
-
-  base::FilePath consent_file_;
-  base::FilePath staged_log_path_;
-  base::FilePath saved_log_path_;
-
-  bool testing_;
-};
-
-#endif  // METRICS_UPLOADER_UPLOAD_SERVICE_H_
diff --git a/metricsd/uploader/upload_service_test.cc b/metricsd/uploader/upload_service_test.cc
deleted file mode 100644
index 70112f4..0000000
--- a/metricsd/uploader/upload_service_test.cc
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <memory>
-
-#include <base/at_exit.h>
-#include <base/files/file_util.h>
-#include <base/files/scoped_temp_dir.h>
-#include <base/logging.h>
-#include <base/metrics/sparse_histogram.h>
-#include <base/metrics/statistics_recorder.h>
-#include <base/sys_info.h>
-#include <gtest/gtest.h>
-
-#include "constants.h"
-#include "persistent_integer.h"
-#include "uploader/metrics_log.h"
-#include "uploader/mock/mock_system_profile_setter.h"
-#include "uploader/mock/sender_mock.h"
-#include "uploader/proto/chrome_user_metrics_extension.pb.h"
-#include "uploader/proto/histogram_event.pb.h"
-#include "uploader/proto/system_profile.pb.h"
-#include "uploader/system_profile_cache.h"
-#include "uploader/upload_service.h"
-
-class UploadServiceTest : public testing::Test {
- protected:
-  virtual void SetUp() {
-    CHECK(dir_.CreateUniqueTempDir());
-    // Make sure the statistics recorder is inactive (contains no metrics) then
-    // initialize it.
-    ASSERT_FALSE(base::StatisticsRecorder::IsActive());
-    base::StatisticsRecorder::Initialize();
-
-    private_dir_ = dir_.path().Append("private");
-    shared_dir_ = dir_.path().Append("shared");
-
-    EXPECT_TRUE(base::CreateDirectory(private_dir_));
-    EXPECT_TRUE(base::CreateDirectory(shared_dir_));
-
-    ASSERT_EQ(0, base::WriteFile(shared_dir_.Append(metrics::kConsentFileName),
-                                 "", 0));
-
-    upload_service_.reset(new UploadService(
-        "", base::TimeDelta(), base::TimeDelta(), private_dir_, shared_dir_));
-    counters_ = upload_service_->counters_;
-
-    upload_service_->sender_.reset(new SenderMock);
-    upload_service_->InitForTest(new MockSystemProfileSetter);
-    upload_service_->GatherHistograms();
-    upload_service_->Reset();
-  }
-
-  void SendSparseHistogram(const std::string& name, int sample) {
-    base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
-        name, base::Histogram::kUmaTargetedHistogramFlag);
-    histogram->Add(sample);
-  }
-
-  void SendHistogram(
-      const std::string& name, int sample, int min, int max, int nbuckets) {
-    base::HistogramBase* histogram = base::Histogram::FactoryGet(
-        name, min, max, nbuckets, base::Histogram::kUmaTargetedHistogramFlag);
-    histogram->Add(sample);
-  }
-
-  void SetTestingProperty(const std::string& name, const std::string& value) {
-    base::FilePath filepath =
-        dir_.path().Append("etc/os-release.d").Append(name);
-    ASSERT_TRUE(base::CreateDirectory(filepath.DirName()));
-    ASSERT_EQ(value.size(),
-              base::WriteFile(filepath, value.data(), value.size()));
-  }
-
-  const metrics::SystemProfileProto_Stability GetCurrentStability() {
-    EXPECT_TRUE(upload_service_->current_log_.get());
-
-    return upload_service_->current_log_->uma_proto()
-        ->system_profile()
-        .stability();
-  }
-
-  base::ScopedTempDir dir_;
-  std::unique_ptr<UploadService> upload_service_;
-
-  std::unique_ptr<base::AtExitManager> exit_manager_;
-  std::shared_ptr<CrashCounters> counters_;
-  base::FilePath private_dir_;
-  base::FilePath shared_dir_;
-};
-
-TEST_F(UploadServiceTest, FailedSendAreRetried) {
-  SenderMock* sender = new SenderMock();
-  upload_service_->sender_.reset(sender);
-
-  sender->set_should_succeed(false);
-
-  SendSparseHistogram("hello", 1);
-  upload_service_->UploadEvent();
-  EXPECT_EQ(1, sender->send_call_count());
-  std::string sent_string = sender->last_message();
-
-  upload_service_->UploadEvent();
-  EXPECT_EQ(2, sender->send_call_count());
-  EXPECT_EQ(sent_string, sender->last_message());
-}
-
-TEST_F(UploadServiceTest, DiscardLogsAfterTooManyFailedUpload) {
-  SenderMock* sender = new SenderMock();
-  upload_service_->sender_.reset(sender);
-
-  sender->set_should_succeed(false);
-
-  SendSparseHistogram("hello", 1);
-
-  for (int i = 0; i < UploadService::kMaxFailedUpload; i++) {
-    upload_service_->UploadEvent();
-  }
-
-  EXPECT_TRUE(upload_service_->HasStagedLog());
-  upload_service_->UploadEvent();
-  EXPECT_FALSE(upload_service_->HasStagedLog());
-
-  // Log a new sample. The failed upload counter should be reset.
-  SendSparseHistogram("hello", 1);
-  for (int i = 0; i < UploadService::kMaxFailedUpload; i++) {
-    upload_service_->UploadEvent();
-  }
-  // The log is not discarded after multiple failed uploads.
-  EXPECT_TRUE(upload_service_->HasStagedLog());
-}
-
-TEST_F(UploadServiceTest, EmptyLogsAreNotSent) {
-  SenderMock* sender = new SenderMock();
-  upload_service_->sender_.reset(sender);
-  upload_service_->UploadEvent();
-  EXPECT_FALSE(upload_service_->current_log_);
-  EXPECT_EQ(0, sender->send_call_count());
-}
-
-TEST_F(UploadServiceTest, LogEmptyByDefault) {
-  // current_log_ should be initialized later as it needs AtExitManager to exist
-  // in order to gather system information from SysInfo.
-  EXPECT_FALSE(upload_service_->current_log_);
-}
-
-TEST_F(UploadServiceTest, CanSendMultipleTimes) {
-  SenderMock* sender = new SenderMock();
-  upload_service_->sender_.reset(sender);
-
-  SendSparseHistogram("hello", 1);
-
-  upload_service_->UploadEvent();
-
-  std::string first_message = sender->last_message();
-  SendSparseHistogram("hello", 2);
-
-  upload_service_->UploadEvent();
-
-  EXPECT_NE(first_message, sender->last_message());
-}
-
-TEST_F(UploadServiceTest, LogEmptyAfterUpload) {
-  SendSparseHistogram("hello", 2);
-
-  upload_service_->UploadEvent();
-  EXPECT_FALSE(upload_service_->current_log_);
-}
-
-TEST_F(UploadServiceTest, LogContainsAggregatedValues) {
-  SendHistogram("foo", 11, 0, 42, 10);
-  SendHistogram("foo", 12, 0, 42, 10);
-
-  upload_service_->GatherHistograms();
-  metrics::ChromeUserMetricsExtension* proto =
-      upload_service_->current_log_->uma_proto();
-  EXPECT_EQ(1, proto->histogram_event().size());
-}
-
-TEST_F(UploadServiceTest, LogContainsCrashCounts) {
-  // By default, there is no current log.
-  upload_service_->GatherHistograms();
-  EXPECT_FALSE(upload_service_->current_log_);
-
-  // If the user crash counter is incremented, we add the count to the current
-  // log.
-  counters_->IncrementUserCrashCount();
-  upload_service_->GatherHistograms();
-  EXPECT_EQ(1, GetCurrentStability().other_user_crash_count());
-
-  // If the kernel crash counter is incremented, we add the count to the current
-  // log.
-  counters_->IncrementKernelCrashCount();
-  upload_service_->GatherHistograms();
-  EXPECT_EQ(1, GetCurrentStability().kernel_crash_count());
-
-  // If the kernel crash counter is incremented, we add the count to the current
-  // log.
-  counters_->IncrementUncleanShutdownCount();
-  counters_->IncrementUncleanShutdownCount();
-  upload_service_->GatherHistograms();
-  EXPECT_EQ(2, GetCurrentStability().unclean_system_shutdown_count());
-
-  // If no counter is incremented, the reported numbers don't change.
-  upload_service_->GatherHistograms();
-  EXPECT_EQ(1, GetCurrentStability().other_user_crash_count());
-  EXPECT_EQ(1, GetCurrentStability().kernel_crash_count());
-  EXPECT_EQ(2, GetCurrentStability().unclean_system_shutdown_count());
-}
-
-TEST_F(UploadServiceTest, ExtractChannelFromString) {
-  EXPECT_EQ(SystemProfileCache::ProtoChannelFromString("developer-build"),
-            metrics::SystemProfileProto::CHANNEL_UNKNOWN);
-
-  EXPECT_EQ(metrics::SystemProfileProto::CHANNEL_DEV,
-            SystemProfileCache::ProtoChannelFromString("dev-channel"));
-
-  EXPECT_EQ(metrics::SystemProfileProto::CHANNEL_STABLE,
-            SystemProfileCache::ProtoChannelFromString("stable-channel"));
-
-  EXPECT_EQ(metrics::SystemProfileProto::CHANNEL_UNKNOWN,
-            SystemProfileCache::ProtoChannelFromString("this is a test"));
-}
-
-TEST_F(UploadServiceTest, ValuesInConfigFileAreSent) {
-  SenderMock* sender = new SenderMock();
-  upload_service_->sender_.reset(sender);
-
-  SetTestingProperty(metrics::kProductId, "hello");
-  SetTestingProperty(metrics::kProductVersion, "1.2.3.4");
-
-  SendSparseHistogram("hello", 1);
-
-  // Reset to create the new log with the profile setter.
-  upload_service_->system_profile_setter_.reset(
-      new SystemProfileCache(true, dir_.path()));
-  upload_service_->Reset();
-  upload_service_->UploadEvent();
-
-  EXPECT_EQ(1, sender->send_call_count());
-  EXPECT_TRUE(sender->is_good_proto());
-  EXPECT_EQ(1, sender->last_message_proto().histogram_event().size());
-
-  EXPECT_NE(0, sender->last_message_proto().client_id());
-  EXPECT_NE(0, sender->last_message_proto().system_profile().build_timestamp());
-  EXPECT_NE(0, sender->last_message_proto().session_id());
-}
-
-TEST_F(UploadServiceTest, PersistentGUID) {
-  std::string tmp_file = dir_.path().Append("tmpfile").value();
-
-  std::string first_guid = SystemProfileCache::GetPersistentGUID(tmp_file);
-  std::string second_guid = SystemProfileCache::GetPersistentGUID(tmp_file);
-
-  // The GUID are cached.
-  EXPECT_EQ(first_guid, second_guid);
-
-  base::DeleteFile(base::FilePath(tmp_file), false);
-
-  first_guid = SystemProfileCache::GetPersistentGUID(tmp_file);
-  base::DeleteFile(base::FilePath(tmp_file), false);
-  second_guid = SystemProfileCache::GetPersistentGUID(tmp_file);
-
-  // Random GUIDs are generated (not all the same).
-  EXPECT_NE(first_guid, second_guid);
-}
-
-TEST_F(UploadServiceTest, SessionIdIncrementedAtInitialization) {
-  SetTestingProperty(metrics::kProductId, "hello");
-  SystemProfileCache cache(true, dir_.path());
-  cache.Initialize();
-  int session_id = cache.profile_.session_id;
-  cache.initialized_ = false;
-  cache.Initialize();
-  EXPECT_EQ(cache.profile_.session_id, session_id + 1);
-}
-
-// The product id must be set for metrics to be uploaded.
-// If it is not set, the system profile cache should fail to initialize.
-TEST_F(UploadServiceTest, ProductIdMandatory) {
-  SystemProfileCache cache(true, dir_.path());
-  ASSERT_FALSE(cache.Initialize());
-  SetTestingProperty(metrics::kProductId, "");
-  ASSERT_FALSE(cache.Initialize());
-  SetTestingProperty(metrics::kProductId, "hello");
-  ASSERT_TRUE(cache.Initialize());
-}
-
-TEST_F(UploadServiceTest, CurrentLogSavedAndResumed) {
-  SendHistogram("hello", 10, 0, 100, 10);
-  upload_service_->PersistToDisk();
-  EXPECT_EQ(
-      1, upload_service_->current_log_->uma_proto()->histogram_event().size());
-  upload_service_.reset(new UploadService(
-      "", base::TimeDelta(), base::TimeDelta(), private_dir_, shared_dir_));
-  upload_service_->InitForTest(nullptr);
-
-  SendHistogram("hello", 10, 0, 100, 10);
-  upload_service_->GatherHistograms();
-  EXPECT_EQ(2, upload_service_->GetOrCreateCurrentLog()
-                   ->uma_proto()
-                   ->histogram_event()
-                   .size());
-}
-
-TEST_F(UploadServiceTest, PersistEmptyLog) {
-  upload_service_->PersistToDisk();
-  EXPECT_FALSE(base::PathExists(upload_service_->saved_log_path_));
-}
-
-TEST_F(UploadServiceTest, CorruptedSavedLog) {
-  // Write a bogus saved log.
-  EXPECT_EQ(5, base::WriteFile(upload_service_->saved_log_path_, "hello", 5));
-
-  upload_service_.reset(new UploadService(
-      "", base::TimeDelta(), base::TimeDelta(), private_dir_, shared_dir_));
-
-  upload_service_->InitForTest(nullptr);
-  // If the log is unreadable, we drop it and continue execution.
-  ASSERT_NE(nullptr, upload_service_->GetOrCreateCurrentLog());
-  ASSERT_FALSE(base::PathExists(upload_service_->saved_log_path_));
-}
diff --git a/reboot/Android.bp b/reboot/Android.bp
new file mode 100644
index 0000000..805fd9a
--- /dev/null
+++ b/reboot/Android.bp
@@ -0,0 +1,8 @@
+// Copyright 2013 The Android Open Source Project
+
+cc_binary {
+    name: "reboot",
+    srcs: ["reboot.c"],
+    shared_libs: ["libcutils"],
+    cflags: ["-Werror"],
+}
diff --git a/reboot/Android.mk b/reboot/Android.mk
deleted file mode 100644
index 7a24f99..0000000
--- a/reboot/Android.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright 2013 The Android Open Source Project
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := reboot.c
-
-LOCAL_SHARED_LIBRARIES := libcutils
-
-LOCAL_MODULE := reboot
-
-LOCAL_CFLAGS := -Werror
-
-include $(BUILD_EXECUTABLE)
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index aa5a520..7d0c87d 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -123,6 +123,7 @@
 LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
     sbin dev proc sys system data oem acct config storage mnt root $(BOARD_ROOT_EXTRA_FOLDERS)); \
     ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
+    ln -sf /data/user_de/0/com.android.shell/files/bugreports $(TARGET_ROOT_OUT)/bugreports; \
     ln -sf /sys/kernel/debug $(TARGET_ROOT_OUT)/d; \
     ln -sf /storage/self/primary $(TARGET_ROOT_OUT)/sdcard
 ifdef BOARD_USES_VENDORIMAGE
diff --git a/rootdir/init-debug.rc b/rootdir/init-debug.rc
index 435d4cb..44d34d8 100644
--- a/rootdir/init-debug.rc
+++ b/rootdir/init-debug.rc
@@ -6,3 +6,6 @@
 
 on property:persist.mmc.cache_size=*
     write /sys/block/mmcblk0/cache_size ${persist.mmc.cache_size}
+
+on early-init
+    mount debugfs debugfs /sys/kernel/debug
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a9b6af0..8903255 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -294,7 +294,6 @@
     trigger early-boot
     trigger boot
 
-
 on post-fs
     start logd
     # once everything is setup, no need to modify /
@@ -305,7 +304,8 @@
     mount none /mnt/runtime/default /storage slave bind rec
 
     # Make sure /sys/kernel/debug (if present) is labeled properly
-    restorecon_recursive /sys/kernel/debug
+    # Note that tracefs may be mounted under debug, so we need to cross filesystems
+    restorecon --recursive --cross-filesystems /sys/kernel/debug
 
     # We chown/chmod /cache again so because mount is run as root + defaults
     chown system cache /cache
@@ -367,11 +367,12 @@
 
     # create basic filesystem structure
     mkdir /data/misc 01771 system misc
-    mkdir /data/misc/bluedroid 02770 bluetooth net_bt_stack
+    mkdir /data/misc/bluedroid 02770 bluetooth bluetooth
     # Fix the access permissions and group ownership for 'bt_config.conf'
     chmod 0660 /data/misc/bluedroid/bt_config.conf
-    chown bluetooth net_bt_stack /data/misc/bluedroid/bt_config.conf
-    mkdir /data/misc/bluetooth 0770 system system
+    chown bluetooth bluetooth /data/misc/bluedroid/bt_config.conf
+    mkdir /data/misc/bluetooth 0770 bluetooth bluetooth
+    mkdir /data/misc/bluetooth/logs 0770 bluetooth bluetooth
     mkdir /data/misc/keystore 0700 keystore keystore
     mkdir /data/misc/gatekeeper 0700 system system
     mkdir /data/misc/keychain 0771 system system
@@ -444,13 +445,6 @@
 
     mkdir /data/anr 0775 system system
 
-    # symlink to bugreport storage location
-    rm /data/bugreports
-    symlink /data/user_de/0/com.android.shell/files/bugreports /data/bugreports
-
-    # Separate location for storing security policy files on data
-    mkdir /data/security 0711 system system
-
     # Create all remaining /data root dirs so that they are made through init
     # and get proper encryption policy installed
     mkdir /data/backup 0700 system system
@@ -480,11 +474,8 @@
 
     init_user0
 
-    # Reload policy from /data/security if present.
-    setprop selinux.reload_policy 1
-
     # Set SELinux security contexts on upgrade or policy update.
-    restorecon_recursive /data
+    restorecon --recursive --skip-ce /data
 
     # Check any timezone data in /data is newer than the copy in /system, delete if not.
     exec - system system -- /system/bin/tzdatacheck /system/usr/share/zoneinfo /data/misc/zoneinfo
@@ -582,6 +573,8 @@
     # Define default initial receive window size in segments.
     setprop net.tcp.default_init_rwnd 60
 
+    # Start all binderized HAL daemons
+    start hwservicemanager
     class_start core
 
 on nonencrypted
diff --git a/rootdir/init.usb.configfs.rc b/rootdir/init.usb.configfs.rc
index 186384b..dc875b4 100644
--- a/rootdir/init.usb.configfs.rc
+++ b/rootdir/init.usb.configfs.rc
@@ -1,9 +1,14 @@
 on property:sys.usb.config=none && property:sys.usb.configfs=1
     write /config/usb_gadget/g1/UDC "none"
     stop adbd
+    setprop sys.usb.ffs.ready 0
     write /config/usb_gadget/g1/bDeviceClass 0
     write /config/usb_gadget/g1/bDeviceSubClass 0
     write /config/usb_gadget/g1/bDeviceProtocol 0
+    rm /config/usb_gadget/g1/configs/b.1/f1
+    rm /config/usb_gadget/g1/configs/b.1/f2
+    rm /config/usb_gadget/g1/configs/b.1/f3
+    rmdir /config/usb_gadget/g1/functions/rndis.gs4
     setprop sys.usb.state ${sys.usb.config}
 
 on property:sys.usb.config=adb && property:sys.usb.configfs=1
@@ -11,18 +16,12 @@
 
 on property:sys.usb.ffs.ready=1 && property:sys.usb.config=adb && property:sys.usb.configfs=1
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "adb"
-    rm /config/usb_gadget/g1/configs/b.1/f1
-    rm /config/usb_gadget/g1/configs/b.1/f2
-    rm /config/usb_gadget/g1/configs/b.1/f3
     symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f1
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
     setprop sys.usb.state ${sys.usb.config}
 
 on property:sys.usb.config=mtp && property:sys.usb.configfs=1
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "mtp"
-    rm /config/usb_gadget/g1/configs/b.1/f1
-    rm /config/usb_gadget/g1/configs/b.1/f2
-    rm /config/usb_gadget/g1/configs/b.1/f3
     symlink /config/usb_gadget/g1/functions/mtp.gs0 /config/usb_gadget/g1/configs/b.1/f1
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
     setprop sys.usb.state ${sys.usb.config}
@@ -32,9 +31,6 @@
 
 on property:sys.usb.ffs.ready=1 && property:sys.usb.config=mtp,adb && property:sys.usb.configfs=1
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "mtp_adb"
-    rm /config/usb_gadget/g1/configs/b.1/f1
-    rm /config/usb_gadget/g1/configs/b.1/f2
-    rm /config/usb_gadget/g1/configs/b.1/f3
     symlink /config/usb_gadget/g1/functions/mtp.gs0 /config/usb_gadget/g1/configs/b.1/f1
     symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
@@ -42,9 +38,6 @@
 
 on property:sys.usb.config=ptp && property:sys.usb.configfs=1
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "ptp"
-    rm /config/usb_gadget/g1/configs/b.1/f1
-    rm /config/usb_gadget/g1/configs/b.1/f2
-    rm /config/usb_gadget/g1/configs/b.1/f3
     symlink /config/usb_gadget/g1/functions/ptp.gs1 /config/usb_gadget/g1/configs/b.1/f1
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
     setprop sys.usb.state ${sys.usb.config}
@@ -54,9 +47,6 @@
 
 on property:sys.usb.ffs.ready=1 && property:sys.usb.config=ptp,adb && property:sys.usb.configfs=1
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "ptp_adb"
-    rm /config/usb_gadget/g1/configs/b.1/f1
-    rm /config/usb_gadget/g1/configs/b.1/f2
-    rm /config/usb_gadget/g1/configs/b.1/f3
     symlink /config/usb_gadget/g1/functions/ptp.gs1 /config/usb_gadget/g1/configs/b.1/f1
     symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
@@ -64,9 +54,6 @@
 
 on property:sys.usb.config=accessory && property:sys.usb.configfs=1
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "accessory"
-    rm /config/usb_gadget/g1/configs/b.1/f1
-    rm /config/usb_gadget/g1/configs/b.1/f2
-    rm /config/usb_gadget/g1/configs/b.1/f3
     symlink /config/usb_gadget/g1/functions/accessory.gs2 /config/usb_gadget/g1/configs/b.1/f1
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
     setprop sys.usb.state ${sys.usb.config}
@@ -76,9 +63,6 @@
 
 on property:sys.usb.ffs.ready=1 && property:sys.usb.config=accessory,adb && property:sys.usb.configfs=1
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "accessory_adb"
-    rm /config/usb_gadget/g1/configs/b.1/f1
-    rm /config/usb_gadget/g1/configs/b.1/f2
-    rm /config/usb_gadget/g1/configs/b.1/f3
     symlink /config/usb_gadget/g1/functions/accessory.gs2 /config/usb_gadget/g1/configs/b.1/f1
     symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
@@ -86,9 +70,6 @@
 
 on property:sys.usb.config=audio_source && property:sys.usb.configfs=1
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "audiosource"
-    rm /config/usb_gadget/g1/configs/b.1/f1
-    rm /config/usb_gadget/g1/configs/b.1/f2
-    rm /config/usb_gadget/g1/configs/b.1/f3
     symlink /config/usb_gadget/g1/functions/audio_source.gs2 /config/usb_gadget/g1/configs/b.1/f1
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
     setprop sys.usb.state ${sys.usb.config}
@@ -98,9 +79,6 @@
 
 on property:sys.usb.ffs.ready=1 && property:sys.usb.config=audio_source,adb && property:sys.usb.configfs=1
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "audiosource_adb"
-    rm /config/usb_gadget/g1/configs/b.1/f1
-    rm /config/usb_gadget/g1/configs/b.1/f2
-    rm /config/usb_gadget/g1/configs/b.1/f3
     symlink /config/usb_gadget/g1/functions/audio_source.gs2 /config/usb_gadget/g1/configs/b.1/f1
     symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
@@ -108,9 +86,6 @@
 
 on property:sys.usb.config=accessory,audio_source && property:sys.usb.configfs=1
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "accessory_audiosource"
-    rm /config/usb_gadget/g1/configs/b.1/f1
-    rm /config/usb_gadget/g1/configs/b.1/f2
-    rm /config/usb_gadget/g1/configs/b.1/f3
     symlink /config/usb_gadget/g1/functions/accessory.gs2 /config/usb_gadget/g1/configs/b.1/f1
     symlink /config/usb_gadget/g1/functions/audio_source.gs3 /config/usb_gadget/g1/configs/b.1/f2
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
@@ -121,9 +96,6 @@
 
 on property:sys.usb.ffs.ready=1 && property:sys.usb.config=accessory,audio_source,adb && property:sys.usb.configfs=1
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "accessory_audiosource_adb"
-    rm /config/usb_gadget/g1/configs/b.1/f1
-    rm /config/usb_gadget/g1/configs/b.1/f2
-    rm /config/usb_gadget/g1/configs/b.1/f3
     symlink /config/usb_gadget/g1/functions/accessory.gs2 /config/usb_gadget/g1/configs/b.1/f1
     symlink /config/usb_gadget/g1/functions/audio_source.gs3 /config/usb_gadget/g1/configs/b.1/f2
     symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f3
@@ -132,9 +104,6 @@
 
 on property:sys.usb.config=midi && property:sys.usb.configfs=1
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "midi"
-    rm /config/usb_gadget/g1/configs/b.1/f1
-    rm /config/usb_gadget/g1/configs/b.1/f2
-    rm /config/usb_gadget/g1/configs/b.1/f3
     symlink /config/usb_gadget/g1/functions/midi.gs5 /config/usb_gadget/g1/configs/b.1/f1
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
     setprop sys.usb.state ${sys.usb.config}
@@ -144,19 +113,14 @@
 
 on property:sys.usb.ffs.ready=1 && property:sys.usb.config=midi,adb && property:sys.usb.configfs=1
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "midi_adb"
-    rm /config/usb_gadget/g1/configs/b.1/f1
-    rm /config/usb_gadget/g1/configs/b.1/f2
-    rm /config/usb_gadget/g1/configs/b.1/f3
     symlink /config/usb_gadget/g1/functions/midi.gs5 /config/usb_gadget/g1/configs/b.1/f1
     symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
     setprop sys.usb.state ${sys.usb.config}
 
 on property:sys.usb.config=rndis && property:sys.usb.configfs=1
+    mkdir /config/usb_gadget/g1/functions/rndis.gs4
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "rndis"
-    rm /config/usb_gadget/g1/configs/b.1/f1
-    rm /config/usb_gadget/g1/configs/b.1/f2
-    rm /config/usb_gadget/g1/configs/b.1/f3
     symlink /config/usb_gadget/g1/functions/rndis.gs4 /config/usb_gadget/g1/configs/b.1/f1
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
     setprop sys.usb.state ${sys.usb.config}
@@ -165,10 +129,8 @@
     start adbd
 
 on property:sys.usb.ffs.ready=1 && property:sys.usb.config=rndis,adb && property:sys.usb.configfs=1
+    mkdir /config/usb_gadget/g1/functions/rndis.gs4
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "rndis_adb"
-    rm /config/usb_gadget/g1/configs/b.1/f1
-    rm /config/usb_gadget/g1/configs/b.1/f2
-    rm /config/usb_gadget/g1/configs/b.1/f3
     symlink /config/usb_gadget/g1/functions/rndis.gs4 /config/usb_gadget/g1/configs/b.1/f1
     symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index b41af92..eedeba8 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -1,5 +1,8 @@
 service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
     class main
+    priority -20
+    user root
+    group root readproc
     socket zygote stream 660 root system
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index 2914f07..84a907f 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -1,5 +1,8 @@
 service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
     class main
+    priority -20
+    user root
+    group root readproc
     socket zygote stream 660 root system
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
@@ -7,10 +10,13 @@
     onrestart restart cameraserver
     onrestart restart media
     onrestart restart netd
-    writepid /dev/cpuset/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
 
 service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
     class main
+    priority -20
+    user root
+    group root readproc
     socket zygote_secondary stream 660 root system
     onrestart restart zygote
     writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index 2cc0966..76e2b79 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -1,5 +1,8 @@
 service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
     class main
+    priority -20
+    user root
+    group root readproc
     socket zygote stream 660 root system
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index a422fcc..e918b67 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -1,5 +1,8 @@
 service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
     class main
+    priority -20
+    user root
+    group root readproc
     socket zygote stream 660 root system
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
@@ -7,10 +10,13 @@
     onrestart restart cameraserver
     onrestart restart media
     onrestart restart netd
-    writepid /dev/cpuset/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
 
 service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
     class main
+    priority -20
+    user root
+    group root readproc
     socket zygote_secondary stream 660 root system
     onrestart restart zygote
     writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 6ef491c..8725113 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -19,6 +19,7 @@
 /dev/hw_random            0440   root       system
 /dev/ashmem               0666   root       root
 /dev/binder               0666   root       root
+/dev/hwbinder             0666   root       root
 
 # Anyone can read the logs, but if they're not in the "logs"
 # group, then they'll only see log entries for their UID.
@@ -40,8 +41,8 @@
 /dev/android_adb          0660   adb        adb
 /dev/android_adb_enable   0660   adb        adb
 /dev/ttyMSM0              0600   bluetooth  bluetooth
-/dev/uhid                 0660   system     net_bt_stack
-/dev/uinput               0660   system     net_bt_stack
+/dev/uhid                 0660   system     bluetooth
+/dev/uinput               0660   system     bluetooth
 /dev/alarm                0664   system     radio
 /dev/rtc0                 0640   system     system
 /dev/tty0                 0660   root       system
diff --git a/run-as/Android.mk b/run-as/Android.mk
index 3774acc..7111fbe 100644
--- a/run-as/Android.mk
+++ b/run-as/Android.mk
@@ -1,12 +1,8 @@
 LOCAL_PATH:= $(call my-dir)
+
 include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := run-as.c package.c
-
-LOCAL_SHARED_LIBRARIES := libselinux
-
+LOCAL_CFLAGS := -Wall -Werror
 LOCAL_MODULE := run-as
-
-LOCAL_CFLAGS := -Werror
-
+LOCAL_SHARED_LIBRARIES := libselinux libpackagelistparser libminijail
+LOCAL_SRC_FILES := run-as.cpp
 include $(BUILD_EXECUTABLE)
diff --git a/run-as/package.c b/run-as/package.c
deleted file mode 100644
index 86824c2..0000000
--- a/run-as/package.c
+++ /dev/null
@@ -1,560 +0,0 @@
-/*
-**
-** Copyright 2010, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <private/android_filesystem_config.h>
-#include "package.h"
-
-/*
- *  WARNING WARNING WARNING WARNING
- *
- *  The following code runs as root on production devices, before
- *  the run-as command has dropped the uid/gid. Hence be very
- *  conservative and keep in mind the following:
- *
- *  - Performance does not matter here, clarity and safety of the code
- *    does however. Documentation is a must.
- *
- *  - Avoid calling C library functions with complex implementations
- *    like malloc() and printf(). You want to depend on simple system
- *    calls instead, which behaviour is not going to be altered in
- *    unpredictible ways by environment variables or system properties.
- *
- *  - Do not trust user input and/or the filesystem whenever possible.
- *
- */
-
-/* The file containing the list of installed packages on the system */
-#define PACKAGES_LIST_FILE  "/data/system/packages.list"
-
-/* Copy 'srclen' string bytes from 'src' into buffer 'dst' of size 'dstlen'
- * This function always zero-terminate the destination buffer unless
- * 'dstlen' is 0, even in case of overflow.
- * Returns a pointer into the src string, leaving off where the copy
- * has stopped. The copy will stop when dstlen, srclen or a null
- * character on src has been reached.
- */
-static const char*
-string_copy(char* dst, size_t dstlen, const char* src, size_t srclen)
-{
-    const char* srcend = src + srclen;
-    const char* dstend = dst + dstlen;
-
-    if (dstlen == 0)
-        return src;
-
-    dstend--; /* make room for terminating zero */
-
-    while (dst < dstend && src < srcend && *src != '\0')
-        *dst++ = *src++;
-
-    *dst = '\0'; /* zero-terminate result */
-    return src;
-}
-
-/* Open 'filename' and map it into our address-space.
- * Returns buffer address, or NULL on error
- * On exit, *filesize will be set to the file's size, or 0 on error
- */
-static void*
-map_file(const char* filename, size_t* filesize)
-{
-    int  fd, ret, old_errno;
-    struct stat  st;
-    size_t  length = 0;
-    void*   address = NULL;
-    gid_t   oldegid;
-
-    *filesize = 0;
-
-    /*
-     * Temporarily switch effective GID to allow us to read
-     * the packages file
-     */
-
-    oldegid = getegid();
-    if (setegid(AID_PACKAGE_INFO) < 0) {
-        return NULL;
-    }
-
-    /* open the file for reading */
-    fd = TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
-    if (fd < 0) {
-        return NULL;
-    }
-
-    /* restore back to our old egid */
-    if (setegid(oldegid) < 0) {
-        goto EXIT;
-    }
-
-    /* get its size */
-    ret = TEMP_FAILURE_RETRY(fstat(fd, &st));
-    if (ret < 0)
-        goto EXIT;
-
-    /* Ensure that the file is owned by the system user */
-    if ((st.st_uid != AID_SYSTEM) || (st.st_gid != AID_PACKAGE_INFO)) {
-        goto EXIT;
-    }
-
-    /* Ensure that the file has sane permissions */
-    if ((st.st_mode & S_IWOTH) != 0) {
-        goto EXIT;
-    }
-
-    /* Ensure that the size is not ridiculously large */
-    length = (size_t)st.st_size;
-    if ((off_t)length != st.st_size) {
-        errno = ENOMEM;
-        goto EXIT;
-    }
-
-    /* Memory-map the file now */
-    do {
-        address = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
-    } while (address == MAP_FAILED && errno == EINTR);
-    if (address == MAP_FAILED) {
-        address = NULL;
-        goto EXIT;
-    }
-
-    /* We're good, return size */
-    *filesize = length;
-
-EXIT:
-    /* close the file, preserve old errno for better diagnostics */
-    old_errno = errno;
-    close(fd);
-    errno = old_errno;
-
-    return address;
-}
-
-/* unmap the file, but preserve errno */
-static void
-unmap_file(void*  address, size_t  size)
-{
-    int old_errno = errno;
-    TEMP_FAILURE_RETRY(munmap(address, size));
-    errno = old_errno;
-}
-
-/* Check that a given directory:
- * - exists
- * - is owned by a given uid/gid
- * - is a real directory, not a symlink
- * - isn't readable or writable by others
- *
- * Return 0 on success, or -1 on error.
- * errno is set to EINVAL in case of failed check.
- */
-static int
-check_directory_ownership(const char* path, uid_t uid)
-{
-    int ret;
-    struct stat st;
-
-    do {
-        ret = lstat(path, &st);
-    } while (ret < 0 && errno == EINTR);
-
-    if (ret < 0)
-        return -1;
-
-    /* /data/user/0 is a known safe symlink */
-    if (strcmp("/data/user/0", path) == 0)
-        return 0;
-
-    /* must be a real directory, not a symlink */
-    if (!S_ISDIR(st.st_mode))
-        goto BAD;
-
-    /* must be owned by specific uid/gid */
-    if (st.st_uid != uid || st.st_gid != uid)
-        goto BAD;
-
-    /* must not be readable or writable by others */
-    if ((st.st_mode & (S_IROTH|S_IWOTH)) != 0)
-        goto BAD;
-
-    /* everything ok */
-    return 0;
-
-BAD:
-    errno = EINVAL;
-    return -1;
-}
-
-/* This function is used to check the data directory path for safety.
- * We check that every sub-directory is owned by the 'system' user
- * and exists and is not a symlink. We also check that the full directory
- * path is properly owned by the user ID.
- *
- * Return 0 on success, -1 on error.
- */
-int
-check_data_path(const char* dataPath, uid_t  uid)
-{
-    int  nn;
-
-    /* the path should be absolute */
-    if (dataPath[0] != '/') {
-        errno = EINVAL;
-        return -1;
-    }
-
-    /* look for all sub-paths, we do that by finding
-     * directory separators in the input path and
-     * checking each sub-path independently
-     */
-    for (nn = 1; dataPath[nn] != '\0'; nn++)
-    {
-        char subpath[PATH_MAX];
-
-        /* skip non-separator characters */
-        if (dataPath[nn] != '/')
-            continue;
-
-        /* handle trailing separator case */
-        if (dataPath[nn+1] == '\0') {
-            break;
-        }
-
-        /* found a separator, check that dataPath is not too long. */
-        if (nn >= (int)(sizeof subpath)) {
-            errno = EINVAL;
-            return -1;
-        }
-
-        /* reject any '..' subpath */
-        if (nn >= 3               &&
-            dataPath[nn-3] == '/' &&
-            dataPath[nn-2] == '.' &&
-            dataPath[nn-1] == '.') {
-            errno = EINVAL;
-            return -1;
-        }
-
-        /* copy to 'subpath', then check ownership */
-        memcpy(subpath, dataPath, nn);
-        subpath[nn] = '\0';
-
-        if (check_directory_ownership(subpath, AID_SYSTEM) < 0)
-            return -1;
-    }
-
-    /* All sub-paths were checked, now verify that the full data
-     * directory is owned by the application uid
-     */
-    if (check_directory_ownership(dataPath, uid) < 0)
-        return -1;
-
-    /* all clear */
-    return 0;
-}
-
-/* Return TRUE iff a character is a space or tab */
-static inline int
-is_space(char c)
-{
-    return (c == ' ' || c == '\t');
-}
-
-/* Skip any space or tab character from 'p' until 'end' is reached.
- * Return new position.
- */
-static const char*
-skip_spaces(const char*  p, const char*  end)
-{
-    while (p < end && is_space(*p))
-        p++;
-
-    return p;
-}
-
-/* Skip any non-space and non-tab character from 'p' until 'end'.
- * Return new position.
- */
-static const char*
-skip_non_spaces(const char* p, const char* end)
-{
-    while (p < end && !is_space(*p))
-        p++;
-
-    return p;
-}
-
-/* Find the first occurence of 'ch' between 'p' and 'end'
- * Return its position, or 'end' if none is found.
- */
-static const char*
-find_first(const char* p, const char* end, char ch)
-{
-    while (p < end && *p != ch)
-        p++;
-
-    return p;
-}
-
-/* Check that the non-space string starting at 'p' and eventually
- * ending at 'end' equals 'name'. Return new position (after name)
- * on success, or NULL on failure.
- *
- * This function fails is 'name' is NULL, empty or contains any space.
- */
-static const char*
-compare_name(const char* p, const char* end, const char* name)
-{
-    /* 'name' must not be NULL or empty */
-    if (name == NULL || name[0] == '\0' || p == end)
-        return NULL;
-
-    /* compare characters to those in 'name', excluding spaces */
-    while (*name) {
-        /* note, we don't check for *p == '\0' since
-         * it will be caught in the next conditional.
-         */
-        if (p >= end || is_space(*p))
-            goto BAD;
-
-        if (*p != *name)
-            goto BAD;
-
-        p++;
-        name++;
-    }
-
-    /* must be followed by end of line or space */
-    if (p < end && !is_space(*p))
-        goto BAD;
-
-    return p;
-
-BAD:
-    return NULL;
-}
-
-/* Parse one or more whitespace characters starting from '*pp'
- * until 'end' is reached. Updates '*pp' on exit.
- *
- * Return 0 on success, -1 on failure.
- */
-static int
-parse_spaces(const char** pp, const char* end)
-{
-    const char* p = *pp;
-
-    if (p >= end || !is_space(*p)) {
-        errno = EINVAL;
-        return -1;
-    }
-    p   = skip_spaces(p, end);
-    *pp = p;
-    return 0;
-}
-
-/* Parse a positive decimal number starting from '*pp' until 'end'
- * is reached. Adjust '*pp' on exit. Return decimal value or -1
- * in case of error.
- *
- * If the value is larger than INT_MAX, -1 will be returned,
- * and errno set to EOVERFLOW.
- *
- * If '*pp' does not start with a decimal digit, -1 is returned
- * and errno set to EINVAL.
- */
-static int
-parse_positive_decimal(const char** pp, const char* end)
-{
-    const char* p = *pp;
-    int value = 0;
-    int overflow = 0;
-
-    if (p >= end || *p < '0' || *p > '9') {
-        errno = EINVAL;
-        return -1;
-    }
-
-    while (p < end) {
-        int      ch = *p;
-        unsigned d  = (unsigned)(ch - '0');
-        int      val2;
-
-        if (d >= 10U) /* d is unsigned, no lower bound check */
-            break;
-
-        val2 = value*10 + (int)d;
-        if (val2 < value)
-            overflow = 1;
-        value = val2;
-        p++;
-    }
-    *pp = p;
-
-    if (overflow) {
-        errno = EOVERFLOW;
-        value = -1;
-    }
-    return value;
-}
-
-/* Read the system's package database and extract information about
- * 'pkgname'. Return 0 in case of success, or -1 in case of error.
- *
- * If the package is unknown, return -1 and set errno to ENOENT
- * If the package database is corrupted, return -1 and set errno to EINVAL
- */
-int
-get_package_info(const char* pkgName, uid_t userId, PackageInfo *info)
-{
-    char*        buffer;
-    size_t       buffer_len;
-    const char*  p;
-    const char*  buffer_end;
-    int          result = -1;
-
-    info->uid          = 0;
-    info->isDebuggable = 0;
-    info->dataDir[0]   = '\0';
-    info->seinfo[0]    = '\0';
-
-    buffer = map_file(PACKAGES_LIST_FILE, &buffer_len);
-    if (buffer == NULL)
-        return -1;
-
-    p          = buffer;
-    buffer_end = buffer + buffer_len;
-
-    /* expect the following format on each line of the control file:
-     *
-     *  <pkgName> <uid> <debugFlag> <dataDir> <seinfo>
-     *
-     * where:
-     *  <pkgName>    is the package's name
-     *  <uid>        is the application-specific user Id (decimal)
-     *  <debugFlag>  is 1 if the package is debuggable, or 0 otherwise
-     *  <dataDir>    is the path to the package's data directory (e.g. /data/data/com.example.foo)
-     *  <seinfo>     is the seinfo label associated with the package
-     *
-     * The file is generated in com.android.server.PackageManagerService.Settings.writeLP()
-     */
-
-    while (p < buffer_end) {
-        /* find end of current line and start of next one */
-        const char*  end  = find_first(p, buffer_end, '\n');
-        const char*  next = (end < buffer_end) ? end + 1 : buffer_end;
-        const char*  q;
-        int          uid, debugFlag;
-
-        /* first field is the package name */
-        p = compare_name(p, end, pkgName);
-        if (p == NULL)
-            goto NEXT_LINE;
-
-        /* skip spaces */
-        if (parse_spaces(&p, end) < 0)
-            goto BAD_FORMAT;
-
-        /* second field is the pid */
-        uid = parse_positive_decimal(&p, end);
-        if (uid < 0)
-            return -1;
-
-        info->uid = (uid_t) uid;
-
-        /* skip spaces */
-        if (parse_spaces(&p, end) < 0)
-            goto BAD_FORMAT;
-
-        /* third field is debug flag (0 or 1) */
-        debugFlag = parse_positive_decimal(&p, end);
-        switch (debugFlag) {
-        case 0:
-            info->isDebuggable = 0;
-            break;
-        case 1:
-            info->isDebuggable = 1;
-            break;
-        default:
-            goto BAD_FORMAT;
-        }
-
-        /* skip spaces */
-        if (parse_spaces(&p, end) < 0)
-            goto BAD_FORMAT;
-
-        /* fourth field is data directory path and must not contain
-         * spaces.
-         */
-        q = skip_non_spaces(p, end);
-        if (q == p)
-            goto BAD_FORMAT;
-
-        /* If userId == 0 (i.e. user is device owner) we can use dataDir value
-         * from packages.list, otherwise compose data directory as
-         * /data/user/$uid/$packageId
-         */
-        if (userId == 0) {
-            p = string_copy(info->dataDir, sizeof info->dataDir, p, q - p);
-        } else {
-            snprintf(info->dataDir,
-                     sizeof info->dataDir,
-                     "/data/user/%d/%s",
-                     userId,
-                     pkgName);
-            p = q;
-        }
-
-        /* skip spaces */
-        if (parse_spaces(&p, end) < 0)
-            goto BAD_FORMAT;
-
-        /* fifth field is the seinfo string */
-        q = skip_non_spaces(p, end);
-        if (q == p)
-            goto BAD_FORMAT;
-
-        string_copy(info->seinfo, sizeof info->seinfo, p, q - p);
-
-        /* Ignore the rest */
-        result = 0;
-        goto EXIT;
-
-    NEXT_LINE:
-        p = next;
-    }
-
-    /* the package is unknown */
-    errno = ENOENT;
-    result = -1;
-    goto EXIT;
-
-BAD_FORMAT:
-    errno = EINVAL;
-    result = -1;
-
-EXIT:
-    unmap_file(buffer, buffer_len);
-    return result;
-}
diff --git a/run-as/package.h b/run-as/package.h
deleted file mode 100644
index eeb5913..0000000
--- a/run-as/package.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-**
-** Copyright 2010, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-#ifndef RUN_AS_PACKAGE_H
-#define RUN_AS_PACKAGE_H
-
-#include <limits.h>
-#include <sys/types.h>
-
-typedef enum {
-    PACKAGE_IS_DEBUGGABLE = 0,
-    PACKAGE_IS_NOT_DEBUGGABLE,
-    PACKAGE_IS_UNKNOWN,
-} PackageStatus;
-
-typedef struct {
-    uid_t  uid;
-    char   isDebuggable;
-    char   dataDir[PATH_MAX];
-    char   seinfo[PATH_MAX];
-} PackageInfo;
-
-/* see documentation in package.c for these functions */
-
-extern int  get_package_info(const char* packageName,
-                             uid_t userId,
-                             PackageInfo*  info);
-
-extern int  check_data_path(const char* dataDir, uid_t uid);
-
-#endif /* RUN_AS_PACKAGE_H */
diff --git a/run-as/run-as.c b/run-as/run-as.c
deleted file mode 100644
index f0fd2fe..0000000
--- a/run-as/run-as.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
-**
-** Copyright 2010, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define PROGNAME "run-as"
-#define LOG_TAG  PROGNAME
-
-#include <dirent.h>
-#include <errno.h>
-#include <paths.h>
-#include <pwd.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/capability.h>
-#include <sys/cdefs.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <private/android_filesystem_config.h>
-#include <selinux/android.h>
-
-#include "package.h"
-
-/*
- *  WARNING WARNING WARNING WARNING
- *
- *  This program runs with CAP_SETUID and CAP_SETGID capabilities on Android
- *  production devices. Be very conservative when modifying it to avoid any
- *  serious security issue. Keep in mind the following:
- *
- *  - This program should only run for the 'root' or 'shell' users
- *
- *  - Avoid anything that is more complex than simple system calls
- *    until the uid/gid has been dropped to that of a normal user
- *    or you are sure to exit.
- *
- *    This avoids depending on environment variables, system properties
- *    and other external factors that may affect the C library in
- *    unpredictable ways.
- *
- *  - Do not trust user input and/or the filesystem whenever possible.
- *
- *  Read README.TXT for more details.
- *
- *
- *
- * The purpose of this program is to run a command as a specific
- * application user-id. Typical usage is:
- *
- *   run-as <package-name> <command> <args>
- *
- *  The 'run-as' binary is installed with CAP_SETUID and CAP_SETGID file
- *  capabilities, but will check the following:
- *
- *  - that it is invoked from the 'shell' or 'root' user (abort otherwise)
- *  - that '<package-name>' is the name of an installed and debuggable package
- *  - that the package's data directory is well-formed (see package.c)
- *
- *  If so, it will drop to the application's user id / group id, cd to the
- *  package's data directory, then run the command there.
- *
- *  NOTE: In the future it might not be possible to cd to the package's data
- *  directory under that package's user id / group id, in which case this
- *  utility will need to be changed accordingly.
- *
- *  This can be useful for a number of different things on production devices:
- *
- *  - Allow application developers to look at their own applicative data
- *    during development.
- *
- *  - Run the 'gdbserver' binary executable to allow native debugging
- */
-
-__noreturn static void
-panic(const char* format, ...)
-{
-    va_list args;
-    int e = errno;
-
-    fprintf(stderr, "%s: ", PROGNAME);
-    va_start(args, format);
-    vfprintf(stderr, format, args);
-    va_end(args);
-    exit(e ? -e : 1);
-}
-
-static void
-usage(void)
-{
-    panic("Usage:\n    " PROGNAME " <package-name> [--user <uid>] <command> [<args>]\n");
-}
-
-int main(int argc, char **argv)
-{
-    const char* pkgname;
-    uid_t myuid, uid, gid, userAppId = 0;
-    int commandArgvOfs = 2, userId = 0;
-    PackageInfo info;
-    struct __user_cap_header_struct capheader;
-    struct __user_cap_data_struct capdata[2];
-
-    /* check arguments */
-    if (argc < 2) {
-        usage();
-    }
-
-    /* check userid of caller - must be 'shell' or 'root' */
-    myuid = getuid();
-    if (myuid != AID_SHELL && myuid != AID_ROOT) {
-        panic("only 'shell' or 'root' users can run this program\n");
-    }
-
-    memset(&capheader, 0, sizeof(capheader));
-    memset(&capdata, 0, sizeof(capdata));
-    capheader.version = _LINUX_CAPABILITY_VERSION_3;
-    capdata[CAP_TO_INDEX(CAP_SETUID)].effective |= CAP_TO_MASK(CAP_SETUID);
-    capdata[CAP_TO_INDEX(CAP_SETGID)].effective |= CAP_TO_MASK(CAP_SETGID);
-    capdata[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
-    capdata[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
-
-    if (capset(&capheader, &capdata[0]) < 0) {
-        panic("Could not set capabilities: %s\n", strerror(errno));
-    }
-
-    pkgname = argv[1];
-
-    /* get user_id from command line if provided */
-    if ((argc >= 4) && !strcmp(argv[2], "--user")) {
-        userId = atoi(argv[3]);
-        if (userId < 0)
-            panic("Negative user id %d is provided\n", userId);
-        commandArgvOfs += 2;
-    }
-
-    /* retrieve package information from system (does setegid) */
-    if (get_package_info(pkgname, userId, &info) < 0) {
-        panic("Package '%s' is unknown\n", pkgname);
-    }
-
-    /* verify that user id is not too big. */
-    if ((UID_MAX - info.uid) / AID_USER < (uid_t)userId) {
-        panic("User id %d is too big\n", userId);
-    }
-
-    /* calculate user app ID. */
-    userAppId = (AID_USER * userId) + info.uid;
-
-    /* reject system packages */
-    if (userAppId < AID_APP) {
-        panic("Package '%s' is not an application\n", pkgname);
-    }
-
-    /* reject any non-debuggable package */
-    if (!info.isDebuggable) {
-        panic("Package '%s' is not debuggable\n", pkgname);
-    }
-
-    /* check that the data directory path is valid */
-    if (check_data_path(info.dataDir, userAppId) < 0) {
-        panic("Package '%s' has corrupt installation\n", pkgname);
-    }
-
-    /* Ensure that we change all real/effective/saved IDs at the
-     * same time to avoid nasty surprises.
-     */
-    uid = gid = userAppId;
-    if(setresgid(gid,gid,gid) || setresuid(uid,uid,uid)) {
-        panic("Permission denied\n");
-    }
-
-    /* Required if caller has uid and gid all non-zero */
-    memset(&capdata, 0, sizeof(capdata));
-    if (capset(&capheader, &capdata[0]) < 0) {
-        panic("Could not clear all capabilities: %s\n", strerror(errno));
-    }
-
-    if (selinux_android_setcontext(uid, 0, info.seinfo, pkgname) < 0) {
-        panic("Could not set SELinux security context: %s\n", strerror(errno));
-    }
-
-    // cd into the data directory, and set $HOME correspondingly.
-    if (TEMP_FAILURE_RETRY(chdir(info.dataDir)) < 0) {
-        panic("Could not cd to package's data directory: %s\n", strerror(errno));
-    }
-    setenv("HOME", info.dataDir, 1);
-
-    // Reset parts of the environment, like su would.
-    setenv("PATH", _PATH_DEFPATH, 1);
-    unsetenv("IFS");
-
-    // Set the user-specific parts for this user.
-    struct passwd* pw = getpwuid(uid);
-    setenv("LOGNAME", pw->pw_name, 1);
-    setenv("SHELL", pw->pw_shell, 1);
-    setenv("USER", pw->pw_name, 1);
-
-    /* User specified command for exec. */
-    if ((argc >= commandArgvOfs + 1) &&
-        (execvp(argv[commandArgvOfs], argv+commandArgvOfs) < 0)) {
-        panic("exec failed for %s: %s\n", argv[commandArgvOfs], strerror(errno));
-    }
-
-    /* Default exec shell. */
-    execlp("/system/bin/sh", "sh", NULL);
-
-    panic("exec failed: %s\n", strerror(errno));
-}
diff --git a/run-as/run-as.cpp b/run-as/run-as.cpp
new file mode 100644
index 0000000..aec51f4
--- /dev/null
+++ b/run-as/run-as.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <error.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/capability.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <libminijail.h>
+#include <scoped_minijail.h>
+
+#include <packagelistparser/packagelistparser.h>
+#include <private/android_filesystem_config.h>
+#include <selinux/android.h>
+
+// The purpose of this program is to run a command as a specific
+// application user-id. Typical usage is:
+//
+//   run-as <package-name> <command> <args>
+//
+//  The 'run-as' binary is installed with CAP_SETUID and CAP_SETGID file
+//  capabilities, but will check the following:
+//
+//  - that it is invoked from the 'shell' or 'root' user (abort otherwise)
+//  - that '<package-name>' is the name of an installed and debuggable package
+//  - that the package's data directory is well-formed
+//
+//  If so, it will drop to the application's user id / group id, cd to the
+//  package's data directory, then run the command there.
+//
+//  This can be useful for a number of different things on production devices:
+//
+//  - Allow application developers to look at their own application data
+//    during development.
+//
+//  - Run the 'gdbserver' binary executable to allow native debugging
+//
+
+static bool packagelist_parse_callback(pkg_info* this_package, void* userdata) {
+  pkg_info* p = reinterpret_cast<pkg_info*>(userdata);
+  if (strcmp(p->name, this_package->name) == 0) {
+    *p = *this_package;
+    return false; // Stop searching.
+  }
+  packagelist_free(this_package);
+  return true; // Keep searching.
+}
+
+static bool check_directory(const char* path, uid_t uid) {
+  struct stat st;
+  if (TEMP_FAILURE_RETRY(lstat(path, &st)) == -1) return false;
+
+  // /data/user/0 is a known safe symlink.
+  if (strcmp("/data/user/0", path) == 0) return true;
+
+  // Must be a real directory, not a symlink.
+  if (!S_ISDIR(st.st_mode)) return false;
+
+  // Must be owned by specific uid/gid.
+  if (st.st_uid != uid || st.st_gid != uid) return false;
+
+  // Must not be readable or writable by others.
+  if ((st.st_mode & (S_IROTH|S_IWOTH)) != 0) return false;
+
+  return true;
+}
+
+// This function is used to check the data directory path for safety.
+// We check that every sub-directory is owned by the 'system' user
+// and exists and is not a symlink. We also check that the full directory
+// path is properly owned by the user ID.
+static bool check_data_path(const char* data_path, uid_t uid) {
+  // The path should be absolute.
+  if (data_path[0] != '/') return false;
+
+  // Look for all sub-paths, we do that by finding
+  // directory separators in the input path and
+  // checking each sub-path independently.
+  for (int nn = 1; data_path[nn] != '\0'; nn++) {
+    char subpath[PATH_MAX];
+
+    /* skip non-separator characters */
+    if (data_path[nn] != '/') continue;
+
+    /* handle trailing separator case */
+    if (data_path[nn+1] == '\0') break;
+
+    /* found a separator, check that data_path is not too long. */
+    if (nn >= (int)(sizeof subpath)) return false;
+
+    /* reject any '..' subpath */
+    if (nn >= 3               &&
+        data_path[nn-3] == '/' &&
+        data_path[nn-2] == '.' &&
+        data_path[nn-1] == '.') {
+      return false;
+    }
+
+    /* copy to 'subpath', then check ownership */
+    memcpy(subpath, data_path, nn);
+    subpath[nn] = '\0';
+
+    if (!check_directory(subpath, AID_SYSTEM)) return false;
+  }
+
+  // All sub-paths were checked, now verify that the full data
+  // directory is owned by the application uid.
+  return check_directory(data_path, uid);
+}
+
+int main(int argc, char* argv[]) {
+  // Check arguments.
+  if (argc < 2) {
+    error(1, 0, "usage: run-as <package-name> [--user <uid>] <command> [<args>]\n");
+  }
+
+  // This program runs with CAP_SETUID and CAP_SETGID capabilities on Android
+  // production devices. Check user id of caller --- must be 'shell' or 'root'.
+  if (getuid() != AID_SHELL && getuid() != AID_ROOT) {
+    error(1, 0, "only 'shell' or 'root' users can run this program");
+  }
+
+  char* pkgname = argv[1];
+  int cmd_argv_offset = 2;
+
+  // Get user_id from command line if provided.
+  int userId = 0;
+  if ((argc >= 4) && !strcmp(argv[2], "--user")) {
+    userId = atoi(argv[3]);
+    if (userId < 0) error(1, 0, "negative user id: %d", userId);
+    cmd_argv_offset += 2;
+  }
+
+  // Retrieve package information from system, switching egid so we can read the file.
+  gid_t old_egid = getegid();
+  if (setegid(AID_PACKAGE_INFO) == -1) error(1, errno, "setegid(AID_PACKAGE_INFO) failed");
+  pkg_info info;
+  memset(&info, 0, sizeof(info));
+  info.name = pkgname;
+  if (!packagelist_parse(packagelist_parse_callback, &info)) {
+    error(1, errno, "packagelist_parse failed");
+  }
+  if (info.uid == 0) {
+    error(1, 0, "unknown package: %s", pkgname);
+  }
+  if (setegid(old_egid) == -1) error(1, errno, "couldn't restore egid");
+
+  // Verify that user id is not too big.
+  if ((UID_MAX - info.uid) / AID_USER < (uid_t)userId) {
+    error(1, 0, "user id too big: %d", userId);
+  }
+
+  // Calculate user app ID.
+  uid_t userAppId = (AID_USER * userId) + info.uid;
+
+  // Reject system packages.
+  if (userAppId < AID_APP) {
+    error(1, 0, "package not an application: %s", pkgname);
+  }
+
+  // Reject any non-debuggable package.
+  if (!info.debuggable) {
+    error(1, 0, "package not debuggable: %s", pkgname);
+  }
+
+  // Check that the data directory path is valid.
+  if (!check_data_path(info.data_dir, userAppId)) {
+    error(1, 0, "package has corrupt installation: %s", pkgname);
+  }
+
+  // Ensure that we change all real/effective/saved IDs at the
+  // same time to avoid nasty surprises.
+  uid_t uid = userAppId;
+  uid_t gid = userAppId;
+  ScopedMinijail j(minijail_new());
+  minijail_change_uid(j.get(), uid);
+  minijail_change_gid(j.get(), gid);
+  minijail_enter(j.get());
+
+  if (selinux_android_setcontext(uid, 0, info.seinfo, pkgname) < 0) {
+    error(1, errno, "couldn't set SELinux security context");
+  }
+
+  // cd into the data directory, and set $HOME correspondingly.
+  if (TEMP_FAILURE_RETRY(chdir(info.data_dir)) == -1) {
+    error(1, errno, "couldn't chdir to package's data directory");
+  }
+  setenv("HOME", info.data_dir, 1);
+
+  // Reset parts of the environment, like su would.
+  setenv("PATH", _PATH_DEFPATH, 1);
+  unsetenv("IFS");
+
+  // Set the user-specific parts for this user.
+  passwd* pw = getpwuid(uid);
+  setenv("LOGNAME", pw->pw_name, 1);
+  setenv("SHELL", pw->pw_shell, 1);
+  setenv("USER", pw->pw_name, 1);
+
+  // User specified command for exec.
+  if ((argc >= cmd_argv_offset + 1) &&
+      (execvp(argv[cmd_argv_offset], argv+cmd_argv_offset) == -1)) {
+    error(1, errno, "exec failed for %s", argv[cmd_argv_offset]);
+  }
+
+  // Default exec shell.
+  execlp(_PATH_BSHELL, "sh", NULL);
+  error(1, errno, "exec failed");
+}
diff --git a/sdcard/Android.mk b/sdcard/Android.mk
index c5f3d1d..0c58574 100644
--- a/sdcard/Android.mk
+++ b/sdcard/Android.mk
@@ -2,9 +2,12 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := sdcard.c
+LOCAL_SRC_FILES := sdcard.cpp fuse.cpp
 LOCAL_MODULE := sdcard
 LOCAL_CFLAGS := -Wall -Wno-unused-parameter -Werror
-LOCAL_SHARED_LIBRARIES := libcutils libpackagelistparser
+LOCAL_SHARED_LIBRARIES := libbase libcutils libminijail libpackagelistparser
+
+LOCAL_SANITIZE := integer
+LOCAL_CLANG := true
 
 include $(BUILD_EXECUTABLE)
diff --git a/sdcard/fuse.cpp b/sdcard/fuse.cpp
new file mode 100644
index 0000000..3f0f95f
--- /dev/null
+++ b/sdcard/fuse.cpp
@@ -0,0 +1,1495 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LOG_TAG "sdcard"
+
+#include "fuse.h"
+
+#include <android-base/logging.h>
+
+/* FUSE_CANONICAL_PATH is not currently upstreamed */
+#define FUSE_CANONICAL_PATH 2016
+
+#define FUSE_UNKNOWN_INO 0xffffffff
+
+/* Pseudo-error constant used to indicate that no fuse status is needed
+ * or that a reply has already been written. */
+#define NO_STATUS 1
+
+static inline void *id_to_ptr(__u64 nid)
+{
+    return (void *) (uintptr_t) nid;
+}
+
+static inline __u64 ptr_to_id(void *ptr)
+{
+    return (__u64) (uintptr_t) ptr;
+}
+
+static void acquire_node_locked(struct node* node)
+{
+    node->refcount++;
+    DLOG(INFO) << "ACQUIRE " << std::hex << node << std::dec
+               << " (" << node->name << ") rc=" << node->refcount;
+}
+
+static void remove_node_from_parent_locked(struct node* node);
+
+static void release_node_locked(struct node* node)
+{
+    DLOG(INFO) << "RELEASE " << std::hex << node << std::dec
+               << " (" << node->name << ") rc=" << node->refcount;
+    if (node->refcount > 0) {
+        node->refcount--;
+        if (!node->refcount) {
+            DLOG(INFO) << "DESTROY " << std::hex << node << std::dec << " (" << node->name << ")";
+            remove_node_from_parent_locked(node);
+
+            /* TODO: remove debugging - poison memory */
+            memset(node->name, 0xef, node->namelen);
+            free(node->name);
+            free(node->actual_name);
+            memset(node, 0xfc, sizeof(*node));
+            free(node);
+        }
+    } else {
+        LOG(ERROR) << std::hex << node << std::dec << " refcount=0";
+    }
+}
+
+static void add_node_to_parent_locked(struct node *node, struct node *parent) {
+    node->parent = parent;
+    node->next = parent->child;
+    parent->child = node;
+    acquire_node_locked(parent);
+}
+
+static void remove_node_from_parent_locked(struct node* node)
+{
+    if (node->parent) {
+        if (node->parent->child == node) {
+            node->parent->child = node->parent->child->next;
+        } else {
+            struct node *node2;
+            node2 = node->parent->child;
+            while (node2->next != node)
+                node2 = node2->next;
+            node2->next = node->next;
+        }
+        release_node_locked(node->parent);
+        node->parent = NULL;
+        node->next = NULL;
+    }
+}
+
+/* Gets the absolute path to a node into the provided buffer.
+ *
+ * Populates 'buf' with the path and returns the length of the path on success,
+ * or returns -1 if the path is too long for the provided buffer.
+ */
+static ssize_t get_node_path_locked(struct node* node, char* buf, size_t bufsize) {
+    const char* name;
+    size_t namelen;
+    if (node->graft_path) {
+        name = node->graft_path;
+        namelen = node->graft_pathlen;
+    } else if (node->actual_name) {
+        name = node->actual_name;
+        namelen = node->namelen;
+    } else {
+        name = node->name;
+        namelen = node->namelen;
+    }
+
+    if (bufsize < namelen + 1) {
+        return -1;
+    }
+
+    ssize_t pathlen = 0;
+    if (node->parent && node->graft_path == NULL) {
+        pathlen = get_node_path_locked(node->parent, buf, bufsize - namelen - 1);
+        if (pathlen < 0) {
+            return -1;
+        }
+        buf[pathlen++] = '/';
+    }
+
+    memcpy(buf + pathlen, name, namelen + 1); /* include trailing \0 */
+    return pathlen + namelen;
+}
+
+/* Finds the absolute path of a file within a given directory.
+ * Performs a case-insensitive search for the file and sets the buffer to the path
+ * of the first matching file.  If 'search' is zero or if no match is found, sets
+ * the buffer to the path that the file would have, assuming the name were case-sensitive.
+ *
+ * Populates 'buf' with the path and returns the actual name (within 'buf') on success,
+ * or returns NULL if the path is too long for the provided buffer.
+ */
+static char* find_file_within(const char* path, const char* name,
+        char* buf, size_t bufsize, int search)
+{
+    size_t pathlen = strlen(path);
+    size_t namelen = strlen(name);
+    size_t childlen = pathlen + namelen + 1;
+    char* actual;
+
+    if (bufsize <= childlen) {
+        return NULL;
+    }
+
+    memcpy(buf, path, pathlen);
+    buf[pathlen] = '/';
+    actual = buf + pathlen + 1;
+    memcpy(actual, name, namelen + 1);
+
+    if (search && access(buf, F_OK)) {
+        struct dirent* entry;
+        DIR* dir = opendir(path);
+        if (!dir) {
+            PLOG(ERROR) << "opendir(" << path << ") failed";
+            return actual;
+        }
+        while ((entry = readdir(dir))) {
+            if (!strcasecmp(entry->d_name, name)) {
+                /* we have a match - replace the name, don't need to copy the null again */
+                memcpy(actual, entry->d_name, namelen);
+                break;
+            }
+        }
+        closedir(dir);
+    }
+    return actual;
+}
+
+static void attr_from_stat(struct fuse* fuse, struct fuse_attr *attr,
+        const struct stat *s, const struct node* node) {
+    attr->ino = node->ino;
+    attr->size = s->st_size;
+    attr->blocks = s->st_blocks;
+    attr->atime = s->st_atim.tv_sec;
+    attr->mtime = s->st_mtim.tv_sec;
+    attr->ctime = s->st_ctim.tv_sec;
+    attr->atimensec = s->st_atim.tv_nsec;
+    attr->mtimensec = s->st_mtim.tv_nsec;
+    attr->ctimensec = s->st_ctim.tv_nsec;
+    attr->mode = s->st_mode;
+    attr->nlink = s->st_nlink;
+
+    attr->uid = node->uid;
+
+    if (fuse->gid == AID_SDCARD_RW) {
+        /* As an optimization, certain trusted system components only run
+         * as owner but operate across all users. Since we're now handing
+         * out the sdcard_rw GID only to trusted apps, we're okay relaxing
+         * the user boundary enforcement for the default view. The UIDs
+         * assigned to app directories are still multiuser aware. */
+        attr->gid = AID_SDCARD_RW;
+    } else {
+        attr->gid = multiuser_get_uid(node->userid, fuse->gid);
+    }
+
+    int visible_mode = 0775 & ~fuse->mask;
+    if (node->perm == PERM_PRE_ROOT) {
+        /* Top of multi-user view should always be visible to ensure
+         * secondary users can traverse inside. */
+        visible_mode = 0711;
+    } else if (node->under_android) {
+        /* Block "other" access to Android directories, since only apps
+         * belonging to a specific user should be in there; we still
+         * leave +x open for the default view. */
+        if (fuse->gid == AID_SDCARD_RW) {
+            visible_mode = visible_mode & ~0006;
+        } else {
+            visible_mode = visible_mode & ~0007;
+        }
+    }
+    int owner_mode = s->st_mode & 0700;
+    int filtered_mode = visible_mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6));
+    attr->mode = (attr->mode & S_IFMT) | filtered_mode;
+}
+
+static int touch(char* path, mode_t mode) {
+    int fd = TEMP_FAILURE_RETRY(open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW | O_CLOEXEC,
+                                     mode));
+    if (fd == -1) {
+        if (errno == EEXIST) {
+            return 0;
+        } else {
+            PLOG(ERROR) << "open(" << path << ") failed";
+            return -1;
+        }
+    }
+    close(fd);
+    return 0;
+}
+
+static void derive_permissions_locked(struct fuse* fuse, struct node *parent,
+        struct node *node) {
+    appid_t appid;
+
+    /* By default, each node inherits from its parent */
+    node->perm = PERM_INHERIT;
+    node->userid = parent->userid;
+    node->uid = parent->uid;
+    node->under_android = parent->under_android;
+
+    /* Derive custom permissions based on parent and current node */
+    switch (parent->perm) {
+    case PERM_INHERIT:
+        /* Already inherited above */
+        break;
+    case PERM_PRE_ROOT:
+        /* Legacy internal layout places users at top level */
+        node->perm = PERM_ROOT;
+        node->userid = strtoul(node->name, NULL, 10);
+        break;
+    case PERM_ROOT:
+        /* Assume masked off by default. */
+        if (!strcasecmp(node->name, "Android")) {
+            /* App-specific directories inside; let anyone traverse */
+            node->perm = PERM_ANDROID;
+            node->under_android = true;
+        }
+        break;
+    case PERM_ANDROID:
+        if (!strcasecmp(node->name, "data")) {
+            /* App-specific directories inside; let anyone traverse */
+            node->perm = PERM_ANDROID_DATA;
+        } else if (!strcasecmp(node->name, "obb")) {
+            /* App-specific directories inside; let anyone traverse */
+            node->perm = PERM_ANDROID_OBB;
+            /* Single OBB directory is always shared */
+            node->graft_path = fuse->global->obb_path;
+            node->graft_pathlen = strlen(fuse->global->obb_path);
+        } else if (!strcasecmp(node->name, "media")) {
+            /* App-specific directories inside; let anyone traverse */
+            node->perm = PERM_ANDROID_MEDIA;
+        }
+        break;
+    case PERM_ANDROID_DATA:
+    case PERM_ANDROID_OBB:
+    case PERM_ANDROID_MEDIA:
+        const auto& iter = fuse->global->package_to_appid->find(node->name);
+        if (iter != fuse->global->package_to_appid->end()) {
+            appid = iter->second;
+            node->uid = multiuser_get_uid(parent->userid, appid);
+        }
+        break;
+    }
+}
+
+void derive_permissions_recursive_locked(struct fuse* fuse, struct node *parent) {
+    struct node *node;
+    for (node = parent->child; node; node = node->next) {
+        derive_permissions_locked(fuse, parent, node);
+        if (node->child) {
+            derive_permissions_recursive_locked(fuse, node);
+        }
+    }
+}
+
+/* Kernel has already enforced everything we returned through
+ * derive_permissions_locked(), so this is used to lock down access
+ * even further, such as enforcing that apps hold sdcard_rw. */
+static bool check_caller_access_to_name(struct fuse* fuse,
+        const struct fuse_in_header *hdr, const struct node* parent_node,
+        const char* name, int mode) {
+    /* Always block security-sensitive files at root */
+    if (parent_node && parent_node->perm == PERM_ROOT) {
+        if (!strcasecmp(name, "autorun.inf")
+                || !strcasecmp(name, ".android_secure")
+                || !strcasecmp(name, "android_secure")) {
+            return false;
+        }
+    }
+
+    /* Root always has access; access for any other UIDs should always
+     * be controlled through packages.list. */
+    if (hdr->uid == 0) {
+        return true;
+    }
+
+    /* No extra permissions to enforce */
+    return true;
+}
+
+static bool check_caller_access_to_node(struct fuse* fuse,
+        const struct fuse_in_header *hdr, const struct node* node, int mode) {
+    return check_caller_access_to_name(fuse, hdr, node->parent, node->name, mode);
+}
+
+struct node *create_node_locked(struct fuse* fuse,
+        struct node *parent, const char *name, const char* actual_name)
+{
+    struct node *node;
+    size_t namelen = strlen(name);
+
+    // Detect overflows in the inode counter. "4 billion nodes should be enough
+    // for everybody".
+    if (fuse->global->inode_ctr == 0) {
+        LOG(ERROR) << "No more inode numbers available";
+        return NULL;
+    }
+
+    node = static_cast<struct node*>(calloc(1, sizeof(struct node)));
+    if (!node) {
+        return NULL;
+    }
+    node->name = static_cast<char*>(malloc(namelen + 1));
+    if (!node->name) {
+        free(node);
+        return NULL;
+    }
+    memcpy(node->name, name, namelen + 1);
+    if (strcmp(name, actual_name)) {
+        node->actual_name = static_cast<char*>(malloc(namelen + 1));
+        if (!node->actual_name) {
+            free(node->name);
+            free(node);
+            return NULL;
+        }
+        memcpy(node->actual_name, actual_name, namelen + 1);
+    }
+    node->namelen = namelen;
+    node->nid = ptr_to_id(node);
+    node->ino = fuse->global->inode_ctr++;
+    node->gen = fuse->global->next_generation++;
+
+    node->deleted = false;
+
+    derive_permissions_locked(fuse, parent, node);
+    acquire_node_locked(node);
+    add_node_to_parent_locked(node, parent);
+    return node;
+}
+
+static int rename_node_locked(struct node *node, const char *name,
+        const char* actual_name)
+{
+    size_t namelen = strlen(name);
+    int need_actual_name = strcmp(name, actual_name);
+
+    /* make the storage bigger without actually changing the name
+     * in case an error occurs part way */
+    if (namelen > node->namelen) {
+        char* new_name = static_cast<char*>(realloc(node->name, namelen + 1));
+        if (!new_name) {
+            return -ENOMEM;
+        }
+        node->name = new_name;
+        if (need_actual_name && node->actual_name) {
+            char* new_actual_name = static_cast<char*>(realloc(node->actual_name, namelen + 1));
+            if (!new_actual_name) {
+                return -ENOMEM;
+            }
+            node->actual_name = new_actual_name;
+        }
+    }
+
+    /* update the name, taking care to allocate storage before overwriting the old name */
+    if (need_actual_name) {
+        if (!node->actual_name) {
+            node->actual_name = static_cast<char*>(malloc(namelen + 1));
+            if (!node->actual_name) {
+                return -ENOMEM;
+            }
+        }
+        memcpy(node->actual_name, actual_name, namelen + 1);
+    } else {
+        free(node->actual_name);
+        node->actual_name = NULL;
+    }
+    memcpy(node->name, name, namelen + 1);
+    node->namelen = namelen;
+    return 0;
+}
+
+static struct node *lookup_node_by_id_locked(struct fuse *fuse, __u64 nid)
+{
+    if (nid == FUSE_ROOT_ID) {
+        return &fuse->global->root;
+    } else {
+        return static_cast<struct node*>(id_to_ptr(nid));
+    }
+}
+
+static struct node* lookup_node_and_path_by_id_locked(struct fuse* fuse, __u64 nid,
+        char* buf, size_t bufsize)
+{
+    struct node* node = lookup_node_by_id_locked(fuse, nid);
+    if (node && get_node_path_locked(node, buf, bufsize) < 0) {
+        node = NULL;
+    }
+    return node;
+}
+
+static struct node *lookup_child_by_name_locked(struct node *node, const char *name)
+{
+    for (node = node->child; node; node = node->next) {
+        /* use exact string comparison, nodes that differ by case
+         * must be considered distinct even if they refer to the same
+         * underlying file as otherwise operations such as "mv x x"
+         * will not work because the source and target nodes are the same. */
+        if (!strcmp(name, node->name) && !node->deleted) {
+            return node;
+        }
+    }
+    return 0;
+}
+
+static struct node* acquire_or_create_child_locked(
+        struct fuse* fuse, struct node* parent,
+        const char* name, const char* actual_name)
+{
+    struct node* child = lookup_child_by_name_locked(parent, name);
+    if (child) {
+        acquire_node_locked(child);
+    } else {
+        child = create_node_locked(fuse, parent, name, actual_name);
+    }
+    return child;
+}
+
+static void fuse_status(struct fuse *fuse, __u64 unique, int err)
+{
+    struct fuse_out_header hdr;
+    hdr.len = sizeof(hdr);
+    hdr.error = err;
+    hdr.unique = unique;
+    ssize_t ret = TEMP_FAILURE_RETRY(write(fuse->fd, &hdr, sizeof(hdr)));
+    if (ret == -1) {
+        PLOG(ERROR) << "*** STATUS FAILED ***";
+    } else if (static_cast<size_t>(ret) != sizeof(hdr)) {
+        LOG(ERROR) << "*** STATUS FAILED: written " << ret << " expected "
+                   << sizeof(hdr) << " ***";
+    }
+}
+
+static void fuse_reply(struct fuse *fuse, __u64 unique, void *data, int len)
+{
+    struct fuse_out_header hdr;
+    hdr.len = len + sizeof(hdr);
+    hdr.error = 0;
+    hdr.unique = unique;
+
+    struct iovec vec[2];
+    vec[0].iov_base = &hdr;
+    vec[0].iov_len = sizeof(hdr);
+    vec[1].iov_base = data;
+    vec[1].iov_len = len;
+
+    ssize_t ret = TEMP_FAILURE_RETRY(writev(fuse->fd, vec, 2));
+    if (ret == -1) {
+        PLOG(ERROR) << "*** REPLY FAILED ***";
+    } else if (static_cast<size_t>(ret) != sizeof(hdr) + len) {
+        LOG(ERROR) << "*** REPLY FAILED: written " << ret << " expected "
+                   << sizeof(hdr) + len << " ***";
+    }
+}
+
+static int fuse_reply_entry(struct fuse* fuse, __u64 unique,
+        struct node* parent, const char* name, const char* actual_name,
+        const char* path)
+{
+    struct node* node;
+    struct fuse_entry_out out;
+    struct stat s;
+
+    if (lstat(path, &s) == -1) {
+        return -errno;
+    }
+
+    pthread_mutex_lock(&fuse->global->lock);
+    node = acquire_or_create_child_locked(fuse, parent, name, actual_name);
+    if (!node) {
+        pthread_mutex_unlock(&fuse->global->lock);
+        return -ENOMEM;
+    }
+    memset(&out, 0, sizeof(out));
+    attr_from_stat(fuse, &out.attr, &s, node);
+    out.attr_valid = 10;
+    out.entry_valid = 10;
+    out.nodeid = node->nid;
+    out.generation = node->gen;
+    pthread_mutex_unlock(&fuse->global->lock);
+    fuse_reply(fuse, unique, &out, sizeof(out));
+    return NO_STATUS;
+}
+
+static int fuse_reply_attr(struct fuse* fuse, __u64 unique, const struct node* node,
+        const char* path)
+{
+    struct fuse_attr_out out;
+    struct stat s;
+
+    if (lstat(path, &s) == -1) {
+        return -errno;
+    }
+    memset(&out, 0, sizeof(out));
+    attr_from_stat(fuse, &out.attr, &s, node);
+    out.attr_valid = 10;
+    fuse_reply(fuse, unique, &out, sizeof(out));
+    return NO_STATUS;
+}
+
+static void fuse_notify_delete(struct fuse* fuse, const __u64 parent,
+        const __u64 child, const char* name) {
+    struct fuse_out_header hdr;
+    struct fuse_notify_delete_out data;
+    size_t namelen = strlen(name);
+    hdr.len = sizeof(hdr) + sizeof(data) + namelen + 1;
+    hdr.error = FUSE_NOTIFY_DELETE;
+    hdr.unique = 0;
+
+    data.parent = parent;
+    data.child = child;
+    data.namelen = namelen;
+    data.padding = 0;
+
+    struct iovec vec[3];
+    vec[0].iov_base = &hdr;
+    vec[0].iov_len = sizeof(hdr);
+    vec[1].iov_base = &data;
+    vec[1].iov_len = sizeof(data);
+    vec[2].iov_base = (void*) name;
+    vec[2].iov_len = namelen + 1;
+
+    ssize_t ret = TEMP_FAILURE_RETRY(writev(fuse->fd, vec, 3));
+    /* Ignore ENOENT, since other views may not have seen the entry */
+    if (ret == -1) {
+        if (errno != ENOENT) {
+            PLOG(ERROR) << "*** NOTIFY FAILED ***";
+        }
+    } else if (static_cast<size_t>(ret) != sizeof(hdr) + sizeof(data) + namelen + 1) {
+        LOG(ERROR) << "*** NOTIFY FAILED: written " << ret << " expected "
+                   << sizeof(hdr) + sizeof(data) + namelen + 1 << " ***";
+    }
+}
+
+static int handle_lookup(struct fuse* fuse, struct fuse_handler* handler,
+        const struct fuse_in_header *hdr, const char* name)
+{
+    struct node* parent_node;
+    char parent_path[PATH_MAX];
+    char child_path[PATH_MAX];
+    const char* actual_name;
+
+    pthread_mutex_lock(&fuse->global->lock);
+    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
+            parent_path, sizeof(parent_path));
+    DLOG(INFO) << "[" << handler->token << "] LOOKUP " << name << " @ " << hdr->nodeid
+               << " (" << (parent_node ? parent_node->name : "?") << ")";
+    pthread_mutex_unlock(&fuse->global->lock);
+
+    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
+            child_path, sizeof(child_path), 1))) {
+        return -ENOENT;
+    }
+    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, R_OK)) {
+        return -EACCES;
+    }
+
+    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
+}
+
+static int handle_forget(struct fuse* fuse, struct fuse_handler* handler,
+        const struct fuse_in_header *hdr, const struct fuse_forget_in *req)
+{
+    struct node* node;
+
+    pthread_mutex_lock(&fuse->global->lock);
+    node = lookup_node_by_id_locked(fuse, hdr->nodeid);
+    DLOG(INFO) << "[" << handler->token << "] FORGET #" << req->nlookup
+               << " @ " << std::hex << hdr->nodeid
+               << " (" << (node ? node->name : "?") << ")";
+    if (node) {
+        __u64 n = req->nlookup;
+        while (n) {
+            n--;
+            release_node_locked(node);
+        }
+    }
+    pthread_mutex_unlock(&fuse->global->lock);
+    return NO_STATUS; /* no reply */
+}
+
+static int handle_getattr(struct fuse* fuse, struct fuse_handler* handler,
+        const struct fuse_in_header *hdr, const struct fuse_getattr_in *req)
+{
+    struct node* node;
+    char path[PATH_MAX];
+
+    pthread_mutex_lock(&fuse->global->lock);
+    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
+    DLOG(INFO) << "[" << handler->token << "] GETATTR flags=" << req->getattr_flags
+               << " fh=" << std::hex << req->fh << " @ " << hdr->nodeid << std::dec
+               << " (" << (node ? node->name : "?") << ")";
+    pthread_mutex_unlock(&fuse->global->lock);
+
+    if (!node) {
+        return -ENOENT;
+    }
+    if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
+        return -EACCES;
+    }
+
+    return fuse_reply_attr(fuse, hdr->unique, node, path);
+}
+
+static int handle_setattr(struct fuse* fuse, struct fuse_handler* handler,
+        const struct fuse_in_header *hdr, const struct fuse_setattr_in *req)
+{
+    struct node* node;
+    char path[PATH_MAX];
+    struct timespec times[2];
+
+    pthread_mutex_lock(&fuse->global->lock);
+    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
+    DLOG(INFO) << "[" << handler->token << "] SETATTR fh=" << std::hex << req->fh
+               << " valid=" << std::hex << req->valid << " @ " << hdr->nodeid << std::dec
+               << " (" << (node ? node->name : "?") << ")";
+    pthread_mutex_unlock(&fuse->global->lock);
+
+    if (!node) {
+        return -ENOENT;
+    }
+
+    if (!(req->valid & FATTR_FH) &&
+            !check_caller_access_to_node(fuse, hdr, node, W_OK)) {
+        return -EACCES;
+    }
+
+    /* XXX: incomplete implementation on purpose.
+     * chmod/chown should NEVER be implemented.*/
+
+    if ((req->valid & FATTR_SIZE) && TEMP_FAILURE_RETRY(truncate64(path, req->size)) == -1) {
+        return -errno;
+    }
+
+    /* Handle changing atime and mtime.  If FATTR_ATIME_and FATTR_ATIME_NOW
+     * are both set, then set it to the current time.  Else, set it to the
+     * time specified in the request.  Same goes for mtime.  Use utimensat(2)
+     * as it allows ATIME and MTIME to be changed independently, and has
+     * nanosecond resolution which fuse also has.
+     */
+    if (req->valid & (FATTR_ATIME | FATTR_MTIME)) {
+        times[0].tv_nsec = UTIME_OMIT;
+        times[1].tv_nsec = UTIME_OMIT;
+        if (req->valid & FATTR_ATIME) {
+            if (req->valid & FATTR_ATIME_NOW) {
+              times[0].tv_nsec = UTIME_NOW;
+            } else {
+              times[0].tv_sec = req->atime;
+              times[0].tv_nsec = req->atimensec;
+            }
+        }
+        if (req->valid & FATTR_MTIME) {
+            if (req->valid & FATTR_MTIME_NOW) {
+              times[1].tv_nsec = UTIME_NOW;
+            } else {
+              times[1].tv_sec = req->mtime;
+              times[1].tv_nsec = req->mtimensec;
+            }
+        }
+        DLOG(INFO) << "[" << handler->token << "] Calling utimensat on " << path
+                   << " with atime " << times[0].tv_sec << ", mtime=" << times[1].tv_sec;
+        if (utimensat(-1, path, times, 0) < 0) {
+            return -errno;
+        }
+    }
+    return fuse_reply_attr(fuse, hdr->unique, node, path);
+}
+
+static int handle_mknod(struct fuse* fuse, struct fuse_handler* handler,
+        const struct fuse_in_header* hdr, const struct fuse_mknod_in* req, const char* name)
+{
+    struct node* parent_node;
+    char parent_path[PATH_MAX];
+    char child_path[PATH_MAX];
+    const char* actual_name;
+
+    pthread_mutex_lock(&fuse->global->lock);
+    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
+            parent_path, sizeof(parent_path));
+    DLOG(INFO) << "[" << handler->token << "] MKNOD " << name << " 0" << std::oct << req->mode
+               << " @ " << std::hex << hdr->nodeid
+               << " (" << (parent_node ? parent_node->name : "?") << ")";
+    pthread_mutex_unlock(&fuse->global->lock);
+
+    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
+            child_path, sizeof(child_path), 1))) {
+        return -ENOENT;
+    }
+    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
+        return -EACCES;
+    }
+    __u32 mode = (req->mode & (~0777)) | 0664;
+    if (mknod(child_path, mode, req->rdev) == -1) {
+        return -errno;
+    }
+    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
+}
+
+static int handle_mkdir(struct fuse* fuse, struct fuse_handler* handler,
+        const struct fuse_in_header* hdr, const struct fuse_mkdir_in* req, const char* name)
+{
+    struct node* parent_node;
+    char parent_path[PATH_MAX];
+    char child_path[PATH_MAX];
+    const char* actual_name;
+
+    pthread_mutex_lock(&fuse->global->lock);
+    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
+            parent_path, sizeof(parent_path));
+    DLOG(INFO) << "[" << handler->token << "] MKDIR " << name << " 0" << std::oct << req->mode
+               << " @ " << std::hex << hdr->nodeid
+               << " (" << (parent_node ? parent_node->name : "?") << ")";
+    pthread_mutex_unlock(&fuse->global->lock);
+
+    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
+            child_path, sizeof(child_path), 1))) {
+        return -ENOENT;
+    }
+    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
+        return -EACCES;
+    }
+    __u32 mode = (req->mode & (~0777)) | 0775;
+    if (mkdir(child_path, mode) == -1) {
+        return -errno;
+    }
+
+    /* When creating /Android/data and /Android/obb, mark them as .nomedia */
+    if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "data")) {
+        char nomedia[PATH_MAX];
+        snprintf(nomedia, PATH_MAX, "%s/.nomedia", child_path);
+        if (touch(nomedia, 0664) != 0) {
+            PLOG(ERROR) << "touch(" << nomedia << ") failed";
+            return -ENOENT;
+        }
+    }
+    if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "obb")) {
+        char nomedia[PATH_MAX];
+        snprintf(nomedia, PATH_MAX, "%s/.nomedia", fuse->global->obb_path);
+        if (touch(nomedia, 0664) != 0) {
+            PLOG(ERROR) << "touch(" << nomedia << ") failed";
+            return -ENOENT;
+        }
+    }
+
+    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
+}
+
+static int handle_unlink(struct fuse* fuse, struct fuse_handler* handler,
+        const struct fuse_in_header* hdr, const char* name)
+{
+    struct node* parent_node;
+    struct node* child_node;
+    char parent_path[PATH_MAX];
+    char child_path[PATH_MAX];
+
+    pthread_mutex_lock(&fuse->global->lock);
+    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
+            parent_path, sizeof(parent_path));
+    DLOG(INFO) << "[" << handler->token << "] UNLINK " << name << " @ " << std::hex << hdr->nodeid
+               << " (" << (parent_node ? parent_node->name : "?") << ")";
+    pthread_mutex_unlock(&fuse->global->lock);
+
+    if (!parent_node || !find_file_within(parent_path, name,
+            child_path, sizeof(child_path), 1)) {
+        return -ENOENT;
+    }
+    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
+        return -EACCES;
+    }
+    if (unlink(child_path) == -1) {
+        return -errno;
+    }
+    pthread_mutex_lock(&fuse->global->lock);
+    child_node = lookup_child_by_name_locked(parent_node, name);
+    if (child_node) {
+        child_node->deleted = true;
+    }
+    pthread_mutex_unlock(&fuse->global->lock);
+    if (parent_node && child_node) {
+        /* Tell all other views that node is gone */
+        DLOG(INFO) << "[" << handler->token << "] fuse_notify_delete"
+                   << " parent=" << std::hex << parent_node->nid
+                   << ", child=" << std::hex << child_node->nid << std::dec
+                   << ", name=" << name;
+        if (fuse != fuse->global->fuse_default) {
+            fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
+        }
+        if (fuse != fuse->global->fuse_read) {
+            fuse_notify_delete(fuse->global->fuse_read, parent_node->nid, child_node->nid, name);
+        }
+        if (fuse != fuse->global->fuse_write) {
+            fuse_notify_delete(fuse->global->fuse_write, parent_node->nid, child_node->nid, name);
+        }
+    }
+    return 0;
+}
+
+static int handle_rmdir(struct fuse* fuse, struct fuse_handler* handler,
+        const struct fuse_in_header* hdr, const char* name)
+{
+    struct node* child_node;
+    struct node* parent_node;
+    char parent_path[PATH_MAX];
+    char child_path[PATH_MAX];
+
+    pthread_mutex_lock(&fuse->global->lock);
+    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
+            parent_path, sizeof(parent_path));
+    DLOG(INFO) << "[" << handler->token << "] UNLINK " << name << " @ " << std::hex << hdr->nodeid
+               << " (" << (parent_node ? parent_node->name : "?") << ")";
+    pthread_mutex_unlock(&fuse->global->lock);
+
+    if (!parent_node || !find_file_within(parent_path, name,
+            child_path, sizeof(child_path), 1)) {
+        return -ENOENT;
+    }
+    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
+        return -EACCES;
+    }
+    if (rmdir(child_path) == -1) {
+        return -errno;
+    }
+    pthread_mutex_lock(&fuse->global->lock);
+    child_node = lookup_child_by_name_locked(parent_node, name);
+    if (child_node) {
+        child_node->deleted = true;
+    }
+    pthread_mutex_unlock(&fuse->global->lock);
+    if (parent_node && child_node) {
+        /* Tell all other views that node is gone */
+        DLOG(INFO) << "[" << handler->token << "] fuse_notify_delete"
+                   << " parent=" << std::hex << parent_node->nid
+                   << ", child=" << std::hex << child_node->nid << std::dec
+                   << ", name=" << name;
+        if (fuse != fuse->global->fuse_default) {
+            fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
+        }
+        if (fuse != fuse->global->fuse_read) {
+            fuse_notify_delete(fuse->global->fuse_read, parent_node->nid, child_node->nid, name);
+        }
+        if (fuse != fuse->global->fuse_write) {
+            fuse_notify_delete(fuse->global->fuse_write, parent_node->nid, child_node->nid, name);
+        }
+    }
+    return 0;
+}
+
+static int handle_rename(struct fuse* fuse, struct fuse_handler* handler,
+        const struct fuse_in_header* hdr, const struct fuse_rename_in* req,
+        const char* old_name, const char* new_name)
+{
+    struct node* old_parent_node;
+    struct node* new_parent_node;
+    struct node* child_node;
+    char old_parent_path[PATH_MAX];
+    char new_parent_path[PATH_MAX];
+    char old_child_path[PATH_MAX];
+    char new_child_path[PATH_MAX];
+    const char* new_actual_name;
+    int search;
+    int res;
+
+    pthread_mutex_lock(&fuse->global->lock);
+    old_parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
+            old_parent_path, sizeof(old_parent_path));
+    new_parent_node = lookup_node_and_path_by_id_locked(fuse, req->newdir,
+            new_parent_path, sizeof(new_parent_path));
+    DLOG(INFO) << "[" << handler->token << "] RENAME " << old_name << "->" << new_name
+               << " @ " << std::hex << hdr->nodeid
+               << " (" << (old_parent_node ? old_parent_node->name : "?") << ") -> "
+               << std::hex << req->newdir
+               << " (" << (new_parent_node ? new_parent_node->name : "?") << ")";
+    if (!old_parent_node || !new_parent_node) {
+        res = -ENOENT;
+        goto lookup_error;
+    }
+    if (!check_caller_access_to_name(fuse, hdr, old_parent_node, old_name, W_OK)) {
+        res = -EACCES;
+        goto lookup_error;
+    }
+    if (!check_caller_access_to_name(fuse, hdr, new_parent_node, new_name, W_OK)) {
+        res = -EACCES;
+        goto lookup_error;
+    }
+    child_node = lookup_child_by_name_locked(old_parent_node, old_name);
+    if (!child_node || get_node_path_locked(child_node,
+            old_child_path, sizeof(old_child_path)) < 0) {
+        res = -ENOENT;
+        goto lookup_error;
+    }
+    acquire_node_locked(child_node);
+    pthread_mutex_unlock(&fuse->global->lock);
+
+    /* Special case for renaming a file where destination is same path
+     * differing only by case.  In this case we don't want to look for a case
+     * insensitive match.  This allows commands like "mv foo FOO" to work as expected.
+     */
+    search = old_parent_node != new_parent_node
+            || strcasecmp(old_name, new_name);
+    if (!(new_actual_name = find_file_within(new_parent_path, new_name,
+            new_child_path, sizeof(new_child_path), search))) {
+        res = -ENOENT;
+        goto io_error;
+    }
+
+    DLOG(INFO) << "[" << handler->token << "] RENAME " << old_child_path << "->" << new_child_path;
+    res = rename(old_child_path, new_child_path);
+    if (res == -1) {
+        res = -errno;
+        goto io_error;
+    }
+
+    pthread_mutex_lock(&fuse->global->lock);
+    res = rename_node_locked(child_node, new_name, new_actual_name);
+    if (!res) {
+        remove_node_from_parent_locked(child_node);
+        derive_permissions_locked(fuse, new_parent_node, child_node);
+        derive_permissions_recursive_locked(fuse, child_node);
+        add_node_to_parent_locked(child_node, new_parent_node);
+    }
+    goto done;
+
+io_error:
+    pthread_mutex_lock(&fuse->global->lock);
+done:
+    release_node_locked(child_node);
+lookup_error:
+    pthread_mutex_unlock(&fuse->global->lock);
+    return res;
+}
+
+static int open_flags_to_access_mode(int open_flags) {
+    if ((open_flags & O_ACCMODE) == O_RDONLY) {
+        return R_OK;
+    } else if ((open_flags & O_ACCMODE) == O_WRONLY) {
+        return W_OK;
+    } else {
+        /* Probably O_RDRW, but treat as default to be safe */
+        return R_OK | W_OK;
+    }
+}
+
+static int handle_open(struct fuse* fuse, struct fuse_handler* handler,
+        const struct fuse_in_header* hdr, const struct fuse_open_in* req)
+{
+    struct node* node;
+    char path[PATH_MAX];
+    struct fuse_open_out out;
+    struct handle *h;
+
+    pthread_mutex_lock(&fuse->global->lock);
+    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
+    DLOG(INFO) << "[" << handler->token << "] OPEN 0" << std::oct << req->flags
+               << " @ " << std::hex << hdr->nodeid << std::dec
+               << " (" << (node ? node->name : "?") << ")";
+    pthread_mutex_unlock(&fuse->global->lock);
+
+    if (!node) {
+        return -ENOENT;
+    }
+    if (!check_caller_access_to_node(fuse, hdr, node,
+            open_flags_to_access_mode(req->flags))) {
+        return -EACCES;
+    }
+    h = static_cast<struct handle*>(malloc(sizeof(*h)));
+    if (!h) {
+        return -ENOMEM;
+    }
+    DLOG(INFO) << "[" << handler->token << "] OPEN " << path;
+    h->fd = TEMP_FAILURE_RETRY(open(path, req->flags));
+    if (h->fd == -1) {
+        free(h);
+        return -errno;
+    }
+    out.fh = ptr_to_id(h);
+    out.open_flags = 0;
+
+#ifdef FUSE_SHORTCIRCUIT
+    out.lower_fd = h->fd;
+#else
+    out.padding = 0;
+#endif
+
+    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
+    return NO_STATUS;
+}
+
+static int handle_read(struct fuse* fuse, struct fuse_handler* handler,
+        const struct fuse_in_header* hdr, const struct fuse_read_in* req)
+{
+    struct handle *h = static_cast<struct handle*>(id_to_ptr(req->fh));
+    __u64 unique = hdr->unique;
+    __u32 size = req->size;
+    __u64 offset = req->offset;
+    int res;
+    __u8 *read_buffer = (__u8 *) ((uintptr_t)(handler->read_buffer + PAGE_SIZE) & ~((uintptr_t)PAGE_SIZE-1));
+
+    /* Don't access any other fields of hdr or req beyond this point, the read buffer
+     * overlaps the request buffer and will clobber data in the request.  This
+     * saves us 128KB per request handler thread at the cost of this scary comment. */
+
+    DLOG(INFO) << "[" << handler->token << "] READ " << std::hex << h << std::dec
+               << "(" << h->fd << ") " << size << "@" << offset;
+    if (size > MAX_READ) {
+        return -EINVAL;
+    }
+    res = TEMP_FAILURE_RETRY(pread64(h->fd, read_buffer, size, offset));
+    if (res == -1) {
+        return -errno;
+    }
+    fuse_reply(fuse, unique, read_buffer, res);
+    return NO_STATUS;
+}
+
+static int handle_write(struct fuse* fuse, struct fuse_handler* handler,
+        const struct fuse_in_header* hdr, const struct fuse_write_in* req,
+        const void* buffer)
+{
+    struct fuse_write_out out;
+    struct handle *h = static_cast<struct handle*>(id_to_ptr(req->fh));
+    int res;
+    __u8 aligned_buffer[req->size] __attribute__((__aligned__(PAGE_SIZE)));
+
+    if (req->flags & O_DIRECT) {
+        memcpy(aligned_buffer, buffer, req->size);
+        buffer = (const __u8*) aligned_buffer;
+    }
+
+    DLOG(INFO) << "[" << handler->token << "] WRITE " << std::hex << h << std::dec
+               << "(" << h->fd << ") " << req->size << "@" << req->offset;
+    res = TEMP_FAILURE_RETRY(pwrite64(h->fd, buffer, req->size, req->offset));
+    if (res == -1) {
+        return -errno;
+    }
+    out.size = res;
+    out.padding = 0;
+    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
+    return NO_STATUS;
+}
+
+static int handle_statfs(struct fuse* fuse, struct fuse_handler* handler,
+        const struct fuse_in_header* hdr)
+{
+    char path[PATH_MAX];
+    struct statfs stat;
+    struct fuse_statfs_out out;
+    int res;
+
+    pthread_mutex_lock(&fuse->global->lock);
+    DLOG(INFO) << "[" << handler->token << "] STATFS";
+    res = get_node_path_locked(&fuse->global->root, path, sizeof(path));
+    pthread_mutex_unlock(&fuse->global->lock);
+    if (res < 0) {
+        return -ENOENT;
+    }
+    if (TEMP_FAILURE_RETRY(statfs(fuse->global->root.name, &stat)) == -1) {
+        return -errno;
+    }
+    memset(&out, 0, sizeof(out));
+    out.st.blocks = stat.f_blocks;
+    out.st.bfree = stat.f_bfree;
+    out.st.bavail = stat.f_bavail;
+    out.st.files = stat.f_files;
+    out.st.ffree = stat.f_ffree;
+    out.st.bsize = stat.f_bsize;
+    out.st.namelen = stat.f_namelen;
+    out.st.frsize = stat.f_frsize;
+    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
+    return NO_STATUS;
+}
+
+static int handle_release(struct fuse* fuse, struct fuse_handler* handler,
+        const struct fuse_in_header* hdr, const struct fuse_release_in* req)
+{
+    struct handle *h = static_cast<struct handle*>(id_to_ptr(req->fh));
+
+    DLOG(INFO) << "[" << handler->token << "] RELEASE " << std::hex << h << std::dec
+               << "(" << h->fd << ")";
+    close(h->fd);
+    free(h);
+    return 0;
+}
+
+static int handle_fsync(struct fuse* fuse, struct fuse_handler* handler,
+        const struct fuse_in_header* hdr, const struct fuse_fsync_in* req)
+{
+    bool is_dir = (hdr->opcode == FUSE_FSYNCDIR);
+    bool is_data_sync = req->fsync_flags & 1;
+
+    int fd = -1;
+    if (is_dir) {
+      struct dirhandle *dh = static_cast<struct dirhandle*>(id_to_ptr(req->fh));
+      fd = dirfd(dh->d);
+    } else {
+      struct handle *h = static_cast<struct handle*>(id_to_ptr(req->fh));
+      fd = h->fd;
+    }
+
+    DLOG(INFO) << "[" << handler->token << "] " << (is_dir ? "FSYNCDIR" : "FSYNC") << " "
+               << std::hex << req->fh << std::dec << "(" << fd << ") is_data_sync=" << is_data_sync;
+    int res = is_data_sync ? fdatasync(fd) : fsync(fd);
+    if (res == -1) {
+        return -errno;
+    }
+    return 0;
+}
+
+static int handle_flush(struct fuse* fuse, struct fuse_handler* handler,
+        const struct fuse_in_header* hdr)
+{
+    DLOG(INFO) << "[" << handler->token << "] FLUSH";
+    return 0;
+}
+
+static int handle_opendir(struct fuse* fuse, struct fuse_handler* handler,
+        const struct fuse_in_header* hdr, const struct fuse_open_in* req)
+{
+    struct node* node;
+    char path[PATH_MAX];
+    struct fuse_open_out out;
+    struct dirhandle *h;
+
+    pthread_mutex_lock(&fuse->global->lock);
+    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
+    DLOG(INFO) << "[" << handler->token << "] OPENDIR @ " << std::hex << hdr->nodeid
+               << " (" << (node ? node->name : "?") << ")";
+    pthread_mutex_unlock(&fuse->global->lock);
+
+    if (!node) {
+        return -ENOENT;
+    }
+    if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
+        return -EACCES;
+    }
+    h = static_cast<struct dirhandle*>(malloc(sizeof(*h)));
+    if (!h) {
+        return -ENOMEM;
+    }
+    DLOG(INFO) << "[" << handler->token << "] OPENDIR " << path;
+    h->d = opendir(path);
+    if (!h->d) {
+        free(h);
+        return -errno;
+    }
+    out.fh = ptr_to_id(h);
+    out.open_flags = 0;
+
+#ifdef FUSE_SHORTCIRCUIT
+    out.lower_fd = -1;
+#else
+    out.padding = 0;
+#endif
+
+    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
+    return NO_STATUS;
+}
+
+static int handle_readdir(struct fuse* fuse, struct fuse_handler* handler,
+        const struct fuse_in_header* hdr, const struct fuse_read_in* req)
+{
+    char buffer[8192];
+    struct fuse_dirent *fde = (struct fuse_dirent*) buffer;
+    struct dirent *de;
+    struct dirhandle *h = static_cast<struct dirhandle*>(id_to_ptr(req->fh));
+
+    DLOG(INFO) << "[" << handler->token << "] READDIR " << h;
+    if (req->offset == 0) {
+        /* rewinddir() might have been called above us, so rewind here too */
+        DLOG(INFO) << "[" << handler->token << "] calling rewinddir()";
+        rewinddir(h->d);
+    }
+    de = readdir(h->d);
+    if (!de) {
+        return 0;
+    }
+    fde->ino = FUSE_UNKNOWN_INO;
+    /* increment the offset so we can detect when rewinddir() seeks back to the beginning */
+    fde->off = req->offset + 1;
+    fde->type = de->d_type;
+    fde->namelen = strlen(de->d_name);
+    memcpy(fde->name, de->d_name, fde->namelen + 1);
+    fuse_reply(fuse, hdr->unique, fde,
+            FUSE_DIRENT_ALIGN(sizeof(struct fuse_dirent) + fde->namelen));
+    return NO_STATUS;
+}
+
+static int handle_releasedir(struct fuse* fuse, struct fuse_handler* handler,
+        const struct fuse_in_header* hdr, const struct fuse_release_in* req)
+{
+    struct dirhandle *h = static_cast<struct dirhandle*>(id_to_ptr(req->fh));
+
+    DLOG(INFO) << "[" << handler->token << "] RELEASEDIR " << h;
+    closedir(h->d);
+    free(h);
+    return 0;
+}
+
+static int handle_init(struct fuse* fuse, struct fuse_handler* handler,
+        const struct fuse_in_header* hdr, const struct fuse_init_in* req)
+{
+    struct fuse_init_out out;
+    size_t fuse_struct_size;
+
+    DLOG(INFO) << "[" << handler->token << "] INIT ver=" << req->major << "." << req->minor
+               << " maxread=" << req->max_readahead << " flags=" << std::hex << req->flags;
+
+    /* Kernel 2.6.16 is the first stable kernel with struct fuse_init_out
+     * defined (fuse version 7.6). The structure is the same from 7.6 through
+     * 7.22. Beginning with 7.23, the structure increased in size and added
+     * new parameters.
+     */
+    if (req->major != FUSE_KERNEL_VERSION || req->minor < 6) {
+        LOG(ERROR) << "Fuse kernel version mismatch: Kernel version "
+                   << req->major << "." << req->minor
+                   << ", Expected at least " << FUSE_KERNEL_VERSION << ".6";
+        return -1;
+    }
+
+    /* We limit ourselves to 15 because we don't handle BATCH_FORGET yet */
+    out.minor = MIN(req->minor, 15);
+    fuse_struct_size = sizeof(out);
+#if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
+    /* FUSE_KERNEL_VERSION >= 23. */
+
+    /* Since we return minor version 15, the kernel does not accept the latest
+     * fuse_init_out size. We need to use FUSE_COMPAT_22_INIT_OUT_SIZE always.*/
+    fuse_struct_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
+#endif
+
+    out.major = FUSE_KERNEL_VERSION;
+    out.max_readahead = req->max_readahead;
+    out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
+
+#ifdef FUSE_SHORTCIRCUIT
+    out.flags |= FUSE_SHORTCIRCUIT;
+#endif
+
+    out.max_background = 32;
+    out.congestion_threshold = 32;
+    out.max_write = MAX_WRITE;
+    fuse_reply(fuse, hdr->unique, &out, fuse_struct_size);
+    return NO_STATUS;
+}
+
+static int handle_canonical_path(struct fuse* fuse, struct fuse_handler* handler,
+        const struct fuse_in_header *hdr)
+{
+    struct node* node;
+    char path[PATH_MAX];
+    int len;
+
+    pthread_mutex_lock(&fuse->global->lock);
+    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
+            path, sizeof(path));
+    DLOG(INFO) << "[" << handler->token << "] CANONICAL_PATH @ " << std::hex << hdr->nodeid
+               << std::dec << " (" << (node ? node->name : "?") << ")";
+    pthread_mutex_unlock(&fuse->global->lock);
+
+    if (!node) {
+        return -ENOENT;
+    }
+    if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
+        return -EACCES;
+    }
+    len = strlen(path);
+    if (len + 1 > PATH_MAX)
+        len = PATH_MAX - 1;
+    path[PATH_MAX - 1] = 0;
+    fuse_reply(fuse, hdr->unique, path, len + 1);
+    return NO_STATUS;
+}
+
+static int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler,
+        const struct fuse_in_header *hdr, const void *data, size_t data_len)
+{
+    switch (hdr->opcode) {
+    case FUSE_LOOKUP: { /* bytez[] -> entry_out */
+        const char *name = static_cast<const char*>(data);
+        return handle_lookup(fuse, handler, hdr, name);
+    }
+
+    case FUSE_FORGET: {
+        const struct fuse_forget_in *req = static_cast<const struct fuse_forget_in*>(data);
+        return handle_forget(fuse, handler, hdr, req);
+    }
+
+    case FUSE_GETATTR: { /* getattr_in -> attr_out */
+        const struct fuse_getattr_in *req = static_cast<const struct fuse_getattr_in*>(data);
+        return handle_getattr(fuse, handler, hdr, req);
+    }
+
+    case FUSE_SETATTR: { /* setattr_in -> attr_out */
+        const struct fuse_setattr_in *req = static_cast<const struct fuse_setattr_in*>(data);
+        return handle_setattr(fuse, handler, hdr, req);
+    }
+
+//    case FUSE_READLINK:
+//    case FUSE_SYMLINK:
+    case FUSE_MKNOD: { /* mknod_in, bytez[] -> entry_out */
+        const struct fuse_mknod_in *req = static_cast<const struct fuse_mknod_in*>(data);
+        const char *name = ((const char*) data) + sizeof(*req);
+        return handle_mknod(fuse, handler, hdr, req, name);
+    }
+
+    case FUSE_MKDIR: { /* mkdir_in, bytez[] -> entry_out */
+        const struct fuse_mkdir_in *req = static_cast<const struct fuse_mkdir_in*>(data);
+        const char *name = ((const char*) data) + sizeof(*req);
+        return handle_mkdir(fuse, handler, hdr, req, name);
+    }
+
+    case FUSE_UNLINK: { /* bytez[] -> */
+        const char *name = static_cast<const char*>(data);
+        return handle_unlink(fuse, handler, hdr, name);
+    }
+
+    case FUSE_RMDIR: { /* bytez[] -> */
+        const char *name = static_cast<const char*>(data);
+        return handle_rmdir(fuse, handler, hdr, name);
+    }
+
+    case FUSE_RENAME: { /* rename_in, oldname, newname ->  */
+        const struct fuse_rename_in *req = static_cast<const struct fuse_rename_in*>(data);
+        const char *old_name = ((const char*) data) + sizeof(*req);
+        const char *new_name = old_name + strlen(old_name) + 1;
+        return handle_rename(fuse, handler, hdr, req, old_name, new_name);
+    }
+
+//    case FUSE_LINK:
+    case FUSE_OPEN: { /* open_in -> open_out */
+        const struct fuse_open_in *req = static_cast<const struct fuse_open_in*>(data);
+        return handle_open(fuse, handler, hdr, req);
+    }
+
+    case FUSE_READ: { /* read_in -> byte[] */
+        const struct fuse_read_in *req = static_cast<const struct fuse_read_in*>(data);
+        return handle_read(fuse, handler, hdr, req);
+    }
+
+    case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */
+        const struct fuse_write_in *req = static_cast<const struct fuse_write_in*>(data);
+        const void* buffer = (const __u8*)data + sizeof(*req);
+        return handle_write(fuse, handler, hdr, req, buffer);
+    }
+
+    case FUSE_STATFS: { /* getattr_in -> attr_out */
+        return handle_statfs(fuse, handler, hdr);
+    }
+
+    case FUSE_RELEASE: { /* release_in -> */
+        const struct fuse_release_in *req = static_cast<const struct fuse_release_in*>(data);
+        return handle_release(fuse, handler, hdr, req);
+    }
+
+    case FUSE_FSYNC:
+    case FUSE_FSYNCDIR: {
+        const struct fuse_fsync_in *req = static_cast<const struct fuse_fsync_in*>(data);
+        return handle_fsync(fuse, handler, hdr, req);
+    }
+
+//    case FUSE_SETXATTR:
+//    case FUSE_GETXATTR:
+//    case FUSE_LISTXATTR:
+//    case FUSE_REMOVEXATTR:
+    case FUSE_FLUSH: {
+        return handle_flush(fuse, handler, hdr);
+    }
+
+    case FUSE_OPENDIR: { /* open_in -> open_out */
+        const struct fuse_open_in *req = static_cast<const struct fuse_open_in*>(data);
+        return handle_opendir(fuse, handler, hdr, req);
+    }
+
+    case FUSE_READDIR: {
+        const struct fuse_read_in *req = static_cast<const struct fuse_read_in*>(data);
+        return handle_readdir(fuse, handler, hdr, req);
+    }
+
+    case FUSE_RELEASEDIR: { /* release_in -> */
+        const struct fuse_release_in *req = static_cast<const struct fuse_release_in*>(data);
+        return handle_releasedir(fuse, handler, hdr, req);
+    }
+
+    case FUSE_INIT: { /* init_in -> init_out */
+        const struct fuse_init_in *req = static_cast<const struct fuse_init_in*>(data);
+        return handle_init(fuse, handler, hdr, req);
+    }
+
+    case FUSE_CANONICAL_PATH: { /* nodeid -> bytez[] */
+        return handle_canonical_path(fuse, handler, hdr);
+    }
+
+    default: {
+        DLOG(INFO) << "[" << handler->token << "] NOTIMPL op=" << hdr->opcode
+                   << "uniq=" << std::hex << hdr->unique << "nid=" << hdr->nodeid << std::dec;
+        return -ENOSYS;
+    }
+    }
+}
+
+void handle_fuse_requests(struct fuse_handler* handler)
+{
+    struct fuse* fuse = handler->fuse;
+    for (;;) {
+        ssize_t len = TEMP_FAILURE_RETRY(read(fuse->fd,
+                handler->request_buffer, sizeof(handler->request_buffer)));
+        if (len == -1) {
+            if (errno == ENODEV) {
+                LOG(ERROR) << "[" << handler->token << "] someone stole our marbles!";
+                exit(2);
+            }
+            PLOG(ERROR) << "[" << handler->token << "] handle_fuse_requests";
+            continue;
+        }
+
+        if (static_cast<size_t>(len) < sizeof(struct fuse_in_header)) {
+            LOG(ERROR) << "[" << handler->token << "] request too short: len=" << len;
+            continue;
+        }
+
+        const struct fuse_in_header* hdr =
+            reinterpret_cast<const struct fuse_in_header*>(handler->request_buffer);
+        if (hdr->len != static_cast<size_t>(len)) {
+            LOG(ERROR) << "[" << handler->token << "] malformed header: len=" << len
+                       << ", hdr->len=" << hdr->len;
+            continue;
+        }
+
+        const void *data = handler->request_buffer + sizeof(struct fuse_in_header);
+        size_t data_len = len - sizeof(struct fuse_in_header);
+        __u64 unique = hdr->unique;
+        int res = handle_fuse_request(fuse, handler, hdr, data, data_len);
+
+        /* We do not access the request again after this point because the underlying
+         * buffer storage may have been reused while processing the request. */
+
+        if (res != NO_STATUS) {
+            if (res) {
+                DLOG(INFO) << "[" << handler->token << "] ERROR " << res;
+            }
+            fuse_status(fuse, unique, res);
+        }
+    }
+}
diff --git a/sdcard/fuse.h b/sdcard/fuse.h
new file mode 100644
index 0000000..9ccd21d
--- /dev/null
+++ b/sdcard/fuse.h
@@ -0,0 +1,209 @@
+/*
+ * 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.
+ */
+
+#ifndef FUSE_H_
+#define FUSE_H_
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <linux/fuse.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+#include <map>
+#include <string>
+
+#include <android-base/logging.h>
+#include <cutils/fs.h>
+#include <cutils/multiuser.h>
+#include <packagelistparser/packagelistparser.h>
+
+#include <private/android_filesystem_config.h>
+
+#define FUSE_TRACE 0
+
+#if FUSE_TRACE
+static constexpr bool kEnableDLog = true;
+#else  // FUSE_TRACE == 0
+static constexpr bool kEnableDLog = false;
+#endif
+
+// Use same strategy as DCHECK().
+#define DLOG(x) \
+    if (kEnableDLog) LOG(x)
+
+/* Maximum number of bytes to write in one request. */
+#define MAX_WRITE (256 * 1024)
+
+/* Maximum number of bytes to read in one request. */
+#define MAX_READ (128 * 1024)
+
+/* Largest possible request.
+ * The request size is bounded by the maximum size of a FUSE_WRITE request because it has
+ * the largest possible data payload. */
+#define MAX_REQUEST_SIZE (sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in) + MAX_WRITE)
+
+namespace {
+struct CaseInsensitiveCompare {
+    bool operator()(const std::string& lhs, const std::string& rhs) const {
+        return strcasecmp(lhs.c_str(), rhs.c_str()) < 0;
+    }
+};
+}
+
+using AppIdMap = std::map<std::string, appid_t, CaseInsensitiveCompare>;
+
+/* Permission mode for a specific node. Controls how file permissions
+ * are derived for children nodes. */
+typedef enum {
+    /* Nothing special; this node should just inherit from its parent. */
+    PERM_INHERIT,
+    /* This node is one level above a normal root; used for legacy layouts
+     * which use the first level to represent user_id. */
+    PERM_PRE_ROOT,
+    /* This node is "/" */
+    PERM_ROOT,
+    /* This node is "/Android" */
+    PERM_ANDROID,
+    /* This node is "/Android/data" */
+    PERM_ANDROID_DATA,
+    /* This node is "/Android/obb" */
+    PERM_ANDROID_OBB,
+    /* This node is "/Android/media" */
+    PERM_ANDROID_MEDIA,
+} perm_t;
+
+struct handle {
+    int fd;
+};
+
+struct dirhandle {
+    DIR *d;
+};
+
+struct node {
+    __u32 refcount;
+    __u64 nid;
+    __u64 gen;
+    /*
+     * The inode number for this FUSE node. Note that this isn't stable across
+     * multiple invocations of the FUSE daemon.
+     */
+    __u32 ino;
+
+    /* State derived based on current position in hierarchy. */
+    perm_t perm;
+    userid_t userid;
+    uid_t uid;
+    bool under_android;
+
+    struct node *next;          /* per-dir sibling list */
+    struct node *child;         /* first contained file by this dir */
+    struct node *parent;        /* containing directory */
+
+    size_t namelen;
+    char *name;
+    /* If non-null, this is the real name of the file in the underlying storage.
+     * This may differ from the field "name" only by case.
+     * strlen(actual_name) will always equal strlen(name), so it is safe to use
+     * namelen for both fields.
+     */
+    char *actual_name;
+
+    /* If non-null, an exact underlying path that should be grafted into this
+     * position. Used to support things like OBB. */
+    char* graft_path;
+    size_t graft_pathlen;
+
+    bool deleted;
+};
+
+/* Global data for all FUSE mounts */
+struct fuse_global {
+    pthread_mutex_t lock;
+
+    uid_t uid;
+    gid_t gid;
+    bool multi_user;
+
+    char source_path[PATH_MAX];
+    char obb_path[PATH_MAX];
+
+    AppIdMap* package_to_appid;
+
+    __u64 next_generation;
+    struct node root;
+
+    /* Used to allocate unique inode numbers for fuse nodes. We use
+     * a simple counter based scheme where inode numbers from deleted
+     * nodes aren't reused. Note that inode allocations are not stable
+     * across multiple invocation of the sdcard daemon, but that shouldn't
+     * be a huge problem in practice.
+     *
+     * Note that we restrict inodes to 32 bit unsigned integers to prevent
+     * truncation on 32 bit processes when unsigned long long stat.st_ino is
+     * assigned to an unsigned long ino_t type in an LP32 process.
+     *
+     * Also note that fuse_attr and fuse_dirent inode values are 64 bits wide
+     * on both LP32 and LP64, but the fuse kernel code doesn't squash 64 bit
+     * inode numbers into 32 bit values on 64 bit kernels (see fuse_squash_ino
+     * in fs/fuse/inode.c).
+     *
+     * Accesses must be guarded by |lock|.
+     */
+    __u32 inode_ctr;
+
+    struct fuse* fuse_default;
+    struct fuse* fuse_read;
+    struct fuse* fuse_write;
+};
+
+/* Single FUSE mount */
+struct fuse {
+    struct fuse_global* global;
+
+    char dest_path[PATH_MAX];
+
+    int fd;
+
+    gid_t gid;
+    mode_t mask;
+};
+
+/* Private data used by a single FUSE handler */
+struct fuse_handler {
+    struct fuse* fuse;
+    int token;
+
+    /* To save memory, we never use the contents of the request buffer and the read
+     * buffer at the same time.  This allows us to share the underlying storage. */
+    union {
+        __u8 request_buffer[MAX_REQUEST_SIZE];
+        __u8 read_buffer[MAX_READ + PAGE_SIZE];
+    };
+};
+
+void handle_fuse_requests(struct fuse_handler* handler);
+void derive_permissions_recursive_locked(struct fuse* fuse, struct node *parent);
+
+#endif  /* FUSE_H_ */
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
deleted file mode 100644
index 13ebaf1..0000000
--- a/sdcard/sdcard.c
+++ /dev/null
@@ -1,2154 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "sdcard"
-
-#include <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <linux/fuse.h>
-#include <pthread.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/inotify.h>
-#include <sys/mount.h>
-#include <sys/param.h>
-#include <sys/resource.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
-
-#include <cutils/fs.h>
-#include <cutils/hashmap.h>
-#include <cutils/log.h>
-#include <cutils/multiuser.h>
-#include <cutils/properties.h>
-#include <packagelistparser/packagelistparser.h>
-
-#include <private/android_filesystem_config.h>
-
-/* FUSE_CANONICAL_PATH is not currently upstreamed */
-#define FUSE_CANONICAL_PATH 2016
-
-/* README
- *
- * What is this?
- *
- * sdcard is a program that uses FUSE to emulate FAT-on-sdcard style
- * directory permissions (all files are given fixed owner, group, and
- * permissions at creation, owner, group, and permissions are not
- * changeable, symlinks and hardlinks are not createable, etc.
- *
- * See usage() for command line options.
- *
- * It must be run as root, but will drop to requested UID/GID as soon as it
- * mounts a filesystem.  It will refuse to run if requested UID/GID are zero.
- *
- * Things I believe to be true:
- *
- * - ops that return a fuse_entry (LOOKUP, MKNOD, MKDIR, LINK, SYMLINK,
- * CREAT) must bump that node's refcount
- * - don't forget that FORGET can forget multiple references (req->nlookup)
- * - if an op that returns a fuse_entry fails writing the reply to the
- * kernel, you must rollback the refcount to reflect the reference the
- * kernel did not actually acquire
- *
- * This daemon can also derive custom filesystem permissions based on directory
- * structure when requested. These custom permissions support several features:
- *
- * - Apps can access their own files in /Android/data/com.example/ without
- * requiring any additional GIDs.
- * - Separate permissions for protecting directories like Pictures and Music.
- * - Multi-user separation on the same physical device.
- */
-
-#define FUSE_TRACE 0
-
-#if FUSE_TRACE
-#define TRACE(x...) ALOGD(x)
-#else
-#define TRACE(x...) do {} while (0)
-#endif
-
-#define ERROR(x...) ALOGE(x)
-
-#define PROP_SDCARDFS_DEVICE "ro.sys.sdcardfs"
-#define PROP_SDCARDFS_USER "persist.sys.sdcardfs"
-
-#define FUSE_UNKNOWN_INO 0xffffffff
-
-/* Maximum number of bytes to write in one request. */
-#define MAX_WRITE (256 * 1024)
-
-/* Maximum number of bytes to read in one request. */
-#define MAX_READ (128 * 1024)
-
-/* Largest possible request.
- * The request size is bounded by the maximum size of a FUSE_WRITE request because it has
- * the largest possible data payload. */
-#define MAX_REQUEST_SIZE (sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in) + MAX_WRITE)
-
-/* Pseudo-error constant used to indicate that no fuse status is needed
- * or that a reply has already been written. */
-#define NO_STATUS 1
-
-/* Supplementary groups to execute with */
-static const gid_t kGroups[1] = { AID_PACKAGE_INFO };
-
-/* Permission mode for a specific node. Controls how file permissions
- * are derived for children nodes. */
-typedef enum {
-    /* Nothing special; this node should just inherit from its parent. */
-    PERM_INHERIT,
-    /* This node is one level above a normal root; used for legacy layouts
-     * which use the first level to represent user_id. */
-    PERM_PRE_ROOT,
-    /* This node is "/" */
-    PERM_ROOT,
-    /* This node is "/Android" */
-    PERM_ANDROID,
-    /* This node is "/Android/data" */
-    PERM_ANDROID_DATA,
-    /* This node is "/Android/obb" */
-    PERM_ANDROID_OBB,
-    /* This node is "/Android/media" */
-    PERM_ANDROID_MEDIA,
-} perm_t;
-
-struct handle {
-    int fd;
-};
-
-struct dirhandle {
-    DIR *d;
-};
-
-struct node {
-    __u32 refcount;
-    __u64 nid;
-    __u64 gen;
-    /*
-     * The inode number for this FUSE node. Note that this isn't stable across
-     * multiple invocations of the FUSE daemon.
-     */
-    __u32 ino;
-
-    /* State derived based on current position in hierarchy. */
-    perm_t perm;
-    userid_t userid;
-    uid_t uid;
-    bool under_android;
-
-    struct node *next;          /* per-dir sibling list */
-    struct node *child;         /* first contained file by this dir */
-    struct node *parent;        /* containing directory */
-
-    size_t namelen;
-    char *name;
-    /* If non-null, this is the real name of the file in the underlying storage.
-     * This may differ from the field "name" only by case.
-     * strlen(actual_name) will always equal strlen(name), so it is safe to use
-     * namelen for both fields.
-     */
-    char *actual_name;
-
-    /* If non-null, an exact underlying path that should be grafted into this
-     * position. Used to support things like OBB. */
-    char* graft_path;
-    size_t graft_pathlen;
-
-    bool deleted;
-};
-
-static int str_hash(void *key) {
-    return hashmapHash(key, strlen(key));
-}
-
-/** Test if two string keys are equal ignoring case */
-static bool str_icase_equals(void *keyA, void *keyB) {
-    return strcasecmp(keyA, keyB) == 0;
-}
-
-/* Global data for all FUSE mounts */
-struct fuse_global {
-    pthread_mutex_t lock;
-
-    uid_t uid;
-    gid_t gid;
-    bool multi_user;
-
-    char source_path[PATH_MAX];
-    char obb_path[PATH_MAX];
-
-    Hashmap* package_to_appid;
-
-    __u64 next_generation;
-    struct node root;
-
-    /* Used to allocate unique inode numbers for fuse nodes. We use
-     * a simple counter based scheme where inode numbers from deleted
-     * nodes aren't reused. Note that inode allocations are not stable
-     * across multiple invocation of the sdcard daemon, but that shouldn't
-     * be a huge problem in practice.
-     *
-     * Note that we restrict inodes to 32 bit unsigned integers to prevent
-     * truncation on 32 bit processes when unsigned long long stat.st_ino is
-     * assigned to an unsigned long ino_t type in an LP32 process.
-     *
-     * Also note that fuse_attr and fuse_dirent inode values are 64 bits wide
-     * on both LP32 and LP64, but the fuse kernel code doesn't squash 64 bit
-     * inode numbers into 32 bit values on 64 bit kernels (see fuse_squash_ino
-     * in fs/fuse/inode.c).
-     *
-     * Accesses must be guarded by |lock|.
-     */
-    __u32 inode_ctr;
-
-    struct fuse* fuse_default;
-    struct fuse* fuse_read;
-    struct fuse* fuse_write;
-};
-
-/* Single FUSE mount */
-struct fuse {
-    struct fuse_global* global;
-
-    char dest_path[PATH_MAX];
-
-    int fd;
-
-    gid_t gid;
-    mode_t mask;
-};
-
-/* Private data used by a single FUSE handler */
-struct fuse_handler {
-    struct fuse* fuse;
-    int token;
-
-    /* To save memory, we never use the contents of the request buffer and the read
-     * buffer at the same time.  This allows us to share the underlying storage. */
-    union {
-        __u8 request_buffer[MAX_REQUEST_SIZE];
-        __u8 read_buffer[MAX_READ + PAGE_SIZE];
-    };
-};
-
-static inline void *id_to_ptr(__u64 nid)
-{
-    return (void *) (uintptr_t) nid;
-}
-
-static inline __u64 ptr_to_id(void *ptr)
-{
-    return (__u64) (uintptr_t) ptr;
-}
-
-static void acquire_node_locked(struct node* node)
-{
-    node->refcount++;
-    TRACE("ACQUIRE %p (%s) rc=%d\n", node, node->name, node->refcount);
-}
-
-static void remove_node_from_parent_locked(struct node* node);
-
-static void release_node_locked(struct node* node)
-{
-    TRACE("RELEASE %p (%s) rc=%d\n", node, node->name, node->refcount);
-    if (node->refcount > 0) {
-        node->refcount--;
-        if (!node->refcount) {
-            TRACE("DESTROY %p (%s)\n", node, node->name);
-            remove_node_from_parent_locked(node);
-
-                /* TODO: remove debugging - poison memory */
-            memset(node->name, 0xef, node->namelen);
-            free(node->name);
-            free(node->actual_name);
-            memset(node, 0xfc, sizeof(*node));
-            free(node);
-        }
-    } else {
-        ERROR("Zero refcnt %p\n", node);
-    }
-}
-
-static void add_node_to_parent_locked(struct node *node, struct node *parent) {
-    node->parent = parent;
-    node->next = parent->child;
-    parent->child = node;
-    acquire_node_locked(parent);
-}
-
-static void remove_node_from_parent_locked(struct node* node)
-{
-    if (node->parent) {
-        if (node->parent->child == node) {
-            node->parent->child = node->parent->child->next;
-        } else {
-            struct node *node2;
-            node2 = node->parent->child;
-            while (node2->next != node)
-                node2 = node2->next;
-            node2->next = node->next;
-        }
-        release_node_locked(node->parent);
-        node->parent = NULL;
-        node->next = NULL;
-    }
-}
-
-/* Gets the absolute path to a node into the provided buffer.
- *
- * Populates 'buf' with the path and returns the length of the path on success,
- * or returns -1 if the path is too long for the provided buffer.
- */
-static ssize_t get_node_path_locked(struct node* node, char* buf, size_t bufsize) {
-    const char* name;
-    size_t namelen;
-    if (node->graft_path) {
-        name = node->graft_path;
-        namelen = node->graft_pathlen;
-    } else if (node->actual_name) {
-        name = node->actual_name;
-        namelen = node->namelen;
-    } else {
-        name = node->name;
-        namelen = node->namelen;
-    }
-
-    if (bufsize < namelen + 1) {
-        return -1;
-    }
-
-    ssize_t pathlen = 0;
-    if (node->parent && node->graft_path == NULL) {
-        pathlen = get_node_path_locked(node->parent, buf, bufsize - namelen - 1);
-        if (pathlen < 0) {
-            return -1;
-        }
-        buf[pathlen++] = '/';
-    }
-
-    memcpy(buf + pathlen, name, namelen + 1); /* include trailing \0 */
-    return pathlen + namelen;
-}
-
-/* Finds the absolute path of a file within a given directory.
- * Performs a case-insensitive search for the file and sets the buffer to the path
- * of the first matching file.  If 'search' is zero or if no match is found, sets
- * the buffer to the path that the file would have, assuming the name were case-sensitive.
- *
- * Populates 'buf' with the path and returns the actual name (within 'buf') on success,
- * or returns NULL if the path is too long for the provided buffer.
- */
-static char* find_file_within(const char* path, const char* name,
-        char* buf, size_t bufsize, int search)
-{
-    size_t pathlen = strlen(path);
-    size_t namelen = strlen(name);
-    size_t childlen = pathlen + namelen + 1;
-    char* actual;
-
-    if (bufsize <= childlen) {
-        return NULL;
-    }
-
-    memcpy(buf, path, pathlen);
-    buf[pathlen] = '/';
-    actual = buf + pathlen + 1;
-    memcpy(actual, name, namelen + 1);
-
-    if (search && access(buf, F_OK)) {
-        struct dirent* entry;
-        DIR* dir = opendir(path);
-        if (!dir) {
-            ERROR("opendir %s failed: %s\n", path, strerror(errno));
-            return actual;
-        }
-        while ((entry = readdir(dir))) {
-            if (!strcasecmp(entry->d_name, name)) {
-                /* we have a match - replace the name, don't need to copy the null again */
-                memcpy(actual, entry->d_name, namelen);
-                break;
-            }
-        }
-        closedir(dir);
-    }
-    return actual;
-}
-
-static void attr_from_stat(struct fuse* fuse, struct fuse_attr *attr,
-        const struct stat *s, const struct node* node) {
-    attr->ino = node->ino;
-    attr->size = s->st_size;
-    attr->blocks = s->st_blocks;
-    attr->atime = s->st_atim.tv_sec;
-    attr->mtime = s->st_mtim.tv_sec;
-    attr->ctime = s->st_ctim.tv_sec;
-    attr->atimensec = s->st_atim.tv_nsec;
-    attr->mtimensec = s->st_mtim.tv_nsec;
-    attr->ctimensec = s->st_ctim.tv_nsec;
-    attr->mode = s->st_mode;
-    attr->nlink = s->st_nlink;
-
-    attr->uid = node->uid;
-
-    if (fuse->gid == AID_SDCARD_RW) {
-        /* As an optimization, certain trusted system components only run
-         * as owner but operate across all users. Since we're now handing
-         * out the sdcard_rw GID only to trusted apps, we're okay relaxing
-         * the user boundary enforcement for the default view. The UIDs
-         * assigned to app directories are still multiuser aware. */
-        attr->gid = AID_SDCARD_RW;
-    } else {
-        attr->gid = multiuser_get_uid(node->userid, fuse->gid);
-    }
-
-    int visible_mode = 0775 & ~fuse->mask;
-    if (node->perm == PERM_PRE_ROOT) {
-        /* Top of multi-user view should always be visible to ensure
-         * secondary users can traverse inside. */
-        visible_mode = 0711;
-    } else if (node->under_android) {
-        /* Block "other" access to Android directories, since only apps
-         * belonging to a specific user should be in there; we still
-         * leave +x open for the default view. */
-        if (fuse->gid == AID_SDCARD_RW) {
-            visible_mode = visible_mode & ~0006;
-        } else {
-            visible_mode = visible_mode & ~0007;
-        }
-    }
-    int owner_mode = s->st_mode & 0700;
-    int filtered_mode = visible_mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6));
-    attr->mode = (attr->mode & S_IFMT) | filtered_mode;
-}
-
-static int touch(char* path, mode_t mode) {
-    int fd = open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, mode);
-    if (fd == -1) {
-        if (errno == EEXIST) {
-            return 0;
-        } else {
-            ERROR("Failed to open(%s): %s\n", path, strerror(errno));
-            return -1;
-        }
-    }
-    close(fd);
-    return 0;
-}
-
-static void derive_permissions_locked(struct fuse* fuse, struct node *parent,
-        struct node *node) {
-    appid_t appid;
-
-    /* By default, each node inherits from its parent */
-    node->perm = PERM_INHERIT;
-    node->userid = parent->userid;
-    node->uid = parent->uid;
-    node->under_android = parent->under_android;
-
-    /* Derive custom permissions based on parent and current node */
-    switch (parent->perm) {
-    case PERM_INHERIT:
-        /* Already inherited above */
-        break;
-    case PERM_PRE_ROOT:
-        /* Legacy internal layout places users at top level */
-        node->perm = PERM_ROOT;
-        node->userid = strtoul(node->name, NULL, 10);
-        break;
-    case PERM_ROOT:
-        /* Assume masked off by default. */
-        if (!strcasecmp(node->name, "Android")) {
-            /* App-specific directories inside; let anyone traverse */
-            node->perm = PERM_ANDROID;
-            node->under_android = true;
-        }
-        break;
-    case PERM_ANDROID:
-        if (!strcasecmp(node->name, "data")) {
-            /* App-specific directories inside; let anyone traverse */
-            node->perm = PERM_ANDROID_DATA;
-        } else if (!strcasecmp(node->name, "obb")) {
-            /* App-specific directories inside; let anyone traverse */
-            node->perm = PERM_ANDROID_OBB;
-            /* Single OBB directory is always shared */
-            node->graft_path = fuse->global->obb_path;
-            node->graft_pathlen = strlen(fuse->global->obb_path);
-        } else if (!strcasecmp(node->name, "media")) {
-            /* App-specific directories inside; let anyone traverse */
-            node->perm = PERM_ANDROID_MEDIA;
-        }
-        break;
-    case PERM_ANDROID_DATA:
-    case PERM_ANDROID_OBB:
-    case PERM_ANDROID_MEDIA:
-        appid = (appid_t) (uintptr_t) hashmapGet(fuse->global->package_to_appid, node->name);
-        if (appid != 0) {
-            node->uid = multiuser_get_uid(parent->userid, appid);
-        }
-        break;
-    }
-}
-
-static void derive_permissions_recursive_locked(struct fuse* fuse, struct node *parent) {
-    struct node *node;
-    for (node = parent->child; node; node = node->next) {
-        derive_permissions_locked(fuse, parent, node);
-        if (node->child) {
-            derive_permissions_recursive_locked(fuse, node);
-        }
-    }
-}
-
-/* Kernel has already enforced everything we returned through
- * derive_permissions_locked(), so this is used to lock down access
- * even further, such as enforcing that apps hold sdcard_rw. */
-static bool check_caller_access_to_name(struct fuse* fuse,
-        const struct fuse_in_header *hdr, const struct node* parent_node,
-        const char* name, int mode) {
-    /* Always block security-sensitive files at root */
-    if (parent_node && parent_node->perm == PERM_ROOT) {
-        if (!strcasecmp(name, "autorun.inf")
-                || !strcasecmp(name, ".android_secure")
-                || !strcasecmp(name, "android_secure")) {
-            return false;
-        }
-    }
-
-    /* Root always has access; access for any other UIDs should always
-     * be controlled through packages.list. */
-    if (hdr->uid == 0) {
-        return true;
-    }
-
-    /* No extra permissions to enforce */
-    return true;
-}
-
-static bool check_caller_access_to_node(struct fuse* fuse,
-        const struct fuse_in_header *hdr, const struct node* node, int mode) {
-    return check_caller_access_to_name(fuse, hdr, node->parent, node->name, mode);
-}
-
-struct node *create_node_locked(struct fuse* fuse,
-        struct node *parent, const char *name, const char* actual_name)
-{
-    struct node *node;
-    size_t namelen = strlen(name);
-
-    // Detect overflows in the inode counter. "4 billion nodes should be enough
-    // for everybody".
-    if (fuse->global->inode_ctr == 0) {
-        ERROR("No more inode numbers available");
-        return NULL;
-    }
-
-    node = calloc(1, sizeof(struct node));
-    if (!node) {
-        return NULL;
-    }
-    node->name = malloc(namelen + 1);
-    if (!node->name) {
-        free(node);
-        return NULL;
-    }
-    memcpy(node->name, name, namelen + 1);
-    if (strcmp(name, actual_name)) {
-        node->actual_name = malloc(namelen + 1);
-        if (!node->actual_name) {
-            free(node->name);
-            free(node);
-            return NULL;
-        }
-        memcpy(node->actual_name, actual_name, namelen + 1);
-    }
-    node->namelen = namelen;
-    node->nid = ptr_to_id(node);
-    node->ino = fuse->global->inode_ctr++;
-    node->gen = fuse->global->next_generation++;
-
-    node->deleted = false;
-
-    derive_permissions_locked(fuse, parent, node);
-    acquire_node_locked(node);
-    add_node_to_parent_locked(node, parent);
-    return node;
-}
-
-static int rename_node_locked(struct node *node, const char *name,
-        const char* actual_name)
-{
-    size_t namelen = strlen(name);
-    int need_actual_name = strcmp(name, actual_name);
-
-    /* make the storage bigger without actually changing the name
-     * in case an error occurs part way */
-    if (namelen > node->namelen) {
-        char* new_name = realloc(node->name, namelen + 1);
-        if (!new_name) {
-            return -ENOMEM;
-        }
-        node->name = new_name;
-        if (need_actual_name && node->actual_name) {
-            char* new_actual_name = realloc(node->actual_name, namelen + 1);
-            if (!new_actual_name) {
-                return -ENOMEM;
-            }
-            node->actual_name = new_actual_name;
-        }
-    }
-
-    /* update the name, taking care to allocate storage before overwriting the old name */
-    if (need_actual_name) {
-        if (!node->actual_name) {
-            node->actual_name = malloc(namelen + 1);
-            if (!node->actual_name) {
-                return -ENOMEM;
-            }
-        }
-        memcpy(node->actual_name, actual_name, namelen + 1);
-    } else {
-        free(node->actual_name);
-        node->actual_name = NULL;
-    }
-    memcpy(node->name, name, namelen + 1);
-    node->namelen = namelen;
-    return 0;
-}
-
-static struct node *lookup_node_by_id_locked(struct fuse *fuse, __u64 nid)
-{
-    if (nid == FUSE_ROOT_ID) {
-        return &fuse->global->root;
-    } else {
-        return id_to_ptr(nid);
-    }
-}
-
-static struct node* lookup_node_and_path_by_id_locked(struct fuse* fuse, __u64 nid,
-        char* buf, size_t bufsize)
-{
-    struct node* node = lookup_node_by_id_locked(fuse, nid);
-    if (node && get_node_path_locked(node, buf, bufsize) < 0) {
-        node = NULL;
-    }
-    return node;
-}
-
-static struct node *lookup_child_by_name_locked(struct node *node, const char *name)
-{
-    for (node = node->child; node; node = node->next) {
-        /* use exact string comparison, nodes that differ by case
-         * must be considered distinct even if they refer to the same
-         * underlying file as otherwise operations such as "mv x x"
-         * will not work because the source and target nodes are the same. */
-        if (!strcmp(name, node->name) && !node->deleted) {
-            return node;
-        }
-    }
-    return 0;
-}
-
-static struct node* acquire_or_create_child_locked(
-        struct fuse* fuse, struct node* parent,
-        const char* name, const char* actual_name)
-{
-    struct node* child = lookup_child_by_name_locked(parent, name);
-    if (child) {
-        acquire_node_locked(child);
-    } else {
-        child = create_node_locked(fuse, parent, name, actual_name);
-    }
-    return child;
-}
-
-static void fuse_status(struct fuse *fuse, __u64 unique, int err)
-{
-    struct fuse_out_header hdr;
-    hdr.len = sizeof(hdr);
-    hdr.error = err;
-    hdr.unique = unique;
-    write(fuse->fd, &hdr, sizeof(hdr));
-}
-
-static void fuse_reply(struct fuse *fuse, __u64 unique, void *data, int len)
-{
-    struct fuse_out_header hdr;
-    struct iovec vec[2];
-    int res;
-
-    hdr.len = len + sizeof(hdr);
-    hdr.error = 0;
-    hdr.unique = unique;
-
-    vec[0].iov_base = &hdr;
-    vec[0].iov_len = sizeof(hdr);
-    vec[1].iov_base = data;
-    vec[1].iov_len = len;
-
-    res = writev(fuse->fd, vec, 2);
-    if (res < 0) {
-        ERROR("*** REPLY FAILED *** %d\n", errno);
-    }
-}
-
-static int fuse_reply_entry(struct fuse* fuse, __u64 unique,
-        struct node* parent, const char* name, const char* actual_name,
-        const char* path)
-{
-    struct node* node;
-    struct fuse_entry_out out;
-    struct stat s;
-
-    if (lstat(path, &s) < 0) {
-        return -errno;
-    }
-
-    pthread_mutex_lock(&fuse->global->lock);
-    node = acquire_or_create_child_locked(fuse, parent, name, actual_name);
-    if (!node) {
-        pthread_mutex_unlock(&fuse->global->lock);
-        return -ENOMEM;
-    }
-    memset(&out, 0, sizeof(out));
-    attr_from_stat(fuse, &out.attr, &s, node);
-    out.attr_valid = 10;
-    out.entry_valid = 10;
-    out.nodeid = node->nid;
-    out.generation = node->gen;
-    pthread_mutex_unlock(&fuse->global->lock);
-    fuse_reply(fuse, unique, &out, sizeof(out));
-    return NO_STATUS;
-}
-
-static int fuse_reply_attr(struct fuse* fuse, __u64 unique, const struct node* node,
-        const char* path)
-{
-    struct fuse_attr_out out;
-    struct stat s;
-
-    if (lstat(path, &s) < 0) {
-        return -errno;
-    }
-    memset(&out, 0, sizeof(out));
-    attr_from_stat(fuse, &out.attr, &s, node);
-    out.attr_valid = 10;
-    fuse_reply(fuse, unique, &out, sizeof(out));
-    return NO_STATUS;
-}
-
-static void fuse_notify_delete(struct fuse* fuse, const __u64 parent,
-        const __u64 child, const char* name) {
-    struct fuse_out_header hdr;
-    struct fuse_notify_delete_out data;
-    struct iovec vec[3];
-    size_t namelen = strlen(name);
-    int res;
-
-    hdr.len = sizeof(hdr) + sizeof(data) + namelen + 1;
-    hdr.error = FUSE_NOTIFY_DELETE;
-    hdr.unique = 0;
-
-    data.parent = parent;
-    data.child = child;
-    data.namelen = namelen;
-    data.padding = 0;
-
-    vec[0].iov_base = &hdr;
-    vec[0].iov_len = sizeof(hdr);
-    vec[1].iov_base = &data;
-    vec[1].iov_len = sizeof(data);
-    vec[2].iov_base = (void*) name;
-    vec[2].iov_len = namelen + 1;
-
-    res = writev(fuse->fd, vec, 3);
-    /* Ignore ENOENT, since other views may not have seen the entry */
-    if (res < 0 && errno != ENOENT) {
-        ERROR("*** NOTIFY FAILED *** %d\n", errno);
-    }
-}
-
-static int handle_lookup(struct fuse* fuse, struct fuse_handler* handler,
-        const struct fuse_in_header *hdr, const char* name)
-{
-    struct node* parent_node;
-    char parent_path[PATH_MAX];
-    char child_path[PATH_MAX];
-    const char* actual_name;
-
-    pthread_mutex_lock(&fuse->global->lock);
-    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
-            parent_path, sizeof(parent_path));
-    TRACE("[%d] LOOKUP %s @ %"PRIx64" (%s)\n", handler->token, name, hdr->nodeid,
-        parent_node ? parent_node->name : "?");
-    pthread_mutex_unlock(&fuse->global->lock);
-
-    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
-            child_path, sizeof(child_path), 1))) {
-        return -ENOENT;
-    }
-    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, R_OK)) {
-        return -EACCES;
-    }
-
-    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
-}
-
-static int handle_forget(struct fuse* fuse, struct fuse_handler* handler,
-        const struct fuse_in_header *hdr, const struct fuse_forget_in *req)
-{
-    struct node* node;
-
-    pthread_mutex_lock(&fuse->global->lock);
-    node = lookup_node_by_id_locked(fuse, hdr->nodeid);
-    TRACE("[%d] FORGET #%"PRIu64" @ %"PRIx64" (%s)\n", handler->token, req->nlookup,
-            hdr->nodeid, node ? node->name : "?");
-    if (node) {
-        __u64 n = req->nlookup;
-        while (n--) {
-            release_node_locked(node);
-        }
-    }
-    pthread_mutex_unlock(&fuse->global->lock);
-    return NO_STATUS; /* no reply */
-}
-
-static int handle_getattr(struct fuse* fuse, struct fuse_handler* handler,
-        const struct fuse_in_header *hdr, const struct fuse_getattr_in *req)
-{
-    struct node* node;
-    char path[PATH_MAX];
-
-    pthread_mutex_lock(&fuse->global->lock);
-    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
-    TRACE("[%d] GETATTR flags=%x fh=%"PRIx64" @ %"PRIx64" (%s)\n", handler->token,
-            req->getattr_flags, req->fh, hdr->nodeid, node ? node->name : "?");
-    pthread_mutex_unlock(&fuse->global->lock);
-
-    if (!node) {
-        return -ENOENT;
-    }
-    if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
-        return -EACCES;
-    }
-
-    return fuse_reply_attr(fuse, hdr->unique, node, path);
-}
-
-static int handle_setattr(struct fuse* fuse, struct fuse_handler* handler,
-        const struct fuse_in_header *hdr, const struct fuse_setattr_in *req)
-{
-    struct node* node;
-    char path[PATH_MAX];
-    struct timespec times[2];
-
-    pthread_mutex_lock(&fuse->global->lock);
-    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
-    TRACE("[%d] SETATTR fh=%"PRIx64" valid=%x @ %"PRIx64" (%s)\n", handler->token,
-            req->fh, req->valid, hdr->nodeid, node ? node->name : "?");
-    pthread_mutex_unlock(&fuse->global->lock);
-
-    if (!node) {
-        return -ENOENT;
-    }
-
-    if (!(req->valid & FATTR_FH) &&
-            !check_caller_access_to_node(fuse, hdr, node, W_OK)) {
-        return -EACCES;
-    }
-
-    /* XXX: incomplete implementation on purpose.
-     * chmod/chown should NEVER be implemented.*/
-
-    if ((req->valid & FATTR_SIZE) && truncate64(path, req->size) < 0) {
-        return -errno;
-    }
-
-    /* Handle changing atime and mtime.  If FATTR_ATIME_and FATTR_ATIME_NOW
-     * are both set, then set it to the current time.  Else, set it to the
-     * time specified in the request.  Same goes for mtime.  Use utimensat(2)
-     * as it allows ATIME and MTIME to be changed independently, and has
-     * nanosecond resolution which fuse also has.
-     */
-    if (req->valid & (FATTR_ATIME | FATTR_MTIME)) {
-        times[0].tv_nsec = UTIME_OMIT;
-        times[1].tv_nsec = UTIME_OMIT;
-        if (req->valid & FATTR_ATIME) {
-            if (req->valid & FATTR_ATIME_NOW) {
-              times[0].tv_nsec = UTIME_NOW;
-            } else {
-              times[0].tv_sec = req->atime;
-              times[0].tv_nsec = req->atimensec;
-            }
-        }
-        if (req->valid & FATTR_MTIME) {
-            if (req->valid & FATTR_MTIME_NOW) {
-              times[1].tv_nsec = UTIME_NOW;
-            } else {
-              times[1].tv_sec = req->mtime;
-              times[1].tv_nsec = req->mtimensec;
-            }
-        }
-        TRACE("[%d] Calling utimensat on %s with atime %ld, mtime=%ld\n",
-                handler->token, path, times[0].tv_sec, times[1].tv_sec);
-        if (utimensat(-1, path, times, 0) < 0) {
-            return -errno;
-        }
-    }
-    return fuse_reply_attr(fuse, hdr->unique, node, path);
-}
-
-static int handle_mknod(struct fuse* fuse, struct fuse_handler* handler,
-        const struct fuse_in_header* hdr, const struct fuse_mknod_in* req, const char* name)
-{
-    struct node* parent_node;
-    char parent_path[PATH_MAX];
-    char child_path[PATH_MAX];
-    const char* actual_name;
-
-    pthread_mutex_lock(&fuse->global->lock);
-    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
-            parent_path, sizeof(parent_path));
-    TRACE("[%d] MKNOD %s 0%o @ %"PRIx64" (%s)\n", handler->token,
-            name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
-    pthread_mutex_unlock(&fuse->global->lock);
-
-    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
-            child_path, sizeof(child_path), 1))) {
-        return -ENOENT;
-    }
-    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
-        return -EACCES;
-    }
-    __u32 mode = (req->mode & (~0777)) | 0664;
-    if (mknod(child_path, mode, req->rdev) < 0) {
-        return -errno;
-    }
-    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
-}
-
-static int handle_mkdir(struct fuse* fuse, struct fuse_handler* handler,
-        const struct fuse_in_header* hdr, const struct fuse_mkdir_in* req, const char* name)
-{
-    struct node* parent_node;
-    char parent_path[PATH_MAX];
-    char child_path[PATH_MAX];
-    const char* actual_name;
-
-    pthread_mutex_lock(&fuse->global->lock);
-    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
-            parent_path, sizeof(parent_path));
-    TRACE("[%d] MKDIR %s 0%o @ %"PRIx64" (%s)\n", handler->token,
-            name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
-    pthread_mutex_unlock(&fuse->global->lock);
-
-    if (!parent_node || !(actual_name = find_file_within(parent_path, name,
-            child_path, sizeof(child_path), 1))) {
-        return -ENOENT;
-    }
-    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
-        return -EACCES;
-    }
-    __u32 mode = (req->mode & (~0777)) | 0775;
-    if (mkdir(child_path, mode) < 0) {
-        return -errno;
-    }
-
-    /* When creating /Android/data and /Android/obb, mark them as .nomedia */
-    if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "data")) {
-        char nomedia[PATH_MAX];
-        snprintf(nomedia, PATH_MAX, "%s/.nomedia", child_path);
-        if (touch(nomedia, 0664) != 0) {
-            ERROR("Failed to touch(%s): %s\n", nomedia, strerror(errno));
-            return -ENOENT;
-        }
-    }
-    if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "obb")) {
-        char nomedia[PATH_MAX];
-        snprintf(nomedia, PATH_MAX, "%s/.nomedia", fuse->global->obb_path);
-        if (touch(nomedia, 0664) != 0) {
-            ERROR("Failed to touch(%s): %s\n", nomedia, strerror(errno));
-            return -ENOENT;
-        }
-    }
-
-    return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
-}
-
-static int handle_unlink(struct fuse* fuse, struct fuse_handler* handler,
-        const struct fuse_in_header* hdr, const char* name)
-{
-    struct node* parent_node;
-    struct node* child_node;
-    char parent_path[PATH_MAX];
-    char child_path[PATH_MAX];
-
-    pthread_mutex_lock(&fuse->global->lock);
-    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
-            parent_path, sizeof(parent_path));
-    TRACE("[%d] UNLINK %s @ %"PRIx64" (%s)\n", handler->token,
-            name, hdr->nodeid, parent_node ? parent_node->name : "?");
-    pthread_mutex_unlock(&fuse->global->lock);
-
-    if (!parent_node || !find_file_within(parent_path, name,
-            child_path, sizeof(child_path), 1)) {
-        return -ENOENT;
-    }
-    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
-        return -EACCES;
-    }
-    if (unlink(child_path) < 0) {
-        return -errno;
-    }
-    pthread_mutex_lock(&fuse->global->lock);
-    child_node = lookup_child_by_name_locked(parent_node, name);
-    if (child_node) {
-        child_node->deleted = true;
-    }
-    pthread_mutex_unlock(&fuse->global->lock);
-    if (parent_node && child_node) {
-        /* Tell all other views that node is gone */
-        TRACE("[%d] fuse_notify_delete parent=%"PRIx64", child=%"PRIx64", name=%s\n",
-                handler->token, (uint64_t) parent_node->nid, (uint64_t) child_node->nid, name);
-        if (fuse != fuse->global->fuse_default) {
-            fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
-        }
-        if (fuse != fuse->global->fuse_read) {
-            fuse_notify_delete(fuse->global->fuse_read, parent_node->nid, child_node->nid, name);
-        }
-        if (fuse != fuse->global->fuse_write) {
-            fuse_notify_delete(fuse->global->fuse_write, parent_node->nid, child_node->nid, name);
-        }
-    }
-    return 0;
-}
-
-static int handle_rmdir(struct fuse* fuse, struct fuse_handler* handler,
-        const struct fuse_in_header* hdr, const char* name)
-{
-    struct node* child_node;
-    struct node* parent_node;
-    char parent_path[PATH_MAX];
-    char child_path[PATH_MAX];
-
-    pthread_mutex_lock(&fuse->global->lock);
-    parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
-            parent_path, sizeof(parent_path));
-    TRACE("[%d] RMDIR %s @ %"PRIx64" (%s)\n", handler->token,
-            name, hdr->nodeid, parent_node ? parent_node->name : "?");
-    pthread_mutex_unlock(&fuse->global->lock);
-
-    if (!parent_node || !find_file_within(parent_path, name,
-            child_path, sizeof(child_path), 1)) {
-        return -ENOENT;
-    }
-    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
-        return -EACCES;
-    }
-    if (rmdir(child_path) < 0) {
-        return -errno;
-    }
-    pthread_mutex_lock(&fuse->global->lock);
-    child_node = lookup_child_by_name_locked(parent_node, name);
-    if (child_node) {
-        child_node->deleted = true;
-    }
-    pthread_mutex_unlock(&fuse->global->lock);
-    if (parent_node && child_node) {
-        /* Tell all other views that node is gone */
-        TRACE("[%d] fuse_notify_delete parent=%"PRIx64", child=%"PRIx64", name=%s\n",
-                handler->token, (uint64_t) parent_node->nid, (uint64_t) child_node->nid, name);
-        if (fuse != fuse->global->fuse_default) {
-            fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
-        }
-        if (fuse != fuse->global->fuse_read) {
-            fuse_notify_delete(fuse->global->fuse_read, parent_node->nid, child_node->nid, name);
-        }
-        if (fuse != fuse->global->fuse_write) {
-            fuse_notify_delete(fuse->global->fuse_write, parent_node->nid, child_node->nid, name);
-        }
-    }
-    return 0;
-}
-
-static int handle_rename(struct fuse* fuse, struct fuse_handler* handler,
-        const struct fuse_in_header* hdr, const struct fuse_rename_in* req,
-        const char* old_name, const char* new_name)
-{
-    struct node* old_parent_node;
-    struct node* new_parent_node;
-    struct node* child_node;
-    char old_parent_path[PATH_MAX];
-    char new_parent_path[PATH_MAX];
-    char old_child_path[PATH_MAX];
-    char new_child_path[PATH_MAX];
-    const char* new_actual_name;
-    int res;
-
-    pthread_mutex_lock(&fuse->global->lock);
-    old_parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
-            old_parent_path, sizeof(old_parent_path));
-    new_parent_node = lookup_node_and_path_by_id_locked(fuse, req->newdir,
-            new_parent_path, sizeof(new_parent_path));
-    TRACE("[%d] RENAME %s->%s @ %"PRIx64" (%s) -> %"PRIx64" (%s)\n", handler->token,
-            old_name, new_name,
-            hdr->nodeid, old_parent_node ? old_parent_node->name : "?",
-            req->newdir, new_parent_node ? new_parent_node->name : "?");
-    if (!old_parent_node || !new_parent_node) {
-        res = -ENOENT;
-        goto lookup_error;
-    }
-    if (!check_caller_access_to_name(fuse, hdr, old_parent_node, old_name, W_OK)) {
-        res = -EACCES;
-        goto lookup_error;
-    }
-    if (!check_caller_access_to_name(fuse, hdr, new_parent_node, new_name, W_OK)) {
-        res = -EACCES;
-        goto lookup_error;
-    }
-    child_node = lookup_child_by_name_locked(old_parent_node, old_name);
-    if (!child_node || get_node_path_locked(child_node,
-            old_child_path, sizeof(old_child_path)) < 0) {
-        res = -ENOENT;
-        goto lookup_error;
-    }
-    acquire_node_locked(child_node);
-    pthread_mutex_unlock(&fuse->global->lock);
-
-    /* Special case for renaming a file where destination is same path
-     * differing only by case.  In this case we don't want to look for a case
-     * insensitive match.  This allows commands like "mv foo FOO" to work as expected.
-     */
-    int search = old_parent_node != new_parent_node
-            || strcasecmp(old_name, new_name);
-    if (!(new_actual_name = find_file_within(new_parent_path, new_name,
-            new_child_path, sizeof(new_child_path), search))) {
-        res = -ENOENT;
-        goto io_error;
-    }
-
-    TRACE("[%d] RENAME %s->%s\n", handler->token, old_child_path, new_child_path);
-    res = rename(old_child_path, new_child_path);
-    if (res < 0) {
-        res = -errno;
-        goto io_error;
-    }
-
-    pthread_mutex_lock(&fuse->global->lock);
-    res = rename_node_locked(child_node, new_name, new_actual_name);
-    if (!res) {
-        remove_node_from_parent_locked(child_node);
-        derive_permissions_locked(fuse, new_parent_node, child_node);
-        derive_permissions_recursive_locked(fuse, child_node);
-        add_node_to_parent_locked(child_node, new_parent_node);
-    }
-    goto done;
-
-io_error:
-    pthread_mutex_lock(&fuse->global->lock);
-done:
-    release_node_locked(child_node);
-lookup_error:
-    pthread_mutex_unlock(&fuse->global->lock);
-    return res;
-}
-
-static int open_flags_to_access_mode(int open_flags) {
-    if ((open_flags & O_ACCMODE) == O_RDONLY) {
-        return R_OK;
-    } else if ((open_flags & O_ACCMODE) == O_WRONLY) {
-        return W_OK;
-    } else {
-        /* Probably O_RDRW, but treat as default to be safe */
-        return R_OK | W_OK;
-    }
-}
-
-static int handle_open(struct fuse* fuse, struct fuse_handler* handler,
-        const struct fuse_in_header* hdr, const struct fuse_open_in* req)
-{
-    struct node* node;
-    char path[PATH_MAX];
-    struct fuse_open_out out;
-    struct handle *h;
-
-    pthread_mutex_lock(&fuse->global->lock);
-    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
-    TRACE("[%d] OPEN 0%o @ %"PRIx64" (%s)\n", handler->token,
-            req->flags, hdr->nodeid, node ? node->name : "?");
-    pthread_mutex_unlock(&fuse->global->lock);
-
-    if (!node) {
-        return -ENOENT;
-    }
-    if (!check_caller_access_to_node(fuse, hdr, node,
-            open_flags_to_access_mode(req->flags))) {
-        return -EACCES;
-    }
-    h = malloc(sizeof(*h));
-    if (!h) {
-        return -ENOMEM;
-    }
-    TRACE("[%d] OPEN %s\n", handler->token, path);
-    h->fd = open(path, req->flags);
-    if (h->fd < 0) {
-        free(h);
-        return -errno;
-    }
-    out.fh = ptr_to_id(h);
-    out.open_flags = 0;
-
-#ifdef FUSE_SHORTCIRCUIT
-    out.lower_fd = h->fd;
-#else
-    out.padding = 0;
-#endif
-
-    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
-    return NO_STATUS;
-}
-
-static int handle_read(struct fuse* fuse, struct fuse_handler* handler,
-        const struct fuse_in_header* hdr, const struct fuse_read_in* req)
-{
-    struct handle *h = id_to_ptr(req->fh);
-    __u64 unique = hdr->unique;
-    __u32 size = req->size;
-    __u64 offset = req->offset;
-    int res;
-    __u8 *read_buffer = (__u8 *) ((uintptr_t)(handler->read_buffer + PAGE_SIZE) & ~((uintptr_t)PAGE_SIZE-1));
-
-    /* Don't access any other fields of hdr or req beyond this point, the read buffer
-     * overlaps the request buffer and will clobber data in the request.  This
-     * saves us 128KB per request handler thread at the cost of this scary comment. */
-
-    TRACE("[%d] READ %p(%d) %u@%"PRIu64"\n", handler->token,
-            h, h->fd, size, (uint64_t) offset);
-    if (size > MAX_READ) {
-        return -EINVAL;
-    }
-    res = pread64(h->fd, read_buffer, size, offset);
-    if (res < 0) {
-        return -errno;
-    }
-    fuse_reply(fuse, unique, read_buffer, res);
-    return NO_STATUS;
-}
-
-static int handle_write(struct fuse* fuse, struct fuse_handler* handler,
-        const struct fuse_in_header* hdr, const struct fuse_write_in* req,
-        const void* buffer)
-{
-    struct fuse_write_out out;
-    struct handle *h = id_to_ptr(req->fh);
-    int res;
-    __u8 aligned_buffer[req->size] __attribute__((__aligned__(PAGE_SIZE)));
-
-    if (req->flags & O_DIRECT) {
-        memcpy(aligned_buffer, buffer, req->size);
-        buffer = (const __u8*) aligned_buffer;
-    }
-
-    TRACE("[%d] WRITE %p(%d) %u@%"PRIu64"\n", handler->token,
-            h, h->fd, req->size, req->offset);
-    res = pwrite64(h->fd, buffer, req->size, req->offset);
-    if (res < 0) {
-        return -errno;
-    }
-    out.size = res;
-    out.padding = 0;
-    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
-    return NO_STATUS;
-}
-
-static int handle_statfs(struct fuse* fuse, struct fuse_handler* handler,
-        const struct fuse_in_header* hdr)
-{
-    char path[PATH_MAX];
-    struct statfs stat;
-    struct fuse_statfs_out out;
-    int res;
-
-    pthread_mutex_lock(&fuse->global->lock);
-    TRACE("[%d] STATFS\n", handler->token);
-    res = get_node_path_locked(&fuse->global->root, path, sizeof(path));
-    pthread_mutex_unlock(&fuse->global->lock);
-    if (res < 0) {
-        return -ENOENT;
-    }
-    if (statfs(fuse->global->root.name, &stat) < 0) {
-        return -errno;
-    }
-    memset(&out, 0, sizeof(out));
-    out.st.blocks = stat.f_blocks;
-    out.st.bfree = stat.f_bfree;
-    out.st.bavail = stat.f_bavail;
-    out.st.files = stat.f_files;
-    out.st.ffree = stat.f_ffree;
-    out.st.bsize = stat.f_bsize;
-    out.st.namelen = stat.f_namelen;
-    out.st.frsize = stat.f_frsize;
-    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
-    return NO_STATUS;
-}
-
-static int handle_release(struct fuse* fuse, struct fuse_handler* handler,
-        const struct fuse_in_header* hdr, const struct fuse_release_in* req)
-{
-    struct handle *h = id_to_ptr(req->fh);
-
-    TRACE("[%d] RELEASE %p(%d)\n", handler->token, h, h->fd);
-    close(h->fd);
-    free(h);
-    return 0;
-}
-
-static int handle_fsync(struct fuse* fuse, struct fuse_handler* handler,
-        const struct fuse_in_header* hdr, const struct fuse_fsync_in* req)
-{
-    bool is_dir = (hdr->opcode == FUSE_FSYNCDIR);
-    bool is_data_sync = req->fsync_flags & 1;
-
-    int fd = -1;
-    if (is_dir) {
-      struct dirhandle *dh = id_to_ptr(req->fh);
-      fd = dirfd(dh->d);
-    } else {
-      struct handle *h = id_to_ptr(req->fh);
-      fd = h->fd;
-    }
-
-    TRACE("[%d] %s %p(%d) is_data_sync=%d\n", handler->token,
-            is_dir ? "FSYNCDIR" : "FSYNC",
-            id_to_ptr(req->fh), fd, is_data_sync);
-    int res = is_data_sync ? fdatasync(fd) : fsync(fd);
-    if (res == -1) {
-        return -errno;
-    }
-    return 0;
-}
-
-static int handle_flush(struct fuse* fuse, struct fuse_handler* handler,
-        const struct fuse_in_header* hdr)
-{
-    TRACE("[%d] FLUSH\n", handler->token);
-    return 0;
-}
-
-static int handle_opendir(struct fuse* fuse, struct fuse_handler* handler,
-        const struct fuse_in_header* hdr, const struct fuse_open_in* req)
-{
-    struct node* node;
-    char path[PATH_MAX];
-    struct fuse_open_out out;
-    struct dirhandle *h;
-
-    pthread_mutex_lock(&fuse->global->lock);
-    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
-    TRACE("[%d] OPENDIR @ %"PRIx64" (%s)\n", handler->token,
-            hdr->nodeid, node ? node->name : "?");
-    pthread_mutex_unlock(&fuse->global->lock);
-
-    if (!node) {
-        return -ENOENT;
-    }
-    if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
-        return -EACCES;
-    }
-    h = malloc(sizeof(*h));
-    if (!h) {
-        return -ENOMEM;
-    }
-    TRACE("[%d] OPENDIR %s\n", handler->token, path);
-    h->d = opendir(path);
-    if (!h->d) {
-        free(h);
-        return -errno;
-    }
-    out.fh = ptr_to_id(h);
-    out.open_flags = 0;
-
-#ifdef FUSE_SHORTCIRCUIT
-    out.lower_fd = -1;
-#else
-    out.padding = 0;
-#endif
-
-    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
-    return NO_STATUS;
-}
-
-static int handle_readdir(struct fuse* fuse, struct fuse_handler* handler,
-        const struct fuse_in_header* hdr, const struct fuse_read_in* req)
-{
-    char buffer[8192];
-    struct fuse_dirent *fde = (struct fuse_dirent*) buffer;
-    struct dirent *de;
-    struct dirhandle *h = id_to_ptr(req->fh);
-
-    TRACE("[%d] READDIR %p\n", handler->token, h);
-    if (req->offset == 0) {
-        /* rewinddir() might have been called above us, so rewind here too */
-        TRACE("[%d] calling rewinddir()\n", handler->token);
-        rewinddir(h->d);
-    }
-    de = readdir(h->d);
-    if (!de) {
-        return 0;
-    }
-    fde->ino = FUSE_UNKNOWN_INO;
-    /* increment the offset so we can detect when rewinddir() seeks back to the beginning */
-    fde->off = req->offset + 1;
-    fde->type = de->d_type;
-    fde->namelen = strlen(de->d_name);
-    memcpy(fde->name, de->d_name, fde->namelen + 1);
-    fuse_reply(fuse, hdr->unique, fde,
-            FUSE_DIRENT_ALIGN(sizeof(struct fuse_dirent) + fde->namelen));
-    return NO_STATUS;
-}
-
-static int handle_releasedir(struct fuse* fuse, struct fuse_handler* handler,
-        const struct fuse_in_header* hdr, const struct fuse_release_in* req)
-{
-    struct dirhandle *h = id_to_ptr(req->fh);
-
-    TRACE("[%d] RELEASEDIR %p\n", handler->token, h);
-    closedir(h->d);
-    free(h);
-    return 0;
-}
-
-static int handle_init(struct fuse* fuse, struct fuse_handler* handler,
-        const struct fuse_in_header* hdr, const struct fuse_init_in* req)
-{
-    struct fuse_init_out out;
-    size_t fuse_struct_size;
-
-    TRACE("[%d] INIT ver=%d.%d maxread=%d flags=%x\n",
-            handler->token, req->major, req->minor, req->max_readahead, req->flags);
-
-    /* Kernel 2.6.16 is the first stable kernel with struct fuse_init_out
-     * defined (fuse version 7.6). The structure is the same from 7.6 through
-     * 7.22. Beginning with 7.23, the structure increased in size and added
-     * new parameters.
-     */
-    if (req->major != FUSE_KERNEL_VERSION || req->minor < 6) {
-        ERROR("Fuse kernel version mismatch: Kernel version %d.%d, Expected at least %d.6",
-              req->major, req->minor, FUSE_KERNEL_VERSION);
-        return -1;
-    }
-
-    /* We limit ourselves to 15 because we don't handle BATCH_FORGET yet */
-    out.minor = MIN(req->minor, 15);
-    fuse_struct_size = sizeof(out);
-#if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
-    /* FUSE_KERNEL_VERSION >= 23. */
-
-    /* If the kernel only works on minor revs older than or equal to 22,
-     * then use the older structure size since this code only uses the 7.22
-     * version of the structure. */
-    if (req->minor <= 22) {
-        fuse_struct_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
-    }
-#endif
-
-    out.major = FUSE_KERNEL_VERSION;
-    out.max_readahead = req->max_readahead;
-    out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
-
-#ifdef FUSE_SHORTCIRCUIT
-    out.flags |= FUSE_SHORTCIRCUIT;
-#endif
-
-    out.max_background = 32;
-    out.congestion_threshold = 32;
-    out.max_write = MAX_WRITE;
-    fuse_reply(fuse, hdr->unique, &out, fuse_struct_size);
-    return NO_STATUS;
-}
-
-static int handle_canonical_path(struct fuse* fuse, struct fuse_handler* handler,
-        const struct fuse_in_header *hdr)
-{
-    struct node* node;
-    char path[PATH_MAX];
-    int len;
-
-    pthread_mutex_lock(&fuse->global->lock);
-    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
-            path, sizeof(path));
-    TRACE("[%d] CANONICAL_PATH @ %" PRIx64 " (%s)\n", handler->token, hdr->nodeid,
-        node ? node->name : "?");
-    pthread_mutex_unlock(&fuse->global->lock);
-
-    if (!node) {
-        return -ENOENT;
-    }
-    if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
-        return -EACCES;
-    }
-    len = strlen(path);
-    if (len + 1 > PATH_MAX)
-        len = PATH_MAX - 1;
-    path[PATH_MAX - 1] = 0;
-    fuse_reply(fuse, hdr->unique, path, len + 1);
-    return NO_STATUS;
-}
-
-
-static int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler,
-        const struct fuse_in_header *hdr, const void *data, size_t data_len)
-{
-    switch (hdr->opcode) {
-    case FUSE_LOOKUP: { /* bytez[] -> entry_out */
-        const char* name = data;
-        return handle_lookup(fuse, handler, hdr, name);
-    }
-
-    case FUSE_FORGET: {
-        const struct fuse_forget_in *req = data;
-        return handle_forget(fuse, handler, hdr, req);
-    }
-
-    case FUSE_GETATTR: { /* getattr_in -> attr_out */
-        const struct fuse_getattr_in *req = data;
-        return handle_getattr(fuse, handler, hdr, req);
-    }
-
-    case FUSE_SETATTR: { /* setattr_in -> attr_out */
-        const struct fuse_setattr_in *req = data;
-        return handle_setattr(fuse, handler, hdr, req);
-    }
-
-//    case FUSE_READLINK:
-//    case FUSE_SYMLINK:
-    case FUSE_MKNOD: { /* mknod_in, bytez[] -> entry_out */
-        const struct fuse_mknod_in *req = data;
-        const char *name = ((const char*) data) + sizeof(*req);
-        return handle_mknod(fuse, handler, hdr, req, name);
-    }
-
-    case FUSE_MKDIR: { /* mkdir_in, bytez[] -> entry_out */
-        const struct fuse_mkdir_in *req = data;
-        const char *name = ((const char*) data) + sizeof(*req);
-        return handle_mkdir(fuse, handler, hdr, req, name);
-    }
-
-    case FUSE_UNLINK: { /* bytez[] -> */
-        const char* name = data;
-        return handle_unlink(fuse, handler, hdr, name);
-    }
-
-    case FUSE_RMDIR: { /* bytez[] -> */
-        const char* name = data;
-        return handle_rmdir(fuse, handler, hdr, name);
-    }
-
-    case FUSE_RENAME: { /* rename_in, oldname, newname ->  */
-        const struct fuse_rename_in *req = data;
-        const char *old_name = ((const char*) data) + sizeof(*req);
-        const char *new_name = old_name + strlen(old_name) + 1;
-        return handle_rename(fuse, handler, hdr, req, old_name, new_name);
-    }
-
-//    case FUSE_LINK:
-    case FUSE_OPEN: { /* open_in -> open_out */
-        const struct fuse_open_in *req = data;
-        return handle_open(fuse, handler, hdr, req);
-    }
-
-    case FUSE_READ: { /* read_in -> byte[] */
-        const struct fuse_read_in *req = data;
-        return handle_read(fuse, handler, hdr, req);
-    }
-
-    case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */
-        const struct fuse_write_in *req = data;
-        const void* buffer = (const __u8*)data + sizeof(*req);
-        return handle_write(fuse, handler, hdr, req, buffer);
-    }
-
-    case FUSE_STATFS: { /* getattr_in -> attr_out */
-        return handle_statfs(fuse, handler, hdr);
-    }
-
-    case FUSE_RELEASE: { /* release_in -> */
-        const struct fuse_release_in *req = data;
-        return handle_release(fuse, handler, hdr, req);
-    }
-
-    case FUSE_FSYNC:
-    case FUSE_FSYNCDIR: {
-        const struct fuse_fsync_in *req = data;
-        return handle_fsync(fuse, handler, hdr, req);
-    }
-
-//    case FUSE_SETXATTR:
-//    case FUSE_GETXATTR:
-//    case FUSE_LISTXATTR:
-//    case FUSE_REMOVEXATTR:
-    case FUSE_FLUSH: {
-        return handle_flush(fuse, handler, hdr);
-    }
-
-    case FUSE_OPENDIR: { /* open_in -> open_out */
-        const struct fuse_open_in *req = data;
-        return handle_opendir(fuse, handler, hdr, req);
-    }
-
-    case FUSE_READDIR: {
-        const struct fuse_read_in *req = data;
-        return handle_readdir(fuse, handler, hdr, req);
-    }
-
-    case FUSE_RELEASEDIR: { /* release_in -> */
-        const struct fuse_release_in *req = data;
-        return handle_releasedir(fuse, handler, hdr, req);
-    }
-
-    case FUSE_INIT: { /* init_in -> init_out */
-        const struct fuse_init_in *req = data;
-        return handle_init(fuse, handler, hdr, req);
-    }
-
-    case FUSE_CANONICAL_PATH: { /* nodeid -> bytez[] */
-        return handle_canonical_path(fuse, handler, hdr);
-    }
-
-    default: {
-        TRACE("[%d] NOTIMPL op=%d uniq=%"PRIx64" nid=%"PRIx64"\n",
-                handler->token, hdr->opcode, hdr->unique, hdr->nodeid);
-        return -ENOSYS;
-    }
-    }
-}
-
-static void handle_fuse_requests(struct fuse_handler* handler)
-{
-    struct fuse* fuse = handler->fuse;
-    for (;;) {
-        ssize_t len = TEMP_FAILURE_RETRY(read(fuse->fd,
-                handler->request_buffer, sizeof(handler->request_buffer)));
-        if (len < 0) {
-            if (errno == ENODEV) {
-                ERROR("[%d] someone stole our marbles!\n", handler->token);
-                exit(2);
-            }
-            ERROR("[%d] handle_fuse_requests: errno=%d\n", handler->token, errno);
-            continue;
-        }
-
-        if ((size_t)len < sizeof(struct fuse_in_header)) {
-            ERROR("[%d] request too short: len=%zu\n", handler->token, (size_t)len);
-            continue;
-        }
-
-        const struct fuse_in_header *hdr = (void*)handler->request_buffer;
-        if (hdr->len != (size_t)len) {
-            ERROR("[%d] malformed header: len=%zu, hdr->len=%u\n",
-                    handler->token, (size_t)len, hdr->len);
-            continue;
-        }
-
-        const void *data = handler->request_buffer + sizeof(struct fuse_in_header);
-        size_t data_len = len - sizeof(struct fuse_in_header);
-        __u64 unique = hdr->unique;
-        int res = handle_fuse_request(fuse, handler, hdr, data, data_len);
-
-        /* We do not access the request again after this point because the underlying
-         * buffer storage may have been reused while processing the request. */
-
-        if (res != NO_STATUS) {
-            if (res) {
-                TRACE("[%d] ERROR %d\n", handler->token, res);
-            }
-            fuse_status(fuse, unique, res);
-        }
-    }
-}
-
-static void* start_handler(void* data)
-{
-    struct fuse_handler* handler = data;
-    handle_fuse_requests(handler);
-    return NULL;
-}
-
-static bool remove_str_to_int(void *key, void *value, void *context) {
-    Hashmap* map = context;
-    hashmapRemove(map, key);
-    free(key);
-    return true;
-}
-
-static bool package_parse_callback(pkg_info *info, void *userdata) {
-    struct fuse_global *global = (struct fuse_global *)userdata;
-
-    char* name = strdup(info->name);
-    hashmapPut(global->package_to_appid, name, (void*) (uintptr_t) info->uid);
-    packagelist_free(info);
-    return true;
-}
-
-static bool read_package_list(struct fuse_global* global) {
-    pthread_mutex_lock(&global->lock);
-
-    hashmapForEach(global->package_to_appid, remove_str_to_int, global->package_to_appid);
-
-    bool rc = packagelist_parse(package_parse_callback, global);
-    TRACE("read_package_list: found %zu packages\n",
-            hashmapSize(global->package_to_appid));
-
-    /* Regenerate ownership details using newly loaded mapping */
-    derive_permissions_recursive_locked(global->fuse_default, &global->root);
-
-    pthread_mutex_unlock(&global->lock);
-
-    return rc;
-}
-
-static void watch_package_list(struct fuse_global* global) {
-    struct inotify_event *event;
-    char event_buf[512];
-
-    int nfd = inotify_init();
-    if (nfd < 0) {
-        ERROR("inotify_init failed: %s\n", strerror(errno));
-        return;
-    }
-
-    bool active = false;
-    while (1) {
-        if (!active) {
-            int res = inotify_add_watch(nfd, PACKAGES_LIST_FILE, IN_DELETE_SELF);
-            if (res == -1) {
-                if (errno == ENOENT || errno == EACCES) {
-                    /* Framework may not have created yet, sleep and retry */
-                    ERROR("missing \"%s\"; retrying\n", PACKAGES_LIST_FILE);
-                    sleep(3);
-                    continue;
-                } else {
-                    ERROR("inotify_add_watch failed: %s\n", strerror(errno));
-                    return;
-                }
-            }
-
-            /* Watch above will tell us about any future changes, so
-             * read the current state. */
-            if (read_package_list(global) == false) {
-                ERROR("read_package_list failed\n");
-                return;
-            }
-            active = true;
-        }
-
-        int event_pos = 0;
-        int res = read(nfd, event_buf, sizeof(event_buf));
-        if (res < (int) sizeof(*event)) {
-            if (errno == EINTR)
-                continue;
-            ERROR("failed to read inotify event: %s\n", strerror(errno));
-            return;
-        }
-
-        while (res >= (int) sizeof(*event)) {
-            int event_size;
-            event = (struct inotify_event *) (event_buf + event_pos);
-
-            TRACE("inotify event: %08x\n", event->mask);
-            if ((event->mask & IN_IGNORED) == IN_IGNORED) {
-                /* Previously watched file was deleted, probably due to move
-                 * that swapped in new data; re-arm the watch and read. */
-                active = false;
-            }
-
-            event_size = sizeof(*event) + event->len;
-            res -= event_size;
-            event_pos += event_size;
-        }
-    }
-}
-
-static int usage() {
-    ERROR("usage: sdcard [OPTIONS] <source_path> <label>\n"
-            "    -u: specify UID to run as\n"
-            "    -g: specify GID to run as\n"
-            "    -U: specify user ID that owns device\n"
-            "    -m: source_path is multi-user\n"
-            "    -w: runtime write mount has full write access\n"
-            "\n");
-    return 1;
-}
-
-static int fuse_setup(struct fuse* fuse, gid_t gid, mode_t mask) {
-    char opts[256];
-
-    fuse->fd = open("/dev/fuse", O_RDWR);
-    if (fuse->fd == -1) {
-        ERROR("failed to open fuse device: %s\n", strerror(errno));
-        return -1;
-    }
-
-    umount2(fuse->dest_path, MNT_DETACH);
-
-    snprintf(opts, sizeof(opts),
-            "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d",
-            fuse->fd, fuse->global->uid, fuse->global->gid);
-    if (mount("/dev/fuse", fuse->dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC |
-            MS_NOATIME, opts) != 0) {
-        ERROR("failed to mount fuse filesystem: %s\n", strerror(errno));
-        return -1;
-    }
-
-    fuse->gid = gid;
-    fuse->mask = mask;
-
-    return 0;
-}
-
-static void run(const char* source_path, const char* label, uid_t uid,
-        gid_t gid, userid_t userid, bool multi_user, bool full_write) {
-    struct fuse_global global;
-    struct fuse fuse_default;
-    struct fuse fuse_read;
-    struct fuse fuse_write;
-    struct fuse_handler handler_default;
-    struct fuse_handler handler_read;
-    struct fuse_handler handler_write;
-    pthread_t thread_default;
-    pthread_t thread_read;
-    pthread_t thread_write;
-
-    memset(&global, 0, sizeof(global));
-    memset(&fuse_default, 0, sizeof(fuse_default));
-    memset(&fuse_read, 0, sizeof(fuse_read));
-    memset(&fuse_write, 0, sizeof(fuse_write));
-    memset(&handler_default, 0, sizeof(handler_default));
-    memset(&handler_read, 0, sizeof(handler_read));
-    memset(&handler_write, 0, sizeof(handler_write));
-
-    pthread_mutex_init(&global.lock, NULL);
-    global.package_to_appid = hashmapCreate(256, str_hash, str_icase_equals);
-    global.uid = uid;
-    global.gid = gid;
-    global.multi_user = multi_user;
-    global.next_generation = 0;
-    global.inode_ctr = 1;
-
-    memset(&global.root, 0, sizeof(global.root));
-    global.root.nid = FUSE_ROOT_ID; /* 1 */
-    global.root.refcount = 2;
-    global.root.namelen = strlen(source_path);
-    global.root.name = strdup(source_path);
-    global.root.userid = userid;
-    global.root.uid = AID_ROOT;
-    global.root.under_android = false;
-
-    strcpy(global.source_path, source_path);
-
-    if (multi_user) {
-        global.root.perm = PERM_PRE_ROOT;
-        snprintf(global.obb_path, sizeof(global.obb_path), "%s/obb", source_path);
-    } else {
-        global.root.perm = PERM_ROOT;
-        snprintf(global.obb_path, sizeof(global.obb_path), "%s/Android/obb", source_path);
-    }
-
-    fuse_default.global = &global;
-    fuse_read.global = &global;
-    fuse_write.global = &global;
-
-    global.fuse_default = &fuse_default;
-    global.fuse_read = &fuse_read;
-    global.fuse_write = &fuse_write;
-
-    snprintf(fuse_default.dest_path, PATH_MAX, "/mnt/runtime/default/%s", label);
-    snprintf(fuse_read.dest_path, PATH_MAX, "/mnt/runtime/read/%s", label);
-    snprintf(fuse_write.dest_path, PATH_MAX, "/mnt/runtime/write/%s", label);
-
-    handler_default.fuse = &fuse_default;
-    handler_read.fuse = &fuse_read;
-    handler_write.fuse = &fuse_write;
-
-    handler_default.token = 0;
-    handler_read.token = 1;
-    handler_write.token = 2;
-
-    umask(0);
-
-    if (multi_user) {
-        /* Multi-user storage is fully isolated per user, so "other"
-         * permissions are completely masked off. */
-        if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
-                || fuse_setup(&fuse_read, AID_EVERYBODY, 0027)
-                || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0027)) {
-            ERROR("failed to fuse_setup\n");
-            exit(1);
-        }
-    } else {
-        /* Physical storage is readable by all users on device, but
-         * the Android directories are masked off to a single user
-         * deep inside attr_from_stat(). */
-        if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
-                || fuse_setup(&fuse_read, AID_EVERYBODY, full_write ? 0027 : 0022)
-                || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0022)) {
-            ERROR("failed to fuse_setup\n");
-            exit(1);
-        }
-    }
-
-    /* Drop privs */
-    if (setgroups(sizeof(kGroups) / sizeof(kGroups[0]), kGroups) < 0) {
-        ERROR("cannot setgroups: %s\n", strerror(errno));
-        exit(1);
-    }
-    if (setgid(gid) < 0) {
-        ERROR("cannot setgid: %s\n", strerror(errno));
-        exit(1);
-    }
-    if (setuid(uid) < 0) {
-        ERROR("cannot setuid: %s\n", strerror(errno));
-        exit(1);
-    }
-
-    if (multi_user) {
-        fs_prepare_dir(global.obb_path, 0775, uid, gid);
-    }
-
-    if (pthread_create(&thread_default, NULL, start_handler, &handler_default)
-            || pthread_create(&thread_read, NULL, start_handler, &handler_read)
-            || pthread_create(&thread_write, NULL, start_handler, &handler_write)) {
-        ERROR("failed to pthread_create\n");
-        exit(1);
-    }
-
-    watch_package_list(&global);
-    ERROR("terminated prematurely\n");
-    exit(1);
-}
-
-static int sdcardfs_setup(const char *source_path, const char *dest_path, uid_t fsuid,
-                        gid_t fsgid, bool multi_user, userid_t userid, gid_t gid, mode_t mask) {
-    char opts[256];
-
-    snprintf(opts, sizeof(opts),
-            "fsuid=%d,fsgid=%d,%smask=%d,userid=%d,gid=%d",
-            fsuid, fsgid, multi_user?"multiuser,":"", mask, userid, gid);
-
-    if (mount(source_path, dest_path, "sdcardfs",
-                        MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts) != 0) {
-        ERROR("failed to mount sdcardfs filesystem: %s\n", strerror(errno));
-        return -1;
-    }
-
-    return 0;
-}
-
-static void run_sdcardfs(const char* source_path, const char* label, uid_t uid,
-        gid_t gid, userid_t userid, bool multi_user, bool full_write) {
-    char dest_path_default[PATH_MAX];
-    char dest_path_read[PATH_MAX];
-    char dest_path_write[PATH_MAX];
-    char obb_path[PATH_MAX];
-    snprintf(dest_path_default, PATH_MAX, "/mnt/runtime/default/%s", label);
-    snprintf(dest_path_read, PATH_MAX, "/mnt/runtime/read/%s", label);
-    snprintf(dest_path_write, PATH_MAX, "/mnt/runtime/write/%s", label);
-
-    umask(0);
-    if (multi_user) {
-        /* Multi-user storage is fully isolated per user, so "other"
-         * permissions are completely masked off. */
-        if (sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
-                                                      AID_SDCARD_RW, 0006)
-                || sdcardfs_setup(source_path, dest_path_read, uid, gid, multi_user, userid,
-                                                      AID_EVERYBODY, 0027)
-                || sdcardfs_setup(source_path, dest_path_write, uid, gid, multi_user, userid,
-                                                      AID_EVERYBODY, full_write ? 0007 : 0027)) {
-            ERROR("failed to fuse_setup\n");
-            exit(1);
-        }
-    } else {
-        /* Physical storage is readable by all users on device, but
-         * the Android directories are masked off to a single user
-         * deep inside attr_from_stat(). */
-        if (sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
-                                                      AID_SDCARD_RW, 0006)
-                || sdcardfs_setup(source_path, dest_path_read, uid, gid, multi_user, userid,
-                                                      AID_EVERYBODY, full_write ? 0027 : 0022)
-                || sdcardfs_setup(source_path, dest_path_write, uid, gid, multi_user, userid,
-                                                      AID_EVERYBODY, full_write ? 0007 : 0022)) {
-            ERROR("failed to fuse_setup\n");
-            exit(1);
-        }
-    }
-
-    /* Drop privs */
-    if (setgroups(sizeof(kGroups) / sizeof(kGroups[0]), kGroups) < 0) {
-        ERROR("cannot setgroups: %s\n", strerror(errno));
-        exit(1);
-    }
-    if (setgid(gid) < 0) {
-        ERROR("cannot setgid: %s\n", strerror(errno));
-        exit(1);
-    }
-    if (setuid(uid) < 0) {
-        ERROR("cannot setuid: %s\n", strerror(errno));
-        exit(1);
-    }
-
-    if (multi_user) {
-        snprintf(obb_path, sizeof(obb_path), "%s/obb", source_path);
-        fs_prepare_dir(&obb_path[0], 0775, uid, gid);
-    }
-
-    exit(0);
-}
-
-static bool supports_sdcardfs(void) {
-    FILE *fp;
-    char *buf = NULL;
-    size_t buflen = 0;
-
-    fp = fopen("/proc/filesystems", "r");
-    if (!fp) {
-        ERROR("Could not read /proc/filesystems, error: %s\n", strerror(errno));
-        return false;
-    }
-    while ((getline(&buf, &buflen, fp)) > 0) {
-        if (strstr(buf, "sdcardfs\n")) {
-            free(buf);
-            fclose(fp);
-            return true;
-        }
-    }
-    free(buf);
-    fclose(fp);
-    return false;
-}
-
-static bool should_use_sdcardfs(void) {
-    char property[PROPERTY_VALUE_MAX];
-
-    // Allow user to have a strong opinion about state
-    property_get(PROP_SDCARDFS_USER, property, "");
-    if (!strcmp(property, "force_on")) {
-        ALOGW("User explicitly enabled sdcardfs");
-        return supports_sdcardfs();
-    } else if (!strcmp(property, "force_off")) {
-        ALOGW("User explicitly disabled sdcardfs");
-        return false;
-    }
-
-    // Fall back to device opinion about state
-    if (property_get_bool(PROP_SDCARDFS_DEVICE, false)) {
-        ALOGW("Device explicitly enabled sdcardfs");
-        return supports_sdcardfs();
-    } else {
-        ALOGW("Device explicitly disabled sdcardfs");
-        return false;
-    }
-}
-
-int main(int argc, char **argv) {
-    const char *source_path = NULL;
-    const char *label = NULL;
-    uid_t uid = 0;
-    gid_t gid = 0;
-    userid_t userid = 0;
-    bool multi_user = false;
-    bool full_write = false;
-    int i;
-    struct rlimit rlim;
-    int fs_version;
-
-    int opt;
-    while ((opt = getopt(argc, argv, "u:g:U:mw")) != -1) {
-        switch (opt) {
-            case 'u':
-                uid = strtoul(optarg, NULL, 10);
-                break;
-            case 'g':
-                gid = strtoul(optarg, NULL, 10);
-                break;
-            case 'U':
-                userid = strtoul(optarg, NULL, 10);
-                break;
-            case 'm':
-                multi_user = true;
-                break;
-            case 'w':
-                full_write = true;
-                break;
-            case '?':
-            default:
-                return usage();
-        }
-    }
-
-    for (i = optind; i < argc; i++) {
-        char* arg = argv[i];
-        if (!source_path) {
-            source_path = arg;
-        } else if (!label) {
-            label = arg;
-        } else {
-            ERROR("too many arguments\n");
-            return usage();
-        }
-    }
-
-    if (!source_path) {
-        ERROR("no source path specified\n");
-        return usage();
-    }
-    if (!label) {
-        ERROR("no label specified\n");
-        return usage();
-    }
-    if (!uid || !gid) {
-        ERROR("uid and gid must be nonzero\n");
-        return usage();
-    }
-
-    rlim.rlim_cur = 8192;
-    rlim.rlim_max = 8192;
-    if (setrlimit(RLIMIT_NOFILE, &rlim)) {
-        ERROR("Error setting RLIMIT_NOFILE, errno = %d\n", errno);
-    }
-
-    while ((fs_read_atomic_int("/data/.layout_version", &fs_version) == -1) || (fs_version < 3)) {
-        ERROR("installd fs upgrade not yet complete. Waiting...\n");
-        sleep(1);
-    }
-
-    if (should_use_sdcardfs()) {
-        run_sdcardfs(source_path, label, uid, gid, userid, multi_user, full_write);
-    } else {
-        run(source_path, label, uid, gid, userid, multi_user, full_write);
-    }
-    return 1;
-}
diff --git a/sdcard/sdcard.cpp b/sdcard/sdcard.cpp
new file mode 100644
index 0000000..bc502a0
--- /dev/null
+++ b/sdcard/sdcard.cpp
@@ -0,0 +1,500 @@
+// 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.
+
+#define LOG_TAG "sdcard"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/fuse.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/inotify.h>
+#include <sys/mount.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+#include <cutils/fs.h>
+#include <cutils/multiuser.h>
+#include <cutils/properties.h>
+
+#include <packagelistparser/packagelistparser.h>
+
+#include <libminijail.h>
+#include <scoped_minijail.h>
+
+#include <private/android_filesystem_config.h>
+
+// README
+//
+// What is this?
+//
+// sdcard is a program that uses FUSE to emulate FAT-on-sdcard style
+// directory permissions (all files are given fixed owner, group, and
+// permissions at creation, owner, group, and permissions are not
+// changeable, symlinks and hardlinks are not createable, etc.
+//
+// See usage() for command line options.
+//
+// It must be run as root, but will drop to requested UID/GID as soon as it
+// mounts a filesystem.  It will refuse to run if requested UID/GID are zero.
+//
+// Things I believe to be true:
+//
+// - ops that return a fuse_entry (LOOKUP, MKNOD, MKDIR, LINK, SYMLINK,
+// CREAT) must bump that node's refcount
+// - don't forget that FORGET can forget multiple references (req->nlookup)
+// - if an op that returns a fuse_entry fails writing the reply to the
+// kernel, you must rollback the refcount to reflect the reference the
+// kernel did not actually acquire
+//
+// This daemon can also derive custom filesystem permissions based on directory
+// structure when requested. These custom permissions support several features:
+//
+// - Apps can access their own files in /Android/data/com.example/ without
+// requiring any additional GIDs.
+// - Separate permissions for protecting directories like Pictures and Music.
+// - Multi-user separation on the same physical device.
+
+#include "fuse.h"
+
+#define PROP_SDCARDFS_DEVICE "ro.sys.sdcardfs"
+#define PROP_SDCARDFS_USER "persist.sys.sdcardfs"
+
+/* Supplementary groups to execute with. */
+static const gid_t kGroups[1] = { AID_PACKAGE_INFO };
+
+static bool package_parse_callback(pkg_info *info, void *userdata) {
+    struct fuse_global *global = (struct fuse_global *)userdata;
+    bool res = global->package_to_appid->emplace(info->name, info->uid).second;
+    packagelist_free(info);
+    return res;
+}
+
+static bool read_package_list(struct fuse_global* global) {
+    pthread_mutex_lock(&global->lock);
+
+    global->package_to_appid->clear();
+    bool rc = packagelist_parse(package_parse_callback, global);
+    DLOG(INFO) << "read_package_list: found " << global->package_to_appid->size() << " packages";
+
+    // Regenerate ownership details using newly loaded mapping.
+    derive_permissions_recursive_locked(global->fuse_default, &global->root);
+
+    pthread_mutex_unlock(&global->lock);
+
+    return rc;
+}
+
+static void watch_package_list(struct fuse_global* global) {
+    struct inotify_event *event;
+    char event_buf[512];
+
+    int nfd = inotify_init();
+    if (nfd == -1) {
+        PLOG(ERROR) << "inotify_init failed";
+        return;
+    }
+
+    bool active = false;
+    while (1) {
+        if (!active) {
+            int res = inotify_add_watch(nfd, PACKAGES_LIST_FILE, IN_DELETE_SELF);
+            if (res == -1) {
+                if (errno == ENOENT || errno == EACCES) {
+                    /* Framework may not have created the file yet, sleep and retry. */
+                    LOG(ERROR) << "missing \"" << PACKAGES_LIST_FILE << "\"; retrying...";
+                    sleep(3);
+                    continue;
+                } else {
+                    PLOG(ERROR) << "inotify_add_watch failed";
+                    return;
+                }
+            }
+
+            /* Watch above will tell us about any future changes, so
+             * read the current state. */
+            if (read_package_list(global) == false) {
+                LOG(ERROR) << "read_package_list failed";
+                return;
+            }
+            active = true;
+        }
+
+        int event_pos = 0;
+        ssize_t res = TEMP_FAILURE_RETRY(read(nfd, event_buf, sizeof(event_buf)));
+        if (res == -1) {
+            PLOG(ERROR) << "failed to read inotify event";
+            return;
+        } else if (static_cast<size_t>(res) < sizeof(*event)) {
+            LOG(ERROR) << "failed to read inotify event: read " << res << " expected "
+                       << sizeof(event_buf);
+            return;
+        }
+
+        while (res >= static_cast<ssize_t>(sizeof(*event))) {
+            int event_size;
+            event = reinterpret_cast<struct inotify_event*>(event_buf + event_pos);
+
+            DLOG(INFO) << "inotify event: " << std::hex << event->mask << std::dec;
+            if ((event->mask & IN_IGNORED) == IN_IGNORED) {
+                /* Previously watched file was deleted, probably due to move
+                 * that swapped in new data; re-arm the watch and read. */
+                active = false;
+            }
+
+            event_size = sizeof(*event) + event->len;
+            res -= event_size;
+            event_pos += event_size;
+        }
+    }
+}
+
+static int fuse_setup(struct fuse* fuse, gid_t gid, mode_t mask) {
+    char opts[256];
+
+    fuse->fd = TEMP_FAILURE_RETRY(open("/dev/fuse", O_RDWR | O_CLOEXEC));
+    if (fuse->fd == -1) {
+        PLOG(ERROR) << "failed to open fuse device";
+        return -1;
+    }
+
+    umount2(fuse->dest_path, MNT_DETACH);
+
+    snprintf(opts, sizeof(opts),
+            "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d",
+            fuse->fd, fuse->global->uid, fuse->global->gid);
+    if (mount("/dev/fuse", fuse->dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME,
+              opts) == -1) {
+        PLOG(ERROR) << "failed to mount fuse filesystem";
+        return -1;
+    }
+
+    fuse->gid = gid;
+    fuse->mask = mask;
+
+    return 0;
+}
+
+static void drop_privs(uid_t uid, gid_t gid) {
+    ScopedMinijail j(minijail_new());
+    minijail_set_supplementary_gids(j.get(), arraysize(kGroups), kGroups);
+    minijail_change_gid(j.get(), gid);
+    minijail_change_uid(j.get(), uid);
+    /* minijail_enter() will abort if priv-dropping fails. */
+    minijail_enter(j.get());
+}
+
+static void* start_handler(void* data) {
+    struct fuse_handler* handler = static_cast<fuse_handler*>(data);
+    handle_fuse_requests(handler);
+    return NULL;
+}
+
+static void run(const char* source_path, const char* label, uid_t uid,
+        gid_t gid, userid_t userid, bool multi_user, bool full_write) {
+    struct fuse_global global;
+    struct fuse fuse_default;
+    struct fuse fuse_read;
+    struct fuse fuse_write;
+    struct fuse_handler handler_default;
+    struct fuse_handler handler_read;
+    struct fuse_handler handler_write;
+    pthread_t thread_default;
+    pthread_t thread_read;
+    pthread_t thread_write;
+
+    memset(&global, 0, sizeof(global));
+    memset(&fuse_default, 0, sizeof(fuse_default));
+    memset(&fuse_read, 0, sizeof(fuse_read));
+    memset(&fuse_write, 0, sizeof(fuse_write));
+    memset(&handler_default, 0, sizeof(handler_default));
+    memset(&handler_read, 0, sizeof(handler_read));
+    memset(&handler_write, 0, sizeof(handler_write));
+
+    pthread_mutex_init(&global.lock, NULL);
+    global.package_to_appid = new AppIdMap;
+    global.uid = uid;
+    global.gid = gid;
+    global.multi_user = multi_user;
+    global.next_generation = 0;
+    global.inode_ctr = 1;
+
+    memset(&global.root, 0, sizeof(global.root));
+    global.root.nid = FUSE_ROOT_ID; /* 1 */
+    global.root.refcount = 2;
+    global.root.namelen = strlen(source_path);
+    global.root.name = strdup(source_path);
+    global.root.userid = userid;
+    global.root.uid = AID_ROOT;
+    global.root.under_android = false;
+
+    strcpy(global.source_path, source_path);
+
+    if (multi_user) {
+        global.root.perm = PERM_PRE_ROOT;
+        snprintf(global.obb_path, sizeof(global.obb_path), "%s/obb", source_path);
+    } else {
+        global.root.perm = PERM_ROOT;
+        snprintf(global.obb_path, sizeof(global.obb_path), "%s/Android/obb", source_path);
+    }
+
+    fuse_default.global = &global;
+    fuse_read.global = &global;
+    fuse_write.global = &global;
+
+    global.fuse_default = &fuse_default;
+    global.fuse_read = &fuse_read;
+    global.fuse_write = &fuse_write;
+
+    snprintf(fuse_default.dest_path, PATH_MAX, "/mnt/runtime/default/%s", label);
+    snprintf(fuse_read.dest_path, PATH_MAX, "/mnt/runtime/read/%s", label);
+    snprintf(fuse_write.dest_path, PATH_MAX, "/mnt/runtime/write/%s", label);
+
+    handler_default.fuse = &fuse_default;
+    handler_read.fuse = &fuse_read;
+    handler_write.fuse = &fuse_write;
+
+    handler_default.token = 0;
+    handler_read.token = 1;
+    handler_write.token = 2;
+
+    umask(0);
+
+    if (multi_user) {
+        /* Multi-user storage is fully isolated per user, so "other"
+         * permissions are completely masked off. */
+        if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
+                || fuse_setup(&fuse_read, AID_EVERYBODY, 0027)
+                || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0027)) {
+            PLOG(FATAL) << "failed to fuse_setup";
+        }
+    } else {
+        /* Physical storage is readable by all users on device, but
+         * the Android directories are masked off to a single user
+         * deep inside attr_from_stat(). */
+        if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
+                || fuse_setup(&fuse_read, AID_EVERYBODY, full_write ? 0027 : 0022)
+                || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0022)) {
+            PLOG(FATAL) << "failed to fuse_setup";
+        }
+    }
+
+    // Will abort if priv-dropping fails.
+    drop_privs(uid, gid);
+
+    if (multi_user) {
+        fs_prepare_dir(global.obb_path, 0775, uid, gid);
+    }
+
+    if (pthread_create(&thread_default, NULL, start_handler, &handler_default)
+            || pthread_create(&thread_read, NULL, start_handler, &handler_read)
+            || pthread_create(&thread_write, NULL, start_handler, &handler_write)) {
+        LOG(FATAL) << "failed to pthread_create";
+    }
+
+    watch_package_list(&global);
+    LOG(FATAL) << "terminated prematurely";
+}
+
+static bool sdcardfs_setup(const std::string& source_path, const std::string& dest_path, uid_t fsuid,
+                        gid_t fsgid, bool multi_user, userid_t userid, gid_t gid, mode_t mask) {
+    std::string opts = android::base::StringPrintf("fsuid=%d,fsgid=%d,%smask=%d,userid=%d,gid=%d",
+            fsuid, fsgid, multi_user?"multiuser,":"", mask, userid, gid);
+
+    if (mount(source_path.c_str(), dest_path.c_str(), "sdcardfs",
+              MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()) == -1) {
+        PLOG(ERROR) << "failed to mount sdcardfs filesystem";
+        return false;
+    }
+
+    return true;
+}
+
+static void run_sdcardfs(const std::string& source_path, const std::string& label, uid_t uid,
+        gid_t gid, userid_t userid, bool multi_user, bool full_write) {
+    std::string dest_path_default = "/mnt/runtime/default/" + label;
+    std::string dest_path_read = "/mnt/runtime/read/" + label;
+    std::string dest_path_write = "/mnt/runtime/write/" + label;
+
+    umask(0);
+    if (multi_user) {
+        // Multi-user storage is fully isolated per user, so "other"
+        // permissions are completely masked off.
+        if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
+                                                      AID_SDCARD_RW, 0006)
+                || !sdcardfs_setup(source_path, dest_path_read, uid, gid, multi_user, userid,
+                                                      AID_EVERYBODY, 0027)
+                || !sdcardfs_setup(source_path, dest_path_write, uid, gid, multi_user, userid,
+                                                      AID_EVERYBODY, full_write ? 0007 : 0027)) {
+            LOG(FATAL) << "failed to sdcardfs_setup";
+        }
+    } else {
+        // Physical storage is readable by all users on device, but
+        // the Android directories are masked off to a single user
+        // deep inside attr_from_stat().
+        if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
+                                                      AID_SDCARD_RW, 0006)
+                || !sdcardfs_setup(source_path, dest_path_read, uid, gid, multi_user, userid,
+                                                      AID_EVERYBODY, full_write ? 0027 : 0022)
+                || !sdcardfs_setup(source_path, dest_path_write, uid, gid, multi_user, userid,
+                                                      AID_EVERYBODY, full_write ? 0007 : 0022)) {
+            LOG(FATAL) << "failed to sdcardfs_setup";
+        }
+    }
+
+    // Will abort if priv-dropping fails.
+    drop_privs(uid, gid);
+
+    if (multi_user) {
+        std::string obb_path = source_path + "/obb";
+        fs_prepare_dir(obb_path.c_str(), 0775, uid, gid);
+    }
+
+    exit(0);
+}
+
+static bool supports_sdcardfs(void) {
+    std::string filesystems;
+    if (!android::base::ReadFileToString("/proc/filesystems", &filesystems)) {
+        PLOG(ERROR) << "Could not read /proc/filesystems";
+        return false;
+    }
+    for (const auto& fs : android::base::Split(filesystems, "\n")) {
+        if (fs.find("sdcardfs") != std::string::npos) return true;
+    }
+    return false;
+}
+
+static bool should_use_sdcardfs(void) {
+    char property[PROPERTY_VALUE_MAX];
+
+    // Allow user to have a strong opinion about state
+    property_get(PROP_SDCARDFS_USER, property, "");
+    if (!strcmp(property, "force_on")) {
+        LOG(WARNING) << "User explicitly enabled sdcardfs";
+        return supports_sdcardfs();
+    } else if (!strcmp(property, "force_off")) {
+        LOG(WARNING) << "User explicitly disabled sdcardfs";
+        return false;
+    }
+
+    // Fall back to device opinion about state
+    if (property_get_bool(PROP_SDCARDFS_DEVICE, false)) {
+        LOG(WARNING) << "Device explicitly enabled sdcardfs";
+        return supports_sdcardfs();
+    } else {
+        LOG(WARNING) << "Device explicitly disabled sdcardfs";
+        return false;
+    }
+}
+
+static int usage() {
+    LOG(ERROR) << "usage: sdcard [OPTIONS] <source_path> <label>"
+               << "    -u: specify UID to run as"
+               << "    -g: specify GID to run as"
+               << "    -U: specify user ID that owns device"
+               << "    -m: source_path is multi-user"
+               << "    -w: runtime write mount has full write access";
+    return 1;
+}
+
+int main(int argc, char **argv) {
+    const char *source_path = NULL;
+    const char *label = NULL;
+    uid_t uid = 0;
+    gid_t gid = 0;
+    userid_t userid = 0;
+    bool multi_user = false;
+    bool full_write = false;
+    int i;
+    struct rlimit rlim;
+    int fs_version;
+
+    int opt;
+    while ((opt = getopt(argc, argv, "u:g:U:mw")) != -1) {
+        switch (opt) {
+            case 'u':
+                uid = strtoul(optarg, NULL, 10);
+                break;
+            case 'g':
+                gid = strtoul(optarg, NULL, 10);
+                break;
+            case 'U':
+                userid = strtoul(optarg, NULL, 10);
+                break;
+            case 'm':
+                multi_user = true;
+                break;
+            case 'w':
+                full_write = true;
+                break;
+            case '?':
+            default:
+                return usage();
+        }
+    }
+
+    for (i = optind; i < argc; i++) {
+        char* arg = argv[i];
+        if (!source_path) {
+            source_path = arg;
+        } else if (!label) {
+            label = arg;
+        } else {
+            LOG(ERROR) << "too many arguments";
+            return usage();
+        }
+    }
+
+    if (!source_path) {
+        LOG(ERROR) << "no source path specified";
+        return usage();
+    }
+    if (!label) {
+        LOG(ERROR) << "no label specified";
+        return usage();
+    }
+    if (!uid || !gid) {
+        LOG(ERROR) << "uid and gid must be nonzero";
+        return usage();
+    }
+
+    rlim.rlim_cur = 8192;
+    rlim.rlim_max = 8192;
+    if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) {
+        PLOG(ERROR) << "setting RLIMIT_NOFILE failed";
+    }
+
+    while ((fs_read_atomic_int("/data/.layout_version", &fs_version) == -1) || (fs_version < 3)) {
+        LOG(ERROR) << "installd fs upgrade not yet complete; waiting...";
+        sleep(1);
+    }
+
+    if (should_use_sdcardfs()) {
+        run_sdcardfs(source_path, label, uid, gid, userid, multi_user, full_write);
+    } else {
+        run(source_path, label, uid, gid, userid, multi_user, full_write);
+    }
+    return 1;
+}
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 9ade759..5319ff4 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -3,7 +3,6 @@
 
 common_cflags := \
     -Werror -Wno-unused-parameter -Wno-unused-const-variable \
-    -I$(LOCAL_PATH)/upstream-netbsd/include/ \
     -include bsd-compatibility.h \
 
 
@@ -21,6 +20,7 @@
     upstream-netbsd/lib/libc/string/swab.c \
     upstream-netbsd/lib/libutil/raise_default_signal.c
 LOCAL_CFLAGS += $(common_cflags) -Dmain=dd_main -DNO_CONV
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/upstream-netbsd/include/
 LOCAL_MODULE := libtoolbox_dd
 include $(BUILD_STATIC_LIBRARY)
 
@@ -32,31 +32,19 @@
 
 OUR_TOOLS := \
     getevent \
-    iftop \
-    ioctl \
-    log \
-    nandread \
     newfs_msdos \
-    ps \
-    prlimit \
-    sendevent \
-    start \
-    stop \
-    top \
 
 ALL_TOOLS = $(BSD_TOOLS) $(OUR_TOOLS)
 
 LOCAL_SRC_FILES := \
-    start_stop.cpp \
     toolbox.c \
     $(patsubst %,%.c,$(OUR_TOOLS)) \
 
 LOCAL_CFLAGS += $(common_cflags)
-LOCAL_CONLYFLAGS += -std=gnu99
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/upstream-netbsd/include/
 
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
-    libselinux \
 
 LOCAL_WHOLE_STATIC_LIBRARIES := $(patsubst %,libtoolbox_%,$(BSD_TOOLS))
 
@@ -72,7 +60,7 @@
 $(LOCAL_PATH)/toolbox.c: $(intermediates)/tools.h
 
 TOOLS_H := $(intermediates)/tools.h
-$(TOOLS_H): PRIVATE_TOOLS := $(ALL_TOOLS)
+$(TOOLS_H): PRIVATE_TOOLS := toolbox $(ALL_TOOLS)
 $(TOOLS_H): PRIVATE_CUSTOM_TOOL = echo "/* file generated automatically */" > $@ ; for t in $(PRIVATE_TOOLS) ; do echo "TOOL($$t)" >> $@ ; done
 $(TOOLS_H): $(LOCAL_PATH)/Android.mk
 $(TOOLS_H):
@@ -80,7 +68,7 @@
 
 $(LOCAL_PATH)/getevent.c: $(intermediates)/input.h-labels.h
 
-UAPI_INPUT_EVENT_CODES_H := bionic/libc/kernel/uapi/linux/input-event-codes.h
+UAPI_INPUT_EVENT_CODES_H := bionic/libc/kernel/uapi/linux/input.h bionic/libc/kernel/uapi/linux/input-event-codes.h
 INPUT_H_LABELS_H := $(intermediates)/input.h-labels.h
 $(INPUT_H_LABELS_H): PRIVATE_LOCAL_PATH := $(LOCAL_PATH)
 # The PRIVATE_CUSTOM_TOOL line uses = to evaluate the output path late.
@@ -97,6 +85,7 @@
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := r.c
 LOCAL_CFLAGS += $(common_cflags)
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/upstream-netbsd/include/
 LOCAL_MODULE := r
 LOCAL_MODULE_TAGS := debug
 include $(BUILD_EXECUTABLE)
@@ -111,6 +100,7 @@
     upstream-netbsd/usr.bin/grep/queue.c \
     upstream-netbsd/usr.bin/grep/util.c
 LOCAL_CFLAGS += $(common_cflags)
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/upstream-netbsd/include/
 LOCAL_MODULE := grep
 LOCAL_POST_INSTALL_CMD := $(hide) $(foreach t,egrep fgrep,ln -sf grep $(TARGET_OUT)/bin/$(t);)
 include $(BUILD_EXECUTABLE)
diff --git a/toolbox/bsd-compatibility.h b/toolbox/bsd-compatibility.h
index 434d370..7c3ddd4 100644
--- a/toolbox/bsd-compatibility.h
+++ b/toolbox/bsd-compatibility.h
@@ -43,7 +43,7 @@
 #define __type_fit(t, a) (0 == 0)
 
 // TODO: should this be in our <sys/cdefs.h>?
-#define __arraycount(a) (sizeof(a) / sizeof(a[0]))
+#define __arraycount(a) (sizeof(a) / sizeof((a)[0]))
 
 // This at least matches GNU dd(1) behavior.
 #define SIGINFO SIGUSR1
diff --git a/toolbox/generate-input.h-labels.py b/toolbox/generate-input.h-labels.py
index a2b9111..c0e9fce 100755
--- a/toolbox/generate-input.h-labels.py
+++ b/toolbox/generate-input.h-labels.py
@@ -38,39 +38,40 @@
 
 r = re.compile(r'#define\s+(\S+)\s+((?:0x)?\d+)')
 
-with open(sys.argv[1], 'r') as f:
-  for line in f:
-    m = r.match(line)
-    if m:
-      name = m.group(1)
-      if name.startswith("INPUT_PROP_"):
-        input_prop_list.append(name)
-      elif name.startswith("EV_"):
-        ev_list.append(name)
-      elif name.startswith("SYN_"):
-        syn_list.append(name)
-      elif name.startswith("KEY_") or name.startswith("BTN_"):
-        key_list.append(name)
-      elif name.startswith("REL_"):
-        rel_list.append(name)
-      elif name.startswith("ABS_"):
-        abs_list.append(name)
-      elif name.startswith("SW_"):
-        sw_list.append(name)
-      elif name.startswith("MSC_"):
-        msc_list.append(name)
-      elif name.startswith("LED_"):
-        led_list.append(name)
-      elif name.startswith("REP_"):
-        rep_list.append(name)
-      elif name.startswith("SND_"):
-        snd_list.append(name)
-      elif name.startswith("MT_TOOL_"):
-        mt_tool_list.append(name)
-      elif name.startswith("FF_STATUS_"):
-        ff_status_list.append(name)
-      elif name.startswith("FF_"):
-        ff_list.append(name)
+for arg in sys.argv[1:]:
+  with open(arg, 'r') as f:
+    for line in f:
+      m = r.match(line)
+      if m:
+        name = m.group(1)
+        if name.startswith("INPUT_PROP_"):
+          input_prop_list.append(name)
+        elif name.startswith("EV_"):
+          ev_list.append(name)
+        elif name.startswith("SYN_"):
+          syn_list.append(name)
+        elif name.startswith("KEY_") or name.startswith("BTN_"):
+          key_list.append(name)
+        elif name.startswith("REL_"):
+          rel_list.append(name)
+        elif name.startswith("ABS_"):
+          abs_list.append(name)
+        elif name.startswith("SW_"):
+          sw_list.append(name)
+        elif name.startswith("MSC_"):
+          msc_list.append(name)
+        elif name.startswith("LED_"):
+          led_list.append(name)
+        elif name.startswith("REP_"):
+          rep_list.append(name)
+        elif name.startswith("SND_"):
+          snd_list.append(name)
+        elif name.startswith("MT_TOOL_"):
+          mt_tool_list.append(name)
+        elif name.startswith("FF_STATUS_"):
+          ff_status_list.append(name)
+        elif name.startswith("FF_"):
+          ff_list.append(name)
 
 def Dump(struct_name, values):
   print('static struct label %s[] = {' % (struct_name))
diff --git a/toolbox/getevent.c b/toolbox/getevent.c
index 30053af..e6def6b 100644
--- a/toolbox/getevent.c
+++ b/toolbox/getevent.c
@@ -9,6 +9,7 @@
 #include <sys/limits.h>
 #include <sys/poll.h>
 #include <linux/input.h>
+#include <err.h>
 #include <errno.h>
 #include <unistd.h>
 
@@ -110,10 +111,8 @@
                 break;
             bits_size = res + 16;
             bits = realloc(bits, bits_size * 2);
-            if(bits == NULL) {
-                fprintf(stderr, "failed to allocate buffer of size %d\n", (int)bits_size);
-                return 1;
-            }
+            if(bits == NULL)
+                err(1, "failed to allocate buffer of size %d\n", (int)bits_size);
         }
         res2 = 0;
         switch(i) {
diff --git a/toolbox/iftop.c b/toolbox/iftop.c
deleted file mode 100644
index 800c0f0..0000000
--- a/toolbox/iftop.c
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (c) 2008, The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the 
- *    distribution.
- *  * Neither the name of Google, Inc. nor the names of its contributors
- *    may be used to endorse or promote products derived from this
- *    software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE 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 <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <net/if.h>
-
-#define PROC_NET_DEV    "/proc/net/dev"
-
-#define MAX_IF           8   /* max interfaces we can handle */
-
-#ifndef PAGE_SIZE
-# define PAGE_SIZE 4096
-#endif
-
-#define _STR(s) #s
-#define STR(s) _STR(s)
-
-struct if_stats {
-    char name[IFNAMSIZ];
-
-    unsigned int mtu;
-
-    unsigned int rx_bytes;
-    unsigned int rx_packets;
-    unsigned int rx_errors;
-    unsigned int rx_dropped;
-
-    unsigned int tx_bytes;
-    unsigned int tx_packets;
-    unsigned int tx_errors;
-    unsigned int tx_dropped;
-};
-
-static int get_mtu(const char *if_name)
-{
-    struct ifreq ifr;
-    int s, ret;
-
-    s = socket(AF_INET, SOCK_DGRAM, 0);
-    if (s < 0) {
-        perror("socket");
-        exit(EXIT_FAILURE);
-    }
-
-    memset(&ifr, 0, sizeof(struct ifreq));
-    ifr.ifr_addr.sa_family = AF_INET;
-    strcpy(ifr.ifr_name, if_name);
-
-    ret = ioctl(s, SIOCGIFMTU, &ifr);
-    if (ret < 0) {
-        perror("ioctl");
-        exit(EXIT_FAILURE);
-    }
-
-    ret = close(s);
-    if (ret < 0) {
-        perror("close");
-        exit(EXIT_FAILURE);
-    }
-
-    return ifr.ifr_mtu;
-}
-
-static int get_interfaces(struct if_stats *ifs)
-{
-    char buf[PAGE_SIZE];
-    char *p;
-    int ret, nr, fd;
-
-    fd = open(PROC_NET_DEV, O_RDONLY);
-    if (fd < 0) {
-        perror("open");
-        exit(EXIT_FAILURE);
-    }
-
-    ret = read(fd, buf, sizeof(buf) - 1);
-    if (ret < 0) {
-        perror("read");
-        exit(EXIT_FAILURE);
-    } else if (!ret) {
-        fprintf(stderr, "reading " PROC_NET_DEV " returned premature EOF\n");
-        exit(EXIT_FAILURE);
-    }
-    buf[ret] = '\0';
-
-    /* skip down to the third line */
-    p = strchr(buf, '\n');
-    if (!p) {
-        fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
-        exit(EXIT_FAILURE);
-    }
-    p = strchr(p + 1, '\n');
-    if (!p) {
-        fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
-        exit(EXIT_FAILURE);
-    }
-    p += 1;
-
-    /*
-     * Key:
-     * if: (Rx) bytes packets errs drop fifo frame compressed multicast \
-     *     (Tx) bytes packets errs drop fifo colls carrier compressed
-     */
-    for (nr = 0; nr < MAX_IF; nr++) {
-        char *c;
-
-        ret = sscanf(p, "%" STR(IFNAMSIZ) "s", ifs->name);
-        if (ret != 1) {
-            fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
-            exit(EXIT_FAILURE);
-        }
-
-        /*
-         * This works around a bug in the proc file where large interface names
-         * or Rx byte counts eat the delimiter, breaking sscanf.
-         */
-        c = strchr(ifs->name, ':');
-        if (c)
-            *c = '\0';
-
-        p = strchr(p, ':') + 1;
-
-        ret = sscanf(p, "%u %u %u %u %*u %*u %*u %*u %u %u %u %u %*u %*u "
-                     "%*u %*u\n", &ifs->rx_bytes, &ifs->rx_packets,
-                     &ifs->rx_errors, &ifs->rx_dropped, &ifs->tx_bytes,
-                     &ifs->tx_packets, &ifs->tx_errors, &ifs->tx_dropped);
-        if (ret != 8) {
-            fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
-            exit(EXIT_FAILURE);
-        }
-
-        ifs->mtu = get_mtu(ifs->name);
-
-        p = strchr(p, '\n') + 1;
-        if (*p == '\0') {
-            nr++;
-            break;
-        }
-
-        ifs++;
-    }
-
-    ret = close(fd);
-    if (ret) {
-        perror("close");
-        exit(EXIT_FAILURE);
-    }
-
-    return nr;
-}
-
-static void print_header(void)
-{
-    printf("               Rx                              Tx\n");
-    printf("%-8s %-5s %-10s %-8s %-5s %-5s %-10s %-8s %-5s %-5s\n",
-           "name", "MTU", "bytes", "packets", "errs", "drpd", "bytes",
-           "packets", "errs", "drpd");
-}
-
-static int print_interfaces(struct if_stats *old, struct if_stats *new, int nr)
-{
-    int i = 0;
-
-    while (nr--) {
-        if (old->rx_packets || old->tx_packets) {
-            printf("%-8s %-5u %-10u %-8u %-5u %-5u %-10u %-8u %-5u %-5u\n",
-                   new->name, new->mtu,
-                   new->rx_bytes - old->rx_bytes,
-                   new->rx_packets - old->rx_packets,
-                   new->rx_errors - old->rx_errors,
-                   new->rx_dropped - old->rx_dropped,
-                   new->tx_bytes - old->tx_bytes,
-                   new->tx_packets - old->tx_packets,
-                   new->tx_errors - old->tx_errors,
-                   new->tx_dropped - old->tx_dropped);
-            i++;
-        }
-        old++;
-        new++;
-    }
-
-    return i;
-}
-
-static void usage(const char *cmd)
-{
-    fprintf(stderr, "usage: %s [ -r repeats] [ -d delay ]\n", cmd);
-}
-
-int iftop_main(int argc, char *argv[])
-{
-    struct if_stats ifs[2][MAX_IF];
-    int count = 0, header_interval = 22, delay = 1, i;
-    unsigned int toggle = 0;
-
-    for (i = 1; i < argc; i++) {
-        if (!strcmp(argv[i], "-d")) {
-            if (i >= argc - 1) {
-                fprintf(stderr, "Option -d requires an argument.\n");
-                exit(EXIT_FAILURE);
-            }
-            delay = atoi(argv[i++]);
-            if (!delay)
-                delay = 1;
-            continue;
-        }
-        if (!strcmp(argv[i], "-r")) {
-            if (i >= argc - 1) {
-                fprintf(stderr, "Option -r requires an argument.\n");
-                exit(EXIT_FAILURE);
-            }
-            header_interval = atoi(argv[i++]);
-            if (header_interval < MAX_IF)
-                header_interval = MAX_IF;
-            continue;
-        }
-        if (!strcmp(argv[i], "-h")) {
-            usage(argv[0]);
-            exit(EXIT_SUCCESS);
-        }
-        usage(argv[0]);
-        exit(EXIT_FAILURE);
-    }
-
-    get_interfaces(ifs[!toggle]);
-    if (header_interval)
-        print_header();
-    while (1) {
-        int nr;
-
-        sleep(delay);
-        nr = get_interfaces(ifs[toggle]);
-        if (header_interval && count + nr > header_interval) {
-            print_header();
-            count = 0;
-        }
-        count += print_interfaces(ifs[!toggle], ifs[toggle], nr);
-        toggle = !toggle;
-    }
-
-    return 0;
-}
diff --git a/toolbox/ioctl.c b/toolbox/ioctl.c
deleted file mode 100644
index 093e467..0000000
--- a/toolbox/ioctl.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (c) 2008, The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name of Google, Inc. nor the names of its contributors
- *    may be used to endorse or promote products derived from this
- *    software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE 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 <errno.h>
-#include <error.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-
-static void usage() {
-    fprintf(stderr, "%s [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>\n"
-            "  -l <length>   Length of io buffer\n"
-            "  -a <argsize>  Size of each argument (1-8)\n"
-            "  -r            Open device in read only mode\n"
-            "  -d            Direct argument (no iobuffer)\n"
-            "  -h            Print help\n", getprogname());
-    exit(1);
-}
-
-static int xstrtoi(const char* s, const char* what) {
-    char* endp;
-    errno = 0;
-    long result = strtol(s, &endp, 0);
-    if (errno != 0 || *endp != '\0') {
-        error(1, errno, "couldn't parse %s '%s'", what, s);
-    }
-    if (result > INT_MAX || result < INT_MIN) {
-        error(1, errno, "%s '%s' out of range", what, s);
-    }
-    return result;
-}
-
-int ioctl_main(int argc, char* argv[]) {
-    int read_only = 0;
-    int length = -1;
-    int arg_size = 4;
-    int direct_arg = 0;
-
-    void *ioctl_args = NULL;
-    uint8_t *ioctl_argp;
-    uint8_t *ioctl_argp_save = NULL;
-    int rem;
-
-    int c;
-    while ((c = getopt(argc, argv, "rdl:a:h")) != -1) {
-        switch (c) {
-        case 'r':
-            read_only = 1;
-            break;
-        case 'd':
-            direct_arg = 1;
-            break;
-        case 'l':
-            length = xstrtoi(optarg, "length");
-            break;
-        case 'a':
-            arg_size = xstrtoi(optarg, "argument size");
-            break;
-        case 'h':
-            usage();
-            break;
-        default:
-            error(1, 0, "invalid option -%c", optopt);
-        }
-    }
-
-    if (optind + 2 > argc) {
-        usage();
-    }
-
-    const char* device = argv[optind];
-    int fd;
-    if (strcmp(device, "-") == 0) {
-        fd = STDIN_FILENO;
-    } else {
-        fd = open(device, read_only ? O_RDONLY : (O_RDWR | O_SYNC));
-        if (fd == -1) {
-            error(1, errno, "cannot open %s", argv[optind]);
-        }
-    }
-    optind++;
-
-    // IOCTL(2) wants second parameter as a signed int.
-    // Let's let the user specify either negative numbers or large positive
-    // numbers, for the case where ioctl number is larger than INT_MAX.
-    errno = 0;
-    char* endp;
-    int ioctl_nr = UINT_MAX & strtoll(argv[optind], &endp, 0);
-    if (errno != 0 || *endp != '\0') {
-        error(1, errno, "couldn't parse ioctl number '%s'", argv[optind]);
-    }
-    optind++;
-
-    if(direct_arg) {
-        arg_size = 4;
-        length = 4;
-    }
-
-    if(length < 0) {
-        length = (argc - optind) * arg_size;
-    }
-    if(length) {
-        ioctl_args = calloc(1, length);
-
-        ioctl_argp_save = ioctl_argp = ioctl_args;
-        rem = length;
-        while (optind < argc) {
-            uint64_t tmp = strtoull(argv[optind], NULL, 0);
-            if (rem < arg_size) {
-                error(1, 0, "too many arguments");
-            }
-            memcpy(ioctl_argp, &tmp, arg_size);
-            ioctl_argp += arg_size;
-            rem -= arg_size;
-            optind++;
-        }
-    }
-    printf("sending ioctl 0x%x", ioctl_nr);
-    rem = length;
-    while(rem--) {
-        printf(" 0x%02x", *ioctl_argp_save++);
-    }
-    printf(" to %s\n", device);
-
-    int res;
-    if(direct_arg)
-        res = ioctl(fd, ioctl_nr, *(uint32_t*)ioctl_args);
-    else if(length)
-        res = ioctl(fd, ioctl_nr, ioctl_args);
-    else
-        res = ioctl(fd, ioctl_nr, 0);
-    if (res < 0) {
-        free(ioctl_args);
-        error(1, errno, "ioctl 0x%x failed (returned %d)", ioctl_nr, res);
-    }
-
-    if (length) {
-        printf("return buf:");
-        ioctl_argp = ioctl_args;
-        rem = length;
-        while(rem--) {
-            printf(" %02x", *ioctl_argp++);
-        }
-        printf("\n");
-    }
-    free(ioctl_args);
-    close(fd);
-    return 0;
-}
diff --git a/toolbox/log.c b/toolbox/log.c
deleted file mode 100644
index 2f020a8..0000000
--- a/toolbox/log.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (c) 2008, The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the 
- *    distribution.
- *  * Neither the name of Google, Inc. nor the names of its contributors
- *    may be used to endorse or promote products derived from this
- *    software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <log/logd.h>
-#include <ctype.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <stdlib.h>
-#include <cutils/sockets.h>
-#include <unistd.h>
-
-/*
- * Note: also accepts 0-9 priorities
- * returns ANDROID_LOG_UNKNOWN if the character is unrecognized
- */
-static android_LogPriority filterCharToPri (char c)
-{
-    android_LogPriority pri;
-
-    c = tolower(c);
-
-    if (c >= '0' && c <= '9') {
-        if (c >= ('0'+ANDROID_LOG_SILENT)) {
-            pri = ANDROID_LOG_VERBOSE;
-        } else {
-            pri = (android_LogPriority)(c - '0');
-        }
-    } else if (c == 'v') {
-        pri = ANDROID_LOG_VERBOSE;
-    } else if (c == 'd') {
-        pri = ANDROID_LOG_DEBUG;
-    } else if (c == 'i') {
-        pri = ANDROID_LOG_INFO;
-    } else if (c == 'w') {
-        pri = ANDROID_LOG_WARN;
-    } else if (c == 'e') {
-        pri = ANDROID_LOG_ERROR;
-    } else if (c == 'f') {
-        pri = ANDROID_LOG_FATAL;
-    } else if (c == 's') {
-        pri = ANDROID_LOG_SILENT;
-    } else if (c == '*') {
-        pri = ANDROID_LOG_DEFAULT;
-    } else {
-        pri = ANDROID_LOG_UNKNOWN;
-    }
-
-    return pri;
-}
-
-static int usage(const char *s)
-{
-    fprintf(stderr, "USAGE: %s [-p priorityChar] [-t tag] message\n", s);
-
-    fprintf(stderr, "\tpriorityChar should be one of:\n"
-                        "\t\tv,d,i,w,e\n");
-    exit(-1);
-}
-
-
-int log_main(int argc, char *argv[])
-{
-    android_LogPriority priority; 
-    const char *tag = "log";
-    char buffer[4096];
-    int i;
-
-    priority = ANDROID_LOG_INFO;
-
-    for (;;) {
-        int ret;
-
-        ret = getopt(argc, argv, "t:p:h");
-
-        if (ret < 0) {
-            break;
-        }
-
-        switch(ret) {
-            case 't':
-                tag = optarg;
-            break;
-            
-            case 'p':
-                priority = filterCharToPri(optarg[0]);
-                if (priority == ANDROID_LOG_UNKNOWN) {
-                    usage(argv[0]);                    
-                }
-            break;
-
-            case 'h':
-                usage(argv[0]);
-            break;
-        }
-    }
-
-    if (optind == argc) {
-        usage(argv[0]);
-    }
-
-    buffer[0] = '\0';
-    
-    for (i = optind ; i < argc ; i++) {
-        strlcat(buffer, argv[i], sizeof(buffer)-1);
-        strlcat(buffer, " ", sizeof(buffer)-1);
-    }
-
-    if(buffer[0] == 0) {
-        usage(argv[0]);
-    }
-
-    __android_log_print(priority, tag, "%s", buffer);
-
-    return 0;
-}
-
diff --git a/toolbox/nandread.c b/toolbox/nandread.c
deleted file mode 100644
index bd19942..0000000
--- a/toolbox/nandread.c
+++ /dev/null
@@ -1,287 +0,0 @@
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <mtd/mtd-user.h>
-#include <sys/ioctl.h>
-
-static int test_empty(const char *buf, size_t size)
-{
-    while(size--) {
-        if (*buf++ != (char) 0xff)
-            return 0;
-    }
-    return 1;
-}
-
-int nandread_main(int argc, char **argv)
-{
-    char *devname = NULL;
-    char *filename = NULL;
-    char *statusfilename = NULL;
-    char *statusext = ".stat";
-    int fd;
-    int outfd = -1;
-    FILE *statusfile = NULL;
-    int ret;
-    int verbose = 0;
-    void *buffer;
-    loff_t pos, opos, end, bpos;
-    loff_t start = 0, len = 0;
-    int c;
-    int i;
-    int empty_pages = 0;
-    int page_count = 0;
-    int bad_block;
-    int rawmode = 0;
-    uint32_t *oob_data;
-    uint8_t *oob_fixed;
-    size_t spare_size = 64;
-    struct mtd_info_user mtdinfo;
-    struct mtd_ecc_stats initial_ecc, last_ecc, ecc;
-    struct mtd_oob_buf oobbuf;
-    nand_ecclayout_t ecclayout;
-
-    do {
-        c = getopt(argc, argv, "d:f:s:S:L:Rhv");
-        if (c == EOF)
-            break;
-        switch (c) {
-        case 'd':
-            devname = optarg;
-            break;
-        case 'f':
-            filename = optarg;
-            break;
-        case 's':
-            spare_size = atoi(optarg);
-            break;
-        case 'S':
-            start = strtoll(optarg, NULL, 0);
-            break;
-        case 'L':
-            len = strtoll(optarg, NULL, 0);
-            break;
-        case 'R':
-            rawmode = 1;
-            break;
-        case 'v':
-            verbose++;
-            break;
-        case 'h':
-            fprintf(stderr, "%s [-d <dev>] [-f file] [-s sparesize] [-vh]\n"
-                    "  -d <dev>   Read from <dev>\n"
-                    "  -f <file>  Write to <file>\n"
-                    "  -s <size>  Number of spare bytes in file (default 64)\n"
-                    "  -R         Raw mode\n"
-                    "  -S <start> Start offset (default 0)\n"
-                    "  -L <len>   Length (default 0)\n"
-                    "  -v         Print info\n"
-                    "  -h         Print help\n", argv[0]);
-            return -1;
-        case '?':
-            fprintf(stderr, "%s: invalid option -%c\n",
-                argv[0], optopt);
-            exit(1);
-        }
-    } while (1);
-
-    if (optind < argc) {
-        fprintf(stderr, "%s: extra arguments\n", argv[0]);
-        return 1;
-    }
-    if (!devname) {
-        fprintf(stderr, "%s: specify device name\n", argv[0]);
-        return 1;
-    }
-
-    fd = open(devname, O_RDONLY);
-    if (fd < 0) {
-        fprintf(stderr, "cannot open %s, %s\n", devname, strerror(errno));
-        return 1;
-    }
-
-    if (filename) {
-        outfd = creat(filename, 0666);
-        if (outfd < 0) {
-            fprintf(stderr, "cannot open %s, %s\n", filename, strerror(errno));
-            return 1;
-        }
-        statusfilename = malloc(strlen(filename) + strlen(statusext) + 1);
-        strcpy(statusfilename, filename);
-        strcat(statusfilename, statusext);
-        statusfile = fopen(statusfilename, "w+");
-        if (!statusfile) {
-            fprintf(stderr, "cannot open %s, %s\n", statusfilename, strerror(errno));
-            return 1;
-        }
-    }
-
-    ret = ioctl(fd, MEMGETINFO, &mtdinfo);
-    if (ret) {
-        fprintf(stderr, "failed get mtd info for %s, %s\n",
-                devname, strerror(errno));
-        return 1;
-    }
-
-    if (verbose) {
-        printf("size: %u\n", mtdinfo.size);
-        printf("erase size: %u\n", mtdinfo.erasesize);
-        printf("write size: %u\n", mtdinfo.writesize);
-        printf("oob size: %u\n", mtdinfo.oobsize);
-    }
-
-    buffer = malloc(mtdinfo.writesize + mtdinfo.oobsize + spare_size);
-    if (!buffer) {
-        fprintf(stderr, "failed allocate readbuffer size %u\n",
-                mtdinfo.writesize + mtdinfo.oobsize);
-        return 1;
-    }
-
-    oobbuf.length = mtdinfo.oobsize;
-    oob_data = (uint32_t *)((uint8_t *)buffer + mtdinfo.writesize);
-    memset(oob_data, 0xff, mtdinfo.oobsize + spare_size);
-    oobbuf.ptr = (uint8_t *)oob_data + spare_size;
-
-    ret = ioctl(fd, ECCGETLAYOUT, &ecclayout);
-    if (ret) {
-        fprintf(stderr, "failed get ecc layout for %s, %s\n",
-                devname, strerror(errno));
-        return 1;
-    }
-    if (verbose) {
-        printf("ecc bytes: %u\n", ecclayout.eccbytes);
-        printf("oobavail: %u\n", ecclayout.oobavail);
-    }
-    if (ecclayout.oobavail > spare_size)
-        printf("oobavail, %d > image spare size, %zu\n", ecclayout.oobavail, spare_size);
-
-    ret = ioctl(fd, ECCGETSTATS, &initial_ecc);
-    if (ret) {
-        fprintf(stderr, "failed get ecc stats for %s, %s\n",
-                devname, strerror(errno));
-        return 1;
-    }
-    last_ecc = initial_ecc;
-
-    if (verbose) {
-        printf("initial ecc corrected: %u\n", initial_ecc.corrected);
-        printf("initial ecc failed: %u\n", initial_ecc.failed);
-        printf("initial ecc badblocks: %u\n", initial_ecc.badblocks);
-        printf("initial ecc bbtblocks: %u\n", initial_ecc.bbtblocks);
-    }
-
-    if (rawmode) {
-        rawmode = mtdinfo.oobsize;
-        ret = ioctl(fd, MTDFILEMODE, MTD_FILE_MODE_RAW);
-        if (ret) {
-            fprintf(stderr, "failed set raw mode for %s, %s\n",
-                    devname, strerror(errno));
-            return 1;
-        }
-    }
-
-    end = len ? (start + len) : mtdinfo.size;
-    for (pos = start, opos = 0; pos < end; pos += mtdinfo.writesize) {
-        bad_block = 0;
-        if (verbose > 3)
-            printf("reading at %" PRIx64 "\n", pos);
-        lseek64(fd, pos, SEEK_SET);
-        ret = read(fd, buffer, mtdinfo.writesize + rawmode);
-        if (ret < (int)mtdinfo.writesize) {
-            fprintf(stderr, "short read at %" PRIx64 ", %d\n", pos, ret);
-            bad_block = 2;
-        }
-        if (!rawmode) {
-            oobbuf.start = pos;
-            ret = ioctl(fd, MEMREADOOB, &oobbuf);
-            if (ret) {
-                fprintf(stderr, "failed to read oob data at %" PRIx64 ", %d\n", pos, ret);
-                bad_block = 2;
-            }
-        }
-        ret = ioctl(fd, ECCGETSTATS, &ecc);
-        if (ret) {
-            fprintf(stderr, "failed get ecc stats for %s, %s\n",
-                    devname, strerror(errno));
-            return 1;
-        }
-        bpos = pos / mtdinfo.erasesize * mtdinfo.erasesize;
-        ret = ioctl(fd, MEMGETBADBLOCK, &bpos);
-        if (ret && errno != EOPNOTSUPP) {
-            printf("badblock at %" PRIx64 "\n", pos);
-            bad_block = 1;
-        }
-        if (ecc.corrected != last_ecc.corrected)
-            printf("ecc corrected, %u, at %" PRIx64 "\n", ecc.corrected - last_ecc.corrected, pos);
-        if (ecc.failed != last_ecc.failed)
-            printf("ecc failed, %u, at %" PRIx64 "\n", ecc.failed - last_ecc.failed, pos);
-        if (ecc.badblocks != last_ecc.badblocks)
-            printf("ecc badblocks, %u, at %" PRIx64 "\n", ecc.badblocks - last_ecc.badblocks, pos);
-        if (ecc.bbtblocks != last_ecc.bbtblocks)
-            printf("ecc bbtblocks, %u, at %" PRIx64 "\n", ecc.bbtblocks - last_ecc.bbtblocks, pos);
-
-        if (!rawmode) {
-            oob_fixed = (uint8_t *)oob_data;
-            for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++) {
-                int len = ecclayout.oobfree[i].length;
-                if (oob_fixed + len > oobbuf.ptr)
-                    len = oobbuf.ptr - oob_fixed;
-                if (len) {
-                    memcpy(oob_fixed, oobbuf.ptr + ecclayout.oobfree[i].offset, len);
-                    oob_fixed += len;
-                }
-            }
-        }
-
-        if (outfd >= 0) {
-            ret = write(outfd, buffer, mtdinfo.writesize + spare_size);
-            if (ret < (int)(mtdinfo.writesize + spare_size)) {
-                fprintf(stderr, "short write at %" PRIx64 ", %d\n", pos, ret);
-                close(outfd);
-                outfd = -1;
-            }
-            if (ecc.corrected != last_ecc.corrected)
-                fprintf(statusfile, "%08" PRIx64 ": ecc corrected\n", opos);
-            if (ecc.failed != last_ecc.failed)
-                fprintf(statusfile, "%08" PRIx64 ": ecc failed\n", opos);
-            if (bad_block == 1)
-                fprintf(statusfile, "%08" PRIx64 ": badblock\n", opos);
-            if (bad_block == 2)
-                fprintf(statusfile, "%08" PRIx64 ": read error\n", opos);
-            opos += mtdinfo.writesize + spare_size;
-        }
-
-        last_ecc = ecc;
-        page_count++;
-        if (test_empty(buffer, mtdinfo.writesize + mtdinfo.oobsize + spare_size))
-            empty_pages++;
-        else if (verbose > 2 || (verbose > 1 && !(pos & (mtdinfo.erasesize - 1))))
-            printf("page at %" PRIx64 " (%d oobbytes): %08x %08x %08x %08x "
-                   "%08x %08x %08x %08x\n", pos, oobbuf.start,
-                   oob_data[0], oob_data[1], oob_data[2], oob_data[3],
-                   oob_data[4], oob_data[5], oob_data[6], oob_data[7]);
-    }
-
-    if (outfd >= 0) {
-        fprintf(statusfile, "read %d pages, %d empty\n", page_count, empty_pages);
-        fprintf(statusfile, "total ecc corrected, %u\n", ecc.corrected - initial_ecc.corrected);
-        fprintf(statusfile, "total ecc failed, %u\n", ecc.failed - initial_ecc.failed);
-        fprintf(statusfile, "total ecc badblocks, %u\n", ecc.badblocks - initial_ecc.badblocks);
-        fprintf(statusfile, "total ecc bbtblocks, %u\n", ecc.bbtblocks - initial_ecc.bbtblocks);
-    }
-    if (verbose) {
-        printf("total ecc corrected, %u\n", ecc.corrected - initial_ecc.corrected);
-        printf("total ecc failed, %u\n", ecc.failed - initial_ecc.failed);
-        printf("total ecc badblocks, %u\n", ecc.badblocks - initial_ecc.badblocks);
-        printf("total ecc bbtblocks, %u\n", ecc.bbtblocks - initial_ecc.bbtblocks);
-    }
-    printf("read %d pages, %d empty\n", page_count, empty_pages);
-
-    return 0;
-}
diff --git a/toolbox/newfs_msdos.c b/toolbox/newfs_msdos.c
index 5b98a01..d7047e2 100644
--- a/toolbox/newfs_msdos.c
+++ b/toolbox/newfs_msdos.c
@@ -695,7 +695,7 @@
                                                     (u_int)tm->tm_min));
                 mk4(bsx->volid, x);
                 mklabel(bsx->label, opt_L ? opt_L : "NO NAME");
-                sprintf(buf, "FAT%u", fat);
+                snprintf(buf, sizeof(buf), "FAT%u", fat);
                 setstr(bsx->type, buf, sizeof(bsx->type));
                 if (!opt_B) {
                     x1 += sizeof(struct bsx);
@@ -741,6 +741,7 @@
                 exit(1);
             }
         }
+        free(img);
     }
     return 0;
 }
diff --git a/toolbox/prlimit.c b/toolbox/prlimit.c
deleted file mode 100644
index 8cf202a..0000000
--- a/toolbox/prlimit.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2014, The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name of Google, Inc. nor the names of its contributors
- *    may be used to endorse or promote products derived from this
- *    software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-
-static void
-usage(const char *s)
-{
-    fprintf(stderr, "usage: %s pid resource cur max\n", s);
-    exit(EXIT_FAILURE);
-}
-
-int prlimit_main(int argc, char *argv[])
-{
-    pid_t pid;
-    struct rlimit64 rl;
-    int resource;
-    int rc;
-
-    if (argc != 5)
-        usage(*argv);
-
-    if (sscanf(argv[1], "%d", &pid) != 1)
-        usage(*argv);
-
-    if (sscanf(argv[2], "%d", &resource) != 1)
-        usage(*argv);
-
-    if (sscanf(argv[3], "%llu", &rl.rlim_cur) != 1)
-        usage(*argv);
-
-    if (sscanf(argv[4], "%llu", &rl.rlim_max) != 1)
-        usage(*argv);
-
-    printf("setting resource %d of pid %d to [%llu,%llu]\n", resource, pid,
-            rl.rlim_cur, rl.rlim_max);
-    rc = prlimit64(pid, resource, &rl, NULL);
-    if (rc < 0) {
-        perror("prlimit");
-        exit(EXIT_FAILURE);
-    }
-
-    return 0;
-}
diff --git a/toolbox/ps.c b/toolbox/ps.c
deleted file mode 100644
index 7e70c71..0000000
--- a/toolbox/ps.c
+++ /dev/null
@@ -1,334 +0,0 @@
-#include <ctype.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <cutils/sched_policy.h>
-
-static char *nexttoksep(char **strp, char *sep)
-{
-    char *p = strsep(strp,sep);
-    return (p == 0) ? "" : p;
-}
-static char *nexttok(char **strp)
-{
-    return nexttoksep(strp, " ");
-}
-
-#define SHOW_PRIO 1
-#define SHOW_TIME 2
-#define SHOW_POLICY 4
-#define SHOW_CPU  8
-#define SHOW_MACLABEL 16
-#define SHOW_NUMERIC_UID 32
-#define SHOW_ABI 64
-
-#if __LP64__
-#define PC_WIDTH 10 /* Realistically, the top bits will be 0, so don't waste space. */
-#else
-#define PC_WIDTH (2*sizeof(uintptr_t))
-#endif
-
-static int display_flags = 0;
-static int ppid_filter = 0;
-
-static void print_exe_abi(int pid);
-
-static int ps_line(int pid, int tid)
-{
-    char statline[1024];
-    char cmdline[1024];
-    char macline[1024];
-    char user[32];
-    struct stat stats;
-    int r;
-    char *ptr, *name, *state;
-    int ppid;
-    unsigned rss, vss;
-    uintptr_t eip;
-    unsigned utime, stime;
-    int prio, nice, rtprio, sched, psr;
-    struct passwd *pw;
-
-    sprintf(statline, "/proc/%d", tid ? tid : pid);
-    stat(statline, &stats);
-
-    if(tid) {
-        sprintf(statline, "/proc/%d/task/%d/stat", pid, tid);
-        cmdline[0] = 0;
-        snprintf(macline, sizeof(macline), "/proc/%d/task/%d/attr/current", pid, tid);
-    } else {
-        sprintf(statline, "/proc/%d/stat", pid);
-        sprintf(cmdline, "/proc/%d/cmdline", pid);
-        snprintf(macline, sizeof(macline), "/proc/%d/attr/current", pid);
-        int fd = open(cmdline, O_RDONLY);
-        if(fd == 0) {
-            r = 0;
-        } else {
-            r = read(fd, cmdline, 1023);
-            close(fd);
-            if(r < 0) r = 0;
-        }
-        cmdline[r] = 0;
-    }
-
-    int fd = open(statline, O_RDONLY);
-    if(fd == 0) return -1;
-    r = read(fd, statline, 1023);
-    close(fd);
-    if(r < 0) return -1;
-    statline[r] = 0;
-
-    ptr = statline;
-    nexttok(&ptr); // skip pid
-    ptr++;          // skip "("
-
-    name = ptr;
-    ptr = strrchr(ptr, ')'); // Skip to *last* occurence of ')',
-    *ptr++ = '\0';           // and null-terminate name.
-
-    ptr++;          // skip " "
-    state = nexttok(&ptr);
-    ppid = atoi(nexttok(&ptr));
-    nexttok(&ptr); // pgrp
-    nexttok(&ptr); // sid
-    nexttok(&ptr); // tty
-    nexttok(&ptr); // tpgid
-    nexttok(&ptr); // flags
-    nexttok(&ptr); // minflt
-    nexttok(&ptr); // cminflt
-    nexttok(&ptr); // majflt
-    nexttok(&ptr); // cmajflt
-#if 1
-    utime = atoi(nexttok(&ptr));
-    stime = atoi(nexttok(&ptr));
-#else
-    nexttok(&ptr); // utime
-    nexttok(&ptr); // stime
-#endif
-    nexttok(&ptr); // cutime
-    nexttok(&ptr); // cstime
-    prio = atoi(nexttok(&ptr));
-    nice = atoi(nexttok(&ptr));
-    nexttok(&ptr); // threads
-    nexttok(&ptr); // itrealvalue
-    nexttok(&ptr); // starttime
-    vss = strtoul(nexttok(&ptr), 0, 10); // vsize
-    rss = strtoul(nexttok(&ptr), 0, 10); // rss
-    nexttok(&ptr); // rlim
-    nexttok(&ptr); // startcode
-    nexttok(&ptr); // endcode
-    nexttok(&ptr); // startstack
-    nexttok(&ptr); // kstkesp
-    eip = strtoul(nexttok(&ptr), 0, 10); // kstkeip
-    nexttok(&ptr); // signal
-    nexttok(&ptr); // blocked
-    nexttok(&ptr); // sigignore
-    nexttok(&ptr); // sigcatch
-    nexttok(&ptr); // wchan
-    nexttok(&ptr); // nswap
-    nexttok(&ptr); // cnswap
-    nexttok(&ptr); // exit signal
-    psr = atoi(nexttok(&ptr)); // processor
-    rtprio = atoi(nexttok(&ptr)); // rt_priority
-    sched = atoi(nexttok(&ptr)); // scheduling policy
-
-    nexttok(&ptr); // tty
-
-    if(tid != 0) {
-        ppid = pid;
-        pid = tid;
-    }
-
-    pw = getpwuid(stats.st_uid);
-    if(pw == 0 || (display_flags & SHOW_NUMERIC_UID)) {
-        sprintf(user,"%d",(int)stats.st_uid);
-    } else {
-        strcpy(user,pw->pw_name);
-    }
-
-    if(ppid_filter != 0 && ppid != ppid_filter) {
-        return 0;
-    }
-
-    if (display_flags & SHOW_MACLABEL) {
-        fd = open(macline, O_RDONLY);
-        strcpy(macline, "-");
-        if (fd >= 0) {
-            r = read(fd, macline, sizeof(macline)-1);
-            close(fd);
-            if (r > 0)
-                macline[r] = 0;
-        }
-        printf("%-30s ", macline);
-    }
-
-    printf("%-9s %-5d %-5d %-6d %-5d", user, pid, ppid, vss / 1024, rss * 4);
-    if (display_flags & SHOW_CPU)
-        printf(" %-2d", psr);
-    if (display_flags & SHOW_PRIO)
-        printf(" %-5d %-5d %-5d %-5d", prio, nice, rtprio, sched);
-    if (display_flags & SHOW_POLICY) {
-        SchedPolicy p;
-        if (get_sched_policy(pid, &p) < 0)
-            printf(" un ");
-        else
-            printf(" %.2s ", get_sched_policy_name(p));
-    }
-    char path[PATH_MAX];
-    snprintf(path, sizeof(path), "/proc/%d/wchan", pid);
-    char wchan[10];
-    fd = open(path, O_RDONLY);
-    ssize_t wchan_len = read(fd, wchan, sizeof(wchan));
-    if (wchan_len == -1) {
-        wchan[wchan_len = 0] = '\0';
-    }
-    close(fd);
-    printf(" %10.*s %0*" PRIxPTR " %s ", (int) wchan_len, wchan, (int) PC_WIDTH, eip, state);
-    if (display_flags & SHOW_ABI) {
-        print_exe_abi(pid);
-    }
-    printf("%s", cmdline[0] ? cmdline : name);
-    if(display_flags&SHOW_TIME)
-        printf(" (u:%d, s:%d)", utime, stime);
-
-    printf("\n");
-    return 0;
-}
-
-static void print_exe_abi(int pid)
-{
-    int fd, r;
-    char exeline[1024];
-
-    sprintf(exeline, "/proc/%d/exe", pid);
-    fd = open(exeline, O_RDONLY);
-    if(fd == 0) {
-        printf("    ");
-        return;
-    }
-    r = read(fd, exeline, 5 /* 4 byte ELFMAG + 1 byte EI_CLASS */);
-    close(fd);
-    if(r < 0) {
-        printf("    ");
-        return;
-    }
-    if (memcmp("\177ELF", exeline, 4) != 0) {
-        printf("??  ");
-        return;
-    }
-    switch (exeline[4]) {
-        case 1:
-            printf("32  ");
-            return;
-        case 2:
-            printf("64  ");
-            return;
-        default:
-            printf("??  ");
-            return;
-    }
-}
-
-void ps_threads(int pid)
-{
-    char tmp[128];
-    DIR *d;
-    struct dirent *de;
-
-    sprintf(tmp,"/proc/%d/task",pid);
-    d = opendir(tmp);
-    if(d == 0) return;
-
-    while((de = readdir(d)) != 0){
-        if(isdigit(de->d_name[0])){
-            int tid = atoi(de->d_name);
-            if(tid == pid) continue;
-            ps_line(pid, tid);
-        }
-    }
-    closedir(d);
-}
-
-int ps_main(int argc, char **argv)
-{
-    DIR *d;
-    struct dirent *de;
-    int pidfilter = 0;
-    int threads = 0;
-
-    while(argc > 1){
-        if(!strcmp(argv[1],"-t")) {
-            threads = 1;
-        } else if(!strcmp(argv[1],"-n")) {
-            display_flags |= SHOW_NUMERIC_UID;
-        } else if(!strcmp(argv[1],"-x")) {
-            display_flags |= SHOW_TIME;
-        } else if(!strcmp(argv[1], "-Z")) {
-            display_flags |= SHOW_MACLABEL;
-        } else if(!strcmp(argv[1],"-P")) {
-            display_flags |= SHOW_POLICY;
-        } else if(!strcmp(argv[1],"-p")) {
-            display_flags |= SHOW_PRIO;
-        } else if(!strcmp(argv[1],"-c")) {
-            display_flags |= SHOW_CPU;
-        } else if(!strcmp(argv[1],"--abi")) {
-            display_flags |= SHOW_ABI;
-        } else if(!strcmp(argv[1],"--ppid")) {
-            ppid_filter = atoi(argv[2]);
-            if (ppid_filter == 0) {
-                /* Bug 26554285: Use printf because some apps require at least
-                 * one line of output to stdout even for errors.
-                 */
-                printf("bad ppid '%s'\n", argv[2]);
-                return 1;
-            }
-            argc--;
-            argv++;
-        } else {
-            pidfilter = atoi(argv[1]);
-            if (pidfilter == 0) {
-                /* Bug 26554285: Use printf because some apps require at least
-                 * one line of output to stdout even for errors.
-                 */
-                printf("bad pid '%s'\n", argv[1]);
-                return 1;
-            }
-        }
-        argc--;
-        argv++;
-    }
-
-    if (display_flags & SHOW_MACLABEL) {
-        printf("LABEL                          ");
-    }
-    printf("USER      PID   PPID  VSIZE  RSS  %s%s %sWCHAN      %*s  %sNAME\n",
-           (display_flags&SHOW_CPU)?"CPU ":"",
-           (display_flags&SHOW_PRIO)?"PRIO  NICE  RTPRI SCHED ":"",
-           (display_flags&SHOW_POLICY)?"PCY " : "",
-           (int) PC_WIDTH, "PC",
-           (display_flags&SHOW_ABI)?"ABI " : "");
-
-    d = opendir("/proc");
-    if(d == 0) return -1;
-
-    while((de = readdir(d)) != 0){
-        if(isdigit(de->d_name[0])){
-            int pid = atoi(de->d_name);
-            if(!pidfilter || (pidfilter == pid)) {
-                ps_line(pid, 0);
-                if(threads) ps_threads(pid);
-            }
-        }
-    }
-    closedir(d);
-    return 0;
-}
-
diff --git a/toolbox/sendevent.c b/toolbox/sendevent.c
deleted file mode 100644
index 4d0ca17..0000000
--- a/toolbox/sendevent.c
+++ /dev/null
@@ -1,42 +0,0 @@
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/input.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-
-int sendevent_main(int argc, char *argv[])
-{
-    int fd;
-    ssize_t ret;
-    int version;
-    struct input_event event;
-
-    if(argc != 5) {
-        fprintf(stderr, "use: %s device type code value\n", argv[0]);
-        return 1;
-    }
-
-    fd = open(argv[1], O_RDWR);
-    if(fd < 0) {
-        fprintf(stderr, "could not open %s, %s\n", argv[optind], strerror(errno));
-        return 1;
-    }
-    if (ioctl(fd, EVIOCGVERSION, &version)) {
-        fprintf(stderr, "could not get driver version for %s, %s\n", argv[optind], strerror(errno));
-        return 1;
-    }
-    memset(&event, 0, sizeof(event));
-    event.type = atoi(argv[2]);
-    event.code = atoi(argv[3]);
-    event.value = atoi(argv[4]);
-    ret = write(fd, &event, sizeof(event));
-    if(ret < (ssize_t) sizeof(event)) {
-        fprintf(stderr, "write event failed, %s\n", strerror(errno));
-        return -1;
-    }
-    return 0;
-}
diff --git a/toolbox/start.c b/toolbox/start.c
deleted file mode 100644
index cca5fef..0000000
--- a/toolbox/start.c
+++ /dev/null
@@ -1 +0,0 @@
-/* Needed by Android.mk. Actual code in start_stop.cpp. */
diff --git a/toolbox/start_stop.cpp b/toolbox/start_stop.cpp
deleted file mode 100644
index dc48c0c..0000000
--- a/toolbox/start_stop.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#include <error.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <cutils/properties.h>
-
-static const char* services[] = {
-  "netd",
-  "surfaceflinger",
-  "zygote",
-  "zygote_secondary",
-};
-
-static int start_stop(bool start, int argc, char* argv[]) {
-  if (getuid() != 0) error(1, 0, "must be root");
-  const char* property = start ? "ctl.start" : "ctl.stop";
-  if (argc > 2) {
-    error(1, 0, "usage: %s [SERVICE]\n", argv[0]);
-  } else if (argc == 2) {
-    property_set(property, argv[1]);
-  } else {
-    if (start) {
-      for (size_t i = 0; i < sizeof(services)/sizeof(services[0]); ++i) {
-        property_set(property, services[i]);
-      }
-    } else {
-      for (int i = sizeof(services)/sizeof(services[0]) - 1; i >= 0; --i) {
-        property_set(property, services[i]);
-      }
-    }
-  }
-  return 0;
-}
-
-extern "C" int start_main(int argc, char* argv[]) {
-  return start_stop(true, argc, argv);
-}
-
-extern "C" int stop_main(int argc, char* argv[]) {
-  return start_stop(false, argc, argv);
-}
diff --git a/toolbox/stop.c b/toolbox/stop.c
deleted file mode 100644
index cca5fef..0000000
--- a/toolbox/stop.c
+++ /dev/null
@@ -1 +0,0 @@
-/* Needed by Android.mk. Actual code in start_stop.cpp. */
diff --git a/toolbox/toolbox.c b/toolbox/toolbox.c
index 915da44..b5a942c 100644
--- a/toolbox/toolbox.c
+++ b/toolbox/toolbox.c
@@ -4,29 +4,14 @@
 #include <string.h>
 #include <unistd.h>
 
-int main(int, char **);
-
-static int toolbox_main(int argc, char **argv)
-{
-    // "toolbox foo ..." is equivalent to "foo ..."
-    if (argc > 1) {
-        return main(argc - 1, argv + 1);
-    } else {
-        printf("Toolbox!\n");
-        return 0;
-    }
-}
-
 #define TOOL(name) int name##_main(int, char**);
 #include "tools.h"
 #undef TOOL
 
-static struct 
-{
-    const char *name;
+static struct {
+    const char* name;
     int (*func)(int, char**);
 } tools[] = {
-    { "toolbox", toolbox_main },
 #define TOOL(name) { #name, name##_main },
 #include "tools.h"
 #undef TOOL
@@ -40,33 +25,35 @@
     _exit(0);
 }
 
-int main(int argc, char **argv)
-{
-    int i;
-    char *name = argv[0];
-
+int main(int argc, char** argv) {
     // Let's assume that none of this code handles broken pipes. At least ls,
     // ps, and top were broken (though I'd previously added this fix locally
     // to top). We exit rather than use SIG_IGN because tools like top will
     // just keep on writing to nowhere forever if we don't stop them.
     signal(SIGPIPE, SIGPIPE_handler);
 
-    if((argc > 1) && (argv[1][0] == '@')) {
-        name = argv[1] + 1;
-        argc--;
-        argv++;
-    } else {
-        char *cmd = strrchr(argv[0], '/');
-        if (cmd)
-            name = cmd + 1;
-    }
+    char* cmd = strrchr(argv[0], '/');
+    char* name = cmd ? (cmd + 1) : argv[0];
 
-    for(i = 0; tools[i].name; i++){
-        if(!strcmp(tools[i].name, name)){
+    for (size_t i = 0; tools[i].name; i++) {
+        if (!strcmp(tools[i].name, name)) {
             return tools[i].func(argc, argv);
         }
     }
 
     printf("%s: no such tool\n", argv[0]);
-    return -1;
+    return 127;
+}
+
+int toolbox_main(int argc, char** argv) {
+    // "toolbox foo ..." is equivalent to "foo ..."
+    if (argc > 1) {
+        return main(argc - 1, argv + 1);
+    }
+
+    // Plain "toolbox" lists the tools.
+    for (size_t i = 1; tools[i].name; i++) {
+        printf("%s%c", tools[i].name, tools[i+1].name ? ' ' : '\n');
+    }
+    return 0;
 }
diff --git a/toolbox/top.c b/toolbox/top.c
deleted file mode 100644
index 6fda132..0000000
--- a/toolbox/top.c
+++ /dev/null
@@ -1,589 +0,0 @@
-/*
- * Copyright (c) 2008, The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name of Google, Inc. nor the names of its contributors
- *    may be used to endorse or promote products derived from this
- *    software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE 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 <ctype.h>
-#include <dirent.h>
-#include <grp.h>
-#include <inttypes.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <cutils/sched_policy.h>
-
-struct cpu_info {
-    long unsigned utime, ntime, stime, itime;
-    long unsigned iowtime, irqtime, sirqtime;
-};
-
-#define PROC_NAME_LEN 64
-#define THREAD_NAME_LEN 32
-#define POLICY_NAME_LEN 4
-
-struct proc_info {
-    struct proc_info *next;
-    pid_t pid;
-    pid_t tid;
-    uid_t uid;
-    gid_t gid;
-    char name[PROC_NAME_LEN];
-    char tname[THREAD_NAME_LEN];
-    char state;
-    uint64_t utime;
-    uint64_t stime;
-    char pr[3];
-    long ni;
-    uint64_t delta_utime;
-    uint64_t delta_stime;
-    uint64_t delta_time;
-    uint64_t vss;
-    uint64_t rss;
-    int num_threads;
-    char policy[POLICY_NAME_LEN];
-};
-
-struct proc_list {
-    struct proc_info **array;
-    int size;
-};
-
-#define die(...) { fprintf(stderr, __VA_ARGS__); exit(EXIT_FAILURE); }
-
-#define INIT_PROCS 50
-#define THREAD_MULT 8
-static struct proc_info **old_procs, **new_procs;
-static int num_old_procs, num_new_procs;
-static struct proc_info *free_procs;
-static int num_used_procs, num_free_procs;
-
-static int max_procs, delay, iterations, threads;
-
-static struct cpu_info old_cpu, new_cpu;
-
-static struct proc_info *alloc_proc(void);
-static void free_proc(struct proc_info *proc);
-static void read_procs(void);
-static int read_stat(char *filename, struct proc_info *proc);
-static void read_policy(int pid, struct proc_info *proc);
-static void add_proc(int proc_num, struct proc_info *proc);
-static int read_cmdline(char *filename, struct proc_info *proc);
-static int read_status(char *filename, struct proc_info *proc);
-static void print_procs(void);
-static struct proc_info *find_old_proc(pid_t pid, pid_t tid);
-static void free_old_procs(void);
-static int (*proc_cmp)(const void *a, const void *b);
-static int proc_cpu_cmp(const void *a, const void *b);
-static int proc_vss_cmp(const void *a, const void *b);
-static int proc_rss_cmp(const void *a, const void *b);
-static int proc_thr_cmp(const void *a, const void *b);
-static int numcmp(long long a, long long b);
-static void usage(char *cmd);
-
-int top_main(int argc, char *argv[]) {
-    num_used_procs = num_free_procs = 0;
-
-    max_procs = 0;
-    delay = 3;
-    iterations = -1;
-    proc_cmp = &proc_cpu_cmp;
-    for (int i = 1; i < argc; i++) {
-        if (!strcmp(argv[i], "-m")) {
-            if (i + 1 >= argc) {
-                fprintf(stderr, "Option -m expects an argument.\n");
-                usage(argv[0]);
-                exit(EXIT_FAILURE);
-            }
-            max_procs = atoi(argv[++i]);
-            continue;
-        }
-        if (!strcmp(argv[i], "-n")) {
-            if (i + 1 >= argc) {
-                fprintf(stderr, "Option -n expects an argument.\n");
-                usage(argv[0]);
-                exit(EXIT_FAILURE);
-            }
-            iterations = atoi(argv[++i]);
-            continue;
-        }
-        if (!strcmp(argv[i], "-d")) {
-            if (i + 1 >= argc) {
-                fprintf(stderr, "Option -d expects an argument.\n");
-                usage(argv[0]);
-                exit(EXIT_FAILURE);
-            }
-            delay = atoi(argv[++i]);
-            continue;
-        }
-        if (!strcmp(argv[i], "-s")) {
-            if (i + 1 >= argc) {
-                fprintf(stderr, "Option -s expects an argument.\n");
-                usage(argv[0]);
-                exit(EXIT_FAILURE);
-            }
-            ++i;
-            if (!strcmp(argv[i], "cpu")) { proc_cmp = &proc_cpu_cmp; continue; }
-            if (!strcmp(argv[i], "vss")) { proc_cmp = &proc_vss_cmp; continue; }
-            if (!strcmp(argv[i], "rss")) { proc_cmp = &proc_rss_cmp; continue; }
-            if (!strcmp(argv[i], "thr")) { proc_cmp = &proc_thr_cmp; continue; }
-            fprintf(stderr, "Invalid argument \"%s\" for option -s.\n", argv[i]);
-            exit(EXIT_FAILURE);
-        }
-        if (!strcmp(argv[i], "-H") || !strcmp(argv[i], "-t")) { threads = 1; continue; }
-        if (!strcmp(argv[i], "-h")) {
-            usage(argv[0]);
-            exit(EXIT_SUCCESS);
-        }
-        fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]);
-        usage(argv[0]);
-        exit(EXIT_FAILURE);
-    }
-
-    if (threads && proc_cmp == &proc_thr_cmp) {
-        fprintf(stderr, "Sorting by threads per thread makes no sense!\n");
-        exit(EXIT_FAILURE);
-    }
-
-    free_procs = NULL;
-
-    num_new_procs = num_old_procs = 0;
-    new_procs = old_procs = NULL;
-
-    read_procs();
-    while ((iterations == -1) || (iterations-- > 0)) {
-        old_procs = new_procs;
-        num_old_procs = num_new_procs;
-        memcpy(&old_cpu, &new_cpu, sizeof(old_cpu));
-        read_procs();
-        print_procs();
-        free_old_procs();
-        fflush(stdout);
-        if (iterations != 0) sleep(delay);
-    }
-
-    return 0;
-}
-
-static struct proc_info *alloc_proc(void) {
-    struct proc_info *proc;
-
-    if (free_procs) {
-        proc = free_procs;
-        free_procs = free_procs->next;
-        num_free_procs--;
-    } else {
-        proc = malloc(sizeof(*proc));
-        if (!proc) die("Could not allocate struct process_info.\n");
-    }
-
-    num_used_procs++;
-
-    return proc;
-}
-
-static void free_proc(struct proc_info *proc) {
-    proc->next = free_procs;
-    free_procs = proc;
-
-    num_used_procs--;
-    num_free_procs++;
-}
-
-#define MAX_LINE 256
-
-static void read_procs(void) {
-    DIR *proc_dir, *task_dir;
-    struct dirent *pid_dir, *tid_dir;
-    char filename[64];
-    FILE *file;
-    int proc_num;
-    struct proc_info *proc;
-    pid_t pid, tid;
-
-    int i;
-
-    proc_dir = opendir("/proc");
-    if (!proc_dir) die("Could not open /proc.\n");
-
-    new_procs = calloc(INIT_PROCS * (threads ? THREAD_MULT : 1), sizeof(struct proc_info *));
-    num_new_procs = INIT_PROCS * (threads ? THREAD_MULT : 1);
-
-    file = fopen("/proc/stat", "r");
-    if (!file) die("Could not open /proc/stat.\n");
-    fscanf(file, "cpu  %lu %lu %lu %lu %lu %lu %lu", &new_cpu.utime, &new_cpu.ntime, &new_cpu.stime,
-            &new_cpu.itime, &new_cpu.iowtime, &new_cpu.irqtime, &new_cpu.sirqtime);
-    fclose(file);
-
-    proc_num = 0;
-    while ((pid_dir = readdir(proc_dir))) {
-        if (!isdigit(pid_dir->d_name[0]))
-            continue;
-
-        pid = atoi(pid_dir->d_name);
-
-        struct proc_info cur_proc;
-
-        if (!threads) {
-            proc = alloc_proc();
-
-            proc->pid = proc->tid = pid;
-
-            sprintf(filename, "/proc/%d/stat", pid);
-            read_stat(filename, proc);
-
-            sprintf(filename, "/proc/%d/cmdline", pid);
-            read_cmdline(filename, proc);
-
-            sprintf(filename, "/proc/%d/status", pid);
-            read_status(filename, proc);
-
-            read_policy(pid, proc);
-
-            proc->num_threads = 0;
-        } else {
-            sprintf(filename, "/proc/%d/cmdline", pid);
-            read_cmdline(filename, &cur_proc);
-
-            sprintf(filename, "/proc/%d/status", pid);
-            read_status(filename, &cur_proc);
-
-            proc = NULL;
-        }
-
-        sprintf(filename, "/proc/%d/task", pid);
-        task_dir = opendir(filename);
-        if (!task_dir) continue;
-
-        while ((tid_dir = readdir(task_dir))) {
-            if (!isdigit(tid_dir->d_name[0]))
-                continue;
-
-            if (threads) {
-                tid = atoi(tid_dir->d_name);
-
-                proc = alloc_proc();
-
-                proc->pid = pid; proc->tid = tid;
-
-                sprintf(filename, "/proc/%d/task/%d/stat", pid, tid);
-                read_stat(filename, proc);
-
-                read_policy(tid, proc);
-
-                strcpy(proc->name, cur_proc.name);
-                proc->uid = cur_proc.uid;
-                proc->gid = cur_proc.gid;
-
-                add_proc(proc_num++, proc);
-            } else {
-                proc->num_threads++;
-            }
-        }
-
-        closedir(task_dir);
-
-        if (!threads)
-            add_proc(proc_num++, proc);
-    }
-
-    for (i = proc_num; i < num_new_procs; i++)
-        new_procs[i] = NULL;
-
-    closedir(proc_dir);
-}
-
-static int read_stat(char *filename, struct proc_info *proc) {
-    FILE *file;
-    char buf[MAX_LINE], *open_paren, *close_paren;
-
-    file = fopen(filename, "r");
-    if (!file) return 1;
-    fgets(buf, MAX_LINE, file);
-    fclose(file);
-
-    /* Split at first '(' and last ')' to get process name. */
-    open_paren = strchr(buf, '(');
-    close_paren = strrchr(buf, ')');
-    if (!open_paren || !close_paren) return 1;
-
-    *open_paren = *close_paren = '\0';
-    strncpy(proc->tname, open_paren + 1, THREAD_NAME_LEN);
-    proc->tname[THREAD_NAME_LEN-1] = 0;
-
-    // Scan rest of string.
-    long pr;
-    sscanf(close_paren + 1,
-           " %c "
-           "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
-           "%" SCNu64 // utime %lu (14)
-           "%" SCNu64 // stime %lu (15)
-           "%*d %*d "
-           "%ld " // priority %ld (18)
-           "%ld " // nice %ld (19)
-           "%*d %*d %*d "
-           "%" SCNu64 // vsize %lu (23)
-           "%" SCNu64, // rss %ld (24)
-           &proc->state,
-           &proc->utime,
-           &proc->stime,
-           &pr,
-           &proc->ni,
-           &proc->vss,
-           &proc->rss);
-
-    // Translate the PR field.
-    if (pr < -9) strcpy(proc->pr, "RT");
-    else snprintf(proc->pr, sizeof(proc->pr), "%ld", pr);
-
-    return 0;
-}
-
-static void add_proc(int proc_num, struct proc_info *proc) {
-    int i;
-
-    if (proc_num >= num_new_procs) {
-        new_procs = realloc(new_procs, 2 * num_new_procs * sizeof(struct proc_info *));
-        if (!new_procs) die("Could not expand procs array.\n");
-        for (i = num_new_procs; i < 2 * num_new_procs; i++)
-            new_procs[i] = NULL;
-        num_new_procs = 2 * num_new_procs;
-    }
-    new_procs[proc_num] = proc;
-}
-
-static int read_cmdline(char *filename, struct proc_info *proc) {
-    FILE *file;
-    char line[MAX_LINE];
-
-    line[0] = '\0';
-    file = fopen(filename, "r");
-    if (!file) return 1;
-    fgets(line, MAX_LINE, file);
-    fclose(file);
-    if (strlen(line) > 0) {
-        strncpy(proc->name, line, PROC_NAME_LEN);
-        proc->name[PROC_NAME_LEN-1] = 0;
-    } else
-        proc->name[0] = 0;
-    return 0;
-}
-
-static void read_policy(int pid, struct proc_info *proc) {
-    SchedPolicy p;
-    if (get_sched_policy(pid, &p) < 0)
-        strlcpy(proc->policy, "unk", POLICY_NAME_LEN);
-    else {
-        strlcpy(proc->policy, get_sched_policy_name(p), POLICY_NAME_LEN);
-        proc->policy[2] = '\0';
-    }
-}
-
-static int read_status(char *filename, struct proc_info *proc) {
-    FILE *file;
-    char line[MAX_LINE];
-    unsigned int uid, gid;
-
-    file = fopen(filename, "r");
-    if (!file) return 1;
-    while (fgets(line, MAX_LINE, file)) {
-        sscanf(line, "Uid: %u", &uid);
-        sscanf(line, "Gid: %u", &gid);
-    }
-    fclose(file);
-    proc->uid = uid; proc->gid = gid;
-    return 0;
-}
-
-static void print_procs(void) {
-    static int call = 0;
-    int i;
-    struct proc_info *old_proc, *proc;
-    long unsigned total_delta_time;
-
-    for (i = 0; i < num_new_procs; i++) {
-        if (new_procs[i]) {
-            old_proc = find_old_proc(new_procs[i]->pid, new_procs[i]->tid);
-            if (old_proc) {
-                new_procs[i]->delta_utime = new_procs[i]->utime - old_proc->utime;
-                new_procs[i]->delta_stime = new_procs[i]->stime - old_proc->stime;
-            } else {
-                new_procs[i]->delta_utime = 0;
-                new_procs[i]->delta_stime = 0;
-            }
-            new_procs[i]->delta_time = new_procs[i]->delta_utime + new_procs[i]->delta_stime;
-        }
-    }
-
-    total_delta_time = (new_cpu.utime + new_cpu.ntime + new_cpu.stime + new_cpu.itime
-                        + new_cpu.iowtime + new_cpu.irqtime + new_cpu.sirqtime)
-                     - (old_cpu.utime + old_cpu.ntime + old_cpu.stime + old_cpu.itime
-                        + old_cpu.iowtime + old_cpu.irqtime + old_cpu.sirqtime);
-
-    qsort(new_procs, num_new_procs, sizeof(struct proc_info *), proc_cmp);
-
-    if (call++ > 0) printf("\n\n\n");
-    printf("User %ld%%, System %ld%%, IOW %ld%%, IRQ %ld%%\n",
-            ((new_cpu.utime + new_cpu.ntime) - (old_cpu.utime + old_cpu.ntime)) * 100  / total_delta_time,
-            ((new_cpu.stime ) - (old_cpu.stime)) * 100 / total_delta_time,
-            ((new_cpu.iowtime) - (old_cpu.iowtime)) * 100 / total_delta_time,
-            ((new_cpu.irqtime + new_cpu.sirqtime)
-                    - (old_cpu.irqtime + old_cpu.sirqtime)) * 100 / total_delta_time);
-    printf("User %ld + Nice %ld + Sys %ld + Idle %ld + IOW %ld + IRQ %ld + SIRQ %ld = %ld\n",
-            new_cpu.utime - old_cpu.utime,
-            new_cpu.ntime - old_cpu.ntime,
-            new_cpu.stime - old_cpu.stime,
-            new_cpu.itime - old_cpu.itime,
-            new_cpu.iowtime - old_cpu.iowtime,
-            new_cpu.irqtime - old_cpu.irqtime,
-            new_cpu.sirqtime - old_cpu.sirqtime,
-            total_delta_time);
-    printf("\n");
-    if (!threads)
-        printf("%5s %-8s %2s %3s %4s %1s %5s %7s %7s %3s %s\n", "PID", "USER", "PR", "NI", "CPU%", "S", "#THR", "VSS", "RSS", "PCY", "Name");
-    else
-        printf("%5s %5s %-8s %2s %3s %4s %1s %7s %7s %3s %-15s %s\n", "PID", "TID", "USER", "PR", "NI", "CPU%", "S", "VSS", "RSS", "PCY", "Thread", "Proc");
-
-    for (i = 0; i < num_new_procs; i++) {
-        proc = new_procs[i];
-
-        if (!proc || (max_procs && (i >= max_procs)))
-            break;
-        struct passwd* user = getpwuid(proc->uid);
-        char user_buf[20];
-        char* user_str;
-        if (user && user->pw_name) {
-            user_str = user->pw_name;
-        } else {
-            snprintf(user_buf, 20, "%d", proc->uid);
-            user_str = user_buf;
-        }
-        if (!threads) {
-            printf("%5d %-8.8s %2s %3ld %3" PRIu64 "%% %c %5d %6" PRIu64 "K %6" PRIu64 "K %3s %s\n",
-                   proc->pid, user_str, proc->pr, proc->ni,
-                   proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads,
-                   proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy,
-                   proc->name[0] != 0 ? proc->name : proc->tname);
-        } else {
-            printf("%5d %5d %-8.8s %2s %3ld %3" PRIu64 "%% %c %6" PRIu64 "K %6" PRIu64 "K %3s %-15s %s\n",
-                   proc->pid, proc->tid, user_str, proc->pr, proc->ni,
-                   proc->delta_time * 100 / total_delta_time, proc->state,
-                   proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy,
-                   proc->tname, proc->name);
-        }
-    }
-}
-
-static struct proc_info *find_old_proc(pid_t pid, pid_t tid) {
-    int i;
-
-    for (i = 0; i < num_old_procs; i++)
-        if (old_procs[i] && (old_procs[i]->pid == pid) && (old_procs[i]->tid == tid))
-            return old_procs[i];
-
-    return NULL;
-}
-
-static void free_old_procs(void) {
-    int i;
-
-    for (i = 0; i < num_old_procs; i++)
-        if (old_procs[i])
-            free_proc(old_procs[i]);
-
-    free(old_procs);
-}
-
-static int proc_cpu_cmp(const void *a, const void *b) {
-    struct proc_info *pa, *pb;
-
-    pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
-
-    if (!pa && !pb) return 0;
-    if (!pa) return 1;
-    if (!pb) return -1;
-
-    return -numcmp(pa->delta_time, pb->delta_time);
-}
-
-static int proc_vss_cmp(const void *a, const void *b) {
-    struct proc_info *pa, *pb;
-
-    pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
-
-    if (!pa && !pb) return 0;
-    if (!pa) return 1;
-    if (!pb) return -1;
-
-    return -numcmp(pa->vss, pb->vss);
-}
-
-static int proc_rss_cmp(const void *a, const void *b) {
-    struct proc_info *pa, *pb;
-
-    pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
-
-    if (!pa && !pb) return 0;
-    if (!pa) return 1;
-    if (!pb) return -1;
-
-    return -numcmp(pa->rss, pb->rss);
-}
-
-static int proc_thr_cmp(const void *a, const void *b) {
-    struct proc_info *pa, *pb;
-
-    pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
-
-    if (!pa && !pb) return 0;
-    if (!pa) return 1;
-    if (!pb) return -1;
-
-    return -numcmp(pa->num_threads, pb->num_threads);
-}
-
-static int numcmp(long long a, long long b) {
-    if (a < b) return -1;
-    if (a > b) return 1;
-    return 0;
-}
-
-static void usage(char *cmd) {
-    fprintf(stderr, "Usage: %s [ -m max_procs ] [ -n iterations ] [ -d delay ] [ -s sort_column ] [ -t ] [ -h ]\n"
-                    "    -m num  Maximum number of processes to display.\n"
-                    "    -n num  Updates to show before exiting.\n"
-                    "    -d num  Seconds to wait between updates.\n"
-                    "    -s col  Column to sort by (cpu,vss,rss,thr).\n"
-                    "    -H      Show threads instead of processes.\n"
-                    "    -h      Display this help screen.\n",
-        cmd);
-}
diff --git a/toolbox/upstream-netbsd/include/util.h b/toolbox/upstream-netbsd/include/util.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/toolbox/upstream-netbsd/include/util.h
diff --git a/trusty/gatekeeper/Android.mk b/trusty/gatekeeper/Android.mk
index 13e9a09..3982c8f 100644
--- a/trusty/gatekeeper/Android.mk
+++ b/trusty/gatekeeper/Android.mk
@@ -43,8 +43,4 @@
 
 LOCAL_MODULE_TAGS := optional
 
-# Symlink gatekeeper.trusty.so -> gatekeeper.<device>.so so libhardware can find it.
-LOCAL_POST_INSTALL_CMD = \
-    $(hide) ln -sf $(notdir $(LOCAL_INSTALLED_MODULE)) $(dir $(LOCAL_INSTALLED_MODULE))gatekeeper.$(TARGET_DEVICE).so
-
 include $(BUILD_SHARED_LIBRARY)
diff --git a/trusty/gatekeeper/trusty_gatekeeper.cpp b/trusty/gatekeeper/trusty_gatekeeper.cpp
index d24f44f..7e55fb1 100644
--- a/trusty/gatekeeper/trusty_gatekeeper.cpp
+++ b/trusty/gatekeeper/trusty_gatekeeper.cpp
@@ -14,18 +14,19 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "TrustyGateKeeper"
+
+#include <assert.h>
 #include <errno.h>
 #include <stdio.h>
-#include <assert.h>
 #include <type_traits>
 
+#include <android/log.h>
+
 #include "trusty_gatekeeper.h"
 #include "trusty_gatekeeper_ipc.h"
 #include "gatekeeper_ipc.h"
 
-#define LOG_TAG "TrustyGateKeeper"
-#include <cutils/log.h>
-
 namespace gatekeeper {
 
 const uint32_t SEND_BUF_SIZE = 8192;
diff --git a/trusty/gatekeeper/trusty_gatekeeper.h b/trusty/gatekeeper/trusty_gatekeeper.h
index 82108dc..2becc49 100644
--- a/trusty/gatekeeper/trusty_gatekeeper.h
+++ b/trusty/gatekeeper/trusty_gatekeeper.h
@@ -27,7 +27,7 @@
 class TrustyGateKeeperDevice {
     public:
 
-    TrustyGateKeeperDevice(const hw_module_t* module);
+    explicit TrustyGateKeeperDevice(const hw_module_t* module);
     ~TrustyGateKeeperDevice();
 
     hw_device_t* hw_device();
diff --git a/trusty/gatekeeper/trusty_gatekeeper_ipc.c b/trusty/gatekeeper/trusty_gatekeeper_ipc.c
index a1c319e..45e65a7 100644
--- a/trusty/gatekeeper/trusty_gatekeeper_ipc.c
+++ b/trusty/gatekeeper/trusty_gatekeeper_ipc.c
@@ -14,12 +14,15 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "TrustyGateKeeper"
+
 #include <errno.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
-#define LOG_TAG "TrustyGateKeeper"
-#include <cutils/log.h>
+#include <android/log.h>
 #include <trusty/tipc.h>
 
 #include "trusty_gatekeeper_ipc.h"
diff --git a/trusty/keymaster/Android.mk b/trusty/keymaster/Android.mk
new file mode 100644
index 0000000..0ebf52d
--- /dev/null
+++ b/trusty/keymaster/Android.mk
@@ -0,0 +1,67 @@
+#
+# 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.
+#
+
+# WARNING: Everything listed here will be built on ALL platforms,
+# including x86, the emulator, and the SDK.  Modules must be uniquely
+# named (liblights.panda), and must build everywhere, or limit themselves
+# to only building on ARM if they include assembly. Individual makefiles
+# are responsible for having their own logic, for fine-grained control.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+###
+# trusty_keymaster is a binary used only for on-device testing.  It
+# runs Trusty Keymaster through a basic set of operations with RSA
+# and ECDSA keys.
+###
+LOCAL_MODULE := trusty_keymaster_tipc
+LOCAL_SRC_FILES := \
+	trusty_keymaster_device.cpp \
+	trusty_keymaster_ipc.c \
+	trusty_keymaster_main.cpp
+LOCAL_SHARED_LIBRARIES := \
+	libcrypto \
+	libcutils \
+	libkeymaster1 \
+	libtrusty \
+	libkeymaster_messages \
+	liblog
+
+include $(BUILD_EXECUTABLE)
+
+###
+# keystore.trusty is the HAL used by keystore on Trusty devices.
+##
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := keystore.trusty
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := module.cpp \
+	trusty_keymaster_ipc.c \
+	trusty_keymaster_device.cpp
+LOCAL_CLFAGS = -fvisibility=hidden -Wall -Werror
+LOCAL_SHARED_LIBRARIES := \
+	libcrypto \
+	libkeymaster_messages \
+	libtrusty \
+	liblog \
+	libcutils
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/trusty/keymaster/Makefile b/trusty/keymaster/Makefile
new file mode 100644
index 0000000..f575381
--- /dev/null
+++ b/trusty/keymaster/Makefile
@@ -0,0 +1,199 @@
+#####
+# Local unit test Makefile
+#
+# This makefile builds and runs the trusty_keymaster unit tests locally on the development
+# machine, not on an Android device.
+#
+# To build and run these tests, one pre-requisite must be manually installed: BoringSSL.
+# This Makefile expects to find BoringSSL in a directory adjacent to $ANDROID_BUILD_TOP.
+# To get and build it, first install the Ninja build tool (e.g. apt-get install
+# ninja-build), then do:
+#
+# cd $ANDROID_BUILD_TOP/..
+# git clone https://boringssl.googlesource.com/boringssl
+# cd boringssl
+# mdkir build
+# cd build
+# cmake -GNinja ..
+# ninja
+#
+# Then return to $ANDROID_BUILD_TOP/system/keymaster and run "make".
+#####
+
+BASE=../../../..
+SUBS=system/core \
+	system/keymaster \
+	hardware/libhardware \
+	external/gtest
+GTEST=$(BASE)/external/gtest
+KM=$(BASE)/system/keymaster
+
+INCLUDES=$(foreach dir,$(SUBS),-I $(BASE)/$(dir)/include) \
+	-I $(BASE)/libnativehelper/include/nativehelper \
+	-I ../tipc/include \
+	-I $(BASE)/system/keymaster \
+	-I $(GTEST) \
+	-I$(BASE)/../boringssl/include
+
+ifdef USE_CLANG
+CC=/usr/bin/clang
+CXX=/usr/bin/clang
+CLANG_TEST_DEFINE=-DKEYMASTER_CLANG_TEST_BUILD
+COMPILER_SPECIFIC_ARGS=-std=c++11 $(CLANG_TEST_DEFINE)
+else
+COMPILER_SPECIFIC_ARGS=-std=c++0x -fprofile-arcs
+endif
+
+CPPFLAGS=$(INCLUDES) -g -O0 -MD
+CXXFLAGS=-Wall -Werror -Wno-unused -Winit-self -Wpointer-arith	-Wunused-parameter \
+	-Wmissing-declarations -ftest-coverage \
+	-Wno-deprecated-declarations -fno-exceptions -DKEYMASTER_NAME_TAGS \
+	$(COMPILER_SPECIFIC_ARGS)
+LDLIBS=-L$(BASE)/../boringssl/build/crypto -lcrypto -lpthread -lstdc++
+
+CPPSRCS=\
+	$(KM)/aead_mode_operation.cpp \
+	$(KM)/aes_key.cpp \
+	$(KM)/aes_operation.cpp \
+	$(KM)/android_keymaster.cpp \
+	$(KM)/android_keymaster_messages.cpp \
+	$(KM)/android_keymaster_messages_test.cpp \
+	$(KM)/android_keymaster_test.cpp \
+	$(KM)/android_keymaster_test_utils.cpp \
+	$(KM)/android_keymaster_utils.cpp \
+	$(KM)/asymmetric_key.cpp \
+	$(KM)/auth_encrypted_key_blob.cpp \
+	$(KM)/auth_encrypted_key_blob.cpp \
+	$(KM)/authorization_set.cpp \
+	$(KM)/authorization_set_test.cpp \
+	$(KM)/ec_key.cpp \
+	$(KM)/ec_keymaster0_key.cpp \
+	$(KM)/ecdsa_operation.cpp \
+	$(KM)/hmac_key.cpp \
+	$(KM)/hmac_operation.cpp \
+	$(KM)/integrity_assured_key_blob.cpp \
+	$(KM)/key.cpp \
+	$(KM)/key_blob_test.cpp \
+	$(KM)/keymaster0_engine.cpp \
+	$(KM)/logger.cpp \
+	$(KM)/ocb_utils.cpp \
+	$(KM)/openssl_err.cpp \
+	$(KM)/openssl_utils.cpp \
+	$(KM)/operation.cpp \
+	$(KM)/operation_table.cpp \
+	$(KM)/rsa_key.cpp \
+	$(KM)/rsa_keymaster0_key.cpp \
+	$(KM)/rsa_operation.cpp \
+	$(KM)/serializable.cpp \
+	$(KM)/soft_keymaster_context.cpp \
+	$(KM)/symmetric_key.cpp \
+	$(KM)/unencrypted_key_blob.cpp \
+	trusty_keymaster_device.cpp \
+	trusty_keymaster_device_test.cpp
+CCSRCS=$(GTEST)/src/gtest-all.cc
+CSRCS=ocb.c
+
+OBJS=$(CPPSRCS:.cpp=.o) $(CCSRCS:.cc=.o) $(CSRCS:.c=.o)
+DEPS=$(CPPSRCS:.cpp=.d) $(CCSRCS:.cc=.d) $(CSRCS:.c=.d)
+GCDA=$(CPPSRCS:.cpp=.gcda) $(CCSRCS:.cc=.gcda) $(CSRCS:.c=.gcda)
+GCNO=$(CPPSRCS:.cpp=.gcno) $(CCSRCS:.cc=.gcno) $(CSRCS:.c=.gcno)
+
+LINK.o=$(LINK.cc)
+
+BINARIES=trusty_keymaster_device_test
+
+ifdef TRUSTY
+BINARIES += trusty_keymaster_device_test
+endif # TRUSTY
+
+.PHONY: coverage memcheck massif clean run
+
+%.run: %
+	./$<
+	touch $@
+
+run: $(BINARIES:=.run)
+
+coverage: coverage.info
+	genhtml coverage.info --output-directory coverage
+
+coverage.info: run
+	lcov --capture --directory=. --output-file coverage.info
+
+%.coverage : %
+	$(MAKE) clean && $(MAKE) $<
+	./$<
+	lcov --capture --directory=. --output-file coverage.info
+	genhtml coverage.info --output-directory coverage
+
+#UNINIT_OPTS=--track-origins=yes
+UNINIT_OPTS=--undef-value-errors=no
+
+MEMCHECK_OPTS=--leak-check=full \
+	--show-reachable=yes \
+	--vgdb=full \
+	$(UNINIT_OPTS) \
+	--error-exitcode=1
+
+MASSIF_OPTS=--tool=massif \
+	--stacks=yes
+
+%.memcheck : %
+	valgrind $(MEMCHECK_OPTS) ./$< && \
+	touch $@
+
+%.massif : %
+	valgrind $(MASSIF_OPTS) --massif-out-file=$@ ./$<
+
+memcheck: $(BINARIES:=.memcheck)
+
+massif: $(BINARIES:=.massif)
+
+trusty_keymaster_device_test: trusty_keymaster_device_test.o \
+	trusty_keymaster_device.o \
+	$(KM)/aead_mode_operation.o \
+	$(KM)/aes_key.o \
+	$(KM)/aes_operation.o \
+	$(KM)/android_keymaster.o \
+	$(KM)/android_keymaster_messages.o \
+	$(KM)/android_keymaster_test_utils.o \
+	$(KM)/android_keymaster_utils.o \
+	$(KM)/asymmetric_key.o \
+	$(KM)/auth_encrypted_key_blob.o \
+	$(KM)/auth_encrypted_key_blob.o \
+	$(KM)/authorization_set.o \
+	$(KM)/ec_key.o \
+	$(KM)/ec_keymaster0_key.cpp \
+	$(KM)/ecdsa_operation.o \
+	$(KM)/hmac_key.o \
+	$(KM)/hmac_operation.o \
+	$(KM)/integrity_assured_key_blob.o \
+	$(KM)/key.o \
+	$(KM)/keymaster0_engine.o \
+	$(KM)/logger.o \
+	$(KM)/ocb.o \
+	$(KM)/ocb_utils.o \
+	$(KM)/openssl_err.o \
+	$(KM)/openssl_utils.o \
+	$(KM)/operation.o \
+	$(KM)/operation_table.o \
+	$(KM)/rsa_key.o \
+	$(KM)/rsa_keymaster0_key.o \
+	$(KM)/rsa_operation.o \
+	$(KM)/serializable.o \
+	$(KM)/soft_keymaster_context.o \
+	$(KM)/symmetric_key.o \
+	$(GTEST)/src/gtest-all.o
+
+$(GTEST)/src/gtest-all.o: CXXFLAGS:=$(subst -Wmissing-declarations,,$(CXXFLAGS))
+ocb.o: CFLAGS=$(CLANG_TEST_DEFINE)
+
+clean:
+	rm -f $(OBJS) $(DEPS) $(GCDA) $(GCNO) $(BINARIES) \
+		$(BINARIES:=.run) $(BINARIES:=.memcheck) $(BINARIES:=.massif) \
+		coverage.info
+	rm -rf coverage
+
+-include $(CPPSRCS:.cpp=.d)
+-include $(CCSRCS:.cc=.d)
+
diff --git a/trusty/keymaster/keymaster_ipc.h b/trusty/keymaster/keymaster_ipc.h
new file mode 100644
index 0000000..48fa53d
--- /dev/null
+++ b/trusty/keymaster/keymaster_ipc.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#define KEYMASTER_PORT "com.android.trusty.keymaster"
+#define KEYMASTER_MAX_BUFFER_LENGTH 4096
+
+// Commands
+enum keymaster_command {
+	KEYMASTER_RESP_BIT              = 1,
+	KEYMASTER_REQ_SHIFT             = 1,
+
+    KM_GENERATE_KEY                 = (0 << KEYMASTER_REQ_SHIFT),
+    KM_BEGIN_OPERATION              = (1 << KEYMASTER_REQ_SHIFT),
+    KM_UPDATE_OPERATION             = (2 << KEYMASTER_REQ_SHIFT),
+    KM_FINISH_OPERATION             = (3 << KEYMASTER_REQ_SHIFT),
+    KM_ABORT_OPERATION              = (4 << KEYMASTER_REQ_SHIFT),
+    KM_IMPORT_KEY                   = (5 << KEYMASTER_REQ_SHIFT),
+    KM_EXPORT_KEY                   = (6 << KEYMASTER_REQ_SHIFT),
+    KM_GET_VERSION                  = (7 << KEYMASTER_REQ_SHIFT),
+    KM_ADD_RNG_ENTROPY              = (8 << KEYMASTER_REQ_SHIFT),
+    KM_GET_SUPPORTED_ALGORITHMS     = (9 << KEYMASTER_REQ_SHIFT),
+    KM_GET_SUPPORTED_BLOCK_MODES    = (10 << KEYMASTER_REQ_SHIFT),
+    KM_GET_SUPPORTED_PADDING_MODES  = (11 << KEYMASTER_REQ_SHIFT),
+    KM_GET_SUPPORTED_DIGESTS        = (12 << KEYMASTER_REQ_SHIFT),
+    KM_GET_SUPPORTED_IMPORT_FORMATS = (13 << KEYMASTER_REQ_SHIFT),
+    KM_GET_SUPPORTED_EXPORT_FORMATS = (14 << KEYMASTER_REQ_SHIFT),
+    KM_GET_KEY_CHARACTERISTICS      = (15 << KEYMASTER_REQ_SHIFT),
+};
+
+#ifdef __ANDROID__
+
+/**
+ * keymaster_message - Serial header for communicating with KM server
+ * @cmd: the command, one of keymaster_command.
+ * @payload: start of the serialized command specific payload
+ */
+struct keymaster_message {
+	uint32_t cmd;
+	uint8_t payload[0];
+};
+
+#endif
diff --git a/trusty/keymaster/module.cpp b/trusty/keymaster/module.cpp
new file mode 100644
index 0000000..81597d9
--- /dev/null
+++ b/trusty/keymaster/module.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 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 <errno.h>
+#include <string.h>
+
+#include <hardware/hardware.h>
+#include <hardware/keymaster0.h>
+
+#include "trusty_keymaster_device.h"
+
+using keymaster::TrustyKeymasterDevice;
+
+/*
+ * Generic device handling
+ */
+static int trusty_keymaster_open(const hw_module_t* module, const char* name,
+                                 hw_device_t** device) {
+    if (strcmp(name, KEYSTORE_KEYMASTER) != 0)
+        return -EINVAL;
+
+    TrustyKeymasterDevice* dev = new TrustyKeymasterDevice(module);
+    if (dev == NULL)
+        return -ENOMEM;
+    *device = dev->hw_device();
+    // Do not delete dev; it will get cleaned up when the caller calls device->close(), and must
+    // exist until then.
+    return 0;
+}
+
+static struct hw_module_methods_t keystore_module_methods = {
+    .open = trusty_keymaster_open,
+};
+
+struct keystore_module HAL_MODULE_INFO_SYM __attribute__((visibility("default"))) = {
+    .common =
+        {
+         .tag = HARDWARE_MODULE_TAG,
+         .module_api_version = KEYMASTER_MODULE_API_VERSION_0_3,
+         .hal_api_version = HARDWARE_HAL_API_VERSION,
+         .id = KEYSTORE_HARDWARE_MODULE_ID,
+         .name = "Trusty Keymaster HAL",
+         .author = "The Android Open Source Project",
+         .methods = &keystore_module_methods,
+         .dso = 0,
+         .reserved = {},
+        },
+};
diff --git a/trusty/keymaster/trusty_keymaster_device.cpp b/trusty/keymaster/trusty_keymaster_device.cpp
new file mode 100644
index 0000000..de5e463
--- /dev/null
+++ b/trusty/keymaster/trusty_keymaster_device.cpp
@@ -0,0 +1,534 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#define LOG_TAG "TrustyKeymaster"
+
+#include <assert.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <type_traits>
+
+#include <android/log.h>
+#include <hardware/keymaster0.h>
+#include <keymaster/authorization_set.h>
+
+#include "trusty_keymaster_device.h"
+#include "trusty_keymaster_ipc.h"
+#include "keymaster_ipc.h"
+
+const uint32_t SEND_BUF_SIZE = 8192;
+const uint32_t RECV_BUF_SIZE = 8192;
+
+namespace keymaster {
+
+static keymaster_error_t translate_error(int err) {
+    switch (err) {
+    case 0:
+        return KM_ERROR_OK;
+    case -EPERM:
+    case -EACCES:
+        return KM_ERROR_SECURE_HW_ACCESS_DENIED;
+
+    case -ECANCELED:
+        return KM_ERROR_OPERATION_CANCELLED;
+
+    case -ENODEV:
+        return KM_ERROR_UNIMPLEMENTED;
+
+    case -ENOMEM:
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    case -EBUSY:
+        return KM_ERROR_SECURE_HW_BUSY;
+
+    case -EIO:
+        return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
+
+    case -EOVERFLOW:
+        return KM_ERROR_INVALID_INPUT_LENGTH;
+
+    default:
+        return KM_ERROR_UNKNOWN_ERROR;
+    }
+}
+
+TrustyKeymasterDevice::TrustyKeymasterDevice(const hw_module_t* module) {
+    static_assert(std::is_standard_layout<TrustyKeymasterDevice>::value,
+                  "TrustyKeymasterDevice must be standard layout");
+    static_assert(offsetof(TrustyKeymasterDevice, device_) == 0,
+                  "device_ must be the first member of KeymasterOpenSsl");
+    static_assert(offsetof(TrustyKeymasterDevice, device_.common) == 0,
+                  "common must be the first member of keymaster_device");
+
+    ALOGI("Creating device");
+    ALOGD("Device address: %p", this);
+
+    memset(&device_, 0, sizeof(device_));
+
+    device_.common.tag = HARDWARE_DEVICE_TAG;
+    device_.common.version = 1;
+    device_.common.module = const_cast<hw_module_t*>(module);
+    device_.common.close = close_device;
+
+    device_.flags = KEYMASTER_BLOBS_ARE_STANDALONE | KEYMASTER_SUPPORTS_EC;
+
+    device_.generate_keypair = generate_keypair;
+    device_.import_keypair = import_keypair;
+    device_.get_keypair_public = get_keypair_public;
+    device_.delete_keypair = NULL;
+    device_.delete_all = NULL;
+    device_.sign_data = sign_data;
+    device_.verify_data = verify_data;
+
+    device_.context = NULL;
+
+    int rc = trusty_keymaster_connect();
+    error_ = translate_error(rc);
+    if (rc < 0) {
+        ALOGE("failed to connect to keymaster (%d)", rc);
+        return;
+    }
+
+    GetVersionRequest version_request;
+    GetVersionResponse version_response;
+    error_ = Send(version_request, &version_response);
+    if (error_ == KM_ERROR_INVALID_ARGUMENT || error_ == KM_ERROR_UNIMPLEMENTED) {
+        ALOGI("\"Bad parameters\" error on GetVersion call.  Assuming version 0.");
+        message_version_ = 0;
+        error_ = KM_ERROR_OK;
+    }
+    message_version_ = MessageVersion(version_response.major_ver, version_response.minor_ver,
+                                      version_response.subminor_ver);
+    if (message_version_ < 0) {
+        // Can't translate version?  Keymaster implementation must be newer.
+        ALOGE("Keymaster version %d.%d.%d not supported.", version_response.major_ver,
+              version_response.minor_ver, version_response.subminor_ver);
+        error_ = KM_ERROR_VERSION_MISMATCH;
+    }
+}
+
+TrustyKeymasterDevice::~TrustyKeymasterDevice() {
+    trusty_keymaster_disconnect();
+}
+
+const uint64_t HUNDRED_YEARS = 1000LL * 60 * 60 * 24 * 365 * 100;
+
+int TrustyKeymasterDevice::generate_keypair(const keymaster_keypair_t key_type,
+                                            const void* key_params, uint8_t** key_blob,
+                                            size_t* key_blob_length) {
+    ALOGD("Device received generate_keypair");
+
+    if (error_ != KM_ERROR_OK)
+        return error_;
+
+    GenerateKeyRequest req(message_version_);
+    StoreNewKeyParams(&req.key_description);
+
+    switch (key_type) {
+    case TYPE_RSA: {
+        req.key_description.push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
+        const keymaster_rsa_keygen_params_t* rsa_params =
+            static_cast<const keymaster_rsa_keygen_params_t*>(key_params);
+        ALOGD("Generating RSA pair, modulus size: %u, public exponent: %lu",
+              rsa_params->modulus_size, rsa_params->public_exponent);
+        req.key_description.push_back(TAG_KEY_SIZE, rsa_params->modulus_size);
+        req.key_description.push_back(TAG_RSA_PUBLIC_EXPONENT, rsa_params->public_exponent);
+        break;
+    }
+
+    case TYPE_EC: {
+        req.key_description.push_back(TAG_ALGORITHM, KM_ALGORITHM_EC);
+        const keymaster_ec_keygen_params_t* ec_params =
+            static_cast<const keymaster_ec_keygen_params_t*>(key_params);
+        ALOGD("Generating ECDSA pair, key size: %u", ec_params->field_size);
+        req.key_description.push_back(TAG_KEY_SIZE, ec_params->field_size);
+        break;
+    }
+    default:
+        ALOGD("Received request for unsuported key type %d", key_type);
+        return KM_ERROR_UNSUPPORTED_ALGORITHM;
+    }
+
+    GenerateKeyResponse rsp(message_version_);
+    ALOGD("Sending generate request");
+    keymaster_error_t err = Send(req, &rsp);
+    if (err != KM_ERROR_OK) {
+        ALOGE("Got error %d from send", err);
+        return err;
+    }
+
+    *key_blob_length = rsp.key_blob.key_material_size;
+    *key_blob = static_cast<uint8_t*>(malloc(*key_blob_length));
+    memcpy(*key_blob, rsp.key_blob.key_material, *key_blob_length);
+    ALOGD("Returning %d bytes in key blob\n", (int)*key_blob_length);
+
+    return KM_ERROR_OK;
+}
+
+struct EVP_PKEY_Delete {
+    void operator()(EVP_PKEY* p) const { EVP_PKEY_free(p); }
+};
+
+struct PKCS8_PRIV_KEY_INFO_Delete {
+    void operator()(PKCS8_PRIV_KEY_INFO* p) const { PKCS8_PRIV_KEY_INFO_free(p); }
+};
+
+int TrustyKeymasterDevice::import_keypair(const uint8_t* key, const size_t key_length,
+                                          uint8_t** key_blob, size_t* key_blob_length) {
+    ALOGD("Device received import_keypair");
+    if (error_ != KM_ERROR_OK)
+        return error_;
+
+    if (!key)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    if (!key_blob || !key_blob_length)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    ImportKeyRequest request(message_version_);
+    StoreNewKeyParams(&request.key_description);
+    keymaster_algorithm_t algorithm;
+    keymaster_error_t err = GetPkcs8KeyAlgorithm(key, key_length, &algorithm);
+    if (err != KM_ERROR_OK)
+        return err;
+    request.key_description.push_back(TAG_ALGORITHM, algorithm);
+
+    request.SetKeyMaterial(key, key_length);
+    request.key_format = KM_KEY_FORMAT_PKCS8;
+    ImportKeyResponse response(message_version_);
+    err = Send(request, &response);
+    if (err != KM_ERROR_OK)
+        return err;
+
+    *key_blob_length = response.key_blob.key_material_size;
+    *key_blob = static_cast<uint8_t*>(malloc(*key_blob_length));
+    memcpy(*key_blob, response.key_blob.key_material, *key_blob_length);
+    printf("Returning %d bytes in key blob\n", (int)*key_blob_length);
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t TrustyKeymasterDevice::GetPkcs8KeyAlgorithm(const uint8_t* key, size_t key_length,
+                                                              keymaster_algorithm_t* algorithm) {
+    if (key == NULL) {
+        ALOGE("No key specified for import");
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    }
+
+    UniquePtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> pkcs8(
+        d2i_PKCS8_PRIV_KEY_INFO(NULL, &key, key_length));
+    if (pkcs8.get() == NULL) {
+        ALOGE("Could not parse PKCS8 key blob");
+        return KM_ERROR_INVALID_KEY_BLOB;
+    }
+
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKCS82PKEY(pkcs8.get()));
+    if (pkey.get() == NULL) {
+        ALOGE("Could not extract key from PKCS8 key blob");
+        return KM_ERROR_INVALID_KEY_BLOB;
+    }
+
+    switch (EVP_PKEY_type(pkey->type)) {
+    case EVP_PKEY_RSA:
+        *algorithm = KM_ALGORITHM_RSA;
+        break;
+    case EVP_PKEY_EC:
+        *algorithm = KM_ALGORITHM_EC;
+        break;
+    default:
+        ALOGE("Unsupported algorithm %d", EVP_PKEY_type(pkey->type));
+        return KM_ERROR_UNSUPPORTED_ALGORITHM;
+    }
+
+    return KM_ERROR_OK;
+}
+
+int TrustyKeymasterDevice::get_keypair_public(const uint8_t* key_blob, const size_t key_blob_length,
+                                              uint8_t** x509_data, size_t* x509_data_length) {
+    ALOGD("Device received get_keypair_public");
+    if (error_ != KM_ERROR_OK)
+        return error_;
+
+    ExportKeyRequest request(message_version_);
+    request.SetKeyMaterial(key_blob, key_blob_length);
+    request.key_format = KM_KEY_FORMAT_X509;
+    ExportKeyResponse response(message_version_);
+    keymaster_error_t err = Send(request, &response);
+    if (err != KM_ERROR_OK)
+        return err;
+
+    *x509_data_length = response.key_data_length;
+    *x509_data = static_cast<uint8_t*>(malloc(*x509_data_length));
+    memcpy(*x509_data, response.key_data, *x509_data_length);
+    printf("Returning %d bytes in x509 key\n", (int)*x509_data_length);
+
+    return KM_ERROR_OK;
+}
+
+int TrustyKeymasterDevice::sign_data(const void* signing_params, const uint8_t* key_blob,
+                                     const size_t key_blob_length, const uint8_t* data,
+                                     const size_t data_length, uint8_t** signed_data,
+                                     size_t* signed_data_length) {
+    ALOGD("Device received sign_data, %d", error_);
+    if (error_ != KM_ERROR_OK)
+        return error_;
+
+    BeginOperationRequest begin_request(message_version_);
+    begin_request.purpose = KM_PURPOSE_SIGN;
+    begin_request.SetKeyMaterial(key_blob, key_blob_length);
+    keymaster_error_t err = StoreSigningParams(signing_params, key_blob, key_blob_length,
+                                               &begin_request.additional_params);
+    if (err != KM_ERROR_OK) {
+        ALOGE("Error extracting signing params: %d", err);
+        return err;
+    }
+
+    BeginOperationResponse begin_response(message_version_);
+    ALOGD("Sending signing request begin");
+    err = Send(begin_request, &begin_response);
+    if (err != KM_ERROR_OK) {
+        ALOGE("Error sending sign begin: %d", err);
+        return err;
+    }
+
+    UpdateOperationRequest update_request(message_version_);
+    update_request.op_handle = begin_response.op_handle;
+    update_request.input.Reinitialize(data, data_length);
+    UpdateOperationResponse update_response(message_version_);
+    ALOGD("Sending signing request update");
+    err = Send(update_request, &update_response);
+    if (err != KM_ERROR_OK) {
+        ALOGE("Error sending sign update: %d", err);
+        return err;
+    }
+
+    FinishOperationRequest finish_request(message_version_);
+    finish_request.op_handle = begin_response.op_handle;
+    FinishOperationResponse finish_response(message_version_);
+    ALOGD("Sending signing request finish");
+    err = Send(finish_request, &finish_response);
+    if (err != KM_ERROR_OK) {
+        ALOGE("Error sending sign finish: %d", err);
+        return err;
+    }
+
+    *signed_data_length = finish_response.output.available_read();
+    *signed_data = static_cast<uint8_t*>(malloc(*signed_data_length));
+    if (!finish_response.output.read(*signed_data, *signed_data_length)) {
+        ALOGE("Error reading response data: %d", err);
+        return KM_ERROR_UNKNOWN_ERROR;
+    }
+    return KM_ERROR_OK;
+}
+
+int TrustyKeymasterDevice::verify_data(const void* signing_params, const uint8_t* key_blob,
+                                       const size_t key_blob_length, const uint8_t* signed_data,
+                                       const size_t signed_data_length, const uint8_t* signature,
+                                       const size_t signature_length) {
+    ALOGD("Device received verify_data");
+    if (error_ != KM_ERROR_OK)
+        return error_;
+
+    BeginOperationRequest begin_request(message_version_);
+    begin_request.purpose = KM_PURPOSE_VERIFY;
+    begin_request.SetKeyMaterial(key_blob, key_blob_length);
+    keymaster_error_t err = StoreSigningParams(signing_params, key_blob, key_blob_length,
+                                               &begin_request.additional_params);
+    if (err != KM_ERROR_OK)
+        return err;
+
+    BeginOperationResponse begin_response(message_version_);
+    err = Send(begin_request, &begin_response);
+    if (err != KM_ERROR_OK)
+        return err;
+
+    UpdateOperationRequest update_request(message_version_);
+    update_request.op_handle = begin_response.op_handle;
+    update_request.input.Reinitialize(signed_data, signed_data_length);
+    UpdateOperationResponse update_response(message_version_);
+    err = Send(update_request, &update_response);
+    if (err != KM_ERROR_OK)
+        return err;
+
+    FinishOperationRequest finish_request(message_version_);
+    finish_request.op_handle = begin_response.op_handle;
+    finish_request.signature.Reinitialize(signature, signature_length);
+    FinishOperationResponse finish_response(message_version_);
+    err = Send(finish_request, &finish_response);
+    if (err != KM_ERROR_OK)
+        return err;
+    return KM_ERROR_OK;
+}
+
+hw_device_t* TrustyKeymasterDevice::hw_device() {
+    return &device_.common;
+}
+
+static inline TrustyKeymasterDevice* convert_device(const keymaster0_device_t* dev) {
+    return reinterpret_cast<TrustyKeymasterDevice*>(const_cast<keymaster0_device_t*>(dev));
+}
+
+/* static */
+int TrustyKeymasterDevice::close_device(hw_device_t* dev) {
+    delete reinterpret_cast<TrustyKeymasterDevice*>(dev);
+    return 0;
+}
+
+/* static */
+int TrustyKeymasterDevice::generate_keypair(const keymaster0_device_t* dev,
+                                            const keymaster_keypair_t key_type,
+                                            const void* key_params, uint8_t** keyBlob,
+                                            size_t* keyBlobLength) {
+    ALOGD("Generate keypair, sending to device: %p", convert_device(dev));
+    return convert_device(dev)->generate_keypair(key_type, key_params, keyBlob, keyBlobLength);
+}
+
+/* static */
+int TrustyKeymasterDevice::import_keypair(const keymaster0_device_t* dev, const uint8_t* key,
+                                          const size_t key_length, uint8_t** key_blob,
+                                          size_t* key_blob_length) {
+    return convert_device(dev)->import_keypair(key, key_length, key_blob, key_blob_length);
+}
+
+/* static */
+int TrustyKeymasterDevice::get_keypair_public(const keymaster0_device_t* dev,
+                                              const uint8_t* key_blob, const size_t key_blob_length,
+                                              uint8_t** x509_data, size_t* x509_data_length) {
+    return convert_device(dev)
+        ->get_keypair_public(key_blob, key_blob_length, x509_data, x509_data_length);
+}
+
+/* static */
+int TrustyKeymasterDevice::sign_data(const keymaster0_device_t* dev, const void* params,
+                                     const uint8_t* keyBlob, const size_t keyBlobLength,
+                                     const uint8_t* data, const size_t dataLength,
+                                     uint8_t** signedData, size_t* signedDataLength) {
+    return convert_device(dev)
+        ->sign_data(params, keyBlob, keyBlobLength, data, dataLength, signedData, signedDataLength);
+}
+
+/* static */
+int TrustyKeymasterDevice::verify_data(const keymaster0_device_t* dev, const void* params,
+                                       const uint8_t* keyBlob, const size_t keyBlobLength,
+                                       const uint8_t* signedData, const size_t signedDataLength,
+                                       const uint8_t* signature, const size_t signatureLength) {
+    return convert_device(dev)->verify_data(params, keyBlob, keyBlobLength, signedData,
+                                            signedDataLength, signature, signatureLength);
+}
+
+keymaster_error_t TrustyKeymasterDevice::Send(uint32_t command, const Serializable& req,
+                                              KeymasterResponse* rsp) {
+    uint32_t req_size = req.SerializedSize();
+    if (req_size > SEND_BUF_SIZE)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    uint8_t send_buf[SEND_BUF_SIZE];
+    Eraser send_buf_eraser(send_buf, SEND_BUF_SIZE);
+    req.Serialize(send_buf, send_buf + req_size);
+
+    // Send it
+    uint8_t recv_buf[RECV_BUF_SIZE];
+    Eraser recv_buf_eraser(recv_buf, RECV_BUF_SIZE);
+    uint32_t rsp_size = RECV_BUF_SIZE;
+    printf("Sending %d byte request\n", (int)req.SerializedSize());
+    int rc = trusty_keymaster_call(command, send_buf, req_size, recv_buf, &rsp_size);
+    if (rc < 0) {
+        ALOGE("tipc error: %d\n", rc);
+        // TODO(swillden): Distinguish permanent from transient errors and set error_ appropriately.
+        return translate_error(rc);
+    } else {
+        ALOGV("Received %d byte response\n", rsp_size);
+    }
+
+    const keymaster_message* msg = (keymaster_message *) recv_buf;
+    const uint8_t *p = msg->payload;
+    if (!rsp->Deserialize(&p, p + rsp_size)) {
+        ALOGE("Error deserializing response of size %d\n", (int)rsp_size);
+        return KM_ERROR_UNKNOWN_ERROR;
+    } else if (rsp->error != KM_ERROR_OK) {
+        ALOGE("Response of size %d contained error code %d\n", (int)rsp_size, (int)rsp->error);
+        return rsp->error;
+    }
+    return rsp->error;
+}
+
+keymaster_error_t TrustyKeymasterDevice::StoreSigningParams(const void* signing_params,
+                                                            const uint8_t* key_blob,
+                                                            size_t key_blob_length,
+                                                            AuthorizationSet* auth_set) {
+    uint8_t* pub_key_data;
+    size_t pub_key_data_length;
+    int err = get_keypair_public(&device_, key_blob, key_blob_length, &pub_key_data,
+                                 &pub_key_data_length);
+    if (err < 0) {
+        ALOGE("Error %d extracting public key to determine algorithm", err);
+        return KM_ERROR_INVALID_KEY_BLOB;
+    }
+    UniquePtr<uint8_t, Malloc_Delete> pub_key(pub_key_data);
+
+    const uint8_t* p = pub_key_data;
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(
+        d2i_PUBKEY(nullptr /* allocate new struct */, &p, pub_key_data_length));
+
+    switch (EVP_PKEY_type(pkey->type)) {
+    case EVP_PKEY_RSA: {
+        const keymaster_rsa_sign_params_t* rsa_params =
+            reinterpret_cast<const keymaster_rsa_sign_params_t*>(signing_params);
+        if (rsa_params->digest_type != DIGEST_NONE)
+            return KM_ERROR_UNSUPPORTED_DIGEST;
+        if (rsa_params->padding_type != PADDING_NONE)
+            return KM_ERROR_UNSUPPORTED_PADDING_MODE;
+        if (!auth_set->push_back(TAG_DIGEST, KM_DIGEST_NONE) ||
+            !auth_set->push_back(TAG_PADDING, KM_PAD_NONE))
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    } break;
+    case EVP_PKEY_EC: {
+        const keymaster_ec_sign_params_t* ecdsa_params =
+            reinterpret_cast<const keymaster_ec_sign_params_t*>(signing_params);
+        if (ecdsa_params->digest_type != DIGEST_NONE)
+            return KM_ERROR_UNSUPPORTED_DIGEST;
+        if (!auth_set->push_back(TAG_DIGEST, KM_DIGEST_NONE))
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    } break;
+    default:
+        return KM_ERROR_UNSUPPORTED_ALGORITHM;
+    }
+    return KM_ERROR_OK;
+}
+
+void TrustyKeymasterDevice::StoreNewKeyParams(AuthorizationSet* auth_set) {
+    auth_set->push_back(TAG_PURPOSE, KM_PURPOSE_SIGN);
+    auth_set->push_back(TAG_PURPOSE, KM_PURPOSE_VERIFY);
+    auth_set->push_back(TAG_ALL_USERS);
+    auth_set->push_back(TAG_NO_AUTH_REQUIRED);
+    uint64_t now = java_time(time(NULL));
+    auth_set->push_back(TAG_CREATION_DATETIME, now);
+    auth_set->push_back(TAG_ORIGINATION_EXPIRE_DATETIME, now + HUNDRED_YEARS);
+    if (message_version_ == 0) {
+        auth_set->push_back(TAG_DIGEST_OLD, KM_DIGEST_NONE);
+        auth_set->push_back(TAG_PADDING_OLD, KM_PAD_NONE);
+    } else {
+        auth_set->push_back(TAG_DIGEST, KM_DIGEST_NONE);
+        auth_set->push_back(TAG_PADDING, KM_PAD_NONE);
+    }
+}
+
+}  // namespace keymaster
diff --git a/trusty/keymaster/trusty_keymaster_device.h b/trusty/keymaster/trusty_keymaster_device.h
new file mode 100644
index 0000000..68cf40c
--- /dev/null
+++ b/trusty/keymaster/trusty_keymaster_device.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef EXTERNAL_KEYMASTER_TRUSTY_KEYMASTER_DEVICE_H_
+#define EXTERNAL_KEYMASTER_TRUSTY_KEYMASTER_DEVICE_H_
+
+#include <hardware/keymaster0.h>
+
+#include <keymaster/android_keymaster_messages.h>
+
+#include "keymaster_ipc.h"
+
+namespace keymaster {
+
+/**
+ * Software OpenSSL-based Keymaster device.
+ *
+ * IMPORTANT MAINTAINER NOTE: Pointers to instances of this class must be castable to hw_device_t
+ * and keymaster_device. This means it must remain a standard layout class (no virtual functions and
+ * no data members which aren't standard layout), and device_ must be the first data member.
+ * Assertions in the constructor validate compliance with those constraints.
+ */
+class TrustyKeymasterDevice {
+  public:
+    /*
+     * These are the only symbols that will be exported by libtrustykeymaster.  All functionality
+     * can be reached via the function pointers in device_.
+     */
+    __attribute__((visibility("default"))) explicit TrustyKeymasterDevice(const hw_module_t* module);
+    __attribute__((visibility("default"))) hw_device_t* hw_device();
+
+    ~TrustyKeymasterDevice();
+
+    keymaster_error_t session_error() { return error_; }
+
+    int generate_keypair(const keymaster_keypair_t key_type, const void* key_params,
+                         uint8_t** key_blob, size_t* key_blob_length);
+    int import_keypair(const uint8_t* key, const size_t key_length, uint8_t** key_blob,
+                       size_t* key_blob_length);
+    int get_keypair_public(const uint8_t* key_blob, const size_t key_blob_length,
+                           uint8_t** x509_data, size_t* x509_data_length);
+    int sign_data(const void* signing_params, const uint8_t* key_blob, const size_t key_blob_length,
+                  const uint8_t* data, const size_t data_length, uint8_t** signed_data,
+                  size_t* signed_data_length);
+    int verify_data(const void* signing_params, const uint8_t* key_blob,
+                    const size_t key_blob_length, const uint8_t* signed_data,
+                    const size_t signed_data_length, const uint8_t* signature,
+                    const size_t signature_length);
+
+  private:
+    keymaster_error_t Send(uint32_t command, const Serializable& request,
+                           KeymasterResponse* response);
+    keymaster_error_t Send(const GenerateKeyRequest& request, GenerateKeyResponse* response) {
+        return Send(KM_GENERATE_KEY, request, response);
+    }
+    keymaster_error_t Send(const BeginOperationRequest& request, BeginOperationResponse* response) {
+        return Send(KM_BEGIN_OPERATION, request, response);
+    }
+    keymaster_error_t Send(const UpdateOperationRequest& request,
+                           UpdateOperationResponse* response) {
+        return Send(KM_UPDATE_OPERATION, request, response);
+    }
+    keymaster_error_t Send(const FinishOperationRequest& request,
+                           FinishOperationResponse* response) {
+        return Send(KM_FINISH_OPERATION, request, response);
+    }
+    keymaster_error_t Send(const ImportKeyRequest& request, ImportKeyResponse* response) {
+        return Send(KM_IMPORT_KEY, request, response);
+    }
+    keymaster_error_t Send(const ExportKeyRequest& request, ExportKeyResponse* response) {
+        return Send(KM_EXPORT_KEY, request, response);
+    }
+    keymaster_error_t Send(const GetVersionRequest& request, GetVersionResponse* response) {
+        return Send(KM_GET_VERSION, request, response);
+    }
+
+    keymaster_error_t StoreSigningParams(const void* signing_params, const uint8_t* key_blob,
+                                         size_t key_blob_length, AuthorizationSet* auth_set);
+    void StoreNewKeyParams(AuthorizationSet* auth_set);
+    keymaster_error_t GetPkcs8KeyAlgorithm(const uint8_t* key, size_t key_length,
+                                           keymaster_algorithm_t* algorithm);
+
+    /*
+     * These static methods are the functions referenced through the function pointers in
+     * keymaster_device.  They're all trivial wrappers.
+     */
+    static int close_device(hw_device_t* dev);
+    static int generate_keypair(const keymaster0_device_t* dev, const keymaster_keypair_t key_type,
+                                const void* key_params, uint8_t** keyBlob, size_t* keyBlobLength);
+    static int import_keypair(const keymaster0_device_t* dev, const uint8_t* key,
+                              const size_t key_length, uint8_t** key_blob, size_t* key_blob_length);
+    static int get_keypair_public(const keymaster0_device_t* dev, const uint8_t* key_blob,
+                                  const size_t key_blob_length, uint8_t** x509_data,
+                                  size_t* x509_data_length);
+    static int sign_data(const keymaster0_device_t* dev, const void* signing_params,
+                         const uint8_t* key_blob, const size_t key_blob_length, const uint8_t* data,
+                         const size_t data_length, uint8_t** signed_data,
+                         size_t* signed_data_length);
+    static int verify_data(const keymaster0_device_t* dev, const void* signing_params,
+                           const uint8_t* key_blob, const size_t key_blob_length,
+                           const uint8_t* signed_data, const size_t signed_data_length,
+                           const uint8_t* signature, const size_t signature_length);
+
+    keymaster0_device_t device_;
+    keymaster_error_t error_;
+    int32_t message_version_;
+};
+
+}  // namespace keymaster
+
+#endif  // EXTERNAL_KEYMASTER_TRUSTY_KEYMASTER_DEVICE_H_
diff --git a/trusty/keymaster/trusty_keymaster_device_test.cpp b/trusty/keymaster/trusty_keymaster_device_test.cpp
new file mode 100644
index 0000000..3bb5430
--- /dev/null
+++ b/trusty/keymaster/trusty_keymaster_device_test.cpp
@@ -0,0 +1,562 @@
+/*
+ * Copyright (C) 2014 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 <algorithm>
+#include <fstream>
+
+#include <UniquePtr.h>
+#include <gtest/gtest.h>
+#include <openssl/engine.h>
+
+#include <hardware/keymaster0.h>
+
+#include <keymaster/android_keymaster.h>
+#include <keymaster/android_keymaster_messages.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/keymaster_tags.h>
+#include <keymaster/soft_keymaster_context.h>
+
+#include "android_keymaster_test_utils.h"
+#include "trusty_keymaster_device.h"
+#include "openssl_utils.h"
+
+using std::string;
+using std::ifstream;
+using std::istreambuf_iterator;
+
+static keymaster::AndroidKeymaster *impl_ =  nullptr;
+
+extern "C" {
+int __android_log_print();
+}
+
+int __android_log_print() {
+    return 0;
+}
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    int result = RUN_ALL_TESTS();
+    // Clean up stuff OpenSSL leaves around, so Valgrind doesn't complain.
+    CRYPTO_cleanup_all_ex_data();
+    ERR_free_strings();
+    return result;
+}
+
+int trusty_keymaster_connect() {
+    impl_ = new keymaster::AndroidKeymaster(new keymaster::SoftKeymasterContext(nullptr), 16);
+}
+
+void trusty_keymaster_disconnect() {
+    delete static_cast<keymaster::AndroidKeymaster*>(priv_);
+}
+
+template <typename Req, typename Rsp>
+static int fake_call(keymaster::AndroidKeymaster* device,
+                       void (keymaster::AndroidKeymaster::*method)(const Req&, Rsp*), void* in_buf,
+                       uint32_t in_size, void* out_buf, uint32_t* out_size) {
+    Req req;
+    const uint8_t* in = static_cast<uint8_t*>(in_buf);
+    req.Deserialize(&in, in + in_size);
+    Rsp rsp;
+    (device->*method)(req, &rsp);
+
+    *out_size = rsp.SerializedSize();
+    uint8_t* out = static_cast<uint8_t*>(out_buf);
+    rsp.Serialize(out, out + *out_size);
+    return 0;
+}
+
+int trusty_keymaster_call(uint32_t cmd, void* in_buf, uint32_t in_size, void* out_buf,
+                       uint32_t* out_size) {
+    switch (cmd) {
+    case KM_GENERATE_KEY:
+        return fake_call(impl_, &keymaster::AndroidKeymaster::GenerateKey, in_buf, in_size,
+                           out_buf, out_size);
+    case KM_BEGIN_OPERATION:
+        return fake_call(impl_, &keymaster::AndroidKeymaster::BeginOperation, in_buf, in_size,
+                           out_buf, out_size);
+    case KM_UPDATE_OPERATION:
+        return fake_call(impl_, &keymaster::AndroidKeymaster::UpdateOperation, in_buf, in_size,
+                           out_buf, out_size);
+    case KM_FINISH_OPERATION:
+        return fake_call(impl_, &keymaster::AndroidKeymaster::FinishOperation, in_buf, in_size,
+                           out_buf, out_size);
+    case KM_IMPORT_KEY:
+        return fake_call(impl_, &keymaster::AndroidKeymaster::ImportKey, in_buf, in_size, out_buf,
+                           out_size);
+    case KM_EXPORT_KEY:
+        return fake_call(impl_, &keymaster::AndroidKeymaster::ExportKey, in_buf, in_size, out_buf,
+                           out_size);
+    }
+    return -EINVAL;
+
+}
+
+namespace keymaster {
+namespace test {
+
+class TrustyKeymasterTest : public testing::Test {
+  protected:
+    TrustyKeymasterTest() : device(NULL) {}
+
+    keymaster_rsa_keygen_params_t build_rsa_params() {
+        keymaster_rsa_keygen_params_t rsa_params;
+        rsa_params.public_exponent = 65537;
+        rsa_params.modulus_size = 2048;
+        return rsa_params;
+    }
+
+    uint8_t* build_message(size_t length) {
+        uint8_t* msg = new uint8_t[length];
+        memset(msg, 'a', length);
+        return msg;
+    }
+
+    size_t dsa_message_len(const keymaster_dsa_keygen_params_t& params) {
+        switch (params.key_size) {
+        case 256:
+        case 1024:
+            return 48;
+        case 2048:
+        case 4096:
+            return 72;
+        default:
+            // Oops.
+            return 0;
+        }
+    }
+
+    TrustyKeymasterDevice device;
+};
+
+class Malloc_Delete {
+  public:
+    Malloc_Delete(void* p) : p_(p) {}
+    ~Malloc_Delete() { free(p_); }
+
+  private:
+    void* p_;
+};
+
+typedef TrustyKeymasterTest KeyGenTest;
+TEST_F(KeyGenTest, RsaSuccess) {
+    keymaster_rsa_keygen_params_t params = build_rsa_params();
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+}
+
+TEST_F(KeyGenTest, EcdsaSuccess) {
+    keymaster_ec_keygen_params_t ec_params = {256};
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_EC, &ec_params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+}
+
+typedef TrustyKeymasterTest SigningTest;
+TEST_F(SigningTest, RsaSuccess) {
+    keymaster_rsa_keygen_params_t params = build_rsa_params();
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_len = params.modulus_size / 8;
+    UniquePtr<uint8_t[]> message(build_message(message_len));
+    uint8_t* signature;
+    size_t siglen;
+    EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+                                            &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_EQ(message_len, siglen);
+}
+
+TEST_F(SigningTest, RsaShortMessage) {
+    keymaster_rsa_keygen_params_t params = build_rsa_params();
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_len = params.modulus_size / 8 - 1;
+    UniquePtr<uint8_t[]> message(build_message(message_len));
+    uint8_t* signature;
+    size_t siglen;
+    EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, device.sign_data(&sig_params, ptr, size, message.get(),
+                                                       message_len, &signature, &siglen));
+}
+
+TEST_F(SigningTest, RsaLongMessage) {
+    keymaster_rsa_keygen_params_t params = build_rsa_params();
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_len = params.modulus_size / 8 + 1;
+    UniquePtr<uint8_t[]> message(build_message(message_len));
+    uint8_t* signature;
+    size_t siglen;
+    EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, device.sign_data(&sig_params, ptr, size, message.get(),
+                                                       message_len, &signature, &siglen));
+}
+
+TEST_F(SigningTest, EcdsaSuccess) {
+    keymaster_ec_keygen_params_t params = {256};
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_EC, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
+    uint8_t message[] = "12345678901234567890123456789012";
+    uint8_t* signature;
+    size_t siglen;
+    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message,
+                                            array_size(message) - 1, &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_GT(siglen, 69U);
+    EXPECT_LT(siglen, 73U);
+}
+
+TEST_F(SigningTest, EcdsaEmptyMessageSuccess) {
+    keymaster_ec_keygen_params_t params = {256};
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_EC, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
+    uint8_t message[] = "";
+    uint8_t* signature;
+    size_t siglen;
+    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message,
+                                            array_size(message) - 1, &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_GT(siglen, 69U);
+    EXPECT_LT(siglen, 73U);
+}
+
+TEST_F(SigningTest, EcdsaLargeMessageSuccess) {
+    keymaster_ec_keygen_params_t params = {256};
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_EC, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
+    size_t message_len = 1024 * 7;
+    UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+    // contents of message don't matter.
+    uint8_t* signature;
+    size_t siglen;
+    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+                                            &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_GT(siglen, 69U);
+    EXPECT_LT(siglen, 73U);
+}
+
+typedef TrustyKeymasterTest VerificationTest;
+TEST_F(VerificationTest, RsaSuccess) {
+    keymaster_rsa_keygen_params_t params = build_rsa_params();
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_len = params.modulus_size / 8;
+    UniquePtr<uint8_t[]> message(build_message(message_len));
+    uint8_t* signature;
+    size_t siglen;
+    EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+                                            &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+
+    EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, ptr, size, message.get(), message_len,
+                                              signature, siglen));
+}
+
+TEST_F(VerificationTest, RsaBadSignature) {
+    keymaster_rsa_keygen_params_t params = build_rsa_params();
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_len = params.modulus_size / 8;
+    UniquePtr<uint8_t[]> message(build_message(message_len));
+    uint8_t* signature;
+    size_t siglen;
+    EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+                                            &signature, &siglen));
+
+    Malloc_Delete sig_deleter(signature);
+    signature[siglen / 2]++;
+    EXPECT_EQ(
+        KM_ERROR_VERIFICATION_FAILED,
+        device.verify_data(&sig_params, ptr, size, message.get(), message_len, signature, siglen));
+}
+
+TEST_F(VerificationTest, RsaBadMessage) {
+    keymaster_rsa_keygen_params_t params = build_rsa_params();
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_len = params.modulus_size / 8;
+    UniquePtr<uint8_t[]> message(build_message(message_len));
+    uint8_t* signature;
+    size_t siglen;
+    EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+                                            &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    message[0]++;
+    EXPECT_EQ(
+        KM_ERROR_VERIFICATION_FAILED,
+        device.verify_data(&sig_params, ptr, size, message.get(), message_len, signature, siglen));
+}
+
+TEST_F(VerificationTest, RsaShortMessage) {
+    keymaster_rsa_keygen_params_t params = build_rsa_params();
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_len = params.modulus_size / 8;
+    UniquePtr<uint8_t[]> message(build_message(message_len));
+    uint8_t* signature;
+    size_t siglen;
+    EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+                                            &signature, &siglen));
+
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH,
+              device.verify_data(&sig_params, ptr, size, message.get(), message_len - 1, signature,
+                                 siglen));
+}
+
+TEST_F(VerificationTest, RsaLongMessage) {
+    keymaster_rsa_keygen_params_t params = build_rsa_params();
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_len = params.modulus_size / 8;
+    UniquePtr<uint8_t[]> message(build_message(message_len + 1));
+    uint8_t* signature;
+    size_t siglen;
+    EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+                                            &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH,
+              device.verify_data(&sig_params, ptr, size, message.get(), message_len + 1, signature,
+                                 siglen));
+}
+
+TEST_F(VerificationTest, EcdsaSuccess) {
+    keymaster_ec_keygen_params_t params = {256};
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_EC, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
+    uint8_t message[] = "12345678901234567890123456789012";
+    uint8_t* signature;
+    size_t siglen;
+    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message,
+                                            array_size(message) - 1, &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, ptr, size, message,
+                                              array_size(message) - 1, signature, siglen));
+}
+
+TEST_F(VerificationTest, EcdsaLargeMessageSuccess) {
+    keymaster_ec_keygen_params_t params = {256};
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_EC, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
+    size_t message_len = 1024 * 7;
+    UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+    // contents of message don't matter.
+    uint8_t* signature;
+    size_t siglen;
+    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+                                            &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, ptr, size, message.get(), message_len,
+                                              signature, siglen));
+}
+
+static string read_file(const string& file_name) {
+    ifstream file_stream(file_name, std::ios::binary);
+    istreambuf_iterator<char> file_begin(file_stream);
+    istreambuf_iterator<char> file_end;
+    return string(file_begin, file_end);
+}
+
+typedef TrustyKeymasterTest ImportKeyTest;
+TEST_F(ImportKeyTest, RsaSuccess) {
+    string pk8_key = read_file("../../../../system/keymaster/rsa_privkey_pk8.der");
+    ASSERT_EQ(633U, pk8_key.size());
+
+    uint8_t* key = NULL;
+    size_t size;
+    ASSERT_EQ(KM_ERROR_OK, device.import_keypair(reinterpret_cast<const uint8_t*>(pk8_key.data()),
+                                                 pk8_key.size(), &key, &size));
+    Malloc_Delete key_deleter(key);
+
+    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_size = 1024 /* key size */ / 8;
+    UniquePtr<uint8_t[]> message(new uint8_t[message_size]);
+    memset(message.get(), 'a', message_size);
+    uint8_t* signature;
+    size_t siglen;
+    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, key, size, message.get(), message_size,
+                                            &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, key, size, message.get(), message_size,
+                                              signature, siglen));
+}
+
+TEST_F(ImportKeyTest, EcdsaSuccess) {
+    string pk8_key = read_file("../../../../system/keymaster/ec_privkey_pk8.der");
+    ASSERT_EQ(138U, pk8_key.size());
+
+    uint8_t* key = NULL;
+    size_t size;
+    ASSERT_EQ(KM_ERROR_OK, device.import_keypair(reinterpret_cast<const uint8_t*>(pk8_key.data()),
+                                                 pk8_key.size(), &key, &size));
+    Malloc_Delete key_deleter(key);
+
+    keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
+    uint8_t message[] = "12345678901234567890123456789012";
+    uint8_t* signature;
+    size_t siglen;
+    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, key, size, message,
+                                            array_size(message) - 1, &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, key, size, message,
+                                              array_size(message) - 1, signature, siglen));
+}
+
+struct EVP_PKEY_CTX_Delete {
+    void operator()(EVP_PKEY_CTX* p) { EVP_PKEY_CTX_free(p); }
+};
+
+static void VerifySignature(const uint8_t* key, size_t key_len, const uint8_t* signature,
+                            size_t signature_len, const uint8_t* message, size_t message_len) {
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(d2i_PUBKEY(NULL, &key, key_len));
+    ASSERT_TRUE(pkey.get() != NULL);
+    UniquePtr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
+    ASSERT_TRUE(ctx.get() != NULL);
+    ASSERT_EQ(1, EVP_PKEY_verify_init(ctx.get()));
+    if (EVP_PKEY_type(pkey->type) == EVP_PKEY_RSA)
+        ASSERT_EQ(1, EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_NO_PADDING));
+    EXPECT_EQ(1, EVP_PKEY_verify(ctx.get(), signature, signature_len, message, message_len));
+}
+
+typedef TrustyKeymasterTest ExportKeyTest;
+TEST_F(ExportKeyTest, RsaSuccess) {
+    keymaster_rsa_keygen_params_t params = build_rsa_params();
+    uint8_t* ptr = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(ptr);
+
+    uint8_t* exported;
+    size_t exported_size;
+    EXPECT_EQ(KM_ERROR_OK, device.get_keypair_public(ptr, size, &exported, &exported_size));
+    Malloc_Delete exported_deleter(exported);
+
+    // Sign a message so we can verify it with the exported pubkey.
+    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_len = params.modulus_size / 8;
+    UniquePtr<uint8_t[]> message(build_message(message_len));
+    uint8_t* signature;
+    size_t siglen;
+    EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+                                            &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_EQ(message_len, siglen);
+    const uint8_t* tmp = exported;
+
+    VerifySignature(exported, exported_size, signature, siglen, message.get(), message_len);
+}
+
+typedef TrustyKeymasterTest ExportKeyTest;
+TEST_F(ExportKeyTest, EcdsaSuccess) {
+    keymaster_ec_keygen_params_t params = {256};
+    uint8_t* key = NULL;
+    size_t size;
+    ASSERT_EQ(0, device.generate_keypair(TYPE_EC, &params, &key, &size));
+    EXPECT_GT(size, 0U);
+    Malloc_Delete key_deleter(key);
+
+    uint8_t* exported;
+    size_t exported_size;
+    EXPECT_EQ(KM_ERROR_OK, device.get_keypair_public(key, size, &exported, &exported_size));
+    Malloc_Delete exported_deleter(exported);
+
+    // Sign a message so we can verify it with the exported pubkey.
+    keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
+    uint8_t message[] = "12345678901234567890123456789012";
+    uint8_t* signature;
+    size_t siglen;
+    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, key, size, message,
+                                            array_size(message) - 1, &signature, &siglen));
+    Malloc_Delete sig_deleter(signature);
+    EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, key, size, message,
+                                              array_size(message) - 1, signature, siglen));
+
+    VerifySignature(exported, exported_size, signature, siglen, message, array_size(message) - 1);
+}
+
+}  // namespace test
+}  // namespace keymaster
diff --git a/trusty/keymaster/trusty_keymaster_ipc.c b/trusty/keymaster/trusty_keymaster_ipc.c
new file mode 100644
index 0000000..8755093
--- /dev/null
+++ b/trusty/keymaster/trusty_keymaster_ipc.c
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "TrustyKeymaster"
+
+// TODO: make this generic in libtrusty
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <android/log.h>
+#include <trusty/tipc.h>
+
+#include "trusty_keymaster_ipc.h"
+#include "keymaster_ipc.h"
+
+#define TRUSTY_DEVICE_NAME "/dev/trusty-ipc-dev0"
+
+static int handle_ = 0;
+
+int trusty_keymaster_connect() {
+    int rc = tipc_connect(TRUSTY_DEVICE_NAME, KEYMASTER_PORT);
+    if (rc < 0) {
+        return rc;
+    }
+
+    handle_ = rc;
+    return 0;
+}
+
+int trusty_keymaster_call(uint32_t cmd, void *in, uint32_t in_size, uint8_t *out,
+                          uint32_t *out_size)  {
+    if (handle_ == 0) {
+        ALOGE("not connected\n");
+        return -EINVAL;
+    }
+
+    size_t msg_size = in_size + sizeof(struct keymaster_message);
+    struct keymaster_message *msg = malloc(msg_size);
+    msg->cmd = cmd;
+    memcpy(msg->payload, in, in_size);
+
+    ssize_t rc = write(handle_, msg, msg_size);
+    free(msg);
+
+    if (rc < 0) {
+        ALOGE("failed to send cmd (%d) to %s: %s\n", cmd,
+                KEYMASTER_PORT, strerror(errno));
+        return -errno;
+    }
+
+    rc = read(handle_, out, *out_size);
+    if (rc < 0) {
+        ALOGE("failed to retrieve response for cmd (%d) to %s: %s\n",
+                cmd, KEYMASTER_PORT, strerror(errno));
+        return -errno;
+    }
+
+    if ((size_t) rc < sizeof(struct keymaster_message)) {
+        ALOGE("invalid response size (%d)\n", (int) rc);
+        return -EINVAL;
+    }
+
+    msg = (struct keymaster_message *) out;
+
+    if ((cmd | KEYMASTER_RESP_BIT) != msg->cmd) {
+        ALOGE("invalid command (%d)", msg->cmd);
+        return -EINVAL;
+    }
+
+    *out_size = ((size_t) rc) - sizeof(struct keymaster_message);
+    return rc;
+}
+
+void trusty_keymaster_disconnect() {
+    if (handle_ != 0) {
+        tipc_close(handle_);
+    }
+}
+
diff --git a/metricsd/aidl/android/brillo/metrics/IMetricsCollectorService.aidl b/trusty/keymaster/trusty_keymaster_ipc.h
similarity index 73%
copy from metricsd/aidl/android/brillo/metrics/IMetricsCollectorService.aidl
copy to trusty/keymaster/trusty_keymaster_ipc.h
index 49f484f..9785247 100644
--- a/metricsd/aidl/android/brillo/metrics/IMetricsCollectorService.aidl
+++ b/trusty/keymaster/trusty_keymaster_ipc.h
@@ -14,8 +14,11 @@
  * limitations under the License.
  */
 
-package android.brillo.metrics;
+__BEGIN_DECLS
 
-interface IMetricsCollectorService {
-  oneway void notifyUserCrash();
-}
+int trusty_keymaster_connect(void);
+int trusty_keymaster_call(uint32_t cmd, void *in, uint32_t in_size, uint8_t *out,
+         uint32_t *out_size);
+void trusty_keymaster_disconnect(void);
+
+__END_DECLS
diff --git a/trusty/keymaster/trusty_keymaster_main.cpp b/trusty/keymaster/trusty_keymaster_main.cpp
new file mode 100644
index 0000000..7ed880e
--- /dev/null
+++ b/trusty/keymaster/trusty_keymaster_main.cpp
@@ -0,0 +1,368 @@
+/*
+ * Copyright 2014 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 <stdio.h>
+
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#include "trusty_keymaster_device.h"
+
+using keymaster::TrustyKeymasterDevice;
+
+unsigned char rsa_privkey_pk8_der[] = {
+    0x30, 0x82, 0x02, 0x75, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+    0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x5f, 0x30, 0x82, 0x02, 0x5b, 0x02, 0x01,
+    0x00, 0x02, 0x81, 0x81, 0x00, 0xc6, 0x09, 0x54, 0x09, 0x04, 0x7d, 0x86, 0x34, 0x81, 0x2d, 0x5a,
+    0x21, 0x81, 0x76, 0xe4, 0x5c, 0x41, 0xd6, 0x0a, 0x75, 0xb1, 0x39, 0x01, 0xf2, 0x34, 0x22, 0x6c,
+    0xff, 0xe7, 0x76, 0x52, 0x1c, 0x5a, 0x77, 0xb9, 0xe3, 0x89, 0x41, 0x7b, 0x71, 0xc0, 0xb6, 0xa4,
+    0x4d, 0x13, 0xaf, 0xe4, 0xe4, 0xa2, 0x80, 0x5d, 0x46, 0xc9, 0xda, 0x29, 0x35, 0xad, 0xb1, 0xff,
+    0x0c, 0x1f, 0x24, 0xea, 0x06, 0xe6, 0x2b, 0x20, 0xd7, 0x76, 0x43, 0x0a, 0x4d, 0x43, 0x51, 0x57,
+    0x23, 0x3c, 0x6f, 0x91, 0x67, 0x83, 0xc3, 0x0e, 0x31, 0x0f, 0xcb, 0xd8, 0x9b, 0x85, 0xc2, 0xd5,
+    0x67, 0x71, 0x16, 0x97, 0x85, 0xac, 0x12, 0xbc, 0xa2, 0x44, 0xab, 0xda, 0x72, 0xbf, 0xb1, 0x9f,
+    0xc4, 0x4d, 0x27, 0xc8, 0x1e, 0x1d, 0x92, 0xde, 0x28, 0x4f, 0x40, 0x61, 0xed, 0xfd, 0x99, 0x28,
+    0x07, 0x45, 0xea, 0x6d, 0x25, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x81, 0x80, 0x1b, 0xe0, 0xf0,
+    0x4d, 0x9c, 0xae, 0x37, 0x18, 0x69, 0x1f, 0x03, 0x53, 0x38, 0x30, 0x8e, 0x91, 0x56, 0x4b, 0x55,
+    0x89, 0x9f, 0xfb, 0x50, 0x84, 0xd2, 0x46, 0x0e, 0x66, 0x30, 0x25, 0x7e, 0x05, 0xb3, 0xce, 0xab,
+    0x02, 0x97, 0x2d, 0xfa, 0xbc, 0xd6, 0xce, 0x5f, 0x6e, 0xe2, 0x58, 0x9e, 0xb6, 0x79, 0x11, 0xed,
+    0x0f, 0xac, 0x16, 0xe4, 0x3a, 0x44, 0x4b, 0x8c, 0x86, 0x1e, 0x54, 0x4a, 0x05, 0x93, 0x36, 0x57,
+    0x72, 0xf8, 0xba, 0xf6, 0xb2, 0x2f, 0xc9, 0xe3, 0xc5, 0xf1, 0x02, 0x4b, 0x06, 0x3a, 0xc0, 0x80,
+    0xa7, 0xb2, 0x23, 0x4c, 0xf8, 0xae, 0xe8, 0xf6, 0xc4, 0x7b, 0xbf, 0x4f, 0xd3, 0xac, 0xe7, 0x24,
+    0x02, 0x90, 0xbe, 0xf1, 0x6c, 0x0b, 0x3f, 0x7f, 0x3c, 0xdd, 0x64, 0xce, 0x3a, 0xb5, 0x91, 0x2c,
+    0xf6, 0xe3, 0x2f, 0x39, 0xab, 0x18, 0x83, 0x58, 0xaf, 0xcc, 0xcd, 0x80, 0x81, 0x02, 0x41, 0x00,
+    0xe4, 0xb4, 0x9e, 0xf5, 0x0f, 0x76, 0x5d, 0x3b, 0x24, 0xdd, 0xe0, 0x1a, 0xce, 0xaa, 0xf1, 0x30,
+    0xf2, 0xc7, 0x66, 0x70, 0xa9, 0x1a, 0x61, 0xae, 0x08, 0xaf, 0x49, 0x7b, 0x4a, 0x82, 0xbe, 0x6d,
+    0xee, 0x8f, 0xcd, 0xd5, 0xe3, 0xf7, 0xba, 0x1c, 0xfb, 0x1f, 0x0c, 0x92, 0x6b, 0x88, 0xf8, 0x8c,
+    0x92, 0xbf, 0xab, 0x13, 0x7f, 0xba, 0x22, 0x85, 0x22, 0x7b, 0x83, 0xc3, 0x42, 0xff, 0x7c, 0x55,
+    0x02, 0x41, 0x00, 0xdd, 0xab, 0xb5, 0x83, 0x9c, 0x4c, 0x7f, 0x6b, 0xf3, 0xd4, 0x18, 0x32, 0x31,
+    0xf0, 0x05, 0xb3, 0x1a, 0xa5, 0x8a, 0xff, 0xdd, 0xa5, 0xc7, 0x9e, 0x4c, 0xce, 0x21, 0x7f, 0x6b,
+    0xc9, 0x30, 0xdb, 0xe5, 0x63, 0xd4, 0x80, 0x70, 0x6c, 0x24, 0xe9, 0xeb, 0xfc, 0xab, 0x28, 0xa6,
+    0xcd, 0xef, 0xd3, 0x24, 0xb7, 0x7e, 0x1b, 0xf7, 0x25, 0x1b, 0x70, 0x90, 0x92, 0xc2, 0x4f, 0xf5,
+    0x01, 0xfd, 0x91, 0x02, 0x40, 0x23, 0xd4, 0x34, 0x0e, 0xda, 0x34, 0x45, 0xd8, 0xcd, 0x26, 0xc1,
+    0x44, 0x11, 0xda, 0x6f, 0xdc, 0xa6, 0x3c, 0x1c, 0xcd, 0x4b, 0x80, 0xa9, 0x8a, 0xd5, 0x2b, 0x78,
+    0xcc, 0x8a, 0xd8, 0xbe, 0xb2, 0x84, 0x2c, 0x1d, 0x28, 0x04, 0x05, 0xbc, 0x2f, 0x6c, 0x1b, 0xea,
+    0x21, 0x4a, 0x1d, 0x74, 0x2a, 0xb9, 0x96, 0xb3, 0x5b, 0x63, 0xa8, 0x2a, 0x5e, 0x47, 0x0f, 0xa8,
+    0x8d, 0xbf, 0x82, 0x3c, 0xdd, 0x02, 0x40, 0x1b, 0x7b, 0x57, 0x44, 0x9a, 0xd3, 0x0d, 0x15, 0x18,
+    0x24, 0x9a, 0x5f, 0x56, 0xbb, 0x98, 0x29, 0x4d, 0x4b, 0x6a, 0xc1, 0x2f, 0xfc, 0x86, 0x94, 0x04,
+    0x97, 0xa5, 0xa5, 0x83, 0x7a, 0x6c, 0xf9, 0x46, 0x26, 0x2b, 0x49, 0x45, 0x26, 0xd3, 0x28, 0xc1,
+    0x1e, 0x11, 0x26, 0x38, 0x0f, 0xde, 0x04, 0xc2, 0x4f, 0x91, 0x6d, 0xec, 0x25, 0x08, 0x92, 0xdb,
+    0x09, 0xa6, 0xd7, 0x7c, 0xdb, 0xa3, 0x51, 0x02, 0x40, 0x77, 0x62, 0xcd, 0x8f, 0x4d, 0x05, 0x0d,
+    0xa5, 0x6b, 0xd5, 0x91, 0xad, 0xb5, 0x15, 0xd2, 0x4d, 0x7c, 0xcd, 0x32, 0xcc, 0xa0, 0xd0, 0x5f,
+    0x86, 0x6d, 0x58, 0x35, 0x14, 0xbd, 0x73, 0x24, 0xd5, 0xf3, 0x36, 0x45, 0xe8, 0xed, 0x8b, 0x4a,
+    0x1c, 0xb3, 0xcc, 0x4a, 0x1d, 0x67, 0x98, 0x73, 0x99, 0xf2, 0xa0, 0x9f, 0x5b, 0x3f, 0xb6, 0x8c,
+    0x88, 0xd5, 0xe5, 0xd9, 0x0a, 0xc3, 0x34, 0x92, 0xd6};
+unsigned int rsa_privkey_pk8_der_len = 633;
+
+unsigned char dsa_privkey_pk8_der[] = {
+    0x30, 0x82, 0x01, 0x4b, 0x02, 0x01, 0x00, 0x30, 0x82, 0x01, 0x2b, 0x06, 0x07, 0x2a, 0x86, 0x48,
+    0xce, 0x38, 0x04, 0x01, 0x30, 0x82, 0x01, 0x1e, 0x02, 0x81, 0x81, 0x00, 0xa3, 0xf3, 0xe9, 0xb6,
+    0x7e, 0x7d, 0x88, 0xf6, 0xb7, 0xe5, 0xf5, 0x1f, 0x3b, 0xee, 0xac, 0xd7, 0xad, 0xbc, 0xc9, 0xd1,
+    0x5a, 0xf8, 0x88, 0xc4, 0xef, 0x6e, 0x3d, 0x74, 0x19, 0x74, 0xe7, 0xd8, 0xe0, 0x26, 0x44, 0x19,
+    0x86, 0xaf, 0x19, 0xdb, 0x05, 0xe9, 0x3b, 0x8b, 0x58, 0x58, 0xde, 0xe5, 0x4f, 0x48, 0x15, 0x01,
+    0xea, 0xe6, 0x83, 0x52, 0xd7, 0xc1, 0x21, 0xdf, 0xb9, 0xb8, 0x07, 0x66, 0x50, 0xfb, 0x3a, 0x0c,
+    0xb3, 0x85, 0xee, 0xbb, 0x04, 0x5f, 0xc2, 0x6d, 0x6d, 0x95, 0xfa, 0x11, 0x93, 0x1e, 0x59, 0x5b,
+    0xb1, 0x45, 0x8d, 0xe0, 0x3d, 0x73, 0xaa, 0xf2, 0x41, 0x14, 0x51, 0x07, 0x72, 0x3d, 0xa2, 0xf7,
+    0x58, 0xcd, 0x11, 0xa1, 0x32, 0xcf, 0xda, 0x42, 0xb7, 0xcc, 0x32, 0x80, 0xdb, 0x87, 0x82, 0xec,
+    0x42, 0xdb, 0x5a, 0x55, 0x24, 0x24, 0xa2, 0xd1, 0x55, 0x29, 0xad, 0xeb, 0x02, 0x15, 0x00, 0xeb,
+    0xea, 0x17, 0xd2, 0x09, 0xb3, 0xd7, 0x21, 0x9a, 0x21, 0x07, 0x82, 0x8f, 0xab, 0xfe, 0x88, 0x71,
+    0x68, 0xf7, 0xe3, 0x02, 0x81, 0x80, 0x19, 0x1c, 0x71, 0xfd, 0xe0, 0x03, 0x0c, 0x43, 0xd9, 0x0b,
+    0xf6, 0xcd, 0xd6, 0xa9, 0x70, 0xe7, 0x37, 0x86, 0x3a, 0x78, 0xe9, 0xa7, 0x47, 0xa7, 0x47, 0x06,
+    0x88, 0xb1, 0xaf, 0xd7, 0xf3, 0xf1, 0xa1, 0xd7, 0x00, 0x61, 0x28, 0x88, 0x31, 0x48, 0x60, 0xd8,
+    0x11, 0xef, 0xa5, 0x24, 0x1a, 0x81, 0xc4, 0x2a, 0xe2, 0xea, 0x0e, 0x36, 0xd2, 0xd2, 0x05, 0x84,
+    0x37, 0xcf, 0x32, 0x7d, 0x09, 0xe6, 0x0f, 0x8b, 0x0c, 0xc8, 0xc2, 0xa4, 0xb1, 0xdc, 0x80, 0xca,
+    0x68, 0xdf, 0xaf, 0xd2, 0x90, 0xc0, 0x37, 0x58, 0x54, 0x36, 0x8f, 0x49, 0xb8, 0x62, 0x75, 0x8b,
+    0x48, 0x47, 0xc0, 0xbe, 0xf7, 0x9a, 0x92, 0xa6, 0x68, 0x05, 0xda, 0x9d, 0xaf, 0x72, 0x9a, 0x67,
+    0xb3, 0xb4, 0x14, 0x03, 0xae, 0x4f, 0x4c, 0x76, 0xb9, 0xd8, 0x64, 0x0a, 0xba, 0x3b, 0xa8, 0x00,
+    0x60, 0x4d, 0xae, 0x81, 0xc3, 0xc5, 0x04, 0x17, 0x02, 0x15, 0x00, 0x81, 0x9d, 0xfd, 0x53, 0x0c,
+    0xc1, 0x8f, 0xbe, 0x8b, 0xea, 0x00, 0x26, 0x19, 0x29, 0x33, 0x91, 0x84, 0xbe, 0xad, 0x81};
+unsigned int dsa_privkey_pk8_der_len = 335;
+
+unsigned char ec_privkey_pk8_der[] = {
+    0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
+    0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02,
+    0x01, 0x01, 0x04, 0x20, 0x73, 0x7c, 0x2e, 0xcd, 0x7b, 0x8d, 0x19, 0x40, 0xbf, 0x29, 0x30, 0xaa,
+    0x9b, 0x4e, 0xd3, 0xff, 0x94, 0x1e, 0xed, 0x09, 0x36, 0x6b, 0xc0, 0x32, 0x99, 0x98, 0x64, 0x81,
+    0xf3, 0xa4, 0xd8, 0x59, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0xbf, 0x85, 0xd7, 0x72, 0x0d, 0x07,
+    0xc2, 0x54, 0x61, 0x68, 0x3b, 0xc6, 0x48, 0xb4, 0x77, 0x8a, 0x9a, 0x14, 0xdd, 0x8a, 0x02, 0x4e,
+    0x3b, 0xdd, 0x8c, 0x7d, 0xdd, 0x9a, 0xb2, 0xb5, 0x28, 0xbb, 0xc7, 0xaa, 0x1b, 0x51, 0xf1, 0x4e,
+    0xbb, 0xbb, 0x0b, 0xd0, 0xce, 0x21, 0xbc, 0xc4, 0x1c, 0x6e, 0xb0, 0x00, 0x83, 0xcf, 0x33, 0x76,
+    0xd1, 0x1f, 0xd4, 0x49, 0x49, 0xe0, 0xb2, 0x18, 0x3b, 0xfe};
+unsigned int ec_privkey_pk8_der_len = 138;
+
+struct EVP_PKEY_Delete {
+    void operator()(EVP_PKEY* p) const { EVP_PKEY_free(p); }
+};
+
+struct EVP_PKEY_CTX_Delete {
+    void operator()(EVP_PKEY_CTX* p) { EVP_PKEY_CTX_free(p); }
+};
+
+static bool test_import_rsa(TrustyKeymasterDevice* device) {
+    printf("===================\n");
+    printf("= RSA Import Test =\n");
+    printf("===================\n\n");
+
+    printf("=== Importing RSA keypair === \n");
+    uint8_t* key;
+    size_t size;
+    int error = device->import_keypair(rsa_privkey_pk8_der, rsa_privkey_pk8_der_len, &key, &size);
+    if (error != KM_ERROR_OK) {
+        printf("Error importing key pair: %d\n\n", error);
+        return false;
+    }
+    UniquePtr<uint8_t[]> key_deleter(key);
+
+    printf("=== Signing with imported RSA key ===\n");
+    keymaster_rsa_sign_params_t sign_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_len = 1024 / 8;
+    UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+    memset(message.get(), 'a', message_len);
+    uint8_t* signature;
+    size_t signature_len;
+    error = device->sign_data(&sign_params, key, size, message.get(), message_len, &signature,
+                              &signature_len);
+    if (error != KM_ERROR_OK) {
+        printf("Error signing data with imported RSA key: %d\n\n", error);
+        return false;
+    }
+    UniquePtr<uint8_t[]> signature_deleter(signature);
+
+    printf("=== Verifying with imported RSA key === \n");
+    error = device->verify_data(&sign_params, key, size, message.get(), message_len, signature,
+                                signature_len);
+    if (error != KM_ERROR_OK) {
+        printf("Error verifying data with imported RSA key: %d\n\n", error);
+        return false;
+    }
+
+    printf("\n");
+    return true;
+}
+
+static bool test_rsa(TrustyKeymasterDevice* device) {
+    printf("============\n");
+    printf("= RSA Test =\n");
+    printf("============\n\n");
+
+    printf("=== Generating RSA key pair ===\n");
+    keymaster_rsa_keygen_params_t params;
+    params.public_exponent = 65537;
+    params.modulus_size = 2048;
+
+    uint8_t* key;
+    size_t size;
+    int error = device->generate_keypair(TYPE_RSA, &params, &key, &size);
+    if (error != KM_ERROR_OK) {
+        printf("Error generating RSA key pair: %d\n\n", error);
+        return false;
+    }
+    UniquePtr<uint8_t[]> deleter(key);
+
+    printf("=== Signing with RSA key === \n");
+    keymaster_rsa_sign_params_t sign_params = {DIGEST_NONE, PADDING_NONE};
+    size_t message_len = params.modulus_size / 8;
+    UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+    memset(message.get(), 'a', message_len);
+    uint8_t* signature;
+    size_t signature_len;
+    error = device->sign_data(&sign_params, key, size, message.get(), message_len, &signature,
+                              &signature_len);
+    if (error != KM_ERROR_OK) {
+        printf("Error signing data with RSA key: %d\n\n", error);
+        return false;
+    }
+    UniquePtr<uint8_t[]> signature_deleter(signature);
+
+    printf("=== Verifying with RSA key === \n");
+    error = device->verify_data(&sign_params, key, size, message.get(), message_len, signature,
+                                signature_len);
+    if (error != KM_ERROR_OK) {
+        printf("Error verifying data with RSA key: %d\n\n", error);
+        return false;
+    }
+
+    printf("=== Exporting RSA public key ===\n");
+    uint8_t* exported_key;
+    size_t exported_size;
+    error = device->get_keypair_public(key, size, &exported_key, &exported_size);
+    if (error != KM_ERROR_OK) {
+        printf("Error exporting RSA public key: %d\n\n", error);
+        return false;
+    }
+
+    printf("=== Verifying with exported key ===\n");
+    const uint8_t* tmp = exported_key;
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(d2i_PUBKEY(NULL, &tmp, exported_size));
+    UniquePtr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
+    if (EVP_PKEY_verify_init(ctx.get()) != 1) {
+        printf("Error initializing openss EVP context\n");
+        return false;
+    }
+    if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) {
+        printf("Exported key was the wrong type?!?\n");
+        return false;
+    }
+
+    EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_NO_PADDING);
+    if (EVP_PKEY_verify(ctx.get(), signature, signature_len, message.get(), message_len) != 1) {
+        printf("Verification with exported pubkey failed.\n");
+        return false;
+    } else {
+        printf("Verification succeeded\n");
+    }
+
+    printf("\n");
+    return true;
+}
+
+static bool test_import_ecdsa(TrustyKeymasterDevice* device) {
+    printf("=====================\n");
+    printf("= ECDSA Import Test =\n");
+    printf("=====================\n\n");
+
+    printf("=== Importing ECDSA keypair === \n");
+    uint8_t* key;
+    size_t size;
+    int error = device->import_keypair(ec_privkey_pk8_der, ec_privkey_pk8_der_len, &key, &size);
+    if (error != KM_ERROR_OK) {
+        printf("Error importing key pair: %d\n\n", error);
+        return false;
+    }
+    UniquePtr<uint8_t[]> deleter(key);
+
+    printf("=== Signing with imported ECDSA key ===\n");
+    keymaster_ec_sign_params_t sign_params = {DIGEST_NONE};
+    size_t message_len = 30 /* arbitrary */;
+    UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+    memset(message.get(), 'a', message_len);
+    uint8_t* signature;
+    size_t signature_len;
+    error = device->sign_data(&sign_params, key, size, message.get(), message_len, &signature,
+                              &signature_len);
+    if (error != KM_ERROR_OK) {
+        printf("Error signing data with imported ECDSA key: %d\n\n", error);
+        return false;
+    }
+    UniquePtr<uint8_t[]> signature_deleter(signature);
+
+    printf("=== Verifying with imported ECDSA key === \n");
+    error = device->verify_data(&sign_params, key, size, message.get(), message_len, signature,
+                                signature_len);
+    if (error != KM_ERROR_OK) {
+        printf("Error verifying data with imported ECDSA key: %d\n\n", error);
+        return false;
+    }
+
+    printf("\n");
+    return true;
+}
+
+static bool test_ecdsa(TrustyKeymasterDevice* device) {
+    printf("==============\n");
+    printf("= ECDSA Test =\n");
+    printf("==============\n\n");
+
+    printf("=== Generating ECDSA key pair ===\n");
+    keymaster_ec_keygen_params_t params;
+    params.field_size = 521;
+    uint8_t* key;
+    size_t size;
+    int error = device->generate_keypair(TYPE_EC, &params, &key, &size);
+    if (error != 0) {
+        printf("Error generating ECDSA key pair: %d\n\n", error);
+        return false;
+    }
+    UniquePtr<uint8_t[]> deleter(key);
+
+    printf("=== Signing with ECDSA key === \n");
+    keymaster_ec_sign_params_t sign_params = {DIGEST_NONE};
+    size_t message_len = 30 /* arbitrary */;
+    UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+    memset(message.get(), 'a', message_len);
+    uint8_t* signature;
+    size_t signature_len;
+    error = device->sign_data(&sign_params, key, size, message.get(), message_len, &signature,
+                              &signature_len);
+    if (error != KM_ERROR_OK) {
+        printf("Error signing data with ECDSA key: %d\n\n", error);
+        return false;
+    }
+    UniquePtr<uint8_t[]> signature_deleter(signature);
+
+    printf("=== Verifying with ECDSA key === \n");
+    error = device->verify_data(&sign_params, key, size, message.get(), message_len, signature,
+                                signature_len);
+    if (error != KM_ERROR_OK) {
+        printf("Error verifying data with ECDSA key: %d\n\n", error);
+        return false;
+    }
+
+    printf("=== Exporting ECDSA public key ===\n");
+    uint8_t* exported_key;
+    size_t exported_size;
+    error = device->get_keypair_public(key, size, &exported_key, &exported_size);
+    if (error != KM_ERROR_OK) {
+        printf("Error exporting ECDSA public key: %d\n\n", error);
+        return false;
+    }
+
+    printf("=== Verifying with exported key ===\n");
+    const uint8_t* tmp = exported_key;
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(d2i_PUBKEY(NULL, &tmp, exported_size));
+    UniquePtr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
+    if (EVP_PKEY_verify_init(ctx.get()) != 1) {
+        printf("Error initializing openss EVP context\n");
+        return false;
+    }
+    if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) {
+        printf("Exported key was the wrong type?!?\n");
+        return false;
+    }
+
+    if (EVP_PKEY_verify(ctx.get(), signature, signature_len, message.get(), message_len) != 1) {
+        printf("Verification with exported pubkey failed.\n");
+        return false;
+    } else {
+        printf("Verification succeeded\n");
+    }
+
+    printf("\n");
+    return true;
+}
+
+int main(void) {
+
+    TrustyKeymasterDevice device(NULL);
+    if (device.session_error() != KM_ERROR_OK) {
+        printf("Failed to initialize Trusty session: %d\n", device.session_error());
+        return 1;
+    }
+    printf("Trusty session initialized\n");
+
+    bool success = true;
+    success &= test_rsa(&device);
+    success &= test_import_rsa(&device);
+    success &= test_ecdsa(&device);
+    success &= test_import_ecdsa(&device);
+
+    if (success) {
+        printf("\nTESTS PASSED!\n");
+    } else {
+        printf("\n!!!!TESTS FAILED!!!\n");
+    }
+
+    return success ? 0 : 1;
+}
diff --git a/trusty/libtrusty/tipc-test/tipc_test.c b/trusty/libtrusty/tipc-test/tipc_test.c
index 55d5ee6..1fb34c9 100644
--- a/trusty/libtrusty/tipc-test/tipc_test.c
+++ b/trusty/libtrusty/tipc-test/tipc_test.c
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <getopt.h>
+#include <sys/uio.h>
 
 #include <trusty/tipc.h>
 
@@ -80,6 +81,8 @@
 "   ta2ta-ipc    - execute TA to TA unittest\n"
 "   dev-uuid     - print device uuid\n"
 "   ta-access    - test ta-access flags\n"
+"   writev       - writev test\n"
+"   readv        - readv test\n"
 "\n"
 ;
 
@@ -93,7 +96,7 @@
 {
 	fprintf (stderr, usage, prog);
 	if (verbose)
-		fprintf (stderr, usage_long);
+		fprintf (stderr, "%s", usage_long);
 	exit(code);
 }
 
@@ -692,6 +695,171 @@
 }
 
 
+static int writev_test(uint repeat, uint msgsz, bool var)
+{
+	uint i;
+	ssize_t rc;
+	size_t  msg_len;
+	int  echo_fd = -1;
+	char tx0_buf[msgsz];
+	char tx1_buf[msgsz];
+	char rx_buf [msgsz];
+	struct iovec iovs[2]= {{tx0_buf, 0}, {tx1_buf, 0}};
+
+	if (!opt_silent) {
+		printf("%s: repeat %u: msgsz %u: variable %s\n",
+			__func__, repeat, msgsz, var ? "true" : "false");
+	}
+
+	echo_fd = tipc_connect(dev_name, echo_name);
+	if (echo_fd < 0) {
+		fprintf(stderr, "Failed to connect to service\n");
+		return echo_fd;
+	}
+
+	for (i = 0; i < repeat; i++) {
+
+		msg_len = msgsz;
+		if (opt_variable && msgsz) {
+			msg_len = rand() % msgsz;
+		}
+
+		iovs[0].iov_len = msg_len / 3;
+		iovs[1].iov_len = msg_len - iovs[0].iov_len;
+
+		memset(tx0_buf, i + 1, iovs[0].iov_len);
+		memset(tx1_buf, i + 2, iovs[1].iov_len);
+		memset(rx_buf,  i + 3, sizeof(rx_buf));
+
+		rc = writev(echo_fd, iovs, 2);
+		if (rc < 0) {
+			perror("writev_test: writev");
+			break;
+		}
+
+		if ((size_t)rc != msg_len) {
+			fprintf(stderr,
+				"%s: %s: data size mismatch (%zd vs. %zd)\n",
+				__func__, "writev", (size_t)rc, msg_len);
+			break;
+		}
+
+		rc = read(echo_fd, rx_buf, sizeof(rx_buf));
+		if (rc < 0) {
+			perror("writev_test: read");
+			break;
+		}
+
+		if ((size_t)rc != msg_len) {
+			fprintf(stderr,
+				"%s: %s: data size mismatch (%zd vs. %zd)\n",
+				__func__, "read", (size_t)rc, msg_len);
+			break;
+		}
+
+		if (memcmp(tx0_buf, rx_buf, iovs[0].iov_len)) {
+			fprintf(stderr, "%s: data mismatch: buf 0\n", __func__);
+			break;
+		}
+
+		if (memcmp(tx1_buf, rx_buf + iovs[0].iov_len, iovs[1].iov_len)) {
+			fprintf(stderr, "%s: data mismatch, buf 1\n", __func__);
+			break;
+		}
+	}
+
+	tipc_close(echo_fd);
+
+	if (!opt_silent) {
+		printf("%s: done\n",__func__);
+	}
+
+	return 0;
+}
+
+static int readv_test(uint repeat, uint msgsz, bool var)
+{
+	uint i;
+	ssize_t rc;
+	size_t  msg_len;
+	int  echo_fd = -1;
+	char tx_buf [msgsz];
+	char rx0_buf[msgsz];
+	char rx1_buf[msgsz];
+	struct iovec iovs[2]= {{rx0_buf, 0}, {rx1_buf, 0}};
+
+	if (!opt_silent) {
+		printf("%s: repeat %u: msgsz %u: variable %s\n",
+			__func__, repeat, msgsz, var ? "true" : "false");
+	}
+
+	echo_fd = tipc_connect(dev_name, echo_name);
+	if (echo_fd < 0) {
+		fprintf(stderr, "Failed to connect to service\n");
+		return echo_fd;
+	}
+
+	for (i = 0; i < repeat; i++) {
+
+		msg_len = msgsz;
+		if (opt_variable && msgsz) {
+			msg_len = rand() % msgsz;
+		}
+
+		iovs[0].iov_len = msg_len / 3;
+		iovs[1].iov_len = msg_len - iovs[0].iov_len;
+
+		memset(tx_buf,  i + 1, sizeof(tx_buf));
+		memset(rx0_buf, i + 2, iovs[0].iov_len);
+		memset(rx1_buf, i + 3, iovs[1].iov_len);
+
+		rc = write(echo_fd, tx_buf, msg_len);
+		if (rc < 0) {
+			perror("readv_test: write");
+			break;
+		}
+
+		if ((size_t)rc != msg_len) {
+			fprintf(stderr,
+				"%s: %s: data size mismatch (%zd vs. %zd)\n",
+				__func__, "write", (size_t)rc, msg_len);
+			break;
+		}
+
+		rc = readv(echo_fd, iovs, 2);
+		if (rc < 0) {
+			perror("readv_test: readv");
+			break;
+		}
+
+		if ((size_t)rc != msg_len) {
+			fprintf(stderr,
+				"%s: %s: data size mismatch (%zd vs. %zd)\n",
+				__func__, "write", (size_t)rc, msg_len);
+			break;
+		}
+
+		if (memcmp(rx0_buf, tx_buf, iovs[0].iov_len)) {
+			fprintf(stderr, "%s: data mismatch: buf 0\n", __func__);
+			break;
+		}
+
+		if (memcmp(rx1_buf, tx_buf + iovs[0].iov_len, iovs[1].iov_len)) {
+			fprintf(stderr, "%s: data mismatch, buf 1\n", __func__);
+			break;
+		}
+	}
+
+	tipc_close(echo_fd);
+
+	if (!opt_silent) {
+		printf("%s: done\n",__func__);
+	}
+
+	return 0;
+}
+
+
 int main(int argc, char **argv)
 {
 	int rc = 0;
@@ -735,6 +903,10 @@
 		rc = dev_uuid_test();
 	} else if (strcmp(test_name, "ta-access") == 0) {
 		rc = ta_access_test();
+	} else if (strcmp(test_name, "writev") == 0) {
+		rc = writev_test(opt_repeat, opt_msgsize, opt_variable);
+	} else if (strcmp(test_name, "readv") == 0) {
+		rc = readv_test(opt_repeat, opt_msgsize, opt_variable);
 	} else {
 		fprintf(stderr, "Unrecognized test name '%s'\n", test_name);
 		print_usage_and_exit(argv[0], EXIT_FAILURE, true);
diff --git a/trusty/libtrusty/trusty.c b/trusty/libtrusty/trusty.c
index b6897ce..2398a53 100644
--- a/trusty/libtrusty/trusty.c
+++ b/trusty/libtrusty/trusty.c
@@ -22,8 +22,10 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
 
-#include <cutils/log.h>
+#include <android/log.h>
 
 #include "tipc_ioctl.h"
 
diff --git a/trusty/nvram/Android.mk b/trusty/nvram/Android.mk
new file mode 100644
index 0000000..44e2212
--- /dev/null
+++ b/trusty/nvram/Android.mk
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+# nvram.trusty is the Trusty NVRAM HAL module.
+include $(CLEAR_VARS)
+LOCAL_MODULE := nvram.trusty
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+	module.c \
+	trusty_nvram_device.cpp \
+	trusty_nvram_implementation.cpp
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -Wall -Werror -Wextra -fvisibility=hidden
+LOCAL_STATIC_LIBRARIES := libnvram-hal
+LOCAL_SHARED_LIBRARIES := libtrusty libnvram-messages liblog
+include $(BUILD_SHARED_LIBRARY)
+
+# nvram-wipe is a helper tool for clearing NVRAM state.
+include $(CLEAR_VARS)
+LOCAL_MODULE := nvram-wipe
+LOCAL_SRC_FILES := \
+	nvram_wipe.cpp \
+	trusty_nvram_implementation.cpp
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -Wall -Werror -Wextra -fvisibility=hidden
+LOCAL_STATIC_LIBRARIES := libnvram-hal
+LOCAL_SHARED_LIBRARIES := libtrusty libnvram-messages liblog
+include $(BUILD_EXECUTABLE)
diff --git a/trusty/nvram/module.c b/trusty/nvram/module.c
new file mode 100644
index 0000000..a2e64d3
--- /dev/null
+++ b/trusty/nvram/module.c
@@ -0,0 +1,39 @@
+/*
+ * 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 <hardware/nvram.h>
+
+// This function is defined in trusty_nvram_device.cpp.
+int trusty_nvram_open(const hw_module_t* module,
+                      const char* device_id,
+                      hw_device_t** device_ptr);
+
+static struct hw_module_methods_t nvram_module_methods = {
+    .open = trusty_nvram_open,
+};
+
+struct nvram_module HAL_MODULE_INFO_SYM
+    __attribute__((visibility("default"))) = {
+        .common = {.tag = HARDWARE_MODULE_TAG,
+                   .module_api_version = NVRAM_MODULE_API_VERSION_0_1,
+                   .hal_api_version = HARDWARE_HAL_API_VERSION,
+                   .id = NVRAM_HARDWARE_MODULE_ID,
+                   .name = "Trusty NVRAM HAL",
+                   .author = "The Android Open Source Project",
+                   .methods = &nvram_module_methods,
+                   .dso = 0,
+                   .reserved = {}},
+};
diff --git a/trusty/nvram/nvram_wipe.cpp b/trusty/nvram/nvram_wipe.cpp
new file mode 100644
index 0000000..d0f4fad
--- /dev/null
+++ b/trusty/nvram/nvram_wipe.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <nvram/messages/nvram_messages.h>
+
+#include "trusty_nvram_implementation.h"
+
+void usage(const char* program_name) {
+  fprintf(stderr, "Usage: %s [status|disable|wipe]\n", program_name);
+  exit(-1);
+}
+
+int main(int argc, char* argv[]) {
+  if (argc < 2) {
+    usage(argv[0]);
+  }
+
+  nvram::TrustyNvramImplementation nvram_proxy;
+  nvram::Request request;
+  nvram::Response response;
+
+  if (!strcmp(argv[1], "status")) {
+    request.payload.Activate<nvram::COMMAND_GET_INFO>();
+    nvram_proxy.Execute(request, &response);
+    const nvram::GetInfoResponse* get_info_response =
+        response.payload.get<nvram::COMMAND_GET_INFO>();
+    if (response.result == NV_RESULT_SUCCESS) {
+      int status = get_info_response && get_info_response->wipe_disabled;
+      printf("Wiping disabled: %d\n", status);
+      return status;
+    }
+  } else if (!strcmp(argv[1], "disable")) {
+    request.payload.Activate<nvram::COMMAND_DISABLE_WIPE>();
+    nvram_proxy.Execute(request, &response);
+  } else if (!strcmp(argv[1], "wipe")) {
+    request.payload.Activate<nvram::COMMAND_WIPE_STORAGE>();
+    nvram_proxy.Execute(request, &response);
+  } else {
+    usage(argv[0]);
+  }
+
+  if (response.result != NV_RESULT_SUCCESS) {
+    fprintf(stderr, "Command execution failure: %u\n", response.result);
+    return -1;
+  }
+
+  return 0;
+}
+
diff --git a/trusty/nvram/trusty_nvram_device.cpp b/trusty/nvram/trusty_nvram_device.cpp
new file mode 100644
index 0000000..2c50915
--- /dev/null
+++ b/trusty/nvram/trusty_nvram_device.cpp
@@ -0,0 +1,32 @@
+/*
+ * 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 <nvram/hal/nvram_device_adapter.h>
+
+#include "trusty_nvram_implementation.h"
+
+extern "C" int trusty_nvram_open(const hw_module_t* module,
+                                 const char* device_id,
+                                 hw_device_t** device_ptr) {
+  if (strcmp(NVRAM_HARDWARE_DEVICE_ID, device_id) != 0) {
+    return -EINVAL;
+  }
+
+  nvram::NvramDeviceAdapter* adapter = new nvram::NvramDeviceAdapter(
+      module, new nvram::TrustyNvramImplementation);
+  *device_ptr = adapter->as_device();
+  return 0;
+}
diff --git a/trusty/nvram/trusty_nvram_implementation.cpp b/trusty/nvram/trusty_nvram_implementation.cpp
new file mode 100644
index 0000000..ddaf333
--- /dev/null
+++ b/trusty/nvram/trusty_nvram_implementation.cpp
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "TrustyNVRAM"
+
+#include "trusty_nvram_implementation.h"
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <android/log.h>
+#include <hardware/nvram.h>
+#include <trusty/tipc.h>
+
+#include <nvram/messages/blob.h>
+
+namespace nvram {
+namespace {
+
+// Character device to open for Trusty IPC connections.
+const char kTrustyDeviceName[] = "/dev/trusty-ipc-dev0";
+
+// App identifier of the NVRAM app.
+const char kTrustyNvramAppId[] = "com.android.trusty.nvram";
+
+}  // namespace
+
+TrustyNvramImplementation::~TrustyNvramImplementation() {
+  if (tipc_nvram_fd_ != -1) {
+    tipc_close(tipc_nvram_fd_);
+    tipc_nvram_fd_ = -1;
+  }
+}
+
+void TrustyNvramImplementation::Execute(const nvram::Request& request,
+                                        nvram::Response* response) {
+  if (!SendRequest(request, response)) {
+    response->result = NV_RESULT_INTERNAL_ERROR;
+  }
+}
+
+bool TrustyNvramImplementation::Connect() {
+  if (tipc_nvram_fd_ != -1) {
+    return true;
+  }
+
+  int rc = tipc_connect(kTrustyDeviceName, kTrustyNvramAppId);
+  if (rc < 0) {
+    ALOGE("Failed to connect to Trusty NVRAM app: %s\n", strerror(-rc));
+    return false;
+  }
+
+  tipc_nvram_fd_ = rc;
+  return true;
+}
+
+bool TrustyNvramImplementation::SendRequest(const nvram::Request& request,
+                                            nvram::Response* response) {
+  if (!Connect()) {
+    return false;
+  }
+
+  nvram::Blob request_buffer;
+  if (!nvram::Encode(request, &request_buffer)) {
+    ALOGE("Failed to encode NVRAM request.\n");
+    return false;
+  }
+
+  ssize_t rc =
+      write(tipc_nvram_fd_, request_buffer.data(), request_buffer.size());
+  if (rc < 0) {
+    ALOGE("Failed to send NVRAM request: %s\n", strerror(-rc));
+    return false;
+  }
+  if (static_cast<size_t>(rc) != request_buffer.size()) {
+    ALOGE("Failed to send full request buffer: %zd\n", rc);
+    return false;
+  }
+
+  rc = read(tipc_nvram_fd_, response_buffer_, sizeof(response_buffer_));
+  if (rc < 0) {
+    ALOGE("Failed to read NVRAM response: %s\n", strerror(-rc));
+    return false;
+  }
+
+  if (static_cast<size_t>(rc) >= sizeof(response_buffer_)) {
+    ALOGE("NVRAM response exceeds response buffer size.\n");
+    return false;
+  }
+
+  if (!nvram::Decode(response_buffer_, static_cast<size_t>(rc), response)) {
+    ALOGE("Failed to decode NVRAM response.\n");
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace nvram
diff --git a/trusty/nvram/trusty_nvram_implementation.h b/trusty/nvram/trusty_nvram_implementation.h
new file mode 100644
index 0000000..60758f7
--- /dev/null
+++ b/trusty/nvram/trusty_nvram_implementation.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#ifndef TRUSTY_NVRAM_TRUSTY_NVRAM_IMPLEMENTATION_H_
+#define TRUSTY_NVRAM_TRUSTY_NVRAM_IMPLEMENTATION_H_
+
+#include <stdint.h>
+
+#include <nvram/hal/nvram_device_adapter.h>
+#include <nvram/messages/nvram_messages.h>
+
+namespace nvram {
+
+// |TrustyNvramImplementation| proxies requests to the Trusty NVRAM app. It
+// serializes the request objects, sends it to the Trusty app and finally reads
+// back the result and decodes it.
+class TrustyNvramImplementation : public nvram::NvramImplementation {
+ public:
+  ~TrustyNvramImplementation() override;
+
+  void Execute(const nvram::Request& request,
+               nvram::Response* response) override;
+
+ private:
+  // Connects the IPC channel to the Trusty app if it is not already open.
+  // Returns true if the channel is open, false on errors.
+  bool Connect();
+
+  // Dispatches a command to the trust app. Returns true if successful (note
+  // that the response may still indicate an error on the Trusty side), false if
+  // there are any I/O or encoding/decoding errors.
+  bool SendRequest(const nvram::Request& request,
+                   nvram::Response* response);
+
+  // The file descriptor for the IPC connection to the Trusty app.
+  int tipc_nvram_fd_ = -1;
+
+  // Response buffer. This puts a hard size limit on the responses from the
+  // Trusty app. 4096 matches the maximum IPC message size currently supported
+  // by Trusty.
+  uint8_t response_buffer_[4096];
+};
+
+}  // namespace nvram
+
+#endif  // TRUSTY_NVRAM_TRUSTY_NVRAM_IMPLEMENTATION_H_
diff --git a/adf/libadf/Android.mk b/trusty/storage/interface/Android.mk
similarity index 76%
rename from adf/libadf/Android.mk
rename to trusty/storage/interface/Android.mk
index 7df354b..15cb6f3 100644
--- a/adf/libadf/Android.mk
+++ b/trusty/storage/interface/Android.mk
@@ -1,4 +1,5 @@
-# Copyright (C) 2013 The Android Open Source Project
+#
+# 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.
@@ -11,14 +12,14 @@
 # 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.
+#
 
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES := adf.c
-LOCAL_MODULE := libadf
-LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS += -Werror
+
+LOCAL_MODULE := libtrustystorageinterface
+
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS)
+
 include $(BUILD_STATIC_LIBRARY)
diff --git a/trusty/storage/interface/include/trusty/interface/storage.h b/trusty/storage/interface/include/trusty/interface/storage.h
new file mode 100644
index 0000000..b196d88
--- /dev/null
+++ b/trusty/storage/interface/include/trusty/interface/storage.h
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2015-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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+/*
+ * Storage port names
+ * @STORAGE_CLIENT_TD_PORT:     Port used by clients that require tamper and
+ *                              rollback detection.
+ * @STORAGE_CLIENT_TDEA_PORT:   Port used by clients that require storage before
+ *                              the non-secure os has booted.
+ * @STORAGE_CLIENT_TP_PORT:     Port used by clients that require tamper proof
+ *                              storage. Note that non-secure code can prevent
+                                read and write operations from succeeding, but
+                                it cannot modify on-disk data.
+ * @STORAGE_DISK_PROXY_PORT:    Port used by non-secure proxy server
+ */
+#define STORAGE_CLIENT_TD_PORT     "com.android.trusty.storage.client.td"
+#define STORAGE_CLIENT_TDEA_PORT   "com.android.trusty.storage.client.tdea"
+#define STORAGE_CLIENT_TP_PORT     "com.android.trusty.storage.client.tp"
+#define STORAGE_DISK_PROXY_PORT    "com.android.trusty.storage.proxy"
+
+enum storage_cmd {
+	STORAGE_REQ_SHIFT = 1,
+	STORAGE_RESP_BIT  = 1,
+
+	STORAGE_RESP_MSG_ERR   = STORAGE_RESP_BIT,
+
+	STORAGE_FILE_DELETE    = 1 << STORAGE_REQ_SHIFT,
+	STORAGE_FILE_OPEN      = 2 << STORAGE_REQ_SHIFT,
+	STORAGE_FILE_CLOSE     = 3 << STORAGE_REQ_SHIFT,
+	STORAGE_FILE_READ      = 4 << STORAGE_REQ_SHIFT,
+	STORAGE_FILE_WRITE     = 5 << STORAGE_REQ_SHIFT,
+	STORAGE_FILE_GET_SIZE  = 6 << STORAGE_REQ_SHIFT,
+	STORAGE_FILE_SET_SIZE  = 7 << STORAGE_REQ_SHIFT,
+
+	STORAGE_RPMB_SEND      = 8 << STORAGE_REQ_SHIFT,
+
+	/* transaction support */
+	STORAGE_END_TRANSACTION = 9 << STORAGE_REQ_SHIFT,
+};
+
+/**
+ * enum storage_err - error codes for storage protocol
+ * @STORAGE_NO_ERROR:           all OK
+ * @STORAGE_ERR_GENERIC:        unknown error. Can occur when there's an internal server
+ *                              error, e.g. the server runs out of memory or is in a bad state.
+ * @STORAGE_ERR_NOT_VALID:      input not valid. May occur if the arguments passed
+ *                              into the command are not valid, for example if the file handle
+ *                              passed in is not a valid one.
+ * @STORAGE_ERR_UNIMPLEMENTED:  the command passed in is not recognized
+ * @STORAGE_ERR_ACCESS:         the file is not accessible in the requested mode
+ * @STORAGE_ERR_NOT_FOUND:      the file was not found
+ * @STORAGE_ERR_EXIST           the file exists when it shouldn't as in with OPEN_CREATE | OPEN_EXCLUSIVE.
+ * @STORAGE_ERR_TRANSACT        returned by various operations to indicate that current transaction
+ *                              is in error state. Such state could be only cleared by sending
+ *                              STORAGE_END_TRANSACTION message.
+ */
+enum storage_err {
+	STORAGE_NO_ERROR          = 0,
+	STORAGE_ERR_GENERIC       = 1,
+	STORAGE_ERR_NOT_VALID     = 2,
+	STORAGE_ERR_UNIMPLEMENTED = 3,
+	STORAGE_ERR_ACCESS        = 4,
+	STORAGE_ERR_NOT_FOUND     = 5,
+	STORAGE_ERR_EXIST         = 6,
+	STORAGE_ERR_TRANSACT      = 7,
+};
+
+/**
+ * storage_delete_flag - flags for controlling delete semantics
+ */
+enum storage_file_delete_flag {
+	STORAGE_FILE_DELETE_MASK = 0,
+};
+
+/**
+ * storage_file_flag - Flags to control 'open' semantics.
+ * @STORAGE_FILE_OPEN_CREATE:           if this file does not exist, create it.
+ * @STORAGE_FILE_OPEN_CREATE_EXCLUSIVE: causes STORAGE_FILE_OPEN_CREATE to fail if the file
+ *                                      already exists. Only meaningful if used in combination
+ *                                      with STORAGE_FILE_OPEN_CREATE.
+ * @STORAGE_FILE_OPEN_TRUNCATE:         if this file already exists, discard existing content
+ *                                      and open it as a new file. No change in semantics if the
+ *                                      file does not exist.
+ * @STORAGE_FILE_OPEN_MASK:             mask for all open flags supported in current protocol.
+ *                                      All other bits must be set to 0.
+ */
+enum storage_file_open_flag {
+	STORAGE_FILE_OPEN_CREATE             = (1 << 0),
+	STORAGE_FILE_OPEN_CREATE_EXCLUSIVE   = (1 << 1),
+	STORAGE_FILE_OPEN_TRUNCATE           = (1 << 2),
+	STORAGE_FILE_OPEN_MASK               = STORAGE_FILE_OPEN_CREATE |
+					       STORAGE_FILE_OPEN_TRUNCATE |
+					       STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+};
+
+/**
+ * enum storage_msg_flag - protocol-level flags in struct storage_msg
+ * @STORAGE_MSG_FLAG_BATCH:             if set, command belongs to a batch transaction.
+ *                                      No response will be sent by the server until
+ *                                      it receives a command with this flag unset, at
+ *                                      which point a cummulative result for all messages
+ *                                      sent with STORAGE_MSG_FLAG_BATCH will be sent.
+ *                                      This is only supported by the non-secure disk proxy
+ *                                      server.
+ * @STORAGE_MSG_FLAG_PRE_COMMIT:        if set, indicates that server need to commit
+ *                                      pending changes before processing this message.
+ * @STORAGE_MSG_FLAG_POST_COMMIT:       if set, indicates that server need to commit
+ *                                      pending changes after processing this message.
+ * @STORAGE_MSG_FLAG_TRANSACT_COMPLETE: if set, indicates that server need to commit
+ *                                      current transaction after processing this message.
+ *                                      It is an alias for STORAGE_MSG_FLAG_POST_COMMIT.
+ */
+enum storage_msg_flag {
+	STORAGE_MSG_FLAG_BATCH = 0x1,
+	STORAGE_MSG_FLAG_PRE_COMMIT = 0x2,
+	STORAGE_MSG_FLAG_POST_COMMIT = 0x4,
+	STORAGE_MSG_FLAG_TRANSACT_COMPLETE = STORAGE_MSG_FLAG_POST_COMMIT,
+};
+
+/*
+ * The following declarations are the message-specific contents of
+ * the 'payload' element inside struct storage_msg.
+ */
+
+/**
+ * struct storage_file_delete_req - request format for STORAGE_FILE_DELETE
+ * @flags: currently unused, must be set to 0.
+ * @name:  the name of the file
+ */
+struct storage_file_delete_req {
+	uint32_t flags;
+	char name[0];
+};
+
+/**
+ * struct storage_file_open_req - request format for STORAGE_FILE_OPEN
+ * @flags: any of enum storage_file_flag or'ed together
+ * @name:  the name of the file
+ */
+struct storage_file_open_req {
+	uint32_t flags;
+	char     name[0];
+};
+
+/**
+ * struct storage_file_open_resp - response format for STORAGE_FILE_OPEN
+ * @handle: opaque handle to the opened file. Only present on success.
+ */
+struct storage_file_open_resp {
+	uint32_t handle;
+};
+
+/**
+ * struct storage_file_close_req - request format for STORAGE_FILE_CLOSE
+ * @handle: the handle for the file to close
+ */
+struct storage_file_close_req {
+	uint32_t handle;
+};
+
+/**
+ * struct storage_file_read_req - request format for STORAGE_FILE_READ
+ * @handle: the handle for the file from which to read
+ * @size:   the quantity of bytes to read from the file
+ * @offset: the offset in the file from whence to read
+ */
+struct storage_file_read_req {
+	uint32_t handle;
+	uint32_t size;
+	uint64_t offset;
+};
+
+/**
+ * struct storage_file_read_resp - response format for STORAGE_FILE_READ
+ * @data: beginning of data retrieved from file
+ */
+struct storage_file_read_resp {
+	uint8_t data[0];
+};
+
+/**
+ * struct storage_file_write_req - request format for STORAGE_FILE_WRITE
+ * @handle:     the handle for the file to write to
+ * @offset:     the offset in the file from whence to write
+ * @__reserved: unused, must be set to 0.
+ * @data:       beginning of the data to be written
+ */
+struct storage_file_write_req {
+	uint64_t offset;
+	uint32_t handle;
+	uint32_t __reserved;
+	uint8_t  data[0];
+};
+
+/**
+ * struct storage_file_get_size_req - request format for STORAGE_FILE_GET_SIZE
+ * @handle: handle for which the size is requested
+ */
+struct storage_file_get_size_req {
+	uint32_t handle;
+};
+
+/**
+ * struct storage_file_get_size_resp - response format for STORAGE_FILE_GET_SIZE
+ * @size:   the size of the file
+ */
+struct storage_file_get_size_resp {
+	uint64_t size;
+};
+
+/**
+ * struct storage_file_set_size_req - request format for STORAGE_FILE_SET_SIZE
+ * @handle: the file handle
+ * @size:   the desired size of the file
+ */
+struct storage_file_set_size_req {
+	uint64_t size;
+	uint32_t handle;
+};
+
+/**
+ * struct storage_rpmb_send_req - request format for STORAGE_RPMB_SEND
+ * @reliable_write_size:        size in bytes of reliable write region
+ * @write_size:                 size in bytes of write region
+ * @read_size:                  number of bytes to read for a read request
+ * @__reserved:                 unused, must be set to 0
+ * @payload:                    start of reliable write region, followed by
+ *                              write region.
+ *
+ * Only used in proxy<->server interface.
+ */
+struct storage_rpmb_send_req {
+	uint32_t reliable_write_size;
+	uint32_t write_size;
+	uint32_t read_size;
+	uint32_t __reserved;
+	uint8_t  payload[0];
+};
+
+/**
+ * struct storage_rpmb_send_resp: response type for STORAGE_RPMB_SEND
+ * @data: the data frames frames retrieved from the MMC.
+ */
+struct storage_rpmb_send_resp {
+	uint8_t data[0];
+};
+
+/**
+ * struct storage_msg - generic req/resp format for all storage commands
+ * @cmd:        one of enum storage_cmd
+ * @op_id:      client chosen operation identifier for an instance
+ *              of a command or atomic grouping of commands (transaction).
+ * @flags:      one or many of enum storage_msg_flag or'ed together.
+ * @size:       total size of the message including this header
+ * @result:     one of enum storage_err
+ * @__reserved: unused, must be set to 0.
+ * @payload:    beginning of command specific message format
+ */
+struct storage_msg {
+	uint32_t cmd;
+	uint32_t op_id;
+	uint32_t flags;
+	uint32_t size;
+	int32_t  result;
+	uint32_t __reserved;
+	uint8_t  payload[0];
+};
+
diff --git a/adf/libadfhwc/Android.mk b/trusty/storage/lib/Android.mk
similarity index 69%
rename from adf/libadfhwc/Android.mk
rename to trusty/storage/lib/Android.mk
index 898f9c9..7e0fc9d 100644
--- a/adf/libadfhwc/Android.mk
+++ b/trusty/storage/lib/Android.mk
@@ -1,4 +1,5 @@
-# Copyright (C) 2013 The Android Open Source Project
+#
+# 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.
@@ -11,15 +12,26 @@
 # 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.
+#
 
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES := adfhwc.cpp
-LOCAL_MODULE := libadfhwc
-LOCAL_MODULE_TAGS := optional
-LOCAL_STATIC_LIBRARIES := libadf liblog libutils
-LOCAL_CFLAGS += -DLOG_TAG=\"adfhwc\" -Werror
+
+LOCAL_MODULE := libtrustystorage
+
+LOCAL_SRC_FILES := \
+	storage.c \
+
+LOCAL_CLFAGS = -fvisibility=hidden -Wall -Werror
+
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+
+LOCAL_STATIC_LIBRARIES := \
+	liblog \
+	libtrusty \
+	libtrustystorageinterface
+
 include $(BUILD_STATIC_LIBRARY)
+
diff --git a/trusty/storage/lib/include/trusty/lib/storage.h b/trusty/storage/lib/include/trusty/lib/storage.h
new file mode 100644
index 0000000..b8ddf67
--- /dev/null
+++ b/trusty/storage/lib/include/trusty/lib/storage.h
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <trusty/interface/storage.h>
+
+#define STORAGE_MAX_NAME_LENGTH_BYTES 159
+
+__BEGIN_DECLS
+
+typedef uint32_t storage_session_t;
+typedef uint64_t file_handle_t;
+typedef uint64_t storage_off_t;
+
+#define STORAGE_INVALID_SESSION ((storage_session_t)-1)
+
+/**
+ * storage_ops_flags - storage related operation flags
+ * @STORAGE_OP_COMPLETE: forces to commit current transaction
+ */
+enum storage_ops_flags {
+    STORAGE_OP_COMPLETE = 0x1,
+};
+
+/**
+ * storage_open_session() - Opens a storage session.
+ * @device:    device node for talking with Trusty
+ * @session_p: pointer to location in which to store session handle
+ *             in case of success.
+ *
+ * Return: 0 on success, or an error code < 0 on failure.
+ */
+int storage_open_session(const char *device, storage_session_t *session_p, const char *port);
+
+/**
+ * storage_close_session() - Closes the session.
+ * @session: the session to close
+ */
+void storage_close_session(storage_session_t session);
+
+/**
+ * storage_open_file() - Opens a file
+ * @session:  the storage_session_t returned from a call to storage_open_session
+ * @handle_p: pointer to location in which to store file handle in case of success
+ * @name:     a null-terminated string identifier of the file to open.
+ *            Cannot be more than STORAGE_MAX_NAME_LENGTH_BYTES in length.
+ * @flags:    A bitmask consisting any storage_file_flag value or'ed together:
+ * - STORAGE_FILE_OPEN_CREATE:           if this file does not exist, create it.
+ * - STORAGE_FILE_OPEN_CREATE_EXCLUSIVE: when specified, opening file with
+ *                                       STORAGE_OPEN_FILE_CREATE flag will
+ *                                       fail if the file already exists.
+ *                                       Only meaningful if used in combination
+ *                                       with STORAGE_FILE_OPEN_CREATE flag.
+ * - STORAGE_FILE_OPEN_TRUNCATE: if this file already exists, discard existing
+ *                               content and open it as a new file. No change
+ *                               in semantics if the  file does not exist.
+ * @opflags: a combination of @storage_op_flags
+ *
+ * Return: 0 on success, or an error code < 0 on failure.
+ */
+int storage_open_file(storage_session_t session, file_handle_t *handle_p,
+                      const char *name, uint32_t flags, uint32_t opflags);
+
+/**
+ * storage_close_file() - Closes a file.
+ * @handle: the file_handle_t retrieved from storage_open_file
+ */
+void storage_close_file(file_handle_t handle);
+
+/**
+ * storage_delete_file - Deletes a file.
+ * @session: the storage_session_t returned from a call to storage_open_session
+ * @name: the name of the file to delete
+ * @opflags: a combination of @storage_op_flags
+ *
+ * Return: 0 on success, or an error code < 0 on failure.
+ */
+int storage_delete_file(storage_session_t session, const char *name,
+                        uint32_t opflags);
+
+/**
+ * storage_read() - Reads a file at a given offset.
+ * @handle: the file_handle_t retrieved from storage_open_file
+ * @off: the start offset from whence to read in the file
+ * @buf: the buffer in which to write the data read
+ * @size: the size of buf and number of bytes to read
+ *
+ * Return: the number of bytes read on success, negative error code on failure
+ */
+ssize_t storage_read(file_handle_t handle,
+                     storage_off_t off, void *buf, size_t size);
+
+/**
+ * storage_write() - Writes to a file at a given offset. Grows the file if necessary.
+ * @handle: the file_handle_t retrieved from storage_open_file
+ * @off: the start offset from whence to write in the file
+ * @buf: the buffer containing the data to write
+ * @size: the size of buf and number of bytes to write
+ * @opflags: a combination of @storage_op_flags
+ *
+ * Return: the number of bytes written on success, negative error code on failure
+ */
+ssize_t storage_write(file_handle_t handle,
+                      storage_off_t off, const void *buf, size_t size,
+                      uint32_t opflags);
+
+/**
+ * storage_set_file_size() - Sets the size of the file.
+ * @handle: the file_handle_t retrieved from storage_open_file
+ * @off: the number of bytes to set as the new size of the file
+ * @opflags: a combination of @storage_op_flags
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int storage_set_file_size(file_handle_t handle, storage_off_t file_size,
+                          uint32_t opflags);
+
+/**
+ * storage_get_file_size() - Gets the size of the file.
+ * @session: the storage_session_t returned from a call to storage_open_session
+ * @handle: the file_handle_t retrieved from storage_open_file
+ * @size: pointer to storage_off_t in which to store the file size
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int storage_get_file_size(file_handle_t handle, storage_off_t *size);
+
+
+/**
+ * storage_end_transaction: End current transaction
+ * @session: the storage_session_t returned from a call to storage_open_session
+ * @complete: if true, commit current transaction, discard it otherwise
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int storage_end_transaction(storage_session_t session, bool complete);
+
+
+__END_DECLS
diff --git a/trusty/storage/lib/storage.c b/trusty/storage/lib/storage.c
new file mode 100644
index 0000000..3002c0b
--- /dev/null
+++ b/trusty/storage/lib/storage.c
@@ -0,0 +1,311 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "trusty_storage_client"
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/uio.h>
+
+#include <android/log.h>
+#include <trusty/tipc.h>
+#include <trusty/lib/storage.h>
+
+#define MAX_CHUNK_SIZE 4040
+
+static inline file_handle_t make_file_handle(storage_session_t s, uint32_t fid)
+{
+    return ((uint64_t)s << 32) | fid;
+}
+
+static inline storage_session_t _to_session(file_handle_t fh)
+{
+    return (storage_session_t)(fh >> 32);
+}
+
+static inline uint32_t _to_handle(file_handle_t fh)
+{
+    return (uint32_t) fh;
+}
+
+static inline uint32_t _to_msg_flags(uint32_t opflags)
+{
+    uint32_t msg_flags = 0;
+
+    if (opflags & STORAGE_OP_COMPLETE)
+        msg_flags |= STORAGE_MSG_FLAG_TRANSACT_COMPLETE;
+
+    return msg_flags;
+}
+
+static ssize_t check_response(struct storage_msg *msg, ssize_t res)
+{
+    if (res < 0)
+        return res;
+
+    if ((size_t)res < sizeof(*msg)) {
+        ALOGE("invalid msg length (%zd < %zd)\n", res, sizeof(*msg));
+        return -EIO;
+    }
+
+    ALOGV("cmd 0x%x: server returned %u\n", msg->cmd, msg->result);
+
+    switch(msg->result) {
+        case STORAGE_NO_ERROR:
+            return res - sizeof(*msg);
+
+        case STORAGE_ERR_NOT_FOUND:
+            return -ENOENT;
+
+        case STORAGE_ERR_EXIST:
+            return -EEXIST;
+
+        case STORAGE_ERR_NOT_VALID:
+            return -EINVAL;
+
+        case STORAGE_ERR_UNIMPLEMENTED:
+            ALOGE("cmd 0x%x: is unhandles command\n", msg->cmd);
+            return -EINVAL;
+
+        case STORAGE_ERR_ACCESS:
+             return -EACCES;
+
+        case STORAGE_ERR_TRANSACT:
+             return -EBUSY;
+
+        case STORAGE_ERR_GENERIC:
+            ALOGE("cmd 0x%x: internal server error\n", msg->cmd);
+            return -EIO;
+
+        default:
+            ALOGE("cmd 0x%x: unhandled server response %u\n",
+                   msg->cmd, msg->result);
+    }
+
+    return -EIO;
+}
+
+static ssize_t send_reqv(storage_session_t session,
+                         const struct iovec *tx_iovs, uint tx_iovcnt,
+                         const struct iovec *rx_iovs, uint rx_iovcnt)
+{
+    ssize_t rc;
+
+    rc = writev(session, tx_iovs, tx_iovcnt);
+    if (rc < 0) {
+        rc = -errno;
+        ALOGE("failed to send request: %s\n", strerror(errno));
+        return rc;
+    }
+
+    rc = readv(session, rx_iovs, rx_iovcnt);
+    if (rc < 0) {
+        rc = -errno;
+        ALOGE("failed to recv response: %s\n", strerror(errno));
+        return rc;
+    }
+
+    return rc;
+}
+
+int storage_open_session(const char *device, storage_session_t *session_p,
+                         const char *port)
+{
+    int rc = tipc_connect(device, port);
+    if (rc < 0)
+        return rc;
+    *session_p = (storage_session_t) rc;
+    return 0;
+}
+
+void storage_close_session(storage_session_t session)
+{
+    tipc_close(session);
+}
+
+
+int storage_open_file(storage_session_t session, file_handle_t *handle_p, const char *name,
+                      uint32_t flags, uint32_t opflags)
+{
+    struct storage_msg msg = { .cmd = STORAGE_FILE_OPEN, .flags = _to_msg_flags(opflags)};
+    struct storage_file_open_req req = { .flags = flags };
+    struct iovec tx[3] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}, {(void *)name, strlen(name)}};
+    struct storage_file_open_resp rsp = { 0 };
+    struct iovec rx[2] = {{&msg, sizeof(msg)}, {&rsp, sizeof(rsp)}};
+
+    ssize_t rc = send_reqv(session, tx, 3, rx, 2);
+    rc = check_response(&msg, rc);
+    if (rc < 0)
+        return rc;
+
+    if ((size_t)rc != sizeof(rsp)) {
+        ALOGE("%s: invalid response length (%zd != %zd)\n", __func__, rc, sizeof(rsp));
+        return -EIO;
+    }
+
+    *handle_p = make_file_handle(session, rsp.handle);
+    return 0;
+}
+
+void storage_close_file(file_handle_t fh)
+{
+    struct storage_msg msg = { .cmd = STORAGE_FILE_CLOSE };
+    struct storage_file_close_req req = { .handle = _to_handle(fh)};
+    struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}};
+    struct iovec rx[1] = {{&msg, sizeof(msg)}};
+
+    ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 1);
+    rc = check_response(&msg, rc);
+    if (rc < 0) {
+        ALOGE("close file failed (%d)\n", (int)rc);
+    }
+}
+
+int storage_delete_file(storage_session_t session, const char *name, uint32_t opflags)
+{
+    struct storage_msg msg = { .cmd = STORAGE_FILE_DELETE, .flags = _to_msg_flags(opflags)};
+    struct storage_file_delete_req req = { .flags = 0, };
+    struct iovec tx[3] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}, {(void *)name, strlen(name)}};
+    struct iovec rx[1] = {{&msg, sizeof(msg)}};
+
+    ssize_t rc = send_reqv(session, tx, 3, rx, 1);
+    return check_response(&msg, rc);
+}
+
+static int _read_chunk(file_handle_t fh, storage_off_t off, void *buf, size_t size)
+{
+    struct storage_msg msg = { .cmd = STORAGE_FILE_READ };
+    struct storage_file_read_req req = { .handle = _to_handle(fh), .size = size, .offset = off };
+    struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}};
+    struct iovec rx[2] = {{&msg, sizeof(msg)}, {buf, size}};
+
+    ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 2);
+    return check_response(&msg, rc);
+}
+
+ssize_t storage_read(file_handle_t fh, storage_off_t off, void *buf, size_t size)
+{
+    int rc;
+    size_t bytes_read = 0;
+    size_t chunk = MAX_CHUNK_SIZE;
+    uint8_t *ptr = buf;
+
+    while (size) {
+        if (chunk > size)
+            chunk = size;
+        rc = _read_chunk(fh, off, ptr, chunk);
+        if (rc < 0)
+            return rc;
+        if (rc == 0)
+            break;
+        off += rc;
+        ptr += rc;
+        bytes_read += rc;
+        size -= rc;
+    }
+    return bytes_read;
+}
+
+static int _write_req(file_handle_t fh, storage_off_t off,
+                      const void *buf, size_t size, uint32_t msg_flags)
+{
+    struct storage_msg msg = { .cmd = STORAGE_FILE_WRITE, .flags = msg_flags, };
+    struct storage_file_write_req req = { .handle = _to_handle(fh), .offset = off, };
+    struct iovec tx[3] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}, {(void *)buf, size}};
+    struct iovec rx[1] = {{&msg, sizeof(msg)}};
+
+    ssize_t rc = send_reqv(_to_session(fh), tx, 3, rx, 1);
+    rc = check_response(&msg, rc);
+    return rc < 0 ? rc : size;
+}
+
+ssize_t storage_write(file_handle_t fh, storage_off_t off,
+                      const void *buf, size_t size, uint32_t opflags)
+{
+    int rc;
+    size_t bytes_written = 0;
+    size_t chunk = MAX_CHUNK_SIZE;
+    const uint8_t *ptr = buf;
+    uint32_t msg_flags = _to_msg_flags(opflags & ~STORAGE_OP_COMPLETE);
+
+    while (size) {
+        if (chunk >= size) {
+            /* last chunk in sequence */
+            chunk = size;
+            msg_flags = _to_msg_flags(opflags);
+        }
+        rc = _write_req(fh, off, ptr, chunk, msg_flags);
+        if (rc < 0)
+            return rc;
+        if ((size_t)rc != chunk) {
+            ALOGE("got partial write (%d)\n", (int)rc);
+            return -EIO;
+        }
+        off += chunk;
+        ptr += chunk;
+        bytes_written += chunk;
+        size -= chunk;
+    }
+    return bytes_written;
+}
+
+int storage_set_file_size(file_handle_t fh, storage_off_t file_size, uint32_t opflags)
+{
+    struct storage_msg msg = { .cmd = STORAGE_FILE_SET_SIZE, .flags = _to_msg_flags(opflags)};
+    struct storage_file_set_size_req req = { .handle = _to_handle(fh), .size = file_size, };
+    struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}};
+    struct iovec rx[1] = {{&msg, sizeof(msg)}};
+
+    ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 1);
+    return check_response(&msg, rc);
+}
+
+int storage_get_file_size(file_handle_t fh, storage_off_t *size_p)
+{
+    struct storage_msg msg = { .cmd = STORAGE_FILE_GET_SIZE };
+    struct storage_file_get_size_req  req = { .handle = _to_handle(fh), };
+    struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}};
+    struct storage_file_get_size_resp rsp;
+    struct iovec rx[2] = {{&msg, sizeof(msg)}, {&rsp, sizeof(rsp)}};
+
+    ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 2);
+    rc = check_response(&msg, rc);
+    if (rc < 0)
+        return rc;
+
+    if ((size_t)rc != sizeof(rsp)) {
+        ALOGE("%s: invalid response length (%zd != %zd)\n", __func__, rc, sizeof(rsp));
+        return -EIO;
+    }
+
+    *size_p = rsp.size;
+    return 0;
+}
+
+int storage_end_transaction(storage_session_t session, bool complete)
+{
+    struct storage_msg msg = {
+        .cmd = STORAGE_END_TRANSACTION,
+        .flags = complete ? STORAGE_MSG_FLAG_TRANSACT_COMPLETE : 0,
+    };
+    struct iovec iov = {&msg, sizeof(msg)};
+
+    ssize_t rc = send_reqv(session, &iov, 1, &iov, 1);
+    return check_response(&msg, rc);
+}
diff --git a/adf/libadf/Android.mk b/trusty/storage/proxy/Android.mk
similarity index 62%
copy from adf/libadf/Android.mk
copy to trusty/storage/proxy/Android.mk
index 7df354b..745e302 100644
--- a/adf/libadf/Android.mk
+++ b/trusty/storage/proxy/Android.mk
@@ -1,4 +1,5 @@
-# Copyright (C) 2013 The Android Open Source Project
+#
+# 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.
@@ -11,14 +12,30 @@
 # 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.
+#
 
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES := adf.c
-LOCAL_MODULE := libadf
-LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS += -Werror
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS)
-include $(BUILD_STATIC_LIBRARY)
+
+LOCAL_MODULE := storageproxyd
+
+LOCAL_C_INCLUDES += bionic/libc/kernel/uapi
+
+LOCAL_SRC_FILES := \
+	ipc.c \
+	rpmb.c \
+	storage.c \
+	proxy.c
+
+LOCAL_CLFAGS = -Wall -Werror
+
+LOCAL_SHARED_LIBRARIES := \
+	liblog \
+
+LOCAL_STATIC_LIBRARIES := \
+	libtrustystorageinterface \
+	libtrusty
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/trusty/storage/proxy/ipc.c b/trusty/storage/proxy/ipc.c
new file mode 100644
index 0000000..57cf600
--- /dev/null
+++ b/trusty/storage/proxy/ipc.c
@@ -0,0 +1,115 @@
+/*
+ * 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 <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+#include <trusty/tipc.h>
+
+#include "ipc.h"
+#include "log.h"
+
+#define MAX_RECONNECT_RETRY_COUNT 5
+#define TRUSTY_RECONNECT_TIMEOUT_SEC 5
+
+static int tipc_fd = -1;
+
+int ipc_connect(const char *device, const char *port)
+{
+    int rc;
+    uint retry_cnt = 0;
+
+    assert(tipc_fd == -1);
+
+    while(true) {
+        rc = tipc_connect(device, port);
+        if (rc >= 0)
+            break;
+
+        ALOGE("failed (%d) to connect to storage server\n", rc);
+        if (++retry_cnt > MAX_RECONNECT_RETRY_COUNT) {
+            ALOGE("max number of reconnect retries (%d) has been reached\n",
+                   retry_cnt);
+            return -1;
+        }
+        sleep(TRUSTY_RECONNECT_TIMEOUT_SEC);
+    }
+    tipc_fd = rc;
+    return 0;
+}
+
+void ipc_disconnect(void)
+{
+    assert(tipc_fd >=  0);
+
+    tipc_close(tipc_fd);
+    tipc_fd = -1;
+}
+
+ssize_t ipc_get_msg(struct storage_msg *msg, void *req_buf, size_t req_buf_len)
+{
+    ssize_t rc;
+    struct iovec iovs[2] = {{msg, sizeof(*msg)}, {req_buf, req_buf_len}};
+
+    assert(tipc_fd >=  0);
+
+    rc = readv(tipc_fd, iovs, 2);
+    if (rc < 0) {
+        ALOGE("failed to read request: %s\n", strerror(errno));
+        return rc;
+    }
+
+   /* check for minimum size */
+   if ((size_t)rc < sizeof(*msg)) {
+       ALOGE("message is too short (%zu bytes received)\n", rc);
+       return -1;
+   }
+
+   /* check for message completeness */
+   if (msg->size != (uint32_t)rc) {
+       ALOGE("inconsistent message size [cmd=%d] (%u != %u)\n",
+             msg->cmd, msg->size, (uint32_t)rc);
+       return -1;
+   }
+
+   return rc - sizeof(*msg);
+}
+
+int ipc_respond(struct storage_msg *msg, void *out, size_t out_size)
+{
+    ssize_t rc;
+    struct iovec iovs[2] = {{msg, sizeof(*msg)}, {out, out_size}};
+
+    assert(tipc_fd >=  0);
+
+    msg->cmd |= STORAGE_RESP_BIT;
+
+    rc = writev(tipc_fd, iovs, out ? 2 : 1);
+    if (rc < 0) {
+        ALOGE("error sending response 0x%x: %s\n",
+              msg->cmd, strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
+
+
diff --git a/crash_reporter/warn_collector_test.c b/trusty/storage/proxy/ipc.h
similarity index 60%
copy from crash_reporter/warn_collector_test.c
copy to trusty/storage/proxy/ipc.h
index 7ebe0a8..2e366bb 100644
--- a/crash_reporter/warn_collector_test.c
+++ b/trusty/storage/proxy/ipc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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.
@@ -13,13 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
-/*
- * Test driver for the warn_collector daemon.
- */
-#include <stdlib.h>
+#include <stdint.h>
+#include <trusty/interface/storage.h>
 
-int main(int ac, char **av) {
-  int status = system("exec \"${SRC}\"/warn_collector_test.sh");
-  return status < 0 ? EXIT_FAILURE : WEXITSTATUS(status);
-}
+int ipc_connect(const char *device, const char *service_name);
+void ipc_disconnect(void);
+ssize_t ipc_get_msg(struct storage_msg *msg, void *req_buf, size_t req_buf_len);
+int ipc_respond(struct storage_msg *msg, void *out, size_t out_size);
diff --git a/metricsd/aidl/android/brillo/metrics/IMetricsCollectorService.aidl b/trusty/storage/proxy/log.h
similarity index 77%
rename from metricsd/aidl/android/brillo/metrics/IMetricsCollectorService.aidl
rename to trusty/storage/proxy/log.h
index 49f484f..3d2e654 100644
--- a/metricsd/aidl/android/brillo/metrics/IMetricsCollectorService.aidl
+++ b/trusty/storage/proxy/log.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-package android.brillo.metrics;
+#define LOG_TAG "storageproxyd"
 
-interface IMetricsCollectorService {
-  oneway void notifyUserCrash();
-}
+#include <android/log.h>
+
diff --git a/trusty/storage/proxy/proxy.c b/trusty/storage/proxy/proxy.c
new file mode 100644
index 0000000..d645ac0
--- /dev/null
+++ b/trusty/storage/proxy/proxy.c
@@ -0,0 +1,264 @@
+/*
+ * 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 <errno.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <private/android_filesystem_config.h>
+
+#include "ipc.h"
+#include "log.h"
+#include "rpmb.h"
+#include "storage.h"
+
+#define REQ_BUFFER_SIZE 4096
+static uint8_t req_buffer[REQ_BUFFER_SIZE + 1];
+
+static const char *ss_data_root;
+static const char *trusty_devname;
+static const char *rpmb_devname;
+static const char *ss_srv_name = STORAGE_DISK_PROXY_PORT;
+
+static const char *_sopts = "hp:d:r:";
+static const struct option _lopts[] =  {
+    {"help",       no_argument,       NULL, 'h'},
+    {"trusty_dev", required_argument, NULL, 'd'},
+    {"data_path",  required_argument, NULL, 'p'},
+    {"rpmb_dev",   required_argument, NULL, 'r'},
+    {0, 0, 0, 0}
+};
+
+static void show_usage_and_exit(int code)
+{
+    ALOGE("usage: storageproxyd -d <trusty_dev> -p <data_path> -r <rpmb_dev>\n");
+    exit(code);
+}
+
+static int drop_privs(void)
+{
+    struct __user_cap_header_struct capheader;
+    struct __user_cap_data_struct capdata[2];
+
+    if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) {
+        return -1;
+    }
+
+    /*
+     * ensure we're running as the system user
+     */
+    if (setgid(AID_SYSTEM) != 0) {
+        return -1;
+    }
+
+    if (setuid(AID_SYSTEM) != 0) {
+        return -1;
+    }
+
+    /*
+     * drop all capabilities except SYS_RAWIO
+     */
+    memset(&capheader, 0, sizeof(capheader));
+    memset(&capdata, 0, sizeof(capdata));
+    capheader.version = _LINUX_CAPABILITY_VERSION_3;
+    capheader.pid = 0;
+
+    capdata[CAP_TO_INDEX(CAP_SYS_RAWIO)].permitted = CAP_TO_MASK(CAP_SYS_RAWIO);
+    capdata[CAP_TO_INDEX(CAP_SYS_RAWIO)].effective = CAP_TO_MASK(CAP_SYS_RAWIO);
+
+    if (capset(&capheader, &capdata[0]) < 0) {
+        return -1;
+    }
+
+    /* no-execute for user, no access for group and other */
+    umask(S_IXUSR | S_IRWXG | S_IRWXO);
+
+    return 0;
+}
+
+static int handle_req(struct storage_msg *msg, const void *req, size_t req_len)
+{
+    int rc;
+
+    if ((msg->flags & STORAGE_MSG_FLAG_POST_COMMIT) &&
+        (msg->cmd != STORAGE_RPMB_SEND)) {
+        /*
+         * handling post commit messages on non rpmb commands are not
+         * implemented as there is no use case for this yet.
+         */
+        ALOGE("cmd 0x%x: post commit option is not implemented\n", msg->cmd);
+        msg->result = STORAGE_ERR_UNIMPLEMENTED;
+        return ipc_respond(msg, NULL, 0);
+    }
+
+    if (msg->flags & STORAGE_MSG_FLAG_PRE_COMMIT) {
+        rc = storage_sync_checkpoint();
+        if (rc < 0) {
+            msg->result = STORAGE_ERR_GENERIC;
+            return ipc_respond(msg, NULL, 0);
+        }
+    }
+
+    switch (msg->cmd) {
+    case STORAGE_FILE_DELETE:
+        rc = storage_file_delete(msg, req, req_len);
+        break;
+
+    case STORAGE_FILE_OPEN:
+        rc = storage_file_open(msg, req, req_len);
+        break;
+
+    case STORAGE_FILE_CLOSE:
+        rc = storage_file_close(msg, req, req_len);
+        break;
+
+    case STORAGE_FILE_WRITE:
+        rc = storage_file_write(msg, req, req_len);
+        break;
+
+    case STORAGE_FILE_READ:
+        rc = storage_file_read(msg, req, req_len);
+        break;
+
+    case STORAGE_FILE_GET_SIZE:
+        rc = storage_file_get_size(msg, req, req_len);
+        break;
+
+    case STORAGE_FILE_SET_SIZE:
+        rc = storage_file_set_size(msg, req, req_len);
+        break;
+
+    case STORAGE_RPMB_SEND:
+        rc = rpmb_send(msg, req, req_len);
+        break;
+
+    default:
+        ALOGE("unhandled command 0x%x\n", msg->cmd);
+        msg->result = STORAGE_ERR_UNIMPLEMENTED;
+        rc = 1;
+    }
+
+    if (rc > 0) {
+        /* still need to send response */
+        rc = ipc_respond(msg, NULL, 0);
+    }
+    return rc;
+}
+
+static int proxy_loop(void)
+{
+    ssize_t rc;
+    struct storage_msg msg;
+
+    /* enter main message handling loop */
+    while (true) {
+
+        /* get incoming message */
+        rc = ipc_get_msg(&msg, req_buffer, REQ_BUFFER_SIZE);
+        if (rc < 0)
+            return rc;
+
+        /* handle request */
+        req_buffer[rc] = 0; /* force zero termination */
+        rc = handle_req(&msg, req_buffer, rc);
+        if (rc)
+            return rc;
+    }
+
+    return 0;
+}
+
+static void parse_args(int argc, char *argv[])
+{
+    int opt;
+    int oidx = 0;
+
+    while ((opt = getopt_long(argc, argv, _sopts, _lopts, &oidx)) != -1) {
+        switch (opt) {
+
+        case 'd':
+            trusty_devname = strdup(optarg);
+            break;
+
+        case 'p':
+            ss_data_root = strdup(optarg);
+            break;
+
+        case 'r':
+            rpmb_devname = strdup(optarg);
+            break;
+
+        default:
+            ALOGE("unrecognized option (%c):\n", opt);
+            show_usage_and_exit(EXIT_FAILURE);
+        }
+    }
+
+    if (ss_data_root == NULL ||
+        trusty_devname == NULL ||
+        rpmb_devname == NULL) {
+        ALOGE("missing required argument(s)\n");
+        show_usage_and_exit(EXIT_FAILURE);
+    }
+
+    ALOGI("starting storageproxyd\n");
+    ALOGI("storage data root: %s\n", ss_data_root);
+    ALOGI("trusty dev: %s\n", trusty_devname);
+    ALOGI("rpmb dev: %s\n", rpmb_devname);
+}
+
+int main(int argc, char *argv[])
+{
+    int rc;
+    uint retry_cnt;
+
+    /* drop privileges */
+    if (drop_privs() < 0)
+        return EXIT_FAILURE;
+
+    /* parse arguments */
+    parse_args(argc, argv);
+
+    /* initialize secure storage directory */
+    rc = storage_init(ss_data_root);
+    if (rc < 0)
+        return EXIT_FAILURE;
+
+    /* open rpmb device */
+    rc = rpmb_open(rpmb_devname);
+    if (rc < 0)
+        return EXIT_FAILURE;
+
+    /* connect to Trusty secure storage server */
+    rc = ipc_connect(trusty_devname, ss_srv_name);
+    if (rc < 0)
+        return EXIT_FAILURE;
+
+    /* enter main loop */
+    rc = proxy_loop();
+    ALOGE("exiting proxy loop with status (%d)\n", rc);
+
+    ipc_disconnect();
+    rpmb_close();
+
+    return (rc < 0) ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/trusty/storage/proxy/rpmb.c b/trusty/storage/proxy/rpmb.c
new file mode 100644
index 0000000..9c79105
--- /dev/null
+++ b/trusty/storage/proxy/rpmb.c
@@ -0,0 +1,211 @@
+/*
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include <linux/major.h>
+#include <linux/mmc/ioctl.h>
+
+#include "ipc.h"
+#include "log.h"
+#include "rpmb.h"
+#include "storage.h"
+
+#define MMC_READ_MULTIPLE_BLOCK 18
+#define MMC_WRITE_MULTIPLE_BLOCK 25
+#define MMC_RELIABLE_WRITE_FLAG (1 << 31)
+
+#define MMC_RSP_PRESENT (1 << 0)
+#define MMC_RSP_CRC (1 << 2)
+#define MMC_RSP_OPCODE (1 << 4)
+#define MMC_CMD_ADTC (1 << 5)
+#define MMC_RSP_SPI_S1 (1 << 7)
+#define MMC_RSP_R1 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
+#define MMC_RSP_SPI_R1 (MMC_RSP_SPI_S1)
+
+#define MMC_WRITE_FLAG_R 0
+#define MMC_WRITE_FLAG_W 1
+#define MMC_WRITE_FLAG_RELW (MMC_WRITE_FLAG_W | MMC_RELIABLE_WRITE_FLAG)
+
+#define MMC_BLOCK_SIZE 512
+
+static int rpmb_fd = -1;
+static uint8_t read_buf[4096];
+
+#ifdef RPMB_DEBUG
+
+static void print_buf(const char *prefix, const uint8_t *buf, size_t size)
+{
+    size_t i;
+
+    printf("%s @%p [%zu]", prefix, buf, size);
+    for (i = 0; i < size; i++) {
+        if (i && i % 32 == 0)
+            printf("\n%*s", (int) strlen(prefix), "");
+        printf(" %02x", buf[i]);
+    }
+    printf("\n");
+    fflush(stdout);
+}
+
+#endif
+
+
+int rpmb_send(struct storage_msg *msg, const void *r, size_t req_len)
+{
+    int rc;
+    struct {
+        struct mmc_ioc_multi_cmd multi;
+        struct mmc_ioc_cmd cmd_buf[3];
+    } mmc = {};
+    struct mmc_ioc_cmd *cmd = mmc.multi.cmds;
+    const struct storage_rpmb_send_req *req = r;
+
+    if (req_len < sizeof(*req)) {
+        ALOGW("malformed rpmb request: invalid length (%zu < %zu)\n",
+              req_len, sizeof(*req));
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    size_t expected_len =
+            sizeof(*req) + req->reliable_write_size + req->write_size;
+    if (req_len != expected_len) {
+        ALOGW("malformed rpmb request: invalid length (%zu != %zu)\n",
+              req_len, expected_len);
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    const uint8_t *write_buf = req->payload;
+    if (req->reliable_write_size) {
+        if ((req->reliable_write_size % MMC_BLOCK_SIZE) != 0) {
+            ALOGW("invalid reliable write size %u\n", req->reliable_write_size);
+            msg->result = STORAGE_ERR_NOT_VALID;
+            goto err_response;
+        }
+
+        cmd->write_flag = MMC_WRITE_FLAG_RELW;
+        cmd->opcode = MMC_WRITE_MULTIPLE_BLOCK;
+        cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+        cmd->blksz = MMC_BLOCK_SIZE;
+        cmd->blocks = req->reliable_write_size / MMC_BLOCK_SIZE;
+        mmc_ioc_cmd_set_data((*cmd), write_buf);
+#ifdef RPMB_DEBUG
+        ALOGI("opcode: 0x%x, write_flag: 0x%x\n", cmd->opcode, cmd->write_flag);
+        print_buf("request: ", write_buf, req->reliable_write_size);
+#endif
+        write_buf += req->reliable_write_size;
+        mmc.multi.num_of_cmds++;
+        cmd++;
+    }
+
+    if (req->write_size) {
+        if ((req->write_size % MMC_BLOCK_SIZE) != 0) {
+            ALOGW("invalid write size %u\n", req->write_size);
+            msg->result = STORAGE_ERR_NOT_VALID;
+            goto err_response;
+        }
+
+        cmd->write_flag = MMC_WRITE_FLAG_W;
+        cmd->opcode = MMC_WRITE_MULTIPLE_BLOCK;
+        cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+        cmd->blksz = MMC_BLOCK_SIZE;
+        cmd->blocks = req->write_size / MMC_BLOCK_SIZE;
+        mmc_ioc_cmd_set_data((*cmd), write_buf);
+#ifdef RPMB_DEBUG
+        ALOGI("opcode: 0x%x, write_flag: 0x%x\n", cmd->opcode, cmd->write_flag);
+        print_buf("request: ", write_buf, req->write_size);
+#endif
+        write_buf += req->write_size;
+        mmc.multi.num_of_cmds++;
+        cmd++;
+    }
+
+    if (req->read_size) {
+        if (req->read_size % MMC_BLOCK_SIZE != 0 ||
+            req->read_size > sizeof(read_buf)) {
+            ALOGE("%s: invalid read size %u\n", __func__, req->read_size);
+            msg->result = STORAGE_ERR_NOT_VALID;
+            goto err_response;
+        }
+
+        cmd->write_flag = MMC_WRITE_FLAG_R;
+        cmd->opcode = MMC_READ_MULTIPLE_BLOCK;
+        cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC,
+        cmd->blksz = MMC_BLOCK_SIZE;
+        cmd->blocks = req->read_size / MMC_BLOCK_SIZE;
+        mmc_ioc_cmd_set_data((*cmd), read_buf);
+#ifdef RPMB_DEBUG
+        ALOGI("opcode: 0x%x, write_flag: 0x%x\n", cmd->opcode, cmd->write_flag);
+#endif
+        mmc.multi.num_of_cmds++;
+        cmd++;
+    }
+
+    rc = ioctl(rpmb_fd, MMC_IOC_MULTI_CMD, &mmc.multi);
+    if (rc < 0) {
+        ALOGE("%s: mmc ioctl failed: %d, %s\n", __func__, rc, strerror(errno));
+        msg->result = STORAGE_ERR_GENERIC;
+        goto err_response;
+    }
+#ifdef RPMB_DEBUG
+    if (req->read_size)
+        print_buf("response: ", read_buf, req->read_size);
+#endif
+
+    if (msg->flags & STORAGE_MSG_FLAG_POST_COMMIT) {
+        /*
+         * Nothing todo for post msg commit request as MMC_IOC_MULTI_CMD
+         * is fully synchronous in this implementation.
+         */
+    }
+
+    msg->result = STORAGE_NO_ERROR;
+    return ipc_respond(msg, read_buf, req->read_size);
+
+err_response:
+    return ipc_respond(msg, NULL, 0);
+}
+
+
+int rpmb_open(const char *rpmb_devname)
+{
+    int rc;
+
+    rc = open(rpmb_devname, O_RDWR, 0);
+    if (rc < 0) {
+        ALOGE("unable (%d) to open rpmb device '%s': %s\n",
+              errno, rpmb_devname, strerror(errno));
+        return rc;
+    }
+    rpmb_fd = rc;
+    return 0;
+}
+
+void rpmb_close(void)
+{
+    close(rpmb_fd);
+    rpmb_fd = -1;
+}
+
diff --git a/metricsd/aidl/android/brillo/metrics/IMetricsCollectorService.aidl b/trusty/storage/proxy/rpmb.h
similarity index 67%
copy from metricsd/aidl/android/brillo/metrics/IMetricsCollectorService.aidl
copy to trusty/storage/proxy/rpmb.h
index 49f484f..85cff44 100644
--- a/metricsd/aidl/android/brillo/metrics/IMetricsCollectorService.aidl
+++ b/trusty/storage/proxy/rpmb.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -13,9 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
-package android.brillo.metrics;
+#include <stdint.h>
+#include <trusty/interface/storage.h>
 
-interface IMetricsCollectorService {
-  oneway void notifyUserCrash();
-}
+int rpmb_open(const char *rpmb_devname);
+int rpmb_send(struct storage_msg *msg, const void *r, size_t req_len);
+void rpmb_close(void);
diff --git a/trusty/storage/proxy/storage.c b/trusty/storage/proxy/storage.c
new file mode 100644
index 0000000..c61e89d
--- /dev/null
+++ b/trusty/storage/proxy/storage.c
@@ -0,0 +1,529 @@
+/*
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "log.h"
+#include "ipc.h"
+#include "storage.h"
+
+#define FD_TBL_SIZE 64
+#define MAX_READ_SIZE 4096
+
+enum sync_state {
+    SS_UNUSED = -1,
+    SS_CLEAN =  0,
+    SS_DIRTY =  1,
+};
+
+static int ssdir_fd = -1;
+static const char *ssdir_name;
+
+static enum sync_state fs_state;
+static enum sync_state dir_state;
+static enum sync_state fd_state[FD_TBL_SIZE];
+
+static struct {
+   struct storage_file_read_resp hdr;
+   uint8_t data[MAX_READ_SIZE];
+}  read_rsp;
+
+static uint32_t insert_fd(int open_flags, int fd)
+{
+    uint32_t handle = fd;
+
+    if (open_flags & O_CREAT) {
+        dir_state = SS_DIRTY;
+    }
+
+    if (handle < FD_TBL_SIZE) {
+            fd_state[fd] = SS_CLEAN; /* fd clean */
+            if (open_flags & O_TRUNC) {
+                fd_state[fd] = SS_DIRTY;  /* set fd dirty */
+            }
+    } else {
+            ALOGW("%s: untracked fd %u\n", __func__, fd);
+            if (open_flags & (O_TRUNC | O_CREAT)) {
+                fs_state = SS_DIRTY;
+            }
+    }
+    return handle;
+}
+
+static int lookup_fd(uint32_t handle, bool dirty)
+{
+    if (dirty) {
+        if (handle < FD_TBL_SIZE) {
+            fd_state[handle] = SS_DIRTY;
+        } else {
+            fs_state = SS_DIRTY;
+        }
+    }
+    return handle;
+}
+
+static int remove_fd(uint32_t handle)
+{
+    if (handle < FD_TBL_SIZE) {
+        fd_state[handle] = SS_UNUSED; /* set to uninstalled */
+    }
+    return handle;
+}
+
+static enum storage_err translate_errno(int error)
+{
+    enum storage_err result;
+    switch (error) {
+    case 0:
+        result = STORAGE_NO_ERROR;
+        break;
+    case EBADF:
+    case EINVAL:
+    case ENOTDIR:
+    case EISDIR:
+    case ENAMETOOLONG:
+        result = STORAGE_ERR_NOT_VALID;
+        break;
+    case ENOENT:
+        result = STORAGE_ERR_NOT_FOUND;
+        break;
+    case EEXIST:
+        result = STORAGE_ERR_EXIST;
+        break;
+    case EPERM:
+    case EACCES:
+        result = STORAGE_ERR_ACCESS;
+        break;
+    default:
+        result = STORAGE_ERR_GENERIC;
+        break;
+    }
+
+    return result;
+}
+
+static ssize_t write_with_retry(int fd, const void *buf_, size_t size, off_t offset)
+{
+    ssize_t rc;
+    const uint8_t *buf = buf_;
+
+    while (size > 0) {
+        rc = TEMP_FAILURE_RETRY(pwrite(fd, buf, size, offset));
+        if (rc < 0)
+            return rc;
+        size -= rc;
+        buf += rc;
+        offset += rc;
+    }
+    return 0;
+}
+
+static ssize_t read_with_retry(int fd, void *buf_, size_t size, off_t offset)
+{
+    ssize_t rc;
+    size_t  rcnt = 0;
+    uint8_t *buf = buf_;
+
+    while (size > 0) {
+        rc = TEMP_FAILURE_RETRY(pread(fd, buf, size, offset));
+        if (rc < 0)
+            return rc;
+        if (rc == 0)
+            break;
+        size -= rc;
+        buf += rc;
+        offset += rc;
+        rcnt += rc;
+    }
+    return rcnt;
+}
+
+int storage_file_delete(struct storage_msg *msg,
+                        const void *r, size_t req_len)
+{
+    char *path = NULL;
+    const struct storage_file_delete_req *req = r;
+
+    if (req_len < sizeof(*req)) {
+        ALOGE("%s: invalid request length (%zd < %zd)\n",
+              __func__, req_len, sizeof(*req));
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    size_t fname_len = strlen(req->name);
+    if (fname_len != req_len - sizeof(*req)) {
+        ALOGE("%s: invalid filename length (%zd != %zd)\n",
+              __func__, fname_len, req_len - sizeof(*req));
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    int rc = asprintf(&path, "%s/%s", ssdir_name, req->name);
+    if (rc < 0) {
+        ALOGE("%s: asprintf failed\n", __func__);
+        msg->result = STORAGE_ERR_GENERIC;
+        goto err_response;
+    }
+
+    dir_state = SS_DIRTY;
+    rc = unlink(path);
+    if (rc < 0) {
+        rc = errno;
+        if (errno == ENOENT) {
+            ALOGV("%s: error (%d) unlinking file '%s'\n",
+                  __func__, rc, path);
+        } else {
+            ALOGE("%s: error (%d) unlinking file '%s'\n",
+                  __func__, rc, path);
+        }
+        msg->result = translate_errno(rc);
+        goto err_response;
+    }
+
+    ALOGV("%s: \"%s\"\n", __func__, path);
+    msg->result = STORAGE_NO_ERROR;
+
+err_response:
+    if (path)
+        free(path);
+    return ipc_respond(msg, NULL, 0);
+}
+
+
+int storage_file_open(struct storage_msg *msg,
+                      const void *r, size_t req_len)
+{
+    char *path = NULL;
+    const struct storage_file_open_req *req = r;
+    struct storage_file_open_resp resp = {0};
+
+    if (req_len < sizeof(*req)) {
+        ALOGE("%s: invalid request length (%zd < %zd)\n",
+               __func__, req_len, sizeof(*req));
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    size_t fname_len = strlen(req->name);
+    if (fname_len != req_len - sizeof(*req)) {
+        ALOGE("%s: invalid filename length (%zd != %zd)\n",
+              __func__, fname_len, req_len - sizeof(*req));
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    int rc = asprintf(&path, "%s/%s", ssdir_name, req->name);
+    if (rc < 0) {
+        ALOGE("%s: asprintf failed\n", __func__);
+        msg->result = STORAGE_ERR_GENERIC;
+        goto err_response;
+    }
+
+    int open_flags = O_RDWR;
+
+    if (req->flags & STORAGE_FILE_OPEN_TRUNCATE)
+        open_flags |= O_TRUNC;
+
+    if (req->flags & STORAGE_FILE_OPEN_CREATE) {
+        /* open or create */
+        if (req->flags & STORAGE_FILE_OPEN_CREATE_EXCLUSIVE) {
+            /* create exclusive */
+            open_flags |= O_CREAT | O_EXCL;
+            rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
+        } else {
+            /* try open first */
+            rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
+            if (rc == -1 && errno == ENOENT) {
+                /* then try open with O_CREATE */
+                open_flags |= O_CREAT;
+                rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
+            }
+
+        }
+    } else {
+        /* open an existing file */
+        rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
+    }
+
+    if (rc < 0) {
+        rc = errno;
+        if (errno == EEXIST || errno == ENOENT) {
+            ALOGV("%s: failed to open file \"%s\": %s\n",
+                  __func__, path, strerror(errno));
+        } else {
+            ALOGE("%s: failed to open file \"%s\": %s\n",
+                  __func__, path, strerror(errno));
+        }
+        msg->result = translate_errno(rc);
+        goto err_response;
+    }
+    free(path);
+
+    /* at this point rc contains storage file fd */
+    msg->result = STORAGE_NO_ERROR;
+    resp.handle = insert_fd(open_flags, rc);
+    ALOGV("%s: \"%s\": fd = %u: handle = %d\n",
+          __func__, path, rc, resp.handle);
+
+    return ipc_respond(msg, &resp, sizeof(resp));
+
+err_response:
+    if (path)
+        free(path);
+    return ipc_respond(msg, NULL, 0);
+}
+
+int storage_file_close(struct storage_msg *msg,
+                       const void *r, size_t req_len)
+{
+    const struct storage_file_close_req *req = r;
+
+    if (req_len != sizeof(*req)) {
+        ALOGE("%s: invalid request length (%zd != %zd)\n",
+              __func__, req_len, sizeof(*req));
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    int fd = remove_fd(req->handle);
+    ALOGV("%s: handle = %u: fd = %u\n", __func__, req->handle, fd);
+
+    int rc = fsync(fd);
+    if (rc < 0) {
+        rc = errno;
+        ALOGE("%s: fsync failed for fd=%u: %s\n",
+              __func__, fd, strerror(errno));
+        msg->result = translate_errno(rc);
+        goto err_response;
+    }
+
+    rc = close(fd);
+    if (rc < 0) {
+        rc = errno;
+        ALOGE("%s: close failed for fd=%u: %s\n",
+              __func__, fd, strerror(errno));
+        msg->result = translate_errno(rc);
+        goto err_response;
+    }
+
+    msg->result = STORAGE_NO_ERROR;
+
+err_response:
+    return ipc_respond(msg, NULL, 0);
+}
+
+
+int storage_file_write(struct storage_msg *msg,
+                       const void *r, size_t req_len)
+{
+    int rc;
+    const struct storage_file_write_req *req = r;
+
+    if (req_len < sizeof(*req)) {
+        ALOGE("%s: invalid request length (%zd < %zd)\n",
+              __func__, req_len, sizeof(*req));
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    int fd = lookup_fd(req->handle, true);
+    if (write_with_retry(fd, &req->data[0], req_len - sizeof(*req),
+                         req->offset) < 0) {
+        rc = errno;
+        ALOGW("%s: error writing file (fd=%d): %s\n",
+              __func__, fd, strerror(errno));
+        msg->result = translate_errno(rc);
+        goto err_response;
+    }
+
+    msg->result = STORAGE_NO_ERROR;
+
+err_response:
+    return ipc_respond(msg, NULL, 0);
+}
+
+
+int storage_file_read(struct storage_msg *msg,
+                      const void *r, size_t req_len)
+{
+    int rc;
+    const struct storage_file_read_req *req = r;
+
+    if (req_len != sizeof(*req)) {
+        ALOGE("%s: invalid request length (%zd != %zd)\n",
+              __func__, req_len, sizeof(*req));
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    if (req->size > MAX_READ_SIZE) {
+        ALOGW("%s: request is too large (%zd > %zd) - refusing\n",
+              __func__, req->size, MAX_READ_SIZE);
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    int fd = lookup_fd(req->handle, false);
+    ssize_t read_res = read_with_retry(fd, read_rsp.hdr.data, req->size,
+                                       (off_t)req->offset);
+    if (read_res < 0) {
+        rc = errno;
+        ALOGW("%s: error reading file (fd=%d): %s\n",
+              __func__, fd, strerror(errno));
+        msg->result = translate_errno(rc);
+        goto err_response;
+    }
+
+    msg->result = STORAGE_NO_ERROR;
+    return ipc_respond(msg, &read_rsp, read_res + sizeof(read_rsp.hdr));
+
+err_response:
+    return ipc_respond(msg, NULL, 0);
+}
+
+
+int storage_file_get_size(struct storage_msg *msg,
+                          const void *r, size_t req_len)
+{
+    const struct storage_file_get_size_req *req = r;
+    struct storage_file_get_size_resp resp = {0};
+
+    if (req_len != sizeof(*req)) {
+        ALOGE("%s: invalid request length (%zd != %zd)\n",
+              __func__, req_len, sizeof(*req));
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    struct stat stat;
+    int fd = lookup_fd(req->handle, false);
+    int rc = fstat(fd, &stat);
+    if (rc < 0) {
+        rc = errno;
+        ALOGE("%s: error stat'ing file (fd=%d): %s\n",
+              __func__, fd, strerror(errno));
+        msg->result = translate_errno(rc);
+        goto err_response;
+    }
+
+    resp.size = stat.st_size;
+    msg->result = STORAGE_NO_ERROR;
+    return ipc_respond(msg, &resp, sizeof(resp));
+
+err_response:
+    return ipc_respond(msg, NULL, 0);
+}
+
+
+int storage_file_set_size(struct storage_msg *msg,
+                          const void *r, size_t req_len)
+{
+    const struct storage_file_set_size_req *req = r;
+
+    if (req_len != sizeof(*req)) {
+        ALOGE("%s: invalid request length (%zd != %zd)\n",
+              __func__, req_len, sizeof(*req));
+        msg->result = STORAGE_ERR_NOT_VALID;
+        goto err_response;
+    }
+
+    int fd = lookup_fd(req->handle, true);
+    int rc = TEMP_FAILURE_RETRY(ftruncate(fd, req->size));
+    if (rc < 0) {
+        rc = errno;
+        ALOGE("%s: error truncating file (fd=%d): %s\n",
+              __func__, fd, strerror(errno));
+        msg->result = translate_errno(rc);
+        goto err_response;
+    }
+
+    msg->result = STORAGE_NO_ERROR;
+
+err_response:
+    return ipc_respond(msg, NULL, 0);
+}
+
+int storage_init(const char *dirname)
+{
+    fs_state = SS_CLEAN;
+    dir_state = SS_CLEAN;
+    for (uint i = 0; i < FD_TBL_SIZE; i++) {
+        fd_state[i] = SS_UNUSED;  /* uninstalled */
+    }
+
+    ssdir_fd = open(dirname, O_RDONLY);
+    if (ssdir_fd < 0) {
+        ALOGE("failed to open ss root dir \"%s\": %s\n",
+               dirname, strerror(errno));
+        return -1;
+    }
+    ssdir_name = dirname;
+    return 0;
+}
+
+int storage_sync_checkpoint(void)
+{
+    int rc;
+
+    /* sync fd table and reset it to clean state first */
+    for (uint fd = 0; fd < FD_TBL_SIZE; fd++) {
+         if (fd_state[fd] == SS_DIRTY) {
+             if (fs_state == SS_CLEAN) {
+                 /* need to sync individual fd */
+                 rc = fsync(fd);
+                 if (rc < 0) {
+                     ALOGE("fsync for fd=%d failed: %s\n", fd, strerror(errno));
+                     return rc;
+                 }
+             }
+             fd_state[fd] = SS_CLEAN; /* set to clean */
+         }
+    }
+
+    /* check if we need to sync the directory */
+    if (dir_state == SS_DIRTY) {
+        if (fs_state == SS_CLEAN) {
+            rc = fsync(ssdir_fd);
+            if (rc < 0) {
+                ALOGE("fsync for ssdir failed: %s\n", strerror(errno));
+                return rc;
+            }
+        }
+        dir_state = SS_CLEAN;  /* set to clean */
+    }
+
+    /* check if we need to sync the whole fs */
+    if (fs_state == SS_DIRTY) {
+        rc = syscall(SYS_syncfs, ssdir_fd);
+        if (rc < 0) {
+            ALOGE("syncfs failed: %s\n", strerror(errno));
+            return rc;
+        }
+        fs_state = SS_CLEAN;
+    }
+
+    return 0;
+}
+
diff --git a/trusty/storage/proxy/storage.h b/trusty/storage/proxy/storage.h
new file mode 100644
index 0000000..5a670d4
--- /dev/null
+++ b/trusty/storage/proxy/storage.h
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <stdint.h>
+#include <trusty/interface/storage.h>
+
+int storage_file_delete(struct storage_msg *msg,
+                        const void *req, size_t req_len);
+
+int storage_file_open(struct storage_msg *msg,
+                      const void *req, size_t req_len);
+
+int storage_file_close(struct storage_msg *msg,
+                       const void *req, size_t req_len);
+
+int storage_file_write(struct storage_msg *msg,
+                       const void *req, size_t req_len);
+
+int storage_file_read(struct storage_msg *msg,
+                      const void *req, size_t req_len);
+
+int storage_file_get_size(struct storage_msg *msg,
+                          const void *req, size_t req_len);
+
+int storage_file_set_size(struct storage_msg *msg,
+                          const void *req, size_t req_len);
+
+int storage_init(const char *dirname);
+
+int storage_sync_checkpoint(void);
+
diff --git a/libsync/tests/Android.mk b/trusty/storage/tests/Android.mk
similarity index 67%
rename from libsync/tests/Android.mk
rename to trusty/storage/tests/Android.mk
index 8137c7a..71c904d 100644
--- a/libsync/tests/Android.mk
+++ b/trusty/storage/tests/Android.mk
@@ -1,5 +1,5 @@
 #
-# Copyright 2014 The Android Open Source Project
+# 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.
@@ -17,13 +17,13 @@
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_CLANG := true
-LOCAL_MODULE := sync-unit-tests
-LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers -Wno-sign-compare
-LOCAL_SHARED_LIBRARIES += libsync
-LOCAL_STATIC_LIBRARIES += libgtest_main
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/../include
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
-LOCAL_SRC_FILES := \
-    sync_test.cpp
+LOCAL_MODULE := secure-storage-unit-test
+LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers
+LOCAL_STATIC_LIBRARIES := \
+	libtrustystorageinterface \
+	libtrustystorage \
+	libtrusty \
+	liblog
+LOCAL_SRC_FILES := main.cpp
 include $(BUILD_NATIVE_TEST)
+
diff --git a/trusty/storage/tests/main.cpp b/trusty/storage/tests/main.cpp
new file mode 100644
index 0000000..1fd6f8d
--- /dev/null
+++ b/trusty/storage/tests/main.cpp
@@ -0,0 +1,3040 @@
+/*
+ * 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 <assert.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <gtest/gtest.h>
+
+#include <trusty/lib/storage.h>
+
+#define TRUSTY_DEVICE_NAME "/dev/trusty-ipc-dev0"
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+
+static inline bool is_32bit_aligned(size_t sz)
+{
+    return ((sz & 0x3) == 0);
+}
+
+static inline bool is_valid_size(size_t sz) {
+    return (sz > 0) && is_32bit_aligned(sz);
+}
+
+static bool is_valid_offset(storage_off_t off)
+{
+    return (off & 0x3) == 0ULL;
+}
+
+static void fill_pattern32(uint32_t *buf, size_t len, storage_off_t off)
+{
+    size_t cnt = len / sizeof(uint32_t);
+    uint32_t pattern = (uint32_t)(off / sizeof(uint32_t));
+    while (cnt--) {
+        *buf++ = pattern++;
+    }
+}
+
+static bool check_pattern32(const uint32_t *buf, size_t len, storage_off_t off)
+{
+    size_t cnt = len / sizeof(uint32_t);
+    uint32_t pattern = (uint32_t)(off / sizeof(uint32_t));
+    while (cnt--) {
+        if (*buf != pattern)
+            return false;
+        buf++;
+        pattern++;
+    }
+    return true;
+}
+
+static bool check_value32(const uint32_t *buf, size_t len, uint32_t val)
+{
+    size_t cnt = len / sizeof(uint32_t);
+    while (cnt--) {
+        if (*buf != val)
+            return false;
+        buf++;
+    }
+    return true;
+}
+
+using testing::TestWithParam;
+
+class StorageServiceTest : public virtual TestWithParam<const char *> {
+public:
+    StorageServiceTest() {}
+    virtual ~StorageServiceTest() {}
+
+    virtual void SetUp() {
+        port_ = GetParam();
+        test_buf_ = NULL;
+        aux_session_ = STORAGE_INVALID_SESSION;
+        int rc = storage_open_session(TRUSTY_DEVICE_NAME, &session_, port_);
+        ASSERT_EQ(0, rc);
+    }
+
+    virtual void TearDown() {
+        if (test_buf_) {
+            delete[] test_buf_;
+            test_buf_ = NULL;
+        }
+        storage_close_session(session_);
+
+        if (aux_session_ != STORAGE_INVALID_SESSION) {
+            storage_close_session(aux_session_);
+            aux_session_ = STORAGE_INVALID_SESSION;
+        }
+    }
+
+    void WriteReadAtOffsetHelper(file_handle_t handle, size_t blk, size_t cnt, bool complete);
+
+    void WriteZeroChunk(file_handle_t handle, storage_off_t off, size_t chunk_len, bool complete );
+    void WritePatternChunk(file_handle_t handle, storage_off_t off, size_t chunk_len, bool complete);
+    void WritePattern(file_handle_t handle, storage_off_t off, size_t data_len, size_t chunk_len, bool complete);
+
+    void ReadChunk(file_handle_t handle, storage_off_t off, size_t chunk_len,
+                   size_t head_len, size_t pattern_len, size_t tail_len);
+    void ReadPattern(file_handle_t handle, storage_off_t off, size_t data_len, size_t chunk_len);
+    void ReadPatternEOF(file_handle_t handle, storage_off_t off, size_t chunk_len, size_t exp_len);
+
+protected:
+    const char *port_;
+    uint32_t *test_buf_;
+    storage_session_t session_;
+    storage_session_t aux_session_;
+};
+
+INSTANTIATE_TEST_CASE_P(SS_TD_Tests, StorageServiceTest,   ::testing::Values(STORAGE_CLIENT_TD_PORT));
+INSTANTIATE_TEST_CASE_P(SS_TDEA_Tests, StorageServiceTest, ::testing::Values(STORAGE_CLIENT_TDEA_PORT));
+INSTANTIATE_TEST_CASE_P(SS_TP_Tests, StorageServiceTest,   ::testing::Values(STORAGE_CLIENT_TP_PORT));
+
+
+void StorageServiceTest::WriteZeroChunk(file_handle_t handle, storage_off_t off,
+                                       size_t chunk_len, bool complete)
+{
+    int rc;
+    uint32_t data_buf[chunk_len/sizeof(uint32_t)];
+
+    ASSERT_PRED1(is_valid_size, chunk_len);
+    ASSERT_PRED1(is_valid_offset, off);
+
+    memset(data_buf, 0, chunk_len);
+
+    rc = storage_write(handle, off, data_buf, sizeof(data_buf),
+                       complete ? STORAGE_OP_COMPLETE : 0);
+    ASSERT_EQ((int)chunk_len, rc);
+}
+
+void StorageServiceTest::WritePatternChunk(file_handle_t handle, storage_off_t off,
+                                           size_t chunk_len, bool complete)
+{
+    int rc;
+    uint32_t data_buf[chunk_len/sizeof(uint32_t)];
+
+    ASSERT_PRED1(is_valid_size, chunk_len);
+    ASSERT_PRED1(is_valid_offset, off);
+
+    fill_pattern32(data_buf, chunk_len, off);
+
+    rc = storage_write(handle, off, data_buf, sizeof(data_buf),
+                       complete ? STORAGE_OP_COMPLETE : 0);
+    ASSERT_EQ((int)chunk_len, rc);
+}
+
+void StorageServiceTest::WritePattern(file_handle_t handle, storage_off_t off,
+                                      size_t data_len, size_t chunk_len, bool complete)
+{
+    ASSERT_PRED1(is_valid_size, data_len);
+    ASSERT_PRED1(is_valid_size, chunk_len);
+
+    while (data_len) {
+        if (data_len < chunk_len)
+            chunk_len = data_len;
+        WritePatternChunk(handle, off, chunk_len, (chunk_len == data_len) && complete);
+        ASSERT_FALSE(HasFatalFailure());
+        off += chunk_len;
+        data_len -= chunk_len;
+    }
+}
+
+void StorageServiceTest::ReadChunk(file_handle_t handle,
+                                   storage_off_t off, size_t chunk_len,
+                                   size_t head_len, size_t pattern_len,
+                                   size_t tail_len)
+{
+    int rc;
+    uint32_t data_buf[chunk_len/sizeof(uint32_t)];
+    uint8_t *data_ptr = (uint8_t *)data_buf;
+
+    ASSERT_PRED1(is_valid_size, chunk_len);
+    ASSERT_PRED1(is_valid_offset, off);
+    ASSERT_EQ(head_len + pattern_len + tail_len, chunk_len);
+
+    rc = storage_read(handle, off, data_buf, chunk_len);
+    ASSERT_EQ((int)chunk_len, rc);
+
+    if (head_len) {
+        ASSERT_TRUE(check_value32((const uint32_t *)data_ptr, head_len, 0));
+        data_ptr += head_len;
+        off += head_len;
+    }
+
+    if (pattern_len) {
+        ASSERT_TRUE(check_pattern32((const uint32_t *)data_ptr, pattern_len, off));
+        data_ptr += pattern_len;
+    }
+
+    if (tail_len) {
+        ASSERT_TRUE(check_value32((const uint32_t *)data_ptr, tail_len, 0));
+    }
+}
+
+void StorageServiceTest::ReadPattern(file_handle_t handle, storage_off_t off,
+                                     size_t data_len, size_t chunk_len)
+{
+    int rc;
+    uint32_t data_buf[chunk_len/sizeof(uint32_t)];
+
+    ASSERT_PRED1(is_valid_size, chunk_len);
+    ASSERT_PRED1(is_valid_size, data_len);
+    ASSERT_PRED1(is_valid_offset, off);
+
+    while (data_len) {
+        if (chunk_len > data_len)
+            chunk_len = data_len;
+        rc = storage_read(handle, off, data_buf, sizeof(data_buf));
+        ASSERT_EQ((int)chunk_len, rc);
+        ASSERT_TRUE(check_pattern32(data_buf, chunk_len, off));
+        off += chunk_len;
+        data_len -= chunk_len;
+    }
+}
+
+void StorageServiceTest::ReadPatternEOF(file_handle_t handle, storage_off_t off,
+                                        size_t chunk_len, size_t exp_len)
+{
+    int rc;
+    size_t bytes_read = 0;
+    uint32_t data_buf[chunk_len/sizeof(uint32_t)];
+
+    ASSERT_PRED1(is_valid_size, chunk_len);
+    ASSERT_PRED1(is_32bit_aligned, exp_len);
+
+    while (true) {
+         rc = storage_read(handle, off, data_buf, sizeof(data_buf));
+         ASSERT_GE(rc, 0);
+         if (rc == 0)
+             break; // end of file reached
+         ASSERT_PRED1(is_valid_size, (size_t)rc);
+         ASSERT_TRUE(check_pattern32(data_buf, rc, off));
+         off += rc;
+         bytes_read += rc;
+    }
+    ASSERT_EQ(bytes_read, exp_len);
+}
+
+TEST_P(StorageServiceTest, CreateDelete) {
+    int rc;
+    file_handle_t handle;
+    const char *fname = "test_create_delete_file";
+
+    // make sure test file does not exist (expect success or -ENOENT)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    rc = (rc == -ENOENT) ? 0 : rc;
+    ASSERT_EQ(0, rc);
+
+    // one more time (expect -ENOENT only)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // create file (expect 0)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // try to create it again while it is still opened (expect -EEXIST)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-EEXIST, rc);
+
+    // close it
+    storage_close_file(handle);
+
+    // try to create it again while it is closed (expect -EEXIST)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-EEXIST, rc);
+
+    // delete file (expect 0)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // one more time (expect -ENOENT)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-ENOENT, rc);
+}
+
+
+TEST_P(StorageServiceTest, DeleteOpened) {
+    int rc;
+    file_handle_t handle;
+    const char *fname = "delete_opened_test_file";
+
+    // make sure test file does not exist (expect success or -ENOENT)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    rc = (rc == -ENOENT) ? 0 : rc;
+    ASSERT_EQ(0, rc);
+
+    // one more time (expect -ENOENT)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // open/create file (expect 0)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // delete opened file (expect 0)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // one more time (expect -ENOENT)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // close file
+    storage_close_file(handle);
+
+    // one more time (expect -ENOENT)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-ENOENT, rc);
+}
+
+
+TEST_P(StorageServiceTest, OpenNoCreate) {
+    int rc;
+    file_handle_t handle;
+    const char *fname = "test_open_no_create_file";
+
+    // make sure test file does not exist (expect success or -ENOENT)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    rc = (rc == -ENOENT) ? 0 : rc;
+    ASSERT_EQ(0, rc);
+
+    // open non-existing file (expect -ENOENT)
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // create file (expect 0)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+    storage_close_file(handle);
+
+    // open existing file (expect 0)
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // close it
+    storage_close_file(handle);
+
+    // delete file (expect 0)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+}
+
+
+TEST_P(StorageServiceTest, OpenOrCreate) {
+    int rc;
+    file_handle_t handle;
+    const char *fname = "test_open_create_file";
+
+    // make sure test file does not exist (expect success or -ENOENT)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    rc = (rc == -ENOENT) ? 0 : rc;
+    ASSERT_EQ(0, rc);
+
+    // open/create a non-existing file (expect 0)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+    storage_close_file(handle);
+
+    // open/create an existing file (expect 0)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+    storage_close_file(handle);
+
+    // delete file (expect 0)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+}
+
+
+TEST_P(StorageServiceTest, OpenCreateDeleteCharset) {
+    int rc;
+    file_handle_t handle;
+    const char *fname = "ABCDEFGHIJKLMNOPQRSTUVWXYZ-abcdefghijklmnopqrstuvwxyz_01234.56789";
+
+    // open/create file (expect 0)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+    storage_close_file(handle);
+
+    // open/create an existing file (expect 0)
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+    storage_close_file(handle);
+
+    // delete file (expect 0)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // open again
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+}
+
+
+TEST_P(StorageServiceTest, WriteReadSequential) {
+    int rc;
+    size_t blk = 2048;
+    file_handle_t handle;
+    const char *fname = "test_write_read_sequential";
+
+    // make sure test file does not exist (expect success or -ENOENT)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    rc = (rc == -ENOENT) ? 0 : rc;
+    ASSERT_EQ(0, rc);
+
+    // create file.
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write a bunch of blocks (sequentially)
+    WritePattern(handle, 0, 32 * blk, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadPattern(handle, 0, 32 * blk, blk);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close file
+    storage_close_file(handle);
+
+    // open the same file again
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // read data back (sequentially) and check pattern again
+    ReadPattern(handle, 0, 32 * blk, blk);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, OpenTruncate) {
+    int rc;
+    uint32_t val;
+    size_t blk = 2048;
+    file_handle_t handle;
+    const char *fname = "test_open_truncate";
+
+    // make sure test file does not exist (expect success or -ENOENT)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    rc = (rc == -ENOENT) ? 0 : rc;
+    ASSERT_EQ(0, rc);
+
+    // create file.
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write some data and read it back
+    WritePatternChunk(handle, 0, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadPattern(handle, 0, blk, blk);
+    ASSERT_FALSE(HasFatalFailure());
+
+     // close file
+    storage_close_file(handle);
+
+    // reopen with truncate
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_TRUNCATE, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    /* try to read data back (expect no data) */
+    rc = storage_read(handle, 0LL, &val, sizeof(val));
+    ASSERT_EQ(0, rc);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, OpenSame) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    file_handle_t handle3;
+    const char *fname = "test_open_same_file";
+
+    // open/create file (expect 0)
+    rc = storage_open_file(session_, &handle1, fname, STORAGE_FILE_OPEN_CREATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+    storage_close_file(handle1);
+
+    // open an existing file first time (expect 0)
+    rc = storage_open_file(session_, &handle1, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // open the same file second time (expect error)
+    rc = storage_open_file(session_, &handle2, fname, 0, 0);
+    ASSERT_NE(0, rc);
+
+    storage_close_file(handle1);
+
+    // delete file (expect 0)
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // open deleted file (expect -ENOENT)
+    rc = storage_open_file(session_, &handle3, fname, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+}
+
+
+TEST_P(StorageServiceTest, OpenMany) {
+    int rc;
+    file_handle_t handles[10];
+    char filename[10];
+    const char *fname_fmt = "mf%d";
+
+    // open or create a bunch of files (expect 0)
+    for (uint i = 0; i < ARRAY_SIZE(handles); ++i) {
+        snprintf(filename, sizeof(filename), fname_fmt, i);
+        rc = storage_open_file(session_, &handles[i], filename,
+                               STORAGE_FILE_OPEN_CREATE, STORAGE_OP_COMPLETE);
+        ASSERT_EQ(0, rc);
+    }
+
+    // check that all handles are different
+    for (uint i = 0; i < ARRAY_SIZE(handles)-1; i++) {
+        for (uint j = i+1; j < ARRAY_SIZE(handles); j++) {
+            ASSERT_NE(handles[i], handles[j]);
+        }
+    }
+
+    // close them all
+    for (uint i = 0; i < ARRAY_SIZE(handles); ++i) {
+        storage_close_file(handles[i]);
+    }
+
+    // open all files without CREATE flags (expect 0)
+    for (uint i = 0; i < ARRAY_SIZE(handles); ++i) {
+        snprintf(filename, sizeof(filename), fname_fmt, i);
+        rc = storage_open_file(session_, &handles[i], filename, 0, 0);
+        ASSERT_EQ(0, rc);
+    }
+
+    // check that all handles are different
+    for (uint i = 0; i < ARRAY_SIZE(handles)-1; i++) {
+        for (uint j = i+1; j < ARRAY_SIZE(handles); j++) {
+            ASSERT_NE(handles[i], handles[j]);
+        }
+    }
+
+    // close and remove all test files
+    for (uint i = 0; i < ARRAY_SIZE(handles); ++i) {
+        storage_close_file(handles[i]);
+        snprintf(filename, sizeof(filename), fname_fmt, i);
+        rc = storage_delete_file(session_, filename, STORAGE_OP_COMPLETE);
+        ASSERT_EQ(0, rc);
+    }
+}
+
+
+TEST_P(StorageServiceTest, ReadAtEOF) {
+    int rc;
+    uint32_t val;
+    size_t blk = 2048;
+    file_handle_t handle;
+    const char *fname = "test_read_eof";
+
+    // open/create/truncate file
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write block at offset 0
+    WritePatternChunk(handle, 0, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close file
+    storage_close_file(handle);
+
+    // open same file again
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // read the whole block back and check pattern again
+    ReadPattern(handle, 0, blk, blk);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read at end of file (expected 0 bytes)
+    rc = storage_read(handle, blk, &val, sizeof(val));
+    ASSERT_EQ(0, rc);
+
+    // partial read at end of the file (expected partial data)
+    ReadPatternEOF(handle, blk/2, blk, blk/2);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read past end of file
+    rc = storage_read(handle, blk + 2, &val, sizeof(val));
+    ASSERT_EQ(-EINVAL, rc);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, GetFileSize) {
+    int rc;
+    size_t blk = 2048;
+    storage_off_t size;
+    file_handle_t handle;
+    const char *fname = "test_get_file_size";
+
+    // open/create/truncate file.
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // check file size (expect success and size == 0)
+    size = 1;
+    rc = storage_get_file_size(handle, &size);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, size);
+
+    // write block
+    WritePatternChunk(handle, 0, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check size
+    rc = storage_get_file_size(handle, &size);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ(blk, size);
+
+    // write another block
+    WritePatternChunk(handle, blk, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check size again
+    rc = storage_get_file_size(handle, &size);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ(blk*2, size);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, SetFileSize) {
+    int rc;
+    size_t blk = 2048;
+    storage_off_t size;
+    file_handle_t handle;
+    const char *fname = "test_set_file_size";
+
+    // open/create/truncate file.
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // check file size (expect success and size == 0)
+    size = 1;
+    rc = storage_get_file_size(handle, &size);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, size);
+
+    // write block
+    WritePatternChunk(handle, 0, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check size
+    rc = storage_get_file_size(handle, &size);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ(blk, size);
+
+    storage_close_file(handle);
+
+    // reopen normally
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // check size again
+    rc = storage_get_file_size(handle, &size);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ(blk, size);
+
+    // set file size to half
+    rc = storage_set_file_size(handle, blk/2, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // check size again (should be half of original size)
+    rc = storage_get_file_size(handle, &size);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ(blk/2, size);
+
+    // read data back
+    ReadPatternEOF(handle, 0, blk, blk/2);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // set file size to 0
+    rc = storage_set_file_size(handle, 0, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // check size again (should be 0)
+    rc = storage_get_file_size(handle, &size);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0LL, size);
+
+    // try to read again
+    ReadPatternEOF(handle, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+void StorageServiceTest::WriteReadAtOffsetHelper(file_handle_t handle, size_t blk, size_t cnt, bool complete)
+{
+    storage_off_t off1 = blk;
+    storage_off_t off2 = blk * (cnt-1);
+
+    // write known pattern data at non-zero offset1
+    WritePatternChunk(handle, off1, blk, complete);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // write known pattern data at non-zero offset2
+    WritePatternChunk(handle, off2, blk, complete);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read data back at offset1
+    ReadPattern(handle, off1, blk, blk);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read data back at offset2
+    ReadPattern(handle, off2, blk, blk);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read partially written data at end of file(expect to get data only, no padding)
+    ReadPatternEOF(handle, off2 + blk/2, blk, blk/2);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read data at offset 0 (expect success and zero data)
+    ReadChunk(handle, 0, blk, blk, 0, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read data from gap (expect success and zero data)
+    ReadChunk(handle, off1 + blk, blk, blk, 0, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read partially written data (start pointing within written data)
+    // (expect to get written data back and zeroes at the end)
+    ReadChunk(handle, off1 + blk/2, blk, 0, blk/2, blk/2);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read partially written data (start pointing withing unwritten data)
+    // expect to get zeroes at the beginning and proper data at the end
+    ReadChunk(handle, off1 - blk/2, blk, blk/2, blk/2, 0);
+    ASSERT_FALSE(HasFatalFailure());
+}
+
+
+TEST_P(StorageServiceTest, WriteReadAtOffset) {
+    int rc;
+    file_handle_t handle;
+    size_t blk = 2048;
+    size_t blk_cnt = 32;
+    const char *fname = "test_write_at_offset";
+
+    // create/truncate file.
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write a bunch of blocks filled with zeroes
+    for (uint i = 0; i < blk_cnt; i++) {
+        WriteZeroChunk(handle, i * blk, blk, true);
+        ASSERT_FALSE(HasFatalFailure());
+    }
+
+    WriteReadAtOffsetHelper(handle, blk, blk_cnt, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, WriteSparse) {
+    int rc;
+    file_handle_t handle;
+    const char *fname = "test_write_sparse";
+
+    // open/create/truncate file.
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write value past en of file
+    uint32_t val = 0xDEADBEEF;
+    rc = storage_write(handle, 1, &val, sizeof(val), STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-EINVAL, rc);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+// Persistent 32k
+
+TEST_P(StorageServiceTest, CreatePersistent32K) {
+    int rc;
+    file_handle_t handle;
+    size_t blk = 2048;
+    size_t file_size = 32768;
+    const char *fname = "test_persistent_32K_file";
+
+    // create/truncate file.
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write a bunch of blocks filled with pattern
+    WritePattern(handle, 0, file_size, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close but do not delete file
+    storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, ReadPersistent32k) {
+    int rc;
+    file_handle_t handle;
+    size_t exp_len = 32 * 1024;
+    const char *fname = "test_persistent_32K_file";
+
+    // create/truncate file.
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    ReadPatternEOF(handle, 0, 2048, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadPatternEOF(handle, 0, 1024, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadPatternEOF(handle, 0,  332, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close but do not delete file
+    storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, CleanUpPersistent32K) {
+    int rc;
+    const char *fname = "test_persistent_32K_file";
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    rc = (rc == -ENOENT) ? 0 : rc;
+    ASSERT_EQ(0, rc);
+}
+
+// Persistent 1M
+TEST_P(StorageServiceTest, CreatePersistent1M_4040) {
+    int rc;
+    file_handle_t handle;
+    size_t file_size = 1024 * 1024;
+    const char *fname = "test_persistent_1M_file";
+
+    // create/truncate file.
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write a bunch of blocks filled with pattern
+    WritePattern(handle, 0, file_size, 4040, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close but do not delete file
+    storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, CreatePersistent1M_2032) {
+    int rc;
+    file_handle_t handle;
+    size_t file_size = 1024 * 1024;
+    const char *fname = "test_persistent_1M_file";
+
+    // create/truncate file.
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write a bunch of blocks filled with pattern
+    WritePattern(handle, 0, file_size, 2032, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close but do not delete file
+    storage_close_file(handle);
+}
+
+
+TEST_P(StorageServiceTest, CreatePersistent1M_496) {
+    int rc;
+    file_handle_t handle;
+    size_t file_size = 1024 * 1024;
+    const char *fname = "test_persistent_1M_file";
+
+    // create/truncate file.
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write a bunch of blocks filled with pattern
+    WritePattern(handle, 0, file_size, 496, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close but do not delete file
+    storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, CreatePersistent1M_240) {
+    int rc;
+    file_handle_t handle;
+    size_t file_size = 1024 * 1024;
+    const char *fname = "test_persistent_1M_file";
+
+    // create/truncate file.
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write a bunch of blocks filled with pattern
+    WritePattern(handle, 0, file_size, 240, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close but do not delete file
+    storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, ReadPersistent1M_4040) {
+    int rc;
+    file_handle_t handle;
+    size_t exp_len = 1024 * 1024;
+    const char *fname = "test_persistent_1M_file";
+
+    // create/truncate file.
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    ReadPatternEOF(handle, 0, 4040, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close but do not delete file
+    storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, ReadPersistent1M_2032) {
+    int rc;
+    file_handle_t handle;
+    size_t exp_len = 1024 * 1024;
+    const char *fname = "test_persistent_1M_file";
+
+    // create/truncate file.
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    ReadPatternEOF(handle, 0, 2032, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close but do not delete file
+    storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, ReadPersistent1M_496) {
+    int rc;
+    file_handle_t handle;
+    size_t exp_len = 1024 * 1024;
+    const char *fname = "test_persistent_1M_file";
+
+    // create/truncate file.
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    ReadPatternEOF(handle, 0, 496, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close but do not delete file
+    storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, ReadPersistent1M_240) {
+    int rc;
+    file_handle_t handle;
+    size_t exp_len = 1024 * 1024;
+    const char *fname = "test_persistent_1M_file";
+
+    // create/truncate file.
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    ReadPatternEOF(handle, 0, 240, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close but do not delete file
+    storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, CleanUpPersistent1M) {
+    int rc;
+    const char *fname = "test_persistent_1M_file";
+    rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+    rc = (rc == -ENOENT) ? 0 : rc;
+    ASSERT_EQ(0, rc);
+}
+
+TEST_P(StorageServiceTest, WriteReadLong) {
+    int rc;
+    file_handle_t handle;
+    size_t wc = 10000;
+    const char *fname = "test_write_read_long";
+
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    test_buf_ = new uint32_t[wc];
+    fill_pattern32(test_buf_, wc * sizeof(uint32_t), 0);
+    rc = storage_write(handle, 0, test_buf_, wc * sizeof(uint32_t), STORAGE_OP_COMPLETE);
+    ASSERT_EQ((int)(wc * sizeof(uint32_t)), rc);
+
+    rc = storage_read(handle, 0, test_buf_, wc * sizeof(uint32_t));
+    ASSERT_EQ((int)(wc * sizeof(uint32_t)), rc);
+    ASSERT_TRUE(check_pattern32(test_buf_, wc * sizeof(uint32_t), 0));
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+// Negative tests
+
+TEST_P(StorageServiceTest, OpenInvalidFileName) {
+    int rc;
+    file_handle_t handle;
+    const char *fname1 = "";
+    const char *fname2 = "ffff$ffff";
+    const char *fname3 = "ffff\\ffff";
+    char max_name[STORAGE_MAX_NAME_LENGTH_BYTES+1];
+
+    rc = storage_open_file(session_, &handle, fname1,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-EINVAL, rc);
+
+    rc = storage_open_file(session_, &handle, fname2,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-EINVAL, rc);
+
+    rc = storage_open_file(session_, &handle, fname3,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-EINVAL, rc);
+
+    /* max name */
+    memset(max_name, 'a', sizeof(max_name));
+    max_name[sizeof(max_name)-1] = 0;
+
+    rc = storage_open_file(session_, &handle, max_name,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-EINVAL, rc);
+
+    max_name[sizeof(max_name)-2] = 0;
+    rc = storage_open_file(session_, &handle, max_name,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    storage_close_file(handle);
+    storage_delete_file(session_, max_name, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, BadFileHnadle) {
+    int rc;
+    file_handle_t handle;
+    file_handle_t handle1;
+    const char *fname = "test_invalid_file_handle";
+
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    handle1 = handle + 1;
+
+    // write to invalid file handle
+    uint32_t val = 0xDEDBEEF;
+    rc = storage_write(handle1,  0, &val, sizeof(val), STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-EINVAL, rc);
+
+    // read from invalid handle
+    rc = storage_read(handle1,  0, &val, sizeof(val));
+    ASSERT_EQ(-EINVAL, rc);
+
+    // set size
+    rc = storage_set_file_size(handle1,  0, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-EINVAL, rc);
+
+    // get size
+    storage_off_t fsize = (storage_off_t)(-1);
+    rc = storage_get_file_size(handle1,  &fsize);
+    ASSERT_EQ(-EINVAL, rc);
+
+    // close (there is no way to check errors here)
+    storage_close_file(handle1);
+
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, ClosedFileHnadle) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    const char *fname1 = "test_invalid_file_handle1";
+    const char *fname2 = "test_invalid_file_handle2";
+
+    rc = storage_open_file(session_, &handle1, fname1,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    rc = storage_open_file(session_, &handle2, fname2,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // close first file handle
+    storage_close_file(handle1);
+
+    // write to invalid file handle
+    uint32_t val = 0xDEDBEEF;
+    rc = storage_write(handle1,  0, &val, sizeof(val), STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-EINVAL, rc);
+
+    // read from invalid handle
+    rc = storage_read(handle1,  0, &val, sizeof(val));
+    ASSERT_EQ(-EINVAL, rc);
+
+    // set size
+    rc = storage_set_file_size(handle1,  0, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-EINVAL, rc);
+
+    // get size
+    storage_off_t fsize = (storage_off_t)(-1);
+    rc = storage_get_file_size(handle1,  &fsize);
+    ASSERT_EQ(-EINVAL, rc);
+
+    // close (there is no way to check errors here)
+    storage_close_file(handle1);
+
+    // clean up
+    storage_close_file(handle2);
+    storage_delete_file(session_, fname1, STORAGE_OP_COMPLETE);
+    storage_delete_file(session_, fname2, STORAGE_OP_COMPLETE);
+}
+
+// Transactions
+
+TEST_P(StorageServiceTest, TransactDiscardInactive) {
+    int rc;
+
+    // discard current transaction (there should not be any)
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // try it again
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+}
+
+TEST_P(StorageServiceTest, TransactCommitInactive) {
+    int rc;
+
+    // try to commit current transaction
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // try it again
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+}
+
+TEST_P(StorageServiceTest, TransactDiscardWrite) {
+
+    int rc;
+    file_handle_t handle;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_discard_write";
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // write (without commit)
+    WritePattern(handle, 0, exp_len, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // abort current transaction
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // cleanup
+    storage_close_file( handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactDiscardWriteAppend) {
+
+    int rc;
+    file_handle_t handle;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_write_append";
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write data with commit
+    WritePattern(handle, 0, exp_len/2, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // write data without commit
+    WritePattern(handle, exp_len/2, exp_len/2, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check file size (should be exp_len)
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // discard transaction
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // check file size, it should be exp_len/2
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len/2, fsize);
+
+    // check file data
+    ReadPatternEOF(handle, 0, blk, exp_len/2);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactDiscardWriteRead) {
+
+    int rc;
+    file_handle_t handle;
+    size_t blk = 2048;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_discard_write_read";
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // Fill with zeroes (with commit)
+    for (uint i = 0; i < 32; i++) {
+        WriteZeroChunk(handle, i * blk, blk, true);
+        ASSERT_FALSE(HasFatalFailure());
+    }
+
+    // check that test chunk is filled with zeroes
+    ReadChunk(handle, blk, blk, blk, 0, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // write test pattern (without commit)
+    WritePattern(handle, blk, blk, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read it back an check pattern
+    ReadChunk(handle, blk, blk, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // abort current transaction
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // read same chunk back (should be filled with zeros)
+    ReadChunk(handle, blk, blk, blk, 0, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactDiscardWriteMany) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    size_t blk = 2048;
+    size_t exp_len1 = 32 * 1024;
+    size_t exp_len2 = 31 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname1 = "test_transact_discard_write_file1";
+    const char *fname2 = "test_transact_discard_write_file2";
+
+    // open create truncate (with commit)
+    rc = storage_open_file(session_, &handle1, fname1,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // open create truncate (with commit)
+    rc = storage_open_file(session_, &handle2, fname2,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // file1: fill file with pattern (without commit)
+    WritePattern(handle1, 0, exp_len1, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // file2: fill file with pattern (without commit)
+    WritePattern(handle2, 0, exp_len2, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check file size, it should be exp_len1
+    rc = storage_get_file_size(handle1, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len1, fsize);
+
+    // check file size, it should be exp_len2
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len2, fsize);
+
+    // commit transaction
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // check file size, it should be exp_len1
+    rc = storage_get_file_size(handle1, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // check file size, it should be exp_len2
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // check data
+    ReadPatternEOF(handle1, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadPatternEOF(handle2, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle1);
+    storage_delete_file(session_, fname1, STORAGE_OP_COMPLETE);
+    storage_close_file(handle2);
+    storage_delete_file(session_, fname2, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactDiscardTruncate) {
+    int rc;
+    file_handle_t handle;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_discard_truncate";
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write data (with commit)
+    WritePattern(handle, 0, exp_len, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // close file
+    storage_close_file(handle);
+
+    // open truncate file (without commit)
+    rc = storage_open_file(session_, &handle, fname, STORAGE_FILE_OPEN_TRUNCATE, 0);
+    ASSERT_EQ(0, rc);
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // abort current transaction
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // check file size (should be an oruginal size)
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactDiscardSetSize) {
+    int rc;
+    file_handle_t handle;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_discard_set_size";
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write data (with commit)
+    WritePattern(handle, 0, exp_len, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // set file size to half of original (no commit)
+    rc = storage_set_file_size(handle,  (storage_off_t)exp_len/2, 0);
+    ASSERT_EQ(0, rc);
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len/2, fsize);
+
+    // set file size to 1/3 of original (no commit)
+    rc = storage_set_file_size(handle,  (storage_off_t)exp_len/3, 0);
+    ASSERT_EQ(0, rc);
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len/3, fsize);
+
+    // abort current transaction
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // check file size (should be an original size)
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactDiscardDelete) {
+    int rc;
+    file_handle_t handle;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_discard_delete";
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write data (with commit)
+    WritePattern(handle, 0, exp_len, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close it
+    storage_close_file(handle);
+
+    // delete file (without commit)
+    rc = storage_delete_file(session_, fname, 0);
+    ASSERT_EQ(0, rc);
+
+    // try to open it (should fail)
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // abort current transaction
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // try to open it
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // check file size (should be an original size)
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactDiscardDelete2) {
+    int rc;
+    file_handle_t handle;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_discard_delete";
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write data (with commit)
+    WritePattern(handle, 0, exp_len, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // delete file (without commit)
+    rc = storage_delete_file(session_, fname, 0);
+    ASSERT_EQ(0, rc);
+    storage_close_file(handle);
+
+    // try to open it (should fail)
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // abort current transaction
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // try to open it
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // check file size (should be an original size)
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactDiscardCreate) {
+    int rc;
+    file_handle_t handle;
+    const char *fname = "test_transact_discard_create_excl";
+
+    // delete test file just in case
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+
+    // create file (without commit)
+    rc = storage_open_file(session_, &handle, fname,
+                               STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                               0);
+    ASSERT_EQ(0, rc);
+
+    // abort current transaction
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactCommitWrites) {
+
+    int rc;
+    file_handle_t handle;
+    file_handle_t handle_aux;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_commit_writes";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // open the same file in aux session
+    rc = storage_open_file(aux_session_, &handle_aux, fname,  0, 0);
+    ASSERT_EQ(0, rc);
+
+    // check file size, it should be 0
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // write data in primary session (without commit)
+    WritePattern(handle, 0, exp_len/2, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // write more data in primary session (without commit)
+    WritePattern(handle, exp_len/2, exp_len/2, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check file size in aux session, it should still be 0
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // commit current transaction
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // check file size of aux session, should fail
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(-EBUSY, rc);
+
+    // abort transaction in aux session to recover
+    rc = storage_end_transaction(aux_session_, false);
+    ASSERT_EQ(0, rc);
+
+    // check file size in aux session, it should be exp_len
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // check file size in primary session, it should be exp_len
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // check data in primary session
+    ReadPatternEOF(handle, 0, blk, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check data in aux session
+    ReadPatternEOF(handle_aux, 0, blk, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle);
+    storage_close_file(handle_aux);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactCommitWrites2) {
+
+    int rc;
+    file_handle_t handle;
+    file_handle_t handle_aux;
+    size_t blk = 2048;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_commit_writes2";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // open the same file in separate session
+    rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // discard transaction in aux_session
+    rc = storage_end_transaction(aux_session_,  false);
+    ASSERT_EQ(0, rc);
+
+    // Fill with zeroes (with commit)
+    for (uint i = 0; i < 8; i++) {
+        WriteZeroChunk(handle, i * blk, blk, true);
+        ASSERT_FALSE(HasFatalFailure());
+    }
+
+    // check that test chunks are filled with zeroes
+    ReadChunk(handle, blk, blk, blk, 0, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadChunk(handle, 2 * blk, blk, blk, 0, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // write test pattern (without commit)
+    WritePattern(handle, blk, blk, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // write test pattern (without commit)
+    WritePattern(handle, 2 * blk, blk, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read it back and check pattern
+    ReadChunk(handle, blk, blk, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadChunk(handle, 2 * blk, blk, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // In aux session it still should be empty
+    ReadChunk(handle_aux, blk, blk, blk, 0, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadChunk(handle_aux, 2 * blk, blk, blk, 0, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // commit current transaction
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // read same chunks back in primary session
+    ReadChunk(handle, blk, blk, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadChunk(handle, 2 * blk, blk, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read same chunks back in aux session (should fail)
+    uint32_t val;
+    rc = storage_read(handle_aux, blk, &val, sizeof(val));
+    ASSERT_EQ(-EBUSY, rc);
+
+    rc = storage_read(handle_aux, 2 * blk, &val, sizeof(val));
+    ASSERT_EQ(-EBUSY, rc);
+
+    // abort transaction in aux session
+    rc = storage_end_transaction(aux_session_,  false);
+    ASSERT_EQ(0, rc);
+
+    // read same chunk again in aux session
+    ReadChunk(handle_aux, blk, blk, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadChunk(handle_aux, 2 * blk, blk, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+
+    // cleanup
+    storage_close_file(handle);
+    storage_close_file(handle_aux);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactCommitSetSize) {
+    int rc;
+    file_handle_t handle;
+    file_handle_t handle_aux;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_commit_set_size";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // open the same file in separate session
+    rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // write data (with commit)
+    WritePattern(handle, 0, exp_len, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // same in aux session
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // set file size to half of original (no commit)
+    rc = storage_set_file_size(handle,  (storage_off_t)exp_len/2, 0);
+    ASSERT_EQ(0, rc);
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len/2, fsize);
+
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // set file size to 1/3 of original (no commit)
+    rc = storage_set_file_size(handle,  (storage_off_t)exp_len/3, 0);
+    ASSERT_EQ(0, rc);
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len/3, fsize);
+
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // commit current transaction
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // check file size (should be 1/3 of an original size)
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len/3, fsize);
+
+    // check file size from aux session
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(-EBUSY, rc);
+
+    // abort transaction in aux_session
+    rc = storage_end_transaction(aux_session_, false);
+    ASSERT_EQ(0, rc);
+
+    // check again
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len/3, fsize);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_close_file(handle_aux);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactCommitDelete) {
+    int rc;
+    file_handle_t handle;
+    file_handle_t handle_aux;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    const char *fname = "test_transact_commit_delete";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write data (with commit)
+    WritePattern(handle, 0, exp_len, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close it
+    storage_close_file(handle);
+
+    // open the same file in separate session
+    rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+    storage_close_file(handle_aux);
+
+    // delete file (without commit)
+    rc = storage_delete_file(session_, fname, 0);
+    ASSERT_EQ(0, rc);
+
+    // try to open it (should fail)
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // open the same file in separate session (should be fine)
+    rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+    storage_close_file(handle_aux);
+
+    // commit current transaction
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // try to open it in primary session (still fails)
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // open the same file in aux session (should also fail)
+    rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+}
+
+
+TEST_P(StorageServiceTest, TransactCommitTruncate) {
+    int rc;
+    file_handle_t handle;
+    file_handle_t handle_aux;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_commit_truncate";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write data (with commit)
+    WritePattern(handle, 0, exp_len, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // close file
+    storage_close_file(handle);
+
+    // check from different session
+    rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // open truncate file (without commit)
+    rc = storage_open_file(session_, &handle, fname, STORAGE_FILE_OPEN_TRUNCATE, 0);
+    ASSERT_EQ(0, rc);
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // commit current transaction
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // check file size (should be 0)
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // check file size in aux session (should be -EBUSY)
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(-EBUSY, rc);
+
+    // abort transaction in aux session
+    rc = storage_end_transaction(aux_session_, false);
+    ASSERT_EQ(0, rc);
+
+    // check again
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_close_file(handle_aux);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactCommitCreate) {
+    int rc;
+    file_handle_t handle;
+    file_handle_t handle_aux;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_commit_create";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // delete test file just in case
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+
+    // check from aux session
+    rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // create file (without commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                           0);
+    ASSERT_EQ(0, rc);
+
+    // check file size
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // close file
+    storage_close_file(handle);
+
+    // check from aux session (should fail)
+    rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // commit current transaction
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // check open from normal session
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // check open from aux session (should succeed)
+    rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // cleanup
+    storage_close_file(handle);
+    storage_close_file(handle_aux);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactCommitCreateMany) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    file_handle_t handle1_aux;
+    file_handle_t handle2_aux;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname1 = "test_transact_commit_create1";
+    const char *fname2 = "test_transact_commit_create2";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // delete test file just in case
+    storage_delete_file(session_, fname1, STORAGE_OP_COMPLETE);
+    storage_delete_file(session_, fname2, STORAGE_OP_COMPLETE);
+
+    // create file (without commit)
+    rc = storage_open_file(session_, &handle1, fname1,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                           0);
+    ASSERT_EQ(0, rc);
+
+    // create file (without commit)
+    rc = storage_open_file(session_, &handle2, fname2,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                           0);
+    ASSERT_EQ(0, rc);
+
+    // check file sizes
+    rc = storage_get_file_size(handle1, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    rc = storage_get_file_size(handle1, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // close files
+    storage_close_file(handle1);
+    storage_close_file(handle2);
+
+    // open files from aux session
+    rc = storage_open_file(aux_session_, &handle1_aux, fname1, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+
+    rc = storage_open_file(aux_session_, &handle2_aux, fname2, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // commit current transaction
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // open from primary session
+    rc = storage_open_file(session_, &handle1, fname1, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    rc = storage_open_file(session_, &handle2, fname2, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // open from aux session
+    rc = storage_open_file(aux_session_, &handle1_aux, fname1, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    rc = storage_open_file(aux_session_, &handle2_aux, fname2, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // cleanup
+    storage_close_file(handle1);
+    storage_close_file(handle1_aux);
+    storage_delete_file(session_, fname1, STORAGE_OP_COMPLETE);
+    storage_close_file(handle2);
+    storage_close_file(handle2_aux);
+    storage_delete_file(session_, fname2, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactCommitWriteMany) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    file_handle_t handle1_aux;
+    file_handle_t handle2_aux;
+    size_t blk = 2048;
+    size_t exp_len1 = 32 * 1024;
+    size_t exp_len2 = 31 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname1 = "test_transact_commit_write_file1";
+    const char *fname2 = "test_transact_commit_write_file2";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // open create truncate (with commit)
+    rc = storage_open_file(session_, &handle1, fname1,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // open create truncate (with commit)
+    rc = storage_open_file(session_, &handle2, fname2,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // open same files from aux session
+    rc = storage_open_file(aux_session_, &handle1_aux, fname1, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    rc = storage_open_file(aux_session_, &handle2_aux, fname2, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // file1: fill file with pattern (without commit)
+    WritePattern(handle1, 0, exp_len1, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // file2: fill file with pattern (without commit)
+    WritePattern(handle2, 0, exp_len2, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check file size, it should be exp_len1
+    rc = storage_get_file_size(handle1, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len1, fsize);
+
+    // check file size, it should be exp_len2
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len2, fsize);
+
+    // check file sizes from aux session (should be 0)
+    rc = storage_get_file_size(handle1_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    rc = storage_get_file_size(handle2_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // commit transaction
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // check file size, it should be exp_len1
+    rc = storage_get_file_size(handle1, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len1, fsize);
+
+    // check file size, it should be exp_len2
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len2, fsize);
+
+    // check from aux session (should be -EBUSY)
+    rc = storage_get_file_size(handle1_aux, &fsize);
+    ASSERT_EQ(-EBUSY, rc);
+
+    // abort transaction in aux session
+    rc = storage_end_transaction(aux_session_, false);
+    ASSERT_EQ(0, rc);
+
+    // and check again
+    rc = storage_get_file_size(handle1_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len1, fsize);
+
+    rc = storage_get_file_size(handle2_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len2, fsize);
+
+    // check data
+    ReadPatternEOF(handle1, 0, blk, exp_len1);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadPatternEOF(handle2, 0, blk, exp_len2);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadPatternEOF(handle1_aux, 0, blk, exp_len1);
+    ASSERT_FALSE(HasFatalFailure());
+
+    ReadPatternEOF(handle2_aux, 0, blk, exp_len2);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle1);
+    storage_close_file(handle1_aux);
+    storage_delete_file(session_, fname1, STORAGE_OP_COMPLETE);
+    storage_close_file(handle2);
+    storage_close_file(handle2_aux);
+    storage_delete_file(session_, fname2, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactCommitDeleteCreate) {
+    int rc;
+    file_handle_t handle;
+    file_handle_t handle_aux;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_delete_create";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write data (with commit)
+    WritePattern(handle, 0, exp_len, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close it
+    storage_close_file(handle);
+
+    // delete file (without commit)
+    rc = storage_delete_file(session_, fname, 0);
+    ASSERT_EQ(0, rc);
+
+    // try to open it (should fail)
+    rc = storage_open_file(session_, &handle, fname, 0, 0);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // try to open it in aux session (should succeed)
+    rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // create file with the same name (no commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+                           0);
+    ASSERT_EQ(0, rc);
+
+    // write half of data (with commit)
+    WritePattern(handle, 0, exp_len/2, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check file size (should be half)
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len/2, fsize);
+
+    // commit transaction
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // check data from primary session
+    ReadPatternEOF(handle, 0, blk, exp_len/2);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // check from aux session (should fail)
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(-EINVAL, rc);
+
+    // abort trunsaction in aux session
+    rc = storage_end_transaction(aux_session_, false);
+    ASSERT_EQ(0, rc);
+
+    // and try again (should still fail)
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(-EINVAL, rc);
+
+    // close file and reopen it again
+    storage_close_file(handle_aux);
+    rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+    ASSERT_EQ(0, rc);
+
+    // try it again (should succeed)
+    rc = storage_get_file_size(handle_aux, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len/2, fsize);
+
+    // check data
+    ReadPatternEOF(handle_aux, 0, blk, exp_len/2);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle);
+    storage_close_file(handle_aux);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactRewriteExistingTruncate) {
+    int rc;
+    file_handle_t handle;
+    size_t blk = 2048;
+    const char *fname = "test_transact_rewrite_existing_truncate";
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // close it
+    storage_close_file(handle);
+
+    // up
+    for (uint i = 1; i < 32; i++) {
+        // open truncate (no commit)
+        rc = storage_open_file(session_, &handle, fname, STORAGE_FILE_OPEN_TRUNCATE, 0);
+        ASSERT_EQ(0, rc);
+
+        // write data (with commit)
+        WritePattern(handle, 0, i * blk, blk, true);
+        ASSERT_FALSE(HasFatalFailure());
+
+        // close
+        storage_close_file(handle);
+    }
+
+    // down
+    for (uint i = 1; i < 32; i++) {
+        // open truncate (no commit)
+        rc = storage_open_file(session_, &handle, fname, STORAGE_FILE_OPEN_TRUNCATE, 0);
+        ASSERT_EQ(0, rc);
+
+        // write data (with commit)
+        WritePattern(handle, 0, (32 - i) * blk, blk, true);
+        ASSERT_FALSE(HasFatalFailure());
+
+        // close
+        storage_close_file(handle);
+    }
+
+    // cleanup
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactRewriteExistingSetSize) {
+    int rc;
+    file_handle_t handle;
+    size_t blk = 2048;
+    const char *fname = "test_transact_rewrite_existing_set_size";
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // close it
+    storage_close_file(handle);
+
+    // up
+    for (uint i = 1; i < 32; i++) {
+        // open truncate (no commit)
+        rc = storage_open_file(session_, &handle, fname, 0, 0);
+        ASSERT_EQ(0, rc);
+
+        // write data (with commit)
+        WritePattern(handle, 0, i * blk, blk, false);
+        ASSERT_FALSE(HasFatalFailure());
+
+        // update size (with commit)
+        rc = storage_set_file_size(handle, i * blk, STORAGE_OP_COMPLETE);
+        ASSERT_EQ(0, rc);
+
+        // close
+        storage_close_file(handle);
+    }
+
+    // down
+    for (uint i = 1; i < 32; i++) {
+        // open trancate (no commit)
+        rc = storage_open_file(session_, &handle, fname, 0, 0);
+        ASSERT_EQ(0, rc);
+
+        // write data (with commit)
+        WritePattern(handle, 0, (32 - i) * blk, blk, false);
+        ASSERT_FALSE(HasFatalFailure());
+
+        // update size (with commit)
+        rc = storage_set_file_size(handle, (32 - i) * blk, STORAGE_OP_COMPLETE);
+        ASSERT_EQ(0, rc);
+
+        // close
+        storage_close_file(handle);
+    }
+
+    // cleanup
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactResumeAfterNonFatalError) {
+
+    int rc;
+    file_handle_t handle;
+    file_handle_t handle1;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_resume_writes";
+
+    // open create truncate file (with commit)
+    rc = storage_open_file(session_, &handle, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // write (without commit)
+    WritePattern(handle, 0, exp_len/2, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // issue some commands that should fail with non-fatal errors
+
+    // write past end of file
+    uint32_t val = 0xDEDBEEF;
+    rc = storage_write(handle,  exp_len/2 + 1, &val, sizeof(val), 0);
+    ASSERT_EQ(-EINVAL, rc);
+
+    // read past end of file
+    rc = storage_read(handle, exp_len/2 + 1, &val, sizeof(val));
+    ASSERT_EQ(-EINVAL, rc);
+
+    // try to extend file past end of file
+    rc = storage_set_file_size(handle, exp_len/2 + 1, 0);
+    ASSERT_EQ(-EINVAL, rc);
+
+    // open non existing file
+    rc = storage_open_file(session_, &handle1, "foo",
+                           STORAGE_FILE_OPEN_TRUNCATE, STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // delete non-existing file
+    rc = storage_delete_file(session_, "foo", STORAGE_OP_COMPLETE);
+    ASSERT_EQ(-ENOENT, rc);
+
+    // then resume writinga (without commit)
+    WritePattern(handle, exp_len/2, exp_len/2, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // commit current transaction
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // check file size, it should be exp_len
+    rc = storage_get_file_size(handle, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // check data
+    ReadPatternEOF(handle, 0, blk, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle);
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+// Transaction Collisions
+
+TEST_P(StorageServiceTest, Transact2_WriteNC) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    size_t blk = 2048;
+    const char *fname1 = "test_transact_f1";
+    const char *fname2 = "test_transact_f2";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    rc = storage_open_file(session_, &handle1, fname1,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    rc = storage_open_file(aux_session_, &handle2, fname2,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // session 1
+    WritePattern(handle1, 0, blk, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read it back
+    ReadPatternEOF(handle1, 0, blk, blk);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // session 2
+    WritePattern(handle2, 0, blk, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read it back
+    ReadPatternEOF(handle2, 0, blk, blk);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle1);
+    storage_close_file(handle2);
+
+    storage_delete_file(session_, fname1, STORAGE_OP_COMPLETE);
+    storage_delete_file(aux_session_, fname2, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, Transact2_DeleteNC) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    size_t blk = 2048;
+    const char *fname1 = "test_transact_delete_f1";
+    const char *fname2 = "test_transact_delete_f2";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    rc = storage_open_file(session_, &handle1, fname1,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    rc = storage_open_file(aux_session_, &handle2, fname2,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // session 1
+    WritePattern(handle1, 0, blk, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read it back
+    ReadPatternEOF(handle1, 0, blk, blk);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // session 2
+    WritePattern(handle2, 0, blk, blk, true);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // read it back
+    ReadPatternEOF(handle2, 0, blk, blk);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // close files and delete them
+    storage_close_file(handle1);
+    storage_delete_file(session_, fname1, 0);
+
+    storage_close_file(handle2);
+    storage_delete_file(aux_session_, fname2, 0);
+
+    // commit
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    rc = storage_end_transaction(aux_session_, true);
+    ASSERT_EQ(0, rc);
+}
+
+
+TEST_P(StorageServiceTest, Transact2_Write_Read) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_writeRead";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // S1: open create truncate file
+    rc = storage_open_file(session_, &handle1, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // S2: open the same file
+    rc = storage_open_file(aux_session_, &handle2, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // S1: write (no commit)
+    WritePattern(handle1, 0, exp_len, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // S1: read it back
+    ReadPatternEOF(handle1, 0, blk, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // S2: check file size, it should be 0
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // S2: read it back (should no data)
+    ReadPatternEOF(handle2, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // S1: commit
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // S2: check file size, it should fail
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(-EBUSY, rc);
+
+    // S2: abort transaction
+    rc = storage_end_transaction(aux_session_, false);
+    ASSERT_EQ(0, rc);
+
+    // S2: check file size again, it should be exp_len
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // S2: read it again (should be exp_len)
+    ReadPatternEOF(handle2, 0, blk, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle1);
+    storage_close_file(handle2);
+
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, Transact2_Write_Write_Commit_Commit) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    file_handle_t handle3;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_write_write_commit_commit";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // S1: open create truncate file
+    rc = storage_open_file(session_, &handle1, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // S2: open the same file
+    rc = storage_open_file(aux_session_, &handle2, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // S1: write (no commit)
+    WritePattern(handle1, 0, exp_len, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // S2: write (no commit)
+    WritePattern(handle2, 0, exp_len/2, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // S1: commit
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // S2: read/write/get/set size/delete (all should fail)
+    uint32_t val = 0;
+    rc = storage_read(handle2, 0, &val, sizeof(val));
+    ASSERT_EQ(-EBUSY, rc);
+
+    rc = storage_write(handle2, 0, &val, sizeof(val), 0);
+    ASSERT_EQ(-EBUSY, rc);
+
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(-EBUSY, rc);
+
+    rc = storage_set_file_size(handle2,  fsize, 0);
+    ASSERT_EQ(-EBUSY, rc);
+
+    rc = storage_delete_file(aux_session_, fname, 0);
+    ASSERT_EQ(-EBUSY, rc);
+
+    rc = storage_open_file(aux_session_, &handle3, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE, 0);
+    ASSERT_EQ(-EBUSY, rc);
+
+    // S2: commit (should fail, and failed state should be cleared)
+    rc = storage_end_transaction(aux_session_, true);
+    ASSERT_EQ(-EBUSY, rc);
+
+    // S2: check file size, it should be exp_len
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // S2: read it again (should be exp_len)
+    ReadPatternEOF(handle2, 0, blk, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle1);
+    storage_close_file(handle2);
+
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, Transact2_Write_Write_Commit_Discard) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    file_handle_t handle3;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_write_write_commit_discard";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // S1: open create truncate file
+    rc = storage_open_file(session_, &handle1, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // S2: open the same file
+    rc = storage_open_file(aux_session_, &handle2, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // S1: write (no commit)
+    WritePattern(handle1, 0, exp_len, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // S2: write (no commit)
+    WritePattern(handle2, 0, exp_len/2, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // S1: commit
+    rc = storage_end_transaction(session_, true);
+    ASSERT_EQ(0, rc);
+
+    // S2: read/write/get/set size/delete (all should fail)
+    uint32_t val = 0;
+    rc = storage_read(handle2, 0, &val, sizeof(val));
+    ASSERT_EQ(-EBUSY, rc);
+
+    rc = storage_write(handle2, 0, &val, sizeof(val), 0);
+    ASSERT_EQ(-EBUSY, rc);
+
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(-EBUSY, rc);
+
+    rc = storage_set_file_size(handle2,  fsize, 0);
+    ASSERT_EQ(-EBUSY, rc);
+
+    rc = storage_delete_file(aux_session_, fname, 0);
+    ASSERT_EQ(-EBUSY, rc);
+
+    rc = storage_open_file(aux_session_, &handle3, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE, 0);
+    ASSERT_EQ(-EBUSY, rc);
+
+    // S2: discard (should fail, and failed state should be cleared)
+    rc = storage_end_transaction(aux_session_, false);
+    ASSERT_EQ(0, rc);
+
+    // S2: check file size, it should be exp_len
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+    // S2: read it again (should be exp_len)
+    ReadPatternEOF(handle2, 0, blk, exp_len);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle1);
+    storage_close_file(handle2);
+
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, Transact2_Write_Write_Discard_Commit) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_write_write_discard_commit";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // S1: open create truncate file
+    rc = storage_open_file(session_, &handle1, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // S2: open the same file
+    rc = storage_open_file(aux_session_, &handle2, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // S1: write (no commit)
+    WritePattern(handle1, 0, exp_len, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // S2: write (no commit)
+    WritePattern(handle2, 0, exp_len/2, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // S1: discard
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // S2: commit (should succeed)
+    rc = storage_end_transaction(aux_session_, true);
+    ASSERT_EQ(0, rc);
+
+    // S2: check file size, it should be exp_len
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)exp_len/2, fsize);
+
+    // S2: read it again (should be exp_len)
+    ReadPatternEOF(handle2, 0, blk, exp_len/2);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle1);
+    storage_close_file(handle2);
+
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, Transact2_Write_Write_Discard_Discard) {
+    int rc;
+    file_handle_t handle1;
+    file_handle_t handle2;
+    size_t blk = 2048;
+    size_t exp_len = 32 * 1024;
+    storage_off_t fsize = (storage_off_t)(-1);
+    const char *fname = "test_transact_write_write_discard_Discard";
+
+    // open second session
+    rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+    ASSERT_EQ(0, rc);
+
+    // S1: open create truncate file
+    rc = storage_open_file(session_, &handle1, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // S2: open the same file
+    rc = storage_open_file(aux_session_, &handle2, fname,
+                           STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+                           STORAGE_OP_COMPLETE);
+    ASSERT_EQ(0, rc);
+
+    // S1: write (no commit)
+    WritePattern(handle1, 0, exp_len, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // S2: write (no commit)
+    WritePattern(handle2, 0, exp_len/2, blk, false);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // S1: discard
+    rc = storage_end_transaction(session_, false);
+    ASSERT_EQ(0, rc);
+
+    // S2: discard
+    rc = storage_end_transaction(aux_session_, false);
+    ASSERT_EQ(0, rc);
+
+    // S2: check file size, it should be 0
+    rc = storage_get_file_size(handle2, &fsize);
+    ASSERT_EQ(0, rc);
+    ASSERT_EQ((storage_off_t)0, fsize);
+
+    // S2: read it again (should be 0)
+    ReadPatternEOF(handle2, 0, blk, 0);
+    ASSERT_FALSE(HasFatalFailure());
+
+    // cleanup
+    storage_close_file(handle1);
+    storage_close_file(handle2);
+
+    storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
diff --git a/libmincrypt/tools/Android.mk b/trusty/trusty-base.mk
similarity index 61%
copy from libmincrypt/tools/Android.mk
copy to trusty/trusty-base.mk
index 3154914..9c3a7df 100644
--- a/libmincrypt/tools/Android.mk
+++ b/trusty/trusty-base.mk
@@ -1,4 +1,5 @@
-# Copyright (C) 2008 The Android Open Source Project
+#
+# 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.
@@ -11,12 +12,17 @@
 # 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.
+#
 
-LOCAL_PATH := $(call my-dir)
+#
+# This makefile should be included by devices that use Trusty TEE
+# to pull in the baseline set of Trusty specific modules.
+#
 
-include $(CLEAR_VARS)
-LOCAL_MODULE := dumpkey
-LOCAL_SRC_FILES := DumpPublicKey.java
-LOCAL_JAR_MANIFEST := DumpPublicKey.mf
-LOCAL_STATIC_JAVA_LIBRARIES := bouncycastle-host
-include $(BUILD_HOST_JAVA_LIBRARY)
+PRODUCT_PACKAGES += \
+	keystore.trusty \
+	gatekeeper.trusty
+
+PRODUCT_PROPERTY_OVERRIDES += \
+	ro.hardware.keystore=trusty \
+	ro.hardware.gatekeeper=trusty
diff --git a/adf/Android.mk b/trusty/trusty-storage.mk
similarity index 80%
rename from adf/Android.mk
rename to trusty/trusty-storage.mk
index 64d486e..3f26316 100644
--- a/adf/Android.mk
+++ b/trusty/trusty-storage.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2013 The Android Open Source Project
+# 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.
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-LOCAL_PATH := $(my-dir)
 
-include $(call first-makefiles-under,$(LOCAL_PATH))
+PRODUCT_PACKAGES += \
+	storageproxyd \
diff --git a/tzdatacheck/Android.bp b/tzdatacheck/Android.bp
new file mode 100644
index 0000000..00ad141
--- /dev/null
+++ b/tzdatacheck/Android.bp
@@ -0,0 +1,14 @@
+// ========================================================
+// Executable
+// ========================================================
+cc_binary {
+    name: "tzdatacheck",
+    host_supported: true,
+    srcs: ["tzdatacheck.cpp"],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+    ],
+    cflags: ["-Werror"],
+}
diff --git a/tzdatacheck/Android.mk b/tzdatacheck/Android.mk
deleted file mode 100644
index 0e25f7d..0000000
--- a/tzdatacheck/Android.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# ========================================================
-# Executable
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= tzdatacheck.cpp
-LOCAL_MODULE := tzdatacheck
-LOCAL_SHARED_LIBRARIES := libbase libcutils liblog
-LOCAL_CFLAGS := -Werror
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= tzdatacheck.cpp
-LOCAL_MODULE := tzdatacheck
-LOCAL_SHARED_LIBRARIES := libbase libcutils liblog
-LOCAL_CFLAGS := -Werror
-include $(BUILD_HOST_EXECUTABLE)
-