Merge "adb: actually fix the windows build." into klp-dev am: da66b9100a am: 0b4bd3feea am: 55d871c401 am: 8027acd140 am: 7e21e1efeb
am: fa961006fd

Change-Id: I193387ccd84e4425070153a242ab320eb434b44b
diff --git a/CleanSpec.mk b/CleanSpec.mk
index e78fc88..b3661e4 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -54,3 +54,5 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/default.prop)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/default.prop)
 $(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)
diff --git a/README b/README
deleted file mode 100644
index 0083247..0000000
--- a/README
+++ /dev/null
@@ -1,20 +0,0 @@
-
-The system/ directory is intended for pieces of the world that are the
-core of the embedded linux platform at the heart of Android.  These
-essential bits are required for basic booting, operation, and debugging.
-
-They should not depend on libraries outside of system/... (some of them
-do currently -- they need to be updated or changed) and they should not
-be required for the simulator build.
-
-The license for all these pieces should be clean (Apache2, BSD, or MIT).
-
-Currently system/bluetooth/... and system/extra/... have some pieces
-with GPL/LGPL licensed code.
-
-Assorted Issues:
-
-- pppd depends on libutils for logging
-- pppd depends on libcrypt/libcrypto
-- init, linker, debuggerd, toolbox, usbd depend on libcutils
-- should probably rename bionic to libc
diff --git a/ThirdPartyProject.prop b/ThirdPartyProject.prop
deleted file mode 100644
index 18b0594..0000000
--- a/ThirdPartyProject.prop
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2010 Google Inc. All Rights Reserved.
-#Fri Jul 16 10:03:09 PDT 2010
-currentVersion=2.6.32
-version=2.6.32
-isNative=true
-feedurl=http\://kernel.org/pub/linux/kernel/v2.6/
-name=linux
-keywords=linux
-onDevice=true
-homepage=http\://kernel.org
diff --git a/adb/.clang-format b/adb/.clang-format
new file mode 100644
index 0000000..0395c8e
--- /dev/null
+++ b/adb/.clang-format
@@ -0,0 +1,11 @@
+BasedOnStyle: Google
+AllowShortBlocksOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
+UseTab: Never
+PenaltyExcessCharacter: 32
diff --git a/adb/Android.mk b/adb/Android.mk
index b70c153..425bf9b 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -5,83 +5,201 @@
 
 LOCAL_PATH:= $(call my-dir)
 
+ifeq ($(HOST_OS),windows)
+  adb_host_clang := false  # libc++ for mingw not ready yet.
+else
+  adb_host_clang := true
+endif
+
+adb_version := $(shell git -C $(LOCAL_PATH) rev-parse --short=12 HEAD 2>/dev/null)-android
+
+ADB_COMMON_CFLAGS := \
+    -Wall -Werror \
+    -Wno-unused-parameter \
+    -DADB_REVISION='"$(adb_version)"' \
+
+# libadb
+# =========================================================
+
+# Much of adb is duplicated in bootable/recovery/minadb and fastboot. Changes
+# made to adb rarely get ported to the other two, so the trees have diverged a
+# bit. We'd like to stop this because it is a maintenance nightmare, but the
+# divergence makes this difficult to do all at once. For now, we will start
+# small by moving common files into a static library. Hopefully some day we can
+# get enough of adb in here that we no longer need minadb. https://b/17626262
+LIBADB_SRC_FILES := \
+    adb.cpp \
+    adb_auth.cpp \
+    adb_io.cpp \
+    adb_listeners.cpp \
+    adb_utils.cpp \
+    sockets.cpp \
+    transport.cpp \
+    transport_local.cpp \
+    transport_usb.cpp \
+
+LIBADB_TEST_SRCS := \
+    adb_io_test.cpp \
+    adb_utils_test.cpp \
+    transport_test.cpp \
+
+LIBADB_CFLAGS := \
+    $(ADB_COMMON_CFLAGS) \
+    -Wno-missing-field-initializers \
+    -fvisibility=hidden \
+
+LIBADB_darwin_SRC_FILES := \
+    fdevent.cpp \
+    get_my_path_darwin.cpp \
+    usb_osx.cpp \
+
+LIBADB_linux_SRC_FILES := \
+    fdevent.cpp \
+    get_my_path_linux.cpp \
+    usb_linux.cpp \
+
+LIBADB_windows_SRC_FILES := \
+    get_my_path_windows.cpp \
+    sysdeps_win32.cpp \
+    usb_windows.cpp \
+
+include $(CLEAR_VARS)
+LOCAL_CLANG := true
+LOCAL_MODULE := libadbd
+LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=0
+LOCAL_SRC_FILES := \
+    $(LIBADB_SRC_FILES) \
+    adb_auth_client.cpp \
+    fdevent.cpp \
+    jdwp_service.cpp \
+    qemu_tracing.cpp \
+    usb_linux_client.cpp \
+
+LOCAL_SHARED_LIBRARIES := libbase
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_CLANG := $(adb_host_clang)
+LOCAL_MODULE := libadb
+LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=1
+LOCAL_SRC_FILES := \
+    $(LIBADB_SRC_FILES) \
+    $(LIBADB_$(HOST_OS)_SRC_FILES) \
+    adb_auth_host.cpp \
+
+LOCAL_SHARED_LIBRARIES := libbase
+
+# Even though we're building a static library (and thus there's no link step for
+# this to take effect), this adds the SSL includes to our path.
+LOCAL_STATIC_LIBRARIES := libcrypto_static
+
+ifeq ($(HOST_OS),windows)
+    LOCAL_C_INCLUDES += development/host/windows/usb/api/
+endif
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_CLANG := true
+LOCAL_MODULE := adbd_test
+LOCAL_CFLAGS := -DADB_HOST=0 $(LIBADB_CFLAGS)
+LOCAL_SRC_FILES := $(LIBADB_TEST_SRCS)
+LOCAL_STATIC_LIBRARIES := libadbd
+LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
+include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_CLANG := $(adb_host_clang)
+LOCAL_MODULE := adb_test
+LOCAL_CFLAGS := -DADB_HOST=1 $(LIBADB_CFLAGS)
+LOCAL_SRC_FILES := $(LIBADB_TEST_SRCS) services.cpp
+LOCAL_SHARED_LIBRARIES := liblog libbase
+LOCAL_STATIC_LIBRARIES := \
+    libadb \
+    libcrypto_static \
+    libcutils \
+
+ifeq ($(HOST_OS),linux)
+  LOCAL_LDLIBS += -lrt -ldl -lpthread
+endif
+
+ifeq ($(HOST_OS),darwin)
+  LOCAL_LDLIBS += -framework CoreFoundation -framework IOKit
+endif
+
+include $(BUILD_HOST_NATIVE_TEST)
+
+# adb device tracker (used by ddms) test tool
+# =========================================================
+
+ifeq ($(HOST_OS),linux)
+include $(CLEAR_VARS)
+LOCAL_CLANG := $(adb_host_clang)
+LOCAL_MODULE := adb_device_tracker_test
+LOCAL_CFLAGS := -DADB_HOST=1 $(LIBADB_CFLAGS)
+LOCAL_SRC_FILES := test_track_devices.cpp
+LOCAL_SHARED_LIBRARIES := liblog libbase
+LOCAL_STATIC_LIBRARIES := libadb libcrypto_static libcutils
+LOCAL_LDLIBS += -lrt -ldl -lpthread
+include $(BUILD_HOST_EXECUTABLE)
+endif
+
 # adb host tool
 # =========================================================
 include $(CLEAR_VARS)
 
-# Default to a virtual (sockets) usb interface
-USB_SRCS :=
-EXTRA_SRCS :=
-
 ifeq ($(HOST_OS),linux)
-  USB_SRCS := usb_linux.c
-  EXTRA_SRCS := get_my_path_linux.c
   LOCAL_LDLIBS += -lrt -ldl -lpthread
   LOCAL_CFLAGS += -DWORKAROUND_BUG6558362
 endif
 
 ifeq ($(HOST_OS),darwin)
-  USB_SRCS := usb_osx.c
-  EXTRA_SRCS := get_my_path_darwin.c
   LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
-endif
-
-ifeq ($(HOST_OS),freebsd)
-  USB_SRCS := usb_libusb.c
-  EXTRA_SRCS := get_my_path_freebsd.c
-  LOCAL_LDLIBS += -lpthread -lusb
+  LOCAL_CFLAGS += -Wno-sizeof-pointer-memaccess -Wno-unused-parameter
 endif
 
 ifeq ($(HOST_OS),windows)
-  USB_SRCS := usb_windows.c
-  EXTRA_SRCS := get_my_path_windows.c
+  LOCAL_LDLIBS += -lws2_32 -lgdi32
   EXTRA_STATIC_LIBS := AdbWinApi
-  ifneq ($(strip $(USE_CYGWIN)),)
-    # Pure cygwin case
-    LOCAL_LDLIBS += -lpthread -lgdi32
-  endif
-  ifneq ($(strip $(USE_MINGW)),)
-    # MinGW under Linux case
-    LOCAL_LDLIBS += -lws2_32 -lgdi32
-    USE_SYSDEPS_WIN32 := 1
-  endif
-  LOCAL_C_INCLUDES += development/host/windows/usb/api/
 endif
 
+LOCAL_CLANG := $(adb_host_clang)
+
 LOCAL_SRC_FILES := \
-	adb.c \
-	console.c \
-	transport.c \
-	transport_local.c \
-	transport_usb.c \
-	commandline.c \
-	adb_client.c \
-	adb_auth_host.c \
-	sockets.c \
-	services.c \
-	file_sync_client.c \
-	$(EXTRA_SRCS) \
-	$(USB_SRCS) \
-	usb_vendors.c
+    adb_main.cpp \
+    console.cpp \
+    commandline.cpp \
+    adb_client.cpp \
+    services.cpp \
+    file_sync_client.cpp \
 
-LOCAL_C_INCLUDES += external/openssl/include
+LOCAL_CFLAGS += \
+    $(ADB_COMMON_CFLAGS) \
+    -D_GNU_SOURCE \
+    -DADB_HOST=1 \
 
-ifneq ($(USE_SYSDEPS_WIN32),)
-  LOCAL_SRC_FILES += sysdeps_win32.c
-else
-  LOCAL_SRC_FILES += fdevent.c
-endif
-
-LOCAL_CFLAGS += -O2 -g -DADB_HOST=1 -Wall -Wno-unused-parameter -Werror
-LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
 LOCAL_MODULE := adb
 LOCAL_MODULE_TAGS := debug
 
-LOCAL_STATIC_LIBRARIES := libzipfile libunz libcrypto_static $(EXTRA_STATIC_LIBS)
-ifeq ($(USE_SYSDEPS_WIN32),)
-	LOCAL_STATIC_LIBRARIES += libcutils
+LOCAL_STATIC_LIBRARIES := \
+    libadb \
+    libbase \
+    libcrypto_static \
+    libcutils \
+    liblog \
+    $(EXTRA_STATIC_LIBS) \
+
+# libc++ not available on windows yet
+ifneq ($(HOST_OS),windows)
+    LOCAL_CXX_STL := libc++_static
 endif
 
+# Don't add anything here, we don't want additional shared dependencies
+# on the host adb tool, and shared libraries that link against libc++
+# will violate ODR
+LOCAL_SHARED_LIBRARIES :=
+
 include $(BUILD_HOST_EXECUTABLE)
 
 $(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE))
@@ -98,31 +216,27 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := \
-	adb.c \
-	fdevent.c \
-	transport.c \
-	transport_local.c \
-	transport_usb.c \
-	adb_auth_client.c \
-	sockets.c \
-	services.c \
-	file_sync_service.c \
-	jdwp_service.c \
-	framebuffer_service.c \
-	remount_service.c \
-	disable_verity_service.c \
-	usb_linux_client.c
+LOCAL_CLANG := true
 
-LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter -Werror
-LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
+LOCAL_SRC_FILES := \
+    adb_main.cpp \
+    services.cpp \
+    file_sync_service.cpp \
+    framebuffer_service.cpp \
+    remount_service.cpp \
+    set_verity_enable_state_service.cpp \
+
+LOCAL_CFLAGS := \
+    $(ADB_COMMON_CFLAGS) \
+    -DADB_HOST=0 \
+    -D_GNU_SOURCE \
+    -Wno-deprecated-declarations \
+
+LOCAL_CFLAGS += -DALLOW_ADBD_NO_AUTH=$(if $(filter userdebug eng,$(TARGET_BUILD_VARIANT)),1,0)
 
 ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
-LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=1
-endif
-
-ifneq (,$(filter userdebug,$(TARGET_BUILD_VARIANT)))
 LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1
+LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=1
 endif
 
 LOCAL_MODULE := adbd
@@ -130,57 +244,17 @@
 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 system/core/fs_mgr/include
+LOCAL_C_INCLUDES += system/extras/ext4_utils
 
-LOCAL_STATIC_LIBRARIES := liblog \
-	libfs_mgr \
-	libcutils \
-	libc \
-	libmincrypt \
-	libselinux \
-	libext4_utils_static
+LOCAL_STATIC_LIBRARIES := \
+    libadbd \
+    libbase \
+    libfs_mgr \
+    liblog \
+    libcutils \
+    libc \
+    libmincrypt \
+    libselinux \
+    libext4_utils_static \
 
 include $(BUILD_EXECUTABLE)
-
-
-# adb host tool for device-as-host
-# =========================================================
-ifneq ($(SDK_ONLY),true)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-	adb.c \
-	console.c \
-	transport.c \
-	transport_local.c \
-	transport_usb.c \
-	commandline.c \
-	adb_client.c \
-	adb_auth_host.c \
-	sockets.c \
-	services.c \
-	file_sync_client.c \
-	get_my_path_linux.c \
-	usb_linux.c \
-	usb_vendors.c \
-	fdevent.c
-
-LOCAL_CFLAGS := \
-	-O2 \
-	-g \
-	-DADB_HOST=1 \
-	-DADB_HOST_ON_TARGET=1 \
-	-Wall -Wno-unused-parameter -Werror \
-	-D_XOPEN_SOURCE \
-	-D_GNU_SOURCE
-
-LOCAL_C_INCLUDES += external/openssl/include
-
-LOCAL_MODULE := adb
-
-LOCAL_STATIC_LIBRARIES := libzipfile libunz libcutils liblog
-
-LOCAL_SHARED_LIBRARIES := libcrypto
-
-include $(BUILD_EXECUTABLE)
-endif
diff --git a/adb/CPPLINT.cfg b/adb/CPPLINT.cfg
new file mode 100644
index 0000000..9b906e8
--- /dev/null
+++ b/adb/CPPLINT.cfg
@@ -0,0 +1,2 @@
+set noparent
+filter=-build/header_guard,-build/include,-readability/function
diff --git a/adb/adb.c b/adb/adb.c
deleted file mode 100644
index 10a1e0d..0000000
--- a/adb/adb.c
+++ /dev/null
@@ -1,1725 +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.
- */
-
-#define  TRACE_TAG   TRACE_ADB
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <stddef.h>
-#include <string.h>
-#include <time.h>
-#include <sys/time.h>
-#include <stdint.h>
-
-#include "sysdeps.h"
-#include "adb.h"
-#include "adb_auth.h"
-
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-
-#if !ADB_HOST
-#include <cutils/properties.h>
-#include <private/android_filesystem_config.h>
-#include <sys/capability.h>
-#include <sys/mount.h>
-#include <sys/prctl.h>
-#include <getopt.h>
-#include <selinux/selinux.h>
-#else
-#include "usb_vendors.h"
-#endif
-
-#if ADB_TRACE
-ADB_MUTEX_DEFINE( D_lock );
-#endif
-
-int HOST = 0;
-int gListenAll = 0;
-
-static int auth_enabled = 0;
-
-#if !ADB_HOST
-static const char *adb_device_banner = "device";
-static const char *root_seclabel = NULL;
-#endif
-
-void fatal(const char *fmt, ...)
-{
-    va_list ap;
-    va_start(ap, fmt);
-    fprintf(stderr, "error: ");
-    vfprintf(stderr, fmt, ap);
-    fprintf(stderr, "\n");
-    va_end(ap);
-    exit(-1);
-}
-
-void fatal_errno(const char *fmt, ...)
-{
-    va_list ap;
-    va_start(ap, fmt);
-    fprintf(stderr, "error: %s: ", strerror(errno));
-    vfprintf(stderr, fmt, ap);
-    fprintf(stderr, "\n");
-    va_end(ap);
-    exit(-1);
-}
-
-int   adb_trace_mask;
-
-/* read a comma/space/colum/semi-column separated list of tags
- * from the ADB_TRACE environment variable and build the trace
- * mask from it. note that '1' and 'all' are special cases to
- * enable all tracing
- */
-void  adb_trace_init(void)
-{
-    const char*  p = getenv("ADB_TRACE");
-    const char*  q;
-
-    static const struct {
-        const char*  tag;
-        int           flag;
-    } tags[] = {
-        { "1", 0 },
-        { "all", 0 },
-        { "adb", TRACE_ADB },
-        { "sockets", TRACE_SOCKETS },
-        { "packets", TRACE_PACKETS },
-        { "rwx", TRACE_RWX },
-        { "usb", TRACE_USB },
-        { "sync", TRACE_SYNC },
-        { "sysdeps", TRACE_SYSDEPS },
-        { "transport", TRACE_TRANSPORT },
-        { "jdwp", TRACE_JDWP },
-        { "services", TRACE_SERVICES },
-        { "auth", TRACE_AUTH },
-        { NULL, 0 }
-    };
-
-    if (p == NULL)
-            return;
-
-    /* use a comma/column/semi-colum/space separated list */
-    while (*p) {
-        int  len, tagn;
-
-        q = strpbrk(p, " ,:;");
-        if (q == NULL) {
-            q = p + strlen(p);
-        }
-        len = q - p;
-
-        for (tagn = 0; tags[tagn].tag != NULL; tagn++)
-        {
-            int  taglen = strlen(tags[tagn].tag);
-
-            if (len == taglen && !memcmp(tags[tagn].tag, p, len) )
-            {
-                int  flag = tags[tagn].flag;
-                if (flag == 0) {
-                    adb_trace_mask = ~0;
-                    return;
-                }
-                adb_trace_mask |= (1 << flag);
-                break;
-            }
-        }
-        p = q;
-        if (*p)
-            p++;
-    }
-}
-
-#if !ADB_HOST
-/*
- * Implements ADB tracing inside the emulator.
- */
-
-#include <stdarg.h>
-
-/*
- * 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.
- */
-
-#undef open
-#undef write
-#define open    adb_open
-#define write   adb_write
-#include <hardware/qemu_pipe.h>
-#undef open
-#undef write
-#define open    ___xxx_open
-#define write   ___xxx_write
-
-/* A handle to adb-debug qemud service in the emulator. */
-int   adb_debug_qemu = -1;
-
-/* Initializes connection with the adb-debug qemud service in the emulator. */
-static int adb_qemu_trace_init(void)
-{
-    char con_name[32];
-
-    if (adb_debug_qemu >= 0) {
-        return 0;
-    }
-
-    /* adb debugging QEMUD service connection request. */
-    snprintf(con_name, sizeof(con_name), "qemud:adb-debug");
-    adb_debug_qemu = qemu_pipe_open(con_name);
-    return (adb_debug_qemu >= 0) ? 0 : -1;
-}
-
-void adb_qemu_trace(const char* fmt, ...)
-{
-    va_list args;
-    va_start(args, fmt);
-    char msg[1024];
-
-    if (adb_debug_qemu >= 0) {
-        vsnprintf(msg, sizeof(msg), fmt, args);
-        adb_write(adb_debug_qemu, msg, strlen(msg));
-    }
-}
-#endif  /* !ADB_HOST */
-
-apacket *get_apacket(void)
-{
-    apacket *p = malloc(sizeof(apacket));
-    if(p == 0) fatal("failed to allocate an apacket");
-    memset(p, 0, sizeof(apacket) - MAX_PAYLOAD);
-    return p;
-}
-
-void put_apacket(apacket *p)
-{
-    free(p);
-}
-
-void handle_online(atransport *t)
-{
-    D("adb: online\n");
-    t->online = 1;
-}
-
-void handle_offline(atransport *t)
-{
-    D("adb: offline\n");
-    //Close the associated usb
-    t->online = 0;
-    run_transport_disconnects(t);
-}
-
-#if DEBUG_PACKETS
-#define DUMPMAX 32
-void print_packet(const char *label, apacket *p)
-{
-    char *tag;
-    char *x;
-    unsigned count;
-
-    switch(p->msg.command){
-    case A_SYNC: tag = "SYNC"; break;
-    case A_CNXN: tag = "CNXN" ; break;
-    case A_OPEN: tag = "OPEN"; break;
-    case A_OKAY: tag = "OKAY"; break;
-    case A_CLSE: tag = "CLSE"; break;
-    case A_WRTE: tag = "WRTE"; break;
-    case A_AUTH: tag = "AUTH"; break;
-    default: tag = "????"; break;
-    }
-
-    fprintf(stderr, "%s: %s %08x %08x %04x \"",
-            label, tag, p->msg.arg0, p->msg.arg1, p->msg.data_length);
-    count = p->msg.data_length;
-    x = (char*) p->data;
-    if(count > DUMPMAX) {
-        count = DUMPMAX;
-        tag = "\n";
-    } else {
-        tag = "\"\n";
-    }
-    while(count-- > 0){
-        if((*x >= ' ') && (*x < 127)) {
-            fputc(*x, stderr);
-        } else {
-            fputc('.', stderr);
-        }
-        x++;
-    }
-    fputs(tag, stderr);
-}
-#endif
-
-static void send_ready(unsigned local, unsigned remote, atransport *t)
-{
-    D("Calling send_ready \n");
-    apacket *p = get_apacket();
-    p->msg.command = A_OKAY;
-    p->msg.arg0 = local;
-    p->msg.arg1 = remote;
-    send_packet(p, t);
-}
-
-static void send_close(unsigned local, unsigned remote, atransport *t)
-{
-    D("Calling send_close \n");
-    apacket *p = get_apacket();
-    p->msg.command = A_CLSE;
-    p->msg.arg0 = local;
-    p->msg.arg1 = remote;
-    send_packet(p, t);
-}
-
-static size_t fill_connect_data(char *buf, size_t bufsize)
-{
-#if ADB_HOST
-    return snprintf(buf, bufsize, "host::") + 1;
-#else
-    static const char *cnxn_props[] = {
-        "ro.product.name",
-        "ro.product.model",
-        "ro.product.device",
-    };
-    static const int num_cnxn_props = ARRAY_SIZE(cnxn_props);
-    int i;
-    size_t remaining = bufsize;
-    size_t len;
-
-    len = snprintf(buf, remaining, "%s::", adb_device_banner);
-    remaining -= len;
-    buf += len;
-    for (i = 0; i < num_cnxn_props; i++) {
-        char value[PROPERTY_VALUE_MAX];
-        property_get(cnxn_props[i], value, "");
-        len = snprintf(buf, remaining, "%s=%s;", cnxn_props[i], value);
-        remaining -= len;
-        buf += len;
-    }
-
-    return bufsize - remaining + 1;
-#endif
-}
-
-#if !ADB_HOST
-static void send_msg_with_header(int fd, const char* msg, size_t msglen) {
-    char header[5];
-    if (msglen > 0xffff)
-        msglen = 0xffff;
-    snprintf(header, sizeof(header), "%04x", (unsigned)msglen);
-    writex(fd, header, 4);
-    writex(fd, msg, msglen);
-}
-#endif
-
-static void send_msg_with_okay(int fd, const char* msg, size_t msglen) {
-    char header[9];
-    if (msglen > 0xffff)
-        msglen = 0xffff;
-    snprintf(header, sizeof(header), "OKAY%04x", (unsigned)msglen);
-    writex(fd, header, 8);
-    writex(fd, msg, msglen);
-}
-
-static void send_connect(atransport *t)
-{
-    D("Calling send_connect \n");
-    apacket *cp = get_apacket();
-    cp->msg.command = A_CNXN;
-    cp->msg.arg0 = A_VERSION;
-    cp->msg.arg1 = MAX_PAYLOAD;
-    cp->msg.data_length = fill_connect_data((char *)cp->data,
-                                            sizeof(cp->data));
-    send_packet(cp, t);
-}
-
-void send_auth_request(atransport *t)
-{
-    D("Calling send_auth_request\n");
-    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\n", 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);
-}
-
-static void send_auth_response(uint8_t *token, size_t token_size, atransport *t)
-{
-    D("Calling send_auth_response\n");
-    apacket *p = get_apacket();
-    int ret;
-
-    ret = adb_auth_sign(t->key, token, token_size, p->data);
-    if (!ret) {
-        D("Error signing the token\n");
-        put_apacket(p);
-        return;
-    }
-
-    p->msg.command = A_AUTH;
-    p->msg.arg0 = ADB_AUTH_SIGNATURE;
-    p->msg.data_length = ret;
-    send_packet(p, t);
-}
-
-static void send_auth_publickey(atransport *t)
-{
-    D("Calling send_auth_publickey\n");
-    apacket *p = get_apacket();
-    int ret;
-
-    ret = adb_auth_get_userkey(p->data, sizeof(p->data));
-    if (!ret) {
-        D("Failed to get user public key\n");
-        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);
-}
-
-static char *connection_state_name(atransport *t)
-{
-    if (t == NULL) {
-        return "unknown";
-    }
-
-    switch(t->connection_state) {
-    case CS_BOOTLOADER:
-        return "bootloader";
-    case CS_DEVICE:
-        return "device";
-    case CS_RECOVERY:
-        return "recovery";
-    case CS_SIDELOAD:
-        return "sideload";
-    case CS_OFFLINE:
-        return "offline";
-    case CS_UNAUTHORIZED:
-        return "unauthorized";
-    default:
-        return "unknown";
-    }
-}
-
-/* qual_overwrite is used to overwrite a qualifier string.  dst is a
- * pointer to a char pointer.  It is assumed that if *dst is non-NULL, it
- * was malloc'ed and needs to freed.  *dst will be set to a dup of src.
- */
-static void qual_overwrite(char **dst, const char *src)
-{
-    if (!dst)
-        return;
-
-    free(*dst);
-    *dst = NULL;
-
-    if (!src || !*src)
-        return;
-
-    *dst = strdup(src);
-}
-
-void parse_banner(char *banner, atransport *t)
-{
-    static const char *prop_seps = ";";
-    static const char key_val_sep = '=';
-    char *cp;
-    char *type;
-
-    D("parse_banner: %s\n", banner);
-    type = banner;
-    cp = strchr(type, ':');
-    if (cp) {
-        *cp++ = 0;
-        /* Nothing is done with second field. */
-        cp = strchr(cp, ':');
-        if (cp) {
-            char *save;
-            char *key;
-            key = adb_strtok_r(cp + 1, prop_seps, &save);
-            while (key) {
-                cp = strchr(key, key_val_sep);
-                if (cp) {
-                    *cp++ = '\0';
-                    if (!strcmp(key, "ro.product.name"))
-                        qual_overwrite(&t->product, cp);
-                    else if (!strcmp(key, "ro.product.model"))
-                        qual_overwrite(&t->model, cp);
-                    else if (!strcmp(key, "ro.product.device"))
-                        qual_overwrite(&t->device, cp);
-                }
-                key = adb_strtok_r(NULL, prop_seps, &save);
-            }
-        }
-    }
-
-    if(!strcmp(type, "bootloader")){
-        D("setting connection_state to CS_BOOTLOADER\n");
-        t->connection_state = CS_BOOTLOADER;
-        update_transports();
-        return;
-    }
-
-    if(!strcmp(type, "device")) {
-        D("setting connection_state to CS_DEVICE\n");
-        t->connection_state = CS_DEVICE;
-        update_transports();
-        return;
-    }
-
-    if(!strcmp(type, "recovery")) {
-        D("setting connection_state to CS_RECOVERY\n");
-        t->connection_state = CS_RECOVERY;
-        update_transports();
-        return;
-    }
-
-    if(!strcmp(type, "sideload")) {
-        D("setting connection_state to CS_SIDELOAD\n");
-        t->connection_state = CS_SIDELOAD;
-        update_transports();
-        return;
-    }
-
-    t->connection_state = CS_HOST;
-}
-
-void handle_packet(apacket *p, atransport *t)
-{
-    asocket *s;
-
-    D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0],
-            ((char*) (&(p->msg.command)))[1],
-            ((char*) (&(p->msg.command)))[2],
-            ((char*) (&(p->msg.command)))[3]);
-    print_packet("recv", p);
-
-    switch(p->msg.command){
-    case A_SYNC:
-        if(p->msg.arg0){
-            send_packet(p, t);
-            if(HOST) send_connect(t);
-        } else {
-            t->connection_state = CS_OFFLINE;
-            handle_offline(t);
-            send_packet(p, t);
-        }
-        return;
-
-    case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
-            /* XXX verify version, etc */
-        if(t->connection_state != CS_OFFLINE) {
-            t->connection_state = CS_OFFLINE;
-            handle_offline(t);
-        }
-
-        parse_banner((char*) p->data, t);
-
-        if (HOST || !auth_enabled) {
-            handle_online(t);
-            if(!HOST) send_connect(t);
-        } else {
-            send_auth_request(t);
-        }
-        break;
-
-    case A_AUTH:
-        if (p->msg.arg0 == ADB_AUTH_TOKEN) {
-            t->connection_state = CS_UNAUTHORIZED;
-            t->key = adb_auth_nextkey(t->key);
-            if (t->key) {
-                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;
-
-    case A_OPEN: /* OPEN(local-id, 0, "destination") */
-        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);
-            if(s == 0) {
-                send_close(0, p->msg.arg0, t);
-            } else {
-                s->peer = create_remote_socket(p->msg.arg0, t);
-                s->peer->peer = s;
-                send_ready(s->id, s->peer->id, t);
-                s->ready(s);
-            }
-        }
-        break;
-
-    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))) {
-                if(s->peer == 0) {
-                    /* On first READY message, create the connection. */
-                    s->peer = create_remote_socket(p->msg.arg0, t);
-                    s->peer->peer = s;
-                    s->ready(s);
-                } else if (s->peer->id == p->msg.arg0) {
-                    /* Other READY messages must use the same local-id */
-                    s->ready(s);
-                } else {
-                    D("Invalid A_OKAY(%d,%d), expected A_OKAY(%d,%d) on transport %s\n",
-                      p->msg.arg0, p->msg.arg1, s->peer->id, p->msg.arg1, t->serial);
-                }
-            }
-        }
-        break;
-
-    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))) {
-                /* 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
-                 * CLOSE() operations.
-                 *
-                 * This is bad because it means a compromised adbd could
-                 * send packets to close connections between the host and
-                 * other devices. To avoid this, only allow this if the local
-                 * socket has a peer on the same transport.
-                 */
-                if (p->msg.arg0 == 0 && s->peer && s->peer->transport != t) {
-                    D("Invalid A_CLSE(0, %u) from transport %s, expected transport %s\n",
-                      p->msg.arg1, t->serial, s->peer->transport->serial);
-                } else {
-                    s->close(s);
-                }
-            }
-        }
-        break;
-
-    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))) {
-                unsigned rid = p->msg.arg0;
-                p->len = p->msg.data_length;
-
-                if(s->enqueue(s, p) == 0) {
-                    D("Enqueue the socket\n");
-                    send_ready(s->id, rid, t);
-                }
-                return;
-            }
-        }
-        break;
-
-    default:
-        printf("handle_packet: what is %08x?!\n", p->msg.command);
-    }
-
-    put_apacket(p);
-}
-
-alistener listener_list = {
-    .next = &listener_list,
-    .prev = &listener_list,
-};
-
-static void ss_listener_event_func(int _fd, unsigned ev, void *_l)
-{
-    asocket *s;
-
-    if(ev & FDE_READ) {
-        struct sockaddr addr;
-        socklen_t alen;
-        int fd;
-
-        alen = sizeof(addr);
-        fd = adb_socket_accept(_fd, &addr, &alen);
-        if(fd < 0) return;
-
-        adb_socket_setbufsize(fd, CHUNK_SIZE);
-
-        s = create_local_socket(fd);
-        if(s) {
-            connect_to_smartsocket(s);
-            return;
-        }
-
-        adb_close(fd);
-    }
-}
-
-static void listener_event_func(int _fd, unsigned ev, void *_l)
-{
-    alistener *l = _l;
-    asocket *s;
-
-    if(ev & FDE_READ) {
-        struct sockaddr addr;
-        socklen_t alen;
-        int fd;
-
-        alen = sizeof(addr);
-        fd = adb_socket_accept(_fd, &addr, &alen);
-        if(fd < 0) return;
-
-        s = create_local_socket(fd);
-        if(s) {
-            s->transport = l->transport;
-            connect_to_remote(s, l->connect_to);
-            return;
-        }
-
-        adb_close(fd);
-    }
-}
-
-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) {
-        remove_transport_disconnect(l->transport, &l->disconnect);
-    }
-    free(l);
-}
-
-static void listener_disconnect(void*  _l, atransport*  t)
-{
-    alistener*  l = _l;
-
-    free_listener(l);
-}
-
-int local_name_to_fd(const char *name)
-{
-    int port;
-
-    if(!strncmp("tcp:", name, 4)){
-        int  ret;
-        port = atoi(name + 4);
-
-        if (gListenAll > 0) {
-            ret = socket_inaddr_any_server(port, SOCK_STREAM);
-        } else {
-            ret = socket_loopback_server(port, SOCK_STREAM);
-        }
-
-        return ret;
-    }
-#ifndef HAVE_WIN32_IPC  /* no Unix-domain sockets on Win32 */
-    // It's non-sensical to support the "reserved" space on the adb host side
-    if(!strncmp(name, "local:", 6)) {
-        return socket_local_server(name + 6,
-                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
-    } else if(!strncmp(name, "localabstract:", 14)) {
-        return socket_local_server(name + 14,
-                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
-    } else if(!strncmp(name, "localfilesystem:", 16)) {
-        return socket_local_server(name + 16,
-                ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
-    }
-
-#endif
-    printf("unknown local portname '%s'\n", name);
-    return -1;
-}
-
-// Write a single line describing a listener to a user-provided buffer.
-// Appends a trailing zero, even in case of truncation, but the function
-// returns the full line length.
-// If |buffer| is NULL, does not write but returns required size.
-static int format_listener(alistener* l, char* buffer, size_t buffer_len) {
-    // Format is simply:
-    //
-    //  <device-serial> " " <local-name> " " <remote-name> "\n"
-    //
-    int local_len = strlen(l->local_name);
-    int connect_len = strlen(l->connect_to);
-    int serial_len = strlen(l->transport->serial);
-
-    if (buffer != NULL) {
-        snprintf(buffer, buffer_len, "%s %s %s\n",
-                l->transport->serial, l->local_name, l->connect_to);
-    }
-    // NOTE: snprintf() on Windows returns -1 in case of truncation, so
-    // return the computed line length instead.
-    return local_len + connect_len + serial_len + 3;
-}
-
-// Write the list of current listeners (network redirections) into a
-// user-provided buffer. Appends a trailing zero, even in case of
-// trunctaion, but return the full size in bytes.
-// If |buffer| is NULL, does not write but returns required size.
-static int format_listeners(char* buf, size_t buflen)
-{
-    alistener* l;
-    int result = 0;
-    for (l = listener_list.next; l != &listener_list; l = l->next) {
-        // Ignore special listeners like those for *smartsocket*
-        if (l->connect_to[0] == '*')
-          continue;
-        int len = format_listener(l, buf, buflen);
-        // Ensure there is space for the trailing zero.
-        result += len;
-        if (buf != NULL) {
-          buf += len;
-          buflen -= len;
-          if (buflen <= 0)
-              break;
-        }
-    }
-    return result;
-}
-
-static int 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)) {
-            listener_disconnect(l, l->transport);
-            return 0;
-        }
-    }
-    return -1;
-}
-
-static void remove_all_listeners(void)
-{
-    alistener *l, *l_next;
-    for (l = listener_list.next; l != &listener_list; l = l_next) {
-        l_next = l->next;
-        // Never remove smart sockets.
-        if (l->connect_to[0] == '*')
-            continue;
-        listener_disconnect(l, l->transport);
-    }
-}
-
-// error/status codes for install_listener.
-typedef enum {
-  INSTALL_STATUS_OK = 0,
-  INSTALL_STATUS_INTERNAL_ERROR = -1,
-  INSTALL_STATUS_CANNOT_BIND = -2,
-  INSTALL_STATUS_CANNOT_REBIND = -3,
-} install_status_t;
-
-static install_status_t install_listener(const char *local_name,
-                                         const char *connect_to,
-                                         atransport* transport,
-                                         int no_rebind)
-{
-    alistener *l;
-
-    //printf("install_listener('%s','%s')\n", local_name, connect_to);
-
-    for(l = listener_list.next; l != &listener_list; l = l->next){
-        if(strcmp(local_name, l->local_name) == 0) {
-            char *cto;
-
-                /* can't repurpose a smartsocket */
-            if(l->connect_to[0] == '*') {
-                return INSTALL_STATUS_INTERNAL_ERROR;
-            }
-
-                /* can't repurpose a listener if 'no_rebind' is true */
-            if (no_rebind) {
-                return INSTALL_STATUS_CANNOT_REBIND;
-            }
-
-            cto = strdup(connect_to);
-            if(cto == 0) {
-                return INSTALL_STATUS_INTERNAL_ERROR;
-            }
-
-            //printf("rebinding '%s' to '%s'\n", local_name, connect_to);
-            free((void*) l->connect_to);
-            l->connect_to = cto;
-            if (l->transport != transport) {
-                remove_transport_disconnect(l->transport, &l->disconnect);
-                l->transport = transport;
-                add_transport_disconnect(l->transport, &l->disconnect);
-            }
-            return INSTALL_STATUS_OK;
-        }
-    }
-
-    if((l = calloc(1, sizeof(alistener))) == 0) goto nomem;
-    if((l->local_name = strdup(local_name)) == 0) goto nomem;
-    if((l->connect_to = strdup(connect_to)) == 0) goto nomem;
-
-
-    l->fd = local_name_to_fd(local_name);
-    if(l->fd < 0) {
-        free((void*) l->local_name);
-        free((void*) l->connect_to);
-        free(l);
-        printf("cannot bind '%s'\n", local_name);
-        return -2;
-    }
-
-    close_on_exec(l->fd);
-    if(!strcmp(l->connect_to, "*smartsocket*")) {
-        fdevent_install(&l->fde, l->fd, ss_listener_event_func, l);
-    } else {
-        fdevent_install(&l->fde, l->fd, listener_event_func, l);
-    }
-    fdevent_set(&l->fde, FDE_READ);
-
-    l->next = &listener_list;
-    l->prev = listener_list.prev;
-    l->next->prev = l;
-    l->prev->next = l;
-    l->transport = transport;
-
-    if (transport) {
-        l->disconnect.opaque = l;
-        l->disconnect.func   = listener_disconnect;
-        add_transport_disconnect(transport, &l->disconnect);
-    }
-    return INSTALL_STATUS_OK;
-
-nomem:
-    fatal("cannot allocate listener");
-    return INSTALL_STATUS_INTERNAL_ERROR;
-}
-
-#ifdef HAVE_WIN32_PROC
-static BOOL WINAPI ctrlc_handler(DWORD type)
-{
-    exit(STATUS_CONTROL_C_EXIT);
-    return TRUE;
-}
-#endif
-
-static void adb_cleanup(void)
-{
-    usb_cleanup();
-}
-
-void start_logging(void)
-{
-#ifdef HAVE_WIN32_PROC
-    char    temp[ MAX_PATH ];
-    FILE*   fnul;
-    FILE*   flog;
-
-    GetTempPath( sizeof(temp) - 8, temp );
-    strcat( temp, "adb.log" );
-
-    /* Win32 specific redirections */
-    fnul = fopen( "NUL", "rt" );
-    if (fnul != NULL)
-        stdin[0] = fnul[0];
-
-    flog = fopen( temp, "at" );
-    if (flog == NULL)
-        flog = fnul;
-
-    setvbuf( flog, NULL, _IONBF, 0 );
-
-    stdout[0] = flog[0];
-    stderr[0] = flog[0];
-    fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
-#else
-    int fd;
-
-    fd = unix_open("/dev/null", O_RDONLY);
-    dup2(fd, 0);
-    adb_close(fd);
-
-    fd = unix_open("/tmp/adb.log", O_WRONLY | O_CREAT | O_APPEND, 0640);
-    if(fd < 0) {
-        fd = unix_open("/dev/null", O_WRONLY);
-    }
-    dup2(fd, 1);
-    dup2(fd, 2);
-    adb_close(fd);
-    fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
-#endif
-}
-
-#if !ADB_HOST
-void start_device_log(void)
-{
-    int fd;
-    char    path[PATH_MAX];
-    struct tm now;
-    time_t t;
-    char value[PROPERTY_VALUE_MAX];
-
-    // read the trace mask from persistent property persist.adb.trace_mask
-    // give up if the property is not set or cannot be parsed
-    property_get("persist.adb.trace_mask", value, "");
-    if (sscanf(value, "%x", &adb_trace_mask) != 1)
-        return;
-
-    adb_mkdir("/data/adb", 0775);
-    tzset();
-    time(&t);
-    localtime_r(&t, &now);
-    strftime(path, sizeof(path),
-                "/data/adb/adb-%Y-%m-%d-%H-%M-%S.txt",
-                &now);
-    fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0640);
-    if (fd < 0)
-        return;
-
-    // redirect stdout and stderr to the log file
-    dup2(fd, 1);
-    dup2(fd, 2);
-    fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
-    adb_close(fd);
-
-    fd = unix_open("/dev/null", O_RDONLY);
-    dup2(fd, 0);
-    adb_close(fd);
-}
-#endif
-
-#if ADB_HOST
-
-#ifdef WORKAROUND_BUG6558362
-#include <sched.h>
-#define AFFINITY_ENVVAR "ADB_CPU_AFFINITY_BUG6558362"
-void adb_set_affinity(void)
-{
-   cpu_set_t cpu_set;
-   const char* cpunum_str = getenv(AFFINITY_ENVVAR);
-   char* strtol_res;
-   int cpu_num;
-
-   if (!cpunum_str || !*cpunum_str)
-       return;
-   cpu_num = strtol(cpunum_str, &strtol_res, 0);
-   if (*strtol_res != '\0')
-     fatal("bad number (%s) in env var %s. Expecting 0..n.\n", cpunum_str, AFFINITY_ENVVAR);
-
-   sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
-   D("orig cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
-   CPU_ZERO(&cpu_set);
-   CPU_SET(cpu_num, &cpu_set);
-   sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
-   sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
-   D("new cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
-}
-#endif
-
-int launch_server(int server_port)
-{
-#ifdef HAVE_WIN32_PROC
-    /* we need to start the server in the background                    */
-    /* we create a PIPE that will be used to wait for the server's "OK" */
-    /* message since the pipe handles must be inheritable, we use a     */
-    /* security attribute                                               */
-    HANDLE                pipe_read, pipe_write;
-    HANDLE                stdout_handle, stderr_handle;
-    SECURITY_ATTRIBUTES   sa;
-    STARTUPINFO           startup;
-    PROCESS_INFORMATION   pinfo;
-    char                  program_path[ MAX_PATH ];
-    int                   ret;
-
-    sa.nLength = sizeof(sa);
-    sa.lpSecurityDescriptor = NULL;
-    sa.bInheritHandle = TRUE;
-
-    /* create pipe, and ensure its read handle isn't inheritable */
-    ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 );
-    if (!ret) {
-        fprintf(stderr, "CreatePipe() failure, error %ld\n", GetLastError() );
-        return -1;
-    }
-
-    SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 );
-
-    /* Some programs want to launch an adb command and collect its output by
-     * calling CreateProcess with inheritable stdout/stderr handles, then
-     * using read() to get its output. When this happens, the stdout/stderr
-     * handles passed to the adb client process will also be inheritable.
-     * When starting the adb server here, care must be taken to reset them
-     * to non-inheritable.
-     * Otherwise, something bad happens: even if the adb command completes,
-     * the calling process is stuck while read()-ing from the stdout/stderr
-     * descriptors, because they're connected to corresponding handles in the
-     * adb server process (even if the latter never uses/writes to them).
-     */
-    stdout_handle = GetStdHandle( STD_OUTPUT_HANDLE );
-    stderr_handle = GetStdHandle( STD_ERROR_HANDLE );
-    if (stdout_handle != INVALID_HANDLE_VALUE) {
-        SetHandleInformation( stdout_handle, HANDLE_FLAG_INHERIT, 0 );
-    }
-    if (stderr_handle != INVALID_HANDLE_VALUE) {
-        SetHandleInformation( stderr_handle, HANDLE_FLAG_INHERIT, 0 );
-    }
-
-    ZeroMemory( &startup, sizeof(startup) );
-    startup.cb = sizeof(startup);
-    startup.hStdInput  = GetStdHandle( STD_INPUT_HANDLE );
-    startup.hStdOutput = pipe_write;
-    startup.hStdError  = GetStdHandle( STD_ERROR_HANDLE );
-    startup.dwFlags    = STARTF_USESTDHANDLES;
-
-    ZeroMemory( &pinfo, sizeof(pinfo) );
-
-    /* get path of current program */
-    GetModuleFileName( NULL, program_path, sizeof(program_path) );
-
-    ret = CreateProcess(
-            program_path,                              /* program path  */
-            "adb fork-server server",
-                                    /* the fork-server argument will set the
-                                       debug = 2 in the child           */
-            NULL,                   /* process handle is not inheritable */
-            NULL,                    /* thread handle is not inheritable */
-            TRUE,                          /* yes, inherit some handles */
-            DETACHED_PROCESS, /* the new process doesn't have a console */
-            NULL,                     /* use parent's environment block */
-            NULL,                    /* use parent's starting directory */
-            &startup,                 /* startup info, i.e. std handles */
-            &pinfo );
-
-    CloseHandle( pipe_write );
-
-    if (!ret) {
-        fprintf(stderr, "CreateProcess failure, error %ld\n", GetLastError() );
-        CloseHandle( pipe_read );
-        return -1;
-    }
-
-    CloseHandle( pinfo.hProcess );
-    CloseHandle( pinfo.hThread );
-
-    /* wait for the "OK\n" message */
-    {
-        char  temp[3];
-        DWORD  count;
-
-        ret = ReadFile( pipe_read, temp, 3, &count, NULL );
-        CloseHandle( pipe_read );
-        if ( !ret ) {
-            fprintf(stderr, "could not read ok from ADB Server, error = %ld\n", GetLastError() );
-            return -1;
-        }
-        if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
-            fprintf(stderr, "ADB server didn't ACK\n" );
-            return -1;
-        }
-    }
-#elif defined(HAVE_FORKEXEC)
-    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 fd[1] will get mapped to stderr in the child.
-    if (pipe(fd)) {
-        fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno);
-        return -1;
-    }
-    get_my_path(path, PATH_MAX);
-    pid_t pid = fork();
-    if(pid < 0) return -1;
-
-    if (pid == 0) {
-        // child side of the fork
-
-        // redirect stderr to the pipe
-        // we use stderr instead of stdout due to stdout's buffering behavior.
-        adb_close(fd[0]);
-        dup2(fd[1], STDERR_FILENO);
-        adb_close(fd[1]);
-
-        char str_port[30];
-        snprintf(str_port, sizeof(str_port), "%d",  server_port);
-        // child process
-        int result = execl(path, "adb", "-P", str_port, "fork-server", "server", NULL);
-        // this should not return
-        fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
-    } else  {
-        // parent side of the fork
-
-        char  temp[3];
-
-        temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';
-        // wait for the "OK\n" message
-        adb_close(fd[1]);
-        int ret = adb_read(fd[0], temp, 3);
-        int saved_errno = errno;
-        adb_close(fd[0]);
-        if (ret < 0) {
-            fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", saved_errno);
-            return -1;
-        }
-        if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
-            fprintf(stderr, "ADB server didn't ACK\n" );
-            return -1;
-        }
-
-        setsid();
-    }
-#else
-#error "cannot implement background server start on this platform"
-#endif
-    return 0;
-}
-#endif
-
-/* Constructs a local name of form tcp:port.
- * target_str points to the target string, it's content will be overwritten.
- * target_size is the capacity of the target string.
- * server_port is the port number to use for the local name.
- */
-void build_local_name(char* target_str, size_t target_size, int server_port)
-{
-  snprintf(target_str, target_size, "tcp:%d", server_port);
-}
-
-#if !ADB_HOST
-
-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) {
-        return;
-    }
-#endif
-    int i;
-    for (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;
-        }
-        int err = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
-
-        // Some kernels don't have file capabilities compiled in, and
-        // prctl(PR_CAPBSET_DROP) returns EINVAL. Don't automatically
-        // die when we see such misconfigured kernels.
-        if ((err < 0) && (errno != EINVAL)) {
-            exit(1);
-        }
-    }
-}
-
-static int should_drop_privileges() {
-#ifndef ALLOW_ADBD_ROOT
-    return 1;
-#else /* ALLOW_ADBD_ROOT */
-    int secure = 0;
-    char value[PROPERTY_VALUE_MAX];
-
-   /* run adbd in secure mode if ro.secure is set and
-    ** we are not in the emulator
-    */
-    property_get("ro.kernel.qemu", value, "");
-    if (strcmp(value, "1") != 0) {
-        property_get("ro.secure", value, "1");
-        if (strcmp(value, "1") == 0) {
-            // don't run as root if ro.secure is set...
-            secure = 1;
-
-            // ... except we allow running as root in userdebug builds if the
-            // service.adb.root property has been set by the "adb root" command
-            property_get("ro.debuggable", value, "");
-            if (strcmp(value, "1") == 0) {
-                property_get("service.adb.root", value, "");
-                if (strcmp(value, "1") == 0) {
-                    secure = 0;
-                }
-            }
-        }
-    }
-    return secure;
-#endif /* ALLOW_ADBD_ROOT */
-}
-#endif /* !ADB_HOST */
-
-int adb_main(int is_daemon, int server_port)
-{
-#if !ADB_HOST
-    int port;
-    char value[PROPERTY_VALUE_MAX];
-
-    umask(000);
-#endif
-
-    atexit(adb_cleanup);
-#ifdef HAVE_WIN32_PROC
-    SetConsoleCtrlHandler( ctrlc_handler, TRUE );
-#elif defined(HAVE_FORKEXEC)
-    // No SIGCHLD. Let the service subproc handle its children.
-    signal(SIGPIPE, SIG_IGN);
-#endif
-
-    init_transport_registration();
-
-#if ADB_HOST
-    HOST = 1;
-
-#ifdef WORKAROUND_BUG6558362
-    if(is_daemon) adb_set_affinity();
-#endif
-    usb_vendors_init();
-    usb_init();
-    local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
-    adb_auth_init();
-
-    char local_name[30];
-    build_local_name(local_name, sizeof(local_name), server_port);
-    if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
-        exit(1);
-    }
-#else
-    property_get("ro.adb.secure", value, "0");
-    auth_enabled = !strcmp(value, "1");
-    if (auth_enabled)
-        adb_auth_init();
-
-    // Our external storage path may be different than apps, since
-    // we aren't able to bind mount after dropping root.
-    const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE");
-    if (NULL != adb_external_storage) {
-        setenv("EXTERNAL_STORAGE", adb_external_storage, 1);
-    } else {
-        D("Warning: ADB_EXTERNAL_STORAGE is not set.  Leaving EXTERNAL_STORAGE"
-          " unchanged.\n");
-    }
-
-    /* add extra groups:
-    ** AID_ADB to access the USB driver
-    ** AID_LOG to read system logs (adb logcat)
-    ** AID_INPUT to diagnose input issues (getevent)
-    ** AID_INET to diagnose network issues (netcfg, ping)
-    ** AID_GRAPHICS to access the frame buffer
-    ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
-    ** AID_SDCARD_R to allow reading from the SD card
-    ** AID_SDCARD_RW to allow writing to the SD card
-    ** AID_NET_BW_STATS to read out qtaguid statistics
-    */
-    gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS,
-                       AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
-                       AID_NET_BW_STATS };
-    if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
-        exit(1);
-    }
-
-    /* don't listen on a port (default 5037) if running in secure mode */
-    /* don't run as root if we are running in secure mode */
-    if (should_drop_privileges()) {
-        drop_capabilities_bounding_set_if_needed();
-
-        /* then switch user and group to "shell" */
-        if (setgid(AID_SHELL) != 0) {
-            exit(1);
-        }
-        if (setuid(AID_SHELL) != 0) {
-            exit(1);
-        }
-
-        D("Local port disabled\n");
-    } else {
-        char local_name[30];
-        if ((root_seclabel != NULL) && (is_selinux_enabled() > 0)) {
-            // b/12587913: fix setcon to allow const pointers
-            if (setcon((char *)root_seclabel) < 0) {
-                exit(1);
-            }
-        }
-        build_local_name(local_name, sizeof(local_name), server_port);
-        if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
-            exit(1);
-        }
-    }
-
-    int usb = 0;
-    if (access(USB_ADB_PATH, F_OK) == 0 || access(USB_FFS_ADB_EP0, F_OK) == 0) {
-        // listen on USB
-        usb_init();
-        usb = 1;
-    }
-
-    // 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.
-    property_get("service.adb.tcp.port", value, "");
-    if (!value[0]) {
-        property_get("persist.adb.tcp.port", value, "");
-    }
-    if (sscanf(value, "%d", &port) == 1 && port > 0) {
-        printf("using port=%d\n", port);
-        // listen on TCP port specified by service.adb.tcp.port property
-        local_init(port);
-    } else if (!usb) {
-        // listen on default port
-        local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
-    }
-
-    D("adb_main(): pre init_jdwp()\n");
-    init_jdwp();
-    D("adb_main(): post init_jdwp()\n");
-#endif
-
-    if (is_daemon)
-    {
-        // inform our parent that we are up and running.
-#ifdef HAVE_WIN32_PROC
-        DWORD  count;
-        WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL );
-#elif defined(HAVE_FORKEXEC)
-        fprintf(stderr, "OK\n");
-#endif
-        start_logging();
-    }
-    D("Event loop starting\n");
-
-    fdevent_loop();
-
-    usb_cleanup();
-
-    return 0;
-}
-
-// Try to handle a network forwarding request.
-// This returns 1 on success, 0 on failure, and -1 to indicate this is not
-// a forwarding-related request.
-int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd)
-{
-    if (!strcmp(service, "list-forward")) {
-        // Create the list of forward redirections.
-        int buffer_size = format_listeners(NULL, 0);
-        // Add one byte for the trailing zero.
-        char* buffer = malloc(buffer_size + 1);
-        if (buffer == NULL) {
-            sendfailmsg(reply_fd, "not enough memory");
-            return 1;
-        }
-        (void) format_listeners(buffer, buffer_size + 1);
-#if ADB_HOST
-        send_msg_with_okay(reply_fd, buffer, buffer_size);
-#else
-        send_msg_with_header(reply_fd, buffer, buffer_size);
-#endif
-        free(buffer);
-        return 1;
-    }
-
-    if (!strcmp(service, "killforward-all")) {
-        remove_all_listeners();
-#if ADB_HOST
-        /* On the host: 1st OKAY is connect, 2nd OKAY is status */
-        adb_write(reply_fd, "OKAY", 4);
-#endif
-        adb_write(reply_fd, "OKAY", 4);
-        return 1;
-    }
-
-    if (!strncmp(service, "forward:",8) ||
-        !strncmp(service, "killforward:",12)) {
-        char *local, *remote, *err;
-        int r;
-        atransport *transport;
-
-        int createForward = strncmp(service, "kill", 4);
-        int no_rebind = 0;
-
-        local = strchr(service, ':') + 1;
-
-        // Handle forward:norebind:<local>... here
-        if (createForward && !strncmp(local, "norebind:", 9)) {
-            no_rebind = 1;
-            local = strchr(local, ':') + 1;
-        }
-
-        remote = strchr(local,';');
-
-        if (createForward) {
-            // Check forward: parameter format: '<local>;<remote>'
-            if(remote == 0) {
-                sendfailmsg(reply_fd, "malformed forward spec");
-                return 1;
-            }
-
-            *remote++ = 0;
-            if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')) {
-                sendfailmsg(reply_fd, "malformed forward spec");
-                return 1;
-            }
-        } else {
-            // Check killforward: parameter format: '<local>'
-            if (local[0] == 0) {
-                sendfailmsg(reply_fd, "malformed forward spec");
-                return 1;
-            }
-        }
-
-        transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
-        if (!transport) {
-            sendfailmsg(reply_fd, err);
-            return 1;
-        }
-
-        if (createForward) {
-            r = install_listener(local, remote, transport, no_rebind);
-        } else {
-            r = remove_listener(local, transport);
-        }
-        if(r == 0) {
-#if ADB_HOST
-            /* On the host: 1st OKAY is connect, 2nd OKAY is status */
-            writex(reply_fd, "OKAY", 4);
-#endif
-            writex(reply_fd, "OKAY", 4);
-            return 1;
-        }
-
-        if (createForward) {
-            const char* message;
-            switch (r) {
-              case INSTALL_STATUS_CANNOT_BIND:
-                message = "cannot bind to socket";
-                break;
-              case INSTALL_STATUS_CANNOT_REBIND:
-                message = "cannot rebind existing socket";
-                break;
-              default:
-                message = "internal error";
-            }
-            sendfailmsg(reply_fd, message);
-        } else {
-            sendfailmsg(reply_fd, "cannot remove listener");
-        }
-        return 1;
-    }
-    return 0;
-}
-
-int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
-{
-    atransport *transport = NULL;
-
-    if(!strcmp(service, "kill")) {
-        fprintf(stderr,"adb server killed by remote request\n");
-        fflush(stdout);
-        adb_write(reply_fd, "OKAY", 4);
-        usb_cleanup();
-        exit(0);
-    }
-
-#if ADB_HOST
-    // "transport:" is used for switching transport with a specified serial number
-    // "transport-usb:" is used for switching transport to the only USB transport
-    // "transport-local:" is used for switching transport to the only local transport
-    // "transport-any:" is used for switching transport to the only transport
-    if (!strncmp(service, "transport", strlen("transport"))) {
-        char* error_string = "unknown failure";
-        transport_type type = kTransportAny;
-
-        if (!strncmp(service, "transport-usb", strlen("transport-usb"))) {
-            type = kTransportUsb;
-        } else if (!strncmp(service, "transport-local", strlen("transport-local"))) {
-            type = kTransportLocal;
-        } else if (!strncmp(service, "transport-any", strlen("transport-any"))) {
-            type = kTransportAny;
-        } else if (!strncmp(service, "transport:", strlen("transport:"))) {
-            service += strlen("transport:");
-            serial = service;
-        }
-
-        transport = acquire_one_transport(CS_ANY, type, serial, &error_string);
-
-        if (transport) {
-            s->transport = transport;
-            adb_write(reply_fd, "OKAY", 4);
-        } else {
-            sendfailmsg(reply_fd, error_string);
-        }
-        return 1;
-    }
-
-    // return a list of all connected devices
-    if (!strncmp(service, "devices", 7)) {
-        char buffer[4096];
-        int use_long = !strcmp(service+7, "-l");
-        if (use_long || service[7] == 0) {
-            memset(buffer, 0, sizeof(buffer));
-            D("Getting device list \n");
-            list_transports(buffer, sizeof(buffer), use_long);
-            D("Wrote device list \n");
-            send_msg_with_okay(reply_fd, buffer, strlen(buffer));
-            return 0;
-        }
-    }
-
-    // remove TCP transport
-    if (!strncmp(service, "disconnect:", 11)) {
-        char buffer[4096];
-        memset(buffer, 0, sizeof(buffer));
-        char* serial = service + 11;
-        if (serial[0] == 0) {
-            // disconnect from all TCP devices
-            unregister_all_tcp_transports();
-        } else {
-            char hostbuf[100];
-            // assume port 5555 if no port is specified
-            if (!strchr(serial, ':')) {
-                snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:5555", serial);
-                serial = hostbuf;
-            }
-            atransport *t = find_transport(serial);
-
-            if (t) {
-                unregister_transport(t);
-            } else {
-                snprintf(buffer, sizeof(buffer), "No such device %s", serial);
-            }
-        }
-
-        send_msg_with_okay(reply_fd, buffer, strlen(buffer));
-        return 0;
-    }
-
-    // returns our value for ADB_SERVER_VERSION
-    if (!strcmp(service, "version")) {
-        char version[12];
-        snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION);
-        send_msg_with_okay(reply_fd, version, strlen(version));
-        return 0;
-    }
-
-    if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
-        char *out = "unknown";
-         transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
-       if (transport && transport->serial) {
-            out = transport->serial;
-        }
-        send_msg_with_okay(reply_fd, out, strlen(out));
-        return 0;
-    }
-    if(!strncmp(service,"get-devpath",strlen("get-devpath"))) {
-        char *out = "unknown";
-         transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
-       if (transport && transport->devpath) {
-            out = transport->devpath;
-        }
-        send_msg_with_okay(reply_fd, out, strlen(out));
-        return 0;
-    }
-    // indicates a new emulator instance has started
-    if (!strncmp(service,"emulator:",9)) {
-        int  port = atoi(service+9);
-        local_connect(port);
-        /* we don't even need to send a reply */
-        return 0;
-    }
-
-    if(!strncmp(service,"get-state",strlen("get-state"))) {
-        transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
-        char *state = connection_state_name(transport);
-        send_msg_with_okay(reply_fd, state, strlen(state));
-        return 0;
-    }
-#endif // ADB_HOST
-
-    int ret = handle_forward_request(service, ttype, serial, reply_fd);
-    if (ret >= 0)
-      return ret - 1;
-    return -1;
-}
-
-int main(int argc, char **argv)
-{
-#if ADB_HOST
-    adb_sysdeps_init();
-    adb_trace_init();
-    D("Handling commandline()\n");
-    return adb_commandline(argc - 1, argv + 1);
-#else
-    /* If adbd runs inside the emulator this will enable adb tracing via
-     * adb-debug qemud service in the emulator. */
-    adb_qemu_trace_init();
-    while(1) {
-        int c;
-        int option_index = 0;
-        static struct option opts[] = {
-            {"root_seclabel", required_argument, 0, 's' },
-            {"device_banner", required_argument, 0, 'b' }
-        };
-        c = getopt_long(argc, argv, "", opts, &option_index);
-        if (c == -1)
-            break;
-        switch (c) {
-        case 's':
-            root_seclabel = optarg;
-            break;
-        case 'b':
-            adb_device_banner = optarg;
-            break;
-        default:
-            break;
-        }
-    }
-
-    start_device_log();
-    D("Handling main()\n");
-    return adb_main(0, DEFAULT_ADB_PORT);
-#endif
-}
diff --git a/adb/adb.cpp b/adb/adb.cpp
new file mode 100644
index 0000000..f64b19f
--- /dev/null
+++ b/adb/adb.cpp
@@ -0,0 +1,931 @@
+/*
+ * 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.
+ */
+
+#define TRACE_TAG TRACE_ADB
+
+#include "sysdeps.h"
+#include "adb.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include <string>
+
+#include <base/stringprintf.h>
+#include <base/strings.h>
+
+#include "adb_auth.h"
+#include "adb_io.h"
+#include "adb_listeners.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>
+#endif
+
+ADB_MUTEX_DEFINE( D_lock );
+
+int HOST = 0;
+
+#if !ADB_HOST
+const char *adb_device_banner = "device";
+#endif
+
+void fatal(const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    fprintf(stderr, "error: ");
+    vfprintf(stderr, fmt, ap);
+    fprintf(stderr, "\n");
+    va_end(ap);
+    exit(-1);
+}
+
+void fatal_errno(const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    fprintf(stderr, "error: %s: ", strerror(errno));
+    vfprintf(stderr, fmt, ap);
+    fprintf(stderr, "\n");
+    va_end(ap);
+    exit(-1);
+}
+
+#if !ADB_HOST
+void start_device_log(void) {
+    struct tm now;
+    time_t t;
+    tzset();
+    time(&t);
+    localtime_r(&t, &now);
+
+    char timestamp[PATH_MAX];
+    strftime(timestamp, sizeof(timestamp), "%Y-%m-%d-%H-%M-%S", &now);
+
+    std::string path = android::base::StringPrintf("/data/adb/adb-%s-%d", timestamp, getpid());
+    int fd = unix_open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0640);
+    if (fd == -1) {
+        return;
+    }
+
+    // redirect stdout and stderr to the log file
+    dup2(fd, STDOUT_FILENO);
+    dup2(fd, STDERR_FILENO);
+    fprintf(stderr, "--- adb starting (pid %d) ---\n", getpid());
+    adb_close(fd);
+}
+#endif
+
+int adb_trace_mask;
+
+std::string get_trace_setting_from_env() {
+    const char* setting = getenv("ADB_TRACE");
+    if (setting == nullptr) {
+        setting = "";
+    }
+
+    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();
+#endif
+}
+
+// Split the comma/space/colum/semi-column separated list of tags from the trace
+// setting and build the trace mask from it. note that '1' and 'all' are special
+// cases to enable all tracing.
+//
+// adb's trace setting comes from the ADB_TRACE environment variable, whereas
+// adbd's comes from the system property persist.adb.trace_mask.
+void adb_trace_init() {
+    const std::string trace_setting = get_trace_setting();
+
+    static const struct {
+        const char*  tag;
+        int           flag;
+    } tags[] = {
+        { "1", 0 },
+        { "all", 0 },
+        { "adb", TRACE_ADB },
+        { "sockets", TRACE_SOCKETS },
+        { "packets", TRACE_PACKETS },
+        { "rwx", TRACE_RWX },
+        { "usb", TRACE_USB },
+        { "sync", TRACE_SYNC },
+        { "sysdeps", TRACE_SYSDEPS },
+        { "transport", TRACE_TRANSPORT },
+        { "jdwp", TRACE_JDWP },
+        { "services", TRACE_SERVICES },
+        { "auth", TRACE_AUTH },
+        { NULL, 0 }
+    };
+
+    if (trace_setting.empty()) {
+        return;
+    }
+
+    // Use a comma/colon/semi-colon/space separated list
+    const char* p = trace_setting.c_str();
+    while (*p) {
+        int  len, tagn;
+
+        const char* q = strpbrk(p, " ,:;");
+        if (q == NULL) {
+            q = p + strlen(p);
+        }
+        len = q - p;
+
+        for (tagn = 0; tags[tagn].tag != NULL; tagn++) {
+            int  taglen = strlen(tags[tagn].tag);
+
+            if (len == taglen && !memcmp(tags[tagn].tag, p, len)) {
+                int  flag = tags[tagn].flag;
+                if (flag == 0) {
+                    adb_trace_mask = ~0;
+                    return;
+                }
+                adb_trace_mask |= (1 << flag);
+                break;
+            }
+        }
+        p = q;
+        if (*p)
+            p++;
+    }
+
+#if !ADB_HOST
+    start_device_log();
+#endif
+}
+
+apacket* get_apacket(void)
+{
+    apacket* p = reinterpret_cast<apacket*>(malloc(sizeof(apacket)));
+    if (p == nullptr) {
+      fatal("failed to allocate an apacket");
+    }
+
+    memset(p, 0, sizeof(apacket) - MAX_PAYLOAD);
+    return p;
+}
+
+void put_apacket(apacket *p)
+{
+    free(p);
+}
+
+void handle_online(atransport *t)
+{
+    D("adb: online\n");
+    t->online = 1;
+}
+
+void handle_offline(atransport *t)
+{
+    D("adb: offline\n");
+    //Close the associated usb
+    t->online = 0;
+    run_transport_disconnects(t);
+}
+
+#if DEBUG_PACKETS
+#define DUMPMAX 32
+void print_packet(const char *label, apacket *p)
+{
+    char *tag;
+    char *x;
+    unsigned count;
+
+    switch(p->msg.command){
+    case A_SYNC: tag = "SYNC"; break;
+    case A_CNXN: tag = "CNXN" ; break;
+    case A_OPEN: tag = "OPEN"; break;
+    case A_OKAY: tag = "OKAY"; break;
+    case A_CLSE: tag = "CLSE"; break;
+    case A_WRTE: tag = "WRTE"; break;
+    case A_AUTH: tag = "AUTH"; break;
+    default: tag = "????"; break;
+    }
+
+    fprintf(stderr, "%s: %s %08x %08x %04x \"",
+            label, tag, p->msg.arg0, p->msg.arg1, p->msg.data_length);
+    count = p->msg.data_length;
+    x = (char*) p->data;
+    if(count > DUMPMAX) {
+        count = DUMPMAX;
+        tag = "\n";
+    } else {
+        tag = "\"\n";
+    }
+    while(count-- > 0){
+        if((*x >= ' ') && (*x < 127)) {
+            fputc(*x, stderr);
+        } else {
+            fputc('.', stderr);
+        }
+        x++;
+    }
+    fputs(tag, stderr);
+}
+#endif
+
+static void send_ready(unsigned local, unsigned remote, atransport *t)
+{
+    D("Calling send_ready \n");
+    apacket *p = get_apacket();
+    p->msg.command = A_OKAY;
+    p->msg.arg0 = local;
+    p->msg.arg1 = remote;
+    send_packet(p, t);
+}
+
+static void send_close(unsigned local, unsigned remote, atransport *t)
+{
+    D("Calling send_close \n");
+    apacket *p = get_apacket();
+    p->msg.command = A_CLSE;
+    p->msg.arg0 = local;
+    p->msg.arg1 = remote;
+    send_packet(p, t);
+}
+
+static size_t fill_connect_data(char *buf, size_t bufsize)
+{
+#if ADB_HOST
+    return snprintf(buf, bufsize, "host::") + 1;
+#else
+    static const char *cnxn_props[] = {
+        "ro.product.name",
+        "ro.product.model",
+        "ro.product.device",
+    };
+    static const int num_cnxn_props = ARRAY_SIZE(cnxn_props);
+    int i;
+    size_t remaining = bufsize;
+    size_t len;
+
+    len = snprintf(buf, remaining, "%s::", adb_device_banner);
+    remaining -= len;
+    buf += len;
+    for (i = 0; i < num_cnxn_props; i++) {
+        char value[PROPERTY_VALUE_MAX];
+        property_get(cnxn_props[i], value, "");
+        len = snprintf(buf, remaining, "%s=%s;", cnxn_props[i], value);
+        remaining -= len;
+        buf += len;
+    }
+
+    return bufsize - remaining + 1;
+#endif
+}
+
+void send_connect(atransport *t)
+{
+    D("Calling send_connect \n");
+    apacket *cp = get_apacket();
+    cp->msg.command = A_CNXN;
+    cp->msg.arg0 = A_VERSION;
+    cp->msg.arg1 = MAX_PAYLOAD;
+    cp->msg.data_length = fill_connect_data((char *)cp->data,
+                                            sizeof(cp->data));
+    send_packet(cp, t);
+}
+
+// qual_overwrite is used to overwrite a qualifier string.  dst is a
+// pointer to a char pointer.  It is assumed that if *dst is non-NULL, it
+// was malloc'ed and needs to freed.  *dst will be set to a dup of src.
+// TODO: switch to std::string for these atransport fields instead.
+static void qual_overwrite(char** dst, const std::string& src) {
+    free(*dst);
+    *dst = strdup(src.c_str());
+}
+
+void parse_banner(const char* banner, atransport* t) {
+    D("parse_banner: %s\n", banner);
+
+    // The format is something like:
+    // "device::ro.product.name=x;ro.product.model=y;ro.product.device=z;".
+    std::vector<std::string> pieces = android::base::Split(banner, ":");
+
+    if (pieces.size() > 2) {
+        const std::string& props = pieces[2];
+        for (auto& prop : android::base::Split(props, ";")) {
+            // The list of properties was traditionally ;-terminated rather than ;-separated.
+            if (prop.empty()) continue;
+
+            std::vector<std::string> key_value = android::base::Split(prop, "=");
+            if (key_value.size() != 2) continue;
+
+            const std::string& key = key_value[0];
+            const std::string& value = key_value[1];
+            if (key == "ro.product.name") {
+                qual_overwrite(&t->product, value);
+            } else if (key == "ro.product.model") {
+                qual_overwrite(&t->model, value);
+            } else if (key == "ro.product.device") {
+                qual_overwrite(&t->device, value);
+            }
+        }
+    }
+
+    const std::string& type = pieces[0];
+    if (type == "bootloader") {
+        D("setting connection_state to CS_BOOTLOADER\n");
+        t->connection_state = CS_BOOTLOADER;
+        update_transports();
+    } else if (type == "device") {
+        D("setting connection_state to CS_DEVICE\n");
+        t->connection_state = CS_DEVICE;
+        update_transports();
+    } else if (type == "recovery") {
+        D("setting connection_state to CS_RECOVERY\n");
+        t->connection_state = CS_RECOVERY;
+        update_transports();
+    } else if (type == "sideload") {
+        D("setting connection_state to CS_SIDELOAD\n");
+        t->connection_state = CS_SIDELOAD;
+        update_transports();
+    } else {
+        D("setting connection_state to CS_HOST\n");
+        t->connection_state = CS_HOST;
+    }
+}
+
+void handle_packet(apacket *p, atransport *t)
+{
+    asocket *s;
+
+    D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0],
+            ((char*) (&(p->msg.command)))[1],
+            ((char*) (&(p->msg.command)))[2],
+            ((char*) (&(p->msg.command)))[3]);
+    print_packet("recv", p);
+
+    switch(p->msg.command){
+    case A_SYNC:
+        if(p->msg.arg0){
+            send_packet(p, t);
+            if(HOST) send_connect(t);
+        } else {
+            t->connection_state = CS_OFFLINE;
+            handle_offline(t);
+            send_packet(p, t);
+        }
+        return;
+
+    case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
+            /* XXX verify version, etc */
+        if(t->connection_state != CS_OFFLINE) {
+            t->connection_state = CS_OFFLINE;
+            handle_offline(t);
+        }
+
+        parse_banner(reinterpret_cast<const char*>(p->data), t);
+
+        if (HOST || !auth_required) {
+            handle_online(t);
+            if (!HOST) send_connect(t);
+        } else {
+            send_auth_request(t);
+        }
+        break;
+
+    case A_AUTH:
+        if (p->msg.arg0 == ADB_AUTH_TOKEN) {
+            t->connection_state = CS_UNAUTHORIZED;
+            t->key = adb_auth_nextkey(t->key);
+            if (t->key) {
+                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;
+
+    case A_OPEN: /* OPEN(local-id, 0, "destination") */
+        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);
+            if(s == 0) {
+                send_close(0, p->msg.arg0, t);
+            } else {
+                s->peer = create_remote_socket(p->msg.arg0, t);
+                s->peer->peer = s;
+                send_ready(s->id, s->peer->id, t);
+                s->ready(s);
+            }
+        }
+        break;
+
+    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))) {
+                if(s->peer == 0) {
+                    /* On first READY message, create the connection. */
+                    s->peer = create_remote_socket(p->msg.arg0, t);
+                    s->peer->peer = s;
+                    s->ready(s);
+                } else if (s->peer->id == p->msg.arg0) {
+                    /* Other READY messages must use the same local-id */
+                    s->ready(s);
+                } else {
+                    D("Invalid A_OKAY(%d,%d), expected A_OKAY(%d,%d) on transport %s\n",
+                      p->msg.arg0, p->msg.arg1, s->peer->id, p->msg.arg1, t->serial);
+                }
+            }
+        }
+        break;
+
+    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))) {
+                /* 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
+                 * CLOSE() operations.
+                 *
+                 * This is bad because it means a compromised adbd could
+                 * send packets to close connections between the host and
+                 * other devices. To avoid this, only allow this if the local
+                 * socket has a peer on the same transport.
+                 */
+                if (p->msg.arg0 == 0 && s->peer && s->peer->transport != t) {
+                    D("Invalid A_CLSE(0, %u) from transport %s, expected transport %s\n",
+                      p->msg.arg1, t->serial, s->peer->transport->serial);
+                } else {
+                    s->close(s);
+                }
+            }
+        }
+        break;
+
+    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))) {
+                unsigned rid = p->msg.arg0;
+                p->len = p->msg.data_length;
+
+                if(s->enqueue(s, p) == 0) {
+                    D("Enqueue the socket\n");
+                    send_ready(s->id, rid, t);
+                }
+                return;
+            }
+        }
+        break;
+
+    default:
+        printf("handle_packet: what is %08x?!\n", p->msg.command);
+    }
+
+    put_apacket(p);
+}
+
+#if ADB_HOST
+
+int launch_server(int server_port)
+{
+#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" */
+    /* message since the pipe handles must be inheritable, we use a     */
+    /* security attribute                                               */
+    HANDLE                pipe_read, pipe_write;
+    HANDLE                stdout_handle, stderr_handle;
+    SECURITY_ATTRIBUTES   sa;
+    STARTUPINFO           startup;
+    PROCESS_INFORMATION   pinfo;
+    char                  program_path[ MAX_PATH ];
+    int                   ret;
+
+    sa.nLength = sizeof(sa);
+    sa.lpSecurityDescriptor = NULL;
+    sa.bInheritHandle = TRUE;
+
+    /* create pipe, and ensure its read handle isn't inheritable */
+    ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 );
+    if (!ret) {
+        fprintf(stderr, "CreatePipe() failure, error %ld\n", GetLastError() );
+        return -1;
+    }
+
+    SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 );
+
+    /* Some programs want to launch an adb command and collect its output by
+     * calling CreateProcess with inheritable stdout/stderr handles, then
+     * using read() to get its output. When this happens, the stdout/stderr
+     * handles passed to the adb client process will also be inheritable.
+     * When starting the adb server here, care must be taken to reset them
+     * to non-inheritable.
+     * Otherwise, something bad happens: even if the adb command completes,
+     * the calling process is stuck while read()-ing from the stdout/stderr
+     * descriptors, because they're connected to corresponding handles in the
+     * adb server process (even if the latter never uses/writes to them).
+     */
+    stdout_handle = GetStdHandle( STD_OUTPUT_HANDLE );
+    stderr_handle = GetStdHandle( STD_ERROR_HANDLE );
+    if (stdout_handle != INVALID_HANDLE_VALUE) {
+        SetHandleInformation( stdout_handle, HANDLE_FLAG_INHERIT, 0 );
+    }
+    if (stderr_handle != INVALID_HANDLE_VALUE) {
+        SetHandleInformation( stderr_handle, HANDLE_FLAG_INHERIT, 0 );
+    }
+
+    ZeroMemory( &startup, sizeof(startup) );
+    startup.cb = sizeof(startup);
+    startup.hStdInput  = GetStdHandle( STD_INPUT_HANDLE );
+    startup.hStdOutput = pipe_write;
+    startup.hStdError  = GetStdHandle( STD_ERROR_HANDLE );
+    startup.dwFlags    = STARTF_USESTDHANDLES;
+
+    ZeroMemory( &pinfo, sizeof(pinfo) );
+
+    /* get path of current program */
+    GetModuleFileName( NULL, program_path, sizeof(program_path) );
+    char args[64];
+    snprintf(args, sizeof(args), "adb -P %d fork-server server",  server_port);
+    ret = CreateProcess(
+            program_path,                              /* program path  */
+            args,
+                                    /* the fork-server argument will set the
+                                       debug = 2 in the child           */
+            NULL,                   /* process handle is not inheritable */
+            NULL,                    /* thread handle is not inheritable */
+            TRUE,                          /* yes, inherit some handles */
+            DETACHED_PROCESS, /* the new process doesn't have a console */
+            NULL,                     /* use parent's environment block */
+            NULL,                    /* use parent's starting directory */
+            &startup,                 /* startup info, i.e. std handles */
+            &pinfo );
+
+    CloseHandle( pipe_write );
+
+    if (!ret) {
+        fprintf(stderr, "CreateProcess failure, error %ld\n", GetLastError() );
+        CloseHandle( pipe_read );
+        return -1;
+    }
+
+    CloseHandle( pinfo.hProcess );
+    CloseHandle( pinfo.hThread );
+
+    /* wait for the "OK\n" message */
+    {
+        char  temp[3];
+        DWORD  count;
+
+        ret = ReadFile( pipe_read, temp, 3, &count, NULL );
+        CloseHandle( pipe_read );
+        if ( !ret ) {
+            fprintf(stderr, "could not read ok from ADB Server, error = %ld\n", GetLastError() );
+            return -1;
+        }
+        if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
+            fprintf(stderr, "ADB server didn't ACK\n" );
+            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 fd[1] will get mapped to stderr in the child.
+    if (pipe(fd)) {
+        fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno);
+        return -1;
+    }
+    get_my_path(path, PATH_MAX);
+    pid_t pid = fork();
+    if(pid < 0) return -1;
+
+    if (pid == 0) {
+        // child side of the fork
+
+        // redirect stderr to the pipe
+        // we use stderr instead of stdout due to stdout's buffering behavior.
+        adb_close(fd[0]);
+        dup2(fd[1], STDERR_FILENO);
+        adb_close(fd[1]);
+
+        char str_port[30];
+        snprintf(str_port, sizeof(str_port), "%d",  server_port);
+        // child process
+        int result = execl(path, "adb", "-P", str_port, "fork-server", "server", NULL);
+        // this should not return
+        fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
+    } else  {
+        // parent side of the fork
+
+        char  temp[3];
+
+        temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';
+        // wait for the "OK\n" message
+        adb_close(fd[1]);
+        int ret = adb_read(fd[0], temp, 3);
+        int saved_errno = errno;
+        adb_close(fd[0]);
+        if (ret < 0) {
+            fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", saved_errno);
+            return -1;
+        }
+        if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
+            fprintf(stderr, "ADB server didn't ACK\n" );
+            return -1;
+        }
+
+        setsid();
+    }
+#endif /* !defined(_WIN32) */
+    return 0;
+}
+#endif /* ADB_HOST */
+
+// Try to handle a network forwarding request.
+// This returns 1 on success, 0 on failure, and -1 to indicate this is not
+// a forwarding-related request.
+int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd)
+{
+    if (!strcmp(service, "list-forward")) {
+        // Create the list of forward redirections.
+        std::string listeners = format_listeners();
+#if ADB_HOST
+        SendOkay(reply_fd);
+#endif
+        SendProtocolString(reply_fd, listeners);
+        return 1;
+    }
+
+    if (!strcmp(service, "killforward-all")) {
+        remove_all_listeners();
+#if ADB_HOST
+        /* On the host: 1st OKAY is connect, 2nd OKAY is status */
+        SendOkay(reply_fd);
+#endif
+        SendOkay(reply_fd);
+        return 1;
+    }
+
+    if (!strncmp(service, "forward:",8) ||
+        !strncmp(service, "killforward:",12)) {
+        char *local, *remote;
+        atransport *transport;
+
+        int createForward = strncmp(service, "kill", 4);
+        int no_rebind = 0;
+
+        local = strchr(service, ':') + 1;
+
+        // Handle forward:norebind:<local>... here
+        if (createForward && !strncmp(local, "norebind:", 9)) {
+            no_rebind = 1;
+            local = strchr(local, ':') + 1;
+        }
+
+        remote = strchr(local,';');
+
+        if (createForward) {
+            // Check forward: parameter format: '<local>;<remote>'
+            if(remote == 0) {
+                SendFail(reply_fd, "malformed forward spec");
+                return 1;
+            }
+
+            *remote++ = 0;
+            if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')) {
+                SendFail(reply_fd, "malformed forward spec");
+                return 1;
+            }
+        } else {
+            // Check killforward: parameter format: '<local>'
+            if (local[0] == 0) {
+                SendFail(reply_fd, "malformed forward spec");
+                return 1;
+            }
+        }
+
+        std::string error_msg;
+        transport = acquire_one_transport(CS_ANY, ttype, serial, &error_msg);
+        if (!transport) {
+            SendFail(reply_fd, error_msg);
+            return 1;
+        }
+
+        install_status_t r;
+        if (createForward) {
+            r = install_listener(local, remote, transport, no_rebind);
+        } else {
+            r = remove_listener(local, transport);
+        }
+        if (r == INSTALL_STATUS_OK) {
+#if ADB_HOST
+            /* On the host: 1st OKAY is connect, 2nd OKAY is status */
+            SendOkay(reply_fd);
+#endif
+            SendOkay(reply_fd);
+            return 1;
+        }
+
+        std::string message;
+        switch (r) {
+          case INSTALL_STATUS_OK: message = " "; break;
+          case INSTALL_STATUS_INTERNAL_ERROR: message = "internal error"; break;
+          case INSTALL_STATUS_CANNOT_BIND:
+            message = android::base::StringPrintf("cannot bind to socket: %s", strerror(errno));
+            break;
+          case INSTALL_STATUS_CANNOT_REBIND:
+            message = android::base::StringPrintf("cannot rebind existing socket: %s", strerror(errno));
+            break;
+          case INSTALL_STATUS_LISTENER_NOT_FOUND: message = "listener not found"; break;
+        }
+        SendFail(reply_fd, message);
+        return 1;
+    }
+    return 0;
+}
+
+int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
+{
+    if(!strcmp(service, "kill")) {
+        fprintf(stderr,"adb server killed by remote request\n");
+        fflush(stdout);
+        SendOkay(reply_fd);
+        usb_cleanup();
+        exit(0);
+    }
+
+#if ADB_HOST
+    atransport *transport = NULL;
+    // "transport:" is used for switching transport with a specified serial number
+    // "transport-usb:" is used for switching transport to the only USB transport
+    // "transport-local:" is used for switching transport to the only local transport
+    // "transport-any:" is used for switching transport to the only transport
+    if (!strncmp(service, "transport", strlen("transport"))) {
+        transport_type type = kTransportAny;
+
+        if (!strncmp(service, "transport-usb", strlen("transport-usb"))) {
+            type = kTransportUsb;
+        } else if (!strncmp(service, "transport-local", strlen("transport-local"))) {
+            type = kTransportLocal;
+        } else if (!strncmp(service, "transport-any", strlen("transport-any"))) {
+            type = kTransportAny;
+        } else if (!strncmp(service, "transport:", strlen("transport:"))) {
+            service += strlen("transport:");
+            serial = service;
+        }
+
+        std::string error_msg = "unknown failure";
+        transport = acquire_one_transport(CS_ANY, type, serial, &error_msg);
+
+        if (transport) {
+            s->transport = transport;
+            SendOkay(reply_fd);
+        } else {
+            SendFail(reply_fd, error_msg);
+        }
+        return 1;
+    }
+
+    // return a list of all connected devices
+    if (!strncmp(service, "devices", 7)) {
+        bool long_listing = (strcmp(service+7, "-l") == 0);
+        if (long_listing || service[7] == 0) {
+            D("Getting device list...\n");
+            std::string device_list = list_transports(long_listing);
+            D("Sending device list...\n");
+            SendOkay(reply_fd);
+            SendProtocolString(reply_fd, device_list);
+            return 0;
+        }
+        return 1;
+    }
+
+    // remove TCP transport
+    if (!strncmp(service, "disconnect:", 11)) {
+        char buffer[4096];
+        memset(buffer, 0, sizeof(buffer));
+        char* serial = service + 11;
+        if (serial[0] == 0) {
+            // disconnect from all TCP devices
+            unregister_all_tcp_transports();
+        } else {
+            char hostbuf[100];
+            // assume port 5555 if no port is specified
+            if (!strchr(serial, ':')) {
+                snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:5555", serial);
+                serial = hostbuf;
+            }
+            atransport *t = find_transport(serial);
+
+            if (t) {
+                unregister_transport(t);
+            } else {
+                snprintf(buffer, sizeof(buffer), "No such device %s", serial);
+            }
+        }
+
+        SendOkay(reply_fd);
+        SendProtocolString(reply_fd, buffer);
+        return 0;
+    }
+
+    // returns our value for ADB_SERVER_VERSION
+    if (!strcmp(service, "version")) {
+        SendOkay(reply_fd);
+        SendProtocolString(reply_fd, android::base::StringPrintf("%04x", ADB_SERVER_VERSION));
+        return 0;
+    }
+
+    if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
+        const char *out = "unknown";
+        transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
+        if (transport && transport->serial) {
+            out = transport->serial;
+        }
+        SendOkay(reply_fd);
+        SendProtocolString(reply_fd, out);
+        return 0;
+    }
+    if(!strncmp(service,"get-devpath",strlen("get-devpath"))) {
+        const char *out = "unknown";
+        transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
+        if (transport && transport->devpath) {
+            out = transport->devpath;
+        }
+        SendOkay(reply_fd);
+        SendProtocolString(reply_fd, out);
+        return 0;
+    }
+    // indicates a new emulator instance has started
+    if (!strncmp(service,"emulator:",9)) {
+        int  port = atoi(service+9);
+        local_connect(port);
+        /* we don't even need to send a reply */
+        return 0;
+    }
+
+    if(!strncmp(service,"get-state",strlen("get-state"))) {
+        transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
+        SendOkay(reply_fd);
+        SendProtocolString(reply_fd, transport->connection_state_name());
+        return 0;
+    }
+#endif // ADB_HOST
+
+    int ret = handle_forward_request(service, ttype, serial, reply_fd);
+    if (ret >= 0)
+      return ret - 1;
+    return -1;
+}
diff --git a/adb/adb.h b/adb/adb.h
index 44e5981..fd9d0e6 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -18,9 +18,10 @@
 #define __ADB_H
 
 #include <limits.h>
+#include <sys/types.h>
 
 #include "adb_trace.h"
-#include "transport.h"  /* readx(), writex() */
+#include "fdevent.h"
 
 #define MAX_PAYLOAD 4096
 
@@ -32,21 +33,18 @@
 #define A_WRTE 0x45545257
 #define A_AUTH 0x48545541
 
-#define A_VERSION 0x01000000        // ADB protocol version
+// ADB protocol version.
+#define A_VERSION 0x01000000
 
-#define ADB_VERSION_MAJOR 1         // Used for help/version information
-#define ADB_VERSION_MINOR 0         // Used for help/version information
+// Used for help/version information.
+#define ADB_VERSION_MAJOR 1
+#define ADB_VERSION_MINOR 0
 
-#define ADB_SERVER_VERSION    32    // Increment this when we want to force users to start a new adb server
+// Increment this when we want to force users to start a new adb server.
+#define ADB_SERVER_VERSION 32
 
-typedef struct amessage amessage;
-typedef struct apacket apacket;
-typedef struct asocket asocket;
-typedef struct alistener alistener;
-typedef struct aservice aservice;
-typedef struct atransport atransport;
-typedef struct adisconnect  adisconnect;
-typedef struct usb_handle usb_handle;
+struct atransport;
+struct usb_handle;
 
 struct amessage {
     unsigned command;       /* command identifier constant      */
@@ -163,12 +161,12 @@
 ** object, it's a special value used to indicate that a client wants to
 ** connect to a service implemented within the ADB server itself.
 */
-typedef enum transport_type {
+enum transport_type {
         kTransportUsb,
         kTransportLocal,
         kTransportAny,
         kTransportHost,
-} transport_type;
+};
 
 #define TOKEN_SIZE 20
 
@@ -211,6 +209,8 @@
     unsigned char token[TOKEN_SIZE];
     fdevent auth_fde;
     unsigned failed_auth_attempts;
+
+    const char* connection_state_name() const;
 };
 
 
@@ -231,8 +231,8 @@
     fdevent fde;
     int fd;
 
-    const char *local_name;
-    const char *connect_to;
+    char *local_name;
+    char *connect_to;
     atransport *transport;
     adisconnect  disconnect;
 };
@@ -245,8 +245,6 @@
 void remove_socket(asocket *s);
 void close_all_sockets(atransport *t);
 
-#define  LOCAL_CLIENT_PREFIX  "emulator-"
-
 asocket *create_local_socket(int fd);
 asocket *create_local_service_socket(const char *destination);
 
@@ -258,33 +256,11 @@
 void fatal_errno(const char *fmt, ...);
 
 void handle_packet(apacket *p, atransport *t);
-void send_packet(apacket *p, atransport *t);
 
 void get_my_path(char *s, size_t maxLen);
 int launch_server(int server_port);
 int adb_main(int is_daemon, int server_port);
 
-
-/* transports are ref-counted
-** get_device_transport does an acquire on your behalf before returning
-*/
-void init_transport_registration(void);
-int  list_transports(char *buf, size_t  bufsize, int long_listing);
-void update_transports(void);
-
-asocket*  create_device_tracker(void);
-
-/* Obtain a transport from the available transports.
-** If state is != CS_ANY, only transports in that state are considered.
-** If serial is non-NULL then only the device with that serial will be chosen.
-** If no suitable transport is found, error is set.
-*/
-atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char **error_out);
-void   add_transport_disconnect( atransport*  t, adisconnect*  dis );
-void   remove_transport_disconnect( atransport*  t, adisconnect*  dis );
-void   run_transport_disconnects( atransport*  t );
-void   kick_transport( atransport*  t );
-
 /* initialize a transport object's func pointers and state */
 #if ADB_HOST
 int get_available_local_transport_index();
@@ -292,22 +268,6 @@
 int  init_socket_transport(atransport *t, int s, int port, int local);
 void init_usb_transport(atransport *t, usb_handle *usb, int state);
 
-/* for MacOS X cleanup */
-void close_usb_devices();
-
-/* cause new transports to be init'd and added to the list */
-int register_socket_transport(int s, const char *serial, int port, int local);
-
-/* these should only be used for the "adb disconnect" command */
-void unregister_transport(atransport *t);
-void unregister_all_tcp_transports();
-
-void register_usb_transport(usb_handle *h, const char *serial, const char *devpath, unsigned writeable);
-
-/* this should only be used for transports with connection_state == CS_NOPERM */
-void unregister_usb_transport(usb_handle *usb);
-
-atransport *find_transport(const char *serial);
 #if ADB_HOST
 atransport* find_emulator_transport_by_adb_port(int adb_port);
 #endif
@@ -328,16 +288,15 @@
 
 #if !ADB_HOST
 void framebuffer_service(int fd, void *cookie);
-void remount_service(int fd, void *cookie);
-void disable_verity_service(int fd, void* cookie);
+void set_verity_enabled_state_service(int fd, void* cookie);
 #endif
 
 /* packet allocator */
 apacket *get_apacket(void);
 void put_apacket(apacket *p);
 
-int check_header(apacket *p);
-int check_data(apacket *p);
+// Define it if you want to dump packets.
+#define DEBUG_PACKETS 0
 
 #if !DEBUG_PACKETS
 #define print_packet(tag,p) do {} while (0)
@@ -376,8 +335,7 @@
 int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol);
 #endif
 
-unsigned host_to_le32(unsigned n);
-int adb_commandline(int argc, char **argv);
+int adb_commandline(int argc, const char **argv);
 
 int connection_state(atransport *t);
 
@@ -391,13 +349,14 @@
 #define CS_SIDELOAD   6
 #define CS_UNAUTHORIZED 7
 
+extern const char *adb_device_banner;
 extern int HOST;
 extern int SHELL_EXIT_NOTIFY_FD;
 
-typedef enum {
+enum subproc_mode {
     SUBPROC_PTY = 0,
     SUBPROC_RAW = 1,
-} subproc_mode;
+} ;
 
 #define CHUNK_SIZE (64*1024)
 
@@ -412,7 +371,11 @@
 #define USB_FFS_ADB_IN    USB_FFS_ADB_EP(ep2)
 #endif
 
-int sendfailmsg(int fd, const char *reason);
 int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s);
 
+void handle_online(atransport *t);
+void handle_offline(atransport *t);
+
+void send_connect(atransport *t);
+
 #endif
diff --git a/adb/adb_auth.cpp b/adb/adb_auth.cpp
new file mode 100644
index 0000000..cff26d6
--- /dev/null
+++ b/adb/adb_auth.cpp
@@ -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 TRACE_TAG TRACE_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\n");
+    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\n", 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\n");
+    apacket *p = get_apacket();
+    int ret;
+
+    ret = adb_auth_sign(t->key, token, token_size, p->data);
+    if (!ret) {
+        D("Error signing the token\n");
+        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\n");
+    apacket *p = get_apacket();
+    int ret;
+
+    ret = adb_auth_get_userkey(p->data, sizeof(p->data));
+    if (!ret) {
+        D("Failed to get user public key\n");
+        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 54dd537..a13604a 100644
--- a/adb/adb_auth.h
+++ b/adb/adb_auth.h
@@ -17,11 +17,16 @@
 #ifndef __ADB_AUTH_H
 #define __ADB_AUTH_H
 
-void adb_auth_init(void);
+#include "adb.h"
+
+extern bool auth_required;
+
 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);
 
 /* AUTH packets first argument */
 /* Request */
@@ -32,7 +37,9 @@
 
 #if ADB_HOST
 
-int adb_auth_sign(void *key, void *token, size_t token_size, void *sig);
+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);
 
@@ -42,12 +49,17 @@
 
 #else // !ADB_HOST
 
-static inline int adb_auth_sign(void* key, void *token, size_t token_size, void *sig) { return 0; }
+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; }
 
+void adbd_auth_init(void);
+void adbd_cloexec_auth_socket();
 int adb_auth_generate_token(void *token, size_t token_size);
-int adb_auth_verify(void *token, void *sig, int siglen);
+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);
 
 #endif // ADB_HOST
diff --git a/adb/adb_auth_client.c b/adb/adb_auth_client.cpp
similarity index 87%
rename from adb/adb_auth_client.c
rename to adb/adb_auth_client.cpp
index 55e9dca..8e7d38b 100644
--- a/adb/adb_auth_client.c
+++ b/adb/adb_auth_client.cpp
@@ -14,28 +14,30 @@
  * limitations under the License.
  */
 
-#include <stdio.h>
-#include <string.h>
-#include <resolv.h>
-#include <cutils/list.h>
-#include <cutils/sockets.h>
+#define TRACE_TAG TRACE_AUTH
 
 #include "sysdeps.h"
-#include "adb.h"
 #include "adb_auth.h"
-#include "fdevent.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"
 
-#define TRACE_TAG TRACE_AUTH
-
+#include "adb.h"
+#include "fdevent.h"
+#include "transport.h"
 
 struct adb_public_key {
     struct listnode node;
     RSAPublicKey key;
 };
 
-static char *key_paths[] = {
+static const char *key_paths[] = {
     "/adb_keys",
     "/data/misc/adb/adb_keys",
     NULL
@@ -51,7 +53,6 @@
 
 static void read_keys(const char *file, struct listnode *list)
 {
-    struct adb_public_key *key;
     FILE *f;
     char buf[MAX_PAYLOAD];
     char *sep;
@@ -65,8 +66,9 @@
 
     while (fgets(buf, sizeof(buf), f)) {
         /* Allocate 4 extra bytes to decode the base64 data in-place */
-        key = calloc(1, sizeof(*key) + 4);
-        if (!key) {
+        auto key = reinterpret_cast<adb_public_key*>(
+            calloc(1, sizeof(adb_public_key) + 4));
+        if (key == nullptr) {
             D("Can't malloc key\n");
             break;
         }
@@ -107,8 +109,8 @@
 
 static void load_keys(struct listnode *list)
 {
-    char *path;
-    char **paths = key_paths;
+    const char* path;
+    const char** paths = key_paths;
     struct stat buf;
 
     list_init(list);
@@ -136,10 +138,9 @@
     return ret * token_size;
 }
 
-int adb_auth_verify(void *token, void *sig, int siglen)
+int adb_auth_verify(uint8_t* token, uint8_t* sig, int siglen)
 {
     struct listnode *item;
-    struct adb_public_key *key;
     struct listnode key_list;
     int ret = 0;
 
@@ -149,7 +150,7 @@
     load_keys(&key_list);
 
     list_for_each(item, &key_list) {
-        key = node_to_item(item, struct adb_public_key, node);
+        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;
@@ -248,19 +249,23 @@
     }
 }
 
-void adb_auth_init(void)
-{
-    int fd, ret;
-
-    fd = android_get_control_socket("adbd");
-    if (fd < 0) {
+void adbd_cloexec_auth_socket() {
+    int fd = android_get_control_socket("adbd");
+    if (fd == -1) {
         D("Failed to get adbd socket\n");
         return;
     }
     fcntl(fd, F_SETFD, FD_CLOEXEC);
+}
 
-    ret = listen(fd, 4);
-    if (ret < 0) {
+void adbd_auth_init(void) {
+    int fd = android_get_control_socket("adbd");
+    if (fd == -1) {
+        D("Failed to get adbd socket\n");
+        return;
+    }
+
+    if (listen(fd, 4) == -1) {
         D("Failed to listen on '%d'\n", fd);
         return;
     }
diff --git a/adb/adb_auth_host.c b/adb/adb_auth_host.cpp
similarity index 75%
rename from adb/adb_auth_host.c
rename to adb/adb_auth_host.cpp
index dd83900..61a3777 100644
--- a/adb/adb_auth_host.c
+++ b/adb/adb_auth_host.cpp
@@ -14,8 +14,14 @@
  * limitations under the License.
  */
 
+#define TRACE_TAG TRACE_AUTH
+
+#include "sysdeps.h"
+#include "adb_auth.h"
+
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #ifdef _WIN32
 #  ifndef WIN32_LEAN_AND_MEAN
@@ -28,11 +34,8 @@
 #  include <sys/stat.h>
 #  include <unistd.h>
 #endif
-#include <string.h>
 
-#include "sysdeps.h"
 #include "adb.h"
-#include "adb_auth.h"
 
 /* HACK: we need the RSAPublicKey struct
  * but RSA_verify conflits with openssl */
@@ -40,6 +43,7 @@
 #include "mincrypt/rsa.h"
 #undef RSA_verify
 
+#include <base/strings.h>
 #include <cutils/list.h>
 
 #include <openssl/evp.h>
@@ -48,12 +52,13 @@
 #include <openssl/rsa.h>
 #include <openssl/sha.h>
 
-#define TRACE_TAG TRACE_AUTH
+#if defined(OPENSSL_IS_BORINGSSL)
+#include <openssl/base64.h>
+#endif
 
 #define ANDROID_PATH   ".android"
 #define ADB_KEY_FILE   "adbkey"
 
-
 struct adb_private_key {
     struct listnode node;
     RSA *rsa;
@@ -151,43 +156,65 @@
 static int write_public_keyfile(RSA *private_key, const char *private_key_path)
 {
     RSAPublicKey pkey;
-    BIO *bio, *b64, *bfile;
+    FILE *outfile = NULL;
     char path[PATH_MAX], info[MAX_PAYLOAD];
-    int ret;
+    uint8_t* encoded = nullptr;
+    size_t encoded_length;
+    int ret = 0;
 
-    ret = snprintf(path, sizeof(path), "%s.pub", private_key_path);
-    if (ret >= (signed)sizeof(path))
+    if (snprintf(path, sizeof(path), "%s.pub", private_key_path) >=
+        (int)sizeof(path)) {
+        D("Path too long while writing public key\n");
         return 0;
+    }
 
-    ret = RSA_to_RSAPublicKey(private_key, &pkey);
-    if (!ret) {
+    if (!RSA_to_RSAPublicKey(private_key, &pkey)) {
         D("Failed to convert to publickey\n");
         return 0;
     }
 
-    bfile = BIO_new_file(path, "w");
-    if (!bfile) {
+    outfile = fopen(path, "w");
+    if (!outfile) {
         D("Failed to open '%s'\n", path);
         return 0;
     }
 
     D("Writing public key to '%s'\n", path);
 
-    b64 = BIO_new(BIO_f_base64());
-    BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
+#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
 
-    bio = BIO_push(b64, bfile);
-    BIO_write(bio, &pkey, sizeof(pkey));
-    (void) BIO_flush(bio);
-    BIO_pop(b64);
-    BIO_free(b64);
+    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));
-    BIO_write(bfile, info, strlen(info));
-    (void) BIO_flush(bfile);
-    BIO_free_all(bfile);
 
-    return 1;
+    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;
 }
 
 static int generate_key(const char *file)
@@ -244,34 +271,26 @@
 
 static int read_key(const char *file, struct listnode *list)
 {
-    struct adb_private_key *key;
-    FILE *f;
-
     D("read_key '%s'\n", file);
 
-    f = fopen(file, "r");
-    if (!f) {
-        D("Failed to open '%s'\n", file);
+    FILE* fp = fopen(file, "r");
+    if (!fp) {
+        D("Failed to open '%s': %s\n", file, strerror(errno));
         return 0;
     }
 
-    key = malloc(sizeof(*key));
-    if (!key) {
-        D("Failed to alloc key\n");
-        fclose(f);
-        return 0;
-    }
+    adb_private_key* key = new adb_private_key;
     key->rsa = RSA_new();
 
-    if (!PEM_read_RSAPrivateKey(f, &key->rsa, NULL, NULL)) {
+    if (!PEM_read_RSAPrivateKey(fp, &key->rsa, NULL, NULL)) {
         D("Failed to read key\n");
-        fclose(f);
+        fclose(fp);
         RSA_free(key->rsa);
-        free(key);
+        delete key;
         return 0;
     }
 
-    fclose(f);
+    fclose(fp);
     list_add_tail(list, &key->node);
     return 1;
 }
@@ -336,37 +355,30 @@
     return read_key(path, list);
 }
 
-static void get_vendor_keys(struct listnode *list)
-{
-    const char *adb_keys_path;
-    char keys_path[MAX_PAYLOAD];
-    char *path;
-    char *save;
-    struct stat buf;
-
-    adb_keys_path = getenv("ADB_VENDOR_KEYS");
-    if (!adb_keys_path)
+static void get_vendor_keys(struct listnode* key_list) {
+    const char* adb_keys_path = getenv("ADB_VENDOR_KEYS");
+    if (adb_keys_path == nullptr) {
         return;
-    strncpy(keys_path, adb_keys_path, sizeof(keys_path));
+    }
 
-    path = adb_strtok_r(keys_path, ENV_PATH_SEPARATOR_STR, &save);
-    while (path) {
-        D("Reading: '%s'\n", path);
-
-        if (stat(path, &buf))
-            D("Can't read '%s'\n", path);
-        else if (!read_key(path, list))
-            D("Failed to read '%s'\n", path);
-
-        path = adb_strtok_r(NULL, ENV_PATH_SEPARATOR_STR, &save);
+    for (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'\n", path.c_str());
+        }
     }
 }
 
-int adb_auth_sign(void *node, void *token, size_t token_size, void *sig)
+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);
 
+    if (token_size != TOKEN_SIZE) {
+        D("Unexpected token size %zd\n", token_size);
+        return 0;
+    }
+
     if (!RSA_sign(NID_sha1, token, token_size, sig, &len, key->rsa)) {
         return 0;
     }
@@ -400,31 +412,33 @@
 int adb_auth_get_userkey(unsigned char *data, size_t len)
 {
     char path[PATH_MAX];
-    char *file;
-    int ret;
-
-    ret = get_user_keyfilepath(path, sizeof(path) - 4);
+    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;
     }
     strcat(path, ".pub");
 
-    file = load_file(path, (unsigned*)&ret);
-    if (!file) {
+    // TODO(danalbert): ReadFileToString
+    unsigned size;
+    char* file_data = reinterpret_cast<char*>(load_file(path, &size));
+    if (file_data == nullptr) {
         D("Can't load '%s'\n", path);
         return 0;
     }
 
-    if (len < (size_t)(ret + 1)) {
-        D("%s: Content too large ret=%d\n", path, ret);
+    if (len < (size_t)(size + 1)) {
+        D("%s: Content too large ret=%d\n", path, size);
+        free(file_data);
         return 0;
     }
 
-    memcpy(data, file, ret);
-    data[ret] = '\0';
+    memcpy(data, file_data, size);
+    free(file_data);
+    file_data = nullptr;
+    data[size] = '\0';
 
-    return ret + 1;
+    return size + 1;
 }
 
 int adb_auth_keygen(const char* filename) {
diff --git a/adb/adb_client.c b/adb/adb_client.c
deleted file mode 100644
index eb1720d..0000000
--- a/adb/adb_client.c
+++ /dev/null
@@ -1,346 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <zipfile/zipfile.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include "sysdeps.h"
-
-#define  TRACE_TAG  TRACE_ADB
-#include "adb_client.h"
-
-static transport_type __adb_transport = kTransportAny;
-static const char* __adb_serial = NULL;
-
-static int __adb_server_port = DEFAULT_ADB_PORT;
-static const char* __adb_server_name = NULL;
-
-void adb_set_transport(transport_type type, const char* serial)
-{
-    __adb_transport = type;
-    __adb_serial = serial;
-}
-
-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;
-}
-
-int  adb_get_emulator_console_port(void)
-{
-    const char*   serial = __adb_serial;
-    int           port;
-
-    if (serial == NULL) {
-        /* if no specific device was specified, we need to look at */
-        /* the list of connected devices, and extract an emulator  */
-        /* name from it. two emulators is an error                 */
-        char*  tmp = adb_query("host:devices");
-        char*  p   = tmp;
-        if(!tmp) {
-            printf("no emulator connected\n");
-            return -1;
-        }
-        while (*p) {
-            char*  q = strchr(p, '\n');
-            if (q != NULL)
-                *q++ = 0;
-            else
-                q = p + strlen(p);
-
-            if (!memcmp(p, LOCAL_CLIENT_PREFIX, sizeof(LOCAL_CLIENT_PREFIX)-1)) {
-                if (serial != NULL) {  /* more than one emulator listed */
-                    free(tmp);
-                    return -2;
-                }
-                serial = p;
-            }
-
-            p = q;
-        }
-        free(tmp);
-
-        if (serial == NULL)
-            return -1;  /* no emulator found */
-    }
-    else {
-        if (memcmp(serial, LOCAL_CLIENT_PREFIX, sizeof(LOCAL_CLIENT_PREFIX)-1) != 0)
-            return -1;  /* not an emulator */
-    }
-
-    serial += sizeof(LOCAL_CLIENT_PREFIX)-1;
-    port    = strtol(serial, NULL, 10);
-    return port;
-}
-
-static char __adb_error[256] = { 0 };
-
-const char *adb_error(void)
-{
-    return __adb_error;
-}
-
-static int switch_socket_transport(int fd)
-{
-    char service[64];
-    char tmp[5];
-    int len;
-
-    if (__adb_serial)
-        snprintf(service, sizeof service, "host:transport:%s", __adb_serial);
-    else {
-        char* transport_type = "???";
-
-         switch (__adb_transport) {
-            case kTransportUsb:
-                transport_type = "transport-usb";
-                break;
-            case kTransportLocal:
-                transport_type = "transport-local";
-                break;
-            case kTransportAny:
-                transport_type = "transport-any";
-                break;
-            case kTransportHost:
-                // no switch necessary
-                return 0;
-                break;
-        }
-
-        snprintf(service, sizeof service, "host:%s", transport_type);
-    }
-    len = strlen(service);
-    snprintf(tmp, sizeof tmp, "%04x", len);
-
-    if(writex(fd, tmp, 4) || writex(fd, service, len)) {
-        strcpy(__adb_error, "write failure during connection");
-        adb_close(fd);
-        return -1;
-    }
-    D("Switch transport in progress\n");
-
-    if(adb_status(fd)) {
-        adb_close(fd);
-        D("Switch transport failed\n");
-        return -1;
-    }
-    D("Switch transport success\n");
-    return 0;
-}
-
-int adb_status(int fd)
-{
-    unsigned char buf[5];
-    unsigned len;
-
-    if(readx(fd, buf, 4)) {
-        strcpy(__adb_error, "protocol fault (no status)");
-        return -1;
-    }
-
-    if(!memcmp(buf, "OKAY", 4)) {
-        return 0;
-    }
-
-    if(memcmp(buf, "FAIL", 4)) {
-        sprintf(__adb_error,
-                "protocol fault (status %02x %02x %02x %02x?!)",
-                buf[0], buf[1], buf[2], buf[3]);
-        return -1;
-    }
-
-    if(readx(fd, buf, 4)) {
-        strcpy(__adb_error, "protocol fault (status len)");
-        return -1;
-    }
-    buf[4] = 0;
-    len = strtoul((char*)buf, 0, 16);
-    if(len > 255) len = 255;
-    if(readx(fd, __adb_error, len)) {
-        strcpy(__adb_error, "protocol fault (status read)");
-        return -1;
-    }
-    __adb_error[len] = 0;
-    return -1;
-}
-
-int _adb_connect(const char *service)
-{
-    char tmp[5];
-    int len;
-    int fd;
-
-    D("_adb_connect: %s\n", service);
-    len = strlen(service);
-    if((len < 1) || (len > 1024)) {
-        strcpy(__adb_error, "service name too long");
-        return -1;
-    }
-    snprintf(tmp, sizeof tmp, "%04x", len);
-
-    if (__adb_server_name)
-        fd = socket_network_client(__adb_server_name, __adb_server_port, SOCK_STREAM);
-    else
-        fd = socket_loopback_client(__adb_server_port, SOCK_STREAM);
-
-    if(fd < 0) {
-        strcpy(__adb_error, "cannot connect to daemon");
-        return -2;
-    }
-
-    if (memcmp(service,"host",4) != 0 && switch_socket_transport(fd)) {
-        return -1;
-    }
-
-    if(writex(fd, tmp, 4) || writex(fd, service, len)) {
-        strcpy(__adb_error, "write failure during connection");
-        adb_close(fd);
-        return -1;
-    }
-
-    if(adb_status(fd)) {
-        adb_close(fd);
-        return -1;
-    }
-
-    D("_adb_connect: return fd %d\n", fd);
-    return fd;
-}
-
-int adb_connect(const char *service)
-{
-    // first query the adb server's version
-    int fd = _adb_connect("host:version");
-
-    D("adb_connect: service %s\n", service);
-    if(fd == -2 && __adb_server_name) {
-        fprintf(stderr,"** Cannot start server on remote host\n");
-        return fd;
-    } else if(fd == -2) {
-        fprintf(stdout,"* daemon not running. starting it now on port %d *\n",
-                __adb_server_port);
-    start_server:
-        if(launch_server(__adb_server_port)) {
-            fprintf(stderr,"* failed to start daemon *\n");
-            return -1;
-        } else {
-            fprintf(stdout,"* daemon started successfully *\n");
-        }
-        /* give the server some time to start properly and detect devices */
-        adb_sleep_ms(3000);
-        // fall through to _adb_connect
-    } else {
-        // if server was running, check its version to make sure it is not out of date
-        char buf[100];
-        size_t n;
-        int version = ADB_SERVER_VERSION - 1;
-
-        // if we have a file descriptor, then parse version result
-        if(fd >= 0) {
-            if(readx(fd, buf, 4)) goto error;
-
-            buf[4] = 0;
-            n = strtoul(buf, 0, 16);
-            if(n > sizeof(buf)) goto error;
-            if(readx(fd, buf, n)) goto error;
-            adb_close(fd);
-
-            if (sscanf(buf, "%04x", &version) != 1) goto error;
-        } else {
-            // if fd is -1, then check for "unknown host service",
-            // which would indicate a version of adb that does not support the version command
-            if (strcmp(__adb_error, "unknown host service") != 0)
-                return fd;
-        }
-
-        if(version != ADB_SERVER_VERSION) {
-            printf("adb server is out of date.  killing...\n");
-            fd = _adb_connect("host:kill");
-            adb_close(fd);
-
-            /* XXX can we better detect its death? */
-            adb_sleep_ms(2000);
-            goto start_server;
-        }
-    }
-
-    // if the command is start-server, we are done.
-    if (!strcmp(service, "host:start-server"))
-        return 0;
-
-    fd = _adb_connect(service);
-    if(fd == -1) {
-        D("_adb_connect error: %s\n", __adb_error);
-    } else if(fd == -2) {
-        fprintf(stderr,"** daemon still not running\n");
-    }
-    D("adb_connect: return fd %d\n", fd);
-
-    return fd;
-error:
-    adb_close(fd);
-    return -1;
-}
-
-
-int adb_command(const char *service)
-{
-    int fd = adb_connect(service);
-    if(fd < 0) {
-        fprintf(stderr, "error: %s\n", adb_error());
-        return -1;
-    }
-
-    if(adb_status(fd)) {
-        adb_close(fd);
-        return -1;
-    }
-
-    return 0;
-}
-
-char *adb_query(const char *service)
-{
-    char buf[5];
-    unsigned n;
-    char *tmp;
-
-    D("adb_query: %s\n", service);
-    int fd = adb_connect(service);
-    if(fd < 0) {
-        fprintf(stderr,"error: %s\n", __adb_error);
-        return 0;
-    }
-
-    if(readx(fd, buf, 4)) goto oops;
-
-    buf[4] = 0;
-    n = strtoul(buf, 0, 16);
-    if(n >= 0xffff) {
-        strcpy(__adb_error, "reply is too long (>= 64kB)");
-        goto oops;
-    }
-
-    tmp = malloc(n + 1);
-    if(tmp == 0) goto oops;
-
-    if(readx(fd, tmp, n) == 0) {
-        tmp[n] = 0;
-        adb_close(fd);
-        return tmp;
-    }
-    free(tmp);
-
-oops:
-    adb_close(fd);
-    return 0;
-}
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
new file mode 100644
index 0000000..7bb8e4a
--- /dev/null
+++ b/adb/adb_client.cpp
@@ -0,0 +1,318 @@
+/*
+ * 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 TRACE_ADB
+
+#include "sysdeps.h"
+#include "adb_client.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <string>
+#include <vector>
+
+#include <base/stringprintf.h>
+#include <base/strings.h>
+
+#include "adb_io.h"
+
+static transport_type __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 std::string perror_str(const char* msg) {
+    return android::base::StringPrintf("%s: %s", msg, strerror(errno));
+}
+
+static bool ReadProtocolString(int fd, std::string* s, std::string* error) {
+    char buf[5];
+    if (!ReadFdExactly(fd, buf, 4)) {
+        *error = perror_str("protocol fault (couldn't read status length)");
+        return false;
+    }
+    buf[4] = 0;
+
+    unsigned long len = strtoul(buf, 0, 16);
+    s->resize(len, '\0');
+    if (!ReadFdExactly(fd, &(*s)[0], len)) {
+        *error = perror_str("protocol fault (couldn't read status message)");
+        return false;
+    }
+
+    return true;
+}
+
+void adb_set_transport(transport_type type, const char* serial)
+{
+    __adb_transport = type;
+    __adb_serial = serial;
+}
+
+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;
+}
+
+int adb_get_emulator_console_port() {
+    if (__adb_serial) {
+        // The user specified a serial number; is it an emulator?
+        int port;
+        return (sscanf(__adb_serial, "emulator-%d", &port) == 1) ? port : -1;
+    }
+
+    // No specific device was given, so get the list of connected
+    // devices and search for emulators. If there's one, we'll
+    // take it. If there are more than one, that's an error.
+    std::string devices;
+    std::string error;
+    if (!adb_query("host:devices", &devices, &error)) {
+        printf("no emulator connected: %s\n", error.c_str());
+        return -1;
+    }
+
+    int port;
+    size_t emulator_count = 0;
+    for (auto& device : android::base::Split(devices, "\n")) {
+        if (sscanf(device.c_str(), "emulator-%d", &port) == 1) {
+            if (++emulator_count > 1) {
+                return -2;
+            }
+        }
+    }
+    if (emulator_count == 0) return -1;
+    return port;
+}
+
+static int switch_socket_transport(int fd, std::string* error) {
+    std::string service;
+    if (__adb_serial) {
+        service += "host:transport:";
+        service += __adb_serial;
+    } else {
+        const char* transport_type = "???";
+        switch (__adb_transport) {
+          case kTransportUsb:
+            transport_type = "transport-usb";
+            break;
+          case kTransportLocal:
+            transport_type = "transport-local";
+            break;
+          case kTransportAny:
+            transport_type = "transport-any";
+            break;
+          case kTransportHost:
+            // no switch necessary
+            return 0;
+        }
+        service += "host:";
+        service += transport_type;
+    }
+
+    if (!SendProtocolString(fd, service)) {
+        *error = perror_str("write failure during connection");
+        adb_close(fd);
+        return -1;
+    }
+    D("Switch transport in progress\n");
+
+    if (!adb_status(fd, error)) {
+        adb_close(fd);
+        D("Switch transport failed: %s\n", error->c_str());
+        return -1;
+    }
+    D("Switch transport success\n");
+    return 0;
+}
+
+bool adb_status(int fd, std::string* error) {
+    char buf[5];
+    if (!ReadFdExactly(fd, buf, 4)) {
+        *error = perror_str("protocol fault (couldn't read status)");
+        return false;
+    }
+
+    if (!memcmp(buf, "OKAY", 4)) {
+        return true;
+    }
+
+    if (memcmp(buf, "FAIL", 4)) {
+        *error = android::base::StringPrintf("protocol fault (status %02x %02x %02x %02x?!)",
+                                             buf[0], buf[1], buf[2], buf[3]);
+        return false;
+    }
+
+    ReadProtocolString(fd, error, error);
+    return false;
+}
+
+int _adb_connect(const std::string& service, std::string* error) {
+    D("_adb_connect: %s\n", service.c_str());
+    if (service.empty() || service.size() > 1024) {
+        *error = android::base::StringPrintf("bad service name length (%d)",
+                                             static_cast<int>(service.size()));
+        return -1;
+    }
+
+    int fd;
+    if (__adb_server_name) {
+        fd = socket_network_client(__adb_server_name, __adb_server_port, SOCK_STREAM);
+    } else {
+        fd = socket_loopback_client(__adb_server_port, SOCK_STREAM);
+    }
+    if (fd < 0) {
+        *error = perror_str("cannot connect to daemon");
+        return -2;
+    }
+
+    if (memcmp(&service[0],"host",4) != 0 && switch_socket_transport(fd, error)) {
+        return -1;
+    }
+
+    if(!SendProtocolString(fd, service)) {
+        *error = perror_str("write failure during connection");
+        adb_close(fd);
+        return -1;
+    }
+
+    if (!adb_status(fd, error)) {
+        adb_close(fd);
+        return -1;
+    }
+
+    D("_adb_connect: return fd %d\n", fd);
+    return fd;
+}
+
+int adb_connect(const std::string& service, std::string* error) {
+    // first query the adb server's version
+    int fd = _adb_connect("host:version", error);
+
+    D("adb_connect: service %s\n", service.c_str());
+    if (fd == -2 && __adb_server_name) {
+        fprintf(stderr,"** Cannot start server on remote host\n");
+        return fd;
+    } else if (fd == -2) {
+        fprintf(stdout,"* daemon not running. starting it now on port %d *\n",
+                __adb_server_port);
+    start_server:
+        if (launch_server(__adb_server_port)) {
+            fprintf(stderr,"* failed to start daemon *\n");
+            return -1;
+        } else {
+            fprintf(stdout,"* daemon started successfully *\n");
+        }
+        /* give the server some time to start properly and detect devices */
+        adb_sleep_ms(3000);
+        // fall through to _adb_connect
+    } else {
+        // if server was running, check its version to make sure it is not out of date
+        int version = ADB_SERVER_VERSION - 1;
+
+        // if we have a file descriptor, then parse version result
+        if (fd >= 0) {
+            std::string version_string;
+            if (!ReadProtocolString(fd, &version_string, error)) {
+                goto error;
+            }
+
+            adb_close(fd);
+
+            if (sscanf(&version_string[0], "%04x", &version) != 1) {
+                goto error;
+            }
+        } else {
+            // if fd is -1, then check for "unknown host service",
+            // which would indicate a version of adb that does not support the version command
+            if (*error == "unknown host service") {
+                return fd;
+            }
+        }
+
+        if (version != ADB_SERVER_VERSION) {
+            printf("adb server is out of date.  killing...\n");
+            fd = _adb_connect("host:kill", error);
+            adb_close(fd);
+
+            /* XXX can we better detect its death? */
+            adb_sleep_ms(2000);
+            goto start_server;
+        }
+    }
+
+    // if the command is start-server, we are done.
+    if (service == "host:start-server") {
+        return 0;
+    }
+
+    fd = _adb_connect(service, error);
+    if (fd == -1) {
+        D("_adb_connect error: %s", error->c_str());
+    } else if(fd == -2) {
+        fprintf(stderr,"** daemon still not running\n");
+    }
+    D("adb_connect: return fd %d\n", fd);
+
+    return fd;
+error:
+    adb_close(fd);
+    return -1;
+}
+
+
+int adb_command(const std::string& service, std::string* error) {
+    int fd = adb_connect(service, error);
+    if (fd < 0) {
+        fprintf(stderr, "error: %s\n", error->c_str());
+        return -1;
+    }
+
+    if (!adb_status(fd, error)) {
+        adb_close(fd);
+        return -1;
+    }
+
+    return 0;
+}
+
+bool adb_query(const std::string& service, std::string* result, std::string* error) {
+    D("adb_query: %s\n", service.c_str());
+    int fd = adb_connect(service, error);
+    if (fd < 0) {
+        fprintf(stderr,"error: %s\n", error->c_str());
+        return 0;
+    }
+
+    result->clear();
+    if (!ReadProtocolString(fd, result, error)) {
+        adb_close(fd);
+        return false;
+    }
+    return true;
+}
diff --git a/adb/adb_client.h b/adb/adb_client.h
index 0ec47ca..96416f5 100644
--- a/adb/adb_client.h
+++ b/adb/adb_client.h
@@ -3,23 +3,23 @@
 
 #include "adb.h"
 
+#include <string>
+
 /* connect to adb, connect to the named service, and return
 ** a valid fd for interacting with that service upon success
 ** or a negative number on failure
 */
-int adb_connect(const char *service);
-int _adb_connect(const char *service);
+int adb_connect(const std::string& service, std::string* error);
+int _adb_connect(const std::string& service, std::string* error);
 
 /* connect to adb, connect to the named service, return 0 if
 ** the connection succeeded AND the service returned OKAY
 */
-int adb_command(const char *service);
+int adb_command(const std::string& service, std::string* error);
 
-/* connect to adb, connect to the named service, return
-** a malloc'd string of its response upon success or NULL
-** on failure.
-*/
-char *adb_query(const char *service);
+// Connects to the named adb service and fills 'result' with the response.
+// Returns true on success; returns false and fills 'error' on failure.
+bool adb_query(const std::string& service, std::string* result, std::string* error);
 
 /* Set the preferred transport to connect to.
 */
@@ -43,15 +43,11 @@
  * is zero, or more than one emulator connected (or if you use -s <serial>
  * with a <serial> that does not designate an emulator)
  */
-int  adb_send_emulator_command(int  argc, char**  argv);
+int  adb_send_emulator_command(int  argc, const char**  argv);
 
-/* return verbose error string from last operation */
-const char *adb_error(void);
-
-/* read a standard adb status response (OKAY|FAIL) and
-** return 0 in the event of OKAY, -1 in the event of FAIL
-** or protocol error
-*/
-int adb_status(int fd);
+// Reads a standard adb status response (OKAY|FAIL) and
+// returns true in the event of OKAY, false in the event of FAIL
+// or protocol error.
+bool adb_status(int fd, std::string* error);
 
 #endif
diff --git a/adb/adb_io.cpp b/adb/adb_io.cpp
new file mode 100644
index 0000000..5ae6ec3
--- /dev/null
+++ b/adb/adb_io.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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 TRACE_RWX
+
+#include "adb_io.h"
+
+#include <unistd.h>
+
+#include <base/stringprintf.h>
+
+#include "adb_trace.h"
+#include "adb_utils.h"
+#include "sysdeps.h"
+
+bool SendProtocolString(int fd, const std::string& s) {
+    int length = s.size();
+    if (length > 0xffff) {
+        length = 0xffff;
+    }
+
+    return WriteFdFmt(fd, "%04x", length) && WriteFdExactly(fd, s);
+}
+
+bool SendOkay(int fd) {
+    return WriteFdExactly(fd, "OKAY", 4);
+}
+
+bool SendFail(int fd, const std::string& reason) {
+    return WriteFdExactly(fd, "FAIL", 4) && SendProtocolString(fd, reason);
+}
+
+bool ReadFdExactly(int fd, void* buf, size_t len) {
+    char* p = reinterpret_cast<char*>(buf);
+
+    size_t len0 = len;
+
+    D("readx: fd=%d wanted=%zu\n", fd, len);
+    while (len > 0) {
+        int r = adb_read(fd, p, len);
+        if (r > 0) {
+            len -= r;
+            p += r;
+        } else if (r == -1) {
+            D("readx: fd=%d error %d: %s\n", fd, errno, strerror(errno));
+            return false;
+        } else {
+            D("readx: fd=%d disconnected\n", fd);
+            errno = 0;
+            return false;
+        }
+    }
+
+    D("readx: fd=%d wanted=%zu got=%zu\n", fd, len0, len0 - len);
+    if (ADB_TRACING) {
+        dump_hex(reinterpret_cast<const unsigned char*>(buf), len0);
+    }
+
+    return true;
+}
+
+bool WriteFdExactly(int fd, const void* buf, size_t len) {
+    const char* p = reinterpret_cast<const char*>(buf);
+    int r;
+
+    D("writex: fd=%d len=%d: ", fd, (int)len);
+    if (ADB_TRACING) {
+        dump_hex(reinterpret_cast<const unsigned char*>(buf), len);
+    }
+
+    while (len > 0) {
+        r = adb_write(fd, p, len);
+        if (r == -1) {
+            D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno));
+            if (errno == EAGAIN) {
+                adb_sleep_ms(1); // just yield some cpu time
+                continue;
+            } else if (errno == EPIPE) {
+                D("writex: fd=%d disconnected\n", fd);
+                errno = 0;
+                return false;
+            } else {
+                return false;
+            }
+        } else {
+            len -= r;
+            p += r;
+        }
+    }
+    return true;
+}
+
+bool WriteFdExactly(int fd, const char* str) {
+    return WriteFdExactly(fd, str, strlen(str));
+}
+
+bool WriteFdExactly(int fd, const std::string& str) {
+    return WriteFdExactly(fd, str.c_str(), str.size());
+}
+
+bool WriteFdFmt(int fd, const char* fmt, ...) {
+    std::string str;
+
+    va_list ap;
+    va_start(ap, fmt);
+    android::base::StringAppendV(&str, fmt, ap);
+    va_end(ap);
+
+    return WriteFdExactly(fd, str);
+}
diff --git a/adb/adb_io.h b/adb/adb_io.h
new file mode 100644
index 0000000..8d50a6d
--- /dev/null
+++ b/adb/adb_io.h
@@ -0,0 +1,59 @@
+/*
+ * 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 ADB_IO_H
+#define ADB_IO_H
+
+#include <sys/types.h>
+
+#include <string>
+
+// Sends the protocol "OKAY" message.
+bool SendOkay(int fd);
+
+// Sends the protocol "FAIL" message, with the given failure reason.
+bool SendFail(int fd, const std::string& reason);
+
+// Writes a protocol-format string; a four hex digit length followed by the string data.
+bool SendProtocolString(int fd, const std::string& s);
+
+/*
+ * Reads exactly len bytes from fd into buf.
+ *
+ * Returns false if there is an error or if EOF was reached before len bytes
+ * were read. If EOF was found, errno will be set to 0.
+ *
+ * If this function fails, the contents of buf are undefined.
+ */
+bool ReadFdExactly(int fd, void *buf, size_t len);
+
+/*
+ * Writes exactly len bytes from buf to fd.
+ *
+ * Returns false if there is an error or if the fd was closed before the write
+ * completed. If the other end of the fd (such as in a socket, pipe, or fifo),
+ * is closed, errno will be set to 0.
+ */
+bool WriteFdExactly(int fd, const void* buf, size_t len);
+
+// Same as above, but for strings.
+bool WriteFdExactly(int fd, const char* s);
+bool WriteFdExactly(int fd, const std::string& s);
+
+// Same as above, but formats the string to send.
+bool WriteFdFmt(int fd, const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3)));
+
+#endif /* ADB_IO_H */
diff --git a/adb/adb_io_test.cpp b/adb/adb_io_test.cpp
new file mode 100644
index 0000000..8fd5cbf
--- /dev/null
+++ b/adb/adb_io_test.cpp
@@ -0,0 +1,167 @@
+/*
+ * 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 "adb_io.h"
+
+#include <gtest/gtest.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "base/file.h"
+
+class TemporaryFile {
+ public:
+  TemporaryFile() {
+    init("/data/local/tmp");
+    if (fd == -1) {
+      init("/tmp");
+    }
+  }
+
+  ~TemporaryFile() {
+    close(fd);
+    unlink(filename);
+  }
+
+  int fd;
+  char filename[1024];
+
+ private:
+  void init(const char* tmp_dir) {
+    snprintf(filename, sizeof(filename), "%s/TemporaryFile-XXXXXX", tmp_dir);
+    fd = mkstemp(filename);
+  }
+};
+
+TEST(io, ReadFdExactly_whole) {
+  const char expected[] = "Foobar";
+  TemporaryFile tf;
+  ASSERT_NE(-1, tf.fd);
+
+  ASSERT_TRUE(android::base::WriteStringToFd(expected, tf.fd)) << strerror(errno);
+  ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0));
+
+  // Test reading the whole file.
+  char buf[sizeof(expected)] = {};
+  ASSERT_TRUE(ReadFdExactly(tf.fd, buf, sizeof(buf) - 1)) << strerror(errno);
+  EXPECT_STREQ(expected, buf);
+}
+
+TEST(io, ReadFdExactly_eof) {
+  const char expected[] = "Foobar";
+  TemporaryFile tf;
+  ASSERT_NE(-1, tf.fd);
+
+  ASSERT_TRUE(android::base::WriteStringToFd(expected, tf.fd)) << strerror(errno);
+  ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0));
+
+  // Test that not having enough data will fail.
+  char buf[sizeof(expected) + 1] = {};
+  ASSERT_FALSE(ReadFdExactly(tf.fd, buf, sizeof(buf)));
+  EXPECT_EQ(0, errno) << strerror(errno);
+}
+
+TEST(io, ReadFdExactly_partial) {
+  const char input[] = "Foobar";
+  TemporaryFile tf;
+  ASSERT_NE(-1, tf.fd);
+
+  ASSERT_TRUE(android::base::WriteStringToFd(input, tf.fd)) << strerror(errno);
+  ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0));
+
+  // Test reading a partial file.
+  char buf[sizeof(input) - 1] = {};
+  ASSERT_TRUE(ReadFdExactly(tf.fd, buf, sizeof(buf) - 1));
+
+  std::string expected(input);
+  expected.pop_back();
+  EXPECT_STREQ(expected.c_str(), buf);
+}
+
+TEST(io, WriteFdExactly_whole) {
+  const char expected[] = "Foobar";
+  TemporaryFile tf;
+  ASSERT_NE(-1, tf.fd);
+
+  // Test writing the whole string to the file.
+  ASSERT_TRUE(WriteFdExactly(tf.fd, expected, sizeof(expected)))
+    << strerror(errno);
+  ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0));
+
+  std::string s;
+  ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s));
+  EXPECT_STREQ(expected, s.c_str());
+}
+
+TEST(io, WriteFdExactly_partial) {
+  const char buf[] = "Foobar";
+  TemporaryFile tf;
+  ASSERT_NE(-1, tf.fd);
+
+  // Test writing a partial string to the file.
+  ASSERT_TRUE(WriteFdExactly(tf.fd, buf, sizeof(buf) - 2)) << strerror(errno);
+  ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0));
+
+  std::string expected(buf);
+  expected.pop_back();
+
+  std::string s;
+  ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s));
+  EXPECT_EQ(expected, s);
+}
+
+TEST(io, WriteFdExactly_ENOSPC) {
+    int fd = open("/dev/full", O_WRONLY);
+    ASSERT_NE(-1, fd);
+
+    char buf[] = "foo";
+    ASSERT_FALSE(WriteFdExactly(fd, buf, sizeof(buf)));
+    ASSERT_EQ(ENOSPC, errno);
+}
+
+TEST(io, WriteFdExactly_string) {
+  const char str[] = "Foobar";
+  TemporaryFile tf;
+  ASSERT_NE(-1, tf.fd);
+
+  // Test writing a partial string to the file.
+  ASSERT_TRUE(WriteFdExactly(tf.fd, str)) << strerror(errno);
+  ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0));
+
+  std::string s;
+  ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s));
+  EXPECT_STREQ(str, s.c_str());
+}
+
+TEST(io, WriteFdFmt) {
+    TemporaryFile tf;
+    ASSERT_NE(-1, tf.fd);
+
+    // Test writing a partial string to the file.
+    ASSERT_TRUE(WriteFdFmt(tf.fd, "Foo%s%d", "bar", 123)) << strerror(errno);
+    ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0));
+
+    std::string s;
+    ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s));
+    EXPECT_STREQ("Foobar123", s.c_str());
+}
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
new file mode 100644
index 0000000..3fc4719
--- /dev/null
+++ b/adb/adb_listeners.cpp
@@ -0,0 +1,274 @@
+/*
+ * 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 "adb_listeners.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <base/stringprintf.h>
+
+#include "sysdeps.h"
+#include "transport.h"
+
+int gListenAll = 0; /* Not static because it is used in commandline.c. */
+
+alistener listener_list = {
+    .next = &listener_list,
+    .prev = &listener_list,
+};
+
+void ss_listener_event_func(int _fd, unsigned ev, void *_l)
+{
+    asocket *s;
+
+    if(ev & FDE_READ) {
+        struct sockaddr addr;
+        socklen_t alen;
+        int fd;
+
+        alen = sizeof(addr);
+        fd = adb_socket_accept(_fd, &addr, &alen);
+        if(fd < 0) return;
+
+        adb_socket_setbufsize(fd, CHUNK_SIZE);
+
+        s = create_local_socket(fd);
+        if(s) {
+            connect_to_smartsocket(s);
+            return;
+        }
+
+        adb_close(fd);
+    }
+}
+
+void listener_event_func(int _fd, unsigned ev, void* _l)
+{
+    alistener* listener = reinterpret_cast<alistener*>(_l);
+    asocket *s;
+
+    if (ev & FDE_READ) {
+        struct sockaddr addr;
+        socklen_t alen;
+        int fd;
+
+        alen = sizeof(addr);
+        fd = adb_socket_accept(_fd, &addr, &alen);
+        if (fd < 0) {
+            return;
+        }
+
+        s = create_local_socket(fd);
+        if (s) {
+            s->transport = listener->transport;
+            connect_to_remote(s, listener->connect_to);
+            return;
+        }
+
+        adb_close(fd);
+    }
+}
+
+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) {
+        remove_transport_disconnect(l->transport, &l->disconnect);
+    }
+    free(l);
+}
+
+void listener_disconnect(void* listener, atransport*  t)
+{
+    free_listener(reinterpret_cast<alistener*>(listener));
+}
+
+int local_name_to_fd(const char *name)
+{
+    int port;
+
+    if(!strncmp("tcp:", name, 4)){
+        int  ret;
+        port = atoi(name + 4);
+
+        if (gListenAll > 0) {
+            ret = socket_inaddr_any_server(port, SOCK_STREAM);
+        } else {
+            ret = socket_loopback_server(port, SOCK_STREAM);
+        }
+
+        return ret;
+    }
+#ifndef HAVE_WIN32_IPC  /* no Unix-domain sockets on Win32 */
+    // It's non-sensical to support the "reserved" space on the adb host side
+    if(!strncmp(name, "local:", 6)) {
+        return socket_local_server(name + 6,
+                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+    } else if(!strncmp(name, "localabstract:", 14)) {
+        return socket_local_server(name + 14,
+                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+    } else if(!strncmp(name, "localfilesystem:", 16)) {
+        return socket_local_server(name + 16,
+                ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
+    }
+
+#endif
+    printf("unknown local portname '%s'\n", 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) {
+        // Ignore special listeners like those for *smartsocket*
+        if (l->connect_to[0] == '*') {
+            continue;
+        }
+        //  <device-serial> " " <local-name> " " <remote-name> "\n"
+        android::base::StringAppendF(&result, "%s %s %s\n",
+                                     l->transport->serial, l->local_name, l->connect_to);
+    }
+    return result;
+}
+
+install_status_t 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)) {
+            listener_disconnect(l, l->transport);
+            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;
+        // Never remove smart sockets.
+        if (l->connect_to[0] == '*')
+            continue;
+        listener_disconnect(l, l->transport);
+    }
+}
+
+install_status_t install_listener(const std::string& local_name,
+                                  const char *connect_to,
+                                  atransport* transport,
+                                  int no_rebind)
+{
+    for (alistener* l = listener_list.next; l != &listener_list; l = l->next) {
+        if (local_name == l->local_name) {
+            char* cto;
+
+            /* can't repurpose a smartsocket */
+            if(l->connect_to[0] == '*') {
+                return INSTALL_STATUS_INTERNAL_ERROR;
+            }
+
+            /* can't repurpose a listener if 'no_rebind' is true */
+            if (no_rebind) {
+                return INSTALL_STATUS_CANNOT_REBIND;
+            }
+
+            cto = strdup(connect_to);
+            if(cto == 0) {
+                return INSTALL_STATUS_INTERNAL_ERROR;
+            }
+
+            free((void*) l->connect_to);
+            l->connect_to = cto;
+            if (l->transport != transport) {
+                remove_transport_disconnect(l->transport, &l->disconnect);
+                l->transport = transport;
+                add_transport_disconnect(l->transport, &l->disconnect);
+            }
+            return INSTALL_STATUS_OK;
+        }
+    }
+
+    alistener* listener = reinterpret_cast<alistener*>(
+        calloc(1, sizeof(alistener)));
+    if (listener == nullptr) {
+        goto nomem;
+    }
+
+    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);
+    if (listener->fd < 0) {
+        printf("cannot bind '%s': %s\n", listener->local_name, strerror(errno));
+        free(listener->local_name);
+        free(listener->connect_to);
+        free(listener);
+        return INSTALL_STATUS_CANNOT_BIND;
+    }
+
+    close_on_exec(listener->fd);
+    if (!strcmp(listener->connect_to, "*smartsocket*")) {
+        fdevent_install(&listener->fde, listener->fd, ss_listener_event_func,
+                        listener);
+    } else {
+        fdevent_install(&listener->fde, listener->fd, listener_event_func,
+                        listener);
+    }
+    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.func   = listener_disconnect;
+        add_transport_disconnect(transport, &listener->disconnect);
+    }
+    return INSTALL_STATUS_OK;
+
+nomem:
+    fatal("cannot allocate listener");
+    return INSTALL_STATUS_INTERNAL_ERROR;
+}
diff --git a/adb/adb_listeners.h b/adb/adb_listeners.h
new file mode 100644
index 0000000..67168ae
--- /dev/null
+++ b/adb/adb_listeners.h
@@ -0,0 +1,49 @@
+/*
+ * 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 __ADB_LISTENERS_H
+#define __ADB_LISTENERS_H
+
+#include "adb.h"
+
+#include <string>
+
+// error/status codes for install_listener.
+enum install_status_t {
+  INSTALL_STATUS_OK = 0,
+  INSTALL_STATUS_INTERNAL_ERROR = -1,
+  INSTALL_STATUS_CANNOT_BIND = -2,
+  INSTALL_STATUS_CANNOT_REBIND = -3,
+  INSTALL_STATUS_LISTENER_NOT_FOUND = -4,
+};
+
+extern alistener listener_list;
+
+void listener_disconnect(void*  _l, atransport*  t);
+void listener_event_func(int _fd, unsigned ev, void *_l);
+void ss_listener_event_func(int _fd, unsigned ev, void *_l);
+
+install_status_t install_listener(const std::string& local_name,
+                                  const char* connect_to,
+                                  atransport* transport,
+                                  int no_rebind);
+
+std::string format_listeners();
+
+install_status_t remove_listener(const char* local_name, atransport* transport);
+void remove_all_listeners(void);
+
+#endif /* __ADB_LISTENERS_H */
diff --git a/adb/adb_main.cpp b/adb/adb_main.cpp
new file mode 100644
index 0000000..45a2158
--- /dev/null
+++ b/adb/adb_main.cpp
@@ -0,0 +1,411 @@
+/*
+ * 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 TRACE_ADB
+
+#include "sysdeps.h"
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "adb.h"
+#include "adb_auth.h"
+#include "adb_listeners.h"
+#include "transport.h"
+
+#include <base/stringprintf.h>
+
+#if !ADB_HOST
+#include <getopt.h>
+#include <sys/prctl.h>
+
+#include "cutils/properties.h"
+#include "private/android_filesystem_config.h"
+#include "selinux/selinux.h"
+
+#include "qemu_tracing.h"
+#endif
+
+static void adb_cleanup(void)
+{
+    usb_cleanup();
+}
+
+#if defined(_WIN32)
+static BOOL WINAPI ctrlc_handler(DWORD type)
+{
+    exit(STATUS_CONTROL_C_EXIT);
+    return TRUE;
+}
+#endif
+
+#if ADB_HOST
+#ifdef WORKAROUND_BUG6558362
+#include <sched.h>
+#define AFFINITY_ENVVAR "ADB_CPU_AFFINITY_BUG6558362"
+void adb_set_affinity(void)
+{
+   cpu_set_t cpu_set;
+   const char* cpunum_str = getenv(AFFINITY_ENVVAR);
+   char* strtol_res;
+   int cpu_num;
+
+   if (!cpunum_str || !*cpunum_str)
+       return;
+   cpu_num = strtol(cpunum_str, &strtol_res, 0);
+   if (*strtol_res != '\0')
+     fatal("bad number (%s) in env var %s. Expecting 0..n.\n", cpunum_str, AFFINITY_ENVVAR);
+
+   sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
+   D("orig cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
+   CPU_ZERO(&cpu_set);
+   CPU_SET(cpu_num, &cpu_set);
+   sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
+   sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
+   D("new cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
+}
+#endif
+#else /* ADB_HOST */
+static const char *root_seclabel = NULL;
+
+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) {
+        return;
+    }
+#endif
+    int i;
+    for (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;
+        }
+        int err = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
+
+        // Some kernels don't have file capabilities compiled in, and
+        // prctl(PR_CAPBSET_DROP) returns EINVAL. Don't automatically
+        // die when we see such misconfigured kernels.
+        if ((err < 0) && (errno != EINVAL)) {
+            exit(1);
+        }
+    }
+}
+
+static bool should_drop_privileges() {
+#if defined(ALLOW_ADBD_ROOT)
+    char value[PROPERTY_VALUE_MAX];
+
+    // The emulator is never secure, so don't drop privileges there.
+    // TODO: this seems like a bug --- shouldn't the emulator behave like a device?
+    property_get("ro.kernel.qemu", value, "");
+    if (strcmp(value, "1") == 0) {
+        return false;
+    }
+
+    // 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.
+    //
+    // ro.debuggable:
+    //   Allowed to become root, but not necessarily the default. Set to 1 on
+    //   eng and userdebug builds.
+    //
+    // 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);
+
+    // 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.
+    if (ro_debuggable && adb_root) {
+        drop = false;
+    }
+
+    // ...and "adb unroot" lets you explicitly drop privileges.
+    if (adb_unroot) {
+        drop = true;
+    }
+
+    return drop;
+#else
+    return true; // "adb root" not allowed, always drop privileges.
+#endif /* ALLOW_ADBD_ROOT */
+}
+#endif /* ADB_HOST */
+
+void start_logging(void)
+{
+#if defined(_WIN32)
+    char    temp[ MAX_PATH ];
+    FILE*   fnul;
+    FILE*   flog;
+
+    GetTempPath( sizeof(temp) - 8, temp );
+    strcat( temp, "adb.log" );
+
+    /* Win32 specific redirections */
+    fnul = fopen( "NUL", "rt" );
+    if (fnul != NULL)
+        stdin[0] = fnul[0];
+
+    flog = fopen( temp, "at" );
+    if (flog == NULL)
+        flog = fnul;
+
+    setvbuf( flog, NULL, _IONBF, 0 );
+
+    stdout[0] = flog[0];
+    stderr[0] = flog[0];
+    fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
+#else
+    int fd;
+
+    fd = unix_open("/dev/null", O_RDONLY);
+    dup2(fd, 0);
+    adb_close(fd);
+
+    fd = unix_open("/tmp/adb.log", O_WRONLY | O_CREAT | O_APPEND, 0640);
+    if(fd < 0) {
+        fd = unix_open("/dev/null", O_WRONLY);
+    }
+    dup2(fd, 1);
+    dup2(fd, 2);
+    adb_close(fd);
+    fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
+#endif
+}
+
+int adb_main(int is_daemon, int server_port)
+{
+#if !ADB_HOST
+    int port;
+    char value[PROPERTY_VALUE_MAX];
+
+    umask(000);
+#endif
+
+    atexit(adb_cleanup);
+#if defined(_WIN32)
+    SetConsoleCtrlHandler( ctrlc_handler, TRUE );
+#else
+    // No SIGCHLD. Let the service subproc handle its children.
+    signal(SIGPIPE, SIG_IGN);
+#endif
+
+    init_transport_registration();
+
+#if ADB_HOST
+    HOST = 1;
+
+#ifdef WORKAROUND_BUG6558362
+    if(is_daemon) adb_set_affinity();
+#endif
+    usb_init();
+    local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
+    adb_auth_init();
+
+    std::string local_name = android::base::StringPrintf("tcp:%d", server_port);
+    if (install_listener(local_name, "*smartsocket*", NULL, 0)) {
+        exit(1);
+    }
+#else
+    // We need to call this even if auth isn't enabled because the file
+    // descriptor will always be open.
+    adbd_cloexec_auth_socket();
+
+    if (ALLOW_ADBD_NO_AUTH && property_get_bool("ro.adb.secure", 0) == 0) {
+        auth_required = false;
+    }
+
+    adbd_auth_init();
+
+    // Our external storage path may be different than apps, since
+    // we aren't able to bind mount after dropping root.
+    const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE");
+    if (NULL != adb_external_storage) {
+        setenv("EXTERNAL_STORAGE", adb_external_storage, 1);
+    } else {
+        D("Warning: ADB_EXTERNAL_STORAGE is not set.  Leaving EXTERNAL_STORAGE"
+          " unchanged.\n");
+    }
+
+    /* add extra groups:
+    ** AID_ADB to access the USB driver
+    ** AID_LOG to read system logs (adb logcat)
+    ** AID_INPUT to diagnose input issues (getevent)
+    ** AID_INET to diagnose network issues (ping)
+    ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
+    ** AID_SDCARD_R to allow reading from the SD card
+    ** AID_SDCARD_RW to allow writing to the SD card
+    ** AID_NET_BW_STATS to read out qtaguid statistics
+    */
+    gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_NET_BT,
+                       AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
+                       AID_NET_BW_STATS };
+    if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
+        exit(1);
+    }
+
+    /* don't listen on a port (default 5037) if running in secure mode */
+    /* don't run as root if we are running in secure mode */
+    if (should_drop_privileges()) {
+        drop_capabilities_bounding_set_if_needed();
+
+        /* then switch user and group to "shell" */
+        if (setgid(AID_SHELL) != 0) {
+            exit(1);
+        }
+        if (setuid(AID_SHELL) != 0) {
+            exit(1);
+        }
+
+        D("Local port disabled\n");
+    } else {
+        if ((root_seclabel != NULL) && (is_selinux_enabled() > 0)) {
+            // b/12587913: fix setcon to allow const pointers
+            if (setcon((char *)root_seclabel) < 0) {
+                exit(1);
+            }
+        }
+        std::string local_name = android::base::StringPrintf("tcp:%d", server_port);
+        if (install_listener(local_name, "*smartsocket*", NULL, 0)) {
+            exit(1);
+        }
+    }
+
+    int usb = 0;
+    if (access(USB_ADB_PATH, F_OK) == 0 || access(USB_FFS_ADB_EP0, F_OK) == 0) {
+        // listen on USB
+        usb_init();
+        usb = 1;
+    }
+
+    // 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.
+    property_get("service.adb.tcp.port", value, "");
+    if (!value[0]) {
+        property_get("persist.adb.tcp.port", value, "");
+    }
+    if (sscanf(value, "%d", &port) == 1 && port > 0) {
+        printf("using port=%d\n", port);
+        // listen on TCP port specified by service.adb.tcp.port property
+        local_init(port);
+    } else if (!usb) {
+        // listen on default port
+        local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
+    }
+
+    D("adb_main(): pre init_jdwp()\n");
+    init_jdwp();
+    D("adb_main(): post init_jdwp()\n");
+#endif
+
+    if (is_daemon)
+    {
+        // inform our parent that we are up and running.
+#if defined(_WIN32)
+        DWORD  count;
+        WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL );
+#else
+        fprintf(stderr, "OK\n");
+#endif
+        start_logging();
+    }
+    D("Event loop starting\n");
+
+    fdevent_loop();
+
+    usb_cleanup();
+
+    return 0;
+}
+
+#if !ADB_HOST
+void close_stdin() {
+    int fd = unix_open("/dev/null", O_RDONLY);
+    if (fd == -1) {
+        perror("failed to open /dev/null, stdin will remain open");
+        return;
+    }
+    dup2(fd, 0);
+    adb_close(fd);
+}
+#endif
+
+// TODO(danalbert): Split this file up into adb_main.cpp and adbd_main.cpp.
+int main(int argc, char **argv) {
+#if ADB_HOST
+    // adb client/server
+    adb_sysdeps_init();
+    adb_trace_init();
+    D("Handling commandline()\n");
+    return adb_commandline(argc - 1, const_cast<const char**>(argv + 1));
+#else
+    // adbd
+    while (true) {
+        static struct option opts[] = {
+            {"root_seclabel", required_argument, nullptr, 's'},
+            {"device_banner", required_argument, nullptr, 'b'},
+            {"version", no_argument, nullptr, 'v'},
+        };
+
+        int option_index = 0;
+        int c = getopt_long(argc, argv, "", opts, &option_index);
+        if (c == -1)
+            break;
+        switch (c) {
+        case 's':
+            root_seclabel = optarg;
+            break;
+        case 'b':
+            adb_device_banner = optarg;
+            break;
+        case 'v':
+            printf("Android Debug Bridge Daemon version %d.%d.%d %s\n",
+                   ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION,
+                   ADB_REVISION);
+            return 0;
+        default:
+            break;
+        }
+    }
+
+    close_stdin();
+
+    adb_trace_init();
+
+    /* If adbd runs inside the emulator this will enable adb tracing via
+     * adb-debug qemud service in the emulator. */
+    adb_qemu_trace_init();
+
+    D("Handling main()\n");
+    return adb_main(0, DEFAULT_ADB_PORT);
+#endif
+}
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
index 8a5d9f8..63d4151 100644
--- a/adb/adb_trace.h
+++ b/adb/adb_trace.h
@@ -19,16 +19,15 @@
 
 #if !ADB_HOST
 #include <android/log.h>
+#else
+#include <stdio.h>
 #endif
 
-/* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */
-#define  ADB_TRACE    1
-
 /* IMPORTANT: if you change the following list, don't
  * forget to update the corresponding 'tags' table in
  * the adb_trace_init() function implemented in adb.c
  */
-typedef enum {
+enum AdbTrace {
     TRACE_ADB = 0,   /* 0x001 */
     TRACE_SOCKETS,
     TRACE_PACKETS,
@@ -41,9 +40,7 @@
     TRACE_SERVICES,
     TRACE_AUTH,
     TRACE_FDEVENT,
-} AdbTrace;
-
-#if ADB_TRACE
+} ;
 
 #if !ADB_HOST
 /*
@@ -73,8 +70,9 @@
             if (ADB_TRACING) {                         \
                 int save_errno = errno;                \
                 adb_mutex_lock(&D_lock);               \
-                fprintf(stderr, "%s::%s():",           \
-                        __FILE__, __FUNCTION__);       \
+                fprintf(stderr, "%16s: %5d:%5lu | ",   \
+                        __FUNCTION__,                  \
+                        getpid(), adb_thread_id());    \
                 errno = save_errno;                    \
                 fprintf(stderr, __VA_ARGS__ );         \
                 fflush(stderr);                        \
@@ -94,18 +92,6 @@
                 errno = save_errno;                    \
            }                                           \
         } while (0)
-#  define  DD(...)                                     \
-        do {                                           \
-          int save_errno = errno;                      \
-          adb_mutex_lock(&D_lock);                     \
-          fprintf(stderr, "%s::%s():",                 \
-                  __FILE__, __FUNCTION__);             \
-          errno = save_errno;                          \
-          fprintf(stderr, __VA_ARGS__ );               \
-          fflush(stderr);                              \
-          adb_mutex_unlock(&D_lock);                   \
-          errno = save_errno;                          \
-        } while (0)
 #else
 #  define  D(...)                                      \
         do {                                           \
@@ -125,19 +111,6 @@
                     __VA_ARGS__ );                     \
             }                                          \
         } while (0)
-#  define  DD(...)                                     \
-        do {                                           \
-          __android_log_print(                         \
-              ANDROID_LOG_INFO,                        \
-              __FUNCTION__,                            \
-              __VA_ARGS__ );                           \
-        } while (0)
 #endif /* ADB_HOST */
-#else
-#  define  D(...)          ((void)0)
-#  define  DR(...)         ((void)0)
-#  define  DD(...)         ((void)0)
-#  define  ADB_TRACING     0
-#endif /* ADB_TRACE */
 
 #endif /* __ADB_TRACE_H */
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
new file mode 100644
index 0000000..604bd57
--- /dev/null
+++ b/adb/adb_utils.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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 TRACE_ADB
+
+#include "adb_utils.h"
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <algorithm>
+
+#include <base/stringprintf.h>
+
+#include "adb_trace.h"
+#include "sysdeps.h"
+
+bool getcwd(std::string* s) {
+  char* cwd = getcwd(nullptr, 0);
+  if (cwd != nullptr) *s = cwd;
+  free(cwd);
+  return (cwd != nullptr);
+}
+
+bool directory_exists(const std::string& path) {
+  struct stat sb;
+  return lstat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode);
+}
+
+std::string escape_arg(const std::string& s) {
+  std::string result = s;
+
+  // Escape any ' in the string (before we single-quote the whole thing).
+  // The correct way to do this for the shell is to replace ' with '\'' --- that is,
+  // close the existing single-quoted string, escape a single single-quote, and start
+  // a new single-quoted string. Like the C preprocessor, the shell will concatenate
+  // these pieces into one string.
+  for (size_t i = 0; i < s.size(); ++i) {
+    if (s[i] == '\'') {
+      result.insert(i, "'\\'");
+      i += 2;
+    }
+  }
+
+  // Prefix and suffix the whole string with '.
+  result.insert(result.begin(), '\'');
+  result.push_back('\'');
+  return result;
+}
+
+void dump_hex(const void* data, size_t byte_count) {
+    byte_count = std::min(byte_count, size_t(16));
+
+    const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
+
+    std::string line;
+    for (size_t i = 0; i < byte_count; ++i) {
+        android::base::StringAppendF(&line, "%02x", p[i]);
+    }
+    line.push_back(' ');
+
+    for (size_t i = 0; i < byte_count; ++i) {
+        int c = p[i];
+        if (c < 32 || c > 127) {
+            c = '.';
+        }
+        line.push_back(c);
+    }
+
+    DR("%s\n", line.c_str());
+}
diff --git a/adb/usb_vendors.h b/adb/adb_utils.h
similarity index 66%
copy from adb/usb_vendors.h
copy to adb/adb_utils.h
index cee23a1..84f7d0c 100644
--- a/adb/usb_vendors.h
+++ b/adb/adb_utils.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 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.
@@ -14,12 +14,16 @@
  * limitations under the License.
  */
 
-#ifndef __USB_VENDORS_H
-#define __USB_VENDORS_H
+#ifndef _ADB_UTILS_H_
+#define _ADB_UTILS_H_
 
-extern int vendorIds[];
-extern unsigned  vendorIdCount;
+#include <string>
 
-void usb_vendors_init(void);
+bool getcwd(std::string* cwd);
+bool directory_exists(const std::string& path);
+
+std::string escape_arg(const std::string& s);
+
+void dump_hex(const void* ptr, size_t byte_count);
 
 #endif
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
new file mode 100644
index 0000000..052aea5
--- /dev/null
+++ b/adb/adb_utils_test.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 "adb_utils.h"
+
+#include <gtest/gtest.h>
+
+TEST(adb_utils, directory_exists) {
+  ASSERT_TRUE(directory_exists("/proc"));
+  ASSERT_FALSE(directory_exists("/proc/self")); // Symbolic link.
+  ASSERT_FALSE(directory_exists("/proc/does-not-exist"));
+}
+
+TEST(adb_utils, escape_arg) {
+  ASSERT_EQ(R"('')", escape_arg(""));
+
+  ASSERT_EQ(R"('abc')", escape_arg("abc"));
+
+  ASSERT_EQ(R"(' abc')", escape_arg(" abc"));
+  ASSERT_EQ(R"(''\''abc')", escape_arg("'abc"));
+  ASSERT_EQ(R"('"abc')", escape_arg("\"abc"));
+  ASSERT_EQ(R"('\abc')", escape_arg("\\abc"));
+  ASSERT_EQ(R"('(abc')", escape_arg("(abc"));
+  ASSERT_EQ(R"(')abc')", escape_arg(")abc"));
+
+  ASSERT_EQ(R"('abc abc')", escape_arg("abc abc"));
+  ASSERT_EQ(R"('abc'\''abc')", escape_arg("abc'abc"));
+  ASSERT_EQ(R"('abc"abc')", escape_arg("abc\"abc"));
+  ASSERT_EQ(R"('abc\abc')", escape_arg("abc\\abc"));
+  ASSERT_EQ(R"('abc(abc')", escape_arg("abc(abc"));
+  ASSERT_EQ(R"('abc)abc')", escape_arg("abc)abc"));
+
+  ASSERT_EQ(R"('abc ')", escape_arg("abc "));
+  ASSERT_EQ(R"('abc'\''')", escape_arg("abc'"));
+  ASSERT_EQ(R"('abc"')", escape_arg("abc\""));
+  ASSERT_EQ(R"('abc\')", escape_arg("abc\\"));
+  ASSERT_EQ(R"('abc(')", escape_arg("abc("));
+  ASSERT_EQ(R"('abc)')", escape_arg("abc)"));
+}
diff --git a/adb/commandline.c b/adb/commandline.c
deleted file mode 100644
index 7704878..0000000
--- a/adb/commandline.c
+++ /dev/null
@@ -1,2085 +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 <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <ctype.h>
-#include <assert.h>
-
-#include "sysdeps.h"
-
-#ifdef HAVE_TERMIO_H
-#include <termios.h>
-#endif
-
-#define  TRACE_TAG  TRACE_ADB
-#include "adb.h"
-#include "adb_client.h"
-#include "adb_auth.h"
-#include "file_sync_service.h"
-
-static int do_cmd(transport_type ttype, char* serial, char *cmd, ...);
-
-void get_my_path(char *s, size_t maxLen);
-int find_sync_dirs(const char *srcarg,
-        char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out);
-int install_app(transport_type transport, char* serial, int argc, char** argv);
-int install_multiple_app(transport_type transport, char* serial, int argc, char** argv);
-int uninstall_app(transport_type transport, char* serial, int argc, char** argv);
-
-static const char *gProductOutPath = NULL;
-extern int gListenAll;
-
-static char *product_file(const char *extra)
-{
-    int n;
-    char *x;
-
-    if (gProductOutPath == NULL) {
-        fprintf(stderr, "adb: Product directory not specified; "
-                "use -p or define ANDROID_PRODUCT_OUT\n");
-        exit(1);
-    }
-
-    n = strlen(gProductOutPath) + strlen(extra) + 2;
-    x = malloc(n);
-    if (x == 0) {
-        fprintf(stderr, "adb: Out of memory (product_file())\n");
-        exit(1);
-    }
-
-    snprintf(x, (size_t)n, "%s" OS_PATH_SEPARATOR_STR "%s", gProductOutPath, extra);
-    return x;
-}
-
-void version(FILE * out) {
-    fprintf(out, "Android Debug Bridge version %d.%d.%d\n",
-         ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION);
-}
-
-void help()
-{
-    version(stderr);
-
-    fprintf(stderr,
-        "\n"
-        " -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"
-        "\n"
-        "device commands:\n"
-        "  adb push [-p] <local> <remote>\n"
-        "                               - copy file/dir to device\n"
-        "                                 ('-p' to display the transfer progress)\n"
-        "  adb pull [-p] [-a] <remote> [<local>]\n"
-        "                               - copy file/dir from device\n"
-        "                                 ('-p' to display the transfer progress)\n"
-        "                                 ('-a' means copy timestamp and mode)\n"
-        "  adb sync [ <directory> ]     - copy host->device only if changed\n"
-        "                                 (-l means list but don't copy)\n"
-        "                                 (see 'adb help all')\n"
-        "  adb shell                    - run remote shell interactively\n"
-        "  adb shell <command>          - run remote shell command\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 --norebind <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 [-lrtsd] <file>\n"
-        "  adb install-multiple [-lrtsdp] <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)\n"
-        "                                 (-p: partial application install)\n"
-        "  adb uninstall [-k] <package> - remove this app package from the device\n"
-        "                                 ('-k' means keep the data and cache directories)\n"
-        "  adb bugreport                - return all information from the device\n"
-        "                                 that should be included in a bug report.\n"
-        "\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 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-device          - block until device is online\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 status-window            - continuously print device status for a specified device\n"
-        "  adb remount                  - remounts the /system and /vendor (if present) partitions on the device read-write\n"
-        "  adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n"
-        "  adb reboot-bootloader        - reboots the device into the bootloader\n"
-        "  adb root                     - restarts the adbd daemon with 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"
-        "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"
-        "\n"
-        "adb sync notes: adb sync [ <directory> ]\n"
-        "  <localdir> can be interpreted in several ways:\n"
-        "\n"
-        "  - If <directory> is not specified, /system, /vendor (if present), and /data partitions will be updated.\n"
-        "\n"
-        "  - If it is \"system\", \"vendor\" or \"data\", only the corresponding partition\n"
-        "    is updated.\n"
-        "\n"
-        "environmental 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"
-        );
-}
-
-int usage()
-{
-    help();
-    return 1;
-}
-
-#ifdef HAVE_TERMIO_H
-static struct termios tio_save;
-
-static void stdin_raw_init(int fd)
-{
-    struct termios tio;
-
-    if(tcgetattr(fd, &tio)) return;
-    if(tcgetattr(fd, &tio_save)) return;
-
-    tio.c_lflag = 0; /* disable CANON, ECHO*, etc */
-
-        /* no timeout but request at least one character per read */
-    tio.c_cc[VTIME] = 0;
-    tio.c_cc[VMIN] = 1;
-
-    tcsetattr(fd, TCSANOW, &tio);
-    tcflush(fd, TCIFLUSH);
-}
-
-static void stdin_raw_restore(int fd)
-{
-    tcsetattr(fd, TCSANOW, &tio_save);
-    tcflush(fd, TCIFLUSH);
-}
-#endif
-
-static void read_and_dump(int fd)
-{
-    char buf[4096];
-    int len;
-
-    while(fd >= 0) {
-        D("read_and_dump(): pre adb_read(fd=%d)\n", fd);
-        len = adb_read(fd, buf, 4096);
-        D("read_and_dump(): post adb_read(fd=%d): len=%d\n", fd, len);
-        if(len == 0) {
-            break;
-        }
-
-        if(len < 0) {
-            if(errno == EINTR) continue;
-            break;
-        }
-        fwrite(buf, 1, len, stdout);
-        fflush(stdout);
-    }
-}
-
-static void read_status_line(int fd, char* buf, size_t count)
-{
-    count--;
-    while (count > 0) {
-        int len = adb_read(fd, buf, count);
-        if (len == 0) {
-            break;
-        } else if (len < 0) {
-            if (errno == EINTR) continue;
-            break;
-        }
-
-        buf += len;
-        count -= len;
-    }
-    *buf = '\0';
-}
-
-static void copy_to_file(int inFd, int outFd) {
-    const size_t BUFSIZE = 32 * 1024;
-    char* buf = (char*) malloc(BUFSIZE);
-    int len;
-    long total = 0;
-
-    D("copy_to_file(%d -> %d)\n", inFd, outFd);
-#ifdef HAVE_TERMIO_H
-    if (inFd == STDIN_FILENO) {
-        stdin_raw_init(STDIN_FILENO);
-    }
-#endif
-    for (;;) {
-        if (inFd == STDIN_FILENO) {
-            len = unix_read(inFd, buf, BUFSIZE);
-        } else {
-            len = adb_read(inFd, buf, BUFSIZE);
-        }
-        if (len == 0) {
-            D("copy_to_file() : read 0 bytes; exiting\n");
-            break;
-        }
-        if (len < 0) {
-            if (errno == EINTR) {
-                D("copy_to_file() : EINTR, retrying\n");
-                continue;
-            }
-            D("copy_to_file() : error %d\n", errno);
-            break;
-        }
-        if (outFd == STDOUT_FILENO) {
-            fwrite(buf, 1, len, stdout);
-            fflush(stdout);
-        } else {
-            adb_write(outFd, buf, len);
-        }
-        total += len;
-    }
-#ifdef HAVE_TERMIO_H
-    if (inFd == STDIN_FILENO) {
-        stdin_raw_restore(STDIN_FILENO);
-    }
-#endif
-    D("copy_to_file() finished after %lu bytes\n", total);
-    free(buf);
-}
-
-static void *stdin_read_thread(void *x)
-{
-    int fd, fdi;
-    unsigned char buf[1024];
-    int r, n;
-    int state = 0;
-
-    int *fds = (int*) x;
-    fd = fds[0];
-    fdi = fds[1];
-    free(fds);
-
-    for(;;) {
-        /* fdi is really the client's stdin, so use read, not adb_read here */
-        D("stdin_read_thread(): pre unix_read(fdi=%d,...)\n", fdi);
-        r = unix_read(fdi, buf, 1024);
-        D("stdin_read_thread(): post unix_read(fdi=%d,...)\n", fdi);
-        if(r == 0) break;
-        if(r < 0) {
-            if(errno == EINTR) continue;
-            break;
-        }
-        for(n = 0; n < r; n++){
-            switch(buf[n]) {
-            case '\n':
-                state = 1;
-                break;
-            case '\r':
-                state = 1;
-                break;
-            case '~':
-                if(state == 1) state++;
-                break;
-            case '.':
-                if(state == 2) {
-                    fprintf(stderr,"\n* disconnect *\n");
-#ifdef HAVE_TERMIO_H
-                    stdin_raw_restore(fdi);
-#endif
-                    exit(0);
-                }
-            default:
-                state = 0;
-            }
-        }
-        r = adb_write(fd, buf, r);
-        if(r <= 0) {
-            break;
-        }
-    }
-    return 0;
-}
-
-int interactive_shell(void)
-{
-    adb_thread_t thr;
-    int fdi, fd;
-    int *fds;
-
-    fd = adb_connect("shell:");
-    if(fd < 0) {
-        fprintf(stderr,"error: %s\n", adb_error());
-        return 1;
-    }
-    fdi = 0; //dup(0);
-
-    fds = malloc(sizeof(int) * 2);
-    fds[0] = fd;
-    fds[1] = fdi;
-
-#ifdef HAVE_TERMIO_H
-    stdin_raw_init(fdi);
-#endif
-    adb_thread_create(&thr, stdin_read_thread, fds);
-    read_and_dump(fd);
-#ifdef HAVE_TERMIO_H
-    stdin_raw_restore(fdi);
-#endif
-    return 0;
-}
-
-
-static void format_host_command(char* buffer, size_t  buflen, const char* command, transport_type ttype, const char* serial)
-{
-    if (serial) {
-        snprintf(buffer, buflen, "host-serial:%s:%s", serial, command);
-    } else {
-        const char* prefix = "host";
-        if (ttype == kTransportUsb)
-            prefix = "host-usb";
-        else if (ttype == kTransportLocal)
-            prefix = "host-local";
-
-        snprintf(buffer, buflen, "%s:%s", prefix, command);
-    }
-}
-
-int adb_download_buffer(const char *service, const char *fn, const void* data, int sz,
-                        unsigned progress)
-{
-    char buf[4096];
-    unsigned total;
-    int fd;
-    const unsigned char *ptr;
-
-    sprintf(buf,"%s:%d", service, sz);
-    fd = adb_connect(buf);
-    if(fd < 0) {
-        fprintf(stderr,"error: %s\n", adb_error());
-        return -1;
-    }
-
-    int opt = CHUNK_SIZE;
-    opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
-
-    total = sz;
-    ptr = data;
-
-    if(progress) {
-        char *x = strrchr(service, ':');
-        if(x) service = x + 1;
-    }
-
-    while(sz > 0) {
-        unsigned xfer = (sz > CHUNK_SIZE) ? CHUNK_SIZE : sz;
-        if(writex(fd, ptr, xfer)) {
-            adb_status(fd);
-            fprintf(stderr,"* failed to write data '%s' *\n", adb_error());
-            return -1;
-        }
-        sz -= xfer;
-        ptr += xfer;
-        if(progress) {
-            printf("sending: '%s' %4d%%    \r", fn, (int)(100LL - ((100LL * sz) / (total))));
-            fflush(stdout);
-        }
-    }
-    if(progress) {
-        printf("\n");
-    }
-
-    if(readx(fd, buf, 4)){
-        fprintf(stderr,"* error reading response *\n");
-        adb_close(fd);
-        return -1;
-    }
-    if(memcmp(buf, "OKAY", 4)) {
-        buf[4] = 0;
-        fprintf(stderr,"* error response '%s' *\n", buf);
-        adb_close(fd);
-        return -1;
-    }
-
-    adb_close(fd);
-    return 0;
-}
-
-
-int adb_download(const char *service, const char *fn, unsigned progress)
-{
-    void *data;
-    unsigned sz;
-
-    data = load_file(fn, &sz);
-    if(data == 0) {
-        fprintf(stderr,"* cannot read '%s' *\n", fn);
-        return -1;
-    }
-
-    int status = adb_download_buffer(service, fn, data, sz, progress);
-    free(data);
-    return status;
-}
-
-#define SIDELOAD_HOST_BLOCK_SIZE (CHUNK_SIZE)
-
-/*
- * The sideload-host protocol serves the data in a file (given on the
- * command line) to the client, using a simple protocol:
- *
- * - The connect message includes the total number of bytes in the
- *   file and a block size chosen by us.
- *
- * - The other side sends the desired block number as eight decimal
- *   digits (eg "00000023" for block 23).  Blocks are numbered from
- *   zero.
- *
- * - We send back the data of the requested block.  The last block is
- *   likely to be partial; when the last block is requested we only
- *   send the part of the block that exists, it's not padded up to the
- *   block size.
- *
- * - When the other side sends "DONEDONE" instead of a block number,
- *   we hang up.
- */
-int adb_sideload_host(const char* fn) {
-    uint8_t* data;
-    unsigned sz;
-    size_t xfer = 0;
-    int status;
-
-    printf("loading: '%s'", fn);
-    fflush(stdout);
-    data = load_file(fn, &sz);
-    if (data == 0) {
-        printf("\n");
-        fprintf(stderr, "* cannot read '%s' *\n", fn);
-        return -1;
-    }
-
-    char buf[100];
-    sprintf(buf, "sideload-host:%d:%d", sz, SIDELOAD_HOST_BLOCK_SIZE);
-    int fd = adb_connect(buf);
-    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, 1);
-        goto done;
-    }
-
-    int opt = SIDELOAD_HOST_BLOCK_SIZE;
-    opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
-
-    int last_percent = -1;
-    for (;;) {
-        if (readx(fd, buf, 8)) {
-            fprintf(stderr, "* failed to read command: %s\n", adb_error());
-            status = -1;
-            goto done;
-        }
-
-        if (strncmp("DONEDONE", buf, 8) == 0) {
-            status = 0;
-            break;
-        }
-
-        buf[8] = '\0';
-        int block = strtol(buf, NULL, 10);
-
-        size_t offset = block * SIDELOAD_HOST_BLOCK_SIZE;
-        if (offset >= sz) {
-            fprintf(stderr, "* attempt to read past end: %s\n", adb_error());
-            status = -1;
-            goto done;
-        }
-        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(writex(fd, start, to_write)) {
-            adb_status(fd);
-            fprintf(stderr,"* failed to write data '%s' *\n", adb_error());
-            status = -1;
-            goto done;
-        }
-        xfer += to_write;
-
-        // For normal OTA packages, we expect to transfer every byte
-        // twice, plus a bit of overhead (one read during
-        // verification, one read of each byte for installation, plus
-        // extra access to things like the zip central directory).
-        // This estimate of the completion becomes 100% when we've
-        // transferred ~2.13 (=100/47) times the package size.
-        int percent = (int)(xfer * 47LL / (sz ? sz : 1));
-        if (percent != last_percent) {
-            printf("\rserving: '%s'  (~%d%%)    ", fn, percent);
-            fflush(stdout);
-            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;
-}
-
-static void status_window(transport_type ttype, const char* serial)
-{
-    char command[4096];
-    char *state = 0;
-    char *laststate = 0;
-
-        /* silence stderr */
-#ifdef _WIN32
-    /* XXX: TODO */
-#else
-    int  fd;
-    fd = unix_open("/dev/null", O_WRONLY);
-    dup2(fd, 2);
-    adb_close(fd);
-#endif
-
-    format_host_command(command, sizeof command, "get-state", ttype, serial);
-
-    for(;;) {
-        adb_sleep_ms(250);
-
-        if(state) {
-            free(state);
-            state = 0;
-        }
-
-        state = adb_query(command);
-
-        if(state) {
-            if(laststate && !strcmp(state,laststate)){
-                continue;
-            } else {
-                if(laststate) free(laststate);
-                laststate = strdup(state);
-            }
-        }
-
-        printf("%c[2J%c[2H", 27, 27);
-        printf("Android Debug Bridge\n");
-        printf("State: %s\n", state ? state : "offline");
-        fflush(stdout);
-    }
-}
-
-static int should_escape(const char c)
-{
-    return (c == ' ' || c == '\'' || c == '"' || c == '\\' || c == '(' || c == ')');
-}
-
-/* Duplicate and escape given argument. */
-static char *escape_arg(const char *s)
-{
-    const char *ts;
-    size_t alloc_len;
-    char *ret;
-    char *dest;
-
-    alloc_len = 0;
-    for (ts = s; *ts != '\0'; ts++) {
-        alloc_len++;
-        if (should_escape(*ts)) {
-            alloc_len++;
-        }
-    }
-
-    if (alloc_len == 0) {
-        // Preserve empty arguments
-        ret = (char *) malloc(3);
-        ret[0] = '\"';
-        ret[1] = '\"';
-        ret[2] = '\0';
-        return ret;
-    }
-
-    ret = (char *) malloc(alloc_len + 1);
-    dest = ret;
-
-    for (ts = s; *ts != '\0'; ts++) {
-        if (should_escape(*ts)) {
-            *dest++ = '\\';
-        }
-        *dest++ = *ts;
-    }
-    *dest++ = '\0';
-
-    return ret;
-}
-
-/**
- * Run ppp in "notty" mode against a resource listed as the first parameter
- * eg:
- *
- * ppp dev:/dev/omap_csmi_tty0 <ppp options>
- *
- */
-int ppp(int argc, char **argv)
-{
-#ifdef HAVE_WIN32_PROC
-    fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
-    return -1;
-#else
-    char *adb_service_name;
-    pid_t pid;
-    int fd;
-
-    if (argc < 2) {
-        fprintf(stderr, "usage: adb %s <adb service name> [ppp opts]\n",
-                argv[0]);
-
-        return 1;
-    }
-
-    adb_service_name = argv[1];
-
-    fd = adb_connect(adb_service_name);
-
-    if(fd < 0) {
-        fprintf(stderr,"Error: Could not open adb service: %s. Error: %s\n",
-                adb_service_name, adb_error());
-        return 1;
-    }
-
-    pid = fork();
-
-    if (pid < 0) {
-        perror("from fork()");
-        return 1;
-    } else if (pid == 0) {
-        int err;
-        int i;
-        const char **ppp_args;
-
-        // copy args
-        ppp_args = (const char **) alloca(sizeof(char *) * argc + 1);
-        ppp_args[0] = "pppd";
-        for (i = 2 ; i < argc ; i++) {
-            //argv[2] and beyond become ppp_args[1] and beyond
-            ppp_args[i - 1] = argv[i];
-        }
-        ppp_args[i-1] = NULL;
-
-        // child side
-
-        dup2(fd, STDIN_FILENO);
-        dup2(fd, STDOUT_FILENO);
-        adb_close(STDERR_FILENO);
-        adb_close(fd);
-
-        err = execvp("pppd", (char * const *)ppp_args);
-
-        if (err < 0) {
-            perror("execing pppd");
-        }
-        exit(-1);
-    } else {
-        // parent side
-
-        adb_close(fd);
-        return 0;
-    }
-#endif /* !HAVE_WIN32_PROC */
-}
-
-static int send_shellcommand(transport_type transport, char* serial, char* buf)
-{
-    int fd, ret;
-
-    for(;;) {
-        fd = adb_connect(buf);
-        if(fd >= 0)
-            break;
-        fprintf(stderr,"- waiting for device -\n");
-        adb_sleep_ms(1000);
-        do_cmd(transport, serial, "wait-for-device", 0);
-    }
-
-    read_and_dump(fd);
-    ret = adb_close(fd);
-    if (ret)
-        perror("close");
-
-    return ret;
-}
-
-static int logcat(transport_type transport, char* serial, int argc, char **argv)
-{
-    char buf[4096];
-
-    char *log_tags;
-    char *quoted;
-
-    log_tags = getenv("ANDROID_LOG_TAGS");
-    quoted = escape_arg(log_tags == NULL ? "" : log_tags);
-    snprintf(buf, sizeof(buf),
-            "shell:export ANDROID_LOG_TAGS=\"%s\"; exec logcat", quoted);
-    free(quoted);
-
-    if (!strcmp(argv[0], "longcat")) {
-        strncat(buf, " -v long", sizeof(buf) - 1);
-    }
-
-    argc -= 1;
-    argv += 1;
-    while(argc-- > 0) {
-        quoted = escape_arg(*argv++);
-        strncat(buf, " ", sizeof(buf) - 1);
-        strncat(buf, quoted, sizeof(buf) - 1);
-        free(quoted);
-    }
-
-    send_shellcommand(transport, serial, buf);
-    return 0;
-}
-
-static int mkdirs(const char *path)
-{
-    int ret;
-    char *x = (char *)path + 1;
-
-    for(;;) {
-        x = adb_dirstart(x);
-        if(x == 0) return 0;
-        *x = 0;
-        ret = adb_mkdir(path, 0775);
-        *x = OS_PATH_SEPARATOR;
-        if((ret < 0) && (errno != EEXIST)) {
-            return ret;
-        }
-        x++;
-    }
-    return 0;
-}
-
-static int backup(int argc, char** argv) {
-    char buf[4096];
-    char default_name[32];
-    const char* filename = strcpy(default_name, "./backup.ab");
-    int fd, outFd;
-    int i, j;
-
-    /* find, extract, and use any -f argument */
-    for (i = 1; i < argc; i++) {
-        if (!strcmp("-f", argv[i])) {
-            if (i == argc-1) {
-                fprintf(stderr, "adb: -f passed with no filename\n");
-                return usage();
-            }
-            filename = argv[i+1];
-            for (j = i+2; j <= argc; ) {
-                argv[i++] = argv[j++];
-            }
-            argc -= 2;
-            argv[argc] = NULL;
-        }
-    }
-
-    /* bare "adb backup" or "adb backup -f filename" are not valid invocations */
-    if (argc < 2) return usage();
-
-    adb_unlink(filename);
-    mkdirs(filename);
-    outFd = adb_creat(filename, 0640);
-    if (outFd < 0) {
-        fprintf(stderr, "adb: unable to open file %s\n", filename);
-        return -1;
-    }
-
-    snprintf(buf, sizeof(buf), "backup");
-    for (argc--, argv++; argc; argc--, argv++) {
-        strncat(buf, ":", sizeof(buf) - strlen(buf) - 1);
-        strncat(buf, argv[0], sizeof(buf) - strlen(buf) - 1);
-    }
-
-    D("backup. filename=%s buf=%s\n", filename, buf);
-    fd = adb_connect(buf);
-    if (fd < 0) {
-        fprintf(stderr, "adb: unable to connect for backup\n");
-        adb_close(outFd);
-        return -1;
-    }
-
-    printf("Now unlock your device and confirm the backup operation.\n");
-    copy_to_file(fd, outFd);
-
-    adb_close(fd);
-    adb_close(outFd);
-    return 0;
-}
-
-static int restore(int argc, char** argv) {
-    const char* filename;
-    int fd, tarFd;
-
-    if (argc != 2) return usage();
-
-    filename = argv[1];
-    tarFd = adb_open(filename, O_RDONLY);
-    if (tarFd < 0) {
-        fprintf(stderr, "adb: unable to open file %s\n", filename);
-        return -1;
-    }
-
-    fd = adb_connect("restore:");
-    if (fd < 0) {
-        fprintf(stderr, "adb: unable to connect for restore\n");
-        adb_close(tarFd);
-        return -1;
-    }
-
-    printf("Now unlock your device and confirm the restore operation.\n");
-    copy_to_file(tarFd, fd);
-
-    adb_close(fd);
-    adb_close(tarFd);
-    return 0;
-}
-
-#define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make"
-static int top_works(const char *top)
-{
-    if (top != NULL && adb_is_absolute_host_path(top)) {
-        char path_buf[PATH_MAX];
-        snprintf(path_buf, sizeof(path_buf),
-                "%s" OS_PATH_SEPARATOR_STR SENTINEL_FILE, top);
-        return access(path_buf, F_OK) == 0;
-    }
-    return 0;
-}
-
-static char *find_top_from(const char *indir, char path_buf[PATH_MAX])
-{
-    strcpy(path_buf, indir);
-    while (1) {
-        if (top_works(path_buf)) {
-            return path_buf;
-        }
-        char *s = adb_dirstop(path_buf);
-        if (s != NULL) {
-            *s = '\0';
-        } else {
-            path_buf[0] = '\0';
-            return NULL;
-        }
-    }
-}
-
-static char *find_top(char path_buf[PATH_MAX])
-{
-    char *top = getenv("ANDROID_BUILD_TOP");
-    if (top != NULL && top[0] != '\0') {
-        if (!top_works(top)) {
-            fprintf(stderr, "adb: bad ANDROID_BUILD_TOP value \"%s\"\n", top);
-            return NULL;
-        }
-    } else {
-        top = getenv("TOP");
-        if (top != NULL && top[0] != '\0') {
-            if (!top_works(top)) {
-                fprintf(stderr, "adb: bad TOP value \"%s\"\n", top);
-                return NULL;
-            }
-        } else {
-            top = NULL;
-        }
-    }
-
-    if (top != NULL) {
-        /* The environment pointed to a top directory that works.
-         */
-        strcpy(path_buf, top);
-        return path_buf;
-    }
-
-    /* The environment didn't help.  Walk up the tree from the CWD
-     * to see if we can find the top.
-     */
-    char dir[PATH_MAX];
-    top = find_top_from(getcwd(dir, sizeof(dir)), path_buf);
-    if (top == NULL) {
-        /* If the CWD isn't under a good-looking top, see if the
-         * executable is.
-         */
-        get_my_path(dir, PATH_MAX);
-        top = find_top_from(dir, path_buf);
-    }
-    return top;
-}
-
-/* <hint> may be:
- * - A simple product name
- *   e.g., "sooner"
-TODO: debug?  sooner-debug, sooner:debug?
- * - A relative path from the CWD to the ANDROID_PRODUCT_OUT dir
- *   e.g., "out/target/product/sooner"
- * - An absolute path to the PRODUCT_OUT dir
- *   e.g., "/src/device/out/target/product/sooner"
- *
- * Given <hint>, try to construct an absolute path to the
- * ANDROID_PRODUCT_OUT dir.
- */
-static const char *find_product_out_path(const char *hint)
-{
-    static char path_buf[PATH_MAX];
-
-    if (hint == NULL || hint[0] == '\0') {
-        return NULL;
-    }
-
-    /* If it's already absolute, don't bother doing any work.
-     */
-    if (adb_is_absolute_host_path(hint)) {
-        strcpy(path_buf, hint);
-        return path_buf;
-    }
-
-    /* If there are any slashes in it, assume it's a relative path;
-     * make it absolute.
-     */
-    if (adb_dirstart(hint) != NULL) {
-        if (getcwd(path_buf, sizeof(path_buf)) == NULL) {
-            fprintf(stderr, "adb: Couldn't get CWD: %s\n", strerror(errno));
-            return NULL;
-        }
-        if (strlen(path_buf) + 1 + strlen(hint) >= sizeof(path_buf)) {
-            fprintf(stderr, "adb: Couldn't assemble path\n");
-            return NULL;
-        }
-        strcat(path_buf, OS_PATH_SEPARATOR_STR);
-        strcat(path_buf, hint);
-        return path_buf;
-    }
-
-    /* It's a string without any slashes.  Try to do something with it.
-     *
-     * Try to find the root of the build tree, and build a PRODUCT_OUT
-     * path from there.
-     */
-    char top_buf[PATH_MAX];
-    const char *top = find_top(top_buf);
-    if (top == NULL) {
-        fprintf(stderr, "adb: Couldn't find top of build tree\n");
-        return NULL;
-    }
-//TODO: if we have a way to indicate debug, look in out/debug/target/...
-    snprintf(path_buf, sizeof(path_buf),
-            "%s" OS_PATH_SEPARATOR_STR
-            "out" OS_PATH_SEPARATOR_STR
-            "target" OS_PATH_SEPARATOR_STR
-            "product" OS_PATH_SEPARATOR_STR
-            "%s", top_buf, hint);
-    if (access(path_buf, F_OK) < 0) {
-        fprintf(stderr, "adb: Couldn't find a product dir "
-                "based on \"-p %s\"; \"%s\" doesn't exist\n", hint, path_buf);
-        return NULL;
-    }
-    return path_buf;
-}
-
-static void parse_push_pull_args(char **arg, int narg, char const **path1, char const **path2,
-                                 int *show_progress, int *copy_attrs) {
-    *show_progress = 0;
-    *copy_attrs = 0;
-
-    while (narg > 0) {
-        if (!strcmp(*arg, "-p")) {
-            *show_progress = 1;
-        } else if (!strcmp(*arg, "-a")) {
-            *copy_attrs = 1;
-        } else {
-            break;
-        }
-        ++arg;
-        --narg;
-    }
-
-    if (narg > 0) {
-        *path1 = *arg;
-        ++arg;
-        --narg;
-    }
-
-    if (narg > 0) {
-        *path2 = *arg;
-    }
-}
-
-int adb_commandline(int argc, char **argv)
-{
-    char buf[4096];
-    int no_daemon = 0;
-    int is_daemon = 0;
-    int is_server = 0;
-    int persist = 0;
-    int r;
-    transport_type ttype = kTransportAny;
-    char* serial = NULL;
-    char* server_port_str = NULL;
-
-        /* If defined, this should be an absolute path to
-         * the directory containing all of the various system images
-         * for a particular product.  If not defined, and the adb
-         * command requires this information, then the user must
-         * specify the path using "-p".
-         */
-    gProductOutPath = getenv("ANDROID_PRODUCT_OUT");
-    if (gProductOutPath == NULL || gProductOutPath[0] == '\0') {
-        gProductOutPath = NULL;
-    }
-    // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
-
-    serial = getenv("ANDROID_SERIAL");
-
-    /* Validate and assign the server port */
-    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 = (int) strtol(server_port_str, NULL, 0);
-        if (server_port <= 0 || server_port > 65535) {
-            fprintf(stderr,
-                    "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive number less than 65535. Got \"%s\"\n",
-                    server_port_str);
-            return usage();
-        }
-    }
-
-    /* modifiers and flags */
-    while(argc > 0) {
-        if(!strcmp(argv[0],"server")) {
-            is_server = 1;
-        } else if(!strcmp(argv[0],"nodaemon")) {
-            no_daemon = 1;
-        } else if (!strcmp(argv[0], "fork-server")) {
-            /* this is a special flag used only when the ADB client launches the ADB Server */
-            is_daemon = 1;
-        } else if(!strcmp(argv[0],"persist")) {
-            persist = 1;
-        } else if(!strncmp(argv[0], "-p", 2)) {
-            const char *product = NULL;
-            if (argv[0][2] == '\0') {
-                if (argc < 2) return usage();
-                product = argv[1];
-                argc--;
-                argv++;
-            } else {
-                product = argv[0] + 2;
-            }
-            gProductOutPath = find_product_out_path(product);
-            if (gProductOutPath == NULL) {
-                fprintf(stderr, "adb: could not resolve \"-p %s\"\n",
-                        product);
-                return usage();
-            }
-        } else if (argv[0][0]=='-' && argv[0][1]=='s') {
-            if (isdigit(argv[0][2])) {
-                serial = argv[0] + 2;
-            } else {
-                if(argc < 2 || argv[0][2] != '\0') return usage();
-                serial = argv[1];
-                argc--;
-                argv++;
-            }
-        } else if (!strcmp(argv[0],"-d")) {
-            ttype = kTransportUsb;
-        } else if (!strcmp(argv[0],"-e")) {
-            ttype = kTransportLocal;
-        } 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];
-                argc--;
-                argv++;
-            } else {
-                hostname = 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();
-                server_port_str = argv[1];
-                argc--;
-                argv++;
-            } 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 {
-                /* out of recognized modifiers and flags */
-            break;
-        }
-        argc--;
-        argv++;
-    }
-
-    adb_set_transport(ttype, serial);
-    adb_set_tcp_specifics(server_port);
-
-    if (is_server) {
-        if (no_daemon || is_daemon) {
-            r = adb_main(is_daemon, server_port);
-        } else {
-            r = launch_server(server_port);
-        }
-        if(r) {
-            fprintf(stderr,"* could not start server *\n");
-        }
-        return r;
-    }
-
-top:
-    if(argc == 0) {
-        return usage();
-    }
-
-    /* adb_connect() commands */
-
-    if(!strcmp(argv[0], "devices")) {
-        char *tmp;
-        char *listopt;
-        if (argc < 2)
-            listopt = "";
-        else if (argc == 2 && !strcmp(argv[1], "-l"))
-            listopt = argv[1];
-        else {
-            fprintf(stderr, "Usage: adb devices [-l]\n");
-            return 1;
-        }
-        snprintf(buf, sizeof buf, "host:%s%s", argv[0], listopt);
-        tmp = adb_query(buf);
-        if(tmp) {
-            printf("List of devices attached \n");
-            printf("%s\n", tmp);
-            return 0;
-        } else {
-            return 1;
-        }
-    }
-
-    if(!strcmp(argv[0], "connect")) {
-        char *tmp;
-        if (argc != 2) {
-            fprintf(stderr, "Usage: adb connect <host>[:<port>]\n");
-            return 1;
-        }
-        snprintf(buf, sizeof buf, "host:connect:%s", argv[1]);
-        tmp = adb_query(buf);
-        if(tmp) {
-            printf("%s\n", tmp);
-            return 0;
-        } else {
-            return 1;
-        }
-    }
-
-    if(!strcmp(argv[0], "disconnect")) {
-        char *tmp;
-        if (argc > 2) {
-            fprintf(stderr, "Usage: adb disconnect [<host>[:<port>]]\n");
-            return 1;
-        }
-        if (argc == 2) {
-            snprintf(buf, sizeof buf, "host:disconnect:%s", argv[1]);
-        } else {
-            snprintf(buf, sizeof buf, "host:disconnect:");
-        }
-        tmp = adb_query(buf);
-        if(tmp) {
-            printf("%s\n", tmp);
-            return 0;
-        } else {
-            return 1;
-        }
-    }
-
-    if (!strcmp(argv[0], "emu")) {
-        return adb_send_emulator_command(argc, argv);
-    }
-
-    if(!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) {
-        int r;
-        int fd;
-
-        char h = (argv[0][0] == 'h');
-
-        if (h) {
-            printf("\x1b[41;33m");
-            fflush(stdout);
-        }
-
-        if(argc < 2) {
-            D("starting interactive shell\n");
-            r = interactive_shell();
-            if (h) {
-                printf("\x1b[0m");
-                fflush(stdout);
-            }
-            return r;
-        }
-
-        snprintf(buf, sizeof(buf), "shell:%s", argv[1]);
-        argc -= 2;
-        argv += 2;
-        while (argc-- > 0) {
-            char *quoted = escape_arg(*argv++);
-            strncat(buf, " ", sizeof(buf) - 1);
-            strncat(buf, quoted, sizeof(buf) - 1);
-            free(quoted);
-        }
-
-        for(;;) {
-            D("interactive shell loop. buff=%s\n", buf);
-            fd = adb_connect(buf);
-            if(fd >= 0) {
-                D("about to read_and_dump(fd=%d)\n", fd);
-                read_and_dump(fd);
-                D("read_and_dump() done.\n");
-                adb_close(fd);
-                r = 0;
-            } else {
-                fprintf(stderr,"error: %s\n", adb_error());
-                r = -1;
-            }
-
-            if(persist) {
-                fprintf(stderr,"\n- waiting for device -\n");
-                adb_sleep_ms(1000);
-                do_cmd(ttype, serial, "wait-for-device", 0);
-            } else {
-                if (h) {
-                    printf("\x1b[0m");
-                    fflush(stdout);
-                }
-                D("interactive shell loop. return r=%d\n", r);
-                return r;
-            }
-        }
-    }
-
-    if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {
-        int exec_in = !strcmp(argv[0], "exec-in");
-        int fd;
-
-        snprintf(buf, sizeof buf, "exec:%s", argv[1]);
-        argc -= 2;
-        argv += 2;
-        while (argc-- > 0) {
-            char *quoted = escape_arg(*argv++);
-            strncat(buf, " ", sizeof(buf) - 1);
-            strncat(buf, quoted, sizeof(buf) - 1);
-            free(quoted);
-        }
-
-        fd = adb_connect(buf);
-        if (fd < 0) {
-            fprintf(stderr, "error: %s\n", adb_error());
-            return -1;
-        }
-
-        if (exec_in) {
-            copy_to_file(STDIN_FILENO, fd);
-        } else {
-            copy_to_file(fd, STDOUT_FILENO);
-        }
-
-        adb_close(fd);
-        return 0;
-    }
-
-    if(!strcmp(argv[0], "kill-server")) {
-        int fd;
-        fd = _adb_connect("host:kill");
-        if(fd == -1) {
-            fprintf(stderr,"* server not running *\n");
-            return 1;
-        }
-        return 0;
-    }
-
-    if(!strcmp(argv[0], "sideload")) {
-        if(argc != 2) return usage();
-        if (adb_sideload_host(argv[1])) {
-            return 1;
-        } else {
-            return 0;
-        }
-    }
-
-    if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot")
-            || !strcmp(argv[0], "reboot-bootloader")
-            || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb")
-            || !strcmp(argv[0], "root") || !strcmp(argv[0], "disable-verity")) {
-        char command[100];
-        if (!strcmp(argv[0], "reboot-bootloader"))
-            snprintf(command, sizeof(command), "reboot:bootloader");
-        else if (argc > 1)
-            snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
-        else
-            snprintf(command, sizeof(command), "%s:", argv[0]);
-        int fd = adb_connect(command);
-        if(fd >= 0) {
-            read_and_dump(fd);
-            adb_close(fd);
-            return 0;
-        }
-        fprintf(stderr,"error: %s\n", adb_error());
-        return 1;
-    }
-
-    if(!strcmp(argv[0], "bugreport")) {
-        if (argc != 1) return usage();
-        do_cmd(ttype, serial, "shell", "bugreport", 0);
-        return 0;
-    }
-
-    /* adb_command() wrapper commands */
-
-    if(!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
-        char* service = argv[0];
-        if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) {
-            if (ttype == kTransportUsb) {
-                service = "wait-for-usb";
-            } else if (ttype == kTransportLocal) {
-                service = "wait-for-local";
-            } else {
-                service = "wait-for-any";
-            }
-        }
-
-        format_host_command(buf, sizeof buf, service, ttype, serial);
-
-        if (adb_command(buf)) {
-            D("failure: %s *\n",adb_error());
-            fprintf(stderr,"error: %s\n", adb_error());
-            return 1;
-        }
-
-        /* Allow a command to be run after wait-for-device,
-            * e.g. 'adb wait-for-device shell'.
-            */
-        if(argc > 1) {
-            argc--;
-            argv++;
-            goto top;
-        }
-        return 0;
-    }
-
-    if(!strcmp(argv[0], "forward") ||
-       !strcmp(argv[0], "reverse"))
-    {
-        char host_prefix[64];
-        char reverse = (char) !strcmp(argv[0], "reverse");
-        char remove = 0;
-        char remove_all = 0;
-        char list = 0;
-        char no_rebind = 0;
-
-        // Parse options here.
-        while (argc > 1 && argv[1][0] == '-') {
-            if (!strcmp(argv[1], "--list"))
-                list = 1;
-            else if (!strcmp(argv[1], "--remove"))
-                remove = 1;
-            else if (!strcmp(argv[1], "--remove-all"))
-                remove_all = 1;
-            else if (!strcmp(argv[1], "--no-rebind"))
-                no_rebind = 1;
-            else {
-                return usage();
-            }
-            argc--;
-            argv++;
-        }
-
-        // Ensure we can only use one option at a time.
-        if (list + remove + remove_all + no_rebind > 1) {
-            return usage();
-        }
-
-        // Determine the <host-prefix> for this command.
-        if (reverse) {
-            snprintf(host_prefix, sizeof host_prefix, "reverse");
-        } else {
-            if (serial) {
-                snprintf(host_prefix, sizeof host_prefix, "host-serial:%s",
-                        serial);
-            } else if (ttype == kTransportUsb) {
-                snprintf(host_prefix, sizeof host_prefix, "host-usb");
-            } else if (ttype == kTransportLocal) {
-                snprintf(host_prefix, sizeof host_prefix, "host-local");
-            } else {
-                snprintf(host_prefix, sizeof host_prefix, "host");
-            }
-        }
-
-        // Implement forward --list
-        if (list) {
-            if (argc != 1)
-                return usage();
-            snprintf(buf, sizeof buf, "%s:list-forward", host_prefix);
-            char* forwards = adb_query(buf);
-            if (forwards == NULL) {
-                fprintf(stderr, "error: %s\n", adb_error());
-                return 1;
-            }
-            printf("%s", forwards);
-            free(forwards);
-            return 0;
-        }
-
-        // Implement forward --remove-all
-        else if (remove_all) {
-            if (argc != 1)
-                return usage();
-            snprintf(buf, sizeof buf, "%s:killforward-all", host_prefix);
-        }
-
-        // Implement forward --remove <local>
-        else if (remove) {
-            if (argc != 2)
-                return usage();
-            snprintf(buf, sizeof buf, "%s:killforward:%s", host_prefix, argv[1]);
-        }
-        // Or implement one of:
-        //    forward <local> <remote>
-        //    forward --no-rebind <local> <remote>
-        else
-        {
-          if (argc != 3)
-            return usage();
-          const char* command = no_rebind ? "forward:norebind:" : "forward";
-          snprintf(buf, sizeof buf, "%s:%s:%s;%s", host_prefix, command, argv[1], argv[2]);
-        }
-
-        if(adb_command(buf)) {
-            fprintf(stderr,"error: %s\n", adb_error());
-            return 1;
-        }
-        return 0;
-    }
-
-    /* do_sync_*() commands */
-
-    if(!strcmp(argv[0], "ls")) {
-        if(argc != 2) return usage();
-        return do_sync_ls(argv[1]);
-    }
-
-    if(!strcmp(argv[0], "push")) {
-        int show_progress = 0;
-        int copy_attrs = 0; // unused
-        const char* lpath = NULL, *rpath = NULL;
-
-        parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress, &copy_attrs);
-
-        if ((lpath != NULL) && (rpath != NULL)) {
-            return do_sync_push(lpath, rpath, show_progress);
-        }
-
-        return usage();
-    }
-
-    if(!strcmp(argv[0], "pull")) {
-        int show_progress = 0;
-        int copy_attrs = 0;
-        const char* rpath = NULL, *lpath = ".";
-
-        parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress, &copy_attrs);
-
-        if (rpath != NULL) {
-            return do_sync_pull(rpath, lpath, show_progress, copy_attrs);
-        }
-
-        return usage();
-    }
-
-    if (!strcmp(argv[0], "install")) {
-        if (argc < 2) return usage();
-        return install_app(ttype, serial, argc, argv);
-    }
-
-    if (!strcmp(argv[0], "install-multiple")) {
-        if (argc < 2) return usage();
-        return install_multiple_app(ttype, serial, argc, argv);
-    }
-
-    if (!strcmp(argv[0], "uninstall")) {
-        if (argc < 2) return usage();
-        return uninstall_app(ttype, serial, argc, argv);
-    }
-
-    if(!strcmp(argv[0], "sync")) {
-        char *srcarg, *android_srcpath, *data_srcpath, *vendor_srcpath;
-        int listonly = 0;
-
-        int ret;
-        if(argc < 2) {
-            /* No local path was specified. */
-            srcarg = NULL;
-        } else if (argc >= 2 && strcmp(argv[1], "-l") == 0) {
-            listonly = 1;
-            if (argc == 3) {
-                srcarg = argv[2];
-            } else {
-                srcarg = NULL;
-            }
-        } else if(argc == 2) {
-            /* A local path or "android"/"data" arg was specified. */
-            srcarg = argv[1];
-        } else {
-            return usage();
-        }
-        ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath, &vendor_srcpath);
-        if(ret != 0) return usage();
-
-        if(android_srcpath != NULL)
-            ret = do_sync_sync(android_srcpath, "/system", listonly);
-        if(ret == 0 && vendor_srcpath != NULL)
-            ret = do_sync_sync(vendor_srcpath, "/vendor", listonly);
-        if(ret == 0 && data_srcpath != NULL)
-            ret = do_sync_sync(data_srcpath, "/data", listonly);
-
-        free(android_srcpath);
-        free(vendor_srcpath);
-        free(data_srcpath);
-        return ret;
-    }
-
-    /* passthrough commands */
-
-    if(!strcmp(argv[0],"get-state") ||
-        !strcmp(argv[0],"get-serialno") ||
-        !strcmp(argv[0],"get-devpath"))
-    {
-        char *tmp;
-
-        format_host_command(buf, sizeof buf, argv[0], ttype, serial);
-        tmp = adb_query(buf);
-        if(tmp) {
-            printf("%s\n", tmp);
-            return 0;
-        } else {
-            return 1;
-        }
-    }
-
-    /* other commands */
-
-    if(!strcmp(argv[0],"status-window")) {
-        status_window(ttype, serial);
-        return 0;
-    }
-
-    if(!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat") || !strcmp(argv[0],"longcat")) {
-        return logcat(ttype, serial, argc, argv);
-    }
-
-    if(!strcmp(argv[0],"ppp")) {
-        return ppp(argc, argv);
-    }
-
-    if (!strcmp(argv[0], "start-server")) {
-        return adb_connect("host:start-server");
-    }
-
-    if (!strcmp(argv[0], "backup")) {
-        return backup(argc, argv);
-    }
-
-    if (!strcmp(argv[0], "restore")) {
-        return restore(argc, argv);
-    }
-
-    if (!strcmp(argv[0], "keygen")) {
-        if (argc < 2) return usage();
-        return adb_auth_keygen(argv[1]);
-    }
-
-    if (!strcmp(argv[0], "jdwp")) {
-        int  fd = adb_connect("jdwp");
-        if (fd >= 0) {
-            read_and_dump(fd);
-            adb_close(fd);
-            return 0;
-        } else {
-            fprintf(stderr, "error: %s\n", adb_error());
-            return -1;
-        }
-    }
-
-    /* "adb /?" is a common idiom under Windows */
-    if(!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
-        help();
-        return 0;
-    }
-
-    if(!strcmp(argv[0], "version")) {
-        version(stdout);
-        return 0;
-    }
-
-    usage();
-    return 1;
-}
-
-#define MAX_ARGV_LENGTH 16
-static int do_cmd(transport_type ttype, char* serial, char *cmd, ...)
-{
-    char *argv[MAX_ARGV_LENGTH];
-    int argc;
-    va_list ap;
-
-    va_start(ap, cmd);
-    argc = 0;
-
-    if (serial) {
-        argv[argc++] = "-s";
-        argv[argc++] = serial;
-    } else if (ttype == kTransportUsb) {
-        argv[argc++] = "-d";
-    } else if (ttype == kTransportLocal) {
-        argv[argc++] = "-e";
-    }
-
-    argv[argc++] = cmd;
-    while(argc < MAX_ARGV_LENGTH &&
-        (argv[argc] = va_arg(ap, char*)) != 0) argc++;
-    assert(argc < MAX_ARGV_LENGTH);
-    va_end(ap);
-
-#if 0
-    int n;
-    fprintf(stderr,"argc = %d\n",argc);
-    for(n = 0; n < argc; n++) {
-        fprintf(stderr,"argv[%d] = \"%s\"\n", n, argv[n]);
-    }
-#endif
-
-    return adb_commandline(argc, argv);
-}
-
-int find_sync_dirs(const char *srcarg,
-        char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out)
-{
-    char *android_srcdir = NULL, *data_srcdir = NULL, *vendor_srcdir = NULL;
-    struct stat st;
-
-    if(srcarg == NULL) {
-        android_srcdir = product_file("system");
-        data_srcdir = product_file("data");
-        vendor_srcdir = product_file("vendor");
-        /* Check if vendor partition exists */
-        if (lstat(vendor_srcdir, &st) || !S_ISDIR(st.st_mode))
-            vendor_srcdir = NULL;
-    } else {
-        /* srcarg may be "data", "system" or NULL.
-         * if srcarg is NULL, then both data and system are synced
-         */
-        if(strcmp(srcarg, "system") == 0) {
-            android_srcdir = product_file("system");
-        } else if(strcmp(srcarg, "data") == 0) {
-            data_srcdir = product_file("data");
-        } else if(strcmp(srcarg, "vendor") == 0) {
-            vendor_srcdir = product_file("vendor");
-        } else {
-            /* It's not "system", "vendor", or "data".
-             */
-            return 1;
-        }
-    }
-
-    if(android_srcdir_out != NULL)
-        *android_srcdir_out = android_srcdir;
-    else
-        free(android_srcdir);
-
-    if(vendor_srcdir_out != NULL)
-        *vendor_srcdir_out = vendor_srcdir;
-    else
-        free(vendor_srcdir);
-
-    if(data_srcdir_out != NULL)
-            *data_srcdir_out = data_srcdir;
-        else
-            free(data_srcdir);
-    return 0;
-}
-
-static int pm_command(transport_type transport, char* serial,
-                      int argc, char** argv)
-{
-    char buf[4096];
-
-    snprintf(buf, sizeof(buf), "shell:pm");
-
-    while(argc-- > 0) {
-        char *quoted = escape_arg(*argv++);
-        strncat(buf, " ", sizeof(buf) - 1);
-        strncat(buf, quoted, sizeof(buf) - 1);
-        free(quoted);
-    }
-
-    send_shellcommand(transport, serial, buf);
-    return 0;
-}
-
-int uninstall_app(transport_type transport, char* serial, int argc, char** argv)
-{
-    /* if the user choose the -k option, we refuse to do it until devices are
-       out with the option to uninstall the remaining data somehow (adb/ui) */
-    if (argc == 3 && strcmp(argv[1], "-k") == 0)
-    {
-        printf(
-            "The -k option uninstalls the application while retaining the data/cache.\n"
-            "At the moment, there is no way to remove the remaining data.\n"
-            "You will have to reinstall the application with the same signature, and fully uninstall it.\n"
-            "If you truly wish to continue, execute 'adb shell pm uninstall -k %s'\n", argv[2]);
-        return -1;
-    }
-
-    /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
-    return pm_command(transport, serial, argc, argv);
-}
-
-static int delete_file(transport_type transport, char* serial, char* filename)
-{
-    char buf[4096];
-    char* quoted;
-
-    snprintf(buf, sizeof(buf), "shell:rm -f ");
-    quoted = escape_arg(filename);
-    strncat(buf, quoted, sizeof(buf)-1);
-    free(quoted);
-
-    send_shellcommand(transport, serial, buf);
-    return 0;
-}
-
-static const char* get_basename(const char* filename)
-{
-    const char* basename = adb_dirstop(filename);
-    if (basename) {
-        basename++;
-        return basename;
-    } else {
-        return filename;
-    }
-}
-
-int install_app(transport_type transport, char* serial, int argc, char** argv)
-{
-    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++) {
-        if (!strcmp(argv[i], "-s")) {
-            where = SD_DEST;
-        }
-    }
-
-    // Find last APK argument.
-    // All other arguments passed through verbatim.
-    int last_apk = -1;
-    for (i = argc - 1; i >= 0; i--) {
-        char* file = argv[i];
-        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 -1;
-            }
-
-            last_apk = i;
-            break;
-        }
-    }
-
-    if (last_apk == -1) {
-        fprintf(stderr, "Missing APK file\n");
-        return -1;
-    }
-
-    char* apk_file = argv[last_apk];
-    char apk_dest[PATH_MAX];
-    snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file));
-    int err = do_sync_push(apk_file, apk_dest, 0 /* no show progress */);
-    if (err) {
-        goto cleanup_apk;
-    } else {
-        argv[last_apk] = apk_dest; /* destination name, not source location */
-    }
-
-    pm_command(transport, serial, argc, argv);
-
-cleanup_apk:
-    delete_file(transport, serial, apk_dest);
-    return err;
-}
-
-int install_multiple_app(transport_type transport, char* serial, int argc, char** argv)
-{
-    char buf[1024];
-    int i;
-    struct stat sb;
-    unsigned long long 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--) {
-        char* file = argv[i];
-        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 -1;
-            }
-
-            total_size += sb.st_size;
-            first_apk = i;
-        } else {
-            break;
-        }
-    }
-
-    if (first_apk == -1) {
-        fprintf(stderr, "Missing APK file\n");
-        return 1;
-    }
-
-    snprintf(buf, sizeof(buf), "exec:pm install-create -S %lld", total_size);
-    for (i = 1; i < first_apk; i++) {
-        char *quoted = escape_arg(argv[i]);
-        strncat(buf, " ", sizeof(buf) - 1);
-        strncat(buf, quoted, sizeof(buf) - 1);
-        free(quoted);
-    }
-
-    // Create install session
-    int fd = adb_connect(buf);
-    if (fd < 0) {
-        fprintf(stderr, "Connect error for create: %s\n", adb_error());
-        return -1;
-    }
-    read_status_line(fd, buf, sizeof(buf));
-    adb_close(fd);
-
-    int session_id = -1;
-    if (!strncmp("Success", buf, 7)) {
-        char* start = strrchr(buf, '[');
-        char* end = strrchr(buf, ']');
-        if (start && end) {
-            *end = '\0';
-            session_id = strtol(start + 1, NULL, 10);
-        }
-    }
-    if (session_id < 0) {
-        fprintf(stderr, "Failed to create session\n");
-        fputs(buf, stderr);
-        return -1;
-    }
-
-    // Valid session, now stream the APKs
-    int success = 1;
-    for (i = first_apk; i < argc; i++) {
-        char* file = argv[i];
-        if (stat(file, &sb) == -1) {
-            fprintf(stderr, "Failed to stat %s\n", file);
-            success = 0;
-            goto finalize_session;
-        }
-
-        snprintf(buf, sizeof(buf), "exec:pm install-write -S %lld %d %d_%s -",
-                (long long int) sb.st_size, session_id, i, get_basename(file));
-
-        int localFd = adb_open(file, O_RDONLY);
-        if (localFd < 0) {
-            fprintf(stderr, "Failed to open %s: %s\n", file, adb_error());
-            success = 0;
-            goto finalize_session;
-        }
-
-        int remoteFd = adb_connect(buf);
-        if (remoteFd < 0) {
-            fprintf(stderr, "Connect error for write: %s\n", adb_error());
-            adb_close(localFd);
-            success = 0;
-            goto finalize_session;
-        }
-
-        copy_to_file(localFd, remoteFd);
-        read_status_line(remoteFd, buf, sizeof(buf));
-
-        adb_close(localFd);
-        adb_close(remoteFd);
-
-        if (strncmp("Success", buf, 7)) {
-            fprintf(stderr, "Failed to write %s\n", file);
-            fputs(buf, stderr);
-            success = 0;
-            goto finalize_session;
-        }
-    }
-
-finalize_session:
-    // Commit session if we streamed everything okay; otherwise abandon
-    if (success) {
-        snprintf(buf, sizeof(buf), "exec:pm install-commit %d", session_id);
-    } else {
-        snprintf(buf, sizeof(buf), "exec:pm install-abandon %d", session_id);
-    }
-
-    fd = adb_connect(buf);
-    if (fd < 0) {
-        fprintf(stderr, "Connect error for finalize: %s\n", adb_error());
-        return -1;
-    }
-    read_status_line(fd, buf, sizeof(buf));
-    adb_close(fd);
-
-    if (!strncmp("Success", buf, 7)) {
-        fputs(buf, stderr);
-        return 0;
-    } else {
-        fprintf(stderr, "Failed to finalize session\n");
-        fputs(buf, stderr);
-        return -1;
-    }
-}
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
new file mode 100644
index 0000000..fd9953c
--- /dev/null
+++ b/adb/commandline.cpp
@@ -0,0 +1,1728 @@
+/*
+ * 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.
+ */
+
+#define TRACE_TAG TRACE_ADB
+
+#include "sysdeps.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <string>
+
+#include <base/stringprintf.h>
+
+#if !defined(_WIN32)
+#include <termios.h>
+#include <unistd.h>
+#endif
+
+#include "adb.h"
+#include "adb_auth.h"
+#include "adb_client.h"
+#include "adb_io.h"
+#include "adb_utils.h"
+#include "file_sync_service.h"
+
+static int install_app(transport_type t, const char* serial, int argc, const char** argv);
+static int install_multiple_app(transport_type t, const char* serial, int argc, const char** argv);
+static int uninstall_app(transport_type t, const char* serial, int argc, const char** argv);
+
+static std::string gProductOutPath;
+extern int gListenAll;
+
+static std::string product_file(const char *extra) {
+    if (gProductOutPath.empty()) {
+        fprintf(stderr, "adb: Product directory not specified; "
+                "use -p or define ANDROID_PRODUCT_OUT\n");
+        exit(1);
+    }
+
+    return android::base::StringPrintf("%s%s%s",
+                                       gProductOutPath.c_str(), OS_PATH_SEPARATOR_STR, extra);
+}
+
+static void version(FILE* out) {
+    fprintf(out, "Android Debug Bridge version %d.%d.%d\nRevision %s\n",
+            ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION, ADB_REVISION);
+}
+
+static void help() {
+    version(stderr);
+
+    fprintf(stderr,
+        "\n"
+        " -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"
+        "\n"
+        "device commands:\n"
+        "  adb push [-p] <local> <remote>\n"
+        "                               - copy file/dir to device\n"
+        "                                 ('-p' to display the transfer progress)\n"
+        "  adb pull [-p] [-a] <remote> [<local>]\n"
+        "                               - copy file/dir from device\n"
+        "                                 ('-p' to display the transfer progress)\n"
+        "                                 ('-a' means copy timestamp and mode)\n"
+        "  adb sync [ <directory> ]     - copy host->device only if changed\n"
+        "                                 (-l means list but don't copy)\n"
+        "                                 (see 'adb help all')\n"
+        "  adb shell                    - run remote shell interactively\n"
+        "  adb shell <command>          - run remote shell command\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 --norebind <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)\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)\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                - return all information from the device\n"
+        "                                 that should be included in a bug report.\n"
+        "\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-device          - block until device is online\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 reboot-bootloader        - reboots the device into the bootloader\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"
+        "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"
+        "\n"
+        "adb sync notes: adb sync [ <directory> ]\n"
+        "  <localdir> can be interpreted in several ways:\n"
+        "\n"
+        "  - If <directory> is not specified, /system, /vendor (if present), /oem (if present) and /data partitions will be updated.\n"
+        "\n"
+        "  - If it is \"system\", \"vendor\", \"oem\" or \"data\", only the corresponding partition\n"
+        "    is updated.\n"
+        "\n"
+        "environmental 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"
+        );
+}
+
+static int usage() {
+    help();
+    return 1;
+}
+
+#if defined(_WIN32)
+
+// Implemented in sysdeps_win32.cpp.
+void stdin_raw_init(int fd);
+void stdin_raw_restore(int fd);
+
+#else
+static termios g_saved_terminal_state;
+
+static void stdin_raw_init(int fd) {
+    if (tcgetattr(fd, &g_saved_terminal_state)) return;
+
+    termios tio;
+    if (tcgetattr(fd, &tio)) return;
+
+    cfmakeraw(&tio);
+
+    // No timeout but request at least one character per read.
+    tio.c_cc[VTIME] = 0;
+    tio.c_cc[VMIN] = 1;
+
+    tcsetattr(fd, TCSAFLUSH, &tio);
+}
+
+static void stdin_raw_restore(int fd) {
+    tcsetattr(fd, TCSAFLUSH, &g_saved_terminal_state);
+}
+#endif
+
+static void read_and_dump(int fd) {
+    while (fd >= 0) {
+        D("read_and_dump(): pre adb_read(fd=%d)\n", fd);
+        char buf[BUFSIZ];
+        int len = adb_read(fd, buf, sizeof(buf));
+        D("read_and_dump(): post adb_read(fd=%d): len=%d\n", fd, len);
+        if (len <= 0) {
+            break;
+        }
+
+        fwrite(buf, 1, len, stdout);
+        fflush(stdout);
+    }
+}
+
+static void read_status_line(int fd, char* buf, size_t count)
+{
+    count--;
+    while (count > 0) {
+        int len = adb_read(fd, buf, count);
+        if (len == 0) {
+            break;
+        } else if (len < 0) {
+            if (errno == EINTR) continue;
+            break;
+        }
+
+        buf += len;
+        count -= len;
+    }
+    *buf = '\0';
+}
+
+static void copy_to_file(int inFd, int outFd) {
+    const size_t BUFSIZE = 32 * 1024;
+    char* buf = (char*) malloc(BUFSIZE);
+    if (buf == nullptr) fatal("couldn't allocate buffer for copy_to_file");
+    int len;
+    long total = 0;
+
+    D("copy_to_file(%d -> %d)\n", inFd, outFd);
+
+    if (inFd == STDIN_FILENO) {
+        stdin_raw_init(STDIN_FILENO);
+    }
+
+    while (true) {
+        if (inFd == STDIN_FILENO) {
+            len = unix_read(inFd, buf, BUFSIZE);
+        } else {
+            len = adb_read(inFd, buf, BUFSIZE);
+        }
+        if (len == 0) {
+            D("copy_to_file() : read 0 bytes; exiting\n");
+            break;
+        }
+        if (len < 0) {
+            if (errno == EINTR) {
+                D("copy_to_file() : EINTR, retrying\n");
+                continue;
+            }
+            D("copy_to_file() : error %d\n", errno);
+            break;
+        }
+        if (outFd == STDOUT_FILENO) {
+            fwrite(buf, 1, len, stdout);
+            fflush(stdout);
+        } else {
+            adb_write(outFd, buf, len);
+        }
+        total += len;
+    }
+
+    if (inFd == STDIN_FILENO) {
+        stdin_raw_restore(STDIN_FILENO);
+    }
+
+    D("copy_to_file() finished after %lu bytes\n", total);
+    free(buf);
+}
+
+static void *stdin_read_thread(void *x)
+{
+    int fd, fdi;
+    unsigned char buf[1024];
+    int r, n;
+    int state = 0;
+
+    int *fds = (int*) x;
+    fd = fds[0];
+    fdi = fds[1];
+    free(fds);
+
+    for(;;) {
+        /* fdi is really the client's stdin, so use read, not adb_read here */
+        D("stdin_read_thread(): pre unix_read(fdi=%d,...)\n", fdi);
+        r = unix_read(fdi, buf, 1024);
+        D("stdin_read_thread(): post unix_read(fdi=%d,...)\n", fdi);
+        if(r == 0) break;
+        if(r < 0) {
+            if(errno == EINTR) continue;
+            break;
+        }
+        for(n = 0; n < r; n++){
+            switch(buf[n]) {
+            case '\n':
+                state = 1;
+                break;
+            case '\r':
+                state = 1;
+                break;
+            case '~':
+                if(state == 1) state++;
+                break;
+            case '.':
+                if(state == 2) {
+                    fprintf(stderr,"\n* disconnect *\n");
+                    stdin_raw_restore(fdi);
+                    exit(0);
+                }
+            default:
+                state = 0;
+            }
+        }
+        r = adb_write(fd, buf, r);
+        if(r <= 0) {
+            break;
+        }
+    }
+    return 0;
+}
+
+static int interactive_shell() {
+    adb_thread_t thr;
+    int fdi;
+
+    std::string error;
+    int fd = adb_connect("shell:", &error);
+    if (fd < 0) {
+        fprintf(stderr,"error: %s\n", error.c_str());
+        return 1;
+    }
+    fdi = 0; //dup(0);
+
+    int* fds = reinterpret_cast<int*>(malloc(sizeof(int) * 2));
+    if (fds == nullptr) {
+        fprintf(stderr, "couldn't allocate fds array: %s\n", strerror(errno));
+        return 1;
+    }
+
+    fds[0] = fd;
+    fds[1] = fdi;
+
+    stdin_raw_init(fdi);
+    adb_thread_create(&thr, stdin_read_thread, fds);
+    read_and_dump(fd);
+    stdin_raw_restore(fdi);
+    return 0;
+}
+
+
+static std::string format_host_command(const char* command, transport_type type, const char* serial) {
+    if (serial) {
+        return android::base::StringPrintf("host-serial:%s:%s", serial, command);
+    }
+
+    const char* prefix = "host";
+    if (type == kTransportUsb) {
+        prefix = "host-usb";
+    } else if (type == kTransportLocal) {
+        prefix = "host-local";
+    }
+    return android::base::StringPrintf("%s:%s", prefix, command);
+}
+
+static int adb_download_buffer(const char *service, const char *fn, const void* data, unsigned sz,
+                               bool show_progress)
+{
+    std::string error;
+    int fd = adb_connect(android::base::StringPrintf("%s:%d", service, sz), &error);
+    if (fd < 0) {
+        fprintf(stderr,"error: %s\n", error.c_str());
+        return -1;
+    }
+
+    int opt = CHUNK_SIZE;
+    opt = adb_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
+
+    unsigned total = sz;
+    const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data);
+
+    if (show_progress) {
+        char *x = strrchr(service, ':');
+        if(x) service = x + 1;
+    }
+
+    while (sz > 0) {
+        unsigned xfer = (sz > CHUNK_SIZE) ? CHUNK_SIZE : sz;
+        if (!WriteFdExactly(fd, ptr, xfer)) {
+            std::string error;
+            adb_status(fd, &error);
+            fprintf(stderr,"* failed to write data '%s' *\n", error.c_str());
+            return -1;
+        }
+        sz -= xfer;
+        ptr += xfer;
+        if (show_progress) {
+            printf("sending: '%s' %4d%%    \r", fn, (int)(100LL - ((100LL * sz) / (total))));
+            fflush(stdout);
+        }
+    }
+    if (show_progress) {
+        printf("\n");
+    }
+
+    if (!adb_status(fd, &error)) {
+        fprintf(stderr,"* error response '%s' *\n", error.c_str());
+        return -1;
+    }
+
+    adb_close(fd);
+    return 0;
+}
+
+#define SIDELOAD_HOST_BLOCK_SIZE (CHUNK_SIZE)
+
+/*
+ * The sideload-host protocol serves the data in a file (given on the
+ * command line) to the client, using a simple protocol:
+ *
+ * - The connect message includes the total number of bytes in the
+ *   file and a block size chosen by us.
+ *
+ * - The other side sends the desired block number as eight decimal
+ *   digits (eg "00000023" for block 23).  Blocks are numbered from
+ *   zero.
+ *
+ * - We send back the data of the requested block.  The last block is
+ *   likely to be partial; when the last block is requested we only
+ *   send the part of the block that exists, it's not padded up to the
+ *   block size.
+ *
+ * - When the other side sends "DONEDONE" instead of a block number,
+ *   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;
+
+    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);
+        return -1;
+    }
+
+    std::string service =
+            android::base::StringPrintf("sideload-host:%d:%d", sz, SIDELOAD_HOST_BLOCK_SIZE);
+    std::string error;
+    int 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;
+    }
+
+    opt = adb_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
+
+    while (true) {
+        char buf[9];
+        if (!ReadFdExactly(fd, buf, 8)) {
+            fprintf(stderr, "* failed to read command: %s\n", strerror(errno));
+            status = -1;
+            goto done;
+        }
+        buf[8] = '\0';
+
+        if (strcmp("DONEDONE", buf) == 0) {
+            status = 0;
+            break;
+        }
+
+        int block = strtol(buf, NULL, 10);
+
+        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;
+        }
+        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)) {
+            adb_status(fd, &error);
+            fprintf(stderr,"* failed to write data '%s' *\n", error.c_str());
+            status = -1;
+            goto done;
+        }
+        xfer += to_write;
+
+        // For normal OTA packages, we expect to transfer every byte
+        // twice, plus a bit of overhead (one read during
+        // verification, one read of each byte for installation, plus
+        // extra access to things like the zip central directory).
+        // This estimate of the completion becomes 100% when we've
+        // transferred ~2.13 (=100/47) times the package size.
+        int percent = (int)(xfer * 47LL / (sz ? sz : 1));
+        if (percent != last_percent) {
+            printf("\rserving: '%s'  (~%d%%)    ", fn, percent);
+            fflush(stdout);
+            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;
+}
+
+/**
+ * Run ppp in "notty" mode against a resource listed as the first parameter
+ * eg:
+ *
+ * ppp dev:/dev/omap_csmi_tty0 <ppp options>
+ *
+ */
+static int ppp(int argc, const char** argv) {
+#if defined(_WIN32)
+    fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
+    return -1;
+#else
+    if (argc < 2) {
+        fprintf(stderr, "usage: adb %s <adb service name> [ppp opts]\n",
+                argv[0]);
+
+        return 1;
+    }
+
+    const char* adb_service_name = argv[1];
+    std::string error;
+    int fd = adb_connect(adb_service_name, &error);
+    if (fd < 0) {
+        fprintf(stderr,"Error: Could not open adb service: %s. Error: %s\n",
+                adb_service_name, error.c_str());
+        return 1;
+    }
+
+    pid_t pid = fork();
+
+    if (pid < 0) {
+        perror("from fork()");
+        return 1;
+    } else if (pid == 0) {
+        int err;
+        int i;
+        const char **ppp_args;
+
+        // copy args
+        ppp_args = (const char **) alloca(sizeof(char *) * argc + 1);
+        ppp_args[0] = "pppd";
+        for (i = 2 ; i < argc ; i++) {
+            //argv[2] and beyond become ppp_args[1] and beyond
+            ppp_args[i - 1] = argv[i];
+        }
+        ppp_args[i-1] = NULL;
+
+        // child side
+
+        dup2(fd, STDIN_FILENO);
+        dup2(fd, STDOUT_FILENO);
+        adb_close(STDERR_FILENO);
+        adb_close(fd);
+
+        err = execvp("pppd", (char * const *)ppp_args);
+
+        if (err < 0) {
+            perror("execing pppd");
+        }
+        exit(-1);
+    } else {
+        // parent side
+
+        adb_close(fd);
+        return 0;
+    }
+#endif /* !defined(_WIN32) */
+}
+
+static bool wait_for_device(const char* service, transport_type t, const char* serial) {
+    // Was the caller vague about what they'd like us to wait for?
+    // If so, check they weren't more specific in their choice of transport type.
+    if (strcmp(service, "wait-for-device") == 0) {
+        if (t == kTransportUsb) {
+            service = "wait-for-usb";
+        } else if (t == kTransportLocal) {
+            service = "wait-for-local";
+        } else {
+            service = "wait-for-any";
+        }
+    }
+
+    std::string cmd = format_host_command(service, t, serial);
+    std::string error;
+    if (adb_command(cmd, &error)) {
+        D("failure: %s *\n", error.c_str());
+        fprintf(stderr,"error: %s\n", error.c_str());
+        return false;
+    }
+
+    return true;
+}
+
+static int send_shell_command(transport_type transport_type, const char* serial,
+                              const std::string& command) {
+    int fd;
+    while (true) {
+        std::string error;
+        fd = adb_connect(command, &error);
+        if (fd >= 0) {
+            break;
+        }
+        fprintf(stderr,"- waiting for device -\n");
+        adb_sleep_ms(1000);
+        wait_for_device("wait-for-device", transport_type, serial);
+    }
+
+    read_and_dump(fd);
+    int rc = adb_close(fd);
+    if (rc) {
+        perror("close");
+    }
+    return rc;
+}
+
+static int logcat(transport_type transport, const char* serial, int argc, const char** argv) {
+    char* log_tags = getenv("ANDROID_LOG_TAGS");
+    std::string quoted = escape_arg(log_tags == nullptr ? "" : log_tags);
+
+    std::string cmd = "shell:export ANDROID_LOG_TAGS=\"" + quoted + "\"; exec logcat";
+
+    if (!strcmp(argv[0], "longcat")) {
+        cmd += " -v long";
+    }
+
+    --argc;
+    ++argv;
+    while (argc-- > 0) {
+        cmd += " " + escape_arg(*argv++);
+    }
+
+    return send_shell_command(transport, serial, cmd);
+}
+
+static int mkdirs(const char *path)
+{
+    int ret;
+    char *x = (char *)path + 1;
+
+    for(;;) {
+        x = adb_dirstart(x);
+        if(x == 0) return 0;
+        *x = 0;
+        ret = adb_mkdir(path, 0775);
+        *x = OS_PATH_SEPARATOR;
+        if((ret < 0) && (errno != EEXIST)) {
+            return ret;
+        }
+        x++;
+    }
+    return 0;
+}
+
+static int backup(int argc, const char** argv) {
+    const char* filename = "./backup.ab";
+
+    /* find, extract, and use any -f argument */
+    for (int i = 1; i < argc; i++) {
+        if (!strcmp("-f", argv[i])) {
+            if (i == argc-1) {
+                fprintf(stderr, "adb: -f passed with no filename\n");
+                return usage();
+            }
+            filename = argv[i+1];
+            for (int j = i+2; j <= argc; ) {
+                argv[i++] = argv[j++];
+            }
+            argc -= 2;
+            argv[argc] = NULL;
+        }
+    }
+
+    /* bare "adb backup" or "adb backup -f filename" are not valid invocations */
+    if (argc < 2) return usage();
+
+    adb_unlink(filename);
+    mkdirs(filename);
+    int outFd = adb_creat(filename, 0640);
+    if (outFd < 0) {
+        fprintf(stderr, "adb: unable to open file %s\n", filename);
+        return -1;
+    }
+
+    std::string cmd = "backup:";
+    --argc;
+    ++argv;
+    while (argc-- > 0) {
+        cmd += " " + escape_arg(*argv++);
+    }
+
+    D("backup. filename=%s cmd=%s\n", filename, cmd.c_str());
+    std::string error;
+    int fd = adb_connect(cmd, &error);
+    if (fd < 0) {
+        fprintf(stderr, "adb: unable to connect for backup: %s\n", error.c_str());
+        adb_close(outFd);
+        return -1;
+    }
+
+    printf("Now unlock your device and confirm the backup operation.\n");
+    copy_to_file(fd, outFd);
+
+    adb_close(fd);
+    adb_close(outFd);
+    return 0;
+}
+
+static int restore(int argc, const char** argv) {
+    if (argc != 2) return usage();
+
+    const char* filename = argv[1];
+    int tarFd = adb_open(filename, O_RDONLY);
+    if (tarFd < 0) {
+        fprintf(stderr, "adb: unable to open file %s: %s\n", filename, strerror(errno));
+        return -1;
+    }
+
+    std::string error;
+    int fd = adb_connect("restore:", &error);
+    if (fd < 0) {
+        fprintf(stderr, "adb: unable to connect for restore: %s\n", error.c_str());
+        adb_close(tarFd);
+        return -1;
+    }
+
+    printf("Now unlock your device and confirm the restore operation.\n");
+    copy_to_file(tarFd, fd);
+
+    adb_close(fd);
+    adb_close(tarFd);
+    return 0;
+}
+
+/* <hint> may be:
+ * - A simple product name
+ *   e.g., "sooner"
+ * - A relative path from the CWD to the ANDROID_PRODUCT_OUT dir
+ *   e.g., "out/target/product/sooner"
+ * - An absolute path to the PRODUCT_OUT dir
+ *   e.g., "/src/device/out/target/product/sooner"
+ *
+ * Given <hint>, try to construct an absolute path to the
+ * ANDROID_PRODUCT_OUT dir.
+ */
+static std::string find_product_out_path(const char* hint) {
+    if (hint == NULL || hint[0] == '\0') {
+        return "";
+    }
+
+    // If it's already absolute, don't bother doing any work.
+    if (adb_is_absolute_host_path(hint)) {
+        return hint;
+    }
+
+    // If there are any slashes in it, assume it's a relative path;
+    // make it absolute.
+    if (adb_dirstart(hint) != nullptr) {
+        std::string cwd;
+        if (!getcwd(&cwd)) {
+            fprintf(stderr, "adb: getcwd failed: %s\n", strerror(errno));
+            return "";
+        }
+        return android::base::StringPrintf("%s%s%s", cwd.c_str(), OS_PATH_SEPARATOR_STR, hint);
+    }
+
+    // It's a string without any slashes.  Try to do something with it.
+    //
+    // Try to find the root of the build tree, and build a PRODUCT_OUT
+    // path from there.
+    char* top = getenv("ANDROID_BUILD_TOP");
+    if (top == nullptr) {
+        fprintf(stderr, "adb: ANDROID_BUILD_TOP not set!\n");
+        return "";
+    }
+
+    std::string path = top;
+    path += OS_PATH_SEPARATOR_STR;
+    path += "out";
+    path += OS_PATH_SEPARATOR_STR;
+    path += "target";
+    path += OS_PATH_SEPARATOR_STR;
+    path += "product";
+    path += OS_PATH_SEPARATOR_STR;
+    path += hint;
+    if (!directory_exists(path)) {
+        fprintf(stderr, "adb: Couldn't find a product dir based on -p %s; "
+                        "\"%s\" doesn't exist\n", hint, path.c_str());
+        return "";
+    }
+    return path;
+}
+
+static void parse_push_pull_args(const char **arg, int narg, char const **path1,
+                                 char const **path2, int *show_progress,
+                                 int *copy_attrs) {
+    *show_progress = 0;
+    *copy_attrs = 0;
+
+    while (narg > 0) {
+        if (!strcmp(*arg, "-p")) {
+            *show_progress = 1;
+        } else if (!strcmp(*arg, "-a")) {
+            *copy_attrs = 1;
+        } else {
+            break;
+        }
+        ++arg;
+        --narg;
+    }
+
+    if (narg > 0) {
+        *path1 = *arg;
+        ++arg;
+        --narg;
+    }
+
+    if (narg > 0) {
+        *path2 = *arg;
+    }
+}
+
+static int adb_connect_command(const std::string& command) {
+    std::string error;
+    int fd = adb_connect(command, &error);
+    if (fd < 0) {
+        fprintf(stderr, "error: %s\n", error.c_str());
+        return 1;
+    }
+    read_and_dump(fd);
+    adb_close(fd);
+    return 0;
+}
+
+static int adb_query_command(const std::string& command) {
+    std::string result;
+    std::string error;
+    if (!adb_query(command, &result, &error)) {
+        fprintf(stderr, "error: %s\n", error.c_str());
+        return 1;
+    }
+    printf("%s\n", result.c_str());
+    return 0;
+}
+
+int adb_commandline(int argc, const char **argv) {
+    int no_daemon = 0;
+    int is_daemon = 0;
+    int is_server = 0;
+    int persist = 0;
+    int r;
+    transport_type ttype = kTransportAny;
+    const char* serial = NULL;
+    const char* server_port_str = NULL;
+
+    // If defined, this should be an absolute path to
+    // the directory containing all of the various system images
+    // for a particular product.  If not defined, and the adb
+    // command requires this information, then the user must
+    // specify the path using "-p".
+    char* ANDROID_PRODUCT_OUT = getenv("ANDROID_PRODUCT_OUT");
+    if (ANDROID_PRODUCT_OUT != nullptr) {
+        gProductOutPath = ANDROID_PRODUCT_OUT;
+    }
+    // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
+
+    serial = getenv("ANDROID_SERIAL");
+
+    /* Validate and assign the server port */
+    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 = (int) strtol(server_port_str, NULL, 0);
+        if (server_port <= 0 || server_port > 65535) {
+            fprintf(stderr,
+                    "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive number less than 65535. Got \"%s\"\n",
+                    server_port_str);
+            return usage();
+        }
+    }
+
+    /* modifiers and flags */
+    while (argc > 0) {
+        if (!strcmp(argv[0],"server")) {
+            is_server = 1;
+        } else if (!strcmp(argv[0],"nodaemon")) {
+            no_daemon = 1;
+        } else if (!strcmp(argv[0], "fork-server")) {
+            /* this is a special flag used only when the ADB client launches the ADB Server */
+            is_daemon = 1;
+        } else if (!strcmp(argv[0],"persist")) {
+            persist = 1;
+        } else if (!strncmp(argv[0], "-p", 2)) {
+            const char *product = NULL;
+            if (argv[0][2] == '\0') {
+                if (argc < 2) return usage();
+                product = argv[1];
+                argc--;
+                argv++;
+            } else {
+                product = argv[0] + 2;
+            }
+            gProductOutPath = find_product_out_path(product);
+            if (gProductOutPath.empty()) {
+                fprintf(stderr, "adb: could not resolve \"-p %s\"\n", product);
+                return usage();
+            }
+        } else if (argv[0][0]=='-' && argv[0][1]=='s') {
+            if (isdigit(argv[0][2])) {
+                serial = argv[0] + 2;
+            } else {
+                if (argc < 2 || argv[0][2] != '\0') return usage();
+                serial = argv[1];
+                argc--;
+                argv++;
+            }
+        } else if (!strcmp(argv[0],"-d")) {
+            ttype = kTransportUsb;
+        } else if (!strcmp(argv[0],"-e")) {
+            ttype = kTransportLocal;
+        } 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];
+                argc--;
+                argv++;
+            } else {
+                hostname = 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();
+                server_port_str = argv[1];
+                argc--;
+                argv++;
+            } 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 {
+                /* out of recognized modifiers and flags */
+            break;
+        }
+        argc--;
+        argv++;
+    }
+
+    adb_set_transport(ttype, serial);
+    adb_set_tcp_specifics(server_port);
+
+    if (is_server) {
+        if (no_daemon || is_daemon) {
+            r = adb_main(is_daemon, server_port);
+        } else {
+            r = launch_server(server_port);
+        }
+        if (r) {
+            fprintf(stderr,"* could not start server *\n");
+        }
+        return r;
+    }
+
+    if (argc == 0) {
+        return usage();
+    }
+
+    /* handle wait-for-* prefix */
+    if (!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
+        const char* service = argv[0];
+
+        if (!wait_for_device(service, ttype, serial)) {
+            return 1;
+        }
+
+        // Allow a command to be run after wait-for-device,
+        // e.g. 'adb wait-for-device shell'.
+        if (argc == 1) {
+            return 0;
+        }
+
+        /* Fall through */
+        argc--;
+        argv++;
+    }
+
+    /* adb_connect() commands */
+    if (!strcmp(argv[0], "devices")) {
+        const char *listopt;
+        if (argc < 2) {
+            listopt = "";
+        } else if (argc == 2 && !strcmp(argv[1], "-l")) {
+            listopt = argv[1];
+        } else {
+            fprintf(stderr, "Usage: adb devices [-l]\n");
+            return 1;
+        }
+
+        std::string query = android::base::StringPrintf("host:%s%s", argv[0], listopt);
+        printf("List of devices attached\n");
+        return adb_query_command(query);
+    }
+    else if (!strcmp(argv[0], "connect")) {
+        if (argc != 2) {
+            fprintf(stderr, "Usage: adb connect <host>[:<port>]\n");
+            return 1;
+        }
+
+        std::string query = android::base::StringPrintf("host:connect:%s", argv[1]);
+        return adb_query_command(query);
+    }
+    else if (!strcmp(argv[0], "disconnect")) {
+        if (argc > 2) {
+            fprintf(stderr, "Usage: adb disconnect [<host>[:<port>]]\n");
+            return 1;
+        }
+
+        std::string query = android::base::StringPrintf("host:disconnect:%s",
+                                                        (argc == 2) ? argv[1] : "");
+        return adb_query_command(query);
+    }
+    else if (!strcmp(argv[0], "emu")) {
+        return adb_send_emulator_command(argc, argv);
+    }
+    else if (!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) {
+        char h = (argv[0][0] == 'h');
+
+        if (h) {
+            printf("\x1b[41;33m");
+            fflush(stdout);
+        }
+
+        if (argc < 2) {
+            D("starting interactive shell\n");
+            r = interactive_shell();
+            if (h) {
+                printf("\x1b[0m");
+                fflush(stdout);
+            }
+            return r;
+        }
+
+        std::string cmd = "shell:";
+        --argc;
+        ++argv;
+        while (argc-- > 0) {
+            // We don't escape here, just like ssh(1). http://b/20564385.
+            cmd += *argv++;
+            if (*argv) cmd += " ";
+        }
+
+        while (true) {
+            D("interactive shell loop. cmd=%s\n", cmd.c_str());
+            std::string error;
+            int fd = adb_connect(cmd, &error);
+            int r;
+            if (fd >= 0) {
+                D("about to read_and_dump(fd=%d)\n", fd);
+                read_and_dump(fd);
+                D("read_and_dump() done.\n");
+                adb_close(fd);
+                r = 0;
+            } else {
+                fprintf(stderr,"error: %s\n", error.c_str());
+                r = -1;
+            }
+
+            if (persist) {
+                fprintf(stderr,"\n- waiting for device -\n");
+                adb_sleep_ms(1000);
+                wait_for_device("wait-for-device", ttype, serial);
+            } else {
+                if (h) {
+                    printf("\x1b[0m");
+                    fflush(stdout);
+                }
+                D("interactive shell loop. return r=%d\n", r);
+                return r;
+            }
+        }
+    }
+    else if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {
+        int exec_in = !strcmp(argv[0], "exec-in");
+
+        std::string cmd = "exec:";
+        cmd += argv[1];
+        argc -= 2;
+        argv += 2;
+        while (argc-- > 0) {
+            cmd += " " + escape_arg(*argv++);
+        }
+
+        std::string error;
+        int fd = adb_connect(cmd, &error);
+        if (fd < 0) {
+            fprintf(stderr, "error: %s\n", error.c_str());
+            return -1;
+        }
+
+        if (exec_in) {
+            copy_to_file(STDIN_FILENO, fd);
+        } else {
+            copy_to_file(fd, STDOUT_FILENO);
+        }
+
+        adb_close(fd);
+        return 0;
+    }
+    else if (!strcmp(argv[0], "kill-server")) {
+        std::string error;
+        int fd = _adb_connect("host:kill", &error);
+        if (fd == -1) {
+            fprintf(stderr,"* server not running *\n");
+            return 1;
+        }
+        return 0;
+    }
+    else if (!strcmp(argv[0], "sideload")) {
+        if (argc != 2) return usage();
+        if (adb_sideload_host(argv[1])) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+    else if (!strcmp(argv[0], "remount") ||
+             !strcmp(argv[0], "reboot") ||
+             !strcmp(argv[0], "reboot-bootloader") ||
+             !strcmp(argv[0], "tcpip") ||
+             !strcmp(argv[0], "usb") ||
+             !strcmp(argv[0], "root") ||
+             !strcmp(argv[0], "unroot") ||
+             !strcmp(argv[0], "disable-verity") ||
+             !strcmp(argv[0], "enable-verity")) {
+        std::string command;
+        if (!strcmp(argv[0], "reboot-bootloader")) {
+            command = "reboot:bootloader";
+        } else if (argc > 1) {
+            command = android::base::StringPrintf("%s:%s", argv[0], argv[1]);
+        } else {
+            command = android::base::StringPrintf("%s:", argv[0]);
+        }
+        return adb_connect_command(command);
+    }
+    else if (!strcmp(argv[0], "bugreport")) {
+        if (argc != 1) return usage();
+        return send_shell_command(ttype, serial, "shell:bugreport");
+    }
+    /* adb_command() wrapper commands */
+    else if (!strcmp(argv[0], "forward") || !strcmp(argv[0], "reverse")) {
+        std::string cmd;
+        char host_prefix[64];
+        char reverse = (char) !strcmp(argv[0], "reverse");
+        char remove = 0;
+        char remove_all = 0;
+        char list = 0;
+        char no_rebind = 0;
+
+        // Parse options here.
+        while (argc > 1 && argv[1][0] == '-') {
+            if (!strcmp(argv[1], "--list"))
+                list = 1;
+            else if (!strcmp(argv[1], "--remove"))
+                remove = 1;
+            else if (!strcmp(argv[1], "--remove-all"))
+                remove_all = 1;
+            else if (!strcmp(argv[1], "--no-rebind"))
+                no_rebind = 1;
+            else {
+                return usage();
+            }
+            argc--;
+            argv++;
+        }
+
+        // Ensure we can only use one option at a time.
+        if (list + remove + remove_all + no_rebind > 1) {
+            return usage();
+        }
+
+        // Determine the <host-prefix> for this command.
+        if (reverse) {
+            snprintf(host_prefix, sizeof host_prefix, "reverse");
+        } else {
+            if (serial) {
+                snprintf(host_prefix, sizeof host_prefix, "host-serial:%s",
+                        serial);
+            } else if (ttype == kTransportUsb) {
+                snprintf(host_prefix, sizeof host_prefix, "host-usb");
+            } else if (ttype == kTransportLocal) {
+                snprintf(host_prefix, sizeof host_prefix, "host-local");
+            } else {
+                snprintf(host_prefix, sizeof host_prefix, "host");
+            }
+        }
+
+        // Implement forward --list
+        if (list) {
+            if (argc != 1) {
+                return usage();
+            }
+
+            std::string query = android::base::StringPrintf("%s:list-forward", host_prefix);
+            return adb_query_command(query);
+        }
+
+        // Implement forward --remove-all
+        else if (remove_all) {
+            if (argc != 1) return usage();
+            cmd = android::base::StringPrintf("%s:killforward-all", host_prefix);
+        }
+
+        // Implement forward --remove <local>
+        else if (remove) {
+            if (argc != 2) return usage();
+            cmd = android::base::StringPrintf("%s:killforward:%s", host_prefix, argv[1]);
+        }
+        // Or implement one of:
+        //    forward <local> <remote>
+        //    forward --no-rebind <local> <remote>
+        else {
+            if (argc != 3) return usage();
+            const char* command = no_rebind ? "forward:norebind" : "forward";
+            cmd = android::base::StringPrintf("%s:%s:%s;%s", host_prefix, command, argv[1], argv[2]);
+        }
+
+        std::string error;
+        if (adb_command(cmd, &error)) {
+            fprintf(stderr, "error: %s\n", error.c_str());
+            return 1;
+        }
+        return 0;
+    }
+    /* do_sync_*() commands */
+    else if (!strcmp(argv[0], "ls")) {
+        if (argc != 2) return usage();
+        return do_sync_ls(argv[1]);
+    }
+    else if (!strcmp(argv[0], "push")) {
+        int show_progress = 0;
+        int copy_attrs = 0; // unused
+        const char* lpath = NULL, *rpath = NULL;
+
+        parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress, &copy_attrs);
+
+        if ((lpath != NULL) && (rpath != NULL)) {
+            return do_sync_push(lpath, rpath, show_progress);
+        }
+
+        return usage();
+    }
+    else if (!strcmp(argv[0], "pull")) {
+        int show_progress = 0;
+        int copy_attrs = 0;
+        const char* rpath = NULL, *lpath = ".";
+
+        parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress, &copy_attrs);
+
+        if (rpath != NULL) {
+            return do_sync_pull(rpath, lpath, show_progress, copy_attrs);
+        }
+
+        return usage();
+    }
+    else if (!strcmp(argv[0], "install")) {
+        if (argc < 2) return usage();
+        return install_app(ttype, serial, argc, argv);
+    }
+    else if (!strcmp(argv[0], "install-multiple")) {
+        if (argc < 2) return usage();
+        return install_multiple_app(ttype, serial, argc, argv);
+    }
+    else if (!strcmp(argv[0], "uninstall")) {
+        if (argc < 2) return usage();
+        return uninstall_app(ttype, serial, argc, argv);
+    }
+    else if (!strcmp(argv[0], "sync")) {
+        std::string src;
+        bool list_only = false;
+        if (argc < 2) {
+            // No local path was specified.
+            src = "";
+        } else if (argc >= 2 && strcmp(argv[1], "-l") == 0) {
+            list_only = true;
+            if (argc == 3) {
+                src = argv[2];
+            } else {
+                src = "";
+            }
+        } else if (argc == 2) {
+            // A local path or "android"/"data" arg was specified.
+            src = argv[1];
+        } else {
+            return usage();
+        }
+
+        if (src != "" &&
+            src != "system" && src != "data" && src != "vendor" && src != "oem") {
+            return usage();
+        }
+
+        std::string system_src_path = product_file("system");
+        std::string data_src_path = product_file("data");
+        std::string vendor_src_path = product_file("vendor");
+        std::string oem_src_path = product_file("oem");
+
+        int rc = 0;
+        if (rc == 0 && (src.empty() || src == "system")) {
+            rc = do_sync_sync(system_src_path, "/system", list_only);
+        }
+        if (rc == 0 && (src.empty() || src == "vendor") && directory_exists(vendor_src_path)) {
+            rc = do_sync_sync(vendor_src_path, "/vendor", list_only);
+        }
+        if (rc == 0 && (src.empty() || src == "oem") && directory_exists(oem_src_path)) {
+            rc = do_sync_sync(oem_src_path, "/oem", list_only);
+        }
+        if (rc == 0 && (src.empty() || src == "data")) {
+            rc = do_sync_sync(data_src_path, "/data", list_only);
+        }
+        return rc;
+    }
+    /* passthrough commands */
+    else if (!strcmp(argv[0],"get-state") ||
+        !strcmp(argv[0],"get-serialno") ||
+        !strcmp(argv[0],"get-devpath"))
+    {
+        return adb_query_command(format_host_command(argv[0], ttype, serial));
+    }
+    /* other commands */
+    else if (!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat") || !strcmp(argv[0],"longcat")) {
+        return logcat(ttype, serial, argc, argv);
+    }
+    else if (!strcmp(argv[0],"ppp")) {
+        return ppp(argc, argv);
+    }
+    else if (!strcmp(argv[0], "start-server")) {
+        std::string error;
+        return adb_connect("host:start-server", &error);
+    }
+    else if (!strcmp(argv[0], "backup")) {
+        return backup(argc, argv);
+    }
+    else if (!strcmp(argv[0], "restore")) {
+        return restore(argc, argv);
+    }
+    else if (!strcmp(argv[0], "keygen")) {
+        if (argc < 2) return usage();
+        return adb_auth_keygen(argv[1]);
+    }
+    else if (!strcmp(argv[0], "jdwp")) {
+        return adb_connect_command("jdwp");
+    }
+    /* "adb /?" is a common idiom under Windows */
+    else if (!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
+        help();
+        return 0;
+    }
+    else if (!strcmp(argv[0], "version")) {
+        version(stdout);
+        return 0;
+    }
+
+    usage();
+    return 1;
+}
+
+static int pm_command(transport_type transport, const char* serial,
+                      int argc, const char** argv)
+{
+    std::string cmd = "shell:pm";
+
+    while (argc-- > 0) {
+        cmd += " " + escape_arg(*argv++);
+    }
+
+    return send_shell_command(transport, serial, cmd);
+}
+
+static int uninstall_app(transport_type transport, const char* serial, int argc,
+                         const char** argv)
+{
+    /* if the user choose the -k option, we refuse to do it until devices are
+       out with the option to uninstall the remaining data somehow (adb/ui) */
+    if (argc == 3 && strcmp(argv[1], "-k") == 0)
+    {
+        printf(
+            "The -k option uninstalls the application while retaining the data/cache.\n"
+            "At the moment, there is no way to remove the remaining data.\n"
+            "You will have to reinstall the application with the same signature, and fully uninstall it.\n"
+            "If you truly wish to continue, execute 'adb shell pm uninstall -k %s'\n", argv[2]);
+        return -1;
+    }
+
+    /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
+    return pm_command(transport, serial, argc, argv);
+}
+
+static int delete_file(transport_type transport, const char* serial, char* filename)
+{
+    std::string cmd = "shell:rm -f " + escape_arg(filename);
+    return send_shell_command(transport, serial, cmd);
+}
+
+static const char* get_basename(const char* filename)
+{
+    const char* basename = adb_dirstop(filename);
+    if (basename) {
+        basename++;
+        return basename;
+    } else {
+        return filename;
+    }
+}
+
+static int install_app(transport_type transport, const char* serial, int argc,
+                       const char** argv)
+{
+    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++) {
+        if (!strcmp(argv[i], "-s")) {
+            where = SD_DEST;
+        }
+    }
+
+    // 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];
+        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 -1;
+            }
+
+            last_apk = i;
+            break;
+        }
+    }
+
+    if (last_apk == -1) {
+        fprintf(stderr, "Missing APK file\n");
+        return -1;
+    }
+
+    const char* apk_file = argv[last_apk];
+    char apk_dest[PATH_MAX];
+    snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file));
+    int err = do_sync_push(apk_file, apk_dest, 0 /* no show progress */);
+    if (err) {
+        goto cleanup_apk;
+    } else {
+        argv[last_apk] = apk_dest; /* destination name, not source location */
+    }
+
+    err = pm_command(transport, serial, argc, argv);
+
+cleanup_apk:
+    delete_file(transport, serial, apk_dest);
+    return err;
+}
+
+static int install_multiple_app(transport_type 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--) {
+        const char* file = argv[i];
+        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 -1;
+            }
+
+            total_size += sb.st_size;
+            first_apk = i;
+        } else {
+            break;
+        }
+    }
+
+    if (first_apk == -1) {
+        fprintf(stderr, "Missing APK file\n");
+        return 1;
+    }
+
+#if defined(_WIN32) // Remove when we're using clang for Win32.
+    std::string cmd = android::base::StringPrintf("exec:pm install-create -S %u", (unsigned) total_size);
+#else
+    std::string cmd = android::base::StringPrintf("exec:pm install-create -S %" PRIu64, total_size);
+#endif
+    for (i = 1; i < first_apk; i++) {
+        cmd += " " + escape_arg(argv[i]);
+    }
+
+    // Create install session
+    std::string error;
+    int fd = adb_connect(cmd, &error);
+    if (fd < 0) {
+        fprintf(stderr, "Connect error for create: %s\n", error.c_str());
+        return -1;
+    }
+    char buf[BUFSIZ];
+    read_status_line(fd, buf, sizeof(buf));
+    adb_close(fd);
+
+    int session_id = -1;
+    if (!strncmp("Success", buf, 7)) {
+        char* start = strrchr(buf, '[');
+        char* end = strrchr(buf, ']');
+        if (start && end) {
+            *end = '\0';
+            session_id = strtol(start + 1, NULL, 10);
+        }
+    }
+    if (session_id < 0) {
+        fprintf(stderr, "Failed to create session\n");
+        fputs(buf, stderr);
+        return -1;
+    }
+
+    // Valid session, now stream the APKs
+    int success = 1;
+    for (i = first_apk; i < argc; i++) {
+        const char* file = argv[i];
+        if (stat(file, &sb) == -1) {
+            fprintf(stderr, "Failed to stat %s\n", file);
+            success = 0;
+            goto finalize_session;
+        }
+
+#if defined(_WIN32) // Remove when we're using clang for Win32.
+        std::string cmd = android::base::StringPrintf(
+                "exec:pm install-write -S %u %d %d_%s -",
+                (unsigned) sb.st_size, session_id, i, get_basename(file));
+#else
+        std::string cmd = android::base::StringPrintf(
+                "exec:pm install-write -S %" PRIu64 " %d %d_%s -",
+                static_cast<uint64_t>(sb.st_size), session_id, i, get_basename(file));
+#endif
+
+        int localFd = adb_open(file, O_RDONLY);
+        if (localFd < 0) {
+            fprintf(stderr, "Failed to open %s: %s\n", file, strerror(errno));
+            success = 0;
+            goto finalize_session;
+        }
+
+        std::string error;
+        int remoteFd = adb_connect(cmd, &error);
+        if (remoteFd < 0) {
+            fprintf(stderr, "Connect error for write: %s\n", error.c_str());
+            adb_close(localFd);
+            success = 0;
+            goto finalize_session;
+        }
+
+        copy_to_file(localFd, remoteFd);
+        read_status_line(remoteFd, buf, sizeof(buf));
+
+        adb_close(localFd);
+        adb_close(remoteFd);
+
+        if (strncmp("Success", buf, 7)) {
+            fprintf(stderr, "Failed to write %s\n", file);
+            fputs(buf, stderr);
+            success = 0;
+            goto finalize_session;
+        }
+    }
+
+finalize_session:
+    // Commit session if we streamed everything okay; otherwise abandon
+    std::string service =
+            android::base::StringPrintf("exec:pm install-%s %d",
+                                        success ? "commit" : "abandon", session_id);
+    fd = adb_connect(service, &error);
+    if (fd < 0) {
+        fprintf(stderr, "Connect error for finalize: %s\n", error.c_str());
+        return -1;
+    }
+    read_status_line(fd, buf, sizeof(buf));
+    adb_close(fd);
+
+    if (!strncmp("Success", buf, 7)) {
+        fputs(buf, stderr);
+        return 0;
+    } else {
+        fprintf(stderr, "Failed to finalize session\n");
+        fputs(buf, stderr);
+        return -1;
+    }
+}
diff --git a/adb/console.c b/adb/console.cpp
similarity index 93%
rename from adb/console.c
rename to adb/console.cpp
index b813d33..452ee41 100644
--- a/adb/console.c
+++ b/adb/console.cpp
@@ -24,7 +24,7 @@
 }
 
 
-int  adb_send_emulator_command(int  argc, char**  argv)
+int  adb_send_emulator_command(int  argc, const char**  argv)
 {
     int   fd, nn;
 
diff --git a/adb/disable_verity_service.c b/adb/disable_verity_service.c
deleted file mode 100644
index ed3da52..0000000
--- a/adb/disable_verity_service.c
+++ /dev/null
@@ -1,199 +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.
- */
-
-#include "sysdeps.h"
-
-#define  TRACE_TAG  TRACE_ADB
-#include "adb.h"
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <inttypes.h>
-
-#include "cutils/properties.h"
-#include "ext4_sb.h"
-#include <fs_mgr.h>
-
-#define FSTAB_PREFIX "/fstab."
-struct fstab *fstab;
-
-__attribute__((__format__(printf, 2, 3))) __nonnull((2))
-static void write_console(int fd, const char* format, ...)
-{
-    char buffer[256];
-    va_list args;
-    va_start (args, format);
-    vsnprintf (buffer, sizeof(buffer), format, args);
-    va_end (args);
-
-    adb_write(fd, buffer, strnlen(buffer, sizeof(buffer)));
-}
-
-static int get_target_device_size(int fd, const char *blk_device,
-                                  uint64_t *device_size)
-{
-    int data_device;
-    struct ext4_super_block sb;
-    struct fs_info info;
-
-    info.len = 0;  /* Only len is set to 0 to ask the device for real size. */
-
-    data_device = adb_open(blk_device, O_RDONLY | O_CLOEXEC);
-    if (data_device < 0) {
-        write_console(fd, "Error opening block device (%s)\n", strerror(errno));
-        return -1;
-    }
-
-    if (lseek64(data_device, 1024, SEEK_SET) < 0) {
-        write_console(fd, "Error seeking to superblock\n");
-        adb_close(data_device);
-        return -1;
-    }
-
-    if (adb_read(data_device, &sb, sizeof(sb)) != sizeof(sb)) {
-        write_console(fd, "Error reading superblock\n");
-        adb_close(data_device);
-        return -1;
-    }
-
-    ext4_parse_sb(&sb, &info);
-    *device_size = info.len;
-
-    adb_close(data_device);
-    return 0;
-}
-
-static int disable_verity(int fd, const char *block_device,
-                          const char* mount_point)
-{
-    uint32_t magic_number;
-    const uint32_t voff = VERITY_METADATA_MAGIC_DISABLE;
-    uint64_t device_length;
-    int device;
-    int retval = -1;
-
-    device = adb_open(block_device, O_RDWR | O_CLOEXEC);
-    if (device == -1) {
-        write_console(fd, "Could not open block device %s (%s).\n",
-                      block_device, strerror(errno));
-        write_console(fd, "Maybe run adb remount?\n");
-        goto errout;
-    }
-
-    // find the start of the verity metadata
-    if (get_target_device_size(fd, (char*)block_device, &device_length) < 0) {
-        write_console(fd, "Could not get target device size.\n");
-        goto errout;
-    }
-
-    if (lseek64(device, device_length, SEEK_SET) < 0) {
-        write_console(fd,
-                      "Could not seek to start of verity metadata block.\n");
-        goto errout;
-    }
-
-    // check the magic number
-    if (adb_read(device, &magic_number, sizeof(magic_number))
-             != sizeof(magic_number)) {
-        write_console(fd, "Couldn't read magic number!\n");
-        goto errout;
-    }
-
-    if (magic_number == VERITY_METADATA_MAGIC_DISABLE) {
-        write_console(fd, "Verity already disabled on %s\n", mount_point);
-        goto errout;
-    }
-
-    if (magic_number != VERITY_METADATA_MAGIC_NUMBER) {
-        write_console(fd,
-                      "Couldn't find verity metadata at offset %"PRIu64"!\n",
-                      device_length);
-        goto errout;
-    }
-
-    if (lseek64(device, device_length, SEEK_SET) < 0) {
-        write_console(fd,
-                      "Could not seek to start of verity metadata block.\n");
-        goto errout;
-    }
-
-    if (adb_write(device, &voff, sizeof(voff)) != sizeof(voff)) {
-        write_console(fd, "Could not set verity disabled flag on device %s\n",
-                      block_device);
-        goto errout;
-    }
-
-    write_console(fd, "Verity disabled on %s\n", mount_point);
-    retval = 0;
-errout:
-    if (device != -1)
-        adb_close(device);
-    return retval;
-}
-
-void disable_verity_service(int fd, void* cookie)
-{
-#ifdef ALLOW_ADBD_DISABLE_VERITY
-    char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
-    char propbuf[PROPERTY_VALUE_MAX];
-    int i;
-    bool any_disabled = false;
-
-    property_get("ro.secure", propbuf, "0");
-    if (strcmp(propbuf, "1")) {
-        write_console(fd, "verity not enabled - ENG build\n");
-        goto errout;
-    }
-
-    property_get("ro.debuggable", propbuf, "0");
-    if (strcmp(propbuf, "1")) {
-        write_console(fd, "verity cannot be disabled - 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) {
-        write_console(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 (!disable_verity(fd, fstab->recs[i].blk_device,
-                                fstab->recs[i].mount_point)) {
-                any_disabled = true;
-            }
-       }
-    }
-
-    if (any_disabled) {
-        write_console(fd,
-                      "Now reboot your device for settings to take effect\n");
-    }
-#else
-    write_console(fd, "disable-verity only works for userdebug builds\n");
-#endif
-
-errout:
-    adb_close(fd);
-}
diff --git a/adb/fdevent.c b/adb/fdevent.cpp
similarity index 96%
rename from adb/fdevent.c
rename to adb/fdevent.cpp
index 43e600c..0c43c5e 100644
--- a/adb/fdevent.c
+++ b/adb/fdevent.cpp
@@ -15,25 +15,23 @@
 ** limitations under the License.
 */
 
-#include <sys/ioctl.h>
+#define TRACE_TAG TRACE_FDEVENT
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
+#include "sysdeps.h"
+#include "fdevent.h"
+
 #include <errno.h>
-
 #include <fcntl.h>
-
 #include <stdarg.h>
 #include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
 
+#include "adb_io.h"
 #include "adb_trace.h"
-#include "fdevent.h"
-#include "transport.h"
-#include "sysdeps.h"
-
-#define TRACE_TAG  TRACE_FDEVENT
 
 /* !!! Do not enable DEBUG for the adb that will run as the server:
 ** both stdout and stderr are used to communicate between the client
@@ -88,6 +86,12 @@
 static fdevent list_pending = {
     .next = &list_pending,
     .prev = &list_pending,
+    .fd = -1,
+    .force_eof = 0,
+    .state = 0,
+    .events = 0,
+    .func = nullptr,
+    .arg = nullptr,
 };
 
 static fdevent **fd_table = 0;
@@ -312,7 +316,7 @@
 }
 
 #if !DEBUG
-static inline void dump_all_fds(const char *extra_msg) {}
+static inline void dump_all_fds(const char* /* extra_msg */) {}
 #else
 static void dump_all_fds(const char *extra_msg)
 {
@@ -434,7 +438,8 @@
         while(fd_table_max <= fde->fd) {
             fd_table_max *= 2;
         }
-        fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max);
+        fd_table = reinterpret_cast<fdevent**>(
+            realloc(fd_table, sizeof(fdevent*) * fd_table_max));
         if(fd_table == 0) {
             FATAL("could not expand fd_table to %d entries\n", fd_table_max);
         }
@@ -505,7 +510,8 @@
     fde->func(fde->fd, events, fde->arg);
 }
 
-static void fdevent_subproc_event_func(int fd, unsigned ev, void *userdata)
+static void fdevent_subproc_event_func(int fd, unsigned ev,
+                                       void* /* userdata */)
 {
 
     D("subproc handling on fd=%d ev=%04x\n", fd, ev);
@@ -520,7 +526,7 @@
     if(ev & FDE_READ){
       int subproc_fd;
 
-      if(readx(fd, &subproc_fd, sizeof(subproc_fd))) {
+      if(!ReadFdExactly(fd, &subproc_fd, sizeof(subproc_fd))) {
           FATAL("Failed to read the subproc's fd from fd=%d\n", fd);
       }
       if((subproc_fd < 0) || (subproc_fd >= fd_table_max)) {
@@ -579,6 +585,7 @@
         FATAL("fde %p not created by fdevent_create()\n", fde);
     }
     fdevent_remove(fde);
+    free(fde);
 }
 
 void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg)
@@ -661,6 +668,8 @@
     if(adb_socketpair(s)) {
         FATAL("cannot create shell-exit socket-pair\n");
     }
+    D("socketpair: (%d,%d)", s[0], s[1]);
+
     SHELL_EXIT_NOTIFY_FD = s[0];
     fdevent *fde;
     fde = fdevent_create(s[1], fdevent_subproc_event_func, NULL);
diff --git a/adb/fdevent.h b/adb/fdevent.h
index a0ebe2a..8d84b29 100644
--- a/adb/fdevent.h
+++ b/adb/fdevent.h
@@ -28,7 +28,7 @@
 /* features that may be set (via the events set/add/del interface) */
 #define FDE_DONT_CLOSE        0x0080
 
-typedef struct fdevent fdevent;
+struct fdevent;
 
 typedef void (*fd_func)(int fd, unsigned events, void *userdata);
 
@@ -64,20 +64,18 @@
 */
 void fdevent_loop();
 
-struct fdevent 
-{
+struct fdevent {
     fdevent *next;
     fdevent *prev;
 
     int fd;
     int force_eof;
 
-    unsigned short state;
-    unsigned short events;
+    uint16_t state;
+    uint16_t events;
 
     fd_func func;
     void *arg;
 };
 
-
 #endif
diff --git a/adb/file_sync_client.c b/adb/file_sync_client.cpp
similarity index 83%
rename from adb/file_sync_client.c
rename to adb/file_sync_client.cpp
index ad59e81..aded301 100644
--- a/adb/file_sync_client.c
+++ b/adb/file_sync_client.cpp
@@ -14,25 +14,25 @@
  * limitations under the License.
  */
 
+#include <dirent.h>
+#include <errno.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <errno.h>
 #include <sys/stat.h>
 #include <sys/time.h>
-#include <time.h>
-#include <dirent.h>
-#include <limits.h>
 #include <sys/types.h>
-#include <zipfile/zipfile.h>
+#include <time.h>
 #include <utime.h>
 
 #include "sysdeps.h"
+
 #include "adb.h"
 #include "adb_client.h"
+#include "adb_io.h"
 #include "file_sync_service.h"
 
-
 static unsigned long long total_bytes;
 static long long start_time;
 
@@ -86,7 +86,7 @@
     msg.req.id = ID_QUIT;
     msg.req.namelen = 0;
 
-    writex(fd, &msg.req, sizeof(msg.req));
+    WriteFdExactly(fd, &msg.req, sizeof(msg.req));
 }
 
 typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie);
@@ -103,20 +103,20 @@
     msg.req.id = ID_LIST;
     msg.req.namelen = htoll(len);
 
-    if(writex(fd, &msg.req, sizeof(msg.req)) ||
-       writex(fd, path, len)) {
+    if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
+       !WriteFdExactly(fd, path, len)) {
         goto fail;
     }
 
     for(;;) {
-        if(readx(fd, &msg.dent, sizeof(msg.dent))) break;
+        if(!ReadFdExactly(fd, &msg.dent, sizeof(msg.dent))) break;
         if(msg.dent.id == ID_DONE) return 0;
         if(msg.dent.id != ID_DENT) break;
 
         len = ltohl(msg.dent.namelen);
         if(len > 256) break;
 
-        if(readx(fd, buf, len)) break;
+        if(!ReadFdExactly(fd, buf, len)) break;
         buf[len] = 0;
 
         func(ltohl(msg.dent.mode),
@@ -130,8 +130,6 @@
     return -1;
 }
 
-typedef struct syncsendbuf syncsendbuf;
-
 struct syncsendbuf {
     unsigned id;
     unsigned size;
@@ -149,12 +147,12 @@
     msg.req.id = ID_STAT;
     msg.req.namelen = htoll(len);
 
-    if(writex(fd, &msg.req, sizeof(msg.req)) ||
-       writex(fd, path, len)) {
+    if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
+       !WriteFdExactly(fd, path, len)) {
         return -1;
     }
 
-    if(readx(fd, &msg.stat, sizeof(msg.stat))) {
+    if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
         return -1;
     }
 
@@ -175,8 +173,8 @@
     msg.req.id = ID_STAT;
     msg.req.namelen = htoll(len);
 
-    if(writex(fd, &msg.req, sizeof(msg.req)) ||
-       writex(fd, path, len)) {
+    if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
+       !WriteFdExactly(fd, path, len)) {
         return -1;
     }
 
@@ -188,7 +186,7 @@
 {
     syncmsg msg;
 
-    if(readx(fd, &msg.stat, sizeof(msg.stat)))
+    if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat)))
         return -1;
 
     if(msg.stat.id != ID_STAT)
@@ -209,12 +207,12 @@
     msg.req.id = ID_STAT;
     msg.req.namelen = htoll(len);
 
-    if(writex(fd, &msg.req, sizeof(msg.req)) ||
-       writex(fd, path, len)) {
+    if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
+       !WriteFdExactly(fd, path, len)) {
         return -1;
     }
 
-    if(readx(fd, &msg.stat, sizeof(msg.stat))) {
+    if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
         return -1;
     }
 
@@ -240,7 +238,7 @@
     if (show_progress) {
         // Determine local file size.
         struct stat st;
-        if (fstat(lfd, &st)) {
+        if (stat(path, &st)) {
             fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno));
             return -1;
         }
@@ -264,7 +262,7 @@
         }
 
         sbuf->size = htoll(ret);
-        if(writex(fd, sbuf, sizeof(unsigned) * 2 + ret)){
+        if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + ret)){
             err = -1;
             break;
         }
@@ -294,7 +292,7 @@
 
         memcpy(sbuf->data, &file_buffer[total], count);
         sbuf->size = htoll(count);
-        if(writex(fd, sbuf, sizeof(unsigned) * 2 + count)){
+        if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + count)){
             err = -1;
             break;
         }
@@ -309,7 +307,9 @@
     return err;
 }
 
-#ifdef HAVE_SYMLINKS
+#if defined(_WIN32)
+extern int write_data_link(int fd, const char *path, syncsendbuf *sbuf) __attribute__((error("no symlinks on Windows")));
+#else
 static int write_data_link(int fd, const char *path, syncsendbuf *sbuf)
 {
     int len, ret;
@@ -324,7 +324,7 @@
     sbuf->size = htoll(len + 1);
     sbuf->id = ID_DATA;
 
-    ret = writex(fd, sbuf, sizeof(unsigned) * 2 + len + 1);
+    ret = !WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + len + 1);
     if(ret)
         return -1;
 
@@ -353,8 +353,8 @@
     msg.req.id = ID_SEND;
     msg.req.namelen = htoll(len + r);
 
-    if(writex(fd, &msg.req, sizeof(msg.req)) ||
-       writex(fd, rpath, len) || writex(fd, tmp, r)) {
+    if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
+       !WriteFdExactly(fd, rpath, len) || !WriteFdExactly(fd, tmp, r)) {
         free(file_buffer);
         goto fail;
     }
@@ -364,26 +364,24 @@
         free(file_buffer);
     } else if (S_ISREG(mode))
         write_data_file(fd, lpath, sbuf, show_progress);
-#ifdef HAVE_SYMLINKS
     else if (S_ISLNK(mode))
         write_data_link(fd, lpath, sbuf);
-#endif
     else
         goto fail;
 
     msg.data.id = ID_DONE;
     msg.data.size = htoll(mtime);
-    if(writex(fd, &msg.data, sizeof(msg.data)))
+    if(!WriteFdExactly(fd, &msg.data, sizeof(msg.data)))
         goto fail;
 
-    if(readx(fd, &msg.status, sizeof(msg.status)))
+    if(!ReadFdExactly(fd, &msg.status, sizeof(msg.status)))
         return -1;
 
     if(msg.status.id != ID_OKAY) {
         if(msg.status.id == ID_FAIL) {
             len = ltohl(msg.status.msglen);
             if(len > 256) len = 256;
-            if(readx(fd, sbuf->data, len)) {
+            if(!ReadFdExactly(fd, sbuf->data, len)) {
                 return -1;
             }
             sbuf->data[len] = 0;
@@ -439,12 +437,12 @@
         stat_msg.req.id = ID_STAT;
         stat_msg.req.namelen = htoll(len);
 
-        if (writex(fd, &stat_msg.req, sizeof(stat_msg.req)) ||
-            writex(fd, rpath, len)) {
+        if (!WriteFdExactly(fd, &stat_msg.req, sizeof(stat_msg.req)) ||
+            !WriteFdExactly(fd, rpath, len)) {
             return -1;
         }
 
-        if (readx(fd, &stat_msg.stat, sizeof(stat_msg.stat))) {
+        if (!ReadFdExactly(fd, &stat_msg.stat, sizeof(stat_msg.stat))) {
             return -1;
         }
 
@@ -455,12 +453,12 @@
 
     msg.req.id = ID_RECV;
     msg.req.namelen = htoll(len);
-    if(writex(fd, &msg.req, sizeof(msg.req)) ||
-       writex(fd, rpath, len)) {
+    if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
+       !WriteFdExactly(fd, rpath, len)) {
         return -1;
     }
 
-    if(readx(fd, &msg.data, sizeof(msg.data))) {
+    if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
         return -1;
     }
     id = msg.data.id;
@@ -479,7 +477,7 @@
     }
 
     for(;;) {
-        if(readx(fd, &msg.data, sizeof(msg.data))) {
+        if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
             return -1;
         }
         id = msg.data.id;
@@ -494,12 +492,12 @@
             return -1;
         }
 
-        if(readx(fd, buffer, len)) {
+        if(!ReadFdExactly(fd, buffer, len)) {
             adb_close(lfd);
             return -1;
         }
 
-        if(writex(lfd, buffer, len)) {
+        if(!WriteFdExactly(lfd, buffer, len)) {
             fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno));
             adb_close(lfd);
             return -1;
@@ -522,35 +520,30 @@
     if(id == ID_FAIL) {
         len = ltohl(msg.data.size);
         if(len > 256) len = 256;
-        if(readx(fd, buffer, len)) {
+        if(!ReadFdExactly(fd, buffer, len)) {
             return -1;
         }
         buffer[len] = 0;
     } else {
         memcpy(buffer, &id, 4);
         buffer[4] = 0;
-//        strcpy(buffer,"unknown reason");
     }
     fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
     return 0;
 }
 
-
-
 /* --- */
-
-
 static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
                           const char *name, void *cookie)
 {
     printf("%08x %08x %08x %s\n", mode, size, time, name);
 }
 
-int do_sync_ls(const char *path)
-{
-    int fd = adb_connect("sync:");
-    if(fd < 0) {
-        fprintf(stderr,"error: %s\n", adb_error());
+int do_sync_ls(const char* path) {
+    std::string error;
+    int fd = adb_connect("sync:", &error);
+    if (fd < 0) {
+        fprintf(stderr,"error: %s\n", error.c_str());
         return 1;
     }
 
@@ -562,8 +555,6 @@
     }
 }
 
-typedef struct copyinfo copyinfo;
-
 struct copyinfo
 {
     copyinfo *next;
@@ -573,7 +564,6 @@
     unsigned int mode;
     unsigned int size;
     int flag;
-    //char data[0];
 };
 
 copyinfo *mkcopyinfo(const char *spath, const char *dpath,
@@ -585,7 +575,8 @@
     int ssize = slen + nlen + 2;
     int dsize = dlen + nlen + 2;
 
-    copyinfo *ci = malloc(sizeof(copyinfo) + ssize + dsize);
+    copyinfo *ci = reinterpret_cast<copyinfo*>(
+        malloc(sizeof(copyinfo) + ssize + dsize));
     if(ci == 0) {
         fprintf(stderr,"out of memory\n");
         abort();
@@ -601,7 +592,6 @@
     snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
     snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
 
-//    fprintf(stderr,"mkcopyinfo('%s','%s')\n", ci->src, ci->dst);
     return ci;
 }
 
@@ -615,8 +605,6 @@
     copyinfo *dirlist = 0;
     copyinfo *ci, *next;
 
-//    fprintf(stderr,"local_build_list('%s','%s')\n", lpath, rpath);
-
     d = opendir(lpath);
     if(d == 0) {
         fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
@@ -692,14 +680,14 @@
     if((lpath[0] == 0) || (rpath[0] == 0)) return -1;
     if(lpath[strlen(lpath) - 1] != '/') {
         int  tmplen = strlen(lpath)+2;
-        char *tmp = malloc(tmplen);
+        char *tmp = reinterpret_cast<char*>(malloc(tmplen));
         if(tmp == 0) return -1;
         snprintf(tmp, tmplen, "%s/",lpath);
         lpath = tmp;
     }
     if(rpath[strlen(rpath) - 1] != '/') {
         int tmplen = strlen(rpath)+2;
-        char *tmp = malloc(tmplen);
+        char *tmp = reinterpret_cast<char*>(malloc(tmplen));
         if(tmp == 0) return -1;
         snprintf(tmp, tmplen, "%s/",rpath);
         rpath = tmp;
@@ -755,11 +743,11 @@
 {
     struct stat st;
     unsigned mode;
-    int fd;
 
-    fd = adb_connect("sync:");
-    if(fd < 0) {
-        fprintf(stderr,"error: %s\n", adb_error());
+    std::string error;
+    int fd = adb_connect("sync:", &error);
+    if (fd < 0) {
+        fprintf(stderr,"error: %s\n", error.c_str());
         return 1;
     }
 
@@ -792,7 +780,8 @@
                 name++;
             }
             int  tmplen = strlen(name) + strlen(rpath) + 2;
-            char *tmp = malloc(strlen(name) + strlen(rpath) + 2);
+            char *tmp = reinterpret_cast<char*>(
+                malloc(strlen(name) + strlen(rpath) + 2));
             if(tmp == 0) return 1;
             snprintf(tmp, tmplen, "%s/%s", rpath, name);
             rpath = tmp;
@@ -811,12 +800,12 @@
 }
 
 
-typedef struct {
+struct sync_ls_build_list_cb_args {
     copyinfo **filelist;
     copyinfo **dirlist;
     const char *rpath;
     const char *lpath;
-} sync_ls_build_list_cb_args;
+};
 
 void
 sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
@@ -880,7 +869,7 @@
     return 0;
 }
 
-static int set_time_and_mode(const char *lpath, unsigned int time, unsigned int mode)
+static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
 {
     struct utimbuf times = { time, time };
     int r1 = utime(lpath, &times);
@@ -893,6 +882,21 @@
     return r1 ? : r2;
 }
 
+/* Return a copy of the path string with / appended if needed */
+static char *add_slash_to_path(const char *path)
+{
+    if (path[strlen(path) - 1] != '/') {
+        size_t len = strlen(path) + 2;
+        char *path_with_slash = reinterpret_cast<char*>(malloc(len));
+        if (path_with_slash == NULL)
+            return NULL;
+        snprintf(path_with_slash, len, "%s/", path);
+        return path_with_slash;
+    } else {
+        return strdup(path);
+    }
+}
+
 static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
                                  int copy_attrs)
 {
@@ -900,28 +904,32 @@
     copyinfo *ci, *next;
     int pulled = 0;
     int skipped = 0;
+    char *rpath_clean = NULL;
+    char *lpath_clean = NULL;
+    int ret = 0;
+
+    if (rpath[0] == '\0' || lpath[0] == '\0') {
+        ret = -1;
+        goto finish;
+    }
 
     /* Make sure that both directory paths end in a slash. */
-    if (rpath[0] == 0 || lpath[0] == 0) return -1;
-    if (rpath[strlen(rpath) - 1] != '/') {
-        int  tmplen = strlen(rpath) + 2;
-        char *tmp = malloc(tmplen);
-        if (tmp == 0) return -1;
-        snprintf(tmp, tmplen, "%s/", rpath);
-        rpath = tmp;
+    rpath_clean = add_slash_to_path(rpath);
+    if (!rpath_clean) {
+        ret = -1;
+        goto finish;
     }
-    if (lpath[strlen(lpath) - 1] != '/') {
-        int  tmplen = strlen(lpath) + 2;
-        char *tmp = malloc(tmplen);
-        if (tmp == 0) return -1;
-        snprintf(tmp, tmplen, "%s/", lpath);
-        lpath = tmp;
+    lpath_clean = add_slash_to_path(lpath);
+    if (!lpath_clean) {
+        ret = -1;
+        goto finish;
     }
 
-    fprintf(stderr, "pull: building file list...\n");
     /* Recursively build the list of files to copy. */
-    if (remote_build_list(fd, &filelist, rpath, lpath)) {
-        return -1;
+    fprintf(stderr, "pull: building file list...\n");
+    if (remote_build_list(fd, &filelist, rpath_clean, lpath_clean)) {
+        ret = -1;
+        goto finish;
     }
 
     for (ci = filelist; ci != 0; ci = next) {
@@ -929,11 +937,13 @@
         if (ci->flag == 0) {
             fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
             if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) {
-                return 1;
+                ret = -1;
+                goto finish;
             }
 
             if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
-               return 1;
+                ret = -1;
+                goto finish;
             }
             pulled++;
         } else {
@@ -946,7 +956,10 @@
             pulled, (pulled == 1) ? "" : "s",
             skipped, (skipped == 1) ? "" : "s");
 
-    return 0;
+finish:
+    free(lpath_clean);
+    free(rpath_clean);
+    return ret;
 }
 
 int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int copy_attrs)
@@ -954,11 +967,10 @@
     unsigned mode, time;
     struct stat st;
 
-    int fd;
-
-    fd = adb_connect("sync:");
-    if(fd < 0) {
-        fprintf(stderr,"error: %s\n", adb_error());
+    std::string error;
+    int fd = adb_connect("sync:", &error);
+    if (fd < 0) {
+        fprintf(stderr,"error: %s\n", error.c_str());
         return 1;
     }
 
@@ -983,7 +995,7 @@
                     name++;
                 }
                 int  tmplen = strlen(name) + strlen(lpath) + 2;
-                char *tmp = malloc(tmplen);
+                char *tmp = reinterpret_cast<char*>(malloc(tmplen));
                 if(tmp == 0) return 1;
                 snprintf(tmp, tmplen, "%s/%s", lpath, name);
                 lpath = tmp;
@@ -1014,18 +1026,19 @@
     }
 }
 
-int do_sync_sync(const char *lpath, const char *rpath, int listonly)
+int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only)
 {
-    fprintf(stderr,"syncing %s...\n",rpath);
+    fprintf(stderr, "syncing %s...\n", rpath.c_str());
 
-    int fd = adb_connect("sync:");
-    if(fd < 0) {
-        fprintf(stderr,"error: %s\n", adb_error());
+    std::string error;
+    int fd = adb_connect("sync:", &error);
+    if (fd < 0) {
+        fprintf(stderr, "error: %s\n", error.c_str());
         return 1;
     }
 
     BEGIN();
-    if(copy_local_dir_remote(fd, lpath, rpath, 1, listonly)){
+    if (copy_local_dir_remote(fd, lpath.c_str(), rpath.c_str(), 1, list_only)) {
         return 1;
     } else {
         END();
diff --git a/adb/file_sync_service.c b/adb/file_sync_service.cpp
similarity index 79%
rename from adb/file_sync_service.c
rename to adb/file_sync_service.cpp
index 7933858..5d17335 100644
--- a/adb/file_sync_service.c
+++ b/adb/file_sync_service.cpp
@@ -14,34 +14,31 @@
  * limitations under the License.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#define TRACE_TAG TRACE_SYNC
 
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <utime.h>
-#include <unistd.h>
-
-#include <errno.h>
-#include <private/android_filesystem_config.h>
-#include <selinux/android.h>
 #include "sysdeps.h"
-
-#define TRACE_TAG  TRACE_SYNC
-#include "adb.h"
 #include "file_sync_service.h"
 
-/* TODO: use fs_config to configure permissions on /data */
-static bool is_on_system(const char *name) {
-    const char *SYSTEM = "/system/";
-    return (strncmp(SYSTEM, name, strlen(SYSTEM)) == 0);
-}
+#include <dirent.h>
+#include <errno.h>
+#include <selinux/android.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utime.h>
 
-static bool is_on_vendor(const char *name) {
-    const char *VENDOR = "/vendor/";
-    return (strncmp(VENDOR, name, strlen(VENDOR)) == 0);
+#include "adb.h"
+#include "adb_io.h"
+#include "private/android_filesystem_config.h"
+
+static bool should_use_fs_config(const char* path) {
+    // TODO: use fs_config to configure permissions on /data.
+    return strncmp("/system/", path, strlen("/system/")) == 0 ||
+           strncmp("/vendor/", path, strlen("/vendor/")) == 0 ||
+           strncmp("/oem/", path, strlen("/oem/")) == 0;
 }
 
 static int mkdirs(char *name)
@@ -59,8 +56,8 @@
         x = adb_dirstart(x);
         if(x == 0) return 0;
         *x = 0;
-        if (is_on_system(name) || is_on_vendor(name)) {
-            fs_config(name, 1, &uid, &gid, &mode, &cap);
+        if (should_use_fs_config(name)) {
+            fs_config(name, 1, NULL, &uid, &gid, &mode, &cap);
         }
         ret = adb_mkdir(name, mode);
         if((ret < 0) && (errno != EEXIST)) {
@@ -97,7 +94,7 @@
         msg.stat.time = htoll(st.st_mtime);
     }
 
-    return writex(s, &msg.stat, sizeof(msg.stat));
+    return WriteFdExactly(s, &msg.stat, sizeof(msg.stat)) ? 0 : -1;
 }
 
 static int do_list(int s, const char *path)
@@ -135,8 +132,8 @@
             msg.dent.time = htoll(st.st_mtime);
             msg.dent.namelen = htoll(len);
 
-            if(writex(s, &msg.dent, sizeof(msg.dent)) ||
-               writex(s, de->d_name, len)) {
+            if(!WriteFdExactly(s, &msg.dent, sizeof(msg.dent)) ||
+               !WriteFdExactly(s, de->d_name, len)) {
                 closedir(d);
                 return -1;
             }
@@ -151,7 +148,7 @@
     msg.dent.size = 0;
     msg.dent.time = 0;
     msg.dent.namelen = 0;
-    return writex(s, &msg.dent, sizeof(msg.dent));
+    return WriteFdExactly(s, &msg.dent, sizeof(msg.dent)) ? 0 : -1;
 }
 
 static int fail_message(int s, const char *reason)
@@ -163,8 +160,8 @@
 
     msg.data.id = ID_FAIL;
     msg.data.size = htoll(len);
-    if(writex(s, &msg.data, sizeof(msg.data)) ||
-       writex(s, reason, len)) {
+    if(!WriteFdExactly(s, &msg.data, sizeof(msg.data)) ||
+       !WriteFdExactly(s, reason, len)) {
         return -1;
     } else {
         return 0;
@@ -217,7 +214,7 @@
     for(;;) {
         unsigned int len;
 
-        if(readx(s, &msg.data, sizeof(msg.data)))
+        if(!ReadFdExactly(s, &msg.data, sizeof(msg.data)))
             goto fail;
 
         if(msg.data.id != ID_DATA) {
@@ -233,12 +230,12 @@
             fail_message(s, "oversize data message");
             goto fail;
         }
-        if(readx(s, buffer, len))
+        if(!ReadFdExactly(s, buffer, len))
             goto fail;
 
         if(fd < 0)
             continue;
-        if(writex(fd, buffer, len)) {
+        if(!WriteFdExactly(fd, buffer, len)) {
             int saved_errno = errno;
             adb_close(fd);
             if (do_unlink) adb_unlink(path);
@@ -258,7 +255,7 @@
 
         msg.status.id = ID_OKAY;
         msg.status.msglen = 0;
-        if(writex(s, &msg.status, sizeof(msg.status)))
+        if(!WriteFdExactly(s, &msg.status, sizeof(msg.status)))
             return -1;
     }
     return 0;
@@ -270,14 +267,16 @@
     return -1;
 }
 
-#ifdef HAVE_SYMLINKS
+#if defined(_WIN32)
+extern int handle_send_link(int s, char *path, char *buffer) __attribute__((error("no symlinks on Windows")));
+#else
 static int handle_send_link(int s, char *path, char *buffer)
 {
     syncmsg msg;
     unsigned int len;
     int ret;
 
-    if(readx(s, &msg.data, sizeof(msg.data)))
+    if(!ReadFdExactly(s, &msg.data, sizeof(msg.data)))
         return -1;
 
     if(msg.data.id != ID_DATA) {
@@ -290,7 +289,7 @@
         fail_message(s, "oversize data message");
         return -1;
     }
-    if(readx(s, buffer, len))
+    if(!ReadFdExactly(s, buffer, len))
         return -1;
 
     ret = symlink(buffer, path);
@@ -306,13 +305,13 @@
         return -1;
     }
 
-    if(readx(s, &msg.data, sizeof(msg.data)))
+    if(!ReadFdExactly(s, &msg.data, sizeof(msg.data)))
         return -1;
 
     if(msg.data.id == ID_DONE) {
         msg.status.id = ID_OKAY;
         msg.status.msglen = 0;
-        if(writex(s, &msg.status, sizeof(msg.status)))
+        if(!WriteFdExactly(s, &msg.status, sizeof(msg.status)))
             return -1;
     } else {
         fail_message(s, "invalid data message: expected ID_DONE");
@@ -321,25 +320,20 @@
 
     return 0;
 }
-#endif /* HAVE_SYMLINKS */
+#endif
 
 static int do_send(int s, char *path, char *buffer)
 {
-    char *tmp;
     unsigned int mode;
-    int is_link, ret;
+    bool is_link = false;
     bool do_unlink;
 
-    tmp = strrchr(path,',');
+    char* tmp = strrchr(path,',');
     if(tmp) {
         *tmp = 0;
         errno = 0;
         mode = strtoul(tmp + 1, NULL, 0);
-#ifndef HAVE_SYMLINKS
-        is_link = 0;
-#else
         is_link = S_ISLNK((mode_t) mode);
-#endif
         mode &= 0777;
     }
     if(!tmp || errno) {
@@ -355,32 +349,26 @@
         }
     }
 
-#ifdef HAVE_SYMLINKS
-    if(is_link)
-        ret = handle_send_link(s, path, buffer);
-    else {
-#else
-    {
-#endif
-        uid_t uid = -1;
-        gid_t gid = -1;
-        uint64_t cap = 0;
-
-        /* copy user permission bits to "group" and "other" permissions */
-        mode |= ((mode >> 3) & 0070);
-        mode |= ((mode >> 3) & 0007);
-
-        tmp = path;
-        if(*tmp == '/') {
-            tmp++;
-        }
-        if (is_on_system(path) || is_on_vendor(path)) {
-            fs_config(tmp, 0, &uid, &gid, &mode, &cap);
-        }
-        ret = handle_send_file(s, path, uid, gid, mode, buffer, do_unlink);
+    if (is_link) {
+        return handle_send_link(s, path, buffer);
     }
 
-    return ret;
+    uid_t uid = -1;
+    gid_t gid = -1;
+    uint64_t cap = 0;
+
+    /* copy user permission bits to "group" and "other" permissions */
+    mode |= ((mode >> 3) & 0070);
+    mode |= ((mode >> 3) & 0007);
+
+    tmp = path;
+    if(*tmp == '/') {
+        tmp++;
+    }
+    if (should_use_fs_config(path)) {
+        fs_config(tmp, 0, NULL, &uid, &gid, &mode, &cap);
+    }
+    return handle_send_file(s, path, uid, gid, mode, buffer, do_unlink);
 }
 
 static int do_recv(int s, const char *path, char *buffer)
@@ -405,8 +393,8 @@
             return r;
         }
         msg.data.size = htoll(r);
-        if(writex(s, &msg.data, sizeof(msg.data)) ||
-           writex(s, buffer, r)) {
+        if(!WriteFdExactly(s, &msg.data, sizeof(msg.data)) ||
+           !WriteFdExactly(s, buffer, r)) {
             adb_close(fd);
             return -1;
         }
@@ -416,7 +404,7 @@
 
     msg.data.id = ID_DONE;
     msg.data.size = 0;
-    if(writex(s, &msg.data, sizeof(msg.data))) {
+    if(!WriteFdExactly(s, &msg.data, sizeof(msg.data))) {
         return -1;
     }
 
@@ -429,13 +417,13 @@
     char name[1025];
     unsigned namelen;
 
-    char *buffer = malloc(SYNC_DATA_MAX);
+    char *buffer = reinterpret_cast<char*>(malloc(SYNC_DATA_MAX));
     if(buffer == 0) goto fail;
 
     for(;;) {
         D("sync: waiting for command\n");
 
-        if(readx(fd, &msg.req, sizeof(msg.req))) {
+        if(!ReadFdExactly(fd, &msg.req, sizeof(msg.req))) {
             fail_message(fd, "command read failure");
             break;
         }
@@ -444,7 +432,7 @@
             fail_message(fd, "invalid namelen");
             break;
         }
-        if(readx(fd, name, namelen)) {
+        if(!ReadFdExactly(fd, name, namelen)) {
             fail_message(fd, "filename read failure");
             break;
         }
diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h
index 5dd2e80..344eb98 100644
--- a/adb/file_sync_service.h
+++ b/adb/file_sync_service.h
@@ -17,22 +17,12 @@
 #ifndef _FILE_SYNC_SERVICE_H_
 #define _FILE_SYNC_SERVICE_H_
 
-#ifdef HAVE_BIG_ENDIAN
-static inline unsigned __swap_uint32(unsigned x) 
-{
-    return (((x) & 0xFF000000) >> 24)
-        | (((x) & 0x00FF0000) >> 8)
-        | (((x) & 0x0000FF00) << 8)
-        | (((x) & 0x000000FF) << 24);
-}
-#define htoll(x) __swap_uint32(x)
-#define ltohl(x) __swap_uint32(x)
-#define MKID(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((a) << 24))
-#else
+#include <string>
+
 #define htoll(x) (x)
 #define ltohl(x) (x)
+
 #define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
-#endif
 
 #define ID_STAT MKID('S','T','A','T')
 #define ID_LIST MKID('L','I','S','T')
@@ -46,7 +36,7 @@
 #define ID_FAIL MKID('F','A','I','L')
 #define ID_QUIT MKID('Q','U','I','T')
 
-typedef union {
+union syncmsg {
     unsigned id;
     struct {
         unsigned id;
@@ -73,13 +63,13 @@
         unsigned id;
         unsigned msglen;
     } status;
-} syncmsg;
+} ;
 
 
 void file_sync_service(int fd, void *cookie);
 int do_sync_ls(const char *path);
 int do_sync_push(const char *lpath, const char *rpath, int show_progress);
-int do_sync_sync(const char *lpath, const char *rpath, int listonly);
+int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only);
 int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int pullTime);
 
 #define SYNC_DATA_MAX (64*1024)
diff --git a/adb/framebuffer_service.c b/adb/framebuffer_service.cpp
similarity index 89%
rename from adb/framebuffer_service.c
rename to adb/framebuffer_service.cpp
index 8cbe840..7baad8b 100644
--- a/adb/framebuffer_service.c
+++ b/adb/framebuffer_service.cpp
@@ -14,21 +14,23 @@
  * limitations under the License.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
 #include <errno.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include "fdevent.h"
-#include "adb.h"
-
+#include <fcntl.h>
 #include <linux/fb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "sysdeps.h"
+
+#include "adb.h"
+#include "adb_io.h"
+#include "fdevent.h"
 
 /* TODO:
 ** - sync with vsync to avoid tearing
@@ -60,28 +62,30 @@
     int fd_screencap;
     int w, h, f;
     int fds[2];
+    pid_t pid;
 
     if (pipe2(fds, O_CLOEXEC) < 0) goto pipefail;
 
-    pid_t pid = fork();
+    pid = fork();
     if (pid < 0) goto done;
 
     if (pid == 0) {
         dup2(fds[1], STDOUT_FILENO);
-        close(fds[0]);
-        close(fds[1]);
+        adb_close(fds[0]);
+        adb_close(fds[1]);
         const char* command = "screencap";
         const char *args[2] = {command, NULL};
         execvp(command, (char**)args);
         exit(1);
     }
 
+    adb_close(fds[1]);
     fd_screencap = fds[0];
 
     /* read w, h & format */
-    if(readx(fd_screencap, &w, 4)) goto done;
-    if(readx(fd_screencap, &h, 4)) goto done;
-    if(readx(fd_screencap, &f, 4)) goto done;
+    if(!ReadFdExactly(fd_screencap, &w, 4)) goto done;
+    if(!ReadFdExactly(fd_screencap, &h, 4)) goto done;
+    if(!ReadFdExactly(fd_screencap, &f, 4)) goto done;
 
     fbinfo.version = DDMS_RAWIMAGE_VERSION;
     /* see hardware/hardware.h */
@@ -161,22 +165,21 @@
     }
 
     /* write header */
-    if(writex(fd, &fbinfo, sizeof(fbinfo))) goto done;
+    if(!WriteFdExactly(fd, &fbinfo, sizeof(fbinfo))) goto done;
 
     /* write data */
     for(i = 0; i < fbinfo.size; i += bsize) {
       bsize = sizeof(buf);
       if (i + bsize > fbinfo.size)
         bsize = fbinfo.size - i;
-      if(readx(fd_screencap, buf, bsize)) goto done;
-      if(writex(fd, buf, bsize)) goto done;
+      if(!ReadFdExactly(fd_screencap, buf, bsize)) goto done;
+      if(!WriteFdExactly(fd, buf, bsize)) goto done;
     }
 
 done:
-    TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0));
+    adb_close(fds[0]);
 
-    close(fds[0]);
-    close(fds[1]);
+    TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0));
 pipefail:
-    close(fd);
+    adb_close(fd);
 }
diff --git a/adb/get_my_path_darwin.c b/adb/get_my_path_darwin.cpp
similarity index 97%
rename from adb/get_my_path_darwin.c
rename to adb/get_my_path_darwin.cpp
index ff1396c..b0c962e 100644
--- a/adb/get_my_path_darwin.c
+++ b/adb/get_my_path_darwin.cpp
@@ -17,6 +17,8 @@
 #import <Carbon/Carbon.h>
 #include <unistd.h>
 
+#include "adb.h"
+
 void get_my_path(char *s, size_t maxLen)
 {
     CFBundleRef mainBundle = CFBundleGetMainBundle();
diff --git a/adb/get_my_path_freebsd.c b/adb/get_my_path_freebsd.c
deleted file mode 100644
index b06ec66..0000000
--- a/adb/get_my_path_freebsd.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2009 bsdroid project
- *               Alexey Tarasov <tarasov@dodologics.com>
- *
- * 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 <sys/types.h>
-#include <unistd.h>
-#include <limits.h>
-#include <stdio.h>
-
-void
-get_my_path(char *exe, size_t maxLen)
-{
-    char proc[64];
-
-    snprintf(proc, sizeof(proc), "/proc/%d/file", getpid());
-
-    int err = readlink(proc, exe, maxLen - 1);
-
-    exe[err > 0 ? err : 0] = '\0';
-}
-
diff --git a/adb/get_my_path_linux.c b/adb/get_my_path_linux.cpp
similarity index 97%
rename from adb/get_my_path_linux.c
rename to adb/get_my_path_linux.cpp
index 179c3dd..11c0b21 100644
--- a/adb/get_my_path_linux.c
+++ b/adb/get_my_path_linux.cpp
@@ -14,10 +14,12 @@
  * limitations under the License.
  */
 
-#include <sys/types.h>
-#include <unistd.h>
 #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)
 {
diff --git a/adb/get_my_path_windows.c b/adb/get_my_path_windows.cpp
similarity index 97%
rename from adb/get_my_path_windows.c
rename to adb/get_my_path_windows.cpp
index ddf2816..9d23e1c 100644
--- a/adb/get_my_path_windows.c
+++ b/adb/get_my_path_windows.cpp
@@ -14,10 +14,12 @@
  * limitations under the License.
  */
 
-#include <limits.h>
 #include <assert.h>
+#include <limits.h>
 #include <windows.h>
 
+#include "adb.h"
+
 void get_my_path(char *exe, size_t maxLen)
 {
     char  *r;
diff --git a/adb/jdwp_service.c b/adb/jdwp_service.cpp
similarity index 94%
rename from adb/jdwp_service.c
rename to adb/jdwp_service.cpp
index cd62b55..c0f7ec2 100644
--- a/adb/jdwp_service.c
+++ b/adb/jdwp_service.cpp
@@ -1,12 +1,32 @@
+/*
+ * 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.
+ */
+
 /* implement the "debug-ports" and "track-debug-ports" device services */
+
+#define TRACE_TAG TRACE_JDWP
+
 #include "sysdeps.h"
-#define  TRACE_TAG   TRACE_JDWP
-#include "adb.h"
+
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 
+#include "adb.h"
+
 /* here's how these things work.
 
    when adbd starts, it creates a unix server socket
@@ -101,7 +121,6 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 
-typedef struct JdwpProcess  JdwpProcess;
 struct JdwpProcess {
     JdwpProcess*  next;
     JdwpProcess*  prev;
@@ -194,7 +213,8 @@
 static JdwpProcess*
 jdwp_process_alloc( int  socket )
 {
-    JdwpProcess*  proc = calloc(1,sizeof(*proc));
+    JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(
+        calloc(1, sizeof(*proc)));
 
     if (proc == NULL) {
         D("not enough memory to create new JDWP process\n");
@@ -234,7 +254,7 @@
 static void
 jdwp_process_event( int  socket, unsigned  events, void*  _proc )
 {
-    JdwpProcess*  proc = _proc;
+    JdwpProcess*  proc = reinterpret_cast<JdwpProcess*>(_proc);
 
     if (events & FDE_READ) {
         if (proc->pid < 0) {
@@ -415,6 +435,7 @@
               __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)
@@ -433,11 +454,10 @@
 #define  JDWP_CONTROL_NAME      "\0jdwp-control"
 #define  JDWP_CONTROL_NAME_LEN  (sizeof(JDWP_CONTROL_NAME)-1)
 
-typedef struct {
+struct JdwpControl {
     int       listen_socket;
     fdevent*  fde;
-
-} JdwpControl;
+};
 
 
 static void
@@ -548,10 +568,10 @@
  ** this simply returns the list of known JDWP process pids
  **/
 
-typedef struct {
+struct JdwpSocket {
     asocket  socket;
     int      pass;
-} JdwpSocket;
+};
 
 static void
 jdwp_socket_close( asocket*  s )
@@ -600,7 +620,7 @@
 asocket*
 create_jdwp_service_socket( void )
 {
-    JdwpSocket*  s = calloc(sizeof(*s),1);
+    JdwpSocket* s = reinterpret_cast<JdwpSocket*>(calloc(sizeof(*s), 1));
 
     if (s == NULL)
         return NULL;
@@ -620,8 +640,6 @@
  ** to the client...
  **/
 
-typedef struct JdwpTracker  JdwpTracker;
-
 struct JdwpTracker {
     asocket       socket;
     JdwpTracker*  next;
@@ -695,7 +713,7 @@
 asocket*
 create_jdwp_tracker_service_socket( void )
 {
-    JdwpTracker*  t = calloc(sizeof(*t),1);
+    JdwpTracker* t = reinterpret_cast<JdwpTracker*>(calloc(sizeof(*t), 1));
 
     if (t == NULL)
         return NULL;
@@ -732,4 +750,3 @@
 }
 
 #endif /* !ADB_HOST */
-
diff --git a/adb/mutex_list.h b/adb/mutex_list.h
index ff72751..15e383c 100644
--- a/adb/mutex_list.h
+++ b/adb/mutex_list.h
@@ -6,7 +6,6 @@
 #ifndef ADB_MUTEX
 #error ADB_MUTEX not defined when including this file
 #endif
-ADB_MUTEX(socket_list_lock)
 ADB_MUTEX(transport_lock)
 #if ADB_HOST
 ADB_MUTEX(local_transports_lock)
diff --git a/adb/qemu_tracing.cpp b/adb/qemu_tracing.cpp
new file mode 100644
index 0000000..f31eae8
--- /dev/null
+++ b/adb/qemu_tracing.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+/*
+ * Implements ADB tracing inside the emulator.
+ */
+
+#include <stdarg.h>
+
+#include "sysdeps.h"
+#include "qemu_tracing.h"
+
+/*
+ * 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.
+ */
+
+#undef open
+#undef write
+#define open    adb_open
+#define write   adb_write
+#include <hardware/qemu_pipe.h>
+#undef open
+#undef write
+#define open    ___xxx_open
+#define write   ___xxx_write
+
+/* A handle to adb-debug qemud service in the emulator. */
+int   adb_debug_qemu = -1;
+
+/* Initializes connection with the adb-debug qemud service in the emulator. */
+int adb_qemu_trace_init(void)
+{
+    char con_name[32];
+
+    if (adb_debug_qemu >= 0) {
+        return 0;
+    }
+
+    /* adb debugging QEMUD service connection request. */
+    snprintf(con_name, sizeof(con_name), "qemud:adb-debug");
+    adb_debug_qemu = qemu_pipe_open(con_name);
+    return (adb_debug_qemu >= 0) ? 0 : -1;
+}
+
+void adb_qemu_trace(const char* fmt, ...)
+{
+    va_list args;
+    va_start(args, fmt);
+    char msg[1024];
+
+    if (adb_debug_qemu >= 0) {
+        vsnprintf(msg, sizeof(msg), fmt, args);
+        adb_write(adb_debug_qemu, msg, strlen(msg));
+    }
+}
diff --git a/adb/usb_vendors.h b/adb/qemu_tracing.h
similarity index 62%
copy from adb/usb_vendors.h
copy to adb/qemu_tracing.h
index cee23a1..ff42d4f 100644
--- a/adb/usb_vendors.h
+++ b/adb/qemu_tracing.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 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.
@@ -14,12 +14,15 @@
  * limitations under the License.
  */
 
-#ifndef __USB_VENDORS_H
-#define __USB_VENDORS_H
+/*
+ * Implements ADB tracing inside the emulator.
+ */
 
-extern int vendorIds[];
-extern unsigned  vendorIdCount;
+#ifndef __QEMU_TRACING_H
+#define __QEMU_TRACING_H
 
-void usb_vendors_init(void);
+/* Initializes connection with the adb-debug qemud service in the emulator. */
+int adb_qemu_trace_init(void);
+void adb_qemu_trace(const char* fmt, ...);
 
-#endif
+#endif /* __QEMU_TRACING_H */
diff --git a/adb/remount_service.c b/adb/remount_service.c
deleted file mode 100644
index 36367a7..0000000
--- a/adb/remount_service.c
+++ /dev/null
@@ -1,170 +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 "sysdeps.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mount.h>
-#include <unistd.h>
-
-#include "cutils/properties.h"
-
-#define  TRACE_TAG  TRACE_ADB
-#include "adb.h"
-
-
-static int system_ro = 1;
-static int vendor_ro = 1;
-
-/* Returns the device used to mount a directory in /proc/mounts */
-static char *find_mount(const char *dir)
-{
-    int fd;
-    int res;
-    char *token = NULL;
-    const char delims[] = "\n";
-    char buf[4096];
-
-    fd = unix_open("/proc/mounts", O_RDONLY | O_CLOEXEC);
-    if (fd < 0)
-        return NULL;
-
-    buf[sizeof(buf) - 1] = '\0';
-    adb_read(fd, buf, sizeof(buf) - 1);
-    adb_close(fd);
-
-    token = strtok(buf, delims);
-
-    while (token) {
-        char mount_dev[256];
-        char mount_dir[256];
-        int mount_freq;
-        int mount_passno;
-
-        res = sscanf(token, "%255s %255s %*s %*s %d %d\n",
-                     mount_dev, mount_dir, &mount_freq, &mount_passno);
-        mount_dev[255] = 0;
-        mount_dir[255] = 0;
-        if (res == 4 && (strcmp(dir, mount_dir) == 0))
-            return strdup(mount_dev);
-
-        token = strtok(NULL, delims);
-    }
-    return NULL;
-}
-
-static int hasVendorPartition()
-{
-    struct stat info;
-    if (!lstat("/vendor", &info))
-        if ((info.st_mode & S_IFMT) == S_IFDIR)
-          return true;
-    return false;
-}
-
-/* Init mounts /system as read only, remount to enable writes. */
-static int remount(const char* dir, int* dir_ro)
-{
-    char *dev;
-    int fd;
-    int OFF = 0;
-
-    if (dir_ro == 0) {
-        return 0;
-    }
-
-    dev = find_mount(dir);
-
-    if (!dev)
-        return -1;
-
-    fd = unix_open(dev, O_RDONLY | O_CLOEXEC);
-    if (fd < 0)
-        return -1;
-
-    ioctl(fd, BLKROSET, &OFF);
-    adb_close(fd);
-
-    *dir_ro = mount(dev, dir, "none", MS_REMOUNT, NULL);
-
-    free(dev);
-
-    return *dir_ro;
-}
-
-static void write_string(int fd, const char* str)
-{
-    writex(fd, str, strlen(str));
-}
-
-void remount_service(int fd, void *cookie)
-{
-    char buffer[200];
-    char prop_buf[PROPERTY_VALUE_MAX];
-
-    bool system_verified = false, vendor_verified = false;
-    property_get("partition.system.verified", prop_buf, "0");
-    if (!strcmp(prop_buf, "1")) {
-        system_verified = true;
-    }
-
-    property_get("partition.vendor.verified", prop_buf, "0");
-    if (!strcmp(prop_buf, "1")) {
-        vendor_verified = true;
-    }
-
-    if (system_verified || vendor_verified) {
-        // Allow remount but warn of likely bad effects
-        bool both = system_verified && vendor_verified;
-        snprintf(buffer, sizeof(buffer),
-                 "dm_verity is enabled on the %s%s%s partition%s.\n",
-                 system_verified ? "system" : "",
-                 both ? " and " : "",
-                 vendor_verified ? "vendor" : "",
-                 both ? "s" : "");
-        write_string(fd, buffer);
-        snprintf(buffer, sizeof(buffer),
-                 "Use \"adb disable-verity\" to disable verity.\n"
-                 "If you do not, remount may succeed, however, you will still "
-                 "not be able to write to these volumes.\n");
-        write_string(fd, buffer);
-    }
-
-    if (remount("/system", &system_ro)) {
-        snprintf(buffer, sizeof(buffer), "remount of system failed: %s\n",strerror(errno));
-        write_string(fd, buffer);
-    }
-
-    if (hasVendorPartition()) {
-        if (remount("/vendor", &vendor_ro)) {
-            snprintf(buffer, sizeof(buffer), "remount of vendor failed: %s\n",strerror(errno));
-            write_string(fd, buffer);
-        }
-    }
-
-    if (!system_ro && (!vendor_ro || !hasVendorPartition()))
-        write_string(fd, "remount succeeded\n");
-    else {
-        write_string(fd, "remount failed\n");
-    }
-
-    adb_close(fd);
-}
-
diff --git a/adb/remount_service.cpp b/adb/remount_service.cpp
new file mode 100644
index 0000000..7a3b89a
--- /dev/null
+++ b/adb/remount_service.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+#define TRACE_TAG TRACE_ADB
+
+#include "sysdeps.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <mntent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "adb.h"
+#include "adb_io.h"
+#include "adb_utils.h"
+#include "cutils/properties.h"
+
+// Returns the device used to mount a directory in /proc/mounts.
+static std::string find_mount(const char* dir) {
+    std::unique_ptr<FILE, int(*)(FILE*)> fp(setmntent("/proc/mounts", "r"), endmntent);
+    if (!fp) {
+        return "";
+    }
+
+    mntent* e;
+    while ((e = getmntent(fp.get())) != nullptr) {
+        if (strcmp(dir, e->mnt_dir) == 0) {
+            return e->mnt_fsname;
+        }
+    }
+    return "";
+}
+
+bool make_block_device_writable(const std::string& dev) {
+    int fd = unix_open(dev.c_str(), O_RDONLY | O_CLOEXEC);
+    if (fd == -1) {
+        return false;
+    }
+
+    int OFF = 0;
+    bool result = (ioctl(fd, BLKROSET, &OFF) != -1);
+    adb_close(fd);
+    return result;
+}
+
+static bool remount_partition(int fd, const char* dir) {
+    if (!directory_exists(dir)) {
+        return true;
+    }
+    std::string dev = find_mount(dir);
+    if (dev.empty()) {
+        return true;
+    }
+    if (!make_block_device_writable(dev)) {
+        WriteFdFmt(fd, "remount of %s failed; couldn't make block device %s writable: %s\n",
+                   dir, dev.c_str(), strerror(errno));
+        return false;
+    }
+    if (mount(dev.c_str(), dir, "none", MS_REMOUNT, nullptr) == -1) {
+        WriteFdFmt(fd, "remount of %s failed: %s\n", dir, strerror(errno));
+        return false;
+    }
+    return true;
+}
+
+void remount_service(int fd, void* cookie) {
+    if (getuid() != 0) {
+        WriteFdExactly(fd, "Not running as root. Try \"adb root\" first.\n");
+        adb_close(fd);
+        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);
+
+    if (system_verified || vendor_verified) {
+        // Allow remount but warn of likely bad effects
+        bool both = system_verified && vendor_verified;
+        WriteFdFmt(fd,
+                   "dm_verity is enabled on the %s%s%s partition%s.\n",
+                   system_verified ? "system" : "",
+                   both ? " and " : "",
+                   vendor_verified ? "vendor" : "",
+                   both ? "s" : "");
+        WriteFdExactly(fd,
+                       "Use \"adb disable-verity\" to disable verity.\n"
+                       "If you do not, remount may succeed, however, you will still "
+                       "not be able to write to these volumes.\n");
+    }
+
+    bool success = true;
+    success &= remount_partition(fd, "/system");
+    success &= remount_partition(fd, "/vendor");
+    success &= remount_partition(fd, "/oem");
+
+    WriteFdExactly(fd, success ? "remount succeeded\n" : "remount failed\n");
+
+    adb_close(fd);
+}
diff --git a/adb/usb_vendors.h b/adb/remount_service.h
similarity index 72%
copy from adb/usb_vendors.h
copy to adb/remount_service.h
index cee23a1..7bda1be 100644
--- a/adb/usb_vendors.h
+++ b/adb/remount_service.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 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.
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-#ifndef __USB_VENDORS_H
-#define __USB_VENDORS_H
+#ifndef _REMOUNT_SERVICE_H_
+#define _REMOUNT_SERVICE_H_
 
-extern int vendorIds[];
-extern unsigned  vendorIdCount;
+#include <string>
 
-void usb_vendors_init(void);
+bool make_block_device_writable(const std::string&);
+void remount_service(int, void*);
 
 #endif
diff --git a/adb/services.c b/adb/services.cpp
similarity index 62%
rename from adb/services.c
rename to adb/services.cpp
index 21b08dc..1847447 100644
--- a/adb/services.c
+++ b/adb/services.cpp
@@ -14,31 +14,37 @@
  * limitations under the License.
  */
 
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
+#define TRACE_TAG TRACE_SERVICES
 
 #include "sysdeps.h"
 
-#define  TRACE_TAG  TRACE_SERVICES
-#include "adb.h"
-#include "file_sync_service.h"
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
-#if ADB_HOST
-#  ifndef HAVE_WINSOCK
-#    include <netinet/in.h>
-#    include <netdb.h>
-#    include <sys/ioctl.h>
-#  endif
-#else
-#  include <cutils/android_reboot.h>
-#  include <cutils/properties.h>
+#ifndef _WIN32
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
 #endif
 
-typedef struct stinfo stinfo;
+#include <base/file.h>
+#include <base/stringprintf.h>
+#include <base/strings.h>
+
+#if !ADB_HOST
+#include "cutils/android_reboot.h"
+#include "cutils/properties.h"
+#endif
+
+#include "adb.h"
+#include "adb_io.h"
+#include "file_sync_service.h"
+#include "remount_service.h"
+#include "transport.h"
 
 struct stinfo {
     void (*func)(int fd, void *cookie);
@@ -49,7 +55,7 @@
 
 void *service_bootstrap_func(void *x)
 {
-    stinfo *sti = x;
+    stinfo* sti = reinterpret_cast<stinfo*>(x);
     sti->func(sti->fd, sti->cookie);
     free(sti);
     return 0;
@@ -57,96 +63,129 @@
 
 #if !ADB_HOST
 
-void restart_root_service(int fd, void *cookie)
-{
-    char buf[100];
-    char value[PROPERTY_VALUE_MAX];
-
+void restart_root_service(int fd, void *cookie) {
     if (getuid() == 0) {
-        snprintf(buf, sizeof(buf), "adbd is already running as root\n");
-        writex(fd, buf, strlen(buf));
+        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) {
-            snprintf(buf, sizeof(buf), "adbd cannot run as root in production builds\n");
-            writex(fd, buf, strlen(buf));
+            WriteFdExactly(fd, "adbd cannot run as root in production builds\n");
             adb_close(fd);
             return;
         }
 
         property_set("service.adb.root", "1");
-        snprintf(buf, sizeof(buf), "restarting adbd as root\n");
-        writex(fd, buf, strlen(buf));
+        WriteFdExactly(fd, "restarting adbd as root\n");
         adb_close(fd);
     }
 }
 
-void restart_tcp_service(int fd, void *cookie)
-{
-    char buf[100];
-    char value[PROPERTY_VALUE_MAX];
-    int port = (int) (uintptr_t) cookie;
+void restart_unroot_service(int fd, void *cookie) {
+    if (getuid() != 0) {
+        WriteFdExactly(fd, "adbd not running as root\n");
+        adb_close(fd);
+    } else {
+        property_set("service.adb.root", "0");
+        WriteFdExactly(fd, "restarting adbd as non root\n");
+        adb_close(fd);
+    }
+}
 
+void restart_tcp_service(int fd, void *cookie) {
+    int port = (int) (uintptr_t) cookie;
     if (port <= 0) {
-        snprintf(buf, sizeof(buf), "invalid port\n");
-        writex(fd, buf, strlen(buf));
+        WriteFdFmt(fd, "invalid port %d\n", port);
         adb_close(fd);
         return;
     }
 
+    char value[PROPERTY_VALUE_MAX];
     snprintf(value, sizeof(value), "%d", port);
     property_set("service.adb.tcp.port", value);
-    snprintf(buf, sizeof(buf), "restarting in TCP mode port: %d\n", port);
-    writex(fd, buf, strlen(buf));
+    WriteFdFmt(fd, "restarting in TCP mode port: %d\n", port);
     adb_close(fd);
 }
 
-void restart_usb_service(int fd, void *cookie)
-{
-    char buf[100];
-
+void restart_usb_service(int fd, void *cookie) {
     property_set("service.adb.tcp.port", "0");
-    snprintf(buf, sizeof(buf), "restarting in USB mode\n");
-    writex(fd, buf, strlen(buf));
+    WriteFdExactly(fd, "restarting in USB mode\n");
     adb_close(fd);
 }
 
-void reboot_service(int fd, void *arg)
-{
-    char buf[100];
-    char property_val[PROPERTY_VALUE_MAX];
-    int ret;
+static bool reboot_service_impl(int fd, const char* arg) {
+    const char* reboot_arg = arg;
+    bool auto_reboot = false;
+
+    if (strcmp(reboot_arg, "sideload-auto-reboot") == 0) {
+        auto_reboot = true;
+        reboot_arg = "sideload";
+    }
+
+    // It reboots into sideload mode by setting "--sideload" or "--sideload_auto_reboot"
+    // in the command file.
+    if (strcmp(reboot_arg, "sideload") == 0) {
+        if (getuid() != 0) {
+            WriteFdExactly(fd, "'adb root' is required for 'adb reboot sideload'.\n");
+            return false;
+        }
+
+        const char* const recovery_dir = "/cache/recovery";
+        const char* const command_file = "/cache/recovery/command";
+        // Ensure /cache/recovery exists.
+        if (adb_mkdir(recovery_dir, 0770) == -1 && errno != EEXIST) {
+            D("Failed to create directory '%s': %s\n", recovery_dir, strerror(errno));
+            return false;
+        }
+
+        bool write_status = android::base::WriteStringToFile(
+                auto_reboot ? "--sideload_auto_reboot" : "--sideload", command_file);
+        if (!write_status) {
+            return false;
+        }
+
+        reboot_arg = "recovery";
+    }
 
     sync();
 
-    ret = snprintf(property_val, sizeof(property_val), "reboot,%s", (char *) arg);
-    if (ret >= (int) sizeof(property_val)) {
-        snprintf(buf, sizeof(buf), "reboot string too long. length=%d\n", ret);
-        writex(fd, buf, strlen(buf));
-        goto cleanup;
+    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) {
-        snprintf(buf, sizeof(buf), "reboot failed: %d\n", ret);
-        writex(fd, buf, strlen(buf));
-        goto cleanup;
+        WriteFdFmt(fd, "reboot failed: %d\n", ret);
+        return false;
     }
-    // Don't return early. Give the reboot command time to take effect
-    // to avoid messing up scripts which do "adb reboot && adb wait-for-device"
-    while(1) { pause(); }
-cleanup:
+
+    return true;
+}
+
+void reboot_service(int fd, void* arg)
+{
+    if (reboot_service_impl(fd, static_cast<const char*>(arg))) {
+        // Don't return early. Give the reboot command time to take effect
+        // to avoid messing up scripts which do "adb reboot && adb wait-for-device"
+        while (true) {
+            pause();
+        }
+    }
+
     free(arg);
     adb_close(fd);
 }
 
 void reverse_service(int fd, void* arg)
 {
-    const char* command = arg;
+    const char* command = reinterpret_cast<const char*>(arg);
 
     if (handle_forward_request(command, kTransportAny, NULL, fd) < 0) {
-        sendfailmsg(fd, "not a reverse forwarding command");
+        SendFail(fd, "not a reverse forwarding command");
     }
     free(arg);
     adb_close(fd);
@@ -156,22 +195,23 @@
 
 static int create_service_thread(void (*func)(int, void *), void *cookie)
 {
-    stinfo *sti;
-    adb_thread_t t;
     int s[2];
-
-    if(adb_socketpair(s)) {
+    if (adb_socketpair(s)) {
         printf("cannot create service socket pair\n");
         return -1;
     }
+    D("socketpair: (%d,%d)", s[0], s[1]);
 
-    sti = malloc(sizeof(stinfo));
-    if(sti == 0) fatal("cannot allocate stinfo");
+    stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo)));
+    if (sti == nullptr) {
+        fatal("cannot allocate stinfo");
+    }
     sti->func = func;
     sti->cookie = cookie;
     sti->fd = s[1];
 
-    if(adb_thread_create( &t, service_bootstrap_func, sti)){
+    adb_thread_t t;
+    if (adb_thread_create(&t, service_bootstrap_func, sti)) {
         free(sti);
         adb_close(s[0]);
         adb_close(s[1]);
@@ -202,10 +242,10 @@
 static int create_subproc_pty(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
 {
     D("create_subproc_pty(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
-#ifdef HAVE_WIN32_PROC
+#if defined(_WIN32)
     fprintf(stderr, "error: create_subproc_pty not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
     return -1;
-#else /* !HAVE_WIN32_PROC */
+#else
     int ptm;
 
     ptm = unix_open("/dev/ptmx", O_RDWR | O_CLOEXEC); // | O_NOCTTY);
@@ -251,23 +291,24 @@
     } else {
         return ptm;
     }
-#endif /* !HAVE_WIN32_PROC */
+#endif /* !defined(_WIN32) */
 }
 
 static int create_subproc_raw(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
 {
     D("create_subproc_raw(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
-#ifdef HAVE_WIN32_PROC
+#if defined(_WIN32)
     fprintf(stderr, "error: create_subproc_raw not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
     return -1;
-#else /* !HAVE_WIN32_PROC */
+#else
 
     // 0 is parent socket, 1 is child socket
     int sv[2];
-    if (unix_socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) {
+    if (adb_socketpair(sv) < 0) {
         printf("[ cannot create socket pair - %s ]\n", strerror(errno));
         return -1;
     }
+    D("socketpair: (%d,%d)", sv[0], sv[1]);
 
     *pid = fork();
     if (*pid < 0) {
@@ -295,7 +336,7 @@
         adb_close(sv[1]);
         return sv[0];
     }
-#endif /* !HAVE_WIN32_PROC */
+#endif /* !defined(_WIN32) */
 }
 #endif  /* !ABD_HOST */
 
@@ -311,7 +352,7 @@
     pid_t pid = (pid_t) (uintptr_t) cookie;
 
     D("entered. fd=%d of pid=%d\n", fd, pid);
-    for (;;) {
+    while (true) {
         int status;
         pid_t p = waitpid(pid, &status, 0);
         if (p == pid) {
@@ -331,7 +372,7 @@
     D("shell exited fd=%d of pid=%d err=%d\n", fd, pid, errno);
     if (SHELL_EXIT_NOTIFY_FD >=0) {
       int res;
-      res = writex(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd));
+      res = WriteFdExactly(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd)) ? 0 : -1;
       D("notified shell exit via fd=%d for pid=%d res=%d errno=%d\n",
         SHELL_EXIT_NOTIFY_FD, pid, res, errno);
     }
@@ -339,7 +380,6 @@
 
 static int create_subproc_thread(const char *name, const subproc_mode mode)
 {
-    stinfo *sti;
     adb_thread_t t;
     int ret_fd;
     pid_t pid = -1;
@@ -364,7 +404,7 @@
     }
     D("create_subproc ret_fd=%d pid=%d\n", ret_fd, pid);
 
-    sti = malloc(sizeof(stinfo));
+    stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo)));
     if(sti == 0) fatal("cannot allocate stinfo");
     sti->func = subproc_waiter_service;
     sti->cookie = (void*) (uintptr_t) pid;
@@ -435,25 +475,16 @@
         ret = create_service_thread(reboot_service, arg);
     } else if(!strncmp(name, "root:", 5)) {
         ret = create_service_thread(restart_root_service, NULL);
+    } else if(!strncmp(name, "unroot:", 7)) {
+        ret = create_service_thread(restart_unroot_service, NULL);
     } else if(!strncmp(name, "backup:", 7)) {
-        char* arg = strdup(name + 7);
-        if (arg == NULL) return -1;
-        char* c = arg;
-        for (; *c != '\0'; c++) {
-            if (*c == ':')
-                *c = ' ';
-        }
-        char* cmd;
-        if (asprintf(&cmd, "/system/bin/bu backup %s", arg) != -1) {
-            ret = create_subproc_thread(cmd, SUBPROC_RAW);
-            free(cmd);
-        }
-        free(arg);
+        ret = create_subproc_thread(android::base::StringPrintf("/system/bin/bu backup %s",
+                                                                (name + 7)).c_str(), SUBPROC_RAW);
     } else if(!strncmp(name, "restore:", 8)) {
         ret = create_subproc_thread("/system/bin/bu restore", SUBPROC_RAW);
     } else if(!strncmp(name, "tcpip:", 6)) {
         int port;
-        if (sscanf(name + 6, "%d", &port) == 0) {
+        if (sscanf(name + 6, "%d", &port) != 1) {
             port = 0;
         }
         ret = create_service_thread(restart_tcp_service, (void *) (uintptr_t) port);
@@ -470,7 +501,9 @@
             }
         }
     } else if(!strncmp(name, "disable-verity:", 15)) {
-        ret = create_service_thread(disable_verity_service, NULL);
+        ret = create_service_thread(set_verity_enabled_state_service, (void*)0);
+    } else if(!strncmp(name, "enable-verity:", 15)) {
+        ret = create_service_thread(set_verity_enabled_state_service, (void*)1);
 #endif
     }
     if (ret >= 0) {
@@ -488,16 +521,16 @@
 
 static void wait_for_state(int fd, void* cookie)
 {
-    struct state_info* sinfo = cookie;
-    char* err = "unknown error";
+    state_info* sinfo = reinterpret_cast<state_info*>(cookie);
 
     D("wait_for_state %d\n", sinfo->state);
 
-    atransport *t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &err);
-    if(t != 0) {
-        writex(fd, "OKAY", 4);
+    std::string error_msg = "unknown error";
+    atransport* t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &error_msg);
+    if (t != 0) {
+        SendOkay(fd);
     } else {
-        sendfailmsg(fd, err);
+        SendFail(fd, error_msg);
     }
 
     if (sinfo->serial)
@@ -507,35 +540,31 @@
     D("wait_for_state is done\n");
 }
 
-static void connect_device(char* host, char* buffer, int buffer_size)
-{
-    int port, fd;
-    char* portstr = strchr(host, ':');
-    char hostbuf[100];
-    char serial[100];
-    int ret;
-
-    strncpy(hostbuf, host, sizeof(hostbuf) - 1);
-    if (portstr) {
-        if (portstr - host >= (ptrdiff_t)sizeof(hostbuf)) {
-            snprintf(buffer, buffer_size, "bad host name %s", host);
-            return;
-        }
-        // zero terminate the host at the point we found the colon
-        hostbuf[portstr - host] = 0;
-        if (sscanf(portstr + 1, "%d", &port) == 0) {
-            snprintf(buffer, buffer_size, "bad port number %s", portstr);
-            return;
-        }
-    } else {
-        port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
+static void connect_device(const std::string& host, std::string* response) {
+    if (host.empty()) {
+        *response = "empty host name";
+        return;
     }
 
-    snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port);
+    std::vector<std::string> pieces = android::base::Split(host, ":");
+    const std::string& hostname = pieces[0];
 
-    fd = socket_network_client_timeout(hostbuf, port, SOCK_STREAM, 10);
+    int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
+    if (pieces.size() > 1) {
+        if (sscanf(pieces[1].c_str(), "%d", &port) != 1) {
+            *response = android::base::StringPrintf("bad port number %s", pieces[1].c_str());
+            return;
+        }
+    }
+
+    // This may look like we're putting 'host' back together,
+    // but we're actually inserting the default port if necessary.
+    std::string serial = android::base::StringPrintf("%s:%d", hostname.c_str(), port);
+
+    int fd = socket_network_client_timeout(hostname.c_str(), port, SOCK_STREAM, 10);
     if (fd < 0) {
-        snprintf(buffer, buffer_size, "unable to connect to %s:%d", host, port);
+        *response = android::base::StringPrintf("unable to connect to %s:%d",
+                                                hostname.c_str(), port);
         return;
     }
 
@@ -543,85 +572,74 @@
     close_on_exec(fd);
     disable_tcp_nagle(fd);
 
-    ret = register_socket_transport(fd, serial, port, 0);
+    int ret = register_socket_transport(fd, serial.c_str(), port, 0);
     if (ret < 0) {
         adb_close(fd);
-        snprintf(buffer, buffer_size, "already connected to %s", serial);
+        *response = android::base::StringPrintf("already connected to %s", serial.c_str());
     } else {
-        snprintf(buffer, buffer_size, "connected to %s", serial);
+        *response = android::base::StringPrintf("connected to %s", serial.c_str());
     }
 }
 
-void connect_emulator(char* port_spec, char* buffer, int buffer_size)
-{
-    char* port_separator = strchr(port_spec, ',');
-    if (!port_separator) {
-        snprintf(buffer, buffer_size,
-                "unable to parse '%s' as <console port>,<adb port>",
-                port_spec);
+void connect_emulator(const std::string& port_spec, std::string* response) {
+    std::vector<std::string> pieces = android::base::Split(port_spec, ",");
+    if (pieces.size() != 2) {
+        *response = android::base::StringPrintf("unable to parse '%s' as <console port>,<adb port>",
+                                                port_spec.c_str());
         return;
     }
 
-    // Zero-terminate console port and make port_separator point to 2nd port.
-    *port_separator++ = 0;
-    int console_port = strtol(port_spec, NULL, 0);
-    int adb_port = strtol(port_separator, NULL, 0);
-    if (!(console_port > 0 && adb_port > 0)) {
-        *(port_separator - 1) = ',';
-        snprintf(buffer, buffer_size,
-                "Invalid port numbers: Expected positive numbers, got '%s'",
-                port_spec);
+    int console_port = strtol(pieces[0].c_str(), NULL, 0);
+    int adb_port = strtol(pieces[1].c_str(), NULL, 0);
+    if (console_port <= 0 || adb_port <= 0) {
+        *response = android::base::StringPrintf("Invalid port numbers: %s", port_spec.c_str());
         return;
     }
 
-    /* Check if the emulator is already known.
-     * Note: There's a small but harmless race condition here: An emulator not
-     * present just yet could be registered by another invocation right
-     * after doing this check here. However, local_connect protects
-     * against double-registration too. From here, a better error message
-     * can be produced. In the case of the race condition, the very specific
-     * error message won't be shown, but the data doesn't get corrupted. */
+    // Check if the emulator is already known.
+    // Note: There's a small but harmless race condition here: An emulator not
+    // present just yet could be registered by another invocation right
+    // after doing this check here. However, local_connect protects
+    // against double-registration too. From here, a better error message
+    // can be produced. In the case of the race condition, the very specific
+    // error message won't be shown, but the data doesn't get corrupted.
     atransport* known_emulator = find_emulator_transport_by_adb_port(adb_port);
-    if (known_emulator != NULL) {
-        snprintf(buffer, buffer_size,
-                "Emulator on port %d already registered.", adb_port);
+    if (known_emulator != nullptr) {
+        *response = android::base::StringPrintf("Emulator already registered on port %d", adb_port);
         return;
     }
 
-    /* Check if more emulators can be registered. Similar unproblematic
-     * race condition as above. */
+    // Check if more emulators can be registered. Similar unproblematic
+    // race condition as above.
     int candidate_slot = get_available_local_transport_index();
     if (candidate_slot < 0) {
-        snprintf(buffer, buffer_size, "Cannot accept more emulators.");
+        *response = "Cannot accept more emulators";
         return;
     }
 
-    /* Preconditions met, try to connect to the emulator. */
+    // Preconditions met, try to connect to the emulator.
     if (!local_connect_arbitrary_ports(console_port, adb_port)) {
-        snprintf(buffer, buffer_size,
-                "Connected to emulator on ports %d,%d", console_port, adb_port);
+        *response = android::base::StringPrintf("Connected to emulator on ports %d,%d",
+                                                console_port, adb_port);
     } else {
-        snprintf(buffer, buffer_size,
-                "Could not connect to emulator on ports %d,%d",
-                console_port, adb_port);
+        *response = android::base::StringPrintf("Could not connect to emulator on ports %d,%d",
+                                                console_port, adb_port);
     }
 }
 
 static void connect_service(int fd, void* cookie)
 {
-    char buf[4096];
-    char resp[4096];
-    char *host = cookie;
+    char *host = reinterpret_cast<char*>(cookie);
 
+    std::string response;
     if (!strncmp(host, "emu:", 4)) {
-        connect_emulator(host + 4, buf, sizeof(buf));
+        connect_emulator(host + 4, &response);
     } else {
-        connect_device(host, buf, sizeof(buf));
+        connect_device(host, &response);
     }
 
     // Send response for emulator and device
-    snprintf(resp, sizeof(resp), "%04x%s",(unsigned)strlen(buf), buf);
-    writex(fd, resp, strlen(resp));
+    SendProtocolString(fd, response);
     adb_close(fd);
 }
 #endif
@@ -632,7 +650,11 @@
     if (!strcmp(name,"track-devices")) {
         return create_device_tracker();
     } else if (!strncmp(name, "wait-for-", strlen("wait-for-"))) {
-        struct state_info* sinfo = malloc(sizeof(struct state_info));
+        auto sinfo = reinterpret_cast<state_info*>(malloc(sizeof(state_info)));
+        if (sinfo == nullptr) {
+            fprintf(stderr, "couldn't allocate state_info: %s", strerror(errno));
+            return NULL;
+        }
 
         if (serial)
             sinfo->serial = strdup(serial);
diff --git a/adb/set_verity_enable_state_service.cpp b/adb/set_verity_enable_state_service.cpp
new file mode 100644
index 0000000..bae38cf
--- /dev/null
+++ b/adb/set_verity_enable_state_service.cpp
@@ -0,0 +1,207 @@
+/*
+ * 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.
+ */
+
+#define TRACE_TAG TRACE_ADB
+
+#include "sysdeps.h"
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/stat.h>
+
+#include "cutils/properties.h"
+
+#include "adb.h"
+#include "adb_io.h"
+#include "ext4_sb.h"
+#include "fs_mgr.h"
+#include "remount_service.h"
+
+#define FSTAB_PREFIX "/fstab."
+struct fstab *fstab;
+
+#ifdef ALLOW_ADBD_DISABLE_VERITY
+static const bool kAllowDisableVerity = true;
+#else
+static const bool kAllowDisableVerity = false;
+#endif
+
+static int get_target_device_size(int fd, const char *blk_device,
+                                  uint64_t *device_size)
+{
+    int data_device;
+    struct ext4_super_block sb;
+    struct fs_info info;
+
+    info.len = 0;  /* Only len is set to 0 to ask the device for real size. */
+
+    data_device = adb_open(blk_device, O_RDONLY | O_CLOEXEC);
+    if (data_device < 0) {
+        WriteFdFmt(fd, "Error opening block device (%s)\n", strerror(errno));
+        return -1;
+    }
+
+    if (lseek64(data_device, 1024, SEEK_SET) < 0) {
+        WriteFdFmt(fd, "Error seeking to superblock\n");
+        adb_close(data_device);
+        return -1;
+    }
+
+    if (adb_read(data_device, &sb, sizeof(sb)) != sizeof(sb)) {
+        WriteFdFmt(fd, "Error reading superblock\n");
+        adb_close(data_device);
+        return -1;
+    }
+
+    ext4_parse_sb(&sb, &info);
+    *device_size = info.len;
+
+    adb_close(data_device);
+    return 0;
+}
+
+/* Turn verity on/off */
+static int set_verity_enabled_state(int fd, const char *block_device,
+                                    const char* mount_point, bool enable)
+{
+    uint32_t magic_number;
+    const uint32_t new_magic = enable ? VERITY_METADATA_MAGIC_NUMBER
+                                      : VERITY_METADATA_MAGIC_DISABLE;
+    uint64_t device_length = 0;
+    int device = -1;
+    int retval = -1;
+
+    if (!make_block_device_writable(block_device)) {
+        WriteFdFmt(fd, "Could not make block device %s writable (%s).\n",
+                   block_device, strerror(errno));
+        goto errout;
+    }
+
+    device = adb_open(block_device, O_RDWR | O_CLOEXEC);
+    if (device == -1) {
+        WriteFdFmt(fd, "Could not open block device %s (%s).\n", block_device, strerror(errno));
+        WriteFdFmt(fd, "Maybe run adb remount?\n");
+        goto errout;
+    }
+
+    // find the start of the verity metadata
+    if (get_target_device_size(fd, (char*)block_device, &device_length) < 0) {
+        WriteFdFmt(fd, "Could not get target device size.\n");
+        goto errout;
+    }
+
+    if (lseek64(device, device_length, SEEK_SET) < 0) {
+        WriteFdFmt(fd, "Could not seek to start of verity metadata block.\n");
+        goto errout;
+    }
+
+    // check the magic number
+    if (adb_read(device, &magic_number, sizeof(magic_number)) != sizeof(magic_number)) {
+        WriteFdFmt(fd, "Couldn't read magic number!\n");
+        goto errout;
+    }
+
+    if (!enable && magic_number == VERITY_METADATA_MAGIC_DISABLE) {
+        WriteFdFmt(fd, "Verity already disabled on %s\n", mount_point);
+        goto errout;
+    }
+
+    if (enable && magic_number == VERITY_METADATA_MAGIC_NUMBER) {
+        WriteFdFmt(fd, "Verity already enabled on %s\n", mount_point);
+        goto errout;
+    }
+
+    if (magic_number != VERITY_METADATA_MAGIC_NUMBER
+            && magic_number != VERITY_METADATA_MAGIC_DISABLE) {
+        WriteFdFmt(fd, "Couldn't find verity metadata at offset %" PRIu64 "!\n", device_length);
+        goto errout;
+    }
+
+    if (lseek64(device, device_length, SEEK_SET) < 0) {
+        WriteFdFmt(fd, "Could not seek to start of verity metadata block.\n");
+        goto errout;
+    }
+
+    if (adb_write(device, &new_magic, sizeof(new_magic)) != sizeof(new_magic)) {
+        WriteFdFmt(fd, "Could not set verity %s flag on device %s with error %s\n",
+                   enable ? "enabled" : "disabled",
+                   block_device, strerror(errno));
+        goto errout;
+    }
+
+    WriteFdFmt(fd, "Verity %s on %s\n", enable ? "enabled" : "disabled", mount_point);
+    retval = 0;
+errout:
+    if (device != -1)
+        adb_close(device);
+    return retval;
+}
+
+void set_verity_enabled_state_service(int fd, void* cookie)
+{
+    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 {
+        WriteFdFmt(fd, "%s-verity only works for userdebug builds\n",
+                   enable ? "enable" : "disable");
+    }
+
+errout:
+    adb_close(fd);
+}
diff --git a/adb/sockets.c b/adb/sockets.cpp
similarity index 82%
rename from adb/sockets.c
rename to adb/sockets.cpp
index faa9564..3919147 100644
--- a/adb/sockets.c
+++ b/adb/sockets.cpp
@@ -14,39 +14,36 @@
  * limitations under the License.
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <ctype.h>
+#define TRACE_TAG TRACE_SOCKETS
 
 #include "sysdeps.h"
 
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <mutex>
+#include <string>
+#include <vector>
+
 #if !ADB_HOST
-#include <cutils/properties.h>
+#include "cutils/properties.h"
 #endif
 
-#define  TRACE_TAG  TRACE_SOCKETS
 #include "adb.h"
+#include "adb_io.h"
+#include "sysdeps/mutex.h"
+#include "transport.h"
 
-ADB_MUTEX_DEFINE( socket_list_lock );
+#if !defined(__BIONIC__)
+using std::recursive_mutex;
+#endif
 
-static void local_socket_close_locked(asocket *s);
-
-int sendfailmsg(int fd, const char *reason)
-{
-    char buf[9];
-    int len;
-    len = strlen(reason);
-    if(len > 0xffff) len = 0xffff;
-    snprintf(buf, sizeof buf, "FAIL%04x", len);
-    if(writex(fd, buf, 8)) return -1;
-    return writex(fd, reason, len);
-}
-
-//extern int online;
-
+static recursive_mutex& local_socket_list_lock = *new recursive_mutex();
 static unsigned local_socket_next_id = 1;
 
 static asocket local_socket_list = {
@@ -71,7 +68,7 @@
     asocket *s;
     asocket *result = NULL;
 
-    adb_mutex_lock(&socket_list_lock);
+    std::lock_guard<recursive_mutex> lock(local_socket_list_lock);
     for (s = local_socket_list.next; s != &local_socket_list; s = s->next) {
         if (s->id != local_id)
             continue;
@@ -80,7 +77,6 @@
         }
         break;
     }
-    adb_mutex_unlock(&socket_list_lock);
 
     return result;
 }
@@ -94,20 +90,17 @@
     s->next->prev = s;
 }
 
-
-void install_local_socket(asocket *s)
-{
-    adb_mutex_lock(&socket_list_lock);
+void install_local_socket(asocket* s) {
+    std::lock_guard<recursive_mutex> lock(local_socket_list_lock);
 
     s->id = local_socket_next_id++;
 
     // Socket ids should never be 0.
-    if (local_socket_next_id == 0)
-      local_socket_next_id = 1;
+    if (local_socket_next_id == 0) {
+        fatal("local socket id overflow");
+    }
 
     insert_local_socket(s, &local_socket_list);
-
-    adb_mutex_unlock(&socket_list_lock);
 }
 
 void remove_socket(asocket *s)
@@ -126,19 +119,17 @@
 void close_all_sockets(atransport *t)
 {
     asocket *s;
-
-        /* this is a little gross, but since s->close() *will* modify
-        ** the list out from under you, your options are limited.
-        */
-    adb_mutex_lock(&socket_list_lock);
+    /* this is a little gross, but since s->close() *will* modify
+    ** the list out from under you, your options are limited.
+    */
+    std::lock_guard<recursive_mutex> lock(local_socket_list_lock);
 restart:
-    for(s = local_socket_list.next; s != &local_socket_list; s = s->next){
-        if(s->transport == t || (s->peer && s->peer->transport == t)) {
-            local_socket_close_locked(s);
+    for (s = local_socket_list.next; s != &local_socket_list; s = s->next) {
+        if (s->transport == t || (s->peer && s->peer->transport == t)) {
+            s->close(s);
             goto restart;
         }
     }
-    adb_mutex_unlock(&socket_list_lock);
 }
 
 static int local_socket_enqueue(asocket *s, apacket *p)
@@ -196,17 +187,9 @@
 
 static void local_socket_ready(asocket *s)
 {
-        /* far side is ready for data, pay attention to
-           readable events */
+    /* far side is ready for data, pay attention to
+       readable events */
     fdevent_add(&s->fde, FDE_READ);
-//    D("LS(%d): ready()\n", s->id);
-}
-
-static void local_socket_close(asocket *s)
-{
-    adb_mutex_lock(&socket_list_lock);
-    local_socket_close_locked(s);
-    adb_mutex_unlock(&socket_list_lock);
 }
 
 // be sure to hold the socket list lock when calling this
@@ -237,27 +220,21 @@
     }
 }
 
-
-static void local_socket_close_locked(asocket *s)
-{
-    D("entered. LS(%d) fd=%d\n", s->id, s->fd);
-    if(s->peer) {
-        D("LS(%d): closing peer. peer->id=%d peer->fd=%d\n",
-          s->id, s->peer->id, s->peer->fd);
+static void local_socket_close(asocket* s) {
+    D("entered local_socket_close. LS(%d) fd=%d", s->id, s->fd);
+    std::lock_guard<recursive_mutex> lock(local_socket_list_lock);
+    if (s->peer) {
+        D("LS(%d): closing peer. peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
         /* Note: it's important to call shutdown before disconnecting from
          * the peer, this ensures that remote sockets can still get the id
          * of the local socket they're connected to, to send a CLOSE()
          * protocol event. */
-        if (s->peer->shutdown)
-          s->peer->shutdown(s->peer);
-        s->peer->peer = 0;
-        // tweak to avoid deadlock
-        if (s->peer->close == local_socket_close) {
-            local_socket_close_locked(s->peer);
-        } else {
-            s->peer->close(s->peer);
+        if (s->peer->shutdown) {
+            s->peer->shutdown(s->peer);
         }
-        s->peer = 0;
+        s->peer->peer = nullptr;
+        s->peer->close(s->peer);
+        s->peer = nullptr;
     }
 
         /* If we are already closing, or if there are no
@@ -280,98 +257,101 @@
     insert_local_socket(s, &local_socket_closing_list);
 }
 
-static void local_socket_event_func(int fd, unsigned ev, void *_s)
+static void local_socket_event_func(int fd, unsigned ev, void* _s)
 {
-    asocket *s = _s;
-
+    asocket* s = reinterpret_cast<asocket*>(_s);
     D("LS(%d): event_func(fd=%d(==%d), ev=%04x)\n", s->id, s->fd, fd, ev);
 
     /* put the FDE_WRITE processing before the FDE_READ
     ** in order to simplify the code.
     */
-    if(ev & FDE_WRITE){
-        apacket *p;
-
-        while((p = s->pkt_first) != 0) {
-            while(p->len > 0) {
+    if (ev & FDE_WRITE) {
+        apacket* p;
+        while ((p = s->pkt_first) != nullptr) {
+            while (p->len > 0) {
                 int r = adb_write(fd, p->ptr, p->len);
-                if(r > 0) {
+                if (r == -1) {
+                    /* returning here is ok because FDE_READ will
+                    ** be processed in the next iteration loop
+                    */
+                    if (errno == EAGAIN) {
+                        return;
+                    }
+                } else if (r > 0) {
                     p->ptr += r;
                     p->len -= r;
                     continue;
                 }
-                if(r < 0) {
-                    /* returning here is ok because FDE_READ will
-                    ** be processed in the next iteration loop
-                    */
-                    if(errno == EAGAIN) return;
-                    if(errno == EINTR) continue;
-                }
+
                 D(" closing after write because r=%d and errno is %d\n", r, errno);
                 s->close(s);
                 return;
             }
 
-            if(p->len == 0) {
+            if (p->len == 0) {
                 s->pkt_first = p->next;
-                if(s->pkt_first == 0) s->pkt_last = 0;
+                if (s->pkt_first == 0) {
+                    s->pkt_last = 0;
+                }
                 put_apacket(p);
             }
         }
 
-            /* if we sent the last packet of a closing socket,
-            ** we can now destroy it.
-            */
+        /* if we sent the last packet of a closing socket,
+        ** we can now destroy it.
+        */
         if (s->closing) {
             D(" closing because 'closing' is set after write\n");
             s->close(s);
             return;
         }
 
-            /* no more packets queued, so we can ignore
-            ** writable events again and tell our peer
-            ** to resume writing
-            */
+        /* no more packets queued, so we can ignore
+        ** writable events again and tell our peer
+        ** to resume writing
+        */
         fdevent_del(&s->fde, FDE_WRITE);
         s->peer->ready(s->peer);
     }
 
 
-    if(ev & FDE_READ){
+    if (ev & FDE_READ) {
         apacket *p = get_apacket();
         unsigned char *x = p->data;
         size_t avail = MAX_PAYLOAD;
         int r;
         int is_eof = 0;
 
-        while(avail > 0) {
+        while (avail > 0) {
             r = adb_read(fd, x, avail);
-            D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu\n", s->id, s->fd, r, r<0?errno:0, avail);
-            if(r > 0) {
+            D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu\n",
+              s->id, s->fd, r, r < 0 ? errno : 0, avail);
+            if (r == -1) {
+                if (errno == EAGAIN) {
+                    break;
+                }
+            } else if (r > 0) {
                 avail -= r;
                 x += r;
                 continue;
             }
-            if(r < 0) {
-                if(errno == EAGAIN) break;
-                if(errno == EINTR) continue;
-            }
 
-                /* r = 0 or unhandled error */
+            /* r = 0 or unhandled error */
             is_eof = 1;
             break;
         }
         D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d\n",
           s->id, s->fd, r, is_eof, s->fde.force_eof);
-        if((avail == MAX_PAYLOAD) || (s->peer == 0)) {
+        if ((avail == MAX_PAYLOAD) || (s->peer == 0)) {
             put_apacket(p);
         } else {
             p->len = MAX_PAYLOAD - avail;
 
             r = s->peer->enqueue(s->peer, p);
-            D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd, r);
+            D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd,
+              r);
 
-            if(r < 0) {
+            if (r < 0) {
                     /* error return means they closed us as a side-effect
                     ** and we must return immediately.
                     **
@@ -383,7 +363,7 @@
                 return;
             }
 
-            if(r > 0) {
+            if (r > 0) {
                     /* if the remote cannot accept further events,
                     ** we disable notification of READs.  They'll
                     ** be enabled again when we get a call to ready()
@@ -392,18 +372,18 @@
             }
         }
         /* Don't allow a forced eof if data is still there */
-        if((s->fde.force_eof && !r) || is_eof) {
-            D(" closing because is_eof=%d r=%d s->fde.force_eof=%d\n", is_eof, r, s->fde.force_eof);
+        if ((s->fde.force_eof && !r) || is_eof) {
+            D(" closing because is_eof=%d r=%d s->fde.force_eof=%d\n",
+              is_eof, r, s->fde.force_eof);
             s->close(s);
         }
     }
 
-    if(ev & FDE_ERROR){
+    if (ev & FDE_ERROR){
             /* this should be caught be the next read or write
             ** catching it here means we may skip the last few
             ** bytes of readable data.
             */
-//        s->close(s);
         D("LS(%d): FDE_ERROR (fd=%d)\n", s->id, s->fd);
 
         return;
@@ -412,7 +392,7 @@
 
 asocket *create_local_socket(int fd)
 {
-    asocket *s = calloc(1, sizeof(asocket));
+    asocket *s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
     if (s == NULL) fatal("cannot allocate socket");
     s->fd = fd;
     s->enqueue = local_socket_enqueue;
@@ -422,20 +402,12 @@
     install_local_socket(s);
 
     fdevent_install(&s->fde, fd, local_socket_event_func, s);
-/*    fdevent_add(&s->fde, FDE_ERROR); */
-    //fprintf(stderr, "Created local socket in create_local_socket \n");
     D("LS(%d): created (fd=%d)\n", s->id, s->fd);
     return s;
 }
 
 asocket *create_local_service_socket(const char *name)
 {
-    asocket *s;
-    int fd;
-#if !ADB_HOST
-    char debug[PROPERTY_VALUE_MAX];
-#endif
-
 #if !ADB_HOST
     if (!strcmp(name,"jdwp")) {
         return create_jdwp_service_socket();
@@ -444,18 +416,19 @@
         return create_jdwp_tracker_service_socket();
     }
 #endif
-    fd = service_to_fd(name);
+    int fd = service_to_fd(name);
     if(fd < 0) return 0;
 
-    s = create_local_socket(fd);
+    asocket* s = create_local_socket(fd);
     D("LS(%d): bound to '%s' via %d\n", 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 && strcmp(debug, "1") == 0)
+        || (!strncmp(name, "unroot:", 7) && getuid() == 0)
         || !strncmp(name, "usb:", 4)
         || !strncmp(name, "tcpip:", 6)) {
         D("LS(%d): enabling exit_on_close\n", s->id);
@@ -485,10 +458,10 @@
 /* a Remote socket is used to send/receive data to/from a given transport object
 ** it needs to be closed when the transport is forcibly destroyed by the user
 */
-typedef struct aremotesocket {
+struct aremotesocket {
     asocket      socket;
     adisconnect  disconnect;
-} aremotesocket;
+};
 
 static int remote_socket_enqueue(asocket *s, apacket *p)
 {
@@ -543,8 +516,8 @@
 
 static void remote_socket_disconnect(void*  _s, atransport*  t)
 {
-    asocket*  s    = _s;
-    asocket*  peer = s->peer;
+    asocket* s = reinterpret_cast<asocket*>(_s);
+    asocket* peer = s->peer;
 
     D("remote_socket_disconnect RS(%d)\n", s->id);
     if (peer) {
@@ -561,12 +534,9 @@
    Returns a new non-NULL asocket handle. */
 asocket *create_remote_socket(unsigned id, atransport *t)
 {
-    asocket* s;
-    adisconnect* dis;
-
     if (id == 0) fatal("invalid remote socket id (0)");
-    s = calloc(1, sizeof(aremotesocket));
-    dis = &((aremotesocket*)s)->disconnect;
+    asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(aremotesocket)));
+    adisconnect* dis = &reinterpret_cast<aremotesocket*>(s)->disconnect;
 
     if (s == NULL) fatal("cannot allocate socket");
     s->id = id;
@@ -609,7 +579,7 @@
     s->ready = local_socket_ready;
     s->shutdown = NULL;
     s->close = local_socket_close;
-    adb_write(s->fd, "OKAY", 4);
+    SendOkay(s->fd);
     s->ready(s);
 }
 
@@ -621,11 +591,11 @@
     s->ready = local_socket_ready;
     s->shutdown = NULL;
     s->close = local_socket_close;
-    sendfailmsg(s->fd, "closed");
+    SendFail(s->fd, "closed");
     s->close(s);
 }
 
-unsigned unhex(unsigned char *s, int len)
+static unsigned unhex(unsigned char *s, int len)
 {
     unsigned n = 0, c;
 
@@ -655,6 +625,8 @@
     return n;
 }
 
+#if ADB_HOST
+
 #define PREFIX(str) { str, sizeof(str) - 1 }
 static const struct prefix_struct {
     const char *str;
@@ -671,7 +643,7 @@
    skipping over the 'serial' parameter in the ADB protocol,
    where parameter string may be a host:port string containing
    the protocol delimiter (colon). */
-char *skip_host_serial(char *service) {
+static char *skip_host_serial(char *service) {
     char *first_colon, *serial_end;
     int i;
 
@@ -699,6 +671,8 @@
     return serial_end;
 }
 
+#endif // ADB_HOST
+
 static int smart_socket_enqueue(asocket *s, apacket *p)
 {
     unsigned len;
@@ -800,7 +774,7 @@
         s2 = create_host_service_socket(service, serial);
         if(s2 == 0) {
             D( "SS(%d): couldn't create host service '%s'\n", s->id, service );
-            sendfailmsg(s->peer->fd, "unknown host service");
+            SendFail(s->peer->fd, "unknown host service");
             goto fail;
         }
 
@@ -811,7 +785,7 @@
             ** connection, and close this smart socket now
             ** that its work is done.
             */
-        adb_write(s->peer->fd, "OKAY", 4);
+        SendOkay(s->peer->fd);
 
         s->peer->ready = local_socket_ready;
         s->peer->shutdown = NULL;
@@ -828,12 +802,11 @@
     }
 #else /* !ADB_HOST */
     if (s->transport == NULL) {
-        char* error_string = "unknown failure";
-        s->transport = acquire_one_transport (CS_ANY,
-                kTransportAny, NULL, &error_string);
+        std::string error_msg = "unknown failure";
+        s->transport = acquire_one_transport(CS_ANY, kTransportAny, NULL, &error_msg);
 
         if (s->transport == NULL) {
-            sendfailmsg(s->peer->fd, error_string);
+            SendFail(s->peer->fd, error_msg);
             goto fail;
         }
     }
@@ -843,7 +816,7 @@
            /* if there's no remote we fail the connection
             ** right here and terminate it
             */
-        sendfailmsg(s->peer->fd, "device offline (x)");
+        SendFail(s->peer->fd, "device offline (x)");
         goto fail;
     }
 
@@ -896,7 +869,7 @@
 static asocket *create_smart_socket(void)
 {
     D("Creating smart socket \n");
-    asocket *s = calloc(1, sizeof(asocket));
+    asocket *s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
     if (s == NULL) fatal("cannot allocate socket");
     s->enqueue = smart_socket_enqueue;
     s->ready = smart_socket_ready;
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index cc1f839..59e5b0b 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -24,18 +24,35 @@
 #  undef _WIN32
 #endif
 
+/*
+ * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
+ * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
+ * not already defined, then define it here.
+ */
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({         \
+    typeof (exp) _rc;                      \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+#endif
+
 #ifdef _WIN32
 
+#include <ctype.h>
+#include <direct.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <io.h>
+#include <process.h>
+#include <sys/stat.h>
 #include <winsock2.h>
 #include <windows.h>
 #include <ws2tcpip.h>
-#include <process.h>
-#include <fcntl.h>
-#include <io.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <ctype.h>
-#include <direct.h>
+
+#include "fdevent.h"
 
 #define OS_PATH_SEPARATOR '\\'
 #define OS_PATH_SEPARATOR_STR "\\"
@@ -77,13 +94,16 @@
     return 0;
 }
 
+static __inline__  unsigned long adb_thread_id()
+{
+    return GetCurrentThreadId();
+}
+
 static __inline__ void  close_on_exec(int  fd)
 {
     /* nothing really */
 }
 
-extern void  disable_tcp_nagle(int  fd);
-
 #define  lstat    stat   /* no symlinks on Win32 */
 
 #define  S_ISLNK(m)   0   /* no symlinks on Win32 */
@@ -126,10 +146,8 @@
 #undef   close
 #define  close   ____xxx_close
 
-static __inline__  int  unix_read(int  fd, void*  buf, size_t  len)
-{
-    return read(fd, buf, len);
-}
+extern int  unix_read(int  fd, void*  buf, size_t  len);
+
 #undef   read
 #define  read  ___xxx_read
 
@@ -182,8 +200,6 @@
 #define FDE_ERROR             0x0004
 #define FDE_DONT_CLOSE        0x0080
 
-typedef struct fdevent fdevent;
-
 typedef void (*fd_func)(int fd, unsigned events, void *userdata);
 
 fdevent *fdevent_create(int fd, fd_func func, void *arg);
@@ -195,20 +211,6 @@
 void     fdevent_del(fdevent *fde, unsigned events);
 void     fdevent_loop();
 
-struct fdevent {
-    fdevent *next;
-    fdevent *prev;
-
-    int fd;
-    int force_eof;
-
-    unsigned short state;
-    unsigned short events;
-
-    fd_func func;
-    void *arg;
-};
-
 static __inline__ void  adb_sleep_ms( int  mseconds )
 {
     Sleep( mseconds );
@@ -219,10 +221,21 @@
 #undef   accept
 #define  accept  ___xxx_accept
 
+extern int  adb_setsockopt(int  fd, int  level, int  optname, const void*  optval, socklen_t  optlen);
+
+#undef   setsockopt
+#define  setsockopt  ___xxx_setsockopt
+
 static __inline__  int  adb_socket_setbufsize( int   fd, int  bufsize )
 {
     int opt = bufsize;
-    return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*)&opt, sizeof(opt));
+    return adb_setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const void*)&opt, sizeof(opt));
+}
+
+static __inline__ void  disable_tcp_nagle( int  fd )
+{
+    int  on = 1;
+    adb_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void*)&on, sizeof(on));
 }
 
 extern int  adb_socketpair( int  sv[2] );
@@ -258,8 +271,6 @@
     return isalpha(path[0]) && path[1] == ':' && path[2] == '\\';
 }
 
-extern char*  adb_strtok_r(char *str, const char *delim, char **saveptr);
-
 #else /* !_WIN32 a.k.a. Unix */
 
 #include "fdevent.h"
@@ -279,21 +290,6 @@
 #include <string.h>
 #include <unistd.h>
 
-/*
- * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
- * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
- * not already defined, then define it here.
- */
-#ifndef TEMP_FAILURE_RETRY
-/* Used to retry syscalls that can return EINTR. */
-#define TEMP_FAILURE_RETRY(exp) ({         \
-    typeof (exp) _rc;                      \
-    do {                                   \
-        _rc = (exp);                       \
-    } while (_rc == -1 && errno == EINTR); \
-    _rc; })
-#endif
-
 #define OS_PATH_SEPARATOR '/'
 #define OS_PATH_SEPARATOR_STR "/"
 #define ENV_PATH_SEPARATOR_STR ":"
@@ -459,6 +455,13 @@
     setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on) );
 }
 
+static __inline__ int  adb_setsockopt( int  fd, int  level, int  optname, const void*  optval, socklen_t  optlen )
+{
+    return setsockopt( fd, level, optname, optval, optlen );
+}
+
+#undef   setsockopt
+#define  setsockopt  ___xxx_setsockopt
 
 static __inline__ int  unix_socketpair( int  d, int  type, int  protocol, int sv[2] )
 {
@@ -512,12 +515,10 @@
     return path[0] == '/';
 }
 
-static __inline__ char*  adb_strtok_r(char *str, const char *delim, char **saveptr)
+static __inline__ unsigned long adb_thread_id()
 {
-    return strtok_r(str, delim, saveptr);
+    return (unsigned long)pthread_self();
 }
-#undef   strtok_r
-#define  strtok_r  ___xxx_strtok_r
 
 #endif /* !_WIN32 */
 
diff --git a/adb/sysdeps/mutex.h b/adb/sysdeps/mutex.h
new file mode 100644
index 0000000..e33551f
--- /dev/null
+++ b/adb/sysdeps/mutex.h
@@ -0,0 +1,143 @@
+#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 <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;
+};
+
+}
+
+#elif defined(__BIONIC__)
+
+// On M, the recovery image uses parts of adb that depends on recursive_mutex, and uses libstdc++,
+// which lacks it.
+
+#include <pthread.h>
+#include <mutex>
+
+#include <base/macros.h>
+
+class recursive_mutex {
+  public:
+    recursive_mutex() {
+    }
+
+    ~recursive_mutex() {
+    }
+
+    void lock() {
+        pthread_mutex_lock(&mutex_);
+    }
+
+    bool try_lock() {
+        return pthread_mutex_trylock(&mutex_);
+    }
+
+    void unlock() {
+        pthread_mutex_unlock(&mutex_);
+    }
+
+  private:
+    pthread_mutex_t mutex_ = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+
+    DISALLOW_COPY_AND_ASSIGN(recursive_mutex);
+};
+
+#endif
diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.c
deleted file mode 100644
index e69ec2b..0000000
--- a/adb/sysdeps_win32.c
+++ /dev/null
@@ -1,2228 +0,0 @@
-#include "sysdeps.h"
-#include <winsock2.h>
-#include <windows.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#define  TRACE_TAG  TRACE_SYSDEPS
-#include "adb.h"
-
-extern void fatal(const char *fmt, ...);
-
-#define assert(cond)  do { if (!(cond)) fatal( "assertion failed '%s' on %s:%ld\n", #cond, __FILE__, __LINE__ ); } while (0)
-
-/**************************************************************************/
-/**************************************************************************/
-/*****                                                                *****/
-/*****      replaces libs/cutils/load_file.c                          *****/
-/*****                                                                *****/
-/**************************************************************************/
-/**************************************************************************/
-
-void *load_file(const char *fn, unsigned *_sz)
-{
-    HANDLE    file;
-    char     *data;
-    DWORD     file_size;
-
-    file = CreateFile( fn,
-                       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\n", 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'\n", file_size, fn);
-                free(data);
-                data      = NULL;
-                file_size = 0;
-            }
-        }
-    }
-    CloseHandle( file );
-
-    *_sz = (unsigned) file_size;
-    return  data;
-}
-
-/**************************************************************************/
-/**************************************************************************/
-/*****                                                                *****/
-/*****    common file descriptor handling                             *****/
-/*****                                                                *****/
-/**************************************************************************/
-/**************************************************************************/
-
-typedef const struct FHClassRec_*   FHClass;
-
-typedef struct FHRec_*          FH;
-
-typedef struct EventHookRec_*  EventHook;
-
-typedef struct FHClassRec_
-{
-    void (*_fh_init) ( FH  f );
-    int  (*_fh_close)( FH  f );
-    int  (*_fh_lseek)( FH  f, int  pos, int  origin );
-    int  (*_fh_read) ( FH  f, void*  buf, int  len );
-    int  (*_fh_write)( FH  f, const void*  buf, int  len );
-    void (*_fh_hook) ( FH  f, int  events, EventHook  hook );
-
-} FHClassRec;
-
-/* used to emulate unix-domain socket pairs */
-typedef struct SocketPairRec_*  SocketPair;
-
-typedef struct FHRec_
-{
-    FHClass    clazz;
-    int        used;
-    int        eof;
-    union {
-        HANDLE      handle;
-        SOCKET      socket;
-        SocketPair  pair;
-    } u;
-
-    HANDLE    event;
-    int       mask;
-
-    char  name[32];
-
-} FHRec;
-
-#define  fh_handle  u.handle
-#define  fh_socket  u.socket
-#define  fh_pair    u.pair
-
-#define  WIN32_FH_BASE    100
-
-#define  WIN32_MAX_FHS    128
-
-static adb_mutex_t   _win32_lock;
-static  FHRec        _win32_fhs[ WIN32_MAX_FHS ];
-static  int          _win32_fh_count;
-
-static FH
-_fh_from_int( int   fd )
-{
-    FH  f;
-
-    fd -= WIN32_FH_BASE;
-
-    if (fd < 0 || fd >= _win32_fh_count) {
-        D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE );
-        errno = EBADF;
-        return NULL;
-    }
-
-    f = &_win32_fhs[fd];
-
-    if (f->used == 0) {
-        D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE );
-        errno = EBADF;
-        return NULL;
-    }
-
-    return f;
-}
-
-
-static int
-_fh_to_int( FH  f )
-{
-    if (f && f->used && f >= _win32_fhs && f < _win32_fhs + WIN32_MAX_FHS)
-        return (int)(f - _win32_fhs) + WIN32_FH_BASE;
-
-    return -1;
-}
-
-static FH
-_fh_alloc( FHClass  clazz )
-{
-    int  nn;
-    FH   f = NULL;
-
-    adb_mutex_lock( &_win32_lock );
-
-    if (_win32_fh_count < WIN32_MAX_FHS) {
-        f = &_win32_fhs[ _win32_fh_count++ ];
-        goto Exit;
-    }
-
-    for (nn = 0; nn < WIN32_MAX_FHS; nn++) {
-        if ( _win32_fhs[nn].clazz == NULL) {
-            f = &_win32_fhs[nn];
-            goto Exit;
-        }
-    }
-    D( "_fh_alloc: no more free file descriptors\n" );
-Exit:
-    if (f) {
-        f->clazz = clazz;
-        f->used  = 1;
-        f->eof   = 0;
-        clazz->_fh_init(f);
-    }
-    adb_mutex_unlock( &_win32_lock );
-    return f;
-}
-
-
-static int
-_fh_close( FH   f )
-{
-    if ( f->used ) {
-        f->clazz->_fh_close( f );
-        f->used = 0;
-        f->eof  = 0;
-        f->clazz = NULL;
-    }
-    return 0;
-}
-
-/* forward definitions */
-static const FHClassRec   _fh_file_class;
-static const FHClassRec   _fh_socket_class;
-
-/**************************************************************************/
-/**************************************************************************/
-/*****                                                                *****/
-/*****    file-based descriptor handling                              *****/
-/*****                                                                *****/
-/**************************************************************************/
-/**************************************************************************/
-
-static void
-_fh_file_init( FH  f )
-{
-    f->fh_handle = INVALID_HANDLE_VALUE;
-}
-
-static int
-_fh_file_close( FH  f )
-{
-    CloseHandle( f->fh_handle );
-    f->fh_handle = INVALID_HANDLE_VALUE;
-    return 0;
-}
-
-static int
-_fh_file_read( FH  f,  void*  buf, int   len )
-{
-    DWORD  read_bytes;
-
-    if ( !ReadFile( f->fh_handle, buf, (DWORD)len, &read_bytes, NULL ) ) {
-        D( "adb_read: could not read %d bytes from %s\n", len, f->name );
-        errno = EIO;
-        return -1;
-    } else if (read_bytes < (DWORD)len) {
-        f->eof = 1;
-    }
-    return (int)read_bytes;
-}
-
-static int
-_fh_file_write( FH  f,  const void*  buf, int   len )
-{
-    DWORD  wrote_bytes;
-
-    if ( !WriteFile( f->fh_handle, buf, (DWORD)len, &wrote_bytes, NULL ) ) {
-        D( "adb_file_write: could not write %d bytes from %s\n", len, f->name );
-        errno = EIO;
-        return -1;
-    } else if (wrote_bytes < (DWORD)len) {
-        f->eof = 1;
-    }
-    return  (int)wrote_bytes;
-}
-
-static int
-_fh_file_lseek( FH  f, int  pos, int  origin )
-{
-    DWORD  method;
-    DWORD  result;
-
-    switch (origin)
-    {
-        case SEEK_SET:  method = FILE_BEGIN; break;
-        case SEEK_CUR:  method = FILE_CURRENT; break;
-        case SEEK_END:  method = FILE_END; break;
-        default:
-            errno = EINVAL;
-            return -1;
-    }
-
-    result = SetFilePointer( f->fh_handle, pos, NULL, method );
-    if (result == INVALID_SET_FILE_POINTER) {
-        errno = EIO;
-        return -1;
-    } else {
-        f->eof = 0;
-    }
-    return (int)result;
-}
-
-static void  _fh_file_hook( FH  f, int  event, EventHook  eventhook );  /* forward */
-
-static const FHClassRec  _fh_file_class =
-{
-    _fh_file_init,
-    _fh_file_close,
-    _fh_file_lseek,
-    _fh_file_read,
-    _fh_file_write,
-    _fh_file_hook
-};
-
-/**************************************************************************/
-/**************************************************************************/
-/*****                                                                *****/
-/*****    file-based descriptor handling                              *****/
-/*****                                                                *****/
-/**************************************************************************/
-/**************************************************************************/
-
-int  adb_open(const char*  path, int  options)
-{
-    FH  f;
-
-    DWORD  desiredAccess       = 0;
-    DWORD  shareMode           = FILE_SHARE_READ | FILE_SHARE_WRITE;
-
-    switch (options) {
-        case O_RDONLY:
-            desiredAccess = GENERIC_READ;
-            break;
-        case O_WRONLY:
-            desiredAccess = GENERIC_WRITE;
-            break;
-        case O_RDWR:
-            desiredAccess = GENERIC_READ | GENERIC_WRITE;
-            break;
-        default:
-            D("adb_open: invalid options (0x%0x)\n", options);
-            errno = EINVAL;
-            return -1;
-    }
-
-    f = _fh_alloc( &_fh_file_class );
-    if ( !f ) {
-        errno = ENOMEM;
-        return -1;
-    }
-
-    f->fh_handle = CreateFile( path, desiredAccess, shareMode, NULL, OPEN_EXISTING,
-                               0, NULL );
-
-    if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
-        _fh_close(f);
-        D( "adb_open: could not open '%s':", path );
-        switch (GetLastError()) {
-            case ERROR_FILE_NOT_FOUND:
-                D( "file not found\n" );
-                errno = ENOENT;
-                return -1;
-
-            case ERROR_PATH_NOT_FOUND:
-                D( "path not found\n" );
-                errno = ENOTDIR;
-                return -1;
-
-            default:
-                D( "unknown error\n" );
-                errno = ENOENT;
-                return -1;
-        }
-    }
-
-    snprintf( f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path );
-    D( "adb_open: '%s' => fd %d\n", path, _fh_to_int(f) );
-    return _fh_to_int(f);
-}
-
-/* ignore mode on Win32 */
-int  adb_creat(const char*  path, int  mode)
-{
-    FH  f;
-
-    f = _fh_alloc( &_fh_file_class );
-    if ( !f ) {
-        errno = ENOMEM;
-        return -1;
-    }
-
-    f->fh_handle = CreateFile( path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
-                               NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
-                               NULL );
-
-    if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
-        _fh_close(f);
-        D( "adb_creat: could not open '%s':", path );
-        switch (GetLastError()) {
-            case ERROR_FILE_NOT_FOUND:
-                D( "file not found\n" );
-                errno = ENOENT;
-                return -1;
-
-            case ERROR_PATH_NOT_FOUND:
-                D( "path not found\n" );
-                errno = ENOTDIR;
-                return -1;
-
-            default:
-                D( "unknown error\n" );
-                errno = ENOENT;
-                return -1;
-        }
-    }
-    snprintf( f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path );
-    D( "adb_creat: '%s' => fd %d\n", path, _fh_to_int(f) );
-    return _fh_to_int(f);
-}
-
-
-int  adb_read(int  fd, void* buf, int len)
-{
-    FH     f = _fh_from_int(fd);
-
-    if (f == NULL) {
-        return -1;
-    }
-
-    return f->clazz->_fh_read( f, buf, len );
-}
-
-
-int  adb_write(int  fd, const void*  buf, int  len)
-{
-    FH     f = _fh_from_int(fd);
-
-    if (f == NULL) {
-        return -1;
-    }
-
-    return f->clazz->_fh_write(f, buf, len);
-}
-
-
-int  adb_lseek(int  fd, int  pos, int  where)
-{
-    FH     f = _fh_from_int(fd);
-
-    if (!f) {
-        return -1;
-    }
-
-    return f->clazz->_fh_lseek(f, pos, where);
-}
-
-
-int  adb_shutdown(int  fd)
-{
-    FH   f = _fh_from_int(fd);
-
-    if (!f) {
-        return -1;
-    }
-
-    D( "adb_shutdown: %s\n", f->name);
-    shutdown( f->fh_socket, SD_BOTH );
-    return 0;
-}
-
-
-int  adb_close(int  fd)
-{
-    FH   f = _fh_from_int(fd);
-
-    if (!f) {
-        return -1;
-    }
-
-    D( "adb_close: %s\n", f->name);
-    _fh_close(f);
-    return 0;
-}
-
-/**************************************************************************/
-/**************************************************************************/
-/*****                                                                *****/
-/*****    socket-based file descriptors                               *****/
-/*****                                                                *****/
-/**************************************************************************/
-/**************************************************************************/
-
-static void
-_socket_set_errno( void )
-{
-    switch (WSAGetLastError()) {
-    case 0:              errno = 0; break;
-    case WSAEWOULDBLOCK: errno = EAGAIN; break;
-    case WSAEINTR:       errno = EINTR; break;
-    default:
-        D( "_socket_set_errno: unhandled value %d\n", WSAGetLastError() );
-        errno = EINVAL;
-    }
-}
-
-static void
-_fh_socket_init( FH  f )
-{
-    f->fh_socket = INVALID_SOCKET;
-    f->event     = WSACreateEvent();
-    f->mask      = 0;
-}
-
-static int
-_fh_socket_close( FH  f )
-{
-    /* gently tell any peer that we're closing the socket */
-    shutdown( f->fh_socket, SD_BOTH );
-    closesocket( f->fh_socket );
-    f->fh_socket = INVALID_SOCKET;
-    CloseHandle( f->event );
-    f->mask = 0;
-    return 0;
-}
-
-static int
-_fh_socket_lseek( FH  f, int pos, int origin )
-{
-    errno = EPIPE;
-    return -1;
-}
-
-static int
-_fh_socket_read( FH  f, void*  buf, int  len )
-{
-    int  result = recv( f->fh_socket, buf, len, 0 );
-    if (result == SOCKET_ERROR) {
-        _socket_set_errno();
-        result = -1;
-    }
-    return  result;
-}
-
-static int
-_fh_socket_write( FH  f, const void*  buf, int  len )
-{
-    int  result = send( f->fh_socket, buf, len, 0 );
-    if (result == SOCKET_ERROR) {
-        _socket_set_errno();
-        result = -1;
-    }
-    return result;
-}
-
-static void  _fh_socket_hook( FH  f, int  event, EventHook  hook );  /* forward */
-
-static const FHClassRec  _fh_socket_class =
-{
-    _fh_socket_init,
-    _fh_socket_close,
-    _fh_socket_lseek,
-    _fh_socket_read,
-    _fh_socket_write,
-    _fh_socket_hook
-};
-
-/**************************************************************************/
-/**************************************************************************/
-/*****                                                                *****/
-/*****    replacement for libs/cutils/socket_xxxx.c                   *****/
-/*****                                                                *****/
-/**************************************************************************/
-/**************************************************************************/
-
-#include <winsock2.h>
-
-static int  _winsock_init;
-
-static void
-_cleanup_winsock( void )
-{
-    WSACleanup();
-}
-
-static void
-_init_winsock( void )
-{
-    if (!_winsock_init) {
-        WSADATA  wsaData;
-        int      rc = WSAStartup( MAKEWORD(2,2), &wsaData);
-        if (rc != 0) {
-            fatal( "adb: could not initialize Winsock\n" );
-        }
-        atexit( _cleanup_winsock );
-        _winsock_init = 1;
-    }
-}
-
-int socket_loopback_client(int port, int type)
-{
-    FH  f = _fh_alloc( &_fh_socket_class );
-    struct sockaddr_in addr;
-    SOCKET  s;
-
-    if (!f)
-        return -1;
-
-    if (!_winsock_init)
-        _init_winsock();
-
-    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 == INVALID_SOCKET) {
-        D("socket_loopback_client: could not create socket\n" );
-        _fh_close(f);
-        return -1;
-    }
-
-    f->fh_socket = s;
-    if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        D("socket_loopback_client: could not connect to %s:%d\n", type != SOCK_STREAM ? "udp" : "tcp", port );
-        _fh_close(f);
-        return -1;
-    }
-    snprintf( f->name, sizeof(f->name), "%d(lo-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
-    D( "socket_loopback_client: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
-    return _fh_to_int(f);
-}
-
-#define LISTEN_BACKLOG 4
-
-int socket_loopback_server(int port, int type)
-{
-    FH   f = _fh_alloc( &_fh_socket_class );
-    struct sockaddr_in addr;
-    SOCKET  s;
-    int  n;
-
-    if (!f) {
-        return -1;
-    }
-
-    if (!_winsock_init)
-        _init_winsock();
-
-    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 == INVALID_SOCKET) return -1;
-
-    f->fh_socket = s;
-
-    n = 1;
-    setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n));
-
-    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        _fh_close(f);
-        return -1;
-    }
-    if (type == SOCK_STREAM) {
-        int ret;
-
-        ret = listen(s, LISTEN_BACKLOG);
-        if (ret < 0) {
-            _fh_close(f);
-            return -1;
-        }
-    }
-    snprintf( f->name, sizeof(f->name), "%d(lo-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
-    D( "socket_loopback_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
-    return _fh_to_int(f);
-}
-
-
-int socket_network_client(const char *host, int port, int type)
-{
-    FH  f = _fh_alloc( &_fh_socket_class );
-    struct hostent *hp;
-    struct sockaddr_in addr;
-    SOCKET s;
-
-    if (!f)
-        return -1;
-
-    if (!_winsock_init)
-        _init_winsock();
-
-    hp = gethostbyname(host);
-    if(hp == 0) {
-        _fh_close(f);
-        return -1;
-    }
-
-    memset(&addr, 0, sizeof(addr));
-    addr.sin_family = hp->h_addrtype;
-    addr.sin_port = htons(port);
-    memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
-
-    s = socket(hp->h_addrtype, type, 0);
-    if(s == INVALID_SOCKET) {
-        _fh_close(f);
-        return -1;
-    }
-    f->fh_socket = s;
-
-    if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        _fh_close(f);
-        return -1;
-    }
-
-    snprintf( f->name, sizeof(f->name), "%d(net-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
-    D( "socket_network_client: host '%s' port %d type %s => fd %d\n", host, port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
-    return _fh_to_int(f);
-}
-
-
-int socket_network_client_timeout(const char *host, int port, int type, int timeout)
-{
-    // TODO: implement timeouts for Windows.
-    return socket_network_client(host, port, type);
-}
-
-
-int socket_inaddr_any_server(int port, int type)
-{
-    FH  f = _fh_alloc( &_fh_socket_class );
-    struct sockaddr_in addr;
-    SOCKET  s;
-    int n;
-
-    if (!f)
-        return -1;
-
-    if (!_winsock_init)
-        _init_winsock();
-
-    memset(&addr, 0, sizeof(addr));
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port);
-    addr.sin_addr.s_addr = htonl(INADDR_ANY);
-
-    s = socket(AF_INET, type, 0);
-    if(s == INVALID_SOCKET) {
-        _fh_close(f);
-        return -1;
-    }
-
-    f->fh_socket = s;
-    n = 1;
-    setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n));
-
-    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        _fh_close(f);
-        return -1;
-    }
-
-    if (type == SOCK_STREAM) {
-        int ret;
-
-        ret = listen(s, LISTEN_BACKLOG);
-        if (ret < 0) {
-            _fh_close(f);
-            return -1;
-        }
-    }
-    snprintf( f->name, sizeof(f->name), "%d(any-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
-    D( "socket_inaddr_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
-    return _fh_to_int(f);
-}
-
-#undef accept
-int  adb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen)
-{
-    FH   serverfh = _fh_from_int(serverfd);
-    FH   fh;
-
-    if ( !serverfh || serverfh->clazz != &_fh_socket_class ) {
-        D( "adb_socket_accept: invalid fd %d\n", serverfd );
-        return -1;
-    }
-
-    fh = _fh_alloc( &_fh_socket_class );
-    if (!fh) {
-        D( "adb_socket_accept: not enough memory to allocate accepted socket descriptor\n" );
-        return -1;
-    }
-
-    fh->fh_socket = accept( serverfh->fh_socket, addr, addrlen );
-    if (fh->fh_socket == INVALID_SOCKET) {
-        _fh_close( fh );
-        D( "adb_socket_accept: accept on fd %d return error %ld\n", serverfd, GetLastError() );
-        return -1;
-    }
-
-    snprintf( fh->name, sizeof(fh->name), "%d(accept:%s)", _fh_to_int(fh), serverfh->name );
-    D( "adb_socket_accept on fd %d returns fd %d\n", serverfd, _fh_to_int(fh) );
-    return  _fh_to_int(fh);
-}
-
-
-void  disable_tcp_nagle(int fd)
-{
-    FH   fh = _fh_from_int(fd);
-    int  on = 1;
-
-    if ( !fh || fh->clazz != &_fh_socket_class )
-        return;
-
-    setsockopt( fh->fh_socket, IPPROTO_TCP, TCP_NODELAY, (const char*)&on, sizeof(on) );
-}
-
-/**************************************************************************/
-/**************************************************************************/
-/*****                                                                *****/
-/*****    emulated socketpairs                                       *****/
-/*****                                                                *****/
-/**************************************************************************/
-/**************************************************************************/
-
-/* we implement socketpairs directly in use space for the following reasons:
- *   - it avoids copying data from/to the Nt kernel
- *   - it allows us to implement fdevent hooks easily and cheaply, something
- *     that is not possible with standard Win32 pipes !!
- *
- * basically, we use two circular buffers, each one corresponding to a given
- * direction.
- *
- * each buffer is implemented as two regions:
- *
- *   region A which is (a_start,a_end)
- *   region B which is (0, b_end)  with b_end <= a_start
- *
- * an empty buffer has:  a_start = a_end = b_end = 0
- *
- * a_start is the pointer where we start reading data
- * a_end is the pointer where we start writing data, unless it is BUFFER_SIZE,
- * then you start writing at b_end
- *
- * the buffer is full when  b_end == a_start && a_end == BUFFER_SIZE
- *
- * there is room when b_end < a_start || a_end < BUFER_SIZE
- *
- * when reading, a_start is incremented, it a_start meets a_end, then
- * we do:  a_start = 0, a_end = b_end, b_end = 0, and keep going on..
- */
-
-#define  BIP_BUFFER_SIZE   4096
-
-#if 0
-#include <stdio.h>
-#  define  BIPD(x)      D x
-#  define  BIPDUMP   bip_dump_hex
-
-static void  bip_dump_hex( const unsigned char*  ptr, size_t  len )
-{
-    int  nn, len2 = len;
-
-    if (len2 > 8) len2 = 8;
-
-    for (nn = 0; nn < len2; nn++)
-        printf("%02x", ptr[nn]);
-    printf("  ");
-
-    for (nn = 0; nn < len2; nn++) {
-        int  c = ptr[nn];
-        if (c < 32 || c > 127)
-            c = '.';
-        printf("%c", c);
-    }
-    printf("\n");
-    fflush(stdout);
-}
-
-#else
-#  define  BIPD(x)        do {} while (0)
-#  define  BIPDUMP(p,l)   BIPD(p)
-#endif
-
-typedef struct BipBufferRec_
-{
-    int                a_start;
-    int                a_end;
-    int                b_end;
-    int                fdin;
-    int                fdout;
-    int                closed;
-    int                can_write;  /* boolean */
-    HANDLE             evt_write;  /* event signaled when one can write to a buffer  */
-    int                can_read;   /* boolean */
-    HANDLE             evt_read;   /* event signaled when one can read from a buffer */
-    CRITICAL_SECTION  lock;
-    unsigned char      buff[ BIP_BUFFER_SIZE ];
-
-} BipBufferRec, *BipBuffer;
-
-static void
-bip_buffer_init( BipBuffer  buffer )
-{
-    D( "bit_buffer_init %p\n", buffer );
-    buffer->a_start   = 0;
-    buffer->a_end     = 0;
-    buffer->b_end     = 0;
-    buffer->can_write = 1;
-    buffer->can_read  = 0;
-    buffer->fdin      = 0;
-    buffer->fdout     = 0;
-    buffer->closed    = 0;
-    buffer->evt_write = CreateEvent( NULL, TRUE, TRUE, NULL );
-    buffer->evt_read  = CreateEvent( NULL, TRUE, FALSE, NULL );
-    InitializeCriticalSection( &buffer->lock );
-}
-
-static void
-bip_buffer_close( BipBuffer  bip )
-{
-    bip->closed = 1;
-
-    if (!bip->can_read) {
-        SetEvent( bip->evt_read );
-    }
-    if (!bip->can_write) {
-        SetEvent( bip->evt_write );
-    }
-}
-
-static void
-bip_buffer_done( BipBuffer  bip )
-{
-    BIPD(( "bip_buffer_done: %d->%d\n", bip->fdin, bip->fdout ));
-    CloseHandle( bip->evt_read );
-    CloseHandle( bip->evt_write );
-    DeleteCriticalSection( &bip->lock );
-}
-
-static int
-bip_buffer_write( BipBuffer  bip, const void* src, int  len )
-{
-    int  avail, count = 0;
-
-    if (len <= 0)
-        return 0;
-
-    BIPD(( "bip_buffer_write: enter %d->%d len %d\n", bip->fdin, bip->fdout, len ));
-    BIPDUMP( src, len );
-
-    EnterCriticalSection( &bip->lock );
-
-    while (!bip->can_write) {
-        int  ret;
-        LeaveCriticalSection( &bip->lock );
-
-        if (bip->closed) {
-            errno = EPIPE;
-            return -1;
-        }
-        /* spinlocking here is probably unfair, but let's live with it */
-        ret = WaitForSingleObject( bip->evt_write, INFINITE );
-        if (ret != WAIT_OBJECT_0) {  /* buffer probably closed */
-            D( "bip_buffer_write: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError() );
-            return 0;
-        }
-        if (bip->closed) {
-            errno = EPIPE;
-            return -1;
-        }
-        EnterCriticalSection( &bip->lock );
-    }
-
-    BIPD(( "bip_buffer_write: exec %d->%d len %d\n", bip->fdin, bip->fdout, len ));
-
-    avail = BIP_BUFFER_SIZE - bip->a_end;
-    if (avail > 0)
-    {
-        /* we can append to region A */
-        if (avail > len)
-            avail = len;
-
-        memcpy( bip->buff + bip->a_end, src, avail );
-        src   = (const char *)src + avail;
-        count += avail;
-        len   -= avail;
-
-        bip->a_end += avail;
-        if (bip->a_end == BIP_BUFFER_SIZE && bip->a_start == 0) {
-            bip->can_write = 0;
-            ResetEvent( bip->evt_write );
-            goto Exit;
-        }
-    }
-
-    if (len == 0)
-        goto Exit;
-
-    avail = bip->a_start - bip->b_end;
-    assert( avail > 0 );  /* since can_write is TRUE */
-
-    if (avail > len)
-        avail = len;
-
-    memcpy( bip->buff + bip->b_end, src, avail );
-    count += avail;
-    bip->b_end += avail;
-
-    if (bip->b_end == bip->a_start) {
-        bip->can_write = 0;
-        ResetEvent( bip->evt_write );
-    }
-
-Exit:
-    assert( count > 0 );
-
-    if ( !bip->can_read ) {
-        bip->can_read = 1;
-        SetEvent( bip->evt_read );
-    }
-
-    BIPD(( "bip_buffer_write: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n",
-            bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
-    LeaveCriticalSection( &bip->lock );
-
-    return count;
- }
-
-static int
-bip_buffer_read( BipBuffer  bip, void*  dst, int  len )
-{
-    int  avail, count = 0;
-
-    if (len <= 0)
-        return 0;
-
-    BIPD(( "bip_buffer_read: enter %d->%d len %d\n", bip->fdin, bip->fdout, len ));
-
-    EnterCriticalSection( &bip->lock );
-    while ( !bip->can_read )
-    {
-#if 0
-        LeaveCriticalSection( &bip->lock );
-        errno = EAGAIN;
-        return -1;
-#else
-        int  ret;
-        LeaveCriticalSection( &bip->lock );
-
-        if (bip->closed) {
-            errno = EPIPE;
-            return -1;
-        }
-
-        ret = WaitForSingleObject( bip->evt_read, INFINITE );
-        if (ret != WAIT_OBJECT_0) { /* probably closed buffer */
-            D( "bip_buffer_read: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError());
-            return 0;
-        }
-        if (bip->closed) {
-            errno = EPIPE;
-            return -1;
-        }
-        EnterCriticalSection( &bip->lock );
-#endif
-    }
-
-    BIPD(( "bip_buffer_read: exec %d->%d len %d\n", bip->fdin, bip->fdout, len ));
-
-    avail = bip->a_end - bip->a_start;
-    assert( avail > 0 );  /* since can_read is TRUE */
-
-    if (avail > len)
-        avail = len;
-
-    memcpy( dst, bip->buff + bip->a_start, avail );
-    dst   = (char *)dst + avail;
-    count += avail;
-    len   -= avail;
-
-    bip->a_start += avail;
-    if (bip->a_start < bip->a_end)
-        goto Exit;
-
-    bip->a_start = 0;
-    bip->a_end   = bip->b_end;
-    bip->b_end   = 0;
-
-    avail = bip->a_end;
-    if (avail > 0) {
-        if (avail > len)
-            avail = len;
-        memcpy( dst, bip->buff, avail );
-        count += avail;
-        bip->a_start += avail;
-
-        if ( bip->a_start < bip->a_end )
-            goto Exit;
-
-        bip->a_start = bip->a_end = 0;
-    }
-
-    bip->can_read = 0;
-    ResetEvent( bip->evt_read );
-
-Exit:
-    assert( count > 0 );
-
-    if (!bip->can_write ) {
-        bip->can_write = 1;
-        SetEvent( bip->evt_write );
-    }
-
-    BIPDUMP( (const unsigned char*)dst - count, count );
-    BIPD(( "bip_buffer_read: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n",
-            bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
-    LeaveCriticalSection( &bip->lock );
-
-    return count;
-}
-
-typedef struct SocketPairRec_
-{
-    BipBufferRec  a2b_bip;
-    BipBufferRec  b2a_bip;
-    FH            a_fd;
-    int           used;
-
-} SocketPairRec;
-
-void _fh_socketpair_init( FH  f )
-{
-    f->fh_pair = NULL;
-}
-
-static int
-_fh_socketpair_close( FH  f )
-{
-    if ( f->fh_pair ) {
-        SocketPair  pair = f->fh_pair;
-
-        if ( f == pair->a_fd ) {
-            pair->a_fd = NULL;
-        }
-
-        bip_buffer_close( &pair->b2a_bip );
-        bip_buffer_close( &pair->a2b_bip );
-
-        if ( --pair->used == 0 ) {
-            bip_buffer_done( &pair->b2a_bip );
-            bip_buffer_done( &pair->a2b_bip );
-            free( pair );
-        }
-        f->fh_pair = NULL;
-    }
-    return 0;
-}
-
-static int
-_fh_socketpair_lseek( FH  f, int pos, int  origin )
-{
-    errno = ESPIPE;
-    return -1;
-}
-
-static int
-_fh_socketpair_read( FH  f, void* buf, int  len )
-{
-    SocketPair  pair = f->fh_pair;
-    BipBuffer   bip;
-
-    if (!pair)
-        return -1;
-
-    if ( f == pair->a_fd )
-        bip = &pair->b2a_bip;
-    else
-        bip = &pair->a2b_bip;
-
-    return bip_buffer_read( bip, buf, len );
-}
-
-static int
-_fh_socketpair_write( FH  f, const void*  buf, int  len )
-{
-    SocketPair  pair = f->fh_pair;
-    BipBuffer   bip;
-
-    if (!pair)
-        return -1;
-
-    if ( f == pair->a_fd )
-        bip = &pair->a2b_bip;
-    else
-        bip = &pair->b2a_bip;
-
-    return bip_buffer_write( bip, buf, len );
-}
-
-
-static void  _fh_socketpair_hook( FH  f, int  event, EventHook  hook );  /* forward */
-
-static const FHClassRec  _fh_socketpair_class =
-{
-    _fh_socketpair_init,
-    _fh_socketpair_close,
-    _fh_socketpair_lseek,
-    _fh_socketpair_read,
-    _fh_socketpair_write,
-    _fh_socketpair_hook
-};
-
-
-int  adb_socketpair( int  sv[2] )
-{
-    FH          fa, fb;
-    SocketPair  pair;
-
-    fa = _fh_alloc( &_fh_socketpair_class );
-    fb = _fh_alloc( &_fh_socketpair_class );
-
-    if (!fa || !fb)
-        goto Fail;
-
-    pair = malloc( sizeof(*pair) );
-    if (pair == NULL) {
-        D("adb_socketpair: not enough memory to allocate pipes\n" );
-        goto Fail;
-    }
-
-    bip_buffer_init( &pair->a2b_bip );
-    bip_buffer_init( &pair->b2a_bip );
-
-    fa->fh_pair = pair;
-    fb->fh_pair = pair;
-    pair->used  = 2;
-    pair->a_fd  = fa;
-
-    sv[0] = _fh_to_int(fa);
-    sv[1] = _fh_to_int(fb);
-
-    pair->a2b_bip.fdin  = sv[0];
-    pair->a2b_bip.fdout = sv[1];
-    pair->b2a_bip.fdin  = sv[1];
-    pair->b2a_bip.fdout = sv[0];
-
-    snprintf( fa->name, sizeof(fa->name), "%d(pair:%d)", sv[0], sv[1] );
-    snprintf( fb->name, sizeof(fb->name), "%d(pair:%d)", sv[1], sv[0] );
-    D( "adb_socketpair: returns (%d, %d)\n", sv[0], sv[1] );
-    return 0;
-
-Fail:
-    _fh_close(fb);
-    _fh_close(fa);
-    return -1;
-}
-
-/**************************************************************************/
-/**************************************************************************/
-/*****                                                                *****/
-/*****    fdevents emulation                                          *****/
-/*****                                                                *****/
-/*****   this is a very simple implementation, we rely on the fact    *****/
-/*****   that ADB doesn't use FDE_ERROR.                              *****/
-/*****                                                                *****/
-/**************************************************************************/
-/**************************************************************************/
-
-#define FATAL(x...) fatal(__FUNCTION__, x)
-
-#if DEBUG
-static void dump_fde(fdevent *fde, const char *info)
-{
-    fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd,
-            fde->state & FDE_READ ? 'R' : ' ',
-            fde->state & FDE_WRITE ? 'W' : ' ',
-            fde->state & FDE_ERROR ? 'E' : ' ',
-            info);
-}
-#else
-#define dump_fde(fde, info) do { } while(0)
-#endif
-
-#define FDE_EVENTMASK  0x00ff
-#define FDE_STATEMASK  0xff00
-
-#define FDE_ACTIVE     0x0100
-#define FDE_PENDING    0x0200
-#define FDE_CREATED    0x0400
-
-static void fdevent_plist_enqueue(fdevent *node);
-static void fdevent_plist_remove(fdevent *node);
-static fdevent *fdevent_plist_dequeue(void);
-
-static fdevent list_pending = {
-    .next = &list_pending,
-    .prev = &list_pending,
-};
-
-static fdevent **fd_table = 0;
-static int       fd_table_max = 0;
-
-typedef struct EventLooperRec_*  EventLooper;
-
-typedef struct EventHookRec_
-{
-    EventHook    next;
-    FH           fh;
-    HANDLE       h;
-    int          wanted;   /* wanted event flags */
-    int          ready;    /* ready event flags  */
-    void*        aux;
-    void        (*prepare)( EventHook  hook );
-    int         (*start)  ( EventHook  hook );
-    void        (*stop)   ( EventHook  hook );
-    int         (*check)  ( EventHook  hook );
-    int         (*peek)   ( EventHook  hook );
-} EventHookRec;
-
-static EventHook  _free_hooks;
-
-static EventHook
-event_hook_alloc( FH  fh )
-{
-    EventHook  hook = _free_hooks;
-    if (hook != NULL)
-        _free_hooks = hook->next;
-    else {
-        hook = malloc( sizeof(*hook) );
-        if (hook == NULL)
-            fatal( "could not allocate event hook\n" );
-    }
-    hook->next   = NULL;
-    hook->fh     = fh;
-    hook->wanted = 0;
-    hook->ready  = 0;
-    hook->h      = INVALID_HANDLE_VALUE;
-    hook->aux    = NULL;
-
-    hook->prepare = NULL;
-    hook->start   = NULL;
-    hook->stop    = NULL;
-    hook->check   = NULL;
-    hook->peek    = NULL;
-
-    return hook;
-}
-
-static void
-event_hook_free( EventHook  hook )
-{
-    hook->fh     = NULL;
-    hook->wanted = 0;
-    hook->ready  = 0;
-    hook->next   = _free_hooks;
-    _free_hooks  = hook;
-}
-
-
-static void
-event_hook_signal( EventHook  hook )
-{
-    FH        f   = hook->fh;
-    int       fd  = _fh_to_int(f);
-    fdevent*  fde = fd_table[ fd - WIN32_FH_BASE ];
-
-    if (fde != NULL && fde->fd == fd) {
-        if ((fde->state & FDE_PENDING) == 0) {
-            fde->state |= FDE_PENDING;
-            fdevent_plist_enqueue( fde );
-        }
-        fde->events |= hook->wanted;
-    }
-}
-
-
-#define  MAX_LOOPER_HANDLES  WIN32_MAX_FHS
-
-typedef struct EventLooperRec_
-{
-    EventHook    hooks;
-    HANDLE       htab[ MAX_LOOPER_HANDLES ];
-    int          htab_count;
-
-} EventLooperRec;
-
-static EventHook*
-event_looper_find_p( EventLooper  looper, FH  fh )
-{
-    EventHook  *pnode = &looper->hooks;
-    EventHook   node  = *pnode;
-    for (;;) {
-        if ( node == NULL || node->fh == fh )
-            break;
-        pnode = &node->next;
-        node  = *pnode;
-    }
-    return  pnode;
-}
-
-static void
-event_looper_hook( EventLooper  looper, int  fd, int  events )
-{
-    FH          f = _fh_from_int(fd);
-    EventHook  *pnode;
-    EventHook   node;
-
-    if (f == NULL)  /* invalid arg */ {
-        D("event_looper_hook: invalid fd=%d\n", fd);
-        return;
-    }
-
-    pnode = event_looper_find_p( looper, f );
-    node  = *pnode;
-    if ( node == NULL ) {
-        node       = event_hook_alloc( f );
-        node->next = *pnode;
-        *pnode     = node;
-    }
-
-    if ( (node->wanted & events) != events ) {
-        /* this should update start/stop/check/peek */
-        D("event_looper_hook: call hook for %d (new=%x, old=%x)\n",
-           fd, node->wanted, events);
-        f->clazz->_fh_hook( f, events & ~node->wanted, node );
-        node->wanted |= events;
-    } else {
-        D("event_looper_hook: ignoring events %x for %d wanted=%x)\n",
-           events, fd, node->wanted);
-    }
-}
-
-static void
-event_looper_unhook( EventLooper  looper, int  fd, int  events )
-{
-    FH          fh    = _fh_from_int(fd);
-    EventHook  *pnode = event_looper_find_p( looper, fh );
-    EventHook   node  = *pnode;
-
-    if (node != NULL) {
-        int  events2 = events & node->wanted;
-        if ( events2 == 0 ) {
-            D( "event_looper_unhook: events %x not registered for fd %d\n", events, fd );
-            return;
-        }
-        node->wanted &= ~events2;
-        if (!node->wanted) {
-            *pnode = node->next;
-            event_hook_free( node );
-        }
-    }
-}
-
-/*
- * A fixer for WaitForMultipleObjects on condition that there are more than 64
- * handles to wait on.
- *
- * In cetain cases DDMS may establish more than 64 connections with ADB. For
- * instance, this may happen if there are more than 64 processes running on a
- * device, or there are multiple devices connected (including the emulator) with
- * the combined number of running processes greater than 64. In this case using
- * WaitForMultipleObjects to wait on connection events simply wouldn't cut,
- * because of the API limitations (64 handles max). So, we need to provide a way
- * to scale WaitForMultipleObjects to accept an arbitrary number of handles. The
- * easiest (and "Microsoft recommended") way to do that would be dividing the
- * handle array into chunks with the chunk size less than 64, and fire up as many
- * waiting threads as there are chunks. Then each thread would wait on a chunk of
- * handles, and will report back to the caller which handle has been set.
- * Here is the implementation of that algorithm.
- */
-
-/* Number of handles to wait on in each wating thread. */
-#define WAIT_ALL_CHUNK_SIZE 63
-
-/* Descriptor for a wating thread */
-typedef struct WaitForAllParam {
-    /* A handle to an event to signal when waiting is over. This handle is shared
-     * accross all the waiting threads, so each waiting thread knows when any
-     * other thread has exited, so it can exit too. */
-    HANDLE          main_event;
-    /* Upon exit from a waiting thread contains the index of the handle that has
-     * been signaled. The index is an absolute index of the signaled handle in
-     * the original array. This pointer is shared accross all the waiting threads
-     * and it's not guaranteed (due to a race condition) that when all the
-     * waiting threads exit, the value contained here would indicate the first
-     * handle that was signaled. This is fine, because the caller cares only
-     * about any handle being signaled. It doesn't care about the order, nor
-     * about the whole list of handles that were signaled. */
-    LONG volatile   *signaled_index;
-    /* Array of handles to wait on in a waiting thread. */
-    HANDLE*         handles;
-    /* Number of handles in 'handles' array to wait on. */
-    int             handles_count;
-    /* Index inside the main array of the first handle in the 'handles' array. */
-    int             first_handle_index;
-    /* Waiting thread handle. */
-    HANDLE          thread;
-} WaitForAllParam;
-
-/* Waiting thread routine. */
-static unsigned __stdcall
-_in_waiter_thread(void*  arg)
-{
-    HANDLE wait_on[WAIT_ALL_CHUNK_SIZE + 1];
-    int res;
-    WaitForAllParam* const param = (WaitForAllParam*)arg;
-
-    /* We have to wait on the main_event in order to be notified when any of the
-     * sibling threads is exiting. */
-    wait_on[0] = param->main_event;
-    /* The rest of the handles go behind the main event handle. */
-    memcpy(wait_on + 1, param->handles, param->handles_count * sizeof(HANDLE));
-
-    res = WaitForMultipleObjects(param->handles_count + 1, wait_on, FALSE, INFINITE);
-    if (res > 0 && res < (param->handles_count + 1)) {
-        /* One of the original handles got signaled. Save its absolute index into
-         * the output variable. */
-        InterlockedCompareExchange(param->signaled_index,
-                                   res - 1L + param->first_handle_index, -1L);
-    }
-
-    /* Notify the caller (and the siblings) that the wait is over. */
-    SetEvent(param->main_event);
-
-    _endthreadex(0);
-    return 0;
-}
-
-/* WaitForMultipeObjects fixer routine.
- * Param:
- *  handles Array of handles to wait on.
- *  handles_count Number of handles in the array.
- * Return:
- *  (>= 0 && < handles_count) - Index of the signaled handle in the array, or
- *  WAIT_FAILED on an error.
- */
-static int
-_wait_for_all(HANDLE* handles, int handles_count)
-{
-    WaitForAllParam* threads;
-    HANDLE main_event;
-    int chunks, chunk, remains;
-
-    /* This variable is going to be accessed by several threads at the same time,
-     * this is bound to fail randomly when the core is run on multi-core machines.
-     * To solve this, we need to do the following (1 _and_ 2):
-     * 1. Use the "volatile" qualifier to ensure the compiler doesn't optimize
-     *    out the reads/writes in this function unexpectedly.
-     * 2. Ensure correct memory ordering. The "simple" way to do that is to wrap
-     *    all accesses inside a critical section. But we can also use
-     *    InterlockedCompareExchange() which always provide a full memory barrier
-     *    on Win32.
-     */
-    volatile LONG sig_index = -1;
-
-    /* Calculate number of chunks, and allocate thread param array. */
-    chunks = handles_count / WAIT_ALL_CHUNK_SIZE;
-    remains = handles_count % WAIT_ALL_CHUNK_SIZE;
-    threads = (WaitForAllParam*)malloc((chunks + (remains ? 1 : 0)) *
-                                        sizeof(WaitForAllParam));
-    if (threads == NULL) {
-        D("Unable to allocate thread array for %d handles.", handles_count);
-        return (int)WAIT_FAILED;
-    }
-
-    /* Create main event to wait on for all waiting threads. This is a "manualy
-     * reset" event that will remain set once it was set. */
-    main_event = CreateEvent(NULL, TRUE, FALSE, NULL);
-    if (main_event == NULL) {
-        D("Unable to create main event. Error: %d", (int)GetLastError());
-        free(threads);
-        return (int)WAIT_FAILED;
-    }
-
-    /*
-     * Initialize waiting thread parameters.
-     */
-
-    for (chunk = 0; chunk < chunks; chunk++) {
-        threads[chunk].main_event = main_event;
-        threads[chunk].signaled_index = &sig_index;
-        threads[chunk].first_handle_index = WAIT_ALL_CHUNK_SIZE * chunk;
-        threads[chunk].handles = handles + threads[chunk].first_handle_index;
-        threads[chunk].handles_count = WAIT_ALL_CHUNK_SIZE;
-    }
-    if (remains) {
-        threads[chunk].main_event = main_event;
-        threads[chunk].signaled_index = &sig_index;
-        threads[chunk].first_handle_index = WAIT_ALL_CHUNK_SIZE * chunk;
-        threads[chunk].handles = handles + threads[chunk].first_handle_index;
-        threads[chunk].handles_count = remains;
-        chunks++;
-    }
-
-    /* Start the waiting threads. */
-    for (chunk = 0; chunk < chunks; chunk++) {
-        /* Note that using adb_thread_create is not appropriate here, since we
-         * need a handle to wait on for thread termination. */
-        threads[chunk].thread = (HANDLE)_beginthreadex(NULL, 0, _in_waiter_thread,
-                                                       &threads[chunk], 0, NULL);
-        if (threads[chunk].thread == NULL) {
-            /* Unable to create a waiter thread. Collapse. */
-            D("Unable to create a waiting thread %d of %d. errno=%d",
-              chunk, chunks, errno);
-            chunks = chunk;
-            SetEvent(main_event);
-            break;
-        }
-    }
-
-    /* Wait on any of the threads to get signaled. */
-    WaitForSingleObject(main_event, INFINITE);
-
-    /* Wait on all the waiting threads to exit. */
-    for (chunk = 0; chunk < chunks; chunk++) {
-        WaitForSingleObject(threads[chunk].thread, INFINITE);
-        CloseHandle(threads[chunk].thread);
-    }
-
-    CloseHandle(main_event);
-    free(threads);
-
-
-    const int ret = (int)InterlockedCompareExchange(&sig_index, -1, -1);
-    return (ret >= 0) ? ret : (int)WAIT_FAILED;
-}
-
-static EventLooperRec  win32_looper;
-
-static void fdevent_init(void)
-{
-    win32_looper.htab_count = 0;
-    win32_looper.hooks      = NULL;
-}
-
-static void fdevent_connect(fdevent *fde)
-{
-    EventLooper  looper = &win32_looper;
-    int          events = fde->state & FDE_EVENTMASK;
-
-    if (events != 0)
-        event_looper_hook( looper, fde->fd, events );
-}
-
-static void fdevent_disconnect(fdevent *fde)
-{
-    EventLooper  looper = &win32_looper;
-    int          events = fde->state & FDE_EVENTMASK;
-
-    if (events != 0)
-        event_looper_unhook( looper, fde->fd, events );
-}
-
-static void fdevent_update(fdevent *fde, unsigned events)
-{
-    EventLooper  looper  = &win32_looper;
-    unsigned     events0 = fde->state & FDE_EVENTMASK;
-
-    if (events != events0) {
-        int  removes = events0 & ~events;
-        int  adds    = events  & ~events0;
-        if (removes) {
-            D("fdevent_update: remove %x from %d\n", removes, fde->fd);
-            event_looper_unhook( looper, fde->fd, removes );
-        }
-        if (adds) {
-            D("fdevent_update: add %x to %d\n", adds, fde->fd);
-            event_looper_hook  ( looper, fde->fd, adds );
-        }
-    }
-}
-
-static void fdevent_process()
-{
-    EventLooper  looper = &win32_looper;
-    EventHook    hook;
-    int          gotone = 0;
-
-    /* if we have at least one ready hook, execute it/them */
-    for (hook = looper->hooks; hook; hook = hook->next) {
-        hook->ready = 0;
-        if (hook->prepare) {
-            hook->prepare(hook);
-            if (hook->ready != 0) {
-                event_hook_signal( hook );
-                gotone = 1;
-            }
-        }
-    }
-
-    /* nothing's ready yet, so wait for something to happen */
-    if (!gotone)
-    {
-        looper->htab_count = 0;
-
-        for (hook = looper->hooks; hook; hook = hook->next)
-        {
-            if (hook->start && !hook->start(hook)) {
-                D( "fdevent_process: error when starting a hook\n" );
-                return;
-            }
-            if (hook->h != INVALID_HANDLE_VALUE) {
-                int  nn;
-
-                for (nn = 0; nn < looper->htab_count; nn++)
-                {
-                    if ( looper->htab[nn] == hook->h )
-                        goto DontAdd;
-                }
-                looper->htab[ looper->htab_count++ ] = hook->h;
-            DontAdd:
-                ;
-            }
-        }
-
-        if (looper->htab_count == 0) {
-            D( "fdevent_process: nothing to wait for !!\n" );
-            return;
-        }
-
-        do
-        {
-            int   wait_ret;
-
-            D( "adb_win32: waiting for %d events\n", looper->htab_count );
-            if (looper->htab_count > MAXIMUM_WAIT_OBJECTS) {
-                D("handle count %d exceeds MAXIMUM_WAIT_OBJECTS.\n", looper->htab_count);
-                wait_ret = _wait_for_all(looper->htab, looper->htab_count);
-            } else {
-                wait_ret = WaitForMultipleObjects( looper->htab_count, looper->htab, FALSE, INFINITE );
-            }
-            if (wait_ret == (int)WAIT_FAILED) {
-                D( "adb_win32: wait failed, error %ld\n", GetLastError() );
-            } else {
-                D( "adb_win32: got one (index %d)\n", wait_ret );
-
-                /* according to Cygwin, some objects like consoles wake up on "inappropriate" events
-                 * like mouse movements. we need to filter these with the "check" function
-                 */
-                if ((unsigned)wait_ret < (unsigned)looper->htab_count)
-                {
-                    for (hook = looper->hooks; hook; hook = hook->next)
-                    {
-                        if ( looper->htab[wait_ret] == hook->h       &&
-                         (!hook->check || hook->check(hook)) )
-                        {
-                            D( "adb_win32: signaling %s for %x\n", hook->fh->name, hook->ready );
-                            event_hook_signal( hook );
-                            gotone = 1;
-                            break;
-                        }
-                    }
-                }
-            }
-        }
-        while (!gotone);
-
-        for (hook = looper->hooks; hook; hook = hook->next) {
-            if (hook->stop)
-                hook->stop( hook );
-        }
-    }
-
-    for (hook = looper->hooks; hook; hook = hook->next) {
-        if (hook->peek && hook->peek(hook))
-                event_hook_signal( hook );
-    }
-}
-
-
-static void fdevent_register(fdevent *fde)
-{
-    int  fd = fde->fd - WIN32_FH_BASE;
-
-    if(fd < 0) {
-        FATAL("bogus negative fd (%d)\n", fde->fd);
-    }
-
-    if(fd >= fd_table_max) {
-        int oldmax = fd_table_max;
-        if(fde->fd > 32000) {
-            FATAL("bogus huuuuge fd (%d)\n", fde->fd);
-        }
-        if(fd_table_max == 0) {
-            fdevent_init();
-            fd_table_max = 256;
-        }
-        while(fd_table_max <= fd) {
-            fd_table_max *= 2;
-        }
-        fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max);
-        if(fd_table == 0) {
-            FATAL("could not expand fd_table to %d entries\n", fd_table_max);
-        }
-        memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax));
-    }
-
-    fd_table[fd] = fde;
-}
-
-static void fdevent_unregister(fdevent *fde)
-{
-    int  fd = fde->fd - WIN32_FH_BASE;
-
-    if((fd < 0) || (fd >= fd_table_max)) {
-        FATAL("fd out of range (%d)\n", fde->fd);
-    }
-
-    if(fd_table[fd] != fde) {
-        FATAL("fd_table out of sync");
-    }
-
-    fd_table[fd] = 0;
-
-    if(!(fde->state & FDE_DONT_CLOSE)) {
-        dump_fde(fde, "close");
-        adb_close(fde->fd);
-    }
-}
-
-static void fdevent_plist_enqueue(fdevent *node)
-{
-    fdevent *list = &list_pending;
-
-    node->next = list;
-    node->prev = list->prev;
-    node->prev->next = node;
-    list->prev = node;
-}
-
-static void fdevent_plist_remove(fdevent *node)
-{
-    node->prev->next = node->next;
-    node->next->prev = node->prev;
-    node->next = 0;
-    node->prev = 0;
-}
-
-static fdevent *fdevent_plist_dequeue(void)
-{
-    fdevent *list = &list_pending;
-    fdevent *node = list->next;
-
-    if(node == list) return 0;
-
-    list->next = node->next;
-    list->next->prev = list;
-    node->next = 0;
-    node->prev = 0;
-
-    return node;
-}
-
-fdevent *fdevent_create(int fd, fd_func func, void *arg)
-{
-    fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
-    if(fde == 0) return 0;
-    fdevent_install(fde, fd, func, arg);
-    fde->state |= FDE_CREATED;
-    return fde;
-}
-
-void fdevent_destroy(fdevent *fde)
-{
-    if(fde == 0) return;
-    if(!(fde->state & FDE_CREATED)) {
-        FATAL("fde %p not created by fdevent_create()\n", fde);
-    }
-    fdevent_remove(fde);
-}
-
-void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg)
-{
-    memset(fde, 0, sizeof(fdevent));
-    fde->state = FDE_ACTIVE;
-    fde->fd = fd;
-    fde->func = func;
-    fde->arg = arg;
-
-    fdevent_register(fde);
-    dump_fde(fde, "connect");
-    fdevent_connect(fde);
-    fde->state |= FDE_ACTIVE;
-}
-
-void fdevent_remove(fdevent *fde)
-{
-    if(fde->state & FDE_PENDING) {
-        fdevent_plist_remove(fde);
-    }
-
-    if(fde->state & FDE_ACTIVE) {
-        fdevent_disconnect(fde);
-        dump_fde(fde, "disconnect");
-        fdevent_unregister(fde);
-    }
-
-    fde->state = 0;
-    fde->events = 0;
-}
-
-
-void fdevent_set(fdevent *fde, unsigned events)
-{
-    events &= FDE_EVENTMASK;
-
-    if((fde->state & FDE_EVENTMASK) == (int)events) return;
-
-    if(fde->state & FDE_ACTIVE) {
-        fdevent_update(fde, events);
-        dump_fde(fde, "update");
-    }
-
-    fde->state = (fde->state & FDE_STATEMASK) | events;
-
-    if(fde->state & FDE_PENDING) {
-            /* if we're pending, make sure
-            ** we don't signal an event that
-            ** is no longer wanted.
-            */
-        fde->events &= (~events);
-        if(fde->events == 0) {
-            fdevent_plist_remove(fde);
-            fde->state &= (~FDE_PENDING);
-        }
-    }
-}
-
-void fdevent_add(fdevent *fde, unsigned events)
-{
-    fdevent_set(
-        fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK));
-}
-
-void fdevent_del(fdevent *fde, unsigned events)
-{
-    fdevent_set(
-        fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
-}
-
-void fdevent_loop()
-{
-    fdevent *fde;
-
-    for(;;) {
-#if DEBUG
-        fprintf(stderr,"--- ---- waiting for events\n");
-#endif
-        fdevent_process();
-
-        while((fde = fdevent_plist_dequeue())) {
-            unsigned events = fde->events;
-            fde->events = 0;
-            fde->state &= (~FDE_PENDING);
-            dump_fde(fde, "callback");
-            fde->func(fde->fd, events, fde->arg);
-        }
-    }
-}
-
-/**  FILE EVENT HOOKS
- **/
-
-static void  _event_file_prepare( EventHook  hook )
-{
-    if (hook->wanted & (FDE_READ|FDE_WRITE)) {
-        /* we can always read/write */
-        hook->ready |= hook->wanted & (FDE_READ|FDE_WRITE);
-    }
-}
-
-static int  _event_file_peek( EventHook  hook )
-{
-    return (hook->wanted & (FDE_READ|FDE_WRITE));
-}
-
-static void  _fh_file_hook( FH  f, int  events, EventHook  hook )
-{
-    hook->h       = f->fh_handle;
-    hook->prepare = _event_file_prepare;
-    hook->peek    = _event_file_peek;
-}
-
-/** SOCKET EVENT HOOKS
- **/
-
-static void  _event_socket_verify( EventHook  hook, WSANETWORKEVENTS*  evts )
-{
-    if ( evts->lNetworkEvents & (FD_READ|FD_ACCEPT|FD_CLOSE) ) {
-        if (hook->wanted & FDE_READ)
-            hook->ready |= FDE_READ;
-        if ((evts->iErrorCode[FD_READ] != 0) && hook->wanted & FDE_ERROR)
-            hook->ready |= FDE_ERROR;
-    }
-    if ( evts->lNetworkEvents & (FD_WRITE|FD_CONNECT|FD_CLOSE) ) {
-        if (hook->wanted & FDE_WRITE)
-            hook->ready |= FDE_WRITE;
-        if ((evts->iErrorCode[FD_WRITE] != 0) && hook->wanted & FDE_ERROR)
-            hook->ready |= FDE_ERROR;
-    }
-    if ( evts->lNetworkEvents & FD_OOB ) {
-        if (hook->wanted & FDE_ERROR)
-            hook->ready |= FDE_ERROR;
-    }
-}
-
-static void  _event_socket_prepare( EventHook  hook )
-{
-    WSANETWORKEVENTS  evts;
-
-    /* look if some of the events we want already happened ? */
-    if (!WSAEnumNetworkEvents( hook->fh->fh_socket, NULL, &evts ))
-        _event_socket_verify( hook, &evts );
-}
-
-static int  _socket_wanted_to_flags( int  wanted )
-{
-    int  flags = 0;
-    if (wanted & FDE_READ)
-        flags |= FD_READ | FD_ACCEPT | FD_CLOSE;
-
-    if (wanted & FDE_WRITE)
-        flags |= FD_WRITE | FD_CONNECT | FD_CLOSE;
-
-    if (wanted & FDE_ERROR)
-        flags |= FD_OOB;
-
-    return flags;
-}
-
-static int _event_socket_start( EventHook  hook )
-{
-    /* create an event which we're going to wait for */
-    FH    fh    = hook->fh;
-    long  flags = _socket_wanted_to_flags( hook->wanted );
-
-    hook->h = fh->event;
-    if (hook->h == INVALID_HANDLE_VALUE) {
-        D( "_event_socket_start: no event for %s\n", fh->name );
-        return 0;
-    }
-
-    if ( flags != fh->mask ) {
-        D( "_event_socket_start: hooking %s for %x (flags %ld)\n", hook->fh->name, hook->wanted, flags );
-        if ( WSAEventSelect( fh->fh_socket, hook->h, flags ) ) {
-            D( "_event_socket_start: WSAEventSelect() for %s failed, error %d\n", hook->fh->name, WSAGetLastError() );
-            CloseHandle( hook->h );
-            hook->h = INVALID_HANDLE_VALUE;
-            exit(1);
-            return 0;
-        }
-        fh->mask = flags;
-    }
-    return 1;
-}
-
-static void _event_socket_stop( EventHook  hook )
-{
-    hook->h = INVALID_HANDLE_VALUE;
-}
-
-static int  _event_socket_check( EventHook  hook )
-{
-    int               result = 0;
-    FH                fh = hook->fh;
-    WSANETWORKEVENTS  evts;
-
-    if (!WSAEnumNetworkEvents( fh->fh_socket, hook->h, &evts ) ) {
-        _event_socket_verify( hook, &evts );
-        result = (hook->ready != 0);
-        if (result) {
-            ResetEvent( hook->h );
-        }
-    }
-    D( "_event_socket_check %s returns %d\n", fh->name, result );
-    return  result;
-}
-
-static int  _event_socket_peek( EventHook  hook )
-{
-    WSANETWORKEVENTS  evts;
-    FH                fh = hook->fh;
-
-    /* look if some of the events we want already happened ? */
-    if (!WSAEnumNetworkEvents( fh->fh_socket, NULL, &evts )) {
-        _event_socket_verify( hook, &evts );
-        if (hook->ready)
-            ResetEvent( hook->h );
-    }
-
-    return hook->ready != 0;
-}
-
-
-
-static void  _fh_socket_hook( FH  f, int  events, EventHook  hook )
-{
-    hook->prepare = _event_socket_prepare;
-    hook->start   = _event_socket_start;
-    hook->stop    = _event_socket_stop;
-    hook->check   = _event_socket_check;
-    hook->peek    = _event_socket_peek;
-
-    _event_socket_start( hook );
-}
-
-/** SOCKETPAIR EVENT HOOKS
- **/
-
-static void  _event_socketpair_prepare( EventHook  hook )
-{
-    FH          fh   = hook->fh;
-    SocketPair  pair = fh->fh_pair;
-    BipBuffer   rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip;
-    BipBuffer   wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip;
-
-    if (hook->wanted & FDE_READ && rbip->can_read)
-        hook->ready |= FDE_READ;
-
-    if (hook->wanted & FDE_WRITE && wbip->can_write)
-        hook->ready |= FDE_WRITE;
- }
-
- static int  _event_socketpair_start( EventHook  hook )
- {
-    FH          fh   = hook->fh;
-    SocketPair  pair = fh->fh_pair;
-    BipBuffer   rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip;
-    BipBuffer   wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip;
-
-    if (hook->wanted == FDE_READ)
-        hook->h = rbip->evt_read;
-
-    else if (hook->wanted == FDE_WRITE)
-        hook->h = wbip->evt_write;
-
-    else {
-        D("_event_socketpair_start: can't handle FDE_READ+FDE_WRITE\n" );
-        return 0;
-    }
-    D( "_event_socketpair_start: hook %s for %x wanted=%x\n",
-       hook->fh->name, _fh_to_int(fh), hook->wanted);
-    return 1;
-}
-
-static int  _event_socketpair_peek( EventHook  hook )
-{
-    _event_socketpair_prepare( hook );
-    return hook->ready != 0;
-}
-
-static void  _fh_socketpair_hook( FH  fh, int  events, EventHook  hook )
-{
-    hook->prepare = _event_socketpair_prepare;
-    hook->start   = _event_socketpair_start;
-    hook->peek    = _event_socketpair_peek;
-}
-
-
-void
-adb_sysdeps_init( void )
-{
-#define  ADB_MUTEX(x)  InitializeCriticalSection( & x );
-#include "mutex_list.h"
-    InitializeCriticalSection( &_win32_lock );
-}
-
-/* Windows doesn't have strtok_r.  Use the one from bionic. */
-
-/*
- * Copyright (c) 1988 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
- */
-
-char *
-adb_strtok_r(char *s, const char *delim, char **last)
-{
-	char *spanp;
-	int c, sc;
-	char *tok;
-
-
-	if (s == NULL && (s = *last) == NULL)
-		return (NULL);
-
-	/*
-	 * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
-	 */
-cont:
-	c = *s++;
-	for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
-		if (c == sc)
-			goto cont;
-	}
-
-	if (c == 0) {		/* no non-delimiter characters */
-		*last = NULL;
-		return (NULL);
-	}
-	tok = s - 1;
-
-	/*
-	 * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
-	 * Note that delim must have one NUL; we stop if we see that, too.
-	 */
-	for (;;) {
-		c = *s++;
-		spanp = (char *)delim;
-		do {
-			if ((sc = *spanp++) == c) {
-				if (c == 0)
-					s = NULL;
-				else
-					s[-1] = 0;
-				*last = s;
-				return (tok);
-			}
-		} while (sc != 0);
-	}
-	/* NOTREACHED */
-}
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
new file mode 100644
index 0000000..a21272f
--- /dev/null
+++ b/adb/sysdeps_win32.cpp
@@ -0,0 +1,3053 @@
+/*
+ * 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 TRACE_SYSDEPS
+
+#include "sysdeps.h"
+
+#include <winsock2.h> /* winsock.h *must* be included before windows.h. */
+#include <windows.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "adb.h"
+
+extern void fatal(const char *fmt, ...);
+
+/* forward declarations */
+
+typedef const struct FHClassRec_* FHClass;
+typedef struct FHRec_* FH;
+typedef struct EventHookRec_* EventHook;
+
+typedef struct FHClassRec_ {
+    void (*_fh_init)(FH);
+    int (*_fh_close)(FH);
+    int (*_fh_lseek)(FH, int, int);
+    int (*_fh_read)(FH, void*, int);
+    int (*_fh_write)(FH, const void*, int);
+    void (*_fh_hook)(FH, int, EventHook);
+} FHClassRec;
+
+static void _fh_file_init(FH);
+static int _fh_file_close(FH);
+static int _fh_file_lseek(FH, int, int);
+static int _fh_file_read(FH, void*, int);
+static int _fh_file_write(FH, const void*, int);
+static void _fh_file_hook(FH, int, EventHook);
+
+static const FHClassRec _fh_file_class = {
+    _fh_file_init,
+    _fh_file_close,
+    _fh_file_lseek,
+    _fh_file_read,
+    _fh_file_write,
+    _fh_file_hook
+};
+
+static void _fh_socket_init(FH);
+static int _fh_socket_close(FH);
+static int _fh_socket_lseek(FH, int, int);
+static int _fh_socket_read(FH, void*, int);
+static int _fh_socket_write(FH, const void*, int);
+static void _fh_socket_hook(FH, int, EventHook);
+
+static const FHClassRec _fh_socket_class = {
+    _fh_socket_init,
+    _fh_socket_close,
+    _fh_socket_lseek,
+    _fh_socket_read,
+    _fh_socket_write,
+    _fh_socket_hook
+};
+
+#define assert(cond)  do { if (!(cond)) fatal( "assertion failed '%s' on %s:%ld\n", #cond, __FILE__, __LINE__ ); } while (0)
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****      replaces libs/cutils/load_file.c                          *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+void *load_file(const char *fn, unsigned *_sz)
+{
+    HANDLE    file;
+    char     *data;
+    DWORD     file_size;
+
+    file = CreateFile( fn,
+                       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\n", 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'\n", file_size, fn);
+                free(data);
+                data      = NULL;
+                file_size = 0;
+            }
+        }
+    }
+    CloseHandle( file );
+
+    *_sz = (unsigned) file_size;
+    return  data;
+}
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****    common file descriptor handling                             *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+/* used to emulate unix-domain socket pairs */
+typedef struct SocketPairRec_*  SocketPair;
+
+typedef struct FHRec_
+{
+    FHClass    clazz;
+    int        used;
+    int        eof;
+    union {
+        HANDLE      handle;
+        SOCKET      socket;
+        SocketPair  pair;
+    } u;
+
+    HANDLE    event;
+    int       mask;
+
+    char  name[32];
+
+} FHRec;
+
+#define  fh_handle  u.handle
+#define  fh_socket  u.socket
+#define  fh_pair    u.pair
+
+#define  WIN32_FH_BASE    100
+
+#define  WIN32_MAX_FHS    128
+
+static adb_mutex_t   _win32_lock;
+static  FHRec        _win32_fhs[ WIN32_MAX_FHS ];
+static  int          _win32_fh_count;
+
+static FH
+_fh_from_int( int   fd )
+{
+    FH  f;
+
+    fd -= WIN32_FH_BASE;
+
+    if (fd < 0 || fd >= _win32_fh_count) {
+        D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE );
+        errno = EBADF;
+        return NULL;
+    }
+
+    f = &_win32_fhs[fd];
+
+    if (f->used == 0) {
+        D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE );
+        errno = EBADF;
+        return NULL;
+    }
+
+    return f;
+}
+
+
+static int
+_fh_to_int( FH  f )
+{
+    if (f && f->used && f >= _win32_fhs && f < _win32_fhs + WIN32_MAX_FHS)
+        return (int)(f - _win32_fhs) + WIN32_FH_BASE;
+
+    return -1;
+}
+
+static FH
+_fh_alloc( FHClass  clazz )
+{
+    int  nn;
+    FH   f = NULL;
+
+    adb_mutex_lock( &_win32_lock );
+
+    if (_win32_fh_count < WIN32_MAX_FHS) {
+        f = &_win32_fhs[ _win32_fh_count++ ];
+        goto Exit;
+    }
+
+    for (nn = 0; nn < WIN32_MAX_FHS; nn++) {
+        if ( _win32_fhs[nn].clazz == NULL) {
+            f = &_win32_fhs[nn];
+            goto Exit;
+        }
+    }
+    D( "_fh_alloc: no more free file descriptors\n" );
+Exit:
+    if (f) {
+        f->clazz = clazz;
+        f->used  = 1;
+        f->eof   = 0;
+        clazz->_fh_init(f);
+    }
+    adb_mutex_unlock( &_win32_lock );
+    return f;
+}
+
+
+static int
+_fh_close( FH   f )
+{
+    if ( f->used ) {
+        f->clazz->_fh_close( f );
+        f->used = 0;
+        f->eof  = 0;
+        f->clazz = NULL;
+    }
+    return 0;
+}
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****    file-based descriptor handling                              *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+static void _fh_file_init( FH  f ) {
+    f->fh_handle = INVALID_HANDLE_VALUE;
+}
+
+static int _fh_file_close( FH  f ) {
+    CloseHandle( f->fh_handle );
+    f->fh_handle = INVALID_HANDLE_VALUE;
+    return 0;
+}
+
+static int _fh_file_read( FH  f,  void*  buf, int   len ) {
+    DWORD  read_bytes;
+
+    if ( !ReadFile( f->fh_handle, buf, (DWORD)len, &read_bytes, NULL ) ) {
+        D( "adb_read: could not read %d bytes from %s\n", len, f->name );
+        errno = EIO;
+        return -1;
+    } else if (read_bytes < (DWORD)len) {
+        f->eof = 1;
+    }
+    return (int)read_bytes;
+}
+
+static int _fh_file_write( FH  f,  const void*  buf, int   len ) {
+    DWORD  wrote_bytes;
+
+    if ( !WriteFile( f->fh_handle, buf, (DWORD)len, &wrote_bytes, NULL ) ) {
+        D( "adb_file_write: could not write %d bytes from %s\n", len, f->name );
+        errno = EIO;
+        return -1;
+    } else if (wrote_bytes < (DWORD)len) {
+        f->eof = 1;
+    }
+    return  (int)wrote_bytes;
+}
+
+static int _fh_file_lseek( FH  f, int  pos, int  origin ) {
+    DWORD  method;
+    DWORD  result;
+
+    switch (origin)
+    {
+        case SEEK_SET:  method = FILE_BEGIN; break;
+        case SEEK_CUR:  method = FILE_CURRENT; break;
+        case SEEK_END:  method = FILE_END; break;
+        default:
+            errno = EINVAL;
+            return -1;
+    }
+
+    result = SetFilePointer( f->fh_handle, pos, NULL, method );
+    if (result == INVALID_SET_FILE_POINTER) {
+        errno = EIO;
+        return -1;
+    } else {
+        f->eof = 0;
+    }
+    return (int)result;
+}
+
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****    file-based descriptor handling                              *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+int  adb_open(const char*  path, int  options)
+{
+    FH  f;
+
+    DWORD  desiredAccess       = 0;
+    DWORD  shareMode           = FILE_SHARE_READ | FILE_SHARE_WRITE;
+
+    switch (options) {
+        case O_RDONLY:
+            desiredAccess = GENERIC_READ;
+            break;
+        case O_WRONLY:
+            desiredAccess = GENERIC_WRITE;
+            break;
+        case O_RDWR:
+            desiredAccess = GENERIC_READ | GENERIC_WRITE;
+            break;
+        default:
+            D("adb_open: invalid options (0x%0x)\n", options);
+            errno = EINVAL;
+            return -1;
+    }
+
+    f = _fh_alloc( &_fh_file_class );
+    if ( !f ) {
+        errno = ENOMEM;
+        return -1;
+    }
+
+    f->fh_handle = CreateFile( path, desiredAccess, shareMode, NULL, OPEN_EXISTING,
+                               0, NULL );
+
+    if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
+        _fh_close(f);
+        D( "adb_open: could not open '%s':", path );
+        switch (GetLastError()) {
+            case ERROR_FILE_NOT_FOUND:
+                D( "file not found\n" );
+                errno = ENOENT;
+                return -1;
+
+            case ERROR_PATH_NOT_FOUND:
+                D( "path not found\n" );
+                errno = ENOTDIR;
+                return -1;
+
+            default:
+                D( "unknown error\n" );
+                errno = ENOENT;
+                return -1;
+        }
+    }
+
+    snprintf( f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path );
+    D( "adb_open: '%s' => fd %d\n", path, _fh_to_int(f) );
+    return _fh_to_int(f);
+}
+
+/* ignore mode on Win32 */
+int  adb_creat(const char*  path, int  mode)
+{
+    FH  f;
+
+    f = _fh_alloc( &_fh_file_class );
+    if ( !f ) {
+        errno = ENOMEM;
+        return -1;
+    }
+
+    f->fh_handle = CreateFile( path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+                               NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
+                               NULL );
+
+    if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
+        _fh_close(f);
+        D( "adb_creat: could not open '%s':", path );
+        switch (GetLastError()) {
+            case ERROR_FILE_NOT_FOUND:
+                D( "file not found\n" );
+                errno = ENOENT;
+                return -1;
+
+            case ERROR_PATH_NOT_FOUND:
+                D( "path not found\n" );
+                errno = ENOTDIR;
+                return -1;
+
+            default:
+                D( "unknown error\n" );
+                errno = ENOENT;
+                return -1;
+        }
+    }
+    snprintf( f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path );
+    D( "adb_creat: '%s' => fd %d\n", path, _fh_to_int(f) );
+    return _fh_to_int(f);
+}
+
+
+int  adb_read(int  fd, void* buf, int len)
+{
+    FH     f = _fh_from_int(fd);
+
+    if (f == NULL) {
+        return -1;
+    }
+
+    return f->clazz->_fh_read( f, buf, len );
+}
+
+
+int  adb_write(int  fd, const void*  buf, int  len)
+{
+    FH     f = _fh_from_int(fd);
+
+    if (f == NULL) {
+        return -1;
+    }
+
+    return f->clazz->_fh_write(f, buf, len);
+}
+
+
+int  adb_lseek(int  fd, int  pos, int  where)
+{
+    FH     f = _fh_from_int(fd);
+
+    if (!f) {
+        return -1;
+    }
+
+    return f->clazz->_fh_lseek(f, pos, where);
+}
+
+
+int  adb_shutdown(int  fd)
+{
+    FH   f = _fh_from_int(fd);
+
+    if (!f || f->clazz != &_fh_socket_class) {
+        D("adb_shutdown: invalid fd %d\n", fd);
+        return -1;
+    }
+
+    D( "adb_shutdown: %s\n", f->name);
+    shutdown( f->fh_socket, SD_BOTH );
+    return 0;
+}
+
+
+int  adb_close(int  fd)
+{
+    FH   f = _fh_from_int(fd);
+
+    if (!f) {
+        return -1;
+    }
+
+    D( "adb_close: %s\n", f->name);
+    _fh_close(f);
+    return 0;
+}
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****    socket-based file descriptors                               *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+#undef setsockopt
+
+static void _socket_set_errno( void ) {
+    switch (WSAGetLastError()) {
+    case 0:              errno = 0; break;
+    case WSAEWOULDBLOCK: errno = EAGAIN; break;
+    case WSAEINTR:       errno = EINTR; break;
+    default:
+        D( "_socket_set_errno: unhandled value %d\n", WSAGetLastError() );
+        errno = EINVAL;
+    }
+}
+
+static void _fh_socket_init( FH  f ) {
+    f->fh_socket = INVALID_SOCKET;
+    f->event     = WSACreateEvent();
+    f->mask      = 0;
+}
+
+static int _fh_socket_close( FH  f ) {
+    /* gently tell any peer that we're closing the socket */
+    shutdown( f->fh_socket, SD_BOTH );
+    closesocket( f->fh_socket );
+    f->fh_socket = INVALID_SOCKET;
+    CloseHandle( f->event );
+    f->mask = 0;
+    return 0;
+}
+
+static int _fh_socket_lseek( FH  f, int pos, int origin ) {
+    errno = EPIPE;
+    return -1;
+}
+
+static int _fh_socket_read(FH f, void* buf, int len) {
+    int  result = recv(f->fh_socket, reinterpret_cast<char*>(buf), len, 0);
+    if (result == SOCKET_ERROR) {
+        _socket_set_errno();
+        result = -1;
+    }
+    return  result;
+}
+
+static int _fh_socket_write(FH f, const void* buf, int len) {
+    int  result = send(f->fh_socket, reinterpret_cast<const char*>(buf), len, 0);
+    if (result == SOCKET_ERROR) {
+        _socket_set_errno();
+        result = -1;
+    }
+    return result;
+}
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****    replacement for libs/cutils/socket_xxxx.c                   *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+#include <winsock2.h>
+
+static int  _winsock_init;
+
+static void
+_cleanup_winsock( void )
+{
+    WSACleanup();
+}
+
+static void
+_init_winsock( void )
+{
+    if (!_winsock_init) {
+        WSADATA  wsaData;
+        int      rc = WSAStartup( MAKEWORD(2,2), &wsaData);
+        if (rc != 0) {
+            fatal( "adb: could not initialize Winsock\n" );
+        }
+        atexit( _cleanup_winsock );
+        _winsock_init = 1;
+    }
+}
+
+int socket_loopback_client(int port, int type)
+{
+    FH  f = _fh_alloc( &_fh_socket_class );
+    struct sockaddr_in addr;
+    SOCKET  s;
+
+    if (!f)
+        return -1;
+
+    if (!_winsock_init)
+        _init_winsock();
+
+    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 == INVALID_SOCKET) {
+        D("socket_loopback_client: could not create socket\n" );
+        _fh_close(f);
+        return -1;
+    }
+
+    f->fh_socket = s;
+    if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        D("socket_loopback_client: could not connect to %s:%d\n", type != SOCK_STREAM ? "udp" : "tcp", port );
+        _fh_close(f);
+        return -1;
+    }
+    snprintf( f->name, sizeof(f->name), "%d(lo-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
+    D( "socket_loopback_client: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
+    return _fh_to_int(f);
+}
+
+#define LISTEN_BACKLOG 4
+
+int socket_loopback_server(int port, int type)
+{
+    FH   f = _fh_alloc( &_fh_socket_class );
+    struct sockaddr_in addr;
+    SOCKET  s;
+    int  n;
+
+    if (!f) {
+        return -1;
+    }
+
+    if (!_winsock_init)
+        _init_winsock();
+
+    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 == INVALID_SOCKET) return -1;
+
+    f->fh_socket = s;
+
+    n = 1;
+    setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n));
+
+    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        _fh_close(f);
+        return -1;
+    }
+    if (type == SOCK_STREAM) {
+        int ret;
+
+        ret = listen(s, LISTEN_BACKLOG);
+        if (ret < 0) {
+            _fh_close(f);
+            return -1;
+        }
+    }
+    snprintf( f->name, sizeof(f->name), "%d(lo-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
+    D( "socket_loopback_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
+    return _fh_to_int(f);
+}
+
+
+int socket_network_client(const char *host, int port, int type)
+{
+    FH  f = _fh_alloc( &_fh_socket_class );
+    struct hostent *hp;
+    struct sockaddr_in addr;
+    SOCKET s;
+
+    if (!f)
+        return -1;
+
+    if (!_winsock_init)
+        _init_winsock();
+
+    hp = gethostbyname(host);
+    if(hp == 0) {
+        _fh_close(f);
+        return -1;
+    }
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = hp->h_addrtype;
+    addr.sin_port = htons(port);
+    memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
+
+    s = socket(hp->h_addrtype, type, 0);
+    if(s == INVALID_SOCKET) {
+        _fh_close(f);
+        return -1;
+    }
+    f->fh_socket = s;
+
+    if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        _fh_close(f);
+        return -1;
+    }
+
+    snprintf( f->name, sizeof(f->name), "%d(net-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
+    D( "socket_network_client: host '%s' port %d type %s => fd %d\n", host, port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
+    return _fh_to_int(f);
+}
+
+
+int socket_network_client_timeout(const char *host, int port, int type, int timeout)
+{
+    // TODO: implement timeouts for Windows.
+    return socket_network_client(host, port, type);
+}
+
+
+int socket_inaddr_any_server(int port, int type)
+{
+    FH  f = _fh_alloc( &_fh_socket_class );
+    struct sockaddr_in addr;
+    SOCKET  s;
+    int n;
+
+    if (!f)
+        return -1;
+
+    if (!_winsock_init)
+        _init_winsock();
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+    addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+    s = socket(AF_INET, type, 0);
+    if(s == INVALID_SOCKET) {
+        _fh_close(f);
+        return -1;
+    }
+
+    f->fh_socket = s;
+    n = 1;
+    setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n));
+
+    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        _fh_close(f);
+        return -1;
+    }
+
+    if (type == SOCK_STREAM) {
+        int ret;
+
+        ret = listen(s, LISTEN_BACKLOG);
+        if (ret < 0) {
+            _fh_close(f);
+            return -1;
+        }
+    }
+    snprintf( f->name, sizeof(f->name), "%d(any-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
+    D( "socket_inaddr_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
+    return _fh_to_int(f);
+}
+
+#undef accept
+int  adb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen)
+{
+    FH   serverfh = _fh_from_int(serverfd);
+    FH   fh;
+
+    if ( !serverfh || serverfh->clazz != &_fh_socket_class ) {
+        D( "adb_socket_accept: invalid fd %d\n", serverfd );
+        return -1;
+    }
+
+    fh = _fh_alloc( &_fh_socket_class );
+    if (!fh) {
+        D( "adb_socket_accept: not enough memory to allocate accepted socket descriptor\n" );
+        return -1;
+    }
+
+    fh->fh_socket = accept( serverfh->fh_socket, addr, addrlen );
+    if (fh->fh_socket == INVALID_SOCKET) {
+        _fh_close( fh );
+        D( "adb_socket_accept: accept on fd %d return error %ld\n", serverfd, GetLastError() );
+        return -1;
+    }
+
+    snprintf( fh->name, sizeof(fh->name), "%d(accept:%s)", _fh_to_int(fh), serverfh->name );
+    D( "adb_socket_accept on fd %d returns fd %d\n", serverfd, _fh_to_int(fh) );
+    return  _fh_to_int(fh);
+}
+
+
+int  adb_setsockopt( int  fd, int  level, int  optname, const void*  optval, socklen_t  optlen )
+{
+    FH   fh = _fh_from_int(fd);
+
+    if ( !fh || fh->clazz != &_fh_socket_class ) {
+        D("adb_setsockopt: invalid fd %d\n", fd);
+        return -1;
+    }
+
+    return setsockopt( fh->fh_socket, level, optname, reinterpret_cast<const char*>(optval), optlen );
+}
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****    emulated socketpairs                                       *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+/* we implement socketpairs directly in use space for the following reasons:
+ *   - it avoids copying data from/to the Nt kernel
+ *   - it allows us to implement fdevent hooks easily and cheaply, something
+ *     that is not possible with standard Win32 pipes !!
+ *
+ * basically, we use two circular buffers, each one corresponding to a given
+ * direction.
+ *
+ * each buffer is implemented as two regions:
+ *
+ *   region A which is (a_start,a_end)
+ *   region B which is (0, b_end)  with b_end <= a_start
+ *
+ * an empty buffer has:  a_start = a_end = b_end = 0
+ *
+ * a_start is the pointer where we start reading data
+ * a_end is the pointer where we start writing data, unless it is BUFFER_SIZE,
+ * then you start writing at b_end
+ *
+ * the buffer is full when  b_end == a_start && a_end == BUFFER_SIZE
+ *
+ * there is room when b_end < a_start || a_end < BUFER_SIZE
+ *
+ * when reading, a_start is incremented, it a_start meets a_end, then
+ * we do:  a_start = 0, a_end = b_end, b_end = 0, and keep going on..
+ */
+
+#define  BIP_BUFFER_SIZE   4096
+
+#if 0
+#include <stdio.h>
+#  define  BIPD(x)      D x
+#  define  BIPDUMP   bip_dump_hex
+
+static void  bip_dump_hex( const unsigned char*  ptr, size_t  len )
+{
+    int  nn, len2 = len;
+
+    if (len2 > 8) len2 = 8;
+
+    for (nn = 0; nn < len2; nn++)
+        printf("%02x", ptr[nn]);
+    printf("  ");
+
+    for (nn = 0; nn < len2; nn++) {
+        int  c = ptr[nn];
+        if (c < 32 || c > 127)
+            c = '.';
+        printf("%c", c);
+    }
+    printf("\n");
+    fflush(stdout);
+}
+
+#else
+#  define  BIPD(x)        do {} while (0)
+#  define  BIPDUMP(p,l)   BIPD(p)
+#endif
+
+typedef struct BipBufferRec_
+{
+    int                a_start;
+    int                a_end;
+    int                b_end;
+    int                fdin;
+    int                fdout;
+    int                closed;
+    int                can_write;  /* boolean */
+    HANDLE             evt_write;  /* event signaled when one can write to a buffer  */
+    int                can_read;   /* boolean */
+    HANDLE             evt_read;   /* event signaled when one can read from a buffer */
+    CRITICAL_SECTION  lock;
+    unsigned char      buff[ BIP_BUFFER_SIZE ];
+
+} BipBufferRec, *BipBuffer;
+
+static void
+bip_buffer_init( BipBuffer  buffer )
+{
+    D( "bit_buffer_init %p\n", buffer );
+    buffer->a_start   = 0;
+    buffer->a_end     = 0;
+    buffer->b_end     = 0;
+    buffer->can_write = 1;
+    buffer->can_read  = 0;
+    buffer->fdin      = 0;
+    buffer->fdout     = 0;
+    buffer->closed    = 0;
+    buffer->evt_write = CreateEvent( NULL, TRUE, TRUE, NULL );
+    buffer->evt_read  = CreateEvent( NULL, TRUE, FALSE, NULL );
+    InitializeCriticalSection( &buffer->lock );
+}
+
+static void
+bip_buffer_close( BipBuffer  bip )
+{
+    bip->closed = 1;
+
+    if (!bip->can_read) {
+        SetEvent( bip->evt_read );
+    }
+    if (!bip->can_write) {
+        SetEvent( bip->evt_write );
+    }
+}
+
+static void
+bip_buffer_done( BipBuffer  bip )
+{
+    BIPD(( "bip_buffer_done: %d->%d\n", bip->fdin, bip->fdout ));
+    CloseHandle( bip->evt_read );
+    CloseHandle( bip->evt_write );
+    DeleteCriticalSection( &bip->lock );
+}
+
+static int
+bip_buffer_write( BipBuffer  bip, const void* src, int  len )
+{
+    int  avail, count = 0;
+
+    if (len <= 0)
+        return 0;
+
+    BIPD(( "bip_buffer_write: enter %d->%d len %d\n", bip->fdin, bip->fdout, len ));
+    BIPDUMP( src, len );
+
+    EnterCriticalSection( &bip->lock );
+
+    while (!bip->can_write) {
+        int  ret;
+        LeaveCriticalSection( &bip->lock );
+
+        if (bip->closed) {
+            errno = EPIPE;
+            return -1;
+        }
+        /* spinlocking here is probably unfair, but let's live with it */
+        ret = WaitForSingleObject( bip->evt_write, INFINITE );
+        if (ret != WAIT_OBJECT_0) {  /* buffer probably closed */
+            D( "bip_buffer_write: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError() );
+            return 0;
+        }
+        if (bip->closed) {
+            errno = EPIPE;
+            return -1;
+        }
+        EnterCriticalSection( &bip->lock );
+    }
+
+    BIPD(( "bip_buffer_write: exec %d->%d len %d\n", bip->fdin, bip->fdout, len ));
+
+    avail = BIP_BUFFER_SIZE - bip->a_end;
+    if (avail > 0)
+    {
+        /* we can append to region A */
+        if (avail > len)
+            avail = len;
+
+        memcpy( bip->buff + bip->a_end, src, avail );
+        src   = (const char *)src + avail;
+        count += avail;
+        len   -= avail;
+
+        bip->a_end += avail;
+        if (bip->a_end == BIP_BUFFER_SIZE && bip->a_start == 0) {
+            bip->can_write = 0;
+            ResetEvent( bip->evt_write );
+            goto Exit;
+        }
+    }
+
+    if (len == 0)
+        goto Exit;
+
+    avail = bip->a_start - bip->b_end;
+    assert( avail > 0 );  /* since can_write is TRUE */
+
+    if (avail > len)
+        avail = len;
+
+    memcpy( bip->buff + bip->b_end, src, avail );
+    count += avail;
+    bip->b_end += avail;
+
+    if (bip->b_end == bip->a_start) {
+        bip->can_write = 0;
+        ResetEvent( bip->evt_write );
+    }
+
+Exit:
+    assert( count > 0 );
+
+    if ( !bip->can_read ) {
+        bip->can_read = 1;
+        SetEvent( bip->evt_read );
+    }
+
+    BIPD(( "bip_buffer_write: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n",
+            bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
+    LeaveCriticalSection( &bip->lock );
+
+    return count;
+ }
+
+static int
+bip_buffer_read( BipBuffer  bip, void*  dst, int  len )
+{
+    int  avail, count = 0;
+
+    if (len <= 0)
+        return 0;
+
+    BIPD(( "bip_buffer_read: enter %d->%d len %d\n", bip->fdin, bip->fdout, len ));
+
+    EnterCriticalSection( &bip->lock );
+    while ( !bip->can_read )
+    {
+#if 0
+        LeaveCriticalSection( &bip->lock );
+        errno = EAGAIN;
+        return -1;
+#else
+        int  ret;
+        LeaveCriticalSection( &bip->lock );
+
+        if (bip->closed) {
+            errno = EPIPE;
+            return -1;
+        }
+
+        ret = WaitForSingleObject( bip->evt_read, INFINITE );
+        if (ret != WAIT_OBJECT_0) { /* probably closed buffer */
+            D( "bip_buffer_read: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError());
+            return 0;
+        }
+        if (bip->closed) {
+            errno = EPIPE;
+            return -1;
+        }
+        EnterCriticalSection( &bip->lock );
+#endif
+    }
+
+    BIPD(( "bip_buffer_read: exec %d->%d len %d\n", bip->fdin, bip->fdout, len ));
+
+    avail = bip->a_end - bip->a_start;
+    assert( avail > 0 );  /* since can_read is TRUE */
+
+    if (avail > len)
+        avail = len;
+
+    memcpy( dst, bip->buff + bip->a_start, avail );
+    dst   = (char *)dst + avail;
+    count += avail;
+    len   -= avail;
+
+    bip->a_start += avail;
+    if (bip->a_start < bip->a_end)
+        goto Exit;
+
+    bip->a_start = 0;
+    bip->a_end   = bip->b_end;
+    bip->b_end   = 0;
+
+    avail = bip->a_end;
+    if (avail > 0) {
+        if (avail > len)
+            avail = len;
+        memcpy( dst, bip->buff, avail );
+        count += avail;
+        bip->a_start += avail;
+
+        if ( bip->a_start < bip->a_end )
+            goto Exit;
+
+        bip->a_start = bip->a_end = 0;
+    }
+
+    bip->can_read = 0;
+    ResetEvent( bip->evt_read );
+
+Exit:
+    assert( count > 0 );
+
+    if (!bip->can_write ) {
+        bip->can_write = 1;
+        SetEvent( bip->evt_write );
+    }
+
+    BIPDUMP( (const unsigned char*)dst - count, count );
+    BIPD(( "bip_buffer_read: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n",
+            bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
+    LeaveCriticalSection( &bip->lock );
+
+    return count;
+}
+
+typedef struct SocketPairRec_
+{
+    BipBufferRec  a2b_bip;
+    BipBufferRec  b2a_bip;
+    FH            a_fd;
+    int           used;
+
+} SocketPairRec;
+
+void _fh_socketpair_init( FH  f )
+{
+    f->fh_pair = NULL;
+}
+
+static int
+_fh_socketpair_close( FH  f )
+{
+    if ( f->fh_pair ) {
+        SocketPair  pair = f->fh_pair;
+
+        if ( f == pair->a_fd ) {
+            pair->a_fd = NULL;
+        }
+
+        bip_buffer_close( &pair->b2a_bip );
+        bip_buffer_close( &pair->a2b_bip );
+
+        if ( --pair->used == 0 ) {
+            bip_buffer_done( &pair->b2a_bip );
+            bip_buffer_done( &pair->a2b_bip );
+            free( pair );
+        }
+        f->fh_pair = NULL;
+    }
+    return 0;
+}
+
+static int
+_fh_socketpair_lseek( FH  f, int pos, int  origin )
+{
+    errno = ESPIPE;
+    return -1;
+}
+
+static int
+_fh_socketpair_read( FH  f, void* buf, int  len )
+{
+    SocketPair  pair = f->fh_pair;
+    BipBuffer   bip;
+
+    if (!pair)
+        return -1;
+
+    if ( f == pair->a_fd )
+        bip = &pair->b2a_bip;
+    else
+        bip = &pair->a2b_bip;
+
+    return bip_buffer_read( bip, buf, len );
+}
+
+static int
+_fh_socketpair_write( FH  f, const void*  buf, int  len )
+{
+    SocketPair  pair = f->fh_pair;
+    BipBuffer   bip;
+
+    if (!pair)
+        return -1;
+
+    if ( f == pair->a_fd )
+        bip = &pair->a2b_bip;
+    else
+        bip = &pair->b2a_bip;
+
+    return bip_buffer_write( bip, buf, len );
+}
+
+
+static void  _fh_socketpair_hook( FH  f, int  event, EventHook  hook );  /* forward */
+
+static const FHClassRec  _fh_socketpair_class =
+{
+    _fh_socketpair_init,
+    _fh_socketpair_close,
+    _fh_socketpair_lseek,
+    _fh_socketpair_read,
+    _fh_socketpair_write,
+    _fh_socketpair_hook
+};
+
+
+int  adb_socketpair(int sv[2]) {
+    SocketPair pair;
+
+    FH fa = _fh_alloc(&_fh_socketpair_class);
+    FH fb = _fh_alloc(&_fh_socketpair_class);
+
+    if (!fa || !fb)
+        goto Fail;
+
+    pair = reinterpret_cast<SocketPair>(malloc(sizeof(*pair)));
+    if (pair == NULL) {
+        D("adb_socketpair: not enough memory to allocate pipes\n" );
+        goto Fail;
+    }
+
+    bip_buffer_init( &pair->a2b_bip );
+    bip_buffer_init( &pair->b2a_bip );
+
+    fa->fh_pair = pair;
+    fb->fh_pair = pair;
+    pair->used  = 2;
+    pair->a_fd  = fa;
+
+    sv[0] = _fh_to_int(fa);
+    sv[1] = _fh_to_int(fb);
+
+    pair->a2b_bip.fdin  = sv[0];
+    pair->a2b_bip.fdout = sv[1];
+    pair->b2a_bip.fdin  = sv[1];
+    pair->b2a_bip.fdout = sv[0];
+
+    snprintf( fa->name, sizeof(fa->name), "%d(pair:%d)", sv[0], sv[1] );
+    snprintf( fb->name, sizeof(fb->name), "%d(pair:%d)", sv[1], sv[0] );
+    D( "adb_socketpair: returns (%d, %d)\n", sv[0], sv[1] );
+    return 0;
+
+Fail:
+    _fh_close(fb);
+    _fh_close(fa);
+    return -1;
+}
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****    fdevents emulation                                          *****/
+/*****                                                                *****/
+/*****   this is a very simple implementation, we rely on the fact    *****/
+/*****   that ADB doesn't use FDE_ERROR.                              *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+#define FATAL(x...) fatal(__FUNCTION__, x)
+
+#if DEBUG
+static void dump_fde(fdevent *fde, const char *info)
+{
+    fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd,
+            fde->state & FDE_READ ? 'R' : ' ',
+            fde->state & FDE_WRITE ? 'W' : ' ',
+            fde->state & FDE_ERROR ? 'E' : ' ',
+            info);
+}
+#else
+#define dump_fde(fde, info) do { } while(0)
+#endif
+
+#define FDE_EVENTMASK  0x00ff
+#define FDE_STATEMASK  0xff00
+
+#define FDE_ACTIVE     0x0100
+#define FDE_PENDING    0x0200
+#define FDE_CREATED    0x0400
+
+static void fdevent_plist_enqueue(fdevent *node);
+static void fdevent_plist_remove(fdevent *node);
+static fdevent *fdevent_plist_dequeue(void);
+
+static fdevent list_pending = {
+    .next = &list_pending,
+    .prev = &list_pending,
+};
+
+static fdevent **fd_table = 0;
+static int       fd_table_max = 0;
+
+typedef struct EventLooperRec_*  EventLooper;
+
+typedef struct EventHookRec_
+{
+    EventHook    next;
+    FH           fh;
+    HANDLE       h;
+    int          wanted;   /* wanted event flags */
+    int          ready;    /* ready event flags  */
+    void*        aux;
+    void        (*prepare)( EventHook  hook );
+    int         (*start)  ( EventHook  hook );
+    void        (*stop)   ( EventHook  hook );
+    int         (*check)  ( EventHook  hook );
+    int         (*peek)   ( EventHook  hook );
+} EventHookRec;
+
+static EventHook  _free_hooks;
+
+static EventHook
+event_hook_alloc(FH fh) {
+    EventHook hook = _free_hooks;
+    if (hook != NULL) {
+        _free_hooks = hook->next;
+    } else {
+        hook = reinterpret_cast<EventHook>(malloc(sizeof(*hook)));
+        if (hook == NULL)
+            fatal( "could not allocate event hook\n" );
+    }
+    hook->next   = NULL;
+    hook->fh     = fh;
+    hook->wanted = 0;
+    hook->ready  = 0;
+    hook->h      = INVALID_HANDLE_VALUE;
+    hook->aux    = NULL;
+
+    hook->prepare = NULL;
+    hook->start   = NULL;
+    hook->stop    = NULL;
+    hook->check   = NULL;
+    hook->peek    = NULL;
+
+    return hook;
+}
+
+static void
+event_hook_free( EventHook  hook )
+{
+    hook->fh     = NULL;
+    hook->wanted = 0;
+    hook->ready  = 0;
+    hook->next   = _free_hooks;
+    _free_hooks  = hook;
+}
+
+
+static void
+event_hook_signal( EventHook  hook )
+{
+    FH        f   = hook->fh;
+    int       fd  = _fh_to_int(f);
+    fdevent*  fde = fd_table[ fd - WIN32_FH_BASE ];
+
+    if (fde != NULL && fde->fd == fd) {
+        if ((fde->state & FDE_PENDING) == 0) {
+            fde->state |= FDE_PENDING;
+            fdevent_plist_enqueue( fde );
+        }
+        fde->events |= hook->wanted;
+    }
+}
+
+
+#define  MAX_LOOPER_HANDLES  WIN32_MAX_FHS
+
+typedef struct EventLooperRec_
+{
+    EventHook    hooks;
+    HANDLE       htab[ MAX_LOOPER_HANDLES ];
+    int          htab_count;
+
+} EventLooperRec;
+
+static EventHook*
+event_looper_find_p( EventLooper  looper, FH  fh )
+{
+    EventHook  *pnode = &looper->hooks;
+    EventHook   node  = *pnode;
+    for (;;) {
+        if ( node == NULL || node->fh == fh )
+            break;
+        pnode = &node->next;
+        node  = *pnode;
+    }
+    return  pnode;
+}
+
+static void
+event_looper_hook( EventLooper  looper, int  fd, int  events )
+{
+    FH          f = _fh_from_int(fd);
+    EventHook  *pnode;
+    EventHook   node;
+
+    if (f == NULL)  /* invalid arg */ {
+        D("event_looper_hook: invalid fd=%d\n", fd);
+        return;
+    }
+
+    pnode = event_looper_find_p( looper, f );
+    node  = *pnode;
+    if ( node == NULL ) {
+        node       = event_hook_alloc( f );
+        node->next = *pnode;
+        *pnode     = node;
+    }
+
+    if ( (node->wanted & events) != events ) {
+        /* this should update start/stop/check/peek */
+        D("event_looper_hook: call hook for %d (new=%x, old=%x)\n",
+           fd, node->wanted, events);
+        f->clazz->_fh_hook( f, events & ~node->wanted, node );
+        node->wanted |= events;
+    } else {
+        D("event_looper_hook: ignoring events %x for %d wanted=%x)\n",
+           events, fd, node->wanted);
+    }
+}
+
+static void
+event_looper_unhook( EventLooper  looper, int  fd, int  events )
+{
+    FH          fh    = _fh_from_int(fd);
+    EventHook  *pnode = event_looper_find_p( looper, fh );
+    EventHook   node  = *pnode;
+
+    if (node != NULL) {
+        int  events2 = events & node->wanted;
+        if ( events2 == 0 ) {
+            D( "event_looper_unhook: events %x not registered for fd %d\n", events, fd );
+            return;
+        }
+        node->wanted &= ~events2;
+        if (!node->wanted) {
+            *pnode = node->next;
+            event_hook_free( node );
+        }
+    }
+}
+
+/*
+ * A fixer for WaitForMultipleObjects on condition that there are more than 64
+ * handles to wait on.
+ *
+ * In cetain cases DDMS may establish more than 64 connections with ADB. For
+ * instance, this may happen if there are more than 64 processes running on a
+ * device, or there are multiple devices connected (including the emulator) with
+ * the combined number of running processes greater than 64. In this case using
+ * WaitForMultipleObjects to wait on connection events simply wouldn't cut,
+ * because of the API limitations (64 handles max). So, we need to provide a way
+ * to scale WaitForMultipleObjects to accept an arbitrary number of handles. The
+ * easiest (and "Microsoft recommended") way to do that would be dividing the
+ * handle array into chunks with the chunk size less than 64, and fire up as many
+ * waiting threads as there are chunks. Then each thread would wait on a chunk of
+ * handles, and will report back to the caller which handle has been set.
+ * Here is the implementation of that algorithm.
+ */
+
+/* Number of handles to wait on in each wating thread. */
+#define WAIT_ALL_CHUNK_SIZE 63
+
+/* Descriptor for a wating thread */
+typedef struct WaitForAllParam {
+    /* A handle to an event to signal when waiting is over. This handle is shared
+     * accross all the waiting threads, so each waiting thread knows when any
+     * other thread has exited, so it can exit too. */
+    HANDLE          main_event;
+    /* Upon exit from a waiting thread contains the index of the handle that has
+     * been signaled. The index is an absolute index of the signaled handle in
+     * the original array. This pointer is shared accross all the waiting threads
+     * and it's not guaranteed (due to a race condition) that when all the
+     * waiting threads exit, the value contained here would indicate the first
+     * handle that was signaled. This is fine, because the caller cares only
+     * about any handle being signaled. It doesn't care about the order, nor
+     * about the whole list of handles that were signaled. */
+    LONG volatile   *signaled_index;
+    /* Array of handles to wait on in a waiting thread. */
+    HANDLE*         handles;
+    /* Number of handles in 'handles' array to wait on. */
+    int             handles_count;
+    /* Index inside the main array of the first handle in the 'handles' array. */
+    int             first_handle_index;
+    /* Waiting thread handle. */
+    HANDLE          thread;
+} WaitForAllParam;
+
+/* Waiting thread routine. */
+static unsigned __stdcall
+_in_waiter_thread(void*  arg)
+{
+    HANDLE wait_on[WAIT_ALL_CHUNK_SIZE + 1];
+    int res;
+    WaitForAllParam* const param = (WaitForAllParam*)arg;
+
+    /* We have to wait on the main_event in order to be notified when any of the
+     * sibling threads is exiting. */
+    wait_on[0] = param->main_event;
+    /* The rest of the handles go behind the main event handle. */
+    memcpy(wait_on + 1, param->handles, param->handles_count * sizeof(HANDLE));
+
+    res = WaitForMultipleObjects(param->handles_count + 1, wait_on, FALSE, INFINITE);
+    if (res > 0 && res < (param->handles_count + 1)) {
+        /* One of the original handles got signaled. Save its absolute index into
+         * the output variable. */
+        InterlockedCompareExchange(param->signaled_index,
+                                   res - 1L + param->first_handle_index, -1L);
+    }
+
+    /* Notify the caller (and the siblings) that the wait is over. */
+    SetEvent(param->main_event);
+
+    _endthreadex(0);
+    return 0;
+}
+
+/* WaitForMultipeObjects fixer routine.
+ * Param:
+ *  handles Array of handles to wait on.
+ *  handles_count Number of handles in the array.
+ * Return:
+ *  (>= 0 && < handles_count) - Index of the signaled handle in the array, or
+ *  WAIT_FAILED on an error.
+ */
+static int
+_wait_for_all(HANDLE* handles, int handles_count)
+{
+    WaitForAllParam* threads;
+    HANDLE main_event;
+    int chunks, chunk, remains;
+
+    /* This variable is going to be accessed by several threads at the same time,
+     * this is bound to fail randomly when the core is run on multi-core machines.
+     * To solve this, we need to do the following (1 _and_ 2):
+     * 1. Use the "volatile" qualifier to ensure the compiler doesn't optimize
+     *    out the reads/writes in this function unexpectedly.
+     * 2. Ensure correct memory ordering. The "simple" way to do that is to wrap
+     *    all accesses inside a critical section. But we can also use
+     *    InterlockedCompareExchange() which always provide a full memory barrier
+     *    on Win32.
+     */
+    volatile LONG sig_index = -1;
+
+    /* Calculate number of chunks, and allocate thread param array. */
+    chunks = handles_count / WAIT_ALL_CHUNK_SIZE;
+    remains = handles_count % WAIT_ALL_CHUNK_SIZE;
+    threads = (WaitForAllParam*)malloc((chunks + (remains ? 1 : 0)) *
+                                        sizeof(WaitForAllParam));
+    if (threads == NULL) {
+        D("Unable to allocate thread array for %d handles.", handles_count);
+        return (int)WAIT_FAILED;
+    }
+
+    /* Create main event to wait on for all waiting threads. This is a "manualy
+     * reset" event that will remain set once it was set. */
+    main_event = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (main_event == NULL) {
+        D("Unable to create main event. Error: %d", (int)GetLastError());
+        free(threads);
+        return (int)WAIT_FAILED;
+    }
+
+    /*
+     * Initialize waiting thread parameters.
+     */
+
+    for (chunk = 0; chunk < chunks; chunk++) {
+        threads[chunk].main_event = main_event;
+        threads[chunk].signaled_index = &sig_index;
+        threads[chunk].first_handle_index = WAIT_ALL_CHUNK_SIZE * chunk;
+        threads[chunk].handles = handles + threads[chunk].first_handle_index;
+        threads[chunk].handles_count = WAIT_ALL_CHUNK_SIZE;
+    }
+    if (remains) {
+        threads[chunk].main_event = main_event;
+        threads[chunk].signaled_index = &sig_index;
+        threads[chunk].first_handle_index = WAIT_ALL_CHUNK_SIZE * chunk;
+        threads[chunk].handles = handles + threads[chunk].first_handle_index;
+        threads[chunk].handles_count = remains;
+        chunks++;
+    }
+
+    /* Start the waiting threads. */
+    for (chunk = 0; chunk < chunks; chunk++) {
+        /* Note that using adb_thread_create is not appropriate here, since we
+         * need a handle to wait on for thread termination. */
+        threads[chunk].thread = (HANDLE)_beginthreadex(NULL, 0, _in_waiter_thread,
+                                                       &threads[chunk], 0, NULL);
+        if (threads[chunk].thread == NULL) {
+            /* Unable to create a waiter thread. Collapse. */
+            D("Unable to create a waiting thread %d of %d. errno=%d",
+              chunk, chunks, errno);
+            chunks = chunk;
+            SetEvent(main_event);
+            break;
+        }
+    }
+
+    /* Wait on any of the threads to get signaled. */
+    WaitForSingleObject(main_event, INFINITE);
+
+    /* Wait on all the waiting threads to exit. */
+    for (chunk = 0; chunk < chunks; chunk++) {
+        WaitForSingleObject(threads[chunk].thread, INFINITE);
+        CloseHandle(threads[chunk].thread);
+    }
+
+    CloseHandle(main_event);
+    free(threads);
+
+
+    const int ret = (int)InterlockedCompareExchange(&sig_index, -1, -1);
+    return (ret >= 0) ? ret : (int)WAIT_FAILED;
+}
+
+static EventLooperRec  win32_looper;
+
+static void fdevent_init(void)
+{
+    win32_looper.htab_count = 0;
+    win32_looper.hooks      = NULL;
+}
+
+static void fdevent_connect(fdevent *fde)
+{
+    EventLooper  looper = &win32_looper;
+    int          events = fde->state & FDE_EVENTMASK;
+
+    if (events != 0)
+        event_looper_hook( looper, fde->fd, events );
+}
+
+static void fdevent_disconnect(fdevent *fde)
+{
+    EventLooper  looper = &win32_looper;
+    int          events = fde->state & FDE_EVENTMASK;
+
+    if (events != 0)
+        event_looper_unhook( looper, fde->fd, events );
+}
+
+static void fdevent_update(fdevent *fde, unsigned events)
+{
+    EventLooper  looper  = &win32_looper;
+    unsigned     events0 = fde->state & FDE_EVENTMASK;
+
+    if (events != events0) {
+        int  removes = events0 & ~events;
+        int  adds    = events  & ~events0;
+        if (removes) {
+            D("fdevent_update: remove %x from %d\n", removes, fde->fd);
+            event_looper_unhook( looper, fde->fd, removes );
+        }
+        if (adds) {
+            D("fdevent_update: add %x to %d\n", adds, fde->fd);
+            event_looper_hook  ( looper, fde->fd, adds );
+        }
+    }
+}
+
+static void fdevent_process()
+{
+    EventLooper  looper = &win32_looper;
+    EventHook    hook;
+    int          gotone = 0;
+
+    /* if we have at least one ready hook, execute it/them */
+    for (hook = looper->hooks; hook; hook = hook->next) {
+        hook->ready = 0;
+        if (hook->prepare) {
+            hook->prepare(hook);
+            if (hook->ready != 0) {
+                event_hook_signal( hook );
+                gotone = 1;
+            }
+        }
+    }
+
+    /* nothing's ready yet, so wait for something to happen */
+    if (!gotone)
+    {
+        looper->htab_count = 0;
+
+        for (hook = looper->hooks; hook; hook = hook->next)
+        {
+            if (hook->start && !hook->start(hook)) {
+                D( "fdevent_process: error when starting a hook\n" );
+                return;
+            }
+            if (hook->h != INVALID_HANDLE_VALUE) {
+                int  nn;
+
+                for (nn = 0; nn < looper->htab_count; nn++)
+                {
+                    if ( looper->htab[nn] == hook->h )
+                        goto DontAdd;
+                }
+                looper->htab[ looper->htab_count++ ] = hook->h;
+            DontAdd:
+                ;
+            }
+        }
+
+        if (looper->htab_count == 0) {
+            D( "fdevent_process: nothing to wait for !!\n" );
+            return;
+        }
+
+        do
+        {
+            int   wait_ret;
+
+            D( "adb_win32: waiting for %d events\n", looper->htab_count );
+            if (looper->htab_count > MAXIMUM_WAIT_OBJECTS) {
+                D("handle count %d exceeds MAXIMUM_WAIT_OBJECTS.\n", looper->htab_count);
+                wait_ret = _wait_for_all(looper->htab, looper->htab_count);
+            } else {
+                wait_ret = WaitForMultipleObjects( looper->htab_count, looper->htab, FALSE, INFINITE );
+            }
+            if (wait_ret == (int)WAIT_FAILED) {
+                D( "adb_win32: wait failed, error %ld\n", GetLastError() );
+            } else {
+                D( "adb_win32: got one (index %d)\n", wait_ret );
+
+                /* according to Cygwin, some objects like consoles wake up on "inappropriate" events
+                 * like mouse movements. we need to filter these with the "check" function
+                 */
+                if ((unsigned)wait_ret < (unsigned)looper->htab_count)
+                {
+                    for (hook = looper->hooks; hook; hook = hook->next)
+                    {
+                        if ( looper->htab[wait_ret] == hook->h       &&
+                         (!hook->check || hook->check(hook)) )
+                        {
+                            D( "adb_win32: signaling %s for %x\n", hook->fh->name, hook->ready );
+                            event_hook_signal( hook );
+                            gotone = 1;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        while (!gotone);
+
+        for (hook = looper->hooks; hook; hook = hook->next) {
+            if (hook->stop)
+                hook->stop( hook );
+        }
+    }
+
+    for (hook = looper->hooks; hook; hook = hook->next) {
+        if (hook->peek && hook->peek(hook))
+                event_hook_signal( hook );
+    }
+}
+
+
+static void fdevent_register(fdevent *fde)
+{
+    int  fd = fde->fd - WIN32_FH_BASE;
+
+    if(fd < 0) {
+        FATAL("bogus negative fd (%d)\n", fde->fd);
+    }
+
+    if(fd >= fd_table_max) {
+        int oldmax = fd_table_max;
+        if(fde->fd > 32000) {
+            FATAL("bogus huuuuge fd (%d)\n", fde->fd);
+        }
+        if(fd_table_max == 0) {
+            fdevent_init();
+            fd_table_max = 256;
+        }
+        while(fd_table_max <= fd) {
+            fd_table_max *= 2;
+        }
+        fd_table = reinterpret_cast<fdevent**>(realloc(fd_table, sizeof(fdevent*) * fd_table_max));
+        if(fd_table == 0) {
+            FATAL("could not expand fd_table to %d entries\n", fd_table_max);
+        }
+        memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax));
+    }
+
+    fd_table[fd] = fde;
+}
+
+static void fdevent_unregister(fdevent *fde)
+{
+    int  fd = fde->fd - WIN32_FH_BASE;
+
+    if((fd < 0) || (fd >= fd_table_max)) {
+        FATAL("fd out of range (%d)\n", fde->fd);
+    }
+
+    if(fd_table[fd] != fde) {
+        FATAL("fd_table out of sync");
+    }
+
+    fd_table[fd] = 0;
+
+    if(!(fde->state & FDE_DONT_CLOSE)) {
+        dump_fde(fde, "close");
+        adb_close(fde->fd);
+    }
+}
+
+static void fdevent_plist_enqueue(fdevent *node)
+{
+    fdevent *list = &list_pending;
+
+    node->next = list;
+    node->prev = list->prev;
+    node->prev->next = node;
+    list->prev = node;
+}
+
+static void fdevent_plist_remove(fdevent *node)
+{
+    node->prev->next = node->next;
+    node->next->prev = node->prev;
+    node->next = 0;
+    node->prev = 0;
+}
+
+static fdevent *fdevent_plist_dequeue(void)
+{
+    fdevent *list = &list_pending;
+    fdevent *node = list->next;
+
+    if(node == list) return 0;
+
+    list->next = node->next;
+    list->next->prev = list;
+    node->next = 0;
+    node->prev = 0;
+
+    return node;
+}
+
+fdevent *fdevent_create(int fd, fd_func func, void *arg)
+{
+    fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
+    if(fde == 0) return 0;
+    fdevent_install(fde, fd, func, arg);
+    fde->state |= FDE_CREATED;
+    return fde;
+}
+
+void fdevent_destroy(fdevent *fde)
+{
+    if(fde == 0) return;
+    if(!(fde->state & FDE_CREATED)) {
+        FATAL("fde %p not created by fdevent_create()\n", fde);
+    }
+    fdevent_remove(fde);
+}
+
+void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg)
+{
+    memset(fde, 0, sizeof(fdevent));
+    fde->state = FDE_ACTIVE;
+    fde->fd = fd;
+    fde->func = func;
+    fde->arg = arg;
+
+    fdevent_register(fde);
+    dump_fde(fde, "connect");
+    fdevent_connect(fde);
+    fde->state |= FDE_ACTIVE;
+}
+
+void fdevent_remove(fdevent *fde)
+{
+    if(fde->state & FDE_PENDING) {
+        fdevent_plist_remove(fde);
+    }
+
+    if(fde->state & FDE_ACTIVE) {
+        fdevent_disconnect(fde);
+        dump_fde(fde, "disconnect");
+        fdevent_unregister(fde);
+    }
+
+    fde->state = 0;
+    fde->events = 0;
+}
+
+
+void fdevent_set(fdevent *fde, unsigned events)
+{
+    events &= FDE_EVENTMASK;
+
+    if((fde->state & FDE_EVENTMASK) == (int)events) return;
+
+    if(fde->state & FDE_ACTIVE) {
+        fdevent_update(fde, events);
+        dump_fde(fde, "update");
+    }
+
+    fde->state = (fde->state & FDE_STATEMASK) | events;
+
+    if(fde->state & FDE_PENDING) {
+            /* if we're pending, make sure
+            ** we don't signal an event that
+            ** is no longer wanted.
+            */
+        fde->events &= (~events);
+        if(fde->events == 0) {
+            fdevent_plist_remove(fde);
+            fde->state &= (~FDE_PENDING);
+        }
+    }
+}
+
+void fdevent_add(fdevent *fde, unsigned events)
+{
+    fdevent_set(
+        fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK));
+}
+
+void fdevent_del(fdevent *fde, unsigned events)
+{
+    fdevent_set(
+        fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
+}
+
+void fdevent_loop()
+{
+    fdevent *fde;
+
+    for(;;) {
+#if DEBUG
+        fprintf(stderr,"--- ---- waiting for events\n");
+#endif
+        fdevent_process();
+
+        while((fde = fdevent_plist_dequeue())) {
+            unsigned events = fde->events;
+            fde->events = 0;
+            fde->state &= (~FDE_PENDING);
+            dump_fde(fde, "callback");
+            fde->func(fde->fd, events, fde->arg);
+        }
+    }
+}
+
+/**  FILE EVENT HOOKS
+ **/
+
+static void  _event_file_prepare( EventHook  hook )
+{
+    if (hook->wanted & (FDE_READ|FDE_WRITE)) {
+        /* we can always read/write */
+        hook->ready |= hook->wanted & (FDE_READ|FDE_WRITE);
+    }
+}
+
+static int  _event_file_peek( EventHook  hook )
+{
+    return (hook->wanted & (FDE_READ|FDE_WRITE));
+}
+
+static void  _fh_file_hook( FH  f, int  events, EventHook  hook )
+{
+    hook->h       = f->fh_handle;
+    hook->prepare = _event_file_prepare;
+    hook->peek    = _event_file_peek;
+}
+
+/** SOCKET EVENT HOOKS
+ **/
+
+static void  _event_socket_verify( EventHook  hook, WSANETWORKEVENTS*  evts )
+{
+    if ( evts->lNetworkEvents & (FD_READ|FD_ACCEPT|FD_CLOSE) ) {
+        if (hook->wanted & FDE_READ)
+            hook->ready |= FDE_READ;
+        if ((evts->iErrorCode[FD_READ] != 0) && hook->wanted & FDE_ERROR)
+            hook->ready |= FDE_ERROR;
+    }
+    if ( evts->lNetworkEvents & (FD_WRITE|FD_CONNECT|FD_CLOSE) ) {
+        if (hook->wanted & FDE_WRITE)
+            hook->ready |= FDE_WRITE;
+        if ((evts->iErrorCode[FD_WRITE] != 0) && hook->wanted & FDE_ERROR)
+            hook->ready |= FDE_ERROR;
+    }
+    if ( evts->lNetworkEvents & FD_OOB ) {
+        if (hook->wanted & FDE_ERROR)
+            hook->ready |= FDE_ERROR;
+    }
+}
+
+static void  _event_socket_prepare( EventHook  hook )
+{
+    WSANETWORKEVENTS  evts;
+
+    /* look if some of the events we want already happened ? */
+    if (!WSAEnumNetworkEvents( hook->fh->fh_socket, NULL, &evts ))
+        _event_socket_verify( hook, &evts );
+}
+
+static int  _socket_wanted_to_flags( int  wanted )
+{
+    int  flags = 0;
+    if (wanted & FDE_READ)
+        flags |= FD_READ | FD_ACCEPT | FD_CLOSE;
+
+    if (wanted & FDE_WRITE)
+        flags |= FD_WRITE | FD_CONNECT | FD_CLOSE;
+
+    if (wanted & FDE_ERROR)
+        flags |= FD_OOB;
+
+    return flags;
+}
+
+static int _event_socket_start( EventHook  hook )
+{
+    /* create an event which we're going to wait for */
+    FH    fh    = hook->fh;
+    long  flags = _socket_wanted_to_flags( hook->wanted );
+
+    hook->h = fh->event;
+    if (hook->h == INVALID_HANDLE_VALUE) {
+        D( "_event_socket_start: no event for %s\n", fh->name );
+        return 0;
+    }
+
+    if ( flags != fh->mask ) {
+        D( "_event_socket_start: hooking %s for %x (flags %ld)\n", hook->fh->name, hook->wanted, flags );
+        if ( WSAEventSelect( fh->fh_socket, hook->h, flags ) ) {
+            D( "_event_socket_start: WSAEventSelect() for %s failed, error %d\n", hook->fh->name, WSAGetLastError() );
+            CloseHandle( hook->h );
+            hook->h = INVALID_HANDLE_VALUE;
+            exit(1);
+            return 0;
+        }
+        fh->mask = flags;
+    }
+    return 1;
+}
+
+static void _event_socket_stop( EventHook  hook )
+{
+    hook->h = INVALID_HANDLE_VALUE;
+}
+
+static int  _event_socket_check( EventHook  hook )
+{
+    int               result = 0;
+    FH                fh = hook->fh;
+    WSANETWORKEVENTS  evts;
+
+    if (!WSAEnumNetworkEvents( fh->fh_socket, hook->h, &evts ) ) {
+        _event_socket_verify( hook, &evts );
+        result = (hook->ready != 0);
+        if (result) {
+            ResetEvent( hook->h );
+        }
+    }
+    D( "_event_socket_check %s returns %d\n", fh->name, result );
+    return  result;
+}
+
+static int  _event_socket_peek( EventHook  hook )
+{
+    WSANETWORKEVENTS  evts;
+    FH                fh = hook->fh;
+
+    /* look if some of the events we want already happened ? */
+    if (!WSAEnumNetworkEvents( fh->fh_socket, NULL, &evts )) {
+        _event_socket_verify( hook, &evts );
+        if (hook->ready)
+            ResetEvent( hook->h );
+    }
+
+    return hook->ready != 0;
+}
+
+
+
+static void  _fh_socket_hook( FH  f, int  events, EventHook  hook )
+{
+    hook->prepare = _event_socket_prepare;
+    hook->start   = _event_socket_start;
+    hook->stop    = _event_socket_stop;
+    hook->check   = _event_socket_check;
+    hook->peek    = _event_socket_peek;
+
+    _event_socket_start( hook );
+}
+
+/** SOCKETPAIR EVENT HOOKS
+ **/
+
+static void  _event_socketpair_prepare( EventHook  hook )
+{
+    FH          fh   = hook->fh;
+    SocketPair  pair = fh->fh_pair;
+    BipBuffer   rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip;
+    BipBuffer   wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip;
+
+    if (hook->wanted & FDE_READ && rbip->can_read)
+        hook->ready |= FDE_READ;
+
+    if (hook->wanted & FDE_WRITE && wbip->can_write)
+        hook->ready |= FDE_WRITE;
+ }
+
+ static int  _event_socketpair_start( EventHook  hook )
+ {
+    FH          fh   = hook->fh;
+    SocketPair  pair = fh->fh_pair;
+    BipBuffer   rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip;
+    BipBuffer   wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip;
+
+    if (hook->wanted == FDE_READ)
+        hook->h = rbip->evt_read;
+
+    else if (hook->wanted == FDE_WRITE)
+        hook->h = wbip->evt_write;
+
+    else {
+        D("_event_socketpair_start: can't handle FDE_READ+FDE_WRITE\n" );
+        return 0;
+    }
+    D( "_event_socketpair_start: hook %s for %x wanted=%x\n",
+       hook->fh->name, _fh_to_int(fh), hook->wanted);
+    return 1;
+}
+
+static int  _event_socketpair_peek( EventHook  hook )
+{
+    _event_socketpair_prepare( hook );
+    return hook->ready != 0;
+}
+
+static void  _fh_socketpair_hook( FH  fh, int  events, EventHook  hook )
+{
+    hook->prepare = _event_socketpair_prepare;
+    hook->start   = _event_socketpair_start;
+    hook->peek    = _event_socketpair_peek;
+}
+
+
+void
+adb_sysdeps_init( void )
+{
+#define  ADB_MUTEX(x)  InitializeCriticalSection( & x );
+#include "mutex_list.h"
+    InitializeCriticalSection( &_win32_lock );
+}
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****      Console Window Terminal Emulation                         *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+// This reads input from a Win32 console window and translates it into Unix
+// terminal-style sequences. This emulates mostly Gnome Terminal (in Normal
+// mode, not Application mode), which itself emulates xterm. Gnome Terminal
+// is emulated instead of xterm because it is probably more popular than xterm:
+// Ubuntu's default Ctrl-Alt-T shortcut opens Gnome Terminal, Gnome Terminal
+// supports modern fonts, etc. It seems best to emulate the terminal that most
+// Android developers use because they'll fix apps (the shell, etc.) to keep
+// working with that terminal's emulation.
+//
+// The point of this emulation is not to be perfect or to solve all issues with
+// console windows on Windows, but to be better than the original code which
+// just called read() (which called ReadFile(), which called ReadConsoleA())
+// which did not support Ctrl-C, tab completion, shell input line editing
+// keys, server echo, and more.
+//
+// This implementation reconfigures the console with SetConsoleMode(), then
+// calls ReadConsoleInput() to get raw input which it remaps to Unix
+// terminal-style sequences which is returned via unix_read() which is used
+// by the 'adb shell' command.
+//
+// Code organization:
+//
+// * stdin_raw_init() and stdin_raw_restore() reconfigure the console.
+// * unix_read() detects console windows (as opposed to pipes, files, etc.).
+// * _console_read() is the main code of the emulation.
+
+
+// Read an input record from the console; one that should be processed.
+static bool _get_interesting_input_record_uncached(const HANDLE console,
+    INPUT_RECORD* const input_record) {
+    for (;;) {
+        DWORD read_count = 0;
+        memset(input_record, 0, sizeof(*input_record));
+        if (!ReadConsoleInputA(console, input_record, 1, &read_count)) {
+            D("_get_interesting_input_record_uncached: ReadConsoleInputA() "
+              "failure, error %ld\n", GetLastError());
+            errno = EIO;
+            return false;
+        }
+
+        if (read_count == 0) {   // should be impossible
+            fatal("ReadConsoleInputA returned 0");
+        }
+
+        if (read_count != 1) {   // should be impossible
+            fatal("ReadConsoleInputA did not return one input record");
+        }
+
+        if ((input_record->EventType == KEY_EVENT) &&
+            (input_record->Event.KeyEvent.bKeyDown)) {
+            if (input_record->Event.KeyEvent.wRepeatCount == 0) {
+                fatal("ReadConsoleInputA returned a key event with zero repeat"
+                      " count");
+            }
+
+            // Got an interesting INPUT_RECORD, so return
+            return true;
+        }
+    }
+}
+
+// Cached input record (in case _console_read() is passed a buffer that doesn't
+// have enough space to fit wRepeatCount number of key sequences). A non-zero
+// wRepeatCount indicates that a record is cached.
+static INPUT_RECORD _win32_input_record;
+
+// Get the next KEY_EVENT_RECORD that should be processed.
+static KEY_EVENT_RECORD* _get_key_event_record(const HANDLE console) {
+    // If nothing cached, read directly from the console until we get an
+    // interesting record.
+    if (_win32_input_record.Event.KeyEvent.wRepeatCount == 0) {
+        if (!_get_interesting_input_record_uncached(console,
+            &_win32_input_record)) {
+            // There was an error, so make sure wRepeatCount is zero because
+            // that signifies no cached input record.
+            _win32_input_record.Event.KeyEvent.wRepeatCount = 0;
+            return NULL;
+        }
+    }
+
+    return &_win32_input_record.Event.KeyEvent;
+}
+
+static __inline__ bool _is_shift_pressed(const DWORD control_key_state) {
+    return (control_key_state & SHIFT_PRESSED) != 0;
+}
+
+static __inline__ bool _is_ctrl_pressed(const DWORD control_key_state) {
+    return (control_key_state & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0;
+}
+
+static __inline__ bool _is_alt_pressed(const DWORD control_key_state) {
+    return (control_key_state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) != 0;
+}
+
+static __inline__ bool _is_numlock_on(const DWORD control_key_state) {
+    return (control_key_state & NUMLOCK_ON) != 0;
+}
+
+static __inline__ bool _is_capslock_on(const DWORD control_key_state) {
+    return (control_key_state & CAPSLOCK_ON) != 0;
+}
+
+static __inline__ bool _is_enhanced_key(const DWORD control_key_state) {
+    return (control_key_state & ENHANCED_KEY) != 0;
+}
+
+// Constants from MSDN for ToAscii().
+static const BYTE TOASCII_KEY_OFF = 0x00;
+static const BYTE TOASCII_KEY_DOWN = 0x80;
+static const BYTE TOASCII_KEY_TOGGLED_ON = 0x01;   // for CapsLock
+
+// Given a key event, ignore a modifier key and return the character that was
+// entered without the modifier. Writes to *ch and returns the number of bytes
+// written.
+static size_t _get_char_ignoring_modifier(char* const ch,
+    const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state,
+    const WORD modifier) {
+    // If there is no character from Windows, try ignoring the specified
+    // modifier and look for a character. Note that if AltGr is being used,
+    // there will be a character from Windows.
+    if (key_event->uChar.AsciiChar == '\0') {
+        // Note that we read the control key state from the passed in argument
+        // instead of from key_event since the argument has been normalized.
+        if (((modifier == VK_SHIFT)   &&
+            _is_shift_pressed(control_key_state)) ||
+            ((modifier == VK_CONTROL) &&
+            _is_ctrl_pressed(control_key_state)) ||
+            ((modifier == VK_MENU)    && _is_alt_pressed(control_key_state))) {
+
+            BYTE key_state[256]   = {0};
+            key_state[VK_SHIFT]   = _is_shift_pressed(control_key_state) ?
+                TOASCII_KEY_DOWN : TOASCII_KEY_OFF;
+            key_state[VK_CONTROL] = _is_ctrl_pressed(control_key_state)  ?
+                TOASCII_KEY_DOWN : TOASCII_KEY_OFF;
+            key_state[VK_MENU]    = _is_alt_pressed(control_key_state)   ?
+                TOASCII_KEY_DOWN : TOASCII_KEY_OFF;
+            key_state[VK_CAPITAL] = _is_capslock_on(control_key_state)   ?
+                TOASCII_KEY_TOGGLED_ON : TOASCII_KEY_OFF;
+
+            // cause this modifier to be ignored
+            key_state[modifier]   = TOASCII_KEY_OFF;
+
+            WORD translated = 0;
+            if (ToAscii(key_event->wVirtualKeyCode,
+                key_event->wVirtualScanCode, key_state, &translated, 0) == 1) {
+                // Ignoring the modifier, we found a character.
+                *ch = (CHAR)translated;
+                return 1;
+            }
+        }
+    }
+
+    // Just use whatever Windows told us originally.
+    *ch = key_event->uChar.AsciiChar;
+
+    // If the character from Windows is NULL, return a size of zero.
+    return (*ch == '\0') ? 0 : 1;
+}
+
+// If a Ctrl key is pressed, lookup the character, ignoring the Ctrl key,
+// but taking into account the shift key. This is because for a sequence like
+// Ctrl-Alt-0, we want to find the character '0' and for Ctrl-Alt-Shift-0,
+// we want to find the character ')'.
+//
+// Note that Windows doesn't seem to pass bKeyDown for Ctrl-Shift-NoAlt-0
+// because it is the default key-sequence to switch the input language.
+// This is configurable in the Region and Language control panel.
+static __inline__ size_t _get_non_control_char(char* const ch,
+    const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state) {
+    return _get_char_ignoring_modifier(ch, key_event, control_key_state,
+        VK_CONTROL);
+}
+
+// Get without Alt.
+static __inline__ size_t _get_non_alt_char(char* const ch,
+    const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state) {
+    return _get_char_ignoring_modifier(ch, key_event, control_key_state,
+        VK_MENU);
+}
+
+// Ignore the control key, find the character from Windows, and apply any
+// Control key mappings (for example, Ctrl-2 is a NULL character). Writes to
+// *pch and returns number of bytes written.
+static size_t _get_control_character(char* const pch,
+    const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state) {
+    const size_t len = _get_non_control_char(pch, key_event,
+        control_key_state);
+
+    if ((len == 1) && _is_ctrl_pressed(control_key_state)) {
+        char ch = *pch;
+        switch (ch) {
+        case '2':
+        case '@':
+        case '`':
+            ch = '\0';
+            break;
+        case '3':
+        case '[':
+        case '{':
+            ch = '\x1b';
+            break;
+        case '4':
+        case '\\':
+        case '|':
+            ch = '\x1c';
+            break;
+        case '5':
+        case ']':
+        case '}':
+            ch = '\x1d';
+            break;
+        case '6':
+        case '^':
+        case '~':
+            ch = '\x1e';
+            break;
+        case '7':
+        case '-':
+        case '_':
+            ch = '\x1f';
+            break;
+        case '8':
+            ch = '\x7f';
+            break;
+        case '/':
+            if (!_is_alt_pressed(control_key_state)) {
+                ch = '\x1f';
+            }
+            break;
+        case '?':
+            if (!_is_alt_pressed(control_key_state)) {
+                ch = '\x7f';
+            }
+            break;
+        }
+        *pch = ch;
+    }
+
+    return len;
+}
+
+static DWORD _normalize_altgr_control_key_state(
+    const KEY_EVENT_RECORD* const key_event) {
+    DWORD control_key_state = key_event->dwControlKeyState;
+
+    // If we're in an AltGr situation where the AltGr key is down (depending on
+    // the keyboard layout, that might be the physical right alt key which
+    // produces a control_key_state where Right-Alt and Left-Ctrl are down) or
+    // AltGr-equivalent keys are down (any Ctrl key + any Alt key), and we have
+    // a character (which indicates that there was an AltGr mapping), then act
+    // as if alt and control are not really down for the purposes of modifiers.
+    // This makes it so that if the user with, say, a German keyboard layout
+    // presses AltGr-] (which we see as Right-Alt + Left-Ctrl + key), we just
+    // output the key and we don't see the Alt and Ctrl keys.
+    if (_is_ctrl_pressed(control_key_state) &&
+        _is_alt_pressed(control_key_state)
+        && (key_event->uChar.AsciiChar != '\0')) {
+        // Try to remove as few bits as possible to improve our chances of
+        // detecting combinations like Left-Alt + AltGr, Right-Ctrl + AltGr, or
+        // Left-Alt + Right-Ctrl + AltGr.
+        if ((control_key_state & RIGHT_ALT_PRESSED) != 0) {
+            // Remove Right-Alt.
+            control_key_state &= ~RIGHT_ALT_PRESSED;
+            // If uChar is set, a Ctrl key is pressed, and Right-Alt is
+            // pressed, Left-Ctrl is almost always set, except if the user
+            // presses Right-Ctrl, then AltGr (in that specific order) for
+            // whatever reason. At any rate, make sure the bit is not set.
+            control_key_state &= ~LEFT_CTRL_PRESSED;
+        } else if ((control_key_state & LEFT_ALT_PRESSED) != 0) {
+            // Remove Left-Alt.
+            control_key_state &= ~LEFT_ALT_PRESSED;
+            // Whichever Ctrl key is down, remove it from the state. We only
+            // remove one key, to improve our chances of detecting the
+            // corner-case of Left-Ctrl + Left-Alt + Right-Ctrl.
+            if ((control_key_state & LEFT_CTRL_PRESSED) != 0) {
+                // Remove Left-Ctrl.
+                control_key_state &= ~LEFT_CTRL_PRESSED;
+            } else if ((control_key_state & RIGHT_CTRL_PRESSED) != 0) {
+                // Remove Right-Ctrl.
+                control_key_state &= ~RIGHT_CTRL_PRESSED;
+            }
+        }
+
+        // Note that this logic isn't 100% perfect because Windows doesn't
+        // allow us to detect all combinations because a physical AltGr key
+        // press shows up as two bits, plus some combinations are ambiguous
+        // about what is actually physically pressed.
+    }
+
+    return control_key_state;
+}
+
+// If NumLock is on and Shift is pressed, SHIFT_PRESSED is not set in
+// dwControlKeyState for the following keypad keys: period, 0-9. If we detect
+// this scenario, set the SHIFT_PRESSED bit so we can add modifiers
+// appropriately.
+static DWORD _normalize_keypad_control_key_state(const WORD vk,
+    const DWORD control_key_state) {
+    if (!_is_numlock_on(control_key_state)) {
+        return control_key_state;
+    }
+    if (!_is_enhanced_key(control_key_state)) {
+        switch (vk) {
+            case VK_INSERT: // 0
+            case VK_DELETE: // .
+            case VK_END:    // 1
+            case VK_DOWN:   // 2
+            case VK_NEXT:   // 3
+            case VK_LEFT:   // 4
+            case VK_CLEAR:  // 5
+            case VK_RIGHT:  // 6
+            case VK_HOME:   // 7
+            case VK_UP:     // 8
+            case VK_PRIOR:  // 9
+                return control_key_state | SHIFT_PRESSED;
+        }
+    }
+
+    return control_key_state;
+}
+
+static const char* _get_keypad_sequence(const DWORD control_key_state,
+    const char* const normal, const char* const shifted) {
+    if (_is_shift_pressed(control_key_state)) {
+        // Shift is pressed and NumLock is off
+        return shifted;
+    } else {
+        // Shift is not pressed and NumLock is off, or,
+        // Shift is pressed and NumLock is on, in which case we want the
+        // NumLock and Shift to neutralize each other, thus, we want the normal
+        // sequence.
+        return normal;
+    }
+    // If Shift is not pressed and NumLock is on, a different virtual key code
+    // is returned by Windows, which can be taken care of by a different case
+    // statement in _console_read().
+}
+
+// Write sequence to buf and return the number of bytes written.
+static size_t _get_modifier_sequence(char* const buf, const WORD vk,
+    DWORD control_key_state, const char* const normal) {
+    // Copy the base sequence into buf.
+    const size_t len = strlen(normal);
+    memcpy(buf, normal, len);
+
+    int code = 0;
+
+    control_key_state = _normalize_keypad_control_key_state(vk,
+        control_key_state);
+
+    if (_is_shift_pressed(control_key_state)) {
+        code |= 0x1;
+    }
+    if (_is_alt_pressed(control_key_state)) {   // any alt key pressed
+        code |= 0x2;
+    }
+    if (_is_ctrl_pressed(control_key_state)) {  // any control key pressed
+        code |= 0x4;
+    }
+    // If some modifier was held down, then we need to insert the modifier code
+    if (code != 0) {
+        if (len == 0) {
+            // Should be impossible because caller should pass a string of
+            // non-zero length.
+            return 0;
+        }
+        size_t index = len - 1;
+        const char lastChar = buf[index];
+        if (lastChar != '~') {
+            buf[index++] = '1';
+        }
+        buf[index++] = ';';         // modifier separator
+        // 2 = shift, 3 = alt, 4 = shift & alt, 5 = control,
+        // 6 = shift & control, 7 = alt & control, 8 = shift & alt & control
+        buf[index++] = '1' + code;
+        buf[index++] = lastChar;    // move ~ (or other last char) to the end
+        return index;
+    }
+    return len;
+}
+
+// Write sequence to buf and return the number of bytes written.
+static size_t _get_modifier_keypad_sequence(char* const buf, const WORD vk,
+    const DWORD control_key_state, const char* const normal,
+    const char shifted) {
+    if (_is_shift_pressed(control_key_state)) {
+        // Shift is pressed and NumLock is off
+        if (shifted != '\0') {
+            buf[0] = shifted;
+            return sizeof(buf[0]);
+        } else {
+            return 0;
+        }
+    } else {
+        // Shift is not pressed and NumLock is off, or,
+        // Shift is pressed and NumLock is on, in which case we want the
+        // NumLock and Shift to neutralize each other, thus, we want the normal
+        // sequence.
+        return _get_modifier_sequence(buf, vk, control_key_state, normal);
+    }
+    // If Shift is not pressed and NumLock is on, a different virtual key code
+    // is returned by Windows, which can be taken care of by a different case
+    // statement in _console_read().
+}
+
+// The decimal key on the keypad produces a '.' for U.S. English and a ',' for
+// Standard German. Figure this out at runtime so we know what to output for
+// Shift-VK_DELETE.
+static char _get_decimal_char() {
+    return (char)MapVirtualKeyA(VK_DECIMAL, MAPVK_VK_TO_CHAR);
+}
+
+// Prefix the len bytes in buf with the escape character, and then return the
+// new buffer length.
+size_t _escape_prefix(char* const buf, const size_t len) {
+    // If nothing to prefix, don't do anything. We might be called with
+    // len == 0, if alt was held down with a dead key which produced nothing.
+    if (len == 0) {
+        return 0;
+    }
+
+    memmove(&buf[1], buf, len);
+    buf[0] = '\x1b';
+    return len + 1;
+}
+
+// Writes to buffer buf (of length len), returning number of bytes written or
+// -1 on error. Never returns zero because Win32 consoles are never 'closed'
+// (as far as I can tell).
+static int _console_read(const HANDLE console, void* buf, size_t len) {
+    for (;;) {
+        KEY_EVENT_RECORD* const key_event = _get_key_event_record(console);
+        if (key_event == NULL) {
+            return -1;
+        }
+
+        const WORD vk = key_event->wVirtualKeyCode;
+        const CHAR ch = key_event->uChar.AsciiChar;
+        const DWORD control_key_state = _normalize_altgr_control_key_state(
+            key_event);
+
+        // The following emulation code should write the output sequence to
+        // either seqstr or to seqbuf and seqbuflen.
+        const char* seqstr = NULL;  // NULL terminated C-string
+        // Enough space for max sequence string below, plus modifiers and/or
+        // escape prefix.
+        char seqbuf[16];
+        size_t seqbuflen = 0;       // Space used in seqbuf.
+
+#define MATCH(vk, normal) \
+            case (vk): \
+            { \
+                seqstr = (normal); \
+            } \
+            break;
+
+        // Modifier keys should affect the output sequence.
+#define MATCH_MODIFIER(vk, normal) \
+            case (vk): \
+            { \
+                seqbuflen = _get_modifier_sequence(seqbuf, (vk), \
+                    control_key_state, (normal)); \
+            } \
+            break;
+
+        // The shift key should affect the output sequence.
+#define MATCH_KEYPAD(vk, normal, shifted) \
+            case (vk): \
+            { \
+                seqstr = _get_keypad_sequence(control_key_state, (normal), \
+                    (shifted)); \
+            } \
+            break;
+
+        // The shift key and other modifier keys should affect the output
+        // sequence.
+#define MATCH_MODIFIER_KEYPAD(vk, normal, shifted) \
+            case (vk): \
+            { \
+                seqbuflen = _get_modifier_keypad_sequence(seqbuf, (vk), \
+                    control_key_state, (normal), (shifted)); \
+            } \
+            break;
+
+#define ESC "\x1b"
+#define CSI ESC "["
+#define SS3 ESC "O"
+
+        // Only support normal mode, not application mode.
+
+        // Enhanced keys:
+        // * 6-pack: insert, delete, home, end, page up, page down
+        // * cursor keys: up, down, right, left
+        // * keypad: divide, enter
+        // * Undocumented: VK_PAUSE (Ctrl-NumLock), VK_SNAPSHOT,
+        //   VK_CANCEL (Ctrl-Pause/Break), VK_NUMLOCK
+        if (_is_enhanced_key(control_key_state)) {
+            switch (vk) {
+                case VK_RETURN: // Enter key on keypad
+                    if (_is_ctrl_pressed(control_key_state)) {
+                        seqstr = "\n";
+                    } else {
+                        seqstr = "\r";
+                    }
+                    break;
+
+                MATCH_MODIFIER(VK_PRIOR, CSI "5~"); // Page Up
+                MATCH_MODIFIER(VK_NEXT,  CSI "6~"); // Page Down
+
+                // gnome-terminal currently sends SS3 "F" and SS3 "H", but that
+                // will be fixed soon to match xterm which sends CSI "F" and
+                // CSI "H". https://bugzilla.redhat.com/show_bug.cgi?id=1119764
+                MATCH(VK_END,  CSI "F");
+                MATCH(VK_HOME, CSI "H");
+
+                MATCH_MODIFIER(VK_LEFT,  CSI "D");
+                MATCH_MODIFIER(VK_UP,    CSI "A");
+                MATCH_MODIFIER(VK_RIGHT, CSI "C");
+                MATCH_MODIFIER(VK_DOWN,  CSI "B");
+
+                MATCH_MODIFIER(VK_INSERT, CSI "2~");
+                MATCH_MODIFIER(VK_DELETE, CSI "3~");
+
+                MATCH(VK_DIVIDE, "/");
+            }
+        } else {    // Non-enhanced keys:
+            switch (vk) {
+                case VK_BACK:   // backspace
+                    if (_is_alt_pressed(control_key_state)) {
+                        seqstr = ESC "\x7f";
+                    } else {
+                        seqstr = "\x7f";
+                    }
+                    break;
+
+                case VK_TAB:
+                    if (_is_shift_pressed(control_key_state)) {
+                        seqstr = CSI "Z";
+                    } else {
+                        seqstr = "\t";
+                    }
+                    break;
+
+                // Number 5 key in keypad when NumLock is off, or if NumLock is
+                // on and Shift is down.
+                MATCH_KEYPAD(VK_CLEAR, CSI "E", "5");
+
+                case VK_RETURN:     // Enter key on main keyboard
+                    if (_is_alt_pressed(control_key_state)) {
+                        seqstr = ESC "\n";
+                    } else if (_is_ctrl_pressed(control_key_state)) {
+                        seqstr = "\n";
+                    } else {
+                        seqstr = "\r";
+                    }
+                    break;
+
+                // VK_ESCAPE: Don't do any special handling. The OS uses many
+                // of the sequences with Escape and many of the remaining
+                // sequences don't produce bKeyDown messages, only !bKeyDown
+                // for whatever reason.
+
+                case VK_SPACE:
+                    if (_is_alt_pressed(control_key_state)) {
+                        seqstr = ESC " ";
+                    } else if (_is_ctrl_pressed(control_key_state)) {
+                        seqbuf[0] = '\0';   // NULL char
+                        seqbuflen = 1;
+                    } else {
+                        seqstr = " ";
+                    }
+                    break;
+
+                MATCH_MODIFIER_KEYPAD(VK_PRIOR, CSI "5~", '9'); // Page Up
+                MATCH_MODIFIER_KEYPAD(VK_NEXT,  CSI "6~", '3'); // Page Down
+
+                MATCH_KEYPAD(VK_END,  CSI "4~", "1");
+                MATCH_KEYPAD(VK_HOME, CSI "1~", "7");
+
+                MATCH_MODIFIER_KEYPAD(VK_LEFT,  CSI "D", '4');
+                MATCH_MODIFIER_KEYPAD(VK_UP,    CSI "A", '8');
+                MATCH_MODIFIER_KEYPAD(VK_RIGHT, CSI "C", '6');
+                MATCH_MODIFIER_KEYPAD(VK_DOWN,  CSI "B", '2');
+
+                MATCH_MODIFIER_KEYPAD(VK_INSERT, CSI "2~", '0');
+                MATCH_MODIFIER_KEYPAD(VK_DELETE, CSI "3~",
+                    _get_decimal_char());
+
+                case 0x30:          // 0
+                case 0x31:          // 1
+                case 0x39:          // 9
+                case VK_OEM_1:      // ;:
+                case VK_OEM_PLUS:   // =+
+                case VK_OEM_COMMA:  // ,<
+                case VK_OEM_PERIOD: // .>
+                case VK_OEM_7:      // '"
+                case VK_OEM_102:    // depends on keyboard, could be <> or \|
+                case VK_OEM_2:      // /?
+                case VK_OEM_3:      // `~
+                case VK_OEM_4:      // [{
+                case VK_OEM_5:      // \|
+                case VK_OEM_6:      // ]}
+                {
+                    seqbuflen = _get_control_character(seqbuf, key_event,
+                        control_key_state);
+
+                    if (_is_alt_pressed(control_key_state)) {
+                        seqbuflen = _escape_prefix(seqbuf, seqbuflen);
+                    }
+                }
+                break;
+
+                case 0x32:          // 2
+                case 0x36:          // 6
+                case VK_OEM_MINUS:  // -_
+                {
+                    seqbuflen = _get_control_character(seqbuf, key_event,
+                        control_key_state);
+
+                    // If Alt is pressed and it isn't Ctrl-Alt-ShiftUp, then
+                    // prefix with escape.
+                    if (_is_alt_pressed(control_key_state) &&
+                        !(_is_ctrl_pressed(control_key_state) &&
+                        !_is_shift_pressed(control_key_state))) {
+                        seqbuflen = _escape_prefix(seqbuf, seqbuflen);
+                    }
+                }
+                break;
+
+                case 0x33:  // 3
+                case 0x34:  // 4
+                case 0x35:  // 5
+                case 0x37:  // 7
+                case 0x38:  // 8
+                {
+                    seqbuflen = _get_control_character(seqbuf, key_event,
+                        control_key_state);
+
+                    // If Alt is pressed and it isn't Ctrl-Alt-ShiftUp, then
+                    // prefix with escape.
+                    if (_is_alt_pressed(control_key_state) &&
+                        !(_is_ctrl_pressed(control_key_state) &&
+                        !_is_shift_pressed(control_key_state))) {
+                        seqbuflen = _escape_prefix(seqbuf, seqbuflen);
+                    }
+                }
+                break;
+
+                case 0x41:  // a
+                case 0x42:  // b
+                case 0x43:  // c
+                case 0x44:  // d
+                case 0x45:  // e
+                case 0x46:  // f
+                case 0x47:  // g
+                case 0x48:  // h
+                case 0x49:  // i
+                case 0x4a:  // j
+                case 0x4b:  // k
+                case 0x4c:  // l
+                case 0x4d:  // m
+                case 0x4e:  // n
+                case 0x4f:  // o
+                case 0x50:  // p
+                case 0x51:  // q
+                case 0x52:  // r
+                case 0x53:  // s
+                case 0x54:  // t
+                case 0x55:  // u
+                case 0x56:  // v
+                case 0x57:  // w
+                case 0x58:  // x
+                case 0x59:  // y
+                case 0x5a:  // z
+                {
+                    seqbuflen = _get_non_alt_char(seqbuf, key_event,
+                        control_key_state);
+
+                    // If Alt is pressed, then prefix with escape.
+                    if (_is_alt_pressed(control_key_state)) {
+                        seqbuflen = _escape_prefix(seqbuf, seqbuflen);
+                    }
+                }
+                break;
+
+                // These virtual key codes are generated by the keys on the
+                // keypad *when NumLock is on* and *Shift is up*.
+                MATCH(VK_NUMPAD0, "0");
+                MATCH(VK_NUMPAD1, "1");
+                MATCH(VK_NUMPAD2, "2");
+                MATCH(VK_NUMPAD3, "3");
+                MATCH(VK_NUMPAD4, "4");
+                MATCH(VK_NUMPAD5, "5");
+                MATCH(VK_NUMPAD6, "6");
+                MATCH(VK_NUMPAD7, "7");
+                MATCH(VK_NUMPAD8, "8");
+                MATCH(VK_NUMPAD9, "9");
+
+                MATCH(VK_MULTIPLY, "*");
+                MATCH(VK_ADD,      "+");
+                MATCH(VK_SUBTRACT, "-");
+                // VK_DECIMAL is generated by the . key on the keypad *when
+                // NumLock is on* and *Shift is up* and the sequence is not
+                // Ctrl-Alt-NoShift-. (which causes Ctrl-Alt-Del and the
+                // Windows Security screen to come up).
+                case VK_DECIMAL:
+                    // U.S. English uses '.', Germany German uses ','.
+                    seqbuflen = _get_non_control_char(seqbuf, key_event,
+                        control_key_state);
+                    break;
+
+                MATCH_MODIFIER(VK_F1,  SS3 "P");
+                MATCH_MODIFIER(VK_F2,  SS3 "Q");
+                MATCH_MODIFIER(VK_F3,  SS3 "R");
+                MATCH_MODIFIER(VK_F4,  SS3 "S");
+                MATCH_MODIFIER(VK_F5,  CSI "15~");
+                MATCH_MODIFIER(VK_F6,  CSI "17~");
+                MATCH_MODIFIER(VK_F7,  CSI "18~");
+                MATCH_MODIFIER(VK_F8,  CSI "19~");
+                MATCH_MODIFIER(VK_F9,  CSI "20~");
+                MATCH_MODIFIER(VK_F10, CSI "21~");
+                MATCH_MODIFIER(VK_F11, CSI "23~");
+                MATCH_MODIFIER(VK_F12, CSI "24~");
+
+                MATCH_MODIFIER(VK_F13, CSI "25~");
+                MATCH_MODIFIER(VK_F14, CSI "26~");
+                MATCH_MODIFIER(VK_F15, CSI "28~");
+                MATCH_MODIFIER(VK_F16, CSI "29~");
+                MATCH_MODIFIER(VK_F17, CSI "31~");
+                MATCH_MODIFIER(VK_F18, CSI "32~");
+                MATCH_MODIFIER(VK_F19, CSI "33~");
+                MATCH_MODIFIER(VK_F20, CSI "34~");
+
+                // MATCH_MODIFIER(VK_F21, ???);
+                // MATCH_MODIFIER(VK_F22, ???);
+                // MATCH_MODIFIER(VK_F23, ???);
+                // MATCH_MODIFIER(VK_F24, ???);
+            }
+        }
+
+#undef MATCH
+#undef MATCH_MODIFIER
+#undef MATCH_KEYPAD
+#undef MATCH_MODIFIER_KEYPAD
+#undef ESC
+#undef CSI
+#undef SS3
+
+        const char* out;
+        size_t outlen;
+
+        // Check for output in any of:
+        // * seqstr is set (and strlen can be used to determine the length).
+        // * seqbuf and seqbuflen are set
+        // Fallback to ch from Windows.
+        if (seqstr != NULL) {
+            out = seqstr;
+            outlen = strlen(seqstr);
+        } else if (seqbuflen > 0) {
+            out = seqbuf;
+            outlen = seqbuflen;
+        } else if (ch != '\0') {
+            // Use whatever Windows told us it is.
+            seqbuf[0] = ch;
+            seqbuflen = 1;
+            out = seqbuf;
+            outlen = seqbuflen;
+        } else {
+            // No special handling for the virtual key code and Windows isn't
+            // telling us a character code, then we don't know how to translate
+            // the key press.
+            //
+            // Consume the input and 'continue' to cause us to get a new key
+            // event.
+            D("_console_read: unknown virtual key code: %d, enhanced: %s\n",
+                vk, _is_enhanced_key(control_key_state) ? "true" : "false");
+            key_event->wRepeatCount = 0;
+            continue;
+        }
+
+        int bytesRead = 0;
+
+        // put output wRepeatCount times into buf/len
+        while (key_event->wRepeatCount > 0) {
+            if (len >= outlen) {
+                // Write to buf/len
+                memcpy(buf, out, outlen);
+                buf = (void*)((char*)buf + outlen);
+                len -= outlen;
+                bytesRead += outlen;
+
+                // consume the input
+                --key_event->wRepeatCount;
+            } else {
+                // Not enough space, so just leave it in _win32_input_record
+                // for a subsequent retrieval.
+                if (bytesRead == 0) {
+                    // We didn't write anything because there wasn't enough
+                    // space to even write one sequence. This should never
+                    // happen if the caller uses sensible buffer sizes
+                    // (i.e. >= maximum sequence length which is probably a
+                    // few bytes long).
+                    D("_console_read: no buffer space to write one sequence; "
+                        "buffer: %ld, sequence: %ld\n", (long)len,
+                        (long)outlen);
+                    errno = ENOMEM;
+                    return -1;
+                } else {
+                    // Stop trying to write to buf/len, just return whatever
+                    // we wrote so far.
+                    break;
+                }
+            }
+        }
+
+        return bytesRead;
+    }
+}
+
+static DWORD _old_console_mode; // previous GetConsoleMode() result
+static HANDLE _console_handle;  // when set, console mode should be restored
+
+void stdin_raw_init(const int fd) {
+    if (STDIN_FILENO == fd) {
+        const HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
+        if ((in == INVALID_HANDLE_VALUE) || (in == NULL)) {
+            return;
+        }
+
+        if (GetFileType(in) != FILE_TYPE_CHAR) {
+            // stdin might be a file or pipe.
+            return;
+        }
+
+        if (!GetConsoleMode(in, &_old_console_mode)) {
+            // If GetConsoleMode() fails, stdin is probably is not a console.
+            return;
+        }
+
+        // Disable ENABLE_PROCESSED_INPUT so that Ctrl-C is read instead of
+        // calling the process Ctrl-C routine (configured by
+        // SetConsoleCtrlHandler()).
+        // Disable ENABLE_LINE_INPUT so that input is immediately sent.
+        // Disable ENABLE_ECHO_INPUT to disable local echo. Disabling this
+        // flag also seems necessary to have proper line-ending processing.
+        if (!SetConsoleMode(in, _old_console_mode & ~(ENABLE_PROCESSED_INPUT |
+            ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT))) {
+            // This really should not fail.
+            D("stdin_raw_init: SetConsoleMode() failure, error %ld\n",
+                GetLastError());
+        }
+
+        // Once this is set, it means that stdin has been configured for
+        // reading from and that the old console mode should be restored later.
+        _console_handle = in;
+
+        // Note that we don't need to configure C Runtime line-ending
+        // translation because _console_read() does not call the C Runtime to
+        // read from the console.
+    }
+}
+
+void stdin_raw_restore(const int fd) {
+    if (STDIN_FILENO == fd) {
+        if (_console_handle != NULL) {
+            const HANDLE in = _console_handle;
+            _console_handle = NULL;  // clear state
+
+            if (!SetConsoleMode(in, _old_console_mode)) {
+                // This really should not fail.
+                D("stdin_raw_restore: SetConsoleMode() failure, error %ld\n",
+                    GetLastError());
+            }
+        }
+    }
+}
+
+// Called by 'adb shell' command to read from stdin.
+int unix_read(int fd, void* buf, size_t len) {
+    if ((fd == STDIN_FILENO) && (_console_handle != NULL)) {
+        // If it is a request to read from stdin, and stdin_raw_init() has been
+        // called, and it successfully configured the console, then read from
+        // the console using Win32 console APIs and partially emulate a unix
+        // terminal.
+        return _console_read(_console_handle, buf, len);
+    } else {
+        // Just call into C Runtime which can read from pipes/files and which
+        // can do LF/CR translation.
+#undef read
+        return read(fd, buf, len);
+    }
+}
diff --git a/adb/test_track_devices.c b/adb/test_track_devices.c
deleted file mode 100644
index 77b3ad9..0000000
--- a/adb/test_track_devices.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/* a simple test program, connects to ADB server, and opens a track-devices session */
-#include <netdb.h>
-#include <sys/socket.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <memory.h>
-
-static void
-panic( const char*  msg )
-{
-    fprintf(stderr, "PANIC: %s: %s\n", msg, strerror(errno));
-    exit(1);
-}
-
-static int
-unix_write( int  fd, const char*  buf, int  len )
-{
-    int  result = 0;
-    while (len > 0) {
-        int  len2 = write(fd, buf, len);
-        if (len2 < 0) {
-            if (errno == EINTR || errno == EAGAIN)
-                continue;
-            return -1;
-        }
-        result += len2;
-        len -= len2;
-        buf += len2;
-    }
-    return  result;
-}
-
-static int
-unix_read( int  fd, char*  buf, int  len )
-{
-    int  result = 0;
-    while (len > 0) {
-        int  len2 = read(fd, buf, len);
-        if (len2 < 0) {
-            if (errno == EINTR || errno == EAGAIN)
-                continue;
-            return -1;
-        }
-        result += len2;
-        len -= len2;
-        buf += len2;
-    }
-    return  result;
-}
-
-
-int  main( void )
-{
-    int                  ret, s;
-    struct sockaddr_in   server;
-    char                 buffer[1024];
-    const char*          request = "host:track-devices";
-    int                  len;
-
-    memset( &server, 0, sizeof(server) );
-    server.sin_family      = AF_INET;
-    server.sin_port        = htons(5037);
-    server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
-    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 */
-    len = snprintf( buffer, sizeof buffer, "%04x%s", strlen(request), request );
-    if (unix_write(s, buffer, len) < 0)
-        panic( "could not send request" );
-
-    /* read the OKAY answer */
-    if (unix_read(s, buffer, 4) != 4)
-        panic( "could not read request" );
-
-    printf( "server answer: %.*s\n", 4, buffer );
-
-    /* now loop */
-    for (;;) {
-        char  head[5] = "0000";
-
-        if (unix_read(s, head, 4) < 0)
-            panic("could not read length");
-
-        if ( sscanf( head, "%04x", &len ) != 1 )
-            panic("could not decode length");
-
-        if (unix_read(s, buffer, len) != len)
-            panic("could not read data");
-
-        printf( "received header %.*s (%d bytes):\n%.*s", 4, head, len, len, buffer );
-    }
-    close(s);
-}
diff --git a/adb/test_track_devices.cpp b/adb/test_track_devices.cpp
new file mode 100644
index 0000000..3e823e9
--- /dev/null
+++ b/adb/test_track_devices.cpp
@@ -0,0 +1,68 @@
+// TODO: replace this with a shell/python script.
+
+/* a simple test program, connects to ADB server, and opens a track-devices session */
+#include <netdb.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <memory.h>
+
+#include <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", 4, head, len, len, buffer );
+    }
+    close(s);
+}
diff --git a/adb/test_track_jdwp.c b/adb/test_track_jdwp.c
deleted file mode 100644
index 8ecc6b8..0000000
--- a/adb/test_track_jdwp.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/* a simple test program, connects to ADB server, and opens a track-devices session */
-#include <netdb.h>
-#include <sys/socket.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <memory.h>
-
-static void
-panic( const char*  msg )
-{
-    fprintf(stderr, "PANIC: %s: %s\n", msg, strerror(errno));
-    exit(1);
-}
-
-static int
-unix_write( int  fd, const char*  buf, int  len )
-{
-    int  result = 0;
-    while (len > 0) {
-        int  len2 = write(fd, buf, len);
-        if (len2 < 0) {
-            if (errno == EINTR || errno == EAGAIN)
-                continue;
-            return -1;
-        }
-        result += len2;
-        len -= len2;
-        buf += len2;
-    }
-    return  result;
-}
-
-static int
-unix_read( int  fd, char*  buf, int  len )
-{
-    int  result = 0;
-    while (len > 0) {
-        int  len2 = read(fd, buf, len);
-        if (len2 < 0) {
-            if (errno == EINTR || errno == EAGAIN)
-                continue;
-            return -1;
-        }
-        result += len2;
-        len -= len2;
-        buf += len2;
-    }
-    return  result;
-}
-
-
-int  main( void )
-{
-    int                  ret, s;
-    struct sockaddr_in   server;
-    char                 buffer[1024];
-    const char*          request = "track-jdwp";
-    int                  len;
-
-    memset( &server, 0, sizeof(server) );
-    server.sin_family      = AF_INET;
-    server.sin_port        = htons(5037);
-    server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
-    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 */
-    len = snprintf( buffer, sizeof buffer, "%04x%s", strlen(request), request );
-    if (unix_write(s, buffer, len) < 0)
-        panic( "could not send request" );
-
-    /* read the OKAY answer */
-    if (unix_read(s, buffer, 4) != 4)
-        panic( "could not read request" );
-
-    printf( "server answer: %.*s\n", 4, buffer );
-
-    /* now loop */
-    for (;;) {
-        char  head[5] = "0000";
-
-        if (unix_read(s, head, 4) < 0)
-            panic("could not read length");
-
-        if ( sscanf( head, "%04x", &len ) != 1 )
-            panic("could not decode length");
-
-        if (unix_read(s, buffer, len) != len)
-            panic("could not read data");
-
-        printf( "received header %.*s (%d bytes):\n%.*s", 4, head, len, len, buffer );
-    }
-    close(s);
-}
diff --git a/adb/tests/test_adb.py b/adb/tests/test_adb.py
new file mode 100755
index 0000000..0ff87d2
--- /dev/null
+++ b/adb/tests/test_adb.py
@@ -0,0 +1,439 @@
+#!/usr/bin/env python2
+"""Simple conformance test for adb.
+
+This script will use the available adb in path and run simple
+tests that attempt to touch all accessible attached devices.
+"""
+import hashlib
+import os
+import pipes
+import random
+import re
+import shlex
+import subprocess
+import sys
+import tempfile
+import unittest
+
+
+def trace(cmd):
+    """Print debug message if tracing enabled."""
+    if False:
+        print >> sys.stderr, cmd
+
+
+def call(cmd_str):
+    """Run process and return output tuple (stdout, stderr, ret code)."""
+    trace(cmd_str)
+    process = subprocess.Popen(shlex.split(cmd_str),
+                               stdout=subprocess.PIPE,
+                               stderr=subprocess.PIPE)
+    stdout, stderr = process.communicate()
+    return stdout, stderr, process.returncode
+
+
+def call_combined(cmd_str):
+    """Run process and return output tuple (stdout+stderr, ret code)."""
+    trace(cmd_str)
+    process = subprocess.Popen(shlex.split(cmd_str),
+                               stdout=subprocess.PIPE,
+                               stderr=subprocess.STDOUT)
+    stdout, _ = process.communicate()
+    return stdout, process.returncode
+
+
+def call_checked(cmd_str):
+    """Run process and get stdout+stderr, raise an exception on trouble."""
+    trace(cmd_str)
+    return subprocess.check_output(shlex.split(cmd_str),
+                                   stderr=subprocess.STDOUT)
+
+
+def call_checked_list(cmd_str):
+    return call_checked(cmd_str).split('\n')
+
+
+def call_checked_list_skip(cmd_str):
+    out_list = call_checked_list(cmd_str)
+
+    def is_init_line(line):
+        if (len(line) >= 3) and (line[0] == "*") and (line[-2] == "*"):
+            return True
+        else:
+            return False
+
+    return [line for line in out_list if not is_init_line(line)]
+
+
+def get_device_list():
+    output = call_checked_list_skip("adb devices")
+    dev_list = []
+    for line in output[1:]:
+        if line.strip() == "":
+            continue
+        device, _ = line.split()
+        dev_list.append(device)
+    return dev_list
+
+
+def get_attached_device_count():
+    return len(get_device_list())
+
+
+def compute_md5(string):
+    hsh = hashlib.md5()
+    hsh.update(string)
+    return hsh.hexdigest()
+
+
+class HostFile(object):
+    def __init__(self, handle, md5):
+        self.handle = handle
+        self.md5 = md5
+        self.full_path = handle.name
+        self.base_name = os.path.basename(self.full_path)
+
+
+class DeviceFile(object):
+    def __init__(self, md5, full_path):
+        self.md5 = md5
+        self.full_path = full_path
+        self.base_name = os.path.basename(self.full_path)
+
+
+def make_random_host_files(in_dir, num_files, rand_size=True):
+    files = {}
+    min_size = 1 * (1 << 10)
+    max_size = 16 * (1 << 10)
+    fixed_size = min_size
+
+    for _ in range(num_files):
+        file_handle = tempfile.NamedTemporaryFile(dir=in_dir)
+
+        if rand_size:
+            size = random.randrange(min_size, max_size, 1024)
+        else:
+            size = fixed_size
+        rand_str = os.urandom(size)
+        file_handle.write(rand_str)
+        file_handle.flush()
+
+        md5 = compute_md5(rand_str)
+        files[file_handle.name] = HostFile(file_handle, md5)
+    return files
+
+
+def make_random_device_files(adb, in_dir, num_files, rand_size=True):
+    files = {}
+    min_size = 1 * (1 << 10)
+    max_size = 16 * (1 << 10)
+    fixed_size = min_size
+
+    for i in range(num_files):
+        if rand_size:
+            size = random.randrange(min_size, max_size, 1024)
+        else:
+            size = fixed_size
+
+        base_name = "device_tmpfile" + str(i)
+        full_path = in_dir + "/" + base_name
+
+        adb.shell("dd if=/dev/urandom of={} bs={} count=1".format(full_path,
+                                                                  size))
+        dev_md5, _ = adb.shell("md5sum {}".format(full_path)).split()
+
+        files[full_path] = DeviceFile(dev_md5, full_path)
+    return files
+
+
+class AdbWrapper(object):
+    """Convenience wrapper object for the adb command."""
+    def __init__(self, device=None, out_dir=None):
+        self.device = device
+        self.out_dir = out_dir
+        self.adb_cmd = "adb "
+        if self.device:
+            self.adb_cmd += "-s {} ".format(device)
+        if self.out_dir:
+            self.adb_cmd += "-p {} ".format(out_dir)
+
+    def shell(self, cmd):
+        return call_checked(self.adb_cmd + "shell " + cmd)
+
+    def shell_nocheck(self, cmd):
+        return call_combined(self.adb_cmd + "shell " + cmd)
+
+    def install(self, filename):
+        return call_checked(self.adb_cmd + "install {}".format(pipes.quote(filename)))
+
+    def push(self, local, remote):
+        return call_checked(self.adb_cmd + "push {} {}".format(local, remote))
+
+    def pull(self, remote, local):
+        return call_checked(self.adb_cmd + "pull {} {}".format(remote, local))
+
+    def sync(self, directory=""):
+        return call_checked(self.adb_cmd + "sync {}".format(directory))
+
+    def forward(self, local, remote):
+        return call_checked(self.adb_cmd + "forward {} {}".format(local,
+                                                                  remote))
+
+    def tcpip(self, port):
+        return call_checked(self.adb_cmd + "tcpip {}".format(port))
+
+    def usb(self):
+        return call_checked(self.adb_cmd + "usb")
+
+    def root(self):
+        return call_checked(self.adb_cmd + "root")
+
+    def unroot(self):
+        return call_checked(self.adb_cmd + "unroot")
+
+    def forward_remove(self, local):
+        return call_checked(self.adb_cmd + "forward --remove {}".format(local))
+
+    def forward_remove_all(self):
+        return call_checked(self.adb_cmd + "forward --remove-all")
+
+    def connect(self, host):
+        return call_checked(self.adb_cmd + "connect {}".format(host))
+
+    def disconnect(self, host):
+        return call_checked(self.adb_cmd + "disconnect {}".format(host))
+
+    def reverse(self, remote, local):
+        return call_checked(self.adb_cmd + "reverse {} {}".format(remote,
+                                                                  local))
+
+    def reverse_remove_all(self):
+        return call_checked(self.adb_cmd + "reverse --remove-all")
+
+    def reverse_remove(self, remote):
+        return call_checked(
+            self.adb_cmd + "reverse --remove {}".format(remote))
+
+    def wait(self):
+        return call_checked(self.adb_cmd + "wait-for-device")
+
+
+class AdbBasic(unittest.TestCase):
+    def test_shell(self):
+        """Check that we can at least cat a file."""
+        adb = AdbWrapper()
+        out = adb.shell("cat /proc/uptime")
+        self.assertEqual(len(out.split()), 2)
+        self.assertGreater(float(out.split()[0]), 0.0)
+        self.assertGreater(float(out.split()[1]), 0.0)
+
+    def test_help(self):
+        """Make sure we get _something_ out of help."""
+        out = call_checked("adb help")
+        self.assertTrue(len(out) > 0)
+
+    def test_version(self):
+        """Get a version number out of the output of adb."""
+        out = call_checked("adb version").split()
+        version_num = False
+        for item in out:
+            if re.match(r"[\d+\.]*\d", item):
+                version_num = True
+        self.assertTrue(version_num)
+
+    def _test_root(self):
+        adb = AdbWrapper()
+        adb.root()
+        adb.wait()
+        self.assertEqual("root", adb.shell("id -un").strip())
+
+    def _test_unroot(self):
+        adb = AdbWrapper()
+        adb.unroot()
+        adb.wait()
+        self.assertEqual("shell", adb.shell("id -un").strip())
+
+    def test_root_unroot(self):
+        """Make sure that adb root and adb unroot work, using id(1)."""
+        adb = AdbWrapper()
+        original_user = adb.shell("id -un").strip()
+        try:
+            if original_user == "root":
+                self._test_unroot()
+                self._test_root()
+            elif original_user == "shell":
+                self._test_root()
+                self._test_unroot()
+        finally:
+            if original_user == "root":
+                adb.root()
+            else:
+                adb.unroot()
+            adb.wait()
+
+    def test_argument_escaping(self):
+        """Make sure that argument escaping is somewhat sane."""
+        adb = AdbWrapper()
+
+        # http://b/19734868
+        # Note that this actually matches ssh(1)'s behavior --- it's
+        # converted to "sh -c echo hello; echo world" which sh interprets
+        # as "sh -c echo" (with an argument to that shell of "hello"),
+        # and then "echo world" back in the first shell.
+        result = adb.shell("sh -c 'echo hello; echo world'").splitlines()
+        self.assertEqual(["", "world"], result)
+        # If you really wanted "hello" and "world", here's what you'd do:
+        result = adb.shell("echo hello\;echo world").splitlines()
+        self.assertEqual(["hello", "world"], result)
+
+        # http://b/15479704
+        self.assertEqual('t', adb.shell("'true && echo t'").strip())
+        self.assertEqual('t', adb.shell("sh -c 'true && echo t'").strip())
+
+        # http://b/20564385
+        self.assertEqual('t', adb.shell("FOO=a BAR=b echo t").strip())
+        self.assertEqual('123Linux', adb.shell("echo -n 123\;uname").strip())
+
+    def test_install_argument_escaping(self):
+        """Make sure that install argument escaping works."""
+        adb = AdbWrapper()
+
+        # http://b/20323053
+        tf = tempfile.NamedTemporaryFile("w", suffix="-text;ls;1.apk")
+        self.assertIn("-text;ls;1.apk", adb.install(tf.name))
+
+        # http://b/3090932
+        tf = tempfile.NamedTemporaryFile("w", suffix="-Live Hold'em.apk")
+        self.assertIn("-Live Hold'em.apk", adb.install(tf.name))
+
+
+class AdbFile(unittest.TestCase):
+    SCRATCH_DIR = "/data/local/tmp"
+    DEVICE_TEMP_FILE = SCRATCH_DIR + "/adb_test_file"
+    DEVICE_TEMP_DIR = SCRATCH_DIR + "/adb_test_dir"
+
+    def test_push(self):
+        """Push a randomly generated file to specified device."""
+        kbytes = 512
+        adb = AdbWrapper()
+        with tempfile.NamedTemporaryFile(mode="w") as tmp:
+            rand_str = os.urandom(1024 * kbytes)
+            tmp.write(rand_str)
+            tmp.flush()
+
+            host_md5 = compute_md5(rand_str)
+            adb.shell_nocheck("rm -r {}".format(AdbFile.DEVICE_TEMP_FILE))
+            try:
+                adb.push(local=tmp.name, remote=AdbFile.DEVICE_TEMP_FILE)
+                dev_md5, _ = adb.shell(
+                    "md5sum {}".format(AdbFile.DEVICE_TEMP_FILE)).split()
+                self.assertEqual(host_md5, dev_md5)
+            finally:
+                adb.shell_nocheck("rm {}".format(AdbFile.DEVICE_TEMP_FILE))
+
+    # TODO: write push directory test.
+
+    def test_pull(self):
+        """Pull a randomly generated file from specified device."""
+        kbytes = 512
+        adb = AdbWrapper()
+        adb.shell_nocheck("rm -r {}".format(AdbFile.DEVICE_TEMP_FILE))
+        try:
+            adb.shell("dd if=/dev/urandom of={} bs=1024 count={}".format(
+                AdbFile.DEVICE_TEMP_FILE, kbytes))
+            dev_md5, _ = adb.shell(
+                "md5sum {}".format(AdbFile.DEVICE_TEMP_FILE)).split()
+
+            with tempfile.NamedTemporaryFile(mode="w") as tmp_write:
+                adb.pull(remote=AdbFile.DEVICE_TEMP_FILE, local=tmp_write.name)
+                with open(tmp_write.name) as tmp_read:
+                    host_contents = tmp_read.read()
+                    host_md5 = compute_md5(host_contents)
+                self.assertEqual(dev_md5, host_md5)
+        finally:
+            adb.shell_nocheck("rm {}".format(AdbFile.DEVICE_TEMP_FILE))
+
+    def test_pull_dir(self):
+        """Pull a randomly generated directory of files from the device."""
+        adb = AdbWrapper()
+        temp_files = {}
+        host_dir = None
+        try:
+            # create temporary host directory
+            host_dir = tempfile.mkdtemp()
+
+            # create temporary dir on device
+            adb.shell_nocheck("rm -r {}".format(AdbFile.DEVICE_TEMP_DIR))
+            adb.shell("mkdir -p {}".format(AdbFile.DEVICE_TEMP_DIR))
+
+            # populate device dir with random files
+            temp_files = make_random_device_files(
+                adb, in_dir=AdbFile.DEVICE_TEMP_DIR, num_files=32)
+
+            adb.pull(remote=AdbFile.DEVICE_TEMP_DIR, local=host_dir)
+
+            for device_full_path in temp_files:
+                host_path = os.path.join(
+                    host_dir, temp_files[device_full_path].base_name)
+                with open(host_path) as host_file:
+                    host_md5 = compute_md5(host_file.read())
+                    self.assertEqual(host_md5,
+                                     temp_files[device_full_path].md5)
+        finally:
+            for dev_file in temp_files.values():
+                host_path = os.path.join(host_dir, dev_file.base_name)
+                os.remove(host_path)
+            adb.shell_nocheck("rm -r {}".format(AdbFile.DEVICE_TEMP_DIR))
+            if host_dir:
+                os.removedirs(host_dir)
+
+    def test_sync(self):
+        """Sync a randomly generated directory of files to specified device."""
+        try:
+            adb = AdbWrapper()
+            temp_files = {}
+
+            # create temporary host directory
+            base_dir = tempfile.mkdtemp()
+
+            # create mirror device directory hierarchy within base_dir
+            full_dir_path = base_dir + AdbFile.DEVICE_TEMP_DIR
+            os.makedirs(full_dir_path)
+
+            # create 32 random files within the host mirror
+            temp_files = make_random_host_files(in_dir=full_dir_path,
+                                                num_files=32)
+
+            # clean up any trash on the device
+            adb = AdbWrapper(out_dir=base_dir)
+            adb.shell_nocheck("rm -r {}".format(AdbFile.DEVICE_TEMP_DIR))
+
+            # issue the sync
+            adb.sync("data")
+
+            # confirm that every file on the device mirrors that on the host
+            for host_full_path in temp_files.keys():
+                device_full_path = os.path.join(
+                    AdbFile.DEVICE_TEMP_DIR,
+                    temp_files[host_full_path].base_name)
+                dev_md5, _ = adb.shell(
+                    "md5sum {}".format(device_full_path)).split()
+                self.assertEqual(temp_files[host_full_path].md5, dev_md5)
+
+        finally:
+            adb.shell_nocheck("rm -r {}".format(AdbFile.DEVICE_TEMP_DIR))
+            if temp_files:
+                for tf in temp_files.values():
+                    tf.handle.close()
+            if base_dir:
+                os.removedirs(base_dir + AdbFile.DEVICE_TEMP_DIR)
+
+
+if __name__ == '__main__':
+    random.seed(0)
+    dev_count = get_attached_device_count()
+    if dev_count:
+        suite = unittest.TestLoader().loadTestsFromName(__name__)
+        unittest.TextTestRunner(verbosity=3).run(suite)
+    else:
+        print "Test suite must be run with attached devices"
diff --git a/adb/transport.c b/adb/transport.cpp
similarity index 74%
rename from adb/transport.c
rename to adb/transport.cpp
index f35880c..2cd6ac2 100644
--- a/adb/transport.c
+++ b/adb/transport.cpp
@@ -14,16 +14,22 @@
  * limitations under the License.
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
+#define TRACE_TAG TRACE_TRANSPORT
 
 #include "sysdeps.h"
+#include "transport.h"
 
-#define   TRACE_TAG  TRACE_TRANSPORT
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <base/stringprintf.h>
+
 #include "adb.h"
+#include "adb_utils.h"
 
 static void transport_unref(atransport *t);
 
@@ -39,36 +45,7 @@
 
 ADB_MUTEX_DEFINE( transport_lock );
 
-#if ADB_TRACE
-#define MAX_DUMP_HEX_LEN 16
-static void  dump_hex( const unsigned char*  ptr, size_t  len )
-{
-    int  nn, len2 = len;
-    // Build a string instead of logging each character.
-    // MAX chars in 2 digit hex, one space, MAX chars, one '\0'.
-    char buffer[MAX_DUMP_HEX_LEN *2 + 1 + MAX_DUMP_HEX_LEN + 1 ], *pb = buffer;
-
-    if (len2 > MAX_DUMP_HEX_LEN) len2 = MAX_DUMP_HEX_LEN;
-
-    for (nn = 0; nn < len2; nn++) {
-        sprintf(pb, "%02x", ptr[nn]);
-        pb += 2;
-    }
-    sprintf(pb++, " ");
-
-    for (nn = 0; nn < len2; nn++) {
-        int  c = ptr[nn];
-        if (c < 32 || c > 127)
-            c = '.';
-        *pb++ =  c;
-    }
-    *pb++ = '\0';
-    DR("%s\n", buffer);
-}
-#endif
-
-void
-kick_transport(atransport*  t)
+void kick_transport(atransport* t)
 {
     if (t && !t->kicked)
     {
@@ -85,8 +62,25 @@
     }
 }
 
-void
-run_transport_disconnects(atransport*  t)
+// Each atransport contains a list of adisconnects (t->disconnects).
+// An adisconnect contains a link to the next/prev adisconnect, a function
+// pointer to a disconnect callback which takes a void* piece of user data and
+// the atransport, and some user data for the callback (helpfully named
+// "opaque").
+//
+// The list is circular. New items are added to the entry member of the list
+// (t->disconnects) by add_transport_disconnect.
+//
+// run_transport_disconnects invokes each function in the list.
+//
+// Gotchas:
+//   * run_transport_disconnects assumes that t->disconnects is non-null, so
+//     this can't be run on a zeroed atransport.
+//   * The callbacks in this list are not removed when called, and this function
+//     is not guarded against running more than once. As such, ensure that this
+//     function is not called multiple times on the same atransport.
+//     TODO(danalbert): Just fix this so that it is guarded once you have tests.
+void run_transport_disconnects(atransport* t)
 {
     adisconnect*  dis = t->disconnects.next;
 
@@ -98,10 +92,7 @@
     }
 }
 
-#if ADB_TRACE
-static void
-dump_packet(const char* name, const char* func, apacket* p)
-{
+static void dump_packet(const char* name, const char* func, apacket* p) {
     unsigned  command = p->msg.command;
     int       len     = p->msg.data_length;
     char      cmd[9];
@@ -136,7 +127,6 @@
         name, func, cmd, arg0, arg1, len);
     dump_hex(p->data, len);
 }
-#endif /* ADB_TRACE */
 
 static int
 read_packet(int  fd, const char* name, apacket** ppacket)
@@ -161,11 +151,9 @@
         }
     }
 
-#if ADB_TRACE
     if (ADB_TRACING) {
         dump_packet(name, "from remote", *ppacket);
     }
-#endif
     return 0;
 }
 
@@ -180,11 +168,9 @@
         name = buff;
     }
 
-#if ADB_TRACE
     if (ADB_TRACING) {
         dump_packet(name, "to remote", *ppacket);
     }
-#endif
     len = sizeof(ppacket);
     while(len > 0) {
         r = adb_write(fd, p, len);
@@ -202,7 +188,7 @@
 
 static void transport_socket_events(int fd, unsigned events, void *_t)
 {
-    atransport *t = _t;
+    atransport *t = reinterpret_cast<atransport*>(_t);
     D("transport_socket_events(fd=%d, events=%04x,...)\n", fd, events);
     if(events & FDE_READ){
         apacket *p = 0;
@@ -259,7 +245,7 @@
 
 static void *output_thread(void *_t)
 {
-    atransport *t = _t;
+    atransport *t = reinterpret_cast<atransport*>(_t);
     apacket *p;
 
     D("%s: starting transport output thread on fd %d, SYNC online (%d)\n",
@@ -314,7 +300,7 @@
 
 static void *input_thread(void *_t)
 {
-    atransport *t = _t;
+    atransport *t = reinterpret_cast<atransport*>(_t);
     apacket *p;
     int active = 0;
 
@@ -370,24 +356,12 @@
 
 
 #if ADB_HOST
-static int list_transports_msg(char*  buffer, size_t  bufferlen)
-{
-    char  head[5];
-    int   len;
-
-    len = list_transports(buffer+4, bufferlen-4, 0);
-    snprintf(head, sizeof(head), "%04x", len);
-    memcpy(buffer, head, 4);
-    len += 4;
-    return len;
-}
 
 /* this adds support required by the 'track-devices' service.
  * this is used to send the content of "list_transport" to any
  * number of client connections that want it through a single
  * live TCP connection
  */
-typedef struct device_tracker  device_tracker;
 struct device_tracker {
     asocket          socket;
     int              update_needed;
@@ -439,45 +413,34 @@
     return -1;
 }
 
-static int
-device_tracker_send( device_tracker*  tracker,
-                     const char*      buffer,
-                     int              len )
-{
-    apacket*  p = get_apacket();
-    asocket*  peer = tracker->socket.peer;
+static int device_tracker_send(device_tracker* tracker, const std::string& string) {
+    apacket* p = get_apacket();
+    asocket* peer = tracker->socket.peer;
 
-    memcpy(p->data, buffer, len);
-    p->len = len;
-    return peer->enqueue( peer, p );
+    snprintf(reinterpret_cast<char*>(p->data), 5, "%04x", static_cast<int>(string.size()));
+    memcpy(&p->data[4], string.data(), string.size());
+    p->len = 4 + string.size();
+    return peer->enqueue(peer, p);
 }
 
+static void device_tracker_ready(asocket* socket) {
+    device_tracker* tracker = reinterpret_cast<device_tracker*>(socket);
 
-static void
-device_tracker_ready( asocket*  socket )
-{
-    device_tracker*  tracker = (device_tracker*) socket;
-
-    /* we want to send the device list when the tracker connects
-    * for the first time, even if no update occured */
+    // We want to send the device list when the tracker connects
+    // for the first time, even if no update occurred.
     if (tracker->update_needed > 0) {
-        char  buffer[1024];
-        int   len;
-
         tracker->update_needed = 0;
 
-        len = list_transports_msg(buffer, sizeof(buffer));
-        device_tracker_send(tracker, buffer, len);
+        std::string transports = list_transports(false);
+        device_tracker_send(tracker, transports);
     }
 }
 
-
 asocket*
 create_device_tracker(void)
 {
-    device_tracker*  tracker = calloc(1,sizeof(*tracker));
-
-    if(tracker == 0) fatal("cannot allocate device tracker");
+    device_tracker* tracker = reinterpret_cast<device_tracker*>(calloc(1, sizeof(*tracker)));
+    if (tracker == nullptr) fatal("cannot allocate device tracker");
 
     D( "device tracker %p created\n", tracker);
 
@@ -493,31 +456,27 @@
 }
 
 
-/* call this function each time the transport list has changed */
-void  update_transports(void)
-{
-    char             buffer[1024];
-    int              len;
-    device_tracker*  tracker;
+// Call this function each time the transport list has changed.
+void update_transports() {
+    std::string transports = list_transports(false);
 
-    len = list_transports_msg(buffer, sizeof(buffer));
-
-    tracker = device_tracker_list;
-    while (tracker != NULL) {
-        device_tracker*  next = tracker->next;
-        /* note: this may destroy the tracker if the connection is closed */
-        device_tracker_send(tracker, buffer, len);
+    device_tracker* tracker = device_tracker_list;
+    while (tracker != nullptr) {
+        device_tracker* next = tracker->next;
+        // This may destroy the tracker if the connection is closed.
+        device_tracker_send(tracker, transports);
         tracker = next;
     }
 }
+
 #else
-void  update_transports(void)
-{
-    // nothing to do on the device side
+
+void update_transports() {
+    // Nothing to do on the device side.
 }
+
 #endif // ADB_HOST
 
-typedef struct tmsg tmsg;
 struct tmsg
 {
     atransport *transport;
@@ -629,7 +588,7 @@
             fatal_errno("cannot open transport socketpair");
         }
 
-        D("transport: %s (%d,%d) starting\n", t->serial, s[0], s[1]);
+        D("transport: %s socketpair: (%d,%d) starting", t->serial, s[0], s[1]);
 
         t->transport_socket = s[0];
         t->fd = s[1];
@@ -673,6 +632,7 @@
     if(adb_socketpair(s)){
         fatal_errno("cannot open transport registration socketpair");
     }
+    D("socketpair: (%d,%d)", s[0], s[1]);
 
     transport_registration_send = s[0];
     transport_registration_recv = s[1];
@@ -751,19 +711,8 @@
     dis->next = dis->prev = dis;
 }
 
-static int qual_char_is_invalid(char ch)
-{
-    if ('A' <= ch && ch <= 'Z')
-        return 0;
-    if ('a' <= ch && ch <= 'z')
-        return 0;
-    if ('0' <= ch && ch <= '9')
-        return 0;
-    return 1;
-}
-
 static int qual_match(const char *to_test,
-                      const char *prefix, const char *qual, int sanitize_qual)
+                      const char *prefix, const char *qual, bool sanitize_qual)
 {
     if (!to_test || !*to_test)
         /* Return true if both the qual and to_test are null strings. */
@@ -781,7 +730,7 @@
 
     while (*qual) {
         char ch = *qual++;
-        if (sanitize_qual && qual_char_is_invalid(ch))
+        if (sanitize_qual && !isalnum(ch))
             ch = '_';
         if (ch != *to_test++)
             return 0;
@@ -791,21 +740,20 @@
     return !*to_test;
 }
 
-atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char** error_out)
+atransport* acquire_one_transport(int state, transport_type ttype,
+                                  const char* serial, std::string* error_out)
 {
     atransport *t;
     atransport *result = NULL;
     int ambiguous = 0;
 
 retry:
-    if (error_out)
-        *error_out = "device not found";
+    if (error_out) *error_out = android::base::StringPrintf("device '%s' not found", serial);
 
     adb_mutex_lock(&transport_lock);
     for (t = transport_list.next; t != &transport_list; t = t->next) {
         if (t->connection_state == CS_NOPERM) {
-        if (error_out)
-            *error_out = "insufficient permissions for device";
+            if (error_out) *error_out = "insufficient permissions for device";
             continue;
         }
 
@@ -813,12 +761,11 @@
         if (serial) {
             if ((t->serial && !strcmp(serial, t->serial)) ||
                 (t->devpath && !strcmp(serial, t->devpath)) ||
-                qual_match(serial, "product:", t->product, 0) ||
-                qual_match(serial, "model:", t->model, 1) ||
-                qual_match(serial, "device:", t->device, 0)) {
+                qual_match(serial, "product:", t->product, false) ||
+                qual_match(serial, "model:", t->model, true) ||
+                qual_match(serial, "device:", t->device, false)) {
                 if (result) {
-                    if (error_out)
-                        *error_out = "more than one device";
+                    if (error_out) *error_out = "more than one device";
                     ambiguous = 1;
                     result = NULL;
                     break;
@@ -828,8 +775,7 @@
         } else {
             if (ttype == kTransportUsb && t->type == kTransportUsb) {
                 if (result) {
-                    if (error_out)
-                        *error_out = "more than one device";
+                    if (error_out) *error_out = "more than one device";
                     ambiguous = 1;
                     result = NULL;
                     break;
@@ -837,8 +783,7 @@
                 result = t;
             } else if (ttype == kTransportLocal && t->type == kTransportLocal) {
                 if (result) {
-                    if (error_out)
-                        *error_out = "more than one emulator";
+                    if (error_out) *error_out = "more than one emulator";
                     ambiguous = 1;
                     result = NULL;
                     break;
@@ -846,8 +791,7 @@
                 result = t;
             } else if (ttype == kTransportAny) {
                 if (result) {
-                    if (error_out)
-                        *error_out = "more than one device and emulator";
+                    if (error_out) *error_out = "more than one device/emulator";
                     ambiguous = 1;
                     result = NULL;
                     break;
@@ -860,29 +804,33 @@
 
     if (result) {
         if (result->connection_state == CS_UNAUTHORIZED) {
-            if (error_out)
-                *error_out = "device unauthorized. Please check the confirmation dialog on your device.";
+            if (error_out) {
+                *error_out = "device unauthorized.\n";
+                char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
+                *error_out += "This adbd's $ADB_VENDOR_KEYS is ";
+                *error_out += ADB_VENDOR_KEYS ? ADB_VENDOR_KEYS : "not set";
+                *error_out += "; try 'adb kill-server' if that seems wrong.\n";
+                *error_out += "Otherwise check for a confirmation dialog on your device.";
+            }
             result = NULL;
         }
 
-         /* offline devices are ignored -- they are either being born or dying */
+        /* offline devices are ignored -- they are either being born or dying */
         if (result && result->connection_state == CS_OFFLINE) {
-            if (error_out)
-                *error_out = "device offline";
+            if (error_out) *error_out = "device offline";
             result = NULL;
         }
-         /* check for required connection state */
+
+        /* check for required connection state */
         if (result && state != CS_ANY && result->connection_state != state) {
-            if (error_out)
-                *error_out = "invalid device state";
+            if (error_out) *error_out = "invalid device state";
             result = NULL;
         }
     }
 
     if (result) {
         /* found one that we can take */
-        if (error_out)
-            *error_out = NULL;
+        if (error_out) *error_out = "success";
     } else if (state != CS_ANY && (serial || !ambiguous)) {
         adb_sleep_ms(1000);
         goto retry;
@@ -891,103 +839,72 @@
     return result;
 }
 
-#if ADB_HOST
-static const char *statename(atransport *t)
-{
-    switch(t->connection_state){
+const char* atransport::connection_state_name() const {
+    switch (connection_state) {
     case CS_OFFLINE: return "offline";
     case CS_BOOTLOADER: return "bootloader";
     case CS_DEVICE: return "device";
     case CS_HOST: return "host";
     case CS_RECOVERY: return "recovery";
-    case CS_SIDELOAD: return "sideload";
     case CS_NOPERM: return "no permissions";
+    case CS_SIDELOAD: return "sideload";
     case CS_UNAUTHORIZED: return "unauthorized";
     default: return "unknown";
     }
 }
 
-static void add_qual(char **buf, size_t *buf_size,
-                     const char *prefix, const char *qual, int sanitize_qual)
-{
-    size_t len;
-    int prefix_len;
+#if ADB_HOST
 
-    if (!buf || !*buf || !buf_size || !*buf_size || !qual || !*qual)
+static void append_transport_info(std::string* result, const char* key,
+                                  const char* value, bool sanitize) {
+    if (value == nullptr || *value == '\0') {
         return;
-
-    len = snprintf(*buf, *buf_size, "%s%n%s", prefix, &prefix_len, qual);
-
-    if (sanitize_qual) {
-        char *cp;
-        for (cp = *buf + prefix_len; cp < *buf + len; cp++) {
-            if (qual_char_is_invalid(*cp))
-                *cp = '_';
-        }
     }
 
-    *buf_size -= len;
-    *buf += len;
+    *result += ' ';
+    *result += key;
+
+    for (const char* p = value; *p; ++p) {
+        result->push_back((!sanitize || isalnum(*p)) ? *p : '_');
+    }
 }
 
-static size_t format_transport(atransport *t, char *buf, size_t bufsize,
-                               int long_listing)
-{
+static void append_transport(atransport* t, std::string* result, bool long_listing) {
     const char* serial = t->serial;
-    if (!serial || !serial[0])
-        serial = "????????????";
+    if (!serial || !serial[0]) {
+        serial = "(no serial number)";
+    }
 
     if (!long_listing) {
-        return snprintf(buf, bufsize, "%s\t%s\n", serial, statename(t));
+        *result += serial;
+        *result += '\t';
+        *result += t->connection_state_name();
     } else {
-        size_t len, remaining = bufsize;
+        android::base::StringAppendF(result, "%-22s %s", serial, t->connection_state_name());
 
-        len = snprintf(buf, remaining, "%-22s %s", serial, statename(t));
-        remaining -= len;
-        buf += len;
-
-        add_qual(&buf, &remaining, " ", t->devpath, 0);
-        add_qual(&buf, &remaining, " product:", t->product, 0);
-        add_qual(&buf, &remaining, " model:", t->model, 1);
-        add_qual(&buf, &remaining, " device:", t->device, 0);
-
-        len = snprintf(buf, remaining, "\n");
-        remaining -= len;
-
-        return bufsize - remaining;
+        append_transport_info(result, "", t->devpath, false);
+        append_transport_info(result, "product:", t->product, false);
+        append_transport_info(result, "model:", t->model, true);
+        append_transport_info(result, "device:", t->device, false);
     }
+    *result += '\n';
 }
 
-int list_transports(char *buf, size_t  bufsize, int long_listing)
-{
-    char*       p   = buf;
-    char*       end = buf + bufsize;
-    int         len;
-    atransport *t;
-
-        /* XXX OVERRUN PROBLEMS XXX */
+std::string list_transports(bool long_listing) {
+    std::string result;
     adb_mutex_lock(&transport_lock);
-    for(t = transport_list.next; t != &transport_list; t = t->next) {
-        len = format_transport(t, p, end - p, long_listing);
-        if (p + len >= end) {
-            /* discard last line if buffer is too short */
-            break;
-        }
-        p += len;
+    for (atransport* t = transport_list.next; t != &transport_list; t = t->next) {
+        append_transport(t, &result, long_listing);
     }
-    p[0] = 0;
     adb_mutex_unlock(&transport_lock);
-    return p - buf;
+    return result;
 }
 
-
 /* hack for osx */
 void close_usb_devices()
 {
-    atransport *t;
-
     adb_mutex_lock(&transport_lock);
-    for(t = transport_list.next; t != &transport_list; t = t->next) {
+    for (atransport* t = transport_list.next; t != &transport_list; t = t->next) {
         if ( !t->kicked ) {
             t->kicked = 1;
             t->kick(t);
@@ -999,7 +916,11 @@
 
 int register_socket_transport(int s, const char *serial, int port, int local)
 {
-    atransport *t = calloc(1, sizeof(atransport));
+    atransport *t = reinterpret_cast<atransport*>(calloc(1, sizeof(atransport)));
+    if (t == nullptr) {
+        return -1;
+    }
+
     atransport *n;
     char buff[32];
 
@@ -1098,7 +1019,8 @@
 
 void register_usb_transport(usb_handle *usb, const char *serial, const char *devpath, unsigned writeable)
 {
-    atransport *t = calloc(1, sizeof(atransport));
+    atransport *t = reinterpret_cast<atransport*>(calloc(1, sizeof(atransport)));
+    if (t == nullptr) fatal("cannot allocate USB atransport");
     D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb,
       serial ? serial : "");
     init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM));
@@ -1137,70 +1059,6 @@
 #undef TRACE_TAG
 #define TRACE_TAG  TRACE_RWX
 
-int readx(int fd, void *ptr, size_t len)
-{
-    char *p = ptr;
-    int r;
-#if ADB_TRACE
-    size_t len0 = len;
-#endif
-    D("readx: fd=%d wanted=%zu\n", fd, len);
-    while(len > 0) {
-        r = adb_read(fd, p, len);
-        if(r > 0) {
-            len -= r;
-            p += r;
-        } else {
-            if (r < 0) {
-                D("readx: fd=%d error %d: %s\n", fd, errno, strerror(errno));
-                if (errno == EINTR)
-                    continue;
-            } else {
-                D("readx: fd=%d disconnected\n", fd);
-            }
-            return -1;
-        }
-    }
-
-#if ADB_TRACE
-    D("readx: fd=%d wanted=%zu got=%zu\n", fd, len0, len0 - len);
-    dump_hex( ptr, len0 );
-#endif
-    return 0;
-}
-
-int writex(int fd, const void *ptr, size_t len)
-{
-    char *p = (char*) ptr;
-    int r;
-
-#if ADB_TRACE
-    D("writex: fd=%d len=%d: ", fd, (int)len);
-    dump_hex( ptr, len );
-#endif
-    while(len > 0) {
-        r = adb_write(fd, p, len);
-        if(r > 0) {
-            len -= r;
-            p += r;
-        } else {
-            if (r < 0) {
-                D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno));
-                if (errno == EINTR)
-                    continue;
-                if (errno == EAGAIN) {
-                    adb_sleep_ms(1); // just yield some cpu time
-                    continue;
-                }
-            } else {
-                D("writex: fd=%d disconnected\n", fd);
-            }
-            return -1;
-        }
-    }
-    return 0;
-}
-
 int check_header(apacket *p)
 {
     if(p->msg.magic != (p->msg.command ^ 0xffffffff)) {
diff --git a/adb/transport.h b/adb/transport.h
index 992e052..5b6fdac 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -17,10 +17,54 @@
 #ifndef __TRANSPORT_H
 #define __TRANSPORT_H
 
-/* convenience wrappers around read/write that will retry on
-** EINTR and/or short read/write.  Returns 0 on success, -1
-** on error or EOF.
+#include <sys/types.h>
+
+#include <string>
+
+#include "adb.h"
+
+/*
+ * Obtain a transport from the available transports.
+ * If state is != CS_ANY, only transports in that state are considered.
+ * If serial is non-NULL then only the device with that serial will be chosen.
+ * If no suitable transport is found, error is set.
+ */
+atransport* acquire_one_transport(int state, transport_type ttype,
+                                  const char* serial, std::string* error_out);
+void add_transport_disconnect(atransport* t, adisconnect* dis);
+void remove_transport_disconnect(atransport* t, adisconnect* dis);
+void kick_transport(atransport* t);
+void run_transport_disconnects(atransport* t);
+void update_transports(void);
+
+/* transports are ref-counted
+** get_device_transport does an acquire on your behalf before returning
 */
-int readx(int fd, void *ptr, size_t len);
-int writex(int fd, const void *ptr, size_t len);
+void init_transport_registration(void);
+std::string list_transports(bool long_listing);
+atransport* find_transport(const char* serial);
+
+void register_usb_transport(usb_handle* h, const char* serial,
+                            const char* devpath, unsigned writeable);
+
+/* cause new transports to be init'd and added to the list */
+int register_socket_transport(int s, const char* serial, int port, int local);
+
+/* this should only be used for transports with connection_state == CS_NOPERM */
+void unregister_usb_transport(usb_handle* usb);
+
+/* these should only be used for the "adb disconnect" command */
+void unregister_transport(atransport* t);
+void unregister_all_tcp_transports();
+
+int check_header(apacket* p);
+int check_data(apacket* p);
+
+/* for MacOS X cleanup */
+void close_usb_devices();
+
+void send_packet(apacket* p, atransport* t);
+
+asocket* create_device_tracker(void);
+
 #endif   /* __TRANSPORT_H */
diff --git a/adb/transport_local.c b/adb/transport_local.cpp
similarity index 89%
rename from adb/transport_local.c
rename to adb/transport_local.cpp
index 948cc15..b1deffd 100644
--- a/adb/transport_local.c
+++ b/adb/transport_local.cpp
@@ -14,34 +14,25 @@
  * limitations under the License.
  */
 
+#define TRACE_TAG TRACE_TRANSPORT
+
+#include "sysdeps.h"
+#include "transport.h"
+
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <errno.h>
-
-#include "sysdeps.h"
 #include <sys/types.h>
+
+#include <base/stringprintf.h>
+
 #if !ADB_HOST
-#include <cutils/properties.h>
+#include "cutils/properties.h"
 #endif
 
-#define  TRACE_TAG  TRACE_TRANSPORT
 #include "adb.h"
-
-#ifdef HAVE_BIG_ENDIAN
-#define H4(x)	(((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)
-static inline void fix_endians(apacket *p)
-{
-    p->msg.command     = H4(p->msg.command);
-    p->msg.arg0        = H4(p->msg.arg0);
-    p->msg.arg1        = H4(p->msg.arg1);
-    p->msg.data_length = H4(p->msg.data_length);
-    p->msg.data_check  = H4(p->msg.data_check);
-    p->msg.magic       = H4(p->msg.magic);
-}
-#else
-#define fix_endians(p) do {} while (0)
-#endif
+#include "adb_io.h"
 
 #if ADB_HOST
 /* we keep a list of opened transports. The atransport struct knows to which
@@ -57,23 +48,17 @@
 
 static int remote_read(apacket *p, atransport *t)
 {
-    if(readx(t->sfd, &p->msg, sizeof(amessage))){
+    if(!ReadFdExactly(t->sfd, &p->msg, sizeof(amessage))){
         D("remote local: read terminated (message)\n");
         return -1;
     }
 
-    fix_endians(p);
-
-#if 0 && defined HAVE_BIG_ENDIAN
-    D("read remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n",
-      p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic);
-#endif
     if(check_header(p)) {
         D("bad header: terminated (data)\n");
         return -1;
     }
 
-    if(readx(t->sfd, p->data, p->msg.data_length)){
+    if(!ReadFdExactly(t->sfd, p->data, p->msg.data_length)){
         D("remote local: terminated (data)\n");
         return -1;
     }
@@ -90,13 +75,7 @@
 {
     int   length = p->msg.data_length;
 
-    fix_endians(p);
-
-#if 0 && defined HAVE_BIG_ENDIAN
-    D("write remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n",
-      p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic);
-#endif
-    if(writex(t->sfd, &p->msg, sizeof(amessage) + length)) {
+    if(!WriteFdExactly(t->sfd, &p->msg, sizeof(amessage) + length)) {
         D("remote local: write terminated\n");
         return -1;
     }
@@ -111,7 +90,6 @@
 
 int local_connect_arbitrary_ports(int console_port, int adb_port)
 {
-    char buf[64];
     int  fd = -1;
 
 #if ADB_HOST
@@ -128,8 +106,8 @@
         D("client: connected on remote on fd %d\n", fd);
         close_on_exec(fd);
         disable_tcp_nagle(fd);
-        snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, console_port);
-        register_socket_transport(fd, buf, adb_port, 1);
+        std::string serial = android::base::StringPrintf("emulator-%d", console_port);
+        register_socket_transport(fd, serial.c_str(), adb_port, 1);
         return 0;
     }
     return -1;
@@ -167,7 +145,7 @@
         if(serverfd == -1) {
             serverfd = socket_inaddr_any_server(port, SOCK_STREAM);
             if(serverfd < 0) {
-                D("server: cannot bind socket yet\n");
+                D("server: cannot bind socket yet: %s\n", strerror(errno));
                 adb_sleep_ms(1000);
                 continue;
             }
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
new file mode 100644
index 0000000..2b3fe3c
--- /dev/null
+++ b/adb/transport_test.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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 "transport.h"
+
+#include <gtest/gtest.h>
+
+#include "adb.h"
+
+TEST(transport, kick_transport) {
+  atransport t = {};
+  // Mutate some member so we can test that the function is run.
+  t.kick = [](atransport* trans) { trans->fd = 42; };
+  atransport expected = t;
+  expected.fd = 42;
+  expected.kicked = 1;
+  kick_transport(&t);
+  ASSERT_EQ(42, t.fd);
+  ASSERT_EQ(1, t.kicked);
+  ASSERT_EQ(0, memcmp(&expected, &t, sizeof(atransport)));
+}
+
+TEST(transport, kick_transport_already_kicked) {
+  // Ensure that the transport is not modified if the transport has already been
+  // kicked.
+  atransport t = {};
+  t.kicked = 1;
+  t.kick = [](atransport*) { FAIL() << "Kick should not have been called"; };
+  atransport expected = t;
+  kick_transport(&t);
+  ASSERT_EQ(0, memcmp(&expected, &t, sizeof(atransport)));
+}
+
+// Disabled because the function currently segfaults for a zeroed atransport. I
+// want to make sure I understand how this is working at all before I try fixing
+// that.
+TEST(transport, DISABLED_run_transport_disconnects_zeroed_atransport) {
+  atransport t = {};
+  run_transport_disconnects(&t);
+}
diff --git a/adb/transport_usb.c b/adb/transport_usb.cpp
similarity index 68%
rename from adb/transport_usb.c
rename to adb/transport_usb.cpp
index ee6b637..cdabffe 100644
--- a/adb/transport_usb.c
+++ b/adb/transport_usb.cpp
@@ -14,42 +14,17 @@
  * limitations under the License.
  */
 
+#define TRACE_TAG TRACE_TRANSPORT
+
+#include "sysdeps.h"
+#include "transport.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include <sysdeps.h>
-
-#define  TRACE_TAG  TRACE_TRANSPORT
 #include "adb.h"
 
-#if ADB_HOST
-#include "usb_vendors.h"
-#endif
-
-#ifdef HAVE_BIG_ENDIAN
-#define H4(x)	(((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)
-static inline void fix_endians(apacket *p)
-{
-    p->msg.command     = H4(p->msg.command);
-    p->msg.arg0        = H4(p->msg.arg0);
-    p->msg.arg1        = H4(p->msg.arg1);
-    p->msg.data_length = H4(p->msg.data_length);
-    p->msg.data_check  = H4(p->msg.data_check);
-    p->msg.magic       = H4(p->msg.magic);
-}
-unsigned host_to_le32(unsigned n)
-{
-    return H4(n);
-}
-#else
-#define fix_endians(p) do {} while (0)
-unsigned host_to_le32(unsigned n)
-{
-    return n;
-}
-#endif
-
 static int remote_read(apacket *p, atransport *t)
 {
     if(usb_read(t->usb, &p->msg, sizeof(amessage))){
@@ -57,8 +32,6 @@
         return -1;
     }
 
-    fix_endians(p);
-
     if(check_header(p)) {
         D("remote usb: check_header failed\n");
         return -1;
@@ -83,8 +56,6 @@
 {
     unsigned size = p->msg.data_length;
 
-    fix_endians(p);
-
     if(usb_write(t->usb, &p->msg, sizeof(amessage))) {
         D("remote usb: 1 - write terminated\n");
         return -1;
@@ -131,18 +102,6 @@
 #if ADB_HOST
 int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol)
 {
-    unsigned i;
-    for (i = 0; i < vendorIdCount; i++) {
-        if (vid == vendorIds[i]) {
-            if (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS &&
-                    usb_protocol == ADB_PROTOCOL) {
-                return 1;
-            }
-
-            return 0;
-        }
-    }
-
-    return 0;
+    return (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && usb_protocol == ADB_PROTOCOL);
 }
 #endif
diff --git a/adb/usb_libusb.c b/adb/usb_libusb.c
deleted file mode 100644
index 06ff5dc..0000000
--- a/adb/usb_libusb.c
+++ /dev/null
@@ -1,657 +0,0 @@
-/* 
- * Copyright (C) 2009 bsdroid project
- *               Alexey Tarasov <tarasov@dodologics.com>
- *   
- * 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 <sys/endian.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-
-#include <err.h>
-#include <errno.h>
-#include <poll.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <strings.h>
-#include <string.h>
-#include <sysexits.h>
-#include <unistd.h>
-#include <libusb.h>
-#include "sysdeps.h"
-
-#define   TRACE_TAG  TRACE_USB
-#include "adb.h"
-
-static adb_mutex_t usb_lock = ADB_MUTEX_INITIALIZER;
-static libusb_context *ctx = NULL;
-
-struct usb_handle
-{
-    usb_handle            *prev;
-    usb_handle            *next;
-
-    libusb_device         *dev;
-    libusb_device_handle  *devh;
-    int                   interface;
-    uint8_t               dev_bus;
-    uint8_t               dev_addr;
-	
-    int                   zero_mask;
-    unsigned char         end_point_address[2];
-    char                  serial[128];
-    
-    adb_cond_t            notify;
-    adb_mutex_t           lock;
-};
-
-static struct usb_handle handle_list = {
-        .prev = &handle_list,
-        .next = &handle_list,
-};
-
-void
-usb_cleanup()
-{
-	libusb_exit(ctx);
-}
-
-void
-report_bulk_libusb_error(int r)
-{
-    switch (r) {
-    case LIBUSB_ERROR_TIMEOUT:
-        D("Transfer timeout\n");
-        break;
-
-    case LIBUSB_ERROR_PIPE:
-        D("Control request is not supported\n");
-        break;
-
-    case LIBUSB_ERROR_OVERFLOW:
-        D("Device offered more data\n");
-        break;
-
-    case LIBUSB_ERROR_NO_DEVICE :
-        D("Device was disconnected\n");
-        break;
-
-    default:
-        D("Error %d during transfer\n", r);
-        break;
-    };
-}
-
-static int
-usb_bulk_write(usb_handle *uh, const void *data, int len)
-{
-    int r = 0;
-    int transferred = 0;
-
-    r = libusb_bulk_transfer(uh->devh, uh->end_point_address[1], (void *)data, len,
-                             &transferred, 0);
-   
-    if (r != 0) {
-        D("usb_bulk_write(): ");
-        report_bulk_libusb_error(r);
-        return r;
-    }
-   
-    return (transferred);
-}
-
-static int
-usb_bulk_read(usb_handle *uh, void *data, int len)
-{
-    int r = 0;
-    int transferred = 0;
-
-    r = libusb_bulk_transfer(uh->devh, uh->end_point_address[0], data, len,
-                             &transferred, 0);
-
-    if (r != 0) {
-        D("usb_bulk_read(): ");
-        report_bulk_libusb_error(r);
-        return r;
-    }
-   
-    return (transferred);
-}
-
-int
-usb_write(struct usb_handle *uh, const void *_data, int len)
-{
-    unsigned char *data = (unsigned char*) _data;
-    int n;
-    int need_zero = 0;
-
-    if (uh->zero_mask == 1) {
-        if (!(len & uh->zero_mask)) {
-            need_zero = 1;
-        }
-    }
-
-    D("usb_write(): %p:%d -> transport %p\n", _data, len, uh);
-    
-    while (len > 0) {
-        int xfer = (len > 4096) ? 4096 : len;
-
-        n = usb_bulk_write(uh, data, xfer);
-        
-        if (n != xfer) {
-            D("usb_write(): failed for transport %p (%d bytes left)\n", uh, len);
-            return -1;
-        }
-
-        len -= xfer;
-        data += xfer;
-    }
-
-    if (need_zero){
-        n = usb_bulk_write(uh, _data, 0);
-        
-        if (n < 0) {
-            D("usb_write(): failed to finish operation for transport %p\n", uh);
-        }
-        return n;
-    }
-
-    return 0;
-}
-
-int
-usb_read(struct usb_handle *uh, void *_data, int len)
-{
-    unsigned char *data = (unsigned char*) _data;
-    int n;
-
-    D("usb_read(): %p:%d <- transport %p\n", _data, len, uh);
-    
-    while (len > 0) {
-        int xfer = (len > 4096) ? 4096 : len;
-
-        n = usb_bulk_read(uh, data, xfer);
-        
-        if (n != xfer) {
-            if (n > 0) {
-                data += n;
-                len -= n;
-                continue;
-            }
-            
-            D("usb_read(): failed for transport %p (%d bytes left)\n", uh, len);
-            return -1;
-        }
-
-        len -= xfer;
-        data += xfer;
-    }
-
-    return 0;
- }
-
-int
-usb_close(struct usb_handle *h)
-{
-    D("usb_close(): closing transport %p\n", h);
-    adb_mutex_lock(&usb_lock);
-    
-    h->next->prev = h->prev;
-    h->prev->next = h->next;
-    h->prev = NULL;
-    h->next = NULL;
-
-    libusb_release_interface(h->devh, h->interface);
-    libusb_close(h->devh);
-    libusb_unref_device(h->dev);
-    
-    adb_mutex_unlock(&usb_lock);
-
-    free(h);
-
-    return (0);
-}
-
-void usb_kick(struct usb_handle *h)
-{
-    D("usb_cick(): kicking transport %p\n", h);
-    
-    adb_mutex_lock(&h->lock);
-    unregister_usb_transport(h);
-    adb_mutex_unlock(&h->lock);
-    
-    h->next->prev = h->prev;
-    h->prev->next = h->next;
-    h->prev = NULL;
-    h->next = NULL;
-
-    libusb_release_interface(h->devh, h->interface);
-    libusb_close(h->devh);
-    libusb_unref_device(h->dev);
-    free(h);
-}
-
-int
-check_usb_interface(libusb_interface *interface,
-                    libusb_device_descriptor *desc,
-                    struct usb_handle *uh)
-{    
-    int e;
-    
-    if (interface->num_altsetting == 0) {
-        D("check_usb_interface(): No interface settings\n");
-        return -1;
-    }
-    
-    libusb_interface_descriptor *idesc = &interface->altsetting[0];
-    
-    if (idesc->bNumEndpoints != 2) {
-        D("check_usb_interface(): Interface have not 2 endpoints, ignoring\n");
-        return -1;
-    }
-
-    for (e = 0; e < idesc->bNumEndpoints; e++) {
-        libusb_endpoint_descriptor *edesc = &idesc->endpoint[e];
-        
-        if (edesc->bmAttributes != LIBUSB_TRANSFER_TYPE_BULK) {
-            D("check_usb_interface(): Endpoint (%u) is not bulk (%u), ignoring\n",
-                    edesc->bmAttributes, LIBUSB_TRANSFER_TYPE_BULK);
-            return -1;
-        }
-        
-        if (edesc->bEndpointAddress & LIBUSB_ENDPOINT_IN)
-            uh->end_point_address[0] = edesc->bEndpointAddress;
-        else
-            uh->end_point_address[1] = edesc->bEndpointAddress;
-        
-            /* aproto 01 needs 0 termination */
-        if (idesc->bInterfaceProtocol == 0x01) {
-            uh->zero_mask = edesc->wMaxPacketSize - 1;
-            D("check_usb_interface(): Forced Android interface protocol v.1\n");
-        }
-    }
-
-    D("check_usb_interface(): Device: %04x:%04x "
-      "iclass: %x, isclass: %x, iproto: %x ep: %x/%x-> ",
-        desc->idVendor, desc->idProduct, idesc->bInterfaceClass,
-	idesc->bInterfaceSubClass, idesc->bInterfaceProtocol,
-	uh->end_point_address[0], uh->end_point_address[1]);
-    
-    if (!is_adb_interface(desc->idVendor, desc->idProduct,
-            idesc->bInterfaceClass, idesc->bInterfaceSubClass,
-            idesc->bInterfaceProtocol))
-    {
-        D("not matches\n");
-        return -1;
-    }
-
-    D("matches\n");
-    return 1;
-}
-
-int
-check_usb_interfaces(libusb_config_descriptor *config,
-                     libusb_device_descriptor *desc, struct usb_handle *uh)
-{  
-    int i;
-    
-    for (i = 0; i < config->bNumInterfaces; ++i) {
-        if (check_usb_interface(&config->interface[i], desc, uh) != -1) {
-            /* found some interface and saved information about it */
-            D("check_usb_interfaces(): Interface %d of %04x:%04x "
-              "matches Android device\n", i, desc->idVendor,
-	      desc->idProduct);
-            
-            return  i;
-        }
-    }
-    
-    return -1;
-}
-
-int
-register_device(struct usb_handle *uh, const char *serial)
-{
-    D("register_device(): Registering %p [%s] as USB transport\n",
-       uh, serial);
-
-    struct usb_handle *usb= NULL;
-
-    usb = calloc(1, sizeof(struct usb_handle));
-    memcpy(usb, uh, sizeof(struct usb_handle));
-    strcpy(usb->serial, uh->serial);
-
-    adb_cond_init(&usb->notify, 0);
-    adb_mutex_init(&usb->lock, 0);
-
-    adb_mutex_lock(&usb_lock);
-    
-    usb->next = &handle_list;
-    usb->prev = handle_list.prev;
-    usb->prev->next = usb;
-    usb->next->prev = usb;
-
-    adb_mutex_unlock(&usb_lock);
-
-    register_usb_transport(usb, serial, NULL, 1); 
-
-    return (1);
-}
-
-int
-already_registered(usb_handle *uh)
-{
-    struct usb_handle *usb= NULL;
-    int exists = 0;
-    
-    adb_mutex_lock(&usb_lock);
-
-    for (usb = handle_list.next; usb != &handle_list; usb = usb->next) {
-        if ((usb->dev_bus == uh->dev_bus) &&
-            (usb->dev_addr == uh->dev_addr))
-        {
-            exists = 1;
-            break;
-        }
-    }
-
-    adb_mutex_unlock(&usb_lock);
-
-    return exists;
-}
-
-void
-check_device(libusb_device *dev) 
-{
-    struct usb_handle uh;
-    int i = 0;
-    int found = -1;
-    char serial[256] = {0};
-
-    libusb_device_descriptor desc;
-    libusb_config_descriptor *config = NULL;
-    
-    int r = libusb_get_device_descriptor(dev, &desc);
-
-    if (r != LIBUSB_SUCCESS) {
-        D("check_device(): Failed to get device descriptor\n");
-        return;
-    }
-    
-    if ((desc.idVendor == 0) && (desc.idProduct == 0))
-        return;
-    
-    D("check_device(): Probing usb device %04x:%04x\n",
-        desc.idVendor, desc.idProduct);
-    
-    if (!is_adb_interface (desc.idVendor, desc.idProduct,
-                           ADB_CLASS, ADB_SUBCLASS, ADB_PROTOCOL))
-    {
-        D("check_device(): Ignored due unknown vendor id\n");
-        return;
-    }
-    
-    uh.dev_bus = libusb_get_bus_number(dev);
-    uh.dev_addr = libusb_get_device_address(dev);
-    
-    if (already_registered(&uh)) {
-        D("check_device(): Device (bus: %d, address: %d) "
-          "is already registered\n", uh.dev_bus, uh.dev_addr);
-        return;
-    }
-    
-    D("check_device(): Device bus: %d, address: %d\n",
-        uh.dev_bus, uh.dev_addr);
-
-    r = libusb_get_active_config_descriptor(dev, &config);
-    
-    if (r != 0) {
-        if (r == LIBUSB_ERROR_NOT_FOUND) {
-            D("check_device(): Device %4x:%4x is unconfigured\n", 
-                desc.idVendor, desc.idProduct);
-            return;
-        }
-        
-        D("check_device(): Failed to get configuration for %4x:%4x\n",
-            desc.idVendor, desc.idProduct);
-        return;
-    }
-    
-    if (config == NULL) {
-        D("check_device(): Sanity check failed after "
-          "getting active config\n");
-        return;
-    }
-    
-    if (config->interface != NULL) {
-        found = check_usb_interfaces(config, &desc, &uh);
-    }
-    
-    /* not needed anymore */
-    libusb_free_config_descriptor(config);
-    
-    r = libusb_open(dev, &uh.devh);
-    uh.dev = dev;
-
-    if (r != 0) {
-        switch (r) {
-            case LIBUSB_ERROR_NO_MEM:
-                D("check_device(): Memory allocation problem\n");
-                break;
-                
-            case LIBUSB_ERROR_ACCESS:
-                D("check_device(): Permissions problem, "
-                  "current user priveleges are messed up?\n");
-                break;
-                
-            case LIBUSB_ERROR_NO_DEVICE:
-                D("check_device(): Device disconected, bad cable?\n");
-                break;
-            
-            default:
-                D("check_device(): libusb triggered error %d\n", r);
-        }
-        // skip rest
-        found = -1;
-    }
-    
-    if (found >= 0) {
-        D("check_device(): Device matches Android interface\n");
-        // read the device's serial number
-        memset(serial, 0, sizeof(serial));
-        uh.interface = found;
-        
-        r = libusb_claim_interface(uh.devh, uh.interface);
-        
-        if (r < 0) {
-            D("check_device(): Failed to claim interface %d\n",
-                uh.interface);
-
-            goto fail;
-        }
-
-        if (desc.iSerialNumber) {
-            // reading serial
-            uint16_t    buffer[128] = {0};
-            uint16_t    languages[128] = {0};
-            int languageCount = 0;
-
-            memset(languages, 0, sizeof(languages));
-            r = libusb_control_transfer(uh.devh, 
-                LIBUSB_ENDPOINT_IN |  LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE,
-                LIBUSB_REQUEST_GET_DESCRIPTOR, LIBUSB_DT_STRING << 8,
-		0, (uint8_t *)languages, sizeof(languages), 0);
-
-            if (r <= 0) {
-                D("check_device(): Failed to get languages count\n");
-                goto fail;
-            } 
-            
-            languageCount = (r - 2) / 2;
-            
-            for (i = 1; i <= languageCount; ++i) {
-                memset(buffer, 0, sizeof(buffer));
-
-                r = libusb_control_transfer(uh.devh, 
-                    LIBUSB_ENDPOINT_IN |  LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE,
-                    LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | desc.iSerialNumber,
-		    languages[i], (uint8_t *)buffer, sizeof(buffer), 0);
-            
-                if (r > 0) { /* converting serial */
-                    int j = 0;
-                    r /= 2;
-                
-                    for (j = 1; j < r; ++j)
-                        serial[j - 1] = buffer[j];
-                
-                    serial[j - 1] = '\0';
-                    break; /* languagesCount cycle */
-                }
-            }
-            
-            if (register_device(&uh, serial) == 0) {
-                D("check_device(): Failed to register device\n");
-                goto fail_interface;
-            }
-            
-            libusb_ref_device(dev);
-        }
-    }
-    
-    return;
-
-fail_interface:
-    libusb_release_interface(uh.devh, uh.interface);
-
-fail:
-    libusb_close(uh.devh);
-    uh.devh = NULL;
-}
-
-int
-check_device_connected(struct usb_handle *uh)
-{
-    int r = libusb_kernel_driver_active(uh->devh, uh->interface);
-    
-    if (r == LIBUSB_ERROR_NO_DEVICE)
-        return 0;
-    
-    if (r < 0)
-        return -1;
-    
-    return 1;
-}
-
-void
-kick_disconnected()
-{
-    struct usb_handle *usb= NULL;
-    
-    adb_mutex_lock(&usb_lock);
-
-    for (usb = handle_list.next; usb != &handle_list; usb = usb->next) {
-        
-        if (check_device_connected(usb) == 0) {
-            D("kick_disconnected(): Transport %p is not online anymore\n",
-                usb);
-
-            usb_kick(usb);
-        }
-    }
-    
-    adb_mutex_unlock(&usb_lock);
-}
-
-void
-scan_usb_devices()
-{
-    D("scan_usb_devices(): started\n");
-    
-    libusb_device **devs= NULL;
-    libusb_device *dev= NULL;
-    ssize_t cnt = libusb_get_device_list(ctx, &devs);
-
-    if (cnt < 0) {
-        D("scan_usb_devices(): Failed to get device list (error: %d)\n",
-            cnt);
-
-        return;
-    }
-    
-    int i = 0;
-
-    while ((dev = devs[i++]) != NULL) {
-        check_device(dev);
-    }
-
-    libusb_free_device_list(devs, 1);
-}
-
-void *
-device_poll_thread(void* unused)
-{
-    D("device_poll_thread(): Created USB scan thread\n");
-    
-    for (;;) {
-        sleep(5);
-        kick_disconnected();
-        scan_usb_devices();
-    }
-
-    /* never reaching this point */
-    return (NULL);
-}
-
-static void
-sigalrm_handler(int signo)
-{
-    /* nothing */
-}
-
-void
-usb_init()
-{
-    D("usb_init(): started\n");
-    adb_thread_t        tid;
-    struct sigaction actions;
-
-    int r = libusb_init(&ctx);
-
-    if (r != LIBUSB_SUCCESS) {
-        err(EX_IOERR, "Failed to init libusb\n");
-    }
-
-    memset(&actions, 0, sizeof(actions));
-    
-    sigemptyset(&actions.sa_mask);
-    
-    actions.sa_flags = 0;
-    actions.sa_handler = sigalrm_handler;
-    
-    sigaction(SIGALRM, &actions, NULL);
-
-	/* initial device scan */
-	scan_usb_devices();
-	
-	/* starting USB event polling thread */
-    if (adb_thread_create(&tid, device_poll_thread, NULL)) {
-            err(EX_IOERR, "cannot create USB scan thread\n");
-    }
-    
-    D("usb_init(): finished\n");
-}
-
diff --git a/adb/usb_linux.c b/adb/usb_linux.cpp
similarity index 81%
rename from adb/usb_linux.c
rename to adb/usb_linux.cpp
index f16bdd0..71baaee 100644
--- a/adb/usb_linux.c
+++ b/adb/usb_linux.cpp
@@ -14,33 +14,31 @@
  * limitations under the License.
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <ctype.h>
-
-#include <linux/usbdevice_fs.h>
-#include <linux/version.h>
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
-#include <linux/usb/ch9.h>
-#else
-#include <linux/usb_ch9.h>
-#endif
-#include <asm/byteorder.h>
+#define TRACE_TAG TRACE_USB
 
 #include "sysdeps.h"
 
-#define   TRACE_TAG  TRACE_USB
-#include "adb.h"
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/usbdevice_fs.h>
+#include <linux/version.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <linux/usb/ch9.h>
 
+#include <base/file.h>
+#include <base/stringprintf.h>
+#include <base/strings.h>
+
+#include "adb.h"
+#include "transport.h"
 
 /* usb scan debugging is waaaay too verbose */
 #define DBGX(x...)
@@ -116,10 +114,6 @@
 
 }
 
-static void register_device(const char *dev_name, const char *devpath,
-                            unsigned char ep_in, unsigned char ep_out,
-                            int ifc, int serial_index, unsigned zero_mask);
-
 static inline int badname(const char *name)
 {
     while(*name) {
@@ -237,8 +231,20 @@
                             // looks like ADB...
                         ep1 = (struct usb_endpoint_descriptor *)bufptr;
                         bufptr += USB_DT_ENDPOINT_SIZE;
+                            // For USB 3.0 SuperSpeed devices, skip potential
+                            // USB 3.0 SuperSpeed Endpoint Companion descriptor
+                        if (bufptr+2 <= devdesc + desclength &&
+                            bufptr[0] == USB_DT_SS_EP_COMP_SIZE &&
+                            bufptr[1] == USB_DT_SS_ENDPOINT_COMP) {
+                            bufptr += USB_DT_SS_EP_COMP_SIZE;
+                        }
                         ep2 = (struct usb_endpoint_descriptor *)bufptr;
                         bufptr += USB_DT_ENDPOINT_SIZE;
+                        if (bufptr+2 <= devdesc + desclength &&
+                            bufptr[0] == USB_DT_SS_EP_COMP_SIZE &&
+                            bufptr[1] == USB_DT_SS_ENDPOINT_COMP) {
+                            bufptr += USB_DT_SS_EP_COMP_SIZE;
+                        }
 
                         if (bufptr > devdesc + desclength ||
                             ep1->bLength != USB_DT_ENDPOINT_SIZE ||
@@ -367,6 +373,7 @@
     struct usbdevfs_urb *out = NULL;
     int res;
 
+    D("++ usb_bulk_read ++\n");
     memset(urb, 0, sizeof(*urb));
     urb->type = USBDEVFS_URB_TYPE_BULK;
     urb->endpoint = h->ep_in;
@@ -429,6 +436,7 @@
     }
 fail:
     adb_mutex_unlock(&h->lock);
+    D("-- usb_bulk_read --\n");
     return res;
 }
 
@@ -439,6 +447,7 @@
     int n;
     int need_zero = 0;
 
+    D("++ usb_write ++\n");
     if(h->zero_mask) {
             /* if we need 0-markers and our transfer
             ** is an even multiple of the packet size,
@@ -468,6 +477,7 @@
         return n;
     }
 
+    D("-- usb_write --\n");
     return 0;
 }
 
@@ -542,7 +552,7 @@
 
 int usb_close(usb_handle *h)
 {
-    D("[ usb close ... ]\n");
+    D("++ usb close ++\n");
     adb_mutex_lock(&usb_lock);
     h->next->prev = h->prev;
     h->prev->next = h->next;
@@ -550,41 +560,36 @@
     h->next = 0;
 
     adb_close(h->desc);
-    D("[ usb closed %p (fd = %d) ]\n", h, h->desc);
+    D("-- usb closed %p (fd = %d) --\n", h, h->desc);
     adb_mutex_unlock(&usb_lock);
 
     free(h);
     return 0;
 }
 
-static void register_device(const char *dev_name, const char *devpath,
+static void register_device(const char* dev_name, const char* dev_path,
                             unsigned char ep_in, unsigned char ep_out,
-                            int interface, int serial_index, unsigned zero_mask)
-{
-    usb_handle* usb = 0;
-    int n = 0;
-    char serial[256];
-
-        /* Since Linux will not reassign the device ID (and dev_name)
-        ** as long as the device is open, we can add to the list here
-        ** once we open it and remove from the list when we're finally
-        ** closed and everything will work out fine.
-        **
-        ** If we have a usb_handle on the list 'o handles with a matching
-        ** name, we have no further work to do.
-        */
+                            int interface, int serial_index,
+                            unsigned zero_mask) {
+    // Since Linux will not reassign the device ID (and dev_name) as long as the
+    // device is open, we can add to the list here once we open it and remove
+    // from the list when we're finally closed and everything will work out
+    // fine.
+    //
+    // If we have a usb_handle on the list 'o handles with a matching name, we
+    // have no further work to do.
     adb_mutex_lock(&usb_lock);
-    for(usb = handle_list.next; usb != &handle_list; usb = usb->next){
-        if(!strcmp(usb->fname, dev_name)) {
+    for (usb_handle* usb = handle_list.next; usb != &handle_list; usb = usb->next) {
+        if (!strcmp(usb->fname, dev_name)) {
             adb_mutex_unlock(&usb_lock);
             return;
         }
     }
     adb_mutex_unlock(&usb_lock);
 
-    D("[ usb located new device %s (%d/%d/%d) ]\n",
-        dev_name, ep_in, ep_out, interface);
-    usb = calloc(1, sizeof(usb_handle));
+    D("[ usb located new device %s (%d/%d/%d) ]\n", dev_name, ep_in, ep_out, interface);
+    usb_handle* usb = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
+    if (usb == nullptr) fatal("couldn't allocate usb_handle");
     strcpy(usb->fname, dev_name);
     usb->ep_in = ep_in;
     usb->ep_out = ep_out;
@@ -593,75 +598,50 @@
 
     adb_cond_init(&usb->notify, 0);
     adb_mutex_init(&usb->lock, 0);
-    /* initialize mark to 1 so we don't get garbage collected after the device scan */
+    // Initialize mark to 1 so we don't get garbage collected after the device
+    // scan.
     usb->mark = 1;
     usb->reaper_thread = 0;
 
     usb->desc = unix_open(usb->fname, O_RDWR | O_CLOEXEC);
-    if(usb->desc < 0) {
-        /* if we fail, see if have read-only access */
+    if (usb->desc == -1) {
+        // Opening RW failed, so see if we have RO access.
         usb->desc = unix_open(usb->fname, O_RDONLY | O_CLOEXEC);
-        if(usb->desc < 0) goto fail;
+        if (usb->desc == -1) {
+            D("[ usb open %s failed: %s]\n", usb->fname, strerror(errno));
+            free(usb);
+            return;
+        }
         usb->writeable = 0;
-        D("[ usb open read-only %s fd = %d]\n", usb->fname, usb->desc);
-    } else {
-        D("[ usb open %s fd = %d]\n", usb->fname, usb->desc);
-        n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface);
-        if(n != 0) goto fail;
     }
 
-        /* read the device's serial number */
-    serial[0] = 0;
-    memset(serial, 0, sizeof(serial));
-    if (serial_index) {
-        struct usbdevfs_ctrltransfer  ctrl;
-        __u16 buffer[128];
-        __u16 languages[128];
-        int i, result;
-        int languageCount = 0;
+    D("[ usb opened %s%s, fd=%d]\n", usb->fname,
+      (usb->writeable ? "" : " (read-only)"), usb->desc);
 
-        memset(languages, 0, sizeof(languages));
-        memset(&ctrl, 0, sizeof(ctrl));
-
-            // read list of supported languages
-        ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
-        ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
-        ctrl.wValue = (USB_DT_STRING << 8) | 0;
-        ctrl.wIndex = 0;
-        ctrl.wLength = sizeof(languages);
-        ctrl.data = languages;
-        ctrl.timeout = 1000;
-
-        result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
-        if (result > 0)
-            languageCount = (result - 2) / 2;
-
-        for (i = 1; i <= languageCount; i++) {
-            memset(buffer, 0, sizeof(buffer));
-            memset(&ctrl, 0, sizeof(ctrl));
-
-            ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
-            ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
-            ctrl.wValue = (USB_DT_STRING << 8) | serial_index;
-            ctrl.wIndex = __le16_to_cpu(languages[i]);
-            ctrl.wLength = sizeof(buffer);
-            ctrl.data = buffer;
-            ctrl.timeout = 1000;
-
-            result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
-            if (result > 0) {
-                int i;
-                // skip first word, and copy the rest to the serial string, changing shorts to bytes.
-                result /= 2;
-                for (i = 1; i < result; i++)
-                    serial[i - 1] = __le16_to_cpu(buffer[i]);
-                serial[i - 1] = 0;
-                break;
-            }
+    if (usb->writeable) {
+        if (ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface) != 0) {
+            D("[ usb ioctl(%d, USBDEVFS_CLAIMINTERFACE) failed: %s]\n",
+              usb->desc, strerror(errno));
+            adb_close(usb->desc);
+            free(usb);
+            return;
         }
     }
 
-        /* add to the end of the active handles */
+    // Read the device's serial number.
+    std::string serial_path = android::base::StringPrintf(
+        "/sys/bus/usb/devices/%s/serial", dev_path + 4);
+    std::string serial;
+    if (!android::base::ReadFileToString(serial_path, &serial)) {
+        D("[ usb read %s failed: %s ]\n", serial_path.c_str(), strerror(errno));
+        // We don't actually want to treat an unknown serial as an error because
+        // devices aren't able to communicate a serial number in early bringup.
+        // http://b/20883914
+        serial = "";
+    }
+    serial = android::base::Trim(serial);
+
+    // Add to the end of the active handles.
     adb_mutex_lock(&usb_lock);
     usb->next = &handle_list;
     usb->prev = handle_list.prev;
@@ -669,32 +649,21 @@
     usb->next->prev = usb;
     adb_mutex_unlock(&usb_lock);
 
-    register_usb_transport(usb, serial, devpath, usb->writeable);
-    return;
-
-fail:
-    D("[ usb open %s error=%d, err_str = %s]\n",
-        usb->fname,  errno, strerror(errno));
-    if(usb->desc >= 0) {
-        adb_close(usb->desc);
-    }
-    free(usb);
+    register_usb_transport(usb, serial.c_str(), dev_path, usb->writeable);
 }
 
-void* device_poll_thread(void* unused)
-{
+static void* device_poll_thread(void* unused) {
     D("Created device thread\n");
-    for(;;) {
-            /* XXX use inotify */
+    while (true) {
+        // TODO: Use inotify.
         find_usb_device("/dev/bus/usb", register_device);
         kick_disconnected_devices();
         sleep(1);
     }
-    return NULL;
+    return nullptr;
 }
 
-static void sigalrm_handler(int signo)
-{
+static void sigalrm_handler(int signo) {
     // don't need to do anything here
 }
 
diff --git a/adb/usb_linux_client.c b/adb/usb_linux_client.cpp
similarity index 65%
rename from adb/usb_linux_client.c
rename to adb/usb_linux_client.cpp
index 8426e0e..18289e2 100644
--- a/adb/usb_linux_client.c
+++ b/adb/usb_linux_client.cpp
@@ -14,25 +14,28 @@
  * limitations under the License.
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-
-#include <linux/usb/ch9.h>
-#include <linux/usb/functionfs.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <errno.h>
+#define TRACE_TAG TRACE_USB
 
 #include "sysdeps.h"
 
-#define   TRACE_TAG  TRACE_USB
+#include <cutils/properties.h>
+#include <dirent.h>
+#include <errno.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/functionfs.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
 #include "adb.h"
+#include "transport.h"
 
 #define MAX_PACKET_SIZE_FS	64
 #define MAX_PACKET_SIZE_HS	512
+#define MAX_PACKET_SIZE_SS	1024
 
 #define cpu_to_le16(x)  htole16(x)
 #define cpu_to_le32(x)  htole32(x)
@@ -55,71 +58,81 @@
     int bulk_in;  /* "in" from the host's perspective => sink for adbd */
 };
 
-static const struct {
-    struct usb_functionfs_descs_head header;
-    struct {
-        struct usb_interface_descriptor intf;
-        struct usb_endpoint_descriptor_no_audio source;
-        struct usb_endpoint_descriptor_no_audio sink;
-    } __attribute__((packed)) fs_descs, hs_descs;
-} __attribute__((packed)) descriptors = {
-    .header = {
-        .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC),
-        .length = cpu_to_le32(sizeof(descriptors)),
-        .fs_count = 3,
-        .hs_count = 3,
+struct func_desc {
+    struct usb_interface_descriptor intf;
+    struct usb_endpoint_descriptor_no_audio source;
+    struct usb_endpoint_descriptor_no_audio sink;
+} __attribute__((packed));
+
+struct desc_v1 {
+    struct usb_functionfs_descs_head_v1 {
+        __le32 magic;
+        __le32 length;
+        __le32 fs_count;
+        __le32 hs_count;
+    } __attribute__((packed)) header;
+    struct func_desc fs_descs, hs_descs;
+} __attribute__((packed));
+
+struct desc_v2 {
+    struct usb_functionfs_descs_head_v2 header;
+    // The rest of the structure depends on the flags in the header.
+    __le32 fs_count;
+    __le32 hs_count;
+    struct func_desc fs_descs, hs_descs;
+} __attribute__((packed));
+
+struct func_desc fs_descriptors = {
+    .intf = {
+        .bLength = sizeof(fs_descriptors.intf),
+        .bDescriptorType = USB_DT_INTERFACE,
+        .bInterfaceNumber = 0,
+        .bNumEndpoints = 2,
+        .bInterfaceClass = ADB_CLASS,
+        .bInterfaceSubClass = ADB_SUBCLASS,
+        .bInterfaceProtocol = ADB_PROTOCOL,
+        .iInterface = 1, /* first string from the provided table */
     },
-    .fs_descs = {
-        .intf = {
-            .bLength = sizeof(descriptors.fs_descs.intf),
-            .bDescriptorType = USB_DT_INTERFACE,
-            .bInterfaceNumber = 0,
-            .bNumEndpoints = 2,
-            .bInterfaceClass = ADB_CLASS,
-            .bInterfaceSubClass = ADB_SUBCLASS,
-            .bInterfaceProtocol = ADB_PROTOCOL,
-            .iInterface = 1, /* first string from the provided table */
-        },
-        .source = {
-            .bLength = sizeof(descriptors.fs_descs.source),
-            .bDescriptorType = USB_DT_ENDPOINT,
-            .bEndpointAddress = 1 | USB_DIR_OUT,
-            .bmAttributes = USB_ENDPOINT_XFER_BULK,
-            .wMaxPacketSize = MAX_PACKET_SIZE_FS,
-        },
-        .sink = {
-            .bLength = sizeof(descriptors.fs_descs.sink),
-            .bDescriptorType = USB_DT_ENDPOINT,
-            .bEndpointAddress = 2 | USB_DIR_IN,
-            .bmAttributes = USB_ENDPOINT_XFER_BULK,
-            .wMaxPacketSize = MAX_PACKET_SIZE_FS,
-        },
+    .source = {
+        .bLength = sizeof(fs_descriptors.source),
+        .bDescriptorType = USB_DT_ENDPOINT,
+        .bEndpointAddress = 1 | USB_DIR_OUT,
+        .bmAttributes = USB_ENDPOINT_XFER_BULK,
+        .wMaxPacketSize = MAX_PACKET_SIZE_FS,
     },
-    .hs_descs = {
-        .intf = {
-            .bLength = sizeof(descriptors.hs_descs.intf),
-            .bDescriptorType = USB_DT_INTERFACE,
-            .bInterfaceNumber = 0,
-            .bNumEndpoints = 2,
-            .bInterfaceClass = ADB_CLASS,
-            .bInterfaceSubClass = ADB_SUBCLASS,
-            .bInterfaceProtocol = ADB_PROTOCOL,
-            .iInterface = 1, /* first string from the provided table */
-        },
-        .source = {
-            .bLength = sizeof(descriptors.hs_descs.source),
-            .bDescriptorType = USB_DT_ENDPOINT,
-            .bEndpointAddress = 1 | USB_DIR_OUT,
-            .bmAttributes = USB_ENDPOINT_XFER_BULK,
-            .wMaxPacketSize = MAX_PACKET_SIZE_HS,
-        },
-        .sink = {
-            .bLength = sizeof(descriptors.hs_descs.sink),
-            .bDescriptorType = USB_DT_ENDPOINT,
-            .bEndpointAddress = 2 | USB_DIR_IN,
-            .bmAttributes = USB_ENDPOINT_XFER_BULK,
-            .wMaxPacketSize = MAX_PACKET_SIZE_HS,
-        },
+    .sink = {
+        .bLength = sizeof(fs_descriptors.sink),
+        .bDescriptorType = USB_DT_ENDPOINT,
+        .bEndpointAddress = 2 | USB_DIR_IN,
+        .bmAttributes = USB_ENDPOINT_XFER_BULK,
+        .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+    },
+};
+
+struct func_desc hs_descriptors = {
+    .intf = {
+        .bLength = sizeof(hs_descriptors.intf),
+        .bDescriptorType = USB_DT_INTERFACE,
+        .bInterfaceNumber = 0,
+        .bNumEndpoints = 2,
+        .bInterfaceClass = ADB_CLASS,
+        .bInterfaceSubClass = ADB_SUBCLASS,
+        .bInterfaceProtocol = ADB_PROTOCOL,
+        .iInterface = 1, /* first string from the provided table */
+    },
+    .source = {
+        .bLength = sizeof(hs_descriptors.source),
+        .bDescriptorType = USB_DT_ENDPOINT,
+        .bEndpointAddress = 1 | USB_DIR_OUT,
+        .bmAttributes = USB_ENDPOINT_XFER_BULK,
+        .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+    },
+    .sink = {
+        .bLength = sizeof(hs_descriptors.sink),
+        .bDescriptorType = USB_DT_ENDPOINT,
+        .bEndpointAddress = 2 | USB_DIR_IN,
+        .bmAttributes = USB_ENDPOINT_XFER_BULK,
+        .wMaxPacketSize = MAX_PACKET_SIZE_HS,
     },
 };
 
@@ -151,7 +164,7 @@
     struct usb_handle *usb = (struct usb_handle *)x;
     int fd;
 
-    while (1) {
+    while (true) {
         // wait until the USB device needs opening
         adb_mutex_lock(&usb->lock);
         while (usb->fd != -1)
@@ -227,11 +240,8 @@
 
 static void usb_adb_init()
 {
-    usb_handle *h;
-    adb_thread_t tid;
-    int fd;
-
-    h = calloc(1, sizeof(usb_handle));
+    usb_handle* h = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
+    if (h == nullptr) fatal("couldn't allocate usb_handle");
 
     h->write = usb_adb_write;
     h->read = usb_adb_read;
@@ -241,12 +251,12 @@
     adb_cond_init(&h->notify, 0);
     adb_mutex_init(&h->lock, 0);
 
-    // Open the file /dev/android_adb_enable to trigger 
+    // Open the file /dev/android_adb_enable to trigger
     // the enabling of the adb USB function in the kernel.
     // We never touch this file again - just leave it open
     // indefinitely so the kernel will know when we are running
     // and when we are not.
-    fd = unix_open("/dev/android_adb_enable", O_RDWR);
+    int fd = unix_open("/dev/android_adb_enable", O_RDWR);
     if (fd < 0) {
        D("failed to open /dev/android_adb_enable\n");
     } else {
@@ -254,6 +264,7 @@
     }
 
     D("[ usb_init - starting thread ]\n");
+    adb_thread_t tid;
     if(adb_thread_create(&tid, usb_adb_open_thread, h)){
         fatal_errno("cannot create usb thread");
     }
@@ -263,6 +274,16 @@
 static void init_functionfs(struct usb_handle *h)
 {
     ssize_t ret;
+    struct desc_v1 v1_descriptor;
+    struct desc_v2 v2_descriptor;
+
+    v2_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
+    v2_descriptor.header.length = cpu_to_le32(sizeof(v2_descriptor));
+    v2_descriptor.header.flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC;
+    v2_descriptor.fs_count = 3;
+    v2_descriptor.hs_count = 3;
+    v2_descriptor.fs_descs = fs_descriptors;
+    v2_descriptor.hs_descs = hs_descriptors;
 
     if (h->control < 0) { // might have already done this before
         D("OPENING %s\n", USB_FFS_ADB_EP0);
@@ -272,10 +293,20 @@
             goto err;
         }
 
-        ret = adb_write(h->control, &descriptors, sizeof(descriptors));
+        ret = adb_write(h->control, &v2_descriptor, sizeof(v2_descriptor));
         if (ret < 0) {
-            D("[ %s: write descriptors failed: errno=%d ]\n", USB_FFS_ADB_EP0, errno);
-            goto err;
+            v1_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC);
+            v1_descriptor.header.length = cpu_to_le32(sizeof(v1_descriptor));
+            v1_descriptor.header.fs_count = 3;
+            v1_descriptor.header.hs_count = 3;
+            v1_descriptor.fs_descs = fs_descriptors;
+            v1_descriptor.hs_descs = hs_descriptors;
+            D("[ %s: Switching to V1_descriptor format errno=%d ]\n", USB_FFS_ADB_EP0, errno);
+            ret = adb_write(h->control, &v1_descriptor, sizeof(v1_descriptor));
+            if (ret < 0) {
+                D("[ %s: write descriptors failed: errno=%d ]\n", USB_FFS_ADB_EP0, errno);
+                goto err;
+            }
         }
 
         ret = adb_write(h->control, &strings, sizeof(strings));
@@ -319,14 +350,14 @@
 {
     struct usb_handle *usb = (struct usb_handle *)x;
 
-    while (1) {
+    while (true) {
         // wait until the USB device needs opening
         adb_mutex_lock(&usb->lock);
         while (usb->control != -1 && usb->bulk_in != -1 && usb->bulk_out != -1)
             adb_cond_wait(&usb->notify, &usb->lock);
         adb_mutex_unlock(&usb->lock);
 
-        while (1) {
+        while (true) {
             init_functionfs(usb);
 
             if (usb->control >= 0 && usb->bulk_in >= 0 && usb->bulk_out >= 0)
@@ -334,6 +365,7 @@
 
             adb_sleep_ms(1000);
         }
+        property_set("sys.usb.ffs.ready", "1");
 
         D("[ usb_thread - registering device ]\n");
         register_usb_transport(usb, 0, 0, 1);
@@ -343,7 +375,7 @@
     return 0;
 }
 
-static int bulk_write(int bulk_in, const char *buf, size_t length)
+static int bulk_write(int bulk_in, const uint8_t* buf, size_t length)
 {
     size_t count = 0;
     int ret;
@@ -362,22 +394,19 @@
     return count;
 }
 
-static int usb_ffs_write(usb_handle *h, const void *data, int len)
+static int usb_ffs_write(usb_handle* h, const void* data, int len)
 {
-    int n;
-
     D("about to write (fd=%d, len=%d)\n", h->bulk_in, len);
-    n = bulk_write(h->bulk_in, data, len);
+    int n = bulk_write(h->bulk_in, reinterpret_cast<const uint8_t*>(data), len);
     if (n != len) {
-        D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
-            h->bulk_in, n, errno, strerror(errno));
+        D("ERROR: fd = %d, n = %d: %s\n", h->bulk_in, n, strerror(errno));
         return -1;
     }
     D("[ done fd=%d ]\n", h->bulk_in);
     return 0;
 }
 
-static int bulk_read(int bulk_out, char *buf, size_t length)
+static int bulk_read(int bulk_out, uint8_t* buf, size_t length)
 {
     size_t count = 0;
     int ret;
@@ -398,15 +427,12 @@
     return count;
 }
 
-static int usb_ffs_read(usb_handle *h, void *data, int len)
+static int usb_ffs_read(usb_handle* h, void* data, int len)
 {
-    int n;
-
     D("about to read (fd=%d, len=%d)\n", h->bulk_out, len);
-    n = bulk_read(h->bulk_out, data, len);
+    int n = bulk_read(h->bulk_out, reinterpret_cast<uint8_t*>(data), len);
     if (n != len) {
-        D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
-            h->bulk_out, n, errno, strerror(errno));
+        D("ERROR: fd = %d, n = %d: %s\n", h->bulk_out, n, strerror(errno));
         return -1;
     }
     D("[ done fd=%d ]\n", h->bulk_out);
@@ -441,18 +467,15 @@
 
 static void usb_ffs_init()
 {
-    usb_handle *h;
-    adb_thread_t tid;
-
     D("[ usb_init - using FunctionFS ]\n");
 
-    h = calloc(1, sizeof(usb_handle));
+    usb_handle* h = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
+    if (h == nullptr) fatal("couldn't allocate usb_handle");
 
     h->write = usb_ffs_write;
     h->read = usb_ffs_read;
     h->kick = usb_ffs_kick;
-
-    h->control  = -1;
+    h->control = -1;
     h->bulk_out = -1;
     h->bulk_out = -1;
 
@@ -460,6 +483,7 @@
     adb_mutex_init(&h->lock, 0);
 
     D("[ usb_init - starting thread ]\n");
+    adb_thread_t tid;
     if (adb_thread_create(&tid, usb_ffs_open_thread, h)){
         fatal_errno("[ cannot create usb thread ]\n");
     }
diff --git a/adb/usb_osx.c b/adb/usb_osx.cpp
similarity index 84%
rename from adb/usb_osx.c
rename to adb/usb_osx.cpp
index ca4f2af..a795ce3 100644
--- a/adb/usb_osx.c
+++ b/adb/usb_osx.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#define TRACE_TAG TRACE_USB
+
+#include "sysdeps.h"
+
 #include <CoreFoundation/CoreFoundation.h>
 
 #include <IOKit/IOKitLib.h>
@@ -22,18 +26,16 @@
 #include <IOKit/IOMessage.h>
 #include <mach/mach_port.h>
 
-#include "sysdeps.h"
-
+#include <inttypes.h>
 #include <stdio.h>
 
-#define TRACE_TAG   TRACE_USB
 #include "adb.h"
-#include "usb_vendors.h"
+#include "transport.h"
 
 #define  DBG   D
 
 static IONotificationPortRef    notificationPort = 0;
-static io_iterator_t*           notificationIterators;
+static io_iterator_t            notificationIterator;
 
 struct usb_handle
 {
@@ -61,8 +63,6 @@
 {
     CFMutableDictionaryRef  matchingDict;
     CFRunLoopSourceRef      runLoopSource;
-    SInt32                  vendor, if_subclass, if_protocol;
-    unsigned                i;
 
     //* To set up asynchronous notifications, create a notification port and
     //* add its run loop event source to the program's run loop
@@ -70,47 +70,33 @@
     runLoopSource = IONotificationPortGetRunLoopSource(notificationPort);
     CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
 
-    memset(notificationIterators, 0, sizeof(notificationIterators));
+    //* Create our matching dictionary to find the Android device's
+    //* adb interface
+    //* IOServiceAddMatchingNotification consumes the reference, so we do
+    //* not need to release this
+    matchingDict = IOServiceMatching(kIOUSBInterfaceClassName);
 
-    //* loop through all supported vendors
-    for (i = 0; i < vendorIdCount; i++) {
-        //* Create our matching dictionary to find the Android device's
-        //* adb interface
-        //* IOServiceAddMatchingNotification consumes the reference, so we do
-        //* not need to release this
-        matchingDict = IOServiceMatching(kIOUSBInterfaceClassName);
-
-        if (!matchingDict) {
-            DBG("ERR: Couldn't create USB matching dictionary.\n");
-            return -1;
-        }
-
-        //* Match based on vendor id, interface subclass and protocol
-        vendor = vendorIds[i];
-        if_subclass = ADB_SUBCLASS;
-        if_protocol = ADB_PROTOCOL;
-        CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID),
-                             CFNumberCreate(kCFAllocatorDefault,
-                                            kCFNumberSInt32Type, &vendor));
-        CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceSubClass),
-                             CFNumberCreate(kCFAllocatorDefault,
-                                            kCFNumberSInt32Type, &if_subclass));
-        CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceProtocol),
-                             CFNumberCreate(kCFAllocatorDefault,
-                                            kCFNumberSInt32Type, &if_protocol));
-        IOServiceAddMatchingNotification(
-                notificationPort,
-                kIOFirstMatchNotification,
-                matchingDict,
-                AndroidInterfaceAdded,
-                NULL,
-                &notificationIterators[i]);
-
-        //* Iterate over set of matching interfaces to access already-present
-        //* devices and to arm the notification
-        AndroidInterfaceAdded(NULL, notificationIterators[i]);
+    if (!matchingDict) {
+        DBG("ERR: Couldn't create USB matching dictionary.\n");
+        return -1;
     }
 
+    //* We have to get notifications for all potential candidates and test them
+    //* at connection time because the matching rules don't allow for a
+    //* USB interface class of 0xff for class+subclass+protocol matches
+    //* See https://developer.apple.com/library/mac/qa/qa1076/_index.html
+    IOServiceAddMatchingNotification(
+            notificationPort,
+            kIOFirstMatchNotification,
+            matchingDict,
+            AndroidInterfaceAdded,
+            NULL,
+            &notificationIterator);
+
+    //* Iterate over set of matching interfaces to access already-present
+    //* devices and to arm the notification
+    AndroidInterfaceAdded(NULL, notificationIterator);
+
     return 0;
 }
 
@@ -126,6 +112,7 @@
     HRESULT                  result;
     SInt32                   score;
     UInt32                   locationId;
+    UInt8                    if_class, subclass, protocol;
     UInt16                   vendor;
     UInt16                   product;
     UInt8                    serialIndex;
@@ -146,9 +133,9 @@
         }
 
         //* This gets us the interface object
-        result = (*plugInInterface)->QueryInterface(plugInInterface,
-                CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID)
-                &iface);
+        result = (*plugInInterface)->QueryInterface(
+            plugInInterface,
+            CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID*)&iface);
         //* We only needed the plugin to get the interface, so discard it
         (*plugInInterface)->Release(plugInInterface);
         if (result || !iface) {
@@ -156,6 +143,16 @@
             continue;
         }
 
+        kr = (*iface)->GetInterfaceClass(iface, &if_class);
+        kr = (*iface)->GetInterfaceSubClass(iface, &subclass);
+        kr = (*iface)->GetInterfaceProtocol(iface, &protocol);
+        if(if_class != ADB_CLASS || subclass != ADB_SUBCLASS || protocol != ADB_PROTOCOL) {
+            // Ignore non-ADB devices.
+            DBG("Ignoring interface with incorrect class/subclass/protocol - %d, %d, %d\n", if_class, subclass, protocol);
+            (*iface)->Release(iface);
+            continue;
+        }
+
         //* this gets us an ioservice, with which we will find the actual
         //* device; after getting a plugin, and querying the interface, of
         //* course.
@@ -181,7 +178,7 @@
         }
 
         result = (*plugInInterface)->QueryInterface(plugInInterface,
-                CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID) &dev);
+            CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID*)&dev);
         //* only needed this to query the plugin
         (*plugInInterface)->Release(plugInInterface);
         if (result || !dev) {
@@ -192,12 +189,12 @@
 
         //* Now after all that, we actually have a ref to the device and
         //* the interface that matched our criteria
-
         kr = (*dev)->GetDeviceVendor(dev, &vendor);
         kr = (*dev)->GetDeviceProduct(dev, &product);
         kr = (*dev)->GetLocationID(dev, &locationId);
         if (kr == 0) {
-            snprintf(devpathBuf, sizeof(devpathBuf), "usb:%lX", locationId);
+            snprintf(devpathBuf, sizeof(devpathBuf), "usb:%" PRIu32 "X",
+	             (unsigned int)locationId);
             devpath = devpathBuf;
         }
         kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
@@ -338,7 +335,8 @@
                 interfaceSubClass, interfaceProtocol))
         goto err_bad_adb_interface;
 
-    handle = calloc(1, sizeof(usb_handle));
+    handle = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
+    if (handle == nullptr) goto err_bad_adb_interface;
 
     //* Iterate over the endpoints for this interface and find the first
     //* bulk in/out pipes available.  These will be our read/write pipes.
@@ -384,8 +382,6 @@
 
 void* RunLoopThread(void* unused)
 {
-    unsigned i;
-
     InitUSB();
 
     currentRunLoop = CFRunLoopGetCurrent();
@@ -398,9 +394,7 @@
     CFRunLoopRun();
     currentRunLoop = 0;
 
-    for (i = 0; i < vendorIdCount; i++) {
-        IOObjectRelease(notificationIterators[i]);
-    }
+    IOObjectRelease(notificationIterator);
     IONotificationPortDestroy(notificationPort);
 
     DBG("RunLoopThread done\n");
@@ -415,9 +409,6 @@
     {
         adb_thread_t    tid;
 
-        notificationIterators = (io_iterator_t*)malloc(
-            vendorIdCount * sizeof(io_iterator_t));
-
         adb_mutex_init(&start_lock, NULL);
         adb_cond_init(&start_cond, NULL);
 
@@ -442,11 +433,6 @@
     close_usb_devices();
     if (currentRunLoop)
         CFRunLoopStop(currentRunLoop);
-
-    if (notificationIterators != NULL) {
-        free(notificationIterators);
-        notificationIterators = NULL;
-    }
 }
 
 int usb_write(usb_handle *handle, const void *buf, int len)
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
deleted file mode 100755
index 19bcae4..0000000
--- a/adb/usb_vendors.c
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * 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.
- */
-
-#include "usb_vendors.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#ifdef _WIN32
-#  ifndef WIN32_LEAN_AND_MEAN
-#    define WIN32_LEAN_AND_MEAN
-#  endif
-#  include "windows.h"
-#  include "shlobj.h"
-#else
-#  include <unistd.h>
-#  include <sys/stat.h>
-#endif
-
-#include "sysdeps.h"
-#include "adb.h"
-
-#define ANDROID_PATH            ".android"
-#define ANDROID_ADB_INI         "adb_usb.ini"
-
-#define TRACE_TAG               TRACE_USB
-
-/* Keep the list below sorted alphabetically by #define name */
-// Acer's USB Vendor ID
-#define VENDOR_ID_ACER          0x0502
-// Allwinner's USB Vendor ID
-#define VENDOR_ID_ALLWINNER     0x1F3A
-// Amlogic's USB Vendor ID
-#define VENDOR_ID_AMLOGIC       0x1b8e
-// AnyDATA's USB Vendor ID
-#define VENDOR_ID_ANYDATA       0x16D5
-// Archos's USB Vendor ID
-#define VENDOR_ID_ARCHOS        0x0E79
-// Asus's USB Vendor ID
-#define VENDOR_ID_ASUS          0x0b05
-// BYD's USB Vendor ID
-#define VENDOR_ID_BYD           0x1D91
-// Compal's USB Vendor ID
-#define VENDOR_ID_COMPAL        0x04B7
-// Compalcomm's USB Vendor ID
-#define VENDOR_ID_COMPALCOMM    0x1219
-// Dell's USB Vendor ID
-#define VENDOR_ID_DELL          0x413c
-// ECS's USB Vendor ID
-#define VENDOR_ID_ECS           0x03fc
-// EMERGING_TECH's USB Vendor ID
-#define VENDOR_ID_EMERGING_TECH 0x297F
-// Emerson's USB Vendor ID
-#define VENDOR_ID_EMERSON       0x2207
-// Foxconn's USB Vendor ID
-#define VENDOR_ID_FOXCONN       0x0489
-// Fujitsu's USB Vendor ID
-#define VENDOR_ID_FUJITSU       0x04C5
-// Funai's USB Vendor ID
-#define VENDOR_ID_FUNAI         0x0F1C
-// Garmin-Asus's USB Vendor ID
-#define VENDOR_ID_GARMIN_ASUS   0x091E
-// Gigabyte's USB Vendor ID
-#define VENDOR_ID_GIGABYTE      0x0414
-// Gigaset's USB Vendor ID
-#define VENDOR_ID_GIGASET       0x1E85
-// GIONEE's USB Vendor ID
-#define VENDOR_ID_GIONEE        0x271D
-// Google's USB Vendor ID
-#define VENDOR_ID_GOOGLE        0x18d1
-// Haier's USB Vendor ID
-#define VENDOR_ID_HAIER         0x201E
-// Harris's USB Vendor ID
-#define VENDOR_ID_HARRIS        0x19A5
-// Hisense's USB Vendor ID
-#define VENDOR_ID_HISENSE       0x109b
-// Honeywell's USB Vendor ID
-#define VENDOR_ID_HONEYWELL     0x0c2e
-// HP's USB Vendor ID
-#define VENDOR_ID_HP            0x03f0
-// HTC's USB Vendor ID
-#define VENDOR_ID_HTC           0x0bb4
-// Huawei's USB Vendor ID
-#define VENDOR_ID_HUAWEI        0x12D1
-// INQ Mobile's USB Vendor ID
-#define VENDOR_ID_INQ_MOBILE    0x2314
-// Intel's USB Vendor ID
-#define VENDOR_ID_INTEL         0x8087
-// Intermec's USB Vendor ID
-#define VENDOR_ID_INTERMEC      0x067e
-// IRiver's USB Vendor ID
-#define VENDOR_ID_IRIVER        0x2420
-// K-Touch's USB Vendor ID
-#define VENDOR_ID_K_TOUCH       0x24E3
-// KT Tech's USB Vendor ID
-#define VENDOR_ID_KT_TECH       0x2116
-// Kobo's USB Vendor ID
-#define VENDOR_ID_KOBO          0x2237
-// Kyocera's USB Vendor ID
-#define VENDOR_ID_KYOCERA       0x0482
-// Lab126's USB Vendor ID
-#define VENDOR_ID_LAB126        0x1949
-// Lenovo's USB Vendor ID
-#define VENDOR_ID_LENOVO        0x17EF
-// LenovoMobile's USB Vendor ID
-#define VENDOR_ID_LENOVOMOBILE  0x2006
-// LG's USB Vendor ID
-#define VENDOR_ID_LGE           0x1004
-// Lumigon's USB Vendor ID
-#define VENDOR_ID_LUMIGON       0x25E3
-// Motorola's USB Vendor ID
-#define VENDOR_ID_MOTOROLA      0x22b8
-// MSI's USB Vendor ID
-#define VENDOR_ID_MSI           0x0DB0
-// MTK's USB Vendor ID
-#define VENDOR_ID_MTK           0x0e8d
-// NEC's USB Vendor ID
-#define VENDOR_ID_NEC           0x0409
-// B&N Nook's USB Vendor ID
-#define VENDOR_ID_NOOK          0x2080
-// Nvidia's USB Vendor ID
-#define VENDOR_ID_NVIDIA        0x0955
-// OPPO's USB Vendor ID
-#define VENDOR_ID_OPPO          0x22D9
-// On-The-Go-Video's USB Vendor ID
-#define VENDOR_ID_OTGV          0x2257
-// OUYA's USB Vendor ID
-#define VENDOR_ID_OUYA          0x2836
-// Pantech's USB Vendor ID
-#define VENDOR_ID_PANTECH       0x10A9
-// Pegatron's USB Vendor ID
-#define VENDOR_ID_PEGATRON      0x1D4D
-// Philips's USB Vendor ID
-#define VENDOR_ID_PHILIPS       0x0471
-// Panasonic Mobile Communication's USB Vendor ID
-#define VENDOR_ID_PMC           0x04DA
-// Positivo's USB Vendor ID
-#define VENDOR_ID_POSITIVO      0x1662
-// Prestigio's USB Vendor ID
-#define VENDOR_ID_PRESTIGIO     0x29e4
-// Qisda's USB Vendor ID
-#define VENDOR_ID_QISDA         0x1D45
-// Qualcomm's USB Vendor ID
-#define VENDOR_ID_QUALCOMM      0x05c6
-// Quanta's USB Vendor ID
-#define VENDOR_ID_QUANTA        0x0408
-// Rockchip's USB Vendor ID
-#define VENDOR_ID_ROCKCHIP      0x2207
-// Samsung's USB Vendor ID
-#define VENDOR_ID_SAMSUNG       0x04e8
-// Sharp's USB Vendor ID
-#define VENDOR_ID_SHARP         0x04dd
-// SK Telesys's USB Vendor ID
-#define VENDOR_ID_SK_TELESYS    0x1F53
-// Smartisan's USB Vendor ID
-#define VENDOR_ID_SMARTISAN     0x29a9
-// Sony's USB Vendor ID
-#define VENDOR_ID_SONY          0x054C
-// Sony Ericsson's USB Vendor ID
-#define VENDOR_ID_SONY_ERICSSON 0x0FCE
-// T & A Mobile Phones' USB Vendor ID
-#define VENDOR_ID_T_AND_A       0x1BBB
-// TechFaith's USB Vendor ID
-#define VENDOR_ID_TECHFAITH     0x1d09
-// Teleepoch's USB Vendor ID
-#define VENDOR_ID_TELEEPOCH     0x2340
-// Texas Instruments's USB Vendor ID
-#define VENDOR_ID_TI            0x0451
-// Toshiba's USB Vendor ID
-#define VENDOR_ID_TOSHIBA       0x0930
-// Unowhy's USB Vendor ID
-#define VENDOR_ID_UNOWHY        0x2A49
-// Vizio's USB Vendor ID
-#define VENDOR_ID_VIZIO         0xE040
-// Wacom's USB Vendor ID
-#define VENDOR_ID_WACOM         0x0531
-// Xiaomi's USB Vendor ID
-#define VENDOR_ID_XIAOMI        0x2717
-// YotaDevices's USB Vendor ID
-#define VENDOR_ID_YOTADEVICES   0x2916
-// Yulong Coolpad's USB Vendor ID
-#define VENDOR_ID_YULONG_COOLPAD 0x1EBF
-// ZTE's USB Vendor ID
-#define VENDOR_ID_ZTE           0x19D2
-/* Keep the list above sorted alphabetically by #define name */
-
-/** built-in vendor list */
-/* Keep the list below sorted alphabetically */
-int builtInVendorIds[] = {
-    VENDOR_ID_ACER,
-    VENDOR_ID_ALLWINNER,
-    VENDOR_ID_AMLOGIC,
-    VENDOR_ID_ANYDATA,
-    VENDOR_ID_ARCHOS,
-    VENDOR_ID_ASUS,
-    VENDOR_ID_BYD,
-    VENDOR_ID_COMPAL,
-    VENDOR_ID_COMPALCOMM,
-    VENDOR_ID_DELL,
-    VENDOR_ID_ECS,
-    VENDOR_ID_EMERGING_TECH,
-    VENDOR_ID_EMERSON,
-    VENDOR_ID_FOXCONN,
-    VENDOR_ID_FUJITSU,
-    VENDOR_ID_FUNAI,
-    VENDOR_ID_GARMIN_ASUS,
-    VENDOR_ID_GIGABYTE,
-    VENDOR_ID_GIGASET,
-    VENDOR_ID_GIONEE,
-    VENDOR_ID_GOOGLE,
-    VENDOR_ID_HAIER,
-    VENDOR_ID_HARRIS,
-    VENDOR_ID_HISENSE,
-    VENDOR_ID_HONEYWELL,
-    VENDOR_ID_HP,
-    VENDOR_ID_HTC,
-    VENDOR_ID_HUAWEI,
-    VENDOR_ID_INQ_MOBILE,
-    VENDOR_ID_INTEL,
-    VENDOR_ID_INTERMEC,
-    VENDOR_ID_IRIVER,
-    VENDOR_ID_KOBO,
-    VENDOR_ID_K_TOUCH,
-    VENDOR_ID_KT_TECH,
-    VENDOR_ID_KYOCERA,
-    VENDOR_ID_LAB126,
-    VENDOR_ID_LENOVO,
-    VENDOR_ID_LENOVOMOBILE,
-    VENDOR_ID_LGE,
-    VENDOR_ID_LUMIGON,
-    VENDOR_ID_MOTOROLA,
-    VENDOR_ID_MSI,
-    VENDOR_ID_MTK,
-    VENDOR_ID_NEC,
-    VENDOR_ID_NOOK,
-    VENDOR_ID_NVIDIA,
-    VENDOR_ID_OPPO,
-    VENDOR_ID_OTGV,
-    VENDOR_ID_OUYA,
-    VENDOR_ID_PANTECH,
-    VENDOR_ID_PEGATRON,
-    VENDOR_ID_PHILIPS,
-    VENDOR_ID_PMC,
-    VENDOR_ID_POSITIVO,
-    VENDOR_ID_PRESTIGIO,
-    VENDOR_ID_QISDA,
-    VENDOR_ID_QUALCOMM,
-    VENDOR_ID_QUANTA,
-    VENDOR_ID_ROCKCHIP,
-    VENDOR_ID_SAMSUNG,
-    VENDOR_ID_SHARP,
-    VENDOR_ID_SK_TELESYS,
-    VENDOR_ID_SMARTISAN,
-    VENDOR_ID_SONY,
-    VENDOR_ID_SONY_ERICSSON,
-    VENDOR_ID_T_AND_A,
-    VENDOR_ID_TECHFAITH,
-    VENDOR_ID_TELEEPOCH,
-    VENDOR_ID_TI,
-    VENDOR_ID_TOSHIBA,
-    VENDOR_ID_UNOWHY,
-    VENDOR_ID_VIZIO,
-    VENDOR_ID_WACOM,
-    VENDOR_ID_XIAOMI,
-    VENDOR_ID_YOTADEVICES,
-    VENDOR_ID_YULONG_COOLPAD,
-    VENDOR_ID_ZTE,
-};
-/* Keep the list above sorted alphabetically */
-
-#define BUILT_IN_VENDOR_COUNT    (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0]))
-
-/* max number of supported vendor ids (built-in + 3rd party). increase as needed */
-#define VENDOR_COUNT_MAX         128
-
-int vendorIds[VENDOR_COUNT_MAX];
-unsigned vendorIdCount = 0;
-
-int get_adb_usb_ini(char* buff, size_t len);
-
-void usb_vendors_init(void)
-{
-    if (VENDOR_COUNT_MAX < BUILT_IN_VENDOR_COUNT) {
-        fprintf(stderr, "VENDOR_COUNT_MAX not big enough for built-in vendor list.\n");
-        exit(2);
-    }
-
-    /* add the built-in vendors at the beginning of the array */
-    memcpy(vendorIds, builtInVendorIds, sizeof(builtInVendorIds));
-
-    /* default array size is the number of built-in vendors */
-    vendorIdCount = BUILT_IN_VENDOR_COUNT;
-
-    if (VENDOR_COUNT_MAX == BUILT_IN_VENDOR_COUNT)
-        return;
-
-    char temp[PATH_MAX];
-    if (get_adb_usb_ini(temp, sizeof(temp)) == 0) {
-        FILE * f = fopen(temp, "rt");
-
-        if (f != NULL) {
-            /* The vendor id file is pretty basic. 1 vendor id per line.
-               Lines starting with # are comments */
-            while (fgets(temp, sizeof(temp), f) != NULL) {
-                if (temp[0] == '#')
-                    continue;
-
-                long value = strtol(temp, NULL, 0);
-                if (errno == EINVAL || errno == ERANGE || value > INT_MAX || value < 0) {
-                    fprintf(stderr, "Invalid content in %s. Quitting.\n", ANDROID_ADB_INI);
-                    exit(2);
-                }
-
-                vendorIds[vendorIdCount++] = (int)value;
-
-                /* make sure we don't go beyond the array */
-                if (vendorIdCount == VENDOR_COUNT_MAX) {
-                    break;
-                }
-            }
-            fclose(f);
-        }
-    }
-}
-
-/* Utils methods */
-
-/* builds the path to the adb vendor id file. returns 0 if success */
-int build_path(char* buff, size_t len, const char* format, const char* home)
-{
-    if (snprintf(buff, len, format, home, ANDROID_PATH, ANDROID_ADB_INI) >= (signed)len) {
-        return 1;
-    }
-
-    return 0;
-}
-
-/* fills buff with the path to the adb vendor id file. returns 0 if success */
-int get_adb_usb_ini(char* buff, size_t len)
-{
-#ifdef _WIN32
-    const char* home = getenv("ANDROID_SDK_HOME");
-    if (home != NULL) {
-        return build_path(buff, len, "%s\\%s\\%s", home);
-    } else {
-        char path[MAX_PATH];
-        SHGetFolderPath( NULL, CSIDL_PROFILE, NULL, 0, path);
-        return build_path(buff, len, "%s\\%s\\%s", path);
-    }
-#else
-    const char* home = getenv("HOME");
-    if (home == NULL)
-        home = "/tmp";
-
-    return build_path(buff, len, "%s/%s/%s", home);
-#endif
-}
diff --git a/adb/usb_windows.c b/adb/usb_windows.cpp
similarity index 98%
rename from adb/usb_windows.c
rename to adb/usb_windows.cpp
index a2d7226..d2bd58c 100644
--- a/adb/usb_windows.c
+++ b/adb/usb_windows.cpp
@@ -14,19 +14,21 @@
  * limitations under the License.
  */
 
-#include <winsock2.h>
-#include <windows.h>
-#include <winerror.h>
-#include <errno.h>
-#include <usb100.h>
-#include <adb_api.h>
-#include <stdio.h>
-#include <stdlib.h>
+#define TRACE_TAG TRACE_USB
 
 #include "sysdeps.h"
 
-#define   TRACE_TAG  TRACE_USB
+#include <winsock2.h>  // winsock.h *must* be included before windows.h.
+#include <adb_api.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <usb100.h>
+#include <windows.h>
+#include <winerror.h>
+
 #include "adb.h"
+#include "transport.h"
 
 /** Structure usb_handle describes our connection to the usb device via
   AdbWinApi.dll. This structure is returned from usb_open() routine and
diff --git a/adf/libadf/Android.mk b/adf/libadf/Android.mk
index 908aa6c..7df354b 100644
--- a/adf/libadf/Android.mk
+++ b/adf/libadf/Android.mk
@@ -18,6 +18,7 @@
 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)
diff --git a/adf/libadf/adf.c b/adf/libadf/adf.c
index 1d19152..66c329c 100644
--- a/adf/libadf/adf.c
+++ b/adf/libadf/adf.c
@@ -17,9 +17,11 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <malloc.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <linux/limits.h>
 
diff --git a/adf/libadf/tests/Android.mk b/adf/libadf/tests/Android.mk
new file mode 100644
index 0000000..68e5817
--- /dev/null
+++ b/adf/libadf/tests/Android.mk
@@ -0,0 +1,23 @@
+#
+# 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/libadf/tests/adf_test.cpp b/adf/libadf/tests/adf_test.cpp
new file mode 100644
index 0000000..01b2785
--- /dev/null
+++ b/adf/libadf/tests/adf_test.cpp
@@ -0,0 +1,342 @@
+/*
+ * 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.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+
+#include <adf/adf.h>
+#include <gtest/gtest.h>
+#include <sys/mman.h>
+
+class AdfTest : public testing::Test {
+public:
+    AdfTest() : intf_id(0), intf(-1), eng_id(0), eng(-1) { }
+
+    virtual void SetUp() {
+        int err = adf_device_open(dev_id, O_RDWR, &dev);
+        ASSERT_GE(err, 0) << "opening ADF device " << dev_id <<
+                " failed: " << strerror(-err);
+
+        err = adf_find_simple_post_configuration(&dev, fmt8888, n_fmt8888,
+                &intf_id, &eng_id);
+        ASSERT_GE(err, 0) << "finding ADF configuration failed: " <<
+                strerror(-err);
+
+        intf = adf_interface_open(&dev, intf_id, O_RDWR);
+        ASSERT_GE(intf, 0) << "opening ADF interface " << dev_id << "." <<
+                intf_id << " failed: " << strerror(-intf);
+
+        eng = adf_overlay_engine_open(&dev, eng_id, O_RDWR);
+        ASSERT_GE(eng, 0) << "opening ADF overlay engine " << dev_id << "." <<
+                eng_id << " failed: " << strerror(-eng);
+    }
+
+    virtual void TearDown() {
+        if (eng >= 0)
+            close(eng);
+        if (intf >= 0)
+            close(intf);
+        adf_device_close(&dev);
+    }
+
+    void get8888Format(uint32_t &fmt, char fmt_str[ADF_FORMAT_STR_SIZE]) {
+        adf_overlay_engine_data data;
+        int err = adf_get_overlay_engine_data(eng, &data);
+        ASSERT_GE(err, 0) << "getting ADF overlay engine data failed: " <<
+                strerror(-err);
+
+        for (size_t i = 0; i < data.n_supported_formats; i++) {
+            for (size_t j = 0; j < n_fmt8888; j++) {
+                if (data.supported_formats[i] == fmt8888[j]) {
+                    fmt = data.supported_formats[i];
+                    adf_format_str(fmt, fmt_str);
+                    adf_free_overlay_engine_data(&data);
+                    return;
+                }
+            }
+        }
+
+        adf_free_overlay_engine_data(&data);
+        FAIL(); /* this should never happen */
+    }
+
+    void drawCheckerboard(void *buf, uint32_t w, uint32_t h, uint32_t pitch) {
+        uint8_t *buf8 = reinterpret_cast<uint8_t *>(buf);
+        for (uint32_t y = 0; y < h / 2; y++) {
+            uint32_t *scanline = reinterpret_cast<uint32_t *>(buf8 + y * pitch);
+            for (uint32_t x = 0; x < w / 2; x++)
+                scanline[x] = 0xFF0000FF;
+            for (uint32_t x = w / 2; x < w; x++)
+                scanline[x] = 0xFF00FFFF;
+        }
+        for (uint32_t y = h / 2; y < h; y++) {
+            uint32_t *scanline = reinterpret_cast<uint32_t *>(buf8 + y * pitch);
+            for (uint32_t x = 0; x < w / 2; x++)
+                scanline[x] = 0xFFFF00FF;
+            for (uint32_t x = w / 2; x < w; x++)
+                scanline[x] = 0xFFFFFFFF;
+        }
+    }
+
+    /* various helpers to call ADF and die on failure */
+
+    void getInterfaceData(adf_interface_data &data) {
+         int err = adf_get_interface_data(intf, &data);
+         ASSERT_GE(err, 0) << "getting ADF interface data failed: " <<
+                 strerror(-err);
+    }
+
+    void getCurrentMode(uint32_t &w, uint32_t &h) {
+        adf_interface_data data;
+        ASSERT_NO_FATAL_FAILURE(getInterfaceData(data));
+        w = data.current_mode.hdisplay;
+        h = data.current_mode.vdisplay;
+        adf_free_interface_data(&data);
+    }
+
+    void blank(uint8_t mode) {
+        int err = adf_interface_blank(intf, mode);
+        ASSERT_FALSE(err < 0 && err != -EBUSY) <<
+                "unblanking interface failed: " << strerror(-err);
+    }
+
+    void attach() {
+        int err = adf_device_attach(&dev, eng_id, intf_id);
+        ASSERT_FALSE(err < 0 && err != -EALREADY) <<
+                "attaching overlay engine " << eng_id << " to interface " <<
+                intf_id << " failed: " << strerror(-err);
+    }
+
+    void detach() {
+        int err = adf_device_detach(&dev, eng_id, intf_id);
+        ASSERT_FALSE(err < 0 && err != -EINVAL) <<
+                "detaching overlay engine " << eng_id << " from interface " <<
+                intf_id << " failed: " << strerror(-err);
+    }
+
+    void readVsyncTimestamp(uint64_t &timestamp) {
+        adf_event *event;
+        int err = adf_read_event(intf, &event);
+        ASSERT_GE(err, 0) << "reading ADF event failed: " << strerror(-err);
+
+        ASSERT_EQ(ADF_EVENT_VSYNC, event->type);
+        ASSERT_EQ(sizeof(adf_vsync_event), event->length);
+
+        adf_vsync_event *vsync_event =
+                reinterpret_cast<adf_vsync_event *>(event);
+        timestamp = vsync_event->timestamp;
+        free(event);
+    }
+
+protected:
+    adf_device dev;
+    adf_id_t intf_id;
+    int intf;
+    adf_id_t eng_id;
+    int eng;
+
+private:
+    const static adf_id_t dev_id = 0;
+    const static __u32 fmt8888[];
+    const static size_t n_fmt8888;
+};
+
+const __u32 AdfTest::fmt8888[] = {
+   DRM_FORMAT_XRGB8888,
+   DRM_FORMAT_XBGR8888,
+   DRM_FORMAT_RGBX8888,
+   DRM_FORMAT_BGRX8888,
+   DRM_FORMAT_ARGB8888,
+   DRM_FORMAT_ABGR8888,
+   DRM_FORMAT_RGBA8888,
+   DRM_FORMAT_BGRA8888
+};
+const size_t AdfTest::n_fmt8888 = sizeof(fmt8888) / sizeof(fmt8888[0]);
+
+TEST(adf, devices) {
+    adf_id_t *devs;
+    ssize_t n_devs = adf_devices(&devs);
+    free(devs);
+
+    ASSERT_GE(n_devs, 0) << "enumerating ADF devices failed: " <<
+            strerror(-n_devs);
+    ASSERT_TRUE(devs != NULL);
+}
+
+TEST_F(AdfTest, device_data) {
+    adf_device_data data;
+    int err = adf_get_device_data(&dev, &data);
+    ASSERT_GE(err, 0) << "getting ADF device data failed: " << strerror(-err);
+
+    EXPECT_LT(data.n_attachments, ADF_MAX_ATTACHMENTS);
+    EXPECT_GT(data.n_allowed_attachments, 0U);
+    EXPECT_LT(data.n_allowed_attachments, ADF_MAX_ATTACHMENTS);
+    EXPECT_LT(data.custom_data_size, (size_t)ADF_MAX_CUSTOM_DATA_SIZE);
+    adf_free_device_data(&data);
+}
+
+TEST_F(AdfTest, interface_data) {
+    adf_interface_data data;
+    ASSERT_NO_FATAL_FAILURE(getInterfaceData(data));
+
+    EXPECT_LT(data.type, ADF_INTF_TYPE_MAX);
+    EXPECT_LE(data.dpms_state, DRM_MODE_DPMS_OFF);
+    EXPECT_EQ(1, data.hotplug_detect);
+    EXPECT_GT(data.n_available_modes, 0U);
+    EXPECT_LT(data.custom_data_size, (size_t)ADF_MAX_CUSTOM_DATA_SIZE);
+    adf_free_interface_data(&data);
+}
+
+TEST_F(AdfTest, overlay_engine_data) {
+    adf_overlay_engine_data data;
+    int err = adf_get_overlay_engine_data(eng, &data);
+    ASSERT_GE(err, 0) << "getting ADF overlay engine failed: " <<
+            strerror(-err);
+
+    EXPECT_GT(data.n_supported_formats, 0U);
+    EXPECT_LT(data.n_supported_formats, ADF_MAX_SUPPORTED_FORMATS);
+    EXPECT_LT(data.custom_data_size, (size_t)ADF_MAX_CUSTOM_DATA_SIZE);
+    adf_free_overlay_engine_data(&data);
+}
+
+TEST_F(AdfTest, blank) {
+    int err = adf_interface_blank(intf, (uint8_t)-1);
+    EXPECT_EQ(-EINVAL, err) << "setting bogus DPMS mode should have failed";
+
+    err = adf_interface_blank(eng, DRM_MODE_DPMS_OFF);
+    EXPECT_EQ(-EINVAL, err) << "blanking overlay engine should have failed";
+
+    ASSERT_NO_FATAL_FAILURE(blank(DRM_MODE_DPMS_OFF));
+    err = adf_interface_blank(intf, DRM_MODE_DPMS_OFF);
+    EXPECT_EQ(-EBUSY, err) << "blanking interface twice should have failed";
+
+    ASSERT_NO_FATAL_FAILURE(blank(DRM_MODE_DPMS_ON));
+    err = adf_interface_blank(intf, DRM_MODE_DPMS_ON);
+    EXPECT_EQ(-EBUSY, err) << "unblanking interface twice should have failed";
+
+    adf_interface_data data;
+    ASSERT_NO_FATAL_FAILURE(getInterfaceData(data));
+    EXPECT_EQ(DRM_MODE_DPMS_ON, data.dpms_state);
+    adf_free_interface_data(&data);
+}
+
+TEST_F(AdfTest, event) {
+    int err = adf_set_event(intf, ADF_EVENT_TYPE_MAX, true);
+    EXPECT_EQ(-EINVAL, err) << "enabling bogus ADF event should have failed";
+
+    err = adf_set_event(intf, ADF_EVENT_TYPE_MAX, false);
+    EXPECT_EQ(-EINVAL, err) << "disabling bogus ADF event should have failed";
+
+    err = adf_set_event(intf, ADF_EVENT_VSYNC, true);
+    ASSERT_GE(err, 0) << "enabling vsync event failed: " << strerror(-err);
+
+    err = adf_set_event(intf, ADF_EVENT_VSYNC, true);
+    EXPECT_EQ(-EALREADY, err) <<
+            "enabling vsync event twice should have failed";
+
+    ASSERT_NO_FATAL_FAILURE(blank(DRM_MODE_DPMS_ON));
+
+    uint64_t timestamp1, timestamp2;
+    ASSERT_NO_FATAL_FAILURE(readVsyncTimestamp(timestamp1));
+    ASSERT_NO_FATAL_FAILURE(readVsyncTimestamp(timestamp2));
+    EXPECT_GT(timestamp2, timestamp1);
+
+    err = adf_set_event(intf, ADF_EVENT_VSYNC, false);
+    EXPECT_GE(err, 0) << "disabling vsync event failed: " << strerror(-err);
+
+    err = adf_set_event(intf, ADF_EVENT_VSYNC, false);
+    EXPECT_EQ(-EALREADY, err) <<
+            "disabling vsync event twice should have failed";
+}
+
+TEST_F(AdfTest, attach) {
+    ASSERT_NO_FATAL_FAILURE(attach());
+    int err = adf_device_attach(&dev, eng_id, intf_id);
+    EXPECT_EQ(-EALREADY, err) << "attaching overlay engine " << eng_id <<
+            " to interface " << intf_id << " twice should have failed";
+
+    ASSERT_NO_FATAL_FAILURE(detach());
+    err = adf_device_detach(&dev, eng_id, intf_id);
+    EXPECT_EQ(-EINVAL, err) << "detaching overlay engine " << eng_id <<
+            " from interface " << intf_id << " twice should have failed";
+
+    err = adf_device_attach(&dev, eng_id, ADF_MAX_INTERFACES);
+    EXPECT_EQ(-EINVAL, err) << "attaching overlay engine " << eng_id <<
+            " to bogus interface should have failed";
+
+    err = adf_device_detach(&dev, eng_id, ADF_MAX_INTERFACES);
+    EXPECT_EQ(-EINVAL, err) << "detaching overlay engine " << eng_id <<
+            " from bogus interface should have failed";
+}
+
+TEST_F(AdfTest, simple_buffer_alloc) {
+    uint32_t w = 0, h = 0;
+    ASSERT_NO_FATAL_FAILURE(getCurrentMode(w, h));
+
+    uint32_t format;
+    char format_str[ADF_FORMAT_STR_SIZE];
+    ASSERT_NO_FATAL_FAILURE(get8888Format(format, format_str));
+
+    uint32_t offset;
+    uint32_t pitch;
+    int buf_fd = adf_interface_simple_buffer_alloc(intf, w, h, format, &offset,
+            &pitch);
+    EXPECT_GE(buf_fd, 0) << "allocating " << w << "x" << h << " " <<
+            format_str << " buffer failed: " << strerror(-buf_fd);
+    EXPECT_GE(pitch, w * 4);
+    close(buf_fd);
+
+    buf_fd = adf_interface_simple_buffer_alloc(intf, w, h, 0xDEADBEEF, &offset,
+            &pitch);
+    /* n.b.: ADF only allows simple buffers with built-in RGB formats,
+       so this should fail even if a driver supports custom format 0xDEADBEEF */
+    EXPECT_EQ(-EINVAL, buf_fd) <<
+            "allocating buffer with bogus format should have failed";
+}
+
+TEST_F(AdfTest, simple_buffer) {
+    uint32_t w = 0, h = 0;
+    ASSERT_NO_FATAL_FAILURE(getCurrentMode(w, h));
+
+    uint32_t format = 0;
+    char format_str[ADF_FORMAT_STR_SIZE];
+    ASSERT_NO_FATAL_FAILURE(get8888Format(format, format_str));
+
+    uint32_t offset;
+    uint32_t pitch;
+    int buf_fd = adf_interface_simple_buffer_alloc(intf, w, h, format, &offset,
+            &pitch);
+    ASSERT_GE(buf_fd, 0) << "allocating " << w << "x" << h << " " <<
+            format_str << " buffer failed: " << strerror(-buf_fd);
+    EXPECT_GE(pitch, w * 4);
+
+    void *mapped = mmap(NULL, pitch * h, PROT_WRITE, MAP_SHARED, buf_fd,
+            offset);
+    ASSERT_NE(mapped, MAP_FAILED) << "mapping " << w << "x" << h << " " <<
+            format_str << " buffer failed: " << strerror(-errno);
+    drawCheckerboard(mapped, w, h, pitch);
+    munmap(mapped, pitch * h);
+
+    ASSERT_NO_FATAL_FAILURE(attach());
+    ASSERT_NO_FATAL_FAILURE(blank(DRM_MODE_DPMS_ON));
+
+    int release_fence = adf_interface_simple_post(intf, eng_id, w, h, format,
+            buf_fd, offset, pitch, -1);
+    close(buf_fd);
+    ASSERT_GE(release_fence, 0) << "posting " << w << "x" << h << " " <<
+            format_str << " buffer failed: " << strerror(-release_fence);
+    close(release_fence);
+}
diff --git a/adf/libadfhwc/Android.mk b/adf/libadfhwc/Android.mk
index acea322..898f9c9 100644
--- a/adf/libadfhwc/Android.mk
+++ b/adf/libadfhwc/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := libadfhwc
 LOCAL_MODULE_TAGS := optional
 LOCAL_STATIC_LIBRARIES := libadf liblog libutils
-LOCAL_CFLAGS += -DLOG_TAG=\"adfhwc\"
+LOCAL_CFLAGS += -DLOG_TAG=\"adfhwc\" -Werror
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS)
 include $(BUILD_STATIC_LIBRARY)
diff --git a/adf/libadfhwc/adfhwc.cpp b/adf/libadfhwc/adfhwc.cpp
index 57e09eb..21f245e 100644
--- a/adf/libadfhwc/adfhwc.cpp
+++ b/adf/libadfhwc/adfhwc.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <fcntl.h>
+#include <malloc.h>
 #include <poll.h>
 #include <pthread.h>
 #include <sys/resource.h>
diff --git a/base/.clang-format b/base/.clang-format
new file mode 100644
index 0000000..2b83a1f
--- /dev/null
+++ b/base/.clang-format
@@ -0,0 +1,11 @@
+BasedOnStyle: Google
+AllowShortBlocksOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 2
+PointerAlignment: Left
+TabWidth: 2
+UseTab: Never
+PenaltyExcessCharacter: 32
diff --git a/base/Android.mk b/base/Android.mk
new file mode 100644
index 0000000..ad85c6b
--- /dev/null
+++ b/base/Android.mk
@@ -0,0 +1,109 @@
+#
+# 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 \
+    stringprintf.cpp \
+    strings.cpp \
+
+libbase_test_src_files := \
+    file_test.cpp \
+    stringprintf_test.cpp \
+    strings_test.cpp \
+    test_main.cpp \
+    test_utils.cpp \
+
+libbase_cppflags := \
+    -Wall \
+    -Wextra \
+    -Werror \
+
+# Device
+# ------------------------------------------------------------------------------
+include $(CLEAR_VARS)
+LOCAL_MODULE := libbase
+LOCAL_CLANG := true
+LOCAL_SRC_FILES := $(libbase_src_files) logging.cpp
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_CPPFLAGS := $(libbase_cppflags)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_STATIC_LIBRARIES := libcutils
+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_SHARED_LIBRARIES := libcutils
+LOCAL_MULTILIB := both
+include $(BUILD_SHARED_LIBRARY)
+
+# Host
+# ------------------------------------------------------------------------------
+include $(CLEAR_VARS)
+LOCAL_MODULE := libbase
+LOCAL_SRC_FILES := $(libbase_src_files)
+ifneq ($(HOST_OS),windows)
+    LOCAL_SRC_FILES += logging.cpp
+endif
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_CPPFLAGS := $(libbase_cppflags)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_STATIC_LIBRARIES := libcutils
+LOCAL_MULTILIB := both
+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_STATIC_LIBRARIES := libcutils
+LOCAL_MULTILIB := both
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+# Tests
+# ------------------------------------------------------------------------------
+include $(CLEAR_VARS)
+LOCAL_MODULE := libbase_test
+LOCAL_CLANG := true
+LOCAL_SRC_FILES := $(libbase_test_src_files) logging_test.cpp
+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_SRC_FILES := $(libbase_test_src_files)
+ifneq ($(HOST_OS),windows)
+    LOCAL_SRC_FILES += logging_test.cpp
+endif
+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/CPPLINT.cfg b/base/CPPLINT.cfg
new file mode 100644
index 0000000..d94a89c
--- /dev/null
+++ b/base/CPPLINT.cfg
@@ -0,0 +1,2 @@
+set noparent
+filter=-build/header_guard,-build/include,-build/c++11,-whitespace/operators
diff --git a/base/file.cpp b/base/file.cpp
new file mode 100644
index 0000000..9a340b7
--- /dev/null
+++ b/base/file.cpp
@@ -0,0 +1,148 @@
+/*
+ * 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/file.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <string>
+
+#include "base/macros.h"  // For TEMP_FAILURE_RETRY on Darwin.
+#define LOG_TAG "base.file"
+#include "cutils/log.h"
+#include "utils/Compat.h"
+
+namespace android {
+namespace base {
+
+bool ReadFdToString(int fd, std::string* content) {
+  content->clear();
+
+  char buf[BUFSIZ];
+  ssize_t n;
+  while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) {
+    content->append(buf, n);
+  }
+  return (n == 0) ? true : false;
+}
+
+bool ReadFileToString(const std::string& path, std::string* content) {
+  content->clear();
+
+  int fd =
+      TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
+  if (fd == -1) {
+    return false;
+  }
+  bool result = ReadFdToString(fd, content);
+  close(fd);
+  return result;
+}
+
+bool WriteStringToFd(const std::string& content, int fd) {
+  const char* p = content.data();
+  size_t left = content.size();
+  while (left > 0) {
+    ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, left));
+    if (n == -1) {
+      return false;
+    }
+    p += n;
+    left -= n;
+  }
+  return true;
+}
+
+static bool CleanUpAfterFailedWrite(const std::string& path) {
+  // Something went wrong. Let's not leave a corrupt file lying around.
+  int saved_errno = errno;
+  unlink(path.c_str());
+  errno = saved_errno;
+  return false;
+}
+
+#if !defined(_WIN32)
+bool WriteStringToFile(const std::string& content, const std::string& path,
+                       mode_t mode, uid_t owner, gid_t group) {
+  int fd = TEMP_FAILURE_RETRY(
+      open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+           mode));
+  if (fd == -1) {
+    ALOGE("android::WriteStringToFile open failed: %s", strerror(errno));
+    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));
+    return CleanUpAfterFailedWrite(path);
+  }
+  if (fchown(fd, owner, group) == -1) {
+    ALOGE("android::WriteStringToFile fchown failed: %s", strerror(errno));
+    return CleanUpAfterFailedWrite(path);
+  }
+  if (!WriteStringToFd(content, fd)) {
+    ALOGE("android::WriteStringToFile write failed: %s", strerror(errno));
+    return CleanUpAfterFailedWrite(path);
+  }
+  close(fd);
+  return true;
+}
+#endif
+
+bool WriteStringToFile(const std::string& content, const std::string& path) {
+  int fd = TEMP_FAILURE_RETRY(
+      open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+           DEFFILEMODE));
+  if (fd == -1) {
+    return false;
+  }
+
+  bool result = WriteStringToFd(content, fd);
+  close(fd);
+  return result || CleanUpAfterFailedWrite(path);
+}
+
+bool ReadFully(int fd, void* data, size_t byte_count) {
+  uint8_t* p = reinterpret_cast<uint8_t*>(data);
+  size_t remaining = byte_count;
+  while (remaining > 0) {
+    ssize_t n = TEMP_FAILURE_RETRY(read(fd, p, remaining));
+    if (n <= 0) return false;
+    p += n;
+    remaining -= n;
+  }
+  return true;
+}
+
+bool WriteFully(int fd, const void* data, size_t byte_count) {
+  const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
+  size_t remaining = byte_count;
+  while (remaining > 0) {
+    ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, remaining));
+    if (n == -1) return false;
+    p += n;
+    remaining -= n;
+  }
+  return true;
+}
+
+}  // namespace base
+}  // namespace android
diff --git a/base/file_test.cpp b/base/file_test.cpp
new file mode 100644
index 0000000..5445a0d
--- /dev/null
+++ b/base/file_test.cpp
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+
+#include "base/file.h"
+
+#include <gtest/gtest.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "test_utils.h"
+
+TEST(file, ReadFileToString_ENOENT) {
+  std::string s("hello");
+  errno = 0;
+  ASSERT_FALSE(android::base::ReadFileToString("/proc/does-not-exist", &s));
+  EXPECT_EQ(ENOENT, errno);
+  EXPECT_EQ("", s);  // s was cleared.
+}
+
+TEST(file, ReadFileToString_success) {
+  std::string s("hello");
+  ASSERT_TRUE(android::base::ReadFileToString("/proc/version", &s)) << errno;
+  EXPECT_GT(s.length(), 6U);
+  EXPECT_EQ('\n', s[s.length() - 1]);
+  s[5] = 0;
+  EXPECT_STREQ("Linux", s.c_str());
+}
+
+TEST(file, WriteStringToFile) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+  ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.filename)) << errno;
+  std::string s;
+  ASSERT_TRUE(android::base::ReadFileToString(tf.filename, &s)) << errno;
+  EXPECT_EQ("abc", s);
+}
+
+TEST(file, WriteStringToFile2) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+  ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.filename, 0660,
+                                               getuid(), getgid()))
+      << errno;
+  struct stat sb;
+  ASSERT_EQ(0, stat(tf.filename, &sb));
+  ASSERT_EQ(0660U, static_cast<unsigned int>(sb.st_mode & ~S_IFMT));
+  ASSERT_EQ(getuid(), sb.st_uid);
+  ASSERT_EQ(getgid(), sb.st_gid);
+  std::string s;
+  ASSERT_TRUE(android::base::ReadFileToString(tf.filename, &s)) << errno;
+  EXPECT_EQ("abc", s);
+}
+
+TEST(file, WriteStringToFd) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+  ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd));
+
+  ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << errno;
+
+  std::string s;
+  ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << errno;
+  EXPECT_EQ("abc", s);
+}
+
+TEST(file, ReadFully) {
+  int fd = open("/proc/version", O_RDONLY);
+  ASSERT_NE(-1, fd) << strerror(errno);
+
+  char buf[1024];
+  memset(buf, 0, sizeof(buf));
+  ASSERT_TRUE(android::base::ReadFully(fd, buf, 5));
+  ASSERT_STREQ("Linux", buf);
+
+  ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno);
+
+  ASSERT_FALSE(android::base::ReadFully(fd, buf, sizeof(buf)));
+
+  close(fd);
+}
+
+TEST(file, WriteFully) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+  ASSERT_TRUE(android::base::WriteFully(tf.fd, "abc", 3));
+  std::string s;
+  ASSERT_TRUE(android::base::ReadFileToString(tf.filename, &s)) << errno;
+  EXPECT_EQ("abc", s);
+}
diff --git a/base/include/base/file.h b/base/include/base/file.h
new file mode 100644
index 0000000..acd29b3
--- /dev/null
+++ b/base/include/base/file.h
@@ -0,0 +1,43 @@
+/*
+ * 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 BASE_FILE_H
+#define BASE_FILE_H
+
+#include <sys/stat.h>
+#include <string>
+
+namespace android {
+namespace base {
+
+bool ReadFdToString(int fd, std::string* content);
+bool ReadFileToString(const std::string& path, std::string* content);
+
+bool WriteStringToFile(const std::string& content, const std::string& path);
+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);
+#endif
+
+bool ReadFully(int fd, void* data, size_t byte_count);
+bool WriteFully(int fd, const void* data, size_t byte_count);
+
+}  // namespace base
+}  // namespace android
+
+#endif  // BASE_FILE_H
diff --git a/base/include/base/logging.h b/base/include/base/logging.h
new file mode 100644
index 0000000..230adb8
--- /dev/null
+++ b/base/include/base/logging.h
@@ -0,0 +1,297 @@
+/*
+ * 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 BASE_LOGGING_H
+#define BASE_LOGGING_H
+
+#include <functional>
+#include <memory>
+#include <ostream>
+
+#include "base/macros.h"
+
+namespace android {
+namespace base {
+
+enum LogSeverity {
+  VERBOSE,
+  DEBUG,
+  INFO,
+  WARNING,
+  ERROR,
+  FATAL,
+};
+
+enum LogId {
+  DEFAULT,
+  MAIN,
+  SYSTEM,
+};
+
+typedef std::function<void(LogId, LogSeverity, const char*, const char*,
+                           unsigned int, const char*)> LogFunction;
+
+extern void StderrLogger(LogId, LogSeverity, const char*, const char*,
+                         unsigned int, const char*);
+
+#ifdef __ANDROID__
+// We expose this even though it is the default because a user that wants to
+// override the default log buffer will have to construct this themselves.
+class LogdLogger {
+ public:
+  explicit LogdLogger(LogId default_log_id = android::base::MAIN);
+
+  void operator()(LogId, LogSeverity, const char* tag, const char* file,
+                  unsigned int line, const char* message);
+
+ private:
+  LogId default_log_id_;
+};
+#endif
+
+// Configure logging based on ANDROID_LOG_TAGS environment variable.
+// We need to parse a string that looks like
+//
+//      *:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i
+//
+// 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[]);
+
+// Replace the current logger.
+extern void SetLogger(LogFunction&& logger);
+
+// Logs a message to logcat on Android otherwise to stderr. If the severity is
+// FATAL it also causes an abort. For example:
+//
+//     LOG(FATAL) << "We didn't expect to reach here";
+#define LOG(severity)                                                       \
+  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
+                              ::android::base::severity, -1).stream()
+
+// Logs a message to logcat with the specified log ID on Android otherwise to
+// stderr. If the severity is FATAL it also causes an abort.
+#define LOG_TO(dest, severity)                                           \
+  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::dest, \
+                              ::android::base::severity, -1).stream()
+
+// A variant of LOG that also logs the current errno value. To be used when
+// library calls fail.
+#define PLOG(severity)                                                      \
+  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
+                              ::android::base::severity, errno).stream()
+
+// Behaves like PLOG, but logs to the specified log ID.
+#define PLOG_TO(dest, severity)                                          \
+  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::dest, \
+                              ::android::base::severity, errno).stream()
+
+// Marker that code is yet to be implemented.
+#define UNIMPLEMENTED(level) \
+  LOG(level) << __PRETTY_FUNCTION__ << " unimplemented "
+
+// 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:
+//
+//     CHECK(false == true) results in a log message of
+//       "Check failed: false == true".
+#define CHECK(x)                                                            \
+  if (UNLIKELY(!(x)))                                                       \
+  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
+                              ::android::base::FATAL, -1).stream()          \
+      << "Check failed: " #x << " "
+
+// Helper for CHECK_xx(x,y) macros.
+#define CHECK_OP(LHS, RHS, OP)                                              \
+  for (auto _values = ::android::base::MakeEagerEvaluator(LHS, RHS);        \
+       UNLIKELY(!(_values.lhs OP _values.rhs));                             \
+       /* empty */)                                                         \
+  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
+                              ::android::base::FATAL, -1).stream()          \
+      << "Check failed: " << #LHS << " " << #OP << " " << #RHS              \
+      << " (" #LHS "=" << _values.lhs << ", " #RHS "=" << _values.rhs << ") "
+
+// Check whether a condition holds between x and y, LOG(FATAL) if not. The value
+// of the expressions x and y is evaluated once. Extra logging can be appended
+// using << after. For example:
+//
+//     CHECK_NE(0 == 1, false) results in
+//       "Check failed: false != false (0==1=false, false=false) ".
+#define CHECK_EQ(x, y) CHECK_OP(x, y, == )
+#define CHECK_NE(x, y) CHECK_OP(x, y, != )
+#define CHECK_LE(x, y) CHECK_OP(x, y, <= )
+#define CHECK_LT(x, y) CHECK_OP(x, y, < )
+#define CHECK_GE(x, y) CHECK_OP(x, y, >= )
+#define CHECK_GT(x, y) CHECK_OP(x, y, > )
+
+// Helper for CHECK_STRxx(s1,s2) macros.
+#define CHECK_STROP(s1, s2, sense)                                         \
+  if (UNLIKELY((strcmp(s1, s2) == 0) != sense))                            \
+    LOG(FATAL) << "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)
+#define CHECK_STRNE(s1, s2) CHECK_STROP(s1, s2, false)
+
+// Perform the pthread function call(args), LOG(FATAL) on error.
+#define CHECK_PTHREAD_CALL(call, args, what)                           \
+  do {                                                                 \
+    int rc = call args;                                                \
+    if (rc != 0) {                                                     \
+      errno = rc;                                                      \
+      PLOG(FATAL) << #call << " failed for " << what; \
+    }                                                                  \
+  } while (false)
+
+// CHECK that can be used in a constexpr function. For example:
+//
+//    constexpr int half(int n) {
+//      return
+//          DCHECK_CONSTEXPR(n >= 0, , 0)
+//          CHECK_CONSTEXPR((n & 1) == 0),
+//              << "Extra debugging output: n = " << n, 0)
+//          n / 2;
+//    }
+#define CHECK_CONSTEXPR(x, out, dummy)                                     \
+  (UNLIKELY(!(x)))                                                         \
+      ? (LOG(FATAL) << "Check failed: " << #x out, dummy) \
+      :
+
+// DCHECKs are debug variants of CHECKs only enabled in debug builds. Generally
+// CHECK should be used unless profiling identifies a CHECK as being in
+// performance critical code.
+#if defined(NDEBUG)
+static constexpr bool kEnableDChecks = false;
+#else
+static constexpr bool kEnableDChecks = true;
+#endif
+
+#define DCHECK(x) \
+  if (::android::base::kEnableDChecks) CHECK(x)
+#define DCHECK_EQ(x, y) \
+  if (::android::base::kEnableDChecks) CHECK_EQ(x, y)
+#define DCHECK_NE(x, y) \
+  if (::android::base::kEnableDChecks) CHECK_NE(x, y)
+#define DCHECK_LE(x, y) \
+  if (::android::base::kEnableDChecks) CHECK_LE(x, y)
+#define DCHECK_LT(x, y) \
+  if (::android::base::kEnableDChecks) CHECK_LT(x, y)
+#define DCHECK_GE(x, y) \
+  if (::android::base::kEnableDChecks) CHECK_GE(x, y)
+#define DCHECK_GT(x, y) \
+  if (::android::base::kEnableDChecks) CHECK_GT(x, y)
+#define DCHECK_STREQ(s1, s2) \
+  if (::android::base::kEnableDChecks) CHECK_STREQ(s1, s2)
+#define DCHECK_STRNE(s1, s2) \
+  if (::android::base::kEnableDChecks) CHECK_STRNE(s1, s2)
+#if defined(NDEBUG)
+#define DCHECK_CONSTEXPR(x, out, dummy)
+#else
+#define DCHECK_CONSTEXPR(x, out, dummy) CHECK_CONSTEXPR(x, out, dummy)
+#endif
+
+// Temporary class created to evaluate the LHS and RHS, used with
+// 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) {
+  }
+  LHS lhs;
+  RHS rhs;
+};
+
+// Helper function for CHECK_xx.
+template <typename LHS, typename RHS>
+static inline EagerEvaluator<LHS, RHS> MakeEagerEvaluator(LHS lhs, RHS rhs) {
+  return EagerEvaluator<LHS, RHS>(lhs, rhs);
+}
+
+// Explicitly instantiate EagerEvalue for pointers so that char*s aren't treated
+// as strings. To compare strings use CHECK_STREQ and CHECK_STRNE. We rely on
+// signed/unsigned warnings to protect you against combinations not explicitly
+// listed below.
+#define EAGER_PTR_EVALUATOR(T1, T2)               \
+  template <>                                     \
+  struct EagerEvaluator<T1, T2> {                 \
+    EagerEvaluator(T1 l, T2 r)                    \
+        : lhs(reinterpret_cast<const void*>(l)),  \
+          rhs(reinterpret_cast<const void*>(r)) { \
+    }                                             \
+    const void* lhs;                              \
+    const void* rhs;                              \
+  }
+EAGER_PTR_EVALUATOR(const char*, const char*);
+EAGER_PTR_EVALUATOR(const char*, char*);
+EAGER_PTR_EVALUATOR(char*, const char*);
+EAGER_PTR_EVALUATOR(char*, char*);
+EAGER_PTR_EVALUATOR(const unsigned char*, const unsigned char*);
+EAGER_PTR_EVALUATOR(const unsigned char*, unsigned char*);
+EAGER_PTR_EVALUATOR(unsigned char*, const unsigned char*);
+EAGER_PTR_EVALUATOR(unsigned char*, unsigned char*);
+EAGER_PTR_EVALUATOR(const signed char*, const signed char*);
+EAGER_PTR_EVALUATOR(const signed char*, signed char*);
+EAGER_PTR_EVALUATOR(signed char*, const signed char*);
+EAGER_PTR_EVALUATOR(signed char*, signed char*);
+
+// Data for the log message, not stored in LogMessage to avoid increasing the
+// stack size.
+class LogMessageData;
+
+// A LogMessage is a temporarily scoped object used by LOG and the unlikely part
+// of a CHECK. The destructor will abort if the severity is FATAL.
+class LogMessage {
+ public:
+  LogMessage(const char* file, unsigned int line, LogId id,
+             LogSeverity severity, int error);
+
+  ~LogMessage();
+
+  // Returns the stream associated with the message, the LogMessage performs
+  // output when it goes out of scope.
+  std::ostream& stream();
+
+  // The routine that performs the actual logging.
+  static void LogLine(const char* file, unsigned int line, LogId id,
+                      LogSeverity severity, const char* msg);
+
+ private:
+  const std::unique_ptr<LogMessageData> data_;
+
+  DISALLOW_COPY_AND_ASSIGN(LogMessage);
+};
+
+// Allows to temporarily change the minimum severity level for logging.
+class ScopedLogSeverity {
+ public:
+  explicit ScopedLogSeverity(LogSeverity level);
+  ~ScopedLogSeverity();
+
+ private:
+  LogSeverity old_;
+};
+
+}  // namespace base
+}  // namespace android
+
+#endif  // BASE_LOGGING_H
diff --git a/base/include/base/macros.h b/base/include/base/macros.h
new file mode 100644
index 0000000..b1ce7c6
--- /dev/null
+++ b/base/include/base/macros.h
@@ -0,0 +1,188 @@
+/*
+ * 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 UTILS_MACROS_H
+#define UTILS_MACROS_H
+
+#include <stddef.h>  // for size_t
+#include <unistd.h>  // for TEMP_FAILURE_RETRY
+
+// bionic and glibc both have TEMP_FAILURE_RETRY, but eg Mac OS' libc doesn't.
+#ifndef TEMP_FAILURE_RETRY
+#define TEMP_FAILURE_RETRY(exp)            \
+  ({                                       \
+    decltype(exp) _rc;                     \
+    do {                                   \
+      _rc = (exp);                         \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc;                                   \
+  })
+#endif
+
+// A macro to disallow the copy constructor and operator= functions
+// This must be placed in the private: declarations for a class.
+//
+// For disallowing only assign or copy, delete the relevant operator or
+// constructor, for example:
+// void operator=(const TypeName&) = delete;
+// 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.
+//
+// This should be used in the private: declarations for a class
+// that wants to prevent anyone from instantiating it. This is
+// especially useful for classes containing only static methods.
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+  TypeName();                                    \
+  DISALLOW_COPY_AND_ASSIGN(TypeName)
+
+// The arraysize(arr) macro returns the # of elements in an array arr.
+// The expression is a compile-time constant, and therefore can be
+// used in defining new arrays, for example.  If you use arraysize on
+// a pointer by mistake, you will get a compile-time error.
+//
+// One caveat is that arraysize() doesn't accept any array of an
+// anonymous type or a type defined inside a function.  In these rare
+// cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below.  This is
+// due to a limitation in C++'s template system.  The limitation might
+// eventually be removed, but it hasn't happened yet.
+
+// This template function declaration is used in defining arraysize.
+// Note that the function doesn't need an implementation, as we only
+// use its type.
+template <typename T, size_t N>
+char(&ArraySizeHelper(T(&array)[N]))[N];  // NOLINT(readability/casting)
+
+#define arraysize(array) (sizeof(ArraySizeHelper(array)))
+
+// ARRAYSIZE_UNSAFE performs essentially the same calculation as arraysize,
+// but can be used on anonymous types or types defined inside
+// functions.  It's less safe than arraysize as it accepts some
+// (although not all) pointers.  Therefore, you should use arraysize
+// whenever possible.
+//
+// The expression ARRAYSIZE_UNSAFE(a) is a compile-time constant of type
+// size_t.
+//
+// ARRAYSIZE_UNSAFE catches a few type errors.  If you see a compiler error
+//
+//   "warning: division by zero in ..."
+//
+// when using ARRAYSIZE_UNSAFE, you are (wrongfully) giving it a pointer.
+// You should only use ARRAYSIZE_UNSAFE on statically allocated arrays.
+//
+// The following comments are on the implementation details, and can
+// be ignored by the users.
+//
+// ARRAYSIZE_UNSAFE(arr) works by inspecting sizeof(arr) (the # of bytes in
+// the array) and sizeof(*(arr)) (the # of bytes in one array
+// element).  If the former is divisible by the latter, perhaps arr is
+// indeed an array, in which case the division result is the # of
+// elements in the array.  Otherwise, arr cannot possibly be an array,
+// and we generate a compiler error to prevent the code from
+// compiling.
+//
+// Since the size of bool is implementation-defined, we need to cast
+// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final
+// result has type size_t.
+//
+// This macro is not perfect as it wrongfully accepts certain
+// pointers, namely where the pointer size is divisible by the pointee
+// size.  Since all our code has to go through a 32-bit compiler,
+// where a pointer is 4 bytes, this means all pointers to a type whose
+// size is 3 or greater than 4 will be (righteously) rejected.
+#define ARRAYSIZE_UNSAFE(a)     \
+  ((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)
+
+#define WARN_UNUSED __attribute__((warn_unused_result))
+
+// A deprecated function to call to create a false use of the parameter, for
+// example:
+//   int foo(int x) { UNUSED(x); return 10; }
+// to avoid compiler warnings. Going forward we prefer ATTRIBUTE_UNUSED.
+template <typename... T>
+void UNUSED(const T&...) {
+}
+
+// An attribute to place on a parameter to a function, for example:
+//   int foo(int x ATTRIBUTE_UNUSED) { return 10; }
+// to avoid compiler warnings.
+#define ATTRIBUTE_UNUSED __attribute__((__unused__))
+
+// The FALLTHROUGH_INTENDED macro can be used to annotate implicit fall-through
+// between switch labels:
+//  switch (x) {
+//    case 40:
+//    case 41:
+//      if (truth_is_out_there) {
+//        ++x;
+//        FALLTHROUGH_INTENDED;  // Use instead of/along with annotations in
+//                               // comments.
+//      } else {
+//        return x;
+//      }
+//    case 42:
+//      ...
+//
+//  As shown in the example above, the FALLTHROUGH_INTENDED macro should be
+//  followed by a semicolon. It is designed to mimic control-flow statements
+//  like 'break;', so it can be placed in most places where 'break;' can, but
+//  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:
+//  http://clang.llvm.org/docs/LanguageExtensions.html#clang__fallthrough
+//
+//  When used with unsupported compilers, the FALLTHROUGH_INTENDED macro has no
+//  effect on diagnostics.
+//
+//  In either case this macro has no effect on runtime behavior and performance
+//  of code.
+#if defined(__clang__) && __cplusplus >= 201103L && defined(__has_warning)
+#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
+#define FALLTHROUGH_INTENDED [[clang::fallthrough]]  // NOLINT
+#endif
+#endif
+
+#ifndef FALLTHROUGH_INTENDED
+#define FALLTHROUGH_INTENDED \
+  do {                       \
+  } while (0)
+#endif
+
+#endif  // UTILS_MACROS_H
diff --git a/base/include/base/memory.h b/base/include/base/memory.h
new file mode 100644
index 0000000..882582f
--- /dev/null
+++ b/base/include/base/memory.h
@@ -0,0 +1,47 @@
+/*
+ * 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 BASE_MEMORY_H
+#define BASE_MEMORY_H
+
+namespace android {
+namespace base {
+
+// Use packed structures for access to unaligned data on targets with alignment
+// restrictions.  The compiler will generate appropriate code to access these
+// structures without generating alignment exceptions.
+template <typename T>
+static inline T get_unaligned(const T* address) {
+  struct unaligned {
+    T v;
+  } __attribute__((packed));
+  const unaligned* p = reinterpret_cast<const unaligned*>(address);
+  return p->v;
+}
+
+template <typename T>
+static inline void put_unaligned(T* address, T v) {
+  struct unaligned {
+    T v;
+  } __attribute__((packed));
+  unaligned* p = reinterpret_cast<unaligned*>(address);
+  p->v = v;
+}
+
+} // namespace base
+} // namespace android
+
+#endif // BASE_MEMORY_H
diff --git a/base/include/base/stringprintf.h b/base/include/base/stringprintf.h
new file mode 100644
index 0000000..195c1de
--- /dev/null
+++ b/base/include/base/stringprintf.h
@@ -0,0 +1,40 @@
+/*
+ * 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 BASE_STRINGPRINTF_H
+#define BASE_STRINGPRINTF_H
+
+#include <stdarg.h>
+#include <string>
+
+namespace android {
+namespace base {
+
+// Returns a string corresponding to printf-like formatting of the arguments.
+std::string StringPrintf(const char* fmt, ...)
+    __attribute__((__format__(__printf__, 1, 2)));
+
+// Appends a printf-like formatting of the arguments to 'dst'.
+void StringAppendF(std::string* dst, const char* fmt, ...)
+    __attribute__((__format__(__printf__, 2, 3)));
+
+// Appends a printf-like formatting of the arguments to 'dst'.
+void StringAppendV(std::string* dst, const char* format, va_list ap);
+
+}  // namespace base
+}  // namespace android
+
+#endif  // BASE_STRINGPRINTF_H
diff --git a/base/include/base/strings.h b/base/include/base/strings.h
new file mode 100644
index 0000000..5dbc5fb
--- /dev/null
+++ b/base/include/base/strings.h
@@ -0,0 +1,50 @@
+/*
+ * 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 BASE_STRINGS_H
+#define BASE_STRINGS_H
+
+#include <string>
+#include <vector>
+
+namespace android {
+namespace base {
+
+// Splits a string into a vector of strings.
+//
+// The string is split at each occurrence of a character in delimiters.
+//
+// The empty string is not a valid delimiter list.
+std::vector<std::string> Split(const std::string& s,
+                               const std::string& delimiters);
+
+// Trims whitespace off both ends of the given string.
+std::string Trim(const std::string& s);
+
+// Joins a vector of strings into a single string, using the given separator.
+template <typename StringT>
+std::string Join(const std::vector<StringT>& strings, char separator);
+
+// Tests whether 's' starts with 'prefix'.
+bool StartsWith(const std::string& s, const char* prefix);
+
+// Tests whether 's' ends with 'suffix'.
+bool EndsWith(const std::string& s, const char* suffix);
+
+}  // namespace base
+}  // namespace android
+
+#endif  // BASE_STRINGS_H
diff --git a/base/logging.cpp b/base/logging.cpp
new file mode 100644
index 0000000..0142b70
--- /dev/null
+++ b/base/logging.cpp
@@ -0,0 +1,304 @@
+/*
+ * 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/logging.h"
+
+#include <libgen.h>
+
+// For getprogname(3) or program_invocation_short_name.
+#if defined(__ANDROID__) || defined(__APPLE__)
+#include <stdlib.h>
+#elif defined(__GLIBC__)
+#include <errno.h>
+#endif
+
+#include <iostream>
+#include <limits>
+#include <mutex>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/strings.h"
+#include "cutils/threads.h"
+
+// Headers for LogMessage::LogLine.
+#ifdef __ANDROID__
+#include <android/set_abort_message.h>
+#include "cutils/log.h"
+#else
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+namespace android {
+namespace base {
+
+static std::mutex logging_lock;
+
+#ifdef __ANDROID__
+static LogFunction gLogger = LogdLogger();
+#else
+static LogFunction gLogger = StderrLogger;
+#endif
+
+static bool gInitialized = false;
+static LogSeverity gMinimumLogSeverity = INFO;
+static std::unique_ptr<std::string> gProgramInvocationName;
+
+#if defined(__GLIBC__)
+static const char* getprogname() {
+  return program_invocation_short_name;
+}
+#endif
+
+static const char* ProgramInvocationName() {
+  if (gProgramInvocationName == nullptr) {
+    gProgramInvocationName.reset(new std::string(getprogname()));
+  }
+
+  return gProgramInvocationName->c_str();
+}
+
+void StderrLogger(LogId, LogSeverity severity, const char*, const char* file,
+                  unsigned int line, const char* message) {
+  static const char* log_characters = "VDIWEF";
+  CHECK_EQ(strlen(log_characters), FATAL + 1U);
+  char severity_char = log_characters[severity];
+  fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationName(),
+          severity_char, getpid(), gettid(), file, line, message);
+}
+
+
+#ifdef __ANDROID__
+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) {
+  int priority = kLogSeverityToAndroidLogPriority[severity];
+  if (id == DEFAULT) {
+    id = default_log_id_;
+  }
+
+  log_id lg_id = kLogIdToAndroidLogId[id];
+
+  if (priority == ANDROID_LOG_FATAL) {
+    __android_log_buf_print(lg_id, priority, tag, "%s:%u] %s", file, line,
+                            message);
+  } else {
+    __android_log_buf_print(lg_id, priority, tag, "%s", message);
+  }
+}
+#endif
+
+void InitLogging(char* argv[], LogFunction&& logger) {
+  SetLogger(std::forward<LogFunction>(logger));
+  InitLogging(argv);
+}
+
+void InitLogging(char* argv[]) {
+  if (gInitialized) {
+    return;
+  }
+
+  gInitialized = true;
+
+  // Stash the command line for later use. We can use /proc/self/cmdline on
+  // Linux to recover this, but we don't have that luxury on the Mac, and there
+  // are a couple of argv[0] variants that are commonly used.
+  if (argv != nullptr) {
+    gProgramInvocationName.reset(new std::string(basename(argv[0])));
+  }
+
+  const char* tags = getenv("ANDROID_LOG_TAGS");
+  if (tags == nullptr) {
+    return;
+  }
+
+  std::vector<std::string> specs = Split(tags, " ");
+  for (size_t i = 0; i < specs.size(); ++i) {
+    // "tag-pattern:[vdiwefs]"
+    std::string spec(specs[i]);
+    if (spec.size() == 3 && StartsWith(spec, "*:")) {
+      switch (spec[2]) {
+        case 'v':
+          gMinimumLogSeverity = VERBOSE;
+          continue;
+        case 'd':
+          gMinimumLogSeverity = DEBUG;
+          continue;
+        case 'i':
+          gMinimumLogSeverity = INFO;
+          continue;
+        case 'w':
+          gMinimumLogSeverity = WARNING;
+          continue;
+        case 'e':
+          gMinimumLogSeverity = ERROR;
+          continue;
+        case 'f':
+          gMinimumLogSeverity = FATAL;
+          continue;
+        // liblog will even suppress FATAL if you say 's' for silent, but that's
+        // crazy!
+        case 's':
+          gMinimumLogSeverity = FATAL;
+          continue;
+      }
+    }
+    LOG(FATAL) << "unsupported '" << spec << "' in ANDROID_LOG_TAGS (" << tags
+               << ")";
+  }
+}
+
+void SetLogger(LogFunction&& logger) {
+  std::lock_guard<std::mutex> lock(logging_lock);
+  gLogger = std::move(logger);
+}
+
+// This indirection greatly reduces the stack impact of having lots of
+// checks/logging in a function.
+class LogMessageData {
+ public:
+  LogMessageData(const char* file, unsigned int line, LogId id,
+                 LogSeverity severity, int error)
+      : file_(file),
+        line_number_(line),
+        id_(id),
+        severity_(severity),
+        error_(error) {
+    const char* last_slash = strrchr(file, '/');
+    file = (last_slash == nullptr) ? file : last_slash + 1;
+  }
+
+  const char* GetFile() const {
+    return file_;
+  }
+
+  unsigned int GetLineNumber() const {
+    return line_number_;
+  }
+
+  LogSeverity GetSeverity() const {
+    return severity_;
+  }
+
+  LogId GetId() const {
+    return id_;
+  }
+
+  int GetError() const {
+    return error_;
+  }
+
+  std::ostream& GetBuffer() {
+    return buffer_;
+  }
+
+  std::string ToString() const {
+    return buffer_.str();
+  }
+
+ private:
+  std::ostringstream buffer_;
+  const char* const file_;
+  const unsigned int line_number_;
+  const LogId id_;
+  const LogSeverity severity_;
+  const int error_;
+
+  DISALLOW_COPY_AND_ASSIGN(LogMessageData);
+};
+
+LogMessage::LogMessage(const char* file, unsigned int line, LogId id,
+                       LogSeverity severity, int error)
+    : data_(new LogMessageData(file, line, id, severity, error)) {
+}
+
+LogMessage::~LogMessage() {
+  if (data_->GetSeverity() < gMinimumLogSeverity) {
+    return;  // No need to format something we're not going to output.
+  }
+
+  // Finish constructing the message.
+  if (data_->GetError() != -1) {
+    data_->GetBuffer() << ": " << strerror(data_->GetError());
+  }
+  std::string msg(data_->ToString());
+
+  if (msg.find('\n') == std::string::npos) {
+    LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(),
+            data_->GetSeverity(), msg.c_str());
+  } else {
+    msg += '\n';
+    size_t i = 0;
+    while (i < msg.size()) {
+      size_t nl = msg.find('\n', i);
+      msg[nl] = '\0';
+      LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(),
+              data_->GetSeverity(), &msg[i]);
+      i = nl + 1;
+    }
+  }
+
+  // Abort if necessary.
+  if (data_->GetSeverity() == FATAL) {
+#ifdef __ANDROID__
+    android_set_abort_message(msg.c_str());
+#endif
+    abort();
+  }
+}
+
+std::ostream& LogMessage::stream() {
+  return data_->GetBuffer();
+}
+
+void LogMessage::LogLine(const char* file, unsigned int line, LogId id,
+                         LogSeverity severity, const char* message) {
+  const char* tag = ProgramInvocationName();
+  std::lock_guard<std::mutex> lock(logging_lock);
+  gLogger(id, severity, tag, file, line, message);
+}
+
+ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) {
+  old_ = gMinimumLogSeverity;
+  gMinimumLogSeverity = level;
+}
+
+ScopedLogSeverity::~ScopedLogSeverity() {
+  gMinimumLogSeverity = old_;
+}
+
+}  // namespace base
+}  // namespace android
diff --git a/base/logging_test.cpp b/base/logging_test.cpp
new file mode 100644
index 0000000..d947c1d
--- /dev/null
+++ b/base/logging_test.cpp
@@ -0,0 +1,171 @@
+/*
+ * 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/logging.h"
+
+#include <regex>
+#include <string>
+
+#include "base/file.h"
+#include "base/stringprintf.h"
+#include "test_utils.h"
+
+#include <gtest/gtest.h>
+
+#ifdef __ANDROID__
+#define HOST_TEST(suite, name) TEST(suite, DISABLED_ ## name)
+#else
+#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() {
+    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_));
+  }
+
+  TemporaryFile temp_file_;
+  int old_stderr_;
+};
+
+TEST(logging, CHECK) {
+  ASSERT_DEATH(CHECK(false), "Check failed: false ");
+  CHECK(true);
+
+  ASSERT_DEATH(CHECK_EQ(0, 1), "Check failed: 0 == 1 ");
+  CHECK_EQ(0, 0);
+
+  ASSERT_DEATH(CHECK_STREQ("foo", "bar"), R"(Check failed: "foo" == "bar")");
+  CHECK_STREQ("foo", "foo");
+}
+
+std::string make_log_pattern(android::base::LogSeverity severity,
+                             const char* message) {
+  static const char* log_characters = "VDIWEF";
+  char log_char = log_characters[severity];
+  return android::base::StringPrintf(
+      "%c[[:space:]]+[[:digit:]]+[[:space:]]+[[:digit:]]+ " __FILE__
+      ":[[:digit:]]+] %s",
+      log_char, message);
+}
+
+TEST(logging, LOG) {
+  ASSERT_DEATH(LOG(FATAL) << "foobar", "foobar");
+
+  {
+    CapturedStderr cap;
+    LOG(WARNING) << "foobar";
+    ASSERT_EQ(0, lseek(cap.fd(), SEEK_SET, 0));
+
+    std::string output;
+    android::base::ReadFdToString(cap.fd(), &output);
+
+    std::regex message_regex(
+        make_log_pattern(android::base::WARNING, "foobar"));
+    ASSERT_TRUE(std::regex_search(output, message_regex));
+  }
+
+  {
+    CapturedStderr cap;
+    LOG(INFO) << "foobar";
+    ASSERT_EQ(0, lseek(cap.fd(), SEEK_SET, 0));
+
+    std::string output;
+    android::base::ReadFdToString(cap.fd(), &output);
+
+    std::regex message_regex(
+        make_log_pattern(android::base::INFO, "foobar"));
+    ASSERT_TRUE(std::regex_search(output, message_regex));
+  }
+
+  {
+    CapturedStderr cap;
+    LOG(DEBUG) << "foobar";
+    ASSERT_EQ(0, lseek(cap.fd(), SEEK_SET, 0));
+
+    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(), SEEK_SET, 0));
+
+    std::string output;
+    android::base::ReadFdToString(cap.fd(), &output);
+
+    std::regex message_regex(
+        make_log_pattern(android::base::DEBUG, "foobar"));
+    ASSERT_TRUE(std::regex_search(output, message_regex));
+  }
+}
+
+TEST(logging, PLOG) {
+  {
+    CapturedStderr cap;
+    errno = ENOENT;
+    PLOG(INFO) << "foobar";
+    ASSERT_EQ(0, lseek(cap.fd(), SEEK_SET, 0));
+
+    std::string output;
+    android::base::ReadFdToString(cap.fd(), &output);
+
+    std::regex message_regex(make_log_pattern(
+        android::base::INFO, "foobar: No such file or directory"));
+    ASSERT_TRUE(std::regex_search(output, message_regex));
+  }
+}
+
+TEST(logging, UNIMPLEMENTED) {
+  {
+    CapturedStderr cap;
+    errno = ENOENT;
+    UNIMPLEMENTED(ERROR);
+    ASSERT_EQ(0, lseek(cap.fd(), SEEK_SET, 0));
+
+    std::string output;
+    android::base::ReadFdToString(cap.fd(), &output);
+
+    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));
+  }
+}
diff --git a/base/stringprintf.cpp b/base/stringprintf.cpp
new file mode 100644
index 0000000..d55ff52
--- /dev/null
+++ b/base/stringprintf.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 "base/stringprintf.h"
+
+#include <stdio.h>
+
+#include <string>
+
+namespace android {
+namespace base {
+
+void StringAppendV(std::string* dst, const char* format, va_list ap) {
+  // First try with a small fixed size buffer
+  char space[1024];
+
+  // It's possible for methods that use a va_list to invalidate
+  // the data in it upon use.  The fix is to make a copy
+  // of the structure before using it and use that copy instead.
+  va_list backup_ap;
+  va_copy(backup_ap, ap);
+  int result = vsnprintf(space, sizeof(space), format, backup_ap);
+  va_end(backup_ap);
+
+  if (result < static_cast<int>(sizeof(space))) {
+    if (result >= 0) {
+      // Normal case -- everything fit.
+      dst->append(space, result);
+      return;
+    }
+
+    if (result < 0) {
+      // Just an error.
+      return;
+    }
+  }
+
+  // Increase the buffer size to the size requested by vsnprintf,
+  // plus one for the closing \0.
+  int length = result + 1;
+  char* buf = new char[length];
+
+  // Restore the va_list before we use it again
+  va_copy(backup_ap, ap);
+  result = vsnprintf(buf, length, format, backup_ap);
+  va_end(backup_ap);
+
+  if (result >= 0 && result < length) {
+    // It fit
+    dst->append(buf, result);
+  }
+  delete[] buf;
+}
+
+std::string StringPrintf(const char* fmt, ...) {
+  va_list ap;
+  va_start(ap, fmt);
+  std::string result;
+  StringAppendV(&result, fmt, ap);
+  va_end(ap);
+  return result;
+}
+
+void StringAppendF(std::string* dst, const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  StringAppendV(dst, format, ap);
+  va_end(ap);
+}
+
+}  // namespace base
+}  // namespace android
diff --git a/base/stringprintf_test.cpp b/base/stringprintf_test.cpp
new file mode 100644
index 0000000..5cc2086
--- /dev/null
+++ b/base/stringprintf_test.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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 "base/stringprintf.h"
+
+#include <gtest/gtest.h>
+
+#include <string>
+
+TEST(StringPrintfTest, HexSizeT) {
+  size_t size = 0x00107e59;
+  EXPECT_EQ("00107e59", android::base::StringPrintf("%08zx", size));
+  EXPECT_EQ("0x00107e59", android::base::StringPrintf("0x%08zx", size));
+}
+
+TEST(StringPrintfTest, StringAppendF) {
+  std::string s("a");
+  android::base::StringAppendF(&s, "b");
+  EXPECT_EQ("ab", s);
+}
+
+TEST(StringPrintfTest, Errno) {
+  errno = 123;
+  android::base::StringPrintf("hello %s", "world");
+  EXPECT_EQ(123, errno);
+}
+
+void TestN(size_t n) {
+  char* buf = new char[n + 1];
+  memset(buf, 'x', n);
+  buf[n] = '\0';
+  std::string s(android::base::StringPrintf("%s", buf));
+  EXPECT_EQ(buf, s);
+  delete[] buf;
+}
+
+TEST(StringPrintfTest, At1023) {
+  TestN(1023);
+}
+
+TEST(StringPrintfTest, At1024) {
+  TestN(1024);
+}
+
+TEST(StringPrintfTest, At1025) {
+  TestN(1025);
+}
diff --git a/base/strings.cpp b/base/strings.cpp
new file mode 100644
index 0000000..d3375d9
--- /dev/null
+++ b/base/strings.cpp
@@ -0,0 +1,117 @@
+/*
+ * 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/strings.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <string>
+#include <vector>
+
+namespace android {
+namespace base {
+
+#define CHECK_NE(a, b) \
+  if ((a) == (b)) abort();
+
+std::vector<std::string> Split(const std::string& s,
+                               const std::string& delimiters) {
+  CHECK_NE(delimiters.size(), 0U);
+
+  std::vector<std::string> result;
+
+  size_t base = 0;
+  size_t found;
+  do {
+    found = s.find_first_of(delimiters, base);
+    result.push_back(s.substr(base, found - base));
+    base = found + 1;
+  } while (found != s.npos);
+
+  return result;
+}
+
+std::string Trim(const std::string& s) {
+  std::string result;
+
+  if (s.size() == 0) {
+    return result;
+  }
+
+  size_t start_index = 0;
+  size_t end_index = s.size() - 1;
+
+  // Skip initial whitespace.
+  while (start_index < s.size()) {
+    if (!isspace(s[start_index])) {
+      break;
+    }
+    start_index++;
+  }
+
+  // Skip terminating whitespace.
+  while (end_index >= start_index) {
+    if (!isspace(s[end_index])) {
+      break;
+    }
+    end_index--;
+  }
+
+  // All spaces, no beef.
+  if (end_index < start_index) {
+    return "";
+  }
+  // Start_index is the first non-space, end_index is the last one.
+  return s.substr(start_index, end_index - start_index + 1);
+}
+
+template <typename StringT>
+std::string Join(const std::vector<StringT>& strings, char separator) {
+  if (strings.empty()) {
+    return "";
+  }
+
+  std::string result(strings[0]);
+  for (size_t i = 1; i < strings.size(); ++i) {
+    result += separator;
+    result += strings[i];
+  }
+  return result;
+}
+
+// Explicit instantiations.
+template std::string Join<std::string>(const std::vector<std::string>& strings,
+                                       char separator);
+template std::string Join<const char*>(const std::vector<const char*>& strings,
+                                       char separator);
+
+bool StartsWith(const std::string& s, const char* prefix) {
+  return s.compare(0, strlen(prefix), prefix) == 0;
+}
+
+bool EndsWith(const std::string& s, const char* suffix) {
+  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;
+}
+
+}  // namespace base
+}  // namespace android
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
new file mode 100644
index 0000000..46a1ab5
--- /dev/null
+++ b/base/strings_test.cpp
@@ -0,0 +1,164 @@
+/*
+ * 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/strings.h"
+
+#include <gtest/gtest.h>
+
+#include <string>
+#include <vector>
+
+TEST(strings, split_empty) {
+  std::vector<std::string> parts = android::base::Split("", ",");
+  ASSERT_EQ(1U, parts.size());
+  ASSERT_EQ("", parts[0]);
+}
+
+TEST(strings, split_single) {
+  std::vector<std::string> parts = android::base::Split("foo", ",");
+  ASSERT_EQ(1U, parts.size());
+  ASSERT_EQ("foo", parts[0]);
+}
+
+TEST(strings, split_simple) {
+  std::vector<std::string> parts = android::base::Split("foo,bar,baz", ",");
+  ASSERT_EQ(3U, parts.size());
+  ASSERT_EQ("foo", parts[0]);
+  ASSERT_EQ("bar", parts[1]);
+  ASSERT_EQ("baz", parts[2]);
+}
+
+TEST(strings, split_with_empty_part) {
+  std::vector<std::string> parts = android::base::Split("foo,,bar", ",");
+  ASSERT_EQ(3U, parts.size());
+  ASSERT_EQ("foo", parts[0]);
+  ASSERT_EQ("", parts[1]);
+  ASSERT_EQ("bar", parts[2]);
+}
+
+TEST(strings, split_null_char) {
+  std::vector<std::string> parts =
+      android::base::Split(std::string("foo\0bar", 7), std::string("\0", 1));
+  ASSERT_EQ(2U, parts.size());
+  ASSERT_EQ("foo", parts[0]);
+  ASSERT_EQ("bar", parts[1]);
+}
+
+TEST(strings, split_any) {
+  std::vector<std::string> parts = android::base::Split("foo:bar,baz", ",:");
+  ASSERT_EQ(3U, parts.size());
+  ASSERT_EQ("foo", parts[0]);
+  ASSERT_EQ("bar", parts[1]);
+  ASSERT_EQ("baz", parts[2]);
+}
+
+TEST(strings, split_any_with_empty_part) {
+  std::vector<std::string> parts = android::base::Split("foo:,bar", ",:");
+  ASSERT_EQ(3U, parts.size());
+  ASSERT_EQ("foo", parts[0]);
+  ASSERT_EQ("", parts[1]);
+  ASSERT_EQ("bar", parts[2]);
+}
+
+TEST(strings, trim_empty) {
+  ASSERT_EQ("", android::base::Trim(""));
+}
+
+TEST(strings, trim_already_trimmed) {
+  ASSERT_EQ("foo", android::base::Trim("foo"));
+}
+
+TEST(strings, trim_left) {
+  ASSERT_EQ("foo", android::base::Trim(" foo"));
+}
+
+TEST(strings, trim_right) {
+  ASSERT_EQ("foo", android::base::Trim("foo "));
+}
+
+TEST(strings, trim_both) {
+  ASSERT_EQ("foo", android::base::Trim(" foo "));
+}
+
+TEST(strings, trim_no_trim_middle) {
+  ASSERT_EQ("foo bar", android::base::Trim("foo bar"));
+}
+
+TEST(strings, trim_other_whitespace) {
+  ASSERT_EQ("foo", android::base::Trim("\v\tfoo\n\f"));
+}
+
+TEST(strings, join_nothing) {
+  std::vector<std::string> list = {};
+  ASSERT_EQ("", android::base::Join(list, ','));
+}
+
+TEST(strings, join_single) {
+  std::vector<std::string> list = {"foo"};
+  ASSERT_EQ("foo", android::base::Join(list, ','));
+}
+
+TEST(strings, join_simple) {
+  std::vector<std::string> list = {"foo", "bar", "baz"};
+  ASSERT_EQ("foo,bar,baz", android::base::Join(list, ','));
+}
+
+TEST(strings, join_separator_in_vector) {
+  std::vector<std::string> list = {",", ","};
+  ASSERT_EQ(",,,", android::base::Join(list, ','));
+}
+
+TEST(strings, startswith_empty) {
+  ASSERT_FALSE(android::base::StartsWith("", "foo"));
+  ASSERT_TRUE(android::base::StartsWith("", ""));
+}
+
+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) {
+  ASSERT_FALSE(android::base::StartsWith("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) {
+  ASSERT_FALSE(android::base::EndsWith("", "foo"));
+  ASSERT_TRUE(android::base::EndsWith("", ""));
+}
+
+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) {
+  ASSERT_FALSE(android::base::EndsWith("foo", "foobar"));
+}
+
+TEST(strings, endswith_contains_prefix) {
+  ASSERT_FALSE(android::base::EndsWith("foobar", "oba"));
+  ASSERT_FALSE(android::base::EndsWith("foobar", "foo"));
+}
diff --git a/adb/usb_vendors.h b/base/test_main.cpp
similarity index 66%
copy from adb/usb_vendors.h
copy to base/test_main.cpp
index cee23a1..546923d 100644
--- a/adb/usb_vendors.h
+++ b/base/test_main.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 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.
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-#ifndef __USB_VENDORS_H
-#define __USB_VENDORS_H
+#include <gtest/gtest.h>
 
-extern int vendorIds[];
-extern unsigned  vendorIdCount;
+#include "base/logging.h"
 
-void usb_vendors_init(void);
-
-#endif
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  android::base::InitLogging(argv, android::base::StderrLogger);
+  return RUN_ALL_TESTS();
+}
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
new file mode 100644
index 0000000..1f6d3cf
--- /dev/null
+++ b/base/test_utils.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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 "test_utils.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+TemporaryFile::TemporaryFile() {
+  init("/data/local/tmp");
+  if (fd == -1) {
+    init("/tmp");
+  }
+}
+
+TemporaryFile::~TemporaryFile() {
+  close(fd);
+  unlink(filename);
+}
+
+void TemporaryFile::init(const char* tmp_dir) {
+  snprintf(filename, sizeof(filename), "%s/TemporaryFile-XXXXXX", tmp_dir);
+  fd = mkstemp(filename);
+}
diff --git a/adb/usb_vendors.h b/base/test_utils.h
similarity index 67%
copy from adb/usb_vendors.h
copy to base/test_utils.h
index cee23a1..132d3a7 100644
--- a/adb/usb_vendors.h
+++ b/base/test_utils.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 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.
@@ -14,12 +14,19 @@
  * limitations under the License.
  */
 
-#ifndef __USB_VENDORS_H
-#define __USB_VENDORS_H
+#ifndef TEST_UTILS_H
+#define TEST_UTILS_H
 
-extern int vendorIds[];
-extern unsigned  vendorIdCount;
+class TemporaryFile {
+ public:
+  TemporaryFile();
+  ~TemporaryFile();
 
-void usb_vendors_init(void);
+  int fd;
+  char filename[1024];
 
-#endif
+ private:
+  void init(const char* tmp_dir);
+};
+
+#endif // TEST_UTILS_H
diff --git a/cpio/Android.mk b/cpio/Android.mk
index 575beb2..2aa7297 100644
--- a/cpio/Android.mk
+++ b/cpio/Android.mk
@@ -10,6 +10,8 @@
 
 LOCAL_CFLAGS := -Werror
 
+LOCAL_SHARED_LIBRARIES := libcutils
+
 include $(BUILD_HOST_EXECUTABLE)
 
 $(call dist-for-goals,dist_files,$(LOCAL_BUILT_MODULE))
diff --git a/cpio/mkbootfs.c b/cpio/mkbootfs.c
index 7175749..0e35323 100644
--- a/cpio/mkbootfs.c
+++ b/cpio/mkbootfs.c
@@ -41,6 +41,7 @@
 };
 
 static struct fs_config_entry* canned_config = NULL;
+static char *target_out_path = NULL;
 
 /* Each line in the canned file should be a path plus three ints (uid,
  * gid, mode). */
@@ -79,7 +80,8 @@
     } else {
         // Use the compiled-in fs_config() function.
         unsigned st_mode = s->st_mode;
-        fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &st_mode, &capabilities);
+        fs_config(path, S_ISDIR(s->st_mode), target_out_path,
+                       &s->st_uid, &s->st_gid, &st_mode, &capabilities);
         s->st_mode = (typeof(s->st_mode)) st_mode;
     }
 }
@@ -328,6 +330,12 @@
     argc--;
     argv++;
 
+    if (argc > 1 && strcmp(argv[0], "-d") == 0) {
+        target_out_path = argv[1];
+        argc -= 2;
+        argv += 2;
+    }
+
     if (argc > 1 && strcmp(argv[0], "-f") == 0) {
         read_canned_config(argv[1]);
         argc -= 2;
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index c33b263..6cfb541 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -1,10 +1,19 @@
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
+
+common_cppflags := \
+    -std=gnu++11 \
+    -W \
+    -Wall \
+    -Wextra \
+    -Wunused \
+    -Werror \
 
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
     backtrace.cpp \
     debuggerd.cpp \
+    elf_utils.cpp \
     getevent.cpp \
     tombstone.cpp \
     utility.cpp \
@@ -12,29 +21,29 @@
 LOCAL_SRC_FILES_arm    := arm/machine.cpp
 LOCAL_SRC_FILES_arm64  := arm64/machine.cpp
 LOCAL_SRC_FILES_mips   := mips/machine.cpp
-LOCAL_SRC_FILES_mips64 := mips/machine.cpp
+LOCAL_SRC_FILES_mips64 := mips64/machine.cpp
 LOCAL_SRC_FILES_x86    := x86/machine.cpp
 LOCAL_SRC_FILES_x86_64 := x86_64/machine.cpp
 
-LOCAL_CPPFLAGS := \
-    -std=gnu++11 \
-    -W -Wall -Wextra \
-    -Wunused \
-    -Werror \
+LOCAL_CPPFLAGS := $(common_cppflags)
+
+ifeq ($(TARGET_IS_64_BIT),true)
+LOCAL_CPPFLAGS += -DTARGET_IS_64_BIT
+endif
 
 LOCAL_SHARED_LIBRARIES := \
     libbacktrace \
+    libbase \
     libcutils \
     liblog \
     libselinux \
 
-include external/stlport/libstlport.mk
+LOCAL_CLANG := true
 
 LOCAL_MODULE := debuggerd
 LOCAL_MODULE_STEM_32 := debuggerd
 LOCAL_MODULE_STEM_64 := debuggerd64
 LOCAL_MULTILIB := both
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 
 include $(BUILD_EXECUTABLE)
 
@@ -45,7 +54,7 @@
 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 := 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)
@@ -65,3 +74,56 @@
 LOCAL_MULTILIB := both
 
 include $(BUILD_EXECUTABLE)
+
+debuggerd_test_src_files := \
+    utility.cpp \
+    test/dump_maps_test.cpp \
+    test/dump_memory_test.cpp \
+    test/elf_fake.cpp \
+    test/log_fake.cpp \
+    test/property_fake.cpp \
+    test/ptrace_fake.cpp \
+    test/selinux_fake.cpp \
+
+debuggerd_shared_libraries := \
+    libbacktrace \
+    libbase \
+    libcutils \
+
+debuggerd_c_includes := \
+    $(LOCAL_PATH)/test \
+
+debuggerd_cpp_flags := \
+    $(common_cppflags) \
+    -Wno-missing-field-initializers \
+
+# Only build the host tests on linux.
+ifeq ($(HOST_OS),linux)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := debuggerd_test
+LOCAL_SRC_FILES := $(debuggerd_test_src_files)
+LOCAL_SHARED_LIBRARIES := $(debuggerd_shared_libraries)
+LOCAL_C_INCLUDES := $(debuggerd_c_includes)
+LOCAL_CPPFLAGS := $(debuggerd_cpp_flags)
+
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+LOCAL_MULTILIB := both
+include $(BUILD_HOST_NATIVE_TEST)
+
+endif
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := debuggerd_test
+LOCAL_SRC_FILES := $(debuggerd_test_src_files)
+LOCAL_SHARED_LIBRARIES := $(debuggerd_shared_libraries)
+LOCAL_C_INCLUDES := $(debuggerd_c_includes)
+LOCAL_CPPFLAGS := $(debuggerd_cpp_flags)
+
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+LOCAL_MULTILIB := both
+include $(BUILD_NATIVE_TEST)
diff --git a/debuggerd/arm/machine.cpp b/debuggerd/arm/machine.cpp
index 50e78c5..b7d6997 100644
--- a/debuggerd/arm/machine.cpp
+++ b/debuggerd/arm/machine.cpp
@@ -16,53 +16,39 @@
  */
 
 #include <errno.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
+#include <stdint.h>
 #include <string.h>
 #include <sys/ptrace.h>
-#include <sys/types.h>
-#include <sys/user.h>
 
-#include "../utility.h"
-#include "../machine.h"
+#include <backtrace/Backtrace.h>
 
-void dump_memory_and_code(log_t* log, pid_t tid) {
+#include "machine.h"
+#include "utility.h"
+
+void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
   pt_regs regs;
-  if (ptrace(PTRACE_GETREGS, tid, 0, &regs)) {
+  if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &regs)) {
+    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
     return;
   }
 
-  static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";
+  static const char reg_names[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";
 
   for (int reg = 0; reg < 14; reg++) {
-    // this may not be a valid way to access, but it'll do for now
-    uintptr_t addr = regs.uregs[reg];
-
-    // Don't bother if it looks like a small int or ~= null, or if
-    // it's in the kernel area.
-    if (addr < 4096 || addr >= 0xc0000000) {
-      continue;
-    }
-
-    _LOG(log, logtype::MEMORY, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
-    dump_memory(log, tid, addr);
+    dump_memory(log, backtrace, regs.uregs[reg], "memory near %.2s:", &reg_names[reg * 2]);
   }
 
-  // explicitly allow upload of code dump logging
-  _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
-  dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_pc));
+  dump_memory(log, backtrace, static_cast<uintptr_t>(regs.ARM_pc), "code around pc:");
 
   if (regs.ARM_pc != regs.ARM_lr) {
-    _LOG(log, logtype::MEMORY, "\ncode around lr:\n");
-    dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_lr));
+    dump_memory(log, backtrace, static_cast<uintptr_t>(regs.ARM_lr), "code around lr:");
   }
 }
 
 void dump_registers(log_t* log, pid_t tid) {
   pt_regs r;
   if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
-    _LOG(log, logtype::REGISTERS, "cannot get registers: %s\n", strerror(errno));
+    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
     return;
   }
 
@@ -82,7 +68,7 @@
 
   user_vfp vfp_regs;
   if (ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) {
-    _LOG(log, logtype::FP_REGISTERS, "cannot get FP registers: %s\n", strerror(errno));
+    _LOG(log, logtype::ERROR, "cannot get FP registers: %s\n", strerror(errno));
     return;
   }
 
diff --git a/debuggerd/arm64/machine.cpp b/debuggerd/arm64/machine.cpp
index 8b17d53..2e097da 100644
--- a/debuggerd/arm64/machine.cpp
+++ b/debuggerd/arm64/machine.cpp
@@ -17,50 +17,37 @@
 
 #include <elf.h>
 #include <errno.h>
-#include <inttypes.h>
+#include <stdint.h>
 #include <string.h>
-#include <sys/types.h>
 #include <sys/ptrace.h>
-#include <sys/user.h>
 #include <sys/uio.h>
 
-#include "../utility.h"
-#include "../machine.h"
+#include <backtrace/Backtrace.h>
 
-void dump_memory_and_code(log_t* log, pid_t tid) {
-    struct user_pt_regs regs;
-    struct iovec io;
-    io.iov_base = &regs;
-    io.iov_len = sizeof(regs);
+#include "machine.h"
+#include "utility.h"
 
-    if (ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, &io) == -1) {
-        _LOG(log, logtype::ERROR, "%s: ptrace failed to get registers: %s\n",
-             __func__, strerror(errno));
-        return;
-    }
+void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
+  struct user_pt_regs regs;
+  struct iovec io;
+  io.iov_base = &regs;
+  io.iov_len = sizeof(regs);
 
-    for (int reg = 0; reg < 31; reg++) {
-        uintptr_t addr = regs.regs[reg];
+  if (ptrace(PTRACE_GETREGSET, backtrace->Tid(), reinterpret_cast<void*>(NT_PRSTATUS), &io) == -1) {
+    _LOG(log, logtype::ERROR, "%s: ptrace failed to get registers: %s",
+         __func__, strerror(errno));
+    return;
+  }
 
-        /*
-         * Don't bother if it looks like a small int or ~= null, or if
-         * it's in the kernel area.
-         */
-        if (addr < 4096 || addr >= (1UL<<63)) {
-            continue;
-        }
+  for (int reg = 0; reg < 31; reg++) {
+    dump_memory(log, backtrace, regs.regs[reg], "memory near x%d:", reg);
+  }
 
-        _LOG(log, logtype::MEMORY, "\nmemory near x%d:\n", reg);
-        dump_memory(log, tid, addr);
-    }
+  dump_memory(log, backtrace, static_cast<uintptr_t>(regs.pc), "code around pc:");
 
-    _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
-    dump_memory(log, tid, (uintptr_t)regs.pc);
-
-    if (regs.pc != regs.sp) {
-        _LOG(log, logtype::MEMORY, "\ncode around sp:\n");
-        dump_memory(log, tid, (uintptr_t)regs.sp);
-    }
+  if (regs.pc != regs.sp) {
+    dump_memory(log, backtrace, static_cast<uintptr_t>(regs.sp), "code around sp:");
+  }
 }
 
 void dump_registers(log_t* log, pid_t tid) {
diff --git a/debuggerd/backtrace.cpp b/debuggerd/backtrace.cpp
index 71f44aa..ad6a6ee 100644
--- a/debuggerd/backtrace.cpp
+++ b/debuggerd/backtrace.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "DEBUG"
+
 #include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
@@ -26,8 +28,11 @@
 #include <sys/types.h>
 #include <sys/ptrace.h>
 
+#include <memory>
+
 #include <backtrace/Backtrace.h>
-#include <UniquePtr.h>
+
+#include <log/log.h>
 
 #include "backtrace.h"
 
@@ -92,9 +97,11 @@
     return;
   }
 
-  UniquePtr<Backtrace> backtrace(Backtrace::Create(tid, BACKTRACE_CURRENT_THREAD));
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(tid, BACKTRACE_CURRENT_THREAD));
   if (backtrace->Unwind(0)) {
     dump_backtrace_to_log(backtrace.get(), log, "  ");
+  } else {
+    ALOGE("Unwind failed: tid = %d", tid);
   }
 
   if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
diff --git a/debuggerd/crasher.c b/debuggerd/crasher.c
index d315ee5..af86fe9 100644
--- a/debuggerd/crasher.c
+++ b/debuggerd/crasher.c
@@ -32,16 +32,23 @@
     }
 }
 
-static int smash_stack(int i __unused) {
+static char* smash_stack_dummy_buf;
+__attribute__ ((noinline)) static void smash_stack_dummy_function(volatile int* plen) {
+  smash_stack_dummy_buf[*plen] = 0;
+}
+
+// This must be marked with "__attribute__ ((noinline))", to ensure the
+// compiler generates the proper stack guards around this function.
+// 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");
-    // Unless there's a "big enough" buffer on the stack, gcc
-    // doesn't bother inserting checks.
-    char buf[8];
-    // If we don't write something relatively unpredictable
-    // into the buffer and then do something with it, gcc
-    // optimizes everything away and just returns a constant.
-    *(int*)(&buf[7]) = (uintptr_t) &buf[0];
-    return *(int*)(&buf[0]);
+
+    char buf[128];
+    smash_stack_dummy_buf = buf;
+    // This should corrupt stack guards and make process abort.
+    smash_stack_dummy_function(plen);
+    return 0;
 }
 
 static void* global = 0; // So GCC doesn't optimize the tail recursion out of overflow_stack.
@@ -59,7 +66,7 @@
     for(;;) {
         usleep(250*1000);
         write(2, &c, 1);
-        if(c == 'C') *((unsigned*) 0) = 42;
+        if(c == 'C') *((volatile unsigned*) 0) = 42;
     }
     return NULL;
 }
@@ -125,7 +132,8 @@
     } else if (!strcmp(arg, "SIGSEGV-non-null")) {
         sigsegv_non_null();
     } else if (!strcmp(arg, "smash-stack")) {
-        return smash_stack(42);
+        volatile int len = 128;
+        return smash_stack(&len);
     } else if (!strcmp(arg, "stack-overflow")) {
         overflow_stack(NULL);
     } else if (!strcmp(arg, "nostack")) {
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 7be64f1..62d7e0e 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -30,6 +30,8 @@
 #include <sys/stat.h>
 #include <sys/poll.h>
 
+#include <selinux/android.h>
+
 #include <log/logger.h>
 
 #include <cutils/sockets.h>
@@ -45,6 +47,14 @@
 #include "tombstone.h"
 #include "utility.h"
 
+// If the 32 bit executable is compiled on a 64 bit system,
+// use the 32 bit socket name.
+#if defined(TARGET_IS_64_BIT) && !defined(__LP64__)
+#define SOCKET_NAME DEBUGGER32_SOCKET_NAME
+#else
+#define SOCKET_NAME DEBUGGER_SOCKET_NAME
+#endif
+
 struct debugger_request_t {
   debugger_action_t action;
   pid_t pid, tid;
@@ -124,6 +134,53 @@
   return fields == 7 ? 0 : -1;
 }
 
+static int selinux_enabled;
+
+/*
+ * Corresponds with debugger_action_t enum type in
+ * include/cutils/debugger.h.
+ */
+static const char *debuggerd_perms[] = {
+  NULL, /* crash is only used on self, no check applied */
+  "dump_tombstone",
+  "dump_backtrace"
+};
+
+static bool selinux_action_allowed(int s, pid_t tid, debugger_action_t action)
+{
+  char *scon = NULL, *tcon = NULL;
+  const char *tclass = "debuggerd";
+  const char *perm;
+  bool allowed = false;
+
+  if (selinux_enabled <= 0)
+    return true;
+
+  if (action <= 0 || action >= (sizeof(debuggerd_perms)/sizeof(debuggerd_perms[0]))) {
+    ALOGE("SELinux:  No permission defined for debugger action %d", action);
+    return false;
+  }
+
+  perm = debuggerd_perms[action];
+
+  if (getpeercon(s, &scon) < 0) {
+    ALOGE("Cannot get peer context from socket\n");
+    goto out;
+  }
+
+  if (getpidcon(tid, &tcon) < 0) {
+    ALOGE("Cannot get context for tid %d\n", tid);
+    goto out;
+  }
+
+  allowed = (selinux_check_access(scon, tcon, tclass, perm, NULL) == 0);
+
+out:
+   freecon(scon);
+   freecon(tcon);
+   return allowed;
+}
+
 static int read_request(int fd, debugger_request_t* out_request) {
   ucred cr;
   socklen_t len = sizeof(cr);
@@ -158,7 +215,7 @@
     return -1;
   }
 
-  out_request->action = msg.action;
+  out_request->action = static_cast<debugger_action_t>(msg.action);
   out_request->tid = msg.tid;
   out_request->pid = cr.pid;
   out_request->uid = cr.uid;
@@ -170,8 +227,8 @@
     // Ensure that the tid reported by the crashing process is valid.
     // This check needs to happen again after ptracing the requested thread to prevent a race.
     if (!pid_contains_tid(out_request->pid, out_request->tid)) {
-      ALOGE("tid %d does not exist in pid %d. ignoring debug request\n", out_request->tid,
-           out_request->pid);
+      ALOGE("tid %d does not exist in pid %d. ignoring debug request\n",
+            out_request->tid, out_request->pid);
       return -1;
     }
   } else if (cr.uid == 0
@@ -184,6 +241,9 @@
       ALOGE("tid %d does not exist. ignoring explicit dump request\n", out_request->tid);
       return -1;
     }
+
+    if (!selinux_action_allowed(fd, out_request->tid, out_request->action))
+      return -1;
   } else {
     // No one else is allowed to dump arbitrary processes.
     return -1;
@@ -201,6 +261,85 @@
   return false;
 }
 
+#if defined(__LP64__)
+static bool is32bit(pid_t tid) {
+  char* exeline;
+  if (asprintf(&exeline, "/proc/%d/exe", tid) == -1) {
+    return false;
+  }
+  int fd = TEMP_FAILURE_RETRY(open(exeline, O_RDONLY | O_CLOEXEC));
+  int saved_errno = errno;
+  free(exeline);
+  if (fd == -1) {
+    ALOGW("Failed to open /proc/%d/exe %s", tid, strerror(saved_errno));
+    return false;
+  }
+
+  char ehdr[EI_NIDENT];
+  ssize_t bytes = TEMP_FAILURE_RETRY(read(fd, &ehdr, sizeof(ehdr)));
+  close(fd);
+  if (bytes != (ssize_t) sizeof(ehdr) || memcmp(ELFMAG, ehdr, SELFMAG) != 0) {
+    return false;
+  }
+  if (ehdr[EI_CLASS] == ELFCLASS32) {
+    return true;
+  }
+  return false;
+}
+
+static void redirect_to_32(int fd, debugger_request_t* request) {
+  debugger_msg_t msg;
+  memset(&msg, 0, sizeof(msg));
+  msg.tid = request->tid;
+  msg.action = request->action;
+
+  int sock_fd = socket_local_client(DEBUGGER32_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT,
+                                    SOCK_STREAM | SOCK_CLOEXEC);
+  if (sock_fd < 0) {
+    ALOGE("Failed to connect to debuggerd32: %s", strerror(errno));
+    return;
+  }
+
+  if (TEMP_FAILURE_RETRY(write(sock_fd, &msg, sizeof(msg))) != (ssize_t) sizeof(msg)) {
+    ALOGE("Failed to write request to debuggerd32 socket: %s", strerror(errno));
+    close(sock_fd);
+    return;
+  }
+
+  char ack;
+  if (TEMP_FAILURE_RETRY(read(sock_fd, &ack, 1)) == -1) {
+    ALOGE("Failed to read ack from debuggerd32 socket: %s", strerror(errno));
+    close(sock_fd);
+    return;
+  }
+
+  char buffer[1024];
+  ssize_t bytes_read;
+  while ((bytes_read = TEMP_FAILURE_RETRY(read(sock_fd, buffer, sizeof(buffer)))) > 0) {
+    ssize_t bytes_to_send = bytes_read;
+    ssize_t bytes_written;
+    do {
+      bytes_written = TEMP_FAILURE_RETRY(write(fd, buffer + bytes_read - bytes_to_send,
+                                               bytes_to_send));
+      if (bytes_written == -1) {
+        if (errno == EAGAIN) {
+          // Retry the write.
+          continue;
+        }
+        ALOGE("Error while writing data to fd: %s", strerror(errno));
+        break;
+      }
+      bytes_to_send -= bytes_written;
+    } while (bytes_written != 0 && bytes_to_send > 0);
+    if (bytes_to_send != 0) {
+        ALOGE("Failed to write all data to fd: read %zd, sent %zd", bytes_read, bytes_to_send);
+        break;
+    }
+  }
+  close(sock_fd);
+}
+#endif
+
 static void handle_request(int fd) {
   ALOGV("handle_request(%d)\n", fd);
 
@@ -211,6 +350,24 @@
     ALOGV("BOOM: pid=%d uid=%d gid=%d tid=%d\n",
          request.pid, request.uid, request.gid, request.tid);
 
+#if defined(__LP64__)
+    // On 64 bit systems, requests to dump 32 bit and 64 bit tids come
+    // to the 64 bit debuggerd. If the process is a 32 bit executable,
+    // redirect the request to the 32 bit debuggerd.
+    if (is32bit(request.tid)) {
+      // Only dump backtrace and dump tombstone requests can be redirected.
+      if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE
+          || request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
+        redirect_to_32(fd, &request);
+      } else {
+        ALOGE("debuggerd: Not allowed to redirect action %d to 32 bit debuggerd\n",
+              request.action);
+      }
+      close(fd);
+      return;
+    }
+#endif
+
     // At this point, the thread that made the request is blocked in
     // a read() call.  If the thread has crashed, then this gives us
     // time to PTRACE_ATTACH to it before it has a chance to really fault.
@@ -397,7 +554,7 @@
   act.sa_flags = SA_NOCLDWAIT;
   sigaction(SIGCHLD, &act, 0);
 
-  int s = socket_local_server(DEBUGGER_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+  int s = socket_local_server(SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
   if (s < 0)
     return 1;
   fcntl(s, F_SETFD, FD_CLOEXEC);
@@ -451,7 +608,11 @@
 }
 
 int main(int argc, char** argv) {
+  union selinux_callback cb;
   if (argc == 1) {
+    selinux_enabled = is_selinux_enabled();
+    cb.func_log = selinux_log_callback;
+    selinux_set_callback(SELINUX_CB_LOG, cb);
     return do_server();
   }
 
diff --git a/debuggerd/elf_utils.cpp b/debuggerd/elf_utils.cpp
new file mode 100644
index 0000000..65c1904
--- /dev/null
+++ b/debuggerd/elf_utils.cpp
@@ -0,0 +1,121 @@
+/*
+ * 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 "DEBUG"
+
+#include <elf.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <string>
+
+#include <backtrace/Backtrace.h>
+#include <base/stringprintf.h>
+#include <log/log.h>
+
+#include "elf_utils.h"
+
+#define NOTE_ALIGN(size)  ((size + 3) & ~3)
+
+template <typename HdrType, typename PhdrType, typename NhdrType>
+static bool get_build_id(
+    Backtrace* backtrace, uintptr_t base_addr, uint8_t* e_ident, std::string* build_id) {
+  HdrType hdr;
+
+  memcpy(&hdr.e_ident[0], e_ident, EI_NIDENT);
+
+  // First read the rest of the header.
+  if (backtrace->Read(base_addr + EI_NIDENT, reinterpret_cast<uint8_t*>(&hdr) + EI_NIDENT,
+                      sizeof(HdrType) - EI_NIDENT) != sizeof(HdrType) - EI_NIDENT) {
+    return false;
+  }
+
+  for (size_t i = 0; i < hdr.e_phnum; i++) {
+    PhdrType phdr;
+    if (backtrace->Read(base_addr + hdr.e_phoff + i * hdr.e_phentsize,
+                        reinterpret_cast<uint8_t*>(&phdr), sizeof(phdr)) != sizeof(phdr)) {
+      return false;
+    }
+    // Looking for the .note.gnu.build-id note.
+    if (phdr.p_type == PT_NOTE) {
+      size_t hdr_size = phdr.p_filesz;
+      uintptr_t addr = base_addr + phdr.p_offset;
+      while (hdr_size >= sizeof(NhdrType)) {
+        NhdrType nhdr;
+        if (backtrace->Read(addr, reinterpret_cast<uint8_t*>(&nhdr), sizeof(nhdr)) != sizeof(nhdr)) {
+          return false;
+        }
+        addr += sizeof(nhdr);
+        if (nhdr.n_type == NT_GNU_BUILD_ID) {
+          // Skip the name (which is the owner and should be "GNU").
+          addr += NOTE_ALIGN(nhdr.n_namesz);
+          uint8_t build_id_data[160];
+          if (nhdr.n_descsz > sizeof(build_id_data)) {
+            ALOGE("Possible corrupted note, desc size value is too large: %u",
+                  nhdr.n_descsz);
+            return false;
+          }
+          if (backtrace->Read(addr, build_id_data, nhdr.n_descsz) != nhdr.n_descsz) {
+            return false;
+          }
+
+          build_id->clear();
+          for (size_t bytes = 0; bytes < nhdr.n_descsz; bytes++) {
+            *build_id += android::base::StringPrintf("%02x", build_id_data[bytes]);
+          }
+
+          return true;
+        } else {
+          // Move past the extra note data.
+          hdr_size -= sizeof(nhdr);
+          size_t skip_bytes = NOTE_ALIGN(nhdr.n_namesz) + NOTE_ALIGN(nhdr.n_descsz);
+          addr += skip_bytes;
+          if (hdr_size < skip_bytes) {
+            break;
+          }
+          hdr_size -= skip_bytes;
+        }
+      }
+    }
+  }
+  return false;
+}
+
+bool elf_get_build_id(Backtrace* backtrace, uintptr_t addr, std::string* build_id) {
+  // Read and verify the elf magic number first.
+  uint8_t e_ident[EI_NIDENT];
+  if (backtrace->Read(addr, e_ident, SELFMAG) != SELFMAG) {
+    return false;
+  }
+
+  if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) {
+    return false;
+  }
+
+  // Read the rest of EI_NIDENT.
+  if (backtrace->Read(addr + SELFMAG, e_ident + SELFMAG, EI_NIDENT - SELFMAG) != EI_NIDENT - SELFMAG) {
+    return false;
+  }
+
+  if (e_ident[EI_CLASS] == ELFCLASS32) {
+    return get_build_id<Elf32_Ehdr, Elf32_Phdr, Elf32_Nhdr>(backtrace, addr, e_ident, build_id);
+  } else if (e_ident[EI_CLASS] == ELFCLASS64) {
+    return get_build_id<Elf64_Ehdr, Elf64_Phdr, Elf64_Nhdr>(backtrace, addr, e_ident, build_id);
+  }
+
+  return false;
+}
diff --git a/adb/usb_vendors.h b/debuggerd/elf_utils.h
similarity index 67%
copy from adb/usb_vendors.h
copy to debuggerd/elf_utils.h
index cee23a1..11d0a43 100644
--- a/adb/usb_vendors.h
+++ b/debuggerd/elf_utils.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 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.
@@ -14,12 +14,14 @@
  * limitations under the License.
  */
 
-#ifndef __USB_VENDORS_H
-#define __USB_VENDORS_H
+#ifndef _DEBUGGERD_ELF_UTILS_H
+#define _DEBUGGERD_ELF_UTILS_H
 
-extern int vendorIds[];
-extern unsigned  vendorIdCount;
+#include <stdint.h>
+#include <string>
 
-void usb_vendors_init(void);
+class Backtrace;
 
-#endif
+bool elf_get_build_id(Backtrace*, uintptr_t, std::string*);
+
+#endif // _DEBUGGERD_ELF_UTILS_H
diff --git a/debuggerd/machine.h b/debuggerd/machine.h
index fca9fbe..e65b147 100644
--- a/debuggerd/machine.h
+++ b/debuggerd/machine.h
@@ -19,9 +19,11 @@
 
 #include <sys/types.h>
 
+#include <backtrace/Backtrace.h>
+
 #include "utility.h"
 
-void dump_memory_and_code(log_t* log, pid_t tid);
+void dump_memory_and_code(log_t* log, Backtrace* backtrace);
 void dump_registers(log_t* log, pid_t tid);
 
 #endif // _DEBUGGERD_MACHINE_H
diff --git a/debuggerd/mips/machine.cpp b/debuggerd/mips/machine.cpp
index 97834c7..f7b8a86 100644
--- a/debuggerd/mips/machine.cpp
+++ b/debuggerd/mips/machine.cpp
@@ -14,42 +14,29 @@
  * limitations under the License.
  */
 
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
 #include <errno.h>
-#include <sys/types.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <string.h>
 #include <sys/ptrace.h>
 
-#include <sys/user.h>
+#include <backtrace/Backtrace.h>
 
-#include "../utility.h"
-#include "../machine.h"
+#include "machine.h"
+#include "utility.h"
 
-#define R(x) (static_cast<unsigned int>(x))
-
-// The MIPS uapi ptrace.h has the wrong definition for pt_regs. PTRACE_GETREGS
-// writes 64-bit quantities even though the public struct uses 32-bit ones.
-struct pt_regs_mips_t {
-  uint64_t regs[32];
-  uint64_t lo;
-  uint64_t hi;
-  uint64_t cp0_epc;
-  uint64_t cp0_badvaddr;
-  uint64_t cp0_status;
-  uint64_t cp0_cause;
-};
+#define R(x) (static_cast<uintptr_t>(x))
 
 // If configured to do so, dump memory around *all* registers
 // for the crashing thread.
-void dump_memory_and_code(log_t* log, pid_t tid) {
-  pt_regs_mips_t r;
-  if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
+void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
+  pt_regs r;
+  if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r)) {
+    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
     return;
   }
 
-  static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
+  static const char reg_names[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
 
   for (int reg = 0; reg < 32; reg++) {
     // skip uninteresting registers
@@ -60,53 +47,49 @@
        )
       continue;
 
-    uintptr_t addr = R(r.regs[reg]);
-
-    // Don't bother if it looks like a small int or ~= null, or if
-    // it's in the kernel area.
-    if (addr < 4096 || addr >= 0x80000000) {
-      continue;
-    }
-
-    _LOG(log, logtype::MEMORY, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
-    dump_memory(log, tid, addr);
+    dump_memory(log, backtrace, R(r.regs[reg]), "memory near %.2s:", &reg_names[reg * 2]);
   }
 
-  unsigned int pc = R(r.cp0_epc);
-  unsigned int ra = R(r.regs[31]);
-
-  _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
-  dump_memory(log, tid, (uintptr_t)pc);
-
+  uintptr_t pc = R(r.cp0_epc);
+  uintptr_t ra = R(r.regs[31]);
+  dump_memory(log, backtrace, pc, "code around pc:");
   if (pc != ra) {
-    _LOG(log, logtype::MEMORY, "\ncode around ra:\n");
-    dump_memory(log, tid, (uintptr_t)ra);
+    dump_memory(log, backtrace, ra, "code around ra:");
   }
 }
 
 void dump_registers(log_t* log, pid_t tid) {
-  pt_regs_mips_t r;
+  pt_regs r;
   if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
     _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
     return;
   }
 
-  _LOG(log, logtype::REGISTERS, " zr %08x  at %08x  v0 %08x  v1 %08x\n",
+  _LOG(log, logtype::REGISTERS, " zr %08" PRIxPTR "  at %08" PRIxPTR
+       "  v0 %08" PRIxPTR "  v1 %08" PRIxPTR "\n",
        R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3]));
-  _LOG(log, logtype::REGISTERS, " a0 %08x  a1 %08x  a2 %08x  a3 %08x\n",
+  _LOG(log, logtype::REGISTERS, " a0 %08" PRIxPTR "  a1 %08" PRIxPTR
+       "  a2 %08" PRIxPTR "  a3 %08" PRIxPTR "\n",
        R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7]));
-  _LOG(log, logtype::REGISTERS, " t0 %08x  t1 %08x  t2 %08x  t3 %08x\n",
+  _LOG(log, logtype::REGISTERS, " t0 %08" PRIxPTR "  t1 %08" PRIxPTR
+       "  t2 %08" PRIxPTR "  t3 %08" PRIxPTR "\n",
        R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11]));
-  _LOG(log, logtype::REGISTERS, " t4 %08x  t5 %08x  t6 %08x  t7 %08x\n",
+  _LOG(log, logtype::REGISTERS, " t4 %08" PRIxPTR "  t5 %08" PRIxPTR
+       "  t6 %08" PRIxPTR "  t7 %08" PRIxPTR "\n",
        R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15]));
-  _LOG(log, logtype::REGISTERS, " s0 %08x  s1 %08x  s2 %08x  s3 %08x\n",
+  _LOG(log, logtype::REGISTERS, " s0 %08" PRIxPTR "  s1 %08" PRIxPTR
+       "  s2 %08" PRIxPTR "  s3 %08" PRIxPTR "\n",
        R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19]));
-  _LOG(log, logtype::REGISTERS, " s4 %08x  s5 %08x  s6 %08x  s7 %08x\n",
+  _LOG(log, logtype::REGISTERS, " s4 %08" PRIxPTR "  s5 %08" PRIxPTR
+       "  s6 %08" PRIxPTR "  s7 %08" PRIxPTR "\n",
        R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23]));
-  _LOG(log, logtype::REGISTERS, " t8 %08x  t9 %08x  k0 %08x  k1 %08x\n",
+  _LOG(log, logtype::REGISTERS, " t8 %08" PRIxPTR "  t9 %08" PRIxPTR
+       "  k0 %08" PRIxPTR "  k1 %08" PRIxPTR "\n",
        R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27]));
-  _LOG(log, logtype::REGISTERS, " gp %08x  sp %08x  s8 %08x  ra %08x\n",
+  _LOG(log, logtype::REGISTERS, " gp %08" PRIxPTR "  sp %08" PRIxPTR
+       "  s8 %08" PRIxPTR "  ra %08" PRIxPTR "\n",
        R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31]));
-  _LOG(log, logtype::REGISTERS, " hi %08x  lo %08x bva %08x epc %08x\n",
+  _LOG(log, logtype::REGISTERS, " hi %08" PRIxPTR "  lo %08" PRIxPTR
+       " bva %08" PRIxPTR " epc %08" PRIxPTR "\n",
        R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc));
 }
diff --git a/debuggerd/mips64/crashglue.S b/debuggerd/mips64/crashglue.S
new file mode 100644
index 0000000..70a6641
--- /dev/null
+++ b/debuggerd/mips64/crashglue.S
@@ -0,0 +1,48 @@
+	.set	noat
+
+	.globl crash1
+	.globl crashnostack
+
+crash1:
+	li	$0,0xdead0000+0
+	li	$1,0xdead0000+1
+	li	$2,0xdead0000+2
+	li	$3,0xdead0000+3
+	li	$4,0xdead0000+4
+	li	$5,0xdead0000+5
+	li	$6,0xdead0000+6
+	li	$7,0xdead0000+7
+	li	$8,0xdead0000+8
+	li	$9,0xdead0000+9
+	li	$10,0xdead0000+10
+	li	$11,0xdead0000+11
+	li	$12,0xdead0000+12
+	li	$13,0xdead0000+13
+	li	$14,0xdead0000+14
+	li	$15,0xdead0000+15
+	li	$16,0xdead0000+16
+	li	$17,0xdead0000+17
+	li	$18,0xdead0000+18
+	li	$19,0xdead0000+19
+	li	$20,0xdead0000+20
+	li	$21,0xdead0000+21
+	li	$22,0xdead0000+22
+	li	$23,0xdead0000+23
+	li	$24,0xdead0000+24
+	li	$25,0xdead0000+25
+	li	$26,0xdead0000+26
+	li	$27,0xdead0000+27
+	li	$28,0xdead0000+28
+	# don't trash the stack otherwise the signal handler won't run
+	#li	$29,0xdead0000+29
+	li	$30,0xdead0000+30
+	li	$31,0xdead0000+31
+
+	lw	$zero,($0)
+	b .
+
+
+crashnostack:
+	li	$sp, 0
+	lw	$zero,($0)
+	b .
diff --git a/debuggerd/mips64/machine.cpp b/debuggerd/mips64/machine.cpp
new file mode 100644
index 0000000..293dcf6
--- /dev/null
+++ b/debuggerd/mips64/machine.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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 <errno.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/ptrace.h>
+
+#include <backtrace/Backtrace.h>
+
+#include "machine.h"
+#include "utility.h"
+
+#define R(x) (static_cast<uintptr_t>(x))
+
+// If configured to do so, dump memory around *all* registers
+// for the crashing thread.
+void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
+  pt_regs r;
+  if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r)) {
+    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
+    return;
+  }
+
+  static const char reg_names[] = "$0atv0v1a0a1a2a3a4a5a6a7t0t1t2t3s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
+
+  for (int reg = 0; reg < 32; reg++) {
+    // skip uninteresting registers
+    if (reg == 0 // $0
+        || reg == 26 // $k0
+        || reg == 27 // $k1
+        || reg == 31 // $ra (done below)
+       )
+      continue;
+
+    dump_memory(log, backtrace, R(r.regs[reg]), "memory near %.2s:", &reg_names[reg * 2]);
+  }
+
+  uintptr_t pc = R(r.cp0_epc);
+  uintptr_t ra = R(r.regs[31]);
+  dump_memory(log, backtrace, pc, "code around pc:");
+  if (pc != ra) {
+    dump_memory(log, backtrace, ra, "code around ra:");
+  }
+}
+
+void dump_registers(log_t* log, pid_t tid) {
+  pt_regs r;
+  if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
+    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
+    return;
+  }
+
+  _LOG(log, logtype::REGISTERS, " zr %016" PRIxPTR "  at %016" PRIxPTR
+       "  v0 %016" PRIxPTR "  v1 %016" PRIxPTR "\n",
+       R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3]));
+  _LOG(log, logtype::REGISTERS, " a0 %016" PRIxPTR "  a1 %016" PRIxPTR
+       "  a2 %016" PRIxPTR "  a3 %016" PRIxPTR "\n",
+       R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7]));
+  _LOG(log, logtype::REGISTERS, " a4 %016" PRIxPTR "  a5 %016" PRIxPTR
+       "  a6 %016" PRIxPTR "  a7 %016" PRIxPTR "\n",
+       R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11]));
+  _LOG(log, logtype::REGISTERS, " t0 %016" PRIxPTR "  t1 %016" PRIxPTR
+       "  t2 %016" PRIxPTR "  t3 %016" PRIxPTR "\n",
+       R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15]));
+  _LOG(log, logtype::REGISTERS, " s0 %016" PRIxPTR "  s1 %016" PRIxPTR
+       "  s2 %016" PRIxPTR "  s3 %016" PRIxPTR "\n",
+       R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19]));
+  _LOG(log, logtype::REGISTERS, " s4 %016" PRIxPTR "  s5 %016" PRIxPTR
+       "  s6 %016" PRIxPTR "  s7 %016" PRIxPTR "\n",
+       R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23]));
+  _LOG(log, logtype::REGISTERS, " t8 %016" PRIxPTR "  t9 %016" PRIxPTR
+       "  k0 %016" PRIxPTR "  k1 %016" PRIxPTR "\n",
+       R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27]));
+  _LOG(log, logtype::REGISTERS, " gp %016" PRIxPTR "  sp %016" PRIxPTR
+       "  s8 %016" PRIxPTR "  ra %016" PRIxPTR "\n",
+       R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31]));
+  _LOG(log, logtype::REGISTERS, " hi %016" PRIxPTR "  lo %016" PRIxPTR
+       " bva %016" PRIxPTR " epc %016" PRIxPTR "\n",
+       R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc));
+}
diff --git a/debuggerd/test/BacktraceMock.h b/debuggerd/test/BacktraceMock.h
new file mode 100644
index 0000000..5c252ab
--- /dev/null
+++ b/debuggerd/test/BacktraceMock.h
@@ -0,0 +1,101 @@
+/*
+ * 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 _DEBUGGERD_TEST_BACKTRACE_MOCK_H
+#define _DEBUGGERD_TEST_BACKTRACE_MOCK_H
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ucontext.h>
+
+#include <string>
+#include <vector>
+
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+
+class BacktraceMapMock : public BacktraceMap {
+ public:
+  BacktraceMapMock() : BacktraceMap(0) {}
+  virtual ~BacktraceMapMock() {}
+
+  void AddMap(backtrace_map_t& map) {
+    maps_.push_back(map);
+  }
+};
+
+
+class BacktraceMock : public Backtrace {
+ public:
+  BacktraceMock(BacktraceMapMock* map) : Backtrace(0, 0, map) {
+    if (map_ == nullptr) {
+      abort();
+    }
+  }
+  virtual ~BacktraceMock() {}
+
+  virtual bool Unwind(size_t, ucontext_t*) { return false; }
+  virtual bool ReadWord(uintptr_t, word_t*) { return false;}
+
+  virtual std::string GetFunctionNameRaw(uintptr_t, uintptr_t*) { return ""; }
+
+  virtual size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
+    size_t offset = 0;
+    if (last_read_addr_ > 0) {
+      offset = addr - last_read_addr_;
+    }
+    size_t bytes_available = buffer_.size() - offset;
+
+    if (bytes_partial_read_ > 0) {
+      // Do a partial read.
+      if (bytes > bytes_partial_read_) {
+        bytes = bytes_partial_read_;
+      }
+      bytes_partial_read_ -= bytes;
+    } else if (bytes > bytes_available) {
+      bytes = bytes_available;
+    }
+
+    if (bytes > 0) {
+      memcpy(buffer, buffer_.data() + offset, bytes);
+    }
+
+    last_read_addr_ = addr;
+    return bytes;
+  }
+
+  void SetReadData(uint8_t* buffer, size_t bytes) {
+    buffer_.resize(bytes);
+    memcpy(buffer_.data(), buffer, bytes);
+    bytes_partial_read_ = 0;
+    last_read_addr_ = 0;
+  }
+
+  void SetPartialReadAmount(size_t bytes) {
+    if (bytes > buffer_.size()) {
+      abort();
+    }
+    bytes_partial_read_ = bytes;
+  }
+
+ private:
+  std::vector<uint8_t> buffer_;
+  size_t bytes_partial_read_ = 0;
+  uintptr_t last_read_addr_ = 0;
+};
+
+#endif //  _DEBUGGERD_TEST_BACKTRACE_MOCK_H
diff --git a/debuggerd/test/dump_maps_test.cpp b/debuggerd/test/dump_maps_test.cpp
new file mode 100644
index 0000000..230f4f5
--- /dev/null
+++ b/debuggerd/test/dump_maps_test.cpp
@@ -0,0 +1,571 @@
+/*
+ * 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 <stdlib.h>
+
+#include <memory>
+#include <string>
+
+#include <gtest/gtest.h>
+#include <base/file.h>
+
+#include "utility.h"
+
+#include "BacktraceMock.h"
+#include "elf_fake.h"
+#include "host_signal_fixup.h"
+#include "log_fake.h"
+#include "ptrace_fake.h"
+
+// In order to test this code, we need to include the tombstone.cpp code.
+// Including it, also allows us to override the ptrace function.
+#define ptrace ptrace_fake
+
+#include "tombstone.cpp"
+
+void dump_registers(log_t*, pid_t) {
+}
+
+void dump_memory_and_code(log_t*, Backtrace*) {
+}
+
+void dump_backtrace_to_log(Backtrace*, log_t*, char const*) {
+}
+
+class DumpMapsTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    map_mock_.reset(new BacktraceMapMock());
+    backtrace_mock_.reset(new BacktraceMock(map_mock_.get()));
+
+    char tmp_file[256];
+    const char data_template[] = "/data/local/tmp/debuggerd_memory_testXXXXXX";
+    memcpy(tmp_file, data_template, sizeof(data_template));
+    int tombstone_fd = mkstemp(tmp_file);
+    if (tombstone_fd == -1) {
+      const char tmp_template[] = "/tmp/debuggerd_memory_testXXXXXX";
+      memcpy(tmp_file, tmp_template, sizeof(tmp_template));
+      tombstone_fd = mkstemp(tmp_file);
+      if (tombstone_fd == -1) {
+        abort();
+      }
+    }
+    if (unlink(tmp_file) == -1) {
+      abort();
+    }
+
+    log_.tfd = tombstone_fd;
+    log_.amfd = -1;
+    log_.crashed_tid = 12;
+    log_.current_tid = 12;
+    log_.should_retrieve_logcat = false;
+
+    resetLogs();
+    elf_set_fake_build_id("");
+    siginfo_t si;
+    si.si_signo = SIGPIPE;
+    ptrace_set_fake_getsiginfo(si);
+  }
+
+  virtual void TearDown() {
+    if (log_.tfd >= 0) {
+      close(log_.tfd);
+    }
+  }
+
+  std::unique_ptr<BacktraceMapMock> map_mock_;
+  std::unique_ptr<BacktraceMock> backtrace_mock_;
+
+  log_t log_;
+};
+
+TEST_F(DumpMapsTest, single_map) {
+  backtrace_map_t map;
+#if defined(__LP64__)
+  map.start = 0x123456789abcd000UL;
+  map.end = 0x123456789abdf000UL;
+#else
+  map.start = 0x1234000;
+  map.end = 0x1235000;
+#endif
+  map_mock_->AddMap(map);
+
+  dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  const char* expected_dump = \
+"\nmemory map:\n"
+#if defined(__LP64__)
+"    12345678'9abcd000-12345678'9abdefff ---         0     12000\n";
+#else
+"    01234000-01234fff ---         0      1000\n";
+#endif
+  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMapsTest, single_map_elf_build_id) {
+  backtrace_map_t map;
+#if defined(__LP64__)
+  map.start = 0x123456789abcd000UL;
+  map.end = 0x123456789abdf000UL;
+#else
+  map.start = 0x1234000;
+  map.end = 0x1235000;
+#endif
+  map.flags = PROT_READ;
+  map.name = "/system/lib/libfake.so";
+  map_mock_->AddMap(map);
+
+  elf_set_fake_build_id("abcdef1234567890abcdef1234567890");
+  dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  const char* expected_dump = \
+"\nmemory map:\n"
+#if defined(__LP64__)
+"    12345678'9abcd000-12345678'9abdefff r--         0     12000  /system/lib/libfake.so (BuildId: abcdef1234567890abcdef1234567890)\n";
+#else
+"    01234000-01234fff r--         0      1000  /system/lib/libfake.so (BuildId: abcdef1234567890abcdef1234567890)\n";
+#endif
+  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+// Even though build id is present, it should not be printed in either of
+// these cases.
+TEST_F(DumpMapsTest, single_map_no_build_id) {
+  backtrace_map_t map;
+#if defined(__LP64__)
+  map.start = 0x123456789abcd000UL;
+  map.end = 0x123456789abdf000UL;
+#else
+  map.start = 0x1234000;
+  map.end = 0x1235000;
+#endif
+  map.flags = PROT_WRITE;
+  map_mock_->AddMap(map);
+
+  map.name = "/system/lib/libfake.so";
+  map_mock_->AddMap(map);
+
+  elf_set_fake_build_id("abcdef1234567890abcdef1234567890");
+  dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  const char* expected_dump = \
+"\nmemory map:\n"
+#if defined(__LP64__)
+"    12345678'9abcd000-12345678'9abdefff -w-         0     12000\n"
+"    12345678'9abcd000-12345678'9abdefff -w-         0     12000  /system/lib/libfake.so\n";
+#else
+"    01234000-01234fff -w-         0      1000\n"
+"    01234000-01234fff -w-         0      1000  /system/lib/libfake.so\n";
+#endif
+  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMapsTest, multiple_maps) {
+  backtrace_map_t map;
+
+  map.start = 0xa234000;
+  map.end = 0xa235000;
+  map_mock_->AddMap(map);
+
+  map.start = 0xa334000;
+  map.end = 0xa335000;
+  map.offset = 0xf000;
+  map.flags = PROT_READ;
+  map_mock_->AddMap(map);
+
+  map.start = 0xa434000;
+  map.end = 0xa435000;
+  map.offset = 0x1000;
+  map.load_base = 0xd000;
+  map.flags = PROT_WRITE;
+  map_mock_->AddMap(map);
+
+  map.start = 0xa534000;
+  map.end = 0xa535000;
+  map.offset = 0x3000;
+  map.load_base = 0x2000;
+  map.flags = PROT_EXEC;
+  map_mock_->AddMap(map);
+
+  map.start = 0xa634000;
+  map.end = 0xa635000;
+  map.offset = 0;
+  map.load_base = 0;
+  map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
+  map.name = "/system/lib/fake.so";
+  map_mock_->AddMap(map);
+
+  dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  const char* expected_dump = \
+"\nmemory map:\n"
+#if defined(__LP64__)
+"    00000000'0a234000-00000000'0a234fff ---         0      1000\n"
+"    00000000'0a334000-00000000'0a334fff r--      f000      1000\n"
+"    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load base 0xd000)\n"
+"    00000000'0a534000-00000000'0a534fff --x      3000      1000  (load base 0x2000)\n"
+"    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n";
+#else
+"    0a234000-0a234fff ---         0      1000\n"
+"    0a334000-0a334fff r--      f000      1000\n"
+"    0a434000-0a434fff -w-      1000      1000  (load base 0xd000)\n"
+"    0a534000-0a534fff --x      3000      1000  (load base 0x2000)\n"
+"    0a634000-0a634fff rwx         0      1000  /system/lib/fake.so\n";
+#endif
+  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMapsTest, multiple_maps_fault_address_before) {
+  backtrace_map_t map;
+
+  map.start = 0xa434000;
+  map.end = 0xa435000;
+  map.offset = 0x1000;
+  map.load_base = 0xd000;
+  map.flags = PROT_WRITE;
+  map_mock_->AddMap(map);
+
+  map.start = 0xa534000;
+  map.end = 0xa535000;
+  map.offset = 0x3000;
+  map.load_base = 0x2000;
+  map.flags = PROT_EXEC;
+  map_mock_->AddMap(map);
+
+  map.start = 0xa634000;
+  map.end = 0xa635000;
+  map.offset = 0;
+  map.load_base = 0;
+  map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
+  map.name = "/system/lib/fake.so";
+  map_mock_->AddMap(map);
+
+  siginfo_t si;
+  si.si_signo = SIGBUS;
+  si.si_addr = reinterpret_cast<void*>(0x1000);
+  ptrace_set_fake_getsiginfo(si);
+  dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  const char* expected_dump = \
+"\nmemory map: (fault address prefixed with --->)\n"
+#if defined(__LP64__)
+"--->Fault address falls at 00000000'00001000 before any mapped regions\n"
+"    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load base 0xd000)\n"
+"    00000000'0a534000-00000000'0a534fff --x      3000      1000  (load base 0x2000)\n"
+"    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n";
+#else
+"--->Fault address falls at 00001000 before any mapped regions\n"
+"    0a434000-0a434fff -w-      1000      1000  (load base 0xd000)\n"
+"    0a534000-0a534fff --x      3000      1000  (load base 0x2000)\n"
+"    0a634000-0a634fff rwx         0      1000  /system/lib/fake.so\n";
+#endif
+  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMapsTest, multiple_maps_fault_address_between) {
+  backtrace_map_t map;
+
+  map.start = 0xa434000;
+  map.end = 0xa435000;
+  map.offset = 0x1000;
+  map.load_base = 0xd000;
+  map.flags = PROT_WRITE;
+  map_mock_->AddMap(map);
+
+  map.start = 0xa534000;
+  map.end = 0xa535000;
+  map.offset = 0x3000;
+  map.load_base = 0x2000;
+  map.flags = PROT_EXEC;
+  map_mock_->AddMap(map);
+
+  map.start = 0xa634000;
+  map.end = 0xa635000;
+  map.offset = 0;
+  map.load_base = 0;
+  map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
+  map.name = "/system/lib/fake.so";
+  map_mock_->AddMap(map);
+
+  siginfo_t si;
+  si.si_signo = SIGBUS;
+  si.si_addr = reinterpret_cast<void*>(0xa533000);
+  ptrace_set_fake_getsiginfo(si);
+  dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  const char* expected_dump = \
+"\nmemory map: (fault address prefixed with --->)\n"
+#if defined(__LP64__)
+"    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load base 0xd000)\n"
+"--->Fault address falls at 00000000'0a533000 between mapped regions\n"
+"    00000000'0a534000-00000000'0a534fff --x      3000      1000  (load base 0x2000)\n"
+"    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n";
+#else
+"    0a434000-0a434fff -w-      1000      1000  (load base 0xd000)\n"
+"--->Fault address falls at 0a533000 between mapped regions\n"
+"    0a534000-0a534fff --x      3000      1000  (load base 0x2000)\n"
+"    0a634000-0a634fff rwx         0      1000  /system/lib/fake.so\n";
+#endif
+  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMapsTest, multiple_maps_fault_address_in_map) {
+  backtrace_map_t map;
+
+  map.start = 0xa434000;
+  map.end = 0xa435000;
+  map.offset = 0x1000;
+  map.load_base = 0xd000;
+  map.flags = PROT_WRITE;
+  map_mock_->AddMap(map);
+
+  map.start = 0xa534000;
+  map.end = 0xa535000;
+  map.offset = 0x3000;
+  map.load_base = 0x2000;
+  map.flags = PROT_EXEC;
+  map_mock_->AddMap(map);
+
+  map.start = 0xa634000;
+  map.end = 0xa635000;
+  map.offset = 0;
+  map.load_base = 0;
+  map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
+  map.name = "/system/lib/fake.so";
+  map_mock_->AddMap(map);
+
+  siginfo_t si;
+  si.si_signo = SIGBUS;
+  si.si_addr = reinterpret_cast<void*>(0xa534040);
+  ptrace_set_fake_getsiginfo(si);
+  dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  const char* expected_dump = \
+"\nmemory map: (fault address prefixed with --->)\n"
+#if defined(__LP64__)
+"    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load base 0xd000)\n"
+"--->00000000'0a534000-00000000'0a534fff --x      3000      1000  (load base 0x2000)\n"
+"    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n";
+#else
+"    0a434000-0a434fff -w-      1000      1000  (load base 0xd000)\n"
+"--->0a534000-0a534fff --x      3000      1000  (load base 0x2000)\n"
+"    0a634000-0a634fff rwx         0      1000  /system/lib/fake.so\n";
+#endif
+  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMapsTest, multiple_maps_fault_address_after) {
+  backtrace_map_t map;
+
+  map.start = 0xa434000;
+  map.end = 0xa435000;
+  map.offset = 0x1000;
+  map.load_base = 0xd000;
+  map.flags = PROT_WRITE;
+  map_mock_->AddMap(map);
+
+  map.start = 0xa534000;
+  map.end = 0xa535000;
+  map.offset = 0x3000;
+  map.load_base = 0x2000;
+  map.flags = PROT_EXEC;
+  map_mock_->AddMap(map);
+
+  map.start = 0xa634000;
+  map.end = 0xa635000;
+  map.offset = 0;
+  map.load_base = 0;
+  map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
+  map.name = "/system/lib/fake.so";
+  map_mock_->AddMap(map);
+
+  siginfo_t si;
+  si.si_signo = SIGBUS;
+#if defined(__LP64__)
+  si.si_addr = reinterpret_cast<void*>(0x12345a534040UL);
+#else
+  si.si_addr = reinterpret_cast<void*>(0xf534040UL);
+#endif
+  ptrace_set_fake_getsiginfo(si);
+  dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  const char* expected_dump = \
+"\nmemory map: (fault address prefixed with --->)\n"
+#if defined(__LP64__)
+"    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load base 0xd000)\n"
+"    00000000'0a534000-00000000'0a534fff --x      3000      1000  (load base 0x2000)\n"
+"    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n"
+"--->Fault address falls at 00001234'5a534040 after any mapped regions\n";
+#else
+"    0a434000-0a434fff -w-      1000      1000  (load base 0xd000)\n"
+"    0a534000-0a534fff --x      3000      1000  (load base 0x2000)\n"
+"    0a634000-0a634fff rwx         0      1000  /system/lib/fake.so\n"
+"--->Fault address falls at 0f534040 after any mapped regions\n";
+#endif
+  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMapsTest, multiple_maps_getsiginfo_fail) {
+  backtrace_map_t map;
+
+  map.start = 0xa434000;
+  map.end = 0xa435000;
+  map.offset = 0x1000;
+  map.load_base = 0xd000;
+  map.flags = PROT_WRITE;
+  map_mock_->AddMap(map);
+
+  siginfo_t si;
+  si.si_signo = 0;
+  ptrace_set_fake_getsiginfo(si);
+  dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  const char* expected_dump = \
+"Cannot get siginfo for 100: Bad address\n"
+"\nmemory map:\n"
+#if defined(__LP64__)
+"    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load base 0xd000)\n";
+#else
+"    0a434000-0a434fff -w-      1000      1000  (load base 0xd000)\n";
+#endif
+  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("DEBUG Cannot get siginfo for 100: Bad address\n",
+               getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMapsTest, multiple_maps_check_signal_has_si_addr) {
+  backtrace_map_t map;
+
+  map.start = 0xa434000;
+  map.end = 0xa435000;
+  map.flags = PROT_WRITE;
+  map_mock_->AddMap(map);
+
+  for (int i = 1; i < 255; i++) {
+    ASSERT_TRUE(ftruncate(log_.tfd, 0) == 0);
+    ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+
+    siginfo_t si;
+    si.si_signo = i;
+    si.si_addr = reinterpret_cast<void*>(0x1000);
+    ptrace_set_fake_getsiginfo(si);
+    dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+
+    std::string tombstone_contents;
+    ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+    ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+    bool has_addr = false;
+    switch (si.si_signo) {
+    case SIGBUS:
+    case SIGFPE:
+    case SIGILL:
+    case SIGSEGV:
+    case SIGTRAP:
+      has_addr = true;
+      break;
+    }
+
+    const char* expected_addr_dump = \
+"\nmemory map: (fault address prefixed with --->)\n"
+#if defined(__LP64__)
+"--->Fault address falls at 00000000'00001000 before any mapped regions\n"
+"    00000000'0a434000-00000000'0a434fff -w-         0      1000\n";
+#else
+"--->Fault address falls at 00001000 before any mapped regions\n"
+"    0a434000-0a434fff -w-         0      1000\n";
+#endif
+    const char* expected_dump = \
+"\nmemory map:\n"
+#if defined(__LP64__)
+"    00000000'0a434000-00000000'0a434fff -w-         0      1000\n";
+#else
+"    0a434000-0a434fff -w-         0      1000\n";
+#endif
+    if (has_addr) {
+      ASSERT_STREQ(expected_addr_dump, tombstone_contents.c_str())
+        << "Signal " << si.si_signo << " expected to include an address.";
+    } else {
+      ASSERT_STREQ(expected_dump, tombstone_contents.c_str())
+        << "Signal " << si.si_signo << " is not expected to include an address.";
+    }
+
+    // Verify that the log buf is empty, and no error messages.
+    ASSERT_STREQ("", getFakeLogBuf().c_str());
+    ASSERT_STREQ("", getFakeLogPrint().c_str());
+  }
+}
diff --git a/debuggerd/test/dump_memory_test.cpp b/debuggerd/test/dump_memory_test.cpp
new file mode 100644
index 0000000..fcb0108
--- /dev/null
+++ b/debuggerd/test/dump_memory_test.cpp
@@ -0,0 +1,504 @@
+/*
+ * 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 <stdlib.h>
+
+#include <memory>
+#include <string>
+
+#include <gtest/gtest.h>
+#include <base/file.h>
+
+#include "BacktraceMock.h"
+#include "log_fake.h"
+#include "utility.h"
+
+const char g_expected_full_dump[] =
+"\nmemory near r1:\n"
+#if defined(__LP64__)
+"    0000000012345658 0706050403020100 0f0e0d0c0b0a0908  ................\n"
+"    0000000012345668 1716151413121110 1f1e1d1c1b1a1918  ................\n"
+"    0000000012345678 2726252423222120 2f2e2d2c2b2a2928   !\"#$%&'()*+,-./\n"
+"    0000000012345688 3736353433323130 3f3e3d3c3b3a3938  0123456789:;<=>?\n"
+"    0000000012345698 4746454443424140 4f4e4d4c4b4a4948  @ABCDEFGHIJKLMNO\n"
+"    00000000123456a8 5756555453525150 5f5e5d5c5b5a5958  PQRSTUVWXYZ[\\]^_\n"
+"    00000000123456b8 6766656463626160 6f6e6d6c6b6a6968  `abcdefghijklmno\n"
+"    00000000123456c8 7776757473727170 7f7e7d7c7b7a7978  pqrstuvwxyz{|}~.\n"
+"    00000000123456d8 8786858483828180 8f8e8d8c8b8a8988  ................\n"
+"    00000000123456e8 9796959493929190 9f9e9d9c9b9a9998  ................\n"
+"    00000000123456f8 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8  ................\n"
+"    0000000012345708 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8  ................\n"
+"    0000000012345718 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8  ................\n"
+"    0000000012345728 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8  ................\n"
+"    0000000012345738 e7e6e5e4e3e2e1e0 efeeedecebeae9e8  ................\n"
+"    0000000012345748 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8  ................\n";
+#else
+"    12345658 03020100 07060504 0b0a0908 0f0e0d0c  ................\n"
+"    12345668 13121110 17161514 1b1a1918 1f1e1d1c  ................\n"
+"    12345678 23222120 27262524 2b2a2928 2f2e2d2c   !\"#$%&'()*+,-./\n"
+"    12345688 33323130 37363534 3b3a3938 3f3e3d3c  0123456789:;<=>?\n"
+"    12345698 43424140 47464544 4b4a4948 4f4e4d4c  @ABCDEFGHIJKLMNO\n"
+"    123456a8 53525150 57565554 5b5a5958 5f5e5d5c  PQRSTUVWXYZ[\\]^_\n"
+"    123456b8 63626160 67666564 6b6a6968 6f6e6d6c  `abcdefghijklmno\n"
+"    123456c8 73727170 77767574 7b7a7978 7f7e7d7c  pqrstuvwxyz{|}~.\n"
+"    123456d8 83828180 87868584 8b8a8988 8f8e8d8c  ................\n"
+"    123456e8 93929190 97969594 9b9a9998 9f9e9d9c  ................\n"
+"    123456f8 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac  ................\n"
+"    12345708 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc  ................\n"
+"    12345718 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc  ................\n"
+"    12345728 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc  ................\n"
+"    12345738 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec  ................\n"
+"    12345748 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc  ................\n";
+#endif
+
+const char g_expected_partial_dump[] = \
+"\nmemory near pc:\n"
+#if defined(__LP64__)
+"    00000000123455e0 0706050403020100 0f0e0d0c0b0a0908  ................\n"
+"    00000000123455f0 1716151413121110 1f1e1d1c1b1a1918  ................\n"
+"    0000000012345600 2726252423222120 2f2e2d2c2b2a2928   !\"#$%&'()*+,-./\n"
+"    0000000012345610 3736353433323130 3f3e3d3c3b3a3938  0123456789:;<=>?\n"
+"    0000000012345620 4746454443424140 4f4e4d4c4b4a4948  @ABCDEFGHIJKLMNO\n"
+"    0000000012345630 5756555453525150 5f5e5d5c5b5a5958  PQRSTUVWXYZ[\\]^_\n"
+"    0000000012345640 6766656463626160 ----------------  `abcdefg........\n"
+"    0000000012345650 ---------------- ----------------  ................\n"
+"    0000000012345660 ---------------- ----------------  ................\n"
+"    0000000012345670 ---------------- ----------------  ................\n"
+"    0000000012345680 ---------------- ----------------  ................\n"
+"    0000000012345690 ---------------- ----------------  ................\n"
+"    00000000123456a0 ---------------- ----------------  ................\n"
+"    00000000123456b0 ---------------- ----------------  ................\n"
+"    00000000123456c0 ---------------- ----------------  ................\n"
+"    00000000123456d0 ---------------- ----------------  ................\n";
+#else
+"    123455e0 03020100 07060504 0b0a0908 0f0e0d0c  ................\n"
+"    123455f0 13121110 17161514 1b1a1918 1f1e1d1c  ................\n"
+"    12345600 23222120 27262524 2b2a2928 2f2e2d2c   !\"#$%&'()*+,-./\n"
+"    12345610 33323130 37363534 3b3a3938 3f3e3d3c  0123456789:;<=>?\n"
+"    12345620 43424140 47464544 4b4a4948 4f4e4d4c  @ABCDEFGHIJKLMNO\n"
+"    12345630 53525150 57565554 5b5a5958 5f5e5d5c  PQRSTUVWXYZ[\\]^_\n"
+"    12345640 63626160 67666564 -------- --------  `abcdefg........\n"
+"    12345650 -------- -------- -------- --------  ................\n"
+"    12345660 -------- -------- -------- --------  ................\n"
+"    12345670 -------- -------- -------- --------  ................\n"
+"    12345680 -------- -------- -------- --------  ................\n"
+"    12345690 -------- -------- -------- --------  ................\n"
+"    123456a0 -------- -------- -------- --------  ................\n"
+"    123456b0 -------- -------- -------- --------  ................\n"
+"    123456c0 -------- -------- -------- --------  ................\n"
+"    123456d0 -------- -------- -------- --------  ................\n";
+#endif
+
+class DumpMemoryTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    map_mock_.reset(new BacktraceMapMock());
+    backtrace_mock_.reset(new BacktraceMock(map_mock_.get()));
+
+    char tmp_file[256];
+    const char data_template[] = "/data/local/tmp/debuggerd_memory_testXXXXXX";
+    memcpy(tmp_file, data_template, sizeof(data_template));
+    int tombstone_fd = mkstemp(tmp_file);
+    if (tombstone_fd == -1) {
+      const char tmp_template[] = "/tmp/debuggerd_memory_testXXXXXX";
+      memcpy(tmp_file, tmp_template, sizeof(tmp_template));
+      tombstone_fd = mkstemp(tmp_file);
+      if (tombstone_fd == -1) {
+        abort();
+      }
+    }
+    if (unlink(tmp_file) == -1) {
+      abort();
+    }
+
+    log_.tfd = tombstone_fd;
+    log_.amfd = -1;
+    log_.crashed_tid = 12;
+    log_.current_tid = 12;
+    log_.should_retrieve_logcat = false;
+
+    resetLogs();
+  }
+
+  virtual void TearDown() {
+    if (log_.tfd >= 0) {
+      close(log_.tfd);
+    }
+  }
+
+  std::unique_ptr<BacktraceMapMock> map_mock_;
+  std::unique_ptr<BacktraceMock> backtrace_mock_;
+
+  log_t log_;
+};
+
+TEST_F(DumpMemoryTest, aligned_addr) {
+  uint8_t buffer[256];
+  for (size_t i = 0; i < sizeof(buffer); i++) {
+    buffer[i] = i;
+  }
+  backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+  dump_memory(&log_, backtrace_mock_.get(), 0x12345678, "memory near %.2s:", "r1");
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  ASSERT_STREQ(g_expected_full_dump, tombstone_contents.c_str());
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, partial_read) {
+  uint8_t buffer[256];
+  for (size_t i = 0; i < sizeof(buffer); i++) {
+    buffer[i] = i;
+  }
+  backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+  backtrace_mock_->SetPartialReadAmount(96);
+
+  dump_memory(&log_, backtrace_mock_.get(), 0x12345679, "memory near %.2s:", "r1");
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  ASSERT_STREQ(g_expected_full_dump, tombstone_contents.c_str());
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, unaligned_addr) {
+  uint8_t buffer[256];
+  for (size_t i = 0; i < sizeof(buffer); i++) {
+    buffer[i] = i;
+  }
+  backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+  dump_memory(&log_, backtrace_mock_.get(), 0x12345679, "memory near %.2s:", "r1");
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  ASSERT_STREQ(g_expected_full_dump, tombstone_contents.c_str());
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_unreadable) {
+  dump_memory(&log_, backtrace_mock_.get(), 0xa2345678, "memory near pc:");
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  const char* expected_dump = \
+"\nmemory near pc:\n"
+#if defined(__LP64__)
+"    00000000a2345658 ---------------- ----------------  ................\n"
+"    00000000a2345668 ---------------- ----------------  ................\n"
+"    00000000a2345678 ---------------- ----------------  ................\n"
+"    00000000a2345688 ---------------- ----------------  ................\n"
+"    00000000a2345698 ---------------- ----------------  ................\n"
+"    00000000a23456a8 ---------------- ----------------  ................\n"
+"    00000000a23456b8 ---------------- ----------------  ................\n"
+"    00000000a23456c8 ---------------- ----------------  ................\n"
+"    00000000a23456d8 ---------------- ----------------  ................\n"
+"    00000000a23456e8 ---------------- ----------------  ................\n"
+"    00000000a23456f8 ---------------- ----------------  ................\n"
+"    00000000a2345708 ---------------- ----------------  ................\n"
+"    00000000a2345718 ---------------- ----------------  ................\n"
+"    00000000a2345728 ---------------- ----------------  ................\n"
+"    00000000a2345738 ---------------- ----------------  ................\n"
+"    00000000a2345748 ---------------- ----------------  ................\n";
+#else
+"    a2345658 -------- -------- -------- --------  ................\n"
+"    a2345668 -------- -------- -------- --------  ................\n"
+"    a2345678 -------- -------- -------- --------  ................\n"
+"    a2345688 -------- -------- -------- --------  ................\n"
+"    a2345698 -------- -------- -------- --------  ................\n"
+"    a23456a8 -------- -------- -------- --------  ................\n"
+"    a23456b8 -------- -------- -------- --------  ................\n"
+"    a23456c8 -------- -------- -------- --------  ................\n"
+"    a23456d8 -------- -------- -------- --------  ................\n"
+"    a23456e8 -------- -------- -------- --------  ................\n"
+"    a23456f8 -------- -------- -------- --------  ................\n"
+"    a2345708 -------- -------- -------- --------  ................\n"
+"    a2345718 -------- -------- -------- --------  ................\n"
+"    a2345728 -------- -------- -------- --------  ................\n"
+"    a2345738 -------- -------- -------- --------  ................\n"
+"    a2345748 -------- -------- -------- --------  ................\n";
+#endif
+  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_partially_unreadable) {
+  uint8_t buffer[104];
+  for (size_t i = 0; i < sizeof(buffer); i++) {
+    buffer[i] = i;
+  }
+  backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+  dump_memory(&log_, backtrace_mock_.get(), 0x12345600, "memory near pc:");
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  ASSERT_STREQ(g_expected_partial_dump, tombstone_contents.c_str());
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_partially_unreadable_unaligned_return) {
+  uint8_t buffer[104];
+  for (size_t i = 0; i < sizeof(buffer); i++) {
+    buffer[i] = i;
+  }
+  backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+  backtrace_mock_->SetPartialReadAmount(102);
+
+  dump_memory(&log_, backtrace_mock_.get(), 0x12345600, "memory near pc:");
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  ASSERT_STREQ(g_expected_partial_dump, tombstone_contents.c_str());
+
+#if defined(__LP64__)
+  ASSERT_STREQ("DEBUG Bytes read 102, is not a multiple of 8\n", getFakeLogPrint().c_str());
+#else
+  ASSERT_STREQ("DEBUG Bytes read 102, is not a multiple of 4\n", getFakeLogPrint().c_str());
+#endif
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_partially_unreadable_two_unaligned_reads) {
+  uint8_t buffer[106];
+  for (size_t i = 0; i < sizeof(buffer); i++) {
+    buffer[i] = i;
+  }
+  backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+  backtrace_mock_->SetPartialReadAmount(45);
+
+  dump_memory(&log_, backtrace_mock_.get(), 0x12345600, "memory near pc:");
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  ASSERT_STREQ(g_expected_partial_dump, tombstone_contents.c_str());
+
+#if defined(__LP64__)
+  ASSERT_STREQ("DEBUG Bytes read 45, is not a multiple of 8\n"
+               "DEBUG Bytes after second read 106, is not a multiple of 8\n",
+               getFakeLogPrint().c_str());
+#else
+  ASSERT_STREQ("DEBUG Bytes read 45, is not a multiple of 4\n"
+               "DEBUG Bytes after second read 106, is not a multiple of 4\n",
+               getFakeLogPrint().c_str());
+#endif
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+}
+
+TEST_F(DumpMemoryTest, address_low_fence) {
+  uint8_t buffer[256];
+  memset(buffer, 0, sizeof(buffer));
+  backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+  dump_memory(&log_, backtrace_mock_.get(), 0x1000, "memory near %.2s:", "r1");
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  const char* expected_dump = \
+"\nmemory near r1:\n"
+#if defined(__LP64__)
+"    0000000000001000 0000000000000000 0000000000000000  ................\n"
+"    0000000000001010 0000000000000000 0000000000000000  ................\n"
+"    0000000000001020 0000000000000000 0000000000000000  ................\n"
+"    0000000000001030 0000000000000000 0000000000000000  ................\n"
+"    0000000000001040 0000000000000000 0000000000000000  ................\n"
+"    0000000000001050 0000000000000000 0000000000000000  ................\n"
+"    0000000000001060 0000000000000000 0000000000000000  ................\n"
+"    0000000000001070 0000000000000000 0000000000000000  ................\n"
+"    0000000000001080 0000000000000000 0000000000000000  ................\n"
+"    0000000000001090 0000000000000000 0000000000000000  ................\n"
+"    00000000000010a0 0000000000000000 0000000000000000  ................\n"
+"    00000000000010b0 0000000000000000 0000000000000000  ................\n"
+"    00000000000010c0 0000000000000000 0000000000000000  ................\n"
+"    00000000000010d0 0000000000000000 0000000000000000  ................\n"
+"    00000000000010e0 0000000000000000 0000000000000000  ................\n"
+"    00000000000010f0 0000000000000000 0000000000000000  ................\n";
+#else
+"    00001000 00000000 00000000 00000000 00000000  ................\n"
+"    00001010 00000000 00000000 00000000 00000000  ................\n"
+"    00001020 00000000 00000000 00000000 00000000  ................\n"
+"    00001030 00000000 00000000 00000000 00000000  ................\n"
+"    00001040 00000000 00000000 00000000 00000000  ................\n"
+"    00001050 00000000 00000000 00000000 00000000  ................\n"
+"    00001060 00000000 00000000 00000000 00000000  ................\n"
+"    00001070 00000000 00000000 00000000 00000000  ................\n"
+"    00001080 00000000 00000000 00000000 00000000  ................\n"
+"    00001090 00000000 00000000 00000000 00000000  ................\n"
+"    000010a0 00000000 00000000 00000000 00000000  ................\n"
+"    000010b0 00000000 00000000 00000000 00000000  ................\n"
+"    000010c0 00000000 00000000 00000000 00000000  ................\n"
+"    000010d0 00000000 00000000 00000000 00000000  ................\n"
+"    000010e0 00000000 00000000 00000000 00000000  ................\n"
+"    000010f0 00000000 00000000 00000000 00000000  ................\n";
+#endif
+  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_address_too_low) {
+  uint8_t buffer[256];
+  memset(buffer, 0, sizeof(buffer));
+  backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+  dump_memory(&log_, backtrace_mock_.get(), 0, "memory near %.2s:", "r1");
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  ASSERT_STREQ("", tombstone_contents.c_str());
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_address_too_high) {
+  uint8_t buffer[256];
+  memset(buffer, 0, sizeof(buffer));
+  backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+#if defined(__LP64__)
+  dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL, "memory near %.2s:", "r1");
+  dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL - 32, "memory near %.2s:", "r1");
+  dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL - 216, "memory near %.2s:", "r1");
+#else
+  dump_memory(&log_, backtrace_mock_.get(), 0xffff0000, "memory near %.2s:", "r1");
+  dump_memory(&log_, backtrace_mock_.get(), 0xffff0000 - 32, "memory near %.2s:", "r1");
+  dump_memory(&log_, backtrace_mock_.get(), 0xffff0000 - 220, "memory near %.2s:", "r1");
+#endif
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  ASSERT_STREQ("", tombstone_contents.c_str());
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_address_would_overflow) {
+  uint8_t buffer[256];
+  memset(buffer, 0, sizeof(buffer));
+  backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+#if defined(__LP64__)
+  dump_memory(&log_, backtrace_mock_.get(), 0xfffffffffffffff0, "memory near %.2s:", "r1");
+#else
+  dump_memory(&log_, backtrace_mock_.get(), 0xfffffff0, "memory near %.2s:", "r1");
+#endif
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  ASSERT_STREQ("", tombstone_contents.c_str());
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_address_nearly_too_high) {
+  uint8_t buffer[256];
+  for (size_t i = 0; i < sizeof(buffer); i++) {
+    buffer[i] = i;
+  }
+  backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+#if defined(__LP64__)
+  dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL - 224, "memory near %.2s:", "r4");
+#else
+  dump_memory(&log_, backtrace_mock_.get(), 0xffff0000 - 224, "memory near %.2s:", "r4");
+#endif
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  const char* expected_dump = \
+"\nmemory near r4:\n"
+#if defined(__LP64__)
+"    3fffffffffffff00 0706050403020100 0f0e0d0c0b0a0908  ................\n"
+"    3fffffffffffff10 1716151413121110 1f1e1d1c1b1a1918  ................\n"
+"    3fffffffffffff20 2726252423222120 2f2e2d2c2b2a2928   !\"#$%&'()*+,-./\n"
+"    3fffffffffffff30 3736353433323130 3f3e3d3c3b3a3938  0123456789:;<=>?\n"
+"    3fffffffffffff40 4746454443424140 4f4e4d4c4b4a4948  @ABCDEFGHIJKLMNO\n"
+"    3fffffffffffff50 5756555453525150 5f5e5d5c5b5a5958  PQRSTUVWXYZ[\\]^_\n"
+"    3fffffffffffff60 6766656463626160 6f6e6d6c6b6a6968  `abcdefghijklmno\n"
+"    3fffffffffffff70 7776757473727170 7f7e7d7c7b7a7978  pqrstuvwxyz{|}~.\n"
+"    3fffffffffffff80 8786858483828180 8f8e8d8c8b8a8988  ................\n"
+"    3fffffffffffff90 9796959493929190 9f9e9d9c9b9a9998  ................\n"
+"    3fffffffffffffa0 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8  ................\n"
+"    3fffffffffffffb0 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8  ................\n"
+"    3fffffffffffffc0 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8  ................\n"
+"    3fffffffffffffd0 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8  ................\n"
+"    3fffffffffffffe0 e7e6e5e4e3e2e1e0 efeeedecebeae9e8  ................\n"
+"    3ffffffffffffff0 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8  ................\n";
+#else
+"    fffeff00 03020100 07060504 0b0a0908 0f0e0d0c  ................\n"
+"    fffeff10 13121110 17161514 1b1a1918 1f1e1d1c  ................\n"
+"    fffeff20 23222120 27262524 2b2a2928 2f2e2d2c   !\"#$%&'()*+,-./\n"
+"    fffeff30 33323130 37363534 3b3a3938 3f3e3d3c  0123456789:;<=>?\n"
+"    fffeff40 43424140 47464544 4b4a4948 4f4e4d4c  @ABCDEFGHIJKLMNO\n"
+"    fffeff50 53525150 57565554 5b5a5958 5f5e5d5c  PQRSTUVWXYZ[\\]^_\n"
+"    fffeff60 63626160 67666564 6b6a6968 6f6e6d6c  `abcdefghijklmno\n"
+"    fffeff70 73727170 77767574 7b7a7978 7f7e7d7c  pqrstuvwxyz{|}~.\n"
+"    fffeff80 83828180 87868584 8b8a8988 8f8e8d8c  ................\n"
+"    fffeff90 93929190 97969594 9b9a9998 9f9e9d9c  ................\n"
+"    fffeffa0 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac  ................\n"
+"    fffeffb0 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc  ................\n"
+"    fffeffc0 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc  ................\n"
+"    fffeffd0 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc  ................\n"
+"    fffeffe0 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec  ................\n"
+"    fffefff0 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc  ................\n";
+#endif
+  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
diff --git a/debuggerd/test/elf_fake.cpp b/debuggerd/test/elf_fake.cpp
new file mode 100644
index 0000000..bb52b59
--- /dev/null
+++ b/debuggerd/test/elf_fake.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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 <string>
+
+class Backtrace;
+
+std::string g_build_id;
+
+void elf_set_fake_build_id(const std::string& build_id) {
+  g_build_id = build_id;
+}
+
+bool elf_get_build_id(Backtrace*, uintptr_t, std::string* build_id) {
+  if (g_build_id != "") {
+    *build_id = g_build_id;
+    return true;
+  }
+  return false;
+}
diff --git a/adb/usb_vendors.h b/debuggerd/test/elf_fake.h
similarity index 70%
copy from adb/usb_vendors.h
copy to debuggerd/test/elf_fake.h
index cee23a1..08a8454 100644
--- a/adb/usb_vendors.h
+++ b/debuggerd/test/elf_fake.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 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.
@@ -14,12 +14,11 @@
  * limitations under the License.
  */
 
-#ifndef __USB_VENDORS_H
-#define __USB_VENDORS_H
+#ifndef _DEBUGGERD_TEST_ELF_FAKE_H
+#define _DEBUGGERD_TEST_ELF_FAKE_H
 
-extern int vendorIds[];
-extern unsigned  vendorIdCount;
+#include <string>
 
-void usb_vendors_init(void);
+void elf_set_fake_build_id(const std::string&);
 
-#endif
+#endif // _DEBUGGERD_TEST_ELF_FAKE_H
diff --git a/debuggerd/test/host_signal_fixup.h b/debuggerd/test/host_signal_fixup.h
new file mode 100644
index 0000000..c7796ef
--- /dev/null
+++ b/debuggerd/test/host_signal_fixup.h
@@ -0,0 +1,65 @@
+/*
+ * 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 _DEBUGGERD_TEST_HOST_SIGNAL_FIXUP_H
+#define _DEBUGGERD_TEST_HOST_SIGNAL_FIXUP_H
+
+#include <signal.h>
+
+#if !defined(__BIONIC__)
+
+// In order to compile parts of debuggerd for the host, we need to
+// define these values.
+
+#if !defined(NSIGILL)
+#define NSIGILL ILL_BADSTK
+#endif
+
+#if !defined(BUS_MCEERR_AR)
+#define BUS_MCEERR_AR 4
+#endif
+#if !defined(BUS_MCEERR_AO)
+#define BUS_MCEERR_AO 5
+#endif
+#if !defined(NSIGBUS)
+#define NSIGBUS BUS_MCEERR_AO
+#endif
+
+#if !defined(NSIGFPE)
+#define NSIGFPE FPE_FLTSUB
+#endif
+
+#if !defined(NSIGSEGV)
+#define NSIGSEGV SEGV_ACCERR
+#endif
+
+#if !defined(TRAP_BRANCH)
+#define TRAP_BRANCH 3
+#endif
+#if !defined(TRAP_HWBKPT)
+#define TRAP_HWBKPT 4
+#endif
+#if !defined(NSIGTRAP)
+#define NSIGTRAP TRAP_HWBKPT
+#endif
+
+#if !defined(SI_DETHREAD)
+#define SI_DETHREAD -7
+#endif
+
+#endif
+
+#endif // _DEBUGGERD_TEST_HOST_SIGNAL_FIXUP_H
diff --git a/debuggerd/test/log_fake.cpp b/debuggerd/test/log_fake.cpp
new file mode 100644
index 0000000..26523ad
--- /dev/null
+++ b/debuggerd/test/log_fake.cpp
@@ -0,0 +1,91 @@
+/*
+ * 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 <stdarg.h>
+
+#include <string>
+
+#include <base/stringprintf.h>
+#include <log/log.h>
+#include <log/logger.h>
+
+// Forward declarations.
+class Backtrace;
+struct EventTagMap;
+struct AndroidLogEntry;
+
+std::string g_fake_log_buf;
+
+std::string g_fake_log_print;
+
+void resetLogs() {
+  g_fake_log_buf = "";
+  g_fake_log_print = "";
+}
+
+std::string getFakeLogBuf() {
+  return g_fake_log_buf;
+}
+
+std::string getFakeLogPrint() {
+  return g_fake_log_print;
+}
+
+extern "C" int __android_log_buf_write(int, int, const char* tag, const char* msg) {
+  g_fake_log_buf += tag;
+  g_fake_log_buf += ' ';
+  g_fake_log_buf += msg;
+  return 1;
+}
+
+extern "C" int __android_log_print(int, const char* tag, const char* fmt, ...) {
+  g_fake_log_print += tag;
+  g_fake_log_print += ' ';
+
+  va_list ap;
+  va_start(ap, fmt);
+  android::base::StringAppendV(&g_fake_log_print, fmt, ap);
+  va_end(ap);
+
+  g_fake_log_print += '\n';
+
+  return 1;
+}
+
+extern "C" log_id_t android_name_to_log_id(const char*) {
+  return LOG_ID_SYSTEM;
+}
+
+extern "C" struct logger_list* android_logger_list_open(log_id_t, int, unsigned int, pid_t) {
+  return nullptr;
+}
+
+extern "C" int android_logger_list_read(struct logger_list*, struct log_msg*) {
+  return 0;
+}
+
+extern "C" EventTagMap* android_openEventTagMap(const char*) {
+  return nullptr;
+}
+
+extern "C" int android_log_processBinaryLogBuffer(
+    struct logger_entry*,
+    AndroidLogEntry*, const EventTagMap*, char*, int) {
+  return 0;
+}
+
+extern "C" void android_logger_list_free(struct logger_list*) {
+}
diff --git a/adb/usb_vendors.h b/debuggerd/test/log_fake.h
similarity index 68%
copy from adb/usb_vendors.h
copy to debuggerd/test/log_fake.h
index cee23a1..5418fce 100644
--- a/adb/usb_vendors.h
+++ b/debuggerd/test/log_fake.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 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.
@@ -14,12 +14,13 @@
  * limitations under the License.
  */
 
-#ifndef __USB_VENDORS_H
-#define __USB_VENDORS_H
+#ifndef _DEBUGGERD_TEST_LOG_FAKE_H
+#define _DEBUGGERD_TEST_LOG_FAKE_H
 
-extern int vendorIds[];
-extern unsigned  vendorIdCount;
+#include <string>
 
-void usb_vendors_init(void);
+void resetLogs();
+std::string getFakeLogBuf();
+std::string getFakeLogPrint();
 
-#endif
+#endif // _DEBUGGERD_TEST_LOG_FAKE_H
diff --git a/debuggerd/test/property_fake.cpp b/debuggerd/test/property_fake.cpp
new file mode 100644
index 0000000..02069f1
--- /dev/null
+++ b/debuggerd/test/property_fake.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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.h>
+
+#include <string>
+#include <unordered_map>
+
+#include <sys/system_properties.h>
+
+std::unordered_map<std::string, std::string> g_properties;
+
+extern "C" int property_set(const char* name, const char* value) {
+  if (g_properties.count(name) != 0) {
+    g_properties.erase(name);
+  }
+  g_properties[name] = value;
+  return 0;
+}
+
+extern "C" int property_get(const char* key, char* value, const char* default_value) {
+  if (g_properties.count(key) == 0) {
+    if (default_value == nullptr) {
+      return 0;
+    }
+    strncpy(value, default_value, PROP_VALUE_MAX-1);
+  } else {
+    strncpy(value, g_properties[key].c_str(), PROP_VALUE_MAX-1);
+  }
+  value[PROP_VALUE_MAX-1] = '\0';
+  return strlen(value);
+}
diff --git a/debuggerd/test/ptrace_fake.cpp b/debuggerd/test/ptrace_fake.cpp
new file mode 100644
index 0000000..f40cbd4
--- /dev/null
+++ b/debuggerd/test/ptrace_fake.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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 <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <sys/ptrace.h>
+
+#include <string>
+
+#include "ptrace_fake.h"
+
+siginfo_t g_fake_si = {.si_signo = 0};
+
+void ptrace_set_fake_getsiginfo(const siginfo_t& si) {
+  g_fake_si = si;
+}
+
+#if !defined(__BIONIC__)
+extern "C" long ptrace_fake(enum __ptrace_request request, ...) {
+#else
+extern "C" long ptrace_fake(int request, ...) {
+#endif
+  if (request == PTRACE_GETSIGINFO) {
+    if (g_fake_si.si_signo == 0) {
+      errno = EFAULT;
+      return -1;
+    }
+
+    va_list ap;
+    va_start(ap, request);
+    va_arg(ap, int);
+    va_arg(ap, int);
+    siginfo_t* si = va_arg(ap, siginfo*);
+    va_end(ap);
+    *si = g_fake_si;
+    return 0;
+  }
+  return -1;
+}
diff --git a/adb/usb_vendors.h b/debuggerd/test/ptrace_fake.h
similarity index 69%
copy from adb/usb_vendors.h
copy to debuggerd/test/ptrace_fake.h
index cee23a1..fdbb663 100644
--- a/adb/usb_vendors.h
+++ b/debuggerd/test/ptrace_fake.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 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.
@@ -14,12 +14,11 @@
  * limitations under the License.
  */
 
-#ifndef __USB_VENDORS_H
-#define __USB_VENDORS_H
+#ifndef _DEBUGGERD_TEST_PTRACE_FAKE_H
+#define _DEBUGGERD_TEST_PTRACE_FAKE_H
 
-extern int vendorIds[];
-extern unsigned  vendorIdCount;
+#include <signal.h>
 
-void usb_vendors_init(void);
+void ptrace_set_fake_getsiginfo(const siginfo_t&);
 
-#endif
+#endif // _DEBUGGERD_TEST_PTRACE_FAKE_H
diff --git a/adb/usb_vendors.h b/debuggerd/test/selinux_fake.cpp
similarity index 73%
rename from adb/usb_vendors.h
rename to debuggerd/test/selinux_fake.cpp
index cee23a1..acdd0a9 100644
--- a/adb/usb_vendors.h
+++ b/debuggerd/test/selinux_fake.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 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.
@@ -14,12 +14,6 @@
  * limitations under the License.
  */
 
-#ifndef __USB_VENDORS_H
-#define __USB_VENDORS_H
-
-extern int vendorIds[];
-extern unsigned  vendorIdCount;
-
-void usb_vendors_init(void);
-
-#endif
+extern "C" int selinux_android_restorecon(const char*, unsigned int) {
+  return 0;
+}
diff --git a/fastbootd/socket_client.h b/debuggerd/test/sys/system_properties.h
similarity index 79%
rename from fastbootd/socket_client.h
rename to debuggerd/test/sys/system_properties.h
index 4481ff2..9d44345 100644
--- a/fastbootd/socket_client.h
+++ b/debuggerd/test/sys/system_properties.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2013, Google Inc.
+ * Copyright (C) 2015 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -11,9 +11,6 @@
  *    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
@@ -29,9 +26,13 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _FASTBOOTD_SOCKET_CLIENT_H
-#define _FASTBOOTD_SOCKET_CLIENT_H
+#ifndef _DEBUGGERD_TEST_SYS_SYSTEM_PROPERTIES_H
+#define _DEBUGGERD_TEST_SYS_SYSTEM_PROPERTIES_H
 
-void run_socket_client();
+// This is just enough to get the property code to compile on
+// the host.
 
-#endif
+#define PROP_NAME_MAX   32
+#define PROP_VALUE_MAX  92
+
+#endif // _DEBUGGERD_TEST_SYS_SYSTEM_PROPERTIES_H
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 3eeff34..d04b721 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "DEBUG"
 
+#include <arpa/inet.h>
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -31,8 +32,12 @@
 #include <sys/stat.h>
 #include <sys/un.h>
 
+#include <memory>
+#include <string>
+
 #include <private/android_filesystem_config.h>
 
+#include <base/stringprintf.h>
 #include <cutils/properties.h>
 #include <log/log.h>
 #include <log/logger.h>
@@ -43,11 +48,10 @@
 
 #include <selinux/android.h>
 
-#include <UniquePtr.h>
-
+#include "backtrace.h"
+#include "elf_utils.h"
 #include "machine.h"
 #include "tombstone.h"
-#include "backtrace.h"
 
 #define STACK_WORDS 16
 
@@ -233,48 +237,36 @@
 
 static void dump_stack_segment(
     Backtrace* backtrace, log_t* log, uintptr_t* sp, size_t words, int label) {
+  // Read the data all at once.
+  word_t stack_data[words];
+  size_t bytes_read = backtrace->Read(*sp, reinterpret_cast<uint8_t*>(&stack_data[0]), sizeof(word_t) * words);
+  words = bytes_read / sizeof(word_t);
+  std::string line;
   for (size_t i = 0; i < words; i++) {
-    word_t stack_content;
-    if (!backtrace->ReadWord(*sp, &stack_content)) {
-      break;
+    line = "    ";
+    if (i == 0 && label >= 0) {
+      // Print the label once.
+      line += android::base::StringPrintf("#%02d  ", label);
+    } else {
+      line += "     ";
     }
+    line += android::base::StringPrintf("%" PRIPTR "  %" PRIPTR, *sp, stack_data[i]);
 
-    const backtrace_map_t* map = backtrace->FindMap(stack_content);
-    const char* map_name;
-    if (!map) {
-      map_name = "";
-    } else {
-      map_name = map->name.c_str();
-    }
-    uintptr_t offset = 0;
-    std::string func_name(backtrace->GetFunctionName(stack_content, &offset));
-    if (!func_name.empty()) {
-      if (!i && label >= 0) {
+    backtrace_map_t map;
+    backtrace->FillInMap(stack_data[i], &map);
+    if (BacktraceMap::IsValid(map) && !map.name.empty()) {
+      line += "  " + map.name;
+      uintptr_t offset = 0;
+      std::string func_name(backtrace->GetFunctionName(stack_data[i], &offset));
+      if (!func_name.empty()) {
+        line += " (" + func_name;
         if (offset) {
-          _LOG(log, logtype::STACK, "    #%02d  %" PRIPTR "  %" PRIPTR "  %s (%s+%" PRIuPTR ")\n",
-               label, *sp, stack_content, map_name, func_name.c_str(), offset);
-        } else {
-          _LOG(log, logtype::STACK, "    #%02d  %" PRIPTR "  %" PRIPTR "  %s (%s)\n",
-               label, *sp, stack_content, map_name, func_name.c_str());
+          line += android::base::StringPrintf("+%" PRIuPTR, offset);
         }
-      } else {
-        if (offset) {
-          _LOG(log, logtype::STACK, "         %" PRIPTR "  %" PRIPTR "  %s (%s+%" PRIuPTR ")\n",
-               *sp, stack_content, map_name, func_name.c_str(), offset);
-        } else {
-          _LOG(log, logtype::STACK, "         %" PRIPTR "  %" PRIPTR "  %s (%s)\n",
-               *sp, stack_content, map_name, func_name.c_str());
-        }
-      }
-    } else {
-      if (!i && label >= 0) {
-        _LOG(log, logtype::STACK, "    #%02d  %" PRIPTR "  %" PRIPTR "  %s\n",
-             label, *sp, stack_content, map_name);
-      } else {
-        _LOG(log, logtype::STACK, "         %" PRIPTR "  %" PRIPTR "  %s\n",
-             *sp, stack_content, map_name);
+        line += ')';
       }
     }
+    _LOG(log, logtype::STACK, "%s\n", line.c_str());
 
     *sp += sizeof(word_t);
   }
@@ -325,6 +317,96 @@
   }
 }
 
+static std::string get_addr_string(uintptr_t addr) {
+  std::string addr_str;
+#if defined(__LP64__)
+  addr_str = android::base::StringPrintf("%08x'%08x",
+                                         static_cast<uint32_t>(addr >> 32),
+                                         static_cast<uint32_t>(addr & 0xffffffff));
+#else
+  addr_str = android::base::StringPrintf("%08x", addr);
+#endif
+  return addr_str;
+}
+
+static void dump_all_maps(Backtrace* backtrace, BacktraceMap* map, log_t* log, pid_t tid) {
+  bool print_fault_address_marker = false;
+  uintptr_t addr = 0;
+  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);
+    addr = reinterpret_cast<uintptr_t>(si.si_addr);
+  } else {
+    _LOG(log, logtype::ERROR, "Cannot get siginfo for %d: %s\n", tid, strerror(errno));
+  }
+
+  _LOG(log, logtype::MAPS, "\n");
+  if (!print_fault_address_marker) {
+    _LOG(log, logtype::MAPS, "memory map:\n");
+  } else {
+    _LOG(log, logtype::MAPS, "memory map: (fault address prefixed with --->)\n");
+    if (map->begin() != map->end() && addr < map->begin()->start) {
+      _LOG(log, logtype::MAPS, "--->Fault address falls at %s before any mapped regions\n",
+           get_addr_string(addr).c_str());
+      print_fault_address_marker = false;
+    }
+  }
+
+  std::string line;
+  for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
+    line = "    ";
+    if (print_fault_address_marker) {
+      if (addr < it->start) {
+        _LOG(log, logtype::MAPS, "--->Fault address falls at %s between mapped regions\n",
+             get_addr_string(addr).c_str());
+        print_fault_address_marker = false;
+      } else if (addr >= it->start && addr < it->end) {
+        line = "--->";
+        print_fault_address_marker = false;
+      }
+    }
+    line += get_addr_string(it->start) + '-' + get_addr_string(it->end - 1) + ' ';
+    if (it->flags & PROT_READ) {
+      line += 'r';
+    } else {
+      line += '-';
+    }
+    if (it->flags & PROT_WRITE) {
+      line += 'w';
+    } else {
+      line += '-';
+    }
+    if (it->flags & PROT_EXEC) {
+      line += 'x';
+    } else {
+      line += '-';
+    }
+    line += android::base::StringPrintf("  %8" PRIxPTR "  %8" PRIxPTR,
+                                        it->offset, it->end - it->start);
+    bool space_needed = true;
+    if (it->name.length() > 0) {
+      space_needed = false;
+      line += "  " + it->name;
+      std::string build_id;
+      if ((it->flags & PROT_READ) && elf_get_build_id(backtrace, it->start, &build_id)) {
+        line += " (BuildId: " + build_id + ")";
+      }
+    }
+    if (it->load_base != 0) {
+      if (space_needed) {
+        line += ' ';
+      }
+      line += android::base::StringPrintf(" (load base 0x%" PRIxPTR ")", it->load_base);
+    }
+    _LOG(log, logtype::MAPS, "%s\n", line.c_str());
+  }
+  if (print_fault_address_marker) {
+    _LOG(log, logtype::MAPS, "--->Fault address falls at %s after any mapped regions\n",
+         get_addr_string(addr).c_str());
+  }
+}
+
 static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log) {
   if (backtrace->NumFrames()) {
     _LOG(log, logtype::BACKTRACE, "\nbacktrace:\n");
@@ -335,53 +417,6 @@
   }
 }
 
-static void dump_map(log_t* log, const backtrace_map_t* map, bool fault_addr) {
-  _LOG(log, logtype::MAPS, "%s%" PRIPTR "-%" PRIPTR " %c%c%c  %7" PRIdPTR "  %s\n",
-         (fault_addr? "--->" : "    "), map->start, map->end - 1,
-         (map->flags & PROT_READ) ? 'r' : '-', (map->flags & PROT_WRITE) ? 'w' : '-',
-         (map->flags & PROT_EXEC) ? 'x' : '-',
-         (map->end - map->start), map->name.c_str());
-}
-
-static void dump_nearby_maps(BacktraceMap* map, log_t* log, pid_t tid) {
-  siginfo_t si;
-  memset(&si, 0, sizeof(si));
-  if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) {
-    _LOG(log, logtype::MAPS, "cannot get siginfo for %d: %s\n", tid, strerror(errno));
-    return;
-  }
-
-  bool has_fault_address = signal_has_si_addr(si.si_signo);
-  uintptr_t addr = reinterpret_cast<uintptr_t>(si.si_addr);
-
-  _LOG(log, logtype::MAPS, "\nmemory map: %s\n", has_fault_address ? "(fault address prefixed with --->)" : "");
-
-  if (has_fault_address && (addr < map->begin()->start)) {
-    _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " before any mapped regions\n", addr);
-  }
-
-  BacktraceMap::const_iterator prev = map->begin();
-  for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
-    if (addr >= (*prev).end && addr < (*it).start) {
-      _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " between mapped regions\n", addr);
-    }
-    prev = it;
-    bool in_map = has_fault_address && (addr >= (*it).start) && (addr < (*it).end);
-    dump_map(log, &*it, in_map);
-  }
-  if (has_fault_address && (addr >= (*prev).end)) {
-    _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " after any mapped regions\n", addr);
-  }
-}
-
-static void dump_thread(Backtrace* backtrace, log_t* log) {
-  dump_registers(log, backtrace->Tid());
-  dump_backtrace_and_stack(backtrace, log);
-
-  dump_memory_and_code(log, backtrace->Tid());
-  dump_nearby_maps(backtrace->GetMap(), log, backtrace->Tid());
-}
-
 // Return true if some thread is not detached cleanly
 static bool dump_sibling_thread_report(
     log_t* log, pid_t pid, pid_t tid, int* total_sleep_time_usec, BacktraceMap* map) {
@@ -425,9 +460,12 @@
     _LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
     dump_thread_info(log, pid, new_tid);
 
-    UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, new_tid, map));
+    dump_registers(log, new_tid);
+    std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, new_tid, map));
     if (backtrace->Unwind(0)) {
-      dump_thread(backtrace.get(), log);
+      dump_backtrace_and_stack(backtrace.get(), log);
+    } else {
+      ALOGE("Unwind of sibling failed: pid = %d, tid = %d", pid, new_tid);
     }
 
     log->current_tid = log->crashed_tid;
@@ -458,7 +496,7 @@
   }
 
   logger_list = android_logger_list_open(
-      android_name_to_log_id(filename), O_RDONLY | O_NONBLOCK, tail, pid);
+      android_name_to_log_id(filename), ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, tail, pid);
 
   if (!logger_list) {
     ALOGE("Unable to open %s: %s\n", filename, strerror(errno));
@@ -624,11 +662,18 @@
     dump_signal_info(log, tid, signal, si_code);
   }
 
-  UniquePtr<BacktraceMap> map(BacktraceMap::Create(pid));
-  UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
+  std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
+  dump_abort_message(backtrace.get(), log, abort_msg_address);
+  dump_registers(log, tid);
   if (backtrace->Unwind(0)) {
-    dump_abort_message(backtrace.get(), log, abort_msg_address);
-    dump_thread(backtrace.get(), log);
+    dump_backtrace_and_stack(backtrace.get(), log);
+  } else {
+    ALOGE("Unwind failed: pid = %d, tid = %d", pid, tid);
+  }
+  dump_memory_and_code(log, backtrace.get());
+  if (map.get() != nullptr) {
+    dump_all_maps(backtrace.get(), map.get(), log, tid);
   }
 
   if (want_logs) {
@@ -760,7 +805,7 @@
   *detach_failed = dump_crash(&log, pid, tid, signal, original_si_code, abort_msg_address,
                               dump_sibling_threads, total_sleep_time_usec);
 
-  ALOGI("\nTombstone written to: %s\n", path);
+  _LOG(&log, logtype::BACKTRACE, "\nTombstone written to: %s\n", path);
 
   // Either of these file descriptors can be -1, any error is ignored.
   close(amfd);
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index 12df1e6..236d667 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -27,25 +27,13 @@
 #include <sys/wait.h>
 
 #include <backtrace/Backtrace.h>
+#include <base/file.h>
+#include <base/stringprintf.h>
 #include <log/log.h>
 
 const int SLEEP_TIME_USEC = 50000;         // 0.05 seconds
 const int MAX_TOTAL_SLEEP_USEC = 10000000; // 10 seconds
 
-static int write_to_am(int fd, const char* buf, int len) {
-  int to_write = len;
-  while (to_write > 0) {
-    int written = TEMP_FAILURE_RETRY(write(fd, buf + len - to_write, to_write));
-    if (written < 0) {
-      // hard failure
-      ALOGE("AM write failure (%d / %s)\n", errno, strerror(errno));
-      return -1;
-    }
-    to_write -= written;
-  }
-  return len;
-}
-
 // Whitelist output desired in the logcat output.
 bool is_allowed_in_logcat(enum logtype ltype) {
   if ((ltype == ERROR)
@@ -81,11 +69,11 @@
   }
 
   if (write_to_logcat) {
-    __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_INFO, LOG_TAG, buf);
+    __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_FATAL, LOG_TAG, buf);
     if (write_to_activitymanager) {
-      int written = write_to_am(log->amfd, buf, len);
-      if (written <= 0) {
+      if (!android::base::WriteFully(log->amfd, buf, len)) {
         // timeout or other failure on write; stop informing the activity manager
+        ALOGE("AM write failed: %s", strerror(errno));
         log->amfd = -1;
       }
     }
@@ -132,78 +120,93 @@
   return -1;
 }
 
-#if defined (__mips__)
-#define DUMP_MEMORY_AS_ASCII 1
+#define MEMORY_BYTES_TO_DUMP 256
+#define MEMORY_BYTES_PER_LINE 16
+
+void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* fmt, ...) {
+  std::string log_msg;
+  va_list ap;
+  va_start(ap, fmt);
+  android::base::StringAppendV(&log_msg, fmt, ap);
+  va_end(ap);
+
+  // Align the address to sizeof(long) and start 32 bytes before the address.
+  addr &= ~(sizeof(long) - 1);
+  if (addr >= 4128) {
+    addr -= 32;
+  }
+
+  // Don't bother if the address looks too low, or looks too high.
+  if (addr < 4096 ||
+#if defined(__LP64__)
+      addr > 0x4000000000000000UL - MEMORY_BYTES_TO_DUMP) {
 #else
-#define DUMP_MEMORY_AS_ASCII 0
+      addr > 0xffff0000 - MEMORY_BYTES_TO_DUMP) {
 #endif
+    return;
+  }
 
-void dump_memory(log_t* log, pid_t tid, uintptr_t addr) {
-    char code_buffer[64];
-    char ascii_buffer[32];
-    uintptr_t p, end;
+  _LOG(log, logtype::MEMORY, "\n%s\n", log_msg.c_str());
 
-    p = addr & ~(sizeof(long) - 1);
-    /* Dump 32 bytes before addr */
-    p -= 32;
-    if (p > addr) {
-        /* catch underflow */
-        p = 0;
+  // Dump 256 bytes
+  uintptr_t data[MEMORY_BYTES_TO_DUMP/sizeof(uintptr_t)];
+  memset(data, 0, MEMORY_BYTES_TO_DUMP);
+  size_t bytes = backtrace->Read(addr, reinterpret_cast<uint8_t*>(data), sizeof(data));
+  if (bytes % sizeof(uintptr_t) != 0) {
+    // This should never happen, but just in case.
+    ALOGE("Bytes read %zu, is not a multiple of %zu", bytes, sizeof(uintptr_t));
+    bytes &= ~(sizeof(uintptr_t) - 1);
+  }
+
+  if (bytes < MEMORY_BYTES_TO_DUMP && bytes > 0) {
+    // Try to do one more read. This could happen if a read crosses a map, but
+    // the maps do not have any break between them. Only requires one extra
+    // read because a map has to contain at least one page, and the total
+    // number of bytes to dump is smaller than a page.
+    size_t bytes2 = backtrace->Read(addr + bytes, reinterpret_cast<uint8_t*>(data) + bytes,
+                                    sizeof(data) - bytes);
+    bytes += bytes2;
+    if (bytes2 > 0 && bytes % sizeof(uintptr_t) != 0) {
+      // This should never happen, but we'll try and continue any way.
+      ALOGE("Bytes after second read %zu, is not a multiple of %zu", bytes, sizeof(uintptr_t));
+      bytes &= ~(sizeof(uintptr_t) - 1);
     }
-    /* Dump 256 bytes */
-    end = p + 256;
-    /* catch overflow; 'end - p' has to be multiples of 16 */
-    while (end < p) {
-        end -= 16;
-    }
+  }
 
-    /* Dump the code around PC as:
-     *  addr             contents                           ascii
-     *  0000000000008d34 ef000000e8bd0090 e1b00000512fff1e  ............../Q
-     *  0000000000008d44 ea00b1f9e92d0090 e3a070fcef000000  ......-..p......
-     * On 32-bit machines, there are still 16 bytes per line but addresses and
-     * words are of course presented differently.
-     */
-    while (p < end) {
-        char* asc_out = ascii_buffer;
+  // Dump the code around memory as:
+  //  addr             contents                           ascii
+  //  0000000000008d34 ef000000e8bd0090 e1b00000512fff1e  ............../Q
+  //  0000000000008d44 ea00b1f9e92d0090 e3a070fcef000000  ......-..p......
+  // On 32-bit machines, there are still 16 bytes per line but addresses and
+  // words are of course presented differently.
+  uintptr_t* data_ptr = data;
+  for (size_t line = 0; line < MEMORY_BYTES_TO_DUMP / MEMORY_BYTES_PER_LINE; line++) {
+    std::string logline;
+    android::base::StringAppendF(&logline, "    %" PRIPTR, addr);
 
-        int len = snprintf(code_buffer, sizeof(code_buffer), "%" PRIPTR " ", p);
+    addr += MEMORY_BYTES_PER_LINE;
+    std::string ascii;
+    for (size_t i = 0; i < MEMORY_BYTES_PER_LINE / sizeof(uintptr_t); i++, data_ptr++) {
+      if (bytes >= sizeof(uintptr_t)) {
+        bytes -= sizeof(uintptr_t);
+        android::base::StringAppendF(&logline, " %" PRIPTR, *data_ptr);
 
-        for (size_t i = 0; i < 16/sizeof(long); i++) {
-            long data = ptrace(PTRACE_PEEKTEXT, tid, (void*)p, NULL);
-            if (data == -1 && errno != 0) {
-                // ptrace failed, probably because we're dumping memory in an
-                // unmapped or inaccessible page.
-#ifdef __LP64__
-                len += sprintf(code_buffer + len, "---------------- ");
-#else
-                len += sprintf(code_buffer + len, "-------- ");
-#endif
-            } else {
-                len += sprintf(code_buffer + len, "%" PRIPTR " ",
-                               static_cast<uintptr_t>(data));
-            }
-
-#if DUMP_MEMORY_AS_ASCII
-            for (size_t j = 0; j < sizeof(long); j++) {
-                /*
-                 * Our isprint() allows high-ASCII characters that display
-                 * differently (often badly) in different viewers, so we
-                 * just use a simpler test.
-                 */
-                char val = (data >> (j*8)) & 0xff;
-                if (val >= 0x20 && val < 0x7f) {
-                    *asc_out++ = val;
-                } else {
-                    *asc_out++ = '.';
-                }
-            }
-#endif
-            p += sizeof(long);
+        // Fill out the ascii string from the data.
+        uint8_t* ptr = reinterpret_cast<uint8_t*>(data_ptr);
+        for (size_t val = 0; val < sizeof(uintptr_t); val++, ptr++) {
+          if (*ptr >= 0x20 && *ptr < 0x7f) {
+            ascii += *ptr;
+          } else {
+            ascii += '.';
+          }
         }
-        *asc_out = '\0';
-        _LOG(log, logtype::MEMORY, "    %s %s\n", code_buffer, ascii_buffer);
+      } else {
+        logline += ' ' + std::string(sizeof(uintptr_t) * 2, '-');
+        ascii += std::string(sizeof(uintptr_t), '.');
+      }
     }
+    _LOG(log, logtype::MEMORY, "%s  %s\n", logline.c_str(), ascii.c_str());
+  }
 }
 
 bool pid_contains_tid(pid_t pid, pid_t tid) {
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index 9f46982..e8ec7ef 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -21,13 +21,17 @@
 #include <stdbool.h>
 #include <sys/types.h>
 
+#include <backtrace/Backtrace.h>
+
 // Figure out the abi based on defined macros.
 #if defined(__arm__)
 #define ABI_STRING "arm"
 #elif defined(__aarch64__)
 #define ABI_STRING "arm64"
-#elif defined(__mips__)
+#elif defined(__mips__) && !defined(__LP64__)
 #define ABI_STRING "mips"
+#elif defined(__mips__) && defined(__LP64__)
+#define ABI_STRING "mips64"
 #elif defined(__i386__)
 #define ABI_STRING "x86"
 #elif defined(__x86_64__)
@@ -73,7 +77,7 @@
 
 int wait_for_sigstop(pid_t, int*, bool*);
 
-void dump_memory(log_t* log, pid_t tid, uintptr_t addr);
+void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* fmt, ...);
 
 bool pid_contains_tid(pid_t pid, pid_t tid);
 
diff --git a/debuggerd/x86/machine.cpp b/debuggerd/x86/machine.cpp
index 57330c1..c5f9259 100644
--- a/debuggerd/x86/machine.cpp
+++ b/debuggerd/x86/machine.cpp
@@ -14,18 +14,31 @@
  * limitations under the License.
  */
 
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
 #include <errno.h>
-#include <sys/types.h>
+#include <stdint.h>
+#include <string.h>
 #include <sys/ptrace.h>
 
-#include "../utility.h"
-#include "../machine.h"
+#include <backtrace/Backtrace.h>
 
-void dump_memory_and_code(log_t*, pid_t) {
+#include "machine.h"
+#include "utility.h"
+
+void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
+  struct pt_regs r;
+  if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r) == -1) {
+    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
+    return;
+  }
+
+  dump_memory(log, backtrace, static_cast<uintptr_t>(r.eax), "memory near eax:");
+  dump_memory(log, backtrace, static_cast<uintptr_t>(r.ebx), "memory near ebx:");
+  dump_memory(log, backtrace, static_cast<uintptr_t>(r.ecx), "memory near ecx:");
+  dump_memory(log, backtrace, static_cast<uintptr_t>(r.edx), "memory near edx:");
+  dump_memory(log, backtrace, static_cast<uintptr_t>(r.esi), "memory near esi:");
+  dump_memory(log, backtrace, static_cast<uintptr_t>(r.edi), "memory near edi:");
+
+  dump_memory(log, backtrace, static_cast<uintptr_t>(r.eip), "code around eip:");
 }
 
 void dump_registers(log_t* log, pid_t tid) {
@@ -34,6 +47,7 @@
     _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
     return;
   }
+
   _LOG(log, logtype::REGISTERS, "    eax %08lx  ebx %08lx  ecx %08lx  edx %08lx\n",
        r.eax, r.ebx, r.ecx, r.edx);
   _LOG(log, logtype::REGISTERS, "    esi %08lx  edi %08lx\n",
diff --git a/debuggerd/x86_64/machine.cpp b/debuggerd/x86_64/machine.cpp
old mode 100755
new mode 100644
index af4f35a..4f09a5d
--- a/debuggerd/x86_64/machine.cpp
+++ b/debuggerd/x86_64/machine.cpp
@@ -14,38 +14,51 @@
 ** limitations under the License.
 */
 
-#include <stddef.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
 #include <errno.h>
-#include <sys/types.h>
+#include <stdint.h>
 #include <sys/ptrace.h>
+#include <string.h>
 #include <sys/user.h>
 
-#include "../utility.h"
-#include "../machine.h"
+#include <backtrace/Backtrace.h>
 
-void dump_memory_and_code(log_t*, pid_t) {
+#include "machine.h"
+#include "utility.h"
+
+void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
+  struct user_regs_struct r;
+  if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r) == -1) {
+    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
+    return;
+  }
+
+  dump_memory(log, backtrace, static_cast<uintptr_t>(r.rax), "memory near rax:");
+  dump_memory(log, backtrace, static_cast<uintptr_t>(r.rbx), "memory near rbx:");
+  dump_memory(log, backtrace, static_cast<uintptr_t>(r.rcx), "memory near rcx:");
+  dump_memory(log, backtrace, static_cast<uintptr_t>(r.rdx), "memory near rdx:");
+  dump_memory(log, backtrace, static_cast<uintptr_t>(r.rsi), "memory near rsi:");
+  dump_memory(log, backtrace, static_cast<uintptr_t>(r.rdi), "memory near rdi:");
+
+  dump_memory(log, backtrace, static_cast<uintptr_t>(r.rip), "code around rip:");
 }
 
 void dump_registers(log_t* log, pid_t tid) {
-    struct user_regs_struct r;
-    if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
-        _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
-        return;
-    }
-    _LOG(log, logtype::REGISTERS, "    rax %016lx  rbx %016lx  rcx %016lx  rdx %016lx\n",
-         r.rax, r.rbx, r.rcx, r.rdx);
-    _LOG(log, logtype::REGISTERS, "    rsi %016lx  rdi %016lx\n",
-         r.rsi, r.rdi);
-    _LOG(log, logtype::REGISTERS, "    r8  %016lx  r9  %016lx  r10 %016lx  r11 %016lx\n",
-         r.r8, r.r9, r.r10, r.r11);
-    _LOG(log, logtype::REGISTERS, "    r12 %016lx  r13 %016lx  r14 %016lx  r15 %016lx\n",
-         r.r12, r.r13, r.r14, r.r15);
-    _LOG(log, logtype::REGISTERS, "    cs  %016lx  ss  %016lx\n",
-         r.cs, r.ss);
-    _LOG(log, logtype::REGISTERS, "    rip %016lx  rbp %016lx  rsp %016lx  eflags %016lx\n",
-         r.rip, r.rbp, r.rsp, r.eflags);
+  struct user_regs_struct r;
+  if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
+    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
+    return;
+  }
+
+  _LOG(log, logtype::REGISTERS, "    rax %016lx  rbx %016lx  rcx %016lx  rdx %016lx\n",
+       r.rax, r.rbx, r.rcx, r.rdx);
+  _LOG(log, logtype::REGISTERS, "    rsi %016lx  rdi %016lx\n",
+       r.rsi, r.rdi);
+  _LOG(log, logtype::REGISTERS, "    r8  %016lx  r9  %016lx  r10 %016lx  r11 %016lx\n",
+       r.r8, r.r9, r.r10, r.r11);
+  _LOG(log, logtype::REGISTERS, "    r12 %016lx  r13 %016lx  r14 %016lx  r15 %016lx\n",
+       r.r12, r.r13, r.r14, r.r15);
+  _LOG(log, logtype::REGISTERS, "    cs  %016lx  ss  %016lx\n",
+       r.cs, r.ss);
+  _LOG(log, logtype::REGISTERS, "    rip %016lx  rbp %016lx  rsp %016lx  eflags %016lx\n",
+       r.rip, r.rbp, r.rsp, r.eflags);
 }
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index e11691f..66a470a 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -14,15 +14,20 @@
 
 LOCAL_PATH:= $(call my-dir)
 
+fastboot_version := $(shell git -C $(LOCAL_PATH) rev-parse --short=12 HEAD 2>/dev/null)-android
+
 include $(CLEAR_VARS)
 
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \
   $(LOCAL_PATH)/../../extras/ext4_utils \
   $(LOCAL_PATH)/../../extras/f2fs_utils
-LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c util.c fs.c
+LOCAL_SRC_FILES := protocol.c engine.c bootimg_utils.cpp fastboot.cpp util.c fs.c
 LOCAL_MODULE := fastboot
 LOCAL_MODULE_TAGS := debug
-LOCAL_CFLAGS += -std=gnu99 -Werror
+LOCAL_CONLYFLAGS += -std=gnu99
+LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
+
+LOCAL_CFLAGS += -DFASTBOOT_REVISION='"$(fastboot_version)"'
 
 ifeq ($(HOST_OS),linux)
   LOCAL_SRC_FILES += usb_linux.c util_linux.c
@@ -30,8 +35,8 @@
 
 ifeq ($(HOST_OS),darwin)
   LOCAL_SRC_FILES += usb_osx.c util_osx.c
-  LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit \
-	-framework Carbon
+  LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
+  LOCAL_CFLAGS += -Wno-unused-parameter
 endif
 
 ifeq ($(HOST_OS),windows)
@@ -51,11 +56,13 @@
 
 LOCAL_STATIC_LIBRARIES := \
     $(EXTRA_STATIC_LIBS) \
-    libzipfile \
-    libunz \
+    libziparchive-host \
     libext4_utils_host \
     libsparse_host \
-    libz
+    libutils \
+    liblog \
+    libz \
+    libbase
 
 ifneq ($(HOST_OS),windows)
 LOCAL_STATIC_LIBRARIES += libselinux
@@ -71,6 +78,16 @@
 LOCAL_STATIC_LIBRARIES += libf2fs_utils_host libf2fs_ioutils_host libf2fs_dlutils_host
 endif
 
+# libc++ not available on windows yet
+ifneq ($(HOST_OS),windows)
+    LOCAL_CXX_STL := libc++_static
+endif
+
+# Don't add anything here, we don't want additional shared dependencies
+# on the host fastboot tool, and shared libraries that link against libc++
+# will violate ODR
+LOCAL_SHARED_LIBRARIES :=
+
 include $(BUILD_HOST_EXECUTABLE)
 
 my_dist_files := $(LOCAL_BUILT_MODULE)
diff --git a/fastboot/bootimg.c b/fastboot/bootimg_utils.cpp
similarity index 95%
rename from fastboot/bootimg.c
rename to fastboot/bootimg_utils.cpp
index 240784f..d8905a6 100644
--- a/fastboot/bootimg.c
+++ b/fastboot/bootimg_utils.cpp
@@ -26,12 +26,12 @@
  * SUCH DAMAGE.
  */
 
+#include "bootimg_utils.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include <bootimg.h>
-
 void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline)
 {
     strcpy((char*) h->cmdline, cmdline);
@@ -47,7 +47,6 @@
     unsigned ramdisk_actual;
     unsigned second_actual;
     unsigned page_mask;
-    boot_img_hdr *hdr;
 
     page_mask = page_size - 1;
 
@@ -57,9 +56,8 @@
 
     *bootimg_size = page_size + kernel_actual + ramdisk_actual + second_actual;
 
-    hdr = calloc(*bootimg_size, 1);
-
-    if(hdr == 0) {
+    boot_img_hdr* hdr = reinterpret_cast<boot_img_hdr*>(calloc(*bootimg_size, 1));
+    if (hdr == 0) {
         return hdr;
     }
 
diff --git a/fastbootd/socket_client.h b/fastboot/bootimg_utils.h
similarity index 66%
copy from fastbootd/socket_client.h
copy to fastboot/bootimg_utils.h
index 4481ff2..b1a86cd 100644
--- a/fastbootd/socket_client.h
+++ b/fastboot/bootimg_utils.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2013, Google Inc.
+ * Copyright (C) 2015 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -11,9 +11,6 @@
  *    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
@@ -29,9 +26,24 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _FASTBOOTD_SOCKET_CLIENT_H
-#define _FASTBOOTD_SOCKET_CLIENT_H
+#ifndef _FASTBOOT_BOOTIMG_UTILS_H_
+#define _FASTBOOT_BOOTIMG_UTILS_H_
 
-void run_socket_client();
+#include <bootimg.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline);
+boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, unsigned kernel_offset,
+                        void *ramdisk, unsigned ramdisk_size, unsigned ramdisk_offset,
+                        void *second, unsigned second_size, unsigned second_offset,
+                        unsigned page_size, unsigned base, unsigned tags_offset,
+                        unsigned *bootimg_size);
+
+#if defined(__cplusplus)
+}
+#endif
 
 #endif
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.cpp
similarity index 79%
rename from fastboot/fastboot.c
rename to fastboot/fastboot.cpp
index 43d05aa..be80cce 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.cpp
@@ -44,10 +44,10 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <bootimg.h>
 #include <sparse/sparse.h>
-#include <zipfile/zipfile.h>
+#include <ziparchive/zip_archive.h>
 
+#include "bootimg_utils.h"
 #include "fastboot.h"
 #include "fs.h"
 
@@ -59,15 +59,6 @@
 
 char cur_product[FB_RESPONSE_SZ + 1];
 
-void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline);
-
-boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, unsigned kernel_offset,
-                        void *ramdisk, unsigned ramdisk_size, unsigned ramdisk_offset,
-                        void *second, unsigned second_size, unsigned second_offset,
-                        unsigned page_size, unsigned base, unsigned tags_offset,
-                        unsigned *bootimg_size);
-
-static usb_handle *usb = 0;
 static const char *serial = 0;
 static const char *product = 0;
 static const char *cmdline = 0;
@@ -106,12 +97,10 @@
     {"vendor.img", "vendor.sig", "vendor", true},
 };
 
-void get_my_path(char *path);
-
 char *find_item(const char *item, const char *product)
 {
     char *dir;
-    char *fn;
+    const char *fn;
     char path[PATH_MAX + 128];
 
     if(!strcmp(item,"boot")) {
@@ -234,7 +223,7 @@
 int list_devices_callback(usb_ifc_info *info)
 {
     if (match_fastboot_with_serial(info, NULL) == 0) {
-        char* serial = info->serial_number;
+        const char* serial = info->serial_number;
         if (!info->writable) {
             serial = "no permissions"; // like "adb devices"
         }
@@ -244,7 +233,7 @@
         // output compatible with "adb devices"
         if (!long_listing) {
             printf("%s\tfastboot\n", serial);
-        } else if (!info->device_path) {
+        } else if (strcmp("", info->device_path) == 0) {
             printf("%-22s fastboot\n", serial);
         } else {
             printf("%-22s fastboot %s\n", serial, info->device_path);
@@ -290,17 +279,27 @@
             "  flashall                                 flash boot, system, vendor and if found,\n"
             "                                           recovery\n"
             "  flash <partition> [ <filename> ]         write a file to a flash partition\n"
+            "  flashing lock                            locks the device. Prevents flashing"
+            "                                           partitions\n"
+            "  flashing unlock                          unlocks the device. Allows user to"
+            "                                           flash any partition except the ones"
+            "                                           that are related to bootloader\n"
+            "  flashing lock_critical                   Prevents flashing bootloader related"
+            "                                           partitions\n"
+            "  flashing unlock_critical                 Enables flashing bootloader related"
+            "                                           partitions\n"
+            "  flashing get_unlock_ability              Queries bootloader to see if the"
+            "                                           device is unlocked\n"
             "  erase <partition>                        erase a flash partition\n"
             "  format[:[<fs type>][:[<size>]] <partition> format a flash partition.\n"
             "                                           Can override the fs type and/or\n"
             "                                           size the bootloader reports.\n"
             "  getvar <variable>                        display a bootloader variable\n"
-            "  boot <kernel> [ <ramdisk> [ <second> ] ] download and boot kernel\n"
-            "  flash:raw boot <kernel> [ <ramdisk> [ <second> ] ] create bootimage and \n"
-            "                                           flash it\n"
+            "  boot <kernel> [ <ramdisk> ]              download and boot kernel\n"
+            "  flash:raw boot <kernel> [ <ramdisk> ]    create bootimage and flash it\n"
             "  devices                                  list all connected devices\n"
             "  continue                                 continue with autoboot\n"
-            "  reboot                                   reboot device normally\n"
+            "  reboot [bootloader]                      reboot device, optionally into bootloader\n"
             "  reboot-bootloader                        reboot device into bootloader\n"
             "  help                                     show this help message\n"
             "\n"
@@ -325,11 +324,10 @@
 }
 
 void *load_bootable_image(const char *kernel, const char *ramdisk,
-                          const char *secondstage, unsigned *sz,
-                          const char *cmdline)
+                          unsigned *sz, const char *cmdline)
 {
-    void *kdata = 0, *rdata = 0, *sdata = 0;
-    unsigned ksize = 0, rsize = 0, ssize = 0;
+    void *kdata = 0, *rdata = 0;
+    unsigned ksize = 0, rsize = 0;
     void *bdata;
     unsigned bsize;
 
@@ -365,18 +363,10 @@
         }
     }
 
-    if (secondstage) {
-        sdata = load_file(secondstage, &ssize);
-        if(sdata == 0) {
-            fprintf(stderr,"cannot load '%s': %s\n", secondstage, strerror(errno));
-            return  0;
-        }
-    }
-
     fprintf(stderr,"creating boot image...\n");
     bdata = mkbootimg(kdata, ksize, kernel_offset,
                       rdata, rsize, ramdisk_offset,
-                      sdata, ssize, second_offset,
+                      0, 0, second_offset,
                       page_size, base_addr, tags_offset, &bsize);
     if(bdata == 0) {
         fprintf(stderr,"failed to create boot.img\n");
@@ -389,30 +379,26 @@
     return bdata;
 }
 
-void *unzip_file(zipfile_t zip, const char *name, unsigned *sz)
+static void* unzip_file(ZipArchiveHandle zip, const char* entry_name, unsigned* sz)
 {
-    void *data;
-    zipentry_t entry;
-    unsigned datasz;
-
-    entry = lookup_zipentry(zip, name);
-    if (entry == NULL) {
-        fprintf(stderr, "archive does not contain '%s'\n", name);
+    ZipEntryName zip_entry_name(entry_name);
+    ZipEntry zip_entry;
+    if (FindEntry(zip, zip_entry_name, &zip_entry) != 0) {
+        fprintf(stderr, "archive does not contain '%s'\n", entry_name);
         return 0;
     }
 
-    *sz = get_zipentry_size(entry);
+    *sz = zip_entry.uncompressed_length;
 
-    datasz = *sz * 1.001;
-    data = malloc(datasz);
-
-    if(data == 0) {
-        fprintf(stderr, "failed to allocate %d bytes\n", *sz);
+    uint8_t* data = reinterpret_cast<uint8_t*>(malloc(zip_entry.uncompressed_length));
+    if (data == NULL) {
+        fprintf(stderr, "failed to allocate %u bytes for '%s'\n", *sz, entry_name);
         return 0;
     }
 
-    if (decompress_zipentry(entry, data, datasz)) {
-        fprintf(stderr, "failed to unzip '%s' from archive\n", name);
+    int error = ExtractToMemory(zip, &zip_entry, data, zip_entry.uncompressed_length);
+    if (error != 0) {
+        fprintf(stderr, "failed to extract '%s': %s\n", entry_name, ErrorCodeString(error));
         free(data);
         return 0;
     }
@@ -420,27 +406,57 @@
     return data;
 }
 
-static int unzip_to_file(zipfile_t zip, char *name)
-{
-    int fd;
-    char *data;
-    unsigned sz;
+#if defined(_WIN32)
 
-    fd = fileno(tmpfile());
-    if (fd < 0) {
+// TODO: move this to somewhere it can be shared.
+
+#include <windows.h>
+
+// Windows' tmpfile(3) requires administrator rights because
+// it creates temporary files in the root directory.
+static FILE* win32_tmpfile() {
+    char temp_path[PATH_MAX];
+    DWORD nchars = GetTempPath(sizeof(temp_path), temp_path);
+    if (nchars == 0 || nchars >= sizeof(temp_path)) {
+        fprintf(stderr, "GetTempPath failed, error %ld\n", GetLastError());
+        return nullptr;
+    }
+
+    char filename[PATH_MAX];
+    if (GetTempFileName(temp_path, "fastboot", 0, filename) == 0) {
+        fprintf(stderr, "GetTempFileName failed, error %ld\n", GetLastError());
+        return nullptr;
+    }
+
+    return fopen(filename, "w+bTD");
+}
+
+#define tmpfile win32_tmpfile
+
+#endif
+
+static int unzip_to_file(ZipArchiveHandle zip, char* entry_name) {
+    FILE* fp = tmpfile();
+    if (fp == NULL) {
+        fprintf(stderr, "failed to create temporary file for '%s': %s\n",
+                entry_name, strerror(errno));
         return -1;
     }
 
-    data = unzip_file(zip, name, &sz);
-    if (data == 0) {
+    ZipEntryName zip_entry_name(entry_name);
+    ZipEntry zip_entry;
+    if (FindEntry(zip, zip_entry_name, &zip_entry) != 0) {
+        fprintf(stderr, "archive does not contain '%s'\n", entry_name);
         return -1;
     }
 
-    if (write(fd, data, sz) != (ssize_t)sz) {
-        fd = -1;
+    int fd = fileno(fp);
+    int error = ExtractEntryToFile(zip, &zip_entry, fd);
+    if (error != 0) {
+        fprintf(stderr, "failed to extract '%s': %s\n", entry_name, ErrorCodeString(error));
+        return -1;
     }
 
-    free(data);
     lseek(fd, 0, SEEK_SET);
     return fd;
 }
@@ -461,7 +477,6 @@
 static int setup_requirement_line(char *name)
 {
     char *val[MAX_OPTIONS];
-    const char **out;
     char *prod = NULL;
     unsigned n, count;
     char *x;
@@ -501,10 +516,11 @@
     name = strip(name);
     if (name == 0) return -1;
 
-        /* work around an unfortunate name mismatch */
-    if (!strcmp(name,"board")) name = "product";
+    const char* var = name;
+    // Work around an unfortunate name mismatch.
+    if (!strcmp(name,"board")) var = "product";
 
-    out = malloc(sizeof(char*) * count);
+    const char** out = reinterpret_cast<const char**>(malloc(sizeof(char*) * count));
     if (out == 0) return -1;
 
     for(n = 0; n < count; n++) {
@@ -518,7 +534,7 @@
         }
     }
 
-    fb_queue_require(prod, name, invert, n, out);
+    fb_queue_require(prod, var, invert, n, out);
     return 0;
 }
 
@@ -551,21 +567,17 @@
 
 static struct sparse_file **load_sparse_files(int fd, int max_size)
 {
-    struct sparse_file *s;
-    int files;
-    struct sparse_file **out_s;
-
-    s = sparse_file_import_auto(fd, false);
+    struct sparse_file* s = sparse_file_import_auto(fd, false, true);
     if (!s) {
         die("cannot sparse read file\n");
     }
 
-    files = sparse_file_resparse(s, max_size, NULL, 0);
+    int files = sparse_file_resparse(s, max_size, NULL, 0);
     if (files < 0) {
         die("Failed to resparse\n");
     }
 
-    out_s = calloc(sizeof(struct sparse_file *), files + 1);
+    sparse_file** out_s = reinterpret_cast<sparse_file**>(calloc(sizeof(struct sparse_file *), files + 1));
     if (!out_s) {
         die("Failed to allocate sparse file array\n");
     }
@@ -625,7 +637,7 @@
  * erase partitions of type ext4 before flashing a filesystem so no stale
  * inodes are left lying around.  Otherwise, e2fsck gets very upset.
  */
-static int needs_erase(const char *part)
+static int needs_erase(usb_handle* usb, const char *part)
 {
     /* The function fb_format_supported() currently returns the value
      * we want, so just call it.
@@ -682,11 +694,11 @@
 
 static void flash_buf(const char *pname, struct fastboot_buffer *buf)
 {
-    struct sparse_file **s;
+    sparse_file** s;
 
     switch (buf->type) {
         case FB_BUFFER_SPARSE:
-            s = buf->data;
+            s = reinterpret_cast<sparse_file**>(buf->data);
             while (*s) {
                 int64_t sz64 = sparse_file_len(*s, true, false);
                 fb_queue_flash_sparse(pname, *s++, sz64);
@@ -710,66 +722,51 @@
     flash_buf(pname, &buf);
 }
 
-void do_update_signature(zipfile_t zip, char *fn)
+void do_update_signature(ZipArchiveHandle zip, char *fn)
 {
-    void *data;
     unsigned sz;
-    data = unzip_file(zip, fn, &sz);
+    void* data = unzip_file(zip, fn, &sz);
     if (data == 0) return;
     fb_queue_download("signature", data, sz);
     fb_queue_command("signature", "installing signature");
 }
 
-void do_update(usb_handle *usb, char *fn, int erase_first)
+void do_update(usb_handle *usb, const char *filename, int erase_first)
 {
-    void *zdata;
-    unsigned zsize;
-    void *data;
-    unsigned sz;
-    zipfile_t zip;
-    int fd;
-    int rc;
-    struct fastboot_buffer buf;
-    size_t i;
-
     queue_info_dump();
 
     fb_queue_query_save("product", cur_product, sizeof(cur_product));
 
-    zdata = load_file(fn, &zsize);
-    if (zdata == 0) die("failed to load '%s': %s", fn, strerror(errno));
-
-    zip = init_zipfile(zdata, zsize);
-    if(zip == 0) die("failed to access zipdata in '%s'");
-
-    data = unzip_file(zip, "android-info.txt", &sz);
-    if (data == 0) {
-        char *tmp;
-            /* fallback for older zipfiles */
-        data = unzip_file(zip, "android-product.txt", &sz);
-        if ((data == 0) || (sz < 1)) {
-            die("update package has no android-info.txt or android-product.txt");
-        }
-        tmp = malloc(sz + 128);
-        if (tmp == 0) die("out of memory");
-        sprintf(tmp,"board=%sversion-baseband=0.66.04.19\n",(char*)data);
-        data = tmp;
-        sz = strlen(tmp);
+    ZipArchiveHandle zip;
+    int error = OpenArchive(filename, &zip);
+    if (error != 0) {
+        CloseArchive(zip);
+        die("failed to open zip file '%s': %s", filename, ErrorCodeString(error));
     }
 
-    setup_requirements(data, sz);
+    unsigned sz;
+    void* data = unzip_file(zip, "android-info.txt", &sz);
+    if (data == 0) {
+        CloseArchive(zip);
+        die("update package '%s' has no android-info.txt", filename);
+    }
 
-    for (i = 0; i < ARRAY_SIZE(images); i++) {
-        fd = unzip_to_file(zip, images[i].img_name);
-        if (fd < 0) {
-            if (images[i].is_optional)
+    setup_requirements(reinterpret_cast<char*>(data), sz);
+
+    for (size_t i = 0; i < ARRAY_SIZE(images); ++i) {
+        int fd = unzip_to_file(zip, images[i].img_name);
+        if (fd == -1) {
+            if (images[i].is_optional) {
                 continue;
-            die("update package missing %s", images[i].img_name);
+            }
+            CloseArchive(zip);
+            exit(1); // unzip_to_file already explained why.
         }
-        rc = load_buf_fd(usb, fd, &buf);
+        fastboot_buffer buf;
+        int rc = load_buf_fd(usb, fd, &buf);
         if (rc) die("cannot load %s from flash", images[i].img_name);
         do_update_signature(zip, images[i].sig_name);
-        if (erase_first && needs_erase(images[i].part_name)) {
+        if (erase_first && needs_erase(usb, images[i].part_name)) {
             fb_queue_erase(images[i].part_name);
         }
         flash_buf(images[i].part_name, &buf);
@@ -778,6 +775,8 @@
          * program exits.
          */
     }
+
+    CloseArchive(zip);
 }
 
 void do_send_signature(char *fn)
@@ -800,31 +799,29 @@
 
 void do_flashall(usb_handle *usb, int erase_first)
 {
-    char *fname;
-    void *data;
-    unsigned sz;
-    struct fastboot_buffer buf;
-    size_t i;
-
     queue_info_dump();
 
     fb_queue_query_save("product", cur_product, sizeof(cur_product));
 
-    fname = find_item("info", product);
+    char* fname = find_item("info", product);
     if (fname == 0) die("cannot find android-info.txt");
-    data = load_file(fname, &sz);
-    if (data == 0) die("could not load android-info.txt: %s", strerror(errno));
-    setup_requirements(data, sz);
 
-    for (i = 0; i < ARRAY_SIZE(images); i++) {
+    unsigned sz;
+    void* data = load_file(fname, &sz);
+    if (data == 0) die("could not load android-info.txt: %s", strerror(errno));
+
+    setup_requirements(reinterpret_cast<char*>(data), sz);
+
+    for (size_t i = 0; i < ARRAY_SIZE(images); i++) {
         fname = find_item(images[i].part_name, product);
+        fastboot_buffer buf;
         if (load_buf(usb, fname, &buf)) {
             if (images[i].is_optional)
                 continue;
             die("could not load %s\n", images[i].img_name);
         }
         do_send_signature(fname);
-        if (erase_first && needs_erase(images[i].part_name)) {
+        if (erase_first && needs_erase(usb, images[i].part_name)) {
             fb_queue_erase(images[i].part_name);
         }
         flash_buf(images[i].part_name, &buf);
@@ -892,7 +889,8 @@
     return num;
 }
 
-void fb_perform_format(const char *partition, int skip_if_not_supported,
+void fb_perform_format(usb_handle* usb,
+                       const char *partition, int skip_if_not_supported,
                        const char *type_override, const char *size_override)
 {
     char pTypeBuff[FB_RESPONSE_SZ + 1], pSizeBuff[FB_RESPONSE_SZ + 1];
@@ -988,6 +986,7 @@
     unsigned sz;
     int status;
     int c;
+    int longindex;
 
     const struct option longopts[] = {
         {"base", required_argument, 0, 'b'},
@@ -995,14 +994,16 @@
         {"page_size", required_argument, 0, 'n'},
         {"ramdisk_offset", required_argument, 0, 'r'},
         {"tags_offset", required_argument, 0, 't'},
-        {"help", 0, 0, 'h'},
+        {"help", no_argument, 0, 'h'},
+        {"unbuffered", no_argument, 0, 0},
+        {"version", no_argument, 0, 0},
         {0, 0, 0, 0}
     };
 
     serial = getenv("ANDROID_SERIAL");
 
     while (1) {
-        c = getopt_long(argc, argv, "wub:k:n:r:t:s:S:lp:c:i:m:h", longopts, NULL);
+        c = getopt_long(argc, argv, "wub:k:n:r:t:s:S:lp:c:i:m:h", longopts, &longindex);
         if (c < 0) {
             break;
         }
@@ -1063,6 +1064,15 @@
             break;
         case '?':
             return 1;
+        case 0:
+            if (strcmp("unbuffered", longopts[longindex].name) == 0) {
+                setvbuf(stdout, NULL, _IONBF, 0);
+                setvbuf(stderr, NULL, _IONBF, 0);
+            } else if (strcmp("version", longopts[longindex].name) == 0) {
+                fprintf(stdout, "fastboot version %s\n", FASTBOOT_REVISION);
+                return 0;
+            }
+            break;
         default:
             abort();
         }
@@ -1087,7 +1097,7 @@
         return 0;
     }
 
-    usb = open_device();
+    usb_handle* usb = open_device();
 
     while (argc > 0) {
         if(!strcmp(*argv, "getvar")) {
@@ -1129,10 +1139,10 @@
             }
             if (type_override && !type_override[0]) type_override = NULL;
             if (size_override && !size_override[0]) size_override = NULL;
-            if (erase_first && needs_erase(argv[1])) {
+            if (erase_first && needs_erase(usb, argv[1])) {
                 fb_queue_erase(argv[1]);
             }
-            fb_perform_format(argv[1], 0, type_override, size_override);
+            fb_perform_format(usb, argv[1], 0, type_override, size_override);
             skip(2);
         } else if(!strcmp(*argv, "signature")) {
             require(2);
@@ -1145,6 +1155,14 @@
         } else if(!strcmp(*argv, "reboot")) {
             wants_reboot = 1;
             skip(1);
+            if (argc > 0) {
+                if (!strcmp(*argv, "bootloader")) {
+                    wants_reboot = 0;
+                    wants_reboot_bootloader = 1;
+                    skip(1);
+                }
+            }
+            require(0);
         } else if(!strcmp(*argv, "reboot-bootloader")) {
             wants_reboot_bootloader = 1;
             skip(1);
@@ -1154,7 +1172,6 @@
         } else if(!strcmp(*argv, "boot")) {
             char *kname = 0;
             char *rname = 0;
-            char *sname = 0;
             skip(1);
             if (argc > 0) {
                 kname = argv[0];
@@ -1164,11 +1181,7 @@
                 rname = argv[0];
                 skip(1);
             }
-            if (argc > 0) {
-                sname = argv[0];
-                skip(1);
-            }
-            data = load_bootable_image(kname, rname, sname, &sz, cmdline);
+            data = load_bootable_image(kname, rname, &sz, cmdline);
             if (data == 0) return 1;
             fb_queue_download("boot.img", data, sz);
             fb_queue_command("boot", "booting");
@@ -1184,7 +1197,7 @@
                 skip(2);
             }
             if (fname == 0) die("cannot determine image filename for '%s'", pname);
-            if (erase_first && needs_erase(pname)) {
+            if (erase_first && needs_erase(usb, pname)) {
                 fb_queue_erase(pname);
             }
             do_flash(usb, pname, fname);
@@ -1192,18 +1205,14 @@
             char *pname = argv[1];
             char *kname = argv[2];
             char *rname = 0;
-            char *sname = 0;
             require(3);
-            skip(3);
-            if (argc > 0) {
-                rname = argv[0];
-                skip(1);
+            if(argc > 3) {
+                rname = argv[3];
+                skip(4);
+            } else {
+                skip(3);
             }
-            if (argc > 0) {
-                sname = argv[0];
-                skip(1);
-            }
-            data = load_bootable_image(kname, rname, sname, &sz, cmdline);
+            data = load_bootable_image(kname, rname, &sz, cmdline);
             if (data == 0) die("cannot load bootable image");
             fb_queue_flash(pname, data, sz);
         } else if(!strcmp(*argv, "flashall")) {
@@ -1221,6 +1230,16 @@
             wants_reboot = 1;
         } else if(!strcmp(*argv, "oem")) {
             argc = do_oem_command(argc, argv);
+        } else if(!strcmp(*argv, "flashing") && argc == 2) {
+            if(!strcmp(*(argv+1), "unlock") || !strcmp(*(argv+1), "lock")
+               || !strcmp(*(argv+1), "unlock_critical")
+               || !strcmp(*(argv+1), "lock_critical")
+               || !strcmp(*(argv+1), "get_unlock_ability")) {
+              argc = do_oem_command(argc, argv);
+            } else {
+              usage();
+              return 1;
+            }
         } else {
             usage();
             return 1;
@@ -1229,9 +1248,9 @@
 
     if (wants_wipe) {
         fb_queue_erase("userdata");
-        fb_perform_format("userdata", 1, NULL, NULL);
+        fb_perform_format(usb, "userdata", 1, NULL, NULL);
         fb_queue_erase("cache");
-        fb_perform_format("cache", 1, NULL, NULL);
+        fb_perform_format(usb, "cache", 1, NULL, NULL);
     }
     if (wants_reboot) {
         fb_queue_reboot();
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index fc5d4f4..481c501 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -31,6 +31,10 @@
 
 #include "usb.h"
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 struct sparse_file;
 
 /* protocol.c - fastboot protocol */
@@ -65,9 +69,15 @@
 /* util stuff */
 double now();
 char *mkmsg(const char *fmt, ...);
-void die(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];
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif
diff --git a/fastboot/fastboot_protocol.txt b/fastboot/fastboot_protocol.txt
index 2248992..37b1959 100644
--- a/fastboot/fastboot_protocol.txt
+++ b/fastboot/fastboot_protocol.txt
@@ -12,8 +12,8 @@
 ------------------
 
 * Two bulk endpoints (in, out) are required
-* Max packet size must be 64 bytes for full-speed and 512 bytes for 
-  high-speed USB
+* Max packet size must be 64 bytes for full-speed, 512 bytes for
+  high-speed and 1024 bytes for Super Speed USB.
 * The protocol is entirely host-driven and synchronous (unlike the
   multi-channel, bi-directional, asynchronous ADB protocol)
 
diff --git a/fastboot/fs.h b/fastboot/fs.h
index 8444081..307772b 100644
--- a/fastboot/fs.h
+++ b/fastboot/fs.h
@@ -3,10 +3,18 @@
 
 #include <stdint.h>
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 struct fs_generator;
 
 const struct fs_generator* fs_get_generator(const char *fs_type);
 int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize);
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif
 
diff --git a/fastboot/protocol.c b/fastboot/protocol.c
index 84e9837..5b97600 100644
--- a/fastboot/protocol.c
+++ b/fastboot/protocol.c
@@ -216,7 +216,7 @@
     }
 }
 
-#define USB_BUF_SIZE 512
+#define USB_BUF_SIZE 1024
 static char usb_buf[USB_BUF_SIZE];
 static int usb_buf_len;
 
@@ -305,7 +305,10 @@
         return -1;
     }
 
-    fb_download_data_sparse_flush(usb);
+    r = fb_download_data_sparse_flush(usb);
+    if (r < 0) {
+        return -1;
+    }
 
     return _command_end(usb);
 }
diff --git a/fastboot/usb.h b/fastboot/usb.h
index 17cf0a9..c7b748e 100644
--- a/fastboot/usb.h
+++ b/fastboot/usb.h
@@ -29,6 +29,10 @@
 #ifndef _USB_H_
 #define _USB_H_
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 typedef struct usb_handle usb_handle;
 
 typedef struct usb_ifc_info usb_ifc_info;
@@ -64,4 +68,8 @@
 int usb_write(usb_handle *h, const void *_data, int len);
 int usb_wait_for_disconnect(usb_handle *h);
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif
diff --git a/fastboot/usb_linux.c b/fastboot/usb_linux.c
index fabbd51..022f364 100644
--- a/fastboot/usb_linux.c
+++ b/fastboot/usb_linux.c
@@ -223,6 +223,13 @@
             } else {
                 out = ept->bEndpointAddress;
             }
+
+            // For USB 3.0 devices skip the SS Endpoint Companion descriptor
+            if (check((struct usb_descriptor_hdr *)ptr, len,
+                      USB_DT_SS_ENDPOINT_COMP, USB_DT_SS_EP_COMP_SIZE) == 0) {
+                len -= USB_DT_SS_EP_COMP_SIZE;
+                ptr += USB_DT_SS_EP_COMP_SIZE;
+            }
         }
 
         info.has_bulk_in = (in != -1);
diff --git a/fastboot/usb_osx.c b/fastboot/usb_osx.c
index 0f55e0d..0b6c515 100644
--- a/fastboot/usb_osx.c
+++ b/fastboot/usb_osx.c
@@ -328,7 +328,8 @@
         ERR("GetLocationId");
         goto error;
     }
-    snprintf(handle->info.device_path, sizeof(handle->info.device_path), "usb:%lX", locationId);
+    snprintf(handle->info.device_path, sizeof(handle->info.device_path),
+             "usb:%" PRIu32 "X", (unsigned int)locationId);
 
     kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
 
diff --git a/fastbootd/Android.mk b/fastbootd/Android.mk
deleted file mode 100644
index 6aa7400..0000000
--- a/fastbootd/Android.mk
+++ /dev/null
@@ -1,92 +0,0 @@
-# Copyright (C) 2013 Google Inc.
-#
-# Licensed under the Apache License, Version 2.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_C_INCLUDES := \
-    external/openssl/include \
-    external/mdnsresponder/mDNSShared \
-    $(LOCAL_PATH)/include \
-    external/zlib/ \
-
-LOCAL_SRC_FILES := \
-    config.c \
-    commands.c \
-    commands/boot.c \
-    commands/flash.c \
-    commands/partitions.c \
-    commands/virtual_partitions.c \
-    fastbootd.c \
-    protocol.c \
-    network_discovery.c \
-    socket_client.c \
-    secure.c \
-    transport.c \
-    transport_socket.c \
-    trigger.c \
-    usb_linux_client.c \
-    utils.c \
-
-LOCAL_MODULE := fastbootd
-LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter -DFLASH_CERT
-LOCAL_LDFLAGS := -ldl
-
-LOCAL_STATIC_LIBRARIES := \
-    libc \
-    libcrypto_static \
-    libcutils \
-    libmdnssd \
-    libsparse_static \
-    libz
-
-LOCAL_HAL_STATIC_LIBRARIES := libvendortrigger
-
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
-    external/zlib/
-
-LOCAL_SRC_FILES := \
-    commands/partitions.c \
-    other/gptedit.c \
-    utils.c
-
-LOCAL_MODULE := gptedit
-LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter
-
-LOCAL_STATIC_LIBRARIES := \
-    libsparse_static \
-    libc \
-    libcutils \
-    libz
-
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-
-include $(BUILD_EXECUTABLE)
-
-# vendor trigger HAL
-include $(CLEAR_VARS)
-LOCAL_CFLAGS := -Wall -Werror
-LOCAL_MODULE := libvendortrigger.default
-LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := vendor_trigger_default.c
-LOCAL_STATIC_LIBRARIES := libcutils
-include $(BUILD_STATIC_LIBRARY)
diff --git a/fastbootd/bootimg.h b/fastbootd/bootimg.h
deleted file mode 100644
index 44fde92..0000000
--- a/fastbootd/bootimg.h
+++ /dev/null
@@ -1,97 +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.
- */
-
-#ifndef _BOOT_IMAGE_H_
-#define _BOOT_IMAGE_H_
-
-typedef struct boot_img_hdr boot_img_hdr;
-
-#define BOOT_MAGIC "ANDROID!"
-#define BOOT_MAGIC_SIZE 8
-#define BOOT_NAME_SIZE 16
-#define BOOT_ARGS_SIZE 512
-
-struct boot_img_hdr
-{
-    unsigned char magic[BOOT_MAGIC_SIZE];
-
-    unsigned kernel_size;  /* size in bytes */
-    unsigned kernel_addr;  /* physical load addr */
-
-    unsigned ramdisk_size; /* size in bytes */
-    unsigned ramdisk_addr; /* physical load addr */
-
-    unsigned second_size;  /* size in bytes */
-    unsigned second_addr;  /* physical load addr */
-
-    unsigned tags_addr;    /* physical addr for kernel tags */
-    unsigned page_size;    /* flash page size we assume */
-    unsigned unused[2];    /* future expansion: should be 0 */
-
-    unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
-    
-    unsigned char cmdline[BOOT_ARGS_SIZE];
-
-    unsigned id[8]; /* timestamp / checksum / sha1 / etc */
-};
-
-/*
-** +-----------------+ 
-** | boot header     | 1 page
-** +-----------------+
-** | kernel          | n pages  
-** +-----------------+
-** | ramdisk         | m pages  
-** +-----------------+
-** | second stage    | o pages
-** +-----------------+
-**
-** n = (kernel_size + page_size - 1) / page_size
-** m = (ramdisk_size + page_size - 1) / page_size
-** o = (second_size + page_size - 1) / page_size
-**
-** 0. all entities are page_size aligned in flash
-** 1. kernel and ramdisk are required (size != 0)
-** 2. second is optional (second_size == 0 -> no second)
-** 3. load each element (kernel, ramdisk, second) at
-**    the specified physical address (kernel_addr, etc)
-** 4. prepare tags at tag_addr.  kernel_args[] is
-**    appended to the kernel commandline in the tags.
-** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
-** 6. if second_size != 0: jump to second_addr
-**    else: jump to kernel_addr
-*/
-
-boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size,
-                        void *ramdisk, unsigned ramdisk_size,
-                        void *second, unsigned second_size,
-                        unsigned page_size,
-                        unsigned *bootimg_size);
-
-void bootimg_set_cmdline(boot_img_hdr *hdr, const char *cmdline);                
-#endif
diff --git a/fastbootd/commands.c b/fastbootd/commands.c
deleted file mode 100644
index 98b7866..0000000
--- a/fastbootd/commands.c
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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 <inttypes.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <sys/reboot.h>
-#include <fcntl.h>
-
-#include "bootimg.h"
-#include "commands/boot.h"
-#include "commands/flash.h"
-#include "commands/partitions.h"
-#include "commands/virtual_partitions.h"
-#include "debug.h"
-#include "protocol.h"
-#include "trigger.h"
-#include "utils.h"
-
-#define ATAGS_LOCATION "/proc/atags"
-
-static void cmd_boot(struct protocol_handle *phandle, const char *arg)
-{
-    int sz, atags_sz, new_atags_sz;
-    int rv;
-    unsigned kernel_actual;
-    unsigned ramdisk_actual;
-    unsigned second_actual;
-    void *kernel_ptr;
-    void *ramdisk_ptr;
-    void *second_ptr;
-    struct boot_img_hdr *hdr;
-    char *ptr = NULL;
-    char *atags_ptr = NULL;
-    char *new_atags = NULL;
-    int data_fd = 0;
-
-    D(DEBUG, "cmd_boot %s\n", arg);
-
-    if (phandle->download_fd < 0) {
-        fastboot_fail(phandle, "no kernel file");
-        return;
-    }
-
-    atags_ptr = read_atags(ATAGS_LOCATION, &atags_sz);
-    if (atags_ptr == NULL) {
-        fastboot_fail(phandle, "atags read error");
-        goto error;
-    }
-
-    // TODO: With cms we can also verify partition name included as
-    // cms signed attribute
-    if (flash_validate_certificate(phandle->download_fd, &data_fd) != 1) {
-        fastboot_fail(phandle, "Access forbiden you need the certificate");
-        return;
-    }
-
-    sz = get_file_size(data_fd);
-
-    ptr = (char *) mmap(NULL, sz, PROT_READ,
-                        MAP_POPULATE | MAP_PRIVATE, data_fd, 0);
-
-    hdr = (struct boot_img_hdr *) ptr;
-
-    if (ptr == MAP_FAILED) {
-        fastboot_fail(phandle, "internal fastbootd error");
-        goto error;
-    }
-
-    if ((size_t) sz < sizeof(*hdr)) {
-        fastboot_fail(phandle, "invalid bootimage header");
-        goto error;
-    }
-
-    kernel_actual = ROUND_TO_PAGE(hdr->kernel_size, hdr->page_size);
-    ramdisk_actual = ROUND_TO_PAGE(hdr->ramdisk_size, hdr->page_size);
-    second_actual = ROUND_TO_PAGE(hdr->second_size, hdr->page_size);
-
-    new_atags = (char *) create_atags((unsigned *) atags_ptr, atags_sz, hdr, &new_atags_sz);
-
-    if (new_atags == NULL) {
-        fastboot_fail(phandle, "atags generate error");
-        goto error;
-    }
-    if (new_atags_sz > 0x4000) {
-        fastboot_fail(phandle, "atags file to large");
-        goto error;
-    }
-
-    if ((int) (hdr->page_size + kernel_actual + ramdisk_actual) < sz) {
-        fastboot_fail(phandle, "incomplete bootimage");
-        goto error;
-    }
-
-    kernel_ptr = (void *)((uintptr_t) ptr + hdr->page_size);
-    ramdisk_ptr = (void *)((uintptr_t) kernel_ptr + kernel_actual);
-    second_ptr = (void *)((uintptr_t) ramdisk_ptr + ramdisk_actual);
-
-    D(INFO, "preparing to boot");
-    // Prepares boot physical address. Addresses from header are ignored
-    rv = prepare_boot_linux(hdr->kernel_addr, kernel_ptr, kernel_actual,
-                            hdr->ramdisk_addr, ramdisk_ptr, ramdisk_actual,
-                            hdr->second_addr, second_ptr, second_actual,
-                            hdr->tags_addr, new_atags, ROUND_TO_PAGE(new_atags_sz, hdr->page_size));
-    if (rv < 0) {
-        fastboot_fail(phandle, "kexec prepare failed");
-        goto error;
-    }
-
-    fastboot_okay(phandle, "");
-
-    free(atags_ptr);
-    munmap(ptr, sz);
-    free(new_atags);
-    close(data_fd);
-
-    D(INFO, "Kexec going to reboot");
-    reboot(LINUX_REBOOT_CMD_KEXEC);
-
-    fastboot_fail(phandle, "reboot error");
-
-    return;
-
-error:
-
-    if (atags_ptr != NULL)
-        free(atags_ptr);
-    if (ptr != NULL)
-        munmap(ptr, sz);
-
-}
-
-static void cmd_erase(struct protocol_handle *phandle, const char *arg)
-{
-    int partition_fd;
-    char path[PATH_MAX];
-    D(DEBUG, "cmd_erase %s\n", arg);
-
-    if (flash_find_entry(arg, path, PATH_MAX)) {
-        fastboot_fail(phandle, "partition table doesn't exist");
-        return;
-    }
-
-    if (path == NULL) {
-        fastboot_fail(phandle, "Couldn't find partition");
-        return;
-    }
-
-    partition_fd = flash_get_partiton(path);
-    if (partition_fd < 0) {
-        fastboot_fail(phandle, "partiton file does not exists");
-    }
-
-    if (flash_erase(partition_fd)) {
-        fastboot_fail(phandle, "failed to erase partition");
-        flash_close(partition_fd);
-        return;
-    }
-
-    if (flash_close(partition_fd) < 0) {
-        D(ERR, "could not close device %s", strerror(errno));
-        fastboot_fail(phandle, "failed to erase partition");
-        return;
-    }
-    fastboot_okay(phandle, "");
-}
-
-static int GPT_header_location() {
-    const char *location_str = fastboot_getvar("gpt_sector");
-    char *str;
-    int location;
-
-    if (!strcmp("", location_str)) {
-        D(INFO, "GPT location not specified using second sector");
-        return 1;
-    }
-    else {
-        location = strtoul(location_str, &str, 10);
-        D(INFO, "GPT location specified as %d", location);
-
-        if (*str != '\0')
-            return -1;
-
-        return location - 1;
-    }
-}
-
-static void cmd_gpt_layout(struct protocol_handle *phandle, const char *arg) {
-    struct GPT_entry_table *oldtable;
-    int location;
-    struct GPT_content content;
-    const char *device;
-    device = fastboot_getvar("blockdev");
-
-    if (!strcmp(device, "")) {
-        fastboot_fail(phandle, "blockdev not defined in config file");
-        return;
-    }
-
-    //TODO: add same verification as in cmd_flash
-    if (phandle->download_fd < 0) {
-        fastboot_fail(phandle, "no layout file");
-        return;
-    }
-
-    location = GPT_header_location();
-    oldtable = GPT_get_device(device, location);
-
-    GPT_default_content(&content, oldtable);
-    if (oldtable == NULL)
-        D(WARN, "Could not get old gpt table");
-    else
-        GPT_release_device(oldtable);
-
-    if (!GPT_parse_file(phandle->download_fd, &content)) {
-        fastboot_fail(phandle, "Could not parse partition config file");
-        return;
-    }
-
-    if (trigger_gpt_layout(&content)) {
-        fastboot_fail(phandle, "Vendor forbids this opperation");
-        GPT_release_content(&content);
-        return;
-    }
-
-    if (!GPT_write_content(device, &content)) {
-        fastboot_fail(phandle, "Unable to write gpt file");
-        GPT_release_content(&content);
-        return;
-    }
-
-    GPT_release_content(&content);
-    fastboot_okay(phandle, "");
-}
-
-static void cmd_flash(struct protocol_handle *phandle, const char *arg)
-{
-    int partition;
-    uint64_t sz;
-    char data[BOOT_MAGIC_SIZE];
-    char path[PATH_MAX];
-    ssize_t header_sz = 0;
-    int data_fd = 0;
-
-    D(DEBUG, "cmd_flash %s\n", arg);
-
-    if (try_handle_virtual_partition(phandle, arg)) {
-        return;
-    }
-
-    if (phandle->download_fd < 0) {
-        fastboot_fail(phandle, "no kernel file");
-        return;
-    }
-
-    if (flash_find_entry(arg, path, PATH_MAX)) {
-        fastboot_fail(phandle, "partition table doesn't exist");
-        return;
-    }
-
-    if (flash_validate_certificate(phandle->download_fd, &data_fd) != 1) {
-        fastboot_fail(phandle, "Access forbiden you need certificate");
-        return;
-    }
-
-    // TODO: Maybe its goot idea to check whether the partition is bootable
-    if (!strcmp(arg, "boot") || !strcmp(arg, "recovery")) {
-        if (read_data_once(data_fd, data, BOOT_MAGIC_SIZE) < BOOT_MAGIC_SIZE) {
-            fastboot_fail(phandle, "incoming data read error, cannot read boot header");
-            return;
-        }
-        if (memcmp((void *)data, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
-            fastboot_fail(phandle, "image is not a boot image");
-            return;
-        }
-    }
-
-    partition = flash_get_partiton(path);
-
-    sz = get_file_size64(data_fd);
-
-    sz -= header_sz;
-
-    if (sz > get_file_size64(partition)) {
-        flash_close(partition);
-        D(WARN, "size of file too large");
-        fastboot_fail(phandle, "size of file too large");
-        return;
-    }
-
-    D(INFO, "writing %"PRId64" bytes to '%s'\n", sz, arg);
-
-    if (flash_write(partition, phandle->download_fd, sz, header_sz)) {
-        fastboot_fail(phandle, "flash write failure");
-        return;
-    }
-    D(INFO, "partition '%s' updated\n", arg);
-
-    flash_close(partition);
-    close(data_fd);
-
-    fastboot_okay(phandle, "");
-}
-
-static void cmd_continue(struct protocol_handle *phandle, const char *arg)
-{
-    fastboot_okay(phandle, "");
-#if 0
-    udc_stop();
-
-    boot_linux_from_flash();
-#endif
-}
-
-static void cmd_getvar(struct protocol_handle *phandle, const char *arg)
-{
-    const char *value;
-    D(DEBUG, "cmd_getvar %s\n", arg);
-
-    value = fastboot_getvar(arg);
-
-    fastboot_okay(phandle, value);
-}
-
-static void cmd_download(struct protocol_handle *phandle, const char *arg)
-{
-    unsigned len = strtoul(arg, NULL, 16);
-    int old_fd;
-
-    if (len > 256 * 1024 * 1024) {
-        fastboot_fail(phandle, "data too large");
-        return;
-    }
-
-    fastboot_data(phandle, len);
-
-    old_fd = protocol_get_download(phandle);
-    if (old_fd >= 0) {
-        off_t len = lseek(old_fd, 0, SEEK_END);
-        D(INFO, "disposing of unused fd %d, size %ld", old_fd, len);
-        close(old_fd);
-    }
-
-    phandle->download_fd = protocol_handle_download(phandle, len);
-    if (phandle->download_fd < 0) {
-        fastboot_fail(phandle, "download failed");
-        return;
-    }
-
-    fastboot_okay(phandle, "");
-}
-
-static void cmd_oem(struct protocol_handle *phandle, const char *arg) {
-    const char *response = "";
-
-    //TODO: Maybe it should get download descriptor also
-    if (trigger_oem_cmd(arg, &response))
-        fastboot_fail(phandle, response);
-    else
-        fastboot_okay(phandle, response);
-}
-
-void commands_init()
-{
-    virtual_partition_register("partition-table", cmd_gpt_layout);
-
-    fastboot_register("boot", cmd_boot);
-    fastboot_register("erase:", cmd_erase);
-    fastboot_register("flash:", cmd_flash);
-    fastboot_register("continue", cmd_continue);
-    fastboot_register("getvar:", cmd_getvar);
-    fastboot_register("download:", cmd_download);
-    fastboot_register("oem", cmd_oem);
-    //fastboot_publish("version", "0.5");
-    //fastboot_publish("product", "swordfish");
-    //fastboot_publish("kernel", "lk");
-}
diff --git a/fastbootd/commands/boot.c b/fastbootd/commands/boot.c
deleted file mode 100644
index 922914b..0000000
--- a/fastbootd/commands/boot.c
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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 <sys/syscall.h>
-#include <stdio.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#include "boot.h"
-#include "debug.h"
-#include "utils.h"
-#include "bootimg.h"
-
-
-#define KEXEC_ARM_ATAGS_OFFSET  0x1000
-#define KEXEC_ARM_ZIMAGE_OFFSET 0x8000
-
-#define MEMORY_SIZE 0x0800000
-#define START_ADDRESS 0x44000000
-#define KERNEL_START (START_ADDRESS + KEXEC_ARM_ZIMAGE_OFFSET)
-
-#define ATAG_NONE_TYPE      0x00000000
-#define ATAG_CORE_TYPE      0x54410001
-#define ATAG_RAMDISK_TYPE   0x54410004
-#define ATAG_INITRD2_TYPE   0x54420005
-#define ATAG_CMDLINE_TYPE   0x54410009
-
-#define MAX_ATAG_SIZE 0x4000
-
-struct atag_info {
-    unsigned size;
-    unsigned type;
-};
-
-struct atag_initrd2 {
-    unsigned start;
-    unsigned size;
-};
-
-struct atag_cmdline {
-    char cmdline[0];
-};
-
-struct atag {
-    struct atag_info info;
-    union {
-        struct atag_initrd2 initrd2;
-        struct atag_cmdline cmdline;
-    } data;
-};
-
-
-long kexec_load(unsigned int entry, unsigned long nr_segments,
-                struct kexec_segment *segment, unsigned long flags) {
-   return syscall(__NR_kexec_load, entry, nr_segments, segment, flags);
-}
-
-/*
- * Prepares arguments for kexec
- * Kernel address is not set into kernel_phys
- * Ramdisk is set to position relative to kernel
- */
-int prepare_boot_linux(uintptr_t kernel_phys, void *kernel_addr, int kernel_size,
-                       uintptr_t ramdisk_phys, void *ramdisk_addr, int ramdisk_size,
-                       uintptr_t second_phys, void *second_addr, int second_size,
-                       uintptr_t atags_phys, void *atags_addr, int atags_size) {
-    struct kexec_segment segment[4];
-    int segment_count = 2;
-    unsigned entry = START_ADDRESS + KEXEC_ARM_ZIMAGE_OFFSET;
-    int rv;
-    int page_size = getpagesize();
-
-    segment[0].buf = kernel_addr;
-    segment[0].bufsz = kernel_size;
-    segment[0].mem = (void *) KERNEL_START;
-    segment[0].memsz = ROUND_TO_PAGE(kernel_size, page_size);
-
-    if (kernel_size > MEMORY_SIZE - KEXEC_ARM_ZIMAGE_OFFSET) {
-        D(INFO, "Kernel image too big");
-        return -1;
-    }
-
-    segment[1].buf = atags_addr;
-    segment[1].bufsz = atags_size;
-    segment[1].mem = (void *) (START_ADDRESS + KEXEC_ARM_ATAGS_OFFSET);
-    segment[1].memsz = ROUND_TO_PAGE(atags_size, page_size);
-
-    D(INFO, "Ramdisk size is %d", ramdisk_size);
-
-    if (ramdisk_size != 0) {
-        segment[segment_count].buf = ramdisk_addr;
-        segment[segment_count].bufsz = ramdisk_size;
-        segment[segment_count].mem = (void *) (KERNEL_START + ramdisk_phys - kernel_phys);
-        segment[segment_count].memsz = ROUND_TO_PAGE(ramdisk_phys, page_size);
-        ++segment_count;
-    }
-
-    D(INFO, "Ramdisk size is %d", ramdisk_size);
-    if (second_size != 0) {
-        segment[segment_count].buf = second_addr;
-        segment[segment_count].bufsz = second_size;
-        segment[segment_count].mem = (void *) (KERNEL_START + second_phys - kernel_phys);
-        segment[segment_count].memsz = ROUND_TO_PAGE(second_size, page_size);
-        entry = second_phys;
-        ++segment_count;
-    }
-
-    rv = kexec_load(entry, segment_count, segment, KEXEC_ARCH_DEFAULT);
-
-    if (rv != 0) {
-        D(INFO, "Kexec_load returned non-zero exit code: %s\n", strerror(errno));
-        return -1;
-    }
-
-    return 1;
-
-}
-
-unsigned *create_atags(unsigned *atags_position, int atag_size, const struct boot_img_hdr *hdr, int *size) {
-    struct atag *current_tag = (struct atag *) atags_position;
-    unsigned *current_tag_raw = atags_position;
-    unsigned *new_atags = malloc(ROUND_TO_PAGE(atag_size + BOOT_ARGS_SIZE * sizeof(char),
-                                               hdr->page_size));
-    //This pointer will point into the beggining of buffer free space
-    unsigned *natags_raw_buff = new_atags;
-    int new_atags_size = 0;
-    int current_size;
-    int cmdl_length;
-
-    // copy tags from current atag file
-    while (current_tag->info.type != ATAG_NONE_TYPE) {
-        switch (current_tag->info.type) {
-            case ATAG_CMDLINE_TYPE:
-            case ATAG_RAMDISK_TYPE:
-            case ATAG_INITRD2_TYPE: break;
-            default:
-                memcpy((void *)natags_raw_buff, (void *)current_tag_raw, current_tag->info.size * sizeof(unsigned));
-                natags_raw_buff += current_tag->info.size;
-                new_atags_size += current_tag->info.size;
-        }
-
-        current_tag_raw += current_tag->info.size;
-        current_tag = (struct atag *) current_tag_raw;
-
-        if (current_tag_raw >= atags_position + atag_size) {
-            D(ERR, "Critical error in atags");
-            return NULL;
-        }
-    }
-
-    // set INITRD2 tag
-    if (hdr->ramdisk_size > 0) {
-        current_size = (sizeof(struct atag_info) + sizeof(struct atag_initrd2)) / sizeof(unsigned);
-        *((struct atag *) natags_raw_buff) = (struct atag) {
-            .info = {
-                .size = current_size,
-                .type = ATAG_INITRD2_TYPE
-            },
-            .data = {
-                .initrd2 = (struct atag_initrd2) {
-                    .start = hdr->ramdisk_addr,
-                    .size = hdr->ramdisk_size
-                }
-            }
-        };
-
-        new_atags_size += current_size;
-        natags_raw_buff += current_size;
-    }
-
-    // set ATAG_CMDLINE
-    cmdl_length = strnlen((char *) hdr->cmdline, BOOT_ARGS_SIZE - 1);
-    current_size = sizeof(struct atag_info) + (1 + cmdl_length);
-    current_size = (current_size + sizeof(unsigned) - 1) / sizeof(unsigned);
-    *((struct atag *) natags_raw_buff) = (struct atag) {
-        .info = {
-            .size = current_size,
-            .type = ATAG_CMDLINE_TYPE
-        },
-    };
-
-    //copy cmdline and ensure that there is null character
-    memcpy(((struct atag *) natags_raw_buff)->data.cmdline.cmdline,
-           (char *) hdr->cmdline, cmdl_length);
-    ((struct atag *) natags_raw_buff)->data.cmdline.cmdline[cmdl_length] = '\0';
-
-    new_atags_size += current_size;
-    natags_raw_buff += current_size;
-
-    // set ATAG_NONE
-    *((struct atag *) natags_raw_buff) = (struct atag) {
-        .info = {
-            .size = 0,
-            .type = ATAG_NONE_TYPE
-        },
-    };
-    new_atags_size += sizeof(struct atag_info) / sizeof(unsigned);
-    natags_raw_buff += sizeof(struct atag_info) / sizeof(unsigned);
-
-    *size = new_atags_size * sizeof(unsigned);
-    return new_atags;
-}
-
-char *read_atags(const char * path, int *atags_sz) {
-    int afd = -1;
-    char *atags_ptr = NULL;
-
-    afd = open(path, O_RDONLY);
-    if (afd < 0) {
-        D(ERR, "wrong atags file");
-        return 0;
-    }
-
-    atags_ptr = (char *) malloc(MAX_ATAG_SIZE);
-    if (atags_ptr == NULL) {
-        D(ERR, "insufficient memory");
-        return 0;
-    }
-
-    *atags_sz = read(afd, atags_ptr, MAX_ATAG_SIZE);
-
-    close(afd);
-    return atags_ptr;
-}
-
diff --git a/fastbootd/commands/boot.h b/fastbootd/commands/boot.h
deleted file mode 100644
index a5efd01..0000000
--- a/fastbootd/commands/boot.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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.
- */
-
-#ifndef __FASTBOOT_BOOT_H
-#define __FASTBOOT_BOOT_H
-
-#include <sys/cdefs.h>
-#include <linux/kexec.h>
-
-#include "bootimg.h"
-
-#define KEXEC_TYPE_DEFAULT 0
-#define KEXEC_TYPE_CRASH   1
-
-int prepare_boot_linux(uintptr_t, void *, int, uintptr_t, void *, int,
-                       uintptr_t, void *, int, uintptr_t, void *, int);
-unsigned *create_atags(unsigned *, int, const struct boot_img_hdr *, int *);
-long kexec_load(unsigned int, unsigned long, struct kexec_segment *, unsigned long);
-char *read_atags(const char *, int *);
-
-#endif /* _SYS_KEXEC_H */
-
diff --git a/fastbootd/commands/flash.c b/fastbootd/commands/flash.c
deleted file mode 100644
index 1eb4d1b..0000000
--- a/fastbootd/commands/flash.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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 <sys/stat.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <sys/mman.h>
-
-#include "flash.h"
-#include "protocol.h"
-#include "debug.h"
-#include "utils.h"
-#include "commands/partitions.h"
-
-#ifdef FLASH_CERT
-#include "secure.h"
-#endif
-
-#define ALLOWED_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-."
-#define BUFFER_SIZE 1024 * 1024
-#define MIN(a, b) (a > b ? b : a)
-
-
-int flash_find_entry(const char *name, char *out, size_t outlen)
-{
-//TODO: Assumption: All the partitions has they unique name
-
-    const char *path = fastboot_getvar("device-directory");
-    size_t length;
-    if (strcmp(path, "") == 0) {
-        D(ERR, "device-directory: not defined in config file");
-        return -1;
-    }
-
-    length = strspn(name, ALLOWED_CHARS);
-    if (length != strlen(name)) {
-        D(ERR, "Not allowed char in name: %c", name[length]);
-        return -1;
-    }
-
-    if (snprintf(out, outlen, "%s%s", path, name) >= (int) outlen) {
-        D(ERR, "Too long path to partition file");
-        return -1;
-    }
-
-    if (access(out, F_OK ) == -1) {
-        D(ERR, "could not find partition file %s", name);
-        return -1;
-    }
-
-    return 0;
-}
-
-int flash_erase(int fd)
-{
-    int64_t size;
-    size = get_block_device_size(fd);
-    D(DEBUG, "erase %"PRId64" data from %d\n", size, fd);
-
-    return wipe_block_device(fd, size);
-}
-
-int flash_write(int partition_fd, int data_fd, ssize_t size, ssize_t skip)
-{
-    ssize_t written = 0;
-    struct GPT_mapping input;
-    struct GPT_mapping output;
-
-    while (written < size) {
-        int current_size = MIN(size - written, BUFFER_SIZE);
-
-        if (gpt_mmap(&input, written + skip, current_size, data_fd)) {
-            D(ERR, "Error in writing data, unable to map data file %zd at %zd size %d", size, skip, current_size);
-            return -1;
-        }
-        if (gpt_mmap(&output, written, current_size, partition_fd)) {
-            D(ERR, "Error in writing data, unable to map output partition");
-            return -1;
-        }
-
-        memcpy(output.ptr, input.ptr, current_size);
-
-        gpt_unmap(&input);
-        gpt_unmap(&output);
-
-        written += current_size;
-    }
-
-    return 0;
-}
-
-#ifdef FLASH_CERT
-
-int flash_validate_certificate(int signed_fd, int *data_fd) {
-    int ret = 0;
-    const char *cert_path;
-    X509_STORE *store = NULL;
-    CMS_ContentInfo *content_info;
-    BIO *content;
-
-    cert_path = fastboot_getvar("certificate-path");
-    if (!strcmp(cert_path, "")) {
-        D(ERR, "could not find cert-key value in config file");
-        goto finish;
-    }
-
-    store = cert_store_from_path(cert_path);
-    if (store == NULL) {
-        D(ERR, "unable to create certification store");
-        goto finish;
-    }
-
-    if (cert_read(signed_fd, &content_info, &content)) {
-        D(ERR, "reading data failed");
-        goto finish;
-    }
-
-    ret = cert_verify(content, content_info, store, data_fd);
-    cert_release(content, content_info);
-
-    return ret;
-
-finish:
-    if (store != NULL)
-        cert_release_store(store);
-
-    return ret;
-}
-
-#else
-int flash_validate_certificate(int signed_fd, int *data_fd) {
-    return 1;
-}
-#endif
diff --git a/fastbootd/commands/flash.h b/fastbootd/commands/flash.h
deleted file mode 100644
index 5a64cab..0000000
--- a/fastbootd/commands/flash.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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.
- */
-
-#ifndef _FASTBOOTD_ERASE_H
-#define _FASTBOOTD_ERASE_H
-
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include "debug.h"
-
-int flash_find_entry(const char *, char *, size_t);
-int flash_erase(int fd);
-
-static inline int flash_get_partiton(const char *path) {
-    return open(path, O_RDWR);
-}
-
-static inline int flash_close(int fd) {
-    return close(fd);
-}
-
-int flash_write(int partition, int data, ssize_t size, ssize_t skip);
-
-static inline ssize_t read_data_once(int fd, char *buffer, ssize_t size) {
-    ssize_t readcount = 0;
-    ssize_t len;
-
-    while ((len = TEMP_FAILURE_RETRY(read(fd, (void *) &buffer[readcount], size - readcount))) > 0) {
-        readcount += len;
-    }
-    if (len < 0) {
-        D(ERR, "Read error:%s", strerror(errno));
-        return len;
-    }
-
-    return readcount;
-}
-
-int flash_validate_certificate(int signed_fd, int *data_fd);
-
-#endif
-
diff --git a/fastbootd/commands/partitions.c b/fastbootd/commands/partitions.c
deleted file mode 100644
index 74232e6..0000000
--- a/fastbootd/commands/partitions.c
+++ /dev/null
@@ -1,772 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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 <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <endian.h>
-#include <zlib.h>
-#include <linux/hdreg.h>
-#include <sys/ioctl.h>
-#include <stdlib.h>
-#include <cutils/config_utils.h>
-#include <inttypes.h>
-
-#include "partitions.h"
-#include "debug.h"
-#include "utils.h"
-#include "protocol.h"
-
-#define BLKRRPART  _IO(0x12,95) /* re-read partition table */
-#define BLKSSZGET  _IO(0x12,104)
-
-#define DIV_ROUND_UP(x, y) (((x) + (y) - 1)/(y))
-#define ALIGN(x, y) ((y) * DIV_ROUND_UP((x), (y)))
-#define ALIGN_DOWN(x, y) ((y) * ((x) / (y)))
-
-
-const uint8_t partition_type_uuid[16] = {
-    0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44,
-    0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7,
-};
-
-//TODO: There is assumption that we are using little endian
-
-static void GPT_entry_clear(struct GPT_entry_raw *entry)
-{
-    memset(entry, 0, sizeof(*entry));
-}
-
-/*
- * returns mapped location to choosen area
- * mapped_ptr is pointer to whole area mapped (it can be bigger then requested)
- */
-int gpt_mmap(struct GPT_mapping *mapping, uint64_t location, int size, int fd)
-{
-    unsigned int location_diff = location & ~PAGE_MASK;
-
-    mapping->size = ALIGN(size + location_diff, PAGE_SIZE);
-
-    uint64_t sz = get_file_size64(fd);
-    if (sz < size + location) {
-        D(ERR, "the location of mapping area is outside of the device size %" PRId64, sz);
-        return 1;
-    }
-    location = ALIGN_DOWN(location, PAGE_SIZE);
-
-    mapping->map_ptr = mmap64(NULL, mapping->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, location);
-
-    if (mapping->map_ptr == MAP_FAILED) {
-        mapping->ptr = MAP_FAILED;
-        D(ERR, "map failed: %s", strerror(errno));
-        return 1;
-    }
-
-    mapping->ptr = (void *)((char *) mapping->map_ptr + location_diff);
-    return 0;
-}
-
-void gpt_unmap(struct GPT_mapping *mapping) {
-    munmap(mapping->map_ptr, mapping->size);
-}
-
-
-#define LBA_ADDR(table, value)   ((uint64_t) (table)->sector_size * (value))
-
-int GPT_map_from_content(struct GPT_entry_table *table, const struct GPT_content *content)
-{
-
-    // Mapping header
-    if (gpt_mmap(&table->header_map, LBA_ADDR(table, content->header.current_lba),
-                 table->sector_size, table->fd)) {
-        D(ERR, "unable to map header:%s\n", strerror(errno));
-        goto error_header;
-    }
-
-    table->header = (struct GPT_header *) table->header_map.ptr;
-
-    table->partition_table_size = ROUND_UP(content->header.entries_count * sizeof(*table->entries),
-                                           table->sector_size);
-
-    // Mapping entry table
-    if (gpt_mmap(&table->entries_map, LBA_ADDR(table, content->header.entries_lba),
-                 table->partition_table_size, table->fd)) {
-        D(ERR, "unable to map entries");
-        goto error_signature;
-    }
-
-    table->entries = (struct GPT_entry_raw *) table->entries_map.ptr;
-
-    // Mapping secondary header
-    if (gpt_mmap(&table->sec_header_map, LBA_ADDR(table, content->header.backup_lba),
-                 table->sector_size, table->fd)) {
-        D(ERR, "unable to map backup gpt header");
-        goto error_sec_header;
-    }
-
-    // Mapping secondary entries table
-    if (gpt_mmap(&table->sec_entries_map,
-                 LBA_ADDR(table, content->header.backup_lba) - table->partition_table_size,
-                 table->partition_table_size, table->fd)) {
-        D(ERR, "unable to map secondary gpt table");
-        goto error_sec_entries;
-    }
-
-    table->second_header = (struct GPT_header *) table->sec_header_map.ptr;
-    table->second_entries = (struct GPT_entry_raw *) table->sec_entries_map.ptr;
-    table->second_valid = strcmp("EFI PART", (char *) table->second_header->signature) == 0;
-
-    return 0;
-
-error_sec_entries:
-    gpt_unmap(&table->sec_header_map);
-error_sec_header:
-    gpt_unmap(&table->entries_map);
-error_signature:
-    gpt_unmap(&table->header_map);
-error_header:
-    return 1;
-}
-
-int GPT_map(struct GPT_entry_table *table, unsigned header_lba)
-{
-    struct GPT_content content;
-    struct GPT_mapping mapping;
-    struct GPT_header *header;
-
-    if (gpt_mmap(&mapping, LBA_ADDR(table, header_lba), table->sector_size, table->fd)) {
-        D(ERR, "unable to map header: %s", strerror(errno));
-        goto error_header;
-    }
-
-    header = (struct GPT_header *) mapping.ptr;
-
-    if (strcmp("EFI PART", (char *) header->signature)) {
-        D(ERR, "GPT entry not valid");
-        goto error_signature;
-    }
-
-    content.header = *header;
-
-    gpt_unmap(&mapping);
-
-    return GPT_map_from_content(table, &content);
-
-error_signature:
-    gpt_unmap(&table->header_map);
-error_header:
-    return 1;
-}
-
-struct GPT_entry_table* GPT_get_device(const char *path, unsigned header_lba)
-{
-    struct GPT_entry_table *table;
-    size_t sector_bytes;
-
-    table = (struct GPT_entry_table *) malloc(sizeof(*table));
-    table->fd = open(path, O_RDWR);
-
-    if (table->fd < 0) {
-        D(ERR, "unable to open file %s:%s\n", path, strerror(errno));
-        return NULL;
-    }
-
-    if (!ioctl(table->fd, BLKSSZGET, &sector_bytes)) {
-        table->sector_size = (unsigned) sector_bytes;
-        D(INFO, "Got sector size %d", table->sector_size);
-    } else {
-        D(WARN, "unable to get sector size, assuming 512");
-        table->sector_size = 512;
-    }
-
-    if (GPT_map(table, header_lba)) {
-        D(ERR, "Could not map gpt");
-        return NULL;
-    }
-
-    return table;
-}
-
-static struct GPT_entry_table* GPT_get_from_content(const char *path, const struct GPT_content *content)
-{
-    struct GPT_entry_table *table;
-    size_t sector_bytes;
-
-    table = (struct GPT_entry_table *) malloc(sizeof(*table));
-    table->fd = open(path, O_RDWR);
-
-    if (table->fd < 0) {
-        D(ERR, "unable to open file %s:%s\n", path, strerror(errno));
-        return NULL;
-    }
-
-    if (!ioctl(table->fd, BLKSSZGET, &sector_bytes)) {
-        table->sector_size = (unsigned) sector_bytes;
-        D(INFO, "Got sector size %d", table->sector_size);
-    } else {
-        D(WARN, "unable to get sector size %s, assuming 512", strerror(errno));
-        table->sector_size = 512;
-    }
-
-    if (GPT_map_from_content(table, content)) {
-        D(ERR, "Could not map gpt");
-        return NULL;
-    }
-
-    return table;
-}
-
-
-void GPT_release_device(struct GPT_entry_table *table)
-{
-    gpt_unmap(&table->header_map);
-    gpt_unmap(&table->entries_map);
-    gpt_unmap(&table->sec_header_map);
-    gpt_unmap(&table->sec_entries_map);
-    close(table->fd);
-    free(table);
-}
-
-static int GPT_check_overlap(struct GPT_entry_table *table, struct GPT_entry_raw *entry);
-static int GPT_check_overlap_except(struct GPT_entry_table *table,
-                                    struct GPT_entry_raw *entry,
-                                    struct GPT_entry_raw *exclude);
-
-void GPT_edit_entry(struct GPT_entry_table *table,
-                    struct GPT_entry_raw *old_entry,
-                    struct GPT_entry_raw *new_entry)
-{
-    struct GPT_entry_raw *current_entry = GPT_get_pointer(table, old_entry);
-
-    if (GPT_check_overlap_except(table, new_entry, current_entry)) {
-        D(ERR, "Couldn't add overlaping partition");
-        return;
-    }
-
-    if (current_entry == NULL) {
-        D(ERR, "Couldn't find entry");
-        return;
-    }
-
-    *current_entry = *new_entry;
-}
-
-int GPT_delete_entry(struct GPT_entry_table *table, struct GPT_entry_raw *entry)
-{
-    struct GPT_entry_raw *raw = GPT_get_pointer(table, entry);
-
-    if (raw == NULL) {
-        D(ERR, "could not find entry");
-        return 1;
-    }
-    D(DEBUG, "Deleting gpt entry '%s'\n", raw->partition_guid);
-
-    // Entry in the middle of table may become empty
-    GPT_entry_clear(raw);
-
-    return 0;
-}
-
-void GPT_add_entry(struct GPT_entry_table *table, struct GPT_entry_raw *entry)
-{
-    unsigned i;
-    int inserted = 0;
-    if (GPT_check_overlap(table, entry)) {
-        D(ERR, "Couldn't add overlaping partition");
-        return;
-    }
-
-    if (GPT_get_pointer(table, entry) != NULL) {
-        D(WARN, "Add entry fault, this entry already exists");
-        return;
-    }
-
-    struct GPT_entry_raw *entries = table->entries;
-
-    for (i = 0; i < table->header->entries_count; ++i) {
-        if (!entries[i].type_guid[0]) {
-            inserted = 1;
-            D(DEBUG, "inserting");
-            memcpy(&entries[i], entry, sizeof(entries[i]));
-            break;
-        }
-    }
-
-    if (!inserted) {
-        D(ERR, "Unable to find empty partion entry");
-    }
-}
-
-struct GPT_entry_raw *GPT_get_pointer_by_UTFname(struct GPT_entry_table *table, const uint16_t *name);
-
-struct GPT_entry_raw *GPT_get_pointer(struct GPT_entry_table *table, struct GPT_entry_raw *entry)
-{
-    if (entry->partition_guid[0] != 0)
-        return GPT_get_pointer_by_guid(table, (const char *) entry->partition_guid);
-    else if (entry->name[0] != 0)
-        return GPT_get_pointer_by_UTFname(table, entry->name);
-
-    D(WARN, "Name or guid needed to find entry");
-    return NULL;
-}
-
-struct GPT_entry_raw *GPT_get_pointer_by_guid(struct GPT_entry_table *table, const char *name)
-{
-    int current = (int) table->header->entries_count;
-
-    for (current = current - 1; current >= 0; --current) {
-        if (strncmp((char *) name,
-                    (char *) table->entries[current].partition_guid, 16) == 0) {
-                return &table->entries[current];
-        }
-    }
-
-    return NULL;
-}
-
-int strncmp_UTF16_char(const uint16_t *s1, const char *s2, size_t n)
-{
-    if (n == 0)
-        return (0);
-    do {
-        if (((*s1) & 127) != *s2++)
-            return (((unsigned char) ((*s1) & 127)) - *(unsigned char *)--s2);
-        if (*s1++ == 0)
-            break;
-    } while (--n != 0);
-    return (0);
-}
-
-int strncmp_UTF16(const uint16_t *s1, const uint16_t *s2, size_t n)
-{
-    if (n == 0)
-        return (0);
-    do {
-        if ((*s1) != *s2++)
-            return (*s1 - *--s2);
-        if (*s1++ == 0)
-            break;
-    } while (--n != 0);
-    return (0);
-}
-
-struct GPT_entry_raw *GPT_get_pointer_by_name(struct GPT_entry_table *table, const char *name)
-{
-    int count = (int) table->header->entries_count;
-    int current;
-
-    for (current = 0; current < count; ++current) {
-        if (strncmp_UTF16_char(table->entries[current].name,
-                         (char *) name, 16) == 0) {
-                    return &table->entries[current];
-        }
-    }
-
-    return NULL;
-}
-
-struct GPT_entry_raw *GPT_get_pointer_by_UTFname(struct GPT_entry_table *table, const uint16_t *name)
-{
-    int count = (int) table->header->entries_count;
-    int current;
-
-    for (current = 0; current < count; ++current) {
-        if (strncmp_UTF16(table->entries[current].name,
-                          name, GPT_NAMELEN) == 0) {
-                return &table->entries[current];
-        }
-    }
-
-    return NULL;
-}
-
-void GPT_sync(struct GPT_entry_table *table)
-{
-    uint32_t crc;
-
-    //calculate crc32
-    crc = crc32(0, Z_NULL, 0);
-    crc = crc32(crc, (void*) table->entries, table->header->entries_count * sizeof(*table->entries));
-    table->header->partition_array_checksum = crc;
-
-    table->header->header_checksum = 0;
-    crc = crc32(0, Z_NULL, 0);
-    crc = crc32(crc, (void*) table->header, table->header->header_size);
-    table->header->header_checksum = crc;
-
-    //sync secondary partion
-    if (table->second_valid) {
-        memcpy((void *)table->second_entries, (void *) table->entries, table->partition_table_size);
-        memcpy((void *)table->second_header, (void *)table->header, sizeof(*table->header));
-    }
-
-    if(!ioctl(table->fd, BLKRRPART, NULL)) {
-        D(WARN, "Unable to force kernel to refresh partition table");
-    }
-}
-
-void GPT_to_UTF16(uint16_t *to, const char *from, int n)
-{
-    int i;
-    for (i = 0; i < (n - 1) && (to[i] = from[i]) != '\0'; ++i);
-    to[i] = '\0';
-}
-
-void GPT_from_UTF16(char *to, const uint16_t *from, int n)
-{
-    int i;
-    for (i = 0; i < (n - 1) && (to[i] = from[i] & 127) != '\0'; ++i);
-    to[i] = '\0';
-}
-
-static int GPT_check_overlap_except(struct GPT_entry_table *table,
-                                    struct GPT_entry_raw *entry,
-                                    struct GPT_entry_raw *exclude) {
-    int current = (int) table->header->entries_count;
-    int dontcheck;
-    struct GPT_entry_raw *current_entry;
-    if (entry->last_lba < entry->first_lba) {
-        D(WARN, "Start address have to be less than end address");
-        return 1;
-    }
-
-    for (current = current - 1; current >= 0; --current) {
-        current_entry = &table->entries[current];
-        dontcheck = strncmp((char *) entry->partition_guid,
-                           (char *) current_entry->partition_guid , 16) == 0;
-        dontcheck |= current_entry->type_guid[0] == 0;
-        dontcheck |= current_entry == exclude;
-
-        if (!dontcheck && ((entry->last_lba >= current_entry->first_lba &&
-                            entry->first_lba < current_entry->last_lba ))) {
-            return 1;
-        }
-    }
-
-    return 0;
-}
-
-static int GPT_check_overlap(struct GPT_entry_table *table, struct GPT_entry_raw *entry)
-{
-    return GPT_check_overlap_except(table, entry, NULL);
-}
-
-static char *get_key_value(char *ptr, char **key, char **value)
-{
-    *key = ptr;
-    ptr = strchr(ptr, '=');
-
-    if (ptr == NULL)
-        return NULL;
-
-    *ptr++ = '\0';
-    *value = ptr;
-    ptr = strchr(ptr, ';');
-
-    if (ptr == NULL)
-        ptr = *value + strlen(*value);
-    else
-        *ptr = '\0';
-
-    *key = strip(*key);
-    *value = strip(*value);
-
-    return ptr;
-}
-
-//TODO: little endian?
-static int add_key_value(const char *key, const char *value, struct GPT_entry_raw *entry)
-{
-    char *endptr;
-    if (!strcmp(key, "type")) {
-        strncpy((char *) entry->type_guid, value, 16);
-        entry->type_guid[15] = 0;
-    }
-    else if (!strcmp(key, "guid")) {
-        strncpy((char *) entry->partition_guid, value, 16);
-        entry->type_guid[15] = 0;
-    }
-    else if (!strcmp(key, "firstlba")) {
-        entry->first_lba = strtoul(value, &endptr, 10);
-        if (*endptr != '\0') goto error;
-    }
-    else if (!strcmp(key, "lastlba")) {
-        entry->last_lba = strtoul(value, &endptr, 10);
-        if (*endptr != '\0') goto error;
-    }
-    else if (!strcmp(key, "flags")) {
-        entry->flags = strtoul(value, &endptr, 16);
-        if (*endptr != '\0') goto error;
-    }
-    else if (!strcmp(key, "name")) {
-        GPT_to_UTF16(entry->name, value, GPT_NAMELEN);
-    }
-    else {
-        goto error;
-    }
-
-    return 0;
-
-error:
-    D(ERR, "Could not find key or parse value: %s,%s", key, value);
-    return 1;
-}
-
-int GPT_parse_entry(char *string, struct GPT_entry_raw *entry)
-{
-    char *ptr = string;
-    char *key, *value;
-
-    while ((ptr = get_key_value(ptr, &key, &value)) != NULL) {
-        if (add_key_value(key, value, entry)) {
-            D(WARN, "key or value not valid: %s %s", key, value);
-            return 1;
-        }
-    }
-
-    return 0;
-}
-
-void entry_set_guid(int n, uint8_t *guid)
-{
-    int fd;
-    fd = open("/dev/urandom", O_RDONLY);
-    read(fd, guid, 16);
-    close(fd);
-
-    //rfc4122
-    guid[8] = (guid[8] & 0x3F) | 0x80;
-    guid[7] = (guid[7] & 0x0F) | 0x40;
-}
-
-void GPT_default_content(struct GPT_content *content, struct GPT_entry_table *table)
-{
-    if (table != NULL) {
-        memcpy(&content->header, table->header, sizeof(content->header));
-        content->header.header_size = sizeof(content->header);
-        content->header.entry_size = sizeof(struct GPT_entry_raw);
-    }
-    else {
-        D(WARN, "Could not locate old gpt table, using default values");
-        memset(&content->header, 0, sizeof(content->header) / sizeof(int));
-        content->header = (struct GPT_header) {
-            .revision = 0x10000,
-            .header_size = sizeof(content->header),
-            .header_checksum = 0,
-            .reserved_zeros = 0,
-            .current_lba = 1,
-            .backup_lba = 1,
-            .entry_size = sizeof(struct GPT_entry_raw),
-            .partition_array_checksum = 0
-        };
-        strncpy((char *)content->header.signature, "EFI PART", 8);
-        strncpy((char *)content->header.disk_guid, "ANDROID MMC DISK", 16);
-    }
-}
-
-static int get_config_uint64(cnode *node, uint64_t *ptr, const char *name)
-{
-    const char *tmp;
-    uint64_t val;
-    char *endptr;
-    if ((tmp = config_str(node, name, NULL))) {
-        val = strtoull(tmp, &endptr, 10);
-        if (*endptr != '\0') {
-            D(WARN, "Value for %s is not a number: %s", name, tmp);
-            return 1;
-        }
-        *ptr = val;
-        return 0;
-    }
-    return 1;
-}
-
-static int get_config_string(cnode *node, char *ptr, int max_len, const char *name)
-{
-    size_t begin, end;
-    const char *value = config_str(node, name, NULL);
-    if (!value)
-        return -1;
-
-    begin = strcspn(value, "\"") + 1;
-    end = strcspn(&value[begin], "\"");
-
-    if ((int) end > max_len) {
-        D(WARN, "Identifier \"%s\" too long", value);
-        return -1;
-    }
-
-    strncpy(ptr, &value[begin], end);
-    if((int) end < max_len)
-        ptr[end] = 0;
-    return 0;
-}
-
-static void GPT_parse_header(cnode *node, struct GPT_content *content)
-{
-    get_config_uint64(node, &content->header.current_lba, "header_lba");
-    get_config_uint64(node, &content->header.backup_lba, "backup_lba");
-    get_config_uint64(node, &content->header.first_usable_lba, "first_lba");
-    get_config_uint64(node, &content->header.last_usable_lba, "last_lba");
-    get_config_uint64(node, &content->header.entries_lba, "entries_lba");
-    get_config_string(node, (char *) content->header.disk_guid, 16, "guid");
-}
-
-static int GPT_parse_partitions(cnode *node, struct GPT_content *content)
-{
-    cnode *current;
-    int i;
-    uint64_t partition_size;
-    struct GPT_entry_raw *entry;
-    for (i = 0, current = node->first_child; current; current = current->next, ++i) {
-        entry = &content->entries[i];
-        entry_set_guid(i, content->entries[i].partition_guid);
-        memcpy(&content->entries[i].type_guid, partition_type_uuid, 16);
-        if (get_config_uint64(current, &entry->first_lba, "first_lba")) {
-            D(ERR, "first_lba not specified");
-            return 1;
-        }
-        if (get_config_uint64(current, &partition_size, "partition_size")) {
-            D(ERR, "partition_size not specified");
-            return 1;
-        }
-        if (config_str(current, "system", NULL)) {
-            entry->flags |= GPT_FLAG_SYSTEM;
-        }
-        if (config_str(current, "bootable", NULL)) {
-            entry->flags |= GPT_FLAG_BOOTABLE;
-        }
-        if (config_str(current, "readonly", NULL)) {
-            entry->flags |= GPT_FLAG_READONLY;
-        }
-        if (config_str(current, "automount", NULL)) {
-            entry->flags |= GPT_FLAG_DOAUTOMOUNT;
-        }
-
-        get_config_uint64(current, &content->entries[i].flags, "flags");
-        content->entries[i].last_lba = content->entries[i].first_lba + partition_size - 1;
-        GPT_to_UTF16(content->entries[i].name, current->name, 16);
-    }
-    return 0;
-}
-
-static inline int cnode_count(cnode *node)
-{
-    int i;
-    cnode *current;
-    for (i = 0, current = node->first_child; current; current = current->next, ++i)
-        ;
-    return i;
-}
-
-
-static int GPT_parse_cnode(cnode *root, struct GPT_content *content)
-{
-    cnode *partnode;
-
-    if (!(partnode = config_find(root, "partitions"))) {
-        D(ERR, "Could not find partition table");
-        return 0;
-    }
-
-    GPT_parse_header(root, content);
-
-    content->header.entries_count = cnode_count(partnode);
-    content->entries = malloc(content->header.entries_count * sizeof(struct GPT_entry_raw));
-
-    if (GPT_parse_partitions(partnode, content)) {
-        D(ERR, "Could not parse partitions");
-        return 0;
-    }
-
-    return 1;
-}
-
-int GPT_parse_file(int fd, struct GPT_content *content)
-{
-    char *data;
-    int size;
-    int ret;
-    cnode *root = config_node("", "");
-
-    size = get_file_size(fd);
-    data = (char *) mmap(NULL, size + 1, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
-
-    if (data == NULL) {
-        if (size == 0)
-            D(ERR, "config file empty");
-        else
-            D(ERR, "Out of memory");
-        return 0;
-    }
-
-    data[size - 1] = 0;
-    config_load(root, data);
-
-    if (root->first_child == NULL) {
-        D(ERR, "Could not read config file");
-        return 0;
-    }
-
-    ret = GPT_parse_cnode(root, content);
-    munmap(data, size);
-    return ret;
-}
-
-void GPT_release_content(struct GPT_content *content)
-{
-    free(content->entries);
-}
-
-int GPT_write_content(const char *device, struct GPT_content *content)
-{
-    struct GPT_entry_table *maptable;
-
-    maptable = GPT_get_from_content(device, content);
-    if (maptable == NULL) {
-        D(ERR, "could not map device");
-        return 0;
-    }
-
-    memcpy(maptable->header, &content->header, sizeof(*maptable->header));
-    memcpy(maptable->entries, content->entries,
-           content->header.entries_count * sizeof(*maptable->entries));
-
-    GPT_sync(maptable);
-    GPT_release_device(maptable);
-
-    return 1;
-}
-
diff --git a/fastbootd/commands/partitions.h b/fastbootd/commands/partitions.h
deleted file mode 100644
index 9a6a88d..0000000
--- a/fastbootd/commands/partitions.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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.
- */
-
-
-#ifndef __FASTBOOTD_PATITIONS_
-#define __FASTBOOTD_PATITIONS_
-
-#include <stdint.h>
-
-#define GPT_ENTRIES 128
-#define GPT_NAMELEN 36
-
-#define GPT_FLAG_SYSTEM (1ULL << 0)
-#define GPT_FLAG_BOOTABLE (1ULL << 2)
-#define GPT_FLAG_READONLY (1ULL << 60)
-#define GPT_FLAG_DOAUTOMOUNT (1ULL << 63)
-
-// it should be passed in little endian order
-struct GPT_entry_raw {
-    uint8_t type_guid[16];
-    uint8_t partition_guid[16];
-    uint64_t first_lba; // little endian
-    uint64_t last_lba;
-    uint64_t flags;
-    uint16_t name[GPT_NAMELEN]; // UTF-16 LE
-};
-
-struct GPT_mapping {
-    void *map_ptr;
-    void *ptr;
-    unsigned size;
-};
-
-struct GPT_entry_table {
-    int fd;
-
-    struct GPT_mapping header_map;
-    struct GPT_mapping entries_map;
-    struct GPT_mapping sec_header_map;
-    struct GPT_mapping sec_entries_map;
-
-    struct GPT_header *header;
-    struct GPT_entry_raw *entries;
-    struct GPT_header *second_header;
-    struct GPT_entry_raw *second_entries;
-
-    unsigned sector_size;
-    unsigned partition_table_size;
-    int second_valid;
-};
-
-struct GPT_header {
-    uint8_t signature[8];
-    uint32_t revision;
-    uint32_t header_size;
-    uint32_t header_checksum;
-    uint32_t reserved_zeros;
-    uint64_t current_lba;
-    uint64_t backup_lba;
-    uint64_t first_usable_lba;
-    uint64_t last_usable_lba;
-    uint8_t disk_guid[16];
-    uint64_t entries_lba;
-    uint32_t entries_count;
-    uint32_t entry_size;
-    uint32_t partition_array_checksum;
-    // the rest should be filled with zeros
-} __attribute__((packed));
-
-struct GPT_content {
-    struct GPT_header header;
-    struct GPT_entry_raw *entries;
-};
-
-
-struct GPT_entry_table* GPT_get_device(const char *, unsigned lba);
-
-void GPT_release_device(struct GPT_entry_table *);
-
-void GPT_edit_entry(struct GPT_entry_table *table,
-                    struct GPT_entry_raw *old_entry,
-                    struct GPT_entry_raw *new_entry);
-
-int GPT_delete_entry(struct GPT_entry_table *table, struct GPT_entry_raw *entry);
-
-void GPT_add_entry(struct GPT_entry_table *table, struct GPT_entry_raw *entry);
-
-struct GPT_entry_raw *GPT_get_pointer(struct GPT_entry_table *table, struct GPT_entry_raw *entry);
-struct GPT_entry_raw *GPT_get_pointer_by_guid(struct GPT_entry_table *, const char *);
-struct GPT_entry_raw *GPT_get_pointer_by_name(struct GPT_entry_table *, const char *);
-
-//Use after every edit operation
-void GPT_sync();
-
-void GPT_to_UTF16(uint16_t *, const char *, int );
-void GPT_from_UTF16(char *, const uint16_t *, int);
-
-int GPT_parse_entry(char *string, struct GPT_entry_raw *entry);
-
-void GPT_default_content(struct GPT_content *content, struct GPT_entry_table *table);
-
-void GPT_release_content(struct GPT_content *content);
-
-int GPT_parse_file(int fd, struct GPT_content *content);
-
-int GPT_write_content(const char *device, struct GPT_content *content);
-
-int gpt_mmap(struct GPT_mapping *mapping, uint64_t location, int size, int fd);
-
-void gpt_unmap(struct GPT_mapping *mapping);
-
-#endif
diff --git a/fastbootd/commands/virtual_partitions.c b/fastbootd/commands/virtual_partitions.c
deleted file mode 100644
index 813f485..0000000
--- a/fastbootd/commands/virtual_partitions.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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 "commands/virtual_partitions.h"
-#include "debug.h"
-
-static struct virtual_partition *partitions = NULL;
-
-int try_handle_virtual_partition(struct protocol_handle *handle, const char *arg)
-{
-    struct virtual_partition *current;
-
-    for (current = partitions; current != NULL; current = current->next) {
-        if (!strcmp(current->name, arg)) {
-            current->handler(handle, arg);
-        }
-    }
-
-    return 0;
-}
-
-void virtual_partition_register(
-        const char * name,
-        void (*handler)(struct protocol_handle *phandle, const char *arg))
-{
-    struct virtual_partition *new;
-    new = malloc(sizeof(*new));
-    if (new) {
-        new->name = name;
-        new->handler = handler;
-        new->next = partitions;
-        partitions = new;
-    }
-    else {
-        D(ERR, "Out of memory");
-    }
-}
diff --git a/fastbootd/commands/virtual_partitions.h b/fastbootd/commands/virtual_partitions.h
deleted file mode 100644
index 88df71e..0000000
--- a/fastbootd/commands/virtual_partitions.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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.
- */
-
-#ifndef FASTBOOTD_VIRTUAL_PARTITIONS_H
-#define FASTBOOTD_VIRTUAL_PARTITIONS_H
-
-#include "protocol.h"
-
-struct virtual_partition {
-    struct virtual_partition *next;
-    const char *name;
-    void (*handler)(struct protocol_handle *phandle, const char *arg);
-};
-
-int try_handle_virtual_partition(struct protocol_handle *handle, const char *arg);
-
-void virtual_partition_register(
-        const char * name,
-        void (*handler)(struct protocol_handle *phandle, const char *arg));
-
-#endif
diff --git a/fastbootd/config.c b/fastbootd/config.c
deleted file mode 100644
index fe6da69..0000000
--- a/fastbootd/config.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (c) 2013, Google Inc.
- * 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 <fcntl.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-
-#include "protocol.h"
-#include "utils.h"
-
-#include "debug.h"
-
-// TODO: change config path
-#define CONFIG_PATH "/data/fastboot.cfg"
-
-static int config_parse_line(char *line)
-{
-    char *c;
-    char *key;
-    char *value;
-
-    c = strchr(line, '#');
-    if (c)
-        *c = '\0';
-
-    if (strspn(line, " \t") == strlen(line))
-        return 0;
-
-    c = strchr(line, '=');
-    if (c == NULL)
-        return -1;
-
-    key = line;
-    *c = '\0';
-    value = c + 1;
-
-    key = strip(key);
-    value = strip(value);
-
-    key = strdup(key);
-    value = strdup(value);
-
-    fastboot_publish(key, value);
-
-    return 0;
-}
-
-static void config_parse(char *buffer)
-{
-    char *saveptr;
-    char *str = buffer;
-    char *line = buffer;
-    int c;
-    int ret;
-
-    for (c = 1; line != NULL; c++) {
-        line = strtok_r(str, "\r\n", &saveptr);
-        if (line != NULL) {
-            D(VERBOSE, "'%s'", line);
-            ret = config_parse_line(line);
-            if (ret < 0) {
-                D(WARN, "error parsing " CONFIG_PATH " line %d", c);
-            }
-        }
-        str = NULL;
-    }
-}
-
-void config_init()
-{
-    int fd;
-    off_t len;
-    ssize_t ret;
-    size_t count = 0;
-    char *buffer;
-
-    fd = open(CONFIG_PATH, O_RDONLY);
-    if (fd < 0) {
-        D(ERR, "failed to open " CONFIG_PATH);
-        return;
-    }
-
-    len = lseek(fd, 0, SEEK_END);
-    if (len < 0) {
-        D(ERR, "failed to seek to end of " CONFIG_PATH);
-        return;
-    }
-
-    lseek(fd, 0, SEEK_SET);
-
-    buffer = malloc(len + 1);
-    if (buffer == NULL) {
-        D(ERR, "failed to allocate %ld bytes", len);
-        return;
-    }
-
-    while (count < (size_t)len) {
-        ret = read(fd, buffer + count, len - count);
-        if (ret < 0 && errno != EINTR) {
-            D(ERR, "failed to read " CONFIG_PATH ": %d %s", errno, strerror(errno));
-            return;
-        }
-        if (ret == 0) {
-            D(ERR, "early EOF reading " CONFIG_PATH);
-            return;
-        }
-
-        count += ret;
-    }
-
-    buffer[len] = '\0';
-
-    config_parse(buffer);
-
-    free(buffer);
-}
diff --git a/fastbootd/debug.h b/fastbootd/debug.h
deleted file mode 100644
index 74620b8..0000000
--- a/fastbootd/debug.h
+++ /dev/null
@@ -1,42 +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 _FASTBOOTD_DEBUG_H_
-#define _FASTBOOTD_DEBUG_H_
-
-#include <stdio.h>
-
-#include <cutils/klog.h>
-
-#define ERR 0
-#define WARN 1
-#define INFO 2
-#define VERBOSE 3
-#define DEBUG 4
-
-extern unsigned int debug_level;
-
-//#define DLOG(fmt, ...) printf(fmt, ##__VA_ARGS__)
-#define DLOG(fmt, ...) KLOG_INFO("fastbootd", fmt, ##__VA_ARGS__)
-
-#define D(level, fmt, ...) \
-    do { \
-        if (debug_level == level || debug_level > level) { \
-            DLOG("%s:%d " fmt "\n", __BASE_FILE__, __LINE__, ##__VA_ARGS__); \
-        } \
-    } while (0)
-
-#endif
diff --git a/fastbootd/fastbootd.c b/fastbootd/fastbootd.c
deleted file mode 100644
index 2b51b33..0000000
--- a/fastbootd/fastbootd.c
+++ /dev/null
@@ -1,100 +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.
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <cutils/klog.h>
-#include <getopt.h>
-#include <stdlib.h>
-
-#include "debug.h"
-#include "trigger.h"
-#include "socket_client.h"
-#include "secure.h"
-
-unsigned int debug_level = DEBUG;
-
-void commands_init();
-void usb_init();
-void config_init();
-int transport_socket_init();
-int network_discovery_init();
-void ssh_server_start();
-
-int main(int argc, char **argv)
-{
-    int socket_client = 0;
-    int c;
-    int network = 1;
-
-    klog_init();
-    klog_set_level(6);
-
-    const struct option longopts[] = {
-        {"socket", no_argument, 0, 'S'},
-        {"nonetwork", no_argument, 0, 'n'},
-        {0, 0, 0, 0}
-    };
-
-    while (1) {
-        c = getopt_long(argc, argv, "Sn", longopts, NULL);
-        /* Alphabetical cases */
-        if (c < 0)
-            break;
-        switch (c) {
-        case 'S':
-            socket_client = 1;
-            break;
-        case 'n':
-            network = 0;
-            break;
-        case '?':
-            return 1;
-        default:
-            return 0;
-        }
-    }
-
-    (void)argc;
-    (void)argv;
-
-    klog_init();
-    klog_set_level(6);
-
-    if (socket_client) {
-        //TODO: Shouldn't we change current tty into raw mode?
-        run_socket_client();
-    }
-    else {
-        cert_init_crypto();
-        config_init();
-        load_trigger();
-        commands_init();
-        usb_init();
-
-        if (network) {
-            if (!transport_socket_init())
-                exit(1);
-            ssh_server_start();
-            network_discovery_init();
-        }
-
-        while (1) {
-            sleep(1);
-        }
-    }
-    return 0;
-}
diff --git a/fastbootd/network_discovery.c b/fastbootd/network_discovery.c
deleted file mode 100644
index 1cd3e48..0000000
--- a/fastbootd/network_discovery.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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 <string.h>
-#include <dns_sd.h>
-#include <cutils/properties.h>
-#include <unistd.h>
-
-#include "debug.h"
-#include "network_discovery.h"
-#include "utils.h"
-
-#define MDNS_SERVICE_NAME "mdnsd"
-#define MDNS_SERVICE_STATUS "init.svc.mdnsd"
-#define FASTBOOTD_TYPE "_fastbootd._tcp"
-#define FASTBOOTD_DOMAIN "local."
-#define FASTBOOTD_NAME "fastbootd"
-
-
-static void reg_reply(DNSServiceRef sdref, const DNSServiceFlags flags, DNSServiceErrorType errorCode,
-    const char *name, const char *regtype, const char *domain, void *context)
-{
-    (void)sdref;    // Unused
-    (void)flags;    // Unused
-    (void)context;  // Unused
-    if (errorCode == kDNSServiceErr_ServiceNotRunning) {
-        fprintf(stderr, "Error code %d\n", errorCode);
-    }
-
-
-    printf("Got a reply for service %s.%s%s: ", name, regtype, domain);
-
-    if (errorCode == kDNSServiceErr_NoError)
-    {
-        if (flags & kDNSServiceFlagsAdd)
-            printf("Name now registered and active\n");
-        else
-            printf("Name registration removed\n");
-        if (errorCode == kDNSServiceErr_NameConflict)
-            printf("Name in use, please choose another\n");
-        else
-            printf("Error %d\n", errorCode);
-
-        if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
-    }
-}
-
-static int register_service() {
-    DNSServiceRef sdref = NULL;
-    const char *domain = FASTBOOTD_DOMAIN;
-    const char *type = FASTBOOTD_TYPE;
-    const char *host = NULL;
-    char name[PROP_VALUE_MAX];
-    uint16_t port = 22;
-    int flags = 0;
-    DNSServiceErrorType result;
-    property_get("ro.serialno", name, "");
-    if (!strcmp(name, "")) {
-        D(ERR, "No property serialno");
-        return -1;
-    }
-
-    result = DNSServiceRegister(&sdref, flags, kDNSServiceInterfaceIndexAny,
-                       name, type, domain, host, port,
-                       0, NULL, reg_reply, NULL);
-    if (result != kDNSServiceErr_NoError) {
-        D(ERR, "Unable to register service");
-        return -1;
-    }
-    return 0;
-}
-
-
-int network_discovery_init()
-{
-    D(INFO, "Starting discovery");
-    if (service_start(MDNS_SERVICE_NAME)) {
-        D(ERR, "Unable to start discovery");
-        return -1;
-    }
-
-    if (register_service()) {
-        D(ERR, "Unable to register service");
-        return -1;
-    }
-
-    return 0;
-}
-
diff --git a/fastbootd/network_discovery.h b/fastbootd/network_discovery.h
deleted file mode 100644
index 75fda63..0000000
--- a/fastbootd/network_discovery.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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.
- */
-
-#ifndef _FASTBOOTD_NETWORK_DISCOVERY_H
-#define _FASTBOOTD_NETWORK_DISCOVERY_H
-
-int network_discovery_init();
-
-#endif
diff --git a/fastbootd/other/gptedit.c b/fastbootd/other/gptedit.c
deleted file mode 100644
index d423529..0000000
--- a/fastbootd/other/gptedit.c
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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 <getopt.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <cutils/klog.h>
-
-#include "commands/partitions.h"
-#include "debug.h"
-
-unsigned int debug_level = DEBUG;
-//TODO: add tool to generate config file
-
-void usage() {
-    fprintf(stderr,
-            "usage: test_gpt [ <option> ] <file>\n"
-            "\n"
-            "options:\n"
-            "  -p                                       print partitions\n"
-            "  -c                                       print config file\n"
-            "  -a                                       adds new partition\n"
-            "  -d                                       deletes partition (-o needed)\n"
-            "\n"
-            "  -n name@startlba,endlba                  new partition detail\n"
-            "  -o                                       old partition name\n"
-            "  -t                                       type guid\n"
-            "  -g                                       partition guid\n"
-            "  -l gpt_location                          specyfies gpt secto\n"
-    );
-
-}
-
-void printGPT(struct GPT_entry_table *table);
-void addGPT(struct GPT_entry_table *table, const char *arg, const char *guid, const char *tguid);
-void deleteGPT(struct GPT_entry_table *table, const char *name);
-void configPrintGPT(struct GPT_entry_table *table);
-
-int main(int argc, char *argv[]) {
-    int print_cmd = 0;
-    int config_cmd = 0;
-    int add_cmd = 0;
-    int del_cmd = 0;
-    int sync_cmd = 0;
-    int c;
-    const char *new_partition = NULL;
-    const char *old_partition = NULL;
-    const char *type_guid = NULL;
-    const char *partition_guid = NULL;
-    unsigned gpt_location = 1;
-
-    klog_init();
-    klog_set_level(6);
-
-    const struct option longopts[] = {
-        {"print", no_argument, 0, 'p'},
-        {"config-print", no_argument, 0, 'c'},
-        {"add", no_argument, 0, 'a'},
-        {"del", no_argument, 0, 'd'},
-        {"new", required_argument, 0, 'n'},
-        {"old", required_argument, 0, 'o'},
-        {"type", required_argument, 0, 't'},
-        {"sync", required_argument, 0, 's'},
-        {"guid", required_argument, 0, 'g'},
-        {"location", required_argument, 0, 'l'},
-        {0, 0, 0, 0}
-    };
-
-    while (1) {
-        c = getopt_long(argc, argv, "pcadt:g:n:o:sl:", longopts, NULL);
-        /* Alphabetical cases */
-        if (c < 0)
-            break;
-        switch (c) {
-        case 'p':
-            print_cmd = 1;
-            break;
-        case 'c':
-            config_cmd = 1;
-            break;
-        case 'a':
-            add_cmd = 1;
-            break;
-        case 'd':
-            del_cmd = 1;
-            break;
-        case 'n':
-            new_partition = optarg;
-            break;
-        case 'o':
-            old_partition = optarg;
-            break;
-        case 't':
-            type_guid = optarg;
-        case 'g':
-            partition_guid = optarg;
-            break;
-        case 's':
-            sync_cmd = 1;
-            break;
-        case 'l':
-            gpt_location = strtoul(optarg, NULL, 10);
-            fprintf(stderr, "Got offset as %d", gpt_location);
-            break;
-        case '?':
-            return 1;
-        default:
-            abort();
-        }
-    }
-
-    argc -= optind;
-    argv += optind;
-
-    if (argc < 1) {
-        usage();
-        return 1;
-    }
-
-    const char *path = argv[0];
-    struct GPT_entry_table *table = GPT_get_device(path, gpt_location);
-    if (table == NULL) {
-        fprintf(stderr, "unable to get GPT table from %s\n", path);
-        return 1;
-    }
-
-    if (add_cmd)
-        addGPT(table, new_partition, partition_guid, type_guid);
-    if (del_cmd)
-        deleteGPT(table, old_partition);
-    if (print_cmd)
-        printGPT(table);
-    if (config_cmd)
-        configPrintGPT(table);
-    if (sync_cmd)
-        GPT_sync(table);
-
-    GPT_release_device(table);
-
-    return 0;
-}
-
-void printGPT(struct GPT_entry_table *table) {
-    struct GPT_entry_raw *entry = table->entries;
-    unsigned n, m;
-    char name[GPT_NAMELEN + 1];
-
-    printf("ptn  start block   end block     name\n");
-    printf("---- ------------- -------------\n");
-
-    for (n = 0; n < table->header->entries_count; n++, entry++) {
-        if (entry->type_guid[0] == 0)
-            continue;
-        for (m = 0; m < GPT_NAMELEN; m++) {
-            name[m] = entry->name[m] & 127;
-        }
-        name[m] = 0;
-        printf("#%03d %13"PRId64" %13"PRId64" %s\n",
-            n + 1, entry->first_lba, entry->last_lba, name);
-    }
-}
-
-void configPrintGPT(struct GPT_entry_table *table) {
-    struct GPT_entry_raw *entry = table->entries;
-    unsigned n, m;
-    char name[GPT_NAMELEN + 1];
-    char temp_guid[17];
-    temp_guid[16] = 0;
-
-    printf("header_lba %"PRId64"\n", table->header->current_lba);
-    printf("backup_lba %"PRId64"\n", table->header->backup_lba);
-    printf("first_lba %"PRId64"\n", table->header->first_usable_lba);
-    printf("last_lba %"PRId64"\n", table->header->last_usable_lba);
-    printf("entries_lba %"PRId64"\n", table->header->entries_lba);
-    snprintf(temp_guid, 17, "%s", table->header->disk_guid);
-    printf("guid \"%s\"", temp_guid);
-
-    printf("\npartitions {\n");
-
-    for (n = 0; n < table->header->entries_count; n++, entry++) {
-        uint64_t size = entry->last_lba - entry->first_lba + 1;
-
-        if (entry->type_guid[0] == 0)
-            continue;
-        for (m = 0; m < GPT_NAMELEN; m++) {
-            name[m] = entry->name[m] & 127;
-        }
-        name[m] = 0;
-
-        printf("    %s {\n", name);
-        snprintf(temp_guid, 17, "%s", entry->partition_guid);
-        printf("        guid \"%s\"\n", temp_guid);
-        printf("        first_lba %"PRId64"\n", entry->first_lba);
-        printf("        partition_size %"PRId64"\n", size);
-        if (entry->flags & GPT_FLAG_SYSTEM)
-            printf("        system\n");
-        if (entry->flags & GPT_FLAG_BOOTABLE)
-            printf("        bootable\n");
-        if (entry->flags & GPT_FLAG_READONLY)
-            printf("        readonly\n");
-        if (entry->flags & GPT_FLAG_DOAUTOMOUNT)
-            printf("        automount\n");
-        printf("    }\n\n");
-    }
-    printf("}\n");
-}
-
-void addGPT(struct GPT_entry_table *table, const char *str  , const char *guid, const char *tguid) {
-    char *c, *c2;
-    char *arg = malloc(strlen(str));
-    char *name = arg;
-    unsigned start, end;
-    strcpy(arg, str);
-    if (guid == NULL || tguid == NULL) {
-        fprintf(stderr, "Type guid and partion guid needed");
-        free(arg);
-        return;
-    }
-
-    c = strchr(arg, '@');
-
-    if (c == NULL) {
-        fprintf(stderr, "Wrong entry format");
-        free(arg);
-        return;
-    }
-
-    *c++ = '\0';
-
-    c2 = strchr(c, ',');
-
-    if (c2 == NULL) {
-        fprintf(stderr, "Wrong entry format");
-        free(arg);
-        return;
-    }
-
-    start = strtoul(c, NULL, 10);
-    *c2++ = '\0';
-    end = strtoul(c2, NULL, 10);
-
-    struct GPT_entry_raw data;
-    strncpy((char *)data.partition_guid, guid, 15);
-    data.partition_guid[15] = '\0';
-    strncpy((char *)data.type_guid, tguid, 15);
-    data.type_guid[15] = '\0';
-    GPT_to_UTF16(data.name, name, GPT_NAMELEN);
-    data.first_lba = start;
-    data.last_lba = end;
-
-    fprintf(stderr, "Adding (%d,%d) %s as, [%s, %s]", start, end, name, (char *) data.type_guid, (char *) data.partition_guid);
-    GPT_add_entry(table, &data);
-    free(arg);
-}
-
-void deleteGPT(struct GPT_entry_table *table, const char *name) {
-    struct GPT_entry_raw *entry;
-
-    if (name == NULL) {
-        fprintf(stderr, "Need partition name");
-        return;
-    }
-
-    entry = GPT_get_pointer_by_name(table, name);
-
-    if (!entry) {
-        fprintf(stderr, "Unable to find partition: %s", name);
-        return;
-    }
-    GPT_delete_entry(table, entry);
-}
-
diff --git a/fastbootd/other/partitions.sample.cfg b/fastbootd/other/partitions.sample.cfg
deleted file mode 100644
index 49562cf..0000000
--- a/fastbootd/other/partitions.sample.cfg
+++ /dev/null
@@ -1,60 +0,0 @@
-
-header_lba 1
-backup_lba 101
-first_lba 43
-last_lba 100
-entries_lba 2
-
-partitions {
-    #You can generate this as output from gptedit -c
-    SOS {
-        first_lba 28672
-        partition_size 16384
-    }
-
-    DTB {
-        first_lba 45056
-        partition_size 8192
-    }
-
-    LNX {
-        first_lba 53248
-        partition_size 16384
-    }
-
-    APP {
-        first_lba 69632
-        partition_size 1048576
-    }
-
-    CAC {
-        first_lba 1118208
-        partition_size 1572864
-    }
-
-    MSC {
-        first_lba 2691072
-        partition_size 4096
-    }
-
-    USP {
-        first_lba 2695168
-        partition_size 65536
-    }
-
-    MDA {
-        first_lba 2760704
-        partition_size 4096
-    }
-
-    FCT {
-        first_lba 2764800
-        partition_size 32768
-    }
-
-    UDA {
-        first_lba 2797568
-        partition_size 27975680
-    }
-}
-
diff --git a/fastbootd/other/sign/src/SignImg.java b/fastbootd/other/sign/src/SignImg.java
deleted file mode 100644
index 338d427..0000000
--- a/fastbootd/other/sign/src/SignImg.java
+++ /dev/null
@@ -1,181 +0,0 @@
-package signtool;
-
-import java.io.*;
-import java.util.Properties;
-import java.util.ArrayList;
-
-import javax.mail.internet.*;
-import javax.mail.MessagingException;
-import javax.mail.Session;
-import javax.activation.MailcapCommandMap;
-import javax.activation.CommandMap;
-
-import java.security.PrivateKey;
-import java.security.Security;
-import java.security.KeyFactory;
-import java.security.KeyStore;
-import java.security.NoSuchAlgorithmException;
-import java.security.spec.PKCS8EncodedKeySpec;
-import java.security.spec.InvalidKeySpecException;
-import java.security.cert.X509Certificate;
-import java.security.cert.CertificateFactory;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateEncodingException;
-
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
-import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
-import org.bouncycastle.operator.ContentSigner;
-import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
-import org.bouncycastle.cms.CMSProcessableByteArray;
-import org.bouncycastle.cms.CMSSignedGenerator;
-import org.bouncycastle.cms.CMSSignedDataGenerator;
-import org.bouncycastle.cms.CMSSignedGenerator;
-import org.bouncycastle.cms.CMSProcessable;
-import org.bouncycastle.cms.CMSSignedData;
-import org.bouncycastle.cms.CMSTypedData;
-import org.bouncycastle.cert.jcajce.JcaCertStore;
-import org.bouncycastle.util.Store;
-import org.bouncycastle.asn1.ASN1InputStream;    
-import org.bouncycastle.asn1.DEROutputStream;
-import org.bouncycastle.asn1.ASN1Object;
-
-
-public class SignImg {
-
-    /* It reads private key in pkcs#8 formate
-     * Conversion:
-     * openssl pkcs8 -topk8 -nocrypt -outform DER < inkey.pem > outkey.pk8
-     */
-    private static PrivateKey getPrivateKey(String path) throws IOException, FileNotFoundException, NoSuchAlgorithmException, InvalidKeySpecException {
-        File file = new File(path);
-        FileInputStream fis = new FileInputStream(file);
-        byte[] data = new byte[(int)file.length()];
-        fis.read(data);
-        fis.close();
-
-        PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(data);
-        KeyFactory kf = KeyFactory.getInstance("RSA");
-        PrivateKey privateKey = kf.generatePrivate(kspec);
-
-        return privateKey;
-    }
-
-    private static MimeBodyPart getContent(String path) throws IOException, FileNotFoundException, MessagingException {
-        MimeBodyPart body = new MimeBodyPart();
-
-        File file = new File(path);
-        FileInputStream fis = new FileInputStream(file);
-        byte[] data = new byte[(int)file.length()];
-        fis.read(data);
-        fis.close();
-
-        body.setContent(data, "application/octet-stream");
-
-        return body;
-    }
-
-    private static CMSProcessableByteArray getCMSContent(String path) throws IOException, FileNotFoundException, MessagingException {
-        File file = new File(path);
-        FileInputStream fis = new FileInputStream(file);
-        byte[] data = new byte[(int)file.length()];
-        fis.read(data);
-        fis.close();
-        CMSProcessableByteArray cms = new CMSProcessableByteArray(data);
-
-        return cms;
-    }
-
-    private static X509Certificate readCert(String path) throws IOException, FileNotFoundException, CertificateException {
-        File file = new File(path);
-        FileInputStream is = new FileInputStream(file);
-
-        CertificateFactory cf = CertificateFactory.getInstance("X.509");
-        Certificate cert = cf.generateCertificate(is);
-        is.close();
-
-        return (X509Certificate) cert;
-    }
-
-    private static void save(MimeBodyPart content, String path) throws IOException, FileNotFoundException, MessagingException {
-        File file = new File(path);
-        FileOutputStream os = new FileOutputStream(file);
-
-        content.writeTo(os);
-
-        os.close();
-    }
-
-    private static Store certToStore(X509Certificate certificate) throws CertificateEncodingException {
-        ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>();
-        certList.add(certificate);
-        return new JcaCertStore(certList);
-    }
-
-    public static void setDefaultMailcap()
-    {
-        MailcapCommandMap _mailcap =
-            (MailcapCommandMap)CommandMap.getDefaultCommandMap();
-
-        _mailcap.addMailcap("application/pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_signature");
-        _mailcap.addMailcap("application/pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_mime");
-        _mailcap.addMailcap("application/x-pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_signature");
-        _mailcap.addMailcap("application/x-pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_mime");
-        _mailcap.addMailcap("multipart/signed;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.multipart_signed");
-
-        CommandMap.setDefaultCommandMap(_mailcap);
-    } 
-
-    public static void main(String[] args) {
-        try {
-            if (args.length < 4) {
-                System.out.println("Usage: signimg data private_key certificate output");
-                return;
-            }
-            System.out.println("Signing the image");
-            setDefaultMailcap();
-
-            Security.addProvider(new BouncyCastleProvider());
-
-            PrivateKey key = getPrivateKey(args[1]);
-            System.out.println("File read sucessfully");
-
-            CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
-
-            CMSTypedData body = getCMSContent(args[0]);
-            System.out.println("Content read sucessfully");
-
-            X509Certificate cert = (X509Certificate) readCert(args[2]);
-            System.out.println("Certificate read sucessfully");
-
-            ContentSigner sha256Signer = new JcaContentSignerBuilder("SHA256withRSA").setProvider("BC").build(key);
-
-            Store certs = certToStore(cert);
-
-            generator.addCertificates(certs);
-            generator.addSignerInfoGenerator(
-                          new JcaSignerInfoGeneratorBuilder(
-                                new JcaDigestCalculatorProviderBuilder().setProvider("BC").build())
-                          .build(sha256Signer, cert));
-
-            CMSSignedData signed = generator.generate(body, true);
-            System.out.println("Signed");
-
-            Properties props = System.getProperties();
-            Session session = Session.getDefaultInstance(props, null);
-            
-            File file = new File(args[3]);
-            FileOutputStream os = new FileOutputStream(file);
-
-            ASN1InputStream asn1 = new ASN1InputStream(signed.getEncoded());
-            ByteArrayOutputStream out = new ByteArrayOutputStream(); 
-            DEROutputStream dOut = new DEROutputStream(os); 
-            dOut.writeObject(ASN1Object.fromByteArray(signed.getEncoded()));
-
-        }
-        catch (Exception ex) {
-            System.out.println("Exception during programm execution: " + ex.getMessage());
-        }
-    }
-}
diff --git a/fastbootd/protocol.c b/fastbootd/protocol.c
deleted file mode 100644
index 3908020..0000000
--- a/fastbootd/protocol.c
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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 <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "debug.h"
-#include "protocol.h"
-#include "transport.h"
-
-#define STATE_OFFLINE   0
-#define STATE_COMMAND   1
-#define STATE_COMPLETE  2
-#define STATE_ERROR     3
-
-struct fastboot_cmd {
-    struct fastboot_cmd *next;
-    const char *prefix;
-    unsigned prefix_len;
-    void (*execute)(struct protocol_handle *phandle, const char *arg);
-};
-
-struct fastboot_var {
-    struct fastboot_var *next;
-    const char *name;
-    const char *value;
-};
-
-static struct fastboot_cmd *cmdlist;
-
-void fastboot_register(const char *prefix,
-        void (*phandle)(struct protocol_handle *phandle, const char *arg))
-{
-    struct fastboot_cmd *cmd;
-    cmd = malloc(sizeof(*cmd));
-    if (cmd) {
-        cmd->prefix = prefix;
-        cmd->prefix_len = strlen(prefix);
-        cmd->execute = phandle;
-        cmd->next = cmdlist;
-        cmdlist = cmd;
-    }
-}
-
-static struct fastboot_var *varlist;
-
-void fastboot_publish(const char *name, const char *value)
-{
-    struct fastboot_var *var;
-    var = malloc(sizeof(*var));
-    if (var) {
-        var->name = name;
-        var->value = value;
-        var->next = varlist;
-        varlist = var;
-    }
-}
-
-const char *fastboot_getvar(const char *name)
-{
-    struct fastboot_var *var;
-
-    for (var = varlist; var; var = var->next) {
-        if (!strcmp(var->name, name)) {
-            return var->value;
-        }
-    }
-
-    return "";
-}
-
-int protocol_handle_download(struct protocol_handle *phandle, size_t len)
-{
-    return transport_handle_download(phandle->transport_handle, len);
-}
-
-static ssize_t protocol_handle_write(struct protocol_handle *phandle,
-        char *buffer, size_t len)
-{
-    return transport_handle_write(phandle->transport_handle, buffer, len);
-}
-
-static void fastboot_ack(struct protocol_handle *phandle, const char *code,
-        const char *reason)
-{
-    char response[64];
-
-    if (phandle->state != STATE_COMMAND)
-        return;
-
-    if (reason == 0)
-        reason = "";
-
-    snprintf(response, 64, "%s%s", code, reason);
-    phandle->state = STATE_COMPLETE;
-
-    protocol_handle_write(phandle, response, strlen(response));
-}
-
-void fastboot_fail(struct protocol_handle *phandle, const char *reason)
-{
-    fastboot_ack(phandle, "FAIL", reason);
-}
-
-void fastboot_okay(struct protocol_handle *phandle, const char *info)
-{
-    fastboot_ack(phandle, "OKAY", info);
-}
-
-void fastboot_data(struct protocol_handle *phandle, size_t len)
-{
-    char response[64];
-    ssize_t ret;
-
-    snprintf(response, 64, "DATA%08zx", len);
-    ret = protocol_handle_write(phandle, response, strlen(response));
-    if (ret < 0)
-        return;
-}
-
-void protocol_handle_command(struct protocol_handle *phandle, char *buffer)
-{
-    D(INFO,"fastboot: %s\n", buffer);
-
-    struct fastboot_cmd *cmd;
-
-    for (cmd = cmdlist; cmd; cmd = cmd->next) {
-        if (memcmp(buffer, cmd->prefix, cmd->prefix_len))
-            continue;
-        phandle->state = STATE_COMMAND;
-        cmd->execute(phandle, buffer + cmd->prefix_len);
-        if (phandle->state == STATE_COMMAND)
-            fastboot_fail(phandle, "unknown reason");
-        return;
-    }
-
-    fastboot_fail(phandle, "unknown command");
-}
-
-struct protocol_handle *create_protocol_handle(struct transport_handle *thandle)
-{
-    struct protocol_handle *phandle;
-
-    phandle = calloc(sizeof(struct protocol_handle), 1);
-
-    phandle->transport_handle = thandle;
-    phandle->state = STATE_OFFLINE;
-    phandle->download_fd = -1;
-
-    pthread_mutex_init(&phandle->lock, NULL);
-
-    return phandle;
-}
-
-int protocol_get_download(struct protocol_handle *phandle)
-{
-    int fd;
-
-    pthread_mutex_lock(&phandle->lock);
-    fd = phandle->download_fd;
-    phandle->download_fd = -1;
-    pthread_mutex_unlock(&phandle->lock);
-
-    return fd;
-}
diff --git a/fastbootd/protocol.h b/fastbootd/protocol.h
deleted file mode 100644
index ea2a8df..0000000
--- a/fastbootd/protocol.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2013, Google Inc.
- * 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.
- */
-
-#ifndef _FASTBOOTD_PROTOCOL_H_
-#define _FASTBOOTD_PROTOCOL_H_
-
-#include <pthread.h>
-#include <stddef.h>
-
-struct protocol_handle {
-    struct transport_handle *transport_handle;
-    unsigned int state;
-    int download_fd;
-
-    pthread_mutex_t lock;
-};
-
-void fastboot_register(const char *prefix,
-               void (*handle)(struct protocol_handle *handle, const char *arg));
-
-void fastboot_publish(const char *name, const char *value);
-const char *fastboot_getvar(const char *name);
-
-struct protocol_handle *create_protocol_handle(struct transport_handle *t);
-void protocol_handle_command(struct protocol_handle *handle, char *buffer);
-int protocol_handle_download(struct protocol_handle *phandle, size_t len);
-int protocol_get_download(struct protocol_handle *phandle);
-
-void fastboot_fail(struct protocol_handle *handle, const char *reason);
-void fastboot_okay(struct protocol_handle *handle, const char *reason);
-void fastboot_data(struct protocol_handle *handle, size_t len);
-
-#endif
diff --git a/fastbootd/secure.c b/fastbootd/secure.c
deleted file mode 100644
index 186e026..0000000
--- a/fastbootd/secure.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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 <openssl/pem.h>
-#include <openssl/engine.h>
-#include <openssl/x509.h>
-#include <openssl/x509v3.h>
-#include <openssl/pem.h>
-#include <openssl/cms.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "secure.h"
-#include "debug.h"
-#include "utils.h"
-
-
-void cert_init_crypto() {
-    CRYPTO_malloc_init();
-    ERR_load_crypto_strings();
-    OpenSSL_add_all_algorithms();
-    ENGINE_load_builtin_engines();
-}
-
-X509_STORE *cert_store_from_path(const char *path) {
-
-    X509_STORE *store;
-    struct stat st;
-    X509_LOOKUP *lookup;
-
-    if (stat(path, &st)) {
-        D(ERR, "Unable to stat cert path");
-        goto error;
-    }
-
-    if (!(store = X509_STORE_new())) {
-        goto error;
-    }
-
-    if (S_ISDIR(st.st_mode)) {
-        lookup = X509_STORE_add_lookup(store,X509_LOOKUP_hash_dir());
-        if (lookup == NULL)
-            goto error;
-        if (!X509_LOOKUP_add_dir(lookup, path, X509_FILETYPE_PEM)) {
-            D(ERR, "Error loading cert directory %s", path);
-            goto error;
-        }
-    }
-    else if(S_ISREG(st.st_mode)) {
-        lookup = X509_STORE_add_lookup(store,X509_LOOKUP_file());
-        if (lookup == NULL)
-            goto error;
-        if (!X509_LOOKUP_load_file(lookup, path, X509_FILETYPE_PEM)) {
-            D(ERR, "Error loading cert directory %s", path);
-            goto error;
-        }
-    }
-    else {
-        D(ERR, "cert path is not directory or regular file");
-        goto error;
-    }
-
-    return store;
-
-error:
-    return NULL;
-}
-
-
-int cert_read(int fd, CMS_ContentInfo **content, BIO **output) {
-    BIO *input;
-    *output = NULL;
-
-
-    input = BIO_new_fd(fd, BIO_NOCLOSE);
-    if (input == NULL) {
-        D(ERR, "Unable to open input");
-        goto error;
-    }
-
-    //TODO:
-    // read with d2i_CMS_bio to support DER
-    // with java or just encode data with base64
-    *content = SMIME_read_CMS(input, output);
-    if (*content == NULL) {
-        unsigned long err = ERR_peek_last_error();
-        D(ERR, "Unable to parse input file: %s", ERR_lib_error_string(err));
-        goto error_read;
-    }
-
-    BIO_free(input);
-
-    return 0;
-
-error_read:
-    BIO_free(input);
-error:
-    return 1;
-}
-
-int cert_verify(BIO *content, CMS_ContentInfo *content_info, X509_STORE *store, int *out_fd) {
-    BIO *output_temp;
-    int ret;
-
-    *out_fd = create_temp_file();
-    if (*out_fd < 0) {
-        D(ERR, "unable to create temporary file");
-        return -1;
-    }
-
-    output_temp = BIO_new_fd(*out_fd, BIO_NOCLOSE);
-    if (output_temp == NULL) {
-        D(ERR, "unable to create temporary bio");
-        close(*out_fd);
-        return -1;
-    }
-
-    ret = CMS_verify(content_info, NULL ,store, content, output_temp, 0);
-
-    if (ret == 0) {
-        char buf[256];
-        unsigned long err = ERR_peek_last_error();
-        D(ERR, "Verification failed with reason: %s, %s", ERR_lib_error_string(err),  ERR_error_string(err, buf));
-        D(ERR, "Data used: content %p", content);
-    }
-
-    ERR_clear_error();
-    ERR_remove_state(0);
-
-    BIO_free(output_temp);
-
-    return ret;
-}
-
-void cert_release(BIO *content, CMS_ContentInfo *info) {
-    BIO_free(content);
-    CMS_ContentInfo_free(info);
-}
-
diff --git a/fastbootd/secure.h b/fastbootd/secure.h
deleted file mode 100644
index 878a643..0000000
--- a/fastbootd/secure.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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.
- */
-
-#ifndef _FASTBOOTD_SECURE_H
-#define _FASTBOOTD_SECURE_H
-
-#include <openssl/ssl.h>
-#include <openssl/x509.h>
-#include <openssl/x509v3.h>
-#include <openssl/pem.h>
-#include <openssl/cms.h>
-
-void cert_init_crypto();
-
-X509_STORE *cert_store_from_path(const char*stream);
-
-static inline void cert_release_store(X509_STORE *store) {
-    X509_STORE_free(store);
-}
-
-int cert_read(int fd, CMS_ContentInfo **content, BIO **output);
-int cert_verify(BIO *content, CMS_ContentInfo *content_info, X509_STORE *store, int *out_fd);
-void cert_release(BIO *content, CMS_ContentInfo *info);
-
-#endif
diff --git a/fastbootd/socket_client.c b/fastbootd/socket_client.c
deleted file mode 100644
index da636db..0000000
--- a/fastbootd/socket_client.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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 <cutils/sockets.h>
-#include <poll.h>
-#include <unistd.h>
-
-#include "utils.h"
-
-#define BUFFER_SIZE 256
-
-#define STDIN_FD 0
-#define STDOUT_FD 1
-#define STDERR_FD 2
-
-void run_socket_client() {
-    int fd;
-    char buffer[BUFFER_SIZE];
-    int n;
-    struct pollfd fds[2];
-
-    fd = socket_local_client("fastbootd",
-                         ANDROID_SOCKET_NAMESPACE_RESERVED,
-                         SOCK_STREAM);
-
-    if (fd < 0) {
-        fprintf(stderr, "ERROR: Unable to open fastbootd socket\n");
-        return;
-    }
-
-    fds[0].fd = STDIN_FD;
-    fds[0].events = POLLIN;
-    fds[1].fd = fd;
-    fds[1].events = POLLIN;
-
-    while(true) {
-        if (poll(fds, 2, -1) <= 0) {
-            fprintf(stderr, "ERROR: socket error");
-            return;
-        }
-
-        if (fds[0].revents & POLLIN) {
-            if ((n = read(STDIN_FD, buffer, BUFFER_SIZE)) < 0) {
-                goto error;
-            }
-
-            if (bulk_write(fd, buffer, n) < 0) {
-                goto error;
-            }
-        }
-
-        if (fds[1].revents & POLLIN) {
-            if ((n = read(fd, buffer, BUFFER_SIZE)) < 0) {
-                goto error;
-            }
-
-            if (bulk_write(STDOUT_FD, buffer, n) < 0) {
-                goto error;
-            }
-        }
-    }
-
-error:
-    fprintf(stderr, "Transport error\n");
-}
diff --git a/fastbootd/transport.c b/fastbootd/transport.c
deleted file mode 100644
index 9a16fd7..0000000
--- a/fastbootd/transport.c
+++ /dev/null
@@ -1,150 +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.
- */
-
-#include <pthread.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/mman.h>
-
-#include "debug.h"
-#include "protocol.h"
-#include "transport.h"
-
-#define COMMAND_BUF_SIZE 64
-
-ssize_t transport_handle_write(struct transport_handle *thandle, char *buffer, size_t len)
-{
-    return thandle->transport->write(thandle, buffer, len);
-}
-
-void transport_handle_close(struct transport_handle *thandle)
-{
-    thandle->transport->close(thandle);
-}
-
-int transport_handle_download(struct transport_handle *thandle, size_t len)
-{
-    ssize_t ret;
-    size_t n = 0;
-    int fd;
-    // TODO: move out of /dev
-    char tempname[] = "/dev/fastboot_download_XXXXXX";
-    char *buffer;
-
-    fd = mkstemp(tempname);
-    if (fd < 0)
-        return -1;
-
-    unlink(tempname);
-
-    ftruncate(fd, len);
-
-    buffer = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-    if (buffer == MAP_FAILED) {
-        D(ERR, "mmap(%zu) failed: %d %s", len, errno, strerror(errno));
-        goto err;
-    }
-
-    while (n < len) {
-        ret = thandle->transport->read(thandle, buffer + n, len - n);
-        if (ret <= 0) {
-            D(WARN, "transport read failed, ret=%zd %s", ret, strerror(-ret));
-            break;
-        }
-        n += ret;
-    }
-
-    munmap(buffer, len);
-
-    if (n != len)
-        goto err;
-
-    return fd;
-
-err:
-    close(fd);
-    transport_handle_close(thandle);
-    return -1;
-}
-
-static void *transport_data_thread(void *arg)
-{
-    struct transport_handle *thandle = arg;
-    struct protocol_handle *phandle = create_protocol_handle(thandle);
-
-    while (!thandle->stopped) {
-        int ret;
-        char buffer[COMMAND_BUF_SIZE + 1];
-        D(VERBOSE, "transport_data_thread\n");
-
-        ret = thandle->transport->read(thandle, buffer, COMMAND_BUF_SIZE);
-        if (ret <= 0) {
-            D(DEBUG, "ret = %d\n", ret);
-            break;
-        }
-        if (ret > 0) {
-            buffer[ret] = 0;
-            //TODO: multiple threads
-            protocol_handle_command(phandle, buffer);
-        }
-    }
-
-    transport_handle_close(thandle);
-    free(thandle);
-
-    return NULL;
-}
-
-static void *transport_connect_thread(void *arg)
-{
-    struct transport *transport = arg;
-    while (!transport->stopped) {
-        struct transport_handle *thandle;
-        pthread_t thread;
-        pthread_attr_t attr;
-
-        D(VERBOSE, "transport_connect_thread\n");
-        thandle = transport->connect(transport);
-        if (thandle == NULL) {
-            D(ERR, "transport connect failed\n");
-            sleep(1);
-            continue;
-        }
-        thandle->transport = transport;
-
-        pthread_attr_init(&attr);
-        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
-        pthread_create(&thread, &attr, transport_data_thread, thandle);
-
-        sleep(1);
-    }
-
-    return NULL;
-}
-
-void transport_register(struct transport *transport)
-{
-    pthread_t thread;
-    pthread_attr_t attr;
-
-    pthread_attr_init(&attr);
-    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
-    pthread_create(&thread, &attr, transport_connect_thread, transport);
-}
diff --git a/fastbootd/transport.h b/fastbootd/transport.h
deleted file mode 100644
index 209340d..0000000
--- a/fastbootd/transport.h
+++ /dev/null
@@ -1,41 +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 _FASTBOOTD_TRANSPORT_H_
-#define _FASTBOOTD_TRANSPORT_H_
-
-#include <stdbool.h>
-
-struct transport_handle {
-    struct transport *transport;
-
-    bool stopped;
-};
-
-struct transport {
-    void (*init)();
-    void (*close)(struct transport_handle *thandle);
-    ssize_t (*read)(struct transport_handle *thandle, void *data, size_t len);
-    ssize_t (*write)(struct transport_handle *thandle, const void *data, size_t len);
-    struct transport_handle *(*connect)(struct transport *transport);
-    bool stopped;
-};
-
-void transport_register(struct transport *transport);
-ssize_t transport_handle_write(struct transport_handle *handle, char *buffer, size_t len);
-int transport_handle_download(struct transport_handle *handle, size_t len);
-
-#endif
diff --git a/fastbootd/transport_socket.c b/fastbootd/transport_socket.c
deleted file mode 100644
index 664d473..0000000
--- a/fastbootd/transport_socket.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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 <stdlib.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <unistd.h>
-#include <cutils/sockets.h>
-
-#include "debug.h"
-#include "transport.h"
-#include "utils.h"
-
-
-#define container_of(ptr, type, member) \
-    ((type*)((char*)(ptr) - offsetof(type, member)))
-
-#define SOCKET_WORKING 0
-#define SOCKET_STOPPED -1
-
-
-struct socket_transport {
-    struct transport transport;
-
-    int fd;
-};
-
-struct socket_handle {
-    struct transport_handle handle;
-
-    int fd;
-};
-
-void socket_close(struct transport_handle *thandle)
-{
-    struct socket_handle * handle = container_of(thandle, struct socket_handle, handle);
-    close(handle->fd);
-}
-
-struct transport_handle *socket_connect(struct transport *transport)
-{
-    struct socket_handle *handle = calloc(sizeof(struct socket_handle), 1);
-    struct socket_transport *socket_transport = container_of(transport, struct socket_transport, transport);
-    struct sockaddr addr;
-    socklen_t alen = sizeof(addr);
-
-    handle->fd = accept(socket_transport->fd, &addr, &alen);
-
-    if (handle->fd < 0) {
-        D(WARN, "socket connect error");
-        return NULL;
-    }
-
-    D(DEBUG, "[ socket_thread - registering device ]");
-    return &handle->handle;
-}
-
-ssize_t socket_write(struct transport_handle *thandle, const void *data, size_t len)
-{
-    ssize_t ret;
-    struct socket_handle *handle = container_of(thandle, struct socket_handle, handle);
-
-    D(DEBUG, "about to write (fd=%d, len=%zu)", handle->fd, len);
-    ret = bulk_write(handle->fd, data, len);
-    if (ret < 0) {
-        D(ERR, "ERROR: fd = %d, ret = %zd", handle->fd, ret);
-        return -1;
-    }
-    D(DEBUG, "[ socket_write done fd=%d ]", handle->fd);
-    return ret;
-}
-
-ssize_t socket_read(struct transport_handle *thandle, void *data, size_t len)
-{
-    ssize_t ret;
-    struct socket_handle *handle = container_of(thandle, struct socket_handle, handle);
-
-    D(DEBUG, "about to read (fd=%d, len=%zu)", handle->fd, len);
-    ret = bulk_read(handle->fd, data, len);
-    if (ret < 0) {
-        D(ERR, "ERROR: fd = %d, ret = %zd", handle->fd, ret);
-        return -1;
-    }
-    D(DEBUG, "[ socket_read done fd=%d ret=%zd]", handle->fd, ret);
-    return ret;
-}
-
-static int listen_socket_init(struct socket_transport *socket_transport)
-{
-    int s = android_get_control_socket("fastbootd");
-
-    if (s < 0) {
-        D(WARN, "android_get_control_socket(fastbootd): %s\n", strerror(errno));
-        return 0;
-    }
-
-    if (listen(s, 4) < 0) {
-        D(WARN, "listen(control socket): %s\n", strerror(errno));
-        return 0;
-    }
-
-    socket_transport->fd = s;
-
-    return 1;
-}
-
-
-int transport_socket_init()
-{
-    struct socket_transport *socket_transport = malloc(sizeof(struct socket_transport));
-
-    socket_transport->transport.connect = socket_connect;
-    socket_transport->transport.close = socket_close;
-    socket_transport->transport.read = socket_read;
-    socket_transport->transport.write = socket_write;
-
-    if (!listen_socket_init(socket_transport)) {
-        D(ERR, "socket transport init failed");
-        free(socket_transport);
-        return 0;
-    }
-
-    transport_register(&socket_transport->transport);
-    return 1;
-}
-
diff --git a/fastbootd/trigger.c b/fastbootd/trigger.c
deleted file mode 100644
index df0f895..0000000
--- a/fastbootd/trigger.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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 <dlfcn.h>
-
-#include <hardware/hardware.h>
-#include "debug.h"
-#include "trigger.h"
-#include "protocol.h"
-#include "vendor_trigger.h"
-
-static const int version = 1;
-
-int load_trigger() {
-    int libversion;
-
-    if (trigger_init() != 0) {
-        D(ERR, "libvendortrigger failed to initialize");
-        return 1;
-    }
-
-    if (trigger_check_version(version, &libversion)) {
-        D(ERR, "Library report incompability");
-        return 1;
-    }
-
-    D(INFO, "libvendortrigger loaded");
-    return 0;
-}
diff --git a/fastbootd/trigger.h b/fastbootd/trigger.h
deleted file mode 100644
index d2d9573..0000000
--- a/fastbootd/trigger.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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.
- */
-
-#ifndef __FASTBOOTD_TRIGGER_H_
-#define __FASTBOOTD_TRIGGER_H_
-
-#include "commands/partitions.h"
-#include "vendor_trigger.h"
-
-int load_trigger();
-
-#endif
diff --git a/fastbootd/usb_linux_client.c b/fastbootd/usb_linux_client.c
deleted file mode 100644
index 64420e9..0000000
--- a/fastbootd/usb_linux_client.c
+++ /dev/null
@@ -1,308 +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 <endian.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <sys/ioctl.h>
-#include <sys/types.h>
-
-#include <linux/usb/ch9.h>
-#include <linux/usb/functionfs.h>
-
-#include "debug.h"
-#include "transport.h"
-#include "utils.h"
-
-#define   TRACE_TAG  TRACE_USB
-
-#define MAX_PACKET_SIZE_FS     64
-#define MAX_PACKET_SIZE_HS     512
-
-#define cpu_to_le16(x)  htole16(x)
-#define cpu_to_le32(x)  htole32(x)
-
-#define FASTBOOT_CLASS         0xff
-#define FASTBOOT_SUBCLASS      0x42
-#define FASTBOOT_PROTOCOL      0x3
-
-#define USB_FFS_FASTBOOT_PATH  "/dev/usb-ffs/adb/"
-#define USB_FFS_FASTBOOT_EP(x) USB_FFS_FASTBOOT_PATH#x
-
-#define USB_FFS_FASTBOOT_EP0   USB_FFS_FASTBOOT_EP(ep0)
-#define USB_FFS_FASTBOOT_OUT   USB_FFS_FASTBOOT_EP(ep1)
-#define USB_FFS_FASTBOOT_IN    USB_FFS_FASTBOOT_EP(ep2)
-
-#define container_of(ptr, type, member) \
-    ((type*)((char*)(ptr) - offsetof(type, member)))
-
-struct usb_transport {
-    struct transport transport;
-
-    pthread_cond_t notify;
-    pthread_mutex_t lock;
-
-    int control;
-    int bulk_out; /* "out" from the host's perspective => source for fastbootd */
-    int bulk_in;  /* "in" from the host's perspective => sink for fastbootd */
-};
-
-struct usb_handle {
-    struct transport_handle handle;
-};
-
-static const struct {
-    struct usb_functionfs_descs_head header;
-    struct {
-        struct usb_interface_descriptor intf;
-        struct usb_endpoint_descriptor_no_audio source;
-        struct usb_endpoint_descriptor_no_audio sink;
-    } __attribute__((packed)) fs_descs, hs_descs;
-} __attribute__((packed)) descriptors = {
-    .header = {
-        .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC),
-        .length = cpu_to_le32(sizeof(descriptors)),
-        .fs_count = 3,
-        .hs_count = 3,
-    },
-    .fs_descs = {
-        .intf = {
-            .bLength = sizeof(descriptors.fs_descs.intf),
-            .bDescriptorType = USB_DT_INTERFACE,
-            .bInterfaceNumber = 0,
-            .bNumEndpoints = 2,
-            .bInterfaceClass = FASTBOOT_CLASS,
-            .bInterfaceSubClass = FASTBOOT_SUBCLASS,
-            .bInterfaceProtocol = FASTBOOT_PROTOCOL,
-            .iInterface = 1, /* first string from the provided table */
-        },
-        .source = {
-            .bLength = sizeof(descriptors.fs_descs.source),
-            .bDescriptorType = USB_DT_ENDPOINT,
-            .bEndpointAddress = 1 | USB_DIR_OUT,
-            .bmAttributes = USB_ENDPOINT_XFER_BULK,
-            .wMaxPacketSize = MAX_PACKET_SIZE_FS,
-        },
-        .sink = {
-            .bLength = sizeof(descriptors.fs_descs.sink),
-            .bDescriptorType = USB_DT_ENDPOINT,
-            .bEndpointAddress = 2 | USB_DIR_IN,
-            .bmAttributes = USB_ENDPOINT_XFER_BULK,
-            .wMaxPacketSize = MAX_PACKET_SIZE_FS,
-        },
-    },
-    .hs_descs = {
-        .intf = {
-            .bLength = sizeof(descriptors.hs_descs.intf),
-            .bDescriptorType = USB_DT_INTERFACE,
-            .bInterfaceNumber = 0,
-            .bNumEndpoints = 2,
-            .bInterfaceClass = FASTBOOT_CLASS,
-            .bInterfaceSubClass = FASTBOOT_SUBCLASS,
-            .bInterfaceProtocol = FASTBOOT_PROTOCOL,
-            .iInterface = 1, /* first string from the provided table */
-        },
-        .source = {
-            .bLength = sizeof(descriptors.hs_descs.source),
-            .bDescriptorType = USB_DT_ENDPOINT,
-            .bEndpointAddress = 1 | USB_DIR_OUT,
-            .bmAttributes = USB_ENDPOINT_XFER_BULK,
-            .wMaxPacketSize = MAX_PACKET_SIZE_HS,
-        },
-        .sink = {
-            .bLength = sizeof(descriptors.hs_descs.sink),
-            .bDescriptorType = USB_DT_ENDPOINT,
-            .bEndpointAddress = 2 | USB_DIR_IN,
-            .bmAttributes = USB_ENDPOINT_XFER_BULK,
-            .wMaxPacketSize = MAX_PACKET_SIZE_HS,
-        },
-    },
-};
-
-#define STR_INTERFACE_ "Fastboot Interface"
-
-static const struct {
-    struct usb_functionfs_strings_head header;
-    struct {
-        __le16 code;
-        const char str1[sizeof(STR_INTERFACE_)];
-    } __attribute__((packed)) lang0;
-} __attribute__((packed)) strings = {
-    .header = {
-        .magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC),
-        .length = cpu_to_le32(sizeof(strings)),
-        .str_count = cpu_to_le32(1),
-        .lang_count = cpu_to_le32(1),
-    },
-    .lang0 = {
-        cpu_to_le16(0x0409), /* en-us */
-        STR_INTERFACE_,
-    },
-};
-
-static int init_functionfs(struct usb_transport *usb_transport)
-{
-    ssize_t ret;
-
-    D(VERBOSE, "OPENING %s", USB_FFS_FASTBOOT_EP0);
-    usb_transport->control = open(USB_FFS_FASTBOOT_EP0, O_RDWR);
-    if (usb_transport->control < 0) {
-        D(ERR, "[ %s: cannot open control endpoint: errno=%d]", USB_FFS_FASTBOOT_EP0, errno);
-        goto err;
-    }
-
-    ret = write(usb_transport->control, &descriptors, sizeof(descriptors));
-    if (ret < 0) {
-        D(ERR, "[ %s: write descriptors failed: errno=%d ]", USB_FFS_FASTBOOT_EP0, errno);
-        goto err;
-    }
-
-    ret = write(usb_transport->control, &strings, sizeof(strings));
-    if (ret < 0) {
-        D(ERR, "[ %s: writing strings failed: errno=%d]", USB_FFS_FASTBOOT_EP0, errno);
-        goto err;
-    }
-
-    usb_transport->bulk_out = open(USB_FFS_FASTBOOT_OUT, O_RDWR);
-    if (usb_transport->bulk_out < 0) {
-        D(ERR, "[ %s: cannot open bulk-out ep: errno=%d ]", USB_FFS_FASTBOOT_OUT, errno);
-        goto err;
-    }
-
-    usb_transport->bulk_in = open(USB_FFS_FASTBOOT_IN, O_RDWR);
-    if (usb_transport->bulk_in < 0) {
-        D(ERR, "[ %s: cannot open bulk-in ep: errno=%d ]", USB_FFS_FASTBOOT_IN, errno);
-        goto err;
-    }
-
-    return 0;
-
-err:
-    if (usb_transport->bulk_in > 0) {
-        close(usb_transport->bulk_in);
-        usb_transport->bulk_in = -1;
-    }
-    if (usb_transport->bulk_out > 0) {
-        close(usb_transport->bulk_out);
-        usb_transport->bulk_out = -1;
-    }
-    if (usb_transport->control > 0) {
-        close(usb_transport->control);
-        usb_transport->control = -1;
-    }
-    return -1;
-}
-
-static ssize_t usb_write(struct transport_handle *thandle, const void *data, size_t len)
-{
-    ssize_t ret;
-    struct transport *t = thandle->transport;
-    struct usb_transport *usb_transport = container_of(t, struct usb_transport, transport);
-
-    D(DEBUG, "about to write (fd=%d, len=%zu)", usb_transport->bulk_in, len);
-    ret = bulk_write(usb_transport->bulk_in, data, len);
-    if (ret < 0) {
-        D(ERR, "ERROR: fd = %d, ret = %zd", usb_transport->bulk_in, ret);
-        return -1;
-    }
-    D(DEBUG, "[ usb_write done fd=%d ]", usb_transport->bulk_in);
-    return ret;
-}
-
-ssize_t usb_read(struct transport_handle *thandle, void *data, size_t len)
-{
-    ssize_t ret;
-    struct transport *t = thandle->transport;
-    struct usb_transport *usb_transport = container_of(t, struct usb_transport, transport);
-
-    D(DEBUG, "about to read (fd=%d, len=%zu)", usb_transport->bulk_out, len);
-    ret = bulk_read(usb_transport->bulk_out, data, len);
-    if (ret < 0) {
-        D(ERR, "ERROR: fd = %d, ret = %zd", usb_transport->bulk_out, ret);
-        return -1;
-    }
-    D(DEBUG, "[ usb_read done fd=%d ret=%zd]", usb_transport->bulk_out, ret);
-    return ret;
-}
-
-void usb_close(struct transport_handle *thandle)
-{
-    int err;
-    struct transport *t = thandle->transport;
-    struct usb_transport *usb_transport = container_of(t, struct usb_transport, transport);
-
-    err = ioctl(usb_transport->bulk_in, FUNCTIONFS_CLEAR_HALT);
-    if (err < 0)
-        D(WARN, "[ kick: source (fd=%d) clear halt failed (%d) ]", usb_transport->bulk_in, errno);
-
-    err = ioctl(usb_transport->bulk_out, FUNCTIONFS_CLEAR_HALT);
-    if (err < 0)
-        D(WARN, "[ kick: sink (fd=%d) clear halt failed (%d) ]", usb_transport->bulk_out, errno);
-
-    pthread_mutex_lock(&usb_transport->lock);
-    close(usb_transport->control);
-    close(usb_transport->bulk_out);
-    close(usb_transport->bulk_in);
-    usb_transport->control = usb_transport->bulk_out = usb_transport->bulk_in = -1;
-
-    pthread_cond_signal(&usb_transport->notify);
-    pthread_mutex_unlock(&usb_transport->lock);
-}
-
-struct transport_handle *usb_connect(struct transport *transport)
-{
-    int ret;
-    struct usb_handle *usb_handle = calloc(sizeof(struct usb_handle), 1);
-    struct usb_transport *usb_transport = container_of(transport, struct usb_transport, transport);
-
-    pthread_mutex_lock(&usb_transport->lock);
-    while (usb_transport->control != -1)
-        pthread_cond_wait(&usb_transport->notify, &usb_transport->lock);
-    pthread_mutex_unlock(&usb_transport->lock);
-
-    ret = init_functionfs(usb_transport);
-    if (ret < 0) {
-        D(ERR, "usb connect: failed to initialize usb transport");
-        return NULL;
-    }
-
-    D(DEBUG, "[ usb_thread - registering device ]");
-    return &usb_handle->handle;
-}
-
-void usb_init()
-{
-    struct usb_transport *usb_transport = calloc(1, sizeof(struct usb_transport));
-
-    usb_transport->transport.connect = usb_connect;
-    usb_transport->transport.close = usb_close;
-    usb_transport->transport.read = usb_read;
-    usb_transport->transport.write = usb_write;
-    usb_transport->control  = -1;
-    usb_transport->bulk_out = -1;
-    usb_transport->bulk_out = -1;
-
-    pthread_cond_init(&usb_transport->notify, NULL);
-    pthread_mutex_init(&usb_transport->lock, NULL);
-
-    transport_register(&usb_transport->transport);
-}
-
diff --git a/fastbootd/utils.c b/fastbootd/utils.c
deleted file mode 100644
index bef2463..0000000
--- a/fastbootd/utils.c
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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 <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <sys/ioctl.h>
-#include <linux/fs.h>
-#include <stdlib.h>
-#include <cutils/properties.h>
-
-#include "utils.h"
-#include "debug.h"
-
-#ifndef BLKDISCARD
-#define BLKDISCARD _IO(0x12,119)
-#endif
-
-#ifndef BLKSECDISCARD
-#define BLKSECDISCARD _IO(0x12,125)
-#endif
-
-#define READ_BUF_SIZE (16*1024)
-
-int get_stream_size(FILE *stream) {
-    int size;
-    fseek(stream, 0, SEEK_END);
-    size = ftell(stream);
-    fseek(stream, 0, SEEK_SET);
-    return size;
-}
-
-uint64_t get_block_device_size(int fd)
-{
-    uint64_t size = 0;
-    int ret;
-
-    ret = ioctl(fd, BLKGETSIZE64, &size);
-
-    if (ret)
-        return 0;
-
-    return size;
-}
-
-uint64_t get_file_size(int fd)
-{
-    struct stat buf;
-    int ret;
-    int64_t computed_size;
-
-    ret = fstat(fd, &buf);
-    if (ret)
-        return 0;
-
-    if (S_ISREG(buf.st_mode))
-        computed_size = buf.st_size;
-    else if (S_ISBLK(buf.st_mode))
-        computed_size = get_block_device_size(fd);
-    else
-        computed_size = 0;
-
-    return computed_size;
-}
-
-uint64_t get_file_size64(int fd)
-{
-    struct stat64 buf;
-    int ret;
-    uint64_t computed_size;
-
-    ret = fstat64(fd, &buf);
-    if (ret)
-        return 0;
-
-    if (S_ISREG(buf.st_mode))
-        computed_size = buf.st_size;
-    else if (S_ISBLK(buf.st_mode))
-        computed_size = get_block_device_size(fd);
-    else
-        computed_size = 0;
-
-    return computed_size;
-}
-
-
-char *strip(char *str)
-{
-    int n;
-
-    n = strspn(str, " \t");
-    str += n;
-    n = strcspn(str, " \t");
-    str[n] = '\0';
-
-    return str;
-}
-
-int wipe_block_device(int fd, int64_t len)
-{
-    uint64_t range[2];
-    int ret;
-
-    range[0] = 0;
-    range[1] = len;
-    ret = ioctl(fd, BLKSECDISCARD, &range);
-    if (ret < 0) {
-        range[0] = 0;
-        range[1] = len;
-        ret = ioctl(fd, BLKDISCARD, &range);
-        if (ret < 0) {
-            D(WARN, "Discard failed\n");
-            return 1;
-        } else {
-            D(WARN, "Wipe via secure discard failed, used discard instead\n");
-            return 0;
-        }
-    }
-
-    return 0;
-}
-
-int create_temp_file() {
-    char tempname[] = "/dev/fastboot_data_XXXXXX";
-    int fd;
-
-    fd = mkstemp(tempname);
-    if (fd < 0)
-        return -1;
-
-    unlink(tempname);
-
-    return fd;
-}
-
-ssize_t bulk_write(int bulk_in, const char *buf, size_t length)
-{
-    size_t count = 0;
-    ssize_t ret;
-
-    do {
-        ret = TEMP_FAILURE_RETRY(write(bulk_in, buf + count, length - count));
-        if (ret < 0) {
-            D(WARN, "[ bulk_write failed fd=%d length=%zu errno=%d %s ]",
-                    bulk_in, length, errno, strerror(errno));
-            return -1;
-        } else {
-            count += ret;
-        }
-    } while (count < length);
-
-    D(VERBOSE, "[ bulk_write done fd=%d ]", bulk_in);
-    return count;
-}
-
-ssize_t bulk_read(int bulk_out, char *buf, size_t length)
-{
-    ssize_t ret;
-    size_t n = 0;
-
-    while (n < length) {
-        size_t to_read = (length - n > READ_BUF_SIZE) ? READ_BUF_SIZE : length - n;
-        ret = TEMP_FAILURE_RETRY(read(bulk_out, buf + n, to_read));
-        if (ret < 0) {
-            D(WARN, "[ bulk_read failed fd=%d length=%zu errno=%d %s ]",
-                    bulk_out, length, errno, strerror(errno));
-            return ret;
-        }
-        n += ret;
-        if (ret < (ssize_t)to_read) {
-            D(VERBOSE, "bulk_read short read, ret=%zd to_read=%zu n=%zu length=%zu",
-                    ret, to_read, n, length);
-            break;
-        }
-    }
-
-    return n;
-}
-
-#define NAP_TIME 200  // 200 ms between polls
-static int wait_for_property(const char *name, const char *desired_value, int maxwait)
-{
-    char value[PROPERTY_VALUE_MAX] = {'\0'};
-    int maxnaps = (maxwait * 1000) / NAP_TIME;
-
-    if (maxnaps < 1) {
-        maxnaps = 1;
-    }
-
-    while (maxnaps-- > 0) {
-        usleep(NAP_TIME * 1000);
-        if (property_get(name, value, NULL)) {
-            if (desired_value == NULL || strcmp(value, desired_value) == 0) {
-                return 0;
-            }
-        }
-    }
-    return -1; /* failure */
-}
-
-int service_start(const char *service_name)
-{
-    int result = 0;
-    char property_value[PROPERTY_VALUE_MAX];
-
-    property_get(service_name, property_value, "");
-    if (strcmp("running", property_value) != 0) {
-        D(INFO, "Starting %s", service_name);
-        property_set("ctl.start", service_name);
-        if (wait_for_property(service_name, "running", 5))
-            result = -1;
-    }
-
-    return result;
-}
-
-int service_stop(const char *service_name)
-{
-    int result = 0;
-
-    D(INFO, "Stopping MDNSD");
-    property_set("ctl.stop", service_name);
-    if (wait_for_property(service_name, "stopped", 5))
-        result = -1;
-
-    return result;
-}
-
-int ssh_server_start()
-{
-    return service_start("sshd");
-}
diff --git a/fastbootd/utils.h b/fastbootd/utils.h
deleted file mode 100644
index 3d98699..0000000
--- a/fastbootd/utils.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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.
- */
-
-#ifndef _FASTBOOT_UTLIS_H
-#define _FASTBOOT_UTILS_H
-
-#include <stdio.h>
-
-int get_stream_size(FILE *);
-
-char *strip(char *str);
-
-uint64_t get_file_size64(int fd);
-uint64_t get_file_size(int fd);
-uint64_t get_block_device_size(int fd);
-int wipe_block_device(int fd, int64_t len);
-int create_temp_file();
-ssize_t bulk_read(int bulk_out, char *buf, size_t length);
-ssize_t bulk_write(int bulk_in, const char *buf, size_t length);
-int service_start(const char *service_name);
-int service_stop(const char *service_name);
-int ssh_server_start();
-
-#define ROUND_TO_PAGE(address,pagesize) ((address + pagesize - 1) & (~(pagesize - 1)))
-
-#define ROUND_UP(number,size) (((number + size - 1) / size) * size)
-
-#endif
diff --git a/fastbootd/vendor_trigger.h b/fastbootd/vendor_trigger.h
deleted file mode 100644
index 0c83be6..0000000
--- a/fastbootd/vendor_trigger.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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.
- */
-
-#ifndef __VENDOR_TRIGGER_H_
-#define __VENDOR_TRIGGER_H_
-
-__BEGIN_DECLS
-
-struct GPT_entry_raw;
-struct GPT_content;
-
-/*
- * Implemented in libvendortrigger to handle platform-specific behavior.
- */
-
-/*
- * trigger_init() is called once at startup time before calling any other method
- *
- * returns 0 on success and nonzero on error
- */
-int trigger_init(void);
-
-/*
- * This function runs once after trigger_init completes.
- *
- * version is number parameter indicating version on the fastbootd side
- * libversion is version indicateing version of the library version
- *
- * returns 0 if it can cooperate with the current version and 1 in opposite
- */
-int trigger_check_version(const int version, int *libversion);
-
-/*
- * Return value -1 forbid the action from the vendor site and sets errno
- */
-int trigger_gpt_layout(struct GPT_content *);
-int trigger_oem_cmd(const char *arg, const char **response);
-
-__END_DECLS
-
-#endif
diff --git a/fastbootd/vendor_trigger_default.c b/fastbootd/vendor_trigger_default.c
deleted file mode 100644
index 3627024..0000000
--- a/fastbootd/vendor_trigger_default.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * 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 <stdlib.h>
-#include <cutils/klog.h>
-#include <vendor_trigger.h>
-
-static const int version = 1;
-
-int trigger_init(void) {
-    klog_init();
-    klog_set_level(7);
-    return 0;
-}
-
-int trigger_check_version(const int fastboot_version, int *libversion) {
-    KLOG_DEBUG("fastbootd", "%s: %d (%d)", __func__, fastboot_version, version);
-    *libversion = version;
-    return !(fastboot_version == version);
-}
-
-int trigger_gpt_layout(struct GPT_content *table) {
-    KLOG_DEBUG("fastbootd", "%s: %p", __func__, table);
-    return 0;
-}
-
-int trigger_oem_cmd(const char *arg, const char **response) {
-    KLOG_DEBUG("fastbootd", "%s: %s", __func__, arg);
-    return 0;
-}
diff --git a/fingerprintd/Android.mk b/fingerprintd/Android.mk
new file mode 100644
index 0000000..48b9525
--- /dev/null
+++ b/fingerprintd/Android.mk
@@ -0,0 +1,33 @@
+#
+# 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)
+
+include $(CLEAR_VARS)
+LOCAL_CFLAGS := -Wall -Wextra -Werror -Wunused
+LOCAL_SRC_FILES := \
+	FingerprintDaemonProxy.cpp \
+	IFingerprintDaemon.cpp \
+	IFingerprintDaemonCallback.cpp \
+	fingerprintd.cpp
+LOCAL_MODULE := fingerprintd
+LOCAL_SHARED_LIBRARIES := \
+	libbinder \
+	liblog \
+	libhardware \
+	libutils \
+	libkeystore_binder
+include $(BUILD_EXECUTABLE)
diff --git a/fingerprintd/FingerprintDaemonProxy.cpp b/fingerprintd/FingerprintDaemonProxy.cpp
new file mode 100644
index 0000000..beb95de
--- /dev/null
+++ b/fingerprintd/FingerprintDaemonProxy.cpp
@@ -0,0 +1,253 @@
+/*
+ * 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 "fingerprintd"
+
+#include <binder/IServiceManager.h>
+#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 "FingerprintDaemonProxy.h"
+
+namespace android {
+
+FingerprintDaemonProxy* FingerprintDaemonProxy::sInstance = NULL;
+
+// Supported fingerprint HAL version
+static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(2, 0);
+
+FingerprintDaemonProxy::FingerprintDaemonProxy() : mModule(NULL), mDevice(NULL), mCallback(NULL) {
+
+}
+
+FingerprintDaemonProxy::~FingerprintDaemonProxy() {
+    closeHal();
+}
+
+void FingerprintDaemonProxy::hal_notify_callback(const fingerprint_msg_t *msg) {
+    FingerprintDaemonProxy* instance = FingerprintDaemonProxy::getInstance();
+    const sp<IFingerprintDaemonCallback> callback = instance->mCallback;
+    if (callback == NULL) {
+        ALOGE("Invalid callback object");
+        return;
+    }
+    const int64_t device = (int64_t) instance->mDevice;
+    switch (msg->type) {
+        case FINGERPRINT_ERROR:
+            ALOGD("onError(%d)", msg->data.error);
+            callback->onError(device, msg->data.error);
+            break;
+        case FINGERPRINT_ACQUIRED:
+            ALOGD("onAcquired(%d)", msg->data.acquired.acquired_info);
+            callback->onAcquired(device, msg->data.acquired.acquired_info);
+            break;
+        case FINGERPRINT_AUTHENTICATED:
+            ALOGD("onAuthenticated(fid=%d, gid=%d)",
+                    msg->data.authenticated.finger.fid,
+                    msg->data.authenticated.finger.gid);
+            if (msg->data.authenticated.finger.fid != 0) {
+                const uint8_t* hat = reinterpret_cast<const uint8_t *>(&msg->data.authenticated.hat);
+                instance->notifyKeystore(hat, sizeof(msg->data.authenticated.hat));
+            }
+            callback->onAuthenticated(device,
+                    msg->data.authenticated.finger.fid,
+                    msg->data.authenticated.finger.gid);
+            break;
+        case FINGERPRINT_TEMPLATE_ENROLLING:
+            ALOGD("onEnrollResult(fid=%d, gid=%d, rem=%d)",
+                    msg->data.enroll.finger.fid,
+                    msg->data.enroll.finger.gid,
+                    msg->data.enroll.samples_remaining);
+            callback->onEnrollResult(device,
+                    msg->data.enroll.finger.fid,
+                    msg->data.enroll.finger.gid,
+                    msg->data.enroll.samples_remaining);
+            break;
+        case FINGERPRINT_TEMPLATE_REMOVED:
+            ALOGD("onRemove(fid=%d, gid=%d)",
+                    msg->data.removed.finger.fid,
+                    msg->data.removed.finger.gid);
+            callback->onRemoved(device,
+                    msg->data.removed.finger.fid,
+                    msg->data.removed.finger.gid);
+            break;
+        default:
+            ALOGE("invalid msg type: %d", msg->type);
+            return;
+    }
+}
+
+void FingerprintDaemonProxy::notifyKeystore(const uint8_t *auth_token, const size_t auth_token_length) {
+    if (auth_token != NULL && auth_token_length > 0) {
+        // TODO: cache service?
+        sp < IServiceManager > sm = defaultServiceManager();
+        sp < IBinder > binder = sm->getService(String16("android.security.keystore"));
+        sp < IKeystoreService > service = interface_cast < IKeystoreService > (binder);
+        if (service != NULL) {
+            status_t ret = service->addAuthToken(auth_token, auth_token_length);
+            if (ret != ResponseCode::NO_ERROR) {
+                ALOGE("Falure sending auth token to KeyStore: %d", ret);
+            }
+        } else {
+            ALOGE("Unable to communicate with KeyStore");
+        }
+    }
+}
+
+void FingerprintDaemonProxy::init(const sp<IFingerprintDaemonCallback>& callback) {
+    if (mCallback != NULL && IInterface::asBinder(callback) != IInterface::asBinder(mCallback)) {
+        IInterface::asBinder(mCallback)->unlinkToDeath(this);
+    }
+    IInterface::asBinder(callback)->linkToDeath(this);
+    mCallback = callback;
+}
+
+int32_t FingerprintDaemonProxy::enroll(const uint8_t* token, ssize_t tokenSize, int32_t groupId,
+        int32_t timeout) {
+    ALOG(LOG_VERBOSE, LOG_TAG, "enroll(gid=%d, timeout=%d)\n", groupId, timeout);
+    if (tokenSize != sizeof(hw_auth_token_t) ) {
+        ALOG(LOG_VERBOSE, LOG_TAG, "enroll() : invalid token size %zu\n", tokenSize);
+        return -1;
+    }
+    const hw_auth_token_t* authToken = reinterpret_cast<const hw_auth_token_t*>(token);
+    return mDevice->enroll(mDevice, authToken, groupId, timeout);
+}
+
+uint64_t FingerprintDaemonProxy::preEnroll() {
+    return mDevice->pre_enroll(mDevice);
+}
+
+int32_t FingerprintDaemonProxy::postEnroll() {
+    return mDevice->post_enroll(mDevice);
+}
+
+int32_t FingerprintDaemonProxy::stopEnrollment() {
+    ALOG(LOG_VERBOSE, LOG_TAG, "stopEnrollment()\n");
+    return mDevice->cancel(mDevice);
+}
+
+int32_t FingerprintDaemonProxy::authenticate(uint64_t sessionId, uint32_t groupId) {
+    ALOG(LOG_VERBOSE, LOG_TAG, "authenticate(sid=%" PRId64 ", gid=%d)\n", sessionId, groupId);
+    return mDevice->authenticate(mDevice, sessionId, groupId);
+}
+
+int32_t FingerprintDaemonProxy::stopAuthentication() {
+    ALOG(LOG_VERBOSE, LOG_TAG, "stopAuthentication()\n");
+    return mDevice->cancel(mDevice);
+}
+
+int32_t FingerprintDaemonProxy::remove(int32_t fingerId, int32_t groupId) {
+    ALOG(LOG_VERBOSE, LOG_TAG, "remove(fid=%d, gid=%d)\n", fingerId, groupId);
+    return mDevice->remove(mDevice, groupId, fingerId);
+}
+
+uint64_t FingerprintDaemonProxy::getAuthenticatorId() {
+    return mDevice->get_authenticator_id(mDevice);
+}
+
+int32_t FingerprintDaemonProxy::setActiveGroup(int32_t groupId, const uint8_t* path,
+        ssize_t pathlen) {
+    if (pathlen >= PATH_MAX || pathlen <= 0) {
+        ALOGE("Bad path length: %zd", pathlen);
+        return -1;
+    }
+    // Convert to null-terminated string
+    char path_name[PATH_MAX];
+    memcpy(path_name, path, pathlen);
+    path_name[pathlen] = '\0';
+    ALOG(LOG_VERBOSE, LOG_TAG, "setActiveGroup(%d, %s, %zu)", groupId, path_name, pathlen);
+    return mDevice->set_active_group(mDevice, groupId, path_name);
+}
+
+int64_t FingerprintDaemonProxy::openHal() {
+    ALOG(LOG_VERBOSE, LOG_TAG, "nativeOpenHal()\n");
+    int err;
+    const hw_module_t *hw_module = NULL;
+    if (0 != (err = hw_get_module(FINGERPRINT_HARDWARE_MODULE_ID, &hw_module))) {
+        ALOGE("Can't open fingerprint HW Module, error: %d", err);
+        return 0;
+    }
+    if (NULL == hw_module) {
+        ALOGE("No valid fingerprint module");
+        return 0;
+    }
+
+    mModule = reinterpret_cast<const fingerprint_module_t*>(hw_module);
+
+    if (mModule->common.methods->open == NULL) {
+        ALOGE("No valid open method");
+        return 0;
+    }
+
+    hw_device_t *device = NULL;
+
+    if (0 != (err = mModule->common.methods->open(hw_module, NULL, &device))) {
+        ALOGE("Can't open fingerprint methods, error: %d", err);
+        return 0;
+    }
+
+    if (kVersion != device->version) {
+        ALOGE("Wrong fp version. Expected %d, got %d", kVersion, device->version);
+        // return 0; // FIXME
+    }
+
+    mDevice = reinterpret_cast<fingerprint_device_t*>(device);
+    err = mDevice->set_notify(mDevice, hal_notify_callback);
+    if (err < 0) {
+        ALOGE("Failed in call to set_notify(), err=%d", err);
+        return 0;
+    }
+
+    // Sanity check - remove
+    if (mDevice->notify != hal_notify_callback) {
+        ALOGE("NOTIFY not set properly: %p != %p", mDevice->notify, hal_notify_callback);
+    }
+
+    ALOG(LOG_VERBOSE, LOG_TAG, "fingerprint HAL successfully initialized");
+    return reinterpret_cast<int64_t>(mDevice); // This is just a handle
+}
+
+int32_t FingerprintDaemonProxy::closeHal() {
+    ALOG(LOG_VERBOSE, LOG_TAG, "nativeCloseHal()\n");
+    if (mDevice == NULL) {
+        ALOGE("No valid device");
+        return -ENOSYS;
+    }
+    int err;
+    if (0 != (err = mDevice->common.close(reinterpret_cast<hw_device_t*>(mDevice)))) {
+        ALOGE("Can't close fingerprint module, error: %d", err);
+        return err;
+    }
+    mDevice = NULL;
+    return 0;
+}
+
+void FingerprintDaemonProxy::binderDied(const wp<IBinder>& who) {
+    ALOGD("binder died");
+    int err;
+    if (0 != (err = closeHal())) {
+        ALOGE("Can't close fingerprint device, error: %d", err);
+    }
+    if (IInterface::asBinder(mCallback) == who) {
+        mCallback = NULL;
+    }
+}
+
+}
diff --git a/fingerprintd/FingerprintDaemonProxy.h b/fingerprintd/FingerprintDaemonProxy.h
new file mode 100644
index 0000000..871c0e6
--- /dev/null
+++ b/fingerprintd/FingerprintDaemonProxy.h
@@ -0,0 +1,63 @@
+/*
+ * 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 FINGERPRINT_DAEMON_PROXY_H_
+#define FINGERPRINT_DAEMON_PROXY_H_
+
+#include "IFingerprintDaemon.h"
+#include "IFingerprintDaemonCallback.h"
+
+namespace android {
+
+class FingerprintDaemonProxy : public BnFingerprintDaemon {
+    public:
+        static FingerprintDaemonProxy* getInstance() {
+            if (sInstance == NULL) {
+                sInstance = new FingerprintDaemonProxy();
+            }
+            return sInstance;
+        }
+
+        // These reflect binder methods.
+        virtual void init(const sp<IFingerprintDaemonCallback>& callback);
+        virtual int32_t enroll(const uint8_t* token, ssize_t tokenLength, int32_t groupId, int32_t timeout);
+        virtual uint64_t preEnroll();
+        virtual int32_t postEnroll();
+        virtual int32_t stopEnrollment();
+        virtual int32_t authenticate(uint64_t sessionId, uint32_t groupId);
+        virtual int32_t stopAuthentication();
+        virtual int32_t remove(int32_t fingerId, int32_t groupId);
+        virtual uint64_t getAuthenticatorId();
+        virtual int32_t setActiveGroup(int32_t groupId, const uint8_t* path, ssize_t pathLen);
+        virtual int64_t openHal();
+        virtual int32_t closeHal();
+
+    private:
+        FingerprintDaemonProxy();
+        virtual ~FingerprintDaemonProxy();
+        void binderDied(const wp<IBinder>& who);
+        void notifyKeystore(const uint8_t *auth_token, const size_t auth_token_length);
+        static void hal_notify_callback(const fingerprint_msg_t *msg);
+
+        static FingerprintDaemonProxy* sInstance;
+        fingerprint_module_t const* mModule;
+        fingerprint_device_t* mDevice;
+        sp<IFingerprintDaemonCallback> mCallback;
+};
+
+} // namespace android
+
+#endif // FINGERPRINT_DAEMON_PROXY_H_
diff --git a/fingerprintd/IFingerprintDaemon.cpp b/fingerprintd/IFingerprintDaemon.cpp
new file mode 100644
index 0000000..7131793
--- /dev/null
+++ b/fingerprintd/IFingerprintDaemon.cpp
@@ -0,0 +1,195 @@
+/*
+ * 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 <inttypes.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/PermissionCache.h>
+#include <utils/String16.h>
+#include <utils/Looper.h>
+#include <keystore/IKeystoreService.h>
+#include <keystore/keystore.h> // for error code
+#include <hardware/hardware.h>
+#include <hardware/fingerprint.h>
+#include <hardware/hw_auth_token.h>
+#include "IFingerprintDaemon.h"
+#include "IFingerprintDaemonCallback.h"
+
+namespace android {
+
+static const String16 USE_FINGERPRINT_PERMISSION("android.permission.USE_FINGERPRINT");
+static const String16 MANAGE_FINGERPRINT_PERMISSION("android.permission.MANAGE_FINGERPRINT");
+static const String16 HAL_FINGERPRINT_PERMISSION("android.permission.MANAGE_FINGERPRINT"); // TODO
+static const String16 DUMP_PERMISSION("android.permission.DUMP");
+
+const android::String16
+IFingerprintDaemon::descriptor("android.hardware.fingerprint.IFingerprintDaemon");
+
+const android::String16&
+IFingerprintDaemon::getInterfaceDescriptor() const {
+    return IFingerprintDaemon::descriptor;
+}
+
+status_t BnFingerprintDaemon::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+        uint32_t flags) {
+    switch(code) {
+        case AUTHENTICATE: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            const uint64_t sessionId = data.readInt64();
+            const uint32_t groupId = data.readInt32();
+            const int32_t ret = authenticate(sessionId, groupId);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        };
+        case CANCEL_AUTHENTICATION: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            const int32_t ret = stopAuthentication();
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        }
+        case ENROLL: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            const ssize_t tokenSize = data.readInt32();
+            const uint8_t* token = static_cast<const uint8_t *>(data.readInplace(tokenSize));
+            const int32_t groupId = data.readInt32();
+            const int32_t timeout = data.readInt32();
+            const int32_t ret = enroll(token, tokenSize, groupId, timeout);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        }
+        case CANCEL_ENROLLMENT: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            const int32_t ret = stopEnrollment();
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        }
+        case PRE_ENROLL: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            const uint64_t ret = preEnroll();
+            reply->writeNoException();
+            reply->writeInt64(ret);
+            return NO_ERROR;
+        }
+        case POST_ENROLL: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            const int32_t ret = postEnroll();
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        }
+        case REMOVE: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            const int32_t fingerId = data.readInt32();
+            const int32_t groupId = data.readInt32();
+            const int32_t ret = remove(fingerId, groupId);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        }
+        case GET_AUTHENTICATOR_ID: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            const uint64_t ret = getAuthenticatorId();
+            reply->writeNoException();
+            reply->writeInt64(ret);
+            return NO_ERROR;
+        }
+        case SET_ACTIVE_GROUP: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            const int32_t group = data.readInt32();
+            const ssize_t pathSize = data.readInt32();
+            const uint8_t* path = static_cast<const uint8_t *>(data.readInplace(pathSize));
+            const int32_t ret = setActiveGroup(group, path, pathSize);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        }
+        case OPEN_HAL: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            const int64_t ret = openHal();
+            reply->writeNoException();
+            reply->writeInt64(ret);
+            return NO_ERROR;
+        }
+        case CLOSE_HAL: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            const int32_t ret = closeHal();
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        }
+        case INIT: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            sp<IFingerprintDaemonCallback> callback =
+                    interface_cast<IFingerprintDaemonCallback>(data.readStrongBinder());
+            init(callback);
+            reply->writeNoException();
+            return NO_ERROR;
+        }
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+};
+
+bool BnFingerprintDaemon::checkPermission(const String16& permission) {
+    const IPCThreadState* ipc = IPCThreadState::self();
+    const int calling_pid = ipc->getCallingPid();
+    const int calling_uid = ipc->getCallingUid();
+    return PermissionCache::checkPermission(permission, calling_pid, calling_uid);
+}
+
+
+}; // namespace android
diff --git a/fingerprintd/IFingerprintDaemon.h b/fingerprintd/IFingerprintDaemon.h
new file mode 100644
index 0000000..1eb4ac1
--- /dev/null
+++ b/fingerprintd/IFingerprintDaemon.h
@@ -0,0 +1,86 @@
+/*
+ * 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 IFINGERPRINT_DAEMON_H_
+#define IFINGERPRINT_DAEMON_H_
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+class IFingerprintDaemonCallback;
+
+/*
+* Abstract base class for native implementation of FingerprintService.
+*
+* Note: This must be kept manually in sync with IFingerprintDaemon.aidl
+*/
+class IFingerprintDaemon : public IInterface, public IBinder::DeathRecipient {
+    public:
+        enum {
+           AUTHENTICATE = IBinder::FIRST_CALL_TRANSACTION + 0,
+           CANCEL_AUTHENTICATION = IBinder::FIRST_CALL_TRANSACTION + 1,
+           ENROLL = IBinder::FIRST_CALL_TRANSACTION + 2,
+           CANCEL_ENROLLMENT = IBinder::FIRST_CALL_TRANSACTION + 3,
+           PRE_ENROLL = IBinder::FIRST_CALL_TRANSACTION + 4,
+           REMOVE = IBinder::FIRST_CALL_TRANSACTION + 5,
+           GET_AUTHENTICATOR_ID = IBinder::FIRST_CALL_TRANSACTION + 6,
+           SET_ACTIVE_GROUP = IBinder::FIRST_CALL_TRANSACTION + 7,
+           OPEN_HAL = IBinder::FIRST_CALL_TRANSACTION + 8,
+           CLOSE_HAL = IBinder::FIRST_CALL_TRANSACTION + 9,
+           INIT = IBinder::FIRST_CALL_TRANSACTION + 10,
+           POST_ENROLL = IBinder::FIRST_CALL_TRANSACTION + 11,
+        };
+
+        IFingerprintDaemon() { }
+        virtual ~IFingerprintDaemon() { }
+        virtual const android::String16& getInterfaceDescriptor() const;
+
+        // Binder interface methods
+        virtual void init(const sp<IFingerprintDaemonCallback>& callback) = 0;
+        virtual int32_t enroll(const uint8_t* token, ssize_t tokenLength, int32_t groupId,
+                int32_t timeout) = 0;
+        virtual uint64_t preEnroll() = 0;
+        virtual int32_t postEnroll() = 0;
+        virtual int32_t stopEnrollment() = 0;
+        virtual int32_t authenticate(uint64_t sessionId, uint32_t groupId) = 0;
+        virtual int32_t stopAuthentication() = 0;
+        virtual int32_t remove(int32_t fingerId, int32_t groupId) = 0;
+        virtual uint64_t getAuthenticatorId() = 0;
+        virtual int32_t setActiveGroup(int32_t groupId, const uint8_t* path, ssize_t pathLen) = 0;
+        virtual int64_t openHal() = 0;
+        virtual int32_t closeHal() = 0;
+
+        // DECLARE_META_INTERFACE - C++ client interface not needed
+        static const android::String16 descriptor;
+        static void hal_notify_callback(const fingerprint_msg_t *msg);
+};
+
+// ----------------------------------------------------------------------------
+
+class BnFingerprintDaemon: public BnInterface<IFingerprintDaemon> {
+    public:
+       virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+               uint32_t flags = 0);
+    private:
+       bool checkPermission(const String16& permission);
+};
+
+} // namespace android
+
+#endif // IFINGERPRINT_DAEMON_H_
+
diff --git a/fingerprintd/IFingerprintDaemonCallback.cpp b/fingerprintd/IFingerprintDaemonCallback.cpp
new file mode 100644
index 0000000..44d8020
--- /dev/null
+++ b/fingerprintd/IFingerprintDaemonCallback.cpp
@@ -0,0 +1,91 @@
+/*
+ * 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 "IFingerprintDaemonCallback"
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+#include <binder/Parcel.h>
+
+#include "IFingerprintDaemonCallback.h"
+
+namespace android {
+
+class BpFingerprintDaemonCallback : public BpInterface<IFingerprintDaemonCallback>
+{
+public:
+    BpFingerprintDaemonCallback(const sp<IBinder>& impl) :
+            BpInterface<IFingerprintDaemonCallback>(impl) {
+    }
+    virtual status_t onEnrollResult(int64_t devId, int32_t fpId, int32_t gpId, int32_t rem) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor());
+        data.writeInt64(devId);
+        data.writeInt32(fpId);
+        data.writeInt32(gpId);
+        data.writeInt32(rem);
+        return remote()->transact(ON_ENROLL_RESULT, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual status_t onAcquired(int64_t devId, int32_t acquiredInfo) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor());
+        data.writeInt64(devId);
+        data.writeInt32(acquiredInfo);
+        return remote()->transact(ON_ACQUIRED, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual status_t onAuthenticated(int64_t devId, int32_t fpId, int32_t gpId) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor());
+        data.writeInt64(devId);
+        data.writeInt32(fpId);
+        data.writeInt32(gpId);
+        return remote()->transact(ON_AUTHENTICATED, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual status_t onError(int64_t devId, int32_t error) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor());
+        data.writeInt64(devId);
+        data.writeInt32(error);
+        return remote()->transact(ON_ERROR, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual status_t onRemoved(int64_t devId, int32_t fpId, int32_t gpId) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor());
+        data.writeInt64(devId);
+        data.writeInt32(fpId);
+        data.writeInt32(gpId);
+        return remote()->transact(ON_REMOVED, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual status_t onEnumerate(int64_t devId, const int32_t* fpIds, const int32_t* gpIds,
+            int32_t sz) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor());
+        data.writeInt64(devId);
+        data.writeInt32Array(sz, fpIds);
+        data.writeInt32Array(sz, gpIds);
+        return remote()->transact(ON_ENUMERATE, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(FingerprintDaemonCallback,
+        "android.hardware.fingerprint.IFingerprintDaemonCallback");
+
+}; // namespace android
diff --git a/fingerprintd/IFingerprintDaemonCallback.h b/fingerprintd/IFingerprintDaemonCallback.h
new file mode 100644
index 0000000..6e32213
--- /dev/null
+++ b/fingerprintd/IFingerprintDaemonCallback.h
@@ -0,0 +1,55 @@
+/*
+ * 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 IFINGERPRINT_DAEMON_CALLBACK_H_
+#define IFINGERPRINT_DAEMON_CALLBACK_H_
+
+#include <inttypes.h>
+#include <utils/Errors.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+/*
+* Communication channel back to FingerprintService.java
+*/
+class IFingerprintDaemonCallback : public IInterface {
+    public:
+        // must be kept in sync with IFingerprintService.aidl
+        enum {
+            ON_ENROLL_RESULT = IBinder::FIRST_CALL_TRANSACTION + 0,
+            ON_ACQUIRED = IBinder::FIRST_CALL_TRANSACTION + 1,
+            ON_AUTHENTICATED = IBinder::FIRST_CALL_TRANSACTION + 2,
+            ON_ERROR = IBinder::FIRST_CALL_TRANSACTION + 3,
+            ON_REMOVED = IBinder::FIRST_CALL_TRANSACTION + 4,
+            ON_ENUMERATE = IBinder::FIRST_CALL_TRANSACTION + 5,
+        };
+
+        virtual status_t onEnrollResult(int64_t devId, int32_t fpId, int32_t gpId, int32_t rem) = 0;
+        virtual status_t onAcquired(int64_t devId, int32_t acquiredInfo) = 0;
+        virtual status_t onAuthenticated(int64_t devId, int32_t fingerId, int32_t groupId) = 0;
+        virtual status_t onError(int64_t devId, int32_t error) = 0;
+        virtual status_t onRemoved(int64_t devId, int32_t fingerId, int32_t groupId) = 0;
+        virtual status_t onEnumerate(int64_t devId, const int32_t* fpIds, const int32_t* gpIds,
+                int32_t sz) = 0;
+
+        DECLARE_META_INTERFACE(FingerprintDaemonCallback);
+};
+
+}; // namespace android
+
+#endif // IFINGERPRINT_DAEMON_CALLBACK_H_
diff --git a/fingerprintd/fingerprintd.cpp b/fingerprintd/fingerprintd.cpp
new file mode 100644
index 0000000..8fa7ed1
--- /dev/null
+++ b/fingerprintd/fingerprintd.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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 "fingerprintd"
+
+#include <cutils/log.h>
+#include <utils/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 "FingerprintDaemonProxy.h"
+
+int main() {
+    ALOGI("Starting " LOG_TAG);
+    android::sp<android::IServiceManager> serviceManager = android::defaultServiceManager();
+    android::sp<android::FingerprintDaemonProxy> proxy =
+            android::FingerprintDaemonProxy::getInstance();
+    android::status_t ret = serviceManager->addService(
+            android::FingerprintDaemonProxy::descriptor, proxy);
+    if (ret != android::OK) {
+        ALOGE("Couldn't register " LOG_TAG " binder service!");
+        return -1;
+    }
+
+    /*
+     * We're the only thread in existence, so we're just going to process
+     * Binder transaction as a single-threaded program.
+     */
+    android::IPCThreadState::self()->joinThreadPool();
+    ALOGI("Done");
+    return 0;
+}
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 0ec6c4b..8ed5cc9 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -12,8 +12,8 @@
     external/openssl/include
 
 LOCAL_MODULE:= libfs_mgr
-LOCAL_STATIC_LIBRARIES := liblogwrap libmincrypt libext4_utils_static
-LOCAL_C_INCLUDES += system/extras/ext4_utils
+LOCAL_STATIC_LIBRARIES := liblogwrap libmincrypt libext4_utils_static libsquashfs_utils
+LOCAL_C_INCLUDES += system/extras/ext4_utils system/extras/squashfs_utils
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_CFLAGS := -Werror
 
@@ -38,8 +38,9 @@
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)/sbin
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
 
-LOCAL_STATIC_LIBRARIES := libfs_mgr liblogwrap libcutils liblog libc libmincrypt libext4_utils_static
+LOCAL_STATIC_LIBRARIES := libfs_mgr liblogwrap libcutils liblog libc libmincrypt libext4_utils_static libsquashfs_utils
 LOCAL_STATIC_LIBRARIES += libsparse_static libz libselinux
+LOCAL_CXX_STL := libc++_static
 
 LOCAL_CFLAGS := -Werror
 
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 8533ff6..15d44ef 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -28,6 +28,10 @@
 #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 <linux/loop.h>
 #include <private/android_filesystem_config.h>
@@ -116,10 +120,23 @@
          * filesytsem due to an error, e2fsck is still run to do a full check
          * fix the filesystem.
          */
+        errno = 0;
         ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts);
-        INFO("%s(): mount(%s,%s,%s)=%d\n", __func__, blk_device, target, fs_type, ret);
+        INFO("%s(): mount(%s,%s,%s)=%d: %s\n",
+             __func__, blk_device, target, fs_type, ret, strerror(errno));
         if (!ret) {
-            umount(target);
+            int i;
+            for (i = 0; i < 5; i++) {
+                // Try to umount 5 times before continuing on.
+                // Should we try rebooting if all attempts fail?
+                int result = umount(target);
+                if (result == 0) {
+                    INFO("%s(): unmount(%s) succeeded\n", __func__, target);
+                    break;
+                }
+                ERROR("%s(): umount(%s)=%d: %s\n", __func__, target, result, strerror(errno));
+                sleep(1);
+            }
         }
 
         /*
@@ -176,19 +193,22 @@
  * Mark the given block device as read-only, using the BLKROSET ioctl.
  * Return 0 on success, and -1 on error.
  */
-static void fs_set_blk_ro(const char *blockdev)
+int fs_mgr_set_blk_ro(const char *blockdev)
 {
     int fd;
+    int rc = -1;
     int ON = 1;
 
-    fd = open(blockdev, O_RDONLY);
+    fd = TEMP_FAILURE_RETRY(open(blockdev, O_RDONLY | O_CLOEXEC));
     if (fd < 0) {
         // should never happen
-        return;
+        return rc;
     }
 
-    ioctl(fd, BLKROSET, &ON);
+    rc = ioctl(fd, BLKROSET, &ON);
     close(fd);
+
+    return rc;
 }
 
 /*
@@ -214,7 +234,7 @@
     save_errno = errno;
     INFO("%s(source=%s,target=%s,type=%s)=%d\n", __func__, source, target, rec->fs_type, ret);
     if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
-        fs_set_blk_ro(source);
+        fs_mgr_set_blk_ro(source);
     }
     errno = save_errno;
     return ret;
@@ -338,6 +358,140 @@
     return 0;
 }
 
+static int translate_ext_labels(struct fstab_rec *rec)
+{
+    DIR *blockdir = NULL;
+    struct dirent *ent;
+    char *label;
+    size_t label_len;
+    int ret = -1;
+
+    if (strncmp(rec->blk_device, "LABEL=", 6))
+        return 0;
+
+    label = rec->blk_device + 6;
+    label_len = strlen(label);
+
+    if (label_len > 16) {
+        ERROR("FS label is longer than allowed by filesystem\n");
+        goto out;
+    }
+
+
+    blockdir = opendir("/dev/block");
+    if (!blockdir) {
+        ERROR("couldn't open /dev/block\n");
+        goto out;
+    }
+
+    while ((ent = readdir(blockdir))) {
+        int fd;
+        char super_buf[1024];
+        struct ext4_super_block *sb;
+
+        if (ent->d_type != DT_BLK)
+            continue;
+
+        fd = openat(dirfd(blockdir), ent->d_name, O_RDONLY);
+        if (fd < 0) {
+            ERROR("Cannot open block device /dev/block/%s\n", ent->d_name);
+            goto out;
+        }
+
+        if (TEMP_FAILURE_RETRY(lseek(fd, 1024, SEEK_SET)) < 0 ||
+            TEMP_FAILURE_RETRY(read(fd, super_buf, 1024)) != 1024) {
+            /* Probably a loopback device or something else without a readable
+             * superblock.
+             */
+            close(fd);
+            continue;
+        }
+
+        sb = (struct ext4_super_block *)super_buf;
+        if (sb->s_magic != EXT4_SUPER_MAGIC) {
+            INFO("/dev/block/%s not ext{234}\n", ent->d_name);
+            continue;
+        }
+
+        if (!strncmp(label, sb->s_volume_name, label_len)) {
+            char *new_blk_device;
+
+            if (asprintf(&new_blk_device, "/dev/block/%s", ent->d_name) < 0) {
+                ERROR("Could not allocate block device string\n");
+                goto out;
+            }
+
+            INFO("resolved label %s to %s\n", rec->blk_device, new_blk_device);
+
+            free(rec->blk_device);
+            rec->blk_device = new_blk_device;
+            ret = 0;
+            break;
+        }
+    }
+
+out:
+    closedir(blockdir);
+    return ret;
+}
+
+// Check to see if a mountable volume has encryption requirements
+static int handle_encryptable(struct fstab *fstab, const struct fstab_rec* rec)
+{
+    /* If this is block encryptable, need to trigger encryption */
+    if (   (rec->fs_mgr_flags & MF_FORCECRYPT)
+        || (device_is_force_encrypted() && fs_mgr_is_encryptable(rec))) {
+        if (umount(rec->mount_point) == 0) {
+            return FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION;
+        } else {
+            WARNING("Could not umount %s (%s) - allow continue unencrypted\n",
+                    rec->mount_point, strerror(errno));
+            return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
+        }
+    }
+
+    // Deal with file level encryption
+    if (rec->fs_mgr_flags & MF_FILEENCRYPTION) {
+        // Default or not yet initialized encryption requires no more work here
+        if (!e4crypt_non_default_key(rec->mount_point)) {
+            INFO("%s is default file encrypted\n", rec->mount_point);
+            return FS_MGR_MNTALL_DEV_DEFAULT_FILE_ENCRYPTED;
+        }
+
+        INFO("%s is non-default file encrypted\n", rec->mount_point);
+
+        // Uses non-default key, so must unmount and set up temp file system
+        if (umount(rec->mount_point)) {
+            ERROR("Failed to umount %s - rebooting\n", rec->mount_point);
+            return FS_MGR_MNTALL_FAIL;
+        }
+
+        if (fs_mgr_do_tmpfs_mount(rec->mount_point) != 0) {
+            ERROR("Failed to mount a tmpfs at %s\n", rec->mount_point);
+            return FS_MGR_MNTALL_FAIL;
+        }
+
+        // Mount data temporarily so we can access unencrypted dir
+        char tmp_mnt[PATH_MAX];
+        strlcpy(tmp_mnt, rec->mount_point, sizeof(tmp_mnt));
+        strlcat(tmp_mnt, "/tmp_mnt", sizeof(tmp_mnt));
+        if (mkdir(tmp_mnt, 0700)) {
+            ERROR("Failed to create temp mount point\n");
+            return FS_MGR_MNTALL_FAIL;
+        }
+
+        if (fs_mgr_do_mount(fstab, rec->mount_point,
+                            rec->blk_device, tmp_mnt)) {
+            ERROR("Error temp mounting encrypted file system\n");
+            return FS_MGR_MNTALL_FAIL;
+        }
+
+        return FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED;
+    }
+
+    return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
+}
+
 /* When multiple fstab records share the same mount_point, it will
  * try to mount each one in turn, and ignore any duplicates after a
  * first successful mount.
@@ -369,6 +523,17 @@
             continue;
         }
 
+        /* Translate LABEL= file system labels into block devices */
+        if (!strcmp(fstab->recs[i].fs_type, "ext2") ||
+            !strcmp(fstab->recs[i].fs_type, "ext3") ||
+            !strcmp(fstab->recs[i].fs_type, "ext4")) {
+            int tret = translate_ext_labels(&fstab->recs[i]);
+            if (tret < 0) {
+                ERROR("Could not translate label to block device\n");
+                continue;
+            }
+        }
+
         if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
             wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
         }
@@ -391,25 +556,21 @@
 
         /* Deal with encryptability. */
         if (!mret) {
-            /* If this is encryptable, need to trigger encryption */
-            if (   (fstab->recs[attempted_idx].fs_mgr_flags & MF_FORCECRYPT)
-                || (device_is_force_encrypted()
-                    && fs_mgr_is_encryptable(&fstab->recs[attempted_idx]))) {
-                if (umount(fstab->recs[attempted_idx].mount_point) == 0) {
-                    if (encryptable == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
-                        ERROR("Will try to encrypt %s %s\n", fstab->recs[attempted_idx].mount_point,
-                              fstab->recs[attempted_idx].fs_type);
-                        encryptable = FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION;
-                    } else {
-                        ERROR("Only one encryptable/encrypted partition supported\n");
-                        encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
-                    }
-                } else {
-                    INFO("Could not umount %s - allow continue unencrypted\n",
-                         fstab->recs[attempted_idx].mount_point);
-                    continue;
-                }
+            int status = handle_encryptable(fstab, &fstab->recs[attempted_idx]);
+
+            if (status == FS_MGR_MNTALL_FAIL) {
+                /* Fatal error - no point continuing */
+                return status;
             }
+
+            if (status != FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
+                if (encryptable != FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
+                    // Log and continue
+                    ERROR("Only one encryptable/encrypted partition supported\n");
+                }
+                encryptable = status;
+            }
+
             /* Success!  Go get the next one */
             continue;
         }
diff --git a/fs_mgr/fs_mgr_format.c b/fs_mgr/fs_mgr_format.c
index b5b92b5..c73045d 100644
--- a/fs_mgr/fs_mgr_format.c
+++ b/fs_mgr/fs_mgr_format.c
@@ -52,7 +52,7 @@
     info.len = ((off64_t)nr_sec * 512);
 
     /* Use make_ext4fs_internal to avoid wiping an already-wiped partition. */
-    rc = make_ext4fs_internal(fd, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
+    rc = make_ext4fs_internal(fd, NULL, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
     if (rc) {
         ERROR("make_ext4fs returned %d.\n", rc);
     }
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index c2da28a..f24af1f 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -26,6 +26,7 @@
 
 struct fs_mgr_flag_values {
     char *key_loc;
+    char *verity_loc;
     long long part_length;
     char *label;
     int partnum;
@@ -62,6 +63,7 @@
     { "check",       MF_CHECK },
     { "encryptable=",MF_CRYPT },
     { "forceencrypt=",MF_FORCECRYPT },
+    { "fileencryption",MF_FILEENCRYPTION },
     { "nonremovable",MF_NONREMOVABLE },
     { "voldmanaged=",MF_VOLDMANAGED},
     { "length=",     MF_LENGTH },
@@ -70,6 +72,7 @@
     { "zramsize=",   MF_ZRAMSIZE },
     { "verify",      MF_VERIFY },
     { "noemulatedsd", MF_NOEMULATEDSD },
+    { "notrim",       MF_NOTRIM },
     { "formattable", MF_FORMATTABLE },
     { "defaults",    0 },
     { 0,             0 },
@@ -123,6 +126,14 @@
                      * location of the keys.  Get it and return it.
                      */
                     flag_vals->key_loc = strdup(strchr(p, '=') + 1);
+                } else if ((fl[i].flag == MF_VERIFY) && flag_vals) {
+                    /* If the verify flag is followed by an = and the
+                     * location for the verity state,  get it and return it.
+                     */
+                    char *start = strchr(p, '=');
+                    if (start) {
+                        flag_vals->verity_loc = strdup(start + 1);
+                    }
                 } else if ((fl[i].flag == MF_FORCECRYPT) && flag_vals) {
                     /* The forceencrypt flag is followed by an = and the
                      * location of the keys.  Get it and return it.
@@ -312,6 +323,7 @@
         fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
                                                     &flag_vals, NULL, 0);
         fstab->recs[cnt].key_loc = flag_vals.key_loc;
+        fstab->recs[cnt].verity_loc = flag_vals.verity_loc;
         fstab->recs[cnt].length = flag_vals.part_length;
         fstab->recs[cnt].label = flag_vals.label;
         fstab->recs[cnt].partnum = flag_vals.partnum;
@@ -429,31 +441,41 @@
     return fs_mgr_get_entry_for_mount_point_after(NULL, fstab, path);
 }
 
-int fs_mgr_is_voldmanaged(struct fstab_rec *fstab)
+int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab)
 {
     return fstab->fs_mgr_flags & MF_VOLDMANAGED;
 }
 
-int fs_mgr_is_nonremovable(struct fstab_rec *fstab)
+int fs_mgr_is_nonremovable(const struct fstab_rec *fstab)
 {
     return fstab->fs_mgr_flags & MF_NONREMOVABLE;
 }
 
-int fs_mgr_is_verified(struct fstab_rec *fstab)
+int fs_mgr_is_verified(const struct fstab_rec *fstab)
 {
     return fstab->fs_mgr_flags & MF_VERIFY;
 }
 
-int fs_mgr_is_encryptable(struct fstab_rec *fstab)
+int fs_mgr_is_encryptable(const struct fstab_rec *fstab)
 {
     return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT);
 }
 
-int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab)
+int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_FILEENCRYPTION;
+}
+
+int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab)
 {
     return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
 }
 
+int fs_mgr_is_notrim(struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_NOTRIM;
+}
+
 int fs_mgr_is_formattable(struct fstab_rec *fstab)
 {
     return fstab->fs_mgr_flags & (MF_FORMATTABLE);
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index fd58306..682fd11 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -21,6 +21,7 @@
 #include <fs_mgr.h>
 
 #define INFO(x...)    KLOG_INFO("fs_mgr", x)
+#define WARNING(x...) KLOG_WARNING("fs_mgr", x)
 #define ERROR(x...)   KLOG_ERROR("fs_mgr", x)
 
 #define CRYPTO_TMPFS_OPTIONS "size=256m,mode=0771,uid=1000,gid=1000"
@@ -75,9 +76,12 @@
 #define MF_FORCECRYPT   0x400
 #define MF_NOEMULATEDSD 0x800 /* no emulated sdcard daemon, sd card is the only
                                  external storage */
-#define MF_FORMATTABLE  0x1000
+#define MF_NOTRIM       0x1000
+#define MF_FILEENCRYPTION 0x2000
+#define MF_FORMATTABLE  0x4000
 
 #define DM_BUF_SIZE 4096
 
-#endif /* __CORE_FS_MGR_PRIV_H */
+int fs_mgr_set_blk_ro(const char *blockdev);
 
+#endif /* __CORE_FS_MGR_PRIV_H */
diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c
index a82db4e..2d1abbe 100644
--- a/fs_mgr/fs_mgr_verity.c
+++ b/fs_mgr/fs_mgr_verity.c
@@ -38,13 +38,38 @@
 #include "mincrypt/sha256.h"
 
 #include "ext4_sb.h"
+#include "squashfs_utils.h"
 
 #include "fs_mgr_priv.h"
 #include "fs_mgr_priv_verity.h"
 
+#define FSTAB_PREFIX "/fstab."
+
 #define VERITY_METADATA_SIZE 32768
 #define VERITY_TABLE_RSA_KEY "/verity_key"
 
+#define METADATA_MAGIC 0x01564c54
+#define METADATA_TAG_MAX_LENGTH 63
+#define METADATA_EOD "eod"
+
+#define VERITY_LASTSIG_TAG "verity_lastsig"
+
+#define VERITY_STATE_TAG "verity_state"
+#define VERITY_STATE_HEADER 0x83c0ae9d
+#define VERITY_STATE_VERSION 1
+
+#define VERITY_KMSG_RESTART "dm-verity device corrupted"
+#define VERITY_KMSG_BUFSIZE 1024
+
+#define __STRINGIFY(x) #x
+#define STRINGIFY(x) __STRINGIFY(x)
+
+struct verity_state {
+    uint32_t header;
+    uint32_t version;
+    int32_t mode;
+};
+
 extern struct fs_info info;
 
 static RSAPublicKey *load_key(char *path)
@@ -116,11 +141,25 @@
     return retval;
 }
 
-static int get_target_device_size(char *blk_device, uint64_t *device_size)
+static int squashfs_get_target_device_size(char *blk_device, uint64_t *device_size)
+{
+    struct squashfs_info sq_info;
+
+    if (squashfs_parse_sb(blk_device, &sq_info) >= 0) {
+        *device_size = sq_info.bytes_used_4K_padded;
+        return 0;
+    } else {
+        return -1;
+    }
+}
+
+static int ext4_get_target_device_size(char *blk_device, uint64_t *device_size)
 {
     int data_device;
     struct ext4_super_block sb;
-    struct fs_info info = {0};
+    struct fs_info info;
+
+    info.len = 0;  /* Only len is set to 0 to ask the device for real size. */
 
     data_device = TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC));
     if (data_device == -1) {
@@ -130,33 +169,55 @@
 
     if (TEMP_FAILURE_RETRY(lseek64(data_device, 1024, SEEK_SET)) < 0) {
         ERROR("Error seeking to superblock");
-        TEMP_FAILURE_RETRY(close(data_device));
+        close(data_device);
         return -1;
     }
 
     if (TEMP_FAILURE_RETRY(read(data_device, &sb, sizeof(sb))) != sizeof(sb)) {
         ERROR("Error reading superblock");
-        TEMP_FAILURE_RETRY(close(data_device));
+        close(data_device);
         return -1;
     }
 
     ext4_parse_sb(&sb, &info);
     *device_size = info.len;
 
-    TEMP_FAILURE_RETRY(close(data_device));
+    close(data_device);
     return 0;
 }
 
-static int read_verity_metadata(char *block_device, char **signature, char **table)
+static int get_fs_size(char *fs_type, char *blk_device, uint64_t *device_size) {
+    if (!strcmp(fs_type, "ext4")) {
+        if (ext4_get_target_device_size(blk_device, device_size) < 0) {
+            ERROR("Failed to get ext4 fs size on %s.", blk_device);
+            return -1;
+        }
+    } else if (!strcmp(fs_type, "squashfs")) {
+        if (squashfs_get_target_device_size(blk_device, device_size) < 0) {
+            ERROR("Failed to get squashfs fs size on %s.", blk_device);
+            return -1;
+        }
+    } else {
+        ERROR("%s: Unsupported filesystem for verity.", fs_type);
+        return -1;
+    }
+    return 0;
+}
+
+static int read_verity_metadata(uint64_t device_size, char *block_device, char **signature,
+        char **table)
 {
     unsigned magic_number;
     unsigned table_length;
-    uint64_t device_length;
     int protocol_version;
     int device;
     int retval = FS_MGR_SETUP_VERITY_FAIL;
-    *signature = 0;
-    *table = 0;
+
+    *signature = NULL;
+
+    if (table) {
+        *table = NULL;
+    }
 
     device = TEMP_FAILURE_RETRY(open(block_device, O_RDONLY | O_CLOEXEC));
     if (device == -1) {
@@ -164,12 +225,7 @@
         goto out;
     }
 
-    // find the start of the verity metadata
-    if (get_target_device_size(block_device, &device_length) < 0) {
-        ERROR("Could not get target device size.\n");
-        goto out;
-    }
-    if (TEMP_FAILURE_RETRY(lseek64(device, device_length, SEEK_SET)) < 0) {
+    if (TEMP_FAILURE_RETRY(lseek64(device, device_size, SEEK_SET)) < 0) {
         ERROR("Could not seek to start of verity metadata block.\n");
         goto out;
     }
@@ -190,8 +246,7 @@
 #endif
 
     if (magic_number != VERITY_METADATA_MAGIC_NUMBER) {
-        ERROR("Couldn't find verity metadata at offset %"PRIu64"!\n",
-              device_length);
+        ERROR("Couldn't find verity metadata at offset %"PRIu64"!\n", device_size);
         goto out;
     }
 
@@ -217,6 +272,11 @@
         goto out;
     }
 
+    if (!table) {
+        retval = FS_MGR_SETUP_VERITY_SUCCESS;
+        goto out;
+    }
+
     // get the size of the table
     if (TEMP_FAILURE_RETRY(read(device, &table_length, sizeof(table_length))) !=
             sizeof(table_length)) {
@@ -241,13 +301,16 @@
 
 out:
     if (device != -1)
-        TEMP_FAILURE_RETRY(close(device));
+        close(device);
 
     if (retval != FS_MGR_SETUP_VERITY_SUCCESS) {
-        free(*table);
         free(*signature);
-        *table = 0;
-        *signature = 0;
+        *signature = NULL;
+
+        if (table) {
+            free(*table);
+            *table = NULL;
+        }
     }
 
     return retval;
@@ -292,15 +355,12 @@
     return 0;
 }
 
-static int load_verity_table(struct dm_ioctl *io, char *name, char *blockdev, int fd, char *table)
+static int load_verity_table(struct dm_ioctl *io, char *name, uint64_t device_size, int fd, char *table,
+        int mode)
 {
     char *verity_params;
     char *buffer = (char*) io;
-    uint64_t device_size = 0;
-
-    if (get_target_device_size(blockdev, &device_size) < 0) {
-        return -1;
-    }
+    size_t bufsize;
 
     verity_ioctl_init(io, name, DM_STATUS_TABLE_FLAG);
 
@@ -315,7 +375,15 @@
 
     // build the verity params here
     verity_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
-    if (sprintf(verity_params, "%s", table) < 0) {
+    bufsize = DM_BUF_SIZE - (verity_params - buffer);
+
+    if (mode == VERITY_MODE_EIO) {
+        // allow operation with older dm-verity drivers that are unaware
+        // of the mode parameter by omitting it; this also means that we
+        // cannot use logging mode with these drivers, they always cause
+        // an I/O error for corrupted blocks
+        strcpy(verity_params, table);
+    } else if (snprintf(verity_params, bufsize, "%s %d", table, mode) < 0) {
         return -1;
     }
 
@@ -354,36 +422,538 @@
     return -1;
 }
 
-static int set_verified_property(char *name) {
-    int ret;
-    char *key;
-    ret = asprintf(&key, "partition.%s.verified", name);
-    if (ret < 0) {
-        ERROR("Error formatting verified property");
-        return ret;
+static int check_verity_restart(const char *fname)
+{
+    char buffer[VERITY_KMSG_BUFSIZE + 1];
+    int fd;
+    int rc = 0;
+    ssize_t size;
+    struct stat s;
+
+    fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
+
+    if (fd == -1) {
+        if (errno != ENOENT) {
+            ERROR("Failed to open %s (%s)\n", fname, strerror(errno));
+        }
+        goto out;
     }
-    ret = PROP_NAME_MAX - strlen(key);
-    if (ret < 0) {
-        ERROR("Verified property name is too long");
+
+    if (fstat(fd, &s) == -1) {
+        ERROR("Failed to fstat %s (%s)\n", fname, strerror(errno));
+        goto out;
+    }
+
+    size = VERITY_KMSG_BUFSIZE;
+
+    if (size > s.st_size) {
+        size = s.st_size;
+    }
+
+    if (lseek(fd, s.st_size - size, SEEK_SET) == -1) {
+        ERROR("Failed to lseek %jd %s (%s)\n", (intmax_t)(s.st_size - size), fname,
+            strerror(errno));
+        goto out;
+    }
+
+    if (TEMP_FAILURE_RETRY(read(fd, buffer, size)) != size) {
+        ERROR("Failed to read %zd bytes from %s (%s)\n", size, fname,
+            strerror(errno));
+        goto out;
+    }
+
+    buffer[size] = '\0';
+
+    if (strstr(buffer, VERITY_KMSG_RESTART) != NULL) {
+        rc = 1;
+    }
+
+out:
+    if (fd != -1) {
+        close(fd);
+    }
+
+    return rc;
+}
+
+static int was_verity_restart()
+{
+    static const char *files[] = {
+        "/sys/fs/pstore/console-ramoops",
+        "/proc/last_kmsg",
+        NULL
+    };
+    int i;
+
+    for (i = 0; files[i]; ++i) {
+        if (check_verity_restart(files[i])) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static int metadata_add(FILE *fp, long start, const char *tag,
+        unsigned int length, off64_t *offset)
+{
+    if (fseek(fp, start, SEEK_SET) < 0 ||
+        fprintf(fp, "%s %u\n", tag, length) < 0) {
         return -1;
     }
-    ret = property_set(key, "1");
-    if (ret < 0)
-        ERROR("Error setting verified property %s: %d", key, ret);
-    free(key);
-    return ret;
+
+    *offset = ftell(fp);
+
+    if (fseek(fp, length, SEEK_CUR) < 0 ||
+        fprintf(fp, METADATA_EOD " 0\n") < 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static int metadata_find(const char *fname, const char *stag,
+        unsigned int slength, off64_t *offset)
+{
+    FILE *fp = NULL;
+    char tag[METADATA_TAG_MAX_LENGTH + 1];
+    int rc = -1;
+    int n;
+    long start = 0x4000; /* skip cryptfs metadata area */
+    uint32_t magic;
+    unsigned int length = 0;
+
+    if (!fname) {
+        return -1;
+    }
+
+    fp = fopen(fname, "r+");
+
+    if (!fp) {
+        ERROR("Failed to open %s (%s)\n", fname, strerror(errno));
+        goto out;
+    }
+
+    /* check magic */
+    if (fseek(fp, start, SEEK_SET) < 0 ||
+        fread(&magic, sizeof(magic), 1, fp) != 1) {
+        ERROR("Failed to read magic from %s (%s)\n", fname, strerror(errno));
+        goto out;
+    }
+
+    if (magic != METADATA_MAGIC) {
+        magic = METADATA_MAGIC;
+
+        if (fseek(fp, start, SEEK_SET) < 0 ||
+            fwrite(&magic, sizeof(magic), 1, fp) != 1) {
+            ERROR("Failed to write magic to %s (%s)\n", fname, strerror(errno));
+            goto out;
+        }
+
+        rc = metadata_add(fp, start + sizeof(magic), stag, slength, offset);
+        if (rc < 0) {
+            ERROR("Failed to add metadata to %s: %s\n", fname, strerror(errno));
+        }
+
+        goto out;
+    }
+
+    start += sizeof(magic);
+
+    while (1) {
+        n = fscanf(fp, "%" STRINGIFY(METADATA_TAG_MAX_LENGTH) "s %u\n",
+                tag, &length);
+
+        if (n == 2 && strcmp(tag, METADATA_EOD)) {
+            /* found a tag */
+            start = ftell(fp);
+
+            if (!strcmp(tag, stag) && length == slength) {
+                *offset = start;
+                rc = 0;
+                goto out;
+            }
+
+            start += length;
+
+            if (fseek(fp, length, SEEK_CUR) < 0) {
+                ERROR("Failed to seek %s (%s)\n", fname, strerror(errno));
+                goto out;
+            }
+        } else {
+            rc = metadata_add(fp, start, stag, slength, offset);
+            if (rc < 0) {
+                ERROR("Failed to write metadata to %s: %s\n", fname,
+                    strerror(errno));
+            }
+            goto out;
+        }
+   }
+
+out:
+    if (fp) {
+        fflush(fp);
+        fclose(fp);
+    }
+
+    return rc;
+}
+
+static int write_verity_state(const char *fname, off64_t offset, int32_t mode)
+{
+    int fd;
+    int rc = -1;
+    struct verity_state s = { VERITY_STATE_HEADER, VERITY_STATE_VERSION, mode };
+
+    fd = TEMP_FAILURE_RETRY(open(fname, O_WRONLY | O_SYNC | O_CLOEXEC));
+
+    if (fd == -1) {
+        ERROR("Failed to open %s (%s)\n", fname, strerror(errno));
+        goto out;
+    }
+
+    if (TEMP_FAILURE_RETRY(pwrite64(fd, &s, sizeof(s), offset)) != sizeof(s)) {
+        ERROR("Failed to write %zu bytes to %s to offset %" PRIu64 " (%s)\n",
+            sizeof(s), fname, offset, strerror(errno));
+        goto out;
+    }
+
+    rc = 0;
+
+out:
+    if (fd != -1) {
+        close(fd);
+    }
+
+    return rc;
+}
+
+static int read_verity_state(const char *fname, off64_t offset, int *mode)
+{
+    int fd = -1;
+    int rc = -1;
+    struct verity_state s;
+
+    fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
+
+    if (fd == -1) {
+        ERROR("Failed to open %s (%s)\n", fname, strerror(errno));
+        goto out;
+    }
+
+    if (TEMP_FAILURE_RETRY(pread64(fd, &s, sizeof(s), offset)) != sizeof(s)) {
+        ERROR("Failed to read %zu bytes from %s offset %" PRIu64 " (%s)\n",
+            sizeof(s), fname, offset, strerror(errno));
+        goto out;
+    }
+
+    if (s.header != VERITY_STATE_HEADER) {
+        /* space allocated, but no state written. write default state */
+        *mode = VERITY_MODE_DEFAULT;
+        rc = write_verity_state(fname, offset, *mode);
+        goto out;
+    }
+
+    if (s.version != VERITY_STATE_VERSION) {
+        ERROR("Unsupported verity state version (%u)\n", s.version);
+        goto out;
+    }
+
+    if (s.mode < VERITY_MODE_EIO ||
+        s.mode > VERITY_MODE_LAST) {
+        ERROR("Unsupported verity mode (%u)\n", s.mode);
+        goto out;
+    }
+
+    *mode = s.mode;
+    rc = 0;
+
+out:
+    if (fd != -1) {
+        close(fd);
+    }
+
+    return rc;
+}
+
+static int compare_last_signature(struct fstab_rec *fstab, int *match)
+{
+    char tag[METADATA_TAG_MAX_LENGTH + 1];
+    char *signature = NULL;
+    int fd = -1;
+    int rc = -1;
+    uint8_t curr[SHA256_DIGEST_SIZE];
+    uint8_t prev[SHA256_DIGEST_SIZE];
+    off64_t offset = 0;
+    uint64_t device_size;
+
+    *match = 1;
+
+    // get verity filesystem size
+    if (get_fs_size(fstab->fs_type, fstab->blk_device, &device_size) < 0) {
+        ERROR("Failed to get filesystem size\n");
+        goto out;
+    }
+
+    if (read_verity_metadata(device_size, fstab->blk_device, &signature, NULL) < 0) {
+        ERROR("Failed to read verity signature from %s\n", fstab->mount_point);
+        goto out;
+    }
+
+    SHA256_hash(signature, RSANUMBYTES, curr);
+
+    if (snprintf(tag, sizeof(tag), VERITY_LASTSIG_TAG "_%s",
+            basename(fstab->mount_point)) >= (int)sizeof(tag)) {
+        ERROR("Metadata tag name too long for %s\n", fstab->mount_point);
+        goto out;
+    }
+
+    if (metadata_find(fstab->verity_loc, tag, SHA256_DIGEST_SIZE,
+            &offset) < 0) {
+        goto out;
+    }
+
+    fd = TEMP_FAILURE_RETRY(open(fstab->verity_loc, O_RDWR | O_SYNC | O_CLOEXEC));
+
+    if (fd == -1) {
+        ERROR("Failed to open %s: %s\n", fstab->verity_loc, strerror(errno));
+        goto out;
+    }
+
+    if (TEMP_FAILURE_RETRY(pread64(fd, prev, sizeof(prev),
+            offset)) != sizeof(prev)) {
+        ERROR("Failed to read %zu bytes from %s offset %" PRIu64 " (%s)\n",
+            sizeof(prev), fstab->verity_loc, offset, strerror(errno));
+        goto out;
+    }
+
+    *match = !memcmp(curr, prev, SHA256_DIGEST_SIZE);
+
+    if (!*match) {
+        /* update current signature hash */
+        if (TEMP_FAILURE_RETRY(pwrite64(fd, curr, sizeof(curr),
+                offset)) != sizeof(curr)) {
+            ERROR("Failed to write %zu bytes to %s offset %" PRIu64 " (%s)\n",
+                sizeof(curr), fstab->verity_loc, offset, strerror(errno));
+            goto out;
+        }
+    }
+
+    rc = 0;
+
+out:
+    free(signature);
+
+    if (fd != -1) {
+        close(fd);
+    }
+
+    return rc;
+}
+
+static int get_verity_state_offset(struct fstab_rec *fstab, off64_t *offset)
+{
+    char tag[METADATA_TAG_MAX_LENGTH + 1];
+
+    if (snprintf(tag, sizeof(tag), VERITY_STATE_TAG "_%s",
+            basename(fstab->mount_point)) >= (int)sizeof(tag)) {
+        ERROR("Metadata tag name too long for %s\n", fstab->mount_point);
+        return -1;
+    }
+
+    return metadata_find(fstab->verity_loc, tag, sizeof(struct verity_state),
+                offset);
+}
+
+static int load_verity_state(struct fstab_rec *fstab, int *mode)
+{
+    char propbuf[PROPERTY_VALUE_MAX];
+    int match = 0;
+    off64_t offset = 0;
+
+    /* use the kernel parameter if set */
+    property_get("ro.boot.veritymode", propbuf, "");
+
+    if (*propbuf != '\0') {
+        if (!strcmp(propbuf, "enforcing")) {
+            *mode = VERITY_MODE_DEFAULT;
+            return 0;
+        } else if (!strcmp(propbuf, "logging")) {
+            *mode = VERITY_MODE_LOGGING;
+            return 0;
+        } else {
+            INFO("Unknown value %s for veritymode; ignoring", propbuf);
+        }
+    }
+
+    if (get_verity_state_offset(fstab, &offset) < 0) {
+        /* fall back to stateless behavior */
+        *mode = VERITY_MODE_EIO;
+        return 0;
+    }
+
+    if (was_verity_restart()) {
+        /* device was restarted after dm-verity detected a corrupted
+         * block, so switch to logging mode */
+        *mode = VERITY_MODE_LOGGING;
+        return write_verity_state(fstab->verity_loc, offset, *mode);
+    }
+
+    if (!compare_last_signature(fstab, &match) && !match) {
+        /* partition has been reflashed, reset dm-verity state */
+        *mode = VERITY_MODE_DEFAULT;
+        return write_verity_state(fstab->verity_loc, offset, *mode);
+    }
+
+    return read_verity_state(fstab->verity_loc, offset, mode);
+}
+
+int fs_mgr_load_verity_state(int *mode)
+{
+    char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
+    char propbuf[PROPERTY_VALUE_MAX];
+    int rc = -1;
+    int i;
+    int current;
+    struct fstab *fstab = NULL;
+
+    /* return the default mode, unless any of the verified partitions are in
+     * logging mode, in which case return that */
+    *mode = VERITY_MODE_DEFAULT;
+
+    property_get("ro.hardware", propbuf, "");
+    snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
+
+    fstab = fs_mgr_read_fstab(fstab_filename);
+
+    if (!fstab) {
+        ERROR("Failed to read %s\n", fstab_filename);
+        goto out;
+    }
+
+    for (i = 0; i < fstab->num_entries; i++) {
+        if (!fs_mgr_is_verified(&fstab->recs[i])) {
+            continue;
+        }
+
+        rc = load_verity_state(&fstab->recs[i], &current);
+        if (rc < 0) {
+            continue;
+        }
+
+        if (current == VERITY_MODE_LOGGING) {
+            *mode = current;
+        }
+    }
+
+    rc = 0;
+
+out:
+    if (fstab) {
+        fs_mgr_free_fstab(fstab);
+    }
+
+    return rc;
+}
+
+int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback)
+{
+    _Alignas(struct dm_ioctl) char buffer[DM_BUF_SIZE];
+    char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
+    char *mount_point;
+    char propbuf[PROPERTY_VALUE_MAX];
+    char *status;
+    int fd = -1;
+    int i;
+    int mode;
+    int rc = -1;
+    off64_t offset = 0;
+    struct dm_ioctl *io = (struct dm_ioctl *) buffer;
+    struct fstab *fstab = NULL;
+
+    /* check if we need to store the state */
+    property_get("ro.boot.veritymode", propbuf, "");
+
+    if (*propbuf != '\0') {
+        return 0; /* state is kept by the bootloader */
+    }
+
+    fd = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));
+
+    if (fd == -1) {
+        ERROR("Error opening device mapper (%s)\n", strerror(errno));
+        goto out;
+    }
+
+    property_get("ro.hardware", propbuf, "");
+    snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
+
+    fstab = fs_mgr_read_fstab(fstab_filename);
+
+    if (!fstab) {
+        ERROR("Failed to read %s\n", fstab_filename);
+        goto out;
+    }
+
+    for (i = 0; i < fstab->num_entries; i++) {
+        if (!fs_mgr_is_verified(&fstab->recs[i])) {
+            continue;
+        }
+
+        if (get_verity_state_offset(&fstab->recs[i], &offset) < 0 ||
+            read_verity_state(fstab->recs[i].verity_loc, offset, &mode) < 0) {
+            continue;
+        }
+
+        mount_point = basename(fstab->recs[i].mount_point);
+        verity_ioctl_init(io, mount_point, 0);
+
+        if (ioctl(fd, DM_TABLE_STATUS, io)) {
+            ERROR("Failed to query DM_TABLE_STATUS for %s (%s)\n", mount_point,
+                strerror(errno));
+            continue;
+        }
+
+        status = &buffer[io->data_start + sizeof(struct dm_target_spec)];
+
+        if (*status == 'C') {
+            if (write_verity_state(fstab->recs[i].verity_loc, offset,
+                    VERITY_MODE_LOGGING) < 0) {
+                continue;
+            }
+        }
+
+        if (callback) {
+            callback(&fstab->recs[i], mount_point, mode, *status);
+        }
+    }
+
+    rc = 0;
+
+out:
+    if (fstab) {
+        fs_mgr_free_fstab(fstab);
+    }
+
+    if (fd) {
+        close(fd);
+    }
+
+    return rc;
 }
 
 int fs_mgr_setup_verity(struct fstab_rec *fstab) {
 
     int retval = FS_MGR_SETUP_VERITY_FAIL;
     int fd = -1;
+    int mode;
 
     char *verity_blk_name = 0;
     char *verity_table = 0;
     char *verity_table_signature = 0;
+    uint64_t device_size = 0;
 
-    char buffer[DM_BUF_SIZE];
+    _Alignas(struct dm_ioctl) char buffer[DM_BUF_SIZE];
     struct dm_ioctl *io = (struct dm_ioctl *) buffer;
     char *mount_point = basename(fstab->mount_point);
 
@@ -391,16 +961,15 @@
     io->flags |= 1;
     io->target_count = 1;
 
-    // check to ensure that the verity device is ext4
-    // TODO: support non-ext4 filesystems
-    if (strcmp(fstab->fs_type, "ext4")) {
-        ERROR("Cannot verify non-ext4 device (%s)", fstab->fs_type);
+    // get verity filesystem size
+    if (get_fs_size(fstab->fs_type, fstab->blk_device, &device_size) < 0) {
         return retval;
     }
 
     // read the verity block at the end of the block device
     // send error code up the chain so we can detect attempts to disable verity
-    retval = read_verity_metadata(fstab->blk_device,
+    retval = read_verity_metadata(device_size,
+                                  fstab->blk_device,
                                   &verity_table_signature,
                                   &verity_table);
     if (retval < 0) {
@@ -434,8 +1003,19 @@
         goto out;
     }
 
+    if (load_verity_state(fstab, &mode) < 0) {
+        /* if accessing or updating the state failed, switch to the default
+         * safe mode. This makes sure the device won't end up in an endless
+         * restart loop, and no corrupted data will be exposed to userspace
+         * without a warning. */
+        mode = VERITY_MODE_EIO;
+    }
+
+    INFO("Enabling dm-verity for %s (mode %d)\n",  mount_point, mode);
+
     // load the verity mapping table
-    if (load_verity_table(io, mount_point, fstab->blk_device, fd, verity_table) < 0) {
+    if (load_verity_table(io, mount_point, device_size, fd, verity_table,
+            mode) < 0) {
         goto out;
     }
 
@@ -444,6 +1024,9 @@
         goto out;
     }
 
+    // mark the underlying block device as read-only
+    fs_mgr_set_blk_ro(fstab->blk_device);
+
     // assign the new verity block device as the block device
     free(fstab->blk_device);
     fstab->blk_device = verity_blk_name;
@@ -454,8 +1037,7 @@
         goto out;
     }
 
-    // set the property indicating that the partition is verified
-    retval = set_verified_property(mount_point);
+    retval = FS_MGR_SETUP_VERITY_SUCCESS;
 
 out:
     if (fd != -1) {
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 5a6ad2d..27fccf7 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -31,6 +31,15 @@
 extern "C" {
 #endif
 
+// Verity modes
+enum verity_mode {
+    VERITY_MODE_EIO = 0,
+    VERITY_MODE_LOGGING = 1,
+    VERITY_MODE_RESTART = 2,
+    VERITY_MODE_LAST = VERITY_MODE_RESTART,
+    VERITY_MODE_DEFAULT = VERITY_MODE_RESTART
+};
+
 /*
  * The entries must be kept in the same order as they were seen in the fstab.
  * Unless explicitly requested, a lookup on mount point should always
@@ -58,13 +67,20 @@
     unsigned int zram_size;
 };
 
+// Callback function for verity status
+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(const char *fstab_path);
 void fs_mgr_free_fstab(struct fstab *fstab);
 
+#define FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED 5
+#define FS_MGR_MNTALL_DEV_DEFAULT_FILE_ENCRYPTED 4
 #define FS_MGR_MNTALL_DEV_NEEDS_RECOVERY 3
 #define FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION 2
 #define FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED 1
 #define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 0
+#define FS_MGR_MNTALL_FAIL -1
 int fs_mgr_mount_all(struct fstab *fstab);
 
 #define FS_MGR_DOMNT_FAILED -1
@@ -75,15 +91,19 @@
 int fs_mgr_unmount_all(struct fstab *fstab);
 int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc,
                           char *real_blk_device, int size);
+int fs_mgr_load_verity_state(int *mode);
+int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback);
 int fs_mgr_add_entry(struct fstab *fstab,
                      const char *mount_point, const char *fs_type,
                      const char *blk_device);
 struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path);
-int fs_mgr_is_voldmanaged(struct fstab_rec *fstab);
-int fs_mgr_is_nonremovable(struct fstab_rec *fstab);
-int fs_mgr_is_verified(struct fstab_rec *fstab);
-int fs_mgr_is_encryptable(struct fstab_rec *fstab);
-int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab);
+int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab);
+int fs_mgr_is_nonremovable(const struct fstab_rec *fstab);
+int fs_mgr_is_verified(const struct fstab_rec *fstab);
+int fs_mgr_is_encryptable(const struct fstab_rec *fstab);
+int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab);
+int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
+int fs_mgr_is_notrim(struct fstab_rec *fstab);
 int fs_mgr_is_formattable(struct fstab_rec *fstab);
 int fs_mgr_swapon_all(struct fstab *fstab);
 
@@ -94,4 +114,3 @@
 #endif
 
 #endif /* __CORE_FS_MGR_H */
-
diff --git a/gatekeeperd/Android.mk b/gatekeeperd/Android.mk
new file mode 100644
index 0000000..55b2d5e
--- /dev/null
+++ b/gatekeeperd/Android.mk
@@ -0,0 +1,41 @@
+#
+# 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)
+
+include $(CLEAR_VARS)
+LOCAL_CFLAGS := -Wall -Wextra -Werror -Wunused
+LOCAL_SRC_FILES := \
+	SoftGateKeeperDevice.cpp \
+	IGateKeeperService.cpp \
+	gatekeeperd.cpp \
+	IUserManager.cpp
+
+LOCAL_MODULE := gatekeeperd
+LOCAL_SHARED_LIBRARIES := \
+	libbinder \
+	libgatekeeper \
+	liblog \
+	libhardware \
+	libbase \
+	libutils \
+	libcrypto \
+	libkeystore_binder
+LOCAL_STATIC_LIBRARIES := libscrypt_static
+LOCAL_C_INCLUDES := external/scrypt/lib/crypto
+include $(BUILD_EXECUTABLE)
+
+include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/gatekeeperd/IGateKeeperService.cpp b/gatekeeperd/IGateKeeperService.cpp
new file mode 100644
index 0000000..95fbfd1
--- /dev/null
+++ b/gatekeeperd/IGateKeeperService.cpp
@@ -0,0 +1,167 @@
+/*
+ * 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.
+*/
+
+#define LOG_TAG "GateKeeperService"
+#include <utils/Log.h>
+
+#include "IGateKeeperService.h"
+
+namespace android {
+
+const android::String16 IGateKeeperService::descriptor("android.service.gatekeeper.IGateKeeperService");
+const android::String16& IGateKeeperService::getInterfaceDescriptor() const {
+    return IGateKeeperService::descriptor;
+}
+
+status_t BnGateKeeperService::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+    switch(code) {
+        case ENROLL: {
+            CHECK_INTERFACE(IGateKeeperService, data, reply);
+            uint32_t uid = data.readInt32();
+
+            ssize_t currentPasswordHandleSize = data.readInt32();
+            const uint8_t *currentPasswordHandle =
+                    static_cast<const uint8_t *>(data.readInplace(currentPasswordHandleSize));
+            if (!currentPasswordHandle) currentPasswordHandleSize = 0;
+
+            ssize_t currentPasswordSize = data.readInt32();
+            const uint8_t *currentPassword =
+                    static_cast<const uint8_t *>(data.readInplace(currentPasswordSize));
+            if (!currentPassword) currentPasswordSize = 0;
+
+            ssize_t desiredPasswordSize = data.readInt32();
+            const uint8_t *desiredPassword =
+                    static_cast<const uint8_t *>(data.readInplace(desiredPasswordSize));
+            if (!desiredPassword) desiredPasswordSize = 0;
+
+            uint8_t *out = NULL;
+            uint32_t outSize = 0;
+            int ret = enroll(uid, currentPasswordHandle, currentPasswordHandleSize,
+                    currentPassword, currentPasswordSize, desiredPassword,
+                    desiredPasswordSize, &out, &outSize);
+
+            reply->writeNoException();
+            reply->writeInt32(1);
+            if (ret == 0 && outSize > 0 && out != NULL) {
+                reply->writeInt32(GATEKEEPER_RESPONSE_OK);
+                reply->writeInt32(0);
+                reply->writeInt32(outSize);
+                reply->writeInt32(outSize);
+                void *buf = reply->writeInplace(outSize);
+                memcpy(buf, out, outSize);
+                delete[] out;
+            } else if (ret > 0) {
+                reply->writeInt32(GATEKEEPER_RESPONSE_RETRY);
+                reply->writeInt32(ret);
+            } else {
+                reply->writeInt32(GATEKEEPER_RESPONSE_ERROR);
+            }
+            return NO_ERROR;
+        }
+        case VERIFY: {
+            CHECK_INTERFACE(IGateKeeperService, data, reply);
+            uint32_t uid = data.readInt32();
+            ssize_t currentPasswordHandleSize = data.readInt32();
+            const uint8_t *currentPasswordHandle =
+                    static_cast<const uint8_t *>(data.readInplace(currentPasswordHandleSize));
+            if (!currentPasswordHandle) currentPasswordHandleSize = 0;
+
+            ssize_t currentPasswordSize = data.readInt32();
+            const uint8_t *currentPassword =
+                static_cast<const uint8_t *>(data.readInplace(currentPasswordSize));
+            if (!currentPassword) currentPasswordSize = 0;
+
+            bool request_reenroll = false;
+            int ret = verify(uid, (uint8_t *) currentPasswordHandle,
+                    currentPasswordHandleSize, (uint8_t *) currentPassword, currentPasswordSize,
+                    &request_reenroll);
+
+            reply->writeNoException();
+            reply->writeInt32(1);
+            if (ret == 0) {
+                reply->writeInt32(GATEKEEPER_RESPONSE_OK);
+                reply->writeInt32(request_reenroll ? 1 : 0);
+                reply->writeInt32(0); // no payload returned from this call
+            } else if (ret > 0) {
+                reply->writeInt32(GATEKEEPER_RESPONSE_RETRY);
+                reply->writeInt32(ret);
+            } else {
+                reply->writeInt32(GATEKEEPER_RESPONSE_ERROR);
+            }
+            return NO_ERROR;
+        }
+        case VERIFY_CHALLENGE: {
+            CHECK_INTERFACE(IGateKeeperService, data, reply);
+            uint32_t uid = data.readInt32();
+            uint64_t challenge = data.readInt64();
+            ssize_t currentPasswordHandleSize = data.readInt32();
+            const uint8_t *currentPasswordHandle =
+                    static_cast<const uint8_t *>(data.readInplace(currentPasswordHandleSize));
+            if (!currentPasswordHandle) currentPasswordHandleSize = 0;
+
+            ssize_t currentPasswordSize = data.readInt32();
+            const uint8_t *currentPassword =
+                static_cast<const uint8_t *>(data.readInplace(currentPasswordSize));
+            if (!currentPassword) currentPasswordSize = 0;
+
+
+            uint8_t *out = NULL;
+            uint32_t outSize = 0;
+            bool request_reenroll = false;
+            int ret = verifyChallenge(uid, challenge, (uint8_t *) currentPasswordHandle,
+                    currentPasswordHandleSize, (uint8_t *) currentPassword, currentPasswordSize,
+                    &out, &outSize, &request_reenroll);
+            reply->writeNoException();
+            reply->writeInt32(1);
+            if (ret == 0 && outSize > 0 && out != NULL) {
+                reply->writeInt32(GATEKEEPER_RESPONSE_OK);
+                reply->writeInt32(request_reenroll ? 1 : 0);
+                reply->writeInt32(outSize);
+                reply->writeInt32(outSize);
+                void *buf = reply->writeInplace(outSize);
+                memcpy(buf, out, outSize);
+                delete[] out;
+            } else if (ret > 0) {
+                reply->writeInt32(GATEKEEPER_RESPONSE_RETRY);
+                reply->writeInt32(ret);
+            } else {
+                reply->writeInt32(GATEKEEPER_RESPONSE_ERROR);
+            }
+            return NO_ERROR;
+        }
+        case GET_SECURE_USER_ID: {
+            CHECK_INTERFACE(IGateKeeperService, data, reply);
+            uint32_t uid = data.readInt32();
+            uint64_t sid = getSecureUserId(uid);
+            reply->writeNoException();
+            reply->writeInt64(sid);
+            return NO_ERROR;
+        }
+        case CLEAR_SECURE_USER_ID: {
+            CHECK_INTERFACE(IGateKeeperService, data, reply);
+            uint32_t uid = data.readInt32();
+            clearSecureUserId(uid);
+            reply->writeNoException();
+            return NO_ERROR;
+        }
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+};
+
+
+}; // namespace android
diff --git a/gatekeeperd/IGateKeeperService.h b/gatekeeperd/IGateKeeperService.h
new file mode 100644
index 0000000..f070486
--- /dev/null
+++ b/gatekeeperd/IGateKeeperService.h
@@ -0,0 +1,111 @@
+/*
+ * 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 IGATEKEEPER_SERVICE_H_
+#define IGATEKEEPER_SERVICE_H_
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+/*
+ * This must be kept manually in sync with frameworks/base's IGateKeeperService.aidl
+ */
+class IGateKeeperService : public IInterface {
+public:
+    enum {
+        ENROLL = IBinder::FIRST_CALL_TRANSACTION + 0,
+        VERIFY = IBinder::FIRST_CALL_TRANSACTION + 1,
+        VERIFY_CHALLENGE = IBinder::FIRST_CALL_TRANSACTION + 2,
+        GET_SECURE_USER_ID = IBinder::FIRST_CALL_TRANSACTION + 3,
+        CLEAR_SECURE_USER_ID = IBinder::FIRST_CALL_TRANSACTION + 4,
+    };
+
+    enum {
+        GATEKEEPER_RESPONSE_OK = 0,
+        GATEKEEPER_RESPONSE_RETRY = 1,
+        GATEKEEPER_RESPONSE_ERROR = -1,
+    };
+
+    // DECLARE_META_INTERFACE - C++ client interface not needed
+    static const android::String16 descriptor;
+    virtual const android::String16& getInterfaceDescriptor() const;
+    IGateKeeperService() {}
+    virtual ~IGateKeeperService() {}
+
+    /**
+     * Enrolls a password with the GateKeeper. Returns 0 on success, negative on failure.
+     * Returns:
+     * - 0 on success
+     * - A timestamp T > 0 if the call has failed due to throttling and should not
+     *   be reattempted until T milliseconds have elapsed
+     * - -1 on failure
+     */
+    virtual int enroll(uint32_t uid,
+            const uint8_t *current_password_handle, uint32_t current_password_handle_length,
+            const uint8_t *current_password, uint32_t current_password_length,
+            const uint8_t *desired_password, uint32_t desired_password_length,
+            uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length) = 0;
+
+    /**
+     * Verifies a password previously enrolled with the GateKeeper.
+     * Returns:
+     * - 0 on success
+     * - A timestamp T > 0 if the call has failed due to throttling and should not
+     *   be reattempted until T milliseconds have elapsed
+     * - -1 on failure
+     */
+    virtual int verify(uint32_t uid, const uint8_t *enrolled_password_handle,
+            uint32_t enrolled_password_handle_length,
+            const uint8_t *provided_password, uint32_t provided_password_length,
+            bool *request_reenroll) = 0;
+
+    /**
+     * Verifies a password previously enrolled with the GateKeeper.
+     * Returns:
+     * - 0 on success
+     * - A timestamp T > 0 if the call has failed due to throttling and should not
+     *   be reattempted until T milliseconds have elapsed
+     * - -1 on failure
+     */
+    virtual int verifyChallenge(uint32_t uid, uint64_t challenge,
+            const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,
+            const uint8_t *provided_password, uint32_t provided_password_length,
+            uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll) = 0;
+    /**
+     * Returns the secure user ID for the provided android user
+     */
+    virtual uint64_t getSecureUserId(uint32_t uid) = 0;
+
+    /**
+     * Clears the secure user ID associated with the user.
+     */
+    virtual void clearSecureUserId(uint32_t uid) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnGateKeeperService: public BnInterface<IGateKeeperService> {
+public:
+    virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+            uint32_t flags = 0);
+};
+
+} // namespace android
+
+#endif
+
diff --git a/gatekeeperd/IUserManager.cpp b/gatekeeperd/IUserManager.cpp
new file mode 100644
index 0000000..8645fc2
--- /dev/null
+++ b/gatekeeperd/IUserManager.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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 "IUserManager"
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+#include <binder/Parcel.h>
+
+#include "IUserManager.h"
+
+namespace android {
+
+class BpUserManager : public BpInterface<IUserManager>
+{
+public:
+    BpUserManager(const sp<IBinder>& impl) :
+            BpInterface<IUserManager>(impl) {
+    }
+    virtual int32_t getCredentialOwnerProfile(int32_t user_id) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IUserManager::getInterfaceDescriptor());
+        data.writeInt32(user_id);
+        status_t rc = remote()->transact(GET_CREDENTIAL_OWNER_PROFILE, data, &reply, 0);
+        if (rc != NO_ERROR) {
+            ALOGE("%s: failed (%d)\n", __func__, rc);
+            return -1;
+        }
+
+        int32_t exception = reply.readExceptionCode();
+        if (exception != 0) {
+            ALOGE("%s: got exception (%d)\n", __func__, exception);
+            return -1;
+        }
+
+        return reply.readInt32();
+    }
+
+};
+
+IMPLEMENT_META_INTERFACE(UserManager, "android.os.IUserManager");
+
+}; // namespace android
+
diff --git a/gatekeeperd/IUserManager.h b/gatekeeperd/IUserManager.h
new file mode 100644
index 0000000..640e9b5
--- /dev/null
+++ b/gatekeeperd/IUserManager.h
@@ -0,0 +1,46 @@
+/*
+ * 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 IUSERMANAGER_H_
+#define IUSERMANAGER_H_
+
+#include <inttypes.h>
+#include <utils/Errors.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+/*
+* Communication channel to UserManager
+*/
+class IUserManager : public IInterface {
+    public:
+        // must be kept in sync with IUserManager.aidl
+        enum {
+            GET_CREDENTIAL_OWNER_PROFILE = IBinder::FIRST_CALL_TRANSACTION + 0,
+        };
+
+        virtual int32_t getCredentialOwnerProfile(int32_t user_id) = 0;
+
+        DECLARE_META_INTERFACE(UserManager);
+};
+
+}; // namespace android
+
+#endif // IUSERMANAGER_H_
+
diff --git a/gatekeeperd/SoftGateKeeper.h b/gatekeeperd/SoftGateKeeper.h
new file mode 100644
index 0000000..75fe11d
--- /dev/null
+++ b/gatekeeperd/SoftGateKeeper.h
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SOFT_GATEKEEPER_H_
+#define SOFT_GATEKEEPER_H_
+
+extern "C" {
+#include <openssl/rand.h>
+#include <openssl/sha.h>
+
+#include <crypto_scrypt.h>
+}
+
+#include <UniquePtr.h>
+#include <gatekeeper/gatekeeper.h>
+#include <iostream>
+#include <unordered_map>
+
+namespace gatekeeper {
+
+struct fast_hash_t {
+    uint64_t salt;
+    uint8_t digest[SHA256_DIGEST_LENGTH];
+};
+
+class SoftGateKeeper : public GateKeeper {
+public:
+    static const uint32_t SIGNATURE_LENGTH_BYTES = 32;
+
+    // scrypt params
+    static const uint64_t N = 16384;
+    static const uint32_t r = 8;
+    static const uint32_t p = 1;
+
+    static const int MAX_UINT_32_CHARS = 11;
+
+    SoftGateKeeper() {
+        key_.reset(new uint8_t[SIGNATURE_LENGTH_BYTES]);
+        memset(key_.get(), 0, SIGNATURE_LENGTH_BYTES);
+    }
+
+    virtual ~SoftGateKeeper() {
+    }
+
+    virtual bool GetAuthTokenKey(const uint8_t **auth_token_key,
+            uint32_t *length) const {
+        if (auth_token_key == NULL || length == NULL) return false;
+        uint8_t *auth_token_key_copy = new uint8_t[SIGNATURE_LENGTH_BYTES];
+        memcpy(auth_token_key_copy, key_.get(), SIGNATURE_LENGTH_BYTES);
+
+        *auth_token_key = auth_token_key_copy;
+        *length = SIGNATURE_LENGTH_BYTES;
+        return true;
+    }
+
+    virtual void GetPasswordKey(const uint8_t **password_key, uint32_t *length) {
+        if (password_key == NULL || length == NULL) return;
+        uint8_t *password_key_copy = new uint8_t[SIGNATURE_LENGTH_BYTES];
+        memcpy(password_key_copy, key_.get(), SIGNATURE_LENGTH_BYTES);
+
+        *password_key = password_key_copy;
+        *length = SIGNATURE_LENGTH_BYTES;
+    }
+
+    virtual void ComputePasswordSignature(uint8_t *signature, uint32_t signature_length,
+            const uint8_t *, uint32_t, const uint8_t *password,
+            uint32_t password_length, salt_t salt) const {
+        if (signature == NULL) return;
+        crypto_scrypt(password, password_length, reinterpret_cast<uint8_t *>(&salt),
+                sizeof(salt), N, r, p, signature, signature_length);
+    }
+
+    virtual void GetRandom(void *random, uint32_t requested_length) const {
+        if (random == NULL) return;
+        RAND_pseudo_bytes((uint8_t *) random, requested_length);
+    }
+
+    virtual void ComputeSignature(uint8_t *signature, uint32_t signature_length,
+            const uint8_t *, uint32_t, const uint8_t *, const uint32_t) const {
+        if (signature == NULL) return;
+        memset(signature, 0, signature_length);
+    }
+
+    virtual uint64_t GetMillisecondsSinceBoot() const {
+        struct timespec time;
+        int res = clock_gettime(CLOCK_BOOTTIME, &time);
+        if (res < 0) return 0;
+        return (time.tv_sec * 1000) + (time.tv_nsec / 1000 / 1000);
+    }
+
+    virtual bool IsHardwareBacked() const {
+        return false;
+    }
+
+    virtual bool GetFailureRecord(uint32_t uid, secure_id_t user_id, failure_record_t *record,
+            bool /* secure */) {
+        failure_record_t *stored = &failure_map_[uid];
+        if (user_id != stored->secure_user_id) {
+            stored->secure_user_id = user_id;
+            stored->last_checked_timestamp = 0;
+            stored->failure_counter = 0;
+        }
+        memcpy(record, stored, sizeof(*record));
+        return true;
+    }
+
+    virtual bool ClearFailureRecord(uint32_t uid, secure_id_t user_id, bool /* secure */) {
+        failure_record_t *stored = &failure_map_[uid];
+        stored->secure_user_id = user_id;
+        stored->last_checked_timestamp = 0;
+        stored->failure_counter = 0;
+        return true;
+    }
+
+    virtual bool WriteFailureRecord(uint32_t uid, failure_record_t *record, bool /* secure */) {
+        failure_map_[uid] = *record;
+        return true;
+    }
+
+    fast_hash_t ComputeFastHash(const SizedBuffer &password, uint64_t salt) {
+        fast_hash_t fast_hash;
+        size_t digest_size = password.length + sizeof(salt);
+        std::unique_ptr<uint8_t[]> digest(new uint8_t[digest_size]);
+        memcpy(digest.get(), &salt, sizeof(salt));
+        memcpy(digest.get() + sizeof(salt), password.buffer.get(), password.length);
+
+        SHA256(digest.get(), digest_size, (uint8_t *) &fast_hash.digest);
+
+        fast_hash.salt = salt;
+        return fast_hash;
+    }
+
+    bool VerifyFast(const fast_hash_t &fast_hash, const SizedBuffer &password) {
+        fast_hash_t computed = ComputeFastHash(password, fast_hash.salt);
+        return memcmp(computed.digest, fast_hash.digest, SHA256_DIGEST_LENGTH) == 0;
+    }
+
+    bool DoVerify(const password_handle_t *expected_handle, const SizedBuffer &password) {
+        FastHashMap::const_iterator it = fast_hash_map_.find(expected_handle->user_id);
+        if (it != fast_hash_map_.end() && VerifyFast(it->second, password)) {
+            return true;
+        } else {
+            if (GateKeeper::DoVerify(expected_handle, password)) {
+                uint64_t salt;
+                GetRandom(&salt, sizeof(salt));
+                fast_hash_map_[expected_handle->user_id] = ComputeFastHash(password, salt);
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+private:
+
+    typedef std::unordered_map<uint32_t, failure_record_t> FailureRecordMap;
+    typedef std::unordered_map<uint64_t, fast_hash_t> FastHashMap;
+
+    UniquePtr<uint8_t[]> key_;
+    FailureRecordMap failure_map_;
+    FastHashMap fast_hash_map_;
+};
+}
+
+#endif // SOFT_GATEKEEPER_H_
+
diff --git a/gatekeeperd/SoftGateKeeperDevice.cpp b/gatekeeperd/SoftGateKeeperDevice.cpp
new file mode 100644
index 0000000..f5e2ce6
--- /dev/null
+++ b/gatekeeperd/SoftGateKeeperDevice.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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 "SoftGateKeeper.h"
+#include "SoftGateKeeperDevice.h"
+
+namespace android {
+
+int SoftGateKeeperDevice::enroll(uint32_t uid,
+            const uint8_t *current_password_handle, uint32_t current_password_handle_length,
+            const uint8_t *current_password, uint32_t current_password_length,
+            const uint8_t *desired_password, uint32_t desired_password_length,
+            uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length) {
+
+    if (enrolled_password_handle == NULL || enrolled_password_handle_length == NULL ||
+            desired_password == NULL || desired_password_length == 0)
+        return -EINVAL;
+
+    // Current password and current password handle go together
+    if (current_password_handle == NULL || current_password_handle_length == 0 ||
+            current_password == NULL || current_password_length == 0) {
+        current_password_handle = NULL;
+        current_password_handle_length = 0;
+        current_password = NULL;
+        current_password_length = 0;
+    }
+
+    SizedBuffer desired_password_buffer(desired_password_length);
+    memcpy(desired_password_buffer.buffer.get(), desired_password, desired_password_length);
+
+    SizedBuffer current_password_handle_buffer(current_password_handle_length);
+    if (current_password_handle) {
+        memcpy(current_password_handle_buffer.buffer.get(), current_password_handle,
+                current_password_handle_length);
+    }
+
+    SizedBuffer current_password_buffer(current_password_length);
+    if (current_password) {
+        memcpy(current_password_buffer.buffer.get(), current_password, current_password_length);
+    }
+
+    EnrollRequest request(uid, &current_password_handle_buffer, &desired_password_buffer,
+            &current_password_buffer);
+    EnrollResponse response;
+
+    impl_->Enroll(request, &response);
+
+    if (response.error == ERROR_RETRY) {
+        return response.retry_timeout;
+    } else if (response.error != ERROR_NONE) {
+        return -EINVAL;
+    }
+
+    *enrolled_password_handle = response.enrolled_password_handle.buffer.release();
+    *enrolled_password_handle_length = response.enrolled_password_handle.length;
+    return 0;
+}
+
+int SoftGateKeeperDevice::verify(uint32_t uid,
+        uint64_t challenge, const uint8_t *enrolled_password_handle,
+        uint32_t enrolled_password_handle_length, const uint8_t *provided_password,
+        uint32_t provided_password_length, uint8_t **auth_token, uint32_t *auth_token_length,
+        bool *request_reenroll) {
+
+    if (enrolled_password_handle == NULL ||
+            provided_password == NULL) {
+        return -EINVAL;
+    }
+
+    SizedBuffer password_handle_buffer(enrolled_password_handle_length);
+    memcpy(password_handle_buffer.buffer.get(), enrolled_password_handle,
+            enrolled_password_handle_length);
+    SizedBuffer provided_password_buffer(provided_password_length);
+    memcpy(provided_password_buffer.buffer.get(), provided_password, provided_password_length);
+
+    VerifyRequest request(uid, challenge, &password_handle_buffer, &provided_password_buffer);
+    VerifyResponse response;
+
+    impl_->Verify(request, &response);
+
+    if (response.error == ERROR_RETRY) {
+        return response.retry_timeout;
+    } else if (response.error != ERROR_NONE) {
+        return -EINVAL;
+    }
+
+    if (auth_token != NULL && auth_token_length != NULL) {
+       *auth_token = response.auth_token.buffer.release();
+       *auth_token_length = response.auth_token.length;
+    }
+
+    if (request_reenroll != NULL) {
+        *request_reenroll = response.request_reenroll;
+    }
+
+    return 0;
+}
+} // namespace android
diff --git a/gatekeeperd/SoftGateKeeperDevice.h b/gatekeeperd/SoftGateKeeperDevice.h
new file mode 100644
index 0000000..3463c29
--- /dev/null
+++ b/gatekeeperd/SoftGateKeeperDevice.h
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#ifndef SOFT_GATEKEEPER_DEVICE_H_
+#define SOFT_GATEKEEPER_DEVICE_H_
+
+#include "SoftGateKeeper.h"
+
+#include <UniquePtr.h>
+
+using namespace gatekeeper;
+
+namespace android {
+
+/**
+ * Software based GateKeeper implementation
+ */
+class SoftGateKeeperDevice {
+public:
+    SoftGateKeeperDevice() {
+        impl_.reset(new SoftGateKeeper());
+    }
+
+   // Wrappers to translate the gatekeeper HAL API to the Kegyuard Messages API.
+
+    /**
+     * Enrolls password_payload, which should be derived from a user selected pin or password,
+     * with the authentication factor private key used only for enrolling authentication
+     * factor data.
+     *
+     * Returns: 0 on success or an error code less than 0 on error.
+     * On error, enrolled_password_handle will not be allocated.
+     */
+    int enroll(uint32_t uid,
+            const uint8_t *current_password_handle, uint32_t current_password_handle_length,
+            const uint8_t *current_password, uint32_t current_password_length,
+            const uint8_t *desired_password, uint32_t desired_password_length,
+            uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length);
+
+    /**
+     * Verifies provided_password matches enrolled_password_handle.
+     *
+     * Implementations of this module may retain the result of this call
+     * to attest to the recency of authentication.
+     *
+     * On success, writes the address of a verification token to auth_token,
+     * usable to attest password verification to other trusted services. Clients
+     * may pass NULL for this value.
+     *
+     * Returns: 0 on success or an error code less than 0 on error
+     * On error, verification token will not be allocated
+     */
+    int verify(uint32_t uid, uint64_t challenge,
+            const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,
+            const uint8_t *provided_password, uint32_t provided_password_length,
+            uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll);
+private:
+    UniquePtr<SoftGateKeeper> impl_;
+};
+
+} // namespace gatekeeper
+
+#endif //SOFT_GATEKEEPER_DEVICE_H_
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
new file mode 100644
index 0000000..b4fdab0
--- /dev/null
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -0,0 +1,351 @@
+/*
+ * 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 "gatekeeperd"
+
+#include "IGateKeeperService.h"
+
+#include <errno.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <cutils/log.h>
+#include <utils/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 "SoftGateKeeperDevice.h"
+#include "IUserManager.h"
+
+namespace android {
+
+static const String16 KEYGUARD_PERMISSION("android.permission.ACCESS_KEYGUARD_SECURE_STORAGE");
+static const String16 DUMP_PERMISSION("android.permission.DUMP");
+
+class GateKeeperProxy : public BnGateKeeperService {
+public:
+    GateKeeperProxy() {
+        int ret = hw_get_module_by_class(GATEKEEPER_HARDWARE_MODULE_ID, NULL, &module);
+        device = NULL;
+
+        if (ret < 0) {
+            ALOGW("falling back to software GateKeeper");
+            soft_device.reset(new SoftGateKeeperDevice());
+        } else {
+            ret = gatekeeper_open(module, &device);
+            if (ret < 0)
+                LOG_ALWAYS_FATAL_IF(ret < 0, "Unable to open GateKeeper HAL");
+        }
+
+        if (mark_cold_boot()) {
+            ALOGI("cold boot: clearing state");
+            if (device != NULL && device->delete_all_users != NULL) {
+                device->delete_all_users(device);
+            }
+        }
+    }
+
+    virtual ~GateKeeperProxy() {
+        if (device) gatekeeper_close(device);
+    }
+
+    void store_sid(uint32_t uid, uint64_t sid) {
+        char filename[21];
+        sprintf(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));
+            return;
+        }
+        write(fd, &sid, sizeof(sid));
+        close(fd);
+    }
+
+    bool mark_cold_boot() {
+        const char *filename = ".coldboot";
+        if (access(filename, F_OK) == -1) {
+            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));
+                return false;
+            }
+            close(fd);
+            return true;
+        }
+        return false;
+    }
+
+    void maybe_store_sid(uint32_t uid, uint64_t sid) {
+        char filename[21];
+        sprintf(filename, "%u", uid);
+        if (access(filename, F_OK) == -1) {
+            store_sid(uid, sid);
+        }
+    }
+
+    uint64_t read_sid(uint32_t uid) {
+        char filename[21];
+        uint64_t sid;
+        sprintf(filename, "%u", uid);
+        int fd = open(filename, O_RDONLY);
+        if (fd < 0) return 0;
+        read(fd, &sid, sizeof(sid));
+        close(fd);
+        return sid;
+    }
+
+    void clear_sid(uint32_t uid) {
+        char filename[21];
+        sprintf(filename, "%u", uid);
+        if (remove(filename) < 0) {
+            ALOGE("%s: could not remove file [%s], attempting 0 write", __func__, strerror(errno));
+            store_sid(uid, 0);
+        }
+    }
+
+    virtual int enroll(uint32_t uid,
+            const uint8_t *current_password_handle, uint32_t current_password_handle_length,
+            const uint8_t *current_password, uint32_t current_password_length,
+            const uint8_t *desired_password, uint32_t desired_password_length,
+            uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length) {
+        IPCThreadState* ipc = IPCThreadState::self();
+        const int calling_pid = ipc->getCallingPid();
+        const int calling_uid = ipc->getCallingUid();
+        if (!PermissionCache::checkPermission(KEYGUARD_PERMISSION, calling_pid, calling_uid)) {
+            return PERMISSION_DENIED;
+        }
+
+        // need a desired password to enroll
+        if (desired_password_length == 0) return -EINVAL;
+
+        int ret;
+        if (device) {
+            const gatekeeper::password_handle_t *handle =
+                    reinterpret_cast<const gatekeeper::password_handle_t *>(current_password_handle);
+
+            if (handle != NULL && handle->version != 0 && !handle->hardware_backed) {
+                // handle is being re-enrolled from a software version. HAL probably won't accept
+                // the handle as valid, so we nullify it and enroll from scratch
+                current_password_handle = NULL;
+                current_password_handle_length = 0;
+                current_password = NULL;
+                current_password_length = 0;
+            }
+
+            ret = device->enroll(device, uid, current_password_handle, current_password_handle_length,
+                    current_password, current_password_length,
+                    desired_password, desired_password_length,
+                    enrolled_password_handle, enrolled_password_handle_length);
+        } else {
+            ret = soft_device->enroll(uid,
+                    current_password_handle, current_password_handle_length,
+                    current_password, current_password_length,
+                    desired_password, desired_password_length,
+                    enrolled_password_handle, enrolled_password_handle_length);
+        }
+
+        if (ret == 0) {
+            gatekeeper::password_handle_t *handle =
+                    reinterpret_cast<gatekeeper::password_handle_t *>(*enrolled_password_handle);
+            store_sid(uid, handle->user_id);
+            bool rr;
+
+            // immediately verify this password so we don't ask the user to enter it again
+            // if they just created it.
+            verify(uid, *enrolled_password_handle, sizeof(password_handle_t), desired_password,
+                    desired_password_length, &rr);
+        }
+
+        return ret;
+    }
+
+    virtual int verify(uint32_t uid,
+            const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,
+            const uint8_t *provided_password, uint32_t provided_password_length, bool *request_reenroll) {
+        uint8_t *auth_token;
+        uint32_t auth_token_length;
+        return verifyChallenge(uid, 0, enrolled_password_handle, enrolled_password_handle_length,
+                provided_password, provided_password_length,
+                &auth_token, &auth_token_length, request_reenroll);
+    }
+
+    virtual int verifyChallenge(uint32_t uid, uint64_t challenge,
+            const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,
+            const uint8_t *provided_password, uint32_t provided_password_length,
+            uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll) {
+        IPCThreadState* ipc = IPCThreadState::self();
+        const int calling_pid = ipc->getCallingPid();
+        const int calling_uid = ipc->getCallingUid();
+        if (!PermissionCache::checkPermission(KEYGUARD_PERMISSION, calling_pid, calling_uid)) {
+            return PERMISSION_DENIED;
+        }
+
+        // can't verify if we're missing either param
+        if ((enrolled_password_handle_length | provided_password_length) == 0)
+            return -EINVAL;
+
+        int ret;
+        if (device) {
+            const gatekeeper::password_handle_t *handle =
+                    reinterpret_cast<const gatekeeper::password_handle_t *>(enrolled_password_handle);
+            // handle version 0 does not have hardware backed flag, and thus cannot be upgraded to
+            // a HAL if there was none before
+            if (handle->version == 0 || handle->hardware_backed) {
+                ret = device->verify(device, uid, challenge,
+                    enrolled_password_handle, enrolled_password_handle_length,
+                    provided_password, provided_password_length, auth_token, auth_token_length,
+                    request_reenroll);
+            } else {
+                // upgrade scenario, a HAL has been added to this device where there was none before
+                SoftGateKeeperDevice soft_dev;
+                ret = soft_dev.verify(uid, challenge,
+                    enrolled_password_handle, enrolled_password_handle_length,
+                    provided_password, provided_password_length, auth_token, auth_token_length,
+                    request_reenroll);
+
+                if (ret == 0) {
+                    // success! re-enroll with HAL
+                    *request_reenroll = true;
+                }
+            }
+        } else {
+            ret = soft_device->verify(uid, challenge,
+                enrolled_password_handle, enrolled_password_handle_length,
+                provided_password, provided_password_length, auth_token, auth_token_length,
+                request_reenroll);
+        }
+
+        if (ret == 0 && *auth_token != NULL && *auth_token_length > 0) {
+            // TODO: cache service?
+            sp<IServiceManager> sm = defaultServiceManager();
+            sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
+            sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
+            if (service != NULL) {
+                status_t ret = service->addAuthToken(*auth_token, *auth_token_length);
+                if (ret != ResponseCode::NO_ERROR) {
+                    ALOGE("Falure sending auth token to KeyStore: %d", ret);
+                }
+            } else {
+                ALOGE("Unable to communicate with KeyStore");
+            }
+        }
+
+        if (ret == 0) {
+            maybe_store_sid(uid, reinterpret_cast<const gatekeeper::password_handle_t *>(
+                        enrolled_password_handle)->user_id);
+        }
+
+        return ret;
+    }
+
+    virtual uint64_t getSecureUserId(uint32_t uid) {
+        uint64_t sid = read_sid(uid);
+         if (sid == 0) {
+            // might be a work profile, look up the parent
+            sp<IServiceManager> sm = defaultServiceManager();
+            sp<IBinder> binder = sm->getService(String16("user"));
+            sp<IUserManager> um = interface_cast<IUserManager>(binder);
+            int32_t parent = um->getCredentialOwnerProfile(uid);
+            if (parent < 0) {
+                return 0;
+            } else if (parent != (int32_t) uid) {
+                return read_sid(parent);
+            }
+        }
+        return sid;
+
+    }
+
+    virtual void clearSecureUserId(uint32_t uid) {
+        IPCThreadState* ipc = IPCThreadState::self();
+        const int calling_pid = ipc->getCallingPid();
+        const int calling_uid = ipc->getCallingUid();
+        if (!PermissionCache::checkPermission(KEYGUARD_PERMISSION, calling_pid, calling_uid)) {
+            ALOGE("%s: permission denied for [%d:%d]", __func__, calling_pid, calling_uid);
+            return;
+        }
+        clear_sid(uid);
+
+        if (device != NULL && device->delete_user != NULL) {
+            device->delete_user(device, uid);
+        }
+    }
+
+    virtual status_t dump(int fd, const Vector<String16> &) {
+        IPCThreadState* ipc = IPCThreadState::self();
+        const int pid = ipc->getCallingPid();
+        const int uid = ipc->getCallingUid();
+        if (!PermissionCache::checkPermission(DUMP_PERMISSION, pid, uid)) {
+            return PERMISSION_DENIED;
+        }
+
+        if (device == NULL) {
+            const char *result = "Device not available";
+            write(fd, result, strlen(result) + 1);
+        } else {
+            const char *result = "OK";
+            write(fd, result, strlen(result) + 1);
+        }
+
+        return NO_ERROR;
+    }
+
+private:
+    gatekeeper_device_t *device;
+    UniquePtr<SoftGateKeeperDevice> soft_device;
+    const hw_module_t *module;
+};
+}// namespace android
+
+int main(int argc, char* argv[]) {
+    ALOGI("Starting gatekeeperd...");
+    if (argc < 2) {
+        ALOGE("A directory must be specified!");
+        return 1;
+    }
+    if (chdir(argv[1]) == -1) {
+        ALOGE("chdir: %s: %s", argv[1], strerror(errno));
+        return 1;
+    }
+
+    android::sp<android::IServiceManager> sm = android::defaultServiceManager();
+    android::sp<android::GateKeeperProxy> proxy = new android::GateKeeperProxy();
+    android::status_t ret = sm->addService(
+            android::String16("android.service.gatekeeper.IGateKeeperService"), proxy);
+    if (ret != android::OK) {
+        ALOGE("Couldn't register binder service!");
+        return -1;
+    }
+
+    /*
+     * We're the only thread in existence, so we're just going to process
+     * Binder transaction as a single-threaded program.
+     */
+    android::IPCThreadState::self()->joinThreadPool();
+    return 0;
+}
diff --git a/gatekeeperd/tests/Android.mk b/gatekeeperd/tests/Android.mk
new file mode 100644
index 0000000..6fc4ac0
--- /dev/null
+++ b/gatekeeperd/tests/Android.mk
@@ -0,0 +1,29 @@
+#
+# 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)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := gatekeeperd-unit-tests
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers
+LOCAL_SHARED_LIBRARIES := libgatekeeper libcrypto
+LOCAL_STATIC_LIBRARIES := libscrypt_static
+LOCAL_C_INCLUDES := external/scrypt/lib/crypto
+LOCAL_SRC_FILES := \
+	gatekeeper_test.cpp
+include $(BUILD_NATIVE_TEST)
+
diff --git a/gatekeeperd/tests/gatekeeper_test.cpp b/gatekeeperd/tests/gatekeeper_test.cpp
new file mode 100644
index 0000000..c504f92
--- /dev/null
+++ b/gatekeeperd/tests/gatekeeper_test.cpp
@@ -0,0 +1,206 @@
+/*
+ * 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 <arpa/inet.h>
+#include <iostream>
+
+#include <gtest/gtest.h>
+#include <UniquePtr.h>
+
+#include <hardware/hw_auth_token.h>
+
+#include "../SoftGateKeeper.h"
+
+using ::gatekeeper::SizedBuffer;
+using ::testing::Test;
+using ::gatekeeper::EnrollRequest;
+using ::gatekeeper::EnrollResponse;
+using ::gatekeeper::VerifyRequest;
+using ::gatekeeper::VerifyResponse;
+using ::gatekeeper::SoftGateKeeper;
+using ::gatekeeper::secure_id_t;
+
+static void do_enroll(SoftGateKeeper &gatekeeper, EnrollResponse *response) {
+    SizedBuffer password;
+
+    password.buffer.reset(new uint8_t[16]);
+    password.length = 16;
+    memset(password.buffer.get(), 0, 16);
+    EnrollRequest request(0, NULL, &password, NULL);
+
+    gatekeeper.Enroll(request, response);
+}
+
+TEST(GateKeeperTest, EnrollSuccess) {
+    SoftGateKeeper gatekeeper;
+    EnrollResponse response;
+    do_enroll(gatekeeper, &response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+}
+
+TEST(GateKeeperTest, EnrollBogusData) {
+    SoftGateKeeper gatekeeper;
+    SizedBuffer password;
+    EnrollResponse response;
+
+    EnrollRequest request(0, NULL, &password, NULL);
+
+    gatekeeper.Enroll(request, &response);
+
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_INVALID, response.error);
+}
+
+TEST(GateKeeperTest, VerifySuccess) {
+    SoftGateKeeper gatekeeper;
+    SizedBuffer provided_password;
+    EnrollResponse enroll_response;
+
+    provided_password.buffer.reset(new uint8_t[16]);
+    provided_password.length = 16;
+    memset(provided_password.buffer.get(), 0, 16);
+
+    do_enroll(gatekeeper, &enroll_response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error);
+    VerifyRequest request(0, 1, &enroll_response.enrolled_password_handle,
+            &provided_password);
+    VerifyResponse response;
+
+    gatekeeper.Verify(request, &response);
+
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+
+    hw_auth_token_t *auth_token =
+        reinterpret_cast<hw_auth_token_t *>(response.auth_token.buffer.get());
+
+    ASSERT_EQ((uint32_t) HW_AUTH_PASSWORD, ntohl(auth_token->authenticator_type));
+    ASSERT_EQ((uint64_t) 1, auth_token->challenge);
+    ASSERT_NE(~((uint32_t) 0), auth_token->timestamp);
+    ASSERT_NE((uint64_t) 0, auth_token->user_id);
+    ASSERT_NE((uint64_t) 0, auth_token->authenticator_id);
+}
+
+TEST(GateKeeperTest, TrustedReEnroll) {
+    SoftGateKeeper gatekeeper;
+    SizedBuffer provided_password;
+    EnrollResponse enroll_response;
+    SizedBuffer password_handle;
+
+    // do_enroll enrolls an all 0 password
+    provided_password.buffer.reset(new uint8_t[16]);
+    provided_password.length = 16;
+    memset(provided_password.buffer.get(), 0, 16);
+    do_enroll(gatekeeper, &enroll_response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error);
+
+    // keep a copy of the handle
+    password_handle.buffer.reset(new uint8_t[enroll_response.enrolled_password_handle.length]);
+    password_handle.length = enroll_response.enrolled_password_handle.length;
+    memcpy(password_handle.buffer.get(), enroll_response.enrolled_password_handle.buffer.get(),
+            password_handle.length);
+
+    // verify first password
+    VerifyRequest request(0, 0, &enroll_response.enrolled_password_handle,
+            &provided_password);
+    VerifyResponse response;
+    gatekeeper.Verify(request, &response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+    hw_auth_token_t *auth_token =
+        reinterpret_cast<hw_auth_token_t *>(response.auth_token.buffer.get());
+
+    secure_id_t secure_id = auth_token->user_id;
+
+    // enroll new password
+    provided_password.buffer.reset(new uint8_t[16]);
+    provided_password.length = 16;
+    memset(provided_password.buffer.get(), 0, 16);
+    SizedBuffer password;
+    password.buffer.reset(new uint8_t[16]);
+    memset(password.buffer.get(), 1, 16);
+    password.length = 16;
+    EnrollRequest enroll_request(0, &password_handle, &password, &provided_password);
+    gatekeeper.Enroll(enroll_request, &enroll_response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error);
+
+    // verify new password
+    password.buffer.reset(new uint8_t[16]);
+    memset(password.buffer.get(), 1, 16);
+    password.length = 16;
+    VerifyRequest new_request(0, 0, &enroll_response.enrolled_password_handle,
+            &password);
+    gatekeeper.Verify(new_request, &response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+    ASSERT_EQ(secure_id,
+        reinterpret_cast<hw_auth_token_t *>(response.auth_token.buffer.get())->user_id);
+}
+
+
+TEST(GateKeeperTest, UntrustedReEnroll) {
+    SoftGateKeeper gatekeeper;
+    SizedBuffer provided_password;
+    EnrollResponse enroll_response;
+
+    // do_enroll enrolls an all 0 password
+    provided_password.buffer.reset(new uint8_t[16]);
+    provided_password.length = 16;
+    memset(provided_password.buffer.get(), 0, 16);
+    do_enroll(gatekeeper, &enroll_response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error);
+
+    // verify first password
+    VerifyRequest request(0, 0, &enroll_response.enrolled_password_handle,
+            &provided_password);
+    VerifyResponse response;
+    gatekeeper.Verify(request, &response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+    hw_auth_token_t *auth_token =
+        reinterpret_cast<hw_auth_token_t *>(response.auth_token.buffer.get());
+
+    secure_id_t secure_id = auth_token->user_id;
+
+    // enroll new password
+    SizedBuffer password;
+    password.buffer.reset(new uint8_t[16]);
+    memset(password.buffer.get(), 1, 16);
+    password.length = 16;
+    EnrollRequest enroll_request(0, NULL, &password, NULL);
+    gatekeeper.Enroll(enroll_request, &enroll_response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error);
+
+    // verify new password
+    password.buffer.reset(new uint8_t[16]);
+    memset(password.buffer.get(), 1, 16);
+    password.length = 16;
+    VerifyRequest new_request(0, 0, &enroll_response.enrolled_password_handle,
+            &password);
+    gatekeeper.Verify(new_request, &response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+    ASSERT_NE(secure_id,
+        reinterpret_cast<hw_auth_token_t *>(response.auth_token.buffer.get())->user_id);
+}
+
+
+TEST(GateKeeperTest, VerifyBogusData) {
+    SoftGateKeeper gatekeeper;
+    SizedBuffer provided_password;
+    SizedBuffer password_handle;
+    VerifyResponse response;
+
+    VerifyRequest request(0, 0, &provided_password, &password_handle);
+
+    gatekeeper.Verify(request, &response);
+
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_INVALID, response.error);
+}
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 1d238b1..07e1d73 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -1,7 +1,5 @@
 # Copyright 2013 The Android Open Source Project
 
-ifneq ($(BUILD_TINY_ANDROID),true)
-
 LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
@@ -77,5 +75,3 @@
 
 _add-charger-image :=
 _img_modules :=
-
-endif
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 9388ed0..7ea8250 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -389,7 +389,6 @@
             if (!strcmp(name, ".") || !strcmp(name, ".."))
                 continue;
 
-            char buf[20];
             // Look for "type" file in each subdirectory
             path.clear();
             path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name);
diff --git a/healthd/BatteryPropertiesRegistrar.cpp b/healthd/BatteryPropertiesRegistrar.cpp
index 74bcbfd..09667a1 100644
--- a/healthd/BatteryPropertiesRegistrar.cpp
+++ b/healthd/BatteryPropertiesRegistrar.cpp
@@ -48,13 +48,13 @@
         Mutex::Autolock _l(mRegistrationLock);
         // check whether this is a duplicate
         for (size_t i = 0; i < mListeners.size(); i++) {
-            if (mListeners[i]->asBinder() == listener->asBinder()) {
+            if (IInterface::asBinder(mListeners[i]) == IInterface::asBinder(listener)) {
                 return;
             }
         }
 
         mListeners.add(listener);
-        listener->asBinder()->linkToDeath(this);
+        IInterface::asBinder(listener)->linkToDeath(this);
     }
     healthd_battery_update();
 }
@@ -64,8 +64,8 @@
         return;
     Mutex::Autolock _l(mRegistrationLock);
     for (size_t i = 0; i < mListeners.size(); i++) {
-        if (mListeners[i]->asBinder() == listener->asBinder()) {
-            mListeners[i]->asBinder()->unlinkToDeath(this);
+        if (IInterface::asBinder(mListeners[i]) == IInterface::asBinder(listener)) {
+            IInterface::asBinder(mListeners[i])->unlinkToDeath(this);
             mListeners.removeAt(i);
             break;
         }
@@ -93,7 +93,7 @@
     Mutex::Autolock _l(mRegistrationLock);
 
     for (size_t i = 0; i < mListeners.size(); i++) {
-        if (mListeners[i]->asBinder() == who) {
+        if (IInterface::asBinder(mListeners[i]) == who) {
             mListeners.removeAt(i);
             break;
         }
diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
index f4171bd..b0002cc 100644
--- a/healthd/healthd.cpp
+++ b/healthd/healthd.cpp
@@ -53,6 +53,7 @@
     .batteryCurrentAvgPath = String8(String8::kEmptyString),
     .batteryChargeCounterPath = String8(String8::kEmptyString),
     .energyCounter = NULL,
+    .boot_min_cap = 0,
     .screen_on = NULL,
 };
 
@@ -65,7 +66,6 @@
 #define MAX_EPOLL_EVENTS 40
 static int uevent_fd;
 static int wakealarm_fd;
-static int binder_fd;
 
 // -1 for no epoll timeout
 static int awake_poll_interval = -1;
diff --git a/healthd/healthd.h b/healthd/healthd.h
index 4704f0b..84b6d76 100644
--- a/healthd/healthd.h
+++ b/healthd/healthd.h
@@ -67,6 +67,7 @@
     android::String8 batteryChargeCounterPath;
 
     int (*energyCounter)(int64_t *);
+    int boot_min_cap;
     bool (*screen_on)(android::BatteryProperties *props);
 };
 
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 5039649..6800ad2 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -88,7 +88,7 @@
     int min_capacity;
     bool level_only;
 
-    gr_surface surface;
+    GRSurface* surface;
 };
 
 struct animation {
@@ -115,7 +115,8 @@
     struct key_state keys[KEY_MAX + 1];
 
     struct animation *batt_anim;
-    gr_surface surf_unknown;
+    GRSurface* surf_unknown;
+    int boot_min_cap;
 };
 
 static struct frame batt_anim_frames[] = {
@@ -273,7 +274,7 @@
 }
 
 /* returns the last y-offset of where the surface ends */
-static int draw_surface_centered(struct charger* /*charger*/, gr_surface surface)
+static int draw_surface_centered(struct charger* /*charger*/, GRSurface* surface)
 {
     int w;
     int h;
@@ -344,7 +345,6 @@
 static void update_screen_state(struct charger *charger, int64_t now)
 {
     struct animation *batt_anim = charger->batt_anim;
-    int cur_frame;
     int disp_time;
 
     if (!batt_anim->run || now < charger->next_screen_transition)
@@ -387,7 +387,6 @@
 
     /* animation starting, set up the animation */
     if (batt_anim->cur_frame == 0) {
-        int ret;
 
         LOGV("[%" PRId64 "] animation starting\n", now);
         if (batt_prop && batt_prop->batteryLevel >= 0 && batt_anim->num_frames != 0) {
@@ -510,7 +509,6 @@
 static void process_key(struct charger *charger, int code, int64_t now)
 {
     struct key_state *key = &charger->keys[code];
-    int64_t next_key_check;
 
     if (code == KEY_POWER) {
         if (key->down) {
@@ -523,19 +521,29 @@
                     LOGW("[%" PRId64 "] booting from charger mode\n", now);
                     property_set("sys.boot_from_charger_mode", "1");
                 } else {
-                    LOGW("[%" PRId64 "] rebooting\n", now);
-                    android_reboot(ANDROID_RB_RESTART, 0, 0);
+                    if (charger->batt_anim->capacity >= charger->boot_min_cap) {
+                        LOGW("[%" PRId64 "] rebooting\n", now);
+                        android_reboot(ANDROID_RB_RESTART, 0, 0);
+                    } else {
+                        LOGV("[%" PRId64 "] ignore power-button press, battery level "
+                            "less than minimum\n", now);
+                    }
                 }
             } else {
                 /* if the key is pressed but timeout hasn't expired,
                  * make sure we wake up at the right-ish time to check
                  */
                 set_next_key_check(charger, key, POWER_ON_KEY_TIME);
+
+               /* Turn on the display and kick animation on power-key press
+                * rather than on key release
+                */
+                kick_animation(charger->batt_anim);
+                request_suspend(false);
             }
         } else {
             /* if the power key got released, force screen state cycle */
             if (key->pending) {
-                request_suspend(false);
                 kick_animation(charger->batt_anim);
             }
         }
@@ -558,6 +566,11 @@
         return;
 
     if (!charger->charger_connected) {
+
+        /* Last cycle would have stopped at the extreme top of battery-icon
+         * Need to show the correct level corresponding to capacity.
+         */
+        kick_animation(charger->batt_anim);
         request_suspend(false);
         if (charger->next_pwr_check == -1) {
             charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
@@ -583,7 +596,6 @@
 {
     struct charger *charger = &charger_state;
     int64_t now = curr_time_ms();
-    int ret;
 
     handle_input_state(charger, now);
     handle_power_supply_state(charger, now);
@@ -618,8 +630,6 @@
     int64_t now = curr_time_ms();
     int64_t next_event = INT64_MAX;
     int64_t timeout;
-    struct input_event ev;
-    int ret;
 
     LOGV("[%" PRId64 "] next screen: %" PRId64 " next key: %" PRId64 " next pwr: %" PRId64 "\n", now,
          charger->next_screen_transition, charger->next_key_check,
@@ -687,7 +697,7 @@
 
     charger->batt_anim = &battery_animation;
 
-    gr_surface* scale_frames;
+    GRSurface** scale_frames;
     int scale_count;
     ret = res_create_multi_display_surface("charger/battery_scale", &scale_count, &scale_frames);
     if (ret < 0) {
@@ -711,4 +721,5 @@
     charger->next_key_check = -1;
     charger->next_pwr_check = -1;
     healthd_config = config;
+    charger->boot_min_cap = config->boot_min_cap;
 }
diff --git a/include/backtrace/Backtrace.h b/include/backtrace/Backtrace.h
index e07d322..290682a 100644
--- a/include/backtrace/Backtrace.h
+++ b/include/backtrace/Backtrace.h
@@ -39,14 +39,11 @@
   uintptr_t pc;           // The absolute pc.
   uintptr_t sp;           // The top of the stack.
   size_t stack_size;      // The size of the stack, zero indicate an unknown stack size.
-  const backtrace_map_t* map;   // The map associated with the given pc.
+  backtrace_map_t map;    // The map associated with the given pc.
   std::string func_name;  // The function name associated with this pc, NULL if not found.
   uintptr_t func_offset;  // pc relative to the start of the function, only valid if func_name is not NULL.
 };
 
-// Forward declarations.
-class BacktraceImpl;
-
 #if defined(__APPLE__)
 struct __darwin_ucontext;
 typedef __darwin_ucontext ucontext_t;
@@ -72,26 +69,32 @@
   virtual ~Backtrace();
 
   // Get the current stack trace and store in the backtrace_ structure.
-  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* context = NULL);
+  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* context = NULL) = 0;
 
   // Get the function name and offset into the function given the pc.
   // If the string is empty, then no valid function name was found.
   virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset);
 
-  // Find the map associated with the given pc.
-  virtual const backtrace_map_t* FindMap(uintptr_t pc);
+  // Fill in the map data associated with the given pc.
+  virtual void FillInMap(uintptr_t pc, backtrace_map_t* map);
 
   // Read the data at a specific address.
   virtual bool ReadWord(uintptr_t ptr, word_t* out_value) = 0;
 
+  // Read arbitrary data from a specific address. If a read request would
+  // span from one map to another, this call only reads up until the end
+  // of the current map.
+  // Returns the total number of bytes actually read.
+  virtual size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) = 0;
+
   // Create a string representing the formatted line of backtrace information
   // for a single frame.
   virtual std::string FormatFrameData(size_t frame_num);
   virtual std::string FormatFrameData(const backtrace_frame_data_t* frame);
 
-  pid_t Pid() { return pid_; }
-  pid_t Tid() { return tid_; }
-  size_t NumFrames() { return frames_.size(); }
+  pid_t Pid() const { return pid_; }
+  pid_t Tid() const { return tid_; }
+  size_t NumFrames() const { return frames_.size(); }
 
   const backtrace_frame_data_t* GetFrame(size_t frame_num) {
     if (frame_num >= frames_.size()) {
@@ -111,7 +114,11 @@
   BacktraceMap* GetMap() { return map_; }
 
 protected:
-  Backtrace(BacktraceImpl* impl, pid_t pid, BacktraceMap* map);
+  Backtrace(pid_t pid, pid_t tid, BacktraceMap* map);
+
+  // The name returned is not demangled, GetFunctionName() takes care of
+  // demangling the name.
+  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) = 0;
 
   virtual bool VerifyReadWordArgs(uintptr_t ptr, word_t* out_value);
 
@@ -124,10 +131,6 @@
   bool map_shared_;
 
   std::vector<backtrace_frame_data_t> frames_;
-
-  BacktraceImpl* impl_;
-
-  friend class BacktraceImpl;
 };
 
 #endif // _BACKTRACE_BACKTRACE_H
diff --git a/include/backtrace/BacktraceMap.h b/include/backtrace/BacktraceMap.h
index 4ed23a8..bb18aa2 100644
--- a/include/backtrace/BacktraceMap.h
+++ b/include/backtrace/BacktraceMap.h
@@ -33,9 +33,11 @@
 #include <string>
 
 struct backtrace_map_t {
-  uintptr_t start;
-  uintptr_t end;
-  int flags;
+  uintptr_t start = 0;
+  uintptr_t end = 0;
+  uintptr_t offset = 0;
+  uintptr_t load_base = 0;
+  int flags = 0;
   std::string name;
 };
 
@@ -48,15 +50,16 @@
 
   virtual ~BacktraceMap();
 
-  // Get the map data structure for the given address.
-  virtual const backtrace_map_t* Find(uintptr_t addr);
+  // Fill in the map data structure for the given address.
+  virtual void FillIn(uintptr_t addr, backtrace_map_t* map);
 
   // The flags returned are the same flags as used by the mmap call.
   // The values are PROT_*.
   int GetFlags(uintptr_t pc) {
-    const backtrace_map_t* map = Find(pc);
-    if (map) {
-      return map->flags;
+    backtrace_map_t map;
+    FillIn(pc, &map);
+    if (IsValid(map)) {
+      return map.flags;
     }
     return PROT_NONE;
   }
@@ -75,6 +78,18 @@
 
   virtual bool Build();
 
+  static inline bool IsValid(const backtrace_map_t& map) {
+    return map.end > 0;
+  }
+
+  static uintptr_t GetRelativePc(const backtrace_map_t& map, uintptr_t pc) {
+    if (IsValid(map)) {
+      return pc - map.start + map.load_base;
+    } else {
+      return pc;
+    }
+  }
+
 protected:
   BacktraceMap(pid_t pid);
 
diff --git a/include/ctest/ctest.h b/include/ctest/ctest.h
deleted file mode 100644
index 1a83b20..0000000
--- a/include/ctest/ctest.h
+++ /dev/null
@@ -1,70 +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.
- */
-
-/**
- * Very simple unit testing framework. 
- */
-
-#ifndef __CUTILS_TEST_H
-#define __CUTILS_TEST_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Adds a test to the test suite.
- */
-#define addTest(test) addNamedTest(#test, &test)
-   
-/**
- * Asserts that a condition is true. The test fails if it isn't.
- */
-#define assertTrue(value, message) assertTrueWithSource(value, __FILE__, __LINE__, message);
-
-/**
- * Asserts that a condition is false. The test fails if the value is true.
- */
-#define assertFalse(value, message) assertTrueWithSource(!value, __FILE__, __LINE__, message);
-
-/** Fails a test with the given message. */
-#define fail(message) assertTrueWithSource(0, __FILE__, __LINE__, message);
-
-/**
- * Asserts that two values are ==.
- */
-#define assertSame(a, b) assertTrueWithSource(a == b, __FILE__, __LINE__, "Expected same value.");
-    
-/**
- * Asserts that two values are !=.
- */
-#define assertNotSame(a, b) assertTrueWithSource(a != b, __FILE__, __LINE__,\
-        "Expected different values");
-    
-/**
- * Runs a test suite.
- */
-void runTests(void);
-
-// Do not call these functions directly. Use macros above instead.
-void addNamedTest(const char* name, void (*test)(void));
-void assertTrueWithSource(int value, const char* file, int line, char* message);
-    
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __CUTILS_TEST_H */ 
diff --git a/include/cutils/android_reboot.h b/include/cutils/android_reboot.h
index 8c30e8e..85e1b7e 100644
--- a/include/cutils/android_reboot.h
+++ b/include/cutils/android_reboot.h
@@ -27,7 +27,7 @@
 /* Properties */
 #define ANDROID_RB_PROPERTY "sys.powerctl"
 
-int android_reboot(int cmd, int flags, char *arg);
+int android_reboot(int cmd, int flags, const char *arg);
 
 __END_DECLS
 
diff --git a/include/cutils/aref.h b/include/cutils/aref.h
index 460ac02..3bd36ea 100644
--- a/include/cutils/aref.h
+++ b/include/cutils/aref.h
@@ -20,11 +20,7 @@
 #include <stddef.h>
 #include <sys/cdefs.h>
 
-#ifdef ANDROID_SMP
-#include <cutils/atomic-inline.h>
-#else
 #include <cutils/atomic.h>
-#endif
 
 __BEGIN_DECLS
 
diff --git a/include/cutils/atomic-arm.h b/include/cutils/atomic-arm.h
deleted file mode 100644
index 6b031b6..0000000
--- a/include/cutils/atomic-arm.h
+++ /dev/null
@@ -1,167 +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 ANDROID_CUTILS_ATOMIC_ARM_H
-#define ANDROID_CUTILS_ATOMIC_ARM_H
-
-#include <stdint.h>
-
-#ifndef ANDROID_ATOMIC_INLINE
-#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline))
-#endif
-
-extern ANDROID_ATOMIC_INLINE void android_compiler_barrier()
-{
-    __asm__ __volatile__ ("" : : : "memory");
-}
-
-extern ANDROID_ATOMIC_INLINE void android_memory_barrier()
-{
-#if ANDROID_SMP == 0
-    android_compiler_barrier();
-#else
-    __asm__ __volatile__ ("dmb" : : : "memory");
-#endif
-}
-
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
-{
-    int32_t value = *ptr;
-    android_memory_barrier();
-    return value;
-}
-
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_release_load(volatile const int32_t *ptr)
-{
-    android_memory_barrier();
-    return *ptr;
-}
-
-extern ANDROID_ATOMIC_INLINE
-void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
-{
-    *ptr = value;
-    android_memory_barrier();
-}
-
-extern ANDROID_ATOMIC_INLINE
-void android_atomic_release_store(int32_t value, volatile int32_t *ptr)
-{
-    android_memory_barrier();
-    *ptr = value;
-}
-
-extern ANDROID_ATOMIC_INLINE
-int android_atomic_cas(int32_t old_value, int32_t new_value,
-                       volatile int32_t *ptr)
-{
-    int32_t prev, status;
-    do {
-        __asm__ __volatile__ ("ldrex %0, [%3]\n"
-                              "mov %1, #0\n"
-                              "teq %0, %4\n"
-#ifdef __thumb2__
-                              "it eq\n"
-#endif
-                              "strexeq %1, %5, [%3]"
-                              : "=&r" (prev), "=&r" (status), "+m"(*ptr)
-                              : "r" (ptr), "Ir" (old_value), "r" (new_value)
-                              : "cc");
-    } while (__builtin_expect(status != 0, 0));
-    return prev != old_value;
-}
-
-extern ANDROID_ATOMIC_INLINE
-int android_atomic_acquire_cas(int32_t old_value, int32_t new_value,
-                               volatile int32_t *ptr)
-{
-    int status = android_atomic_cas(old_value, new_value, ptr);
-    android_memory_barrier();
-    return status;
-}
-
-extern ANDROID_ATOMIC_INLINE
-int android_atomic_release_cas(int32_t old_value, int32_t new_value,
-                               volatile int32_t *ptr)
-{
-    android_memory_barrier();
-    return android_atomic_cas(old_value, new_value, ptr);
-}
-
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr)
-{
-    int32_t prev, tmp, status;
-    android_memory_barrier();
-    do {
-        __asm__ __volatile__ ("ldrex %0, [%4]\n"
-                              "add %1, %0, %5\n"
-                              "strex %2, %1, [%4]"
-                              : "=&r" (prev), "=&r" (tmp),
-                                "=&r" (status), "+m" (*ptr)
-                              : "r" (ptr), "Ir" (increment)
-                              : "cc");
-    } while (__builtin_expect(status != 0, 0));
-    return prev;
-}
-
-extern ANDROID_ATOMIC_INLINE int32_t android_atomic_inc(volatile int32_t *addr)
-{
-    return android_atomic_add(1, addr);
-}
-
-extern ANDROID_ATOMIC_INLINE int32_t android_atomic_dec(volatile int32_t *addr)
-{
-    return android_atomic_add(-1, addr);
-}
-
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_and(int32_t value, volatile int32_t *ptr)
-{
-    int32_t prev, tmp, status;
-    android_memory_barrier();
-    do {
-        __asm__ __volatile__ ("ldrex %0, [%4]\n"
-                              "and %1, %0, %5\n"
-                              "strex %2, %1, [%4]"
-                              : "=&r" (prev), "=&r" (tmp),
-                                "=&r" (status), "+m" (*ptr)
-                              : "r" (ptr), "Ir" (value)
-                              : "cc");
-    } while (__builtin_expect(status != 0, 0));
-    return prev;
-}
-
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_or(int32_t value, volatile int32_t *ptr)
-{
-    int32_t prev, tmp, status;
-    android_memory_barrier();
-    do {
-        __asm__ __volatile__ ("ldrex %0, [%4]\n"
-                              "orr %1, %0, %5\n"
-                              "strex %2, %1, [%4]"
-                              : "=&r" (prev), "=&r" (tmp),
-                                "=&r" (status), "+m" (*ptr)
-                              : "r" (ptr), "Ir" (value)
-                              : "cc");
-    } while (__builtin_expect(status != 0, 0));
-    return prev;
-}
-
-#endif /* ANDROID_CUTILS_ATOMIC_ARM_H */
diff --git a/include/cutils/atomic-arm64.h b/include/cutils/atomic-arm64.h
deleted file mode 100644
index 7ae47d7..0000000
--- a/include/cutils/atomic-arm64.h
+++ /dev/null
@@ -1,156 +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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef ANDROID_CUTILS_ATOMIC_AARCH64_H
-#define ANDROID_CUTILS_ATOMIC_AARCH64_H
-
-#include <stdint.h>
-
-#ifndef ANDROID_ATOMIC_INLINE
-#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline))
-#endif
-
-/*
-   TODOAArch64: Revisit the below functions and check for potential
-   optimizations using assembly code or otherwise.
-*/
-
-extern ANDROID_ATOMIC_INLINE
-void android_compiler_barrier(void)
-{
-    __asm__ __volatile__ ("" : : : "memory");
-}
-
-extern ANDROID_ATOMIC_INLINE
-void android_memory_barrier(void)
-{
-    __asm__ __volatile__ ("dmb ish" : : : "memory");
-}
-
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
-{
-    int32_t value = *ptr;
-    android_memory_barrier();
-    return value;
-}
-
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_release_load(volatile const int32_t *ptr)
-{
-    android_memory_barrier();
-    return *ptr;
-}
-
-extern ANDROID_ATOMIC_INLINE
-void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
-{
-    *ptr = value;
-    android_memory_barrier();
-}
-
-extern ANDROID_ATOMIC_INLINE
-void android_atomic_release_store(int32_t value, volatile int32_t *ptr)
-{
-    android_memory_barrier();
-    *ptr = value;
-}
-
-extern ANDROID_ATOMIC_INLINE
-int android_atomic_cas(int32_t old_value, int32_t new_value,
-                       volatile int32_t *ptr)
-{
-    return __sync_val_compare_and_swap(ptr, old_value, new_value) != old_value;
-}
-
-extern ANDROID_ATOMIC_INLINE
-int android_atomic_acquire_cas(int32_t old_value, int32_t new_value,
-                               volatile int32_t *ptr)
-{
-    int status = android_atomic_cas(old_value, new_value, ptr);
-    android_memory_barrier();
-    return status;
-}
-
-extern ANDROID_ATOMIC_INLINE
-int android_atomic_release_cas(int32_t old_value, int32_t new_value,
-                               volatile int32_t *ptr)
-{
-    android_memory_barrier();
-    return android_atomic_cas(old_value, new_value, ptr);
-}
-
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr)
-{
-    int32_t prev, status;
-    android_memory_barrier();
-    do {
-        prev = *ptr;
-        status = android_atomic_cas(prev, prev + increment, ptr);
-    } while (__builtin_expect(status != 0, 0));
-    return prev;
-}
-
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_inc(volatile int32_t *addr)
-{
-    return android_atomic_add(1, addr);
-}
-
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_dec(volatile int32_t *addr)
-{
-    return android_atomic_add(-1, addr);
-}
-
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_and(int32_t value, volatile int32_t *ptr)
-{
-    int32_t prev, status;
-    android_memory_barrier();
-    do {
-        prev = *ptr;
-        status = android_atomic_cas(prev, prev & value, ptr);
-    } while (__builtin_expect(status != 0, 0));
-    return prev;
-}
-
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_or(int32_t value, volatile int32_t *ptr)
-{
-    int32_t prev, status;
-    android_memory_barrier();
-    do {
-        prev = *ptr;
-        status = android_atomic_cas(prev, prev | value, ptr);
-    } while (__builtin_expect(status != 0, 0));
-    return prev;
-}
-
-#endif /* ANDROID_CUTILS_ATOMIC_AARCH64_H */
diff --git a/include/cutils/atomic-inline.h b/include/cutils/atomic-inline.h
deleted file mode 100644
index a31e913..0000000
--- a/include/cutils/atomic-inline.h
+++ /dev/null
@@ -1,72 +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 ANDROID_CUTILS_ATOMIC_INLINE_H
-#define ANDROID_CUTILS_ATOMIC_INLINE_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Inline declarations and macros for some special-purpose atomic
- * operations.  These are intended for rare circumstances where a
- * memory barrier needs to be issued inline rather than as a function
- * call.
- *
- * Most code should not use these.
- *
- * Anything that does include this file must set ANDROID_SMP to either
- * 0 or 1, indicating compilation for UP or SMP, respectively.
- *
- * Macros defined in this header:
- *
- * void ANDROID_MEMBAR_FULL(void)
- *   Full memory barrier.  Provides a compiler reordering barrier, and
- *   on SMP systems emits an appropriate instruction.
- */
-
-#if !defined(ANDROID_SMP)
-# error "Must define ANDROID_SMP before including atomic-inline.h"
-#endif
-
-#if defined(__aarch64__)
-#include <cutils/atomic-arm64.h>
-#elif defined(__arm__)
-#include <cutils/atomic-arm.h>
-#elif defined(__i386__)
-#include <cutils/atomic-x86.h>
-#elif defined(__x86_64__)
-#include <cutils/atomic-x86_64.h>
-#elif defined(__mips64)
-#include <cutils/atomic-mips64.h>
-#elif defined(__mips__)
-#include <cutils/atomic-mips.h>
-#else
-#error atomic operations are unsupported
-#endif
-
-#if ANDROID_SMP == 0
-#define ANDROID_MEMBAR_FULL android_compiler_barrier
-#else
-#define ANDROID_MEMBAR_FULL android_memory_barrier
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* ANDROID_CUTILS_ATOMIC_INLINE_H */
diff --git a/include/cutils/atomic-mips.h b/include/cutils/atomic-mips.h
deleted file mode 100644
index 5d4f097..0000000
--- a/include/cutils/atomic-mips.h
+++ /dev/null
@@ -1,174 +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 ANDROID_CUTILS_ATOMIC_MIPS_H
-#define ANDROID_CUTILS_ATOMIC_MIPS_H
-
-#include <stdint.h>
-
-#ifndef ANDROID_ATOMIC_INLINE
-#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline))
-#endif
-
-extern ANDROID_ATOMIC_INLINE void android_compiler_barrier(void)
-{
-    __asm__ __volatile__ ("" : : : "memory");
-}
-
-#if ANDROID_SMP == 0
-extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
-{
-    android_compiler_barrier();
-}
-#else
-extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
-{
-    __asm__ __volatile__ ("sync" : : : "memory");
-}
-#endif
-
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_acquire_load(volatile const int32_t *ptr)
-{
-    int32_t value = *ptr;
-    android_memory_barrier();
-    return value;
-}
-
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_release_load(volatile const int32_t *ptr)
-{
-    android_memory_barrier();
-    return *ptr;
-}
-
-extern ANDROID_ATOMIC_INLINE void
-android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
-{
-    *ptr = value;
-    android_memory_barrier();
-}
-
-extern ANDROID_ATOMIC_INLINE void
-android_atomic_release_store(int32_t value, volatile int32_t *ptr)
-{
-    android_memory_barrier();
-    *ptr = value;
-}
-
-extern ANDROID_ATOMIC_INLINE int
-android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr)
-{
-    int32_t prev, status;
-    do {
-        __asm__ __volatile__ (
-            "    ll     %[prev], (%[ptr])\n"
-            "    li     %[status], 1\n"
-            "    bne    %[prev], %[old], 9f\n"
-            "    move   %[status], %[new_value]\n"
-            "    sc     %[status], (%[ptr])\n"
-            "9:\n"
-            : [prev] "=&r" (prev), [status] "=&r" (status)
-            : [ptr] "r" (ptr), [old] "r" (old_value), [new_value] "r" (new_value)
-            );
-    } while (__builtin_expect(status == 0, 0));
-    return prev != old_value;
-}
-
-extern ANDROID_ATOMIC_INLINE int
-android_atomic_acquire_cas(int32_t old_value,
-                           int32_t new_value,
-                           volatile int32_t *ptr)
-{
-    int status = android_atomic_cas(old_value, new_value, ptr);
-    android_memory_barrier();
-    return status;
-}
-
-extern ANDROID_ATOMIC_INLINE int
-android_atomic_release_cas(int32_t old_value,
-                           int32_t new_value,
-                           volatile int32_t *ptr)
-{
-    android_memory_barrier();
-    return android_atomic_cas(old_value, new_value, ptr);
-}
-
-
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_add(int32_t increment, volatile int32_t *ptr)
-{
-    int32_t prev, status;
-    android_memory_barrier();
-    do {
-        __asm__ __volatile__ (
-        "    ll    %[prev], (%[ptr])\n"
-        "    addu  %[status], %[prev], %[inc]\n"
-        "    sc    %[status], (%[ptr])\n"
-        :  [status] "=&r" (status), [prev] "=&r" (prev)
-        :  [ptr] "r" (ptr), [inc] "Ir" (increment)
-        );
-    } while (__builtin_expect(status == 0, 0));
-    return prev;
-}
-
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_inc(volatile int32_t *addr)
-{
-    return android_atomic_add(1, addr);
-}
-
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_dec(volatile int32_t *addr)
-{
-    return android_atomic_add(-1, addr);
-}
-
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_and(int32_t value, volatile int32_t *ptr)
-{
-    int32_t prev, status;
-    android_memory_barrier();
-    do {
-        __asm__ __volatile__ (
-        "    ll    %[prev], (%[ptr])\n"
-        "    and   %[status], %[prev], %[value]\n"
-        "    sc    %[status], (%[ptr])\n"
-        : [prev] "=&r" (prev), [status] "=&r" (status)
-        : [ptr] "r" (ptr), [value] "Ir" (value)
-            );
-    } while (__builtin_expect(status == 0, 0));
-    return prev;
-}
-
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_or(int32_t value, volatile int32_t *ptr)
-{
-    int32_t prev, status;
-    android_memory_barrier();
-    do {
-        __asm__ __volatile__ (
-        "    ll    %[prev], (%[ptr])\n"
-        "    or    %[status], %[prev], %[value]\n"
-        "    sc    %[status], (%[ptr])\n"
-        : [prev] "=&r" (prev), [status] "=&r" (status)
-        : [ptr] "r" (ptr), [value] "Ir" (value)
-            );
-    } while (__builtin_expect(status == 0, 0));
-    return prev;
-}
-
-#endif /* ANDROID_CUTILS_ATOMIC_MIPS_H */
diff --git a/include/cutils/atomic-mips64.h b/include/cutils/atomic-mips64.h
deleted file mode 100644
index 9d8f65e..0000000
--- a/include/cutils/atomic-mips64.h
+++ /dev/null
@@ -1,166 +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 ANDROID_CUTILS_ATOMIC_MIPS64_H
-#define ANDROID_CUTILS_ATOMIC_MIPS64_H
-
-#include <stdint.h>
-
-#ifndef ANDROID_ATOMIC_INLINE
-#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline))
-#endif
-
-extern ANDROID_ATOMIC_INLINE void android_compiler_barrier(void)
-{
-    __asm__ __volatile__ ("" : : : "memory");
-}
-
-extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
-{
-    __asm__ __volatile__ ("sync" : : : "memory");
-}
-
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
-{
-    int32_t value = *ptr;
-    android_memory_barrier();
-    return value;
-}
-
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_release_load(volatile const int32_t *ptr)
-{
-    android_memory_barrier();
-    return *ptr;
-}
-
-extern ANDROID_ATOMIC_INLINE
-void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
-{
-    *ptr = value;
-    android_memory_barrier();
-}
-
-extern ANDROID_ATOMIC_INLINE
-void android_atomic_release_store(int32_t value, volatile int32_t *ptr)
-{
-    android_memory_barrier();
-    *ptr = value;
-}
-
-extern ANDROID_ATOMIC_INLINE
-int android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr)
-{
-    int32_t prev, status;
-    do {
-        __asm__ __volatile__ (
-            "    ll     %[prev], (%[ptr])\n"
-            "    li     %[status], 1\n"
-            "    bne    %[prev], %[old], 9f\n"
-            "    move   %[status], %[new_value]\n"
-            "    sc     %[status], (%[ptr])\n"
-            "9:\n"
-            : [prev] "=&r" (prev), [status] "=&r" (status)
-            : [ptr] "r" (ptr), [old] "r" (old_value), [new_value] "r" (new_value)
-            );
-    } while (__builtin_expect(status == 0, 0));
-    return prev != old_value;
-}
-
-extern ANDROID_ATOMIC_INLINE
-int android_atomic_acquire_cas(int32_t old_value,
-                           int32_t new_value,
-                           volatile int32_t *ptr)
-{
-    int status = android_atomic_cas(old_value, new_value, ptr);
-    android_memory_barrier();
-    return status;
-}
-
-extern ANDROID_ATOMIC_INLINE
-int android_atomic_release_cas(int32_t old_value,
-                           int32_t new_value,
-                           volatile int32_t *ptr)
-{
-    android_memory_barrier();
-    return android_atomic_cas(old_value, new_value, ptr);
-}
-
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr)
-{
-    int32_t prev, status;
-    android_memory_barrier();
-    do {
-        __asm__ __volatile__ (
-        "    ll    %[prev], (%[ptr])\n"
-        "    addu  %[status], %[prev], %[inc]\n"
-        "    sc    %[status], (%[ptr])\n"
-        :  [status] "=&r" (status), [prev] "=&r" (prev)
-        :  [ptr] "r" (ptr), [inc] "Ir" (increment)
-        );
-    } while (__builtin_expect(status == 0, 0));
-    return prev;
-}
-
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_inc(volatile int32_t *addr)
-{
-    return android_atomic_add(1, addr);
-}
-
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_dec(volatile int32_t *addr)
-{
-    return android_atomic_add(-1, addr);
-}
-
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_and(int32_t value, volatile int32_t *ptr)
-{
-    int32_t prev, status;
-    android_memory_barrier();
-    do {
-        __asm__ __volatile__ (
-        "    ll    %[prev], (%[ptr])\n"
-        "    and   %[status], %[prev], %[value]\n"
-        "    sc    %[status], (%[ptr])\n"
-        : [prev] "=&r" (prev), [status] "=&r" (status)
-        : [ptr] "r" (ptr), [value] "Ir" (value)
-            );
-    } while (__builtin_expect(status == 0, 0));
-    return prev;
-}
-
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_or(int32_t value, volatile int32_t *ptr)
-{
-    int32_t prev, status;
-    android_memory_barrier();
-    do {
-        __asm__ __volatile__ (
-        "    ll    %[prev], (%[ptr])\n"
-        "    or    %[status], %[prev], %[value]\n"
-        "    sc    %[status], (%[ptr])\n"
-        : [prev] "=&r" (prev), [status] "=&r" (status)
-        : [ptr] "r" (ptr), [value] "Ir" (value)
-            );
-    } while (__builtin_expect(status == 0, 0));
-    return prev;
-}
-
-#endif /* ANDROID_CUTILS_ATOMIC_MIPS_H */
diff --git a/include/cutils/atomic-x86.h b/include/cutils/atomic-x86.h
deleted file mode 100644
index 06bf1a3..0000000
--- a/include/cutils/atomic-x86.h
+++ /dev/null
@@ -1,145 +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 ANDROID_CUTILS_ATOMIC_X86_H
-#define ANDROID_CUTILS_ATOMIC_X86_H
-
-#include <stdint.h>
-
-#ifndef ANDROID_ATOMIC_INLINE
-#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline))
-#endif
-
-extern ANDROID_ATOMIC_INLINE void android_compiler_barrier(void)
-{
-    __asm__ __volatile__ ("" : : : "memory");
-}
-
-#if ANDROID_SMP == 0
-extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
-{
-    android_compiler_barrier();
-}
-#else
-extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
-{
-    __asm__ __volatile__ ("mfence" : : : "memory");
-}
-#endif
-
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_acquire_load(volatile const int32_t *ptr)
-{
-    int32_t value = *ptr;
-    android_compiler_barrier();
-    return value;
-}
-
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_release_load(volatile const int32_t *ptr)
-{
-    android_memory_barrier();
-    return *ptr;
-}
-
-extern ANDROID_ATOMIC_INLINE void
-android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
-{
-    *ptr = value;
-    android_memory_barrier();
-}
-
-extern ANDROID_ATOMIC_INLINE void
-android_atomic_release_store(int32_t value, volatile int32_t *ptr)
-{
-    android_compiler_barrier();
-    *ptr = value;
-}
-
-extern ANDROID_ATOMIC_INLINE int
-android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr)
-{
-    int32_t prev;
-    __asm__ __volatile__ ("lock; cmpxchgl %1, %2"
-                          : "=a" (prev)
-                          : "q" (new_value), "m" (*ptr), "0" (old_value)
-                          : "memory");
-    return prev != old_value;
-}
-
-extern ANDROID_ATOMIC_INLINE int
-android_atomic_acquire_cas(int32_t old_value,
-                           int32_t new_value,
-                           volatile int32_t *ptr)
-{
-    /* Loads are not reordered with other loads. */
-    return android_atomic_cas(old_value, new_value, ptr);
-}
-
-extern ANDROID_ATOMIC_INLINE int
-android_atomic_release_cas(int32_t old_value,
-                           int32_t new_value,
-                           volatile int32_t *ptr)
-{
-    /* Stores are not reordered with other stores. */
-    return android_atomic_cas(old_value, new_value, ptr);
-}
-
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_add(int32_t increment, volatile int32_t *ptr)
-{
-    __asm__ __volatile__ ("lock; xaddl %0, %1"
-                          : "+r" (increment), "+m" (*ptr)
-                          : : "memory");
-    /* increment now holds the old value of *ptr */
-    return increment;
-}
-
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_inc(volatile int32_t *addr)
-{
-    return android_atomic_add(1, addr);
-}
-
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_dec(volatile int32_t *addr)
-{
-    return android_atomic_add(-1, addr);
-}
-
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_and(int32_t value, volatile int32_t *ptr)
-{
-    int32_t prev, status;
-    do {
-        prev = *ptr;
-        status = android_atomic_cas(prev, prev & value, ptr);
-    } while (__builtin_expect(status != 0, 0));
-    return prev;
-}
-
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_or(int32_t value, volatile int32_t *ptr)
-{
-    int32_t prev, status;
-    do {
-        prev = *ptr;
-        status = android_atomic_cas(prev, prev | value, ptr);
-    } while (__builtin_expect(status != 0, 0));
-    return prev;
-}
-
-#endif /* ANDROID_CUTILS_ATOMIC_X86_H */
diff --git a/include/cutils/atomic-x86_64.h b/include/cutils/atomic-x86_64.h
deleted file mode 100644
index 99cb070..0000000
--- a/include/cutils/atomic-x86_64.h
+++ /dev/null
@@ -1,151 +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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef ANDROID_CUTILS_ATOMIC_X86_64_H
-#define ANDROID_CUTILS_ATOMIC_X86_64_H
-
-#include <stdint.h>
-
-#ifndef ANDROID_ATOMIC_INLINE
-#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline))
-#endif
-
-extern ANDROID_ATOMIC_INLINE
-void android_compiler_barrier(void)
-{
-    __asm__ __volatile__ ("" : : : "memory");
-}
-
-extern ANDROID_ATOMIC_INLINE
-void android_memory_barrier(void)
-{
-    __asm__ __volatile__ ("mfence" : : : "memory");
-}
-
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
-{
-    int32_t value = *ptr;
-    android_compiler_barrier();
-    return value;
-}
-
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_release_load(volatile const int32_t *ptr)
-{
-    android_memory_barrier();
-    return *ptr;
-}
-
-extern ANDROID_ATOMIC_INLINE
-void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
-{
-    *ptr = value;
-    android_memory_barrier();
-}
-
-extern ANDROID_ATOMIC_INLINE
-void android_atomic_release_store(int32_t value, volatile int32_t *ptr)
-{
-    android_compiler_barrier();
-    *ptr = value;
-}
-
-extern ANDROID_ATOMIC_INLINE
-int android_atomic_cas(int32_t old_value, int32_t new_value,
-                       volatile int32_t *ptr)
-{
-    int32_t prev;
-    __asm__ __volatile__ ("lock; cmpxchgl %1, %2"
-                          : "=a" (prev)
-                          : "q" (new_value), "m" (*ptr), "0" (old_value)
-                          : "memory");
-    return prev != old_value;
-}
-
-extern ANDROID_ATOMIC_INLINE
-int android_atomic_acquire_cas(int32_t old_value, int32_t new_value,
-                               volatile int32_t *ptr)
-{
-    /* Loads are not reordered with other loads. */
-    return android_atomic_cas(old_value, new_value, ptr);
-}
-
-extern ANDROID_ATOMIC_INLINE
-int android_atomic_release_cas(int32_t old_value, int32_t new_value,
-                               volatile int32_t *ptr)
-{
-    /* Stores are not reordered with other stores. */
-    return android_atomic_cas(old_value, new_value, ptr);
-}
-
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr)
-{
-    __asm__ __volatile__ ("lock; xaddl %0, %1"
-                          : "+r" (increment), "+m" (*ptr)
-                          : : "memory");
-    /* increment now holds the old value of *ptr */
-    return increment;
-}
-
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_inc(volatile int32_t *addr)
-{
-    return android_atomic_add(1, addr);
-}
-
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_dec(volatile int32_t *addr)
-{
-    return android_atomic_add(-1, addr);
-}
-
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_and(int32_t value, volatile int32_t *ptr)
-{
-    int32_t prev, status;
-    do {
-        prev = *ptr;
-        status = android_atomic_cas(prev, prev & value, ptr);
-    } while (__builtin_expect(status != 0, 0));
-    return prev;
-}
-
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_or(int32_t value, volatile int32_t *ptr)
-{
-    int32_t prev, status;
-    do {
-        prev = *ptr;
-        status = android_atomic_cas(prev, prev | value, ptr);
-    } while (__builtin_expect(status != 0, 0));
-    return prev;
-}
-
-#endif /* ANDROID_CUTILS_ATOMIC_X86_64_H */
diff --git a/include/cutils/atomic.h b/include/cutils/atomic.h
index 79409a7..ded972a 100644
--- a/include/cutils/atomic.h
+++ b/include/cutils/atomic.h
@@ -19,9 +19,10 @@
 
 #include <stdint.h>
 #include <sys/types.h>
+#include <stdatomic.h>
 
-#ifdef __cplusplus
-extern "C" {
+#ifndef ANDROID_ATOMIC_INLINE
+#define ANDROID_ATOMIC_INLINE static inline
 #endif
 
 /*
@@ -77,11 +78,41 @@
  * These have the same characteristics (e.g. what happens on overflow)
  * as the equivalent non-atomic C operations.
  */
-int32_t android_atomic_inc(volatile int32_t* addr);
-int32_t android_atomic_dec(volatile int32_t* addr);
-int32_t android_atomic_add(int32_t value, volatile int32_t* addr);
-int32_t android_atomic_and(int32_t value, volatile int32_t* addr);
-int32_t android_atomic_or(int32_t value, volatile int32_t* addr);
+ANDROID_ATOMIC_INLINE
+int32_t android_atomic_inc(volatile int32_t* addr)
+{
+    volatile atomic_int_least32_t* a = (volatile 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);
+}
+
+ANDROID_ATOMIC_INLINE
+int32_t android_atomic_dec(volatile int32_t* addr)
+{
+    volatile atomic_int_least32_t* a = (volatile 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;
+    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;
+    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;
+    return atomic_fetch_or_explicit(a, value, memory_order_release);
+}
 
 /*
  * Perform an atomic load with "acquire" or "release" ordering.
@@ -96,29 +127,53 @@
  * this comment, you are in the vast majority, and should not be
  * using release loads or replacing them with anything other than
  * locks or default sequentially consistent atomics.
- *
- * This is only necessary if you need the memory barrier.  A 32-bit read
- * from a 32-bit aligned address is atomic on all supported platforms.
  */
-int32_t android_atomic_acquire_load(volatile const int32_t* addr);
-int32_t android_atomic_release_load(volatile const int32_t* addr);
+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;
+    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;
+    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         */
+    /* abusing this API in strange ways, e.g. by using it as a fence.   */
+    /* Thus we are conservative until we can get rid of remaining       */
+    /* clients (and this function).                                     */
+    return atomic_load_explicit(a, memory_order_relaxed);
+}
 
 /*
  * Perform an atomic store with "acquire" or "release" ordering.
  *
- * Note that the notion of a "acquire" ordering for a store does not
+ * Note that the notion of an "acquire" ordering for a store does not
  * really fit into the C11 or C++11 memory model.  The extra ordering
  * is normally observable only by code using memory_order_relaxed
  * atomics, or data races.  In the rare cases in which such ordering
  * is called for, use memory_order_relaxed atomics and a trailing
  * atomic_thread_fence (typically with memory_order_release,
  * not memory_order_acquire!) instead.
- *
- * This is only necessary if you need the memory barrier.  A 32-bit write
- * to a 32-bit aligned address is atomic on all supported platforms.
  */
-void android_atomic_acquire_store(int32_t value, volatile int32_t* addr);
-void android_atomic_release_store(int32_t value, volatile int32_t* addr);
+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;
+    atomic_store_explicit(a, value, memory_order_relaxed);
+    atomic_thread_fence(memory_order_seq_cst);
+    /* Again overly conservative to accomodate weird clients.   */
+}
+
+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;
+    atomic_store_explicit(a, value, memory_order_release);
+}
 
 /*
  * Compare-and-set operation with "acquire" or "release" ordering.
@@ -132,10 +187,44 @@
  * Implementations that use the release CAS in a loop may be less efficient
  * than possible, because we re-issue the memory barrier on each iteration.
  */
+ANDROID_ATOMIC_INLINE
 int android_atomic_acquire_cas(int32_t oldvalue, int32_t newvalue,
-        volatile int32_t* addr);
+                           volatile int32_t* addr)
+{
+    volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr;
+    return (int)(!atomic_compare_exchange_strong_explicit(
+                                          a, &oldvalue, newvalue,
+                                          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 int32_t* addr)
+{
+    volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr;
+    return (int)(!atomic_compare_exchange_strong_explicit(
+                                          a, &oldvalue, newvalue,
+                                          memory_order_release,
+                                          memory_order_relaxed));
+}
+
+/*
+ * Fence primitives.
+ */
+ANDROID_ATOMIC_INLINE
+void android_compiler_barrier(void)
+{
+    __asm__ __volatile__ ("" : : : "memory");
+    /* Could probably also be:                          */
+    /* atomic_signal_fence(memory_order_seq_cst);       */
+}
+
+ANDROID_ATOMIC_INLINE
+void android_memory_barrier(void)
+{
+    atomic_thread_fence(memory_order_seq_cst);
+}
 
 /*
  * Aliases for code using an older version of this header.  These are now
@@ -145,8 +234,4 @@
 #define android_atomic_write android_atomic_release_store
 #define android_atomic_cmpxchg android_atomic_release_cas
 
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
 #endif // ANDROID_CUTILS_ATOMIC_H
diff --git a/include/cutils/cpu_info.h b/include/cutils/cpu_info.h
deleted file mode 100644
index 78c1884..0000000
--- a/include/cutils/cpu_info.h
+++ /dev/null
@@ -1,34 +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.
- */
-
-#ifndef __CUTILS_CPU_INFO_H
-#define __CUTILS_CPU_INFO_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* returns a string contiaining an ASCII representation of the CPU serial number, 
-** or NULL if cpu info not available.
-** The string is a static variable, so don't call free() on it.
-*/
-extern const char* get_cpu_serial_number(void);
-    
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __CUTILS_CPU_INFO_H */ 
diff --git a/include/cutils/debugger.h b/include/cutils/debugger.h
index bae687d..285e1af 100644
--- a/include/cutils/debugger.h
+++ b/include/cutils/debugger.h
@@ -17,20 +17,14 @@
 #ifndef __CUTILS_DEBUGGER_H
 #define __CUTILS_DEBUGGER_H
 
+#include <sys/cdefs.h>
 #include <sys/types.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+__BEGIN_DECLS
 
-#define DEBUGGER32_SOCKET_NAME "android:debuggerd"
-#define DEBUGGER64_SOCKET_NAME "android:debuggerd64"
-
-#if defined(__LP64__)
-#define DEBUGGER_SOCKET_NAME DEBUGGER64_SOCKET_NAME
-#else
-#define DEBUGGER_SOCKET_NAME DEBUGGER32_SOCKET_NAME
-#endif
+#define DEBUGGER_SOCKET_NAME "android:debuggerd"
+#define DEBUGGER32_SOCKET_NAME "android:debuggerd32"
+#define DEBUGGER64_SOCKET_NAME DEBUGGER_SOCKET_NAME
 
 typedef enum {
     // dump a crash
@@ -41,23 +35,17 @@
     DEBUGGER_ACTION_DUMP_BACKTRACE,
 } debugger_action_t;
 
-typedef struct {
-    debugger_action_t action;
+// 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;
-    uintptr_t abort_msg_address;
+    uint64_t abort_msg_address;
     int32_t original_si_code;
 } debugger_msg_t;
 
-#if defined(__LP64__)
-// For a 64 bit process to contact the 32 bit debuggerd.
-typedef struct {
-    debugger_action_t action;
-    pid_t tid;
-    uint32_t abort_msg_address;
-    int32_t original_si_code;
-} debugger32_msg_t;
-#endif
-
 /* 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.
@@ -84,8 +72,6 @@
  */
 int dump_backtrace_to_file_timeout(pid_t tid, int fd, int timeout_secs);
 
-#ifdef __cplusplus
-}
-#endif
+__END_DECLS
 
 #endif /* __CUTILS_DEBUGGER_H */
diff --git a/include/cutils/dir_hash.h b/include/cutils/dir_hash.h
deleted file mode 100644
index fbb4d02..0000000
--- a/include/cutils/dir_hash.h
+++ /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.
- */
-
-typedef enum {
-    SHA_1,
-} HashAlgorithm;
-
-int get_file_hash(HashAlgorithm algorithm, const char *path,
-                  char *output_string, size_t max_output_string);
-
-int get_recursive_hash_manifest(HashAlgorithm algorithm,
-                                const char *directory_path,
-                                char **output_string);
diff --git a/include/cutils/klog.h b/include/cutils/klog.h
index d5ae6d7..295d62b 100644
--- a/include/cutils/klog.h
+++ b/include/cutils/klog.h
@@ -18,6 +18,7 @@
 #define _CUTILS_KLOG_H_
 
 #include <sys/cdefs.h>
+#include <sys/uio.h>
 #include <stdarg.h>
 
 __BEGIN_DECLS
@@ -26,9 +27,10 @@
 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)));
-void klog_vwrite(int level, const char *fmt, va_list ap);
+void klog_writev(int level, const struct iovec* iov, int iov_count);
 
 __END_DECLS
 
diff --git a/include/cutils/memory.h b/include/cutils/memory.h
index e725cdd..4d26882 100644
--- a/include/cutils/memory.h
+++ b/include/cutils/memory.h
@@ -30,7 +30,7 @@
 /* size is given in bytes and must be multiple of 4 */
 void android_memset32(uint32_t* dst, uint32_t value, size_t size);
 
-#if !HAVE_STRLCPY
+#if defined(__GLIBC__) || defined(_WIN32)
 /* Declaration of strlcpy() for platforms that don't already have it. */
 size_t strlcpy(char *dst, const char *src, size_t size);
 #endif
diff --git a/include/cutils/open_memstream.h b/include/cutils/open_memstream.h
index b7998be..c1a81eb 100644
--- a/include/cutils/open_memstream.h
+++ b/include/cutils/open_memstream.h
@@ -19,7 +19,7 @@
 
 #include <stdio.h>
 
-#ifndef HAVE_OPEN_MEMSTREAM
+#if defined(__APPLE__)
 
 #ifdef __cplusplus
 extern "C" {
@@ -31,6 +31,6 @@
 }
 #endif
 
-#endif /*!HAVE_OPEN_MEMSTREAM*/
+#endif /* __APPLE__ */
 
 #endif /*__CUTILS_OPEN_MEMSTREAM_H__*/
diff --git a/include/cutils/partition_utils.h b/include/cutils/partition_utils.h
index 597df92..72ca80d 100644
--- a/include/cutils/partition_utils.h
+++ b/include/cutils/partition_utils.h
@@ -20,7 +20,6 @@
 __BEGIN_DECLS
 
 int partition_wiped(char *source);
-void erase_footer(const char *dev_path, long long size);
 
 __END_DECLS
 
diff --git a/include/cutils/properties.h b/include/cutils/properties.h
index 798db8b..24aa224 100644
--- a/include/cutils/properties.h
+++ b/include/cutils/properties.h
@@ -126,22 +126,6 @@
 
 #endif
 
-#ifdef HAVE_SYSTEM_PROPERTY_SERVER
-/*
- * We have an external property server instead of built-in libc support.
- * Used by the simulator.
- */
-#define SYSTEM_PROPERTY_PIPE_NAME       "/tmp/android-sysprop"
-
-enum {
-    kSystemPropertyUnknown = 0,
-    kSystemPropertyGet,
-    kSystemPropertySet,
-    kSystemPropertyList
-};
-#endif /*HAVE_SYSTEM_PROPERTY_SERVER*/
-
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/cutils/sched_policy.h b/include/cutils/sched_policy.h
index ba84ce3..6a8d570 100644
--- a/include/cutils/sched_policy.h
+++ b/include/cutils/sched_policy.h
@@ -34,6 +34,8 @@
     SP_SYSTEM_DEFAULT = SP_FOREGROUND,
 } SchedPolicy;
 
+extern int set_cpuset_policy(int tid, SchedPolicy policy);
+
 /* Assign thread tid to the cgroup associated with the specified policy.
  * If the thread is a thread group leader, that is it's gettid() == getpid(),
  * then the other threads in the same thread group are _not_ affected.
diff --git a/include/cutils/sockets.h b/include/cutils/sockets.h
index daf43ec..f8076ca 100644
--- a/include/cutils/sockets.h
+++ b/include/cutils/sockets.h
@@ -18,6 +18,7 @@
 #define __CUTILS_SOCKETS_H
 
 #include <errno.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdbool.h>
@@ -25,7 +26,7 @@
 #ifdef HAVE_WINSOCK
 #include <winsock2.h>
 typedef int  socklen_t;
-#elif HAVE_SYS_SOCKET_H
+#else
 #include <sys/socket.h>
 #endif
 
@@ -46,30 +47,19 @@
  */
 static inline int android_get_control_socket(const char *name)
 {
-	char key[64] = ANDROID_SOCKET_ENV_PREFIX;
-	const char *val;
-	int fd;
+	char key[64];
+	snprintf(key, sizeof(key), ANDROID_SOCKET_ENV_PREFIX "%s", name);
 
-	/* build our environment variable, counting cycles like a wolf ... */
-#if HAVE_STRLCPY
-	strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
-		name,
-		sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
-#else	/* for the host, which may lack the almightly strncpy ... */
-	strncpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
-		name,
-		sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
-	key[sizeof(key)-1] = '\0';
-#endif
-
-	val = getenv(key);
-	if (!val)
+	const char* val = getenv(key);
+	if (!val) {
 		return -1;
+	}
 
 	errno = 0;
-	fd = strtol(val, NULL, 10);
-	if (errno)
+	int fd = strtol(val, NULL, 10);
+	if (errno) {
 		return -1;
+	}
 
 	return fd;
 }
diff --git a/include/cutils/str_parms.h b/include/cutils/str_parms.h
index 66f3637..aa1435a 100644
--- a/include/cutils/str_parms.h
+++ b/include/cutils/str_parms.h
@@ -18,6 +18,9 @@
 #define __CUTILS_STR_PARMS_H
 
 #include <stdint.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
 
 struct str_parms;
 
@@ -52,4 +55,6 @@
 /* debug */
 void str_parms_dump(struct str_parms *str_parms);
 
+__END_DECLS
+
 #endif /* __CUTILS_STR_PARMS_H */
diff --git a/include/cutils/threads.h b/include/cutils/threads.h
index acf8f48..5727494 100644
--- a/include/cutils/threads.h
+++ b/include/cutils/threads.h
@@ -17,6 +17,14 @@
 #ifndef _LIBS_CUTILS_THREADS_H
 #define _LIBS_CUTILS_THREADS_H
 
+#include  <sys/types.h>
+
+#if !defined(_WIN32)
+#include <pthread.h>
+#else
+#include <windows.h>
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -29,42 +37,36 @@
 /***********************************************************************/
 /***********************************************************************/
 
-#ifdef HAVE_PTHREADS
+extern pid_t gettid();
 
-#include  <pthread.h>
+#if !defined(_WIN32)
 
 typedef struct {
     pthread_mutex_t   lock;
     int               has_tls;
     pthread_key_t     tls;
-
 } thread_store_t;
 
 #define  THREAD_STORE_INITIALIZER  { PTHREAD_MUTEX_INITIALIZER, 0, 0 }
 
-#elif defined HAVE_WIN32_THREADS
-
-#include <windows.h>
+#else // !defined(_WIN32)
 
 typedef struct {
     int               lock_init;
     int               has_tls;
     DWORD             tls;
     CRITICAL_SECTION  lock;
-
 } thread_store_t;
 
 #define  THREAD_STORE_INITIALIZER  { 0, 0, 0, {0, 0, 0, 0, 0, 0} }
 
-#else
-#  error  "no thread_store_t implementation for your platform !!"
-#endif
+#endif // !defined(_WIN32)
 
 typedef void  (*thread_store_destruct_t)(void*  value);
 
 extern void*  thread_store_get(thread_store_t*  store);
 
-extern void   thread_store_set(thread_store_t*          store, 
+extern void   thread_store_set(thread_store_t*          store,
                                void*                    value,
                                thread_store_destruct_t  destroy);
 
@@ -76,7 +78,7 @@
 /***********************************************************************/
 /***********************************************************************/
 
-#ifdef HAVE_PTHREADS
+#if !defined(_WIN32)
 
 typedef pthread_mutex_t   mutex_t;
 
@@ -98,10 +100,10 @@
 {
     pthread_mutex_destroy(lock);
 }
-#endif
 
-#ifdef HAVE_WIN32_THREADS
-typedef struct { 
+#else // !defined(_WIN32)
+
+typedef struct {
     int                init;
     CRITICAL_SECTION   lock[1];
 } mutex_t;
@@ -134,10 +136,10 @@
 {
     if (lock->init) {
         lock->init = 0;
-        DeleteCriticalSection(lock->lock); 
+        DeleteCriticalSection(lock->lock);
     }
 }
-#endif
+#endif // !defined(_WIN32)
 
 #ifdef __cplusplus
 }
diff --git a/include/cutils/trace.h b/include/cutils/trace.h
index fd24561..e4ed179 100644
--- a/include/cutils/trace.h
+++ b/include/cutils/trace.h
@@ -18,6 +18,7 @@
 #define _LIBS_CUTILS_TRACE_H
 
 #include <inttypes.h>
+#include <stdatomic.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -26,11 +27,6 @@
 #include <unistd.h>
 
 #include <cutils/compiler.h>
-#ifdef ANDROID_SMP
-#include <cutils/atomic-inline.h>
-#else
-#include <cutils/atomic.h>
-#endif
 
 __BEGIN_DECLS
 
@@ -84,14 +80,6 @@
 #error ATRACE_TAG must be defined to be one of the tags defined in cutils/trace.h
 #endif
 
-#ifdef HAVE_ANDROID_OS
-/**
- * Maximum size of a message that can be logged to the trace buffer.
- * Note this message includes a tag, the pid, and the string given as the name.
- * Names should be kept short to get the most use of the trace buffer.
- */
-#define ATRACE_MESSAGE_LENGTH 1024
-
 /**
  * Opens the trace file for writing and reads the property for initial tags.
  * The atrace.tags.enableflags property sets the tags to trace.
@@ -125,7 +113,7 @@
  * Nonzero indicates setup has completed.
  * Note: This does NOT indicate whether or not setup was successful.
  */
-extern volatile int32_t atrace_is_ready;
+extern atomic_bool atrace_is_ready;
 
 /**
  * Set of ATRACE_TAG flags to trace for, initialized to ATRACE_TAG_NOT_READY.
@@ -148,7 +136,7 @@
 #define ATRACE_INIT() atrace_init()
 static inline void atrace_init()
 {
-    if (CC_UNLIKELY(!android_atomic_acquire_load(&atrace_is_ready))) {
+    if (CC_UNLIKELY(!atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) {
         atrace_setup();
     }
 }
@@ -184,11 +172,8 @@
 static inline void atrace_begin(uint64_t tag, const char* name)
 {
     if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
-        char buf[ATRACE_MESSAGE_LENGTH];
-        size_t len;
-
-        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "B|%d|%s", getpid(), name);
-        write(atrace_marker_fd, buf, len);
+        void atrace_begin_body(const char*);
+        atrace_begin_body(name);
     }
 }
 
@@ -218,12 +203,8 @@
         int32_t cookie)
 {
     if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
-        char buf[ATRACE_MESSAGE_LENGTH];
-        size_t len;
-
-        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "S|%d|%s|%" PRId32,
-                getpid(), name, cookie);
-        write(atrace_marker_fd, buf, len);
+        void atrace_async_begin_body(const char*, int32_t);
+        atrace_async_begin_body(name, cookie);
     }
 }
 
@@ -232,20 +213,14 @@
  * This should have a corresponding ATRACE_ASYNC_BEGIN.
  */
 #define ATRACE_ASYNC_END(name, cookie) atrace_async_end(ATRACE_TAG, name, cookie)
-static inline void atrace_async_end(uint64_t tag, const char* name,
-        int32_t cookie)
+static inline void atrace_async_end(uint64_t tag, const char* name, int32_t cookie)
 {
     if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
-        char buf[ATRACE_MESSAGE_LENGTH];
-        size_t len;
-
-        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "F|%d|%s|%" PRId32,
-                getpid(), name, cookie);
-        write(atrace_marker_fd, buf, len);
+        void atrace_async_end_body(const char*, int32_t);
+        atrace_async_end_body(name, cookie);
     }
 }
 
-
 /**
  * Traces an integer counter value.  name is used to identify the counter.
  * This can be used to track how a value changes over time.
@@ -254,12 +229,8 @@
 static inline void atrace_int(uint64_t tag, const char* name, int32_t value)
 {
     if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
-        char buf[ATRACE_MESSAGE_LENGTH];
-        size_t len;
-
-        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%" PRId32,
-                getpid(), name, value);
-        write(atrace_marker_fd, buf, len);
+        void atrace_int_body(const char*, int32_t);
+        atrace_int_body(name, value);
     }
 }
 
@@ -271,28 +242,11 @@
 static inline void atrace_int64(uint64_t tag, const char* name, int64_t value)
 {
     if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
-        char buf[ATRACE_MESSAGE_LENGTH];
-        size_t len;
-
-        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%" PRId64,
-                getpid(), name, value);
-        write(atrace_marker_fd, buf, len);
+        void atrace_int64_body(const char*, int64_t);
+        atrace_int64_body(name, value);
     }
 }
 
-#else // not HAVE_ANDROID_OS
-
-#define ATRACE_INIT()
-#define ATRACE_GET_ENABLED_TAGS()
-#define ATRACE_ENABLED() 0
-#define ATRACE_BEGIN(name)
-#define ATRACE_END()
-#define ATRACE_ASYNC_BEGIN(name, cookie)
-#define ATRACE_ASYNC_END(name, cookie)
-#define ATRACE_INT(name, value)
-
-#endif // not HAVE_ANDROID_OS
-
 __END_DECLS
 
 #endif // _LIBS_CUTILS_TRACE_H
diff --git a/include/cutils/uevent.h b/include/cutils/uevent.h
index 4cca7e5..da1c2aa 100644
--- a/include/cutils/uevent.h
+++ b/include/cutils/uevent.h
@@ -27,6 +27,7 @@
 int uevent_open_socket(int buf_sz, bool passcred);
 ssize_t uevent_kernel_multicast_recv(int socket, void *buffer, size_t length);
 ssize_t uevent_kernel_multicast_uid_recv(int socket, void *buffer, size_t length, uid_t *uid);
+ssize_t uevent_kernel_recv(int socket, void *buffer, size_t length, bool require_group, uid_t *uid);
 
 #ifdef __cplusplus
 }
diff --git a/include/log/log.h b/include/log/log.h
index e3b7ec1..1cdf7bc 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -28,14 +28,12 @@
 #ifndef _LIBS_LOG_LOG_H
 #define _LIBS_LOG_LOG_H
 
-#include <sys/types.h>
-#ifdef HAVE_PTHREADS
-#include <pthread.h>
-#endif
 #include <stdarg.h>
 #include <stdio.h>
+#include <sys/types.h>
 #include <time.h>
 #include <unistd.h>
+
 #include <log/logd.h>
 #include <log/uio.h>
 
@@ -69,6 +67,23 @@
 
 // ---------------------------------------------------------------------
 
+#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.
+ */
+#ifndef LINT_RLOG
+
 /*
  * Simplified macro to send a verbose log message using the current LOG_TAG.
  */
@@ -81,14 +96,12 @@
 #endif
 #endif
 
-#define CONDITION(cond)     (__builtin_expect((cond)!=0, 0))
-
 #ifndef ALOGV_IF
 #if LOG_NDEBUG
 #define ALOGV_IF(cond, ...)   ((void)0)
 #else
 #define ALOGV_IF(cond, ...) \
-    ( (CONDITION(cond)) \
+    ( (__predict_false(cond)) \
     ? ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
     : (void)0 )
 #endif
@@ -103,7 +116,7 @@
 
 #ifndef ALOGD_IF
 #define ALOGD_IF(cond, ...) \
-    ( (CONDITION(cond)) \
+    ( (__predict_false(cond)) \
     ? ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
     : (void)0 )
 #endif
@@ -117,7 +130,7 @@
 
 #ifndef ALOGI_IF
 #define ALOGI_IF(cond, ...) \
-    ( (CONDITION(cond)) \
+    ( (__predict_false(cond)) \
     ? ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \
     : (void)0 )
 #endif
@@ -131,7 +144,7 @@
 
 #ifndef ALOGW_IF
 #define ALOGW_IF(cond, ...) \
-    ( (CONDITION(cond)) \
+    ( (__predict_false(cond)) \
     ? ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \
     : (void)0 )
 #endif
@@ -145,7 +158,7 @@
 
 #ifndef ALOGE_IF
 #define ALOGE_IF(cond, ...) \
-    ( (CONDITION(cond)) \
+    ( (__predict_false(cond)) \
     ? ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
     : (void)0 )
 #endif
@@ -203,7 +216,8 @@
  * Simplified macro to send a verbose system log message using the current LOG_TAG.
  */
 #ifndef SLOGV
-#define __SLOGV(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#define __SLOGV(...) \
+    ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
 #if LOG_NDEBUG
 #define SLOGV(...) do { if (0) { __SLOGV(__VA_ARGS__); } } while (0)
 #else
@@ -211,14 +225,12 @@
 #endif
 #endif
 
-#define CONDITION(cond)     (__builtin_expect((cond)!=0, 0))
-
 #ifndef SLOGV_IF
 #if LOG_NDEBUG
 #define SLOGV_IF(cond, ...)   ((void)0)
 #else
 #define SLOGV_IF(cond, ...) \
-    ( (CONDITION(cond)) \
+    ( (__predict_false(cond)) \
     ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
     : (void)0 )
 #endif
@@ -228,12 +240,13 @@
  * Simplified macro to send a debug system log message using the current LOG_TAG.
  */
 #ifndef SLOGD
-#define SLOGD(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
+#define SLOGD(...) \
+    ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
 #endif
 
 #ifndef SLOGD_IF
 #define SLOGD_IF(cond, ...) \
-    ( (CONDITION(cond)) \
+    ( (__predict_false(cond)) \
     ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
     : (void)0 )
 #endif
@@ -242,12 +255,13 @@
  * Simplified macro to send an info system log message using the current LOG_TAG.
  */
 #ifndef SLOGI
-#define SLOGI(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
+#define SLOGI(...) \
+    ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
 #endif
 
 #ifndef SLOGI_IF
 #define SLOGI_IF(cond, ...) \
-    ( (CONDITION(cond)) \
+    ( (__predict_false(cond)) \
     ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
     : (void)0 )
 #endif
@@ -256,12 +270,13 @@
  * Simplified macro to send a warning system log message using the current LOG_TAG.
  */
 #ifndef SLOGW
-#define SLOGW(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
+#define SLOGW(...) \
+    ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
 #endif
 
 #ifndef SLOGW_IF
 #define SLOGW_IF(cond, ...) \
-    ( (CONDITION(cond)) \
+    ( (__predict_false(cond)) \
     ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
     : (void)0 )
 #endif
@@ -270,23 +285,27 @@
  * Simplified macro to send an error system log message using the current LOG_TAG.
  */
 #ifndef SLOGE
-#define SLOGE(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
+#define SLOGE(...) \
+    ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
 #endif
 
 #ifndef SLOGE_IF
 #define SLOGE_IF(cond, ...) \
-    ( (CONDITION(cond)) \
+    ( (__predict_false(cond)) \
     ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
     : (void)0 )
 #endif
 
+#endif /* !LINT_RLOG */
+
 // ---------------------------------------------------------------------
 
 /*
  * Simplified macro to send a verbose radio log message using the current LOG_TAG.
  */
 #ifndef RLOGV
-#define __RLOGV(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#define __RLOGV(...) \
+    ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
 #if LOG_NDEBUG
 #define RLOGV(...) do { if (0) { __RLOGV(__VA_ARGS__); } } while (0)
 #else
@@ -294,14 +313,12 @@
 #endif
 #endif
 
-#define CONDITION(cond)     (__builtin_expect((cond)!=0, 0))
-
 #ifndef RLOGV_IF
 #if LOG_NDEBUG
 #define RLOGV_IF(cond, ...)   ((void)0)
 #else
 #define RLOGV_IF(cond, ...) \
-    ( (CONDITION(cond)) \
+    ( (__predict_false(cond)) \
     ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
     : (void)0 )
 #endif
@@ -311,12 +328,13 @@
  * Simplified macro to send a debug radio log message using the current LOG_TAG.
  */
 #ifndef RLOGD
-#define RLOGD(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
+#define RLOGD(...) \
+    ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
 #endif
 
 #ifndef RLOGD_IF
 #define RLOGD_IF(cond, ...) \
-    ( (CONDITION(cond)) \
+    ( (__predict_false(cond)) \
     ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
     : (void)0 )
 #endif
@@ -325,12 +343,13 @@
  * Simplified macro to send an info radio log message using the current LOG_TAG.
  */
 #ifndef RLOGI
-#define RLOGI(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
+#define RLOGI(...) \
+    ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
 #endif
 
 #ifndef RLOGI_IF
 #define RLOGI_IF(cond, ...) \
-    ( (CONDITION(cond)) \
+    ( (__predict_false(cond)) \
     ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
     : (void)0 )
 #endif
@@ -339,12 +358,13 @@
  * Simplified macro to send a warning radio log message using the current LOG_TAG.
  */
 #ifndef RLOGW
-#define RLOGW(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
+#define RLOGW(...) \
+    ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
 #endif
 
 #ifndef RLOGW_IF
 #define RLOGW_IF(cond, ...) \
-    ( (CONDITION(cond)) \
+    ( (__predict_false(cond)) \
     ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
     : (void)0 )
 #endif
@@ -353,12 +373,13 @@
  * Simplified macro to send an error radio log message using the current LOG_TAG.
  */
 #ifndef RLOGE
-#define RLOGE(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
+#define RLOGE(...) \
+    ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
 #endif
 
 #ifndef RLOGE_IF
 #define RLOGE_IF(cond, ...) \
-    ( (CONDITION(cond)) \
+    ( (__predict_false(cond)) \
     ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
     : (void)0 )
 #endif
@@ -374,7 +395,7 @@
  */
 #ifndef LOG_ALWAYS_FATAL_IF
 #define LOG_ALWAYS_FATAL_IF(cond, ...) \
-    ( (CONDITION(cond)) \
+    ( (__predict_false(cond)) \
     ? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \
     : (void)0 )
 #endif
@@ -471,6 +492,7 @@
     EVENT_TYPE_LONG     = 1,
     EVENT_TYPE_STRING   = 2,
     EVENT_TYPE_LIST     = 3,
+    EVENT_TYPE_FLOAT    = 4,
 } AndroidEventLogType;
 #define sizeof_AndroidEventLogType sizeof(typeof_AndroidEventLogType)
 #define typeof_AndroidEventLogType unsigned char
@@ -489,6 +511,13 @@
             sizeof(longBuf));                                               \
     }
 #endif
+#ifndef LOG_EVENT_FLOAT
+#define LOG_EVENT_FLOAT(_tag, _value) {                                     \
+        float floatBuf = _value;                                            \
+        (void) android_btWriteLog(_tag, EVENT_TYPE_FLOAT, &floatBuf,        \
+            sizeof(floatBuf));                                              \
+    }
+#endif
 #ifndef LOG_EVENT_STRING
 #define LOG_EVENT_STRING(_tag, _value)                                      \
         (void) __android_log_bswrite(_tag, _value);
@@ -540,8 +569,23 @@
 #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)
+#else
+#define android_testLog(prio, tag) \
+    (__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE) != 0)
+#endif
+
 // TODO: remove these prototypes and their users
-#define android_testLog(prio, tag) (1)
 #define android_writevLog(vec,num) do{}while(0)
 #define android_write1Log(str,len) do{}while (0)
 #define android_setMinPriority(tag, prio) do{}while(0)
@@ -552,17 +596,28 @@
 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_KERNEL = 5,
+#endif
 
     LOG_ID_MAX
 } log_id_t;
 #define sizeof_log_id_t sizeof(typeof_log_id_t)
 #define typeof_log_id_t unsigned char
 
+/*
+ * Use the per-tag properties "log.tag.<tagname>" to generate a runtime
+ * result of non-zero to expose a log.
+ */
+int __android_log_is_loggable(int prio, const char *tag, int def);
+
 int __android_log_error_write(int tag, const char *subTag, int32_t uid, const char *data,
                               uint32_t dataLen);
 
diff --git a/include/log/log_read.h b/include/log/log_read.h
index 946711a..1b70aff 100644
--- a/include/log/log_read.h
+++ b/include/log/log_read.h
@@ -100,6 +100,12 @@
         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
@@ -134,6 +140,12 @@
         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
     {
diff --git a/include/log/logd.h b/include/log/logd.h
index 2e6f220..0fe515f 100644
--- a/include/log/logd.h
+++ b/include/log/logd.h
@@ -23,16 +23,17 @@
 #include <android/log.h>
 
 /* the rest is only used internally by the system */
-#include <time.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <sys/types.h>
-#ifdef HAVE_PTHREADS
+#if !defined(_WIN32)
 #include <pthread.h>
 #endif
-#include <log/uio.h>
 #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" {
diff --git a/include/log/logger.h b/include/log/logger.h
index 53be1d3..f030dab 100644
--- a/include/log/logger.h
+++ b/include/log/logger.h
@@ -154,6 +154,13 @@
 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_PSTORE   0x80000000
+
 struct logger_list *android_logger_list_alloc(int mode,
                                               unsigned int tail,
                                               pid_t pid);
diff --git a/include/log/logprint.h b/include/log/logprint.h
index 481c96e..4b812cc 100644
--- a/include/log/logprint.h
+++ b/include/log/logprint.h
@@ -36,6 +36,10 @@
     FORMAT_TIME,
     FORMAT_THREADTIME,
     FORMAT_LONG,
+    /* The following three are modifiers to above formats */
+    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 */
 } AndroidLogPrintFormat;
 
 typedef struct AndroidLogFormat_t AndroidLogFormat;
@@ -55,7 +59,8 @@
 
 void android_log_format_free(AndroidLogFormat *p_format);
 
-void android_log_setPrintFormat(AndroidLogFormat *p_format, 
+/* currently returns 0 if format is a modifier, 1 if not */
+int android_log_setPrintFormat(AndroidLogFormat *p_format,
         AndroidLogPrintFormat format);
 
 /**
@@ -63,7 +68,7 @@
  */
 AndroidLogPrintFormat android_log_formatFromString(const char *s);
 
-/** 
+/**
  * filterExpression: a single filter expression
  * eg "AT:d"
  *
@@ -73,12 +78,12 @@
  *
  */
 
-int android_log_addFilterRule(AndroidLogFormat *p_format, 
+int android_log_addFilterRule(AndroidLogFormat *p_format,
         const char *filterExpression);
 
 
-/** 
- * filterString: a whitespace-separated set of filter expressions 
+/**
+ * filterString: a whitespace-separated set of filter expressions
  * eg "AT:d *:i"
  *
  * returns 0 on success and -1 on invalid expression
@@ -91,7 +96,7 @@
         const char *filterString);
 
 
-/** 
+/**
  * returns 1 if this log line should be printed based on its priority
  * and tag, and 0 if it should not
  */
@@ -128,7 +133,7 @@
  * Returns NULL on malloc error
  */
 
-char *android_log_formatLogLine (    
+char *android_log_formatLogLine (
     AndroidLogFormat *p_format,
     char *defaultBuffer,
     size_t defaultBufferSize,
diff --git a/include/log/uio.h b/include/log/uio.h
index a71f515..7059da5 100644
--- a/include/log/uio.h
+++ b/include/log/uio.h
@@ -14,20 +14,23 @@
  * limitations under the License.
  */
 
-//
-// implementation of sys/uio.h for platforms that don't have it (Win32)
-//
 #ifndef _LIBS_CUTILS_UIO_H
 #define _LIBS_CUTILS_UIO_H
 
-#ifdef HAVE_SYS_UIO_H
+#if !defined(_WIN32)
+
 #include <sys/uio.h>
+
 #else
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+//
+// Implementation of sys/uio.h for Win32.
+//
+
 #include <stddef.h>
 
 struct iovec {
@@ -42,7 +45,7 @@
 }
 #endif
 
-#endif /* !HAVE_SYS_UIO_H */
+#endif
 
 #endif /* _LIBS_UTILS_UIO_H */
 
diff --git a/include/memtrack/memtrack.h b/include/memtrack/memtrack.h
index 0f1f85e..3917300 100644
--- a/include/memtrack/memtrack.h
+++ b/include/memtrack/memtrack.h
@@ -121,7 +121,7 @@
 ssize_t memtrack_proc_gl_pss(struct memtrack_proc *p);
 
 /**
- * memtrack_proc_gl_total
+ * memtrack_proc_other_total
  *
  * Same as memtrack_proc_graphics_total, but counts miscellaneous memory
  * not tracked by gl or graphics calls above.
@@ -131,7 +131,7 @@
 ssize_t memtrack_proc_other_total(struct memtrack_proc *p);
 
 /**
- * memtrack_proc_gl_pss
+ * memtrack_proc_other_pss
  *
  * Same as memtrack_proc_graphics_total, but counts miscellaneous memory
  * not tracked by gl or graphics calls above.
diff --git a/include/nativebridge/native_bridge.h b/include/nativebridge/native_bridge.h
index 523dc49..18300bc 100644
--- a/include/nativebridge/native_bridge.h
+++ b/include/nativebridge/native_bridge.h
@@ -18,6 +18,7 @@
 #define NATIVE_BRIDGE_H_
 
 #include "jni.h"
+#include <signal.h>
 #include <stdint.h>
 #include <sys/types.h>
 
@@ -26,6 +27,12 @@
 struct NativeBridgeRuntimeCallbacks;
 struct NativeBridgeRuntimeValues;
 
+// Function pointer type for sigaction. This is mostly the signature of a signal handler, except
+// for the return type. The runtime needs to know whether the signal was handled or should be given
+// to the chain.
+typedef bool (*NativeBridgeSignalHandlerFn)(int, siginfo_t*, void*);
+
+
 // Open the native bridge, if any. Should be called by Runtime::Init(). A null library filename
 // signals that we do not want to load a native bridge.
 bool LoadNativeBridge(const char* native_bridge_library_filename,
@@ -63,6 +70,16 @@
 // True if native library is valid and is for an ABI that is supported by native bridge.
 bool NativeBridgeIsSupported(const char* libpath);
 
+// Returns the version number of the native bridge. This information is available after a
+// successful LoadNativeBridge() and before closing it, that is, as long as NativeBridgeAvailable()
+// returns true. Returns 0 otherwise.
+uint32_t NativeBridgeGetVersion();
+
+// Returns a signal handler that the bridge would like to be managed. Only valid for a native
+// bridge supporting the version 2 interface. Will return null if the bridge does not support
+// version 2, or if it doesn't have a signal handler it wants to be known.
+NativeBridgeSignalHandlerFn NativeBridgeGetSignalHandler(int signal);
+
 // Returns whether we have seen a native bridge error. This could happen because the library
 // was not found, rejected, could not be initialized and so on.
 //
@@ -127,6 +144,31 @@
   //    NULL if not supported by native bridge.
   //    Otherwise, return all environment values to be set after fork.
   const struct NativeBridgeRuntimeValues* (*getAppEnv)(const char* instruction_set);
+
+  // Added callbacks in version 2.
+
+  // Check whether the bridge is compatible with the given version. A bridge may decide not to be
+  // forwards- or backwards-compatible, and libnativebridge will then stop using it.
+  //
+  // Parameters:
+  //     bridge_version [IN] the version of libnativebridge.
+  // Returns:
+  //     true iff the native bridge supports the given version of libnativebridge.
+  bool (*isCompatibleWith)(uint32_t bridge_version);
+
+  // A callback to retrieve a native bridge's signal handler for the specified signal. The runtime
+  // will ensure that the signal handler is being called after the runtime's own handler, but before
+  // all chained handlers. The native bridge should not try to install the handler by itself, as
+  // that will potentially lead to cycles.
+  //
+  // Parameters:
+  //     signal [IN] the signal for which the handler is asked for. Currently, only SIGSEGV is
+  //                 supported by the runtime.
+  // Returns:
+  //     NULL if the native bridge doesn't use a handler or doesn't want it to be managed by the
+  //     runtime.
+  //     Otherwise, a pointer to the signal handler.
+  NativeBridgeSignalHandlerFn (*getSignalHandler)(int signal);
 };
 
 // Runtime interfaces to native bridge.
diff --git a/include/netutils/dhcp.h b/include/netutils/dhcp.h
index de6bc82..008dbd8 100644
--- a/include/netutils/dhcp.h
+++ b/include/netutils/dhcp.h
@@ -23,26 +23,18 @@
 __BEGIN_DECLS
 
 extern int do_dhcp(char *iname);
-extern int dhcp_do_request(const char *ifname,
-                          char *ipaddr,
-                          char *gateway,
-                          uint32_t *prefixLength,
-                          char *dns[],
-                          char *server,
-                          uint32_t *lease,
-                          char *vendorInfo,
-                          char *domain,
-                          char *mtu);
-extern int dhcp_do_request_renew(const char *ifname,
-                                char *ipaddr,
-                                char *gateway,
-                                uint32_t *prefixLength,
-                                char *dns[],
-                                char *server,
-                                uint32_t *lease,
-                                char *vendorInfo,
-                                char *domain,
-                                char *mtu);
+extern int dhcp_start(const char *ifname);
+extern int dhcp_start_renew(const char *ifname);
+extern int dhcp_get_results(const char *ifname,
+                            char *ipaddr,
+                            char *gateway,
+                            uint32_t *prefixLength,
+                            char *dns[],
+                            char *server,
+                            uint32_t *lease,
+                            char *vendorInfo,
+                            char *domain,
+                            char *mtu);
 extern int dhcp_stop(const char *ifname);
 extern int dhcp_release_lease(const char *ifname);
 extern char *dhcp_get_errmsg();
diff --git a/include/private/android_filesystem_capability.h b/include/private/android_filesystem_capability.h
index 0505cda..b92d3db 100644
--- a/include/private/android_filesystem_capability.h
+++ b/include/private/android_filesystem_capability.h
@@ -105,7 +105,9 @@
 #define CAP_MAC_ADMIN 33
 #define CAP_SYSLOG 34
 #define CAP_WAKE_ALARM 35
-#define CAP_LAST_CAP CAP_WAKE_ALARM
+#define CAP_BLOCK_SUSPEND 36
+#define CAP_AUDIT_READ 37
+#define CAP_LAST_CAP CAP_AUDIT_READ
 #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
 #define CAP_TO_INDEX(x) ((x) >> 5)
 #define CAP_TO_MASK(x) (1 << ((x) & 31))
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 2f528b9..2ed27dc 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -22,8 +22,7 @@
 #ifndef _ANDROID_FILESYSTEM_CONFIG_H_
 #define _ANDROID_FILESYSTEM_CONFIG_H_
 
-#include <string.h>
-#include <sys/stat.h>
+#include <sys/cdefs.h>
 #include <sys/types.h>
 #include <stdint.h>
 
@@ -83,6 +82,11 @@
 #define AID_CACHE         2001  /* cache access */
 #define AID_DIAG          2002  /* access to diagnostic resources */
 
+/* The range 2900-2999 is reserved for OEM, and must never be
+ * used here */
+#define AID_OEM_RESERVED_START 2900
+#define AID_OEM_RESERVED_END   2999
+
 /* The 3000 series are intended for use as supplemental group id's only.
  * They indicate special Android capabilities that the kernel is aware of. */
 #define AID_NET_BT_ADMIN  3001  /* bluetooth: create any socket */
@@ -109,6 +113,14 @@
 #define AID_SHARED_GID_END   59999 /* start of gids for apps in each user to share */
 
 #if !defined(EXCLUDE_FS_CONFIG_STRUCTURES)
+/*
+ * Used in:
+ *  bionic/libc/bionic/stubs.cpp
+ *  external/libselinux/src/android.c
+ *  system/core/logd/LogStatistics.cpp
+ *  system/core/init/ueventd.cpp
+ *  system/core/init/util.cpp
+ */
 struct android_id_info {
     const char *name;
     unsigned aid;
@@ -186,124 +198,26 @@
     const char *prefix;
 };
 
-/* Rules for directories.
-** These rules are applied based on "first match", so they
-** should start with the most specific path and work their
-** way up to the root.
-*/
+/* Rules for directories and files has moved to system/code/libcutils/fs_config.c */
 
-static const struct fs_path_config android_dirs[] = {
-    { 00770, AID_SYSTEM, AID_CACHE,  0, "cache" },
-    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" },
-    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" },
-    { 00771, AID_ROOT,   AID_ROOT,   0, "data/dalvik-cache" },
-    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" },
-    { 00771, AID_SHELL,  AID_SHELL,  0, "data/local/tmp" },
-    { 00771, AID_SHELL,  AID_SHELL,  0, "data/local" },
-    { 01771, AID_SYSTEM, AID_MISC,   0, "data/misc" },
-    { 00770, AID_DHCP,   AID_DHCP,   0, "data/misc/dhcp" },
-    { 00771, AID_SHARED_RELRO, AID_SHARED_RELRO, 0, "data/misc/shared_relro" },
-    { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media" },
-    { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" },
-    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" },
-    { 00750, AID_ROOT,   AID_SHELL,  0, "sbin" },
-    { 00755, AID_ROOT,   AID_SHELL,  0, "system/bin" },
-    { 00755, AID_ROOT,   AID_SHELL,  0, "system/vendor" },
-    { 00755, AID_ROOT,   AID_SHELL,  0, "system/xbin" },
-    { 00755, AID_ROOT,   AID_ROOT,   0, "system/etc/ppp" },
-    { 00755, AID_ROOT,   AID_SHELL,  0, "vendor" },
-    { 00777, AID_ROOT,   AID_ROOT,   0, "sdcard" },
-    { 00755, AID_ROOT,   AID_ROOT,   0, 0 },
-};
+__BEGIN_DECLS
 
-/* Rules for files.
-** These rules are applied based on "first match", so they
-** should start with the most specific path and work their
-** way up to the root. Prefixes ending in * denotes wildcard
-** and will allow partial matches.
-*/
-static const struct fs_path_config android_files[] = {
-    { 00440, AID_ROOT,      AID_SHELL,     0, "system/etc/init.goldfish.rc" },
-    { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.goldfish.sh" },
-    { 00440, AID_ROOT,      AID_SHELL,     0, "system/etc/init.trout.rc" },
-    { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.ril" },
-    { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.testmenu" },
-    { 00550, AID_DHCP,      AID_SHELL,     0, "system/etc/dhcpcd/dhcpcd-run-hooks" },
-    { 00444, AID_RADIO,     AID_AUDIO,     0, "system/etc/AudioPara4.csv" },
-    { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/ppp/*" },
-    { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/rc.*" },
-    { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app/*" },
-    { 00644, AID_MEDIA_RW,  AID_MEDIA_RW,  0, "data/media/*" },
-    { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app-private/*" },
-    { 00644, AID_APP,       AID_APP,       0, "data/data/*" },
-    { 00755, AID_ROOT,      AID_ROOT,      0, "system/bin/ping" },
+/*
+ * Used in:
+ *  build/tools/fs_config/fs_config.c
+ *  build/tools/fs_get_stats/fs_get_stats.c
+ *  system/extras/ext4_utils/make_ext4fs_main.c
+ *  external/squashfs-tools/squashfs-tools/android.c
+ *  system/core/cpio/mkbootfs.c
+ *  system/core/adb/file_sync_service.cpp
+ *  system/extras/ext4_utils/canned_fs_config.c
+ */
+void fs_config(const char *path, int dir, const char *target_out_path,
+               unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities);
 
-    /* the following file is INTENTIONALLY set-gid and not set-uid.
-     * Do not change. */
-    { 02750, AID_ROOT,      AID_INET,      0, "system/bin/netcfg" },
+ssize_t fs_config_generate(char *buffer, size_t length, const struct fs_path_config *pc);
 
-    /* the following five files are INTENTIONALLY set-uid, but they
-     * are NOT included on user builds. */
-    { 04750, AID_ROOT,      AID_SHELL,     0, "system/xbin/su" },
-    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/librank" },
-    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procrank" },
-    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procmem" },
-    { 04770, AID_ROOT,      AID_RADIO,     0, "system/bin/pppd-ril" },
+__END_DECLS
 
-    /* the following files have enhanced capabilities and ARE included in user builds. */
-    { 00750, AID_ROOT,      AID_SHELL,     (1 << CAP_SETUID) | (1 << CAP_SETGID), "system/bin/run-as" },
-
-    { 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/*" },
-    { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib/valgrind/*" },
-    { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib64/valgrind/*" },
-    { 00755, AID_ROOT,      AID_SHELL,     0, "system/xbin/*" },
-    { 00755, AID_ROOT,      AID_SHELL,     0, "system/vendor/bin/*" },
-    { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/bin/*" },
-    { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/*" },
-    { 00755, AID_ROOT,      AID_ROOT,      0, "bin/*" },
-    { 00750, AID_ROOT,      AID_SHELL,     0, "init*" },
-    { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/fs_mgr" },
-    { 00640, AID_ROOT,      AID_SHELL,     0, "fstab.*" },
-    { 00644, AID_ROOT,      AID_ROOT,      0, 0 },
-};
-
-static inline void fs_config(const char *path, int dir,
-                             unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities)
-{
-    const struct fs_path_config *pc;
-    int plen;
-
-    if (path[0] == '/') {
-        path++;
-    }
-
-    pc = dir ? android_dirs : android_files;
-    plen = strlen(path);
-    for(; pc->prefix; pc++){
-        int len = strlen(pc->prefix);
-        if (dir) {
-            if(plen < len) continue;
-            if(!strncmp(pc->prefix, path, len)) break;
-            continue;
-        }
-        /* If name ends in * then allow partial matches. */
-        if (pc->prefix[len -1] == '*') {
-            if(!strncmp(pc->prefix, path, len - 1)) break;
-        } else if (plen == len){
-            if(!strncmp(pc->prefix, path, len)) break;
-        }
-    }
-    *uid = pc->uid;
-    *gid = pc->gid;
-    *mode = (*mode & (~07777)) | pc->mode;
-    *capabilities = pc->capabilities;
-
-#if 0
-    fprintf(stderr,"< '%s' '%s' %d %d %o >\n",
-            path, pc->prefix ? pc->prefix : "", *uid, *gid, *mode);
-#endif
-}
 #endif
 #endif
diff --git a/include/private/android_logger.h b/include/private/android_logger.h
new file mode 100644
index 0000000..04238a6
--- /dev/null
+++ b/include/private/android_logger.h
@@ -0,0 +1,98 @@
+/*
+ * 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 is used to define the internal protocol for the Android Logger */
+
+#ifndef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
+#define _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
+
+#include <stdint.h>
+
+#include <log/log.h>
+#include <log/log_read.h>
+
+#define LOGGER_MAGIC 'l'
+
+/* Header Structure to pstore */
+typedef struct __attribute__((__packed__)) {
+    uint8_t magic;
+    uint16_t len;
+    uint16_t uid;
+    uint16_t pid;
+} android_pmsg_log_header_t;
+
+/* Header Structure to logd, and second header for pstore */
+typedef struct __attribute__((__packed__)) {
+    typeof_log_id_t id;
+    uint16_t tid;
+    log_time realtime;
+} android_log_header_t;
+
+/* Event Header Structure to logd */
+typedef struct __attribute__((__packed__)) {
+    int32_t tag;  // Little Endian Order
+} android_event_header_t;
+
+/* Event payload EVENT_TYPE_INT */
+typedef struct __attribute__((__packed__)) {
+    int8_t type;  // EVENT_TYPE_INT
+    int32_t data; // Little Endian Order
+} android_event_int_t;
+
+/* Event with single EVENT_TYPE_INT */
+typedef struct __attribute__((__packed__)) {
+    android_event_header_t header;
+    android_event_int_t payload;
+} android_log_event_int_t;
+
+/* Event payload EVENT_TYPE_LONG */
+typedef struct __attribute__((__packed__)) {
+    int8_t type;  // EVENT_TYPE_LONG
+    int64_t data; // Little Endian Order
+} android_event_long_t;
+
+/* Event with single EVENT_TYPE_LONG */
+typedef struct __attribute__((__packed__)) {
+    android_event_header_t header;
+    android_event_long_t payload;
+} android_log_event_long_t;
+
+/*
+ * Event payload EVENT_TYPE_STRING
+ *
+ * Danger: do not embed this structure into another structure.
+ * This structure uses a flexible array member, and when
+ * compiled using g++, __builtin_object_size(data, 1) returns
+ * a bad value. This is possibly a g++ bug, or a bug due to
+ * the fact that flexible array members are not supported
+ * 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
+    char data[];
+} android_event_string_t;
+
+/* Event with single EVENT_TYPE_STRING */
+typedef struct __attribute__((__packed__)) {
+    android_event_header_t header;
+    int8_t type;    // EVENT_TYPE_STRING;
+    int32_t length; // Little Endian Order
+    char data[];
+} android_log_event_string_t;
+
+#endif
diff --git a/include/system/audio.h b/include/system/audio.h
deleted file mode 100644
index 181a171..0000000
--- a/include/system/audio.h
+++ /dev/null
@@ -1,1373 +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.
- */
-
-
-#ifndef ANDROID_AUDIO_CORE_H
-#define ANDROID_AUDIO_CORE_H
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <sys/cdefs.h>
-#include <sys/types.h>
-
-#include <cutils/bitops.h>
-
-__BEGIN_DECLS
-
-/* The enums were moved here mostly from
- * frameworks/base/include/media/AudioSystem.h
- */
-
-/* device address used to refer to the standard remote submix */
-#define AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS "0"
-
-/* AudioFlinger and AudioPolicy services use I/O handles to identify audio sources and sinks */
-typedef int audio_io_handle_t;
-#define AUDIO_IO_HANDLE_NONE    0
-
-/* Audio stream types */
-typedef enum {
-    /* These values must kept in sync with
-     * frameworks/base/media/java/android/media/AudioSystem.java
-     */
-    AUDIO_STREAM_DEFAULT          = -1,
-    AUDIO_STREAM_MIN              = 0,
-    AUDIO_STREAM_VOICE_CALL       = 0,
-    AUDIO_STREAM_SYSTEM           = 1,
-    AUDIO_STREAM_RING             = 2,
-    AUDIO_STREAM_MUSIC            = 3,
-    AUDIO_STREAM_ALARM            = 4,
-    AUDIO_STREAM_NOTIFICATION     = 5,
-    AUDIO_STREAM_BLUETOOTH_SCO    = 6,
-    AUDIO_STREAM_ENFORCED_AUDIBLE = 7, /* Sounds that cannot be muted by user
-                                        * and must be routed to speaker
-                                        */
-    AUDIO_STREAM_DTMF             = 8,
-    AUDIO_STREAM_TTS              = 9,  /* Transmitted Through Speaker.
-                                         * Plays over speaker only, silent on other devices.
-                                         */
-    AUDIO_STREAM_ACCESSIBILITY    = 10, /* For accessibility talk back prompts */
-    AUDIO_STREAM_REROUTING        = 11, /* For dynamic policy output mixes */
-    AUDIO_STREAM_PATCH            = 12, /* For internal audio flinger tracks. Fixed volume */
-    AUDIO_STREAM_PUBLIC_CNT       = AUDIO_STREAM_TTS + 1,
-    AUDIO_STREAM_CNT              = AUDIO_STREAM_PATCH + 1,
-} audio_stream_type_t;
-
-/* Do not change these values without updating their counterparts
- * in frameworks/base/media/java/android/media/AudioAttributes.java
- */
-typedef enum {
-    AUDIO_CONTENT_TYPE_UNKNOWN      = 0,
-    AUDIO_CONTENT_TYPE_SPEECH       = 1,
-    AUDIO_CONTENT_TYPE_MUSIC        = 2,
-    AUDIO_CONTENT_TYPE_MOVIE        = 3,
-    AUDIO_CONTENT_TYPE_SONIFICATION = 4,
-
-    AUDIO_CONTENT_TYPE_CNT,
-    AUDIO_CONTENT_TYPE_MAX          = AUDIO_CONTENT_TYPE_CNT - 1,
-} audio_content_type_t;
-
-/* Do not change these values without updating their counterparts
- * in frameworks/base/media/java/android/media/AudioAttributes.java
- */
-typedef enum {
-    AUDIO_USAGE_UNKNOWN                            = 0,
-    AUDIO_USAGE_MEDIA                              = 1,
-    AUDIO_USAGE_VOICE_COMMUNICATION                = 2,
-    AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING     = 3,
-    AUDIO_USAGE_ALARM                              = 4,
-    AUDIO_USAGE_NOTIFICATION                       = 5,
-    AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE    = 6,
-    AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7,
-    AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8,
-    AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9,
-    AUDIO_USAGE_NOTIFICATION_EVENT                 = 10,
-    AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY           = 11,
-    AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE     = 12,
-    AUDIO_USAGE_ASSISTANCE_SONIFICATION            = 13,
-    AUDIO_USAGE_GAME                               = 14,
-    AUDIO_USAGE_VIRTUAL_SOURCE                     = 15,
-
-    AUDIO_USAGE_CNT,
-    AUDIO_USAGE_MAX                                = AUDIO_USAGE_CNT - 1,
-} audio_usage_t;
-
-typedef uint32_t audio_flags_mask_t;
-
-/* Do not change these values without updating their counterparts
- * in frameworks/base/media/java/android/media/AudioAttributes.java
- */
-enum {
-    AUDIO_FLAG_AUDIBILITY_ENFORCED = 0x1,
-    AUDIO_FLAG_SECURE              = 0x2,
-    AUDIO_FLAG_SCO                 = 0x4,
-    AUDIO_FLAG_BEACON              = 0x8,
-    AUDIO_FLAG_HW_AV_SYNC          = 0x10,
-    AUDIO_FLAG_HW_HOTWORD          = 0x20,
-};
-
-/* Do not change these values without updating their counterparts
- * in frameworks/base/media/java/android/media/MediaRecorder.java,
- * frameworks/av/services/audiopolicy/AudioPolicyService.cpp,
- * and system/media/audio_effects/include/audio_effects/audio_effects_conf.h!
- */
-typedef enum {
-    AUDIO_SOURCE_DEFAULT             = 0,
-    AUDIO_SOURCE_MIC                 = 1,
-    AUDIO_SOURCE_VOICE_UPLINK        = 2,
-    AUDIO_SOURCE_VOICE_DOWNLINK      = 3,
-    AUDIO_SOURCE_VOICE_CALL          = 4,
-    AUDIO_SOURCE_CAMCORDER           = 5,
-    AUDIO_SOURCE_VOICE_RECOGNITION   = 6,
-    AUDIO_SOURCE_VOICE_COMMUNICATION = 7,
-    AUDIO_SOURCE_REMOTE_SUBMIX       = 8, /* Source for the mix to be presented remotely.      */
-                                          /* An example of remote presentation is Wifi Display */
-                                          /*  where a dongle attached to a TV can be used to   */
-                                          /*  play the mix captured by this audio source.      */
-    AUDIO_SOURCE_CNT,
-    AUDIO_SOURCE_MAX                 = AUDIO_SOURCE_CNT - 1,
-    AUDIO_SOURCE_FM_TUNER            = 1998,
-    AUDIO_SOURCE_HOTWORD             = 1999, /* A low-priority, preemptible audio source for
-                                                for background software hotword detection.
-                                                Same tuning as AUDIO_SOURCE_VOICE_RECOGNITION.
-                                                Used only internally to the framework. Not exposed
-                                                at the audio HAL. */
-} audio_source_t;
-
-/* Audio attributes */
-#define AUDIO_ATTRIBUTES_TAGS_MAX_SIZE 256
-typedef struct {
-    audio_content_type_t content_type;
-    audio_usage_t        usage;
-    audio_source_t       source;
-    audio_flags_mask_t   flags;
-    char                 tags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE]; /* UTF8 */
-} audio_attributes_t;
-
-/* special audio session values
- * (XXX: should this be living in the audio effects land?)
- */
-typedef enum {
-    /* session for effects attached to a particular output stream
-     * (value must be less than 0)
-     */
-    AUDIO_SESSION_OUTPUT_STAGE = -1,
-
-    /* session for effects applied to output mix. These effects can
-     * be moved by audio policy manager to another output stream
-     * (value must be 0)
-     */
-    AUDIO_SESSION_OUTPUT_MIX = 0,
-
-    /* application does not specify an explicit session ID to be used,
-     * and requests a new session ID to be allocated
-     * TODO use unique values for AUDIO_SESSION_OUTPUT_MIX and AUDIO_SESSION_ALLOCATE,
-     * after all uses have been updated from 0 to the appropriate symbol, and have been tested.
-     */
-    AUDIO_SESSION_ALLOCATE = 0,
-} audio_session_t;
-
-/* a unique ID allocated by AudioFlinger for use as a audio_io_handle_t or audio_session_t */
-typedef int audio_unique_id_t;
-
-#define AUDIO_UNIQUE_ID_ALLOCATE AUDIO_SESSION_ALLOCATE
-
-/* Audio sub formats (see enum audio_format). */
-
-/* PCM sub formats */
-typedef enum {
-    /* All of these are in native byte order */
-    AUDIO_FORMAT_PCM_SUB_16_BIT          = 0x1, /* DO NOT CHANGE - PCM signed 16 bits */
-    AUDIO_FORMAT_PCM_SUB_8_BIT           = 0x2, /* DO NOT CHANGE - PCM unsigned 8 bits */
-    AUDIO_FORMAT_PCM_SUB_32_BIT          = 0x3, /* PCM signed .31 fixed point */
-    AUDIO_FORMAT_PCM_SUB_8_24_BIT        = 0x4, /* PCM signed 7.24 fixed point */
-    AUDIO_FORMAT_PCM_SUB_FLOAT           = 0x5, /* PCM single-precision floating point */
-    AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED   = 0x6, /* PCM signed .23 fixed point packed in 3 bytes */
-} audio_format_pcm_sub_fmt_t;
-
-/* The audio_format_*_sub_fmt_t declarations are not currently used */
-
-/* MP3 sub format field definition : can use 11 LSBs in the same way as MP3
- * frame header to specify bit rate, stereo mode, version...
- */
-typedef enum {
-    AUDIO_FORMAT_MP3_SUB_NONE            = 0x0,
-} audio_format_mp3_sub_fmt_t;
-
-/* AMR NB/WB sub format field definition: specify frame block interleaving,
- * bandwidth efficient or octet aligned, encoding mode for recording...
- */
-typedef enum {
-    AUDIO_FORMAT_AMR_SUB_NONE            = 0x0,
-} audio_format_amr_sub_fmt_t;
-
-/* AAC sub format field definition: specify profile or bitrate for recording... */
-typedef enum {
-    AUDIO_FORMAT_AAC_SUB_MAIN            = 0x1,
-    AUDIO_FORMAT_AAC_SUB_LC              = 0x2,
-    AUDIO_FORMAT_AAC_SUB_SSR             = 0x4,
-    AUDIO_FORMAT_AAC_SUB_LTP             = 0x8,
-    AUDIO_FORMAT_AAC_SUB_HE_V1           = 0x10,
-    AUDIO_FORMAT_AAC_SUB_SCALABLE        = 0x20,
-    AUDIO_FORMAT_AAC_SUB_ERLC            = 0x40,
-    AUDIO_FORMAT_AAC_SUB_LD              = 0x80,
-    AUDIO_FORMAT_AAC_SUB_HE_V2           = 0x100,
-    AUDIO_FORMAT_AAC_SUB_ELD             = 0x200,
-} audio_format_aac_sub_fmt_t;
-
-/* VORBIS sub format field definition: specify quality for recording... */
-typedef enum {
-    AUDIO_FORMAT_VORBIS_SUB_NONE         = 0x0,
-} audio_format_vorbis_sub_fmt_t;
-
-/* Audio format consists of a main format field (upper 8 bits) and a sub format
- * field (lower 24 bits).
- *
- * The main format indicates the main codec type. The sub format field
- * indicates options and parameters for each format. The sub format is mainly
- * used for record to indicate for instance the requested bitrate or profile.
- * It can also be used for certain formats to give informations not present in
- * the encoded audio stream (e.g. octet alignement for AMR).
- */
-typedef enum {
-    AUDIO_FORMAT_INVALID             = 0xFFFFFFFFUL,
-    AUDIO_FORMAT_DEFAULT             = 0,
-    AUDIO_FORMAT_PCM                 = 0x00000000UL, /* DO NOT CHANGE */
-    AUDIO_FORMAT_MP3                 = 0x01000000UL,
-    AUDIO_FORMAT_AMR_NB              = 0x02000000UL,
-    AUDIO_FORMAT_AMR_WB              = 0x03000000UL,
-    AUDIO_FORMAT_AAC                 = 0x04000000UL,
-    AUDIO_FORMAT_HE_AAC_V1           = 0x05000000UL, /* Deprecated, Use AUDIO_FORMAT_AAC_HE_V1*/
-    AUDIO_FORMAT_HE_AAC_V2           = 0x06000000UL, /* Deprecated, Use AUDIO_FORMAT_AAC_HE_V2*/
-    AUDIO_FORMAT_VORBIS              = 0x07000000UL,
-    AUDIO_FORMAT_OPUS                = 0x08000000UL,
-    AUDIO_FORMAT_AC3                 = 0x09000000UL,
-    AUDIO_FORMAT_E_AC3               = 0x0A000000UL,
-    AUDIO_FORMAT_MAIN_MASK           = 0xFF000000UL,
-    AUDIO_FORMAT_SUB_MASK            = 0x00FFFFFFUL,
-
-    /* Aliases */
-    /* note != AudioFormat.ENCODING_PCM_16BIT */
-    AUDIO_FORMAT_PCM_16_BIT          = (AUDIO_FORMAT_PCM |
-                                        AUDIO_FORMAT_PCM_SUB_16_BIT),
-    /* note != AudioFormat.ENCODING_PCM_8BIT */
-    AUDIO_FORMAT_PCM_8_BIT           = (AUDIO_FORMAT_PCM |
-                                        AUDIO_FORMAT_PCM_SUB_8_BIT),
-    AUDIO_FORMAT_PCM_32_BIT          = (AUDIO_FORMAT_PCM |
-                                        AUDIO_FORMAT_PCM_SUB_32_BIT),
-    AUDIO_FORMAT_PCM_8_24_BIT        = (AUDIO_FORMAT_PCM |
-                                        AUDIO_FORMAT_PCM_SUB_8_24_BIT),
-    AUDIO_FORMAT_PCM_FLOAT           = (AUDIO_FORMAT_PCM |
-                                        AUDIO_FORMAT_PCM_SUB_FLOAT),
-    AUDIO_FORMAT_PCM_24_BIT_PACKED   = (AUDIO_FORMAT_PCM |
-                                        AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED),
-    AUDIO_FORMAT_AAC_MAIN            = (AUDIO_FORMAT_AAC |
-                                        AUDIO_FORMAT_AAC_SUB_MAIN),
-    AUDIO_FORMAT_AAC_LC              = (AUDIO_FORMAT_AAC |
-                                        AUDIO_FORMAT_AAC_SUB_LC),
-    AUDIO_FORMAT_AAC_SSR             = (AUDIO_FORMAT_AAC |
-                                        AUDIO_FORMAT_AAC_SUB_SSR),
-    AUDIO_FORMAT_AAC_LTP             = (AUDIO_FORMAT_AAC |
-                                        AUDIO_FORMAT_AAC_SUB_LTP),
-    AUDIO_FORMAT_AAC_HE_V1           = (AUDIO_FORMAT_AAC |
-                                        AUDIO_FORMAT_AAC_SUB_HE_V1),
-    AUDIO_FORMAT_AAC_SCALABLE        = (AUDIO_FORMAT_AAC |
-                                        AUDIO_FORMAT_AAC_SUB_SCALABLE),
-    AUDIO_FORMAT_AAC_ERLC            = (AUDIO_FORMAT_AAC |
-                                        AUDIO_FORMAT_AAC_SUB_ERLC),
-    AUDIO_FORMAT_AAC_LD              = (AUDIO_FORMAT_AAC |
-                                        AUDIO_FORMAT_AAC_SUB_LD),
-    AUDIO_FORMAT_AAC_HE_V2           = (AUDIO_FORMAT_AAC |
-                                        AUDIO_FORMAT_AAC_SUB_HE_V2),
-    AUDIO_FORMAT_AAC_ELD             = (AUDIO_FORMAT_AAC |
-                                        AUDIO_FORMAT_AAC_SUB_ELD),
-} audio_format_t;
-
-/* For the channel mask for position assignment representation */
-enum {
-
-/* These can be a complete audio_channel_mask_t. */
-
-    AUDIO_CHANNEL_NONE                      = 0x0,
-    AUDIO_CHANNEL_INVALID                   = 0xC0000000,
-
-/* These can be the bits portion of an audio_channel_mask_t
- * with representation AUDIO_CHANNEL_REPRESENTATION_POSITION.
- * Using these bits as a complete audio_channel_mask_t is deprecated.
- */
-
-    /* output channels */
-    AUDIO_CHANNEL_OUT_FRONT_LEFT            = 0x1,
-    AUDIO_CHANNEL_OUT_FRONT_RIGHT           = 0x2,
-    AUDIO_CHANNEL_OUT_FRONT_CENTER          = 0x4,
-    AUDIO_CHANNEL_OUT_LOW_FREQUENCY         = 0x8,
-    AUDIO_CHANNEL_OUT_BACK_LEFT             = 0x10,
-    AUDIO_CHANNEL_OUT_BACK_RIGHT            = 0x20,
-    AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER  = 0x40,
-    AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x80,
-    AUDIO_CHANNEL_OUT_BACK_CENTER           = 0x100,
-    AUDIO_CHANNEL_OUT_SIDE_LEFT             = 0x200,
-    AUDIO_CHANNEL_OUT_SIDE_RIGHT            = 0x400,
-    AUDIO_CHANNEL_OUT_TOP_CENTER            = 0x800,
-    AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT        = 0x1000,
-    AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER      = 0x2000,
-    AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT       = 0x4000,
-    AUDIO_CHANNEL_OUT_TOP_BACK_LEFT         = 0x8000,
-    AUDIO_CHANNEL_OUT_TOP_BACK_CENTER       = 0x10000,
-    AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT        = 0x20000,
-
-/* TODO: should these be considered complete channel masks, or only bits? */
-
-    AUDIO_CHANNEL_OUT_MONO     = AUDIO_CHANNEL_OUT_FRONT_LEFT,
-    AUDIO_CHANNEL_OUT_STEREO   = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
-                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT),
-    AUDIO_CHANNEL_OUT_QUAD     = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
-                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT |
-                                  AUDIO_CHANNEL_OUT_BACK_LEFT |
-                                  AUDIO_CHANNEL_OUT_BACK_RIGHT),
-    AUDIO_CHANNEL_OUT_QUAD_BACK = AUDIO_CHANNEL_OUT_QUAD,
-    /* like AUDIO_CHANNEL_OUT_QUAD_BACK with *_SIDE_* instead of *_BACK_* */
-    AUDIO_CHANNEL_OUT_QUAD_SIDE = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
-                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT |
-                                  AUDIO_CHANNEL_OUT_SIDE_LEFT |
-                                  AUDIO_CHANNEL_OUT_SIDE_RIGHT),
-    AUDIO_CHANNEL_OUT_5POINT1  = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
-                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT |
-                                  AUDIO_CHANNEL_OUT_FRONT_CENTER |
-                                  AUDIO_CHANNEL_OUT_LOW_FREQUENCY |
-                                  AUDIO_CHANNEL_OUT_BACK_LEFT |
-                                  AUDIO_CHANNEL_OUT_BACK_RIGHT),
-    AUDIO_CHANNEL_OUT_5POINT1_BACK = AUDIO_CHANNEL_OUT_5POINT1,
-    /* like AUDIO_CHANNEL_OUT_5POINT1_BACK with *_SIDE_* instead of *_BACK_* */
-    AUDIO_CHANNEL_OUT_5POINT1_SIDE = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
-                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT |
-                                  AUDIO_CHANNEL_OUT_FRONT_CENTER |
-                                  AUDIO_CHANNEL_OUT_LOW_FREQUENCY |
-                                  AUDIO_CHANNEL_OUT_SIDE_LEFT |
-                                  AUDIO_CHANNEL_OUT_SIDE_RIGHT),
-    // matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND definition for 7.1
-    AUDIO_CHANNEL_OUT_7POINT1  = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
-                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT |
-                                  AUDIO_CHANNEL_OUT_FRONT_CENTER |
-                                  AUDIO_CHANNEL_OUT_LOW_FREQUENCY |
-                                  AUDIO_CHANNEL_OUT_BACK_LEFT |
-                                  AUDIO_CHANNEL_OUT_BACK_RIGHT |
-                                  AUDIO_CHANNEL_OUT_SIDE_LEFT |
-                                  AUDIO_CHANNEL_OUT_SIDE_RIGHT),
-    AUDIO_CHANNEL_OUT_ALL      = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
-                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT |
-                                  AUDIO_CHANNEL_OUT_FRONT_CENTER |
-                                  AUDIO_CHANNEL_OUT_LOW_FREQUENCY |
-                                  AUDIO_CHANNEL_OUT_BACK_LEFT |
-                                  AUDIO_CHANNEL_OUT_BACK_RIGHT |
-                                  AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER |
-                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER |
-                                  AUDIO_CHANNEL_OUT_BACK_CENTER|
-                                  AUDIO_CHANNEL_OUT_SIDE_LEFT|
-                                  AUDIO_CHANNEL_OUT_SIDE_RIGHT|
-                                  AUDIO_CHANNEL_OUT_TOP_CENTER|
-                                  AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT|
-                                  AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER|
-                                  AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT|
-                                  AUDIO_CHANNEL_OUT_TOP_BACK_LEFT|
-                                  AUDIO_CHANNEL_OUT_TOP_BACK_CENTER|
-                                  AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT),
-
-/* These are bits only, not complete values */
-
-    /* input channels */
-    AUDIO_CHANNEL_IN_LEFT            = 0x4,
-    AUDIO_CHANNEL_IN_RIGHT           = 0x8,
-    AUDIO_CHANNEL_IN_FRONT           = 0x10,
-    AUDIO_CHANNEL_IN_BACK            = 0x20,
-    AUDIO_CHANNEL_IN_LEFT_PROCESSED  = 0x40,
-    AUDIO_CHANNEL_IN_RIGHT_PROCESSED = 0x80,
-    AUDIO_CHANNEL_IN_FRONT_PROCESSED = 0x100,
-    AUDIO_CHANNEL_IN_BACK_PROCESSED  = 0x200,
-    AUDIO_CHANNEL_IN_PRESSURE        = 0x400,
-    AUDIO_CHANNEL_IN_X_AXIS          = 0x800,
-    AUDIO_CHANNEL_IN_Y_AXIS          = 0x1000,
-    AUDIO_CHANNEL_IN_Z_AXIS          = 0x2000,
-    AUDIO_CHANNEL_IN_VOICE_UPLINK    = 0x4000,
-    AUDIO_CHANNEL_IN_VOICE_DNLINK    = 0x8000,
-
-/* TODO: should these be considered complete channel masks, or only bits, or deprecated? */
-
-    AUDIO_CHANNEL_IN_MONO   = AUDIO_CHANNEL_IN_FRONT,
-    AUDIO_CHANNEL_IN_STEREO = (AUDIO_CHANNEL_IN_LEFT | AUDIO_CHANNEL_IN_RIGHT),
-    AUDIO_CHANNEL_IN_FRONT_BACK = (AUDIO_CHANNEL_IN_FRONT | AUDIO_CHANNEL_IN_BACK),
-    AUDIO_CHANNEL_IN_ALL    = (AUDIO_CHANNEL_IN_LEFT |
-                               AUDIO_CHANNEL_IN_RIGHT |
-                               AUDIO_CHANNEL_IN_FRONT |
-                               AUDIO_CHANNEL_IN_BACK|
-                               AUDIO_CHANNEL_IN_LEFT_PROCESSED |
-                               AUDIO_CHANNEL_IN_RIGHT_PROCESSED |
-                               AUDIO_CHANNEL_IN_FRONT_PROCESSED |
-                               AUDIO_CHANNEL_IN_BACK_PROCESSED|
-                               AUDIO_CHANNEL_IN_PRESSURE |
-                               AUDIO_CHANNEL_IN_X_AXIS |
-                               AUDIO_CHANNEL_IN_Y_AXIS |
-                               AUDIO_CHANNEL_IN_Z_AXIS |
-                               AUDIO_CHANNEL_IN_VOICE_UPLINK |
-                               AUDIO_CHANNEL_IN_VOICE_DNLINK),
-};
-
-/* A channel mask per se only defines the presence or absence of a channel, not the order.
- * But see AUDIO_INTERLEAVE_* below for the platform convention of order.
- *
- * audio_channel_mask_t is an opaque type and its internal layout should not
- * be assumed as it may change in the future.
- * Instead, always use the functions declared in this header to examine.
- *
- * These are the current representations:
- *
- *   AUDIO_CHANNEL_REPRESENTATION_POSITION
- *     is a channel mask representation for position assignment.
- *     Each low-order bit corresponds to the spatial position of a transducer (output),
- *     or interpretation of channel (input).
- *     The user of a channel mask needs to know the context of whether it is for output or input.
- *     The constants AUDIO_CHANNEL_OUT_* or AUDIO_CHANNEL_IN_* apply to the bits portion.
- *     It is not permitted for no bits to be set.
- *
- *   AUDIO_CHANNEL_REPRESENTATION_INDEX
- *     is a channel mask representation for index assignment.
- *     Each low-order bit corresponds to a selected channel.
- *     There is no platform interpretation of the various bits.
- *     There is no concept of output or input.
- *     It is not permitted for no bits to be set.
- *
- * All other representations are reserved for future use.
- *
- * Warning: current representation distinguishes between input and output, but this will not the be
- * case in future revisions of the platform. Wherever there is an ambiguity between input and output
- * that is currently resolved by checking the channel mask, the implementer should look for ways to
- * fix it with additional information outside of the mask.
- */
-typedef uint32_t audio_channel_mask_t;
-
-/* Maximum number of channels for all representations */
-#define AUDIO_CHANNEL_COUNT_MAX             30
-
-/* log(2) of maximum number of representations, not part of public API */
-#define AUDIO_CHANNEL_REPRESENTATION_LOG2   2
-
-/* Representations */
-typedef enum {
-    AUDIO_CHANNEL_REPRESENTATION_POSITION    = 0,    // must be zero for compatibility
-    // 1 is reserved for future use
-    AUDIO_CHANNEL_REPRESENTATION_INDEX       = 2,
-    // 3 is reserved for future use
-} audio_channel_representation_t;
-
-/* The return value is undefined if the channel mask is invalid. */
-static inline uint32_t audio_channel_mask_get_bits(audio_channel_mask_t channel)
-{
-    return channel & ((1 << AUDIO_CHANNEL_COUNT_MAX) - 1);
-}
-
-/* The return value is undefined if the channel mask is invalid. */
-static inline audio_channel_representation_t audio_channel_mask_get_representation(
-        audio_channel_mask_t channel)
-{
-    // The right shift should be sufficient, but also "and" for safety in case mask is not 32 bits
-    return (audio_channel_representation_t)
-            ((channel >> AUDIO_CHANNEL_COUNT_MAX) & ((1 << AUDIO_CHANNEL_REPRESENTATION_LOG2) - 1));
-}
-
-/* Returns true if the channel mask is valid,
- * or returns false for AUDIO_CHANNEL_NONE, AUDIO_CHANNEL_INVALID, and other invalid values.
- * This function is unable to determine whether a channel mask for position assignment
- * is invalid because an output mask has an invalid output bit set,
- * or because an input mask has an invalid input bit set.
- * All other APIs that take a channel mask assume that it is valid.
- */
-static inline bool audio_channel_mask_is_valid(audio_channel_mask_t channel)
-{
-    uint32_t bits = audio_channel_mask_get_bits(channel);
-    audio_channel_representation_t representation = audio_channel_mask_get_representation(channel);
-    switch (representation) {
-    case AUDIO_CHANNEL_REPRESENTATION_POSITION:
-    case AUDIO_CHANNEL_REPRESENTATION_INDEX:
-        break;
-    default:
-        bits = 0;
-        break;
-    }
-    return bits != 0;
-}
-
-/* Not part of public API */
-static inline audio_channel_mask_t audio_channel_mask_from_representation_and_bits(
-        audio_channel_representation_t representation, uint32_t bits)
-{
-    return (audio_channel_mask_t) ((representation << AUDIO_CHANNEL_COUNT_MAX) | bits);
-}
-
-/* Expresses the convention when stereo audio samples are stored interleaved
- * in an array.  This should improve readability by allowing code to use
- * symbolic indices instead of hard-coded [0] and [1].
- *
- * For multi-channel beyond stereo, the platform convention is that channels
- * are interleaved in order from least significant channel mask bit
- * to most significant channel mask bit, with unused bits skipped.
- * Any exceptions to this convention will be noted at the appropriate API.
- */
-enum {
-    AUDIO_INTERLEAVE_LEFT   = 0,
-    AUDIO_INTERLEAVE_RIGHT  = 1,
-};
-
-typedef enum {
-    AUDIO_MODE_INVALID          = -2,
-    AUDIO_MODE_CURRENT          = -1,
-    AUDIO_MODE_NORMAL           = 0,
-    AUDIO_MODE_RINGTONE         = 1,
-    AUDIO_MODE_IN_CALL          = 2,
-    AUDIO_MODE_IN_COMMUNICATION = 3,
-
-    AUDIO_MODE_CNT,
-    AUDIO_MODE_MAX              = AUDIO_MODE_CNT - 1,
-} audio_mode_t;
-
-/* This enum is deprecated */
-typedef enum {
-    AUDIO_IN_ACOUSTICS_NONE          = 0,
-    AUDIO_IN_ACOUSTICS_AGC_ENABLE    = 0x0001,
-    AUDIO_IN_ACOUSTICS_AGC_DISABLE   = 0,
-    AUDIO_IN_ACOUSTICS_NS_ENABLE     = 0x0002,
-    AUDIO_IN_ACOUSTICS_NS_DISABLE    = 0,
-    AUDIO_IN_ACOUSTICS_TX_IIR_ENABLE = 0x0004,
-    AUDIO_IN_ACOUSTICS_TX_DISABLE    = 0,
-} audio_in_acoustics_t;
-
-enum {
-    AUDIO_DEVICE_NONE                          = 0x0,
-    /* reserved bits */
-    AUDIO_DEVICE_BIT_IN                        = 0x80000000,
-    AUDIO_DEVICE_BIT_DEFAULT                   = 0x40000000,
-    /* output devices */
-    AUDIO_DEVICE_OUT_EARPIECE                  = 0x1,
-    AUDIO_DEVICE_OUT_SPEAKER                   = 0x2,
-    AUDIO_DEVICE_OUT_WIRED_HEADSET             = 0x4,
-    AUDIO_DEVICE_OUT_WIRED_HEADPHONE           = 0x8,
-    AUDIO_DEVICE_OUT_BLUETOOTH_SCO             = 0x10,
-    AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET     = 0x20,
-    AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT      = 0x40,
-    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP            = 0x80,
-    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
-    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER    = 0x200,
-    AUDIO_DEVICE_OUT_AUX_DIGITAL               = 0x400,
-    AUDIO_DEVICE_OUT_HDMI                      = AUDIO_DEVICE_OUT_AUX_DIGITAL,
-    /* uses an analog connection (multiplexed over the USB connector pins for instance) */
-    AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET         = 0x800,
-    AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET         = 0x1000,
-    /* USB accessory mode: your Android device is a USB device and the dock is a USB host */
-    AUDIO_DEVICE_OUT_USB_ACCESSORY             = 0x2000,
-    /* USB host mode: your Android device is a USB host and the dock is a USB device */
-    AUDIO_DEVICE_OUT_USB_DEVICE                = 0x4000,
-    AUDIO_DEVICE_OUT_REMOTE_SUBMIX             = 0x8000,
-    /* Telephony voice TX path */
-    AUDIO_DEVICE_OUT_TELEPHONY_TX              = 0x10000,
-    /* Analog jack with line impedance detected */
-    AUDIO_DEVICE_OUT_LINE                      = 0x20000,
-    /* HDMI Audio Return Channel */
-    AUDIO_DEVICE_OUT_HDMI_ARC                  = 0x40000,
-    /* S/PDIF out */
-    AUDIO_DEVICE_OUT_SPDIF                     = 0x80000,
-    /* FM transmitter out */
-    AUDIO_DEVICE_OUT_FM                        = 0x100000,
-    /* Line out for av devices */
-    AUDIO_DEVICE_OUT_AUX_LINE                  = 0x200000,
-    /* limited-output speaker device for acoustic safety */
-    AUDIO_DEVICE_OUT_SPEAKER_SAFE              = 0x400000,
-    AUDIO_DEVICE_OUT_DEFAULT                   = AUDIO_DEVICE_BIT_DEFAULT,
-    AUDIO_DEVICE_OUT_ALL      = (AUDIO_DEVICE_OUT_EARPIECE |
-                                 AUDIO_DEVICE_OUT_SPEAKER |
-                                 AUDIO_DEVICE_OUT_WIRED_HEADSET |
-                                 AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
-                                 AUDIO_DEVICE_OUT_BLUETOOTH_SCO |
-                                 AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
-                                 AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT |
-                                 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
-                                 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
-                                 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER |
-                                 AUDIO_DEVICE_OUT_HDMI |
-                                 AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
-                                 AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET |
-                                 AUDIO_DEVICE_OUT_USB_ACCESSORY |
-                                 AUDIO_DEVICE_OUT_USB_DEVICE |
-                                 AUDIO_DEVICE_OUT_REMOTE_SUBMIX |
-                                 AUDIO_DEVICE_OUT_TELEPHONY_TX |
-                                 AUDIO_DEVICE_OUT_LINE |
-                                 AUDIO_DEVICE_OUT_HDMI_ARC |
-                                 AUDIO_DEVICE_OUT_SPDIF |
-                                 AUDIO_DEVICE_OUT_FM |
-                                 AUDIO_DEVICE_OUT_AUX_LINE |
-                                 AUDIO_DEVICE_OUT_SPEAKER_SAFE |
-                                 AUDIO_DEVICE_OUT_DEFAULT),
-    AUDIO_DEVICE_OUT_ALL_A2DP = (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
-                                 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
-                                 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
-    AUDIO_DEVICE_OUT_ALL_SCO  = (AUDIO_DEVICE_OUT_BLUETOOTH_SCO |
-                                 AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
-                                 AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT),
-    AUDIO_DEVICE_OUT_ALL_USB  = (AUDIO_DEVICE_OUT_USB_ACCESSORY |
-                                 AUDIO_DEVICE_OUT_USB_DEVICE),
-
-    /* input devices */
-    AUDIO_DEVICE_IN_COMMUNICATION         = AUDIO_DEVICE_BIT_IN | 0x1,
-    AUDIO_DEVICE_IN_AMBIENT               = AUDIO_DEVICE_BIT_IN | 0x2,
-    AUDIO_DEVICE_IN_BUILTIN_MIC           = AUDIO_DEVICE_BIT_IN | 0x4,
-    AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = AUDIO_DEVICE_BIT_IN | 0x8,
-    AUDIO_DEVICE_IN_WIRED_HEADSET         = AUDIO_DEVICE_BIT_IN | 0x10,
-    AUDIO_DEVICE_IN_AUX_DIGITAL           = AUDIO_DEVICE_BIT_IN | 0x20,
-    AUDIO_DEVICE_IN_HDMI                  = AUDIO_DEVICE_IN_AUX_DIGITAL,
-    /* Telephony voice RX path */
-    AUDIO_DEVICE_IN_VOICE_CALL            = AUDIO_DEVICE_BIT_IN | 0x40,
-    AUDIO_DEVICE_IN_TELEPHONY_RX          = AUDIO_DEVICE_IN_VOICE_CALL,
-    AUDIO_DEVICE_IN_BACK_MIC              = AUDIO_DEVICE_BIT_IN | 0x80,
-    AUDIO_DEVICE_IN_REMOTE_SUBMIX         = AUDIO_DEVICE_BIT_IN | 0x100,
-    AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET     = AUDIO_DEVICE_BIT_IN | 0x200,
-    AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET     = AUDIO_DEVICE_BIT_IN | 0x400,
-    AUDIO_DEVICE_IN_USB_ACCESSORY         = AUDIO_DEVICE_BIT_IN | 0x800,
-    AUDIO_DEVICE_IN_USB_DEVICE            = AUDIO_DEVICE_BIT_IN | 0x1000,
-    /* FM tuner input */
-    AUDIO_DEVICE_IN_FM_TUNER              = AUDIO_DEVICE_BIT_IN | 0x2000,
-    /* TV tuner input */
-    AUDIO_DEVICE_IN_TV_TUNER              = AUDIO_DEVICE_BIT_IN | 0x4000,
-    /* Analog jack with line impedance detected */
-    AUDIO_DEVICE_IN_LINE                  = AUDIO_DEVICE_BIT_IN | 0x8000,
-    /* S/PDIF in */
-    AUDIO_DEVICE_IN_SPDIF                 = AUDIO_DEVICE_BIT_IN | 0x10000,
-    AUDIO_DEVICE_IN_BLUETOOTH_A2DP        = AUDIO_DEVICE_BIT_IN | 0x20000,
-    AUDIO_DEVICE_IN_LOOPBACK              = AUDIO_DEVICE_BIT_IN | 0x40000,
-    AUDIO_DEVICE_IN_DEFAULT               = AUDIO_DEVICE_BIT_IN | AUDIO_DEVICE_BIT_DEFAULT,
-
-    AUDIO_DEVICE_IN_ALL     = (AUDIO_DEVICE_IN_COMMUNICATION |
-                               AUDIO_DEVICE_IN_AMBIENT |
-                               AUDIO_DEVICE_IN_BUILTIN_MIC |
-                               AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET |
-                               AUDIO_DEVICE_IN_WIRED_HEADSET |
-                               AUDIO_DEVICE_IN_HDMI |
-                               AUDIO_DEVICE_IN_TELEPHONY_RX |
-                               AUDIO_DEVICE_IN_BACK_MIC |
-                               AUDIO_DEVICE_IN_REMOTE_SUBMIX |
-                               AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET |
-                               AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET |
-                               AUDIO_DEVICE_IN_USB_ACCESSORY |
-                               AUDIO_DEVICE_IN_USB_DEVICE |
-                               AUDIO_DEVICE_IN_FM_TUNER |
-                               AUDIO_DEVICE_IN_TV_TUNER |
-                               AUDIO_DEVICE_IN_LINE |
-                               AUDIO_DEVICE_IN_SPDIF |
-                               AUDIO_DEVICE_IN_BLUETOOTH_A2DP |
-                               AUDIO_DEVICE_IN_LOOPBACK |
-                               AUDIO_DEVICE_IN_DEFAULT),
-    AUDIO_DEVICE_IN_ALL_SCO = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,
-    AUDIO_DEVICE_IN_ALL_USB  = (AUDIO_DEVICE_IN_USB_ACCESSORY |
-                                AUDIO_DEVICE_IN_USB_DEVICE),
-};
-
-typedef uint32_t audio_devices_t;
-
-/* the audio output flags serve two purposes:
- * - when an AudioTrack is created they indicate a "wish" to be connected to an
- * output stream with attributes corresponding to the specified flags
- * - when present in an output profile descriptor listed for a particular audio
- * hardware module, they indicate that an output stream can be opened that
- * supports the attributes indicated by the flags.
- * the audio policy manager will try to match the flags in the request
- * (when getOuput() is called) to an available output stream.
- */
-typedef enum {
-    AUDIO_OUTPUT_FLAG_NONE = 0x0,       // no attributes
-    AUDIO_OUTPUT_FLAG_DIRECT = 0x1,     // this output directly connects a track
-                                        // to one output stream: no software mixer
-    AUDIO_OUTPUT_FLAG_PRIMARY = 0x2,    // this output is the primary output of
-                                        // the device. It is unique and must be
-                                        // present. It is opened by default and
-                                        // receives routing, audio mode and volume
-                                        // controls related to voice calls.
-    AUDIO_OUTPUT_FLAG_FAST = 0x4,       // output supports "fast tracks",
-                                        // defined elsewhere
-    AUDIO_OUTPUT_FLAG_DEEP_BUFFER = 0x8, // use deep audio buffers
-    AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD = 0x10,  // offload playback of compressed
-                                                // streams to hardware codec
-    AUDIO_OUTPUT_FLAG_NON_BLOCKING = 0x20, // use non-blocking write
-    AUDIO_OUTPUT_FLAG_HW_AV_SYNC = 0x40 // output uses a hardware A/V synchronization source
-} audio_output_flags_t;
-
-/* The audio input flags are analogous to audio output flags.
- * Currently they are used only when an AudioRecord is created,
- * to indicate a preference to be connected to an input stream with
- * attributes corresponding to the specified flags.
- */
-typedef enum {
-    AUDIO_INPUT_FLAG_NONE       = 0x0,  // no attributes
-    AUDIO_INPUT_FLAG_FAST       = 0x1,  // prefer an input that supports "fast tracks"
-    AUDIO_INPUT_FLAG_HW_HOTWORD = 0x2,  // prefer an input that captures from hw hotword source
-} audio_input_flags_t;
-
-/* Additional information about compressed streams offloaded to
- * hardware playback
- * The version and size fields must be initialized by the caller by using
- * one of the constants defined here.
- */
-typedef struct {
-    uint16_t version;                   // version of the info structure
-    uint16_t size;                      // total size of the structure including version and size
-    uint32_t sample_rate;               // sample rate in Hz
-    audio_channel_mask_t channel_mask;  // channel mask
-    audio_format_t format;              // audio format
-    audio_stream_type_t stream_type;    // stream type
-    uint32_t bit_rate;                  // bit rate in bits per second
-    int64_t duration_us;                // duration in microseconds, -1 if unknown
-    bool has_video;                     // true if stream is tied to a video stream
-    bool is_streaming;                  // true if streaming, false if local playback
-} audio_offload_info_t;
-
-#define AUDIO_MAKE_OFFLOAD_INFO_VERSION(maj,min) \
-            ((((maj) & 0xff) << 8) | ((min) & 0xff))
-
-#define AUDIO_OFFLOAD_INFO_VERSION_0_1 AUDIO_MAKE_OFFLOAD_INFO_VERSION(0, 1)
-#define AUDIO_OFFLOAD_INFO_VERSION_CURRENT AUDIO_OFFLOAD_INFO_VERSION_0_1
-
-static const audio_offload_info_t AUDIO_INFO_INITIALIZER = {
-    version: AUDIO_OFFLOAD_INFO_VERSION_CURRENT,
-    size: sizeof(audio_offload_info_t),
-    sample_rate: 0,
-    channel_mask: 0,
-    format: AUDIO_FORMAT_DEFAULT,
-    stream_type: AUDIO_STREAM_VOICE_CALL,
-    bit_rate: 0,
-    duration_us: 0,
-    has_video: false,
-    is_streaming: false
-};
-
-/* common audio stream configuration parameters
- * You should memset() the entire structure to zero before use to
- * ensure forward compatibility
- */
-struct audio_config {
-    uint32_t sample_rate;
-    audio_channel_mask_t channel_mask;
-    audio_format_t  format;
-    audio_offload_info_t offload_info;
-    size_t frame_count;
-};
-typedef struct audio_config audio_config_t;
-
-static const audio_config_t AUDIO_CONFIG_INITIALIZER = {
-    sample_rate: 0,
-    channel_mask: AUDIO_CHANNEL_NONE,
-    format: AUDIO_FORMAT_DEFAULT,
-    offload_info: {
-        version: AUDIO_OFFLOAD_INFO_VERSION_CURRENT,
-        size: sizeof(audio_offload_info_t),
-        sample_rate: 0,
-        channel_mask: 0,
-        format: AUDIO_FORMAT_DEFAULT,
-        stream_type: AUDIO_STREAM_VOICE_CALL,
-        bit_rate: 0,
-        duration_us: 0,
-        has_video: false,
-        is_streaming: false
-    },
-    frame_count: 0,
-};
-
-
-/* audio hw module handle functions or structures referencing a module */
-typedef int audio_module_handle_t;
-
-/******************************
- *  Volume control
- *****************************/
-
-/* If the audio hardware supports gain control on some audio paths,
- * the platform can expose them in the audio_policy.conf file. The audio HAL
- * will then implement gain control functions that will use the following data
- * structures. */
-
-/* Type of gain control exposed by an audio port */
-#define AUDIO_GAIN_MODE_JOINT     0x1 /* supports joint channel gain control */
-#define AUDIO_GAIN_MODE_CHANNELS  0x2 /* supports separate channel gain control */
-#define AUDIO_GAIN_MODE_RAMP      0x4 /* supports gain ramps */
-
-typedef uint32_t audio_gain_mode_t;
-
-
-/* An audio_gain struct is a representation of a gain stage.
- * A gain stage is always attached to an audio port. */
-struct audio_gain  {
-    audio_gain_mode_t    mode;          /* e.g. AUDIO_GAIN_MODE_JOINT */
-    audio_channel_mask_t channel_mask;  /* channels which gain an be controlled.
-                                           N/A if AUDIO_GAIN_MODE_CHANNELS is not supported */
-    int                  min_value;     /* minimum gain value in millibels */
-    int                  max_value;     /* maximum gain value in millibels */
-    int                  default_value; /* default gain value in millibels */
-    unsigned int         step_value;    /* gain step in millibels */
-    unsigned int         min_ramp_ms;   /* minimum ramp duration in ms */
-    unsigned int         max_ramp_ms;   /* maximum ramp duration in ms */
-};
-
-/* The gain configuration structure is used to get or set the gain values of a
- * given port */
-struct audio_gain_config  {
-    int                  index;             /* index of the corresponding audio_gain in the
-                                               audio_port gains[] table */
-    audio_gain_mode_t    mode;              /* mode requested for this command */
-    audio_channel_mask_t channel_mask;      /* channels which gain value follows.
-                                               N/A in joint mode */
-    int                  values[sizeof(audio_channel_mask_t) * 8]; /* gain values in millibels
-                                               for each channel ordered from LSb to MSb in
-                                               channel mask. The number of values is 1 in joint
-                                               mode or popcount(channel_mask) */
-    unsigned int         ramp_duration_ms; /* ramp duration in ms */
-};
-
-/******************************
- *  Routing control
- *****************************/
-
-/* Types defined here are used to describe an audio source or sink at internal
- * framework interfaces (audio policy, patch panel) or at the audio HAL.
- * Sink and sources are grouped in a concept of “audio port” representing an
- * audio end point at the edge of the system managed by the module exposing
- * the interface. */
-
-/* Audio port role: either source or sink */
-typedef enum {
-    AUDIO_PORT_ROLE_NONE,
-    AUDIO_PORT_ROLE_SOURCE,
-    AUDIO_PORT_ROLE_SINK,
-} audio_port_role_t;
-
-/* Audio port type indicates if it is a session (e.g AudioTrack),
- * a mix (e.g PlaybackThread output) or a physical device
- * (e.g AUDIO_DEVICE_OUT_SPEAKER) */
-typedef enum {
-    AUDIO_PORT_TYPE_NONE,
-    AUDIO_PORT_TYPE_DEVICE,
-    AUDIO_PORT_TYPE_MIX,
-    AUDIO_PORT_TYPE_SESSION,
-} audio_port_type_t;
-
-/* Each port has a unique ID or handle allocated by policy manager */
-typedef int audio_port_handle_t;
-#define AUDIO_PORT_HANDLE_NONE 0
-
-
-/* maximum audio device address length */
-#define AUDIO_DEVICE_MAX_ADDRESS_LEN 32
-
-/* extension for audio port configuration structure when the audio port is a
- * hardware device */
-struct audio_port_config_device_ext {
-    audio_module_handle_t hw_module;                /* module the device is attached to */
-    audio_devices_t       type;                     /* device type (e.g AUDIO_DEVICE_OUT_SPEAKER) */
-    char                  address[AUDIO_DEVICE_MAX_ADDRESS_LEN]; /* device address. "" if N/A */
-};
-
-/* extension for audio port configuration structure when the audio port is a
- * sub mix */
-struct audio_port_config_mix_ext {
-    audio_module_handle_t hw_module;    /* module the stream is attached to */
-    audio_io_handle_t handle;           /* I/O handle of the input/output stream */
-    union {
-        //TODO: change use case for output streams: use strategy and mixer attributes
-        audio_stream_type_t stream;
-        audio_source_t      source;
-    } usecase;
-};
-
-/* extension for audio port configuration structure when the audio port is an
- * audio session */
-struct audio_port_config_session_ext {
-    audio_session_t   session; /* audio session */
-};
-
-/* Flags indicating which fields are to be considered in struct audio_port_config */
-#define AUDIO_PORT_CONFIG_SAMPLE_RATE  0x1
-#define AUDIO_PORT_CONFIG_CHANNEL_MASK 0x2
-#define AUDIO_PORT_CONFIG_FORMAT       0x4
-#define AUDIO_PORT_CONFIG_GAIN         0x8
-#define AUDIO_PORT_CONFIG_ALL (AUDIO_PORT_CONFIG_SAMPLE_RATE | \
-                               AUDIO_PORT_CONFIG_CHANNEL_MASK | \
-                               AUDIO_PORT_CONFIG_FORMAT | \
-                               AUDIO_PORT_CONFIG_GAIN)
-
-/* audio port configuration structure used to specify a particular configuration of
- * an audio port */
-struct audio_port_config {
-    audio_port_handle_t      id;           /* port unique ID */
-    audio_port_role_t        role;         /* sink or source */
-    audio_port_type_t        type;         /* device, mix ... */
-    unsigned int             config_mask;  /* e.g AUDIO_PORT_CONFIG_ALL */
-    unsigned int             sample_rate;  /* sampling rate in Hz */
-    audio_channel_mask_t     channel_mask; /* channel mask if applicable */
-    audio_format_t           format;       /* format if applicable */
-    struct audio_gain_config gain;         /* gain to apply if applicable */
-    union {
-        struct audio_port_config_device_ext  device;  /* device specific info */
-        struct audio_port_config_mix_ext     mix;     /* mix specific info */
-        struct audio_port_config_session_ext session; /* session specific info */
-    } ext;
-};
-
-
-/* max number of sampling rates in audio port */
-#define AUDIO_PORT_MAX_SAMPLING_RATES 16
-/* max number of channel masks in audio port */
-#define AUDIO_PORT_MAX_CHANNEL_MASKS 16
-/* max number of audio formats in audio port */
-#define AUDIO_PORT_MAX_FORMATS 16
-/* max number of gain controls in audio port */
-#define AUDIO_PORT_MAX_GAINS 16
-
-/* extension for audio port structure when the audio port is a hardware device */
-struct audio_port_device_ext {
-    audio_module_handle_t hw_module;    /* module the device is attached to */
-    audio_devices_t       type;         /* device type (e.g AUDIO_DEVICE_OUT_SPEAKER) */
-    char                  address[AUDIO_DEVICE_MAX_ADDRESS_LEN];
-};
-
-/* Latency class of the audio mix */
-typedef enum {
-    AUDIO_LATENCY_LOW,
-    AUDIO_LATENCY_NORMAL,
-} audio_mix_latency_class_t;
-
-/* extension for audio port structure when the audio port is a sub mix */
-struct audio_port_mix_ext {
-    audio_module_handle_t     hw_module;     /* module the stream is attached to */
-    audio_io_handle_t         handle;        /* I/O handle of the input.output stream */
-    audio_mix_latency_class_t latency_class; /* latency class */
-    // other attributes: routing strategies
-};
-
-/* extension for audio port structure when the audio port is an audio session */
-struct audio_port_session_ext {
-    audio_session_t   session; /* audio session */
-};
-
-
-struct audio_port {
-    audio_port_handle_t      id;                /* port unique ID */
-    audio_port_role_t        role;              /* sink or source */
-    audio_port_type_t        type;              /* device, mix ... */
-    unsigned int             num_sample_rates;  /* number of sampling rates in following array */
-    unsigned int             sample_rates[AUDIO_PORT_MAX_SAMPLING_RATES];
-    unsigned int             num_channel_masks; /* number of channel masks in following array */
-    audio_channel_mask_t     channel_masks[AUDIO_PORT_MAX_CHANNEL_MASKS];
-    unsigned int             num_formats;       /* number of formats in following array */
-    audio_format_t           formats[AUDIO_PORT_MAX_FORMATS];
-    unsigned int             num_gains;         /* number of gains in following array */
-    struct audio_gain        gains[AUDIO_PORT_MAX_GAINS];
-    struct audio_port_config active_config;     /* current audio port configuration */
-    union {
-        struct audio_port_device_ext  device;
-        struct audio_port_mix_ext     mix;
-        struct audio_port_session_ext session;
-    } ext;
-};
-
-/* An audio patch represents a connection between one or more source ports and
- * one or more sink ports. Patches are connected and disconnected by audio policy manager or by
- * applications via framework APIs.
- * Each patch is identified by a handle at the interface used to create that patch. For instance,
- * when a patch is created by the audio HAL, the HAL allocates and returns a handle.
- * This handle is unique to a given audio HAL hardware module.
- * But the same patch receives another system wide unique handle allocated by the framework.
- * This unique handle is used for all transactions inside the framework.
- */
-typedef int audio_patch_handle_t;
-#define AUDIO_PATCH_HANDLE_NONE 0
-
-#define AUDIO_PATCH_PORTS_MAX   16
-
-struct audio_patch {
-    audio_patch_handle_t id;            /* patch unique ID */
-    unsigned int      num_sources;      /* number of sources in following array */
-    struct audio_port_config sources[AUDIO_PATCH_PORTS_MAX];
-    unsigned int      num_sinks;        /* number of sinks in following array */
-    struct audio_port_config sinks[AUDIO_PATCH_PORTS_MAX];
-};
-
-
-
-/* a HW synchronization source returned by the audio HAL */
-typedef uint32_t audio_hw_sync_t;
-
-/* an invalid HW synchronization source indicating an error */
-#define AUDIO_HW_SYNC_INVALID 0
-
-static inline bool audio_is_output_device(audio_devices_t device)
-{
-    if (((device & AUDIO_DEVICE_BIT_IN) == 0) &&
-            (popcount(device) == 1) && ((device & ~AUDIO_DEVICE_OUT_ALL) == 0))
-        return true;
-    else
-        return false;
-}
-
-static inline bool audio_is_input_device(audio_devices_t device)
-{
-    if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
-        device &= ~AUDIO_DEVICE_BIT_IN;
-        if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_IN_ALL) == 0))
-            return true;
-    }
-    return false;
-}
-
-static inline bool audio_is_output_devices(audio_devices_t device)
-{
-    return (device & AUDIO_DEVICE_BIT_IN) == 0;
-}
-
-static inline bool audio_is_a2dp_in_device(audio_devices_t device)
-{
-    if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
-        device &= ~AUDIO_DEVICE_BIT_IN;
-        if ((popcount(device) == 1) && (device & AUDIO_DEVICE_IN_BLUETOOTH_A2DP))
-            return true;
-    }
-    return false;
-}
-
-static inline bool audio_is_a2dp_out_device(audio_devices_t device)
-{
-    if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_ALL_A2DP))
-        return true;
-    else
-        return false;
-}
-
-// Deprecated - use audio_is_a2dp_out_device() instead
-static inline bool audio_is_a2dp_device(audio_devices_t device)
-{
-    return audio_is_a2dp_out_device(device);
-}
-
-static inline bool audio_is_bluetooth_sco_device(audio_devices_t device)
-{
-    if ((device & AUDIO_DEVICE_BIT_IN) == 0) {
-        if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_OUT_ALL_SCO) == 0))
-            return true;
-    } else {
-        device &= ~AUDIO_DEVICE_BIT_IN;
-        if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) == 0))
-            return true;
-    }
-
-    return false;
-}
-
-static inline bool audio_is_usb_out_device(audio_devices_t device)
-{
-    return ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_ALL_USB));
-}
-
-static inline bool audio_is_usb_in_device(audio_devices_t device)
-{
-    if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
-        device &= ~AUDIO_DEVICE_BIT_IN;
-        if (popcount(device) == 1 && (device & AUDIO_DEVICE_IN_ALL_USB) != 0)
-            return true;
-    }
-    return false;
-}
-
-/* OBSOLETE - use audio_is_usb_out_device() instead. */
-static inline bool audio_is_usb_device(audio_devices_t device)
-{
-    return audio_is_usb_out_device(device);
-}
-
-static inline bool audio_is_remote_submix_device(audio_devices_t device)
-{
-    if ((device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX) == AUDIO_DEVICE_OUT_REMOTE_SUBMIX
-            || (device & AUDIO_DEVICE_IN_REMOTE_SUBMIX) == AUDIO_DEVICE_IN_REMOTE_SUBMIX)
-        return true;
-    else
-        return false;
-}
-
-/* Returns true if:
- *  representation is valid, and
- *  there is at least one channel bit set which _could_ correspond to an input channel, and
- *  there are no channel bits set which could _not_ correspond to an input channel.
- * Otherwise returns false.
- */
-static inline bool audio_is_input_channel(audio_channel_mask_t channel)
-{
-    uint32_t bits = audio_channel_mask_get_bits(channel);
-    switch (audio_channel_mask_get_representation(channel)) {
-    case AUDIO_CHANNEL_REPRESENTATION_POSITION:
-        if (bits & ~AUDIO_CHANNEL_IN_ALL) {
-            bits = 0;
-        }
-        // fall through
-    case AUDIO_CHANNEL_REPRESENTATION_INDEX:
-        return bits != 0;
-    default:
-        return false;
-    }
-}
-
-/* Returns true if:
- *  representation is valid, and
- *  there is at least one channel bit set which _could_ correspond to an output channel, and
- *  there are no channel bits set which could _not_ correspond to an output channel.
- * Otherwise returns false.
- */
-static inline bool audio_is_output_channel(audio_channel_mask_t channel)
-{
-    uint32_t bits = audio_channel_mask_get_bits(channel);
-    switch (audio_channel_mask_get_representation(channel)) {
-    case AUDIO_CHANNEL_REPRESENTATION_POSITION:
-        if (bits & ~AUDIO_CHANNEL_OUT_ALL) {
-            bits = 0;
-        }
-        // fall through
-    case AUDIO_CHANNEL_REPRESENTATION_INDEX:
-        return bits != 0;
-    default:
-        return false;
-    }
-}
-
-/* Returns the number of channels from an input channel mask,
- * used in the context of audio input or recording.
- * If a channel bit is set which could _not_ correspond to an input channel,
- * it is excluded from the count.
- * Returns zero if the representation is invalid.
- */
-static inline uint32_t audio_channel_count_from_in_mask(audio_channel_mask_t channel)
-{
-    uint32_t bits = audio_channel_mask_get_bits(channel);
-    switch (audio_channel_mask_get_representation(channel)) {
-    case AUDIO_CHANNEL_REPRESENTATION_POSITION:
-        // TODO: We can now merge with from_out_mask and remove anding
-        bits &= AUDIO_CHANNEL_IN_ALL;
-        // fall through
-    case AUDIO_CHANNEL_REPRESENTATION_INDEX:
-        return popcount(bits);
-    default:
-        return 0;
-    }
-}
-
-/* Returns the number of channels from an output channel mask,
- * used in the context of audio output or playback.
- * If a channel bit is set which could _not_ correspond to an output channel,
- * it is excluded from the count.
- * Returns zero if the representation is invalid.
- */
-static inline uint32_t audio_channel_count_from_out_mask(audio_channel_mask_t channel)
-{
-    uint32_t bits = audio_channel_mask_get_bits(channel);
-    switch (audio_channel_mask_get_representation(channel)) {
-    case AUDIO_CHANNEL_REPRESENTATION_POSITION:
-        // TODO: We can now merge with from_in_mask and remove anding
-        bits &= AUDIO_CHANNEL_OUT_ALL;
-        // fall through
-    case AUDIO_CHANNEL_REPRESENTATION_INDEX:
-        return popcount(bits);
-    default:
-        return 0;
-    }
-}
-
-/* Derive an output channel mask for position assignment from a channel count.
- * This is to be used when the content channel mask is unknown. The 1, 2, 4, 5, 6, 7 and 8 channel
- * cases are mapped to the standard game/home-theater layouts, but note that 4 is mapped to quad,
- * and not stereo + FC + mono surround. A channel count of 3 is arbitrarily mapped to stereo + FC
- * for continuity with stereo.
- * Returns the matching channel mask,
- * or AUDIO_CHANNEL_NONE if the channel count is zero,
- * or AUDIO_CHANNEL_INVALID if the channel count exceeds that of the
- * configurations for which a default output channel mask is defined.
- */
-static inline audio_channel_mask_t audio_channel_out_mask_from_count(uint32_t channel_count)
-{
-    uint32_t bits;
-    switch (channel_count) {
-    case 0:
-        return AUDIO_CHANNEL_NONE;
-    case 1:
-        bits = AUDIO_CHANNEL_OUT_MONO;
-        break;
-    case 2:
-        bits = AUDIO_CHANNEL_OUT_STEREO;
-        break;
-    case 3:
-        bits = AUDIO_CHANNEL_OUT_STEREO | AUDIO_CHANNEL_OUT_FRONT_CENTER;
-        break;
-    case 4: // 4.0
-        bits = AUDIO_CHANNEL_OUT_QUAD;
-        break;
-    case 5: // 5.0
-        bits = AUDIO_CHANNEL_OUT_QUAD | AUDIO_CHANNEL_OUT_FRONT_CENTER;
-        break;
-    case 6: // 5.1
-        bits = AUDIO_CHANNEL_OUT_5POINT1;
-        break;
-    case 7: // 6.1
-        bits = AUDIO_CHANNEL_OUT_5POINT1 | AUDIO_CHANNEL_OUT_BACK_CENTER;
-        break;
-    case 8:
-        bits = AUDIO_CHANNEL_OUT_7POINT1;
-        break;
-    default:
-        return AUDIO_CHANNEL_INVALID;
-    }
-    return audio_channel_mask_from_representation_and_bits(
-            AUDIO_CHANNEL_REPRESENTATION_POSITION, bits);
-}
-
-/* Derive an input channel mask for position assignment from a channel count.
- * Currently handles only mono and stereo.
- * Returns the matching channel mask,
- * or AUDIO_CHANNEL_NONE if the channel count is zero,
- * or AUDIO_CHANNEL_INVALID if the channel count exceeds that of the
- * configurations for which a default input channel mask is defined.
- */
-static inline audio_channel_mask_t audio_channel_in_mask_from_count(uint32_t channel_count)
-{
-    uint32_t bits;
-    switch (channel_count) {
-    case 0:
-        return AUDIO_CHANNEL_NONE;
-    case 1:
-        bits = AUDIO_CHANNEL_IN_MONO;
-        break;
-    case 2:
-        bits = AUDIO_CHANNEL_IN_STEREO;
-        break;
-    default:
-        return AUDIO_CHANNEL_INVALID;
-    }
-    return audio_channel_mask_from_representation_and_bits(
-            AUDIO_CHANNEL_REPRESENTATION_POSITION, bits);
-}
-
-/* Derive a channel mask for index assignment from a channel count.
- * Returns the matching channel mask,
- * or AUDIO_CHANNEL_NONE if the channel count is zero,
- * or AUDIO_CHANNEL_INVALID if the channel count exceeds AUDIO_CHANNEL_COUNT_MAX.
- */
-static inline audio_channel_mask_t audio_channel_mask_for_index_assignment_from_count(
-        uint32_t channel_count)
-{
-    if (channel_count == 0) {
-        return AUDIO_CHANNEL_NONE;
-    }
-    if (channel_count > AUDIO_CHANNEL_COUNT_MAX) {
-        return AUDIO_CHANNEL_INVALID;
-    }
-    uint32_t bits = (1 << channel_count) - 1;
-    return audio_channel_mask_from_representation_and_bits(
-            AUDIO_CHANNEL_REPRESENTATION_INDEX, bits);
-}
-
-static inline bool audio_is_valid_format(audio_format_t format)
-{
-    switch (format & AUDIO_FORMAT_MAIN_MASK) {
-    case AUDIO_FORMAT_PCM:
-        switch (format) {
-        case AUDIO_FORMAT_PCM_16_BIT:
-        case AUDIO_FORMAT_PCM_8_BIT:
-        case AUDIO_FORMAT_PCM_32_BIT:
-        case AUDIO_FORMAT_PCM_8_24_BIT:
-        case AUDIO_FORMAT_PCM_FLOAT:
-        case AUDIO_FORMAT_PCM_24_BIT_PACKED:
-            return true;
-        default:
-            return false;
-        }
-        /* not reached */
-    case AUDIO_FORMAT_MP3:
-    case AUDIO_FORMAT_AMR_NB:
-    case AUDIO_FORMAT_AMR_WB:
-    case AUDIO_FORMAT_AAC:
-    case AUDIO_FORMAT_HE_AAC_V1:
-    case AUDIO_FORMAT_HE_AAC_V2:
-    case AUDIO_FORMAT_VORBIS:
-    case AUDIO_FORMAT_OPUS:
-    case AUDIO_FORMAT_AC3:
-    case AUDIO_FORMAT_E_AC3:
-        return true;
-    default:
-        return false;
-    }
-}
-
-static inline bool audio_is_linear_pcm(audio_format_t format)
-{
-    return ((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM);
-}
-
-static inline size_t audio_bytes_per_sample(audio_format_t format)
-{
-    size_t size = 0;
-
-    switch (format) {
-    case AUDIO_FORMAT_PCM_32_BIT:
-    case AUDIO_FORMAT_PCM_8_24_BIT:
-        size = sizeof(int32_t);
-        break;
-    case AUDIO_FORMAT_PCM_24_BIT_PACKED:
-        size = sizeof(uint8_t) * 3;
-        break;
-    case AUDIO_FORMAT_PCM_16_BIT:
-        size = sizeof(int16_t);
-        break;
-    case AUDIO_FORMAT_PCM_8_BIT:
-        size = sizeof(uint8_t);
-        break;
-    case AUDIO_FORMAT_PCM_FLOAT:
-        size = sizeof(float);
-        break;
-    default:
-        break;
-    }
-    return size;
-}
-
-/* converts device address to string sent to audio HAL via set_parameters */
-static char *audio_device_address_to_parameter(audio_devices_t device, const char *address)
-{
-    const size_t kSize = AUDIO_DEVICE_MAX_ADDRESS_LEN + sizeof("a2dp_sink_address=");
-    char param[kSize];
-
-    if (device & AUDIO_DEVICE_OUT_ALL_A2DP)
-        snprintf(param, kSize, "%s=%s", "a2dp_sink_address", address);
-    else if (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)
-        snprintf(param, kSize, "%s=%s", "mix", address);
-    else
-        snprintf(param, kSize, "%s", address);
-
-    return strdup(param);
-}
-
-
-__END_DECLS
-
-#endif  // ANDROID_AUDIO_CORE_H
diff --git a/include/system/audio_policy.h b/include/system/audio_policy.h
deleted file mode 100644
index 2881104..0000000
--- a/include/system/audio_policy.h
+++ /dev/null
@@ -1,103 +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.
- */
-
-
-#ifndef ANDROID_AUDIO_POLICY_CORE_H
-#define ANDROID_AUDIO_POLICY_CORE_H
-
-#include <stdint.h>
-#include <sys/cdefs.h>
-#include <sys/types.h>
-
-#include <cutils/bitops.h>
-
-__BEGIN_DECLS
-
-/* The enums were moved here mostly from
- * frameworks/base/include/media/AudioSystem.h
- */
-
-/* device categories used for audio_policy->set_force_use() */
-typedef enum {
-    AUDIO_POLICY_FORCE_NONE,
-    AUDIO_POLICY_FORCE_SPEAKER,
-    AUDIO_POLICY_FORCE_HEADPHONES,
-    AUDIO_POLICY_FORCE_BT_SCO,
-    AUDIO_POLICY_FORCE_BT_A2DP,
-    AUDIO_POLICY_FORCE_WIRED_ACCESSORY,
-    AUDIO_POLICY_FORCE_BT_CAR_DOCK,
-    AUDIO_POLICY_FORCE_BT_DESK_DOCK,
-    AUDIO_POLICY_FORCE_ANALOG_DOCK,
-    AUDIO_POLICY_FORCE_DIGITAL_DOCK,
-    AUDIO_POLICY_FORCE_NO_BT_A2DP, /* A2DP sink is not preferred to speaker or wired HS */
-    AUDIO_POLICY_FORCE_SYSTEM_ENFORCED,
-    AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED,
-
-    AUDIO_POLICY_FORCE_CFG_CNT,
-    AUDIO_POLICY_FORCE_CFG_MAX = AUDIO_POLICY_FORCE_CFG_CNT - 1,
-
-    AUDIO_POLICY_FORCE_DEFAULT = AUDIO_POLICY_FORCE_NONE,
-} audio_policy_forced_cfg_t;
-
-/* usages used for audio_policy->set_force_use() */
-typedef enum {
-    AUDIO_POLICY_FORCE_FOR_COMMUNICATION,
-    AUDIO_POLICY_FORCE_FOR_MEDIA,
-    AUDIO_POLICY_FORCE_FOR_RECORD,
-    AUDIO_POLICY_FORCE_FOR_DOCK,
-    AUDIO_POLICY_FORCE_FOR_SYSTEM,
-    AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO,
-
-    AUDIO_POLICY_FORCE_USE_CNT,
-    AUDIO_POLICY_FORCE_USE_MAX = AUDIO_POLICY_FORCE_USE_CNT - 1,
-} audio_policy_force_use_t;
-
-/* device connection states used for audio_policy->set_device_connection_state()
- */
-typedef enum {
-    AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
-    AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
-
-    AUDIO_POLICY_DEVICE_STATE_CNT,
-    AUDIO_POLICY_DEVICE_STATE_MAX = AUDIO_POLICY_DEVICE_STATE_CNT - 1,
-} audio_policy_dev_state_t;
-
-typedef enum {
-    /* Used to generate a tone to notify the user of a
-     * notification/alarm/ringtone while they are in a call. */
-    AUDIO_POLICY_TONE_IN_CALL_NOTIFICATION = 0,
-
-    AUDIO_POLICY_TONE_CNT,
-    AUDIO_POLICY_TONE_MAX                  = AUDIO_POLICY_TONE_CNT - 1,
-} audio_policy_tone_t;
-
-
-static inline bool audio_is_low_visibility(audio_stream_type_t stream)
-{
-    switch (stream) {
-    case AUDIO_STREAM_SYSTEM:
-    case AUDIO_STREAM_NOTIFICATION:
-    case AUDIO_STREAM_RING:
-        return true;
-    default:
-        return false;
-    }
-}
-
-
-__END_DECLS
-
-#endif  // ANDROID_AUDIO_POLICY_CORE_H
diff --git a/include/system/camera.h b/include/system/camera.h
index 7a4dd53..5d0873a 100644
--- a/include/system/camera.h
+++ b/include/system/camera.h
@@ -174,6 +174,22 @@
      * count is non-positive or too big to be realized.
      */
     CAMERA_CMD_SET_VIDEO_BUFFER_COUNT = 10,
+
+    /**
+     * Configure an explicit format to use for video recording metadata mode.
+     * This can be used to switch the format from the
+     * default IMPLEMENTATION_DEFINED gralloc format to some other
+     * device-supported format, and the default dataspace from the BT_709 color
+     * space to some other device-supported dataspace. arg1 is the HAL pixel
+     * format, and arg2 is the HAL dataSpace. This command returns
+     * INVALID_OPERATION error if it is sent after video recording is started,
+     * or the command is not supported at all.
+     *
+     * If the gralloc format is set to a format other than
+     * IMPLEMENTATION_DEFINED, then HALv3 devices will use gralloc usage flags
+     * of SW_READ_OFTEN.
+     */
+    CAMERA_CMD_SET_VIDEO_FORMAT = 11
 };
 
 /** camera fatal errors */
@@ -194,7 +210,12 @@
     /** The facing of the camera is opposite to that of the screen. */
     CAMERA_FACING_BACK = 0,
     /** The facing of the camera is the same as that of the screen. */
-    CAMERA_FACING_FRONT = 1
+    CAMERA_FACING_FRONT = 1,
+    /**
+     * The facing of the camera is not fixed relative to the screen.
+     * The cameras with this facing are external cameras, e.g. USB cameras.
+     */
+    CAMERA_FACING_EXTERNAL = 2
 };
 
 enum {
diff --git a/include/system/graphics.h b/include/system/graphics.h
index c3fca97..afd9f7b 100644
--- a/include/system/graphics.h
+++ b/include/system/graphics.h
@@ -45,9 +45,12 @@
     /*
      * "linear" color pixel formats:
      *
-     * The pixel formats below contain sRGB data but are otherwise treated
-     * as linear formats, i.e.: no special operation is performed when
-     * reading or writing into a buffer in one of these formats
+     * When used with ANativeWindow, the dataSpace field describes the color
+     * space of the buffer.
+     *
+     * The color space determines, for example, if the formats are linear or
+     * gamma-corrected; or whether any special operations are performed when
+     * reading or writing into a buffer in one of these formats.
      */
     HAL_PIXEL_FORMAT_RGBA_8888          = 1,
     HAL_PIXEL_FORMAT_RGBX_8888          = 2,
@@ -56,28 +59,6 @@
     HAL_PIXEL_FORMAT_BGRA_8888          = 5,
 
     /*
-     * sRGB color pixel formats:
-     *
-     * The red, green and blue components are stored in sRGB space, and converted
-     * to linear space when read, using the standard sRGB to linear equation:
-     *
-     * Clinear = Csrgb / 12.92                  for Csrgb <= 0.04045
-     *         = (Csrgb + 0.055 / 1.055)^2.4    for Csrgb >  0.04045
-     *
-     * When written the inverse transformation is performed:
-     *
-     * Csrgb = 12.92 * Clinear                  for Clinear <= 0.0031308
-     *       = 1.055 * Clinear^(1/2.4) - 0.055  for Clinear >  0.0031308
-     *
-     *
-     *  The alpha component, if present, is always stored in linear space and
-     *  is left unmodified when read or written.
-     *
-     */
-    HAL_PIXEL_FORMAT_sRGB_A_8888        = 0xC,
-    HAL_PIXEL_FORMAT_sRGB_X_8888        = 0xD,
-
-    /*
      * 0x100 - 0x1FF
      *
      * This range is reserved for pixel formats that are specific to the HAL
@@ -111,6 +92,8 @@
      *   cr_offset = y_size
      *   cb_offset = y_size + c_size
      *
+     * When used with ANativeWindow, the dataSpace field describes the color
+     * space of the buffer.
      */
     HAL_PIXEL_FORMAT_YV12   = 0x32315659, // YCrCb 4:2:0 Planar
 
@@ -135,6 +118,8 @@
      *
      *   size = stride * height
      *
+     * When used with ANativeWindow, the dataSpace field describes the color
+     * space of the buffer.
      */
     HAL_PIXEL_FORMAT_Y8     = 0x20203859,
 
@@ -159,6 +144,11 @@
      *
      *   size = stride * height * 2
      *
+     * When used with ANativeWindow, the dataSpace field describes the color
+     * space of the buffer, except that dataSpace field
+     * HAL_DATASPACE_DEPTH indicates that this buffer contains a depth
+     * image where each sample is a distance value measured by a depth camera,
+     * plus an associated confidence value.
      */
     HAL_PIXEL_FORMAT_Y16    = 0x20363159,
 
@@ -167,7 +157,7 @@
      *
      * This format is exposed outside of the camera HAL to applications.
      *
-     * RAW_SENSOR is a single-channel, 16-bit, little endian  format, typically
+     * RAW16 is a single-channel, 16-bit, little endian format, typically
      * representing raw Bayer-pattern images from an image sensor, with minimal
      * processing.
      *
@@ -193,9 +183,12 @@
      *    - GRALLOC_USAGE_HW_CAMERA_*
      *    - GRALLOC_USAGE_SW_*
      *    - GRALLOC_USAGE_RENDERSCRIPT
+     *
+     * When used with ANativeWindow, the dataSpace should be
+     * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
+     * extra metadata to define.
      */
     HAL_PIXEL_FORMAT_RAW16 = 0x20,
-    HAL_PIXEL_FORMAT_RAW_SENSOR = 0x20, // TODO(rubenbrunk): Remove RAW_SENSOR.
 
     /*
      * Android RAW10 format:
@@ -244,10 +237,64 @@
      *    - GRALLOC_USAGE_HW_CAMERA_*
      *    - GRALLOC_USAGE_SW_*
      *    - GRALLOC_USAGE_RENDERSCRIPT
+     *
+     * When used with ANativeWindow, the dataSpace field should be
+     * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
+     * extra metadata to define.
      */
     HAL_PIXEL_FORMAT_RAW10 = 0x25,
 
     /*
+     * Android RAW12 format:
+     *
+     * This format is exposed outside of camera HAL to applications.
+     *
+     * RAW12 is a single-channel, 12-bit per pixel, densely packed in each row,
+     * unprocessed format, usually representing raw Bayer-pattern images coming from
+     * an image sensor.
+     *
+     * In an image buffer with this format, starting from the first pixel of each
+     * row, each two consecutive pixels are packed into 3 bytes (24 bits). The first
+     * and second byte contains the top 8 bits of first and second pixel. The third
+     * byte contains the 4 least significant bits of the two pixels, the exact layout
+     * data for each two consecutive pixels is illustrated below (Pi[j] stands for
+     * the jth bit of the ith pixel):
+     *
+     *           bit 7                                            bit 0
+     *          ======|======|======|======|======|======|======|======|
+     * Byte 0: |P0[11]|P0[10]|P0[ 9]|P0[ 8]|P0[ 7]|P0[ 6]|P0[ 5]|P0[ 4]|
+     *         |------|------|------|------|------|------|------|------|
+     * Byte 1: |P1[11]|P1[10]|P1[ 9]|P1[ 8]|P1[ 7]|P1[ 6]|P1[ 5]|P1[ 4]|
+     *         |------|------|------|------|------|------|------|------|
+     * Byte 2: |P1[ 3]|P1[ 2]|P1[ 1]|P1[ 0]|P0[ 3]|P0[ 2]|P0[ 1]|P0[ 0]|
+     *          =======================================================
+     *
+     * This format assumes:
+     * - a width multiple of 4 pixels
+     * - an even height
+     * - a vertical stride equal to the height
+     * - strides are specified in bytes, not in pixels
+     *
+     *   size = stride * height
+     *
+     * When stride is equal to width * (12 / 8), there will be no padding bytes at
+     * the end of each row, the entire image data is densely packed. When stride is
+     * larger than width * (12 / 8), padding bytes will be present at the end of
+     * each row (including the last row).
+     *
+     * This format must be accepted by the gralloc module when used with the
+     * following usage flags:
+     *    - GRALLOC_USAGE_HW_CAMERA_*
+     *    - GRALLOC_USAGE_SW_*
+     *    - GRALLOC_USAGE_RENDERSCRIPT
+     *
+     * When used with ANativeWindow, the dataSpace field should be
+     * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
+     * extra metadata to define.
+     */
+    HAL_PIXEL_FORMAT_RAW12 = 0x26,
+
+    /*
      * Android opaque RAW format:
      *
      * This format is exposed outside of the camera HAL to applications.
@@ -261,6 +308,10 @@
      *    - GRALLOC_USAGE_HW_CAMERA_*
      *    - GRALLOC_USAGE_SW_*
      *    - GRALLOC_USAGE_RENDERSCRIPT
+     *
+     * When used with ANativeWindow, the dataSpace field should be
+     * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
+     * extra metadata to define.
      */
     HAL_PIXEL_FORMAT_RAW_OPAQUE = 0x24,
 
@@ -276,6 +327,16 @@
      *
      * Buffers of this format must have a height of 1, and width equal to their
      * size in bytes.
+     *
+     * When used with ANativeWindow, the mapping of the dataSpace field to
+     * buffer contents for BLOB is as follows:
+     *
+     *  dataSpace value               | Buffer contents
+     * -------------------------------+-----------------------------------------
+     *  HAL_DATASPACE_JFIF            | An encoded JPEG image
+     *  HAL_DATASPACE_DEPTH           | An android_depth_points buffer
+     *  Other                         | Unsupported
+     *
      */
     HAL_PIXEL_FORMAT_BLOB = 0x21,
 
@@ -292,28 +353,89 @@
      * framework will assume that sampling the texture will always return an
      * alpha value of 1.0 (i.e. the buffer contains only opaque pixel values).
      *
+     * When used with ANativeWindow, the dataSpace field describes the color
+     * space of the buffer.
      */
     HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22,
 
     /*
-     * Android flexible YCbCr formats
+     * Android flexible YCbCr 4:2:0 formats
      *
-     * This format allows platforms to use an efficient YCbCr/YCrCb buffer
-     * layout, while still describing the buffer layout in a way accessible to
-     * the CPU in a device-independent manner.  While called YCbCr, it can be
+     * This format allows platforms to use an efficient YCbCr/YCrCb 4:2:0
+     * buffer layout, while still describing the general format in a
+     * layout-independent manner.  While called YCbCr, it can be
      * used to describe formats with either chromatic ordering, as well as
      * whole planar or semiplanar layouts.
      *
      * struct android_ycbcr (below) is the the struct used to describe it.
      *
      * This format must be accepted by the gralloc module when
-     * USAGE_HW_CAMERA_WRITE and USAGE_SW_READ_* are set.
+     * USAGE_SW_WRITE_* or USAGE_SW_READ_* are set.
      *
      * This format is locked for use by gralloc's (*lock_ycbcr) method, and
      * locking with the (*lock) method will return an error.
+     *
+     * When used with ANativeWindow, the dataSpace field describes the color
+     * space of the buffer.
      */
     HAL_PIXEL_FORMAT_YCbCr_420_888 = 0x23,
 
+    /*
+     * Android flexible YCbCr 4:2:2 formats
+     *
+     * This format allows platforms to use an efficient YCbCr/YCrCb 4:2:2
+     * buffer layout, while still describing the general format in a
+     * layout-independent manner.  While called YCbCr, it can be
+     * used to describe formats with either chromatic ordering, as well as
+     * whole planar or semiplanar layouts.
+     *
+     * This format is currently only used by SW readable buffers
+     * produced by MediaCodecs, so the gralloc module can ignore this format.
+     */
+    HAL_PIXEL_FORMAT_YCbCr_422_888 = 0x27,
+
+    /*
+     * Android flexible YCbCr 4:4:4 formats
+     *
+     * This format allows platforms to use an efficient YCbCr/YCrCb 4:4:4
+     * buffer layout, while still describing the general format in a
+     * layout-independent manner.  While called YCbCr, it can be
+     * used to describe formats with either chromatic ordering, as well as
+     * whole planar or semiplanar layouts.
+     *
+     * This format is currently only used by SW readable buffers
+     * produced by MediaCodecs, so the gralloc module can ignore this format.
+     */
+    HAL_PIXEL_FORMAT_YCbCr_444_888 = 0x28,
+
+    /*
+     * Android flexible RGB 888 formats
+     *
+     * This format allows platforms to use an efficient RGB/BGR/RGBX/BGRX
+     * buffer layout, while still describing the general format in a
+     * layout-independent manner.  While called RGB, it can be
+     * used to describe formats with either color ordering and optional
+     * padding, as well as whole planar layout.
+     *
+     * This format is currently only used by SW readable buffers
+     * produced by MediaCodecs, so the gralloc module can ignore this format.
+     */
+    HAL_PIXEL_FORMAT_FLEX_RGB_888 = 0x29,
+
+    /*
+     * Android flexible RGBA 8888 formats
+     *
+     * This format allows platforms to use an efficient RGBA/BGRA/ARGB/ABGR
+     * buffer layout, while still describing the general format in a
+     * layout-independent manner.  While called RGBA, it can be
+     * used to describe formats with any of the component orderings, as
+     * well as whole planar layout.
+     *
+     * This format is currently only used by SW readable buffers
+     * produced by MediaCodecs, so the gralloc module can ignore this format.
+     */
+    HAL_PIXEL_FORMAT_FLEX_RGBA_8888 = 0x2A,
+
     /* Legacy formats (deprecated), used by ImageFormat.java */
     HAL_PIXEL_FORMAT_YCbCr_422_SP       = 0x10, // NV16
     HAL_PIXEL_FORMAT_YCrCb_420_SP       = 0x11, // NV21
@@ -355,6 +477,48 @@
 };
 
 /**
+ * Structure used to define depth point clouds for format HAL_PIXEL_FORMAT_BLOB
+ * with dataSpace value of HAL_DATASPACE_DEPTH.
+ * When locking a native buffer of the above format and dataSpace value,
+ * the vaddr pointer can be cast to this structure.
+ *
+ * A variable-length list of (x,y,z, confidence) 3D points, as floats.  (x, y,
+ * z) represents a measured point's position, with the coordinate system defined
+ * by the data source.  Confidence represents the estimated likelihood that this
+ * 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
+ *
+ * @xyz_points is the flexible array of floating-point values.
+ *   It contains (num_points) * 4 floats.
+ *
+ *   For example:
+ *     android_depth_points d = get_depth_buffer();
+ *     struct {
+ *       float x; float y; float z; float confidence;
+ *     } firstPoint, lastPoint;
+ *
+ *     firstPoint.x = d.xyzc_points[0];
+ *     firstPoint.y = d.xyzc_points[1];
+ *     firstPoint.z = d.xyzc_points[2];
+ *     firstPoint.confidence = d.xyzc_points[3];
+ *     lastPoint.x = d.xyzc_points[(d.num_points - 1) * 4 + 0];
+ *     lastPoint.y = d.xyzc_points[(d.num_points - 1) * 4 + 1];
+ *     lastPoint.z = d.xyzc_points[(d.num_points - 1) * 4 + 2];
+ *     lastPoint.confidence = d.xyzc_points[(d.num_points - 1) * 4 + 3];
+ */
+
+struct android_depth_points {
+    uint32_t num_points;
+
+    /** reserved for future use, set to 0 by gralloc's (*lock)() */
+    uint32_t reserved[8];
+
+    float xyzc_points[];
+};
+
+/**
  * Transformation definitions
  *
  * IMPORTANT NOTE:
@@ -378,19 +542,33 @@
 };
 
 /**
- * Colorspace Definitions
+ * Dataspace Definitions
  * ======================
  *
- * Colorspace is the definition of how pixel values should be interpreted.
- * It includes primaries (including white point) and the transfer
- * characteristic function, which describes both gamma curve and numeric
- * range (within the bit depth).
+ * Dataspace is the definition of how pixel values should be interpreted.
+ *
+ * For many formats, this is the colorspace of the image data, which includes
+ * primaries (including white point) and the transfer characteristic function,
+ * which describes both gamma curve and numeric range (within the bit depth).
+ *
+ * Other dataspaces include depth measurement data from a depth camera.
  */
 
-enum {
+typedef enum android_dataspace {
     /*
-     * Arbitrary colorspace with manually defined characteristics.
-     * Colorspace definition must be communicated separately.
+     * Default-assumption data space, when not explicitly specified.
+     *
+     * It is safest to assume the buffer is an image with sRGB primaries and
+     * encoding ranges, but the consumer and/or the producer of the data may
+     * simply be using defaults. No automatic gamma transform should be
+     * expected, except for a possible display gamma transform when drawn to a
+     * screen.
+     */
+    HAL_DATASPACE_UNKNOWN = 0x0,
+
+    /*
+     * Arbitrary dataspace with manually defined characteristics.  Definition
+     * for colorspaces or other meaning must be communicated separately.
      *
      * This is used when specifying primaries, transfer characteristics,
      * etc. separately.
@@ -399,7 +577,57 @@
      * where a colorspace can have separately defined primaries, transfer
      * characteristics, etc.
      */
-    HAL_COLORSPACE_ARBITRARY = 0x1,
+    HAL_DATASPACE_ARBITRARY = 0x1,
+
+    /*
+     * RGB Colorspaces
+     * -----------------
+     *
+     * Primaries are given using (x,y) coordinates in the CIE 1931 definition
+     * of x and y specified by ISO 11664-1.
+     *
+     * Transfer characteristics are the opto-electronic transfer characteristic
+     * at the source as a function of linear optical intensity (luminance).
+     */
+
+    /*
+     * sRGB linear encoding:
+     *
+     * The red, green, and blue components are stored in sRGB space, but
+     * are linear, not gamma-encoded.
+     * The RGB primaries and the white point are the same as BT.709.
+     *
+     * The values are encoded using the full range ([0,255] for 8-bit) for all
+     * components.
+     */
+    HAL_DATASPACE_SRGB_LINEAR = 0x200,
+
+    /*
+     * sRGB gamma encoding:
+     *
+     * The red, green and blue components are stored in sRGB space, and
+     * converted to linear space when read, using the standard sRGB to linear
+     * equation:
+     *
+     * Clinear = Csrgb / 12.92                  for Csrgb <= 0.04045
+     *         = (Csrgb + 0.055 / 1.055)^2.4    for Csrgb >  0.04045
+     *
+     * When written the inverse transformation is performed:
+     *
+     * Csrgb = 12.92 * Clinear                  for Clinear <= 0.0031308
+     *       = 1.055 * Clinear^(1/2.4) - 0.055  for Clinear >  0.0031308
+     *
+     *
+     * The alpha component, if present, is always stored in linear space and
+     * is left unmodified when read or written.
+     *
+     * The RGB primaries and the white point are the same as BT.709.
+     *
+     * The values are encoded using the full range ([0,255] for 8-bit) for all
+     * components.
+     *
+     */
+    HAL_DATASPACE_SRGB = 0x201,
 
     /*
      * YCbCr Colorspaces
@@ -429,7 +657,7 @@
      *  red             0.640   0.330
      *  white (D65)     0.3127  0.3290
      */
-    HAL_COLORSPACE_JFIF = 0x101,
+    HAL_DATASPACE_JFIF = 0x101,
 
     /*
      * ITU-R Recommendation 601 (BT.601) - 625-line
@@ -456,7 +684,7 @@
      *  red             0.640   0.330
      *  white (D65)     0.3127  0.3290
      */
-    HAL_COLORSPACE_BT601_625 = 0x102,
+    HAL_DATASPACE_BT601_625 = 0x102,
 
     /*
      * ITU-R Recommendation 601 (BT.601) - 525-line
@@ -483,7 +711,7 @@
      *  red             0.630   0.340
      *  white (D65)     0.3127  0.3290
      */
-    HAL_COLORSPACE_BT601_525 = 0x103,
+    HAL_DATASPACE_BT601_525 = 0x103,
 
     /*
      * ITU-R Recommendation 709 (BT.709)
@@ -504,8 +732,29 @@
      *  red             0.640   0.330
      *  white (D65)     0.3127  0.3290
      */
-    HAL_COLORSPACE_BT709 = 0x104,
-};
+    HAL_DATASPACE_BT709 = 0x104,
+
+    /*
+     * The buffer contains depth ranging measurements from a depth camera.
+     * This value is valid with formats:
+     *    HAL_PIXEL_FORMAT_Y16: 16-bit samples, consisting of a depth measurement
+     *       and an associated confidence value. The 3 MSBs of the sample make
+     *       up the confidence value, and the low 13 LSBs of the sample make up
+     *       the depth measurement.
+     *       For the confidence section, 0 means 100% confidence, 1 means 0%
+     *       confidence. The mapping to a linear float confidence value between
+     *       0.f and 1.f can be obtained with
+     *         float confidence = (((depthSample >> 13) - 1) & 0x7) / 7.0f;
+     *       The depth measurement can be extracted simply with
+     *         uint16_t range = (depthSample & 0x1FFF);
+     *    HAL_PIXEL_FORMAT_BLOB: A depth point cloud, as
+     *       a variable-length float (x,y,z, confidence) coordinate point list.
+     *       The point cloud will be represented with the android_depth_points
+     *       structure.
+     */
+    HAL_DATASPACE_DEPTH = 0x1000
+
+} android_dataspace_t;
 
 #ifdef __cplusplus
 }
diff --git a/include/system/radio.h b/include/system/radio.h
new file mode 100644
index 0000000..a088526
--- /dev/null
+++ b/include/system/radio.h
@@ -0,0 +1,247 @@
+/*
+ * 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 ANDROID_RADIO_H
+#define ANDROID_RADIO_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+
+#define RADIO_NUM_BANDS_MAX     16
+#define RADIO_NUM_SPACINGS_MAX  16
+#define RADIO_STRING_LEN_MAX    128
+
+/*
+ * Radio hardware module class. A given radio hardware module HAL is of one class
+ * only. The platform can not have more than one hardware module of each class.
+ * Current version of the framework only supports RADIO_CLASS_AM_FM.
+ */
+typedef enum {
+    RADIO_CLASS_AM_FM = 0,  /* FM (including HD radio) and AM */
+    RADIO_CLASS_SAT   = 1,  /* Satellite Radio */
+    RADIO_CLASS_DT    = 2,  /* Digital Radio (DAB) */
+} radio_class_t;
+
+/* value for field "type" of radio band described in struct radio_hal_band_config */
+typedef enum {
+    RADIO_BAND_AM     = 0,  /* Amplitude Modulation band: LW, MW, SW */
+    RADIO_BAND_FM     = 1,  /* Frequency Modulation band: FM */
+    RADIO_BAND_FM_HD  = 2,  /* FM HD Radio / DRM (IBOC) */
+    RADIO_BAND_AM_HD  = 3,  /* AM HD Radio / DRM (IBOC) */
+} radio_band_t;
+
+/* RDS variant implemented. A struct radio_hal_fm_band_config can list none or several. */
+enum {
+    RADIO_RDS_NONE   = 0x0,
+    RADIO_RDS_WORLD  = 0x01,
+    RADIO_RDS_US     = 0x02,
+};
+typedef unsigned int radio_rds_t;
+
+/* FM deemphasis variant implemented. A struct radio_hal_fm_band_config can list one or more. */
+enum {
+    RADIO_DEEMPHASIS_50   = 0x1,
+    RADIO_DEEMPHASIS_75   = 0x2,
+};
+typedef unsigned int radio_deemphasis_t;
+
+/* Region a particular radio band configuration corresponds to. Not used at the HAL.
+ * Derived by the framework when converting the band descriptors retrieved from the HAL to
+ * individual band descriptors for each supported region. */
+typedef enum {
+    RADIO_REGION_NONE  = -1,
+    RADIO_REGION_ITU_1 = 0,
+    RADIO_REGION_ITU_2 = 1,
+    RADIO_REGION_OIRT  = 2,
+    RADIO_REGION_JAPAN = 3,
+    RADIO_REGION_KOREA = 4,
+} radio_region_t;
+
+/* scanning direction for scan() and step() tuner APIs */
+typedef enum {
+    RADIO_DIRECTION_UP,
+    RADIO_DIRECTION_DOWN
+} radio_direction_t;
+
+/* unique handle allocated to a radio module */
+typedef unsigned int radio_handle_t;
+
+/* Opaque meta data structure used by radio meta data API (see system/radio_metadata.h) */
+typedef struct radio_medtadata radio_metadata_t;
+
+
+/* Additional attributes for an FM band configuration */
+typedef struct radio_hal_fm_band_config {
+    radio_deemphasis_t  deemphasis; /* deemphasis variant */
+    bool                stereo;     /* stereo supported */
+    radio_rds_t         rds;        /* RDS variants supported */
+    bool                ta;         /* Traffic Announcement supported */
+    bool                af;         /* Alternate Frequency supported */
+} radio_hal_fm_band_config_t;
+
+/* Additional attributes for an AM band configuration */
+typedef struct radio_hal_am_band_config {
+    bool                stereo;     /* stereo supported */
+} radio_hal_am_band_config_t;
+
+/* Radio band configuration. Describes a given band supported by the radio module.
+ * The HAL can expose only one band per type with the the maximum range supported and all options.
+ * THe framework will derive the actual regions were this module can operate and expose separate
+ * band configurations for applications to chose from. */
+typedef struct radio_hal_band_config {
+    radio_band_t type;
+    bool         antenna_connected;
+    unsigned int lower_limit;
+    unsigned int upper_limit;
+    unsigned int num_spacings;
+    unsigned int spacings[RADIO_NUM_SPACINGS_MAX];
+    union {
+        radio_hal_fm_band_config_t fm;
+        radio_hal_am_band_config_t am;
+    };
+} radio_hal_band_config_t;
+
+/* Used internally by the framework to represent a band for s specific region */
+typedef struct radio_band_config {
+    radio_region_t  region;
+    radio_hal_band_config_t band;
+} radio_band_config_t;
+
+
+/* Exposes properties of a given hardware radio module.
+ * NOTE: current framework implementation supports only one audio source (num_audio_sources = 1).
+ * The source corresponds to AUDIO_DEVICE_IN_FM_TUNER.
+ * If more than one tuner is supported (num_tuners > 1), only one can be connected to the audio
+ * source. */
+typedef struct radio_hal_properties {
+    radio_class_t   class_id;   /* Class of this module. E.g RADIO_CLASS_AM_FM */
+    char            implementor[RADIO_STRING_LEN_MAX];  /* implementor name */
+    char            product[RADIO_STRING_LEN_MAX];  /* product name */
+    char            version[RADIO_STRING_LEN_MAX];  /* product version */
+    char            serial[RADIO_STRING_LEN_MAX];  /* serial number (for subscription services) */
+    unsigned int    num_tuners;     /* number of tuners controllable independently */
+    unsigned int    num_audio_sources; /* number of audio sources driven simultaneously */
+    bool            supports_capture; /* the hardware supports capture of audio source audio HAL */
+    unsigned int    num_bands;      /* number of band descriptors */
+    radio_hal_band_config_t bands[RADIO_NUM_BANDS_MAX]; /* band descriptors */
+} radio_hal_properties_t;
+
+/* Used internally by the framework. Same information as in struct radio_hal_properties plus a
+ * unique handle and one band configuration per region. */
+typedef struct radio_properties {
+    radio_handle_t      handle;
+    radio_class_t       class_id;
+    char                implementor[RADIO_STRING_LEN_MAX];
+    char                product[RADIO_STRING_LEN_MAX];
+    char                version[RADIO_STRING_LEN_MAX];
+    char                serial[RADIO_STRING_LEN_MAX];
+    unsigned int        num_tuners;
+    unsigned int        num_audio_sources;
+    bool                supports_capture;
+    unsigned int        num_bands;
+    radio_band_config_t bands[RADIO_NUM_BANDS_MAX];
+} radio_properties_t;
+
+/* Radio program information. Returned by the HAL with event RADIO_EVENT_TUNED.
+ * Contains information on currently tuned channel.
+ */
+typedef struct radio_program_info {
+    unsigned int     channel;   /* current channel. (e.g kHz for band type RADIO_BAND_FM) */
+    unsigned int     sub_channel; /* current sub channel. (used for RADIO_BAND_FM_HD) */
+    bool             tuned;     /* tuned to a program or not */
+    bool             stereo;    /* program is stereo or not */
+    bool             digital;   /* digital program or not (e.g HD Radio program) */
+    unsigned int     signal_strength; /* signal strength from 0 to 100 */
+    radio_metadata_t *metadata; /* non null if meta data are present (e.g PTY, song title ...) */
+} radio_program_info_t;
+
+
+/* Events sent to the framework via the HAL callback. An event can notify the completion of an
+ * asynchronous command (configuration, tune, scan ...) or a spontaneous change (antenna connection,
+ * failure, AF switching, meta data reception... */
+enum {
+    RADIO_EVENT_HW_FAILURE  = 0,  /* hardware module failure. Requires reopening the tuner */
+    RADIO_EVENT_CONFIG      = 1,  /* configuration change completed */
+    RADIO_EVENT_ANTENNA     = 2,  /* Antenna connected, disconnected */
+    RADIO_EVENT_TUNED       = 3,  /* tune, step, scan completed */
+    RADIO_EVENT_METADATA    = 4,  /* New meta data received */
+    RADIO_EVENT_TA          = 5,  /* Traffic announcement start or stop */
+    RADIO_EVENT_AF_SWITCH   = 6,  /* Switch to Alternate Frequency */
+    // begin framework only events
+    RADIO_EVENT_CONTROL     = 100, /* loss/gain of tuner control */
+    RADIO_EVENT_SERVER_DIED = 101, /* radio service died */
+};
+typedef unsigned int radio_event_type_t;
+
+/* Event passed to the framework by the HAL callback */
+typedef struct radio_hal_event {
+    radio_event_type_t  type;       /* event type */
+    int                 status;     /* used by RADIO_EVENT_CONFIG, RADIO_EVENT_TUNED */
+    union {
+        bool                    on;     /* RADIO_EVENT_ANTENNA, RADIO_EVENT_TA */
+        radio_hal_band_config_t config; /* RADIO_EVENT_CONFIG */
+        radio_program_info_t    info;   /* RADIO_EVENT_TUNED, RADIO_EVENT_AF_SWITCH */
+        radio_metadata_t        *metadata; /* RADIO_EVENT_METADATA */
+    };
+} radio_hal_event_t;
+
+/* Used internally by the framework. Same information as in struct radio_hal_event */
+typedef struct radio_event {
+    radio_event_type_t  type;
+    int                 status;
+    union {
+        bool                    on;
+        radio_band_config_t     config;
+        radio_program_info_t    info;
+        radio_metadata_t        *metadata; /* offset from start of struct when in shared memory */
+    };
+} radio_event_t;
+
+
+static radio_rds_t radio_rds_for_region(bool rds, radio_region_t region) {
+    if (!rds)
+        return RADIO_RDS_NONE;
+    switch(region) {
+        case RADIO_REGION_ITU_1:
+        case RADIO_REGION_OIRT:
+        case RADIO_REGION_JAPAN:
+        case RADIO_REGION_KOREA:
+            return RADIO_RDS_WORLD;
+        case RADIO_REGION_ITU_2:
+            return RADIO_RDS_US;
+        default:
+            return RADIO_REGION_NONE;
+    }
+}
+
+static radio_deemphasis_t radio_demephasis_for_region(radio_region_t region) {
+    switch(region) {
+        case RADIO_REGION_KOREA:
+        case RADIO_REGION_ITU_2:
+            return RADIO_DEEMPHASIS_75;
+        case RADIO_REGION_ITU_1:
+        case RADIO_REGION_OIRT:
+        case RADIO_REGION_JAPAN:
+        default:
+            return RADIO_DEEMPHASIS_50;
+    }
+}
+
+#endif  // ANDROID_RADIO_H
diff --git a/include/system/sound_trigger.h b/include/system/sound_trigger.h
deleted file mode 100644
index 773e4f7..0000000
--- a/include/system/sound_trigger.h
+++ /dev/null
@@ -1,223 +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 ANDROID_SOUND_TRIGGER_H
-#define ANDROID_SOUND_TRIGGER_H
-
-#include <stdbool.h>
-#include <system/audio.h>
-
-#define SOUND_TRIGGER_MAX_STRING_LEN 64 /* max length of strings in properties or
-                                           descriptor structs */
-#define SOUND_TRIGGER_MAX_LOCALE_LEN 6  /* max length of locale string. e.g en_US */
-#define SOUND_TRIGGER_MAX_USERS 10      /* max number of concurrent users */
-#define SOUND_TRIGGER_MAX_PHRASES 10    /* max number of concurrent phrases */
-
-typedef enum {
-    SOUND_TRIGGER_STATE_NO_INIT = -1,   /* The sound trigger service is not initialized */
-    SOUND_TRIGGER_STATE_ENABLED = 0,    /* The sound trigger service is enabled */
-    SOUND_TRIGGER_STATE_DISABLED = 1    /* The sound trigger service is disabled */
-} sound_trigger_service_state_t;
-
-#define RECOGNITION_MODE_VOICE_TRIGGER 0x1       /* simple voice trigger */
-#define RECOGNITION_MODE_USER_IDENTIFICATION 0x2 /* trigger only if one user in model identified */
-#define RECOGNITION_MODE_USER_AUTHENTICATION 0x4 /* trigger only if one user in mode
-                                                    authenticated */
-#define RECOGNITION_STATUS_SUCCESS 0
-#define RECOGNITION_STATUS_ABORT 1
-#define RECOGNITION_STATUS_FAILURE 2
-
-#define SOUND_MODEL_STATUS_UPDATED 0
-
-typedef enum {
-    SOUND_MODEL_TYPE_UNKNOWN = -1,    /* use for unspecified sound model type */
-    SOUND_MODEL_TYPE_KEYPHRASE = 0    /* use for key phrase sound models */
-} sound_trigger_sound_model_type_t;
-
-typedef struct sound_trigger_uuid_s {
-    unsigned int   timeLow;
-    unsigned short timeMid;
-    unsigned short timeHiAndVersion;
-    unsigned short clockSeq;
-    unsigned char  node[6];
-} sound_trigger_uuid_t;
-
-/*
- * sound trigger implementation descriptor read by the framework via get_properties().
- * Used by SoundTrigger service to report to applications and manage concurrency and policy.
- */
-struct sound_trigger_properties {
-    char                 implementor[SOUND_TRIGGER_MAX_STRING_LEN]; /* implementor name */
-    char                 description[SOUND_TRIGGER_MAX_STRING_LEN]; /* implementation description */
-    unsigned int         version;               /* implementation version */
-    sound_trigger_uuid_t uuid;                  /* unique implementation ID.
-                                                   Must change with version each version */
-    unsigned int         max_sound_models;      /* maximum number of concurrent sound models
-                                                   loaded */
-    unsigned int         max_key_phrases;       /* maximum number of key phrases */
-    unsigned int         max_users;             /* maximum number of concurrent users detected */
-    unsigned int         recognition_modes;     /* all supported modes.
-                                                   e.g RECOGNITION_MODE_VOICE_TRIGGER */
-    bool                 capture_transition;    /* supports seamless transition from detection
-                                                   to capture */
-    unsigned int         max_buffer_ms;         /* maximum buffering capacity in ms if
-                                                   capture_transition is true*/
-    bool                 concurrent_capture;    /* supports capture by other use cases while
-                                                   detection is active */
-    bool                 trigger_in_event;      /* returns the trigger capture in event */
-    unsigned int         power_consumption_mw;  /* Rated power consumption when detection is active
-                                                   with TDB silence/sound/speech ratio */
-};
-
-typedef int sound_trigger_module_handle_t;
-
-struct sound_trigger_module_descriptor {
-    sound_trigger_module_handle_t   handle;
-    struct sound_trigger_properties properties;
-};
-
-typedef int sound_model_handle_t;
-
-/*
- * Generic sound model descriptor. This struct is the header of a larger block passed to
- * load_sound_model() and containing the binary data of the sound model.
- * Proprietary representation of users in binary data must match information indicated
- * by users field
- */
-struct sound_trigger_sound_model {
-    sound_trigger_sound_model_type_t type;        /* model type. e.g. SOUND_MODEL_TYPE_KEYPHRASE */
-    sound_trigger_uuid_t             uuid;        /* unique sound model ID. */
-    sound_trigger_uuid_t             vendor_uuid; /* unique vendor ID. Identifies the engine the
-                                                  sound model was build for */
-    unsigned int                     data_size;   /* size of opaque model data */
-    unsigned int                     data_offset; /* offset of opaque data start from head of struct
-                                                    (e.g sizeof struct sound_trigger_sound_model) */
-};
-
-/* key phrase descriptor */
-struct sound_trigger_phrase {
-    unsigned int id;                /* keyphrase ID */
-    unsigned int recognition_mode;  /* recognition modes supported by this key phrase */
-    unsigned int num_users;         /* number of users in the key phrase */
-    unsigned int users[SOUND_TRIGGER_MAX_USERS]; /* users ids: (not uid_t but sound trigger
-                                                 specific IDs */
-    char         locale[SOUND_TRIGGER_MAX_LOCALE_LEN]; /* locale - JAVA Locale style (e.g. en_US) */
-    char         text[SOUND_TRIGGER_MAX_STRING_LEN];   /* phrase text in UTF-8 format. */
-};
-
-/*
- * Specialized sound model for key phrase detection.
- * Proprietary representation of key phrases in binary data must match information indicated
- * by phrases field
- */
-struct sound_trigger_phrase_sound_model {
-    struct sound_trigger_sound_model common;
-    unsigned int                     num_phrases;   /* number of key phrases in model */
-    struct sound_trigger_phrase      phrases[SOUND_TRIGGER_MAX_PHRASES];
-};
-
-
-/*
- * Generic recognition event sent via recognition callback
- */
-struct sound_trigger_recognition_event {
-    int                              status;            /* recognition status e.g.
-                                                           RECOGNITION_STATUS_SUCCESS */
-    sound_trigger_sound_model_type_t type;              /* event type, same as sound model type.
-                                                           e.g. SOUND_MODEL_TYPE_KEYPHRASE */
-    sound_model_handle_t             model;             /* loaded sound model that triggered the
-                                                           event */
-    bool                             capture_available; /* it is possible to capture audio from this
-                                                           utterance buffered by the
-                                                           implementation */
-    int                              capture_session;   /* audio session ID. framework use */
-    int                              capture_delay_ms;  /* delay in ms between end of model
-                                                           detection and start of audio available
-                                                           for capture. A negative value is possible
-                                                           (e.g. if key phrase is also available for
-                                                           capture */
-    int                              capture_preamble_ms; /* duration in ms of audio captured
-                                                            before the start of the trigger.
-                                                            0 if none. */
-    bool                             trigger_in_data; /* the opaque data is the capture of
-                                                            the trigger sound */
-    audio_config_t                   audio_config;        /* audio format of either the trigger in
-                                                             event data or to use for capture of the
-                                                             rest of the utterance */
-    unsigned int                     data_size;         /* size of opaque event data */
-    unsigned int                     data_offset;       /* offset of opaque data start from start of
-                                                          this struct (e.g sizeof struct
-                                                          sound_trigger_phrase_recognition_event) */
-};
-
-/*
- * Confidence level for each user in struct sound_trigger_phrase_recognition_extra
- */
-struct sound_trigger_confidence_level {
-    unsigned int user_id;   /* user ID */
-    unsigned int level;     /* confidence level in percent (0 - 100).
-                               - min level for recognition configuration
-                               - detected level for recognition event */
-};
-
-/*
- * Specialized recognition event for key phrase detection
- */
-struct sound_trigger_phrase_recognition_extra {
-    unsigned int id;                /* keyphrase ID */
-    unsigned int recognition_modes; /* recognition modes used for this keyphrase */
-    unsigned int confidence_level;  /* confidence level for mode RECOGNITION_MODE_VOICE_TRIGGER */
-    unsigned int num_levels;        /* number of user confidence levels */
-    struct sound_trigger_confidence_level levels[SOUND_TRIGGER_MAX_USERS];
-};
-
-struct sound_trigger_phrase_recognition_event {
-    struct sound_trigger_recognition_event common;
-    unsigned int                           num_phrases;
-    struct sound_trigger_phrase_recognition_extra phrase_extras[SOUND_TRIGGER_MAX_PHRASES];
-};
-
-/*
- * configuration for sound trigger capture session passed to start_recognition()
- */
-struct sound_trigger_recognition_config {
-    audio_io_handle_t    capture_handle;    /* IO handle that will be used for capture.
-                                            N/A if capture_requested is false */
-    audio_devices_t      capture_device;    /* input device requested for detection capture */
-    bool                 capture_requested; /* capture and buffer audio for this recognition
-                                            instance */
-    unsigned int         num_phrases;   /* number of key phrases recognition extras */
-    struct sound_trigger_phrase_recognition_extra phrases[SOUND_TRIGGER_MAX_PHRASES];
-                                           /* configuration for each key phrase */
-    unsigned int        data_size;         /* size of opaque capture configuration data */
-    unsigned int        data_offset;       /* offset of opaque data start from start of this struct
-                                           (e.g sizeof struct sound_trigger_recognition_config) */
-};
-
-/*
- * Event sent via load sound model callback
- */
-struct sound_trigger_model_event {
-    int                  status;      /* sound model status e.g. SOUND_MODEL_STATUS_UPDATED */
-    sound_model_handle_t model;       /* loaded sound model that triggered the event */
-    unsigned int         data_size;   /* size of event data if any. Size of updated sound model if
-                                       status is SOUND_MODEL_STATUS_UPDATED */
-    unsigned int         data_offset; /* offset of data start from start of this struct
-                                       (e.g sizeof struct sound_trigger_model_event) */
-};
-
-
-#endif  // ANDROID_SOUND_TRIGGER_H
diff --git a/include/system/window.h b/include/system/window.h
index bf93b79..508ce00 100644
--- a/include/system/window.h
+++ b/include/system/window.h
@@ -262,6 +262,21 @@
      * the aspect ratio of the buffers produced.
      */
     NATIVE_WINDOW_STICKY_TRANSFORM = 11,
+
+    /**
+     * The default data space for the buffers as set by the consumer.
+     * The values are defined in graphics.h.
+     */
+    NATIVE_WINDOW_DEFAULT_DATASPACE = 12,
+
+    /*
+     * Returns the age of the contents of the most recently dequeued buffer as
+     * the number of frames that have elapsed since it was last queued. For
+     * example, if the window is double-buffered, the age of any given buffer in
+     * steady state will be 2. If the dequeued buffer has never been queued, its
+     * age will be 0.
+     */
+    NATIVE_WINDOW_BUFFER_AGE = 13,
 };
 
 /* Valid operations for the (*perform)() hook.
@@ -294,6 +309,8 @@
     NATIVE_WINDOW_SET_POST_TRANSFORM_CROP   = 16,   /* private */
     NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17,/* private */
     NATIVE_WINDOW_SET_SIDEBAND_STREAM       = 18,
+    NATIVE_WINDOW_SET_BUFFERS_DATASPACE     = 19,
+    NATIVE_WINDOW_SET_SURFACE_DAMAGE        = 20,   /* private */
 };
 
 /* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */
@@ -486,30 +503,12 @@
      * DO NOT CALL THIS HOOK DIRECTLY.  Instead, use the helper functions
      * defined below.
      *
-     *  (*perform)() returns -ENOENT if the 'what' parameter is not supported
-     *  by the surface's implementation.
+     * (*perform)() returns -ENOENT if the 'what' parameter is not supported
+     * by the surface's implementation.
      *
-     * The valid operations are:
-     *     NATIVE_WINDOW_SET_USAGE
-     *     NATIVE_WINDOW_CONNECT               (deprecated)
-     *     NATIVE_WINDOW_DISCONNECT            (deprecated)
-     *     NATIVE_WINDOW_SET_CROP              (private)
-     *     NATIVE_WINDOW_SET_BUFFER_COUNT
-     *     NATIVE_WINDOW_SET_BUFFERS_GEOMETRY  (deprecated)
-     *     NATIVE_WINDOW_SET_BUFFERS_TRANSFORM
-     *     NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP
-     *     NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS
-     *     NATIVE_WINDOW_SET_BUFFERS_FORMAT
-     *     NATIVE_WINDOW_SET_SCALING_MODE       (private)
-     *     NATIVE_WINDOW_LOCK                   (private)
-     *     NATIVE_WINDOW_UNLOCK_AND_POST        (private)
-     *     NATIVE_WINDOW_API_CONNECT            (private)
-     *     NATIVE_WINDOW_API_DISCONNECT         (private)
-     *     NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS (private)
-     *     NATIVE_WINDOW_SET_POST_TRANSFORM_CROP (private)
-     *
+     * See above for a list of valid operations, such as
+     * NATIVE_WINDOW_SET_USAGE or NATIVE_WINDOW_CONNECT
      */
-
     int     (*perform)(struct ANativeWindow* window,
                 int operation, ... );
 
@@ -799,6 +798,26 @@
 }
 
 /*
+ * native_window_set_buffers_data_space(..., int dataSpace)
+ * All buffers queued after this call will be associated with the dataSpace
+ * parameter specified.
+ *
+ * dataSpace specifies additional information about the buffer that's dependent
+ * on the buffer format and the endpoints. For example, it can be used to convey
+ * the color space of the image data in the buffer, or it can be used to
+ * indicate that the buffers contain depth measurement data instead of color
+ * images.  The default dataSpace is 0, HAL_DATASPACE_UNKNOWN, unless it has been
+ * overridden by the consumer.
+ */
+static inline int native_window_set_buffers_data_space(
+        struct ANativeWindow* window,
+        android_dataspace_t dataSpace)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_DATASPACE,
+            dataSpace);
+}
+
+/*
  * native_window_set_buffers_transform(..., int transform)
  * All buffers queued after this call will be displayed transformed according
  * to the transform parameter specified.
@@ -906,6 +925,30 @@
             sidebandHandle);
 }
 
+/*
+ * native_window_set_surface_damage(..., android_native_rect_t* rects, int numRects)
+ * Set the surface damage (i.e., the region of the surface that has changed
+ * since the previous frame). The damage set by this call will be reset (to the
+ * default of full-surface damage) after calling queue, so this must be called
+ * prior to every frame with damage that does not cover the whole surface if the
+ * caller desires downstream consumers to use this optimization.
+ *
+ * The damage region is specified as an array of rectangles, with the important
+ * caveat that the origin of the surface is considered to be the bottom-left
+ * corner, as in OpenGL ES.
+ *
+ * If numRects is set to 0, rects may be NULL, and the surface damage will be
+ * set to the full surface (the same as if this function had not been called for
+ * this frame).
+ */
+static inline int native_window_set_surface_damage(
+        struct ANativeWindow* window,
+        const android_native_rect_t* rects, size_t numRects)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_SURFACE_DAMAGE,
+            rects, numRects);
+}
+
 __END_DECLS
 
 #endif /* SYSTEM_CORE_INCLUDE_ANDROID_WINDOW_H */
diff --git a/include/sysutils/NetlinkEvent.h b/include/sysutils/NetlinkEvent.h
index c345cdb..b80f3ea 100644
--- a/include/sysutils/NetlinkEvent.h
+++ b/include/sysutils/NetlinkEvent.h
@@ -21,25 +21,29 @@
 #define NL_PARAMS_MAX 32
 
 class NetlinkEvent {
+public:
+    enum class Action {
+        kUnknown = 0,
+        kAdd = 1,
+        kRemove = 2,
+        kChange = 3,
+        kLinkUp = 4,
+        kLinkDown = 5,
+        kAddressUpdated = 6,
+        kAddressRemoved = 7,
+        kRdnss = 8,
+        kRouteUpdated = 9,
+        kRouteRemoved = 10,
+    };
+
+private:
     int  mSeq;
     char *mPath;
-    int  mAction;
+    Action mAction;
     char *mSubsystem;
     char *mParams[NL_PARAMS_MAX];
 
 public:
-    const static int NlActionUnknown;
-    const static int NlActionAdd;
-    const static int NlActionRemove;
-    const static int NlActionChange;
-    const static int NlActionLinkDown;
-    const static int NlActionLinkUp;
-    const static int NlActionAddressUpdated;
-    const static int NlActionAddressRemoved;
-    const static int NlActionRdnss;
-    const static int NlActionRouteUpdated;
-    const static int NlActionRouteRemoved;
-
     NetlinkEvent();
     virtual ~NetlinkEvent();
 
@@ -47,7 +51,7 @@
     const char *findParam(const char *paramName);
 
     const char *getSubsystem() { return mSubsystem; }
-    int getAction() { return mAction; }
+    Action getAction() { return mAction; }
 
     void dump();
 
@@ -57,6 +61,7 @@
     bool parseIfInfoMessage(const struct nlmsghdr *nh);
     bool parseIfAddrMessage(const struct nlmsghdr *nh);
     bool parseUlogPacketMessage(const struct nlmsghdr *nh);
+    bool parseNfPacketMessage(struct nlmsghdr *nh);
     bool parseRtMessage(const struct nlmsghdr *nh);
     bool parseNdUserOptMessage(const struct nlmsghdr *nh);
 };
diff --git a/include/sysutils/NetlinkListener.h b/include/sysutils/NetlinkListener.h
index 6e52c3b..82465d6 100644
--- a/include/sysutils/NetlinkListener.h
+++ b/include/sysutils/NetlinkListener.h
@@ -27,6 +27,7 @@
 public:
     static const int NETLINK_FORMAT_ASCII = 0;
     static const int NETLINK_FORMAT_BINARY = 1;
+    static const int NETLINK_FORMAT_BINARY_UNICAST = 2;
 
 #if 1
     /* temporary version until we can get Motorola to update their
diff --git a/include/usbhost/usbhost.h b/include/usbhost/usbhost.h
index d26e931..4350ec1 100644
--- a/include/usbhost/usbhost.h
+++ b/include/usbhost/usbhost.h
@@ -156,6 +156,10 @@
  */
 char* usb_device_get_product_name(struct usb_device *device);
 
+/* Returns the version number for the USB device.
+ */
+int usb_device_get_version(struct usb_device *device);
+
 /* Returns the USB serial number for the USB device.
  * Call free() to free the result when you are done with it.
  */
diff --git a/include/utils/AndroidThreads.h b/include/utils/AndroidThreads.h
index 4eee14d..aad1e82 100644
--- a/include/utils/AndroidThreads.h
+++ b/include/utils/AndroidThreads.h
@@ -20,7 +20,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#if defined(HAVE_PTHREADS)
+#if !defined(_WIN32)
 # include <pthread.h>
 #endif
 
@@ -73,9 +73,6 @@
 // ------------------------------------------------------------------
 // Extra functions working with raw pids.
 
-// Get pid for the current thread.
-extern pid_t androidGetTid();
-
 #ifdef HAVE_ANDROID_OS
 // Change the priority AND scheduling group of a particular thread.  The priority
 // should be one of the ANDROID_PRIORITY constants.  Returns INVALID_OPERATION
diff --git a/include/utils/BlobCache.h b/include/utils/BlobCache.h
index 7d621e4..65dca9f 100644
--- a/include/utils/BlobCache.h
+++ b/include/utils/BlobCache.h
@@ -185,6 +185,12 @@
         // mNumEntries is number of cache entries following the header in the
         // data.
         size_t mNumEntries;
+
+        // mBuildId is the build id of the device when the cache was created.
+        // When an update to the build happens (via an OTA or other update) this
+        // is used to invalidate the cache.
+        int mBuildIdLength;
+        char mBuildId[];
     };
 
     // An EntryHeader is the header for a serialized cache entry.  No need to
diff --git a/include/utils/Compat.h b/include/utils/Compat.h
index fb7748e..7d96310 100644
--- a/include/utils/Compat.h
+++ b/include/utils/Compat.h
@@ -19,11 +19,9 @@
 
 #include <unistd.h>
 
-/* Compatibility definitions for non-Linux (i.e., BSD-based) hosts. */
-#ifndef HAVE_OFF64_T
-#if _FILE_OFFSET_BITS < 64
-#error "_FILE_OFFSET_BITS < 64; large files are not supported on this platform"
-#endif /* _FILE_OFFSET_BITS < 64 */
+#if defined(__APPLE__)
+
+/* Mac OS has always had a 64-bit off_t, so it doesn't have off64_t. */
 
 typedef off_t off64_t;
 
@@ -31,20 +29,35 @@
     return lseek(fd, offset, whence);
 }
 
-#ifdef HAVE_PREAD
 static inline ssize_t pread64(int fd, void* buf, size_t nbytes, off64_t offset) {
     return pread(fd, buf, nbytes, offset);
 }
+
+#endif /* __APPLE__ */
+
+#if defined(_WIN32)
+#define O_CLOEXEC O_NOINHERIT
+#define O_NOFOLLOW 0
+#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
 
-#endif /* !HAVE_OFF64_T */
-
-#if HAVE_PRINTF_ZD
-#  define ZD "%zd"
-#  define ZD_TYPE ssize_t
+/*
+ * Needed for cases where something should be constexpr if possible, but not
+ * being constexpr is fine if in pre-C++11 code (such as a const static float
+ * member variable).
+ */
+#if __cplusplus >= 201103L
+#define CONSTEXPR constexpr
 #else
-#  define ZD "%ld"
-#  define ZD_TYPE long
+#define CONSTEXPR
 #endif
 
 /*
diff --git a/include/utils/Condition.h b/include/utils/Condition.h
index 1c99d1a..5a72519 100644
--- a/include/utils/Condition.h
+++ b/include/utils/Condition.h
@@ -21,7 +21,7 @@
 #include <sys/types.h>
 #include <time.h>
 
-#if defined(HAVE_PTHREADS)
+#if !defined(_WIN32)
 # include <pthread.h>
 #endif
 
@@ -74,7 +74,7 @@
     void broadcast();
 
 private:
-#if defined(HAVE_PTHREADS)
+#if !defined(_WIN32)
     pthread_cond_t mCond;
 #else
     void*   mState;
@@ -83,7 +83,7 @@
 
 // ---------------------------------------------------------------------------
 
-#if defined(HAVE_PTHREADS)
+#if !defined(_WIN32)
 
 inline Condition::Condition() {
     pthread_cond_init(&mCond, NULL);
@@ -113,15 +113,15 @@
     return -pthread_cond_timedwait_relative_np(&mCond, &mutex.mMutex, &ts);
 #else // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
     struct timespec ts;
-#if defined(HAVE_POSIX_CLOCKS)
+#if defined(__linux__)
     clock_gettime(CLOCK_REALTIME, &ts);
-#else // HAVE_POSIX_CLOCKS
+#else // __APPLE__
     // we don't support the clocks here.
     struct timeval t;
     gettimeofday(&t, NULL);
     ts.tv_sec = t.tv_sec;
     ts.tv_nsec= t.tv_usec*1000;
-#endif // HAVE_POSIX_CLOCKS
+#endif
     ts.tv_sec += reltime/1000000000;
     ts.tv_nsec+= reltime%1000000000;
     if (ts.tv_nsec >= 1000000000) {
@@ -149,7 +149,7 @@
     pthread_cond_broadcast(&mCond);
 }
 
-#endif // HAVE_PTHREADS
+#endif // !defined(_WIN32)
 
 // ---------------------------------------------------------------------------
 }; // namespace android
diff --git a/include/utils/Endian.h b/include/utils/Endian.h
index 19f2504..591cae0 100644
--- a/include/utils/Endian.h
+++ b/include/utils/Endian.h
@@ -20,21 +20,16 @@
 #ifndef _LIBS_UTILS_ENDIAN_H
 #define _LIBS_UTILS_ENDIAN_H
 
-#if defined(HAVE_ENDIAN_H)
-
-#include <endian.h>
-
-#else /*not HAVE_ENDIAN_H*/
+#if defined(__APPLE__) || defined(_WIN32)
 
 #define __BIG_ENDIAN 0x1000
 #define __LITTLE_ENDIAN 0x0001
+#define __BYTE_ORDER __LITTLE_ENDIAN
 
-#if defined(HAVE_LITTLE_ENDIAN)
-# define __BYTE_ORDER __LITTLE_ENDIAN
 #else
-# define __BYTE_ORDER __BIG_ENDIAN
-#endif
 
-#endif /*not HAVE_ENDIAN_H*/
+#include <endian.h>
+
+#endif
 
 #endif /*_LIBS_UTILS_ENDIAN_H*/
diff --git a/include/utils/FileMap.h b/include/utils/FileMap.h
index dfe6d51..f70fc92 100644
--- a/include/utils/FileMap.h
+++ b/include/utils/FileMap.h
@@ -24,7 +24,11 @@
 
 #include <utils/Compat.h>
 
-#ifdef HAVE_WIN32_FILEMAP
+#if defined(__MINGW32__)
+// Ensure that we always pull in winsock2.h before windows.h
+#ifdef HAVE_WINSOCK
+#include <winsock2.h>
+#endif
 #include <windows.h>
 #endif
 
@@ -59,6 +63,8 @@
     bool create(const char* origFileName, int fd,
                 off64_t offset, size_t length, bool readOnly);
 
+    ~FileMap(void);
+
     /*
      * Return the name of the file this map came from, if known.
      */
@@ -80,19 +86,6 @@
     off64_t getDataOffset(void) const { return mDataOffset; }
 
     /*
-     * Get a "copy" of the object.
-     */
-    FileMap* acquire(void) { mRefCount++; return this; }
-
-    /*
-     * Call this when mapping is no longer needed.
-     */
-    void release(void) {
-        if (--mRefCount <= 0)
-            delete this;
-    }
-
-    /*
      * This maps directly to madvise() values, but allows us to avoid
      * including <sys/mman.h> everywhere.
      */
@@ -108,22 +101,19 @@
     int advise(MapAdvice advice);
 
 protected:
-    // don't delete objects; call release()
-    ~FileMap(void);
 
 private:
     // these are not implemented
     FileMap(const FileMap& src);
     const FileMap& operator=(const FileMap& src);
 
-    int         mRefCount;      // reference count
     char*       mFileName;      // original file name, if known
     void*       mBasePtr;       // base of mmap area; page aligned
     size_t      mBaseLength;    // length, measured from "mBasePtr"
     off64_t     mDataOffset;    // offset used when map was created
     void*       mDataPtr;       // start of requested data, offset from base
     size_t      mDataLength;    // length, measured from "mDataPtr"
-#ifdef HAVE_WIN32_FILEMAP
+#if defined(__MINGW32__)
     HANDLE      mFileHandle;    // Win32 file handle
     HANDLE      mFileMapping;   // Win32 file mapping handle
 #endif
diff --git a/include/utils/LinearAllocator.h b/include/utils/LinearAllocator.h
deleted file mode 100644
index 4772bc8..0000000
--- a/include/utils/LinearAllocator.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef ANDROID_LINEARALLOCATOR_H
-#define ANDROID_LINEARALLOCATOR_H
-
-#include <stddef.h>
-
-namespace android {
-
-/**
- * A memory manager that internally allocates multi-kbyte buffers for placing objects in. It avoids
- * the overhead of malloc when many objects are allocated. It is most useful when creating many
- * small objects with a similar lifetime, and doesn't add significant overhead for large
- * allocations.
- */
-class LinearAllocator {
-public:
-    LinearAllocator();
-    ~LinearAllocator();
-
-    /**
-     * Reserves and returns a region of memory of at least size 'size', aligning as needed.
-     * Typically this is used in an object's overridden new() method or as a replacement for malloc.
-     *
-     * The lifetime of the returned buffers is tied to that of the LinearAllocator. If calling
-     * delete() on an object stored in a buffer is needed, it should be overridden to use
-     * rewindIfLastAlloc()
-     */
-    void* alloc(size_t size);
-
-    /**
-     * Attempt to deallocate the given buffer, with the LinearAllocator attempting to rewind its
-     * state if possible. No destructors are called.
-     */
-    void rewindIfLastAlloc(void* ptr, size_t allocSize);
-
-    /**
-     * Dump memory usage statistics to the log (allocated and wasted space)
-     */
-    void dumpMemoryStats(const char* prefix = "");
-
-    /**
-     * The number of bytes used for buffers allocated in the LinearAllocator (does not count space
-     * wasted)
-     */
-    size_t usedSize() const { return mTotalAllocated - mWastedSpace; }
-
-private:
-    LinearAllocator(const LinearAllocator& other);
-
-    class Page;
-
-    Page* newPage(size_t pageSize);
-    bool fitsInCurrentPage(size_t size);
-    void ensureNext(size_t size);
-    void* start(Page *p);
-    void* end(Page* p);
-
-    size_t mPageSize;
-    size_t mMaxAllocSize;
-    void* mNext;
-    Page* mCurrentPage;
-    Page* mPages;
-
-    // Memory usage tracking
-    size_t mTotalAllocated;
-    size_t mWastedSpace;
-    size_t mPageCount;
-    size_t mDedicatedPageCount;
-};
-
-}; // namespace android
-
-#endif // ANDROID_LINEARALLOCATOR_H
diff --git a/include/utils/Looper.h b/include/utils/Looper.h
index 15c9891..da2d5f2 100644
--- a/include/utils/Looper.h
+++ b/include/utils/Looper.h
@@ -386,11 +386,12 @@
     void removeMessages(const sp<MessageHandler>& handler, int what);
 
     /**
-     * Return whether this looper's thread is currently idling -- that is, whether it
-     * stopped waiting for more work to do.  Note that this is intrinsically racy, since
-     * its state can change before you get the result back.
+     * Returns whether this looper's thread is currently polling for more work to do.
+     * This is a good signal that the loop is still alive rather than being stuck
+     * handling a callback.  Note that this method is intrinsically racy, since the
+     * state of the loop can change before you get the result back.
      */
-    bool isIdling() const;
+    bool isPolling() const;
 
     /**
      * Prepares a looper associated with the calling thread, and returns it.
@@ -419,8 +420,12 @@
     struct Request {
         int fd;
         int ident;
+        int events;
+        int seq;
         sp<LooperCallback> callback;
         void* data;
+
+        void initEventItem(struct epoll_event* eventItem) const;
     };
 
     struct Response {
@@ -442,8 +447,7 @@
 
     const bool mAllowNonCallbacks; // immutable
 
-    int mWakeReadPipeFd;  // immutable
-    int mWakeWritePipeFd; // immutable
+    int mWakeEventFd;  // immutable
     Mutex mLock;
 
     Vector<MessageEnvelope> mMessageEnvelopes; // guarded by mLock
@@ -451,12 +455,14 @@
 
     // Whether we are currently waiting for work.  Not protected by a lock,
     // any use of it is racy anyway.
-    volatile bool mIdling;
+    volatile bool mPolling;
 
-    int mEpollFd; // immutable
+    int mEpollFd; // guarded by mLock but only modified on the looper thread
+    bool mEpollRebuildRequired; // guarded by mLock
 
     // Locked list of file descriptor monitoring requests.
     KeyedVector<int, Request> mRequests;  // guarded by mLock
+    int mNextRequestSeq;
 
     // This state is only used privately by pollOnce and does not require a lock since
     // it runs on a single thread.
@@ -465,11 +471,15 @@
     nsecs_t mNextMessageUptime; // set to LLONG_MAX when none
 
     int pollInner(int timeoutMillis);
+    int removeFd(int fd, int seq);
     void awoken();
     void pushResponse(int events, const Request& request);
+    void rebuildEpollLocked();
+    void scheduleEpollRebuildLocked();
 
     static void initTLSKey();
     static void threadDestructor(void *st);
+    static void initEpollEvent(struct epoll_event* eventItem);
 };
 
 } // namespace android
diff --git a/include/utils/Mutex.h b/include/utils/Mutex.h
index dd201c8..757519b 100644
--- a/include/utils/Mutex.h
+++ b/include/utils/Mutex.h
@@ -21,11 +21,12 @@
 #include <sys/types.h>
 #include <time.h>
 
-#if defined(HAVE_PTHREADS)
+#if !defined(_WIN32)
 # include <pthread.h>
 #endif
 
 #include <utils/Errors.h>
+#include <utils/Timers.h>
 
 // ---------------------------------------------------------------------------
 namespace android {
@@ -45,7 +46,7 @@
         PRIVATE = 0,
         SHARED = 1
     };
-    
+
                 Mutex();
                 Mutex(const char* name);
                 Mutex(int type, const char* name = NULL);
@@ -58,6 +59,16 @@
     // lock if possible; returns 0 on success, error otherwise
     status_t    tryLock();
 
+#if HAVE_ANDROID_OS
+    // lock the mutex, but don't wait longer than timeoutMilliseconds.
+    // Returns 0 on success, TIMED_OUT for failure due to timeout expiration.
+    //
+    // OSX doesn't have pthread_mutex_timedlock() or equivalent. To keep
+    // capabilities consistent across host OSes, this method is only available
+    // when building Android binaries.
+    status_t    timedLock(nsecs_t timeoutMilliseconds);
+#endif
+
     // Manages the mutex automatically. It'll be locked when Autolock is
     // constructed and released when Autolock goes out of scope.
     class Autolock {
@@ -71,12 +82,12 @@
 
 private:
     friend class Condition;
-    
+
     // A mutex cannot be copied
                 Mutex(const Mutex&);
     Mutex&      operator = (const Mutex&);
-    
-#if defined(HAVE_PTHREADS)
+
+#if !defined(_WIN32)
     pthread_mutex_t mMutex;
 #else
     void    _init();
@@ -86,7 +97,7 @@
 
 // ---------------------------------------------------------------------------
 
-#if defined(HAVE_PTHREADS)
+#if !defined(_WIN32)
 
 inline Mutex::Mutex() {
     pthread_mutex_init(&mMutex, NULL);
@@ -117,8 +128,17 @@
 inline status_t Mutex::tryLock() {
     return -pthread_mutex_trylock(&mMutex);
 }
+#if HAVE_ANDROID_OS
+inline status_t Mutex::timedLock(nsecs_t timeoutNs) {
+    const struct timespec ts = {
+        /* .tv_sec = */ static_cast<time_t>(timeoutNs / 1000000000),
+        /* .tv_nsec = */ static_cast<long>(timeoutNs % 1000000000),
+    };
+    return -pthread_mutex_timedlock(&mMutex, &ts);
+}
+#endif
 
-#endif // HAVE_PTHREADS
+#endif // !defined(_WIN32)
 
 // ---------------------------------------------------------------------------
 
@@ -127,7 +147,7 @@
  * When the function returns, it will go out of scope, and release the
  * mutex.
  */
- 
+
 typedef Mutex::Autolock AutoMutex;
 
 // ---------------------------------------------------------------------------
diff --git a/include/utils/RWLock.h b/include/utils/RWLock.h
index 90beb5f..e743b1c 100644
--- a/include/utils/RWLock.h
+++ b/include/utils/RWLock.h
@@ -20,7 +20,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#if defined(HAVE_PTHREADS)
+#if !defined(_WIN32)
 # include <pthread.h>
 #endif
 
@@ -31,7 +31,7 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
-#if defined(HAVE_PTHREADS)
+#if !defined(_WIN32)
 
 /*
  * Simple mutex class.  The implementation is system-dependent.
@@ -117,7 +117,7 @@
     pthread_rwlock_unlock(&mRWLock);
 }
 
-#endif // HAVE_PTHREADS
+#endif // !defined(_WIN32)
 
 // ---------------------------------------------------------------------------
 }; // namespace android
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index 8e15c19..eac6a78 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -491,7 +491,8 @@
                 TYPE::renameRefId(d[i].get(), &s[i], &d[i]);
             }
         public:
-            Renamer(sp<TYPE>* d, sp<TYPE> const* s) : s(s), d(d) { }
+            Renamer(sp<TYPE>* d, sp<TYPE> const* s) : d(d), s(s) { }
+            virtual ~Renamer() { }
         };
 
         memmove(d, s, n*sizeof(sp<TYPE>));
@@ -510,7 +511,8 @@
                 TYPE::renameRefId(d[i].get_refs(), &s[i], &d[i]);
             }
         public:
-            Renamer(wp<TYPE>* d, wp<TYPE> const* s) : s(s), d(d) { }
+            Renamer(wp<TYPE>* d, wp<TYPE> const* s) : d(d), s(s) { }
+            virtual ~Renamer() { }
         };
 
         memmove(d, s, n*sizeof(wp<TYPE>));
diff --git a/include/utils/Singleton.h b/include/utils/Singleton.h
index c60680e..ffc03cb 100644
--- a/include/utils/Singleton.h
+++ b/include/utils/Singleton.h
@@ -65,9 +65,10 @@
  */
 
 #define ANDROID_SINGLETON_STATIC_INSTANCE(TYPE)                 \
-    template<> Mutex Singleton< TYPE >::sLock(Mutex::PRIVATE);  \
-    template<> TYPE* Singleton< TYPE >::sInstance(0);           \
-    template class Singleton< TYPE >;
+    template<> ::android::Mutex  \
+        (::android::Singleton< TYPE >::sLock)(::android::Mutex::PRIVATE);  \
+    template<> TYPE* ::android::Singleton< TYPE >::sInstance(0);  \
+    template class ::android::Singleton< TYPE >;
 
 
 // ---------------------------------------------------------------------------
diff --git a/include/utils/Thread.h b/include/utils/Thread.h
index df30611..28839fd 100644
--- a/include/utils/Thread.h
+++ b/include/utils/Thread.h
@@ -21,7 +21,7 @@
 #include <sys/types.h>
 #include <time.h>
 
-#if defined(HAVE_PTHREADS)
+#if !defined(_WIN32)
 # include <pthread.h>
 #endif
 
@@ -71,8 +71,8 @@
             bool        isRunning() const;
 
 #ifdef HAVE_ANDROID_OS
-    // Return the thread's kernel ID, same as the thread itself calling gettid() or
-    // androidGetTid(), or -1 if the thread is not running.
+    // Return the thread's kernel ID, same as the thread itself calling gettid(),
+    // or -1 if the thread is not running.
             pid_t       getTid() const;
 #endif
 
diff --git a/include/utils/Timers.h b/include/utils/Timers.h
index d015421..54ec474 100644
--- a/include/utils/Timers.h
+++ b/include/utils/Timers.h
@@ -24,6 +24,8 @@
 #include <sys/types.h>
 #include <sys/time.h>
 
+#include <utils/Compat.h>
+
 // ------------------------------------------------------------------
 // C API
 
@@ -33,46 +35,46 @@
 
 typedef int64_t nsecs_t;       // nano-seconds
 
-static inline nsecs_t seconds_to_nanoseconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t seconds_to_nanoseconds(nsecs_t secs)
 {
     return secs*1000000000;
 }
 
-static inline nsecs_t milliseconds_to_nanoseconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t milliseconds_to_nanoseconds(nsecs_t secs)
 {
     return secs*1000000;
 }
 
-static inline nsecs_t microseconds_to_nanoseconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t microseconds_to_nanoseconds(nsecs_t secs)
 {
     return secs*1000;
 }
 
-static inline nsecs_t nanoseconds_to_seconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t nanoseconds_to_seconds(nsecs_t secs)
 {
     return secs/1000000000;
 }
 
-static inline nsecs_t nanoseconds_to_milliseconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t nanoseconds_to_milliseconds(nsecs_t secs)
 {
     return secs/1000000;
 }
 
-static inline nsecs_t nanoseconds_to_microseconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t nanoseconds_to_microseconds(nsecs_t secs)
 {
     return secs/1000;
 }
 
-static inline nsecs_t s2ns(nsecs_t v)  {return seconds_to_nanoseconds(v);}
-static inline nsecs_t ms2ns(nsecs_t v) {return milliseconds_to_nanoseconds(v);}
-static inline nsecs_t us2ns(nsecs_t v) {return microseconds_to_nanoseconds(v);}
-static inline nsecs_t ns2s(nsecs_t v)  {return nanoseconds_to_seconds(v);}
-static inline nsecs_t ns2ms(nsecs_t v) {return nanoseconds_to_milliseconds(v);}
-static inline nsecs_t ns2us(nsecs_t v) {return nanoseconds_to_microseconds(v);}
+static CONSTEXPR inline nsecs_t s2ns(nsecs_t v)  {return seconds_to_nanoseconds(v);}
+static CONSTEXPR inline nsecs_t ms2ns(nsecs_t v) {return milliseconds_to_nanoseconds(v);}
+static CONSTEXPR inline nsecs_t us2ns(nsecs_t v) {return microseconds_to_nanoseconds(v);}
+static CONSTEXPR inline nsecs_t ns2s(nsecs_t v)  {return nanoseconds_to_seconds(v);}
+static CONSTEXPR inline nsecs_t ns2ms(nsecs_t v) {return nanoseconds_to_milliseconds(v);}
+static CONSTEXPR inline nsecs_t ns2us(nsecs_t v) {return nanoseconds_to_microseconds(v);}
 
-static inline nsecs_t seconds(nsecs_t v)      { return s2ns(v); }
-static inline nsecs_t milliseconds(nsecs_t v) { return ms2ns(v); }
-static inline nsecs_t microseconds(nsecs_t v) { return us2ns(v); }
+static CONSTEXPR inline nsecs_t seconds(nsecs_t v)      { return s2ns(v); }
+static CONSTEXPR inline nsecs_t milliseconds(nsecs_t v) { return ms2ns(v); }
+static CONSTEXPR inline nsecs_t microseconds(nsecs_t v) { return us2ns(v); }
 
 enum {
     SYSTEM_TIME_REALTIME = 0,  // system-wide realtime clock
diff --git a/include/utils/Unicode.h b/include/utils/Unicode.h
index f8f0aee..4e17cc3 100644
--- a/include/utils/Unicode.h
+++ b/include/utils/Unicode.h
@@ -22,12 +22,6 @@
 
 extern "C" {
 
-// Definitions exist in C++11
-#if defined __cplusplus && __cplusplus < 201103L
-typedef uint32_t char32_t;
-typedef uint16_t char16_t;
-#endif
-
 // Standard string functions on char16_t strings.
 int strcmp16(const char16_t *, const char16_t *);
 int strncmp16(const char16_t *s1, const char16_t *s2, size_t n);
diff --git a/include/ziparchive/zip_archive.h b/include/ziparchive/zip_archive.h
index 1877494..3b00683 100644
--- a/include/ziparchive/zip_archive.h
+++ b/include/ziparchive/zip_archive.h
@@ -21,6 +21,7 @@
 #define LIBZIPARCHIVE_ZIPARCHIVE_H_
 
 #include <stdint.h>
+#include <string.h>
 #include <sys/types.h>
 #include <utils/Compat.h>
 
@@ -33,8 +34,16 @@
 };
 
 struct ZipEntryName {
-  const char* name;
+  const uint8_t* name;
   uint16_t name_length;
+
+  ZipEntryName() {}
+
+  /*
+   * entry_name has to be an c-style string with only ASCII characters.
+   */
+  explicit ZipEntryName(const char* entry_name)
+      : name(reinterpret_cast<const uint8_t*>(entry_name)), name_length(strlen(entry_name)) {}
 };
 
 /*
@@ -92,6 +101,9 @@
  * Sets handle to the value of the opaque handle for this file descriptor.
  * This handle must be released by calling CloseArchive with this handle.
  *
+ * If assume_ownership parameter is 'true' calling CloseArchive will close
+ * the file.
+ *
  * This function maps and scans the central directory and builds a table
  * of entries for future lookups.
  *
@@ -100,7 +112,7 @@
  * Returns 0 on success, and negative values on failure.
  */
 int32_t OpenArchiveFd(const int fd, const char* debugFileName,
-                      ZipArchiveHandle *handle);
+                      ZipArchiveHandle *handle, bool assume_ownership = true);
 
 /*
  * Close archive, releasing resources associated with it. This will
@@ -124,24 +136,26 @@
  * and length, a call to VerifyCrcAndLengths must be made after entry data
  * has been processed.
  */
-int32_t FindEntry(const ZipArchiveHandle handle, const char* entryName,
+int32_t FindEntry(const ZipArchiveHandle handle, const ZipEntryName& entryName,
                   ZipEntry* data);
 
 /*
  * Start iterating over all entries of a zip file. The order of iteration
  * is not guaranteed to be the same as the order of elements
- * in the central directory but is stable for a given zip file. |cookie|
- * must point to a writeable memory location, and will be set to the value
- * of an opaque cookie which can be used to make one or more calls to
- * Next.
+ * in the central directory but is stable for a given zip file. |cookie| will
+ * contain the value of an opaque cookie which can be used to make one or more
+ * calls to Next. All calls to StartIteration must be matched by a call to
+ * EndIteration to free any allocated memory.
  *
  * This method also accepts an optional prefix to restrict iteration to
- * entry names that start with |prefix|.
+ * entry names that start with |optional_prefix|.
  *
  * Returns 0 on success and negative values on failure.
  */
 int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr,
-                       const char* prefix);
+                       const ZipEntryName* optional_prefix,
+                       // TODO: Remove the default parameter.
+                       const ZipEntryName* optional_suffix = NULL);
 
 /*
  * Advance to the next element in the zipfile in iteration order.
@@ -152,6 +166,12 @@
 int32_t Next(void* cookie, ZipEntry* data, ZipEntryName *name);
 
 /*
+ * End iteration over all entries of a zip file and frees the memory allocated
+ * in StartIteration.
+ */
+void EndIteration(void* cookie);
+
+/*
  * 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
diff --git a/include/zipfile/zipfile.h b/include/zipfile/zipfile.h
deleted file mode 100644
index 0ae4ee4..0000000
--- a/include/zipfile/zipfile.h
+++ /dev/null
@@ -1,58 +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.
- */
-
-#ifndef _ZIPFILE_ZIPFILE_H
-#define _ZIPFILE_ZIPFILE_H
-
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef void* zipfile_t;
-typedef void* zipentry_t;
-
-// Provide a buffer.  Returns NULL on failure.
-zipfile_t init_zipfile(const void* data, size_t size);
-
-// Release the zipfile resources.
-void release_zipfile(zipfile_t file);
-
-// Get a named entry object.  Returns NULL if it doesn't exist
-// or if we won't be able to decompress it.  The zipentry_t is
-// freed by release_zipfile()
-zipentry_t lookup_zipentry(zipfile_t file, const char* entryName);
-
-// Return the size of the entry.
-size_t get_zipentry_size(zipentry_t entry);
-
-// return the filename of this entry, you own the memory returned
-char* get_zipentry_name(zipentry_t entry);
-
-// The buffer must be 1.001 times the buffer size returned
-// by get_zipentry_size.  Returns nonzero on failure.
-int decompress_zipentry(zipentry_t entry, void* buf, int bufsize);
-
-// iterate through the entries in the zip file.  pass a pointer to
-// a void* initialized to NULL to start.  Returns NULL when done
-zipentry_t iterate_zipfile(zipfile_t file, void** cookie);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // _ZIPFILE_ZIPFILE_H
diff --git a/init/Android.mk b/init/Android.mk
index 228e645..de065dc 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -1,73 +1,102 @@
 # Copyright 2005 The Android Open Source Project
 
 LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:= \
-	builtins.c \
-	init.c \
-	devices.c \
-	property_service.c \
-	util.c \
-	parser.c \
-	keychords.c \
-	signal_handler.c \
-	init_parser.c \
-	ueventd.c \
-	ueventd_parser.c \
-	watchdogd.c
-
-LOCAL_CFLAGS    += -Wno-unused-parameter
-
-ifeq ($(strip $(INIT_BOOTCHART)),true)
-LOCAL_SRC_FILES += bootchart.c
-LOCAL_CFLAGS    += -DBOOTCHART=1
-endif
+# --
 
 ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
-LOCAL_CFLAGS += -DALLOW_LOCAL_PROP_OVERRIDE=1 -DALLOW_DISABLE_SELINUX=1
+init_options += -DALLOW_LOCAL_PROP_OVERRIDE=1 -DALLOW_DISABLE_SELINUX=1
+else
+init_options += -DALLOW_LOCAL_PROP_OVERRIDE=0 -DALLOW_DISABLE_SELINUX=0
 endif
 
-# Enable ueventd logging
-#LOCAL_CFLAGS += -DLOG_UEVENTS=1
+init_options += -DLOG_UEVENTS=0
+
+init_cflags += \
+    $(init_options) \
+    -Wall -Wextra \
+    -Wno-unused-parameter \
+    -Werror \
+
+init_clang := true
+
+# --
+
+include $(CLEAR_VARS)
+LOCAL_CPPFLAGS := $(init_cflags)
+LOCAL_SRC_FILES:= \
+    init_parser.cpp \
+    log.cpp \
+    parser.cpp \
+    util.cpp \
+
+LOCAL_STATIC_LIBRARIES := libbase
+LOCAL_MODULE := libinit
+LOCAL_CLANG := $(init_clang)
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_CPPFLAGS := $(init_cflags)
+LOCAL_SRC_FILES:= \
+    bootchart.cpp \
+    builtins.cpp \
+    devices.cpp \
+    init.cpp \
+    keychords.cpp \
+    property_service.cpp \
+    signal_handler.cpp \
+    ueventd.cpp \
+    ueventd_parser.cpp \
+    watchdogd.cpp \
 
 LOCAL_MODULE:= init
+LOCAL_C_INCLUDES += \
+    system/extras/ext4_utils \
+    system/core/mkbootimg
 
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
 
 LOCAL_STATIC_LIBRARIES := \
-	libfs_mgr \
-	liblogwrap \
-	libcutils \
-	liblog \
-	libc \
-	libselinux \
-	libmincrypt \
-	libext4_utils_static \
-	libsparse_static \
-	libz
+    libinit \
+    libfs_mgr \
+    libsquashfs_utils \
+    liblogwrap \
+    libcutils \
+    libbase \
+    libext4_utils_static \
+    libutils \
+    liblog \
+    libc \
+    libselinux \
+    libmincrypt \
+    libc++_static \
+    libdl \
+    libsparse_static \
+    libz
 
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+# 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
 
+LOCAL_CLANG := $(init_clang)
 include $(BUILD_EXECUTABLE)
 
-# Make a symlink from /sbin/ueventd and /sbin/watchdogd to /init
-SYMLINKS := \
-	$(TARGET_ROOT_OUT)/sbin/ueventd \
-	$(TARGET_ROOT_OUT)/sbin/watchdogd
 
-$(SYMLINKS): INIT_BINARY := $(LOCAL_MODULE)
-$(SYMLINKS): $(LOCAL_INSTALLED_MODULE) $(LOCAL_PATH)/Android.mk
-	@echo "Symlink: $@ -> ../$(INIT_BINARY)"
-	@mkdir -p $(dir $@)
-	@rm -rf $@
-	$(hide) ln -sf ../$(INIT_BINARY) $@
 
-ALL_DEFAULT_INSTALLED_MODULES += $(SYMLINKS)
 
-# We need this so that the installed files could be picked up based on the
-# local module name
-ALL_MODULES.$(LOCAL_MODULE).INSTALLED := \
-    $(ALL_MODULES.$(LOCAL_MODULE).INSTALLED) $(SYMLINKS)
+include $(CLEAR_VARS)
+LOCAL_MODULE := init_tests
+LOCAL_SRC_FILES := \
+    init_parser_test.cpp \
+    util_test.cpp \
+
+LOCAL_SHARED_LIBRARIES += \
+    libcutils \
+    libbase \
+
+LOCAL_STATIC_LIBRARIES := libinit
+LOCAL_CLANG := $(init_clang)
+include $(BUILD_NATIVE_TEST)
diff --git a/init/README.BOOTCHART b/init/README.BOOTCHART
deleted file mode 100644
index 70cf2c3..0000000
--- a/init/README.BOOTCHART
+++ /dev/null
@@ -1,52 +0,0 @@
-This version of init contains code to perform "bootcharting", i.e. generating log
-files that can be later processed by the tools provided by www.bootchart.org.
-
-To activate it, you need to define build 'init' with the INIT_BOOTCHART environment
-variable defined to 'true', for example:
-
-    touch system/init/init.c
-    m INIT_BOOTCHART=true
-
-On the emulator, use the new -bootchart <timeout> option to boot with bootcharting
-activated for <timeout> seconds.
-
-Otherwise, flash your device, and start it. Then create a file on the /data partition
-with a command like the following:
-
-  adb shell 'echo $TIMEOUT > /data/bootchart-start'
-
-Where the value of $TIMEOUT corresponds to the wanted bootcharted period in seconds;
-for example, to bootchart for 2 minutes, do:
-
-  adb shell 'echo 120 > /data/bootchart-start'
-
-Reboot your device, bootcharting will begin and stop after the period you gave.
-You can also stop the bootcharting at any moment by doing the following:
-
-  adb shell 'echo 1 > /data/bootchart-stop'
-
-Note that /data/bootchart-stop is deleted automatically by init at the end of the
-bootcharting. This is not the case of /data/bootchart-start, so don't forget to delete it
-when you're done collecting data:
-
-  adb shell rm /data/bootchart-start
-
-The log files are placed in /data/bootchart/. you must run the script tools/grab-bootchart.sh
-which will use ADB to retrieve them and create a bootchart.tgz file that can be used with
-the bootchart parser/renderer, or even uploaded directly to the form located at:
-
-  http://www.bootchart.org/download.html
-
-NOTE: the bootchart.org webform doesn't seem to work at the moment, you can generate an
-      image on your machine by doing the following:
-
-         1/ download the sources from www.bootchart.org
-         2/ unpack them
-         3/ in the source directory, type 'ant' to build the bootchart program
-         4/ type 'java -jar bootchart.jar /path/to/bootchart.tgz
-
-technical note:
-
-this implementation of bootcharting does use the 'bootchartd' script provided by
-www.bootchart.org, but a C re-implementation that is directly compiled into our init
-program.
diff --git a/init/bootchart.c b/init/bootchart.c
deleted file mode 100644
index f72fcaa..0000000
--- a/init/bootchart.c
+++ /dev/null
@@ -1,378 +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.
- */
-
-/* this code is used to generate a boot sequence profile that can be used
- * with the 'bootchart' graphics generation tool. see www.bootchart.org
- * note that unlike the original bootchartd, this is not a Bash script but
- * some C code that is run right from the init script.
- */
-
-#include <stdio.h>
-#include <time.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include "bootchart.h"
-
-#define VERSION         "0.8"
-#define SAMPLE_PERIOD   0.2
-#define LOG_ROOT        "/data/bootchart"
-#define LOG_STAT        LOG_ROOT"/proc_stat.log"
-#define LOG_PROCS       LOG_ROOT"/proc_ps.log"
-#define LOG_DISK        LOG_ROOT"/proc_diskstats.log"
-#define LOG_HEADER      LOG_ROOT"/header"
-#define LOG_ACCT        LOG_ROOT"/kernel_pacct"
-
-#define LOG_STARTFILE   "/data/bootchart-start"
-#define LOG_STOPFILE    "/data/bootchart-stop"
-
-static int
-unix_read(int  fd, void*  buff, int  len)
-{
-    int  ret;
-    do { ret = read(fd, buff, len); } while (ret < 0 && errno == EINTR);
-    return ret;
-}
-
-static int
-unix_write(int  fd, const void*  buff, int  len)
-{
-    int  ret;
-    do { ret = write(fd, buff, len); } while (ret < 0 && errno == EINTR);
-    return ret;
-}
-
-static int
-proc_read(const char*  filename, char* buff, size_t  buffsize)
-{
-    int  len = 0;
-    int  fd  = open(filename, O_RDONLY);
-    if (fd >= 0) {
-        len = unix_read(fd, buff, buffsize-1);
-        close(fd);
-    }
-    buff[len > 0 ? len : 0] = 0;
-    return len;
-}
-
-#define FILE_BUFF_SIZE    65536
-
-typedef struct {
-    int   count;
-    int   fd;
-    char  data[FILE_BUFF_SIZE];
-} FileBuffRec, *FileBuff;
-
-static void
-file_buff_open( FileBuff  buff, const char*  path )
-{
-    buff->count = 0;
-    buff->fd    = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0755);
-}
-
-static void
-file_buff_write( FileBuff  buff, const void*  src, int  len )
-{
-    while (len > 0) {
-        int  avail = sizeof(buff->data) - buff->count;
-        if (avail > len)
-            avail = len;
-
-        memcpy( buff->data + buff->count, src, avail );
-        len -= avail;
-        src  = (char*)src + avail;
-
-        buff->count += avail;
-        if (buff->count == FILE_BUFF_SIZE) {
-            unix_write( buff->fd, buff->data, buff->count );
-            buff->count = 0;
-        }
-    }
-}
-
-static void
-file_buff_done( FileBuff  buff )
-{
-    if (buff->count > 0) {
-        unix_write( buff->fd, buff->data, buff->count );
-        buff->count = 0;
-    }
-}
-
-static void
-log_header(void)
-{
-    FILE*      out;
-    char       cmdline[1024];
-    char       uname[128];
-    char       cpuinfo[128];
-    char*      cpu;
-    char       date[32];
-    time_t     now_t = time(NULL);
-    struct tm  now = *localtime(&now_t);
-    strftime(date, sizeof(date), "%x %X", &now);
-
-    out = fopen( LOG_HEADER, "w" );
-    if (out == NULL)
-        return;
-
-    proc_read("/proc/cmdline", cmdline, sizeof(cmdline));
-    proc_read("/proc/version", uname, sizeof(uname));
-    proc_read("/proc/cpuinfo", cpuinfo, sizeof(cpuinfo));
-
-    cpu = strchr( cpuinfo, ':' );
-    if (cpu) {
-        char*  p = strchr(cpu, '\n');
-        cpu += 2;
-        if (p)
-            *p = 0;
-    }
-
-    fprintf(out, "version = %s\n", VERSION);
-    fprintf(out, "title = Boot chart for Android ( %s )\n", date);
-    fprintf(out, "system.uname = %s\n", uname);
-    fprintf(out, "system.release = 0.0\n");
-    fprintf(out, "system.cpu = %s\n", cpu);
-    fprintf(out, "system.kernel.options = %s\n", cmdline);
-    fclose(out);
-}
-
-static void
-close_on_exec(int  fd)
-{
-    fcntl(fd, F_SETFD, FD_CLOEXEC);
-}
-
-static void
-open_log_file(int*  plogfd, const char*  logfile)
-{
-    int    logfd = *plogfd;
-
-    /* create log file if needed */
-    if (logfd < 0) 
-    {
-        logfd = open(logfile,O_WRONLY|O_CREAT|O_TRUNC,0755);
-        if (logfd < 0) {
-            *plogfd = -2;
-            return;
-        }
-        close_on_exec(logfd);
-        *plogfd = logfd;
-    }
-}
-
-static void
-do_log_uptime(FileBuff  log)
-{
-    char  buff[65];
-    int   fd, ret, len;
-
-    fd = open("/proc/uptime",O_RDONLY);
-    if (fd >= 0) {
-        int  ret;
-        ret = unix_read(fd, buff, 64);
-        close(fd);
-        buff[64] = 0;
-        if (ret >= 0) {
-            long long  jiffies = 100LL*strtod(buff,NULL);
-            int        len;
-            snprintf(buff,sizeof(buff),"%lld\n",jiffies);
-            len = strlen(buff);
-            file_buff_write(log, buff, len);
-        }
-    }
-}
-
-static void
-do_log_ln(FileBuff  log)
-{
-    file_buff_write(log, "\n", 1);
-}
-
-
-static void
-do_log_file(FileBuff  log, const char*  procfile)
-{
-    char   buff[1024];
-    int    fd;
-
-    do_log_uptime(log);
-
-    /* append file content */
-    fd = open(procfile,O_RDONLY);
-    if (fd >= 0) {
-        close_on_exec(fd);
-        for (;;) {
-            int  ret;
-            ret = unix_read(fd, buff, sizeof(buff));
-            if (ret <= 0)
-                break;
-
-            file_buff_write(log, buff, ret);
-            if (ret < (int)sizeof(buff))
-                break;
-        }
-        close(fd);
-    }
-
-    do_log_ln(log);
-}
-
-static void
-do_log_procs(FileBuff  log)
-{
-    DIR*  dir = opendir("/proc");
-    struct dirent*  entry;
-
-    do_log_uptime(log);
-
-    while ((entry = readdir(dir)) != NULL) {
-        /* only match numeric values */
-        char*  end;
-        int    pid = strtol( entry->d_name, &end, 10);
-        if (end != NULL && end > entry->d_name && *end == 0) {
-            char  filename[32];
-            char  buff[1024];
-            char  cmdline[1024];
-            int   len;
-            int   fd;
-
-            /* read command line and extract program name */
-            snprintf(filename,sizeof(filename),"/proc/%d/cmdline",pid);
-            proc_read(filename, cmdline, sizeof(cmdline));
-
-            /* read process stat line */
-            snprintf(filename,sizeof(filename),"/proc/%d/stat",pid);
-            fd = open(filename,O_RDONLY);
-            if (fd >= 0) {
-               len = unix_read(fd, buff, sizeof(buff)-1);
-               close(fd);
-               if (len > 0) {
-                    int  len2 = strlen(cmdline);
-                    if (len2 > 0) {
-                        /* we want to substitute the process name with its real name */
-                        const char*  p1;
-                        const char*  p2;
-                        buff[len] = 0;
-                        p1 = strchr(buff, '(');
-                        p2 = strchr(p1, ')');
-                        file_buff_write(log, buff, p1+1-buff);
-                        file_buff_write(log, cmdline, strlen(cmdline));
-                        file_buff_write(log, p2, strlen(p2));
-                    } else {
-                        /* no substitution */
-                        file_buff_write(log,buff,len);
-                    }
-               }
-            }
-        }
-    }
-    closedir(dir);
-    do_log_ln(log);
-}
-
-static FileBuffRec  log_stat[1];
-static FileBuffRec  log_procs[1];
-static FileBuffRec  log_disks[1];
-
-/* called to setup bootcharting */
-int   bootchart_init( void )
-{
-    int  ret;
-    char buff[4];
-    int  timeout = 0, count = 0;
-
-    buff[0] = 0;
-    proc_read( LOG_STARTFILE, buff, sizeof(buff) );
-    if (buff[0] != 0) {
-        timeout = atoi(buff);
-    }
-    else {
-        /* when running with emulator, androidboot.bootchart=<timeout>
-         * might be passed by as kernel parameters to specify the bootchart
-         * timeout. this is useful when using -wipe-data since the /data
-         * partition is fresh
-         */
-        char  cmdline[1024];
-        char* s;
-#define  KERNEL_OPTION  "androidboot.bootchart="
-        proc_read( "/proc/cmdline", cmdline, sizeof(cmdline) );
-        s = strstr(cmdline, KERNEL_OPTION);
-        if (s) {
-            s      += sizeof(KERNEL_OPTION)-1;
-            timeout = atoi(s);
-        }
-    }
-    if (timeout == 0)
-        return 0;
-
-    if (timeout > BOOTCHART_MAX_TIME_SEC)
-        timeout = BOOTCHART_MAX_TIME_SEC;
-
-    count = (timeout*1000 + BOOTCHART_POLLING_MS-1)/BOOTCHART_POLLING_MS;
-
-    do {ret=mkdir(LOG_ROOT,0755);}while (ret < 0 && errno == EINTR);
-
-    file_buff_open(log_stat,  LOG_STAT);
-    file_buff_open(log_procs, LOG_PROCS);
-    file_buff_open(log_disks, LOG_DISK);
-
-    /* create kernel process accounting file */
-    {
-        int  fd = open( LOG_ACCT, O_WRONLY|O_CREAT|O_TRUNC,0644);
-        if (fd >= 0) {
-            close(fd);
-            acct( LOG_ACCT );
-        }
-    }
-
-    log_header();
-    return count;
-}
-
-/* called each time you want to perform a bootchart sampling op */
-int  bootchart_step( void )
-{
-    do_log_file(log_stat,   "/proc/stat");
-    do_log_file(log_disks,  "/proc/diskstats");
-    do_log_procs(log_procs);
-
-    /* we stop when /data/bootchart-stop contains 1 */
-    {
-        char  buff[2];
-        if (proc_read(LOG_STOPFILE,buff,sizeof(buff)) > 0 && buff[0] == '1') {
-            return -1;
-        }
-    }
-
-    return 0;
-}
-
-void  bootchart_finish( void )
-{
-    unlink( LOG_STOPFILE );
-    file_buff_done(log_stat);
-    file_buff_done(log_disks);
-    file_buff_done(log_procs);
-    acct(NULL);
-}
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
new file mode 100644
index 0000000..95687cb
--- /dev/null
+++ b/init/bootchart.cpp
@@ -0,0 +1,273 @@
+/*
+ * 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 "bootchart.h"
+#include "keywords.h"
+#include "log.h"
+#include "property_service.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <memory>
+#include <string>
+
+#include <base/file.h>
+
+#define LOG_ROOT        "/data/bootchart"
+#define LOG_STAT        LOG_ROOT"/proc_stat.log"
+#define LOG_PROCS       LOG_ROOT"/proc_ps.log"
+#define LOG_DISK        LOG_ROOT"/proc_diskstats.log"
+#define LOG_HEADER      LOG_ROOT"/header"
+#define LOG_ACCT        LOG_ROOT"/kernel_pacct"
+
+#define LOG_STARTFILE   LOG_ROOT"/start"
+#define LOG_STOPFILE    LOG_ROOT"/stop"
+
+// Polling period in ms.
+static const int BOOTCHART_POLLING_MS = 200;
+
+// Max polling time in seconds.
+static const int BOOTCHART_MAX_TIME_SEC = 10*60;
+
+static long long g_last_bootchart_time;
+static int g_remaining_samples;
+
+static FILE* log_stat;
+static FILE* log_procs;
+static FILE* log_disks;
+
+static long long get_uptime_jiffies() {
+    std::string uptime;
+    if (!android::base::ReadFileToString("/proc/uptime", &uptime)) {
+        return 0;
+    }
+    return 100LL * strtod(uptime.c_str(), NULL);
+}
+
+static void log_header() {
+    char date[32];
+    time_t now_t = time(NULL);
+    struct tm now = *localtime(&now_t);
+    strftime(date, sizeof(date), "%F %T", &now);
+
+    utsname uts;
+    if (uname(&uts) == -1) {
+        return;
+    }
+
+    char fingerprint[PROP_VALUE_MAX];
+    if (property_get("ro.build.fingerprint", fingerprint) == -1) {
+        return;
+    }
+
+    std::string kernel_cmdline;
+    android::base::ReadFileToString("/proc/cmdline", &kernel_cmdline);
+
+    FILE* out = fopen(LOG_HEADER, "we");
+    if (out == NULL) {
+        return;
+    }
+    fprintf(out, "version = Android init 0.8 " __TIME__  "\n");
+    fprintf(out, "title = Boot chart for Android (%s)\n", date);
+    fprintf(out, "system.uname = %s %s %s %s\n", uts.sysname, uts.release, uts.version, uts.machine);
+    fprintf(out, "system.release = %s\n", fingerprint);
+    // TODO: use /proc/cpuinfo "model name" line for x86, "Processor" line for arm.
+    fprintf(out, "system.cpu = %s\n", uts.machine);
+    fprintf(out, "system.kernel.options = %s\n", kernel_cmdline.c_str());
+    fclose(out);
+}
+
+static void do_log_uptime(FILE* log) {
+    fprintf(log, "%lld\n", get_uptime_jiffies());
+}
+
+static void do_log_file(FILE* log, const char* procfile) {
+    do_log_uptime(log);
+
+    std::string content;
+    if (android::base::ReadFileToString(procfile, &content)) {
+        fprintf(log, "%s\n", content.c_str());
+    }
+}
+
+static void do_log_procs(FILE* log) {
+    do_log_uptime(log);
+
+    std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir("/proc"), closedir);
+    struct dirent* entry;
+    while ((entry = readdir(dir.get())) != NULL) {
+        // Only match numeric values.
+        char* end;
+        int pid = strtol(entry->d_name, &end, 10);
+        if (end != NULL && end > entry->d_name && *end == 0) {
+            char filename[32];
+
+            // /proc/<pid>/stat only has truncated task names, so get the full
+            // name from /proc/<pid>/cmdline.
+            snprintf(filename, sizeof(filename), "/proc/%d/cmdline", pid);
+            std::string cmdline;
+            android::base::ReadFileToString(filename, &cmdline);
+            const char* full_name = cmdline.c_str(); // So we stop at the first NUL.
+
+            // Read process stat line.
+            snprintf(filename, sizeof(filename), "/proc/%d/stat", pid);
+            std::string stat;
+            if (android::base::ReadFileToString(filename, &stat)) {
+                if (!cmdline.empty()) {
+                    // Substitute the process name with its real name.
+                    size_t open = stat.find('(');
+                    size_t close = stat.find_last_of(')');
+                    if (open != std::string::npos && close != std::string::npos) {
+                        stat.replace(open + 1, close - open - 1, full_name);
+                    }
+                }
+                fputs(stat.c_str(), log);
+            }
+        }
+    }
+
+    fputc('\n', log);
+}
+
+static int bootchart_init() {
+    int timeout = 0;
+
+    std::string start;
+    android::base::ReadFileToString(LOG_STARTFILE, &start);
+    if (!start.empty()) {
+        timeout = atoi(start.c_str());
+    } else {
+        // When running with emulator, androidboot.bootchart=<timeout>
+        // might be passed by as kernel parameters to specify the bootchart
+        // timeout. this is useful when using -wipe-data since the /data
+        // partition is fresh.
+        std::string cmdline;
+        android::base::ReadFileToString("/proc/cmdline", &cmdline);
+#define KERNEL_OPTION  "androidboot.bootchart="
+        if (strstr(cmdline.c_str(), KERNEL_OPTION) != NULL) {
+            timeout = atoi(cmdline.c_str() + sizeof(KERNEL_OPTION) - 1);
+        }
+    }
+    if (timeout == 0)
+        return 0;
+
+    if (timeout > BOOTCHART_MAX_TIME_SEC)
+        timeout = BOOTCHART_MAX_TIME_SEC;
+
+    int count = (timeout*1000 + BOOTCHART_POLLING_MS-1)/BOOTCHART_POLLING_MS;
+
+    log_stat = fopen(LOG_STAT, "we");
+    if (log_stat == NULL) {
+        return -1;
+    }
+    log_procs = fopen(LOG_PROCS, "we");
+    if (log_procs == NULL) {
+        fclose(log_stat);
+        return -1;
+    }
+    log_disks = fopen(LOG_DISK, "we");
+    if (log_disks == NULL) {
+        fclose(log_stat);
+        fclose(log_procs);
+        return -1;
+    }
+
+    // Create kernel process accounting file.
+    close(open(LOG_ACCT, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644));
+    acct(LOG_ACCT);
+
+    log_header();
+    return count;
+}
+
+int do_bootchart_init(int nargs, char** args) {
+    g_remaining_samples = bootchart_init();
+    if (g_remaining_samples < 0) {
+        ERROR("Bootcharting init failure: %s\n", strerror(errno));
+    } else if (g_remaining_samples > 0) {
+        NOTICE("Bootcharting started (will run for %d s).\n",
+               (g_remaining_samples * BOOTCHART_POLLING_MS) / 1000);
+    } else {
+        NOTICE("Not bootcharting.\n");
+    }
+    return 0;
+}
+
+static int bootchart_step() {
+    do_log_file(log_stat,   "/proc/stat");
+    do_log_file(log_disks,  "/proc/diskstats");
+    do_log_procs(log_procs);
+
+    // Stop if /data/bootchart/stop contains 1.
+    std::string stop;
+    if (android::base::ReadFileToString(LOG_STOPFILE, &stop) && stop == "1") {
+        return -1;
+    }
+
+    return 0;
+}
+
+/* called to get time (in ms) used by bootchart */
+static long long bootchart_gettime() {
+    return 10LL*get_uptime_jiffies();
+}
+
+static void bootchart_finish() {
+    unlink(LOG_STOPFILE);
+    fclose(log_stat);
+    fclose(log_disks);
+    fclose(log_procs);
+    acct(NULL);
+}
+
+void bootchart_sample(int* timeout) {
+    // Do we have any more bootcharting to do?
+    if (g_remaining_samples <= 0) {
+        return;
+    }
+
+    long long current_time = bootchart_gettime();
+    int elapsed_time = current_time - g_last_bootchart_time;
+
+    if (elapsed_time >= BOOTCHART_POLLING_MS) {
+        /* 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 */
+        g_last_bootchart_time = current_time;
+        if (bootchart_step() < 0 || g_remaining_samples <= 0) {
+            bootchart_finish();
+            g_remaining_samples = 0;
+        }
+    }
+    if (g_remaining_samples > 0) {
+        int remaining_time = BOOTCHART_POLLING_MS - elapsed_time;
+        if (*timeout < 0 || *timeout > remaining_time) {
+            *timeout = remaining_time;
+        }
+    }
+}
diff --git a/init/bootchart.h b/init/bootchart.h
index 39d2d4f..cf61d83 100644
--- a/init/bootchart.h
+++ b/init/bootchart.h
@@ -17,20 +17,6 @@
 #ifndef _BOOTCHART_H
 #define _BOOTCHART_H
 
-#ifndef BOOTCHART
-# define  BOOTCHART  0
-#endif
-
-#if BOOTCHART
-
-extern int   bootchart_init(void);
-extern int   bootchart_step(void);
-extern void  bootchart_finish(void);
-
-# define BOOTCHART_POLLING_MS   200   /* polling period in ms */
-# define BOOTCHART_DEFAULT_TIME_SEC    (2*60)  /* default polling time in seconds */
-# define BOOTCHART_MAX_TIME_SEC        (10*60) /* max polling time in seconds */
-
-#endif /* BOOTCHART */
+void bootchart_sample(int* timeout);
 
 #endif /* _BOOTCHART_H */
diff --git a/init/builtins.c b/init/builtins.cpp
similarity index 80%
rename from init/builtins.c
rename to init/builtins.cpp
index c192551..9e5f9ff 100644
--- a/init/builtins.c
+++ b/init/builtins.cpp
@@ -14,30 +14,32 @@
  * limitations under the License.
  */
 
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-#include <linux/kd.h>
 #include <errno.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <linux/if.h>
-#include <arpa/inet.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
 #include <sys/mount.h>
 #include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 #include <sys/wait.h>
+#include <unistd.h>
 #include <linux/loop.h>
-#include <cutils/partition_utils.h>
-#include <cutils/android_reboot.h>
-#include <fs_mgr.h>
+#include <ext4_crypt_init_extensions.h>
 
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 
+#include <fs_mgr.h>
+#include <base/stringprintf.h>
+#include <cutils/partition_utils.h>
+#include <cutils/android_reboot.h>
+#include <private/android_filesystem_config.h>
+
 #include "init.h"
 #include "keywords.h"
 #include "property_service.h"
@@ -46,121 +48,28 @@
 #include "util.h"
 #include "log.h"
 
-#include <private/android_filesystem_config.h>
+#define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW
 
 int add_environment(const char *name, const char *value);
 
-extern int init_module(void *, unsigned long, const char *);
-
-static int write_file(const char *path, const char *value)
-{
-    int fd, ret, len;
-
-    fd = open(path, O_WRONLY|O_CREAT|O_NOFOLLOW, 0600);
-
-    if (fd < 0)
-        return -errno;
-
-    len = strlen(value);
-
-    do {
-        ret = write(fd, value, len);
-    } while (ret < 0 && errno == EINTR);
-
-    close(fd);
-    if (ret < 0) {
-        return -errno;
-    } else {
-        return 0;
-    }
-}
-
-static int _open(const char *path)
-{
-    int fd;
-
-    fd = open(path, O_RDONLY | O_NOFOLLOW);
-    if (fd < 0)
-        fd = open(path, O_WRONLY | O_NOFOLLOW);
-
-    return fd;
-}
-
-static int _chown(const char *path, unsigned int uid, unsigned int gid)
-{
-    int fd;
-    int ret;
-
-    fd = _open(path);
-    if (fd < 0) {
-        return -1;
-    }
-
-    ret = fchown(fd, uid, gid);
-    if (ret < 0) {
-        int errno_copy = errno;
-        close(fd);
-        errno = errno_copy;
-        return -1;
-    }
-
-    close(fd);
-
-    return 0;
-}
-
-static int _chmod(const char *path, mode_t mode)
-{
-    int fd;
-    int ret;
-
-    fd = _open(path);
-    if (fd < 0) {
-        return -1;
-    }
-
-    ret = fchmod(fd, mode);
-    if (ret < 0) {
-        int errno_copy = errno;
-        close(fd);
-        errno = errno_copy;
-        return -1;
-    }
-
-    close(fd);
-
-    return 0;
-}
+// System call provided by bionic but not in any header file.
+extern "C" int init_module(void *, unsigned long, const char *);
 
 static int insmod(const char *filename, char *options)
 {
-    void *module;
-    unsigned size;
-    int ret;
+    char filename_val[PROP_VALUE_MAX];
+    if (expand_props(filename_val, filename, sizeof(filename_val)) == -1) {
+        ERROR("insmod: cannot expand '%s'\n", filename);
+        return -EINVAL;
+    }
 
-    module = read_file(filename, &size);
-    if (!module)
+    std::string module;
+    if (!read_file(filename_val, &module)) {
         return -1;
+    }
 
-    ret = init_module(module, size, options);
-
-    free(module);
-
-    return ret;
-}
-
-static int setkey(struct kbentry *kbe)
-{
-    int fd, ret;
-
-    fd = open("/dev/tty0", O_RDWR | O_SYNC);
-    if (fd < 0)
-        return -1;
-
-    ret = ioctl(fd, KDSKBENT, kbe);
-
-    close(fd);
-    return ret;
+    // TODO: use finit_module for >= 3.8 kernels.
+    return init_module(&module[0], module.size(), options);
 }
 
 static int __ifupdown(const char *interface, int up)
@@ -185,7 +94,7 @@
         ifr.ifr_flags &= ~IFF_UP;
 
     ret = ioctl(s, SIOCSIFFLAGS, &ifr);
-    
+
 done:
     close(s);
     return ret;
@@ -200,18 +109,6 @@
     }
 }
 
-int do_chdir(int nargs, char **args)
-{
-    chdir(args[1]);
-    return 0;
-}
-
-int do_chroot(int nargs, char **args)
-{
-    chroot(args[1]);
-    return 0;
-}
-
 int do_class_start(int nargs, char **args)
 {
         /* Starting a class does not start services
@@ -254,9 +151,13 @@
     return 0;
 }
 
-int do_exec(int nargs, char **args)
-{
-    return -1;
+int do_exec(int nargs, char** args) {
+    service* svc = make_exec_oneshot_service(nargs, args);
+    if (svc == NULL) {
+        return -1;
+    }
+    service_start(svc, NULL);
+    return 0;
 }
 
 int do_export(int nargs, char **args)
@@ -319,7 +220,7 @@
     ret = make_dir(args[1], mode);
     /* chmod in case the directory already exists */
     if (ret == -1 && errno == EEXIST) {
-        ret = _chmod(args[1], mode);
+        ret = fchmodat(AT_FDCWD, args[1], mode, AT_SYMLINK_NOFOLLOW);
     }
     if (ret == -1) {
         return -errno;
@@ -333,20 +234,20 @@
             gid = decode_uid(args[4]);
         }
 
-        if (_chown(args[1], uid, gid) < 0) {
+        if (lchown(args[1], uid, gid) == -1) {
             return -errno;
         }
 
         /* chown may have cleared S_ISUID and S_ISGID, chmod again */
         if (mode & (S_ISUID | S_ISGID)) {
-            ret = _chmod(args[1], mode);
+            ret = fchmodat(AT_FDCWD, args[1], mode, AT_SYMLINK_NOFOLLOW);
             if (ret == -1) {
                 return -errno;
             }
         }
     }
 
-    return 0;
+    return e4crypt_set_directory_policy(args[1]);
 }
 
 static struct {
@@ -410,7 +311,7 @@
             return -1;
         }
 
-        sprintf(tmp, "/dev/block/mtdblock%d", n);
+        snprintf(tmp, sizeof(tmp), "/dev/block/mtdblock%d", n);
 
         if (wait)
             wait_for_file(tmp, COMMAND_RETRY_TIMEOUT);
@@ -424,15 +325,16 @@
         struct loop_info info;
 
         mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR;
-        fd = open(source + 5, mode);
+        fd = open(source + 5, mode | O_CLOEXEC);
         if (fd < 0) {
             return -1;
         }
 
         for (n = 0; ; n++) {
-            sprintf(tmp, "/dev/block/loop%d", n);
-            loop = open(tmp, mode);
+            snprintf(tmp, sizeof(tmp), "/dev/block/loop%d", n);
+            loop = open(tmp, mode | O_CLOEXEC);
             if (loop < 0) {
+                close(fd);
                 return -1;
             }
 
@@ -476,7 +378,7 @@
 static int wipe_data_via_recovery()
 {
     mkdir("/cache/recovery", 0700);
-    int fd = open("/cache/recovery/command", O_RDWR|O_CREAT|O_TRUNC, 0600);
+    int fd = open("/cache/recovery/command", O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0600);
     if (fd >= 0) {
         write(fd, "--wipe_data\n", strlen("--wipe_data\n") + 1);
         write(fd, "--reason=wipe_data_via_recovery\n", strlen("--reason=wipe_data_via_recovery\n") + 1);
@@ -489,7 +391,6 @@
     while (1) { pause(); }  // never reached
 }
 
-
 /*
  * This function might request a reboot, in which case it will
  * not return.
@@ -500,7 +401,6 @@
     int ret = -1;
     int child_ret = -1;
     int status;
-    const char *prop;
     struct fstab *fstab;
 
     if (nargs != 2) {
@@ -519,7 +419,7 @@
         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, errno=%d\n", wp_ret, errno);
+            NOTICE("waitpid failed rc=%d: %s\n", wp_ret, strerror(errno));
         }
 
         if (WIFEXITED(status)) {
@@ -546,6 +446,7 @@
         property_set("vold.decrypt", "trigger_encryption");
     } else if (ret == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
         property_set("ro.crypto.state", "encrypted");
+        property_set("ro.crypto.type", "block");
         property_set("vold.decrypt", "trigger_default_encryption");
     } else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
         property_set("ro.crypto.state", "unencrypted");
@@ -558,6 +459,23 @@
         ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n");
         ret = wipe_data_via_recovery();
         /* If reboot worked, there is no return. */
+    } else if (ret == FS_MGR_MNTALL_DEV_DEFAULT_FILE_ENCRYPTED) {
+        if (e4crypt_install_keyring()) {
+            return -1;
+        }
+        property_set("ro.crypto.state", "encrypted");
+        property_set("ro.crypto.type", "file");
+
+        // Although encrypted, we have device key, so we do not need to
+        // do anything different from the nonencrypted case.
+        action_for_each_trigger("nonencrypted", action_add_queue_tail);
+    } else if (ret == FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED) {
+        if (e4crypt_install_keyring()) {
+            return -1;
+        }
+        property_set("ro.crypto.state", "encrypted");
+        property_set("ro.crypto.type", "file");
+        property_set("vold.decrypt", "trigger_restart_min_framework");
     } else if (ret > 0) {
         ERROR("fs_mgr_mount_all returned unexpected error %d\n", ret);
     }
@@ -578,33 +496,6 @@
     return ret;
 }
 
-int do_setcon(int nargs, char **args) {
-    if (is_selinux_enabled() <= 0)
-        return 0;
-    if (setcon(args[1]) < 0) {
-        return -errno;
-    }
-    return 0;
-}
-
-int do_setenforce(int nargs, char **args) {
-    if (is_selinux_enabled() <= 0)
-        return 0;
-    if (security_setenforce(atoi(args[1])) < 0) {
-        return -errno;
-    }
-    return 0;
-}
-
-int do_setkey(int nargs, char **args)
-{
-    struct kbentry kbe;
-    kbe.kb_table = strtoul(args[1], 0, 0);
-    kbe.kb_index = strtoul(args[2], 0, 0);
-    kbe.kb_value = strtoul(args[3], 0, 0);
-    return setkey(&kbe);
-}
-
 int do_setprop(int nargs, char **args)
 {
     const char *name = args[1];
@@ -667,7 +558,7 @@
     int res;
     int len = 0;
     int cmd = 0;
-    char *reboot_target;
+    const char *reboot_target;
 
     res = expand_props(command, args[1], sizeof(command));
     if (res) {
@@ -727,25 +618,41 @@
         return -1;
 
     memset(&tz, 0, sizeof(tz));
-    tz.tz_minuteswest = atoi(args[1]);   
+    tz.tz_minuteswest = atoi(args[1]);
     if (settimeofday(NULL, &tz))
         return -1;
     return 0;
 }
 
+int do_verity_load_state(int nargs, char **args) {
+    int mode = -1;
+    int rc = fs_mgr_load_verity_state(&mode);
+    if (rc == 0 && mode == VERITY_MODE_LOGGING) {
+        action_for_each_trigger("verity-logging", action_add_queue_tail);
+    }
+    return rc;
+}
+
+static void verity_update_property(fstab_rec *fstab, const char *mount_point, int mode, int status) {
+    property_set(android::base::StringPrintf("partition.%s.verified", mount_point).c_str(),
+                 android::base::StringPrintf("%d", mode).c_str());
+}
+
+int do_verity_update_state(int nargs, char** args) {
+    return fs_mgr_update_verity_state(verity_update_property);
+}
+
 int do_write(int nargs, char **args)
 {
     const char *path = args[1];
     const char *value = args[2];
-    char prop_val[PROP_VALUE_MAX];
-    int ret;
 
-    ret = expand_props(prop_val, value, sizeof(prop_val));
-    if (ret) {
+    char expanded_value[256];
+    if (expand_props(expanded_value, value, sizeof(expanded_value))) {
         ERROR("cannot expand '%s' while writing to '%s'\n", value, path);
         return -EINVAL;
     }
-    return write_file(path, prop_val);
+    return write_file(path, expanded_value);
 }
 
 int do_copy(int nargs, char **args)
@@ -760,16 +667,16 @@
     if (nargs != 3)
         return -1;
 
-    if (stat(args[1], &info) < 0) 
+    if (stat(args[1], &info) < 0)
         return -1;
 
-    if ((fd1 = open(args[1], O_RDONLY)) < 0) 
+    if ((fd1 = open(args[1], O_RDONLY|O_CLOEXEC)) < 0)
         goto out_err;
 
-    if ((fd2 = open(args[2], O_WRONLY|O_CREAT|O_TRUNC, 0660)) < 0)
+    if ((fd2 = open(args[2], O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0660)) < 0)
         goto out_err;
 
-    if (!(buffer = malloc(info.st_size)))
+    if (!(buffer = (char*) malloc(info.st_size)))
         goto out_err;
 
     p = buffer;
@@ -813,10 +720,10 @@
 int do_chown(int nargs, char **args) {
     /* GID is optional. */
     if (nargs == 3) {
-        if (_chown(args[2], decode_uid(args[1]), -1) < 0)
+        if (lchown(args[2], decode_uid(args[1]), -1) == -1)
             return -errno;
     } else if (nargs == 4) {
-        if (_chown(args[3], decode_uid(args[1]), decode_uid(args[2])) < 0)
+        if (lchown(args[3], decode_uid(args[1]), decode_uid(args[2])) == -1)
             return -errno;
     } else {
         return -1;
@@ -839,7 +746,7 @@
 
 int do_chmod(int nargs, char **args) {
     mode_t mode = get_mode(args[1]);
-    if (_chmod(args[2], mode) < 0) {
+    if (fchmodat(AT_FDCWD, args[2], mode, AT_SYMLINK_NOFOLLOW) < 0) {
         return -errno;
     }
     return 0;
@@ -867,34 +774,6 @@
     return ret;
 }
 
-int do_setsebool(int nargs, char **args) {
-    const char *name = args[1];
-    const char *value = args[2];
-    SELboolean b;
-    int ret;
-
-    if (is_selinux_enabled() <= 0)
-        return 0;
-
-    b.name = name;
-    if (!strcmp(value, "1") || !strcasecmp(value, "true") || !strcasecmp(value, "on"))
-        b.value = 1;
-    else if (!strcmp(value, "0") || !strcasecmp(value, "false") || !strcasecmp(value, "off"))
-        b.value = 0;
-    else {
-        ERROR("setsebool: invalid value %s\n", value);
-        return -EINVAL;
-    }
-
-    if (security_set_boolean_list(1, &b, 0) < 0) {
-        ret = -errno;
-        ERROR("setsebool: could not set %s to %s\n", name, value);
-        return ret;
-    }
-
-    return 0;
-}
-
 int do_loglevel(int nargs, char **args) {
     int log_level;
     char log_level_str[PROP_VALUE_MAX] = "";
@@ -941,3 +820,31 @@
     } else
         return -1;
 }
+
+/*
+ * Callback to make a directory from the ext4 code
+ */
+static int do_installkeys_ensure_dir_exists(const char* dir)
+{
+    if (make_dir(dir, 0700) && errno != EEXIST) {
+        return -1;
+    }
+
+    return 0;
+}
+
+int do_installkey(int nargs, char **args)
+{
+    if (nargs != 2) {
+        return -1;
+    }
+
+    char prop_value[PROP_VALUE_MAX] = {0};
+    property_get("ro.crypto.type", prop_value);
+    if (strcmp(prop_value, "file")) {
+        return 0;
+    }
+
+    return e4crypt_create_device_key(args[1],
+                                     do_installkeys_ensure_dir_exists);
+}
diff --git a/init/devices.c b/init/devices.cpp
similarity index 86%
rename from init/devices.c
rename to init/devices.cpp
index 73fe223..4944cec 100644
--- a/init/devices.c
+++ b/init/devices.cpp
@@ -48,12 +48,10 @@
 #include "util.h"
 #include "log.h"
 
-#define UNUSED __attribute__((__unused__))
-
 #define SYSFS_PREFIX    "/sys"
-#define FIRMWARE_DIR1   "/etc/firmware"
-#define FIRMWARE_DIR2   "/vendor/firmware"
-#define FIRMWARE_DIR3   "/firmware/image"
+static const char *firmware_dirs[] = { "/etc/firmware",
+                                       "/vendor/firmware",
+                                       "/firmware/image" };
 
 extern struct selabel_handle *sehandle;
 
@@ -101,7 +99,7 @@
                   mode_t perm, unsigned int uid, unsigned int gid,
                   unsigned short prefix,
                   unsigned short wildcard) {
-    struct perm_node *node = calloc(1, sizeof(*node));
+    struct perm_node *node = (perm_node*) calloc(1, sizeof(*node));
     if (!node)
         return -ENOMEM;
 
@@ -154,7 +152,7 @@
         if ((strlen(upath) + strlen(dp->attr) + 6) > sizeof(buf))
             break;
 
-        sprintf(buf,"/sys%s/%s", upath, dp->attr);
+        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);
@@ -191,7 +189,6 @@
 static mode_t get_device_perm(const char *path, const char **links,
                 unsigned *uid, unsigned *gid)
 {
-    mode_t perm;
     struct listnode *node;
     struct perm_node *perm_node;
     struct perms_ *dp;
@@ -232,7 +229,7 @@
 }
 
 static void make_device(const char *path,
-                        const char *upath UNUSED,
+                        const char */*upath*/,
                         int block, int major, int minor,
                         const char **links)
 {
@@ -269,7 +266,6 @@
 static void add_platform_device(const char *path)
 {
     int path_len = strlen(path);
-    struct listnode *node;
     struct platform_node *bus;
     const char *name = path;
 
@@ -279,18 +275,9 @@
             name += 9;
     }
 
-    list_for_each_reverse(node, &platform_names) {
-        bus = node_to_item(node, struct platform_node, list);
-        if ((bus->path_len < path_len) &&
-                (path[bus->path_len] == '/') &&
-                !strncmp(path, bus->path, bus->path_len))
-            /* subdevice of an existing platform, ignore it */
-            return;
-    }
-
     INFO("adding platform device %s (%s)\n", name, path);
 
-    bus = calloc(1, sizeof(struct platform_node));
+    bus = (platform_node*) calloc(1, sizeof(struct platform_node));
     bus->path = strdup(path);
     bus->path_len = path_len;
     bus->name = bus->path + (name - path);
@@ -367,24 +354,6 @@
     return 0;
 }
 
-#if LOG_UEVENTS
-
-static inline suseconds_t get_usecs(void)
-{
-    struct timeval tv;
-    gettimeofday(&tv, 0);
-    return tv.tv_sec * (suseconds_t) 1000000 + tv.tv_usec;
-}
-
-#define log_event_print(x...) INFO(x)
-
-#else
-
-#define log_event_print(fmt, args...)   do { } while (0)
-#define get_usecs()                     0
-
-#endif
-
 static void parse_event(const char *msg, struct uevent *uevent)
 {
     uevent->action = "";
@@ -433,9 +402,11 @@
             ;
     }
 
-    log_event_print("event { '%s', '%s', '%s', '%s', %d, %d }\n",
-                    uevent->action, uevent->path, uevent->subsystem,
-                    uevent->firmware, uevent->major, uevent->minor);
+    if (LOG_UEVENTS) {
+        INFO("event { '%s', '%s', '%s', '%s', %d, %d }\n",
+             uevent->action, uevent->path, uevent->subsystem,
+             uevent->firmware, uevent->major, uevent->minor);
+    }
 }
 
 static char **get_character_device_symlinks(struct uevent *uevent)
@@ -451,14 +422,14 @@
     if (!pdev)
         return NULL;
 
-    links = malloc(sizeof(char *) * 2);
+    links = (char**) malloc(sizeof(char *) * 2);
     if (!links)
         return NULL;
     memset(links, 0, sizeof(char *) * 2);
 
     /* skip "/devices/platform/<driver>" */
     parent = strchr(uevent->path + pdev->path_len, '/');
-    if (!*parent)
+    if (!parent)
         goto err;
 
     if (!strncmp(parent, "/usb", 4)) {
@@ -497,15 +468,10 @@
     struct platform_node *pdev;
     char *slash;
     const char *type;
-    int width;
     char buf[256];
     char link_path[256];
-    int fd;
     int link_num = 0;
-    int ret;
     char *p;
-    unsigned int size;
-    struct stat info;
 
     pdev = find_platform_device(uevent->path);
     if (pdev) {
@@ -518,7 +484,7 @@
         return NULL;
     }
 
-    char **links = malloc(sizeof(char *) * 4);
+    char **links = (char**) malloc(sizeof(char *) * 4);
     if (!links)
         return NULL;
     memset(links, 0, sizeof(char *) * 4);
@@ -667,14 +633,9 @@
     mkdir_recursive(dir, 0755);
 }
 
-static inline void __attribute__((__deprecated__)) kernel_logger()
-{
-    INFO("kernel logger is deprecated\n");
-}
-
 static void handle_generic_device_event(struct uevent *uevent)
 {
-    char *base;
+    const char *base;
     const char *name;
     char devpath[DEVPATH_LEN] = {0};
     char **links = NULL;
@@ -758,7 +719,7 @@
          make_dir(base, 0755);
      } else if(!strncmp(uevent->subsystem, "misc", 4) &&
                  !strncmp(name, "log_", 4)) {
-         kernel_logger();
+         INFO("kernel logger is deprecated\n");
          base = "/dev/log/";
          make_dir(base, 0755);
          name += 4;
@@ -840,8 +801,9 @@
 
 static void process_firmware_event(struct uevent *uevent)
 {
-    char *root, *loading, *data, *file1 = NULL, *file2 = NULL, *file3 = NULL;
+    char *root, *loading, *data;
     int l, loading_fd, data_fd, fw_fd;
+    size_t i;
     int booting = is_booting();
 
     INFO("firmware: loading '%s' for '%s'\n",
@@ -859,62 +821,49 @@
     if (l == -1)
         goto loading_free_out;
 
-    l = asprintf(&file1, FIRMWARE_DIR1"/%s", uevent->firmware);
-    if (l == -1)
-        goto data_free_out;
-
-    l = asprintf(&file2, FIRMWARE_DIR2"/%s", uevent->firmware);
-    if (l == -1)
-        goto data_free_out;
-
-    l = asprintf(&file3, FIRMWARE_DIR3"/%s", uevent->firmware);
-    if (l == -1)
-        goto data_free_out;
-
-    loading_fd = open(loading, O_WRONLY);
+    loading_fd = open(loading, O_WRONLY|O_CLOEXEC);
     if(loading_fd < 0)
-        goto file_free_out;
+        goto data_free_out;
 
-    data_fd = open(data, O_WRONLY);
+    data_fd = open(data, O_WRONLY|O_CLOEXEC);
     if(data_fd < 0)
         goto loading_close_out;
 
 try_loading_again:
-    fw_fd = open(file1, O_RDONLY);
-    if(fw_fd < 0) {
-        fw_fd = open(file2, O_RDONLY);
-        if (fw_fd < 0) {
-            fw_fd = open(file3, O_RDONLY);
-            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' %d\n", uevent->firmware, errno);
-                write(loading_fd, "-1", 2);
-                goto data_close_out;
-            }
+    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;
         }
     }
-
-    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);
+    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);
-file_free_out:
-    free(file1);
-    free(file2);
-    free(file3);
 data_free_out:
     free(data);
 loading_free_out:
@@ -926,7 +875,6 @@
 static void handle_firmware_event(struct uevent *uevent)
 {
     pid_t pid;
-    int ret;
 
     if(strcmp(uevent->subsystem, "firmware"))
         return;
@@ -938,7 +886,9 @@
     pid = fork();
     if (!pid) {
         process_firmware_event(uevent);
-        exit(EXIT_SUCCESS);
+        _exit(EXIT_SUCCESS);
+    } else if (pid < 0) {
+        ERROR("could not fork to process firmware event: %s\n", strerror(errno));
     }
 }
 
@@ -977,7 +927,7 @@
 **
 ** We drain any pending events from the netlink socket every time
 ** we poke another uevent file to make sure we don't overrun the
-** socket's buffer.  
+** socket's buffer.
 */
 
 static void do_coldboot(DIR *d)
@@ -1023,12 +973,7 @@
     }
 }
 
-void device_init(void)
-{
-    suseconds_t t0, t1;
-    struct stat info;
-    int fd;
-
+void device_init() {
     sehandle = NULL;
     if (is_selinux_enabled() > 0) {
         sehandle = selinux_android_file_context_handle();
@@ -1037,24 +982,22 @@
 
     /* is 256K enough? udev uses 16MB! */
     device_fd = uevent_open_socket(256*1024, true);
-    if(device_fd < 0)
+    if (device_fd == -1) {
         return;
-
-    fcntl(device_fd, F_SETFD, FD_CLOEXEC);
+    }
     fcntl(device_fd, F_SETFL, O_NONBLOCK);
 
-    if (stat(coldboot_done, &info) < 0) {
-        t0 = get_usecs();
-        coldboot("/sys/class");
-        coldboot("/sys/block");
-        coldboot("/sys/devices");
-        t1 = get_usecs();
-        fd = open(coldboot_done, O_WRONLY|O_CREAT, 0000);
-        close(fd);
-        log_event_print("coldboot %ld uS\n", ((long) (t1 - t0)));
-    } else {
-        log_event_print("skipping coldboot, already done\n");
+    if (access(COLDBOOT_DONE, F_OK) == 0) {
+        NOTICE("Skipping coldboot, already done!\n");
+        return;
     }
+
+    Timer t;
+    coldboot("/sys/class");
+    coldboot("/sys/block");
+    coldboot("/sys/devices");
+    close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
+    NOTICE("Coldboot took %.2fs.\n", t.duration());
 }
 
 int get_device_fd()
diff --git a/init/devices.h b/init/devices.h
index 5d0fe88..6cb0a77 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -26,4 +26,5 @@
                          unsigned int gid, unsigned short prefix,
                          unsigned short wildcard);
 int get_device_fd();
+
 #endif	/* _INIT_DEVICES_H */
diff --git a/init/grab-bootchart.sh b/init/grab-bootchart.sh
index 7fe8904..d6082aa 100755
--- a/init/grab-bootchart.sh
+++ b/init/grab-bootchart.sh
@@ -1,10 +1,9 @@
 #!/bin/sh
 #
-# this script is used to retrieve the bootchart log generated
-# by init when compiled with INIT_BOOTCHART=true.
-#
-# for all details, see //device/system/init/README.BOOTCHART
-#
+# This script is used to retrieve a bootchart log generated by init.
+# All options are passed to adb, for better or for worse.
+# See the readme in this directory for more on bootcharting.
+
 TMPDIR=/tmp/android-bootchart
 rm -rf $TMPDIR
 mkdir -p $TMPDIR
@@ -15,8 +14,9 @@
 FILES="header proc_stat.log proc_ps.log proc_diskstats.log kernel_pacct"
 
 for f in $FILES; do
-    adb pull $LOGROOT/$f $TMPDIR/$f 2>&1 > /dev/null
+    adb "${@}" pull $LOGROOT/$f $TMPDIR/$f 2>&1 > /dev/null
 done
 (cd $TMPDIR && tar -czf $TARBALL $FILES)
-cp -f $TMPDIR/$TARBALL ./$TARBALL
-echo "look at $TARBALL"
+bootchart ${TMPDIR}/${TARBALL}
+gnome-open ${TARBALL%.tgz}.png
+echo "Clean up ${TMPDIR}/ and ./${TARBALL%.tgz}.png when done"
diff --git a/init/init.c b/init/init.cpp
similarity index 61%
rename from init/init.c
rename to init/init.cpp
index bd1db7a..93fe944 100644
--- a/init/init.c
+++ b/init/init.cpp
@@ -14,37 +14,43 @@
  * limitations under the License.
  */
 
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <signal.h>
-#include <sys/wait.h>
+#include <sys/epoll.h>
 #include <sys/mount.h>
-#include <sys/stat.h>
-#include <sys/poll.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <mtd/mtd-user.h>
-#include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <sys/un.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <mtd/mtd-user.h>
 
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 #include <selinux/android.h>
 
-#include <libgen.h>
-
-#include <cutils/list.h>
+#include <base/file.h>
+#include <base/stringprintf.h>
 #include <cutils/android_reboot.h>
-#include <cutils/sockets.h>
-#include <cutils/iosched_policy.h>
 #include <cutils/fs.h>
+#include <cutils/iosched_policy.h>
+#include <cutils/list.h>
+#include <cutils/sockets.h>
 #include <private/android_filesystem_config.h>
-#include <termios.h>
+
+#include <memory>
 
 #include "devices.h"
 #include "init.h"
@@ -63,29 +69,10 @@
 
 static int property_triggers_enabled = 0;
 
-#if BOOTCHART
-static int   bootchart_count;
-#endif
-
-static char console[32];
-static char bootmode[32];
-static char hardware[32];
-static unsigned revision = 0;
 static char qemu[32];
 
 static struct action *cur_action = NULL;
 static struct command *cur_command = NULL;
-static struct listnode *command_queue = NULL;
-
-void notify_service_state(const char *name, const char *state)
-{
-    char pname[PROP_NAME_MAX];
-    int len = strlen(name);
-    if ((len + 10) > PROP_NAME_MAX)
-        return;
-    snprintf(pname, sizeof(pname), "init.svc.%s", name);
-    property_set(pname, state);
-}
 
 static int have_console;
 static char console_name[PROP_VALUE_MAX] = "/dev/console";
@@ -93,6 +80,40 @@
 
 static const char *ENV[32];
 
+bool waiting_for_exec = false;
+
+static int epoll_fd = -1;
+
+void register_epoll_handler(int fd, void (*fn)()) {
+    epoll_event ev;
+    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));
+    }
+}
+
+void service::NotifyStateChange(const char* new_state) {
+    if (!properties_initialized()) {
+        // If properties aren't available yet, we can't set them.
+        return;
+    }
+
+    if ((flags & SVC_EXEC) != 0) {
+        // 'exec' commands don't have properties tracking their state.
+        return;
+    }
+
+    char prop_name[PROP_NAME_MAX];
+    if (snprintf(prop_name, sizeof(prop_name), "init.svc.%s", name) >= 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, new_state);
+        return;
+    }
+
+    property_set(prop_name, new_state);
+}
+
 /* add_environment - add "key=value" to the current environment */
 int add_environment(const char *key, const char *val)
 {
@@ -113,9 +134,8 @@
 
         /* Add entry if a free slot is available */
         if (ENV[n] == NULL) {
-            size_t len = key_len + strlen(val) + 2;
-            char *entry = malloc(len);
-            snprintf(entry, len, "%s=%s", key, val);
+            char* entry;
+            asprintf(&entry, "%s=%s", key, val);
             ENV[n] = entry;
             return 0;
         }
@@ -126,7 +146,7 @@
     return -1;
 }
 
-static void zap_stdio(void)
+void zap_stdio(void)
 {
     int fd;
     fd = open("/dev/null", O_RDWR);
@@ -166,36 +186,26 @@
 
 void service_start(struct service *svc, const char *dynamic_args)
 {
-    struct stat s;
-    pid_t pid;
-    int needs_console;
-    int n;
-    char *scon = NULL;
-    int rc;
-
-        /* 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
-         */
+    // 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.
     svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
     svc->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 on exit, unless
-         * they are ONESHOT
-         */
+    // Running processes require no additional work --- if they're in the
+    // process of exiting, we've ensured that they will immediately restart
+    // on exit, unless they are ONESHOT.
     if (svc->flags & SVC_RUNNING) {
         return;
     }
 
-    needs_console = (svc->flags & SVC_CONSOLE) ? 1 : 0;
-    if (needs_console && (!have_console)) {
+    bool needs_console = (svc->flags & SVC_CONSOLE);
+    if (needs_console && !have_console) {
         ERROR("service '%s' requires console\n", svc->name);
         svc->flags |= SVC_DISABLED;
         return;
     }
 
+    struct stat s;
     if (stat(svc->args[0], &s) != 0) {
         ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name);
         svc->flags |= SVC_DISABLED;
@@ -209,6 +219,7 @@
         return;
     }
 
+    char* scon = NULL;
     if (is_selinux_enabled() > 0) {
         if (svc->seclabel) {
             scon = strdup(svc->seclabel);
@@ -220,7 +231,7 @@
             char *mycon = NULL, *fcon = NULL;
 
             INFO("computing context for service '%s'\n", svc->args[0]);
-            rc = getcon(&mycon);
+            int rc = getcon(&mycon);
             if (rc < 0) {
                 ERROR("could not get context while starting '%s'\n", svc->name);
                 return;
@@ -246,10 +257,9 @@
         }
     }
 
-    NOTICE("starting '%s'\n", svc->name);
+    NOTICE("Starting service '%s'...\n", svc->name);
 
-    pid = fork();
-
+    pid_t pid = fork();
     if (pid == 0) {
         struct socketinfo *si;
         struct svcenvinfo *ei;
@@ -257,9 +267,9 @@
         int fd, sz;
 
         umask(077);
-        if (properties_inited()) {
+        if (properties_initialized()) {
             get_property_workspace(&fd, &sz);
-            sprintf(tmp, "%d,%d", dup(fd), sz);
+            snprintf(tmp, sizeof(tmp), "%d,%d", dup(fd), sz);
             add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);
         }
 
@@ -280,6 +290,16 @@
         freecon(scon);
         scon = NULL;
 
+        if (svc->writepid_files_) {
+            std::string pid_str = android::base::StringPrintf("%d", pid);
+            for (auto& file : *svc->writepid_files_) {
+                if (!android::base::WriteStringToFile(pid_str, file)) {
+                    ERROR("couldn't write %s to %s: %s\n",
+                          pid_str.c_str(), file.c_str(), strerror(errno));
+                }
+            }
+        }
+
         if (svc->ioprio_class != IoSchedClass_NONE) {
             if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) {
                 ERROR("Failed to set pid %d ioprio = %d,%d: %s\n",
@@ -294,18 +314,18 @@
             zap_stdio();
         }
 
-#if 0
-        for (n = 0; svc->args[n]; n++) {
-            INFO("args[%d] = '%s'\n", n, svc->args[n]);
+        if (false) {
+            for (size_t n = 0; svc->args[n]; n++) {
+                INFO("args[%zu] = '%s'\n", n, svc->args[n]);
+            }
+            for (size_t n = 0; ENV[n]; n++) {
+                INFO("env[%zu] = '%s'\n", n, ENV[n]);
+            }
         }
-        for (n = 0; ENV[n]; n++) {
-            INFO("env[%d] = '%s'\n", n, ENV[n]);
-        }
-#endif
 
         setpgid(0, getpid());
 
-    /* as requested, set our gid, supplemental gids, and uid */
+        // As requested, set our gid, supplemental gids, and uid.
         if (svc->gid) {
             if (setgid(svc->gid) != 0) {
                 ERROR("setgid failed: %s\n", strerror(errno));
@@ -350,7 +370,7 @@
                 if (arg_idx == INIT_PARSER_MAXARGS)
                     break;
             }
-            arg_ptrs[arg_idx] = '\0';
+            arg_ptrs[arg_idx] = NULL;
             execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
         }
         _exit(127);
@@ -368,8 +388,14 @@
     svc->pid = pid;
     svc->flags |= SVC_RUNNING;
 
-    if (properties_inited())
-        notify_service_state(svc->name, "running");
+    if ((svc->flags & SVC_EXEC) != 0) {
+        INFO("SVC_EXEC pid %d (uid %d gid %d+%zu context %s) started; waiting...\n",
+             svc->pid, svc->uid, svc->gid, svc->nr_supp_gids,
+             svc->seclabel ? : "default");
+        waiting_for_exec = true;
+    }
+
+    svc->NotifyStateChange("running");
 }
 
 /* The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART */
@@ -393,11 +419,11 @@
     }
 
     if (svc->pid) {
-        NOTICE("service '%s' is being killed\n", svc->name);
+        NOTICE("Service '%s' is being killed...\n", svc->name);
         kill(-svc->pid, SIGKILL);
-        notify_service_state(svc->name, "stopping");
+        svc->NotifyStateChange("stopping");
     } else {
-        notify_service_state(svc->name, "stopped");
+        svc->NotifyStateChange("stopped");
     }
 }
 
@@ -541,47 +567,77 @@
     return (list_tail(&act->commands) == &cmd->clist);
 }
 
-void execute_one_command(void)
-{
-    int ret, i;
+
+void build_triggers_string(char *name_str, int length, struct action *cur_action) {
+    struct listnode *node;
+    struct trigger *cur_trigger;
+
+    list_for_each(node, &cur_action->triggers) {
+        cur_trigger = node_to_item(node, struct trigger, nlist);
+        if (node != cur_action->triggers.next) {
+            strlcat(name_str, " " , length);
+        }
+        strlcat(name_str, cur_trigger->name , length);
+    }
+}
+
+void execute_one_command() {
+    Timer t;
+
     char cmd_str[256] = "";
+    char name_str[256] = "";
 
     if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {
         cur_action = action_remove_queue_head();
         cur_command = NULL;
-        if (!cur_action)
+        if (!cur_action) {
             return;
-        INFO("processing action %p (%s)\n", cur_action, cur_action->name);
+        }
+
+        build_triggers_string(name_str, sizeof(name_str), cur_action);
+
+        INFO("processing action %p (%s)\n", cur_action, name_str);
         cur_command = get_first_command(cur_action);
     } else {
         cur_command = get_next_command(cur_action, cur_command);
     }
 
-    if (!cur_command)
+    if (!cur_command) {
         return;
+    }
 
-    ret = cur_command->func(cur_command->nargs, cur_command->args);
+    int result = cur_command->func(cur_command->nargs, cur_command->args);
     if (klog_get_level() >= KLOG_INFO_LEVEL) {
-        for (i = 0; i < cur_command->nargs; i++) {
+        for (int i = 0; i < cur_command->nargs; i++) {
             strlcat(cmd_str, cur_command->args[i], sizeof(cmd_str));
             if (i < cur_command->nargs - 1) {
                 strlcat(cmd_str, " ", sizeof(cmd_str));
             }
         }
-        INFO("command '%s' action=%s status=%d (%s:%d)\n",
-             cmd_str, cur_action ? cur_action->name : "", ret, cur_command->filename,
-             cur_command->line);
+        char source[256];
+        if (cur_command->filename) {
+            snprintf(source, sizeof(source), " (%s:%d)", cur_command->filename, cur_command->line);
+        } else {
+            *source = '\0';
+        }
+        INFO("Command '%s' action=%s%s returned %d took %.2fs\n",
+             cmd_str, cur_action ? name_str : "", source, result, t.duration());
     }
 }
 
-static int wait_for_coldboot_done_action(int nargs, char **args)
-{
-    int ret;
-    INFO("wait for %s\n", coldboot_done);
-    ret = wait_for_file(coldboot_done, COMMAND_RETRY_TIMEOUT);
-    if (ret)
-        ERROR("Timed out waiting for %s\n", coldboot_done);
-    return ret;
+static int wait_for_coldboot_done_action(int nargs, char **args) {
+    Timer t;
+
+    NOTICE("Waiting for %s...\n", 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);
+    }
+
+    NOTICE("Waiting for %s took %.2fs.\n", COLDBOOT_DONE, t.duration());
+    return 0;
 }
 
 /*
@@ -609,7 +665,7 @@
     size_t total_bytes_written = 0;
 
     hwrandom_fd = TEMP_FAILURE_RETRY(
-            open("/dev/hw_random", O_RDONLY | O_NOFOLLOW));
+            open("/dev/hw_random", O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
     if (hwrandom_fd == -1) {
         if (errno == ENOENT) {
           ERROR("/dev/hw_random not found\n");
@@ -622,7 +678,7 @@
     }
 
     urandom_fd = TEMP_FAILURE_RETRY(
-            open("/dev/urandom", O_WRONLY | O_NOFOLLOW));
+            open("/dev/urandom", O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
     if (urandom_fd == -1) {
         ERROR("Failed to open /dev/urandom: %s\n", strerror(errno));
         goto ret;
@@ -658,7 +714,6 @@
     if (urandom_fd != -1) {
         close(urandom_fd);
     }
-    memset(buf, 0, sizeof(buf));
     return result;
 }
 
@@ -670,18 +725,17 @@
 
 static int console_init_action(int nargs, char **args)
 {
-    int fd;
-
-    if (console[0]) {
+    char console[PROP_VALUE_MAX];
+    if (property_get("ro.boot.console", console) > 0) {
         snprintf(console_name, sizeof(console_name), "/dev/%s", console);
     }
 
-    fd = open(console_name, O_RDWR);
+    int fd = open(console_name, O_RDWR | O_CLOEXEC);
     if (fd >= 0)
         have_console = 1;
     close(fd);
 
-    fd = open("/dev/tty0", O_WRONLY);
+    fd = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
     if (fd >= 0) {
         const char *msg;
             msg = "\n"
@@ -706,7 +760,7 @@
     return 0;
 }
 
-static void import_kernel_nv(char *name, int for_emulator)
+static void import_kernel_nv(char *name, bool for_emulator)
 {
     char *value = strchr(name, '=');
     int name_len = strlen(name);
@@ -739,55 +793,56 @@
     }
 }
 
-static void export_kernel_boot_props(void)
-{
-    char tmp[PROP_VALUE_MAX];
-    int ret;
-    unsigned i;
+static void export_kernel_boot_props() {
     struct {
         const char *src_prop;
-        const char *dest_prop;
-        const char *def_val;
+        const char *dst_prop;
+        const char *default_value;
     } prop_map[] = {
-        { "ro.boot.serialno", "ro.serialno", "", },
-        { "ro.boot.mode", "ro.bootmode", "unknown", },
-        { "ro.boot.baseband", "ro.baseband", "unknown", },
+        { "ro.boot.serialno",   "ro.serialno",   "", },
+        { "ro.boot.mode",       "ro.bootmode",   "unknown", },
+        { "ro.boot.baseband",   "ro.baseband",   "unknown", },
         { "ro.boot.bootloader", "ro.bootloader", "unknown", },
+        { "ro.boot.hardware",   "ro.hardware",   "unknown", },
+        { "ro.boot.revision",   "ro.revision",   "0", },
     };
+    for (size_t i = 0; i < ARRAY_SIZE(prop_map); i++) {
+        char value[PROP_VALUE_MAX];
+        int rc = property_get(prop_map[i].src_prop, value);
+        property_set(prop_map[i].dst_prop, (rc > 0) ? value : prop_map[i].default_value);
+    }
+}
 
-    for (i = 0; i < ARRAY_SIZE(prop_map); i++) {
-        ret = property_get(prop_map[i].src_prop, tmp);
-        if (ret > 0)
-            property_set(prop_map[i].dest_prop, tmp);
-        else
-            property_set(prop_map[i].dest_prop, prop_map[i].def_val);
+static void process_kernel_dt(void)
+{
+    static const char android_dir[] = "/proc/device-tree/firmware/android";
+
+    std::string file_name = android::base::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");
+        return;
     }
 
-    ret = property_get("ro.boot.console", tmp);
-    if (ret)
-        strlcpy(console, tmp, sizeof(console));
+    std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dir), closedir);
+    if (!dir)
+        return;
 
-    /* save a copy for init's usage during boot */
-    property_get("ro.bootmode", tmp);
-    strlcpy(bootmode, tmp, sizeof(bootmode));
+    struct dirent *dp;
+    while ((dp = readdir(dir.get())) != NULL) {
+        if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible"))
+            continue;
 
-    /* if this was given on kernel command line, override what we read
-     * before (e.g. from /proc/cpuinfo), if anything */
-    ret = property_get("ro.boot.hardware", tmp);
-    if (ret)
-        strlcpy(hardware, tmp, sizeof(hardware));
-    property_set("ro.hardware", hardware);
+        file_name = android::base::StringPrintf("%s/%s", android_dir, dp->d_name);
 
-    snprintf(tmp, PROP_VALUE_MAX, "%d", revision);
-    property_set("ro.revision", tmp);
+        android::base::ReadFileToString(file_name, &dt_file);
+        std::replace(dt_file.begin(), dt_file.end(), ',', '.');
 
-    /* TODO: these are obsolete. We should delete them */
-    if (!strcmp(bootmode,"factory"))
-        property_set("ro.factorytest", "1");
-    else if (!strcmp(bootmode,"factory2"))
-        property_set("ro.factorytest", "2");
-    else
-        property_set("ro.factorytest", "0");
+        std::string property_name = android::base::StringPrintf("ro.boot.%s", dp->d_name);
+        property_set(property_name.c_str(), dt_file.c_str());
+    }
 }
 
 static void process_kernel_cmdline(void)
@@ -799,40 +854,9 @@
      * second pass is only necessary for qemu to export all kernel params
      * as props.
      */
-    import_kernel_cmdline(0, import_kernel_nv);
+    import_kernel_cmdline(false, import_kernel_nv);
     if (qemu[0])
-        import_kernel_cmdline(1, import_kernel_nv);
-
-    /* now propogate the info given on command line to internal variables
-     * used by init as well as the current required properties
-     */
-    export_kernel_boot_props();
-}
-
-static int property_service_init_action(int nargs, char **args)
-{
-    /* read any property files on system or data and
-     * fire up the property service.  This must happen
-     * after the ro.foo properties are set above so
-     * that /data/local.prop cannot interfere with them.
-     */
-    start_property_service();
-    if (get_property_set_fd() < 0) {
-        ERROR("start_property_service() failed\n");
-        exit(1);
-    }
-
-    return 0;
-}
-
-static int signal_init_action(int nargs, char **args)
-{
-    signal_init();
-    if (get_signal_fd() < 0) {
-        ERROR("signal_init() failed\n");
-        exit(1);
-    }
-    return 0;
+        import_kernel_cmdline(true, import_kernel_nv);
 }
 
 static int queue_property_triggers_action(int nargs, char **args)
@@ -843,90 +867,55 @@
     return 0;
 }
 
-#if BOOTCHART
-static int bootchart_init_action(int nargs, char **args)
-{
-    bootchart_count = bootchart_init();
-    if (bootchart_count < 0) {
-        ERROR("bootcharting init failure\n");
-    } else if (bootchart_count > 0) {
-        NOTICE("bootcharting started (period=%d ms)\n", bootchart_count*BOOTCHART_POLLING_MS);
-    } else {
-        NOTICE("bootcharting ignored\n");
-    }
-
-    return 0;
-}
-#endif
-
-static const struct selinux_opt seopts_prop[] = {
-        { SELABEL_OPT_PATH, "/property_contexts" },
-        { SELABEL_OPT_PATH, "/data/security/current/property_contexts" },
-        { 0, NULL }
-};
-
-struct selabel_handle* selinux_android_prop_context_handle(void)
-{
-    int policy_index = selinux_android_use_data_policy() ? 1 : 0;
-    struct selabel_handle* sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP,
-                                                   &seopts_prop[policy_index], 1);
-    if (!sehandle) {
-        ERROR("SELinux:  Could not load property_contexts:  %s\n",
-              strerror(errno));
-        return NULL;
-    }
-    INFO("SELinux: Loaded property contexts from %s\n", seopts_prop[policy_index].value);
-    return sehandle;
-}
-
-void selinux_init_all_handles(void)
+static void selinux_init_all_handles(void)
 {
     sehandle = selinux_android_file_context_handle();
     selinux_android_set_sehandle(sehandle);
     sehandle_prop = selinux_android_prop_context_handle();
 }
 
+enum selinux_enforcing_status { SELINUX_DISABLED, SELINUX_PERMISSIVE, SELINUX_ENFORCING };
+
+static selinux_enforcing_status selinux_status_from_cmdline() {
+    selinux_enforcing_status status = SELINUX_ENFORCING;
+
+    std::function<void(char*,bool)> fn = [&](char* name, bool in_qemu) {
+        char *value = strchr(name, '=');
+        if (value == nullptr) { return; }
+        *value++ = '\0';
+        if (strcmp(name, "androidboot.selinux") == 0) {
+            if (strcmp(value, "disabled") == 0) {
+                status = SELINUX_DISABLED;
+            } else if (strcmp(value, "permissive") == 0) {
+                status = SELINUX_PERMISSIVE;
+            }
+        }
+    };
+    import_kernel_cmdline(false, fn);
+
+    return status;
+}
+
+
 static bool selinux_is_disabled(void)
 {
-#ifdef ALLOW_DISABLE_SELINUX
-    char tmp[PROP_VALUE_MAX];
-
-    if (access("/sys/fs/selinux", F_OK) != 0) {
-        /* SELinux is not compiled into the kernel, or has been disabled
-         * via the kernel command line "selinux=0".
-         */
-        return true;
+    if (ALLOW_DISABLE_SELINUX) {
+        if (access("/sys/fs/selinux", F_OK) != 0) {
+            // SELinux is not compiled into the kernel, or has been disabled
+            // via the kernel command line "selinux=0".
+            return true;
+        }
+        return selinux_status_from_cmdline() == SELINUX_DISABLED;
     }
 
-    if ((property_get("ro.boot.selinux", tmp) != 0) && (strcmp(tmp, "disabled") == 0)) {
-        /* SELinux is compiled into the kernel, but we've been told to disable it. */
-        return true;
-    }
-#endif
-
     return false;
 }
 
 static bool selinux_is_enforcing(void)
 {
-#ifdef ALLOW_DISABLE_SELINUX
-    char tmp[PROP_VALUE_MAX];
-
-    if (property_get("ro.boot.selinux", tmp) == 0) {
-        /* Property is not set.  Assume enforcing */
-        return true;
+    if (ALLOW_DISABLE_SELINUX) {
+        return selinux_status_from_cmdline() == SELINUX_ENFORCING;
     }
-
-    if (strcmp(tmp, "permissive") == 0) {
-        /* SELinux is in the kernel, but we've been told to go into permissive mode */
-        return false;
-    }
-
-    if (strcmp(tmp, "enforcing") != 0) {
-        ERROR("SELinux: Unknown value of ro.boot.selinux. Got: \"%s\". Assuming enforcing.\n", tmp);
-    }
-
-#endif
     return true;
 }
 
@@ -952,223 +941,196 @@
     return 0;
 }
 
-static int audit_callback(void *data, security_class_t cls __attribute__((unused)), char *buf, size_t len)
-{
+static int audit_callback(void *data, security_class_t /*cls*/, char *buf, size_t len) {
     snprintf(buf, len, "property=%s", !data ? "NULL" : (char *)data);
     return 0;
 }
 
-int log_callback(int type, const char *fmt, ...)
-{
-    int level;
-    va_list ap;
-    switch (type) {
-    case SELINUX_WARNING:
-        level = KLOG_WARNING_LEVEL;
-        break;
-    case SELINUX_INFO:
-        level = KLOG_INFO_LEVEL;
-        break;
-    default:
-        level = KLOG_ERROR_LEVEL;
-        break;
-    }
-    va_start(ap, fmt);
-    klog_vwrite(level, fmt, ap);
-    va_end(ap);
-    return 0;
+static void security_failure() {
+    ERROR("Security failure; rebooting into recovery mode...\n");
+    android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
+    while (true) { pause(); }  // never reached
 }
 
-static void selinux_initialize(void)
-{
+static void selinux_initialize(bool in_kernel_domain) {
+    Timer t;
+
+    selinux_callback cb;
+    cb.func_log = selinux_klog_callback;
+    selinux_set_callback(SELINUX_CB_LOG, cb);
+    cb.func_audit = audit_callback;
+    selinux_set_callback(SELINUX_CB_AUDIT, cb);
+
     if (selinux_is_disabled()) {
         return;
     }
 
-    INFO("loading selinux policy\n");
-    if (selinux_android_load_policy() < 0) {
-        ERROR("SELinux: Failed to load policy; rebooting into recovery mode\n");
-        android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
-        while (1) { pause(); }  // never reached
-    }
+    if (in_kernel_domain) {
+        INFO("Loading SELinux policy...\n");
+        if (selinux_android_load_policy() < 0) {
+            ERROR("failed to load policy: %s\n", strerror(errno));
+            security_failure();
+        }
 
-    selinux_init_all_handles();
-    bool is_enforcing = selinux_is_enforcing();
-    INFO("SELinux: security_setenforce(%d)\n", is_enforcing);
-    security_setenforce(is_enforcing);
+        bool is_enforcing = selinux_is_enforcing();
+        security_setenforce(is_enforcing);
+
+        if (write_file("/sys/fs/selinux/checkreqprot", "0") == -1) {
+            security_failure();
+        }
+
+        NOTICE("(Initializing SELinux %s took %.2fs.)\n",
+               is_enforcing ? "enforcing" : "non-enforcing", t.duration());
+    } else {
+        selinux_init_all_handles();
+    }
 }
 
-int main(int argc, char **argv)
-{
-    int fd_count = 0;
-    struct pollfd ufds[4];
-    char *tmpdev;
-    char* debuggable;
-    char tmp[32];
-    int property_set_fd_init = 0;
-    int signal_fd_init = 0;
-    int keychord_fd_init = 0;
-    bool is_charger = false;
-
-    if (!strcmp(basename(argv[0]), "ueventd"))
+int main(int argc, char** argv) {
+    if (!strcmp(basename(argv[0]), "ueventd")) {
         return ueventd_main(argc, argv);
+    }
 
-    if (!strcmp(basename(argv[0]), "watchdogd"))
+    if (!strcmp(basename(argv[0]), "watchdogd")) {
         return watchdogd_main(argc, argv);
+    }
 
-    /* clear the umask */
+    // Clear the umask.
     umask(0);
 
-        /* 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.
-         */
-    mkdir("/dev", 0755);
-    mkdir("/proc", 0755);
-    mkdir("/sys", 0755);
+    add_environment("PATH", _PATH_DEFPATH);
 
-    mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
-    mkdir("/dev/pts", 0755);
-    mkdir("/dev/socket", 0755);
-    mount("devpts", "/dev/pts", "devpts", 0, NULL);
-    mount("proc", "/proc", "proc", 0, NULL);
-    mount("sysfs", "/sys", "sysfs", 0, NULL);
+    bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);
 
-        /* indicate that booting is in progress to background fw loaders, etc */
-    close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000));
+    // 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.
+    if (is_first_stage) {
+        mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
+        mkdir("/dev/pts", 0755);
+        mkdir("/dev/socket", 0755);
+        mount("devpts", "/dev/pts", "devpts", 0, NULL);
+        mount("proc", "/proc", "proc", 0, NULL);
+        mount("sysfs", "/sys", "sysfs", 0, NULL);
+    }
 
-        /* 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.
-         */
+    // 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();
-    property_init();
+    klog_set_level(KLOG_NOTICE_LEVEL);
 
-    get_hardware_name(hardware, &revision);
+    NOTICE("init%s started!\n", is_first_stage ? "" : " second stage");
 
-    process_kernel_cmdline();
+    if (!is_first_stage) {
+        // Indicate that booting is in progress to background fw loaders, etc.
+        close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
 
-    union selinux_callback cb;
-    cb.func_log = log_callback;
-    selinux_set_callback(SELINUX_CB_LOG, cb);
+        property_init();
 
-    cb.func_audit = audit_callback;
-    selinux_set_callback(SELINUX_CB_AUDIT, cb);
+        // If arguments are passed both on the command line and in DT,
+        // properties set in DT always have priority over the command-line ones.
+        process_kernel_dt();
+        process_kernel_cmdline();
 
-    selinux_initialize();
-    /* 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.
-     */
+        // Propogate 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);
+
+    // 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();
+        }
+    }
+
+    // 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.
+    INFO("Running restorecon...\n");
     restorecon("/dev");
     restorecon("/dev/socket");
     restorecon("/dev/__properties__");
     restorecon_recursive("/sys");
 
-    is_charger = !strcmp(bootmode, "charger");
+    epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+    if (epoll_fd == -1) {
+        ERROR("epoll_create1 failed: %s\n", strerror(errno));
+        exit(1);
+    }
 
-    INFO("property init\n");
+    signal_handler_init();
+
     property_load_boot_defaults();
+    start_property_service();
 
-    INFO("reading config file\n");
     init_parse_config_file("/init.rc");
 
     action_for_each_trigger("early-init", action_add_queue_tail);
 
+    // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
     queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
+    // ... so that we can start queuing up actions that require stuff from /dev.
     queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
     queue_builtin_action(keychord_init_action, "keychord_init");
     queue_builtin_action(console_init_action, "console_init");
 
-    /* execute all the boot actions to get us started */
+    // Trigger all the boot actions to get us started.
     action_for_each_trigger("init", action_add_queue_tail);
 
-    /* Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
-     * wasn't ready immediately after wait_for_coldboot_done
-     */
+    // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
+    // wasn't ready immediately after wait_for_coldboot_done
     queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
-    queue_builtin_action(property_service_init_action, "property_service_init");
-    queue_builtin_action(signal_init_action, "signal_init");
 
-    /* Don't mount filesystems or start core system services if in charger mode. */
-    if (is_charger) {
+    // Don't mount filesystems or start core system services in charger mode.
+    char bootmode[PROP_VALUE_MAX];
+    if (property_get("ro.bootmode", bootmode) > 0 && strcmp(bootmode, "charger") == 0) {
         action_for_each_trigger("charger", action_add_queue_tail);
     } else {
         action_for_each_trigger("late-init", action_add_queue_tail);
     }
 
-    /* run all property triggers based on current state of the properties */
+    // Run all property triggers based on current state of the properties.
     queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
 
-
-#if BOOTCHART
-    queue_builtin_action(bootchart_init_action, "bootchart_init");
-#endif
-
-    for(;;) {
-        int nr, i, timeout = -1;
-
-        execute_one_command();
-        restart_processes();
-
-        if (!property_set_fd_init && get_property_set_fd() > 0) {
-            ufds[fd_count].fd = get_property_set_fd();
-            ufds[fd_count].events = POLLIN;
-            ufds[fd_count].revents = 0;
-            fd_count++;
-            property_set_fd_init = 1;
-        }
-        if (!signal_fd_init && get_signal_fd() > 0) {
-            ufds[fd_count].fd = get_signal_fd();
-            ufds[fd_count].events = POLLIN;
-            ufds[fd_count].revents = 0;
-            fd_count++;
-            signal_fd_init = 1;
-        }
-        if (!keychord_fd_init && get_keychord_fd() > 0) {
-            ufds[fd_count].fd = get_keychord_fd();
-            ufds[fd_count].events = POLLIN;
-            ufds[fd_count].revents = 0;
-            fd_count++;
-            keychord_fd_init = 1;
+    while (true) {
+        if (!waiting_for_exec) {
+            execute_one_command();
+            restart_processes();
         }
 
+        int timeout = -1;
         if (process_needs_restart) {
             timeout = (process_needs_restart - gettime()) * 1000;
             if (timeout < 0)
                 timeout = 0;
         }
 
-        if (!action_queue_empty() || cur_action)
+        if (!action_queue_empty() || cur_action) {
             timeout = 0;
-
-#if BOOTCHART
-        if (bootchart_count > 0) {
-            if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)
-                timeout = BOOTCHART_POLLING_MS;
-            if (bootchart_step() < 0 || --bootchart_count == 0) {
-                bootchart_finish();
-                bootchart_count = 0;
-            }
         }
-#endif
 
-        nr = poll(ufds, fd_count, timeout);
-        if (nr <= 0)
-            continue;
+        bootchart_sample(&timeout);
 
-        for (i = 0; i < fd_count; i++) {
-            if (ufds[i].revents & POLLIN) {
-                if (ufds[i].fd == get_property_set_fd())
-                    handle_property_set_fd();
-                else if (ufds[i].fd == get_keychord_fd())
-                    handle_keychord();
-                else if (ufds[i].fd == get_signal_fd())
-                    handle_signal();
-            }
+        epoll_event ev;
+        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
+        if (nr == -1) {
+            ERROR("epoll_wait failed: %s\n", strerror(errno));
+        } else if (nr == 1) {
+            ((void (*)()) ev.data.ptr)();
         }
     }
 
diff --git a/init/init.h b/init/init.h
index a7615a3..c166969 100644
--- a/init/init.h
+++ b/init/init.h
@@ -17,11 +17,13 @@
 #ifndef _INIT_INIT_H
 #define _INIT_INIT_H
 
+#include <sys/types.h>
+
+#include <string>
+#include <vector>
+
 #include <cutils/list.h>
-
-#include <sys/stat.h>
-
-void handle_control_message(const char *msg, const char *arg);
+#include <cutils/iosched_policy.h>
 
 struct command
 {
@@ -37,6 +39,11 @@
     char *args[1];
 };
 
+struct trigger {
+    struct listnode nlist;
+    const char *name;
+};
+
 struct action {
         /* node in list of all actions */
     struct listnode alist;
@@ -46,8 +53,9 @@
     struct listnode tlist;
 
     unsigned hash;
-    const char *name;
 
+        /* list of actions which triggers the commands*/
+    struct listnode triggers;
     struct listnode commands;
     struct command *current;
 };
@@ -68,27 +76,29 @@
     const char *value;
 };
 
-#define SVC_DISABLED    0x01  /* do not autostart with class */
-#define SVC_ONESHOT     0x02  /* do not restart on exit */
-#define SVC_RUNNING     0x04  /* currently active */
-#define SVC_RESTARTING  0x08  /* waiting to restart */
-#define SVC_CONSOLE     0x10  /* requires console */
-#define SVC_CRITICAL    0x20  /* will reboot into recovery if keeps crashing */
-#define SVC_RESET       0x40  /* Use when stopping a process, but not disabling
-                                 so it can be restarted with its class */
-#define SVC_RC_DISABLED 0x80  /* Remember if the disabled flag was set in the rc script */
-#define SVC_RESTART     0x100 /* Use to safely restart (stop, wait, start) a service */
-#define SVC_DISABLED_START 0x200 /* a start was requested but it was disabled at the time */
+#define SVC_DISABLED       0x001  // do not autostart with class
+#define SVC_ONESHOT        0x002  // do not restart on exit
+#define SVC_RUNNING        0x004  // currently active
+#define SVC_RESTARTING     0x008  // waiting to restart
+#define SVC_CONSOLE        0x010  // requires console
+#define SVC_CRITICAL       0x020  // will reboot into recovery if keeps crashing
+#define SVC_RESET          0x040  // Use when stopping a process, but not disabling so it can be restarted with its class.
+#define SVC_RC_DISABLED    0x080  // Remember if the disabled flag was set in the rc script.
+#define SVC_RESTART        0x100  // Use to safely restart (stop, wait, start) a service.
+#define SVC_DISABLED_START 0x200  // A start was requested but it was disabled at the time.
+#define SVC_EXEC           0x400  // This synthetic service corresponds to an 'exec'.
 
 #define NR_SVC_SUPP_GIDS 12    /* twelve supplementary groups */
 
 #define COMMAND_RETRY_TIMEOUT 5
 
 struct service {
+    void NotifyStateChange(const char* new_state);
+
         /* list of all services */
     struct listnode slist;
 
-    const char *name;
+    char *name;
     const char *classname;
 
     unsigned flags;
@@ -96,25 +106,27 @@
     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 */
-    
+
     uid_t uid;
     gid_t gid;
     gid_t supp_gids[NR_SVC_SUPP_GIDS];
     size_t nr_supp_gids;
 
-    char *seclabel;
+    const char* seclabel;
 
     struct socketinfo *sockets;
     struct svcenvinfo *envvars;
 
     struct action onrestart;  /* Actions to execute on restart. */
-    
+
+    std::vector<std::string>* writepid_files_;
+
     /* keycodes for triggering this service via /dev/keychord */
     int *keycodes;
     int nkeycodes;
     int keychord_id;
 
-    int ioprio_class;
+    IoSchedClass ioprio_class;
     int ioprio_pri;
 
     int nargs;
@@ -122,7 +134,13 @@
     char *args[1];
 }; /*     ^-------'args' MUST be at the end of this struct! */
 
-void notify_service_state(const char *name, const char *state);
+extern bool waiting_for_exec;
+extern struct selabel_handle *sehandle;
+extern struct selabel_handle *sehandle_prop;
+
+void build_triggers_string(char *name_str, int length, struct action *cur_action);
+
+void handle_control_message(const char *msg, const char *arg);
 
 struct service *service_find_by_name(const char *name);
 struct service *service_find_by_pid(pid_t pid);
@@ -138,8 +156,10 @@
 void service_start(struct service *svc, const char *dynamic_args);
 void property_changed(const char *name, const char *value);
 
-extern struct selabel_handle *sehandle;
-extern struct selabel_handle *sehandle_prop;
-extern int selinux_reload_policy(void);
+int selinux_reload_policy(void);
+
+void zap_stdio(void);
+
+void register_epoll_handler(int fd, void (*fn)());
 
 #endif	/* _INIT_INIT_H */
diff --git a/init/init_parser.c b/init/init_parser.cpp
similarity index 70%
rename from init/init_parser.c
rename to init/init_parser.cpp
index 6466db2..666a86e 100644
--- a/init/init_parser.c
+++ b/init/init_parser.cpp
@@ -14,14 +14,16 @@
  * limitations under the License.
  */
 
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdarg.h>
 #include <string.h>
-#include <stddef.h>
-#include <ctype.h>
+#include <unistd.h>
 
 #include "init.h"
 #include "parser.h"
@@ -73,14 +75,53 @@
 #define kw_func(kw) (keyword_info[kw].func)
 #define kw_nargs(kw) (keyword_info[kw].nargs)
 
+void dump_parser_state() {
+    if (false) {
+        struct listnode* node;
+        list_for_each(node, &service_list) {
+            service* svc = node_to_item(node, struct service, slist);
+            INFO("service %s\n", svc->name);
+            INFO("  class '%s'\n", svc->classname);
+            INFO("  exec");
+            for (int n = 0; n < svc->nargs; n++) {
+                INFO(" '%s'", svc->args[n]);
+            }
+            INFO("\n");
+            for (socketinfo* si = svc->sockets; si; si = si->next) {
+                INFO("  socket %s %s 0%o\n", si->name, si->type, si->perm);
+            }
+        }
+
+        list_for_each(node, &action_list) {
+            action* act = node_to_item(node, struct action, alist);
+            INFO("on ");
+            char name_str[256] = "";
+            build_triggers_string(name_str, sizeof(name_str), act);
+            INFO("%s", name_str);
+            INFO("\n");
+
+            struct listnode* node2;
+            list_for_each(node2, &act->commands) {
+                command* cmd = node_to_item(node2, struct command, clist);
+                INFO("  %p", cmd->func);
+                for (int n = 0; n < cmd->nargs; n++) {
+                    INFO(" %s", cmd->args[n]);
+                }
+                INFO("\n");
+            }
+            INFO("\n");
+        }
+    }
+}
+
 static int lookup_keyword(const char *s)
 {
     switch (*s++) {
+    case 'b':
+        if (!strcmp(s, "ootchart_init")) return K_bootchart_init;
+        break;
     case 'c':
-    if (!strcmp(s, "opy")) return K_copy;
-        if (!strcmp(s, "apability")) return K_capability;
-        if (!strcmp(s, "hdir")) return K_chdir;
-        if (!strcmp(s, "hroot")) return K_chroot;
+        if (!strcmp(s, "opy")) return K_copy;
         if (!strcmp(s, "lass")) return K_class;
         if (!strcmp(s, "lass_start")) return K_class_start;
         if (!strcmp(s, "lass_stop")) return K_class_stop;
@@ -110,6 +151,7 @@
         if (!strcmp(s, "fup")) return K_ifup;
         if (!strcmp(s, "nsmod")) return K_insmod;
         if (!strcmp(s, "mport")) return K_import;
+        if (!strcmp(s, "nstallkey")) return K_installkey;
         break;
     case 'k':
         if (!strcmp(s, "eycodes")) return K_keycodes;
@@ -131,6 +173,7 @@
         break;
     case 'p':
         if (!strcmp(s, "owerctl")) return K_powerctl;
+        break;
     case 'r':
         if (!strcmp(s, "estart")) return K_restart;
         if (!strcmp(s, "estorecon")) return K_restorecon;
@@ -141,13 +184,9 @@
     case 's':
         if (!strcmp(s, "eclabel")) return K_seclabel;
         if (!strcmp(s, "ervice")) return K_service;
-        if (!strcmp(s, "etcon")) return K_setcon;
-        if (!strcmp(s, "etenforce")) return K_setenforce;
         if (!strcmp(s, "etenv")) return K_setenv;
-        if (!strcmp(s, "etkey")) return K_setkey;
         if (!strcmp(s, "etprop")) return K_setprop;
         if (!strcmp(s, "etrlimit")) return K_setrlimit;
-        if (!strcmp(s, "etsebool")) return K_setsebool;
         if (!strcmp(s, "ocket")) return K_socket;
         if (!strcmp(s, "tart")) return K_start;
         if (!strcmp(s, "top")) return K_stop;
@@ -161,16 +200,20 @@
     case 'u':
         if (!strcmp(s, "ser")) return K_user;
         break;
+    case 'v':
+        if (!strcmp(s, "erity_load_state")) return K_verity_load_state;
+        if (!strcmp(s, "erity_update_state")) return K_verity_update_state;
+        break;
     case 'w':
         if (!strcmp(s, "rite")) return K_write;
+        if (!strcmp(s, "ritepid")) return K_writepid;
         if (!strcmp(s, "ait")) return K_wait;
         break;
     }
     return K_UNKNOWN;
 }
 
-static void parse_line_no_op(struct parse_state *state, int nargs, char **args)
-{
+static void parse_line_no_op(struct parse_state*, int, char**) {
 }
 
 static int push_chars(char **dst, int *len, const char *chars, int cnt)
@@ -187,19 +230,14 @@
 
 int expand_props(char *dst, const char *src, int dst_size)
 {
-    int cnt = 0;
     char *dst_ptr = dst;
     const char *src_ptr = src;
-    int src_len;
-    int idx = 0;
     int ret = 0;
     int left = dst_size - 1;
 
     if (!src || !dst || dst_size == 0)
         return -1;
 
-    src_len = strlen(src);
-
     /* - variables can either be $x.y or ${x.y}, in case they are only part
      *   of the string.
      * - will accept $$ as a literal $.
@@ -294,8 +332,7 @@
 
 static void parse_import(struct parse_state *state, int nargs, char **args)
 {
-    struct listnode *import_list = state->priv;
-    struct import *import;
+    struct listnode *import_list = (listnode*) state->priv;
     char conf_file[PATH_MAX];
     int ret;
 
@@ -311,10 +348,10 @@
         return;
     }
 
-    import = calloc(1, sizeof(struct import));
+    struct import* import = (struct import*) calloc(1, sizeof(struct import));
     import->filename = strdup(conf_file);
     list_add_tail(import_list, &import->list);
-    INFO("found import '%s', adding to import list", import->filename);
+    INFO("Added '%s' to import list\n", import->filename);
 }
 
 static void parse_new_section(struct parse_state *state, int kw,
@@ -344,18 +381,18 @@
     state->parse_line = parse_line_no_op;
 }
 
-static void parse_config(const char *fn, char *s)
+static void parse_config(const char *fn, const std::string& data)
 {
-    struct parse_state state;
     struct listnode import_list;
     struct listnode *node;
     char *args[INIT_PARSER_MAXARGS];
-    int nargs;
 
-    nargs = 0;
+    int nargs = 0;
+
+    parse_state state;
     state.filename = fn;
     state.line = 0;
-    state.ptr = s;
+    state.ptr = strdup(data.c_str());  // TODO: fix this code!
     state.nexttoken = 0;
     state.parse_line = parse_line_no_op;
 
@@ -393,7 +430,6 @@
          struct import *import = node_to_item(node, struct import, list);
          int ret;
 
-         INFO("importing '%s'", import->filename);
          ret = init_parse_config_file(import->filename);
          if (ret)
              ERROR("could not import file '%s' from '%s'\n",
@@ -401,14 +437,19 @@
     }
 }
 
-int init_parse_config_file(const char *fn)
-{
-    char *data;
-    data = read_file(fn, 0);
-    if (!data) return -1;
+int init_parse_config_file(const char* path) {
+    INFO("Parsing %s...\n", path);
+    Timer t;
+    std::string data;
+    if (!read_file(path, &data)) {
+        return -1;
+    }
 
-    parse_config(fn, data);
-    DUMP();
+    data.push_back('\n'); // TODO: fix parse_config.
+    parse_config(path, data);
+    dump_parser_state();
+
+    NOTICE("(Parsing %s took %.2fs.)\n", path, t.duration());
     return 0;
 }
 
@@ -504,83 +545,94 @@
 void action_for_each_trigger(const char *trigger,
                              void (*func)(struct action *act))
 {
-    struct listnode *node;
+    struct listnode *node, *node2;
     struct action *act;
+    struct trigger *cur_trigger;
+
     list_for_each(node, &action_list) {
         act = node_to_item(node, struct action, alist);
-        if (!strcmp(act->name, trigger)) {
-            func(act);
+        list_for_each(node2, &act->triggers) {
+            cur_trigger = node_to_item(node2, struct trigger, nlist);
+            if (!strcmp(cur_trigger->name, trigger)) {
+                func(act);
+            }
         }
     }
 }
 
+
 void queue_property_triggers(const char *name, const char *value)
 {
-    struct listnode *node;
+    struct listnode *node, *node2;
     struct action *act;
+    struct trigger *cur_trigger;
+    bool match;
+    int name_length;
+
     list_for_each(node, &action_list) {
         act = node_to_item(node, struct action, alist);
-        if (!strncmp(act->name, "property:", strlen("property:"))) {
-            const char *test = act->name + strlen("property:");
-            int name_length = strlen(name);
+            match = !name;
+        list_for_each(node2, &act->triggers) {
+            cur_trigger = node_to_item(node2, struct trigger, nlist);
+            if (!strncmp(cur_trigger->name, "property:", strlen("property:"))) {
+                const char *test = cur_trigger->name + strlen("property:");
+                if (!match) {
+                    name_length = strlen(name);
+                    if (!strncmp(name, test, name_length) &&
+                        test[name_length] == '=' &&
+                        (!strcmp(test + name_length + 1, value) ||
+                        !strcmp(test + name_length + 1, "*"))) {
+                        match = true;
+                        continue;
+                    }
+                } else {
+                     const char* equals = strchr(test, '=');
+                     if (equals) {
+                         char prop_name[PROP_NAME_MAX + 1];
+                         char value[PROP_VALUE_MAX];
+                         int length = equals - test;
+                         if (length <= PROP_NAME_MAX) {
+                             int ret;
+                             memcpy(prop_name, test, length);
+                             prop_name[length] = 0;
 
-            if (!strncmp(name, test, name_length) &&
-                    test[name_length] == '=' &&
-                    (!strcmp(test + name_length + 1, value) ||
-                     !strcmp(test + name_length + 1, "*"))) {
-                action_add_queue_tail(act);
-            }
+                             /* does the property exist, and match the trigger value? */
+                             ret = property_get(prop_name, value);
+                             if (ret > 0 && (!strcmp(equals + 1, value) ||
+                                !strcmp(equals + 1, "*"))) {
+                                 continue;
+                             }
+                         }
+                     }
+                 }
+             }
+             match = false;
+             break;
+        }
+        if (match) {
+            action_add_queue_tail(act);
         }
     }
 }
 
 void queue_all_property_triggers()
 {
-    struct listnode *node;
-    struct action *act;
-    list_for_each(node, &action_list) {
-        act = node_to_item(node, struct action, alist);
-        if (!strncmp(act->name, "property:", strlen("property:"))) {
-            /* parse property name and value
-               syntax is property:<name>=<value> */
-            const char* name = act->name + strlen("property:");
-            const char* equals = strchr(name, '=');
-            if (equals) {
-                char prop_name[PROP_NAME_MAX + 1];
-                char value[PROP_VALUE_MAX];
-                int length = equals - name;
-                if (length > PROP_NAME_MAX) {
-                    ERROR("property name too long in trigger %s", act->name);
-                } else {
-                    int ret;
-                    memcpy(prop_name, name, length);
-                    prop_name[length] = 0;
-
-                    /* does the property exist, and match the trigger value? */
-                    ret = property_get(prop_name, value);
-                    if (ret > 0 && (!strcmp(equals + 1, value) ||
-                                    !strcmp(equals + 1, "*"))) {
-                        action_add_queue_tail(act);
-                    }
-                }
-            }
-        }
-    }
+    queue_property_triggers(NULL, NULL);
 }
 
-void queue_builtin_action(int (*func)(int nargs, char **args), char *name)
+void queue_builtin_action(int (*func)(int nargs, char **args), const char *name)
 {
-    struct action *act;
-    struct command *cmd;
-
-    act = calloc(1, sizeof(*act));
-    act->name = name;
+    action* act = (action*) calloc(1, sizeof(*act));
+    trigger* cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger));
+    cur_trigger->name = name;
+    list_init(&act->triggers);
+    list_add_tail(&act->triggers, &cur_trigger->nlist);
     list_init(&act->commands);
     list_init(&act->qlist);
 
-    cmd = calloc(1, sizeof(*cmd));
+    command* cmd = (command*) calloc(1, sizeof(*cmd));
     cmd->func = func;
-    cmd->args[0] = name;
+    cmd->args[0] = const_cast<char*>(name);
     cmd->nargs = 1;
     list_add_tail(&act->commands, &cmd->clist);
 
@@ -613,9 +665,68 @@
     return list_empty(&action_queue);
 }
 
+service* make_exec_oneshot_service(int nargs, char** args) {
+    // Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS...
+    // SECLABEL can be a - to denote default
+    int command_arg = 1;
+    for (int i = 1; i < nargs; ++i) {
+        if (strcmp(args[i], "--") == 0) {
+            command_arg = i + 1;
+            break;
+        }
+    }
+    if (command_arg > 4 + NR_SVC_SUPP_GIDS) {
+        ERROR("exec called with too many supplementary group ids\n");
+        return NULL;
+    }
+
+    int argc = nargs - command_arg;
+    char** argv = (args + command_arg);
+    if (argc < 1) {
+        ERROR("exec called without command\n");
+        return NULL;
+    }
+
+    service* svc = (service*) calloc(1, sizeof(*svc) + sizeof(char*) * argc);
+    if (svc == NULL) {
+        ERROR("Couldn't allocate service for exec of '%s': %s", argv[0], strerror(errno));
+        return NULL;
+    }
+
+    if ((command_arg > 2) && strcmp(args[1], "-")) {
+        svc->seclabel = args[1];
+    }
+    if (command_arg > 3) {
+        svc->uid = decode_uid(args[2]);
+    }
+    if (command_arg > 4) {
+        svc->gid = decode_uid(args[3]);
+        svc->nr_supp_gids = command_arg - 1 /* -- */ - 4 /* exec SECLABEL UID GID */;
+        for (size_t i = 0; i < svc->nr_supp_gids; ++i) {
+            svc->supp_gids[i] = decode_uid(args[4 + i]);
+        }
+    }
+
+    static int exec_count; // Every service needs a unique name.
+    char* name = NULL;
+    asprintf(&name, "exec %d (%s)", exec_count++, argv[0]);
+    if (name == NULL) {
+        ERROR("Couldn't allocate name for exec service '%s'\n", argv[0]);
+        free(svc);
+        return NULL;
+    }
+    svc->name = name;
+    svc->classname = "default";
+    svc->flags = SVC_EXEC | SVC_ONESHOT;
+    svc->nargs = argc;
+    memcpy(svc->args, argv, sizeof(char*) * svc->nargs);
+    svc->args[argc] = NULL;
+    list_add_tail(&service_list, &svc->slist);
+    return svc;
+}
+
 static void *parse_service(struct parse_state *state, int nargs, char **args)
 {
-    struct service *svc;
     if (nargs < 3) {
         parse_error(state, "services must have a name and a program\n");
         return 0;
@@ -625,24 +736,27 @@
         return 0;
     }
 
-    svc = service_find_by_name(args[1]);
+    service* svc = (service*) service_find_by_name(args[1]);
     if (svc) {
         parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]);
         return 0;
     }
 
     nargs -= 2;
-    svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs);
+    svc = (service*) calloc(1, sizeof(*svc) + sizeof(char*) * nargs);
     if (!svc) {
         parse_error(state, "out of memory\n");
         return 0;
     }
-    svc->name = args[1];
+    svc->name = strdup(args[1]);
     svc->classname = "default";
     memcpy(svc->args, args + 2, sizeof(char*) * nargs);
+    trigger* cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger));
     svc->args[nargs] = 0;
     svc->nargs = nargs;
-    svc->onrestart.name = "onrestart";
+    list_init(&svc->onrestart.triggers);
+    cur_trigger->name = "onrestart";
+    list_add_tail(&svc->onrestart.triggers, &cur_trigger->nlist);
     list_init(&svc->onrestart.commands);
     list_add_tail(&service_list, &svc->slist);
     return svc;
@@ -650,7 +764,7 @@
 
 static void parse_line_service(struct parse_state *state, int nargs, char **args)
 {
-    struct service *svc = state->context;
+    struct service *svc = (service*) state->context;
     struct command *cmd;
     int i, kw, kw_nargs;
 
@@ -662,8 +776,6 @@
 
     kw = lookup_keyword(args[0]);
     switch (kw) {
-    case K_capability:
-        break;
     case K_class:
         if (nargs != 2) {
             parse_error(state, "class option requires a classname\n");
@@ -719,7 +831,7 @@
         if (nargs < 2) {
             parse_error(state, "keycodes option requires atleast one keycode\n");
         } else {
-            svc->keycodes = malloc((nargs - 1) * sizeof(svc->keycodes[0]));
+            svc->keycodes = (int*) malloc((nargs - 1) * sizeof(svc->keycodes[0]));
             if (!svc->keycodes) {
                 parse_error(state, "could not allocate keycodes\n");
             } else {
@@ -748,7 +860,7 @@
             break;
         }
 
-        cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
+        cmd = (command*) malloc(sizeof(*cmd) + sizeof(char*) * nargs);
         cmd->func = kw_func(kw);
         cmd->nargs = nargs;
         memcpy(cmd->args, args, sizeof(char*) * nargs);
@@ -758,12 +870,11 @@
         svc->flags |= SVC_CRITICAL;
         break;
     case K_setenv: { /* name value */
-        struct svcenvinfo *ei;
         if (nargs < 3) {
             parse_error(state, "setenv option requires name and value arguments\n");
             break;
         }
-        ei = calloc(1, sizeof(*ei));
+        svcenvinfo* ei = (svcenvinfo*) calloc(1, sizeof(*ei));
         if (!ei) {
             parse_error(state, "out of memory\n");
             break;
@@ -775,7 +886,6 @@
         break;
     }
     case K_socket: {/* name type perm [ uid gid context ] */
-        struct socketinfo *si;
         if (nargs < 4) {
             parse_error(state, "socket option requires name, type, perm arguments\n");
             break;
@@ -785,7 +895,7 @@
             parse_error(state, "socket type must be 'dgram', 'stream' or 'seqpacket'\n");
             break;
         }
-        si = calloc(1, sizeof(*si));
+        socketinfo* si = (socketinfo*) calloc(1, sizeof(*si));
         if (!si) {
             parse_error(state, "out of memory\n");
             break;
@@ -817,6 +927,16 @@
             svc->seclabel = args[1];
         }
         break;
+    case K_writepid:
+        if (nargs < 2) {
+            parse_error(state, "writepid option requires at least one filename\n");
+            break;
+        }
+        svc->writepid_files_ = new std::vector<std::string>;
+        for (int i = 1; i < nargs; ++i) {
+            svc->writepid_files_->push_back(args[i]);
+        }
+        break;
 
     default:
         parse_error(state, "invalid option '%s'\n", args[0]);
@@ -825,17 +945,36 @@
 
 static void *parse_action(struct parse_state *state, int nargs, char **args)
 {
-    struct action *act;
+    struct trigger *cur_trigger;
+    int i;
     if (nargs < 2) {
         parse_error(state, "actions must have a trigger\n");
         return 0;
     }
-    if (nargs > 2) {
-        parse_error(state, "actions may not have extra parameters\n");
-        return 0;
+
+    action* act = (action*) calloc(1, sizeof(*act));
+    list_init(&act->triggers);
+
+    for (i = 1; i < nargs; i++) {
+        if (!(i % 2)) {
+            if (strcmp(args[i], "&&")) {
+                struct listnode *node;
+                struct listnode *node2;
+                parse_error(state, "& is the only symbol allowed to concatenate actions\n");
+                list_for_each_safe(node, node2, &act->triggers) {
+                    struct trigger *trigger = node_to_item(node, struct trigger, nlist);
+                    free(trigger);
+                }
+                free(act);
+                return 0;
+            } else
+                continue;
+        }
+        cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger));
+        cur_trigger->name = args[i];
+        list_add_tail(&act->triggers, &cur_trigger->nlist);
     }
-    act = calloc(1, sizeof(*act));
-    act->name = args[1];
+
     list_init(&act->commands);
     list_init(&act->qlist);
     list_add_tail(&action_list, &act->alist);
@@ -845,9 +984,7 @@
 
 static void parse_line_action(struct parse_state* state, int nargs, char **args)
 {
-    struct command *cmd;
-    struct action *act = state->context;
-    int (*func)(int nargs, char **args);
+    struct action *act = (action*) state->context;
     int kw, n;
 
     if (nargs == 0) {
@@ -866,7 +1003,7 @@
             n > 2 ? "arguments" : "argument");
         return;
     }
-    cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
+    command* cmd = (command*) malloc(sizeof(*cmd) + sizeof(char*) * nargs);
     cmd->func = kw_func(kw);
     cmd->line = state->line;
     cmd->filename = state->filename;
diff --git a/init/init_parser.h b/init/init_parser.h
index b078cad..6348607 100644
--- a/init/init_parser.h
+++ b/init/init_parser.h
@@ -20,6 +20,7 @@
 #define INIT_PARSER_MAXARGS 64
 
 struct action;
+struct service;
 
 struct action *action_remove_queue_head(void);
 void action_add_queue_tail(struct action *act);
@@ -28,9 +29,11 @@
 int action_queue_empty(void);
 void queue_property_triggers(const char *name, const char *value);
 void queue_all_property_triggers();
-void queue_builtin_action(int (*func)(int nargs, char **args), char *name);
+void queue_builtin_action(int (*func)(int nargs, char **args), const char *name);
 
 int init_parse_config_file(const char *fn);
 int expand_props(char *dst, const char *src, int len);
 
+service* make_exec_oneshot_service(int argc, char** argv);
+
 #endif
diff --git a/init/init_parser_test.cpp b/init/init_parser_test.cpp
new file mode 100644
index 0000000..170a73a
--- /dev/null
+++ b/init/init_parser_test.cpp
@@ -0,0 +1,134 @@
+/*
+ * 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 "init_parser.h"
+
+#include "init.h"
+#include "util.h"
+
+#include <errno.h>
+#include <gtest/gtest.h>
+
+TEST(init_parser, make_exec_oneshot_service_invalid_syntax) {
+    char* argv[10];
+    memset(argv, 0, sizeof(argv));
+
+    // Nothing.
+    ASSERT_EQ(nullptr, make_exec_oneshot_service(0, argv));
+
+    // No arguments to 'exec'.
+    argv[0] = const_cast<char*>("exec");
+    ASSERT_EQ(nullptr, make_exec_oneshot_service(1, argv));
+
+    // No command in "exec --".
+    argv[1] = const_cast<char*>("--");
+    ASSERT_EQ(nullptr, make_exec_oneshot_service(2, argv));
+}
+
+TEST(init_parser, make_exec_oneshot_service_too_many_supplementary_gids) {
+    int argc = 0;
+    char* argv[4 + NR_SVC_SUPP_GIDS + 3];
+    argv[argc++] = const_cast<char*>("exec");
+    argv[argc++] = const_cast<char*>("seclabel");
+    argv[argc++] = const_cast<char*>("root"); // uid.
+    argv[argc++] = const_cast<char*>("root"); // gid.
+    for (int i = 0; i < NR_SVC_SUPP_GIDS; ++i) {
+        argv[argc++] = const_cast<char*>("root"); // Supplementary gid.
+    }
+    argv[argc++] = const_cast<char*>("--");
+    argv[argc++] = const_cast<char*>("/system/bin/id");
+    argv[argc] = nullptr;
+    ASSERT_EQ(nullptr, make_exec_oneshot_service(argc, argv));
+}
+
+static void Test_make_exec_oneshot_service(bool dash_dash, bool seclabel, bool uid, bool gid, bool supplementary_gids) {
+    int argc = 0;
+    char* argv[10];
+    argv[argc++] = const_cast<char*>("exec");
+    if (seclabel) {
+        argv[argc++] = const_cast<char*>("u:r:su:s0"); // seclabel
+        if (uid) {
+            argv[argc++] = const_cast<char*>("log");      // uid
+            if (gid) {
+                argv[argc++] = const_cast<char*>("shell");     // gid
+                if (supplementary_gids) {
+                    argv[argc++] = const_cast<char*>("system");    // supplementary gid 0
+                    argv[argc++] = const_cast<char*>("adb");       // supplementary gid 1
+                }
+            }
+        }
+    }
+    if (dash_dash) {
+        argv[argc++] = const_cast<char*>("--");
+    }
+    argv[argc++] = const_cast<char*>("/system/bin/toybox");
+    argv[argc++] = const_cast<char*>("id");
+    argv[argc] = nullptr;
+    service* svc = make_exec_oneshot_service(argc, argv);
+    ASSERT_NE(nullptr, svc);
+
+    if (seclabel) {
+        ASSERT_STREQ("u:r:su:s0", svc->seclabel);
+    } else {
+        ASSERT_EQ(nullptr, svc->seclabel);
+    }
+    if (uid) {
+        ASSERT_EQ(decode_uid("log"), svc->uid);
+    } else {
+        ASSERT_EQ(0U, svc->uid);
+    }
+    if (gid) {
+        ASSERT_EQ(decode_uid("shell"), svc->gid);
+    } else {
+        ASSERT_EQ(0U, svc->gid);
+    }
+    if (supplementary_gids) {
+        ASSERT_EQ(2U, svc->nr_supp_gids);
+        ASSERT_EQ(decode_uid("system"), svc->supp_gids[0]);
+        ASSERT_EQ(decode_uid("adb"), svc->supp_gids[1]);
+    } else {
+        ASSERT_EQ(0U, svc->nr_supp_gids);
+    }
+
+    ASSERT_EQ(2, svc->nargs);
+    ASSERT_EQ("/system/bin/toybox", svc->args[0]);
+    ASSERT_EQ("id", svc->args[1]);
+    ASSERT_EQ(nullptr, svc->args[2]);
+}
+
+TEST(init_parser, make_exec_oneshot_service_with_everything) {
+    Test_make_exec_oneshot_service(true, true, true, true, true);
+}
+
+TEST(init_parser, make_exec_oneshot_service_with_seclabel_uid_gid) {
+    Test_make_exec_oneshot_service(true, true, true, true, false);
+}
+
+TEST(init_parser, make_exec_oneshot_service_with_seclabel_uid) {
+    Test_make_exec_oneshot_service(true, true, true, false, false);
+}
+
+TEST(init_parser, make_exec_oneshot_service_with_seclabel) {
+    Test_make_exec_oneshot_service(true, true, false, false, false);
+}
+
+TEST(init_parser, make_exec_oneshot_service_with_just_command) {
+    Test_make_exec_oneshot_service(true, false, false, false, false);
+}
+
+TEST(init_parser, make_exec_oneshot_service_with_just_command_no_dash) {
+    Test_make_exec_oneshot_service(false, false, false, false, false);
+}
diff --git a/init/keychords.c b/init/keychords.cpp
similarity index 77%
rename from init/keychords.c
rename to init/keychords.cpp
index 4a64042..10d9573 100644
--- a/init/keychords.c
+++ b/init/keychords.cpp
@@ -40,7 +40,7 @@
     if (svc->keycodes) {
         /* add a new keychord to the list */
         size = sizeof(*keychord) + svc->nkeycodes * sizeof(keychord->keycodes[0]);
-        keychords = realloc(keychords, keychords_length + size);
+        keychords = (input_keychord*) realloc(keychords, keychords_length + size);
         if (!keychords) {
             ERROR("could not allocate keychords\n");
             keychords_length = 0;
@@ -62,38 +62,7 @@
     }
 }
 
-void keychord_init()
-{
-    int fd, ret;
-
-    service_for_each(add_service_keycodes);
-
-    /* nothing to do if no services require keychords */
-    if (!keychords)
-        return;
-
-    fd = open("/dev/keychord", O_RDWR);
-    if (fd < 0) {
-        ERROR("could not open /dev/keychord\n");
-        return;
-    }
-    fcntl(fd, F_SETFD, FD_CLOEXEC);
-
-    ret = write(fd, keychords, keychords_length);
-    if (ret != keychords_length) {
-        ERROR("could not configure /dev/keychord %d (%d)\n", ret, errno);
-        close(fd);
-        fd = -1;
-    }
-
-    free(keychords);
-    keychords = 0;
-
-    keychord_fd = fd;
-}
-
-void handle_keychord()
-{
+static void handle_keychord() {
     struct service *svc;
     char adb_enabled[PROP_VALUE_MAX];
     int ret;
@@ -110,7 +79,7 @@
     if (!strcmp(adb_enabled, "running")) {
         svc = service_find_by_keychord(id);
         if (svc) {
-            INFO("starting service %s from keychord\n", svc->name);
+            INFO("Starting service %s from keychord\n", svc->name);
             service_start(svc, NULL);
         } else {
             ERROR("service for keychord %d not found\n", id);
@@ -118,7 +87,28 @@
     }
 }
 
-int get_keychord_fd()
-{
-    return keychord_fd;
+void keychord_init() {
+    service_for_each(add_service_keycodes);
+
+    // Nothing to do if no services require keychords.
+    if (!keychords) {
+        return;
+    }
+
+    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));
+        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));
+        close(keychord_fd);
+    }
+
+    free(keychords);
+    keychords = nullptr;
+
+    register_epoll_handler(keychord_fd, handle_keychord);
 }
diff --git a/init/keychords.h b/init/keychords.h
index 070b858..d2723b7 100644
--- a/init/keychords.h
+++ b/init/keychords.h
@@ -19,9 +19,7 @@
 
 struct service;
 
-void add_service_keycodes(struct service *svc);
-void keychord_init(void);
-void handle_keychord(void);
-int get_keychord_fd(void);
+void add_service_keycodes(service*);
+void keychord_init();
 
 #endif
diff --git a/init/keywords.h b/init/keywords.h
index 2d97e5b..e637d7d 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -1,7 +1,5 @@
-
 #ifndef KEYWORD
-int do_chroot(int nargs, char **args);
-int do_chdir(int nargs, char **args);
+int do_bootchart_init(int nargs, char **args);
 int do_class_start(int nargs, char **args);
 int do_class_stop(int nargs, char **args);
 int do_class_reset(int nargs, char **args);
@@ -12,6 +10,7 @@
 int do_hostname(int nargs, char **args);
 int do_ifup(int nargs, char **args);
 int do_insmod(int nargs, char **args);
+int do_installkey(int nargs, char **args);
 int do_mkdir(int nargs, char **args);
 int do_mount_all(int nargs, char **args);
 int do_mount(int nargs, char **args);
@@ -21,12 +20,8 @@
 int do_restorecon_recursive(int nargs, char **args);
 int do_rm(int nargs, char **args);
 int do_rmdir(int nargs, char **args);
-int do_setcon(int nargs, char **args);
-int do_setenforce(int nargs, char **args);
-int do_setkey(int nargs, char **args);
 int do_setprop(int nargs, char **args);
 int do_setrlimit(int nargs, char **args);
-int do_setsebool(int nargs, char **args);
 int do_start(int nargs, char **args);
 int do_stop(int nargs, char **args);
 int do_swapon_all(int nargs, char **args);
@@ -40,20 +35,23 @@
 int do_loglevel(int nargs, char **args);
 int do_load_persist_props(int nargs, char **args);
 int do_load_all_props(int nargs, char **args);
+int do_verity_load_state(int nargs, char **args);
+int do_verity_update_state(int nargs, char **args);
 int do_wait(int nargs, char **args);
 #define __MAKE_KEYWORD_ENUM__
 #define KEYWORD(symbol, flags, nargs, func) K_##symbol,
 enum {
     K_UNKNOWN,
 #endif
-    KEYWORD(capability,  OPTION,  0, 0)
-    KEYWORD(chdir,       COMMAND, 1, do_chdir)
-    KEYWORD(chroot,      COMMAND, 1, do_chroot)
+    KEYWORD(bootchart_init,        COMMAND, 0, do_bootchart_init)
+    KEYWORD(chmod,       COMMAND, 2, do_chmod)
+    KEYWORD(chown,       COMMAND, 2, do_chown)
     KEYWORD(class,       OPTION,  0, 0)
+    KEYWORD(class_reset, COMMAND, 1, do_class_reset)
     KEYWORD(class_start, COMMAND, 1, do_class_start)
     KEYWORD(class_stop,  COMMAND, 1, do_class_stop)
-    KEYWORD(class_reset, COMMAND, 1, do_class_reset)
     KEYWORD(console,     OPTION,  0, 0)
+    KEYWORD(copy,        COMMAND, 2, do_copy)
     KEYWORD(critical,    OPTION,  0, 0)
     KEYWORD(disabled,    OPTION,  0, 0)
     KEYWORD(domainname,  COMMAND, 1, do_domainname)
@@ -63,15 +61,20 @@
     KEYWORD(group,       OPTION,  0, 0)
     KEYWORD(hostname,    COMMAND, 1, do_hostname)
     KEYWORD(ifup,        COMMAND, 1, do_ifup)
-    KEYWORD(insmod,      COMMAND, 1, do_insmod)
     KEYWORD(import,      SECTION, 1, 0)
+    KEYWORD(insmod,      COMMAND, 1, do_insmod)
+    KEYWORD(installkey,  COMMAND, 1, do_installkey)
+    KEYWORD(ioprio,      OPTION,  0, 0)
     KEYWORD(keycodes,    OPTION,  0, 0)
+    KEYWORD(load_all_props,        COMMAND, 0, do_load_all_props)
+    KEYWORD(load_persist_props,    COMMAND, 0, do_load_persist_props)
+    KEYWORD(loglevel,    COMMAND, 1, do_loglevel)
     KEYWORD(mkdir,       COMMAND, 1, do_mkdir)
     KEYWORD(mount_all,   COMMAND, 1, do_mount_all)
     KEYWORD(mount,       COMMAND, 3, do_mount)
-    KEYWORD(on,          SECTION, 0, 0)
     KEYWORD(oneshot,     OPTION,  0, 0)
     KEYWORD(onrestart,   OPTION,  0, 0)
+    KEYWORD(on,          SECTION, 0, 0)
     KEYWORD(powerctl,    COMMAND, 1, do_powerctl)
     KEYWORD(restart,     COMMAND, 1, do_restart)
     KEYWORD(restorecon,  COMMAND, 1, do_restorecon)
@@ -80,34 +83,25 @@
     KEYWORD(rmdir,       COMMAND, 1, do_rmdir)
     KEYWORD(seclabel,    OPTION,  0, 0)
     KEYWORD(service,     SECTION, 0, 0)
-    KEYWORD(setcon,      COMMAND, 1, do_setcon)
-    KEYWORD(setenforce,  COMMAND, 1, do_setenforce)
     KEYWORD(setenv,      OPTION,  2, 0)
-    KEYWORD(setkey,      COMMAND, 0, do_setkey)
     KEYWORD(setprop,     COMMAND, 2, do_setprop)
     KEYWORD(setrlimit,   COMMAND, 3, do_setrlimit)
-    KEYWORD(setsebool,   COMMAND, 2, do_setsebool)
     KEYWORD(socket,      OPTION,  0, 0)
     KEYWORD(start,       COMMAND, 1, do_start)
     KEYWORD(stop,        COMMAND, 1, do_stop)
     KEYWORD(swapon_all,  COMMAND, 1, do_swapon_all)
-    KEYWORD(trigger,     COMMAND, 1, do_trigger)
     KEYWORD(symlink,     COMMAND, 1, do_symlink)
     KEYWORD(sysclktz,    COMMAND, 1, do_sysclktz)
+    KEYWORD(trigger,     COMMAND, 1, do_trigger)
     KEYWORD(user,        OPTION,  0, 0)
+    KEYWORD(verity_load_state,      COMMAND, 0, do_verity_load_state)
+    KEYWORD(verity_update_state,    COMMAND, 0, do_verity_update_state)
     KEYWORD(wait,        COMMAND, 1, do_wait)
     KEYWORD(write,       COMMAND, 2, do_write)
-    KEYWORD(copy,        COMMAND, 2, do_copy)
-    KEYWORD(chown,       COMMAND, 2, do_chown)
-    KEYWORD(chmod,       COMMAND, 2, do_chmod)
-    KEYWORD(loglevel,    COMMAND, 1, do_loglevel)
-    KEYWORD(load_persist_props,    COMMAND, 0, do_load_persist_props)
-    KEYWORD(load_all_props,        COMMAND, 0, do_load_all_props)
-    KEYWORD(ioprio,      OPTION,  0, 0)
+    KEYWORD(writepid,    OPTION,  0, 0)
 #ifdef __MAKE_KEYWORD_ENUM__
     KEYWORD_COUNT,
 };
 #undef __MAKE_KEYWORD_ENUM__
 #undef KEYWORD
 #endif
-
diff --git a/init/log.cpp b/init/log.cpp
new file mode 100644
index 0000000..d32f2da
--- /dev/null
+++ b/init/log.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+#include <sys/uio.h>
+
+#include <selinux/selinux.h>
+
+#include "log.h"
+
+static void init_klog_vwrite(int level, const char* fmt, va_list ap) {
+    static const char* tag = basename(getprogname());
+
+    char prefix[64];
+    snprintf(prefix, sizeof(prefix), "<%d>%s: ", level, tag);
+
+    char msg[512];
+    vsnprintf(msg, sizeof(msg), fmt, ap);
+
+    iovec iov[2];
+    iov[0].iov_base = prefix;
+    iov[0].iov_len = strlen(prefix);
+    iov[1].iov_base = msg;
+    iov[1].iov_len = strlen(msg);
+
+    klog_writev(level, iov, 2);
+}
+
+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);
+}
+
+int selinux_klog_callback(int type, const char *fmt, ...) {
+    int level = KLOG_ERROR_LEVEL;
+    if (type == SELINUX_WARNING) {
+        level = KLOG_WARNING_LEVEL;
+    } else if (type == SELINUX_INFO) {
+        level = KLOG_INFO_LEVEL;
+    }
+    va_list ap;
+    va_start(ap, fmt);
+    init_klog_vwrite(level, fmt, ap);
+    va_end(ap);
+    return 0;
+}
diff --git a/init/log.h b/init/log.h
index e9cb65a..b804d1f 100644
--- a/init/log.h
+++ b/init/log.h
@@ -19,10 +19,11 @@
 
 #include <cutils/klog.h>
 
-#define ERROR(x...)   KLOG_ERROR("init", x)
-#define NOTICE(x...)  KLOG_NOTICE("init", x)
-#define INFO(x...)    KLOG_INFO("init", x)
+#define ERROR(x...)   init_klog_write(KLOG_ERROR_LEVEL, x)
+#define NOTICE(x...)  init_klog_write(KLOG_NOTICE_LEVEL, x)
+#define INFO(x...)    init_klog_write(KLOG_INFO_LEVEL, x)
 
-extern int log_callback(int type, const char *fmt, ...);
+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.c b/init/parser.cpp
similarity index 73%
rename from init/parser.c
rename to init/parser.cpp
index 48e7aec..8193729 100644
--- a/init/parser.c
+++ b/init/parser.cpp
@@ -1,59 +1,17 @@
-#include <stdio.h>
+#include "parser.h"
+
 #include <stdarg.h>
+#include <stdio.h>
 #include <string.h>
 
-#include "parser.h"
 #include "log.h"
 
-#define RAW(x...) log_write(6, x)
-
-void DUMP(void)
-{
-#if 0
-    struct service *svc;
-    struct action *act;
-    struct command *cmd;
-    struct listnode *node;
-    struct listnode *node2;
-    struct socketinfo *si;
-    int n;
-    
-    list_for_each(node, &service_list) {
-        svc = node_to_item(node, struct service, slist);
-        RAW("service %s\n", svc->name);
-        RAW("  class '%s'\n", svc->classname);
-        RAW("  exec");
-        for (n = 0; n < svc->nargs; n++) {
-            RAW(" '%s'", svc->args[n]);
-        }
-        RAW("\n");
-        for (si = svc->sockets; si; si = si->next) {
-            RAW("  socket %s %s 0%o\n", si->name, si->type, si->perm);
-        }
-    }
-
-    list_for_each(node, &action_list) {
-        act = node_to_item(node, struct action, alist);
-        RAW("on %s\n", act->name);
-        list_for_each(node2, &act->commands) {
-            cmd = node_to_item(node2, struct command, clist);
-            RAW("  %p", cmd->func);
-            for (n = 0; n < cmd->nargs; n++) {
-                RAW(" %s", cmd->args[n]);
-            }
-            RAW("\n");
-        }
-        RAW("\n");
-    }
-#endif       
-}
-
 void parse_error(struct parse_state *state, const char *fmt, ...)
 {
     va_list ap;
     char buf[128];
     int off;
-    
+
     snprintf(buf, 128, "%s: %d: ", state->filename, state->line);
     buf[127] = 0;
     off = strlen(buf);
diff --git a/init/parser.h b/init/parser.h
index a58272a..95e1164 100644
--- a/init/parser.h
+++ b/init/parser.h
@@ -33,7 +33,7 @@
     void *priv;
 };
 
-void DUMP(void);
+void dump_parser_state(void);
 int next_token(struct parse_state *state);
 void parse_error(struct parse_state *state, const char *fmt, ...);
 
diff --git a/init/property_service.c b/init/property_service.cpp
similarity index 63%
rename from init/property_service.c
rename to init/property_service.cpp
index 91ef251..c2881ae 100644
--- a/init/property_service.c
+++ b/init/property_service.cpp
@@ -26,6 +26,8 @@
 #include <errno.h>
 #include <sys/poll.h>
 
+#include <memory>
+
 #include <cutils/misc.h>
 #include <cutils/sockets.h>
 #include <cutils/multiuser.h>
@@ -44,52 +46,48 @@
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 
+#include <fs_mgr.h>
+#include <base/file.h>
+#include "bootimg.h"
+
 #include "property_service.h"
 #include "init.h"
 #include "util.h"
 #include "log.h"
 
 #define PERSISTENT_PROPERTY_DIR  "/data/property"
+#define FSTAB_PREFIX "/fstab."
+#define RECOVERY_MOUNT_POINT "/recovery"
 
 static int persistent_properties_loaded = 0;
-static int property_area_inited = 0;
+static bool property_area_initialized = false;
 
 static int property_set_fd = -1;
 
-typedef struct {
+struct workspace {
     size_t size;
     int fd;
-} workspace;
-
-static int init_workspace(workspace *w, size_t size)
-{
-    void *data;
-    int fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW);
-    if (fd < 0)
-        return -1;
-
-    w->size = size;
-    w->fd = fd;
-    return 0;
-}
+};
 
 static workspace pa_workspace;
 
-static int init_property_area(void)
-{
-    if (property_area_inited)
-        return -1;
+void property_init() {
+    if (property_area_initialized) {
+        return;
+    }
 
-    if(__system_property_area_init())
-        return -1;
+    property_area_initialized = true;
 
-    if(init_workspace(&pa_workspace, 0))
-        return -1;
+    if (__system_property_area_init()) {
+        return;
+    }
 
-    fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC);
-
-    property_area_inited = 1;
-    return 0;
+    pa_workspace.size = 0;
+    pa_workspace.fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
+    if (pa_workspace.fd == -1) {
+        ERROR("Failed to open %s: %s\n", PROP_FILENAME, strerror(errno));
+        return;
+    }
 }
 
 static int check_mac_perms(const char *name, char *sctx)
@@ -98,8 +96,6 @@
         return 1;
 
     char *tctx = NULL;
-    const char *class = "property_service";
-    const char *perm = "set";
     int result = 0;
 
     if (!sctx)
@@ -111,7 +107,7 @@
     if (selabel_lookup(sehandle_prop, &tctx, name, 1) != 0)
         goto err;
 
-    if (selinux_check_access(sctx, tctx, class, perm, (void*) name) == 0)
+    if (selinux_check_access(sctx, tctx, "property_service", "set", (void*) name) == 0)
         result = 1;
 
     freecon(tctx);
@@ -142,9 +138,6 @@
  */
 static int check_perms(const char *name, char *sctx)
 {
-    int i;
-    unsigned int app_id;
-
     if(!strncmp(name, "ro.", 3))
         name +=3;
 
@@ -165,7 +158,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 errno: %d\n", tempPath, errno);
+        ERROR("Unable to write persistent property to temp file %s: %s\n", tempPath, strerror(errno));
         return;
     }
     write(fd, value, strlen(value));
@@ -205,18 +198,24 @@
     return true;
 }
 
-int property_set(const char *name, const char *value)
-{
-    prop_info *pi;
-    int ret;
-
+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 (valuelen >= PROP_VALUE_MAX) return -1;
 
-    pi = (prop_info*) __system_property_find(name);
+    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);
+        }
+    }
+
+    prop_info* pi = (prop_info*) __system_property_find(name);
 
     if(pi != 0) {
         /* ro.* properties may NEVER be modified once set */
@@ -224,10 +223,9 @@
 
         __system_property_update(pi, value, valuelen);
     } else {
-        ret = __system_property_add(name, namelen, value, valuelen);
-        if (ret < 0) {
-            ERROR("Failed to set '%s'='%s'\n", name, value);
-            return ret;
+        int rc = __system_property_add(name, namelen, value, valuelen);
+        if (rc < 0) {
+            return rc;
         }
     }
     /* If name starts with "net." treat as a DNS property. */
@@ -248,20 +246,24 @@
          * to prevent them from being overwritten by default values.
          */
         write_persistent_property(name, value);
-    } else if (strcmp("selinux.reload_policy", name) == 0 &&
-               strcmp("1", value) == 0) {
-        selinux_reload_policy();
     }
     property_changed(name, value);
     return 0;
 }
 
-void handle_property_set_fd()
+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);
+    }
+    return rc;
+}
+
+static void handle_property_set_fd()
 {
     prop_msg msg;
     int s;
     int r;
-    int res;
     struct ucred cr;
     struct sockaddr_un addr;
     socklen_t addr_size = sizeof(addr);
@@ -291,15 +293,15 @@
         close(s);
         return;
     } else if (nr < 0) {
-        ERROR("sys_prop: error waiting for uid=%d to send property message. err=%d %s\n", cr.uid, errno, strerror(errno));
+        ERROR("sys_prop: error waiting for uid=%d to send property message: %s\n", cr.uid, strerror(errno));
         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 errno: %d\n",
-              r, sizeof(prop_msg), errno);
+        ERROR("sys_prop: mis-match msg size received: %d expected: %zu: %s\n",
+              r, sizeof(prop_msg), strerror(errno));
         close(s);
         return;
     }
@@ -421,125 +423,145 @@
  * 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 *fn, const char *filter)
-{
-    char *data;
-    unsigned sz;
-
-    data = read_file(fn, &sz);
-
-    if(data != 0) {
-        load_properties(data, filter);
-        free(data);
+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);
     }
+    NOTICE("(Loading properties from %s took %.2fs.)\n", filename, t.duration());
 }
 
-static void load_persistent_properties()
-{
-    DIR* dir = opendir(PERSISTENT_PROPERTY_DIR);
-    int dir_fd;
-    struct dirent*  entry;
-    char value[PROP_VALUE_MAX];
-    int fd, length;
-    struct stat sb;
-
-    if (dir) {
-        dir_fd = dirfd(dir);
-        while ((entry = readdir(dir)) != NULL) {
-            if (strncmp("persist.", entry->d_name, strlen("persist.")))
-                continue;
-#if HAVE_DIRENT_D_TYPE
-            if (entry->d_type != DT_REG)
-                continue;
-#endif
-            /* open the file and read the property value */
-            fd = openat(dir_fd, entry->d_name, O_RDONLY | O_NOFOLLOW);
-            if (fd < 0) {
-                ERROR("Unable to open persistent property file \"%s\" errno: %d\n",
-                      entry->d_name, errno);
-                continue;
-            }
-            if (fstat(fd, &sb) < 0) {
-                ERROR("fstat on property file \"%s\" failed errno: %d\n", entry->d_name, errno);
-                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=%d mode=%o)\n",
-                      entry->d_name, (unsigned int)sb.st_uid, (unsigned int)sb.st_gid,
-                      sb.st_nlink, sb.st_mode);
-                close(fd);
-                continue;
-            }
-
-            length = read(fd, value, sizeof(value) - 1);
-            if (length >= 0) {
-                value[length] = 0;
-                property_set(entry->d_name, value);
-            } else {
-                ERROR("Unable to read persistent property file %s errno: %d\n",
-                      entry->d_name, errno);
-            }
-            close(fd);
-        }
-        closedir(dir);
-    } else {
-        ERROR("Unable to open persistent property directory %s errno: %d\n", PERSISTENT_PROPERTY_DIR, errno);
-    }
-
+static void load_persistent_properties() {
     persistent_properties_loaded = 1;
+
+    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));
+        return;
+    }
+
+    struct dirent* entry;
+    while ((entry = readdir(dir.get())) != NULL) {
+        if (strncmp("persist.", entry->d_name, strlen("persist."))) {
+            continue;
+        }
+        if (entry->d_type != DT_REG) {
+            continue;
+        }
+
+        // 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));
+            continue;
+        }
+
+        struct stat sb;
+        if (fstat(fd, &sb) == -1) {
+            ERROR("fstat on property file \"%s\" failed: %s\n", entry->d_name, strerror(errno));
+            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);
+            close(fd);
+            continue;
+        }
+
+        char value[PROP_VALUE_MAX];
+        int length = read(fd, value, sizeof(value) - 1);
+        if (length >= 0) {
+            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));
+        }
+        close(fd);
+    }
 }
 
-void property_init(void)
-{
-    init_property_area();
-}
-
-void property_load_boot_defaults(void)
-{
+void property_load_boot_defaults() {
     load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT, NULL);
 }
 
-int properties_inited(void)
-{
-    return property_area_inited;
+bool properties_initialized() {
+    return property_area_initialized;
 }
 
 static void load_override_properties() {
-#ifdef ALLOW_LOCAL_PROP_OVERRIDE
-    char debuggable[PROP_VALUE_MAX];
-    int ret;
-
-    ret = property_get("ro.debuggable", debuggable);
-    if (ret && (strcmp(debuggable, "1") == 0)) {
-        load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE, NULL);
+    if (ALLOW_LOCAL_PROP_OVERRIDE) {
+        char debuggable[PROP_VALUE_MAX];
+        int ret = property_get("ro.debuggable", debuggable);
+        if (ret && (strcmp(debuggable, "1") == 0)) {
+            load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE, NULL);
+        }
     }
-#endif /* ALLOW_LOCAL_PROP_OVERRIDE */
 }
 
-
 /* When booting an encrypted system, /data is not mounted when the
  * property service is started, so any properties stored there are
  * not loaded.  Vold triggers init to load these properties once it
  * has mounted /data.
  */
-void load_persist_props(void)
-{
+void load_persist_props(void) {
     load_override_properties();
     /* Read persistent properties after all default values have been loaded. */
     load_persistent_properties();
 }
 
-void load_all_props(void)
-{
+void load_recovery_id_prop() {
+    char fstab_filename[PROP_VALUE_MAX + sizeof(FSTAB_PREFIX)];
+    char propbuf[PROP_VALUE_MAX];
+    int ret = property_get("ro.hardware", propbuf);
+    if (!ret) {
+        ERROR("ro.hardware not set - unable to load recovery id\n");
+        return;
+    }
+    snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX "%s", propbuf);
+
+    std::unique_ptr<fstab, void(*)(fstab*)> tab(fs_mgr_read_fstab(fstab_filename),
+            fs_mgr_free_fstab);
+    if (!tab) {
+        ERROR("unable to read fstab %s: %s\n", fstab_filename, strerror(errno));
+        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");
+        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));
+        return;
+    }
+
+    boot_img_hdr hdr;
+    if (android::base::ReadFully(fd, &hdr, sizeof(hdr))) {
+        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));
+    }
+
+    close(fd);
+}
+
+void load_all_props() {
     load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);
-    load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT, NULL);
     load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL);
     load_properties_from_file(PROP_PATH_FACTORY, "ro.*");
 
@@ -547,22 +569,19 @@
 
     /* Read persistent properties after all default values have been loaded. */
     load_persistent_properties();
+
+    load_recovery_id_prop();
 }
 
-void start_property_service(void)
-{
-    int fd;
+void start_property_service() {
+    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));
+        exit(1);
+    }
 
-    fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0, NULL);
-    if(fd < 0) return;
-    fcntl(fd, F_SETFD, FD_CLOEXEC);
-    fcntl(fd, F_SETFL, O_NONBLOCK);
+    listen(property_set_fd, 8);
 
-    listen(fd, 8);
-    property_set_fd = fd;
-}
-
-int get_property_set_fd()
-{
-    return property_set_fd;
+    register_epoll_handler(property_set_fd, handle_property_set_fd);
 }
diff --git a/init/property_service.h b/init/property_service.h
index 730495e..a27053d 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -17,10 +17,9 @@
 #ifndef _INIT_PROPERTY_H
 #define _INIT_PROPERTY_H
 
-#include <stdbool.h>
+#include <stddef.h>
 #include <sys/system_properties.h>
 
-extern void handle_property_set_fd(void);
 extern void property_init(void);
 extern void property_load_boot_defaults(void);
 extern void load_persist_props(void);
@@ -29,16 +28,21 @@
 void get_property_workspace(int *fd, int *sz);
 extern int __property_get(const char *name, char *value);
 extern int property_set(const char *name, const char *value);
-extern int properties_inited();
-int get_property_set_fd(void);
+extern bool properties_initialized();
 
+#ifndef __clang__
 extern void __property_get_size_error()
     __attribute__((__error__("property_get called with too small buffer")));
+#else
+extern void __property_get_size_error();
+#endif
 
 static inline
 __attribute__ ((always_inline))
 __attribute__ ((gnu_inline))
+#ifndef __clang__
 __attribute__ ((artificial))
+#endif
 int property_get(const char *name, char *value)
 {
     size_t value_len = __builtin_object_size(value, 0);
diff --git a/init/readme.txt b/init/readme.txt
index 26be536..9e3394e 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -60,60 +60,65 @@
 runs the service.
 
 critical
-   This is a device-critical service. If it exits more than four times in
-   four minutes, the device will reboot into recovery mode.
+  This is a device-critical service. If it exits more than four times in
+  four minutes, the device will reboot into recovery mode.
 
 disabled
-   This service will not automatically start with its class.
-   It must be explicitly started by name.
+  This service will not automatically start with its class.
+  It must be explicitly started by name.
 
 setenv <name> <value>
-   Set the environment variable <name> to <value> in the launched process.
+  Set the environment variable <name> to <value> in the launched process.
 
-socket <name> <type> <perm> [ <user> [ <group> [ <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.
-   Context 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.
+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.
 
 user <username>
-   Change to username before exec'ing this service.
-   Currently defaults to root.  (??? probably should default to nobody)
-   Currently, if your process requires linux capabilities then you cannot use
-   this command. You must instead request the capabilities in-process while
-   still root, and then drop to your desired uid.
+  Change to username before exec'ing this service.
+  Currently defaults to root.  (??? probably should default to nobody)
+  Currently, if your process requires linux capabilities then you cannot use
+  this command. You must instead request the capabilities in-process while
+  still root, and then drop to your desired uid.
 
 group <groupname> [ <groupname> ]*
-   Change to groupname before exec'ing this service.  Additional
-   groupnames beyond the (required) first one are used to set the
-   supplemental groups of the process (via setgroups()).
-   Currently defaults to root.  (??? probably should default to nobody)
+  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)
 
-seclabel <securitycontext>
-  Change to securitycontext before exec'ing this service.
+seclabel <seclabel>
+  Change to 'seclabel' before exec'ing this service.
   Primarily for use by services run from the rootfs, e.g. ueventd, adbd.
   Services on the system partition can instead use policy-defined transitions
   based on their file security context.
   If not specified and no transition is defined in policy, defaults to the init context.
 
 oneshot
-   Do not restart the service when it exits.
+  Do not restart the service when it exits.
 
 class <name>
-   Specify a class name for the service.  All services in a
-   named class may be started or stopped together.  A service
-   is in the class "default" if one is not specified via the
-   class option.
+  Specify a class name for the service.  All services in a
+  named class may be started or stopped together.  A service
+  is in the class "default" if one is not specified via the
+  class option.
 
 onrestart
-    Execute a Command (see below) when service restarts.
+  Execute a Command (see below) when service restarts.
+
+writepid <file...>
+  Write the child's pid to the given files when it forks. Meant for
+  cgroup/cpuset usage.
+
 
 Triggers
 --------
-   Triggers are strings which can be used to match certain kinds
-   of events and used to cause an action to occur.
+Triggers are strings which can be used to match certain kinds
+of events and used to cause an action to occur.
 
 boot
    This is the first trigger that will occur when init starts
@@ -123,40 +128,22 @@
    Triggers of this form occur when the property <name> is set
    to the specific value <value>.
 
-device-added-<path>
-device-removed-<path>
-   Triggers of these forms occur when a device node is added
-   or removed.
+   One can also test multiple properties to execute a group
+   of commands. For example:
 
-service-exited-<name>
-   Triggers of this form occur when the specified service exits.
+   on property:test.a=1 && property:test.b=1
+       setprop test.c 1
+
+   The above stub sets test.c to 1 only when
+   both test.a=1 and test.b=1
 
 
 Commands
 --------
 
-exec <path> [ <argument> ]*
-   Fork and execute a program (<path>).  This will block until
-   the program completes execution.  It is best to avoid exec
-   as unlike the builtin commands, it runs the risk of getting
-   init "stuck". (??? maybe there should be a timeout?)
-
-export <name> <value>
-   Set the environment variable <name> equal to <value> in the
-   global environment (which will be inherited by all processes
-   started after this command is executed)
-
-ifup <interface>
-   Bring the network interface <interface> online.
-
-import <filename>
-   Parse an init config file, extending the current configuration.
-
-hostname <name>
-   Set the host name.
-
-chdir <directory>
-   Change working directory.
+bootchart_init
+   Start bootcharting if configured (see below).
+   This is included in the default init.rc.
 
 chmod <octal-mode> <path>
    Change file access permissions.
@@ -164,17 +151,23 @@
 chown <owner> <group> <path>
    Change file owner and group.
 
-chroot <directory>
-  Change process root directory.
-
 class_start <serviceclass>
    Start all services of the specified class if they are
    not already running.
 
 class_stop <serviceclass>
-   Stop all services of the specified class if they are
+   Stop and disable all services of the specified class if they are
    currently running.
 
+class_reset <serviceclass>
+   Stop all services of the specified class if they are
+   currently running, without disabling them. They can be restarted
+   later using class_start.
+
+copy <src> <dst>
+   Copies a file. Similar to write, but useful for binary/large
+   amounts of data.
+
 domainname <name>
    Set the domain name.
 
@@ -187,20 +180,63 @@
      on property:ro.boot.myfancyhardware=1
         enable my_fancy_service_for_my_fancy_hardware
 
+exec [ <seclabel> [ <user> [ <group> ]* ] ] -- <command> [ <argument> ]*
+   Fork and execute command with the given arguments. The command starts
+   after "--" so that an optional security context, user, and supplementary
+   groups can be provided. No other commands will be run until this one
+   finishes. <seclabel> can be a - to denote default.
+
+export <name> <value>
+   Set the environment variable <name> equal to <value> in the
+   global environment (which will be inherited by all processes
+   started after this command is executed)
+
+hostname <name>
+   Set the host name.
+
+ifup <interface>
+   Bring the network interface <interface> online.
+
+import <filename>
+   Parse an init config file, extending the current configuration.
 
 insmod <path>
    Install the module at <path>
 
+load_all_props
+   Loads properties from /system, /vendor, et cetera.
+   This is included in the default init.rc.
+
+load_persist_props
+   Loads persistent properties when /data has been decrypted.
+   This is included in the default init.rc.
+
+loglevel <level>
+   Sets the kernel log level to level. Properties are expanded within <level>.
+
 mkdir <path> [mode] [owner] [group]
    Create a directory at <path>, optionally with the given mode, owner, and
    group. If not provided, the directory is created with permissions 755 and
-   owned by the root user and root group.
+   owned by the root user and root group. If provided, the mode, owner and group
+   will be updated if the directory exists already.
 
-mount <type> <device> <dir> [ <mountoption> ]*
+mount_all <fstab>
+   Calls fs_mgr_mount_all on the given fs_mgr-format fstab.
+
+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.
-   <mountoption>s include "ro", "rw", "remount", "noatime", ...
+   <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
+
+powerctl
+   Internal implementation detail used to respond to changes to the
+   "sys.powerctl" system property, used to implement rebooting.
+
+restart <service>
+   Like stop, but doesn't disable the service.
 
 restorecon <path> [ <path> ]*
    Restore the file named by <path> to the security context specified
@@ -211,37 +247,31 @@
 restorecon_recursive <path> [ <path> ]*
    Recursively restore the directory tree named by <path> to the
    security contexts specified in the file_contexts configuration.
-   Do NOT use this with paths leading to shell-writable or app-writable
-   directories, e.g. /data/local/tmp, /data/data or any prefix thereof.
 
-setcon <securitycontext>
-   Set the current process security context to the specified string.
-   This is typically only used from early-init to set the init context
-   before any other process is started.
+rm <path>
+   Calls unlink(2) on the given path. You might want to
+   use "exec -- rm ..." instead (provided the system partition is
+   already mounted).
 
-setenforce 0|1
-   Set the SELinux system-wide enforcing status.
-   0 is permissive (i.e. log but do not deny), 1 is enforcing.
-
-setkey
-   TBD
+rmdir <path>
+   Calls rmdir(2) on the given path.
 
 setprop <name> <value>
-   Set system property <name> to <value>.
+   Set system property <name> to <value>. Properties are expanded
+   within <value>.
 
 setrlimit <resource> <cur> <max>
    Set the rlimit for a resource.
 
-setsebool <name> <value>
-   Set SELinux boolean <name> to <value>.
-   <value> may be 1|true|on or 0|false|off
-
 start <service>
    Start a service running if it is not already running.
 
 stop <service>
    Stop a service from running if it is currently running.
 
+swapon_all <fstab>
+   Calls fs_mgr_swapon_all on the given fstab file.
+
 symlink <target> <path>
    Create a symbolic link at <path> with the value <target>
 
@@ -252,14 +282,23 @@
    Trigger an event.  Used to queue an action from another
    action.
 
-wait <path> [ <timeout> ]
-  Poll for the existence of the given file and return when found,
-  or the timeout has been reached. If timeout is not specified it
-  currently defaults to five seconds.
+verity_load_state
+   Internal implementation detail used to load dm-verity state.
 
-write <path> <string>
-   Open the file at <path> and write a string to it with write(2)
-   without appending.
+verity_update_state <mount_point>
+   Internal implementation detail used to update dm-verity state and
+   set the partition.<mount_point>.verified properties used by adb remount
+   because fs_mgr can't set them directly itself.
+
+wait <path> [ <timeout> ]
+   Poll for the existence of the given file and return when found,
+   or the timeout has been reached. If timeout is not specified it
+   currently defaults to five seconds.
+
+write <path> <content>
+   Open the file at <path> and write a string to it with write(2).
+   If the file does not exist, it will be created. If it does exist,
+   it will be truncated. Properties are expanded within <content>.
 
 
 Properties
@@ -267,7 +306,7 @@
 Init updates some system properties to provide some insight into
 what it's doing:
 
-init.action 
+init.action
    Equal to the name of the action currently being executed or "" if none
 
 init.command
@@ -277,73 +316,62 @@
    State of a named service ("stopped", "running", "restarting")
 
 
-Example init.conf
------------------
+Bootcharting
+------------
+This version of init contains code to perform "bootcharting": generating log
+files that can be later processed by the tools provided by www.bootchart.org.
 
-# not complete -- just providing some examples of usage
-#
-on boot
-   export PATH /sbin:/system/sbin:/system/bin
-   export LD_LIBRARY_PATH /system/lib
+On the emulator, use the -bootchart <timeout> option to boot with bootcharting
+activated for <timeout> seconds.
 
-   mkdir /dev
-   mkdir /proc
-   mkdir /sys
+On a device, create /data/bootchart/start with a command like the following:
 
-   mount tmpfs tmpfs /dev
-   mkdir /dev/pts
-   mkdir /dev/socket
-   mount devpts devpts /dev/pts
-   mount proc proc /proc
-   mount sysfs sysfs /sys
+  adb shell 'echo $TIMEOUT > /data/bootchart/start'
 
-   write /proc/cpu/alignment 4
+Where the value of $TIMEOUT corresponds to the desired bootcharted period in
+seconds. Bootcharting will stop after that many seconds have elapsed.
+You can also stop the bootcharting at any moment by doing the following:
 
-   ifup lo
+  adb shell 'echo 1 > /data/bootchart/stop'
 
-   hostname localhost
-   domainname localhost
+Note that /data/bootchart/stop is deleted automatically by init at the end of
+the bootcharting. This is not the case with /data/bootchart/start, so don't
+forget to delete it when you're done collecting data.
 
-   mount yaffs2 mtd@system /system
-   mount yaffs2 mtd@userdata /data
+The log files are written to /data/bootchart/. A script is provided to
+retrieve them and create a bootchart.tgz file that can be used with the
+bootchart command-line utility:
 
-   import /system/etc/init.conf
+  sudo apt-get install pybootchartgui
+  # grab-bootchart.sh uses $ANDROID_SERIAL.
+  $ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
 
-   class_start default
+One thing to watch for is that the bootchart will show init as if it started
+running at 0s. You'll have to look at dmesg to work out when the kernel
+actually started init.
 
-service adbd /sbin/adbd
-   user adb
-   group adb
 
-service usbd /system/bin/usbd -r
-   user usbd
-   group usbd
-   socket usbd 666
-
-service zygote /system/bin/app_process -Xzygote /system/bin --zygote
-   socket zygote 666
-
-service runtime /system/bin/runtime
-   user system
-   group system
-
-on device-added-/dev/compass
-   start akmd
-
-on device-removed-/dev/compass
-   stop akmd
-
-service akmd /sbin/akmd
-   disabled
-   user akmd
-   group akmd
-
-Debugging notes
----------------
+Debugging init
+--------------
 By default, programs executed by init will drop stdout and stderr into
 /dev/null. To help with debugging, you can execute your program via the
-Andoird program logwrapper. This will redirect stdout/stderr into the
+Android program logwrapper. This will redirect stdout/stderr into the
 Android logging system (accessed via logcat).
 
 For example
 service akmd /system/bin/logwrapper /sbin/akmd
+
+For quicker turnaround when working on init itself, use:
+
+  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/signal_handler.c b/init/signal_handler.c
deleted file mode 100644
index 7e8e1a7..0000000
--- a/init/signal_handler.c
+++ /dev/null
@@ -1,165 +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 <stdio.h>
-#include <errno.h>
-#include <signal.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
-#include <cutils/sockets.h>
-#include <cutils/android_reboot.h>
-#include <cutils/list.h>
-
-#include "init.h"
-#include "util.h"
-#include "log.h"
-
-static int signal_fd = -1;
-static int signal_recv_fd = -1;
-
-static void sigchld_handler(int s)
-{
-    write(signal_fd, &s, 1);
-}
-
-#define CRITICAL_CRASH_THRESHOLD    4       /* if we crash >4 times ... */
-#define CRITICAL_CRASH_WINDOW       (4*60)  /* ... in 4 minutes, goto recovery*/
-
-static int wait_for_one_process(int block)
-{
-    pid_t pid;
-    int status;
-    struct service *svc;
-    struct socketinfo *si;
-    time_t now;
-    struct listnode *node;
-    struct command *cmd;
-
-    while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR );
-    if (pid <= 0) return -1;
-    INFO("waitpid returned pid %d, status = %08x\n", pid, status);
-
-    svc = service_find_by_pid(pid);
-    if (!svc) {
-        if (WIFEXITED(status)) {
-            ERROR("untracked pid %d exited with status %d\n", pid, WEXITSTATUS(status));
-        } else if (WIFSIGNALED(status)) {
-            ERROR("untracked pid %d killed by signal %d\n", pid, WTERMSIG(status));
-        } else if (WIFSTOPPED(status)) {
-            ERROR("untracked pid %d stopped by signal %d\n", pid, WSTOPSIG(status));
-        } else {
-            ERROR("untracked pid %d state changed\n", pid);
-        }
-        return 0;
-    }
-
-    NOTICE("process '%s', pid %d exited\n", svc->name, pid);
-
-    if (!(svc->flags & SVC_ONESHOT) || (svc->flags & SVC_RESTART)) {
-        kill(-pid, SIGKILL);
-        NOTICE("process '%s' killing any children in process group\n", svc->name);
-    }
-
-    /* remove any sockets we may have created */
-    for (si = svc->sockets; si; si = si->next) {
-        char tmp[128];
-        snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name);
-        unlink(tmp);
-    }
-
-    svc->pid = 0;
-    svc->flags &= (~SVC_RUNNING);
-
-        /* oneshot processes go into the disabled state on exit,
-         * except when manually restarted. */
-    if ((svc->flags & SVC_ONESHOT) && !(svc->flags & SVC_RESTART)) {
-        svc->flags |= SVC_DISABLED;
-    }
-
-        /* disabled and reset processes do not get restarted automatically */
-    if (svc->flags & (SVC_DISABLED | SVC_RESET) )  {
-        notify_service_state(svc->name, "stopped");
-        return 0;
-    }
-
-    now = gettime();
-    if ((svc->flags & SVC_CRITICAL) && !(svc->flags & SVC_RESTART)) {
-        if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
-            if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
-                ERROR("critical process '%s' exited %d times in %d minutes; "
-                      "rebooting into recovery mode\n", svc->name,
-                      CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);
-                android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
-                return 0;
-            }
-        } else {
-            svc->time_crashed = now;
-            svc->nr_crashed = 1;
-        }
-    }
-
-    svc->flags &= (~SVC_RESTART);
-    svc->flags |= SVC_RESTARTING;
-
-    /* Execute all onrestart commands for this service. */
-    list_for_each(node, &svc->onrestart.commands) {
-        cmd = node_to_item(node, struct command, clist);
-        cmd->func(cmd->nargs, cmd->args);
-    }
-    notify_service_state(svc->name, "restarting");
-    return 0;
-}
-
-void handle_signal(void)
-{
-    char tmp[32];
-
-    /* we got a SIGCHLD - reap and restart as needed */
-    read(signal_recv_fd, tmp, sizeof(tmp));
-    while (!wait_for_one_process(0))
-        ;
-}
-
-void signal_init(void)
-{
-    int s[2];
-
-    struct sigaction act;
-    memset(&act, 0, sizeof(act));
-    act.sa_handler = sigchld_handler;
-    act.sa_flags = SA_NOCLDSTOP;
-    sigaction(SIGCHLD, &act, 0);
-
-    /* create a signalling mechanism for the sigchld handler */
-    if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) {
-        signal_fd = s[0];
-        signal_recv_fd = s[1];
-        fcntl(s[0], F_SETFD, FD_CLOEXEC);
-        fcntl(s[0], F_SETFL, O_NONBLOCK);
-        fcntl(s[1], F_SETFD, FD_CLOEXEC);
-        fcntl(s[1], F_SETFL, O_NONBLOCK);
-    }
-
-    handle_signal();
-}
-
-int get_signal_fd()
-{
-    return signal_recv_fd;
-}
diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp
new file mode 100644
index 0000000..39a466d
--- /dev/null
+++ b/init/signal_handler.cpp
@@ -0,0 +1,185 @@
+/*
+ * 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 <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <base/stringprintf.h>
+#include <cutils/android_reboot.h>
+#include <cutils/list.h>
+#include <cutils/sockets.h>
+
+#include "init.h"
+#include "log.h"
+#include "util.h"
+
+#define CRITICAL_CRASH_THRESHOLD    4       /* if we crash >4 times ... */
+#define CRITICAL_CRASH_WINDOW       (4*60)  /* ... in 4 minutes, goto recovery */
+
+static int signal_write_fd = -1;
+static int signal_read_fd = -1;
+
+static std::string DescribeStatus(int status) {
+    if (WIFEXITED(status)) {
+        return android::base::StringPrintf("exited with status %d", WEXITSTATUS(status));
+    } else if (WIFSIGNALED(status)) {
+        return android::base::StringPrintf("killed by signal %d", WTERMSIG(status));
+    } else if (WIFSTOPPED(status)) {
+        return android::base::StringPrintf("stopped by signal %d", WSTOPSIG(status));
+    } else {
+        return "state changed";
+    }
+}
+
+static bool wait_for_one_process() {
+    int status;
+    pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG));
+    if (pid == 0) {
+        return false;
+    } else if (pid == -1) {
+        ERROR("waitpid failed: %s\n", strerror(errno));
+        return false;
+    }
+
+    service* svc = service_find_by_pid(pid);
+
+    std::string name;
+    if (svc) {
+        name = android::base::StringPrintf("Service '%s' (pid %d)", svc->name, pid);
+    } else {
+        name = android::base::StringPrintf("Untracked pid %d", pid);
+    }
+
+    NOTICE("%s %s\n", name.c_str(), DescribeStatus(status).c_str());
+
+    if (!svc) {
+        return true;
+    }
+
+    // TODO: all the code from here down should be a member function on service.
+
+    if (!(svc->flags & SVC_ONESHOT) || (svc->flags & SVC_RESTART)) {
+        NOTICE("Service '%s' (pid %d) killing any children in process group\n", svc->name, pid);
+        kill(-pid, SIGKILL);
+    }
+
+    // Remove any sockets we may have created.
+    for (socketinfo* si = svc->sockets; si; si = si->next) {
+        char tmp[128];
+        snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name);
+        unlink(tmp);
+    }
+
+    if (svc->flags & SVC_EXEC) {
+        INFO("SVC_EXEC pid %d finished...\n", svc->pid);
+        waiting_for_exec = false;
+        list_remove(&svc->slist);
+        free(svc->name);
+        free(svc);
+        return true;
+    }
+
+    svc->pid = 0;
+    svc->flags &= (~SVC_RUNNING);
+
+    // Oneshot processes go into the disabled state on exit,
+    // except when manually restarted.
+    if ((svc->flags & SVC_ONESHOT) && !(svc->flags & SVC_RESTART)) {
+        svc->flags |= SVC_DISABLED;
+    }
+
+    // Disabled and reset processes do not get restarted automatically.
+    if (svc->flags & (SVC_DISABLED | SVC_RESET))  {
+        svc->NotifyStateChange("stopped");
+        return true;
+    }
+
+    time_t now = gettime();
+    if ((svc->flags & SVC_CRITICAL) && !(svc->flags & SVC_RESTART)) {
+        if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
+            if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
+                ERROR("critical process '%s' exited %d times in %d minutes; "
+                      "rebooting into recovery mode\n", svc->name,
+                      CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);
+                android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
+                return true;
+            }
+        } else {
+            svc->time_crashed = now;
+            svc->nr_crashed = 1;
+        }
+    }
+
+    svc->flags &= (~SVC_RESTART);
+    svc->flags |= SVC_RESTARTING;
+
+    // Execute all onrestart commands for this service.
+    struct listnode* node;
+    list_for_each(node, &svc->onrestart.commands) {
+        command* cmd = node_to_item(node, struct command, clist);
+        cmd->func(cmd->nargs, cmd->args);
+    }
+    svc->NotifyStateChange("restarting");
+    return true;
+}
+
+static void reap_any_outstanding_children() {
+    while (wait_for_one_process()) {
+    }
+}
+
+static void handle_signal() {
+    // Clear outstanding requests.
+    char buf[32];
+    read(signal_read_fd, buf, sizeof(buf));
+
+    reap_any_outstanding_children();
+}
+
+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));
+    }
+}
+
+void signal_handler_init() {
+    // 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));
+        exit(1);
+    }
+
+    signal_write_fd = s[0];
+    signal_read_fd = s[1];
+
+    // Write to signal_write_fd if we catch SIGCHLD.
+    struct sigaction act;
+    memset(&act, 0, sizeof(act));
+    act.sa_handler = SIGCHLD_handler;
+    act.sa_flags = SA_NOCLDSTOP;
+    sigaction(SIGCHLD, &act, 0);
+
+    reap_any_outstanding_children();
+
+    register_epoll_handler(signal_read_fd, handle_signal);
+}
diff --git a/init/signal_handler.h b/init/signal_handler.h
index b092ccb..449b4af 100644
--- a/init/signal_handler.h
+++ b/init/signal_handler.h
@@ -17,8 +17,6 @@
 #ifndef _INIT_SIGNAL_HANDLER_H_
 #define _INIT_SIGNAL_HANDLER_H_
 
-void signal_init(void);
-void handle_signal(void);
-int get_signal_fd(void);
+void signal_handler_init(void);
 
 #endif
diff --git a/init/ueventd.c b/init/ueventd.cpp
similarity index 74%
rename from init/ueventd.c
rename to init/ueventd.cpp
index 833e4fd..c63fdaa 100644
--- a/init/ueventd.c
+++ b/init/ueventd.cpp
@@ -14,46 +14,27 @@
  * limitations under the License.
  */
 
-#include <poll.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
 #include <ctype.h>
+#include <fcntl.h>
+#include <poll.h>
 #include <signal.h>
-#include <selinux/selinux.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
+#include <base/stringprintf.h>
 #include <private/android_filesystem_config.h>
+#include <selinux/selinux.h>
 
 #include "ueventd.h"
 #include "log.h"
 #include "util.h"
 #include "devices.h"
 #include "ueventd_parser.h"
-
-static char hardware[32];
-static unsigned revision = 0;
-
-static void import_kernel_nv(char *name, int in_qemu)
-{
-    if (*name != '\0') {
-        char *value = strchr(name, '=');
-        if (value != NULL) {
-            *value++ = 0;
-            if (!strcmp(name,"androidboot.hardware"))
-            {
-                strlcpy(hardware, value, sizeof(hardware));
-            }
-        }
-    }
-}
+#include "property_service.h"
 
 int ueventd_main(int argc, char **argv)
 {
-    struct pollfd ufd;
-    int nr;
-    char tmp[32];
-
     /*
      * init sets the umask to 077 for forked processes. We need to
      * create files with exact permissions, without modification by
@@ -70,44 +51,38 @@
 
     open_devnull_stdio();
     klog_init();
-#if LOG_UEVENTS
-    /* Ensure we're at a logging level that will show the events */
-    if (klog_get_level() < KLOG_INFO_LEVEL) {
-        klog_set_level(KLOG_INFO_LEVEL);
-    }
-#endif
+    klog_set_level(KLOG_NOTICE_LEVEL);
 
-    union selinux_callback cb;
-    cb.func_log = log_callback;
+    NOTICE("ueventd started!\n");
+
+    selinux_callback cb;
+    cb.func_log = selinux_klog_callback;
     selinux_set_callback(SELINUX_CB_LOG, cb);
 
-    INFO("starting ueventd\n");
-
-    /* Respect hardware passed in through the kernel cmd line. Here we will look
-     * for androidboot.hardware param in kernel cmdline, and save its value in
-     * hardware[]. */
-    import_kernel_cmdline(0, import_kernel_nv);
-
-    get_hardware_name(hardware, &revision);
+    char hardware[PROP_VALUE_MAX];
+    property_get("ro.hardware", hardware);
 
     ueventd_parse_config_file("/ueventd.rc");
-
-    snprintf(tmp, sizeof(tmp), "/ueventd.%s.rc", hardware);
-    ueventd_parse_config_file(tmp);
+    ueventd_parse_config_file(android::base::StringPrintf("/ueventd.%s.rc", hardware).c_str());
 
     device_init();
 
+    pollfd ufd;
     ufd.events = POLLIN;
     ufd.fd = get_device_fd();
 
-    while(1) {
+    while (true) {
         ufd.revents = 0;
-        nr = poll(&ufd, 1, -1);
-        if (nr <= 0)
+        int nr = poll(&ufd, 1, -1);
+        if (nr <= 0) {
             continue;
-        if (ufd.revents & POLLIN)
-               handle_device_fd();
+        }
+        if (ufd.revents & POLLIN) {
+            handle_device_fd();
+        }
     }
+
+    return 0;
 }
 
 static int get_android_id(const char *id)
diff --git a/init/ueventd.h b/init/ueventd.h
index 0a454c5..d12d7fe 100644
--- a/init/ueventd.h
+++ b/init/ueventd.h
@@ -20,16 +20,18 @@
 #include <cutils/list.h>
 #include <sys/types.h>
 
+enum devname_src_t {
+    DEVNAME_UNKNOWN = 0,
+    DEVNAME_UEVENT_DEVNAME,
+    DEVNAME_UEVENT_DEVPATH,
+};
+
 struct ueventd_subsystem {
     struct listnode slist;
 
     const char *name;
-    enum {
-        DEVNAME_UNKNOWN = 0,
-        DEVNAME_UEVENT_DEVNAME,
-        DEVNAME_UEVENT_DEVPATH,
-    } devname_src;
     const char *dirname;
+    devname_src_t devname_src;
 };
 
 int ueventd_main(int argc, char **argv);
diff --git a/init/ueventd_parser.c b/init/ueventd_parser.cpp
similarity index 87%
rename from init/ueventd_parser.c
rename to init/ueventd_parser.cpp
index e447006..497c606 100644
--- a/init/ueventd_parser.c
+++ b/init/ueventd_parser.cpp
@@ -67,9 +67,7 @@
     return K_UNKNOWN;
 }
 
-static void parse_line_no_op(struct parse_state *state __attribute__((unused)),
-        int nargs __attribute__((unused)), char **args  __attribute__((unused)))
-{
+static void parse_line_no_op(struct parse_state*, int, char**) {
 }
 
 static int valid_name(const char *name)
@@ -97,24 +95,20 @@
     return 0;
 }
 
-static void *parse_subsystem(struct parse_state *state,
-        int nargs __attribute__((unused)), char **args)
-{
-    struct ueventd_subsystem *s;
-
+static void *parse_subsystem(parse_state* state, int /*nargs*/, char** args) {
     if (!valid_name(args[1])) {
         parse_error(state, "invalid subsystem name '%s'\n", args[1]);
         return 0;
     }
 
-    s = ueventd_subsystem_find_by_name(args[1]);
+    ueventd_subsystem* s = ueventd_subsystem_find_by_name(args[1]);
     if (s) {
         parse_error(state, "ignored duplicate definition of subsystem '%s'\n",
                 args[1]);
         return 0;
     }
 
-    s = calloc(1, sizeof(*s));
+    s = (ueventd_subsystem*) calloc(1, sizeof(*s));
     if (!s) {
         parse_error(state, "out of memory\n");
         return 0;
@@ -128,7 +122,7 @@
 static void parse_line_subsystem(struct parse_state *state, int nargs,
         char **args)
 {
-    struct ueventd_subsystem *s = state->context;
+    struct ueventd_subsystem *s = (ueventd_subsystem*) state->context;
     int kw;
 
     if (nargs == 0) {
@@ -197,15 +191,15 @@
     }
 }
 
-static void parse_config(const char *fn, char *s)
+static void parse_config(const char *fn, const std::string& data)
 {
-    struct parse_state state;
     char *args[UEVENTD_PARSER_MAXARGS];
-    int nargs;
-    nargs = 0;
+
+    int nargs = 0;
+    parse_state state;
     state.filename = fn;
     state.line = 1;
-    state.ptr = s;
+    state.ptr = strdup(data.c_str());  // TODO: fix this code!
     state.nexttoken = 0;
     state.parse_line = parse_line_no_op;
     for (;;) {
@@ -232,17 +226,17 @@
 
 int ueventd_parse_config_file(const char *fn)
 {
-    char *data;
-    data = read_file(fn, 0);
-    if (!data) return -1;
+    std::string data;
+    if (!read_file(fn, &data)) {
+        return -1;
+    }
 
+    data.push_back('\n'); // TODO: fix parse_config.
     parse_config(fn, data);
-    DUMP();
+    dump_parser_state();
     return 0;
 }
 
-static void parse_line_device(struct parse_state *state __attribute__((unused)),
-        int nargs, char **args)
-{
+static void parse_line_device(parse_state*, int nargs, char** args) {
     set_device_permission(nargs, args);
 }
diff --git a/init/util.c b/init/util.cpp
similarity index 73%
rename from init/util.c
rename to init/util.cpp
index 12cb11d..a5392c6 100644
--- a/init/util.c
+++ b/init/util.cpp
@@ -32,8 +32,11 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 
+#include <base/file.h>
+
 /* for ANDROID_SOCKET_* */
 #include <cutils/sockets.h>
+#include <base/stringprintf.h>
 
 #include <private/android_filesystem_config.h>
 
@@ -146,48 +149,43 @@
     return -1;
 }
 
-/* reads a file, making sure it is terminated with \n \0 */
-void *read_file(const char *fn, unsigned *_sz)
-{
-    char *data;
-    int sz;
-    int fd;
+bool read_file(const char* path, std::string* content) {
+    content->clear();
+
+    int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY|O_NOFOLLOW|O_CLOEXEC));
+    if (fd == -1) {
+        return false;
+    }
+
+    // For security reasons, disallow world-writable
+    // or group-writable files.
     struct stat sb;
-
-    data = 0;
-    fd = open(fn, O_RDONLY);
-    if(fd < 0) return 0;
-
-    // for security reasons, disallow world-writable
-    // or group-writable files
-    if (fstat(fd, &sb) < 0) {
-        ERROR("fstat failed for '%s'\n", fn);
-        goto oops;
+    if (fstat(fd, &sb) == -1) {
+        ERROR("fstat failed for '%s': %s\n", path, strerror(errno));
+        return false;
     }
     if ((sb.st_mode & (S_IWGRP | S_IWOTH)) != 0) {
-        ERROR("skipping insecure file '%s'\n", fn);
-        goto oops;
+        ERROR("skipping insecure file '%s'\n", path);
+        return false;
     }
 
-    sz = lseek(fd, 0, SEEK_END);
-    if(sz < 0) goto oops;
-
-    if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
-
-    data = (char*) malloc(sz + 2);
-    if(data == 0) goto oops;
-
-    if(read(fd, data, sz) != sz) goto oops;
+    bool okay = android::base::ReadFdToString(fd, content);
     close(fd);
-    data[sz] = '\n';
-    data[sz+1] = 0;
-    if(_sz) *_sz = sz;
-    return data;
+    return okay;
+}
 
-oops:
+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));
+        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));
+    }
     close(fd);
-    if(data != 0) free(data);
-    return 0;
+    return result;
 }
 
 #define MAX_MTD_PARTITIONS 16
@@ -207,7 +205,7 @@
     ssize_t pmtdsize;
     int r;
 
-    fd = open("/proc/mtd", O_RDONLY);
+    fd = open("/proc/mtd", O_RDONLY|O_CLOEXEC);
     if (fd < 0)
         return;
 
@@ -262,22 +260,16 @@
     return -1;
 }
 
-/*
- * gettime() - returns the time in seconds of the system's monotonic clock or
- * zero on error.
- */
-time_t gettime(void)
-{
-    struct timespec ts;
-    int ret;
+time_t gettime() {
+    timespec now;
+    clock_gettime(CLOCK_MONOTONIC, &now);
+    return now.tv_sec;
+}
 
-    ret = clock_gettime(CLOCK_MONOTONIC, &ts);
-    if (ret < 0) {
-        ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno));
-        return 0;
-    }
-
-    return ts.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;
 }
 
 int mkdir_recursive(const char *pathname, mode_t mode)
@@ -374,10 +366,10 @@
 int wait_for_file(const char *filename, int timeout)
 {
     struct stat info;
-    time_t timeout_time = gettime() + timeout;
+    uint64_t timeout_time_ns = gettime_ns() + timeout * UINT64_C(1000000000);
     int ret = -1;
 
-    while (gettime() < timeout_time && ((ret = stat(filename, &info)) < 0))
+    while (gettime_ns() < timeout_time_ns && ((ret = stat(filename, &info)) < 0))
         usleep(10000);
 
     return ret;
@@ -385,101 +377,37 @@
 
 void open_devnull_stdio(void)
 {
-    int fd;
-    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 >= 0) {
-            dup2(fd, 0);
-            dup2(fd, 1);
-            dup2(fd, 2);
-            if (fd > 2) {
-                close(fd);
-            }
-            return;
+    // 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);
         }
     }
 
-    exit(1);
+    dup2(fd, 0);
+    dup2(fd, 1);
+    dup2(fd, 2);
+    if (fd > 2) {
+        close(fd);
+    }
 }
 
-void get_hardware_name(char *hardware, unsigned int *revision)
-{
-    const char *cpuinfo = "/proc/cpuinfo";
-    char *data = NULL;
-    size_t len = 0, limit = 1024;
-    int fd, n;
-    char *x, *hw, *rev;
-
-    /* Hardware string was provided on kernel command line */
-    if (hardware[0])
-        return;
-
-    fd = open(cpuinfo, O_RDONLY);
-    if (fd < 0) return;
-
-    for (;;) {
-        x = realloc(data, limit);
-        if (!x) {
-            ERROR("Failed to allocate memory to read %s\n", cpuinfo);
-            goto done;
-        }
-        data = x;
-
-        n = read(fd, data + len, limit - len);
-        if (n < 0) {
-            ERROR("Failed reading %s: %s (%d)\n", cpuinfo, strerror(errno), errno);
-            goto done;
-        }
-        len += n;
-
-        if (len < limit)
-            break;
-
-        /* We filled the buffer, so increase size and loop to read more */
-        limit *= 2;
-    }
-
-    data[len] = 0;
-    hw = strstr(data, "\nHardware");
-    rev = strstr(data, "\nRevision");
-
-    if (hw) {
-        x = strstr(hw, ": ");
-        if (x) {
-            x += 2;
-            n = 0;
-            while (*x && *x != '\n') {
-                if (!isspace(*x))
-                    hardware[n++] = tolower(*x);
-                x++;
-                if (n == 31) break;
-            }
-            hardware[n] = 0;
-        }
-    }
-
-    if (rev) {
-        x = strstr(rev, ": ");
-        if (x) {
-            *revision = strtoul(x + 2, 0, 16);
-        }
-    }
-
-done:
-    close(fd);
-    free(data);
-}
-
-void import_kernel_cmdline(int in_qemu,
-                           void (*import_kernel_nv)(char *name, int in_qemu))
+void import_kernel_cmdline(bool in_qemu, std::function<void(char*,bool)> import_kernel_nv)
 {
     char cmdline[2048];
     char *ptr;
     int fd;
 
-    fd = open("/proc/cmdline", O_RDONLY);
+    fd = open("/proc/cmdline", O_RDONLY | O_CLOEXEC);
     if (fd >= 0) {
         int n = read(fd, cmdline, sizeof(cmdline) - 1);
         if (n < 0) n = 0;
@@ -534,3 +462,13 @@
 {
     return selinux_android_restorecon(pathname, SELINUX_ANDROID_RESTORECON_RECURSE);
 }
+
+/*
+ * Writes hex_len hex characters (1/2 byte) to hex from bytes.
+ */
+std::string bytes_to_hex(const uint8_t* bytes, size_t bytes_len) {
+    std::string hex("0x");
+    for (size_t i = 0; i < bytes_len; i++)
+        android::base::StringAppendF(&hex, "%02x", bytes[i]);
+    return hex;
+}
diff --git a/init/util.h b/init/util.h
index a7e7c8b..09d64cd 100644
--- a/init/util.h
+++ b/init/util.h
@@ -20,15 +20,36 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <string>
+#include <functional>
+
 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
 
-static const char *coldboot_done = "/dev/.coldboot_done";
+#define COLDBOOT_DONE "/dev/.coldboot_done"
 
 int mtd_name_to_number(const char *name);
 int create_socket(const char *name, int type, mode_t perm,
                   uid_t uid, gid_t gid, const char *socketcon);
-void *read_file(const char *fn, unsigned *_sz);
-time_t gettime(void);
+
+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();
+
+class Timer {
+ public:
+  Timer() : t0(gettime_ns()) {
+  }
+
+  double duration() {
+    return static_cast<double>(gettime_ns() - t0) / 1000000000.0;
+  }
+
+ private:
+  uint64_t t0;
+};
+
 unsigned int decode_uid(const char *s);
 
 int mkdir_recursive(const char *pathname, mode_t mode);
@@ -37,9 +58,9 @@
 void remove_link(const char *oldpath, const char *newpath);
 int wait_for_file(const char *filename, int timeout);
 void open_devnull_stdio(void);
-void get_hardware_name(char *hardware, unsigned int *revision);
-void import_kernel_cmdline(int in_qemu, void (*import_kernel_nv)(char *name, int in_qemu));
+void import_kernel_cmdline(bool in_qemu, std::function<void(char*,bool)>);
 int make_dir(const char *path, mode_t mode);
 int restorecon(const char *pathname);
 int restorecon_recursive(const char *pathname);
+std::string bytes_to_hex(const uint8_t *bytes, size_t bytes_len);
 #endif
diff --git a/init/util_test.cpp b/init/util_test.cpp
new file mode 100644
index 0000000..5b3ab50
--- /dev/null
+++ b/init/util_test.cpp
@@ -0,0 +1,43 @@
+/*
+ * 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 "util.h"
+
+#include <errno.h>
+#include <gtest/gtest.h>
+
+TEST(util, read_file_ENOENT) {
+  std::string s("hello");
+  errno = 0;
+  EXPECT_FALSE(read_file("/proc/does-not-exist", &s));
+  EXPECT_EQ(ENOENT, errno);
+  EXPECT_EQ("", s); // s was cleared.
+}
+
+TEST(util, read_file_success) {
+  std::string s("hello");
+  EXPECT_TRUE(read_file("/proc/version", &s));
+  EXPECT_GT(s.length(), 6U);
+  EXPECT_EQ('\n', s[s.length() - 1]);
+  s[5] = 0;
+  EXPECT_STREQ("Linux", s.c_str());
+}
+
+TEST(util, decode_uid) {
+  EXPECT_EQ(0U, decode_uid("root"));
+  EXPECT_EQ(-1U, decode_uid("toot"));
+  EXPECT_EQ(123U, decode_uid("123"));
+}
diff --git a/init/watchdogd.c b/init/watchdogd.cpp
similarity index 75%
rename from init/watchdogd.c
rename to init/watchdogd.cpp
index fb53836..881a4df 100644
--- a/init/watchdogd.c
+++ b/init/watchdogd.cpp
@@ -18,6 +18,7 @@
 #include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <linux/watchdog.h>
 
@@ -26,52 +27,45 @@
 
 #define DEV_NAME "/dev/watchdog"
 
-int watchdogd_main(int argc, char **argv)
-{
-    int fd;
-    int ret;
-    int interval = 10;
-    int margin = 10;
-    int timeout;
-
+int watchdogd_main(int argc, char **argv) {
     open_devnull_stdio();
     klog_init();
+    klog_set_level(KLOG_NOTICE_LEVEL);
 
-    INFO("Starting watchdogd\n");
+    int interval = 10;
+    if (argc >= 2) interval = atoi(argv[1]);
 
-    if (argc >= 2)
-        interval = atoi(argv[1]);
+    int margin = 10;
+    if (argc >= 3) margin = atoi(argv[2]);
 
-    if (argc >= 3)
-        margin = atoi(argv[2]);
+    NOTICE("watchdogd started (interval %d, margin %d)!\n", interval, margin);
 
-    timeout = interval + margin;
-
-    fd = open(DEV_NAME, O_RDWR);
-    if (fd < 0) {
+    int fd = open(DEV_NAME, O_RDWR|O_CLOEXEC);
+    if (fd == -1) {
         ERROR("watchdogd: Failed to open %s: %s\n", DEV_NAME, strerror(errno));
         return 1;
     }
 
-    ret = ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
+    int timeout = interval + margin;
+    int ret = ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
     if (ret) {
         ERROR("watchdogd: Failed to set timeout to %d: %s\n", timeout, strerror(errno));
         ret = ioctl(fd, WDIOC_GETTIMEOUT, &timeout);
         if (ret) {
             ERROR("watchdogd: Failed to get timeout: %s\n", strerror(errno));
         } else {
-            if (timeout > margin)
+            if (timeout > margin) {
                 interval = timeout - margin;
-            else
+            } else {
                 interval = 1;
+            }
             ERROR("watchdogd: Adjusted interval to timeout returned by driver: timeout %d, interval %d, margin %d\n",
                   timeout, interval, margin);
         }
     }
 
-    while(1) {
+    while (true) {
         write(fd, "", 1);
         sleep(interval);
     }
 }
-
diff --git a/libbacktrace/Android.build.mk b/libbacktrace/Android.build.mk
index 2f55645..35fed6d 100644
--- a/libbacktrace/Android.build.mk
+++ b/libbacktrace/Android.build.mk
@@ -19,28 +19,37 @@
 LOCAL_MODULE := $(module)
 LOCAL_MODULE_TAGS := $(module_tag)
 LOCAL_MULTILIB := $($(module)_multilib)
+ifeq ($(LOCAL_MULTILIB),both)
+ifneq ($(build_target),$(filter $(build_target),SHARED_LIBRARY STATIC_LIBRRARY))
+  LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+  LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+endif
+endif
 
 LOCAL_ADDITIONAL_DEPENDENCIES := \
     $(LOCAL_PATH)/Android.mk \
     $(LOCAL_PATH)/Android.build.mk \
 
 LOCAL_CFLAGS := \
-    $(common_cflags) \
+    $(libbacktrace_common_cflags) \
     $($(module)_cflags) \
     $($(module)_cflags_$(build_type)) \
 
+LOCAL_CLANG_CFLAGS += \
+    $(libbacktrace_common_clang_cflags) \
+
 LOCAL_CONLYFLAGS += \
-    $(common_conlyflags) \
+    $(libbacktrace_common_conlyflags) \
     $($(module)_conlyflags) \
     $($(module)_conlyflags_$(build_type)) \
 
 LOCAL_CPPFLAGS += \
-    $(common_cppflags) \
+    $(libbacktrace_common_cppflags) \
     $($(module)_cppflags) \
     $($(module)_cppflags_$(build_type)) \
 
 LOCAL_C_INCLUDES := \
-    $(common_c_includes) \
+    $(libbacktrace_common_c_includes) \
     $($(module)_c_includes) \
     $($(module)_c_includes_$(build_type)) \
 
@@ -61,21 +70,13 @@
     $($(module)_ldlibs_$(build_type)) \
 
 ifeq ($(build_type),target)
-  ifneq ($($(module)_libc++),)
-    include external/libcxx/libcxx.mk
-  else
-    include external/stlport/libstlport.mk
-  endif
-
   include $(BUILD_$(build_target))
 endif
 
 ifeq ($(build_type),host)
   # Only build if host builds are supported.
   ifeq ($(build_host),true)
-    ifneq ($($(module)_libc++),)
-      include external/libcxx/libcxx.mk
-    endif
+    LOCAL_CFLAGS += -Wno-extern-c-compat -fno-omit-frame-pointer
     include $(BUILD_HOST_$(build_target))
   endif
 endif
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
old mode 100755
new mode 100644
index 9588dd6..6a689a6
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -16,16 +16,20 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-common_cflags := \
+libbacktrace_common_cflags := \
 	-Wall \
 	-Werror \
 
-common_conlyflags := \
+libbacktrace_common_conlyflags := \
 	-std=gnu99 \
 
-common_cppflags := \
+libbacktrace_common_cppflags := \
 	-std=gnu++11 \
 
+# The latest clang (r230699) does not allow SP/PC to be declared in inline asm lists.
+libbacktrace_common_clang_cflags += \
+    -Wno-inline-asm
+
 build_host := false
 ifeq ($(HOST_OS),linux)
 ifeq ($(HOST_ARCH),$(filter $(HOST_ARCH),x86 x86_64))
@@ -37,26 +41,22 @@
 # The libbacktrace library.
 #-------------------------------------------------------------------------
 libbacktrace_src_files := \
-	BacktraceImpl.cpp \
+	Backtrace.cpp \
+	BacktraceCurrent.cpp \
 	BacktraceMap.cpp \
-	BacktraceThread.cpp \
+	BacktracePtrace.cpp \
 	thread_utils.c \
-
-libbacktrace_shared_libraries_target := \
-	libcutils \
-	libgccdemangle \
-
-libbacktrace_src_files += \
+	ThreadEntry.cpp \
 	UnwindCurrent.cpp \
 	UnwindMap.cpp \
 	UnwindPtrace.cpp \
 
-libbacktrace_c_includes := \
-	external/libunwind/include \
+libbacktrace_shared_libraries_target := \
+	libcutils \
 
 libbacktrace_shared_libraries := \
+	libbase \
 	libunwind \
-	libunwind-ptrace \
 
 libbacktrace_shared_libraries_host := \
 	liblog \
@@ -74,58 +74,9 @@
 build_target := SHARED_LIBRARY
 include $(LOCAL_PATH)/Android.build.mk
 build_type := host
+libbacktrace_multilib := both
 include $(LOCAL_PATH)/Android.build.mk
 
-# Don't build for unbundled branches
-ifeq (,$(TARGET_BUILD_APPS))
-#-------------------------------------------------------------------------
-# The libbacktrace library (libc++)
-#-------------------------------------------------------------------------
-libbacktrace_libc++_src_files := \
-	BacktraceImpl.cpp \
-	BacktraceMap.cpp \
-	BacktraceThread.cpp \
-	thread_utils.c \
-
-libbacktrace_libc++_shared_libraries_target := \
-	libcutils \
-	libgccdemangle \
-
-libbacktrace_libc++_src_files += \
-	UnwindCurrent.cpp \
-	UnwindMap.cpp \
-	UnwindPtrace.cpp \
-
-libbacktrace_libc++_c_includes := \
-	external/libunwind/include \
-
-libbacktrace_libc++_shared_libraries := \
-	libunwind \
-	libunwind-ptrace \
-
-libbacktrace_libc++_shared_libraries_host := \
-	liblog \
-
-libbacktrace_libc++_static_libraries_host := \
-	libcutils \
-
-libbacktrace_libc++_ldlibs_host := \
-	-lpthread \
-	-lrt \
-
-libbacktrace_libc++_libc++ := true
-
-module := libbacktrace_libc++
-module_tag := optional
-build_type := target
-build_target := SHARED_LIBRARY
-include $(LOCAL_PATH)/Android.build.mk
-build_type := host
-libbacktrace_libc++_multilib := both
-include $(LOCAL_PATH)/Android.build.mk
-libbacktrace_libc++_multilib :=
-endif
-
 #-------------------------------------------------------------------------
 # The libbacktrace_test library needed by backtrace_test.
 #-------------------------------------------------------------------------
@@ -139,6 +90,7 @@
 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
@@ -166,17 +118,20 @@
 backtrace_test_shared_libraries := \
 	libbacktrace_test \
 	libbacktrace \
-
-backtrace_test_shared_libraries_target := \
+	libbase \
 	libcutils \
 
-backtrace_test_static_libraries_host := \
-	libcutils \
+backtrace_test_shared_libraries_target += \
+	libdl \
+
+backtrace_test_ldlibs_host += \
+	-ldl \
 
 module := backtrace_test
 module_tag := debug
 build_type := target
 build_target := NATIVE_TEST
+backtrace_test_multilib := both
 include $(LOCAL_PATH)/Android.build.mk
 build_type := host
 include $(LOCAL_PATH)/Android.build.mk
@@ -194,25 +149,8 @@
 LOCAL_SRC_FILES := \
 	BacktraceMap.cpp \
 
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-# Don't build for unbundled branches
-ifeq (,$(TARGET_BUILD_APPS))
-#-------------------------------------------------------------------------
-# The libbacktrace library (libc++)
-#-------------------------------------------------------------------------
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libbacktrace_libc++
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := \
-	BacktraceMap.cpp \
-
 LOCAL_MULTILIB := both
 
 include $(BUILD_HOST_SHARED_LIBRARY)
 
-endif # TARGET_BUILD_APPS
-
 endif # HOST_OS-darwin
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
new file mode 100644
index 0000000..42769ed
--- /dev/null
+++ b/libbacktrace/Backtrace.cpp
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <ucontext.h>
+
+#include <string>
+
+#include <base/stringprintf.h>
+
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+
+#include <cutils/threads.h>
+
+#include "BacktraceLog.h"
+#include "thread_utils.h"
+#include "UnwindCurrent.h"
+#include "UnwindPtrace.h"
+
+using android::base::StringPrintf;
+
+//-------------------------------------------------------------------------
+// Backtrace functions.
+//-------------------------------------------------------------------------
+Backtrace::Backtrace(pid_t pid, pid_t tid, BacktraceMap* map)
+    : pid_(pid), tid_(tid), map_(map), map_shared_(true) {
+  if (map_ == nullptr) {
+    map_ = BacktraceMap::Create(pid);
+    map_shared_ = false;
+  }
+}
+
+Backtrace::~Backtrace() {
+  if (map_ && !map_shared_) {
+    delete map_;
+    map_ = nullptr;
+  }
+}
+
+std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
+  std::string func_name = GetFunctionNameRaw(pc, offset);
+  return func_name;
+}
+
+bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, word_t* out_value) {
+  if (ptr & (sizeof(word_t)-1)) {
+    BACK_LOGW("invalid pointer %p", reinterpret_cast<void*>(ptr));
+    *out_value = static_cast<word_t>(-1);
+    return false;
+  }
+  return true;
+}
+
+std::string Backtrace::FormatFrameData(size_t frame_num) {
+  if (frame_num >= frames_.size()) {
+    return "";
+  }
+  return FormatFrameData(&frames_[frame_num]);
+}
+
+std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) {
+  const char* map_name;
+  if (BacktraceMap::IsValid(frame->map) && !frame->map.name.empty()) {
+    map_name = frame->map.name.c_str();
+  } else {
+    map_name = "<unknown>";
+  }
+
+  uintptr_t relative_pc = BacktraceMap::GetRelativePc(frame->map, frame->pc);
+
+  std::string line(StringPrintf("#%02zu pc %" PRIPTR "  %s", frame->num, relative_pc, map_name));
+  // Special handling for non-zero offset maps, we need to print that
+  // information.
+  if (frame->map.offset != 0) {
+    line += " (offset " + StringPrintf("0x%" PRIxPTR, frame->map.offset) + ")";
+  }
+  if (!frame->func_name.empty()) {
+    line += " (" + frame->func_name;
+    if (frame->func_offset) {
+      line += StringPrintf("+%" PRIuPTR, frame->func_offset);
+    }
+    line += ')';
+  }
+
+  return line;
+}
+
+void Backtrace::FillInMap(uintptr_t pc, backtrace_map_t* map) {
+  if (map_ != nullptr) {
+    map_->FillIn(pc, map);
+  }
+}
+
+Backtrace* Backtrace::Create(pid_t pid, pid_t tid, BacktraceMap* map) {
+  if (pid == BACKTRACE_CURRENT_PROCESS) {
+    pid = getpid();
+    if (tid == BACKTRACE_CURRENT_THREAD) {
+      tid = gettid();
+    }
+  } else if (tid == BACKTRACE_CURRENT_THREAD) {
+    tid = pid;
+  }
+
+  if (pid == getpid()) {
+    return new UnwindCurrent(pid, tid, map);
+  } else {
+    return new UnwindPtrace(pid, tid, map);
+  }
+}
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
new file mode 100644
index 0000000..2714d93
--- /dev/null
+++ b/libbacktrace/BacktraceCurrent.cpp
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ */
+
+#define _GNU_SOURCE 1
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <ucontext.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+
+#include <cutils/threads.h>
+
+#include "BacktraceCurrent.h"
+#include "BacktraceLog.h"
+#include "ThreadEntry.h"
+#include "thread_utils.h"
+
+bool BacktraceCurrent::ReadWord(uintptr_t ptr, word_t* out_value) {
+  if (!VerifyReadWordArgs(ptr, out_value)) {
+    return false;
+  }
+
+  backtrace_map_t map;
+  FillInMap(ptr, &map);
+  if (BacktraceMap::IsValid(map) && map.flags & PROT_READ) {
+    *out_value = *reinterpret_cast<word_t*>(ptr);
+    return true;
+  } else {
+    BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr));
+    *out_value = static_cast<word_t>(-1);
+    return false;
+  }
+}
+
+size_t BacktraceCurrent::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
+  backtrace_map_t map;
+  FillInMap(addr, &map);
+  if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
+    return 0;
+  }
+  bytes = MIN(map.end - addr, bytes);
+  memcpy(buffer, reinterpret_cast<uint8_t*>(addr), bytes);
+  return bytes;
+}
+
+bool BacktraceCurrent::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
+  if (GetMap() == nullptr) {
+    // Without a map object, we can't do anything.
+    return false;
+  }
+
+  if (ucontext) {
+    return UnwindFromContext(num_ignore_frames, ucontext);
+  }
+
+  if (Tid() != gettid()) {
+    return UnwindThread(num_ignore_frames);
+  }
+
+  return UnwindFromContext(num_ignore_frames, nullptr);
+}
+
+bool BacktraceCurrent::DiscardFrame(const backtrace_frame_data_t& frame) {
+  if (BacktraceMap::IsValid(frame.map)) {
+    const std::string library = basename(frame.map.name.c_str());
+    if (library == "libunwind.so" || library == "libbacktrace.so") {
+      return true;
+    }
+  }
+  return false;
+}
+
+static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void SignalHandler(int, siginfo_t*, void* sigcontext) {
+  ThreadEntry* entry = ThreadEntry::Get(getpid(), gettid(), false);
+  if (!entry) {
+    BACK_LOGE("pid %d, tid %d entry not found", getpid(), gettid());
+    return;
+  }
+
+  entry->CopyUcontextFromSigcontext(sigcontext);
+
+  // Indicate the ucontext is now valid.
+  entry->Wake();
+
+  // Pause the thread until the unwind is complete. This avoids having
+  // the thread run ahead causing problems.
+  // The number indicates that we are waiting for the second Wake() call
+  // overall which is made by the thread requesting an unwind.
+  if (entry->Wait(2)) {
+    // Do not remove the entry here because that can result in a deadlock
+    // if the code cannot properly send a signal to the thread under test.
+    entry->Wake();
+  } else {
+    // At this point, it is possible that entry has been freed, so just exit.
+    BACK_LOGE("Timed out waiting for unwind thread to indicate it completed.");
+  }
+}
+
+bool BacktraceCurrent::UnwindThread(size_t num_ignore_frames) {
+  // Prevent multiple threads trying to set the trigger action on different
+  // threads at the same time.
+  pthread_mutex_lock(&g_sigaction_mutex);
+
+  ThreadEntry* entry = ThreadEntry::Get(Pid(), Tid());
+  entry->Lock();
+
+  struct sigaction act, oldact;
+  memset(&act, 0, sizeof(act));
+  act.sa_sigaction = SignalHandler;
+  act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
+  sigemptyset(&act.sa_mask);
+  if (sigaction(THREAD_SIGNAL, &act, &oldact) != 0) {
+    BACK_LOGE("sigaction failed: %s", strerror(errno));
+    ThreadEntry::Remove(entry);
+    pthread_mutex_unlock(&g_sigaction_mutex);
+    return false;
+  }
+
+  if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) {
+    BACK_LOGE("tgkill %d failed: %s", Tid(), strerror(errno));
+    sigaction(THREAD_SIGNAL, &oldact, nullptr);
+    ThreadEntry::Remove(entry);
+    pthread_mutex_unlock(&g_sigaction_mutex);
+    return false;
+  }
+
+  // Wait for the thread to get the ucontext. The number indicates
+  // that we are waiting for the first Wake() call made by the thread.
+  bool wait_completed = entry->Wait(1);
+
+  // After the thread has received the signal, allow other unwinders to
+  // continue.
+  sigaction(THREAD_SIGNAL, &oldact, nullptr);
+  pthread_mutex_unlock(&g_sigaction_mutex);
+
+  bool unwind_done = false;
+  if (wait_completed) {
+    unwind_done = UnwindFromContext(num_ignore_frames, entry->GetUcontext());
+
+    // Tell the signal handler to exit and release the entry.
+    entry->Wake();
+
+    // Wait for the thread to indicate it is done with the ThreadEntry.
+    if (!entry->Wait(3)) {
+      // Send a warning, but do not mark as a failure to unwind.
+      BACK_LOGW("Timed out waiting for signal handler to indicate it finished.");
+    }
+  } else {
+    BACK_LOGE("Timed out waiting for signal handler to get ucontext data.");
+  }
+
+  ThreadEntry::Remove(entry);
+
+  return unwind_done;
+}
diff --git a/libbacktrace/BacktraceCurrent.h b/libbacktrace/BacktraceCurrent.h
new file mode 100644
index 0000000..8aad36d
--- /dev/null
+++ b/libbacktrace/BacktraceCurrent.h
@@ -0,0 +1,58 @@
+/*
+ * 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 _LIBBACKTRACE_BACKTRACE_CURRENT_H
+#define _LIBBACKTRACE_BACKTRACE_CURRENT_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <ucontext.h>
+
+#include <backtrace/Backtrace.h>
+
+// The signal used to cause a thread to dump the stack.
+#if defined(__GLIBC__)
+// In order to run the backtrace_tests on the host, we can't use
+// the internal real time signals used by GLIBC. To avoid this,
+// use SIGRTMIN for the signal to dump the stack.
+#define THREAD_SIGNAL SIGRTMIN
+#else
+#define THREAD_SIGNAL (__SIGRTMIN+1)
+#endif
+
+class BacktraceMap;
+
+class BacktraceCurrent : public Backtrace {
+public:
+  BacktraceCurrent(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {}
+  virtual ~BacktraceCurrent() {}
+
+  size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) override;
+
+  bool ReadWord(uintptr_t ptr, word_t* out_value) override;
+
+  bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) override;
+
+protected:
+  bool DiscardFrame(const backtrace_frame_data_t& frame);
+
+private:
+  bool UnwindThread(size_t num_ignore_frames);
+
+  virtual bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) = 0;
+};
+
+#endif // _LIBBACKTRACE_BACKTRACE_CURRENT_H
diff --git a/libbacktrace/BacktraceImpl.cpp b/libbacktrace/BacktraceImpl.cpp
deleted file mode 100644
index 4693600..0000000
--- a/libbacktrace/BacktraceImpl.cpp
+++ /dev/null
@@ -1,191 +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.
- */
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ptrace.h>
-#include <sys/types.h>
-#include <ucontext.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-
-#include "BacktraceImpl.h"
-#include "BacktraceLog.h"
-#include "thread_utils.h"
-
-//-------------------------------------------------------------------------
-// Backtrace functions.
-//-------------------------------------------------------------------------
-Backtrace::Backtrace(BacktraceImpl* impl, pid_t pid, BacktraceMap* map)
-    : pid_(pid), tid_(-1), map_(map), map_shared_(true), impl_(impl) {
-  impl_->SetParent(this);
-
-  if (map_ == NULL) {
-    map_ = BacktraceMap::Create(pid);
-    map_shared_ = false;
-  }
-}
-
-Backtrace::~Backtrace() {
-  if (impl_) {
-    delete impl_;
-    impl_ = NULL;
-  }
-
-  if (map_ && !map_shared_) {
-    delete map_;
-    map_ = NULL;
-  }
-}
-
-bool Backtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
-  return impl_->Unwind(num_ignore_frames, ucontext);
-}
-
-std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
-  std::string func_name = impl_->GetFunctionNameRaw(pc, offset);
-  return func_name;
-}
-
-bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, word_t* out_value) {
-  if (ptr & (sizeof(word_t)-1)) {
-    BACK_LOGW("invalid pointer %p", (void*)ptr);
-    *out_value = (word_t)-1;
-    return false;
-  }
-  return true;
-}
-
-std::string Backtrace::FormatFrameData(size_t frame_num) {
-  if (frame_num >= frames_.size()) {
-    return "";
-  }
-  return FormatFrameData(&frames_[frame_num]);
-}
-
-std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) {
-  const char* map_name;
-  if (frame->map && !frame->map->name.empty()) {
-    map_name = frame->map->name.c_str();
-  } else {
-    map_name = "<unknown>";
-  }
-
-  uintptr_t relative_pc;
-  if (frame->map) {
-    relative_pc = frame->pc - frame->map->start;
-  } else {
-    relative_pc = frame->pc;
-  }
-
-  char buf[512];
-  if (!frame->func_name.empty() && frame->func_offset) {
-    snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR "  %s (%s+%" PRIuPTR ")",
-             frame->num, (int)sizeof(uintptr_t)*2, relative_pc, map_name,
-             frame->func_name.c_str(), frame->func_offset);
-  } else if (!frame->func_name.empty()) {
-    snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR "  %s (%s)", frame->num,
-             (int)sizeof(uintptr_t)*2, relative_pc, map_name, frame->func_name.c_str());
-  } else {
-    snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR "  %s", frame->num,
-             (int)sizeof(uintptr_t)*2, relative_pc, map_name);
-  }
-
-  return buf;
-}
-
-const backtrace_map_t* Backtrace::FindMap(uintptr_t pc) {
-  return map_->Find(pc);
-}
-
-//-------------------------------------------------------------------------
-// BacktraceCurrent functions.
-//-------------------------------------------------------------------------
-BacktraceCurrent::BacktraceCurrent(
-    BacktraceImpl* impl, BacktraceMap* map) : Backtrace(impl, getpid(), map) {
-}
-
-BacktraceCurrent::~BacktraceCurrent() {
-}
-
-bool BacktraceCurrent::ReadWord(uintptr_t ptr, word_t* out_value) {
-  if (!VerifyReadWordArgs(ptr, out_value)) {
-    return false;
-  }
-
-  const backtrace_map_t* map = FindMap(ptr);
-  if (map && map->flags & PROT_READ) {
-    *out_value = *reinterpret_cast<word_t*>(ptr);
-    return true;
-  } else {
-    BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr));
-    *out_value = static_cast<word_t>(-1);
-    return false;
-  }
-}
-
-//-------------------------------------------------------------------------
-// BacktracePtrace functions.
-//-------------------------------------------------------------------------
-BacktracePtrace::BacktracePtrace(
-    BacktraceImpl* impl, pid_t pid, pid_t tid, BacktraceMap* map)
-    : Backtrace(impl, pid, map) {
-  tid_ = tid;
-}
-
-BacktracePtrace::~BacktracePtrace() {
-}
-
-bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) {
-  if (!VerifyReadWordArgs(ptr, out_value)) {
-    return false;
-  }
-
-#if defined(__APPLE__)
-  BACK_LOGW("MacOS does not support reading from another pid.");
-  return false;
-#else
-  // ptrace() returns -1 and sets errno when the operation fails.
-  // To disambiguate -1 from a valid result, we clear errno beforehand.
-  errno = 0;
-  *out_value = ptrace(PTRACE_PEEKTEXT, Tid(), reinterpret_cast<void*>(ptr), NULL);
-  if (*out_value == static_cast<word_t>(-1) && errno) {
-    BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s",
-              reinterpret_cast<void*>(ptr), Tid(), strerror(errno));
-    return false;
-  }
-  return true;
-#endif
-}
-
-Backtrace* Backtrace::Create(pid_t pid, pid_t tid, BacktraceMap* map) {
-  if (pid == BACKTRACE_CURRENT_PROCESS || pid == getpid()) {
-    if (tid == BACKTRACE_CURRENT_THREAD || tid == gettid()) {
-      return CreateCurrentObj(map);
-    } else {
-      return CreateThreadObj(tid, map);
-    }
-  } else if (tid == BACKTRACE_CURRENT_THREAD) {
-    return CreatePtraceObj(pid, pid, map);
-  } else {
-    return CreatePtraceObj(pid, tid, map);
-  }
-}
diff --git a/libbacktrace/BacktraceImpl.h b/libbacktrace/BacktraceImpl.h
deleted file mode 100755
index d34ad05..0000000
--- a/libbacktrace/BacktraceImpl.h
+++ /dev/null
@@ -1,74 +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 _LIBBACKTRACE_BACKTRACE_IMPL_H
-#define _LIBBACKTRACE_BACKTRACE_IMPL_H
-
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-
-#include <sys/types.h>
-
-class BacktraceImpl {
-public:
-  virtual ~BacktraceImpl() { }
-
-  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) = 0;
-
-  // The name returned is not demangled, Backtrace::GetFunctionName()
-  // takes care of demangling the name.
-  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) = 0;
-
-  void SetParent(Backtrace* backtrace) { backtrace_obj_ = backtrace; }
-
-  inline pid_t Pid() { return backtrace_obj_->Pid(); }
-  inline pid_t Tid() { return backtrace_obj_->Tid(); }
-
-  inline const backtrace_map_t* FindMap(uintptr_t addr) {
-    return backtrace_obj_->FindMap(addr);
-  }
-  inline std::string GetFunctionName(uintptr_t pc, uintptr_t* offset) {
-    return backtrace_obj_->GetFunctionName(pc, offset);
-  }
-  inline BacktraceMap* GetMap() { return backtrace_obj_->GetMap(); }
-
-protected:
-  inline std::vector<backtrace_frame_data_t>* GetFrames() { return &backtrace_obj_->frames_; }
-
-  Backtrace* backtrace_obj_;
-};
-
-class BacktraceCurrent : public Backtrace {
-public:
-  BacktraceCurrent(BacktraceImpl* impl, BacktraceMap* map);
-  virtual ~BacktraceCurrent();
-
-  bool ReadWord(uintptr_t ptr, word_t* out_value);
-};
-
-class BacktracePtrace : public Backtrace {
-public:
-  BacktracePtrace(BacktraceImpl* impl, pid_t pid, pid_t tid, BacktraceMap* map);
-  virtual ~BacktracePtrace();
-
-  bool ReadWord(uintptr_t ptr, word_t* out_value);
-};
-
-Backtrace* CreateCurrentObj(BacktraceMap* map);
-Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, BacktraceMap* map);
-Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map);
-
-#endif // _LIBBACKTRACE_BACKTRACE_IMPL_H
diff --git a/libbacktrace/BacktraceLog.h b/libbacktrace/BacktraceLog.h
old mode 100755
new mode 100644
index 1632ec2..5c39f1c
--- a/libbacktrace/BacktraceLog.h
+++ b/libbacktrace/BacktraceLog.h
@@ -25,4 +25,7 @@
 #define BACK_LOGW(format, ...) \
   ALOGW("%s: " format, __PRETTY_FUNCTION__, ##__VA_ARGS__)
 
+#define BACK_LOGE(format, ...) \
+  ALOGE("%s: " format, __PRETTY_FUNCTION__, ##__VA_ARGS__)
+
 #endif // _LIBBACKTRACE_BACKTRACE_LOG_H
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index f38e484..b0ada46 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -15,18 +15,15 @@
  */
 
 #include <ctype.h>
+#include <stdint.h>
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <string>
-#include <vector>
-
 #include <backtrace/backtrace_constants.h>
 #include <backtrace/BacktraceMap.h>
 #include <log/log.h>
 
 #include "thread_utils.h"
-#include "BacktraceImpl.h"
 
 BacktraceMap::BacktraceMap(pid_t pid) : pid_(pid) {
   if (pid_ < 0) {
@@ -37,14 +34,15 @@
 BacktraceMap::~BacktraceMap() {
 }
 
-const backtrace_map_t* BacktraceMap::Find(uintptr_t addr) {
+void BacktraceMap::FillIn(uintptr_t addr, backtrace_map_t* map) {
   for (BacktraceMap::const_iterator it = begin();
        it != end(); ++it) {
     if (addr >= it->start && addr < it->end) {
-      return &*it;
+      *map = *it;
+      return;
     }
   }
-  return NULL;
+  *map = {};
 }
 
 bool BacktraceMap::ParseLine(const char* line, backtrace_map_t* map) {
@@ -115,7 +113,7 @@
   snprintf(path, sizeof(path), "/proc/%d/maps", pid_);
   FILE* fp = fopen(path, "r");
 #endif
-  if (fp == NULL) {
+  if (fp == nullptr) {
     return false;
   }
 
@@ -141,7 +139,7 @@
   BacktraceMap* map = new BacktraceMap(pid);
   if (!map->Build()) {
     delete map;
-    return NULL;
+    return nullptr;
   }
   return map;
 }
diff --git a/libbacktrace/BacktracePtrace.cpp b/libbacktrace/BacktracePtrace.cpp
new file mode 100644
index 0000000..fd8b713
--- /dev/null
+++ b/libbacktrace/BacktracePtrace.cpp
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <ucontext.h>
+#include <unistd.h>
+
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+
+#include "BacktraceLog.h"
+#include "BacktracePtrace.h"
+#include "thread_utils.h"
+
+#if !defined(__APPLE__)
+static bool PtraceRead(pid_t tid, uintptr_t addr, word_t* out_value) {
+  // ptrace() returns -1 and sets errno when the operation fails.
+  // To disambiguate -1 from a valid result, we clear errno beforehand.
+  errno = 0;
+  *out_value = ptrace(PTRACE_PEEKTEXT, tid, reinterpret_cast<void*>(addr), nullptr);
+  if (*out_value == static_cast<word_t>(-1) && errno) {
+    return false;
+  }
+  return true;
+}
+#endif
+
+bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) {
+#if defined(__APPLE__)
+  BACK_LOGW("MacOS does not support reading from another pid.");
+  return false;
+#else
+  if (!VerifyReadWordArgs(ptr, out_value)) {
+    return false;
+  }
+
+  backtrace_map_t map;
+  FillInMap(ptr, &map);
+  if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
+    return false;
+  }
+
+  return PtraceRead(Tid(), ptr, out_value);
+#endif
+}
+
+size_t BacktracePtrace::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
+#if defined(__APPLE__)
+  BACK_LOGW("MacOS does not support reading from another pid.");
+  return 0;
+#else
+  backtrace_map_t map;
+  FillInMap(addr, &map);
+  if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
+    return 0;
+  }
+
+  bytes = MIN(map.end - addr, bytes);
+  size_t bytes_read = 0;
+  word_t data_word;
+  size_t align_bytes = addr & (sizeof(word_t) - 1);
+  if (align_bytes != 0) {
+    if (!PtraceRead(Tid(), addr & ~(sizeof(word_t) - 1), &data_word)) {
+      return 0;
+    }
+    size_t copy_bytes = MIN(sizeof(word_t) - align_bytes, bytes);
+    memcpy(buffer, reinterpret_cast<uint8_t*>(&data_word) + align_bytes, copy_bytes);
+    addr += copy_bytes;
+    buffer += copy_bytes;
+    bytes -= copy_bytes;
+    bytes_read += copy_bytes;
+  }
+
+  size_t num_words = bytes / sizeof(word_t);
+  for (size_t i = 0; i < num_words; i++) {
+    if (!PtraceRead(Tid(), addr, &data_word)) {
+      return bytes_read;
+    }
+    memcpy(buffer, &data_word, sizeof(word_t));
+    buffer += sizeof(word_t);
+    addr += sizeof(word_t);
+    bytes_read += sizeof(word_t);
+  }
+
+  size_t left_over = bytes & (sizeof(word_t) - 1);
+  if (left_over) {
+    if (!PtraceRead(Tid(), addr, &data_word)) {
+      return bytes_read;
+    }
+    memcpy(buffer, &data_word, left_over);
+    bytes_read += left_over;
+  }
+  return bytes_read;
+#endif
+}
diff --git a/libbacktrace/BacktracePtrace.h b/libbacktrace/BacktracePtrace.h
new file mode 100644
index 0000000..1d49811
--- /dev/null
+++ b/libbacktrace/BacktracePtrace.h
@@ -0,0 +1,37 @@
+/*
+ * 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 _LIBBACKTRACE_BACKTRACE_PTRACE_H
+#define _LIBBACKTRACE_BACKTRACE_PTRACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <backtrace/Backtrace.h>
+
+class BacktraceMap;
+
+class BacktracePtrace : public Backtrace {
+public:
+  BacktracePtrace(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {}
+  virtual ~BacktracePtrace() {}
+
+  size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes);
+
+  bool ReadWord(uintptr_t ptr, word_t* out_value);
+};
+
+#endif // _LIBBACKTRACE_BACKTRACE_PTRACE_H
diff --git a/libbacktrace/BacktraceThread.cpp b/libbacktrace/BacktraceThread.cpp
deleted file mode 100644
index 439cc3b..0000000
--- a/libbacktrace/BacktraceThread.cpp
+++ /dev/null
@@ -1,227 +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.
- */
-
-#include <errno.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <pthread.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/syscall.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <ucontext.h>
-#include <unistd.h>
-
-#include <cutils/atomic.h>
-
-#include "BacktraceLog.h"
-#include "BacktraceThread.h"
-#include "thread_utils.h"
-
-//-------------------------------------------------------------------------
-// ThreadEntry implementation.
-//-------------------------------------------------------------------------
-ThreadEntry* ThreadEntry::list_ = NULL;
-pthread_mutex_t ThreadEntry::list_mutex_ = PTHREAD_MUTEX_INITIALIZER;
-
-// Assumes that ThreadEntry::list_mutex_ has already been locked before
-// creating a ThreadEntry object.
-ThreadEntry::ThreadEntry(pid_t pid, pid_t tid)
-    : pid_(pid), tid_(tid), ref_count_(1), mutex_(PTHREAD_MUTEX_INITIALIZER),
-      wait_mutex_(PTHREAD_MUTEX_INITIALIZER), wait_value_(0),
-      next_(ThreadEntry::list_), prev_(NULL) {
-  pthread_condattr_t attr;
-  pthread_condattr_init(&attr);
-  pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
-  pthread_cond_init(&wait_cond_, &attr);
-
-  // Add ourselves to the list.
-  if (ThreadEntry::list_) {
-    ThreadEntry::list_->prev_ = this;
-  }
-  ThreadEntry::list_ = this;
-}
-
-ThreadEntry* ThreadEntry::Get(pid_t pid, pid_t tid, bool create) {
-  pthread_mutex_lock(&ThreadEntry::list_mutex_);
-  ThreadEntry* entry = list_;
-  while (entry != NULL) {
-    if (entry->Match(pid, tid)) {
-      break;
-    }
-    entry = entry->next_;
-  }
-
-  if (!entry) {
-    if (create) {
-      entry = new ThreadEntry(pid, tid);
-    }
-  } else {
-    entry->ref_count_++;
-  }
-  pthread_mutex_unlock(&ThreadEntry::list_mutex_);
-
-  return entry;
-}
-
-void ThreadEntry::Remove(ThreadEntry* entry) {
-  pthread_mutex_unlock(&entry->mutex_);
-
-  pthread_mutex_lock(&ThreadEntry::list_mutex_);
-  if (--entry->ref_count_ == 0) {
-    delete entry;
-  }
-  pthread_mutex_unlock(&ThreadEntry::list_mutex_);
-}
-
-// Assumes that ThreadEntry::list_mutex_ has already been locked before
-// deleting a ThreadEntry object.
-ThreadEntry::~ThreadEntry() {
-  if (list_ == this) {
-    list_ = next_;
-  } else {
-    if (next_) {
-      next_->prev_ = prev_;
-    }
-    prev_->next_ = next_;
-  }
-
-  next_ = NULL;
-  prev_ = NULL;
-
-  pthread_cond_destroy(&wait_cond_);
-}
-
-void ThreadEntry::Wait(int value) {
-  timespec ts;
-  if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
-    BACK_LOGW("clock_gettime failed: %s", strerror(errno));
-    abort();
-  }
-  ts.tv_sec += 10;
-
-  pthread_mutex_lock(&wait_mutex_);
-  while (wait_value_ != value) {
-    int ret = pthread_cond_timedwait(&wait_cond_, &wait_mutex_, &ts);
-    if (ret != 0) {
-      BACK_LOGW("pthread_cond_timedwait failed: %s", strerror(ret));
-      break;
-    }
-  }
-  pthread_mutex_unlock(&wait_mutex_);
-}
-
-void ThreadEntry::Wake() {
-  pthread_mutex_lock(&wait_mutex_);
-  wait_value_++;
-  pthread_mutex_unlock(&wait_mutex_);
-
-  pthread_cond_signal(&wait_cond_);
-}
-
-void ThreadEntry::CopyUcontextFromSigcontext(void* sigcontext) {
-  ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(sigcontext);
-  // The only thing the unwinder cares about is the mcontext data.
-  memcpy(&ucontext_.uc_mcontext, &ucontext->uc_mcontext, sizeof(ucontext->uc_mcontext));
-}
-
-//-------------------------------------------------------------------------
-// BacktraceThread functions.
-//-------------------------------------------------------------------------
-static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void SignalHandler(int, siginfo_t*, void* sigcontext) {
-  ThreadEntry* entry = ThreadEntry::Get(getpid(), gettid(), false);
-  if (!entry) {
-    BACK_LOGW("Unable to find pid %d tid %d information", getpid(), gettid());
-    return;
-  }
-
-  entry->CopyUcontextFromSigcontext(sigcontext);
-
-  // Indicate the ucontext is now valid.
-  entry->Wake();
-
-  // Pause the thread until the unwind is complete. This avoids having
-  // the thread run ahead causing problems.
-  entry->Wait(2);
-
-  ThreadEntry::Remove(entry);
-}
-
-BacktraceThread::BacktraceThread(BacktraceImpl* impl, pid_t tid, BacktraceMap* map)
-    : BacktraceCurrent(impl, map) {
-  tid_ = tid;
-}
-
-BacktraceThread::~BacktraceThread() {
-}
-
-bool BacktraceThread::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
-  if (ucontext) {
-    // Unwind using an already existing ucontext.
-    return impl_->Unwind(num_ignore_frames, ucontext);
-  }
-
-  // Prevent multiple threads trying to set the trigger action on different
-  // threads at the same time.
-  if (pthread_mutex_lock(&g_sigaction_mutex) < 0) {
-    BACK_LOGW("sigaction failed: %s", strerror(errno));
-    return false;
-  }
-
-  ThreadEntry* entry = ThreadEntry::Get(Pid(), Tid());
-  entry->Lock();
-
-  struct sigaction act, oldact;
-  memset(&act, 0, sizeof(act));
-  act.sa_sigaction = SignalHandler;
-  act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
-  sigemptyset(&act.sa_mask);
-  if (sigaction(THREAD_SIGNAL, &act, &oldact) != 0) {
-    BACK_LOGW("sigaction failed %s", strerror(errno));
-    entry->Unlock();
-    ThreadEntry::Remove(entry);
-    pthread_mutex_unlock(&g_sigaction_mutex);
-    return false;
-  }
-
-  if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) {
-    BACK_LOGW("tgkill %d failed: %s", Tid(), strerror(errno));
-    sigaction(THREAD_SIGNAL, &oldact, NULL);
-    entry->Unlock();
-    ThreadEntry::Remove(entry);
-    pthread_mutex_unlock(&g_sigaction_mutex);
-    return false;
-  }
-
-  // Wait for the thread to get the ucontext.
-  entry->Wait(1);
-
-  // After the thread has received the signal, allow other unwinders to
-  // continue.
-  sigaction(THREAD_SIGNAL, &oldact, NULL);
-  pthread_mutex_unlock(&g_sigaction_mutex);
-
-  bool unwind_done = impl_->Unwind(num_ignore_frames, entry->GetUcontext());
-
-  // Tell the signal handler to exit and release the entry.
-  entry->Wake();
-
-  return unwind_done;
-}
diff --git a/libbacktrace/GetPss.cpp b/libbacktrace/GetPss.cpp
index 442383b..09a721d 100644
--- a/libbacktrace/GetPss.cpp
+++ b/libbacktrace/GetPss.cpp
@@ -14,11 +14,10 @@
  * limitations under the License.
  */
 
-#include <assert.h>
 #include <inttypes.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdint.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -46,13 +45,22 @@
 
 size_t GetPssBytes() {
   FILE* maps = fopen("/proc/self/maps", "r");
-  assert(maps != NULL);
+  if (maps == nullptr) {
+    return 0;
+  }
 
   int pagecount_fd = open("/proc/kpagecount", O_RDONLY);
-  assert(pagecount_fd >= 0);
+  if (pagecount_fd == -1) {
+    fclose(maps);
+    return 0;
+  }
 
   int pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
-  assert(pagemap_fd >= 0);
+  if (pagemap_fd == -1) {
+    fclose(maps);
+    close(pagecount_fd);
+    return 0;
+  }
 
   char line[4096];
   size_t total_pss = 0;
diff --git a/libbacktrace/ThreadEntry.cpp b/libbacktrace/ThreadEntry.cpp
new file mode 100644
index 0000000..084c1aa
--- /dev/null
+++ b/libbacktrace/ThreadEntry.cpp
@@ -0,0 +1,131 @@
+/*
+ * 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 <pthread.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+#include <ucontext.h>
+
+#include "BacktraceLog.h"
+#include "ThreadEntry.h"
+
+// Initialize static member variables.
+ThreadEntry* ThreadEntry::list_ = nullptr;
+pthread_mutex_t ThreadEntry::list_mutex_ = PTHREAD_MUTEX_INITIALIZER;
+
+// Assumes that ThreadEntry::list_mutex_ has already been locked before
+// creating a ThreadEntry object.
+ThreadEntry::ThreadEntry(pid_t pid, pid_t tid)
+    : pid_(pid), tid_(tid), ref_count_(1), mutex_(PTHREAD_MUTEX_INITIALIZER),
+      wait_mutex_(PTHREAD_MUTEX_INITIALIZER), wait_value_(0),
+      next_(ThreadEntry::list_), prev_(nullptr) {
+  pthread_condattr_t attr;
+  pthread_condattr_init(&attr);
+  pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
+  pthread_cond_init(&wait_cond_, &attr);
+
+  // Add ourselves to the list.
+  if (ThreadEntry::list_) {
+    ThreadEntry::list_->prev_ = this;
+  }
+  ThreadEntry::list_ = this;
+}
+
+ThreadEntry* ThreadEntry::Get(pid_t pid, pid_t tid, bool create) {
+  pthread_mutex_lock(&ThreadEntry::list_mutex_);
+  ThreadEntry* entry = list_;
+  while (entry != nullptr) {
+    if (entry->Match(pid, tid)) {
+      break;
+    }
+    entry = entry->next_;
+  }
+
+  if (!entry) {
+    if (create) {
+      entry = new ThreadEntry(pid, tid);
+    }
+  } else {
+    entry->ref_count_++;
+  }
+  pthread_mutex_unlock(&ThreadEntry::list_mutex_);
+
+  return entry;
+}
+
+void ThreadEntry::Remove(ThreadEntry* entry) {
+  entry->Unlock();
+
+  pthread_mutex_lock(&ThreadEntry::list_mutex_);
+  if (--entry->ref_count_ == 0) {
+    delete entry;
+  }
+  pthread_mutex_unlock(&ThreadEntry::list_mutex_);
+}
+
+// Assumes that ThreadEntry::list_mutex_ has already been locked before
+// deleting a ThreadEntry object.
+ThreadEntry::~ThreadEntry() {
+  if (list_ == this) {
+    list_ = next_;
+  } else {
+    if (next_) {
+      next_->prev_ = prev_;
+    }
+    prev_->next_ = next_;
+  }
+
+  next_ = nullptr;
+  prev_ = nullptr;
+
+  pthread_cond_destroy(&wait_cond_);
+}
+
+bool ThreadEntry::Wait(int value) {
+  timespec ts;
+  clock_gettime(CLOCK_MONOTONIC, &ts);
+  ts.tv_sec += 5;
+
+  bool wait_completed = true;
+  pthread_mutex_lock(&wait_mutex_);
+  while (wait_value_ != value) {
+    int ret = pthread_cond_timedwait(&wait_cond_, &wait_mutex_, &ts);
+    if (ret != 0) {
+      BACK_LOGW("pthread_cond_timedwait for value %d failed: %s", value, strerror(ret));
+      wait_completed = false;
+      break;
+    }
+  }
+  pthread_mutex_unlock(&wait_mutex_);
+
+  return wait_completed;
+}
+
+void ThreadEntry::Wake() {
+  pthread_mutex_lock(&wait_mutex_);
+  wait_value_++;
+  pthread_mutex_unlock(&wait_mutex_);
+
+  pthread_cond_signal(&wait_cond_);
+}
+
+void ThreadEntry::CopyUcontextFromSigcontext(void* sigcontext) {
+  ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(sigcontext);
+  // The only thing the unwinder cares about is the mcontext data.
+  memcpy(&ucontext_.uc_mcontext, &ucontext->uc_mcontext, sizeof(ucontext->uc_mcontext));
+}
diff --git a/libbacktrace/BacktraceThread.h b/libbacktrace/ThreadEntry.h
similarity index 70%
rename from libbacktrace/BacktraceThread.h
rename to libbacktrace/ThreadEntry.h
index 99a8638..11924a3 100644
--- a/libbacktrace/BacktraceThread.h
+++ b/libbacktrace/ThreadEntry.h
@@ -14,26 +14,13 @@
  * limitations under the License.
  */
 
-#ifndef _LIBBACKTRACE_BACKTRACE_THREAD_H
-#define _LIBBACKTRACE_BACKTRACE_THREAD_H
+#ifndef _LIBBACKTRACE_THREAD_ENTRY_H
+#define _LIBBACKTRACE_THREAD_ENTRY_H
 
-#include <inttypes.h>
 #include <pthread.h>
-#include <signal.h>
-#include <string.h>
 #include <sys/types.h>
 #include <ucontext.h>
 
-#include "BacktraceImpl.h"
-
-// The signal used to cause a thread to dump the stack.
-#if defined(__GLIBC__)
-// GLIBC reserves __SIGRTMIN signals, so use SIGRTMIN to avoid errors.
-#define THREAD_SIGNAL SIGRTMIN
-#else
-#define THREAD_SIGNAL (__SIGRTMIN+1)
-#endif
-
 class ThreadEntry {
 public:
   static ThreadEntry* Get(pid_t pid, pid_t tid, bool create = true);
@@ -42,7 +29,7 @@
 
   void Wake();
 
-  void Wait(int);
+  bool Wait(int);
 
   void CopyUcontextFromSigcontext(void*);
 
@@ -81,12 +68,4 @@
   static pthread_mutex_t list_mutex_;
 };
 
-class BacktraceThread : public BacktraceCurrent {
-public:
-  BacktraceThread(BacktraceImpl* impl, pid_t tid, BacktraceMap* map);
-  virtual ~BacktraceThread();
-
-  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext);
-};
-
-#endif // _LIBBACKTRACE_BACKTRACE_THREAD_H
+#endif // _LIBBACKTRACE_THREAD_ENTRY_H
diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp
old mode 100755
new mode 100644
index b176aaf..67e583f
--- a/libbacktrace/UnwindCurrent.cpp
+++ b/libbacktrace/UnwindCurrent.cpp
@@ -14,41 +14,30 @@
  * limitations under the License.
  */
 
-#include <sys/types.h>
+#include <stdint.h>
 #include <ucontext.h>
 
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
+#include <memory>
+#include <string>
 
 #define UNW_LOCAL_ONLY
 #include <libunwind.h>
 
+#include <backtrace/Backtrace.h>
+
 #include "BacktraceLog.h"
-#include "BacktraceThread.h"
 #include "UnwindCurrent.h"
-#include "UnwindMap.h"
 
-//-------------------------------------------------------------------------
-// UnwindCurrent functions.
-//-------------------------------------------------------------------------
-UnwindCurrent::UnwindCurrent() {
-}
-
-UnwindCurrent::~UnwindCurrent() {
-}
-
-bool UnwindCurrent::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
-  if (!ucontext) {
-    int ret = unw_getcontext(&context_);
-    if (ret < 0) {
-      BACK_LOGW("unw_getcontext failed %d", ret);
-      return false;
-    }
+std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+  *offset = 0;
+  char buf[512];
+  unw_word_t value;
+  if (unw_get_proc_name_by_ip(unw_local_addr_space, pc, buf, sizeof(buf),
+                              &value, &context_) >= 0 && buf[0] != '\0') {
+    *offset = static_cast<uintptr_t>(value);
+    return buf;
   }
-  else {
-    GetUnwContextFromUcontext(ucontext);
-  }
-  return UnwindFromContext(num_ignore_frames, false);
+  return "";
 }
 
 void UnwindCurrent::GetUnwContextFromUcontext(const ucontext_t* ucontext) {
@@ -76,90 +65,67 @@
 #endif
 }
 
-std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
-  *offset = 0;
-  char buf[512];
-  unw_word_t value;
-  if (unw_get_proc_name_by_ip(unw_local_addr_space, pc, buf, sizeof(buf),
-                              &value, &context_) >= 0 && buf[0] != '\0') {
-    *offset = static_cast<uintptr_t>(value);
-    return buf;
-  }
-  return "";
-}
-
-bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool within_handler) {
-  // The cursor structure is pretty large, do not put it on the stack.
-  unw_cursor_t* cursor = new unw_cursor_t;
-  int ret = unw_init_local(cursor, &context_);
-  if (ret < 0) {
-    if (!within_handler) {
-      BACK_LOGW("unw_init_local failed %d", ret);
+bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) {
+  if (ucontext == nullptr) {
+    int ret = unw_getcontext(&context_);
+    if (ret < 0) {
+      BACK_LOGW("unw_getcontext failed %d", ret);
+      return false;
     }
-    delete cursor;
+  } else {
+    GetUnwContextFromUcontext(ucontext);
+  }
+
+  // The cursor structure is pretty large, do not put it on the stack.
+  std::unique_ptr<unw_cursor_t> cursor(new unw_cursor_t);
+  int ret = unw_init_local(cursor.get(), &context_);
+  if (ret < 0) {
+    BACK_LOGW("unw_init_local failed %d", ret);
     return false;
   }
 
-  std::vector<backtrace_frame_data_t>* frames = GetFrames();
-  frames->reserve(MAX_BACKTRACE_FRAMES);
   size_t num_frames = 0;
   do {
     unw_word_t pc;
-    ret = unw_get_reg(cursor, UNW_REG_IP, &pc);
+    ret = unw_get_reg(cursor.get(), UNW_REG_IP, &pc);
     if (ret < 0) {
-      if (!within_handler) {
-        BACK_LOGW("Failed to read IP %d", ret);
-      }
+      BACK_LOGW("Failed to read IP %d", ret);
       break;
     }
     unw_word_t sp;
-    ret = unw_get_reg(cursor, UNW_REG_SP, &sp);
+    ret = unw_get_reg(cursor.get(), UNW_REG_SP, &sp);
     if (ret < 0) {
-      if (!within_handler) {
-        BACK_LOGW("Failed to read SP %d", ret);
-      }
+      BACK_LOGW("Failed to read SP %d", ret);
       break;
     }
 
-    if (num_ignore_frames == 0) {
-      frames->resize(num_frames+1);
-      backtrace_frame_data_t* frame = &frames->at(num_frames);
-      frame->num = num_frames;
-      frame->pc = static_cast<uintptr_t>(pc);
-      frame->sp = static_cast<uintptr_t>(sp);
-      frame->stack_size = 0;
+    frames_.resize(num_frames+1);
+    backtrace_frame_data_t* frame = &frames_.at(num_frames);
+    frame->num = num_frames;
+    frame->pc = static_cast<uintptr_t>(pc);
+    frame->sp = static_cast<uintptr_t>(sp);
+    frame->stack_size = 0;
 
-      if (num_frames > 0) {
-        // Set the stack size for the previous frame.
-        backtrace_frame_data_t* prev = &frames->at(num_frames-1);
-        prev->stack_size = frame->sp - prev->sp;
-      }
-
-      if (!within_handler) {
+    FillInMap(frame->pc, &frame->map);
+    // Check to see if we should skip this frame because it's coming
+    // from within the library, and we are doing a local unwind.
+    if (ucontext != nullptr || num_frames != 0 || !DiscardFrame(*frame)) {
+      if (num_ignore_frames == 0) {
+        // GetFunctionName is an expensive call, only do it if we are
+        // keeping the frame.
         frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
-        frame->map = FindMap(frame->pc);
+        if (num_frames > 0) {
+          // Set the stack size for the previous frame.
+          backtrace_frame_data_t* prev = &frames_.at(num_frames-1);
+          prev->stack_size = frame->sp - prev->sp;
+        }
+        num_frames++;
       } else {
-        frame->map = NULL;
-        frame->func_offset = 0;
+        num_ignore_frames--;
       }
-      num_frames++;
-    } else {
-      num_ignore_frames--;
     }
-    ret = unw_step (cursor);
+    ret = unw_step (cursor.get());
   } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);
 
-  delete cursor;
   return true;
 }
-
-//-------------------------------------------------------------------------
-// C++ object creation function.
-//-------------------------------------------------------------------------
-Backtrace* CreateCurrentObj(BacktraceMap* map) {
-  return new BacktraceCurrent(new UnwindCurrent(), map);
-}
-
-Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map) {
-  return new BacktraceThread(new UnwindCurrent(), tid, map);
-}
diff --git a/libbacktrace/UnwindCurrent.h b/libbacktrace/UnwindCurrent.h
index 2375e6e..3023996 100644
--- a/libbacktrace/UnwindCurrent.h
+++ b/libbacktrace/UnwindCurrent.h
@@ -17,27 +17,32 @@
 #ifndef _LIBBACKTRACE_UNWIND_CURRENT_H
 #define _LIBBACKTRACE_UNWIND_CURRENT_H
 
+#include <stdint.h>
+#include <sys/types.h>
+#include <ucontext.h>
+
 #include <string>
 
-#include "BacktraceImpl.h"
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+
+#include "BacktraceCurrent.h"
 
 #define UNW_LOCAL_ONLY
 #include <libunwind.h>
 
-class UnwindCurrent : public BacktraceImpl {
+class UnwindCurrent : public BacktraceCurrent {
 public:
-  UnwindCurrent();
-  virtual ~UnwindCurrent();
+  UnwindCurrent(pid_t pid, pid_t tid, BacktraceMap* map) : BacktraceCurrent(pid, tid, map) {}
+  virtual ~UnwindCurrent() {}
 
-  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext);
+  std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;
 
-  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+private:
+  void GetUnwContextFromUcontext(const ucontext_t* ucontext);
 
-  bool UnwindFromContext(size_t num_ignore_frames, bool within_handler);
+  bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) override;
 
-  void GetUnwContextFromUcontext(const ucontext_t* context);
-
-protected:
   unw_context_t context_;
 };
 
diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp
index 387d768..879fea5 100644
--- a/libbacktrace/UnwindMap.cpp
+++ b/libbacktrace/UnwindMap.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <pthread.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -51,6 +51,8 @@
 
     map.start = unw_map.start;
     map.end = unw_map.end;
+    map.offset = unw_map.offset;
+    map.load_base = unw_map.load_base;
     map.flags = unw_map.flags;
     map.name = unw_map.path;
 
@@ -91,6 +93,8 @@
 
       map.start = unw_map.start;
       map.end = unw_map.end;
+      map.offset = unw_map.offset;
+      map.load_base = unw_map.load_base;
       map.flags = unw_map.flags;
       map.name = unw_map.path;
 
@@ -113,18 +117,17 @@
   return (map_created_ = (unw_map_local_create() == 0)) && GenerateMap();;
 }
 
-const backtrace_map_t* UnwindMapLocal::Find(uintptr_t addr) {
-  const backtrace_map_t* map = BacktraceMap::Find(addr);
-  if (!map) {
+void UnwindMapLocal::FillIn(uintptr_t addr, backtrace_map_t* map) {
+  BacktraceMap::FillIn(addr, map);
+  if (!IsValid(*map)) {
     // Check to see if the underlying map changed and regenerate the map
     // if it did.
     if (unw_map_local_cursor_valid(&map_cursor_) < 0) {
       if (GenerateMap()) {
-        map = BacktraceMap::Find(addr);
+        BacktraceMap::FillIn(addr, map);
       }
     }
   }
-  return map;
 }
 
 //-------------------------------------------------------------------------
@@ -143,7 +146,7 @@
   }
   if (!map->Build()) {
     delete map;
-    return NULL;
+    return nullptr;
   }
   return map;
 }
diff --git a/libbacktrace/UnwindMap.h b/libbacktrace/UnwindMap.h
index 2fdb29f..e292016 100644
--- a/libbacktrace/UnwindMap.h
+++ b/libbacktrace/UnwindMap.h
@@ -17,6 +17,9 @@
 #ifndef _LIBBACKTRACE_UNWIND_MAP_H
 #define _LIBBACKTRACE_UNWIND_MAP_H
 
+#include <stdint.h>
+#include <sys/types.h>
+
 #include <backtrace/BacktraceMap.h>
 
 // The unw_map_cursor_t structure is different depending on whether it is
@@ -45,7 +48,7 @@
 
   virtual bool Build();
 
-  virtual const backtrace_map_t* Find(uintptr_t addr);
+  virtual void FillIn(uintptr_t addr, backtrace_map_t* map);
 
 protected:
   virtual bool GenerateMap();
diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp
index 7ba8775..07c2430 100644
--- a/libbacktrace/UnwindPtrace.cpp
+++ b/libbacktrace/UnwindPtrace.cpp
@@ -14,39 +14,45 @@
  * limitations under the License.
  */
 
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-
+#include <stdint.h>
 #include <sys/types.h>
-#include <string.h>
 #include <ucontext.h>
 
 #include <libunwind.h>
 #include <libunwind-ptrace.h>
 
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+
 #include "BacktraceLog.h"
 #include "UnwindMap.h"
 #include "UnwindPtrace.h"
 
-UnwindPtrace::UnwindPtrace() : addr_space_(NULL), upt_info_(NULL) {
+UnwindPtrace::UnwindPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
+    : BacktracePtrace(pid, tid, map), addr_space_(nullptr), upt_info_(nullptr) {
 }
 
 UnwindPtrace::~UnwindPtrace() {
   if (upt_info_) {
     _UPT_destroy(upt_info_);
-    upt_info_ = NULL;
+    upt_info_ = nullptr;
   }
   if (addr_space_) {
     // Remove the map from the address space before destroying it.
     // It will be freed in the UnwindMap destructor.
-    unw_map_set(addr_space_, NULL);
+    unw_map_set(addr_space_, nullptr);
 
     unw_destroy_addr_space(addr_space_);
-    addr_space_ = NULL;
+    addr_space_ = nullptr;
   }
 }
 
 bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
+  if (GetMap() == nullptr) {
+    // Without a map object, we can't do anything.
+    return false;
+  }
+
   if (ucontext) {
     BACK_LOGW("Unwinding from a specified context not supported yet.");
     return false;
@@ -74,8 +80,6 @@
     return false;
   }
 
-  std::vector<backtrace_frame_data_t>* frames = GetFrames();
-  frames->reserve(MAX_BACKTRACE_FRAMES);
   size_t num_frames = 0;
   do {
     unw_word_t pc;
@@ -92,21 +96,21 @@
     }
 
     if (num_ignore_frames == 0) {
-      frames->resize(num_frames+1);
-      backtrace_frame_data_t* frame = &frames->at(num_frames);
+      frames_.resize(num_frames+1);
+      backtrace_frame_data_t* frame = &frames_.at(num_frames);
       frame->num = num_frames;
       frame->pc = static_cast<uintptr_t>(pc);
       frame->sp = static_cast<uintptr_t>(sp);
       frame->stack_size = 0;
 
       if (num_frames > 0) {
-        backtrace_frame_data_t* prev = &frames->at(num_frames-1);
+        backtrace_frame_data_t* prev = &frames_.at(num_frames-1);
         prev->stack_size = frame->sp - prev->sp;
       }
 
       frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
 
-      frame->map = FindMap(frame->pc);
+      FillInMap(frame->pc, &frame->map);
 
       num_frames++;
     } else {
@@ -129,10 +133,3 @@
   }
   return "";
 }
-
-//-------------------------------------------------------------------------
-// C++ object creation function.
-//-------------------------------------------------------------------------
-Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, BacktraceMap* map) {
-  return new BacktracePtrace(new UnwindPtrace(), pid, tid, map);
-}
diff --git a/libbacktrace/UnwindPtrace.h b/libbacktrace/UnwindPtrace.h
index 2fb7967..ab04abf 100644
--- a/libbacktrace/UnwindPtrace.h
+++ b/libbacktrace/UnwindPtrace.h
@@ -17,20 +17,26 @@
 #ifndef _LIBBACKTRACE_UNWIND_PTRACE_H
 #define _LIBBACKTRACE_UNWIND_PTRACE_H
 
+#include <stdint.h>
+#include <sys/types.h>
+
 #include <string>
 
-#include "BacktraceImpl.h"
-
+#ifdef UNW_LOCAL_ONLY
+#undef UNW_LOCAL_ONLY
+#endif
 #include <libunwind.h>
 
-class UnwindPtrace : public BacktraceImpl {
+#include "BacktracePtrace.h"
+
+class UnwindPtrace : public BacktracePtrace {
 public:
-  UnwindPtrace();
+  UnwindPtrace(pid_t pid, pid_t tid, BacktraceMap* map);
   virtual ~UnwindPtrace();
 
-  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext);
+  bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) override;
 
-  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+  std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;
 
 private:
   unw_addr_space_t addr_space_;
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 8002ed6..c650755 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -14,8 +14,11 @@
  * limitations under the License.
  */
 
+#define _GNU_SOURCE 1
 #include <dirent.h>
+#include <dlfcn.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <inttypes.h>
 #include <pthread.h>
 #include <signal.h>
@@ -24,24 +27,29 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/ptrace.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <time.h>
 #include <unistd.h>
 
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-#include <UniquePtr.h>
-
-// For the THREAD_SIGNAL definition.
-#include "BacktraceThread.h"
-
-#include <cutils/atomic.h>
-#include <gtest/gtest.h>
-
 #include <algorithm>
+#include <list>
+#include <memory>
+#include <string>
 #include <vector>
 
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+
+#include <base/stringprintf.h>
+#include <cutils/atomic.h>
+#include <cutils/threads.h>
+
+#include <gtest/gtest.h>
+
+// For the THREAD_SIGNAL definition.
+#include "BacktraceCurrent.h"
 #include "thread_utils.h"
 
 // Number of microseconds per milliseconds.
@@ -60,6 +68,7 @@
   pid_t tid;
   int32_t state;
   pthread_t threadId;
+  void* data;
 };
 
 struct dump_thread_t {
@@ -82,15 +91,16 @@
   return static_cast<uint64_t>(t.tv_sec * NS_PER_SEC + t.tv_nsec);
 }
 
-void DumpFrames(Backtrace* backtrace) {
+std::string DumpFrames(Backtrace* backtrace) {
   if (backtrace->NumFrames() == 0) {
-    printf("    No frames to dump\n");
-    return;
+    return "   No frames to dump.\n";
   }
 
+  std::string frame;
   for (size_t i = 0; i < backtrace->NumFrames(); i++) {
-    printf("    %s\n", backtrace->FormatFrameData(i).c_str());
+    frame += "   " + backtrace->FormatFrameData(i) + '\n';
   }
+  return frame;
 }
 
 void WaitForStop(pid_t pid) {
@@ -120,8 +130,10 @@
 }
 
 void VerifyLevelDump(Backtrace* backtrace) {
-  ASSERT_GT(backtrace->NumFrames(), static_cast<size_t>(0));
-  ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES));
+  ASSERT_GT(backtrace->NumFrames(), static_cast<size_t>(0))
+    << DumpFrames(backtrace);
+  ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES))
+    << DumpFrames(backtrace);
 
   // Look through the frames starting at the highest to find the
   // frame we want.
@@ -132,19 +144,23 @@
       break;
     }
   }
-  ASSERT_LT(static_cast<size_t>(0), frame_num);
-  ASSERT_LE(static_cast<size_t>(3), frame_num);
+  ASSERT_LT(static_cast<size_t>(0), frame_num) << DumpFrames(backtrace);
+  ASSERT_LE(static_cast<size_t>(3), frame_num) << DumpFrames(backtrace);
 
-  ASSERT_EQ(backtrace->GetFrame(frame_num)->func_name, "test_level_one");
-  ASSERT_EQ(backtrace->GetFrame(frame_num-1)->func_name, "test_level_two");
-  ASSERT_EQ(backtrace->GetFrame(frame_num-2)->func_name, "test_level_three");
-  ASSERT_EQ(backtrace->GetFrame(frame_num-3)->func_name, "test_level_four");
+  ASSERT_EQ(backtrace->GetFrame(frame_num)->func_name, "test_level_one")
+    << DumpFrames(backtrace);
+  ASSERT_EQ(backtrace->GetFrame(frame_num-1)->func_name, "test_level_two")
+    << DumpFrames(backtrace);
+  ASSERT_EQ(backtrace->GetFrame(frame_num-2)->func_name, "test_level_three")
+    << DumpFrames(backtrace);
+  ASSERT_EQ(backtrace->GetFrame(frame_num-3)->func_name, "test_level_four")
+    << DumpFrames(backtrace);
 }
 
 void VerifyLevelBacktrace(void*) {
-  UniquePtr<Backtrace> backtrace(
+  std::unique_ptr<Backtrace> backtrace(
       Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
-  ASSERT_TRUE(backtrace.get() != NULL);
+  ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
 
   VerifyLevelDump(backtrace.get());
@@ -155,16 +171,17 @@
 }
 
 void VerifyMaxDump(Backtrace* backtrace) {
-  ASSERT_EQ(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES));
+  ASSERT_EQ(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES))
+    << DumpFrames(backtrace);
   // Verify that the last frame is our recursive call.
-  ASSERT_EQ(backtrace->GetFrame(MAX_BACKTRACE_FRAMES-1)->func_name,
-            "test_recursive_call");
+  ASSERT_EQ(backtrace->GetFrame(MAX_BACKTRACE_FRAMES-1)->func_name, "test_recursive_call")
+    << DumpFrames(backtrace);
 }
 
 void VerifyMaxBacktrace(void*) {
-  UniquePtr<Backtrace> backtrace(
+  std::unique_ptr<Backtrace> backtrace(
       Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
-  ASSERT_TRUE(backtrace.get() != NULL);
+  ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
 
   VerifyMaxDump(backtrace.get());
@@ -180,8 +197,8 @@
 }
 
 void VerifyThreadTest(pid_t tid, void (*VerifyFunc)(Backtrace*)) {
-  UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), tid));
-  ASSERT_TRUE(backtrace.get() != NULL);
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), tid));
+  ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
 
   VerifyFunc(backtrace.get());
@@ -197,18 +214,38 @@
   return false;
 }
 
+TEST(libbacktrace, local_no_unwind_frames) {
+  // Verify that a local unwind does not include any frames within
+  // libunwind or libbacktrace.
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), getpid()));
+  ASSERT_TRUE(backtrace.get() != nullptr);
+  ASSERT_TRUE(backtrace->Unwind(0));
+
+  ASSERT_TRUE(backtrace->NumFrames() != 0);
+  for (const auto& frame : *backtrace ) {
+    if (BacktraceMap::IsValid(frame.map)) {
+      const std::string name = basename(frame.map.name.c_str());
+      ASSERT_TRUE(name != "libunwind.so" && name != "libbacktrace.so")
+        << DumpFrames(backtrace.get());
+    }
+    break;
+  }
+}
+
 TEST(libbacktrace, local_trace) {
-  ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelBacktrace, NULL), 0);
+  ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelBacktrace, nullptr), 0);
 }
 
 void VerifyIgnoreFrames(
     Backtrace* bt_all, Backtrace* bt_ign1,
     Backtrace* bt_ign2, const char* cur_proc) {
-  EXPECT_EQ(bt_all->NumFrames(), bt_ign1->NumFrames() + 1);
-  EXPECT_EQ(bt_all->NumFrames(), bt_ign2->NumFrames() + 2);
+  EXPECT_EQ(bt_all->NumFrames(), bt_ign1->NumFrames() + 1)
+    << "All backtrace:\n" << DumpFrames(bt_all) << "Ignore 1 backtrace:\n" << DumpFrames(bt_ign1);
+  EXPECT_EQ(bt_all->NumFrames(), bt_ign2->NumFrames() + 2)
+    << "All backtrace:\n" << DumpFrames(bt_all) << "Ignore 2 backtrace:\n" << DumpFrames(bt_ign2);
 
   // Check all of the frames are the same > the current frame.
-  bool check = (cur_proc == NULL);
+  bool check = (cur_proc == nullptr);
   for (size_t i = 0; i < bt_ign2->NumFrames(); i++) {
     if (check) {
       EXPECT_EQ(bt_ign2->GetFrame(i)->pc, bt_ign1->GetFrame(i+1)->pc);
@@ -226,30 +263,30 @@
 }
 
 void VerifyLevelIgnoreFrames(void*) {
-  UniquePtr<Backtrace> all(
+  std::unique_ptr<Backtrace> all(
       Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
-  ASSERT_TRUE(all.get() != NULL);
+  ASSERT_TRUE(all.get() != nullptr);
   ASSERT_TRUE(all->Unwind(0));
 
-  UniquePtr<Backtrace> ign1(
+  std::unique_ptr<Backtrace> ign1(
       Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
-  ASSERT_TRUE(ign1.get() != NULL);
+  ASSERT_TRUE(ign1.get() != nullptr);
   ASSERT_TRUE(ign1->Unwind(1));
 
-  UniquePtr<Backtrace> ign2(
+  std::unique_ptr<Backtrace> ign2(
       Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
-  ASSERT_TRUE(ign2.get() != NULL);
+  ASSERT_TRUE(ign2.get() != nullptr);
   ASSERT_TRUE(ign2->Unwind(2));
 
   VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), "VerifyLevelIgnoreFrames");
 }
 
 TEST(libbacktrace, local_trace_ignore_frames) {
-  ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelIgnoreFrames, NULL), 0);
+  ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelIgnoreFrames, nullptr), 0);
 }
 
 TEST(libbacktrace, local_max_trace) {
-  ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxBacktrace, NULL), 0);
+  ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxBacktrace, nullptr), 0);
 }
 
 void VerifyProcTest(pid_t pid, pid_t tid, bool share_map,
@@ -263,35 +300,38 @@
   }
   uint64_t start = NanoTime();
   bool verified = false;
+  std::string last_dump;
   do {
     usleep(US_PER_MSEC);
     if (ptrace(PTRACE_ATTACH, ptrace_tid, 0, 0) == 0) {
       // Wait for the process to get to a stopping point.
       WaitForStop(ptrace_tid);
 
-      UniquePtr<BacktraceMap> map;
+      std::unique_ptr<BacktraceMap> map;
       if (share_map) {
         map.reset(BacktraceMap::Create(pid));
       }
-      UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
+      std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
+      ASSERT_TRUE(backtrace.get() != nullptr);
       ASSERT_TRUE(backtrace->Unwind(0));
-      ASSERT_TRUE(backtrace.get() != NULL);
       if (ReadyFunc(backtrace.get())) {
         VerifyFunc(backtrace.get());
         verified = true;
+      } else {
+        last_dump = DumpFrames(backtrace.get());
       }
 
       ASSERT_TRUE(ptrace(PTRACE_DETACH, ptrace_tid, 0, 0) == 0);
     }
     // If 5 seconds have passed, then we are done.
   } while (!verified && (NanoTime() - start) <= 5 * NS_PER_SEC);
-  ASSERT_TRUE(verified);
+  ASSERT_TRUE(verified) << "Last backtrace:\n" << last_dump;
 }
 
 TEST(libbacktrace, ptrace_trace) {
   pid_t pid;
   if ((pid = fork()) == 0) {
-    ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
+    ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
     _exit(1);
   }
   VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyLevelBacktrace, VerifyLevelDump);
@@ -304,7 +344,7 @@
 TEST(libbacktrace, ptrace_trace_shared_map) {
   pid_t pid;
   if ((pid = fork()) == 0) {
-    ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
+    ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
     _exit(1);
   }
 
@@ -318,7 +358,7 @@
 TEST(libbacktrace, ptrace_max_trace) {
   pid_t pid;
   if ((pid = fork()) == 0) {
-    ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, NULL, NULL), 0);
+    ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, nullptr, nullptr), 0);
     _exit(1);
   }
   VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyMaxBacktrace, VerifyMaxDump);
@@ -329,21 +369,21 @@
 }
 
 void VerifyProcessIgnoreFrames(Backtrace* bt_all) {
-  UniquePtr<Backtrace> ign1(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD));
-  ASSERT_TRUE(ign1.get() != NULL);
+  std::unique_ptr<Backtrace> ign1(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD));
+  ASSERT_TRUE(ign1.get() != nullptr);
   ASSERT_TRUE(ign1->Unwind(1));
 
-  UniquePtr<Backtrace> ign2(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD));
-  ASSERT_TRUE(ign2.get() != NULL);
+  std::unique_ptr<Backtrace> ign2(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD));
+  ASSERT_TRUE(ign2.get() != nullptr);
   ASSERT_TRUE(ign2->Unwind(2));
 
-  VerifyIgnoreFrames(bt_all, ign1.get(), ign2.get(), NULL);
+  VerifyIgnoreFrames(bt_all, ign1.get(), ign2.get(), nullptr);
 }
 
 TEST(libbacktrace, ptrace_ignore_frames) {
   pid_t pid;
   if ((pid = fork()) == 0) {
-    ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
+    ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
     _exit(1);
   }
   VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyLevelBacktrace, VerifyProcessIgnoreFrames);
@@ -355,8 +395,8 @@
 
 // Create a process with multiple threads and dump all of the threads.
 void* PtraceThreadLevelRun(void*) {
-  EXPECT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
-  return NULL;
+  EXPECT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
+  return nullptr;
 }
 
 void GetThreads(pid_t pid, std::vector<pid_t>* threads) {
@@ -365,9 +405,9 @@
   snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
 
   DIR* tasks_dir = opendir(task_path);
-  ASSERT_TRUE(tasks_dir != NULL);
+  ASSERT_TRUE(tasks_dir != nullptr);
   struct dirent* entry;
-  while ((entry = readdir(tasks_dir)) != NULL) {
+  while ((entry = readdir(tasks_dir)) != nullptr) {
     char* end;
     pid_t tid = strtoul(entry->d_name, &end, 10);
     if (*end == '\0') {
@@ -386,9 +426,9 @@
       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 
       pthread_t thread;
-      ASSERT_TRUE(pthread_create(&thread, &attr, PtraceThreadLevelRun, NULL) == 0);
+      ASSERT_TRUE(pthread_create(&thread, &attr, PtraceThreadLevelRun, nullptr) == 0);
     }
-    ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
+    ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
     _exit(1);
   }
 
@@ -420,27 +460,27 @@
 }
 
 void VerifyLevelThread(void*) {
-  UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
-  ASSERT_TRUE(backtrace.get() != NULL);
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
+  ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
 
   VerifyLevelDump(backtrace.get());
 }
 
 TEST(libbacktrace, thread_current_level) {
-  ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelThread, NULL), 0);
+  ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelThread, nullptr), 0);
 }
 
 void VerifyMaxThread(void*) {
-  UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
-  ASSERT_TRUE(backtrace.get() != NULL);
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
+  ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
 
   VerifyMaxDump(backtrace.get());
 }
 
 TEST(libbacktrace, thread_current_max) {
-  ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxThread, NULL), 0);
+  ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxThread, nullptr), 0);
 }
 
 void* ThreadLevelRun(void* data) {
@@ -448,7 +488,7 @@
 
   thread->tid = gettid();
   EXPECT_NE(test_level_one(1, 2, 3, 4, ThreadSetState, data), 0);
-  return NULL;
+  return nullptr;
 }
 
 TEST(libbacktrace, thread_level_trace) {
@@ -456,7 +496,7 @@
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 
-  thread_t thread_data = { 0, 0, 0 };
+  thread_t thread_data = { 0, 0, 0, nullptr };
   pthread_t thread;
   ASSERT_TRUE(pthread_create(&thread, &attr, ThreadLevelRun, &thread_data) == 0);
 
@@ -471,10 +511,10 @@
 
   // Save the current signal action and make sure it is restored afterwards.
   struct sigaction cur_action;
-  ASSERT_TRUE(sigaction(THREAD_SIGNAL, NULL, &cur_action) == 0);
+  ASSERT_TRUE(sigaction(THREAD_SIGNAL, nullptr, &cur_action) == 0);
 
-  UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
-  ASSERT_TRUE(backtrace.get() != NULL);
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
+  ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
 
   VerifyLevelDump(backtrace.get());
@@ -484,14 +524,18 @@
 
   // Verify that the old action was restored.
   struct sigaction new_action;
-  ASSERT_TRUE(sigaction(THREAD_SIGNAL, NULL, &new_action) == 0);
+  ASSERT_TRUE(sigaction(THREAD_SIGNAL, nullptr, &new_action) == 0);
   EXPECT_EQ(cur_action.sa_sigaction, new_action.sa_sigaction);
   // The SA_RESTORER flag gets set behind our back, so a direct comparison
   // doesn't work unless we mask the value off. Mips doesn't have this
   // flag, so skip this on that platform.
-#ifdef SA_RESTORER
+#if defined(SA_RESTORER)
   cur_action.sa_flags &= ~SA_RESTORER;
   new_action.sa_flags &= ~SA_RESTORER;
+#elif defined(__GLIBC__)
+  // Our host compiler doesn't appear to define this flag for some reason.
+  cur_action.sa_flags &= ~0x04000000;
+  new_action.sa_flags &= ~0x04000000;
 #endif
   EXPECT_EQ(cur_action.sa_flags, new_action.sa_flags);
 }
@@ -501,26 +545,26 @@
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 
-  thread_t thread_data = { 0, 0, 0 };
+  thread_t thread_data = { 0, 0, 0, nullptr };
   pthread_t thread;
   ASSERT_TRUE(pthread_create(&thread, &attr, ThreadLevelRun, &thread_data) == 0);
 
   // Wait up to 2 seconds for the tid to be set.
   ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
 
-  UniquePtr<Backtrace> all(Backtrace::Create(getpid(), thread_data.tid));
-  ASSERT_TRUE(all.get() != NULL);
+  std::unique_ptr<Backtrace> all(Backtrace::Create(getpid(), thread_data.tid));
+  ASSERT_TRUE(all.get() != nullptr);
   ASSERT_TRUE(all->Unwind(0));
 
-  UniquePtr<Backtrace> ign1(Backtrace::Create(getpid(), thread_data.tid));
-  ASSERT_TRUE(ign1.get() != NULL);
+  std::unique_ptr<Backtrace> ign1(Backtrace::Create(getpid(), thread_data.tid));
+  ASSERT_TRUE(ign1.get() != nullptr);
   ASSERT_TRUE(ign1->Unwind(1));
 
-  UniquePtr<Backtrace> ign2(Backtrace::Create(getpid(), thread_data.tid));
-  ASSERT_TRUE(ign2.get() != NULL);
+  std::unique_ptr<Backtrace> ign2(Backtrace::Create(getpid(), thread_data.tid));
+  ASSERT_TRUE(ign2.get() != nullptr);
   ASSERT_TRUE(ign2->Unwind(2));
 
-  VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), NULL);
+  VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), nullptr);
 
   // Tell the thread to exit its infinite loop.
   android_atomic_acquire_store(0, &thread_data.state);
@@ -531,7 +575,7 @@
 
   thread->tid = gettid();
   EXPECT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, ThreadSetState, data), 0);
-  return NULL;
+  return nullptr;
 }
 
 TEST(libbacktrace, thread_max_trace) {
@@ -539,15 +583,15 @@
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 
-  thread_t thread_data = { 0, 0, 0 };
+  thread_t thread_data = { 0, 0, 0, nullptr };
   pthread_t thread;
   ASSERT_TRUE(pthread_create(&thread, &attr, ThreadMaxRun, &thread_data) == 0);
 
   // Wait for the tid to be set.
   ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
 
-  UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
-  ASSERT_TRUE(backtrace.get() != NULL);
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
+  ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
 
   VerifyMaxDump(backtrace.get());
@@ -570,7 +614,7 @@
 
   android_atomic_acquire_store(1, &dump->done);
 
-  return NULL;
+  return nullptr;
 }
 
 TEST(libbacktrace, thread_multiple_dump) {
@@ -614,11 +658,11 @@
     // Tell the runner thread to exit its infinite loop.
     android_atomic_acquire_store(0, &runners[i].state);
 
-    ASSERT_TRUE(dumpers[i].backtrace != NULL);
+    ASSERT_TRUE(dumpers[i].backtrace != nullptr);
     VerifyMaxDump(dumpers[i].backtrace);
 
     delete dumpers[i].backtrace;
-    dumpers[i].backtrace = NULL;
+    dumpers[i].backtrace = nullptr;
   }
 }
 
@@ -654,11 +698,11 @@
   for (size_t i = 0; i < NUM_THREADS; i++) {
     ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 30));
 
-    ASSERT_TRUE(dumpers[i].backtrace != NULL);
+    ASSERT_TRUE(dumpers[i].backtrace != nullptr);
     VerifyMaxDump(dumpers[i].backtrace);
 
     delete dumpers[i].backtrace;
-    dumpers[i].backtrace = NULL;
+    dumpers[i].backtrace = nullptr;
   }
 
   // Tell the runner thread to exit its infinite loop.
@@ -673,37 +717,54 @@
   BacktraceMap* map3 = BacktraceMap::Create(getpid());
 
   Backtrace* back1 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map1);
+  ASSERT_TRUE(back1 != nullptr);
   EXPECT_TRUE(back1->Unwind(0));
   delete back1;
   delete map1;
 
   Backtrace* back2 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map2);
+  ASSERT_TRUE(back2 != nullptr);
   EXPECT_TRUE(back2->Unwind(0));
   delete back2;
   delete map2;
 
   Backtrace* back3 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map3);
+  ASSERT_TRUE(back3 != nullptr);
   EXPECT_TRUE(back3->Unwind(0));
   delete back3;
   delete map3;
 }
 
+TEST(libbacktrace, fillin_erases) {
+  BacktraceMap* back_map = BacktraceMap::Create(getpid());
+
+  backtrace_map_t map;
+
+  map.start = 1;
+  map.end = 3;
+  map.flags = 1;
+  map.name = "Initialized";
+  back_map->FillIn(0, &map);
+  delete back_map;
+
+  ASSERT_FALSE(BacktraceMap::IsValid(map));
+  ASSERT_EQ(static_cast<uintptr_t>(0), map.start);
+  ASSERT_EQ(static_cast<uintptr_t>(0), map.end);
+  ASSERT_EQ(0, map.flags);
+  ASSERT_EQ("", map.name);
+}
+
 TEST(libbacktrace, format_test) {
-  UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD));
-  ASSERT_TRUE(backtrace.get() != NULL);
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD));
+  ASSERT_TRUE(backtrace.get() != nullptr);
 
   backtrace_frame_data_t frame;
   frame.num = 1;
   frame.pc = 2;
   frame.sp = 0;
   frame.stack_size = 0;
-  frame.map = NULL;
   frame.func_offset = 0;
 
-  backtrace_map_t map;
-  map.start = 0;
-  map.end = 0;
-
   // Check no map set.
   frame.num = 1;
 #if defined(__LP64__)
@@ -714,8 +775,9 @@
             backtrace->FormatFrameData(&frame));
 
   // Check map name empty, but exists.
-  frame.map = &map;
-  map.start = 1;
+  frame.map.start = 1;
+  frame.map.end = 1;
+  frame.map.load_base = 0;
 #if defined(__LP64__)
   EXPECT_EQ("#01 pc 0000000000000001  <unknown>",
 #else
@@ -726,9 +788,9 @@
 
   // Check relative pc is set and map name is set.
   frame.pc = 0x12345679;
-  frame.map = &map;
-  map.name = "MapFake";
-  map.start =  1;
+  frame.map.name = "MapFake";
+  frame.map.start =  1;
+  frame.map.end =  1;
 #if defined(__LP64__)
   EXPECT_EQ("#01 pc 0000000012345678  MapFake",
 #else
@@ -753,6 +815,25 @@
   EXPECT_EQ("#01 pc 12345678  MapFake (ProcFake+645)",
 #endif
             backtrace->FormatFrameData(&frame));
+
+  // Check func_name is set, func offset is non-zero, and load_base is non-zero.
+  frame.func_offset = 645;
+  frame.map.load_base = 100;
+#if defined(__LP64__)
+  EXPECT_EQ("#01 pc 00000000123456dc  MapFake (ProcFake+645)",
+#else
+  EXPECT_EQ("#01 pc 123456dc  MapFake (ProcFake+645)",
+#endif
+            backtrace->FormatFrameData(&frame));
+
+  // Check a non-zero map offset.
+  frame.map.offset = 0x1000;
+#if defined(__LP64__)
+  EXPECT_EQ("#01 pc 00000000123456dc  MapFake (offset 0x1000) (ProcFake+645)",
+#else
+  EXPECT_EQ("#01 pc 123456dc  MapFake (offset 0x1000) (ProcFake+645)",
+#endif
+            backtrace->FormatFrameData(&frame));
 }
 
 struct map_test_t {
@@ -764,12 +845,12 @@
   return i.start < j.start;
 }
 
-static void VerifyMap(pid_t pid) {
+void VerifyMap(pid_t pid) {
   char buffer[4096];
   snprintf(buffer, sizeof(buffer), "/proc/%d/maps", pid);
 
   FILE* map_file = fopen(buffer, "r");
-  ASSERT_TRUE(map_file != NULL);
+  ASSERT_TRUE(map_file != nullptr);
   std::vector<map_test_t> test_maps;
   while (fgets(buffer, sizeof(buffer), map_file)) {
     map_test_t map;
@@ -779,7 +860,7 @@
   fclose(map_file);
   std::sort(test_maps.begin(), test_maps.end(), map_sort);
 
-  UniquePtr<BacktraceMap> map(BacktraceMap::Create(pid));
+  std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
 
   // Basic test that verifies that the map is in the expected order.
   std::vector<map_test_t>::const_iterator test_it = test_maps.begin();
@@ -813,7 +894,485 @@
   ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
 
   kill(pid, SIGKILL);
-  ASSERT_EQ(waitpid(pid, NULL, 0), pid);
+  ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
+}
+
+void InitMemory(uint8_t* memory, size_t bytes) {
+  for (size_t i = 0; i < bytes; i++) {
+    memory[i] = i;
+    if (memory[i] == '\0') {
+      // Don't use '\0' in our data so we can verify that an overread doesn't
+      // occur by using a '\0' as the character after the read data.
+      memory[i] = 23;
+    }
+  }
+}
+
+void* ThreadReadTest(void* data) {
+  thread_t* thread_data = reinterpret_cast<thread_t*>(data);
+
+  thread_data->tid = gettid();
+
+  // Create two map pages.
+  // Mark the second page as not-readable.
+  size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE));
+  uint8_t* memory;
+  if (posix_memalign(reinterpret_cast<void**>(&memory), pagesize, 2 * pagesize) != 0) {
+    return reinterpret_cast<void*>(-1);
+  }
+
+  if (mprotect(&memory[pagesize], pagesize, PROT_NONE) != 0) {
+    return reinterpret_cast<void*>(-1);
+  }
+
+  // Set up a simple pattern in memory.
+  InitMemory(memory, pagesize);
+
+  thread_data->data = memory;
+
+  // Tell the caller it's okay to start reading memory.
+  android_atomic_acquire_store(1, &thread_data->state);
+
+  // Loop waiting for the caller to finish reading the memory.
+  while (thread_data->state) {
+  }
+
+  // Re-enable read-write on the page so that we don't crash if we try
+  // and access data on this page when freeing the memory.
+  if (mprotect(&memory[pagesize], pagesize, PROT_READ | PROT_WRITE) != 0) {
+    return reinterpret_cast<void*>(-1);
+  }
+  free(memory);
+
+  android_atomic_acquire_store(1, &thread_data->state);
+
+  return nullptr;
+}
+
+void RunReadTest(Backtrace* backtrace, uintptr_t read_addr) {
+  size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE));
+
+  // Create a page of data to use to do quick compares.
+  uint8_t* expected = new uint8_t[pagesize];
+  InitMemory(expected, pagesize);
+
+  uint8_t* data = new uint8_t[2*pagesize];
+  // Verify that we can only read one page worth of data.
+  size_t bytes_read = backtrace->Read(read_addr, data, 2 * pagesize);
+  ASSERT_EQ(pagesize, bytes_read);
+  ASSERT_TRUE(memcmp(data, expected, pagesize) == 0);
+
+  // Verify unaligned reads.
+  for (size_t i = 1; i < sizeof(word_t); i++) {
+    bytes_read = backtrace->Read(read_addr + i, data, 2 * sizeof(word_t));
+    ASSERT_EQ(2 * sizeof(word_t), bytes_read);
+    ASSERT_TRUE(memcmp(data, &expected[i], 2 * sizeof(word_t)) == 0)
+        << "Offset at " << i << " failed";
+  }
+
+  // Verify small unaligned reads.
+  for (size_t i = 1; i < sizeof(word_t); i++) {
+    for (size_t j = 1; j < sizeof(word_t); j++) {
+      // Set one byte past what we expect to read, to guarantee we don't overread.
+      data[j] = '\0';
+      bytes_read = backtrace->Read(read_addr + i, data, j);
+      ASSERT_EQ(j, bytes_read);
+      ASSERT_TRUE(memcmp(data, &expected[i], j) == 0)
+          << "Offset at " << i << " length " << j << " miscompared";
+      ASSERT_EQ('\0', data[j])
+          << "Offset at " << i << " length " << j << " wrote too much data";
+    }
+  }
+  delete data;
+  delete expected;
+}
+
+TEST(libbacktrace, thread_read) {
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+  pthread_t thread;
+  thread_t thread_data = { 0, 0, 0, nullptr };
+  ASSERT_TRUE(pthread_create(&thread, &attr, ThreadReadTest, &thread_data) == 0);
+
+  ASSERT_TRUE(WaitForNonZero(&thread_data.state, 10));
+
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
+  ASSERT_TRUE(backtrace.get() != nullptr);
+
+  RunReadTest(backtrace.get(), reinterpret_cast<uintptr_t>(thread_data.data));
+
+  android_atomic_acquire_store(0, &thread_data.state);
+
+  ASSERT_TRUE(WaitForNonZero(&thread_data.state, 10));
+}
+
+volatile uintptr_t g_ready = 0;
+volatile uintptr_t g_addr = 0;
+
+void ForkedReadTest() {
+  // Create two map pages.
+  size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE));
+  uint8_t* memory;
+  if (posix_memalign(reinterpret_cast<void**>(&memory), pagesize, 2 * pagesize) != 0) {
+    perror("Failed to allocate memory\n");
+    exit(1);
+  }
+
+  // Mark the second page as not-readable.
+  if (mprotect(&memory[pagesize], pagesize, PROT_NONE) != 0) {
+    perror("Failed to mprotect memory\n");
+    exit(1);
+  }
+
+  // Set up a simple pattern in memory.
+  InitMemory(memory, pagesize);
+
+  g_addr = reinterpret_cast<uintptr_t>(memory);
+  g_ready = 1;
+
+  while (1) {
+    usleep(US_PER_MSEC);
+  }
+}
+
+TEST(libbacktrace, process_read) {
+  g_ready = 0;
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    ForkedReadTest();
+    exit(0);
+  }
+  ASSERT_NE(-1, pid);
+
+  bool test_executed = false;
+  uint64_t start = NanoTime();
+  while (1) {
+    if (ptrace(PTRACE_ATTACH, pid, 0, 0) == 0) {
+      WaitForStop(pid);
+
+      std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
+      ASSERT_TRUE(backtrace.get() != nullptr);
+
+      uintptr_t read_addr;
+      size_t bytes_read = backtrace->Read(reinterpret_cast<uintptr_t>(&g_ready),
+                                          reinterpret_cast<uint8_t*>(&read_addr),
+                                          sizeof(uintptr_t));
+      ASSERT_EQ(sizeof(uintptr_t), bytes_read);
+      if (read_addr) {
+        // The forked process is ready to be read.
+        bytes_read = backtrace->Read(reinterpret_cast<uintptr_t>(&g_addr),
+                                     reinterpret_cast<uint8_t*>(&read_addr),
+                                     sizeof(uintptr_t));
+        ASSERT_EQ(sizeof(uintptr_t), bytes_read);
+
+        RunReadTest(backtrace.get(), read_addr);
+
+        test_executed = true;
+        break;
+      }
+      ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
+    }
+    if ((NanoTime() - start) > 5 * NS_PER_SEC) {
+      break;
+    }
+    usleep(US_PER_MSEC);
+  }
+  kill(pid, SIGKILL);
+  ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
+
+  ASSERT_TRUE(test_executed);
+}
+
+void VerifyFunctionsFound(const std::vector<std::string>& found_functions) {
+  // We expect to find these functions in libbacktrace_test. If we don't
+  // find them, that's a bug in the memory read handling code in libunwind.
+  std::list<std::string> expected_functions;
+  expected_functions.push_back("test_recursive_call");
+  expected_functions.push_back("test_level_one");
+  expected_functions.push_back("test_level_two");
+  expected_functions.push_back("test_level_three");
+  expected_functions.push_back("test_level_four");
+  for (const auto& found_function : found_functions) {
+    for (const auto& expected_function : expected_functions) {
+      if (found_function == expected_function) {
+        expected_functions.remove(found_function);
+        break;
+      }
+    }
+  }
+  ASSERT_TRUE(expected_functions.empty()) << "Not all functions found in shared library.";
+}
+
+const char* CopySharedLibrary() {
+#if defined(__LP64__)
+  const char* lib_name = "lib64";
+#else
+  const char* lib_name = "lib";
+#endif
+
+#if defined(__BIONIC__)
+  const char* tmp_so_name = "/data/local/tmp/libbacktrace_test.so";
+  std::string cp_cmd = android::base::StringPrintf("cp /system/%s/libbacktrace_test.so %s",
+                                                   lib_name, tmp_so_name);
+#else
+  const char* tmp_so_name = "/tmp/libbacktrace_test.so";
+  if (getenv("ANDROID_HOST_OUT") == NULL) {
+    fprintf(stderr, "ANDROID_HOST_OUT not set, make sure you run lunch.");
+    return nullptr;
+  }
+  std::string cp_cmd = android::base::StringPrintf("cp %s/%s/libbacktrace_test.so %s",
+                                                   getenv("ANDROID_HOST_OUT"), lib_name,
+                                                   tmp_so_name);
+#endif
+
+  // Copy the shared so to a tempory directory.
+  system(cp_cmd.c_str());
+
+  return tmp_so_name;
+}
+
+TEST(libbacktrace, check_unreadable_elf_local) {
+  const char* tmp_so_name = CopySharedLibrary();
+  ASSERT_TRUE(tmp_so_name != nullptr);
+
+  struct stat buf;
+  ASSERT_TRUE(stat(tmp_so_name, &buf) != -1);
+  uintptr_t map_size = buf.st_size;
+
+  int fd = open(tmp_so_name, O_RDONLY);
+  ASSERT_TRUE(fd != -1);
+
+  void* map = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE, fd, 0);
+  ASSERT_TRUE(map != MAP_FAILED);
+  close(fd);
+  ASSERT_TRUE(unlink(tmp_so_name) != -1);
+
+  std::vector<std::string> found_functions;
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS,
+                                                         BACKTRACE_CURRENT_THREAD));
+  ASSERT_TRUE(backtrace.get() != nullptr);
+
+  // Needed before GetFunctionName will work.
+  backtrace->Unwind(0);
+
+  // Loop through the entire map, and get every function we can find.
+  map_size += reinterpret_cast<uintptr_t>(map);
+  std::string last_func;
+  for (uintptr_t read_addr = reinterpret_cast<uintptr_t>(map);
+       read_addr < map_size; read_addr += 4) {
+    uintptr_t offset;
+    std::string func_name = backtrace->GetFunctionName(read_addr, &offset);
+    if (!func_name.empty() && last_func != func_name) {
+      found_functions.push_back(func_name);
+    }
+    last_func = func_name;
+  }
+
+  ASSERT_TRUE(munmap(map, map_size - reinterpret_cast<uintptr_t>(map)) == 0);
+
+  VerifyFunctionsFound(found_functions);
+}
+
+TEST(libbacktrace, check_unreadable_elf_remote) {
+  const char* tmp_so_name = CopySharedLibrary();
+  ASSERT_TRUE(tmp_so_name != nullptr);
+
+  g_ready = 0;
+
+  struct stat buf;
+  ASSERT_TRUE(stat(tmp_so_name, &buf) != -1);
+  uintptr_t map_size = buf.st_size;
+
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    int fd = open(tmp_so_name, O_RDONLY);
+    if (fd == -1) {
+      fprintf(stderr, "Failed to open file %s: %s\n", tmp_so_name, strerror(errno));
+      unlink(tmp_so_name);
+      exit(0);
+    }
+
+    void* map = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE, fd, 0);
+    if (map == MAP_FAILED) {
+      fprintf(stderr, "Failed to map in memory: %s\n", strerror(errno));
+      unlink(tmp_so_name);
+      exit(0);
+    }
+    close(fd);
+    if (unlink(tmp_so_name) == -1) {
+      fprintf(stderr, "Failed to unlink: %s\n", strerror(errno));
+      exit(0);
+    }
+
+    g_addr = reinterpret_cast<uintptr_t>(map);
+    g_ready = 1;
+    while (true) {
+      usleep(US_PER_MSEC);
+    }
+    exit(0);
+  }
+  ASSERT_TRUE(pid > 0);
+
+  std::vector<std::string> found_functions;
+  uint64_t start = NanoTime();
+  while (true) {
+    ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
+
+    // Wait for the process to get to a stopping point.
+    WaitForStop(pid);
+
+    std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
+    ASSERT_TRUE(backtrace.get() != nullptr);
+
+    uintptr_t read_addr;
+    ASSERT_EQ(sizeof(uintptr_t), backtrace->Read(reinterpret_cast<uintptr_t>(&g_ready), reinterpret_cast<uint8_t*>(&read_addr), sizeof(uintptr_t)));
+    if (read_addr) {
+      ASSERT_EQ(sizeof(uintptr_t), backtrace->Read(reinterpret_cast<uintptr_t>(&g_addr), reinterpret_cast<uint8_t*>(&read_addr), sizeof(uintptr_t)));
+
+      // Needed before GetFunctionName will work.
+      backtrace->Unwind(0);
+
+      // Loop through the entire map, and get every function we can find.
+      map_size += read_addr;
+      std::string last_func;
+      for (; read_addr < map_size; read_addr += 4) {
+        uintptr_t offset;
+        std::string func_name = backtrace->GetFunctionName(read_addr, &offset);
+        if (!func_name.empty() && last_func != func_name) {
+          found_functions.push_back(func_name);
+        }
+        last_func = func_name;
+      }
+      break;
+    }
+    ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
+
+    if ((NanoTime() - start) > 5 * NS_PER_SEC) {
+      break;
+    }
+    usleep(US_PER_MSEC);
+  }
+
+  kill(pid, SIGKILL);
+  ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
+
+  VerifyFunctionsFound(found_functions);
+}
+
+bool FindFuncFrameInBacktrace(Backtrace* backtrace, uintptr_t test_func, size_t* frame_num) {
+  backtrace_map_t map;
+  backtrace->FillInMap(test_func, &map);
+  if (!BacktraceMap::IsValid(map)) {
+    return false;
+  }
+
+  // Loop through the frames, and find the one that is in the map.
+  *frame_num = 0;
+  for (Backtrace::const_iterator it = backtrace->begin(); it != backtrace->end(); ++it) {
+    if (BacktraceMap::IsValid(it->map) && map.start == it->map.start &&
+        it->pc >= test_func) {
+      *frame_num = it->num;
+      return true;
+    }
+  }
+  return false;
+}
+
+void VerifyUnreadableElfFrame(Backtrace* backtrace, uintptr_t test_func, size_t frame_num) {
+  ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES))
+    << DumpFrames(backtrace);
+
+  ASSERT_TRUE(frame_num != 0) << DumpFrames(backtrace);
+  // Make sure that there is at least one more frame above the test func call.
+  ASSERT_LT(frame_num, backtrace->NumFrames()) << DumpFrames(backtrace);
+
+  uintptr_t diff = backtrace->GetFrame(frame_num)->pc - test_func;
+  ASSERT_LT(diff, 200U) << DumpFrames(backtrace);
+}
+
+void VerifyUnreadableElfBacktrace(uintptr_t test_func) {
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS,
+                                                         BACKTRACE_CURRENT_THREAD));
+  ASSERT_TRUE(backtrace.get() != nullptr);
+  ASSERT_TRUE(backtrace->Unwind(0));
+
+  size_t frame_num;
+  ASSERT_TRUE(FindFuncFrameInBacktrace(backtrace.get(), test_func, &frame_num));
+
+  VerifyUnreadableElfFrame(backtrace.get(), test_func, frame_num);
+}
+
+typedef int (*test_func_t)(int, int, int, int, void (*)(uintptr_t), uintptr_t);
+
+TEST(libbacktrace, unwind_through_unreadable_elf_local) {
+  const char* tmp_so_name = CopySharedLibrary();
+  ASSERT_TRUE(tmp_so_name != nullptr);
+  void* lib_handle = dlopen(tmp_so_name, RTLD_NOW);
+  ASSERT_TRUE(lib_handle != nullptr);
+  ASSERT_TRUE(unlink(tmp_so_name) != -1);
+
+  test_func_t test_func;
+  test_func = reinterpret_cast<test_func_t>(dlsym(lib_handle, "test_level_one"));
+  ASSERT_TRUE(test_func != nullptr);
+
+  ASSERT_NE(test_func(1, 2, 3, 4, VerifyUnreadableElfBacktrace,
+                      reinterpret_cast<uintptr_t>(test_func)), 0);
+
+  ASSERT_TRUE(dlclose(lib_handle) == 0);
+}
+
+TEST(libbacktrace, unwind_through_unreadable_elf_remote) {
+  const char* tmp_so_name = CopySharedLibrary();
+  ASSERT_TRUE(tmp_so_name != nullptr);
+  void* lib_handle = dlopen(tmp_so_name, RTLD_NOW);
+  ASSERT_TRUE(lib_handle != nullptr);
+  ASSERT_TRUE(unlink(tmp_so_name) != -1);
+
+  test_func_t test_func;
+  test_func = reinterpret_cast<test_func_t>(dlsym(lib_handle, "test_level_one"));
+  ASSERT_TRUE(test_func != nullptr);
+
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    test_func(1, 2, 3, 4, 0, 0);
+    exit(0);
+  }
+  ASSERT_TRUE(pid > 0);
+  ASSERT_TRUE(dlclose(lib_handle) == 0);
+
+  uint64_t start = NanoTime();
+  bool done = false;
+  while (!done) {
+    ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
+
+    // Wait for the process to get to a stopping point.
+    WaitForStop(pid);
+
+    std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
+    ASSERT_TRUE(backtrace.get() != nullptr);
+    ASSERT_TRUE(backtrace->Unwind(0));
+
+    size_t frame_num;
+    if (FindFuncFrameInBacktrace(backtrace.get(),
+                                 reinterpret_cast<uintptr_t>(test_func), &frame_num)) {
+
+      VerifyUnreadableElfFrame(backtrace.get(), reinterpret_cast<uintptr_t>(test_func), frame_num);
+      done = true;
+    }
+
+    ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
+
+    if ((NanoTime() - start) > 5 * NS_PER_SEC) {
+      break;
+    }
+    usleep(US_PER_MSEC);
+  }
+
+  kill(pid, SIGKILL);
+  ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
+
+  ASSERT_TRUE(done) << "Test function never found in unwind.";
 }
 
 #if defined(ENABLE_PSS_TESTS)
@@ -821,24 +1380,26 @@
 
 #define MAX_LEAK_BYTES 32*1024UL
 
-static void CheckForLeak(pid_t pid, pid_t tid) {
+void CheckForLeak(pid_t pid, pid_t tid) {
   // Do a few runs to get the PSS stable.
   for (size_t i = 0; i < 100; i++) {
     Backtrace* backtrace = Backtrace::Create(pid, tid);
-    ASSERT_TRUE(backtrace != NULL);
+    ASSERT_TRUE(backtrace != nullptr);
     ASSERT_TRUE(backtrace->Unwind(0));
     delete backtrace;
   }
   size_t stable_pss = GetPssBytes();
+  ASSERT_TRUE(stable_pss != 0);
 
   // Loop enough that even a small leak should be detectable.
   for (size_t i = 0; i < 4096; i++) {
     Backtrace* backtrace = Backtrace::Create(pid, tid);
-    ASSERT_TRUE(backtrace != NULL);
+    ASSERT_TRUE(backtrace != nullptr);
     ASSERT_TRUE(backtrace->Unwind(0));
     delete backtrace;
   }
   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);
@@ -849,9 +1410,9 @@
 }
 
 TEST(libbacktrace, check_for_leak_local_thread) {
-  thread_t thread_data = { 0, 0, 0 };
+  thread_t thread_data = { 0, 0, 0, nullptr };
   pthread_t thread;
-  ASSERT_TRUE(pthread_create(&thread, NULL, ThreadLevelRun, &thread_data) == 0);
+  ASSERT_TRUE(pthread_create(&thread, nullptr, ThreadLevelRun, &thread_data) == 0);
 
   // Wait up to 2 seconds for the tid to be set.
   ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
@@ -861,7 +1422,7 @@
   // Tell the thread to exit its infinite loop.
   android_atomic_acquire_store(0, &thread_data.state);
 
-  ASSERT_TRUE(pthread_join(thread, NULL) == 0);
+  ASSERT_TRUE(pthread_join(thread, nullptr) == 0);
 }
 
 TEST(libbacktrace, check_for_leak_remote) {
@@ -884,6 +1445,7 @@
   ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
 
   kill(pid, SIGKILL);
-  ASSERT_EQ(waitpid(pid, NULL, 0), pid);
+  ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
 }
 #endif
+
diff --git a/libbacktrace/thread_utils.c b/libbacktrace/thread_utils.c
index 6f4cd3c..e75f56e 100644
--- a/libbacktrace/thread_utils.c
+++ b/libbacktrace/thread_utils.c
@@ -16,25 +16,12 @@
 
 #include "thread_utils.h"
 
-#if defined(__APPLE__)
+#if !defined(__BIONIC__)
 
-#include <sys/syscall.h>
-
-// Mac OS >= 10.6 has a system call equivalent to Linux's gettid().
-pid_t gettid() {
-  return syscall(SYS_thread_selfid);
-}
-
-#elif !defined(__BIONIC__)
-
-// glibc doesn't implement or export either gettid or tgkill.
+// glibc doesn't implement or export tgkill.
 #include <unistd.h>
 #include <sys/syscall.h>
 
-pid_t gettid() {
-  return syscall(__NR_gettid);
-}
-
 int tgkill(int tgid, int tid, int sig) {
   return syscall(__NR_tgkill, tgid, tid, sig);
 }
diff --git a/libbacktrace/thread_utils.h b/libbacktrace/thread_utils.h
index ae4c929..df83581 100644
--- a/libbacktrace/thread_utils.h
+++ b/libbacktrace/thread_utils.h
@@ -23,8 +23,6 @@
 
 int tgkill(int tgid, int tid, int sig);
 
-pid_t gettid();
-
 __END_DECLS
 
 #endif /* _LIBBACKTRACE_THREAD_UTILS_H */
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index b016a42..0963076 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -16,20 +16,13 @@
 LOCAL_PATH := $(my-dir)
 include $(CLEAR_VARS)
 
-ifeq ($(TARGET_CPU_SMP),true)
-    targetSmpFlag := -DANDROID_SMP=1
-else
-    targetSmpFlag := -DANDROID_SMP=0
-endif
-hostSmpFlag := -DANDROID_SMP=0
-
 commonSources := \
 	hashmap.c \
 	atomic.c.arm \
 	native_handle.c \
 	config_utils.c \
-	cpu_info.c \
 	load_file.c \
+	strlcpy.c \
 	open_memstream.c \
 	strdup16to8.c \
 	strdup8to16.c \
@@ -39,6 +32,7 @@
 	sched_policy.c \
 	iosched_policy.c \
 	str_parms.c \
+	fs_config.c
 
 # some files must not be compiled when building against Mingw
 # they correspond to features not used by our host development tools
@@ -67,38 +61,33 @@
         sockets.c \
 
     commonHostSources += \
-        ashmem-host.c
+        ashmem-host.c \
+        trace-host.c
 
 endif
 
 
-# Static library for host
+# Shared and static library for host
 # ========================================================
 LOCAL_MODULE := libcutils
 LOCAL_SRC_FILES := $(commonSources) $(commonHostSources) dlmalloc_stubs.c
 LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_CFLAGS += $(hostSmpFlag)
 ifneq ($(HOST_OS),windows)
 LOCAL_CFLAGS += -Werror
 endif
 LOCAL_MULTILIB := both
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_HOST_STATIC_LIBRARY)
 
-
-# Tests for host
-# ========================================================
 include $(CLEAR_VARS)
-LOCAL_MODULE := tst_str_parms
-LOCAL_CFLAGS += -DTEST_STR_PARMS
+LOCAL_MODULE := libcutils
+LOCAL_SRC_FILES := $(commonSources) $(commonHostSources) dlmalloc_stubs.c
+LOCAL_SHARED_LIBRARIES := liblog
 ifneq ($(HOST_OS),windows)
 LOCAL_CFLAGS += -Werror
 endif
-LOCAL_SRC_FILES := str_parms.c hashmap.c memory.c
-LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-include $(BUILD_HOST_EXECUTABLE)
+LOCAL_MULTILIB := both
+include $(BUILD_HOST_SHARED_LIBRARY)
+
 
 
 # Shared and static library for target
@@ -111,40 +100,35 @@
         ashmem-dev.c \
         debugger.c \
         klog.c \
-        memory.c \
         partition_utils.c \
         properties.c \
         qtaguid.c \
-        trace.c \
+        trace-dev.c \
         uevent.c \
 
-LOCAL_SRC_FILES_arm += \
-        arch-arm/memset32.S \
+# arch-arm/memset32.S does not compile with Clang.
+LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
 
-LOCAL_SRC_FILES_arm64 += \
-        arch-arm64/android_memset.S \
+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_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_SSE2-atom.S \
-        arch-x86_64/android_memset32_SSE2-atom.S \
-
-LOCAL_CFLAGS_arm += -DHAVE_MEMSET16 -DHAVE_MEMSET32
-LOCAL_CFLAGS_arm64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
-LOCAL_CFLAGS_mips += -DHAVE_MEMSET16 -DHAVE_MEMSET32
-LOCAL_CFLAGS_x86 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
-LOCAL_CFLAGS_x86_64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
+        arch-x86_64/android_memset16.S \
+        arch-x86_64/android_memset32.S \
 
 LOCAL_C_INCLUDES := $(libcutils_c_includes)
 LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_CFLAGS += $(targetSmpFlag) -Werror
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+ifneq ($(ENABLE_CPUSETS),)
+LOCAL_CFLAGS += -DUSE_CPUSETS
+endif
+LOCAL_CFLAGS += -Werror -std=gnu90
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -153,18 +137,11 @@
 # liblog symbols present in libcutils.
 LOCAL_WHOLE_STATIC_LIBRARIES := libcutils liblog
 LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_CFLAGS += $(targetSmpFlag) -Werror
+ifneq ($(ENABLE_CPUSETS),)
+LOCAL_CFLAGS += -DUSE_CPUSETS
+endif
+LOCAL_CFLAGS += -Werror
 LOCAL_C_INCLUDES := $(libcutils_c_includes)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_SHARED_LIBRARY)
 
-include $(CLEAR_VARS)
-LOCAL_MODULE := tst_str_parms
-LOCAL_CFLAGS += -DTEST_STR_PARMS -Werror
-LOCAL_SRC_FILES := str_parms.c hashmap.c memory.c
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-include $(BUILD_EXECUTABLE)
-
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libcutils/android_reboot.c b/libcutils/android_reboot.c
index 5d98295..6ae23c1 100644
--- a/libcutils/android_reboot.c
+++ b/libcutils/android_reboot.c
@@ -20,6 +20,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#include <mntent.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -33,37 +34,21 @@
  */
 static int remount_ro_done(void)
 {
-    FILE *f;
-    char mount_dev[256];
-    char mount_dir[256];
-    char mount_type[256];
-    char mount_opts[256];
-    int mount_freq;
-    int mount_passno;
-    int match;
+    FILE* fp;
+    struct mntent* mentry;
     int found_rw_fs = 0;
 
-    f = fopen("/proc/mounts", "r");
-    if (! f) {
-        /* If we can't read /proc/mounts, just give up */
+    if ((fp = setmntent("/proc/mounts", "r")) == NULL) {
+        /* If we can't read /proc/mounts, just give up. */
         return 1;
     }
-
-    do {
-        match = fscanf(f, "%255s %255s %255s %255s %d %d\n",
-                       mount_dev, mount_dir, mount_type,
-                       mount_opts, &mount_freq, &mount_passno);
-        mount_dev[255] = 0;
-        mount_dir[255] = 0;
-        mount_type[255] = 0;
-        mount_opts[255] = 0;
-        if ((match == 6) && !strncmp(mount_dev, "/dev/block", 10) && strstr(mount_opts, "rw,")) {
+    while ((mentry = getmntent(fp)) != NULL) {
+        if (!strncmp(mentry->mnt_fsname, "/dev/block", 10) && strstr(mentry->mnt_opts, "rw,")) {
             found_rw_fs = 1;
             break;
         }
-    } while (match != EOF);
-
-    fclose(f);
+    }
+    endmntent(fp);
 
     return !found_rw_fs;
 }
@@ -104,7 +89,7 @@
 }
 
 
-int android_reboot(int cmd, int flags UNUSED, char *arg)
+int android_reboot(int cmd, int flags UNUSED, const char *arg)
 {
     int ret;
 
diff --git a/libcutils/arch-mips/android_memset.c b/libcutils/arch-mips/android_memset.c
index bbc99fe..a6b7496 100644
--- a/libcutils/arch-mips/android_memset.c
+++ b/libcutils/arch-mips/android_memset.c
@@ -1,31 +1,93 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
+ * All rights reserved.
  *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * 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.
  *
- *      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 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.
  */
 
+/* generic C version for any machine */
+
 #include <cutils/memory.h>
 
-/* Use mips-assembler versions supplied by bionic/libc/arch-mips/string/memset.S: */
-void _memset16(uint16_t* dst, uint16_t value, size_t size);
-void _memset32(uint32_t* dst, uint32_t value, size_t size);
-
 void android_memset16(uint16_t* dst, uint16_t value, size_t size)
 {
-    _memset16(dst, value, size);
+   /* optimized version of
+      size >>= 1;
+      while (size--)
+        *dst++ = value;
+   */
+
+   size >>= 1;
+   if (((uintptr_t)dst & 2) && size) {
+      /* fill unpaired first elem separately */
+      *dst++ = value;
+      size--;
+   }
+   /* dst is now 32-bit-aligned */
+   /* fill body with 32-bit pairs */
+   uint32_t value32 = (value << 16) | value;
+   android_memset32((uint32_t*) dst, value32, size<<1);
+   if (size & 1) {
+      dst[size-1] = value;  /* fill unpaired last elem */
+   }
 }
 
+
 void android_memset32(uint32_t* dst, uint32_t value, size_t size)
 {
-    _memset32(dst, value, size);
+   /* optimized version of
+      size >>= 2;
+      while (size--)
+         *dst++ = value;
+   */
+
+   size >>= 2;
+   if (((uintptr_t)dst & 4) && size) {
+      /* fill unpaired first 32-bit elem separately */
+      *dst++ = value;
+      size--;
+   }
+   /* dst is now 64-bit aligned */
+   /* fill body with 64-bit pairs */
+   uint64_t value64 = (((uint64_t)value)<<32) | value;
+   uint64_t* dst64 = (uint64_t*)dst;
+
+   while (size >= 12) {
+      dst64[0] = value64;
+      dst64[1] = value64;
+      dst64[2] = value64;
+      dst64[3] = value64;
+      dst64[4] = value64;
+      dst64[5] = value64;
+      size  -= 12;
+      dst64 += 6;
+   }
+
+   /* fill remainder with original 32-bit single-elem loop */
+   dst = (uint32_t*) dst64;
+   while (size--) {
+      *dst++ = value;
+   }
+
 }
diff --git a/libcutils/arch-x86/android_memset16.S b/libcutils/arch-x86/android_memset16.S
old mode 100644
new mode 100755
index f8b79bd..cb2ff14
--- a/libcutils/arch-x86/android_memset16.S
+++ b/libcutils/arch-x86/android_memset16.S
@@ -13,13 +13,707 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-/*
- * Contributed by: Intel Corporation
- */
 
-# include "cache_wrapper.S"
-# undef __i686
-# define USE_AS_ANDROID
-# define sse2_memset16_atom android_memset16
-# include "sse2-memset16-atom.S"
+#include "cache.h"
 
+#ifndef MEMSET
+# define MEMSET		android_memset16
+#endif
+
+#ifndef L
+# define L(label)	.L##label
+#endif
+
+#ifndef ALIGN
+# define ALIGN(n)	.p2align n
+#endif
+
+#ifndef cfi_startproc
+# define cfi_startproc			.cfi_startproc
+#endif
+
+#ifndef cfi_endproc
+# define cfi_endproc			.cfi_endproc
+#endif
+
+#ifndef cfi_rel_offset
+# define cfi_rel_offset(reg, off)	.cfi_rel_offset reg, off
+#endif
+
+#ifndef cfi_restore
+# define cfi_restore(reg)		.cfi_restore reg
+#endif
+
+#ifndef cfi_adjust_cfa_offset
+# define cfi_adjust_cfa_offset(off)	.cfi_adjust_cfa_offset off
+#endif
+
+#ifndef ENTRY
+# define ENTRY(name)			\
+	.type name,  @function; 	\
+	.globl name;			\
+	.p2align 4;			\
+name:					\
+	cfi_startproc
+#endif
+
+#ifndef END
+# define END(name)			\
+	cfi_endproc;			\
+	.size name, .-name
+#endif
+
+#define CFI_PUSH(REG)						\
+  cfi_adjust_cfa_offset (4);					\
+  cfi_rel_offset (REG, 0)
+
+#define CFI_POP(REG)						\
+  cfi_adjust_cfa_offset (-4);					\
+  cfi_restore (REG)
+
+#define PUSH(REG)	pushl REG; CFI_PUSH (REG)
+#define POP(REG)	popl REG; CFI_POP (REG)
+
+#ifdef USE_AS_BZERO16
+# define DEST		PARMS
+# define LEN		DEST+4
+# define SETRTNVAL
+#else
+# define DEST		PARMS
+# define CHR		DEST+4
+# define LEN		CHR+4
+# define SETRTNVAL	movl DEST(%esp), %eax
+#endif
+
+#if (defined SHARED || defined __PIC__)
+# define ENTRANCE	PUSH (%ebx);
+# define RETURN_END	POP (%ebx); ret
+# define RETURN		RETURN_END; CFI_PUSH (%ebx)
+# define PARMS		8		/* Preserve EBX.  */
+# define JMPTBL(I, B)	I - B
+
+/* Load an entry in a jump table into EBX and branch to it.  TABLE is a
+   jump table with relative offsets.   */
+# define BRANCH_TO_JMPTBL_ENTRY(TABLE)				\
+    /* We first load PC into EBX.  */				\
+    call	__x86.get_pc_thunk.bx;				\
+    /* Get the address of the jump table.  */			\
+    add		$(TABLE - .), %ebx;				\
+    /* Get the entry and convert the relative offset to the	\
+       absolute address.  */					\
+    add		(%ebx,%ecx,4), %ebx;				\
+    /* We loaded the jump table and adjuested EDX. Go.  */	\
+    jmp		*%ebx
+
+	.section	.gnu.linkonce.t.__x86.get_pc_thunk.bx,"ax",@progbits
+	.globl	__x86.get_pc_thunk.bx
+	.hidden	__x86.get_pc_thunk.bx
+	ALIGN (4)
+	.type	__x86.get_pc_thunk.bx,@function
+__x86.get_pc_thunk.bx:
+	movl	(%esp), %ebx
+	ret
+#else
+# define ENTRANCE
+# define RETURN_END	ret
+# define RETURN		RETURN_END
+# define PARMS		4
+# define JMPTBL(I, B)	I
+
+/* Branch to an entry in a jump table.  TABLE is a jump table with
+   absolute offsets.  */
+# define BRANCH_TO_JMPTBL_ENTRY(TABLE)				\
+    jmp		*TABLE(,%ecx,4)
+#endif
+
+	.section .text.sse2,"ax",@progbits
+	ALIGN (4)
+ENTRY (MEMSET)
+	ENTRANCE
+
+	movl	LEN(%esp), %ecx
+	shr	$1, %ecx
+#ifdef USE_AS_BZERO16
+	xor	%eax, %eax
+#else
+	movzwl	CHR(%esp), %eax
+	mov	%eax, %edx
+	shl	$16, %eax
+	or	%edx, %eax
+#endif
+	movl	DEST(%esp), %edx
+	cmp	$32, %ecx
+	jae	L(32wordsormore)
+
+L(write_less32words):
+	lea	(%edx, %ecx, 2), %edx
+	BRANCH_TO_JMPTBL_ENTRY (L(table_less32words))
+
+
+	.pushsection .rodata.sse2,"a",@progbits
+	ALIGN (2)
+L(table_less32words):
+	.int	JMPTBL (L(write_0words), L(table_less32words))
+	.int	JMPTBL (L(write_1words), L(table_less32words))
+	.int	JMPTBL (L(write_2words), L(table_less32words))
+	.int	JMPTBL (L(write_3words), L(table_less32words))
+	.int	JMPTBL (L(write_4words), L(table_less32words))
+	.int	JMPTBL (L(write_5words), L(table_less32words))
+	.int	JMPTBL (L(write_6words), L(table_less32words))
+	.int	JMPTBL (L(write_7words), L(table_less32words))
+	.int	JMPTBL (L(write_8words), L(table_less32words))
+	.int	JMPTBL (L(write_9words), L(table_less32words))
+	.int	JMPTBL (L(write_10words), L(table_less32words))
+	.int	JMPTBL (L(write_11words), L(table_less32words))
+	.int	JMPTBL (L(write_12words), L(table_less32words))
+	.int	JMPTBL (L(write_13words), L(table_less32words))
+	.int	JMPTBL (L(write_14words), L(table_less32words))
+	.int	JMPTBL (L(write_15words), L(table_less32words))
+	.int	JMPTBL (L(write_16words), L(table_less32words))
+	.int	JMPTBL (L(write_17words), L(table_less32words))
+	.int	JMPTBL (L(write_18words), L(table_less32words))
+	.int	JMPTBL (L(write_19words), L(table_less32words))
+	.int	JMPTBL (L(write_20words), L(table_less32words))
+	.int	JMPTBL (L(write_21words), L(table_less32words))
+	.int	JMPTBL (L(write_22words), L(table_less32words))
+	.int	JMPTBL (L(write_23words), L(table_less32words))
+	.int	JMPTBL (L(write_24words), L(table_less32words))
+	.int	JMPTBL (L(write_25words), L(table_less32words))
+	.int	JMPTBL (L(write_26words), L(table_less32words))
+	.int	JMPTBL (L(write_27words), L(table_less32words))
+	.int	JMPTBL (L(write_28words), L(table_less32words))
+	.int	JMPTBL (L(write_29words), L(table_less32words))
+	.int	JMPTBL (L(write_30words), L(table_less32words))
+	.int	JMPTBL (L(write_31words), L(table_less32words))
+	.popsection
+
+	ALIGN (4)
+L(write_28words):
+	movl	%eax, -56(%edx)
+	movl	%eax, -52(%edx)
+L(write_24words):
+	movl	%eax, -48(%edx)
+	movl	%eax, -44(%edx)
+L(write_20words):
+	movl	%eax, -40(%edx)
+	movl	%eax, -36(%edx)
+L(write_16words):
+	movl	%eax, -32(%edx)
+	movl	%eax, -28(%edx)
+L(write_12words):
+	movl	%eax, -24(%edx)
+	movl	%eax, -20(%edx)
+L(write_8words):
+	movl	%eax, -16(%edx)
+	movl	%eax, -12(%edx)
+L(write_4words):
+	movl	%eax, -8(%edx)
+	movl	%eax, -4(%edx)
+L(write_0words):
+	SETRTNVAL
+	RETURN
+
+	ALIGN (4)
+L(write_29words):
+	movl	%eax, -58(%edx)
+	movl	%eax, -54(%edx)
+L(write_25words):
+	movl	%eax, -50(%edx)
+	movl	%eax, -46(%edx)
+L(write_21words):
+	movl	%eax, -42(%edx)
+	movl	%eax, -38(%edx)
+L(write_17words):
+	movl	%eax, -34(%edx)
+	movl	%eax, -30(%edx)
+L(write_13words):
+	movl	%eax, -26(%edx)
+	movl	%eax, -22(%edx)
+L(write_9words):
+	movl	%eax, -18(%edx)
+	movl	%eax, -14(%edx)
+L(write_5words):
+	movl	%eax, -10(%edx)
+	movl	%eax, -6(%edx)
+L(write_1words):
+	mov	%ax, -2(%edx)
+	SETRTNVAL
+	RETURN
+
+	ALIGN (4)
+L(write_30words):
+	movl	%eax, -60(%edx)
+	movl	%eax, -56(%edx)
+L(write_26words):
+	movl	%eax, -52(%edx)
+	movl	%eax, -48(%edx)
+L(write_22words):
+	movl	%eax, -44(%edx)
+	movl	%eax, -40(%edx)
+L(write_18words):
+	movl	%eax, -36(%edx)
+	movl	%eax, -32(%edx)
+L(write_14words):
+	movl	%eax, -28(%edx)
+	movl	%eax, -24(%edx)
+L(write_10words):
+	movl	%eax, -20(%edx)
+	movl	%eax, -16(%edx)
+L(write_6words):
+	movl	%eax, -12(%edx)
+	movl	%eax, -8(%edx)
+L(write_2words):
+	movl	%eax, -4(%edx)
+	SETRTNVAL
+	RETURN
+
+	ALIGN (4)
+L(write_31words):
+	movl	%eax, -62(%edx)
+	movl	%eax, -58(%edx)
+L(write_27words):
+	movl	%eax, -54(%edx)
+	movl	%eax, -50(%edx)
+L(write_23words):
+	movl	%eax, -46(%edx)
+	movl	%eax, -42(%edx)
+L(write_19words):
+	movl	%eax, -38(%edx)
+	movl	%eax, -34(%edx)
+L(write_15words):
+	movl	%eax, -30(%edx)
+	movl	%eax, -26(%edx)
+L(write_11words):
+	movl	%eax, -22(%edx)
+	movl	%eax, -18(%edx)
+L(write_7words):
+	movl	%eax, -14(%edx)
+	movl	%eax, -10(%edx)
+L(write_3words):
+	movl	%eax, -6(%edx)
+	movw	%ax, -2(%edx)
+	SETRTNVAL
+	RETURN
+
+	ALIGN (4)
+
+L(32wordsormore):
+	shl	$1, %ecx
+	test	$0x01, %edx
+	jz	L(aligned2bytes)
+	mov	%eax, (%edx)
+	mov	%eax, -4(%edx, %ecx)
+	sub	$2, %ecx
+	add	$1, %edx
+	rol	$8, %eax
+L(aligned2bytes):
+#ifdef USE_AS_BZERO16
+	pxor	%xmm0, %xmm0
+#else
+	movd	%eax, %xmm0
+	pshufd	$0, %xmm0, %xmm0
+#endif
+	testl	$0xf, %edx
+	jz	L(aligned_16)
+/* ECX > 32 and EDX is not 16 byte aligned.  */
+L(not_aligned_16):
+	movdqu	%xmm0, (%edx)
+	movl	%edx, %eax
+	and	$-16, %edx
+	add	$16, %edx
+	sub	%edx, %eax
+	add	%eax, %ecx
+	movd	%xmm0, %eax
+
+	ALIGN (4)
+L(aligned_16):
+	cmp	$128, %ecx
+	jae	L(128bytesormore)
+
+L(aligned_16_less128bytes):
+	add	%ecx, %edx
+	shr	$1, %ecx
+	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
+
+	ALIGN (4)
+L(128bytesormore):
+#ifdef SHARED_CACHE_SIZE
+	PUSH (%ebx)
+	mov	$SHARED_CACHE_SIZE, %ebx
+#else
+# if (defined SHARED || defined __PIC__)
+	call	__x86.get_pc_thunk.bx
+	add	$_GLOBAL_OFFSET_TABLE_, %ebx
+	mov	__x86_shared_cache_size@GOTOFF(%ebx), %ebx
+# else
+	PUSH (%ebx)
+	mov	__x86_shared_cache_size, %ebx
+# endif
+#endif
+	cmp	%ebx, %ecx
+	jae	L(128bytesormore_nt_start)
+
+
+#ifdef DATA_CACHE_SIZE
+	POP (%ebx)
+# define RESTORE_EBX_STATE CFI_PUSH (%ebx)
+	cmp	$DATA_CACHE_SIZE, %ecx
+#else
+# if (defined SHARED || defined __PIC__)
+#  define RESTORE_EBX_STATE
+	call	__x86.get_pc_thunk.bx
+	add	$_GLOBAL_OFFSET_TABLE_, %ebx
+	cmp	__x86_data_cache_size@GOTOFF(%ebx), %ecx
+# else
+	POP (%ebx)
+#  define RESTORE_EBX_STATE CFI_PUSH (%ebx)
+	cmp	__x86_data_cache_size, %ecx
+# endif
+#endif
+
+	jae	L(128bytes_L2_normal)
+	subl	$128, %ecx
+L(128bytesormore_normal):
+	sub	$128, %ecx
+	movdqa	%xmm0, (%edx)
+	movdqa	%xmm0, 0x10(%edx)
+	movdqa	%xmm0, 0x20(%edx)
+	movdqa	%xmm0, 0x30(%edx)
+	movdqa	%xmm0, 0x40(%edx)
+	movdqa	%xmm0, 0x50(%edx)
+	movdqa	%xmm0, 0x60(%edx)
+	movdqa	%xmm0, 0x70(%edx)
+	lea	128(%edx), %edx
+	jb	L(128bytesless_normal)
+
+
+	sub	$128, %ecx
+	movdqa	%xmm0, (%edx)
+	movdqa	%xmm0, 0x10(%edx)
+	movdqa	%xmm0, 0x20(%edx)
+	movdqa	%xmm0, 0x30(%edx)
+	movdqa	%xmm0, 0x40(%edx)
+	movdqa	%xmm0, 0x50(%edx)
+	movdqa	%xmm0, 0x60(%edx)
+	movdqa	%xmm0, 0x70(%edx)
+	lea	128(%edx), %edx
+	jae	L(128bytesormore_normal)
+
+L(128bytesless_normal):
+	lea	128(%ecx), %ecx
+	add	%ecx, %edx
+	shr	$1, %ecx
+	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
+
+	ALIGN (4)
+L(128bytes_L2_normal):
+	prefetcht0	0x380(%edx)
+	prefetcht0	0x3c0(%edx)
+	sub	$128, %ecx
+	movdqa	%xmm0, (%edx)
+	movaps	%xmm0, 0x10(%edx)
+	movaps	%xmm0, 0x20(%edx)
+	movaps	%xmm0, 0x30(%edx)
+	movaps	%xmm0, 0x40(%edx)
+	movaps	%xmm0, 0x50(%edx)
+	movaps	%xmm0, 0x60(%edx)
+	movaps	%xmm0, 0x70(%edx)
+	add	$128, %edx
+	cmp	$128, %ecx
+	jae	L(128bytes_L2_normal)
+
+L(128bytesless_L2_normal):
+	add	%ecx, %edx
+	shr	$1, %ecx
+	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
+
+	RESTORE_EBX_STATE
+L(128bytesormore_nt_start):
+	sub	%ebx, %ecx
+	mov	%ebx, %eax
+	and	$0x7f, %eax
+	add	%eax, %ecx
+	movd	%xmm0, %eax
+	ALIGN (4)
+L(128bytesormore_shared_cache_loop):
+	prefetcht0	0x3c0(%edx)
+	prefetcht0	0x380(%edx)
+	sub	$0x80, %ebx
+	movdqa	%xmm0, (%edx)
+	movdqa	%xmm0, 0x10(%edx)
+	movdqa	%xmm0, 0x20(%edx)
+	movdqa	%xmm0, 0x30(%edx)
+	movdqa	%xmm0, 0x40(%edx)
+	movdqa	%xmm0, 0x50(%edx)
+	movdqa	%xmm0, 0x60(%edx)
+	movdqa	%xmm0, 0x70(%edx)
+	add	$0x80, %edx
+	cmp	$0x80, %ebx
+	jae	L(128bytesormore_shared_cache_loop)
+	cmp	$0x80, %ecx
+	jb	L(shared_cache_loop_end)
+	ALIGN (4)
+L(128bytesormore_nt):
+	sub	$0x80, %ecx
+	movntdq	%xmm0, (%edx)
+	movntdq	%xmm0, 0x10(%edx)
+	movntdq	%xmm0, 0x20(%edx)
+	movntdq	%xmm0, 0x30(%edx)
+	movntdq	%xmm0, 0x40(%edx)
+	movntdq	%xmm0, 0x50(%edx)
+	movntdq	%xmm0, 0x60(%edx)
+	movntdq	%xmm0, 0x70(%edx)
+	add	$0x80, %edx
+	cmp	$0x80, %ecx
+	jae	L(128bytesormore_nt)
+	sfence
+L(shared_cache_loop_end):
+#if defined DATA_CACHE_SIZE || !(defined SHARED || defined __PIC__)
+	POP (%ebx)
+#endif
+	add	%ecx, %edx
+	shr	$1, %ecx
+	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
+
+
+	.pushsection .rodata.sse2,"a",@progbits
+	ALIGN (2)
+L(table_16_128bytes):
+	.int	JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_2bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_6bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_10bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_14bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_18bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_22bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_26bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_30bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_34bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_38bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_42bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_46bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_50bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_54bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_58bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_62bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_66bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_70bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_74bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_78bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_82bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_86bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_90bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_94bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_98bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_102bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_106bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_110bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_114bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_118bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_122bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_126bytes), L(table_16_128bytes))
+	.popsection
+
+
+	ALIGN (4)
+L(aligned_16_112bytes):
+	movdqa	%xmm0, -112(%edx)
+L(aligned_16_96bytes):
+	movdqa	%xmm0, -96(%edx)
+L(aligned_16_80bytes):
+	movdqa	%xmm0, -80(%edx)
+L(aligned_16_64bytes):
+	movdqa	%xmm0, -64(%edx)
+L(aligned_16_48bytes):
+	movdqa	%xmm0, -48(%edx)
+L(aligned_16_32bytes):
+	movdqa	%xmm0, -32(%edx)
+L(aligned_16_16bytes):
+	movdqa	%xmm0, -16(%edx)
+L(aligned_16_0bytes):
+	SETRTNVAL
+	RETURN
+
+
+	ALIGN (4)
+L(aligned_16_114bytes):
+	movdqa	%xmm0, -114(%edx)
+L(aligned_16_98bytes):
+	movdqa	%xmm0, -98(%edx)
+L(aligned_16_82bytes):
+	movdqa	%xmm0, -82(%edx)
+L(aligned_16_66bytes):
+	movdqa	%xmm0, -66(%edx)
+L(aligned_16_50bytes):
+	movdqa	%xmm0, -50(%edx)
+L(aligned_16_34bytes):
+	movdqa	%xmm0, -34(%edx)
+L(aligned_16_18bytes):
+	movdqa	%xmm0, -18(%edx)
+L(aligned_16_2bytes):
+	movw	%ax, -2(%edx)
+	SETRTNVAL
+	RETURN
+
+	ALIGN (4)
+L(aligned_16_116bytes):
+	movdqa	%xmm0, -116(%edx)
+L(aligned_16_100bytes):
+	movdqa	%xmm0, -100(%edx)
+L(aligned_16_84bytes):
+	movdqa	%xmm0, -84(%edx)
+L(aligned_16_68bytes):
+	movdqa	%xmm0, -68(%edx)
+L(aligned_16_52bytes):
+	movdqa	%xmm0, -52(%edx)
+L(aligned_16_36bytes):
+	movdqa	%xmm0, -36(%edx)
+L(aligned_16_20bytes):
+	movdqa	%xmm0, -20(%edx)
+L(aligned_16_4bytes):
+	movl	%eax, -4(%edx)
+	SETRTNVAL
+	RETURN
+
+
+	ALIGN (4)
+L(aligned_16_118bytes):
+	movdqa	%xmm0, -118(%edx)
+L(aligned_16_102bytes):
+	movdqa	%xmm0, -102(%edx)
+L(aligned_16_86bytes):
+	movdqa	%xmm0, -86(%edx)
+L(aligned_16_70bytes):
+	movdqa	%xmm0, -70(%edx)
+L(aligned_16_54bytes):
+	movdqa	%xmm0, -54(%edx)
+L(aligned_16_38bytes):
+	movdqa	%xmm0, -38(%edx)
+L(aligned_16_22bytes):
+	movdqa	%xmm0, -22(%edx)
+L(aligned_16_6bytes):
+	movl	%eax, -6(%edx)
+	movw	%ax, -2(%edx)
+	SETRTNVAL
+	RETURN
+
+
+	ALIGN (4)
+L(aligned_16_120bytes):
+	movdqa	%xmm0, -120(%edx)
+L(aligned_16_104bytes):
+	movdqa	%xmm0, -104(%edx)
+L(aligned_16_88bytes):
+	movdqa	%xmm0, -88(%edx)
+L(aligned_16_72bytes):
+	movdqa	%xmm0, -72(%edx)
+L(aligned_16_56bytes):
+	movdqa	%xmm0, -56(%edx)
+L(aligned_16_40bytes):
+	movdqa	%xmm0, -40(%edx)
+L(aligned_16_24bytes):
+	movdqa	%xmm0, -24(%edx)
+L(aligned_16_8bytes):
+	movq	%xmm0, -8(%edx)
+	SETRTNVAL
+	RETURN
+
+
+	ALIGN (4)
+L(aligned_16_122bytes):
+	movdqa	%xmm0, -122(%edx)
+L(aligned_16_106bytes):
+	movdqa	%xmm0, -106(%edx)
+L(aligned_16_90bytes):
+	movdqa	%xmm0, -90(%edx)
+L(aligned_16_74bytes):
+	movdqa	%xmm0, -74(%edx)
+L(aligned_16_58bytes):
+	movdqa	%xmm0, -58(%edx)
+L(aligned_16_42bytes):
+	movdqa	%xmm0, -42(%edx)
+L(aligned_16_26bytes):
+	movdqa	%xmm0, -26(%edx)
+L(aligned_16_10bytes):
+	movq	%xmm0, -10(%edx)
+	movw	%ax, -2(%edx)
+	SETRTNVAL
+	RETURN
+
+
+	ALIGN (4)
+L(aligned_16_124bytes):
+	movdqa	%xmm0, -124(%edx)
+L(aligned_16_108bytes):
+	movdqa	%xmm0, -108(%edx)
+L(aligned_16_92bytes):
+	movdqa	%xmm0, -92(%edx)
+L(aligned_16_76bytes):
+	movdqa	%xmm0, -76(%edx)
+L(aligned_16_60bytes):
+	movdqa	%xmm0, -60(%edx)
+L(aligned_16_44bytes):
+	movdqa	%xmm0, -44(%edx)
+L(aligned_16_28bytes):
+	movdqa	%xmm0, -28(%edx)
+L(aligned_16_12bytes):
+	movq	%xmm0, -12(%edx)
+	movl	%eax, -4(%edx)
+	SETRTNVAL
+	RETURN
+
+
+	ALIGN (4)
+L(aligned_16_126bytes):
+	movdqa	%xmm0, -126(%edx)
+L(aligned_16_110bytes):
+	movdqa	%xmm0, -110(%edx)
+L(aligned_16_94bytes):
+	movdqa	%xmm0, -94(%edx)
+L(aligned_16_78bytes):
+	movdqa	%xmm0, -78(%edx)
+L(aligned_16_62bytes):
+	movdqa	%xmm0, -62(%edx)
+L(aligned_16_46bytes):
+	movdqa	%xmm0, -46(%edx)
+L(aligned_16_30bytes):
+	movdqa	%xmm0, -30(%edx)
+L(aligned_16_14bytes):
+	movq	%xmm0, -14(%edx)
+	movl	%eax, -6(%edx)
+	movw	%ax, -2(%edx)
+	SETRTNVAL
+	RETURN
+
+END (MEMSET)
diff --git a/libcutils/arch-x86/android_memset32.S b/libcutils/arch-x86/android_memset32.S
old mode 100644
new mode 100755
index 6249fce..f4326dc
--- a/libcutils/arch-x86/android_memset32.S
+++ b/libcutils/arch-x86/android_memset32.S
@@ -13,13 +13,498 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-/*
- * Contributed by: Intel Corporation
- */
 
-# include "cache_wrapper.S"
-# undef __i686
-# define USE_AS_ANDROID
-# define sse2_memset32_atom android_memset32
-# include "sse2-memset32-atom.S"
+#include "cache.h"
 
+#ifndef MEMSET
+# define MEMSET 	android_memset32
+#endif
+
+#ifndef L
+# define L(label)	.L##label
+#endif
+
+#ifndef ALIGN
+# define ALIGN(n)	.p2align n
+#endif
+
+#ifndef cfi_startproc
+# define cfi_startproc			.cfi_startproc
+#endif
+
+#ifndef cfi_endproc
+# define cfi_endproc			.cfi_endproc
+#endif
+
+#ifndef cfi_rel_offset
+# define cfi_rel_offset(reg, off)	.cfi_rel_offset reg, off
+#endif
+
+#ifndef cfi_restore
+# define cfi_restore(reg)		.cfi_restore reg
+#endif
+
+#ifndef cfi_adjust_cfa_offset
+# define cfi_adjust_cfa_offset(off)	.cfi_adjust_cfa_offset off
+#endif
+
+#ifndef ENTRY
+# define ENTRY(name)			\
+	.type name,  @function; 	\
+	.globl name;			\
+	.p2align 4;			\
+name:					\
+	cfi_startproc
+#endif
+
+#ifndef END
+# define END(name)			\
+	cfi_endproc;			\
+	.size name, .-name
+#endif
+
+#define CFI_PUSH(REG)						\
+  cfi_adjust_cfa_offset (4);					\
+  cfi_rel_offset (REG, 0)
+
+#define CFI_POP(REG)						\
+  cfi_adjust_cfa_offset (-4);					\
+  cfi_restore (REG)
+
+#define PUSH(REG)	pushl REG; CFI_PUSH (REG)
+#define POP(REG)	popl REG; CFI_POP (REG)
+
+#ifdef USE_AS_BZERO32
+# define DEST		PARMS
+# define LEN		DEST+4
+# define SETRTNVAL
+#else
+# define DEST		PARMS
+# define DWDS		DEST+4
+# define LEN		DWDS+4
+# define SETRTNVAL	movl DEST(%esp), %eax
+#endif
+
+#if (defined SHARED || defined __PIC__)
+# define ENTRANCE	PUSH (%ebx);
+# define RETURN_END	POP (%ebx); ret
+# define RETURN		RETURN_END; CFI_PUSH (%ebx)
+# define PARMS		8		/* Preserve EBX.  */
+# define JMPTBL(I, B)	I - B
+
+/* Load an entry in a jump table into EBX and branch to it.  TABLE is a
+   jump table with relative offsets.   */
+# define BRANCH_TO_JMPTBL_ENTRY(TABLE)				\
+    /* We first load PC into EBX.  */				\
+    call	__x86.get_pc_thunk.bx;				\
+    /* Get the address of the jump table.  */			\
+    add		$(TABLE - .), %ebx;				\
+    /* Get the entry and convert the relative offset to the	\
+       absolute address.  */					\
+    add		(%ebx,%ecx,4), %ebx;				\
+    /* We loaded the jump table and adjuested EDX. Go.  */	\
+    jmp		*%ebx
+
+	.section	.gnu.linkonce.t.__x86.get_pc_thunk.bx,"ax",@progbits
+	.globl	__x86.get_pc_thunk.bx
+	.hidden	__x86.get_pc_thunk.bx
+	ALIGN (4)
+	.type	__x86.get_pc_thunk.bx,@function
+__x86.get_pc_thunk.bx:
+	movl	(%esp), %ebx
+	ret
+#else
+# define ENTRANCE
+# define RETURN_END	ret
+# define RETURN		RETURN_END
+# define PARMS		4
+# define JMPTBL(I, B)	I
+
+/* Branch to an entry in a jump table.  TABLE is a jump table with
+   absolute offsets.  */
+# define BRANCH_TO_JMPTBL_ENTRY(TABLE)				\
+    jmp		*TABLE(,%ecx,4)
+#endif
+
+	.section .text.sse2,"ax",@progbits
+	ALIGN (4)
+ENTRY (MEMSET)
+	ENTRANCE
+
+	movl	LEN(%esp), %ecx
+	shr     $2, %ecx
+#ifdef USE_AS_BZERO32
+	xor	%eax, %eax
+#else
+	mov	DWDS(%esp), %eax
+	mov	%eax, %edx
+#endif
+	movl	DEST(%esp), %edx
+	cmp	$16, %ecx
+	jae	L(16dbwordsormore)
+
+L(write_less16dbwords):
+	lea	(%edx, %ecx, 4), %edx
+	BRANCH_TO_JMPTBL_ENTRY (L(table_less16dbwords))
+
+	.pushsection .rodata.sse2,"a",@progbits
+	ALIGN (2)
+L(table_less16dbwords):
+	.int	JMPTBL (L(write_0dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_1dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_2dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_3dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_4dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_5dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_6dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_7dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_8dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_9dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_10dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_11dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_12dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_13dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_14dbwords), L(table_less16dbwords))
+	.int	JMPTBL (L(write_15dbwords), L(table_less16dbwords))
+	.popsection
+
+	ALIGN (4)
+L(write_15dbwords):
+	movl	%eax, -60(%edx)
+L(write_14dbwords):
+	movl	%eax, -56(%edx)
+L(write_13dbwords):
+	movl	%eax, -52(%edx)
+L(write_12dbwords):
+	movl	%eax, -48(%edx)
+L(write_11dbwords):
+	movl	%eax, -44(%edx)
+L(write_10dbwords):
+	movl	%eax, -40(%edx)
+L(write_9dbwords):
+	movl	%eax, -36(%edx)
+L(write_8dbwords):
+	movl	%eax, -32(%edx)
+L(write_7dbwords):
+	movl	%eax, -28(%edx)
+L(write_6dbwords):
+	movl	%eax, -24(%edx)
+L(write_5dbwords):
+	movl	%eax, -20(%edx)
+L(write_4dbwords):
+	movl	%eax, -16(%edx)
+L(write_3dbwords):
+	movl	%eax, -12(%edx)
+L(write_2dbwords):
+	movl	%eax, -8(%edx)
+L(write_1dbwords):
+	movl	%eax, -4(%edx)
+L(write_0dbwords):
+	SETRTNVAL
+	RETURN
+
+	ALIGN (4)
+L(16dbwordsormore):
+	test	$3, %edx
+	jz	L(aligned4bytes)
+	mov	%eax, (%edx)
+	mov	%eax, -4(%edx, %ecx, 4)
+	sub	$1, %ecx
+	rol	$24, %eax
+	add	$1, %edx
+	test	$3, %edx
+	jz	L(aligned4bytes)
+	ror	$8, %eax
+	add	$1, %edx
+	test	$3, %edx
+	jz	L(aligned4bytes)
+	ror	$8, %eax
+	add	$1, %edx
+L(aligned4bytes):
+	shl	$2, %ecx
+
+#ifdef USE_AS_BZERO32
+	pxor	%xmm0, %xmm0
+#else
+	movd	%eax, %xmm0
+	pshufd	$0, %xmm0, %xmm0
+#endif
+	testl	$0xf, %edx
+	jz	L(aligned_16)
+/* ECX > 32 and EDX is not 16 byte aligned.  */
+L(not_aligned_16):
+	movdqu	%xmm0, (%edx)
+	movl	%edx, %eax
+	and	$-16, %edx
+	add	$16, %edx
+	sub	%edx, %eax
+	add	%eax, %ecx
+	movd	%xmm0, %eax
+	ALIGN (4)
+L(aligned_16):
+	cmp	$128, %ecx
+	jae	L(128bytesormore)
+
+L(aligned_16_less128bytes):
+	add	%ecx, %edx
+	shr	$2, %ecx
+	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
+
+	ALIGN (4)
+L(128bytesormore):
+#ifdef SHARED_CACHE_SIZE
+	PUSH (%ebx)
+	mov	$SHARED_CACHE_SIZE, %ebx
+#else
+# if (defined SHARED || defined __PIC__)
+	call	__x86.get_pc_thunk.bx
+	add	$_GLOBAL_OFFSET_TABLE_, %ebx
+	mov	__x86_shared_cache_size@GOTOFF(%ebx), %ebx
+# else
+	PUSH (%ebx)
+	mov	__x86_shared_cache_size, %ebx
+# endif
+#endif
+	cmp	%ebx, %ecx
+	jae	L(128bytesormore_nt_start)
+
+#ifdef DATA_CACHE_SIZE
+	POP (%ebx)
+# define RESTORE_EBX_STATE CFI_PUSH (%ebx)
+	cmp	$DATA_CACHE_SIZE, %ecx
+#else
+# if (defined SHARED || defined __PIC__)
+#  define RESTORE_EBX_STATE
+	call	__x86.get_pc_thunk.bx
+	add	$_GLOBAL_OFFSET_TABLE_, %ebx
+	cmp	__x86_data_cache_size@GOTOFF(%ebx), %ecx
+# else
+	POP (%ebx)
+#  define RESTORE_EBX_STATE CFI_PUSH (%ebx)
+	cmp	__x86_data_cache_size, %ecx
+# endif
+#endif
+
+	jae	L(128bytes_L2_normal)
+	subl	$128, %ecx
+L(128bytesormore_normal):
+	sub	$128, %ecx
+	movdqa	%xmm0, (%edx)
+	movdqa	%xmm0, 0x10(%edx)
+	movdqa	%xmm0, 0x20(%edx)
+	movdqa	%xmm0, 0x30(%edx)
+	movdqa	%xmm0, 0x40(%edx)
+	movdqa	%xmm0, 0x50(%edx)
+	movdqa	%xmm0, 0x60(%edx)
+	movdqa	%xmm0, 0x70(%edx)
+	lea	128(%edx), %edx
+	jb	L(128bytesless_normal)
+
+
+	sub	$128, %ecx
+	movdqa	%xmm0, (%edx)
+	movdqa	%xmm0, 0x10(%edx)
+	movdqa	%xmm0, 0x20(%edx)
+	movdqa	%xmm0, 0x30(%edx)
+	movdqa	%xmm0, 0x40(%edx)
+	movdqa	%xmm0, 0x50(%edx)
+	movdqa	%xmm0, 0x60(%edx)
+	movdqa	%xmm0, 0x70(%edx)
+	lea	128(%edx), %edx
+	jae	L(128bytesormore_normal)
+
+L(128bytesless_normal):
+	lea	128(%ecx), %ecx
+	add	%ecx, %edx
+	shr	$2, %ecx
+	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
+
+	ALIGN (4)
+L(128bytes_L2_normal):
+	prefetcht0	0x380(%edx)
+	prefetcht0	0x3c0(%edx)
+	sub	$128, %ecx
+	movdqa	%xmm0, (%edx)
+	movaps	%xmm0, 0x10(%edx)
+	movaps	%xmm0, 0x20(%edx)
+	movaps	%xmm0, 0x30(%edx)
+	movaps	%xmm0, 0x40(%edx)
+	movaps	%xmm0, 0x50(%edx)
+	movaps	%xmm0, 0x60(%edx)
+	movaps	%xmm0, 0x70(%edx)
+	add	$128, %edx
+	cmp	$128, %ecx
+	jae	L(128bytes_L2_normal)
+
+L(128bytesless_L2_normal):
+	add	%ecx, %edx
+	shr	$2, %ecx
+	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
+
+	RESTORE_EBX_STATE
+L(128bytesormore_nt_start):
+	sub	%ebx, %ecx
+	mov	%ebx, %eax
+	and	$0x7f, %eax
+	add	%eax, %ecx
+	movd	%xmm0, %eax
+	ALIGN (4)
+L(128bytesormore_shared_cache_loop):
+	prefetcht0	0x3c0(%edx)
+	prefetcht0	0x380(%edx)
+	sub	$0x80, %ebx
+	movdqa	%xmm0, (%edx)
+	movdqa	%xmm0, 0x10(%edx)
+	movdqa	%xmm0, 0x20(%edx)
+	movdqa	%xmm0, 0x30(%edx)
+	movdqa	%xmm0, 0x40(%edx)
+	movdqa	%xmm0, 0x50(%edx)
+	movdqa	%xmm0, 0x60(%edx)
+	movdqa	%xmm0, 0x70(%edx)
+	add	$0x80, %edx
+	cmp	$0x80, %ebx
+	jae	L(128bytesormore_shared_cache_loop)
+	cmp	$0x80, %ecx
+	jb	L(shared_cache_loop_end)
+
+	ALIGN (4)
+L(128bytesormore_nt):
+	sub	$0x80, %ecx
+	movntdq	%xmm0, (%edx)
+	movntdq	%xmm0, 0x10(%edx)
+	movntdq	%xmm0, 0x20(%edx)
+	movntdq	%xmm0, 0x30(%edx)
+	movntdq	%xmm0, 0x40(%edx)
+	movntdq	%xmm0, 0x50(%edx)
+	movntdq	%xmm0, 0x60(%edx)
+	movntdq	%xmm0, 0x70(%edx)
+	add	$0x80, %edx
+	cmp	$0x80, %ecx
+	jae	L(128bytesormore_nt)
+	sfence
+L(shared_cache_loop_end):
+#if defined DATA_CACHE_SIZE || !(defined SHARED || defined __PIC__)
+	POP (%ebx)
+#endif
+	add	%ecx, %edx
+	shr	$2, %ecx
+	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
+
+	.pushsection .rodata.sse2,"a",@progbits
+	ALIGN (2)
+L(table_16_128bytes):
+	.int	JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes))
+	.int	JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes))
+	.popsection
+
+	ALIGN (4)
+L(aligned_16_112bytes):
+	movdqa	%xmm0, -112(%edx)
+L(aligned_16_96bytes):
+	movdqa	%xmm0, -96(%edx)
+L(aligned_16_80bytes):
+	movdqa	%xmm0, -80(%edx)
+L(aligned_16_64bytes):
+	movdqa	%xmm0, -64(%edx)
+L(aligned_16_48bytes):
+	movdqa	%xmm0, -48(%edx)
+L(aligned_16_32bytes):
+	movdqa	%xmm0, -32(%edx)
+L(aligned_16_16bytes):
+	movdqa	%xmm0, -16(%edx)
+L(aligned_16_0bytes):
+	SETRTNVAL
+	RETURN
+
+	ALIGN (4)
+L(aligned_16_116bytes):
+	movdqa	%xmm0, -116(%edx)
+L(aligned_16_100bytes):
+	movdqa	%xmm0, -100(%edx)
+L(aligned_16_84bytes):
+	movdqa	%xmm0, -84(%edx)
+L(aligned_16_68bytes):
+	movdqa	%xmm0, -68(%edx)
+L(aligned_16_52bytes):
+	movdqa	%xmm0, -52(%edx)
+L(aligned_16_36bytes):
+	movdqa	%xmm0, -36(%edx)
+L(aligned_16_20bytes):
+	movdqa	%xmm0, -20(%edx)
+L(aligned_16_4bytes):
+	movl	%eax, -4(%edx)
+	SETRTNVAL
+	RETURN
+
+	ALIGN (4)
+L(aligned_16_120bytes):
+	movdqa	%xmm0, -120(%edx)
+L(aligned_16_104bytes):
+	movdqa	%xmm0, -104(%edx)
+L(aligned_16_88bytes):
+	movdqa	%xmm0, -88(%edx)
+L(aligned_16_72bytes):
+	movdqa	%xmm0, -72(%edx)
+L(aligned_16_56bytes):
+	movdqa	%xmm0, -56(%edx)
+L(aligned_16_40bytes):
+	movdqa	%xmm0, -40(%edx)
+L(aligned_16_24bytes):
+	movdqa	%xmm0, -24(%edx)
+L(aligned_16_8bytes):
+	movq	%xmm0, -8(%edx)
+	SETRTNVAL
+	RETURN
+
+	ALIGN (4)
+L(aligned_16_124bytes):
+	movdqa	%xmm0, -124(%edx)
+L(aligned_16_108bytes):
+	movdqa	%xmm0, -108(%edx)
+L(aligned_16_92bytes):
+	movdqa	%xmm0, -92(%edx)
+L(aligned_16_76bytes):
+	movdqa	%xmm0, -76(%edx)
+L(aligned_16_60bytes):
+	movdqa	%xmm0, -60(%edx)
+L(aligned_16_44bytes):
+	movdqa	%xmm0, -44(%edx)
+L(aligned_16_28bytes):
+	movdqa	%xmm0, -28(%edx)
+L(aligned_16_12bytes):
+	movq	%xmm0, -12(%edx)
+	movl	%eax, -4(%edx)
+	SETRTNVAL
+	RETURN
+
+END (MEMSET)
diff --git a/libcutils/arch-x86/cache_wrapper.S b/libcutils/arch-x86/cache.h
similarity index 95%
rename from libcutils/arch-x86/cache_wrapper.S
rename to libcutils/arch-x86/cache.h
index 9eee25c..1c22fea 100644
--- a/libcutils/arch-x86/cache_wrapper.S
+++ b/libcutils/arch-x86/cache.h
@@ -13,9 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-/*
- * Contributed by: Intel Corporation
- */
 
 #if defined(__slm__)
 /* Values are optimized for Silvermont */
diff --git a/libcutils/arch-x86/sse2-memset16-atom.S b/libcutils/arch-x86/sse2-memset16-atom.S
deleted file mode 100755
index c2a762b..0000000
--- a/libcutils/arch-x86/sse2-memset16-atom.S
+++ /dev/null
@@ -1,722 +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.
- */
-/*
- * Contributed by: Intel Corporation
- */
-
-#ifndef L
-# define L(label)	.L##label
-#endif
-
-#ifndef ALIGN
-# define ALIGN(n)	.p2align n
-#endif
-
-#ifndef cfi_startproc
-# define cfi_startproc			.cfi_startproc
-#endif
-
-#ifndef cfi_endproc
-# define cfi_endproc			.cfi_endproc
-#endif
-
-#ifndef cfi_rel_offset
-# define cfi_rel_offset(reg, off)	.cfi_rel_offset reg, off
-#endif
-
-#ifndef cfi_restore
-# define cfi_restore(reg)		.cfi_restore reg
-#endif
-
-#ifndef cfi_adjust_cfa_offset
-# define cfi_adjust_cfa_offset(off)	.cfi_adjust_cfa_offset off
-#endif
-
-#ifndef ENTRY
-# define ENTRY(name)			\
-	.type name,  @function; 	\
-	.globl name;			\
-	.p2align 4;			\
-name:					\
-	cfi_startproc
-#endif
-
-#ifndef END
-# define END(name)			\
-	cfi_endproc;			\
-	.size name, .-name
-#endif
-
-#define CFI_PUSH(REG)						\
-  cfi_adjust_cfa_offset (4);					\
-  cfi_rel_offset (REG, 0)
-
-#define CFI_POP(REG)						\
-  cfi_adjust_cfa_offset (-4);					\
-  cfi_restore (REG)
-
-#define PUSH(REG)	pushl REG; CFI_PUSH (REG)
-#define POP(REG)	popl REG; CFI_POP (REG)
-
-#ifdef USE_AS_BZERO16
-# define DEST		PARMS
-# define LEN		DEST+4
-#else
-# define DEST		PARMS
-# define CHR		DEST+4
-# define LEN		CHR+4
-#endif
-
-#if 1
-# define SETRTNVAL
-#else
-# define SETRTNVAL	movl DEST(%esp), %eax
-#endif
-
-#if (defined SHARED || defined __PIC__)
-# define ENTRANCE	PUSH (%ebx);
-# define RETURN_END	POP (%ebx); ret
-# define RETURN		RETURN_END; CFI_PUSH (%ebx)
-# define PARMS		8		/* Preserve EBX.  */
-# define JMPTBL(I, B)	I - B
-
-/* Load an entry in a jump table into EBX and branch to it.  TABLE is a
-   jump table with relative offsets.   */
-# define BRANCH_TO_JMPTBL_ENTRY(TABLE)				\
-    /* We first load PC into EBX.  */				\
-    call	__i686.get_pc_thunk.bx;				\
-    /* Get the address of the jump table.  */			\
-    add		$(TABLE - .), %ebx;				\
-    /* Get the entry and convert the relative offset to the	\
-       absolute address.  */					\
-    add		(%ebx,%ecx,4), %ebx;				\
-    /* We loaded the jump table and adjuested EDX. Go.  */	\
-    jmp		*%ebx
-
-	.section	.gnu.linkonce.t.__i686.get_pc_thunk.bx,"ax",@progbits
-	.globl	__i686.get_pc_thunk.bx
-	.hidden	__i686.get_pc_thunk.bx
-	ALIGN (4)
-	.type	__i686.get_pc_thunk.bx,@function
-__i686.get_pc_thunk.bx:
-	movl	(%esp), %ebx
-	ret
-#else
-# define ENTRANCE
-# define RETURN_END	ret
-# define RETURN		RETURN_END
-# define PARMS		4
-# define JMPTBL(I, B)	I
-
-/* Branch to an entry in a jump table.  TABLE is a jump table with
-   absolute offsets.  */
-# define BRANCH_TO_JMPTBL_ENTRY(TABLE)				\
-    jmp		*TABLE(,%ecx,4)
-#endif
-
-	.section .text.sse2,"ax",@progbits
-	ALIGN (4)
-ENTRY (sse2_memset16_atom)
-	ENTRANCE
-
-	movl	LEN(%esp), %ecx
-#ifdef USE_AS_ANDROID
-	shr	$1, %ecx
-#endif
-#ifdef USE_AS_BZERO16
-	xor	%eax, %eax
-#else
-	movzwl	CHR(%esp), %eax
-	mov	%eax, %edx
-	shl	$16, %eax
-	or	%edx, %eax
-#endif
-	movl	DEST(%esp), %edx
-	cmp	$32, %ecx
-	jae	L(32wordsormore)
-
-L(write_less32words):
-	lea	(%edx, %ecx, 2), %edx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_less32words))
-
-
-	.pushsection .rodata.sse2,"a",@progbits
-	ALIGN (2)
-L(table_less32words):
-	.int	JMPTBL (L(write_0words), L(table_less32words))
-	.int	JMPTBL (L(write_1words), L(table_less32words))
-	.int	JMPTBL (L(write_2words), L(table_less32words))
-	.int	JMPTBL (L(write_3words), L(table_less32words))
-	.int	JMPTBL (L(write_4words), L(table_less32words))
-	.int	JMPTBL (L(write_5words), L(table_less32words))
-	.int	JMPTBL (L(write_6words), L(table_less32words))
-	.int	JMPTBL (L(write_7words), L(table_less32words))
-	.int	JMPTBL (L(write_8words), L(table_less32words))
-	.int	JMPTBL (L(write_9words), L(table_less32words))
-	.int	JMPTBL (L(write_10words), L(table_less32words))
-	.int	JMPTBL (L(write_11words), L(table_less32words))
-	.int	JMPTBL (L(write_12words), L(table_less32words))
-	.int	JMPTBL (L(write_13words), L(table_less32words))
-	.int	JMPTBL (L(write_14words), L(table_less32words))
-	.int	JMPTBL (L(write_15words), L(table_less32words))
-	.int	JMPTBL (L(write_16words), L(table_less32words))
-	.int	JMPTBL (L(write_17words), L(table_less32words))
-	.int	JMPTBL (L(write_18words), L(table_less32words))
-	.int	JMPTBL (L(write_19words), L(table_less32words))
-	.int	JMPTBL (L(write_20words), L(table_less32words))
-	.int	JMPTBL (L(write_21words), L(table_less32words))
-	.int	JMPTBL (L(write_22words), L(table_less32words))
-	.int	JMPTBL (L(write_23words), L(table_less32words))
-	.int	JMPTBL (L(write_24words), L(table_less32words))
-	.int	JMPTBL (L(write_25words), L(table_less32words))
-	.int	JMPTBL (L(write_26words), L(table_less32words))
-	.int	JMPTBL (L(write_27words), L(table_less32words))
-	.int	JMPTBL (L(write_28words), L(table_less32words))
-	.int	JMPTBL (L(write_29words), L(table_less32words))
-	.int	JMPTBL (L(write_30words), L(table_less32words))
-	.int	JMPTBL (L(write_31words), L(table_less32words))
-	.popsection
-
-	ALIGN (4)
-L(write_28words):
-	movl	%eax, -56(%edx)
-	movl	%eax, -52(%edx)
-L(write_24words):
-	movl	%eax, -48(%edx)
-	movl	%eax, -44(%edx)
-L(write_20words):
-	movl	%eax, -40(%edx)
-	movl	%eax, -36(%edx)
-L(write_16words):
-	movl	%eax, -32(%edx)
-	movl	%eax, -28(%edx)
-L(write_12words):
-	movl	%eax, -24(%edx)
-	movl	%eax, -20(%edx)
-L(write_8words):
-	movl	%eax, -16(%edx)
-	movl	%eax, -12(%edx)
-L(write_4words):
-	movl	%eax, -8(%edx)
-	movl	%eax, -4(%edx)
-L(write_0words):
-	SETRTNVAL
-	RETURN
-
-	ALIGN (4)
-L(write_29words):
-	movl	%eax, -58(%edx)
-	movl	%eax, -54(%edx)
-L(write_25words):
-	movl	%eax, -50(%edx)
-	movl	%eax, -46(%edx)
-L(write_21words):
-	movl	%eax, -42(%edx)
-	movl	%eax, -38(%edx)
-L(write_17words):
-	movl	%eax, -34(%edx)
-	movl	%eax, -30(%edx)
-L(write_13words):
-	movl	%eax, -26(%edx)
-	movl	%eax, -22(%edx)
-L(write_9words):
-	movl	%eax, -18(%edx)
-	movl	%eax, -14(%edx)
-L(write_5words):
-	movl	%eax, -10(%edx)
-	movl	%eax, -6(%edx)
-L(write_1words):
-	mov	%ax, -2(%edx)
-	SETRTNVAL
-	RETURN
-
-	ALIGN (4)
-L(write_30words):
-	movl	%eax, -60(%edx)
-	movl	%eax, -56(%edx)
-L(write_26words):
-	movl	%eax, -52(%edx)
-	movl	%eax, -48(%edx)
-L(write_22words):
-	movl	%eax, -44(%edx)
-	movl	%eax, -40(%edx)
-L(write_18words):
-	movl	%eax, -36(%edx)
-	movl	%eax, -32(%edx)
-L(write_14words):
-	movl	%eax, -28(%edx)
-	movl	%eax, -24(%edx)
-L(write_10words):
-	movl	%eax, -20(%edx)
-	movl	%eax, -16(%edx)
-L(write_6words):
-	movl	%eax, -12(%edx)
-	movl	%eax, -8(%edx)
-L(write_2words):
-	movl	%eax, -4(%edx)
-	SETRTNVAL
-	RETURN
-
-	ALIGN (4)
-L(write_31words):
-	movl	%eax, -62(%edx)
-	movl	%eax, -58(%edx)
-L(write_27words):
-	movl	%eax, -54(%edx)
-	movl	%eax, -50(%edx)
-L(write_23words):
-	movl	%eax, -46(%edx)
-	movl	%eax, -42(%edx)
-L(write_19words):
-	movl	%eax, -38(%edx)
-	movl	%eax, -34(%edx)
-L(write_15words):
-	movl	%eax, -30(%edx)
-	movl	%eax, -26(%edx)
-L(write_11words):
-	movl	%eax, -22(%edx)
-	movl	%eax, -18(%edx)
-L(write_7words):
-	movl	%eax, -14(%edx)
-	movl	%eax, -10(%edx)
-L(write_3words):
-	movl	%eax, -6(%edx)
-	movw	%ax, -2(%edx)
-	SETRTNVAL
-	RETURN
-
-	ALIGN (4)
-
-L(32wordsormore):
-	shl	$1, %ecx
-	test	$0x01, %edx
-	jz	L(aligned2bytes)
-	mov	%eax, (%edx)
-	mov	%eax, -4(%edx, %ecx)
-	sub	$2, %ecx
-	add	$1, %edx
-	rol	$8, %eax
-L(aligned2bytes):
-#ifdef USE_AS_BZERO16
-	pxor	%xmm0, %xmm0
-#else
-	movd	%eax, %xmm0
-	pshufd	$0, %xmm0, %xmm0
-#endif
-	testl	$0xf, %edx
-	jz	L(aligned_16)
-/* ECX > 32 and EDX is not 16 byte aligned.  */
-L(not_aligned_16):
-	movdqu	%xmm0, (%edx)
-	movl	%edx, %eax
-	and	$-16, %edx
-	add	$16, %edx
-	sub	%edx, %eax
-	add	%eax, %ecx
-	movd	%xmm0, %eax
-
-	ALIGN (4)
-L(aligned_16):
-	cmp	$128, %ecx
-	jae	L(128bytesormore)
-
-L(aligned_16_less128bytes):
-	add	%ecx, %edx
-	shr	$1, %ecx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
-	ALIGN (4)
-L(128bytesormore):
-#ifdef SHARED_CACHE_SIZE
-	PUSH (%ebx)
-	mov	$SHARED_CACHE_SIZE, %ebx
-#else
-# if (defined SHARED || defined __PIC__)
-	call	__i686.get_pc_thunk.bx
-	add	$_GLOBAL_OFFSET_TABLE_, %ebx
-	mov	__x86_shared_cache_size@GOTOFF(%ebx), %ebx
-# else
-	PUSH (%ebx)
-	mov	__x86_shared_cache_size, %ebx
-# endif
-#endif
-	cmp	%ebx, %ecx
-	jae	L(128bytesormore_nt_start)
-
-	
-#ifdef DATA_CACHE_SIZE
-	POP (%ebx)
-# define RESTORE_EBX_STATE CFI_PUSH (%ebx)
-	cmp	$DATA_CACHE_SIZE, %ecx
-#else
-# if (defined SHARED || defined __PIC__)
-#  define RESTORE_EBX_STATE
-	call	__i686.get_pc_thunk.bx
-	add	$_GLOBAL_OFFSET_TABLE_, %ebx
-	cmp	__x86_data_cache_size@GOTOFF(%ebx), %ecx
-# else
-	POP (%ebx)
-#  define RESTORE_EBX_STATE CFI_PUSH (%ebx)
-	cmp	__x86_data_cache_size, %ecx
-# endif
-#endif
-
-	jae	L(128bytes_L2_normal)
-	subl	$128, %ecx
-L(128bytesormore_normal):
-	sub	$128, %ecx
-	movdqa	%xmm0, (%edx)
-	movdqa	%xmm0, 0x10(%edx)
-	movdqa	%xmm0, 0x20(%edx)
-	movdqa	%xmm0, 0x30(%edx)
-	movdqa	%xmm0, 0x40(%edx)
-	movdqa	%xmm0, 0x50(%edx)
-	movdqa	%xmm0, 0x60(%edx)
-	movdqa	%xmm0, 0x70(%edx)
-	lea	128(%edx), %edx
-	jb	L(128bytesless_normal)
-
-
-	sub	$128, %ecx
-	movdqa	%xmm0, (%edx)
-	movdqa	%xmm0, 0x10(%edx)
-	movdqa	%xmm0, 0x20(%edx)
-	movdqa	%xmm0, 0x30(%edx)
-	movdqa	%xmm0, 0x40(%edx)
-	movdqa	%xmm0, 0x50(%edx)
-	movdqa	%xmm0, 0x60(%edx)
-	movdqa	%xmm0, 0x70(%edx)
-	lea	128(%edx), %edx
-	jae	L(128bytesormore_normal)
-
-L(128bytesless_normal):
-	lea	128(%ecx), %ecx
-	add	%ecx, %edx
-	shr	$1, %ecx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
-	ALIGN (4)
-L(128bytes_L2_normal):
-	prefetcht0	0x380(%edx)
-	prefetcht0	0x3c0(%edx)
-	sub	$128, %ecx
-	movdqa	%xmm0, (%edx)
-	movaps	%xmm0, 0x10(%edx)
-	movaps	%xmm0, 0x20(%edx)
-	movaps	%xmm0, 0x30(%edx)
-	movaps	%xmm0, 0x40(%edx)
-	movaps	%xmm0, 0x50(%edx)
-	movaps	%xmm0, 0x60(%edx)
-	movaps	%xmm0, 0x70(%edx)
-	add	$128, %edx
-	cmp	$128, %ecx 	
-	jae	L(128bytes_L2_normal)
-
-L(128bytesless_L2_normal):
-	add	%ecx, %edx
-	shr	$1, %ecx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
-	RESTORE_EBX_STATE
-L(128bytesormore_nt_start):
-	sub	%ebx, %ecx
-	mov	%ebx, %eax
-	and	$0x7f, %eax
-	add	%eax, %ecx
-	movd	%xmm0, %eax
-	ALIGN (4)
-L(128bytesormore_shared_cache_loop):
-	prefetcht0	0x3c0(%edx)
-	prefetcht0	0x380(%edx)
-	sub	$0x80, %ebx
-	movdqa	%xmm0, (%edx)
-	movdqa	%xmm0, 0x10(%edx)
-	movdqa	%xmm0, 0x20(%edx)
-	movdqa	%xmm0, 0x30(%edx)
-	movdqa	%xmm0, 0x40(%edx)
-	movdqa	%xmm0, 0x50(%edx)
-	movdqa	%xmm0, 0x60(%edx)
-	movdqa	%xmm0, 0x70(%edx)
-	add	$0x80, %edx
-	cmp	$0x80, %ebx
-	jae	L(128bytesormore_shared_cache_loop)
-	cmp	$0x80, %ecx
-	jb	L(shared_cache_loop_end)
-	ALIGN (4)
-L(128bytesormore_nt):
-	sub	$0x80, %ecx
-	movntdq	%xmm0, (%edx)
-	movntdq	%xmm0, 0x10(%edx)
-	movntdq	%xmm0, 0x20(%edx)
-	movntdq	%xmm0, 0x30(%edx)
-	movntdq	%xmm0, 0x40(%edx)
-	movntdq	%xmm0, 0x50(%edx)
-	movntdq	%xmm0, 0x60(%edx)
-	movntdq	%xmm0, 0x70(%edx)
-	add	$0x80, %edx
-	cmp	$0x80, %ecx
-	jae	L(128bytesormore_nt)
-	sfence
-L(shared_cache_loop_end):
-#if defined DATA_CACHE_SIZE || !(defined SHARED || defined __PIC__)
-	POP (%ebx)
-#endif
-	add	%ecx, %edx
-	shr	$1, %ecx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
-
-	.pushsection .rodata.sse2,"a",@progbits
-	ALIGN (2)
-L(table_16_128bytes):
-	.int	JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_2bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_6bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_10bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_14bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_18bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_22bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_26bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_30bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_34bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_38bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_42bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_46bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_50bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_54bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_58bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_62bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_66bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_70bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_74bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_78bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_82bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_86bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_90bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_94bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_98bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_102bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_106bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_110bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_114bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_118bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_122bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_126bytes), L(table_16_128bytes))
-	.popsection
-
-
-	ALIGN (4)
-L(aligned_16_112bytes):
-	movdqa	%xmm0, -112(%edx)
-L(aligned_16_96bytes):
-	movdqa	%xmm0, -96(%edx)
-L(aligned_16_80bytes):
-	movdqa	%xmm0, -80(%edx)
-L(aligned_16_64bytes):
-	movdqa	%xmm0, -64(%edx)
-L(aligned_16_48bytes):
-	movdqa	%xmm0, -48(%edx)
-L(aligned_16_32bytes):
-	movdqa	%xmm0, -32(%edx)
-L(aligned_16_16bytes):
-	movdqa	%xmm0, -16(%edx)
-L(aligned_16_0bytes):
-	SETRTNVAL
-	RETURN
-
-
-	ALIGN (4)
-L(aligned_16_114bytes):
-	movdqa	%xmm0, -114(%edx)
-L(aligned_16_98bytes):
-	movdqa	%xmm0, -98(%edx)
-L(aligned_16_82bytes):
-	movdqa	%xmm0, -82(%edx)
-L(aligned_16_66bytes):
-	movdqa	%xmm0, -66(%edx)
-L(aligned_16_50bytes):
-	movdqa	%xmm0, -50(%edx)
-L(aligned_16_34bytes):
-	movdqa	%xmm0, -34(%edx)
-L(aligned_16_18bytes):
-	movdqa	%xmm0, -18(%edx)
-L(aligned_16_2bytes):
-	movw	%ax, -2(%edx)
-	SETRTNVAL
-	RETURN
-
-	ALIGN (4)
-L(aligned_16_116bytes):
-	movdqa	%xmm0, -116(%edx)
-L(aligned_16_100bytes):
-	movdqa	%xmm0, -100(%edx)
-L(aligned_16_84bytes):
-	movdqa	%xmm0, -84(%edx)
-L(aligned_16_68bytes):
-	movdqa	%xmm0, -68(%edx)
-L(aligned_16_52bytes):
-	movdqa	%xmm0, -52(%edx)
-L(aligned_16_36bytes):
-	movdqa	%xmm0, -36(%edx)
-L(aligned_16_20bytes):
-	movdqa	%xmm0, -20(%edx)
-L(aligned_16_4bytes):
-	movl	%eax, -4(%edx)
-	SETRTNVAL
-	RETURN
-
-
-	ALIGN (4)
-L(aligned_16_118bytes):
-	movdqa	%xmm0, -118(%edx)
-L(aligned_16_102bytes):
-	movdqa	%xmm0, -102(%edx)
-L(aligned_16_86bytes):
-	movdqa	%xmm0, -86(%edx)
-L(aligned_16_70bytes):
-	movdqa	%xmm0, -70(%edx)
-L(aligned_16_54bytes):
-	movdqa	%xmm0, -54(%edx)
-L(aligned_16_38bytes):
-	movdqa	%xmm0, -38(%edx)
-L(aligned_16_22bytes):
-	movdqa	%xmm0, -22(%edx)
-L(aligned_16_6bytes):
-	movl	%eax, -6(%edx)
-	movw	%ax, -2(%edx)
-	SETRTNVAL
-	RETURN
-
-
-	ALIGN (4)
-L(aligned_16_120bytes):
-	movdqa	%xmm0, -120(%edx)
-L(aligned_16_104bytes):
-	movdqa	%xmm0, -104(%edx)
-L(aligned_16_88bytes):
-	movdqa	%xmm0, -88(%edx)
-L(aligned_16_72bytes):
-	movdqa	%xmm0, -72(%edx)
-L(aligned_16_56bytes):
-	movdqa	%xmm0, -56(%edx)
-L(aligned_16_40bytes):
-	movdqa	%xmm0, -40(%edx)
-L(aligned_16_24bytes):
-	movdqa	%xmm0, -24(%edx)
-L(aligned_16_8bytes):
-	movq	%xmm0, -8(%edx)
-	SETRTNVAL
-	RETURN
-
-
-	ALIGN (4)
-L(aligned_16_122bytes):
-	movdqa	%xmm0, -122(%edx)
-L(aligned_16_106bytes):
-	movdqa	%xmm0, -106(%edx)
-L(aligned_16_90bytes):
-	movdqa	%xmm0, -90(%edx)
-L(aligned_16_74bytes):
-	movdqa	%xmm0, -74(%edx)
-L(aligned_16_58bytes):
-	movdqa	%xmm0, -58(%edx)
-L(aligned_16_42bytes):
-	movdqa	%xmm0, -42(%edx)
-L(aligned_16_26bytes):
-	movdqa	%xmm0, -26(%edx)
-L(aligned_16_10bytes):
-	movq	%xmm0, -10(%edx)
-	movw	%ax, -2(%edx)
-	SETRTNVAL
-	RETURN
-
-
-	ALIGN (4)
-L(aligned_16_124bytes):
-	movdqa	%xmm0, -124(%edx)
-L(aligned_16_108bytes):
-	movdqa	%xmm0, -108(%edx)
-L(aligned_16_92bytes):
-	movdqa	%xmm0, -92(%edx)
-L(aligned_16_76bytes):
-	movdqa	%xmm0, -76(%edx)
-L(aligned_16_60bytes):
-	movdqa	%xmm0, -60(%edx)
-L(aligned_16_44bytes):
-	movdqa	%xmm0, -44(%edx)
-L(aligned_16_28bytes):
-	movdqa	%xmm0, -28(%edx)
-L(aligned_16_12bytes):
-	movq	%xmm0, -12(%edx)
-	movl	%eax, -4(%edx)
-	SETRTNVAL
-	RETURN
-
-
-	ALIGN (4)
-L(aligned_16_126bytes):
-	movdqa	%xmm0, -126(%edx)
-L(aligned_16_110bytes):
-	movdqa	%xmm0, -110(%edx)
-L(aligned_16_94bytes):
-	movdqa	%xmm0, -94(%edx)
-L(aligned_16_78bytes):
-	movdqa	%xmm0, -78(%edx)
-L(aligned_16_62bytes):
-	movdqa	%xmm0, -62(%edx)
-L(aligned_16_46bytes):
-	movdqa	%xmm0, -46(%edx)
-L(aligned_16_30bytes):
-	movdqa	%xmm0, -30(%edx)
-L(aligned_16_14bytes):
-	movq	%xmm0, -14(%edx)
-	movl	%eax, -6(%edx)
-	movw	%ax, -2(%edx)
-	SETRTNVAL
-	RETURN
-
-END (sse2_memset16_atom)
diff --git a/libcutils/arch-x86/sse2-memset32-atom.S b/libcutils/arch-x86/sse2-memset32-atom.S
deleted file mode 100755
index 05eb64f..0000000
--- a/libcutils/arch-x86/sse2-memset32-atom.S
+++ /dev/null
@@ -1,513 +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.
- */
-/*
- * Contributed by: Intel Corporation
- */
-
-#ifndef L
-# define L(label)	.L##label
-#endif
-
-#ifndef ALIGN
-# define ALIGN(n)	.p2align n
-#endif
-
-#ifndef cfi_startproc
-# define cfi_startproc			.cfi_startproc
-#endif
-
-#ifndef cfi_endproc
-# define cfi_endproc			.cfi_endproc
-#endif
-
-#ifndef cfi_rel_offset
-# define cfi_rel_offset(reg, off)	.cfi_rel_offset reg, off
-#endif
-
-#ifndef cfi_restore
-# define cfi_restore(reg)		.cfi_restore reg
-#endif
-
-#ifndef cfi_adjust_cfa_offset
-# define cfi_adjust_cfa_offset(off)	.cfi_adjust_cfa_offset off
-#endif
-
-#ifndef ENTRY
-# define ENTRY(name)			\
-	.type name,  @function; 	\
-	.globl name;			\
-	.p2align 4;			\
-name:					\
-	cfi_startproc
-#endif
-
-#ifndef END
-# define END(name)			\
-	cfi_endproc;			\
-	.size name, .-name
-#endif
-
-#define CFI_PUSH(REG)						\
-  cfi_adjust_cfa_offset (4);					\
-  cfi_rel_offset (REG, 0)
-
-#define CFI_POP(REG)						\
-  cfi_adjust_cfa_offset (-4);					\
-  cfi_restore (REG)
-
-#define PUSH(REG)	pushl REG; CFI_PUSH (REG)
-#define POP(REG)	popl REG; CFI_POP (REG)
-
-#ifdef USE_AS_BZERO32
-# define DEST		PARMS
-# define LEN		DEST+4
-#else
-# define DEST		PARMS
-# define DWDS		DEST+4
-# define LEN		DWDS+4
-#endif
-
-#ifdef USE_AS_WMEMSET32
-# define SETRTNVAL	movl DEST(%esp), %eax
-#else
-# define SETRTNVAL
-#endif
-
-#if (defined SHARED || defined __PIC__)
-# define ENTRANCE	PUSH (%ebx);
-# define RETURN_END	POP (%ebx); ret
-# define RETURN		RETURN_END; CFI_PUSH (%ebx)
-# define PARMS		8		/* Preserve EBX.  */
-# define JMPTBL(I, B)	I - B
-
-/* Load an entry in a jump table into EBX and branch to it.  TABLE is a
-   jump table with relative offsets.   */
-# define BRANCH_TO_JMPTBL_ENTRY(TABLE)				\
-    /* We first load PC into EBX.  */				\
-    call	__i686.get_pc_thunk.bx;				\
-    /* Get the address of the jump table.  */			\
-    add		$(TABLE - .), %ebx;				\
-    /* Get the entry and convert the relative offset to the	\
-       absolute address.  */					\
-    add		(%ebx,%ecx,4), %ebx;				\
-    /* We loaded the jump table and adjuested EDX. Go.  */	\
-    jmp		*%ebx
-
-	.section	.gnu.linkonce.t.__i686.get_pc_thunk.bx,"ax",@progbits
-	.globl	__i686.get_pc_thunk.bx
-	.hidden	__i686.get_pc_thunk.bx
-	ALIGN (4)
-	.type	__i686.get_pc_thunk.bx,@function
-__i686.get_pc_thunk.bx:
-	movl	(%esp), %ebx
-	ret
-#else
-# define ENTRANCE
-# define RETURN_END	ret
-# define RETURN		RETURN_END
-# define PARMS		4
-# define JMPTBL(I, B)	I
-
-/* Branch to an entry in a jump table.  TABLE is a jump table with
-   absolute offsets.  */
-# define BRANCH_TO_JMPTBL_ENTRY(TABLE)				\
-    jmp		*TABLE(,%ecx,4)
-#endif
-
-	.section .text.sse2,"ax",@progbits
-	ALIGN (4)
-ENTRY (sse2_memset32_atom)
-	ENTRANCE
-
-	movl	LEN(%esp), %ecx
-#ifdef USE_AS_ANDROID
-	shr     $2, %ecx
-#endif
-#ifdef USE_AS_BZERO32
-	xor	%eax, %eax
-#else
-	mov	DWDS(%esp), %eax
-	mov	%eax, %edx
-#endif
-	movl	DEST(%esp), %edx
-	cmp	$16, %ecx
-	jae	L(16dbwordsormore)
-
-L(write_less16dbwords):
-	lea	(%edx, %ecx, 4), %edx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_less16dbwords))
-
-	.pushsection .rodata.sse2,"a",@progbits
-	ALIGN (2)
-L(table_less16dbwords):
-	.int	JMPTBL (L(write_0dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_1dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_2dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_3dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_4dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_5dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_6dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_7dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_8dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_9dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_10dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_11dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_12dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_13dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_14dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_15dbwords), L(table_less16dbwords))
-	.popsection
-
-	ALIGN (4)
-L(write_15dbwords):
-	movl	%eax, -60(%edx)
-L(write_14dbwords):
-	movl	%eax, -56(%edx)
-L(write_13dbwords):
-	movl	%eax, -52(%edx)
-L(write_12dbwords):
-	movl	%eax, -48(%edx)
-L(write_11dbwords):
-	movl	%eax, -44(%edx)
-L(write_10dbwords):
-	movl	%eax, -40(%edx)
-L(write_9dbwords):
-	movl	%eax, -36(%edx)
-L(write_8dbwords):
-	movl	%eax, -32(%edx)
-L(write_7dbwords):
-	movl	%eax, -28(%edx)
-L(write_6dbwords):
-	movl	%eax, -24(%edx)
-L(write_5dbwords):
-	movl	%eax, -20(%edx)
-L(write_4dbwords):
-	movl	%eax, -16(%edx)
-L(write_3dbwords):
-	movl	%eax, -12(%edx)
-L(write_2dbwords):
-	movl	%eax, -8(%edx)
-L(write_1dbwords):
-	movl	%eax, -4(%edx)
-L(write_0dbwords):
-	SETRTNVAL
-	RETURN
-
-	ALIGN (4)
-L(16dbwordsormore):
-	test	$3, %edx
-	jz	L(aligned4bytes)
-	mov	%eax, (%edx)
-	mov	%eax, -4(%edx, %ecx, 4)
-	sub	$1, %ecx
-	rol	$24, %eax
-	add	$1, %edx
-	test	$3, %edx
-	jz	L(aligned4bytes)
-	ror	$8, %eax
-	add	$1, %edx
-	test	$3, %edx
-	jz	L(aligned4bytes)
-	ror	$8, %eax
-	add	$1, %edx
-L(aligned4bytes):
-	shl	$2, %ecx
-
-#ifdef USE_AS_BZERO32
-	pxor	%xmm0, %xmm0
-#else
-	movd	%eax, %xmm0
-	pshufd	$0, %xmm0, %xmm0
-#endif
-	testl	$0xf, %edx
-	jz	L(aligned_16)
-/* ECX > 32 and EDX is not 16 byte aligned.  */
-L(not_aligned_16):
-	movdqu	%xmm0, (%edx)
-	movl	%edx, %eax
-	and	$-16, %edx
-	add	$16, %edx
-	sub	%edx, %eax
-	add	%eax, %ecx
-	movd	%xmm0, %eax
-	ALIGN (4)
-L(aligned_16):
-	cmp	$128, %ecx
-	jae	L(128bytesormore)
-
-L(aligned_16_less128bytes):
-	add	%ecx, %edx
-	shr	$2, %ecx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
-	ALIGN (4)
-L(128bytesormore):
-#ifdef SHARED_CACHE_SIZE
-	PUSH (%ebx)
-	mov	$SHARED_CACHE_SIZE, %ebx
-#else
-# if (defined SHARED || defined __PIC__)
-	call	__i686.get_pc_thunk.bx
-	add	$_GLOBAL_OFFSET_TABLE_, %ebx
-	mov	__x86_shared_cache_size@GOTOFF(%ebx), %ebx
-# else
-	PUSH (%ebx)
-	mov	__x86_shared_cache_size, %ebx
-# endif
-#endif
-	cmp	%ebx, %ecx
-	jae	L(128bytesormore_nt_start)
-	
-#ifdef DATA_CACHE_SIZE
-	POP (%ebx)
-# define RESTORE_EBX_STATE CFI_PUSH (%ebx)
-	cmp	$DATA_CACHE_SIZE, %ecx
-#else
-# if (defined SHARED || defined __PIC__)
-#  define RESTORE_EBX_STATE
-	call	__i686.get_pc_thunk.bx
-	add	$_GLOBAL_OFFSET_TABLE_, %ebx
-	cmp	__x86_data_cache_size@GOTOFF(%ebx), %ecx
-# else
-	POP (%ebx)
-#  define RESTORE_EBX_STATE CFI_PUSH (%ebx)
-	cmp	__x86_data_cache_size, %ecx
-# endif
-#endif
-
-	jae	L(128bytes_L2_normal)
-	subl	$128, %ecx
-L(128bytesormore_normal):
-	sub	$128, %ecx
-	movdqa	%xmm0, (%edx)
-	movdqa	%xmm0, 0x10(%edx)
-	movdqa	%xmm0, 0x20(%edx)
-	movdqa	%xmm0, 0x30(%edx)
-	movdqa	%xmm0, 0x40(%edx)
-	movdqa	%xmm0, 0x50(%edx)
-	movdqa	%xmm0, 0x60(%edx)
-	movdqa	%xmm0, 0x70(%edx)
-	lea	128(%edx), %edx
-	jb	L(128bytesless_normal)
-
-
-	sub	$128, %ecx
-	movdqa	%xmm0, (%edx)
-	movdqa	%xmm0, 0x10(%edx)
-	movdqa	%xmm0, 0x20(%edx)
-	movdqa	%xmm0, 0x30(%edx)
-	movdqa	%xmm0, 0x40(%edx)
-	movdqa	%xmm0, 0x50(%edx)
-	movdqa	%xmm0, 0x60(%edx)
-	movdqa	%xmm0, 0x70(%edx)
-	lea	128(%edx), %edx
-	jae	L(128bytesormore_normal)
-
-L(128bytesless_normal):
-	lea	128(%ecx), %ecx
-	add	%ecx, %edx
-	shr	$2, %ecx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
-	ALIGN (4)
-L(128bytes_L2_normal):
-	prefetcht0	0x380(%edx)
-	prefetcht0	0x3c0(%edx)
-	sub	$128, %ecx
-	movdqa	%xmm0, (%edx)
-	movaps	%xmm0, 0x10(%edx)
-	movaps	%xmm0, 0x20(%edx)
-	movaps	%xmm0, 0x30(%edx)
-	movaps	%xmm0, 0x40(%edx)
-	movaps	%xmm0, 0x50(%edx)
-	movaps	%xmm0, 0x60(%edx)
-	movaps	%xmm0, 0x70(%edx)
-	add	$128, %edx
-	cmp	$128, %ecx 	
-	jae	L(128bytes_L2_normal)
-
-L(128bytesless_L2_normal):
-	add	%ecx, %edx
-	shr	$2, %ecx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
-	RESTORE_EBX_STATE
-L(128bytesormore_nt_start):
-	sub	%ebx, %ecx
-	mov	%ebx, %eax
-	and	$0x7f, %eax
-	add	%eax, %ecx
-	movd	%xmm0, %eax
-	ALIGN (4)
-L(128bytesormore_shared_cache_loop):
-	prefetcht0	0x3c0(%edx)
-	prefetcht0	0x380(%edx)
-	sub	$0x80, %ebx
-	movdqa	%xmm0, (%edx)
-	movdqa	%xmm0, 0x10(%edx)
-	movdqa	%xmm0, 0x20(%edx)
-	movdqa	%xmm0, 0x30(%edx)
-	movdqa	%xmm0, 0x40(%edx)
-	movdqa	%xmm0, 0x50(%edx)
-	movdqa	%xmm0, 0x60(%edx)
-	movdqa	%xmm0, 0x70(%edx)
-	add	$0x80, %edx
-	cmp	$0x80, %ebx
-	jae	L(128bytesormore_shared_cache_loop)
-	cmp	$0x80, %ecx
-	jb	L(shared_cache_loop_end)
-
-	ALIGN (4)
-L(128bytesormore_nt):
-	sub	$0x80, %ecx
-	movntdq	%xmm0, (%edx)
-	movntdq	%xmm0, 0x10(%edx)
-	movntdq	%xmm0, 0x20(%edx)
-	movntdq	%xmm0, 0x30(%edx)
-	movntdq	%xmm0, 0x40(%edx)
-	movntdq	%xmm0, 0x50(%edx)
-	movntdq	%xmm0, 0x60(%edx)
-	movntdq	%xmm0, 0x70(%edx)
-	add	$0x80, %edx
-	cmp	$0x80, %ecx
-	jae	L(128bytesormore_nt)
-	sfence
-L(shared_cache_loop_end):
-#if defined DATA_CACHE_SIZE || !(defined SHARED || defined __PIC__)
-	POP (%ebx)
-#endif
-	add	%ecx, %edx
-	shr	$2, %ecx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
-	.pushsection .rodata.sse2,"a",@progbits
-	ALIGN (2)
-L(table_16_128bytes):
-	.int	JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes))
-	.popsection
-
-	ALIGN (4)
-L(aligned_16_112bytes):
-	movdqa	%xmm0, -112(%edx)
-L(aligned_16_96bytes):
-	movdqa	%xmm0, -96(%edx)
-L(aligned_16_80bytes):
-	movdqa	%xmm0, -80(%edx)
-L(aligned_16_64bytes):
-	movdqa	%xmm0, -64(%edx)
-L(aligned_16_48bytes):
-	movdqa	%xmm0, -48(%edx)
-L(aligned_16_32bytes):
-	movdqa	%xmm0, -32(%edx)
-L(aligned_16_16bytes):
-	movdqa	%xmm0, -16(%edx)
-L(aligned_16_0bytes):
-	SETRTNVAL
-	RETURN
-
-	ALIGN (4)
-L(aligned_16_116bytes):
-	movdqa	%xmm0, -116(%edx)
-L(aligned_16_100bytes):
-	movdqa	%xmm0, -100(%edx)
-L(aligned_16_84bytes):
-	movdqa	%xmm0, -84(%edx)
-L(aligned_16_68bytes):
-	movdqa	%xmm0, -68(%edx)
-L(aligned_16_52bytes):
-	movdqa	%xmm0, -52(%edx)
-L(aligned_16_36bytes):
-	movdqa	%xmm0, -36(%edx)
-L(aligned_16_20bytes):
-	movdqa	%xmm0, -20(%edx)
-L(aligned_16_4bytes):
-	movl	%eax, -4(%edx)
-	SETRTNVAL
-	RETURN
-
-	ALIGN (4)
-L(aligned_16_120bytes):
-	movdqa	%xmm0, -120(%edx)
-L(aligned_16_104bytes):
-	movdqa	%xmm0, -104(%edx)
-L(aligned_16_88bytes):
-	movdqa	%xmm0, -88(%edx)
-L(aligned_16_72bytes):
-	movdqa	%xmm0, -72(%edx)
-L(aligned_16_56bytes):
-	movdqa	%xmm0, -56(%edx)
-L(aligned_16_40bytes):
-	movdqa	%xmm0, -40(%edx)
-L(aligned_16_24bytes):
-	movdqa	%xmm0, -24(%edx)
-L(aligned_16_8bytes):
-	movq	%xmm0, -8(%edx)
-	SETRTNVAL
-	RETURN
-
-	ALIGN (4)
-L(aligned_16_124bytes):
-	movdqa	%xmm0, -124(%edx)
-L(aligned_16_108bytes):
-	movdqa	%xmm0, -108(%edx)
-L(aligned_16_92bytes):
-	movdqa	%xmm0, -92(%edx)
-L(aligned_16_76bytes):
-	movdqa	%xmm0, -76(%edx)
-L(aligned_16_60bytes):
-	movdqa	%xmm0, -60(%edx)
-L(aligned_16_44bytes):
-	movdqa	%xmm0, -44(%edx)
-L(aligned_16_28bytes):
-	movdqa	%xmm0, -28(%edx)
-L(aligned_16_12bytes):
-	movq	%xmm0, -12(%edx)
-	movl	%eax, -4(%edx)
-	SETRTNVAL
-	RETURN
-
-END (sse2_memset32_atom)
diff --git a/libcutils/arch-x86_64/android_memset16_SSE2-atom.S b/libcutils/arch-x86_64/android_memset16.S
similarity index 98%
rename from libcutils/arch-x86_64/android_memset16_SSE2-atom.S
rename to libcutils/arch-x86_64/android_memset16.S
index 48a10ed..cb6d4a3 100644
--- a/libcutils/arch-x86_64/android_memset16_SSE2-atom.S
+++ b/libcutils/arch-x86_64/android_memset16.S
@@ -13,12 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-/*
- * Contributed by: Intel Corporation
- */
 
 #include "cache.h"
 
+#ifndef MEMSET
+# define MEMSET		android_memset16
+#endif
+
 #ifndef L
 # define L(label)	.L##label
 #endif
@@ -63,7 +64,7 @@
 
 	.section .text.sse2,"ax",@progbits
 	ALIGN (4)
-ENTRY (android_memset16)	// Address in rdi
+ENTRY (MEMSET)	// Address in rdi
 	shr    $1, %rdx			// Count in rdx
 	movzwl %si, %ecx
 	/* Fill the whole ECX with pattern.  */
@@ -561,4 +562,4 @@
 	movw   %cx, -2(%rdi)
 	ret
 
-END (android_memset16)
+END (MEMSET)
diff --git a/libcutils/arch-x86_64/android_memset32_SSE2-atom.S b/libcutils/arch-x86_64/android_memset32.S
similarity index 98%
rename from libcutils/arch-x86_64/android_memset32_SSE2-atom.S
rename to libcutils/arch-x86_64/android_memset32.S
index 4bdea8e..1514aa2 100644
--- a/libcutils/arch-x86_64/android_memset32_SSE2-atom.S
+++ b/libcutils/arch-x86_64/android_memset32.S
@@ -13,12 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-/*
- * Contributed by: Intel Corporation
- */
 
 #include "cache.h"
 
+#ifndef MEMSET
+# define MEMSET		android_memset32
+#endif
+
 #ifndef L
 # define L(label)	.L##label
 #endif
@@ -63,7 +64,7 @@
 
 	.section .text.sse2,"ax",@progbits
 	ALIGN (4)
-ENTRY (android_memset32)	// Address in rdi
+ENTRY (MEMSET)	// Address in rdi
 	shr    $2, %rdx			// Count in rdx
 	movl   %esi, %ecx		// Pattern in ecx
 
@@ -369,4 +370,4 @@
 	movl	%ecx, -4(%rdi)
 	ret
 
-END (android_memset32)
+END (MEMSET)
diff --git a/libcutils/arch-x86_64/cache.h b/libcutils/arch-x86_64/cache.h
index ab5dd2f..f144309 100644
--- a/libcutils/arch-x86_64/cache.h
+++ b/libcutils/arch-x86_64/cache.h
@@ -13,19 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-/*
- * Contributed by: Intel Corporation
- */
 
-#if defined(__slm__)
 /* Values are optimized for Silvermont */
 #define SHARED_CACHE_SIZE	(1024*1024)			/* Silvermont L2 Cache */
 #define DATA_CACHE_SIZE		(24*1024)			/* Silvermont L1 Data Cache */
-#else
-/* Values are optimized for Atom */
-#define SHARED_CACHE_SIZE	(512*1024)			/* Atom L2 Cache */
-#define DATA_CACHE_SIZE		(24*1024)			/* Atom L1 Data Cache */
-#endif
 
 #define SHARED_CACHE_SIZE_HALF	(SHARED_CACHE_SIZE / 2)
 #define DATA_CACHE_SIZE_HALF	(DATA_CACHE_SIZE / 2)
diff --git a/libcutils/ashmem-host.c b/libcutils/ashmem-host.c
index 4ac4f57..abc4f94 100644
--- a/libcutils/ashmem-host.c
+++ b/libcutils/ashmem-host.c
@@ -22,7 +22,6 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
-#include <pthread.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -33,51 +32,18 @@
 #include <unistd.h>
 
 #include <cutils/ashmem.h>
+#include <utils/Compat.h>
 
 #ifndef __unused
 #define __unused __attribute__((__unused__))
 #endif
 
-static pthread_once_t seed_initialized = PTHREAD_ONCE_INIT;
-static void initialize_random() {
-    srand(time(NULL) + getpid());
-}
-
 int ashmem_create_region(const char *ignored __unused, size_t size)
 {
-    static const char txt[] = "abcdefghijklmnopqrstuvwxyz"
-            "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-    char name[64];
-    unsigned int retries = 0;
-    pid_t pid = getpid();
-    int fd;
-    if (pthread_once(&seed_initialized, &initialize_random) != 0) {
-        return -1;
-    }
-    do {
-        /* not beautiful, its just wolf-like loop unrolling */
-        snprintf(name, sizeof(name), "/tmp/android-ashmem-%d-%c%c%c%c%c%c%c%c",
-        pid,
-        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
-        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
-        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
-        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
-        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
-        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
-        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
-        txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))]);
-
-        /* open O_EXCL & O_CREAT: we are either the sole owner or we fail */
-        fd = open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
-        if (fd == -1) {
-            /* unlikely, but if we failed because `name' exists, retry */
-            if (errno != EEXIST || ++retries >= 6) {
-                return -1;
-            }
-        }
-    } while (fd == -1);
-    /* truncate the file to `len' bytes */
-    if (ftruncate(fd, size) != -1 && unlink(name) != -1) {
+    char template[PATH_MAX];
+    snprintf(template, sizeof(template), "/tmp/android-ashmem-%d-XXXXXXXXX", getpid());
+    int fd = mkstemp(template);
+    if (fd != -1 && TEMP_FAILURE_RETRY(ftruncate(fd, size)) != -1 && unlink(template) != -1) {
         return fd;
     }
     close(fd);
@@ -102,9 +68,7 @@
 int ashmem_get_size_region(int fd)
 {
     struct stat buf;
-    int result;
-
-    result = fstat(fd, &buf);
+    int result = fstat(fd, &buf);
     if (result == -1) {
         return -1;
     }
@@ -116,5 +80,5 @@
         return -1;
     }
 
-    return (int)buf.st_size;    // TODO: care about overflow (> 2GB file)?
+    return buf.st_size;
 }
diff --git a/libcutils/atomic.c b/libcutils/atomic.c
index 1484ef8..d34aa00 100644
--- a/libcutils/atomic.c
+++ b/libcutils/atomic.c
@@ -14,6 +14,13 @@
  * 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-inline.h>
+#include <cutils/atomic.h>
diff --git a/libcutils/cpu_info.c b/libcutils/cpu_info.c
deleted file mode 100644
index 21fa1dc..0000000
--- a/libcutils/cpu_info.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
-**
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
-** limitations under the License.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <cutils/cpu_info.h>
-
-// we cache the serial number here.
-// this is also used as a fgets() line buffer when we are reading /proc/cpuinfo
-static char serial_number[100] = { 0 };
-
-extern const char* get_cpu_serial_number(void)
-{
-    if (serial_number[0] == 0)
-    {
-        FILE* file;
-        char* chp, *end;
-        char* whitespace;
-        
-        // read serial number from /proc/cpuinfo
-        file = fopen("proc/cpuinfo", "r");
-        if (! file)
-            return NULL;
-        
-        while ((chp = fgets(serial_number, sizeof(serial_number), file)) != NULL)
-        {
-            // look for something like "Serial          : 999206122a03591c"
-
-            if (strncmp(chp, "Serial", 6) != 0)
-                continue;
-            
-            chp = strchr(chp, ':');
-            if (!chp)
-                continue;
-                
-             // skip colon and whitespace
-            while ( *(++chp) == ' ') {}
-            
-            // truncate trailing whitespace
-            end = chp;
-            while (*end && *end != ' ' && *end != '\t' && *end != '\n' && *end != '\r')
-                ++end;
-            *end = 0; 
-            
-            whitespace = strchr(chp, ' ');
-            if (whitespace)
-                *whitespace = 0;
-            whitespace = strchr(chp, '\t');
-            if (whitespace)
-                *whitespace = 0;
-            whitespace = strchr(chp, '\r');
-            if (whitespace)
-                *whitespace = 0;
-            whitespace = strchr(chp, '\n');
-            if (whitespace)
-                *whitespace = 0;
-
-            // shift serial number to beginning of the buffer
-            memmove(serial_number, chp, strlen(chp) + 1);
-            break;
-        }
-        
-        fclose(file);
-    }
-
-    return (serial_number[0] ? serial_number : NULL);
-}
diff --git a/libcutils/debugger.c b/libcutils/debugger.c
index b8a2efc..3407ec3 100644
--- a/libcutils/debugger.c
+++ b/libcutils/debugger.c
@@ -29,33 +29,6 @@
 #define LOG_TAG "DEBUG"
 #include <log/log.h>
 
-#if defined(__LP64__)
-#include <elf.h>
-
-static bool is32bit(pid_t tid) {
-  char* exeline;
-  if (asprintf(&exeline, "/proc/%d/exe", tid) == -1) {
-    return false;
-  }
-  int fd = open(exeline, O_RDONLY | O_CLOEXEC);
-  free(exeline);
-  if (fd == -1) {
-    return false;
-  }
-
-  char ehdr[EI_NIDENT];
-  ssize_t bytes = read(fd, &ehdr, sizeof(ehdr));
-  close(fd);
-  if (bytes != (ssize_t) sizeof(ehdr) || memcmp(ELFMAG, ehdr, SELFMAG) != 0) {
-    return false;
-  }
-  if (ehdr[EI_CLASS] == ELFCLASS32) {
-    return true;
-  }
-  return false;
-}
-#endif
-
 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) {
@@ -70,34 +43,12 @@
 }
 
 static int make_dump_request(debugger_action_t action, pid_t tid, int timeout_secs) {
-  const char* socket_name;
   debugger_msg_t msg;
-  size_t msg_len;
-  void* msg_ptr;
+  memset(&msg, 0, sizeof(msg));
+  msg.tid = tid;
+  msg.action = action;
 
-#if defined(__LP64__)
-  debugger32_msg_t msg32;
-  if (is32bit(tid)) {
-    msg_len = sizeof(debugger32_msg_t);
-    memset(&msg32, 0, msg_len);
-    msg32.tid = tid;
-    msg32.action = action;
-    msg_ptr = &msg32;
-
-    socket_name = DEBUGGER32_SOCKET_NAME;
-  } else
-#endif
-  {
-    msg_len = sizeof(debugger_msg_t);
-    memset(&msg, 0, msg_len);
-    msg.tid = tid;
-    msg.action = action;
-    msg_ptr = &msg;
-
-    socket_name = DEBUGGER_SOCKET_NAME;
-  }
-
-  int sock_fd = socket_local_client(socket_name, ANDROID_SOCKET_NAMESPACE_ABSTRACT,
+  int sock_fd = socket_local_client(DEBUGGER_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT,
       SOCK_STREAM | SOCK_CLOEXEC);
   if (sock_fd < 0) {
     return -1;
@@ -116,8 +67,8 @@
     }
   }
 
-  if (send_request(sock_fd, msg_ptr, msg_len) < 0) {
-    TEMP_FAILURE_RETRY(close(sock_fd));
+  if (send_request(sock_fd, &msg, sizeof(msg)) < 0) {
+    close(sock_fd);
     return -1;
   }
 
@@ -144,7 +95,7 @@
       break;
     }
   }
-  TEMP_FAILURE_RETRY(close(sock_fd));
+  close(sock_fd);
   return result;
 }
 
@@ -173,6 +124,6 @@
       memcpy(pathbuf, buffer, n + 1);
     }
   }
-  TEMP_FAILURE_RETRY(close(sock_fd));
+  close(sock_fd);
   return result;
 }
diff --git a/libcutils/dir_hash.c b/libcutils/dir_hash.c
deleted file mode 100644
index 098b5db..0000000
--- a/libcutils/dir_hash.c
+++ /dev/null
@@ -1,335 +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 <dirent.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sha1.h>
-#include <unistd.h>
-#include <limits.h>
-
-#include <sys/stat.h>
-
-#include <netinet/in.h>
-#include <resolv.h>
-
-#include <cutils/dir_hash.h>
-
-/**
- * Copies, if it fits within max_output_string bytes, into output_string
- * a hash of the contents, size, permissions, uid, and gid of the file
- * specified by path, using the specified algorithm.  Returns the length
- * of the output string, or a negative number if the buffer is too short.
- */
-int get_file_hash(HashAlgorithm algorithm, const char *path,
-                  char *output_string, size_t max_output_string) {
-    SHA1_CTX context;
-    struct stat sb;
-    unsigned char md[SHA1_DIGEST_LENGTH];
-    int used;
-    size_t n;
-
-    if (algorithm != SHA_1) {
-        errno = EINVAL;
-        return -1;
-    }
-
-    if (stat(path, &sb) != 0) {
-        return -1;
-    }
-
-    if (S_ISLNK(sb.st_mode)) {
-        char buf[PATH_MAX];
-        int len;
-
-        len = readlink(path, buf, sizeof(buf));
-        if (len < 0) {
-            return -1;
-        }
-
-        SHA1Init(&context);
-        SHA1Update(&context, (unsigned char *) buf, len);
-        SHA1Final(md, &context);
-    } else if (S_ISREG(sb.st_mode)) {
-        char buf[10000];
-        FILE *f = fopen(path, "rb");
-        int len;
-
-        if (f == NULL) {
-            return -1;
-        }
-
-        SHA1Init(&context);
-
-        while ((len = fread(buf, 1, sizeof(buf), f)) > 0) {
-            SHA1Update(&context, (unsigned char *) buf, len);
-        }
-
-        if (ferror(f)) {
-            fclose(f);
-            return -1;
-        }
-
-        fclose(f);
-        SHA1Final(md, &context);
-    }
-
-    if (S_ISLNK(sb.st_mode) || S_ISREG(sb.st_mode)) {
-        used = b64_ntop(md, SHA1_DIGEST_LENGTH,
-                        output_string, max_output_string);
-        if (used < 0) {
-            errno = ENOSPC;
-            return -1;
-        }
-
-        n = snprintf(output_string + used, max_output_string - used,
-                     " %d 0%o %d %d", (int) sb.st_size, sb.st_mode,
-                     (int) sb.st_uid, (int) sb.st_gid);
-    } else {
-        n = snprintf(output_string, max_output_string,
-                     "- - 0%o %d %d", sb.st_mode,
-                     (int) sb.st_uid, (int) sb.st_gid);
-    }
-
-    if (n >= max_output_string - used) {
-        errno = ENOSPC;
-        return -(used + n);
-    }
-
-    return used + n;
-}
-
-struct list {
-    char *name;
-    struct list *next;
-};
-
-static int cmp(const void *a, const void *b) {
-    struct list *const *ra = a;
-    struct list *const *rb = b;
-
-    return strcmp((*ra)->name, (*rb)->name);
-}
-
-static int recurse(HashAlgorithm algorithm, const char *directory_path,
-                    struct list **out) {
-    struct list *list = NULL;
-    struct list *f;
-
-    struct dirent *de;
-    DIR *d = opendir(directory_path);
-
-    if (d == NULL) {
-        return -1;
-    }
-
-    while ((de = readdir(d)) != NULL) {
-        if (strcmp(de->d_name, ".") == 0) {
-            continue;
-        }
-        if (strcmp(de->d_name, "..") == 0) {
-            continue;
-        }
-
-        char *name = malloc(strlen(de->d_name) + 1);
-        struct list *node = malloc(sizeof(struct list));
-
-        if (name == NULL || node == NULL) {
-            struct list *next;
-            for (f = list; f != NULL; f = next) {
-                next = f->next;
-                free(f->name);
-                free(f);
-            }
-
-            free(name);
-            free(node);
-            closedir(d);
-            return -1;
-        }
-
-        strcpy(name, de->d_name);
-
-        node->name = name;
-        node->next = list;
-        list = node;
-    }
-
-    closedir(d);
-
-    for (f = list; f != NULL; f = f->next) {
-        struct stat sb;
-        char *name;
-        char outstr[NAME_MAX + 100];
-        char *keep;
-        struct list *res;
-
-        name = malloc(strlen(f->name) + strlen(directory_path) + 2);
-        if (name == NULL) {
-            struct list *next;
-            for (f = list; f != NULL; f = f->next) {
-                next = f->next;
-                free(f->name);
-                free(f);
-            }
-            for (f = *out; f != NULL; f = f->next) {
-                next = f->next;
-                free(f->name);
-                free(f);
-            }
-            *out = NULL;
-            return -1;
-        }
-
-        sprintf(name, "%s/%s", directory_path, f->name);
-
-        int len = get_file_hash(algorithm, name,
-                                outstr, sizeof(outstr));
-        if (len < 0) {
-            // should not happen
-            return -1;
-        }
-
-        keep = malloc(len + strlen(name) + 3);
-        res = malloc(sizeof(struct list));
-
-        if (keep == NULL || res == NULL) {
-            struct list *next;
-            for (f = list; f != NULL; f = f->next) {
-                next = f->next;
-                free(f->name);
-                free(f);
-            }
-            for (f = *out; f != NULL; f = f->next) {
-                next = f->next;
-                free(f->name);
-                free(f);
-            }
-            *out = NULL;
-
-            free(keep);
-            free(res);
-            return -1;
-        }
-
-        sprintf(keep, "%s %s\n", name, outstr);
-
-        res->name = keep;
-        res->next = *out;
-        *out = res;
-
-        if ((stat(name, &sb) == 0) && S_ISDIR(sb.st_mode)) {
-            if (recurse(algorithm, name, out) < 0) {
-                struct list *next;
-                for (f = list; f != NULL; f = next) {
-                    next = f->next;
-                    free(f->name);
-                    free(f);
-                }
-
-                return -1;
-            }
-        }
-    }
-
-    struct list *next;
-    for (f = list; f != NULL; f = next) {
-        next = f->next;
-
-        free(f->name);
-        free(f);
-    }
-}
-
-/**
- * Allocates a string containing the names and hashes of all files recursively
- * reached under the specified directory_path, using the specified algorithm.
- * The string is returned as *output_string; the return value is the length
- * of the string, or a negative number if there was a failure.
- */
-int get_recursive_hash_manifest(HashAlgorithm algorithm,
-                                const char *directory_path,
-                                char **output_string) {
-    struct list *out = NULL;
-    struct list *r;
-    struct list **list;
-    int count = 0;
-    int len = 0;
-    int retlen = 0;
-    int i;
-    char *buf;
-    
-    if (recurse(algorithm, directory_path, &out) < 0) {
-        return -1;
-    }
-
-    for (r = out; r != NULL; r = r->next) {
-        count++;
-        len += strlen(r->name);
-    }
-
-    list = malloc(count * sizeof(struct list *));
-    if (list == NULL) {
-        struct list *next;
-        for (r = out; r != NULL; r = next) {
-            next = r->next;
-            free(r->name);
-            free(r);
-        }
-        return -1;
-    }
-
-    count = 0;
-    for (r = out; r != NULL; r = r->next) {
-        list[count++] = r;
-    }
-
-    qsort(list, count, sizeof(struct list *), cmp);
-
-    buf = malloc(len + 1);
-    if (buf == NULL) {
-        struct list *next;
-        for (r = out; r != NULL; r = next) {
-            next = r->next;
-            free(r->name);
-            free(r);
-        }
-        free(list);
-        return -1;
-    }
-
-    for (i = 0; i < count; i++) {
-        int n = strlen(list[i]->name);
-
-        strcpy(buf + retlen, list[i]->name);
-        retlen += n;
-    }
-
-    free(list);
-
-    struct list *next;
-    for (r = out; r != NULL; r = next) {
-        next = r->next;
-
-        free(r->name);
-        free(r);
-    }
-
-    *output_string = buf;
-    return retlen;
-}
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
new file mode 100644
index 0000000..9a1ad19
--- /dev/null
+++ b/libcutils/fs_config.c
@@ -0,0 +1,280 @@
+/*
+ * 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.
+ */
+
+/* This file is used to define the properties of the filesystem
+** images generated by build tools (mkbootfs and mkyaffs2image) and
+** by the device side of adb.
+*/
+
+#define LOG_TAG "fs_config"
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <log/log.h>
+#include <private/android_filesystem_config.h>
+#include <utils/Compat.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+/* The following structure is stored little endian */
+struct fs_path_config_from_file {
+    uint16_t len;
+    uint16_t mode;
+    uint16_t uid;
+    uint16_t gid;
+    uint64_t capabilities;
+    char prefix[];
+} __attribute__((__aligned__(sizeof(uint64_t))));
+
+/* My kingdom for <endian.h> */
+static inline uint16_t get2LE(const uint8_t* src)
+{
+    return src[0] | (src[1] << 8);
+}
+
+static inline uint64_t get8LE(const uint8_t* src)
+{
+    uint32_t low, high;
+
+    low = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+    high = src[4] | (src[5] << 8) | (src[6] << 16) | (src[7] << 24);
+    return ((uint64_t) high << 32) | (uint64_t) low;
+}
+
+#define ALIGN(x, alignment) ( ((x) + ((alignment) - 1)) & ~((alignment) - 1) )
+
+/* Rules for directories.
+** These rules are applied based on "first match", so they
+** should start with the most specific path and work their
+** way up to the root.
+*/
+
+static const struct fs_path_config android_dirs[] = {
+    { 00770, AID_SYSTEM, AID_CACHE,  0, "cache" },
+    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" },
+    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" },
+    { 00771, AID_ROOT,   AID_ROOT,   0, "data/dalvik-cache" },
+    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" },
+    { 00771, AID_SHELL,  AID_SHELL,  0, "data/local/tmp" },
+    { 00771, AID_SHELL,  AID_SHELL,  0, "data/local" },
+    { 01771, AID_SYSTEM, AID_MISC,   0, "data/misc" },
+    { 00770, AID_DHCP,   AID_DHCP,   0, "data/misc/dhcp" },
+    { 00771, AID_SHARED_RELRO, AID_SHARED_RELRO, 0, "data/misc/shared_relro" },
+    { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media" },
+    { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" },
+    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" },
+    { 00750, AID_ROOT,   AID_SHELL,  0, "sbin" },
+    { 00755, AID_ROOT,   AID_SHELL,  0, "system/bin" },
+    { 00755, AID_ROOT,   AID_SHELL,  0, "system/vendor" },
+    { 00755, AID_ROOT,   AID_SHELL,  0, "system/xbin" },
+    { 00755, AID_ROOT,   AID_ROOT,   0, "system/etc/ppp" },
+    { 00755, AID_ROOT,   AID_SHELL,  0, "vendor" },
+    { 00777, AID_ROOT,   AID_ROOT,   0, "sdcard" },
+    { 00755, AID_ROOT,   AID_ROOT,   0, 0 },
+};
+
+/* Rules for files.
+** These rules are applied based on "first match", so they
+** should start with the most specific path and work their
+** way up to the root. Prefixes ending in * denotes wildcard
+** and will allow partial matches.
+*/
+static const char conf_dir[] = "/system/etc/fs_config_dirs";
+static const char conf_file[] = "/system/etc/fs_config_files";
+
+static const struct fs_path_config android_files[] = {
+    { 00440, AID_ROOT,      AID_SHELL,     0, "system/etc/init.goldfish.rc" },
+    { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.goldfish.sh" },
+    { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.ril" },
+    { 00550, AID_DHCP,      AID_SHELL,     0, "system/etc/dhcpcd/dhcpcd-run-hooks" },
+    { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/ppp/*" },
+    { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/rc.*" },
+    { 00444, AID_ROOT,      AID_ROOT,      0, conf_dir + 1 },
+    { 00444, AID_ROOT,      AID_ROOT,      0, conf_file + 1 },
+    { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app/*" },
+    { 00644, AID_MEDIA_RW,  AID_MEDIA_RW,  0, "data/media/*" },
+    { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app-private/*" },
+    { 00644, AID_APP,       AID_APP,       0, "data/data/*" },
+
+    /* the following five files are INTENTIONALLY set-uid, but they
+     * are NOT included on user builds. */
+    { 04750, AID_ROOT,      AID_SHELL,     0, "system/xbin/su" },
+    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/librank" },
+    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procrank" },
+    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procmem" },
+    { 04770, AID_ROOT,      AID_RADIO,     0, "system/bin/pppd-ril" },
+
+    /* the following files have enhanced capabilities and ARE included in user builds. */
+    { 00750, AID_ROOT,      AID_SHELL,     (1ULL << CAP_SETUID) | (1ULL << CAP_SETGID), "system/bin/run-as" },
+    { 00700, AID_SYSTEM,    AID_SHELL,     (1ULL << CAP_BLOCK_SUSPEND), "system/bin/inputflinger" },
+
+    { 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/*" },
+    { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib/valgrind/*" },
+    { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib64/valgrind/*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/xbin/*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/vendor/bin/*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/bin/*" },
+    { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/*" },
+    { 00755, AID_ROOT,      AID_ROOT,      0, "bin/*" },
+    { 00750, AID_ROOT,      AID_SHELL,     0, "init*" },
+    { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/fs_mgr" },
+    { 00640, AID_ROOT,      AID_SHELL,     0, "fstab.*" },
+    { 00644, AID_ROOT,      AID_ROOT,      0, 0 },
+};
+
+static int fs_config_open(int dir, const char *target_out_path)
+{
+    int fd = -1;
+
+    if (target_out_path && *target_out_path) {
+        /* target_out_path is the path to the directory holding content of system partition
+           but as we cannot guaranty it ends with '/system' we need this below skip_len logic */
+        char *name = NULL;
+        int target_out_path_len = strlen(target_out_path);
+        int skip_len = strlen("/system");
+
+        if (target_out_path[target_out_path_len] == '/') {
+            skip_len++;
+        }
+        asprintf(&name, "%s%s", target_out_path, (dir ? conf_dir : conf_file) + skip_len);
+        if (name) {
+            fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_BINARY));
+            free(name);
+        }
+    }
+    if (fd < 0) {
+        fd = TEMP_FAILURE_RETRY(open(dir ? conf_dir : conf_file, O_RDONLY | O_BINARY));
+    }
+    return fd;
+}
+
+static bool fs_config_cmp(bool dir, const char *prefix, size_t len,
+                                    const char *path, size_t plen)
+{
+    if (dir) {
+        if (plen < len) {
+            return false;
+        }
+    } else {
+        /* If name ends in * then allow partial matches. */
+        if (prefix[len - 1] == '*') {
+            return !strncmp(prefix, path, len - 1);
+        }
+        if (plen != len) {
+            return false;
+        }
+    }
+    return !strncmp(prefix, path, len);
+}
+
+void fs_config(const char *path, int dir, const char *target_out_path,
+               unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities)
+{
+    const struct fs_path_config *pc;
+    int fd, plen;
+
+    if (path[0] == '/') {
+        path++;
+    }
+
+    plen = strlen(path);
+
+    fd = fs_config_open(dir, target_out_path);
+    if (fd >= 0) {
+        struct fs_path_config_from_file header;
+
+        while (TEMP_FAILURE_RETRY(read(fd, &header, sizeof(header))) == sizeof(header)) {
+            char *prefix;
+            uint16_t host_len = get2LE((const uint8_t *)&header.len);
+            ssize_t len, remainder = host_len - sizeof(header);
+            if (remainder <= 0) {
+                ALOGE("%s len is corrupted", dir ? conf_dir : conf_file);
+                break;
+            }
+            prefix = calloc(1, remainder);
+            if (!prefix) {
+                ALOGE("%s out of memory", dir ? conf_dir : conf_file);
+                break;
+            }
+            if (TEMP_FAILURE_RETRY(read(fd, prefix, remainder)) != remainder) {
+                free(prefix);
+                ALOGE("%s prefix is truncated", dir ? conf_dir : conf_file);
+                break;
+            }
+            len = strnlen(prefix, remainder);
+            if (len >= remainder) { /* missing a terminating null */
+                free(prefix);
+                ALOGE("%s is corrupted", dir ? conf_dir : conf_file);
+                break;
+            }
+            if (fs_config_cmp(dir, prefix, len, path, plen)) {
+                free(prefix);
+                close(fd);
+                *uid = get2LE((const uint8_t *)&(header.uid));
+                *gid = get2LE((const uint8_t *)&(header.gid));
+                *mode = (*mode & (~07777)) | get2LE((const uint8_t *)&(header.mode));
+                *capabilities = get8LE((const uint8_t *)&(header.capabilities));
+                return;
+            }
+            free(prefix);
+        }
+        close(fd);
+    }
+
+    pc = dir ? android_dirs : android_files;
+    for(; pc->prefix; pc++){
+        if (fs_config_cmp(dir, pc->prefix, strlen(pc->prefix), path, plen)) {
+            break;
+        }
+    }
+    *uid = pc->uid;
+    *gid = pc->gid;
+    *mode = (*mode & (~07777)) | pc->mode;
+    *capabilities = pc->capabilities;
+}
+
+ssize_t fs_config_generate(char *buffer, size_t length, const struct fs_path_config *pc)
+{
+    struct fs_path_config_from_file *p = (struct fs_path_config_from_file *)buffer;
+    size_t len = ALIGN(sizeof(*p) + strlen(pc->prefix) + 1, sizeof(uint64_t));
+
+    if ((length < len) || (len > UINT16_MAX)) {
+        return -ENOSPC;
+    }
+    memset(p, 0, len);
+    uint16_t host_len = len;
+    p->len = get2LE((const uint8_t *)&host_len);
+    p->mode = get2LE((const uint8_t *)&(pc->mode));
+    p->uid = get2LE((const uint8_t *)&(pc->uid));
+    p->gid = get2LE((const uint8_t *)&(pc->gid));
+    p->capabilities = get8LE((const uint8_t *)&(pc->capabilities));
+    strcpy(p->prefix, pc->prefix);
+    return len;
+}
diff --git a/libcutils/iosched_policy.c b/libcutils/iosched_policy.c
index a6da9ca..8946d3c 100644
--- a/libcutils/iosched_policy.c
+++ b/libcutils/iosched_policy.c
@@ -1,5 +1,5 @@
 /*
-** Copyright 2007-2014, The Android Open Source Project
+** Copyright 2007, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License"); 
 ** you may not use this file except in compliance with the License. 
diff --git a/libcutils/klog.c b/libcutils/klog.c
index fbb7b72..710dc66 100644
--- a/libcutils/klog.c
+++ b/libcutils/klog.c
@@ -14,13 +14,14 @@
  * limitations under the License.
  */
 
-#include <sys/stat.h>
-#include <sys/types.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #include <cutils/klog.h>
@@ -36,41 +37,41 @@
     klog_level = level;
 }
 
-void klog_init(void)
-{
-    static const char *name = "/dev/__kmsg__";
-
+void klog_init(void) {
     if (klog_fd >= 0) return; /* Already initialized */
 
+    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);
-        if (klog_fd < 0)
-                return;
-        fcntl(klog_fd, F_SETFD, FD_CLOEXEC);
+        klog_fd = open(name, O_WRONLY | O_CLOEXEC);
         unlink(name);
     }
 }
 
 #define LOG_BUF_MAX 512
 
-void klog_vwrite(int level, const char *fmt, va_list ap)
-{
-    char buf[LOG_BUF_MAX];
-
+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;
-
-    vsnprintf(buf, LOG_BUF_MAX, fmt, ap);
-    buf[LOG_BUF_MAX - 1] = 0;
-
-    write(klog_fd, buf, strlen(buf));
+    TEMP_FAILURE_RETRY(writev(klog_fd, iov, iov_count));
 }
 
-void klog_write(int level, const char *fmt, ...)
-{
+void klog_write(int level, const char* fmt, ...) {
+    char buf[LOG_BUF_MAX];
     va_list ap;
     va_start(ap, fmt);
-    klog_vwrite(level, fmt, ap);
+    vsnprintf(buf, sizeof(buf), fmt, ap);
     va_end(ap);
+
+    buf[LOG_BUF_MAX - 1] = 0;
+
+    struct iovec iov[1];
+    iov[0].iov_base = buf;
+    iov[0].iov_len = strlen(buf);
+    klog_writev(level, iov, 1);
 }
diff --git a/libcutils/loghack.h b/libcutils/loghack.h
deleted file mode 100644
index 750cab0..0000000
--- a/libcutils/loghack.h
+++ /dev/null
@@ -1,38 +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.
- */
-
-/**
- * This is a temporary hack to enable logging from cutils.
- */
-
-#ifndef _CUTILS_LOGHACK_H
-#define _CUTILS_LOGHACK_H
-
-#ifdef HAVE_ANDROID_OS
-#include <cutils/log.h>
-#else
-#include <stdio.h>
-#define ALOG(level, ...) \
-        ((void)printf("cutils:" level "/" LOG_TAG ": " __VA_ARGS__))
-#define ALOGV(...)   ALOG("V", __VA_ARGS__)
-#define ALOGD(...)   ALOG("D", __VA_ARGS__)
-#define ALOGI(...)   ALOG("I", __VA_ARGS__)
-#define ALOGW(...)   ALOG("W", __VA_ARGS__)
-#define ALOGE(...)   ALOG("E", __VA_ARGS__)
-#define LOG_ALWAYS_FATAL(...)   do { ALOGE(__VA_ARGS__); exit(1); } while (0)
-#endif
-
-#endif // _CUTILS_LOGHACK_H
diff --git a/libcutils/open_memstream.c b/libcutils/open_memstream.c
index 5b4388a..9183266 100644
--- a/libcutils/open_memstream.c
+++ b/libcutils/open_memstream.c
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef HAVE_OPEN_MEMSTREAM
+#if defined(__APPLE__)
 
 /*
  * Implementation of the POSIX open_memstream() function, which Linux has
@@ -59,8 +59,6 @@
 # define DBUG(x) ((void)0)
 #endif
 
-#ifdef HAVE_FUNOPEN
-
 /*
  * Definition of a seekable, write-only memory stream.
  */
@@ -251,12 +249,6 @@
     return fp;
 }
 
-#else /*not HAVE_FUNOPEN*/
-FILE* open_memstream(char** bufp, size_t* sizep)
-{
-    abort();
-}
-#endif /*HAVE_FUNOPEN*/
 
 
 
@@ -378,4 +370,4 @@
 
 #endif
 
-#endif /*!HAVE_OPEN_MEMSTREAM*/
+#endif /* __APPLE__ */
diff --git a/libcutils/process_name.c b/libcutils/process_name.c
index 9c3dfb8..cc931eb 100644
--- a/libcutils/process_name.c
+++ b/libcutils/process_name.c
@@ -17,7 +17,7 @@
 #include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
-#if defined(HAVE_PRCTL)
+#if defined(__linux__)
 #include <sys/prctl.h>
 #endif
 #include <sys/stat.h>
@@ -51,7 +51,7 @@
     strcpy(copy, new_name);
     process_name = (const char*) copy;
 
-#if defined(HAVE_PRCTL)
+#if defined(__linux__)
     if (len < 16) {
         prctl(PR_SET_NAME, (unsigned long) new_name, 0, 0, 0);
     } else {
diff --git a/libcutils/properties.c b/libcutils/properties.c
index b283658..4e46e02 100644
--- a/libcutils/properties.c
+++ b/libcutils/properties.c
@@ -28,7 +28,7 @@
 #include <cutils/properties.h>
 #include <stdbool.h>
 #include <inttypes.h>
-#include "loghack.h"
+#include <log/log.h>
 
 int8_t property_get_bool(const char *key, int8_t default_value) {
     if (!key) {
@@ -104,8 +104,6 @@
     return (int32_t)property_get_imax(key, INT32_MIN, INT32_MAX, default_value);
 }
 
-#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
-
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
 #include <sys/_system_properties.h>
 
@@ -156,265 +154,3 @@
     struct property_list_callback_data data = { propfn, cookie };
     return __system_property_foreach(property_list_callback, &data);
 }
-
-#elif defined(HAVE_SYSTEM_PROPERTY_SERVER)
-
-/*
- * The Linux simulator provides a "system property server" that uses IPC
- * to set/get/list properties.  The file descriptor is shared by all
- * threads in the process, so we use a mutex to ensure that requests
- * from multiple threads don't get interleaved.
- */
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <pthread.h>
-
-static pthread_once_t gInitOnce = PTHREAD_ONCE_INIT;
-static pthread_mutex_t gPropertyFdLock = PTHREAD_MUTEX_INITIALIZER;
-static int gPropFd = -1;
-
-/*
- * Connect to the properties server.
- *
- * Returns the socket descriptor on success.
- */
-static int connectToServer(const char* fileName)
-{
-    int sock = -1;
-    int cc;
-
-    struct sockaddr_un addr;
-    
-    sock = socket(AF_UNIX, SOCK_STREAM, 0);
-    if (sock < 0) {
-        ALOGW("UNIX domain socket create failed (errno=%d)\n", errno);
-        return -1;
-    }
-
-    /* connect to socket; fails if file doesn't exist */
-    strcpy(addr.sun_path, fileName);    // max 108 bytes
-    addr.sun_family = AF_UNIX;
-    cc = connect(sock, (struct sockaddr*) &addr, SUN_LEN(&addr));
-    if (cc < 0) {
-        // ENOENT means socket file doesn't exist
-        // ECONNREFUSED means socket exists but nobody is listening
-        //ALOGW("AF_UNIX connect failed for '%s': %s\n",
-        //    fileName, strerror(errno));
-        close(sock);
-        return -1;
-    }
-
-    return sock;
-}
-
-/*
- * Perform one-time initialization.
- */
-static void init(void)
-{
-    assert(gPropFd == -1);
-
-    gPropFd = connectToServer(SYSTEM_PROPERTY_PIPE_NAME);
-    if (gPropFd < 0) {
-        //ALOGW("not connected to system property server\n");
-    } else {
-        //ALOGV("Connected to system property server\n");
-    }
-}
-
-int property_get(const char *key, char *value, const char *default_value)
-{
-    char sendBuf[1+PROPERTY_KEY_MAX];
-    char recvBuf[1+PROPERTY_VALUE_MAX];
-    int len = -1;
-
-    //ALOGV("PROPERTY GET [%s]\n", key);
-
-    pthread_once(&gInitOnce, init);
-    if (gPropFd < 0) {
-        /* this mimics the behavior of the device implementation */
-        if (default_value != NULL) {
-            strcpy(value, default_value);
-            len = strlen(value);
-        }
-        return len;
-    }
-
-    if (strlen(key) >= PROPERTY_KEY_MAX) return -1;
-
-    memset(sendBuf, 0xdd, sizeof(sendBuf));    // placate valgrind
-
-    sendBuf[0] = (char) kSystemPropertyGet;
-    strcpy(sendBuf+1, key);
-
-    pthread_mutex_lock(&gPropertyFdLock);
-    if (write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) {
-        pthread_mutex_unlock(&gPropertyFdLock);
-        return -1;
-    }
-    if (read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) {
-        pthread_mutex_unlock(&gPropertyFdLock);
-        return -1;
-    }
-    pthread_mutex_unlock(&gPropertyFdLock);
-
-    /* first byte is 0 if value not defined, 1 if found */
-    if (recvBuf[0] == 0) {
-        if (default_value != NULL) {
-            strcpy(value, default_value);
-            len = strlen(value);
-        } else {
-            /*
-             * If the value isn't defined, hand back an empty string and
-             * a zero length, rather than a failure.  This seems wrong,
-             * since you can't tell the difference between "undefined" and
-             * "defined but empty", but it's what the device does.
-             */
-            value[0] = '\0';
-            len = 0;
-        }
-    } else if (recvBuf[0] == 1) {
-        strcpy(value, recvBuf+1);
-        len = strlen(value);
-    } else {
-        ALOGE("Got strange response to property_get request (%d)\n",
-            recvBuf[0]);
-        assert(0);
-        return -1;
-    }
-    //ALOGV("PROP [found=%d def='%s'] (%d) [%s]: [%s]\n",
-    //    recvBuf[0], default_value, len, key, value);
-
-    return len;
-}
-
-
-int property_set(const char *key, const char *value)
-{
-    char sendBuf[1+PROPERTY_KEY_MAX+PROPERTY_VALUE_MAX];
-    char recvBuf[1];
-    int result = -1;
-
-    //ALOGV("PROPERTY SET [%s]: [%s]\n", key, value);
-
-    pthread_once(&gInitOnce, init);
-    if (gPropFd < 0)
-        return -1;
-
-    if (strlen(key) >= PROPERTY_KEY_MAX) return -1;
-    if (strlen(value) >= PROPERTY_VALUE_MAX) return -1;
-
-    memset(sendBuf, 0xdd, sizeof(sendBuf));    // placate valgrind
-
-    sendBuf[0] = (char) kSystemPropertySet;
-    strcpy(sendBuf+1, key);
-    strcpy(sendBuf+1+PROPERTY_KEY_MAX, value);
-
-    pthread_mutex_lock(&gPropertyFdLock);
-    if (write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) {
-        pthread_mutex_unlock(&gPropertyFdLock);
-        return -1;
-    }
-    if (read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) {
-        pthread_mutex_unlock(&gPropertyFdLock);
-        return -1;
-    }
-    pthread_mutex_unlock(&gPropertyFdLock);
-
-    if (recvBuf[0] != 1)
-        return -1;
-    return 0;
-}
-
-int property_list(void (*propfn)(const char *key, const char *value, void *cookie), 
-                  void *cookie)
-{
-    //ALOGV("PROPERTY LIST\n");
-    pthread_once(&gInitOnce, init);
-    if (gPropFd < 0)
-        return -1;
-
-    return 0;
-}
-
-#else
-
-/* SUPER-cheesy place-holder implementation for Win32 */
-
-#include <cutils/threads.h>
-
-static mutex_t  env_lock = MUTEX_INITIALIZER;
-
-int property_get(const char *key, char *value, const char *default_value)
-{
-    char ename[PROPERTY_KEY_MAX + 6];
-    char *p;
-    int len;
-    
-    len = strlen(key);
-    if(len >= PROPERTY_KEY_MAX) return -1;
-    memcpy(ename, "PROP_", 5);
-    memcpy(ename + 5, key, len + 1);
-    
-    mutex_lock(&env_lock);
-
-    p = getenv(ename);
-    if(p == 0) p = "";
-    len = strlen(p);
-    if(len >= PROPERTY_VALUE_MAX) {
-        len = PROPERTY_VALUE_MAX - 1;
-    }
-    
-    if((len == 0) && default_value) {
-        len = strlen(default_value);
-        memcpy(value, default_value, len + 1);
-    } else {
-        memcpy(value, p, len);
-        value[len] = 0;
-    }
-
-    mutex_unlock(&env_lock);
-    
-    return len;
-}
-
-
-int property_set(const char *key, const char *value)
-{
-    char ename[PROPERTY_KEY_MAX + 6];
-    char *p;
-    int len;
-    int r;
-
-    if(strlen(value) >= PROPERTY_VALUE_MAX) return -1;
-    
-    len = strlen(key);
-    if(len >= PROPERTY_KEY_MAX) return -1;
-    memcpy(ename, "PROP_", 5);
-    memcpy(ename + 5, key, len + 1);
-
-    mutex_lock(&env_lock);
-#ifdef HAVE_MS_C_RUNTIME
-    {
-        char  temp[256];
-        snprintf( temp, sizeof(temp), "%s=%s", ename, value);
-        putenv(temp);
-        r = 0;
-    }
-#else    
-    r = setenv(ename, value, 1);
-#endif    
-    mutex_unlock(&env_lock);
-    
-    return r;
-}
-
-int property_list(void (*propfn)(const char *key, const char *value, void *cookie), 
-                  void *cookie)
-{
-    return 0;
-}
-
-#endif
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index 493511e..83222f4 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -1,16 +1,16 @@
 /*
 ** Copyright 2007, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.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.
 */
 
@@ -37,7 +37,7 @@
    return p == SP_DEFAULT ? SP_SYSTEM_DEFAULT : p;
 }
 
-#if defined(HAVE_ANDROID_OS) && defined(HAVE_SCHED_H) && defined(HAVE_PTHREADS)
+#if defined(HAVE_ANDROID_OS)
 
 #include <pthread.h>
 #include <sched.h>
@@ -50,6 +50,7 @@
 
 // timer slack value in nS enforced when the thread moves to background
 #define TIMER_SLACK_BG 40000000
+#define TIMER_SLACK_FG 50000
 
 static pthread_once_t the_once = PTHREAD_ONCE_INIT;
 
@@ -59,27 +60,16 @@
 static int bg_cgroup_fd = -1;
 static int fg_cgroup_fd = -1;
 
+// File descriptors open to /dev/cpuset/../tasks, setup by initialize, or -1 on error
+static int bg_cpuset_fd = -1;
+static int fg_cpuset_fd = -1;
+
 /* Add tid to the scheduling group defined by the policy */
-static int add_tid_to_cgroup(int tid, SchedPolicy policy)
+static int add_tid_to_cgroup(int tid, int fd)
 {
-    int fd;
-
-    switch (policy) {
-    case SP_BACKGROUND:
-        fd = bg_cgroup_fd;
-        break;
-    case SP_FOREGROUND:
-    case SP_AUDIO_APP:
-    case SP_AUDIO_SYS:
-        fd = fg_cgroup_fd;
-        break;
-    default:
-        fd = -1;
-        break;
-    }
-
     if (fd < 0) {
-        SLOGE("add_tid_to_cgroup failed; policy=%d\n", policy);
+        SLOGE("add_tid_to_cgroup failed; fd=%d\n", fd);
+        errno = EINVAL;
         return -1;
     }
 
@@ -100,8 +90,9 @@
          */
         if (errno == ESRCH)
                 return 0;
-        SLOGW("add_tid_to_cgroup failed to write '%s' (%s); policy=%d\n",
-              ptr, strerror(errno), policy);
+        SLOGW("add_tid_to_cgroup failed to write '%s' (%s); fd=%d\n",
+              ptr, strerror(errno), fd);
+        errno = EINVAL;
         return -1;
     }
 
@@ -127,6 +118,17 @@
     } else {
         __sys_supports_schedgroups = 0;
     }
+
+#ifdef USE_CPUSETS
+    if (!access("/dev/cpuset/tasks", F_OK)) {
+
+        filename = "/dev/cpuset/foreground/tasks";
+        fg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
+        filename = "/dev/cpuset/background/tasks";
+        bg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
+    }
+#endif
+
 }
 
 /*
@@ -203,11 +205,9 @@
 
 int get_sched_policy(int tid, SchedPolicy *policy)
 {
-#ifdef HAVE_GETTID
     if (tid == 0) {
         tid = gettid();
     }
-#endif
     pthread_once(&the_once, __initialize);
 
     if (__sys_supports_schedgroups) {
@@ -238,13 +238,47 @@
     return 0;
 }
 
-int set_sched_policy(int tid, SchedPolicy policy)
+int set_cpuset_policy(int tid, SchedPolicy policy)
 {
-#ifdef HAVE_GETTID
+    // in the absence of cpusets, use the old sched policy
+#ifndef USE_CPUSETS
+    return set_sched_policy(tid, policy);
+#else
     if (tid == 0) {
         tid = gettid();
     }
+    policy = _policy(policy);
+    pthread_once(&the_once, __initialize);
+
+    int fd;
+    switch (policy) {
+    case SP_BACKGROUND:
+        fd = bg_cpuset_fd;
+        break;
+    case SP_FOREGROUND:
+    case SP_AUDIO_APP:
+    case SP_AUDIO_SYS:
+        fd = fg_cpuset_fd;
+        break;
+    default:
+        fd = -1;
+        break;
+    }
+
+    if (add_tid_to_cgroup(tid, fd) != 0) {
+        if (errno != ESRCH && errno != ENOENT)
+            return -errno;
+    }
+
+    return 0;
 #endif
+}
+
+int set_sched_policy(int tid, SchedPolicy policy)
+{
+    if (tid == 0) {
+        tid = gettid();
+    }
     policy = _policy(policy);
     pthread_once(&the_once, __initialize);
 
@@ -290,7 +324,23 @@
 #endif
 
     if (__sys_supports_schedgroups) {
-        if (add_tid_to_cgroup(tid, policy)) {
+        int fd;
+        switch (policy) {
+        case SP_BACKGROUND:
+            fd = bg_cgroup_fd;
+            break;
+        case SP_FOREGROUND:
+        case SP_AUDIO_APP:
+        case SP_AUDIO_SYS:
+            fd = fg_cgroup_fd;
+            break;
+        default:
+            fd = -1;
+            break;
+        }
+
+
+        if (add_tid_to_cgroup(tid, fd) != 0) {
             if (errno != ESRCH && errno != ENOENT)
                 return -errno;
         }
@@ -300,11 +350,12 @@
         param.sched_priority = 0;
         sched_setscheduler(tid,
                            (policy == SP_BACKGROUND) ?
-                            SCHED_BATCH : SCHED_NORMAL,
+                           SCHED_BATCH : SCHED_NORMAL,
                            &param);
     }
 
-    prctl(PR_SET_TIMERSLACK_PID, policy == SP_BACKGROUND ? TIMER_SLACK_BG : 0, tid);
+    prctl(PR_SET_TIMERSLACK_PID,
+          policy == SP_BACKGROUND ? TIMER_SLACK_BG : TIMER_SLACK_FG, tid);
 
     return 0;
 }
@@ -341,4 +392,3 @@
     else
         return "error";
 }
-
diff --git a/libcutils/socket_local_client.c b/libcutils/socket_local_client.c
index ddcc2da..7b42daa 100644
--- a/libcutils/socket_local_client.c
+++ b/libcutils/socket_local_client.c
@@ -52,7 +52,7 @@
 
     switch (namespaceId) {
         case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
-#ifdef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE
+#if defined(__linux__)
             namelen  = strlen(name);
 
             // Test with length +1 for the *initial* '\0'.
@@ -67,7 +67,7 @@
             
             p_addr->sun_path[0] = 0;
             memcpy(p_addr->sun_path + 1, name, namelen);
-#else /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
+#else
             /* this OS doesn't have the Linux abstract namespace */
 
             namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
@@ -79,7 +79,7 @@
 
             strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
             strcat(p_addr->sun_path, name);
-#endif /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
+#endif
         break;
 
         case ANDROID_SOCKET_NAMESPACE_RESERVED:
diff --git a/libcutils/socket_local_server.c b/libcutils/socket_local_server.c
index 7628fe4..60eb86b 100644
--- a/libcutils/socket_local_server.c
+++ b/libcutils/socket_local_server.c
@@ -66,7 +66,7 @@
     }
 
     /* basically: if this is a filesystem path, unlink first */
-#ifndef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE
+#if !defined(__linux__)
     if (1) {
 #else
     if (namespaceId == ANDROID_SOCKET_NAMESPACE_RESERVED
diff --git a/libcutils/socket_network_client.c b/libcutils/socket_network_client.c
index 4826033..e0031ba 100644
--- a/libcutils/socket_network_client.c
+++ b/libcutils/socket_network_client.c
@@ -45,7 +45,6 @@
 {
     struct hostent *hp;
     struct sockaddr_in addr;
-    socklen_t alen;
     int s;
     int flags = 0, error = 0, ret = 0;
     fd_set rset, wset;
diff --git a/libcutils/str_parms.c b/libcutils/str_parms.c
index dfe8c4b..924289a 100644
--- a/libcutils/str_parms.c
+++ b/libcutils/str_parms.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2013 The Android Open Source Project
+ * 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.
@@ -357,51 +357,3 @@
 {
     hashmapForEach(str_parms->map, dump_entry, str_parms);
 }
-
-#ifdef TEST_STR_PARMS
-static void test_str_parms_str(const char *str)
-{
-    struct str_parms *str_parms;
-    char *out_str;
-
-    str_parms = str_parms_create_str(str);
-    str_parms_add_str(str_parms, "dude", "woah");
-    str_parms_add_str(str_parms, "dude", "woah");
-    str_parms_del(str_parms, "dude");
-    str_parms_dump(str_parms);
-    out_str = str_parms_to_str(str_parms);
-    str_parms_destroy(str_parms);
-    ALOGI("%s: '%s' stringified is '%s'", __func__, str, out_str);
-    free(out_str);
-}
-
-int main(void)
-{
-    test_str_parms_str("");
-    test_str_parms_str(";");
-    test_str_parms_str("=");
-    test_str_parms_str("=;");
-    test_str_parms_str("=bar");
-    test_str_parms_str("=bar;");
-    test_str_parms_str("foo=");
-    test_str_parms_str("foo=;");
-    test_str_parms_str("foo=bar");
-    test_str_parms_str("foo=bar;");
-    test_str_parms_str("foo=bar;baz");
-    test_str_parms_str("foo=bar;baz=");
-    test_str_parms_str("foo=bar;baz=bat");
-    test_str_parms_str("foo=bar;baz=bat;");
-    test_str_parms_str("foo=bar;baz=bat;foo=bar");
-
-    // hashmapPut reports errors by setting errno to ENOMEM.
-    // Test that we're not confused by running in an environment where this is already true.
-    errno = ENOMEM;
-    test_str_parms_str("foo=bar;baz=");
-    if (errno != ENOMEM) {
-        abort();
-    }
-    test_str_parms_str("foo=bar;baz=");
-
-    return 0;
-}
-#endif
diff --git a/libcutils/memory.c b/libcutils/strlcpy.c
similarity index 62%
rename from libcutils/memory.c
rename to libcutils/strlcpy.c
index 6486b45..c66246c 100644
--- a/libcutils/memory.c
+++ b/libcutils/strlcpy.c
@@ -1,43 +1,4 @@
 /*
- * 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 <cutils/memory.h>
-
-#if !HAVE_MEMSET16
-void android_memset16(uint16_t* dst, uint16_t value, size_t size)
-{
-    size >>= 1;
-    while (size--) {
-        *dst++ = value;
-    }
-}
-#endif
-
-#if !HAVE_MEMSET32
-void android_memset32(uint32_t* dst, uint32_t value, size_t size)
-{
-    size >>= 2;
-    while (size--) {
-        *dst++ = value;
-    }
-}
-#endif
-
-#if !HAVE_STRLCPY
-/*
  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -54,8 +15,13 @@
  */
 
 #include <sys/types.h>
+
+#if defined(__GLIBC__) || defined(_WIN32)
+
 #include <string.h>
 
+#include <cutils/memory.h>
+
 /* Implementation of strlcpy() for platforms that don't already have it. */
 
 /*
@@ -88,4 +54,5 @@
 
 	return(s - src - 1);	/* count does not include NUL */
 }
+
 #endif
diff --git a/libcutils/tests/Android.mk b/libcutils/tests/Android.mk
index 8e65310..cf70345 100644
--- a/libcutils/tests/Android.mk
+++ b/libcutils/tests/Android.mk
@@ -15,17 +15,23 @@
 LOCAL_PATH := $(call my-dir)
 
 test_src_files := \
+    test_str_parms.cpp \
+
+test_target_only_src_files := \
     MemsetTest.cpp \
     PropertiesTest.cpp \
 
+test_libraries := libcutils liblog
+
+
+#
+# Target.
+#
+
 include $(CLEAR_VARS)
 LOCAL_MODULE := libcutils_test
-LOCAL_SRC_FILES := $(test_src_files)
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    liblog \
-    libutils \
-
+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
@@ -34,15 +40,34 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := libcutils_test_static
 LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_SRC_FILES := $(test_src_files)
-LOCAL_STATIC_LIBRARIES := \
-    libc \
-    libcutils \
-    liblog \
-    libstlport_static \
-    libutils \
-
+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)
+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_STATIC_LIBRARIES := $(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_HOST_NATIVE_TEST)
diff --git a/libcutils/tests/test_str_parms.cpp b/libcutils/tests/test_str_parms.cpp
new file mode 100644
index 0000000..d8f639b
--- /dev/null
+++ b/libcutils/tests/test_str_parms.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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 <cutils/str_parms.h>
+#include <gtest/gtest.h>
+
+static void test_str_parms_str(const char* str, const char* expected) {
+    str_parms* str_parms = str_parms_create_str(str);
+    str_parms_add_str(str_parms, "dude", "woah");
+    str_parms_add_str(str_parms, "dude", "woah");
+    str_parms_del(str_parms, "dude");
+    str_parms_dump(str_parms);
+    char* out_str = str_parms_to_str(str_parms);
+    str_parms_destroy(str_parms);
+    ASSERT_STREQ(expected, out_str) << str;
+    free(out_str);
+}
+
+TEST(str_parms, smoke) {
+    test_str_parms_str("", "");
+    test_str_parms_str(";", "");
+    test_str_parms_str("=", "");
+    test_str_parms_str("=;", "");
+    test_str_parms_str("=bar", "");
+    test_str_parms_str("=bar;", "");
+    test_str_parms_str("foo=", "foo=");
+    test_str_parms_str("foo=;", "foo=");
+    test_str_parms_str("foo=bar", "foo=bar");
+    test_str_parms_str("foo=bar;", "foo=bar");
+    test_str_parms_str("foo=bar;baz", "foo=bar;baz=");
+    test_str_parms_str("foo=bar;baz=", "foo=bar;baz=");
+    test_str_parms_str("foo=bar;baz=bat", "foo=bar;baz=bat");
+    test_str_parms_str("foo=bar;baz=bat;", "foo=bar;baz=bat");
+    test_str_parms_str("foo=bar1;baz=bat;foo=bar2", "foo=bar2;baz=bat");
+}
+
+TEST(str_parms, put_ENOMEM) {
+    // hashmapPut reports errors by setting errno to ENOMEM.
+    // Test that we're not confused by running in an environment where this is already true.
+    errno = ENOMEM;
+    test_str_parms_str("foo=bar;baz=", "foo=bar;baz=");
+    ASSERT_EQ(ENOMEM, errno);
+    test_str_parms_str("foo=bar;baz=", "foo=bar;baz=");
+}
diff --git a/libcutils/threads.c b/libcutils/threads.c
index bf182f0..036f8c5 100644
--- a/libcutils/threads.c
+++ b/libcutils/threads.c
@@ -1,22 +1,51 @@
 /*
 ** 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 
+** Licensed under the Apache License, Version 2.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 <cutils/threads.h>
+#include "cutils/threads.h"
 
-#ifdef HAVE_PTHREADS
+// For gettid.
+#if defined(__APPLE__)
+#include "AvailabilityMacros.h"  // For MAC_OS_X_VERSION_MAX_ALLOWED
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <unistd.h>
+#elif defined(__linux__) && !defined(__ANDROID__)
+#include <syscall.h>
+#include <unistd.h>
+#elif defined(_WIN32)
+#include <windows.h>
+#endif
+
+// No definition needed for Android because we'll just pick up bionic's copy.
+#ifndef __ANDROID__
+pid_t gettid() {
+#if defined(__APPLE__)
+  return syscall(SYS_thread_selfid);
+#elif defined(__linux__)
+  return syscall(__NR_gettid);
+#elif defined(_WIN32)
+  return GetCurrentThreadId();
+#endif
+}
+#endif  // __ANDROID__
+
+#if !defined(_WIN32)
+
 void*  thread_store_get( thread_store_t*  store )
 {
     if (!store->has_tls)
@@ -24,8 +53,8 @@
 
     return pthread_getspecific( store->tls );
 }
-    
-extern void   thread_store_set( thread_store_t*          store, 
+
+extern void   thread_store_set( thread_store_t*          store,
                                 void*                    value,
                                 thread_store_destruct_t  destroy)
 {
@@ -42,14 +71,12 @@
     pthread_setspecific( store->tls, value );
 }
 
-#endif
-
-#ifdef HAVE_WIN32_THREADS
+#else /* !defined(_WIN32) */
 void*  thread_store_get( thread_store_t*  store )
 {
     if (!store->has_tls)
         return NULL;
-    
+
     return (void*) TlsGetValue( store->tls );
 }
 
@@ -65,7 +92,7 @@
     } else while (store->lock_init != -2) {
         Sleep(10); /* 10ms */
     }
-        
+
     EnterCriticalSection( &store->lock );
     if (!store->has_tls) {
         store->tls = TlsAlloc();
@@ -76,7 +103,7 @@
         store->has_tls = 1;
     }
     LeaveCriticalSection( &store->lock );
-    
+
     TlsSetValue( store->tls, value );
 }
-#endif
+#endif /* !defined(_WIN32) */
diff --git a/libcutils/trace.c b/libcutils/trace-dev.c
similarity index 72%
rename from libcutils/trace.c
rename to libcutils/trace-dev.c
index f57aac2..a06987e 100644
--- a/libcutils/trace.c
+++ b/libcutils/trace-dev.c
@@ -18,11 +18,11 @@
 #include <fcntl.h>
 #include <limits.h>
 #include <pthread.h>
+#include <stdatomic.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
-#include <cutils/atomic.h>
 #include <cutils/compiler.h>
 #include <cutils/properties.h>
 #include <cutils/trace.h>
@@ -30,11 +30,18 @@
 #define LOG_TAG "cutils-trace"
 #include <log/log.h>
 
-volatile int32_t        atrace_is_ready      = 0;
+/**
+ * Maximum size of a message that can be logged to the trace buffer.
+ * Note this message includes a tag, the pid, and the string given as the name.
+ * Names should be kept short to get the most use of the trace buffer.
+ */
+#define ATRACE_MESSAGE_LENGTH 1024
+
+atomic_bool             atrace_is_ready      = ATOMIC_VAR_INIT(false);
 int                     atrace_marker_fd     = -1;
 uint64_t                atrace_enabled_tags  = ATRACE_TAG_NOT_READY;
 static bool             atrace_is_debuggable = false;
-static volatile int32_t atrace_is_enabled    = 1;
+static atomic_bool      atrace_is_enabled    = ATOMIC_VAR_INIT(true);
 static pthread_once_t   atrace_once_control  = PTHREAD_ONCE_INIT;
 static pthread_mutex_t  atrace_tags_mutex    = PTHREAD_MUTEX_INITIALIZER;
 
@@ -51,7 +58,7 @@
 // the Zygote process from tracing.
 void atrace_set_tracing_enabled(bool enabled)
 {
-    android_atomic_release_store(enabled ? 1 : 0, &atrace_is_enabled);
+    atomic_store_explicit(&atrace_is_enabled, enabled, memory_order_release);
     atrace_update_tags();
 }
 
@@ -148,8 +155,8 @@
 void atrace_update_tags()
 {
     uint64_t tags;
-    if (CC_UNLIKELY(android_atomic_acquire_load(&atrace_is_ready))) {
-        if (android_atomic_acquire_load(&atrace_is_enabled)) {
+    if (CC_UNLIKELY(atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) {
+        if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
             tags = atrace_get_property();
             pthread_mutex_lock(&atrace_tags_mutex);
             atrace_enabled_tags = tags;
@@ -176,10 +183,60 @@
     atrace_enabled_tags = atrace_get_property();
 
 done:
-    android_atomic_release_store(1, &atrace_is_ready);
+    atomic_store_explicit(&atrace_is_ready, true, memory_order_release);
 }
 
 void atrace_setup()
 {
     pthread_once(&atrace_once_control, atrace_init_once);
 }
+
+void atrace_begin_body(const char* name)
+{
+    char buf[ATRACE_MESSAGE_LENGTH];
+    size_t len;
+
+    len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "B|%d|%s", getpid(), name);
+    write(atrace_marker_fd, buf, len);
+}
+
+
+void atrace_async_begin_body(const char* name, int32_t cookie)
+{
+    char buf[ATRACE_MESSAGE_LENGTH];
+    size_t len;
+
+    len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "S|%d|%s|%" PRId32,
+            getpid(), name, cookie);
+    write(atrace_marker_fd, buf, len);
+}
+
+void atrace_async_end_body(const char* name, int32_t cookie)
+{
+    char buf[ATRACE_MESSAGE_LENGTH];
+    size_t len;
+
+    len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "F|%d|%s|%" PRId32,
+            getpid(), name, cookie);
+    write(atrace_marker_fd, buf, len);
+}
+
+void atrace_int_body(const char* name, int32_t value)
+{
+    char buf[ATRACE_MESSAGE_LENGTH];
+    size_t len;
+
+    len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%" PRId32,
+            getpid(), name, value);
+    write(atrace_marker_fd, buf, len);
+}
+
+void atrace_int64_body(const char* name, int64_t value)
+{
+    char buf[ATRACE_MESSAGE_LENGTH];
+    size_t len;
+
+    len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%" PRId64,
+            getpid(), name, value);
+    write(atrace_marker_fd, buf, len);
+}
diff --git a/libcutils/trace-host.c b/libcutils/trace-host.c
new file mode 100644
index 0000000..6478e3e
--- /dev/null
+++ b/libcutils/trace-host.c
@@ -0,0 +1,35 @@
+/*
+ * 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 <cutils/trace.h>
+
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
+
+atomic_bool             atrace_is_ready      = ATOMIC_VAR_INIT(true);
+int                     atrace_marker_fd     = -1;
+uint64_t                atrace_enabled_tags  = 0;
+
+void atrace_set_debuggable(bool debuggable __unused) { }
+void atrace_set_tracing_enabled(bool enabled __unused) { }
+void atrace_update_tags() { }
+void atrace_setup() { }
+void atrace_begin_body(const char* name __unused) { }
+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) { }
+void atrace_int64_body(const char* name __unused, int64_t value __unused) { }
diff --git a/libcutils/uevent.c b/libcutils/uevent.c
index 97a81e3..de5d227 100644
--- a/libcutils/uevent.c
+++ b/libcutils/uevent.c
@@ -31,12 +31,12 @@
  */
 ssize_t uevent_kernel_multicast_recv(int socket, void *buffer, size_t length)
 {
-    uid_t user = -1;
-    return uevent_kernel_multicast_uid_recv(socket, buffer, length, &user);
+    uid_t uid = -1;
+    return uevent_kernel_multicast_uid_recv(socket, buffer, length, &uid);
 }
 
 /**
- * Like the above, but passes a uid_t in by reference. In the event that this
+ * Like the above, but passes a uid_t in by pointer. In the event that this
  * fails due to a bad uid check, the uid_t will be set to the uid of the
  * socket's peer.
  *
@@ -44,8 +44,12 @@
  * returns -1, sets errno to EIO, and sets "user" to the UID associated with the
  * message. If the peer UID cannot be determined, "user" is set to -1."
  */
-ssize_t uevent_kernel_multicast_uid_recv(int socket, void *buffer,
-                                         size_t length, uid_t *user)
+ssize_t uevent_kernel_multicast_uid_recv(int socket, void *buffer, size_t length, uid_t *uid)
+{
+    return uevent_kernel_recv(socket, buffer, length, true, uid);
+}
+
+ssize_t uevent_kernel_recv(int socket, void *buffer, size_t length, bool require_group, uid_t *uid)
 {
     struct iovec iov = { buffer, length };
     struct sockaddr_nl addr;
@@ -60,7 +64,7 @@
         0,
     };
 
-    *user = -1;
+    *uid = -1;
     ssize_t n = recvmsg(socket, &hdr, 0);
     if (n <= 0) {
         return n;
@@ -73,14 +77,18 @@
     }
 
     struct ucred *cred = (struct ucred *)CMSG_DATA(cmsg);
-    *user = cred->uid;
+    *uid = cred->uid;
     if (cred->uid != 0) {
         /* ignoring netlink message from non-root user */
         goto out;
     }
 
-    if (addr.nl_groups == 0 || addr.nl_pid != 0) {
-        /* ignoring non-kernel or unicast netlink message */
+    if (addr.nl_pid != 0) {
+        /* ignore non-kernel */
+        goto out;
+    }
+    if (require_group && addr.nl_groups == 0) {
+        /* ignore unicast messages when requested */
         goto out;
     }
 
@@ -104,7 +112,7 @@
     addr.nl_pid = getpid();
     addr.nl_groups = 0xffffffff;
 
-    s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+    s = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT);
     if(s < 0)
         return -1;
 
diff --git a/libion/ion.c b/libion/ion.c
index 80bdc2a..d1984bd 100644
--- a/libion/ion.c
+++ b/libion/ion.c
@@ -23,6 +23,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
+#include <string.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 #include <sys/types.h>
@@ -90,6 +91,7 @@
             int flags, off_t offset, unsigned char **ptr, int *map_fd)
 {
     int ret;
+    unsigned char *tmp_ptr;
     struct ion_fd_data data = {
         .handle = handle,
     };
@@ -102,22 +104,22 @@
     ret = ion_ioctl(fd, ION_IOC_MAP, &data);
     if (ret < 0)
         return ret;
-    *map_fd = data.fd;
-    if (*map_fd < 0) {
+    if (data.fd < 0) {
         ALOGE("map ioctl returned negative fd\n");
         return -EINVAL;
     }
-    *ptr = mmap(NULL, length, prot, flags, *map_fd, offset);
-    if (*ptr == MAP_FAILED) {
+    tmp_ptr = mmap(NULL, length, prot, flags, data.fd, offset);
+    if (tmp_ptr == MAP_FAILED) {
         ALOGE("mmap failed: %s\n", strerror(errno));
         return -errno;
     }
+    *map_fd = data.fd;
+    *ptr = tmp_ptr;
     return ret;
 }
 
 int ion_share(int fd, ion_user_handle_t handle, int *share_fd)
 {
-    int map_fd;
     int ret;
     struct ion_fd_data data = {
         .handle = handle,
@@ -129,11 +131,11 @@
     ret = ion_ioctl(fd, ION_IOC_SHARE, &data);
     if (ret < 0)
         return ret;
-    *share_fd = data.fd;
-    if (*share_fd < 0) {
+    if (data.fd < 0) {
         ALOGE("share ioctl returned negative fd\n");
         return -EINVAL;
     }
+    *share_fd = data.fd;
     return ret;
 }
 
diff --git a/libion/ion_test.c b/libion/ion_test.c
index 8872282..b7d5583 100644
--- a/libion/ion_test.c
+++ b/libion/ion_test.c
@@ -164,8 +164,9 @@
         printf("master->master? [%10s]\n", ptr);
         if (recvmsg(sd[0], &msg, 0) < 0)
             perror("master recv 1");
+        close(fd);
+        _exit(0);
     } else {
-        struct msghdr msg;
         struct cmsghdr *cmsg;
         char* ptr;
         int fd, recv_fd;
@@ -205,6 +206,7 @@
         strcpy(ptr, "child");
         printf("child sending msg 2\n");
         sendmsg(sd[1], &child_msg, 0);
+        close(fd);
     }
 }
 
diff --git a/libion/tests/Android.mk b/libion/tests/Android.mk
index 8dc7f9d..894f90e 100644
--- a/libion/tests/Android.mk
+++ b/libion/tests/Android.mk
@@ -18,10 +18,8 @@
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := ion-unit-tests
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers
 LOCAL_SHARED_LIBRARIES += libion
-LOCAL_STATIC_LIBRARIES += libgtest_main
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/../kernel-headers
 LOCAL_SRC_FILES := \
 	ion_test_fixture.cpp \
diff --git a/liblog/Android.mk b/liblog/Android.mk
index 1a63761..115dd79 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -16,6 +16,14 @@
 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
+
 ifneq ($(TARGET_USES_LOGD),false)
 liblog_sources := logd_write.c log_event_write.c
 else
@@ -25,28 +33,20 @@
 # 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
-WITH_MINGW :=
-ifeq ($(HOST_OS),windows)
-    ifeq ($(strip $(USE_CYGWIN)),)
-        WITH_MINGW := true
-    endif
-endif
-# USE_MINGW is defined when we build against Mingw on Linux
-ifneq ($(strip $(USE_MINGW)),)
-    WITH_MINGW := true
-endif
 
-ifndef WITH_MINGW
+ifeq ($(strip $(USE_MINGW)),)
     liblog_sources += \
-        logprint.c \
         event_tag_map.c
 else
     liblog_sources += \
         uio.c
 endif
 
-liblog_host_sources := $(liblog_sources) fake_log_device.c
-liblog_target_sources := $(liblog_sources) log_time.cpp
+liblog_host_sources := $(liblog_sources) fake_log_device.c event.logtags
+liblog_target_sources := $(liblog_sources) log_time.cpp log_is_loggable.c
+ifeq ($(strip $(USE_MINGW)),)
+liblog_target_sources += logprint.c
+endif
 ifneq ($(TARGET_USES_LOGD),false)
 liblog_target_sources += log_read.c
 else
@@ -57,7 +57,7 @@
 # ========================================================
 LOCAL_MODULE := liblog
 LOCAL_SRC_FILES := $(liblog_host_sources)
-LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -Werror
+LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -Werror $(liblog_cflags)
 LOCAL_MULTILIB := both
 include $(BUILD_HOST_STATIC_LIBRARY)
 
@@ -76,13 +76,17 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := liblog
 LOCAL_SRC_FILES := $(liblog_target_sources)
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror $(liblog_cflags)
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := liblog
 LOCAL_WHOLE_STATIC_LIBRARIES := liblog
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror $(liblog_cflags)
+
+# TODO: This is to work around b/19059885. Remove after root cause is fixed
+LOCAL_LDFLAGS_arm := -Wl,--hash-style=both
+
 include $(BUILD_SHARED_LIBRARY)
 
 include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/liblog/README b/liblog/README
index d7472e4..f29ac04 100644
--- a/liblog/README
+++ b/liblog/README
@@ -111,24 +111,56 @@
        ger_list_alloc,  calling  in  turn the android_logger_open for each log
        id.  Each entry can be retrieved  with  android_logger_list_read.   The
        log(s) can be closed with android_logger_list_free.  The logs should be
-       opened with an O_RDONLY mode.  O_NDELAY mode will report when  the  log
-       reading  is  done  with  an  EAGAIN  error  return  code, otherwise the
-       android_logger_list_read call will block for new entries.
+       opened  with an  ANDROID_LOG_RDONLY  mode.   ANDROID_LOG_NONBLOCK  mode
+       will report when the  log reading is done with an  EAGAIN  error return
+       code,  otherwise the  android_logger_list_read  call will block for new
+       entries.
+
+       The  ANDROID_LOG_PSTORE mode flag to the android_logger_open is used to
+       switch from the active logs to the persistent logs from before the last
+       reboot.
 
        The value returned by android_logger_open can be used as a parameter to
        the  android_logger_clear  function to empty the sub-log.  It is recom‐
-       mended to only open log O_WRONLY.
+       mended to only open log ANDROID_LOG_WRONLY in that case.
 
        The value returned by android_logger_open can be used as a parameter to
        the android_logger_get_log_(size|readable_size|version) to retrieve the
        sub-log maximum size, readable size and log buffer format protocol ver‐
        sion  respectively.  android_logger_get_id returns the id that was used
-       when opening the sub-log.  It is recommended to open the  log  O_RDONLY
-       in these cases.
+       when  opening  the  sub-log.    It  is  recommended  to  open  the  log
+       ANDROID_LOG_RDONLY in these cases.
+
+ERRORS
+       If messages fail, a negative error code will be returned to the caller.
+
+       The -ENOTCONN return code indicates that the logger daemon is stopped.
+
+       The  -EBADF return code indicates that the log access point can not be
+       opened, or the log buffer id is out of range.
+
+       For the  -EAGAIN  return code,  this means that the logging message was
+       temporarily backed-up either because of Denial Of Service (DOS) logging
+       pressure from some chatty application or service in the Android system,
+       or if too small of a value is set in /proc/sys/net/unix/max_dgram_qlen.
+       To aid in diagnosing the occurence of this,  a binary event from liblog
+       will be sent to the  log  daemon  once a  new  message  can get through
+       indicating how many  messages were  dropped  as a result.   Please take
+       action to resolve the structural problems at the source.
+
+       It is generally not advised for the caller to retry the  -EAGAIN return
+       code as  this  will  only  make the  problem(s)  worse  and  cause your
+       application to temporarily drop to the  logger daemon  priority,  BATCH
+       scheduling policy and background task cgroup. If you require a group of
+       messages to be passed atomically,  merge  them  into  one  message with
+       embedded newlines to the maximum length LOGGER_ENTRY_MAX_PAYLOAD.
+
+       Other return codes  from  writing operation can be returned.  Since the
+       library retries on EINTR, -EINTR should never be returned.
 
 SEE ALSO
        syslogd(8)
 
 
 
-                                  17 Dec 2013                        LIBLOG(3)
+                                  24 Jan 2014                        LIBLOG(3)
diff --git a/liblog/event.logtags b/liblog/event.logtags
new file mode 100644
index 0000000..72ecab1
--- /dev/null
+++ b/liblog/event.logtags
@@ -0,0 +1,36 @@
+# The entries in this file map a sparse set of log tag numbers to tag names.
+# This is installed on the device, in /system/etc, and parsed by logcat.
+#
+# Tag numbers are decimal integers, from 0 to 2^31.  (Let's leave the
+# negative values alone for now.)
+#
+# Tag names are one or more ASCII letters and numbers or underscores, i.e.
+# "[A-Z][a-z][0-9]_".  Do not include spaces or punctuation (the former
+# impacts log readability, the latter makes regex searches more annoying).
+#
+# Tag numbers and names are separated by whitespace.  Blank lines and lines
+# starting with '#' are ignored.
+#
+# 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
+#
+# 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).
+#
+# TODO: generate ".java" and ".h" files with integer constants from this file.
+
+1005  liblog (dropped|1)
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index 136792d..8a8ece2 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -29,7 +29,7 @@
 
 #include <log/logd.h>
 
-#ifdef HAVE_PTHREADS
+#if !defined(_WIN32)
 #include <pthread.h>
 #endif
 
@@ -88,7 +88,7 @@
 } LogState;
 
 
-#ifdef HAVE_PTHREADS
+#if !defined(_WIN32)
 /*
  * Locking.  Since we're emulating a device, we need to be prepared
  * to have multiple callers at the same time.  This lock is used
@@ -106,10 +106,10 @@
 {
     pthread_mutex_unlock(&fakeLogDeviceLock);
 }
-#else   // !HAVE_PTHREADS
+#else   // !defined(_WIN32)
 #define lock() ((void)0)
 #define unlock() ((void)0)
-#endif  // !HAVE_PTHREADS
+#endif  // !defined(_WIN32)
 
 
 /*
@@ -320,9 +320,9 @@
     return priorityStrings[idx];
 }
 
-#ifndef HAVE_WRITEV
+#if defined(_WIN32)
 /*
- * Some platforms like WIN32 do not have writev().
+ * WIN32 does not have writev().
  * Make up something to replace it.
  */
 static ssize_t fake_writev(int fd, const struct iovec *iov, int iovcnt) {
@@ -352,7 +352,7 @@
 static void showLog(LogState *state,
         int logPrio, const char* tag, const char* msg)
 {
-#if defined(HAVE_LOCALTIME_R)
+#if !defined(_WIN32)
     struct tm tmBuf;
 #endif
     struct tm* ptm;
@@ -377,7 +377,7 @@
      * in the time stamp.  Don't use forward slashes, parenthesis,
      * brackets, asterisks, or other special chars here.
      */
-#if defined(HAVE_LOCALTIME_R)
+#if !defined(_WIN32)
     ptm = localtime_r(&when, &tmBuf);
 #else
     ptm = localtime(&when);
@@ -689,3 +689,9 @@
     /* Assume that open() was called first. */
     return redirectWritev(fd, vector, count);
 }
+
+int __android_log_is_loggable(int prio, const char *tag __unused, int def)
+{
+    int logLevel = def;
+    return logLevel >= 0 && prio >= logLevel;
+}
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
new file mode 100644
index 0000000..7a8e33f
--- /dev/null
+++ b/liblog/log_is_loggable.c
@@ -0,0 +1,178 @@
+/*
+** 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 <ctype.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+
+#include <android/log.h>
+
+struct cache {
+    const prop_info *pinfo;
+    uint32_t serial;
+    char c;
+};
+
+static void refresh_cache(struct cache *cache, const char *key)
+{
+    uint32_t serial;
+    char buf[PROP_VALUE_MAX];
+
+    if (!cache->pinfo) {
+        cache->pinfo = __system_property_find(key);
+        if (!cache->pinfo) {
+            return;
+        }
+    }
+    serial = __system_property_serial(cache->pinfo);
+    if (serial == cache->serial) {
+        return;
+    }
+    cache->serial = serial;
+    __system_property_read(cache->pinfo, 0, buf);
+    cache->c = buf[0];
+}
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+static int __android_log_level(const char *tag, int def)
+{
+    /* 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;
+    /* sizeof(log_namespace) = strlen(log_namespace) + 1 */
+    char key[sizeof(log_namespace) + taglen];
+    char *kp;
+    size_t i;
+    char c = 0;
+    /*
+     * Single layer cache of four properties. Priorities are:
+     *    log.tag.<tag>
+     *    persist.log.tag.<tag>
+     *    log.tag
+     *    persist.log.tag
+     * Where the missing tag matches all tags and becomes the
+     * system global default. We do not support ro.log.tag* .
+     */
+    static char *last_tag;
+    static uint32_t global_serial;
+    uint32_t current_global_serial;
+    static struct cache tag_cache[2] = {
+        { NULL, -1, 0 },
+        { NULL, -1, 0 }
+    };
+    static struct cache global_cache[2] = {
+        { NULL, -1, 0 },
+        { NULL, -1, 0 }
+    };
+
+    strcpy(key, log_namespace);
+
+    pthread_mutex_lock(&lock);
+
+    current_global_serial = __system_property_area_serial();
+
+    if (taglen) {
+        uint32_t current_local_serial = current_global_serial;
+
+        if (!last_tag || strcmp(last_tag, tag)) {
+            /* 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].serial = -1;
+                tag_cache[i].c = '\0';
+            }
+            free(last_tag);
+            last_tag = NULL;
+            current_global_serial = -1;
+        }
+        if (!last_tag) {
+            last_tag = strdup(tag);
+        }
+        strcpy(key + sizeof(log_namespace) - 1, tag);
+
+        kp = key;
+        for(i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
+            if (current_local_serial != global_serial) {
+                refresh_cache(&tag_cache[i], kp);
+            }
+
+            if (tag_cache[i].c) {
+                c = tag_cache[i].c;
+                break;
+            }
+
+            kp = key + base_offset;
+        }
+    }
+
+    switch (toupper(c)) { /* if invalid, resort to global */
+    case 'V':
+    case 'D':
+    case 'I':
+    case 'W':
+    case 'E':
+    case 'F': /* Not officially supported */
+    case 'A':
+    case 'S':
+        break;
+    default:
+        /* clear '.' after log.tag */
+        key[sizeof(log_namespace) - 2] = '\0';
+
+        kp = key;
+        for(i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
+            if (current_global_serial != global_serial) {
+                refresh_cache(&global_cache[i], kp);
+            }
+
+            if (global_cache[i].c) {
+                c = global_cache[i].c;
+                break;
+            }
+
+            kp = key + base_offset;
+        }
+        break;
+    }
+
+    global_serial = current_global_serial;
+
+    pthread_mutex_unlock(&lock);
+
+    switch (toupper(c)) {
+    case 'V': return ANDROID_LOG_VERBOSE;
+    case 'D': return ANDROID_LOG_DEBUG;
+    case 'I': return ANDROID_LOG_INFO;
+    case 'W': return ANDROID_LOG_WARN;
+    case 'E': return ANDROID_LOG_ERROR;
+    case 'F': /* FALLTHRU */ /* Not officially supported */
+    case 'A': return ANDROID_LOG_FATAL;
+    case 'S': return -1; /* ANDROID_LOG_SUPPRESS */
+    }
+    return def;
+}
+
+int __android_log_is_loggable(int prio, const char *tag, int def)
+{
+    int logLevel = __android_log_level(tag, def);
+    return logLevel >= 0 && prio >= logLevel;
+}
diff --git a/liblog/log_read.c b/liblog/log_read.c
index ca5a1a7..9c4af30 100644
--- a/liblog/log_read.c
+++ b/liblog/log_read.c
@@ -19,6 +19,7 @@
 #include <inttypes.h>
 #include <poll.h>
 #include <signal.h>
+#include <stdbool.h>
 #include <stddef.h>
 #define NOMINMAX /* for windows to suppress definition of min in stdlib.h */
 #include <stdlib.h>
@@ -30,11 +31,17 @@
 #include <cutils/sockets.h>
 #include <log/log.h>
 #include <log/logger.h>
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
 
 /* branchless on many architectures. */
 #define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
 
+#if (defined(USE_MINGW) || defined(HAVE_WINSOCK))
+#define WEAK static
+#else
 #define WEAK __attribute__((weak))
+#endif
 #ifndef __unused
 #define __unused __attribute__((unused))
 #endif
@@ -72,7 +79,7 @@
 
     switch (namespaceId) {
     case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
-#ifdef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE
+#if defined(__linux__)
         namelen  = strlen(name);
 
         /* Test with length +1 for the *initial* '\0'. */
@@ -87,7 +94,7 @@
 
         p_addr->sun_path[0] = 0;
         memcpy(p_addr->sun_path + 1, name, namelen);
-#else /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
+#else
         /* this OS doesn't have the Linux abstract namespace */
 
         namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
@@ -99,7 +106,7 @@
 
         strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
         strcat(p_addr->sun_path, name);
-#endif /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
+#endif
         break;
 
     case ANDROID_SOCKET_NAMESPACE_RESERVED:
@@ -201,6 +208,7 @@
     [LOG_ID_EVENTS] = "events",
     [LOG_ID_SYSTEM] = "system",
     [LOG_ID_CRASH] = "crash",
+    [LOG_ID_KERNEL] = "kernel",
 };
 
 const char *android_log_id_to_name(log_id_t log_id)
@@ -353,10 +361,64 @@
     return 0;
 }
 
+/* Determine the credentials of the caller */
+static bool uid_has_log_permission(uid_t uid)
+{
+    return (uid == AID_SYSTEM) || (uid == AID_LOG) || (uid == AID_ROOT);
+}
+
+static uid_t get_best_effective_uid()
+{
+    uid_t euid;
+    uid_t uid;
+    gid_t gid;
+    ssize_t i;
+    static uid_t last_uid = (uid_t) -1;
+
+    if (last_uid != (uid_t) -1) {
+        return last_uid;
+    }
+    uid = getuid();
+    if (uid_has_log_permission(uid)) {
+        return last_uid = uid;
+    }
+    euid = geteuid();
+    if (uid_has_log_permission(euid)) {
+        return last_uid = euid;
+    }
+    gid = getgid();
+    if (uid_has_log_permission(gid)) {
+        return last_uid = gid;
+    }
+    gid = getegid();
+    if (uid_has_log_permission(gid)) {
+        return last_uid = gid;
+    }
+    i = getgroups((size_t) 0, NULL);
+    if (i > 0) {
+        gid_t list[i];
+
+        getgroups(i, list);
+        while (--i >= 0) {
+            if (uid_has_log_permission(list[i])) {
+                return last_uid = list[i];
+            }
+        }
+    }
+    return last_uid = uid;
+}
+
 int android_logger_clear(struct logger *logger)
 {
     char buf[512];
 
+    if (logger->top->mode & ANDROID_LOG_PSTORE) {
+        if (uid_has_log_permission(get_best_effective_uid())) {
+            return unlink("/sys/fs/pstore/pmsg-ramoops-0");
+        }
+        errno = EPERM;
+        return -1;
+    }
     return check_log_success(buf,
         send_log_msg(logger, "clear %d", buf, sizeof(buf)));
 }
@@ -560,6 +622,116 @@
     return logger_list;
 }
 
+static int android_logger_list_read_pstore(struct logger_list *logger_list,
+                                           struct log_msg *log_msg)
+{
+    ssize_t ret;
+    off_t current, next;
+    uid_t uid;
+    struct logger *logger;
+    struct __attribute__((__packed__)) {
+        android_pmsg_log_header_t p;
+        android_log_header_t l;
+    } buf;
+    static uint8_t preread_count;
+
+    memset(log_msg, 0, sizeof(*log_msg));
+
+    if (logger_list->sock < 0) {
+        int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY);
+
+        if (fd < 0) {
+            return -errno;
+        }
+        logger_list->sock = fd;
+        preread_count = 0;
+    }
+
+    ret = 0;
+    while(1) {
+        if (preread_count < sizeof(buf)) {
+            ret = TEMP_FAILURE_RETRY(read(logger_list->sock,
+                                          &buf.p.magic + preread_count,
+                                          sizeof(buf) - preread_count));
+            if (ret < 0) {
+                return -errno;
+            }
+            preread_count += ret;
+        }
+        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)) {
+            do {
+                memmove(&buf.p.magic, &buf.p.magic + 1, --preread_count);
+            } while (preread_count && (buf.p.magic != LOGGER_MAGIC));
+            continue;
+        }
+        preread_count = 0;
+
+        logger_for_each(logger, logger_list) {
+            if (buf.l.id != logger->id) {
+                continue;
+            }
+
+            if ((logger_list->start.tv_sec || logger_list->start.tv_nsec)
+             && ((logger_list->start.tv_sec > buf.l.realtime.tv_sec)
+              || ((logger_list->start.tv_sec == buf.l.realtime.tv_sec)
+               && (logger_list->start.tv_nsec > buf.l.realtime.tv_nsec)))) {
+                break;
+            }
+
+            if (logger_list->pid && (logger_list->pid != buf.p.pid)) {
+                break;
+            }
+
+            uid = get_best_effective_uid();
+            if (!uid_has_log_permission(uid) && (uid != buf.p.uid)) {
+                break;
+            }
+
+            ret = TEMP_FAILURE_RETRY(read(logger_list->sock,
+                                          log_msg->entry_v3.msg,
+                                          buf.p.len - sizeof(buf)));
+            if (ret < 0) {
+                return -errno;
+            }
+            if (ret != (ssize_t)(buf.p.len - sizeof(buf))) {
+                return -EIO;
+            }
+
+            log_msg->entry_v3.len = buf.p.len - sizeof(buf);
+            log_msg->entry_v3.hdr_size = sizeof(log_msg->entry_v3);
+            log_msg->entry_v3.pid = buf.p.pid;
+            log_msg->entry_v3.tid = buf.l.tid;
+            log_msg->entry_v3.sec = buf.l.realtime.tv_sec;
+            log_msg->entry_v3.nsec = buf.l.realtime.tv_nsec;
+            log_msg->entry_v3.lid = buf.l.id;
+
+            return ret;
+        }
+
+        current = TEMP_FAILURE_RETRY(lseek(logger_list->sock,
+                                           (off_t)0, SEEK_CUR));
+        if (current < 0) {
+            return -errno;
+        }
+        next = TEMP_FAILURE_RETRY(lseek(logger_list->sock,
+                                        (off_t)(buf.p.len - sizeof(buf)),
+                                        SEEK_CUR));
+        if (next < 0) {
+            return -errno;
+        }
+        if ((next - current) != (ssize_t)(buf.p.len - sizeof(buf))) {
+            return -EIO;
+        }
+    }
+}
+
 static void caught_signal(int signum __unused)
 {
 }
@@ -578,7 +750,11 @@
         return -EINVAL;
     }
 
-    if (logger_list->mode & O_NONBLOCK) {
+    if (logger_list->mode & ANDROID_LOG_PSTORE) {
+        return android_logger_list_read_pstore(logger_list, log_msg);
+    }
+
+    if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
         memset(&ignore, 0, sizeof(ignore));
         ignore.sa_handler = caught_signal;
         sigemptyset(&ignore.sa_mask);
@@ -598,7 +774,7 @@
         }
 
         strcpy(buffer,
-               (logger_list->mode & O_NONBLOCK) ? "dumpAndClose" : "stream");
+               (logger_list->mode & ANDROID_LOG_NONBLOCK) ? "dumpAndClose" : "stream");
         cp = buffer + strlen(buffer);
 
         strcpy(cp, " lids");
@@ -636,14 +812,14 @@
             cp += ret;
         }
 
-        if (logger_list->mode & O_NONBLOCK) {
+        if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
             /* Deal with an unresponsive logd */
             sigaction(SIGALRM, &ignore, &old_sigaction);
             old_alarm = alarm(30);
         }
         ret = write(sock, buffer, cp - buffer);
         e = errno;
-        if (logger_list->mode & O_NONBLOCK) {
+        if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
             if (e == EINTR) {
                 e = ETIMEDOUT;
             }
@@ -669,7 +845,7 @@
     while(1) {
         memset(log_msg, 0, sizeof(*log_msg));
 
-        if (logger_list->mode & O_NONBLOCK) {
+        if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
             /* particularily useful if tombstone is reporting for logd */
             sigaction(SIGALRM, &ignore, &old_sigaction);
             old_alarm = alarm(30);
@@ -677,7 +853,7 @@
         /* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
         ret = recv(logger_list->sock, log_msg, LOGGER_ENTRY_MAX_LEN, 0);
         e = errno;
-        if (logger_list->mode & O_NONBLOCK) {
+        if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
             if ((ret == 0) || (e == EINTR)) {
                 e = EAGAIN;
                 ret = -1;
diff --git a/liblog/log_read_kern.c b/liblog/log_read_kern.c
index 41b8a51..69b405c 100644
--- a/liblog/log_read_kern.c
+++ b/liblog/log_read_kern.c
@@ -62,7 +62,8 @@
     [LOG_ID_RADIO] = "radio",
     [LOG_ID_EVENTS] = "events",
     [LOG_ID_SYSTEM] = "system",
-    [LOG_ID_CRASH] = "crash"
+    [LOG_ID_CRASH] = "crash",
+    [LOG_ID_KERNEL] = "kernel",
 };
 
 const char *android_log_id_to_name(log_id_t log_id)
@@ -75,10 +76,10 @@
 
 static int accessmode(int mode)
 {
-    if ((mode & O_ACCMODE) == O_WRONLY) {
+    if ((mode & ANDROID_LOG_ACCMODE) == ANDROID_LOG_WRONLY) {
         return W_OK;
     }
-    if ((mode & O_ACCMODE) == O_RDWR) {
+    if ((mode & ANDROID_LOG_ACCMODE) == ANDROID_LOG_RDWR) {
         return R_OK | W_OK;
     }
     return R_OK;
@@ -117,7 +118,7 @@
         ++b;
     }
 
-    ret = check_allocate_accessible(&n, b, O_RDONLY);
+    ret = check_allocate_accessible(&n, b, ANDROID_LOG_RDONLY);
     free(n);
     if (ret) {
         return ret;
@@ -201,8 +202,8 @@
         return -EFAULT;
     }
 
-    if (((mode & O_ACCMODE) == O_RDWR)
-            || (((mode ^ logger->top->mode) & O_ACCMODE) == 0)) {
+    if (((mode & ANDROID_LOG_ACCMODE) == ANDROID_LOG_RDWR)
+            || (((mode ^ logger->top->mode) & ANDROID_LOG_ACCMODE) == 0)) {
         return ioctl(logger->fd, cmd);
     }
 
@@ -227,13 +228,13 @@
 
 int android_logger_clear(struct logger *logger)
 {
-    return logger_ioctl(logger, LOGGER_FLUSH_LOG, O_WRONLY);
+    return logger_ioctl(logger, LOGGER_FLUSH_LOG, ANDROID_LOG_WRONLY);
 }
 
 /* returns the total size of the log's ring buffer */
 long android_logger_get_log_size(struct logger *logger)
 {
-    return logger_ioctl(logger, LOGGER_GET_LOG_BUF_SIZE, O_RDWR);
+    return logger_ioctl(logger, LOGGER_GET_LOG_BUF_SIZE, ANDROID_LOG_RDWR);
 }
 
 int android_logger_set_log_size(struct logger *logger __unused,
@@ -248,7 +249,7 @@
  */
 long android_logger_get_log_readable_size(struct logger *logger)
 {
-    return logger_ioctl(logger, LOGGER_GET_LOG_LEN, O_RDONLY);
+    return logger_ioctl(logger, LOGGER_GET_LOG_LEN, ANDROID_LOG_RDONLY);
 }
 
 /*
@@ -256,7 +257,7 @@
  */
 int android_logger_get_log_version(struct logger *logger)
 {
-    int ret = logger_ioctl(logger, LOGGER_GET_VERSION, O_RDWR);
+    int ret = logger_ioctl(logger, LOGGER_GET_VERSION, ANDROID_LOG_RDWR);
     return (ret < 0) ? 1 : ret;
 }
 
@@ -342,7 +343,7 @@
         goto err_name;
     }
 
-    logger->fd = open(n, logger_list->mode);
+    logger->fd = open(n, logger_list->mode & (ANDROID_LOG_ACCMODE | ANDROID_LOG_NONBLOCK));
     if (logger->fd < 0) {
         goto err_name;
     }
@@ -565,7 +566,7 @@
         if (result <= 0) {
             if (result) {
                 error = errno;
-            } else if (logger_list->mode & O_NDELAY) {
+            } else if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
                 error = EAGAIN;
             } else {
                 logger_list->timeout_ms = LOG_TIMEOUT_NEVER;
diff --git a/liblog/log_time.cpp b/liblog/log_time.cpp
index 755c2d9..9d5ea0e 100644
--- a/liblog/log_time.cpp
+++ b/liblog/log_time.cpp
@@ -22,7 +22,7 @@
 
 #include <log/log_read.h>
 
-const char log_time::default_format[] = "%m-%d %H:%M:%S.%3q";
+const char log_time::default_format[] = "%m-%d %H:%M:%S.%q";
 const timespec log_time::EPOCH = { 0, 0 };
 
 // Add %#q for fractional seconds to standard strptime function
@@ -39,7 +39,7 @@
 #endif
 
     struct tm *ptm;
-#if (defined(HAVE_LOCALTIME_R))
+#if !defined(_WIN32)
     struct tm tmBuf;
     ptm = localtime_r(&now, &tmBuf);
 #else
@@ -78,7 +78,7 @@
                 ++ret;
             }
             now = tv_sec;
-#if (defined(HAVE_LOCALTIME_R))
+#if !defined(_WIN32)
             ptm = localtime_r(&now, &tmBuf);
 #else
             ptm = localtime(&now);
@@ -150,6 +150,17 @@
     return *this;
 }
 
+log_time log_time::operator+= (const timespec &T) {
+    this->tv_nsec += (unsigned long int)T.tv_nsec;
+    if (this->tv_nsec >= NS_PER_SEC) {
+        this->tv_nsec -= NS_PER_SEC;
+        ++this->tv_sec;
+    }
+    this->tv_sec += T.tv_sec;
+
+    return *this;
+}
+
 log_time log_time::operator-= (const log_time &T) {
     // No concept of negative time, clamp to EPOCH
     if (*this <= T) {
@@ -166,3 +177,14 @@
 
     return *this;
 }
+
+log_time log_time::operator+= (const log_time &T) {
+    this->tv_nsec += T.tv_nsec;
+    if (this->tv_nsec >= NS_PER_SEC) {
+        this->tv_nsec -= NS_PER_SEC;
+        ++this->tv_sec;
+    }
+    this->tv_sec += T.tv_sec;
+
+    return *this;
+}
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index 6451abe..667fdb3 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -13,12 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#if (FAKE_LOG_DEVICE == 0)
+#include <endian.h>
+#endif
 #include <errno.h>
 #include <fcntl.h>
-#ifdef HAVE_PTHREADS
+#if !defined(_WIN32)
 #include <pthread.h>
 #endif
 #include <stdarg.h>
+#include <stdatomic.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -39,6 +43,7 @@
 #include <log/logger.h>
 #include <log/log_read.h>
 #include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
 
 #define LOG_BUF_SIZE 1024
 
@@ -49,7 +54,7 @@
 
 static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);
 static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;
-#ifdef HAVE_PTHREADS
+#if !defined(_WIN32)
 static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
 #endif
 
@@ -61,6 +66,7 @@
 static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1 };
 #else
 static int logd_fd = -1;
+static int pstore_fd = -1;
 #endif
 
 /*
@@ -71,6 +77,7 @@
 static enum {
     kLogUninitialized, kLogNotAvailable, kLogAvailable
 } g_log_status = kLogUninitialized;
+
 int __android_log_dev_available(void)
 {
     if (g_log_status == kLogUninitialized) {
@@ -83,15 +90,6 @@
     return (g_log_status == kLogAvailable);
 }
 
-#if !FAKE_LOG_DEVICE
-/* give up, resources too limited */
-static int __write_to_log_null(log_id_t log_fd __unused, struct iovec *vec __unused,
-                               size_t nr __unused)
-{
-    return -1;
-}
-#endif
-
 /* log_init_lock assumed */
 static int __write_to_log_initialize()
 {
@@ -104,40 +102,38 @@
         log_fds[i] = fakeLogOpen(buf, O_WRONLY);
     }
 #else
-    if (logd_fd >= 0) {
-        i = logd_fd;
-        logd_fd = -1;
-        close(i);
+    if (pstore_fd < 0) {
+        pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
     }
 
-    i = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
-    if (i < 0) {
-        ret = -errno;
-        write_to_log = __write_to_log_null;
-    } else if (fcntl(i, F_SETFL, O_NONBLOCK) < 0) {
-        ret = -errno;
-        close(i);
-        i = -1;
-        write_to_log = __write_to_log_null;
-    } else {
-        struct sockaddr_un un;
-        memset(&un, 0, sizeof(struct sockaddr_un));
-        un.sun_family = AF_UNIX;
-        strcpy(un.sun_path, "/dev/socket/logdw");
-
-        if (connect(i, (struct sockaddr *)&un, sizeof(struct sockaddr_un)) < 0) {
+    if (logd_fd < 0) {
+        i = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0));
+        if (i < 0) {
+            ret = -errno;
+        } else if (TEMP_FAILURE_RETRY(fcntl(i, F_SETFL, O_NONBLOCK)) < 0) {
             ret = -errno;
             close(i);
-            i = -1;
+        } else {
+            struct sockaddr_un un;
+            memset(&un, 0, sizeof(struct sockaddr_un));
+            un.sun_family = AF_UNIX;
+            strcpy(un.sun_path, "/dev/socket/logdw");
+
+            if (TEMP_FAILURE_RETRY(connect(i, (struct sockaddr *)&un,
+                                           sizeof(struct sockaddr_un))) < 0) {
+                ret = -errno;
+                close(i);
+            } else {
+                logd_fd = i;
+            }
         }
     }
-    logd_fd = i;
 #endif
 
     return ret;
 }
 
-static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr)
+static int __write_to_log_daemon(log_id_t log_id, struct iovec *vec, size_t nr)
 {
     ssize_t ret;
 #if FAKE_LOG_DEVICE
@@ -155,37 +151,32 @@
         }
     } while (ret == -EINTR);
 #else
-    static const unsigned header_length = 3;
+    static const unsigned header_length = 2;
     struct iovec newVec[nr + header_length];
-    typeof_log_id_t log_id_buf;
-    uint16_t tid;
+    android_log_header_t header;
+    android_pmsg_log_header_t pmsg_header;
     struct timespec ts;
-    log_time realtime_ts;
     size_t i, payload_size;
     static uid_t last_uid = AID_ROOT; /* logd *always* starts up as AID_ROOT */
+    static pid_t last_pid = (pid_t) -1;
+    static atomic_int_fast32_t dropped;
+
+    if (!nr) {
+        return -EINVAL;
+    }
 
     if (last_uid == AID_ROOT) { /* have we called to get the UID yet? */
         last_uid = getuid();
     }
-    if (last_uid == AID_LOGD) { /* logd, after initialization and priv drop */
-        /*
-         * ignore log messages we send to ourself (logd).
-         * Such log messages are often generated by libraries we depend on
-         * which use standard Android logging.
-         */
-        return 0;
+    if (last_pid == (pid_t) -1) {
+        last_pid = getpid();
     }
-
-    if (logd_fd < 0) {
-        return -EBADF;
-    }
-
     /*
      *  struct {
-     *      // what we provide
-     *      typeof_log_id_t  log_id;
-     *      u16              tid;
-     *      log_time         realtime;
+     *      // what we provide to pstore
+     *      android_pmsg_log_header_t pmsg_header;
+     *      // what we provide to socket
+     *      android_log_header_t header;
      *      // caller provides
      *      union {
      *          struct {
@@ -201,18 +192,42 @@
      */
 
     clock_gettime(CLOCK_REALTIME, &ts);
-    realtime_ts.tv_sec = ts.tv_sec;
-    realtime_ts.tv_nsec = ts.tv_nsec;
 
-    log_id_buf = log_id;
-    tid = gettid();
+    pmsg_header.magic = LOGGER_MAGIC;
+    pmsg_header.len = sizeof(pmsg_header) + sizeof(header);
+    pmsg_header.uid = last_uid;
+    pmsg_header.pid = last_pid;
 
-    newVec[0].iov_base   = (unsigned char *) &log_id_buf;
-    newVec[0].iov_len    = sizeof_log_id_t;
-    newVec[1].iov_base   = (unsigned char *) &tid;
-    newVec[1].iov_len    = sizeof(tid);
-    newVec[2].iov_base   = (unsigned char *) &realtime_ts;
-    newVec[2].iov_len    = sizeof(log_time);
+    header.tid = gettid();
+    header.realtime.tv_sec = ts.tv_sec;
+    header.realtime.tv_nsec = ts.tv_nsec;
+
+    newVec[0].iov_base   = (unsigned char *) &pmsg_header;
+    newVec[0].iov_len    = sizeof(pmsg_header);
+    newVec[1].iov_base   = (unsigned char *) &header;
+    newVec[1].iov_len    = sizeof(header);
+
+    if (logd_fd > 0) {
+        int32_t snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
+        if (snapshot) {
+            android_log_event_int_t buffer;
+
+            header.id = LOG_ID_EVENTS;
+            buffer.header.tag = htole32(LIBLOG_LOG_TAG);
+            buffer.payload.type = EVENT_TYPE_INT;
+            buffer.payload.data = htole32(snapshot);
+
+            newVec[2].iov_base = &buffer;
+            newVec[2].iov_len  = sizeof(buffer);
+
+            ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, 2));
+            if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
+                atomic_fetch_add_explicit(&dropped, snapshot, memory_order_relaxed);
+            }
+        }
+    }
+
+    header.id = log_id;
 
     for (payload_size = 0, i = header_length; i < nr + header_length; i++) {
         newVec[i].iov_base = vec[i - header_length].iov_base;
@@ -223,25 +238,48 @@
             if (newVec[i].iov_len) {
                 ++i;
             }
+            payload_size = LOGGER_ENTRY_MAX_PAYLOAD;
             break;
         }
     }
+    pmsg_header.len += payload_size;
+
+    if (pstore_fd >= 0) {
+        TEMP_FAILURE_RETRY(writev(pstore_fd, newVec, i));
+    }
+
+    if (last_uid == AID_LOGD) { /* logd, after initialization and priv drop */
+        /*
+         * ignore log messages we send to ourself (logd).
+         * Such log messages are often generated by libraries we depend on
+         * which use standard Android logging.
+         */
+        return 0;
+    }
+
+    if (logd_fd < 0) {
+        return -EBADF;
+    }
 
     /*
      * The write below could be lost, but will never block.
      *
+     * To logd, we drop the pmsg_header
+     *
      * ENOTCONN occurs if logd dies.
      * EAGAIN occurs if logd is overloaded.
      */
-    ret = writev(logd_fd, newVec, i);
+    ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, i - 1));
     if (ret < 0) {
         ret = -errno;
         if (ret == -ENOTCONN) {
-#ifdef HAVE_PTHREADS
+#if !defined(_WIN32)
             pthread_mutex_lock(&log_init_lock);
 #endif
+            close(logd_fd);
+            logd_fd = -1;
             ret = __write_to_log_initialize();
-#ifdef HAVE_PTHREADS
+#if !defined(_WIN32)
             pthread_mutex_unlock(&log_init_lock);
 #endif
 
@@ -249,15 +287,17 @@
                 return ret;
             }
 
-            ret = writev(logd_fd, newVec, nr + header_length);
+            ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, i - 1));
             if (ret < 0) {
                 ret = -errno;
             }
         }
     }
 
-    if (ret > (ssize_t)(sizeof_log_id_t + sizeof(tid) + sizeof(log_time))) {
-        ret -= sizeof_log_id_t + sizeof(tid) + sizeof(log_time);
+    if (ret > (ssize_t)sizeof(header)) {
+        ret -= sizeof(header);
+    } else if (ret == -EAGAIN) {
+        atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
     }
 #endif
 
@@ -270,7 +310,8 @@
     [LOG_ID_RADIO] = "radio",
     [LOG_ID_EVENTS] = "events",
     [LOG_ID_SYSTEM] = "system",
-    [LOG_ID_CRASH] = "crash"
+    [LOG_ID_CRASH] = "crash",
+    [LOG_ID_KERNEL] = "kernel",
 };
 
 const char *android_log_id_to_name(log_id_t log_id)
@@ -314,6 +355,9 @@
 #else
     close(logd_fd);
     logd_fd = -1;
+
+    close(pstore_fd);
+    pstore_fd = -1;
 #endif
 
 #ifdef HAVE_PTHREADS
@@ -323,7 +367,7 @@
 
 static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
 {
-#ifdef HAVE_PTHREADS
+#if !defined(_WIN32)
     pthread_mutex_lock(&log_init_lock);
 #endif
 
@@ -332,16 +376,21 @@
 
         ret = __write_to_log_initialize();
         if (ret < 0) {
-#ifdef HAVE_PTHREADS
+#if !defined(_WIN32)
             pthread_mutex_unlock(&log_init_lock);
 #endif
+#if (FAKE_LOG_DEVICE == 0)
+            if (pstore_fd >= 0) {
+                __write_to_log_daemon(log_id, vec, nr);
+            }
+#endif
             return ret;
         }
 
-        write_to_log = __write_to_log_kernel;
+        write_to_log = __write_to_log_daemon;
     }
 
-#ifdef HAVE_PTHREADS
+#if !defined(_WIN32)
     pthread_mutex_unlock(&log_init_lock);
 #endif
 
@@ -350,43 +399,7 @@
 
 int __android_log_write(int prio, const char *tag, const char *msg)
 {
-    struct iovec vec[3];
-    log_id_t log_id = LOG_ID_MAIN;
-    char tmp_tag[32];
-
-    if (!tag)
-        tag = "";
-
-    /* XXX: This needs to go! */
-    if (!strcmp(tag, "HTC_RIL") ||
-        !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
-        !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
-        !strcmp(tag, "AT") ||
-        !strcmp(tag, "GSM") ||
-        !strcmp(tag, "STK") ||
-        !strcmp(tag, "CDMA") ||
-        !strcmp(tag, "PHONE") ||
-        !strcmp(tag, "SMS")) {
-            log_id = LOG_ID_RADIO;
-            /* Inform third party apps/ril/radio.. to use Rlog or RLOG */
-            snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
-            tag = tmp_tag;
-    }
-
-#if __BIONIC__
-    if (prio == ANDROID_LOG_FATAL) {
-        android_set_abort_message(msg);
-    }
-#endif
-
-    vec[0].iov_base   = (unsigned char *) &prio;
-    vec[0].iov_len    = 1;
-    vec[1].iov_base   = (void *) tag;
-    vec[1].iov_len    = strlen(tag) + 1;
-    vec[2].iov_base   = (void *) msg;
-    vec[2].iov_len    = strlen(msg) + 1;
-
-    return write_to_log(log_id, vec, 3);
+    return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
 }
 
 int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)
@@ -414,6 +427,12 @@
             tag = tmp_tag;
     }
 
+#if __BIONIC__
+    if (prio == ANDROID_LOG_FATAL) {
+        android_set_abort_message(msg);
+    }
+#endif
+
     vec[0].iov_base   = (unsigned char *) &prio;
     vec[0].iov_len    = 1;
     vec[1].iov_base   = (void *) tag;
@@ -479,7 +498,7 @@
     }
 
     __android_log_write(ANDROID_LOG_FATAL, tag, buf);
-    __builtin_trap(); /* trap so we have a chance to debug the situation */
+    abort(); /* abort so we have a chance to debug the situation */
     /* NOTREACHED */
 }
 
diff --git a/liblog/logd_write_kern.c b/liblog/logd_write_kern.c
index 0b97d85..abdbd03 100644
--- a/liblog/logd_write_kern.c
+++ b/liblog/logd_write_kern.c
@@ -16,9 +16,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
-#ifdef HAVE_PTHREADS
 #include <pthread.h>
-#endif
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -28,9 +26,7 @@
 #include <time.h>
 #include <unistd.h>
 
-#ifdef __BIONIC__
 #include <android/set_abort_message.h>
-#endif
 
 #include <log/log.h>
 #include <log/logd.h>
@@ -43,23 +39,14 @@
 
 #define LOG_BUF_SIZE 1024
 
-#if FAKE_LOG_DEVICE
-/* This will be defined when building for the host. */
-#include "fake_log_device.h"
-#define log_open(pathname, flags) fakeLogOpen(pathname, flags)
-#define log_writev(filedes, vector, count) fakeLogWritev(filedes, vector, count)
-#define log_close(filedes) fakeLogClose(filedes)
-#else
 #define log_open(pathname, flags) open(pathname, (flags) | O_CLOEXEC)
 #define log_writev(filedes, vector, count) writev(filedes, vector, count)
 #define log_close(filedes) close(filedes)
-#endif
 
 static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);
 static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;
-#ifdef HAVE_PTHREADS
+
 static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
-#endif
 
 #ifndef __unused
 #define __unused  __attribute__((__unused__))
@@ -154,9 +141,7 @@
 
 static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
 {
-#ifdef HAVE_PTHREADS
     pthread_mutex_lock(&log_init_lock);
-#endif
 
     if (write_to_log == __write_to_log_init) {
         log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY);
@@ -182,52 +167,14 @@
         }
     }
 
-#ifdef HAVE_PTHREADS
     pthread_mutex_unlock(&log_init_lock);
-#endif
 
     return write_to_log(log_id, vec, nr);
 }
 
 int __android_log_write(int prio, const char *tag, const char *msg)
 {
-    struct iovec vec[3];
-    log_id_t log_id = LOG_ID_MAIN;
-    char tmp_tag[32];
-
-    if (!tag)
-        tag = "";
-
-    /* XXX: This needs to go! */
-    if (!strcmp(tag, "HTC_RIL") ||
-        !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
-        !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
-        !strcmp(tag, "AT") ||
-        !strcmp(tag, "GSM") ||
-        !strcmp(tag, "STK") ||
-        !strcmp(tag, "CDMA") ||
-        !strcmp(tag, "PHONE") ||
-        !strcmp(tag, "SMS")) {
-            log_id = LOG_ID_RADIO;
-            /* Inform third party apps/ril/radio.. to use Rlog or RLOG */
-            snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
-            tag = tmp_tag;
-    }
-
-#if __BIONIC__
-    if (prio == ANDROID_LOG_FATAL) {
-        android_set_abort_message(msg);
-    }
-#endif
-
-    vec[0].iov_base   = (unsigned char *) &prio;
-    vec[0].iov_len    = 1;
-    vec[1].iov_base   = (void *) tag;
-    vec[1].iov_len    = strlen(tag) + 1;
-    vec[2].iov_base   = (void *) msg;
-    vec[2].iov_len    = strlen(msg) + 1;
-
-    return write_to_log(log_id, vec, 3);
+    return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
 }
 
 int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)
@@ -255,6 +202,10 @@
             tag = tmp_tag;
     }
 
+    if (prio == ANDROID_LOG_FATAL) {
+        android_set_abort_message(msg);
+    }
+
     vec[0].iov_base   = (unsigned char *) &prio;
     vec[0].iov_len    = 1;
     vec[1].iov_base   = (void *) tag;
@@ -320,7 +271,7 @@
     }
 
     __android_log_write(ANDROID_LOG_FATAL, tag, buf);
-    __builtin_trap(); /* trap so we have a chance to debug the situation */
+    abort(); /* abort so we have a chance to debug the situation */
     /* NOTREACHED */
 }
 
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 08e830a..c2f1545 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -21,14 +21,20 @@
 #include <assert.h>
 #include <ctype.h>
 #include <errno.h>
+#include <stdbool.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <inttypes.h>
+#include <sys/param.h>
 
 #include <log/logd.h>
 #include <log/logprint.h>
 
+/* open coded fragment, prevent circular dependencies */
+#define WEAK static
+
 typedef struct FilterInfo_t {
     char *mTag;
     android_LogPriority mPri;
@@ -39,8 +45,25 @@
     android_LogPriority global_pri;
     FilterInfo *filters;
     AndroidLogPrintFormat format;
+    bool colored_output;
+    bool usec_time_output;
+    bool printable_output;
 };
 
+/*
+ *  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.
+ *    The color manipulation character stream is defined as:
+ *      ESC [ 3 8 ; 5 ; <color#> m
+ */
+#define ANDROID_COLOR_BLUE     75
+#define ANDROID_COLOR_DEFAULT 231
+#define ANDROID_COLOR_GREEN    40
+#define ANDROID_COLOR_ORANGE  166
+#define ANDROID_COLOR_RED     196
+#define ANDROID_COLOR_YELLOW  226
+
 static FilterInfo * filterinfo_new(const char * tag, android_LogPriority pri)
 {
     FilterInfo *p_ret;
@@ -110,6 +133,23 @@
     }
 }
 
+static int colorFromPri (android_LogPriority pri)
+{
+    switch (pri) {
+        case ANDROID_LOG_VERBOSE:       return ANDROID_COLOR_DEFAULT;
+        case ANDROID_LOG_DEBUG:         return ANDROID_COLOR_BLUE;
+        case ANDROID_LOG_INFO:          return ANDROID_COLOR_GREEN;
+        case ANDROID_LOG_WARN:          return ANDROID_COLOR_ORANGE;
+        case ANDROID_LOG_ERROR:         return ANDROID_COLOR_RED;
+        case ANDROID_LOG_FATAL:         return ANDROID_COLOR_RED;
+        case ANDROID_LOG_SILENT:        return ANDROID_COLOR_DEFAULT;
+
+        case ANDROID_LOG_DEFAULT:
+        case ANDROID_LOG_UNKNOWN:
+        default:                        return ANDROID_COLOR_DEFAULT;
+    }
+}
+
 static android_LogPriority filterPriForTag(
         AndroidLogFormat *p_format, const char *tag)
 {
@@ -149,6 +189,9 @@
 
     p_ret->global_pri = ANDROID_LOG_VERBOSE;
     p_ret->format = FORMAT_BRIEF;
+    p_ret->colored_output = false;
+    p_ret->usec_time_output = false;
+    p_ret->printable_output = false;
 
     return p_ret;
 }
@@ -171,10 +214,24 @@
 
 
 
-void android_log_setPrintFormat(AndroidLogFormat *p_format,
+int android_log_setPrintFormat(AndroidLogFormat *p_format,
         AndroidLogPrintFormat format)
 {
-    p_format->format=format;
+    switch (format) {
+    case FORMAT_MODIFIER_COLOR:
+        p_format->colored_output = true;
+        return 0;
+    case FORMAT_MODIFIER_TIME_USEC:
+        p_format->usec_time_output = true;
+        return 0;
+    case FORMAT_MODIFIER_PRINTABLE:
+        p_format->printable_output = true;
+        return 0;
+    default:
+        break;
+    }
+    p_format->format = format;
+    return 1;
 }
 
 /**
@@ -192,6 +249,9 @@
     else if (strcmp(formatString, "time") == 0) format = FORMAT_TIME;
     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, "usec") == 0) format = FORMAT_MODIFIER_TIME_USEC;
+    else if (strcmp(formatString, "printable") == 0) format = FORMAT_MODIFIER_PRINTABLE;
     else format = FORMAT_OFF;
 
     return format;
@@ -227,29 +287,35 @@
     }
 
     if(0 == strncmp("*", filterExpression, tagNameLength)) {
-        // This filter expression refers to the global filter
-        // The default level for this is DEBUG if the priority
-        // is unspecified
+        /*
+         * This filter expression refers to the global filter
+         * The default level for this is DEBUG if the priority
+         * is unspecified
+         */
         if (pri == ANDROID_LOG_DEFAULT) {
             pri = ANDROID_LOG_DEBUG;
         }
 
         p_format->global_pri = pri;
     } else {
-        // for filter expressions that don't refer to the global
-        // filter, the default is verbose if the priority is unspecified
+        /*
+         * for filter expressions that don't refer to the global
+         * filter, the default is verbose if the priority is unspecified
+         */
         if (pri == ANDROID_LOG_DEFAULT) {
             pri = ANDROID_LOG_VERBOSE;
         }
 
         char *tagName;
 
-// Presently HAVE_STRNDUP is never defined, so the second case is always taken
-// Darwin doesn't have strnup, everything else does
+/*
+ * Presently HAVE_STRNDUP is never defined, so the second case is always taken
+ * Darwin doesn't have strnup, everything else does
+ */
 #ifdef HAVE_STRNDUP
         tagName = strndup(filterExpression, tagNameLength);
 #else
-        //a few extra bytes copied...
+        /* a few extra bytes copied... */
         tagName = strdup(filterExpression);
         tagName[tagNameLength] = '\0';
 #endif /*HAVE_STRNDUP*/
@@ -286,9 +352,9 @@
     char *p_ret;
     int err;
 
-    // Yes, I'm using strsep
+    /* Yes, I'm using strsep */
     while (NULL != (p_ret = strsep(&p_cur, " \t,"))) {
-        // ignore whitespace-only entries
+        /* ignore whitespace-only entries */
         if(p_ret[0] != '\0') {
             err = android_log_addFilterRule(p_format, p_ret);
 
@@ -305,15 +371,6 @@
     return -1;
 }
 
-static inline char * strip_end(char *str)
-{
-    char *end = str + strlen(str) - 1;
-
-    while (end >= str && isspace(*end))
-        *end-- = '\0';
-    return str;
-}
-
 /**
  * Splits a wire-format buffer into an AndroidLogEntry
  * entry allocated by caller. Pointers will point directly into buf
@@ -341,8 +398,10 @@
      * When that happens, we must null-terminate the message ourselves.
      */
     if (buf->len < 3) {
-        // An well-formed entry must consist of at least a priority
-        // and two null characters
+        /*
+         * An well-formed entry must consist of at least a priority
+         * and two null characters
+         */
         fprintf(stderr, "+++ LOG: entry too small\n");
         return -1;
     }
@@ -372,7 +431,7 @@
         return -1;
     }
     if (msgEnd == -1) {
-        // incoming message not null-terminated; force it
+        /* incoming message not null-terminated; force it */
         msgEnd = buf->len - 1;
         msg[msgEnd] = '\0';
     }
@@ -402,7 +461,7 @@
 
     low = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
     high = src[4] | (src[5] << 8) | (src[6] << 16) | (src[7] << 24);
-    return ((long long) high << 32) | (long long) low;
+    return ((uint64_t) high << 32) | (uint64_t) low;
 }
 
 
@@ -433,8 +492,6 @@
     type = *eventData++;
     eventDataLen--;
 
-    //fprintf(stderr, "--- type=%d (rem len=%d)\n", type, eventDataLen);
-
     switch (type) {
     case EVENT_TYPE_INT:
         /* 32-bit signed int */
@@ -460,7 +517,7 @@
     case EVENT_TYPE_LONG:
         /* 64-bit signed long */
         {
-            long long lval;
+            uint64_t lval;
 
             if (eventDataLen < 8)
                 return -1;
@@ -468,7 +525,30 @@
             eventData += 8;
             eventDataLen -= 8;
 
-            outCount = snprintf(outBuf, outBufLen, "%lld", 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:
+        /* float */
+        {
+            uint32_t ival;
+            float fval;
+
+            if (eventDataLen < 4)
+                return -1;
+            ival = get4LE(eventData);
+            fval = *(float*)&ival;
+            eventData += 4;
+            eventDataLen -= 4;
+
+            outCount = snprintf(outBuf, outBufLen, "%f", fval);
             if (outCount < outBufLen) {
                 outBuf += outCount;
                 outBufLen -= outCount;
@@ -672,6 +752,122 @@
     return 0;
 }
 
+/*
+ * One utf8 character at a time
+ *
+ * Returns the length of the utf8 character in the buffer,
+ * or -1 if illegal or truncated
+ *
+ * Open coded from libutils/Unicode.cpp, borrowed from utf8_length(),
+ * can not remove from here because of library circular dependencies.
+ * Expect one-day utf8_character_length with the same signature could
+ * _also_ be part of libutils/Unicode.cpp if its usefullness needs to
+ * propagate globally.
+ */
+WEAK ssize_t utf8_character_length(const char *src, size_t len)
+{
+    const char *cur = src;
+    const char first_char = *cur++;
+    static const uint32_t kUnicodeMaxCodepoint = 0x0010FFFF;
+    int32_t mask, to_ignore_mask;
+    size_t num_to_read;
+    uint32_t utf32;
+
+    if ((first_char & 0x80) == 0) { /* ASCII */
+        return 1;
+    }
+
+    /*
+     * (UTF-8's character must not be like 10xxxxxx,
+     *  but 110xxxxx, 1110xxxx, ... or 1111110x)
+     */
+    if ((first_char & 0x40) == 0) {
+        return -1;
+    }
+
+    for (utf32 = 1, num_to_read = 1, mask = 0x40, to_ignore_mask = 0x80;
+         num_to_read < 5 && (first_char & mask);
+         num_to_read++, to_ignore_mask |= mask, mask >>= 1) {
+        if (num_to_read > len) {
+            return -1;
+        }
+        if ((*cur & 0xC0) != 0x80) { /* can not be 10xxxxxx? */
+            return -1;
+        }
+        utf32 = (utf32 << 6) + (*cur++ & 0b00111111);
+    }
+    /* "first_char" must be (110xxxxx - 11110xxx) */
+    if (num_to_read >= 5) {
+        return -1;
+    }
+    to_ignore_mask |= mask;
+    utf32 |= ((~to_ignore_mask) & first_char) << (6 * (num_to_read - 1));
+    if (utf32 > kUnicodeMaxCodepoint) {
+        return -1;
+    }
+    return num_to_read;
+}
+
+/*
+ * Convert to printable from message to p buffer, return string length. If p is
+ * NULL, do not copy, but still return the expected string length.
+ */
+static size_t convertPrintable(char *p, const char *message, size_t messageLen)
+{
+    char *begin = p;
+    bool print = p != NULL;
+
+    while (messageLen) {
+        char buf[6];
+        ssize_t len = sizeof(buf) - 1;
+        if ((size_t)len > messageLen) {
+            len = messageLen;
+        }
+        len = utf8_character_length(message, len);
+
+        if (len < 0) {
+            snprintf(buf, sizeof(buf),
+                     ((messageLen > 1) && isdigit(message[1]))
+                         ? "\\%03o"
+                         : "\\%o",
+                     *message & 0377);
+            len = 1;
+        } else {
+            buf[0] = '\0';
+            if (len == 1) {
+                if (*message == '\a') {
+                    strcpy(buf, "\\a");
+                } else if (*message == '\b') {
+                    strcpy(buf, "\\b");
+                } else if (*message == '\t') {
+                    strcpy(buf, "\\t");
+                } else if (*message == '\v') {
+                    strcpy(buf, "\\v");
+                } else if (*message == '\f') {
+                    strcpy(buf, "\\f");
+                } else if (*message == '\r') {
+                    strcpy(buf, "\\r");
+                } else if (*message == '\\') {
+                    strcpy(buf, "\\\\");
+                } else if ((*message < ' ') || (*message & 0x80)) {
+                    snprintf(buf, sizeof(buf), "\\%o", *message & 0377);
+                }
+            }
+            if (!buf[0]) {
+                strncpy(buf, message, len);
+                buf[len] = '\0';
+            }
+        }
+        if (print) {
+            strcpy(p, buf);
+        }
+        p += strlen(buf);
+        message += len;
+        messageLen -= len;
+    }
+    return p - begin;
+}
+
 /**
  * Formats a log message into a buffer
  *
@@ -687,17 +883,19 @@
     const AndroidLogEntry *entry,
     size_t *p_outLength)
 {
-#if defined(HAVE_LOCALTIME_R)
+#if !defined(_WIN32)
     struct tm tmBuf;
 #endif
     struct tm* ptm;
-    char timeBuf[32];
+    char timeBuf[32]; /* good margin, 23+nul for msec, 26+nul for usec */
     char prefixBuf[128], suffixBuf[128];
     char priChar;
     int prefixSuffixIsHeaderFooter = 0;
     char * ret = NULL;
 
     priChar = filterPriToChar(entry->priority);
+    size_t prefixLen = 0, suffixLen = 0;
+    size_t len;
 
     /*
      * Get the current date/time in pretty form
@@ -708,84 +906,97 @@
      * in the time stamp.  Don't use forward slashes, parenthesis,
      * brackets, asterisks, or other special chars here.
      */
-#if defined(HAVE_LOCALTIME_R)
+#if !defined(_WIN32)
     ptm = localtime_r(&(entry->tv_sec), &tmBuf);
 #else
     ptm = localtime(&(entry->tv_sec));
 #endif
-    //strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
+    /* strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm); */
     strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
+    len = strlen(timeBuf);
+    if (p_format->usec_time_output) {
+        snprintf(timeBuf + len, sizeof(timeBuf) - len,
+                 ".%06ld", entry->tv_nsec / 1000);
+    } else {
+        snprintf(timeBuf + len, sizeof(timeBuf) - len,
+                 ".%03ld", entry->tv_nsec / 1000000);
+    }
 
     /*
      * Construct a buffer containing the log header and log message.
      */
-    size_t prefixLen, suffixLen;
+    if (p_format->colored_output) {
+        prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "\x1B[38;5;%dm",
+                             colorFromPri(entry->priority));
+        prefixLen = MIN(prefixLen, sizeof(prefixBuf));
+        suffixLen = snprintf(suffixBuf, sizeof(suffixBuf), "\x1B[0m");
+        suffixLen = MIN(suffixLen, sizeof(suffixBuf));
+    }
 
     switch (p_format->format) {
         case FORMAT_TAG:
-            prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
+            len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
                 "%c/%-8s: ", priChar, entry->tag);
-            strcpy(suffixBuf, "\n"); suffixLen = 1;
+            strcpy(suffixBuf + suffixLen, "\n");
+            ++suffixLen;
             break;
         case FORMAT_PROCESS:
-            prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
-                "%c(%5d) ", priChar, entry->pid);
-            suffixLen = snprintf(suffixBuf, sizeof(suffixBuf),
+            len = snprintf(suffixBuf + suffixLen, sizeof(suffixBuf) - suffixLen,
                 "  (%s)\n", entry->tag);
+            suffixLen += MIN(len, sizeof(suffixBuf) - suffixLen);
+            len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
+                "%c(%5d) ", priChar, entry->pid);
             break;
         case FORMAT_THREAD:
-            prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
+            len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
                 "%c(%5d:%5d) ", priChar, entry->pid, entry->tid);
-            strcpy(suffixBuf, "\n");
-            suffixLen = 1;
+            strcpy(suffixBuf + suffixLen, "\n");
+            ++suffixLen;
             break;
         case FORMAT_RAW:
-            prefixBuf[0] = 0;
-            prefixLen = 0;
-            strcpy(suffixBuf, "\n");
-            suffixLen = 1;
+            prefixBuf[prefixLen] = 0;
+            len = 0;
+            strcpy(suffixBuf + suffixLen, "\n");
+            ++suffixLen;
             break;
         case FORMAT_TIME:
-            prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
-                "%s.%03ld %c/%-8s(%5d): ", timeBuf, entry->tv_nsec / 1000000,
-                priChar, entry->tag, entry->pid);
-            strcpy(suffixBuf, "\n");
-            suffixLen = 1;
+            len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
+                "%s %c/%-8s(%5d): ", timeBuf, priChar, entry->tag, entry->pid);
+            strcpy(suffixBuf + suffixLen, "\n");
+            ++suffixLen;
             break;
         case FORMAT_THREADTIME:
-            prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
-                "%s.%03ld %5d %5d %c %-8s: ", timeBuf, entry->tv_nsec / 1000000,
+            len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
+                "%s %5d %5d %c %-8s: ", timeBuf,
                 entry->pid, entry->tid, priChar, entry->tag);
-            strcpy(suffixBuf, "\n");
-            suffixLen = 1;
+            strcpy(suffixBuf + suffixLen, "\n");
+            ++suffixLen;
             break;
         case FORMAT_LONG:
-            prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
-                "[ %s.%03ld %5d:%5d %c/%-8s ]\n",
-                timeBuf, entry->tv_nsec / 1000000, entry->pid,
-                entry->tid, priChar, entry->tag);
-            strcpy(suffixBuf, "\n\n");
-            suffixLen = 2;
+            len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
+                "[ %s %5d:%5d %c/%-8s ]\n",
+                timeBuf, entry->pid, entry->tid, priChar, entry->tag);
+            strcpy(suffixBuf + suffixLen, "\n\n");
+            suffixLen += 2;
             prefixSuffixIsHeaderFooter = 1;
             break;
         case FORMAT_BRIEF:
         default:
-            prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
+            len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
                 "%c/%-8s(%5d): ", priChar, entry->tag, entry->pid);
-            strcpy(suffixBuf, "\n");
-            suffixLen = 1;
+            strcpy(suffixBuf + suffixLen, "\n");
+            ++suffixLen;
             break;
     }
+
     /* snprintf has a weird return value.   It returns what would have been
      * written given a large enough buffer.  In the case that the prefix is
      * longer then our buffer(128), it messes up the calculations below
      * possibly causing heap corruption.  To avoid this we double check and
      * set the length at the maximum (size minus null byte)
      */
-    if(prefixLen >= sizeof(prefixBuf))
-        prefixLen = sizeof(prefixBuf) - 1;
-    if(suffixLen >= sizeof(suffixBuf))
-        suffixLen = sizeof(suffixBuf) - 1;
+    prefixLen += MIN(len, sizeof(prefixBuf) - prefixLen);
+    suffixLen = MIN(suffixLen, sizeof(suffixBuf));
 
     /* the following code is tragically unreadable */
 
@@ -795,24 +1006,34 @@
     const char *pm;
 
     if (prefixSuffixIsHeaderFooter) {
-        // we're just wrapping message with a header/footer
+        /* we're just wrapping message with a header/footer */
         numLines = 1;
     } else {
         pm = entry->message;
         numLines = 0;
 
-        // The line-end finding here must match the line-end finding
-        // in for ( ... numLines...) loop below
+        /*
+         * The line-end finding here must match the line-end finding
+         * in for ( ... numLines...) loop below
+         */
         while (pm < (entry->message + entry->messageLen)) {
             if (*pm++ == '\n') numLines++;
         }
-        // plus one line for anything not newline-terminated at the end
+        /* plus one line for anything not newline-terminated at the end */
         if (pm > entry->message && *(pm-1) != '\n') numLines++;
     }
 
-    // this is an upper bound--newlines in message may be counted
-    // extraneously
-    bufferSize = (numLines * (prefixLen + suffixLen)) + entry->messageLen + 1;
+    /*
+     * this is an upper bound--newlines in message may be counted
+     * extraneously
+     */
+    bufferSize = (numLines * (prefixLen + suffixLen)) + 1;
+    if (p_format->printable_output) {
+        /* Calculate extra length to convert non-printable to printable */
+        bufferSize += convertPrintable(NULL, entry->message, entry->messageLen);
+    } else {
+        bufferSize += entry->messageLen;
+    }
 
     if (defaultBufferSize >= bufferSize) {
         ret = defaultBuffer;
@@ -832,8 +1053,12 @@
     if (prefixSuffixIsHeaderFooter) {
         strcat(p, prefixBuf);
         p += prefixLen;
-        strncat(p, entry->message, entry->messageLen);
-        p += entry->messageLen;
+        if (p_format->printable_output) {
+            p += convertPrintable(p, entry->message, entry->messageLen);
+        } else {
+            strncat(p, entry->message, entry->messageLen);
+            p += entry->messageLen;
+        }
         strcat(p, suffixBuf);
         p += suffixLen;
     } else {
@@ -842,15 +1067,19 @@
             size_t lineLen;
             lineStart = pm;
 
-            // Find the next end-of-line in message
+            /* Find the next end-of-line in message */
             while (pm < (entry->message + entry->messageLen)
                     && *pm != '\n') pm++;
             lineLen = pm - lineStart;
 
             strcat(p, prefixBuf);
             p += prefixLen;
-            strncat(p, lineStart, lineLen);
-            p += lineLen;
+            if (p_format->printable_output) {
+                p += convertPrintable(p, lineStart, lineLen);
+            } else {
+                strncat(p, lineStart, lineLen);
+                p += lineLen;
+            }
             strcat(p, suffixBuf);
             p += suffixLen;
 
diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk
index cd1bf33..a407c50 100644
--- a/liblog/tests/Android.mk
+++ b/liblog/tests/Android.mk
@@ -39,16 +39,10 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := $(test_module_prefix)benchmarks
 LOCAL_MODULE_TAGS := $(test_tags)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += $(benchmark_c_flags)
 LOCAL_SHARED_LIBRARIES += liblog libm
 LOCAL_SRC_FILES := $(benchmark_src_files)
-ifndef LOCAL_SDK_VERSION
-LOCAL_C_INCLUDES += bionic bionic/libstdc++/include external/stlport/stlport
-LOCAL_SHARED_LIBRARIES += libstlport
-endif
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
-include $(BUILD_EXECUTABLE)
+include $(BUILD_NATIVE_TEST)
 
 # -----------------------------------------------------------------------------
 # Unit tests.
@@ -71,7 +65,7 @@
 test_src_files += \
     libc_test.cpp
 
-ifndef ($(TARGET_USES_LOGD),false)
+ifneq ($(TARGET_USES_LOGD),false)
 test_c_flags += -DTARGET_USES_LOGD
 endif
 
@@ -82,8 +76,7 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := $(test_module_prefix)unit-tests
 LOCAL_MODULE_TAGS := $(test_tags)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += $(test_c_flags)
-LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SHARED_LIBRARIES := liblog libcutils
 LOCAL_SRC_FILES := $(test_src_files)
 include $(BUILD_NATIVE_TEST)
diff --git a/liblog/tests/benchmark_main.cpp b/liblog/tests/benchmark_main.cpp
index 090394c..e5ef970 100644
--- a/liblog/tests/benchmark_main.cpp
+++ b/liblog/tests/benchmark_main.cpp
@@ -17,6 +17,7 @@
 #include <benchmark.h>
 
 #include <inttypes.h>
+#include <math.h>
 #include <regex.h>
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp
index 9839729..0e84f4e 100644
--- a/liblog/tests/libc_test.cpp
+++ b/liblog/tests/libc_test.cpp
@@ -39,7 +39,7 @@
     pid_t pid = getpid();
 
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_EVENTS, O_RDONLY | O_NDELAY, 1000, pid)));
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
     struct timespec ts;
     clock_gettime(CLOCK_MONOTONIC, &ts);
@@ -99,7 +99,7 @@
     pid_t pid = getpid();
 
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        (log_id_t)LOG_ID_CRASH, O_RDONLY | O_NDELAY, 1000, pid)));
+        (log_id_t)LOG_ID_CRASH, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
     char b[80];
     struct timespec ts;
@@ -136,3 +136,12 @@
 
     android_logger_list_close(logger_list);
 }
+
+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");
+}
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index 549d79e..b594634 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -130,7 +130,7 @@
     pid_t pid = getpid();
 
     struct logger_list * logger_list = android_logger_list_open(LOG_ID_EVENTS,
-        O_RDONLY, 0, pid);
+        ANDROID_LOG_RDONLY, 0, pid);
 
     if (!logger_list) {
         fprintf(stderr, "Unable to open events log: %s\n", strerror(errno));
@@ -208,7 +208,7 @@
     pid_t pid = getpid();
 
     struct logger_list * logger_list = android_logger_list_open(LOG_ID_EVENTS,
-        O_RDONLY, 0, pid);
+        ANDROID_LOG_RDONLY, 0, pid);
 
     if (!logger_list) {
         fprintf(stderr, "Unable to open events log: %s\n", strerror(errno));
@@ -266,3 +266,17 @@
     android_logger_list_free(logger_list);
 }
 BENCHMARK(BM_log_delay);
+
+/*
+ *	Measure the time it takes for __android_log_is_loggable.
+ */
+static void BM_is_loggable(int iters) {
+    StartBenchmarkTiming();
+
+    for (int i = 0; i < iters; ++i) {
+        __android_log_is_loggable(ANDROID_LOG_WARN, "logd", ANDROID_LOG_VERBOSE);
+    }
+
+    StopBenchmarkTiming();
+}
+BENCHMARK(BM_is_loggable);
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 61e226e..0e7fec4 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -17,6 +17,9 @@
 #include <fcntl.h>
 #include <inttypes.h>
 #include <signal.h>
+#include <string.h>
+
+#include <cutils/properties.h>
 #include <gtest/gtest.h>
 #include <log/log.h>
 #include <log/logger.h>
@@ -122,7 +125,7 @@
     pid_t pid = getpid();
 
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_EVENTS, O_RDONLY | O_NDELAY, 1000, pid)));
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
     // Check that we can close and reopen the logger
     log_time ts(CLOCK_MONOTONIC);
@@ -231,7 +234,7 @@
     v += pid & 0xFFFF;
 
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_EVENTS, O_RDONLY, 1000, pid)));
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY, 1000, pid)));
 
     int count = 0;
 
@@ -447,11 +450,12 @@
 
     LOG_FAILURE_RETRY(__android_log_buf_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
                                               tag, max_payload_buf));
+    sleep(2);
 
     struct logger_list *logger_list;
 
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_SYSTEM, O_RDONLY, 100, 0)));
+        LOG_ID_SYSTEM, ANDROID_LOG_RDONLY, 100, 0)));
 
     bool matches = false;
     ssize_t max_len = 0;
@@ -513,7 +517,7 @@
     struct logger_list *logger_list;
 
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_SYSTEM, O_RDONLY | O_NDELAY, 100, 0)));
+        LOG_ID_SYSTEM, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 100, 0)));
 
     ssize_t max_len = 0;
 
@@ -560,12 +564,12 @@
 
     // >25 messages due to liblog.__android_log_buf_print__concurrentXX above.
     ASSERT_TRUE(NULL != (logger_list1 = android_logger_list_open(
-        LOG_ID_MAIN, O_RDONLY | O_NDELAY, 25, 0)));
+        LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 25, 0)));
 
     struct logger_list *logger_list2;
 
     if (NULL == (logger_list2 = android_logger_list_open(
-            LOG_ID_MAIN, O_RDONLY | O_NDELAY, 15, 0))) {
+            LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 15, 0))) {
         android_logger_list_close(logger_list1);
         ASSERT_TRUE(NULL != logger_list2);
     }
@@ -603,7 +607,7 @@
 }
 
 TEST(liblog, android_logger_get_) {
-    struct logger_list * logger_list = android_logger_list_alloc(O_WRONLY, 0, 0);
+    struct logger_list * logger_list = android_logger_list_alloc(ANDROID_LOG_WRONLY, 0, 0);
 
     for(int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
         log_id_t id = static_cast<log_id_t>(i);
@@ -611,10 +615,14 @@
         if (id != android_name_to_log_id(name)) {
             continue;
         }
+        fprintf(stderr, "log buffer %s\r", name);
         struct logger * logger;
         EXPECT_TRUE(NULL != (logger = android_logger_open(logger_list, id)));
         EXPECT_EQ(id, android_logger_get_id(logger));
-        EXPECT_LT(0, android_logger_get_log_size(logger));
+        /* crash buffer is allowed to be empty, that is actually healthy! */
+        if (android_logger_get_log_size(logger) || strcmp("crash", name)) {
+            EXPECT_LT(0, android_logger_get_log_size(logger));
+        }
         EXPECT_LT(0, android_logger_get_log_readable_size(logger));
         EXPECT_LT(0, android_logger_get_log_version(logger));
     }
@@ -691,6 +699,193 @@
     android_log_format_free(p_format);
 }
 
+TEST(liblog, is_loggable) {
+    static const char tag[] = "is_loggable";
+    static const char log_namespace[] = "persist.log.tag.";
+    static const size_t base_offset = 8; /* skip "persist." */
+    // sizeof("string") = strlen("string") + 1
+    char key[sizeof(log_namespace) + sizeof(tag) - 1];
+    char hold[4][PROP_VALUE_MAX];
+    static const struct {
+        int level;
+        char type;
+    } levels[] = {
+        { ANDROID_LOG_VERBOSE, 'v' },
+        { ANDROID_LOG_DEBUG  , 'd' },
+        { ANDROID_LOG_INFO   , 'i' },
+        { ANDROID_LOG_WARN   , 'w' },
+        { ANDROID_LOG_ERROR  , 'e' },
+        { ANDROID_LOG_FATAL  , 'a' },
+        { -1                 , 's' },
+        { -2                 , 'g' }, // Illegal value, resort to default
+    };
+
+    // Set up initial test condition
+    memset(hold, 0, sizeof(hold));
+    snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
+    property_get(key, hold[0], "");
+    property_set(key, "");
+    property_get(key + base_offset, hold[1], "");
+    property_set(key + base_offset, "");
+    strcpy(key, log_namespace);
+    key[sizeof(log_namespace) - 2] = '\0';
+    property_get(key, hold[2], "");
+    property_set(key, "");
+    property_get(key, hold[3], "");
+    property_set(key + base_offset, "");
+
+    // All combinations of level and defaults
+    for(size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
+        if (levels[i].level == -2) {
+            continue;
+        }
+        for(size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
+            if (levels[j].level == -2) {
+                continue;
+            }
+            fprintf(stderr, "i=%zu j=%zu\r", i, j);
+            if ((levels[i].level < levels[j].level)
+                    || (levels[j].level == -1)) {
+                EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
+                                                       levels[j].level));
+            } else {
+                EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
+                                                      levels[j].level));
+            }
+        }
+    }
+
+    // All combinations of level and tag and global properties
+    for(size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
+        if (levels[i].level == -2) {
+            continue;
+        }
+        for(size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
+            char buf[2];
+            buf[0] = levels[j].type;
+            buf[1] = '\0';
+
+            snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
+            fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
+                    i, j, key, buf);
+            property_set(key, buf);
+            if ((levels[i].level < levels[j].level)
+                    || (levels[j].level == -1)
+                    || ((levels[i].level < ANDROID_LOG_DEBUG)
+                        && (levels[j].level == -2))) {
+                EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
+                                                       ANDROID_LOG_DEBUG));
+            } else {
+                EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
+                                                      ANDROID_LOG_DEBUG));
+            }
+            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);
+            if ((levels[i].level < levels[j].level)
+                    || (levels[j].level == -1)
+                    || ((levels[i].level < ANDROID_LOG_DEBUG)
+                        && (levels[j].level == -2))) {
+                EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
+                                                       ANDROID_LOG_DEBUG));
+            } else {
+                EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
+                                                      ANDROID_LOG_DEBUG));
+            }
+            property_set(key + base_offset, "");
+
+            strcpy(key, log_namespace);
+            key[sizeof(log_namespace) - 2] = '\0';
+            fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
+                    i, j, key, buf);
+            property_set(key, buf);
+            if ((levels[i].level < levels[j].level)
+                    || (levels[j].level == -1)
+                    || ((levels[i].level < ANDROID_LOG_DEBUG)
+                        && (levels[j].level == -2))) {
+                EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
+                                                       ANDROID_LOG_DEBUG));
+            } else {
+                EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
+                                                      ANDROID_LOG_DEBUG));
+            }
+            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);
+            if ((levels[i].level < levels[j].level)
+                    || (levels[j].level == -1)
+                    || ((levels[i].level < ANDROID_LOG_DEBUG)
+                        && (levels[j].level == -2))) {
+                EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
+                                                       ANDROID_LOG_DEBUG));
+            } else {
+                EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
+                                                      ANDROID_LOG_DEBUG));
+            }
+            property_set(key + base_offset, "");
+        }
+    }
+
+    // All combinations of level and tag properties, but with global set to INFO
+    strcpy(key, log_namespace);
+    key[sizeof(log_namespace) - 2] = '\0';
+    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) {
+        if (levels[i].level == -2) {
+            continue;
+        }
+        for(size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
+            char buf[2];
+            buf[0] = levels[j].type;
+            buf[1] = '\0';
+
+            fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
+                    i, j, key, buf);
+            property_set(key, buf);
+            if ((levels[i].level < levels[j].level)
+                    || (levels[j].level == -1)
+                    || ((levels[i].level < ANDROID_LOG_INFO) // Yes INFO
+                        && (levels[j].level == -2))) {
+                EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
+                                                       ANDROID_LOG_DEBUG));
+            } else {
+                EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
+                                                      ANDROID_LOG_DEBUG));
+            }
+            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);
+            if ((levels[i].level < levels[j].level)
+                    || (levels[j].level == -1)
+                    || ((levels[i].level < ANDROID_LOG_INFO) // Yes INFO
+                        && (levels[j].level == -2))) {
+                EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
+                                                       ANDROID_LOG_DEBUG));
+            } else {
+                EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
+                                                      ANDROID_LOG_DEBUG));
+            }
+            property_set(key + base_offset, "");
+        }
+    }
+
+    // reset parms
+    snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
+    property_set(key, hold[0]);
+    property_set(key + base_offset, hold[1]);
+    strcpy(key, log_namespace);
+    key[sizeof(log_namespace) - 2] = '\0';
+    property_set(key, hold[2]);
+    property_set(key + base_offset, hold[3]);
+}
+
 static inline int32_t get4LE(const char* src)
 {
     return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
@@ -706,7 +901,7 @@
     pid_t pid = getpid();
 
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_EVENTS,  O_RDONLY | O_NDELAY, 1000, pid)));
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
     ASSERT_LT(0, android_errorWriteWithInfoLog(
             TAG, SUBTAG, UID, max_payload_buf, DATA_LEN));
@@ -787,7 +982,7 @@
     pid_t pid = getpid();
 
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_EVENTS,  O_RDONLY | O_NDELAY, 1000, pid)));
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
     ASSERT_LT(0, android_errorWriteWithInfoLog(
             TAG, SUBTAG, UID, max_payload_buf, DATA_LEN));
@@ -874,7 +1069,7 @@
     pid_t pid = getpid();
 
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_EVENTS,  O_RDONLY | O_NDELAY, 1000, pid)));
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
     ASSERT_GT(0, android_errorWriteWithInfoLog(
             TAG, SUBTAG, UID, NULL, DATA_LEN));
@@ -917,7 +1112,7 @@
     pid_t pid = getpid();
 
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_EVENTS,  O_RDONLY | O_NDELAY, 1000, pid)));
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
     ASSERT_LT(0, android_errorWriteWithInfoLog(
             TAG, SUBTAG, UID, max_payload_buf, DATA_LEN));
@@ -997,7 +1192,7 @@
     pid_t pid = getpid();
 
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_EVENTS,  O_RDONLY | O_NDELAY, 1000, pid)));
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
     ASSERT_LT(0, android_errorWriteLog(TAG, SUBTAG));
 
@@ -1054,7 +1249,7 @@
     pid_t pid = getpid();
 
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_EVENTS,  O_RDONLY | O_NDELAY, 1000, pid)));
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
     ASSERT_GT(0, android_errorWriteLog(TAG, NULL));
 
diff --git a/liblog/uio.c b/liblog/uio.c
index 24a6507..f77cc49 100644
--- a/liblog/uio.c
+++ b/liblog/uio.c
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef HAVE_SYS_UIO_H
+#if defined(_WIN32)
 
 #include <log/uio.h>
 #include <unistd.h>
@@ -73,4 +73,4 @@
     return total;
 }
 
-#endif /* !HAVE_SYS_UIO_H */
+#endif
diff --git a/libmemtrack/memtrack.c b/libmemtrack/memtrack.c
index 9a656df..21d9ebd 100644
--- a/libmemtrack/memtrack.c
+++ b/libmemtrack/memtrack.c
@@ -20,6 +20,10 @@
 
 #include <log/log.h>
 
+#include <errno.h>
+#include <malloc.h>
+#include <string.h>
+
 #include <hardware/memtrack.h>
 
 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc
index eab2de0..f63497b 100644
--- a/libnativebridge/native_bridge.cc
+++ b/libnativebridge/native_bridge.cc
@@ -83,7 +83,7 @@
 static void* native_bridge_handle = nullptr;
 // Pointer to the callbacks. Available as soon as LoadNativeBridge succeeds, but only initialized
 // later.
-static NativeBridgeCallbacks* callbacks = nullptr;
+static const NativeBridgeCallbacks* callbacks = nullptr;
 // Callbacks provided by the environment to the bridge. Passed to LoadNativeBridge.
 static const NativeBridgeRuntimeCallbacks* runtime_callbacks = nullptr;
 
@@ -96,7 +96,7 @@
 // and hard code the directory name again here.
 static constexpr const char* kCodeCacheDir = "code_cache";
 
-static constexpr uint32_t kNativeBridgeCallbackVersion = 1;
+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._-].
@@ -121,7 +121,9 @@
     // First character must be [a-zA-Z].
     if (!CharacterAllowed(*ptr, true))  {
       // Found an invalid fist character, don't accept.
-      ALOGE("Native bridge library %s has been rejected for first character %c", nb_library_filename, *ptr);
+      ALOGE("Native bridge library %s has been rejected for first character %c",
+            nb_library_filename,
+            *ptr);
       return false;
     } else {
       // For the rest, be more liberal.
@@ -139,8 +141,22 @@
   }
 }
 
-static bool VersionCheck(NativeBridgeCallbacks* cb) {
-  return cb != nullptr && cb->version == kNativeBridgeCallbackVersion;
+static bool VersionCheck(const NativeBridgeCallbacks* cb) {
+  // Libnativebridge is now designed to be forward-compatible. So only "0" is an unsupported
+  // version.
+  if (cb == nullptr || cb->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;
+    }
+  }
+
+  return true;
 }
 
 static void CloseNativeBridge(bool with_error) {
@@ -321,7 +337,7 @@
 }
 
 // Set up the environment for the bridged app.
-static void SetupEnvironment(NativeBridgeCallbacks* callbacks, JNIEnv* env, const char* isa) {
+static void SetupEnvironment(const NativeBridgeCallbacks* callbacks, JNIEnv* env, const char* isa) {
   // Need a JNIEnv* to do anything.
   if (env == nullptr) {
     ALOGW("No JNIEnv* to set up app environment.");
@@ -360,7 +376,7 @@
   if (env_values->os_arch != nullptr) {
     jclass sclass_id = env->FindClass("java/lang/System");
     if (sclass_id != nullptr) {
-      jmethodID set_prop_id = env->GetStaticMethodID(sclass_id, "initUnchangeableSystemProperty",
+      jmethodID set_prop_id = env->GetStaticMethodID(sclass_id, "setUnchangeableSystemProperty",
           "(Ljava/lang/String;Ljava/lang/String;)V");
       if (set_prop_id != nullptr) {
         // Init os.arch to the value reqired by the apps running with native bridge.
@@ -368,7 +384,7 @@
             env->NewStringUTF(env_values->os_arch));
       } else {
         env->ExceptionClear();
-        ALOGW("Could not find initUnchangeableSystemProperty method.");
+        ALOGW("Could not find System#setUnchangeableSystemProperty.");
       }
     } else {
       env->ExceptionClear();
@@ -485,4 +501,18 @@
   return false;
 }
 
+uint32_t NativeBridgeGetVersion() {
+  if (NativeBridgeAvailable()) {
+    return callbacks->version;
+  }
+  return 0;
+}
+
+NativeBridgeSignalHandlerFn NativeBridgeGetSignalHandler(int signal) {
+  if (NativeBridgeInitialized() && callbacks->version >= 2) {
+    return callbacks->getSignalHandler(signal);
+  }
+  return nullptr;
+}
+
 };  // namespace android
diff --git a/libnativebridge/tests/Android.mk b/libnativebridge/tests/Android.mk
index f28c490..285e8c2 100644
--- a/libnativebridge/tests/Android.mk
+++ b/libnativebridge/tests/Android.mk
@@ -11,6 +11,8 @@
     CodeCacheExists_test.cpp \
     CompleteFlow_test.cpp \
     InvalidCharsNativeBridge_test.cpp \
+    NativeBridge2Signal_test.cpp \
+    NativeBridgeVersion_test.cpp \
     NeedsNativeBridge_test.cpp \
     PreInitializeNativeBridge_test.cpp \
     PreInitializeNativeBridgeFail1_test.cpp \
diff --git a/libnativebridge/tests/Android.nativebridge-dummy.mk b/libnativebridge/tests/Android.nativebridge-dummy.mk
index 1caf50a..2efc176 100644
--- a/libnativebridge/tests/Android.nativebridge-dummy.mk
+++ b/libnativebridge/tests/Android.nativebridge-dummy.mk
@@ -32,3 +32,39 @@
 LOCAL_MULTILIB := both
 
 include $(BUILD_HOST_SHARED_LIBRARY)
+
+
+# v2.
+
+NATIVE_BRIDGE2_COMMON_SRC_FILES := \
+  DummyNativeBridge2.cpp
+
+# Shared library for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libnativebridge2-dummy
+
+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_MULTILIB := both
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Shared library for host
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libnativebridge2-dummy
+
+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_MULTILIB := both
+
+include $(BUILD_HOST_SHARED_LIBRARY)
diff --git a/libnativebridge/tests/CompleteFlow_test.cpp b/libnativebridge/tests/CompleteFlow_test.cpp
index cf06d2c..b033792 100644
--- a/libnativebridge/tests/CompleteFlow_test.cpp
+++ b/libnativebridge/tests/CompleteFlow_test.cpp
@@ -36,6 +36,7 @@
 
     // Unload
     UnloadNativeBridge();
+
     ASSERT_FALSE(NativeBridgeAvailable());
     ASSERT_FALSE(NativeBridgeError());
 
diff --git a/libnativebridge/tests/DummyNativeBridge2.cpp b/libnativebridge/tests/DummyNativeBridge2.cpp
new file mode 100644
index 0000000..6920c74
--- /dev/null
+++ b/libnativebridge/tests/DummyNativeBridge2.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+// A dummy implementation of the native-bridge interface.
+
+#include "nativebridge/native_bridge.h"
+
+#include <signal.h>
+
+// NativeBridgeCallbacks implementations
+extern "C" bool native_bridge2_initialize(const android::NativeBridgeRuntimeCallbacks* /* art_cbs */,
+                                         const char* /* app_code_cache_dir */,
+                                         const char* /* isa */) {
+  return true;
+}
+
+extern "C" void* native_bridge2_loadLibrary(const char* /* libpath */, int /* flag */) {
+  return nullptr;
+}
+
+extern "C" void* native_bridge2_getTrampoline(void* /* handle */, const char* /* name */,
+                                             const char* /* shorty */, uint32_t /* len */) {
+  return nullptr;
+}
+
+extern "C" bool native_bridge2_isSupported(const char* /* libpath */) {
+  return false;
+}
+
+extern "C" const struct android::NativeBridgeRuntimeValues* native_bridge2_getAppEnv(
+    const char* /* abi */) {
+  return nullptr;
+}
+
+extern "C" bool native_bridge2_is_compatible_compatible_with(uint32_t version) {
+  // For testing, allow 1 and 2, but disallow 3+.
+  return version <= 2;
+}
+
+static bool native_bridge2_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_bridge2_get_signal_handler(int signal) {
+  if (signal == SIGSEGV) {
+    return &native_bridge2_dummy_signal_handler;
+  }
+  return nullptr;
+}
+
+android::NativeBridgeCallbacks NativeBridgeItf {
+  .version = 2,
+  .initialize = &native_bridge2_initialize,
+  .loadLibrary = &native_bridge2_loadLibrary,
+  .getTrampoline = &native_bridge2_getTrampoline,
+  .isSupported = &native_bridge2_isSupported,
+  .getAppEnv = &native_bridge2_getAppEnv,
+  .isCompatibleWith = &native_bridge2_is_compatible_compatible_with,
+  .getSignalHandler = &native_bridge2_get_signal_handler
+};
+
diff --git a/libnativebridge/tests/NativeBridge2Signal_test.cpp b/libnativebridge/tests/NativeBridge2Signal_test.cpp
new file mode 100644
index 0000000..44e45e3
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge2Signal_test.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+#include <signal.h>
+#include <unistd.h>
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary2 = "libnativebridge2-dummy.so";
+
+TEST_F(NativeBridgeTest, V2_Signal) {
+    // Init
+    ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary2, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+    ASSERT_TRUE(NativeBridgeAvailable());
+    ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+    ASSERT_TRUE(NativeBridgeAvailable());
+
+    ASSERT_EQ(2U, NativeBridgeGetVersion());
+    ASSERT_NE(nullptr, NativeBridgeGetSignalHandler(SIGSEGV));
+
+    // Clean-up code_cache
+    ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+}  // namespace android
diff --git a/libnativebridge/tests/NativeBridgeVersion_test.cpp b/libnativebridge/tests/NativeBridgeVersion_test.cpp
new file mode 100644
index 0000000..d3f9a80
--- /dev/null
+++ b/libnativebridge/tests/NativeBridgeVersion_test.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+#include <unistd.h>
+
+namespace android {
+
+TEST_F(NativeBridgeTest, Version) {
+    // When a bridge isn't loaded, we expect 0.
+    EXPECT_EQ(NativeBridgeGetVersion(), 0U);
+
+    // After our dummy bridge has been loaded, we expect 1.
+    ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr));
+    EXPECT_EQ(NativeBridgeGetVersion(), 1U);
+
+    // Unload
+    UnloadNativeBridge();
+
+    // Version information is gone.
+    EXPECT_EQ(NativeBridgeGetVersion(), 0U);
+}
+
+}  // namespace android
diff --git a/libnetutils/Android.mk b/libnetutils/Android.mk
index 1f61511..2060df4 100644
--- a/libnetutils/Android.mk
+++ b/libnetutils/Android.mk
@@ -17,3 +17,10 @@
 LOCAL_CFLAGS := -Werror
 
 include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := dhcptool.c
+LOCAL_SHARED_LIBRARIES := libnetutils
+LOCAL_MODULE := dhcptool
+LOCAL_MODULE_TAGS := debug
+include $(BUILD_EXECUTABLE)
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
index e1df874..c6b9fe4 100644
--- a/libnetutils/dhcp_utils.c
+++ b/libnetutils/dhcp_utils.c
@@ -1,16 +1,16 @@
 /*
  * 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.
  */
 
@@ -33,7 +33,7 @@
 static const int NAP_TIME = 200;   /* wait for 200ms at a time */
                                   /* when polling for property values */
 static const char DAEMON_NAME_RENEW[]  = "iprenew";
-static char errmsg[100];
+static char errmsg[100] = "\0";
 /* interface length for dhcpcd daemon start (dhcpcd_<interface> as defined in init.rc file)
  * or for filling up system properties dhcpcd.<interface>.ipaddress, dhcpcd.<interface>.dns1
  * and other properties on a successful bind
@@ -72,14 +72,16 @@
         maxnaps = 1;
     }
 
-    while (maxnaps-- > 0) {
-        usleep(NAP_TIME * 1000);
+    while (maxnaps-- >= 0) {
         if (property_get(name, value, NULL)) {
-            if (desired_value == NULL || 
+            if (desired_value == NULL ||
                     strcmp(value, desired_value) == 0) {
                 return 0;
             }
         }
+        if (maxnaps >= 0) {
+            usleep(NAP_TIME * 1000);
+        }
     }
     return -1; /* failure */
 }
@@ -166,12 +168,45 @@
     return 0;
 }
 
-static const char *ipaddr_to_string(in_addr_t addr)
+/*
+ * Get any available DHCP results.
+ */
+int dhcp_get_results(const char *interface,
+                     char *ipaddr,
+                     char *gateway,
+                     uint32_t *prefixLength,
+                     char *dns[],
+                     char *server,
+                     uint32_t *lease,
+                     char *vendorInfo,
+                     char *domain,
+                     char *mtu)
 {
-    struct in_addr in_addr;
+    char result_prop_name[PROPERTY_KEY_MAX];
+    char prop_value[PROPERTY_VALUE_MAX];
 
-    in_addr.s_addr = addr;
-    return inet_ntoa(in_addr);
+    /* Interface name after converting p2p0-p2p0-X to p2p to reuse system properties */
+    char p2p_interface[MAX_INTERFACE_LENGTH];
+    get_p2p_interface_replacement(interface, p2p_interface);
+    snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
+            DHCP_PROP_NAME_PREFIX,
+            p2p_interface);
+
+    memset(prop_value, '\0', PROPERTY_VALUE_MAX);
+    if (!property_get(result_prop_name, prop_value, NULL)) {
+        snprintf(errmsg, sizeof(errmsg), "%s", "DHCP result property was not set");
+        return -1;
+    }
+    if (strcmp(prop_value, "ok") == 0) {
+        if (fill_ip_info(interface, ipaddr, gateway, prefixLength, dns,
+                server, lease, vendorInfo, domain, mtu) == -1) {
+            return -1;
+        }
+        return 0;
+    } else {
+        snprintf(errmsg, sizeof(errmsg), "DHCP result was %s", prop_value);
+        return -1;
+    }
 }
 
 /*
@@ -183,16 +218,7 @@
  * Example:
  * service dhcpcd_<interface> /system/bin/dhcpcd -ABKL -f dhcpcd.conf
  */
-int dhcp_do_request(const char *interface,
-                    char *ipaddr,
-                    char *gateway,
-                    uint32_t *prefixLength,
-                    char *dns[],
-                    char *server,
-                    uint32_t *lease,
-                    char *vendorInfo,
-                    char *domain,
-                    char *mtu)
+int dhcp_start(const char *interface)
 {
     char result_prop_name[PROPERTY_KEY_MAX];
     char daemon_prop_name[PROPERTY_KEY_MAX];
@@ -236,22 +262,7 @@
         return -1;
     }
 
-    if (!property_get(result_prop_name, prop_value, NULL)) {
-        /* shouldn't ever happen, given the success of wait_for_property() */
-        snprintf(errmsg, sizeof(errmsg), "%s", "DHCP result property was not set");
-        return -1;
-    }
-    if (strcmp(prop_value, "ok") == 0) {
-        char dns_prop_name[PROPERTY_KEY_MAX];
-        if (fill_ip_info(interface, ipaddr, gateway, prefixLength, dns,
-                server, lease, vendorInfo, domain, mtu) == -1) {
-            return -1;
-        }
-        return 0;
-    } else {
-        snprintf(errmsg, sizeof(errmsg), "DHCP result was %s", prop_value);
-        return -1;
-    }
+    return 0;
 }
 
 /**
@@ -327,16 +338,7 @@
  * service iprenew_<interface> /system/bin/dhcpcd -n
  *
  */
-int dhcp_do_request_renew(const char *interface,
-                    char *ipaddr,
-                    char *gateway,
-                    uint32_t *prefixLength,
-                    char *dns[],
-                    char *server,
-                    uint32_t *lease,
-                    char *vendorInfo,
-                    char *domain,
-                    char *mtu)
+int dhcp_start_renew(const char *interface)
 {
     char result_prop_name[PROPERTY_KEY_MAX];
     char prop_value[PROPERTY_VALUE_MAX] = {'\0'};
@@ -366,16 +368,5 @@
         return -1;
     }
 
-    if (!property_get(result_prop_name, prop_value, NULL)) {
-        /* shouldn't ever happen, given the success of wait_for_property() */
-        snprintf(errmsg, sizeof(errmsg), "%s", "DHCP Renew result property was not set");
-        return -1;
-    }
-    if (strcmp(prop_value, "ok") == 0) {
-        return fill_ip_info(interface, ipaddr, gateway, prefixLength, dns,
-                server, lease, vendorInfo, domain, mtu);
-    } else {
-        snprintf(errmsg, sizeof(errmsg), "DHCP Renew result was %s", prop_value);
-        return -1;
-    }
+    return 0;
 }
diff --git a/libnetutils/dhcpclient.c b/libnetutils/dhcpclient.c
index b58120e..240a789 100644
--- a/libnetutils/dhcpclient.c
+++ b/libnetutils/dhcpclient.c
@@ -150,7 +150,7 @@
 
 void dump_dhcp_info(dhcp_info *info)
 {
-    char addr[20], gway[20], mask[20];
+    char addr[20], gway[20];
     ALOGD("--- dhcp %s (%d) ---",
             dhcp_type_to_name(info->type), info->type);
     strcpy(addr, ipaddr(info->ipaddr));
@@ -236,13 +236,13 @@
 
 #if VERBOSE
 
-static void hex2str(char *buf, const unsigned char *array, int len)
+static void hex2str(char *buf, size_t buf_size, const unsigned char *array, int len)
 {
     int i;
     char *cp = buf;
-
+    char *buf_end = buf + buf_size;
     for (i = 0; i < len; i++) {
-        cp += sprintf(cp, " %02x ", array[i]);
+        cp += snprintf(cp, buf_end - cp, " %02x ", array[i]);
     }
 }
 
@@ -278,7 +278,7 @@
     ALOGD("giaddr = %s", ipaddr(msg->giaddr));
 
     c = msg->hlen > 16 ? 16 : msg->hlen;
-    hex2str(buf, msg->chaddr, c);
+    hex2str(buf, sizeof(buf), msg->chaddr, c);
     ALOGD("chaddr = {%s}", buf);
 
     for (n = 0; n < 64; n++) {
@@ -327,7 +327,7 @@
             memcpy(buf, &x[2], n);
             buf[n] = '\0';
         } else {
-            hex2str(buf, &x[2], optsz);
+            hex2str(buf, sizeof(buf), &x[2], optsz);
         }
         if (x[0] == OPT_MESSAGE_TYPE)
             name = dhcp_type_to_name(x[2]);
@@ -353,28 +353,28 @@
 static int is_valid_reply(dhcp_msg *msg, dhcp_msg *reply, int sz)
 {
     if (sz < DHCP_MSG_FIXED_SIZE) {
-        if (verbose) ALOGD("netcfg: Wrong size %d != %d\n", sz, DHCP_MSG_FIXED_SIZE);
+        if (verbose) ALOGD("Wrong size %d != %d\n", sz, DHCP_MSG_FIXED_SIZE);
         return 0;
     }
     if (reply->op != OP_BOOTREPLY) {
-        if (verbose) ALOGD("netcfg: Wrong Op %d != %d\n", reply->op, OP_BOOTREPLY);
+        if (verbose) ALOGD("Wrong Op %d != %d\n", reply->op, OP_BOOTREPLY);
         return 0;
     }
     if (reply->xid != msg->xid) {
-        if (verbose) ALOGD("netcfg: Wrong Xid 0x%x != 0x%x\n", ntohl(reply->xid),
-                          ntohl(msg->xid));
+        if (verbose) ALOGD("Wrong Xid 0x%x != 0x%x\n", ntohl(reply->xid),
+                           ntohl(msg->xid));
         return 0;
     }
     if (reply->htype != msg->htype) {
-        if (verbose) ALOGD("netcfg: Wrong Htype %d != %d\n", reply->htype, msg->htype);
+        if (verbose) ALOGD("Wrong Htype %d != %d\n", reply->htype, msg->htype);
         return 0;
     }
     if (reply->hlen != msg->hlen) {
-        if (verbose) ALOGD("netcfg: Wrong Hlen %d != %d\n", reply->hlen, msg->hlen);
+        if (verbose) ALOGD("Wrong Hlen %d != %d\n", reply->hlen, msg->hlen);
         return 0;
     }
     if (memcmp(msg->chaddr, reply->chaddr, msg->hlen)) {
-        if (verbose) ALOGD("netcfg: Wrong chaddr %x != %x\n", *(reply->chaddr),*(msg->chaddr));
+        if (verbose) ALOGD("Wrong chaddr %x != %x\n", *(reply->chaddr),*(msg->chaddr));
         return 0;
     }
     return 1;
diff --git a/libnetutils/dhcptool.c b/libnetutils/dhcptool.c
new file mode 100644
index 0000000..352ac5e
--- /dev/null
+++ b/libnetutils/dhcptool.c
@@ -0,0 +1,43 @@
+/*
+ * 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 <errno.h>
+#include <error.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <netutils/dhcp.h>
+#include <netutils/ifc.h>
+
+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()) {
+    error(EXIT_FAILURE, errno, "dhcptool %s: ifc_init failed", interface);
+  }
+
+  int rc = do_dhcp(interface);
+  if (rc) {
+    error(0, 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 913f51e..7d2a5fb 100644
--- a/libnetutils/ifc_utils.c
+++ b/libnetutils/ifc_utils.c
@@ -123,7 +123,7 @@
 {
     int ret;
     if (ifc_ctl_sock == -1) {
-        ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM, 0);
+        ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
         if (ifc_ctl_sock < 0) {
             printerr("socket() failed: %s\n", strerror(errno));
         }
@@ -137,7 +137,7 @@
 int ifc_init6(void)
 {
     if (ifc_ctl_sock6 == -1) {
-        ifc_ctl_sock6 = socket(AF_INET6, SOCK_DGRAM, 0);
+        ifc_ctl_sock6 = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
         if (ifc_ctl_sock6 < 0) {
             printerr("socket() failed: %s\n", strerror(errno));
         }
@@ -316,7 +316,7 @@
     req.n.nlmsg_len = NLMSG_ALIGN(req.n.nlmsg_len) + RTA_LENGTH(addrlen);
     memcpy(RTA_DATA(rta), addr, addrlen);
 
-    s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+    s = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
     if (send(s, &req, req.n.nlmsg_len, 0) < 0) {
         close(s);
         return -errno;
@@ -421,7 +421,6 @@
 
 int ifc_set_hwaddr(const char *name, const void *ptr)
 {
-    int r;
     struct ifreq ifr;
     ifc_init_ifr(name, &ifr);
 
diff --git a/libnetutils/packet.c b/libnetutils/packet.c
index 3cdefb0..cd26d05 100644
--- a/libnetutils/packet.c
+++ b/libnetutils/packet.c
@@ -15,6 +15,7 @@
  */
 
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 #include <sys/uio.h>
 #include <sys/socket.h>
@@ -41,7 +42,7 @@
 
 int open_raw_socket(const char *ifname __attribute__((unused)), uint8_t *hwaddr, int if_index)
 {
-    int s, flag;
+    int s;
     struct sockaddr_ll bindaddr;
 
     if((s = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk
index 8a427b3..f02da7f 100644
--- a/libpixelflinger/Android.mk
+++ b/libpixelflinger/Android.mk
@@ -34,6 +34,7 @@
 
 ifeq ($(ARCH_ARM_HAVE_NEON),true)
 PIXELFLINGER_SRC_FILES_arm += col32cb16blend_neon.S
+PIXELFLINGER_CFLAGS_arm += -D__ARM_HAVE_NEON
 endif
 
 PIXELFLINGER_SRC_FILES_arm64 := \
@@ -42,11 +43,13 @@
 	arch-arm64/col32cb16blend.S \
 	arch-arm64/t32cb16blend.S \
 
+ifndef ARCH_MIPS_REV6
 PIXELFLINGER_SRC_FILES_mips := \
 	codeflinger/MIPSAssembler.cpp \
 	codeflinger/mips_disassem.c \
 	arch-mips/t32cb16blend.S \
 
+endif
 #
 # Shared library
 #
@@ -57,29 +60,19 @@
 LOCAL_SRC_FILES_arm64 := $(PIXELFLINGER_SRC_FILES_arm64)
 LOCAL_SRC_FILES_mips := $(PIXELFLINGER_SRC_FILES_mips)
 LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS) \
+		    external/safe-iop/include
 LOCAL_SHARED_LIBRARIES := libcutils liblog libutils
-LOCAL_C_INCLUDES += external/safe-iop/include
 
-ifneq ($(BUILD_TINY_ANDROID),true)
 # 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
-endif
+# t32cb16blend.S does not compile with Clang.
+LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
+# arch-arm64/col32cb16blend.S does not compile with Clang.
+LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as
 include $(BUILD_SHARED_LIBRARY)
 
-#
-# Static library version
-#
-
-include $(CLEAR_VARS)
-LOCAL_MODULE:= libpixelflinger_static
-LOCAL_SRC_FILES := $(PIXELFLINGER_SRC_FILES)
-LOCAL_SRC_FILES_arm := $(PIXELFLINGER_SRC_FILES_arm)
-LOCAL_SRC_FILES_arm64 := $(PIXELFLINGER_SRC_FILES_arm64)
-LOCAL_SRC_FILES_mips := $(PIXELFLINGER_SRC_FILES_mips)
-LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS)
-include $(BUILD_STATIC_LIBRARY)
-
-
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libpixelflinger/codeflinger/CodeCache.cpp b/libpixelflinger/codeflinger/CodeCache.cpp
index cfd2b37..d770302 100644
--- a/libpixelflinger/codeflinger/CodeCache.cpp
+++ b/libpixelflinger/codeflinger/CodeCache.cpp
@@ -201,8 +201,8 @@
         mCacheInUse += assemblySize;
         mWhen++;
         // synchronize caches...
-        void* base = assembly->base();
-        void* curr = (uint8_t*)base + assembly->size();
+        char* base = reinterpret_cast<char*>(assembly->base());
+        char* curr = reinterpret_cast<char*>(base + assembly->size());
         __builtin___clear_cache(base, curr);
     }
 
diff --git a/libpixelflinger/codeflinger/load_store.cpp b/libpixelflinger/codeflinger/load_store.cpp
index 0a46eaa..e5a1ae0 100644
--- a/libpixelflinger/codeflinger/load_store.cpp
+++ b/libpixelflinger/codeflinger/load_store.cpp
@@ -20,10 +20,6 @@
 #include <cutils/log.h>
 #include "GGLAssembler.h"
 
-#ifdef __ARM_ARCH__
-#include <machine/cpu-features.h>
-#endif
-
 namespace android {
 
 // ----------------------------------------------------------------------------
@@ -117,20 +113,6 @@
 #endif
     assert(h);
     
-#if __ARM_ARCH__ >= 7
-    const int mask = (1<<maskLen)-1;
-    if ((h == bits) && !l && (s != d.reg)) {
-        MOV(AL, 0, d.reg, s);                   // component = packed;
-    } else if ((h == bits) && l) {
-        MOV(AL, 0, d.reg, reg_imm(s, LSR, l));  // component = packed >> l;
-    } else if (!l && isValidImmediate(mask)) {
-        AND(AL, 0, d.reg, s, imm(mask));        // component = packed & mask;
-    } else if (!l && isValidImmediate(~mask)) {
-        BIC(AL, 0, d.reg, s, imm(~mask));       // component = packed & mask;
-    } else {
-        UBFX(AL, d.reg, s, l, maskLen);         // component = (packed & mask) >> l;
-    }
-#else
     if (h != bits) {
         const int mask = ((1<<maskLen)-1) << l;
         if (isValidImmediate(mask)) {
@@ -153,7 +135,6 @@
     if (s != d.reg) {
         MOV(AL, 0, d.reg, s);
     }
-#endif
 
     d.s = maskLen;
 }
diff --git a/libpixelflinger/codeflinger/texturing.cpp b/libpixelflinger/codeflinger/texturing.cpp
index 81950bf..29a3742 100644
--- a/libpixelflinger/codeflinger/texturing.cpp
+++ b/libpixelflinger/codeflinger/texturing.cpp
@@ -25,10 +25,6 @@
 
 #include "GGLAssembler.h"
 
-#ifdef __ARM_ARCH__
-#include <machine/cpu-features.h>
-#endif
-
 namespace android {
 
 // ---------------------------------------------------------------------------
@@ -888,106 +884,6 @@
     load(txPtr, texel, 0);
 }
 
-#if __ARM_ARCH__ >= 6
-// ARMv6 version, using UXTB16, and scheduled for Cortex-A8 pipeline
-void GGLAssembler::filter32(
-        const fragment_parts_t& parts,
-        pixel_t& texel, const texture_unit_t& tmu,
-        int U, int V, pointer_t& txPtr,
-        int FRAC_BITS)
-{
-    const int adjust = FRAC_BITS*2 - 8;
-    const int round  = 0;
-    const int prescale = 16 - adjust;
-
-    Scratch scratches(registerFile());
-    
-    int pixel= scratches.obtain();
-    int dh   = scratches.obtain();
-    int u    = scratches.obtain();
-    int k    = scratches.obtain();
-
-    int temp = scratches.obtain();
-    int dl   = scratches.obtain();
-
-    int offsetrt = scratches.obtain();
-    int offsetlb = scratches.obtain();
-
-    int pixellb = offsetlb;
-
-    // RB -> U * V
-    CONTEXT_LOAD(offsetrt, generated_vars.rt);
-    CONTEXT_LOAD(offsetlb, generated_vars.lb);
-    if(!round) {
-        MOV(AL, 0, U, reg_imm(U, LSL, prescale));
-    }
-    ADD(AL, 0, u, offsetrt, offsetlb);
-
-    LDR(AL, pixel, txPtr.reg, reg_scale_pre(u));
-    if (round) {
-        SMULBB(AL, u, U, V);
-        RSB(AL, 0, U, U, imm(1<<FRAC_BITS));
-    } else {
-        SMULWB(AL, u, U, V);
-        RSB(AL, 0, U, U, imm(1<<(FRAC_BITS+prescale)));
-    }
-    UXTB16(AL, temp, pixel, 0);
-    if (round) {
-        ADD(AL, 0, u, u, imm(1<<(adjust-1)));
-        MOV(AL, 0, u, reg_imm(u, LSR, adjust));
-    }
-    LDR(AL, pixellb, txPtr.reg, reg_scale_pre(offsetlb));
-    MUL(AL, 0, dh, temp, u);
-    UXTB16(AL, temp, pixel, 8);
-    MUL(AL, 0, dl, temp, u);
-    RSB(AL, 0, k, u, imm(0x100));
-
-    // LB -> (1-U) * V
-    if (round) {
-        SMULBB(AL, u, U, V);
-    } else {
-        SMULWB(AL, u, U, V);
-    }
-    UXTB16(AL, temp, pixellb, 0);
-    if (round) {
-        ADD(AL, 0, u, u, imm(1<<(adjust-1)));
-        MOV(AL, 0, u, reg_imm(u, LSR, adjust));
-    }
-    MLA(AL, 0, dh, temp, u, dh);    
-    UXTB16(AL, temp, pixellb, 8);
-    MLA(AL, 0, dl, temp, u, dl);
-    SUB(AL, 0, k, k, u);
-
-    // LT -> (1-U)*(1-V)
-    RSB(AL, 0, V, V, imm(1<<FRAC_BITS));
-    LDR(AL, pixel, txPtr.reg);
-    if (round) {
-        SMULBB(AL, u, U, V);
-    } else {
-        SMULWB(AL, u, U, V);
-    }
-    UXTB16(AL, temp, pixel, 0);
-    if (round) {
-        ADD(AL, 0, u, u, imm(1<<(adjust-1)));
-        MOV(AL, 0, u, reg_imm(u, LSR, adjust));
-    }
-    MLA(AL, 0, dh, temp, u, dh);    
-    UXTB16(AL, temp, pixel, 8);
-    MLA(AL, 0, dl, temp, u, dl);
-
-    // RT -> U*(1-V)            
-    LDR(AL, pixel, txPtr.reg, reg_scale_pre(offsetrt));
-    SUB(AL, 0, u, k, u);
-    UXTB16(AL, temp, pixel, 0);
-    MLA(AL, 0, dh, temp, u, dh);    
-    UXTB16(AL, temp, pixel, 8);
-    MLA(AL, 0, dl, temp, u, dl);
-
-    UXTB16(AL, dh, dh, 8);
-    UXTB16(AL, dl, dl, 8);
-    ORR(AL, 0, texel.reg, dh, reg_imm(dl, LSL, 8));
-}
-#else
 void GGLAssembler::filter32(
         const fragment_parts_t& /*parts*/,
         pixel_t& texel, const texture_unit_t& /*tmu*/,
@@ -1075,7 +971,6 @@
     AND(AL, 0, dl, dl, reg_imm(mask, LSL, 8));
     ORR(AL, 0, texel.reg, dh, dl);
 }
-#endif
 
 void GGLAssembler::build_texture_environment(
         component_t& fragment,
diff --git a/include/pixelflinger/format.h b/libpixelflinger/include/pixelflinger/format.h
similarity index 100%
rename from include/pixelflinger/format.h
rename to libpixelflinger/include/pixelflinger/format.h
diff --git a/include/pixelflinger/pixelflinger.h b/libpixelflinger/include/pixelflinger/pixelflinger.h
similarity index 100%
rename from include/pixelflinger/pixelflinger.h
rename to libpixelflinger/include/pixelflinger/pixelflinger.h
diff --git a/include/private/pixelflinger/ggl_context.h b/libpixelflinger/include/private/pixelflinger/ggl_context.h
similarity index 100%
rename from include/private/pixelflinger/ggl_context.h
rename to libpixelflinger/include/private/pixelflinger/ggl_context.h
diff --git a/include/private/pixelflinger/ggl_fixed.h b/libpixelflinger/include/private/pixelflinger/ggl_fixed.h
similarity index 99%
rename from include/private/pixelflinger/ggl_fixed.h
rename to libpixelflinger/include/private/pixelflinger/ggl_fixed.h
index d0493f3..787f620 100644
--- a/include/private/pixelflinger/ggl_fixed.h
+++ b/libpixelflinger/include/private/pixelflinger/ggl_fixed.h
@@ -190,7 +190,7 @@
         );
     return res;
 }
-#elif defined(__mips__)
+#elif defined(__mips__) && __mips_isa_rev < 6
 
 /*inline MIPS implementations*/
 inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) CONST;
diff --git a/libpixelflinger/pixelflinger.cpp b/libpixelflinger/pixelflinger.cpp
index ea5bc8e..fd449b2 100644
--- a/libpixelflinger/pixelflinger.cpp
+++ b/libpixelflinger/pixelflinger.cpp
@@ -727,18 +727,10 @@
 
 int64_t ggl_system_time()
 {
-#if defined(HAVE_POSIX_CLOCKS)
     struct timespec t;
     t.tv_sec = t.tv_nsec = 0;
     clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t);
     return int64_t(t.tv_sec)*1000000000LL + t.tv_nsec;
-#else
-    // we don't support the clocks here.
-    struct timeval t;
-    t.tv_sec = t.tv_usec = 0;
-    gettimeofday(&t, NULL);
-    return int64_t(t.tv_sec)*1000000000LL + int64_t(t.tv_usec)*1000LL;
-#endif
 }
 
 // ----------------------------------------------------------------------------
diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp
index 26b9a3e..3d14531 100644
--- a/libpixelflinger/scanline.cpp
+++ b/libpixelflinger/scanline.cpp
@@ -39,7 +39,7 @@
 #include "codeflinger/ARMAssembler.h"
 #elif defined(__aarch64__)
 #include "codeflinger/Arm64Assembler.h"
-#elif defined(__mips__) && !defined(__LP64__)
+#elif defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6
 #include "codeflinger/MIPSAssembler.h"
 #endif
 //#include "codeflinger/ARMAssemblerOptimizer.h"
@@ -59,7 +59,7 @@
 #   define ANDROID_CODEGEN      ANDROID_CODEGEN_GENERATED
 #endif
 
-#if defined(__arm__) || (defined(__mips__) && !defined(__LP64__)) || defined(__aarch64__)
+#if defined(__arm__) || (defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6) || defined(__aarch64__)
 #   define ANDROID_ARM_CODEGEN  1
 #else
 #   define ANDROID_ARM_CODEGEN  0
@@ -73,7 +73,7 @@
  */
 #define DEBUG_NEEDS  0
 
-#if defined( __mips__) && !defined(__LP64__)
+#if defined( __mips__) && !defined(__LP64__) && __mips_isa_rev < 6
 #define ASSEMBLY_SCRATCH_SIZE   4096
 #elif defined(__aarch64__)
 #define ASSEMBLY_SCRATCH_SIZE   8192
@@ -134,7 +134,7 @@
 #elif defined(__aarch64__)
 extern "C" void scanline_t32cb16blend_arm64(uint16_t*, uint32_t*, size_t);
 extern "C" void scanline_col32cb16blend_arm64(uint16_t *dst, uint32_t col, size_t ct);
-#elif defined(__mips__)  && !defined(__LP64__)
+#elif defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6
 extern "C" void scanline_t32cb16blend_mips(uint16_t*, uint32_t*, size_t);
 #endif
 
@@ -286,7 +286,7 @@
 
 #if ANDROID_ARM_CODEGEN
 
-#if defined(__mips__)
+#if defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6
 static CodeCache gCodeCache(32 * 1024);
 #elif defined(__aarch64__)
 static CodeCache gCodeCache(48 * 1024);
@@ -2175,7 +2175,7 @@
 
 void scanline_t32cb16blend(context_t* c)
 {
-#if ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && (defined(__arm__) || (defined(__mips__) && !defined(__LP64__)) || defined(__aarch64__)))
+#if ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && (defined(__arm__) || (defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6) || defined(__aarch64__)))
     int32_t x = c->iterators.xl;
     size_t ct = c->iterators.xr - x;
     int32_t y = c->iterators.y;
diff --git a/libpixelflinger/tests/arch-arm64/assembler/Android.mk b/libpixelflinger/tests/arch-arm64/assembler/Android.mk
index eca36ef..448d298 100644
--- a/libpixelflinger/tests/arch-arm64/assembler/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/assembler/Android.mk
@@ -5,12 +5,15 @@
     arm64_assembler_test.cpp\
     asm_test_jacket.S
 
+# asm_test_jacket.S does not compile with Clang.
+LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as
+
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
     libpixelflinger
 
 LOCAL_C_INCLUDES := \
-    system/core/libpixelflinger
+    $(LOCAL_PATH)/../../..
 
 LOCAL_MODULE:= test-pixelflinger-arm64-assembler-test
 
diff --git a/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp b/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp
index 456be58..5f58797 100644
--- a/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp
+++ b/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp
@@ -409,7 +409,7 @@
 {
     const long base = long(instrMem);
     const long curr = base + long(instrMemSize);
-    __builtin___clear_cache((void*)base, (void*)curr);
+    __builtin___clear_cache((char*)base, (char*)curr);
 }
 void dataOpTest(dataOpTest_t test, ARMAssemblerInterface *a64asm, uint32_t Rd = 0,
                 uint32_t Rn = 1, uint32_t Rm = 2, uint32_t Rs = 3)
@@ -493,16 +493,17 @@
         if(i == Rd) continue;
         if(regs[i] != savedRegs[i])
         {
-            printf("Test %x failed Reg(%d) tampered Expected(0x%"PRIx64"),"
-                   "Actual(0x%"PRIx64") t\n", test.id, i, savedRegs[i], regs[i]);
+            printf("Test %x failed Reg(%d) tampered Expected(0x%" PRIx64 "),"
+                   "Actual(0x%" PRIx64 ") t\n", test.id, i, savedRegs[i],
+                   regs[i]);
             return;
         }
     }
 
     if(test.checkRd == 1 && (uint64_t)regs[Rd] != test.postRdValue)
     {
-        printf("Test %x failed, Expected(%"PRIx64"), Actual(%"PRIx64")\n",
-                test.id, test.postRdValue, regs[Rd]);
+        printf("Test %x failed, Expected(%" PRIx64 "), Actual(%" PRIx64 ")\n",
+               test.id, test.postRdValue, regs[Rd]);
     }
     else if(test.checkFlag == 1 && flags[test.postFlag] == 0)
     {
@@ -610,7 +611,7 @@
         if(regs[i] != savedRegs[i])
         {
             printf("Test %x failed Reg(%d) tampered"
-                   " Expected(0x%"PRIx64"), Actual(0x%"PRIx64") t\n",
+                   " Expected(0x%" PRIx64 "), Actual(0x%" PRIx64 ") t\n",
                    test.id, i, savedRegs[i], regs[i]);
             return;
         }
@@ -619,13 +620,13 @@
     if((uint64_t)regs[Rd] != test.postRdValue)
     {
         printf("Test %x failed, "
-               "Expected in Rd(0x%"PRIx64"), Actual(0x%"PRIx64")\n",
+               "Expected in Rd(0x%" PRIx64 "), Actual(0x%" PRIx64 ")\n",
                test.id, test.postRdValue, regs[Rd]);
     }
     else if((uint64_t)regs[Rn] != (uint64_t)(&dataMem[test.postRnValue]))
     {
         printf("Test %x failed, "
-               "Expected in Rn(0x%"PRIx64"), Actual(0x%"PRIx64")\n",
+               "Expected in Rn(0x%" PRIx64 "), Actual(0x%" PRIx64 ")\n",
                test.id, test.postRnValue, regs[Rn] - (uint64_t)dataMem);
     }
     else if(test.checkMem == true)
@@ -638,7 +639,7 @@
         if(value != test.postMemValue)
         {
             printf("Test %x failed, "
-                   "Expected in Mem(0x%"PRIx64"), Actual(0x%"PRIx64")\n",
+                   "Expected in Mem(0x%" PRIx64 "), Actual(0x%" PRIx64 ")\n",
                    test.id, test.postMemValue, value);
         }
         else
@@ -697,8 +698,8 @@
                 if(regs[j] != j)
                 {
                     printf("LDM/STM Test %x failed "
-                           "Reg%d expected(0x%x) Actual(0x%"PRIx64") \n",
-                            patterns[i],j,j,regs[j]);
+                           "Reg%d expected(0x%x) Actual(0x%" PRIx64 ") \n",
+                           patterns[i], j, j, regs[j]);
                     break;
                 }
             }
diff --git a/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk b/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
index 3368eb0..5d69203 100644
--- a/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
@@ -5,6 +5,8 @@
     col32cb16blend_test.c \
     ../../../arch-arm64/col32cb16blend.S
 
+LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as
+
 LOCAL_SHARED_LIBRARIES :=
 
 LOCAL_C_INCLUDES :=
diff --git a/libpixelflinger/tests/arch-arm64/disassembler/Android.mk b/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
index 8f62f09..d8f7e69 100644
--- a/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
@@ -7,9 +7,6 @@
 
 LOCAL_SHARED_LIBRARIES :=
 
-LOCAL_C_INCLUDES := \
-    system/core/libpixelflinger/codeflinger
-
 LOCAL_MODULE:= test-pixelflinger-arm64-disassembler-test
 
 LOCAL_MODULE_TAGS := tests
diff --git a/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
index 8e5ec5e..2c1379b 100644
--- a/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
@@ -5,6 +5,8 @@
     t32cb16blend_test.c \
     ../../../arch-arm64/t32cb16blend.S
 
+LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as
+
 LOCAL_SHARED_LIBRARIES :=
 
 LOCAL_C_INCLUDES :=
diff --git a/libpixelflinger/tests/codegen/Android.mk b/libpixelflinger/tests/codegen/Android.mk
index bc07015..2f9ca2f 100644
--- a/libpixelflinger/tests/codegen/Android.mk
+++ b/libpixelflinger/tests/codegen/Android.mk
@@ -9,7 +9,7 @@
     libpixelflinger
 
 LOCAL_C_INCLUDES := \
-	system/core/libpixelflinger
+	$(LOCAL_PATH)/../..
 
 LOCAL_MODULE:= test-opengl-codegen
 
diff --git a/libpixelflinger/tests/codegen/codegen.cpp b/libpixelflinger/tests/codegen/codegen.cpp
index 46c1ccc..148b6f4 100644
--- a/libpixelflinger/tests/codegen/codegen.cpp
+++ b/libpixelflinger/tests/codegen/codegen.cpp
@@ -9,16 +9,18 @@
 #include "codeflinger/CodeCache.h"
 #include "codeflinger/GGLAssembler.h"
 #include "codeflinger/ARMAssembler.h"
+#if defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6
 #include "codeflinger/MIPSAssembler.h"
+#endif
 #include "codeflinger/Arm64Assembler.h"
 
-#if defined(__arm__) || defined(__mips__) || defined(__aarch64__)
+#if defined(__arm__) || (defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6) || defined(__aarch64__)
 #   define ANDROID_ARM_CODEGEN  1
 #else
 #   define ANDROID_ARM_CODEGEN  0
 #endif
 
-#if defined (__mips__)
+#if defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6
 #define ASSEMBLY_SCRATCH_SIZE   4096
 #elif defined(__aarch64__)
 #define ASSEMBLY_SCRATCH_SIZE   8192
@@ -52,7 +54,7 @@
     GGLAssembler assembler( new ARMAssembler(a) );
 #endif
 
-#if defined(__mips__) && !defined(__LP64__)
+#if defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6
     GGLAssembler assembler( new ArmToMipsAssembler(a) );
 #endif
 
diff --git a/libpixelflinger/tests/gglmul/Android.mk b/libpixelflinger/tests/gglmul/Android.mk
index f479fa1..75bd39e 100644
--- a/libpixelflinger/tests/gglmul/Android.mk
+++ b/libpixelflinger/tests/gglmul/Android.mk
@@ -7,7 +7,7 @@
 LOCAL_SHARED_LIBRARIES :=
 
 LOCAL_C_INCLUDES := \
-	system/core/libpixelflinger
+	$(LOCAL_PATH)/../../include
 
 LOCAL_MODULE:= test-pixelflinger-gglmul
 
diff --git a/libprocessgroup/Android.mk b/libprocessgroup/Android.mk
index 051999a..ee6ba58 100644
--- a/libprocessgroup/Android.mk
+++ b/libprocessgroup/Android.mk
@@ -8,7 +8,6 @@
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_CFLAGS := -Wall -Werror
 LOCAL_REQUIRED_MODULE := processgroup_cleanup
-include external/libcxx/libcxx.mk
 include $(BUILD_SHARED_LIBRARY)
 
 include $(CLEAR_VARS)
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 49f5903..ad0500d 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -19,7 +19,9 @@
 
 #include <assert.h>
 #include <dirent.h>
+#include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -100,7 +102,7 @@
 
     ctx->buf_len += ret;
     ctx->buf[ctx->buf_len] = 0;
-    SLOGV("Read %d to buffer: %s", ret, ctx->buf);
+    SLOGV("Read %zd to buffer: %s", ret, ctx->buf);
 
     assert(ctx->buf_len <= sizeof(ctx->buf));
 
@@ -250,14 +252,15 @@
 int killProcessGroup(uid_t uid, int initialPid, int signal)
 {
     int processes;
-    int sleep_us = 100;
-    long startTime = android::uptimeMillis();
+    const int sleep_us = 5 * 1000;  // 5ms
+    int64_t startTime = android::uptimeMillis();
+    int retry = 40;
 
     while ((processes = killProcessGroupOnce(uid, initialPid, signal)) > 0) {
         SLOGV("killed %d processes for processgroup %d\n", processes, initialPid);
-        if (sleep_us < 128000) {
+        if (retry > 0) {
             usleep(sleep_us);
-            sleep_us *= 2;
+            --retry;
         } else {
             SLOGE("failed to kill %d processes for processgroup %d\n",
                     processes, initialPid);
@@ -265,7 +268,7 @@
         }
     }
 
-    SLOGV("Killed process group uid %d pid %d in %ldms, %d procs remain", uid, initialPid,
+    SLOGV("Killed process group uid %d pid %d in %" PRId64 "ms, %d procs remain", uid, initialPid,
             android::uptimeMillis()-startTime, processes);
 
     if (processes == 0) {
@@ -279,12 +282,12 @@
 {
     int ret;
 
-    ret = mkdir(path, 0750);
+    ret = mkdir(path, mode);
     if (ret < 0 && errno != EEXIST) {
         return -errno;
     }
 
-    ret = chown(path, AID_SYSTEM, AID_SYSTEM);
+    ret = chown(path, uid, gid);
     if (ret < 0) {
         ret = -errno;
         rmdir(path);
diff --git a/libsparse/Android.mk b/libsparse/Android.mk
index 0abe33d..925b98b 100644
--- a/libsparse/Android.mk
+++ b/libsparse/Android.mk
@@ -16,7 +16,7 @@
 LOCAL_SRC_FILES := $(libsparse_src_files)
 LOCAL_MODULE := libsparse_host
 LOCAL_STATIC_LIBRARIES := libz
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/include external/zlib
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 LOCAL_CFLAGS := -Werror
 include $(BUILD_HOST_STATIC_LIBRARY)
 
@@ -25,7 +25,7 @@
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_SRC_FILES := $(libsparse_src_files)
 LOCAL_MODULE := libsparse
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/include external/zlib
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
 LOCAL_SHARED_LIBRARIES := \
     libz
 LOCAL_CFLAGS := -Werror
@@ -36,7 +36,7 @@
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_SRC_FILES := $(libsparse_src_files)
 LOCAL_MODULE := libsparse_static
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/include external/zlib
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
 LOCAL_STATIC_LIBRARIES := libz
 LOCAL_CFLAGS := -Werror
 include $(BUILD_STATIC_LIBRARY)
diff --git a/libsparse/append2simg.c b/libsparse/append2simg.c
index 65e6cc2..1cf827c 100644
--- a/libsparse/append2simg.c
+++ b/libsparse/append2simg.c
@@ -82,7 +82,7 @@
         exit(-1);
     }
 
-    sparse_output = sparse_file_import_auto(output, true);
+    sparse_output = sparse_file_import_auto(output, true, true);
     if (!sparse_output) {
         fprintf(stderr, "Couldn't import output file\n");
         exit(-1);
diff --git a/libsparse/include/sparse/sparse.h b/libsparse/include/sparse/sparse.h
index 8b757d2..42d4adb 100644
--- a/libsparse/include/sparse/sparse.h
+++ b/libsparse/include/sparse/sparse.h
@@ -234,6 +234,7 @@
  *
  * @fd - file descriptor to read from
  * @crc - verify the crc of a file in the Android sparse file format
+ * @verbose - whether to use verbose logging
  *
  * Reads an existing sparse or normal file into a sparse file cookie.
  * Attempts to determine if the file is sparse or not by looking for the sparse
@@ -243,7 +244,7 @@
  *
  * Returns a new sparse file cookie on success, NULL on error.
  */
-struct sparse_file *sparse_file_import_auto(int fd, bool crc);
+struct sparse_file *sparse_file_import_auto(int fd, bool crc, bool verbose);
 
 /** sparse_file_resparse - rechunk an existing sparse file into smaller files
  *
diff --git a/libsparse/sparse.c b/libsparse/sparse.c
index baa30cd..311678a 100644
--- a/libsparse/sparse.c
+++ b/libsparse/sparse.c
@@ -101,26 +101,32 @@
 	return chunks;
 }
 
-static void sparse_file_write_block(struct output_file *out,
+static int sparse_file_write_block(struct output_file *out,
 		struct backed_block *bb)
 {
+	int ret = -EINVAL;
+
 	switch (backed_block_type(bb)) {
 	case BACKED_BLOCK_DATA:
-		write_data_chunk(out, backed_block_len(bb), backed_block_data(bb));
+		ret = write_data_chunk(out, backed_block_len(bb), backed_block_data(bb));
 		break;
 	case BACKED_BLOCK_FILE:
-		write_file_chunk(out, backed_block_len(bb),
-				backed_block_filename(bb), backed_block_file_offset(bb));
+		ret = write_file_chunk(out, backed_block_len(bb),
+				       backed_block_filename(bb),
+				       backed_block_file_offset(bb));
 		break;
 	case BACKED_BLOCK_FD:
-		write_fd_chunk(out, backed_block_len(bb),
-				backed_block_fd(bb), backed_block_file_offset(bb));
+		ret = write_fd_chunk(out, backed_block_len(bb),
+				     backed_block_fd(bb),
+				     backed_block_file_offset(bb));
 		break;
 	case BACKED_BLOCK_FILL:
-		write_fill_chunk(out, backed_block_len(bb),
-				backed_block_fill_val(bb));
+		ret = write_fill_chunk(out, backed_block_len(bb),
+				       backed_block_fill_val(bb));
 		break;
 	}
+
+	return ret;
 }
 
 static int write_all_blocks(struct sparse_file *s, struct output_file *out)
@@ -128,6 +134,7 @@
 	struct backed_block *bb;
 	unsigned int last_block = 0;
 	int64_t pad;
+	int ret = 0;
 
 	for (bb = backed_block_iter_new(s->backed_block_list); bb;
 			bb = backed_block_iter_next(bb)) {
@@ -135,7 +142,9 @@
 			unsigned int blocks = backed_block_block(bb) - last_block;
 			write_skip_chunk(out, (int64_t)blocks * s->block_size);
 		}
-		sparse_file_write_block(out, bb);
+		ret = sparse_file_write_block(out, bb);
+		if (ret)
+			return ret;
 		last_block = backed_block_block(bb) +
 				DIV_ROUND_UP(backed_block_len(bb), s->block_size);
 	}
@@ -229,13 +238,15 @@
 	struct backed_block *last_bb = NULL;
 	struct backed_block *bb;
 	struct backed_block *start;
+	unsigned int last_block = 0;
 	int64_t file_len = 0;
+	int ret;
 
 	/*
-	 * overhead is sparse file header, initial skip chunk, split chunk, end
-	 * skip chunk, and crc chunk.
+	 * overhead is sparse file header, the potential end skip
+	 * chunk and crc chunk.
 	 */
-	int overhead = sizeof(sparse_header_t) + 4 * sizeof(chunk_header_t) +
+	int overhead = sizeof(sparse_header_t) + 2 * sizeof(chunk_header_t) +
 			sizeof(uint32_t);
 	len -= overhead;
 
@@ -248,28 +259,39 @@
 
 	for (bb = start; bb; bb = backed_block_iter_next(bb)) {
 		count = 0;
+		if (backed_block_block(bb) > last_block)
+			count += sizeof(chunk_header_t);
+		last_block = backed_block_block(bb) +
+				DIV_ROUND_UP(backed_block_len(bb), to->block_size);
+
 		/* will call out_counter_write to update count */
-		sparse_file_write_block(out_counter, bb);
+		ret = sparse_file_write_block(out_counter, bb);
+		if (ret) {
+			bb = NULL;
+			goto out;
+		}
 		if (file_len + count > len) {
 			/*
 			 * If the remaining available size is more than 1/8th of the
 			 * requested size, split the chunk.  Results in sparse files that
 			 * are at least 7/8ths of the requested size
 			 */
+			file_len += sizeof(chunk_header_t);
 			if (!last_bb || (len - file_len > (len / 8))) {
 				backed_block_split(from->backed_block_list, bb, len - file_len);
 				last_bb = bb;
 			}
-			goto out;
+			goto move;
 		}
 		file_len += count;
 		last_bb = bb;
 	}
 
-out:
+move:
 	backed_block_list_move(from->backed_block_list,
 		to->backed_block_list, start, last_bb);
 
+out:
 	output_file_close(out_counter);
 
 	return bb;
diff --git a/libsparse/sparse_read.c b/libsparse/sparse_read.c
index 8e188e9..9b10293 100644
--- a/libsparse/sparse_read.c
+++ b/libsparse/sparse_read.c
@@ -472,13 +472,13 @@
 	return s;
 }
 
-struct sparse_file *sparse_file_import_auto(int fd, bool crc)
+struct sparse_file *sparse_file_import_auto(int fd, bool crc, bool verbose)
 {
 	struct sparse_file *s;
 	int64_t len;
 	int ret;
 
-	s = sparse_file_import(fd, true, crc);
+	s = sparse_file_import(fd, verbose, crc);
 	if (s) {
 		return s;
 	}
diff --git a/libsuspend/autosuspend_autosleep.c b/libsuspend/autosuspend_autosleep.c
index 5451615..7262cc7 100644
--- a/libsuspend/autosuspend_autosleep.c
+++ b/libsuspend/autosuspend_autosleep.c
@@ -40,7 +40,7 @@
 
     ALOGV("autosuspend_autosleep_enable\n");
 
-    ret = write(autosleep_fd, sleep_state, strlen(sleep_state));
+    ret = TEMP_FAILURE_RETRY(write(autosleep_fd, sleep_state, strlen(sleep_state)));
     if (ret < 0) {
         strerror_r(errno, buf, sizeof(buf));
         ALOGE("Error writing to %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
@@ -62,7 +62,7 @@
 
     ALOGV("autosuspend_autosleep_disable\n");
 
-    ret = write(autosleep_fd, on_state, strlen(on_state));
+    ret = TEMP_FAILURE_RETRY(write(autosleep_fd, on_state, strlen(on_state)));
     if (ret < 0) {
         strerror_r(errno, buf, sizeof(buf));
         ALOGE("Error writing to %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
@@ -84,10 +84,9 @@
 
 struct autosuspend_ops *autosuspend_autosleep_init(void)
 {
-    int ret;
     char buf[80];
 
-    autosleep_fd = open(SYS_POWER_AUTOSLEEP, O_WRONLY);
+    autosleep_fd = TEMP_FAILURE_RETRY(open(SYS_POWER_AUTOSLEEP, O_WRONLY));
     if (autosleep_fd < 0) {
         strerror_r(errno, buf, sizeof(buf));
         ALOGE("Error opening %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
diff --git a/libsuspend/autosuspend_earlysuspend.c b/libsuspend/autosuspend_earlysuspend.c
index 2bece4c..3793a69 100644
--- a/libsuspend/autosuspend_earlysuspend.c
+++ b/libsuspend/autosuspend_earlysuspend.c
@@ -49,11 +49,9 @@
 {
     int err = 0;
     char buf;
-    int fd = open(EARLYSUSPEND_WAIT_FOR_FB_WAKE, O_RDONLY, 0);
+    int fd = TEMP_FAILURE_RETRY(open(EARLYSUSPEND_WAIT_FOR_FB_WAKE, O_RDONLY, 0));
     // if the file doesn't exist, the error will be caught in read() below
-    do {
-        err = read(fd, &buf, 1);
-    } while (err < 0 && errno == EINTR);
+    err = TEMP_FAILURE_RETRY(read(fd, &buf, 1));
     ALOGE_IF(err < 0,
             "*** ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
     close(fd);
@@ -64,11 +62,9 @@
 {
     int err = 0;
     char buf;
-    int fd = open(EARLYSUSPEND_WAIT_FOR_FB_SLEEP, O_RDONLY, 0);
+    int fd = TEMP_FAILURE_RETRY(open(EARLYSUSPEND_WAIT_FOR_FB_SLEEP, O_RDONLY, 0));
     // if the file doesn't exist, the error will be caught in read() below
-    do {
-        err = read(fd, &buf, 1);
-    } while (err < 0 && errno == EINTR);
+    err = TEMP_FAILURE_RETRY(read(fd, &buf, 1));
     ALOGE_IF(err < 0,
             "*** ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
     close(fd);
@@ -134,7 +130,7 @@
 
     ALOGV("autosuspend_earlysuspend_disable\n");
 
-    ret = write(sPowerStatefd, pwr_state_on, strlen(pwr_state_on));
+    ret = TEMP_FAILURE_RETRY(write(sPowerStatefd, pwr_state_on, strlen(pwr_state_on)));
     if (ret < 0) {
         strerror_r(errno, buf, sizeof(buf));
         ALOGE("Error writing to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
@@ -195,7 +191,7 @@
     char buf[80];
     int ret;
 
-    sPowerStatefd = open(EARLYSUSPEND_SYS_POWER_STATE, O_RDWR);
+    sPowerStatefd = TEMP_FAILURE_RETRY(open(EARLYSUSPEND_SYS_POWER_STATE, O_RDWR));
 
     if (sPowerStatefd < 0) {
         strerror_r(errno, buf, sizeof(buf));
@@ -203,7 +199,7 @@
         return NULL;
     }
 
-    ret = write(sPowerStatefd, "on", 2);
+    ret = TEMP_FAILURE_RETRY(write(sPowerStatefd, "on", 2));
     if (ret < 0) {
         strerror_r(errno, buf, sizeof(buf));
         ALOGW("Error writing 'on' to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
diff --git a/libsuspend/autosuspend_wakeup_count.c b/libsuspend/autosuspend_wakeup_count.c
index 7483a8f..23a0290 100644
--- a/libsuspend/autosuspend_wakeup_count.c
+++ b/libsuspend/autosuspend_wakeup_count.c
@@ -19,6 +19,7 @@
 #include <pthread.h>
 #include <semaphore.h>
 #include <stddef.h>
+#include <stdbool.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -38,7 +39,7 @@
 static pthread_t suspend_thread;
 static sem_t suspend_lockout;
 static const char *sleep_state = "mem";
-static void (*wakeup_func)(void) = NULL;
+static void (*wakeup_func)(bool success) = NULL;
 
 static void *suspend_thread_func(void *arg __attribute__((unused)))
 {
@@ -46,12 +47,14 @@
     char wakeup_count[20];
     int wakeup_count_len;
     int ret;
+    bool success;
 
     while (1) {
         usleep(100000);
         ALOGV("%s: read wakeup_count\n", __func__);
         lseek(wakeup_count_fd, 0, SEEK_SET);
-        wakeup_count_len = read(wakeup_count_fd, wakeup_count, sizeof(wakeup_count));
+        wakeup_count_len = TEMP_FAILURE_RETRY(read(wakeup_count_fd, wakeup_count,
+                sizeof(wakeup_count)));
         if (wakeup_count_len < 0) {
             strerror_r(errno, buf, sizeof(buf));
             ALOGE("Error reading from %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf);
@@ -71,22 +74,21 @@
             continue;
         }
 
+        success = true;
         ALOGV("%s: write %*s to wakeup_count\n", __func__, wakeup_count_len, wakeup_count);
-        ret = write(wakeup_count_fd, wakeup_count, wakeup_count_len);
+        ret = TEMP_FAILURE_RETRY(write(wakeup_count_fd, wakeup_count, wakeup_count_len));
         if (ret < 0) {
             strerror_r(errno, buf, sizeof(buf));
             ALOGE("Error writing to %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf);
         } else {
             ALOGV("%s: write %s to %s\n", __func__, sleep_state, SYS_POWER_STATE);
-            ret = write(state_fd, sleep_state, strlen(sleep_state));
+            ret = TEMP_FAILURE_RETRY(write(state_fd, sleep_state, strlen(sleep_state)));
             if (ret < 0) {
-                strerror_r(errno, buf, sizeof(buf));
-                ALOGE("Error writing to %s: %s\n", SYS_POWER_STATE, buf);
-            } else {
-                void (*func)(void) = wakeup_func;
-                if (func != NULL) {
-                    (*func)();
-                }
+                success = false;
+            }
+            void (*func)(bool success) = wakeup_func;
+            if (func != NULL) {
+                (*func)(success);
             }
         }
 
@@ -138,7 +140,7 @@
     return ret;
 }
 
-void set_wakeup_callback(void (*func)(void))
+void set_wakeup_callback(void (*func)(bool success))
 {
     if (wakeup_func != NULL) {
         ALOGE("Duplicate wakeup callback applied, keeping original");
@@ -157,14 +159,14 @@
     int ret;
     char buf[80];
 
-    state_fd = open(SYS_POWER_STATE, O_RDWR);
+    state_fd = TEMP_FAILURE_RETRY(open(SYS_POWER_STATE, O_RDWR));
     if (state_fd < 0) {
         strerror_r(errno, buf, sizeof(buf));
         ALOGE("Error opening %s: %s\n", SYS_POWER_STATE, buf);
         goto err_open_state;
     }
 
-    wakeup_count_fd = open(SYS_POWER_WAKEUP_COUNT, O_RDWR);
+    wakeup_count_fd = TEMP_FAILURE_RETRY(open(SYS_POWER_WAKEUP_COUNT, O_RDWR));
     if (wakeup_count_fd < 0) {
         strerror_r(errno, buf, sizeof(buf));
         ALOGE("Error opening %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf);
diff --git a/libsuspend/include/suspend/autosuspend.h b/libsuspend/include/suspend/autosuspend.h
index 10e3d27..59188a8 100644
--- a/libsuspend/include/suspend/autosuspend.h
+++ b/libsuspend/include/suspend/autosuspend.h
@@ -18,6 +18,7 @@
 #define _LIBSUSPEND_AUTOSUSPEND_H_
 
 #include <sys/cdefs.h>
+#include <stdbool.h>
 
 __BEGIN_DECLS
 
@@ -46,9 +47,11 @@
 /*
  * set_wakeup_callback
  *
- * Set a function to be called each time the device wakes up from suspend.
+ * Set a function to be called each time the device returns from suspend.
+ * success is true if the suspend was sucessful and false if the suspend
+ * aborted due to some reason.
  */
-void set_wakeup_callback(void (*func)(void));
+void set_wakeup_callback(void (*func)(bool success));
 
 __END_DECLS
 
diff --git a/libsync/sync.c b/libsync/sync.c
index 4892866..d73bb11 100644
--- a/libsync/sync.c
+++ b/libsync/sync.c
@@ -17,6 +17,7 @@
  */
 
 #include <fcntl.h>
+#include <malloc.h>
 #include <stdint.h>
 #include <string.h>
 
diff --git a/libsync/tests/Android.mk b/libsync/tests/Android.mk
index ad20e50..8137c7a 100644
--- a/libsync/tests/Android.mk
+++ b/libsync/tests/Android.mk
@@ -17,10 +17,8 @@
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
-include external/libcxx/libcxx.mk
 LOCAL_CLANG := true
 LOCAL_MODULE := sync-unit-tests
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers -Wno-sign-compare
 LOCAL_SHARED_LIBRARIES += libsync
 LOCAL_STATIC_LIBRARIES += libgtest_main
diff --git a/libsysutils/Android.mk b/libsysutils/Android.mk
index 246f954..7bf53e3 100644
--- a/libsysutils/Android.mk
+++ b/libsysutils/Android.mk
@@ -1,5 +1,3 @@
-ifneq ($(BUILD_TINY_ANDROID),true)
-
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
@@ -16,12 +14,12 @@
 
 LOCAL_MODULE:= libsysutils
 
-LOCAL_C_INCLUDES :=
-
 LOCAL_CFLAGS := -Werror
 
-LOCAL_SHARED_LIBRARIES := libcutils liblog
+LOCAL_SHARED_LIBRARIES := \
+        libcutils \
+        liblog \
+        libnl
 
 include $(BUILD_SHARED_LIBRARY)
 
-endif
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 9d596ef..23dcd62 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -32,27 +32,23 @@
 #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>
+
 /* From kernel's net/netfilter/xt_quota2.c */
-const int QLOG_NL_EVENT  = 112;
+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>
 
-const int NetlinkEvent::NlActionUnknown = 0;
-const int NetlinkEvent::NlActionAdd = 1;
-const int NetlinkEvent::NlActionRemove = 2;
-const int NetlinkEvent::NlActionChange = 3;
-const int NetlinkEvent::NlActionLinkUp = 4;
-const int NetlinkEvent::NlActionLinkDown = 5;
-const int NetlinkEvent::NlActionAddressUpdated = 6;
-const int NetlinkEvent::NlActionAddressRemoved = 7;
-const int NetlinkEvent::NlActionRdnss = 8;
-const int NetlinkEvent::NlActionRouteUpdated = 9;
-const int NetlinkEvent::NlActionRouteRemoved = 10;
+#include <netlink/attr.h>
+#include <netlink/genl/genl.h>
+#include <netlink/handlers.h>
+#include <netlink/msg.h>
 
 NetlinkEvent::NetlinkEvent() {
-    mAction = NlActionUnknown;
+    mAction = Action::kUnknown;
     memset(mParams, 0, sizeof(mParams));
     mPath = NULL;
     mSubsystem = NULL;
@@ -95,7 +91,8 @@
         NL_EVENT_RTM_NAME(RTM_NEWROUTE);
         NL_EVENT_RTM_NAME(RTM_DELROUTE);
         NL_EVENT_RTM_NAME(RTM_NEWNDUSEROPT);
-        NL_EVENT_RTM_NAME(QLOG_NL_EVENT);
+        NL_EVENT_RTM_NAME(LOCAL_QLOG_NL_EVENT);
+        NL_EVENT_RTM_NAME(LOCAL_NFLOG_PACKET);
         default:
             return NULL;
     }
@@ -145,8 +142,8 @@
         switch(rta->rta_type) {
             case IFLA_IFNAME:
                 asprintf(&mParams[0], "INTERFACE=%s", (char *) RTA_DATA(rta));
-                mAction = (ifi->ifi_flags & IFF_LOWER_UP) ?  NlActionLinkUp :
-                                                             NlActionLinkDown;
+                mAction = (ifi->ifi_flags & IFF_LOWER_UP) ? Action::kLinkUp :
+                                                            Action::kLinkDown;
                 mSubsystem = strdup("net");
                 return true;
         }
@@ -235,8 +232,8 @@
     }
 
     // Fill in netlink event information.
-    mAction = (type == RTM_NEWADDR) ? NlActionAddressUpdated :
-                                      NlActionAddressRemoved;
+    mAction = (type == RTM_NEWADDR) ? Action::kAddressUpdated :
+                                      Action::kAddressRemoved;
     mSubsystem = strdup("net");
     asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr,
              ifaddr->ifa_prefixlen);
@@ -267,7 +264,42 @@
     asprintf(&mParams[0], "ALERT_NAME=%s", pm->prefix);
     asprintf(&mParams[1], "INTERFACE=%s", devname);
     mSubsystem = strdup("qlog");
-    mAction = NlActionChange;
+    mAction = Action::kChange;
+    return true;
+}
+
+/*
+ * Parse a LOCAL_NFLOG_PACKET message.
+ */
+bool NetlinkEvent::parseNfPacketMessage(struct nlmsghdr *nh) {
+    int uid = -1;
+    int len = 0;
+    char* raw = NULL;
+
+    struct nlattr *uid_attr = nlmsg_find_attr(nh, sizeof(struct genlmsghdr), NFULA_UID);
+    if (uid_attr) {
+        uid = ntohl(nla_get_u32(uid_attr));
+    }
+
+    struct nlattr *payload = nlmsg_find_attr(nh, sizeof(struct genlmsghdr), NFULA_PAYLOAD);
+    if (payload) {
+        /* First 256 bytes is plenty */
+        len = nla_len(payload);
+        if (len > 256) len = 256;
+        raw = (char*) nla_data(payload);
+    }
+
+    char* hex = (char*) calloc(1, 5 + (len * 2));
+    strcpy(hex, "HEX=");
+    for (int i = 0; i < len; i++) {
+        hex[4 + (i * 2)] = "0123456789abcdef"[(raw[i] >> 4) & 0xf];
+        hex[5 + (i * 2)] = "0123456789abcdef"[raw[i] & 0xf];
+    }
+
+    asprintf(&mParams[0], "UID=%d", uid);
+    mParams[1] = hex;
+    mSubsystem = strdup("strict");
+    mAction = Action::kChange;
     return true;
 }
 
@@ -353,8 +385,8 @@
         return false;
 
     // Fill in netlink event information.
-    mAction = (type == RTM_NEWROUTE) ? NlActionRouteUpdated :
-                                       NlActionRouteRemoved;
+    mAction = (type == RTM_NEWROUTE) ? Action::kRouteUpdated :
+                                       Action::kRouteRemoved;
     mSubsystem = strdup("net");
     asprintf(&mParams[0], "ROUTE=%s/%d", dst, prefixLength);
     asprintf(&mParams[1], "GATEWAY=%s", (*gw) ? gw : "");
@@ -423,25 +455,27 @@
             SLOGE("Invalid optlen %d for RDNSS option\n", optlen);
             return false;
         }
-        int numaddrs = (optlen - 1) / 2;
+        const int numaddrs = (optlen - 1) / 2;
 
         // Find the lifetime.
         struct nd_opt_rdnss *rndss_opt = (struct nd_opt_rdnss *) opthdr;
-        uint32_t lifetime = ntohl(rndss_opt->nd_opt_rdnss_lifetime);
+        const uint32_t lifetime = ntohl(rndss_opt->nd_opt_rdnss_lifetime);
 
         // Construct "SERVERS=<comma-separated string of DNS addresses>".
-        // Reserve (INET6_ADDRSTRLEN + 1) chars for each address: all but the
-        // the last address are followed by ','; the last is followed by '\0'.
         static const char kServerTag[] = "SERVERS=";
-        static const int kTagLength = sizeof(kServerTag) - 1;
-        int bufsize = kTagLength + numaddrs * (INET6_ADDRSTRLEN + 1);
+        static const size_t kTagLength = strlen(kServerTag);
+        // Reserve sufficient space for an IPv6 link-local address: all but the
+        // last address are followed by ','; the last is followed by '\0'.
+        static const size_t kMaxSingleAddressLength =
+                INET6_ADDRSTRLEN + strlen("%") + IFNAMSIZ + strlen(",");
+        const size_t bufsize = kTagLength + numaddrs * kMaxSingleAddressLength;
         char *buf = (char *) malloc(bufsize);
         if (!buf) {
             SLOGE("RDNSS option: out of memory\n");
             return false;
         }
         strcpy(buf, kServerTag);
-        int pos = kTagLength;
+        size_t pos = kTagLength;
 
         struct in6_addr *addrs = (struct in6_addr *) (rndss_opt + 1);
         for (int i = 0; i < numaddrs; i++) {
@@ -450,10 +484,14 @@
             }
             inet_ntop(AF_INET6, addrs + i, buf + pos, bufsize - pos);
             pos += strlen(buf + pos);
+            if (IN6_IS_ADDR_LINKLOCAL(addrs + i)) {
+                buf[pos++] = '%';
+                pos += strlcpy(buf + pos, ifname, bufsize - pos);
+            }
         }
         buf[pos] = '\0';
 
-        mAction = NlActionRdnss;
+        mAction = Action::kRdnss;
         mSubsystem = strdup("net");
         asprintf(&mParams[0], "INTERFACE=%s", ifname);
         asprintf(&mParams[1], "LIFETIME=%u", lifetime);
@@ -478,7 +516,7 @@
  * TODO: consider only ever looking at the first message.
  */
 bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) {
-    const struct nlmsghdr *nh;
+    struct nlmsghdr *nh;
 
     for (nh = (struct nlmsghdr *) buffer;
          NLMSG_OK(nh, (unsigned) size) && (nh->nlmsg_type != NLMSG_DONE);
@@ -493,7 +531,7 @@
             if (parseIfInfoMessage(nh))
                 return true;
 
-        } else if (nh->nlmsg_type == QLOG_NL_EVENT) {
+        } else if (nh->nlmsg_type == LOCAL_QLOG_NL_EVENT) {
             if (parseUlogPacketMessage(nh))
                 return true;
 
@@ -511,6 +549,10 @@
             if (parseNdUserOptMessage(nh))
                 return true;
 
+        } else if (nh->nlmsg_type == LOCAL_NFLOG_PACKET) {
+            if (parseNfPacketMessage(nh))
+                return true;
+
         }
     }
 
@@ -569,11 +611,11 @@
             const char* a;
             if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) {
                 if (!strcmp(a, "add"))
-                    mAction = NlActionAdd;
+                    mAction = Action::kAdd;
                 else if (!strcmp(a, "remove"))
-                    mAction = NlActionRemove;
+                    mAction = Action::kRemove;
                 else if (!strcmp(a, "change"))
-                    mAction = NlActionChange;
+                    mAction = Action::kChange;
             } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) {
                 mSeq = atoi(a);
             } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) {
@@ -588,7 +630,8 @@
 }
 
 bool NetlinkEvent::decode(char *buffer, int size, int format) {
-    if (format == NetlinkListener::NETLINK_FORMAT_BINARY) {
+    if (format == NetlinkListener::NETLINK_FORMAT_BINARY
+            || format == NetlinkListener::NETLINK_FORMAT_BINARY_UNICAST) {
         return parseBinaryNetlinkMessage(buffer, size);
     } else {
         return parseAsciiNetlinkMessage(buffer, size);
diff --git a/libsysutils/src/NetlinkListener.cpp b/libsysutils/src/NetlinkListener.cpp
index 81c5cc2..637aa1e 100644
--- a/libsysutils/src/NetlinkListener.cpp
+++ b/libsysutils/src/NetlinkListener.cpp
@@ -47,8 +47,13 @@
     ssize_t count;
     uid_t uid = -1;
 
-    count = TEMP_FAILURE_RETRY(uevent_kernel_multicast_uid_recv(
-                                       socket, mBuffer, sizeof(mBuffer), &uid));
+    bool require_group = true;
+    if (mFormat == NETLINK_FORMAT_BINARY_UNICAST) {
+        require_group = false;
+    }
+
+    count = TEMP_FAILURE_RETRY(uevent_kernel_recv(socket,
+            mBuffer, sizeof(mBuffer), require_group, &uid));
     if (count < 0) {
         if (uid > 0)
             LOG_EVENT_INT(65537, uid);
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
index d3ce8f5..bb9b6a1 100644
--- a/libsysutils/src/SocketClient.cpp
+++ b/libsysutils/src/SocketClient.cpp
@@ -1,5 +1,6 @@
 #include <alloca.h>
 #include <errno.h>
+#include <malloc.h>
 #include <pthread.h>
 #include <signal.h>
 #include <string.h>
@@ -220,7 +221,9 @@
 
     sigaction(SIGPIPE, &old_action, &new_action);
 
-    errno = e;
+    if (e != 0) {
+        errno = e;
+    }
     return ret;
 }
 
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 527a6a0..3011ed7 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -86,6 +86,7 @@
             return -1;
         }
         SLOGV("got mSock = %d for %s", mSock, mSocketName);
+        fcntl(mSock, F_SETFD, FD_CLOEXEC);
     }
 
     if (mListen && listen(mSock, backlog) < 0) {
@@ -212,6 +213,7 @@
                 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/usbhost.c b/libusbhost/usbhost.c
index 684f401..b8e3215 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -56,6 +56,9 @@
 #define USB_FS_ID_SCANNER   USB_FS_DIR "/%d/%d"
 #define USB_FS_ID_FORMAT    USB_FS_DIR "/%03d/%03d"
 
+// Some devices fail to send string descriptors if we attempt reading > 255 bytes
+#define MAX_STRING_DESCRIPTOR_LENGTH    255
+
 // From drivers/usb/core/devio.c
 // I don't know why this isn't in a kernel header
 #define MAX_USBFS_BUFFER_SIZE   16384
@@ -449,8 +452,8 @@
 char* usb_device_get_string(struct usb_device *device, int id)
 {
     char string[256];
-    __u16 buffer[128];
-    __u16 languages[128];
+    __u16 buffer[MAX_STRING_DESCRIPTOR_LENGTH / sizeof(__u16)];
+    __u16 languages[MAX_STRING_DESCRIPTOR_LENGTH / sizeof(__u16)];
     int i, result;
     int languageCount = 0;
 
@@ -498,6 +501,12 @@
     return usb_device_get_string(device, desc->iProduct);
 }
 
+int usb_device_get_version(struct usb_device *device)
+{
+    struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
+    return desc->bcdUSB;
+}
+
 char* usb_device_get_serial(struct usb_device *device)
 {
     struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
diff --git a/libutils/Android.mk b/libutils/Android.mk
index 035846b..23a5c59 100644
--- a/libutils/Android.mk
+++ b/libutils/Android.mk
@@ -14,16 +14,11 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-# libutils is a little unique: It's built twice, once for the host
-# and once for the device.
-
 commonSources:= \
 	BasicHashtable.cpp \
-	BlobCache.cpp \
 	CallStack.cpp \
 	FileMap.cpp \
 	JenkinsHash.cpp \
-	LinearAllocator.cpp \
 	LinearTransform.cpp \
 	Log.cpp \
 	NativeHandle.cpp \
@@ -42,7 +37,7 @@
 	Tokenizer.cpp \
 	Unicode.cpp \
 	VectorImpl.cpp \
-	misc.cpp
+	misc.cpp \
 
 host_commonCflags := -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS) -Werror
 
@@ -53,13 +48,6 @@
 endif
 endif
 
-host_commonLdlibs :=
-
-ifeq ($(TARGET_OS),linux)
-host_commonLdlibs += -lrt -ldl
-endif
-
-
 # For the host
 # =====================================================
 include $(CLEAR_VARS)
@@ -67,6 +55,9 @@
 ifeq ($(HOST_OS), linux)
 LOCAL_SRC_FILES += Looper.cpp
 endif
+ifeq ($(HOST_OS),darwin)
+LOCAL_CFLAGS += -Wno-unused-parameter
+endif
 LOCAL_MODULE:= libutils
 LOCAL_STATIC_LIBRARIES := liblog
 LOCAL_CFLAGS += $(host_commonCflags)
@@ -83,6 +74,7 @@
 # we have the common sources, plus some device-specific stuff
 LOCAL_SRC_FILES:= \
 	$(commonSources) \
+	BlobCache.cpp \
 	Looper.cpp \
 	Trace.cpp
 
@@ -91,20 +83,15 @@
 endif
 LOCAL_CFLAGS += -Werror
 
-LOCAL_C_INCLUDES += \
-		bionic/libc \
-		external/zlib
-
 LOCAL_STATIC_LIBRARIES := \
-	libcutils
+	libcutils \
+	libc
 
 LOCAL_SHARED_LIBRARIES := \
         libbacktrace \
         liblog \
         libdl
 
-include external/stlport/libstlport.mk
-
 LOCAL_MODULE:= libutils
 LOCAL_C_INCLUDES += external/safe-iop/include
 include $(BUILD_STATIC_LIBRARY)
@@ -122,12 +109,11 @@
 LOCAL_CFLAGS := -Werror
 LOCAL_C_INCLUDES += external/safe-iop/include
 
-include external/stlport/libstlport.mk
-
 include $(BUILD_SHARED_LIBRARY)
 
 # Include subdirectory makefiles
 # ============================================================
+
 include $(CLEAR_VARS)
 LOCAL_MODULE := SharedBufferTest
 LOCAL_STATIC_LIBRARIES := libutils libcutils
@@ -142,8 +128,5 @@
 LOCAL_SRC_FILES := SharedBufferTest.cpp
 include $(BUILD_HOST_NATIVE_TEST)
 
-# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
-# team really wants is to build the stuff defined by this makefile.
-ifeq (,$(ONE_SHOT_MAKEFILE))
+# Build the tests in the tests/ subdirectory.
 include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/libutils/BlobCache.cpp b/libutils/BlobCache.cpp
index 0ea09cf..126995b 100644
--- a/libutils/BlobCache.cpp
+++ b/libutils/BlobCache.cpp
@@ -25,13 +25,15 @@
 #include <utils/Errors.h>
 #include <utils/Log.h>
 
+#include <cutils/properties.h>
+
 namespace android {
 
 // BlobCache::Header::mMagicNumber value
 static const uint32_t blobCacheMagic = ('_' << 24) + ('B' << 16) + ('b' << 8) + '$';
 
 // BlobCache::Header::mBlobCacheVersion value
-static const uint32_t blobCacheVersion = 2;
+static const uint32_t blobCacheVersion = 3;
 
 // BlobCache::Header::mDeviceVersion value
 static const uint32_t blobCacheDeviceVersion = 1;
@@ -165,7 +167,7 @@
 }
 
 size_t BlobCache::getFlattenedSize() const {
-    size_t size = align4(sizeof(Header));
+    size_t size = align4(sizeof(Header) + PROPERTY_VALUE_MAX);
     for (size_t i = 0; i < mCacheEntries.size(); i++) {
         const CacheEntry& e(mCacheEntries[i]);
         sp<Blob> keyBlob = e.getKey();
@@ -187,10 +189,13 @@
     header->mBlobCacheVersion = blobCacheVersion;
     header->mDeviceVersion = blobCacheDeviceVersion;
     header->mNumEntries = mCacheEntries.size();
+    char buildId[PROPERTY_VALUE_MAX];
+    header->mBuildIdLength = property_get("ro.build.id", buildId, "");
+    memcpy(header->mBuildId, buildId, header->mBuildIdLength);
 
     // Write cache entries
     uint8_t* byteBuffer = reinterpret_cast<uint8_t*>(buffer);
-    off_t byteOffset = align4(sizeof(Header));
+    off_t byteOffset = align4(sizeof(Header) + header->mBuildIdLength);
     for (size_t i = 0; i < mCacheEntries.size(); i++) {
         const CacheEntry& e(mCacheEntries[i]);
         sp<Blob> keyBlob = e.getKey();
@@ -239,15 +244,19 @@
         ALOGE("unflatten: bad magic number: %" PRIu32, header->mMagicNumber);
         return BAD_VALUE;
     }
+    char buildId[PROPERTY_VALUE_MAX];
+    int len = property_get("ro.build.id", buildId, "");
     if (header->mBlobCacheVersion != blobCacheVersion ||
-            header->mDeviceVersion != blobCacheDeviceVersion) {
+            header->mDeviceVersion != blobCacheDeviceVersion ||
+            len != header->mBuildIdLength ||
+            strncmp(buildId, header->mBuildId, len)) {
         // We treat version mismatches as an empty cache.
         return OK;
     }
 
     // Read cache entries
     const uint8_t* byteBuffer = reinterpret_cast<const uint8_t*>(buffer);
-    off_t byteOffset = align4(sizeof(Header));
+    off_t byteOffset = align4(sizeof(Header) + header->mBuildIdLength);
     size_t numEntries = header->mNumEntries;
     for (size_t i = 0; i < numEntries; i++) {
         if (byteOffset + sizeof(EntryHeader) > size) {
diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp
index f8d6bda..91e45d8 100644
--- a/libutils/FileMap.cpp
+++ b/libutils/FileMap.cpp
@@ -23,7 +23,7 @@
 #include <utils/FileMap.h>
 #include <utils/Log.h>
 
-#if defined(HAVE_WIN32_FILEMAP) && !defined(__USE_MINGW_ANSI_STDIO)
+#if defined(__MINGW32__) && !defined(__USE_MINGW_ANSI_STDIO)
 # define PRId32 "I32d"
 # define PRIx32 "I32x"
 # define PRId64 "I64d"
@@ -33,7 +33,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-#ifdef HAVE_POSIX_FILEMAP
+#if !defined(__MINGW32__)
 #include <sys/mman.h>
 #endif
 
@@ -48,7 +48,7 @@
 
 // Constructor.  Create an empty object.
 FileMap::FileMap(void)
-    : mRefCount(1), mFileName(NULL), mBasePtr(NULL), mBaseLength(0),
+    : mFileName(NULL), mBasePtr(NULL), mBaseLength(0),
       mDataPtr(NULL), mDataLength(0)
 {
 }
@@ -56,20 +56,10 @@
 // Destructor.
 FileMap::~FileMap(void)
 {
-    assert(mRefCount == 0);
-
-    //printf("+++ removing FileMap %p %zu\n", mDataPtr, mDataLength);
-
-    mRefCount = -100;       // help catch double-free
     if (mFileName != NULL) {
         free(mFileName);
     }
-#ifdef HAVE_POSIX_FILEMAP
-    if (mBasePtr && munmap(mBasePtr, mBaseLength) != 0) {
-        ALOGD("munmap(%p, %zu) failed\n", mBasePtr, mBaseLength);
-    }
-#endif
-#ifdef HAVE_WIN32_FILEMAP
+#if defined(__MINGW32__)
     if (mBasePtr && UnmapViewOfFile(mBasePtr) == 0) {
         ALOGD("UnmapViewOfFile(%p) failed, error = %" PRId32 "\n", mBasePtr,
               GetLastError() );
@@ -77,6 +67,10 @@
     if (mFileMapping != INVALID_HANDLE_VALUE) {
         CloseHandle(mFileMapping);
     }
+#else
+    if (mBasePtr && munmap(mBasePtr, mBaseLength) != 0) {
+        ALOGD("munmap(%p, %zu) failed\n", mBasePtr, mBaseLength);
+    }
 #endif
 }
 
@@ -90,7 +84,7 @@
 bool FileMap::create(const char* origFileName, int fd, off64_t offset, size_t length,
         bool readOnly)
 {
-#ifdef HAVE_WIN32_FILEMAP
+#if defined(__MINGW32__)
     int     adjust;
     off64_t adjOffset;
     size_t  adjLength;
@@ -128,35 +122,27 @@
         mFileMapping = INVALID_HANDLE_VALUE;
         return false;
     }
-#endif
-#ifdef HAVE_POSIX_FILEMAP
+#else // !defined(__MINGW32__)
     int     prot, flags, adjust;
     off64_t adjOffset;
     size_t  adjLength;
 
     void* ptr;
 
-    assert(mRefCount == 1);
     assert(fd >= 0);
     assert(offset >= 0);
     assert(length > 0);
 
     // init on first use
     if (mPageSize == -1) {
-#if NOT_USING_KLIBC
         mPageSize = sysconf(_SC_PAGESIZE);
         if (mPageSize == -1) {
             ALOGE("could not get _SC_PAGESIZE\n");
             return false;
         }
-#else
-        // this holds for Linux, Darwin, Cygwin, and doesn't pain the ARM
-        mPageSize = 4096;
-#endif
     }
 
-    adjust   = offset % mPageSize;
-try_again:
+    adjust = offset % mPageSize;
     adjOffset = offset - adjust;
     adjLength = length + adjust;
 
@@ -167,19 +153,12 @@
 
     ptr = mmap(NULL, adjLength, prot, flags, fd, adjOffset);
     if (ptr == MAP_FAILED) {
-        // Cygwin does not seem to like file mapping files from an offset.
-        // So if we fail, try again with offset zero
-        if (adjOffset > 0) {
-            adjust = offset;
-            goto try_again;
-        }
-
         ALOGE("mmap(%lld,%zu) failed: %s\n",
             (long long)adjOffset, adjLength, strerror(errno));
         return false;
     }
     mBasePtr = ptr;
-#endif // HAVE_POSIX_FILEMAP
+#endif // !defined(__MINGW32__)
 
     mFileName = origFileName != NULL ? strdup(origFileName) : NULL;
     mBaseLength = adjLength;
@@ -196,9 +175,9 @@
 }
 
 // Provide guidance to the system.
+#if !defined(_WIN32)
 int FileMap::advise(MapAdvice advice)
 {
-#if HAVE_MADVISE
     int cc, sysAdvice;
 
     switch (advice) {
@@ -216,7 +195,11 @@
     if (cc != 0)
         ALOGW("madvise(%d) failed: %s\n", sysAdvice, strerror(errno));
     return cc;
-#else
-    return -1;
-#endif // HAVE_MADVISE
 }
+
+#else
+int FileMap::advise(MapAdvice /* advice */)
+{
+    return -1;
+}
+#endif
diff --git a/libutils/LinearAllocator.cpp b/libutils/LinearAllocator.cpp
deleted file mode 100644
index 8b90696..0000000
--- a/libutils/LinearAllocator.cpp
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define LOG_TAG "LinearAllocator"
-#define LOG_NDEBUG 1
-
-#include <stdlib.h>
-#include <utils/LinearAllocator.h>
-#include <utils/Log.h>
-
-
-// The ideal size of a page allocation (these need to be multiples of 8)
-#define INITIAL_PAGE_SIZE ((size_t)4096) // 4kb
-#define MAX_PAGE_SIZE ((size_t)131072) // 128kb
-
-// The maximum amount of wasted space we can have per page
-// Allocations exceeding this will have their own dedicated page
-// If this is too low, we will malloc too much
-// Too high, and we may waste too much space
-// Must be smaller than INITIAL_PAGE_SIZE
-#define MAX_WASTE_SIZE ((size_t)1024)
-
-#if ALIGN_DOUBLE
-#define ALIGN_SZ (sizeof(double))
-#else
-#define ALIGN_SZ (sizeof(int))
-#endif
-
-#define ALIGN(x) ((x + ALIGN_SZ - 1 ) & ~(ALIGN_SZ - 1))
-#define ALIGN_PTR(p) ((void*)(ALIGN((size_t)p)))
-
-#if LOG_NDEBUG
-#define ADD_ALLOCATION(size)
-#define RM_ALLOCATION(size)
-#else
-#include <utils/Thread.h>
-#include <utils/Timers.h>
-static size_t s_totalAllocations = 0;
-static nsecs_t s_nextLog = 0;
-static android::Mutex s_mutex;
-
-static void _logUsageLocked() {
-    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-    if (now > s_nextLog) {
-        s_nextLog = now + milliseconds_to_nanoseconds(10);
-        ALOGV("Total memory usage: %zu kb", s_totalAllocations / 1024);
-    }
-}
-
-static void _addAllocation(size_t size) {
-    android::AutoMutex lock(s_mutex);
-    s_totalAllocations += size;
-    _logUsageLocked();
-}
-
-#define ADD_ALLOCATION(size) _addAllocation(size);
-#define RM_ALLOCATION(size) _addAllocation(-size);
-#endif
-
-#define min(x,y) (((x) < (y)) ? (x) : (y))
-
-namespace android {
-
-class LinearAllocator::Page {
-public:
-    Page* next() { return mNextPage; }
-    void setNext(Page* next) { mNextPage = next; }
-
-    Page()
-        : mNextPage(0)
-    {}
-
-    void* operator new(size_t /*size*/, void* buf) { return buf; }
-
-    void* start() {
-        return (void*) (((size_t)this) + sizeof(Page));
-    }
-
-    void* end(int pageSize) {
-        return (void*) (((size_t)start()) + pageSize);
-    }
-
-private:
-    Page(const Page& /*other*/) {}
-    Page* mNextPage;
-};
-
-LinearAllocator::LinearAllocator()
-    : mPageSize(INITIAL_PAGE_SIZE)
-    , mMaxAllocSize(MAX_WASTE_SIZE)
-    , mNext(0)
-    , mCurrentPage(0)
-    , mPages(0)
-    , mTotalAllocated(0)
-    , mWastedSpace(0)
-    , mPageCount(0)
-    , mDedicatedPageCount(0) {}
-
-LinearAllocator::~LinearAllocator(void) {
-    Page* p = mPages;
-    while (p) {
-        Page* next = p->next();
-        p->~Page();
-        free(p);
-        RM_ALLOCATION(mPageSize);
-        p = next;
-    }
-}
-
-void* LinearAllocator::start(Page* p) {
-    return ALIGN_PTR(((size_t*)p) + sizeof(Page));
-}
-
-void* LinearAllocator::end(Page* p) {
-    return ((char*)p) + mPageSize;
-}
-
-bool LinearAllocator::fitsInCurrentPage(size_t size) {
-    return mNext && ((char*)mNext + size) <= end(mCurrentPage);
-}
-
-void LinearAllocator::ensureNext(size_t size) {
-    if (fitsInCurrentPage(size)) return;
-
-    if (mCurrentPage && mPageSize < MAX_PAGE_SIZE) {
-        mPageSize = min(MAX_PAGE_SIZE, mPageSize * 2);
-        mPageSize = ALIGN(mPageSize);
-    }
-    mWastedSpace += mPageSize;
-    Page* p = newPage(mPageSize);
-    if (mCurrentPage) {
-        mCurrentPage->setNext(p);
-    }
-    mCurrentPage = p;
-    if (!mPages) {
-        mPages = mCurrentPage;
-    }
-    mNext = start(mCurrentPage);
-}
-
-void* LinearAllocator::alloc(size_t size) {
-    size = ALIGN(size);
-    if (size > mMaxAllocSize && !fitsInCurrentPage(size)) {
-        ALOGV("Exceeded max size %zu > %zu", size, mMaxAllocSize);
-        // Allocation is too large, create a dedicated page for the allocation
-        Page* page = newPage(size);
-        mDedicatedPageCount++;
-        page->setNext(mPages);
-        mPages = page;
-        if (!mCurrentPage)
-            mCurrentPage = mPages;
-        return start(page);
-    }
-    ensureNext(size);
-    void* ptr = mNext;
-    mNext = ((char*)mNext) + size;
-    mWastedSpace -= size;
-    return ptr;
-}
-
-void LinearAllocator::rewindIfLastAlloc(void* ptr, size_t allocSize) {
-    // Don't bother rewinding across pages
-    allocSize = ALIGN(allocSize);
-    if (ptr >= start(mCurrentPage) && ptr < end(mCurrentPage)
-            && ptr == ((char*)mNext - allocSize)) {
-        mTotalAllocated -= allocSize;
-        mWastedSpace += allocSize;
-        mNext = ptr;
-    }
-}
-
-LinearAllocator::Page* LinearAllocator::newPage(size_t pageSize) {
-    pageSize = ALIGN(pageSize + sizeof(LinearAllocator::Page));
-    ADD_ALLOCATION(pageSize);
-    mTotalAllocated += pageSize;
-    mPageCount++;
-    void* buf = malloc(pageSize);
-    return new (buf) Page();
-}
-
-static const char* toSize(size_t value, float& result) {
-    if (value < 2000) {
-        result = value;
-        return "B";
-    }
-    if (value < 2000000) {
-        result = value / 1024.0f;
-        return "KB";
-    }
-    result = value / 1048576.0f;
-    return "MB";
-}
-
-void LinearAllocator::dumpMemoryStats(const char* prefix) {
-    float prettySize;
-    const char* prettySuffix;
-    prettySuffix = toSize(mTotalAllocated, prettySize);
-    ALOGD("%sTotal allocated: %.2f%s", prefix, prettySize, prettySuffix);
-    prettySuffix = toSize(mWastedSpace, prettySize);
-    ALOGD("%sWasted space: %.2f%s (%.1f%%)", prefix, prettySize, prettySuffix,
-          (float) mWastedSpace / (float) mTotalAllocated * 100.0f);
-    ALOGD("%sPages %zu (dedicated %zu)", prefix, mPageCount, mDedicatedPageCount);
-}
-
-}; // namespace android
diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp
index 9a2dd6c..5b0ff3a 100644
--- a/libutils/Looper.cpp
+++ b/libutils/Looper.cpp
@@ -20,6 +20,8 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <limits.h>
+#include <inttypes.h>
+#include <sys/eventfd.h>
 
 
 namespace android {
@@ -68,41 +70,20 @@
 
 Looper::Looper(bool allowNonCallbacks) :
         mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
-        mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
-    int wakeFds[2];
-    int result = pipe(wakeFds);
-    LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe.  errno=%d", errno);
+        mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false),
+        mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
+    mWakeEventFd = eventfd(0, EFD_NONBLOCK);
+    LOG_ALWAYS_FATAL_IF(mWakeEventFd < 0, "Could not make wake event fd.  errno=%d", errno);
 
-    mWakeReadPipeFd = wakeFds[0];
-    mWakeWritePipeFd = wakeFds[1];
-
-    result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
-    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking.  errno=%d",
-            errno);
-
-    result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
-    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking.  errno=%d",
-            errno);
-
-    mIdling = false;
-
-    // Allocate the epoll instance and register the wake pipe.
-    mEpollFd = epoll_create(EPOLL_SIZE_HINT);
-    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance.  errno=%d", errno);
-
-    struct epoll_event eventItem;
-    memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
-    eventItem.events = EPOLLIN;
-    eventItem.data.fd = mWakeReadPipeFd;
-    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
-    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance.  errno=%d",
-            errno);
+    AutoMutex _l(mLock);
+    rebuildEpollLocked();
 }
 
 Looper::~Looper() {
-    close(mWakeReadPipeFd);
-    close(mWakeWritePipeFd);
-    close(mEpollFd);
+    close(mWakeEventFd);
+    if (mEpollFd >= 0) {
+        close(mEpollFd);
+    }
 }
 
 void Looper::initTLSKey() {
@@ -156,6 +137,50 @@
     return mAllowNonCallbacks;
 }
 
+void Looper::rebuildEpollLocked() {
+    // Close old epoll instance if we have one.
+    if (mEpollFd >= 0) {
+#if DEBUG_CALLBACKS
+        ALOGD("%p ~ rebuildEpollLocked - rebuilding epoll set", this);
+#endif
+        close(mEpollFd);
+    }
+
+    // Allocate the new epoll instance and register the wake pipe.
+    mEpollFd = epoll_create(EPOLL_SIZE_HINT);
+    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance.  errno=%d", errno);
+
+    struct epoll_event eventItem;
+    memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
+    eventItem.events = EPOLLIN;
+    eventItem.data.fd = mWakeEventFd;
+    int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);
+    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake event fd to epoll instance.  errno=%d",
+            errno);
+
+    for (size_t i = 0; i < mRequests.size(); i++) {
+        const Request& request = mRequests.valueAt(i);
+        struct epoll_event eventItem;
+        request.initEventItem(&eventItem);
+
+        int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, request.fd, & eventItem);
+        if (epollResult < 0) {
+            ALOGE("Error adding epoll events for fd %d while rebuilding epoll set, errno=%d",
+                    request.fd, errno);
+        }
+    }
+}
+
+void Looper::scheduleEpollRebuildLocked() {
+    if (!mEpollRebuildRequired) {
+#if DEBUG_CALLBACKS
+        ALOGD("%p ~ scheduleEpollRebuildLocked - scheduling epoll set rebuild", this);
+#endif
+        mEpollRebuildRequired = true;
+        wake();
+    }
+}
+
 int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
     int result = 0;
     for (;;) {
@@ -206,7 +231,7 @@
             timeoutMillis = messageTimeoutMillis;
         }
 #if DEBUG_POLL_AND_WAKE
-        ALOGD("%p ~ pollOnce - next message in %lldns, adjusted timeout: timeoutMillis=%d",
+        ALOGD("%p ~ pollOnce - next message in %" PRId64 "ns, adjusted timeout: timeoutMillis=%d",
                 this, mNextMessageUptime - now, timeoutMillis);
 #endif
     }
@@ -217,17 +242,24 @@
     mResponseIndex = 0;
 
     // We are about to idle.
-    mIdling = true;
+    mPolling = true;
 
     struct epoll_event eventItems[EPOLL_MAX_EVENTS];
     int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
 
     // No longer idling.
-    mIdling = false;
+    mPolling = false;
 
     // Acquire lock.
     mLock.lock();
 
+    // Rebuild epoll set if needed.
+    if (mEpollRebuildRequired) {
+        mEpollRebuildRequired = false;
+        rebuildEpollLocked();
+        goto Done;
+    }
+
     // Check for poll error.
     if (eventCount < 0) {
         if (errno == EINTR) {
@@ -255,11 +287,11 @@
     for (int i = 0; i < eventCount; i++) {
         int fd = eventItems[i].data.fd;
         uint32_t epollEvents = eventItems[i].events;
-        if (fd == mWakeReadPipeFd) {
+        if (fd == mWakeEventFd) {
             if (epollEvents & EPOLLIN) {
                 awoken();
             } else {
-                ALOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);
+                ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);
             }
         } else {
             ssize_t requestIndex = mRequests.indexOfKey(fd);
@@ -326,10 +358,14 @@
             ALOGD("%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p",
                     this, response.request.callback.get(), fd, events, data);
 #endif
+            // Invoke the callback.  Note that the file descriptor may be closed by
+            // the callback (and potentially even reused) before the function returns so
+            // we need to be a little careful when removing the file descriptor afterwards.
             int callbackResult = response.request.callback->handleEvent(fd, events, data);
             if (callbackResult == 0) {
-                removeFd(fd);
+                removeFd(fd, response.request.seq);
             }
+
             // Clear the callback reference in the response structure promptly because we
             // will not clear the response vector itself until the next poll.
             response.request.callback.clear();
@@ -370,12 +406,9 @@
     ALOGD("%p ~ wake", this);
 #endif
 
-    ssize_t nWrite;
-    do {
-        nWrite = write(mWakeWritePipeFd, "W", 1);
-    } while (nWrite == -1 && errno == EINTR);
-
-    if (nWrite != 1) {
+    uint64_t inc = 1;
+    ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
+    if (nWrite != sizeof(uint64_t)) {
         if (errno != EAGAIN) {
             ALOGW("Could not write wake signal, errno=%d", errno);
         }
@@ -387,11 +420,8 @@
     ALOGD("%p ~ awoken", this);
 #endif
 
-    char buffer[16];
-    ssize_t nRead;
-    do {
-        nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
-    } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
+    uint64_t counter;
+    TEMP_FAILURE_RETRY(read(mWakeEventFd, &counter, sizeof(uint64_t)));
 }
 
 void Looper::pushResponse(int events, const Request& request) {
@@ -425,23 +455,20 @@
         ident = POLL_CALLBACK;
     }
 
-    int epollEvents = 0;
-    if (events & EVENT_INPUT) epollEvents |= EPOLLIN;
-    if (events & EVENT_OUTPUT) epollEvents |= EPOLLOUT;
-
     { // acquire lock
         AutoMutex _l(mLock);
 
         Request request;
         request.fd = fd;
         request.ident = ident;
+        request.events = events;
+        request.seq = mNextRequestSeq++;
         request.callback = callback;
         request.data = data;
+        if (mNextRequestSeq == -1) mNextRequestSeq = 0; // reserve sequence number -1
 
         struct epoll_event eventItem;
-        memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
-        eventItem.events = epollEvents;
-        eventItem.data.fd = fd;
+        request.initEventItem(&eventItem);
 
         ssize_t requestIndex = mRequests.indexOfKey(fd);
         if (requestIndex < 0) {
@@ -454,8 +481,36 @@
         } else {
             int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
             if (epollResult < 0) {
-                ALOGE("Error modifying epoll events for fd %d, errno=%d", fd, errno);
-                return -1;
+                if (errno == ENOENT) {
+                    // Tolerate ENOENT because it means that an older file descriptor was
+                    // closed before its callback was unregistered and meanwhile a new
+                    // file descriptor with the same number has been created and is now
+                    // being registered for the first time.  This error may occur naturally
+                    // when a callback has the side-effect of closing the file descriptor
+                    // before returning and unregistering itself.  Callback sequence number
+                    // checks further ensure that the race is benign.
+                    //
+                    // Unfortunately due to kernel limitations we need to rebuild the epoll
+                    // set from scratch because it may contain an old file handle that we are
+                    // now unable to remove since its file descriptor is no longer valid.
+                    // No such problem would have occurred if we were using the poll system
+                    // call instead, but that approach carries others disadvantages.
+#if DEBUG_CALLBACKS
+                    ALOGD("%p ~ addFd - EPOLL_CTL_MOD failed due to file descriptor "
+                            "being recycled, falling back on EPOLL_CTL_ADD, errno=%d",
+                            this, errno);
+#endif
+                    epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
+                    if (epollResult < 0) {
+                        ALOGE("Error modifying or adding epoll events for fd %d, errno=%d",
+                                fd, errno);
+                        return -1;
+                    }
+                    scheduleEpollRebuildLocked();
+                } else {
+                    ALOGE("Error modifying epoll events for fd %d, errno=%d", fd, errno);
+                    return -1;
+                }
             }
             mRequests.replaceValueAt(requestIndex, request);
         }
@@ -464,8 +519,12 @@
 }
 
 int Looper::removeFd(int fd) {
+    return removeFd(fd, -1);
+}
+
+int Looper::removeFd(int fd, int seq) {
 #if DEBUG_CALLBACKS
-    ALOGD("%p ~ removeFd - fd=%d", this, fd);
+    ALOGD("%p ~ removeFd - fd=%d, seq=%d", this, fd, seq);
 #endif
 
     { // acquire lock
@@ -475,13 +534,48 @@
             return 0;
         }
 
-        int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL);
-        if (epollResult < 0) {
-            ALOGE("Error removing epoll events for fd %d, errno=%d", fd, errno);
-            return -1;
+        // Check the sequence number if one was given.
+        if (seq != -1 && mRequests.valueAt(requestIndex).seq != seq) {
+#if DEBUG_CALLBACKS
+            ALOGD("%p ~ removeFd - sequence number mismatch, oldSeq=%d",
+                    this, mRequests.valueAt(requestIndex).seq);
+#endif
+            return 0;
         }
 
+        // Always remove the FD from the request map even if an error occurs while
+        // updating the epoll set so that we avoid accidentally leaking callbacks.
         mRequests.removeItemsAt(requestIndex);
+
+        int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL);
+        if (epollResult < 0) {
+            if (seq != -1 && (errno == EBADF || errno == ENOENT)) {
+                // Tolerate EBADF or ENOENT when the sequence number is known because it
+                // means that the file descriptor was closed before its callback was
+                // unregistered.  This error may occur naturally when a callback has the
+                // side-effect of closing the file descriptor before returning and
+                // unregistering itself.
+                //
+                // Unfortunately due to kernel limitations we need to rebuild the epoll
+                // set from scratch because it may contain an old file handle that we are
+                // now unable to remove since its file descriptor is no longer valid.
+                // No such problem would have occurred if we were using the poll system
+                // call instead, but that approach carries others disadvantages.
+#if DEBUG_CALLBACKS
+                ALOGD("%p ~ removeFd - EPOLL_CTL_DEL failed due to file descriptor "
+                        "being closed, errno=%d", this, errno);
+#endif
+                scheduleEpollRebuildLocked();
+            } else {
+                // Some other error occurred.  This is really weird because it means
+                // our list of callbacks got out of sync with the epoll set somehow.
+                // We defensively rebuild the epoll set to avoid getting spurious
+                // notifications with nowhere to go.
+                ALOGE("Error removing epoll events for fd %d, errno=%d", fd, errno);
+                scheduleEpollRebuildLocked();
+                return -1;
+            }
+        }
     } // release lock
     return 1;
 }
@@ -500,7 +594,7 @@
 void Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
         const Message& message) {
 #if DEBUG_CALLBACKS
-    ALOGD("%p ~ sendMessageAtTime - uptime=%lld, handler=%p, what=%d",
+    ALOGD("%p ~ sendMessageAtTime - uptime=%" PRId64 ", handler=%p, what=%d",
             this, uptime, handler.get(), message.what);
 #endif
 
@@ -566,8 +660,18 @@
     } // release lock
 }
 
-bool Looper::isIdling() const {
-    return mIdling;
+bool Looper::isPolling() const {
+    return mPolling;
+}
+
+void Looper::Request::initEventItem(struct epoll_event* eventItem) const {
+    int epollEvents = 0;
+    if (events & EVENT_INPUT) epollEvents |= EPOLLIN;
+    if (events & EVENT_OUTPUT) epollEvents |= EPOLLOUT;
+
+    memset(eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
+    eventItem->events = epollEvents;
+    eventItem->data.fd = fd;
 }
 
 } // namespace android
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 94b8231..75dfa29 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -431,7 +431,7 @@
             next = len;
         }
 
-        memcpy(buf + tail, buf + index + skip, next - index - skip);
+        memmove(buf + tail, buf + index + skip, next - index - skip);
         tail += next - index - skip;
         index = next;
     }
diff --git a/libutils/SystemClock.cpp b/libutils/SystemClock.cpp
index dbad581..ac3dd98 100644
--- a/libutils/SystemClock.cpp
+++ b/libutils/SystemClock.cpp
@@ -68,7 +68,7 @@
  */
 #define DEBUG_TIMESTAMP         0
 
-#if DEBUG_TIMESTAMP && defined(ARCH_ARM)
+#if DEBUG_TIMESTAMP && defined(__arm__)
 static inline void checkTimeStamps(int64_t timestamp,
                                    int64_t volatile *prevTimestampPtr,
                                    int volatile *prevMethodPtr,
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index b09d510..1e014c6 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -24,21 +24,18 @@
 #include <stdlib.h>
 #include <unistd.h>
 
-#if defined(HAVE_PTHREADS)
+#if !defined(_WIN32)
 # include <pthread.h>
 # include <sched.h>
 # include <sys/resource.h>
-#ifdef HAVE_ANDROID_OS
-# include <private/bionic_pthread.h>
-#endif
-#elif defined(HAVE_WIN32_THREADS)
+#else
 # include <windows.h>
 # include <stdint.h>
 # include <process.h>
 # define HAVE_CREATETHREAD  // Cygwin, vs. HAVE__BEGINTHREADEX for MinGW
 #endif
 
-#if defined(HAVE_PRCTL)
+#if defined(__linux__)
 #include <sys/prctl.h>
 #endif
 
@@ -62,7 +59,7 @@
 using namespace android;
 
 // ----------------------------------------------------------------------------
-#if defined(HAVE_PTHREADS)
+#if !defined(_WIN32)
 // ----------------------------------------------------------------------------
 
 /*
@@ -93,7 +90,7 @@
         } else {
             set_sched_policy(0, SP_FOREGROUND);
         }
-        
+
         if (name) {
             androidSetThreadName(name);
             free(name);
@@ -103,7 +100,7 @@
 };
 
 void androidSetThreadName(const char* name) {
-#if defined(HAVE_PRCTL)
+#if defined(__linux__)
     // Mac OS doesn't have this, and we build libutil for the host too
     int hasAt = 0;
     int hasDot = 0;
@@ -130,7 +127,7 @@
                                size_t threadStackSize,
                                android_thread_id_t *threadId)
 {
-    pthread_attr_t attr; 
+    pthread_attr_t attr;
     pthread_attr_init(&attr);
     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 
@@ -149,14 +146,14 @@
         t->entryFunction = entryFunction;
         t->userData = userData;
         entryFunction = (android_thread_func_t)&thread_data_t::trampoline;
-        userData = t;            
+        userData = t;
     }
 #endif
 
     if (threadStackSize) {
         pthread_attr_setstacksize(&attr, threadStackSize);
     }
-    
+
     errno = 0;
     pthread_t thread;
     int result = pthread_create(&thread, &attr,
@@ -191,7 +188,7 @@
 }
 
 // ----------------------------------------------------------------------------
-#elif defined(HAVE_WIN32_THREADS)
+#else // !defined(_WIN32)
 // ----------------------------------------------------------------------------
 
 /*
@@ -271,9 +268,7 @@
 }
 
 // ----------------------------------------------------------------------------
-#else
-#error "Threads not supported"
-#endif
+#endif // !defined(_WIN32)
 
 // ----------------------------------------------------------------------------
 
@@ -306,21 +301,12 @@
     gCreateThreadFn = func;
 }
 
-pid_t androidGetTid()
-{
-#ifdef HAVE_GETTID
-    return gettid();
-#else
-    return getpid();
-#endif
-}
-
 #ifdef HAVE_ANDROID_OS
 int androidSetThreadPriority(pid_t tid, int pri)
 {
     int rc = 0;
-    
-#if defined(HAVE_PTHREADS)
+
+#if !defined(_WIN32)
     int lasterr = 0;
 
     if (pri >= ANDROID_PRIORITY_BACKGROUND) {
@@ -339,12 +325,12 @@
         errno = lasterr;
     }
 #endif
-    
+
     return rc;
 }
 
 int androidGetThreadPriority(pid_t tid) {
-#if defined(HAVE_PTHREADS)
+#if !defined(_WIN32)
     return getpriority(PRIO_PROCESS, tid);
 #else
     return ANDROID_PRIORITY_NORMAL;
@@ -361,9 +347,9 @@
  * ===========================================================================
  */
 
-#if defined(HAVE_PTHREADS)
+#if !defined(_WIN32)
 // implemented as inlines in threads.h
-#elif defined(HAVE_WIN32_THREADS)
+#else
 
 Mutex::Mutex()
 {
@@ -425,9 +411,7 @@
     return (dwWaitResult == WAIT_OBJECT_0) ? 0 : -1;
 }
 
-#else
-#error "Somebody forgot to implement threads for this platform."
-#endif
+#endif // !defined(_WIN32)
 
 
 /*
@@ -436,9 +420,9 @@
  * ===========================================================================
  */
 
-#if defined(HAVE_PTHREADS)
+#if !defined(_WIN32)
 // implemented as inlines in threads.h
-#elif defined(HAVE_WIN32_THREADS)
+#else
 
 /*
  * Windows doesn't have a condition variable solution.  It's possible
@@ -486,7 +470,7 @@
         //printf("+++ wait: incr waitersCount to %d (tid=%ld)\n",
         //    condState->waitersCount, getThreadId());
         LeaveCriticalSection(&condState->waitersCountLock);
-    
+
         DWORD timeout = INFINITE;
         if (abstime) {
             nsecs_t reltime = *abstime - systemTime();
@@ -494,27 +478,27 @@
                 reltime = 0;
             timeout = reltime/1000000;
         }
-        
+
         // Atomically release the external mutex and wait on the semaphore.
         DWORD res =
             SignalObjectAndWait(hMutex, condState->sema, timeout, FALSE);
-    
+
         //printf("+++ wait: awake (tid=%ld)\n", getThreadId());
-    
+
         // Reacquire lock to avoid race conditions.
         EnterCriticalSection(&condState->waitersCountLock);
-    
+
         // No longer waiting.
         condState->waitersCount--;
-    
+
         // Check to see if we're the last waiter after a broadcast.
         bool lastWaiter = (condState->wasBroadcast && condState->waitersCount == 0);
-    
+
         //printf("+++ wait: lastWaiter=%d (wasBc=%d wc=%d)\n",
         //    lastWaiter, condState->wasBroadcast, condState->waitersCount);
-    
+
         LeaveCriticalSection(&condState->waitersCountLock);
-    
+
         // If we're the last waiter thread during this particular broadcast
         // then signal broadcast() that we're all awake.  It'll drop the
         // internal mutex.
@@ -530,11 +514,11 @@
             // Grab the internal mutex.
             WaitForSingleObject(condState->internalMutex, INFINITE);
         }
-    
+
         // Release the internal and grab the external.
         ReleaseMutex(condState->internalMutex);
         WaitForSingleObject(hMutex, INFINITE);
-    
+
         return res == WAIT_OBJECT_0 ? NO_ERROR : -1;
     }
 } WinCondition;
@@ -577,7 +561,7 @@
 {
     WinCondition* condState = (WinCondition*) mState;
     HANDLE hMutex = (HANDLE) mutex.mState;
-    
+
     return ((WinCondition*)mState)->wait(condState, hMutex, NULL);
 }
 
@@ -659,9 +643,7 @@
     ReleaseMutex(condState->internalMutex);
 }
 
-#else
-#error "condition variables not supported on this platform"
-#endif
+#endif // !defined(_WIN32)
 
 // ----------------------------------------------------------------------------
 
@@ -704,7 +686,7 @@
     mStatus = NO_ERROR;
     mExitPending = false;
     mThread = thread_id_t(-1);
-    
+
     // hold a strong reference on ourself
     mHoldSelf = this;
 
@@ -718,7 +700,7 @@
         res = androidCreateRawThreadEtc(_threadLoop,
                 this, name, priority, stack, &mThread);
     }
-    
+
     if (res == false) {
         mStatus = UNKNOWN_ERROR;   // something happened!
         mRunning = false;
@@ -727,7 +709,7 @@
 
         return UNKNOWN_ERROR;
     }
-    
+
     // Do not refer to mStatus here: The thread is already running (may, in fact
     // already have exited with a valid mStatus result). The NO_ERROR indication
     // here merely indicates successfully starting the thread and does not
@@ -791,14 +773,14 @@
             break;
         }
         }
-        
+
         // Release our strong reference, to let a chance to the thread
         // to die a peaceful death.
         strong.clear();
         // And immediately, re-acquire a strong reference for the next loop
         strong = weak.promote();
     } while(strong != 0);
-    
+
     return 0;
 }
 
@@ -819,7 +801,7 @@
 
         return WOULD_BLOCK;
     }
-    
+
     mExitPending = true;
 
     while (mRunning == true) {
@@ -864,7 +846,7 @@
     pid_t tid;
     if (mRunning) {
         pthread_t pthread = android_thread_id_t_to_pthread(mThread);
-        tid = __pthread_gettid(pthread);
+        tid = pthread_gettid_np(pthread);
     } else {
         ALOGW("Thread (this=%p): getTid() is undefined before run()", this);
         tid = -1;
diff --git a/libutils/Timers.cpp b/libutils/Timers.cpp
index 4687d4d..fb70e15 100644
--- a/libutils/Timers.cpp
+++ b/libutils/Timers.cpp
@@ -18,19 +18,10 @@
 // Timer functions.
 //
 #include <utils/Timers.h>
-#include <utils/Log.h>
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
+#include <limits.h>
 #include <sys/time.h>
 #include <time.h>
-#include <errno.h>
-#include <limits.h>
-
-#ifdef HAVE_WIN32_THREADS
-#include <windows.h>
-#endif
 
 #if defined(HAVE_ANDROID_OS)
 nsecs_t systemTime(int clock)
diff --git a/libutils/Tokenizer.cpp b/libutils/Tokenizer.cpp
index 7067533..610002f 100644
--- a/libutils/Tokenizer.cpp
+++ b/libutils/Tokenizer.cpp
@@ -43,9 +43,7 @@
 }
 
 Tokenizer::~Tokenizer() {
-    if (mFileMap) {
-        mFileMap->release();
-    }
+    delete mFileMap;
     if (mOwnBuffer) {
         delete[] mBuffer;
     }
@@ -74,7 +72,7 @@
                 fileMap->advise(FileMap::SEQUENTIAL);
                 buffer = static_cast<char*>(fileMap->getDataPtr());
             } else {
-                fileMap->release();
+                delete fileMap;
                 fileMap = NULL;
 
                 // Fall back to reading into a buffer since we can't mmap files in sysfs.
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index f5e28d4..2b5293e 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -25,17 +25,10 @@
 # undef  nhtos
 # undef  htons
 
-# ifdef HAVE_LITTLE_ENDIAN
-#  define ntohl(x)    ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) )
-#  define htonl(x)    ntohl(x)
-#  define ntohs(x)    ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) )
-#  define htons(x)    ntohs(x)
-# else
-#  define ntohl(x)    (x)
-#  define htonl(x)    (x)
-#  define ntohs(x)    (x)
-#  define htons(x)    (x)
-# endif
+# define ntohl(x)    ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) )
+# define htonl(x)    ntohl(x)
+# define ntohs(x)    ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) )
+# define htons(x)    ntohs(x)
 #else
 # include <netinet/in.h>
 #endif
@@ -48,8 +41,9 @@
 // Surrogates aren't valid for UTF-32 characters, so define some
 // constants that will let us screen them out.
 static const char32_t kUnicodeSurrogateHighStart  = 0x0000D800;
-static const char32_t kUnicodeSurrogateHighEnd    = 0x0000DBFF;
-static const char32_t kUnicodeSurrogateLowStart   = 0x0000DC00;
+// Unused, here for completeness:
+// static const char32_t kUnicodeSurrogateHighEnd = 0x0000DBFF;
+// static const char32_t kUnicodeSurrogateLowStart = 0x0000DC00;
 static const char32_t kUnicodeSurrogateLowEnd     = 0x0000DFFF;
 static const char32_t kUnicodeSurrogateStart      = kUnicodeSurrogateHighStart;
 static const char32_t kUnicodeSurrogateEnd        = kUnicodeSurrogateLowEnd;
diff --git a/libutils/misc.cpp b/libutils/misc.cpp
index 58eb499..ed1ba23 100644
--- a/libutils/misc.cpp
+++ b/libutils/misc.cpp
@@ -27,7 +27,7 @@
 #include <errno.h>
 #include <stdio.h>
 
-#if defined(HAVE_PTHREADS)
+#if !defined(_WIN32)
 # include <pthread.h>
 #endif
 
@@ -42,13 +42,13 @@
     int priority;
 };
 
-#if defined(HAVE_PTHREADS)
+#if !defined(_WIN32)
 static pthread_mutex_t gSyspropMutex = PTHREAD_MUTEX_INITIALIZER;
 static Vector<sysprop_change_callback_info>* gSyspropList = NULL;
 #endif
 
 void add_sysprop_change_callback(sysprop_change_callback cb, int priority) {
-#if defined(HAVE_PTHREADS)
+#if !defined(_WIN32)
     pthread_mutex_lock(&gSyspropMutex);
     if (gSyspropList == NULL) {
         gSyspropList = new Vector<sysprop_change_callback_info>();
@@ -72,7 +72,7 @@
 }
 
 void report_sysprop_change() {
-#if defined(HAVE_PTHREADS)
+#if !defined(_WIN32)
     pthread_mutex_lock(&gSyspropMutex);
     Vector<sysprop_change_callback_info> listeners;
     if (gSyspropList != NULL) {
diff --git a/libutils/tests/Android.mk b/libutils/tests/Android.mk
index caedaff..d4a45fd 100644
--- a/libutils/tests/Android.mk
+++ b/libutils/tests/Android.mk
@@ -1,9 +1,27 @@
-# Build the unit tests.
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
+#
+# 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.
-test_src_files := \
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libutils_tests
+
+LOCAL_SRC_FILES := \
     BasicHashtable_test.cpp \
     BlobCache_test.cpp \
     BitSet_test.cpp \
@@ -11,24 +29,20 @@
     LruCache_test.cpp \
     String8_test.cpp \
     Unicode_test.cpp \
-    Vector_test.cpp
+    Vector_test.cpp \
 
-shared_libraries := \
+LOCAL_SHARED_LIBRARIES := \
     libz \
     liblog \
     libcutils \
     libutils \
-    libstlport
 
-static_libraries := \
-    libgtest \
-    libgtest_main
+include $(BUILD_NATIVE_TEST)
 
-$(foreach file,$(test_src_files), \
-    $(eval include $(CLEAR_VARS)) \
-    $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
-    $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
-    $(eval LOCAL_SRC_FILES := $(file)) \
-    $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
-    $(eval 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/BasicHashtable_test.cpp b/libutils/tests/BasicHashtable_test.cpp
index a61b1e1..4b3a717 100644
--- a/libutils/tests/BasicHashtable_test.cpp
+++ b/libutils/tests/BasicHashtable_test.cpp
@@ -21,12 +21,12 @@
 #include <gtest/gtest.h>
 #include <unistd.h>
 
-namespace android {
+namespace {
 
 typedef int SimpleKey;
 typedef int SimpleValue;
-typedef key_value_pair_t<SimpleKey, SimpleValue> SimpleEntry;
-typedef BasicHashtable<SimpleKey, SimpleEntry> SimpleHashtable;
+typedef android::key_value_pair_t<SimpleKey, SimpleValue> SimpleEntry;
+typedef android::BasicHashtable<SimpleKey, SimpleEntry> SimpleHashtable;
 
 struct ComplexKey {
     int k;
@@ -56,10 +56,6 @@
 
 ssize_t ComplexKey::instanceCount = 0;
 
-template<> inline hash_t hash_type(const ComplexKey& value) {
-    return hash_type(value.k);
-}
-
 struct ComplexValue {
     int v;
 
@@ -80,9 +76,18 @@
 
 ssize_t ComplexValue::instanceCount = 0;
 
+} // namespace
+
+
+namespace android {
+
 typedef key_value_pair_t<ComplexKey, ComplexValue> ComplexEntry;
 typedef BasicHashtable<ComplexKey, ComplexEntry> ComplexHashtable;
 
+template<> inline hash_t hash_type(const ComplexKey& value) {
+    return hash_type(value.k);
+}
+
 class BasicHashtableTest : public testing::Test {
 protected:
     virtual void SetUp() {
diff --git a/libutils/tests/LruCache_test.cpp b/libutils/tests/LruCache_test.cpp
index bcbea32..6534211 100644
--- a/libutils/tests/LruCache_test.cpp
+++ b/libutils/tests/LruCache_test.cpp
@@ -20,7 +20,7 @@
 #include <cutils/log.h>
 #include <gtest/gtest.h>
 
-namespace android {
+namespace {
 
 typedef int SimpleKey;
 typedef const char* StringValue;
@@ -53,10 +53,6 @@
 
 ssize_t ComplexKey::instanceCount = 0;
 
-template<> inline hash_t hash_type(const ComplexKey& value) {
-    return hash_type(value.k);
-}
-
 struct ComplexValue {
     int v;
 
@@ -77,8 +73,17 @@
 
 ssize_t ComplexValue::instanceCount = 0;
 
+} // namespace
+
+
+namespace android {
+
 typedef LruCache<ComplexKey, ComplexValue> ComplexCache;
 
+template<> inline android::hash_t hash_type(const ComplexKey& value) {
+    return hash_type(value.k);
+}
+
 class EntryRemovedCallback : public OnEntryRemoved<SimpleKey, StringValue> {
 public:
     EntryRemovedCallback() : callbackCount(0), lastKey(-1), lastValue(NULL) { }
diff --git a/libutils/tests/String8_test.cpp b/libutils/tests/String8_test.cpp
index 7394163..7cd67d3 100644
--- a/libutils/tests/String8_test.cpp
+++ b/libutils/tests/String8_test.cpp
@@ -77,8 +77,7 @@
 TEST_F(String8Test, CorrectInvalidSurrogate) {
     // d841d8 is an invalid start for a surrogate pair. Make sure this is handled by ignoring the
     // first character in the pair and handling the rest correctly.
-    char16_t char16_arr[] = { 0xd841, 0xd841, 0xdc41, 0x0000 };
-    String16 string16(char16_arr);
+    String16 string16(u"\xd841\xd841\xdc41\x0000");
     String8 string8(string16);
 
     EXPECT_EQ(4U, string8.length());
@@ -87,7 +86,7 @@
 TEST_F(String8Test, CheckUtf32Conversion) {
     // Since bound checks were added, check the conversion can be done without fatal errors.
     // The utf8 lengths of these are chars are 1 + 2 + 3 + 4 = 10.
-    const char32_t string32[] = { 0x0000007f, 0x000007ff, 0x0000911, 0x0010fffe, 0 };
+    const char32_t string32[] = U"\x0000007f\x000007ff\x0000911\x0010fffe";
     String8 string8(string32);
     EXPECT_EQ(10U, string8.length());
 }
diff --git a/libutils/tests/Vector_test.cpp b/libutils/tests/Vector_test.cpp
index 8013187..96d3168 100644
--- a/libutils/tests/Vector_test.cpp
+++ b/libutils/tests/Vector_test.cpp
@@ -89,9 +89,9 @@
   vector.add(4);
 
   vector.setCapacity(8);
-  ASSERT_EQ(8U, vector.capacity());
+  ASSERT_EQ(8, vector.capacity());
   vector.setCapacity(2);
-  ASSERT_EQ(8U, vector.capacity());
+  ASSERT_EQ(8, vector.capacity());
 }
 
 // NOTE: All of the tests below are useless because of the "TODO" above.
diff --git a/libziparchive/Android.mk b/libziparchive/Android.mk
index d23a94f..a3087ee 100644
--- a/libziparchive/Android.mk
+++ b/libziparchive/Android.mk
@@ -14,32 +14,23 @@
 # limitations under the License.
 
 LOCAL_PATH := $(call my-dir)
+
+source_files := zip_archive.cc
+
 include $(CLEAR_VARS)
-
-source_files := \
-	zip_archive.h \
-	zip_archive.cc
-
-includes := external/zlib
-
 LOCAL_CPP_EXTENSION := .cc
 LOCAL_SRC_FILES := ${source_files}
-
 LOCAL_STATIC_LIBRARIES := libz
-LOCAL_SHARED_LIBRARIES := libutils
+LOCAL_SHARED_LIBRARIES := libutils libbase
 LOCAL_MODULE:= libziparchive
-
-LOCAL_C_INCLUDES += ${includes}
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror -Wall
+LOCAL_CPPFLAGS := -Wold-style-cast
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := libziparchive
 LOCAL_CPP_EXTENSION := .cc
 LOCAL_SRC_FILES := ${source_files}
-LOCAL_C_INCLUDES += ${includes}
-
-LOCAL_STATIC_LIBRARIES := libz libutils
+LOCAL_STATIC_LIBRARIES := libz libutils libbase
 LOCAL_MODULE:= libziparchive-host
 LOCAL_CFLAGS := -Werror
 ifneq ($(strip $(USE_MINGW)),)
@@ -49,29 +40,34 @@
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_SRC_FILES := ${source_files}
+LOCAL_STATIC_LIBRARIES := libz libutils
+LOCAL_SHARED_LIBRARIES := liblog libbase
+LOCAL_MODULE:= libziparchive-host
+LOCAL_CFLAGS := -Werror
+LOCAL_MULTILIB := both
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+# Tests.
+include $(CLEAR_VARS)
 LOCAL_MODULE := ziparchive-tests
 LOCAL_CPP_EXTENSION := .cc
-LOCAL_CFLAGS += \
-    -DGTEST_OS_LINUX_ANDROID \
-    -DGTEST_HAS_STD_STRING \
-    -Werror
-LOCAL_SRC_FILES := zip_archive_test.cc
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_STATIC_LIBRARIES := libziparchive libz libgtest libgtest_main libutils
+LOCAL_CFLAGS := -Werror
+LOCAL_SRC_FILES := zip_archive_test.cc entry_name_utils_test.cc
+LOCAL_SHARED_LIBRARIES := liblog libbase
+LOCAL_STATIC_LIBRARIES := libziparchive libz libutils
 include $(BUILD_NATIVE_TEST)
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := ziparchive-tests-host
 LOCAL_CPP_EXTENSION := .cc
 LOCAL_CFLAGS += \
-    -DGTEST_OS_LINUX \
-    -DGTEST_HAS_STD_STRING \
-    -Werror
-LOCAL_SRC_FILES := zip_archive_test.cc
-LOCAL_STATIC_LIBRARIES := libziparchive-host \
-	libz \
-	libgtest_host \
-	libgtest_main_host \
-	liblog \
-	libutils
+    -Werror \
+    -Wno-unnamed-type-template-args
+LOCAL_SRC_FILES := zip_archive_test.cc entry_name_utils_test.cc
+LOCAL_SHARED_LIBRARIES := libziparchive-host liblog libbase
+LOCAL_STATIC_LIBRARIES := \
+    libz \
+    libutils
 include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libziparchive/entry_name_utils-inl.h b/libziparchive/entry_name_utils-inl.h
new file mode 100644
index 0000000..ddbc286
--- /dev/null
+++ b/libziparchive/entry_name_utils-inl.h
@@ -0,0 +1,59 @@
+/*
+ * 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 LIBZIPARCHIVE_ENTRY_NAME_UTILS_INL_H_
+#define LIBZIPARCHIVE_ENTRY_NAME_UTILS_INL_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+// Check if |length| bytes at |entry_name| constitute a valid entry name.
+// Entry names must be valid UTF-8 and must not contain '0'.
+inline bool IsValidEntryName(const uint8_t* entry_name, const size_t length) {
+  for (size_t i = 0; i < length; ++i) {
+    const uint8_t byte = entry_name[i];
+    if (byte == 0) {
+      return false;
+    } else if ((byte & 0x80) == 0) {
+      // Single byte sequence.
+      continue;
+    } else if ((byte & 0xc0) == 0x80 || (byte & 0xfe) == 0xfe) {
+      // Invalid sequence.
+      return false;
+    } else {
+      // 2-5 byte sequences.
+      for (uint8_t first = byte << 1; first & 0x80; first <<= 1) {
+        ++i;
+
+        // Missing continuation byte..
+        if (i == length) {
+          return false;
+        }
+
+        // Invalid continuation byte.
+        const uint8_t continuation_byte = entry_name[i];
+        if ((continuation_byte & 0xc0) != 0x80) {
+          return false;
+        }
+      }
+    }
+  }
+
+  return true;
+}
+
+
+#endif  // LIBZIPARCHIVE_ENTRY_NAME_UTILS_INL_H_
diff --git a/libziparchive/entry_name_utils_test.cc b/libziparchive/entry_name_utils_test.cc
new file mode 100644
index 0000000..20715bb
--- /dev/null
+++ b/libziparchive/entry_name_utils_test.cc
@@ -0,0 +1,63 @@
+/*
+ * 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 "entry_name_utils-inl.h"
+
+#include <gtest/gtest.h>
+
+TEST(entry_name_utils, NullChars) {
+  // 'A', 'R', '\0', 'S', 'E'
+  const uint8_t zeroes[] = { 0x41, 0x52, 0x00, 0x53, 0x45 };
+  ASSERT_FALSE(IsValidEntryName(zeroes, sizeof(zeroes)));
+
+  const uint8_t zeroes_continuation_chars[] = { 0xc2, 0xa1, 0xc2, 0x00 };
+  ASSERT_FALSE(IsValidEntryName(zeroes_continuation_chars,
+                                sizeof(zeroes_continuation_chars)));
+}
+
+TEST(entry_name_utils, InvalidSequence) {
+  // 0xfe is an invalid start byte
+  const uint8_t invalid[] = { 0x41, 0xfe };
+  ASSERT_FALSE(IsValidEntryName(invalid, sizeof(invalid)));
+
+  // 0x91 is an invalid start byte (it's a valid continuation byte).
+  const uint8_t invalid2[] = { 0x41, 0x91 };
+  ASSERT_FALSE(IsValidEntryName(invalid2, sizeof(invalid2)));
+}
+
+TEST(entry_name_utils, TruncatedContinuation) {
+  // Malayalam script with truncated bytes. There should be 2 bytes
+  // after 0xe0
+  const uint8_t truncated[] = { 0xe0, 0xb4, 0x85, 0xe0, 0xb4 };
+  ASSERT_FALSE(IsValidEntryName(truncated, sizeof(truncated)));
+
+  // 0xc2 is the start of a 2 byte sequence that we've subsequently
+  // dropped.
+  const uint8_t truncated2[] = { 0xc2, 0xc2, 0xa1 };
+  ASSERT_FALSE(IsValidEntryName(truncated2, sizeof(truncated2)));
+}
+
+TEST(entry_name_utils, BadContinuation) {
+  // 0x41 is an invalid continuation char, since it's MSBs
+  // aren't "10..." (are 01).
+  const uint8_t bad[] = { 0xc2, 0xa1, 0xc2, 0x41 };
+  ASSERT_FALSE(IsValidEntryName(bad, sizeof(bad)));
+
+  // 0x41 is an invalid continuation char, since it's MSBs
+  // aren't "10..." (are 11).
+  const uint8_t bad2[] = { 0xc2, 0xa1, 0xc2, 0xfe };
+  ASSERT_FALSE(IsValidEntryName(bad2, sizeof(bad2)));
+}
diff --git a/libziparchive/testdata/declaredlength.zip b/libziparchive/testdata/declaredlength.zip
new file mode 100644
index 0000000..773380c
--- /dev/null
+++ b/libziparchive/testdata/declaredlength.zip
Binary files differ
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 54d866c..a17091f 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -23,29 +23,32 @@
 #include <fcntl.h>
 #include <inttypes.h>
 #include <limits.h>
-#include <log/log.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <utils/Compat.h>
-#include <utils/FileMap.h>
-#include <zlib.h>
 
-#include <JNIHelp.h>  // TEMP_FAILURE_RETRY may or may not be in unistd
+#include <memory>
+#include <vector>
 
+#include "base/file.h"
+#include "base/macros.h"  // TEMP_FAILURE_RETRY may or may not be in unistd
+#include "base/memory.h"
+#include "log/log.h"
+#include "utils/Compat.h"
+#include "utils/FileMap.h"
+#include "zlib.h"
+
+#include "entry_name_utils-inl.h"
 #include "ziparchive/zip_archive.h"
 
+using android::base::get_unaligned;
+
 // This is for windows. If we don't open a file in binary mode, weird
 // things will happen.
 #ifndef O_BINARY
 #define O_BINARY 0
 #endif
 
-#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
-    TypeName(); \
-    TypeName(const TypeName&); \
-    void operator=(const TypeName&)
-
 // The "end of central directory" (EOCD) record. Each archive
 // contains exactly once such record which appears at the end of
 // the archive. It contains archive wide information like the
@@ -83,7 +86,8 @@
   // Length of the central directory comment.
   uint16_t comment_length;
  private:
-  DISALLOW_IMPLICIT_CONSTRUCTORS(EocdRecord);
+  EocdRecord() = default;
+  DISALLOW_COPY_AND_ASSIGN(EocdRecord);
 } __attribute__((packed));
 
 // A structure representing the fixed length fields for a single
@@ -136,7 +140,8 @@
   // beginning of this archive.
   uint32_t local_file_header_offset;
  private:
-  DISALLOW_IMPLICIT_CONSTRUCTORS(CentralDirectoryRecord);
+  CentralDirectoryRecord() = default;
+  DISALLOW_COPY_AND_ASSIGN(CentralDirectoryRecord);
 } __attribute__((packed));
 
 // The local file header for a given entry. This duplicates information
@@ -173,7 +178,8 @@
   // will appear immediately after the entry file name.
   uint16_t extra_field_length;
  private:
-  DISALLOW_IMPLICIT_CONSTRUCTORS(LocalFileHeader);
+  LocalFileHeader() = default;
+  DISALLOW_COPY_AND_ASSIGN(LocalFileHeader);
 } __attribute__((packed));
 
 struct DataDescriptor {
@@ -187,13 +193,12 @@
   // Uncompressed size of the entry.
   uint32_t uncompressed_size;
  private:
-  DISALLOW_IMPLICIT_CONSTRUCTORS(DataDescriptor);
+  DataDescriptor() = default;
+  DISALLOW_COPY_AND_ASSIGN(DataDescriptor);
 } __attribute__((packed));
 
-#undef DISALLOW_IMPLICIT_CONSTRUCTORS
 
 static const uint32_t kGPBDDFlagMask = 0x0008;         // mask value that signifies that the entry has a DD
-static const uint32_t kMaxErrorLen = 1024;
 
 // The maximum size of a central directory or a file
 // comment in bytes.
@@ -264,8 +269,6 @@
 
 static const int32_t kErrorMessageLowerBound = -13;
 
-static const char kTempMappingFileName[] = "zip: ExtractFileToFile";
-
 /*
  * A Read-only Zip archive.
  *
@@ -288,10 +291,11 @@
 struct ZipArchive {
   /* open Zip archive */
   const int fd;
+  const bool close_file;
 
   /* mapped central directory area */
   off64_t directory_offset;
-  android::FileMap* directory_map;
+  android::FileMap directory_map;
 
   /* number of entries in the Zip archive */
   uint16_t num_entries;
@@ -305,69 +309,23 @@
   uint32_t hash_table_size;
   ZipEntryName* hash_table;
 
-  ZipArchive(const int fd) :
+  ZipArchive(const int fd, bool assume_ownership) :
       fd(fd),
+      close_file(assume_ownership),
       directory_offset(0),
-      directory_map(NULL),
       num_entries(0),
       hash_table_size(0),
       hash_table(NULL) {}
 
   ~ZipArchive() {
-    if (fd >= 0) {
+    if (close_file && fd >= 0) {
       close(fd);
     }
 
-    if (directory_map != NULL) {
-      directory_map->release();
-    }
     free(hash_table);
   }
 };
 
-// Returns 0 on success and negative values on failure.
-static android::FileMap* MapFileSegment(const int fd, const off64_t start,
-                                        const size_t length, const bool read_only,
-                                        const char* debug_file_name) {
-  android::FileMap* file_map = new android::FileMap;
-  const bool success = file_map->create(debug_file_name, fd, start, length, read_only);
-  if (!success) {
-    file_map->release();
-    return NULL;
-  }
-
-  return file_map;
-}
-
-static int32_t CopyFileToFile(int fd, uint8_t* begin, const uint32_t length, uint64_t *crc_out) {
-  static const uint32_t kBufSize = 32768;
-  uint8_t buf[kBufSize];
-
-  uint32_t count = 0;
-  uint64_t crc = 0;
-  while (count < length) {
-    uint32_t remaining = length - count;
-
-    // Safe conversion because kBufSize is narrow enough for a 32 bit signed
-    // value.
-    ssize_t get_size = (remaining > kBufSize) ? kBufSize : remaining;
-    ssize_t actual = TEMP_FAILURE_RETRY(read(fd, buf, get_size));
-
-    if (actual != get_size) {
-      ALOGW("CopyFileToFile: copy read failed (" ZD " vs " ZD ")", actual, get_size);
-      return kIoError;
-    }
-
-    memcpy(begin + count, buf, get_size);
-    crc = crc32(crc, buf, get_size);
-    count += get_size;
-  }
-
-  *crc_out = crc;
-
-  return 0;
-}
-
 /*
  * Round up to the next highest power of 2.
  *
@@ -385,8 +343,10 @@
   return val;
 }
 
-static uint32_t ComputeHash(const char* str, uint16_t len) {
+static uint32_t ComputeHash(const ZipEntryName& name) {
   uint32_t hash = 0;
+  uint16_t len = name.name_length;
+  const uint8_t* str = name.name;
 
   while (len--) {
     hash = hash * 31 + *str++;
@@ -401,21 +361,21 @@
  */
 static int64_t EntryToIndex(const ZipEntryName* hash_table,
                             const uint32_t hash_table_size,
-                            const char* name, uint16_t length) {
-  const uint32_t hash = ComputeHash(name, length);
+                            const ZipEntryName& name) {
+  const uint32_t hash = ComputeHash(name);
 
   // NOTE: (hash_table_size - 1) is guaranteed to be non-negative.
   uint32_t ent = hash & (hash_table_size - 1);
   while (hash_table[ent].name != NULL) {
-    if (hash_table[ent].name_length == length &&
-        memcmp(hash_table[ent].name, name, length) == 0) {
+    if (hash_table[ent].name_length == name.name_length &&
+        memcmp(hash_table[ent].name, name.name, name.name_length) == 0) {
       return ent;
     }
 
     ent = (ent + 1) & (hash_table_size - 1);
   }
 
-  ALOGV("Zip: Unable to find entry %.*s", length, name);
+  ALOGV("Zip: Unable to find entry %.*s", name.name_length, name.name);
   return kEntryNotFound;
 }
 
@@ -423,8 +383,8 @@
  * Add a new entry to the hash table.
  */
 static int32_t AddToHash(ZipEntryName *hash_table, const uint64_t hash_table_size,
-                         const char* name, uint16_t length) {
-  const uint64_t hash = ComputeHash(name, length);
+                         const ZipEntryName& name) {
+  const uint64_t hash = ComputeHash(name);
   uint32_t ent = hash & (hash_table_size - 1);
 
   /*
@@ -432,17 +392,17 @@
    * Further, we guarantee that the hashtable size is not 0.
    */
   while (hash_table[ent].name != NULL) {
-    if (hash_table[ent].name_length == length &&
-        memcmp(hash_table[ent].name, name, length) == 0) {
+    if (hash_table[ent].name_length == name.name_length &&
+        memcmp(hash_table[ent].name, name.name, name.name_length) == 0) {
       // We've found a duplicate entry. We don't accept it
-      ALOGW("Zip: Found duplicate entry %.*s", length, name);
+      ALOGW("Zip: Found duplicate entry %.*s", name.name_length, name.name);
       return kDuplicateEntry;
     }
     ent = (ent + 1) & (hash_table_size - 1);
   }
 
-  hash_table[ent].name = name;
-  hash_table[ent].name_length = length;
+  hash_table[ent].name = name.name;
+  hash_table[ent].name_length = name.name_length;
   return 0;
 }
 
@@ -472,10 +432,12 @@
    */
   int i = read_amount - sizeof(EocdRecord);
   for (; i >= 0; i--) {
-    if (scan_buffer[i] == 0x50 &&
-        ((*reinterpret_cast<uint32_t*>(&scan_buffer[i])) == EocdRecord::kSignature)) {
-      ALOGV("+++ Found EOCD at buf+%d", i);
-      break;
+    if (scan_buffer[i] == 0x50) {
+      uint32_t* sig_addr = reinterpret_cast<uint32_t*>(&scan_buffer[i]);
+      if (get_unaligned<uint32_t>(sig_addr) == EocdRecord::kSignature) {
+        ALOGV("+++ Found EOCD at buf+%d", i);
+        break;
+      }
     }
   }
   if (i < 0) {
@@ -523,16 +485,12 @@
    * It all looks good.  Create a mapping for the CD, and set the fields
    * in archive.
    */
-  android::FileMap* map = MapFileSegment(fd,
-      static_cast<off64_t>(eocd->cd_start_offset),
-      static_cast<size_t>(eocd->cd_size),
-      true /* read only */, debug_file_name);
-  if (map == NULL) {
-    archive->directory_map = NULL;
+  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 */) ) {
     return kMmapFailed;
   }
 
-  archive->directory_map = map;
   archive->num_entries = eocd->num_records;
   archive->directory_offset = eocd->cd_start_offset;
 
@@ -559,7 +517,7 @@
     return kInvalidFile;
   }
 
-  if (file_length > (off64_t) 0xffffffff) {
+  if (file_length > static_cast<off64_t>(0xffffffff)) {
     ALOGV("Zip: zip file too long %" PRId64, static_cast<int64_t>(file_length));
     return kInvalidFile;
   }
@@ -601,9 +559,9 @@
  * Returns 0 on success.
  */
 static int32_t ParseZipArchive(ZipArchive* archive) {
-  int32_t result = -1;
-  const uint8_t* const cd_ptr = (const uint8_t*) archive->directory_map->getDataPtr();
-  const size_t cd_length = archive->directory_map->getDataLength();
+  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 uint16_t num_entries = archive->num_entries;
 
   /*
@@ -612,8 +570,8 @@
    * least one unused entry to avoid an infinite loop during creation.
    */
   archive->hash_table_size = RoundUpPower2(1 + (num_entries * 4) / 3);
-  archive->hash_table = (ZipEntryName*) calloc(archive->hash_table_size,
-      sizeof(ZipEntryName));
+  archive->hash_table = reinterpret_cast<ZipEntryName*>(calloc(archive->hash_table_size,
+      sizeof(ZipEntryName)));
 
   /*
    * Walk through the central directory, adding entries to the hash
@@ -626,53 +584,52 @@
         reinterpret_cast<const CentralDirectoryRecord*>(ptr);
     if (cdr->record_signature != CentralDirectoryRecord::kSignature) {
       ALOGW("Zip: missed a central dir sig (at %" PRIu16 ")", i);
-      goto bail;
+      return -1;
     }
 
     if (ptr + sizeof(CentralDirectoryRecord) > cd_end) {
       ALOGW("Zip: ran off the end (at %" PRIu16 ")", i);
-      goto bail;
+      return -1;
     }
 
     const off64_t local_header_offset = cdr->local_file_header_offset;
     if (local_header_offset >= archive->directory_offset) {
-      ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16, (int64_t)local_header_offset, i);
-      goto bail;
+      ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16,
+          static_cast<int64_t>(local_header_offset), i);
+      return -1;
     }
 
     const uint16_t file_name_length = cdr->file_name_length;
     const uint16_t extra_length = cdr->extra_field_length;
     const uint16_t comment_length = cdr->comment_length;
-    const char* file_name = reinterpret_cast<const char*>(ptr + sizeof(CentralDirectoryRecord));
+    const uint8_t* file_name = ptr + sizeof(CentralDirectoryRecord);
 
-    /* check that file name doesn't contain \0 character */
-    if (memchr(file_name, 0, file_name_length) != NULL) {
-      ALOGW("Zip: entry name can't contain \\0 character");
-      goto bail;
+    /* check that file name is valid UTF-8 and doesn't contain NUL (U+0000) characters */
+    if (!IsValidEntryName(file_name, file_name_length)) {
+      return -1;
     }
 
     /* add the CDE filename to the hash table */
+    ZipEntryName entry_name;
+    entry_name.name = file_name;
+    entry_name.name_length = file_name_length;
     const int add_result = AddToHash(archive->hash_table,
-        archive->hash_table_size, file_name, file_name_length);
-    if (add_result) {
+        archive->hash_table_size, entry_name);
+    if (add_result != 0) {
       ALOGW("Zip: Error adding entry to hash table %d", add_result);
-      result = add_result;
-      goto bail;
+      return add_result;
     }
 
     ptr += sizeof(CentralDirectoryRecord) + file_name_length + extra_length + comment_length;
     if ((ptr - cd_ptr) > static_cast<int64_t>(cd_length)) {
       ALOGW("Zip: bad CD advance (%tu vs %zu) at entry %" PRIu16,
           ptr - cd_ptr, cd_length, i);
-      goto bail;
+      return -1;
     }
   }
   ALOGV("+++ zip good scan %" PRIu16 " entries", num_entries);
 
-  result = 0;
-
-bail:
-  return result;
+  return 0;
 }
 
 static int32_t OpenArchiveInternal(ZipArchive* archive,
@@ -690,21 +647,22 @@
 }
 
 int32_t OpenArchiveFd(int fd, const char* debug_file_name,
-                      ZipArchiveHandle* handle) {
-  ZipArchive* archive = new ZipArchive(fd);
+                      ZipArchiveHandle* handle, bool assume_ownership) {
+  ZipArchive* archive = new ZipArchive(fd, assume_ownership);
   *handle = archive;
   return OpenArchiveInternal(archive, debug_file_name);
 }
 
 int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle) {
   const int fd = open(fileName, O_RDONLY | O_BINARY, 0);
-  ZipArchive* archive = new ZipArchive(fd);
+  ZipArchive* archive = new ZipArchive(fd, true);
   *handle = archive;
 
   if (fd < 0) {
     ALOGW("Unable to open '%s': %s", fileName, strerror(errno));
     return kIoError;
   }
+
   return OpenArchiveInternal(archive, fileName);
 }
 
@@ -712,7 +670,7 @@
  * Close a ZipArchive, closing the file and freeing the contents.
  */
 void CloseArchive(ZipArchiveHandle handle) {
-  ZipArchive* archive = (ZipArchive*) handle;
+  ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
   ALOGV("Closing archive %p", archive);
   delete archive;
 }
@@ -744,7 +702,7 @@
 // as a side effect of this call.
 static inline ssize_t ReadAtOffset(int fd, uint8_t* buf, size_t len,
                                    off64_t off) {
-#ifdef HAVE_PREAD
+#if !defined(_WIN32)
   return TEMP_FAILURE_RETRY(pread64(fd, buf, len, off));
 #else
   // The only supported platform that doesn't support pread at the moment
@@ -756,26 +714,25 @@
   }
 
   return TEMP_FAILURE_RETRY(read(fd, buf, len));
-#endif  // HAVE_PREAD
+#endif
 }
 
 static int32_t FindEntry(const ZipArchive* archive, const int ent,
                          ZipEntry* data) {
   const uint16_t nameLen = archive->hash_table[ent].name_length;
-  const char* name = archive->hash_table[ent].name;
 
   // Recover the start of the central directory entry from the filename
   // pointer.  The filename is the first entry past the fixed-size data,
   // so we can just subtract back from that.
-  const uint8_t* ptr = reinterpret_cast<const uint8_t*>(name);
+  const uint8_t* ptr = archive->hash_table[ent].name;
   ptr -= sizeof(CentralDirectoryRecord);
 
   // 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()) {
+    archive->directory_map.getDataPtr());
+  if (ptr < base_ptr || ptr > base_ptr + archive->directory_map.getDataLength()) {
     ALOGW("Zip: Invalid entry pointer");
     return kInvalidOffset;
   }
@@ -810,7 +767,8 @@
   ssize_t actual = ReadAtOffset(archive->fd, lfh_buf, sizeof(lfh_buf),
                                  local_header_offset);
   if (actual != sizeof(lfh_buf)) {
-    ALOGW("Zip: failed reading lfh name from offset %" PRId64, (int64_t)local_header_offset);
+    ALOGW("Zip: failed reading lfh name from offset %" PRId64,
+        static_cast<int64_t>(local_header_offset));
     return kIoError;
   }
 
@@ -843,22 +801,22 @@
   // name in the central directory.
   if (lfh->file_name_length == nameLen) {
     const off64_t name_offset = local_header_offset + sizeof(LocalFileHeader);
-    if (name_offset + lfh->file_name_length >= cd_offset) {
+    if (name_offset + lfh->file_name_length > cd_offset) {
       ALOGW("Zip: Invalid declared length");
       return kInvalidOffset;
     }
 
-    uint8_t* name_buf = (uint8_t*) malloc(nameLen);
+    uint8_t* name_buf = reinterpret_cast<uint8_t*>(malloc(nameLen));
     ssize_t actual = ReadAtOffset(archive->fd, name_buf, nameLen,
                                   name_offset);
 
     if (actual != nameLen) {
-      ALOGW("Zip: failed reading lfh name from offset %" PRId64, (int64_t)name_offset);
+      ALOGW("Zip: failed reading lfh name from offset %" PRId64, static_cast<int64_t>(name_offset));
       free(name_buf);
       return kIoError;
     }
 
-    if (memcmp(name, name_buf, nameLen)) {
+    if (memcmp(archive->hash_table[ent].name, name_buf, nameLen)) {
       free(name_buf);
       return kInconsistentInformation;
     }
@@ -872,20 +830,21 @@
   const off64_t data_offset = local_header_offset + sizeof(LocalFileHeader)
       + lfh->file_name_length + lfh->extra_field_length;
   if (data_offset > cd_offset) {
-    ALOGW("Zip: bad data offset %" PRId64 " in zip", (int64_t)data_offset);
+    ALOGW("Zip: bad data offset %" PRId64 " in zip", static_cast<int64_t>(data_offset));
     return kInvalidOffset;
   }
 
-  if ((off64_t)(data_offset + data->compressed_length) > cd_offset) {
+  if (static_cast<off64_t>(data_offset + data->compressed_length) > cd_offset) {
     ALOGW("Zip: bad compressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
-      (int64_t)data_offset, data->compressed_length, (int64_t)cd_offset);
+      static_cast<int64_t>(data_offset), data->compressed_length, static_cast<int64_t>(cd_offset));
     return kInvalidOffset;
   }
 
   if (data->method == kCompressStored &&
-    (off64_t)(data_offset + data->uncompressed_length) > cd_offset) {
+    static_cast<off64_t>(data_offset + data->uncompressed_length) > cd_offset) {
      ALOGW("Zip: bad uncompressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
-       (int64_t)data_offset, data->uncompressed_length, (int64_t)cd_offset);
+       static_cast<int64_t>(data_offset), data->uncompressed_length,
+       static_cast<int64_t>(cd_offset));
      return kInvalidOffset;
   }
 
@@ -895,45 +854,73 @@
 
 struct IterationHandle {
   uint32_t position;
-  const char* prefix;
-  uint16_t prefix_len;
+  // We're not using vector here because this code is used in the Windows SDK
+  // where the STL is not available.
+  const uint8_t* prefix;
+  const uint16_t prefix_len;
+  const uint8_t* suffix;
+  const uint16_t suffix_len;
   ZipArchive* archive;
+
+  IterationHandle(const ZipEntryName* prefix_name,
+                  const ZipEntryName* suffix_name)
+    : prefix(NULL),
+      prefix_len(prefix_name ? prefix_name->name_length : 0),
+      suffix(NULL),
+      suffix_len(suffix_name ? suffix_name->name_length : 0) {
+    if (prefix_name) {
+      uint8_t* prefix_copy = new uint8_t[prefix_len];
+      memcpy(prefix_copy, prefix_name->name, prefix_len);
+      prefix = prefix_copy;
+    }
+    if (suffix_name) {
+      uint8_t* suffix_copy = new uint8_t[suffix_len];
+      memcpy(suffix_copy, suffix_name->name, suffix_len);
+      suffix = suffix_copy;
+    }
+  }
+
+  ~IterationHandle() {
+    delete[] prefix;
+    delete[] suffix;
+  }
 };
 
-int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr, const char* prefix) {
-  ZipArchive* archive = (ZipArchive *) handle;
+int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr,
+                       const ZipEntryName* optional_prefix,
+                       const ZipEntryName* optional_suffix) {
+  ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
 
   if (archive == NULL || archive->hash_table == NULL) {
     ALOGW("Zip: Invalid ZipArchiveHandle");
     return kInvalidHandle;
   }
 
-  IterationHandle* cookie = (IterationHandle*) malloc(sizeof(IterationHandle));
+  IterationHandle* cookie = new IterationHandle(optional_prefix, optional_suffix);
   cookie->position = 0;
-  cookie->prefix = prefix;
   cookie->archive = archive;
-  if (prefix != NULL) {
-    cookie->prefix_len = strlen(prefix);
-  }
 
   *cookie_ptr = cookie ;
   return 0;
 }
 
-int32_t FindEntry(const ZipArchiveHandle handle, const char* entryName,
+void EndIteration(void* cookie) {
+  delete reinterpret_cast<IterationHandle*>(cookie);
+}
+
+int32_t FindEntry(const ZipArchiveHandle handle, const ZipEntryName& entryName,
                   ZipEntry* data) {
-  const ZipArchive* archive = (ZipArchive*) handle;
-  const int nameLen = strlen(entryName);
-  if (nameLen == 0 || nameLen > 65535) {
-    ALOGW("Zip: Invalid filename %s", entryName);
+  const ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
+  if (entryName.name_length == 0) {
+    ALOGW("Zip: Invalid filename %.*s", entryName.name_length, entryName.name);
     return kInvalidEntryName;
   }
 
   const int64_t ent = EntryToIndex(archive->hash_table,
-    archive->hash_table_size, entryName, nameLen);
+    archive->hash_table_size, entryName);
 
   if (ent < 0) {
-    ALOGV("Zip: Could not find entry %.*s", nameLen, entryName);
+    ALOGV("Zip: Could not find entry %.*s", entryName.name_length, entryName.name);
     return ent;
   }
 
@@ -941,7 +928,7 @@
 }
 
 int32_t Next(void* cookie, ZipEntry* data, ZipEntryName* name) {
-  IterationHandle* handle = (IterationHandle *) cookie;
+  IterationHandle* handle = reinterpret_cast<IterationHandle*>(cookie);
   if (handle == NULL) {
     return kInvalidHandle;
   }
@@ -958,8 +945,14 @@
 
   for (uint32_t i = currentOffset; i < hash_table_length; ++i) {
     if (hash_table[i].name != NULL &&
-        (handle->prefix == NULL ||
-         (memcmp(handle->prefix, hash_table[i].name, handle->prefix_len) == 0))) {
+        (handle->prefix_len == 0 ||
+         (hash_table[i].name_length >= handle->prefix_len &&
+          memcmp(handle->prefix, hash_table[i].name, handle->prefix_len) == 0)) &&
+        (handle->suffix_len == 0 ||
+         (hash_table[i].name_length >= handle->suffix_len &&
+          memcmp(handle->suffix,
+                 hash_table[i].name + hash_table[i].name_length - handle->suffix_len,
+                 handle->suffix_len) == 0))) {
       handle->position = (i + 1);
       const int error = FindEntry(archive, i, data);
       if (!error) {
@@ -975,13 +968,135 @@
   return kIterationEnd;
 }
 
-static int32_t InflateToFile(int fd, const ZipEntry* entry,
-                             uint8_t* begin, uint32_t length,
-                             uint64_t* crc_out) {
-  int32_t result = -1;
-  const uint32_t kBufSize = 32768;
-  uint8_t read_buf[kBufSize];
-  uint8_t write_buf[kBufSize];
+class Writer {
+ public:
+  virtual bool Append(uint8_t* buf, size_t buf_size) = 0;
+  virtual ~Writer() {}
+ protected:
+  Writer() = default;
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Writer);
+};
+
+// A Writer that writes data to a fixed size memory region.
+// The size of the memory region must be equal to the total size of
+// the data appended to it.
+class MemoryWriter : public Writer {
+ public:
+  MemoryWriter(uint8_t* buf, size_t size) : Writer(),
+      buf_(buf), size_(size), bytes_written_(0) {
+  }
+
+  virtual bool Append(uint8_t* buf, size_t buf_size) override {
+    if (bytes_written_ + buf_size > size_) {
+      ALOGW("Zip: Unexpected size " ZD " (declared) vs " ZD " (actual)",
+            size_, bytes_written_ + buf_size);
+      return false;
+    }
+
+    memcpy(buf_ + bytes_written_, buf, buf_size);
+    bytes_written_ += buf_size;
+    return true;
+  }
+
+ private:
+  uint8_t* const buf_;
+  const size_t size_;
+  size_t bytes_written_;
+};
+
+// A Writer that appends data to a file |fd| at its current position.
+// The file will be truncated to the end of the written data.
+class FileWriter : public Writer {
+ public:
+
+  // 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.
+  //
+  // Returns a valid FileWriter on success, |nullptr| if an error occurred.
+  static std::unique_ptr<FileWriter> Create(int fd, const ZipEntry* entry) {
+    const uint32_t declared_length = entry->uncompressed_length;
+    const off64_t current_offset = lseek64(fd, 0, SEEK_CUR);
+    if (current_offset == -1) {
+      ALOGW("Zip: unable to seek to current location on fd %d: %s", fd, strerror(errno));
+      return nullptr;
+    }
+
+    int result = 0;
+#if defined(__linux__)
+    if (declared_length > 0) {
+      // Make sure we have enough space on the volume to extract the compressed
+      // entry. Note that the call to ftruncate below will change the file size but
+      // will not allocate space on disk and this call to fallocate will not
+      // change the file size.
+      // Note: fallocate is only supported by the following filesystems -
+      // btrfs, ext4, ocfs2, and xfs. Therefore fallocate might fail with
+      // EOPNOTSUPP error when issued in other filesystems.
+      // Hence, check for the return error code before concluding that the
+      // 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));
+        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));
+      return std::unique_ptr<FileWriter>(nullptr);
+    }
+
+    return std::unique_ptr<FileWriter>(new FileWriter(fd, declared_length));
+  }
+
+  virtual bool Append(uint8_t* buf, size_t buf_size) override {
+    if (total_bytes_written_ + buf_size > declared_length_) {
+      ALOGW("Zip: Unexpected size " ZD " (declared) vs " ZD " (actual)",
+            declared_length_, total_bytes_written_ + buf_size);
+      return false;
+    }
+
+    const bool result = android::base::WriteFully(fd_, buf, buf_size);
+    if (result) {
+      total_bytes_written_ += buf_size;
+    } else {
+      ALOGW("Zip: unable to write " ZD " bytes to file; %s", buf_size, strerror(errno));
+    }
+
+    return result;
+  }
+ private:
+  FileWriter(const int fd, const size_t declared_length) :
+      Writer(),
+      fd_(fd),
+      declared_length_(declared_length),
+      total_bytes_written_(0) {
+  }
+
+  const int fd_;
+  const size_t declared_length_;
+  size_t total_bytes_written_;
+};
+
+// This method is using libz macros with old-style-casts
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+static inline int zlib_inflateInit2(z_stream* stream, int window_bits) {
+  return inflateInit2(stream, window_bits);
+}
+#pragma GCC diagnostic pop
+
+static int32_t InflateEntryToWriter(int fd, const ZipEntry* entry,
+                                    Writer* writer, uint64_t* crc_out) {
+  const size_t kBufSize = 32768;
+  std::vector<uint8_t> read_buf(kBufSize);
+  std::vector<uint8_t> write_buf(kBufSize);
   z_stream zstream;
   int zerr;
 
@@ -994,7 +1109,7 @@
   zstream.opaque = Z_NULL;
   zstream.next_in = NULL;
   zstream.avail_in = 0;
-  zstream.next_out = (Bytef*) write_buf;
+  zstream.next_out = &write_buf[0];
   zstream.avail_out = kBufSize;
   zstream.data_type = Z_UNKNOWN;
 
@@ -1002,7 +1117,7 @@
    * Use the undocumented "negative window bits" feature to tell zlib
    * that there's no zlib header waiting for it.
    */
-  zerr = inflateInit2(&zstream, -MAX_WBITS);
+  zerr = zlib_inflateInit2(&zstream, -MAX_WBITS);
   if (zerr != Z_OK) {
     if (zerr == Z_VERSION_ERROR) {
       ALOGE("Installed zlib is not compatible with linked version (%s)",
@@ -1014,24 +1129,28 @@
     return kZlibError;
   }
 
+  auto zstream_deleter = [](z_stream* stream) {
+    inflateEnd(stream);  /* free up any allocated structures */
+  };
+
+  std::unique_ptr<z_stream, decltype(zstream_deleter)> zstream_guard(&zstream, zstream_deleter);
+
   const uint32_t uncompressed_length = entry->uncompressed_length;
 
   uint32_t compressed_length = entry->compressed_length;
-  uint32_t write_count = 0;
   do {
     /* read as much as we can */
     if (zstream.avail_in == 0) {
       const ZD_TYPE getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
-      const ZD_TYPE actual = TEMP_FAILURE_RETRY(read(fd, read_buf, getSize));
+      const ZD_TYPE actual = TEMP_FAILURE_RETRY(read(fd, &read_buf[0], getSize));
       if (actual != getSize) {
         ALOGW("Zip: inflate read failed (" ZD " vs " ZD ")", actual, getSize);
-        result = kIoError;
-        goto z_bail;
+        return kIoError;
       }
 
       compressed_length -= getSize;
 
-      zstream.next_in = read_buf;
+      zstream.next_in = &read_buf[0];
       zstream.avail_in = getSize;
     }
 
@@ -1041,22 +1160,19 @@
       ALOGW("Zip: inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)",
           zerr, zstream.next_in, zstream.avail_in,
           zstream.next_out, zstream.avail_out);
-      result = kZlibError;
-      goto z_bail;
+      return kZlibError;
     }
 
     /* write when we're full or when we're done */
     if (zstream.avail_out == 0 ||
       (zerr == Z_STREAM_END && zstream.avail_out != kBufSize)) {
-      const size_t write_size = zstream.next_out - write_buf;
-      // The file might have declared a bogus length.
-      if (write_size + write_count > length) {
-        goto z_bail;
+      const size_t write_size = zstream.next_out - &write_buf[0];
+      if (!writer->Append(&write_buf[0], write_size)) {
+        // The file might have declared a bogus length.
+        return kInconsistentInformation;
       }
-      memcpy(begin + write_count, write_buf, write_size);
-      write_count += write_size;
 
-      zstream.next_out = write_buf;
+      zstream.next_out = &write_buf[0];
       zstream.avail_out = kBufSize;
     }
   } while (zerr == Z_OK);
@@ -1069,26 +1185,53 @@
   if (zstream.total_out != uncompressed_length || compressed_length != 0) {
     ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu32 ")",
         zstream.total_out, uncompressed_length);
-    result = kInconsistentInformation;
-    goto z_bail;
+    return kInconsistentInformation;
   }
 
-  result = 0;
-
-z_bail:
-  inflateEnd(&zstream);    /* free up any allocated structures */
-
-  return result;
+  return 0;
 }
 
-int32_t ExtractToMemory(ZipArchiveHandle handle,
-                        ZipEntry* entry, uint8_t* begin, uint32_t size) {
-  ZipArchive* archive = (ZipArchive*) handle;
+static int32_t CopyEntryToWriter(int fd, const ZipEntry* entry, Writer* writer,
+                                 uint64_t *crc_out) {
+  static const uint32_t kBufSize = 32768;
+  std::vector<uint8_t> buf(kBufSize);
+
+  const uint32_t length = entry->uncompressed_length;
+  uint32_t count = 0;
+  uint64_t crc = 0;
+  while (count < length) {
+    uint32_t remaining = length - count;
+
+    // Safe conversion because kBufSize is narrow enough for a 32 bit signed
+    // value.
+    const ssize_t block_size = (remaining > kBufSize) ? kBufSize : remaining;
+    const ssize_t actual = TEMP_FAILURE_RETRY(read(fd, &buf[0], block_size));
+
+    if (actual != block_size) {
+      ALOGW("CopyFileToFile: copy read failed (" ZD " vs " ZD ")", actual, block_size);
+      return kIoError;
+    }
+
+    if (!writer->Append(&buf[0], block_size)) {
+      return kIoError;
+    }
+    crc = crc32(crc, &buf[0], block_size);
+    count += block_size;
+  }
+
+  *crc_out = crc;
+
+  return 0;
+}
+
+int32_t ExtractToWriter(ZipArchiveHandle handle,
+                        ZipEntry* entry, Writer* writer) {
+  ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
   const uint16_t method = entry->method;
   off64_t data_offset = entry->offset;
 
   if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) {
-    ALOGW("Zip: lseek to data at %" PRId64 " failed", (int64_t)data_offset);
+    ALOGW("Zip: lseek to data at %" PRId64 " failed", static_cast<int64_t>(data_offset));
     return kIoError;
   }
 
@@ -1096,9 +1239,9 @@
   int32_t return_value = -1;
   uint64_t crc = 0;
   if (method == kCompressStored) {
-    return_value = CopyFileToFile(archive->fd, begin, size, &crc);
+    return_value = CopyEntryToWriter(archive->fd, entry, writer, &crc);
   } else if (method == kCompressDeflated) {
-    return_value = InflateToFile(archive->fd, entry, begin, size, &crc);
+    return_value = InflateEntryToWriter(archive->fd, entry, writer, &crc);
   }
 
   if (!return_value && entry->has_data_descriptor) {
@@ -1118,42 +1261,20 @@
   return return_value;
 }
 
+int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry,
+                        uint8_t* begin, uint32_t size) {
+  std::unique_ptr<Writer> writer(new MemoryWriter(begin, size));
+  return ExtractToWriter(handle, entry, writer.get());
+}
+
 int32_t ExtractEntryToFile(ZipArchiveHandle handle,
                            ZipEntry* entry, int fd) {
-  const int32_t declared_length = entry->uncompressed_length;
-
-  const off64_t current_offset = lseek64(fd, 0, SEEK_CUR);
-  if (current_offset == -1) {
-    ALOGW("Zip: unable to seek to current location on fd %d: %s", fd,
-          strerror(errno));
+  std::unique_ptr<Writer> writer(FileWriter::Create(fd, entry));
+  if (writer.get() == nullptr) {
     return kIoError;
   }
 
-  int result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
-  if (result == -1) {
-    ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
-          (int64_t)(declared_length + current_offset), strerror(errno));
-    return kIoError;
-  }
-
-  // Don't attempt to map a region of length 0. We still need the
-  // ftruncate() though, since the API guarantees that we will truncate
-  // the file to the end of the uncompressed output.
-  if (declared_length == 0) {
-      return 0;
-  }
-
-  android::FileMap* map  = MapFileSegment(fd, current_offset, declared_length,
-                                          false, kTempMappingFileName);
-  if (map == NULL) {
-    return kMmapFailed;
-  }
-
-  const int32_t error = ExtractToMemory(handle, entry,
-                                        reinterpret_cast<uint8_t*>(map->getDataPtr()),
-                                        map->getDataLength());
-  map->release();
-  return error;
+  return ExtractToWriter(handle, entry, writer.get());
 }
 
 const char* ErrorCodeString(int32_t error_code) {
@@ -1165,6 +1286,5 @@
 }
 
 int GetFileDescriptor(const ZipArchiveHandle handle) {
-  return ((ZipArchive*) handle)->fd;
+  return reinterpret_cast<ZipArchive*>(handle)->fd;
 }
-
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 813a87f..c799869 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -17,11 +17,13 @@
 #include "ziparchive/zip_archive.h"
 
 #include <errno.h>
+#include <fcntl.h>
 #include <getopt.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <vector>
 
+#include <base/file.h>
 #include <gtest/gtest.h>
 
 static std::string test_data_dir;
@@ -40,6 +42,27 @@
   '\n'
 };
 
+static const uint16_t kATxtNameLength = 5;
+static const uint16_t kBTxtNameLength = 5;
+static const uint16_t kNonexistentTxtNameLength = 15;
+static const uint16_t kEmptyTxtNameLength = 9;
+
+static const uint8_t kATxtName[kATxtNameLength] = {
+  'a', '.', 't', 'x', 't'
+};
+
+static const uint8_t kBTxtName[kBTxtNameLength] = {
+  'b', '.', 't', 'x', 't'
+};
+
+static const uint8_t kNonexistentTxtName[kNonexistentTxtNameLength] = {
+  'n', 'o', 'n', 'e', 'x', 'i', 's', 't', 'e', 'n', 't', '.', 't', 'x' ,'t'
+};
+
+static const uint8_t kEmptyTxtName[kEmptyTxtNameLength] = {
+  'e', 'm', 'p', 't', 'y', '.', 't', 'x', 't'
+};
+
 static int32_t OpenArchiveWrapper(const std::string& name,
                                   ZipArchiveHandle* handle) {
   const std::string abs_path = test_data_dir + "/" + name;
@@ -67,12 +90,32 @@
   ASSERT_EQ(-1, GetFileDescriptor(handle));
 }
 
+TEST(ziparchive, OpenAssumeFdOwnership) {
+  int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY);
+  ASSERT_NE(-1, fd);
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle));
+  CloseArchive(handle);
+  ASSERT_EQ(-1, lseek(fd, 0, SEEK_SET));
+  ASSERT_EQ(EBADF, errno);
+}
+
+TEST(ziparchive, OpenDoNotAssumeFdOwnership) {
+  int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY);
+  ASSERT_NE(-1, fd);
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle, false));
+  CloseArchive(handle);
+  ASSERT_EQ(0, lseek(fd, 0, SEEK_SET));
+  close(fd);
+}
+
 TEST(ziparchive, Iteration) {
   ZipArchiveHandle handle;
   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
 
   void* iteration_cookie;
-  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, NULL));
+  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, NULL, NULL));
 
   ZipEntry data;
   ZipEntryName name;
@@ -103,12 +146,125 @@
   CloseArchive(handle);
 }
 
+TEST(ziparchive, IterationWithPrefix) {
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+
+  void* iteration_cookie;
+  ZipEntryName prefix("b/");
+  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, NULL));
+
+  ZipEntry data;
+  ZipEntryName name;
+
+  // b/c.txt
+  ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+  AssertNameEquals("b/c.txt", name);
+
+  // b/d.txt
+  ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+  AssertNameEquals("b/d.txt", name);
+
+  // b/
+  ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+  AssertNameEquals("b/", name);
+
+  // End of iteration.
+  ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
+
+  CloseArchive(handle);
+}
+
+TEST(ziparchive, IterationWithSuffix) {
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+
+  void* iteration_cookie;
+  ZipEntryName suffix(".txt");
+  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, NULL, &suffix));
+
+  ZipEntry data;
+  ZipEntryName name;
+
+  // b/c.txt
+  ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+  AssertNameEquals("b/c.txt", name);
+
+  // b/d.txt
+  ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+  AssertNameEquals("b/d.txt", name);
+
+  // a.txt
+  ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+  AssertNameEquals("a.txt", name);
+
+  // b.txt
+  ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+  AssertNameEquals("b.txt", name);
+
+  // End of iteration.
+  ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
+
+  CloseArchive(handle);
+}
+
+TEST(ziparchive, IterationWithPrefixAndSuffix) {
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+
+  void* iteration_cookie;
+  ZipEntryName prefix("b");
+  ZipEntryName suffix(".txt");
+  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, &suffix));
+
+  ZipEntry data;
+  ZipEntryName name;
+
+  // b/c.txt
+  ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+  AssertNameEquals("b/c.txt", name);
+
+  // b/d.txt
+  ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+  AssertNameEquals("b/d.txt", name);
+
+  // b.txt
+  ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+  AssertNameEquals("b.txt", name);
+
+  // End of iteration.
+  ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
+
+  CloseArchive(handle);
+}
+
+TEST(ziparchive, IterationWithBadPrefixAndSuffix) {
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+
+  void* iteration_cookie;
+  ZipEntryName prefix("x");
+  ZipEntryName suffix("y");
+  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, &suffix));
+
+  ZipEntry data;
+  ZipEntryName name;
+
+  // End of iteration.
+  ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
+
+  CloseArchive(handle);
+}
+
 TEST(ziparchive, FindEntry) {
   ZipArchiveHandle handle;
   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
 
   ZipEntry data;
-  ASSERT_EQ(0, FindEntry(handle, "a.txt", &data));
+  ZipEntryName name;
+  name.name = kATxtName;
+  name.name_length = kATxtNameLength;
+  ASSERT_EQ(0, FindEntry(handle, name, &data));
 
   // Known facts about a.txt, from zipinfo -v.
   ASSERT_EQ(63, data.offset);
@@ -118,7 +274,26 @@
   ASSERT_EQ(0x950821c5, data.crc32);
 
   // An entry that doesn't exist. Should be a negative return code.
-  ASSERT_LT(FindEntry(handle, "nonexistent.txt", &data), 0);
+  ZipEntryName absent_name;
+  absent_name.name = kNonexistentTxtName;
+  absent_name.name_length = kNonexistentTxtNameLength;
+  ASSERT_LT(FindEntry(handle, absent_name, &data), 0);
+
+  CloseArchive(handle);
+}
+
+TEST(ziparchive, TestInvalidDeclaredLength) {
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveWrapper("declaredlength.zip", &handle));
+
+  void* iteration_cookie;
+  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, NULL));
+
+  ZipEntryName name;
+  ZipEntry data;
+
+  ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
+  ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
 
   CloseArchive(handle);
 }
@@ -129,7 +304,10 @@
 
   // An entry that's deflated.
   ZipEntry data;
-  ASSERT_EQ(0, FindEntry(handle, "a.txt", &data));
+  ZipEntryName a_name;
+  a_name.name = kATxtName;
+  a_name.name_length = kATxtNameLength;
+  ASSERT_EQ(0, FindEntry(handle, a_name, &data));
   const uint32_t a_size = data.uncompressed_length;
   ASSERT_EQ(a_size, sizeof(kATxtContents));
   uint8_t* buffer = new uint8_t[a_size];
@@ -138,7 +316,10 @@
   delete[] buffer;
 
   // An entry that's stored.
-  ASSERT_EQ(0, FindEntry(handle, "b.txt", &data));
+  ZipEntryName b_name;
+  b_name.name = kBTxtName;
+  b_name.name_length = kBTxtNameLength;
+  ASSERT_EQ(0, FindEntry(handle, b_name, &data));
   const uint32_t b_size = data.uncompressed_length;
   ASSERT_EQ(b_size, sizeof(kBTxtContents));
   buffer = new uint8_t[b_size];
@@ -158,6 +339,44 @@
       0x54557478, 0x13030005, 0x7552e25c, 0x01000b78, 0x00428904, 0x13880400,
       0x4b500000, 0x00000605, 0x00010000, 0x004f0001, 0x00430000, 0x00000000 };
 
+// This is a zip file containing a single entry (ab.txt) that contains
+// 90072 repetitions of the string "ab\n" and has an uncompressed length
+// of 270216 bytes.
+static const uint16_t kAbZip[] = {
+  0x4b50, 0x0403, 0x0014, 0x0000, 0x0008, 0x51d2, 0x4698, 0xc4b0,
+  0x2cda, 0x011b, 0x0000, 0x1f88, 0x0004, 0x0006, 0x001c, 0x6261,
+  0x742e, 0x7478, 0x5455, 0x0009, 0x7c03, 0x3a09, 0x7c55, 0x3a09,
+  0x7555, 0x0b78, 0x0100, 0x8904, 0x0042, 0x0400, 0x1388, 0x0000,
+  0xc2ed, 0x0d31, 0x0000, 0x030c, 0x7fa0, 0x3b2e, 0x22ff, 0xa2aa,
+  0x841f, 0x45fc, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0xdd55, 0x502c, 0x014b, 0x1e02,
+  0x1403, 0x0000, 0x0800, 0xd200, 0x9851, 0xb046, 0xdac4, 0x1b2c,
+  0x0001, 0x8800, 0x041f, 0x0600, 0x1800, 0x0000, 0x0000, 0x0100,
+  0x0000, 0xa000, 0x0081, 0x0000, 0x6100, 0x2e62, 0x7874, 0x5574,
+  0x0554, 0x0300, 0x097c, 0x553a, 0x7875, 0x000b, 0x0401, 0x4289,
+  0x0000, 0x8804, 0x0013, 0x5000, 0x054b, 0x0006, 0x0000, 0x0100,
+  0x0100, 0x4c00, 0x0000, 0x5b00, 0x0001, 0x0000, 0x0000
+};
+
+static const uint8_t kAbTxtName[] = { 'a', 'b', '.', 't', 'x', 't' };
+static const uint16_t kAbTxtNameLength = sizeof(kAbTxtName);
+static const size_t kAbUncompressedSize = 270216;
+
 static int make_temporary_file(const char* file_name_pattern) {
   char full_path[1024];
   // Account for differences between the host and the target.
@@ -184,7 +403,10 @@
   ASSERT_EQ(0, OpenArchiveFd(fd, "EmptyEntriesTest", &handle));
 
   ZipEntry entry;
-  ASSERT_EQ(0, FindEntry(handle, "empty.txt", &entry));
+  ZipEntryName empty_name;
+  empty_name.name = kEmptyTxtName;
+  empty_name.name_length = kEmptyTxtNameLength;
+  ASSERT_EQ(0, FindEntry(handle, empty_name, &entry));
   ASSERT_EQ(static_cast<uint32_t>(0), entry.uncompressed_length);
   uint8_t buffer[1];
   ASSERT_EQ(0, ExtractToMemory(handle, &entry, buffer, 1));
@@ -202,6 +424,55 @@
   close(output_fd);
 }
 
+TEST(ziparchive, EntryLargerThan32K) {
+  char temp_file_pattern[] = "entry_larger_than_32k_test_XXXXXX";
+  int fd = make_temporary_file(temp_file_pattern);
+  ASSERT_NE(-1, fd);
+  ASSERT_TRUE(android::base::WriteFully(fd, reinterpret_cast<const uint8_t*>(kAbZip),
+                         sizeof(kAbZip) - 1));
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveFd(fd, "EntryLargerThan32KTest", &handle));
+
+  ZipEntry entry;
+  ZipEntryName ab_name;
+  ab_name.name = kAbTxtName;
+  ab_name.name_length = kAbTxtNameLength;
+  ASSERT_EQ(0, FindEntry(handle, ab_name, &entry));
+  ASSERT_EQ(kAbUncompressedSize, entry.uncompressed_length);
+
+  // Extract the entry to memory.
+  std::vector<uint8_t> buffer(kAbUncompressedSize);
+  ASSERT_EQ(0, ExtractToMemory(handle, &entry, &buffer[0], buffer.size()));
+
+  // Extract the entry to a file.
+  char output_file_pattern[] = "entry_larger_than_32k_test_output_XXXXXX";
+  int output_fd = make_temporary_file(output_file_pattern);
+  ASSERT_NE(-1, output_fd);
+  ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, output_fd));
+
+  // Make sure the extracted file size is as expected.
+  struct stat stat_buf;
+  ASSERT_EQ(0, fstat(output_fd, &stat_buf));
+  ASSERT_EQ(kAbUncompressedSize, static_cast<size_t>(stat_buf.st_size));
+
+  // Read the file back to a buffer and make sure the contents are
+  // the same as the memory buffer we extracted directly to.
+  std::vector<uint8_t> file_contents(kAbUncompressedSize);
+  ASSERT_EQ(0, lseek64(output_fd, 0, SEEK_SET));
+  ASSERT_TRUE(android::base::ReadFully(output_fd, &file_contents[0], file_contents.size()));
+  ASSERT_EQ(file_contents, buffer);
+
+  for (int i = 0; i < 90072; ++i) {
+    const uint8_t* line = &file_contents[0] + (3 * i);
+    ASSERT_EQ('a', line[0]);
+    ASSERT_EQ('b', line[1]);
+    ASSERT_EQ('\n', line[2]);
+  }
+
+  close(fd);
+  close(output_fd);
+}
+
 TEST(ziparchive, TrailerAfterEOCD) {
   char temp_file_pattern[] = "trailer_after_eocd_test_XXXXXX";
   int fd = make_temporary_file(temp_file_pattern);
@@ -231,7 +502,10 @@
   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
 
   ZipEntry entry;
-  ASSERT_EQ(0, FindEntry(handle, "a.txt", &entry));
+  ZipEntryName name;
+  name.name = kATxtName;
+  name.name_length = kATxtNameLength;
+  ASSERT_EQ(0, FindEntry(handle, name, &entry));
   ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, fd));
 
 
diff --git a/libzipfile/Android.mk b/libzipfile/Android.mk
deleted file mode 100644
index 12a2229..0000000
--- a/libzipfile/Android.mk
+++ /dev/null
@@ -1,56 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# build host static library
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	centraldir.c \
-	zipfile.c
-
-LOCAL_STATIC_LIBRARIES := \
-	libunz
-
-LOCAL_MODULE:= libzipfile
-
-LOCAL_C_INCLUDES += external/zlib
-
-LOCAL_CFLAGS := -Werror
-
-LOCAL_MULTILIB := both
-
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-# build device static library
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	centraldir.c \
-	zipfile.c
-
-LOCAL_STATIC_LIBRARIES := \
-	libunz
-
-LOCAL_MODULE:= libzipfile
-
-LOCAL_C_INCLUDES += external/zlib
-
-LOCAL_CFLAGS := -Werror
-
-include $(BUILD_STATIC_LIBRARY)
-
-
-# build test_zipfile
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	test_zipfile.c
-
-LOCAL_STATIC_LIBRARIES := libzipfile libunz
-
-LOCAL_MODULE := test_zipfile
-
-LOCAL_C_INCLUDES += external/zlib
-
-LOCAL_CFLAGS := -Werror
-
-include $(BUILD_HOST_EXECUTABLE)
diff --git a/libzipfile/MODULE_LICENSE_APACHE2 b/libzipfile/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/libzipfile/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/libzipfile/NOTICE b/libzipfile/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/libzipfile/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
-   Copyright (c) 2005-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.
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the 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.
-
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
diff --git a/libzipfile/centraldir.c b/libzipfile/centraldir.c
deleted file mode 100644
index 98eef73..0000000
--- a/libzipfile/centraldir.c
+++ /dev/null
@@ -1,275 +0,0 @@
-#include "private.h"

-#include <stdio.h>

-#include <string.h>

-#include <stdlib.h>

-

-#include <utils/Compat.h>

-

-enum {

-    // finding the directory

-    CD_SIGNATURE = 0x06054b50,

-    EOCD_LEN     = 22,        // EndOfCentralDir len, excl. comment

-    MAX_COMMENT_LEN = 65535,

-    MAX_EOCD_SEARCH = MAX_COMMENT_LEN + EOCD_LEN,

-

-    // central directory entries

-    ENTRY_SIGNATURE = 0x02014b50,

-    ENTRY_LEN = 46,          // CentralDirEnt len, excl. var fields

-

-    // local file header

-    LFH_SIZE = 30,

-};

-

-unsigned int

-read_le_int(const unsigned char* buf)

-{

-    return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);

-}

-

-unsigned int

-read_le_short(const unsigned char* buf)

-{

-    return buf[0] | (buf[1] << 8);

-}

-

-static int

-read_central_dir_values(Zipfile* file, const unsigned char* buf, int len)

-{

-    if (len < EOCD_LEN) {

-        // looks like ZIP file got truncated

-        fprintf(stderr, " Zip EOCD: expected >= %d bytes, found %d\n",

-                EOCD_LEN, len);

-        return -1;

-    }

-

-    file->disknum = read_le_short(&buf[0x04]);

-    file->diskWithCentralDir = read_le_short(&buf[0x06]);

-    file->entryCount = read_le_short(&buf[0x08]);

-    file->totalEntryCount = read_le_short(&buf[0x0a]);

-    file->centralDirSize = read_le_int(&buf[0x0c]);

-    file->centralDirOffest = read_le_int(&buf[0x10]);

-    file->commentLen = read_le_short(&buf[0x14]);

-

-    if (file->commentLen > 0) {

-        if (EOCD_LEN + file->commentLen > len) {

-            fprintf(stderr, "EOCD(%d) + comment(%d) exceeds len (%d)\n",

-                    EOCD_LEN, file->commentLen, len);

-            return -1;

-        }

-        file->comment = buf + EOCD_LEN;

-    }

-

-    return 0;

-}

-

-static const int kCompressionStored = 0x0;

-static const int kCompressionDeflate = 0x8;

-

-static int

-read_central_directory_entry(Zipfile* file, Zipentry* entry,

-                const unsigned char** buf, ssize_t* len)

-{

-    const unsigned char* p;

-    size_t remaining;

-    const unsigned char* bufLimit;

-

-    unsigned short  extraFieldLength;

-    unsigned short  fileCommentLength;

-    unsigned long   localHeaderRelOffset;

-    unsigned int dataOffset;

-

-    p = *buf;

-    remaining = *len;

-    bufLimit = file->buf + file->bufsize;

-

-    if (*len < ENTRY_LEN) {

-        fprintf(stderr, "cde entry not large enough\n");

-        return -1;

-    }

-

-    if (read_le_int(&p[0x00]) != ENTRY_SIGNATURE) {

-        fprintf(stderr, "Whoops: didn't find expected signature\n");

-        return -1;

-    }

-

-    entry->compressionMethod = read_le_short(&p[0x0a]);

-    entry->compressedSize = read_le_int(&p[0x14]);

-    entry->uncompressedSize = read_le_int(&p[0x18]);

-    entry->fileNameLength = read_le_short(&p[0x1c]);

-    extraFieldLength = read_le_short(&p[0x1e]);

-    fileCommentLength = read_le_short(&p[0x20]);

-    localHeaderRelOffset = read_le_int(&p[0x2a]);

-

-    p += ENTRY_LEN;

-    remaining -= ENTRY_LEN;

-

-    // filename

-    if (entry->fileNameLength != 0) {

-        if (entry->fileNameLength > remaining) {

-            fprintf(stderr, "cde entry not large enough for file name.\n");

-            return 1;

-        }

-

-        entry->fileName = p;

-    } else {

-        fprintf(stderr, "cde entry does not contain a file name.\n");

-        return 1;

-    }

-    p += entry->fileNameLength;

-    remaining -= entry->fileNameLength;

-

-    // extra field

-    if (extraFieldLength > remaining) {

-        fprintf(stderr, "cde entry not large enough for extra field.\n");

-        return 1;

-    }

-    p += extraFieldLength;

-    remaining -= extraFieldLength;

-

-    // comment, if any

-    if (fileCommentLength > remaining) {

-        fprintf(stderr, "cde entry not large enough for file comment.\n");

-        return 1;

-    }

-

-    p += fileCommentLength;

-    remaining -= fileCommentLength;

-

-    *buf = p;

-    *len = remaining;

-

-    // the size of the extraField in the central dir is how much data there is,

-    // but the one in the local file header also contains some padding.

-    p = file->buf + localHeaderRelOffset;

-    if (p >= bufLimit) {

-      fprintf(stderr, "Invalid local header offset for entry.\n");

-      return 1;

-    }

-

-    extraFieldLength = read_le_short(&p[0x1c]);

-

-    dataOffset = localHeaderRelOffset + LFH_SIZE

-        + entry->fileNameLength + extraFieldLength;

-    entry->data = file->buf + dataOffset;

-

-    // Sanity check: make sure that the start of the entry data is within

-    // our allocated buffer.

-    if ((entry->data < file->buf) || (entry->data >= bufLimit)) {

-      fprintf(stderr, "Invalid data offset for entry.\n");

-      return 1;

-    }

-

-    // Sanity check: make sure that the end of the entry data is within

-    // our allocated buffer. We need to look at the uncompressedSize for

-    // stored entries and the compressed size for deflated entries.

-    if ((entry->compressionMethod == kCompressionStored) &&

-        (entry->uncompressedSize > (unsigned int) (bufLimit - entry->data))) {

-      fprintf(stderr, "Invalid uncompressed size for stored entry.\n");

-      return 1;

-    }

-    if ((entry->compressionMethod == kCompressionDeflate) &&

-        (entry->compressedSize > (unsigned int) (bufLimit - entry->data))) {

-      fprintf(stderr, "Invalid uncompressed size for deflated entry.\n");

-      return 1;

-    }

-#if 0

-    printf("file->buf=%p entry->data=%p dataOffset=%x localHeaderRelOffset=%d "

-           "entry->fileNameLength=%d extraFieldLength=%d\n",

-           file->buf, entry->data, dataOffset, localHeaderRelOffset,

-           entry->fileNameLength, extraFieldLength);

-#endif

-    return 0;

-}

-

-/*

- * Find the central directory and read the contents.

- *

- * The fun thing about ZIP archives is that they may or may not be

- * readable from start to end.  In some cases, notably for archives

- * that were written to stdout, the only length information is in the

- * central directory at the end of the file.

- *

- * Of course, the central directory can be followed by a variable-length

- * comment field, so we have to scan through it backwards.  The comment

- * is at most 64K, plus we have 18 bytes for the end-of-central-dir stuff

- * itself, plus apparently sometimes people throw random junk on the end

- * just for the fun of it.

- *

- * This is all a little wobbly.  If the wrong value ends up in the EOCD

- * area, we're hosed.  This appears to be the way that everbody handles

- * it though, so we're in pretty good company if this fails.

- */

-int

-read_central_dir(Zipfile *file)

-{

-    int err;

-

-    const unsigned char* buf = file->buf;

-    ZD_TYPE bufsize = file->bufsize;

-    const unsigned char* eocd;

-    const unsigned char* p;

-    const unsigned char* start;

-    ssize_t len;

-    int i;

-

-    // too small to be a ZIP archive?

-    if (bufsize < EOCD_LEN) {

-        fprintf(stderr, "Length is " ZD " -- too small\n", bufsize);

-        goto bail;

-    }

-

-    // find the end-of-central-dir magic

-    if (bufsize > MAX_EOCD_SEARCH) {

-        start = buf + bufsize - MAX_EOCD_SEARCH;

-    } else {

-        start = buf;

-    }

-    p = buf + bufsize - 4;

-    while (p >= start) {

-        if (*p == 0x50 && read_le_int(p) == CD_SIGNATURE) {

-            eocd = p;

-            break;

-        }

-        p--;

-    }

-    if (p < start) {

-        fprintf(stderr, "EOCD not found, not Zip\n");

-        goto bail;

-    }

-

-    // extract eocd values

-    err = read_central_dir_values(file, eocd, (buf+bufsize)-eocd);

-    if (err != 0) {

-        goto bail;

-    }

-

-    if (file->disknum != 0

-          || file->diskWithCentralDir != 0

-          || file->entryCount != file->totalEntryCount) {

-        fprintf(stderr, "Archive spanning not supported\n");

-        goto bail;

-    }

-

-    // Loop through and read the central dir entries.

-    p = buf + file->centralDirOffest;

-    len = (buf+bufsize)-p;

-    for (i=0; i < file->totalEntryCount; i++) {

-        Zipentry* entry = malloc(sizeof(Zipentry));

-        memset(entry, 0, sizeof(Zipentry));

-

-        err = read_central_directory_entry(file, entry, &p, &len);

-        if (err != 0) {

-            fprintf(stderr, "read_central_directory_entry failed\n");

-            free(entry);

-            goto bail;

-        }

-

-        // add it to our list

-        entry->next = file->entries;

-        file->entries = entry;

-    }

-

-    return 0;

-bail:

-    return -1;

-}

diff --git a/libzipfile/private.h b/libzipfile/private.h
deleted file mode 100644
index 06f788d..0000000
--- a/libzipfile/private.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef PRIVATE_H

-#define PRIVATE_H

-

-#include <stddef.h>

-#include <stdint.h>

-#include <stdio.h>

-#include <string.h>

-#include <stdlib.h>

-

-typedef struct Zipentry {

-    unsigned long fileNameLength;

-    const unsigned char* fileName;

-    unsigned short compressionMethod;

-    unsigned int uncompressedSize;

-    unsigned int compressedSize;

-    const unsigned char* data;

-    

-    struct Zipentry* next;

-} Zipentry;

-

-typedef struct Zipfile

-{

-    const unsigned char *buf;

-    ssize_t bufsize;

-

-    // Central directory

-    unsigned short  disknum;            //mDiskNumber;

-    unsigned short  diskWithCentralDir; //mDiskWithCentralDir;

-    unsigned short  entryCount;         //mNumEntries;

-    unsigned short  totalEntryCount;    //mTotalNumEntries;

-    unsigned int    centralDirSize;     //mCentralDirSize;

-    unsigned int    centralDirOffest;  // offset from first disk  //mCentralDirOffset;

-    unsigned short  commentLen;         //mCommentLen;

-    const unsigned char*  comment;            //mComment;

-

-    Zipentry* entries;

-} Zipfile;

-

-int read_central_dir(Zipfile* file);

-

-unsigned int read_le_int(const unsigned char* buf);

-unsigned int read_le_short(const unsigned char* buf);

-

-#endif // PRIVATE_H

-

diff --git a/libzipfile/test_zipfile.c b/libzipfile/test_zipfile.c
deleted file mode 100644
index a2f6bc7..0000000
--- a/libzipfile/test_zipfile.c
+++ /dev/null
@@ -1,93 +0,0 @@
-#include <zipfile/zipfile.h>

-#include <string.h>

-#include <stdio.h>

-#include <stdlib.h>

-

-void dump_zipfile(FILE* to, zipfile_t file);

-

-int

-main(int argc, char** argv)

-{

-    FILE* f;

-    size_t size, unsize;

-    void* buf;

-    void* scratch;

-    zipfile_t zip;

-    zipentry_t entry;

-    int err;

-    enum { HUH, LIST, UNZIP } what = HUH;

-

-    if (strcmp(argv[2], "-l") == 0 && argc == 3) {

-        what = LIST;

-    }

-    else if (strcmp(argv[2], "-u") == 0 && argc == 5) {

-        what = UNZIP;

-    }

-    else {

-        fprintf(stderr, "usage: test_zipfile ZIPFILE -l\n"

-                        "          lists the files in the zipfile\n"

-                        "       test_zipfile ZIPFILE -u FILENAME SAVETO\n"

-                        "          saves FILENAME from the zip file into SAVETO\n");

-        return 1;

-    }

-    

-    f = fopen(argv[1], "r");

-    if (f == NULL) {

-        fprintf(stderr, "couldn't open %s\n", argv[1]);

-        return 1;

-    }

-

-    fseek(f, 0, SEEK_END);

-    size = ftell(f);

-    rewind(f);

-    

-    buf = malloc(size);

-    fread(buf, 1, size, f);

-

-    zip = init_zipfile(buf, size);

-    if (zip == NULL) {

-        fprintf(stderr, "inti_zipfile failed\n");

-        return 1;

-    }

-

-    fclose(f);

-

-

-    switch (what)

-    {

-        case HUH:

-            break;

-        case LIST:

-            dump_zipfile(stdout, zip);

-            break;

-        case UNZIP:

-            entry = lookup_zipentry(zip, argv[3]);

-            if (entry == NULL) {

-                fprintf(stderr, "zip file '%s' does not contain file '%s'\n",

-                                argv[1], argv[1]);

-                return 1;

-            }

-            f = fopen(argv[4], "w");

-            if (f == NULL) {

-                fprintf(stderr, "can't open file for writing '%s'\n", argv[4]);

-                return 1;

-            }

-            unsize = get_zipentry_size(entry);

-            size = unsize * 1.001;

-            scratch = malloc(size);

-            err = decompress_zipentry(entry, scratch, size);

-            if (err != 0) {

-                fprintf(stderr, "error decompressing file\n");

-                return 1;

-            }

-            fwrite(scratch, unsize, 1, f);

-            free(scratch);

-            fclose(f);

-            break;

-    }

-    

-    free(buf);

-

-    return 0;

-}

-

diff --git a/libzipfile/zipfile.c b/libzipfile/zipfile.c
deleted file mode 100644
index b903fcf..0000000
--- a/libzipfile/zipfile.c
+++ /dev/null
@@ -1,159 +0,0 @@
-#include <zipfile/zipfile.h>
-
-#include "private.h"
-#include <stdlib.h>
-#include <string.h>
-#include <zlib.h>
-#define DEF_MEM_LEVEL 8                // normally in zutil.h?
-
-zipfile_t
-init_zipfile(const void* data, size_t size)
-{
-    int err;
-
-    Zipfile *file = malloc(sizeof(Zipfile));
-    if (file == NULL) return NULL;
-    memset(file, 0, sizeof(Zipfile));
-    file->buf = data;
-    file->bufsize = size;
-
-    err = read_central_dir(file);
-    if (err != 0) goto fail;
-
-    return file;
-fail:
-    free(file);
-    return NULL;
-}
-
-void
-release_zipfile(zipfile_t f)
-{
-    Zipfile* file = (Zipfile*)f;
-    Zipentry* entry = file->entries;
-    while (entry) {
-        Zipentry* next = entry->next;
-        free(entry);
-        entry = next;
-    }
-    free(file);
-}
-
-zipentry_t
-lookup_zipentry(zipfile_t f, const char* entryName)
-{
-    Zipfile* file = (Zipfile*)f;
-    Zipentry* entry = file->entries;
-    while (entry) {
-        if (0 == memcmp(entryName, entry->fileName, entry->fileNameLength)) {
-            return entry;
-        }
-        entry = entry->next;
-    }
-    return NULL;
-}
-
-size_t
-get_zipentry_size(zipentry_t entry)
-{
-    return ((Zipentry*)entry)->uncompressedSize;
-}
-
-char*
-get_zipentry_name(zipentry_t entry)
-{
-    Zipentry* e = (Zipentry*)entry;
-    int l = e->fileNameLength;
-    char* s = malloc(l+1);
-    memcpy(s, e->fileName, l);
-    s[l] = '\0';
-    return s;
-}
-
-enum {
-    STORED = 0,
-    DEFLATED = 8
-};
-
-static int
-uninflate(unsigned char* out, int unlen, const unsigned char* in, int clen)
-{
-    z_stream zstream;
-    int err = 0;
-    int zerr;
-
-    memset(&zstream, 0, sizeof(zstream));
-    zstream.zalloc = Z_NULL;
-    zstream.zfree = Z_NULL;
-    zstream.opaque = Z_NULL;
-    zstream.next_in = (void*)in;
-    zstream.avail_in = clen;
-    zstream.next_out = (Bytef*) out;
-    zstream.avail_out = unlen;
-    zstream.data_type = Z_UNKNOWN;
-
-    // Use the undocumented "negative window bits" feature to tell zlib
-    // that there's no zlib header waiting for it.
-    zerr = inflateInit2(&zstream, -MAX_WBITS);
-    if (zerr != Z_OK) {
-        return -1;
-    }
-
-    // uncompress the data
-    zerr = inflate(&zstream, Z_FINISH);
-    if (zerr != Z_STREAM_END) {
-        fprintf(stderr, "zerr=%d Z_STREAM_END=%d total_out=%lu\n", zerr, Z_STREAM_END,
-                    zstream.total_out);
-        err = -1;
-    }
-
-     inflateEnd(&zstream);
-    return err;
-}
-
-int
-decompress_zipentry(zipentry_t e, void* buf, int bufsize)
-{
-    Zipentry* entry = (Zipentry*)e;
-    switch (entry->compressionMethod)
-    {
-        case STORED:
-            memcpy(buf, entry->data, entry->uncompressedSize);
-            return 0;
-        case DEFLATED:
-            return uninflate(buf, bufsize, entry->data, entry->compressedSize);
-        default:
-            return -1;
-    }
-}
-
-void
-dump_zipfile(FILE* to, zipfile_t file)
-{
-    Zipfile* zip = (Zipfile*)file;
-    Zipentry* entry = zip->entries;
-    int i;
-
-    fprintf(to, "entryCount=%d\n", zip->entryCount);
-    for (i=0; i<zip->entryCount; i++) {
-        fprintf(to, "  file \"");
-        fwrite(entry->fileName, entry->fileNameLength, 1, to);
-        fprintf(to, "\"\n");
-        entry = entry->next;
-    }
-}
-
-zipentry_t
-iterate_zipfile(zipfile_t file, void** cookie)
-{
-    Zipentry* entry = (Zipentry*)*cookie;
-    if (entry == NULL) {
-        Zipfile* zip = (Zipfile*)file;
-        *cookie = zip->entries;
-        return *cookie;
-    } else {
-        entry = entry->next;
-        *cookie = entry;
-        return entry;
-    }
-}
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index a534a24..7bbc811 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -607,7 +607,6 @@
 static int find_and_kill_process(int other_free, int other_file, bool first)
 {
     int i;
-    int r;
     int min_score_adj = OOM_ADJUST_MAX + 1;
     int minfree = 0;
     int killed_size = 0;
@@ -643,7 +642,6 @@
 }
 
 static void mp_event(uint32_t events __unused) {
-    int i;
     int ret;
     unsigned long long evcount;
     struct sysmeminfo mi;
diff --git a/logcat/Android.mk b/logcat/Android.mk
index f46a4de..7115f9b 100644
--- a/logcat/Android.mk
+++ b/logcat/Android.mk
@@ -5,7 +5,7 @@
 
 LOCAL_SRC_FILES:= logcat.cpp event.logtags
 
-LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
 
 LOCAL_MODULE := logcat
 
diff --git a/logcat/event.logtags b/logcat/event.logtags
index 1b5c6f4..909f8e2 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -21,6 +21,7 @@
 # 2: long
 # 3: string
 # 4: list
+# 5: float
 #
 # The data unit is a number taken from the following list:
 # 1: Number of objects
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 858e56c..e598bb8 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -1,29 +1,41 @@
-// Copyright 2006-2014 The Android Open Source Project
+// Copyright 2006-2015 The Android Open Source Project
 
+#include <arpa/inet.h>
 #include <assert.h>
 #include <ctype.h>
+#include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <math.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdarg.h>
 #include <string.h>
-#include <signal.h>
-#include <time.h>
-#include <unistd.h>
+#include <sys/cdefs.h>
+#include <sys/resource.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
-#include <arpa/inet.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
 
+#include <memory>
+#include <string>
+
+#include <base/file.h>
+#include <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/logger.h>
 #include <log/logd.h>
+#include <log/logger.h>
 #include <log/logprint.h>
-#include <log/event_tag_map.h>
+#include <utils/threads.h>
 
-#define DEFAULT_LOG_ROTATE_SIZE_KBYTES 16
 #define DEFAULT_MAX_ROTATED_LOGS 4
 
 static AndroidLogFormat * g_logformat;
@@ -37,16 +49,16 @@
     struct logger *logger;
     struct logger_list *logger_list;
     bool printed;
-    char label;
 
     log_device_t* next;
 
-    log_device_t(const char* d, bool b, char l) {
+    log_device_t(const char* d, bool b) {
         device = d;
         binary = b;
-        label = l;
         next = NULL;
         printed = false;
+        logger = NULL;
+        logger_list = NULL;
     }
 };
 
@@ -55,14 +67,16 @@
 /* Global Variables */
 
 static const char * g_outputFileName = NULL;
-static int g_logRotateSizeKBytes = 0;                   // 0 means "no log rotation"
-static int g_maxRotatedLogs = DEFAULT_MAX_ROTATED_LOGS; // 0 means "unbounded"
+// 0 means "no log rotation"
+static size_t g_logRotateSizeKBytes = 0;
+// 0 means "unbounded"
+static size_t g_maxRotatedLogs = DEFAULT_MAX_ROTATED_LOGS;
 static int g_outFD = -1;
-static off_t g_outByteCount = 0;
+static size_t g_outByteCount = 0;
 static int g_printBinary = 0;
-static int g_devCount = 0;
+static int g_devCount = 0;                              // >1 means multiple
 
-static EventTagMap* g_eventTagMap = NULL;
+__noreturn static void logcat_panic(bool showHelp, const char *fmt, ...) __printflike(2,3);
 
 static int openLogFile (const char *pathname)
 {
@@ -80,18 +94,28 @@
 
     close(g_outFD);
 
+    // Compute the maximum number of digits needed to count up to g_maxRotatedLogs in decimal.
+    // eg: g_maxRotatedLogs == 30 -> log10(30) == 1.477 -> maxRotationCountDigits == 2
+    int maxRotationCountDigits =
+            (g_maxRotatedLogs > 0) ? (int) (floor(log10(g_maxRotatedLogs) + 1)) : 0;
+
     for (int i = g_maxRotatedLogs ; i > 0 ; i--) {
         char *file0, *file1;
 
-        asprintf(&file1, "%s.%d", g_outputFileName, i);
+        asprintf(&file1, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i);
 
         if (i - 1 == 0) {
             asprintf(&file0, "%s", g_outputFileName);
         } else {
-            asprintf(&file0, "%s.%d", g_outputFileName, i - 1);
+            asprintf(&file0, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i - 1);
         }
 
-        err = rename (file0, file1);
+        if (!file0 || !file1) {
+            perror("while rotating log files");
+            break;
+        }
+
+        err = rename(file0, file1);
 
         if (err < 0 && errno != ENOENT) {
             perror("while rotating log files");
@@ -101,11 +125,10 @@
         free(file0);
     }
 
-    g_outFD = openLogFile (g_outputFileName);
+    g_outFD = openLogFile(g_outputFileName);
 
     if (g_outFD < 0) {
-        perror ("couldn't open output file");
-        exit(-1);
+        logcat_panic(false, "couldn't open output file");
     }
 
     g_outByteCount = 0;
@@ -127,8 +150,15 @@
     char binaryMsgBuf[1024];
 
     if (dev->binary) {
+        static bool hasOpenedEventTagMap = false;
+        static EventTagMap *eventTagMap = NULL;
+
+        if (!eventTagMap && !hasOpenedEventTagMap) {
+            eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+            hasOpenedEventTagMap = true;
+        }
         err = android_log_processBinaryLogBuffer(&buf->entry_v1, &entry,
-                                                 g_eventTagMap,
+                                                 eventTagMap,
                                                  binaryMsgBuf,
                                                  sizeof(binaryMsgBuf));
         //printf(">>> pri=%d len=%d msg='%s'\n",
@@ -141,21 +171,10 @@
     }
 
     if (android_log_shouldPrintLine(g_logformat, entry.tag, entry.priority)) {
-        if (false && g_devCount > 1) {
-            binaryMsgBuf[0] = dev->label;
-            binaryMsgBuf[1] = ' ';
-            bytesWritten = write(g_outFD, binaryMsgBuf, 2);
-            if (bytesWritten < 0) {
-                perror("output error");
-                exit(-1);
-            }
-        }
-
         bytesWritten = android_log_printLogLine(g_logformat, g_outFD, &entry);
 
         if (bytesWritten < 0) {
-            perror("output error");
-            exit(-1);
+            logcat_panic(false, "output error");
         }
     }
 
@@ -172,18 +191,18 @@
     return;
 }
 
-static void maybePrintStart(log_device_t* dev) {
-    if (!dev->printed) {
-        dev->printed = true;
+static void maybePrintStart(log_device_t* dev, bool printDividers) {
+    if (!dev->printed || printDividers) {
         if (g_devCount > 1 && !g_printBinary) {
             char buf[1024];
-            snprintf(buf, sizeof(buf), "--------- beginning of %s\n",
+            snprintf(buf, sizeof(buf), "--------- %s %s\n",
+                     dev->printed ? "switch to" : "beginning of",
                      dev->device);
             if (write(g_outFD, buf, strlen(buf)) < 0) {
-                perror("output error");
-                exit(-1);
+                logcat_panic(false, "output error");
             }
         }
+        dev->printed = true;
     }
 }
 
@@ -194,16 +213,36 @@
         g_outFD = STDOUT_FILENO;
 
     } else {
-        struct stat statbuf;
+        if (set_sched_policy(0, SP_BACKGROUND) < 0) {
+            fprintf(stderr, "failed to set background scheduling policy\n");
+        }
+
+        struct sched_param param;
+        memset(&param, 0, sizeof(param));
+        if (sched_setscheduler((pid_t) 0, SCHED_BATCH, &param) < 0) {
+            fprintf(stderr, "failed to set to batch scheduler\n");
+        }
+
+        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) {
-            perror ("couldn't open output file");
-            exit(-1);
+            logcat_panic(false, "couldn't open output file");
         }
 
-        fstat(g_outFD, &statbuf);
+        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;
     }
@@ -215,12 +254,14 @@
 
     fprintf(stderr, "options include:\n"
                     "  -s              Set default filter to silent.\n"
-                    "                  Like specifying filterspec '*:s'\n"
-                    "  -f <filename>   Log to file. Default to stdout\n"
-                    "  -r [<kbytes>]   Rotate log every kbytes. (16 if unspecified). Requires -f\n"
+                    "                  Like specifying filterspec '*:S'\n"
+                    "  -f <filename>   Log to file. Default is stdout\n"
+                    "  -r <kbytes>     Rotate log every kbytes. Requires -f\n"
                     "  -n <count>      Sets max number of rotated logs to <count>, default 4\n"
-                    "  -v <format>     Sets the log print format, where <format> is one of:\n\n"
-                    "                  brief process tag thread raw time threadtime long\n\n"
+                    "  -v <format>     Sets the log print format, where <format> is:\n\n"
+                    "                      brief color long printable process raw tag thread\n"
+                    "                      threadtime time usec\n\n"
+                    "  -D              print dividers between each log buffer\n"
                     "  -c              clear (flush) the entire log and exit\n"
                     "  -d              dump the log and then exit (don't block)\n"
                     "  -t <count>      print only the most recent <count> lines (implies -d)\n"
@@ -229,6 +270,7 @@
                     "  -T '<time>'     print most recent lines since specified time (not imply -d)\n"
                     "                  count is pure numerical, time is 'MM-DD hh:mm:ss.mmm'\n"
                     "  -g              get the size of the log's ring buffer and exit\n"
+                    "  -L              dump logs from prior to last reboot\n"
                     "  -b <buffer>     Request alternate ring buffer, 'main', 'system', 'radio',\n"
                     "                  'events', 'crash' or 'all'. Multiple -b parameters are\n"
                     "                  allowed and results are interleaved. The default is\n"
@@ -248,26 +290,21 @@
     fprintf(stderr,"\nfilterspecs are a series of \n"
                    "  <tag>[:priority]\n\n"
                    "where <tag> is a log component tag (or * for all) and priority is:\n"
-                   "  V    Verbose\n"
-                   "  D    Debug\n"
+                   "  V    Verbose (default for <tag>)\n"
+                   "  D    Debug (default for '*')\n"
                    "  I    Info\n"
                    "  W    Warn\n"
                    "  E    Error\n"
                    "  F    Fatal\n"
-                   "  S    Silent (supress all output)\n"
-                   "\n'*' means '*:d' and <tag> by itself means <tag>:v\n"
-                   "\nIf not specified on the commandline, filterspec is set from ANDROID_LOG_TAGS.\n"
-                   "If no filterspec is found, filter defaults to '*:I'\n"
-                   "\nIf not specified with -v, format is set from ANDROID_PRINTF_LOG\n"
-                   "or defaults to \"brief\"\n\n");
-
-
-
+                   "  S    Silent (suppress all output)\n"
+                   "\n'*' by itself means '*:D' and <tag> by itself means <tag>:V.\n"
+                   "If no '*' filterspec or -s on command line, all filter defaults to '*:V'.\n"
+                   "eg: '*:S <tag>' prints only <tag>, '<tag>:S' suppresses all <tag> log messages.\n"
+                   "\nIf not specified on the command line, filterspec is set from ANDROID_LOG_TAGS.\n"
+                   "\nIf not specified with -v on command line, format is set from ANDROID_PRINTF_LOG\n"
+                   "or defaults to \"threadtime\"\n\n");
 }
 
-
-} /* namespace android */
-
 static int setLogFormat(const char * formatString)
 {
     static AndroidLogPrintFormat format;
@@ -279,9 +316,7 @@
         return -1;
     }
 
-    android_log_setPrintFormat(g_logformat, format);
-
-    return 0;
+    return android_log_setPrintFormat(g_logformat, format);
 }
 
 static const char multipliers[][2] = {
@@ -308,8 +343,126 @@
     return multipliers[i];
 }
 
+/*String to unsigned int, returns -1 if it fails*/
+static bool getSizeTArg(char *ptr, size_t *val, size_t min = 0,
+                        size_t max = SIZE_MAX)
+{
+    char *endp;
+    errno = 0;
+    size_t ret = (size_t) strtoll(ptr, &endp, 0);
+
+    if (endp[0] != '\0' || errno != 0 ) {
+        return false;
+    }
+
+    if (ret >  max || ret <  min) {
+        return false;
+    }
+
+    *val = ret;
+    return true;
+}
+
+static void logcat_panic(bool showHelp, const char *fmt, ...)
+{
+    va_list  args;
+    va_start(args, fmt);
+    vfprintf(stderr, fmt,  args);
+    va_end(args);
+
+    if (showHelp) {
+       show_help(getprogname());
+    }
+
+    exit(EXIT_FAILURE);
+}
+
+static const char g_defaultTimeFormat[] = "%m-%d %H:%M:%S.%q";
+
+// Find last logged line in gestalt of all matching existing output files
+static log_time lastLogTime(char *outputFileName) {
+    log_time retval(log_time::EPOCH);
+    if (!outputFileName) {
+        return retval;
+    }
+
+    log_time now(CLOCK_REALTIME);
+
+    std::string directory;
+    char *file = strrchr(outputFileName, '/');
+    if (!file) {
+        directory = ".";
+        file = outputFileName;
+    } else {
+        *file = '\0';
+        directory = outputFileName;
+        *file = '/';
+        ++file;
+    }
+    size_t len = strlen(file);
+    log_time modulo(0, NS_PER_SEC);
+    std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(directory.c_str()), closedir);
+    struct dirent *dp;
+    while ((dp = readdir(dir.get())) != NULL) {
+        if ((dp->d_type != DT_REG)
+                || strncmp(dp->d_name, file, len)
+                || (dp->d_name[len]
+                    && ((dp->d_name[len] != '.')
+                        || !isdigit(dp->d_name[len+1])))) {
+            continue;
+        }
+
+        std::string file_name = directory;
+        file_name += "/";
+        file_name += dp->d_name;
+        std::string file;
+        if (!android::base::ReadFileToString(file_name, &file)) {
+            continue;
+        }
+
+        bool found = false;
+        for (const auto& line : android::base::Split(file, "\n")) {
+            log_time t(log_time::EPOCH);
+            char *ep = t.strptime(line.c_str(), g_defaultTimeFormat);
+            if (!ep || (*ep != ' ')) {
+                continue;
+            }
+            // determine the time precision of the logs (eg: msec or usec)
+            for (unsigned long mod = 1UL; mod < modulo.tv_nsec; mod *= 10) {
+                if (t.tv_nsec % (mod * 10)) {
+                    modulo.tv_nsec = mod;
+                    break;
+                }
+            }
+            // We filter any times later than current as we may not have the
+            // year stored with each log entry. Also, since it is possible for
+            // entries to be recorded out of order (very rare) we select the
+            // maximum we find just in case.
+            if ((t < now) && (t > retval)) {
+                retval = t;
+                found = true;
+            }
+        }
+        // We count on the basename file to be the definitive end, so stop here.
+        if (!dp->d_name[len] && found) {
+            break;
+        }
+    }
+    if (retval == log_time::EPOCH) {
+        return retval;
+    }
+    // tail_time prints matching or higher, round up by the modulo to prevent
+    // a replay of the last entry we have just checked.
+    retval += modulo;
+    return retval;
+}
+
+} /* namespace android */
+
+
 int main(int argc, char **argv)
 {
+    using namespace android;
     int err;
     int hasSetLogFormat = 0;
     int clearLog = 0;
@@ -318,13 +471,13 @@
     int getPruneList = 0;
     char *setPruneList = NULL;
     int printStatistics = 0;
-    int mode = O_RDONLY;
+    int mode = ANDROID_LOG_RDONLY;
     const char *forceFilters = NULL;
     log_device_t* devices = NULL;
     log_device_t* dev;
-    bool needBinary = false;
+    bool printDividers = false;
     struct logger_list *logger_list;
-    unsigned int tail_lines = 0;
+    size_t tail_lines = 0;
     log_time tail_time(log_time::EPOCH);
 
     signal(SIGPIPE, exit);
@@ -332,14 +485,14 @@
     g_logformat = android_log_format_new();
 
     if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
-        android::show_help(argv[0]);
-        exit(0);
+        show_help(argv[0]);
+        return EXIT_SUCCESS;
     }
 
     for (;;) {
         int ret;
 
-        ret = getopt(argc, argv, "cdt:T:gG:sQf:r:n:v:b:BSpP:");
+        ret = getopt(argc, argv, ":cdDLt:T:gG:sQf:r:n:v:b:BSpP:");
 
         if (ret < 0) {
             break;
@@ -353,25 +506,27 @@
 
             case 'c':
                 clearLog = 1;
-                mode = O_WRONLY;
+                mode |= ANDROID_LOG_WRONLY;
+            break;
+
+            case 'L':
+                mode |= ANDROID_LOG_PSTORE;
             break;
 
             case 'd':
-                mode = O_RDONLY | O_NDELAY;
+                mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK;
             break;
 
             case 't':
-                mode = O_RDONLY | O_NDELAY;
+                mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK;
                 /* FALLTHRU */
             case 'T':
                 if (strspn(optarg, "0123456789") != strlen(optarg)) {
-                    char *cp = tail_time.strptime(optarg,
-                                                  log_time::default_format);
+                    char *cp = tail_time.strptime(optarg, g_defaultTimeFormat);
                     if (!cp) {
-                        fprintf(stderr,
-                                "ERROR: -%c \"%s\" not in \"%s\" time format\n",
-                                ret, optarg, log_time::default_format);
-                        exit(1);
+                        logcat_panic(false,
+                                    "-%c \"%s\" not in \"%s\" time format\n",
+                                    ret, optarg, g_defaultTimeFormat);
                     }
                     if (*cp) {
                         char c = *cp;
@@ -382,8 +537,7 @@
                         *cp = c;
                     }
                 } else {
-                    tail_lines = atoi(optarg);
-                    if (!tail_lines) {
+                    if (!getSizeTArg(optarg, &tail_lines, 1)) {
                         fprintf(stderr,
                                 "WARNING: -%c %s invalid, setting to 1\n",
                                 ret, optarg);
@@ -392,18 +546,20 @@
                 }
             break;
 
+            case 'D':
+                printDividers = true;
+            break;
+
             case 'g':
                 getLogSize = 1;
             break;
 
             case 'G': {
-                // would use atol if not for the multiplier
-                char *cp = optarg;
-                setLogSize = 0;
-                while (('0' <= *cp) && (*cp <= '9')) {
-                    setLogSize *= 10;
-                    setLogSize += *cp - '0';
-                    ++cp;
+                char *cp;
+                if (strtoll(optarg, &cp, 0) > 0) {
+                    setLogSize = strtoll(optarg, &cp, 0);
+                } else {
+                    setLogSize = 0;
                 }
 
                 switch(*cp) {
@@ -428,7 +584,7 @@
 
                 if (!setLogSize) {
                     fprintf(stderr, "ERROR: -G <num><multiplier>\n");
-                    exit(1);
+                    return EXIT_FAILURE;
                 }
             }
             break;
@@ -449,101 +605,75 @@
                         delete dev;
                     }
 
-                    dev = devices = new log_device_t("main", false, 'm');
-                    android::g_devCount = 1;
-                    if (android_name_to_log_id("system") == LOG_ID_SYSTEM) {
-                        dev->next = new log_device_t("system", false, 's');
-                        if (dev->next) {
-                            dev = dev->next;
-                            android::g_devCount++;
+                    devices = dev = NULL;
+                    g_devCount = 0;
+                    for(int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
+                        const char *name = android_log_id_to_name((log_id_t)i);
+                        log_id_t log_id = android_name_to_log_id(name);
+
+                        if (log_id != (log_id_t)i) {
+                            continue;
                         }
-                    }
-                    if (android_name_to_log_id("radio") == LOG_ID_RADIO) {
-                        dev->next = new log_device_t("radio", false, 'r');
-                        if (dev->next) {
-                            dev = dev->next;
-                            android::g_devCount++;
+
+                        bool binary = strcmp(name, "events") == 0;
+                        log_device_t* d = new log_device_t(name, binary);
+
+                        if (dev) {
+                            dev->next = d;
+                            dev = d;
+                        } else {
+                            devices = dev = d;
                         }
-                    }
-                    if (android_name_to_log_id("events") == LOG_ID_EVENTS) {
-                        dev->next = new log_device_t("events", true, 'e');
-                        if (dev->next) {
-                            dev = dev->next;
-                            android::g_devCount++;
-                            needBinary = true;
-                        }
-                    }
-                    if (android_name_to_log_id("crash") == LOG_ID_CRASH) {
-                        dev->next = new log_device_t("crash", false, 'c');
-                        if (dev->next) {
-                            android::g_devCount++;
-                        }
+                        g_devCount++;
                     }
                     break;
                 }
 
                 bool binary = strcmp(optarg, "events") == 0;
-                if (binary) {
-                    needBinary = true;
-                }
 
                 if (devices) {
                     dev = devices;
                     while (dev->next) {
                         dev = dev->next;
                     }
-                    dev->next = new log_device_t(optarg, binary, optarg[0]);
+                    dev->next = new log_device_t(optarg, binary);
                 } else {
-                    devices = new log_device_t(optarg, binary, optarg[0]);
+                    devices = new log_device_t(optarg, binary);
                 }
-                android::g_devCount++;
+                g_devCount++;
             }
             break;
 
             case 'B':
-                android::g_printBinary = 1;
+                g_printBinary = 1;
             break;
 
             case 'f':
+                if ((tail_time == log_time::EPOCH) && (tail_lines != 0)) {
+                    tail_time = lastLogTime(optarg);
+                }
                 // redirect output to a file
-
-                android::g_outputFileName = optarg;
-
+                g_outputFileName = optarg;
             break;
 
             case 'r':
-                if (optarg == NULL) {
-                    android::g_logRotateSizeKBytes
-                                = DEFAULT_LOG_ROTATE_SIZE_KBYTES;
-                } else {
-                    if (!isdigit(optarg[0])) {
-                        fprintf(stderr,"Invalid parameter to -r\n");
-                        android::show_help(argv[0]);
-                        exit(-1);
-                    }
-                    android::g_logRotateSizeKBytes = atoi(optarg);
+                if (!getSizeTArg(optarg, &g_logRotateSizeKBytes, 1)) {
+                    logcat_panic(true, "Invalid parameter %s to -r\n", optarg);
                 }
             break;
 
             case 'n':
-                if (!isdigit(optarg[0])) {
-                    fprintf(stderr,"Invalid parameter to -r\n");
-                    android::show_help(argv[0]);
-                    exit(-1);
+                if (!getSizeTArg(optarg, &g_maxRotatedLogs, 1)) {
+                    logcat_panic(true, "Invalid parameter %s to -n\n", optarg);
                 }
-
-                android::g_maxRotatedLogs = atoi(optarg);
             break;
 
             case 'v':
                 err = setLogFormat (optarg);
                 if (err < 0) {
-                    fprintf(stderr,"Invalid parameter to -v\n");
-                    android::show_help(argv[0]);
-                    exit(-1);
+                    logcat_panic(true, "Invalid parameter %s to -v\n", optarg);
                 }
-
-                hasSetLogFormat = 1;
+                hasSetLogFormat |= err;
             break;
 
             case 'Q':
@@ -584,8 +714,9 @@
                         force_exit   = 0;
                     }
                     /* if nothing found or invalid filters, exit quietly */
-                    if (force_exit)
-                        exit(0);
+                    if (force_exit) {
+                        return EXIT_SUCCESS;
+                    }
 
                     /* redirect our output to the emulator console */
                     if (console) {
@@ -617,55 +748,53 @@
                 printStatistics = 1;
                 break;
 
+            case ':':
+                logcat_panic(true, "Option -%c needs an argument\n", optopt);
+                break;
+
             default:
-                fprintf(stderr,"Unrecognized Option\n");
-                android::show_help(argv[0]);
-                exit(-1);
-            break;
+                logcat_panic(true, "Unrecognized Option %c\n", optopt);
+                break;
         }
     }
 
     if (!devices) {
-        dev = devices = new log_device_t("main", false, 'm');
-        android::g_devCount = 1;
+        dev = devices = new log_device_t("main", false);
+        g_devCount = 1;
         if (android_name_to_log_id("system") == LOG_ID_SYSTEM) {
-            dev = dev->next = new log_device_t("system", false, 's');
-            android::g_devCount++;
+            dev = dev->next = new log_device_t("system", false);
+            g_devCount++;
         }
         if (android_name_to_log_id("crash") == LOG_ID_CRASH) {
-            dev = dev->next = new log_device_t("crash", false, 'c');
-            android::g_devCount++;
+            dev = dev->next = new log_device_t("crash", false);
+            g_devCount++;
         }
     }
 
-    if (android::g_logRotateSizeKBytes != 0
-        && android::g_outputFileName == NULL
-    ) {
-        fprintf(stderr,"-r requires -f as well\n");
-        android::show_help(argv[0]);
-        exit(-1);
+    if (g_logRotateSizeKBytes != 0 && g_outputFileName == NULL) {
+        logcat_panic(true, "-r requires -f as well\n");
     }
 
-    android::setupOutput();
+    setupOutput();
 
     if (hasSetLogFormat == 0) {
         const char* logFormat = getenv("ANDROID_PRINTF_LOG");
 
         if (logFormat != NULL) {
             err = setLogFormat(logFormat);
-
             if (err < 0) {
                 fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n",
                                     logFormat);
             }
+        } else {
+            setLogFormat("threadtime");
         }
     }
 
     if (forceFilters) {
         err = android_log_addFilterString(g_logformat, forceFilters);
         if (err < 0) {
-            fprintf (stderr, "Invalid filter expression in -logcat option\n");
-            exit(0);
+            logcat_panic(false, "Invalid filter expression in logcat args\n");
         }
     } else if (argc == optind) {
         // Add from environment variable
@@ -675,10 +804,8 @@
             err = android_log_addFilterString(g_logformat, env_tags_orig);
 
             if (err < 0) {
-                fprintf(stderr, "Invalid filter expression in"
-                                    " ANDROID_LOG_TAGS\n");
-                android::show_help(argv[0]);
-                exit(-1);
+                logcat_panic(true,
+                            "Invalid filter expression in ANDROID_LOG_TAGS\n");
             }
         }
     } else {
@@ -687,9 +814,7 @@
             err = android_log_addFilterString(g_logformat, argv[i]);
 
             if (err < 0) {
-                fprintf (stderr, "Invalid filter expression '%s'\n", argv[i]);
-                android::show_help(argv[0]);
-                exit(-1);
+                logcat_panic(true, "Invalid filter expression '%s'\n", argv[i]);
             }
         }
     }
@@ -705,22 +830,20 @@
         dev->logger = android_logger_open(logger_list,
                                           android_name_to_log_id(dev->device));
         if (!dev->logger) {
-            fprintf(stderr, "Unable to open log device '%s'\n", dev->device);
-            exit(EXIT_FAILURE);
+            logcat_panic(false, "Unable to open log device '%s'\n",
+                         dev->device);
         }
 
         if (clearLog) {
             int ret;
             ret = android_logger_clear(dev->logger);
             if (ret) {
-                perror("failed to clear the log");
-                exit(EXIT_FAILURE);
+                logcat_panic(false, "failed to clear the log");
             }
         }
 
         if (setLogSize && android_logger_set_log_size(dev->logger, setLogSize)) {
-            perror("failed to set the log size");
-            exit(EXIT_FAILURE);
+            logcat_panic(false, "failed to set the log size");
         }
 
         if (getLogSize) {
@@ -728,14 +851,12 @@
 
             size = android_logger_get_log_size(dev->logger);
             if (size < 0) {
-                perror("failed to get the log size");
-                exit(EXIT_FAILURE);
+                logcat_panic(false, "failed to get the log size");
             }
 
             readable = android_logger_get_log_readable_size(dev->logger);
             if (readable < 0) {
-                perror("failed to get the readable log size");
-                exit(EXIT_FAILURE);
+                logcat_panic(false, "failed to get the readable log size");
             }
 
             printf("%s: ring buffer is %ld%sb (%ld%sb consumed), "
@@ -749,16 +870,18 @@
     }
 
     if (setPruneList) {
-        size_t len = strlen(setPruneList) + 32; // margin to allow rc
-        char *buf = (char *) malloc(len);
-
-        strcpy(buf, setPruneList);
-        int ret = android_logger_set_prune_list(logger_list, buf, len);
-        free(buf);
-
-        if (ret) {
-            perror("failed to set the prune list");
-            exit(EXIT_FAILURE);
+        size_t len = strlen(setPruneList);
+        /*extra 32 bytes are needed by  android_logger_set_prune_list */
+        size_t bLen = len + 32;
+        char *buf = NULL;
+        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");
+            }
+            free(buf);
+        } else {
+            logcat_panic(false, "failed to set the prune list (alloc)");
         }
     }
 
@@ -768,29 +891,28 @@
 
         for(int retry = 32;
                 (retry >= 0) && ((buf = new char [len]));
-                delete [] buf, --retry) {
+                delete [] buf, buf = NULL, --retry) {
             if (getPruneList) {
                 android_logger_get_prune_list(logger_list, buf, len);
             } else {
                 android_logger_get_statistics(logger_list, buf, len);
             }
             buf[len-1] = '\0';
-            size_t ret = atol(buf) + 1;
-            if (ret < 4) {
+            if (atol(buf) < 3) {
                 delete [] buf;
                 buf = NULL;
                 break;
             }
-            bool check = ret <= len;
-            len = ret;
-            if (check) {
+            size_t ret = atol(buf) + 1;
+            if (ret <= len) {
+                len = ret;
                 break;
             }
+            len = ret;
         }
 
         if (!buf) {
-            perror("failed to read data");
-            exit(EXIT_FAILURE);
+            logcat_panic(false, "failed to read data");
         }
 
         // remove trailing FF
@@ -814,34 +936,33 @@
 
         printf("%s", cp);
         delete [] buf;
-        exit(0);
+        return EXIT_SUCCESS;
     }
 
 
     if (getLogSize) {
-        exit(0);
+        return EXIT_SUCCESS;
     }
     if (setLogSize || setPruneList) {
-        exit(0);
+        return EXIT_SUCCESS;
     }
     if (clearLog) {
-        exit(0);
+        return EXIT_SUCCESS;
     }
 
     //LOG_EVENT_INT(10, 12345);
     //LOG_EVENT_LONG(11, 0x1122334455667788LL);
     //LOG_EVENT_STRING(0, "whassup, doc?");
 
-    if (needBinary)
-        android::g_eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
-
+    dev = NULL;
+    log_device_t unexpected("unexpected", false);
     while (1) {
         struct log_msg log_msg;
+        log_device_t* d;
         int ret = android_logger_list_read(logger_list, &log_msg);
 
         if (ret == 0) {
-            fprintf(stderr, "read: Unexpected EOF!\n");
-            exit(EXIT_FAILURE);
+            logcat_panic(false, "read: unexpected EOF!\n");
         }
 
         if (ret < 0) {
@@ -850,36 +971,37 @@
             }
 
             if (ret == -EIO) {
-                fprintf(stderr, "read: Unexpected EOF!\n");
-                exit(EXIT_FAILURE);
+                logcat_panic(false, "read: unexpected EOF!\n");
             }
             if (ret == -EINVAL) {
-                fprintf(stderr, "read: unexpected length.\n");
-                exit(EXIT_FAILURE);
+                logcat_panic(false, "read: unexpected length.\n");
             }
-            perror("logcat read failure");
-            exit(EXIT_FAILURE);
+            logcat_panic(false, "logcat read failure");
         }
 
-        for(dev = devices; dev; dev = dev->next) {
-            if (android_name_to_log_id(dev->device) == log_msg.id()) {
+        for(d = devices; d; d = d->next) {
+            if (android_name_to_log_id(d->device) == log_msg.id()) {
                 break;
             }
         }
-        if (!dev) {
-            fprintf(stderr, "read: Unexpected log ID!\n");
-            exit(EXIT_FAILURE);
+        if (!d) {
+            g_devCount = 2; // set to Multiple
+            d = &unexpected;
+            d->binary = log_msg.id() == LOG_ID_EVENTS;
         }
 
-        android::maybePrintStart(dev);
-        if (android::g_printBinary) {
-            android::printBinary(&log_msg);
+        if (dev != d) {
+            dev = d;
+            maybePrintStart(dev, printDividers);
+        }
+        if (g_printBinary) {
+            printBinary(&log_msg);
         } else {
-            android::processBuffer(dev, &log_msg);
+            processBuffer(dev, &log_msg);
         }
     }
 
     android_logger_list_free(logger_list);
 
-    return 0;
+    return EXIT_SUCCESS;
 }
diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk
index 015a23d..a28664e 100644
--- a/logcat/tests/Android.mk
+++ b/logcat/tests/Android.mk
@@ -39,7 +39,6 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := $(test_module_prefix)benchmarks
 LOCAL_MODULE_TAGS := $(test_tags)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += $(test_c_flags)
 LOCAL_SRC_FILES := $(benchmark_src_files)
 include $(BUILD_NATIVE_TEST)
@@ -56,7 +55,6 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := $(test_module_prefix)unit-tests
 LOCAL_MODULE_TAGS := $(test_tags)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += $(test_c_flags)
 LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_SRC_FILES := $(test_src_files)
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 85756d5..de2db67 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -243,7 +243,7 @@
 
     FILE *fp;
     ASSERT_TRUE(NULL != (fp = popen(
-      "logcat -b events -t 100 2>/dev/null",
+      "logcat -v brief -b events -t 100 2>/dev/null",
       "r")));
 
     char buffer[5120];
@@ -275,7 +275,7 @@
 
     // NB: crash log only available in user space
     ASSERT_TRUE(NULL != (fp = popen(
-      "logcat -b radio -b events -b system -b main -g 2>/dev/null",
+      "logcat -v brief -b radio -b events -b system -b main -g 2>/dev/null",
       "r")));
 
     char buffer[5120];
@@ -364,7 +364,7 @@
 
     ASSERT_TRUE(NULL != (fp = popen(
       "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
-      " logcat -b events 2>&1",
+      " logcat -v brief -b events 2>&1",
       "r")));
 
     char buffer[5120];
@@ -433,7 +433,7 @@
 
     ASSERT_TRUE(NULL != (fp = popen(
       "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
-      " logcat -b events -T 5 2>&1",
+      " logcat -v brief -b events -T 5 2>&1",
       "r")));
 
     char buffer[5120];
@@ -503,10 +503,16 @@
             int count = 0;
 
             while (fgets(buffer, sizeof(buffer), fp)) {
-                static const char match[] = "4 log.txt";
+                static const char match_1[] = "4 log.txt";
+                static const char match_2[] = "8 log.txt";
+                static const char match_3[] = "12 log.txt";
+                static const char match_4[] = "16 log.txt";
                 static const char total[] = "total ";
 
-                if (!strncmp(buffer, match, sizeof(match) - 1)) {
+                if (!strncmp(buffer, match_1, sizeof(match_1) - 1)
+                 || !strncmp(buffer, match_2, sizeof(match_2) - 1)
+                 || !strncmp(buffer, match_3, sizeof(match_3) - 1)
+                 || !strncmp(buffer, match_4, sizeof(match_4) - 1)) {
                     ++count;
                 } else if (strncmp(buffer, total, sizeof(total) - 1)) {
                     fprintf(stderr, "WARNING: Parse error: %s", buffer);
@@ -520,6 +526,59 @@
     EXPECT_FALSE(system(command));
 }
 
+TEST(logcat, logrotate_suffix) {
+    static const char tmp_out_dir_form[] = "/data/local/tmp/logcat.logrotate.XXXXXX";
+    char tmp_out_dir[sizeof(tmp_out_dir_form)];
+    ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form)));
+
+    static const char logcat_cmd[] = "logcat -b radio -b events -b system -b main"
+                                     " -d -f %s/log.txt -n 10 -r 1";
+    char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd)];
+    sprintf(command, logcat_cmd, tmp_out_dir);
+
+    int ret;
+    EXPECT_FALSE((ret = system(command)));
+    if (!ret) {
+        sprintf(command, "ls %s 2>/dev/null", tmp_out_dir);
+
+        FILE *fp;
+        EXPECT_TRUE(NULL != (fp = popen(command, "r")));
+        char buffer[5120];
+        int log_file_count = 0;
+
+        while (fgets(buffer, sizeof(buffer), fp)) {
+            static const char rotated_log_filename_prefix[] = "log.txt.";
+            static const size_t rotated_log_filename_prefix_len =
+                strlen(rotated_log_filename_prefix);
+            static const char log_filename[] = "log.txt";
+
+            if (!strncmp(buffer, rotated_log_filename_prefix, rotated_log_filename_prefix_len)) {
+              // Rotated file should have form log.txt.##
+              char* rotated_log_filename_suffix = buffer + rotated_log_filename_prefix_len;
+              char* endptr;
+              const long int suffix_value = strtol(rotated_log_filename_suffix, &endptr, 10);
+              EXPECT_EQ(rotated_log_filename_suffix + 2, endptr);
+              EXPECT_LE(suffix_value, 10);
+              EXPECT_GT(suffix_value, 0);
+              ++log_file_count;
+              continue;
+            }
+
+            if (!strncmp(buffer, log_filename, strlen(log_filename))) {
+              ++log_file_count;
+              continue;
+            }
+
+            fprintf(stderr, "ERROR: Unexpected file: %s", buffer);
+            ADD_FAILURE();
+        }
+        pclose(fp);
+        EXPECT_EQ(11, log_file_count);
+    }
+    sprintf(command, "rm -rf %s", tmp_out_dir);
+    EXPECT_FALSE(system(command));
+}
+
 static void caught_blocking_clear(int /*signum*/)
 {
     unsigned long long v = 0xDEADBEEFA55C0000ULL;
@@ -542,7 +601,7 @@
     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 2>&1",
+      " logcat -v brief -b events 2>&1",
       "r")));
 
     char buffer[5120];
diff --git a/logd/Android.mk b/logd/Android.mk
index 188511f..615d030 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -18,6 +18,7 @@
     LogWhiteBlackList.cpp \
     libaudit.c \
     LogAudit.cpp \
+    LogKlog.cpp \
     event.logtags
 
 LOCAL_SHARED_LIBRARIES := \
@@ -26,8 +27,29 @@
     libcutils \
     libutils
 
-LOCAL_CFLAGS := -Werror $(shell sed -n 's/^\([0-9]*\)[ \t]*auditd[ \t].*/-DAUDITD_LOG_TAG=\1/p' $(LOCAL_PATH)/event.logtags)
+# This is what we want to do:
+#  event_logtags = $(shell \
+#    sed -n \
+#        "s/^\([0-9]*\)[ \t]*$1[ \t].*/-D`echo $1 | tr a-z A-Z`_LOG_TAG=\1/p" \
+#        $(LOCAL_PATH)/$2/event.logtags)
+#  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
+
+LOCAL_CFLAGS := -Werror $(event_flag)
 
 include $(BUILD_EXECUTABLE)
 
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := logpersist.start
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_PATH := $(bin_dir)
+LOCAL_SRC_FILES := logpersist
+ALL_TOOLS := logpersist.start logpersist.stop logpersist.cat
+LOCAL_POST_INSTALL_CMD := $(hide) $(foreach t,$(filter-out $(LOCAL_MODULE),$(ALL_TOOLS)),ln -sf $(LOCAL_MODULE) $(TARGET_OUT)/bin/$(t);)
+include $(BUILD_PREBUILT)
+
 include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index d7088b4..5489cc9 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -33,9 +33,9 @@
 #include "LogCommand.h"
 
 CommandListener::CommandListener(LogBuffer *buf, LogReader * /*reader*/,
-                                 LogListener * /*swl*/)
-        : FrameworkListener(getLogSocket())
-        , mBuf(*buf) {
+                                 LogListener * /*swl*/) :
+        FrameworkListener(getLogSocket()),
+        mBuf(*buf) {
     // registerCmd(new ShutdownCmd(buf, writer, swl));
     registerCmd(new ClearCmd(buf));
     registerCmd(new GetBufSizeCmd(buf));
@@ -44,15 +44,16 @@
     registerCmd(new GetStatisticsCmd(buf));
     registerCmd(new SetPruneListCmd(buf));
     registerCmd(new GetPruneListCmd(buf));
+    registerCmd(new ReinitCmd());
 }
 
 CommandListener::ShutdownCmd::ShutdownCmd(LogBuffer *buf, LogReader *reader,
-                                          LogListener *swl)
-        : LogCommand("shutdown")
-        , mBuf(*buf)
-        , mReader(*reader)
-        , mSwl(*swl)
-{ }
+                                          LogListener *swl) :
+        LogCommand("shutdown"),
+        mBuf(*buf),
+        mReader(*reader),
+        mSwl(*swl) {
+}
 
 int CommandListener::ShutdownCmd::runCommand(SocketClient * /*cli*/,
                                              int /*argc*/,
@@ -62,13 +63,17 @@
     exit(0);
 }
 
-CommandListener::ClearCmd::ClearCmd(LogBuffer *buf)
-        : LogCommand("clear")
-        , mBuf(*buf)
-{ }
+CommandListener::ClearCmd::ClearCmd(LogBuffer *buf) :
+        LogCommand("clear"),
+        mBuf(*buf) {
+}
 
 static void setname() {
-    prctl(PR_SET_NAME, "logd.control");
+    static bool name_set;
+    if (!name_set) {
+        prctl(PR_SET_NAME, "logd.control");
+        name_set = true;
+    }
 }
 
 int CommandListener::ClearCmd::runCommand(SocketClient *cli,
@@ -95,10 +100,10 @@
     return 0;
 }
 
-CommandListener::GetBufSizeCmd::GetBufSizeCmd(LogBuffer *buf)
-        : LogCommand("getLogSize")
-        , mBuf(*buf)
-{ }
+CommandListener::GetBufSizeCmd::GetBufSizeCmd(LogBuffer *buf) :
+        LogCommand("getLogSize"),
+        mBuf(*buf) {
+}
 
 int CommandListener::GetBufSizeCmd::runCommand(SocketClient *cli,
                                          int argc, char **argv) {
@@ -121,10 +126,10 @@
     return 0;
 }
 
-CommandListener::SetBufSizeCmd::SetBufSizeCmd(LogBuffer *buf)
-        : LogCommand("setLogSize")
-        , mBuf(*buf)
-{ }
+CommandListener::SetBufSizeCmd::SetBufSizeCmd(LogBuffer *buf) :
+        LogCommand("setLogSize"),
+        mBuf(*buf) {
+}
 
 int CommandListener::SetBufSizeCmd::runCommand(SocketClient *cli,
                                          int argc, char **argv) {
@@ -155,10 +160,10 @@
     return 0;
 }
 
-CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer *buf)
-        : LogCommand("getLogSizeUsed")
-        , mBuf(*buf)
-{ }
+CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer *buf) :
+        LogCommand("getLogSizeUsed"),
+        mBuf(*buf) {
+}
 
 int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient *cli,
                                          int argc, char **argv) {
@@ -181,10 +186,10 @@
     return 0;
 }
 
-CommandListener::GetStatisticsCmd::GetStatisticsCmd(LogBuffer *buf)
-        : LogCommand("getStatistics")
-        , mBuf(*buf)
-{ }
+CommandListener::GetStatisticsCmd::GetStatisticsCmd(LogBuffer *buf) :
+        LogCommand("getStatistics"),
+        mBuf(*buf) {
+}
 
 static void package_string(char **strp) {
     const char *a = *strp;
@@ -238,10 +243,10 @@
     return 0;
 }
 
-CommandListener::GetPruneListCmd::GetPruneListCmd(LogBuffer *buf)
-        : LogCommand("getPruneList")
-        , mBuf(*buf)
-{ }
+CommandListener::GetPruneListCmd::GetPruneListCmd(LogBuffer *buf) :
+        LogCommand("getPruneList"),
+        mBuf(*buf) {
+}
 
 int CommandListener::GetPruneListCmd::runCommand(SocketClient *cli,
                                          int /*argc*/, char ** /*argv*/) {
@@ -258,10 +263,10 @@
     return 0;
 }
 
-CommandListener::SetPruneListCmd::SetPruneListCmd(LogBuffer *buf)
-        : LogCommand("setPruneList")
-        , mBuf(*buf)
-{ }
+CommandListener::SetPruneListCmd::SetPruneListCmd(LogBuffer *buf) :
+        LogCommand("setPruneList"),
+        mBuf(*buf) {
+}
 
 int CommandListener::SetPruneListCmd::runCommand(SocketClient *cli,
                                          int argc, char **argv) {
@@ -296,6 +301,20 @@
     return 0;
 }
 
+CommandListener::ReinitCmd::ReinitCmd() : LogCommand("reinit") {
+}
+
+int CommandListener::ReinitCmd::runCommand(SocketClient *cli,
+                                         int /*argc*/, char ** /*argv*/) {
+    setname();
+
+    reinit_signal_handler(SIGHUP);
+
+    cli->sendMsg("success");
+
+    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 cd1c306..83e06b4 100644
--- a/logd/CommandListener.h
+++ b/logd/CommandListener.h
@@ -23,6 +23,9 @@
 #include "LogReader.h"
 #include "LogListener.h"
 
+// See main.cpp for implementation
+void reinit_signal_handler(int /*signal*/);
+
 class CommandListener : public FrameworkListener {
     LogBuffer &mBuf;
 
@@ -60,6 +63,14 @@
     LogBufferCmd(GetStatistics)
     LogBufferCmd(GetPruneList)
     LogBufferCmd(SetPruneList)
+
+    class ReinitCmd : public LogCommand {
+    public:
+        ReinitCmd();
+        virtual ~ReinitCmd() {}
+        int runCommand(SocketClient *c, int argc, char ** argv);
+    };
+
 };
 
 #endif
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
index 3be07c0..d584925 100644
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -27,14 +27,14 @@
                            unsigned long tail,
                            unsigned int logMask,
                            pid_t pid,
-                           log_time start)
-        : mReader(reader)
-        , mNonBlock(nonBlock)
-        , mTail(tail)
-        , mLogMask(logMask)
-        , mPid(pid)
-        , mStart(start)
-{ }
+                           uint64_t start) :
+        mReader(reader),
+        mNonBlock(nonBlock),
+        mTail(tail),
+        mLogMask(logMask),
+        mPid(pid),
+        mStart(start) {
+}
 
 // runSocketCommand is called once for every open client on the
 // log reader socket. Here we manage and associated the reader
diff --git a/logd/FlushCommand.h b/logd/FlushCommand.h
index f34c06a..61c6858 100644
--- a/logd/FlushCommand.h
+++ b/logd/FlushCommand.h
@@ -31,7 +31,7 @@
     unsigned long mTail;
     unsigned int mLogMask;
     pid_t mPid;
-    log_time mStart;
+    uint64_t mStart;
 
 public:
     FlushCommand(LogReader &mReader,
@@ -39,7 +39,7 @@
                  unsigned long tail = -1,
                  unsigned int logMask = -1,
                  pid_t pid = 0,
-                 log_time start = LogTimeEntry::EPOCH);
+                 uint64_t start = 1);
     virtual void runSocketCommand(SocketClient *client);
 
     static bool hasReadLogs(SocketClient *client);
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index ee2f32d..4b3547c 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -15,39 +15,45 @@
  */
 
 #include <ctype.h>
+#include <endian.h>
 #include <errno.h>
 #include <limits.h>
 #include <stdarg.h>
 #include <stdlib.h>
-#include <sys/klog.h>
 #include <sys/prctl.h>
 #include <sys/uio.h>
 #include <syslog.h>
 
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
+
 #include "libaudit.h"
 #include "LogAudit.h"
+#include "LogKlog.h"
 
-#define KMSG_PRIORITY(PRI)         \
-    '<',                           \
-    '0' + (LOG_AUTH | (PRI)) / 10, \
-    '0' + (LOG_AUTH | (PRI)) % 10, \
+#define KMSG_PRIORITY(PRI)                          \
+    '<',                                            \
+    '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) / 10, \
+    '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) % 10, \
     '>'
 
-LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmsg)
-        : SocketListener(getLogSocket(), false)
-        , logbuf(buf)
-        , reader(reader)
-        , fdDmesg(-1) {
+LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg) :
+        SocketListener(getLogSocket(), false),
+        logbuf(buf),
+        reader(reader),
+        fdDmesg(fdDmesg),
+        initialized(false) {
     static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO),
         'l', 'o', 'g', 'd', '.', 'a', 'u', 'd', 'i', 't', 'd', ':',
         ' ', 's', 't', 'a', 'r', 't', '\n' };
-    write(fdDmsg, auditd_message, sizeof(auditd_message));
-    logDmesg();
-    fdDmesg = fdDmsg;
+    write(fdDmesg, auditd_message, sizeof(auditd_message));
 }
 
 bool LogAudit::onDataAvailable(SocketClient *cli) {
-    prctl(PR_SET_NAME, "logd.auditd");
+    if (!initialized) {
+        prctl(PR_SET_NAME, "logd.auditd");
+        initialized = true;
+    }
 
     struct audit_message rep;
 
@@ -60,7 +66,8 @@
         return false;
     }
 
-    logPrint("type=%d %.*s", rep.nlh.nlmsg_type, rep.nlh.nlmsg_len, rep.data);
+    logPrint("type=%d %.*s",
+        rep.nlh.nlmsg_type, rep.nlh.nlmsg_len, rep.data);
 
     return true;
 }
@@ -87,7 +94,7 @@
     }
 
     bool info = strstr(str, " permissive=1") || strstr(str, " policy loaded ");
-    if (fdDmesg >= 0) {
+    if ((fdDmesg >= 0) && initialized) {
         struct iovec iov[3];
         static const char log_info[] = { KMSG_PRIORITY(LOG_INFO) };
         static const char log_warning[] = { KMSG_PRIORITY(LOG_WARNING) };
@@ -105,7 +112,7 @@
 
     pid_t pid = getpid();
     pid_t tid = gettid();
-    uid_t uid = getuid();
+    uid_t uid = AID_LOGD;
     log_time now;
 
     static const char audit_str[] = " audit(";
@@ -115,6 +122,15 @@
             && (*cp == ':')) {
         memcpy(timeptr + sizeof(audit_str) - 1, "0.0", 3);
         memmove(timeptr + sizeof(audit_str) - 1 + 3, cp, strlen(cp) + 1);
+        //
+        // We are either in 1970ish (MONOTONIC) or 2015+ish (REALTIME) so to
+        // differentiate without prejudice, we use 1980 to delineate, earlier
+        // is monotonic, later is real.
+        //
+#       define EPOCH_PLUS_10_YEARS (10 * 1461 / 4 * 24 * 60 * 60)
+        if (now.tv_sec < EPOCH_PLUS_10_YEARS) {
+            LogKlog::convertMonotonicToReal(now);
+        }
     } else {
         now.strptime("", ""); // side effect of setting CLOCK_REALTIME
     }
@@ -129,38 +145,36 @@
             ++cp;
         }
         tid = pid;
+        logbuf->lock();
         uid = logbuf->pidToUid(pid);
+        logbuf->unlock();
         memmove(pidptr, cp, strlen(cp) + 1);
     }
 
     // log to events
 
     size_t l = strlen(str);
-    size_t n = l + sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
+    size_t n = l + sizeof(android_log_event_string_t);
 
     bool notify = false;
 
-    char *newstr = reinterpret_cast<char *>(malloc(n));
-    if (!newstr) {
+    android_log_event_string_t *event = static_cast<android_log_event_string_t *>(malloc(n));
+    if (!event) {
         rc = -ENOMEM;
     } else {
-        cp = newstr;
-        *cp++ = AUDITD_LOG_TAG & 0xFF;
-        *cp++ = (AUDITD_LOG_TAG >> 8) & 0xFF;
-        *cp++ = (AUDITD_LOG_TAG >> 16) & 0xFF;
-        *cp++ = (AUDITD_LOG_TAG >> 24) & 0xFF;
-        *cp++ = EVENT_TYPE_STRING;
-        *cp++ = l & 0xFF;
-        *cp++ = (l >> 8) & 0xFF;
-        *cp++ = (l >> 16) & 0xFF;
-        *cp++ = (l >> 24) & 0xFF;
-        memcpy(cp, str, l);
+        event->header.tag = htole32(AUDITD_LOG_TAG);
+        event->type = EVENT_TYPE_STRING;
+        event->length = htole32(l);
+        memcpy(event->data, str, l);
 
-        logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid, newstr,
-                    (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
-        free(newstr);
+        rc = logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid,
+                         reinterpret_cast<char *>(event),
+                         (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
+        free(event);
 
-        notify = true;
+        if (rc >= 0) {
+            notify = true;
+        }
     }
 
     // log to main
@@ -168,14 +182,20 @@
     static const char comm_str[] = " comm=\"";
     const char *comm = strstr(str, comm_str);
     const char *estr = str + strlen(str);
+    char *commfree = NULL;
     if (comm) {
         estr = comm;
         comm += sizeof(comm_str) - 1;
     } else if (pid == getpid()) {
         pid = tid;
         comm = "auditd";
-    } else if (!(comm = logbuf->pidToName(pid))) {
-        comm = "unknown";
+    } else {
+        logbuf->lock();
+        comm = commfree = logbuf->pidToName(pid);
+        logbuf->unlock();
+        if (!comm) {
+            comm = "unknown";
+        }
     }
 
     const char *ecomm = strchr(comm, '"');
@@ -188,7 +208,7 @@
     }
     n = (estr - str) + strlen(ecomm) + l + 2;
 
-    newstr = reinterpret_cast<char *>(malloc(n));
+    char *newstr = static_cast<char *>(malloc(n));
     if (!newstr) {
         rc = -ENOMEM;
     } else {
@@ -197,50 +217,45 @@
         strncpy(newstr + 1 + l, str, estr - str);
         strcpy(newstr + 1 + l + (estr - str), ecomm);
 
-        logbuf->log(LOG_ID_MAIN, now, uid, pid, tid, newstr,
-                    (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
+        rc = logbuf->log(LOG_ID_MAIN, now, uid, pid, tid, newstr,
+                         (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
         free(newstr);
 
-        notify = true;
+        if (rc >= 0) {
+            notify = true;
+        }
     }
 
+    free(commfree);
     free(str);
 
     if (notify) {
         reader->notifyNewLog();
+        if (rc < 0) {
+            rc = n;
+        }
     }
 
     return rc;
 }
 
-void LogAudit::logDmesg() {
-    int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
-    if (len <= 0) {
-        return;
+int LogAudit::log(char *buf) {
+    char *audit = strstr(buf, " audit(");
+    if (!audit) {
+        return 0;
     }
 
-    len++;
-    char buf[len];
+    *audit = '\0';
 
-    int rc = klogctl(KLOG_READ_ALL, buf, len);
-
-    buf[len - 1] = '\0';
-
-    for(char *tok = buf; (rc >= 0) && ((tok = strtok(tok, "\r\n"))); tok = NULL) {
-        char *audit = strstr(tok, " audit(");
-        if (!audit) {
-            continue;
-        }
-
-        *audit++ = '\0';
-
-        char *type = strstr(tok, "type=");
-        if (type) {
-            rc = logPrint("%s %s", type, audit);
-        } else {
-            rc = logPrint("%s", audit);
-        }
+    int rc;
+    char *type = strstr(buf, "type=");
+    if (type) {
+        rc = logPrint("%s %s", type, audit + 1);
+    } else {
+        rc = logPrint("%s", audit + 1);
     }
+    *audit = ' ';
+    return rc;
 }
 
 int LogAudit::getLogSocket() {
diff --git a/logd/LogAudit.h b/logd/LogAudit.h
index 111030a..f977be9 100644
--- a/logd/LogAudit.h
+++ b/logd/LogAudit.h
@@ -24,16 +24,17 @@
     LogBuffer *logbuf;
     LogReader *reader;
     int fdDmesg;
+    bool initialized;
 
 public:
     LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg);
+    int log(char *buf);
 
 protected:
     virtual bool onDataAvailable(SocketClient *cli);
 
 private:
     static int getLogSocket();
-    void logDmesg();
     int logPrint(const char *fmt, ...)
         __attribute__ ((__format__ (__printf__, 2, 3)));
 };
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 8c1c344..0f5071b 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -15,20 +15,20 @@
  */
 
 #include <ctype.h>
+#include <errno.h>
 #include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
 #include <sys/user.h>
 #include <time.h>
 #include <unistd.h>
 
+#include <unordered_map>
+
 #include <cutils/properties.h>
 #include <log/logger.h>
 
 #include "LogBuffer.h"
 #include "LogReader.h"
-#include "LogStatistics.h"
-#include "LogWhiteBlackList.h"
 
 // Default
 #define LOG_BUFFER_SIZE (256 * 1024) // Tuned on a per-platform basis here?
@@ -92,11 +92,7 @@
     return value;
 }
 
-LogBuffer::LogBuffer(LastLogTimes *times)
-        : dgramQlenStatistics(false)
-        , mTimes(*times) {
-    pthread_mutex_init(&mLogElementsLock, NULL);
-
+void LogBuffer::init() {
     static const char global_tuneable[] = "persist.logd.size"; // Settings App
     static const char global_default[] = "ro.logd.size";       // BoardConfig.mk
 
@@ -132,14 +128,38 @@
     }
 }
 
-void LogBuffer::log(log_id_t log_id, log_time realtime,
-                    uid_t uid, pid_t pid, pid_t tid,
-                    const char *msg, unsigned short len) {
+LogBuffer::LogBuffer(LastLogTimes *times) : mTimes(*times) {
+    pthread_mutex_init(&mLogElementsLock, NULL);
+
+    init();
+}
+
+int LogBuffer::log(log_id_t log_id, log_time realtime,
+                   uid_t uid, pid_t pid, pid_t tid,
+                   const char *msg, unsigned short len) {
     if ((log_id >= LOG_ID_MAX) || (log_id < 0)) {
-        return;
+        return -EINVAL;
     }
+
     LogBufferElement *elem = new LogBufferElement(log_id, realtime,
                                                   uid, pid, tid, msg, len);
+    int prio = ANDROID_LOG_INFO;
+    const char *tag = NULL;
+    if (log_id == LOG_ID_EVENTS) {
+        tag = android::tagToName(elem->getTag());
+    } else {
+        prio = *msg;
+        tag = msg + 1;
+    }
+    if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
+        // Log traffic received to total
+        pthread_mutex_lock(&mLogElementsLock);
+        stats.add(elem);
+        stats.subtract(elem);
+        pthread_mutex_unlock(&mLogElementsLock);
+        delete elem;
+        return -EACCES;
+    }
 
     pthread_mutex_lock(&mLogElementsLock);
 
@@ -147,25 +167,9 @@
     //  NB: if end is region locked, place element at end of list
     LogBufferElementCollection::iterator it = mLogElements.end();
     LogBufferElementCollection::iterator last = it;
-    while (--it != mLogElements.begin()) {
+    while (last != mLogElements.begin()) {
+        --it;
         if ((*it)->getRealTime() <= realtime) {
-            // halves the peak performance, use with caution
-            if (dgramQlenStatistics) {
-                LogBufferElementCollection::iterator ib = it;
-                unsigned short buckets, num = 1;
-                for (unsigned short i = 0; (buckets = stats.dgramQlen(i)); ++i) {
-                    buckets -= num;
-                    num += buckets;
-                    while (buckets && (--ib != mLogElements.begin())) {
-                        --buckets;
-                    }
-                    if (buckets) {
-                        break;
-                    }
-                    stats.recordDiff(
-                        elem->getRealTime() - (*ib)->getRealTime(), i);
-                }
-            }
             break;
         }
         last = it;
@@ -174,7 +178,7 @@
     if (last == mLogElements.end()) {
         mLogElements.push_back(elem);
     } else {
-        log_time end = log_time::EPOCH;
+        uint64_t end = 1;
         bool end_set = false;
         bool end_always = false;
 
@@ -197,7 +201,7 @@
         }
 
         if (end_always
-                || (end_set && (end >= (*last)->getMonotonicTime()))) {
+                || (end_set && (end >= (*last)->getSequence()))) {
             mLogElements.push_back(elem);
         } else {
             mLogElements.insert(last,elem);
@@ -206,9 +210,11 @@
         LogTimeEntry::unlock();
     }
 
-    stats.add(len, log_id, uid, pid);
+    stats.add(elem);
     maybePrune(log_id);
     pthread_mutex_unlock(&mLogElementsLock);
+
+    return len;
 }
 
 // If we're using more than 256K of memory for log entries, prune
@@ -229,6 +235,85 @@
     }
 }
 
+LogBufferElementCollection::iterator LogBuffer::erase(LogBufferElementCollection::iterator it) {
+    LogBufferElement *e = *it;
+
+    it = mLogElements.erase(it);
+    stats.subtract(e);
+    delete e;
+
+    return it;
+}
+
+// Define a temporary mechanism to report the last LogBufferElement pointer
+// for the specified uid, pid and tid. Used below to help merge-sort when
+// pruning for worst UID.
+class LogBufferElementKey {
+    const union {
+        struct {
+            uint16_t uid;
+            uint16_t pid;
+            uint16_t tid;
+            uint16_t padding;
+        } __packed;
+        uint64_t value;
+    } __packed;
+
+public:
+    LogBufferElementKey(uid_t u, pid_t p, pid_t t):uid(u),pid(p),tid(t),padding(0) { }
+    LogBufferElementKey(uint64_t k):value(k) { }
+
+    uint64_t getKey() { return value; }
+};
+
+class LogBufferElementLast {
+
+    typedef std::unordered_map<uint64_t, LogBufferElement *> LogBufferElementMap;
+    LogBufferElementMap map;
+
+public:
+
+    bool merge(LogBufferElement *e, unsigned short dropped) {
+        LogBufferElementKey key(e->getUid(), e->getPid(), e->getTid());
+        LogBufferElementMap::iterator it = map.find(key.getKey());
+        if (it != map.end()) {
+            LogBufferElement *l = it->second;
+            unsigned short d = l->getDropped();
+            if ((dropped + d) > USHRT_MAX) {
+                map.erase(it);
+            } else {
+                l->setDropped(dropped + d);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    void add(LogBufferElement *e) {
+        LogBufferElementKey key(e->getUid(), e->getPid(), e->getTid());
+        map[key.getKey()] = e;
+    }
+
+    inline void clear() {
+        map.clear();
+    }
+
+    void clear(LogBufferElement *e) {
+        uint64_t current = e->getRealTime().nsec()
+                         - (EXPIRE_RATELIMIT * NS_PER_SEC);
+        for(LogBufferElementMap::iterator it = map.begin(); it != map.end();) {
+            LogBufferElement *l = it->second;
+            if ((l->getDropped() >= EXPIRE_THRESHOLD)
+                    && (current > l->getRealTime().nsec())) {
+                it = map.erase(it);
+            } else {
+                ++it;
+            }
+        }
+    }
+
+};
+
 // prune "pruneRows" of type "id" from the buffer.
 //
 // mLogElementsLock must be held when this function is called.
@@ -241,7 +326,7 @@
     LastLogTimes::iterator t = mTimes.begin();
     while(t != mTimes.end()) {
         LogTimeEntry *entry = (*t);
-        if (entry->owned_Locked()
+        if (entry->owned_Locked() && entry->isWatching(id)
                 && (!oldest || (oldest->mStart > entry->mStart))) {
             oldest = entry;
         }
@@ -254,7 +339,7 @@
         for(it = mLogElements.begin(); it != mLogElements.end();) {
             LogBufferElement *e = *it;
 
-            if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
+            if (oldest && (oldest->mStart <= e->getSequence())) {
                 break;
             }
 
@@ -263,12 +348,8 @@
                 continue;
             }
 
-            uid_t uid = e->getUid();
-
-            if (uid == caller_uid) {
-                it = mLogElements.erase(it);
-                stats.subtract(e->getMsgLen(), id, uid, e->getPid());
-                delete e;
+            if (e->getUid() == caller_uid) {
+                it = erase(it);
                 pruneRows--;
                 if (pruneRows == 0) {
                     break;
@@ -282,31 +363,44 @@
     }
 
     // prune by worst offender by uid
+    bool hasBlacklist = mPrune.naughty();
     while (pruneRows > 0) {
         // recalculate the worst offender on every batched pass
         uid_t worst = (uid_t) -1;
         size_t worst_sizes = 0;
         size_t second_worst_sizes = 0;
 
-        if ((id != LOG_ID_CRASH) && mPrune.worstUidEnabled()) {
-            LidStatistics &l = stats.id(id);
-            l.sort();
-            UidStatisticsCollection::iterator iu = l.begin();
-            if (iu != l.end()) {
-                UidStatistics *u = *iu;
-                worst = u->getUid();
-                worst_sizes = u->sizes();
-                if (++iu != l.end()) {
-                    second_worst_sizes = (*iu)->sizes();
+        if (worstUidEnabledForLogid(id) && mPrune.worstUidEnabled()) {
+            std::unique_ptr<const UidEntry *[]> sorted = stats.sort(2, id);
+
+            if (sorted.get()) {
+                if (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) {
+                        worst = sorted[0]->getKey();
+                        second_worst_sizes = sorted[1]->getSizes();
+                        if (second_worst_sizes < threshold) {
+                            second_worst_sizes = threshold;
+                        }
+                    }
                 }
             }
         }
 
+        // skip if we have neither worst nor naughty filters
+        if ((worst == (uid_t) -1) && !hasBlacklist) {
+            break;
+        }
+
         bool kick = false;
+        bool leading = true;
+        LogBufferElementLast last;
         for(it = mLogElements.begin(); it != mLogElements.end();) {
             LogBufferElement *e = *it;
 
-            if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
+            if (oldest && (oldest->mStart <= e->getSequence())) {
                 break;
             }
 
@@ -315,27 +409,99 @@
                 continue;
             }
 
-            uid_t uid = e->getUid();
+            unsigned short dropped = e->getDropped();
 
-            if ((uid == worst) || mPrune.naughty(e)) { // Worst or BlackListed
+            // remove any leading drops
+            if (leading && dropped) {
+                it = erase(it);
+                continue;
+            }
+
+            // merge any drops
+            if (dropped && last.merge(e, dropped)) {
                 it = mLogElements.erase(it);
-                unsigned short len = e->getMsgLen();
-                stats.subtract(len, id, uid, e->getPid());
+                stats.erase(e);
                 delete e;
+                continue;
+            }
+
+            if (hasBlacklist && mPrune.naughty(e)) {
+                last.clear(e);
+                it = erase(it);
+                if (dropped) {
+                    continue;
+                }
+
                 pruneRows--;
-                if (uid == worst) {
-                    kick = true;
-                    if ((pruneRows == 0) || (worst_sizes < second_worst_sizes)) {
-                        break;
-                    }
-                    worst_sizes -= len;
-                } else if (pruneRows == 0) {
+                if (pruneRows == 0) {
                     break;
                 }
-            } else {
-                ++it;
+
+                if (e->getUid() == worst) {
+                    kick = true;
+                    if (worst_sizes < second_worst_sizes) {
+                        break;
+                    }
+                    worst_sizes -= e->getMsgLen();
+                }
+                continue;
             }
+
+            if (dropped) {
+                last.add(e);
+                ++it;
+                continue;
+            }
+
+            if (e->getUid() != worst) {
+                if (leading) {
+                    static const timespec too_old = {
+                        EXPIRE_HOUR_THRESHOLD * 60 * 60, 0
+                    };
+                    LogBufferElementCollection::iterator last;
+                    last = mLogElements.end();
+                    --last;
+                    if ((e->getRealTime() < ((*last)->getRealTime() - too_old))
+                            || (e->getRealTime() > (*last)->getRealTime())) {
+                        break;
+                    }
+                }
+                leading = false;
+                last.clear(e);
+                ++it;
+                continue;
+            }
+
+            pruneRows--;
+            if (pruneRows == 0) {
+                break;
+            }
+
+            kick = true;
+
+            unsigned short len = e->getMsgLen();
+
+            // do not create any leading drops
+            if (leading) {
+                it = erase(it);
+            } else {
+                stats.drop(e);
+                e->setDropped(1);
+                if (last.merge(e, 1)) {
+                    it = mLogElements.erase(it);
+                    stats.erase(e);
+                    delete e;
+                } else {
+                    last.add(e);
+                    ++it;
+                }
+            }
+            if (worst_sizes < second_worst_sizes) {
+                break;
+            }
+            worst_sizes -= len;
         }
+        last.clear();
 
         if (!kick || !mPrune.worstUidEnabled()) {
             break; // the following loop will ask bad clients to skip/drop
@@ -343,58 +509,63 @@
     }
 
     bool whitelist = false;
+    bool hasWhitelist = mPrune.nice();
     it = mLogElements.begin();
     while((pruneRows > 0) && (it != mLogElements.end())) {
         LogBufferElement *e = *it;
-        if (e->getLogId() == id) {
-            if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
-                if (!whitelist) {
-                    if (stats.sizes(id) > (2 * log_buffer_size(id))) {
-                        // kick a misbehaving log reader client off the island
-                        oldest->release_Locked();
-                    } else {
-                        oldest->triggerSkip_Locked(pruneRows);
-                    }
-                }
+
+        if (e->getLogId() != id) {
+            it++;
+            continue;
+        }
+
+        if (oldest && (oldest->mStart <= e->getSequence())) {
+            if (whitelist) {
                 break;
             }
 
-            if (mPrune.nice(e)) { // WhiteListed
-                whitelist = true;
-                it++;
-                continue;
+            if (stats.sizes(id) > (2 * log_buffer_size(id))) {
+                // kick a misbehaving log reader client off the island
+                oldest->release_Locked();
+            } else {
+                oldest->triggerSkip_Locked(id, pruneRows);
             }
-
-            it = mLogElements.erase(it);
-            stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
-            delete e;
-            pruneRows--;
-        } else {
-            it++;
+            break;
         }
+
+        if (hasWhitelist && !e->getDropped() && mPrune.nice(e)) { // WhiteListed
+            whitelist = true;
+            it++;
+            continue;
+        }
+
+        it = erase(it);
+        pruneRows--;
     }
 
+    // Do not save the whitelist if we are reader range limited
     if (whitelist && (pruneRows > 0)) {
         it = mLogElements.begin();
         while((it != mLogElements.end()) && (pruneRows > 0)) {
             LogBufferElement *e = *it;
-            if (e->getLogId() == id) {
-                if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
-                    if (stats.sizes(id) > (2 * log_buffer_size(id))) {
-                        // kick a misbehaving log reader client off the island
-                        oldest->release_Locked();
-                    } else {
-                        oldest->triggerSkip_Locked(pruneRows);
-                    }
-                    break;
-                }
-                it = mLogElements.erase(it);
-                stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
-                delete e;
-                pruneRows--;
-            } else {
-                it++;
+
+            if (e->getLogId() != id) {
+                ++it;
+                continue;
             }
+
+            if (oldest && (oldest->mStart <= e->getSequence())) {
+                if (stats.sizes(id) > (2 * log_buffer_size(id))) {
+                    // kick a misbehaving log reader client off the island
+                    oldest->release_Locked();
+                } else {
+                    oldest->triggerSkip_Locked(id, pruneRows);
+                }
+                break;
+            }
+
+            it = erase(it);
+            pruneRows--;
         }
     }
 
@@ -436,34 +607,57 @@
     return retval;
 }
 
-log_time LogBuffer::flushTo(
-        SocketClient *reader, const log_time start, bool privileged,
-        bool (*filter)(const LogBufferElement *element, void *arg), void *arg) {
+uint64_t LogBuffer::flushTo(
+        SocketClient *reader, const uint64_t start, bool privileged,
+        int (*filter)(const LogBufferElement *element, void *arg), void *arg) {
     LogBufferElementCollection::iterator it;
-    log_time max = start;
+    uint64_t max = start;
     uid_t uid = reader->getUid();
 
     pthread_mutex_lock(&mLogElementsLock);
-    for (it = mLogElements.begin(); it != mLogElements.end(); ++it) {
+
+    if (start <= 1) {
+        // client wants to start from the beginning
+        it = mLogElements.begin();
+    } else {
+        // Client wants to start from some specified time. Chances are
+        // we are better off starting from the end of the time sorted list.
+        for (it = mLogElements.end(); it != mLogElements.begin(); /* do nothing */) {
+            --it;
+            LogBufferElement *element = *it;
+            if (element->getSequence() <= start) {
+                it++;
+                break;
+            }
+        }
+    }
+
+    for (; it != mLogElements.end(); ++it) {
         LogBufferElement *element = *it;
 
         if (!privileged && (element->getUid() != uid)) {
             continue;
         }
 
-        if (element->getMonotonicTime() <= start) {
+        if (element->getSequence() <= start) {
             continue;
         }
 
         // NB: calling out to another object with mLogElementsLock held (safe)
-        if (filter && !(*filter)(element, arg)) {
-            continue;
+        if (filter) {
+            int ret = (*filter)(element, arg);
+            if (ret == false) {
+                continue;
+            }
+            if (ret != true) {
+                break;
+            }
         }
 
         pthread_mutex_unlock(&mLogElementsLock);
 
         // range locking in LastLogTimes looks after us
-        max = element->flushTo(reader);
+        max = element->flushTo(reader, this);
 
         if (max == element->FLUSH_ERROR) {
             return max;
@@ -477,22 +671,9 @@
 }
 
 void LogBuffer::formatStatistics(char **strp, uid_t uid, unsigned int logMask) {
-    log_time oldest(CLOCK_MONOTONIC);
-
     pthread_mutex_lock(&mLogElementsLock);
 
-    // Find oldest element in the log(s)
-    LogBufferElementCollection::iterator it;
-    for (it = mLogElements.begin(); it != mLogElements.end(); ++it) {
-        LogBufferElement *element = *it;
-
-        if ((logMask & (1 << element->getLogId()))) {
-            oldest = element->getMonotonicTime();
-            break;
-        }
-    }
-
-    stats.format(strp, uid, logMask, oldest);
+    stats.format(strp, uid, logMask);
 
     pthread_mutex_unlock(&mLogElementsLock);
 }
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 879baea..a13fded 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -37,7 +37,6 @@
     pthread_mutex_t mLogElementsLock;
 
     LogStatistics stats;
-    bool dgramQlenStatistics;
 
     PruneList mPrune;
 
@@ -47,13 +46,14 @@
     LastLogTimes &mTimes;
 
     LogBuffer(LastLogTimes *times);
+    void init();
 
-    void log(log_id_t log_id, log_time realtime,
-             uid_t uid, pid_t pid, pid_t tid,
-             const char *msg, unsigned short len);
-    log_time flushTo(SocketClient *writer, const log_time start,
+    int log(log_id_t log_id, log_time realtime,
+            uid_t uid, pid_t pid, pid_t tid,
+            const char *msg, unsigned short len);
+    uint64_t flushTo(SocketClient *writer, const uint64_t start,
                      bool privileged,
-                     bool (*filter)(const LogBufferElement *element, void *arg) = NULL,
+                     int (*filter)(const LogBufferElement *element, void *arg) = NULL,
                      void *arg = NULL);
 
     void clear(log_id_t id, uid_t uid = AID_ROOT);
@@ -63,11 +63,6 @@
     // *strp uses malloc, use free to release.
     void formatStatistics(char **strp, uid_t uid, unsigned int logMask);
 
-    void enableDgramQlenStatistics() {
-        stats.enableDgramQlenStatistics();
-        dgramQlenStatistics = true;
-    }
-
     void enableStatistics() {
         stats.enableStatistics();
     }
@@ -76,14 +71,17 @@
     // *strp uses malloc, use free to release.
     void formatPrune(char **strp) { mPrune.format(strp); }
 
-    // helper
+    // helper must be protected directly or implicitly by lock()/unlock()
     char *pidToName(pid_t pid) { return stats.pidToName(pid); }
     uid_t pidToUid(pid_t pid) { return stats.pidToUid(pid); }
+    char *uidToName(uid_t uid) { return stats.uidToName(uid); }
+    void lock() { pthread_mutex_lock(&mLogElementsLock); }
+    void unlock() { pthread_mutex_unlock(&mLogElementsLock); }
 
 private:
     void maybePrune(log_id_t id);
     void prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT);
-
+    LogBufferElementCollection::iterator erase(LogBufferElementCollection::iterator it);
 };
 
 #endif // _LOGD_LOG_BUFFER_H__
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index d959ceb..9fb1439 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -14,28 +14,34 @@
  * limitations under the License.
  */
 
+#include <ctype.h>
+#include <endian.h>
+#include <fcntl.h>
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
 
 #include <log/logger.h>
+#include <private/android_logger.h>
 
 #include "LogBufferElement.h"
+#include "LogCommand.h"
 #include "LogReader.h"
 
-const log_time LogBufferElement::FLUSH_ERROR((uint32_t)0, (uint32_t)0);
+const uint64_t LogBufferElement::FLUSH_ERROR(0);
+atomic_int_fast64_t LogBufferElement::sequence(1);
 
 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)
-        , mMonotonicTime(CLOCK_MONOTONIC)
-        , mRealTime(realtime) {
+                                   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) {
     mMsg = new char[len];
     memcpy(mMsg, msg, len);
 }
@@ -44,11 +50,152 @@
     delete [] mMsg;
 }
 
-log_time LogBufferElement::flushTo(SocketClient *reader) {
+uint32_t LogBufferElement::getTag() const {
+    if ((mLogId != LOG_ID_EVENTS) || !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;
+    char buffer[256];
+    snprintf(buffer, sizeof(buffer), "/proc/%u/comm", tid);
+    int fd = open(buffer, O_RDONLY);
+    if (fd >= 0) {
+        ssize_t ret = read(fd, buffer, sizeof(buffer));
+        if (ret >= (ssize_t)sizeof(buffer)) {
+            ret = sizeof(buffer) - 1;
+        }
+        while ((ret > 0) && isspace(buffer[ret - 1])) {
+            --ret;
+        }
+        if (ret > 0) {
+            buffer[ret] = '\0';
+            retval = strdup(buffer);
+        }
+        close(fd);
+    }
+
+    // if nothing for comm, check out cmdline
+    char *name = android::pidToName(tid);
+    if (!retval) {
+        retval = name;
+        name = NULL;
+    }
+
+    // check if comm is truncated, see if cmdline has full representation
+    if (name) {
+        // impossible for retval to be NULL if name not NULL
+        size_t retval_len = strlen(retval);
+        size_t name_len = strlen(name);
+        // KISS: ToDo: Only checks prefix truncated, not suffix, or both
+        if ((retval_len < name_len) && !strcmp(retval, name + name_len - retval_len)) {
+            free(retval);
+            retval = name;
+        } else {
+            free(name);
+        }
+    }
+    return retval;
+}
+
+// assumption: mMsg == NULL
+size_t LogBufferElement::populateDroppedMessage(char *&buffer,
+        LogBuffer *parent) {
+    static const char tag[] = "chatty";
+
+    if (!__android_log_is_loggable(ANDROID_LOG_INFO, tag, ANDROID_LOG_VERBOSE)) {
+        return 0;
+    }
+
+    static const char format_uid[] = "uid=%u%s%s expire %u line%s";
+    parent->lock();
+    char *name = parent->uidToName(mUid);
+    parent->unlock();
+    char *commName = android::tidToName(mTid);
+    if (!commName && (mTid != mPid)) {
+        commName = android::tidToName(mPid);
+    }
+    if (!commName) {
+        parent->lock();
+        commName = parent->pidToName(mPid);
+        parent->unlock();
+    }
+    size_t len = name ? strlen(name) : 0;
+    if (len && commName && !strncmp(name, commName, len)) {
+        if (commName[len] == '\0') {
+            free(commName);
+            commName = NULL;
+        } else {
+            free(name);
+            name = NULL;
+        }
+    }
+    if (name) {
+        char *p = NULL;
+        asprintf(&p, "(%s)", name);
+        if (p) {
+            free(name);
+            name = p;
+        }
+    }
+    if (commName) {
+        char *p = NULL;
+        asprintf(&p, " %s", commName);
+        if (p) {
+            free(commName);
+            commName = p;
+        }
+    }
+    // identical to below to calculate the buffer size required
+    len = snprintf(NULL, 0, format_uid, mUid, name ? name : "",
+                   commName ? commName : "",
+                   mDropped, (mDropped > 1) ? "s" : "");
+
+    size_t hdrLen;
+    if (mLogId == LOG_ID_EVENTS) {
+        hdrLen = sizeof(android_log_event_string_t);
+    } else {
+        hdrLen = 1 + sizeof(tag);
+    }
+
+    buffer = static_cast<char *>(calloc(1, hdrLen + len + 1));
+    if (!buffer) {
+        free(name);
+        free(commName);
+        return 0;
+    }
+
+    size_t retval = hdrLen + len;
+    if (mLogId == LOG_ID_EVENTS) {
+        android_log_event_string_t *e = reinterpret_cast<android_log_event_string_t *>(buffer);
+
+        e->header.tag = htole32(LOGD_LOG_TAG);
+        e->type = EVENT_TYPE_STRING;
+        e->length = htole32(len);
+    } else {
+        ++retval;
+        buffer[0] = ANDROID_LOG_INFO;
+        strcpy(buffer + 1, tag);
+    }
+
+    snprintf(buffer + hdrLen, len + 1, format_uid, mUid, name ? name : "",
+             commName ? commName : "",
+             mDropped, (mDropped > 1) ? "s" : "");
+    free(name);
+    free(commName);
+
+    return retval;
+}
+
+uint64_t LogBufferElement::flushTo(SocketClient *reader, LogBuffer *parent) {
     struct logger_entry_v3 entry;
+
     memset(&entry, 0, sizeof(struct logger_entry_v3));
+
     entry.hdr_size = sizeof(struct logger_entry_v3);
-    entry.len = mMsgLen;
     entry.lid = mLogId;
     entry.pid = mPid;
     entry.tid = mTid;
@@ -58,11 +205,26 @@
     struct iovec iovec[2];
     iovec[0].iov_base = &entry;
     iovec[0].iov_len = sizeof(struct logger_entry_v3);
-    iovec[1].iov_base = mMsg;
-    iovec[1].iov_len = mMsgLen;
-    if (reader->sendDatav(iovec, 2)) {
-        return FLUSH_ERROR;
+
+    char *buffer = NULL;
+
+    if (!mMsg) {
+        entry.len = populateDroppedMessage(buffer, parent);
+        if (!entry.len) {
+            return mSequence;
+        }
+        iovec[1].iov_base = buffer;
+    } else {
+        entry.len = mMsgLen;
+        iovec[1].iov_base = mMsg;
+    }
+    iovec[1].iov_len = entry.len;
+
+    uint64_t retval = reader->sendDatav(iovec, 2) ? FLUSH_ERROR : mSequence;
+
+    if (buffer) {
+        free(buffer);
     }
 
-    return mMonotonicTime;
+    return retval;
 }
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index fdca973..ca2c3a6 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -17,20 +17,60 @@
 #ifndef _LOGD_LOG_BUFFER_ELEMENT_H__
 #define _LOGD_LOG_BUFFER_ELEMENT_H__
 
+#include <stdatomic.h>
+#include <stdlib.h>
 #include <sys/types.h>
+
 #include <sysutils/SocketClient.h>
 #include <log/log.h>
 #include <log/log_read.h>
 
+// Hijack this header as a common include file used by most all sources
+// to report some utilities defined here and there.
+
+namespace android {
+
+// Furnished in main.cpp. Caller must own and free returned value
+char *uidToName(uid_t uid);
+
+// 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);
+
+}
+
+static inline bool worstUidEnabledForLogid(log_id_t id) {
+    return (id != LOG_ID_CRASH) && (id != LOG_ID_KERNEL) && (id != LOG_ID_EVENTS);
+}
+
+class LogBuffer;
+
+#define EXPIRE_HOUR_THRESHOLD 24 // Only expire chatty UID logs to preserve
+                                 // non-chatty UIDs less than this age in hours
+#define EXPIRE_THRESHOLD 10      // A smaller expire count is considered too
+                                 // chatty for the temporal expire messages
+#define EXPIRE_RATELIMIT 10      // maximum rate in seconds to report expiration
+
 class LogBufferElement {
     const log_id_t mLogId;
     const uid_t mUid;
     const pid_t mPid;
     const pid_t mTid;
     char *mMsg;
-    const unsigned short mMsgLen;
-    const log_time mMonotonicTime;
+    union {
+        const unsigned short mMsgLen; // mMSg != NULL
+        unsigned short mDropped;      // mMsg == NULL
+    };
+    const uint64_t mSequence;
     const log_time mRealTime;
+    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,
@@ -42,12 +82,23 @@
     uid_t getUid(void) const { return mUid; }
     pid_t getPid(void) const { return mPid; }
     pid_t getTid(void) const { return mTid; }
-    unsigned short getMsgLen() const { return mMsgLen; }
-    log_time getMonotonicTime(void) const { return mMonotonicTime; }
+    unsigned short getDropped(void) const { return mMsg ? 0 : mDropped; }
+    unsigned short setDropped(unsigned short value) {
+        if (mMsg) {
+            free(mMsg);
+            mMsg = NULL;
+        }
+        return mDropped = value;
+    }
+    unsigned short getMsgLen() const { return mMsg ? mMsgLen : 0; }
+    uint64_t getSequence(void) const { return mSequence; }
+    static uint64_t getCurrentSequence(void) { return sequence.load(memory_order_relaxed); }
     log_time getRealTime(void) const { return mRealTime; }
 
-    static const log_time FLUSH_ERROR;
-    log_time flushTo(SocketClient *writer);
+    uint32_t getTag(void) const;
+
+    static const uint64_t FLUSH_ERROR;
+    uint64_t flushTo(SocketClient *writer, LogBuffer *parent);
 };
 
 #endif
diff --git a/logd/LogCommand.cpp b/logd/LogCommand.cpp
index e4c138e..06d865c 100644
--- a/logd/LogCommand.cpp
+++ b/logd/LogCommand.cpp
@@ -17,13 +17,13 @@
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include <private/android_filesystem_config.h>
 
 #include "LogCommand.h"
 
-LogCommand::LogCommand(const char *cmd)
-        : FrameworkCommand(cmd) {
+LogCommand::LogCommand(const char *cmd) : FrameworkCommand(cmd) {
 }
 
 // gets a list of supplementary group IDs associated with
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
new file mode 100644
index 0000000..d578c04
--- /dev/null
+++ b/logd/LogKlog.cpp
@@ -0,0 +1,598 @@
+/*
+ * 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 <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/prctl.h>
+#include <sys/uio.h>
+#include <syslog.h>
+
+#include <log/logger.h>
+
+#include "LogKlog.h"
+
+#define KMSG_PRIORITY(PRI)           \
+    '<',                             \
+    '0' + (LOG_SYSLOG | (PRI)) / 10, \
+    '0' + (LOG_SYSLOG | (PRI)) % 10, \
+    '>'
+
+static const char priority_message[] = { KMSG_PRIORITY(LOG_INFO), '\0' };
+
+// Parsing is hard
+
+// called if we see a '<', s is the next character, returns pointer after '>'
+static char *is_prio(char *s) {
+    if (!isdigit(*s++)) {
+        return NULL;
+    }
+    char c;
+    while ((c = *s++)) {
+        if (!isdigit(c)) {
+            return (c == '>') ? s : NULL;
+        }
+    }
+    return NULL;
+}
+
+// called if we see a '[', s is the next character, returns pointer after ']'
+static char *is_timestamp(char *s) {
+    while (*s == ' ') {
+        ++s;
+    }
+    if (!isdigit(*s++)) {
+        return NULL;
+    }
+    bool first_period = true;
+    char c;
+    while ((c = *s++)) {
+        if ((c == '.') && first_period) {
+            first_period = false;
+        } else if (!isdigit(c)) {
+            return ((c == ']') && !first_period && (*s == ' ')) ? s : NULL;
+        }
+    }
+    return NULL;
+}
+
+// Like strtok_r with "\r\n" except that we look for log signatures (regex)
+// \(\(<[0-9]+>\)\([[] *[0-9]+[.][0-9]+[]] \)\{0,1\}\|[[] *[0-9]+[.][0-9]+[]] \)
+// and split if we see a second one without a newline.
+
+#define SIGNATURE_MASK     0xF0
+// <digit> following ('0' to '9' masked with ~SIGNATURE_MASK) added to signature
+#define LESS_THAN_SIG      SIGNATURE_MASK
+#define OPEN_BRACKET_SIG   ((SIGNATURE_MASK << 1) & SIGNATURE_MASK)
+// space is one more than <digit> of 9
+#define OPEN_BRACKET_SPACE ((char)(OPEN_BRACKET_SIG | 10))
+
+char *log_strtok_r(char *s, char **last) {
+    if (!s) {
+        if (!(s = *last)) {
+            return NULL;
+        }
+        // fixup for log signature split <,
+        // LESS_THAN_SIG + <digit>
+        if ((*s & SIGNATURE_MASK) == LESS_THAN_SIG) {
+            *s = (*s & ~SIGNATURE_MASK) + '0';
+            *--s = '<';
+        }
+        // fixup for log signature split [,
+        // OPEN_BRACKET_SPACE is space, OPEN_BRACKET_SIG + <digit>
+        if ((*s & SIGNATURE_MASK) == OPEN_BRACKET_SIG) {
+            if (*s == OPEN_BRACKET_SPACE) {
+                *s = ' ';
+            } else {
+                *s = (*s & ~SIGNATURE_MASK) + '0';
+            }
+            *--s = '[';
+        }
+    }
+
+    s += strspn(s, "\r\n");
+
+    if (!*s) { // no non-delimiter characters
+        *last = NULL;
+        return NULL;
+    }
+    char *peek, *tok = s;
+
+    for (;;) {
+        char c = *s++;
+        switch (c) {
+        case '\0':
+            *last = NULL;
+            return tok;
+
+        case '\r':
+        case '\n':
+            s[-1] = '\0';
+            *last = s;
+            return tok;
+
+        case '<':
+            peek = is_prio(s);
+            if (!peek) {
+                break;
+            }
+            if (s != (tok + 1)) { // not first?
+                s[-1] = '\0';
+                *s &= ~SIGNATURE_MASK;
+                *s |= LESS_THAN_SIG; // signature for '<'
+                *last = s;
+                return tok;
+            }
+            s = peek;
+            if ((*s == '[') && ((peek = is_timestamp(s + 1)))) {
+                s = peek;
+            }
+            break;
+
+        case '[':
+            peek = is_timestamp(s);
+            if (!peek) {
+                break;
+            }
+            if (s != (tok + 1)) { // not first?
+                s[-1] = '\0';
+                if (*s == ' ') {
+                    *s = OPEN_BRACKET_SPACE;
+                } else {
+                    *s &= ~SIGNATURE_MASK;
+                    *s |= OPEN_BRACKET_SIG; // signature for '['
+                }
+                *last = s;
+                return tok;
+            }
+            s = peek;
+            break;
+        }
+    }
+    /* NOTREACHED */
+}
+
+log_time LogKlog::correction = log_time(CLOCK_REALTIME) - log_time(CLOCK_MONOTONIC);
+
+LogKlog::LogKlog(LogBuffer *buf, LogReader *reader, int fdWrite, int fdRead, bool auditd) :
+        SocketListener(fdRead, false),
+        logbuf(buf),
+        reader(reader),
+        signature(CLOCK_MONOTONIC),
+        fdWrite(fdWrite),
+        fdRead(fdRead),
+        initialized(false),
+        enableLogging(true),
+        auditd(auditd) {
+    static const char klogd_message[] = "%slogd.klogd: %" PRIu64 "\n";
+    char buffer[sizeof(priority_message) + sizeof(klogd_message) + 20 - 4];
+    snprintf(buffer, sizeof(buffer), klogd_message, priority_message,
+        signature.nsec());
+    write(fdWrite, buffer, strlen(buffer));
+}
+
+bool LogKlog::onDataAvailable(SocketClient *cli) {
+    if (!initialized) {
+        prctl(PR_SET_NAME, "logd.klogd");
+        initialized = true;
+        enableLogging = false;
+    }
+
+    char buffer[LOGGER_ENTRY_MAX_PAYLOAD];
+    size_t len = 0;
+
+    for(;;) {
+        ssize_t retval = 0;
+        if ((sizeof(buffer) - 1 - len) > 0) {
+            retval = read(cli->getSocket(), buffer + len, sizeof(buffer) - 1 - len);
+        }
+        if ((retval == 0) && (len == 0)) {
+            break;
+        }
+        if (retval < 0) {
+            return false;
+        }
+        len += retval;
+        bool full = len == (sizeof(buffer) - 1);
+        char *ep = buffer + len;
+        *ep = '\0';
+        len = 0;
+        for(char *ptr = NULL, *tok = buffer;
+                ((tok = log_strtok_r(tok, &ptr)));
+                tok = NULL) {
+            if (((tok + strlen(tok)) == ep) && (retval != 0) && full) {
+                len = strlen(tok);
+                memmove(buffer, tok, len);
+                break;
+            }
+            if (*tok) {
+                log(tok);
+            }
+        }
+    }
+
+    return true;
+}
+
+
+void LogKlog::calculateCorrection(const log_time &monotonic,
+                                  const char *real_string) {
+    log_time real;
+    if (!real.strptime(real_string, "%Y-%m-%d %H:%M:%S.%09q UTC")) {
+        return;
+    }
+    // kernel report UTC, log_time::strptime is localtime from calendar.
+    // Bionic and liblog strptime does not support %z or %Z to pick up
+    // timezone so we are calculating our own correction.
+    time_t now = real.tv_sec;
+    struct tm tm;
+    memset(&tm, 0, sizeof(tm));
+    tm.tm_isdst = -1;
+    localtime_r(&now, &tm);
+    real.tv_sec += tm.tm_gmtoff;
+    correction = real - monotonic;
+}
+
+void LogKlog::sniffTime(log_time &now, const char **buf, bool reverse) {
+    const char *cp;
+    if ((cp = now.strptime(*buf, "[ %s.%q]"))) {
+        static const char suspend[] = "PM: suspend entry ";
+        static const char resume[] = "PM: suspend exit ";
+        static const char suspended[] = "Suspended for ";
+
+        if (isspace(*cp)) {
+            ++cp;
+        }
+        if (!strncmp(cp, suspend, sizeof(suspend) - 1)) {
+            calculateCorrection(now, cp + sizeof(suspend) - 1);
+        } else if (!strncmp(cp, resume, sizeof(resume) - 1)) {
+            calculateCorrection(now, cp + sizeof(resume) - 1);
+        } else if (!strncmp(cp, suspended, sizeof(suspended) - 1)) {
+            log_time real;
+            char *endp;
+            real.tv_sec = strtol(cp + sizeof(suspended) - 1, &endp, 10);
+            if (*endp == '.') {
+                real.tv_nsec = strtol(endp + 1, &endp, 10) * 1000000L;
+                if (reverse) {
+                    correction -= real;
+                } else {
+                    correction += real;
+                }
+            }
+        }
+
+        convertMonotonicToReal(now);
+        *buf = cp;
+    } else {
+        now = log_time(CLOCK_REALTIME);
+    }
+}
+
+// Passed the entire SYSLOG_ACTION_READ_ALL buffer and interpret a
+// compensated start time.
+void LogKlog::synchronize(const char *buf) {
+    const char *cp = strstr(buf, "] PM: suspend e");
+    if (!cp) {
+        return;
+    }
+
+    do {
+        --cp;
+    } while ((cp > buf) && (isdigit(*cp) || isspace(*cp) || (*cp == '.')));
+
+    log_time now;
+    sniffTime(now, &cp, true);
+
+    char *suspended = strstr(buf, "] Suspended for ");
+    if (!suspended || (suspended > cp)) {
+        return;
+    }
+    cp = suspended;
+
+    do {
+        --cp;
+    } while ((cp > buf) && (isdigit(*cp) || isspace(*cp) || (*cp == '.')));
+
+    sniffTime(now, &cp, true);
+}
+
+// kernel log prefix, convert to a kernel log priority number
+static int parseKernelPrio(const char **buf) {
+    int pri = LOG_USER | LOG_INFO;
+    const char *cp = *buf;
+    if (*cp == '<') {
+        pri = 0;
+        while(isdigit(*++cp)) {
+            pri = (pri * 10) + *cp - '0';
+        }
+        if (*cp == '>') {
+            ++cp;
+        } else {
+            cp = *buf;
+            pri = LOG_USER | LOG_INFO;
+        }
+        *buf = cp;
+    }
+    return pri;
+}
+
+// Convert kernel log priority number into an Android Logger priority number
+static int convertKernelPrioToAndroidPrio(int pri) {
+    switch(pri & LOG_PRIMASK) {
+    case LOG_EMERG:
+        // FALLTHRU
+    case LOG_ALERT:
+        // FALLTHRU
+    case LOG_CRIT:
+        return ANDROID_LOG_FATAL;
+
+    case LOG_ERR:
+        return ANDROID_LOG_ERROR;
+
+    case LOG_WARNING:
+        return ANDROID_LOG_WARN;
+
+    default:
+        // FALLTHRU
+    case LOG_NOTICE:
+        // FALLTHRU
+    case LOG_INFO:
+        break;
+
+    case LOG_DEBUG:
+        return ANDROID_LOG_DEBUG;
+    }
+
+    return ANDROID_LOG_INFO;
+}
+
+//
+// log a message into the kernel log buffer
+//
+// Filter rules to parse <PRI> <TIME> <tag> and <message> in order for
+// them to appear correct in the logcat output:
+//
+// LOG_KERN (0):
+// <PRI>[<TIME>] <tag> ":" <message>
+// <PRI>[<TIME>] <tag> <tag> ":" <message>
+// <PRI>[<TIME>] <tag> <tag>_work ":" <message>
+// <PRI>[<TIME>] <tag> '<tag>.<num>' ":" <message>
+// <PRI>[<TIME>] <tag> '<tag><num>' ":" <message>
+// <PRI>[<TIME>] <tag>_host '<tag>.<num>' ":" <message>
+// (unimplemented) <PRI>[<TIME>] <tag> '<num>.<tag>' ":" <message>
+// <PRI>[<TIME>] "[INFO]"<tag> : <message>
+// <PRI>[<TIME>] "------------[ cut here ]------------"   (?)
+// <PRI>[<TIME>] "---[ end trace 3225a3070ca3e4ac ]---"   (?)
+// LOG_USER, LOG_MAIL, LOG_DAEMON, LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS
+// LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_FTP:
+// <PRI+TAG>[<TIME>] (see sys/syslog.h)
+// Observe:
+//  Minimum tag length = 3   NB: drops things like r5:c00bbadf, but allow PM:
+//  Maximum tag words = 2
+//  Maximum tag length = 16  NB: we are thinking of how ugly logcat can get.
+//  Not a Tag if there is no message content.
+//  leading additional spaces means no tag, inherit last tag.
+//  Not a Tag if <tag>: is "ERROR:", "WARNING:", "INFO:" or "CPU:"
+// Drop:
+//  empty messages
+//  messages with ' audit(' in them if auditd is running
+//  logd.klogd:
+// return -1 if message logd.klogd: <signature>
+//
+int LogKlog::log(const char *buf) {
+    if (auditd && strstr(buf, " audit(")) {
+        return 0;
+    }
+
+    int pri = parseKernelPrio(&buf);
+
+    log_time now;
+    sniffTime(now, &buf, false);
+
+    // sniff for start marker
+    const char klogd_message[] = "logd.klogd: ";
+    if (!strncmp(buf, klogd_message, sizeof(klogd_message) - 1)) {
+        char *endp;
+        uint64_t sig = strtoll(buf + sizeof(klogd_message) - 1, &endp, 10);
+        if (sig == signature.nsec()) {
+            if (initialized) {
+                enableLogging = true;
+            } else {
+                enableLogging = false;
+            }
+            return -1;
+        }
+        return 0;
+    }
+
+    if (!enableLogging) {
+        return 0;
+    }
+
+    // Parse pid, tid and uid (not possible)
+    const pid_t pid = 0;
+    const pid_t tid = 0;
+    const uid_t uid = 0;
+
+    // Parse (rules at top) to pull out a tag from the incoming kernel message.
+    // Some may view the following as an ugly heuristic, the desire is to
+    // beautify the kernel logs into an Android Logging format; the goal is
+    // admirable but costly.
+    while (isspace(*buf)) {
+        ++buf;
+    }
+    if (!*buf) {
+        return 0;
+    }
+    const char *start = buf;
+    const char *tag = "";
+    const char *etag = tag;
+    if (!isspace(*buf)) {
+        const char *bt, *et, *cp;
+
+        bt = buf;
+        if (!strncmp(buf, "[INFO]", 6)) {
+            // <PRI>[<TIME>] "[INFO]"<tag> ":" message
+            bt = buf + 6;
+        }
+        for(et = bt; *et && (*et != ':') && !isspace(*et); ++et);
+        for(cp = et; isspace(*cp); ++cp);
+        size_t size;
+
+        if (*cp == ':') {
+            // One Word
+            tag = bt;
+            etag = et;
+            buf = cp + 1;
+        } else {
+            size = et - bt;
+            if (strncmp(bt, cp, size)) {
+                // <PRI>[<TIME>] <tag>_host '<tag>.<num>' : message
+                if (!strncmp(bt + size - 5, "_host", 5)
+                 && !strncmp(bt, cp, size - 5)) {
+                    const char *b = cp;
+                    cp += size - 5;
+                    if (*cp == '.') {
+                        while (!isspace(*++cp) && (*cp != ':'));
+                        const char *e;
+                        for(e = cp; isspace(*cp); ++cp);
+                        if (*cp == ':') {
+                            tag = b;
+                            etag = e;
+                            buf = cp + 1;
+                        }
+                    }
+                } else {
+                    while (!isspace(*++cp) && (*cp != ':'));
+                    const char *e;
+                    for(e = cp; isspace(*cp); ++cp);
+                    // Two words
+                    if (*cp == ':') {
+                        tag = bt;
+                        etag = e;
+                        buf = cp + 1;
+                    }
+                }
+            } else if (isspace(cp[size])) {
+                const char *b = cp;
+                cp += size;
+                while (isspace(*++cp));
+                // <PRI>[<TIME>] <tag> <tag> : message
+                if (*cp == ':') {
+                    tag = bt;
+                    etag = et;
+                    buf = cp + 1;
+                }
+            } else if (cp[size] == ':') {
+                // <PRI>[<TIME>] <tag> <tag> : message
+                tag = bt;
+                etag = et;
+                buf = cp + size + 1;
+            } else if ((cp[size] == '.') || isdigit(cp[size])) {
+                // <PRI>[<TIME>] <tag> '<tag>.<num>' : message
+                // <PRI>[<TIME>] <tag> '<tag><num>' : message
+                const char *b = cp;
+                cp += size;
+                while (!isspace(*++cp) && (*cp != ':'));
+                const char *e = cp;
+                while (isspace(*cp)) {
+                    ++cp;
+                }
+                if (*cp == ':') {
+                    tag = b;
+                    etag = e;
+                    buf = cp + 1;
+                }
+            } else {
+                while (!isspace(*++cp) && (*cp != ':'));
+                const char *e = cp;
+                while (isspace(*cp)) {
+                    ++cp;
+                }
+                // Two words
+                if (*cp == ':') {
+                    tag = bt;
+                    etag = e;
+                    buf = cp + 1;
+                }
+            }
+        }
+        size = etag - tag;
+        if ((size <= 1)
+         || ((size == 2) && (isdigit(tag[0]) || isdigit(tag[1])))
+         || ((size == 3) && !strncmp(tag, "CPU", 3))
+         || ((size == 7) && !strncmp(tag, "WARNING", 7))
+         || ((size == 5) && !strncmp(tag, "ERROR", 5))
+         || ((size == 4) && !strncmp(tag, "INFO", 4))) {
+            buf = start;
+            etag = tag = "";
+        }
+    }
+    size_t l = etag - tag;
+    // skip leading space
+    while (isspace(*buf)) {
+        ++buf;
+    }
+    // truncate trailing space
+    size_t b = strlen(buf);
+    while (b && isspace(buf[b-1])) {
+        --b;
+    }
+    // trick ... allow tag with empty content to be logged. log() drops empty
+    if (!b && l) {
+        buf = " ";
+        b = 1;
+    }
+    size_t n = 1 + l + 1 + b + 1;
+
+    // Allocate a buffer to hold the interpreted log message
+    int rc = n;
+    char *newstr = reinterpret_cast<char *>(malloc(n));
+    if (!newstr) {
+        rc = -ENOMEM;
+        return rc;
+    }
+    char *np = newstr;
+
+    // Convert priority into single-byte Android logger priority
+    *np = convertKernelPrioToAndroidPrio(pri);
+    ++np;
+
+    // Copy parsed tag following priority
+    strncpy(np, tag, l);
+    np += l;
+    *np = '\0';
+    ++np;
+
+    // Copy main message to the remainder
+    strncpy(np, buf, b);
+    np[b] = '\0';
+
+    // Log message
+    rc = logbuf->log(LOG_ID_KERNEL, now, uid, pid, tid, newstr,
+                     (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
+    free(newstr);
+
+    // notify readers
+    if (!rc) {
+        reader->notifyNewLog();
+    }
+
+    return rc;
+}
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
new file mode 100644
index 0000000..a898c63
--- /dev/null
+++ b/logd/LogKlog.h
@@ -0,0 +1,57 @@
+/*
+ * 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 _LOGD_LOG_KLOG_H__
+#define _LOGD_LOG_KLOG_H__
+
+#include <sysutils/SocketListener.h>
+#include <log/log_read.h>
+#include "LogReader.h"
+
+char *log_strtok_r(char *str, char **saveptr);
+
+class LogKlog : public SocketListener {
+    LogBuffer *logbuf;
+    LogReader *reader;
+    const log_time signature;
+    const int fdWrite; // /dev/kmsg
+    const int fdRead;  // /proc/kmsg
+    // Set once thread is started, separates KLOG_ACTION_READ_ALL
+    // and KLOG_ACTION_READ phases.
+    bool initialized;
+    // Used during each of the above phases to control logging.
+    bool enableLogging;
+    // set if we are also running auditd, to filter out audit reports from
+    // our copy of the kernel log
+    bool auditd;
+
+    static log_time correction;
+
+public:
+    LogKlog(LogBuffer *buf, LogReader *reader, int fdWrite, int fdRead, bool auditd);
+    int log(const char *buf);
+    void synchronize(const char *buf);
+
+    static void convertMonotonicToReal(log_time &real) { real += correction; }
+
+protected:
+    void sniffTime(log_time &now, const char **buf, bool reverse);
+    void calculateCorrection(const log_time &monotonic, const char *real_string);
+    virtual bool onDataAvailable(SocketClient *cli);
+
+};
+
+#endif
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index 8186cea..b29f5ab 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -23,17 +23,23 @@
 
 #include <cutils/sockets.h>
 #include <log/logger.h>
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
 
 #include "LogListener.h"
 
-LogListener::LogListener(LogBuffer *buf, LogReader *reader)
-        : SocketListener(getLogSocket(), false)
-        , logbuf(buf)
-        , reader(reader)
-{  }
+LogListener::LogListener(LogBuffer *buf, LogReader *reader) :
+        SocketListener(getLogSocket(), false),
+        logbuf(buf),
+        reader(reader) {
+}
 
 bool LogListener::onDataAvailable(SocketClient *cli) {
-    prctl(PR_SET_NAME, "logd.writer");
+    static bool name_set;
+    if (!name_set) {
+        prctl(PR_SET_NAME, "logd.writer");
+        name_set = true;
+    }
 
     char buffer[sizeof_log_id_t + sizeof(uint16_t) + sizeof(log_time)
         + LOGGER_ENTRY_MAX_PAYLOAD];
@@ -54,7 +60,7 @@
     int socket = cli->getSocket();
 
     ssize_t n = recvmsg(socket, &hdr, 0);
-    if (n <= (ssize_t)(sizeof_log_id_t + sizeof(uint16_t) + sizeof(log_time))) {
+    if (n <= (ssize_t)(sizeof(android_log_header_t))) {
         return false;
     }
 
@@ -74,37 +80,29 @@
         return false;
     }
 
-    if (cred->uid == getuid()) {
+    if (cred->uid == AID_LOGD) {
         // ignore log messages we send to ourself.
         // Such log messages are often generated by libraries we depend on
         // which use standard Android logging.
         return false;
     }
 
-    // First log element is always log_id.
-    log_id_t log_id = (log_id_t) *((typeof_log_id_t *) buffer);
-    if (log_id < 0 || log_id >= LOG_ID_MAX) {
+    android_log_header_t *header = reinterpret_cast<android_log_header_t *>(buffer);
+    if (/* header->id < LOG_ID_MIN || */ header->id >= LOG_ID_MAX || header->id == LOG_ID_KERNEL) {
         return false;
     }
-    char *msg = ((char *)buffer) + sizeof_log_id_t;
-    n -= sizeof_log_id_t;
 
-    // second element is the thread id of the caller
-    pid_t tid = (pid_t) *((uint16_t *) msg);
-    msg += sizeof(uint16_t);
-    n -= sizeof(uint16_t);
-
-    // third element is the realtime at point of caller
-    log_time realtime(msg);
-    msg += sizeof(log_time);
-    n -= sizeof(log_time);
+    char *msg = ((char *)buffer) + sizeof(android_log_header_t);
+    n -= sizeof(android_log_header_t);
 
     // NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a
     // truncated message to the logs.
 
-    logbuf->log(log_id, realtime, cred->uid, cred->pid, tid, msg,
-        ((size_t) n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
-    reader->notifyNewLog();
+    if (logbuf->log((log_id_t)header->id, header->realtime,
+            cred->uid, cred->pid, header->tid, msg,
+            ((size_t) n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX) >= 0) {
+        reader->notifyNewLog();
+    }
 
     return true;
 }
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 26df087..c7deec0 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -24,10 +24,10 @@
 #include "LogReader.h"
 #include "FlushCommand.h"
 
-LogReader::LogReader(LogBuffer *logbuf)
-        : SocketListener(getLogSocket(), true)
-        , mLogbuf(*logbuf)
-{ }
+LogReader::LogReader(LogBuffer *logbuf) :
+        SocketListener(getLogSocket(), true),
+        mLogbuf(*logbuf) {
+}
 
 // When we are notified a new log entry is available, inform
 // all of our listening sockets.
@@ -37,7 +37,11 @@
 }
 
 bool LogReader::onDataAvailable(SocketClient *cli) {
-    prctl(PR_SET_NAME, "logd.reader");
+    static bool name_set;
+    if (!name_set) {
+        prctl(PR_SET_NAME, "logd.reader");
+        name_set = true;
+    }
 
     char buffer[255];
 
@@ -100,50 +104,51 @@
         nonBlock = true;
     }
 
-    // Convert realtime to monotonic time
-    if (start == log_time::EPOCH) {
-        start = LogTimeEntry::EPOCH;
-    } else {
+    uint64_t sequence = 1;
+    // Convert realtime to sequence number
+    if (start != log_time::EPOCH) {
         class LogFindStart {
             const pid_t mPid;
             const unsigned mLogMask;
             bool startTimeSet;
             log_time &start;
-            log_time last;
+            uint64_t &sequence;
+            uint64_t last;
 
         public:
-            LogFindStart(unsigned logMask, pid_t pid, log_time &start)
-                    : mPid(pid)
-                    , mLogMask(logMask)
-                    , startTimeSet(false)
-                    , start(start)
-                    , last(LogTimeEntry::EPOCH)
-            { }
+            LogFindStart(unsigned logMask, pid_t pid, log_time &start, uint64_t &sequence) :
+                    mPid(pid),
+                    mLogMask(logMask),
+                    startTimeSet(false),
+                    start(start),
+                    sequence(sequence),
+                    last(sequence) {
+            }
 
-            static bool callback(const LogBufferElement *element, void *obj) {
+            static int callback(const LogBufferElement *element, void *obj) {
                 LogFindStart *me = reinterpret_cast<LogFindStart *>(obj);
-                if (!me->startTimeSet
-                        && (!me->mPid || (me->mPid == element->getPid()))
+                if ((!me->mPid || (me->mPid == element->getPid()))
                         && (me->mLogMask & (1 << element->getLogId()))) {
                     if (me->start == element->getRealTime()) {
-                        me->start = element->getMonotonicTime();
+                        me->sequence = element->getSequence();
                         me->startTimeSet = true;
+                        return -1;
                     } else {
                         if (me->start < element->getRealTime()) {
-                            me->start = me->last;
+                            me->sequence = me->last;
                             me->startTimeSet = true;
+                            return -1;
                         }
-                        me->last = element->getMonotonicTime();
+                        me->last = element->getSequence();
                     }
                 }
                 return false;
             }
 
             bool found() { return startTimeSet; }
-        } logFindStart(logMask, pid, start);
+        } logFindStart(logMask, pid, start, sequence);
 
-        logbuf().flushTo(cli, LogTimeEntry::EPOCH,
-                         FlushCommand::hasReadLogs(cli),
+        logbuf().flushTo(cli, sequence, FlushCommand::hasReadLogs(cli),
                          logFindStart.callback, &logFindStart);
 
         if (!logFindStart.found()) {
@@ -151,12 +156,11 @@
                 doSocketDelete(cli);
                 return false;
             }
-            log_time now(CLOCK_MONOTONIC);
-            start = now;
+            sequence = LogBufferElement::getCurrentSequence();
         }
     }
 
-    FlushCommand command(*this, nonBlock, tail, logMask, pid, start);
+    FlushCommand command(*this, nonBlock, tail, logMask, pid, sequence);
     command.runSocketCommand(cli);
     return true;
 }
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 2a45590..48c2fe6 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -14,9 +14,11 @@
  * limitations under the License.
  */
 
+#include <algorithm> // std::max
 #include <fcntl.h>
-#include <stdarg.h>
-#include <time.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
 
 #include <log/logger.h>
 #include <private/android_filesystem_config.h>
@@ -24,80 +26,23 @@
 
 #include "LogStatistics.h"
 
-PidStatistics::PidStatistics(pid_t pid, char *name)
-        : pid(pid)
-        , mSizesTotal(0)
-        , mElementsTotal(0)
-        , mSizes(0)
-        , mElements(0)
-        , name(name)
-        , mGone(false)
-{ }
-
-#ifdef DO_NOT_ERROR_IF_PIDSTATISTICS_USES_A_COPY_CONSTRUCTOR
-PidStatistics::PidStatistics(const PidStatistics &copy)
-        : pid(copy->pid)
-        , name(copy->name ? strdup(copy->name) : NULL)
-        , mSizesTotal(copy->mSizesTotal)
-        , mElementsTotal(copy->mElementsTotal)
-        , mSizes(copy->mSizes)
-        , mElements(copy->mElements)
-        , mGone(copy->mGone)
-{ }
-#endif
-
-PidStatistics::~PidStatistics() {
-    free(name);
-}
-
-bool PidStatistics::pidGone() {
-    if (mGone || (pid == gone)) {
-        return true;
-    }
-    if (pid == 0) {
-        return false;
-    }
-    if (kill(pid, 0) && (errno != EPERM)) {
-        mGone = true;
-        return true;
-    }
-    return false;
-}
-
-void PidStatistics::setName(char *new_name) {
-    free(name);
-    name = new_name;
-}
-
-void PidStatistics::add(unsigned short size) {
-    mSizesTotal += size;
-    ++mElementsTotal;
-    mSizes += size;
-    ++mElements;
-}
-
-bool PidStatistics::subtract(unsigned short size) {
-    mSizes -= size;
-    --mElements;
-    return (mElements == 0) && pidGone();
-}
-
-void PidStatistics::addTotal(size_t size, size_t element) {
-    if (pid == gone) {
-        mSizesTotal += size;
-        mElementsTotal += element;
+LogStatistics::LogStatistics() : enable(false) {
+    log_id_for_each(id) {
+        mSizes[id] = 0;
+        mElements[id] = 0;
+        mSizesTotal[id] = 0;
+        mElementsTotal[id] = 0;
     }
 }
 
-// must call free to release return value
-//  If only we could sniff our own logs for:
-//   <time> <pid> <pid> E AndroidRuntime: Process: <name>, PID: <pid>
-//  which debuggerd prints as a process is crashing.
-char *PidStatistics::pidToName(pid_t pid) {
+namespace android {
+
+// caller must own and free character string
+char *pidToName(pid_t pid) {
     char *retval = NULL;
-    if (pid == 0) { // special case from auditd for kernel
-        retval = strdup("logd.auditd");
-    } else if (pid != gone) {
+    if (pid == 0) { // special case from auditd/klogd for kernel
+        retval = strdup("logd");
+    } else {
         char buffer[512];
         snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
         int fd = open(buffer, O_RDONLY);
@@ -116,418 +61,148 @@
     return retval;
 }
 
-UidStatistics::UidStatistics(uid_t uid)
-        : uid(uid)
-        , mSizes(0)
-        , mElements(0) {
-    Pids.clear();
 }
 
-UidStatistics::~UidStatistics() {
-    PidStatisticsCollection::iterator it;
-    for (it = begin(); it != end();) {
-        delete (*it);
-        it = erase(it);
-    }
-}
-
-void UidStatistics::add(unsigned short size, pid_t pid) {
-    mSizes += size;
-    ++mElements;
-
-    PidStatistics *p = NULL;
-    PidStatisticsCollection::iterator last;
-    PidStatisticsCollection::iterator it;
-    for (last = it = begin(); it != end(); last = it, ++it) {
-        p = *it;
-        if (pid == p->getPid()) {
-            p->add(size);
-            return;
-        }
-    }
-    // insert if the gone entry.
-    bool insert_before_last = (last != it) && p && (p->getPid() == p->gone);
-    p = new PidStatistics(pid, pidToName(pid));
-    if (insert_before_last) {
-        insert(last, p);
-    } else {
-        push_back(p);
-    }
-    p->add(size);
-}
-
-void UidStatistics::subtract(unsigned short size, pid_t pid) {
-    mSizes -= size;
-    --mElements;
-
-    PidStatisticsCollection::iterator it;
-    for (it = begin(); it != end(); ++it) {
-        PidStatistics *p = *it;
-        if (pid == p->getPid()) {
-            if (p->subtract(size)) {
-                size_t szsTotal = p->sizesTotal();
-                size_t elsTotal = p->elementsTotal();
-                delete p;
-                erase(it);
-                it = end();
-                --it;
-                if (it == end()) {
-                    p = new PidStatistics(p->gone);
-                    push_back(p);
-                } else {
-                    p = *it;
-                    if (p->getPid() != p->gone) {
-                        p = new PidStatistics(p->gone);
-                        push_back(p);
-                    }
-                }
-                p->addTotal(szsTotal, elsTotal);
-            }
-            return;
-        }
-    }
-}
-
-void UidStatistics::sort() {
-    for (bool pass = true; pass;) {
-        pass = false;
-        PidStatisticsCollection::iterator it = begin();
-        if (it != end()) {
-            PidStatisticsCollection::iterator lt = it;
-            PidStatistics *l = (*lt);
-            while (++it != end()) {
-                PidStatistics *n = (*it);
-                if ((n->getPid() != n->gone) && (n->sizes() > l->sizes())) {
-                    pass = true;
-                    erase(it);
-                    insert(lt, n);
-                    it = lt;
-                    n = l;
-                }
-                lt = it;
-                l = n;
-            }
-        }
-    }
-}
-
-size_t UidStatistics::sizes(pid_t pid) {
-    if (pid == pid_all) {
-        return sizes();
-    }
-
-    PidStatisticsCollection::iterator it;
-    for (it = begin(); it != end(); ++it) {
-        PidStatistics *p = *it;
-        if (pid == p->getPid()) {
-            return p->sizes();
-        }
-    }
-    return 0;
-}
-
-size_t UidStatistics::elements(pid_t pid) {
-    if (pid == pid_all) {
-        return elements();
-    }
-
-    PidStatisticsCollection::iterator it;
-    for (it = begin(); it != end(); ++it) {
-        PidStatistics *p = *it;
-        if (pid == p->getPid()) {
-            return p->elements();
-        }
-    }
-    return 0;
-}
-
-size_t UidStatistics::sizesTotal(pid_t pid) {
-    size_t sizes = 0;
-    PidStatisticsCollection::iterator it;
-    for (it = begin(); it != end(); ++it) {
-        PidStatistics *p = *it;
-        if ((pid == pid_all) || (pid == p->getPid())) {
-            sizes += p->sizesTotal();
-        }
-    }
-    return sizes;
-}
-
-size_t UidStatistics::elementsTotal(pid_t pid) {
-    size_t elements = 0;
-    PidStatisticsCollection::iterator it;
-    for (it = begin(); it != end(); ++it) {
-        PidStatistics *p = *it;
-        if ((pid == pid_all) || (pid == p->getPid())) {
-            elements += p->elementsTotal();
-        }
-    }
-    return elements;
-}
-
-LidStatistics::LidStatistics() {
-    Uids.clear();
-}
-
-LidStatistics::~LidStatistics() {
-    UidStatisticsCollection::iterator it;
-    for (it = begin(); it != end();) {
-        delete (*it);
-        it = Uids.erase(it);
-    }
-}
-
-void LidStatistics::add(unsigned short size, uid_t uid, pid_t pid) {
-    UidStatistics *u;
-    UidStatisticsCollection::iterator it;
-    UidStatisticsCollection::iterator last;
-
-    if (uid == (uid_t) -1) { // init
-        uid = (uid_t) AID_ROOT;
-    }
-
-    for (last = it = begin(); it != end(); last = it, ++it) {
-        u = *it;
-        if (uid == u->getUid()) {
-            u->add(size, pid);
-            if ((last != it) && ((*last)->sizesTotal() < u->sizesTotal())) {
-                Uids.erase(it);
-                Uids.insert(last, u);
-            }
-            return;
-        }
-    }
-    u = new UidStatistics(uid);
-    if ((last != it) && ((*last)->sizesTotal() < (size_t) size)) {
-        Uids.insert(last, u);
-    } else {
-        Uids.push_back(u);
-    }
-    u->add(size, pid);
-}
-
-void LidStatistics::subtract(unsigned short size, uid_t uid, pid_t pid) {
-    if (uid == (uid_t) -1) { // init
-        uid = (uid_t) AID_ROOT;
-    }
-
-    UidStatisticsCollection::iterator it;
-    for (it = begin(); it != end(); ++it) {
-        UidStatistics *u = *it;
-        if (uid == u->getUid()) {
-            u->subtract(size, pid);
-            return;
-        }
-    }
-}
-
-void LidStatistics::sort() {
-    for (bool pass = true; pass;) {
-        pass = false;
-        UidStatisticsCollection::iterator it = begin();
-        if (it != end()) {
-            UidStatisticsCollection::iterator lt = it;
-            UidStatistics *l = (*lt);
-            while (++it != end()) {
-                UidStatistics *n = (*it);
-                if (n->sizes() > l->sizes()) {
-                    pass = true;
-                    Uids.erase(it);
-                    Uids.insert(lt, n);
-                    it = lt;
-                    n = l;
-                }
-                lt = it;
-                l = n;
-            }
-        }
-    }
-}
-
-size_t LidStatistics::sizes(uid_t uid, pid_t pid) {
-    size_t sizes = 0;
-    UidStatisticsCollection::iterator it;
-    for (it = begin(); it != end(); ++it) {
-        UidStatistics *u = *it;
-        if ((uid == uid_all) || (uid == u->getUid())) {
-            sizes += u->sizes(pid);
-        }
-    }
-    return sizes;
-}
-
-size_t LidStatistics::elements(uid_t uid, pid_t pid) {
-    size_t elements = 0;
-    UidStatisticsCollection::iterator it;
-    for (it = begin(); it != end(); ++it) {
-        UidStatistics *u = *it;
-        if ((uid == uid_all) || (uid == u->getUid())) {
-            elements += u->elements(pid);
-        }
-    }
-    return elements;
-}
-
-size_t LidStatistics::sizesTotal(uid_t uid, pid_t pid) {
-    size_t sizes = 0;
-    UidStatisticsCollection::iterator it;
-    for (it = begin(); it != end(); ++it) {
-        UidStatistics *u = *it;
-        if ((uid == uid_all) || (uid == u->getUid())) {
-            sizes += u->sizesTotal(pid);
-        }
-    }
-    return sizes;
-}
-
-size_t LidStatistics::elementsTotal(uid_t uid, pid_t pid) {
-    size_t elements = 0;
-    UidStatisticsCollection::iterator it;
-    for (it = begin(); it != end(); ++it) {
-        UidStatistics *u = *it;
-        if ((uid == uid_all) || (uid == u->getUid())) {
-            elements += u->elementsTotal(pid);
-        }
-    }
-    return elements;
-}
-
-LogStatistics::LogStatistics()
-        : mStatistics(false)
-        , dgramQlenStatistics(false)
-        , start(CLOCK_MONOTONIC) {
-    log_id_for_each(i) {
-        mSizes[i] = 0;
-        mElements[i] = 0;
-    }
-
-    for(unsigned short bucket = 0; dgramQlen(bucket); ++bucket) {
-        mMinimum[bucket].tv_sec = mMinimum[bucket].tv_sec_max;
-        mMinimum[bucket].tv_nsec = mMinimum[bucket].tv_nsec_max;
-    }
-}
-
-//   Each bucket below represents a dgramQlen of log messages. By
-//   finding the minimum period of time from start to finish
-//   of each dgramQlen, we can get a performance expectation for
-//   the user space logger. The net result is that the period
-//   of time divided by the dgramQlen will give us the average time
-//   between log messages; at the point where the average time
-//   is greater than the throughput capability of the logger
-//   we will not longer require the benefits of the FIFO formed
-//   by max_dgram_qlen. We will also expect to see a very visible
-//   knee in the average time between log messages at this point,
-//   so we do not necessarily have to compare the rate against the
-//   measured performance (BM_log_maximum_retry) of the logger.
-//
-//   for example (reformatted):
-//
-//       Minimum time between log events per dgramQlen:
-//       1   2   3   5   10  20  30  50  100  200 300 400 500 600
-//       5u2 12u 13u 15u 16u 27u 30u 36u 407u 3m1 3m3 3m9 3m9 5m5
-//
-//   demonstrates a clear knee rising at 100, so this means that for this
-//   case max_dgram_qlen = 100 would be more than sufficient to handle the
-//   worst that the system could stuff into the logger. The
-//   BM_log_maximum_retry performance (derated by the log collection) on the
-//   same system was 33.2us so we would almost be fine with max_dgram_qlen = 50.
-//   BM_log_maxumum_retry with statistics off is roughly 20us, so
-//   max_dgram_qlen = 20 would work. We will be more than willing to have
-//   a large engineering margin so the rule of thumb that lead us to 100 is
-//   fine.
-//
-// bucket dgramQlen are tuned for /proc/sys/net/unix/max_dgram_qlen = 300
-const unsigned short LogStatistics::mBuckets[] = {
-    1, 2, 3, 5, 10, 20, 30, 50, 100, 200, 300, 400, 500, 600
-};
-
-unsigned short LogStatistics::dgramQlen(unsigned short bucket) {
-    if (bucket >= sizeof(mBuckets) / sizeof(mBuckets[0])) {
-        return 0;
-    }
-    return mBuckets[bucket];
-}
-
-unsigned long long LogStatistics::minimum(unsigned short bucket) {
-    if (mMinimum[bucket].tv_sec == mMinimum[bucket].tv_sec_max) {
-        return 0;
-    }
-    return mMinimum[bucket].nsec();
-}
-
-void LogStatistics::recordDiff(log_time diff, unsigned short bucket) {
-    if ((diff.tv_sec || diff.tv_nsec) && (mMinimum[bucket] > diff)) {
-        mMinimum[bucket] = diff;
-    }
-}
-
-void LogStatistics::add(unsigned short size,
-                        log_id_t log_id, uid_t uid, pid_t pid) {
+void LogStatistics::add(LogBufferElement *e) {
+    log_id_t log_id = e->getLogId();
+    unsigned short size = e->getMsgLen();
     mSizes[log_id] += size;
     ++mElements[log_id];
-    if (!mStatistics) {
+
+    mSizesTotal[log_id] += size;
+    ++mElementsTotal[log_id];
+
+    if (log_id == LOG_ID_KERNEL) {
         return;
     }
-    id(log_id).add(size, uid, pid);
+
+    uidTable[log_id].add(e->getUid(), e);
+
+    if (!enable) {
+        return;
+    }
+
+    pidTable.add(e->getPid(), e);
+    tidTable.add(e->getTid(), e);
+
+    uint32_t tag = e->getTag();
+    if (tag) {
+        tagTable.add(tag, e);
+    }
 }
 
-void LogStatistics::subtract(unsigned short size,
-                             log_id_t log_id, uid_t uid, pid_t pid) {
+void LogStatistics::subtract(LogBufferElement *e) {
+    log_id_t log_id = e->getLogId();
+    unsigned short size = e->getMsgLen();
     mSizes[log_id] -= size;
     --mElements[log_id];
-    if (!mStatistics) {
+
+    if (log_id == LOG_ID_KERNEL) {
         return;
     }
-    id(log_id).subtract(size, uid, pid);
+
+    uidTable[log_id].subtract(e->getUid(), e);
+
+    if (!enable) {
+        return;
+    }
+
+    pidTable.subtract(e->getPid(), e);
+    tidTable.subtract(e->getTid(), e);
+
+    uint32_t tag = e->getTag();
+    if (tag) {
+        tagTable.subtract(tag, e);
+    }
 }
 
-size_t LogStatistics::sizes(log_id_t log_id, uid_t uid, pid_t pid) {
-    if (log_id != log_id_all) {
-        return id(log_id).sizes(uid, pid);
+// Atomically set an entry to drop
+// entry->setDropped(1) must follow this call, caller should do this explicitly.
+void LogStatistics::drop(LogBufferElement *e) {
+    log_id_t log_id = e->getLogId();
+    unsigned short size = e->getMsgLen();
+    mSizes[log_id] -= size;
+
+    uidTable[log_id].drop(e->getUid(), e);
+
+    if (!enable) {
+        return;
     }
-    size_t sizes = 0;
-    log_id_for_each(i) {
-        sizes += id(i).sizes(uid, pid);
-    }
-    return sizes;
+
+    pidTable.drop(e->getPid(), e);
+    tidTable.drop(e->getTid(), e);
 }
 
-size_t LogStatistics::elements(log_id_t log_id, uid_t uid, pid_t pid) {
-    if (log_id != log_id_all) {
-        return id(log_id).elements(uid, pid);
+// caller must own and free character string
+char *LogStatistics::uidToName(uid_t uid) {
+    // Local hard coded favourites
+    if (uid == AID_LOGD) {
+        return strdup("auditd");
     }
-    size_t elements = 0;
-    log_id_for_each(i) {
-        elements += id(i).elements(uid, pid);
+
+    // 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);
+        }
+        ++info;
     }
-    return elements;
+
+    // Parse /data/system/packages.list
+    uid_t userId = uid % AID_USER;
+    char *name = android::uidToName(userId);
+    if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
+        name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
+    }
+    if (name) {
+        return name;
+    }
+
+    // report uid -> pid(s) -> pidToName if unique
+    for(pidTable_t::iterator it = pidTable.begin(); it != pidTable.end(); ++it) {
+        const PidEntry &entry = it->second;
+
+        if (entry.getUid() == uid) {
+            const char *n = entry.getName();
+
+            if (n) {
+                if (!name) {
+                    name = strdup(n);
+                } else if (strcmp(name, n)) {
+                    free(name);
+                    name = NULL;
+                    break;
+                }
+            }
+        }
+    }
+
+    // No one
+    return name;
 }
 
-size_t LogStatistics::sizesTotal(log_id_t log_id, uid_t uid, pid_t pid) {
-    if (log_id != log_id_all) {
-        return id(log_id).sizesTotal(uid, pid);
+static void format_line(android::String8 &output,
+        android::String8 &name, android::String8 &size, android::String8 &pruned) {
+    static const size_t pruned_len = 6;
+    static const size_t total_len = 70 + pruned_len;
+
+    ssize_t drop_len = std::max(pruned.length() + 1, pruned_len);
+    ssize_t size_len = std::max(size.length() + 1,
+                                total_len - name.length() - drop_len - 1);
+
+    if (pruned.length()) {
+        output.appendFormat("%s%*s%*s\n", name.string(),
+                                          (int)size_len, size.string(),
+                                          (int)drop_len, pruned.string());
+    } else {
+        output.appendFormat("%s%*s\n", name.string(),
+                                       (int)size_len, size.string());
     }
-    size_t sizes = 0;
-    log_id_for_each(i) {
-        sizes += id(i).sizesTotal(uid, pid);
-    }
-    return sizes;
 }
 
-size_t LogStatistics::elementsTotal(log_id_t log_id, uid_t uid, pid_t pid) {
-    if (log_id != log_id_all) {
-        return id(log_id).elementsTotal(uid, pid);
-    }
-    size_t elements = 0;
-    log_id_for_each(i) {
-        elements += id(i).elementsTotal(uid, pid);
-    }
-    return elements;
-}
-
-void LogStatistics::format(char **buf,
-                           uid_t uid, unsigned int logMask, log_time oldest) {
-    static const unsigned short spaces_current = 13;
+void LogStatistics::format(char **buf, uid_t uid, unsigned int logMask) {
     static const unsigned short spaces_total = 19;
 
     if (*buf) {
@@ -535,411 +210,323 @@
         *buf = NULL;
     }
 
-    android::String8 string("        span -> size/num");
-    size_t oldLength;
-    short spaces = 2;
+    // Report on total logging, current and for all time
 
-    log_id_for_each(i) {
-        if (!(logMask & (1 << i))) {
+    android::String8 output("size/num");
+    size_t oldLength;
+    short spaces = 1;
+
+    log_id_for_each(id) {
+        if (!(logMask & (1 << id))) {
             continue;
         }
-        oldLength = string.length();
+        oldLength = output.length();
         if (spaces < 0) {
             spaces = 0;
         }
-        string.appendFormat("%*s%s", spaces, "", android_log_id_to_name(i));
-        spaces += spaces_total + oldLength - string.length();
-
-        LidStatistics &l = id(i);
-        l.sort();
-
-        UidStatisticsCollection::iterator iu;
-        for (iu = l.begin(); iu != l.end(); ++iu) {
-            (*iu)->sort();
-        }
+        output.appendFormat("%*s%s", spaces, "", android_log_id_to_name(id));
+        spaces += spaces_total + oldLength - output.length();
     }
 
-    spaces = 1;
-    log_time t(CLOCK_MONOTONIC);
-    unsigned long long d;
-    if (mStatistics) {
-        d = t.nsec() - start.nsec();
-        string.appendFormat("\nTotal%4llu:%02llu:%02llu.%09llu",
-                  d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60,
-                  (d / NS_PER_SEC) % 60, d % NS_PER_SEC);
+    spaces = 4;
+    output.appendFormat("\nTotal");
 
-        log_id_for_each(i) {
-            if (!(logMask & (1 << i))) {
-                continue;
-            }
-            oldLength = string.length();
-            if (spaces < 0) {
-                spaces = 0;
-            }
-            string.appendFormat("%*s%zu/%zu", spaces, "",
-                                sizesTotal(i), elementsTotal(i));
-            spaces += spaces_total + oldLength - string.length();
+    log_id_for_each(id) {
+        if (!(logMask & (1 << id))) {
+            continue;
         }
-        spaces = 1;
+        oldLength = output.length();
+        if (spaces < 0) {
+            spaces = 0;
+        }
+        output.appendFormat("%*s%zu/%zu", spaces, "",
+                            sizesTotal(id), elementsTotal(id));
+        spaces += spaces_total + oldLength - output.length();
     }
 
-    d = t.nsec() - oldest.nsec();
-    string.appendFormat("\nNow%6llu:%02llu:%02llu.%09llu",
-                  d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60,
-                  (d / NS_PER_SEC) % 60, d % NS_PER_SEC);
+    spaces = 6;
+    output.appendFormat("\nNow");
 
-    log_id_for_each(i) {
-        if (!(logMask & (1 << i))) {
+    log_id_for_each(id) {
+        if (!(logMask & (1 << id))) {
             continue;
         }
 
-        size_t els = elements(i);
+        size_t els = elements(id);
         if (els) {
-            oldLength = string.length();
+            oldLength = output.length();
             if (spaces < 0) {
                 spaces = 0;
             }
-            string.appendFormat("%*s%zu/%zu", spaces, "", sizes(i), els);
-            spaces -= string.length() - oldLength;
+            output.appendFormat("%*s%zu/%zu", spaces, "", sizes(id), els);
+            spaces -= output.length() - oldLength;
         }
         spaces += spaces_total;
     }
 
-    // Construct list of worst spammers by Pid
-    static const unsigned char num_spammers = 10;
-    bool header = false;
+    // Report on Chattiest
 
-    log_id_for_each(i) {
-        if (!(logMask & (1 << i))) {
+    // Chattiest by application (UID)
+    static const size_t maximum_sorted_entries = 32;
+    log_id_for_each(id) {
+        if (!(logMask & (1 << id))) {
             continue;
         }
 
-        PidStatisticsCollection pids;
-        pids.clear();
-
-        LidStatistics &l = id(i);
-        UidStatisticsCollection::iterator iu;
-        for (iu = l.begin(); iu != l.end(); ++iu) {
-            UidStatistics &u = *(*iu);
-            PidStatisticsCollection::iterator ip;
-            for (ip = u.begin(); ip != u.end(); ++ip) {
-                PidStatistics *p = (*ip);
-                if (p->getPid() == p->gone) {
-                    break;
-                }
-
-                size_t mySizes = p->sizes();
-
-                PidStatisticsCollection::iterator q;
-                unsigned char num = 0;
-                for (q = pids.begin(); q != pids.end(); ++q) {
-                    if (mySizes > (*q)->sizes()) {
-                        pids.insert(q, p);
-                        break;
-                    }
-                    // do we need to traverse deeper in the list?
-                    if (++num > num_spammers) {
-                        break;
-                    }
-                }
-                if (q == pids.end()) {
-                   pids.push_back(p);
-                }
-            }
-        }
-
-        size_t threshold = sizes(i);
-        if (threshold < 65536) {
-            threshold = 65536;
-        }
-        threshold /= 100;
-
-        PidStatisticsCollection::iterator pt = pids.begin();
-
-        for(int line = 0;
-                (pt != pids.end()) && (line < num_spammers);
-                ++line, pt = pids.erase(pt)) {
-            PidStatistics *p = *pt;
-
-            size_t sizes = p->sizes();
-            if (sizes < threshold) {
-                break;
+        bool headerPrinted = false;
+        std::unique_ptr<const UidEntry *[]> sorted = sort(maximum_sorted_entries, id);
+        ssize_t index = -1;
+        while ((index = uidTable_t::next(index, sorted, maximum_sorted_entries)) >= 0) {
+            const UidEntry *entry = sorted[index];
+            uid_t u = entry->getKey();
+            if ((uid != AID_ROOT) && (u != uid)) {
+                continue;
             }
 
-            char *name = p->getName();
-            pid_t pid = p->getPid();
-            if (!name || !*name) {
-                name = pidToName(pid);
-                if (name) {
-                    if (*name) {
-                        p->setName(name);
-                    } else {
-                        free(name);
-                        name = NULL;
-                    }
-                }
-            }
-
-            if (!header) {
-                string.appendFormat("\n\nChattiest clients:\n"
-                                    "log id %-*s PID[?] name",
-                                    spaces_total, "size/total");
-                header = true;
-            }
-
-            size_t sizesTotal = p->sizesTotal();
-
-            android::String8 sz("");
-            sz.appendFormat((sizes != sizesTotal) ? "%zu/%zu" : "%zu",
-                            sizes, sizesTotal);
-
-            android::String8 pd("");
-            pd.appendFormat("%u%c", pid, p->pidGone() ? '?' : ' ');
-
-            string.appendFormat("\n%-7s%-*s %-7s%s",
-                                line ? "" : android_log_id_to_name(i),
-                                spaces_total, sz.string(), pd.string(),
-                                name ? name : "");
-        }
-
-        pids.clear();
-    }
-
-    if (dgramQlenStatistics) {
-        const unsigned short spaces_time = 6;
-        const unsigned long long max_seconds = 100000;
-        spaces = 0;
-        string.append("\n\nMinimum time between log events per max_dgram_qlen:\n");
-        for(unsigned short i = 0; dgramQlen(i); ++i) {
-            oldLength = string.length();
-            if (spaces < 0) {
-                spaces = 0;
-            }
-            string.appendFormat("%*s%u", spaces, "", dgramQlen(i));
-            spaces += spaces_time + oldLength - string.length();
-        }
-        string.append("\n");
-        spaces = 0;
-        unsigned short n;
-        for(unsigned short i = 0; (n = dgramQlen(i)); ++i) {
-            unsigned long long duration = minimum(i);
-            if (duration) {
-                duration /= n;
-                if (duration >= (NS_PER_SEC * max_seconds)) {
-                    duration = NS_PER_SEC * (max_seconds - 1);
-                }
-                oldLength = string.length();
-                if (spaces < 0) {
-                    spaces = 0;
-                }
-                string.appendFormat("%*s", spaces, "");
-                if (duration >= (NS_PER_SEC * 10)) {
-                    string.appendFormat("%llu",
-                        (duration + (NS_PER_SEC / 2))
-                            / NS_PER_SEC);
-                } else if (duration >= (NS_PER_SEC / (1000 / 10))) {
-                    string.appendFormat("%llum",
-                        (duration + (NS_PER_SEC / 2 / 1000))
-                            / (NS_PER_SEC / 1000));
-                } else if (duration >= (NS_PER_SEC / (1000000 / 10))) {
-                    string.appendFormat("%lluu",
-                        (duration + (NS_PER_SEC / 2 / 1000000))
-                            / (NS_PER_SEC / 1000000));
+            if (!headerPrinted) {
+                output.appendFormat("\n\n");
+                android::String8 name("");
+                if (uid == AID_ROOT) {
+                    name.appendFormat(
+                        "Chattiest UIDs in %s log buffer:",
+                        android_log_id_to_name(id));
                 } else {
-                    string.appendFormat("%llun", duration);
+                    name.appendFormat(
+                        "Logging for your UID in %s log buffer:",
+                        android_log_id_to_name(id));
                 }
-                spaces -= string.length() - oldLength;
+                android::String8 size("Size");
+                android::String8 pruned("Pruned");
+                if (!worstUidEnabledForLogid(id)) {
+                    pruned.setTo("");
+                }
+                format_line(output, name, size, pruned);
+
+                name.setTo("UID   PACKAGE");
+                size.setTo("BYTES");
+                pruned.setTo("LINES");
+                if (!worstUidEnabledForLogid(id)) {
+                    pruned.setTo("");
+                }
+                format_line(output, name, size, pruned);
+
+                headerPrinted = true;
             }
-            spaces += spaces_time;
+
+            android::String8 name("");
+            name.appendFormat("%u", u);
+            char *n = uidToName(u);
+            if (n) {
+                name.appendFormat("%*s%s", (int)std::max(6 - name.length(), (size_t)1), "", n);
+                free(n);
+            }
+
+            android::String8 size("");
+            size.appendFormat("%zu", entry->getSizes());
+
+            android::String8 pruned("");
+            size_t dropped = entry->getDropped();
+            if (dropped) {
+                pruned.appendFormat("%zu", dropped);
+            }
+
+            format_line(output, name, size, pruned);
         }
     }
 
-    log_id_for_each(i) {
-        if (!(logMask & (1 << i))) {
-            continue;
-        }
-
-        header = false;
-        bool first = true;
-
-        UidStatisticsCollection::iterator ut;
-        for(ut = id(i).begin(); ut != id(i).end(); ++ut) {
-            UidStatistics *up = *ut;
-            if ((uid != AID_ROOT) && (uid != up->getUid())) {
+    if (enable) {
+        // Pid table
+        bool headerPrinted = false;
+        std::unique_ptr<const PidEntry *[]> sorted = pidTable.sort(maximum_sorted_entries);
+        ssize_t index = -1;
+        while ((index = pidTable.next(index, sorted, maximum_sorted_entries)) >= 0) {
+            const PidEntry *entry = sorted[index];
+            uid_t u = entry->getUid();
+            if ((uid != AID_ROOT) && (u != uid)) {
                 continue;
             }
 
-            PidStatisticsCollection::iterator pt = up->begin();
-            if (pt == up->end()) {
-                continue;
+            if (!headerPrinted) {
+                output.appendFormat("\n\n");
+                android::String8 name("");
+                if (uid == AID_ROOT) {
+                    name.appendFormat("Chattiest PIDs:");
+                } else {
+                    name.appendFormat("Logging for this PID:");
+                }
+                android::String8 size("Size");
+                android::String8 pruned("Pruned");
+                format_line(output, name, size, pruned);
+
+                name.setTo("  PID/UID   COMMAND LINE");
+                size.setTo("BYTES");
+                pruned.setTo("LINES");
+                format_line(output, name, size, pruned);
+
+                headerPrinted = true;
             }
 
-            android::String8 intermediate;
-
-            if (!header) {
-                // header below tuned to match spaces_total and spaces_current
-                spaces = 0;
-                intermediate = string.format("%s: UID/PID Total size/num",
-                                             android_log_id_to_name(i));
-                string.appendFormat("\n\n%-31sNow          "
-                                         "UID/PID[?]  Total              Now",
-                                    intermediate.string());
-                intermediate.clear();
-                header = true;
+            android::String8 name("");
+            name.appendFormat("%5u/%u", entry->getKey(), u);
+            const char *n = entry->getName();
+            if (n) {
+                name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", n);
+            } else {
+                char *un = uidToName(u);
+                if (un) {
+                    name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", un);
+                    free(un);
+                }
             }
 
-            bool oneline = ++pt == up->end();
-            --pt;
+            android::String8 size("");
+            size.appendFormat("%zu", entry->getSizes());
 
-            if (!oneline) {
-                first = true;
-            } else if (!first && (spaces > 0)) {
-                string.appendFormat("%*s", spaces, "");
-            }
-            spaces = 0;
-
-            uid_t u = up->getUid();
-            PidStatistics *pp = *pt;
-            pid_t p = pp->getPid();
-
-            intermediate = string.format(oneline
-                                             ? ((p == PidStatistics::gone)
-                                                 ? "%d/?"
-                                                 : "%d/%d%c")
-                                             : "%d",
-                                         u, p, pp->pidGone() ? '?' : '\0');
-            string.appendFormat(first ? "\n%-12s" : "%-12s",
-                                intermediate.string());
-            intermediate.clear();
-
-            size_t elsTotal = up->elementsTotal();
-            oldLength = string.length();
-            string.appendFormat("%zu/%zu", up->sizesTotal(), elsTotal);
-            spaces += spaces_total + oldLength - string.length();
-
-            size_t els = up->elements();
-            if (els == elsTotal) {
-                if (spaces < 0) {
-                    spaces = 0;
-                }
-                string.appendFormat("%*s=", spaces, "");
-                spaces = -1;
-            } else if (els) {
-                oldLength = string.length();
-                if (spaces < 0) {
-                    spaces = 0;
-                }
-                string.appendFormat("%*s%zu/%zu", spaces, "", up->sizes(), els);
-                spaces -= string.length() - oldLength;
-            }
-            spaces += spaces_current;
-
-            first = !first;
-
-            if (oneline) {
-                continue;
+            android::String8 pruned("");
+            size_t dropped = entry->getDropped();
+            if (dropped) {
+                pruned.appendFormat("%zu", dropped);
             }
 
-            size_t gone_szs = 0;
-            size_t gone_els = 0;
-
-            for(; pt != up->end(); ++pt) {
-                pp = *pt;
-                p = pp->getPid();
-
-                // If a PID no longer has any current logs, and is not
-                // active anymore, skip & report totals for gone.
-                elsTotal = pp->elementsTotal();
-                size_t szsTotal = pp->sizesTotal();
-                if (p == pp->gone) {
-                    gone_szs += szsTotal;
-                    gone_els += elsTotal;
-                    continue;
-                }
-                els = pp->elements();
-                bool gone = pp->pidGone();
-                if (gone && (els == 0)) {
-                    // ToDo: garbage collection: move this statistical bucket
-                    //       from its current UID/PID to UID/? (races and
-                    //       wrap around are our achilles heel). Below is
-                    //       merely lipservice to catch PIDs that were still
-                    //       around when the stats were pruned to zero.
-                    gone_szs += szsTotal;
-                    gone_els += elsTotal;
-                    continue;
-                }
-
-                if (!first && (spaces > 0)) {
-                    string.appendFormat("%*s", spaces, "");
-                }
-                spaces = 0;
-
-                intermediate = string.format(gone ? "%d/%d?" : "%d/%d", u, p);
-                string.appendFormat(first ? "\n%-12s" : "%-12s",
-                                    intermediate.string());
-                intermediate.clear();
-
-                oldLength = string.length();
-                string.appendFormat("%zu/%zu", szsTotal, elsTotal);
-                spaces += spaces_total + oldLength - string.length();
-
-                if (els == elsTotal) {
-                    if (spaces < 0) {
-                        spaces = 0;
-                    }
-                    string.appendFormat("%*s=", spaces, "");
-                    spaces = -1;
-                } else if (els) {
-                    oldLength = string.length();
-                    if (spaces < 0) {
-                        spaces = 0;
-                    }
-                    string.appendFormat("%*s%zu/%zu", spaces, "",
-                                        pp->sizes(), els);
-                    spaces -= string.length() - oldLength;
-                }
-                spaces += spaces_current;
-
-                first = !first;
-            }
-
-            if (gone_els) {
-                if (!first && (spaces > 0)) {
-                    string.appendFormat("%*s", spaces, "");
-                }
-
-                intermediate = string.format("%d/?", u);
-                string.appendFormat(first ? "\n%-12s" : "%-12s",
-                                    intermediate.string());
-                intermediate.clear();
-
-                spaces = spaces_total + spaces_current;
-
-                oldLength = string.length();
-                string.appendFormat("%zu/%zu", gone_szs, gone_els);
-                spaces -= string.length() - oldLength;
-
-                first = !first;
-            }
+            format_line(output, name, size, pruned);
         }
     }
 
-    *buf = strdup(string.string());
+    if (enable) {
+        // Tid table
+        bool headerPrinted = false;
+        // sort() returns list of references, unique_ptr makes sure self-delete
+        std::unique_ptr<const TidEntry *[]> sorted = tidTable.sort(maximum_sorted_entries);
+        ssize_t index = -1;
+        while ((index = tidTable.next(index, sorted, maximum_sorted_entries)) >= 0) {
+            const TidEntry *entry = sorted[index];
+            uid_t u = entry->getUid();
+            if ((uid != AID_ROOT) && (u != uid)) {
+                continue;
+            }
+
+            if (!headerPrinted) { // Only print header if we have table to print
+                output.appendFormat("\n\n");
+                android::String8 name("Chattiest TIDs:");
+                android::String8 size("Size");
+                android::String8 pruned("Pruned");
+                format_line(output, name, size, pruned);
+
+                name.setTo("  TID/UID   COMM");
+                size.setTo("BYTES");
+                pruned.setTo("LINES");
+                format_line(output, name, size, pruned);
+
+                headerPrinted = true;
+            }
+
+            android::String8 name("");
+            name.appendFormat("%5u/%u", entry->getKey(), u);
+            const char *n = entry->getName();
+            if (n) {
+                name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", n);
+            } else {
+                // if we do not have a PID name, lets punt to try UID name?
+                char *un = uidToName(u);
+                if (un) {
+                    name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", un);
+                    free(un);
+                }
+                // We tried, better to not have a name at all, we still
+                // have TID/UID by number to report in any case.
+            }
+
+            android::String8 size("");
+            size.appendFormat("%zu", entry->getSizes());
+
+            android::String8 pruned("");
+            size_t dropped = entry->getDropped();
+            if (dropped) {
+                pruned.appendFormat("%zu", dropped);
+            }
+
+            format_line(output, name, size, pruned);
+        }
+    }
+
+    if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
+        // Tag table
+        bool headerPrinted = false;
+        std::unique_ptr<const TagEntry *[]> sorted = tagTable.sort(maximum_sorted_entries);
+        ssize_t index = -1;
+        while ((index = tagTable.next(index, sorted, maximum_sorted_entries)) >= 0) {
+            const TagEntry *entry = sorted[index];
+            uid_t u = entry->getUid();
+            if ((uid != AID_ROOT) && (u != uid)) {
+                continue;
+            }
+
+            android::String8 pruned("");
+
+            if (!headerPrinted) {
+                output.appendFormat("\n\n");
+                android::String8 name("Chattiest events log buffer TAGs:");
+                android::String8 size("Size");
+                format_line(output, name, size, pruned);
+
+                name.setTo("    TAG/UID   TAGNAME");
+                size.setTo("BYTES");
+                format_line(output, name, size, pruned);
+
+                headerPrinted = true;
+            }
+
+            android::String8 name("");
+            if (u == (uid_t)-1) {
+                name.appendFormat("%7u", entry->getKey());
+            } else {
+                name.appendFormat("%7u/%u", entry->getKey(), u);
+            }
+            const char *n = entry->getName();
+            if (n) {
+                name.appendFormat("%*s%s", (int)std::max(14 - name.length(), (size_t)1), "", n);
+            }
+
+            android::String8 size("");
+            size.appendFormat("%zu", entry->getSizes());
+
+            format_line(output, name, size, pruned);
+        }
+    }
+
+    *buf = strdup(output.string());
+}
+
+namespace android {
+
+uid_t pidToUid(pid_t pid) {
+    char buffer[512];
+    snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid);
+    FILE *fp = fopen(buffer, "r");
+    if (fp) {
+        while (fgets(buffer, sizeof(buffer), fp)) {
+            int uid;
+            if (sscanf(buffer, "Uid: %d", &uid) == 1) {
+                fclose(fp);
+                return uid;
+            }
+        }
+        fclose(fp);
+    }
+    return AID_LOGD; // associate this with the logger
+}
+
 }
 
 uid_t LogStatistics::pidToUid(pid_t pid) {
-    log_id_for_each(i) {
-        LidStatistics &l = id(i);
-        UidStatisticsCollection::iterator iu;
-        for (iu = l.begin(); iu != l.end(); ++iu) {
-            UidStatistics &u = *(*iu);
-            PidStatisticsCollection::iterator ip;
-            for (ip = u.begin(); ip != u.end(); ++ip) {
-                if ((*ip)->getPid() == pid) {
-                    return u.getUid();
-                }
-            }
-        }
+    return pidTable.add(pid)->second.getUid();
+}
+
+// caller must free character string
+char *LogStatistics::pidToName(pid_t pid) {
+    const char *name = pidTable.add(pid)->second.getName();
+    if (!name) {
+        return NULL;
     }
-    return getuid(); // associate this with the logger
+    return strdup(name);
 }
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index f6c4329..760d6b2 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -17,183 +17,327 @@
 #ifndef _LOGD_LOG_STATISTICS_H__
 #define _LOGD_LOG_STATISTICS_H__
 
+#include <memory>
+#include <stdlib.h>
 #include <sys/types.h>
 
+#include <unordered_map>
+
 #include <log/log.h>
-#include <log/log_read.h>
-#include <utils/List.h>
+
+#include "LogBufferElement.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))
 
-class PidStatistics {
-    const pid_t pid;
+template <typename TKey, typename TEntry>
+class LogHashtable {
 
-    // Total
-    size_t mSizesTotal;
-    size_t mElementsTotal;
-    // Current
-    size_t mSizes;
-    size_t mElements;
-
-    char *name;
-    bool mGone;
+    std::unordered_map<TKey, TEntry> map;
 
 public:
-    static const pid_t gone = (pid_t) -1;
 
-    PidStatistics(pid_t pid, char *name = NULL);
-    PidStatistics(const PidStatistics &copy);
-    ~PidStatistics();
+    typedef typename std::unordered_map<TKey, TEntry>::iterator iterator;
 
-    pid_t getPid() const { return pid; }
-    bool pidGone();
-    char *getName() const { return name; }
-    void setName(char *name);
+    std::unique_ptr<const TEntry *[]> sort(size_t n) {
+        if (!n) {
+            std::unique_ptr<const TEntry *[]> sorted(NULL);
+            return sorted;
+        }
 
-    void add(unsigned short size);
-    bool subtract(unsigned short size); // returns true if stats and PID gone
-    void addTotal(size_t size, size_t element);
+        const TEntry **retval = new const TEntry* [n];
+        memset(retval, 0, sizeof(*retval) * n);
 
-    size_t sizes() const { return mSizes; }
-    size_t elements() const { return mElements; }
+        for(iterator it = map.begin(); it != map.end(); ++it) {
+            const TEntry &entry = it->second;
+            size_t s = entry.getSizes();
+            ssize_t i = n - 1;
+            while ((!retval[i] || (s > retval[i]->getSizes())) && (--i >= 0))
+                ;
+            if (++i < (ssize_t)n) {
+                size_t b = n - i - 1;
+                if (b) {
+                    memmove(&retval[i+1], &retval[i], b * sizeof(retval[0]));
+                }
+                retval[i] = &entry;
+            }
+        }
+        std::unique_ptr<const TEntry *[]> sorted(retval);
+        return sorted;
+    }
 
-    size_t sizesTotal() const { return mSizesTotal; }
-    size_t elementsTotal() const { return mElementsTotal; }
+    // Iteration handler for the sort method output
+    static ssize_t next(ssize_t index, std::unique_ptr<const TEntry *[]> &sorted, size_t n) {
+        ++index;
+        if (!sorted.get() || (index < 0) || (n <= (size_t)index) || !sorted[index]
+         || (sorted[index]->getSizes() <= (sorted[0]->getSizes() / 100))) {
+            return -1;
+        }
+        return index;
+    }
 
-    // helper
-    static char *pidToName(pid_t pid);
+    inline iterator add(TKey key, LogBufferElement *e) {
+        iterator it = map.find(key);
+        if (it == map.end()) {
+            it = map.insert(std::make_pair(key, TEntry(e))).first;
+        } else {
+            it->second.add(e);
+        }
+        return it;
+    }
+
+    inline iterator add(TKey key) {
+        iterator it = map.find(key);
+        if (it == map.end()) {
+            it = map.insert(std::make_pair(key, TEntry(key))).first;
+        } else {
+            it->second.add(key);
+        }
+        return it;
+    }
+
+    void subtract(TKey key, LogBufferElement *e) {
+        iterator it = map.find(key);
+        if ((it != map.end()) && it->second.subtract(e)) {
+            map.erase(it);
+        }
+    }
+
+    inline void drop(TKey key, LogBufferElement *e) {
+        iterator it = map.find(key);
+        if (it != map.end()) {
+            it->second.drop(e);
+        }
+    }
+
+    inline iterator begin() { return map.begin(); }
+    inline iterator end() { return map.end(); }
+
 };
 
-typedef android::List<PidStatistics *> PidStatisticsCollection;
+struct EntryBase {
+    size_t size;
 
-class UidStatistics {
+    EntryBase():size(0) { }
+    EntryBase(LogBufferElement *e):size(e->getMsgLen()) { }
+
+    size_t getSizes() const { return size; }
+
+    inline void add(LogBufferElement *e) { size += e->getMsgLen(); }
+    inline bool subtract(LogBufferElement *e) { size -= e->getMsgLen(); return !size; }
+};
+
+struct EntryBaseDropped : public EntryBase {
+    size_t dropped;
+
+    EntryBaseDropped():dropped(0) { }
+    EntryBaseDropped(LogBufferElement *e):EntryBase(e),dropped(e->getDropped()){ }
+
+    size_t getDropped() const { return dropped; }
+
+    inline void add(LogBufferElement *e) {
+        dropped += e->getDropped();
+        EntryBase::add(e);
+    }
+    inline bool subtract(LogBufferElement *e) {
+        dropped -= e->getDropped();
+        return EntryBase::subtract(e) && !dropped;
+    }
+    inline void drop(LogBufferElement *e) {
+        dropped += 1;
+        EntryBase::subtract(e);
+    }
+};
+
+struct UidEntry : public EntryBaseDropped {
     const uid_t uid;
 
-    PidStatisticsCollection Pids;
+    UidEntry(LogBufferElement *e):EntryBaseDropped(e),uid(e->getUid()) { }
 
-    void insert(PidStatisticsCollection::iterator i, PidStatistics *p)
-        { Pids.insert(i, p); }
-    void push_back(PidStatistics *p) { Pids.push_back(p); }
-
-    size_t mSizes;
-    size_t mElements;
-
-public:
-    UidStatistics(uid_t uid);
-    ~UidStatistics();
-
-    PidStatisticsCollection::iterator begin() { return Pids.begin(); }
-    PidStatisticsCollection::iterator end() { return Pids.end(); }
-    PidStatisticsCollection::iterator erase(PidStatisticsCollection::iterator i)
-        { return Pids.erase(i); }
-
-    uid_t getUid() { return uid; }
-
-    void add(unsigned short size, pid_t pid);
-    void subtract(unsigned short size, pid_t pid);
-    void sort();
-
-    static const pid_t pid_all = (pid_t) -1;
-
-    // fast track current value
-    size_t sizes() const { return mSizes; };
-    size_t elements() const { return mElements; };
-
-    // statistical track
-    size_t sizes(pid_t pid);
-    size_t elements(pid_t pid);
-
-    size_t sizesTotal(pid_t pid = pid_all);
-    size_t elementsTotal(pid_t pid = pid_all);
-
-    // helper
-    static char *pidToName(pid_t pid) { return PidStatistics::pidToName(pid); }
+    inline const uid_t&getKey() const { return uid; }
 };
 
-typedef android::List<UidStatistics *> UidStatisticsCollection;
+namespace android {
+uid_t pidToUid(pid_t pid);
+}
 
-class LidStatistics {
-    UidStatisticsCollection Uids;
+struct PidEntry : public EntryBaseDropped {
+    const pid_t pid;
+    uid_t uid;
+    char *name;
 
-public:
-    LidStatistics();
-    ~LidStatistics();
+    PidEntry(pid_t p):
+        EntryBaseDropped(),
+        pid(p),
+        uid(android::pidToUid(p)),
+        name(android::pidToName(pid)) { }
+    PidEntry(LogBufferElement *e):
+        EntryBaseDropped(e),
+        pid(e->getPid()),
+        uid(e->getUid()),
+        name(android::pidToName(e->getPid())) { }
+    PidEntry(const PidEntry &c):
+        EntryBaseDropped(c),
+        pid(c.pid),
+        uid(c.uid),
+        name(c.name ? strdup(c.name) : NULL) { }
+    ~PidEntry() { free(name); }
 
-    UidStatisticsCollection::iterator begin() { return Uids.begin(); }
-    UidStatisticsCollection::iterator end() { return Uids.end(); }
+    const pid_t&getKey() const { return pid; }
+    const uid_t&getUid() const { return uid; }
+    const char*getName() const { return name; }
 
-    void add(unsigned short size, uid_t uid, pid_t pid);
-    void subtract(unsigned short size, uid_t uid, pid_t pid);
-    void sort();
+    inline void add(pid_t p) {
+        if (name && !strncmp(name, "zygote", 6)) {
+            free(name);
+            name = NULL;
+        }
+        if (!name) {
+            char *n = android::pidToName(p);
+            if (n) {
+                name = n;
+            }
+        }
+    }
 
-    static const pid_t pid_all = (pid_t) -1;
-    static const uid_t uid_all = (uid_t) -1;
+    inline void add(LogBufferElement *e) {
+        uid_t u = e->getUid();
+        if (getUid() != u) {
+            uid = u;
+            free(name);
+            name = android::pidToName(e->getPid());
+        } else {
+            add(e->getPid());
+        }
+        EntryBaseDropped::add(e);
+    }
+};
 
-    size_t sizes(uid_t uid = uid_all, pid_t pid = pid_all);
-    size_t elements(uid_t uid = uid_all, pid_t pid = pid_all);
+struct TidEntry : public EntryBaseDropped {
+    const pid_t tid;
+    uid_t uid;
+    char *name;
 
-    size_t sizesTotal(uid_t uid = uid_all, pid_t pid = pid_all);
-    size_t elementsTotal(uid_t uid = uid_all, pid_t pid = pid_all);
+    TidEntry(pid_t t):
+        EntryBaseDropped(),
+        tid(t),
+        uid(android::pidToUid(t)),
+        name(android::tidToName(tid)) { }
+    TidEntry(LogBufferElement *e):
+        EntryBaseDropped(e),
+        tid(e->getTid()),
+        uid(e->getUid()),
+        name(android::tidToName(e->getTid())) { }
+    TidEntry(const TidEntry &c):
+        EntryBaseDropped(c),
+        tid(c.tid),
+        uid(c.uid),
+        name(c.name ? strdup(c.name) : NULL) { }
+    ~TidEntry() { free(name); }
+
+    const pid_t&getKey() const { return tid; }
+    const uid_t&getUid() const { return uid; }
+    const char*getName() const { return name; }
+
+    inline void add(pid_t t) {
+        if (name && !strncmp(name, "zygote", 6)) {
+            free(name);
+            name = NULL;
+        }
+        if (!name) {
+            char *n = android::tidToName(t);
+            if (n) {
+                name = n;
+            }
+        }
+    }
+
+    inline void add(LogBufferElement *e) {
+        uid_t u = e->getUid();
+        if (getUid() != u) {
+            uid = u;
+            free(name);
+            name = android::tidToName(e->getTid());
+        } else {
+            add(e->getTid());
+        }
+        EntryBaseDropped::add(e);
+    }
+};
+
+struct TagEntry : public EntryBase {
+    const uint32_t tag;
+    uid_t uid;
+
+    TagEntry(LogBufferElement *e):
+        EntryBase(e),
+        tag(e->getTag()),
+        uid(e->getUid()) { }
+
+    const uint32_t&getKey() const { return tag; }
+    const uid_t&getUid() const { return uid; }
+    const char*getName() const { return android::tagToName(tag); }
+
+    inline void add(LogBufferElement *e) {
+        uid_t u = e->getUid();
+        if (uid != u) {
+            uid = -1;
+        }
+        EntryBase::add(e);
+    }
 };
 
 // Log Statistics
 class LogStatistics {
-    LidStatistics LogIds[LOG_ID_MAX];
-
     size_t mSizes[LOG_ID_MAX];
     size_t mElements[LOG_ID_MAX];
+    size_t mSizesTotal[LOG_ID_MAX];
+    size_t mElementsTotal[LOG_ID_MAX];
+    bool enable;
 
-    bool mStatistics;
-    bool dgramQlenStatistics;
+    // uid to size list
+    typedef LogHashtable<uid_t, UidEntry> uidTable_t;
+    uidTable_t uidTable[LOG_ID_MAX];
 
-    static const unsigned short mBuckets[14];
-    log_time mMinimum[sizeof(mBuckets) / sizeof(mBuckets[0])];
+    // pid to uid list
+    typedef LogHashtable<pid_t, PidEntry> pidTable_t;
+    pidTable_t pidTable;
+
+    // tid to uid list
+    typedef LogHashtable<pid_t, TidEntry> tidTable_t;
+    tidTable_t tidTable;
+
+    // tag list
+    typedef LogHashtable<uint32_t, TagEntry> tagTable_t;
+    tagTable_t tagTable;
 
 public:
-    const log_time start;
-
     LogStatistics();
 
-    LidStatistics &id(log_id_t log_id) { return LogIds[log_id]; }
+    void enableStatistics() { enable = true; }
 
-    void enableDgramQlenStatistics() { dgramQlenStatistics = true; }
-    void enableStatistics() { mStatistics = true; }
-    static unsigned short dgramQlen(unsigned short bucket);
-    unsigned long long minimum(unsigned short bucket);
-    void recordDiff(log_time diff, unsigned short bucket);
+    void add(LogBufferElement *entry);
+    void subtract(LogBufferElement *entry);
+    // entry->setDropped(1) must follow this call
+    void drop(LogBufferElement *entry);
+    // Correct for merging two entries referencing dropped content
+    void erase(LogBufferElement *e) { --mElements[e->getLogId()]; }
 
-    void add(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid);
-    void subtract(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid);
-    void sort();
+    std::unique_ptr<const UidEntry *[]> sort(size_t n, log_id i) { return uidTable[i].sort(n); }
 
     // fast track current value by id only
     size_t sizes(log_id_t id) const { return mSizes[id]; }
     size_t elements(log_id_t id) const { return mElements[id]; }
-
-    // statistical track
-    static const log_id_t log_id_all = (log_id_t) -1;
-    static const uid_t uid_all = (uid_t) -1;
-    static const pid_t pid_all = (pid_t) -1;
-
-    size_t sizes(log_id_t id, uid_t uid, pid_t pid = pid_all);
-    size_t elements(log_id_t id, uid_t uid, pid_t pid = pid_all);
-    size_t sizes() { return sizes(log_id_all, uid_all); }
-    size_t elements() { return elements(log_id_all, uid_all); }
-
-    size_t sizesTotal(log_id_t id = log_id_all,
-                      uid_t uid = uid_all,
-                      pid_t pid = pid_all);
-    size_t elementsTotal(log_id_t id = log_id_all,
-                         uid_t uid = uid_all,
-                         pid_t pid = pid_all);
+    size_t sizesTotal(log_id_t id) const { return mSizesTotal[id]; }
+    size_t elementsTotal(log_id_t id) const { return mElementsTotal[id]; }
 
     // *strp = malloc, balance with free
-    void format(char **strp, uid_t uid, unsigned int logMask, log_time oldest);
+    void format(char **strp, uid_t uid, unsigned int logMask);
 
-    // helper
-    static char *pidToName(pid_t pid) { return PidStatistics::pidToName(pid); }
+    // helper (must be locked directly or implicitly by mLogElementsLock)
+    char *pidToName(pid_t pid);
     uid_t pidToUid(pid_t pid);
+    char *uidToName(uid_t uid);
 };
 
 #endif // _LOGD_LOG_STATISTICS_H__
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index ea4e8c8..68a0680 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -23,29 +23,27 @@
 
 pthread_mutex_t LogTimeEntry::timesLock = PTHREAD_MUTEX_INITIALIZER;
 
-const struct timespec LogTimeEntry::EPOCH = { 0, 1 };
-
 LogTimeEntry::LogTimeEntry(LogReader &reader, SocketClient *client,
                            bool nonBlock, unsigned long tail,
                            unsigned int logMask, pid_t pid,
-                           log_time start)
-        : mRefCount(1)
-        , mRelease(false)
-        , mError(false)
-        , threadRunning(false)
-        , mReader(reader)
-        , mLogMask(logMask)
-        , mPid(pid)
-        , skipAhead(0)
-        , mCount(0)
-        , mTail(tail)
-        , mIndex(0)
-        , mClient(client)
-        , mStart(start)
-        , mNonBlock(nonBlock)
-        , mEnd(CLOCK_MONOTONIC)
-{
-        pthread_cond_init(&threadTriggeredCondition, NULL);
+                           uint64_t start) :
+        mRefCount(1),
+        mRelease(false),
+        mError(false),
+        threadRunning(false),
+        leadingDropped(false),
+        mReader(reader),
+        mLogMask(logMask),
+        mPid(pid),
+        mCount(0),
+        mTail(tail),
+        mIndex(0),
+        mClient(client),
+        mStart(start),
+        mNonBlock(nonBlock),
+        mEnd(LogBufferElement::getCurrentSequence()) {
+    pthread_cond_init(&threadTriggeredCondition, NULL);
+    cleanSkip_Locked();
 }
 
 void LogTimeEntry::startReader_Locked(void) {
@@ -126,15 +124,18 @@
 
     bool privileged = FlushCommand::hasReadLogs(client);
 
+    me->leadingDropped = true;
+
     lock();
 
     while (me->threadRunning && !me->isError_Locked()) {
-        log_time start = me->mStart;
+        uint64_t start = me->mStart;
 
         unlock();
 
         if (me->mTail) {
             logbuf.flushTo(client, start, privileged, FilterFirstPass, me);
+            me->leadingDropped = true;
         }
         start = logbuf.flushTo(client, start, privileged, FilterSecondPass, me);
 
@@ -148,6 +149,8 @@
             break;
         }
 
+        me->cleanSkip_Locked();
+
         pthread_cond_wait(&me->threadTriggeredCondition, &timesLock);
     }
 
@@ -159,17 +162,25 @@
 }
 
 // A first pass to count the number of elements
-bool LogTimeEntry::FilterFirstPass(const LogBufferElement *element, void *obj) {
+int LogTimeEntry::FilterFirstPass(const LogBufferElement *element, void *obj) {
     LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
 
     LogTimeEntry::lock();
 
+    if (me->leadingDropped) {
+        if (element->getDropped()) {
+            LogTimeEntry::unlock();
+            return false;
+        }
+        me->leadingDropped = false;
+    }
+
     if (me->mCount == 0) {
-        me->mStart = element->getMonotonicTime();
+        me->mStart = element->getSequence();
     }
 
     if ((!me->mPid || (me->mPid == element->getPid()))
-            && (me->mLogMask & (1 << element->getLogId()))) {
+            && (me->isWatching(element->getLogId()))) {
         ++me->mCount;
     }
 
@@ -179,24 +190,31 @@
 }
 
 // A second pass to send the selected elements
-bool LogTimeEntry::FilterSecondPass(const LogBufferElement *element, void *obj) {
+int LogTimeEntry::FilterSecondPass(const LogBufferElement *element, void *obj) {
     LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
 
     LogTimeEntry::lock();
 
-    if (me->skipAhead) {
-        me->skipAhead--;
+    me->mStart = element->getSequence();
+
+    if (me->skipAhead[element->getLogId()]) {
+        me->skipAhead[element->getLogId()]--;
         goto skip;
     }
 
-    me->mStart = element->getMonotonicTime();
+    if (me->leadingDropped) {
+        if (element->getDropped()) {
+            goto skip;
+        }
+        me->leadingDropped = false;
+    }
 
     // Truncate to close race between first and second pass
     if (me->mNonBlock && me->mTail && (me->mIndex >= me->mCount)) {
-        goto skip;
+        goto stop;
     }
 
-    if ((me->mLogMask & (1 << element->getLogId())) == 0) {
+    if (!me->isWatching(element->getLogId())) {
         goto skip;
     }
 
@@ -205,7 +223,7 @@
     }
 
     if (me->isError_Locked()) {
-        goto skip;
+        goto stop;
     }
 
     if (!me->mTail) {
@@ -223,7 +241,7 @@
     }
 
 ok:
-    if (!me->skipAhead) {
+    if (!me->skipAhead[element->getLogId()]) {
         LogTimeEntry::unlock();
         return true;
     }
@@ -232,4 +250,14 @@
 skip:
     LogTimeEntry::unlock();
     return false;
+
+stop:
+    LogTimeEntry::unlock();
+    return -1;
+}
+
+void LogTimeEntry::cleanSkip_Locked(void) {
+    for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t) (i + 1)) {
+        skipAhead[i] = 0;
+    }
 }
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index 0bfa7a2..783bce6 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -22,6 +22,7 @@
 #include <sys/types.h>
 #include <sysutils/SocketClient.h>
 #include <utils/List.h>
+#include <log/log.h>
 
 class LogReader;
 
@@ -31,6 +32,7 @@
     bool mRelease;
     bool mError;
     bool threadRunning;
+    bool leadingDropped;
     pthread_cond_t threadTriggeredCondition;
     pthread_t mThread;
     LogReader &mReader;
@@ -38,7 +40,7 @@
     static void threadStop(void *me);
     const unsigned int mLogMask;
     const pid_t mPid;
-    unsigned int skipAhead;
+    unsigned int skipAhead[LOG_ID_MAX];
     unsigned long mCount;
     unsigned long mTail;
     unsigned long mIndex;
@@ -46,13 +48,12 @@
 public:
     LogTimeEntry(LogReader &reader, SocketClient *client, bool nonBlock,
                  unsigned long tail, unsigned int logMask, pid_t pid,
-                 log_time start);
+                 uint64_t start);
 
     SocketClient *mClient;
-    static const struct timespec EPOCH;
-    log_time mStart;
+    uint64_t mStart;
     const bool mNonBlock;
-    const log_time mEnd; // only relevant if mNonBlock
+    const uint64_t mEnd; // only relevant if mNonBlock
 
     // Protect List manipulations
     static void lock(void) { pthread_mutex_lock(&timesLock); }
@@ -67,7 +68,8 @@
         pthread_cond_signal(&threadTriggeredCondition);
     }
 
-    void triggerSkip_Locked(unsigned int skip) { skipAhead = skip; }
+    void triggerSkip_Locked(log_id_t id, unsigned int skip) { skipAhead[id] = skip; }
+    void cleanSkip_Locked(void);
 
     // Called after LogTimeEntry removed from list, lock implicitly held
     void release_Locked(void) {
@@ -99,10 +101,10 @@
         // No one else is holding a reference to this
         delete this;
     }
-
+    bool isWatching(log_id_t id) { return (mLogMask & (1<<id)) != 0; }
     // flushTo filter callbacks
-    static bool FilterFirstPass(const LogBufferElement *element, void *me);
-    static bool FilterSecondPass(const LogBufferElement *element, void *me);
+    static int FilterFirstPass(const LogBufferElement *element, void *me);
+    static int FilterSecondPass(const LogBufferElement *element, void *me);
 };
 
 typedef android::List<LogTimeEntry *> LastLogTimes;
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
index e87b604..277b3ca 100644
--- a/logd/LogWhiteBlackList.cpp
+++ b/logd/LogWhiteBlackList.cpp
@@ -22,10 +22,8 @@
 
 // White and Black list
 
-Prune::Prune(uid_t uid, pid_t pid)
-        : mUid(uid)
-        , mPid(pid)
-{ }
+Prune::Prune(uid_t uid, pid_t pid) : mUid(uid), mPid(pid) {
+}
 
 int Prune::cmp(uid_t uid, pid_t pid) const {
     if ((mUid == uid_all) || (mUid == uid)) {
@@ -39,15 +37,19 @@
 
 void Prune::format(char **strp) {
     if (mUid != uid_all) {
-        asprintf(strp, (mPid != pid_all) ? "%u/%u" : "%u", mUid, mPid);
-    } else {
-        // NB: mPid == pid_all can not happen if mUid == uid_all
-        asprintf(strp, (mPid != pid_all) ? "/%u" : "/", mPid);
+        if (mPid != pid_all) {
+            asprintf(strp, "%u/%u", mUid, mPid);
+        } else {
+            asprintf(strp, "%u", mUid);
+        }
+    } else if (mPid != pid_all) {
+        asprintf(strp, "/%u", mPid);
+    } else { // NB: mPid == pid_all can not happen if mUid == uid_all
+        asprintf(strp, "/");
     }
 }
 
-PruneList::PruneList()
-        : mWorstUidEnabled(false) {
+PruneList::PruneList() : mWorstUidEnabled(true) {
     mNaughty.clear();
     mNice.clear();
 }
@@ -65,7 +67,7 @@
 }
 
 int PruneList::init(char *str) {
-    mWorstUidEnabled = false;
+    mWorstUidEnabled = true;
     PruneCollection::iterator it;
     for (it = mNice.begin(); it != mNice.end();) {
         delete (*it);
diff --git a/logd/LogWhiteBlackList.h b/logd/LogWhiteBlackList.h
index 769d651..5f60801 100644
--- a/logd/LogWhiteBlackList.h
+++ b/logd/LogWhiteBlackList.h
@@ -61,7 +61,9 @@
     int init(char *str);
 
     bool naughty(LogBufferElement *element);
+    bool naughty(void) { return !mNaughty.empty(); }
     bool nice(LogBufferElement *element);
+    bool nice(void) { return !mNice.empty(); }
     bool worstUidEnabled() const { return mWorstUidEnabled; }
 
     // *strp is malloc'd, use free to release
diff --git a/logd/README.property b/logd/README.property
index b7fcece..a472efd 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -4,15 +4,14 @@
 logd.auditd                 bool  true   Enable selinux audit daemon
 logd.auditd.dmesg           bool  true   selinux audit messages duplicated and
                                          sent on to dmesg log
+logd.klogd                  bool depends Enable klogd daemon
 logd.statistics             bool depends Enable logcat -S statistics.
-ro.config.low_ram           bool  false  if true, logd.statistics default false
-ro.build.type               string       if user, logd.statistics default false
-logd.statistics.dgram_qlen  bool  false  Record dgram_qlen statistics. This
-                                         represents a performance impact and
-                                         is used to determine the platform's
-                                         minimum domain socket network FIFO
-                                         size (see source for details) based
-                                         on typical load (logcat -S to view)
+ro.config.low_ram           bool  false  if true, logd.statistics & logd.klogd
+                                         default false
+ro.build.type               string       if user, logd.statistics & logd.klogd
+                                         default false
+persist.logd.logpersistd    string       Enable logpersist daemon, "logcatd"
+                                         turns on logcat -f in logd context
 persist.logd.size          number 256K   default size of the buffer for all
                                          log ids at initial startup, at runtime
                                          use: logcat -b all -G <value>
diff --git a/logd/event.logtags b/logd/event.logtags
index a63f034..db8c19b 100644
--- a/logd/event.logtags
+++ b/logd/event.logtags
@@ -34,3 +34,4 @@
 # TODO: generate ".java" and ".h" files with integer constants from this file.
 
 1003  auditd (avc|3)
+1004  logd (dropped|3)
diff --git a/logd/logpersist b/logd/logpersist
new file mode 100755
index 0000000..215e1e2
--- /dev/null
+++ b/logd/logpersist
@@ -0,0 +1,36 @@
+#! /system/bin/sh
+# logpersist cat start and stop handlers
+data=/data/misc/logd
+property=persist.logd.logpersistd
+service=logcatd
+progname="${0##*/}"
+if [ X"${1}" = "-h" -o X"${1}" = X"--help" ]; then
+  echo "${progname%.*}.cat            - dump current ${service%d} logs"
+  echo "${progname%.*}.start          - start ${service} service"
+  echo "${progname%.*}.stop [--clear] - stop ${service} service"
+  exit 0
+fi
+case ${progname} in
+*.cat)
+  su 1036 ls "${data}" |
+  tr -d '\r' |
+  sort -ru |
+  sed "s#^#${data}/#" |
+  su 1036 xargs cat
+  ;;
+*.start)
+  su 0 setprop ${property} ${service}
+  getprop ${property}
+  sleep 1
+  ps -t | grep "${data##*/}.*${service%d}"
+  ;;
+*.stop)
+  su 0 stop ${service}
+  su 0 setprop ${property} ""
+  [ X"${1}" != X"-c" -a X"${1}" != X"--clear" ] ||
+  ( sleep 1 ; su 1036,9998 rm -rf "${data}" )
+  ;;
+*)
+  echo "Unexpected command ${0##*/} ${@}" >&2
+  exit 1
+esac
diff --git a/logd/main.cpp b/logd/main.cpp
index 54da7e3..a3241d0 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -17,23 +17,42 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <poll.h>
 #include <sched.h>
+#include <semaphore.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/capability.h>
+#include <sys/klog.h>
 #include <sys/prctl.h>
+#include <sys/resource.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <syslog.h>
 #include <unistd.h>
 
-#include <cutils/properties.h>
+#include <memory>
 
-#include "private/android_filesystem_config.h"
+#include <cutils/properties.h>
+#include <cutils/sched_policy.h>
+#include <cutils/sockets.h>
+#include <log/event_tag_map.h>
+#include <private/android_filesystem_config.h>
+#include <utils/threads.h>
+
 #include "CommandListener.h"
 #include "LogBuffer.h"
 #include "LogListener.h"
 #include "LogAudit.h"
+#include "LogKlog.h"
+
+#define KMSG_PRIORITY(PRI)                            \
+    '<',                                              \
+    '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) / 10, \
+    '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) % 10, \
+    '>'
 
 //
 //  The service is designed to be run by init, it does not respond well
@@ -68,14 +87,26 @@
     struct sched_param param;
     memset(&param, 0, sizeof(param));
 
+    if (set_sched_policy(0, SP_BACKGROUND) < 0) {
+        return -1;
+    }
+
     if (sched_setscheduler((pid_t) 0, SCHED_BATCH, &param) < 0) {
         return -1;
     }
 
+    if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
+        return -1;
+    }
+
     if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
         return -1;
     }
 
+    if (setgroups(0, NULL) == -1) {
+        return -1;
+    }
+
     if (setgid(AID_LOGD) != 0) {
         return -1;
     }
@@ -121,17 +152,243 @@
     return def;
 }
 
-// Foreground waits for exit of the three main persistent threads that
-// are started here.  The three threads are created to manage UNIX
-// domain client sockets for writing, reading and controlling the user
-// space logger.  Additional transitory per-client threads are created
-// for each reader once they register.
-int main() {
-    bool auditd = property_get_bool("logd.auditd", true);
+// Remove the static, and use this variable
+// globally for debugging if necessary. eg:
+//   write(fdDmesg, "I am here\n", 10);
+static int fdDmesg = -1;
 
-    int fdDmesg = -1;
-    if (auditd && property_get_bool("logd.auditd.dmesg", true)) {
-        fdDmesg = open("/dev/kmsg", O_WRONLY);
+static sem_t uidName;
+static uid_t uid;
+static char *name;
+
+static sem_t reinit;
+static bool reinit_running = false;
+static LogBuffer *logBuf = NULL;
+
+static void *reinit_thread_start(void * /*obj*/) {
+    prctl(PR_SET_NAME, "logd.daemon");
+    set_sched_policy(0, SP_BACKGROUND);
+    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND);
+
+    setgid(AID_SYSTEM);
+    setuid(AID_SYSTEM);
+
+    while (reinit_running && !sem_wait(&reinit) && reinit_running) {
+
+        // uidToName Privileged Worker
+        if (uid) {
+            name = NULL;
+
+            FILE *fp = fopen("/data/system/packages.list", "r");
+            if (fp) {
+                // This simple parser is sensitive to format changes in
+                // frameworks/base/services/core/java/com/android/server/pm/Settings.java
+                // A dependency note has been added to that file to correct
+                // this parser.
+
+                char *buffer = NULL;
+                size_t len;
+                while (getline(&buffer, &len, fp) > 0) {
+                    char *userId = strchr(buffer, ' ');
+                    if (!userId) {
+                        continue;
+                    }
+                    *userId = '\0';
+                    unsigned long value = strtoul(userId + 1, NULL, 10);
+                    if (value != uid) {
+                        continue;
+                    }
+                    name = strdup(buffer);
+                    break;
+                }
+                free(buffer);
+                fclose(fp);
+            }
+            uid = 0;
+            sem_post(&uidName);
+            continue;
+        }
+
+        if (fdDmesg >= 0) {
+            static const char reinit_message[] = { KMSG_PRIORITY(LOG_INFO),
+                'l', 'o', 'g', 'd', '.', 'd', 'a', 'e', 'm', 'o', 'n', ':',
+                ' ', 'r', 'e', 'i', 'n', 'i', 't', '\n' };
+            write(fdDmesg, reinit_message, sizeof(reinit_message));
+        }
+
+        // Anything that reads persist.<property>
+        if (logBuf) {
+            logBuf->init();
+        }
+    }
+
+    return NULL;
+}
+
+static sem_t sem_name;
+
+char *android::uidToName(uid_t u) {
+    if (!u || !reinit_running) {
+        return NULL;
+    }
+
+    sem_wait(&sem_name);
+
+    // Not multi-thread safe, we use sem_name to protect
+    uid = u;
+
+    name = NULL;
+    sem_post(&reinit);
+    sem_wait(&uidName);
+    char *ret = name;
+
+    sem_post(&sem_name);
+
+    return ret;
+}
+
+// Serves as a global method to trigger reinitialization
+// and as a function that can be provided to signal().
+void reinit_signal_handler(int /*signal*/) {
+    sem_post(&reinit);
+}
+
+// tagToName converts an events tag into a name
+const char *android::tagToName(uint32_t tag) {
+    static const EventTagMap *map;
+
+    if (!map) {
+        sem_wait(&sem_name);
+        if (!map) {
+            map = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+        }
+        sem_post(&sem_name);
+        if (!map) {
+            return NULL;
+        }
+    }
+    return android_lookupEventTag(map, tag);
+}
+
+static bool property_get_bool_svelte(const char *key) {
+    bool not_user;
+    {
+        char property[PROPERTY_VALUE_MAX];
+        property_get("ro.build.type", property, "");
+        not_user = !!strcmp(property, "user");
+    }
+    return property_get_bool(key, not_user
+            && !property_get_bool("ro.config.low_ram", false));
+}
+
+static void readDmesg(LogAudit *al, LogKlog *kl) {
+    if (!al && !kl) {
+        return;
+    }
+
+    int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
+    if (len <= 0) {
+        return;
+    }
+
+    len += 1024; // Margin for additional input race or trailing nul
+    std::unique_ptr<char []> buf(new char[len]);
+
+    int rc = klogctl(KLOG_READ_ALL, buf.get(), len);
+    if (rc <= 0) {
+        return;
+    }
+
+    if (rc < len) {
+        len = rc + 1;
+    }
+    buf[len - 1] = '\0';
+
+    if (kl) {
+        kl->synchronize(buf.get());
+    }
+
+    for (char *ptr = NULL, *tok = buf.get();
+         (rc >= 0) && ((tok = log_strtok_r(tok, &ptr)));
+         tok = NULL) {
+        if (al) {
+            rc = al->log(tok);
+        }
+        if (kl) {
+            rc = kl->log(tok);
+        }
+    }
+}
+
+// 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
+// controlling the user space logger, and for any additional
+// 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_svelte("logd.klogd");
+    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;
+        }
+        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, 100));
+        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;
+    }
+
+    // Reinit Thread
+    sem_init(&reinit, 0, 0);
+    sem_init(&uidName, 0, 0);
+    sem_init(&sem_name, 0, 1);
+    pthread_attr_t attr;
+    if (!pthread_attr_init(&attr)) {
+        struct sched_param param;
+
+        memset(&param, 0, sizeof(param));
+        pthread_attr_setschedparam(&attr, &param);
+        pthread_attr_setschedpolicy(&attr, SCHED_BATCH);
+        if (!pthread_attr_setdetachstate(&attr,
+                                         PTHREAD_CREATE_DETACHED)) {
+            pthread_t thread;
+            reinit_running = true;
+            if (pthread_create(&thread, &attr, reinit_thread_start, NULL)) {
+                reinit_running = false;
+            }
+        }
+        pthread_attr_destroy(&attr);
     }
 
     if (drop_privs() != 0) {
@@ -147,19 +404,12 @@
     // LogBuffer is the object which is responsible for holding all
     // log entries.
 
-    LogBuffer *logBuf = new LogBuffer(times);
+    logBuf = new LogBuffer(times);
 
-    if (property_get_bool("logd.statistics.dgram_qlen", false)) {
-        logBuf->enableDgramQlenStatistics();
-    }
-    {
-        char property[PROPERTY_VALUE_MAX];
-        property_get("ro.build.type", property, "");
-        if (property_get_bool("logd.statistics",
-                   !!strcmp(property, "user")
-                && !property_get_bool("ro.config.low_ram", false))) {
-            logBuf->enableStatistics();
-        }
+    signal(SIGHUP, reinit_signal_handler);
+
+    if (property_get_bool_svelte("logd.statistics")) {
+        logBuf->enableStatistics();
     }
 
     // LogReader listens on /dev/socket/logdr. When a client
@@ -192,16 +442,32 @@
     // 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", true);
+
+    LogAudit *al = NULL;
     if (auditd) {
-        // failure is an option ... messages are in dmesg (required by standard)
-        LogAudit *al = new LogAudit(logBuf, reader, fdDmesg);
-        if (al->startListener()) {
-            delete al;
-            close(fdDmesg);
-        }
+        bool dmesg = property_get_bool("logd.auditd.dmesg", true);
+        al = new LogAudit(logBuf, reader, dmesg ? fdDmesg : -1);
     }
 
-    pause();
+    LogKlog *kl = NULL;
+    if (klogd) {
+        kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, al != NULL);
+    }
+
+    readDmesg(al, kl);
+
+    // failure is an option ... messages are in dmesg (required by standard)
+
+    if (kl && kl->startListener()) {
+        delete kl;
+    }
+
+    if (al && al->startListener()) {
+        delete al;
+    }
+
+    TEMP_FAILURE_RETRY(pause());
+
     exit(0);
 }
-
diff --git a/logd/tests/Android.mk b/logd/tests/Android.mk
index f851288..85ca4ac 100644
--- a/logd/tests/Android.mk
+++ b/logd/tests/Android.mk
@@ -46,7 +46,6 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := $(test_module_prefix)unit-tests
 LOCAL_MODULE_TAGS := $(test_tags)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += $(test_c_flags)
 LOCAL_SHARED_LIBRARIES := libcutils
 LOCAL_SRC_FILES := $(test_src_files)
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 4bea4be..3266360 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -93,53 +93,42 @@
 static char *find_benchmark_spam(char *cp)
 {
     // liblog_benchmarks has been run designed to SPAM.  The signature of
-    // a noisiest UID statistics is one of the following:
+    // a noisiest UID statistics is:
     //
-    // main: UID/PID Total size/num   Now          UID/PID[?]  Total
-    // 0           7500306/304207     71608/3183   0/4225?     7454388/303656
-    //    <wrap>                                                     93432/1012
-    // -or-
-    // 0/gone      7454388/303656     93432/1012
+    // Chattiest UIDs in main log buffer:                           Size Pruned
+    // UID   PACKAGE                                                BYTES LINES
+    // 0     root                                                  54164 147569
     //
-    // basically if we see a *large* number of 0/????? entries
-    unsigned long value;
+    char *benchmark = NULL;
     do {
-        char *benchmark = strstr(cp, " 0/");
-        char *benchmark_newline = strstr(cp, "\n0/");
+        static const char signature[] = "\n0     root ";
+
+        benchmark = strstr(cp, signature);
         if (!benchmark) {
-            benchmark = benchmark_newline;
-        }
-        if (benchmark_newline && (benchmark > benchmark_newline)) {
-            benchmark = benchmark_newline;
-        }
-        cp = benchmark;
-        if (!cp) {
             break;
         }
-        cp += 3;
-        while (isdigit(*cp) || (*cp == 'g') || (*cp == 'o') || (*cp == 'n')) {
+        cp = benchmark + sizeof(signature);
+        while (isspace(*cp)) {
             ++cp;
         }
-        value = 0;
-        // ###? or gone
-        if ((*cp == '?') || (*cp == 'e')) {
-            while (*++cp == ' ');
-            while (isdigit(*cp)) {
-                value = value * 10ULL + *cp - '0';
-                ++cp;
-            }
-            if (*cp != '/') {
-                value = 0;
-                continue;
-            }
-            while (isdigit(*++cp));
-            while (*cp == ' ') ++cp;
-            if (!isdigit(*cp)) {
-                value = 0;
-            }
+        benchmark = cp;
+        while (isdigit(*cp)) {
+            ++cp;
         }
-    } while ((value < 900000ULL) && *cp);
-    return cp;
+        while (isspace(*cp)) {
+            ++cp;
+        }
+        unsigned long value = 0;
+        while (isdigit(*cp)) {
+            value = value * 10ULL + *cp - '0';
+            ++cp;
+        }
+        if (value > 100000UL) {
+            break;
+        }
+        benchmark = NULL;
+    } while (*cp);
+    return benchmark;
 }
 
 TEST(logd, statistics) {
@@ -179,177 +168,19 @@
     EXPECT_EQ(0, truncated);
 
 #ifdef TARGET_USES_LOGD
-    char *main_logs = strstr(cp, "\nmain:");
+    char *main_logs = strstr(cp, "\nChattiest UIDs in main ");
     EXPECT_TRUE(NULL != main_logs);
 
-    char *radio_logs = strstr(cp, "\nradio:");
+    char *radio_logs = strstr(cp, "\nChattiest UIDs in radio ");
     EXPECT_TRUE(NULL != radio_logs);
 
-    char *system_logs = strstr(cp, "\nsystem:");
+    char *system_logs = strstr(cp, "\nChattiest UIDs in system ");
     EXPECT_TRUE(NULL != system_logs);
 
-    char *events_logs = strstr(cp, "\nevents:");
+    char *events_logs = strstr(cp, "\nChattiest UIDs in events ");
     EXPECT_TRUE(NULL != events_logs);
 #endif
 
-    // Parse timing stats
-
-    cp = strstr(cp, "Minimum time between log events per dgram_qlen:");
-
-    if (cp) {
-        while (*cp && (*cp != '\n')) {
-            ++cp;
-        }
-        if (*cp == '\n') {
-            ++cp;
-        }
-
-        char *list_of_spans = cp;
-        EXPECT_NE('\0', *list_of_spans);
-
-        unsigned short number_of_buckets = 0;
-        unsigned short *dgram_qlen = NULL;
-        unsigned short bucket = 0;
-        while (*cp && (*cp != '\n')) {
-            bucket = 0;
-            while (isdigit(*cp)) {
-                bucket = bucket * 10 + *cp - '0';
-                ++cp;
-            }
-            while (*cp == ' ') {
-                ++cp;
-            }
-            if (!bucket) {
-                break;
-            }
-            unsigned short *new_dgram_qlen = new unsigned short[number_of_buckets + 1];
-            EXPECT_TRUE(new_dgram_qlen != NULL);
-            if (dgram_qlen) {
-                memcpy(new_dgram_qlen, dgram_qlen, sizeof(*dgram_qlen) * number_of_buckets);
-                delete [] dgram_qlen;
-            }
-
-            dgram_qlen = new_dgram_qlen;
-            dgram_qlen[number_of_buckets++] = bucket;
-        }
-
-        char *end_of_spans = cp;
-        EXPECT_NE('\0', *end_of_spans);
-
-        EXPECT_LT(5, number_of_buckets);
-
-        unsigned long long *times = new unsigned long long [number_of_buckets];
-        ASSERT_TRUE(times != NULL);
-
-        memset(times, 0, sizeof(*times) * number_of_buckets);
-
-        while (*cp == '\n') {
-            ++cp;
-        }
-
-        unsigned short number_of_values = 0;
-        unsigned long long value;
-        while (*cp && (*cp != '\n')) {
-            EXPECT_GE(number_of_buckets, number_of_values);
-
-            value = 0;
-            while (isdigit(*cp)) {
-                value = value * 10ULL + *cp - '0';
-                ++cp;
-            }
-
-            switch(*cp) {
-            case ' ':
-            case '\n':
-                value *= 1000ULL;
-                /* FALLTHRU */
-            case 'm':
-                value *= 1000ULL;
-                /* FALLTHRU */
-            case 'u':
-                value *= 1000ULL;
-                /* FALLTHRU */
-            case 'n':
-            default:
-                break;
-            }
-            while (*++cp == ' ');
-
-            if (!value) {
-                break;
-            }
-
-            times[number_of_values] = value;
-            ++number_of_values;
-        }
-
-#ifdef TARGET_USES_LOGD
-        EXPECT_EQ(number_of_values, number_of_buckets);
-#endif
-
-        FILE *fp;
-        ASSERT_TRUE(NULL != (fp = fopen("/proc/sys/net/unix/max_dgram_qlen", "r")));
-
-        unsigned max_dgram_qlen = 0;
-        fscanf(fp, "%u", &max_dgram_qlen);
-
-        fclose(fp);
-
-        // Find launch point
-        unsigned short launch = 0;
-        unsigned long long total = 0;
-        do {
-            total += times[launch];
-        } while (((++launch < number_of_buckets)
-                && ((total / launch) >= (times[launch] / 8ULL)))
-            || (launch == 1)); // too soon
-
-        bool failure = number_of_buckets <= launch;
-        if (!failure) {
-            unsigned short l = launch;
-            if (l >= number_of_buckets) {
-                l = number_of_buckets - 1;
-            }
-            failure = max_dgram_qlen < dgram_qlen[l];
-        }
-
-        // We can get failure if at any time liblog_benchmarks has been run
-        // because designed to overload /proc/sys/net/unix/max_dgram_qlen even
-        // at excessive values like 20000. It does so to measure the raw processing
-        // performance of logd.
-        if (failure) {
-            cp = find_benchmark_spam(cp);
-        }
-
-        if (cp) {
-            // Fake a failure, but without the failure code
-            if (number_of_buckets <= launch) {
-                printf ("Expected: number_of_buckets > launch, actual: %u vs %u\n",
-                        number_of_buckets, launch);
-            }
-            if (launch >= number_of_buckets) {
-                launch = number_of_buckets - 1;
-            }
-            if (max_dgram_qlen < dgram_qlen[launch]) {
-                printf ("Expected: max_dgram_qlen >= dgram_qlen[%d],"
-                            " actual: %u vs %u\n",
-                        launch, max_dgram_qlen, dgram_qlen[launch]);
-            }
-        } else
-#ifndef TARGET_USES_LOGD
-        if (total)
-#endif
-        {
-            EXPECT_GT(number_of_buckets, launch);
-            if (launch >= number_of_buckets) {
-                launch = number_of_buckets - 1;
-            }
-            EXPECT_GE(max_dgram_qlen, dgram_qlen[launch]);
-        }
-
-        delete [] dgram_qlen;
-        delete [] times;
-    }
     delete [] buf;
 }
 
@@ -417,7 +248,11 @@
         if (((p - cp) > 3) && !*p && ((unsigned int)(p - cp) < len)) {
             fprintf(stderr, "\"");
             while (*cp) {
-                fprintf(stderr, (*cp != '\n') ? "%c" : "\\n", *cp);
+                if (*cp != '\n') {
+                    fprintf(stderr, "%c", *cp);
+                } else {
+                    fprintf(stderr, "\\n");
+                }
                 ++cp;
                 --len;
             }
@@ -585,13 +420,13 @@
     }
 
 #ifdef TARGET_USES_LOGD
-    EXPECT_GE(100000UL, ns[log_maximum_retry]); // 42777 user
+    EXPECT_GE(200000UL, ns[log_maximum_retry]); // 104734 user
 #else
     EXPECT_GE(10000UL, ns[log_maximum_retry]); // 5636 kernel
 #endif
 
 #ifdef TARGET_USES_LOGD
-    EXPECT_GE(30000UL, ns[log_maximum]); // 27305 user
+    EXPECT_GE(90000UL, ns[log_maximum]); // 46913 user
 #else
     EXPECT_GE(10000UL, ns[log_maximum]); // 5637 kernel
 #endif
@@ -599,13 +434,13 @@
     EXPECT_GE(4096UL, ns[clock_overhead]); // 4095
 
 #ifdef TARGET_USES_LOGD
-    EXPECT_GE(250000UL, ns[log_overhead]); // 121876 user
+    EXPECT_GE(250000UL, ns[log_overhead]); // 126886 user
 #else
     EXPECT_GE(100000UL, ns[log_overhead]); // 50945 kernel
 #endif
 
 #ifdef TARGET_USES_LOGD
-    EXPECT_GE(7500UL, ns[log_latency]); // 3718 user space
+    EXPECT_GE(10000UL, ns[log_latency]); // 5669 user space
 #else
     EXPECT_GE(500000UL, ns[log_latency]); // 254200 kernel
 #endif
@@ -637,8 +472,7 @@
     ASSERT_TRUE(benchmark_statistics_found != NULL);
 
     // Check how effective the SPAM filter is, parse out Now size.
-    //             Total               Now
-    // 0/4225?     7454388/303656      31488/755
+    // 0     root                      54164 147569
     //                                 ^-- benchmark_statistics_found
 
     unsigned long nowSpamSize = atol(benchmark_statistics_found);
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index 3a6276e..83576fb 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -325,7 +325,7 @@
 
     if (log_target & LOG_KLOG) {
         snprintf(log_info.klog_fmt, sizeof(log_info.klog_fmt),
-                 "<6>%.*s: %%s", MAX_KLOG_TAG, log_info.btag);
+                 "<6>%.*s: %%s\n", MAX_KLOG_TAG, log_info.btag);
     }
 
     if ((log_target & LOG_FILE) && !file_path) {
diff --git a/mkbootimg/bootimg.h b/mkbootimg/bootimg.h
index 9171d85..5ab6195 100644
--- a/mkbootimg/bootimg.h
+++ b/mkbootimg/bootimg.h
@@ -15,6 +15,8 @@
 ** limitations under the License.
 */
 
+#include <stdint.h>
+
 #ifndef _BOOT_IMAGE_H_
 #define _BOOT_IMAGE_H_
 
@@ -28,31 +30,31 @@
 
 struct boot_img_hdr
 {
-    unsigned char magic[BOOT_MAGIC_SIZE];
+    uint8_t magic[BOOT_MAGIC_SIZE];
 
-    unsigned kernel_size;  /* size in bytes */
-    unsigned kernel_addr;  /* physical load addr */
+    uint32_t kernel_size;  /* size in bytes */
+    uint32_t kernel_addr;  /* physical load addr */
 
-    unsigned ramdisk_size; /* size in bytes */
-    unsigned ramdisk_addr; /* physical load addr */
+    uint32_t ramdisk_size; /* size in bytes */
+    uint32_t ramdisk_addr; /* physical load addr */
 
-    unsigned second_size;  /* size in bytes */
-    unsigned second_addr;  /* physical load addr */
+    uint32_t second_size;  /* size in bytes */
+    uint32_t second_addr;  /* physical load addr */
 
-    unsigned tags_addr;    /* physical addr for kernel tags */
-    unsigned page_size;    /* flash page size we assume */
-    unsigned unused[2];    /* future expansion: should be 0 */
+    uint32_t tags_addr;    /* physical addr for kernel tags */
+    uint32_t page_size;    /* flash page size we assume */
+    uint32_t unused[2];    /* future expansion: should be 0 */
 
-    unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
+    uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */
 
-    unsigned char cmdline[BOOT_ARGS_SIZE];
+    uint8_t cmdline[BOOT_ARGS_SIZE];
 
-    unsigned id[8]; /* timestamp / checksum / sha1 / etc */
+    uint32_t id[8]; /* timestamp / checksum / sha1 / etc */
 
     /* Supplemental command line data; kept here to maintain
      * binary compatibility with older versions of mkbootimg */
-    unsigned char extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
-};
+    uint8_t extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
+} __attribute__((packed));
 
 /*
 ** +-----------------+ 
diff --git a/mkbootimg/mkbootimg.c b/mkbootimg/mkbootimg.c
index fc92b4d..b6a2801 100644
--- a/mkbootimg/mkbootimg.c
+++ b/mkbootimg/mkbootimg.c
@@ -21,6 +21,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <stdbool.h>
 
 #include "mincrypt/sha.h"
 #include "bootimg.h"
@@ -59,12 +60,13 @@
 {
     fprintf(stderr,"usage: mkbootimg\n"
             "       --kernel <filename>\n"
-            "       --ramdisk <filename>\n"
+            "       [ --ramdisk <filename> ]\n"
             "       [ --second <2ndbootloader-filename> ]\n"
             "       [ --cmdline <kernel-commandline> ]\n"
             "       [ --board <boardname> ]\n"
             "       [ --base <address> ]\n"
             "       [ --pagesize <pagesize> ]\n"
+            "       [ --id ]\n"
             "       -o|--output <filename>\n"
             );
     return 1;
@@ -74,6 +76,14 @@
 
 static unsigned char padding[16384] = { 0, };
 
+static void print_id(const uint8_t *id, size_t id_len) {
+    printf("0x");
+    for (unsigned i = 0; i < id_len; i++) {
+        printf("%02x", id[i]);
+    }
+    printf("\n");
+}
+
 int write_padding(int fd, unsigned pagesize, unsigned itemsize)
 {
     unsigned pagemask = pagesize - 1;
@@ -96,24 +106,24 @@
 {
     boot_img_hdr hdr;
 
-    char *kernel_fn = 0;
-    void *kernel_data = 0;
-    char *ramdisk_fn = 0;
-    void *ramdisk_data = 0;
-    char *second_fn = 0;
-    void *second_data = 0;
+    char *kernel_fn = NULL;
+    void *kernel_data = NULL;
+    char *ramdisk_fn = NULL;
+    void *ramdisk_data = NULL;
+    char *second_fn = NULL;
+    void *second_data = NULL;
     char *cmdline = "";
-    char *bootimg = 0;
+    char *bootimg = NULL;
     char *board = "";
-    unsigned pagesize = 2048;
+    uint32_t pagesize = 2048;
     int fd;
     SHA_CTX ctx;
     const uint8_t* sha;
-    unsigned base           = 0x10000000;
-    unsigned kernel_offset  = 0x00008000;
-    unsigned ramdisk_offset = 0x01000000;
-    unsigned second_offset  = 0x00f00000;
-    unsigned tags_offset    = 0x00000100;
+    uint32_t base           = 0x10000000U;
+    uint32_t kernel_offset  = 0x00008000U;
+    uint32_t ramdisk_offset = 0x01000000U;
+    uint32_t second_offset  = 0x00f00000U;
+    uint32_t tags_offset    = 0x00000100U;
     size_t cmdlen;
 
     argc--;
@@ -121,42 +131,48 @@
 
     memset(&hdr, 0, sizeof(hdr));
 
+    bool get_id = false;
     while(argc > 0){
         char *arg = argv[0];
-        char *val = argv[1];
-        if(argc < 2) {
-            return usage();
-        }
-        argc -= 2;
-        argv += 2;
-        if(!strcmp(arg, "--output") || !strcmp(arg, "-o")) {
-            bootimg = val;
-        } else if(!strcmp(arg, "--kernel")) {
-            kernel_fn = val;
-        } else if(!strcmp(arg, "--ramdisk")) {
-            ramdisk_fn = val;
-        } else if(!strcmp(arg, "--second")) {
-            second_fn = val;
-        } else if(!strcmp(arg, "--cmdline")) {
-            cmdline = val;
-        } else if(!strcmp(arg, "--base")) {
-            base = strtoul(val, 0, 16);
-        } else if(!strcmp(arg, "--kernel_offset")) {
-            kernel_offset = strtoul(val, 0, 16);
-        } else if(!strcmp(arg, "--ramdisk_offset")) {
-            ramdisk_offset = strtoul(val, 0, 16);
-        } else if(!strcmp(arg, "--second_offset")) {
-            second_offset = strtoul(val, 0, 16);
-        } else if(!strcmp(arg, "--tags_offset")) {
-            tags_offset = strtoul(val, 0, 16);
-        } else if(!strcmp(arg, "--board")) {
-            board = val;
-        } else if(!strcmp(arg,"--pagesize")) {
-            pagesize = strtoul(val, 0, 10);
-            if ((pagesize != 2048) && (pagesize != 4096)
-                && (pagesize != 8192) && (pagesize != 16384)) {
-                fprintf(stderr,"error: unsupported page size %d\n", pagesize);
-                return -1;
+        if (!strcmp(arg, "--id")) {
+            get_id = true;
+            argc -= 1;
+            argv += 1;
+        } else if(argc >= 2) {
+            char *val = argv[1];
+            argc -= 2;
+            argv += 2;
+            if(!strcmp(arg, "--output") || !strcmp(arg, "-o")) {
+                bootimg = val;
+            } else if(!strcmp(arg, "--kernel")) {
+                kernel_fn = val;
+            } else if(!strcmp(arg, "--ramdisk")) {
+                ramdisk_fn = val;
+            } else if(!strcmp(arg, "--second")) {
+                second_fn = val;
+            } else if(!strcmp(arg, "--cmdline")) {
+                cmdline = val;
+            } else if(!strcmp(arg, "--base")) {
+                base = strtoul(val, 0, 16);
+            } else if(!strcmp(arg, "--kernel_offset")) {
+                kernel_offset = strtoul(val, 0, 16);
+            } else if(!strcmp(arg, "--ramdisk_offset")) {
+                ramdisk_offset = strtoul(val, 0, 16);
+            } else if(!strcmp(arg, "--second_offset")) {
+                second_offset = strtoul(val, 0, 16);
+            } else if(!strcmp(arg, "--tags_offset")) {
+                tags_offset = strtoul(val, 0, 16);
+            } else if(!strcmp(arg, "--board")) {
+                board = val;
+            } else if(!strcmp(arg,"--pagesize")) {
+                pagesize = strtoul(val, 0, 10);
+                if ((pagesize != 2048) && (pagesize != 4096)
+                    && (pagesize != 8192) && (pagesize != 16384)) {
+                    fprintf(stderr,"error: unsupported page size %d\n", pagesize);
+                    return -1;
+                }
+            } else {
+                return usage();
             }
         } else {
             return usage();
@@ -179,11 +195,6 @@
         return usage();
     }
 
-    if(ramdisk_fn == 0) {
-        fprintf(stderr,"error: no ramdisk image specified\n");
-        return usage();
-    }
-
     if(strlen(board) >= BOOT_NAME_SIZE) {
         fprintf(stderr,"error: board name too large\n");
         return usage();
@@ -213,7 +224,7 @@
         return 1;
     }
 
-    if(!strcmp(ramdisk_fn,"NONE")) {
+    if(ramdisk_fn == 0) {
         ramdisk_data = 0;
         hdr.ramdisk_size = 0;
     } else {
@@ -266,6 +277,10 @@
         if(write_padding(fd, pagesize, hdr.second_size)) goto fail;
     }
 
+    if (get_id) {
+        print_id((uint8_t *) hdr.id, sizeof(hdr.id));
+    }
+
     return 0;
 
 fail:
diff --git a/netcfg/Android.mk b/netcfg/Android.mk
deleted file mode 100644
index fc01a54..0000000
--- a/netcfg/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-ifneq ($(BUILD_TINY_ANDROID),true)
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= netcfg.c
-LOCAL_MODULE:= netcfg
-
-#LOCAL_FORCE_STATIC_EXECUTABLE := true
-#LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
-#LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
-#LOCAL_STATIC_LIBRARIES := libcutils libc
-
-LOCAL_SHARED_LIBRARIES := libc libnetutils
-LOCAL_CFLAGS := -Werror
-
-include $(BUILD_EXECUTABLE)
-endif
diff --git a/netcfg/MODULE_LICENSE_APACHE2 b/netcfg/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/netcfg/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/netcfg/NOTICE b/netcfg/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/netcfg/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
-   Copyright (c) 2005-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.
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the 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.
-
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
diff --git a/netcfg/netcfg.c b/netcfg/netcfg.c
deleted file mode 100644
index 4e83ba4..0000000
--- a/netcfg/netcfg.c
+++ /dev/null
@@ -1,182 +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 <dirent.h>
-#include <netinet/ether.h>
-#include <netinet/if_ether.h>
-#include <netutils/dhcp.h>
-#include <netutils/ifc.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-void die(const char *reason)
-{
-    perror(reason);
-    exit(1);
-}
-
-const char *ipaddr(in_addr_t addr)
-{
-    struct in_addr in_addr;
-
-    in_addr.s_addr = addr;
-    return inet_ntoa(in_addr);
-}
-
-void usage(void)
-{
-    fprintf(stderr,"usage: netcfg [<interface> {dhcp|up|down}]\n");
-    exit(1);
-}
-
-int dump_interface(const char *name)
-{
-    unsigned addr, flags;
-    unsigned char hwbuf[ETH_ALEN];
-    int prefixLength;
-
-    if(ifc_get_info(name, &addr, &prefixLength, &flags)) {
-        return 0;
-    }
-
-    printf("%-8s %s  ", name, flags & 1 ? "UP  " : "DOWN");
-    printf("%40s", ipaddr(addr));
-    printf("/%-4d", prefixLength);
-    printf("0x%08x ", flags);
-    if (!ifc_get_hwaddr(name, hwbuf)) {
-        int i;
-        for(i=0; i < (ETH_ALEN-1); i++)
-            printf("%02x:", hwbuf[i]);
-        printf("%02x\n", hwbuf[i]);
-    } else {
-        printf("\n");
-    }
-    return 0;
-}
-
-int dump_interfaces(void)
-{
-    DIR *d;
-    struct dirent *de;
-
-    d = opendir("/sys/class/net");
-    if(d == 0) return -1;
-
-    while((de = readdir(d))) {
-        if(de->d_name[0] == '.') continue;
-        dump_interface(de->d_name);
-    }
-    closedir(d);
-    return 0;
-}
-
-int set_hwaddr(const char *name, const char *asc) {
-    struct ether_addr *addr = ether_aton(asc);
-    if (!addr) {
-        printf("Failed to parse '%s'\n", asc);
-        return -1;
-    }
-    return ifc_set_hwaddr(name, addr->ether_addr_octet);
-}
-
-struct 
-{
-    const char *name;
-    int nargs;
-    void *func;
-} CMDS[] = {
-    { "dhcp",   1, do_dhcp },
-    { "up",     1, ifc_up },
-    { "down",   1, ifc_down },
-    { "deldefault", 1, ifc_remove_default_route },
-    { "hwaddr", 2, set_hwaddr },
-    { 0, 0, 0 },
-};
-
-static int call_func(void *_func, unsigned nargs, char **args)
-{
-    switch(nargs){
-    case 1: {
-        int (*func)(char *a0) = _func;
-        return func(args[0]);
-    }
-    case 2: {
-        int (*func)(char *a0, char *a1) = _func;
-        return func(args[0], args[1]);
-    }
-    case 3: {
-        int (*func)(char *a0, char *a1, char *a2) = _func;
-        return func(args[0], args[1], args[2]);
-    }
-    default:
-        return -1;
-    }
-}
-
-int main(int argc, char **argv)
-{
-    char *iname;
-    int n;
-    
-    if(ifc_init()) {
-        die("Cannot perform requested operation");
-    }
-
-    if(argc == 1) {
-        int result = dump_interfaces();
-        ifc_close();
-        return result;
-    }
-
-    if(argc < 3) usage();
-
-    iname = argv[1];
-    if(strlen(iname) > 16) usage();
-
-    argc -= 2;
-    argv += 2;
-    while(argc > 0) {
-        for(n = 0; CMDS[n].name; n++){
-            if(!strcmp(argv[0], CMDS[n].name)) {
-                char *cmdname = argv[0];
-                int nargs = CMDS[n].nargs;
-                
-                argv[0] = iname;
-                if(argc < nargs) {
-                    fprintf(stderr, "not enough arguments for '%s'\n", cmdname);
-                    ifc_close();
-                    exit(1);
-                }
-                if(call_func(CMDS[n].func, nargs, argv)) {
-                    fprintf(stderr, "action '%s' failed (%s)\n", cmdname, strerror(errno));
-                    ifc_close();
-                    exit(1);
-                }
-                argc -= nargs;
-                argv += nargs;
-                goto done;
-            }
-        }
-        fprintf(stderr,"no such action '%s'\n", argv[0]);
-        usage();
-    done:
-        ;
-    }
-    ifc_close();
-
-    return 0;
-}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 3ecb1db..7ab76b8 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -26,7 +26,7 @@
 #
 # create some directories (some are mount points)
 LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
-    sbin dev proc sys system data)
+    sbin dev proc sys system data oem)
 
 include $(BUILD_SYSTEM)/base_rules.mk
 
diff --git a/rootdir/etc/hosts b/rootdir/etc/hosts
index 99848f6..649151c 100644
--- a/rootdir/etc/hosts
+++ b/rootdir/etc/hosts
@@ -1 +1,2 @@
-127.0.0.1		    localhost
+127.0.0.1       localhost
+::1             ip6-localhost
diff --git a/rootdir/etc/init.testmenu b/rootdir/etc/init.testmenu
deleted file mode 100755
index 7ae16d5..0000000
--- a/rootdir/etc/init.testmenu
+++ /dev/null
@@ -1,322 +0,0 @@
-#!/system/bin/sh
-
-atdev=/dev/omap_csmi_tty0
-pppdev=/dev/omap_csmi_tty1
-
-n1=`cat /data/phoneentry1 2>/dev/null`
-n2=`cat /data/phoneentry2 2>/dev/null`
-n3=`cat /data/phoneentry3 2>/dev/null`
-n1=${n1:-"*#06#"}
-n2=${n2:-"*#06#"}
-n3=${n3:-"*#06#"}
-phoneoutputpid=
-eventoutputpid=
-notifypid=
-notifytoggle=false
-pppdpid=
-powerdidletime=120
-
-# map phone specific keys
-setkey -k 0xe4 -v 0x23 # map #
-setkey -k 0xe3 -v 0x2a # map *
-setkey -k 231 -v 513 # map send to newline
-#setkey -k 0x67 -v 0x20b # map up to scroll back
-#setkey -k 0x6c -v 0x20a # map down to scroll forward
-setkey -k 0x73 -v 0x20b # map volume up to scroll back
-setkey -k 0x72 -v 0x20a # map volume down to scroll forward
-setkey -k 0x60 -v 0x211 # map PoC to next console
-
-# tuttle keys
-setkey -k 0x38 -v 0x703 # map leftalt to alt
-setkey -k 0x9b -v 0x703 # map mail to alt
-setkey -t 8 -k 0x9b -v 0x703 # map alt-mail to alt
-setkey -t 8 -k 0x10 -v 0x21 # map alt-q to !
-setkey -t 8 -k 0x11 -v 0x31 # map alt-w to 1
-setkey -t 8 -k 0x12 -v 0x32 # map alt-e to 2
-setkey -t 8 -k 0x13 -v 0x33 # map alt-r to 3
-setkey -t 8 -k 0x14 -v 0x2b # map alt-t to +
-setkey -t 8 -k 0x15 -v 0x28 # map alt-y to (
-setkey -t 8 -k 0x16 -v 0x29 # map alt-u to )
-setkey -t 8 -k 0x17 -v 0x2d # map alt-i to -
-setkey -t 8 -k 0x18 -v 0x5f # map alt-o to _
-setkey -t 8 -k 0x19 -v 0x22 # map alt-p to "
-setkey -t 8 -k 0x1e -v 0x23 # map alt-a to #
-setkey -t 8 -k 0x1f -v 0x34 # map alt-s to 4
-setkey -t 8 -k 0x20 -v 0x35 # map alt-d to 5
-setkey -t 8 -k 0x21 -v 0x36 # map alt-f to 6
-setkey -t 8 -k 0x22 -v 0x2f # map alt-g to /
-setkey -t 8 -k 0x23 -v 0x3f # map alt-h to ?
-setkey -t 8 -k 0x24 -v 0xa3 # map alt-j to pound
-setkey -t 8 -k 0x25 -v 0x24 # map alt-k to $
-setkey -t 8 -k 0x2c -v 0x2a # map alt-z to *
-setkey -t 8 -k 0x2d -v 0x37 # map alt-x to 7
-setkey -t 8 -k 0x2e -v 0x38 # map alt-c to 8
-setkey -t 8 -k 0x2f -v 0x39 # map alt-v to 9
-setkey -t 8 -k 0x30 -v 0x7c # map alt-b to |
-setkey -t 8 -k 0x31 -v 0x40 # map alt-n to @
-setkey -t 8 -k 0x32 -v 0x3d # map alt-m to =
-setkey -t 8 -k 0x33 -v 0x3b # map alt-, to ;
-setkey -t 8 -k 0x34 -v 0x3a # map alt-. to :
-setkey -t 8 -k 0x0f -v 0x30 # map alt-tab to 0
-setkey -t 8 -k 0x67 -v 0x20b # map alt-up to scroll back
-setkey -t 8 -k 0x6c -v 0x20a # map alt-down to scroll forward
-
-while true
-do
-	echo
-	echo "------------------------------"
-	echo " 1: init commands"
-	echo " 2: call commands"
-	echo " 3: misc phone"
-	echo " 4: phone debug output"
-	echo " 5: test data connection"
-	echo " 6: start runtime"
-	echo " 7: start runtime w/output"
-	echo " 8: stop runtime"
-	echo " 9: misc"
-	echo -n ": "
-	while true
-	do
-		c=`readtty -t 50 -f -a 1234567890#`
-		case "$c" in
-			"" ) ;;
-			* ) break;
-		esac
-	done
-	echo Got key -$c-
-	case $c in
-		"1" )
-			while true; do
-				echo
-				echo "------------------------------"
-				echo " 1: Print phone output"
-				echo " 2: ATQ0V1E1+CMEE=2;+CREG=0"
-				echo " 3: AT+CFUN=1"
-				echo " 4: AT+COPS=0"
-				echo " 5: AT+CREG?"
-				echo " 6: Stop phone output"
-				echo " 0: back"
-				echo -n ": "
-				c=`readtty -f -a 1234560#`
-				echo Got key -$c-
-				case "$c" in
-					"1" ) kill $phoneoutputpid; cat $atdev & phoneoutputpid=$! ;;
-					"2" ) echo -e "ATQ0V1E1+CMEE=2;+CREG=0\r" >$atdev;;
-					"3" ) echo -e "AT+CFUN=1\r" >$atdev;;
-					"4" ) echo -e "AT+COPS=0\r" >$atdev;;
-					"5" ) echo -e "AT+CREG?\r" >$atdev;;
-					"6" ) kill $phoneoutputpid; phoneoutputpid= ;;
-					"0" ) break;;
-				esac
-			done
-		;;
-		"2" )
-			while true; do
-				echo
-				echo "------------------------------"
-				echo " 1: Dial: ATD $n1;"
-				echo " 2: Dial: ATD $n2;"
-				echo " 3: Dial: ATD $n3;"
-				echo " 4: Set number for 1"
-				echo " 5: Set number for 2"
-				echo " 6: Set number for 3"
-				echo " 7: Dial: ATD ...;"
-				echo " 8: Hang up: ATH"
-				echo " 9: Answer: ATA"
-				echo " 0: back"
-				echo -n ": "
-				c=`readtty -f -a 1234567890#`
-				echo Got key -$c-
-				case "$c" in
-					"1" ) echo "Dialing $n1"; echo -e "ATD $n1;\r" >$atdev;;
-					"2" ) echo "Dialing $n2"; echo -e "ATD $n2;\r" >$atdev;;
-					"3" ) echo "Dialing $n3"; echo -e "ATD $n3;\r" >$atdev;;
-					"4" ) echo -n "Number: "; read n1; echo $n1 >/data/phoneentry1;;
-					"5" ) echo -n "Number: "; read n2; echo $n2 >/data/phoneentry2;;
-					"6" ) echo -n "Number: "; read n3; echo $n3 >/data/phoneentry3;;
-					"7" ) echo -n "Number: "; read n; echo "Dialing $n"; echo -e "ATD $n;\r" >$atdev;;
-					"8" ) echo -e "ATH\r" >$atdev;;
-					"9" ) echo -e "ATA\r" >$atdev;;
-					"0" ) break;;
-				esac
-			done
-		;;
-		"3" )
-			while true; do
-				echo
-				echo "------------------------------"
-				echo " 1: Save FFS data"
-				echo " 2: Load user FFS data"
-				echo " 3: Load system FFS data"
-				echo " 4: Reset FFS data"
-				echo " 5: Set uplink gain"
-				echo " 6: Set echo"
-				echo " 7: cat /dev/omap_csmi_battery_t"
-				echo " 8: cat /dev/omap_csmi_htc"
-				echo " 0: back"
-				echo -n ": "
-				c=`readtty -f -a 123456780#`
-				echo Got key -$c-
-				case "$c" in
-					"1" ) cat /dev/omap_csmi_ffs >/data/ffsdata;;
-					"2" ) cat /data/ffsdata >/dev/omap_csmi_ffs;;
-					"3" ) cat /system/ffsdata >/dev/omap_csmi_ffs;;
-					"4" ) echo - >/dev/omap_csmi_ffs;;
-					"5" )
-						echo -n "Gain: "; read g;
-						echo gu$g >/tmp/gain;
-						cat /tmp/gain 2>/dev/null >/dev/omap_csmi_audio_tes
-					;;
-					"6" )
-						echo -n "Echo param (hex): "; read e;
-						echo "e0x$e" >/tmp/echo;
-						cat /tmp/echo 2>/dev/null >/dev/omap_csmi_audio_tes
-					;;
-					"7" ) cat /dev/omap_csmi_battery_t;;
-					"8" ) cat /dev/omap_csmi_htc;;
-					"0" ) break;;
-				esac
-			done
-		;;
-		"4" )
-			while true; do
-				echo
-				echo "------------------------------"
-				echo " 1: Toggle debug I/O"
-				echo " 2: Toggle debug Flow"
-				echo " 3: Toggle debug Interrupt"
-				echo " 4: Toggle debug Info"
-				echo " 5: Toggle GSM run state"
-				echo " 6: Clear GSM data area"
-				echo " 0: back"
-				echo -n ": "
-				c=`readtty -f -a 1234560#`
-				echo Got key -$c-
-				case "$c" in
-					"1" ) echo -n "i" >/sys/devices/system/omap_csmi/debug;;
-					"2" ) echo -n "f" >/sys/devices/system/omap_csmi/debug;;
-					"3" ) echo -n "I" >/sys/devices/system/omap_csmi/debug;;
-					"4" ) echo -n "F" >/sys/devices/system/omap_csmi/debug;;
-					"5" ) echo -n "s" >/sys/devices/system/omap_csmi/debug;;
-					"6" ) echo -n "c" >/sys/devices/system/omap_csmi/debug;;
-					"0" ) break;;
-				esac
-			done
-		;;
-		"5" )
-			while true; do
-				echo
-				echo "------------------------------"
-				echo " 1: Start pppd - userspace"
-				echo " 2: Start pppd - kernel"
-				echo " 3: Start pppd - kernel <at1"
-				echo " 4: Configure ppp data to at2"
-				echo " 5: Test with HTTP GET"
-				echo " 6: Kill pppd"
-				echo " 0: back"
-				echo -n ": "
-				c=`readtty -f -a 1234560#`
-				echo Got key -$c-
-				case "$c" in
-					"1" ) kill $pppdpid; pppd notty < $pppdev > $pppdev & pppdpid=$!;;
-					"2" ) kill $pppdpid; pppd nodetach $pppdev & pppdpid=$!;;
-					"3" ) kill &pppdpid; pppd nodetach $pppdev connect "sh -c \"chat -v -f /etc/ppp/connect-data <$atdev >$atdev\"" & pppdpid=$!;;
-					"4" ) echo -e 'AT%DATA=2,"UART",1,,"SER","UART",0\r' >$atdev;;
-					"5" ) test-data-connection;;
-					"6" ) kill $pppdpid; pppdpid=;;
-					"0" ) break;;
-				esac
-			done
-		;;
-		"6" )
-			echo
-			echo ------------------------
-			echo Starting android runtime
-			echo ------------------------
-			start
-		;;
-		"7" )
-			echo
-			echo ------------------------
-			echo Starting android runtime
-			echo ------------------------
-			if exists /data/singleproc
-			then
-				single_process="-s"
-			else
-				single_process=""
-			fi
-			start runtime $single_process
-		;;
-		"8" )
-			stop
-		;;
-		"9" )
-			while true; do
-				echo
-				echo "------------------------------"
-				echo " 1: Print events"
-				echo " 2: Stop event output"
-				if $notifytoggle
-				then
-					echo " 3: stop notify"
-				else
-					echo " 3: notify /sys/android_power"
-				fi
-				echo " 4: start powerd"
-				echo " 5: start powerd verbose"
-				echo " 6: stop powerd"
-				echo " 7: set powerd idletime ($powerdidletime)"
-				echo " 8: start multitap shell"
-				if exists /data/singleproc
-				then
-					echo " 9: enable multiprocess"
-				else
-					echo " 9: disable multiprocess"
-				fi
-				echo " c: start shell"
-				echo " 0: back"
-				echo -n ": "
-				c=`readtty -f -a 1234567890c#`
-				echo Got key -$c-
-				case "$c" in
-					"1" ) kill $eventoutputpid; getevent & eventoutputpid=$! ;;
-					"2" ) kill $eventoutputpid; eventoutputpid= ;;
-					"3" )
-						if $notifytoggle
-						then
-							kill $notifypid
-							notifypid=
-							notifytoggle=false
-						else
-							kill $notifypid
-							notify -m 0x00000002 -c 0 -p -v 0 -w 30 /sys/android_power &
-							notifypid=$!
-							notifytoggle=true
-						fi
-					;;
-					"4" ) start powerd -i $powerdidletime ;;
-					"5" ) start powerd -i $powerdidletime -v ;;
-					"6" ) stop powerd ;;
-					"7" ) echo -n "Idle time (seconds): "; read powerdidletime ;;
-					"8" )
-						readtty -f -p -t 10 -e "[ ~" | sh -i
-					;;
-					"9" )
-						if exists /data/singleproc
-						then
-							echo "Enabling multiprocess environment."
-							rm /data/singleproc
-						else
-							echo "Disabling multiprocess environment."
-							echo >/data/singleproc "true"
-						fi
-					;;
-					"c" ) sh -i <>/dev/tty0 1>&0 2>&1 ;;
-					"0" ) break;;
-				esac
-			done
-		;;
-	esac
-done
-
diff --git a/rootdir/etc/mountd.conf b/rootdir/etc/mountd.conf
deleted file mode 100644
index 094a2c7..0000000
--- a/rootdir/etc/mountd.conf
+++ /dev/null
@@ -1,19 +0,0 @@
-## mountd configuration file
-
-## add a mount entry for each mount point to be managed by mountd
-mount {
-    ## root block device with partition map or raw FAT file system
-    block_device    /dev/block/mmcblk0
-        
-    ## mount point for block device
-    mount_point     /sdcard
-    
-    ## true if this mount point can be shared via USB mass storage
-    enable_ums      true
-    
-    ## path to the UMS driver file for specifying the block device path  
-    ## use this for the mass_storage function driver
-    driver_store_path   /sys/devices/platform/usb_mass_storage/lun0/file
-    ## use this for android_usb composite gadget driver
-    ##driver_store_path   /sys/devices/platform/msm_hsusb/gadget/lun0/file
-}
diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in
index 30bef46..b34ea01 100644
--- a/rootdir/init.environ.rc.in
+++ b/rootdir/init.environ.rc.in
@@ -1,12 +1,11 @@
 # set up the global environment
 on init
-    export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
     export ANDROID_BOOTLOGO 1
     export ANDROID_ROOT /system
     export ANDROID_ASSETS /system/app
     export ANDROID_DATA /data
     export ANDROID_STORAGE /storage
+    export EXTERNAL_STORAGE /sdcard
     export ASEC_MOUNTPOINT /mnt/asec
-    export LOOP_MOUNTPOINT /mnt/obb
     export BOOTCLASSPATH %BOOTCLASSPATH%
     export SYSTEMSERVERCLASSPATH %SYSTEMSERVERCLASSPATH%
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 34b10d2..c75138b 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -14,32 +14,19 @@
     # Set init and its forked children's oom_adj.
     write /proc/1/oom_score_adj -1000
 
-    # Apply strict SELinux checking of PROT_EXEC on mmap/mprotect calls.
-    write /sys/fs/selinux/checkreqprot 0
-
-    # Set the security context for the init process.
-    # This should occur before anything else (e.g. ueventd) is started.
-    setcon u:r:init:s0
-
     # Set the security context of /adb_keys if present.
     restorecon /adb_keys
 
     start ueventd
 
-    # create mountpoints
-    mkdir /mnt 0775 root system
-
 on init
     sysclktz 0
 
-    loglevel 3
-
-    # Backward compatibility
+    # Backward compatibility.
     symlink /system/etc /etc
     symlink /sys/kernel/debug /d
 
-    # Right now vendor lives on the same filesystem as system,
-    # but someday that may change.
+    # Link /vendor to /system/vendor for devices without a vendor partition.
     symlink /system/vendor /vendor
 
     # Create cgroup mount point for cpu accounting
@@ -65,28 +52,34 @@
     mkdir /cache 0770 system cache
     mkdir /config 0500 root root
 
+    # Mount staging areas for devices managed by vold
     # See storage config details at http://source.android.com/tech/storage/
-    mkdir /mnt/shell 0700 shell shell
-    mkdir /mnt/media_rw 0700 media_rw media_rw
-    mkdir /storage 0751 root sdcard_r
+    mkdir /mnt 0755 root system
+    mount tmpfs tmpfs /mnt mode=0755,uid=0,gid=1000
+    restorecon_recursive /mnt
 
-    # Directory for putting things only root should see.
     mkdir /mnt/secure 0700 root root
+    mkdir /mnt/secure/asec 0700 root root
+    mkdir /mnt/asec 0755 root system
+    mkdir /mnt/obb 0755 root system
+    mkdir /mnt/media_rw 0750 root media_rw
+    mkdir /mnt/user 0755 root root
+    mkdir /mnt/user/0 0755 root root
+    mkdir /mnt/expand 0771 system system
 
-    # Directory for staging bindmounts
-    mkdir /mnt/secure/staging 0700 root root
+    # Storage views to support runtime permissions
+    mkdir /storage 0755 root root
+    mkdir /mnt/runtime 0700 root root
+    mkdir /mnt/runtime/default 0755 root root
+    mkdir /mnt/runtime/default/self 0755 root root
+    mkdir /mnt/runtime/read 0755 root root
+    mkdir /mnt/runtime/read/self 0755 root root
+    mkdir /mnt/runtime/write 0755 root root
+    mkdir /mnt/runtime/write/self 0755 root root
 
-    # Directory-target for where the secure container
-    # imagefile directory will be bind-mounted
-    mkdir /mnt/secure/asec  0700 root root
-
-    # Secure container public mount points.
-    mkdir /mnt/asec  0700 root system
-    mount tmpfs tmpfs /mnt/asec mode=0755,gid=1000
-
-    # Filesystem image public mount points.
-    mkdir /mnt/obb 0700 root system
-    mount tmpfs tmpfs /mnt/obb mode=0755,gid=1000
+    # Symlink to keep legacy apps working in multi-user world
+    symlink /storage/self/primary /sdcard
+    symlink /mnt/user/0/primary /mnt/runtime/default/self/primary
 
     # memory control cgroup
     mkdir /dev/memcg 0700 root system
@@ -114,6 +107,10 @@
     # set fwmark on accepted sockets
     write /proc/sys/net/ipv4/tcp_fwmark_accept 1
 
+    # disable icmp redirects
+    write /proc/sys/net/ipv4/conf/all/accept_redirects 0
+    write /proc/sys/net/ipv6/conf/all/accept_redirects 0
+
     # Create cgroup mount points for process groups
     mkdir /dev/cpuctl
     mount cgroup none /dev/cpuctl cpu
@@ -132,6 +129,28 @@
     write /dev/cpuctl/bg_non_interactive/cpu.rt_runtime_us 700000
     write /dev/cpuctl/bg_non_interactive/cpu.rt_period_us 1000000
 
+    # sets up initial cpusets for ActivityManager
+    mkdir /dev/cpuset
+    mount cpuset none /dev/cpuset
+    mkdir /dev/cpuset/foreground
+    mkdir /dev/cpuset/background
+    # this ensures that the cpusets are present and usable, but the device's
+    # init.rc must actually set the correct cpus
+    write /dev/cpuset/foreground/cpus 0
+    write /dev/cpuset/background/cpus 0
+    write /dev/cpuset/foreground/mems 0
+    write /dev/cpuset/background/mems 0
+    chown system system /dev/cpuset
+    chown system system /dev/cpuset/foreground
+    chown system system /dev/cpuset/background
+    chown system system /dev/cpuset/tasks
+    chown system system /dev/cpuset/foreground/tasks
+    chown system system /dev/cpuset/background/tasks
+    chmod 0664 /dev/cpuset/foreground/tasks
+    chmod 0664 /dev/cpuset/background/tasks
+    chmod 0664 /dev/cpuset/tasks
+
+
     # qtaguid will limit access to specific data based on group memberships.
     #   net_bw_acct grants impersonation of socket owners.
     #   net_bw_stats grants access to other apps' detailed tagged-socket stats.
@@ -150,6 +169,11 @@
     mount pstore pstore /sys/fs/pstore
     chown system log /sys/fs/pstore/console-ramoops
     chmod 0440 /sys/fs/pstore/console-ramoops
+    chown system log /sys/fs/pstore/pmsg-ramoops-0
+    chmod 0440 /sys/fs/pstore/pmsg-ramoops-0
+
+    # enable armv8_deprecated instruction hooks
+    write /proc/sys/abi/swp 1
 
 # Healthd can trigger a full boot from charger mode by signaling this
 # property when the power button is held.
@@ -160,6 +184,8 @@
 # Load properties from /system/ + /factory after fs mount.
 on load_all_props_action
     load_all_props
+    start logd
+    start logd-reinit
 
 # Indicate to fw loaders that the relevant mounts are up.
 on firmware_mounts_complete
@@ -185,10 +211,13 @@
 
 
 on post-fs
+    start logd
     # once everything is setup, no need to modify /
     mount rootfs rootfs / ro remount
-    # mount shared so changes propagate into child namespaces
+    # Mount shared so changes propagate into child namespaces
     mount rootfs rootfs / shared rec
+    # Mount default storage into root namespace
+    mount none /mnt/runtime/default /storage slave bind rec
 
     # We chown/chmod /cache again so because mount is run as root + defaults
     chown system cache /cache
@@ -196,9 +225,9 @@
     # We restorecon /cache in case the cache partition has been reset.
     restorecon_recursive /cache
 
-    # This may have been created by the recovery system with odd permissions
-    chown system cache /cache/recovery
-    chmod 0770 /cache/recovery
+    # Create /cache/recovery in case it's not there. It'll also fix the odd
+    # permissions if created by the recovery system.
+    mkdir /cache/recovery 0770 system cache
 
     #change permissions on vmallocinfo so we can grab it from bugreports
     chown root log /proc/vmallocinfo
@@ -228,31 +257,32 @@
     # We restorecon /data in case the userdata partition has been reset.
     restorecon /data
 
+    # Emulated internal storage area
+    mkdir /data/media 0770 media_rw media_rw
+
+    # Make sure we have the device encryption key
+    start logd
+    start vold
+    installkey /data
+
+    # Start bootcharting as soon as possible after the data partition is
+    # mounted to collect more data.
+    mkdir /data/bootchart 0755 shell shell
+    bootchart_init
+
     # Avoid predictable entropy pool. Carry over entropy from previous boot.
     copy /data/system/entropy.dat /dev/urandom
 
-    # Create dump dir and collect dumps.
-    # Do this before we mount cache so eventually we can use cache for
-    # storing dumps on platforms which do not have a dedicated dump partition.
-    mkdir /data/dontpanic 0750 root log
-
-    # Collect apanic data, free resources and re-arm trigger
-    copy /proc/apanic_console /data/dontpanic/apanic_console
-    chown root log /data/dontpanic/apanic_console
-    chmod 0640 /data/dontpanic/apanic_console
-
-    copy /proc/apanic_threads /data/dontpanic/apanic_threads
-    chown root log /data/dontpanic/apanic_threads
-    chmod 0640 /data/dontpanic/apanic_threads
-
-    write /proc/apanic_console 1
-
     # create basic filesystem structure
     mkdir /data/misc 01771 system misc
     mkdir /data/misc/adb 02750 system shell
-    mkdir /data/misc/bluedroid 0770 bluetooth net_bt_stack
+    mkdir /data/misc/bluedroid 02770 bluetooth net_bt_stack
+    # 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
     mkdir /data/misc/keystore 0700 keystore keystore
+    mkdir /data/misc/gatekeeper 0700 system system
     mkdir /data/misc/keychain 0771 system system
     mkdir /data/misc/net 0750 root shell
     mkdir /data/misc/radio 0770 system radio
@@ -267,10 +297,12 @@
     mkdir /data/misc/ethernet 0770 system system
     mkdir /data/misc/dhcp 0770 dhcp dhcp
     mkdir /data/misc/user 0771 root root
+    mkdir /data/misc/perfprofd 0775 root root
     # give system access to wpa_supplicant.conf for backup and restore
     chmod 0660 /data/misc/wifi/wpa_supplicant.conf
     mkdir /data/local 0751 root root
     mkdir /data/misc/media 0700 media media
+    mkdir /data/misc/vold 0700 root root
 
     # For security reasons, /data/local/tmp should always be empty.
     # Do not place files or directories in /data/local/tmp
@@ -311,12 +343,24 @@
     # 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
+    mkdir /data/media 0770 media_rw media_rw
+    mkdir /data/ss 0700 system system
+    mkdir /data/system 0775 system system
+    mkdir /data/system/heapdump 0700 system system
+    mkdir /data/user 0711 system system
+
     # Reload policy from /data/security if present.
     setprop selinux.reload_policy 1
 
     # Set SELinux security contexts on upgrade or policy update.
     restorecon_recursive /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
+
     # If there is no fs-post-data action in the init.<device>.rc file, you
     # must uncomment this line, otherwise encrypted filesystems
     # won't work.
@@ -338,9 +382,9 @@
     write /proc/sys/vm/overcommit_memory 1
     write /proc/sys/vm/min_free_order_shift 4
     chown root system /sys/module/lowmemorykiller/parameters/adj
-    chmod 0220 /sys/module/lowmemorykiller/parameters/adj
+    chmod 0664 /sys/module/lowmemorykiller/parameters/adj
     chown root system /sys/module/lowmemorykiller/parameters/minfree
-    chmod 0220 /sys/module/lowmemorykiller/parameters/minfree
+    chmod 0664 /sys/module/lowmemorykiller/parameters/minfree
 
     # Tweak background writeout
     write /proc/sys/vm/dirty_expire_centisecs 200
@@ -437,6 +481,8 @@
 
 on property:vold.decrypt=trigger_load_persist_props
     load_persist_props
+    start logd
+    start logd-reinit
 
 on property:vold.decrypt=trigger_post_fs_data
     trigger post-fs-data
@@ -465,6 +511,11 @@
 on property:sys.sysctl.tcp_def_init_rwnd=*
     write /proc/sys/net/ipv4/tcp_default_init_rwnd ${sys.sysctl.tcp_def_init_rwnd}
 
+on property:security.perf_harden=0
+    write /proc/sys/kernel/perf_event_paranoid 1
+
+on property:security.perf_harden=1
+    write /proc/sys/kernel/perf_event_paranoid 3
 
 ## Daemon processes to be run by init.
 ##
@@ -478,12 +529,17 @@
     socket logd stream 0666 logd logd
     socket logdr seqpacket 0666 logd logd
     socket logdw dgram 0222 logd logd
-    seclabel u:r:logd:s0
+    group root system
+
+service logd-reinit /system/bin/logd --reinit
+    oneshot
+    disabled
 
 service healthd /sbin/healthd
     class core
     critical
     seclabel u:r:healthd:s0
+    group root system
 
 service console /system/bin/sh
     class core
@@ -523,9 +579,12 @@
     onrestart restart surfaceflinger
     onrestart restart drm
 
-service vold /system/bin/vold
+service vold /system/bin/vold \
+        --blkid_context=u:r:blkid:s0 --blkid_untrusted_context=u:r:blkid_untrusted:s0 \
+        --fsck_context=u:r:fsck:s0 --fsck_untrusted_context=u:r:fsck_untrusted:s0
     class core
     socket vold stream 0660 root mount
+    socket cryptd stream 0660 root mount
     ioprio be 2
 
 service netd /system/bin/netd
@@ -544,6 +603,7 @@
 service ril-daemon /system/bin/rild
     class main
     socket rild stream 660 root radio
+    socket sap_uim_socket1 stream 660 bluetooth bluetooth
     socket rild-debug stream 660 radio system
     user root
     group radio cache inet misc audio log
@@ -586,13 +646,16 @@
     disabled
     oneshot
 
+service gatekeeperd /system/bin/gatekeeperd /data/misc/gatekeeper
+    class late_start
+    user system
+
 service installd /system/bin/installd
     class main
     socket installd stream 600 system system
 
 service flash_recovery /system/bin/install-recovery.sh
     class main
-    seclabel u:r:install_recovery:s0
     oneshot
 
 service racoon /system/bin/racoon
@@ -630,7 +693,31 @@
     disabled
     oneshot
 
-service pre-recovery /system/bin/uncrypt
+service uncrypt /system/bin/uncrypt
     class main
     disabled
     oneshot
+
+service pre-recovery /system/bin/uncrypt --reboot
+    class main
+    disabled
+    oneshot
+
+service perfprofd /system/xbin/perfprofd
+    class late_start
+    user root
+    oneshot
+
+on property:persist.logd.logpersistd=logcatd
+    # all exec/services are called with umask(077), so no gain beyond 0700
+    mkdir /data/misc/logd 0700 logd log
+    # logd for write to /data/misc/logd, log group for read from pstore (-L)
+    exec - logd log -- /system/bin/logcat -L -b all -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 64 -n 256
+    start logcatd
+
+service logcatd /system/bin/logcat -b all -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 64 -n 256
+    class late_start
+    disabled
+    # logd for write to /data/misc/logd, log group for read from log daemon
+    user logd
+    group log
diff --git a/rootdir/init.trace.rc b/rootdir/init.trace.rc
index cd8d350..50944e6 100644
--- a/rootdir/init.trace.rc
+++ b/rootdir/init.trace.rc
@@ -1,6 +1,6 @@
 ## Permissions to allow system-wide tracing to the kernel trace buffer.
 ##
-on early-boot
+on boot
 
 # Allow writing to the kernel trace log.
     chmod 0222 /sys/kernel/debug/tracing/trace_marker
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 474f630..b735dc3 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -16,6 +16,7 @@
 # Anyone can read the logs, but if they're not in the "logs"
 # group, then they'll only see log entries for their UID.
 /dev/log/*                0666   root       log
+/dev/pmsg0                0222   root       log
 
 # the msm hw3d client device node is world writable/readable.
 /dev/msm_hw3dc            0666   root       root
@@ -94,3 +95,6 @@
 /sys/devices/virtual/usb_composite/*   enable      0664  root   system
 /sys/devices/system/cpu/cpu*   cpufreq/scaling_max_freq   0664  system system
 /sys/devices/system/cpu/cpu*   cpufreq/scaling_min_freq   0664  system system
+
+# DVB API device nodes
+/dev/dvb*                 0660   root       system
diff --git a/run-as/package.c b/run-as/package.c
index 4f8f3a7..aea89e5 100644
--- a/run-as/package.c
+++ b/run-as/package.c
@@ -16,9 +16,12 @@
 */
 #include <errno.h>
 #include <fcntl.h>
-#include <unistd.h>
-#include <sys/stat.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"
 
@@ -419,7 +422,7 @@
  * If the package database is corrupted, return -1 and set errno to EINVAL
  */
 int
-get_package_info(const char* pkgName, PackageInfo *info)
+get_package_info(const char* pkgName, uid_t userId, PackageInfo *info)
 {
     char*        buffer;
     size_t       buffer_len;
@@ -504,7 +507,20 @@
         if (q == p)
             goto BAD_FORMAT;
 
-        p = string_copy(info->dataDir, sizeof info->dataDir, p, q - p);
+        /* 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)
diff --git a/run-as/package.h b/run-as/package.h
index 34603c0..eeb5913 100644
--- a/run-as/package.h
+++ b/run-as/package.h
@@ -33,9 +33,11 @@
     char   seinfo[PATH_MAX];
 } PackageInfo;
 
-/* see documentation in package.c for these functiosn */
+/* see documentation in package.c for these functions */
 
-extern int  get_package_info(const char* packageName, PackageInfo*  info);
+extern int  get_package_info(const char* packageName,
+                             uid_t userId,
+                             PackageInfo*  info);
 
 extern int  check_data_path(const char* dataDir, uid_t uid);
 
diff --git a/run-as/run-as.c b/run-as/run-as.c
index cc05e63..3f32e7d 100644
--- a/run-as/run-as.c
+++ b/run-as/run-as.c
@@ -15,22 +15,25 @@
 ** limitations under the License.
 */
 
-#define PROGNAME  "run-as"
-#define LOG_TAG   PROGNAME
+#define PROGNAME "run-as"
+#define LOG_TAG  PROGNAME
 
+#include <dirent.h>
+#include <errno.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/types.h>
+#include <sys/capability.h>
+#include <sys/cdefs.h>
 #include <sys/stat.h>
-#include <dirent.h>
-#include <errno.h>
-#include <unistd.h>
+#include <sys/types.h>
 #include <time.h>
-#include <stdarg.h>
+#include <unistd.h>
 
-#include <selinux/android.h>
 #include <private/android_filesystem_config.h>
+#include <selinux/android.h>
+
 #include "package.h"
 
 /*
@@ -83,37 +86,38 @@
  *  - Run the 'gdbserver' binary executable to allow native debugging
  */
 
-static void
-usage(void)
-{
-    const char*  str = "Usage: " PROGNAME " <package-name> <command> [<args>]\n\n";
-    write(1, str, strlen(str));
-    exit(1);
-}
-
-
-static void
+__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(1);
+    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;
-    int myuid, uid, gid;
+    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)
+    if (argc < 2) {
         usage();
+    }
 
     /* check userid of caller - must be 'shell' or 'root' */
     myuid = getuid();
@@ -121,69 +125,87 @@
         panic("only 'shell' or 'root' users can run this program\n");
     }
 
-    /* retrieve package information from system */
-    pkgname = argv[1];
-    if (get_package_info(pkgname, &info) < 0) {
-        panic("Package '%s' is unknown\n", pkgname);
-        return 1;
+    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 (info.uid < AID_APP) {
+    if (userAppId < AID_APP) {
         panic("Package '%s' is not an application\n", pkgname);
-        return 1;
     }
 
     /* reject any non-debuggable package */
     if (!info.isDebuggable) {
         panic("Package '%s' is not debuggable\n", pkgname);
-        return 1;
     }
 
     /* check that the data directory path is valid */
-    if (check_data_path(info.dataDir, info.uid) < 0) {
+    if (check_data_path(info.dataDir, userAppId) < 0) {
         panic("Package '%s' has corrupt installation\n", pkgname);
-        return 1;
     }
 
     /* Ensure that we change all real/effective/saved IDs at the
      * same time to avoid nasty surprises.
      */
-    uid = gid = info.uid;
+    uid = gid = userAppId;
     if(setresgid(gid,gid,gid) || setresuid(uid,uid,uid)) {
         panic("Permission denied\n");
-        return 1;
+    }
+
+    /* 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));
-        return 1;
+        panic("Could not set SELinux security context: %s\n", strerror(errno));
     }
 
     /* cd into the data directory */
-    {
-        int ret;
-        do {
-            ret = chdir(info.dataDir);
-        } while (ret < 0 && errno == EINTR);
-
-        if (ret < 0) {
-            panic("Could not cd to package's data directory: %s\n", strerror(errno));
-            return 1;
-        }
+    if (TEMP_FAILURE_RETRY(chdir(info.dataDir)) < 0) {
+        panic("Could not cd to package's data directory: %s\n", strerror(errno));
     }
 
     /* User specified command for exec. */
-    if (argc >= 3 ) {
-        if (execvp(argv[2], argv+2) < 0) {
-            panic("exec failed for %s Error:%s\n", argv[2], strerror(errno));
-            return -errno;
-        }
+    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\n");
-    return 1;
+    panic("exec failed: %s\n", strerror(errno));
 }
diff --git a/sdcard/Android.mk b/sdcard/Android.mk
index 63b0f41..cb3a8fb 100644
--- a/sdcard/Android.mk
+++ b/sdcard/Android.mk
@@ -6,6 +6,6 @@
 LOCAL_MODULE := sdcard
 LOCAL_CFLAGS := -Wall -Wno-unused-parameter -Werror
 
-LOCAL_SHARED_LIBRARIES := libc libcutils
+LOCAL_SHARED_LIBRARIES := libcutils
 
 include $(BUILD_EXECUTABLE)
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 613dcbb..f6ae8c2 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -29,6 +29,7 @@
 #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>
@@ -73,22 +74,6 @@
  * requiring any additional GIDs.
  * - Separate permissions for protecting directories like Pictures and Music.
  * - Multi-user separation on the same physical device.
- *
- * The derived permissions look like this:
- *
- * rwxrwx--x root:sdcard_rw     /
- * rwxrwx--- root:sdcard_pics   /Pictures
- * rwxrwx--- root:sdcard_av     /Music
- *
- * rwxrwx--x root:sdcard_rw     /Android
- * rwxrwx--x root:sdcard_rw     /Android/data
- * rwxrwx--- u0_a12:sdcard_rw   /Android/data/com.example
- * rwxrwx--x root:sdcard_rw     /Android/obb/
- * rwxrwx--- u0_a12:sdcard_rw   /Android/obb/com.example
- *
- * rwxrwx--- root:sdcard_all    /Android/user
- * rwxrwx--x root:sdcard_rw     /Android/user/10
- * rwxrwx--- u10_a12:sdcard_rw  /Android/user/10/Android/data/com.example
  */
 
 #define FUSE_TRACE 0
@@ -114,9 +99,6 @@
  * the largest possible data payload. */
 #define MAX_REQUEST_SIZE (sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in) + MAX_WRITE)
 
-/* Default number of threads. */
-#define DEFAULT_NUM_THREADS 2
-
 /* Pseudo-error constant used to indicate that no fuse status is needed
  * or that a reply has already been written. */
 #define NO_STATUS 1
@@ -134,7 +116,7 @@
     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_LEGACY_PRE_ROOT,
+    PERM_PRE_ROOT,
     /* This node is "/" */
     PERM_ROOT,
     /* This node is "/Android" */
@@ -145,17 +127,8 @@
     PERM_ANDROID_OBB,
     /* This node is "/Android/media" */
     PERM_ANDROID_MEDIA,
-    /* This node is "/Android/user" */
-    PERM_ANDROID_USER,
 } perm_t;
 
-/* Permissions structure to derive */
-typedef enum {
-    DERIVE_NONE,
-    DERIVE_LEGACY,
-    DERIVE_UNIFIED,
-} derive_t;
-
 struct handle {
     int fd;
 };
@@ -178,8 +151,7 @@
     perm_t perm;
     userid_t userid;
     uid_t uid;
-    gid_t gid;
-    mode_t mode;
+    bool under_android;
 
     struct node *next;          /* per-dir sibling list */
     struct node *child;         /* first contained file by this dir */
@@ -198,6 +170,8 @@
      * position. Used to support things like OBB. */
     char* graft_path;
     size_t graft_pathlen;
+
+    bool deleted;
 };
 
 static int str_hash(void *key) {
@@ -209,25 +183,21 @@
     return strcasecmp(keyA, keyB) == 0;
 }
 
-static int int_hash(void *key) {
-    return (int) (uintptr_t) key;
-}
-
-static bool int_equals(void *keyA, void *keyB) {
-    return keyA == keyB;
-}
-
-/* Global data structure shared by all fuse handlers. */
-struct fuse {
+/* 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;
-    int fd;
-    derive_t derive;
-    bool split_perms;
-    gid_t write_gid;
     struct node root;
-    char obbpath[PATH_MAX];
 
     /* Used to allocate unique inode numbers for fuse nodes. We use
      * a simple counter based scheme where inode numbers from deleted
@@ -248,11 +218,24 @@
      */
     __u32 inode_ctr;
 
-    Hashmap* package_to_appid;
-    Hashmap* appid_with_rw;
+    struct fuse* fuse_default;
+    struct fuse* fuse_read;
+    struct fuse* fuse_write;
 };
 
-/* Private data used by a single fuse handler. */
+/* 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;
@@ -409,27 +392,50 @@
     return actual;
 }
 
-static void attr_from_stat(struct fuse_attr *attr, const struct stat *s, const struct node* node)
-{
+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_atime;
-    attr->mtime = s->st_mtime;
-    attr->ctime = s->st_ctime;
-    attr->atimensec = s->st_atime_nsec;
-    attr->mtimensec = s->st_mtime_nsec;
-    attr->ctimensec = s->st_ctime_nsec;
+    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;
-    attr->gid = node->gid;
 
-    /* Filter requested mode based on underlying file, and
-     * pass through file type. */
+    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 = node->mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6));
+    int filtered_mode = visible_mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6));
     attr->mode = (attr->mode & S_IFMT) | filtered_mode;
 }
 
@@ -455,105 +461,58 @@
     node->perm = PERM_INHERIT;
     node->userid = parent->userid;
     node->uid = parent->uid;
-    node->gid = parent->gid;
-    node->mode = parent->mode;
-
-    if (fuse->derive == DERIVE_NONE) {
-        return;
-    }
+    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_LEGACY_PRE_ROOT:
+    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. */
-        node->mode = 0770;
         if (!strcasecmp(node->name, "Android")) {
             /* App-specific directories inside; let anyone traverse */
             node->perm = PERM_ANDROID;
-            node->mode = 0771;
-        } else if (fuse->split_perms) {
-            if (!strcasecmp(node->name, "DCIM")
-                    || !strcasecmp(node->name, "Pictures")) {
-                node->gid = AID_SDCARD_PICS;
-            } else if (!strcasecmp(node->name, "Alarms")
-                    || !strcasecmp(node->name, "Movies")
-                    || !strcasecmp(node->name, "Music")
-                    || !strcasecmp(node->name, "Notifications")
-                    || !strcasecmp(node->name, "Podcasts")
-                    || !strcasecmp(node->name, "Ringtones")) {
-                node->gid = AID_SDCARD_AV;
-            }
+            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;
-            node->mode = 0771;
         } else if (!strcasecmp(node->name, "obb")) {
             /* App-specific directories inside; let anyone traverse */
             node->perm = PERM_ANDROID_OBB;
-            node->mode = 0771;
             /* Single OBB directory is always shared */
-            node->graft_path = fuse->obbpath;
-            node->graft_pathlen = strlen(fuse->obbpath);
+            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;
-            node->mode = 0771;
-        } else if (!strcasecmp(node->name, "user")) {
-            /* User directories must only be accessible to system, protected
-             * by sdcard_all. Zygote will bind mount the appropriate user-
-             * specific path. */
-            node->perm = PERM_ANDROID_USER;
-            node->gid = AID_SDCARD_ALL;
-            node->mode = 0770;
         }
         break;
     case PERM_ANDROID_DATA:
     case PERM_ANDROID_OBB:
     case PERM_ANDROID_MEDIA:
-        appid = (appid_t) (uintptr_t) hashmapGet(fuse->package_to_appid, node->name);
+        appid = (appid_t) (uintptr_t) hashmapGet(fuse->global->package_to_appid, node->name);
         if (appid != 0) {
             node->uid = multiuser_get_uid(parent->userid, appid);
         }
-        node->mode = 0770;
-        break;
-    case PERM_ANDROID_USER:
-        /* Root of a secondary user */
-        node->perm = PERM_ROOT;
-        node->userid = strtoul(node->name, NULL, 10);
-        node->gid = AID_SDCARD_R;
-        node->mode = 0771;
         break;
     }
 }
 
-/* Return if the calling UID holds sdcard_rw. */
-static bool get_caller_has_rw_locked(struct fuse* fuse, const struct fuse_in_header *hdr) {
-    /* No additional permissions enforcement */
-    if (fuse->derive == DERIVE_NONE) {
-        return true;
-    }
-
-    appid_t appid = multiuser_get_app_id(hdr->uid);
-    return hashmapContainsKey(fuse->appid_with_rw, (void*) (uintptr_t) appid);
-}
-
 /* 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, bool has_rw) {
+        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")
@@ -563,34 +522,19 @@
         }
     }
 
-    /* No additional permissions enforcement */
-    if (fuse->derive == DERIVE_NONE) {
-        return true;
-    }
-
     /* Root always has access; access for any other UIDs should always
      * be controlled through packages.list. */
     if (hdr->uid == 0) {
         return true;
     }
 
-    /* If asking to write, verify that caller either owns the
-     * parent or holds sdcard_rw. */
-    if (mode & W_OK) {
-        if (parent_node && hdr->uid == parent_node->uid) {
-            return true;
-        }
-
-        return has_rw;
-    }
-
     /* 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, bool has_rw) {
-    return check_caller_access_to_name(fuse, hdr, node->parent, node->name, mode, has_rw);
+        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,
@@ -601,7 +545,7 @@
 
     // Detect overflows in the inode counter. "4 billion nodes should be enough
     // for everybody".
-    if (fuse->inode_ctr == 0) {
+    if (fuse->global->inode_ctr == 0) {
         ERROR("No more inode numbers available");
         return NULL;
     }
@@ -627,8 +571,10 @@
     }
     node->namelen = namelen;
     node->nid = ptr_to_id(node);
-    node->ino = fuse->inode_ctr++;
-    node->gen = fuse->next_generation++;
+    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);
@@ -680,7 +626,7 @@
 static struct node *lookup_node_by_id_locked(struct fuse *fuse, __u64 nid)
 {
     if (nid == FUSE_ROOT_ID) {
-        return &fuse->root;
+        return &fuse->global->root;
     } else {
         return id_to_ptr(nid);
     }
@@ -703,7 +649,7 @@
          * 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)) {
+        if (!strcmp(name, node->name) && !node->deleted) {
             return node;
         }
     }
@@ -723,59 +669,6 @@
     return child;
 }
 
-static void fuse_init(struct fuse *fuse, int fd, const char *source_path,
-        gid_t write_gid, derive_t derive, bool split_perms) {
-    pthread_mutex_init(&fuse->lock, NULL);
-
-    fuse->fd = fd;
-    fuse->next_generation = 0;
-    fuse->derive = derive;
-    fuse->split_perms = split_perms;
-    fuse->write_gid = write_gid;
-    fuse->inode_ctr = 1;
-
-    memset(&fuse->root, 0, sizeof(fuse->root));
-    fuse->root.nid = FUSE_ROOT_ID; /* 1 */
-    fuse->root.refcount = 2;
-    fuse->root.namelen = strlen(source_path);
-    fuse->root.name = strdup(source_path);
-    fuse->root.userid = 0;
-    fuse->root.uid = AID_ROOT;
-
-    /* Set up root node for various modes of operation */
-    switch (derive) {
-    case DERIVE_NONE:
-        /* Traditional behavior that treats entire device as being accessible
-         * to sdcard_rw, and no permissions are derived. */
-        fuse->root.perm = PERM_ROOT;
-        fuse->root.mode = 0775;
-        fuse->root.gid = AID_SDCARD_RW;
-        break;
-    case DERIVE_LEGACY:
-        /* Legacy behavior used to support internal multiuser layout which
-         * places user_id at the top directory level, with the actual roots
-         * just below that. Shared OBB path is also at top level. */
-        fuse->root.perm = PERM_LEGACY_PRE_ROOT;
-        fuse->root.mode = 0771;
-        fuse->root.gid = AID_SDCARD_R;
-        fuse->package_to_appid = hashmapCreate(256, str_hash, str_icase_equals);
-        fuse->appid_with_rw = hashmapCreate(128, int_hash, int_equals);
-        snprintf(fuse->obbpath, sizeof(fuse->obbpath), "%s/obb", source_path);
-        fs_prepare_dir(fuse->obbpath, 0775, getuid(), getgid());
-        break;
-    case DERIVE_UNIFIED:
-        /* Unified multiuser layout which places secondary user_id under
-         * /Android/user and shared OBB path under /Android/obb. */
-        fuse->root.perm = PERM_ROOT;
-        fuse->root.mode = 0771;
-        fuse->root.gid = AID_SDCARD_R;
-        fuse->package_to_appid = hashmapCreate(256, str_hash, str_icase_equals);
-        fuse->appid_with_rw = hashmapCreate(128, int_hash, int_equals);
-        snprintf(fuse->obbpath, sizeof(fuse->obbpath), "%s/Android/obb", source_path);
-        break;
-    }
-}
-
 static void fuse_status(struct fuse *fuse, __u64 unique, int err)
 {
     struct fuse_out_header hdr;
@@ -818,19 +711,19 @@
         return -errno;
     }
 
-    pthread_mutex_lock(&fuse->lock);
+    pthread_mutex_lock(&fuse->global->lock);
     node = acquire_or_create_child_locked(fuse, parent, name, actual_name);
     if (!node) {
-        pthread_mutex_unlock(&fuse->lock);
+        pthread_mutex_unlock(&fuse->global->lock);
         return -ENOMEM;
     }
     memset(&out, 0, sizeof(out));
-    attr_from_stat(&out.attr, &s, node);
+    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->lock);
+    pthread_mutex_unlock(&fuse->global->lock);
     fuse_reply(fuse, unique, &out, sizeof(out));
     return NO_STATUS;
 }
@@ -845,12 +738,43 @@
         return -errno;
     }
     memset(&out, 0, sizeof(out));
-    attr_from_stat(&out.attr, &s, node);
+    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)
 {
@@ -859,18 +783,18 @@
     char child_path[PATH_MAX];
     const char* actual_name;
 
-    pthread_mutex_lock(&fuse->lock);
+    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->lock);
+    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, false)) {
+    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, R_OK)) {
         return -EACCES;
     }
 
@@ -882,7 +806,7 @@
 {
     struct node* node;
 
-    pthread_mutex_lock(&fuse->lock);
+    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 : "?");
@@ -892,7 +816,7 @@
             release_node_locked(node);
         }
     }
-    pthread_mutex_unlock(&fuse->lock);
+    pthread_mutex_unlock(&fuse->global->lock);
     return NO_STATUS; /* no reply */
 }
 
@@ -902,16 +826,16 @@
     struct node* node;
     char path[PATH_MAX];
 
-    pthread_mutex_lock(&fuse->lock);
+    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->lock);
+    pthread_mutex_unlock(&fuse->global->lock);
 
     if (!node) {
         return -ENOENT;
     }
-    if (!check_caller_access_to_node(fuse, hdr, node, R_OK, false)) {
+    if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
         return -EACCES;
     }
 
@@ -921,22 +845,22 @@
 static int handle_setattr(struct fuse* fuse, struct fuse_handler* handler,
         const struct fuse_in_header *hdr, const struct fuse_setattr_in *req)
 {
-    bool has_rw;
     struct node* node;
     char path[PATH_MAX];
     struct timespec times[2];
 
-    pthread_mutex_lock(&fuse->lock);
-    has_rw = get_caller_has_rw_locked(fuse, hdr);
+    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->lock);
+    pthread_mutex_unlock(&fuse->global->lock);
 
     if (!node) {
         return -ENOENT;
     }
-    if (!check_caller_access_to_node(fuse, hdr, node, W_OK, has_rw)) {
+
+    if (!(req->valid & FATTR_FH) &&
+            !check_caller_access_to_node(fuse, hdr, node, W_OK)) {
         return -EACCES;
     }
 
@@ -984,25 +908,23 @@
 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)
 {
-    bool has_rw;
     struct node* parent_node;
     char parent_path[PATH_MAX];
     char child_path[PATH_MAX];
     const char* actual_name;
 
-    pthread_mutex_lock(&fuse->lock);
-    has_rw = get_caller_has_rw_locked(fuse, hdr);
+    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->lock);
+    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, has_rw)) {
+    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
         return -EACCES;
     }
     __u32 mode = (req->mode & (~0777)) | 0664;
@@ -1015,25 +937,23 @@
 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)
 {
-    bool has_rw;
     struct node* parent_node;
     char parent_path[PATH_MAX];
     char child_path[PATH_MAX];
     const char* actual_name;
 
-    pthread_mutex_lock(&fuse->lock);
-    has_rw = get_caller_has_rw_locked(fuse, hdr);
+    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->lock);
+    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, has_rw)) {
+    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
         return -EACCES;
     }
     __u32 mode = (req->mode & (~0777)) | 0775;
@@ -1052,7 +972,7 @@
     }
     if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "obb")) {
         char nomedia[PATH_MAX];
-        snprintf(nomedia, PATH_MAX, "%s/.nomedia", fuse->obbpath);
+        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;
@@ -1065,58 +985,96 @@
 static int handle_unlink(struct fuse* fuse, struct fuse_handler* handler,
         const struct fuse_in_header* hdr, const char* name)
 {
-    bool has_rw;
     struct node* parent_node;
+    struct node* child_node;
     char parent_path[PATH_MAX];
     char child_path[PATH_MAX];
 
-    pthread_mutex_lock(&fuse->lock);
-    has_rw = get_caller_has_rw_locked(fuse, hdr);
+    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->lock);
+    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, has_rw)) {
+    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)
 {
-    bool has_rw;
+    struct node* child_node;
     struct node* parent_node;
     char parent_path[PATH_MAX];
     char child_path[PATH_MAX];
 
-    pthread_mutex_lock(&fuse->lock);
-    has_rw = get_caller_has_rw_locked(fuse, hdr);
+    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->lock);
+    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, has_rw)) {
+    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;
 }
 
@@ -1124,7 +1082,6 @@
         const struct fuse_in_header* hdr, const struct fuse_rename_in* req,
         const char* old_name, const char* new_name)
 {
-    bool has_rw;
     struct node* old_parent_node;
     struct node* new_parent_node;
     struct node* child_node;
@@ -1135,8 +1092,7 @@
     const char* new_actual_name;
     int res;
 
-    pthread_mutex_lock(&fuse->lock);
-    has_rw = get_caller_has_rw_locked(fuse, hdr);
+    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,
@@ -1149,11 +1105,11 @@
         res = -ENOENT;
         goto lookup_error;
     }
-    if (!check_caller_access_to_name(fuse, hdr, old_parent_node, old_name, W_OK, has_rw)) {
+    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, has_rw)) {
+    if (!check_caller_access_to_name(fuse, hdr, new_parent_node, new_name, W_OK)) {
         res = -EACCES;
         goto lookup_error;
     }
@@ -1164,7 +1120,7 @@
         goto lookup_error;
     }
     acquire_node_locked(child_node);
-    pthread_mutex_unlock(&fuse->lock);
+    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
@@ -1185,7 +1141,7 @@
         goto io_error;
     }
 
-    pthread_mutex_lock(&fuse->lock);
+    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);
@@ -1194,11 +1150,11 @@
     goto done;
 
 io_error:
-    pthread_mutex_lock(&fuse->lock);
+    pthread_mutex_lock(&fuse->global->lock);
 done:
     release_node_locked(child_node);
 lookup_error:
-    pthread_mutex_unlock(&fuse->lock);
+    pthread_mutex_unlock(&fuse->global->lock);
     return res;
 }
 
@@ -1216,24 +1172,22 @@
 static int handle_open(struct fuse* fuse, struct fuse_handler* handler,
         const struct fuse_in_header* hdr, const struct fuse_open_in* req)
 {
-    bool has_rw;
     struct node* node;
     char path[PATH_MAX];
     struct fuse_open_out out;
     struct handle *h;
 
-    pthread_mutex_lock(&fuse->lock);
-    has_rw = get_caller_has_rw_locked(fuse, hdr);
+    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->lock);
+    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), has_rw)) {
+            open_flags_to_access_mode(req->flags))) {
         return -EACCES;
     }
     h = malloc(sizeof(*h));
@@ -1301,6 +1255,7 @@
         return -errno;
     }
     out.size = res;
+    out.padding = 0;
     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
     return NO_STATUS;
 }
@@ -1313,14 +1268,14 @@
     struct fuse_statfs_out out;
     int res;
 
-    pthread_mutex_lock(&fuse->lock);
+    pthread_mutex_lock(&fuse->global->lock);
     TRACE("[%d] STATFS\n", handler->token);
-    res = get_node_path_locked(&fuse->root, path, sizeof(path));
-    pthread_mutex_unlock(&fuse->lock);
+    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->root.name, &stat) < 0) {
+    if (statfs(fuse->global->root.name, &stat) < 0) {
         return -errno;
     }
     memset(&out, 0, sizeof(out));
@@ -1387,16 +1342,16 @@
     struct fuse_open_out out;
     struct dirhandle *h;
 
-    pthread_mutex_lock(&fuse->lock);
+    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->lock);
+    pthread_mutex_unlock(&fuse->global->lock);
 
     if (!node) {
         return -ENOENT;
     }
-    if (!check_caller_access_to_node(fuse, hdr, node, R_OK, false)) {
+    if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
         return -EACCES;
     }
     h = malloc(sizeof(*h));
@@ -1460,17 +1415,43 @@
         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.minor = FUSE_KERNEL_MINOR_VERSION;
     out.max_readahead = req->max_readahead;
     out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
     out.max_background = 32;
     out.congestion_threshold = 32;
     out.max_write = MAX_WRITE;
-    fuse_reply(fuse, hdr->unique, &out, sizeof(out));
+    fuse_reply(fuse, hdr->unique, &out, fuse_struct_size);
     return NO_STATUS;
 }
 
@@ -1601,12 +1582,14 @@
 {
     struct fuse* fuse = handler->fuse;
     for (;;) {
-        ssize_t len = read(fuse->fd,
-                handler->request_buffer, sizeof(handler->request_buffer));
+        ssize_t len = TEMP_FAILURE_RETRY(read(fuse->fd,
+                handler->request_buffer, sizeof(handler->request_buffer)));
         if (len < 0) {
-            if (errno != EINTR) {
-                ERROR("[%d] handle_fuse_requests: errno=%d\n", handler->token, errno);
+            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;
         }
 
@@ -1653,22 +1636,15 @@
     return true;
 }
 
-static bool remove_int_to_null(void *key, void *value, void *context) {
-    Hashmap* map = context;
-    hashmapRemove(map, key);
-    return true;
-}
+static int read_package_list(struct fuse_global* global) {
+    pthread_mutex_lock(&global->lock);
 
-static int read_package_list(struct fuse *fuse) {
-    pthread_mutex_lock(&fuse->lock);
-
-    hashmapForEach(fuse->package_to_appid, remove_str_to_int, fuse->package_to_appid);
-    hashmapForEach(fuse->appid_with_rw, remove_int_to_null, fuse->appid_with_rw);
+    hashmapForEach(global->package_to_appid, remove_str_to_int, global->package_to_appid);
 
     FILE* file = fopen(kPackagesListFile, "r");
     if (!file) {
         ERROR("failed to open package list: %s\n", strerror(errno));
-        pthread_mutex_unlock(&fuse->lock);
+        pthread_mutex_unlock(&global->lock);
         return -1;
     }
 
@@ -1680,28 +1656,18 @@
 
         if (sscanf(buf, "%s %d %*d %*s %*s %s", package_name, &appid, gids) == 3) {
             char* package_name_dup = strdup(package_name);
-            hashmapPut(fuse->package_to_appid, package_name_dup, (void*) (uintptr_t) appid);
-
-            char* token = strtok(gids, ",");
-            while (token != NULL) {
-                if (strtoul(token, NULL, 10) == fuse->write_gid) {
-                    hashmapPut(fuse->appid_with_rw, (void*) (uintptr_t) appid, (void*) (uintptr_t) 1);
-                    break;
-                }
-                token = strtok(NULL, ",");
-            }
+            hashmapPut(global->package_to_appid, package_name_dup, (void*) (uintptr_t) appid);
         }
     }
 
-    TRACE("read_package_list: found %zu packages, %zu with write_gid\n",
-            hashmapSize(fuse->package_to_appid),
-            hashmapSize(fuse->appid_with_rw));
+    TRACE("read_package_list: found %zu packages\n",
+            hashmapSize(global->package_to_appid));
     fclose(file);
-    pthread_mutex_unlock(&fuse->lock);
+    pthread_mutex_unlock(&global->lock);
     return 0;
 }
 
-static void watch_package_list(struct fuse* fuse) {
+static void watch_package_list(struct fuse_global* global) {
     struct inotify_event *event;
     char event_buf[512];
 
@@ -1729,7 +1695,7 @@
 
             /* Watch above will tell us about any future changes, so
              * read the current state. */
-            if (read_package_list(fuse) == -1) {
+            if (read_package_list(global) == -1) {
                 ERROR("read_package_list failed: %s\n", strerror(errno));
                 return;
             }
@@ -1763,137 +1729,178 @@
     }
 }
 
-static int ignite_fuse(struct fuse* fuse, int num_threads)
-{
-    struct fuse_handler* handlers;
-    int i;
-
-    handlers = malloc(num_threads * sizeof(struct fuse_handler));
-    if (!handlers) {
-        ERROR("cannot allocate storage for threads\n");
-        return -ENOMEM;
-    }
-
-    for (i = 0; i < num_threads; i++) {
-        handlers[i].fuse = fuse;
-        handlers[i].token = i;
-    }
-
-    /* When deriving permissions, this thread is used to process inotify events,
-     * otherwise it becomes one of the FUSE handlers. */
-    i = (fuse->derive == DERIVE_NONE) ? 1 : 0;
-    for (; i < num_threads; i++) {
-        pthread_t thread;
-        int res = pthread_create(&thread, NULL, start_handler, &handlers[i]);
-        if (res) {
-            ERROR("failed to start thread #%d, error=%d\n", i, res);
-            goto quit;
-        }
-    }
-
-    if (fuse->derive == DERIVE_NONE) {
-        handle_fuse_requests(&handlers[0]);
-    } else {
-        watch_package_list(fuse);
-    }
-
-    ERROR("terminated prematurely\n");
-
-    /* don't bother killing all of the other threads or freeing anything,
-     * should never get here anyhow */
-quit:
-    exit(1);
-}
-
-static int usage()
-{
-    ERROR("usage: sdcard [OPTIONS] <source_path> <dest_path>\n"
+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"
-            "    -w: specify GID required to write (default sdcard_rw, requires -d or -l)\n"
-            "    -t: specify number of threads to use (default %d)\n"
-            "    -d: derive file permissions based on path\n"
-            "    -l: derive file permissions based on legacy internal layout\n"
-            "    -s: split derived permissions for pics, av\n"
-            "\n", DEFAULT_NUM_THREADS);
+            "    -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 run(const char* source_path, const char* dest_path, uid_t uid,
-        gid_t gid, gid_t write_gid, int num_threads, derive_t derive,
-        bool split_perms) {
-    int fd;
+static int fuse_setup(struct fuse* fuse, gid_t gid, mode_t mask) {
     char opts[256];
-    int res;
-    struct fuse fuse;
 
-    /* cleanup from previous instance, if necessary */
-    umount2(dest_path, 2);
-
-    fd = open("/dev/fuse", O_RDWR);
-    if (fd < 0){
-        ERROR("cannot open fuse device: %s\n", strerror(errno));
+    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",
-            fd, uid, gid);
-
-    res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC, opts);
-    if (res < 0) {
-        ERROR("cannot mount fuse filesystem: %s\n", strerror(errno));
-        goto error;
+            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;
     }
 
-    res = setgroups(sizeof(kGroups) / sizeof(kGroups[0]), kGroups);
-    if (res < 0) {
-        ERROR("cannot setgroups: %s\n", strerror(errno));
-        goto error;
-    }
+    fuse->gid = gid;
+    fuse->mask = mask;
 
-    res = setgid(gid);
-    if (res < 0) {
-        ERROR("cannot setgid: %s\n", strerror(errno));
-        goto error;
-    }
-
-    res = setuid(uid);
-    if (res < 0) {
-        ERROR("cannot setuid: %s\n", strerror(errno));
-        goto error;
-    }
-
-    fuse_init(&fuse, fd, source_path, write_gid, derive, split_perms);
-
-    umask(0);
-    res = ignite_fuse(&fuse, num_threads);
-
-    /* we do not attempt to umount the file system here because we are no longer
-     * running as the root user */
-
-error:
-    close(fd);
-    return res;
+    return 0;
 }
 
-int main(int argc, char **argv)
-{
-    int res;
+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);
+}
+
+int main(int argc, char **argv) {
     const char *source_path = NULL;
-    const char *dest_path = NULL;
+    const char *label = NULL;
     uid_t uid = 0;
     gid_t gid = 0;
-    gid_t write_gid = AID_SDCARD_RW;
-    int num_threads = DEFAULT_NUM_THREADS;
-    derive_t derive = DERIVE_NONE;
-    bool split_perms = false;
+    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:w:t:dls")) != -1) {
+    while ((opt = getopt(argc, argv, "u:g:U:mw")) != -1) {
         switch (opt) {
             case 'u':
                 uid = strtoul(optarg, NULL, 10);
@@ -1901,20 +1908,14 @@
             case 'g':
                 gid = strtoul(optarg, NULL, 10);
                 break;
+            case 'U':
+                userid = strtoul(optarg, NULL, 10);
+                break;
+            case 'm':
+                multi_user = true;
+                break;
             case 'w':
-                write_gid = strtoul(optarg, NULL, 10);
-                break;
-            case 't':
-                num_threads = strtoul(optarg, NULL, 10);
-                break;
-            case 'd':
-                derive = DERIVE_UNIFIED;
-                break;
-            case 'l':
-                derive = DERIVE_LEGACY;
-                break;
-            case 's':
-                split_perms = true;
+                full_write = true;
                 break;
             case '?':
             default:
@@ -1926,12 +1927,8 @@
         char* arg = argv[i];
         if (!source_path) {
             source_path = arg;
-        } else if (!dest_path) {
-            dest_path = arg;
-        } else if (!uid) {
-            uid = strtoul(arg, NULL, 10);
-        } else if (!gid) {
-            gid = strtoul(arg, NULL, 10);
+        } else if (!label) {
+            label = arg;
         } else {
             ERROR("too many arguments\n");
             return usage();
@@ -1942,22 +1939,14 @@
         ERROR("no source path specified\n");
         return usage();
     }
-    if (!dest_path) {
-        ERROR("no dest path specified\n");
+    if (!label) {
+        ERROR("no label specified\n");
         return usage();
     }
     if (!uid || !gid) {
         ERROR("uid and gid must be nonzero\n");
         return usage();
     }
-    if (num_threads < 1) {
-        ERROR("number of threads must be at least 1\n");
-        return usage();
-    }
-    if (split_perms && derive == DERIVE_NONE) {
-        ERROR("cannot split permissions without deriving\n");
-        return usage();
-    }
 
     rlim.rlim_cur = 8192;
     rlim.rlim_max = 8192;
@@ -1970,6 +1959,6 @@
         sleep(1);
     }
 
-    res = run(source_path, dest_path, uid, gid, write_gid, num_threads, derive, split_perms);
-    return res < 0 ? 1 : 0;
+    run(source_path, label, uid, gid, userid, multi_user, full_write);
+    return 1;
 }
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 84714cf..ad99a39 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -9,230 +9,75 @@
 
 
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES := upstream-netbsd/bin/cat/cat.c
-LOCAL_CFLAGS += $(common_cflags) -Dmain=cat_main
-LOCAL_MODULE := libtoolbox_cat
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := upstream-netbsd/sbin/chown/chown.c
-LOCAL_CFLAGS += $(common_cflags) -Dmain=chown_main
-LOCAL_MODULE := libtoolbox_chown
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := \
-    upstream-netbsd/bin/cp/cp.c \
-    upstream-netbsd/bin/cp/utils.c
-LOCAL_CFLAGS += $(common_cflags) -Dmain=cp_main
-LOCAL_MODULE := libtoolbox_cp
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
 LOCAL_SRC_FILES := \
     upstream-netbsd/bin/dd/args.c \
     upstream-netbsd/bin/dd/conv.c \
     upstream-netbsd/bin/dd/dd.c \
     upstream-netbsd/bin/dd/dd_hostops.c \
     upstream-netbsd/bin/dd/misc.c \
-    upstream-netbsd/bin/dd/position.c
+    upstream-netbsd/bin/dd/position.c \
+    upstream-netbsd/lib/libc/gen/getbsize.c \
+    upstream-netbsd/lib/libc/gen/humanize_number.c \
+    upstream-netbsd/lib/libc/stdlib/strsuftoll.c \
+    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_MODULE := libtoolbox_dd
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := upstream-netbsd/usr.bin/du/du.c
 LOCAL_CFLAGS += $(common_cflags) -Dmain=du_main
 LOCAL_MODULE := libtoolbox_du
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := \
-    upstream-netbsd/usr.bin/grep/fastgrep.c \
-    upstream-netbsd/usr.bin/grep/file.c \
-    upstream-netbsd/usr.bin/grep/grep.c \
-    upstream-netbsd/usr.bin/grep/queue.c \
-    upstream-netbsd/usr.bin/grep/util.c
-LOCAL_CFLAGS += $(common_cflags) -Dmain=grep_main
-LOCAL_MODULE := libtoolbox_grep
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := upstream-netbsd/bin/kill/kill.c
-LOCAL_CFLAGS += $(common_cflags) -Dmain=kill_main
-LOCAL_MODULE := libtoolbox_kill
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := upstream-netbsd/bin/ln/ln.c
-LOCAL_CFLAGS += $(common_cflags) -Dmain=ln_main
-LOCAL_MODULE := libtoolbox_ln
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := upstream-netbsd/bin/mv/mv.c
-LOCAL_CFLAGS += $(common_cflags) -Dmain=mv_main -D__SVR4
-LOCAL_MODULE := libtoolbox_mv
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := upstream-netbsd/usr.bin/printenv/printenv.c
-LOCAL_CFLAGS += $(common_cflags) -Dmain=printenv_main
-LOCAL_MODULE := libtoolbox_printenv
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := upstream-netbsd/bin/rm/rm.c
-LOCAL_CFLAGS += $(common_cflags) -Dmain=rm_main
-LOCAL_MODULE := libtoolbox_rm
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := upstream-netbsd/bin/rmdir/rmdir.c
-LOCAL_CFLAGS += $(common_cflags) -Dmain=rmdir_main
-LOCAL_MODULE := libtoolbox_rmdir
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := upstream-netbsd/bin/sleep/sleep.c
-LOCAL_CFLAGS += $(common_cflags) -Dmain=sleep_main
-LOCAL_MODULE := libtoolbox_sleep
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := upstream-netbsd/bin/sync/sync.c
-LOCAL_CFLAGS += $(common_cflags) -Dmain=sync_main
-LOCAL_MODULE := libtoolbox_sync
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 include $(BUILD_STATIC_LIBRARY)
 
 
 include $(CLEAR_VARS)
 
 BSD_TOOLS := \
-    cat \
-    chown \
-    cp \
     dd \
     du \
-    grep \
-    kill \
-    ln \
-    mv \
-    printenv \
-    rm \
-    rmdir \
-    sleep \
-    sync \
 
 OUR_TOOLS := \
-    chcon \
-    chmod \
-    clear \
-    cmp \
-    date \
     df \
-    dmesg \
-    getenforce \
     getevent \
-    getprop \
-    getsebool \
-    hd \
-    id \
-    ifconfig \
     iftop \
-    insmod \
     ioctl \
     ionice \
-    load_policy \
     log \
     ls \
-    lsmod \
     lsof \
-    md5 \
-    mkdir \
-    mknod \
-    mkswap \
     mount \
     nandread \
-    netstat \
     newfs_msdos \
-    nohup \
-    notify \
     ps \
-    readlink \
-    renice \
-    restorecon \
     prlimit \
-    rmmod \
-    route \
-    runcon \
-    schedtop \
+    renice \
     sendevent \
-    setenforce \
-    setprop \
-    setsebool \
-    smd \
     start \
     stop \
-    swapoff \
-    swapon \
     top \
-    touch \
-    umount \
     uptime \
-    vmstat \
     watchprops \
-    wipe \
-
-ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
-OUR_TOOLS += r
-endif
 
 ALL_TOOLS = $(BSD_TOOLS) $(OUR_TOOLS)
 
 LOCAL_SRC_FILES := \
-    upstream-netbsd/lib/libc/gen/getbsize.c \
-    upstream-netbsd/lib/libc/gen/humanize_number.c \
-    upstream-netbsd/lib/libc/stdlib/strsuftoll.c \
-    upstream-netbsd/lib/libc/string/swab.c \
-    upstream-netbsd/lib/libutil/raise_default_signal.c \
-    dynarray.c \
-    pwcache.c \
-    $(patsubst %,%.c,$(OUR_TOOLS)) \
     toolbox.c \
+    $(patsubst %,%.c,$(OUR_TOOLS)) \
 
 LOCAL_CFLAGS += $(common_cflags)
 
-LOCAL_C_INCLUDES += external/openssl/include
-
 LOCAL_SHARED_LIBRARIES := \
-    libcrypto \
     libcutils \
     libselinux \
 
-# libusbhost is only used by lsusb, and that isn't usually included in toolbox.
-# The linker strips out all the unused library code in the normal case.
-LOCAL_STATIC_LIBRARIES := \
-    libusbhost \
-
 LOCAL_WHOLE_STATIC_LIBRARIES := $(patsubst %,libtoolbox_%,$(BSD_TOOLS))
 
 LOCAL_MODULE := toolbox
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+
+# Install the symlinks.
+LOCAL_POST_INSTALL_CMD := $(hide) $(foreach t,$(ALL_TOOLS),ln -sf toolbox $(TARGET_OUT)/bin/$(t);)
 
 # Including this will define $(intermediates).
 #
@@ -247,19 +92,33 @@
 $(TOOLS_H):
 	$(transform-generated-source)
 
-# Make #!/system/bin/toolbox launchers for each tool.
-#
-SYMLINKS := $(addprefix $(TARGET_OUT)/bin/,$(ALL_TOOLS))
-$(SYMLINKS): TOOLBOX_BINARY := $(LOCAL_MODULE)
-$(SYMLINKS): $(LOCAL_INSTALLED_MODULE) $(LOCAL_PATH)/Android.mk
-	@echo "Symlink: $@ -> $(TOOLBOX_BINARY)"
-	@mkdir -p $(dir $@)
-	@rm -rf $@
-	$(hide) ln -sf $(TOOLBOX_BINARY) $@
+$(LOCAL_PATH)/getevent.c: $(intermediates)/input.h-labels.h
 
-ALL_DEFAULT_INSTALLED_MODULES += $(SYMLINKS)
+INPUT_H_LABELS_H := $(intermediates)/input.h-labels.h
+$(INPUT_H_LABELS_H): PRIVATE_LOCAL_PATH := $(LOCAL_PATH)
+$(INPUT_H_LABELS_H): PRIVATE_CUSTOM_TOOL = $(PRIVATE_LOCAL_PATH)/generate-input.h-labels.py > $@
+$(INPUT_H_LABELS_H): $(LOCAL_PATH)/Android.mk $(LOCAL_PATH)/generate-input.h-labels.py
+$(INPUT_H_LABELS_H):
+	$(transform-generated-source)
 
-# We need this so that the installed files could be picked up based on the
-# local module name
-ALL_MODULES.$(LOCAL_MODULE).INSTALLED := \
-    $(ALL_MODULES.$(LOCAL_MODULE).INSTALLED) $(SYMLINKS)
+# We only want 'r' on userdebug and eng builds.
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := r.c
+LOCAL_CFLAGS += $(common_cflags)
+LOCAL_MODULE := r
+LOCAL_MODULE_TAGS := debug
+include $(BUILD_EXECUTABLE)
+
+
+# We build BSD grep separately, so it can provide egrep and fgrep too.
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+    upstream-netbsd/usr.bin/grep/fastgrep.c \
+    upstream-netbsd/usr.bin/grep/file.c \
+    upstream-netbsd/usr.bin/grep/grep.c \
+    upstream-netbsd/usr.bin/grep/queue.c \
+    upstream-netbsd/usr.bin/grep/util.c
+LOCAL_CFLAGS += $(common_cflags)
+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/alarm.c b/toolbox/alarm.c
deleted file mode 100644
index 9bd58aa..0000000
--- a/toolbox/alarm.c
+++ /dev/null
@@ -1,190 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <string.h>
-#include <errno.h>
-#include <time.h>
-#include <asm/ioctl.h>
-//#include <linux/rtc.h>
-#include <linux/android_alarm.h>
-
-int alarm_main(int argc, char *argv[])
-{
-	int c;
-    int res;
-	struct tm tm;
-	time_t t;
-	struct timespec ts;
-//	struct rtc_time rtc_time;
-	char strbuf[26];
-	int afd;
-	int nfd;
-//	struct timeval timeout = { 0, 0 };
-    int wait = 0;
-	fd_set rfds;
-	const char wake_lock_id[] = "alarm_test"; 
-	int waitalarmmask = 0;
-
-    int useutc = 0;
-	android_alarm_type_t alarmtype_low = ANDROID_ALARM_RTC_WAKEUP;
-	android_alarm_type_t alarmtype_high = ANDROID_ALARM_RTC_WAKEUP;
-	android_alarm_type_t alarmtype = 0;
-
-    do {
-        //c = getopt(argc, argv, "uw:");
-        c = getopt(argc, argv, "uwat:");
-        if (c == EOF)
-            break;
-        switch (c) {
-        case 'u':
-            useutc = 1;
-            break;
-		case 't':
-			alarmtype_low = alarmtype_high = strtol(optarg, NULL, 0);
-			break;
-		case 'a':
-			alarmtype_low = ANDROID_ALARM_RTC_WAKEUP;
-			alarmtype_high = ANDROID_ALARM_TYPE_COUNT - 1;
-			break;
-        case 'w':
-            //timeout.tv_sec = strtol(optarg, NULL, 0);
-            wait = 1;
-            break;
-        case '?':
-            fprintf(stderr, "%s: invalid option -%c\n",
-                argv[0], optopt);
-            exit(1);
-        }
-    } while (1);
-    if(optind + 2 < argc) {
-        fprintf(stderr,"%s [-uwa] [-t type] [seconds]\n", argv[0]);
-        return 1;
-    }
-
-    afd = open("/dev/alarm", O_RDWR);
-    if(afd < 0) {
-        fprintf(stderr, "Unable to open rtc: %s\n", strerror(errno));
-        return 1;
-    }
-
-    if(optind == argc) {
-		for(alarmtype = alarmtype_low; alarmtype <= alarmtype_high; alarmtype++) {
-			waitalarmmask |= 1U << alarmtype;
-		}
-#if 0
-        res = ioctl(fd, RTC_ALM_READ, &tm);
-        if(res < 0) {
-            fprintf(stderr, "Unable to read alarm: %s\n", strerror(errno));
-			return 1;
-        }
-#endif
-#if 0
-		t = timegm(&tm);
-        if(useutc)
-            gmtime_r(&t, &tm);
-        else
-            localtime_r(&t, &tm);
-#endif
-#if 0
-        asctime_r(&tm, strbuf);
-        printf("%s", strbuf);
-#endif
-    }
-    else if(optind + 1 == argc) {
-#if 0
-        res = ioctl(fd, RTC_RD_TIME, &tm);
-        if(res < 0) {
-            fprintf(stderr, "Unable to set alarm: %s\n", strerror(errno));
-			return 1;
-        }
-        asctime_r(&tm, strbuf);
-        printf("Now: %s", strbuf);
-        time(&tv.tv_sec);
-#endif
-#if 0
-		time(&ts.tv_sec);
-		ts.tv_nsec = 0;
-		
-        //strptime(argv[optind], NULL, &tm);
-        //tv.tv_sec = mktime(&tm);
-        //tv.tv_usec = 0;
-#endif
-		for(alarmtype = alarmtype_low; alarmtype <= alarmtype_high; alarmtype++) {
-			waitalarmmask |= 1U << alarmtype;
-		    res = ioctl(afd, ANDROID_ALARM_GET_TIME(alarmtype), &ts);
-		    if(res < 0) {
-		        fprintf(stderr, "Unable to get current time: %s\n", strerror(errno));
-				return 1;
-		    }
-		    ts.tv_sec += strtol(argv[optind], NULL, 0);
-		    //strtotimeval(argv[optind], &tv);
-			gmtime_r(&ts.tv_sec, &tm);
-		    printf("time %s -> %ld.%09ld\n", argv[optind], ts.tv_sec, ts.tv_nsec);
-		    asctime_r(&tm, strbuf);
-		    printf("Requested %s", strbuf);
-			
-		    res = ioctl(afd, ANDROID_ALARM_SET(alarmtype), &ts);
-		    if(res < 0) {
-		        fprintf(stderr, "Unable to set alarm: %s\n", strerror(errno));
-				return 1;
-		    }
-		}
-#if 0
-        res = ioctl(fd, RTC_ALM_SET, &tm);
-        if(res < 0) {
-            fprintf(stderr, "Unable to set alarm: %s\n", strerror(errno));
-			return 1;
-        }
-        res = ioctl(fd, RTC_AIE_ON);
-        if(res < 0) {
-            fprintf(stderr, "Unable to enable alarm: %s\n", strerror(errno));
-			return 1;
-        }
-#endif
-    }
-    else {
-        fprintf(stderr,"%s [-u] [date]\n", argv[0]);
-        return 1;
-    }
-
-	if(wait) {
-		while(waitalarmmask) {
-			printf("wait for alarm %x\n", waitalarmmask);
-			res = ioctl(afd, ANDROID_ALARM_WAIT);
-			if(res < 0) {
-				fprintf(stderr, "alarm wait failed\n");
-			}
-			printf("got alarm %x\n", res);
-			waitalarmmask &= ~res;
-			nfd = open("/sys/android_power/acquire_full_wake_lock", O_RDWR);
-			write(nfd, wake_lock_id, sizeof(wake_lock_id) - 1);
-			close(nfd);
-			//sleep(5);
-			nfd = open("/sys/android_power/release_wake_lock", O_RDWR);
-			write(nfd, wake_lock_id, sizeof(wake_lock_id) - 1);
-			close(nfd);
-		}
-		printf("done\n");
-	}
-#if 0	
-	FD_ZERO(&rfds);
-	FD_SET(fd, &rfds);
-	res = select(fd + 1, &rfds, NULL, NULL, &timeout);
-    if(res < 0) {
-        fprintf(stderr, "select failed: %s\n", strerror(errno));
-		return 1;
-    }
-	if(res > 0) {
-		int event;
-		read(fd, &event, sizeof(event));
-		fprintf(stderr, "got %x\n", event);
-	}
-	else {
-		fprintf(stderr, "timeout waiting for alarm\n");
-	}
-#endif
-
-    close(afd);
-
-    return 0;
-}
diff --git a/toolbox/bsd-compatibility.h b/toolbox/bsd-compatibility.h
index 9c6c34a..434d370 100644
--- a/toolbox/bsd-compatibility.h
+++ b/toolbox/bsd-compatibility.h
@@ -50,16 +50,8 @@
 
 #define S_ISWHT(x) false
 
-// TODO: should this be in bionic? (glibc does this, even though it's not quite right.)
-#define O_RSYNC O_SYNC
-
 __BEGIN_DECLS
 
-/* From NetBSD <grp.h> and <pwd.h>. */
-char* group_from_gid(gid_t gid, int noname);
-int uid_from_user(const char* name, uid_t* uid);
-char* user_from_uid(uid_t uid, int noname);
-
 /* From NetBSD <stdlib.h>. */
 #define HN_DECIMAL              0x01
 #define HN_NOSPACE              0x02
diff --git a/toolbox/chcon.c b/toolbox/chcon.c
deleted file mode 100644
index d594b9b..0000000
--- a/toolbox/chcon.c
+++ /dev/null
@@ -1,25 +0,0 @@
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <selinux/selinux.h>
-
-int chcon_main(int argc, char **argv)
-{
-    int rc, i;
-
-    if (argc < 3) {
-        fprintf(stderr, "usage:  %s context path...\n", argv[0]);
-        exit(1);
-    }
-
-    for (i = 2; i < argc; i++) {
-        rc = setfilecon(argv[i], argv[1]);
-        if (rc < 0) {
-            fprintf(stderr, "%s:  Could not label %s with %s:  %s\n",
-                    argv[0], argv[i], argv[1], strerror(errno));
-            exit(2);
-        }
-    }
-    exit(0);
-}
diff --git a/toolbox/chmod.c b/toolbox/chmod.c
deleted file mode 100644
index 2a524e9..0000000
--- a/toolbox/chmod.c
+++ /dev/null
@@ -1,101 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <errno.h>
-#include <sys/limits.h>
-#include <sys/stat.h>
-
-#include <unistd.h>
-#include <time.h>
-
-void recurse_chmod(char* path, int mode)
-{
-    struct dirent *dp;
-    DIR *dir = opendir(path);
-    if (dir == NULL) {
-        // not a directory, carry on
-        return;
-    }
-    char *subpath = malloc(sizeof(char)*PATH_MAX);
-    int pathlen = strlen(path);
-
-    while ((dp = readdir(dir)) != NULL) {
-        if (strcmp(dp->d_name, ".") == 0 ||
-            strcmp(dp->d_name, "..") == 0) continue;
-
-        if (strlen(dp->d_name) + pathlen + 2/*NUL and slash*/ > PATH_MAX) {
-            fprintf(stderr, "Invalid path specified: too long\n");
-            exit(1);
-        }
-
-        strcpy(subpath, path);
-        strcat(subpath, "/");
-        strcat(subpath, dp->d_name);
-
-        if (chmod(subpath, mode) < 0) {
-            fprintf(stderr, "Unable to chmod %s: %s\n", subpath, strerror(errno));
-            exit(1);
-        }
-
-        recurse_chmod(subpath, mode);
-    }
-    free(subpath);
-    closedir(dir);
-}
-
-static int usage()
-{
-    fprintf(stderr, "Usage: chmod [OPTION] <MODE> <FILE>\n");
-    fprintf(stderr, "  -R, --recursive         change files and directories recursively\n");
-    fprintf(stderr, "  --help                  display this help and exit\n");
-
-    return 10;
-}
-
-int chmod_main(int argc, char **argv)
-{
-    int i;
-
-    if (argc < 3 || strcmp(argv[1], "--help") == 0) {
-        return usage();
-    }
-
-    int recursive = (strcmp(argv[1], "-R") == 0 ||
-                     strcmp(argv[1], "--recursive") == 0) ? 1 : 0;
-
-    if (recursive && argc < 4) {
-        return usage();
-    }
-
-    if (recursive) {
-        argc--;
-        argv++;
-    }
-
-    int mode = 0;
-    const char* s = argv[1];
-    while (*s) {
-        if (*s >= '0' && *s <= '7') {
-            mode = (mode<<3) | (*s-'0');
-        }
-        else {
-            fprintf(stderr, "Bad mode\n");
-            return 10;
-        }
-        s++;
-    }
-
-    for (i = 2; i < argc; i++) {
-        if (chmod(argv[i], mode) < 0) {
-            fprintf(stderr, "Unable to chmod %s: %s\n", argv[i], strerror(errno));
-            return 10;
-        }
-        if (recursive) {
-            recurse_chmod(argv[i], mode);
-        }
-    }
-    return 0;
-}
-
diff --git a/toolbox/clear.c b/toolbox/clear.c
deleted file mode 100644
index df46ad2..0000000
--- a/toolbox/clear.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2012, 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>
-
-int clear_main(int argc, char **argv) {
-    /* This prints the clear screen and move cursor to top-left corner control
-     * characters for VT100 terminals. This means it will not work on
-     * non-VT100 compliant terminals, namely Windows' cmd.exe, but should
-     * work on anything unix-y. */
-    fputs("\x1b[2J\x1b[H", stdout);
-    return 0;
-}
diff --git a/toolbox/cmp.c b/toolbox/cmp.c
deleted file mode 100644
index 80635ad..0000000
--- a/toolbox/cmp.c
+++ /dev/null
@@ -1,91 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-
-int cmp_main(int argc, char *argv[])
-{
-    int c;
-    int fd1, fd2;
-	char buf1[4096], buf2[4096];
-    int res, res1, res2;
-	int rv = 0;
-	int i;
-	int filepos = 0;
-
-	int show_byte = 0;
-	int show_all = 0;
-	int limit = 0;
-
-    do {
-        c = getopt(argc, argv, "bln:");
-        if (c == EOF)
-            break;
-        switch (c) {
-        case 'b':
-            show_byte = 1;
-            break;
-        case 'l':
-            show_all = 1;
-            break;
-        case 'n':
-            limit = atoi(optarg);
-            break;
-        case '?':
-            fprintf(stderr, "%s: invalid option -%c\n",
-                argv[0], optopt);
-            exit(1);
-        }
-    } while (1);
-
-    if (optind + 2 != argc) {
-        fprintf(stderr, "Usage: %s [-b] [-l] [-n count] file1 file2\n", argv[0]);
-        exit(1);
-    }
-
-    fd1 = open(argv[optind], O_RDONLY);
-    if(fd1 < 0) {
-        fprintf(stderr, "could not open %s, %s\n", argv[optind], strerror(errno));
-        return 1;
-    }
-
-    fd2 = open(argv[optind+1], O_RDONLY);
-    if(fd2 < 0) {
-        fprintf(stderr, "could not open %s, %s\n", argv[optind+1], strerror(errno));
-        return 1;
-    }
-    
-    while(1) {
-        res1 = read(fd1, &buf1, sizeof(buf1));
-        res2 = read(fd2, &buf2, sizeof(buf2));
-		res = res1 < res2 ? res1 : res2;
-		if(res1 == 0 && res2 == 0) {
-			return rv;
-		}
-		for(i = 0; i < res; i++) {
-			if(buf1[i] != buf2[i]) {
-				printf("%s %s differ byte %d", argv[optind], argv[optind+1], filepos + i);
-				if(show_byte)
-					printf(" 0x%02x 0x%02x", buf1[i], buf2[i]);
-				printf("\n");
-				if(!show_all)
-					return 1;
-				rv = 1;
-			}
-			if(limit) {
-				limit--;
-				if(limit == 0)
-					return rv;
-			}
-		}
-		if(res1 != res2 || res < 0) {
-			printf("%s on %s\n", res < 0 ? "Read error" : "EOF", res1 < res2 ? argv[optind] : argv[optind+1]);
-			return 1;
-		}
-		filepos += res;
-    }
-}
diff --git a/toolbox/date.c b/toolbox/date.c
deleted file mode 100644
index 70ce1d5..0000000
--- a/toolbox/date.c
+++ /dev/null
@@ -1,227 +0,0 @@
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <linux/android_alarm.h>
-#include <linux/rtc.h>
-#include <sys/ioctl.h>
-
-static int settime_alarm(struct timespec *ts) {
-    int fd, ret;
-
-    fd = open("/dev/alarm", O_RDWR);
-    if (fd < 0)
-        return fd;
-
-    ret = ioctl(fd, ANDROID_ALARM_SET_RTC, ts);
-    close(fd);
-    return ret;
-}
-
-static int settime_alarm_tm(struct tm *tm) {
-    time_t t;
-    struct timespec ts;
-
-    t = mktime(tm);
-    ts.tv_sec = t;
-    ts.tv_nsec = 0;
-    return settime_alarm(&ts);
-}
-
-static int settime_alarm_timeval(struct timeval *tv) {
-    struct timespec ts;
-
-    ts.tv_sec = tv->tv_sec;
-    ts.tv_nsec = tv->tv_usec * 1000;
-    return settime_alarm(&ts);
-}
-
-static int settime_rtc_tm(struct tm *tm) {
-    int fd, ret;
-    struct timeval tv;
-    struct rtc_time rtc;
-
-    fd = open("/dev/rtc0", O_RDWR);
-    if (fd < 0)
-        return fd;
-
-    tv.tv_sec = mktime(tm);
-    tv.tv_usec = 0;
-
-    ret = settimeofday(&tv, NULL);
-    if (ret < 0)
-        goto done;
-
-    memset(&rtc, 0, sizeof(rtc));
-    rtc.tm_sec = tm->tm_sec;
-    rtc.tm_min = tm->tm_min;
-    rtc.tm_hour = tm->tm_hour;
-    rtc.tm_mday = tm->tm_mday;
-    rtc.tm_mon = tm->tm_mon;
-    rtc.tm_year = tm->tm_year;
-    rtc.tm_wday = tm->tm_wday;
-    rtc.tm_yday = tm->tm_yday;
-    rtc.tm_isdst = tm->tm_isdst;
-
-    ret = ioctl(fd, RTC_SET_TIME, rtc);
-done:
-    close(fd);
-    return ret;
-}
-
-static int settime_rtc_timeval(struct timeval *tv) {
-    struct tm tm, *err;
-    time_t t = tv->tv_sec;
-
-    err = gmtime_r(&t, &tm);
-    if (!err)
-        return -1;
-
-    return settime_rtc_tm(&tm);
-}
-
-static void settime(char *s) {
-    struct tm tm;
-    int day = atoi(s);
-    int hour;
-
-    while (*s && *s != '.')
-        s++;
-
-    if (*s)
-        s++;
-
-    hour = atoi(s);
-
-    tm.tm_year = day / 10000 - 1900;
-    tm.tm_mon = (day % 10000) / 100 - 1;
-    tm.tm_mday = (day % 100);
-    tm.tm_hour = hour / 10000;
-    tm.tm_min = (hour % 10000) / 100;
-    tm.tm_sec = (hour % 100);
-    tm.tm_isdst = -1;
-
-    if (settime_alarm_tm(&tm) < 0)
-        settime_rtc_tm(&tm);
-}
-
-static char *parse_time(const char *str, struct timeval *ts) {
-  char *s;
-  long fs = 0; /* fractional seconds */
-
-  ts->tv_sec = strtoumax(str, &s, 10);
-
-  if (*s == '.') {
-    s++;
-    int count = 0;
-
-    /* read up to 6 digits (microseconds) */
-    while (*s && isdigit(*s)) {
-      if (++count < 7) {
-        fs = fs*10 + (*s - '0');
-      }
-      s++;
-    }
-
-    for (; count < 6; count++) {
-      fs *= 10;
-    }
-  }
-
-  ts->tv_usec = fs;
-  return s;
-}
-
-int date_main(int argc, char *argv[])
-{
-    int c;
-    int res;
-    struct tm tm;
-    time_t t;
-    struct timeval tv;
-    char strbuf[260];
-
-    int useutc = 0;
-
-    tzset();
-
-    do {
-        c = getopt(argc, argv, "us:");
-        if (c == EOF)
-            break;
-        switch (c) {
-        case 'u':
-            useutc = 1;
-            break;
-        case 's':
-            settime(optarg);
-            break;
-        case '?':
-            fprintf(stderr, "%s: invalid option -%c\n",
-                argv[0], optopt);
-            exit(1);
-        }
-    } while (1);
-    if(optind + 2 < argc) {
-        fprintf(stderr,"%s [-u] [date]\n", argv[0]);
-        return 1;
-    }
-
-    int hasfmt = argc == optind + 1 && argv[optind][0] == '+';
-    if(optind == argc || hasfmt) {
-        time(&t);
-        if (useutc) {
-            gmtime_r(&t, &tm);
-            strftime(strbuf, sizeof(strbuf),
-                     (hasfmt ? argv[optind] + 1 : "%a %b %e %H:%M:%S GMT %Y"),
-                     &tm);
-        } else {
-            localtime_r(&t, &tm);
-            strftime(strbuf, sizeof(strbuf),
-                     (hasfmt ? argv[optind] + 1 : "%a %b %e %H:%M:%S %Z %Y"),
-                     &tm);
-        }
-        printf("%s\n", strbuf);
-    }
-    else if(optind + 1 == argc) {
-#if 0
-        struct tm *tmptr;
-        tmptr = getdate(argv[optind]);
-        if(tmptr == NULL) {
-            fprintf(stderr,"getdate_r failed\n");
-            return 1;
-        }
-        tm = *tmptr;
-#if 0
-        if(getdate_r(argv[optind], &tm) < 0) {
-            fprintf(stderr,"getdate_r failed %s\n", strerror(errno));
-            return 1;
-        }
-#endif
-#endif
-        //strptime(argv[optind], NULL, &tm);
-        //tv.tv_sec = mktime(&tm);
-        //tv.tv_usec = 0;
-        parse_time(argv[optind], &tv);
-        printf("time %s -> %lu.%lu\n", argv[optind], tv.tv_sec, tv.tv_usec);
-        res = settime_alarm_timeval(&tv);
-        if (res < 0)
-            res = settime_rtc_timeval(&tv);
-        if(res < 0) {
-            fprintf(stderr,"settimeofday failed %s\n", strerror(errno));
-            return 1;
-        }
-    }
-    else {
-        fprintf(stderr,"%s [-s 20070325.123456] [-u] [date]\n", argv[0]);
-        return 1;
-    }
-
-    return 0;
-}
diff --git a/toolbox/dmesg.c b/toolbox/dmesg.c
deleted file mode 100644
index 9c73b00..0000000
--- a/toolbox/dmesg.c
+++ /dev/null
@@ -1,58 +0,0 @@
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-#include <sys/klog.h>
-#include <string.h>
-
-#define FALLBACK_KLOG_BUF_SHIFT	17	/* CONFIG_LOG_BUF_SHIFT from our kernel */
-#define FALLBACK_KLOG_BUF_LEN	(1 << FALLBACK_KLOG_BUF_SHIFT)
-
-int dmesg_main(int argc, char **argv)
-{
-    char *buffer;
-    char *p;
-    ssize_t ret;
-    int n, op, klog_buf_len;
-
-    klog_buf_len = klogctl(KLOG_SIZE_BUFFER, 0, 0);
-
-    if (klog_buf_len <= 0) {
-        klog_buf_len = FALLBACK_KLOG_BUF_LEN;
-    }
-
-    buffer = (char *)malloc(klog_buf_len + 1);
-
-    if (!buffer) {
-        perror("malloc");
-        return EXIT_FAILURE;
-    }
-
-    p = buffer;
-
-    if((argc == 2) && (!strcmp(argv[1],"-c"))) {
-        op = KLOG_READ_CLEAR;
-    } else {
-        op = KLOG_READ_ALL;
-    }
-
-    n = klogctl(op, buffer, klog_buf_len);
-    if (n < 0) {
-        perror("klogctl");
-        return EXIT_FAILURE;
-    }
-    buffer[n] = '\0';
-
-    while((ret = write(STDOUT_FILENO, p, n))) {
-        if (ret == -1) {
-	    if (errno == EINTR)
-                continue;
-	    perror("write");
-	    return EXIT_FAILURE;
-	}
-	p += ret;
-	n -= ret;
-    }
-
-    return 0;
-}
diff --git a/toolbox/dynarray.c b/toolbox/dynarray.c
deleted file mode 100644
index e9b7b03..0000000
--- a/toolbox/dynarray.c
+++ /dev/null
@@ -1,103 +0,0 @@
-#include "dynarray.h"
-#include <stdlib.h>
-#include <limits.h>
-
-void
-dynarray_init( dynarray_t *a )
-{
-    a->count = a->capacity = 0;
-    a->items = NULL;
-}
-
-
-static void
-dynarray_reserve_more( dynarray_t *a, int count )
-{
-    int old_cap = a->capacity;
-    int new_cap = old_cap;
-    const int max_cap = INT_MAX/sizeof(void*);
-    void** new_items;
-    int new_count = a->count + count;
-
-    if (count <= 0)
-        return;
-
-    if (count > max_cap - a->count)
-        abort();
-
-    new_count = a->count + count;
-
-    while (new_cap < new_count) {
-        old_cap = new_cap;
-        new_cap += (new_cap >> 2) + 4;
-        if (new_cap < old_cap || new_cap > max_cap) {
-            new_cap = max_cap;
-        }
-    }
-    new_items = realloc(a->items, new_cap*sizeof(void*));
-    if (new_items == NULL)
-        abort();
-
-    a->items = new_items;
-    a->capacity = new_cap;
-}
-
-void
-dynarray_append( dynarray_t *a, void* item )
-{
-    if (a->count >= a->capacity)
-        dynarray_reserve_more(a, 1);
-
-    a->items[a->count++] = item;
-}
-
-void
-dynarray_done( dynarray_t *a )
-{
-    free(a->items);
-    a->items = NULL;
-    a->count = a->capacity = 0;
-}
-
-// string arrays
-
-void strlist_init( strlist_t *list )
-{
-    dynarray_init(list);
-}
-
-void strlist_append_b( strlist_t *list, const void* str, size_t  slen )
-{
-    char *copy = malloc(slen+1);
-    memcpy(copy, str, slen);
-    copy[slen] = '\0';
-    dynarray_append(list, copy);
-}
-
-void strlist_append_dup( strlist_t *list, const char *str)
-{
-    strlist_append_b(list, str, strlen(str));
-}
-
-void strlist_done( strlist_t *list )
-{
-    STRLIST_FOREACH(list, string, free(string));
-    dynarray_done(list);
-}
-
-static int strlist_compare_strings(const void* a, const void* b)
-{
-    const char *sa = *(const char **)a;
-    const char *sb = *(const char **)b;
-    return strcmp(sa, sb);
-}
-
-void strlist_sort( strlist_t *list )
-{
-    if (list->count > 0) {
-        qsort(list->items,
-              (size_t)list->count,
-              sizeof(void*),
-              strlist_compare_strings);
-    }
-}
diff --git a/toolbox/dynarray.h b/toolbox/dynarray.h
deleted file mode 100644
index f73fb3b..0000000
--- a/toolbox/dynarray.h
+++ /dev/null
@@ -1,80 +0,0 @@
-#ifndef DYNARRAY_H
-#define DYNARRAY_H
-
-#include <stddef.h>
-
-/* simple dynamic array of pointers */
-typedef struct {
-    int count;
-    int capacity;
-    void** items;
-} dynarray_t;
-
-#define DYNARRAY_INITIALIZER  { 0, 0, NULL }
-
-void dynarray_init( dynarray_t *a );
-void dynarray_done( dynarray_t *a );
-
-void dynarray_append( dynarray_t *a, void* item );
-
-/* Used to iterate over a dynarray_t
- * _array :: pointer to the array
- * _item_type :: type of objects pointed to by the array
- * _item      :: name of a local variable defined within the loop
- *               with type '_item_type'
- * _stmnt     :: C statement that will be executed in each iteration.
- *
- * You case use 'break' and 'continue' within _stmnt
- *
- * This macro is only intended for simple uses. I.e. do not add or
- * remove items from the array during iteration.
- */
-#define DYNARRAY_FOREACH_TYPE(_array,_item_type,_item,_stmnt) \
-    do { \
-        int _nn_##__LINE__ = 0; \
-        for (;_nn_##__LINE__ < (_array)->count; ++ _nn_##__LINE__) { \
-            _item_type _item = (_item_type)(_array)->items[_nn_##__LINE__]; \
-            _stmnt; \
-        } \
-    } while (0)
-
-#define DYNARRAY_FOREACH(_array,_item,_stmnt) \
-    DYNARRAY_FOREACH_TYPE(_array,void *,_item,_stmnt)
-
-/* Simple dynamic string arrays
- *
- * NOTE: A strlist_t owns the strings it references.
- */
-typedef dynarray_t  strlist_t;
-
-#define  STRLIST_INITIALIZER  DYNARRAY_INITIALIZER
-
-/* Used to iterate over a strlist_t
- * _list   :: pointer to strlist_t object
- * _string :: name of local variable name defined within the loop with
- *            type 'char*'
- * _stmnt  :: C statement executed in each iteration
- *
- * This macro is only intended for simple uses. Do not add or remove items
- * to/from the list during iteration.
- */
-#define  STRLIST_FOREACH(_list,_string,_stmnt) \
-    DYNARRAY_FOREACH_TYPE(_list,char *,_string,_stmnt)
-
-void strlist_init( strlist_t *list );
-
-/* note: strlist_done will free all the strings owned by the list */
-void strlist_done( strlist_t *list );
-
-/* append a new string made of the first 'slen' characters from 'str'
- * followed by a trailing zero.
- */
-void strlist_append_b( strlist_t *list, const void* str, size_t  slen );
-
-/* append the copy of a given input string to a strlist_t */
-void strlist_append_dup( strlist_t *list, const char *str);
-
-/* sort the strings in a given list (using strcmp) */
-void strlist_sort( strlist_t *list );
-
-#endif /* DYNARRAY_H */
\ No newline at end of file
diff --git a/toolbox/exists.c b/toolbox/exists.c
deleted file mode 100644
index e348668..0000000
--- a/toolbox/exists.c
+++ /dev/null
@@ -1,16 +0,0 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-int exists_main(int argc, char *argv[])
-{
-    struct stat s;
-
-    if(argc < 2) return 1;
-
-    if(stat(argv[1], &s)) {
-        return 1;
-    } else {
-        return 0;
-    }
-}
diff --git a/toolbox/generate-input.h-labels.py b/toolbox/generate-input.h-labels.py
new file mode 100755
index 0000000..ebb9588
--- /dev/null
+++ b/toolbox/generate-input.h-labels.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+# pylint: disable=bad-indentation,bad-continuation
+
+import os
+import re
+
+input_prop_list = []
+ev_list = []
+syn_list = []
+key_list = []
+rel_list = []
+abs_list = []
+sw_list = []
+msc_list = []
+led_list = []
+rep_list = []
+snd_list = []
+mt_tool_list = []
+ff_status_list = []
+ff_list = []
+
+r = re.compile(r'#define\s+(\S+)\s+((?:0x)?\d+)')
+
+with open('bionic/libc/kernel/uapi/linux/input.h', '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)
+  for value in values:
+    print '    LABEL(%s),' % (value)
+  print '    LABEL_END,'
+  print '};'
+
+Dump("input_prop_labels", input_prop_list)
+Dump("ev_labels", ev_list)
+Dump("syn_labels", syn_list)
+Dump("key_labels", key_list)
+Dump("rel_labels", rel_list)
+Dump("abs_labels", abs_list)
+Dump("sw_labels", sw_list)
+Dump("msc_labels", msc_list)
+Dump("led_labels", led_list)
+Dump("rep_labels", rep_list)
+Dump("snd_labels", snd_list)
+Dump("mt_tool_labels", mt_tool_list)
+Dump("ff_status_labels", ff_status_list)
+Dump("ff_labels", ff_list)
diff --git a/toolbox/getenforce.c b/toolbox/getenforce.c
deleted file mode 100644
index 9e7589a..0000000
--- a/toolbox/getenforce.c
+++ /dev/null
@@ -1,30 +0,0 @@
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <selinux/selinux.h>
-
-int getenforce_main(int argc, char **argv)
-{
-    int rc;
-
-    rc = is_selinux_enabled();
-    if (rc <= 0) {
-        printf("Disabled\n");
-        return 0;
-    }
-
-    rc = security_getenforce();
-    if (rc < 0) {
-        fprintf(stderr, "Could not get enforcing status:  %s\n",
-                strerror(errno));
-        return 2;
-    }
-
-    if (rc)
-        printf("Enforcing\n");
-    else
-        printf("Permissive\n");
-
-    return 0;
-}
diff --git a/toolbox/getevent.c b/toolbox/getevent.c
index da83ec3..30053af 100644
--- a/toolbox/getevent.c
+++ b/toolbox/getevent.c
@@ -10,8 +10,27 @@
 #include <sys/poll.h>
 #include <linux/input.h>
 #include <errno.h>
+#include <unistd.h>
 
-#include "getevent.h"
+struct label {
+    const char *name;
+    int value;
+};
+
+#define LABEL(constant) { #constant, constant }
+#define LABEL_END { NULL, -1 }
+
+static struct label key_value_labels[] = {
+        { "UP", 0 },
+        { "DOWN", 1 },
+        { "REPEAT", 2 },
+        LABEL_END,
+};
+
+#include "input.h-labels.h"
+
+#undef LABEL
+#undef LABEL_END
 
 static struct pollfd *ufds;
 static char **device_names;
diff --git a/toolbox/getevent.h b/toolbox/getevent.h
deleted file mode 100644
index 0482d04..0000000
--- a/toolbox/getevent.h
+++ /dev/null
@@ -1,727 +0,0 @@
-#include <linux/input.h>
-
-struct label {
-    const char *name;
-    int value;
-};
-
-#define LABEL(constant) { #constant, constant }
-#define LABEL_END { NULL, -1 }
-
-static struct label input_prop_labels[] = {
-        LABEL(INPUT_PROP_POINTER),
-        LABEL(INPUT_PROP_DIRECT),
-        LABEL(INPUT_PROP_BUTTONPAD),
-        LABEL(INPUT_PROP_SEMI_MT),
-        LABEL_END,
-};
-
-static struct label ev_labels[] = {
-        LABEL(EV_SYN),
-        LABEL(EV_KEY),
-        LABEL(EV_REL),
-        LABEL(EV_ABS),
-        LABEL(EV_MSC),
-        LABEL(EV_SW),
-        LABEL(EV_LED),
-        LABEL(EV_SND),
-        LABEL(EV_REP),
-        LABEL(EV_FF),
-        LABEL(EV_PWR),
-        LABEL(EV_FF_STATUS),
-        LABEL_END,
-};
-
-static struct label syn_labels[] = {
-        LABEL(SYN_REPORT),
-        LABEL(SYN_CONFIG),
-        LABEL(SYN_MT_REPORT),
-        LABEL(SYN_DROPPED),
-        LABEL_END,
-};
-
-static struct label key_labels[] = {
-        LABEL(KEY_RESERVED),
-        LABEL(KEY_ESC),
-        LABEL(KEY_1),
-        LABEL(KEY_2),
-        LABEL(KEY_3),
-        LABEL(KEY_4),
-        LABEL(KEY_5),
-        LABEL(KEY_6),
-        LABEL(KEY_7),
-        LABEL(KEY_8),
-        LABEL(KEY_9),
-        LABEL(KEY_0),
-        LABEL(KEY_MINUS),
-        LABEL(KEY_EQUAL),
-        LABEL(KEY_BACKSPACE),
-        LABEL(KEY_TAB),
-        LABEL(KEY_Q),
-        LABEL(KEY_W),
-        LABEL(KEY_E),
-        LABEL(KEY_R),
-        LABEL(KEY_T),
-        LABEL(KEY_Y),
-        LABEL(KEY_U),
-        LABEL(KEY_I),
-        LABEL(KEY_O),
-        LABEL(KEY_P),
-        LABEL(KEY_LEFTBRACE),
-        LABEL(KEY_RIGHTBRACE),
-        LABEL(KEY_ENTER),
-        LABEL(KEY_LEFTCTRL),
-        LABEL(KEY_A),
-        LABEL(KEY_S),
-        LABEL(KEY_D),
-        LABEL(KEY_F),
-        LABEL(KEY_G),
-        LABEL(KEY_H),
-        LABEL(KEY_J),
-        LABEL(KEY_K),
-        LABEL(KEY_L),
-        LABEL(KEY_SEMICOLON),
-        LABEL(KEY_APOSTROPHE),
-        LABEL(KEY_GRAVE),
-        LABEL(KEY_LEFTSHIFT),
-        LABEL(KEY_BACKSLASH),
-        LABEL(KEY_Z),
-        LABEL(KEY_X),
-        LABEL(KEY_C),
-        LABEL(KEY_V),
-        LABEL(KEY_B),
-        LABEL(KEY_N),
-        LABEL(KEY_M),
-        LABEL(KEY_COMMA),
-        LABEL(KEY_DOT),
-        LABEL(KEY_SLASH),
-        LABEL(KEY_RIGHTSHIFT),
-        LABEL(KEY_KPASTERISK),
-        LABEL(KEY_LEFTALT),
-        LABEL(KEY_SPACE),
-        LABEL(KEY_CAPSLOCK),
-        LABEL(KEY_F1),
-        LABEL(KEY_F2),
-        LABEL(KEY_F3),
-        LABEL(KEY_F4),
-        LABEL(KEY_F5),
-        LABEL(KEY_F6),
-        LABEL(KEY_F7),
-        LABEL(KEY_F8),
-        LABEL(KEY_F9),
-        LABEL(KEY_F10),
-        LABEL(KEY_NUMLOCK),
-        LABEL(KEY_SCROLLLOCK),
-        LABEL(KEY_KP7),
-        LABEL(KEY_KP8),
-        LABEL(KEY_KP9),
-        LABEL(KEY_KPMINUS),
-        LABEL(KEY_KP4),
-        LABEL(KEY_KP5),
-        LABEL(KEY_KP6),
-        LABEL(KEY_KPPLUS),
-        LABEL(KEY_KP1),
-        LABEL(KEY_KP2),
-        LABEL(KEY_KP3),
-        LABEL(KEY_KP0),
-        LABEL(KEY_KPDOT),
-        LABEL(KEY_ZENKAKUHANKAKU),
-        LABEL(KEY_102ND),
-        LABEL(KEY_F11),
-        LABEL(KEY_F12),
-        LABEL(KEY_RO),
-        LABEL(KEY_KATAKANA),
-        LABEL(KEY_HIRAGANA),
-        LABEL(KEY_HENKAN),
-        LABEL(KEY_KATAKANAHIRAGANA),
-        LABEL(KEY_MUHENKAN),
-        LABEL(KEY_KPJPCOMMA),
-        LABEL(KEY_KPENTER),
-        LABEL(KEY_RIGHTCTRL),
-        LABEL(KEY_KPSLASH),
-        LABEL(KEY_SYSRQ),
-        LABEL(KEY_RIGHTALT),
-        LABEL(KEY_LINEFEED),
-        LABEL(KEY_HOME),
-        LABEL(KEY_UP),
-        LABEL(KEY_PAGEUP),
-        LABEL(KEY_LEFT),
-        LABEL(KEY_RIGHT),
-        LABEL(KEY_END),
-        LABEL(KEY_DOWN),
-        LABEL(KEY_PAGEDOWN),
-        LABEL(KEY_INSERT),
-        LABEL(KEY_DELETE),
-        LABEL(KEY_MACRO),
-        LABEL(KEY_MUTE),
-        LABEL(KEY_VOLUMEDOWN),
-        LABEL(KEY_VOLUMEUP),
-        LABEL(KEY_POWER),
-        LABEL(KEY_KPEQUAL),
-        LABEL(KEY_KPPLUSMINUS),
-        LABEL(KEY_PAUSE),
-        LABEL(KEY_SCALE),
-        LABEL(KEY_KPCOMMA),
-        LABEL(KEY_HANGEUL),
-        LABEL(KEY_HANGUEL),
-        LABEL(KEY_HANJA),
-        LABEL(KEY_YEN),
-        LABEL(KEY_LEFTMETA),
-        LABEL(KEY_RIGHTMETA),
-        LABEL(KEY_COMPOSE),
-        LABEL(KEY_STOP),
-        LABEL(KEY_AGAIN),
-        LABEL(KEY_PROPS),
-        LABEL(KEY_UNDO),
-        LABEL(KEY_FRONT),
-        LABEL(KEY_COPY),
-        LABEL(KEY_OPEN),
-        LABEL(KEY_PASTE),
-        LABEL(KEY_FIND),
-        LABEL(KEY_CUT),
-        LABEL(KEY_HELP),
-        LABEL(KEY_MENU),
-        LABEL(KEY_CALC),
-        LABEL(KEY_SETUP),
-        LABEL(KEY_SLEEP),
-        LABEL(KEY_WAKEUP),
-        LABEL(KEY_FILE),
-        LABEL(KEY_SENDFILE),
-        LABEL(KEY_DELETEFILE),
-        LABEL(KEY_XFER),
-        LABEL(KEY_PROG1),
-        LABEL(KEY_PROG2),
-        LABEL(KEY_WWW),
-        LABEL(KEY_MSDOS),
-        LABEL(KEY_COFFEE),
-        LABEL(KEY_SCREENLOCK),
-        LABEL(KEY_DIRECTION),
-        LABEL(KEY_CYCLEWINDOWS),
-        LABEL(KEY_MAIL),
-        LABEL(KEY_BOOKMARKS),
-        LABEL(KEY_COMPUTER),
-        LABEL(KEY_BACK),
-        LABEL(KEY_FORWARD),
-        LABEL(KEY_CLOSECD),
-        LABEL(KEY_EJECTCD),
-        LABEL(KEY_EJECTCLOSECD),
-        LABEL(KEY_NEXTSONG),
-        LABEL(KEY_PLAYPAUSE),
-        LABEL(KEY_PREVIOUSSONG),
-        LABEL(KEY_STOPCD),
-        LABEL(KEY_RECORD),
-        LABEL(KEY_REWIND),
-        LABEL(KEY_PHONE),
-        LABEL(KEY_ISO),
-        LABEL(KEY_CONFIG),
-        LABEL(KEY_HOMEPAGE),
-        LABEL(KEY_REFRESH),
-        LABEL(KEY_EXIT),
-        LABEL(KEY_MOVE),
-        LABEL(KEY_EDIT),
-        LABEL(KEY_SCROLLUP),
-        LABEL(KEY_SCROLLDOWN),
-        LABEL(KEY_KPLEFTPAREN),
-        LABEL(KEY_KPRIGHTPAREN),
-        LABEL(KEY_NEW),
-        LABEL(KEY_REDO),
-        LABEL(KEY_F13),
-        LABEL(KEY_F14),
-        LABEL(KEY_F15),
-        LABEL(KEY_F16),
-        LABEL(KEY_F17),
-        LABEL(KEY_F18),
-        LABEL(KEY_F19),
-        LABEL(KEY_F20),
-        LABEL(KEY_F21),
-        LABEL(KEY_F22),
-        LABEL(KEY_F23),
-        LABEL(KEY_F24),
-        LABEL(KEY_PLAYCD),
-        LABEL(KEY_PAUSECD),
-        LABEL(KEY_PROG3),
-        LABEL(KEY_PROG4),
-        LABEL(KEY_DASHBOARD),
-        LABEL(KEY_SUSPEND),
-        LABEL(KEY_CLOSE),
-        LABEL(KEY_PLAY),
-        LABEL(KEY_FASTFORWARD),
-        LABEL(KEY_BASSBOOST),
-        LABEL(KEY_PRINT),
-        LABEL(KEY_HP),
-        LABEL(KEY_CAMERA),
-        LABEL(KEY_SOUND),
-        LABEL(KEY_QUESTION),
-        LABEL(KEY_EMAIL),
-        LABEL(KEY_CHAT),
-        LABEL(KEY_SEARCH),
-        LABEL(KEY_CONNECT),
-        LABEL(KEY_FINANCE),
-        LABEL(KEY_SPORT),
-        LABEL(KEY_SHOP),
-        LABEL(KEY_ALTERASE),
-        LABEL(KEY_CANCEL),
-        LABEL(KEY_BRIGHTNESSDOWN),
-        LABEL(KEY_BRIGHTNESSUP),
-        LABEL(KEY_MEDIA),
-        LABEL(KEY_SWITCHVIDEOMODE),
-        LABEL(KEY_KBDILLUMTOGGLE),
-        LABEL(KEY_KBDILLUMDOWN),
-        LABEL(KEY_KBDILLUMUP),
-        LABEL(KEY_SEND),
-        LABEL(KEY_REPLY),
-        LABEL(KEY_FORWARDMAIL),
-        LABEL(KEY_SAVE),
-        LABEL(KEY_DOCUMENTS),
-        LABEL(KEY_BATTERY),
-        LABEL(KEY_BLUETOOTH),
-        LABEL(KEY_WLAN),
-        LABEL(KEY_UWB),
-        LABEL(KEY_UNKNOWN),
-        LABEL(KEY_VIDEO_NEXT),
-        LABEL(KEY_VIDEO_PREV),
-        LABEL(KEY_BRIGHTNESS_CYCLE),
-        LABEL(KEY_BRIGHTNESS_ZERO),
-        LABEL(KEY_DISPLAY_OFF),
-        LABEL(KEY_WIMAX),
-        LABEL(KEY_RFKILL),
-        LABEL(BTN_0),
-        LABEL(BTN_1),
-        LABEL(BTN_2),
-        LABEL(BTN_3),
-        LABEL(BTN_4),
-        LABEL(BTN_5),
-        LABEL(BTN_6),
-        LABEL(BTN_7),
-        LABEL(BTN_8),
-        LABEL(BTN_9),
-        LABEL(BTN_LEFT),
-        LABEL(BTN_RIGHT),
-        LABEL(BTN_MIDDLE),
-        LABEL(BTN_SIDE),
-        LABEL(BTN_EXTRA),
-        LABEL(BTN_FORWARD),
-        LABEL(BTN_BACK),
-        LABEL(BTN_TASK),
-        LABEL(BTN_JOYSTICK),
-        LABEL(BTN_TRIGGER),
-        LABEL(BTN_THUMB),
-        LABEL(BTN_THUMB2),
-        LABEL(BTN_TOP),
-        LABEL(BTN_TOP2),
-        LABEL(BTN_PINKIE),
-        LABEL(BTN_BASE),
-        LABEL(BTN_BASE2),
-        LABEL(BTN_BASE3),
-        LABEL(BTN_BASE4),
-        LABEL(BTN_BASE5),
-        LABEL(BTN_BASE6),
-        LABEL(BTN_DEAD),
-        LABEL(BTN_A),
-        LABEL(BTN_B),
-        LABEL(BTN_C),
-        LABEL(BTN_X),
-        LABEL(BTN_Y),
-        LABEL(BTN_Z),
-        LABEL(BTN_TL),
-        LABEL(BTN_TR),
-        LABEL(BTN_TL2),
-        LABEL(BTN_TR2),
-        LABEL(BTN_SELECT),
-        LABEL(BTN_START),
-        LABEL(BTN_MODE),
-        LABEL(BTN_THUMBL),
-        LABEL(BTN_THUMBR),
-        LABEL(BTN_TOOL_PEN),
-        LABEL(BTN_TOOL_RUBBER),
-        LABEL(BTN_TOOL_BRUSH),
-        LABEL(BTN_TOOL_PENCIL),
-        LABEL(BTN_TOOL_AIRBRUSH),
-        LABEL(BTN_TOOL_FINGER),
-        LABEL(BTN_TOOL_MOUSE),
-        LABEL(BTN_TOOL_LENS),
-        LABEL(BTN_TOUCH),
-        LABEL(BTN_STYLUS),
-        LABEL(BTN_STYLUS2),
-        LABEL(BTN_TOOL_DOUBLETAP),
-        LABEL(BTN_TOOL_TRIPLETAP),
-        LABEL(BTN_TOOL_QUADTAP),
-        LABEL(BTN_GEAR_DOWN),
-        LABEL(BTN_GEAR_UP),
-        LABEL(KEY_OK),
-        LABEL(KEY_SELECT),
-        LABEL(KEY_GOTO),
-        LABEL(KEY_CLEAR),
-        LABEL(KEY_POWER2),
-        LABEL(KEY_OPTION),
-        LABEL(KEY_INFO),
-        LABEL(KEY_TIME),
-        LABEL(KEY_VENDOR),
-        LABEL(KEY_ARCHIVE),
-        LABEL(KEY_PROGRAM),
-        LABEL(KEY_CHANNEL),
-        LABEL(KEY_FAVORITES),
-        LABEL(KEY_EPG),
-        LABEL(KEY_PVR),
-        LABEL(KEY_MHP),
-        LABEL(KEY_LANGUAGE),
-        LABEL(KEY_TITLE),
-        LABEL(KEY_SUBTITLE),
-        LABEL(KEY_ANGLE),
-        LABEL(KEY_ZOOM),
-        LABEL(KEY_MODE),
-        LABEL(KEY_KEYBOARD),
-        LABEL(KEY_SCREEN),
-        LABEL(KEY_PC),
-        LABEL(KEY_TV),
-        LABEL(KEY_TV2),
-        LABEL(KEY_VCR),
-        LABEL(KEY_VCR2),
-        LABEL(KEY_SAT),
-        LABEL(KEY_SAT2),
-        LABEL(KEY_CD),
-        LABEL(KEY_TAPE),
-        LABEL(KEY_RADIO),
-        LABEL(KEY_TUNER),
-        LABEL(KEY_PLAYER),
-        LABEL(KEY_TEXT),
-        LABEL(KEY_DVD),
-        LABEL(KEY_AUX),
-        LABEL(KEY_MP3),
-        LABEL(KEY_AUDIO),
-        LABEL(KEY_VIDEO),
-        LABEL(KEY_DIRECTORY),
-        LABEL(KEY_LIST),
-        LABEL(KEY_MEMO),
-        LABEL(KEY_CALENDAR),
-        LABEL(KEY_RED),
-        LABEL(KEY_GREEN),
-        LABEL(KEY_YELLOW),
-        LABEL(KEY_BLUE),
-        LABEL(KEY_CHANNELUP),
-        LABEL(KEY_CHANNELDOWN),
-        LABEL(KEY_FIRST),
-        LABEL(KEY_LAST),
-        LABEL(KEY_AB),
-        LABEL(KEY_NEXT),
-        LABEL(KEY_RESTART),
-        LABEL(KEY_SLOW),
-        LABEL(KEY_SHUFFLE),
-        LABEL(KEY_BREAK),
-        LABEL(KEY_PREVIOUS),
-        LABEL(KEY_DIGITS),
-        LABEL(KEY_TEEN),
-        LABEL(KEY_TWEN),
-        LABEL(KEY_VIDEOPHONE),
-        LABEL(KEY_GAMES),
-        LABEL(KEY_ZOOMIN),
-        LABEL(KEY_ZOOMOUT),
-        LABEL(KEY_ZOOMRESET),
-        LABEL(KEY_WORDPROCESSOR),
-        LABEL(KEY_EDITOR),
-        LABEL(KEY_SPREADSHEET),
-        LABEL(KEY_GRAPHICSEDITOR),
-        LABEL(KEY_PRESENTATION),
-        LABEL(KEY_DATABASE),
-        LABEL(KEY_NEWS),
-        LABEL(KEY_VOICEMAIL),
-        LABEL(KEY_ADDRESSBOOK),
-        LABEL(KEY_MESSENGER),
-        LABEL(KEY_DISPLAYTOGGLE),
-        LABEL(KEY_SPELLCHECK),
-        LABEL(KEY_LOGOFF),
-        LABEL(KEY_DOLLAR),
-        LABEL(KEY_EURO),
-        LABEL(KEY_FRAMEBACK),
-        LABEL(KEY_FRAMEFORWARD),
-        LABEL(KEY_CONTEXT_MENU),
-        LABEL(KEY_MEDIA_REPEAT),
-        LABEL(KEY_10CHANNELSUP),
-        LABEL(KEY_10CHANNELSDOWN),
-        LABEL(KEY_IMAGES),
-        LABEL(KEY_DEL_EOL),
-        LABEL(KEY_DEL_EOS),
-        LABEL(KEY_INS_LINE),
-        LABEL(KEY_DEL_LINE),
-        LABEL(KEY_FN),
-        LABEL(KEY_FN_ESC),
-        LABEL(KEY_FN_F1),
-        LABEL(KEY_FN_F2),
-        LABEL(KEY_FN_F3),
-        LABEL(KEY_FN_F4),
-        LABEL(KEY_FN_F5),
-        LABEL(KEY_FN_F6),
-        LABEL(KEY_FN_F7),
-        LABEL(KEY_FN_F8),
-        LABEL(KEY_FN_F9),
-        LABEL(KEY_FN_F10),
-        LABEL(KEY_FN_F11),
-        LABEL(KEY_FN_F12),
-        LABEL(KEY_FN_1),
-        LABEL(KEY_FN_2),
-        LABEL(KEY_FN_D),
-        LABEL(KEY_FN_E),
-        LABEL(KEY_FN_F),
-        LABEL(KEY_FN_S),
-        LABEL(KEY_FN_B),
-        LABEL(KEY_BRL_DOT1),
-        LABEL(KEY_BRL_DOT2),
-        LABEL(KEY_BRL_DOT3),
-        LABEL(KEY_BRL_DOT4),
-        LABEL(KEY_BRL_DOT5),
-        LABEL(KEY_BRL_DOT6),
-        LABEL(KEY_BRL_DOT7),
-        LABEL(KEY_BRL_DOT8),
-        LABEL(KEY_BRL_DOT9),
-        LABEL(KEY_BRL_DOT10),
-        LABEL(KEY_NUMERIC_0),
-        LABEL(KEY_NUMERIC_1),
-        LABEL(KEY_NUMERIC_2),
-        LABEL(KEY_NUMERIC_3),
-        LABEL(KEY_NUMERIC_4),
-        LABEL(KEY_NUMERIC_5),
-        LABEL(KEY_NUMERIC_6),
-        LABEL(KEY_NUMERIC_7),
-        LABEL(KEY_NUMERIC_8),
-        LABEL(KEY_NUMERIC_9),
-        LABEL(KEY_NUMERIC_STAR),
-        LABEL(KEY_NUMERIC_POUND),
-        LABEL(KEY_CAMERA_FOCUS),
-        LABEL(KEY_WPS_BUTTON),
-        LABEL(KEY_TOUCHPAD_TOGGLE),
-        LABEL(KEY_TOUCHPAD_ON),
-        LABEL(KEY_TOUCHPAD_OFF),
-        LABEL(KEY_CAMERA_ZOOMIN),
-        LABEL(KEY_CAMERA_ZOOMOUT),
-        LABEL(KEY_CAMERA_UP),
-        LABEL(KEY_CAMERA_DOWN),
-        LABEL(KEY_CAMERA_LEFT),
-        LABEL(KEY_CAMERA_RIGHT),
-        LABEL(BTN_TRIGGER_HAPPY1),
-        LABEL(BTN_TRIGGER_HAPPY2),
-        LABEL(BTN_TRIGGER_HAPPY3),
-        LABEL(BTN_TRIGGER_HAPPY4),
-        LABEL(BTN_TRIGGER_HAPPY5),
-        LABEL(BTN_TRIGGER_HAPPY6),
-        LABEL(BTN_TRIGGER_HAPPY7),
-        LABEL(BTN_TRIGGER_HAPPY8),
-        LABEL(BTN_TRIGGER_HAPPY9),
-        LABEL(BTN_TRIGGER_HAPPY10),
-        LABEL(BTN_TRIGGER_HAPPY11),
-        LABEL(BTN_TRIGGER_HAPPY12),
-        LABEL(BTN_TRIGGER_HAPPY13),
-        LABEL(BTN_TRIGGER_HAPPY14),
-        LABEL(BTN_TRIGGER_HAPPY15),
-        LABEL(BTN_TRIGGER_HAPPY16),
-        LABEL(BTN_TRIGGER_HAPPY17),
-        LABEL(BTN_TRIGGER_HAPPY18),
-        LABEL(BTN_TRIGGER_HAPPY19),
-        LABEL(BTN_TRIGGER_HAPPY20),
-        LABEL(BTN_TRIGGER_HAPPY21),
-        LABEL(BTN_TRIGGER_HAPPY22),
-        LABEL(BTN_TRIGGER_HAPPY23),
-        LABEL(BTN_TRIGGER_HAPPY24),
-        LABEL(BTN_TRIGGER_HAPPY25),
-        LABEL(BTN_TRIGGER_HAPPY26),
-        LABEL(BTN_TRIGGER_HAPPY27),
-        LABEL(BTN_TRIGGER_HAPPY28),
-        LABEL(BTN_TRIGGER_HAPPY29),
-        LABEL(BTN_TRIGGER_HAPPY30),
-        LABEL(BTN_TRIGGER_HAPPY31),
-        LABEL(BTN_TRIGGER_HAPPY32),
-        LABEL(BTN_TRIGGER_HAPPY33),
-        LABEL(BTN_TRIGGER_HAPPY34),
-        LABEL(BTN_TRIGGER_HAPPY35),
-        LABEL(BTN_TRIGGER_HAPPY36),
-        LABEL(BTN_TRIGGER_HAPPY37),
-        LABEL(BTN_TRIGGER_HAPPY38),
-        LABEL(BTN_TRIGGER_HAPPY39),
-        LABEL(BTN_TRIGGER_HAPPY40),
-        LABEL_END,
-};
-
-static struct label rel_labels[] = {
-        LABEL(REL_X),
-        LABEL(REL_Y),
-        LABEL(REL_Z),
-        LABEL(REL_RX),
-        LABEL(REL_RY),
-        LABEL(REL_RZ),
-        LABEL(REL_HWHEEL),
-        LABEL(REL_DIAL),
-        LABEL(REL_WHEEL),
-        LABEL(REL_MISC),
-        LABEL_END,
-};
-
-static struct label abs_labels[] = {
-        LABEL(ABS_X),
-        LABEL(ABS_Y),
-        LABEL(ABS_Z),
-        LABEL(ABS_RX),
-        LABEL(ABS_RY),
-        LABEL(ABS_RZ),
-        LABEL(ABS_THROTTLE),
-        LABEL(ABS_RUDDER),
-        LABEL(ABS_WHEEL),
-        LABEL(ABS_GAS),
-        LABEL(ABS_BRAKE),
-        LABEL(ABS_HAT0X),
-        LABEL(ABS_HAT0Y),
-        LABEL(ABS_HAT1X),
-        LABEL(ABS_HAT1Y),
-        LABEL(ABS_HAT2X),
-        LABEL(ABS_HAT2Y),
-        LABEL(ABS_HAT3X),
-        LABEL(ABS_HAT3Y),
-        LABEL(ABS_PRESSURE),
-        LABEL(ABS_DISTANCE),
-        LABEL(ABS_TILT_X),
-        LABEL(ABS_TILT_Y),
-        LABEL(ABS_TOOL_WIDTH),
-        LABEL(ABS_VOLUME),
-        LABEL(ABS_MISC),
-        LABEL(ABS_MT_SLOT),
-        LABEL(ABS_MT_TOUCH_MAJOR),
-        LABEL(ABS_MT_TOUCH_MINOR),
-        LABEL(ABS_MT_WIDTH_MAJOR),
-        LABEL(ABS_MT_WIDTH_MINOR),
-        LABEL(ABS_MT_ORIENTATION),
-        LABEL(ABS_MT_POSITION_X),
-        LABEL(ABS_MT_POSITION_Y),
-        LABEL(ABS_MT_TOOL_TYPE),
-        LABEL(ABS_MT_BLOB_ID),
-        LABEL(ABS_MT_TRACKING_ID),
-        LABEL(ABS_MT_PRESSURE),
-        LABEL(ABS_MT_DISTANCE),
-        LABEL_END,
-};
-
-static struct label sw_labels[] = {
-        LABEL(SW_LID),
-        LABEL(SW_TABLET_MODE),
-        LABEL(SW_HEADPHONE_INSERT),
-        LABEL(SW_RFKILL_ALL),
-        LABEL(SW_RADIO),
-        LABEL(SW_MICROPHONE_INSERT),
-        LABEL(SW_DOCK),
-        LABEL(SW_LINEOUT_INSERT),
-        LABEL(SW_JACK_PHYSICAL_INSERT),
-        LABEL(SW_VIDEOOUT_INSERT),
-        LABEL(SW_CAMERA_LENS_COVER),
-        LABEL(SW_KEYPAD_SLIDE),
-        LABEL(SW_FRONT_PROXIMITY),
-        LABEL(SW_ROTATE_LOCK),
-        LABEL_END,
-};
-
-static struct label msc_labels[] = {
-        LABEL(MSC_SERIAL),
-        LABEL(MSC_PULSELED),
-        LABEL(MSC_GESTURE),
-        LABEL(MSC_RAW),
-        LABEL(MSC_SCAN),
-        LABEL_END,
-};
-
-static struct label led_labels[] = {
-        LABEL(LED_NUML),
-        LABEL(LED_CAPSL),
-        LABEL(LED_SCROLLL),
-        LABEL(LED_COMPOSE),
-        LABEL(LED_KANA),
-        LABEL(LED_SLEEP),
-        LABEL(LED_SUSPEND),
-        LABEL(LED_MUTE),
-        LABEL(LED_MISC),
-        LABEL(LED_MAIL),
-        LABEL(LED_CHARGING),
-        LABEL_END,
-};
-
-static struct label rep_labels[] = {
-        LABEL(REP_DELAY),
-        LABEL(REP_PERIOD),
-        LABEL_END,
-};
-
-static struct label snd_labels[] = {
-        LABEL(SND_CLICK),
-        LABEL(SND_BELL),
-        LABEL(SND_TONE),
-        LABEL_END,
-};
-
-#if 0
-static struct label id_labels[] = {
-        LABEL(ID_BUS),
-        LABEL(ID_VENDOR),
-        LABEL(ID_PRODUCT),
-        LABEL(ID_VERSION),
-        LABEL_END,
-};
-
-static struct label bus_labels[] = {
-        LABEL(BUS_PCI),
-        LABEL(BUS_ISAPNP),
-        LABEL(BUS_USB),
-        LABEL(BUS_HIL),
-        LABEL(BUS_BLUETOOTH),
-        LABEL(BUS_VIRTUAL),
-        LABEL(BUS_ISA),
-        LABEL(BUS_I8042),
-        LABEL(BUS_XTKBD),
-        LABEL(BUS_RS232),
-        LABEL(BUS_GAMEPORT),
-        LABEL(BUS_PARPORT),
-        LABEL(BUS_AMIGA),
-        LABEL(BUS_ADB),
-        LABEL(BUS_I2C),
-        LABEL(BUS_HOST),
-        LABEL(BUS_GSC),
-        LABEL(BUS_ATARI),
-        LABEL(BUS_SPI),
-        LABEL_END,
-};
-#endif
-
-static struct label mt_tool_labels[] = {
-        LABEL(MT_TOOL_FINGER),
-        LABEL(MT_TOOL_PEN),
-        LABEL(MT_TOOL_MAX),
-        LABEL_END,
-};
-
-static struct label ff_status_labels[] = {
-        LABEL(FF_STATUS_STOPPED),
-        LABEL(FF_STATUS_PLAYING),
-        LABEL(FF_STATUS_MAX),
-        LABEL_END,
-};
-
-static struct label ff_labels[] = {
-        LABEL(FF_RUMBLE),
-        LABEL(FF_PERIODIC),
-        LABEL(FF_CONSTANT),
-        LABEL(FF_SPRING),
-        LABEL(FF_FRICTION),
-        LABEL(FF_DAMPER),
-        LABEL(FF_INERTIA),
-        LABEL(FF_RAMP),
-        LABEL(FF_SQUARE),
-        LABEL(FF_TRIANGLE),
-        LABEL(FF_SINE),
-        LABEL(FF_SAW_UP),
-        LABEL(FF_SAW_DOWN),
-        LABEL(FF_CUSTOM),
-        LABEL(FF_GAIN),
-        LABEL(FF_AUTOCENTER),
-        LABEL_END,
-};
-
-static struct label key_value_labels[] = {
-        { "UP", 0 },
-        { "DOWN", 1 },
-        { "REPEAT", 2 },
-        LABEL_END,
-};
diff --git a/toolbox/getprop.c b/toolbox/getprop.c
deleted file mode 100644
index dcc0ea0..0000000
--- a/toolbox/getprop.c
+++ /dev/null
@@ -1,50 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <cutils/properties.h>
-
-#include "dynarray.h"
-
-static void record_prop(const char* key, const char* name, void* opaque)
-{
-    strlist_t* list = opaque;
-    char temp[PROP_VALUE_MAX + PROP_NAME_MAX + 16];
-    snprintf(temp, sizeof temp, "[%s]: [%s]", key, name);
-    strlist_append_dup(list, temp);
-}
-
-static void list_properties(void)
-{
-    strlist_t  list[1] = { STRLIST_INITIALIZER };
-
-    /* Record properties in the string list */
-    (void)property_list(record_prop, list);
-
-    /* Sort everything */
-    strlist_sort(list);
-
-    /* print everything */
-    STRLIST_FOREACH(list, str, printf("%s\n", str));
-
-    /* voila */
-    strlist_done(list);
-}
-
-int getprop_main(int argc, char *argv[])
-{
-    if (argc == 1) {
-        list_properties();
-    } else {
-        char value[PROPERTY_VALUE_MAX];
-        char *default_value;
-        if(argc > 2) {
-            default_value = argv[2];
-        } else {
-            default_value = "";
-        }
-
-        property_get(argv[1], value, default_value);
-        printf("%s\n", value);
-    }
-    return 0;
-}
diff --git a/toolbox/getsebool.c b/toolbox/getsebool.c
deleted file mode 100644
index aab5200..0000000
--- a/toolbox/getsebool.c
+++ /dev/null
@@ -1,104 +0,0 @@
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <getopt.h>
-#include <errno.h>
-#include <string.h>
-#include <selinux/selinux.h>
-
-static void usage(const char *progname)
-{
-    fprintf(stderr, "usage:  %s -a or %s boolean...\n", progname, progname);
-    exit(1);
-}
-
-int getsebool_main(int argc, char **argv)
-{
-    int i, get_all = 0, rc = 0, active, pending, len = 0, opt;
-    char **names;
-
-    while ((opt = getopt(argc, argv, "a")) > 0) {
-        switch (opt) {
-        case 'a':
-            if (argc > 2)
-                usage(argv[0]);
-            if (is_selinux_enabled() <= 0) {
-                fprintf(stderr, "%s:  SELinux is disabled\n",
-                        argv[0]);
-                return 1;
-            }
-            errno = 0;
-            rc = security_get_boolean_names(&names, &len);
-            if (rc) {
-                fprintf(stderr,
-                        "%s:  Unable to get boolean names:  %s\n",
-                        argv[0], strerror(errno));
-                return 1;
-            }
-            if (!len) {
-                printf("No booleans\n");
-                return 0;
-            }
-            get_all = 1;
-            break;
-        default:
-            usage(argv[0]);
-        }
-    }
-
-    if (is_selinux_enabled() <= 0) {
-        fprintf(stderr, "%s:  SELinux is disabled\n", argv[0]);
-        return 1;
-    }
-    if (!len) {
-        if (argc < 2)
-            usage(argv[0]);
-        len = argc - 1;
-        names = malloc(sizeof(char *) * len);
-        if (!names) {
-            fprintf(stderr, "%s:  out of memory\n", argv[0]);
-            return 2;
-        }
-        for (i = 0; i < len; i++) {
-            names[i] = strdup(argv[i + 1]);
-            if (!names[i]) {
-                fprintf(stderr, "%s:  out of memory\n",
-                        argv[0]);
-                return 2;
-            }
-        }
-    }
-
-    for (i = 0; i < len; i++) {
-        active = security_get_boolean_active(names[i]);
-        if (active < 0) {
-            if (get_all && errno == EACCES)
-                continue;
-            fprintf(stderr, "Error getting active value for %s\n",
-                    names[i]);
-            rc = -1;
-            goto out;
-        }
-        pending = security_get_boolean_pending(names[i]);
-        if (pending < 0) {
-            fprintf(stderr, "Error getting pending value for %s\n",
-                    names[i]);
-            rc = -1;
-            goto out;
-        }
-        if (pending != active) {
-            printf("%s --> %s pending: %s\n", names[i],
-                   (active ? "on" : "off"),
-                   (pending ? "on" : "off"));
-        } else {
-            printf("%s --> %s\n", names[i],
-                   (active ? "on" : "off"));
-        }
-    }
-
-out:
-    for (i = 0; i < len; i++)
-        free(names[i]);
-    free(names);
-    return rc;
-}
diff --git a/toolbox/hd.c b/toolbox/hd.c
deleted file mode 100644
index 7c9998e..0000000
--- a/toolbox/hd.c
+++ /dev/null
@@ -1,97 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-
-int hd_main(int argc, char *argv[])
-{
-    int c;
-    int fd;
-	unsigned char buf[4096];
-    int res;
-	int read_len;
-	int i;
-	int filepos = 0;
-	int sum;
-	int lsum;
-
-	int base = -1;
-	int count = 0;
-	int repeat = 0;
-
-    do {
-        c = getopt(argc, argv, "b:c:r:");
-        if (c == EOF)
-            break;
-        switch (c) {
-        case 'b':
-            base = strtol(optarg, NULL, 0);
-            break;
-        case 'c':
-            count = strtol(optarg, NULL, 0);
-            break;
-		case 'r':
-			repeat = strtol(optarg, NULL, 0);
-			break;
-        case '?':
-            fprintf(stderr, "%s: invalid option -%c\n",
-                argv[0], optopt);
-            exit(1);
-        }
-    } while (1);
-
-    if (optind + 1 != argc) {
-        fprintf(stderr, "Usage: %s [-b base] [-c count] [-r delay] file\n", argv[0]);
-        exit(1);
-    }
-
-    fd = open(argv[optind], O_RDONLY);
-    if(fd < 0) {
-        fprintf(stderr, "could not open %s, %s\n", argv[optind], strerror(errno));
-        return 1;
-    }
-
-	do {
-		if(base >= 0) {
-			lseek(fd, base, SEEK_SET);
-			filepos = base;
-		}
-		sum = 0;
-		lsum = 0;
-	    while(1) {
-			read_len = sizeof(buf);
-			if(count > 0 && base + count - filepos < read_len)
-				read_len = base + count - filepos;
-	        res = read(fd, &buf, read_len);
-			if(res == 0)
-				break;
-			for(i = 0; i < res; i++) {
-				if((i & 15) == 0) {
-					printf("%08x: ", filepos + i);
-				}
-				lsum += buf[i];
-				sum += buf[i];
-				printf("%02x ", buf[i]);
-				if(((i & 15) == 15) || (i == res - 1)) {
-					printf("s %x\n", lsum);
-					lsum = 0;
-				}
-			}
-			if(res < 0) {
-				printf("Read error on %s, offset %d len %d, %s\n", argv[optind], filepos, read_len, strerror(errno));
-				return 1;
-			}
-			filepos += res;
-			if(filepos == base + count)
-				break;
-	    }
-		printf("sum %x\n", sum);
-		if(repeat)
-			sleep(repeat);
-	} while(repeat);
-	return 0;
-}
diff --git a/toolbox/id.c b/toolbox/id.c
deleted file mode 100644
index 8ec79c1..0000000
--- a/toolbox/id.c
+++ /dev/null
@@ -1,57 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <pwd.h>
-#include <grp.h>
-#include <selinux/selinux.h>
-
-static void print_uid(uid_t uid)
-{
-    struct passwd *pw = getpwuid(uid);
-
-    if (pw) {
-        printf("%d(%s)", uid, pw->pw_name);
-    } else {
-        printf("%d",uid);
-    }
-}
-
-static void print_gid(gid_t gid)
-{
-    struct group *gr = getgrgid(gid);
-    if (gr) {
-        printf("%d(%s)", gid, gr->gr_name);
-    } else {
-        printf("%d",gid);
-    }
-}
-
-int id_main(int argc, char **argv)
-{
-    gid_t list[64];
-    int n, max;
-    char *secctx;
-
-    max = getgroups(64, list);
-    if (max < 0) max = 0;
-
-    printf("uid=");
-    print_uid(getuid());
-    printf(" gid=");
-    print_gid(getgid());
-    if (max) {
-        printf(" groups=");
-        print_gid(list[0]);
-        for(n = 1; n < max; n++) {
-            printf(",");
-            print_gid(list[n]);
-        }
-    }
-    if (getcon(&secctx) == 0) {
-        printf(" context=%s", secctx);
-        free(secctx);
-    }
-    printf("\n");
-    return 0;
-}
diff --git a/toolbox/ifconfig.c b/toolbox/ifconfig.c
deleted file mode 100644
index b953176..0000000
--- a/toolbox/ifconfig.c
+++ /dev/null
@@ -1,157 +0,0 @@
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <errno.h>
-#include <string.h>
-#include <ctype.h>
-
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <linux/if.h>
-#include <linux/sockios.h>
-#include <arpa/inet.h>
-
-static void die(const char *s)
-{
-    fprintf(stderr,"error: %s (%s)\n", s, strerror(errno));
-    exit(-1);
-}
-
-static void setflags(int s, struct ifreq *ifr, int set, int clr)
-{
-    if(ioctl(s, SIOCGIFFLAGS, ifr) < 0) die("SIOCGIFFLAGS");
-    ifr->ifr_flags = (ifr->ifr_flags & (~clr)) | set;
-    if(ioctl(s, SIOCSIFFLAGS, ifr) < 0) die("SIOCSIFFLAGS");
-}
-
-static inline void init_sockaddr_in(struct sockaddr_in *sin, const char *addr)
-{
-    sin->sin_family = AF_INET;
-    sin->sin_port = 0;
-    sin->sin_addr.s_addr = inet_addr(addr);
-}
-
-static void setmtu(int s, struct ifreq *ifr, const char *mtu)
-{
-    int m = atoi(mtu);
-    ifr->ifr_mtu = m;
-    if(ioctl(s, SIOCSIFMTU, ifr) < 0) die("SIOCSIFMTU");
-}
-static void setdstaddr(int s, struct ifreq *ifr, const char *addr)
-{
-    init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_dstaddr, addr);
-    if(ioctl(s, SIOCSIFDSTADDR, ifr) < 0) die("SIOCSIFDSTADDR");
-}
-
-static void setnetmask(int s, struct ifreq *ifr, const char *addr)
-{
-    init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_netmask, addr);
-    if(ioctl(s, SIOCSIFNETMASK, ifr) < 0) die("SIOCSIFNETMASK");
-}
-
-static void setaddr(int s, struct ifreq *ifr, const char *addr)
-{
-    init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_addr, addr);
-    if(ioctl(s, SIOCSIFADDR, ifr) < 0) die("SIOCSIFADDR");
-}
-
-int ifconfig_main(int argc, char *argv[])
-{
-    struct ifreq ifr;
-    int s;
-    unsigned int flags;
-    char astring[20];
-    char mstring[20];
-    char *updown, *brdcst, *loopbk, *ppp, *running, *multi;
-
-    argc--;
-    argv++;
-
-    if(argc == 0) return 0;
-
-    memset(&ifr, 0, sizeof(struct ifreq));
-    strncpy(ifr.ifr_name, argv[0], IFNAMSIZ);
-    ifr.ifr_name[IFNAMSIZ-1] = 0;
-    argc--, argv++;
-
-    if((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
-        die("cannot open control socket\n");
-    }
-
-    if (argc == 0) {
-        if (ioctl(s, SIOCGIFADDR, &ifr) < 0) {
-            perror(ifr.ifr_name);
-            return -1;
-        } else
-            strlcpy(astring,
-                   inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr),
-                   sizeof(astring));
-
-        if (ioctl(s, SIOCGIFNETMASK, &ifr) < 0) {
-            perror(ifr.ifr_name);
-            return -1;
-        } else
-            strlcpy(mstring,
-                   inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr),
-                   sizeof(mstring));
-
-        if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
-            perror(ifr.ifr_name);
-            return -1;
-        } else
-            flags = ifr.ifr_flags;
-
-        printf("%s: ip %s mask %s flags [", ifr.ifr_name,
-               astring,
-               mstring
-               );
-
-        updown =  (flags & IFF_UP)           ? "up" : "down";
-        brdcst =  (flags & IFF_BROADCAST)    ? " broadcast" : "";
-        loopbk =  (flags & IFF_LOOPBACK)     ? " loopback" : "";
-        ppp =     (flags & IFF_POINTOPOINT)  ? " point-to-point" : "";
-        running = (flags & IFF_RUNNING)      ? " running" : "";
-        multi =   (flags & IFF_MULTICAST)    ? " multicast" : "";
-        printf("%s%s%s%s%s%s]\n", updown, brdcst, loopbk, ppp, running, multi);
-        return 0;
-    }
-    
-    while(argc > 0) {
-        if (!strcmp(argv[0], "up")) {
-            setflags(s, &ifr, IFF_UP, 0);
-        } else if (!strcmp(argv[0], "mtu")) {
-            argc--, argv++;
-            if (!argc) {
-                errno = EINVAL;
-                die("expecting a value for parameter \"mtu\"");
-            }
-            setmtu(s, &ifr, argv[0]);
-        } else if (!strcmp(argv[0], "-pointopoint")) {
-            setflags(s, &ifr, IFF_POINTOPOINT, 1);
-        } else if (!strcmp(argv[0], "pointopoint")) {
-            argc--, argv++;
-            if (!argc) { 
-                errno = EINVAL;
-                die("expecting an IP address for parameter \"pointtopoint\"");
-            }
-            setdstaddr(s, &ifr, argv[0]);
-            setflags(s, &ifr, IFF_POINTOPOINT, 0);
-        } else if (!strcmp(argv[0], "down")) {
-            setflags(s, &ifr, 0, IFF_UP);
-        } else if (!strcmp(argv[0], "netmask")) {
-            argc--, argv++;
-            if (!argc) { 
-                errno = EINVAL;
-                die("expecting an IP address for parameter \"netmask\"");
-            }
-            setnetmask(s, &ifr, argv[0]);
-        } else if (isdigit(argv[0][0])) {
-            setaddr(s, &ifr, argv[0]);
-            setflags(s, &ifr, IFF_UP, 0);
-        }
-        argc--, argv++;
-    }
-    return 0;
-}
diff --git a/toolbox/insmod.c b/toolbox/insmod.c
deleted file mode 100644
index d252433..0000000
--- a/toolbox/insmod.c
+++ /dev/null
@@ -1,97 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <errno.h>
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-extern int init_module(void *, unsigned long, const char *);
-
-static void *read_file(const char *filename, ssize_t *_size)
-{
-	int ret, fd;
-	struct stat sb;
-	ssize_t size;
-	void *buffer = NULL;
-
-	/* open the file */
-	fd = open(filename, O_RDONLY);
-	if (fd < 0)
-		return NULL;
-
-	/* find out how big it is */
-	if (fstat(fd, &sb) < 0)
-		goto bail;
-	size = sb.st_size;
-
-	/* allocate memory for it to be read into */
-	buffer = malloc(size);
-	if (!buffer)
-		goto bail;
-
-	/* slurp it into our buffer */
-	ret = read(fd, buffer, size);
-	if (ret != size)
-		goto bail;
-
-	/* let the caller know how big it is */
-	*_size = size;
-
-bail:
-	close(fd);
-	return buffer;
-}
-
-int insmod_main(int argc, char **argv)
-{
-	void *file;
-	ssize_t size = 0;
-	char opts[1024];
-	int ret;
-
-	/* make sure we've got an argument */
-	if (argc < 2) {
-		fprintf(stderr, "usage: insmod <module.o>\n");
-		return -1;
-	}
-
-	/* read the file into memory */
-	file = read_file(argv[1], &size);
-	if (!file) {
-		fprintf(stderr, "insmod: can't open '%s'\n", argv[1]);
-		return -1;
-	}
-
-	opts[0] = '\0';
-	if (argc > 2) {
-		int i, len;
-		char *end = opts + sizeof(opts) - 1;
-		char *ptr = opts;
-
-		for (i = 2; (i < argc) && (ptr < end); i++) {
-			len = MIN(strlen(argv[i]), (size_t)(end - ptr));
-			memcpy(ptr, argv[i], len);
-			ptr += len;
-			*ptr++ = ' ';
-		}
-		*(ptr - 1) = '\0';
-	}
-
-	/* pass it to the kernel */
-	ret = init_module(file, size, opts);
-	if (ret != 0) {
-		fprintf(stderr,
-                "insmod: init_module '%s' failed (%s)\n",
-                argv[1], strerror(errno));
-	}
-
-	/* free the file buffer */
-	free(file);
-
-	return ret;
-}
-
diff --git a/toolbox/ioctl.c b/toolbox/ioctl.c
index fd90812..093e467 100644
--- a/toolbox/ioctl.c
+++ b/toolbox/ioctl.c
@@ -1,35 +1,81 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
+/*
+ * 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 <linux/kd.h>
-#include <linux/vt.h>
-#include <errno.h>
-#include <pthread.h>
 #include <sys/ioctl.h>
+#include <unistd.h>
 
-int ioctl_main(int argc, char *argv[])
-{
-    int c;
-    int fd;
-    int res;
+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;
-    uint32_t ioctl_nr;
+
     void *ioctl_args = NULL;
     uint8_t *ioctl_argp;
     uint8_t *ioctl_argp_save = NULL;
     int rem;
 
-    do {
-        c = getopt(argc, argv, "rdl:a:h");
-        if (c == EOF)
-            break;
+    int c;
+    while ((c = getopt(argc, argv, "rdl:a:h")) != -1) {
         switch (c) {
         case 'r':
             read_only = 1;
@@ -38,43 +84,44 @@
             direct_arg = 1;
             break;
         case 'l':
-            length = strtol(optarg, NULL, 0);
+            length = xstrtoi(optarg, "length");
             break;
         case 'a':
-            arg_size = strtol(optarg, NULL, 0);
+            arg_size = xstrtoi(optarg, "argument size");
             break;
         case 'h':
-            fprintf(stderr, "%s [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>\n"
-                    "  -l <lenght>   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", argv[0]);
-            return -1;
-        case '?':
-            fprintf(stderr, "%s: invalid option -%c\n",
-                argv[0], optopt);
-            exit(1);
+            usage();
+            break;
+        default:
+            error(1, 0, "invalid option -%c", optopt);
         }
-    } while (1);
-
-    if(optind + 2 > argc) {
-        fprintf(stderr, "%s: too few arguments\n", argv[0]);
-        exit(1);
     }
 
-    if (!strcmp(argv[optind], "-")) {
+    if (optind + 2 > argc) {
+        usage();
+    }
+
+    const char* device = argv[optind];
+    int fd;
+    if (strcmp(device, "-") == 0) {
         fd = STDIN_FILENO;
     } else {
-        fd = open(argv[optind], read_only ? O_RDONLY : (O_RDWR | O_SYNC));
-        if (fd < 0) {
-            fprintf(stderr, "cannot open %s\n", argv[optind]);
-            return 1;
+        fd = open(device, read_only ? O_RDONLY : (O_RDWR | O_SYNC));
+        if (fd == -1) {
+            error(1, errno, "cannot open %s", argv[optind]);
         }
     }
     optind++;
-    
-    ioctl_nr = strtol(argv[optind], NULL, 0);
+
+    // 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) {
@@ -90,11 +137,10 @@
 
         ioctl_argp_save = ioctl_argp = ioctl_args;
         rem = length;
-        while(optind < argc) {
+        while (optind < argc) {
             uint64_t tmp = strtoull(argv[optind], NULL, 0);
-            if(rem < arg_size) {
-                fprintf(stderr, "%s: too many arguments\n", argv[0]);
-                exit(1);
+            if (rem < arg_size) {
+                error(1, 0, "too many arguments");
             }
             memcpy(ioctl_argp, &tmp, arg_size);
             ioctl_argp += arg_size;
@@ -107,8 +153,9 @@
     while(rem--) {
         printf(" 0x%02x", *ioctl_argp_save++);
     }
-    printf("\n");
+    printf(" to %s\n", device);
 
+    int res;
     if(direct_arg)
         res = ioctl(fd, ioctl_nr, *(uint32_t*)ioctl_args);
     else if(length)
@@ -117,10 +164,10 @@
         res = ioctl(fd, ioctl_nr, 0);
     if (res < 0) {
         free(ioctl_args);
-        fprintf(stderr, "ioctl 0x%x failed, %d\n", ioctl_nr, res);
-        return 1;
+        error(1, errno, "ioctl 0x%x failed (returned %d)", ioctl_nr, res);
     }
-    if(length) {
+
+    if (length) {
         printf("return buf:");
         ioctl_argp = ioctl_args;
         rem = length;
@@ -130,5 +177,6 @@
         printf("\n");
     }
     free(ioctl_args);
+    close(fd);
     return 0;
 }
diff --git a/toolbox/ionice.c b/toolbox/ionice.c
index 4a182f2..7abc261 100644
--- a/toolbox/ionice.c
+++ b/toolbox/ionice.c
@@ -1,5 +1,6 @@
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 #include <errno.h>
 
diff --git a/toolbox/load_policy.c b/toolbox/load_policy.c
deleted file mode 100644
index 90d48c4..0000000
--- a/toolbox/load_policy.c
+++ /dev/null
@@ -1,49 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <errno.h>
-#include <selinux/selinux.h>
-
-int load_policy_main(int argc, char **argv)
-{
-    int fd, rc;
-    struct stat sb;
-    void *map;
-    const char *path;
-
-    if (argc != 2) {
-        fprintf(stderr, "usage:  %s policy-file\n", argv[0]);
-        exit(1);
-    }
-
-    path = argv[1];
-    fd = open(path, O_RDONLY);
-    if (fd < 0) {
-        fprintf(stderr, "Could not open %s:  %s\n", path, strerror(errno));
-        exit(2);
-    }
-
-    if (fstat(fd, &sb) < 0) {
-        fprintf(stderr, "Could not stat %s:  %s\n", path, strerror(errno));
-        exit(3);
-    }
-
-    map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
-    if (map == MAP_FAILED) {
-        fprintf(stderr, "Could not mmap %s:  %s\n", path, strerror(errno));
-        exit(4);
-    }
-
-    rc = security_load_policy(map, sb.st_size);
-    if (rc < 0) {
-        fprintf(stderr, "Could not load %s:  %s\n", path, strerror(errno));
-        exit(5);
-    }
-    munmap(map, sb.st_size);
-    close(fd);
-    exit(0);
-}
diff --git a/toolbox/ls.c b/toolbox/ls.c
index 963fcb5..9a89dd4 100644
--- a/toolbox/ls.c
+++ b/toolbox/ls.c
@@ -1,23 +1,119 @@
+#include <dirent.h>
+#include <errno.h>
+#include <grp.h>
+#include <limits.h>
+#include <pwd.h>
+#include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
 #include <sys/types.h>
-#include <dirent.h>
-#include <errno.h>
+#include <time.h>
+#include <unistd.h>
 
 #include <selinux/selinux.h>
 
-#include <sys/stat.h>
-#include <unistd.h>
-#include <time.h>
+// simple dynamic array of strings.
+typedef struct {
+    int count;
+    int capacity;
+    void** items;
+} strlist_t;
 
-#include <pwd.h>
-#include <grp.h>
+#define STRLIST_INITIALIZER { 0, 0, NULL }
 
-#include <linux/kdev_t.h>
-#include <limits.h>
+/* Used to iterate over a strlist_t
+ * _list   :: pointer to strlist_t object
+ * _item   :: name of local variable name defined within the loop with
+ *            type 'char*'
+ * _stmnt  :: C statement executed in each iteration
+ *
+ * This macro is only intended for simple uses. Do not add or remove items
+ * to/from the list during iteration.
+ */
+#define  STRLIST_FOREACH(_list,_item,_stmnt) \
+    do { \
+        int _nn_##__LINE__ = 0; \
+        for (;_nn_##__LINE__ < (_list)->count; ++ _nn_##__LINE__) { \
+            char* _item = (char*)(_list)->items[_nn_##__LINE__]; \
+            _stmnt; \
+        } \
+    } while (0)
 
-#include "dynarray.h"
+static void dynarray_reserve_more( strlist_t *a, int count ) {
+    int old_cap = a->capacity;
+    int new_cap = old_cap;
+    const int max_cap = INT_MAX/sizeof(void*);
+    void** new_items;
+    int new_count = a->count + count;
+
+    if (count <= 0)
+        return;
+
+    if (count > max_cap - a->count)
+        abort();
+
+    new_count = a->count + count;
+
+    while (new_cap < new_count) {
+        old_cap = new_cap;
+        new_cap += (new_cap >> 2) + 4;
+        if (new_cap < old_cap || new_cap > max_cap) {
+            new_cap = max_cap;
+        }
+    }
+    new_items = realloc(a->items, new_cap*sizeof(void*));
+    if (new_items == NULL)
+        abort();
+
+    a->items = new_items;
+    a->capacity = new_cap;
+}
+
+void strlist_init( strlist_t *list ) {
+    list->count = list->capacity = 0;
+    list->items = NULL;
+}
+
+// append a new string made of the first 'slen' characters from 'str'
+// followed by a trailing zero.
+void strlist_append_b( strlist_t *list, const void* str, size_t  slen ) {
+    char *copy = malloc(slen+1);
+    memcpy(copy, str, slen);
+    copy[slen] = '\0';
+    if (list->count >= list->capacity)
+        dynarray_reserve_more(list, 1);
+    list->items[list->count++] = copy;
+}
+
+// append the copy of a given input string to a strlist_t.
+void strlist_append_dup( strlist_t *list, const char *str) {
+    strlist_append_b(list, str, strlen(str));
+}
+
+// note: strlist_done will free all the strings owned by the list.
+void strlist_done( strlist_t *list ) {
+    STRLIST_FOREACH(list, string, free(string));
+    free(list->items);
+    list->items = NULL;
+    list->count = list->capacity = 0;
+}
+
+static int strlist_compare_strings(const void* a, const void* b) {
+    const char *sa = *(const char **)a;
+    const char *sb = *(const char **)b;
+    return strcmp(sa, sb);
+}
+
+/* sort the strings in a given list (using strcmp) */
+void strlist_sort( strlist_t *list ) {
+    if (list->count > 0) {
+        qsort(list->items, (size_t)list->count, sizeof(void*), strlist_compare_strings);
+    }
+}
+
 
 // bits for flags argument
 #define LIST_LONG           (1 << 0)
@@ -200,7 +296,7 @@
     case S_IFCHR:
         printf("%s %-8s %-8s %3d, %3d %s %s\n",
                mode, user, group,
-               (int) MAJOR(s->st_rdev), (int) MINOR(s->st_rdev),
+               major(s->st_rdev), minor(s->st_rdev),
                date, name);
         break;
     case S_IFREG:
diff --git a/toolbox/lsmod.c b/toolbox/lsmod.c
deleted file mode 100644
index 8b55ee6..0000000
--- a/toolbox/lsmod.c
+++ /dev/null
@@ -1,10 +0,0 @@
-#include <stdio.h>
-
-extern int cat_main(int argc, char **argv);
-
-int lsmod_main(int argc, char **argv)
-{
-	char *cat_argv[] = { "cat", "/proc/modules", NULL };
-	return cat_main(2, cat_argv);
-}
-
diff --git a/toolbox/lsof.c b/toolbox/lsof.c
index 655806d..da78ddd 100644
--- a/toolbox/lsof.c
+++ b/toolbox/lsof.c
@@ -35,6 +35,7 @@
 #include <libgen.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
 #include <pwd.h>
diff --git a/toolbox/lsusb.c b/toolbox/lsusb.c
deleted file mode 100644
index 236e74b..0000000
--- a/toolbox/lsusb.c
+++ /dev/null
@@ -1,227 +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 <endian.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-
-#include <usbhost/usbhost.h>
-
-static int verbose = 0;
-static char str_buff[4096];
-
-static const char *get_str(struct usb_device *dev, int id)
-{
-    char *str = usb_device_get_string(dev, id);
-
-    if (id && str) {
-        strlcpy(str_buff, str, sizeof(str_buff));
-        free(str);
-    } else {
-        snprintf(str_buff, sizeof(str_buff), "%02x", id);
-    }
-
-    return str_buff;
-}
-
-
-static void lsusb_parse_device_descriptor(struct usb_device *dev,
-                                          struct usb_device_descriptor *desc)
-{
-    printf("  Device Descriptor\n");
-    printf("\tbcdUSB: %04x\n", letoh16(desc->bcdUSB));
-    printf("\tbDeviceClass: %02x\n", desc->bDeviceClass);
-    printf("\tbDeviceSubClass: %02x\n", desc->bDeviceSubClass);
-    printf("\tbDeviceProtocol: %02x\n", desc->bDeviceProtocol);
-    printf("\tbMaxPacketSize0: %02x\n", desc->bMaxPacketSize0);
-    printf("\tidVendor: %04x\n", letoh16(desc->idVendor));
-    printf("\tidProduct: %04x\n", letoh16(desc->idProduct));
-    printf("\tbcdDevice: %04x\n", letoh16(desc->bcdDevice));
-    printf("\tiManufacturer: %s\n", get_str(dev, desc->iManufacturer));
-    printf("\tiProduct: %s\n", get_str(dev, desc->iProduct));
-    printf("\tiSerialNumber: %s\n", get_str(dev,desc->iSerialNumber));
-    printf("\tbNumConfiguration: %02x\n", desc->bNumConfigurations);
-    printf("\n");
-}
-
-static void lsusb_parse_config_descriptor(struct usb_device *dev,
-                                          struct usb_config_descriptor *desc)
-{
-    printf("  Config Descriptor\n");
-    printf("\twTotalLength: %04x\n", letoh16(desc->wTotalLength));
-    printf("\tbNumInterfaces: %02x\n", desc->bNumInterfaces);
-    printf("\tbConfigurationValue: %02x\n", desc->bConfigurationValue);
-    printf("\tiConfiguration: %s\n", get_str(dev, desc->iConfiguration));
-    printf("\tbmAttributes: %02x\n", desc->bmAttributes);
-    printf("\tbMaxPower: %d mA\n", desc->bMaxPower * 2);
-    printf("\n");
-}
-
-static void lsusb_parse_interface_descriptor(struct usb_device *dev,
-                                             struct usb_interface_descriptor *desc)
-{
-    printf("  Interface Descriptor\n");
-    printf("\tbInterfaceNumber: %02x\n", desc->bInterfaceNumber);
-    printf("\tbAlternateSetting: %02x\n", desc->bAlternateSetting);
-    printf("\tbNumEndpoints: %02x\n", desc->bNumEndpoints);
-    printf("\tbInterfaceClass: %02x\n", desc->bInterfaceClass);
-    printf("\tbInterfaceSubClass: %02x\n", desc->bInterfaceSubClass);
-    printf("\tbInterfaceProtocol: %02x\n", desc->bInterfaceProtocol);
-    printf("\tiInterface: %s\n", get_str(dev, desc->iInterface));
-    printf("\n");
-}
-
-static void lsusb_parse_endpoint_descriptor(struct usb_device *dev,
-                                            struct usb_endpoint_descriptor *desc)
-{
-    printf("  Endpoint Descriptor\n");
-    printf("\tbEndpointAddress: %02x\n", desc->bEndpointAddress);
-    printf("\tbmAttributes: %02x\n", desc->bmAttributes);
-    printf("\twMaxPacketSize: %02x\n", letoh16(desc->wMaxPacketSize));
-    printf("\tbInterval: %02x\n", desc->bInterval);
-    printf("\tbRefresh: %02x\n", desc->bRefresh);
-    printf("\tbSynchAddress: %02x\n", desc->bSynchAddress);
-    printf("\n");
-}
-
-static void lsusb_dump_descriptor(struct usb_device *dev,
-                                  struct usb_descriptor_header *desc)
-{
-    int i;
-    printf("  Descriptor type %02x\n", desc->bDescriptorType);
-
-    for (i = 0; i < desc->bLength; i++ ) {
-        if ((i % 16) == 0)
-            printf("\t%02x:", i);
-        printf(" %02x", ((uint8_t *)desc)[i]);
-        if ((i % 16) == 15)
-            printf("\n");
-    }
-
-    if ((i % 16) != 0)
-        printf("\n");
-    printf("\n");
-}
-
-static void lsusb_parse_descriptor(struct usb_device *dev,
-                                   struct usb_descriptor_header *desc)
-{
-    switch (desc->bDescriptorType) {
-    case USB_DT_DEVICE:
-        lsusb_parse_device_descriptor(dev, (struct usb_device_descriptor *) desc);
-        break;
-
-    case USB_DT_CONFIG:
-        lsusb_parse_config_descriptor(dev, (struct usb_config_descriptor *) desc);
-        break;
-
-    case USB_DT_INTERFACE:
-        lsusb_parse_interface_descriptor(dev, (struct usb_interface_descriptor *) desc);
-        break;
-
-    case USB_DT_ENDPOINT:
-        lsusb_parse_endpoint_descriptor(dev, (struct usb_endpoint_descriptor *) desc);
-        break;
-
-    default:
-        lsusb_dump_descriptor(dev, desc);
-
-        break;
-    }
-}
-
-static int lsusb_device_added(const char *dev_name, void *client_data)
-{
-    struct usb_device *dev = usb_device_open(dev_name);
-
-    if (!dev) {
-        fprintf(stderr, "can't open device %s: %s\n", dev_name, strerror(errno));
-        return 0;
-    }
-
-    if (verbose) {
-        struct usb_descriptor_iter iter;
-        struct usb_descriptor_header *desc;
-
-        printf("%s:\n", dev_name);
-
-        usb_descriptor_iter_init(dev, &iter);
-
-        while ((desc = usb_descriptor_iter_next(&iter)) != NULL)
-            lsusb_parse_descriptor(dev, desc);
-
-    } else {
-        uint16_t vid, pid;
-        char *mfg_name, *product_name, *serial;
-
-        vid = usb_device_get_vendor_id(dev);
-        pid = usb_device_get_product_id(dev);
-        mfg_name = usb_device_get_manufacturer_name(dev);
-        product_name = usb_device_get_product_name(dev);
-        serial = usb_device_get_serial(dev);
-
-        printf("%s: %04x:%04x %s %s %s\n", dev_name, vid, pid,
-               mfg_name, product_name, serial);
-
-        free(mfg_name);
-        free(product_name);
-        free(serial);
-    }
-
-    usb_device_close(dev);
-
-    return 0;
-}
-
-static int lsusb_device_removed(const char *dev_name, void *client_data)
-{
-    return 0;
-}
-
-
-static int lsusb_discovery_done(void *client_data)
-{
-    return 1;
-}
-
-
-
-int lsusb_main(int argc, char **argv)
-{
-    struct usb_host_context *ctx;
-
-    if (argc == 2 && !strcmp(argv[1], "-v"))
-        verbose = 1;
-
-    ctx = usb_host_init();
-    if (!ctx) {
-        perror("usb_host_init:");
-        return 1;
-    }
-
-    usb_host_run(ctx,
-                 lsusb_device_added,
-                 lsusb_device_removed,
-                 lsusb_discovery_done,
-                 NULL);
-
-    usb_host_cleanup(ctx);
-
-    return 0;
-}
-
diff --git a/toolbox/md5.c b/toolbox/md5.c
deleted file mode 100644
index 5de4d9e..0000000
--- a/toolbox/md5.c
+++ /dev/null
@@ -1,71 +0,0 @@
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <openssl/md5.h>
-
-static int usage()
-{
-    fprintf(stderr,"md5 file ...\n");
-    return -1;
-}
-
-static int do_md5(const char *path)
-{
-    unsigned int i;
-    int fd;
-    MD5_CTX md5_ctx;
-    unsigned char md5[MD5_DIGEST_LENGTH];
-
-    fd = open(path, O_RDONLY);
-    if (fd < 0) {
-        fprintf(stderr,"could not open %s, %s\n", path, strerror(errno));
-        return -1;
-    }
-
-    MD5_Init(&md5_ctx);
-
-    while (1) {
-        char buf[4096];
-        ssize_t rlen;
-        rlen = read(fd, buf, sizeof(buf));
-        if (rlen == 0)
-            break;
-        else if (rlen < 0) {
-            (void)close(fd);
-            fprintf(stderr,"could not read %s, %s\n", path, strerror(errno));
-            return -1;
-        }
-        MD5_Update(&md5_ctx, buf, rlen);
-    }
-    if (close(fd)) {
-        fprintf(stderr,"could not close %s, %s\n", path, strerror(errno));
-        return -1;
-    }
-
-    MD5_Final(md5, &md5_ctx);
-
-    for (i = 0; i < (int)sizeof(md5); i++)
-        printf("%02x", md5[i]);
-    printf("  %s\n", path);
-
-    return 0;
-}
-
-int md5_main(int argc, char *argv[])
-{
-    int i, ret = 0;
-
-    if (argc < 2)
-        return usage();
-
-    /* loop over the file args */
-    for (i = 1; i < argc; i++) {
-        if (do_md5(argv[i]))
-            ret = 1;
-    }
-
-    return ret;
-}
diff --git a/toolbox/mkdir.c b/toolbox/mkdir.c
deleted file mode 100644
index 398d350..0000000
--- a/toolbox/mkdir.c
+++ /dev/null
@@ -1,77 +0,0 @@
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/limits.h>
-#include <sys/stat.h>
-
-static int usage()
-{
-    fprintf(stderr,"mkdir [OPTION] <target>\n");
-    fprintf(stderr,"    --help           display usage and exit\n");
-    fprintf(stderr,"    -p, --parents    create parent directories as needed\n");
-    return -1;
-}
-
-int mkdir_main(int argc, char *argv[])
-{
-    int ret;
-    if(argc < 2 || strcmp(argv[1], "--help") == 0) {
-        return usage();
-    }
-
-    int recursive = (strcmp(argv[1], "-p") == 0 ||
-                     strcmp(argv[1], "--parents") == 0) ? 1 : 0;
-
-    if(recursive && argc < 3) {
-        // -p specified without a path
-        return usage();
-    }
-
-    if(recursive) {
-        argc--;
-        argv++;
-    }
-
-    char currpath[PATH_MAX], *pathpiece;
-    struct stat st;
-
-    while(argc > 1) {
-        argc--;
-        argv++;
-        if(recursive) {
-            // reset path
-            strcpy(currpath, "");
-            // create the pieces of the path along the way
-            pathpiece = strtok(argv[0], "/");
-            if(argv[0][0] == '/') {
-                // prepend / if needed
-                strcat(currpath, "/");
-            }
-            while(pathpiece != NULL) {
-                if(strlen(currpath) + strlen(pathpiece) + 2/*NUL and slash*/ > PATH_MAX) {
-                    fprintf(stderr, "Invalid path specified: too long\n");
-                    return 1;
-                }
-                strcat(currpath, pathpiece);
-                strcat(currpath, "/");
-                if(stat(currpath, &st) != 0) {
-                    ret = mkdir(currpath, 0777);
-                    if(ret < 0) {
-                        fprintf(stderr, "mkdir failed for %s, %s\n", currpath, strerror(errno));
-                        return ret;
-                    }
-                }
-                pathpiece = strtok(NULL, "/");
-            }
-        } else {
-            ret = mkdir(argv[0], 0777);
-            if(ret < 0) {
-                fprintf(stderr, "mkdir failed for %s, %s\n", argv[0], strerror(errno));
-                return ret;
-            }
-        }
-    }
-    
-    return 0;
-}
diff --git a/toolbox/mknod.c b/toolbox/mknod.c
deleted file mode 100644
index 0fedece..0000000
--- a/toolbox/mknod.c
+++ /dev/null
@@ -1,95 +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 <stdlib.h>
-#include <unistd.h>
-#include <sys/stat.h>
-
-static int print_usage() {
-    fprintf(stderr, "mknod <path> [b|c|u|p] <major> <minor>\n");
-    return EXIT_FAILURE;
-}
-
-int mknod_main(int argc, char **argv) {
-    char *path = NULL;
-    int major = 0;
-    int minor = 0;
-    int args = 0;
-    mode_t mode = 0660;
-
-    /* Check correct argument count is 3 or 5 */
-    if (argc != 3 && argc != 5) {
-        fprintf(stderr, "Incorrect argument count\n");
-        return print_usage();
-    }
-
-    path = argv[1];
-
-    const char node_type = *argv[2];
-    switch (node_type) {
-    case 'b':
-        mode |= S_IFBLK;
-        args = 5;
-        break;
-    case 'c':
-    case 'u':
-        mode |= S_IFCHR;
-        args = 5;
-        break;
-    case 'p':
-        mode |= S_IFIFO;
-        args = 3;
-        break;
-    default:
-        fprintf(stderr, "Invalid node type '%c'\n", node_type);
-        return print_usage();
-    }
-
-    if (argc != args) {
-        if (args == 5) {
-            fprintf(stderr, "Node type '%c' requires <major> and <minor>\n", node_type);
-        } else {
-            fprintf(stderr, "Node type '%c' does not require <major> and <minor>\n", node_type);
-        }
-        return print_usage();
-    }
-
-    if (args == 5) {
-        major = atoi(argv[3]);
-        minor = atoi(argv[4]);
-    }
-
-    if (mknod(path, mode, makedev(major, minor))) {
-        perror("Unable to create node");
-        return EXIT_FAILURE;
-    }
-    return 0;
-}
diff --git a/toolbox/mkswap.c b/toolbox/mkswap.c
deleted file mode 100644
index 0904152..0000000
--- a/toolbox/mkswap.c
+++ /dev/null
@@ -1,93 +0,0 @@
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/swap.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-/* XXX This needs to be obtained from kernel headers. See b/9336527 */
-struct linux_swap_header {
-    char            bootbits[1024]; /* Space for disklabel etc. */
-    uint32_t        version;
-    uint32_t        last_page;
-    uint32_t        nr_badpages;
-    unsigned char   sws_uuid[16];
-    unsigned char   sws_volume[16];
-    uint32_t        padding[117];
-    uint32_t        badpages[1];
-};
-
-#define MAGIC_SWAP_HEADER     "SWAPSPACE2"
-#define MAGIC_SWAP_HEADER_LEN 10
-#define MIN_PAGES             10
-
-int mkswap_main(int argc, char **argv)
-{
-    int err = 0;
-    int fd;
-    ssize_t len;
-    off_t swap_size;
-    int pagesize;
-    struct linux_swap_header sw_hdr;
-
-    if (argc != 2) {
-        fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
-        return -EINVAL;
-    }
-
-    fd = open(argv[1], O_WRONLY);
-    if (fd < 0) {
-        err = errno;
-        fprintf(stderr, "Cannot open %s\n", argv[1]);
-        return err;
-    }
-
-    pagesize = getpagesize();
-    /* Determine the length of the swap file */
-    swap_size = lseek(fd, 0, SEEK_END);
-    if (swap_size < MIN_PAGES * pagesize) {
-        fprintf(stderr, "Swap file needs to be at least %dkB\n",
-            (MIN_PAGES * pagesize) >> 10);
-        err = -ENOSPC;
-        goto err;
-    }
-    if (lseek(fd, 0, SEEK_SET)) {
-        err = errno;
-        fprintf(stderr, "Can't seek to the beginning of the file\n");
-        goto err;
-    }
-
-    memset(&sw_hdr, 0, sizeof(sw_hdr));
-    sw_hdr.version = 1;
-    sw_hdr.last_page = (swap_size / pagesize) - 1;
-
-    len = write(fd, &sw_hdr, sizeof(sw_hdr));
-    if (len != sizeof(sw_hdr)) {
-        err = errno;
-        fprintf(stderr, "Failed to write swap header into %s\n", argv[1]);
-        goto err;
-    }
-
-    /* Write the magic header */
-    if (lseek(fd, pagesize - MAGIC_SWAP_HEADER_LEN, SEEK_SET) < 0) {
-        err = errno;
-        fprintf(stderr, "Failed to seek into %s\n", argv[1]);
-        goto err;
-    }
-
-    len = write(fd, MAGIC_SWAP_HEADER, MAGIC_SWAP_HEADER_LEN);
-    if (len != MAGIC_SWAP_HEADER_LEN) {
-        err = errno;
-        fprintf(stderr, "Failed to write magic swap header into %s\n", argv[1]);
-        goto err;
-    }
-
-    if (fsync(fd) < 0) {
-        err = errno;
-        fprintf(stderr, "Failed to sync %s\n", argv[1]);
-        goto err;
-    }
-err:
-    close(fd);
-    return err;
-}
diff --git a/toolbox/netstat.c b/toolbox/netstat.c
deleted file mode 100644
index 05dc640..0000000
--- a/toolbox/netstat.c
+++ /dev/null
@@ -1,154 +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 <arpa/inet.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-
-typedef union iaddr iaddr;
-typedef union iaddr6 iaddr6;
-
-union iaddr {
-    unsigned u;
-    unsigned char b[4];
-};
-
-union iaddr6 {
-    struct {
-        unsigned a;
-        unsigned b;
-        unsigned c;
-        unsigned d;
-    } u;
-    unsigned char b[16];
-};
-
-static const char *state2str(unsigned state)
-{
-    switch(state){
-    case 0x1: return "ESTABLISHED";
-    case 0x2: return "SYN_SENT";
-    case 0x3: return "SYN_RECV";
-    case 0x4: return "FIN_WAIT1";
-    case 0x5: return "FIN_WAIT2";
-    case 0x6: return "TIME_WAIT";
-    case 0x7: return "CLOSE";
-    case 0x8: return "CLOSE_WAIT";
-    case 0x9: return "LAST_ACK";
-    case 0xA: return "LISTEN";
-    case 0xB: return "CLOSING";
-    default: return "UNKNOWN";
-    }
-}
-
-/* addr + : + port + \0 */
-#define ADDR_LEN INET6_ADDRSTRLEN + 1 + 5 + 1
-
-static void addr2str(int af, const void *addr, unsigned port, char *buf)
-{
-    if (inet_ntop(af, addr, buf, ADDR_LEN) == NULL) {
-        *buf = '\0';
-        return;
-    }
-    size_t len = strlen(buf);
-    if (port) {
-        snprintf(buf+len, ADDR_LEN-len, ":%d", port);
-    } else {
-        strncat(buf+len, ":*", ADDR_LEN-len-1);
-    }
-}
-
-static void ipv4(const char *filename, const char *label) {
-    FILE *fp = fopen(filename, "r");
-    if (fp == NULL) {
-        return;
-    }
-    char buf[BUFSIZ];
-    fgets(buf, BUFSIZ, fp);
-    while (fgets(buf, BUFSIZ, fp)){
-        char lip[ADDR_LEN];
-        char rip[ADDR_LEN];
-        iaddr laddr, raddr;
-        unsigned lport, rport, state, txq, rxq, num;
-        int n = sscanf(buf, " %d: %x:%x %x:%x %x %x:%x",
-                       &num, &laddr.u, &lport, &raddr.u, &rport,
-                       &state, &txq, &rxq);
-        if (n == 8) {
-            addr2str(AF_INET, &laddr, lport, lip);
-            addr2str(AF_INET, &raddr, rport, rip);
-
-            printf("%4s  %6d %6d %-22s %-22s %s\n",
-                   label, rxq, txq, lip, rip,
-                   state2str(state));
-        }
-    }
-    fclose(fp);
-}
-
-static void ipv6(const char *filename, const char *label) {
-    FILE *fp = fopen(filename, "r");
-    if (fp == NULL) {
-        return;
-    }
-    char buf[BUFSIZ];
-    fgets(buf, BUFSIZ, fp);
-    while (fgets(buf, BUFSIZ, fp)){
-        char lip[ADDR_LEN];
-        char rip[ADDR_LEN];
-        iaddr6 laddr6, raddr6;
-        unsigned lport, rport, state, txq, rxq, num;
-        int n = sscanf(buf, " %d: %8x%8x%8x%8x:%x %8x%8x%8x%8x:%x %x %x:%x",
-                       &num, &laddr6.u.a, &laddr6.u.b, &laddr6.u.c, &laddr6.u.d, &lport,
-                       &raddr6.u.a, &raddr6.u.b, &raddr6.u.c, &raddr6.u.d, &rport,
-                       &state, &txq, &rxq);
-        if (n == 14) {
-            addr2str(AF_INET6, &laddr6, lport, lip);
-            addr2str(AF_INET6, &raddr6, rport, rip);
-
-            printf("%4s  %6d %6d %-22s %-22s %s\n",
-                   label, rxq, txq, lip, rip,
-                   state2str(state));
-        }
-    }
-    fclose(fp);
-}
-
-int netstat_main(int argc, char *argv[])
-{
-    printf("Proto Recv-Q Send-Q Local Address          Foreign Address        State\n");
-    ipv4("/proc/net/tcp",  "tcp");
-    ipv4("/proc/net/udp",  "udp");
-    ipv6("/proc/net/tcp6", "tcp6");
-    ipv6("/proc/net/udp6", "udp6");
-    return 0;
-}
diff --git a/toolbox/newfs_msdos.c b/toolbox/newfs_msdos.c
index 01517fd..5b98a01 100644
--- a/toolbox/newfs_msdos.c
+++ b/toolbox/newfs_msdos.c
@@ -798,6 +798,7 @@
                         __unused int oflag,struct bpb *bpb)
 {
     struct hd_geometry geom;
+    u_long block_size;
 
     if (ioctl(fd, BLKSSZGET, &bpb->bps)) {
         fprintf(stderr, "Error getting bytes / sector (%s)\n", strerror(errno));
@@ -806,11 +807,18 @@
 
     ckgeom(fname, bpb->bps, "bytes/sector");
 
-    if (ioctl(fd, BLKGETSIZE, &bpb->bsec)) {
+    if (ioctl(fd, BLKGETSIZE, &block_size)) {
         fprintf(stderr, "Error getting blocksize (%s)\n", strerror(errno));
         exit(1);
     }
 
+    if (block_size > UINT32_MAX) {
+        fprintf(stderr, "Error blocksize too large: %lu\n", block_size);
+        exit(1);
+    }
+
+    bpb->bsec = (u_int)block_size;
+
     if (ioctl(fd, HDIO_GETGEO, &geom)) {
         fprintf(stderr, "Error getting gemoetry (%s) - trying sane values\n", strerror(errno));
         geom.heads = 64;
diff --git a/toolbox/nohup.c b/toolbox/nohup.c
deleted file mode 100644
index 363999d..0000000
--- a/toolbox/nohup.c
+++ /dev/null
@@ -1,26 +0,0 @@
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-int nohup_main(int argc, char *argv[])
-{
-    if (argc < 2) {
-        fprintf(stderr, "Usage: %s [-n] program args...\n", argv[0]);
-        return EXIT_FAILURE;
-    }
-    signal(SIGHUP, SIG_IGN);
-    argv++;
-    if (strcmp(argv[0], "-n") == 0) {
-        argv++;
-        signal(SIGINT, SIG_IGN);
-        signal(SIGSTOP, SIG_IGN);
-        signal(SIGTTIN, SIG_IGN);
-        signal(SIGTTOU, SIG_IGN);
-        signal(SIGQUIT, SIG_IGN);
-        signal(SIGTERM, SIG_IGN);
-    }
-    execvp(argv[0], argv);
-    perror(argv[0]);
-    return EXIT_FAILURE;
-}
diff --git a/toolbox/notify.c b/toolbox/notify.c
deleted file mode 100644
index c983ed5..0000000
--- a/toolbox/notify.c
+++ /dev/null
@@ -1,145 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <sys/inotify.h>
-#include <errno.h>
-
-int notify_main(int argc, char *argv[])
-{
-    int c;
-    int nfd, ffd;
-    int res;
-	char event_buf[512];
-    struct inotify_event *event;
-	int event_mask = IN_ALL_EVENTS;
-    int event_count = 1;
-	int print_files = 0;
-	int verbose = 2;
-	int width = 80;
-	char **file_names;
-	int file_count;
-	int id_offset = 0;
-	int i;
-	char *buf;
-
-    do {
-        c = getopt(argc, argv, "m:c:pv:w:");
-        if (c == EOF)
-            break;
-        switch (c) {
-        case 'm':
-            event_mask = strtol(optarg, NULL, 0);
-            break;
-        case 'c':
-            event_count = atoi(optarg);
-            break;
-		case 'p':
-			print_files = 1;
-			break;
-        case 'v':
-            verbose = atoi(optarg);
-            break;
-        case 'w':
-            width = atoi(optarg);
-            break;
-        case '?':
-            fprintf(stderr, "%s: invalid option -%c\n",
-                argv[0], optopt);
-            exit(1);
-        }
-    } while (1);
-
-    if (argc <= optind) {
-        fprintf(stderr, "Usage: %s [-m eventmask] [-c count] [-p] [-v verbosity] path [path ...]\n", argv[0]);
-		return 1;
-    }
-
-    nfd = inotify_init();
-    if(nfd < 0) {
-        fprintf(stderr, "inotify_init failed, %s\n", strerror(errno));
-        return 1;
-    }
-	file_names = argv + optind;
-	file_count = argc - optind;
-	for(i = 0; i < file_count; i++) {
-		res = inotify_add_watch(nfd, file_names[i], event_mask);
-		if(res < 0) {
-	        fprintf(stderr, "inotify_add_watch failed for %s, %s\n", file_names[i], strerror(errno));
-			return 1;
-		}
-		if(i == 0)
-			id_offset = -res;
-		if(res + id_offset != i) {
-			fprintf(stderr, "%s got unexpected id %d instead of %d\n", file_names[i], res, i);
-			return 1;
-		}
-	}
-
-	buf = malloc(width + 2);
-    
-    while(1) {
-		int event_pos = 0;
-        res = read(nfd, event_buf, sizeof(event_buf));
-        if(res < (int)sizeof(*event)) {
-			if(errno == EINTR)
-				continue;
-            fprintf(stderr, "could not get event, %s\n", strerror(errno));
-            return 1;
-        }
-		//printf("got %d bytes of event information\n", res);
-		while(res >= (int)sizeof(*event)) {
-			int event_size;
-			event = (struct inotify_event *)(event_buf + event_pos);
-			if(verbose >= 2)
-		        printf("%s: %08x %08x \"%s\"\n", file_names[event->wd + id_offset], event->mask, event->cookie, event->len ? event->name : "");
-			else if(verbose >= 2)
-		        printf("%s: %08x \"%s\"\n", file_names[event->wd + id_offset], event->mask, event->len ? event->name : "");
-			else if(verbose >= 1)
-		        printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
-			if(print_files && (event->mask & IN_MODIFY)) {
-				char filename[512];
-				ssize_t read_len;
-				char *display_name;
-				int buflen;
-				strcpy(filename, file_names[event->wd + id_offset]);
-				if(event->len) {
-					strcat(filename, "/");
-					strcat(filename, event->name);
-				}
-				ffd = open(filename, O_RDONLY);
-				display_name = (verbose >= 2 || event->len == 0) ? filename : event->name;
-				buflen = width - strlen(display_name);
-				read_len = read(ffd, buf, buflen);
-				if(read_len > 0) {
-					if(read_len < buflen && buf[read_len-1] != '\n') {
-						buf[read_len] = '\n';
-						read_len++;
-					}
-					if(read_len == buflen) {
-						buf[--read_len] = '\0';
-						buf[--read_len] = '\n';
-						buf[--read_len] = '.';
-						buf[--read_len] = '.';
-						buf[--read_len] = '.';
-					}
-					else {
-						buf[read_len] = '\0';
-					}
-					printf("%s: %s", display_name, buf);
-				}
-				close(ffd);
-			}
-	        if(event_count && --event_count == 0)
-	            return 0;
-			event_size = sizeof(*event) + event->len;
-			res -= event_size;
-			event_pos += event_size;
-		}
-    }
-
-    return 0;
-}
diff --git a/toolbox/ps.c b/toolbox/ps.c
index 5458f6b..cf3f05a 100644
--- a/toolbox/ps.c
+++ b/toolbox/ps.c
@@ -1,15 +1,14 @@
+#include <ctype.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <ctype.h>
-#include <fcntl.h>
-
 #include <string.h>
-
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <dirent.h>
-
-#include <pwd.h>
+#include <unistd.h>
 
 #include <cutils/sched_policy.h>
 
@@ -31,7 +30,14 @@
 #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);
 
@@ -45,7 +51,8 @@
     int fd, r;
     char *ptr, *name, *state;
     int ppid;
-    unsigned wchan, rss, vss, eip;
+    unsigned rss, vss;
+    uintptr_t eip;
     unsigned utime, stime;
     int prio, nice, rtprio, sched, psr;
     struct passwd *pw;
@@ -125,7 +132,7 @@
     nexttok(&ptr); // blocked
     nexttok(&ptr); // sigignore
     nexttok(&ptr); // sigcatch
-    wchan = strtoul(nexttok(&ptr), 0, 10); // wchan
+    nexttok(&ptr); // wchan
     nexttok(&ptr); // nswap
     nexttok(&ptr); // cnswap
     nexttok(&ptr); // exit signal
@@ -147,7 +154,11 @@
         strcpy(user,pw->pw_name);
     }
 
-    if(!namefilter || !strncmp(name, namefilter, strlen(namefilter))) {
+    if(ppid_filter != 0 && ppid != ppid_filter) {
+        return 0;
+    }
+
+    if(!namefilter || !strncmp(cmdline[0] ? cmdline : name, namefilter, strlen(namefilter))) {
         if (display_flags & SHOW_MACLABEL) {
             fd = open(macline, O_RDONLY);
             strcpy(macline, "-");
@@ -173,7 +184,16 @@
             else
                 printf(" %.2s ", get_sched_policy_name(p));
         }
-        printf(" %08x %08x %s ", wchan, eip, state);
+        char path[PATH_MAX];
+        snprintf(path, sizeof(path), "/proc/%d/wchan", pid);
+        char wchan[10];
+        int 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);
         }
@@ -268,6 +288,10 @@
             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]);
+            argc--;
+            argv++;
         } else if(isdigit(argv[1][0])){
             pidfilter = atoi(argv[1]);
         } else {
@@ -278,12 +302,13 @@
     }
 
     if (display_flags & SHOW_MACLABEL) {
-        printf("LABEL                          USER     PID   PPID  NAME\n");
+        printf("LABEL                          USER      PID   PPID  NAME\n");
     } else {
-        printf("USER     PID   PPID  VSIZE  RSS   %s%s %s WCHAN    PC        %sNAME\n",
+        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 " : "");
     }
     while((de = readdir(d)) != 0){
diff --git a/toolbox/pwcache.c b/toolbox/pwcache.c
deleted file mode 100644
index 9d81981..0000000
--- a/toolbox/pwcache.c
+++ /dev/null
@@ -1,61 +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.
- *
- * 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 <grp.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <sys/types.h>
-
-int uid_from_user(const char* name, uid_t* uid) {
-  struct passwd* pw = getpwnam(name);
-  if (pw == NULL) {
-    return -1;
-  }
-  *uid = pw->pw_uid;
-  return 0;
-}
-
-char* group_from_gid(gid_t gid, int noname) {
-  struct group* g = getgrgid(gid);
-  if (g == NULL) {
-    static char buf[32];
-    snprintf(buf, sizeof(buf), "%lu", (long) gid);
-    return noname ? NULL : buf;
-  }
-  return g->gr_name;
-}
-
-char* user_from_uid(uid_t uid, int noname) {
-  struct passwd* pw = getpwuid(uid);
-  if (pw == NULL) {
-    static char buf[32];
-    snprintf(buf, sizeof(buf), "%lu", (long) uid);
-    return noname ? NULL : buf;
-  }
-  return pw->pw_name;
-}
diff --git a/toolbox/r.c b/toolbox/r.c
index 3b80db7..b96cdb2 100644
--- a/toolbox/r.c
+++ b/toolbox/r.c
@@ -5,6 +5,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/mman.h>
+#include <unistd.h>
 
 #if __LP64__
 #define strtoptr strtoull
@@ -18,7 +19,7 @@
     return -1;
 }
 
-int r_main(int argc, char *argv[])
+int main(int argc, char *argv[])
 {
     if(argc < 2) return usage();
 
diff --git a/toolbox/readlink.c b/toolbox/readlink.c
deleted file mode 100644
index d114e20..0000000
--- a/toolbox/readlink.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (c) 2013, 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 <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-static int skip_newline, quiet_errors, canonicalize;
-
-static void usage(char* name) {
-    fprintf(stderr, "Usage: %s [OPTION]... FILE\n", name);
-}
-
-int readlink_main(int argc, char* argv[]) {
-    int c;
-    while ((c = getopt(argc, argv, "nfqs")) != -1) {
-        switch (c) {
-        case 'n':
-            skip_newline = 1;
-            break;
-        case 'f':
-            canonicalize = 1;
-            break;
-        case 'q':
-        case 's':
-            quiet_errors = 1;
-            break;
-        case '?':
-        default:
-            usage(argv[0]);
-            return EXIT_FAILURE;
-        }
-    }
-    int index = optind;
-    if (argc - index != 1) {
-        usage(argv[0]);
-        return EXIT_FAILURE;
-    }
-
-    char name[PATH_MAX+1];
-    if (canonicalize) {
-        if(!realpath(argv[optind], name)) {
-            if (!quiet_errors) {
-                perror("readlink");
-            }
-            return EXIT_FAILURE;
-        }
-    } else {
-        ssize_t len = readlink(argv[1], name, PATH_MAX);
-
-        if (len < 0) {
-            if (!quiet_errors) {
-                perror("readlink");
-            }
-            return EXIT_FAILURE;
-        }
-        name[len] = '\0';
-    }
-
-    fputs(name, stdout);
-    if (!skip_newline) {
-        fputs("\n", stdout);
-    }
-
-    return EXIT_SUCCESS;
-}
diff --git a/toolbox/readtty.c b/toolbox/readtty.c
deleted file mode 100644
index 2b27548..0000000
--- a/toolbox/readtty.c
+++ /dev/null
@@ -1,183 +0,0 @@
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-#include <string.h>
-#include <termios.h>
-#include <unistd.h>
-
-struct {
-    char key;
-    char *chars;
-} map[] = {
-    { '1', "_ -1?!,.:;\"'<=>()_" },
-    { '2', "Cabc2ABC" },
-    { '3', "Fdef3DEF" },
-    { '4', "Ighi4GHI" },
-    { '5', "Ljkl5JKL" },
-    { '6', "Omno6MNO" },
-    { '7', "Spqrs7PQRS" },
-    { '8', "Vtuv8TUV" },
-    { '9', "Zwxyz9WXYZ" },
-    { '0', "*+&0@/#*" },
-};
-
-char next_char(char key, char current)
-{
-    int i;
-    char *next;
-    for(i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
-        if(key == map[i].key) {
-            next = strchr(map[i].chars, current);
-            if(next && next[1])
-                return next[1];
-            return map[i].chars[1];
-        }
-    }
-    return key;
-}
-
-char prev_char(char key, char current)
-{
-    int i;
-    char *next;
-    for(i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
-        if(key == map[i].key) {
-            next = strchr(map[i].chars+1, current);
-            if(next && next[-1])
-                return next[-1];
-            return map[i].chars[1];
-        }
-    }
-    return key;
-}
-
-int readtty_main(int argc, char *argv[])
-{
-    int c;
-    //int flags;
-    char buf[1];
-    int res;
-    struct termios ttyarg;
-    struct termios savedttyarg;
-    int nonblock = 0;
-    int timeout = 0;
-    int flush = 0;
-    int phone = 0;
-    char *accept = NULL;
-    char *rejectstring = NULL;
-    char last_char_in = 0;
-    char current_char = 0;
-    char *exit_string = NULL;
-    int exit_match = 0;
-
-    do {
-        c = getopt(argc, argv, "nt:fa:r:pe:");
-        if (c == EOF)
-            break;
-        switch (c) {
-        case 't':
-            timeout = atoi(optarg);
-            break;
-        case 'n':
-            nonblock = 1;
-            break;
-        case 'f':
-            flush = 1;
-            break;
-        case 'a':
-            accept = optarg;
-            break;
-        case 'r':
-            rejectstring = optarg;
-            break;
-        case 'p':
-            phone = 1;
-            break;
-        case 'e':
-            exit_string = optarg;
-            break;
-        case '?':
-            fprintf(stderr, "%s: invalid option -%c\n",
-                argv[0], optopt);
-            exit(1);
-        }
-    } while (1);
-
-    if(flush)
-        tcflush(STDIN_FILENO, TCIFLUSH);
-    ioctl(STDIN_FILENO, TCGETS , &savedttyarg) ;       /* set changed tty arguments */
-    ttyarg = savedttyarg;
-    ttyarg.c_cc[VMIN] = (timeout > 0 || nonblock) ? 0 : 1;                /* minimum of 0 chars */
-    ttyarg.c_cc[VTIME] = timeout;              /* wait max 15/10 sec */
-    ttyarg.c_iflag = BRKINT | ICRNL; 
-    ttyarg.c_lflag &= ~(ECHO | ICANON);
-    ioctl(STDIN_FILENO, TCSETS , &ttyarg);
-
-    while (1) {
-        res = read(STDIN_FILENO, buf, 1);
-        if(res <= 0) {
-            if(phone) {
-                if(current_char) {
-                    write(STDERR_FILENO, &current_char, 1);
-                    write(STDOUT_FILENO, &current_char, 1);
-                    if(exit_string && current_char == exit_string[exit_match]) {
-                        exit_match++;
-                        if(exit_string[exit_match] == '\0')
-                            break;
-                    }
-                    else
-                        exit_match = 0;
-                    current_char = 0;
-                }
-                continue;
-            }
-            break;
-        }
-        if(accept && strchr(accept, buf[0]) == NULL) {
-            if(rejectstring) {
-                write(STDOUT_FILENO, rejectstring, strlen(rejectstring));
-                break;
-            }
-            if(flush)
-                tcflush(STDIN_FILENO, TCIFLUSH);
-            continue;
-        }
-        if(phone) {
-            //if(!isprint(buf[0])) {
-            //  fprintf(stderr, "got unprintable character 0x%x\n", buf[0]);
-            //}
-            if(buf[0] == '\0') {
-                if(current_char) {
-                    current_char = prev_char(last_char_in, current_char);
-                    write(STDERR_FILENO, &current_char, 1);
-                    write(STDERR_FILENO, "\b", 1);
-                }
-                continue;
-            }
-            if(current_char && buf[0] != last_char_in) {
-                write(STDERR_FILENO, &current_char, 1);
-                write(STDOUT_FILENO, &current_char, 1);
-                if(exit_string && current_char == exit_string[exit_match]) {
-                    exit_match++;
-                    if(exit_string[exit_match] == '\0')
-                        break;
-                }
-                else
-                    exit_match = 0;
-                current_char = 0;
-            }
-            last_char_in = buf[0];
-            current_char = next_char(last_char_in, current_char);
-            write(STDERR_FILENO, &current_char, 1);
-            write(STDERR_FILENO, "\b", 1);
-            continue;
-        }
-        write(STDOUT_FILENO, buf, 1);
-        break;
-    }
-    ioctl(STDIN_FILENO, TCSETS , &savedttyarg) ;       /* set changed tty arguments */
-
-    return 0;
-}
diff --git a/toolbox/renice.c b/toolbox/renice.c
index 9dfeb51..99a06f4 100644
--- a/toolbox/renice.c
+++ b/toolbox/renice.c
@@ -32,6 +32,7 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <string.h>
 #include <sys/time.h>
 #include <sys/resource.h>
 #include <sched.h>
diff --git a/toolbox/restorecon.c b/toolbox/restorecon.c
deleted file mode 100644
index 3568625..0000000
--- a/toolbox/restorecon.c
+++ /dev/null
@@ -1,62 +0,0 @@
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <selinux/selinux.h>
-#include <selinux/android.h>
-
-static const char *progname;
-
-static void usage(void)
-{
-    fprintf(stderr, "usage:  %s [-DFnrRv] pathname...\n", progname);
-    exit(1);
-}
-
-int restorecon_main(int argc, char **argv)
-{
-    int ch, i, rc;
-    unsigned int flags = 0;
-
-    progname = argv[0];
-
-    do {
-        ch = getopt(argc, argv, "DFnrRv");
-        if (ch == EOF)
-            break;
-        switch (ch) {
-        case 'D':
-            flags |= SELINUX_ANDROID_RESTORECON_DATADATA;
-            break;
-        case 'F':
-            flags |= SELINUX_ANDROID_RESTORECON_FORCE;
-            break;
-        case 'n':
-            flags |= SELINUX_ANDROID_RESTORECON_NOCHANGE;
-            break;
-        case 'r':
-        case 'R':
-            flags |= SELINUX_ANDROID_RESTORECON_RECURSE;
-            break;
-        case 'v':
-            flags |= SELINUX_ANDROID_RESTORECON_VERBOSE;
-            break;
-        default:
-            usage();
-        }
-    } while (1);
-
-    argc -= optind;
-    argv += optind;
-    if (!argc)
-        usage();
-
-    for (i = 0; i < argc; i++) {
-        rc = selinux_android_restorecon(argv[i], flags);
-        if (rc < 0)
-            fprintf(stderr, "Could not restorecon %s:  %s\n", argv[i],
-                    strerror(errno));
-    }
-
-    return 0;
-}
diff --git a/toolbox/rmmod.c b/toolbox/rmmod.c
deleted file mode 100644
index c7e0d6a..0000000
--- a/toolbox/rmmod.c
+++ /dev/null
@@ -1,53 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <errno.h>
-#include <asm/unistd.h>
-
-extern int delete_module(const char *, unsigned int);
-
-int rmmod_main(int argc, char **argv)
-{
-	int ret, i;
-	char *modname, *dot;
-
-	/* make sure we've got an argument */
-	if (argc < 2) {
-		fprintf(stderr, "usage: rmmod <module>\n");
-		return -1;
-	}
-
-	/* if given /foo/bar/blah.ko, make a weak attempt
-	 * to convert to "blah", just for convenience
-	 */
-	modname = strrchr(argv[1], '/');
-	if (!modname)
-		modname = argv[1];
-	else modname++;
-
-	dot = strchr(argv[1], '.');
-	if (dot)
-		*dot = '\0';
-
-	/* Replace "-" with "_". This would keep rmmod
-	 * compatible with module-init-tools version of
-	 * rmmod
-	 */
-	for (i = 0; modname[i] != '\0'; i++) {
-		if (modname[i] == '-')
-			modname[i] = '_';
-	}
-
-	/* pass it to the kernel */
-	ret = delete_module(modname, O_NONBLOCK | O_EXCL);
-	if (ret != 0) {
-		fprintf(stderr, "rmmod: delete_module '%s' failed (errno %d)\n",
-						modname, errno);
-		return -1;
-	}
-
-	return 0;
-}
-
diff --git a/toolbox/rotatefb.c b/toolbox/rotatefb.c
deleted file mode 100644
index 2ff4127..0000000
--- a/toolbox/rotatefb.c
+++ /dev/null
@@ -1,71 +0,0 @@
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-#include <string.h>
-#include <termios.h>
-#include <unistd.h>
-#include <errno.h>
-#include <linux/fb.h>
-
-
-int rotatefb_main(int argc, char *argv[])
-{
-    int c;
-    char *fbdev = "/dev/graphics/fb0";
-    int rotation = 0;
-    int fd;
-    int res;
-    struct fb_var_screeninfo fbinfo;
-
-    do {
-        c = getopt(argc, argv, "d:");
-        if (c == EOF)
-            break;
-        switch (c) {
-        case 'd':
-            fbdev = optarg;
-            break;
-        case '?':
-            fprintf(stderr, "%s: invalid option -%c\n",
-                argv[0], optopt);
-            exit(1);
-        }
-    } while (1);
-
-    if(optind + 1 != argc) {
-        fprintf(stderr, "%s: specify rotation\n", argv[0]);
-        exit(1);
-    }
-    rotation = atoi(argv[optind]);
-
-    fd = open(fbdev, O_RDWR);
-    if(fd < 0) {
-        fprintf(stderr, "cannot open %s\n", fbdev);
-        return 1;
-    }
-
-    res = ioctl(fd, FBIOGET_VSCREENINFO, &fbinfo);
-    if(res < 0) {
-        fprintf(stderr, "failed to get fbinfo: %s\n", strerror(errno));
-        return 1;
-    }
-    if((fbinfo.rotate ^ rotation) & 1) {
-        unsigned int xres = fbinfo.yres;
-        fbinfo.yres = fbinfo.xres;
-        fbinfo.xres = xres;
-        fbinfo.xres_virtual = fbinfo.xres;
-        fbinfo.yres_virtual = fbinfo.yres * 2;
-        if(fbinfo.yoffset == xres)
-            fbinfo.yoffset = fbinfo.yres;
-    }
-    fbinfo.rotate = rotation; 
-    res = ioctl(fd, FBIOPUT_VSCREENINFO, &fbinfo);
-    if(res < 0) {
-        fprintf(stderr, "failed to set fbinfo: %s\n", strerror(errno));
-        return 1;
-    }
-
-    return 0;
-}
diff --git a/toolbox/route.c b/toolbox/route.c
deleted file mode 100644
index 3e10014..0000000
--- a/toolbox/route.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (c) 2009, 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 <string.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <linux/route.h>
-
-static inline int set_address(const char *address, struct sockaddr *sa) {
-    return inet_aton(address, &((struct sockaddr_in *)sa)->sin_addr);
-}
-
-/* current support the following routing entries */
-/* route add default dev wlan0 */
-/* route add default gw 192.168.1.1 dev wlan0 */
-/* route add -net 192.168.1.2 netmask 255.255.255.0 gw 192.168.1.1 */
-
-int route_main(int argc, char *argv[])
-{
-    struct rtentry rt = {
-        .rt_dst     = {.sa_family = AF_INET},
-        .rt_genmask = {.sa_family = AF_INET},
-        .rt_gateway = {.sa_family = AF_INET},
-    };
-
-    errno = EINVAL;
-    if (argc > 2 && !strcmp(argv[1], "add")) {
-        if (!strcmp(argv[2], "default")) {
-            /* route add default dev wlan0 */
-            if (argc > 4 && !strcmp(argv[3], "dev")) {
-                rt.rt_flags = RTF_UP;
-                rt.rt_dev = argv[4];
-                errno = 0;
-                goto apply;
-            }
-
-            /* route add default gw 192.168.1.1 dev wlan0 */
-            if (argc > 6 && !strcmp(argv[3], "gw") && !strcmp(argv[5], "dev")) {
-                rt.rt_flags = RTF_UP | RTF_GATEWAY;
-                rt.rt_dev = argv[6];
-                if (set_address(argv[4], &rt.rt_gateway)) {
-                    errno = 0;
-                }
-                goto apply;
-            }
-        }
-
-        /* route add -net 192.168.1.2 netmask 255.255.255.0 gw 192.168.1.1 */
-        if (argc > 7 && !strcmp(argv[2], "-net") &&
-                !strcmp(argv[4], "netmask")) {
-            if (!strcmp(argv[6], "gw")) {
-                rt.rt_flags = RTF_UP | RTF_GATEWAY;
-                if (set_address(argv[3], &rt.rt_dst) &&
-                    set_address(argv[5], &rt.rt_genmask) &&
-                    set_address(argv[7], &rt.rt_gateway)) {
-                    errno = 0;
-                }
-                goto apply;
-            } else if (!strcmp(argv[6], "dev")) {
-                rt.rt_flags = RTF_UP;
-                rt.rt_dev = argv[7];
-                if (set_address(argv[3], &rt.rt_dst) &&
-                    set_address(argv[5], &rt.rt_genmask)) {
-                    errno = 0;
-                }
-                goto apply;
-            }
-        }
-    }
-
-apply:
-    if (!errno) {
-        int s = socket(AF_INET, SOCK_DGRAM, 0);
-        if (s != -1 && (ioctl(s, SIOCADDRT, &rt) != -1 || errno == EEXIST)) {
-            return 0;
-        }
-    }
-    puts(strerror(errno));
-    return errno;
-}
diff --git a/toolbox/runcon.c b/toolbox/runcon.c
deleted file mode 100644
index 4a57bf3..0000000
--- a/toolbox/runcon.c
+++ /dev/null
@@ -1,28 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <selinux/selinux.h>
-
-int runcon_main(int argc, char **argv)
-{
-    int rc;
-
-    if (argc < 3) {
-        fprintf(stderr, "usage:  %s context program args...\n", argv[0]);
-        exit(1);
-    }
-
-    rc = setexeccon(argv[1]);
-    if (rc < 0) {
-        fprintf(stderr, "Could not set context to %s:  %s\n", argv[1], strerror(errno));
-        exit(2);
-    }
-
-    argv += 2;
-    argc -= 2;
-    execvp(argv[0], argv);
-    fprintf(stderr, "Could not exec %s:  %s\n", argv[0], strerror(errno));
-    exit(3);
-}
diff --git a/toolbox/schedtop.c b/toolbox/schedtop.c
deleted file mode 100644
index 2fccd2e..0000000
--- a/toolbox/schedtop.c
+++ /dev/null
@@ -1,330 +0,0 @@
-#include <ctype.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <pwd.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-struct thread_info {
-    int pid;
-    int tid;
-    char name[64];
-    unsigned long long exec_time;
-    unsigned long long delay_time;
-    unsigned long long run_count;
-};
-
-struct thread_table {
-    size_t allocated;
-    size_t active;
-    struct thread_info *data;
-};
-
-enum {
-    FLAG_BATCH = 1U << 0,
-    FLAG_HIDE_IDLE = 1U << 1,
-    FLAG_SHOW_THREADS = 1U << 2,
-    FLAG_USE_ALTERNATE_SCREEN = 1U << 3,
-};
-
-static int time_dp = 9;
-static int time_div = 1;
-#define NS_TO_S_D(ns) \
-    (uint32_t)((ns) / 1000000000), time_dp, ((uint32_t)((ns) % 1000000000) / time_div)
-
-struct thread_table processes;
-struct thread_table last_processes;
-struct thread_table threads;
-struct thread_table last_threads;
-
-static void grow_table(struct thread_table *table)
-{
-    size_t size = table->allocated;
-    struct thread_info *new_table;
-    if (size < 128)
-        size = 128;
-    else
-        size *= 2;
-    
-    new_table = realloc(table->data, size * sizeof(*table->data));
-    if (new_table == NULL) {
-        fprintf(stderr, "out of memory\n");
-        exit(1);
-    }
-    table->data = new_table;
-    table->allocated = size;
-}
-
-static struct thread_info *get_item(struct thread_table *table)
-{
-    if (table->active >= table->allocated)
-        grow_table(table);
-    return table->data + table->active;
-}
-
-static void commit_item(struct thread_table *table)
-{
-    table->active++;
-}
-
-static int read_line(char *line, size_t line_size)
-{
-    int fd;
-    int len;
-    fd = open(line, O_RDONLY);
-    if(fd == 0)
-        return -1;
-    len = read(fd, line, line_size - 1);
-    close(fd);
-    if (len <= 0)
-        return -1;
-    line[len] = '\0';
-    return 0;
-}
-
-static void add_thread(int pid, int tid, struct thread_info *proc_info)
-{
-    char line[1024];
-    char *name, *name_end;
-    size_t name_len;
-    struct thread_info *info;
-    if(tid == 0)
-        info = get_item(&processes);
-    else
-        info = get_item(&threads);
-    info->pid = pid;
-    info->tid = tid;
-
-    if(tid)
-        sprintf(line, "/proc/%d/task/%d/schedstat", pid, tid);
-    else
-        sprintf(line, "/proc/%d/schedstat", pid);
-    if (read_line(line, sizeof(line)))
-        return;
-    if(sscanf(line, "%llu %llu %llu",
-              &info->exec_time, &info->delay_time, &info->run_count) != 3)
-        return;
-    if (proc_info) {
-        proc_info->exec_time += info->exec_time;
-        proc_info->delay_time += info->delay_time;
-        proc_info->run_count += info->run_count;
-    }
-
-    name = NULL;
-    if (!tid) {
-        sprintf(line, "/proc/%d/cmdline", pid);
-        if (read_line(line, sizeof(line)) == 0 && line[0]) {
-            name = line;
-            name_len = strlen(name);
-        }
-    }
-    if (!name) {
-        if (tid)
-            sprintf(line, "/proc/%d/task/%d/stat", pid, tid);
-        else
-            sprintf(line, "/proc/%d/stat", pid);
-        if (read_line(line, sizeof(line)))
-            return;
-        name = strchr(line, '(');
-        if (name == NULL)
-            return;
-        name_end = strchr(name, ')');
-        if (name_end == NULL)
-            return;
-        name++;
-        name_len = name_end - name;
-    }
-    if (name_len >= sizeof(info->name))
-        name_len = sizeof(info->name) - 1;
-    memcpy(info->name, name, name_len);
-    info->name[name_len] = '\0';
-    if(tid == 0)
-        commit_item(&processes);
-    else
-        commit_item(&threads);
-}
-
-static void add_threads(int pid, struct thread_info *proc_info)
-{
-    char path[1024];
-    DIR *d;
-    struct dirent *de;
-    sprintf(path, "/proc/%d/task", pid);
-    d = opendir(path);
-    if(d == 0) return;
-    while((de = readdir(d)) != 0){
-        if(isdigit(de->d_name[0])){
-            int tid = atoi(de->d_name);
-            add_thread(pid, tid, proc_info);
-        }
-    }
-    closedir(d);
-}
-
-static void print_threads(int pid, uint32_t flags)
-{
-    size_t i, j;
-    for (i = 0; i < last_threads.active; i++) {
-        int epid = last_threads.data[i].pid;
-        int tid = last_threads.data[i].tid;
-        if (epid != pid)
-            continue;
-        for (j = 0; j < threads.active; j++)
-            if (tid == threads.data[j].tid)
-                break;
-        if (j == threads.active)
-            printf(" %5u died\n", tid);
-        else if (!(flags & FLAG_HIDE_IDLE) || threads.data[j].run_count - last_threads.data[i].run_count)
-            printf(" %5u %2u.%0*u %2u.%0*u %5llu %5u.%0*u %5u.%0*u %7llu  %s\n", tid,
-                NS_TO_S_D(threads.data[j].exec_time - last_threads.data[i].exec_time),
-                NS_TO_S_D(threads.data[j].delay_time - last_threads.data[i].delay_time),
-                threads.data[j].run_count - last_threads.data[i].run_count,
-                NS_TO_S_D(threads.data[j].exec_time), NS_TO_S_D(threads.data[j].delay_time),
-                threads.data[j].run_count, threads.data[j].name);
-    }
-}
-
-static void update_table(DIR *d, uint32_t flags)
-{
-    size_t i, j;
-    struct dirent *de;
-    
-    rewinddir(d);
-    while((de = readdir(d)) != 0){
-        if(isdigit(de->d_name[0])){
-            int pid = atoi(de->d_name);
-            struct thread_info *proc_info;
-            add_thread(pid, 0, NULL);
-            proc_info = &processes.data[processes.active - 1];
-            proc_info->exec_time = 0;
-            proc_info->delay_time = 0;
-            proc_info->run_count = 0;
-            add_threads(pid, proc_info);
-        }
-    }
-    if (!(flags & FLAG_BATCH))
-        printf("\e[H\e[0J");
-    printf("Processes: %zu, Threads %zu\n", processes.active, threads.active);
-    switch (time_dp) {
-    case 3:
-        printf("   TID --- SINCE LAST ---- ---------- TOTAL ----------\n");
-        printf("  PID  EXEC_T  DELAY SCHED EXEC_TIME DELAY_TIM   SCHED NAME\n");
-        break;
-    case 6:
-        printf("   TID ------ SINCE LAST -------    ------------ TOTAL -----------\n");
-        printf("  PID  EXEC_TIME DELAY_TIM SCHED    EXEC_TIME   DELAY_TIME   SCHED NAME\n");
-        break;
-    default:
-        printf("   TID    -------- SINCE LAST --------       ------------- TOTAL -------------\n");
-        printf("  PID     EXEC_TIME   DELAY_TIME SCHED       EXEC_TIME      DELAY_TIME   SCHED NAME\n");
-        break;
-    }
-    for (i = 0; i < last_processes.active; i++) {
-        int pid = last_processes.data[i].pid;
-        for (j = 0; j < processes.active; j++)
-            if (pid == processes.data[j].pid)
-                break;
-        if (j == processes.active)
-            printf("%5u died\n", pid);
-        else if (!(flags & FLAG_HIDE_IDLE) || processes.data[j].run_count - last_processes.data[i].run_count) {
-            printf("%5u  %2u.%0*u %2u.%0*u %5llu %5u.%0*u %5u.%0*u %7llu %s\n", pid,
-                NS_TO_S_D(processes.data[j].exec_time - last_processes.data[i].exec_time),
-                NS_TO_S_D(processes.data[j].delay_time - last_processes.data[i].delay_time),
-                processes.data[j].run_count - last_processes.data[i].run_count,
-                NS_TO_S_D(processes.data[j].exec_time), NS_TO_S_D(processes.data[j].delay_time),
-                processes.data[j].run_count, processes.data[j].name);
-            if (flags & FLAG_SHOW_THREADS)
-                print_threads(pid, flags);
-        }
-    }
-
-    {
-        struct thread_table tmp;
-        tmp = last_processes;
-        last_processes = processes;
-        processes = tmp;
-        processes.active = 0;
-        tmp = last_threads;
-        last_threads = threads;
-        threads = tmp;
-        threads.active = 0;
-    }
-}
-
-void
-sig_abort(int signum)
-{
-    printf("\e[?47l");
-    exit(0);
-}
-
-
-int schedtop_main(int argc, char **argv)
-{
-    int c;
-    DIR *d;
-    uint32_t flags = 0;    
-    int delay = 3000000;
-    float delay_f;
-
-    while(1) {
-        c = getopt(argc, argv, "d:ibtamun");
-        if (c == EOF)
-            break;
-        switch (c) {
-        case 'd':
-            delay_f = atof(optarg);
-            delay = delay_f * 1000000;
-            break;
-        case 'b':
-            flags |= FLAG_BATCH;
-            break;
-        case 'i':
-            flags |= FLAG_HIDE_IDLE;
-            break;
-        case 't':
-            flags |= FLAG_SHOW_THREADS;
-            break;
-        case 'a':
-            flags |= FLAG_USE_ALTERNATE_SCREEN;
-            break;
-        case 'm':
-            time_dp = 3;
-            time_div = 1000000;
-            break;
-        case 'u':
-            time_dp = 6;
-            time_div = 1000;
-            break;
-        case 'n':
-            time_dp = 9;
-            time_div = 1;
-            break;
-        }
-    }
-
-    d = opendir("/proc");
-    if(d == 0) return -1;
-
-    if (!(flags & FLAG_BATCH)) {
-        if(flags & FLAG_USE_ALTERNATE_SCREEN) {
-            signal(SIGINT, sig_abort);
-            signal(SIGPIPE, sig_abort);
-            signal(SIGTERM, sig_abort);
-            printf("\e7\e[?47h");
-        }
-        printf("\e[2J");
-    }
-    while (1) {
-        update_table(d, flags);
-        usleep(delay);
-    }
-    closedir(d);
-    return 0;
-}
diff --git a/toolbox/sendevent.c b/toolbox/sendevent.c
index 9b813f6..4d0ca17 100644
--- a/toolbox/sendevent.c
+++ b/toolbox/sendevent.c
@@ -1,49 +1,12 @@
+#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 <fcntl.h>
 #include <sys/ioctl.h>
-//#include <linux/input.h> // this does not compile
-#include <errno.h>
-
-
-// from <linux/input.h>
-
-struct input_event {
-	struct timeval time;
-	__u16 type;
-	__u16 code;
-	__s32 value;
-};
-
-#define EVIOCGVERSION		_IOR('E', 0x01, int)			/* get driver version */
-#define EVIOCGID		_IOR('E', 0x02, struct input_id)	/* get device ID */
-#define EVIOCGKEYCODE		_IOR('E', 0x04, int[2])			/* get keycode */
-#define EVIOCSKEYCODE		_IOW('E', 0x04, int[2])			/* set keycode */
-
-#define EVIOCGNAME(len)		_IOC(_IOC_READ, 'E', 0x06, len)		/* get device name */
-#define EVIOCGPHYS(len)		_IOC(_IOC_READ, 'E', 0x07, len)		/* get physical location */
-#define EVIOCGUNIQ(len)		_IOC(_IOC_READ, 'E', 0x08, len)		/* get unique identifier */
-
-#define EVIOCGKEY(len)		_IOC(_IOC_READ, 'E', 0x18, len)		/* get global keystate */
-#define EVIOCGLED(len)		_IOC(_IOC_READ, 'E', 0x19, len)		/* get all LEDs */
-#define EVIOCGSND(len)		_IOC(_IOC_READ, 'E', 0x1a, len)		/* get all sounds status */
-#define EVIOCGSW(len)		_IOC(_IOC_READ, 'E', 0x1b, len)		/* get all switch states */
-
-#define EVIOCGBIT(ev,len)	_IOC(_IOC_READ, 'E', 0x20 + ev, len)	/* get event bits */
-#define EVIOCGABS(abs)		_IOR('E', 0x40 + abs, struct input_absinfo)		/* get abs value/limits */
-#define EVIOCSABS(abs)		_IOW('E', 0xc0 + abs, struct input_absinfo)		/* set abs value/limits */
-
-#define EVIOCSFF		_IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect))	/* send a force effect to a force feedback device */
-#define EVIOCRMFF		_IOW('E', 0x81, int)			/* Erase a force effect */
-#define EVIOCGEFFECTS		_IOR('E', 0x84, int)			/* Report number of effects playable at the same time */
-
-#define EVIOCGRAB		_IOW('E', 0x90, int)			/* Grab/Release device */
-
-// end <linux/input.h>
-
-
+#include <unistd.h>
 
 int sendevent_main(int argc, char *argv[])
 {
diff --git a/toolbox/setenforce.c b/toolbox/setenforce.c
deleted file mode 100644
index 444073d..0000000
--- a/toolbox/setenforce.c
+++ /dev/null
@@ -1,44 +0,0 @@
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
-#include <strings.h>
-#include <errno.h>
-#include <selinux/selinux.h>
-
-static void usage(const char *progname)
-{
-    fprintf(stderr, "usage:  %s [ Enforcing | Permissive | 1 | 0 ]\n",
-            progname);
-    exit(1);
-}
-
-int setenforce_main(int argc, char **argv)
-{
-    int rc = 0;
-    if (argc != 2) {
-        usage(argv[0]);
-    }
-
-    if (is_selinux_enabled() <= 0) {
-        fprintf(stderr, "%s: SELinux is disabled\n", argv[0]);
-        return 1;
-    }
-    if (strlen(argv[1]) == 1 && (argv[1][0] == '0' || argv[1][0] == '1')) {
-        rc = security_setenforce(atoi(argv[1]));
-    } else {
-        if (strcasecmp(argv[1], "enforcing") == 0) {
-            rc = security_setenforce(1);
-        } else if (strcasecmp(argv[1], "permissive") == 0) {
-            rc = security_setenforce(0);
-        } else
-            usage(argv[0]);
-    }
-    if (rc < 0) {
-        fprintf(stderr, "%s:  Could not set enforcing status:  %s\n",
-                argv[0], strerror(errno));
-        return 2;
-    }
-    return 0;
-}
diff --git a/toolbox/setkey.c b/toolbox/setkey.c
deleted file mode 100644
index 1ff2774..0000000
--- a/toolbox/setkey.c
+++ /dev/null
@@ -1,89 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <string.h>
-#include <linux/kd.h>
-#include <linux/vt.h>
-#include <errno.h>
-
-static void setkey_usage(char *argv[])
-{
-    fprintf(stderr, "%s [-t <table>] [-k <index>] [-v value] [-r] [-h]\n"
-            "  -t <table> Select table\n"
-            "  -k <index> Select key\n"
-            "  -v <value> Set entry\n"
-            "  -r         Read current entry\n"
-            "  -h         Print help\n", argv[0]);
-}
-
-#define TTYDEV	"/dev/tty0"
-
-int setkey_main(int argc, char *argv[])
-{
-    int fd;
-    struct kbentry kbe;
-    int did_something = 0;
-
-    kbe.kb_table = 0;
-    kbe.kb_index = -1;
-    kbe.kb_value = 0;
-
-    fd = open(TTYDEV, O_RDWR | O_SYNC);
-    if (fd < 0) {
-        fprintf(stderr, "open %s: %s\n", TTYDEV, strerror(errno));
-        return 1;
-    }
-
-    do {
-        int c, ret;
-
-        c = getopt(argc, argv, "t:k:v:hr");
-        if (c == EOF)
-            break;
-
-        switch (c) {
-        case 't':
-            kbe.kb_table = strtol(optarg, NULL, 0);
-            break;
-        case 'k':
-            kbe.kb_index = strtol(optarg, NULL, 0);
-            break;
-        case 'v':
-            kbe.kb_value = strtol(optarg, NULL, 0);
-            ret = ioctl(fd, KDSKBENT, &kbe);
-            if (ret < 0) {
-                fprintf(stderr, "KDSKBENT %d %d %d failed: %s\n",
-                        kbe.kb_table, kbe.kb_index, kbe.kb_value,
-                        strerror(errno));
-                return 1;
-            }
-            did_something = 1;
-            break;
-        case 'r':
-            ret = ioctl(fd, KDGKBENT, &kbe);
-            if (ret < 0) {
-                fprintf(stderr, "KDGKBENT %d %d  failed: %s\n",
-                        kbe.kb_table, kbe.kb_index, strerror(errno));
-                return 1;
-            }
-            printf("0x%x 0x%x 0x%x\n",
-                   kbe.kb_table, kbe.kb_index, kbe.kb_value);
-            did_something = 1;
-            break;
-        case 'h':
-            setkey_usage(argv);
-            return 1;
-        case '?':
-            fprintf(stderr, "%s: invalid option -%c\n",
-                argv[0], optopt);
-            return 1;
-        }
-    } while (1);
-
-    if(optind != argc || !did_something) {
-        setkey_usage(argv);
-        return 1;
-    }
-
-    return 0;
-}
diff --git a/toolbox/setprop.c b/toolbox/setprop.c
deleted file mode 100644
index 63ad2b4..0000000
--- a/toolbox/setprop.c
+++ /dev/null
@@ -1,18 +0,0 @@
-#include <stdio.h>
-
-#include <cutils/properties.h>
-
-int setprop_main(int argc, char *argv[])
-{
-    if(argc != 3) {
-        fprintf(stderr,"usage: setprop <key> <value>\n");
-        return 1;
-    }
-
-    if(property_set(argv[1], argv[2])){
-        fprintf(stderr,"could not set property\n");
-        return 1;
-    }
-
-    return 0;
-}
diff --git a/toolbox/setsebool.c b/toolbox/setsebool.c
deleted file mode 100644
index f79a612..0000000
--- a/toolbox/setsebool.c
+++ /dev/null
@@ -1,46 +0,0 @@
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <selinux/selinux.h>
-#include <errno.h>
-
-static int do_setsebool(int nargs, char **args) {
-    const char *name = args[1];
-    const char *value = args[2];
-    SELboolean b;
-
-    if (is_selinux_enabled() <= 0)
-        return 0;
-
-    b.name = name;
-    if (!strcmp(value, "1") || !strcasecmp(value, "true") || !strcasecmp(value, "on"))
-        b.value = 1;
-    else if (!strcmp(value, "0") || !strcasecmp(value, "false") || !strcasecmp(value, "off"))
-        b.value = 0;
-    else {
-        fprintf(stderr, "setsebool: invalid value %s\n", value);
-        return -1;
-    }
-
-    if (security_set_boolean_list(1, &b, 0) < 0)
-    {
-        fprintf(stderr, "setsebool: could not set %s to %s:  %s", name, value, strerror(errno));
-        return -1;
-    }
-
-    return 0;
-}
-
-int setsebool_main(int argc, char **argv)
-{
-    if (argc != 3) {
-        fprintf(stderr, "Usage:  %s name value\n", argv[0]);
-        exit(1);
-    }
-
-    return do_setsebool(argc, argv);
-}
diff --git a/toolbox/smd.c b/toolbox/smd.c
deleted file mode 100644
index 91e495c..0000000
--- a/toolbox/smd.c
+++ /dev/null
@@ -1,41 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-
-int smd_main(int argc, char **argv)
-{
-    int fd, len, r, port = 0;
-    char devname[32];
-    argc--;
-    argv++;
-
-    if((argc > 0) && (argv[0][0] == '-')) {
-        port = atoi(argv[0] + 1);
-        argc--;
-        argv++;
-    }
-
-    sprintf(devname,"/dev/smd%d",port);
-    fd = open(devname, O_WRONLY);
-    if(fd < 0) {
-        fprintf(stderr,"failed to open smd0 - %s\n",
-            strerror(errno));
-        return -1;
-    }
-    while(argc > 0) {
-        len = strlen(argv[0]);
-        r = write(fd, argv[0], len);
-        if(r != len) {
-            fprintf(stderr,"failed to write smd0 (%d) %s\n",
-                r, strerror(errno));
-            return -1;
-        }
-        argc--;
-        argv++;
-        write(fd, argc ? " " : "\r", 1);
-    }
-    close(fd);
-    return 0;       
-}
diff --git a/toolbox/swapoff.c b/toolbox/swapoff.c
deleted file mode 100644
index d8f6a00..0000000
--- a/toolbox/swapoff.c
+++ /dev/null
@@ -1,20 +0,0 @@
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/swap.h>
-
-int swapoff_main(int argc, char **argv)
-{
-    int err = 0;
-
-    if (argc != 2) {
-        fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
-        return -EINVAL;
-    }
-
-    err = swapoff(argv[1]);
-    if (err) {
-        fprintf(stderr, "swapoff failed for %s\n", argv[1]);
-    }
-
-    return err;
-}
diff --git a/toolbox/swapon.c b/toolbox/swapon.c
deleted file mode 100644
index 150701a..0000000
--- a/toolbox/swapon.c
+++ /dev/null
@@ -1,66 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <sys/swap.h>
-
-static void usage(char *name)
-{
-    fprintf(stderr, "Usage: %s [-p prio] <filename>\n"
-        "        prio must be between 0 and %d\n", name, SWAP_FLAG_PRIO_MASK);
-}
-
-static int parse_prio(char *prio_str)
-{
-    unsigned long p = strtoul(prio_str, NULL, 10);
-
-    return (p > SWAP_FLAG_PRIO_MASK)? -1 : (int)p;
-}
-
-int swapon_main(int argc, char **argv)
-{
-    int err = 0;
-    int flags = 0;
-    int prio;
-
-    opterr = 0;
-    do {
-        int c = getopt(argc, argv, "hp:");
-        if (c == -1)
-            break;
-
-        switch (c) {
-            case 'p':
-                if (optarg != NULL)
-                    prio = parse_prio(optarg);
-                else
-                    prio = -1;
-
-                if (prio < 0) {
-                    usage(argv[0]);
-                    return -EINVAL;
-                }
-                flags |= SWAP_FLAG_PREFER;
-                flags |= (prio << SWAP_FLAG_PRIO_SHIFT) & SWAP_FLAG_PRIO_MASK;
-                break;
-            case 'h':
-                usage(argv[0]);
-                return 0;
-            case '?':
-                fprintf(stderr, "unknown option: %c\n", optopt);
-                return -EINVAL;
-        }
-    } while (1);
-
-    if (optind != argc - 1) {
-        usage(argv[0]);
-        return -EINVAL;
-    }
-
-    err = swapon(argv[argc - 1], flags);
-    if (err) {
-        fprintf(stderr, "swapon failed for %s\n", argv[argc - 1]);
-    }
-
-    return err;
-}
diff --git a/toolbox/syren.c b/toolbox/syren.c
deleted file mode 100644
index 47c2460..0000000
--- a/toolbox/syren.c
+++ /dev/null
@@ -1,158 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <malloc.h>
-
-/* ioctl crap */
-#define SYREN_RD		101
-#define SYREN_WR		102
-#define SYREN_OLD_RD	108
-#define SYREN_OLD_WR	109
-
-struct syren_io_args {
-	unsigned long	page;
-	unsigned long	addr;
-	unsigned long	value;
-};
-
-typedef struct {
-	u_char			page;
-	u_char			addr;
-	const char		*name;
-} syren_reg;
-
-static syren_reg registers[] = {
-	{ 0, 0x04, "TOGBR1" },
-	{ 0, 0x05, "TOGBR2" },
-	{ 0, 0x06, "VBDCTRL" },
-	{ 1, 0x07, "VBUCTRL" },
-	{ 1, 0x08, "VBCTRL" },
-	{ 1, 0x09, "PWDNRG" },
-	{ 1, 0x0a, "VBPOP" },
-	{ 1, 0x0b, "VBCTRL2" },
-	{ 1, 0x0f, "VAUDCTRL" },
-	{ 1, 0x10, "VAUSCTRL" },
-	{ 1, 0x11, "VAUOCTRL" },
-	{ 1, 0x12, "VAUDPLL" },
-	{ 1, 0x17, "VRPCSIMR" },
-	{ 0, 0, 0 }
-};
-
-static syren_reg *find_reg(const char *name)
-{
-	int i;
-
-	for (i = 0; registers[i].name != 0; i++) {
-		if (!strcasecmp(registers[i].name, name))
-			return &registers[i];
-	}
-
-	return NULL;
-}
-
-static int usage(void)
-{
-	fprintf(stderr, "usage: syren [r/w] [REGNAME | page:addr] (value)\n");
-	return 1;
-}
-
-int
-syren_main(int argc, char **argv)
-{
-	int cmd = -1;
-	syren_reg *r;
-	struct syren_io_args sio;
-	char name[32];
-	int fd;
-
-	if (argc < 3) {
-		return usage();
-	}
-
-	switch(argv[1][0]) {
-	case 'r':
-		cmd = SYREN_RD;
-		break;
-	case 'w':
-		cmd = SYREN_WR;
-		break;
-	case 'R':
-		cmd = SYREN_OLD_RD;
-		break;
-	case 'W':
-		cmd = SYREN_OLD_WR;
-		break;
-	default:
-		return usage();
-	}
-
-	if (cmd == SYREN_WR || cmd == SYREN_OLD_WR) {
-		if (argc < 4)
-			return usage();
-		sio.value = strtoul(argv[3], 0, 0);
-	}
-
-	fd = open("/dev/eac", O_RDONLY);
-	if (fd < 0) {
-		fprintf(stderr, "can't open /dev/eac\n");
-		return 1;
-	}
-
-	if (strcasecmp(argv[2], "all") == 0) {
-		int i;
-		if (cmd != SYREN_RD && cmd != SYREN_OLD_RD) {
-			fprintf(stderr, "can only read all registers\n");
-			return 1;
-		}
-
-		for (i = 0; registers[i].name; i++) {
-			sio.page = registers[i].page;
-			sio.addr = registers[i].addr;
-			if (ioctl(fd, cmd, &sio) < 0) {
-				fprintf(stderr, "%s: error\n", registers[i].name);
-			} else {
-				fprintf(stderr, "%s: %04x\n", registers[i].name, sio.value);
-			}
-		}
-
-		close(fd);
-		return 0;
-	}
-
-	r = find_reg(argv[2]);
-	if (r == NULL) {
-		if(strlen(argv[2]) >= sizeof(name)){
-			fprintf(stderr, "REGNAME too long\n");
-			return 0;
-		}
-		strlcpy(name, argv[2], sizeof(name));
-		char *addr_str = strchr(argv[2], ':');
-		if (addr_str == NULL)
-			return usage();
-		*addr_str++ = 0;
-		sio.page = strtoul(argv[2], 0, 0);
-		sio.addr = strtoul(addr_str, 0, 0);
-	} else {
-		strlcpy(name, r->name, sizeof(name));
-		sio.page = r->page;
-		sio.addr = r->addr;
-	}
-
-	if (ioctl(fd, cmd, &sio) < 0) {
-		fprintf(stderr, "ioctl(%d) failed\n", cmd);
-		return 1;
-	}
-
-	if (cmd == SYREN_RD || cmd == SYREN_OLD_RD) {
-		printf("%s: %04x\n", name, sio.value);
-	} else {
-		printf("wrote %04x to %s\n", sio.value, name);
-	}
-
-	close(fd);
-
-	return 0;
-}
-
diff --git a/toolbox/toolbox.c b/toolbox/toolbox.c
index 0eac390..915da44 100644
--- a/toolbox/toolbox.c
+++ b/toolbox/toolbox.c
@@ -1,6 +1,8 @@
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 int main(int, char **);
 
@@ -31,11 +33,24 @@
     { 0, 0 },
 };
 
+static void SIGPIPE_handler(int signal) {
+    // Those desktop Linux tools that catch SIGPIPE seem to agree that it's
+    // a successful way to exit, not a failure. (Which makes sense --- we were
+    // told to stop by a reader, rather than failing to continue ourselves.)
+    _exit(0);
+}
+
 int main(int argc, char **argv)
 {
     int i;
     char *name = argv[0];
 
+    // 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--;
diff --git a/toolbox/top.c b/toolbox/top.c
index b1a275c..1e99d4c 100644
--- a/toolbox/top.c
+++ b/toolbox/top.c
@@ -109,15 +109,9 @@
 static int numcmp(long long a, long long b);
 static void usage(char *cmd);
 
-static void exit_top(int signal) {
-  exit(EXIT_FAILURE);
-}
-
 int top_main(int argc, char *argv[]) {
     num_used_procs = num_free_procs = 0;
 
-    signal(SIGPIPE, exit_top);
-
     max_procs = 0;
     delay = 3;
     iterations = -1;
diff --git a/toolbox/touch.c b/toolbox/touch.c
deleted file mode 100644
index 52ddf2a..0000000
--- a/toolbox/touch.c
+++ /dev/null
@@ -1,114 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <time.h>
-
-static void usage(void)
-{
-        fprintf(stderr, "touch: usage: touch [-alm] [-t YYYYMMDD[.hhmmss]] <file>\n");
-        exit(1);
-}
-
-static time_t parse_time(char *s)
-{
-    struct tm tm;
-    int day = atoi(s);
-    int hour = 0;
-
-    while (*s && *s != '.') {
-        s++;
-    }
-
-    if (*s) {
-        s++;
-        hour = atoi(s);
-    }
-
-    tm.tm_year = day / 10000 - 1900;
-    tm.tm_mon = (day % 10000) / 100 - 1;
-    tm.tm_mday = day % 100;
-    tm.tm_hour = hour / 10000;
-    tm.tm_min = (hour % 10000) / 100;
-    tm.tm_sec = hour % 100;
-    tm.tm_isdst = -1;
-
-    return mktime(&tm);
-}
-
-int touch_main(int argc, char *argv[])
-{
-        int i, fd, aflag = 0, mflag = 0, debug = 0, flags = 0;
-        struct timespec specified_time, times[2];
-        char *file = 0;
-
-        specified_time.tv_nsec = UTIME_NOW;
-
-        for (i = 1; i < argc; i++) {
-            if (argv[i][0] == '-') {
-                /* an option */
-                const char *arg = argv[i]+1;
-                while (arg[0]) {
-                    switch (arg[0]) {
-                    case 'a': aflag = 1; break;
-                    case 'm': mflag = 1; break;
-                    case 't':
-                        if ((i+1) >= argc)
-                            usage();
-                        specified_time.tv_sec = parse_time(argv[++i]);
-                        if (specified_time.tv_sec == -1) {
-                            fprintf(stderr, "touch: invalid timestamp specified\n");
-                            exit(1);
-                        }
-                        specified_time.tv_nsec = 0;
-                        break;
-                    case 'l': flags |= AT_SYMLINK_NOFOLLOW; break;
-                    case 'd': debug = 1; break;
-                    default:
-                        usage();
-                    }
-                    arg++;
-                }
-            } else {
-                /* not an option, and only accept one filename */
-                if (i+1 != argc)
-                    usage();
-                file = argv[i];
-            }
-        }
-
-        if (! file) {
-            fprintf(stderr, "touch: no file specified\n");
-            exit(1);
-        }
-
-        if (access(file, F_OK))
-            if ((fd=creat(file, 0666)) != -1)
-                close(fd);
-
-        if ((mflag == 0) && (aflag == 0))
-            aflag = mflag = 1;
-
-        if (aflag)
-            times[0] = specified_time;
-        else
-            times[0].tv_nsec = UTIME_OMIT;
-
-        if (mflag)
-            times[1] = specified_time;
-        else
-            times[1].tv_nsec = UTIME_OMIT;
-
-        if (debug) {
-            fprintf(stderr, "file = %s\n", file);
-            fprintf(stderr, "times[0].tv_sec = %ld, times[0].tv_nsec = %ld\n", times[0].tv_sec, times[0].tv_nsec);
-            fprintf(stderr, "times[1].tv_sec = %ld, times[1].tv_nsec = %ld\n", times[1].tv_sec, times[1].tv_nsec);
-            fprintf(stderr, "flags = 0x%8.8x\n", flags);
-        }
-
-        return utimensat(AT_FDCWD, file, times, flags);
-}
-
diff --git a/toolbox/umount.c b/toolbox/umount.c
deleted file mode 100644
index 3e17396..0000000
--- a/toolbox/umount.c
+++ /dev/null
@@ -1,90 +0,0 @@
-
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <linux/loop.h>
-#include <errno.h>
-
-#define LOOPDEV_MAXLEN 64
-#define LOOP_MAJOR 7
-
-static int is_loop(char *dev)
-{
-    struct stat st;
-    int ret = 0;
-
-    if (stat(dev, &st) == 0) {
-        if (S_ISBLK(st.st_mode) && (major(st.st_rdev) == LOOP_MAJOR)) {
-            ret = 1;
-        }
-    }
-
-    return ret;
-}
-
-static int is_loop_mount(const char* path, char *loopdev)
-{
-    FILE* f;
-    int count;
-    char device[256];
-    char mount_path[256];
-    char rest[256];
-    int result = 0;
-    
-    f = fopen("/proc/mounts", "r");
-    if (!f) {
-        fprintf(stdout, "could not open /proc/mounts: %s\n", strerror(errno));
-        return -1;
-    }
-
-    do {
-        count = fscanf(f, "%255s %255s %255s\n", device, mount_path, rest);
-        if (count == 3) {
-            if (is_loop(device) && strcmp(path, mount_path) == 0) {
-                strlcpy(loopdev, device, LOOPDEV_MAXLEN);
-                result = 1;
-                break;
-            }
-        }
-    } while (count == 3);
-
-    fclose(f);
-    return result;
-}
-
-int umount_main(int argc, char *argv[])
-{
-    int loop, loop_fd;
-    char loopdev[LOOPDEV_MAXLEN];
-
-    if(argc != 2) {
-        fprintf(stderr,"umount <path>\n");
-        return 1;
-    }
-
-    loop = is_loop_mount(argv[1], loopdev);
-    if (umount(argv[1])) {
-        fprintf(stderr, "failed: %s\n", strerror(errno));
-        return 1;
-    }
-
-    if (loop) {
-        // free the loop device
-        loop_fd = open(loopdev, O_RDONLY);
-        if (loop_fd < 0) {
-            fprintf(stderr, "open loop device failed: %s\n", strerror(errno));
-            return 1;
-        }
-        if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
-            fprintf(stderr, "ioctl LOOP_CLR_FD failed: %s\n", strerror(errno));
-            return 1;
-        }
-
-        close(loop_fd);
-    }
-
-    return 0;
-}
diff --git a/toolbox/upstream-netbsd/bin/cat/cat.c b/toolbox/upstream-netbsd/bin/cat/cat.c
deleted file mode 100644
index cca8cf5..0000000
--- a/toolbox/upstream-netbsd/bin/cat/cat.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/* $NetBSD: cat.c,v 1.54 2013/12/08 08:32:13 spz Exp $	*/
-
-/*
- * Copyright (c) 1989, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kevin Fall.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
- */
-
-#if HAVE_NBTOOL_CONFIG_H
-#include "nbtool_config.h"
-#endif
-
-#include <sys/cdefs.h>
-#if !defined(lint)
-__COPYRIGHT(
-"@(#) Copyright (c) 1989, 1993\
- The Regents of the University of California.  All rights reserved.");
-#if 0
-static char sccsid[] = "@(#)cat.c	8.2 (Berkeley) 4/27/95";
-#else
-__RCSID("$NetBSD: cat.c,v 1.54 2013/12/08 08:32:13 spz Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/param.h>
-#include <sys/stat.h>
-
-#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <locale.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-static int bflag, eflag, fflag, lflag, nflag, sflag, tflag, vflag;
-static size_t bsize;
-static int rval;
-static const char *filename;
-
-void cook_args(char *argv[]);
-void cook_buf(FILE *);
-void raw_args(char *argv[]);
-void raw_cat(int);
-
-int
-main(int argc, char *argv[])
-{
-	int ch;
-	struct flock stdout_lock;
-
-	setprogname(argv[0]);
-	(void)setlocale(LC_ALL, "");
-
-	while ((ch = getopt(argc, argv, "B:beflnstuv")) != -1)
-		switch (ch) {
-		case 'B':
-			bsize = (size_t)strtol(optarg, NULL, 0);
-			break;
-		case 'b':
-			bflag = nflag = 1;	/* -b implies -n */
-			break;
-		case 'e':
-			eflag = vflag = 1;	/* -e implies -v */
-			break;
-		case 'f':
-			fflag = 1;
-			break;
-		case 'l':
-			lflag = 1;
-			break;
-		case 'n':
-			nflag = 1;
-			break;
-		case 's':
-			sflag = 1;
-			break;
-		case 't':
-			tflag = vflag = 1;	/* -t implies -v */
-			break;
-		case 'u':
-			setbuf(stdout, NULL);
-			break;
-		case 'v':
-			vflag = 1;
-			break;
-		default:
-		case '?':
-			(void)fprintf(stderr,
-			    "Usage: %s [-beflnstuv] [-B bsize] [-] "
-			    "[file ...]\n", getprogname());
-			return EXIT_FAILURE;
-		}
-	argv += optind;
-
-	if (lflag) {
-		stdout_lock.l_len = 0;
-		stdout_lock.l_start = 0;
-		stdout_lock.l_type = F_WRLCK;
-		stdout_lock.l_whence = SEEK_SET;
-		if (fcntl(STDOUT_FILENO, F_SETLKW, &stdout_lock) == -1)
-			err(EXIT_FAILURE, "stdout");
-	}
-
-	if (bflag || eflag || nflag || sflag || tflag || vflag)
-		cook_args(argv);
-	else
-		raw_args(argv);
-	if (fclose(stdout))
-		err(EXIT_FAILURE, "stdout");
-	return rval;
-}
-
-void
-cook_args(char **argv)
-{
-	FILE *fp;
-
-	fp = stdin;
-	filename = "stdin";
-	do {
-		if (*argv) {
-			if (!strcmp(*argv, "-"))
-				fp = stdin;
-			else if ((fp = fopen(*argv,
-			    fflag ? "rf" : "r")) == NULL) {
-				warn("%s", *argv);
-				rval = EXIT_FAILURE;
-				++argv;
-				continue;
-			}
-			filename = *argv++;
-		}
-		cook_buf(fp);
-		if (fp != stdin)
-			(void)fclose(fp);
-		else
-			clearerr(fp);
-	} while (*argv);
-}
-
-void
-cook_buf(FILE *fp)
-{
-	int ch, gobble, line, prev;
-
-	line = gobble = 0;
-	for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
-		if (prev == '\n') {
-			if (ch == '\n') {
-				if (sflag) {
-					if (!gobble && nflag && !bflag)
-						(void)fprintf(stdout,
-							"%6d\t\n", ++line);
-					else if (!gobble && putchar(ch) == EOF)
-						break;
-					gobble = 1;
-					continue;
-				}
-				if (nflag) {
-					if (!bflag) {
-						(void)fprintf(stdout,
-						    "%6d\t", ++line);
-						if (ferror(stdout))
-							break;
-					} else if (eflag) {
-						(void)fprintf(stdout,
-						    "%6s\t", "");
-						if (ferror(stdout))
-							break;
-					}
-				}
-			} else if (nflag) {
-				(void)fprintf(stdout, "%6d\t", ++line);
-				if (ferror(stdout))
-					break;
-			}
-		}
-		gobble = 0;
-		if (ch == '\n') {
-			if (eflag)
-				if (putchar('$') == EOF)
-					break;
-		} else if (ch == '\t') {
-			if (tflag) {
-				if (putchar('^') == EOF || putchar('I') == EOF)
-					break;
-				continue;
-			}
-		} else if (vflag) {
-			if (!isascii(ch)) {
-				if (putchar('M') == EOF || putchar('-') == EOF)
-					break;
-				ch = toascii(ch);
-			}
-			if (iscntrl(ch)) {
-				if (putchar('^') == EOF ||
-				    putchar(ch == '\177' ? '?' :
-				    ch | 0100) == EOF)
-					break;
-				continue;
-			}
-		}
-		if (putchar(ch) == EOF)
-			break;
-	}
-	if (ferror(fp)) {
-		warn("%s", filename);
-		rval = EXIT_FAILURE;
-		clearerr(fp);
-	}
-	if (ferror(stdout))
-		err(EXIT_FAILURE, "stdout");
-}
-
-void
-raw_args(char **argv)
-{
-	int fd;
-
-	fd = fileno(stdin);
-	filename = "stdin";
-	do {
-		if (*argv) {
-			if (!strcmp(*argv, "-")) {
-				fd = fileno(stdin);
-				if (fd < 0)
-					goto skip;
-			} else if (fflag) {
-				struct stat st;
-				fd = open(*argv, O_RDONLY|O_NONBLOCK, 0);
-				if (fd < 0)
-					goto skip;
-
-				if (fstat(fd, &st) == -1) {
-					close(fd);
-					goto skip;
-				}
-				if (!S_ISREG(st.st_mode)) {
-					close(fd);
-					warnx("%s: not a regular file", *argv);
-					goto skipnomsg;
-				}
-			}
-			else if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
-skip:
-				warn("%s", *argv);
-skipnomsg:
-				rval = EXIT_FAILURE;
-				++argv;
-				continue;
-			}
-			filename = *argv++;
-		} else if (fd < 0) {
-			err(EXIT_FAILURE, "stdin");
-		}
-		raw_cat(fd);
-		if (fd != fileno(stdin))
-			(void)close(fd);
-	} while (*argv);
-}
-
-void
-raw_cat(int rfd)
-{
-	static char *buf;
-	static char fb_buf[BUFSIZ];
-
-	ssize_t nr, nw, off;
-	int wfd;
-
-	wfd = fileno(stdout);
-	if (wfd < 0)
-		err(EXIT_FAILURE, "stdout");
-	if (buf == NULL) {
-		struct stat sbuf;
-
-		if (bsize == 0) {
-			if (fstat(wfd, &sbuf) == 0 && sbuf.st_blksize > 0 &&
-			    (size_t)sbuf.st_blksize > sizeof(fb_buf))
-				bsize = sbuf.st_blksize;
-		}
-		if (bsize > sizeof(fb_buf)) {
-			buf = malloc(bsize);
-			if (buf == NULL)
-				warnx("malloc, using %zu buffer", bsize);
-		}
-		if (buf == NULL) {
-			bsize = sizeof(fb_buf);
-			buf = fb_buf;
-		}
-	}
-	while ((nr = read(rfd, buf, bsize)) > 0)
-		for (off = 0; nr; nr -= nw, off += nw)
-			if ((nw = write(wfd, buf + off, (size_t)nr)) < 0)
-				err(EXIT_FAILURE, "stdout");
-	if (nr < 0) {
-		warn("%s", filename);
-		rval = EXIT_FAILURE;
-	}
-}
diff --git a/toolbox/upstream-netbsd/bin/cp/cp.c b/toolbox/upstream-netbsd/bin/cp/cp.c
deleted file mode 100644
index 4bbe1b7..0000000
--- a/toolbox/upstream-netbsd/bin/cp/cp.c
+++ /dev/null
@@ -1,548 +0,0 @@
-/* $NetBSD: cp.c,v 1.58 2012/01/04 15:58:37 christos Exp $ */
-
-/*
- * Copyright (c) 1988, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * David Hitz of Auspex Systems Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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 <sys/cdefs.h>
-#ifndef lint
-__COPYRIGHT(
-"@(#) Copyright (c) 1988, 1993, 1994\
- The Regents of the University of California.  All rights reserved.");
-#endif /* not lint */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)cp.c	8.5 (Berkeley) 4/29/95";
-#else
-__RCSID("$NetBSD: cp.c,v 1.58 2012/01/04 15:58:37 christos Exp $");
-#endif
-#endif /* not lint */
-
-/*
- * Cp copies source files to target files.
- * 
- * The global PATH_T structure "to" always contains the path to the
- * current target file.  Since fts(3) does not change directories,
- * this path can be either absolute or dot-relative.
- * 
- * The basic algorithm is to initialize "to" and use fts(3) to traverse
- * the file hierarchy rooted in the argument list.  A trivial case is the
- * case of 'cp file1 file2'.  The more interesting case is the case of
- * 'cp file1 file2 ... fileN dir' where the hierarchy is traversed and the
- * path (relative to the root of the traversal) is appended to dir (stored
- * in "to") to form the final target path.
- */
-
-#include <sys/param.h>
-#include <sys/stat.h>
-
-#include <assert.h>
-#include <err.h>
-#include <errno.h>
-#include <fts.h>
-#include <locale.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "extern.h"
-
-#define	STRIP_TRAILING_SLASH(p) {					\
-        while ((p).p_end > (p).p_path + 1 && (p).p_end[-1] == '/')	\
-                *--(p).p_end = '\0';					\
-}
-
-static char empty[] = "";
-PATH_T to = { .p_end = to.p_path, .target_end = empty  };
-
-uid_t myuid;
-int Hflag, Lflag, Rflag, Pflag, fflag, iflag, lflag, pflag, rflag, vflag, Nflag;
-mode_t myumask;
-sig_atomic_t pinfo;
-
-enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
-
-static int copy(char *[], enum op, int);
-
-static void
-progress(int sig __unused)
-{
-
-	pinfo++;
-}
-
-int
-main(int argc, char *argv[])
-{
-	struct stat to_stat, tmp_stat;
-	enum op type;
-	int ch, fts_options, r, have_trailing_slash;
-	char *target, **src;
-
-	setprogname(argv[0]);
-	(void)setlocale(LC_ALL, "");
-
-	Hflag = Lflag = Pflag = Rflag = 0;
-	while ((ch = getopt(argc, argv, "HLNPRfailprv")) != -1) 
-		switch (ch) {
-		case 'H':
-			Hflag = 1;
-			Lflag = Pflag = 0;
-			break;
-		case 'L':
-			Lflag = 1;
-			Hflag = Pflag = 0;
-			break;
-		case 'N':
-			Nflag = 1;
-			break;
-		case 'P':
-			Pflag = 1;
-			Hflag = Lflag = 0;
-			break;
-		case 'R':
-			Rflag = 1;
-			break;
-		case 'a':
-			Pflag = 1;
-			pflag = 1;
-			Rflag = 1;
-			Hflag = Lflag = 0;
-			break;
-		case 'f':
-			fflag = 1;
-			iflag = 0;
-			break;
-		case 'i':
-			iflag = isatty(fileno(stdin));
-			fflag = 0;
-			break;
-		case 'l':
-			lflag = 1;
-			break;
-		case 'p':
-			pflag = 1;
-			break;
-		case 'r':
-			rflag = 1;
-			break;
-		case 'v':
-			vflag = 1;
-			break;
-		case '?':
-		default:
-			usage();
-			/* NOTREACHED */
-		}
-	argc -= optind;
-	argv += optind;
-
-	if (argc < 2)
-		usage();
-
-	fts_options = FTS_NOCHDIR | FTS_PHYSICAL;
-	if (rflag) {
-		if (Rflag) {
-			errx(EXIT_FAILURE,
-		    "the -R and -r options may not be specified together.");
-			/* NOTREACHED */
-		}
-		if (Hflag || Lflag || Pflag) {
-			errx(EXIT_FAILURE,
-	"the -H, -L, and -P options may not be specified with the -r option.");
-			/* NOTREACHED */
-		}
-		fts_options &= ~FTS_PHYSICAL;
-		fts_options |= FTS_LOGICAL;
-	}
-
-	if (Rflag) {
-		if (Hflag)
-			fts_options |= FTS_COMFOLLOW;
-		if (Lflag) {
-			fts_options &= ~FTS_PHYSICAL;
-			fts_options |= FTS_LOGICAL;
-		}
-	} else if (!Pflag) {
-		fts_options &= ~FTS_PHYSICAL;
-		fts_options |= FTS_LOGICAL | FTS_COMFOLLOW;
-	}
-
-	myuid = getuid();
-
-	/* Copy the umask for explicit mode setting. */
-	myumask = umask(0);
-	(void)umask(myumask);
-
-	/* Save the target base in "to". */
-	target = argv[--argc];
-	if (strlcpy(to.p_path, target, sizeof(to.p_path)) >= sizeof(to.p_path))
-		errx(EXIT_FAILURE, "%s: name too long", target);
-	to.p_end = to.p_path + strlen(to.p_path);
-	have_trailing_slash = (to.p_end[-1] == '/');
-	if (have_trailing_slash)
-		STRIP_TRAILING_SLASH(to);
-	to.target_end = to.p_end;
-
-	/* Set end of argument list for fts(3). */
-	argv[argc] = NULL;     
-	
-	(void)signal(SIGINFO, progress);
-	
-	/*
-	 * Cp has two distinct cases:
-	 *
-	 * cp [-R] source target
-	 * cp [-R] source1 ... sourceN directory
-	 *
-	 * In both cases, source can be either a file or a directory.
-	 *
-	 * In (1), the target becomes a copy of the source. That is, if the
-	 * source is a file, the target will be a file, and likewise for
-	 * directories.
-	 *
-	 * In (2), the real target is not directory, but "directory/source".
-	 */
-	if (Pflag)
-		r = lstat(to.p_path, &to_stat);
-	else
-		r = stat(to.p_path, &to_stat);
-	if (r == -1 && errno != ENOENT) {
-		err(EXIT_FAILURE, "%s", to.p_path);
-		/* NOTREACHED */
-	}
-	if (r == -1 || !S_ISDIR(to_stat.st_mode)) {
-		/*
-		 * Case (1).  Target is not a directory.
-		 */ 
-		if (argc > 1)
-			usage();
-		/*
-		 * Need to detect the case:
-		 *	cp -R dir foo
-		 * Where dir is a directory and foo does not exist, where
-		 * we want pathname concatenations turned on but not for
-		 * the initial mkdir().
-		 */
-		if (r == -1) {
-			if (rflag || (Rflag && (Lflag || Hflag)))
-				r = stat(*argv, &tmp_stat);
-			else
-				r = lstat(*argv, &tmp_stat);
-			if (r == -1) {
-				err(EXIT_FAILURE, "%s", *argv);
-				/* NOTREACHED */
-			}
-			
-			if (S_ISDIR(tmp_stat.st_mode) && (Rflag || rflag))
-				type = DIR_TO_DNE;
-			else
-				type = FILE_TO_FILE;
-		} else
-			type = FILE_TO_FILE;
-
-		if (have_trailing_slash && type == FILE_TO_FILE) {
-			if (r == -1)
-				errx(1, "directory %s does not exist",
-				     to.p_path);
-			else
-				errx(1, "%s is not a directory", to.p_path);
-		}
-	} else {
-		/*
-		 * Case (2).  Target is a directory.
-		 */
-		type = FILE_TO_DIR;
-	}
-
-	/*
-	 * make "cp -rp src/ dst" behave like "cp -rp src dst" not
-	 * like "cp -rp src/. dst"
-	 */
-	for (src = argv; *src; src++) {
-		size_t len = strlen(*src);
-		while (len-- > 1 && (*src)[len] == '/')
-			(*src)[len] = '\0';
-	}
-
-	exit(copy(argv, type, fts_options));
-	/* NOTREACHED */
-}
-
-static int dnestack[MAXPATHLEN]; /* unlikely we'll have more nested dirs */
-static ssize_t dnesp;
-static void
-pushdne(int dne)
-{
-
-	dnestack[dnesp++] = dne;
-	assert(dnesp < MAXPATHLEN);
-}
-
-static int
-popdne(void)
-{
-	int rv;
-
-	rv = dnestack[--dnesp];
-	assert(dnesp >= 0);
-	return rv;
-}
-
-static int
-copy(char *argv[], enum op type, int fts_options)
-{
-	struct stat to_stat;
-	FTS *ftsp;
-	FTSENT *curr;
-	int base, dne, sval;
-	int this_failed, any_failed;
-	size_t nlen;
-	char *p, *target_mid;
-
-	base = 0;	/* XXX gcc -Wuninitialized (see comment below) */
-
-	if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL)
-		err(EXIT_FAILURE, "%s", argv[0]);
-		/* NOTREACHED */
-	for (any_failed = 0; (curr = fts_read(ftsp)) != NULL;) {
-		this_failed = 0;
-		switch (curr->fts_info) {
-		case FTS_NS:
-		case FTS_DNR:
-		case FTS_ERR:
-			warnx("%s: %s", curr->fts_path,
-					strerror(curr->fts_errno));
-			this_failed = any_failed = 1;
-			continue;
-		case FTS_DC:			/* Warn, continue. */
-			warnx("%s: directory causes a cycle", curr->fts_path);
-			this_failed = any_failed = 1;
-			continue;
-		}
-
-		/*
-		 * If we are in case (2) or (3) above, we need to append the 
-                 * source name to the target name.  
-                 */
-		if (type != FILE_TO_FILE) {
-			if ((curr->fts_namelen +
-			    to.target_end - to.p_path + 1) > MAXPATHLEN) {
-				warnx("%s/%s: name too long (not copied)",
-						to.p_path, curr->fts_name);
-				this_failed = any_failed = 1;
-				continue;
-			}
-
-			/*
-			 * Need to remember the roots of traversals to create
-			 * correct pathnames.  If there's a directory being
-			 * copied to a non-existent directory, e.g.
-			 *	cp -R a/dir noexist
-			 * the resulting path name should be noexist/foo, not
-			 * noexist/dir/foo (where foo is a file in dir), which
-			 * is the case where the target exists.
-			 *
-			 * Also, check for "..".  This is for correct path
-			 * concatentation for paths ending in "..", e.g.
-			 *	cp -R .. /tmp
-			 * Paths ending in ".." are changed to ".".  This is
-			 * tricky, but seems the easiest way to fix the problem.
-			 *
-			 * XXX
-			 * Since the first level MUST be FTS_ROOTLEVEL, base
-			 * is always initialized.
-			 */
-			if (curr->fts_level == FTS_ROOTLEVEL) {
-				if (type != DIR_TO_DNE) {
-					p = strrchr(curr->fts_path, '/');
-					base = (p == NULL) ? 0 : 
-					    (int)(p - curr->fts_path + 1);
-
-					if (!strcmp(&curr->fts_path[base], 
-					    ".."))
-						base += 1;
-				} else
-					base = curr->fts_pathlen;
-			}
-
-			p = &curr->fts_path[base];
-			nlen = curr->fts_pathlen - base;
-			target_mid = to.target_end;
-			if (*p != '/' && target_mid[-1] != '/')
-				*target_mid++ = '/';
-			*target_mid = 0;
-
-			if (target_mid - to.p_path + nlen >= PATH_MAX) {
-				warnx("%s%s: name too long (not copied)",
-				    to.p_path, p);
-				this_failed = any_failed = 1;
-				continue;
-			}
-			(void)strncat(target_mid, p, nlen);
-			to.p_end = target_mid + nlen;
-			*to.p_end = 0;
-			STRIP_TRAILING_SLASH(to);
-		}
-
-		sval = Pflag ? lstat(to.p_path, &to_stat) : stat(to.p_path, &to_stat);
-		/* Not an error but need to remember it happened */
-		if (sval == -1)
-			dne = 1;
-		else {
-			if (to_stat.st_dev == curr->fts_statp->st_dev &&
-			    to_stat.st_ino == curr->fts_statp->st_ino) {
-				warnx("%s and %s are identical (not copied).",
-				    to.p_path, curr->fts_path);
-				this_failed = any_failed = 1;
-				if (S_ISDIR(curr->fts_statp->st_mode))
-					(void)fts_set(ftsp, curr, FTS_SKIP);
-				continue;
-			}
-			if (!S_ISDIR(curr->fts_statp->st_mode) &&
-			    S_ISDIR(to_stat.st_mode)) {
-		warnx("cannot overwrite directory %s with non-directory %s",
-				    to.p_path, curr->fts_path);
-				this_failed = any_failed = 1;
-				continue;
-			}
-			dne = 0;
-		}
-
-		switch (curr->fts_statp->st_mode & S_IFMT) {
-		case S_IFLNK:
-			/* Catch special case of a non dangling symlink */
-			if((fts_options & FTS_LOGICAL) ||
-			   ((fts_options & FTS_COMFOLLOW) && curr->fts_level == 0)) {
-				if (copy_file(curr, dne))
-					this_failed = any_failed = 1;
-			} else {	
-				if (copy_link(curr, !dne))
-					this_failed = any_failed = 1;
-			}
-			break;
-		case S_IFDIR:
-			if (!Rflag && !rflag) {
-				if (curr->fts_info == FTS_D)
-					warnx("%s is a directory (not copied).",
-					    curr->fts_path);
-				(void)fts_set(ftsp, curr, FTS_SKIP);
-				this_failed = any_failed = 1;
-				break;
-			}
-
-                        /*
-                         * Directories get noticed twice:
-                         *  In the first pass, create it if needed.
-                         *  In the second pass, after the children have been copied, set the permissions.
-                         */
-			if (curr->fts_info == FTS_D) /* First pass */
-			{
-				/*
-				 * If the directory doesn't exist, create the new
-				 * one with the from file mode plus owner RWX bits,
-				 * modified by the umask.  Trade-off between being
-				 * able to write the directory (if from directory is
-				 * 555) and not causing a permissions race.  If the
-				 * umask blocks owner writes, we fail..
-				 */
-				pushdne(dne);
-				if (dne) {
-					if (mkdir(to.p_path, 
-					    curr->fts_statp->st_mode | S_IRWXU) < 0)
-						err(EXIT_FAILURE, "%s",
-						    to.p_path);
-						/* NOTREACHED */
-				} else if (!S_ISDIR(to_stat.st_mode)) {
-					errno = ENOTDIR;
-					err(EXIT_FAILURE, "%s",
-						to.p_path);
-					/* NOTREACHED */
-				}
-			}
-			else if (curr->fts_info == FTS_DP) /* Second pass */
-			{
-	                        /*
-				 * If not -p and directory didn't exist, set it to be
-				 * the same as the from directory, umodified by the 
-                        	 * umask; arguably wrong, but it's been that way 
-                        	 * forever.
-				 */
-				if (pflag && setfile(curr->fts_statp, 0))
-					this_failed = any_failed = 1;
-				else if ((dne = popdne()))
-					(void)chmod(to.p_path, 
-					    curr->fts_statp->st_mode);
-			}
-			else
-			{
-				warnx("directory %s encountered when not expected.",
-				    curr->fts_path);
-				this_failed = any_failed = 1;
-				break;
-			}
-
-			break;
-		case S_IFBLK:
-		case S_IFCHR:
-			if (Rflag) {
-				if (copy_special(curr->fts_statp, !dne))
-					this_failed = any_failed = 1;
-			} else
-				if (copy_file(curr, dne))
-					this_failed = any_failed = 1;
-			break;
-		case S_IFIFO:
-			if (Rflag) {
-				if (copy_fifo(curr->fts_statp, !dne))
-					this_failed = any_failed = 1;
-			} else 
-				if (copy_file(curr, dne))
-					this_failed = any_failed = 1;
-			break;
-		default:
-			if (copy_file(curr, dne))
-				this_failed = any_failed = 1;
-			break;
-		}
-		if (vflag && !this_failed)
-			(void)printf("%s -> %s\n", curr->fts_path, to.p_path);
-	}
-	if (errno) {
-		err(EXIT_FAILURE, "fts_read");
-		/* NOTREACHED */
-	}
-	(void)fts_close(ftsp);
-	return (any_failed);
-}
diff --git a/toolbox/upstream-netbsd/bin/cp/extern.h b/toolbox/upstream-netbsd/bin/cp/extern.h
deleted file mode 100644
index e393844..0000000
--- a/toolbox/upstream-netbsd/bin/cp/extern.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* $NetBSD: extern.h,v 1.17 2012/01/04 15:58:37 christos Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
- *
- *	@(#)extern.h	8.2 (Berkeley) 4/1/94
- */
-
-#ifndef _EXTERN_H_
-#define _EXTERN_H_
-
-typedef struct {
-	char *p_end;			/* pointer to NULL at end of path */
-	char *target_end;		/* pointer to end of target base */
-	char p_path[MAXPATHLEN + 1];	/* pointer to the start of a path */
-} PATH_T;
-
-extern PATH_T to;
-extern uid_t myuid;
-extern int Rflag, rflag, Hflag, Lflag, Pflag, fflag, iflag, lflag, pflag, Nflag;
-extern mode_t myumask;
-extern sig_atomic_t pinfo;
-
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-int	copy_fifo(struct stat *, int);
-int	copy_file(FTSENT *, int);
-int	copy_link(FTSENT *, int);
-int	copy_special(struct stat *, int);
-int	set_utimes(const char *, struct stat *);
-int	setfile(struct stat *, int);
-void	usage(void) __attribute__((__noreturn__));
-__END_DECLS
-
-#endif /* !_EXTERN_H_ */
diff --git a/toolbox/upstream-netbsd/bin/cp/utils.c b/toolbox/upstream-netbsd/bin/cp/utils.c
deleted file mode 100644
index d8f900a..0000000
--- a/toolbox/upstream-netbsd/bin/cp/utils.c
+++ /dev/null
@@ -1,444 +0,0 @@
-/* $NetBSD: utils.c,v 1.42 2013/12/11 06:00:11 dholland Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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 <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)utils.c	8.3 (Berkeley) 4/1/94";
-#else
-__RCSID("$NetBSD: utils.c,v 1.42 2013/12/11 06:00:11 dholland Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/mman.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/extattr.h>
-
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <fts.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "extern.h"
-
-#define	MMAP_MAX_SIZE	(8 * 1048576)
-#define	MMAP_MAX_WRITE	(64 * 1024)
-
-int
-set_utimes(const char *file, struct stat *fs)
-{
-    static struct timeval tv[2];
-
-#ifdef __ANDROID__
-    tv[0].tv_sec = fs->st_atime;
-    tv[0].tv_usec = 0;
-    tv[1].tv_sec = fs->st_mtime;
-    tv[1].tv_usec = 0;
-
-    if (utimes(file, tv)) {
-        warn("utimes: %s", file);
-        return 1;
-    }
-#else
-    TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec);
-    TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec);
-
-    if (lutimes(file, tv)) {
-	warn("lutimes: %s", file);
-	return (1);
-    }
-#endif
-    return (0);
-}
-
-struct finfo {
-	const char *from;
-	const char *to;
-	size_t size;
-};
-
-static void
-progress(const struct finfo *fi, size_t written)
-{
-	int pcent = (int)((100.0 * written) / fi->size);
-
-	pinfo = 0;
-	(void)fprintf(stderr, "%s => %s %zu/%zu bytes %d%% written\n",
-	    fi->from, fi->to, written, fi->size, pcent);
-}
-
-int
-copy_file(FTSENT *entp, int dne)
-{
-	static char buf[MAXBSIZE];
-	struct stat to_stat, *fs;
-	int ch, checkch, from_fd, rcount, rval, to_fd, tolnk, wcount;
-	char *p;
-	size_t ptotal = 0;
-	
-	if ((from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) {
-		warn("%s", entp->fts_path);
-		return (1);
-	}
-
-	to_fd = -1;
-	fs = entp->fts_statp;
-	tolnk = ((Rflag && !(Lflag || Hflag)) || Pflag);
-
-	/*
-	 * If the file exists and we're interactive, verify with the user.
-	 * If the file DNE, set the mode to be the from file, minus setuid
-	 * bits, modified by the umask; arguably wrong, but it makes copying
-	 * executables work right and it's been that way forever.  (The
-	 * other choice is 666 or'ed with the execute bits on the from file
-	 * modified by the umask.)
-	 */
-	if (!dne) {
-		struct stat sb;
-		int sval;
-
-		if (iflag) {
-			(void)fprintf(stderr, "overwrite %s? ", to.p_path);
-			checkch = ch = getchar();
-			while (ch != '\n' && ch != EOF)
-				ch = getchar();
-			if (checkch != 'y' && checkch != 'Y') {
-				(void)close(from_fd);
-				return (0);
-			}
-		}
-
-		sval = tolnk ?
-			lstat(to.p_path, &sb) : stat(to.p_path, &sb);
-		if (sval == -1) {
-			warn("stat: %s", to.p_path);
-			(void)close(from_fd);
-			return (1);
-		}
-
-		if (!(tolnk && S_ISLNK(sb.st_mode)))
-			to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
-	} else
-		to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
-		    fs->st_mode & ~(S_ISUID | S_ISGID));
-
-	if (to_fd == -1 && (fflag || tolnk)) {
-		/*
-		 * attempt to remove existing destination file name and
-		 * create a new file
-		 */
-		(void)unlink(to.p_path);
-		to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
-			     fs->st_mode & ~(S_ISUID | S_ISGID));
-	}
-
-	if (to_fd == -1) {
-		warn("%s", to.p_path);
-		(void)close(from_fd);
-		return (1);
-	}
-
-	rval = 0;
-
-	/* if hard linking then simply close the open fds, link and return */
-	if (lflag) {
-		(void)close(from_fd);
-		(void)close(to_fd);
-		(void)unlink(to.p_path);
-		if (link(entp->fts_path, to.p_path)) {
-			warn("%s", to.p_path);
-			return (1);
-		}
-		return (0);
-	}
-
-	/*
-	 * There's no reason to do anything other than close the file
-	 * now if it's empty, so let's not bother.
-	 */
-#ifndef __ANDROID__ // Files in /proc report length 0. mmap will fail but we'll fall back to read.
-	if (fs->st_size > 0) {
-#endif
-		struct finfo fi;
-
-		fi.from = entp->fts_path;
-		fi.to = to.p_path;
-		fi.size = (size_t)fs->st_size;
-
-		/*
-		 * Mmap and write if less than 8M (the limit is so
-		 * we don't totally trash memory on big files).
-		 * This is really a minor hack, but it wins some CPU back.
-		 */
-		bool use_read;
-
-		use_read = true;
-		if (fs->st_size <= MMAP_MAX_SIZE) {
-			size_t fsize = (size_t)fs->st_size;
-			p = mmap(NULL, fsize, PROT_READ, MAP_FILE|MAP_SHARED,
-			    from_fd, (off_t)0);
-			if (p != MAP_FAILED) {
-				size_t remainder;
-
-				use_read = false;
-
-				(void) madvise(p, (size_t)fs->st_size,
-				     MADV_SEQUENTIAL);
-
-				/*
-				 * Write out the data in small chunks to
-				 * avoid locking the output file for a
-				 * long time if the reading the data from
-				 * the source is slow.
-				 */
-				remainder = fsize;
-				do {
-					ssize_t chunk;
-
-					chunk = (remainder > MMAP_MAX_WRITE) ?
-					    MMAP_MAX_WRITE : remainder;
-					if (write(to_fd, &p[fsize - remainder],
-					    chunk) != chunk) {
-						warn("%s", to.p_path);
-						rval = 1;
-						break;
-					}
-					remainder -= chunk;
-					ptotal += chunk;
-					if (pinfo)
-						progress(&fi, ptotal);
-				} while (remainder > 0);
-
-				if (munmap(p, fsize) < 0) {
-					warn("%s", entp->fts_path);
-					rval = 1;
-				}
-			}
-		}
-
-		if (use_read) {
-			while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
-				wcount = write(to_fd, buf, (size_t)rcount);
-				if (rcount != wcount || wcount == -1) {
-					warn("%s", to.p_path);
-					rval = 1;
-					break;
-				}
-				ptotal += wcount;
-				if (pinfo)
-					progress(&fi, ptotal);
-			}
-			if (rcount < 0) {
-				warn("%s", entp->fts_path);
-				rval = 1;
-			}
-		}
-#ifndef __ANDROID__
-	}
-#endif
-
-#ifndef __ANDROID__
-	if (pflag && (fcpxattr(from_fd, to_fd) != 0))
-		warn("%s: error copying extended attributes", to.p_path);
-#endif
-
-	(void)close(from_fd);
-
-	if (rval == 1) {
-		(void)close(to_fd);
-		return (1);
-	}
-
-	if (pflag && setfile(fs, to_fd))
-		rval = 1;
-	/*
-	 * If the source was setuid or setgid, lose the bits unless the
-	 * copy is owned by the same user and group.
-	 */
-#define	RETAINBITS \
-	(S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
-	if (!pflag && dne
-	    && fs->st_mode & (S_ISUID | S_ISGID) && fs->st_uid == myuid) {
-		if (fstat(to_fd, &to_stat)) {
-			warn("%s", to.p_path);
-			rval = 1;
-		} else if (fs->st_gid == to_stat.st_gid &&
-		    fchmod(to_fd, fs->st_mode & RETAINBITS & ~myumask)) {
-			warn("%s", to.p_path);
-			rval = 1;
-		}
-	}
-	if (close(to_fd)) {
-		warn("%s", to.p_path);
-		rval = 1;
-	}
-	/* set the mod/access times now after close of the fd */
-	if (pflag && set_utimes(to.p_path, fs)) { 
-	    rval = 1;
-	}
-	return (rval);
-}
-
-int
-copy_link(FTSENT *p, int exists)
-{
-	int len;
-	char target[MAXPATHLEN];
-
-	if ((len = readlink(p->fts_path, target, sizeof(target)-1)) == -1) {
-		warn("readlink: %s", p->fts_path);
-		return (1);
-	}
-	target[len] = '\0';
-	if (exists && unlink(to.p_path)) {
-		warn("unlink: %s", to.p_path);
-		return (1);
-	}
-	if (symlink(target, to.p_path)) {
-		warn("symlink: %s", target);
-		return (1);
-	}
-	return (pflag ? setfile(p->fts_statp, 0) : 0);
-}
-
-int
-copy_fifo(struct stat *from_stat, int exists)
-{
-	if (exists && unlink(to.p_path)) {
-		warn("unlink: %s", to.p_path);
-		return (1);
-	}
-	if (mkfifo(to.p_path, from_stat->st_mode)) {
-		warn("mkfifo: %s", to.p_path);
-		return (1);
-	}
-	return (pflag ? setfile(from_stat, 0) : 0);
-}
-
-int
-copy_special(struct stat *from_stat, int exists)
-{
-	if (exists && unlink(to.p_path)) {
-		warn("unlink: %s", to.p_path);
-		return (1);
-	}
-	if (mknod(to.p_path, from_stat->st_mode, from_stat->st_rdev)) {
-		warn("mknod: %s", to.p_path);
-		return (1);
-	}
-	return (pflag ? setfile(from_stat, 0) : 0);
-}
-
-
-/*
- * Function: setfile
- *
- * Purpose:
- *   Set the owner/group/permissions for the "to" file to the information
- *   in the stat structure.  If fd is zero, also call set_utimes() to set
- *   the mod/access times.  If fd is non-zero, the caller must do a utimes
- *   itself after close(fd).
- */
-int
-setfile(struct stat *fs, int fd)
-{
-	int rval, islink;
-
-	rval = 0;
-	islink = S_ISLNK(fs->st_mode);
-	fs->st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
-
-	/*
-	 * Changing the ownership probably won't succeed, unless we're root
-	 * or POSIX_CHOWN_RESTRICTED is not set.  Set uid/gid before setting
-	 * the mode; current BSD behavior is to remove all setuid bits on
-	 * chown.  If chown fails, lose setuid/setgid bits.
-	 */
-	if (fd ? fchown(fd, fs->st_uid, fs->st_gid) :
-	    lchown(to.p_path, fs->st_uid, fs->st_gid)) {
-		if (errno != EPERM) {
-			warn("chown: %s", to.p_path);
-			rval = 1;
-		}
-		fs->st_mode &= ~(S_ISUID | S_ISGID);
-	}
-#ifdef __ANDROID__
-	if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) {
-#else
-	if (fd ? fchmod(fd, fs->st_mode) : lchmod(to.p_path, fs->st_mode)) {
-#endif
-		warn("chmod: %s", to.p_path);
-		rval = 1;
-	}
-
-#ifndef __ANDROID__
-	if (!islink && !Nflag) {
-		unsigned long fflags = fs->st_flags;
-		/*
-		 * XXX
-		 * NFS doesn't support chflags; ignore errors unless
-		 * there's reason to believe we're losing bits.
-		 * (Note, this still won't be right if the server
-		 * supports flags and we were trying to *remove* flags
-		 * on a file that we copied, i.e., that we didn't create.)
-		 */
-		errno = 0;
-		if ((fd ? fchflags(fd, fflags) :
-		    chflags(to.p_path, fflags)) == -1)
-			if (errno != EOPNOTSUPP || fs->st_flags != 0) {
-				warn("chflags: %s", to.p_path);
-				rval = 1;
-			}
-	}
-#endif
-	/* if fd is non-zero, caller must call set_utimes() after close() */
-	if (fd == 0 && set_utimes(to.p_path, fs))
-	    rval = 1;
-	return (rval);
-}
-
-void
-usage(void)
-{
-	(void)fprintf(stderr,
-	    "usage: %s [-R [-H | -L | -P]] [-f | -i] [-alNpv] src target\n"
-	    "       %s [-R [-H | -L | -P]] [-f | -i] [-alNpv] src1 ... srcN directory\n",
-	    getprogname(), getprogname());
-	exit(1);
-	/* NOTREACHED */
-}
diff --git a/toolbox/upstream-netbsd/bin/kill/kill.c b/toolbox/upstream-netbsd/bin/kill/kill.c
deleted file mode 100644
index 0592577..0000000
--- a/toolbox/upstream-netbsd/bin/kill/kill.c
+++ /dev/null
@@ -1,253 +0,0 @@
-/* $NetBSD: kill.c,v 1.27 2011/08/29 14:51:18 joerg Exp $ */
-
-/*
- * Copyright (c) 1988, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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 <sys/cdefs.h>
-#if !defined(lint) && !defined(SHELL)
-__COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\
- The Regents of the University of California.  All rights reserved.");
-#endif /* not lint */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)kill.c	8.4 (Berkeley) 4/28/95";
-#else
-__RCSID("$NetBSD: kill.c,v 1.27 2011/08/29 14:51:18 joerg Exp $");
-#endif
-#endif /* not lint */
-
-#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <inttypes.h>
-#include <string.h>
-#include <termios.h>
-#include <unistd.h>
-#include <locale.h>
-#include <sys/ioctl.h>
-
-#ifdef SHELL            /* sh (aka ash) builtin */
-int killcmd(int, char *argv[]);
-#define main killcmd
-#include "../../bin/sh/bltin/bltin.h"
-#endif /* SHELL */ 
-
-__dead static void nosig(char *);
-static void printsignals(FILE *);
-static int signame_to_signum(char *);
-__dead static void usage(void);
-
-int
-main(int argc, char *argv[])
-{
-	int errors;
-	intmax_t numsig, pid;
-	char *ep;
-
-	setprogname(argv[0]);
-	setlocale(LC_ALL, "");
-	if (argc < 2)
-		usage();
-
-	numsig = SIGTERM;
-
-	argc--, argv++;
-	if (strcmp(*argv, "-l") == 0) {
-		argc--, argv++;
-		if (argc > 1)
-			usage();
-		if (argc == 1) {
-			if (isdigit((unsigned char)**argv) == 0)
-				usage();
-			numsig = strtoimax(*argv, &ep, 10);
-			/* check for correctly parsed number */
-			if (*ep != '\0' || numsig == INTMAX_MIN || numsig == INTMAX_MAX) {
-				errx(EXIT_FAILURE, "illegal signal number: %s",
-						*argv);
-				/* NOTREACHED */
-			}
-			if (numsig >= 128)
-				numsig -= 128;
-			/* and whether it fits into signals range */
-			if (numsig <= 0 || numsig >= NSIG)
-				nosig(*argv);
-			printf("%s\n", sys_signame[(int) numsig]);
-			exit(0);
-		}
-		printsignals(stdout);
-		exit(0);
-	}
-
-	if (!strcmp(*argv, "-s")) {
-		argc--, argv++;
-		if (argc < 1) {
-			warnx("option requires an argument -- s");
-			usage();
-		}
-		if (strcmp(*argv, "0")) {
-			if ((numsig = signame_to_signum(*argv)) < 0)
-				nosig(*argv);
-		} else
-			numsig = 0;
-		argc--, argv++;
-	} else if (**argv == '-') {
-		char *sn = *argv + 1;
-		if (isalpha((unsigned char)*sn)) {
-			if ((numsig = signame_to_signum(sn)) < 0)
-				nosig(sn);
-		} else if (isdigit((unsigned char)*sn)) {
-			numsig = strtoimax(sn, &ep, 10);
-			/* check for correctly parsed number */
-			if (*ep || numsig == INTMAX_MIN || numsig == INTMAX_MAX ) {
-				errx(EXIT_FAILURE, "illegal signal number: %s",
-						sn);
-				/* NOTREACHED */
-			}
-			/* and whether it fits into signals range */
-			if (numsig < 0 || numsig >= NSIG)
-				nosig(sn);
-		} else
-			nosig(sn);
-		argc--, argv++;
-	}
-
-	if (argc == 0)
-		usage();
-
-	for (errors = 0; argc; argc--, argv++) {
-#ifdef SHELL
-		extern int getjobpgrp(const char *);
-		if (*argv[0] == '%') {
-			pid = getjobpgrp(*argv);
-			if (pid == 0) {
-				warnx("illegal job id: %s", *argv);
-				errors = 1;
-				continue;
-			}
-		} else 
-#endif
-		{
-			pid = strtoimax(*argv, &ep, 10);
-			/* make sure the pid is a number and fits into pid_t */
-			if (!**argv || *ep || pid == INTMAX_MIN ||
-				pid == INTMAX_MAX || pid != (pid_t) pid) {
-
-				warnx("illegal process id: %s", *argv);
-				errors = 1;
-				continue;
-			}
-		}
-		if (kill((pid_t) pid, (int) numsig) == -1) {
-			warn("%s", *argv);
-			errors = 1;
-		}
-#ifdef SHELL
-		/* Wakeup the process if it was suspended, so it can
-		   exit without an explicit 'fg'. */
-		if (numsig == SIGTERM || numsig == SIGHUP)
-			kill((pid_t) pid, SIGCONT);
-#endif
-	}
-
-	exit(errors);
-	/* NOTREACHED */
-}
-
-static int
-signame_to_signum(char *sig)
-{
-	int n;
-
-	if (strncasecmp(sig, "sig", 3) == 0)
-		sig += 3;
-	for (n = 1; n < NSIG; n++) {
-		if (!strcasecmp(sys_signame[n], sig))
-			return (n);
-	}
-	return (-1);
-}
-
-static void
-nosig(char *name)
-{
-
-	warnx("unknown signal %s; valid signals:", name);
-	printsignals(stderr);
-	exit(1);
-	/* NOTREACHED */
-}
-
-static void
-printsignals(FILE *fp)
-{
-	int sig;
-	int len, nl;
-	const char *name;
-	int termwidth = 80;
-
-	if (isatty(fileno(fp))) {
-		struct winsize win;
-		if (ioctl(fileno(fp), TIOCGWINSZ, &win) == 0 && win.ws_col > 0)
-			termwidth = win.ws_col;
-	}
-
-	for (len = 0, sig = 1; sig < NSIG; sig++) {
-		name = sys_signame[sig];
-		nl = 1 + strlen(name);
-
-		if (len + nl >= termwidth) {
-			fprintf(fp, "\n");
-			len = 0;
-		} else
-			if (len != 0)
-				fprintf(fp, " ");
-		len += nl;
-		fprintf(fp, "%s", name);
-	}
-	if (len != 0)
-		fprintf(fp, "\n");
-}
-
-static void
-usage(void)
-{
-
-	fprintf(stderr, "usage: %s [-s signal_name] pid ...\n"
-	    "       %s -l [exit_status]\n"
-	    "       %s -signal_name pid ...\n"
-	    "       %s -signal_number pid ...\n",
-	    getprogname(), getprogname(), getprogname(), getprogname());
-	exit(1);
-	/* NOTREACHED */
-}
diff --git a/toolbox/upstream-netbsd/bin/ln/ln.c b/toolbox/upstream-netbsd/bin/ln/ln.c
deleted file mode 100644
index 9127477..0000000
--- a/toolbox/upstream-netbsd/bin/ln/ln.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/* $NetBSD: ln.c,v 1.35 2011/08/29 14:38:30 joerg Exp $ */
-
-/*
- * Copyright (c) 1987, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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 <sys/cdefs.h>
-#ifndef lint
-__COPYRIGHT("@(#) Copyright (c) 1987, 1993, 1994\
- The Regents of the University of California.  All rights reserved.");
-#endif /* not lint */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)ln.c	8.2 (Berkeley) 3/31/94";
-#else
-__RCSID("$NetBSD: ln.c,v 1.35 2011/08/29 14:38:30 joerg Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/param.h>
-#include <sys/stat.h>
-
-#include <err.h>
-#include <errno.h>
-#include <locale.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-static int	fflag;				/* Unlink existing files. */
-static int	hflag;				/* Check new name for symlink first. */
-static int	iflag;				/* Interactive mode. */
-static int	sflag;				/* Symbolic, not hard, link. */
-static int	vflag;                          /* Verbose output */
-
-					/* System link call. */
-static int (*linkf)(const char *, const char *);
-static char   linkch;
-
-static int	linkit(const char *, const char *, int);
-__dead static void	usage(void);
-
-int
-main(int argc, char *argv[])
-{
-	struct stat sb;
-	int ch, exitval;
-	char *sourcedir;
-
-	setprogname(argv[0]);
-	(void)setlocale(LC_ALL, "");
-
-	while ((ch = getopt(argc, argv, "fhinsv")) != -1)
-		switch (ch) {
-		case 'f':
-			fflag = 1;
-			iflag = 0;
-			break;
-		case 'h':
-		case 'n':
-			hflag = 1;
-			break;
-		case 'i':
-			iflag = 1;
-			fflag = 0;
-			break;
-		case 's':
-			sflag = 1;
-			break;
-		case 'v':               
-			vflag = 1;
-			break;
-		case '?':
-		default:
-			usage();
-			/* NOTREACHED */
-		}
-
-	argv += optind;
-	argc -= optind;
-
-	if (sflag) {
-		linkf  = symlink;
-		linkch = '-';
-	} else {
-		linkf  = link;
-		linkch = '=';
-	}
-
-	switch(argc) {
-	case 0:
-		usage();
-		/* NOTREACHED */
-	case 1:				/* ln target */
-		exit(linkit(argv[0], ".", 1));
-		/* NOTREACHED */
-	case 2:				/* ln target source */
-		exit(linkit(argv[0], argv[1], 0));
-		/* NOTREACHED */
-	}
-
-					/* ln target1 target2 directory */
-	sourcedir = argv[argc - 1];
-	if (hflag && lstat(sourcedir, &sb) == 0 && S_ISLNK(sb.st_mode)) {
-		/* we were asked not to follow symlinks, but found one at
-		   the target--simulate "not a directory" error */
-		errno = ENOTDIR;
-		err(EXIT_FAILURE, "%s", sourcedir);
-		/* NOTREACHED */
-	}
-	if (stat(sourcedir, &sb)) {
-		err(EXIT_FAILURE, "%s", sourcedir);
-		/* NOTREACHED */
-	}
-	if (!S_ISDIR(sb.st_mode)) {
-		usage();
-		/* NOTREACHED */
-	}
-	for (exitval = 0; *argv != sourcedir; ++argv)
-		exitval |= linkit(*argv, sourcedir, 1);
-	exit(exitval);
-	/* NOTREACHED */
-}
-
-static int
-linkit(const char *target, const char *source, int isdir)
-{
-	struct stat sb;
-	const char *p;
-	char path[MAXPATHLEN];
-	int ch, exists, first;
-
-	if (!sflag) {
-		/* If target doesn't exist, quit now. */
-		if (stat(target, &sb)) {
-			warn("%s", target);
-			return (1);
-		}
-	}
-
-	/* If the source is a directory (and not a symlink if hflag),
-	   append the target's name. */
-	if (isdir ||
-	    (!lstat(source, &sb) && S_ISDIR(sb.st_mode)) ||
-	    (!hflag && !stat(source, &sb) && S_ISDIR(sb.st_mode))) {
-		if ((p = strrchr(target, '/')) == NULL)
-			p = target;
-		else
-			++p;
-		(void)snprintf(path, sizeof(path), "%s/%s", source, p);
-		source = path;
-	}
-
-	exists = !lstat(source, &sb);
-
-	/*
-	 * If the file exists, then unlink it forcibly if -f was specified
-	 * and interactively if -i was specified.
-	 */
-	if (fflag && exists) {
-		if (unlink(source)) {
-			warn("%s", source);
-			return (1);
-		}
-	} else if (iflag && exists) {
-		fflush(stdout);
-		(void)fprintf(stderr, "replace %s? ", source);
-
-		first = ch = getchar();
-		while (ch != '\n' && ch != EOF)
-			ch = getchar();
-		if (first != 'y' && first != 'Y') {
-			(void)fprintf(stderr, "not replaced\n");
-			return (1);
-		}
-
-		if (unlink(source)) {
-			warn("%s", source);
-			return (1);
-		}
-	}
-
-	/* Attempt the link. */
-	if ((*linkf)(target, source)) {
-		warn("%s", source);
-		return (1);
-	}
-	if (vflag)
-		(void)printf("%s %c> %s\n", source, linkch, target);
-
-	return (0);
-}
-
-static void
-usage(void)
-{
-
-	(void)fprintf(stderr,
-	    "usage:\t%s [-fhinsv] file1 file2\n\t%s [-fhinsv] file ... directory\n",
-	    getprogname(), getprogname());
-	exit(1);
-	/* NOTREACHED */
-}
diff --git a/toolbox/upstream-netbsd/bin/mv/mv.c b/toolbox/upstream-netbsd/bin/mv/mv.c
deleted file mode 100644
index 4be6c30..0000000
--- a/toolbox/upstream-netbsd/bin/mv/mv.c
+++ /dev/null
@@ -1,396 +0,0 @@
-/* $NetBSD: mv.c,v 1.43 2011/08/29 14:46:54 joerg Exp $ */
-
-/*
- * Copyright (c) 1989, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Ken Smith of The State University of New York at Buffalo.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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 <sys/cdefs.h>
-#ifndef lint
-__COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\
- The Regents of the University of California.  All rights reserved.");
-#endif /* not lint */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)mv.c	8.2 (Berkeley) 4/2/94";
-#else
-__RCSID("$NetBSD: mv.c,v 1.43 2011/08/29 14:46:54 joerg Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/param.h>
-#include <sys/time.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <sys/extattr.h>
-
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <grp.h>
-#include <locale.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "pathnames.h"
-
-static int fflg, iflg, vflg;
-static int stdin_ok;
-
-static int	copy(char *, char *);
-static int	do_move(char *, char *);
-static int	fastcopy(char *, char *, struct stat *);
-__dead static void	usage(void);
-
-int
-main(int argc, char *argv[])
-{
-	int ch, len, rval;
-	char *p, *endp;
-	struct stat sb;
-	char path[MAXPATHLEN + 1];
-	size_t baselen;
-
-	setprogname(argv[0]);
-	(void)setlocale(LC_ALL, "");
-
-	while ((ch = getopt(argc, argv, "ifv")) != -1)
-		switch (ch) {
-		case 'i':
-			fflg = 0;
-			iflg = 1;
-			break;
-		case 'f':
-			iflg = 0;
-			fflg = 1;
-			break;
-		case 'v':
-			vflg = 1;
-			break;
-		default:
-			usage();
-		}
-	argc -= optind;
-	argv += optind;
-
-	if (argc < 2)
-		usage();
-
-	stdin_ok = isatty(STDIN_FILENO);
-
-	/*
-	 * If the stat on the target fails or the target isn't a directory,
-	 * try the move.  More than 2 arguments is an error in this case.
-	 */
-	if (stat(argv[argc - 1], &sb) || !S_ISDIR(sb.st_mode)) {
-		if (argc > 2)
-			usage();
-		exit(do_move(argv[0], argv[1]));
-	}
-
-	/* It's a directory, move each file into it. */
-	baselen = strlcpy(path, argv[argc - 1], sizeof(path));
-	if (baselen >= sizeof(path))
-		errx(1, "%s: destination pathname too long", argv[argc - 1]);
-	endp = &path[baselen];
-	if (!baselen || *(endp - 1) != '/') {
-		*endp++ = '/';
-		++baselen;
-	}
-	for (rval = 0; --argc; ++argv) {
-		p = *argv + strlen(*argv) - 1;
-		while (*p == '/' && p != *argv)
-			*p-- = '\0';
-		if ((p = strrchr(*argv, '/')) == NULL)
-			p = *argv;
-		else
-			++p;
-
-		if ((baselen + (len = strlen(p))) >= MAXPATHLEN) {
-			warnx("%s: destination pathname too long", *argv);
-			rval = 1;
-		} else {
-			memmove(endp, p, len + 1);
-			if (do_move(*argv, path))
-				rval = 1;
-		}
-	}
-	exit(rval);
-	/* NOTREACHED */
-}
-
-static int
-do_move(char *from, char *to)
-{
-	struct stat sb;
-	char modep[15];
-
-	/*
-	 * (1)	If the destination path exists, the -f option is not specified
-	 *	and either of the following conditions are true:
-	 *
-	 *	(a) The permissions of the destination path do not permit
-	 *	    writing and the standard input is a terminal.
-	 *	(b) The -i option is specified.
-	 *
-	 *	the mv utility shall write a prompt to standard error and
-	 *	read a line from standard input.  If the response is not
-	 *	affirmative, mv shall do nothing more with the current
-	 *	source file...
-	 */
-	if (!fflg && !access(to, F_OK)) {
-		int ask = 1;
-		int ch;
-
-		if (iflg) {
-			if (access(from, F_OK)) {
-				warn("rename %s", from);
-				return (1);
-			}
-			(void)fprintf(stderr, "overwrite %s? ", to);
-		} else if (stdin_ok && access(to, W_OK) && !stat(to, &sb)) {
-			if (access(from, F_OK)) {
-				warn("rename %s", from);
-				return (1);
-			}
-			strmode(sb.st_mode, modep);
-			(void)fprintf(stderr, "override %s%s%s/%s for %s? ",
-			    modep + 1, modep[9] == ' ' ? "" : " ",
-			    user_from_uid(sb.st_uid, 0),
-			    group_from_gid(sb.st_gid, 0), to);
-		} else
-			ask = 0;
-		if (ask) {
-			if ((ch = getchar()) != EOF && ch != '\n') {
-				int ch2;
-				while ((ch2 = getchar()) != EOF && ch2 != '\n')
-					continue;
-			}
-			if (ch != 'y' && ch != 'Y')
-				return (0);
-		}
-	}
-
-	/*
-	 * (2)	If rename() succeeds, mv shall do nothing more with the
-	 *	current source file.  If it fails for any other reason than
-	 *	EXDEV, mv shall write a diagnostic message to the standard
-	 *	error and do nothing more with the current source file.
-	 *
-	 * (3)	If the destination path exists, and it is a file of type
-	 *	directory and source_file is not a file of type directory,
-	 *	or it is a file not of type directory, and source file is
-	 *	a file of type directory, mv shall write a diagnostic
-	 *	message to standard error, and do nothing more with the
-	 *	current source file...
-	 */
-	if (!rename(from, to)) {
-		if (vflg)
-			printf("%s -> %s\n", from, to);
-		return (0);
-	}
-
-	if (errno != EXDEV) {
-		warn("rename %s to %s", from, to);
-		return (1);
-	}
-
-	/*
-	 * (4)	If the destination path exists, mv shall attempt to remove it.
-	 *	If this fails for any reason, mv shall write a diagnostic
-	 *	message to the standard error and do nothing more with the
-	 *	current source file...
-	 */
-	if (!lstat(to, &sb)) {
-		if ((S_ISDIR(sb.st_mode)) ? rmdir(to) : unlink(to)) {
-			warn("can't remove %s", to);
-			return (1);
-		}
-	}
-
-	/*
-	 * (5)	The file hierarchy rooted in source_file shall be duplicated
-	 *	as a file hierarchy rooted in the destination path...
-	 */
-	if (lstat(from, &sb)) {
-		warn("%s", from);
-		return (1);
-	}
-
-	return (S_ISREG(sb.st_mode) ?
-	    fastcopy(from, to, &sb) : copy(from, to));
-}
-
-static int
-fastcopy(char *from, char *to, struct stat *sbp)
-{
-	struct timeval tval[2];
-	static blksize_t blen;
-	static char *bp;
-	int nread, from_fd, to_fd;
-
-	if ((from_fd = open(from, O_RDONLY, 0)) < 0) {
-		warn("%s", from);
-		return (1);
-	}
-	if ((to_fd =
-	    open(to, O_CREAT | O_TRUNC | O_WRONLY, sbp->st_mode)) < 0) {
-		warn("%s", to);
-		(void)close(from_fd);
-		return (1);
-	}
-	if (!blen && !(bp = malloc(blen = sbp->st_blksize))) {
-		warn(NULL);
-		blen = 0;
-		(void)close(from_fd);
-		(void)close(to_fd);
-		return (1);
-	}
-	while ((nread = read(from_fd, bp, blen)) > 0)
-		if (write(to_fd, bp, nread) != nread) {
-			warn("%s", to);
-			goto err;
-		}
-	if (nread < 0) {
-		warn("%s", from);
-err:		if (unlink(to))
-			warn("%s: remove", to);
-		(void)close(from_fd);
-		(void)close(to_fd);
-		return (1);
-	}
-
-#ifndef __ANDROID__
-	if (fcpxattr(from_fd, to_fd) == -1)
-		warn("%s: error copying extended attributes", to);
-#endif
-
-	(void)close(from_fd);
-#ifdef BSD4_4
-	TIMESPEC_TO_TIMEVAL(&tval[0], &sbp->st_atimespec);
-	TIMESPEC_TO_TIMEVAL(&tval[1], &sbp->st_mtimespec);
-#else
-	tval[0].tv_sec = sbp->st_atime;
-	tval[1].tv_sec = sbp->st_mtime;
-	tval[0].tv_usec = 0;
-	tval[1].tv_usec = 0;
-#endif
-#ifdef __SVR4
-	if (utimes(to, tval))
-#else
-	if (futimes(to_fd, tval))
-#endif
-		warn("%s: set times", to);
-	if (fchown(to_fd, sbp->st_uid, sbp->st_gid)) {
-		if (errno != EPERM)
-			warn("%s: set owner/group", to);
-		sbp->st_mode &= ~(S_ISUID | S_ISGID);
-	}
-	if (fchmod(to_fd, sbp->st_mode))
-		warn("%s: set mode", to);
-#ifndef __ANDROID__
-	if (fchflags(to_fd, sbp->st_flags) && (errno != EOPNOTSUPP))
-		warn("%s: set flags (was: 0%07o)", to, sbp->st_flags);
-#endif
-
-	if (close(to_fd)) {
-		warn("%s", to);
-		return (1);
-	}
-
-	if (unlink(from)) {
-		warn("%s: remove", from);
-		return (1);
-	}
-
-	if (vflg)
-		printf("%s -> %s\n", from, to);
-
-	return (0);
-}
-
-static int
-copy(char *from, char *to)
-{
-	pid_t pid;
-	int status;
-
-	if ((pid = vfork()) == 0) {
-		execl(_PATH_CP, "mv", vflg ? "-PRpv" : "-PRp", "--", from, to, NULL);
-		warn("%s", _PATH_CP);
-		_exit(1);
-	}
-	if (waitpid(pid, &status, 0) == -1) {
-		warn("%s: waitpid", _PATH_CP);
-		return (1);
-	}
-	if (!WIFEXITED(status)) {
-		warnx("%s: did not terminate normally", _PATH_CP);
-		return (1);
-	}
-	if (WEXITSTATUS(status)) {
-		warnx("%s: terminated with %d (non-zero) status",
-		    _PATH_CP, WEXITSTATUS(status));
-		return (1);
-	}
-	if (!(pid = vfork())) {
-		execl(_PATH_RM, "mv", "-rf", "--", from, NULL);
-		warn("%s", _PATH_RM);
-		_exit(1);
-	}
-	if (waitpid(pid, &status, 0) == -1) {
-		warn("%s: waitpid", _PATH_RM);
-		return (1);
-	}
-	if (!WIFEXITED(status)) {
-		warnx("%s: did not terminate normally", _PATH_RM);
-		return (1);
-	}
-	if (WEXITSTATUS(status)) {
-		warnx("%s: terminated with %d (non-zero) status",
-		    _PATH_RM, WEXITSTATUS(status));
-		return (1);
-	}
-	return (0);
-}
-
-static void
-usage(void)
-{
-	(void)fprintf(stderr, "usage: %s [-fiv] source target\n"
-	    "       %s [-fiv] source ... directory\n", getprogname(),
-	    getprogname());
-	exit(1);
-	/* NOTREACHED */
-}
diff --git a/toolbox/upstream-netbsd/bin/mv/pathnames.h b/toolbox/upstream-netbsd/bin/mv/pathnames.h
deleted file mode 100644
index 7838946..0000000
--- a/toolbox/upstream-netbsd/bin/mv/pathnames.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*	$NetBSD: pathnames.h,v 1.8 2004/08/19 22:26:07 christos Exp $	*/
-
-/*
- * Copyright (c) 1989, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
- *
- *	@(#)pathnames.h	8.1 (Berkeley) 5/31/93
- */
-
-#ifdef __ANDROID__
-#define	_PATH_RM	"/system/bin/rm"
-#define	_PATH_CP	"/system/bin/cp"
-#else
-#ifdef RESCUEDIR
-#define	_PATH_RM	RESCUEDIR "/rm"
-#define	_PATH_CP	RESCUEDIR "/cp"
-#else
-#define	_PATH_RM	"/bin/rm"
-#define	_PATH_CP	"/bin/cp"
-#endif
-#endif
diff --git a/toolbox/upstream-netbsd/bin/rm/rm.c b/toolbox/upstream-netbsd/bin/rm/rm.c
deleted file mode 100644
index f183810..0000000
--- a/toolbox/upstream-netbsd/bin/rm/rm.c
+++ /dev/null
@@ -1,625 +0,0 @@
-/* $NetBSD: rm.c,v 1.53 2013/04/26 18:43:22 christos Exp $ */
-
-/*-
- * Copyright (c) 1990, 1993, 1994, 2003
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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 <sys/cdefs.h>
-#ifndef lint
-__COPYRIGHT("@(#) Copyright (c) 1990, 1993, 1994\
- The Regents of the University of California.  All rights reserved.");
-#endif /* not lint */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)rm.c	8.8 (Berkeley) 4/27/95";
-#else
-__RCSID("$NetBSD: rm.c,v 1.53 2013/04/26 18:43:22 christos Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <fts.h>
-#include <grp.h>
-#include <locale.h>
-#include <pwd.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-static int dflag, eval, fflag, iflag, Pflag, stdin_ok, vflag, Wflag;
-static int xflag;
-static sig_atomic_t pinfo;
-
-static int	check(char *, char *, struct stat *);
-static void	checkdot(char **);
-static void	progress(int);
-static void	rm_file(char **);
-static int	rm_overwrite(char *, struct stat *);
-static void	rm_tree(char **);
-__dead static void	usage(void);
-
-/*
- * For the sake of the `-f' flag, check whether an error number indicates the
- * failure of an operation due to an non-existent file, either per se (ENOENT)
- * or because its filename argument was illegal (ENAMETOOLONG, ENOTDIR).
- */
-#define NONEXISTENT(x) \
-    ((x) == ENOENT || (x) == ENAMETOOLONG || (x) == ENOTDIR)
-
-/*
- * rm --
- *	This rm is different from historic rm's, but is expected to match
- *	POSIX 1003.2 behavior.  The most visible difference is that -f
- *	has two specific effects now, ignore non-existent files and force
- * 	file removal.
- */
-int
-main(int argc, char *argv[])
-{
-	int ch, rflag;
-
-	setprogname(argv[0]);
-	(void)setlocale(LC_ALL, "");
-
-	Pflag = rflag = xflag = 0;
-	while ((ch = getopt(argc, argv, "dfiPRrvWx")) != -1)
-		switch (ch) {
-		case 'd':
-			dflag = 1;
-			break;
-		case 'f':
-			fflag = 1;
-			iflag = 0;
-			break;
-		case 'i':
-			fflag = 0;
-			iflag = 1;
-			break;
-		case 'P':
-			Pflag = 1;
-			break;
-		case 'R':
-		case 'r':			/* Compatibility. */
-			rflag = 1;
-			break;
-		case 'v':
-			vflag = 1;
-			break;
-		case 'x':
-			xflag = 1;
-			break;
-#ifndef __ANDROID__
-		case 'W':
-			Wflag = 1;
-			break;
-#endif
-		case '?':
-		default:
-			usage();
-		}
-	argc -= optind;
-	argv += optind;
-
-	if (argc < 1) {
-		if (fflag)
-			return 0;
-		usage();
-	}
-
-	(void)signal(SIGINFO, progress);
-
-	checkdot(argv);
-
-	if (*argv) {
-		stdin_ok = isatty(STDIN_FILENO);
-
-		if (rflag)
-			rm_tree(argv);
-		else
-			rm_file(argv);
-	}
-
-	exit(eval);
-	/* NOTREACHED */
-}
-
-static void
-rm_tree(char **argv)
-{
-	FTS *fts;
-	FTSENT *p;
-	int flags, needstat, rval;
-			
-	/*
-	 * Remove a file hierarchy.  If forcing removal (-f), or interactive
-	 * (-i) or can't ask anyway (stdin_ok), don't stat the file.
-	 */
-	needstat = !fflag && !iflag && stdin_ok;
-
-	/*
-	 * If the -i option is specified, the user can skip on the pre-order
-	 * visit.  The fts_number field flags skipped directories.
-	 */
-#define	SKIPPED	1
-
-	flags = FTS_PHYSICAL;
-	if (!needstat)
-		flags |= FTS_NOSTAT;
-#ifndef __ANDROID__
-	if (Wflag)
-		flags |= FTS_WHITEOUT;
-#endif
-	if (xflag)
-		flags |= FTS_XDEV;
-	if ((fts = fts_open(argv, flags, NULL)) == NULL)
-		err(1, "fts_open failed");
-	while ((p = fts_read(fts)) != NULL) {
-	
-		switch (p->fts_info) {
-		case FTS_DNR:
-			if (!fflag || p->fts_errno != ENOENT) {
-				warnx("%s: %s", p->fts_path,
-						strerror(p->fts_errno));
-				eval = 1;
-			}
-			continue;
-		case FTS_ERR:
-			errx(EXIT_FAILURE, "%s: %s", p->fts_path,
-					strerror(p->fts_errno));
-			/* NOTREACHED */
-		case FTS_NS:
-			/*
-			 * FTS_NS: assume that if can't stat the file, it
-			 * can't be unlinked.
-			 */
-			if (fflag && NONEXISTENT(p->fts_errno))
-				continue;
-			if (needstat) {
-				warnx("%s: %s", p->fts_path,
-						strerror(p->fts_errno));
-				eval = 1;
-				continue;
-			}
-			break;
-		case FTS_D:
-			/* Pre-order: give user chance to skip. */
-			if (!fflag && !check(p->fts_path, p->fts_accpath,
-			    p->fts_statp)) {
-				(void)fts_set(fts, p, FTS_SKIP);
-				p->fts_number = SKIPPED;
-			}
-			continue;
-		case FTS_DP:
-			/* Post-order: see if user skipped. */
-			if (p->fts_number == SKIPPED)
-				continue;
-			break;
-		default:
-			if (!fflag &&
-			    !check(p->fts_path, p->fts_accpath, p->fts_statp))
-				continue;
-		}
-
-		rval = 0;
-		/*
-		 * If we can't read or search the directory, may still be
-		 * able to remove it.  Don't print out the un{read,search}able
-		 * message unless the remove fails.
-		 */
-		switch (p->fts_info) {
-		case FTS_DP:
-		case FTS_DNR:
-			rval = rmdir(p->fts_accpath);
-			if (rval != 0 && fflag && errno == ENOENT)
-				continue;
-			break;
-
-#ifndef __ANDROID__
-		case FTS_W:
-			rval = undelete(p->fts_accpath);
-			if (rval != 0 && fflag && errno == ENOENT)
-				continue;
-			break;
-#endif
-
-		default:
-			if (Pflag) {
-				if (rm_overwrite(p->fts_accpath, NULL))
-					continue;
-			}
-			rval = unlink(p->fts_accpath);
-			if (rval != 0 && fflag && NONEXISTENT(errno))
-				continue;
-			break;
-		}
-		if (rval != 0) {
-			warn("%s", p->fts_path);
-			eval = 1;
-		} else if (vflag || pinfo) {
-			pinfo = 0;
-			(void)printf("%s\n", p->fts_path);
-		}
-	}
-	if (errno)
-		err(1, "fts_read");
-	fts_close(fts);
-}
-
-static void
-rm_file(char **argv)
-{
-	struct stat sb;
-	int rval;
-	char *f;
-
-	/*
-	 * Remove a file.  POSIX 1003.2 states that, by default, attempting
-	 * to remove a directory is an error, so must always stat the file.
-	 */
-	while ((f = *argv++) != NULL) {
-		/* Assume if can't stat the file, can't unlink it. */
-		if (lstat(f, &sb)) {
-#ifndef __ANDROID__
-			if (Wflag) {
-				sb.st_mode = S_IFWHT|S_IWUSR|S_IRUSR;
-			} else {
-#endif
-				if (!fflag || !NONEXISTENT(errno)) {
-					warn("%s", f);
-					eval = 1;
-				}
-				continue;
-#ifndef __ANDROID__
-			}
-		} else if (Wflag) {
-			warnx("%s: %s", f, strerror(EEXIST));
-			eval = 1;
-			continue;
-#endif
-		}
-
-		if (S_ISDIR(sb.st_mode) && !dflag) {
-			warnx("%s: is a directory", f);
-			eval = 1;
-			continue;
-		}
-		if (!fflag && !S_ISWHT(sb.st_mode) && !check(f, f, &sb))
-			continue;
-#ifndef __ANDROID__
-		if (S_ISWHT(sb.st_mode))
-			rval = undelete(f);
-		else if (S_ISDIR(sb.st_mode))
-#else
-		if (S_ISDIR(sb.st_mode))
-#endif
-			rval = rmdir(f);
-		else {
-			if (Pflag) {
-				if (rm_overwrite(f, &sb))
-					continue;
-			}
-			rval = unlink(f);
-		}
-		if (rval && (!fflag || !NONEXISTENT(errno))) {
-			warn("%s", f);
-			eval = 1;
-		}
-		if (vflag && rval == 0)
-			(void)printf("%s\n", f);
-	}
-}
-
-/*
- * rm_overwrite --
- *	Overwrite the file 3 times with varying bit patterns.
- *
- * This is an expensive way to keep people from recovering files from your
- * non-snapshotted FFS filesystems using fsdb(8).  Really.  No more.  Only
- * regular files are deleted, directories (and therefore names) will remain.
- * Also, this assumes a fixed-block file system (like FFS, or a V7 or a
- * System V file system).  In a logging file system, you'll have to have
- * kernel support.
- *
- * A note on standards:  U.S. DoD 5220.22-M "National Industrial Security
- * Program Operating Manual" ("NISPOM") is often cited as a reference
- * for clearing and sanitizing magnetic media.  In fact, a matrix of
- * "clearing" and "sanitization" methods for various media was given in
- * Chapter 8 of the original 1995 version of NISPOM.  However, that
- * matrix was *removed from the document* when Chapter 8 was rewritten
- * in Change 2 to the document in 2001.  Recently, the Defense Security
- * Service has made a revised clearing and sanitization matrix available
- * in Microsoft Word format on the DSS web site.  The standardization
- * status of this matrix is unclear.  Furthermore, one must be very
- * careful when referring to this matrix: it is intended for the "clearing"
- * prior to reuse or "sanitization" prior to disposal of *entire media*,
- * not individual files and the only non-physically-destructive method of
- * "sanitization" that is permitted for magnetic disks of any kind is
- * specifically noted to be prohibited for media that have contained
- * Top Secret data.
- *
- * It is impossible to actually conform to the exact procedure given in
- * the matrix if one is overwriting a file, not an entire disk, because
- * the procedure requires examination and comparison of the disk's defect
- * lists.  Any program that claims to securely erase *files* while 
- * conforming to the standard, then, is not correct.  We do as much of
- * what the standard requires as can actually be done when erasing a
- * file, rather than an entire disk; but that does not make us conformant.
- *
- * Furthermore, the presence of track caches, disk and controller write
- * caches, and so forth make it extremely difficult to ensure that data
- * have actually been written to the disk, particularly when one tries
- * to repeatedly overwrite the same sectors in quick succession.  We call
- * fsync(), but controllers with nonvolatile cache, as well as IDE disks
- * that just plain lie about the stable storage of data, will defeat this.
- *
- * Finally, widely respected research suggests that the given procedure
- * is nowhere near sufficient to prevent the recovery of data using special
- * forensic equipment and techniques that are well-known.  This is 
- * presumably one reason that the matrix requires physical media destruction,
- * rather than any technique of the sort attempted here, for secret data.
- *
- * Caveat Emptor.
- *
- * rm_overwrite will return 0 on success.
- */
-
-static int
-rm_overwrite(char *file, struct stat *sbp)
-{
-	struct stat sb, sb2;
-	int fd, randint;
-	char randchar;
-
-	fd = -1;
-	if (sbp == NULL) {
-		if (lstat(file, &sb))
-			goto err;
-		sbp = &sb;
-	}
-	if (!S_ISREG(sbp->st_mode))
-		return 0;
-
-	/* flags to try to defeat hidden caching by forcing seeks */
-	if ((fd = open(file, O_RDWR|O_SYNC|O_RSYNC|O_NOFOLLOW, 0)) == -1)
-		goto err;
-
-	if (fstat(fd, &sb2)) {
-		goto err;
-	}
-
-	if (sb2.st_dev != sbp->st_dev || sb2.st_ino != sbp->st_ino ||
-	    !S_ISREG(sb2.st_mode)) {
-		errno = EPERM;
-		goto err;
-	}
-
-#define RAND_BYTES	1
-#define THIS_BYTE	0
-
-#define	WRITE_PASS(mode, byte) do {					\
-	off_t len;							\
-	size_t wlen, i;							\
-	char buf[8 * 1024];						\
-									\
-	if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))			\
-		goto err;						\
-									\
-	if (mode == THIS_BYTE)						\
-		memset(buf, byte, sizeof(buf));				\
-	for (len = sbp->st_size; len > 0; len -= wlen) {		\
-		if (mode == RAND_BYTES) {				\
-			for (i = 0; i < sizeof(buf); 			\
-			    i+= sizeof(u_int32_t))			\
-				*(int *)(buf + i) = arc4random();	\
-		}							\
-		wlen = len < (off_t)sizeof(buf) ? (size_t)len : sizeof(buf); \
-		if ((size_t)write(fd, buf, wlen) != wlen)		\
-			goto err;					\
-	}								\
-	sync();		/* another poke at hidden caches */		\
-} while (/* CONSTCOND */ 0)
-
-#define READ_PASS(byte) do {						\
-	off_t len;							\
-	size_t rlen;							\
-	char pattern[8 * 1024];						\
-	char buf[8 * 1024];						\
-									\
-	if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))			\
-		goto err;						\
-									\
-	memset(pattern, byte, sizeof(pattern));				\
-	for(len = sbp->st_size; len > 0; len -= rlen) {			\
-		rlen = len < (off_t)sizeof(buf) ? (size_t)len : sizeof(buf); \
-		if((size_t)read(fd, buf, rlen) != rlen)			\
-			goto err;					\
-		if(memcmp(buf, pattern, rlen))				\
-			goto err;					\
-	}								\
-	sync();		/* another poke at hidden caches */		\
-} while (/* CONSTCOND */ 0)
-
-	/*
-	 * DSS sanitization matrix "clear" for magnetic disks: 
-	 * option 'c' "Overwrite all addressable locations with a single 
-	 * character."
-	 */
-	randint = arc4random();
-	randchar = *(char *)&randint;
-	WRITE_PASS(THIS_BYTE, randchar);
-
-	/*
-	 * DSS sanitization matrix "sanitize" for magnetic disks: 
-	 * option 'd', sub 2 "Overwrite all addressable locations with a
-	 * character, then its complement.  Verify "complement" character
-	 * was written successfully to all addressable locations, then
-	 * overwrite all addressable locations with random characters; or
-	 * verify third overwrite of random characters."  The rest of the
-	 * text in d-sub-2 specifies requirements for overwriting spared
-	 * sectors; we cannot conform to it when erasing only a file, thus
-	 * we do not conform to the standard.
-	 */
-
-	/* 1. "a character" */
-	WRITE_PASS(THIS_BYTE, 0xff);
-
-	/* 2. "its complement" */
-	WRITE_PASS(THIS_BYTE, 0x00);
-
-	/* 3. "Verify 'complement' character" */
-	READ_PASS(0x00);
-
-	/* 4. "overwrite all addressable locations with random characters" */
-
-	WRITE_PASS(RAND_BYTES, 0x00);
-
-	/*
-	 * As the file might be huge, and we note that this revision of
-	 * the matrix says "random characters", not "a random character"
-	 * as the original did, we do not verify the random-character
-	 * write; the "or" in the standard allows this.
-	 */
-
-	if (close(fd) == -1) {
-		fd = -1;
-		goto err;
-	}
-
-	return 0;
-
-err:	eval = 1;
-	warn("%s", file);
-	if (fd != -1)
-		close(fd);
-	return 1;
-}
-
-static int
-check(char *path, char *name, struct stat *sp)
-{
-	int ch, first;
-	char modep[15];
-
-	/* Check -i first. */
-	if (iflag)
-		(void)fprintf(stderr, "remove '%s'? ", path);
-	else {
-		/*
-		 * If it's not a symbolic link and it's unwritable and we're
-		 * talking to a terminal, ask.  Symbolic links are excluded
-		 * because their permissions are meaningless.  Check stdin_ok
-		 * first because we may not have stat'ed the file.
-		 */
-		if (!stdin_ok || S_ISLNK(sp->st_mode) ||
-		    !(access(name, W_OK) && (errno != ETXTBSY)))
-			return (1);
-		strmode(sp->st_mode, modep);
-		if (Pflag) {
-			warnx(
-			    "%s: -P was specified but file could not"
-			    " be overwritten", path);
-			return 0;
-		}
-		(void)fprintf(stderr, "override %s%s%s:%s for '%s'? ",
-		    modep + 1, modep[9] == ' ' ? "" : " ",
-		    user_from_uid(sp->st_uid, 0),
-		    group_from_gid(sp->st_gid, 0), path);
-	}
-	(void)fflush(stderr);
-
-	first = ch = getchar();
-	while (ch != '\n' && ch != EOF)
-		ch = getchar();
-	return (first == 'y' || first == 'Y');
-}
-
-/*
- * POSIX.2 requires that if "." or ".." are specified as the basename
- * portion of an operand, a diagnostic message be written to standard
- * error and nothing more be done with such operands.
- *
- * Since POSIX.2 defines basename as the final portion of a path after
- * trailing slashes have been removed, we'll remove them here.
- */
-#define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || ((a)[1] == '.' && !(a)[2])))
-static void
-checkdot(char **argv)
-{
-	char *p, **save, **t;
-	int complained;
-
-	complained = 0;
-	for (t = argv; *t;) {
-		/* strip trailing slashes */
-		p = strrchr(*t, '\0');
-		while (--p > *t && *p == '/')
-			*p = '\0';
-
-		/* extract basename */
-		if ((p = strrchr(*t, '/')) != NULL)
-			++p;
-		else
-			p = *t;
-
-		if (ISDOT(p)) {
-			if (!complained++)
-				warnx("\".\" and \"..\" may not be removed");
-			eval = 1;
-			for (save = t; (t[0] = t[1]) != NULL; ++t)
-				continue;
-			t = save;
-		} else
-			++t;
-	}
-}
-
-static void
-usage(void)
-{
-
-	(void)fprintf(stderr, "usage: %s [-f|-i] [-dPRrvWx] file ...\n",
-	    getprogname());
-	exit(1);
-	/* NOTREACHED */
-}
-
-static void
-progress(int sig __unused)
-{
-	
-	pinfo++;
-}
diff --git a/toolbox/upstream-netbsd/bin/rmdir/rmdir.c b/toolbox/upstream-netbsd/bin/rmdir/rmdir.c
deleted file mode 100644
index 03261ce..0000000
--- a/toolbox/upstream-netbsd/bin/rmdir/rmdir.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/* $NetBSD: rmdir.c,v 1.26 2011/08/29 14:49:38 joerg Exp $ */
-
-/*-
- * Copyright (c) 1992, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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 <sys/cdefs.h>
-#ifndef lint
-__COPYRIGHT("@(#) Copyright (c) 1992, 1993, 1994\
- The Regents of the University of California.  All rights reserved.");
-#endif /* not lint */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)rmdir.c	8.3 (Berkeley) 4/2/94";
-#else
-__RCSID("$NetBSD: rmdir.c,v 1.26 2011/08/29 14:49:38 joerg Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/param.h>
-
-#include <err.h>
-#include <locale.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-static int	rm_path(char *);
-__dead static void	usage(void);
-
-int
-main(int argc, char *argv[])
-{
-	int ch, errors, pflag;
-
-	setprogname(argv[0]);
-	(void)setlocale(LC_ALL, "");
-
-	pflag = 0;
-	while ((ch = getopt(argc, argv, "p")) != -1)
-		switch(ch) {
-		case 'p':
-			pflag = 1;
-			break;
-		case '?':
-		default:
-			usage();
-		}
-	argc -= optind;
-	argv += optind;
-
-	if (argc == 0)
-		usage();
-
-	for (errors = 0; *argv; argv++) {
-		/* We rely on the kernel to ignore trailing '/' characters. */
-		if (rmdir(*argv) < 0) {
-			warn("%s", *argv);
-			errors = 1;
-		} else if (pflag)
-			errors |= rm_path(*argv);
-	}
-
-	exit(errors);
-	/* NOTREACHED */
-}
-
-static int
-rm_path(char *path)
-{
-	char *p;
-
-	while ((p = strrchr(path, '/')) != NULL) {
-		*p = 0;
-		if (p[1] == 0)
-			/* Ignore trailing '/' on deleted name */
-			continue;
-
-		if (rmdir(path) < 0) {
-			warn("%s", path);
-			return (1);
-		}
-	}
-
-	return (0);
-}
-
-static void
-usage(void)
-{
-	(void)fprintf(stderr, "usage: %s [-p] directory ...\n", getprogname());
-	exit(1);
-	/* NOTREACHED */
-}
diff --git a/toolbox/upstream-netbsd/bin/sleep/sleep.c b/toolbox/upstream-netbsd/bin/sleep/sleep.c
deleted file mode 100644
index 4349af4..0000000
--- a/toolbox/upstream-netbsd/bin/sleep/sleep.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/* $NetBSD: sleep.c,v 1.24 2011/08/29 14:51:19 joerg Exp $ */
-
-/*
- * Copyright (c) 1988, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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 <sys/cdefs.h>
-#ifndef lint
-__COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\
- The Regents of the University of California.  All rights reserved.");
-#endif /* not lint */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)sleep.c	8.3 (Berkeley) 4/2/94";
-#else
-__RCSID("$NetBSD: sleep.c,v 1.24 2011/08/29 14:51:19 joerg Exp $");
-#endif
-#endif /* not lint */
-
-#include <ctype.h>
-#include <err.h>
-#include <locale.h>
-#include <math.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include <unistd.h>
-
-__dead static void alarmhandle(int);
-__dead static void usage(void);
-
-static volatile sig_atomic_t report_requested;
-static void
-report_request(int signo __unused)
-{
-
-	report_requested = 1;
-}
-
-int
-main(int argc, char *argv[])
-{
-	char *arg, *temp;
-	double fval, ival, val;
-	struct timespec ntime;
-	time_t original;
-	int ch, fracflag, rv;
-
-	setprogname(argv[0]);
-	(void)setlocale(LC_ALL, "");
-
-	(void)signal(SIGALRM, alarmhandle);
-
-	while ((ch = getopt(argc, argv, "")) != -1)
-		switch(ch) {
-		default:
-			usage();
-		}
-	argc -= optind;
-	argv += optind;
-
-	if (argc != 1)
-		usage();
-
-	/*
-	 * Okay, why not just use atof for everything? Why bother
-	 * checking if there is a fraction in use? Because the old
-	 * sleep handled the full range of integers, that's why, and a
-	 * double can't handle a large long. This is fairly useless
-	 * given how large a number a double can hold on most
-	 * machines, but now we won't ever have trouble. If you want
-	 * 1000000000.9 seconds of sleep, well, that's your
-	 * problem. Why use an isdigit() check instead of checking for
-	 * a period? Because doing it this way means locales will be
-	 * handled transparently by the atof code.
-	 */
-	fracflag = 0;
-	arg = *argv;
-	for (temp = arg; *temp != '\0'; temp++)
-		if (!isdigit((unsigned char)*temp))
-			fracflag++;
-
-	if (fracflag) {
-		val = atof(arg);
-		if (val <= 0)
-			usage();
-		ival = floor(val);
-		fval = (1000000000 * (val-ival));
-		ntime.tv_sec = ival;
-		ntime.tv_nsec = fval;
-	}
-	else {
-		ntime.tv_sec = atol(arg);
-		if (ntime.tv_sec <= 0)
-			return EXIT_SUCCESS;
-		ntime.tv_nsec = 0;
-	}
-
-	original = ntime.tv_sec;
-	signal(SIGINFO, report_request);
-	while ((rv = nanosleep(&ntime, &ntime)) != 0) {
-		if (report_requested) {
-		/* Reporting does not bother with nanoseconds. */
-			warnx("about %d second(s) left out of the original %d",
-			(int)ntime.tv_sec, (int)original);
-			report_requested = 0;
-		} else
-			break;
-	}
-
-	if (rv == -1)
-		err(EXIT_FAILURE, "nanosleep failed");
-
-	return EXIT_SUCCESS;
-	/* NOTREACHED */
-}
-
-static void
-usage(void)
-{
-	(void)fprintf(stderr, "usage: %s seconds\n", getprogname());
-	exit(EXIT_FAILURE);
-	/* NOTREACHED */
-}
-
-/* ARGSUSED */
-static void
-alarmhandle(int i)
-{
-	_exit(EXIT_SUCCESS);
-	/* NOTREACHED */
-}
diff --git a/toolbox/upstream-netbsd/bin/sync/sync.c b/toolbox/upstream-netbsd/bin/sync/sync.c
deleted file mode 100644
index 2b9c367..0000000
--- a/toolbox/upstream-netbsd/bin/sync/sync.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/* $NetBSD: sync.c,v 1.13 2008/07/20 00:52:40 lukem Exp $ */
-
-/*
- * Copyright (c) 1987, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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 <sys/cdefs.h>
-#ifndef lint
-__COPYRIGHT("@(#) Copyright (c) 1987, 1993\
- The Regents of the University of California.  All rights reserved.");
-#endif /* not lint */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)sync.c	8.1 (Berkeley) 5/31/93";
-#else
-__RCSID("$NetBSD: sync.c,v 1.13 2008/07/20 00:52:40 lukem Exp $");
-#endif
-#endif /* not lint */
-
-#include <stdlib.h>
-#include <unistd.h>
-
-int main(int, char *[]);
-
-/* ARGSUSED */
-int
-main(int argc, char *argv[])
-{
-	setprogname(argv[0]);
-	sync();
-	exit(0);
-	/* NOTREACHED */
-}
diff --git a/toolbox/upstream-netbsd/sbin/chown/chown.c b/toolbox/upstream-netbsd/sbin/chown/chown.c
deleted file mode 100644
index ee46eee..0000000
--- a/toolbox/upstream-netbsd/sbin/chown/chown.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/*	$NetBSD: chown.c,v 1.8 2012/10/24 01:12:51 enami Exp $	*/
-
-/*
- * Copyright (c) 1988, 1993, 1994, 2003
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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 <sys/cdefs.h>
-#ifndef lint
-__COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994, 2003\
- The Regents of the University of California.  All rights reserved.");
-#endif /* not lint */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)chown.c	8.8 (Berkeley) 4/4/94";
-#else
-__RCSID("$NetBSD: chown.c,v 1.8 2012/10/24 01:12:51 enami Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <ctype.h>
-#include <dirent.h>
-#include <err.h>
-#include <errno.h>
-#include <locale.h>
-#include <fts.h>
-#include <grp.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <getopt.h>
-
-static void	a_gid(const char *);
-static void	a_uid(const char *);
-static id_t	id(const char *, const char *);
-__dead static void	usage(void);
-
-static uid_t uid;
-static gid_t gid;
-static int ischown;
-static const char *myname;
-
-struct option chown_longopts[] = {
-	{ "reference",		required_argument,	0,
-						1 },
-	{ NULL,			0,			0,
-						0 },
-};
-
-int
-main(int argc, char **argv)
-{
-	FTS *ftsp;
-	FTSENT *p;
-	int Hflag, Lflag, Rflag, ch, fflag, fts_options, hflag, rval, vflag;
-	char *cp, *reference;
-	int (*change_owner)(const char *, uid_t, gid_t);
-
-	setprogname(*argv);
-
-	(void)setlocale(LC_ALL, "");
-
-	myname = getprogname();
-	ischown = (myname[2] == 'o');
-	reference = NULL;
-
-	Hflag = Lflag = Rflag = fflag = hflag = vflag = 0;
-	while ((ch = getopt_long(argc, argv, "HLPRfhv",
-	    chown_longopts, NULL)) != -1)
-		switch (ch) {
-		case 1:
-			reference = optarg;
-			break;
-		case 'H':
-			Hflag = 1;
-			Lflag = 0;
-			break;
-		case 'L':
-			Lflag = 1;
-			Hflag = 0;
-			break;
-		case 'P':
-			Hflag = Lflag = 0;
-			break;
-		case 'R':
-			Rflag = 1;
-			break;
-		case 'f':
-			fflag = 1;
-			break;
-		case 'h':
-			/*
-			 * In System V the -h option causes chown/chgrp to
-			 * change the owner/group of the symbolic link.
-			 * 4.4BSD's symbolic links didn't have owners/groups,
-			 * so it was an undocumented noop.
-			 * In NetBSD 1.3, lchown(2) is introduced.
-			 */
-			hflag = 1;
-			break;
-		case 'v':
-			vflag = 1;
-			break;
-		case '?':
-		default:
-			usage();
-		}
-	argv += optind;
-	argc -= optind;
-
-	if (argc == 0 || (argc == 1 && reference == NULL))
-		usage();
-
-	fts_options = FTS_PHYSICAL;
-	if (Rflag) {
-		if (Hflag)
-			fts_options |= FTS_COMFOLLOW;
-		if (Lflag) {
-			if (hflag)
-				errx(EXIT_FAILURE,
-				    "the -L and -h options "
-				    "may not be specified together.");
-			fts_options &= ~FTS_PHYSICAL;
-			fts_options |= FTS_LOGICAL;
-		}
-	} else if (!hflag)
-		fts_options |= FTS_COMFOLLOW;
-
-	uid = (uid_t)-1;
-	gid = (gid_t)-1;
-	if (reference == NULL) {
-		if (ischown) {
-			if ((cp = strchr(*argv, ':')) != NULL) {
-				*cp++ = '\0';
-				a_gid(cp);
-			}
-#ifdef SUPPORT_DOT
-			else if ((cp = strrchr(*argv, '.')) != NULL) {
-				if (uid_from_user(*argv, &uid) == -1) {
-					*cp++ = '\0';
-					a_gid(cp);
-				}
-			}
-#endif
-			a_uid(*argv);
-		} else
-			a_gid(*argv);
-		argv++;
-	} else {
-		struct stat st;
-
-		if (stat(reference, &st) == -1)
-			err(EXIT_FAILURE, "Cannot stat `%s'", reference);
-		if (ischown)
-			uid = st.st_uid;
-		gid = st.st_gid;
-	}
-
-	if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL)
-		err(EXIT_FAILURE, "fts_open");
-
-	for (rval = EXIT_SUCCESS; (p = fts_read(ftsp)) != NULL;) {
-		change_owner = chown;
-		switch (p->fts_info) {
-		case FTS_D:
-			if (!Rflag)		/* Change it at FTS_DP. */
-				fts_set(ftsp, p, FTS_SKIP);
-			continue;
-		case FTS_DNR:			/* Warn, chown, continue. */
-			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
-			rval = EXIT_FAILURE;
-			break;
-		case FTS_ERR:			/* Warn, continue. */
-		case FTS_NS:
-			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
-			rval = EXIT_FAILURE;
-			continue;
-		case FTS_SL:			/* Ignore unless -h. */
-			/*
-			 * All symlinks we found while doing a physical
-			 * walk end up here.
-			 */
-			if (!hflag)
-				continue;
-			/*
-			 * Note that if we follow a symlink, fts_info is
-			 * not FTS_SL but FTS_F or whatever.  And we should
-			 * use lchown only for FTS_SL and should use chown
-			 * for others.
-			 */
-			change_owner = lchown;
-			break;
-		case FTS_SLNONE:		/* Ignore. */
-			/*
-			 * The only symlinks that end up here are ones that
-			 * don't point to anything.  Note that if we are
-			 * doing a phisycal walk, we never reach here unless
-			 * we asked to follow explicitly.
-			 */
-			continue;
-		default:
-			break;
-		}
-
-		if ((*change_owner)(p->fts_accpath, uid, gid) && !fflag) {
-			warn("%s", p->fts_path);
-			rval = EXIT_FAILURE;
-		} else {
-			if (vflag)
-				printf("%s\n", p->fts_path);
-		}
-	}
-	if (errno)
-		err(EXIT_FAILURE, "fts_read");
-	exit(rval);
-	/* NOTREACHED */
-}
-
-static void
-a_gid(const char *s)
-{
-	struct group *gr;
-
-	if (*s == '\0')			/* Argument was "uid[:.]". */
-		return;
-	gr = *s == '#' ? NULL : getgrnam(s);
-	if (gr == NULL)
-		gid = id(s, "group");
-	else
-		gid = gr->gr_gid;
-	return;
-}
-
-static void
-a_uid(const char *s)
-{
-	if (*s == '\0')			/* Argument was "[:.]gid". */
-		return;
-	if (*s == '#' || uid_from_user(s, &uid) == -1) {
-		uid = id(s, "user");
-	}
-	return;
-}
-
-static id_t
-id(const char *name, const char *type)
-{
-	id_t val;
-	char *ep;
-
-	errno = 0;
-	if (*name == '#')
-		name++;
-	val = (id_t)strtoul(name, &ep, 10);
-	if (errno)
-		err(EXIT_FAILURE, "%s", name);
-	if (*ep != '\0')
-		errx(EXIT_FAILURE, "%s: invalid %s name", name, type);
-	return (val);
-}
-
-static void
-usage(void)
-{
-
-	(void)fprintf(stderr,
-	    "Usage: %s [-R [-H | -L | -P]] [-fhv] %s file ...\n"
-	    "\t%s [-R [-H | -L | -P]] [-fhv] --reference=rfile file ...\n",
-	    myname, ischown ? "owner:group|owner|:group" : "group",
-	    myname);
-	exit(EXIT_FAILURE);
-}
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/file.c b/toolbox/upstream-netbsd/usr.bin/grep/file.c
index da03d71..cf4a0fa 100644
--- a/toolbox/upstream-netbsd/usr.bin/grep/file.c
+++ b/toolbox/upstream-netbsd/usr.bin/grep/file.c
@@ -78,7 +78,9 @@
 grep_refill(struct file *f)
 {
 	ssize_t nr;
+#ifndef __ANDROID__
 	int bzerr;
+#endif
 
 	bufpos = buffer;
 	bufrem = 0;
diff --git a/toolbox/upstream-netbsd/usr.bin/printenv/printenv.c b/toolbox/upstream-netbsd/usr.bin/printenv/printenv.c
deleted file mode 100644
index e15384f..0000000
--- a/toolbox/upstream-netbsd/usr.bin/printenv/printenv.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*	$NetBSD: printenv.c,v 1.12 2011/09/06 18:26:55 joerg Exp $	*/
-
-/*
- * Copyright (c) 1987, 1993
- *    The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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 <sys/cdefs.h>
-#ifndef lint
-__COPYRIGHT("@(#) Copyright (c) 1987, 1993\
- The Regents of the University of California.  All rights reserved.");
-#endif /* not lint */
-
-#ifndef lint
-/*static char sccsid[] = "from: @(#)printenv.c	8.2 (Berkeley) 5/4/95";*/
-__RCSID("$NetBSD: printenv.c,v 1.12 2011/09/06 18:26:55 joerg Exp $");
-#endif /* not lint */
-
-#include <sys/types.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <err.h>
-
-__dead static void usage(void);
-
-/*
- * printenv
- *
- * Bill Joy, UCB
- * February, 1979
- */
-int
-main(int argc, char *argv[])
-{
-	extern char **environ;
-	char *cp, **ep;
-	size_t len;
-	int ch;
-
-	while ((ch = getopt(argc, argv, "")) != -1)
-		switch(ch) {
-		case '?':
-		default:
-			usage();
-		}
-	argc -= optind;
-	argv += optind;
-
-	if (argc == 0) {
-		for (ep = environ; *ep; ep++)
-			(void)printf("%s\n", *ep);
-		exit(0);
-	}
-	if (argc != 1)
-		usage();
-	if (strchr(*argv, '=') != NULL)
-		errx(1, "Invalid environment variable %s", *argv);
-	len = strlen(*argv);
-	for (ep = environ; *ep; ep++)
-		if (!memcmp(*ep, *argv, len)) {
-			cp = *ep + len;
-			if (!*cp || *cp == '=') {
-				(void)printf("%s\n", *cp ? cp + 1 : cp);
-				exit(0);
-			}
-		}
-	exit(1);
-}
-
-static void
-usage(void)
-{
-	(void)fprintf(stderr, "Usage: printenv [name]\n");
-	exit(1);
-}
diff --git a/toolbox/uptime.c b/toolbox/uptime.c
index 3fb4606..ebfb15e 100644
--- a/toolbox/uptime.c
+++ b/toolbox/uptime.c
@@ -29,71 +29,33 @@
  * SUCH DAMAGE.
  */
 
-#include <sys/time.h>
-#include <linux/ioctl.h>
-#include <linux/rtc.h>
-#include <linux/android_alarm.h>
-#include <fcntl.h>
+#include <errno.h>
 #include <stdio.h>
+#include <string.h>
 #include <time.h>
 
-
 static void format_time(int time, char* buffer) {
-    int seconds, minutes, hours, days;
-
-    seconds = time % 60;
+    int seconds = time % 60;
     time /= 60;
-    minutes = time % 60;
+    int minutes = time % 60;
     time /= 60;
-    hours = time % 24;
-    days = time / 24;
+    int hours = time % 24;
+    int days = time / 24;
 
-    if (days > 0)
-        sprintf(buffer, "%d days, %02d:%02d:%02d", days, hours, minutes, seconds);
-    else
+    if (days > 0) {
+        sprintf(buffer, "%d day%s, %02d:%02d:%02d", days, (days == 1) ? "" : "s", hours, minutes, seconds);
+    } else {
         sprintf(buffer, "%02d:%02d:%02d", hours, minutes, seconds);
+    }
 }
 
-static int elapsedRealtimeAlarm(struct timespec *ts)
-{
-    int fd, result;
-
-    fd = open("/dev/alarm", O_RDONLY);
-    if (fd < 0)
-        return fd;
-
-    result = ioctl(fd, ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), ts);
-    close(fd);
-
-    return result;
-}
-
-int64_t elapsedRealtime()
-{
-    struct timespec ts;
-
-    int result = elapsedRealtimeAlarm(&ts);
-    if (result < 0)
-        result = clock_gettime(CLOCK_BOOTTIME, &ts);
-
-    if (result == 0)
-        return ts.tv_sec;
-    return -1;
-}
-
-int uptime_main(int argc __attribute__((unused)),
-        char *argv[] __attribute__((unused)))
-{
-    float up_time, idle_time;
-    char up_string[100], idle_string[100], sleep_string[100];
-    int elapsed;
-    struct timespec up_timespec;
-
+int uptime_main(int argc __attribute__((unused)), char *argv[] __attribute__((unused))) {
     FILE* file = fopen("/proc/uptime", "r");
     if (!file) {
         fprintf(stderr, "Could not open /proc/uptime\n");
         return -1;
     }
+    float idle_time;
     if (fscanf(file, "%*f %f", &idle_time) != 1) {
         fprintf(stderr, "Could not parse /proc/uptime\n");
         fclose(file);
@@ -101,18 +63,21 @@
     }
     fclose(file);
 
-    if (clock_gettime(CLOCK_MONOTONIC, &up_timespec) < 0) {
-        fprintf(stderr, "Could not get monotonic time\n");
+    struct timespec up_timespec;
+    if (clock_gettime(CLOCK_MONOTONIC, &up_timespec) == -1) {
+        fprintf(stderr, "Could not get monotonic time: %s\n", strerror(errno));
 	return -1;
     }
-    up_time = up_timespec.tv_sec + up_timespec.tv_nsec / 1e9;
+    float up_time = up_timespec.tv_sec + up_timespec.tv_nsec / 1e9;
 
-    elapsed = elapsedRealtime();
-    if (elapsed < 0) {
-        fprintf(stderr, "elapsedRealtime failed\n");
+    struct timespec elapsed_timespec;
+    if (clock_gettime(CLOCK_BOOTTIME, &elapsed_timespec) == -1) {
+        fprintf(stderr, "Could not get boot time: %s\n", strerror(errno));
         return -1;
     }
+    int elapsed = elapsed_timespec.tv_sec;
 
+    char up_string[100], idle_string[100], sleep_string[100];
     format_time(elapsed, up_string);
     format_time((int)idle_time, idle_string);
     format_time((int)(elapsed - up_time), sleep_string);
diff --git a/toolbox/vmstat.c b/toolbox/vmstat.c
deleted file mode 100644
index 4086ed0..0000000
--- a/toolbox/vmstat.c
+++ /dev/null
@@ -1,247 +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 <stdio.h>
-#include <stdlib.h>
-#include <sys/param.h>
-#include <unistd.h>
-
-struct state {
-    long procs_r;
-    long procs_b;
-
-    long mem_free;
-    long mem_mapped;
-    long mem_anon;
-    long mem_slab;
-
-    long sys_in;
-    long sys_cs;
-    long sys_flt;
-
-    long cpu_us;
-    long cpu_ni;
-    long cpu_sy;
-    long cpu_id;
-    long cpu_wa;
-    long cpu_ir;
-    long cpu_si;
-};
-
-#define MAX_LINE 256
-
-char line[MAX_LINE];
-
-static void read_state(struct state *s);
-static int read_meminfo(struct state *s);
-static int read_stat(struct state *s);
-static int read_vmstat(struct state *s);
-static void print_header(void);
-static void print_line(struct state *old, struct state *new);
-static void usage(char *cmd);
-
-int vmstat_main(int argc, char *argv[]) {
-    struct state s[2];
-    int iterations, delay, header_interval;
-    int toggle, count;
-    int i;
-
-    iterations = -1;
-    delay = 1;
-    header_interval = 20;
-
-    for (i = 1; i < argc; i++) {
-        if (!strcmp(argv[i], "-n")) { 
-            if (i >= argc - 1) {
-                fprintf(stderr, "Option -n requires an argument.\n");
-                exit(EXIT_FAILURE);
-            }
-            iterations = atoi(argv[++i]);
-            continue;
-        }
-        if (!strcmp(argv[i], "-d")) {
-            if (i >= argc - 1) {
-                fprintf(stderr, "Option -d requires an argument.\n");
-                exit(EXIT_FAILURE);
-            }
-            delay = atoi(argv[++i]);
-            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]);
-            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);
-    }
-
-    toggle = 0;
-    count = 0;
-
-    if (!header_interval)
-        print_header();
-    read_state(&s[1 - toggle]);
-    while ((iterations < 0) || (iterations-- > 0)) {
-        sleep(delay);
-        read_state(&s[toggle]);
-        if (header_interval) {
-            if (count == 0)
-                print_header();
-            count = (count + 1) % header_interval;
-        }
-        print_line(&s[1 - toggle], &s[toggle]);
-        toggle = 1 - toggle;
-    }
-
-    return 0;
-}
-
-static void read_state(struct state *s) {
-    int error;
-
-    error = read_meminfo(s);
-    if (error) {
-        fprintf(stderr, "vmstat: could not read /proc/meminfo: %s\n", strerror(error));
-        exit(EXIT_FAILURE);
-    }
-
-    error = read_stat(s);
-    if (error) {
-        fprintf(stderr, "vmstat: could not read /proc/stat: %s\n", strerror(error));
-        exit(EXIT_FAILURE);
-    }
-
-    error = read_vmstat(s);
-    if (error) {
-        fprintf(stderr, "vmstat: could not read /proc/vmstat: %s\n", strerror(error));
-        exit(EXIT_FAILURE);
-    }
-}
-
-static int read_meminfo(struct state *s) {
-    FILE *f;
-
-    f = fopen("/proc/meminfo", "r");
-    if (!f) return errno;
-
-    while (fgets(line, MAX_LINE, f)) {
-        sscanf(line, "MemFree: %ld kB", &s->mem_free);
-        sscanf(line, "AnonPages: %ld kB", &s->mem_anon);
-        sscanf(line, "Mapped: %ld kB", &s->mem_mapped);
-        sscanf(line, "Slab: %ld kB", &s->mem_slab);
-    }
-
-    fclose(f);
-
-    return 0;
-}
-
-static int read_stat(struct state *s) {
-    FILE *f;
-
-    f = fopen("/proc/stat", "r");
-    if (!f) return errno;
-
-    while (fgets(line, MAX_LINE, f)) {
-        if (!strncmp(line, "cpu ", 4)) {
-            sscanf(line, "cpu  %ld %ld %ld %ld %ld %ld %ld",
-                &s->cpu_us, &s->cpu_ni, &s->cpu_sy, &s->cpu_id, &s->cpu_wa,
-                &s->cpu_ir, &s->cpu_si);
-        }
-        sscanf(line, "intr %ld", &s->sys_in);
-        sscanf(line, "ctxt %ld", &s->sys_cs);
-        sscanf(line, "procs_running %ld", &s->procs_r);
-        sscanf(line, "procs_blocked %ld", &s->procs_b);
-    }
-
-    fclose(f);
-
-    return 0;
-}
-
-static int read_vmstat(struct state *s) {
-    FILE *f;
-
-    f = fopen("/proc/vmstat", "r");
-    if (!f) return errno;
-
-    while (fgets(line, MAX_LINE, f)) {
-        sscanf(line, "pgmajfault %ld", &s->sys_flt);
-    }
-
-    fclose(f);
-
-    return 0;
-}
-
-static void print_header(void) {
-    printf("%-5s  %-27s  %-14s  %-17s\n", "procs", "memory", "system", "cpu");
-    printf("%2s %2s  %6s %6s %6s %6s  %4s %4s %4s  %2s %2s %2s %2s %2s %2s\n", "r", "b", "free", "mapped", "anon", "slab", "in", "cs", "flt", "us", "ni", "sy", "id", "wa", "ir");
-}
-
-/* Jiffies to percent conversion */
-#define JP(jif) ((jif) * 100 / (HZ))
-#define NORM(var) ((var) = (((var) > 99) ? (99) : (var)))
-
-static void print_line(struct state *old, struct state *new) {
-    int us, ni, sy, id, wa, ir;
-    us = JP(new->cpu_us - old->cpu_us); NORM(us);
-    ni = JP(new->cpu_ni - old->cpu_ni); NORM(ni);
-    sy = JP(new->cpu_sy - old->cpu_sy); NORM(sy);
-    id = JP(new->cpu_id - old->cpu_id); NORM(id);
-    wa = JP(new->cpu_wa - old->cpu_wa); NORM(wa);
-    ir = JP(new->cpu_ir - old->cpu_ir); NORM(ir);
-    printf("%2ld %2ld  %6ld %6ld %6ld %6ld  %4ld %4ld %4ld  %2d %2d %2d %2d %2d %2d\n",
-        new->procs_r ? (new->procs_r - 1) : 0, new->procs_b,
-        new->mem_free, new->mem_mapped, new->mem_anon, new->mem_slab,
-        new->sys_in - old->sys_in, new->sys_cs - old->sys_cs, new->sys_flt - old->sys_flt,
-        us, ni, sy, id, wa, ir);
-}
-
-static void usage(char *cmd) {
-    fprintf(stderr, "Usage: %s [ -h ] [ -n iterations ] [ -d delay ] [ -r header_repeat ]\n"
-                    "    -n iterations     How many rows of data to print.\n"
-                    "    -d delay          How long to sleep between rows.\n"
-                    "    -r header_repeat  How many rows to print before repeating\n"
-                    "                      the header.  Zero means never repeat.\n"
-                    "    -h                Displays this help screen.\n",
-        cmd);
-}
diff --git a/toolbox/watchprops.c b/toolbox/watchprops.c
index 0d05aba..cd62922 100644
--- a/toolbox/watchprops.c
+++ b/toolbox/watchprops.c
@@ -1,5 +1,6 @@
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <time.h>
 #include <errno.h>
 
diff --git a/toolbox/wipe.c b/toolbox/wipe.c
deleted file mode 100644
index 650a0d6..0000000
--- a/toolbox/wipe.c
+++ /dev/null
@@ -1,176 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <cutils/android_reboot.h>
-#include <sys/stat.h>
-
-#ifndef PATH_MAX
-#define PATH_MAX 4096
-#endif
-
-
-/* Directories created by init defined in system/rootdir/init.rc */
-static char *INIT_DIRS[] = {
-    "/system/etc/ppp",
-    "/data/misc",
-    "/data/local",
-    "/data/local/tmp",
-    "/data/data",
-    "/data/app_private",
-    "/data/app",
-    NULL
-};
-
-static void wipe (const char *path);
-
-static int usage()
-{
-    fprintf(stderr, "wipe <system|data|all>\n\n"
-                    "system means '/system'\n"
-                    "data means '/data'\n");
-
-    return -1;
-}
-
-int wipe_main (int argc, char *argv[])
-{
-    char *whatToWipe;
-
-    if (argc != 2) return usage();
-
-    whatToWipe = argv[1];
-
-    if (0 == strcmp (whatToWipe, "system")) {
-        fprintf(stdout, "Wiping /system\n");
-        wipe ("/system");
-        fprintf(stdout, "Done wiping /android\n");
-    } else if (0 == strcmp (whatToWipe, "data")) {
-        fprintf(stdout, "Wiping /data\n");
-        wipe ("/data");
-        fprintf(stdout, "Done wiping /data\n");
-    } else if (0 == strcmp (whatToWipe, "all")) {
-        fprintf(stdout, "Wiping /system and /data\n");
-        wipe ("/system");
-        wipe ("/data");
-        fprintf(stdout, "Done wiping /system and /data\n");
-    } else if (0 == strcmp(whatToWipe, "nuke")) {
-		int ret;
-		fprintf(stdout, "Nuking the device...\n");
-		wipe ("/system");
-        wipe ("/data");
-		fprintf(stdout, "Device nuked! Rebooting...\n");
-		ret = android_reboot(ANDROID_RB_RESTART, 0, 0);
-	    if (ret < 0) {
-	        fprintf(stderr, "Reboot failed, %s\n", strerror(errno));
-	        return 1;
-	    }
-	} else {
-        return usage();
-    }
-
-    return 0;
-}
-
-static char nameBuffer[PATH_MAX];
-static struct stat statBuffer;
-
-static void wipe (const char *path) 
-{
-    DIR *dir;
-    struct dirent *de;
-    int ret;
-
-    dir = opendir(path);
-
-    if (dir == NULL) {
-        fprintf (stderr, "Error opendir'ing %s '%s'\n",
-                    path, strerror(errno));
-        return;
-    }
-
-    char *filenameOffset;
-
-    strcpy(nameBuffer, path);
-    strcat(nameBuffer, "/");
-
-    filenameOffset = nameBuffer + strlen(nameBuffer);
-
-    for (;;) {
-        de = readdir(dir);
-
-        if (de == NULL) {
-            break;
-        }
-
-        if (0 == strcmp(de->d_name, ".")
-                || 0 == strcmp(de->d_name, "..")
-                || 0 == strcmp(de->d_name, "lost+found")
-        ) {
-            continue;
-        }
-
-        strcpy(filenameOffset, de->d_name);
-
-        ret = lstat (nameBuffer, &statBuffer);
-
-        if (ret != 0) {
-            fprintf(stderr, "stat() error on '%s' '%s'\n", 
-                    nameBuffer, strerror(errno));
-        }
-
-        if(S_ISDIR(statBuffer.st_mode)) {
-            int i;
-            char *newpath;
-
-#if 0
-            closedir(dir);
-#endif
-
-            newpath = strdup(nameBuffer);
-            wipe(newpath);
-
-            /* Leave directories created by init, they have special permissions. */
-            for (i = 0; INIT_DIRS[i]; i++) {
-                if (strcmp(INIT_DIRS[i], newpath) == 0) {
-                    break;
-                }
-            }
-            if (INIT_DIRS[i] == NULL) {
-                ret = rmdir(newpath);
-                if (ret != 0) {
-                    fprintf(stderr, "rmdir() error on '%s' '%s'\n", 
-                        newpath, strerror(errno));
-                }
-            }
-
-            free(newpath);
-
-#if 0
-            dir = opendir(path);
-            if (dir == NULL) {
-                fprintf (stderr, "Error opendir'ing %s '%s'\n",
-                            path, strerror(errno));
-                return;
-            }
-#endif
-
-            strcpy(nameBuffer, path);
-            strcat(nameBuffer, "/");
-
-        } else {
-            ret = unlink(nameBuffer);
-
-            if (ret != 0) {
-                fprintf(stderr, "unlink() error on '%s' '%s'\n", 
-                    nameBuffer, strerror(errno));
-            }
-        }
-    }
-
-    closedir(dir);
-
-}
diff --git a/tzdatacheck/Android.mk b/tzdatacheck/Android.mk
new file mode 100644
index 0000000..0e25f7d
--- /dev/null
+++ b/tzdatacheck/Android.mk
@@ -0,0 +1,21 @@
+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)
+
diff --git a/tzdatacheck/tzdatacheck.cpp b/tzdatacheck/tzdatacheck.cpp
new file mode 100644
index 0000000..31f7b55
--- /dev/null
+++ b/tzdatacheck/tzdatacheck.cpp
@@ -0,0 +1,236 @@
+/*
+ * 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 <errno.h>
+#include <ftw.h>
+#include <libgen.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+
+static const char* TZDATA_FILENAME = "/tzdata";
+// tzdata file header (as much as we need for the version):
+// byte[11] tzdata_version  -- e.g. "tzdata2012f"
+static const int TZ_HEADER_LENGTH = 11;
+
+static void usage() {
+    std::cerr << "Usage: tzdatacheck SYSTEM_TZ_DIR DATA_TZ_DIR\n"
+            "\n"
+            "Compares the headers of two tzdata files. If the one in SYSTEM_TZ_DIR is the\n"
+            "same or a higher version than the one in DATA_TZ_DIR the DATA_TZ_DIR is renamed\n"
+            "and then deleted.\n";
+    exit(1);
+}
+
+/*
+ * Opens a file and fills headerBytes with the first byteCount bytes from the file. It is a fatal
+ * error if the file is too small or cannot be opened. If the file does not exist false is returned.
+ * If the bytes were read successfully then true is returned.
+ */
+static bool readHeader(const std::string& tzDataFileName, char* headerBytes, size_t byteCount) {
+    FILE* tzDataFile = fopen(tzDataFileName.c_str(), "r");
+    if (tzDataFile == nullptr) {
+        if (errno == ENOENT) {
+            return false;
+        } else {
+            PLOG(FATAL) << "Error opening tzdata file " << tzDataFileName;
+        }
+    }
+    size_t bytesRead = fread(headerBytes, 1, byteCount, tzDataFile);
+    if (bytesRead != byteCount) {
+        LOG(FATAL) << tzDataFileName << " is too small. " << byteCount << " bytes required";
+    }
+    fclose(tzDataFile);
+    return true;
+}
+
+/* Checks the contents of headerBytes. It is a fatal error if it not a tzdata header. */
+static void checkValidHeader(const std::string& fileName, char* headerBytes) {
+    if (strncmp("tzdata", headerBytes, 6) != 0) {
+        LOG(FATAL) << fileName << " does not start with the expected bytes (tzdata)";
+    }
+}
+
+/* Return the parent directory of dirName. */
+static std::string getParentDir(const std::string& dirName) {
+    std::unique_ptr<char> mutable_dirname(strdup(dirName.c_str()));
+    return dirname(mutable_dirname.get());
+}
+
+/* Deletes a single file, symlink or directory. Called from nftw(). */
+static int deleteFn(const char* fpath, const struct stat*, int typeflag, struct FTW*) {
+    LOG(DEBUG) << "Inspecting " << fpath;
+    switch (typeflag) {
+    case FTW_F:
+    case FTW_SL:
+        LOG(DEBUG) << "Unlinking " << fpath;
+        if (unlink(fpath)) {
+            PLOG(WARNING) << "Failed to unlink file/symlink " << fpath;
+        }
+        break;
+    case FTW_D:
+    case FTW_DP:
+        LOG(DEBUG) << "Removing dir " << fpath;
+        if (rmdir(fpath)) {
+            PLOG(WARNING) << "Failed to remove dir " << fpath;
+        }
+        break;
+    default:
+        LOG(WARNING) << "Unsupported file type " << fpath << ": " << typeflag;
+        break;
+    }
+    return 0;
+}
+
+/*
+ * Deletes dirToDelete and returns true if it is successful in removing or moving the directory out
+ * of the way. If dirToDelete does not exist this function does nothing and returns true.
+ *
+ * During deletion, this function first renames the directory to a temporary name. If the temporary
+ * directory cannot be created, or the directory cannot be renamed, false is returned. After the
+ * rename, deletion of files and subdirs beneath the directory is performed on a "best effort"
+ * basis. Symlinks beneath the directory are not followed.
+ */
+static bool deleteDir(const std::string& dirToDelete) {
+    // Check whether the dir exists.
+    struct stat buf;
+    if (stat(dirToDelete.c_str(), &buf) == 0) {
+      if (!S_ISDIR(buf.st_mode)) {
+        LOG(WARNING) << dirToDelete << " is not a directory";
+        return false;
+      }
+    } else {
+      if (errno == ENOENT) {
+          PLOG(INFO) << "Directory does not exist: " << dirToDelete;
+          return true;
+      } else {
+          PLOG(WARNING) << "Unable to stat " << dirToDelete;
+          return false;
+      }
+    }
+
+    // First, rename dirToDelete.
+    std::string tempDirNameTemplate = getParentDir(dirToDelete);
+    tempDirNameTemplate += "/tempXXXXXX";
+
+    // Create an empty directory with the temporary name. For this we need a non-const char*.
+    std::vector<char> tempDirName(tempDirNameTemplate.length() + 1);
+    strcpy(&tempDirName[0], tempDirNameTemplate.c_str());
+    if (mkdtemp(&tempDirName[0]) == nullptr) {
+        PLOG(WARNING) << "Unable to create a temporary directory: " << tempDirNameTemplate;
+        return false;
+    }
+
+    // Rename dirToDelete to tempDirName.
+    int rc = rename(dirToDelete.c_str(), &tempDirName[0]);
+    if (rc == -1) {
+        PLOG(WARNING) << "Unable to rename directory from " << dirToDelete << " to "
+                << &tempDirName[0];
+        return false;
+    }
+
+    // Recursively delete contents of tempDirName.
+    rc = nftw(&tempDirName[0], deleteFn, 10 /* openFiles */,
+            FTW_DEPTH | FTW_MOUNT | FTW_PHYS);
+    if (rc == -1) {
+        LOG(INFO) << "Could not delete directory: " << &tempDirName[0];
+    }
+    return true;
+}
+
+/*
+ * After a platform update it is likely that timezone data found on the system partition will be
+ * newer than the version found in the data partition. This tool detects this case and removes the
+ * version in /data along with any update metadata.
+ *
+ * Note: This code is related to code in com.android.server.updates.TzDataInstallReceiver. The
+ * paths for the metadata and current timezone data must match.
+ *
+ * Typically on device the two args will be:
+ *   /system/usr/share/zoneinfo /data/misc/zoneinfo
+ *
+ * See usage() for usage notes.
+ */
+int main(int argc, char* argv[]) {
+    if (argc != 3) {
+        usage();
+    }
+
+    const char* systemZoneInfoDir = argv[1];
+    const char* dataZoneInfoDir = argv[2];
+
+    std::string dataCurrentDirName(dataZoneInfoDir);
+    dataCurrentDirName += "/current";
+    std::string dataTzDataFileName(dataCurrentDirName);
+    dataTzDataFileName += TZDATA_FILENAME;
+
+    std::vector<char> dataTzDataHeader;
+    dataTzDataHeader.reserve(TZ_HEADER_LENGTH);
+
+    bool dataFileExists = readHeader(dataTzDataFileName, dataTzDataHeader.data(), TZ_HEADER_LENGTH);
+    if (!dataFileExists) {
+        LOG(INFO) << "tzdata file " << dataTzDataFileName << " does not exist. No action required.";
+        return 0;
+    }
+    checkValidHeader(dataTzDataFileName, dataTzDataHeader.data());
+
+    std::string systemTzDataFileName(systemZoneInfoDir);
+    systemTzDataFileName += TZDATA_FILENAME;
+    std::vector<char> systemTzDataHeader;
+    systemTzDataHeader.reserve(TZ_HEADER_LENGTH);
+    bool systemFileExists =
+            readHeader(systemTzDataFileName, systemTzDataHeader.data(), TZ_HEADER_LENGTH);
+    if (!systemFileExists) {
+        LOG(FATAL) << systemTzDataFileName << " does not exist or could not be opened";
+    }
+    checkValidHeader(systemTzDataFileName, systemTzDataHeader.data());
+
+    if (strncmp(&systemTzDataHeader[0], &dataTzDataHeader[0], TZ_HEADER_LENGTH) < 0) {
+        LOG(INFO) << "tzdata file " << dataTzDataFileName << " is the newer than "
+                << systemTzDataFileName << ". No action required.";
+    } else {
+        // We have detected the case this tool is intended to prevent. Go fix it.
+        LOG(INFO) << "tzdata file " << dataTzDataFileName << " is the same as or older than "
+                << systemTzDataFileName << "; fixing...";
+
+        // Delete the update metadata
+        std::string dataUpdatesDirName(dataZoneInfoDir);
+        dataUpdatesDirName += "/updates";
+        LOG(INFO) << "Removing: " << dataUpdatesDirName;
+        bool deleted = deleteDir(dataUpdatesDirName);
+        if (!deleted) {
+            LOG(WARNING) << "Deletion of install metadata " << dataUpdatesDirName
+                    << " was not successful";
+        }
+
+        // Delete the TZ data
+        LOG(INFO) << "Removing: " << dataCurrentDirName;
+        deleted = deleteDir(dataCurrentDirName);
+        if (!deleted) {
+            LOG(WARNING) << "Deletion of tzdata " << dataCurrentDirName << " was not successful";
+        }
+    }
+
+    return 0;
+}